├── .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 ├── 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.c 8 | -------------------------------------------------------------------------------- /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 | CONFIG_XRADIO_USE_EXTENSIONS := y 3 | 4 | xradio_wlan-y := \ 5 | fwio.o \ 6 | tx.o \ 7 | rx.o \ 8 | main.o \ 9 | queue.o \ 10 | hwio.o \ 11 | bh.o \ 12 | wsm.o \ 13 | sta.o \ 14 | ap.o \ 15 | keys.o \ 16 | scan.o \ 17 | module.o \ 18 | sdio.o \ 19 | pm.o \ 20 | ht.o \ 21 | p2p.o 22 | 23 | ccflags-y += -DMCAST_FWDING 24 | ccflags-y += -DXRADIO_SUSPEND_RESUME_FILTER_ENABLE 25 | ccflags-y += -DAP_AGGREGATE_FW_FIX 26 | ccflags-y += -DAP_HT_CAP_UPDATE 27 | ccflags-y += -DAP_HT_COMPAT_FIX 28 | ccflags-y += -DCONFIG_XRADIO_DUMP_ON_ERROR 29 | 30 | ccflags-y += -DCONFIG_XRADIO_SUSPEND_POWER_OFF 31 | 32 | # Extra IE for probe response from upper layer is needed in P2P GO 33 | # For offloading probe response to FW, the extra IE must be included 34 | # in the probe response template 35 | ccflags-y += -DPROBE_RESP_EXTRA_IE 36 | 37 | # Modified by wzw 38 | ccflags-y += -DTES_P2P_0002_ROC_RESTART 39 | ccflags-y += -DTES_P2P_000B_EXTEND_INACTIVITY_CNT 40 | ccflags-y += -DTES_P2P_000B_DISABLE_EAPOL_FILTER 41 | ccflags-y += -DXRADIO_USE_LONG_DTIM_PERIOD 42 | ccflags-y += -DXRADIO_USE_LONG_KEEP_ALIVE_PERIOD 43 | 44 | #ccflags-y += -DDEBUG 45 | 46 | 47 | #~dgp 48 | #ccflags-y += -DXRADIO_DISABLE_HW_CRYPTO 49 | 50 | ldflags-y += --strip-debug 51 | 52 | obj-$(CONFIG_XRADIO) += xradio_wlan.o 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xradio 2 | Port Allwinner xradio driver to mainline Linux. 3 | 4 | #Building 5 | 6 | Something like this: 7 | 8 | ``` 9 | make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C M=$PWD modules 10 | make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -C M=$PWD INSTALL_MOD_PATH= modules_install 11 | ``` 12 | 13 | #How to use this 14 | 15 | You need to specify one or two regulators for the xr819's 1.8v and 3.3v supplies in your device tree. 16 | The orange pi zero only has control over the 1.8v regulator and a 3.3v fixed regulator is provided elsewhere 17 | so we one need one there: 18 | 19 | ``` 20 | vdd_wifi: vdd_wifi { 21 | compatible = "regulator-fixed"; 22 | regulator-name = "wifi"; 23 | regulator-min-microvolt = <1800000>; 24 | regulator-max-microvolt = <1800000>; 25 | gpio = <&pio 0 20 GPIO_ACTIVE_HIGH>; 26 | startup-delay-us = <70000>; 27 | enable-active-high; 28 | }; 29 | ``` 30 | 31 | Next you need a pwrseq node that controls the reset pin of the xr819. 32 | 33 | ``` 34 | pwrseq_wifi: pwrseq_wifi@0 { 35 | compatible = "mmc-pwrseq-simple"; 36 | pinctrl-names = "default"; 37 | pinctrl-0 = <&wifi_rst>; 38 | reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>; 39 | post-power-on-delay-ms = <50>; 40 | }; 41 | ``` 42 | 43 | Next you need to add some things to the mmc node that the xr819 is connected to. 44 | 45 | ``` 46 | &mmc1 { 47 | pinctrl-names = "default"; 48 | pinctrl-0 = <&mmc1_pins_a>; 49 | vqmmc-supply = <&vdd_wifi>; 50 | vmmc-supply = <®_vcc3v3>; 51 | bus-width = <4>; 52 | mmc-pwrseq = <&pwrseq_wifi>; 53 | non-removable; 54 | status = "okay"; 55 | 56 | xr819wifi: xr819wifi@1 { 57 | reg = <1>; 58 | compatible = "xradio,xr819"; 59 | pinctrl-names = "default"; 60 | pinctrl-0 = <&wifi_wake>; 61 | interrupt-parent = <&pio>; 62 | interrupts = <6 10 IRQ_TYPE_EDGE_RISING>; 63 | interrupt-names = "host-wake"; 64 | local-mac-address = [dc 44 6d c0 ff ee]; 65 | }; 66 | }; 67 | ``` 68 | 69 | 70 | vqmmc-supply and vmmc-supply should reference the regulators that control the xr819 supplies. 71 | The device tree for the SoC the orange pi zero is based on supplies a fixed 3.3v regulator 72 | so we use that for vmmc-supply and provide the 1.8v controllable regulator as vqmmc-supply. 73 | vqmcc-supply is apparently for the IO supply which is 3.3v for the orange pi zero but 74 | swapping vqmmc and vmmc around results in the kernel complaining that the card's (the xr819) 75 | required IO voltage isn't supported. The setup above might not be technically correct but 76 | does work. 77 | The xr819 node should be self explanatory. The compatible string is used by the driver 78 | to find the node. The wake interrupt from the xr819 needs to be provided. 79 | 80 | Finally you can specify a MAC address to use. If you don't set one you will get a random one 81 | on each boot. Instead of creating a new device tree file for every system you should 82 | probably overwrite the address given after loading the device tree in u-boot. For the sunxi 83 | uboot all you have to actually do is add something like "ethernet1 = &xr819wifi;" to the 84 | aliases section of the device tree you give to the kernel and u-boot will update the mac 85 | address to something based on the unique chip id for you. 86 | # What works, what doesn't 87 | 88 | Working: 89 | 90 | Standard client station mode seems to work fine. 91 | Master (AP) mode works with WPA/WPA2 enabled etc. 92 | Dual role station and master mode. 93 | 94 | #Issues 95 | 96 | The firmware running on the xr819 is very crash happy and the driver is a bit 97 | stupid. For example the driver can get confused about how many packets of data 98 | the xr819 has for it to read and can try to read too many. The firmware on the 99 | xr819 responds by triggering an assert and shutting down. The driver gets 100 | a packet that tells it that the firmware is dead and shuts down the thread used 101 | to push and pull data but the rest of the driver and the os has no idea and 102 | if the os tries to interact with the driver everything starts to lock up. 103 | 104 | Pings from the device to the network are faster than from the network to the device. 105 | This seems to be because of latency between the interrupt and servicing RX reports 106 | from the device. 107 | 108 | #Fun stuff 109 | 110 | The driver is based on the driver for the ST CW1100/CW1200 chips. 111 | The XR819 is probably a clone, licensed version or actually a CW1100 family chip 112 | that has been packaged by xradio/allwinner as the CW1100 is available as a raw 113 | wafer. 114 | 115 | The silicon version from the XR819 and procedure for loading firmware 116 | matches up with the CW1x60 chips which were apparently never released so 117 | maybe Allwinner bought the design after the ST/Ericsson split? 118 | 119 | If anyone wants to mainline support for the XR819 they should probably do it by 120 | adding support for the XR819 to the existing CW1200 driver so they don't have to 121 | get thousands and thousands of lines of code signed off. 122 | -------------------------------------------------------------------------------- /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 | void xradio_bss_info_changed(struct ieee80211_hw *dev, 33 | struct ieee80211_vif *vif, 34 | struct ieee80211_bss_conf *info, 35 | u32 changed); 36 | int xradio_ampdu_action(struct ieee80211_hw *hw, 37 | struct ieee80211_vif *vif, 38 | struct ieee80211_ampdu_params *params); 39 | /* enum ieee80211_ampdu_mlme_action action, 40 | struct ieee80211_sta *sta, u16 tid, u16 *ssn, 41 | u8 buf_size);*/ 42 | 43 | void xradio_suspend_resume(struct xradio_vif *priv, 44 | struct wsm_suspend_resume *arg); 45 | void xradio_set_tim_work(struct work_struct *work); 46 | void xradio_set_cts_work(struct work_struct *work); 47 | void xradio_multicast_start_work(struct work_struct *work); 48 | void xradio_multicast_stop_work(struct work_struct *work); 49 | void xradio_mcast_timeout(unsigned long arg); 50 | int xradio_find_link_id(struct xradio_vif *priv, const u8 *mac); 51 | int xradio_alloc_link_id(struct xradio_vif *priv, const u8 *mac); 52 | void xradio_link_id_work(struct work_struct *work); 53 | void xradio_link_id_gc_work(struct work_struct *work); 54 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 55 | /*in linux3.4 mac,it does't have the noa pass*/ 56 | //void xradio_notify_noa(struct xradio_vif *priv, int delay); 57 | #endif 58 | int xrwl_unmap_link(struct xradio_vif *priv, int link_id); 59 | #ifdef AP_HT_CAP_UPDATE 60 | void xradio_ht_oper_update_work(struct work_struct *work); 61 | #endif 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /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(%d)!\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(%d)!\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 | // print_hex_dump_bytes("<-- ", DUMP_PREFIX_NONE, 444 | // data, min(len, (size_t) 64)); 445 | #endif 446 | } 447 | 448 | #define READLEN(ctrl) ((ctrl & HIF_CTRL_NEXT_LEN_MASK) << 1) //read_len=ctrl_reg*2. 449 | 450 | static int xradio_bh_rx_availlen(struct xradio_common *hw_priv){ 451 | u16 ctrl_reg = 0; 452 | if (xradio_bh_read_ctrl_reg(hw_priv, &ctrl_reg)) { 453 | return -EIO; 454 | } 455 | return READLEN(ctrl_reg); 456 | } 457 | 458 | static int xradio_bh_rx(struct xradio_common *hw_priv, u16* nextlen) { 459 | size_t read_len = 0; 460 | struct sk_buff *skb_rx = NULL; 461 | struct wsm_hdr *wsm; 462 | size_t wsm_len; 463 | int wsm_id; 464 | u8 wsm_seq; 465 | size_t alloc_len; 466 | u8 *data; 467 | int ret; 468 | 469 | read_len = *nextlen > 0 ? *nextlen : xradio_bh_rx_availlen(hw_priv); 470 | if(read_len <= 0) 471 | return read_len; 472 | 473 | if (read_len < sizeof(struct wsm_hdr) || (read_len > EFFECTIVE_BUF_SIZE)) { 474 | dev_err(hw_priv->pdev, "Invalid read len: %d", read_len); 475 | return -1; 476 | } 477 | 478 | /* Add SIZE of PIGGYBACK reg (CONTROL Reg) 479 | * to the NEXT Message length + 2 Bytes for SKB */ 480 | read_len = read_len + 2; 481 | 482 | alloc_len = sdio_align_len(hw_priv, read_len); 483 | /* Check if not exceeding XRADIO capabilities */ 484 | if (WARN_ON_ONCE(alloc_len > EFFECTIVE_BUF_SIZE)) { 485 | dev_err(hw_priv->pdev, "Read aligned len: %d\n", alloc_len); 486 | } 487 | 488 | /* Get skb buffer. */ 489 | skb_rx = xradio_get_skb(hw_priv, alloc_len); 490 | if (!skb_rx) { 491 | dev_err(hw_priv->pdev, "xradio_get_skb failed.\n"); 492 | return -ENOMEM; 493 | } 494 | skb_trim(skb_rx, 0); 495 | skb_put(skb_rx, read_len); 496 | data = skb_rx->data; 497 | if (!data) { 498 | dev_err(hw_priv->pdev, "skb data is NULL.\n"); 499 | ret = -ENOMEM; 500 | goto out; 501 | } 502 | 503 | /* Read data from device. */ 504 | if (xradio_data_read(hw_priv, data, alloc_len)) { 505 | ret = -EIO; 506 | goto out; 507 | } 508 | 509 | /* the ctrl register is appened to the end of the wsm frame 510 | * so we can use this to avoid reading the control register 511 | * again for the next read .. but if this is invalid we'll 512 | * do an invalid read and the firmware will crash so this 513 | * probably needs some sort of validation */ 514 | *nextlen = READLEN(__le16_to_cpu(((__le16 *) data)[(alloc_len >> 1) - 1])); 515 | 516 | /* check wsm length. */ 517 | wsm = (struct wsm_hdr *) data; 518 | wsm_len = __le32_to_cpu(wsm->len); 519 | 520 | if (WARN_ON(wsm_len > read_len)) { 521 | dev_err(hw_priv->pdev, "wsm is bigger than data read, read %d but frame is %d\n", 522 | read_len, wsm_len); 523 | ret = -1; 524 | goto out; 525 | } 526 | 527 | /* dump rx data. */ 528 | xradio_bh_rx_dump(hw_priv->pdev, data, wsm_len); 529 | 530 | /* extract wsm id and seq. */ 531 | wsm_id = __le32_to_cpu(wsm->id) & 0xFFF; 532 | wsm_seq = (__le32_to_cpu(wsm->id) >> 13) & 7; 533 | skb_trim(skb_rx, wsm_len); 534 | 535 | /* process exceptions. */ 536 | if (wsm_id == 0) { 537 | printk("wtf?\n"); 538 | ret = 0; 539 | goto out; 540 | } else if (unlikely(wsm_id == 0x0800)) { 541 | dev_err(hw_priv->pdev, "firmware exception!\n"); 542 | wsm_handle_exception(hw_priv, &data[sizeof(*wsm)], 543 | wsm_len - sizeof(*wsm)); 544 | ret = -1; 545 | goto out; 546 | } 547 | 548 | hw_priv->wsm_rx_seq = (wsm_seq + 1) & 7; 549 | 550 | /* Process tx frames confirm. */ 551 | if (wsm_id & 0x0400) { 552 | if (wsm_release_tx_buffer(hw_priv, 1) < 0) { 553 | dev_err(hw_priv->pdev, "tx buffer < 0.\n"); 554 | ret = -1; 555 | goto out; 556 | } 557 | } 558 | 559 | /* WSM processing frames. */ 560 | if (wsm_handle_rx(hw_priv, wsm_id, wsm, &skb_rx)) { 561 | dev_err(hw_priv->pdev, "wsm_handle_rx failed.\n"); 562 | ret = -1; 563 | goto out; 564 | } 565 | 566 | ret = 1; 567 | 568 | out: 569 | /* Reclaim the SKB buffer */ 570 | if (skb_rx) { 571 | if (xradio_put_resv_skb(hw_priv, skb_rx)) 572 | xradio_put_skb(hw_priv, skb_rx); 573 | } 574 | 575 | return ret; 576 | } 577 | 578 | static void xradio_bh_tx_dump(struct device *dev, u8 *data, size_t len){ 579 | #ifdef DEBUG 580 | static const char *msgnames[0xffff] = { 581 | [0x0004] = "tx", 582 | [0x0006] = "MIB", 583 | [0x0007] = "start scan", 584 | [0x0009] = "configure", 585 | [0x000A] = "reset", 586 | [0x000B] = "join", 587 | [0x000C] = "add key", 588 | [0x000D] = "remove key", 589 | [0x0010] = "set pm", 590 | [0x0011] = "set bss params", 591 | [0x0012] = "set tx queue params", 592 | [0x0013] = "set edca", 593 | [0x0017] = "start", 594 | [0x001b] = "update ie", 595 | [0x001c] = "map link", 596 | }; 597 | static const char *mibnames[0xffff] = { 598 | [0x0003] = "DOT11_SLOT_TIME", 599 | [0x1002] = "TEMPLATE_FRAME", 600 | [0x1003] = "RX_FILTER", 601 | [0x1004] = "BEACON_FILTER_TABLE", 602 | [0x1005] = "BEACON_FILTER_ENABLE", 603 | [0x1006] = "OPERATIONAL POWER MODE", 604 | [0x1007] = "BEACON_WAKEUP_PERIOD", 605 | [0x1009] = "RCPI_RSSI_THRESHOLD", 606 | [0x1010] = "SET_ASSOCIATION_MODE", 607 | [0x100e] = "BLOCK_ACK_POLICY", 608 | [0x100f] = "OVERRIDE_INTERNAL_TX_RATE", 609 | [0x1013] = "SET_UAPSD_INFORMATION", 610 | [0x1016] = "SET_TX_RATE_RETRY_POLICY", 611 | [0x1020] = "PROTECTED_MGMT_POLICY", 612 | [0x1021] = "SET_HT_PROTECTION", 613 | [0x1024] = "USE_MULTI_TX_CONF", 614 | [0x1025] = "KEEP_ALIVE_PERIOD", 615 | [0x1026] = "DISABLE_BSSID_FILTER", 616 | [0x1035] = "SET_INACTIVITY", 617 | }; 618 | 619 | u16 msgid, ifid, mib; 620 | u16 *p = (u16 *)data; 621 | msgid = (*(p + 1)) & 0x3F; 622 | ifid = (*(p + 1)) >> 6; 623 | ifid &= 0xF; 624 | mib = *(p + 2); 625 | 626 | WARN_ON(msgnames[msgid] == NULL); 627 | 628 | if (msgid == 0x0006) { 629 | dev_dbg(dev, "vif %d: sdio tx, msgid %s(0x%.4X) len %d MIB %s(0x%.4X)\n", 630 | ifid, msgnames[msgid], msgid,*p, mibnames[mib], mib); 631 | } else { 632 | dev_dbg(dev, "vif %d: sdio tx, msgid %s(0x%.4X) len %d\n", ifid, msgnames[msgid], msgid, *p); 633 | } 634 | 635 | // print_hex_dump_bytes("--> ", DUMP_PREFIX_NONE, data, 636 | // min(len, (size_t) 64)); 637 | #endif 638 | } 639 | 640 | static int xradio_bh_tx(struct xradio_common *hw_priv){ 641 | int txavailable; 642 | int txburst; 643 | int vif_selected; 644 | struct wsm_hdr *wsm; 645 | size_t tx_len; 646 | int ret; 647 | u8 *data; 648 | 649 | BUG_ON(hw_priv->hw_bufs_used > hw_priv->wsm_caps.numInpChBufs); 650 | txavailable = hw_priv->wsm_caps.numInpChBufs - hw_priv->hw_bufs_used; 651 | if (txavailable) { 652 | /* Wake up the devices */ 653 | if (hw_priv->device_can_sleep) { 654 | ret = xradio_device_wakeup(hw_priv); 655 | if (WARN_ON(ret < 0)) { 656 | return -1; 657 | } else if (ret) { 658 | hw_priv->device_can_sleep = false; 659 | } else { /* Wait for "awake" interrupt */ 660 | dev_dbg(hw_priv->pdev, 661 | "need to wait for device to wake before doing tx\n"); 662 | return 0; 663 | } 664 | } 665 | /* Increase Tx buffer*/ 666 | wsm_alloc_tx_buffer(hw_priv); 667 | 668 | /* Get data to send and send it. */ 669 | ret = wsm_get_tx(hw_priv, &data, &tx_len, &txburst, &vif_selected); 670 | if (ret <= 0) { 671 | wsm_release_tx_buffer(hw_priv, 1); 672 | if (WARN_ON(ret < 0)) { 673 | dev_err(hw_priv->pdev, "wsm_get_tx=%d.\n", ret); 674 | return -ENOMEM; 675 | } else { 676 | return 0; 677 | } 678 | } else { 679 | wsm = (struct wsm_hdr *) data; 680 | BUG_ON(tx_len < sizeof(*wsm)); 681 | BUG_ON(__le32_to_cpu(wsm->len) != tx_len); 682 | 683 | /* Align tx length and check it. */ 684 | if (tx_len <= 8) 685 | tx_len = 16; 686 | tx_len = sdio_align_len(hw_priv, tx_len); 687 | 688 | /* Check if not exceeding XRADIO capabilities */ 689 | if (tx_len > EFFECTIVE_BUF_SIZE) { 690 | dev_warn(hw_priv->pdev, "Write aligned len: %d\n", tx_len); 691 | } 692 | 693 | /* Make sequence number. */ 694 | wsm->id &= __cpu_to_le32(~WSM_TX_SEQ(WSM_TX_SEQ_MAX)); 695 | wsm->id |= cpu_to_le32(WSM_TX_SEQ(hw_priv->wsm_tx_seq)); 696 | 697 | /* Send the data to devices. */ 698 | if (WARN_ON(xradio_data_write(hw_priv, data, tx_len))) { 699 | wsm_release_tx_buffer(hw_priv, 1); 700 | dev_err(hw_priv->pdev, "xradio_data_write failed\n"); 701 | return -EIO; 702 | } 703 | 704 | xradio_bh_tx_dump(hw_priv->pdev, data, tx_len); 705 | 706 | /* Process after data have sent. */ 707 | if (vif_selected != -1) { 708 | hw_priv->hw_bufs_used_vif[vif_selected]++; 709 | } 710 | wsm_txed(hw_priv, data); 711 | hw_priv->wsm_tx_seq = (hw_priv->wsm_tx_seq + 1) & WSM_TX_SEQ_MAX; 712 | 713 | return 1; 714 | } 715 | } else 716 | return 0; 717 | } 718 | 719 | static int xradio_bh_exchange(struct xradio_common *hw_priv) { 720 | int rxdone; 721 | int txdone; 722 | u16 nextlen = 0; 723 | 724 | /* query stuck frames in firmware. */ 725 | if (atomic_xchg(&hw_priv->query_cnt, 0)) { 726 | if (schedule_work(&hw_priv->query_work) <= 0) 727 | atomic_add(1, &hw_priv->query_cnt); 728 | } 729 | 730 | /* keep doing tx and rx until they both stop or we are told 731 | * to terminate */ 732 | do { 733 | txdone = xradio_bh_tx(hw_priv); 734 | if (txdone < 0) { 735 | break; 736 | } 737 | rxdone = xradio_bh_rx(hw_priv, &nextlen); 738 | if (rxdone < 0) { 739 | break; 740 | } 741 | } while ((txdone > 0 || rxdone > 0) && !kthread_should_stop()); 742 | return 0; 743 | } 744 | 745 | static int xradio_bh(void *arg) 746 | { 747 | struct xradio_common *hw_priv = arg; 748 | int term, suspend; 749 | int wake = 0; 750 | long timeout; 751 | long status; 752 | 753 | for (;;) { 754 | timeout = HZ / 30; 755 | 756 | // wait for something to happen or a timeout 757 | status = wait_event_interruptible_timeout(hw_priv->bh_wq, ( { 758 | wake = atomic_xchg(&hw_priv->bh_tx, 0); 759 | term = kthread_should_stop(); 760 | suspend = atomic_read(&hw_priv->bh_suspend); 761 | (wake || term || suspend);}), timeout); 762 | 763 | if (wake) { 764 | if(xradio_bh_exchange(hw_priv) < 0){ 765 | break; 766 | } 767 | } else if (term) { 768 | dev_dbg(hw_priv->pdev, "xradio_bh exit!\n"); 769 | break; 770 | } else if (status < 0) { 771 | dev_err(hw_priv->pdev, "bh_error=%d, status=%ld\n", 772 | hw_priv->bh_error, status); 773 | break; 774 | } else if (!status) { 775 | /* check if there is data waiting but we missed the interrupt*/ 776 | if (xradio_bh_rx_availlen(hw_priv) > 0) { 777 | dev_warn(hw_priv->pdev, "missed interrupt\n"); 778 | if(xradio_bh_exchange(hw_priv) < 0){ 779 | break; 780 | } 781 | } 782 | /* There are some frames to be confirmed. */ 783 | else if (hw_priv->hw_bufs_used) { 784 | long timeout = 0; 785 | bool pending = 0; 786 | dev_dbg(hw_priv->pdev, "Need confirm:%d!\n", 787 | hw_priv->hw_bufs_used); 788 | /* Check if frame transmission is timed out. */ 789 | pending = xradio_query_txpkt_timeout(hw_priv, XRWL_ALL_IFS, 790 | hw_priv->pending_frame_id, &timeout); 791 | /* There are some frames confirm time out. */ 792 | if (pending && timeout < 0) { 793 | dev_err(hw_priv->pdev, "query_txpkt_timeout:%ld!\n", 794 | timeout); 795 | break; 796 | } 797 | } //else if (!txpending){ 798 | //if (hw_priv->powersave_enabled && !hw_priv->device_can_sleep && !atomic_read(&hw_priv->recent_scan)) { 799 | // /* Device is idle, we can go to sleep. */ 800 | // dev_dbg(hw_priv->pdev, "Device idle(timeout), can sleep.\n"); 801 | // WARN_ON(xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, 0)); 802 | // hw_priv->device_can_sleep = true; 803 | //} 804 | //continue; 805 | //} 806 | } else if (suspend) { 807 | dev_dbg(hw_priv->pdev, "Host suspend request.\n"); 808 | /* Check powersave setting again. */ 809 | if (hw_priv->powersave_enabled) { 810 | dev_dbg(hw_priv->pdev, 811 | "Device idle(host suspend), can sleep.\n"); 812 | WARN_ON(xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, 0)); 813 | hw_priv->device_can_sleep = true; 814 | } 815 | 816 | /* bh thread go to suspend. */ 817 | atomic_set(&hw_priv->bh_suspend, XRADIO_BH_SUSPENDED); 818 | wake_up(&hw_priv->bh_evt_wq); 819 | status = wait_event_interruptible(hw_priv->bh_wq, 820 | XRADIO_BH_RESUME == atomic_read(&hw_priv->bh_suspend)); 821 | 822 | if (status < 0) { 823 | dev_err(hw_priv->pdev, "Failed to wait for resume: %ld.\n", 824 | status); 825 | break; 826 | } 827 | dev_dbg(hw_priv->pdev, "Host resume.\n"); 828 | atomic_set(&hw_priv->bh_suspend, XRADIO_BH_RESUMED); 829 | wake_up(&hw_priv->bh_evt_wq); 830 | } 831 | } /* for (;;)*/ 832 | 833 | dev_err(hw_priv->pdev, "bh thread exiting\n"); 834 | 835 | return 0; 836 | } 837 | -------------------------------------------------------------------------------- /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=%d 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 = &hw_priv->keys[idx]; 69 | 70 | if (idx < 0) { 71 | wiphy_err(dev->wiphy, "xradio_alloc_key failed!\n"); 72 | ret = -EINVAL; 73 | goto finally; 74 | } 75 | 76 | BUG_ON(pairwise && !sta); 77 | if (sta) 78 | peer_addr = sta->addr; 79 | 80 | key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; 81 | 82 | priv->cipherType = key->cipher; 83 | switch (key->cipher) { 84 | case WLAN_CIPHER_SUITE_WEP40: 85 | case WLAN_CIPHER_SUITE_WEP104: 86 | if (key->keylen > 16) { 87 | xradio_free_key(hw_priv, idx); 88 | wiphy_err(dev->wiphy, "keylen too long=%d!\n", key->keylen); 89 | ret = -EINVAL; 90 | goto finally; 91 | } 92 | 93 | if (pairwise) { 94 | wsm_key->type = WSM_KEY_TYPE_WEP_PAIRWISE; 95 | memcpy(wsm_key->wepPairwiseKey.peerAddress, peer_addr, ETH_ALEN); 96 | memcpy(wsm_key->wepPairwiseKey.keyData, &key->key[0], key->keylen); 97 | wsm_key->wepPairwiseKey.keyLength = key->keylen; 98 | } else { 99 | wsm_key->type = WSM_KEY_TYPE_WEP_DEFAULT; 100 | memcpy(wsm_key->wepGroupKey.keyData, &key->key[0], key->keylen); 101 | wsm_key->wepGroupKey.keyLength = key->keylen; 102 | wsm_key->wepGroupKey.keyId = key->keyidx; 103 | } 104 | break; 105 | case WLAN_CIPHER_SUITE_TKIP: 106 | if (pairwise) { 107 | wsm_key->type = WSM_KEY_TYPE_TKIP_PAIRWISE; 108 | memcpy(wsm_key->tkipPairwiseKey.peerAddress, peer_addr, ETH_ALEN); 109 | memcpy(wsm_key->tkipPairwiseKey.tkipKeyData, &key->key[0], 16); 110 | memcpy(wsm_key->tkipPairwiseKey.txMicKey, &key->key[16], 8); 111 | memcpy(wsm_key->tkipPairwiseKey.rxMicKey, &key->key[24], 8); 112 | } else { 113 | size_t mic_offset = (priv->mode == NL80211_IFTYPE_AP) ? 16 : 24; 114 | wsm_key->type = WSM_KEY_TYPE_TKIP_GROUP; 115 | memcpy(wsm_key->tkipGroupKey.tkipKeyData,&key->key[0], 16); 116 | memcpy(wsm_key->tkipGroupKey.rxMicKey, &key->key[mic_offset], 8); 117 | 118 | /* TODO: Where can I find TKIP SEQ? */ 119 | memset(wsm_key->tkipGroupKey.rxSeqCounter, 0, 8); 120 | wsm_key->tkipGroupKey.keyId = key->keyidx; 121 | } 122 | break; 123 | case WLAN_CIPHER_SUITE_CCMP: 124 | if (pairwise) { 125 | wsm_key->type = WSM_KEY_TYPE_AES_PAIRWISE; 126 | memcpy(wsm_key->aesPairwiseKey.peerAddress, peer_addr, ETH_ALEN); 127 | memcpy(wsm_key->aesPairwiseKey.aesKeyData, &key->key[0], 16); 128 | wiphy_debug(dev->wiphy, "CCMP_PAIRWISE keylen=%d!\n", 129 | key->keylen); 130 | } else { 131 | wsm_key->type = WSM_KEY_TYPE_AES_GROUP; 132 | memcpy(wsm_key->aesGroupKey.aesKeyData, &key->key[0], 16); 133 | /* TODO: Where can I find AES SEQ? */ 134 | memset(wsm_key->aesGroupKey.rxSeqCounter, 0, 8); 135 | wsm_key->aesGroupKey.keyId = key->keyidx; 136 | } 137 | break; 138 | #ifdef CONFIG_XRADIO_WAPI_SUPPORT 139 | case WLAN_CIPHER_SUITE_SMS4: 140 | if (pairwise) { 141 | wsm_key->type = WSM_KEY_TYPE_WAPI_PAIRWISE; 142 | memcpy(wsm_key->wapiPairwiseKey.peerAddress, peer_addr, ETH_ALEN); 143 | memcpy(wsm_key->wapiPairwiseKey.wapiKeyData, &key->key[0], 16); 144 | memcpy(wsm_key->wapiPairwiseKey.micKeyData, &key->key[16], 16); 145 | wsm_key->wapiPairwiseKey.keyId = key->keyidx; 146 | sta_printk(XRADIO_DBG_NIY,"%s: WAPI_PAIRWISE keylen=%d!\n", 147 | __func__, key->keylen); 148 | } else { 149 | wsm_key->type = WSM_KEY_TYPE_WAPI_GROUP; 150 | memcpy(wsm_key->wapiGroupKey.wapiKeyData, &key->key[0], 16); 151 | memcpy(wsm_key->wapiGroupKey.micKeyData, &key->key[16], 16); 152 | wsm_key->wapiGroupKey.keyId = key->keyidx; 153 | sta_printk(XRADIO_DBG_NIY,"%s: WAPI_GROUP keylen=%d!\n", 154 | __func__, key->keylen); 155 | } 156 | break; 157 | #endif /* CONFIG_XRADIO_WAPI_SUPPORT */ 158 | default: 159 | wiphy_err(dev->wiphy, "key->cipher unknown(%d)!\n", key->cipher); 160 | xradio_free_key(hw_priv, idx); 161 | ret = -EOPNOTSUPP; 162 | goto finally; 163 | } 164 | ret = WARN_ON(wsm_add_key(hw_priv, wsm_key, priv->if_id)); 165 | if (!ret) 166 | key->hw_key_idx = idx; 167 | else 168 | xradio_free_key(hw_priv, idx); 169 | 170 | if (!ret && (pairwise || wsm_key->type == WSM_KEY_TYPE_WEP_DEFAULT) && 171 | (priv->filter4.enable & 0x2)) 172 | xradio_set_arpreply(dev, vif); 173 | } else if (cmd == DISABLE_KEY) { 174 | struct wsm_remove_key wsm_key = { 175 | .entryIndex = key->hw_key_idx, 176 | }; 177 | 178 | if (wsm_key.entryIndex > WSM_KEY_MAX_IDX) { 179 | ret = -EINVAL; 180 | goto finally; 181 | } 182 | 183 | xradio_free_key(hw_priv, wsm_key.entryIndex); 184 | ret = wsm_remove_key(hw_priv, &wsm_key, priv->if_id); 185 | } else { 186 | wiphy_err(dev->wiphy, "Unsupported command\n"); 187 | } 188 | 189 | finally: 190 | mutex_unlock(&hw_priv->conf_mutex); 191 | return ret; 192 | #endif // XRADIO_DISABLE_HW_CRYPTO 193 | } 194 | -------------------------------------------------------------------------------- /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 | 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 | }; 167 | 168 | 169 | /*************************************** functions ***************************************/ 170 | 171 | static void xradio_set_ifce_comb(struct xradio_common *hw_priv, 172 | struct ieee80211_hw *hw) 173 | { 174 | hw_priv->if_limits1[0].max = 1; 175 | 176 | hw_priv->if_limits1[0].types = BIT(NL80211_IFTYPE_STATION); 177 | hw_priv->if_limits1[1].max = 1; 178 | hw_priv->if_limits1[1].types = BIT(NL80211_IFTYPE_AP); 179 | 180 | hw_priv->if_limits2[0].max = 2; 181 | hw_priv->if_limits2[0].types = BIT(NL80211_IFTYPE_STATION); 182 | 183 | hw_priv->if_limits3[0].max = 1; 184 | 185 | hw_priv->if_limits3[0].types = BIT(NL80211_IFTYPE_STATION); 186 | hw_priv->if_limits3[1].max = 1; 187 | hw_priv->if_limits3[1].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | 188 | BIT(NL80211_IFTYPE_P2P_GO); 189 | 190 | /* TODO:COMBO: mac80211 doesn't yet support more than 1 191 | * different channel */ 192 | hw_priv->if_combs[0].num_different_channels = 1; 193 | hw_priv->if_combs[0].max_interfaces = 2; 194 | hw_priv->if_combs[0].limits = hw_priv->if_limits1; 195 | hw_priv->if_combs[0].n_limits = 2; 196 | 197 | hw_priv->if_combs[1].num_different_channels = 1; 198 | 199 | hw_priv->if_combs[1].max_interfaces = 2; 200 | hw_priv->if_combs[1].limits = hw_priv->if_limits2; 201 | hw_priv->if_combs[1].n_limits = 1; 202 | 203 | hw_priv->if_combs[2].num_different_channels = 1; 204 | hw_priv->if_combs[2].max_interfaces = 2; 205 | hw_priv->if_combs[2].limits = hw_priv->if_limits3; 206 | hw_priv->if_combs[2].n_limits = 2; 207 | 208 | hw->wiphy->iface_combinations = &hw_priv->if_combs[0]; 209 | hw->wiphy->n_iface_combinations = 3; 210 | } 211 | 212 | struct ieee80211_hw *xradio_init_common(size_t hw_priv_data_len) 213 | { 214 | int i; 215 | struct ieee80211_hw *hw; 216 | struct xradio_common *hw_priv; 217 | struct ieee80211_supported_band *sband; 218 | int band; 219 | 220 | /* Alloc ieee_802.11 hw and xradio_common struct. */ 221 | hw = ieee80211_alloc_hw(hw_priv_data_len, &xradio_ops); 222 | if (!hw) 223 | return NULL; 224 | hw_priv = hw->priv; 225 | memset(hw_priv, 0, sizeof(*hw_priv)); 226 | 227 | /* Initialize members of hw_priv. */ 228 | hw_priv->hw = hw; 229 | hw_priv->if_id_slot = 0; 230 | hw_priv->roc_if_id = -1; 231 | atomic_set(&hw_priv->num_vifs, 0); 232 | /* initial rates and channels TODO: fetch from FW */ 233 | hw_priv->rates = xradio_rates; 234 | hw_priv->mcs_rates = xradio_n_rates; 235 | #ifdef ROAM_OFFLOAD 236 | hw_priv->auto_scanning = 0; 237 | hw_priv->frame_rcvd = 0; 238 | hw_priv->num_scanchannels = 0; 239 | hw_priv->num_2g_channels = 0; 240 | hw_priv->num_5g_channels = 0; 241 | #endif /*ROAM_OFFLOAD*/ 242 | #ifdef AP_AGGREGATE_FW_FIX 243 | /* Enable block ACK for 4 TID (BE,VI,VI,VO). */ 244 | hw_priv->ba_tid_mask = 0xB1; /*due to HW limitations*/ 245 | #else 246 | /* Enable block ACK for every TID but voice. */ 247 | hw_priv->ba_tid_mask = 0x3F; 248 | #endif 249 | hw_priv->noise = -94; 250 | /* hw_priv->beacon_req_id = cpu_to_le32(0); */ 251 | 252 | /* Initialize members of ieee80211_hw, it works in UMAC. */ 253 | hw->sta_data_size = sizeof(struct xradio_sta_priv); 254 | hw->vif_data_size = sizeof(struct xradio_vif); 255 | 256 | ieee80211_hw_set(hw, SIGNAL_DBM); 257 | ieee80211_hw_set(hw, SUPPORTS_PS); 258 | ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); 259 | ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); 260 | ieee80211_hw_set(hw, CONNECTION_MONITOR); 261 | 262 | /* hw->flags = IEEE80211_HW_SIGNAL_DBM | 263 | IEEE80211_HW_SUPPORTS_PS | 264 | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | 265 | IEEE80211_HW_REPORTS_TX_ACK_STATUS | 266 | IEEE80211_HW_CONNECTION_MONITOR;*/ 267 | //IEEE80211_HW_SUPPORTS_CQM_RSSI | 268 | /* Aggregation is fully controlled by firmware. 269 | * Do not need any support from the mac80211 stack */ 270 | /* IEEE80211_HW_AMPDU_AGGREGATION | */ 271 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 272 | //IEEE80211_HW_SUPPORTS_P2P_PS | 273 | //IEEE80211_HW_SUPPORTS_CQM_BEACON_MISS | 274 | // IEEE80211_HW_SUPPORTS_CQM_TX_FAIL | 275 | #endif /* CONFIG_XRADIO_USE_EXTENSIONS */ 276 | //IEEE80211_HW_BEACON_FILTER; 277 | 278 | hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | 279 | BIT(NL80211_IFTYPE_ADHOC) | 280 | BIT(NL80211_IFTYPE_AP) | 281 | BIT(NL80211_IFTYPE_MESH_POINT) | 282 | BIT(NL80211_IFTYPE_P2P_CLIENT) | 283 | BIT(NL80211_IFTYPE_P2P_GO); 284 | 285 | /* Support only for limited wowlan functionalities */ 286 | /* TODO by Icenowy: RESTORE THIS */ 287 | /* hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | WIPHY_WOWLAN_DISCONNECT; 288 | hw->wiphy->wowlan.n_patterns = 0;*/ 289 | 290 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 291 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; 292 | #endif /* CONFIG_XRADIO_USE_EXTENSIONS */ 293 | /* fix the problem that driver can not set pro-resp template frame to fw */ 294 | hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; 295 | 296 | #if defined(CONFIG_XRADIO_DISABLE_BEACON_HINTS) 297 | hw->wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS; 298 | #endif 299 | hw->wiphy->n_addresses = XRWL_MAX_VIFS; 300 | hw->wiphy->addresses = hw_priv->addresses; 301 | hw->wiphy->max_remain_on_channel_duration = 500; 302 | hw->extra_tx_headroom = WSM_TX_EXTRA_HEADROOM + 303 | 8 /* TKIP IV */ + 304 | 12 /* TKIP ICV and MIC */; 305 | hw->wiphy->bands[NL80211_BAND_2GHZ] = &xradio_band_2ghz; 306 | hw->queues = AC_QUEUE_NUM; 307 | hw->max_rates = MAX_RATES_STAGE; 308 | hw->max_rate_tries = MAX_RATES_RETRY; 309 | /* Channel params have to be cleared before registering wiphy again */ 310 | for (band = 0; band < NUM_NL80211_BANDS; band++) { 311 | sband = hw->wiphy->bands[band]; 312 | if (!sband) 313 | continue; 314 | for (i = 0; i < sband->n_channels; i++) { 315 | sband->channels[i].flags = 0; 316 | sband->channels[i].max_antenna_gain = 0; 317 | sband->channels[i].max_power = 30; 318 | } 319 | } 320 | /* hw_priv->channel init value is the local->oper_channel init value;when transplanting,take care */ 321 | for (band = 0; band < NUM_NL80211_BANDS; band++) { 322 | sband = hw->wiphy->bands[band]; 323 | if (!sband) 324 | continue; 325 | if(!hw_priv->channel){ 326 | hw_priv->channel = &sband->channels[2]; 327 | } 328 | } 329 | hw->wiphy->max_scan_ssids = WSM_SCAN_MAX_NUM_OF_SSIDS; 330 | hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; 331 | SET_IEEE80211_PERM_ADDR(hw, hw_priv->addresses[0].addr); 332 | 333 | /* Initialize locks. */ 334 | spin_lock_init(&hw_priv->vif_list_lock); 335 | mutex_init(&hw_priv->wsm_cmd_mux); 336 | mutex_init(&hw_priv->conf_mutex); 337 | mutex_init(&hw_priv->wsm_oper_lock); 338 | atomic_set(&hw_priv->tx_lock, 0); 339 | sema_init(&hw_priv->tx_lock_sem, 1); 340 | 341 | hw_priv->workqueue = create_singlethread_workqueue(XRADIO_WORKQUEUE); 342 | sema_init(&hw_priv->scan.lock, 1); 343 | sema_init(&hw_priv->scan.status_lock,1); 344 | INIT_WORK(&hw_priv->scan.work, xradio_scan_work); 345 | #ifdef ROAM_OFFLOAD 346 | INIT_WORK(&hw_priv->scan.swork, xradio_sched_scan_work); 347 | #endif /*ROAM_OFFLOAD*/ 348 | INIT_DELAYED_WORK(&hw_priv->scan.probe_work, xradio_probe_work); 349 | INIT_DELAYED_WORK(&hw_priv->scan.timeout, xradio_scan_timeout); 350 | INIT_DELAYED_WORK(&hw_priv->rem_chan_timeout, xradio_rem_chan_timeout); 351 | INIT_WORK(&hw_priv->tx_policy_upload_work, tx_policy_upload_work); 352 | atomic_set(&hw_priv->upload_count, 0); 353 | memset(&hw_priv->connet_time, 0, sizeof(hw_priv->connet_time)); 354 | 355 | spin_lock_init(&hw_priv->event_queue_lock); 356 | INIT_LIST_HEAD(&hw_priv->event_queue); 357 | INIT_WORK(&hw_priv->event_handler, xradio_event_handler); 358 | INIT_WORK(&hw_priv->ba_work, xradio_ba_work); 359 | spin_lock_init(&hw_priv->ba_lock); 360 | init_timer(&hw_priv->ba_timer); 361 | hw_priv->ba_timer.data = (unsigned long)hw_priv; 362 | hw_priv->ba_timer.function = xradio_ba_timer; 363 | 364 | if (unlikely(xradio_queue_stats_init(&hw_priv->tx_queue_stats, 365 | WLAN_LINK_ID_MAX,xradio_skb_dtor, hw_priv))) { 366 | ieee80211_free_hw(hw); 367 | return NULL; 368 | } 369 | for (i = 0; i < AC_QUEUE_NUM; ++i) { 370 | if (unlikely(xradio_queue_init(&hw_priv->tx_queue[i], 371 | &hw_priv->tx_queue_stats, i, XRWL_MAX_QUEUE_SZ, xradio_ttl[i]))) { 372 | for (; i > 0; i--) 373 | xradio_queue_deinit(&hw_priv->tx_queue[i - 1]); 374 | xradio_queue_stats_deinit(&hw_priv->tx_queue_stats); 375 | ieee80211_free_hw(hw); 376 | return NULL; 377 | } 378 | } 379 | 380 | init_waitqueue_head(&hw_priv->channel_switch_done); 381 | init_waitqueue_head(&hw_priv->wsm_cmd_wq); 382 | init_waitqueue_head(&hw_priv->wsm_startup_done); 383 | init_waitqueue_head(&hw_priv->offchannel_wq); 384 | hw_priv->wsm_caps.firmwareReady = 0; 385 | hw_priv->driver_ready = 0; 386 | hw_priv->offchannel_done = 0; 387 | wsm_buf_init(&hw_priv->wsm_cmd_buf); 388 | spin_lock_init(&hw_priv->wsm_cmd.lock); 389 | tx_policy_init(hw_priv); 390 | xradio_init_resv_skb(hw_priv); 391 | /* add for setting short_frame_max_tx_count(mean wdev->retry_short) to drv,init the max_rate_tries */ 392 | spin_lock_bh(&hw_priv->tx_policy_cache.lock); 393 | hw_priv->long_frame_max_tx_count = hw->conf.long_frame_max_tx_count; 394 | hw_priv->short_frame_max_tx_count = 395 | (hw->conf.short_frame_max_tx_count< 0x0F) ? 396 | hw->conf.short_frame_max_tx_count : 0x0F; 397 | hw_priv->hw->max_rate_tries = hw->conf.short_frame_max_tx_count; 398 | spin_unlock_bh(&hw_priv->tx_policy_cache.lock); 399 | 400 | for (i = 0; i < XRWL_MAX_VIFS; i++) 401 | hw_priv->hw_bufs_used_vif[i] = 0; 402 | 403 | #ifdef MCAST_FWDING 404 | for (i = 0; i < WSM_MAX_BUF; i++) 405 | wsm_init_release_buffer_request(hw_priv, i); 406 | hw_priv->buf_released = 0; 407 | #endif 408 | hw_priv->vif0_throttle = XRWL_HOST_VIF0_11BG_THROTTLE; 409 | hw_priv->vif1_throttle = XRWL_HOST_VIF1_11BG_THROTTLE; 410 | 411 | hw_priv->query_packetID = 0; 412 | atomic_set(&hw_priv->query_cnt, 0); 413 | INIT_WORK(&hw_priv->query_work, wsm_query_work); 414 | 415 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 416 | atomic_set(&hw_priv->suspend_state, XRADIO_RESUME); 417 | #endif 418 | 419 | xradio_set_ifce_comb(hw_priv, hw_priv->hw); 420 | 421 | return hw; 422 | } 423 | 424 | void xradio_free_common(struct ieee80211_hw *dev) 425 | { 426 | int i; 427 | struct xradio_common *hw_priv = dev->priv; 428 | 429 | cancel_work_sync(&hw_priv->query_work); 430 | del_timer_sync(&hw_priv->ba_timer); 431 | mutex_destroy(&hw_priv->wsm_oper_lock); 432 | mutex_destroy(&hw_priv->conf_mutex); 433 | mutex_destroy(&hw_priv->wsm_cmd_mux); 434 | wsm_buf_deinit(&hw_priv->wsm_cmd_buf); 435 | flush_workqueue(hw_priv->workqueue); 436 | destroy_workqueue(hw_priv->workqueue); 437 | hw_priv->workqueue = NULL; 438 | 439 | xradio_deinit_resv_skb(hw_priv); 440 | if (hw_priv->skb_cache) { 441 | dev_kfree_skb(hw_priv->skb_cache); 442 | hw_priv->skb_cache = NULL; 443 | } 444 | 445 | for (i = 0; i < 4; ++i) 446 | xradio_queue_deinit(&hw_priv->tx_queue[i]); 447 | xradio_queue_stats_deinit(&hw_priv->tx_queue_stats); 448 | 449 | for (i = 0; i < XRWL_MAX_VIFS; i++) { 450 | kfree(hw_priv->vif_list[i]); 451 | hw_priv->vif_list[i] = NULL; 452 | } 453 | 454 | //fixed memory leakage by yangfh 455 | #ifdef MCAST_FWDING 456 | wsm_deinit_release_buffer(hw_priv); 457 | #endif 458 | /* unsigned int i; */ 459 | ieee80211_free_hw(dev); 460 | } 461 | 462 | int xradio_register_common(struct ieee80211_hw *dev) 463 | { 464 | int err = 0; 465 | struct xradio_common *hw_priv = dev->priv; 466 | 467 | SET_IEEE80211_DEV(dev, hw_priv->pdev); 468 | err = ieee80211_register_hw(dev); 469 | if (err) { 470 | dev_dbg(hw_priv->pdev, "Cannot register device (%d).\n", err); 471 | return err; 472 | } 473 | dev_dbg(hw_priv->pdev, "is registered as '%s'\n", 474 | wiphy_name(dev->wiphy)); 475 | 476 | hw_priv->driver_ready = 1; 477 | wake_up(&hw_priv->wsm_startup_done); 478 | return 0; 479 | } 480 | 481 | void xradio_unregister_common(struct ieee80211_hw *dev) 482 | { 483 | struct xradio_common *hw_priv = dev->priv; 484 | 485 | if (wiphy_dev(dev->wiphy)) { 486 | ieee80211_unregister_hw(dev); 487 | SET_IEEE80211_DEV(dev, NULL); 488 | } 489 | hw_priv->driver_ready = 0; 490 | } 491 | 492 | int xradio_core_init(struct sdio_func* func) 493 | { 494 | int err = -ENOMEM; 495 | u16 ctrl_reg; 496 | int if_id; 497 | struct ieee80211_hw *dev; 498 | struct xradio_common *hw_priv; 499 | unsigned char randomaddr[ETH_ALEN]; 500 | const unsigned char *addr = NULL; 501 | 502 | //init xradio_common 503 | dev = xradio_init_common(sizeof(struct xradio_common)); 504 | if (!dev) { 505 | dev_dbg(&func->dev, "xradio_init_common failed\n"); 506 | return err; 507 | } 508 | hw_priv = dev->priv; 509 | hw_priv->pdev = &func->dev; 510 | hw_priv->sdio_func = func; 511 | sdio_set_drvdata(func, hw_priv); 512 | 513 | // fill in mac addresses 514 | if (hw_priv->pdev->of_node) { 515 | addr = of_get_mac_address(hw_priv->pdev->of_node); 516 | } 517 | if (!addr) { 518 | dev_warn(hw_priv->pdev, "no mac address provided, using random\n"); 519 | eth_random_addr(randomaddr); 520 | addr = randomaddr; 521 | } 522 | memcpy(hw_priv->addresses[0].addr, addr, ETH_ALEN); 523 | memcpy(hw_priv->addresses[1].addr, addr, ETH_ALEN); 524 | hw_priv->addresses[1].addr[5] += 0x01; 525 | 526 | /*init pm and wakelock. */ 527 | #ifdef CONFIG_PM 528 | err = xradio_pm_init(&hw_priv->pm_state, hw_priv); 529 | if (err) { 530 | dev_dbg(hw_priv->pdev, "xradio_pm_init failed(%d).\n", err); 531 | goto err2; 532 | } 533 | #endif 534 | /* Register bh thread*/ 535 | err = xradio_register_bh(hw_priv); 536 | if (err) { 537 | dev_dbg(hw_priv->pdev, "xradio_register_bh failed(%d).\n", err); 538 | goto err3; 539 | } 540 | 541 | /* Load firmware and register Interrupt Handler */ 542 | err = xradio_load_firmware(hw_priv); 543 | if (err) { 544 | dev_dbg(hw_priv->pdev, "xradio_load_firmware failed(%d).\n", err); 545 | goto err4; 546 | } 547 | 548 | /* Set sdio blocksize. */ 549 | sdio_lock(hw_priv); 550 | WARN_ON(sdio_set_blk_size(hw_priv, 551 | SDIO_BLOCK_SIZE)); 552 | sdio_unlock(hw_priv); 553 | 554 | if (wait_event_interruptible_timeout(hw_priv->wsm_startup_done, 555 | hw_priv->wsm_caps.firmwareReady, 3*HZ) <= 0) { 556 | 557 | /* TODO: Needs to find how to reset device */ 558 | /* in QUEUE mode properly. */ 559 | dev_dbg(hw_priv->pdev, "Firmware Startup Timeout!\n"); 560 | err = -ETIMEDOUT; 561 | goto err5; 562 | } 563 | dev_dbg(hw_priv->pdev, "Firmware Startup Done.\n"); 564 | 565 | /* Keep device wake up. */ 566 | WARN_ON(xradio_reg_write_16(hw_priv, HIF_CONTROL_REG_ID, HIF_CTRL_WUP_BIT)); 567 | if (xradio_reg_read_16(hw_priv,HIF_CONTROL_REG_ID, &ctrl_reg)) 568 | WARN_ON(xradio_reg_read_16(hw_priv,HIF_CONTROL_REG_ID, &ctrl_reg)); 569 | WARN_ON(!(ctrl_reg & HIF_CTRL_RDY_BIT)); 570 | 571 | /* Set device mode parameter. */ 572 | for (if_id = 0; if_id < xrwl_get_nr_hw_ifaces(hw_priv); if_id++) { 573 | /* Set low-power mode. */ 574 | WARN_ON(wsm_set_operational_mode(hw_priv, &defaultoperationalmode, if_id)); 575 | /* Enable multi-TX confirmation */ 576 | WARN_ON(wsm_use_multi_tx_conf(hw_priv, true, if_id)); 577 | } 578 | 579 | /* Register wireless net device. */ 580 | err = xradio_register_common(dev); 581 | if (err) { 582 | dev_dbg(hw_priv->pdev, "xradio_register_common failed(%d)!\n", err); 583 | goto err5; 584 | } 585 | 586 | return err; 587 | 588 | err5: 589 | xradio_dev_deinit(hw_priv); 590 | err4: 591 | xradio_unregister_bh(hw_priv); 592 | err3: 593 | xradio_pm_deinit(&hw_priv->pm_state); 594 | err2: 595 | err1: 596 | xradio_free_common(dev); 597 | return err; 598 | } 599 | 600 | void xradio_core_deinit(struct sdio_func* func) 601 | { 602 | struct xradio_common* hw_priv = sdio_get_drvdata(func); 603 | if (hw_priv) { 604 | xradio_unregister_common(hw_priv->hw); 605 | xradio_dev_deinit(hw_priv); 606 | xradio_unregister_bh(hw_priv); 607 | xradio_pm_deinit(&hw_priv->pm_state); 608 | xradio_free_common(hw_priv->hw); 609 | } 610 | return; 611 | } 612 | -------------------------------------------------------------------------------- /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 | static void xradio_pm_stay_awake_tmo(unsigned long arg) 260 | { 261 | } 262 | 263 | int xradio_pm_init(struct xradio_pm_state *pm, 264 | struct xradio_common *hw_priv) 265 | { 266 | int ret = 0; 267 | pm_printk(XRADIO_DBG_MSG,"%s\n", __FUNCTION__); 268 | 269 | ret = xradio_pm_init_common(pm, hw_priv); 270 | if (!ret) { 271 | init_timer(&pm->stay_awake); 272 | pm->stay_awake.data = (unsigned long)pm; 273 | pm->stay_awake.function = xradio_pm_stay_awake_tmo; 274 | } else 275 | pm_printk(XRADIO_DBG_ERROR,"xradio_pm_init_common failed!\n"); 276 | return ret; 277 | } 278 | 279 | void xradio_pm_deinit(struct xradio_pm_state *pm) 280 | { 281 | del_timer_sync(&pm->stay_awake); 282 | xradio_pm_deinit_common(pm); 283 | } 284 | 285 | void xradio_pm_stay_awake(struct xradio_pm_state *pm, 286 | unsigned long tmo) 287 | { 288 | long cur_tmo; 289 | 290 | spin_lock_bh(&pm->lock); 291 | cur_tmo = pm->stay_awake.expires - jiffies; 292 | if (!timer_pending(&pm->stay_awake) || cur_tmo < (long)tmo) 293 | mod_timer(&pm->stay_awake, jiffies + tmo); 294 | spin_unlock_bh(&pm->lock); 295 | } 296 | void xradio_pm_lock_awake(struct xradio_pm_state *pm) 297 | { 298 | 299 | spin_lock_bh(&pm->lock); 300 | pm->expires_save = pm->stay_awake.expires; 301 | mod_timer(&pm->stay_awake, jiffies + LONG_MAX); 302 | spin_unlock_bh(&pm->lock); 303 | } 304 | void xradio_pm_unlock_awake(struct xradio_pm_state *pm) 305 | { 306 | 307 | spin_lock_bh(&pm->lock); 308 | if (time_before(jiffies, pm->expires_save)) 309 | mod_timer(&pm->stay_awake, pm->expires_save); 310 | else 311 | mod_timer(&pm->stay_awake, jiffies + 1); 312 | spin_unlock_bh(&pm->lock); 313 | } 314 | #endif /* CONFIG_WAKELOCK */ 315 | 316 | static long xradio_suspend_work(struct delayed_work *work) 317 | { 318 | int ret = cancel_delayed_work(work); 319 | long tmo; 320 | pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); 321 | 322 | if (ret > 0) { 323 | /* Timer is pending */ 324 | tmo = work->timer.expires - jiffies; 325 | if (tmo < 0) 326 | tmo = 0; 327 | } else { 328 | tmo = -1; 329 | } 330 | return tmo; 331 | } 332 | 333 | static int xradio_resume_work(struct xradio_common *hw_priv, 334 | struct delayed_work *work, 335 | unsigned long tmo) 336 | { 337 | pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); 338 | if ((long)tmo < 0) 339 | return 1; 340 | 341 | return queue_delayed_work(hw_priv->workqueue, work, tmo); 342 | } 343 | 344 | static int xradio_suspend_late(struct device *dev) 345 | { 346 | struct xradio_common *hw_priv = dev->platform_data; 347 | 348 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 349 | if (XRADIO_POWEROFF_SUSP == atomic_read(&hw_priv->suspend_state)) { 350 | return 0; /* we don't rx data when power down wifi.*/ 351 | } 352 | #endif 353 | 354 | //if (atomic_read(&hw_priv->bh_rx)) { 355 | // pm_printk(XRADIO_DBG_WARN, "%s: Suspend interrupted.\n", __func__); 356 | // return -EAGAIN; 357 | //} 358 | return 0; 359 | } 360 | 361 | static void xradio_pm_release(struct device *dev) 362 | { 363 | pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); 364 | } 365 | 366 | static int xradio_pm_probe(struct platform_device *pdev) 367 | { 368 | pm_printk(XRADIO_DBG_TRC, "%s\n", __func__); 369 | pdev->dev.release = xradio_pm_release; 370 | return 0; 371 | } 372 | 373 | int xradio_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) 374 | { 375 | struct xradio_common *hw_priv = hw->priv; 376 | struct xradio_vif *priv; 377 | int i, ret = 0; 378 | 379 | 380 | if(hw_priv->bh_error) return -EBUSY; 381 | WARN_ON(!atomic_read(&hw_priv->num_vifs)); 382 | 383 | if (work_pending(&hw_priv->query_work)) 384 | return -EBUSY; 385 | 386 | #ifdef ROAM_OFFLOAD 387 | xradio_for_each_vif(hw_priv, priv, i) { 388 | if (!priv) 389 | continue; 390 | if((priv->vif->type == NL80211_IFTYPE_STATION) 391 | && (priv->join_status == XRADIO_JOIN_STATUS_STA)) { 392 | down(&hw_priv->scan.lock); 393 | hw_priv->scan.if_id = priv->if_id; 394 | xradio_sched_scan_work(&hw_priv->scan.swork); 395 | } 396 | } 397 | #endif /*ROAM_OFFLOAD*/ 398 | 399 | /* Do not suspend when datapath is not idle */ 400 | if (hw_priv->tx_queue_stats.num_queued[0] + 401 | hw_priv->tx_queue_stats.num_queued[1]) { 402 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 403 | "because of tx_queue is not empty.\n"); 404 | return -EBUSY; 405 | } 406 | 407 | /* Make sure there is no configuration requests in progress. */ 408 | if (!mutex_trylock(&hw_priv->conf_mutex)) { 409 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 410 | "because of configuration requests.\n"); 411 | return -EBUSY; 412 | } 413 | 414 | /* Make sure there is no wsm_oper_lock in progress. */ 415 | if (!mutex_trylock(&hw_priv->wsm_oper_lock)) { 416 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 417 | "because of wsm_oper_lock.\n"); 418 | mutex_unlock(&hw_priv->conf_mutex); 419 | return -EBUSY; 420 | } 421 | 422 | /* Do not suspend when scanning or ROC*/ 423 | if (down_trylock(&hw_priv->scan.lock)) { 424 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 425 | "because of scan requests.\n"); 426 | goto revert1; 427 | } 428 | 429 | if (delayed_work_pending(&hw_priv->scan.probe_work)) { 430 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 431 | "because of probe frames tx in progress.\n"); 432 | goto revert2; 433 | } 434 | 435 | /* Lock TX. */ 436 | wsm_lock_tx_async(hw_priv); 437 | 438 | /* Wait to avoid possible race with bh code. 439 | * But do not wait too long... */ 440 | if (wait_event_timeout(hw_priv->bh_evt_wq, 441 | !hw_priv->hw_bufs_used, HZ / 10) <= 0) { 442 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 443 | "because of there are frames not confirm.\n"); 444 | goto revert3; 445 | } 446 | 447 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 448 | // if (STANDBY_WITH_POWER_OFF == standby_level) { 449 | if (1) { 450 | return xradio_poweroff_suspend(hw_priv); 451 | } 452 | #endif 453 | 454 | xradio_for_each_vif(hw_priv, priv, i) { 455 | if (!priv) 456 | continue; 457 | 458 | ret = __xradio_wow_suspend(priv, wowlan); 459 | if (ret) { 460 | for (; i >= 0; i--) { 461 | if (!hw_priv->vif_list[i]) 462 | continue; 463 | priv = (struct xradio_vif *)hw_priv->vif_list[i]->drv_priv; 464 | __xradio_wow_resume(priv); 465 | } 466 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 467 | "because of __xradio_wow_suspend failed!\n"); 468 | goto revert3; 469 | } 470 | } 471 | 472 | /* Stop serving thread */ 473 | if (xradio_bh_suspend(hw_priv)) { 474 | pm_printk(XRADIO_DBG_WARN, "Don't suspend " 475 | "because of xradio_bh_suspend failed!\n"); 476 | xradio_wow_resume(hw); 477 | return -EBUSY; 478 | } 479 | 480 | /* Enable IRQ wake */ 481 | ret = sdio_pm(hw_priv, true); 482 | if (ret) { 483 | pm_printk(XRADIO_DBG_WARN, "Don't suspend sbus pm failed\n"); 484 | xradio_wow_resume(hw); 485 | return -EBUSY; 486 | } 487 | 488 | /* Force resume if event is coming from the device. */ 489 | //if (atomic_read(&hw_priv->bh_rx)) { 490 | // pm_printk(XRADIO_DBG_WARN, "Don't suspend " 491 | // "because of recieved rx event!\n"); 492 | // xradio_wow_resume(hw); 493 | // return -EAGAIN; 494 | //} 495 | return 0; 496 | 497 | revert3: 498 | wsm_unlock_tx(hw_priv); 499 | revert2: 500 | up(&hw_priv->scan.lock); 501 | revert1: 502 | mutex_unlock(&hw_priv->conf_mutex); 503 | mutex_unlock(&hw_priv->wsm_oper_lock); 504 | return -EBUSY; 505 | } 506 | 507 | static int __xradio_wow_suspend(struct xradio_vif *priv, 508 | struct cfg80211_wowlan *wowlan) 509 | { 510 | struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); 511 | struct xradio_pm_state_vif *pm_state_vif = &priv->pm_state_vif; 512 | struct xradio_suspend_state *state; 513 | int ret; 514 | #ifdef MCAST_FWDING 515 | struct wsm_forwarding_offload fwdoffload = { 516 | .fwenable = 0x1, 517 | .flags = 0x1, 518 | }; 519 | #endif 520 | 521 | 522 | /* Do not suspend when join work is scheduled */ 523 | if (work_pending(&priv->join_work)) { 524 | pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend " 525 | "when join work is scheduled\n", __func__); 526 | goto revert1; 527 | } 528 | 529 | /* Set UDP filter */ 530 | wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_on.hdr, 531 | priv->if_id); 532 | 533 | /* Set ethernet frame type filter */ 534 | wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_on.hdr, 535 | priv->if_id); 536 | 537 | /* Set IP multicast filter */ 538 | wsm_set_host_sleep(hw_priv, 1, priv->if_id); 539 | 540 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 541 | WARN_ON(wsm_set_keepalive_filter(priv, true)); 542 | 543 | #ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE 544 | /* Set Multicast Address Filter */ 545 | if (priv->multicast_filter.numOfAddresses) { 546 | priv->multicast_filter.enable = 1; 547 | wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); 548 | } 549 | 550 | /* Set Enable Broadcast Address Filter */ 551 | priv->broadcast_filter.action_mode = 1; 552 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 553 | priv->broadcast_filter.address_mode = 3; 554 | 555 | xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter); 556 | #endif 557 | 558 | #ifdef MCAST_FWDING 559 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 560 | WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload,priv->if_id)); 561 | #endif 562 | 563 | /* Allocate state */ 564 | state = kzalloc(sizeof(struct xradio_suspend_state), GFP_KERNEL); 565 | if (!state) { 566 | pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend " 567 | "alloc xradio_suspend_state failed.\n", __func__); 568 | goto revert2; 569 | } 570 | /* Store delayed work states. */ 571 | state->bss_loss_tmo = xradio_suspend_work(&priv->bss_loss_work); 572 | state->connection_loss_tmo = xradio_suspend_work(&priv->connection_loss_work); 573 | state->join_tmo = xradio_suspend_work(&priv->join_timeout); 574 | state->link_id_gc = xradio_suspend_work(&priv->link_id_gc_work); 575 | 576 | /* Enable beacon skipping */ 577 | if (priv->join_status == XRADIO_JOIN_STATUS_STA && 578 | priv->join_dtim_period && !priv->has_multicast_subscription) { 579 | state->beacon_skipping = true; 580 | wsm_set_beacon_wakeup_period(hw_priv, priv->join_dtim_period, 581 | XRADIO_BEACON_SKIPPING_MULTIPLIER * \ 582 | priv->join_dtim_period, priv->if_id); 583 | } 584 | 585 | ret = timer_pending(&priv->mcast_timeout); 586 | if (ret) { 587 | pm_printk(XRADIO_DBG_WARN, "%s:Do not suspend " 588 | "mcast timeout timer_pending failed.\n", __func__); 589 | goto revert3; 590 | } 591 | 592 | /* Store suspend state */ 593 | pm_state_vif->suspend_state = state; 594 | 595 | return 0; 596 | 597 | revert3: 598 | xradio_resume_work(hw_priv, &priv->bss_loss_work, state->bss_loss_tmo); 599 | xradio_resume_work(hw_priv, &priv->connection_loss_work, 600 | state->connection_loss_tmo); 601 | xradio_resume_work(hw_priv, &priv->join_timeout, state->join_tmo); 602 | xradio_resume_work(hw_priv, &priv->link_id_gc_work, state->link_id_gc); 603 | kfree(state); 604 | 605 | revert2: 606 | wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_off, priv->if_id); 607 | wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_off, priv->if_id); 608 | wsm_set_host_sleep(hw_priv, 0, priv->if_id); 609 | 610 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 611 | WARN_ON(wsm_set_keepalive_filter(priv, false)); 612 | 613 | #ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE 614 | /* Set Multicast Address Filter */ 615 | if (priv->multicast_filter.numOfAddresses) { 616 | priv->multicast_filter.enable = 0; 617 | wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); 618 | } 619 | 620 | /* Set Enable Broadcast Address Filter */ 621 | priv->broadcast_filter.action_mode = 0; 622 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 623 | priv->broadcast_filter.address_mode = 0; 624 | xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter); 625 | #endif 626 | 627 | #ifdef MCAST_FWDING 628 | fwdoffload.flags = 0x0; 629 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 630 | WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload,priv->if_id)); 631 | #endif 632 | 633 | revert1: 634 | /* mutex_unlock(&hw_priv->conf_mutex); */ 635 | return -EBUSY; 636 | } 637 | 638 | int xradio_wow_resume(struct ieee80211_hw *hw) 639 | { 640 | 641 | struct xradio_common *hw_priv = hw->priv; 642 | struct xradio_vif *priv; 643 | int i, ret = 0; 644 | 645 | 646 | WARN_ON(!atomic_read(&hw_priv->num_vifs)); 647 | if(hw_priv->bh_error) return 0; 648 | 649 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 650 | if (XRADIO_POWEROFF_SUSP == atomic_read(&hw_priv->suspend_state)) { 651 | return xradio_poweroff_resume(hw_priv); 652 | } 653 | #endif 654 | 655 | /* Disable IRQ wake */ 656 | sdio_pm(hw_priv, false); 657 | 658 | up(&hw_priv->scan.lock); 659 | 660 | /* Resume BH thread */ 661 | WARN_ON(xradio_bh_resume(hw_priv)); 662 | 663 | xradio_for_each_vif(hw_priv, priv, i) { 664 | if (!priv) 665 | continue; 666 | ret = __xradio_wow_resume(priv); 667 | if (ret) { 668 | pm_printk(XRADIO_DBG_ERROR, "%s:__xradio_wow_resume failed!\n", __func__); 669 | break; 670 | } 671 | } 672 | 673 | wsm_unlock_tx(hw_priv); 674 | 675 | /* Unlock configuration mutex */ 676 | mutex_unlock(&hw_priv->conf_mutex); 677 | mutex_unlock(&hw_priv->wsm_oper_lock); 678 | 679 | return ret; 680 | } 681 | 682 | static int __xradio_wow_resume(struct xradio_vif *priv) 683 | { 684 | struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); 685 | struct xradio_pm_state_vif *pm_state_vif = &priv->pm_state_vif; 686 | struct xradio_suspend_state *state; 687 | #ifdef MCAST_FWDING 688 | struct wsm_forwarding_offload fwdoffload = { 689 | .fwenable = 0x1, 690 | .flags = 0x0, 691 | }; 692 | #endif 693 | 694 | 695 | /* Restore suspend state */ 696 | state = pm_state_vif->suspend_state; 697 | pm_state_vif->suspend_state = NULL; 698 | 699 | #ifdef ROAM_OFFLOAD 700 | if((priv->vif->type == NL80211_IFTYPE_STATION) 701 | && (priv->join_status == XRADIO_JOIN_STATUS_STA)) 702 | xradio_hw_sched_scan_stop(hw_priv); 703 | #endif /*ROAM_OFFLOAD*/ 704 | 705 | if (state->beacon_skipping) { 706 | #ifdef XRADIO_USE_LONG_DTIM_PERIOD 707 | int join_dtim_period_extend; 708 | if (priv->join_dtim_period <= 3) { 709 | join_dtim_period_extend = priv->join_dtim_period * 3; 710 | } else if (priv->join_dtim_period <= 5) { 711 | join_dtim_period_extend = priv->join_dtim_period * 2; 712 | } else { 713 | join_dtim_period_extend = priv->join_dtim_period; 714 | } 715 | wsm_set_beacon_wakeup_period(hw_priv, 716 | ((priv->beacon_int * join_dtim_period_extend) > MAX_BEACON_SKIP_TIME_MS ? 717 | 1 : join_dtim_period_extend) , 0, priv->if_id); 718 | #else 719 | wsm_set_beacon_wakeup_period(hw_priv, priv->beacon_int * 720 | (priv->join_dtim_period > MAX_BEACON_SKIP_TIME_MS ? 1 : priv->join_dtim_period), 721 | 0, priv->if_id); 722 | #endif 723 | state->beacon_skipping = false; 724 | } 725 | 726 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 727 | WARN_ON(wsm_set_keepalive_filter(priv, false)); 728 | 729 | #ifdef XRADIO_SUSPEND_RESUME_FILTER_ENABLE 730 | /* Set Multicast Address Filter */ 731 | if (priv->multicast_filter.numOfAddresses) { 732 | priv->multicast_filter.enable = 0; 733 | wsm_set_multicast_filter(hw_priv, &priv->multicast_filter, priv->if_id); 734 | } 735 | /* Set Enable Broadcast Address Filter */ 736 | priv->broadcast_filter.action_mode = 0; 737 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 738 | priv->broadcast_filter.address_mode = 0; 739 | xradio_set_macaddrfilter(hw_priv, priv, (u8 *)&priv->broadcast_filter); 740 | #endif 741 | 742 | #ifdef MCAST_FWDING 743 | if (priv->join_status == XRADIO_JOIN_STATUS_AP) 744 | WARN_ON(wsm_set_forwarding_offlad(hw_priv, &fwdoffload,priv->if_id)); 745 | #endif 746 | 747 | /* Resume delayed work */ 748 | xradio_resume_work(hw_priv, &priv->bss_loss_work, state->bss_loss_tmo); 749 | xradio_resume_work(hw_priv, &priv->connection_loss_work, 750 | state->connection_loss_tmo); 751 | xradio_resume_work(hw_priv, &priv->join_timeout, state->join_tmo); 752 | xradio_resume_work(hw_priv, &priv->link_id_gc_work, state->link_id_gc); 753 | 754 | /* Remove UDP port filter */ 755 | wsm_set_udp_port_filter(hw_priv, &xradio_udp_port_filter_off, priv->if_id); 756 | 757 | /* Remove ethernet frame type filter */ 758 | wsm_set_ether_type_filter(hw_priv, &xradio_ether_type_filter_off, priv->if_id); 759 | 760 | /* Remove IP multicast filter */ 761 | wsm_set_host_sleep(hw_priv, 0, priv->if_id); 762 | /* Free memory */ 763 | kfree(state); 764 | 765 | return 0; 766 | } 767 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 768 | static int xradio_poweroff_suspend(struct xradio_common *hw_priv) 769 | { 770 | 771 | //flush all work. 772 | cancel_work_sync(&hw_priv->query_work); 773 | flush_workqueue(hw_priv->workqueue); 774 | /* Schedule hardware restart, ensure no cmds in progress.*/ 775 | mutex_lock(&hw_priv->wsm_cmd_mux); 776 | atomic_set(&hw_priv->suspend_state, XRADIO_POWEROFF_SUSP); 777 | //hw_priv->hw_restart = true; 778 | mutex_unlock(&hw_priv->wsm_cmd_mux); 779 | /* Stop serving thread */ 780 | if (xradio_bh_suspend(hw_priv)) { 781 | pm_printk(XRADIO_DBG_WARN, "%s, xradio_bh_suspend failed!\n", __func__); 782 | return -EBUSY; 783 | } 784 | 785 | return 0; 786 | } 787 | 788 | static int xradio_poweroff_resume(struct xradio_common *hw_priv) 789 | { 790 | 791 | /* Revert locks */ 792 | wsm_unlock_tx(hw_priv); 793 | up(&hw_priv->scan.lock); 794 | mutex_unlock(&hw_priv->conf_mutex); 795 | mutex_unlock(&hw_priv->wsm_oper_lock); 796 | //if (schedule_work(&hw_priv->hw_restart_work) <= 0) 797 | // pm_printk(XRADIO_DBG_ERROR, "%s restart_work failed!\n", __func__); 798 | return 0; 799 | } 800 | #endif 801 | -------------------------------------------------------------------------------- /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 | xradio_queue_skb_dtor_t skb_dtor, 77 | struct xradio_common *priv); 78 | int xradio_queue_init(struct xradio_queue *queue, 79 | struct xradio_queue_stats *stats, 80 | u8 queue_id, 81 | size_t capacity, 82 | unsigned long ttl); 83 | int xradio_queue_clear(struct xradio_queue *queue, int if_id); 84 | void xradio_queue_stats_deinit(struct xradio_queue_stats *stats); 85 | void xradio_queue_deinit(struct xradio_queue *queue); 86 | 87 | size_t xradio_queue_get_num_queued(struct xradio_vif *priv, 88 | struct xradio_queue *queue, 89 | u32 link_id_map); 90 | int xradio_queue_put(struct xradio_queue *queue, 91 | struct sk_buff *skb, struct xradio_txpriv *txpriv); 92 | int xradio_queue_get(struct xradio_queue *queue, 93 | int if_id, u32 link_id_map, 94 | struct wsm_tx **tx, 95 | struct ieee80211_tx_info **tx_info, 96 | struct xradio_txpriv **txpriv); 97 | 98 | int xradio_queue_requeue(struct xradio_queue *queue, u32 packetID, bool check); 99 | 100 | int xradio_queue_requeue_all(struct xradio_queue *queue); 101 | int xradio_queue_remove(struct xradio_queue *queue, 102 | u32 packetID); 103 | 104 | int xradio_queue_get_skb(struct xradio_queue *queue, u32 packetID, 105 | struct sk_buff **skb, 106 | const struct xradio_txpriv **txpriv); 107 | void xradio_queue_lock(struct xradio_queue *queue); 108 | void xradio_queue_unlock(struct xradio_queue *queue); 109 | bool xradio_queue_get_xmit_timestamp(struct xradio_queue *queue, 110 | unsigned long *timestamp, int if_id, 111 | u32 pending_frameID, u32 *Old_frame_ID); 112 | bool xradio_query_txpkt_timeout(struct xradio_common *hw_priv, int if_id, 113 | u32 pending_pkt_id, long *timeout); 114 | 115 | 116 | bool xradio_queue_stats_is_empty(struct xradio_queue_stats *stats, 117 | u32 link_id_map, int if_id); 118 | 119 | static inline u8 xradio_queue_get_queue_id(u32 packetID) 120 | { 121 | return (packetID >> 16) & 0xF; 122 | } 123 | 124 | static inline u8 xradio_queue_get_if_id(u32 packetID) 125 | { 126 | return (packetID >> 20) & 0xF; 127 | } 128 | 129 | static inline u8 xradio_queue_get_link_id(u32 packetID) 130 | { 131 | return (packetID >> 24) & 0xF; 132 | } 133 | 134 | static inline u8 xradio_queue_get_generation(u32 packetID) 135 | { 136 | return (packetID >> 8) & 0xFF; 137 | } 138 | 139 | #endif /* XRADIO_QUEUE_H_INCLUDED */ 140 | -------------------------------------------------------------------------------- /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 int xradio_handle_pspoll(struct xradio_vif *priv, 12 | struct sk_buff *skb) 13 | { 14 | struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); 15 | struct ieee80211_sta *sta; 16 | struct ieee80211_pspoll *pspoll = 17 | (struct ieee80211_pspoll *) skb->data; 18 | int link_id = 0; 19 | u32 pspoll_mask = 0; 20 | int drop = 1; 21 | int i; 22 | 23 | 24 | if (priv->join_status != XRADIO_JOIN_STATUS_AP) 25 | goto done; 26 | if (memcmp(priv->vif->addr, pspoll->bssid, ETH_ALEN)) 27 | goto done; 28 | 29 | rcu_read_lock(); 30 | sta = ieee80211_find_sta(priv->vif, pspoll->ta); 31 | if (sta) { 32 | struct xradio_sta_priv *sta_priv; 33 | sta_priv = (struct xradio_sta_priv *)&sta->drv_priv; 34 | link_id = sta_priv->link_id; 35 | pspoll_mask = BIT(sta_priv->link_id); 36 | } 37 | rcu_read_unlock(); 38 | if (!link_id) 39 | goto done; 40 | 41 | priv->pspoll_mask |= pspoll_mask; 42 | drop = 0; 43 | 44 | /* Do not report pspols if data for given link id is 45 | * queued already. */ 46 | for (i = 0; i < 4; ++i) { 47 | if (xradio_queue_get_num_queued(priv, 48 | &hw_priv->tx_queue[i], 49 | pspoll_mask)) { 50 | xradio_bh_wakeup(hw_priv); 51 | drop = 1; 52 | break; 53 | } 54 | } 55 | txrx_printk(XRADIO_DBG_NIY, "[RX] PSPOLL: %s\n", drop ? "local" : "fwd"); 56 | done: 57 | return drop; 58 | } 59 | 60 | 61 | static void 62 | xradio_rx_h_ba_stat(struct xradio_vif *priv, 63 | size_t hdrlen, size_t skb_len ) 64 | { 65 | struct xradio_common *hw_priv = priv->hw_priv; 66 | 67 | 68 | if (priv->join_status != XRADIO_JOIN_STATUS_STA) 69 | return; 70 | if (!xradio_is_ht(&hw_priv->ht_oper)) 71 | return; 72 | if (!priv->setbssparams_done) 73 | return; 74 | 75 | spin_lock_bh(&hw_priv->ba_lock); 76 | hw_priv->ba_acc_rx += skb_len - hdrlen; 77 | if (!(hw_priv->ba_cnt_rx || hw_priv->ba_cnt)) { 78 | mod_timer(&hw_priv->ba_timer, 79 | jiffies + XRADIO_BLOCK_ACK_INTERVAL); 80 | } 81 | hw_priv->ba_cnt_rx++; 82 | spin_unlock_bh(&hw_priv->ba_lock); 83 | } 84 | 85 | void xradio_rx_cb(struct xradio_vif *priv, 86 | struct wsm_rx *arg, 87 | struct sk_buff **skb_p) 88 | { 89 | struct xradio_common *hw_priv = xrwl_vifpriv_to_hwpriv(priv); 90 | struct sk_buff *skb = *skb_p; 91 | struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb); 92 | struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; 93 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 94 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; 95 | #endif 96 | struct xradio_link_entry *entry = NULL; 97 | unsigned long grace_period; 98 | bool early_data = false; 99 | size_t hdrlen = 0; 100 | u8 parse_iv_len = 0; 101 | 102 | dev_dbg(hw_priv->pdev, "vif %d: rx, status %u flags 0x%.8x", 103 | priv->if_id, arg->status, arg->flags); 104 | if(ieee80211_is_deauth(frame->frame_control)) 105 | dev_dbg(hw_priv->pdev, "vif %d: deauth\n", priv->if_id); 106 | 107 | hdr->flag = 0; 108 | 109 | if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) { 110 | /* STA is stopped. */ 111 | goto drop; 112 | } 113 | 114 | #ifdef TES_P2P_0002_ROC_RESTART 115 | xradio_frame_monitor(hw_priv,skb,false); 116 | #endif 117 | 118 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 119 | if ((ieee80211_is_action(frame->frame_control)) 120 | && (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { 121 | u8 *action = (u8*)&mgmt->u.action.category; 122 | xradio_check_go_neg_conf_success(hw_priv, action); 123 | } 124 | #endif 125 | 126 | if (arg->link_id && (arg->link_id != XRADIO_LINK_ID_UNMAPPED) 127 | && (arg->link_id <= XRADIO_MAX_STA_IN_AP_MODE)) { 128 | entry = &priv->link_id_db[arg->link_id - 1]; 129 | if (entry->status == XRADIO_LINK_SOFT && 130 | ieee80211_is_data(frame->frame_control)) 131 | early_data = true; 132 | entry->timestamp = jiffies; 133 | } 134 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 135 | else if ((arg->link_id == XRADIO_LINK_ID_UNMAPPED) 136 | && (priv->vif->p2p == WSM_START_MODE_P2P_GO) 137 | && ieee80211_is_action(frame->frame_control) 138 | && (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { 139 | txrx_printk(XRADIO_DBG_NIY, "[RX] Going to MAP&RESET link ID\n"); 140 | 141 | if (work_pending(&priv->linkid_reset_work)) 142 | WARN_ON(1); 143 | 144 | memcpy(&priv->action_frame_sa[0], 145 | ieee80211_get_SA(frame), ETH_ALEN); 146 | priv->action_linkid = 0; 147 | schedule_work(&priv->linkid_reset_work); 148 | } 149 | 150 | if (arg->link_id && (arg->link_id != XRADIO_LINK_ID_UNMAPPED) 151 | && (priv->vif->p2p == WSM_START_MODE_P2P_GO) 152 | && ieee80211_is_action(frame->frame_control) 153 | && (mgmt->u.action.category == WLAN_CATEGORY_PUBLIC)) { 154 | /* Link ID already exists for the ACTION frame. 155 | * Reset and Remap */ 156 | if (work_pending(&priv->linkid_reset_work)) 157 | WARN_ON(1); 158 | memcpy(&priv->action_frame_sa[0], 159 | ieee80211_get_SA(frame), ETH_ALEN); 160 | priv->action_linkid = arg->link_id; 161 | schedule_work(&priv->linkid_reset_work); 162 | } 163 | #endif 164 | if (unlikely(arg->status)) { 165 | if (arg->status == WSM_STATUS_MICFAILURE) { 166 | dev_err(priv->hw_priv->pdev, "[RX] IF=%d, MIC failure.\n", 167 | priv->if_id); 168 | hdr->flag |= RX_FLAG_MMIC_ERROR; 169 | } else if (arg->status == WSM_STATUS_NO_KEY_FOUND) { 170 | dev_warn(priv->hw_priv->pdev, "received frame has no key status\n"); 171 | //goto drop; 172 | } else { 173 | dev_err(priv->hw_priv->pdev, "[RX] IF=%d, Receive failure: %d.\n", 174 | priv->if_id, arg->status); 175 | goto drop; 176 | } 177 | } 178 | 179 | if (skb->len < sizeof(struct ieee80211_pspoll)) { 180 | dev_err(priv->hw_priv->pdev, "Malformed SDU rx'ed. " 181 | "Size is lesser than IEEE header.\n"); 182 | goto drop; 183 | } 184 | 185 | if (unlikely(ieee80211_is_pspoll(frame->frame_control))) 186 | if (xradio_handle_pspoll(priv, skb)) 187 | goto drop; 188 | 189 | hdr->mactime = 0; /* Not supported by WSM */ 190 | hdr->band = (arg->channelNumber > 14) ? 191 | NL80211_BAND_5GHZ : NL80211_BAND_2GHZ; 192 | hdr->freq = ieee80211_channel_to_frequency( 193 | arg->channelNumber, 194 | hdr->band); 195 | 196 | #ifdef AP_HT_COMPAT_FIX 197 | if (!priv->ht_compat_det && priv->htcap && 198 | ieee80211_is_data_qos(frame->frame_control)) { 199 | if(xradio_apcompat_detect(priv, arg->rxedRate)) 200 | goto drop; 201 | } 202 | #endif 203 | 204 | if (arg->rxedRate >= 14) { 205 | #ifdef RX_ENC_FLAG_STBC_SHIFT 206 | hdr->flag |= RX_ENC_HT; 207 | #else 208 | hdr->flag |= RX_FLAG_HT; 209 | #endif 210 | hdr->rate_idx = arg->rxedRate - 14; 211 | } else if (arg->rxedRate >= 4) { 212 | if (hdr->band == NL80211_BAND_5GHZ) 213 | hdr->rate_idx = arg->rxedRate - 6; 214 | else 215 | hdr->rate_idx = arg->rxedRate - 2; 216 | } else { 217 | hdr->rate_idx = arg->rxedRate; 218 | } 219 | 220 | hdr->signal = (s8)arg->rcpiRssi; 221 | hdr->antenna = 0; 222 | 223 | hdrlen = ieee80211_hdrlen(frame->frame_control); 224 | 225 | if (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { 226 | size_t iv_len = 0, icv_len = 0; 227 | 228 | hdr->flag |= RX_FLAG_DECRYPTED; 229 | 230 | /* Oops... There is no fast way to ask mac80211 about 231 | * IV/ICV lengths. Even defines are not exposed.*/ 232 | switch (WSM_RX_STATUS_ENCRYPTION(arg->flags)) { 233 | case WSM_RX_STATUS_WEP: 234 | iv_len = 4 /* WEP_IV_LEN */; 235 | icv_len = 4 /* WEP_ICV_LEN */; 236 | break; 237 | case WSM_RX_STATUS_TKIP: 238 | iv_len = 8 /* TKIP_IV_LEN */; 239 | icv_len = 4 /* TKIP_ICV_LEN */ 240 | + 8 /*MICHAEL_MIC_LEN*/; 241 | break; 242 | case WSM_RX_STATUS_AES: 243 | iv_len = 8 /* CCMP_HDR_LEN */; 244 | icv_len = 8 /* CCMP_MIC_LEN */; 245 | break; 246 | case WSM_RX_STATUS_WAPI: 247 | iv_len = 18 /* WAPI_HDR_LEN */; 248 | icv_len = 16 /* WAPI_MIC_LEN */; 249 | hdr->flag |= RX_FLAG_IV_STRIPPED; 250 | break; 251 | default: 252 | WARN_ON("Unknown encryption type"); 253 | goto drop; 254 | } 255 | 256 | /* Firmware strips ICV in case of MIC failure. */ 257 | if (arg->status == WSM_STATUS_MICFAILURE) { 258 | icv_len = 0; 259 | hdr->flag |= RX_FLAG_IV_STRIPPED; 260 | } 261 | 262 | if (skb->len < hdrlen + iv_len + icv_len) { 263 | dev_err(priv->hw_priv->pdev, "Mailformed SDU rx'ed. " 264 | "Size is lesser than crypto headers.\n"); 265 | goto drop; 266 | } 267 | 268 | if (WSM_RX_STATUS_ENCRYPTION(arg->flags) == 269 | WSM_RX_STATUS_TKIP) { 270 | /* Remove TKIP MIC 8 bytes*/ 271 | memmove(skb->data + skb->len-icv_len, 272 | skb->data + skb->len-icv_len+8, 4); 273 | skb_trim(skb, skb->len - 8); 274 | hdr->flag |= RX_FLAG_MMIC_STRIPPED; 275 | } else if (unlikely(WSM_RX_STATUS_ENCRYPTION(arg->flags) == 276 | WSM_RX_STATUS_WAPI)) { 277 | /* Protocols not defined in mac80211 should be 278 | stripped/crypted in driver/firmware */ 279 | /* Remove IV, ICV and MIC */ 280 | skb_trim(skb, skb->len - icv_len); 281 | memmove(skb->data + iv_len, skb->data, hdrlen); 282 | skb_pull(skb, iv_len); 283 | } 284 | parse_iv_len = iv_len; 285 | } 286 | 287 | if (ieee80211_is_beacon(frame->frame_control) && 288 | !arg->status && 289 | !memcmp(ieee80211_get_SA(frame), priv->join_bssid,ETH_ALEN)) { 290 | const u8 *tim_ie; 291 | u8 *ies; 292 | size_t ies_len; 293 | priv->disable_beacon_filter = false; 294 | queue_work(hw_priv->workqueue, &priv->update_filtering_work); 295 | ies = ((struct ieee80211_mgmt *) 296 | (skb->data))->u.beacon.variable; 297 | ies_len = skb->len - (ies - (u8 *)(skb->data)); 298 | 299 | tim_ie = xradio_get_ie(ies, ies_len, WLAN_EID_TIM); 300 | if (tim_ie) { 301 | struct ieee80211_tim_ie *tim = 302 | (struct ieee80211_tim_ie *)&tim_ie[2]; 303 | 304 | if (priv->join_dtim_period != tim->dtim_period) { 305 | priv->join_dtim_period = tim->dtim_period; 306 | queue_work(hw_priv->workqueue, 307 | &priv->set_beacon_wakeup_period_work); 308 | } 309 | } 310 | if (unlikely(priv->disable_beacon_filter)) { 311 | priv->disable_beacon_filter = false; 312 | queue_work(hw_priv->workqueue, 313 | &priv->update_filtering_work); 314 | } 315 | } 316 | #ifdef AP_HT_CAP_UPDATE 317 | if (priv->mode == NL80211_IFTYPE_AP && 318 | ieee80211_is_beacon(frame->frame_control) && 319 | ((priv->ht_oper&HT_INFO_MASK) != 0x0011) && 320 | !arg->status){ 321 | u8 *ies; 322 | size_t ies_len; 323 | const u8 *ht_cap; 324 | ies = ((struct ieee80211_mgmt *)(skb->data))->u.beacon.variable; 325 | ies_len = skb->len - (ies - (u8 *)(skb->data)); 326 | ht_cap = xradio_get_ie(ies, ies_len, WLAN_EID_HT_CAPABILITY); 327 | if(!ht_cap) { 328 | priv->ht_oper |= 0x0011; 329 | queue_work(hw_priv->workqueue, &priv->ht_oper_update_work); 330 | } 331 | } 332 | #endif 333 | 334 | #ifdef AP_HT_COMPAT_FIX 335 | if (ieee80211_is_mgmt(frame->frame_control) && 336 | priv->if_id == 0 && !(priv->ht_compat_det & 0x10)) { 337 | xradio_remove_ht_ie(priv, skb); 338 | } 339 | #endif 340 | 341 | #ifdef ROAM_OFFLOAD 342 | if ((ieee80211_is_beacon(frame->frame_control)||ieee80211_is_probe_resp(frame->frame_control)) && 343 | !arg->status ) { 344 | if (hw_priv->auto_scanning && !atomic_read(&hw_priv->scan.in_progress)) 345 | hw_priv->frame_rcvd = 1; 346 | 347 | if (!memcmp(ieee80211_get_SA(frame), priv->join_bssid, ETH_ALEN)) { 348 | if (hw_priv->beacon) 349 | dev_kfree_skb(hw_priv->beacon); 350 | hw_priv->beacon = skb_copy(skb, GFP_ATOMIC); 351 | if (!hw_priv->beacon) 352 | txrx_printk(XRADIO_DBG_ERROR, "sched_scan: own beacon storing failed\n"); 353 | } 354 | } 355 | #endif /*ROAM_OFFLOAD*/ 356 | 357 | //don't delay scan before next connect, yangfh. 358 | if (ieee80211_is_deauth(frame->frame_control) || 359 | ieee80211_is_disassoc(frame->frame_control)) 360 | hw_priv->connet_time[priv->if_id] = 0; 361 | 362 | /* Stay awake for 1sec. after frame is received to give 363 | * userspace chance to react and acquire appropriate 364 | * wakelock. */ 365 | if (ieee80211_is_auth(frame->frame_control)) 366 | grace_period = 5 * HZ; 367 | else if (ieee80211_is_deauth(frame->frame_control)) 368 | grace_period = 5 * HZ; 369 | else 370 | grace_period = HZ; 371 | 372 | if (ieee80211_is_data(frame->frame_control)) 373 | xradio_rx_h_ba_stat(priv, hdrlen, skb->len); 374 | 375 | xradio_pm_stay_awake(&hw_priv->pm_state, grace_period); 376 | 377 | if(xradio_realloc_resv_skb(hw_priv, *skb_p)) { 378 | *skb_p = NULL; 379 | return; 380 | } 381 | /* Try to a packet for the case dev_alloc_skb failed in bh.*/ 382 | if (unlikely(early_data)) { 383 | spin_lock_bh(&priv->ps_state_lock); 384 | /* Double-check status with lock held */ 385 | if (entry->status == XRADIO_LINK_SOFT) { 386 | skb_queue_tail(&entry->rx_queue, skb); 387 | dev_warn(priv->hw_priv->pdev, "***skb_queue_tail\n"); 388 | } else 389 | ieee80211_rx_irqsafe(priv->hw, skb); 390 | spin_unlock_bh(&priv->ps_state_lock); 391 | } else { 392 | ieee80211_rx_irqsafe(priv->hw, skb); 393 | } 394 | *skb_p = NULL; 395 | 396 | return; 397 | 398 | drop: 399 | dev_warn(priv->hw_priv->pdev, "dropped received frame\n"); 400 | return; 401 | } 402 | -------------------------------------------------------------------------------- /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 = sdio_memcpy_fromio(self->sdio_func, dst, addr, count); 39 | // printk("sdio_memcpy_fromio 0x%x:%d ret %d\n", addr, count, ret); 40 | // print_hex_dump_bytes("sdio read ", 0, dst, min(count,32)); 41 | return ret; 42 | } 43 | 44 | int sdio_data_write(struct xradio_common* self, unsigned int addr, 45 | const void *src, int count) 46 | { 47 | int ret = sdio_memcpy_toio(self->sdio_func, addr, (void *)src, count); 48 | // printk("sdio_memcpy_toio 0x%x:%d ret %d\n", addr, count, ret); 49 | // print_hex_dump_bytes("sdio write", 0, src, min(count,32)); 50 | return ret; 51 | } 52 | 53 | void sdio_lock(struct xradio_common* self) 54 | { 55 | sdio_claim_host(self->sdio_func); 56 | } 57 | 58 | void sdio_unlock(struct xradio_common *self) 59 | { 60 | sdio_release_host(self->sdio_func); 61 | } 62 | 63 | size_t sdio_align_len(struct xradio_common *self, size_t size) 64 | { 65 | return sdio_align_size(self->sdio_func, size); 66 | } 67 | 68 | int sdio_set_blk_size(struct xradio_common *self, size_t size) 69 | { 70 | return sdio_set_block_size(self->sdio_func, size); 71 | } 72 | 73 | extern void xradio_irq_handler(struct xradio_common*); 74 | 75 | static irqreturn_t sdio_irq_handler(int irq, void *dev_id) 76 | { 77 | struct sdio_func *func = (struct sdio_func*) dev_id; 78 | struct xradio_common *self = sdio_get_drvdata(func); 79 | if (self != NULL) 80 | xradio_irq_handler(self); 81 | return IRQ_HANDLED; 82 | } 83 | 84 | static int sdio_enableint(struct sdio_func* func) 85 | { 86 | int ret = 0; 87 | u8 cccr; 88 | int func_num; 89 | 90 | sdio_claim_host(func); 91 | 92 | /* Hack to access Fuction-0 */ 93 | func_num = func->num; 94 | func->num = 0; 95 | cccr = sdio_readb(func, SDIO_CCCR_IENx, &ret); 96 | cccr |= BIT(0); /* Master interrupt enable ... */ 97 | cccr |= BIT(func_num); /* ... for our function */ 98 | sdio_writeb(func, cccr, SDIO_CCCR_IENx, &ret); 99 | 100 | /* Restore the WLAN function number */ 101 | func->num = func_num; 102 | 103 | sdio_release_host(func); 104 | 105 | return ret; 106 | } 107 | 108 | int sdio_pm(struct xradio_common *self, bool suspend) 109 | { 110 | int ret = 0; 111 | if (suspend) { 112 | /* Notify SDIO that XRADIO will remain powered during suspend */ 113 | ret = sdio_set_host_pm_flags(self->sdio_func, MMC_PM_KEEP_POWER); 114 | if (ret) 115 | dev_dbg(&self->sdio_func->dev, "Error setting SDIO pm flags: %i\n", ret); 116 | } 117 | 118 | return ret; 119 | } 120 | 121 | static const struct of_device_id xradio_sdio_of_match_table[] = { 122 | { .compatible = "xradio,xr819" }, 123 | { } 124 | }; 125 | 126 | static int xradio_probe_of(struct sdio_func *func) 127 | { 128 | struct device *dev = &func->dev; 129 | struct device_node *np = dev->of_node; 130 | const struct of_device_id *of_id; 131 | int irq; 132 | 133 | of_id = of_match_node(xradio_sdio_of_match_table, np); 134 | if (!of_id) 135 | return -ENODEV; 136 | 137 | //pdev_data->family = of_id->data; 138 | 139 | irq = irq_of_parse_and_map(np, 0); 140 | if (!irq) { 141 | dev_err(dev, "No irq in platform data\n"); 142 | return -EINVAL; 143 | } 144 | 145 | devm_request_irq(dev, irq, sdio_irq_handler, 0, "xradio", func); 146 | 147 | return 0; 148 | } 149 | 150 | /* Probe Function to be called by SDIO stack when device is discovered */ 151 | static int sdio_probe(struct sdio_func *func, 152 | const struct sdio_device_id *id) 153 | { 154 | dev_dbg(&func->dev, "XRadio Device:sdio clk=%d\n", 155 | func->card->host->ios.clock); 156 | dev_dbg(&func->dev, "sdio func->class=%x\n", func->class); 157 | dev_dbg(&func->dev, "sdio_vendor: 0x%04x\n", func->vendor); 158 | dev_dbg(&func->dev, "sdio_device: 0x%04x\n", func->device); 159 | dev_dbg(&func->dev, "Function#: 0x%04x\n", func->num); 160 | 161 | #if 0 //for odly and sdly debug. 162 | { 163 | u32 sdio_param = 0; 164 | sdio_param = readl(__io_address(0x01c20088)); 165 | sdio_param &= ~(0xf<<8); 166 | sdio_param |= 3<<8; 167 | sdio_param &= ~(0xf<<20); 168 | sdio_param |= s_dly<<20; 169 | writel(sdio_param, __io_address(0x01c20088)); 170 | sbus_printk(XRADIO_DBG_ALWY, "%s: 0x01c20088=0x%08x\n", __func__, sdio_param); 171 | } 172 | #endif 173 | 174 | xradio_probe_of(func); 175 | 176 | func->card->quirks |= MMC_QUIRK_BROKEN_BYTE_MODE_512; 177 | sdio_claim_host(func); 178 | sdio_enable_func(func); 179 | sdio_release_host(func); 180 | 181 | sdio_enableint(func); 182 | 183 | xradio_core_init(func); 184 | 185 | try_module_get(func->dev.driver->owner); 186 | return 0; 187 | } 188 | /* Disconnect Function to be called by SDIO stack when 189 | * device is disconnected */ 190 | static void sdio_remove(struct sdio_func *func) 191 | { 192 | sdio_claim_host(func); 193 | sdio_disable_func(func); 194 | sdio_release_host(func); 195 | module_put(func->dev.driver->owner); 196 | } 197 | 198 | static int sdio_suspend(struct device *dev) 199 | { 200 | int ret = 0; 201 | /* 202 | struct sdio_func *func = dev_to_sdio_func(dev); 203 | ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); 204 | if (ret) 205 | sbus_printk(XRADIO_DBG_ERROR, "set MMC_PM_KEEP_POWER error\n"); 206 | */ 207 | return ret; 208 | } 209 | 210 | static int sdio_resume(struct device *dev) 211 | { 212 | return 0; 213 | } 214 | 215 | static const struct dev_pm_ops sdio_pm_ops = { 216 | .suspend = sdio_suspend, 217 | .resume = sdio_resume, 218 | }; 219 | 220 | static struct sdio_driver sdio_driver = { 221 | .name = "xradio_wlan", 222 | .id_table = xradio_sdio_ids, 223 | .probe = sdio_probe, 224 | .remove = sdio_remove, 225 | .drv = { 226 | .owner = THIS_MODULE, 227 | .pm = &sdio_pm_ops, 228 | } 229 | }; 230 | 231 | 232 | int xradio_sdio_register(){ 233 | return sdio_register_driver(&sdio_driver); 234 | } 235 | 236 | void xradio_sdio_unregister(){ 237 | sdio_unregister_driver(&sdio_driver); 238 | } 239 | 240 | MODULE_DEVICE_TABLE(sdio, xradio_sdio_ids); 241 | -------------------------------------------------------------------------------- /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 (28) 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 | void xradio_stop(struct ieee80211_hw *dev); 35 | int xradio_add_interface(struct ieee80211_hw *dev, struct ieee80211_vif *vif); 36 | void xradio_remove_interface(struct ieee80211_hw *dev, struct ieee80211_vif *vif); 37 | int xradio_change_interface(struct ieee80211_hw *dev, 38 | struct ieee80211_vif *vif, 39 | enum nl80211_iftype new_type, 40 | bool p2p); 41 | int xradio_config(struct ieee80211_hw *dev, u32 changed); 42 | int xradio_change_interface(struct ieee80211_hw *dev, 43 | struct ieee80211_vif *vif, 44 | enum nl80211_iftype new_type, 45 | bool p2p); 46 | void xradio_configure_filter(struct ieee80211_hw *dev, 47 | unsigned int changed_flags, 48 | unsigned int *total_flags, 49 | u64 multicast); 50 | int xradio_conf_tx(struct ieee80211_hw *dev, struct ieee80211_vif *vif, 51 | u16 queue, const struct ieee80211_tx_queue_params *params); 52 | int xradio_get_stats(struct ieee80211_hw *dev, 53 | struct ieee80211_low_level_stats *stats); 54 | /* Not more a part of interface? 55 | int xradio_get_tx_stats(struct ieee80211_hw *dev, 56 | struct ieee80211_tx_queue_stats *stats); 57 | */ 58 | int xradio_set_rts_threshold(struct ieee80211_hw *hw, u32 value); 59 | 60 | void xradio_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop); 61 | 62 | 63 | int xradio_remain_on_channel(struct ieee80211_hw *hw, 64 | struct ieee80211_vif *vif, 65 | struct ieee80211_channel *chan, 66 | int duration, enum ieee80211_roc_type type); 67 | int xradio_cancel_remain_on_channel(struct ieee80211_hw *hw); 68 | int xradio_set_arpreply(struct ieee80211_hw *hw, struct ieee80211_vif *vif); 69 | u64 xradio_prepare_multicast(struct ieee80211_hw *hw, 70 | struct netdev_hw_addr_list *mc_list); 71 | int xradio_set_pm(struct xradio_vif *priv, const struct wsm_set_pm *arg); 72 | void xradio_set_data_filter(struct ieee80211_hw *hw, 73 | struct ieee80211_vif *vif, 74 | void *data, 75 | int len); 76 | 77 | /* ******************************************************************** */ 78 | /* WSM callbacks */ 79 | 80 | /* void xradio_set_pm_complete_cb(struct xradio_common *hw_priv, 81 | struct wsm_set_pm_complete *arg); */ 82 | void xradio_channel_switch_cb(struct xradio_common *hw_priv); 83 | 84 | /* ******************************************************************** */ 85 | /* WSM events */ 86 | 87 | void xradio_free_event_queue(struct xradio_common *hw_priv); 88 | void xradio_event_handler(struct work_struct *work); 89 | void xradio_bss_loss_work(struct work_struct *work); 90 | void xradio_connection_loss_work(struct work_struct *work); 91 | void xradio_keep_alive_work(struct work_struct *work); 92 | void xradio_tx_failure_work(struct work_struct *work); 93 | 94 | /* ******************************************************************** */ 95 | /* Internal API */ 96 | 97 | int xradio_setup_mac(struct xradio_common *hw_priv); 98 | void xradio_join_work(struct work_struct *work); 99 | void xradio_join_timeout(struct work_struct *work); 100 | void xradio_unjoin_work(struct work_struct *work); 101 | void xradio_offchannel_work(struct work_struct *work); 102 | void xradio_wep_key_work(struct work_struct *work); 103 | void xradio_update_filtering(struct xradio_vif *priv); 104 | void xradio_update_filtering_work(struct work_struct *work); 105 | int __xradio_flush(struct xradio_common *hw_priv, bool drop, int if_id); 106 | void xradio_set_beacon_wakeup_period_work(struct work_struct *work); 107 | int xradio_enable_listening(struct xradio_vif *priv, struct ieee80211_channel *chan); 108 | int xradio_disable_listening(struct xradio_vif *priv); 109 | int xradio_set_uapsd_param(struct xradio_vif *priv, const struct wsm_edca_params *arg); 110 | void xradio_ba_work(struct work_struct *work); 111 | void xradio_ba_timer(unsigned long arg); 112 | const u8 *xradio_get_ie(u8 *start, size_t len, u8 ie); 113 | int xradio_vif_setup(struct xradio_vif *priv); 114 | int xradio_setup_mac_pvif(struct xradio_vif *priv); 115 | void xradio_iterate_vifs(void *data, u8 *mac, struct ieee80211_vif *vif); 116 | void xradio_rem_chan_timeout(struct work_struct *work); 117 | int xradio_set_macaddrfilter(struct xradio_common *hw_priv, struct xradio_vif *priv, u8 *data); 118 | #ifdef ROAM_OFFLOAD 119 | int xradio_testmode_event(struct wiphy *wiphy, const u32 msg_id, 120 | const void *data, int len, gfp_t gfp); 121 | #endif /*ROAM_OFFLOAD*/ 122 | #endif 123 | -------------------------------------------------------------------------------- /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 defined; /* TODO: u32 or u8, profile and select best */ 31 | u8 usage_count; /* --// -- */ 32 | u8 retry_count; /* --// -- */ 33 | u8 uploaded; 34 | }; 35 | 36 | struct tx_policy_cache_entry { 37 | struct tx_policy policy; 38 | struct list_head link; 39 | }; 40 | 41 | #define TX_POLICY_CACHE_SIZE (8) 42 | struct tx_policy_cache { 43 | struct tx_policy_cache_entry cache[TX_POLICY_CACHE_SIZE]; 44 | struct list_head used; 45 | struct list_head free; 46 | spinlock_t lock; 47 | }; 48 | 49 | /* ******************************************************************** */ 50 | /* TX policy cache */ 51 | /* Intention of TX policy cache is an overcomplicated WSM API. 52 | * Device does not accept per-PDU tx retry sequence. 53 | * It uses "tx retry policy id" instead, so driver code has to sync 54 | * linux tx retry sequences with a retry policy table in the device. 55 | */ 56 | void tx_policy_init(struct xradio_common *hw_priv); 57 | void tx_policy_upload_work(struct work_struct *work); 58 | 59 | /* ******************************************************************** */ 60 | /* TX implementation */ 61 | 62 | u32 xradio_rate_mask_to_wsm(struct xradio_common *hw_priv, 63 | u32 rates); 64 | void xradio_tx(struct ieee80211_hw *dev, struct ieee80211_tx_control *control, struct sk_buff *skb); 65 | void xradio_skb_dtor(struct xradio_common *hw_priv, 66 | struct sk_buff *skb, 67 | const struct xradio_txpriv *txpriv); 68 | 69 | /* ******************************************************************** */ 70 | /* WSM callbacks */ 71 | 72 | void xradio_tx_confirm_cb(struct xradio_common *hw_priv, 73 | struct wsm_tx_confirm *arg); 74 | 75 | /* ******************************************************************** */ 76 | /* Timeout */ 77 | 78 | void xradio_tx_timeout(struct work_struct *work); 79 | 80 | /* ******************************************************************** */ 81 | /* Workaround for WFD test case 6.1.10 */ 82 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 83 | void xradio_link_id_reset(struct work_struct *work); 84 | #endif 85 | 86 | #endif /* XRADIO_TXRX_H */ 87 | -------------------------------------------------------------------------------- /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 | 22 | //Macroses for Driver parameters. 23 | #define XRWL_MAX_QUEUE_SZ (128) 24 | #define AC_QUEUE_NUM 4 25 | 26 | #define XRWL_MAX_VIFS (2) 27 | #define XRWL_GENERIC_IF_ID (2) 28 | #define XRWL_HOST_VIF0_11N_THROTTLE (58) //(XRWL_MAX_QUEUE_SZ/(XRWL_MAX_VIFS-1))*0.9 29 | #define XRWL_HOST_VIF1_11N_THROTTLE (58) //(XRWL_MAX_QUEUE_SZ/(XRWL_MAX_VIFS-1))*0.9 30 | #define XRWL_HOST_VIF0_11BG_THROTTLE (35) //XRWL_HOST_VIF0_11N_THROTTLE*0.6 = 35 31 | #define XRWL_HOST_VIF1_11BG_THROTTLE (35) //XRWL_HOST_VIF0_11N_THROTTLE*0.6 = 35 32 | #if 0 33 | #define XRWL_FW_VIF0_THROTTLE (15) 34 | #define XRWL_FW_VIF1_THROTTLE (15) 35 | #endif 36 | 37 | #define IEEE80211_FCTL_WEP 0x4000 38 | #define IEEE80211_QOS_DATAGRP 0x0080 39 | #define WSM_KEY_MAX_IDX 20 40 | 41 | #include "queue.h" 42 | #include "wsm.h" 43 | #include "scan.h" 44 | #include "tx.h" 45 | #include "ht.h" 46 | #include "pm.h" 47 | #include "fwio.h" 48 | 49 | /* #define ROC_DEBUG */ 50 | /* hidden ssid is only supported when separate probe resp IE 51 | configuration is supported */ 52 | #ifdef PROBE_RESP_EXTRA_IE 53 | #define HIDDEN_SSID 1 54 | #endif 55 | 56 | #define XRADIO_MAX_CTRL_FRAME_LEN (0x1000) 57 | 58 | #define MAX_STA_IN_AP_MODE (14) 59 | #define WLAN_LINK_ID_MAX (MAX_STA_IN_AP_MODE + 3) 60 | 61 | #define XRADIO_MAX_STA_IN_AP_MODE (5) 62 | #define XRADIO_MAX_REQUEUE_ATTEMPTS (5) 63 | #define XRADIO_LINK_ID_UNMAPPED (15) 64 | #define XRADIO_MAX_TID (8) 65 | 66 | #define XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID (0x3F) 67 | #define XRADIO_RX_BLOCK_ACK_ENABLED_FOR_ALL_TID (0x3F) 68 | #define XRADIO_RX_BLOCK_ACK_ENABLED_FOR_BE_TID \ 69 | (XRADIO_TX_BLOCK_ACK_ENABLED_FOR_ALL_TID & 0x01) 70 | #define XRADIO_TX_BLOCK_ACK_DISABLED_FOR_ALL_TID (0) 71 | #define XRADIO_RX_BLOCK_ACK_DISABLED_FOR_ALL_TID (0) 72 | 73 | #define XRADIO_BLOCK_ACK_CNT (30) 74 | #define XRADIO_BLOCK_ACK_THLD (800) 75 | #define XRADIO_BLOCK_ACK_HIST (3) 76 | #define XRADIO_BLOCK_ACK_INTERVAL (1 * HZ / XRADIO_BLOCK_ACK_HIST) 77 | #define XRWL_ALL_IFS (-1) 78 | 79 | #ifdef ROAM_OFFLOAD 80 | #define XRADIO_SCAN_TYPE_ACTIVE 0x1000 81 | #define XRADIO_SCAN_BAND_5G 0x2000 82 | #endif /*ROAM_OFFLOAD*/ 83 | 84 | #define IEEE80211_FCTL_WEP 0x4000 85 | #define IEEE80211_QOS_DATAGRP 0x0080 86 | 87 | #ifdef MCAST_FWDING 88 | #define WSM_MAX_BUF 30 89 | #endif 90 | 91 | #define MAX_RATES_STAGE 8 // 92 | #define MAX_RATES_RETRY 15 93 | 94 | #define XRADIO_WORKQUEUE "xradio_wq" 95 | #define WIFI_CONF_PATH "/data/xr_wifi.conf" 96 | 97 | /* extern */ struct task_struct; 98 | /* extern */ struct xradio_debug_priv; 99 | /* extern */ struct xradio_debug_common; 100 | /* extern */ struct firmware; 101 | 102 | /* Please keep order */ 103 | enum xradio_join_status { 104 | XRADIO_JOIN_STATUS_PASSIVE = 0, 105 | XRADIO_JOIN_STATUS_MONITOR, 106 | XRADIO_JOIN_STATUS_STA, 107 | XRADIO_JOIN_STATUS_AP, 108 | }; 109 | 110 | enum xradio_link_status { 111 | XRADIO_LINK_OFF, 112 | XRADIO_LINK_RESERVE, 113 | XRADIO_LINK_SOFT, 114 | XRADIO_LINK_HARD, 115 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 116 | XRADIO_LINK_RESET, 117 | XRADIO_LINK_RESET_REMAP, 118 | #endif 119 | }; 120 | 121 | enum xradio_bss_loss_status { 122 | XRADIO_BSS_LOSS_NONE, 123 | XRADIO_BSS_LOSS_CHECKING, 124 | XRADIO_BSS_LOSS_CONFIRMING, 125 | XRADIO_BSS_LOSS_CONFIRMED, 126 | }; 127 | 128 | struct xradio_link_entry { 129 | unsigned long timestamp; 130 | enum xradio_link_status status; 131 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 132 | enum xradio_link_status prev_status; 133 | #endif 134 | u8 mac[ETH_ALEN]; 135 | u8 buffered[XRADIO_MAX_TID]; 136 | struct sk_buff_head rx_queue; 137 | }; 138 | 139 | #if defined(ROAM_OFFLOAD) 140 | struct xradio_testframe { 141 | u8 len; 142 | u8 *data; 143 | }; 144 | #endif 145 | 146 | struct xradio_common { 147 | struct xradio_debug_common *debug; 148 | struct xradio_queue tx_queue[AC_QUEUE_NUM]; 149 | struct xradio_queue_stats tx_queue_stats; 150 | 151 | struct ieee80211_hw *hw; 152 | struct mac_address addresses[XRWL_MAX_VIFS]; 153 | 154 | /*Will be a pointer to a list of VIFs - Dynamically allocated */ 155 | struct ieee80211_vif *vif_list[XRWL_MAX_VIFS]; 156 | atomic_t num_vifs; 157 | spinlock_t vif_list_lock; 158 | u32 if_id_slot; 159 | struct device *pdev; 160 | struct workqueue_struct *workqueue; 161 | 162 | struct mutex conf_mutex; 163 | 164 | struct sdio_func *sdio_func; 165 | int driver_ready; 166 | 167 | /* HW/FW type (HIF_...) */ 168 | int hw_type; 169 | int hw_revision; 170 | int fw_revision; 171 | 172 | /* firmware/hardware info */ 173 | unsigned int tx_hdr_len; 174 | 175 | /* Radio data */ 176 | int output_power; 177 | int noise; 178 | 179 | /* calibration, output power limit and rssi<->dBm conversation data */ 180 | 181 | /* BBP/MAC state */ 182 | const struct firmware *sdd; 183 | struct ieee80211_rate *rates; 184 | struct ieee80211_rate *mcs_rates; 185 | u8 mac_addr[ETH_ALEN]; 186 | /*TODO:COMBO: To be made per VIFF after mac80211 support */ 187 | struct ieee80211_channel *channel; 188 | int channel_switch_in_progress; 189 | wait_queue_head_t channel_switch_done; 190 | u8 channel_changed; //add by yangfh 2015-5-15 16:57:38. 191 | u8 long_frame_max_tx_count; 192 | u8 short_frame_max_tx_count; 193 | /* TODO:COMBO: According to Hong aggregation will happen per VIFF. 194 | * Keeping in common structure for the time being. Will be moved to VIFF 195 | * after the mechanism is clear */ 196 | u8 ba_tid_mask; 197 | int ba_acc; /*TODO: Same as above */ 198 | int ba_cnt; /*TODO: Same as above */ 199 | int ba_cnt_rx; /*TODO: Same as above */ 200 | int ba_acc_rx; /*TODO: Same as above */ 201 | int ba_hist; /*TODO: Same as above */ 202 | struct timer_list ba_timer;/*TODO: Same as above */ 203 | spinlock_t ba_lock; /*TODO: Same as above */ 204 | bool ba_ena; /*TODO: Same as above */ 205 | struct work_struct ba_work; /*TODO: Same as above */ 206 | struct xradio_pm_state pm_state; 207 | bool is_BT_Present; 208 | bool is_go_thru_go_neg; 209 | u8 conf_listen_interval; 210 | 211 | /* BH */ 212 | atomic_t bh_tx; 213 | atomic_t bh_term; 214 | atomic_t bh_suspend; 215 | struct task_struct *bh_thread; 216 | int bh_error; 217 | wait_queue_head_t bh_wq; 218 | wait_queue_head_t bh_evt_wq; 219 | 220 | 221 | int buf_id_tx; /* byte */ 222 | int buf_id_rx; /* byte */ 223 | int wsm_rx_seq; /* byte */ 224 | int wsm_tx_seq; /* byte */ 225 | int hw_bufs_used; 226 | int hw_bufs_used_vif[XRWL_MAX_VIFS]; 227 | struct sk_buff *skb_cache; 228 | struct sk_buff *skb_reserved; 229 | int skb_resv_len; 230 | bool powersave_enabled; 231 | bool device_can_sleep; 232 | /* Keep xradio awake (WUP = 1) 1 second after each scan to avoid 233 | * FW issue with sleeping/waking up. */ 234 | atomic_t recent_scan; 235 | long connet_time[XRWL_MAX_VIFS]; 236 | #ifdef CONFIG_XRADIO_SUSPEND_POWER_OFF 237 | atomic_t suspend_state; 238 | #endif 239 | 240 | /* WSM */ 241 | struct wsm_caps wsm_caps; 242 | struct mutex wsm_cmd_mux; 243 | struct wsm_buf wsm_cmd_buf; 244 | struct wsm_cmd wsm_cmd; 245 | wait_queue_head_t wsm_cmd_wq; 246 | wait_queue_head_t wsm_startup_done; 247 | struct semaphore tx_lock_sem; 248 | atomic_t tx_lock; 249 | u32 pending_frame_id; 250 | 251 | /* WSM debug */ 252 | u32 query_packetID; 253 | atomic_t query_cnt; 254 | struct work_struct query_work; /* for query packet */ 255 | 256 | /* Scan status */ 257 | struct xradio_scan scan; 258 | 259 | /* TX/RX */ 260 | unsigned long rx_timestamp; 261 | 262 | /* WSM events */ 263 | spinlock_t event_queue_lock; 264 | struct list_head event_queue; 265 | struct work_struct event_handler; 266 | 267 | /* TX rate policy cache */ 268 | struct tx_policy_cache tx_policy_cache; 269 | struct work_struct tx_policy_upload_work; 270 | atomic_t upload_count; 271 | 272 | /* cryptographic engine information */ 273 | 274 | /* bit field of glowing LEDs */ 275 | u16 softled_state; 276 | 277 | /* statistics */ 278 | struct ieee80211_low_level_stats stats; 279 | 280 | struct xradio_ht_oper ht_oper; 281 | int tx_burst_idx; 282 | 283 | struct ieee80211_iface_limit if_limits1[2]; 284 | struct ieee80211_iface_limit if_limits2[2]; 285 | struct ieee80211_iface_limit if_limits3[2]; 286 | struct ieee80211_iface_combination if_combs[3]; 287 | 288 | struct mutex wsm_oper_lock; 289 | struct delayed_work rem_chan_timeout; 290 | atomic_t remain_on_channel; 291 | int roc_if_id; 292 | u64 roc_cookie; 293 | wait_queue_head_t offchannel_wq; 294 | u16 offchannel_done; 295 | u16 prev_channel; 296 | int if_id_selected; 297 | u32 key_map; 298 | struct wsm_add_key keys[WSM_KEY_MAX_INDEX + 1]; 299 | #ifdef MCAST_FWDING 300 | struct wsm_buf wsm_release_buf[WSM_MAX_BUF]; 301 | u8 buf_released; 302 | #endif 303 | #ifdef ROAM_OFFLOAD 304 | u8 auto_scanning; 305 | u8 frame_rcvd; 306 | u8 num_scanchannels; 307 | u8 num_2g_channels; 308 | u8 num_5g_channels; 309 | struct wsm_scan_ch scan_channels[48]; 310 | struct sk_buff *beacon; 311 | struct sk_buff *beacon_bkp; 312 | struct xradio_testframe testframe; 313 | #endif /*ROAM_OFFLOAD*/ 314 | 315 | u8 connected_sta_cnt; 316 | u16 vif0_throttle; 317 | u16 vif1_throttle; 318 | }; 319 | 320 | /* Virtual Interface State. One copy per VIF */ 321 | struct xradio_vif { 322 | atomic_t enabled; 323 | spinlock_t vif_lock; 324 | int if_id; 325 | /*TODO: Split into Common and VIF parts */ 326 | struct xradio_debug_priv *debug; 327 | /* BBP/MAC state */ 328 | u8 bssid[ETH_ALEN]; 329 | struct wsm_edca_params edca; 330 | struct wsm_tx_queue_params tx_queue_params; 331 | struct wsm_association_mode association_mode; 332 | struct wsm_set_bss_params bss_params; 333 | struct wsm_set_pm powersave_mode; 334 | struct wsm_set_pm firmware_ps_mode; 335 | int power_set_true; 336 | int user_power_set_true; 337 | u8 user_pm_mode; 338 | int cqm_rssi_thold; 339 | unsigned cqm_rssi_hyst; 340 | unsigned cqm_tx_failure_thold; 341 | unsigned cqm_tx_failure_count; 342 | bool cqm_use_rssi; 343 | int cqm_link_loss_count; 344 | int cqm_beacon_loss_count; 345 | int mode; 346 | bool enable_beacon; 347 | int beacon_int; 348 | size_t ssid_length; 349 | u8 ssid[IEEE80211_MAX_SSID_LEN]; 350 | #ifdef HIDDEN_SSID 351 | bool hidden_ssid; 352 | #endif 353 | bool listening; 354 | struct wsm_rx_filter rx_filter; 355 | struct wsm_beacon_filter_table bf_table; 356 | struct wsm_beacon_filter_control bf_control; 357 | struct wsm_multicast_filter multicast_filter; 358 | bool has_multicast_subscription; 359 | struct wsm_broadcast_addr_filter broadcast_filter; 360 | bool disable_beacon_filter; 361 | struct wsm_arp_ipv4_filter filter4; 362 | struct work_struct update_filtering_work; 363 | struct work_struct set_beacon_wakeup_period_work; 364 | struct xradio_pm_state_vif pm_state_vif; 365 | /*TODO: Add support in mac80211 for psmode info per VIF */ 366 | struct wsm_p2p_ps_modeinfo p2p_ps_modeinfo; 367 | struct wsm_uapsd_info uapsd_info; 368 | bool setbssparams_done; 369 | u32 listen_interval; 370 | u32 erp_info; 371 | bool powersave_enabled; 372 | 373 | /* WSM Join */ 374 | enum xradio_join_status join_status; 375 | u8 join_bssid[ETH_ALEN]; 376 | struct work_struct join_work; 377 | struct delayed_work join_timeout; 378 | struct work_struct unjoin_work; 379 | struct work_struct offchannel_work; 380 | int join_dtim_period; 381 | atomic_t delayed_unjoin; 382 | 383 | /* Security */ 384 | s8 wep_default_key_id; 385 | struct work_struct wep_key_work; 386 | unsigned long rx_timestamp; 387 | u32 cipherType; 388 | 389 | 390 | /* AP powersave */ 391 | u32 link_id_map; 392 | u32 max_sta_ap_mode; 393 | u32 link_id_after_dtim; 394 | u32 link_id_uapsd; 395 | u32 link_id_max; 396 | u32 wsm_key_max_idx; 397 | struct xradio_link_entry link_id_db[MAX_STA_IN_AP_MODE]; 398 | struct work_struct link_id_work; 399 | struct delayed_work link_id_gc_work; 400 | u32 sta_asleep_mask; 401 | u32 pspoll_mask; 402 | bool aid0_bit_set; 403 | spinlock_t ps_state_lock; 404 | bool buffered_multicasts; 405 | bool tx_multicast; 406 | u8 last_tim[8]; //for softap dtim, add by yangfh 407 | struct work_struct set_tim_work; 408 | struct delayed_work set_cts_work; 409 | struct work_struct multicast_start_work; 410 | struct work_struct multicast_stop_work; 411 | struct timer_list mcast_timeout; 412 | 413 | /* CQM Implementation */ 414 | struct delayed_work bss_loss_work; 415 | struct delayed_work connection_loss_work; 416 | struct work_struct tx_failure_work; 417 | int delayed_link_loss; 418 | spinlock_t bss_loss_lock; 419 | int bss_loss_status; 420 | int bss_loss_confirm_id; 421 | 422 | struct ieee80211_vif *vif; 423 | struct xradio_common *hw_priv; 424 | struct ieee80211_hw *hw; 425 | 426 | /* ROC implementation */ 427 | struct delayed_work pending_offchanneltx_work; 428 | #if defined(CONFIG_XRADIO_USE_EXTENSIONS) 429 | /* Workaround for WFD testcase 6.1.10*/ 430 | struct work_struct linkid_reset_work; 431 | u8 action_frame_sa[ETH_ALEN]; 432 | u8 action_linkid; 433 | #endif 434 | bool htcap; 435 | #ifdef AP_HT_CAP_UPDATE 436 | u16 ht_oper; 437 | struct work_struct ht_oper_update_work; 438 | #endif 439 | 440 | #ifdef AP_HT_COMPAT_FIX 441 | u16 ht_compat_cnt; 442 | u16 ht_compat_det; 443 | #endif 444 | }; 445 | struct xradio_sta_priv { 446 | int link_id; 447 | struct xradio_vif *priv; 448 | }; 449 | enum xradio_data_filterid { 450 | IPV4ADDR_FILTER_ID = 0, 451 | }; 452 | 453 | /* Datastructure for LLC-SNAP HDR */ 454 | #define P80211_OUI_LEN 3 455 | struct ieee80211_snap_hdr { 456 | u8 dsap; /* always 0xAA */ 457 | u8 ssap; /* always 0xAA */ 458 | u8 ctrl; /* always 0x03 */ 459 | u8 oui[P80211_OUI_LEN]; /* organizational universal id */ 460 | } __packed; 461 | 462 | 463 | #ifdef TES_P2P_0002_ROC_RESTART 464 | extern s32 TES_P2P_0002_roc_dur; 465 | extern s32 TES_P2P_0002_roc_sec; 466 | extern s32 TES_P2P_0002_roc_usec; 467 | extern u32 TES_P2P_0002_packet_id; 468 | extern u32 TES_P2P_0002_state; 469 | 470 | #define TES_P2P_0002_STATE_IDLE 0x00 471 | #define TES_P2P_0002_STATE_SEND_RESP 0x01 472 | #define TES_P2P_0002_STATE_GET_PKTID 0x02 473 | #endif 474 | 475 | /* debug.h must be here because refer to struct xradio_vif and 476 | struct xradio_common.*/ 477 | #include "debug.h" 478 | 479 | /******************************************************* 480 | interfaces for operations of vif. 481 | ********************************************************/ 482 | static inline 483 | struct xradio_common *xrwl_vifpriv_to_hwpriv(struct xradio_vif *priv) 484 | { 485 | return priv->hw_priv; 486 | } 487 | static inline 488 | struct xradio_vif *xrwl_get_vif_from_ieee80211(struct ieee80211_vif *vif) 489 | { 490 | return (struct xradio_vif *)vif->drv_priv; 491 | } 492 | 493 | static inline 494 | struct xradio_vif *xrwl_hwpriv_to_vifpriv(struct xradio_common *hw_priv, 495 | int if_id) 496 | { 497 | struct xradio_vif *vif; 498 | 499 | if (WARN_ON((-1 == if_id) || (if_id > XRWL_MAX_VIFS))) 500 | return NULL; 501 | /* TODO:COMBO: During scanning frames can be received 502 | * on interface ID 3 */ 503 | spin_lock(&hw_priv->vif_list_lock); 504 | if (!hw_priv->vif_list[if_id]) { 505 | spin_unlock(&hw_priv->vif_list_lock); 506 | return NULL; 507 | } 508 | 509 | vif = xrwl_get_vif_from_ieee80211(hw_priv->vif_list[if_id]); 510 | WARN_ON(!vif); 511 | if (vif) 512 | spin_lock(&vif->vif_lock); 513 | spin_unlock(&hw_priv->vif_list_lock); 514 | return vif; 515 | } 516 | 517 | static inline 518 | struct xradio_vif *__xrwl_hwpriv_to_vifpriv(struct xradio_common *hw_priv, 519 | int if_id) 520 | { 521 | WARN_ON((-1 == if_id) || (if_id > XRWL_MAX_VIFS)); 522 | /* TODO:COMBO: During scanning frames can be received 523 | * on interface ID 3 */ 524 | if (!hw_priv->vif_list[if_id]) { 525 | return NULL; 526 | } 527 | 528 | return xrwl_get_vif_from_ieee80211(hw_priv->vif_list[if_id]); 529 | } 530 | 531 | static inline 532 | struct xradio_vif *xrwl_get_activevif(struct xradio_common *hw_priv) 533 | { 534 | return xrwl_hwpriv_to_vifpriv(hw_priv, ffs(hw_priv->if_id_slot)-1); 535 | } 536 | 537 | static inline bool is_hardware_xradio(struct xradio_common *hw_priv) 538 | { 539 | return (hw_priv->hw_revision == XR819_HW_REV0); 540 | } 541 | 542 | static inline int xrwl_get_nr_hw_ifaces(struct xradio_common *hw_priv) 543 | { 544 | switch(hw_priv->hw_revision) { 545 | case XR819_HW_REV0: 546 | default: 547 | return 1; 548 | } 549 | } 550 | 551 | #define xradio_for_each_vif(_hw_priv, _priv, _i) \ 552 | for( \ 553 | _i = 0; \ 554 | (_i < XRWL_MAX_VIFS) \ 555 | && ((_priv = _hw_priv->vif_list[_i] ? \ 556 | xrwl_get_vif_from_ieee80211(_hw_priv->vif_list[_i]) : NULL),1); \ 557 | _i++ \ 558 | ) 559 | 560 | /******************************************************* 561 | interfaces for operations of queue. 562 | ********************************************************/ 563 | static inline void xradio_tx_queues_lock(struct xradio_common *hw_priv) 564 | { 565 | int i; 566 | for (i = 0; i < 4; ++i) 567 | xradio_queue_lock(&hw_priv->tx_queue[i]); 568 | } 569 | 570 | static inline void xradio_tx_queues_unlock(struct xradio_common *hw_priv) 571 | { 572 | int i; 573 | for (i = 0; i < 4; ++i) 574 | xradio_queue_unlock(&hw_priv->tx_queue[i]); 575 | } 576 | 577 | #endif /* XRADIO_H */ 578 | --------------------------------------------------------------------------------