├── .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 |
--------------------------------------------------------------------------------