├── .gitignore ├── Kconfig ├── LICENSE ├── Makefile ├── README.md ├── ap.c ├── ap.h ├── bh.c ├── bh.h ├── common.h ├── debug.h ├── fwio.c ├── fwio.h ├── ht.c ├── ht.h ├── hwio.c ├── hwio.h ├── keys.c ├── keys.h ├── main.c ├── main.h ├── module.c ├── p2p.c ├── p2p.h ├── pm.c ├── pm.h ├── queue.c ├── queue.h ├── rx.c ├── rx.h ├── scan.c ├── scan.h ├── sdio.c ├── sdio.h ├── sta.c ├── sta.h ├── sun8i-h2-plus-orangepi-zero.dts ├── tx.c ├── tx.h ├── wsm.c ├── wsm.h └── xradio.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.cmd 2 | *.o 3 | Module.symvers 4 | modules.order 5 | .tmp_versions 6 | *.ko 7 | *.mod 8 | *.mod.c 9 | tags 10 | -------------------------------------------------------------------------------- /Kconfig: -------------------------------------------------------------------------------- 1 | config XRADIO 2 | tristate "XRADIO WLAN support" 3 | depends on MAC80211 4 | default n 5 | help 6 | 7 | This is an experimental driver for the XRADIO chip-set. 8 | Enabling this option enables the generic driver without 9 | any platform support. 10 | Please select the appropriate platform below. 11 | 12 | if XRADIO 13 | 14 | config XRADIO_NON_POWER_OF_TWO_BLOCKSIZES 15 | bool "Platform supports non-power-of-two SDIO transfer" 16 | depends on XRADIO 17 | default y 18 | ---help--- 19 | Say N here only if you are running the driver on a platform 20 | which does not have support for non-power-of-two SDIO transfer. 21 | If unsure, say Y. 22 | 23 | config XRADIO_5GHZ_SUPPORT 24 | bool "5GHz band support" 25 | depends on XRADIO 26 | default n 27 | ---help--- 28 | Say Y if your device supports 5GHz band. If unsure, say N. 29 | 30 | config XRADIO_WAPI_SUPPORT 31 | bool "WAPI support" 32 | depends on XRADIO 33 | default n 34 | ---help--- 35 | Say Y if your compat-wireless support WAPI. 36 | If unsure, say N. 37 | 38 | config XRADIO_USE_EXTENSIONS 39 | bool "Extensions for WFD and PS mode" 40 | depends on XRADIO 41 | default y 42 | ---help--- 43 | Say Y if you want to include XR extensions 44 | If unsure, say Y. 45 | 46 | endif 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CONFIG_XRADIO := m 2 | 3 | xradio_wlan-y := \ 4 | fwio.o \ 5 | tx.o \ 6 | rx.o \ 7 | main.o \ 8 | queue.o \ 9 | hwio.o \ 10 | bh.o \ 11 | wsm.o \ 12 | sta.o \ 13 | ap.o \ 14 | keys.o \ 15 | scan.o \ 16 | module.o \ 17 | sdio.o \ 18 | pm.o \ 19 | ht.o \ 20 | p2p.o 21 | 22 | ccflags-y += -DCONFIG_XRADIO_USE_EXTENSIONS 23 | 24 | ccflags-y += -DMCAST_FWDING 25 | ccflags-y += -DXRADIO_SUSPEND_RESUME_FILTER_ENABLE 26 | ccflags-y += -DAP_AGGREGATE_FW_FIX 27 | ccflags-y += -DAP_HT_CAP_UPDATE 28 | ccflags-y += -DAP_HT_COMPAT_FIX 29 | ccflags-y += -DCONFIG_XRADIO_DUMP_ON_ERROR 30 | 31 | ccflags-y += -DCONFIG_XRADIO_SUSPEND_POWER_OFF 32 | 33 | # Extra IE for probe response from upper layer is needed in P2P GO 34 | # For offloading probe response to FW, the extra IE must be included 35 | # in the probe response template 36 | ccflags-y += -DPROBE_RESP_EXTRA_IE 37 | 38 | # Modified by wzw 39 | ccflags-y += -DTES_P2P_0002_ROC_RESTART 40 | ccflags-y += -DTES_P2P_000B_EXTEND_INACTIVITY_CNT 41 | ccflags-y += -DTES_P2P_000B_DISABLE_EAPOL_FILTER 42 | # ccflags-y += -DXRADIO_USE_LONG_DTIM_PERIOD 43 | ccflags-y += -DXRADIO_USE_LONG_KEEP_ALIVE_PERIOD 44 | 45 | #ccflags-y += -DDEBUG 46 | 47 | 48 | #~dgp 49 | #ccflags-y += -DXRADIO_DISABLE_HW_CRYPTO 50 | 51 | ldflags-y += --strip-debug 52 | 53 | obj-$(CONFIG_XRADIO) += xradio_wlan.o 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xradio 2 | Port Allwinner xradio driver to mainline Linux. 3 | 4 | # READ THIS 5 | 6 | This driver just about works. If it loads and starts working normally it usually doesn't have any major issues until you try to reboot. The structure of the driver isn't great and it can lock up the kernel if it gets confused. It's not production ready for your large scale commercial IoT deployment. 7 | 8 | Also: The xr819 chip/firmware drops tons and tons of frames with FCS errors and this makes performance horrible at best. 9 | Most people have lost interest in having anything to do with the xr819 because of people being idiots and demanding that issues that are incredibly hard to fix without documentation be fixed because they spent $8 on a board and somehow people that got exactly zero of their $8 are responsible. 10 | 11 | Moral of the story: If you're going to post nasty things on the interwebs and demand people fix stuff because *reasons* at least have a bunch of packet dumps etc and have some idea about what you're talking about. 12 | 13 | # Building 14 | 15 | Something like this: 16 | 17 | ``` 18 | make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C M=$PWD modules 19 | make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C M=$PWD INSTALL_MOD_PATH= modules_install 20 | ``` 21 | 22 | # How to use this 23 | 24 | You need to specify one or two regulators for the xr819's 1.8v and 3.3v supplies in your device tree. 25 | (for example, at: `.../linux_sources/linux-4.12-rc5/arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts`) 26 | 27 | It is possible to build dtb-s only: 28 | 29 | ``` 30 | make sunxi_defconfig 31 | make dtbs 32 | ``` 33 | 34 | or via cross-compilation: 35 | 36 | ``` 37 | make -j4 ARCH=arm CROSS_COMPILE=arm-none-eabi- sunxi_defconfig 38 | make -j4 ARCH=arm CROSS_COMPILE=arm-none-eabi- dtbs 39 | ``` 40 | 41 | For example, with appropriate archlinux arm kernel build you could use mainline kernel without rebuiding everything, only replacing your dtb-file at `/boot/dtbs/`. 42 | 43 | The orange pi zero only has control over the 1.8v regulator and a 3.3v fixed regulator is provided elsewhere 44 | so we only need one here: 45 | 46 | ``` 47 | vdd_wifi: vdd_wifi { 48 | compatible = "regulator-fixed"; 49 | regulator-name = "wifi"; 50 | regulator-min-microvolt = <1800000>; 51 | regulator-max-microvolt = <1800000>; 52 | gpio = <&pio 0 20 GPIO_ACTIVE_HIGH>; 53 | startup-delay-us = <70000>; 54 | enable-active-high; 55 | }; 56 | ``` 57 | 58 | Next you need a pwrseq node that controls the reset pin of the xr819. 59 | 60 | ``` 61 | pwrseq_wifi: pwrseq_wifi@0 { 62 | compatible = "mmc-pwrseq-simple"; 63 | pinctrl-names = "default"; 64 | pinctrl-0 = <&wifi_rst>; 65 | reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; 66 | post-power-on-delay-ms = <50>; 67 | }; 68 | ``` 69 | 70 | Next you need to add some things to the mmc node that the xr819 is connected to. 71 | 72 | ``` 73 | &mmc1 { 74 | pinctrl-names = "default"; 75 | pinctrl-0 = <&mmc1_pins_a>; 76 | vqmmc-supply = <&vdd_wifi>; 77 | vmmc-supply = <®_vcc3v3>; 78 | bus-width = <4>; 79 | mmc-pwrseq = <&pwrseq_wifi>; 80 | non-removable; 81 | status = "okay"; 82 | 83 | xr819wifi: xr819wifi@1 { 84 | reg = <1>; 85 | compatible = "xradio,xr819"; 86 | pinctrl-names = "default"; 87 | pinctrl-0 = <&wifi_wake>; 88 | interrupt-parent = <&pio>; 89 | interrupts = <6 10 IRQ_TYPE_EDGE_RISING>; 90 | interrupt-names = "host-wake"; 91 | local-mac-address = [dc 44 6d c0 ff ee]; 92 | }; 93 | }; 94 | ``` 95 | 96 | and probably we also need this: 97 | 98 | ``` 99 | &pio { 100 | wifi_wake: wifi_wake { 101 | pins = "PG10"; 102 | function = "gpio_in"; 103 | }; 104 | }; 105 | 106 | ``` 107 | 108 | ``` 109 | &r_pio { 110 | wifi_rst: wifi_rst { 111 | pins = "PL7"; 112 | function = "gpio_out"; 113 | }; 114 | }; 115 | 116 | ``` 117 | 118 | example `sun8i-h2-plus-orangepi-zero.dts` is provided too. 119 | 120 | vqmmc-supply and vmmc-supply should reference the regulators that control the xr819 supplies. 121 | The device tree for the SoC the orange pi zero is based on supplies a fixed 3.3v regulator 122 | so we use that for vmmc-supply and provide the 1.8v controllable regulator as vqmmc-supply. 123 | vqmcc-supply is apparently for the IO supply which is 3.3v for the orange pi zero but 124 | swapping vqmmc and vmmc around results in the kernel complaining that the card's (the xr819) 125 | required IO voltage isn't supported. The setup above might not be technically correct but 126 | does work. 127 | The xr819 node should be self explanatory. The compatible string is used by the driver 128 | to find the node. The wake interrupt from the xr819 needs to be provided. 129 | 130 | Finally you can specify a MAC address to use. If you don't set one you will get a random one 131 | on each boot. Instead of creating a new device tree file for every system you should 132 | probably overwrite the address given after loading the device tree in u-boot. For the sunxi 133 | uboot all you have to actually do is add something like "ethernet1 = &xr819wifi;" to the 134 | aliases section of the device tree you give to the kernel and u-boot will update the mac 135 | address to something based on the unique chip id for you. 136 | 137 | # Running 138 | 139 | place `xradio_wlan.ko` to your modules folder (for archlinux: `/lib/modules/.../kernel/net/wireless/xradio`) 140 | 141 | Don't forget to take [firmware binaries from somewhere](https://github.com/armbian/firmware/tree/master/xr819): `boot_xr819.bin`, `fw_xr819.bin`, `sdd_xr819.bin` (for archlunux place it to `/lib/firmware/xr819/`) 142 | 143 | # What works, what doesn't 144 | 145 | Working: 146 | 147 | Standard client station mode seems to work fine. 148 | Master (AP) mode works with WPA/WPA2 enabled etc. 149 | Dual role station and master mode. 150 | 151 | # Issues 152 | 153 | The firmware running on the xr819 is very crash happy and the driver is a bit 154 | stupid. For example the driver can get confused about how many packets of data 155 | the xr819 has for it to read and can try to read too many. The firmware on the 156 | xr819 responds by triggering an assert and shutting down. The driver gets 157 | a packet that tells it that the firmware is dead and shuts down the thread used 158 | to push and pull data but the rest of the driver and the os has no idea and 159 | if the os tries to interact with the driver everything starts to lock up. 160 | 161 | Pings from the device to the network are faster than from the network to the device. 162 | This seems to be because of latency between the interrupt and servicing RX reports 163 | from the device. 164 | 165 | # Fun stuff 166 | 167 | The driver is based on the driver for the ST CW1100/CW1200 chips. 168 | The XR819 is probably a clone, licensed version or actually a CW1100 family chip 169 | that has been packaged by xradio/allwinner as the CW1100 is available as a raw 170 | wafer. 171 | 172 | The silicon version from the XR819 and procedure for loading firmware 173 | matches up with the CW1x60 chips which were apparently never released so 174 | maybe Allwinner bought the design after the ST/Ericsson split? 175 | 176 | If anyone wants to mainline support for the XR819 they should probably do it by 177 | adding support for the XR819 to the existing CW1200 driver so they don't have to 178 | get thousands and thousands of lines of code signed off. 179 | -------------------------------------------------------------------------------- /ap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * STA and AP APIs for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #ifndef AP_H_INCLUDED 13 | #define AP_H_INCLUDED 14 | 15 | #define XRADIO_NOA_NOTIFICATION_DELAY 10 16 | 17 | #ifdef AP_HT_CAP_UPDATE 18 | #define HT_INFO_OFFSET 4 19 | #define HT_INFO_MASK 0x0011 20 | #define HT_INFO_IE_LEN 22 21 | #endif 22 | 23 | int xradio_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, 24 | bool set); 25 | int xradio_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 26 | struct ieee80211_sta *sta); 27 | int xradio_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 28 | struct ieee80211_sta *sta); 29 | void xradio_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, 30 | enum sta_notify_cmd notify_cmd, 31 | struct ieee80211_sta *sta); 32 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) 33 | void xradio_bss_info_changed(struct ieee80211_hw *dev, 34 | struct ieee80211_vif *vif, 35 | struct ieee80211_bss_conf *info, 36 | u64 changed); 37 | #else 38 | void xradio_bss_info_changed(struct ieee80211_hw *dev, 39 | struct ieee80211_vif *vif, 40 | struct ieee80211_bss_conf *info, 41 | u32 changed); 42 | #endif 43 | int xradio_ampdu_action(struct ieee80211_hw *hw, 44 | struct ieee80211_vif *vif, 45 | struct ieee80211_ampdu_params *params); 46 | /* enum ieee80211_ampdu_mlme_action action, 47 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, 48 | u8 buf_size);*/ 49 | 50 | void xradio_suspend_resume(struct xradio_vif *priv, 51 | struct wsm_suspend_resume *arg); 52 | void xradio_set_tim_work(struct work_struct *work); 53 | void xradio_set_cts_work(struct work_struct *work); 54 | void xradio_multicast_start_work(struct work_struct *work); 55 | void xradio_multicast_stop_work(struct work_struct *work); 56 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) 57 | void xradio_mcast_timeout(struct timer_list *t); 58 | #else 59 | void xradio_mcast_timeout(unsigned long arg); 60 | #endif 61 | int xradio_find_link_id(struct xradio_vif *priv, const u8 *mac); 62 | int xradio_alloc_link_id(struct xradio_vif *priv, const u8 *mac); 63 | void xradio_link_id_work(struct work_struct *work); 64 | void xradio_link_id_gc_work(struct work_struct *work); 65 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 66 | /*in linux3.4 mac,it does't have the noa pass*/ 67 | //void xradio_notify_noa(struct xradio_vif *priv, int delay); 68 | #endif 69 | int xrwl_unmap_link(struct xradio_vif *priv, int link_id); 70 | #ifdef AP_HT_CAP_UPDATE 71 | void xradio_ht_oper_update_work(struct work_struct *work); 72 | #endif 73 | 74 | #endif 75 | -------------------------------------------------------------------------------- /bh.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Data Transmission thread implementation for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | #include "xradio.h" 16 | #include "bh.h" 17 | #include "hwio.h" 18 | #include "wsm.h" 19 | #include "sdio.h" 20 | 21 | /* TODO: Verify these numbers with WSM specification. */ 22 | #define DOWNLOAD_BLOCK_SIZE_WR (0x1000 - 4) 23 | /* an SPI message cannot be bigger than (2"12-1)*2 bytes 24 | * "*2" to cvt to bytes */ 25 | #define MAX_SZ_RD_WR_BUFFERS (DOWNLOAD_BLOCK_SIZE_WR*2) 26 | #define PIGGYBACK_CTRL_REG (2) 27 | #define EFFECTIVE_BUF_SIZE (MAX_SZ_RD_WR_BUFFERS - PIGGYBACK_CTRL_REG) 28 | 29 | /* Suspend state privates */ 30 | enum xradio_bh_pm_state { 31 | XRADIO_BH_RESUMED = 0, 32 | XRADIO_BH_SUSPEND, 33 | XRADIO_BH_SUSPENDED, 34 | XRADIO_BH_RESUME, 35 | }; 36 | typedef int (*xradio_wsm_handler)(struct xradio_common *hw_priv, u8 *data, size_t size); 37 | 38 | #ifdef MCAST_FWDING 39 | int wsm_release_buffer_to_fw(struct xradio_vif *priv, int count); 40 | #endif 41 | static int xradio_bh(void *arg); 42 | 43 | int xradio_register_bh(struct xradio_common *hw_priv) 44 | { 45 | int ret = 0; 46 | 47 | atomic_set(&hw_priv->bh_tx, 0); 48 | atomic_set(&hw_priv->bh_term, 0); 49 | atomic_set(&hw_priv->bh_suspend, XRADIO_BH_RESUMED); 50 | hw_priv->buf_id_tx = 0; 51 | hw_priv->buf_id_rx = 0; 52 | init_waitqueue_head(&hw_priv->bh_wq); 53 | init_waitqueue_head(&hw_priv->bh_evt_wq); 54 | 55 | hw_priv->bh_thread = kthread_run(&xradio_bh, hw_priv, XRADIO_BH_THREAD); 56 | if (IS_ERR(hw_priv->bh_thread)) { 57 | ret = PTR_ERR(hw_priv->bh_thread); 58 | hw_priv->bh_thread = NULL; 59 | } 60 | 61 | return ret; 62 | } 63 | 64 | void xradio_unregister_bh(struct xradio_common *hw_priv) 65 | { 66 | struct task_struct *thread = hw_priv->bh_thread; 67 | 68 | if (WARN_ON(!thread)) 69 | return; 70 | 71 | hw_priv->bh_thread = NULL; 72 | kthread_stop(thread); 73 | #ifdef HAS_PUT_TASK_STRUCT 74 | put_task_struct(thread); 75 | #endif 76 | dev_dbg(hw_priv->pdev, "Unregister success.\n"); 77 | } 78 | 79 | void xradio_irq_handler(struct xradio_common *hw_priv) 80 | { 81 | xradio_bh_wakeup(hw_priv); 82 | } 83 | 84 | void xradio_bh_wakeup(struct xradio_common *hw_priv) 85 | { 86 | atomic_set(&hw_priv->bh_tx, 1); 87 | wake_up(&hw_priv->bh_wq); 88 | } 89 | 90 | int xradio_bh_suspend(struct xradio_common *hw_priv) 91 | { 92 | #ifdef MCAST_FWDING 93 | int i =0; 94 | struct xradio_vif *priv = NULL; 95 | #endif 96 | 97 | if (hw_priv->bh_error) { 98 | return -EINVAL; 99 | } 100 | 101 | #ifdef MCAST_FWDING 102 | xradio_for_each_vif(hw_priv, priv, i) { 103 | if (!priv) 104 | continue; 105 | if ( (priv->multicast_filter.enable) 106 | && (priv->join_status == XRADIO_JOIN_STATUS_AP) ) { 107 | wsm_release_buffer_to_fw(priv, 108 | (hw_priv->wsm_caps.numInpChBufs - 1)); 109 | break; 110 | } 111 | } 112 | #endif 113 | 114 | atomic_set(&hw_priv->bh_suspend, XRADIO_BH_SUSPEND); 115 | wake_up(&hw_priv->bh_wq); 116 | return wait_event_timeout(hw_priv->bh_evt_wq, (hw_priv->bh_error || 117 | XRADIO_BH_SUSPENDED == atomic_read(&hw_priv->bh_suspend)), 118 | 1 * HZ)? 0 : -ETIMEDOUT; 119 | } 120 | 121 | int xradio_bh_resume(struct xradio_common *hw_priv) 122 | { 123 | #ifdef MCAST_FWDING 124 | int ret; 125 | int i =0; 126 | struct xradio_vif *priv =NULL; 127 | #endif 128 | 129 | 130 | if (hw_priv->bh_error) { 131 | return -EINVAL; 132 | } 133 | 134 | atomic_set(&hw_priv->bh_suspend, XRADIO_BH_RESUME); 135 | wake_up(&hw_priv->bh_wq); 136 | 137 | #ifdef MCAST_FWDING 138 | ret = wait_event_timeout(hw_priv->bh_evt_wq, (hw_priv->bh_error || 139 | XRADIO_BH_RESUMED == atomic_read(&hw_priv->bh_suspend)) 140 | ,1 * HZ)? 0 : -ETIMEDOUT; 141 | 142 | xradio_for_each_vif(hw_priv, priv, i) { 143 | if (!priv) 144 | continue; 145 | if ((priv->join_status == XRADIO_JOIN_STATUS_AP) && 146 | (priv->multicast_filter.enable)) { 147 | u8 count = 0; 148 | WARN_ON(wsm_request_buffer_request(priv, &count)); 149 | dev_dbg(hw_priv->pdev, "Reclaim Buff %d \n",count); 150 | break; 151 | } 152 | } 153 | 154 | return ret; 155 | #else 156 | return wait_event_timeout(hw_priv->bh_evt_wq,hw_priv->bh_error || 157 | (XRADIO_BH_RESUMED == atomic_read(&hw_priv->bh_suspend)), 158 | 1 * HZ) ? 0 : -ETIMEDOUT; 159 | #endif 160 | 161 | } 162 | 163 | static inline void wsm_alloc_tx_buffer(struct xradio_common *hw_priv) 164 | { 165 | ++hw_priv->hw_bufs_used; 166 | } 167 | 168 | int wsm_release_tx_buffer(struct xradio_common *hw_priv, int count) 169 | { 170 | int ret = 0; 171 | int hw_bufs_used = hw_priv->hw_bufs_used; 172 | 173 | hw_priv->hw_bufs_used -= count; 174 | if (WARN_ON(hw_priv->hw_bufs_used < 0)) { 175 | /* Tx data patch stops when all but one hw buffers are used. 176 | So, re-start tx path in case we find hw_bufs_used equals 177 | numInputChBufs - 1. 178 | */ 179 | dev_err(hw_priv->pdev, "hw_bufs_used=%d, count=%d.\n", 180 | hw_priv->hw_bufs_used, count); 181 | ret = -1; 182 | } else if (hw_bufs_used >= (hw_priv->wsm_caps.numInpChBufs - 1)) 183 | ret = 1; 184 | if (!hw_priv->hw_bufs_used) 185 | wake_up(&hw_priv->bh_evt_wq); 186 | return ret; 187 | } 188 | 189 | int wsm_release_vif_tx_buffer(struct xradio_common *hw_priv, int if_id, int count) 190 | { 191 | int ret = 0; 192 | 193 | hw_priv->hw_bufs_used_vif[if_id] -= count; 194 | if (!hw_priv->hw_bufs_used_vif[if_id]) 195 | wake_up(&hw_priv->bh_evt_wq); 196 | 197 | if (WARN_ON(hw_priv->hw_bufs_used_vif[if_id] < 0)) 198 | ret = -1; 199 | return ret; 200 | } 201 | #ifdef MCAST_FWDING 202 | int wsm_release_buffer_to_fw(struct xradio_vif *priv, int count) 203 | { 204 | int i; 205 | u8 flags; 206 | struct wsm_buf *buf; 207 | size_t buf_len; 208 | struct wsm_hdr *wsm; 209 | struct xradio_common *hw_priv = priv->hw_priv; 210 | 211 | if (priv->join_status != XRADIO_JOIN_STATUS_AP) { 212 | return 0; 213 | } 214 | dev_dbg(hw_priv->pdev, "Rel buffer to FW %d, %d\n", count, hw_priv->hw_bufs_used); 215 | 216 | for (i = 0; i < count; i++) { 217 | if ((hw_priv->hw_bufs_used + 1) < hw_priv->wsm_caps.numInpChBufs) { 218 | flags = i ? 0: 0x1; 219 | 220 | wsm_alloc_tx_buffer(hw_priv); 221 | buf = &hw_priv->wsm_release_buf[i]; 222 | buf_len = buf->data - buf->begin; 223 | 224 | /* Add sequence number */ 225 | wsm = (struct wsm_hdr *)buf->begin; 226 | BUG_ON(buf_len < sizeof(*wsm)); 227 | 228 | wsm->id &= __cpu_to_le32(~WSM_TX_SEQ(WSM_TX_SEQ_MAX)); 229 | wsm->id |= cpu_to_le32(WSM_TX_SEQ(hw_priv->wsm_tx_seq)); 230 | 231 | dev_dbg(hw_priv->pdev, "REL %d\n", hw_priv->wsm_tx_seq); 232 | if (WARN_ON(xradio_data_write(hw_priv, buf->begin, buf_len))) { 233 | break; 234 | } 235 | hw_priv->buf_released = 1; 236 | hw_priv->wsm_tx_seq = (hw_priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX; 237 | } else 238 | break; 239 | } 240 | 241 | if (i == count) { 242 | return 0; 243 | } 244 | 245 | /* Should not be here */ 246 | dev_dbg(hw_priv->pdev, "Error, Less HW buf %d,%d.\n", 247 | hw_priv->hw_bufs_used, hw_priv->wsm_caps.numInpChBufs); 248 | WARN_ON(1); 249 | return -1; 250 | } 251 | #endif 252 | 253 | /* reserve a packet for the case dev_alloc_skb failed in bh.*/ 254 | int xradio_init_resv_skb(struct xradio_common *hw_priv) 255 | { 256 | int len = (SDIO_BLOCK_SIZE<<2) + WSM_TX_EXTRA_HEADROOM + \ 257 | 8 + 12; /* TKIP IV + ICV and MIC */ 258 | 259 | hw_priv->skb_reserved = dev_alloc_skb(len); 260 | if (hw_priv->skb_reserved) { 261 | hw_priv->skb_resv_len = len; 262 | } else { 263 | dev_warn(hw_priv->pdev, "xr_alloc_skb failed(%d)\n", len); 264 | } 265 | return 0; 266 | } 267 | 268 | void xradio_deinit_resv_skb(struct xradio_common *hw_priv) 269 | { 270 | if (hw_priv->skb_reserved) { 271 | dev_kfree_skb(hw_priv->skb_reserved); 272 | hw_priv->skb_reserved = NULL; 273 | hw_priv->skb_resv_len = 0; 274 | } 275 | } 276 | 277 | int xradio_realloc_resv_skb(struct xradio_common *hw_priv, 278 | struct sk_buff *skb) 279 | { 280 | if (!hw_priv->skb_reserved && hw_priv->skb_resv_len) { 281 | hw_priv->skb_reserved = dev_alloc_skb(hw_priv->skb_resv_len); 282 | if (!hw_priv->skb_reserved) { 283 | hw_priv->skb_reserved = skb; 284 | dev_warn(hw_priv->pdev, "xr_alloc_skb failed(%d)\n", 285 | hw_priv->skb_resv_len); 286 | return -1; 287 | } 288 | } 289 | return 0; /* realloc sbk success, deliver to upper.*/ 290 | } 291 | 292 | static inline struct sk_buff *xradio_get_resv_skb(struct xradio_common *hw_priv, 293 | size_t len) 294 | { struct sk_buff *skb = NULL; 295 | if (hw_priv->skb_reserved && len <= hw_priv->skb_resv_len) { 296 | skb = hw_priv->skb_reserved; 297 | hw_priv->skb_reserved = NULL; 298 | } 299 | return skb; 300 | } 301 | 302 | static inline int xradio_put_resv_skb(struct xradio_common *hw_priv, 303 | struct sk_buff *skb) 304 | { 305 | if (!hw_priv->skb_reserved && hw_priv->skb_resv_len) { 306 | hw_priv->skb_reserved = skb; 307 | return 0; 308 | } 309 | return 1; /* sbk not put to reserve*/ 310 | } 311 | 312 | static struct sk_buff *xradio_get_skb(struct xradio_common *hw_priv, size_t len) 313 | { 314 | struct sk_buff *skb = NULL; 315 | size_t alloc_len = (len > SDIO_BLOCK_SIZE) ? len : SDIO_BLOCK_SIZE; 316 | 317 | /* TKIP IV + TKIP ICV and MIC - Piggyback.*/ 318 | alloc_len += WSM_TX_EXTRA_HEADROOM + 8 + 12- 2; 319 | if (len > SDIO_BLOCK_SIZE || !hw_priv->skb_cache) { 320 | skb = dev_alloc_skb(alloc_len); 321 | /* In AP mode RXed SKB can be looped back as a broadcast. 322 | * Here we reserve enough space for headers. */ 323 | if (skb) { 324 | skb_reserve(skb, WSM_TX_EXTRA_HEADROOM + 8 /* TKIP IV */ 325 | - WSM_RX_EXTRA_HEADROOM); 326 | } else { 327 | skb = xradio_get_resv_skb(hw_priv, alloc_len); 328 | if (skb) { 329 | dev_dbg(hw_priv->pdev, "get skb_reserved(%zu)!\n", alloc_len); 330 | skb_reserve(skb, WSM_TX_EXTRA_HEADROOM + 8 /* TKIP IV */ 331 | - WSM_RX_EXTRA_HEADROOM); 332 | } else { 333 | dev_dbg(hw_priv->pdev, "xr_alloc_skb failed(%zu)!\n", alloc_len); 334 | } 335 | } 336 | } else { 337 | skb = hw_priv->skb_cache; 338 | hw_priv->skb_cache = NULL; 339 | } 340 | return skb; 341 | } 342 | 343 | static void xradio_put_skb(struct xradio_common *hw_priv, struct sk_buff *skb) 344 | { 345 | if (hw_priv->skb_cache) 346 | dev_kfree_skb(skb); 347 | else 348 | hw_priv->skb_cache = skb; 349 | } 350 | 351 | static int xradio_bh_read_ctrl_reg(struct xradio_common *hw_priv, 352 | u16 *ctrl_reg) 353 | { 354 | int ret; 355 | ret = xradio_reg_read_16(hw_priv, HIF_CONTROL_REG_ID, ctrl_reg); 356 | if (ret) { 357 | ret = xradio_reg_read_16(hw_priv, HIF_CONTROL_REG_ID, ctrl_reg); 358 | if (ret) { 359 | hw_priv->bh_error = 1; 360 | dev_err(hw_priv->pdev, "Failed to read control register.\n"); 361 | } 362 | } 363 | 364 | return ret; 365 | } 366 | 367 | static int xradio_device_wakeup(struct xradio_common *hw_priv) 368 | { 369 | u16 ctrl_reg; 370 | int ret, i=0; 371 | 372 | /* To force the device to be always-on, the host sets WLAN_UP to 1 */ 373 | ret = xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, HIF_CTRL_WUP_BIT); 374 | if (WARN_ON(ret)) 375 | return ret; 376 | 377 | ret = xradio_bh_read_ctrl_reg(hw_priv, &ctrl_reg); 378 | if (WARN_ON(ret)) 379 | return ret; 380 | 381 | /* If the device returns WLAN_RDY as 1, the device is active and will 382 | * remain active. */ 383 | while (!(ctrl_reg & HIF_CTRL_RDY_BIT) && i < 500) { 384 | ret = xradio_bh_read_ctrl_reg(hw_priv, &ctrl_reg); 385 | msleep(1); 386 | i++; 387 | } 388 | if (unlikely(i >= 500)) { 389 | dev_err(hw_priv->pdev, "Device cannot wakeup.\n"); 390 | return -1; 391 | } else if (unlikely(i >= 50)) 392 | dev_warn(hw_priv->pdev, "Device wakeup time=%dms.\n", i); 393 | dev_dbg(hw_priv->pdev, "Device awake, t=%dms.\n", i); 394 | return 1; 395 | } 396 | 397 | /* Must be called from BH thraed. */ 398 | void xradio_enable_powersave(struct xradio_vif *priv, 399 | bool enable) 400 | { 401 | priv->powersave_enabled = enable; 402 | } 403 | 404 | static void xradio_bh_rx_dump(struct device *dev, u8 *data, size_t len){ 405 | #ifdef DEBUG 406 | static const char *msgnames[0xffff] = { 407 | // 0x4?? is a sync response to a command 408 | [0x0404] = "tx confirm", 409 | [0x0406] = "mib confirm", 410 | [0x0407] = "scan started", 411 | [0x0409] = "configuration confirm", 412 | [0x040a] = "reset confirm", 413 | [0x040b] = "join confirm", 414 | [0x040c] = "key added", 415 | [0x040d] = "key removed", 416 | [0x0410] = "pm confirm", 417 | [0x0411] = "set bss params", 418 | [0x0412] = "tx queue params", 419 | [0x0413] = "edca confirm", 420 | [0x0417] = "start confirm", 421 | [0x041b] = "update ie confirm", 422 | [0x041c] = "map link confirm", 423 | // 0x8?? seem to be async responses or events 424 | [0x0801] = "firmware startup complete", 425 | [0x0804] = "rx", 426 | [0x0805] = "event", 427 | [0x0806] = "scan complete", 428 | [0x0810] = "set pm indication" 429 | }; 430 | 431 | u16 msgid, ifid; 432 | u16 *p = (u16 *)data; 433 | msgid = (*(p + 1)) & 0xC3F; 434 | ifid = (*(p + 1)) >> 6; 435 | ifid &= 0xF; 436 | const char *msgname = msgnames[msgid]; 437 | if(msgid == 0x804 && ifid == 2){ 438 | msgname = "scan result"; 439 | } 440 | 441 | dev_dbg(dev, "vif %d: sdio rx, msgid %s(0x%.4X) len %d\n", 442 | ifid, msgname, msgid, *p); 443 | #if defined(CONFIG_XRADIO_DEBUG) 444 | // print_hex_dump_bytes("<-- ", DUMP_PREFIX_NONE, 445 | // data, min(len, (size_t) 64)); 446 | #endif /* CONFIG_XRADIO_DEBUG */ 447 | #endif 448 | } 449 | 450 | #define READLEN(ctrl) ((ctrl & HIF_CTRL_NEXT_LEN_MASK) << 1) //read_len=ctrl_reg*2. 451 | 452 | static int xradio_bh_rx_availlen(struct xradio_common *hw_priv){ 453 | u16 ctrl_reg = 0; 454 | if (xradio_bh_read_ctrl_reg(hw_priv, &ctrl_reg)) { 455 | return -EIO; 456 | } 457 | return READLEN(ctrl_reg); 458 | } 459 | 460 | static int xradio_bh_rx(struct xradio_common *hw_priv, u16* nextlen) { 461 | size_t read_len = 0; 462 | struct sk_buff *skb_rx = NULL; 463 | struct wsm_hdr *wsm; 464 | size_t wsm_len; 465 | int wsm_id; 466 | u8 wsm_seq; 467 | size_t alloc_len; 468 | u8 *data; 469 | int ret; 470 | 471 | read_len = *nextlen > 0 ? *nextlen : xradio_bh_rx_availlen(hw_priv); 472 | if(read_len <= 0) 473 | return read_len; 474 | 475 | if (read_len < sizeof(struct wsm_hdr) || (read_len > EFFECTIVE_BUF_SIZE)) { 476 | dev_err(hw_priv->pdev, "Invalid read len: %zu", read_len); 477 | return -1; 478 | } 479 | 480 | /* Add SIZE of PIGGYBACK reg (CONTROL Reg) 481 | * to the NEXT Message length + 2 Bytes for SKB */ 482 | read_len = read_len + 2; 483 | 484 | alloc_len = sdio_align_len(hw_priv, read_len); 485 | /* Check if not exceeding XRADIO capabilities */ 486 | if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) { 487 | dev_err(hw_priv->pdev, "Read aligned len: %zu\n", alloc_len); 488 | } 489 | 490 | /* Get skb buffer. */ 491 | skb_rx = xradio_get_skb(hw_priv, alloc_len); 492 | if (!skb_rx) { 493 | dev_err(hw_priv->pdev, "xradio_get_skb failed.\n"); 494 | return -ENOMEM; 495 | } 496 | skb_trim(skb_rx, 0); 497 | skb_put(skb_rx, read_len); 498 | data = skb_rx->data; 499 | if (!data) { 500 | dev_err(hw_priv->pdev, "skb data is NULL.\n"); 501 | ret = -ENOMEM; 502 | goto out; 503 | } 504 | 505 | /* Read data from device. */ 506 | if (xradio_data_read(hw_priv, data, alloc_len)) { 507 | ret = -EIO; 508 | goto out; 509 | } 510 | 511 | /* the ctrl register is appened to the end of the wsm frame 512 | * so we can use this to avoid reading the control register 513 | * again for the next read .. but if this is invalid we'll 514 | * do an invalid read and the firmware will crash so this 515 | * probably needs some sort of validation */ 516 | *nextlen = READLEN(__le16_to_cpu(((__le16 *) data)[(alloc_len >> 1) - 1])); 517 | 518 | /* check wsm length. */ 519 | wsm = (struct wsm_hdr *) data; 520 | wsm_len = __le32_to_cpu(wsm->len); 521 | 522 | if (WARN_ON(wsm_len > read_len)) { 523 | dev_err(hw_priv->pdev, "wsm is bigger than data read, read %zu but frame is %zu\n", 524 | read_len, wsm_len); 525 | ret = -1; 526 | goto out; 527 | } 528 | 529 | /* dump rx data. */ 530 | xradio_bh_rx_dump(hw_priv->pdev, data, wsm_len); 531 | 532 | /* extract wsm id and seq. */ 533 | wsm_id = __le32_to_cpu(wsm->id) & 0xFFF; 534 | wsm_seq = (__le32_to_cpu(wsm->id) >> 13) & 7; 535 | skb_trim(skb_rx, wsm_len); 536 | 537 | /* process exceptions. */ 538 | if (wsm_id == 0) { 539 | printk("wtf?\n"); 540 | ret = 0; 541 | goto out; 542 | } else if (unlikely(wsm_id == 0x0800)) { 543 | dev_err(hw_priv->pdev, "firmware exception!\n"); 544 | wsm_handle_exception(hw_priv, &data[sizeof(*wsm)], 545 | wsm_len - sizeof(*wsm)); 546 | ret = -1; 547 | goto out; 548 | } 549 | 550 | hw_priv->wsm_rx_seq = (wsm_seq + 1) & 7; 551 | 552 | /* Process tx frames confirm. */ 553 | if (wsm_id & 0x0400) { 554 | if (wsm_release_tx_buffer(hw_priv, 1) < 0) { 555 | dev_err(hw_priv->pdev, "tx buffer < 0.\n"); 556 | ret = -1; 557 | goto out; 558 | } 559 | } 560 | 561 | /* WSM processing frames. */ 562 | if (wsm_handle_rx(hw_priv, wsm_id, wsm, &skb_rx)) { 563 | dev_err(hw_priv->pdev, "wsm_handle_rx failed.\n"); 564 | ret = -1; 565 | goto out; 566 | } 567 | 568 | ret = 1; 569 | 570 | out: 571 | /* Reclaim the SKB buffer */ 572 | if (skb_rx) { 573 | if (xradio_put_resv_skb(hw_priv, skb_rx)) 574 | xradio_put_skb(hw_priv, skb_rx); 575 | } 576 | 577 | return ret; 578 | } 579 | 580 | static void xradio_bh_tx_dump(struct device *dev, u8 *data, size_t len){ 581 | #ifdef DEBUG 582 | static const char *msgnames[0xffff] = { 583 | [0x0004] = "tx", 584 | [0x0006] = "MIB", 585 | [0x0007] = "start scan", 586 | [0x0009] = "configure", 587 | [0x000A] = "reset", 588 | [0x000B] = "join", 589 | [0x000C] = "add key", 590 | [0x000D] = "remove key", 591 | [0x0010] = "set pm", 592 | [0x0011] = "set bss params", 593 | [0x0012] = "set tx queue params", 594 | [0x0013] = "set edca", 595 | [0x0017] = "start", 596 | [0x001b] = "update ie", 597 | [0x001c] = "map link", 598 | }; 599 | static const char *mibnames[0xffff] = { 600 | [0x0003] = "DOT11_SLOT_TIME", 601 | [0x1002] = "TEMPLATE_FRAME", 602 | [0x1003] = "RX_FILTER", 603 | [0x1004] = "BEACON_FILTER_TABLE", 604 | [0x1005] = "BEACON_FILTER_ENABLE", 605 | [0x1006] = "OPERATIONAL POWER MODE", 606 | [0x1007] = "BEACON_WAKEUP_PERIOD", 607 | [0x1009] = "RCPI_RSSI_THRESHOLD", 608 | [0x1010] = "SET_ASSOCIATION_MODE", 609 | [0x100e] = "BLOCK_ACK_POLICY", 610 | [0x100f] = "OVERRIDE_INTERNAL_TX_RATE", 611 | [0x1013] = "SET_UAPSD_INFORMATION", 612 | [0x1016] = "SET_TX_RATE_RETRY_POLICY", 613 | [0x1020] = "PROTECTED_MGMT_POLICY", 614 | [0x1021] = "SET_HT_PROTECTION", 615 | [0x1024] = "USE_MULTI_TX_CONF", 616 | [0x1025] = "KEEP_ALIVE_PERIOD", 617 | [0x1026] = "DISABLE_BSSID_FILTER", 618 | [0x1035] = "SET_INACTIVITY", 619 | }; 620 | 621 | u16 msgid, ifid, mib; 622 | u16 *p = (u16 *)data; 623 | msgid = (*(p + 1)) & 0x3F; 624 | ifid = (*(p + 1)) >> 6; 625 | ifid &= 0xF; 626 | mib = *(p + 2); 627 | 628 | WARN_ON(msgnames[msgid] == NULL); 629 | 630 | if (msgid == 0x0006) { 631 | dev_dbg(dev, "vif %d: sdio tx, msgid %s(0x%.4X) len %d MIB %s(0x%.4X)\n", 632 | ifid, msgnames[msgid], msgid,*p, mibnames[mib], mib); 633 | } else { 634 | dev_dbg(dev, "vif %d: sdio tx, msgid %s(0x%.4X) len %d\n", ifid, msgnames[msgid], msgid, *p); 635 | } 636 | 637 | // print_hex_dump_bytes("--> ", DUMP_PREFIX_NONE, data, 638 | // min(len, (size_t) 64)); 639 | #endif 640 | } 641 | 642 | static int xradio_bh_tx(struct xradio_common *hw_priv){ 643 | int txavailable; 644 | int txburst; 645 | int vif_selected; 646 | struct wsm_hdr *wsm; 647 | size_t tx_len; 648 | int ret; 649 | u8 *data; 650 | 651 | BUG_ON(hw_priv->hw_bufs_used > hw_priv->wsm_caps.numInpChBufs); 652 | txavailable = hw_priv->wsm_caps.numInpChBufs - hw_priv->hw_bufs_used; 653 | if (txavailable) { 654 | /* Wake up the devices */ 655 | if (hw_priv->device_can_sleep) { 656 | ret = xradio_device_wakeup(hw_priv); 657 | if (WARN_ON(ret < 0)) { 658 | return -1; 659 | } else if (ret) { 660 | hw_priv->device_can_sleep = false; 661 | } else { /* Wait for "awake" interrupt */ 662 | dev_dbg(hw_priv->pdev, 663 | "need to wait for device to wake before doing tx\n"); 664 | return 0; 665 | } 666 | } 667 | /* Increase Tx buffer*/ 668 | wsm_alloc_tx_buffer(hw_priv); 669 | 670 | /* Get data to send and send it. */ 671 | ret = wsm_get_tx(hw_priv, &data, &tx_len, &txburst, &vif_selected); 672 | if (ret <= 0) { 673 | wsm_release_tx_buffer(hw_priv, 1); 674 | if (WARN_ON(ret < 0)) { 675 | dev_err(hw_priv->pdev, "wsm_get_tx=%d.\n", ret); 676 | return -ENOMEM; 677 | } else { 678 | return 0; 679 | } 680 | } else { 681 | wsm = (struct wsm_hdr *) data; 682 | BUG_ON(tx_len < sizeof(*wsm)); 683 | BUG_ON(__le32_to_cpu(wsm->len) != tx_len); 684 | 685 | /* Align tx length and check it. */ 686 | if (tx_len <= 8) 687 | tx_len = 16; 688 | tx_len = sdio_align_len(hw_priv, tx_len); 689 | 690 | /* Check if not exceeding XRADIO capabilities */ 691 | if (tx_len > EFFECTIVE_BUF_SIZE) { 692 | dev_warn(hw_priv->pdev, "Write aligned len: %zu\n", tx_len); 693 | } 694 | 695 | /* Make sequence number. */ 696 | wsm->id &= __cpu_to_le32(~WSM_TX_SEQ(WSM_TX_SEQ_MAX)); 697 | wsm->id |= cpu_to_le32(WSM_TX_SEQ(hw_priv->wsm_tx_seq)); 698 | 699 | /* Send the data to devices. */ 700 | if (WARN_ON(xradio_data_write(hw_priv, data, tx_len))) { 701 | wsm_release_tx_buffer(hw_priv, 1); 702 | dev_err(hw_priv->pdev, "xradio_data_write failed\n"); 703 | return -EIO; 704 | } 705 | 706 | xradio_bh_tx_dump(hw_priv->pdev, data, tx_len); 707 | 708 | /* Process after data have sent. */ 709 | if (vif_selected != -1) { 710 | hw_priv->hw_bufs_used_vif[vif_selected]++; 711 | } 712 | wsm_txed(hw_priv, data); 713 | hw_priv->wsm_tx_seq = (hw_priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX; 714 | 715 | return 1; 716 | } 717 | } else 718 | return 0; 719 | } 720 | 721 | static int xradio_bh_exchange(struct xradio_common *hw_priv) { 722 | int rxdone; 723 | int txdone; 724 | u16 nextlen = 0; 725 | 726 | /* query stuck frames in firmware. */ 727 | if (atomic_xchg(&hw_priv->query_cnt, 0)) { 728 | if (schedule_work(&hw_priv->query_work) <= 0) 729 | atomic_add(1, &hw_priv->query_cnt); 730 | } 731 | 732 | /* keep doing tx and rx until they both stop or we are told 733 | * to terminate */ 734 | do { 735 | txdone = xradio_bh_tx(hw_priv); 736 | if (txdone < 0) { 737 | break; 738 | } 739 | rxdone = xradio_bh_rx(hw_priv, &nextlen); 740 | if (rxdone < 0) { 741 | break; 742 | } 743 | } while ((txdone > 0 || rxdone > 0) && !kthread_should_stop()); 744 | return 0; 745 | } 746 | 747 | static int xradio_bh(void *arg) 748 | { 749 | struct xradio_common *hw_priv = arg; 750 | int term, suspend; 751 | int wake = 0; 752 | long timeout; 753 | long status; 754 | 755 | for (;;) { 756 | timeout = HZ / 30; 757 | 758 | // wait for something to happen or a timeout 759 | status = wait_event_interruptible_timeout(hw_priv->bh_wq, ( { 760 | wake = atomic_xchg(&hw_priv->bh_tx, 0); 761 | term = kthread_should_stop(); 762 | suspend = atomic_read(&hw_priv->bh_suspend); 763 | (wake || term || suspend);}), timeout); 764 | 765 | if (wake) { 766 | if(xradio_bh_exchange(hw_priv) < 0){ 767 | break; 768 | } 769 | } else if (term) { 770 | dev_dbg(hw_priv->pdev, "xradio_bh exit!\n"); 771 | break; 772 | } else if (status < 0) { 773 | dev_err(hw_priv->pdev, "bh_error=%d, status=%ld\n", 774 | hw_priv->bh_error, status); 775 | break; 776 | } else if (!status) { 777 | /* check if there is data waiting but we missed the interrupt*/ 778 | if (xradio_bh_rx_availlen(hw_priv) > 0) { 779 | dev_warn(hw_priv->pdev, "missed interrupt\n"); 780 | if(xradio_bh_exchange(hw_priv) < 0){ 781 | break; 782 | } 783 | } 784 | /* There are some frames to be confirmed. */ 785 | else if (hw_priv->hw_bufs_used) { 786 | long timeout = 0; 787 | bool pending = 0; 788 | dev_dbg(hw_priv->pdev, "Need confirm:%d!\n", 789 | hw_priv->hw_bufs_used); 790 | /* Check if frame transmission is timed out. */ 791 | pending = xradio_query_txpkt_timeout(hw_priv, XRWL_ALL_IFS, 792 | hw_priv->pending_frame_id, &timeout); 793 | /* There are some frames confirm time out. */ 794 | if (pending && timeout < 0) { 795 | dev_err(hw_priv->pdev, "query_txpkt_timeout:%ld!\n", 796 | timeout); 797 | break; 798 | } 799 | } //else if (!txpending){ 800 | //if (hw_priv->powersave_enabled && !hw_priv->device_can_sleep && !atomic_read(&hw_priv->recent_scan)) { 801 | // /* Device is idle, we can go to sleep. */ 802 | // dev_dbg(hw_priv->pdev, "Device idle(timeout), can sleep.\n"); 803 | // WARN_ON(xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, 0)); 804 | // hw_priv->device_can_sleep = true; 805 | //} 806 | //continue; 807 | //} 808 | } else if (suspend) { 809 | dev_dbg(hw_priv->pdev, "Host suspend request.\n"); 810 | /* Check powersave setting again. */ 811 | if (hw_priv->powersave_enabled) { 812 | dev_dbg(hw_priv->pdev, 813 | "Device idle(host suspend), can sleep.\n"); 814 | WARN_ON(xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, 0)); 815 | hw_priv->device_can_sleep = true; 816 | } 817 | 818 | /* bh thread go to suspend. */ 819 | atomic_set(&hw_priv->bh_suspend, XRADIO_BH_SUSPENDED); 820 | wake_up(&hw_priv->bh_evt_wq); 821 | status = wait_event_interruptible(hw_priv->bh_wq, 822 | XRADIO_BH_RESUME == atomic_read(&hw_priv->bh_suspend)); 823 | 824 | if (status < 0) { 825 | dev_err(hw_priv->pdev, "Failed to wait for resume: %ld.\n", 826 | status); 827 | break; 828 | } 829 | dev_dbg(hw_priv->pdev, "Host resume.\n"); 830 | atomic_set(&hw_priv->bh_suspend, XRADIO_BH_RESUMED); 831 | wake_up(&hw_priv->bh_evt_wq); 832 | } 833 | } /* for (;;)*/ 834 | 835 | dev_err(hw_priv->pdev, "bh thread exiting\n"); 836 | 837 | return 0; 838 | } 839 | -------------------------------------------------------------------------------- /bh.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Data Transmission thread for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #ifndef XRADIO_BH_H 13 | #define XRADIO_BH_H 14 | 15 | #define XRADIO_BH_THREAD "xradio_bh" 16 | 17 | /* extern */ struct xradio_common; 18 | 19 | #define SDIO_BLOCK_SIZE (528) 20 | 21 | int xradio_register_bh(struct xradio_common *hw_priv); 22 | void xradio_unregister_bh(struct xradio_common *hw_priv); 23 | void xradio_irq_handler(struct xradio_common *hw_priv); 24 | void xradio_bh_wakeup(struct xradio_common *hw_priv); 25 | int xradio_bh_suspend(struct xradio_common *hw_priv); 26 | int xradio_bh_resume(struct xradio_common *hw_priv); 27 | /* Must be called from BH thread. */ 28 | void xradio_enable_powersave(struct xradio_vif *priv, bool enable); 29 | int wsm_release_tx_buffer(struct xradio_common *hw_priv, int count); 30 | int wsm_release_vif_tx_buffer(struct xradio_common *hw_priv, int if_id, 31 | int count); 32 | int xradio_init_resv_skb(struct xradio_common *hw_priv); 33 | void xradio_deinit_resv_skb(struct xradio_common *hw_priv); 34 | int xradio_realloc_resv_skb(struct xradio_common *hw_priv, 35 | struct sk_buff *skb); 36 | #endif /* XRADIO_BH_H */ 37 | -------------------------------------------------------------------------------- /common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Common interfaces for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #ifndef XRADIO_COMMON_H 13 | #define XRADIO_COMMON_H 14 | 15 | /******************************************************* 16 | interfaces for parse frame protocol info. 17 | ********************************************************/ 18 | #define LLC_LEN 8 19 | #define LLC_TYPE_OFF 6 //Ether type offset 20 | #define IP_PROTO_OFF 9 //protocol offset 21 | #define IP_S_ADD_OFF 12 22 | #define IP_D_ADD_OFF 16 23 | #define UDP_LEN 8 24 | //DHCP 25 | #define DHCP_BOOTP_C 68 26 | #define DHCP_BOOTP_S 67 27 | #define UDP_BOOTP_LEN 236 //exclude "Options:64" 28 | #define BOOTP_OPS_LEN 64 29 | #define DHCP_MAGIC 0x63825363 30 | #define DHCP_DISCOVER 0x01 31 | #define DHCP_OFFER 0x02 32 | #define DHCP_REQUEST 0x03 33 | #define DHCP_DECLINE 0x04 34 | #define DHCP_ACK 0x05 35 | #define DHCP_NACK 0x06 36 | #define DHCP_RELEASE 0x07 37 | 38 | //LLC layer. 39 | static inline bool is_SNAP(u8* llc_data) 40 | { 41 | return (bool)(*(u16*)(llc_data) == 0xAAAA && llc_data[2] == 0x03); //0xAA, 0xAA, 0x03. 42 | } 43 | 44 | static inline bool is_STP(u8* llc_data) 45 | { 46 | return (bool)(*(u16*)(llc_data) == 0xAAAA && llc_data[2] == 0x03); //0x42, 0x42, 0x03. 47 | } 48 | 49 | //IP/IPV6/ARP layer... 50 | static inline bool is_ip(u8* llc_data) 51 | { 52 | return (bool)(*(u16*)(llc_data+LLC_TYPE_OFF) == cpu_to_be16(ETH_P_IP)); //0x0800 53 | } 54 | static inline bool is_ipv6(u8* llc_data) 55 | { 56 | return (bool)(*(u16*)(llc_data+LLC_TYPE_OFF) == cpu_to_be16(ETH_P_IPV6)); //0x08dd 57 | } 58 | static inline bool is_arp(u8* llc_data) 59 | { 60 | return (bool)(*(u16*)(llc_data+LLC_TYPE_OFF) == cpu_to_be16(ETH_P_ARP)); //0x0806 61 | } 62 | static inline bool is_8021x(u8* llc_data) 63 | { 64 | return (bool)(*(u16*)(llc_data+LLC_TYPE_OFF) == cpu_to_be16(ETH_P_PAE)); //0x888E 65 | } 66 | 67 | //TCP/UDP layer... 68 | static inline bool is_tcp(u8* llc_data) 69 | { 70 | return (bool)(llc_data[LLC_LEN+IP_PROTO_OFF] == IPPROTO_TCP); // 71 | } 72 | 73 | static inline bool is_udp(u8* llc_data) 74 | { 75 | return (bool)(llc_data[LLC_LEN+IP_PROTO_OFF] == IPPROTO_UDP); // 76 | } 77 | 78 | static inline bool is_icmp(u8* llc_data) 79 | { 80 | return (bool)(llc_data[LLC_LEN+IP_PROTO_OFF] == IPPROTO_ICMP); // 81 | } 82 | 83 | static inline bool is_igmp(u8* llc_data) 84 | { 85 | return (bool)(llc_data[LLC_LEN+IP_PROTO_OFF] == IPPROTO_IGMP); // 86 | } 87 | 88 | static inline bool is_dhcp(u8* llc_data) 89 | { 90 | u8* ip_hdr = llc_data+LLC_LEN; 91 | if(!is_ip(llc_data)) 92 | return (bool)0; 93 | if(ip_hdr[IP_PROTO_OFF] == IPPROTO_UDP) { 94 | u8* udp_hdr = ip_hdr+((ip_hdr[0]&0xf)<<2); //ihl:words 95 | return (bool)((((udp_hdr[0]<<8)|udp_hdr[1]) == DHCP_BOOTP_C) || //DHCP client 96 | (((udp_hdr[0]<<8)|udp_hdr[1]) == DHCP_BOOTP_S)); //DHCP server 97 | } 98 | return (bool)0; 99 | } 100 | 101 | #endif //XRADIO_COMMON_H 102 | -------------------------------------------------------------------------------- /debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * DebugFS code for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | #ifndef XRADIO_DEBUG_H_INCLUDED 12 | #define XRADIO_DEBUG_H_INCLUDED 13 | 14 | #define xradio_dbg(level, ...) 15 | #define txrx_printk(level, ...) 16 | #define wsm_printk(level, ...) 17 | #define sta_printk(level, ...) 18 | #define scan_printk(level, ...) 19 | #define ap_printk(level, ...) 20 | #define pm_printk(level, ...) 21 | 22 | #endif /* XRADIO_DEBUG_H_INCLUDED */ 23 | -------------------------------------------------------------------------------- /fwio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Firmware I/O implementation for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "xradio.h" 18 | #include "fwio.h" 19 | #include "hwio.h" 20 | #include "bh.h" 21 | #include "sdio.h" 22 | 23 | /* Macroses are local. */ 24 | #define APB_WRITE(reg, val) \ 25 | do { \ 26 | ret = xradio_apb_write_32(hw_priv, APB_ADDR(reg), (val)); \ 27 | if (ret < 0) { \ 28 | dev_err(hw_priv->pdev, \ 29 | "%s: can't write %s at line %d.\n", \ 30 | __func__, #reg, __LINE__); \ 31 | goto error; \ 32 | } \ 33 | } while (0) 34 | #define APB_READ(reg, val) \ 35 | do { \ 36 | ret = xradio_apb_read_32(hw_priv, APB_ADDR(reg), &(val)); \ 37 | if (ret < 0) { \ 38 | dev_err(hw_priv->pdev, \ 39 | "%s: can't read %s at line %d.\n", \ 40 | __func__, #reg, __LINE__); \ 41 | goto error; \ 42 | } \ 43 | } while (0) 44 | #define REG_WRITE(reg, val) \ 45 | do { \ 46 | ret = xradio_reg_write_32(hw_priv, (reg), (val)); \ 47 | if (ret < 0) { \ 48 | dev_err(hw_priv->pdev, \ 49 | "%s: can't write %s at line %d.\n", \ 50 | __func__, #reg, __LINE__); \ 51 | goto error; \ 52 | } \ 53 | } while (0) 54 | #define REG_READ(reg, val) \ 55 | do { \ 56 | ret = xradio_reg_read_32(hw_priv, (reg), &(val)); \ 57 | if (ret < 0) { \ 58 | dev_err(hw_priv->pdev, \ 59 | "%s: can't read %s at line %d.\n", \ 60 | __func__, #reg, __LINE__); \ 61 | goto error; \ 62 | } \ 63 | } while (0) 64 | 65 | 66 | static int xradio_get_hw_type(u32 config_reg_val, int *major_revision) 67 | { 68 | int hw_type = -1; 69 | u32 hif_type = (config_reg_val >> 24) & 0x4; 70 | //u32 hif_vers = (config_reg_val >> 31) & 0x1; 71 | 72 | /* Check if we have XRADIO*/ 73 | if (hif_type == 0x4) { 74 | *major_revision = 0x4; 75 | hw_type = HIF_HW_TYPE_XRADIO; 76 | } else { 77 | //hw type unknown. 78 | *major_revision = 0x0; 79 | } 80 | return hw_type; 81 | } 82 | 83 | /* 84 | * This function is called to Parse the SDD file 85 | * to extract some informations 86 | */ 87 | static int xradio_parse_sdd(struct xradio_common *hw_priv, u32 *dpll) 88 | { 89 | int ret = 0; 90 | const char *sdd_path = NULL; 91 | struct xradio_sdd *pElement = NULL; 92 | int parsedLength = 0; 93 | 94 | BUG_ON(hw_priv->sdd != NULL); 95 | 96 | /* select and load sdd file depend on hardware version. */ 97 | switch (hw_priv->hw_revision) { 98 | case XR819_HW_REV0: 99 | sdd_path = XR819_SDD_FILE; 100 | break; 101 | default: 102 | dev_dbg(hw_priv->pdev, "unknown hardware version.\n"); 103 | return ret; 104 | } 105 | 106 | ret = request_firmware(&hw_priv->sdd, sdd_path, hw_priv->pdev); 107 | if (unlikely(ret)) { 108 | dev_dbg(hw_priv->pdev, "can't load sdd file %s.\n", 109 | sdd_path); 110 | return ret; 111 | } 112 | 113 | //parse SDD config. 114 | hw_priv->is_BT_Present = false; 115 | pElement = (struct xradio_sdd *)hw_priv->sdd->data; 116 | parsedLength += (FIELD_OFFSET(struct xradio_sdd, data) + pElement->length); 117 | pElement = FIND_NEXT_ELT(pElement); 118 | 119 | while (parsedLength < hw_priv->sdd->size) { 120 | switch (pElement->id) { 121 | case SDD_PTA_CFG_ELT_ID: 122 | hw_priv->conf_listen_interval = (*((u16 *)pElement->data+1) >> 7) & 0x1F; 123 | hw_priv->is_BT_Present = true; 124 | xradio_dbg(XRADIO_DBG_NIY, "PTA element found.Listen Interval %d\n", 125 | hw_priv->conf_listen_interval); 126 | break; 127 | case SDD_REFERENCE_FREQUENCY_ELT_ID: 128 | switch(*((uint16_t*)pElement->data)) { 129 | case 0x32C8: 130 | *dpll = 0x1D89D241; 131 | break; 132 | case 0x3E80: 133 | *dpll = 0x1E1; 134 | break; 135 | case 0x41A0: 136 | *dpll = 0x124931C1; 137 | break; 138 | case 0x4B00: 139 | *dpll = 0x191; 140 | break; 141 | case 0x5DC0: 142 | *dpll = 0x141; 143 | break; 144 | case 0x6590: 145 | *dpll = 0x0EC4F121; 146 | break; 147 | case 0x8340: 148 | *dpll = 0x92490E1; 149 | break; 150 | case 0x9600: 151 | *dpll = 0x100010C1; 152 | break; 153 | case 0x9C40: 154 | *dpll = 0xC1; 155 | break; 156 | case 0xBB80: 157 | *dpll = 0xA1; 158 | break; 159 | case 0xCB20: 160 | *dpll = 0x7627091; 161 | break; 162 | default: 163 | *dpll = DPLL_INIT_VAL_XRADIO; 164 | xradio_dbg(XRADIO_DBG_WARN, "Unknown Reference clock frequency." 165 | "Use default DPLL value=0x%08x.", DPLL_INIT_VAL_XRADIO); 166 | break; 167 | } 168 | default: 169 | break; 170 | } 171 | parsedLength += (FIELD_OFFSET(struct xradio_sdd, data) + pElement->length); 172 | pElement = FIND_NEXT_ELT(pElement); 173 | } 174 | 175 | dev_dbg(hw_priv->pdev, "sdd size=%zu parse len=%d.\n", 176 | hw_priv->sdd->size, parsedLength); 177 | 178 | // 179 | if (hw_priv->is_BT_Present == false) { 180 | hw_priv->conf_listen_interval = 0; 181 | xradio_dbg(XRADIO_DBG_NIY, "PTA element NOT found.\n"); 182 | } 183 | return ret; 184 | } 185 | 186 | static int xradio_firmware(struct xradio_common *hw_priv) 187 | { 188 | int ret, block, num_blocks; 189 | unsigned i; 190 | u32 val32; 191 | u32 put = 0, get = 0; 192 | u8 *buf = NULL; 193 | const char *fw_path; 194 | const struct firmware *firmware = NULL; 195 | 196 | switch (hw_priv->hw_revision) { 197 | case XR819_HW_REV0: 198 | fw_path = XR819_FIRMWARE; 199 | break; 200 | default: 201 | dev_dbg(hw_priv->pdev, "invalid silicon revision %d.\n", 202 | hw_priv->hw_revision); 203 | return -EINVAL; 204 | } 205 | /* Initialize common registers */ 206 | APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, DOWNLOAD_ARE_YOU_HERE); 207 | APB_WRITE(DOWNLOAD_PUT_REG, 0); 208 | APB_WRITE(DOWNLOAD_GET_REG, 0); 209 | APB_WRITE(DOWNLOAD_STATUS_REG, DOWNLOAD_PENDING); 210 | APB_WRITE(DOWNLOAD_FLAGS_REG, 0); 211 | 212 | /* Release CPU from RESET */ 213 | REG_READ(HIF_CONFIG_REG_ID, val32); 214 | val32 &= ~HIF_CONFIG_CPU_RESET_BIT; 215 | REG_WRITE(HIF_CONFIG_REG_ID, val32); 216 | 217 | /* Enable Clock */ 218 | val32 &= ~HIF_CONFIG_CPU_CLK_DIS_BIT; 219 | REG_WRITE(HIF_CONFIG_REG_ID, val32); 220 | 221 | /* Load a firmware file */ 222 | ret = request_firmware(&firmware, fw_path, hw_priv->pdev); 223 | if (ret) { 224 | dev_dbg(hw_priv->pdev, "can't load firmware file %s.\n", 225 | fw_path); 226 | goto error; 227 | } 228 | BUG_ON(!firmware->data); 229 | 230 | buf = kmalloc(DOWNLOAD_BLOCK_SIZE, GFP_KERNEL); 231 | if (!buf) { 232 | dev_dbg(hw_priv->pdev, "can't allocate firmware buffer.\n"); 233 | ret = -ENOMEM; 234 | goto error; 235 | } 236 | 237 | /* Check if the bootloader is ready */ 238 | for (i = 0; i < 100; i++/*= 1 + i / 2*/) { 239 | APB_READ(DOWNLOAD_IMAGE_SIZE_REG, val32); 240 | if (val32 == DOWNLOAD_I_AM_HERE) 241 | break; 242 | mdelay(10); 243 | } /* End of for loop */ 244 | if (val32 != DOWNLOAD_I_AM_HERE) { 245 | dev_dbg(hw_priv->pdev, "bootloader is not ready.\n"); 246 | ret = -ETIMEDOUT; 247 | goto error; 248 | } 249 | 250 | /* Calculcate number of download blocks */ 251 | num_blocks = (firmware->size - 1) / DOWNLOAD_BLOCK_SIZE + 1; 252 | 253 | /* Updating the length in Download Ctrl Area */ 254 | val32 = firmware->size; /* Explicit cast from size_t to u32 */ 255 | APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, val32); 256 | 257 | /* Firmware downloading loop */ 258 | for (block = 0; block < num_blocks ; block++) { 259 | size_t tx_size; 260 | size_t block_size; 261 | 262 | /* check the download status */ 263 | APB_READ(DOWNLOAD_STATUS_REG, val32); 264 | if (val32 != DOWNLOAD_PENDING) { 265 | dev_dbg(hw_priv->pdev, "bootloader reported error %d.\n", 266 | val32); 267 | ret = -EIO; 268 | goto error; 269 | } 270 | 271 | /* loop until put - get <= 24K */ 272 | for (i = 0; i < 100; i++) { 273 | APB_READ(DOWNLOAD_GET_REG, get); 274 | if ((put - get) <= (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) 275 | break; 276 | mdelay(i); 277 | } 278 | 279 | if ((put - get) > (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) { 280 | dev_dbg(hw_priv->pdev, "Timeout waiting for FIFO.\n"); 281 | ret = -ETIMEDOUT; 282 | goto error; 283 | } 284 | 285 | /* calculate the block size */ 286 | tx_size = block_size = min((size_t)(firmware->size - put), (size_t)DOWNLOAD_BLOCK_SIZE); 287 | memcpy(buf, &firmware->data[put], block_size); 288 | 289 | if (block_size < DOWNLOAD_BLOCK_SIZE) { 290 | memset(&buf[block_size], 0, DOWNLOAD_BLOCK_SIZE - block_size); 291 | tx_size = DOWNLOAD_BLOCK_SIZE; 292 | } 293 | 294 | /* send the block to sram */ 295 | ret = xradio_apb_write(hw_priv, APB_ADDR(DOWNLOAD_FIFO_OFFSET + (put & (DOWNLOAD_FIFO_SIZE - 1))), 296 | buf, tx_size); 297 | if (ret < 0) { 298 | dev_err(hw_priv->pdev, "%s: can't write block at line %d.\n", __func__, __LINE__); 299 | goto error; 300 | } 301 | 302 | /* update the put register */ 303 | put += block_size; 304 | APB_WRITE(DOWNLOAD_PUT_REG, put); 305 | } /* End of firmware download loop */ 306 | 307 | /* Wait for the download completion */ 308 | for (i = 0; i < 300; i += 1 + i / 2) { 309 | APB_READ(DOWNLOAD_STATUS_REG, val32); 310 | if (val32 != DOWNLOAD_PENDING) 311 | break; 312 | mdelay(i); 313 | } 314 | if (val32 != DOWNLOAD_SUCCESS) { 315 | dev_dbg(hw_priv->pdev, "wait for download completion failed. " \ 316 | "Read: 0x%.8X\n", val32); 317 | ret = -ETIMEDOUT; 318 | goto error; 319 | } else { 320 | dev_dbg(hw_priv->pdev, "Firmware completed.\n"); 321 | ret = 0; 322 | } 323 | 324 | error: 325 | if(buf) 326 | kfree(buf); 327 | if (firmware) { 328 | release_firmware(firmware); 329 | } 330 | return ret; 331 | } 332 | 333 | static int xradio_bootloader(struct xradio_common *hw_priv) 334 | { 335 | const char *bl_path = XR819_BOOTLOADER; 336 | u32 addr = AHB_MEMORY_ADDRESS; 337 | int ret; 338 | u32 i; 339 | u32 *data; 340 | const struct firmware *bootloader; 341 | 342 | /* Load a bootloader file */ 343 | ret = request_firmware(&bootloader, bl_path, hw_priv->pdev); 344 | if (ret) { 345 | dev_dbg(hw_priv->pdev, "can't load bootloader file %s.\n", 346 | bl_path); 347 | goto error; 348 | } 349 | 350 | /* Down bootloader. */ 351 | data = (u32 *)bootloader->data; 352 | for(i = 0; i < (bootloader->size)/4; i++, addr+=4) { 353 | REG_WRITE(HIF_SRAM_BASE_ADDR_REG_ID, addr); 354 | REG_WRITE(HIF_AHB_DPORT_REG_ID,data[i]); 355 | } 356 | dev_dbg(hw_priv->pdev, "Bootloader complete\n"); 357 | 358 | error: 359 | if(bootloader) { 360 | release_firmware(bootloader); 361 | } 362 | return ret; 363 | } 364 | 365 | bool test_retry = false; 366 | int xradio_load_firmware(struct xradio_common *hw_priv) 367 | { 368 | int ret; 369 | int i; 370 | u32 val32; 371 | u16 val16; 372 | u32 dpll = 0; 373 | int major_revision; 374 | 375 | /* Read CONFIG Register Value - We will read 32 bits */ 376 | ret = xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); 377 | if (ret < 0) { 378 | dev_dbg(hw_priv->pdev, "can't read config register, err=%d.\n", 379 | ret); 380 | return ret; 381 | } 382 | 383 | //check hardware type and revision. 384 | hw_priv->hw_type = xradio_get_hw_type(val32, &major_revision); 385 | switch (hw_priv->hw_type) { 386 | case HIF_HW_TYPE_XRADIO: 387 | dev_dbg(hw_priv->pdev, "HW_TYPE_XRADIO detected.\n"); 388 | break; 389 | default: 390 | dev_dbg(hw_priv->pdev, "Unknown hardware: %d.\n", 391 | hw_priv->hw_type); 392 | return -ENOTSUPP; 393 | } 394 | if (major_revision == 4) { 395 | hw_priv->hw_revision = XR819_HW_REV0; 396 | dev_dbg(hw_priv->pdev, "XRADIO_HW_REV 1.0 detected.\n"); 397 | } else { 398 | dev_dbg(hw_priv->pdev, "Unsupported major revision %d.\n", 399 | major_revision); 400 | return -ENOTSUPP; 401 | } 402 | 403 | //load sdd file, and get config from it. 404 | ret = xradio_parse_sdd(hw_priv, &dpll); 405 | if (ret < 0) { 406 | return ret; 407 | } 408 | 409 | //set dpll initial value and check. 410 | ret = xradio_reg_write_32(hw_priv, HIF_TSET_GEN_R_W_REG_ID, dpll); 411 | if (ret < 0) { 412 | dev_dbg(hw_priv->pdev, "can't write DPLL register.\n"); 413 | goto out; 414 | } 415 | msleep(5); 416 | ret = xradio_reg_read_32(hw_priv, HIF_TSET_GEN_R_W_REG_ID, &val32); 417 | if (ret < 0) { 418 | dev_dbg(hw_priv->pdev, "can't read DPLL register.\n"); 419 | goto out; 420 | } 421 | if (val32 != dpll) { 422 | dev_dbg(hw_priv->pdev, "unable to initialise " \ 423 | "DPLL register. Wrote 0x%.8X, read 0x%.8X.\n", 424 | dpll, val32); 425 | ret = -EIO; 426 | goto out; 427 | } 428 | 429 | /* Set wakeup bit in device */ 430 | ret = xradio_reg_read_16(hw_priv, HIF_CONTROL_REG_ID, &val16); 431 | if (ret < 0) { 432 | dev_dbg(hw_priv->pdev, "set_wakeup: can't read control register.\n"); 433 | goto out; 434 | } 435 | ret = xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, val16 | HIF_CTRL_WUP_BIT); 436 | if (ret < 0) { 437 | dev_dbg(hw_priv->pdev, "set_wakeup: can't write control register.\n"); 438 | goto out; 439 | } 440 | 441 | /* Wait for wakeup */ 442 | for (i = 0 ; i < 300 ; i += 1 + i / 2) { 443 | ret = xradio_reg_read_16(hw_priv, HIF_CONTROL_REG_ID, &val16); 444 | if (ret < 0) { 445 | dev_dbg(hw_priv->pdev, "Wait_for_wakeup: " 446 | "can't read control register.\n"); 447 | goto out; 448 | } 449 | if (val16 & HIF_CTRL_RDY_BIT) { 450 | break; 451 | } 452 | msleep(i); 453 | } 454 | if ((val16 & HIF_CTRL_RDY_BIT) == 0) { 455 | dev_dbg(hw_priv->pdev, "Wait for wakeup:" 456 | "device is not responding.\n"); 457 | ret = -ETIMEDOUT; 458 | goto out; 459 | } else { 460 | dev_dbg(hw_priv->pdev, "WLAN device is ready.\n"); 461 | } 462 | 463 | /* Checking for access mode and download firmware. */ 464 | ret = xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); 465 | if (ret < 0) { 466 | dev_dbg(hw_priv->pdev, "check_access_mode: " 467 | "can't read config register.\n"); 468 | goto out; 469 | } 470 | if (val32 & HIF_CONFIG_ACCESS_MODE_BIT) { 471 | /* Down bootloader. */ 472 | ret = xradio_bootloader(hw_priv); 473 | if (ret < 0) { 474 | dev_dbg(hw_priv->pdev, "can't download bootloader.\n"); 475 | goto out; 476 | } 477 | /* Down firmware. */ 478 | ret = xradio_firmware(hw_priv); 479 | if (ret < 0) { 480 | dev_dbg(hw_priv->pdev, "can't download firmware.\n"); 481 | goto out; 482 | } 483 | } else { 484 | dev_dbg(hw_priv->pdev, "check_access_mode: " 485 | "device is already in QUEUE mode.\n"); 486 | /* TODO: verify this branch. Do we need something to do? */ 487 | } 488 | 489 | if (HIF_HW_TYPE_XRADIO == hw_priv->hw_type) { 490 | /* If device is XRADIO the IRQ enable/disable bits 491 | * are in CONFIG register */ 492 | ret = xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); 493 | if (ret < 0) { 494 | dev_dbg(hw_priv->pdev, "enable_irq: can't read " \ 495 | "config register.\n"); 496 | goto unsubscribe; 497 | } 498 | ret = xradio_reg_write_32(hw_priv, HIF_CONFIG_REG_ID, 499 | val32 | HIF_CONF_IRQ_RDY_ENABLE); 500 | if (ret < 0) { 501 | dev_dbg(hw_priv->pdev, "enable_irq: can't write " \ 502 | "config register.\n"); 503 | goto unsubscribe; 504 | } 505 | } else { 506 | /* If device is XRADIO the IRQ enable/disable bits 507 | * are in CONTROL register */ 508 | /* Enable device interrupts - Both DATA_RDY and WLAN_RDY */ 509 | ret = xradio_reg_read_16(hw_priv, HIF_CONFIG_REG_ID, &val16); 510 | if (ret < 0) { 511 | dev_dbg(hw_priv->pdev, "enable_irq: can't read " \ 512 | "control register.\n"); 513 | goto unsubscribe; 514 | } 515 | ret = xradio_reg_write_16(hw_priv, HIF_CONFIG_REG_ID, 516 | val16 | HIF_CTRL_IRQ_RDY_ENABLE); 517 | if (ret < 0) { 518 | dev_dbg(hw_priv->pdev, "enable_irq: can't write " \ 519 | "control register.\n"); 520 | goto unsubscribe; 521 | } 522 | 523 | } 524 | 525 | /* Configure device for MESSSAGE MODE */ 526 | ret = xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); 527 | if (ret < 0) { 528 | dev_dbg(hw_priv->pdev, "set_mode: can't read config register.\n"); 529 | goto unsubscribe; 530 | } 531 | ret = xradio_reg_write_32(hw_priv, HIF_CONFIG_REG_ID, 532 | val32 & ~HIF_CONFIG_ACCESS_MODE_BIT); 533 | if (ret < 0) { 534 | dev_dbg(hw_priv->pdev, "set_mode: can't write config register.\n"); 535 | goto unsubscribe; 536 | } 537 | 538 | /* Unless we read the CONFIG Register we are 539 | * not able to get an interrupt */ 540 | mdelay(10); 541 | xradio_reg_read_32(hw_priv, HIF_CONFIG_REG_ID, &val32); 542 | return 0; 543 | 544 | unsubscribe: 545 | out: 546 | if (hw_priv->sdd) { 547 | release_firmware(hw_priv->sdd); 548 | hw_priv->sdd = NULL; 549 | } 550 | return ret; 551 | } 552 | 553 | int xradio_dev_deinit(struct xradio_common *hw_priv) 554 | { 555 | if (hw_priv->sdd) { 556 | release_firmware(hw_priv->sdd); 557 | hw_priv->sdd = NULL; 558 | } 559 | return 0; 560 | } 561 | -------------------------------------------------------------------------------- /fwio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Firmware APIs for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | #ifndef FWIO_H_INCLUDED 12 | #define FWIO_H_INCLUDED 13 | 14 | #define XR819_HW_REV0 (8190) 15 | #define XR819_BOOTLOADER ("xr819/boot_xr819.bin") 16 | #define XR819_FIRMWARE ("xr819/fw_xr819.bin") 17 | #define XR819_SDD_FILE ("xr819/sdd_xr819.bin") 18 | 19 | #define SDD_PTA_CFG_ELT_ID 0xEB 20 | #define SDD_REFERENCE_FREQUENCY_ELT_ID 0xC5 21 | #define FIELD_OFFSET(type, field) ((u8 *)&((type *)0)->field - (u8 *)0) 22 | #define FIND_NEXT_ELT(e) (struct xradio_sdd *)((u8 *)&e->data + e->length) 23 | struct xradio_sdd { 24 | u8 id; 25 | u8 length; 26 | u8 data[]; 27 | }; 28 | 29 | struct xradio_common; 30 | int xradio_load_firmware(struct xradio_common *hw_priv); 31 | int xradio_dev_deinit(struct xradio_common *hw_priv); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /ht.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "xradio.h" 4 | #include "sta.h" 5 | 6 | #define AG_RATE_INDEX 6 //11a/g rate for important short frames in 5G. 7 | 8 | #ifdef AP_HT_COMPAT_FIX 9 | #define AP_COMPAT_THRESHOLD 2000 10 | #define AP_COMPAT_MIN_CNT 200 11 | u8 ap_compat_bssid[ETH_ALEN] = {0}; 12 | int xradio_apcompat_detect(struct xradio_vif *priv, u8 rx_rate) 13 | { 14 | if (rx_rate < AG_RATE_INDEX) { 15 | priv->ht_compat_cnt++; 16 | txrx_printk(XRADIO_DBG_MSG,"%s:rate=%d.\n", __func__, rx_rate); 17 | } else { 18 | priv->ht_compat_det |= 1; 19 | priv->ht_compat_cnt = 0; 20 | txrx_printk(XRADIO_DBG_NIY,"%s:HT compat detect\n", __func__); 21 | return 0; 22 | } 23 | 24 | /* Enhance compatibility with some illegal APs.*/ 25 | if (priv->ht_compat_cnt > AP_COMPAT_THRESHOLD || 26 | (priv->ht_compat_cnt > AP_COMPAT_MIN_CNT && 27 | priv->bssid[0] == 0xC8 && 28 | priv->bssid[1] == 0x3A && 29 | priv->bssid[2] == 0x35)) { 30 | struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); 31 | memcpy(ap_compat_bssid, priv->bssid, ETH_ALEN); 32 | wms_send_disassoc_to_self(hw_priv, priv); 33 | txrx_printk(XRADIO_DBG_WARN, "%s:SSID=%s, BSSID=" \ 34 | "%02x:%02x:%02x:%02x:%02x:%02x\n", __func__, priv->ssid, 35 | ap_compat_bssid[0], ap_compat_bssid[1], 36 | ap_compat_bssid[2], ap_compat_bssid[3], 37 | ap_compat_bssid[4], ap_compat_bssid[5]); 38 | return 1; 39 | } 40 | return 0; 41 | } 42 | 43 | void xradio_remove_ht_ie(struct xradio_vif *priv, struct sk_buff *skb) 44 | { 45 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 46 | u8 *ies = NULL; 47 | size_t ies_len = 0; 48 | u8 *ht_ie = NULL; 49 | 50 | if (!mgmt || memcmp(ap_compat_bssid, mgmt->bssid, ETH_ALEN)) 51 | return; 52 | 53 | if (ieee80211_is_probe_resp(mgmt->frame_control)) 54 | ies = mgmt->u.probe_resp.variable; 55 | else if (ieee80211_is_beacon(mgmt->frame_control)) 56 | ies = mgmt->u.beacon.variable; 57 | else if (ieee80211_is_assoc_resp(mgmt->frame_control)) 58 | ies = mgmt->u.assoc_resp.variable; 59 | else if (ieee80211_is_assoc_req(mgmt->frame_control)) 60 | ies = mgmt->u.assoc_req.variable; 61 | else 62 | return; 63 | 64 | ies_len = skb->len - (ies - (u8 *)(skb->data)); 65 | ht_ie = (u8 *)xradio_get_ie(ies, ies_len, WLAN_EID_HT_CAPABILITY); 66 | if (ht_ie) { 67 | u8 ht_len = *(ht_ie + 1) + 2; 68 | u8 move_len = (ies + ies_len) - (ht_ie + ht_len); 69 | memmove(ht_ie, (ht_ie + ht_len), move_len); 70 | skb_trim(skb, skb->len - ht_len); 71 | ies_len = skb->len - (ies - (u8 *)(skb->data)); 72 | ht_ie = (u8 *)xradio_get_ie(ies, ies_len, WLAN_EID_HT_OPERATION); 73 | if (ht_ie) { 74 | ht_len = *(ht_ie + 1) + 2; 75 | move_len = (ies + ies_len) - (ht_ie + ht_len); 76 | memmove(ht_ie, (ht_ie + ht_len), move_len); 77 | skb_trim(skb, skb->len - ht_len); 78 | } 79 | } 80 | txrx_printk(XRADIO_DBG_WARN, "%s: BSSID=%02x:%02x:%02x:%02x:%02x:%02x\n", 81 | __func__, 82 | mgmt->bssid[0], mgmt->bssid[1], 83 | mgmt->bssid[2], mgmt->bssid[3], 84 | mgmt->bssid[4], mgmt->bssid[5]); 85 | } 86 | #endif //AP_HT_COMPAT_FIX -------------------------------------------------------------------------------- /ht.h: -------------------------------------------------------------------------------- 1 | /* 2 | * HT-related code for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | #ifndef XRADIO_HT_H_INCLUDED 12 | #define XRADIO_HT_H_INCLUDED 13 | 14 | #include 15 | 16 | struct xradio_ht_oper { 17 | struct ieee80211_sta_ht_cap ht_cap; 18 | enum nl80211_channel_type channel_type; 19 | u16 operation_mode; 20 | }; 21 | 22 | static inline int xradio_is_ht(const struct xradio_ht_oper *ht_oper) 23 | { 24 | return ht_oper->channel_type != NL80211_CHAN_NO_HT; 25 | } 26 | 27 | static inline int xradio_ht_greenfield(const struct xradio_ht_oper *ht_oper) 28 | { 29 | return (xradio_is_ht(ht_oper) && 30 | (ht_oper->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && 31 | !(ht_oper->operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)); 32 | } 33 | 34 | static inline int xradio_ht_ampdu_density(const struct xradio_ht_oper *ht_oper) 35 | { 36 | if (!xradio_is_ht(ht_oper)) 37 | return 0; 38 | return ht_oper->ht_cap.ampdu_density; 39 | } 40 | 41 | int xradio_apcompat_detect(struct xradio_vif *priv, u8 rx_rate); 42 | void xradio_remove_ht_ie(struct xradio_vif *priv, struct sk_buff *skb); 43 | 44 | #endif /* XRADIO_HT_H_INCLUDED */ 45 | -------------------------------------------------------------------------------- /hwio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Hardware I/O implementation for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #include 13 | 14 | #include "xradio.h" 15 | #include "hwio.h" 16 | #include "sdio.h" 17 | 18 | #define CHECK_ADDR_LEN 1 19 | 20 | /* Sdio addr is 4*spi_addr */ 21 | #define SPI_REG_ADDR_TO_SDIO(spi_reg_addr) ((spi_reg_addr) << 2) 22 | #define SDIO_ADDR17BIT(buf_id, mpf, rfu, reg_id_ofs) \ 23 | ((((buf_id) & 0x1F) << 7) \ 24 | | (((mpf) & 1) << 6) \ 25 | | (((rfu) & 1) << 5) \ 26 | | (((reg_id_ofs) & 0x1F) << 0)) 27 | #define MAX_RETRY 3 28 | 29 | 30 | static int __xradio_read(struct xradio_common *hw_priv, u16 addr, 31 | void *buf, size_t buf_len, int buf_id) 32 | { 33 | u16 addr_sdio; 34 | u32 sdio_reg_addr_17bit ; 35 | 36 | #if (CHECK_ADDR_LEN) 37 | /* Check if buffer is aligned to 4 byte boundary */ 38 | if (WARN_ON(((unsigned long)buf & 3) && (buf_len > 4))) { 39 | dev_dbg(hw_priv->pdev, "buffer is not aligned.\n"); 40 | return -EINVAL; 41 | } 42 | #endif 43 | 44 | /* Convert to SDIO Register Address */ 45 | addr_sdio = SPI_REG_ADDR_TO_SDIO(addr); 46 | sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio); 47 | return sdio_data_read(hw_priv, 48 | sdio_reg_addr_17bit, 49 | buf, buf_len); 50 | } 51 | 52 | static int __xradio_write(struct xradio_common *hw_priv, u16 addr, 53 | const void *buf, size_t buf_len, int buf_id) 54 | { 55 | u16 addr_sdio; 56 | u32 sdio_reg_addr_17bit ; 57 | 58 | #if (CHECK_ADDR_LEN) 59 | /* Check if buffer is aligned to 4 byte boundary */ 60 | if (WARN_ON(((unsigned long)buf & 3) && (buf_len > 4))) { 61 | dev_err(hw_priv->pdev, "buffer is not aligned.\n"); 62 | return -EINVAL; 63 | } 64 | #endif 65 | 66 | /* Convert to SDIO Register Address */ 67 | addr_sdio = SPI_REG_ADDR_TO_SDIO(addr); 68 | sdio_reg_addr_17bit = SDIO_ADDR17BIT(buf_id, 0, 0, addr_sdio); 69 | 70 | return sdio_data_write(hw_priv, 71 | sdio_reg_addr_17bit, 72 | buf, buf_len); 73 | } 74 | 75 | static inline int __xradio_read_reg32(struct xradio_common *hw_priv, 76 | u16 addr, u32 *val) 77 | { 78 | return __xradio_read(hw_priv, addr, val, sizeof(val), 0); 79 | } 80 | 81 | static inline int __xradio_write_reg32(struct xradio_common *hw_priv, 82 | u16 addr, u32 val) 83 | { 84 | return __xradio_write(hw_priv, addr, &val, sizeof(val), 0); 85 | } 86 | 87 | int xradio_reg_read(struct xradio_common *hw_priv, u16 addr, 88 | void *buf, size_t buf_len) 89 | { 90 | int ret; 91 | sdio_lock(hw_priv); 92 | ret = __xradio_read(hw_priv, addr, buf, buf_len, 0); 93 | sdio_unlock(hw_priv); 94 | return ret; 95 | } 96 | 97 | int xradio_reg_write(struct xradio_common *hw_priv, u16 addr, 98 | const void *buf, size_t buf_len) 99 | { 100 | int ret; 101 | sdio_lock(hw_priv); 102 | ret = __xradio_write(hw_priv, addr, buf, buf_len, 0); 103 | sdio_unlock(hw_priv); 104 | return ret; 105 | } 106 | 107 | int xradio_data_read(struct xradio_common *hw_priv, void *buf, size_t buf_len) 108 | { 109 | int ret, retry = 1; 110 | sdio_lock(hw_priv); 111 | { 112 | int buf_id_rx = hw_priv->buf_id_rx; 113 | while (retry <= MAX_RETRY) { 114 | ret = __xradio_read(hw_priv, HIF_IN_OUT_QUEUE_REG_ID, buf, 115 | buf_len, buf_id_rx + 1); 116 | if (!ret) { 117 | buf_id_rx = (buf_id_rx + 1) & 3; 118 | hw_priv->buf_id_rx = buf_id_rx; 119 | break; 120 | } else { 121 | //~dgp this retrying stuff is silly as it can crash the fw if there is nothing to read 122 | dev_err(hw_priv->pdev, "data read error :%d - attempt %d of %d\n", ret, retry, MAX_RETRY); 123 | retry++; 124 | mdelay(1); 125 | } 126 | } 127 | } 128 | sdio_unlock(hw_priv); 129 | return ret; 130 | } 131 | 132 | int xradio_data_write(struct xradio_common *hw_priv, const void *buf, 133 | size_t buf_len) 134 | { 135 | int ret, retry = 1; 136 | sdio_lock(hw_priv); 137 | { 138 | int buf_id_tx = hw_priv->buf_id_tx; 139 | while (retry <= MAX_RETRY) { 140 | ret = __xradio_write(hw_priv, HIF_IN_OUT_QUEUE_REG_ID, buf, 141 | buf_len, buf_id_tx); 142 | if (!ret) { 143 | buf_id_tx = (buf_id_tx + 1) & 31; 144 | hw_priv->buf_id_tx = buf_id_tx; 145 | break; 146 | } else { 147 | dev_err(hw_priv->pdev, "data write error :%d - attempt %d - %d\n", ret, retry, MAX_RETRY); 148 | retry++; 149 | mdelay(1); 150 | } 151 | } 152 | } 153 | sdio_unlock(hw_priv); 154 | return ret; 155 | } 156 | 157 | int xradio_indirect_read(struct xradio_common *hw_priv, u32 addr, void *buf, 158 | size_t buf_len, u32 prefetch, u16 port_addr) 159 | { 160 | u32 val32 = 0; 161 | int i, ret; 162 | 163 | if ((buf_len / 2) >= 0x1000) { 164 | dev_err(hw_priv->pdev, "Can't read more than 0xfff words.\n"); 165 | return -EINVAL; 166 | goto out; 167 | } 168 | 169 | sdio_lock(hw_priv); 170 | /* Write address */ 171 | ret = __xradio_write_reg32(hw_priv, HIF_SRAM_BASE_ADDR_REG_ID, addr); 172 | if (ret < 0) { 173 | dev_err(hw_priv->pdev, "Can't write address register.\n"); 174 | goto out; 175 | } 176 | 177 | /* Read CONFIG Register Value - We will read 32 bits */ 178 | ret = __xradio_read_reg32(hw_priv, HIF_CONFIG_REG_ID, &val32); 179 | if (ret < 0) { 180 | dev_err(hw_priv->pdev, "Can't read config register.\n"); 181 | goto out; 182 | } 183 | 184 | /* Set PREFETCH bit */ 185 | ret = __xradio_write_reg32(hw_priv, HIF_CONFIG_REG_ID, val32 | prefetch); 186 | if (ret < 0) { 187 | dev_err(hw_priv->pdev, "Can't write prefetch bit.\n"); 188 | goto out; 189 | } 190 | 191 | /* Check for PRE-FETCH bit to be cleared */ 192 | for (i = 0; i < 20; i++) { 193 | ret = __xradio_read_reg32(hw_priv, HIF_CONFIG_REG_ID, &val32); 194 | if (ret < 0) { 195 | dev_err(hw_priv->pdev, "Can't check prefetch bit.\n"); 196 | goto out; 197 | } 198 | if (!(val32 & prefetch)) 199 | break; 200 | mdelay(i); 201 | } 202 | 203 | if (val32 & prefetch) { 204 | dev_err(hw_priv->pdev, "Prefetch bit is not cleared.\n"); 205 | goto out; 206 | } 207 | 208 | /* Read data port */ 209 | ret = __xradio_read(hw_priv, port_addr, buf, buf_len, 0); 210 | if (ret < 0) { 211 | dev_err(hw_priv->pdev, "Can't read data port.\n"); 212 | goto out; 213 | } 214 | 215 | out: 216 | sdio_unlock(hw_priv); 217 | return ret; 218 | } 219 | 220 | int xradio_apb_write(struct xradio_common *hw_priv, u32 addr, const void *buf, 221 | size_t buf_len) 222 | { 223 | int ret; 224 | 225 | if ((buf_len / 2) >= 0x1000) { 226 | dev_err(hw_priv->pdev, "Can't wrire more than 0xfff words.\n"); 227 | return -EINVAL; 228 | } 229 | 230 | sdio_lock(hw_priv); 231 | 232 | /* Write address */ 233 | ret = __xradio_write_reg32(hw_priv, HIF_SRAM_BASE_ADDR_REG_ID, addr); 234 | if (ret < 0) { 235 | dev_err(hw_priv->pdev, "Can't write address register.\n"); 236 | goto out; 237 | } 238 | 239 | /* Write data port */ 240 | ret = __xradio_write(hw_priv, HIF_SRAM_DPORT_REG_ID, buf, buf_len, 0); 241 | if (ret < 0) { 242 | dev_err(hw_priv->pdev, "Can't write data port.\n"); 243 | goto out; 244 | } 245 | 246 | out: 247 | sdio_unlock(hw_priv); 248 | return ret; 249 | } 250 | 251 | int xradio_ahb_write(struct xradio_common *hw_priv, u32 addr, const void *buf, 252 | size_t buf_len) 253 | { 254 | int ret; 255 | 256 | if ((buf_len / 2) >= 0x1000) { 257 | dev_err(hw_priv->pdev, "Can't wrire more than 0xfff words.\n"); 258 | return -EINVAL; 259 | } 260 | 261 | sdio_lock(hw_priv); 262 | 263 | /* Write address */ 264 | ret = __xradio_write_reg32(hw_priv, HIF_SRAM_BASE_ADDR_REG_ID, addr); 265 | if (ret < 0) { 266 | dev_err(hw_priv->pdev, "Can't write address register.\n"); 267 | goto out; 268 | } 269 | 270 | /* Write data port */ 271 | ret = __xradio_write(hw_priv, HIF_AHB_DPORT_REG_ID, buf, buf_len, 0); 272 | if (ret < 0) { 273 | dev_err(hw_priv->pdev, "Can't write data port.\n"); 274 | goto out; 275 | } 276 | 277 | out: 278 | sdio_unlock(hw_priv); 279 | return ret; 280 | } 281 | -------------------------------------------------------------------------------- /hwio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * hardware interfaces for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #ifndef XRADIO_HWIO_H_INCLUDED 13 | #define XRADIO_HWIO_H_INCLUDED 14 | 15 | /* extern */ struct xradio_common; 16 | 17 | /* DPLL initial values */ 18 | #define DPLL_INIT_VAL_XRADIO (0x0EC4F121) 19 | 20 | /* Hardware Type Definitions */ 21 | #define HIF_HW_TYPE_XRADIO (1) 22 | 23 | 24 | /* boot loader start address in SRAM */ 25 | #define DOWNLOAD_BOOT_LOADER_OFFSET (0x00000000) 26 | /* 32K, 0x4000 to 0xDFFF */ 27 | #define DOWNLOAD_FIFO_OFFSET (0x00004000) 28 | /* 32K */ 29 | #define DOWNLOAD_FIFO_SIZE (0x00008000) 30 | /* 128 bytes, 0xFF80 to 0xFFFF */ 31 | #define DOWNLOAD_CTRL_OFFSET (0x0000FF80) 32 | #define DOWNLOAD_CTRL_DATA_DWORDS (32-6) 33 | 34 | /* Download control area */ 35 | struct download_cntl_t { 36 | /* size of whole firmware file (including Cheksum), host init */ 37 | u32 ImageSize; 38 | /* downloading flags */ 39 | u32 Flags; 40 | /* No. of bytes put into the download, init & updated by host */ 41 | u32 Put; 42 | /* last traced program counter, last ARM reg_pc */ 43 | u32 TracePc; 44 | /* No. of bytes read from the download, host init, device updates */ 45 | u32 Get; 46 | /* r0, boot losader status, host init to pending, device updates */ 47 | u32 Status; 48 | /* Extra debug info, r1 to r14 if status=r0=DOWNLOAD_EXCEPTION */ 49 | u32 DebugData[DOWNLOAD_CTRL_DATA_DWORDS]; 50 | }; 51 | 52 | #define DOWNLOAD_IMAGE_SIZE_REG \ 53 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, ImageSize)) 54 | #define DOWNLOAD_FLAGS_REG \ 55 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, Flags)) 56 | #define DOWNLOAD_PUT_REG \ 57 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, Put)) 58 | #define DOWNLOAD_TRACE_PC_REG \ 59 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, TracePc)) 60 | #define DOWNLOAD_GET_REG \ 61 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, Get)) 62 | #define DOWNLOAD_STATUS_REG \ 63 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, Status)) 64 | #define DOWNLOAD_DEBUG_DATA_REG \ 65 | (DOWNLOAD_CTRL_OFFSET + offsetof(struct download_cntl_t, DebugData)) 66 | 67 | #define DOWNLOAD_DEBUG_DATA_LEN (108) 68 | #define DOWNLOAD_BLOCK_SIZE (1024) 69 | 70 | /* For boot loader detection */ 71 | #define DOWNLOAD_ARE_YOU_HERE (0x87654321) 72 | #define DOWNLOAD_I_AM_HERE (0x12345678) 73 | 74 | /* Download error code */ 75 | #define DOWNLOAD_PENDING (0xFFFFFFFF) 76 | #define DOWNLOAD_SUCCESS (0) 77 | #define DOWNLOAD_EXCEPTION (1) 78 | #define DOWNLOAD_ERR_MEM_1 (2) 79 | #define DOWNLOAD_ERR_MEM_2 (3) 80 | #define DOWNLOAD_ERR_SOFTWARE (4) 81 | #define DOWNLOAD_ERR_FILE_SIZE (5) 82 | #define DOWNLOAD_ERR_CHECKSUM (6) 83 | #define DOWNLOAD_ERR_OVERFLOW (7) 84 | #define DOWNLOAD_ERR_IMAGE (8) 85 | #define DOWNLOAD_ERR_HOST (9) 86 | #define DOWNLOAD_ERR_ABORT (10) 87 | 88 | #define SYS_BASE_ADDR_SILICON (0) 89 | #define AHB_MEMORY_ADDRESS (SYS_BASE_ADDR_SILICON + 0x08000000) 90 | #define PAC_BASE_ADDRESS_SILICON (SYS_BASE_ADDR_SILICON + 0x09000000) 91 | #define PAC_SHARED_MEMORY_SILICON (PAC_BASE_ADDRESS_SILICON) 92 | #define APB_ADDR(addr) (PAC_SHARED_MEMORY_SILICON + (addr)) 93 | 94 | /* *************************************************************** 95 | *Device register definitions 96 | *************************************************************** */ 97 | /* WBF - SPI Register Addresses */ 98 | #define HIF_ADDR_ID_BASE (0x0000) 99 | /* 16/32 bits */ 100 | #define HIF_CONFIG_REG_ID (0x0000) 101 | /* 16/32 bits */ 102 | #define HIF_CONTROL_REG_ID (0x0001) 103 | /* 16 bits, Q mode W/R */ 104 | #define HIF_IN_OUT_QUEUE_REG_ID (0x0002) 105 | /* 32 bits, AHB bus R/W */ 106 | #define HIF_AHB_DPORT_REG_ID (0x0003) 107 | /* 16/32 bits */ 108 | #define HIF_SRAM_BASE_ADDR_REG_ID (0x0004) 109 | /* 32 bits, APB bus R/W */ 110 | #define HIF_SRAM_DPORT_REG_ID (0x0005) 111 | /* 32 bits, t_settle/general */ 112 | #define HIF_TSET_GEN_R_W_REG_ID (0x0006) 113 | /* 16 bits, Q mode read, no length */ 114 | #define HIF_FRAME_OUT_REG_ID (0x0007) 115 | #define HIF_ADDR_ID_MAX (HIF_FRAME_OUT_REG_ID) 116 | 117 | /* WBF - Control register bit set */ 118 | /* next o/p length, bit 11 to 0 */ 119 | #define HIF_CTRL_NEXT_LEN_MASK (0x0FFF) 120 | #define HIF_CTRL_WUP_BIT (BIT(12)) 121 | #define HIF_CTRL_RDY_BIT (BIT(13)) 122 | #define HIF_CTRL_IRQ_ENABLE (BIT(14)) 123 | #define HIF_CTRL_RDY_ENABLE (BIT(15)) 124 | #define HIF_CTRL_IRQ_RDY_ENABLE (BIT(14)|BIT(15)) 125 | 126 | /* SPI Config register bit set */ 127 | #define HIF_CONFIG_FRAME_BIT (BIT(2)) 128 | #define HIF_CONFIG_WORD_MODE_BITS (BIT(3)|BIT(4)) 129 | #define HIF_CONFIG_WORD_MODE_1 (BIT(3)) 130 | #define HIF_CONFIG_WORD_MODE_2 (BIT(4)) 131 | #define HIF_CONFIG_ERROR_0_BIT (BIT(5)) 132 | #define HIF_CONFIG_ERROR_1_BIT (BIT(6)) 133 | #define HIF_CONFIG_ERROR_2_BIT (BIT(7)) 134 | /* TBD: Sure??? */ 135 | #define HIF_CONFIG_CSN_FRAME_BIT (BIT(7)) 136 | #define HIF_CONFIG_ERROR_3_BIT (BIT(8)) 137 | #define HIF_CONFIG_ERROR_4_BIT (BIT(9)) 138 | /* QueueM */ 139 | #define HIF_CONFIG_ACCESS_MODE_BIT (BIT(10)) 140 | /* AHB bus */ 141 | #define HIF_CONFIG_AHB_PFETCH_BIT (BIT(11)) 142 | #define HIF_CONFIG_CPU_CLK_DIS_BIT (BIT(12)) 143 | /* APB bus */ 144 | #define HIF_CONFIG_PFETCH_BIT (BIT(13)) 145 | /* cpu reset */ 146 | #define HIF_CONFIG_CPU_RESET_BIT (BIT(14)) 147 | #define HIF_CONFIG_CLEAR_INT_BIT (BIT(15)) 148 | 149 | /* For XRADIO the IRQ Enable and Ready Bits are in CONFIG register */ 150 | #define HIF_CONF_IRQ_RDY_ENABLE (BIT(16)|BIT(17)) 151 | 152 | int xradio_data_read(struct xradio_common *hw_priv, void *buf, size_t buf_len); 153 | int xradio_data_write(struct xradio_common *hw_priv, const void *buf, size_t buf_len); 154 | int xradio_reg_read(struct xradio_common *hw_priv, u16 addr, void *buf, size_t buf_len); 155 | int xradio_reg_write(struct xradio_common *hw_priv, u16 addr, const void *buf, size_t buf_len); 156 | int xradio_indirect_read(struct xradio_common *hw_priv, u32 addr, void *buf, 157 | size_t buf_len, u32 prefetch, u16 port_addr); 158 | int xradio_apb_write(struct xradio_common *hw_priv, u32 addr, const void *buf, size_t buf_len); 159 | int xradio_ahb_write(struct xradio_common *hw_priv, u32 addr, const void *buf, size_t buf_len); 160 | 161 | 162 | static inline int xradio_reg_read_16(struct xradio_common *hw_priv, 163 | u16 addr, u16 *val) 164 | { 165 | int ret = 0; 166 | u32 bigVal = 0; 167 | ret = xradio_reg_read(hw_priv, addr, &bigVal, sizeof(bigVal)); 168 | *val = (u16)bigVal; 169 | return ret; 170 | } 171 | 172 | static inline int xradio_reg_write_16(struct xradio_common *hw_priv, 173 | u16 addr, u16 val) 174 | { 175 | u32 bigVal = (u32)val; 176 | return xradio_reg_write(hw_priv, addr, &bigVal, sizeof(bigVal)); 177 | } 178 | 179 | static inline int xradio_reg_read_32(struct xradio_common *hw_priv, 180 | u16 addr, u32 *val) 181 | { 182 | return xradio_reg_read(hw_priv, addr, val, sizeof(val)); 183 | } 184 | 185 | static inline int xradio_reg_write_32(struct xradio_common *hw_priv, 186 | u16 addr, u32 val) 187 | { 188 | return xradio_reg_write(hw_priv, addr, &val, sizeof(val)); 189 | } 190 | 191 | static inline int xradio_apb_read(struct xradio_common *hw_priv, u32 addr, 192 | void *buf, size_t buf_len) 193 | { 194 | return xradio_indirect_read(hw_priv, addr, buf, buf_len, HIF_CONFIG_PFETCH_BIT, 195 | HIF_SRAM_DPORT_REG_ID); 196 | } 197 | 198 | static inline int xradio_ahb_read(struct xradio_common *hw_priv, u32 addr, 199 | void *buf, size_t buf_len) 200 | { 201 | return xradio_indirect_read(hw_priv, addr, buf, buf_len, HIF_CONFIG_AHB_PFETCH_BIT, 202 | HIF_AHB_DPORT_REG_ID); 203 | } 204 | 205 | static inline int xradio_apb_read_32(struct xradio_common *hw_priv, 206 | u32 addr, u32 *val) 207 | { 208 | return xradio_apb_read(hw_priv, addr, val, sizeof(val)); 209 | } 210 | 211 | static inline int xradio_apb_write_32(struct xradio_common *hw_priv, 212 | u32 addr, u32 val) 213 | { 214 | return xradio_apb_write(hw_priv, addr, &val, sizeof(val)); 215 | } 216 | 217 | static inline int xradio_ahb_read_32(struct xradio_common *hw_priv, 218 | u32 addr, u32 *val) 219 | { 220 | return xradio_ahb_read(hw_priv, addr, val, sizeof(val)); 221 | } 222 | 223 | static inline int xradio_ahb_write_32(struct xradio_common *hw_priv, 224 | u32 addr, u32 val) 225 | { 226 | return xradio_ahb_write(hw_priv, addr, &val, sizeof(val)); 227 | } 228 | 229 | #endif /* XRADIO_HWIO_H_INCLUDED */ 230 | -------------------------------------------------------------------------------- /keys.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "xradio.h" 4 | #include "sta.h" 5 | #include "keys.h" 6 | 7 | int xradio_alloc_key(struct xradio_common *hw_priv) 8 | { 9 | int idx; 10 | 11 | idx = ffs(~hw_priv->key_map) - 1; 12 | if (idx < 0 || idx > WSM_KEY_MAX_INDEX) 13 | return -1; 14 | 15 | hw_priv->key_map |= BIT(idx); 16 | hw_priv->keys[idx].entryIndex = idx; 17 | return idx; 18 | } 19 | 20 | void xradio_free_key(struct xradio_common *hw_priv, int idx) 21 | { 22 | BUG_ON(!(hw_priv->key_map & BIT(idx))); 23 | memset(&hw_priv->keys[idx], 0, sizeof(hw_priv->keys[idx])); 24 | hw_priv->key_map &= ~BIT(idx); 25 | } 26 | 27 | void xradio_free_keys(struct xradio_common *hw_priv) 28 | { 29 | memset(&hw_priv->keys, 0, sizeof(hw_priv->keys)); 30 | hw_priv->key_map = 0; 31 | } 32 | 33 | int xradio_upload_keys(struct xradio_vif *priv) 34 | { 35 | struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); 36 | int idx, ret = 0; 37 | 38 | 39 | for (idx = 0; idx <= WSM_KEY_MAX_IDX; ++idx) 40 | if (hw_priv->key_map & BIT(idx)) { 41 | ret = wsm_add_key(hw_priv, &hw_priv->keys[idx], priv->if_id); 42 | if (ret < 0) 43 | break; 44 | } 45 | return ret; 46 | } 47 | 48 | int xradio_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, 49 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, 50 | struct ieee80211_key_conf *key) 51 | { 52 | #ifdef XRADIO_DISABLE_HW_CRYPTO 53 | wiphy_info(dev->wiphy, "hw crypto is disabled, ignoring key request\n"); 54 | return -EOPNOTSUPP; 55 | #else 56 | int ret = -EOPNOTSUPP; 57 | struct xradio_common *hw_priv = dev->priv; 58 | struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(vif); 59 | 60 | wiphy_dbg(dev->wiphy, "vif %d: set_key cmd %d\n", priv->if_id, (int) cmd); 61 | 62 | mutex_lock(&hw_priv->conf_mutex); 63 | 64 | if (cmd == SET_KEY) { 65 | u8 *peer_addr = NULL; 66 | int pairwise = (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) ? 1 : 0; 67 | int idx = xradio_alloc_key(hw_priv); 68 | struct wsm_add_key *wsm_key; 69 | 70 | if (idx < 0) { 71 | wiphy_err(dev->wiphy, "xradio_alloc_key failed!\n"); 72 | ret = -EINVAL; 73 | goto finally; 74 | } 75 | 76 | wsm_key = &hw_priv->keys[idx]; 77 | 78 | BUG_ON(pairwise && !sta); 79 | if (sta) 80 | peer_addr = sta->addr; 81 | 82 | key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; 83 | 84 | priv->cipherType = key->cipher; 85 | switch (key->cipher) { 86 | case WLAN_CIPHER_SUITE_WEP40: 87 | case WLAN_CIPHER_SUITE_WEP104: 88 | if (key->keylen > 16) { 89 | xradio_free_key(hw_priv, idx); 90 | wiphy_err(dev->wiphy, "keylen too long=%d!\n", key->keylen); 91 | ret = -EINVAL; 92 | goto finally; 93 | } 94 | 95 | if (pairwise) { 96 | wsm_key->type = WSM_KEY_TYPE_WEP_PAIRWISE; 97 | memcpy(wsm_key->wepPairwiseKey.peerAddress, peer_addr, ETH_ALEN); 98 | memcpy(wsm_key->wepPairwiseKey.keyData, &key->key[0], key->keylen); 99 | wsm_key->wepPairwiseKey.keyLength = key->keylen; 100 | } else { 101 | wsm_key->type = WSM_KEY_TYPE_WEP_DEFAULT; 102 | memcpy(wsm_key->wepGroupKey.keyData, &key->key[0], key->keylen); 103 | wsm_key->wepGroupKey.keyLength = key->keylen; 104 | wsm_key->wepGroupKey.keyId = key->keyidx; 105 | } 106 | break; 107 | case WLAN_CIPHER_SUITE_TKIP: 108 | if (pairwise) { 109 | wsm_key->type = WSM_KEY_TYPE_TKIP_PAIRWISE; 110 | memcpy(wsm_key->tkipPairwiseKey.peerAddress, peer_addr, ETH_ALEN); 111 | memcpy(wsm_key->tkipPairwiseKey.tkipKeyData, &key->key[0], 16); 112 | memcpy(wsm_key->tkipPairwiseKey.txMicKey, &key->key[16], 8); 113 | memcpy(wsm_key->tkipPairwiseKey.rxMicKey, &key->key[24], 8); 114 | } else { 115 | size_t mic_offset = (priv->mode == NL80211_IFTYPE_AP) ? 16 : 24; 116 | wsm_key->type = WSM_KEY_TYPE_TKIP_GROUP; 117 | memcpy(wsm_key->tkipGroupKey.tkipKeyData,&key->key[0], 16); 118 | memcpy(wsm_key->tkipGroupKey.rxMicKey, &key->key[mic_offset], 8); 119 | 120 | /* TODO: Where can I find TKIP SEQ? */ 121 | memset(wsm_key->tkipGroupKey.rxSeqCounter, 0, 8); 122 | wsm_key->tkipGroupKey.keyId = key->keyidx; 123 | } 124 | break; 125 | case WLAN_CIPHER_SUITE_CCMP: 126 | if (pairwise) { 127 | wsm_key->type = WSM_KEY_TYPE_AES_PAIRWISE; 128 | memcpy(wsm_key->aesPairwiseKey.peerAddress, peer_addr, ETH_ALEN); 129 | memcpy(wsm_key->aesPairwiseKey.aesKeyData, &key->key[0], 16); 130 | wiphy_debug(dev->wiphy, "CCMP_PAIRWISE keylen=%d!\n", 131 | key->keylen); 132 | } else { 133 | wsm_key->type = WSM_KEY_TYPE_AES_GROUP; 134 | memcpy(wsm_key->aesGroupKey.aesKeyData, &key->key[0], 16); 135 | /* TODO: Where can I find AES SEQ? */ 136 | memset(wsm_key->aesGroupKey.rxSeqCounter, 0, 8); 137 | wsm_key->aesGroupKey.keyId = key->keyidx; 138 | } 139 | break; 140 | #ifdef CONFIG_XRADIO_WAPI_SUPPORT 141 | case WLAN_CIPHER_SUITE_SMS4: 142 | if (pairwise) { 143 | wsm_key->type = WSM_KEY_TYPE_WAPI_PAIRWISE; 144 | memcpy(wsm_key->wapiPairwiseKey.peerAddress, peer_addr, ETH_ALEN); 145 | memcpy(wsm_key->wapiPairwiseKey.wapiKeyData, &key->key[0], 16); 146 | memcpy(wsm_key->wapiPairwiseKey.micKeyData, &key->key[16], 16); 147 | wsm_key->wapiPairwiseKey.keyId = key->keyidx; 148 | sta_printk(XRADIO_DBG_NIY,"%s: WAPI_PAIRWISE keylen=%d!\n", 149 | __func__, key->keylen); 150 | } else { 151 | wsm_key->type = WSM_KEY_TYPE_WAPI_GROUP; 152 | memcpy(wsm_key->wapiGroupKey.wapiKeyData, &key->key[0], 16); 153 | memcpy(wsm_key->wapiGroupKey.micKeyData, &key->key[16], 16); 154 | wsm_key->wapiGroupKey.keyId = key->keyidx; 155 | sta_printk(XRADIO_DBG_NIY,"%s: WAPI_GROUP keylen=%d!\n", 156 | __func__, key->keylen); 157 | } 158 | break; 159 | #endif /* CONFIG_XRADIO_WAPI_SUPPORT */ 160 | default: 161 | wiphy_err(dev->wiphy, "key->cipher unknown(%d)!\n", key->cipher); 162 | xradio_free_key(hw_priv, idx); 163 | ret = -EOPNOTSUPP; 164 | goto finally; 165 | } 166 | ret = WARN_ON(wsm_add_key(hw_priv, wsm_key, priv->if_id)); 167 | if (!ret) 168 | key->hw_key_idx = idx; 169 | else 170 | xradio_free_key(hw_priv, idx); 171 | 172 | if (!ret && (pairwise || wsm_key->type == WSM_KEY_TYPE_WEP_DEFAULT) && 173 | (priv->filter4.enable & 0x2)) 174 | xradio_set_arpreply(dev, vif); 175 | } else if (cmd == DISABLE_KEY) { 176 | struct wsm_remove_key wsm_key = { 177 | .entryIndex = key->hw_key_idx, 178 | }; 179 | 180 | if (wsm_key.entryIndex > WSM_KEY_MAX_IDX) { 181 | ret = -EINVAL; 182 | goto finally; 183 | } 184 | 185 | xradio_free_key(hw_priv, wsm_key.entryIndex); 186 | ret = wsm_remove_key(hw_priv, &wsm_key, priv->if_id); 187 | } else { 188 | wiphy_err(dev->wiphy, "Unsupported command\n"); 189 | } 190 | 191 | finally: 192 | mutex_unlock(&hw_priv->conf_mutex); 193 | return ret; 194 | #endif // XRADIO_DISABLE_HW_CRYPTO 195 | } 196 | -------------------------------------------------------------------------------- /keys.h: -------------------------------------------------------------------------------- 1 | #ifndef __KEYS_H_ 2 | #define __KEYS_H_INCLUDED 3 | 4 | int xradio_alloc_key(struct xradio_common *hw_priv); 5 | void xradio_free_key(struct xradio_common *hw_priv, int idx); 6 | void xradio_free_keys(struct xradio_common *hw_priv); 7 | int xradio_upload_keys(struct xradio_vif *priv); 8 | int xradio_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, 9 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, 10 | struct ieee80211_key_conf *key); 11 | 12 | #endif -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Main code of XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "xradio.h" 19 | #include "fwio.h" 20 | #include "hwio.h" 21 | #include "bh.h" 22 | #include "sta.h" 23 | #include "ap.h" 24 | #include "keys.h" 25 | #include "scan.h" 26 | #include "pm.h" 27 | #include "sdio.h" 28 | 29 | /* TODO: use rates and channels from the device */ 30 | #define RATETAB_ENT(_rate, _rateid, _flags) \ 31 | { \ 32 | .bitrate = (_rate), \ 33 | .hw_value = (_rateid), \ 34 | .flags = (_flags), \ 35 | } 36 | 37 | static struct ieee80211_rate xradio_rates[] = { 38 | RATETAB_ENT(10, 0, 0), 39 | RATETAB_ENT(20, 1, 0), 40 | RATETAB_ENT(55, 2, 0), 41 | RATETAB_ENT(110, 3, 0), 42 | RATETAB_ENT(60, 6, 0), 43 | RATETAB_ENT(90, 7, 0), 44 | RATETAB_ENT(120, 8, 0), 45 | RATETAB_ENT(180, 9, 0), 46 | RATETAB_ENT(240, 10, 0), 47 | RATETAB_ENT(360, 11, 0), 48 | RATETAB_ENT(480, 12, 0), 49 | RATETAB_ENT(540, 13, 0), 50 | }; 51 | 52 | static struct ieee80211_rate xradio_mcs_rates[] = { 53 | RATETAB_ENT(65, 14, IEEE80211_TX_RC_MCS), 54 | RATETAB_ENT(130, 15, IEEE80211_TX_RC_MCS), 55 | RATETAB_ENT(195, 16, IEEE80211_TX_RC_MCS), 56 | RATETAB_ENT(260, 17, IEEE80211_TX_RC_MCS), 57 | RATETAB_ENT(390, 18, IEEE80211_TX_RC_MCS), 58 | RATETAB_ENT(520, 19, IEEE80211_TX_RC_MCS), 59 | RATETAB_ENT(585, 20, IEEE80211_TX_RC_MCS), 60 | RATETAB_ENT(650, 21, IEEE80211_TX_RC_MCS), 61 | }; 62 | 63 | #define xradio_g_rates (xradio_rates + 0) 64 | #define xradio_a_rates (xradio_rates + 4) 65 | #define xradio_n_rates (xradio_mcs_rates) 66 | 67 | #define xradio_g_rates_size (ARRAY_SIZE(xradio_rates)) 68 | #define xradio_a_rates_size (ARRAY_SIZE(xradio_rates) - 4) 69 | #define xradio_n_rates_size (ARRAY_SIZE(xradio_mcs_rates)) 70 | 71 | #define CHAN2G(_channel, _freq, _flags) { \ 72 | .band = NL80211_BAND_2GHZ, \ 73 | .center_freq = (_freq), \ 74 | .hw_value = (_channel), \ 75 | .flags = (_flags), \ 76 | .max_antenna_gain = 0, \ 77 | .max_power = 30, \ 78 | } 79 | 80 | #define CHAN5G(_channel, _flags) { \ 81 | .band = NL80211_BAND_5GHZ, \ 82 | .center_freq = 5000 + (5 * (_channel)), \ 83 | .hw_value = (_channel), \ 84 | .flags = (_flags), \ 85 | .max_antenna_gain = 0, \ 86 | .max_power = 30, \ 87 | } 88 | 89 | static struct ieee80211_channel xradio_2ghz_chantable[] = { 90 | CHAN2G(1, 2412, 0), 91 | CHAN2G(2, 2417, 0), 92 | CHAN2G(3, 2422, 0), 93 | CHAN2G(4, 2427, 0), 94 | CHAN2G(5, 2432, 0), 95 | CHAN2G(6, 2437, 0), 96 | CHAN2G(7, 2442, 0), 97 | CHAN2G(8, 2447, 0), 98 | CHAN2G(9, 2452, 0), 99 | CHAN2G(10, 2457, 0), 100 | CHAN2G(11, 2462, 0), 101 | CHAN2G(12, 2467, 0), 102 | CHAN2G(13, 2472, 0), 103 | CHAN2G(14, 2484, 0), 104 | }; 105 | 106 | static struct ieee80211_supported_band xradio_band_2ghz = { 107 | .channels = xradio_2ghz_chantable, 108 | .n_channels = ARRAY_SIZE(xradio_2ghz_chantable), 109 | .bitrates = xradio_g_rates, 110 | .n_bitrates = xradio_g_rates_size, 111 | .ht_cap = { 112 | .cap = IEEE80211_HT_CAP_GRN_FLD | 113 | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), 114 | .ht_supported = 1, 115 | .ampdu_factor = IEEE80211_HT_MAX_AMPDU_32K, 116 | .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, 117 | .mcs = { 118 | .rx_mask[0] = 0xFF, 119 | .rx_highest = __cpu_to_le16(0x41), 120 | .tx_params = IEEE80211_HT_MCS_TX_DEFINED, 121 | }, 122 | }, 123 | }; 124 | 125 | static const unsigned long xradio_ttl[] = { 126 | 1 * HZ, /* VO */ 127 | 2 * HZ, /* VI */ 128 | 5 * HZ, /* BE */ 129 | 10 * HZ /* BK */ 130 | }; 131 | 132 | static const struct ieee80211_ops xradio_ops = { 133 | .start = xradio_start, 134 | .stop = xradio_stop, 135 | .add_interface = xradio_add_interface, 136 | .remove_interface = xradio_remove_interface, 137 | .change_interface = xradio_change_interface, 138 | .tx = xradio_tx, 139 | .hw_scan = xradio_hw_scan, 140 | #ifdef ROAM_OFFLOAD 141 | .sched_scan_start = xradio_hw_sched_scan_start, 142 | .sched_scan_stop = xradio_hw_sched_scan_stop, 143 | #endif /*ROAM_OFFLOAD*/ 144 | .set_tim = xradio_set_tim, 145 | .sta_notify = xradio_sta_notify, 146 | .sta_add = xradio_sta_add, 147 | .sta_remove = xradio_sta_remove, 148 | .set_key = xradio_set_key, 149 | .set_rts_threshold = xradio_set_rts_threshold, 150 | .config = xradio_config, 151 | .bss_info_changed = xradio_bss_info_changed, 152 | .prepare_multicast = xradio_prepare_multicast, 153 | .configure_filter = xradio_configure_filter, 154 | .conf_tx = xradio_conf_tx, 155 | .get_stats = xradio_get_stats, 156 | .ampdu_action = xradio_ampdu_action, 157 | .flush = xradio_flush, 158 | #ifdef CONFIG_PM 159 | .suspend = xradio_wow_suspend, 160 | .resume = xradio_wow_resume, 161 | #endif /* CONFIG_PM */ 162 | /* Intentionally not offloaded: */ 163 | /*.channel_switch = xradio_channel_switch, */ 164 | .remain_on_channel = xradio_remain_on_channel, 165 | .cancel_remain_on_channel = xradio_cancel_remain_on_channel, 166 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 2, 0)) 167 | .wake_tx_queue = ieee80211_handle_wake_tx_queue, 168 | #endif 169 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 9, 0)) 170 | .add_chanctx = ieee80211_emulate_add_chanctx, 171 | .remove_chanctx = ieee80211_emulate_remove_chanctx, 172 | .change_chanctx = ieee80211_emulate_change_chanctx, 173 | .switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx, 174 | #endif 175 | }; 176 | 177 | 178 | /*************************************** functions ***************************************/ 179 | 180 | static void xradio_set_ifce_comb(struct xradio_common *hw_priv, 181 | struct ieee80211_hw *hw) 182 | { 183 | hw_priv->if_limits1[0].max = 1; 184 | 185 | hw_priv->if_limits1[0].types = BIT(NL80211_IFTYPE_STATION); 186 | hw_priv->if_limits1[1].max = 1; 187 | hw_priv->if_limits1[1].types = BIT(NL80211_IFTYPE_AP); 188 | 189 | hw_priv->if_limits2[0].max = 2; 190 | hw_priv->if_limits2[0].types = BIT(NL80211_IFTYPE_STATION); 191 | 192 | hw_priv->if_limits3[0].max = 1; 193 | 194 | hw_priv->if_limits3[0].types = BIT(NL80211_IFTYPE_STATION); 195 | hw_priv->if_limits3[1].max = 1; 196 | hw_priv->if_limits3[1].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | 197 | BIT(NL80211_IFTYPE_P2P_GO); 198 | 199 | /* TODO:COMBO: mac80211 doesn't yet support more than 1 200 | * different channel */ 201 | hw_priv->if_combs[0].num_different_channels = 1; 202 | hw_priv->if_combs[0].max_interfaces = 2; 203 | hw_priv->if_combs[0].limits = hw_priv->if_limits1; 204 | hw_priv->if_combs[0].n_limits = 2; 205 | 206 | hw_priv->if_combs[1].num_different_channels = 1; 207 | 208 | hw_priv->if_combs[1].max_interfaces = 2; 209 | hw_priv->if_combs[1].limits = hw_priv->if_limits2; 210 | hw_priv->if_combs[1].n_limits = 1; 211 | 212 | hw_priv->if_combs[2].num_different_channels = 1; 213 | hw_priv->if_combs[2].max_interfaces = 2; 214 | hw_priv->if_combs[2].limits = hw_priv->if_limits3; 215 | hw_priv->if_combs[2].n_limits = 2; 216 | 217 | hw->wiphy->iface_combinations = &hw_priv->if_combs[0]; 218 | hw->wiphy->n_iface_combinations = 3; 219 | } 220 | 221 | struct ieee80211_hw *xradio_init_common(size_t hw_priv_data_len) 222 | { 223 | int i; 224 | struct ieee80211_hw *hw; 225 | struct xradio_common *hw_priv; 226 | struct ieee80211_supported_band *sband; 227 | int band; 228 | 229 | /* Alloc ieee_802.11 hw and xradio_common struct. */ 230 | hw = ieee80211_alloc_hw(hw_priv_data_len, &xradio_ops); 231 | if (!hw) 232 | return NULL; 233 | hw_priv = hw->priv; 234 | memset(hw_priv, 0, sizeof(*hw_priv)); 235 | 236 | /* Initialize members of hw_priv. */ 237 | hw_priv->hw = hw; 238 | hw_priv->if_id_slot = 0; 239 | hw_priv->roc_if_id = -1; 240 | atomic_set(&hw_priv->num_vifs, 0); 241 | /* initial rates and channels TODO: fetch from FW */ 242 | hw_priv->rates = xradio_rates; 243 | hw_priv->mcs_rates = xradio_n_rates; 244 | #ifdef ROAM_OFFLOAD 245 | hw_priv->auto_scanning = 0; 246 | hw_priv->frame_rcvd = 0; 247 | hw_priv->num_scanchannels = 0; 248 | hw_priv->num_2g_channels = 0; 249 | hw_priv->num_5g_channels = 0; 250 | #endif /*ROAM_OFFLOAD*/ 251 | #ifdef AP_AGGREGATE_FW_FIX 252 | /* Enable block ACK for 4 TID (BE,VI,VI,VO). */ 253 | hw_priv->ba_tid_mask = 0xB1; /*due to HW limitations*/ 254 | #else 255 | /* Enable block ACK for every TID but voice. */ 256 | hw_priv->ba_tid_mask = 0x3F; 257 | #endif 258 | hw_priv->noise = -94; 259 | /* hw_priv->beacon_req_id = cpu_to_le32(0); */ 260 | 261 | /* Initialize members of ieee80211_hw, it works in UMAC. */ 262 | hw->sta_data_size = sizeof(struct xradio_sta_priv); 263 | hw->vif_data_size = sizeof(struct xradio_vif); 264 | 265 | ieee80211_hw_set(hw, SIGNAL_DBM); 266 | ieee80211_hw_set(hw, SUPPORTS_PS); 267 | ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); 268 | ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 269 | ieee80211_hw_set(hw, CONNECTION_MONITOR); 270 | 271 | /* hw->flags = IEEE80211_HW_SIGNAL_DBM | 272 | IEEE80211_HW_SUPPORTS_PS | 273 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | 274 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | 275 | IEEE80211_HW_CONNECTION_MONITOR;*/ 276 | //IEEE80211_HW_SUPPORTS_CQM_RSSI | 277 | /* Aggregation is fully controlled by firmware. 278 | * Do not need any support from the mac80211 stack */ 279 | /* IEEE80211_HW_AMPDU_AGGREGATION | */ 280 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 281 | //IEEE80211_HW_SUPPORTS_P2P_PS | 282 | //IEEE80211_HW_SUPPORTS_CQM_BEACON_MISS | 283 | // IEEE80211_HW_SUPPORTS_CQM_TX_FAIL | 284 | #endif /* CONFIG_XRADIO_USE_EXTENSIONS */ 285 | //IEEE80211_HW_BEACON_FILTER; 286 | 287 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | 288 | BIT(NL80211_IFTYPE_ADHOC) | 289 | BIT(NL80211_IFTYPE_AP) | 290 | BIT(NL80211_IFTYPE_MESH_POINT) | 291 | BIT(NL80211_IFTYPE_P2P_CLIENT) | 292 | BIT(NL80211_IFTYPE_P2P_GO); 293 | 294 | /* Support only for limited wowlan functionalities */ 295 | /* TODO by Icenowy: RESTORE THIS */ 296 | /* hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT; 297 | hw->wiphy->wowlan.n_patterns = 0;*/ 298 | 299 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 300 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; 301 | #endif /* CONFIG_XRADIO_USE_EXTENSIONS */ 302 | /* fix the problem that driver can not set pro-resp template frame to fw */ 303 | hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD | 304 | WIPHY_FLAG_PS_ON_BY_DEFAULT; 305 | 306 | #if defined(CONFIG_XRADIO_DISABLE_BEACON_HINTS) 307 | hw->wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS; 308 | #endif 309 | hw->wiphy->n_addresses = XRWL_MAX_VIFS; 310 | hw->wiphy->addresses = hw_priv->addresses; 311 | hw->wiphy->max_remain_on_channel_duration = 500; 312 | hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM + 313 | 8 /* TKIP IV */ + 314 | 12 /* TKIP ICV and MIC */; 315 | hw->wiphy->bands[NL80211_BAND_2GHZ] = &xradio_band_2ghz; 316 | hw->queues = AC_QUEUE_NUM; 317 | hw->max_rates = MAX_RATES_STAGE; 318 | hw->max_rate_tries = MAX_RATES_RETRY; 319 | /* Channel params have to be cleared before registering wiphy again */ 320 | for (band = 0; band < NUM_NL80211_BANDS; band++) { 321 | sband = hw->wiphy->bands[band]; 322 | if (!sband) 323 | continue; 324 | for (i = 0; i < sband->n_channels; i++) { 325 | sband->channels[i].flags = 0; 326 | sband->channels[i].max_antenna_gain = 0; 327 | sband->channels[i].max_power = 30; 328 | } 329 | } 330 | /* hw_priv->channel init value is the local->oper_channel init value;when transplanting,take care */ 331 | for (band = 0; band < NUM_NL80211_BANDS; band++) { 332 | sband = hw->wiphy->bands[band]; 333 | if (!sband) 334 | continue; 335 | if(!hw_priv->channel){ 336 | hw_priv->channel = &sband->channels[2]; 337 | } 338 | } 339 | hw->wiphy->max_scan_ssids = WSM_SCAN_MAX_NUM_OF_SSIDS; 340 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; 341 | SET_IEEE80211_PERM_ADDR(hw, hw_priv->addresses[0].addr); 342 | 343 | /* Initialize locks. */ 344 | spin_lock_init(&hw_priv->vif_list_lock); 345 | mutex_init(&hw_priv->wsm_cmd_mux); 346 | mutex_init(&hw_priv->conf_mutex); 347 | mutex_init(&hw_priv->wsm_oper_lock); 348 | atomic_set(&hw_priv->tx_lock, 0); 349 | sema_init(&hw_priv->tx_lock_sem, 1); 350 | 351 | hw_priv->workqueue = create_singlethread_workqueue(XRADIO_WORKQUEUE); 352 | sema_init(&hw_priv->scan.lock, 1); 353 | sema_init(&hw_priv->scan.status_lock,1); 354 | INIT_WORK(&hw_priv->scan.work, xradio_scan_work); 355 | #ifdef ROAM_OFFLOAD 356 | INIT_WORK(&hw_priv->scan.swork, xradio_sched_scan_work); 357 | #endif /*ROAM_OFFLOAD*/ 358 | INIT_DELAYED_WORK(&hw_priv->scan.probe_work, xradio_probe_work); 359 | INIT_DELAYED_WORK(&hw_priv->scan.timeout, xradio_scan_timeout); 360 | INIT_DELAYED_WORK(&hw_priv->rem_chan_timeout, xradio_rem_chan_timeout); 361 | INIT_WORK(&hw_priv->tx_policy_upload_work, tx_policy_upload_work); 362 | atomic_set(&hw_priv->upload_count, 0); 363 | memset(&hw_priv->connet_time, 0, sizeof(hw_priv->connet_time)); 364 | 365 | spin_lock_init(&hw_priv->event_queue_lock); 366 | INIT_LIST_HEAD(&hw_priv->event_queue); 367 | INIT_WORK(&hw_priv->event_handler, xradio_event_handler); 368 | INIT_WORK(&hw_priv->ba_work, xradio_ba_work); 369 | spin_lock_init(&hw_priv->ba_lock); 370 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) 371 | timer_setup(&hw_priv->ba_timer, xradio_ba_timer, 0); 372 | #else 373 | init_timer(&hw_priv->ba_timer); 374 | hw_priv->ba_timer.data = (unsigned long)hw_priv; 375 | hw_priv->ba_timer.function = xradio_ba_timer; 376 | #endif 377 | if (unlikely(xradio_queue_stats_init(&hw_priv->tx_queue_stats, 378 | WLAN_LINK_ID_MAX,sizeof(int[WLAN_LINK_ID_MAX]),xradio_skb_dtor, hw_priv))) { 379 | ieee80211_free_hw(hw); 380 | return NULL; 381 | } 382 | for (i = 0; i < AC_QUEUE_NUM; ++i) { 383 | if (unlikely(xradio_queue_init(&hw_priv->tx_queue[i], 384 | &hw_priv->tx_queue_stats, i, XRWL_MAX_QUEUE_SZ, xradio_ttl[i]))) { 385 | for (; i > 0; i--) 386 | xradio_queue_deinit(&hw_priv->tx_queue[i - 1]); 387 | xradio_queue_stats_deinit(&hw_priv->tx_queue_stats); 388 | ieee80211_free_hw(hw); 389 | return NULL; 390 | } 391 | } 392 | 393 | init_waitqueue_head(&hw_priv->channel_switch_done); 394 | init_waitqueue_head(&hw_priv->wsm_cmd_wq); 395 | init_waitqueue_head(&hw_priv->wsm_startup_done); 396 | init_waitqueue_head(&hw_priv->offchannel_wq); 397 | hw_priv->wsm_caps.firmwareReady = 0; 398 | hw_priv->driver_ready = 0; 399 | hw_priv->offchannel_done = 0; 400 | wsm_buf_init(&hw_priv->wsm_cmd_buf); 401 | spin_lock_init(&hw_priv->wsm_cmd.lock); 402 | tx_policy_init(hw_priv); 403 | xradio_init_resv_skb(hw_priv); 404 | /* add for setting short_frame_max_tx_count(mean wdev->retry_short) to drv,init the max_rate_tries */ 405 | spin_lock_bh(&hw_priv->tx_policy_cache.lock); 406 | hw_priv->long_frame_max_tx_count = hw->conf.long_frame_max_tx_count; 407 | hw_priv->short_frame_max_tx_count = 408 | (hw->conf.short_frame_max_tx_count< 0x0F) ? 409 | hw->conf.short_frame_max_tx_count : 0x0F; 410 | hw_priv->hw->max_rate_tries = hw->conf.short_frame_max_tx_count; 411 | spin_unlock_bh(&hw_priv->tx_policy_cache.lock); 412 | 413 | for (i = 0; i < XRWL_MAX_VIFS; i++) 414 | hw_priv->hw_bufs_used_vif[i] = 0; 415 | 416 | #ifdef MCAST_FWDING 417 | for (i = 0; i < WSM_MAX_BUF; i++) 418 | wsm_init_release_buffer_request(hw_priv, i); 419 | hw_priv->buf_released = 0; 420 | #endif 421 | hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; 422 | hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; 423 | 424 | hw_priv->query_packetID = 0; 425 | atomic_set(&hw_priv->query_cnt, 0); 426 | INIT_WORK(&hw_priv->query_work, wsm_query_work); 427 | 428 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 429 | atomic_set(&hw_priv->suspend_state, XRADIO_RESUME); 430 | #endif 431 | 432 | xradio_set_ifce_comb(hw_priv, hw_priv->hw); 433 | 434 | return hw; 435 | } 436 | 437 | void xradio_free_common(struct ieee80211_hw *dev) 438 | { 439 | int i; 440 | struct xradio_common *hw_priv = dev->priv; 441 | 442 | cancel_work_sync(&hw_priv->query_work); 443 | del_timer_sync(&hw_priv->ba_timer); 444 | mutex_destroy(&hw_priv->wsm_oper_lock); 445 | mutex_destroy(&hw_priv->conf_mutex); 446 | mutex_destroy(&hw_priv->wsm_cmd_mux); 447 | wsm_buf_deinit(&hw_priv->wsm_cmd_buf); 448 | flush_workqueue(hw_priv->workqueue); 449 | destroy_workqueue(hw_priv->workqueue); 450 | hw_priv->workqueue = NULL; 451 | 452 | xradio_deinit_resv_skb(hw_priv); 453 | if (hw_priv->skb_cache) { 454 | dev_kfree_skb(hw_priv->skb_cache); 455 | hw_priv->skb_cache = NULL; 456 | } 457 | 458 | for (i = 0; i < 4; ++i) 459 | xradio_queue_deinit(&hw_priv->tx_queue[i]); 460 | xradio_queue_stats_deinit(&hw_priv->tx_queue_stats); 461 | 462 | for (i = 0; i < XRWL_MAX_VIFS; i++) { 463 | kfree(hw_priv->vif_list[i]); 464 | hw_priv->vif_list[i] = NULL; 465 | } 466 | 467 | //fixed memory leakage by yangfh 468 | #ifdef MCAST_FWDING 469 | wsm_deinit_release_buffer(hw_priv); 470 | #endif 471 | /* unsigned int i; */ 472 | ieee80211_free_hw(dev); 473 | } 474 | 475 | int xradio_register_common(struct ieee80211_hw *dev) 476 | { 477 | int err = 0; 478 | struct xradio_common *hw_priv = dev->priv; 479 | 480 | SET_IEEE80211_DEV(dev, hw_priv->pdev); 481 | err = ieee80211_register_hw(dev); 482 | if (err) { 483 | dev_dbg(hw_priv->pdev, "Cannot register device (%d).\n", err); 484 | return err; 485 | } 486 | dev_dbg(hw_priv->pdev, "is registered as '%s'\n", 487 | wiphy_name(dev->wiphy)); 488 | 489 | hw_priv->driver_ready = 1; 490 | wake_up(&hw_priv->wsm_startup_done); 491 | return 0; 492 | } 493 | 494 | void xradio_unregister_common(struct ieee80211_hw *dev) 495 | { 496 | struct xradio_common *hw_priv = dev->priv; 497 | 498 | if (wiphy_dev(dev->wiphy)) { 499 | ieee80211_unregister_hw(dev); 500 | SET_IEEE80211_DEV(dev, NULL); 501 | } 502 | hw_priv->driver_ready = 0; 503 | } 504 | 505 | int xradio_core_init(struct sdio_func* func) 506 | { 507 | int err = -ENOMEM; 508 | u16 ctrl_reg; 509 | int if_id; 510 | struct ieee80211_hw *dev; 511 | struct xradio_common *hw_priv; 512 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0) 513 | unsigned char addr[ETH_ALEN]; 514 | #else 515 | unsigned char randomaddr[ETH_ALEN]; 516 | const unsigned char *addr = NULL; 517 | #endif 518 | 519 | //init xradio_common 520 | dev = xradio_init_common(sizeof(struct xradio_common)); 521 | if (!dev) { 522 | dev_dbg(&func->dev, "xradio_init_common failed\n"); 523 | return err; 524 | } 525 | hw_priv = dev->priv; 526 | hw_priv->pdev = &func->dev; 527 | hw_priv->sdio_func = func; 528 | sdio_set_drvdata(func, hw_priv); 529 | 530 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 13, 0) 531 | // fill in mac addresses 532 | if (hw_priv->pdev->of_node) { 533 | err = of_get_mac_address(hw_priv->pdev->of_node, addr); 534 | } 535 | if (err < 0) { 536 | dev_warn(hw_priv->pdev, "no mac address provided, using random\n"); 537 | eth_random_addr(addr); 538 | } 539 | #else 540 | // fill in mac addresses 541 | if (hw_priv->pdev->of_node) { 542 | addr = of_get_mac_address(hw_priv->pdev->of_node); 543 | } 544 | if (!addr) { 545 | dev_warn(hw_priv->pdev, "no mac address provided, using random\n"); 546 | eth_random_addr(randomaddr); 547 | addr = randomaddr; 548 | } 549 | #endif 550 | 551 | memcpy(hw_priv->addresses[0].addr, addr, ETH_ALEN); 552 | memcpy(hw_priv->addresses[1].addr, addr, ETH_ALEN); 553 | hw_priv->addresses[1].addr[5] += 0x01; 554 | 555 | /*init pm and wakelock. */ 556 | #ifdef CONFIG_PM 557 | err = xradio_pm_init(&hw_priv->pm_state, hw_priv); 558 | if (err) { 559 | dev_dbg(hw_priv->pdev, "xradio_pm_init failed(%d).\n", err); 560 | goto err1; 561 | } 562 | #endif 563 | /* Register bh thread*/ 564 | err = xradio_register_bh(hw_priv); 565 | if (err) { 566 | dev_dbg(hw_priv->pdev, "xradio_register_bh failed(%d).\n", err); 567 | goto err2; 568 | } 569 | 570 | /* Load firmware and register Interrupt Handler */ 571 | err = xradio_load_firmware(hw_priv); 572 | if (err) { 573 | dev_dbg(hw_priv->pdev, "xradio_load_firmware failed(%d).\n", err); 574 | goto err3; 575 | } 576 | 577 | /* Set sdio blocksize. */ 578 | sdio_lock(hw_priv); 579 | WARN_ON(sdio_set_blk_size(hw_priv, 580 | SDIO_BLOCK_SIZE)); 581 | sdio_unlock(hw_priv); 582 | 583 | if (wait_event_interruptible_timeout(hw_priv->wsm_startup_done, 584 | hw_priv->wsm_caps.firmwareReady, 3*HZ) <= 0) { 585 | 586 | /* TODO: Needs to find how to reset device */ 587 | /* in QUEUE mode properly. */ 588 | dev_dbg(hw_priv->pdev, "Firmware Startup Timeout!\n"); 589 | err = -ETIMEDOUT; 590 | goto err4; 591 | } 592 | dev_dbg(hw_priv->pdev, "Firmware Startup Done.\n"); 593 | 594 | /* Keep device wake up. */ 595 | WARN_ON(xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, HIF_CTRL_WUP_BIT)); 596 | if (xradio_reg_read_16(hw_priv,HIF_CONTROL_REG_ID, &ctrl_reg)) 597 | WARN_ON(xradio_reg_read_16(hw_priv,HIF_CONTROL_REG_ID, &ctrl_reg)); 598 | WARN_ON(!(ctrl_reg & HIF_CTRL_RDY_BIT)); 599 | 600 | /* Set device mode parameter. */ 601 | for (if_id = 0; if_id < xrwl_get_nr_hw_ifaces(hw_priv); if_id++) { 602 | /* Set low-power mode. */ 603 | WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, if_id)); 604 | /* Enable multi-TX confirmation */ 605 | WARN_ON(wsm_use_multi_tx_conf(hw_priv, true, if_id)); 606 | } 607 | 608 | /* Register wireless net device. */ 609 | err = xradio_register_common(dev); 610 | if (err) { 611 | dev_dbg(hw_priv->pdev, "xradio_register_common failed(%d)!\n", err); 612 | goto err4; 613 | } 614 | 615 | return err; 616 | 617 | err4: 618 | xradio_dev_deinit(hw_priv); 619 | err3: 620 | xradio_unregister_bh(hw_priv); 621 | err2: 622 | xradio_pm_deinit(&hw_priv->pm_state); 623 | err1: 624 | xradio_free_common(dev); 625 | sdio_set_drvdata(func, NULL); 626 | return err; 627 | } 628 | 629 | void xradio_core_deinit(struct sdio_func* func) 630 | { 631 | struct xradio_common* hw_priv = sdio_get_drvdata(func); 632 | if (hw_priv) { 633 | xradio_unregister_common(hw_priv->hw); 634 | xradio_dev_deinit(hw_priv); 635 | xradio_unregister_bh(hw_priv); 636 | xradio_pm_deinit(&hw_priv->pm_state); 637 | xradio_free_common(hw_priv->hw); 638 | sdio_set_drvdata(func, NULL); 639 | } 640 | return; 641 | } 642 | -------------------------------------------------------------------------------- /main.h: -------------------------------------------------------------------------------- 1 | #ifndef __XRADIO_MAIN_H 2 | #define __XRADIO_MAIN_H 3 | 4 | int xradio_core_init(struct sdio_func* func); 5 | void xradio_core_deinit(struct sdio_func* func); 6 | 7 | #endif -------------------------------------------------------------------------------- /module.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "xradio.h" 4 | #include "debug.h" 5 | #include "sdio.h" 6 | 7 | MODULE_AUTHOR("XRadioTech"); 8 | MODULE_DESCRIPTION("XRadioTech WLAN driver core"); 9 | MODULE_LICENSE("GPL"); 10 | MODULE_ALIAS("xradio_core"); 11 | 12 | /* Init Module function -> Called by insmod */ 13 | static int __init xradio_core_entry(void) 14 | { 15 | int ret = 0; 16 | ret = xradio_sdio_register(); 17 | return ret; 18 | } 19 | 20 | /* Called at Driver Unloading */ 21 | static void __exit xradio_core_exit(void) 22 | { 23 | xradio_sdio_unregister(); 24 | } 25 | 26 | module_init(xradio_core_entry); 27 | module_exit(xradio_core_exit); 28 | -------------------------------------------------------------------------------- /p2p.c: -------------------------------------------------------------------------------- 1 | #include "xradio.h" 2 | 3 | #ifdef TES_P2P_0002_ROC_RESTART 4 | ///w, TES_P2P_0002 WorkAround: 5 | ///w, P2P GO Neg Process and P2P FIND may be collision. 6 | ///w, When P2P Device is waiting for GO NEG CFM in 30ms, 7 | ///w, P2P FIND may end with p2p listen, and then goes to p2p search. 8 | ///w, Then xradio scan will occupy phy on other channel in 3+ seconds. 9 | ///w, P2P Device will not be able to receive the GO NEG CFM. 10 | ///w, We extend the roc period to remaind phy to receive GO NEG CFM as WorkAround. 11 | 12 | s32 TES_P2P_0002_roc_dur; 13 | s32 TES_P2P_0002_roc_sec; 14 | s32 TES_P2P_0002_roc_usec; 15 | u32 TES_P2P_0002_packet_id; 16 | u32 TES_P2P_0002_state = TES_P2P_0002_STATE_IDLE; 17 | 18 | void xradio_frame_monitor(struct xradio_common *hw_priv, struct sk_buff *skb, bool tx) { 19 | struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; 20 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 21 | 22 | u8 *action = (u8*)&mgmt->u.action.category; 23 | u8 *category_code = &(action[0]); 24 | u8 *action_code = &(action[1]); 25 | u8 *oui = &(action[2]); 26 | u8 *subtype = &(action[5]); 27 | u8 *oui_subtype = &(action[6]); 28 | 29 | 30 | if(ieee80211_is_action(frame->frame_control)) { 31 | if( *category_code == WLAN_CATEGORY_PUBLIC) { 32 | if (*action_code == 0x09) { 33 | if((oui[0] == 0x50) && (oui[1] == 0x6F) && 34 | (oui[2] == 0x9A) && (*subtype == 0x09)) { 35 | if ( *oui_subtype == 0x01 ) { ///w, GO Negotiation Response 36 | if((TES_P2P_0002_state == TES_P2P_0002_STATE_IDLE) && 37 | (tx == true)) { ///w, p2p atturbute:status,id=0 38 | u8 *go_neg_resp_res = &(action[17]); 39 | if (*go_neg_resp_res == 0x0) { 40 | TES_P2P_0002_state = TES_P2P_0002_STATE_SEND_RESP; 41 | txrx_printk(XRADIO_DBG_WARN, "[ROC_RESTART_STATE_SEND_RESP]\n"); 42 | } 43 | } 44 | } else if ( *oui_subtype == 0x02 ) { ///w, GO Negotiation Confirmation 45 | if( tx == false ) { 46 | TES_P2P_0002_state = TES_P2P_0002_STATE_IDLE; 47 | txrx_printk(XRADIO_DBG_WARN, "[ROC_RESTART_STATE_IDLE]" 48 | "[GO Negotiation Confirmation]\n"); 49 | } 50 | } else if ( *oui_subtype == 0x08 ) { ///w, Provision Discovery Response 51 | if(tx == false) { 52 | TES_P2P_0002_state = TES_P2P_0002_STATE_IDLE; 53 | txrx_printk(XRADIO_DBG_WARN, "[ROC_RESTART_STATE_IDLE]" 54 | "[Provision Discovery Response]\n"); 55 | } 56 | } 57 | } 58 | } 59 | } 60 | } 61 | } 62 | #endif -------------------------------------------------------------------------------- /p2p.h: -------------------------------------------------------------------------------- 1 | #ifndef XRADIO_P2P_H 2 | #define XRADIO_P2P_H 3 | 4 | void xradio_frame_monitor(struct xradio_common *hw_priv, struct sk_buff *skb, bool tx); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /pm.c: -------------------------------------------------------------------------------- 1 | /* 2 | * PM implementation for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #include 13 | #include 14 | #include "xradio.h" 15 | #include "pm.h" 16 | #include "sta.h" 17 | #include "bh.h" 18 | #include "sdio.h" 19 | 20 | #define XRADIO_BEACON_SKIPPING_MULTIPLIER 3 21 | 22 | struct xradio_udp_port_filter { 23 | struct wsm_udp_port_filter_hdr hdr; 24 | struct wsm_udp_port_filter dhcp; 25 | struct wsm_udp_port_filter upnp; 26 | } __packed; 27 | 28 | struct xradio_ether_type_filter { 29 | struct wsm_ether_type_filter_hdr hdr; 30 | struct wsm_ether_type_filter ip; 31 | struct wsm_ether_type_filter pae; 32 | struct wsm_ether_type_filter wapi; 33 | } __packed; 34 | 35 | static struct xradio_udp_port_filter xradio_udp_port_filter_on = { 36 | .hdr.nrFilters = 2, 37 | .dhcp = { 38 | .filterAction = WSM_FILTER_ACTION_FILTER_OUT, 39 | .portType = WSM_FILTER_PORT_TYPE_DST, 40 | .udpPort = __cpu_to_le16(67), 41 | }, 42 | .upnp = { 43 | .filterAction = WSM_FILTER_ACTION_FILTER_OUT, 44 | .portType = WSM_FILTER_PORT_TYPE_DST, 45 | .udpPort = __cpu_to_le16(1900), 46 | }, 47 | /* Please add other known ports to be filtered out here and 48 | * update nrFilters field in the header. 49 | * Up to 4 filters are allowed. */ 50 | }; 51 | 52 | static struct wsm_udp_port_filter_hdr xradio_udp_port_filter_off = { 53 | .nrFilters = 0, 54 | }; 55 | 56 | #ifndef ETH_P_WAPI 57 | #define ETH_P_WAPI 0x88B4 58 | #endif 59 | 60 | #ifdef TES_P2P_000B_DISABLE_EAPOL_FILTER 61 | /* TES_P2P_000B WorkAround: 62 | * when the link keep 10min more or less(i am not sure), 63 | * wpa_s session maybe expired, and want to update group key. 64 | * it will use eapol frame(802.1x,0x888E). 65 | * if driver suspend, and discard eapol frame, then session end. 66 | * i don't know why original code discards eapol frame in suspend. 67 | * but now make this filter disable as WorkAround. wzw */ 68 | static struct xradio_ether_type_filter xradio_ether_type_filter_on = { 69 | .hdr.nrFilters = 1, 70 | /* .ip = { 71 | .filterAction = WSM_FILTER_ACTION_FILTER_IN, 72 | .etherType = __cpu_to_le16(ETH_P_IP), 73 | },*/ 74 | /* .pae = { 75 | .filterAction = WSM_FILTER_ACTION_FILTER_IN, 76 | .etherType = __cpu_to_le16(ETH_P_PAE), 77 | },*/ 78 | .wapi = { 79 | .filterAction = WSM_FILTER_ACTION_FILTER_IN, 80 | .etherType = __cpu_to_le16(ETH_P_WAPI), 81 | }, 82 | /* Please add other known ether types to be filtered out here and 83 | * update nrFilters field in the header. 84 | * Up to 4 filters are allowed. */ 85 | }; 86 | #else 87 | static struct xradio_ether_type_filter xradio_ether_type_filter_on = { 88 | .hdr.nrFilters = 2, 89 | /* .ip = { 90 | .filterAction = WSM_FILTER_ACTION_FILTER_IN, 91 | .etherType = __cpu_to_le16(ETH_P_IP), 92 | },*/ 93 | .pae = { 94 | .filterAction = WSM_FILTER_ACTION_FILTER_IN, 95 | .etherType = __cpu_to_le16(ETH_P_PAE), 96 | }, 97 | .wapi = { 98 | .filterAction = WSM_FILTER_ACTION_FILTER_IN, 99 | .etherType = __cpu_to_le16(ETH_P_WAPI), 100 | }, 101 | /* Please add other known ether types to be filtered out here and 102 | * update nrFilters field in the header. 103 | * Up to 4 filters are allowed. */ 104 | }; 105 | #endif 106 | 107 | static struct wsm_ether_type_filter_hdr xradio_ether_type_filter_off = { 108 | .nrFilters = 0, 109 | }; 110 | 111 | static int xradio_suspend_late(struct device *dev); 112 | static void xradio_pm_release(struct device *dev); 113 | static int xradio_pm_probe(struct platform_device *pdev); 114 | static int __xradio_wow_suspend(struct xradio_vif *priv, 115 | struct cfg80211_wowlan *wowlan); 116 | static int __xradio_wow_resume(struct xradio_vif *priv); 117 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 118 | static int xradio_poweroff_suspend(struct xradio_common *hw_priv); 119 | static int xradio_poweroff_resume(struct xradio_common *hw_priv); 120 | #endif 121 | 122 | 123 | /* private */ 124 | struct xradio_suspend_state { 125 | unsigned long bss_loss_tmo; 126 | unsigned long connection_loss_tmo; 127 | unsigned long join_tmo; 128 | unsigned long direct_probe; 129 | unsigned long link_id_gc; 130 | bool beacon_skipping; 131 | }; 132 | 133 | static const struct dev_pm_ops xradio_pm_ops = { 134 | .suspend_noirq = xradio_suspend_late, 135 | }; 136 | 137 | static struct platform_driver xradio_power_driver = { 138 | .probe = xradio_pm_probe, 139 | .driver = { 140 | .name = XRADIO_PM_DEVICE, 141 | .pm = &xradio_pm_ops, 142 | }, 143 | }; 144 | 145 | static int xradio_pm_init_common(struct xradio_pm_state *pm, 146 | struct xradio_common *hw_priv) 147 | { 148 | int ret; 149 | pm_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); 150 | 151 | spin_lock_init(&pm->lock); 152 | /* Register pm driver. */ 153 | ret = platform_driver_register(&xradio_power_driver); 154 | if (ret) { 155 | pm_printk(XRADIO_DBG_ERROR, "%s:platform_driver_register failed(%d)!\n", 156 | __FUNCTION__, ret); 157 | return ret; 158 | } 159 | 160 | /* Add pm device. */ 161 | pm->pm_dev = platform_device_alloc(XRADIO_PM_DEVICE, 0); 162 | if (!pm->pm_dev) { 163 | pm_printk(XRADIO_DBG_ERROR, "%s:platform_device_alloc failed!\n", 164 | __FUNCTION__); 165 | platform_driver_unregister(&xradio_power_driver); 166 | return -ENOMEM; 167 | } 168 | pm->pm_dev->dev.platform_data = hw_priv; 169 | ret = platform_device_add(pm->pm_dev); 170 | if (ret) { 171 | pm_printk(XRADIO_DBG_ERROR, "%s:platform_device_add failed(%d)!\n", 172 | __FUNCTION__, ret); 173 | platform_driver_unregister(&xradio_power_driver); 174 | kfree(pm->pm_dev); 175 | pm->pm_dev = NULL; 176 | } 177 | 178 | return ret; 179 | } 180 | 181 | static void xradio_pm_deinit_common(struct xradio_pm_state *pm) 182 | { 183 | pm_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); 184 | platform_driver_unregister(&xradio_power_driver); 185 | if (pm->pm_dev) { 186 | pm->pm_dev->dev.platform_data = NULL; 187 | platform_device_unregister(pm->pm_dev); /* kfree is already do */ 188 | pm->pm_dev = NULL; 189 | } 190 | } 191 | 192 | #ifdef CONFIG_WAKELOCK 193 | 194 | int xradio_pm_init(struct xradio_pm_state *pm, 195 | struct xradio_common *hw_priv) 196 | { 197 | int ret = 0; 198 | pm_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); 199 | 200 | ret = xradio_pm_init_common(pm, hw_priv); 201 | if (!ret) 202 | wake_lock_init(&pm->wakelock, WAKE_LOCK_SUSPEND, XRADIO_WAKE_LOCK); 203 | else 204 | pm_printk(XRADIO_DBG_ERROR,"xradio_pm_init_common failed!\n"); 205 | return ret; 206 | } 207 | 208 | void xradio_pm_deinit(struct xradio_pm_state *pm) 209 | { 210 | pm_printk(XRADIO_DBG_TRC,"%s\n", __FUNCTION__); 211 | if (wake_lock_active(&pm->wakelock)) 212 | wake_unlock(&pm->wakelock); 213 | wake_lock_destroy(&pm->wakelock); 214 | xradio_pm_deinit_common(pm); 215 | } 216 | 217 | void xradio_pm_stay_awake(struct xradio_pm_state *pm, 218 | unsigned long tmo) 219 | { 220 | long cur_tmo; 221 | pm_printk(XRADIO_DBG_MSG,"%s\n", __FUNCTION__); 222 | 223 | spin_lock_bh(&pm->lock); 224 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) 225 | cur_tmo = pm->wakelock.ws.timer.expires - jiffies; 226 | #else 227 | cur_tmo = pm->wakelock.expires - jiffies; 228 | #endif 229 | if (!wake_lock_active(&pm->wakelock) || cur_tmo < (long)tmo) 230 | wake_lock_timeout(&pm->wakelock, tmo); 231 | spin_unlock_bh(&pm->lock); 232 | } 233 | void xradio_pm_lock_awake(struct xradio_pm_state *pm) 234 | { 235 | 236 | spin_lock_bh(&pm->lock); 237 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) 238 | pm->expires_save = pm->wakelock.ws.timer.expires; 239 | #else 240 | pm->expires_save = pm->wakelock.expires; 241 | #endif 242 | wake_lock_timeout(&pm->wakelock, LONG_MAX); 243 | spin_unlock_bh(&pm->lock); 244 | } 245 | void xradio_pm_unlock_awake(struct xradio_pm_state *pm) 246 | { 247 | 248 | spin_lock_bh(&pm->lock); 249 | pm->expires_save -= jiffies; 250 | if (pm->expires_save) 251 | wake_lock_timeout(&pm->wakelock, pm->expires_save); 252 | else 253 | wake_lock_timeout(&pm->wakelock, 1); 254 | spin_unlock_bh(&pm->lock); 255 | } 256 | 257 | #else /* CONFIG_WAKELOCK */ 258 | 259 | 260 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) 261 | static void xradio_pm_stay_awake_tmo(struct timer_list *t) 262 | { 263 | struct xradio_pm_state *pm = from_timer(pm, t, stay_awake); 264 | #else 265 | static void xradio_pm_stay_awake_tmo(unsigned long arg) 266 | { 267 | struct xradio_pm_state *pm = (struct xradio_pm_state *)arg; 268 | #endif 269 | (void)pm; 270 | } 271 | 272 | int xradio_pm_init(struct xradio_pm_state *pm, 273 | struct xradio_common *hw_priv) 274 | { 275 | int ret = 0; 276 | pm_printk(XRADIO_DBG_MSG,"%s\n", __FUNCTION__); 277 | 278 | ret = xradio_pm_init_common(pm, hw_priv); 279 | if (!ret) { 280 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) 281 | timer_setup(&pm->stay_awake, xradio_pm_stay_awake_tmo, 0); 282 | #else 283 | init_timer(&pm->stay_awake); 284 | pm->stay_awake.data = (unsigned long)pm; 285 | pm->stay_awake.function = xradio_pm_stay_awake_tmo; 286 | #endif 287 | } else 288 | pm_printk(XRADIO_DBG_ERROR,"xradio_pm_init_common failed!\n"); 289 | return ret; 290 | } 291 | 292 | void xradio_pm_deinit(struct xradio_pm_state *pm) 293 | { 294 | del_timer_sync(&pm->stay_awake); 295 | xradio_pm_deinit_common(pm); 296 | } 297 | 298 | void xradio_pm_stay_awake(struct xradio_pm_state *pm, 299 | unsigned long tmo) 300 | { 301 | long cur_tmo; 302 | 303 | spin_lock_bh(&pm->lock); 304 | cur_tmo = pm->stay_awake.expires - jiffies; 305 | if (!timer_pending(&pm->stay_awake) || cur_tmo < (long)tmo) 306 | mod_timer(&pm->stay_awake, jiffies + tmo); 307 | spin_unlock_bh(&pm->lock); 308 | } 309 | void xradio_pm_lock_awake(struct xradio_pm_state *pm) 310 | { 311 | 312 | spin_lock_bh(&pm->lock); 313 | pm->expires_save = pm->stay_awake.expires; 314 | mod_timer(&pm->stay_awake, jiffies + LONG_MAX); 315 | spin_unlock_bh(&pm->lock); 316 | } 317 | void xradio_pm_unlock_awake(struct xradio_pm_state *pm) 318 | { 319 | 320 | spin_lock_bh(&pm->lock); 321 | if (time_before(jiffies, pm->expires_save)) 322 | mod_timer(&pm->stay_awake, pm->expires_save); 323 | else 324 | mod_timer(&pm->stay_awake, jiffies + 1); 325 | spin_unlock_bh(&pm->lock); 326 | } 327 | #endif /* CONFIG_WAKELOCK */ 328 | 329 | static long xradio_suspend_work(struct delayed_work *work) 330 | { 331 | int ret = cancel_delayed_work(work); 332 | long tmo; 333 | pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); 334 | 335 | if (ret > 0) { 336 | /* Timer is pending */ 337 | tmo = work->timer.expires - jiffies; 338 | if (tmo < 0) 339 | tmo = 0; 340 | } else { 341 | tmo = -1; 342 | } 343 | return tmo; 344 | } 345 | 346 | static int xradio_resume_work(struct xradio_common *hw_priv, 347 | struct delayed_work *work, 348 | unsigned long tmo) 349 | { 350 | pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); 351 | if ((long)tmo < 0) 352 | return 1; 353 | 354 | return queue_delayed_work(hw_priv->workqueue, work, tmo); 355 | } 356 | 357 | static int xradio_suspend_late(struct device *dev) 358 | { 359 | struct xradio_common *hw_priv = dev->platform_data; 360 | 361 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 362 | if (XRADIO_POWEROFF_SUSP == atomic_read(&hw_priv->suspend_state)) { 363 | return 0; /* we don't rx data when power down wifi.*/ 364 | } 365 | #endif 366 | 367 | //if (atomic_read(&hw_priv->bh_rx)) { 368 | // pm_printk(XRADIO_DBG_WARN, "%s: Suspend interrupted.\n", __func__); 369 | // return -EAGAIN; 370 | //} 371 | return 0; 372 | } 373 | 374 | static void xradio_pm_release(struct device *dev) 375 | { 376 | pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); 377 | } 378 | 379 | static int xradio_pm_probe(struct platform_device *pdev) 380 | { 381 | pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); 382 | pdev->dev.release = xradio_pm_release; 383 | return 0; 384 | } 385 | 386 | int xradio_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) 387 | { 388 | struct xradio_common *hw_priv = hw->priv; 389 | struct xradio_vif *priv; 390 | int i, ret = 0; 391 | 392 | 393 | if(hw_priv->bh_error) return -EBUSY; 394 | WARN_ON(!atomic_read(&hw_priv->num_vifs)); 395 | 396 | if (work_pending(&hw_priv->query_work)) 397 | return -EBUSY; 398 | 399 | #ifdef ROAM_OFFLOAD 400 | xradio_for_each_vif(hw_priv, priv, i) { 401 | if (!priv) 402 | continue; 403 | if((priv->vif->type == NL80211_IFTYPE_STATION) 404 | && (priv->join_status == XRADIO_JOIN_STATUS_STA)) { 405 | down(&hw_priv->scan.lock); 406 | hw_priv->scan.if_id = priv->if_id; 407 | xradio_sched_scan_work(&hw_priv->scan.swork); 408 | } 409 | } 410 | #endif /*ROAM_OFFLOAD*/ 411 | 412 | /* Do not suspend when datapath is not idle */ 413 | if (hw_priv->tx_queue_stats.num_queued[0] + 414 | hw_priv->tx_queue_stats.num_queued[1]) { 415 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 416 | "because of tx_queue is not empty.\n"); 417 | return -EBUSY; 418 | } 419 | 420 | /* Make sure there is no configuration requests in progress. */ 421 | if (!mutex_trylock(&hw_priv->conf_mutex)) { 422 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 423 | "because of configuration requests.\n"); 424 | return -EBUSY; 425 | } 426 | 427 | /* Make sure there is no wsm_oper_lock in progress. */ 428 | if (!mutex_trylock(&hw_priv->wsm_oper_lock)) { 429 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 430 | "because of wsm_oper_lock.\n"); 431 | mutex_unlock(&hw_priv->conf_mutex); 432 | return -EBUSY; 433 | } 434 | 435 | /* Do not suspend when scanning or ROC*/ 436 | if (down_trylock(&hw_priv->scan.lock)) { 437 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 438 | "because of scan requests.\n"); 439 | goto revert1; 440 | } 441 | 442 | if (delayed_work_pending(&hw_priv->scan.probe_work)) { 443 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 444 | "because of probe frames tx in progress.\n"); 445 | goto revert2; 446 | } 447 | 448 | /* Lock TX. */ 449 | wsm_lock_tx_async(hw_priv); 450 | 451 | /* Wait to avoid possible race with bh code. 452 | * But do not wait too long... */ 453 | if (wait_event_timeout(hw_priv->bh_evt_wq, 454 | !hw_priv->hw_bufs_used, HZ / 10) <= 0) { 455 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 456 | "because of there are frames not confirm.\n"); 457 | goto revert3; 458 | } 459 | 460 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 461 | // if (STANDBY_WITH_POWER_OFF == standby_level) { 462 | if (1) { 463 | return xradio_poweroff_suspend(hw_priv); 464 | } 465 | #endif 466 | 467 | xradio_for_each_vif(hw_priv, priv, i) { 468 | if (!priv) 469 | continue; 470 | 471 | ret = __xradio_wow_suspend(priv, wowlan); 472 | if (ret) { 473 | for (; i >= 0; i--) { 474 | if (!hw_priv->vif_list[i]) 475 | continue; 476 | priv = (struct xradio_vif *)hw_priv->vif_list[i]->drv_priv; 477 | __xradio_wow_resume(priv); 478 | } 479 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 480 | "because of __xradio_wow_suspend failed!\n"); 481 | goto revert3; 482 | } 483 | } 484 | 485 | /* Stop serving thread */ 486 | if (xradio_bh_suspend(hw_priv)) { 487 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 488 | "because of xradio_bh_suspend failed!\n"); 489 | xradio_wow_resume(hw); 490 | return -EBUSY; 491 | } 492 | 493 | /* Enable IRQ wake */ 494 | ret = sdio_pm(hw_priv, true); 495 | if (ret) { 496 | pm_printk(XRADIO_DBG_WARN, "Don't suspend sbus pm failed\n"); 497 | xradio_wow_resume(hw); 498 | return -EBUSY; 499 | } 500 | 501 | /* Force resume if event is coming from the device. */ 502 | //if (atomic_read(&hw_priv->bh_rx)) { 503 | // pm_printk(XRADIO_DBG_WARN, "Don't suspend " 504 | // "because of recieved rx event!\n"); 505 | // xradio_wow_resume(hw); 506 | // return -EAGAIN; 507 | //} 508 | return 0; 509 | 510 | revert3: 511 | wsm_unlock_tx(hw_priv); 512 | revert2: 513 | up(&hw_priv->scan.lock); 514 | revert1: 515 | mutex_unlock(&hw_priv->conf_mutex); 516 | mutex_unlock(&hw_priv->wsm_oper_lock); 517 | return -EBUSY; 518 | } 519 | 520 | static int __xradio_wow_suspend(struct xradio_vif *priv, 521 | struct cfg80211_wowlan *wowlan) 522 | { 523 | struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); 524 | struct xradio_pm_state_vif *pm_state_vif = &priv->pm_state_vif; 525 | struct xradio_suspend_state *state; 526 | int ret; 527 | #ifdef MCAST_FWDING 528 | struct wsm_forwarding_offload fwdoffload = { 529 | .fwenable = 0x1, 530 | .flags = 0x1, 531 | }; 532 | #endif 533 | 534 | 535 | /* Do not suspend when join work is scheduled */ 536 | if (work_pending(&priv->join_work)) { 537 | pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend " 538 | "when join work is scheduled\n", __func__); 539 | goto revert1; 540 | } 541 | 542 | /* Set UDP filter */ 543 | wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_on.hdr, 544 | priv->if_id); 545 | 546 | /* Set ethernet frame type filter */ 547 | wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_on.hdr, 548 | priv->if_id); 549 | 550 | /* Set IP multicast filter */ 551 | wsm_set_host_sleep(hw_priv, 1, priv->if_id); 552 | 553 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 554 | WARN_ON(wsm_set_keepalive_filter(priv, true)); 555 | 556 | #ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE 557 | /* Set Multicast Address Filter */ 558 | if (priv->multicast_filter.numOfAddresses) { 559 | priv->multicast_filter.enable = 1; 560 | wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); 561 | } 562 | 563 | /* Set Enable Broadcast Address Filter */ 564 | priv->broadcast_filter.action_mode = 1; 565 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 566 | priv->broadcast_filter.address_mode = 3; 567 | 568 | xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter); 569 | #endif 570 | 571 | #ifdef MCAST_FWDING 572 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 573 | WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload,priv->if_id)); 574 | #endif 575 | 576 | /* Allocate state */ 577 | state = kzalloc(sizeof(struct xradio_suspend_state), GFP_KERNEL); 578 | if (!state) { 579 | pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend " 580 | "alloc xradio_suspend_state failed.\n", __func__); 581 | goto revert2; 582 | } 583 | /* Store delayed work states. */ 584 | state->bss_loss_tmo = xradio_suspend_work(&priv->bss_loss_work); 585 | state->connection_loss_tmo = xradio_suspend_work(&priv->connection_loss_work); 586 | state->join_tmo = xradio_suspend_work(&priv->join_timeout); 587 | state->link_id_gc = xradio_suspend_work(&priv->link_id_gc_work); 588 | 589 | /* Enable beacon skipping */ 590 | if (priv->join_status == XRADIO_JOIN_STATUS_STA && 591 | priv->join_dtim_period && !priv->has_multicast_subscription) { 592 | state->beacon_skipping = true; 593 | wsm_set_beacon_wakeup_period(hw_priv, priv->join_dtim_period * XRADIO_BEACON_SKIPPING_MULTIPLIER, 0, priv->if_id); 594 | } 595 | 596 | ret = timer_pending(&priv->mcast_timeout); 597 | if (ret) { 598 | pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend " 599 | "mcast timeout timer_pending failed.\n", __func__); 600 | goto revert3; 601 | } 602 | 603 | /* Store suspend state */ 604 | pm_state_vif->suspend_state = state; 605 | 606 | return 0; 607 | 608 | revert3: 609 | xradio_resume_work(hw_priv, &priv->bss_loss_work, state->bss_loss_tmo); 610 | xradio_resume_work(hw_priv, &priv->connection_loss_work, 611 | state->connection_loss_tmo); 612 | xradio_resume_work(hw_priv, &priv->join_timeout, state->join_tmo); 613 | xradio_resume_work(hw_priv, &priv->link_id_gc_work, state->link_id_gc); 614 | kfree(state); 615 | 616 | revert2: 617 | wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_off, priv->if_id); 618 | wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_off, priv->if_id); 619 | wsm_set_host_sleep(hw_priv, 0, priv->if_id); 620 | 621 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 622 | WARN_ON(wsm_set_keepalive_filter(priv, false)); 623 | 624 | #ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE 625 | /* Set Multicast Address Filter */ 626 | if (priv->multicast_filter.numOfAddresses) { 627 | priv->multicast_filter.enable = 0; 628 | wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); 629 | } 630 | 631 | /* Set Enable Broadcast Address Filter */ 632 | priv->broadcast_filter.action_mode = 0; 633 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 634 | priv->broadcast_filter.address_mode = 0; 635 | xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter); 636 | #endif 637 | 638 | #ifdef MCAST_FWDING 639 | fwdoffload.flags = 0x0; 640 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 641 | WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload,priv->if_id)); 642 | #endif 643 | 644 | revert1: 645 | /* mutex_unlock(&hw_priv->conf_mutex); */ 646 | return -EBUSY; 647 | } 648 | 649 | int xradio_wow_resume(struct ieee80211_hw *hw) 650 | { 651 | 652 | struct xradio_common *hw_priv = hw->priv; 653 | struct xradio_vif *priv; 654 | int i, ret = 0; 655 | 656 | 657 | WARN_ON(!atomic_read(&hw_priv->num_vifs)); 658 | if(hw_priv->bh_error) return 0; 659 | 660 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 661 | if (XRADIO_POWEROFF_SUSP == atomic_read(&hw_priv->suspend_state)) { 662 | return xradio_poweroff_resume(hw_priv); 663 | } 664 | #endif 665 | 666 | /* Disable IRQ wake */ 667 | sdio_pm(hw_priv, false); 668 | 669 | up(&hw_priv->scan.lock); 670 | 671 | /* Resume BH thread */ 672 | WARN_ON(xradio_bh_resume(hw_priv)); 673 | 674 | xradio_for_each_vif(hw_priv, priv, i) { 675 | if (!priv) 676 | continue; 677 | ret = __xradio_wow_resume(priv); 678 | if (ret) { 679 | pm_printk(XRADIO_DBG_ERROR, "%s:__xradio_wow_resume failed!\n", __func__); 680 | break; 681 | } 682 | } 683 | 684 | wsm_unlock_tx(hw_priv); 685 | 686 | /* Unlock configuration mutex */ 687 | mutex_unlock(&hw_priv->conf_mutex); 688 | mutex_unlock(&hw_priv->wsm_oper_lock); 689 | 690 | return ret; 691 | } 692 | 693 | static int __xradio_wow_resume(struct xradio_vif *priv) 694 | { 695 | struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); 696 | struct xradio_pm_state_vif *pm_state_vif = &priv->pm_state_vif; 697 | struct xradio_suspend_state *state; 698 | #ifdef MCAST_FWDING 699 | struct wsm_forwarding_offload fwdoffload = { 700 | .fwenable = 0x1, 701 | .flags = 0x0, 702 | }; 703 | #endif 704 | 705 | 706 | /* Restore suspend state */ 707 | state = pm_state_vif->suspend_state; 708 | pm_state_vif->suspend_state = NULL; 709 | 710 | #ifdef ROAM_OFFLOAD 711 | if((priv->vif->type == NL80211_IFTYPE_STATION) 712 | && (priv->join_status == XRADIO_JOIN_STATUS_STA)) 713 | xradio_hw_sched_scan_stop(hw_priv); 714 | #endif /*ROAM_OFFLOAD*/ 715 | 716 | if (state->beacon_skipping) { 717 | #ifdef XRADIO_USE_LONG_DTIM_PERIOD 718 | int join_dtim_period_extend; 719 | if (priv->join_dtim_period <= 3) { 720 | join_dtim_period_extend = priv->join_dtim_period * 3; 721 | } else if (priv->join_dtim_period <= 5) { 722 | join_dtim_period_extend = priv->join_dtim_period * 2; 723 | } else { 724 | join_dtim_period_extend = priv->join_dtim_period; 725 | } 726 | wsm_set_beacon_wakeup_period(hw_priv, join_dtim_period_extend, 0, priv->if_id); 727 | #else 728 | wsm_set_beacon_wakeup_period(hw_priv, priv->join_dtim_period, 0, priv->if_id); 729 | #endif 730 | state->beacon_skipping = false; 731 | } 732 | 733 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 734 | WARN_ON(wsm_set_keepalive_filter(priv, false)); 735 | 736 | #ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE 737 | /* Set Multicast Address Filter */ 738 | if (priv->multicast_filter.numOfAddresses) { 739 | priv->multicast_filter.enable = 0; 740 | wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); 741 | } 742 | /* Set Enable Broadcast Address Filter */ 743 | priv->broadcast_filter.action_mode = 0; 744 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 745 | priv->broadcast_filter.address_mode = 0; 746 | xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter); 747 | #endif 748 | 749 | #ifdef MCAST_FWDING 750 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 751 | WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload,priv->if_id)); 752 | #endif 753 | 754 | /* Resume delayed work */ 755 | xradio_resume_work(hw_priv, &priv->bss_loss_work, state->bss_loss_tmo); 756 | xradio_resume_work(hw_priv, &priv->connection_loss_work, 757 | state->connection_loss_tmo); 758 | xradio_resume_work(hw_priv, &priv->join_timeout, state->join_tmo); 759 | xradio_resume_work(hw_priv, &priv->link_id_gc_work, state->link_id_gc); 760 | 761 | /* Remove UDP port filter */ 762 | wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_off, priv->if_id); 763 | 764 | /* Remove ethernet frame type filter */ 765 | wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_off, priv->if_id); 766 | 767 | /* Remove IP multicast filter */ 768 | wsm_set_host_sleep(hw_priv, 0, priv->if_id); 769 | /* Free memory */ 770 | kfree(state); 771 | 772 | return 0; 773 | } 774 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 775 | static int xradio_poweroff_suspend(struct xradio_common *hw_priv) 776 | { 777 | 778 | //flush all work. 779 | cancel_work_sync(&hw_priv->query_work); 780 | flush_workqueue(hw_priv->workqueue); 781 | /* Schedule hardware restart, ensure no cmds in progress.*/ 782 | mutex_lock(&hw_priv->wsm_cmd_mux); 783 | atomic_set(&hw_priv->suspend_state, XRADIO_POWEROFF_SUSP); 784 | //hw_priv->hw_restart = true; 785 | mutex_unlock(&hw_priv->wsm_cmd_mux); 786 | /* Stop serving thread */ 787 | if (xradio_bh_suspend(hw_priv)) { 788 | pm_printk(XRADIO_DBG_WARN, "%s, xradio_bh_suspend failed!\n", __func__); 789 | return -EBUSY; 790 | } 791 | 792 | return 0; 793 | } 794 | 795 | static int xradio_poweroff_resume(struct xradio_common *hw_priv) 796 | { 797 | 798 | /* Revert locks */ 799 | wsm_unlock_tx(hw_priv); 800 | up(&hw_priv->scan.lock); 801 | mutex_unlock(&hw_priv->conf_mutex); 802 | mutex_unlock(&hw_priv->wsm_oper_lock); 803 | //if (schedule_work(&hw_priv->hw_restart_work) <= 0) 804 | // pm_printk(XRADIO_DBG_ERROR, "%s restart_work failed!\n", __func__); 805 | return 0; 806 | } 807 | #endif 808 | -------------------------------------------------------------------------------- /pm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * power management interfaces for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | 13 | #ifndef PM_H_INCLUDED 14 | #define PM_H_INCLUDED 15 | 16 | #ifdef CONFIG_WAKELOCK 17 | #include 18 | #endif 19 | 20 | /* ******************************************************************** */ 21 | /* mac80211 API */ 22 | 23 | #ifdef CONFIG_PM 24 | 25 | #define XRADIO_PM_DEVICE "xradio_pm" 26 | #define XRADIO_WAKE_LOCK "xradio_wlan" 27 | 28 | /* extern */ struct xradio_common; 29 | /* private */ struct xradio_suspend_state; 30 | 31 | struct xradio_pm_state { 32 | #ifdef CONFIG_WAKELOCK 33 | struct wake_lock wakelock; 34 | #else 35 | struct timer_list stay_awake; 36 | #endif 37 | struct platform_device *pm_dev; 38 | spinlock_t lock; 39 | unsigned long expires_save; 40 | }; 41 | 42 | struct xradio_pm_state_vif { 43 | struct xradio_suspend_state *suspend_state; 44 | }; 45 | 46 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 47 | enum suspend_state { 48 | XRADIO_RESUME = 0, 49 | XRADIO_CONNECT_SUSP, 50 | XRADIO_DISCONNECT_SUSP, 51 | XRADIO_POWEROFF_SUSP 52 | }; 53 | #endif 54 | int xradio_pm_init(struct xradio_pm_state *pm, struct xradio_common *priv); 55 | void xradio_pm_deinit(struct xradio_pm_state *pm); 56 | void xradio_pm_stay_awake(struct xradio_pm_state *pm, unsigned long tmo); 57 | void xradio_pm_lock_awake(struct xradio_pm_state *pm); 58 | void xradio_pm_unlock_awake(struct xradio_pm_state *pm); 59 | int xradio_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); 60 | int xradio_wow_resume(struct ieee80211_hw *hw); 61 | 62 | #endif /* CONFIG_PM */ 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * queue operations for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | 13 | #ifndef XRADIO_QUEUE_H_INCLUDED 14 | #define XRADIO_QUEUE_H_INCLUDED 15 | 16 | /* private */ struct xradio_queue_item; 17 | 18 | /* extern */ struct sk_buff; 19 | /* extern */ struct wsm_tx; 20 | /* extern */ struct xradio_common; 21 | /* extern */ struct xradio_vif; 22 | /* extern */ struct ieee80211_tx_queue_stats; 23 | /* extern */ struct xradio_txpriv; 24 | 25 | /* forward */ struct xradio_queue_stats; 26 | 27 | typedef void (*xradio_queue_skb_dtor_t)(struct xradio_common *priv, 28 | struct sk_buff *skb, 29 | const struct xradio_txpriv *txpriv); 30 | 31 | struct xradio_queue { 32 | struct xradio_queue_stats *stats; 33 | size_t capacity; 34 | size_t num_queued; 35 | size_t num_queued_vif[XRWL_MAX_VIFS]; 36 | size_t num_pending; 37 | size_t num_pending_vif[XRWL_MAX_VIFS]; 38 | size_t num_sent; 39 | struct xradio_queue_item *pool; 40 | struct list_head queue; 41 | struct list_head free_pool; 42 | struct list_head pending; 43 | int tx_locked_cnt; 44 | int *link_map_cache[XRWL_MAX_VIFS]; 45 | bool overfull; 46 | spinlock_t lock; 47 | u8 queue_id; 48 | u8 generation; 49 | struct timer_list gc; 50 | unsigned long ttl; 51 | }; 52 | 53 | struct xradio_queue_stats { 54 | spinlock_t lock; 55 | int *link_map_cache[XRWL_MAX_VIFS]; 56 | int num_queued[XRWL_MAX_VIFS]; 57 | size_t map_capacity; 58 | wait_queue_head_t wait_link_id_empty; 59 | xradio_queue_skb_dtor_t skb_dtor; 60 | struct xradio_common *hw_priv; 61 | }; 62 | 63 | struct xradio_txpriv { 64 | u8 link_id; 65 | u8 raw_link_id; 66 | u8 tid; 67 | u8 rate_id; 68 | u8 offset; 69 | u8 if_id; 70 | u8 offchannel_if_id; 71 | u8 use_bg_rate; 72 | }; 73 | 74 | int xradio_queue_stats_init(struct xradio_queue_stats *stats, 75 | size_t map_capacity, 76 | size_t map_capacity_size, 77 | xradio_queue_skb_dtor_t skb_dtor, 78 | struct xradio_common *priv); 79 | int xradio_queue_init(struct xradio_queue *queue, 80 | struct xradio_queue_stats *stats, 81 | u8 queue_id, 82 | size_t capacity, 83 | unsigned long ttl); 84 | int xradio_queue_clear(struct xradio_queue *queue, int if_id); 85 | void xradio_queue_stats_deinit(struct xradio_queue_stats *stats); 86 | void xradio_queue_deinit(struct xradio_queue *queue); 87 | 88 | size_t xradio_queue_get_num_queued(struct xradio_vif *priv, 89 | struct xradio_queue *queue, 90 | u32 link_id_map); 91 | int xradio_queue_put(struct xradio_queue *queue, 92 | struct sk_buff *skb, struct xradio_txpriv *txpriv); 93 | int xradio_queue_get(struct xradio_queue *queue, 94 | int if_id, u32 link_id_map, 95 | struct wsm_tx **tx, 96 | struct ieee80211_tx_info **tx_info, 97 | struct xradio_txpriv **txpriv); 98 | 99 | int xradio_queue_requeue(struct xradio_queue *queue, u32 packetID, bool check); 100 | 101 | int xradio_queue_requeue_all(struct xradio_queue *queue); 102 | int xradio_queue_remove(struct xradio_queue *queue, 103 | u32 packetID); 104 | 105 | int xradio_queue_get_skb(struct xradio_queue *queue, u32 packetID, 106 | struct sk_buff **skb, 107 | const struct xradio_txpriv **txpriv); 108 | void xradio_queue_lock(struct xradio_queue *queue); 109 | void xradio_queue_unlock(struct xradio_queue *queue); 110 | bool xradio_queue_get_xmit_timestamp(struct xradio_queue *queue, 111 | unsigned long *timestamp, int if_id, 112 | u32 pending_frameID, u32 *Old_frame_ID); 113 | bool xradio_query_txpkt_timeout(struct xradio_common *hw_priv, int if_id, 114 | u32 pending_pkt_id, long *timeout); 115 | 116 | 117 | bool xradio_queue_stats_is_empty(struct xradio_queue_stats *stats, 118 | u32 link_id_map, int if_id); 119 | 120 | static inline u8 xradio_queue_get_queue_id(u32 packetID) 121 | { 122 | return (packetID >> 16) & 0xF; 123 | } 124 | 125 | static inline u8 xradio_queue_get_if_id(u32 packetID) 126 | { 127 | return (packetID >> 20) & 0xF; 128 | } 129 | 130 | static inline u8 xradio_queue_get_link_id(u32 packetID) 131 | { 132 | return (packetID >> 24) & 0xF; 133 | } 134 | 135 | static inline u8 xradio_queue_get_generation(u32 packetID) 136 | { 137 | return (packetID >> 8) & 0xFF; 138 | } 139 | 140 | #endif /* XRADIO_QUEUE_H_INCLUDED */ 141 | -------------------------------------------------------------------------------- /rx.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "xradio.h" 4 | #include "rx.h" 5 | #include "ht.h" 6 | #include "p2p.h" 7 | #include "sta.h" 8 | #include "bh.h" 9 | #include "ap.h" 10 | 11 | static void xradio_check_go_neg_conf_success(struct xradio_common *hw_priv, 12 | u8 *action) 13 | { 14 | if (action[2] == 0x50 && action[3] == 0x6F && action[4] == 0x9A && 15 | action[5] == 0x09 && action[6] == 0x02) { 16 | if(action[17] == 0) { 17 | hw_priv->is_go_thru_go_neg = true; 18 | } 19 | else { 20 | hw_priv->is_go_thru_go_neg = false; 21 | } 22 | } 23 | } 24 | 25 | static int xradio_handle_pspoll(struct xradio_vif *priv, 26 | struct sk_buff *skb) 27 | { 28 | struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); 29 | struct ieee80211_sta *sta; 30 | struct ieee80211_pspoll *pspoll = 31 | (struct ieee80211_pspoll *) skb->data; 32 | int link_id = 0; 33 | u32 pspoll_mask = 0; 34 | int drop = 1; 35 | int i; 36 | 37 | 38 | if (priv->join_status != XRADIO_JOIN_STATUS_AP) 39 | goto done; 40 | if (memcmp(priv->vif->addr, pspoll->bssid, ETH_ALEN)) 41 | goto done; 42 | 43 | rcu_read_lock(); 44 | sta = ieee80211_find_sta(priv->vif, pspoll->ta); 45 | if (sta) { 46 | struct xradio_sta_priv *sta_priv; 47 | sta_priv = (struct xradio_sta_priv *)&sta->drv_priv; 48 | link_id = sta_priv->link_id; 49 | pspoll_mask = BIT(sta_priv->link_id); 50 | } 51 | rcu_read_unlock(); 52 | if (!link_id) 53 | goto done; 54 | 55 | priv->pspoll_mask |= pspoll_mask; 56 | drop = 0; 57 | 58 | /* Do not report pspols if data for given link id is 59 | * queued already. */ 60 | for (i = 0; i < 4; ++i) { 61 | if (xradio_queue_get_num_queued(priv, 62 | &hw_priv->tx_queue[i], 63 | pspoll_mask)) { 64 | xradio_bh_wakeup(hw_priv); 65 | drop = 1; 66 | break; 67 | } 68 | } 69 | txrx_printk(XRADIO_DBG_NIY, "[RX] PSPOLL: %s\n", drop ? "local" : "fwd"); 70 | done: 71 | return drop; 72 | } 73 | 74 | 75 | static void 76 | xradio_rx_h_ba_stat(struct xradio_vif *priv, 77 | size_t hdrlen, size_t skb_len ) 78 | { 79 | struct xradio_common *hw_priv = priv->hw_priv; 80 | 81 | 82 | if (priv->join_status != XRADIO_JOIN_STATUS_STA) 83 | return; 84 | if (!xradio_is_ht(&hw_priv->ht_oper)) 85 | return; 86 | if (!priv->setbssparams_done) 87 | return; 88 | 89 | spin_lock_bh(&hw_priv->ba_lock); 90 | hw_priv->ba_acc_rx += skb_len - hdrlen; 91 | if (!(hw_priv->ba_cnt_rx || hw_priv->ba_cnt)) { 92 | mod_timer(&hw_priv->ba_timer, 93 | jiffies + XRADIO_BLOCK_ACK_INTERVAL); 94 | } 95 | hw_priv->ba_cnt_rx++; 96 | spin_unlock_bh(&hw_priv->ba_lock); 97 | } 98 | 99 | void xradio_rx_cb(struct xradio_vif *priv, 100 | struct wsm_rx *arg, 101 | struct sk_buff **skb_p) 102 | { 103 | struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); 104 | struct sk_buff *skb = *skb_p; 105 | struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb); 106 | struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; 107 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 108 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 109 | #endif 110 | struct xradio_link_entry *entry = NULL; 111 | unsigned long grace_period; 112 | bool early_data = false; 113 | size_t hdrlen = 0; 114 | u8 parse_iv_len = 0; 115 | 116 | dev_dbg(hw_priv->pdev, "vif %d: rx, status %u flags 0x%.8x", 117 | priv->if_id, arg->status, arg->flags); 118 | if(ieee80211_is_deauth(frame->frame_control)) 119 | dev_dbg(hw_priv->pdev, "vif %d: deauth\n", priv->if_id); 120 | 121 | hdr->flag = 0; 122 | 123 | if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) { 124 | /* STA is stopped. */ 125 | goto drop; 126 | } 127 | 128 | #ifdef TES_P2P_0002_ROC_RESTART 129 | xradio_frame_monitor(hw_priv,skb,false); 130 | #endif 131 | 132 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 133 | if ((ieee80211_is_action(frame->frame_control)) 134 | && (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { 135 | u8 *action = (u8*)&mgmt->u.action.category; 136 | xradio_check_go_neg_conf_success(hw_priv, action); 137 | } 138 | #endif 139 | 140 | if (arg->link_id && (arg->link_id != XRADIO_LINK_ID_UNMAPPED) 141 | && (arg->link_id <= XRADIO_MAX_STA_IN_AP_MODE)) { 142 | entry = &priv->link_id_db[arg->link_id - 1]; 143 | if (entry->status == XRADIO_LINK_SOFT && 144 | ieee80211_is_data(frame->frame_control)) 145 | early_data = true; 146 | entry->timestamp = jiffies; 147 | } 148 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 149 | else if ((arg->link_id == XRADIO_LINK_ID_UNMAPPED) 150 | && (priv->vif->p2p == WSM_START_MODE_P2P_GO) 151 | && ieee80211_is_action(frame->frame_control) 152 | && (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { 153 | txrx_printk(XRADIO_DBG_NIY, "[RX] Going to MAP&RESET link ID\n"); 154 | 155 | if (work_pending(&priv->linkid_reset_work)) 156 | WARN_ON(1); 157 | 158 | memcpy(&priv->action_frame_sa[0], 159 | ieee80211_get_SA(frame), ETH_ALEN); 160 | priv->action_linkid = 0; 161 | schedule_work(&priv->linkid_reset_work); 162 | } 163 | 164 | if (arg->link_id && (arg->link_id != XRADIO_LINK_ID_UNMAPPED) 165 | && (priv->vif->p2p == WSM_START_MODE_P2P_GO) 166 | && ieee80211_is_action(frame->frame_control) 167 | && (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { 168 | /* Link ID already exists for the ACTION frame. 169 | * Reset and Remap */ 170 | if (work_pending(&priv->linkid_reset_work)) 171 | WARN_ON(1); 172 | memcpy(&priv->action_frame_sa[0], 173 | ieee80211_get_SA(frame), ETH_ALEN); 174 | priv->action_linkid = arg->link_id; 175 | schedule_work(&priv->linkid_reset_work); 176 | } 177 | #endif 178 | if (unlikely(arg->status)) { 179 | if (arg->status == WSM_STATUS_MICFAILURE) { 180 | dev_err(priv->hw_priv->pdev, "[RX] IF=%d, MIC failure.\n", 181 | priv->if_id); 182 | hdr->flag |= RX_FLAG_MMIC_ERROR; 183 | } else if (arg->status == WSM_STATUS_NO_KEY_FOUND) { 184 | dev_warn(priv->hw_priv->pdev, "received frame has no key status\n"); 185 | //goto drop; 186 | } else { 187 | dev_err(priv->hw_priv->pdev, "[RX] IF=%d, Receive failure: %d.\n", 188 | priv->if_id, arg->status); 189 | goto drop; 190 | } 191 | } 192 | 193 | if (skb->len < sizeof(struct ieee80211_pspoll)) { 194 | dev_err(priv->hw_priv->pdev, "Malformed SDU rx'ed. " 195 | "Size is lesser than IEEE header.\n"); 196 | goto drop; 197 | } 198 | 199 | if (unlikely(ieee80211_is_pspoll(frame->frame_control))) 200 | if (xradio_handle_pspoll(priv, skb)) 201 | goto drop; 202 | 203 | hdr->mactime = 0; /* Not supported by WSM */ 204 | hdr->band = (arg->channelNumber > 14) ? 205 | NL80211_BAND_5GHZ : NL80211_BAND_2GHZ; 206 | hdr->freq = ieee80211_channel_to_frequency( 207 | arg->channelNumber, 208 | hdr->band); 209 | 210 | #ifdef AP_HT_COMPAT_FIX 211 | if (!priv->ht_compat_det && priv->htcap && 212 | ieee80211_is_data_qos(frame->frame_control)) { 213 | if(xradio_apcompat_detect(priv, arg->rxedRate)) 214 | goto drop; 215 | } 216 | #endif 217 | 218 | if (arg->rxedRate >= 14) { 219 | hdr->flag |= RX_ENC_HT; 220 | hdr->rate_idx = arg->rxedRate - 14; 221 | } else if (arg->rxedRate >= 4) { 222 | if (hdr->band == NL80211_BAND_5GHZ) 223 | hdr->rate_idx = arg->rxedRate - 6; 224 | else 225 | hdr->rate_idx = arg->rxedRate - 2; 226 | } else { 227 | hdr->rate_idx = arg->rxedRate; 228 | } 229 | 230 | hdr->signal = (s8)arg->rcpiRssi; 231 | hdr->antenna = 0; 232 | 233 | hdrlen = ieee80211_hdrlen(frame->frame_control); 234 | 235 | if (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { 236 | size_t iv_len = 0, icv_len = 0; 237 | 238 | hdr->flag |= RX_FLAG_DECRYPTED; 239 | 240 | /* Oops... There is no fast way to ask mac80211 about 241 | * IV/ICV lengths. Even defines are not exposed.*/ 242 | switch (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { 243 | case WSM_RX_STATUS_WEP: 244 | iv_len = 4 /* WEP_IV_LEN */; 245 | icv_len = 4 /* WEP_ICV_LEN */; 246 | break; 247 | case WSM_RX_STATUS_TKIP: 248 | iv_len = 8 /* TKIP_IV_LEN */; 249 | icv_len = 4 /* TKIP_ICV_LEN */ 250 | + 8 /*MICHAEL_MIC_LEN*/; 251 | break; 252 | case WSM_RX_STATUS_AES: 253 | iv_len = 8 /* CCMP_HDR_LEN */; 254 | icv_len = 8 /* CCMP_MIC_LEN */; 255 | break; 256 | case WSM_RX_STATUS_WAPI: 257 | iv_len = 18 /* WAPI_HDR_LEN */; 258 | icv_len = 16 /* WAPI_MIC_LEN */; 259 | hdr->flag |= RX_FLAG_IV_STRIPPED; 260 | break; 261 | default: 262 | WARN_ON("Unknown encryption type"); 263 | goto drop; 264 | } 265 | 266 | /* Firmware strips ICV in case of MIC failure. */ 267 | if (arg->status == WSM_STATUS_MICFAILURE) { 268 | icv_len = 0; 269 | hdr->flag |= RX_FLAG_IV_STRIPPED; 270 | } 271 | 272 | if (skb->len < hdrlen + iv_len + icv_len) { 273 | dev_err(priv->hw_priv->pdev, "Mailformed SDU rx'ed. " 274 | "Size is lesser than crypto headers.\n"); 275 | goto drop; 276 | } 277 | 278 | if (WSM_RX_STATUS_ENCRYPTION(arg->flags) == 279 | WSM_RX_STATUS_TKIP) { 280 | /* Remove TKIP MIC 8 bytes*/ 281 | memmove(skb->data + skb->len-icv_len, 282 | skb->data + skb->len-icv_len+8, 4); 283 | skb_trim(skb, skb->len - 8); 284 | hdr->flag |= RX_FLAG_MMIC_STRIPPED; 285 | } else if (unlikely(WSM_RX_STATUS_ENCRYPTION(arg->flags) == 286 | WSM_RX_STATUS_WAPI)) { 287 | /* Protocols not defined in mac80211 should be 288 | stripped/crypted in driver/firmware */ 289 | /* Remove IV, ICV and MIC */ 290 | skb_trim(skb, skb->len - icv_len); 291 | memmove(skb->data + iv_len, skb->data, hdrlen); 292 | skb_pull(skb, iv_len); 293 | } 294 | parse_iv_len = iv_len; 295 | } 296 | 297 | if (ieee80211_is_beacon(frame->frame_control) && 298 | !arg->status && 299 | !memcmp(ieee80211_get_SA(frame), priv->join_bssid,ETH_ALEN)) { 300 | const u8 *tim_ie; 301 | u8 *ies; 302 | size_t ies_len; 303 | priv->disable_beacon_filter = false; 304 | queue_work(hw_priv->workqueue, &priv->update_filtering_work); 305 | ies = ((struct ieee80211_mgmt *) 306 | (skb->data))->u.beacon.variable; 307 | ies_len = skb->len - (ies - (u8 *)(skb->data)); 308 | 309 | tim_ie = xradio_get_ie(ies, ies_len, WLAN_EID_TIM); 310 | if (tim_ie) { 311 | struct ieee80211_tim_ie *tim = 312 | (struct ieee80211_tim_ie *)&tim_ie[2]; 313 | 314 | if (priv->join_dtim_period != tim->dtim_period) { 315 | priv->join_dtim_period = tim->dtim_period; 316 | queue_work(hw_priv->workqueue, 317 | &priv->set_beacon_wakeup_period_work); 318 | } 319 | } 320 | if (unlikely(priv->disable_beacon_filter)) { 321 | priv->disable_beacon_filter = false; 322 | queue_work(hw_priv->workqueue, 323 | &priv->update_filtering_work); 324 | } 325 | } 326 | #ifdef AP_HT_CAP_UPDATE 327 | if (priv->mode == NL80211_IFTYPE_AP && 328 | ieee80211_is_beacon(frame->frame_control) && 329 | ((priv->ht_oper&HT_INFO_MASK) != 0x0011) && 330 | !arg->status){ 331 | u8 *ies; 332 | size_t ies_len; 333 | const u8 *ht_cap; 334 | ies = ((struct ieee80211_mgmt *)(skb->data))->u.beacon.variable; 335 | ies_len = skb->len - (ies - (u8 *)(skb->data)); 336 | ht_cap = xradio_get_ie(ies, ies_len, WLAN_EID_HT_CAPABILITY); 337 | if(!ht_cap) { 338 | priv->ht_oper |= 0x0011; 339 | queue_work(hw_priv->workqueue, &priv->ht_oper_update_work); 340 | } 341 | } 342 | #endif 343 | 344 | #ifdef AP_HT_COMPAT_FIX 345 | if (ieee80211_is_mgmt(frame->frame_control) && 346 | priv->if_id == 0 && !(priv->ht_compat_det & 0x10)) { 347 | xradio_remove_ht_ie(priv, skb); 348 | } 349 | #endif 350 | 351 | #ifdef ROAM_OFFLOAD 352 | if ((ieee80211_is_beacon(frame->frame_control)||ieee80211_is_probe_resp(frame->frame_control)) && 353 | !arg->status ) { 354 | if (hw_priv->auto_scanning && !atomic_read(&hw_priv->scan.in_progress)) 355 | hw_priv->frame_rcvd = 1; 356 | 357 | if (!memcmp(ieee80211_get_SA(frame), priv->join_bssid, ETH_ALEN)) { 358 | if (hw_priv->beacon) 359 | dev_kfree_skb(hw_priv->beacon); 360 | hw_priv->beacon = skb_copy(skb, GFP_ATOMIC); 361 | if (!hw_priv->beacon) 362 | txrx_printk(XRADIO_DBG_ERROR, "sched_scan: own beacon storing failed\n"); 363 | } 364 | } 365 | #endif /*ROAM_OFFLOAD*/ 366 | 367 | //don't delay scan before next connect, yangfh. 368 | if (ieee80211_is_deauth(frame->frame_control) || 369 | ieee80211_is_disassoc(frame->frame_control)) 370 | hw_priv->connet_time[priv->if_id] = 0; 371 | 372 | /* Stay awake for 1sec. after frame is received to give 373 | * userspace chance to react and acquire appropriate 374 | * wakelock. */ 375 | if (ieee80211_is_auth(frame->frame_control)) 376 | grace_period = 5 * HZ; 377 | else if (ieee80211_is_deauth(frame->frame_control)) 378 | grace_period = 5 * HZ; 379 | else 380 | grace_period = HZ; 381 | 382 | if (ieee80211_is_data(frame->frame_control)) 383 | xradio_rx_h_ba_stat(priv, hdrlen, skb->len); 384 | 385 | xradio_pm_stay_awake(&hw_priv->pm_state, grace_period); 386 | 387 | if(xradio_realloc_resv_skb(hw_priv, *skb_p)) { 388 | *skb_p = NULL; 389 | return; 390 | } 391 | /* Try to a packet for the case dev_alloc_skb failed in bh.*/ 392 | if (unlikely(early_data)) { 393 | spin_lock_bh(&priv->ps_state_lock); 394 | /* Double-check status with lock held */ 395 | if (entry->status == XRADIO_LINK_SOFT) { 396 | skb_queue_tail(&entry->rx_queue, skb); 397 | dev_warn(priv->hw_priv->pdev, "***skb_queue_tail\n"); 398 | } else 399 | ieee80211_rx_irqsafe(priv->hw, skb); 400 | spin_unlock_bh(&priv->ps_state_lock); 401 | } else { 402 | ieee80211_rx_irqsafe(priv->hw, skb); 403 | } 404 | *skb_p = NULL; 405 | 406 | return; 407 | 408 | drop: 409 | dev_warn(priv->hw_priv->pdev, "dropped received frame\n"); 410 | return; 411 | } 412 | -------------------------------------------------------------------------------- /rx.h: -------------------------------------------------------------------------------- 1 | #ifndef XRADIO_RX_H 2 | #define XRADIO_RX_H 3 | 4 | void xradio_rx_cb(struct xradio_vif *priv, 5 | struct wsm_rx *arg, 6 | struct sk_buff **skb_p); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /scan.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Scan interfaces for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | 13 | #ifndef SCAN_H_INCLUDED 14 | #define SCAN_H_INCLUDED 15 | 16 | #include 17 | #include "wsm.h" 18 | 19 | /* external */ struct sk_buff; 20 | /* external */ struct cfg80211_scan_request; 21 | /* external */ struct ieee80211_channel; 22 | /* external */ struct ieee80211_hw; 23 | /* external */ struct work_struct; 24 | 25 | #define SCAN_MAX_DELAY (3*HZ) //3s, add by yangfh for connect 26 | 27 | struct xradio_scan { 28 | struct semaphore lock; 29 | struct work_struct work; 30 | #ifdef ROAM_OFFLOAD 31 | struct work_struct swork; /* scheduled scan work */ 32 | struct cfg80211_sched_scan_request *sched_req; 33 | #endif /*ROAM_OFFLOAD*/ 34 | struct delayed_work timeout; 35 | struct cfg80211_scan_request *req; 36 | struct ieee80211_channel **begin; 37 | struct ieee80211_channel **curr; 38 | struct ieee80211_channel **end; 39 | struct wsm_ssid ssids[WSM_SCAN_MAX_NUM_OF_SSIDS]; 40 | int output_power; 41 | int n_ssids; 42 | //add by liwei, for h64 ping WS550 BUG 43 | struct semaphore status_lock; 44 | int status; 45 | atomic_t in_progress; 46 | /* Direct probe requests workaround */ 47 | struct delayed_work probe_work; 48 | int direct_probe; 49 | u8 if_id; 50 | }; 51 | 52 | int xradio_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 53 | struct ieee80211_scan_request *req); 54 | #ifdef ROAM_OFFLOAD 55 | int xradio_hw_sched_scan_start(struct ieee80211_hw *hw, 56 | struct ieee80211_vif *vif, 57 | struct cfg80211_sched_scan_request *req, 58 | struct ieee80211_sched_scan_ies *ies); 59 | void xradio_hw_sched_scan_stop(struct xradio_common *priv); 60 | void xradio_sched_scan_work(struct work_struct *work); 61 | #endif /*ROAM_OFFLOAD*/ 62 | void xradio_scan_work(struct work_struct *work); 63 | void xradio_scan_timeout(struct work_struct *work); 64 | void xradio_scan_complete_cb(struct xradio_common *priv, 65 | struct wsm_scan_complete *arg); 66 | 67 | /* ******************************************************************** */ 68 | /* Raw probe requests TX workaround */ 69 | void xradio_probe_work(struct work_struct *work); 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /sdio.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SDIO driver for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "xradio.h" 22 | #include "sdio.h" 23 | #include "main.h" 24 | 25 | /* sdio vendor id and device id*/ 26 | #define SDIO_VENDOR_ID_XRADIO 0x0020 27 | #define SDIO_DEVICE_ID_XRADIO 0x2281 28 | static const struct sdio_device_id xradio_sdio_ids[] = { 29 | { SDIO_DEVICE(SDIO_VENDOR_ID_XRADIO, SDIO_DEVICE_ID_XRADIO) }, 30 | //{ SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) }, 31 | { /* end: all zeroes */ }, 32 | }; 33 | 34 | /* sbus_ops implemetation */ 35 | int sdio_data_read(struct xradio_common* self, unsigned int addr, 36 | void *dst, int count) 37 | { 38 | int ret; 39 | 40 | switch (count) { 41 | case 4: 42 | *((u32 *)dst) = sdio_readl(self->sdio_func, addr, &ret); 43 | break; 44 | default: 45 | ret = sdio_memcpy_fromio(self->sdio_func, dst, addr, count); 46 | break; 47 | } 48 | 49 | return ret; 50 | } 51 | 52 | int sdio_data_write(struct xradio_common* self, unsigned int addr, 53 | const void *src, int count) 54 | { 55 | int ret; 56 | 57 | switch (count) { 58 | case 4: 59 | sdio_writel(self->sdio_func, *((u32 *)src), addr, &ret); 60 | break; 61 | default: 62 | ret = sdio_memcpy_toio(self->sdio_func, addr, (void *)src, count); 63 | break; 64 | } 65 | 66 | return ret; 67 | } 68 | 69 | void sdio_lock(struct xradio_common* self) 70 | { 71 | sdio_claim_host(self->sdio_func); 72 | } 73 | 74 | void sdio_unlock(struct xradio_common *self) 75 | { 76 | sdio_release_host(self->sdio_func); 77 | } 78 | 79 | size_t sdio_align_len(struct xradio_common *self, size_t size) 80 | { 81 | return sdio_align_size(self->sdio_func, size); 82 | } 83 | 84 | int sdio_set_blk_size(struct xradio_common *self, size_t size) 85 | { 86 | return sdio_set_block_size(self->sdio_func, size); 87 | } 88 | 89 | extern void xradio_irq_handler(struct xradio_common*); 90 | 91 | static irqreturn_t sdio_irq_handler(int irq, void *dev_id) 92 | { 93 | struct sdio_func *func = (struct sdio_func*) dev_id; 94 | struct xradio_common *self = sdio_get_drvdata(func); 95 | if (self != NULL) 96 | xradio_irq_handler(self); 97 | return IRQ_HANDLED; 98 | } 99 | 100 | static int sdio_enableint(struct sdio_func* func) 101 | { 102 | int ret = 0; 103 | u8 cccr; 104 | int func_num; 105 | 106 | sdio_claim_host(func); 107 | 108 | /* Hack to access Fuction-0 */ 109 | func_num = func->num; 110 | func->num = 0; 111 | cccr = sdio_readb(func, SDIO_CCCR_IENx, &ret); 112 | cccr |= BIT(0); /* Master interrupt enable ... */ 113 | cccr |= BIT(func_num); /* ... for our function */ 114 | sdio_writeb(func, cccr, SDIO_CCCR_IENx, &ret); 115 | 116 | /* Restore the WLAN function number */ 117 | func->num = func_num; 118 | 119 | sdio_release_host(func); 120 | 121 | return ret; 122 | } 123 | 124 | int sdio_pm(struct xradio_common *self, bool suspend) 125 | { 126 | int ret = 0; 127 | if (suspend) { 128 | /* Notify SDIO that XRADIO will remain powered during suspend */ 129 | ret = sdio_set_host_pm_flags(self->sdio_func, MMC_PM_KEEP_POWER); 130 | if (ret) 131 | dev_dbg(&self->sdio_func->dev, "Error setting SDIO pm flags: %i\n", ret); 132 | } 133 | 134 | return ret; 135 | } 136 | 137 | static const struct of_device_id xradio_sdio_of_match_table[] = { 138 | { .compatible = "xradio,xr819" }, 139 | { } 140 | }; 141 | 142 | static int xradio_probe_of(struct sdio_func *func) 143 | { 144 | struct device *dev = &func->dev; 145 | struct device_node *np = dev->of_node; 146 | const struct of_device_id *of_id; 147 | int irq; 148 | 149 | of_id = of_match_node(xradio_sdio_of_match_table, np); 150 | if (!of_id) 151 | return -ENODEV; 152 | 153 | //pdev_data->family = of_id->data; 154 | 155 | irq = irq_of_parse_and_map(np, 0); 156 | if (!irq) { 157 | dev_err(dev, "No irq in platform data\n"); 158 | return -EINVAL; 159 | } 160 | 161 | return devm_request_irq(dev, irq, sdio_irq_handler, 0, "xradio", func); 162 | } 163 | 164 | /* Probe Function to be called by SDIO stack when device is discovered */ 165 | static int sdio_probe(struct sdio_func *func, 166 | const struct sdio_device_id *id) 167 | { 168 | dev_dbg(&func->dev, "XRadio Device:sdio clk=%d\n", 169 | func->card->host->ios.clock); 170 | dev_dbg(&func->dev, "sdio func->class=%x\n", func->class); 171 | dev_dbg(&func->dev, "sdio_vendor: 0x%04x\n", func->vendor); 172 | dev_dbg(&func->dev, "sdio_device: 0x%04x\n", func->device); 173 | dev_dbg(&func->dev, "Function#: 0x%04x\n", func->num); 174 | 175 | #if 0 //for odly and sdly debug. 176 | { 177 | u32 sdio_param = 0; 178 | sdio_param = readl(__io_address(0x01c20088)); 179 | sdio_param &= ~(0xf<<8); 180 | sdio_param |= 3<<8; 181 | sdio_param &= ~(0xf<<20); 182 | sdio_param |= s_dly<<20; 183 | writel(sdio_param, __io_address(0x01c20088)); 184 | sbus_printk(XRADIO_DBG_ALWY, "%s: 0x01c20088=0x%08x\n", __func__, sdio_param); 185 | } 186 | #endif 187 | 188 | xradio_probe_of(func); 189 | 190 | func->card->quirks |= MMC_QUIRK_BROKEN_BYTE_MODE_512; 191 | sdio_claim_host(func); 192 | sdio_enable_func(func); 193 | sdio_release_host(func); 194 | 195 | sdio_enableint(func); 196 | 197 | xradio_core_init(func); 198 | 199 | return 0; 200 | } 201 | /* Disconnect Function to be called by SDIO stack when 202 | * device is disconnected */ 203 | static void sdio_remove(struct sdio_func *func) 204 | { 205 | struct mmc_card *card = func->card; 206 | xradio_core_deinit(func); 207 | sdio_claim_host(func); 208 | sdio_disable_func(func); 209 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)) 210 | mmc_hw_reset(card); 211 | #else 212 | mmc_hw_reset(card->host); 213 | #endif 214 | sdio_release_host(func); 215 | } 216 | 217 | static int sdio_suspend(struct device *dev) 218 | { 219 | int ret = 0; 220 | /* 221 | struct sdio_func *func = dev_to_sdio_func(dev); 222 | ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 223 | if (ret) 224 | sbus_printk(XRADIO_DBG_ERROR, "set MMC_PM_KEEP_POWER error\n"); 225 | */ 226 | return ret; 227 | } 228 | 229 | static int sdio_resume(struct device *dev) 230 | { 231 | return 0; 232 | } 233 | 234 | static const struct dev_pm_ops sdio_pm_ops = { 235 | .suspend = sdio_suspend, 236 | .resume = sdio_resume, 237 | }; 238 | 239 | static struct sdio_driver sdio_driver = { 240 | .name = "xradio_wlan", 241 | .id_table = xradio_sdio_ids, 242 | .probe = sdio_probe, 243 | .remove = sdio_remove, 244 | .drv = { 245 | .owner = THIS_MODULE, 246 | .pm = &sdio_pm_ops, 247 | } 248 | }; 249 | 250 | 251 | int xradio_sdio_register(){ 252 | return sdio_register_driver(&sdio_driver); 253 | } 254 | 255 | void xradio_sdio_unregister(){ 256 | sdio_unregister_driver(&sdio_driver); 257 | } 258 | 259 | MODULE_DEVICE_TABLE(sdio, xradio_sdio_ids); 260 | -------------------------------------------------------------------------------- /sdio.h: -------------------------------------------------------------------------------- 1 | #ifndef __XRADIO_SDIO_H 2 | #define __XRADIO_SDIO_H 3 | 4 | size_t sdio_align_len(struct xradio_common *self, size_t size); 5 | void sdio_lock(struct xradio_common *self); 6 | void sdio_unlock(struct xradio_common *self); 7 | int sdio_set_blk_size(struct xradio_common *self, size_t size); 8 | int sdio_data_read(struct xradio_common *self, unsigned int addr, void *dst, 9 | int count); 10 | int sdio_data_write(struct xradio_common *self, unsigned int addr, const void *src, 11 | int count); 12 | int sdio_pm(struct xradio_common *self, bool suspend); 13 | 14 | int xradio_sdio_register(void); 15 | void xradio_sdio_unregister(void); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /sta.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sta interfaces for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | #ifndef STA_H_INCLUDED 12 | #define STA_H_INCLUDED 13 | 14 | 15 | #ifdef XRADIO_USE_LONG_KEEP_ALIVE_PERIOD 16 | #define XRADIO_KEEP_ALIVE_PERIOD (10) 17 | #else 18 | /*For Samsung, it is defined as 4*/ 19 | #define XRADIO_KEEP_ALIVE_PERIOD (4) 20 | #endif 21 | 22 | #ifdef XRADIO_USE_LONG_DTIM_PERIOD 23 | #define XRADIO_BSS_LOSS_THOLD_DEF 30 24 | #define XRADIO_LINK_LOSS_THOLD_DEF 50 25 | #else 26 | #define XRADIO_BSS_LOSS_THOLD_DEF 20 27 | #define XRADIO_LINK_LOSS_THOLD_DEF 40 28 | #endif 29 | 30 | /* ******************************************************************** */ 31 | /* mac80211 API */ 32 | 33 | int xradio_start(struct ieee80211_hw *dev); 34 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 11, 0)) 35 | void xradio_stop(struct ieee80211_hw *dev, bool suspend); 36 | #else 37 | void xradio_stop(struct ieee80211_hw *dev); 38 | #endif 39 | int xradio_add_interface(struct ieee80211_hw *dev, struct ieee80211_vif *vif); 40 | void xradio_remove_interface(struct ieee80211_hw *dev, struct ieee80211_vif *vif); 41 | int xradio_change_interface(struct ieee80211_hw *dev, 42 | struct ieee80211_vif *vif, 43 | enum nl80211_iftype new_type, 44 | bool p2p); 45 | int xradio_config(struct ieee80211_hw *dev, u32 changed); 46 | int xradio_change_interface(struct ieee80211_hw *dev, 47 | struct ieee80211_vif *vif, 48 | enum nl80211_iftype new_type, 49 | bool p2p); 50 | void xradio_configure_filter(struct ieee80211_hw *dev, 51 | unsigned int changed_flags, 52 | unsigned int *total_flags, 53 | u64 multicast); 54 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) 55 | int xradio_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, 56 | unsigned int link_id, u16 queue, 57 | const struct ieee80211_tx_queue_params *params); 58 | #else 59 | int xradio_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, 60 | u16 queue, const struct ieee80211_tx_queue_params *params); 61 | #endif 62 | int xradio_get_stats(struct ieee80211_hw *dev, 63 | struct ieee80211_low_level_stats *stats); 64 | /* Not more a part of interface? 65 | int xradio_get_tx_stats(struct ieee80211_hw *dev, 66 | struct ieee80211_tx_queue_stats *stats); 67 | */ 68 | int xradio_set_rts_threshold(struct ieee80211_hw *hw, u32 value); 69 | 70 | void xradio_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop); 71 | 72 | 73 | int xradio_remain_on_channel(struct ieee80211_hw *hw, 74 | struct ieee80211_vif *vif, 75 | struct ieee80211_channel *chan, 76 | int duration, enum ieee80211_roc_type type); 77 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) 78 | int xradio_cancel_remain_on_channel(struct ieee80211_hw *hw, 79 | struct ieee80211_vif *vif); 80 | #else 81 | int xradio_cancel_remain_on_channel(struct ieee80211_hw *hw); 82 | #endif 83 | int xradio_set_arpreply(struct ieee80211_hw *hw, struct ieee80211_vif *vif); 84 | u64 xradio_prepare_multicast(struct ieee80211_hw *hw, 85 | struct netdev_hw_addr_list *mc_list); 86 | int xradio_set_pm(struct xradio_vif *priv, const struct wsm_set_pm *arg); 87 | void xradio_set_data_filter(struct ieee80211_hw *hw, 88 | struct ieee80211_vif *vif, 89 | void *data, 90 | int len); 91 | 92 | /* ******************************************************************** */ 93 | /* WSM callbacks */ 94 | 95 | /* void xradio_set_pm_complete_cb(struct xradio_common *hw_priv, 96 | struct wsm_set_pm_complete *arg); */ 97 | void xradio_channel_switch_cb(struct xradio_common *hw_priv); 98 | 99 | /* ******************************************************************** */ 100 | /* WSM events */ 101 | 102 | void xradio_free_event_queue(struct xradio_common *hw_priv); 103 | void xradio_event_handler(struct work_struct *work); 104 | void xradio_bss_loss_work(struct work_struct *work); 105 | void xradio_connection_loss_work(struct work_struct *work); 106 | void xradio_keep_alive_work(struct work_struct *work); 107 | void xradio_tx_failure_work(struct work_struct *work); 108 | 109 | /* ******************************************************************** */ 110 | /* Internal API */ 111 | 112 | int xradio_setup_mac(struct xradio_common *hw_priv); 113 | void xradio_join_work(struct work_struct *work); 114 | void xradio_join_timeout(struct work_struct *work); 115 | void xradio_unjoin_work(struct work_struct *work); 116 | void xradio_offchannel_work(struct work_struct *work); 117 | void xradio_wep_key_work(struct work_struct *work); 118 | void xradio_update_filtering(struct xradio_vif *priv); 119 | void xradio_update_filtering_work(struct work_struct *work); 120 | int __xradio_flush(struct xradio_common *hw_priv, bool drop, int if_id); 121 | void xradio_set_beacon_wakeup_period_work(struct work_struct *work); 122 | int xradio_enable_listening(struct xradio_vif *priv, struct ieee80211_channel *chan); 123 | int xradio_disable_listening(struct xradio_vif *priv); 124 | int xradio_set_uapsd_param(struct xradio_vif *priv, const struct wsm_edca_params *arg); 125 | void xradio_ba_work(struct work_struct *work); 126 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) 127 | void xradio_ba_timer(struct timer_list *t); 128 | #else 129 | void xradio_ba_timer(unsigned long arg); 130 | #endif 131 | const u8 *xradio_get_ie(u8 *start, size_t len, u8 ie); 132 | int xradio_vif_setup(struct xradio_vif *priv); 133 | int xradio_setup_mac_pvif(struct xradio_vif *priv); 134 | void xradio_iterate_vifs(void *data, u8 *mac, struct ieee80211_vif *vif); 135 | void xradio_rem_chan_timeout(struct work_struct *work); 136 | int xradio_set_macaddrfilter(struct xradio_common *hw_priv, struct xradio_vif *priv, u8 *data); 137 | #ifdef ROAM_OFFLOAD 138 | int xradio_testmode_event(struct wiphy *wiphy, const u32 msg_id, 139 | const void *data, int len, gfp_t gfp); 140 | #endif /*ROAM_OFFLOAD*/ 141 | #endif 142 | -------------------------------------------------------------------------------- /sun8i-h2-plus-orangepi-zero.dts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Icenowy Zheng 3 | * 4 | * Based on sun8i-h3-orangepi-one.dts, which is: 5 | * Copyright (C) 2016 Hans de Goede 6 | * 7 | * This file is dual-licensed: you can use it either under the terms 8 | * of the GPL or the X11 license, at your option. Note that this dual 9 | * licensing only applies to this file, and not this project as a 10 | * whole. 11 | * 12 | * a) This file is free software; you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License as 14 | * published by the Free Software Foundation; either version 2 of the 15 | * License, or (at your option) any later version. 16 | * 17 | * This file is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | * GNU General Public License for more details. 21 | * 22 | * Or, alternatively, 23 | * 24 | * b) Permission is hereby granted, free of charge, to any person 25 | * obtaining a copy of this software and associated documentation 26 | * files (the "Software"), to deal in the Software without 27 | * restriction, including without limitation the rights to use, 28 | * copy, modify, merge, publish, distribute, sublicense, and/or 29 | * sell copies of the Software, and to permit persons to whom the 30 | * Software is furnished to do so, subject to the following 31 | * conditions: 32 | * 33 | * The above copyright notice and this permission notice shall be 34 | * included in all copies or substantial portions of the Software. 35 | * 36 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 37 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 38 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 39 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 40 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 41 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 42 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 43 | * OTHER DEALINGS IN THE SOFTWARE. 44 | */ 45 | 46 | /dts-v1/; 47 | #include "sun8i-h3.dtsi" 48 | #include "sunxi-common-regulators.dtsi" 49 | 50 | #include 51 | #include 52 | 53 | / { 54 | model = "Xunlong Orange Pi Zero"; 55 | compatible = "xunlong,orangepi-zero", "allwinner,sun8i-h2-plus"; 56 | 57 | aliases { 58 | serial0 = &uart0; 59 | /* ethernet0 is the H3 emac, defined in sun8i-h3.dtsi */ 60 | ethernet1 = &xr819; 61 | }; 62 | 63 | chosen { 64 | stdout-path = "serial0:115200n8"; 65 | }; 66 | 67 | leds { 68 | compatible = "gpio-leds"; 69 | 70 | pwr_led { 71 | label = "orangepi:green:pwr"; 72 | gpios = <&r_pio 0 10 GPIO_ACTIVE_HIGH>; 73 | default-state = "on"; 74 | }; 75 | 76 | status_led { 77 | label = "orangepi:red:status"; 78 | gpios = <&pio 0 17 GPIO_ACTIVE_HIGH>; 79 | }; 80 | }; 81 | 82 | vdd_wifi: vdd_wifi { 83 | compatible = "regulator-fixed"; 84 | regulator-name = "wifi"; 85 | regulator-min-microvolt = <1800000>; 86 | regulator-max-microvolt = <1800000>; 87 | gpio = <&pio 0 20 GPIO_ACTIVE_HIGH>; 88 | startup-delay-us = <70000>; 89 | enable-active-high; 90 | }; 91 | 92 | pwrseq_wifi: pwrseq_wifi@0 { 93 | compatible = "mmc-pwrseq-simple"; 94 | pinctrl-names = "default"; 95 | pinctrl-0 = <&wifi_rst>; 96 | reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; 97 | post-power-on-delay-ms = <50>; 98 | }; 99 | }; 100 | 101 | &ehci0 { 102 | status = "okay"; 103 | }; 104 | 105 | &ehci1 { 106 | status = "okay"; 107 | }; 108 | 109 | &mmc0 { 110 | pinctrl-names = "default"; 111 | pinctrl-0 = <&mmc0_pins_a>; 112 | vmmc-supply = <®_vcc3v3>; 113 | bus-width = <4>; 114 | cd-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */ 115 | cd-inverted; 116 | status = "okay"; 117 | }; 118 | 119 | &mmc1 { 120 | pinctrl-names = "default"; 121 | pinctrl-0 = <&mmc1_pins_a>; 122 | vmmc-supply = <®_vcc3v3>; 123 | vqmmc-supply = <&vdd_wifi>; 124 | mmc-pwrseq = <&pwrseq_wifi>; 125 | bus-width = <4>; 126 | max-frequency = <16000000>; 127 | non-removable; 128 | status = "okay"; 129 | 130 | /* 131 | * Explicitly define the sdio device, so that we can add an ethernet 132 | * alias for it (which e.g. makes u-boot set a mac-address). 133 | */ 134 | xr819: sdio_wifi@1 { 135 | reg = <1>; 136 | compatible = "xradio,xr819"; 137 | pinctrl-names = "default"; 138 | pinctrl-0 = <&wifi_wake>; 139 | interrupt-parent = <&pio>; 140 | interrupts = <6 10 IRQ_TYPE_EDGE_RISING>; 141 | interrupt-names = "host-wake"; 142 | local-mac-address = [dc 44 6d c0 ff ee]; 143 | }; 144 | }; 145 | 146 | &pio { 147 | wifi_wake: wifi_wake { 148 | pins = "PG10"; 149 | function = "gpio_in"; 150 | }; 151 | }; 152 | 153 | &r_pio { 154 | wifi_rst: wifi_rst { 155 | pins = "PL7"; 156 | function = "gpio_out"; 157 | }; 158 | }; 159 | 160 | &mmc1_pins_a { 161 | bias-pull-up; 162 | }; 163 | 164 | &ohci0 { 165 | status = "okay"; 166 | }; 167 | 168 | &ohci1 { 169 | status = "okay"; 170 | }; 171 | 172 | &uart0 { 173 | pinctrl-names = "default"; 174 | pinctrl-0 = <&uart0_pins_a>; 175 | status = "okay"; 176 | }; 177 | 178 | &uart1 { 179 | pinctrl-names = "default"; 180 | pinctrl-0 = <&uart1_pins>; 181 | status = "disabled"; 182 | }; 183 | 184 | &uart2 { 185 | pinctrl-names = "default"; 186 | pinctrl-0 = <&uart2_pins>; 187 | status = "disabled"; 188 | }; 189 | 190 | &usb_otg { 191 | dr_mode = "peripheral"; 192 | status = "okay"; 193 | }; 194 | 195 | &usbphy { 196 | /* 197 | * USB Type-A port VBUS is always on. However, MicroUSB VBUS can only 198 | * power up the board; when it's used as OTG port, this VBUS is 199 | * always off even if the board is powered via GPIO pins. 200 | */ 201 | status = "okay"; 202 | usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */ 203 | }; 204 | -------------------------------------------------------------------------------- /tx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * txrx interfaces for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #ifndef XRADIO_TXRX_H 13 | #define XRADIO_TXRX_H 14 | 15 | #include 16 | 17 | /* extern */ struct ieee80211_hw; 18 | /* extern */ struct sk_buff; 19 | /* extern */ struct wsm_tx; 20 | /* extern */ struct wsm_rx; 21 | /* extern */ struct wsm_tx_confirm; 22 | /* extern */ struct xradio_txpriv; 23 | /* extern */ struct xradio_vif; 24 | 25 | struct tx_policy { 26 | union { 27 | __le32 tbl[3]; 28 | u8 raw[12]; 29 | }; 30 | u8 usage_count; /* --// -- */ 31 | u8 retry_count; /* --// -- */ 32 | u8 uploaded; 33 | }; 34 | 35 | struct tx_policy_cache_entry { 36 | struct tx_policy policy; 37 | struct list_head link; 38 | }; 39 | 40 | #define TX_POLICY_CACHE_SIZE (8) 41 | struct tx_policy_cache { 42 | struct tx_policy_cache_entry cache[TX_POLICY_CACHE_SIZE]; 43 | struct list_head used; 44 | struct list_head free; 45 | spinlock_t lock; 46 | }; 47 | 48 | /* ******************************************************************** */ 49 | /* TX policy cache */ 50 | /* Intention of TX policy cache is an overcomplicated WSM API. 51 | * Device does not accept per-PDU tx retry sequence. 52 | * It uses "tx retry policy id" instead, so driver code has to sync 53 | * linux tx retry sequences with a retry policy table in the device. 54 | */ 55 | void tx_policy_init(struct xradio_common *hw_priv); 56 | void tx_policy_upload_work(struct work_struct *work); 57 | 58 | /* ******************************************************************** */ 59 | /* TX implementation */ 60 | 61 | u32 xradio_rate_mask_to_wsm(struct xradio_common *hw_priv, 62 | u32 rates); 63 | void xradio_tx(struct ieee80211_hw *dev, struct ieee80211_tx_control *control, struct sk_buff *skb); 64 | void xradio_skb_dtor(struct xradio_common *hw_priv, 65 | struct sk_buff *skb, 66 | const struct xradio_txpriv *txpriv); 67 | 68 | /* ******************************************************************** */ 69 | /* WSM callbacks */ 70 | 71 | void xradio_tx_confirm_cb(struct xradio_common *hw_priv, 72 | struct wsm_tx_confirm *arg); 73 | 74 | /* ******************************************************************** */ 75 | /* Timeout */ 76 | 77 | void xradio_tx_timeout(struct work_struct *work); 78 | 79 | /* ******************************************************************** */ 80 | /* Workaround for WFD test case 6.1.10 */ 81 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 82 | void xradio_link_id_reset(struct work_struct *work); 83 | #endif 84 | 85 | #endif /* XRADIO_TXRX_H */ 86 | -------------------------------------------------------------------------------- /xradio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Common define of private data for XRadio drivers 3 | * 4 | * Copyright (c) 2013, XRadio 5 | * Author: XRadio 6 | * 7 | * This program is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License version 2 as 9 | * published by the Free Software Foundation. 10 | */ 11 | 12 | #ifndef XRADIO_H 13 | #define XRADIO_H 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | //Macroses for Driver parameters. 24 | #define XRWL_MAX_QUEUE_SZ (128) 25 | #define AC_QUEUE_NUM 4 26 | 27 | #define XRWL_MAX_VIFS (2) 28 | #define XRWL_GENERIC_IF_ID (2) 29 | #define XRWL_HOST_VIF0_11N_THROTTLE (58) //(XRWL_MAX_QUEUE_SZ/(XRWL_MAX_VIFS-1))*0.9 30 | #define XRWL_HOST_VIF1_11N_THROTTLE (58) //(XRWL_MAX_QUEUE_SZ/(XRWL_MAX_VIFS-1))*0.9 31 | #define XRWL_HOST_VIF0_11BG_THROTTLE (35) //XRWL_HOST_VIF0_11N_THROTTLE*0.6 = 35 32 | #define XRWL_HOST_VIF1_11BG_THROTTLE (35) //XRWL_HOST_VIF0_11N_THROTTLE*0.6 = 35 33 | #if 0 34 | #define XRWL_FW_VIF0_THROTTLE (15) 35 | #define XRWL_FW_VIF1_THROTTLE (15) 36 | #endif 37 | 38 | #define IEEE80211_FCTL_WEP 0x4000 39 | #define IEEE80211_QOS_DATAGRP 0x0080 40 | #define WSM_KEY_MAX_IDX 20 41 | 42 | #include "queue.h" 43 | #include "wsm.h" 44 | #include "scan.h" 45 | #include "tx.h" 46 | #include "ht.h" 47 | #include "pm.h" 48 | #include "fwio.h" 49 | 50 | /* #define ROC_DEBUG */ 51 | /* hidden ssid is only supported when separate probe resp IE 52 | configuration is supported */ 53 | #ifdef PROBE_RESP_EXTRA_IE 54 | #define HIDDEN_SSID 1 55 | #endif 56 | 57 | #define XRADIO_MAX_CTRL_FRAME_LEN (0x1000) 58 | 59 | #define MAX_STA_IN_AP_MODE (14) 60 | #define WLAN_LINK_ID_MAX (MAX_STA_IN_AP_MODE + 3) 61 | 62 | #define XRADIO_MAX_STA_IN_AP_MODE (5) 63 | #define XRADIO_MAX_REQUEUE_ATTEMPTS (5) 64 | #define XRADIO_LINK_ID_UNMAPPED (15) 65 | #define XRADIO_MAX_TID (8) 66 | 67 | #define XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID (0x3F) 68 | #define XRADIO_RX_BLOCK_ACK_ENABLED_FOR_ALL_TID (0x3F) 69 | #define XRADIO_RX_BLOCK_ACK_ENABLED_FOR_BE_TID \ 70 | (XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID & 0x01) 71 | #define XRADIO_TX_BLOCK_ACK_DISABLED_FOR_ALL_TID (0) 72 | #define XRADIO_RX_BLOCK_ACK_DISABLED_FOR_ALL_TID (0) 73 | 74 | #define XRADIO_BLOCK_ACK_CNT (30) 75 | #define XRADIO_BLOCK_ACK_THLD (800) 76 | #define XRADIO_BLOCK_ACK_HIST (3) 77 | #define XRADIO_BLOCK_ACK_INTERVAL (1 * HZ / XRADIO_BLOCK_ACK_HIST) 78 | #define XRWL_ALL_IFS (-1) 79 | 80 | #ifdef ROAM_OFFLOAD 81 | #define XRADIO_SCAN_TYPE_ACTIVE 0x1000 82 | #define XRADIO_SCAN_BAND_5G 0x2000 83 | #endif /*ROAM_OFFLOAD*/ 84 | 85 | #define IEEE80211_FCTL_WEP 0x4000 86 | #define IEEE80211_QOS_DATAGRP 0x0080 87 | 88 | #ifdef MCAST_FWDING 89 | #define WSM_MAX_BUF 30 90 | #endif 91 | 92 | #define MAX_RATES_STAGE 8 // 93 | #define MAX_RATES_RETRY 7 94 | 95 | #define XRADIO_WORKQUEUE "xradio_wq" 96 | #define WIFI_CONF_PATH "/data/xr_wifi.conf" 97 | 98 | /* extern */ struct task_struct; 99 | /* extern */ struct xradio_debug_priv; 100 | /* extern */ struct xradio_debug_common; 101 | /* extern */ struct firmware; 102 | 103 | /* Please keep order */ 104 | enum xradio_join_status { 105 | XRADIO_JOIN_STATUS_PASSIVE = 0, 106 | XRADIO_JOIN_STATUS_MONITOR, 107 | XRADIO_JOIN_STATUS_STA, 108 | XRADIO_JOIN_STATUS_AP, 109 | }; 110 | 111 | enum xradio_link_status { 112 | XRADIO_LINK_OFF, 113 | XRADIO_LINK_RESERVE, 114 | XRADIO_LINK_SOFT, 115 | XRADIO_LINK_HARD, 116 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 117 | XRADIO_LINK_RESET, 118 | XRADIO_LINK_RESET_REMAP, 119 | #endif 120 | }; 121 | 122 | enum xradio_bss_loss_status { 123 | XRADIO_BSS_LOSS_NONE, 124 | XRADIO_BSS_LOSS_CHECKING, 125 | XRADIO_BSS_LOSS_CONFIRMING, 126 | XRADIO_BSS_LOSS_CONFIRMED, 127 | }; 128 | 129 | struct xradio_link_entry { 130 | unsigned long timestamp; 131 | enum xradio_link_status status; 132 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 133 | enum xradio_link_status prev_status; 134 | #endif 135 | u8 mac[ETH_ALEN]; 136 | u8 buffered[XRADIO_MAX_TID]; 137 | struct sk_buff_head rx_queue; 138 | }; 139 | 140 | #if defined(ROAM_OFFLOAD) 141 | struct xradio_testframe { 142 | u8 len; 143 | u8 *data; 144 | }; 145 | #endif 146 | 147 | struct xradio_common { 148 | struct xradio_debug_common *debug; 149 | struct xradio_queue tx_queue[AC_QUEUE_NUM]; 150 | struct xradio_queue_stats tx_queue_stats; 151 | 152 | struct ieee80211_hw *hw; 153 | struct mac_address addresses[XRWL_MAX_VIFS]; 154 | 155 | /*Will be a pointer to a list of VIFs - Dynamically allocated */ 156 | struct ieee80211_vif *vif_list[XRWL_MAX_VIFS]; 157 | atomic_t num_vifs; 158 | spinlock_t vif_list_lock; 159 | u32 if_id_slot; 160 | struct device *pdev; 161 | struct workqueue_struct *workqueue; 162 | 163 | struct mutex conf_mutex; 164 | 165 | struct sdio_func *sdio_func; 166 | int driver_ready; 167 | 168 | /* HW/FW type (HIF_...) */ 169 | int hw_type; 170 | int hw_revision; 171 | int fw_revision; 172 | 173 | /* firmware/hardware info */ 174 | unsigned int tx_hdr_len; 175 | 176 | /* Radio data */ 177 | int output_power; 178 | int noise; 179 | 180 | /* calibration, output power limit and rssi<->dBm conversation data */ 181 | 182 | /* BBP/MAC state */ 183 | const struct firmware *sdd; 184 | struct ieee80211_rate *rates; 185 | struct ieee80211_rate *mcs_rates; 186 | u8 mac_addr[ETH_ALEN]; 187 | /*TODO:COMBO: To be made per VIFF after mac80211 support */ 188 | struct ieee80211_channel *channel; 189 | int channel_switch_in_progress; 190 | wait_queue_head_t channel_switch_done; 191 | u8 channel_changed; //add by yangfh 2015-5-15 16:57:38. 192 | u8 long_frame_max_tx_count; 193 | u8 short_frame_max_tx_count; 194 | /* TODO:COMBO: According to Hong aggregation will happen per VIFF. 195 | * Keeping in common structure for the time being. Will be moved to VIFF 196 | * after the mechanism is clear */ 197 | u8 ba_tid_mask; 198 | int ba_acc; /*TODO: Same as above */ 199 | int ba_cnt; /*TODO: Same as above */ 200 | int ba_cnt_rx; /*TODO: Same as above */ 201 | int ba_acc_rx; /*TODO: Same as above */ 202 | int ba_hist; /*TODO: Same as above */ 203 | struct timer_list ba_timer;/*TODO: Same as above */ 204 | spinlock_t ba_lock; /*TODO: Same as above */ 205 | bool ba_ena; /*TODO: Same as above */ 206 | struct work_struct ba_work; /*TODO: Same as above */ 207 | struct xradio_pm_state pm_state; 208 | bool is_BT_Present; 209 | bool is_go_thru_go_neg; 210 | u8 conf_listen_interval; 211 | 212 | /* BH */ 213 | atomic_t bh_tx; 214 | atomic_t bh_term; 215 | atomic_t bh_suspend; 216 | struct task_struct *bh_thread; 217 | int bh_error; 218 | wait_queue_head_t bh_wq; 219 | wait_queue_head_t bh_evt_wq; 220 | 221 | 222 | int buf_id_tx; /* byte */ 223 | int buf_id_rx; /* byte */ 224 | int wsm_rx_seq; /* byte */ 225 | int wsm_tx_seq; /* byte */ 226 | int hw_bufs_used; 227 | int hw_bufs_used_vif[XRWL_MAX_VIFS]; 228 | struct sk_buff *skb_cache; 229 | struct sk_buff *skb_reserved; 230 | int skb_resv_len; 231 | bool powersave_enabled; 232 | bool device_can_sleep; 233 | /* Keep xradio awake (WUP = 1) 1 second after each scan to avoid 234 | * FW issue with sleeping/waking up. */ 235 | atomic_t recent_scan; 236 | long connet_time[XRWL_MAX_VIFS]; 237 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 238 | atomic_t suspend_state; 239 | #endif 240 | 241 | /* WSM */ 242 | struct wsm_caps wsm_caps; 243 | struct mutex wsm_cmd_mux; 244 | struct wsm_buf wsm_cmd_buf; 245 | struct wsm_cmd wsm_cmd; 246 | wait_queue_head_t wsm_cmd_wq; 247 | wait_queue_head_t wsm_startup_done; 248 | struct semaphore tx_lock_sem; 249 | atomic_t tx_lock; 250 | u32 pending_frame_id; 251 | 252 | /* WSM debug */ 253 | u32 query_packetID; 254 | atomic_t query_cnt; 255 | struct work_struct query_work; /* for query packet */ 256 | 257 | /* Scan status */ 258 | struct xradio_scan scan; 259 | 260 | /* TX/RX */ 261 | unsigned long rx_timestamp; 262 | 263 | /* WSM events */ 264 | spinlock_t event_queue_lock; 265 | struct list_head event_queue; 266 | struct work_struct event_handler; 267 | 268 | /* TX rate policy cache */ 269 | struct tx_policy_cache tx_policy_cache; 270 | struct work_struct tx_policy_upload_work; 271 | atomic_t upload_count; 272 | 273 | /* cryptographic engine information */ 274 | 275 | /* bit field of glowing LEDs */ 276 | u16 softled_state; 277 | 278 | /* statistics */ 279 | struct ieee80211_low_level_stats stats; 280 | 281 | struct xradio_ht_oper ht_oper; 282 | int tx_burst_idx; 283 | 284 | struct ieee80211_iface_limit if_limits1[2]; 285 | struct ieee80211_iface_limit if_limits2[2]; 286 | struct ieee80211_iface_limit if_limits3[2]; 287 | struct ieee80211_iface_combination if_combs[3]; 288 | 289 | struct mutex wsm_oper_lock; 290 | struct delayed_work rem_chan_timeout; 291 | atomic_t remain_on_channel; 292 | int roc_if_id; 293 | u64 roc_cookie; 294 | wait_queue_head_t offchannel_wq; 295 | u16 offchannel_done; 296 | u16 prev_channel; 297 | int if_id_selected; 298 | u32 key_map; 299 | struct wsm_add_key keys[WSM_KEY_MAX_INDEX + 1]; 300 | #ifdef MCAST_FWDING 301 | struct wsm_buf wsm_release_buf[WSM_MAX_BUF]; 302 | u8 buf_released; 303 | #endif 304 | #ifdef ROAM_OFFLOAD 305 | u8 auto_scanning; 306 | u8 frame_rcvd; 307 | u8 num_scanchannels; 308 | u8 num_2g_channels; 309 | u8 num_5g_channels; 310 | struct wsm_scan_ch scan_channels[48]; 311 | struct sk_buff *beacon; 312 | struct sk_buff *beacon_bkp; 313 | struct xradio_testframe testframe; 314 | #endif /*ROAM_OFFLOAD*/ 315 | 316 | u8 connected_sta_cnt; 317 | u16 vif0_throttle; 318 | u16 vif1_throttle; 319 | }; 320 | 321 | /* Virtual Interface State. One copy per VIF */ 322 | struct xradio_vif { 323 | atomic_t enabled; 324 | spinlock_t vif_lock; 325 | int if_id; 326 | /*TODO: Split into Common and VIF parts */ 327 | struct xradio_debug_priv *debug; 328 | /* BBP/MAC state */ 329 | u8 bssid[ETH_ALEN]; 330 | struct wsm_edca_params edca; 331 | struct wsm_tx_queue_params tx_queue_params; 332 | struct wsm_association_mode association_mode; 333 | struct wsm_set_bss_params bss_params; 334 | struct wsm_set_pm powersave_mode; 335 | struct wsm_set_pm firmware_ps_mode; 336 | int power_set_true; 337 | int user_power_set_true; 338 | u8 user_pm_mode; 339 | int cqm_rssi_thold; 340 | unsigned cqm_rssi_hyst; 341 | unsigned cqm_tx_failure_thold; 342 | unsigned cqm_tx_failure_count; 343 | bool cqm_use_rssi; 344 | int cqm_link_loss_count; 345 | int cqm_beacon_loss_count; 346 | int mode; 347 | bool enable_beacon; 348 | int beacon_int; 349 | size_t ssid_length; 350 | u8 ssid[IEEE80211_MAX_SSID_LEN]; 351 | #ifdef HIDDEN_SSID 352 | bool hidden_ssid; 353 | #endif 354 | bool listening; 355 | struct wsm_rx_filter rx_filter; 356 | struct wsm_beacon_filter_table bf_table; 357 | struct wsm_beacon_filter_control bf_control; 358 | struct wsm_multicast_filter multicast_filter; 359 | bool has_multicast_subscription; 360 | struct wsm_broadcast_addr_filter broadcast_filter; 361 | bool disable_beacon_filter; 362 | struct wsm_arp_ipv4_filter filter4; 363 | struct work_struct update_filtering_work; 364 | struct work_struct set_beacon_wakeup_period_work; 365 | struct xradio_pm_state_vif pm_state_vif; 366 | /*TODO: Add support in mac80211 for psmode info per VIF */ 367 | struct wsm_p2p_ps_modeinfo p2p_ps_modeinfo; 368 | struct wsm_uapsd_info uapsd_info; 369 | bool setbssparams_done; 370 | u32 listen_interval; 371 | u32 erp_info; 372 | bool powersave_enabled; 373 | 374 | /* WSM Join */ 375 | enum xradio_join_status join_status; 376 | u8 join_bssid[ETH_ALEN]; 377 | struct work_struct join_work; 378 | struct delayed_work join_timeout; 379 | struct work_struct unjoin_work; 380 | struct work_struct offchannel_work; 381 | int join_dtim_period; 382 | atomic_t delayed_unjoin; 383 | 384 | /* Security */ 385 | s8 wep_default_key_id; 386 | struct work_struct wep_key_work; 387 | unsigned long rx_timestamp; 388 | u32 cipherType; 389 | 390 | 391 | /* AP powersave */ 392 | u32 link_id_map; 393 | u32 max_sta_ap_mode; 394 | u32 link_id_after_dtim; 395 | u32 link_id_uapsd; 396 | u32 link_id_max; 397 | u32 wsm_key_max_idx; 398 | struct xradio_link_entry link_id_db[MAX_STA_IN_AP_MODE]; 399 | struct work_struct link_id_work; 400 | struct delayed_work link_id_gc_work; 401 | u32 sta_asleep_mask; 402 | u32 pspoll_mask; 403 | bool aid0_bit_set; 404 | spinlock_t ps_state_lock; 405 | bool buffered_multicasts; 406 | bool tx_multicast; 407 | u8 last_tim[8]; //for softap dtim, add by yangfh 408 | struct work_struct set_tim_work; 409 | struct delayed_work set_cts_work; 410 | struct work_struct multicast_start_work; 411 | struct work_struct multicast_stop_work; 412 | struct timer_list mcast_timeout; 413 | 414 | /* CQM Implementation */ 415 | struct delayed_work bss_loss_work; 416 | struct delayed_work connection_loss_work; 417 | struct work_struct tx_failure_work; 418 | int delayed_link_loss; 419 | spinlock_t bss_loss_lock; 420 | int bss_loss_status; 421 | int bss_loss_confirm_id; 422 | 423 | struct ieee80211_vif *vif; 424 | struct xradio_common *hw_priv; 425 | struct ieee80211_hw *hw; 426 | 427 | /* ROC implementation */ 428 | struct delayed_work pending_offchanneltx_work; 429 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 430 | /* Workaround for WFD testcase 6.1.10*/ 431 | struct work_struct linkid_reset_work; 432 | u8 action_frame_sa[ETH_ALEN]; 433 | u8 action_linkid; 434 | #endif 435 | bool htcap; 436 | #ifdef AP_HT_CAP_UPDATE 437 | u16 ht_oper; 438 | struct work_struct ht_oper_update_work; 439 | #endif 440 | 441 | #ifdef AP_HT_COMPAT_FIX 442 | u16 ht_compat_cnt; 443 | u16 ht_compat_det; 444 | #endif 445 | }; 446 | struct xradio_sta_priv { 447 | int link_id; 448 | struct xradio_vif *priv; 449 | }; 450 | enum xradio_data_filterid { 451 | IPV4ADDR_FILTER_ID = 0, 452 | }; 453 | 454 | /* Datastructure for LLC-SNAP HDR */ 455 | #define P80211_OUI_LEN 3 456 | struct ieee80211_snap_hdr { 457 | u8 dsap; /* always 0xAA */ 458 | u8 ssap; /* always 0xAA */ 459 | u8 ctrl; /* always 0x03 */ 460 | u8 oui[P80211_OUI_LEN]; /* organizational universal id */ 461 | } __packed; 462 | 463 | 464 | #ifdef TES_P2P_0002_ROC_RESTART 465 | extern s32 TES_P2P_0002_roc_dur; 466 | extern s32 TES_P2P_0002_roc_sec; 467 | extern s32 TES_P2P_0002_roc_usec; 468 | extern u32 TES_P2P_0002_packet_id; 469 | extern u32 TES_P2P_0002_state; 470 | 471 | #define TES_P2P_0002_STATE_IDLE 0x00 472 | #define TES_P2P_0002_STATE_SEND_RESP 0x01 473 | #define TES_P2P_0002_STATE_GET_PKTID 0x02 474 | #endif 475 | 476 | /* debug.h must be here because refer to struct xradio_vif and 477 | struct xradio_common.*/ 478 | #include "debug.h" 479 | 480 | /******************************************************* 481 | interfaces for operations of vif. 482 | ********************************************************/ 483 | static inline 484 | struct xradio_common *xrwl_vifpriv_to_hwpriv(struct xradio_vif *priv) 485 | { 486 | return priv->hw_priv; 487 | } 488 | static inline 489 | struct xradio_vif *xrwl_get_vif_from_ieee80211(struct ieee80211_vif *vif) 490 | { 491 | return (struct xradio_vif *)vif->drv_priv; 492 | } 493 | 494 | static inline 495 | struct xradio_vif *xrwl_hwpriv_to_vifpriv(struct xradio_common *hw_priv, 496 | int if_id) 497 | { 498 | struct xradio_vif *vif; 499 | 500 | if (WARN_ON((-1 == if_id) || (if_id > XRWL_MAX_VIFS))) 501 | return NULL; 502 | /* TODO:COMBO: During scanning frames can be received 503 | * on interface ID 3 */ 504 | spin_lock(&hw_priv->vif_list_lock); 505 | if (!hw_priv->vif_list[if_id]) { 506 | spin_unlock(&hw_priv->vif_list_lock); 507 | return NULL; 508 | } 509 | 510 | vif = xrwl_get_vif_from_ieee80211(hw_priv->vif_list[if_id]); 511 | WARN_ON(!vif); 512 | if (vif) 513 | spin_lock(&vif->vif_lock); 514 | spin_unlock(&hw_priv->vif_list_lock); 515 | return vif; 516 | } 517 | 518 | static inline 519 | struct xradio_vif *__xrwl_hwpriv_to_vifpriv(struct xradio_common *hw_priv, 520 | int if_id) 521 | { 522 | WARN_ON((-1 == if_id) || (if_id > XRWL_MAX_VIFS)); 523 | /* TODO:COMBO: During scanning frames can be received 524 | * on interface ID 3 */ 525 | if (!hw_priv->vif_list[if_id]) { 526 | return NULL; 527 | } 528 | 529 | return xrwl_get_vif_from_ieee80211(hw_priv->vif_list[if_id]); 530 | } 531 | 532 | static inline 533 | struct xradio_vif *xrwl_get_activevif(struct xradio_common *hw_priv) 534 | { 535 | return xrwl_hwpriv_to_vifpriv(hw_priv, ffs(hw_priv->if_id_slot)-1); 536 | } 537 | 538 | static inline bool is_hardware_xradio(struct xradio_common *hw_priv) 539 | { 540 | return (hw_priv->hw_revision == XR819_HW_REV0); 541 | } 542 | 543 | static inline int xrwl_get_nr_hw_ifaces(struct xradio_common *hw_priv) 544 | { 545 | switch(hw_priv->hw_revision) { 546 | case XR819_HW_REV0: 547 | default: 548 | return 1; 549 | } 550 | } 551 | 552 | #define xradio_for_each_vif(_hw_priv, _priv, _i) \ 553 | for( \ 554 | _i = 0; \ 555 | (_i < XRWL_MAX_VIFS) \ 556 | && ((_priv = _hw_priv->vif_list[_i] ? \ 557 | xrwl_get_vif_from_ieee80211(_hw_priv->vif_list[_i]) : NULL),1); \ 558 | _i++ \ 559 | ) 560 | 561 | /******************************************************* 562 | interfaces for operations of queue. 563 | ********************************************************/ 564 | static inline void xradio_tx_queues_lock(struct xradio_common *hw_priv) 565 | { 566 | int i; 567 | for (i = 0; i < 4; ++i) 568 | xradio_queue_lock(&hw_priv->tx_queue[i]); 569 | } 570 | 571 | static inline void xradio_tx_queues_unlock(struct xradio_common *hw_priv) 572 | { 573 | int i; 574 | for (i = 0; i < 4; ++i) 575 | xradio_queue_unlock(&hw_priv->tx_queue[i]); 576 | } 577 | 578 | #endif /* XRADIO_H */ 579 | --------------------------------------------------------------------------------