diff options
author | thompsa <thompsa@FreeBSD.org> | 2010-05-17 23:51:57 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2010-05-17 23:51:57 +0000 |
commit | 7946a2df95022c225b4f95a86f47af3db7d8a675 (patch) | |
tree | ff640182bfe19121892f3a8457d0fdb15c6ce865 | |
parent | d32505134348031814dc73769109fa056c99e54e (diff) | |
download | FreeBSD-src-7946a2df95022c225b4f95a86f47af3db7d8a675.zip FreeBSD-src-7946a2df95022c225b4f95a86f47af3db7d8a675.tar.gz |
MFC r208019
Sync run(4) driver from author's site.
-rw-r--r-- | sys/contrib/dev/run/rt2870.fw.uu | 309 | ||||
-rw-r--r-- | sys/dev/usb/wlan/if_run.c | 1151 | ||||
-rw-r--r-- | sys/dev/usb/wlan/if_runreg.h | 22 | ||||
-rw-r--r-- | sys/dev/usb/wlan/if_runvar.h | 61 |
4 files changed, 947 insertions, 596 deletions
diff --git a/sys/contrib/dev/run/rt2870.fw.uu b/sys/contrib/dev/run/rt2870.fw.uu index 1c3a0c7..c4d7ae2 100644 --- a/sys/contrib/dev/run/rt2870.fw.uu +++ b/sys/contrib/dev/run/rt2870.fw.uu @@ -1,112 +1,108 @@ -# Copyright (c) 2007, Ralink Technology Corporation +# Copyright (c) 2007, Ralink Technology Corporation # All rights reserved. # -# Redistribution. Redistribution and use in binary form, without -# modification, are permitted provided that the following conditions are +# Redistribution. Redistribution and use in binary form, without +# modification, are permitted provided that the following conditions are # met: -# -# * Redistributions must reproduce the above copyright notice and the -# following disclaimer in the documentation and/or other materials -# provided with the distribution. +# +# * Redistributions must reproduce the above copyright notice and the +# following disclaimer in the documentation and/or other materials +# provided with the distribution. # * Neither the name of Ralink Technology Corporation nor the names of its # suppliers may be used to endorse or promote products derived from this -# software without specific prior written permission. -# * No reverse engineering, decompilation, or disassembly of this software +# software without specific prior written permission. +# * No reverse engineering, decompilation, or disassembly of this software # is permitted. -# -# Limited patent license. Ralink Technology Corporation grants a world-wide, -# royalty-free, non-exclusive license under patents it now or hereafter -# owns or controls to make, have made, use, import, offer to sell and -# sell ("Utilize") this software, but solely to the extent that any -# such patent is necessary to Utilize the software alone, or in -# combination with an operating system licensed under an approved Open -# Source license as listed by the Open Source Initiative at -# http://opensource.org/licenses. The patent license shall not apply to -# any other combinations which include this software. No hardware per +# +# Limited patent license. Ralink Technology Corporation grants a world-wide, +# royalty-free, non-exclusive license under patents it now or hereafter +# owns or controls to make, have made, use, import, offer to sell and +# sell ("Utilize") this software, but solely to the extent that any +# such patent is necessary to Utilize the software alone, or in +# combination with an operating system licensed under an approved Open +# Source license as listed by the Open Source Initiative at +# http://opensource.org/licenses. The patent license shall not apply to +# any other combinations which include this software. No hardware per # se is licensed hereunder. -# -# DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, -# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +# +# DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH # DAMAGE. -begin 644 rt2870.fw -M____`A`H`A`R`A!X`A)G`A)H`A*'`A*,$A*((@(620(7'P(3=P(2C3`%!B`- -M`Q(7P2*0`8S@,.,;Y4PPX`1_0(`"?P"0$"_O\)`!C'0(\.20`:?PD`&,X##@ -M')`!@."T`A6CX+0!$)`!A."T@0F0`8QT`?`2#<@BD`04X"#G`P(29I!P$N#U -M5I`$!.`2"IT0MS$0X%`1!%$1#5(1#5,1#5013E41?G`1J7$1UW(2'7,2/H`` -M`!)F(`(#,`,=?0*O5A(+D9`$%'2`\.20<!/PY5;T<`,"$F8"$E^%5D'2`B*0 -M<!#@5']D`F`#`A)FD'`1X&0(8`C@9"!@`P(29G5.`W5/("*0<!'@)/^21R*0 -M!`3@)>`D7?57D'`0X/]T1R57^,;OQI!P$>#_=$@E5_C&[\;D_:]6$@N1D`04 -M=(#PY)!P$_#E5O1P`P(29@(27^5'9`=@"^5'9`A@!>5'M`D(D'`1X%0/]3KE -M1[0)".4ZM`,#Y/5&Y/VO5A(+D=($(I!P$.#^D'`1X/WM^.;U5_VO5A(+D9`$ -M%'2`\.20<!/PY5;T<`,"$F8"$E^0<!#@_I!P$>#][?6"CH/@]5?]KU82"Y&0 -M!!1T@/#DD'`3\.56]'`#`A)F`A)?D!`"X+1P'J/@M#`9D`4(X$0!\/V0!07@ -M5/OP1`3P[53^D`4(\.3U3O5/=3K_K5>O5A(+D9`$%'2`\.20<!/PY5;T8$N` -M0I!P$.`D_Y*3Y/VO5A(+D9`$%'2`\.20<!/PY5;T8"J`(9!P$.`D_Y)*T@6M -M5Z]6$@N1D`04=(#PY)!P$_#E5O1@!Y!P)>!$`?`B(N53<!HP8`FR33!-!`5& -MP@3E3T5.8`CE3Q5/<`(53B(BPD+3(B+"2\),Y402"IT2KP`30@03/@@3&1`2 -MPR`2XV`2]*```!-$A4A#A4I"A4Q>Y4=D!F`#`A-$@!OE2,14#_5#Y4K$5`_U -M0N5,Q%0/]5[E1V0&<&930P^`885)0X5+0H5-7N5'9`9P4H`;Y4G$5`_U0^5+ -MQ%0/]4+E3<14#_5>Y4=D!G`UY4-4#T00]4.`*^5'M`0&4U[[=4()Y4>T!09# -M7@1U0@GE1[0&$.5#5`]$,/5#@`;22X`"TDSD]27E0L14\/_E0U0/3_5?D'!$ -M\*/E7O"CY4KPH^5(\*/E3/"CY43PH^5"\*/E0_#28"+E1V`0),!P`Q(6*1(3 -MC,*OP@32KR+"KY`$%.!4#F`$TAB`".5.14\D_Y(8TJ^0!!3@HN22&70>\.5? -M5`_U+>4E<!,P&`7E7R#E"S`9&>5?5##_OS`1Y25P!74E#(`"%272;-)M@`_E -M7S#F!L)LTFV`!-)LPFWE1V0#<"$P2P;";-)M@!CE)7`#,$P1PDSE)7`%=24' -M@`(5)=)LTFWE1[0)%.5$(.,+Y3ID`F`%Y3JT`P3";-)MD'!&Y2WP(&D'Y5X@ -MX`*R:"!K!^5>(.$"LFH@;0?E7B#B`K)LD'!'Y2WP=2Y`(&D$HFB`)C!H!N5& -MHN*`'>5>(.($?P&``G\`Y494\/Z^\`1^`8`"?@#N;R3_DG.2<B!K!*)J@"8P -M:@;E1J+B@!WE7B#@!'\!@`)_`.5&5/#^OO`$?@&``GX`[F\D_Y)UDG0@;02B -M;(`F,&P&Y4:BXH`=Y5X@X01_`8`"?P#E1E3P_K[P!'X!@`)^`.YO)/^2<9)P -MD!``X)`0+_"0$`/@PY0P0!2B<9)WHG"2=N4N$Q-4/_4NPG?2=I`0+^4N\.5' -M9`9P3)`"*>!4_O#E0\14#Q1@%"3^8",D`V`#`A88D`(HX#!'#X`'D`(HX"!' -M!E3^\`(6&$0!\`(6&.5&,.($?P&``G\`D`(HX%3^3_`"%ACE1V0'8`_E1V0( -M8`GE1V0)8`,"%ACD]2>0`BG@5/SPY3H48"T48"X48#8D_&!?)/E@'R0.<&GE -M1A,35#]U\`.$K_`@1P1^`8`"?@#O;B3_@$6B1X!!Y48PX@/3@"?#@"3E1C#B -M#50XPY0P4`9^`'\!@`1^`'\`($<$?0&``GT`[VU.)/^2.*)'LY(Y@!GE1C#B -M`].``<.2.:)'LY(X@`>B1[.2.)(YD`(HX%3\12?PD'"<Y3KPH^5'\)!P0>4Z -M\"+DD`(I\#!'!*]%@`3E1?3_D`(H[_`BCU#262*/5-)8(N3U8L*OY5$48$84 -M8&(D`F`#`A<#TEEU50&0`J+@5'_PH^`@YR*0!#3@M`(;H^"T`A:CX+0"$7\@ -M$A8_D!`$X%3S\'51`8!SY5!P!75B`X!JD!(`X%0#<!%_(!(6/Y`"HN!4O_!U -M40*`4>50<`*`1I`"H^`@YCN0!#?@9")P,Y`!BG1^\)`!EO"0$@1T"O"0$RC@ -M5/#PH^!4\/"CX%3Z\)`$`>!4^?!U8@%U50+D]5&`">50<`5U8@/U4>5B8!7" -M`>3U4<)9K6*O0!(7C>5BM`,"T@/2KR+"KS`!$N20`9;P]5'"6<(!?0*O0!(7 -MC>52%&`)!'!,=5(!=54#D`0!X$0.\)`3*.!$#_"CX$0/\*/@1`7PD!($=`/P -MD`*BX$3`\)`0!.!$#/#D]5+U53`""\("?0&O01(7C8`"P@/DD`&6\-*O(N_T -M8"WD_G04+O6"Y#1P]8/@M/\9=!0N]8+D-'#U@^_P=!PN]8+D-'#U@^WP(@Z^ -M!-4B(B*0<"K@,.%-PJ^0<"C@D!`<\)!P*>"0$!WPD'`JX)`0'O"0$!S@]6*0 -M$![@(.'SD!`<X)!P*/"0$!W@D'`I\)`0'N"0<"KP,$H'D'`DX$0!\,(%TJ\B -M(B(````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` +# +# This file contains two 4KB firmware, first half is RT2870 and last half +# is RT3071. On each 4KB firmware, 3rd last byte is major version number and +# 2nd last byte is minor version number. +# This file comes with +# RT2870 v. 0.17 +# RT3071 v. 0.17 +begin 644 rt2870.fw.uu +M____`A`H`A`R`A!X`A,J`A,K`A-*`A-/$A-+(@(7N0(8\`(42`(3@S`%!B`- +M`Q(9R"*0`8S@,.,;Y4PPX`1_0(`"?P"0$"_O\)`!C'0(\.20`:?PD`&,X##@ +M')`!@."T`A6CX+0!$)`!A."T@0F0`8QT`?`2#<@BD`04X"#G`P(3*9!P$N#U +M5I`$!.`2"IT0V3$0O381`E`1.5$10E(10E,10E01@U41TE82,'`26W$2B7(2 +MX',3`8```!,ID'`1X/4\Y)!P$_"0!!1T@/#E5O1P`P(3*0(3(B`"`S`#'7T" +MKU82"Y&0!!1T@/#DD'`3\.56]'`#`A,I`A,BA59!T@(BD'`0X%1__[\*#9!P +M$>"T"`9U3@%U3X20<!#@5'__OP(2D'`1X&0(8`3@M"`&=4X#=4\@Y/4G(I!P +M$>`D_Y)'(I`$!.`EX"1=]5>0<!#@_W1')5?XQN_&D'`1X/]T2"57^,;OQN3] +MKU82"Y&0!!1T@/#DD'`3\.56]'`#`A,I`A,BY4=D!V`=Y4=D"&`7Y4=D"6`1 +MY4=D"F`+Y4=D"V`%Y4>T#`B0<!'@5`_U.N5'M`D(Y3JT`P/D]4;E1[0*".4Z +MM`$#Y/5&Y/VO5A(+D=($(I!P$>#T_Y!P$.!?_Y!P$>!5)T^0<!CPD'`1X)!P +M&?#D_:]6$@N1,!4$TA2`)I!P&.#U)Y`"*>#_D'`9X/[O7I`"*?`P1P2O)X`$ +MY2?T_Y`"*._PY5;T<`,"$RD"$R*0<!#@_I!P$>#][?CF]5?]KU82"Y&0!!1T +M@/#DD'`3\.56]'`#`A,I`A,BD'`0X/Z0<!'@_>WU@HZ#X/57_:]6$@N1D`04 +M=(#PY)!P$_#E5O1P`P(3*0(3(I`0`.#U5Y`0`N#U6*/@]5GE6+1P'N59M#`9 +MD`4(X$0!\/V0!07@5/OP1`3P[53^D`4(\.3U3O5/=3K_=3S_K5>O5A(+D9`$ +M%'2`\.20<!/PY5;T8$N`0I!P$.`D_Y*3Y/VO5A(+D9`$%'2`\.20<!/PY5;T +M8"J`(9!P$.`D_Y)*T@6M5Z]6$@N1D`04=(#PY)!P$_#E5O1@!Y!P)>!$`?`B +M(N53<!HP8`FR33!-!`5&P@3E3T5.8`CE3Q5/<`(53B(BPD+3(C`4,)!P&>!5 +M)_^0<!C@3_4GD`(IX/^0<!G@_N]>D`(I\#!'!*\G@`3E)_3_D`(H[_#"%"+" +M2\),Y402"IT3I0`4,P04+P@4#Q`3N2`3V6`3ZJ```!0UA4A#A4I"A4Q>Y4=D +M!F`#`A0U@!OE2,14#_5#Y4K$5`_U0N5,Q%0/]5[E1V0&<&%30P^`7(5)0X5+ +M0H5-7N5'9`9P38`;Y4G$5`_U0^5+Q%0/]4+E3<14#_5>Y4=D!G`PY4-4#T00 +M]4.`)N5'9`1@!>5'M`4&0UX$=4()Y4>T!A#E0U0/1##U0X`&TDN``M),Y/4E +MY4+$5/#_Y4-4#T_U7])@(M(5Y4<D]6`+),M@!R1`<`;"%2(2%X02%&K"%<*O +MP@32KR+"KY`$%.!4#F`$TAB`".5.14\D_Y(8TJ^0!!3@HN22&70>\.5?5`_U +M+>4E<!,P&`7E7R#E"S`9&>5?5##_OS`1Y25P!74E#(`"%272;-)M@`_E7S#F +M!L)LTFV`!-)LPFWE1V0#<"$P2P;";-)M@!CE)7`#,$P1PDSE)7`%=24'@`(5 +M)=)LTFWE1[0)%.5$(.,+Y3ID`F`%Y3JT`P3";-)MY4>T"A/E.K0!!L)LTFV` +M".4Z<`32;,)M(&D'Y5X@X`*R:"!K!^5>(.$"LFH@;0?E7B#B`K)L=2Y`(&D$ +MHFB`)C!H!N5&HN*`'>5>(.($?P&``G\`Y494\/Z^\`1^`8`"?@#N;R3_DG.2 +M<B!K!*)J@"8P:@;E1J+B@!WE7B#@!'\!@`)_`.5&5/#^OO`$?@&``GX`[F\D +M_Y)UDG0@;02B;(`FY4=D"G`B,&P&Y4:BXX`7Y3JT`0;E1J+C@#3E1B#D`S#E +M`].``<.`)C!L!N5&HN*`'>5>(.$$?P&``G\`Y494\/Z^\`1^`8`"?@#N;R3_ +MDG&2<)`0`."0$"SPD!`#X,.4,$`4HG&2=Z)PDG;E+A,35#_U+L)WTG:0$"_E +M+O#E1V0&<#F0`BG@5/[PY4/$5`\48`PD_F`,)`-P$\(X@`_2.(`+Y48PX@/3 +M@`'#DC@P1P6O)P(7?N4G]/\"%W[E1V0'8`_E1V0(8`GE1V0)8`,"%OV0`BG@ +M5/SPY3H48"(48"448"TD_&!))/E@%"0.<%#E1A,35#]U\`.$Y?`D_X`ZTCG" +M.(`^Y48PX@/3@!W#@!KE1C#B#50XPY0P4`9^`'\!@`1^`'\`[D\D_Y(XPCF` +M$^5&,.(#TX`!PY(YPCB`!,(XPCDP1P2O)X`$Y2?T_P(7?N5'9`Q@!N5'9`MP +M>I`"*>!4_?#E.A1@(!1@(11@*R3\8$4D^6`2)`YP2N5&$Q-4/W7P`X3E\(`I +MTCF`.N5&,.(#TX`!PY(Y@"WE1C#B#50XPY0P4`9^`'\!@`1^`'\`[D\D_Y(Y +M@`_E1C#B`].``<.2.8`"PCDP1P2O)X`$Y2?T_Y`"*._P(N5'M`L0D`(IX%3K +M\.4G5.M%1?4G(N20`BGP,$<$KT6`!.5%]/^0`BCO\"*/4-)9(H]4TE@BY/5B +MPJ_E411@2!1@9B0"8`,"&-326755`9`"HN!4?_"CX"#G(Y`$-."T`ARCX+0" +M%Z/@M`(2?R`2%Z^0$`3@5//P=5$!`AC4Y5!P!G5B`P(8U)`2`.!4`W`2?R`2 +M%Z^0`J+@5+_P=5$"`AC4Y5!P`P(8SY`"H^`PY@,"&,N0!#?@9")@`P(8RY`! +MBG1^\)`!EO"0$@1T"O#E6+1R%>59M#40Y)`%`/"C=`CPHW0!\'0#\'\!$@TJ +MD!,HX)!P&O"0$RG@D'`;\)`3*.!4\/"CX%3P\.59M#44Y3ST8`:CX%3S@!20 +M$RK@5/OP@!3E//20$RI@".!4\D4\\(`$X%3Z\)`$`>!4_?!U8@%U50+D]5&` +M">50<`5U8@/U4>5B8!7"`>3U4<)9K6*O0!(9E.5BM`,"T@/2KR+"KS`!$N20 +M`9;P]5'"6<(!?0*O0!(9E.52%&`,!&`#`AF1=5(!=54#D`0!X$0.\)!P&N"0 +M$RCPD'`;X)`3*?#E//1@".4\1`&C\(`&D!,J=`7PD!($=`/PY5BT<A;E6;0U +M$9`%`'3B\*-T"/"C=`'P=`/P?P$2#2J0`J+@1,#PD!`$X$0,\.3U4O55,`() +MP@)]`:]!$AF4,`,"P@/DD`&6\-*O(N_T8"WD_G04+O6"Y#1P]8/@M/\9=!0N +M]8+D-'#U@^_P=!PN]8+D-'#U@^WP(@Z^!-4B(B*0<"K@,.%-PJ^0<"C@D!`< +M\)!P*>"0$!WPD'`JX)`0'O"0$!S@]6*0$![@(.'SD!`<X)!P*/"0$!W@D'`I +M\)`0'N"0<"KP,$H'D'`DX$0!\,(%TJ\B(B(````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -128,54 +124,6 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` -M``````````````````````````````````````````````````````````R4 -M/____P(0*`(0,@(0>`(29P(2:`(2AP(2C!(2B"("%DD"%Q\"$W<"$HTP!08@ -M#0,2%\$BD`&,X##C&^5,,.`$?T"``G\`D!`O[_"0`8QT"/#DD`&G\)`!C.`P -MX!R0`8#@M`(5H^"T`1"0`83@M($)D`&,=`'P$@W=(I`$%.`@YP,"$F:0<!+@ -M]5:0!`3@$@JV$+<Q$.!0$011$0U2$0U3$0U4$4Y5$7YP$:EQ$==R$AUS$CZ` -M```29B`"`S`#'7T"KU82"ZJ0!!1T@/#DD'`3\.56]'`#`A)F`A)?A59!T@(B -MD'`0X%1_9`)@`P(29I!P$>!D"&`(X&0@8`,"$F9U3@-U3R`BD'`1X"3_DD<B -MD`0$X"7@)%WU5Y!P$.#_=$<E5_C&[\:0<!'@_W1()5?XQN_&Y/VO5A(+JI`$ -M%'2`\.20<!/PY5;T<`,"$F8"$E_E1V0'8`OE1V0(8`7E1[0)")!P$>!4#_4Z -MY4>T"0CE.K0#`^3U1N3]KU82"ZK2!"*0<!#@_I!P$>#][?CF]5?]KU82"ZJ0 -M!!1T@/#DD'`3\.56]'`#`A)F`A)?D'`0X/Z0<!'@_>WU@HZ#X/57_:]6$@NJ -MD`04=(#PY)!P$_#E5O1P`P(29@(27Y`0`N"T<!ZCX+0P&9`%".!$`?#]D`4% -MX%3[\$0$\.U4_I`%"/#D]4[U3W4Z_ZU7KU82"ZJ0!!1T@/#DD'`3\.56]&!+ -M@$*0<!#@)/^2D^3]KU82"ZJ0!!1T@/#DD'`3\.56]&`J@"&0<!#@)/^22M(% -MK5>O5A(+JI`$%'2`\.20<!/PY5;T8`>0<"7@1`'P(B+E4W`:,&`)LDTP300% -M1L($Y4]%3F`(Y4\53W`"%4XB(L)"TR(BPDO"3.5$$@JV$J\`$T($$SX($QD0 -M$L,@$N-@$O2@```31(5(0X5*0H5,7N5'9`9@`P(31(`;Y4C$5`_U0^5*Q%0/ -M]4+E3,14#_5>Y4=D!G!F4T,/@&&%24.%2T*%35[E1V0&<%*`&^5)Q%0/]4/E -M2\14#_5"Y4W$5`_U7N5'9`9P->5#5`]$$/5#@"OE1[0$!E->^W5"">5'M`4& -M0UX$=4()Y4>T!A#E0U0/1##U0X`&TDN``M),Y/4EY4+$5/#_Y4-4#T_U7Y!P -M1/"CY5[PH^5*\*/E2/"CY4SPH^5$\*/E0O"CY4/PTF`BY4=@$"3`<`,2%BD2 -M$XS"K\($TJ\BPJ^0!!3@5`Y@!-(8@`CE3D5/)/^2&-*OD`04X*+DDAET'O#E -M7U0/]2WE)7`3,!@%Y5\@Y0LP&1GE7U0P_[\P$>4E<`5U)0R``A4ETFS2;8`/ -MY5\PY@;";-)M@`32;,)MY4=D`W`A,$L&PFS2;8`8Y25P`S!,$<),Y25P!74E -M!X`"%272;-)MY4>T"13E1"#C"^4Z9`)@!>4ZM`,$PFS2;9!P1N4M\"!I!^5> -M(.`"LF@@:P?E7B#A`K)J(&T'Y5X@X@*R;)!P1^4M\'4N0"!I!*)H@"8P:`;E -M1J+B@!WE7B#B!'\!@`)_`.5&5/#^OO`$?@&``GX`[F\D_Y)SDG(@:P2B:H`F -M,&H&Y4:BXH`=Y5X@X`1_`8`"?P#E1E3P_K[P!'X!@`)^`.YO)/^2=9)T(&T$ -MHFR`)C!L!N5&HN*`'>5>(.$$?P&``G\`Y494\/Z^\`1^`8`"?@#N;R3_DG&2 -M<)`0`."0$"_PD!`#X,.4,$`4HG&2=Z)PDG;E+A,35#_U+L)WTG:0$"_E+O#E -M1V0&<$R0`BG@5/[PY4/$5`\48!0D_F`C)`-@`P(6&)`"*.`P1P^`!Y`"*.`@ -M1P94_O`"%AA$`?`"%ACE1C#B!'\!@`)_`)`"*.!4_D_P`A88Y4=D!V`/Y4=D -M"&`)Y4=D"6`#`A88Y/4GD`(IX%3\\.4Z%&`M%&`N%&`V)/Q@7R3Y8!\D#G!I -MY483$U0_=?`#A*_P($<$?@&``GX`[VXD_X!%HD>`0>5&,.(#TX`GPX`DY48P -MX@U4.,.4,%`&?@!_`8`$?@!_`"!'!'T!@`)]`.]M3B3_DCBB1[.2.8`9Y48P -MX@/3@`'#DCFB1[.2.(`'HD>SDCB2.9`"*.!4_$4G\)!PG.4Z\*/E1_"0<$'E -M.O`BY)`"*?`P1P2O18`$Y47T_Y`"*._P(H]0TEDBCU326"+D]6+"K^51%&!& -M%&!B)`)@`P(7`])9=54!D`*BX%1_\*/@(.<BD`0TX+0"&Z/@M`(6H^"T`A%_ -M(!(6/Y`0!.!4\_!U40&`<^50<`5U8@.`:I`2`.!4`W`1?R`2%C^0`J+@5+_P -M=5$"@%'E4'`"@$:0`J/@(.8[D`0WX&0B<#.0`8IT?O"0`9;PD!($=`KPD!,H -MX%3P\*/@5/#PH^!4^O"0!`'@5/GP=6(!=54"Y/51@`GE4'`%=6(#]5'E8F`5 -MP@'D]5'"6:UBKT`2%XWE8K0#`M(#TJ\BPJ\P`1+DD`&6\/51PEG"`7T"KT`2 -M%XWE4A1@"01P3'52`755`Y`$`>!$#O"0$RC@1`_PH^!$#_"CX$0%\)`2!'0# -M\)`"HN!$P/"0$`3@1`SPY/52]54P`@O"`GT!KT$2%XV``L(#Y)`!EO#2KR+O -M]&`MY/YT%"[U@N0T</6#X+3_&704+O6"Y#1P]8/O\'0<+O6"Y#1P]8/M\"(. -MO@35(B(BD'`JX##A3<*OD'`HX)`0'/"0<"G@D!`=\)!P*N"0$![PD!`<X/5B -MD!`>X"#A\Y`0'."0<"CPD!`=X)!P*?"0$![@D'`J\#!*!Y!P).!$`?#"!=*O -M(B(B```````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -187,6 +135,65 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` +M`````````````````````````````````````````````````````````!'" +M>O___P(0*`(0,@(0>`(3*@(3*P(32@(33Q(32R("%[D"&/`"%$@"$X,P!08@ +M#0,2&<@BD`&,X##C&^5,,.`$?T"``G\`D!`O[_"0`8QT"/#DD`&G\)`!C.`P +MX!R0`8#@M`(5H^"T`1"0`83@M($)D`&,=`'P$@W=(I`$%.`@YP,"$RF0<!+@ +M]5:0!`3@$@JV$-DQ$+TV$0)0$3E1$4)2$4)3$4)4$8-5$=)6$C!P$EMQ$HER +M$N!S$P&````3*9!P$>#U/.20<!/PD`04=(#PY5;T<`,"$RD"$R(@`@,P`QU] +M`J]6$@NJD`04=(#PY)!P$_#E5O1P`P(3*0(3(H560=("(I!P$.!4?_^_"@V0 +M<!'@M`@&=4X!=4^$D'`0X%1__[\"$I!P$>!D"&`$X+0@!G5.`W5/(.3U)R*0 +M<!'@)/^21R*0!`3@)>`D7?57D'`0X/]T1R57^,;OQI!P$>#_=$@E5_C&[\;D +M_:]6$@NJD`04=(#PY)!P$_#E5O1P`P(3*0(3(N5'9`=@'>5'9`A@%^5'9`E@ +M$>5'9`I@"^5'9`M@!>5'M`P(D'`1X%0/]3KE1[0)".4ZM`,#Y/5&Y4>T"@CE +M.K0!`^3U1N3]KU82"ZK2!"*0<!'@]/^0<!#@7_^0<!'@52=/D'`8\)!P$>"0 +M<!GPY/VO5A(+JC`5!-(4@":0<!C@]2>0`BG@_Y!P&>#^[UZ0`BGP,$<$KR>` +M!.4G]/^0`BCO\.56]'`#`A,I`A,BD'`0X/Z0<!'@_>WXYO57_:]6$@NJD`04 +M=(#PY)!P$_#E5O1P`P(3*0(3(I!P$.#^D'`1X/WM]8*.@^#U5_VO5A(+JI`$ +M%'2`\.20<!/PY5;T<`,"$RD"$R*0$`#@]5>0$`+@]5BCX/59Y5BT<![E6;0P +M&9`%".!$`?#]D`4%X%3[\$0$\.U4_I`%"/#D]4[U3W4Z_W4\_ZU7KU82"ZJ0 +M!!1T@/#DD'`3\.56]&!+@$*0<!#@)/^2D^3]KU82"ZJ0!!1T@/#DD'`3\.56 +M]&`J@"&0<!#@)/^22M(%K5>O5A(+JI`$%'2`\.20<!/PY5;T8`>0<"7@1`'P +M(B+E4W`:,&`)LDTP300%1L($Y4]%3F`(Y4\53W`"%4XB(L)"TR(P%#"0<!G@ +M52?_D'`8X$_U)Y`"*>#_D'`9X/[O7I`"*?`P1P2O)X`$Y2?T_Y`"*._PPA0B +MPDO"3.5$$@JV$Z4`%#,$%"\(%`\0$[D@$]E@$^J@```4-85(0X5*0H5,7N5' +M9`9@`P(4-8`;Y4C$5`_U0^5*Q%0/]4+E3,14#_5>Y4=D!G!A4T,/@%R%24.% +M2T*%35[E1V0&<$V`&^5)Q%0/]4/E2\14#_5"Y4W$5`_U7N5'9`9P,.5#5`]$ +M$/5#@";E1V0$8`7E1[0%!D->!'5"">5'M`80Y4-4#T0P]4.`!M)+@`+23.3U +M)>5"Q%3P_^5#5`]/]5_28"+2%>5')/5@"R3+8`<D0'`&PA4B$A>$$A1JPA7" +MK\($TJ\BPJ^0!!3@5`Y@!-(8@`CE3D5/)/^2&-*OD`04X*+DDAET'O#E7U0/ +M]2WE)7`3,!@%Y5\@Y0LP&1GE7U0P_[\P$>4E<`5U)0R``A4ETFS2;8`/Y5\P +MY@;";-)M@`32;,)MY4=D`W`A,$L&PFS2;8`8Y25P`S!,$<),Y25P!74E!X`" +M%272;-)MY4>T"13E1"#C"^4Z9`)@!>4ZM`,$PFS2;>5'M`H3Y3JT`0;";-)M +M@`CE.G`$TFS";2!I!^5>(.`"LF@@:P?E7B#A`K)J(&T'Y5X@X@*R;'4N0"!I +M!*)H@"8P:`;E1J+B@!WE7B#B!'\!@`)_`.5&5/#^OO`$?@&``GX`[F\D_Y)S +MDG(@:P2B:H`F,&H&Y4:BXH`=Y5X@X`1_`8`"?P#E1E3P_K[P!'X!@`)^`.YO +M)/^2=9)T(&T$HFR`)N5'9`IP(C!L!N5&HN.`%^4ZM`$&Y4:BXX`TY48@Y`,P +MY0/3@`'#@"8P;`;E1J+B@!WE7B#A!'\!@`)_`.5&5/#^OO`$?@&``GX`[F\D +M_Y)QDG"0$`#@D!`L\)`0`^##E#!`%*)QDG>B<))VY2X3$U0_]2["=])VD!`O +MY2[PY4=D!G`YD`(IX%3^\.5#Q%0/%&`,)/Y@#"0#<!/".(`/TCB`"^5&,.(# +MTX`!PY(X,$<%KR<"%W[E)_3_`A=^Y4=D!V`/Y4=D"&`)Y4=D"6`#`A;]D`(I +MX%3\\.4Z%&`B%&`E%&`M)/Q@223Y8!0D#G!0Y483$U0_=?`#A.7P)/^`.M(Y +MPCB`/N5&,.(#TX`=PX`:Y48PX@U4.,.4,%`&?@!_`8`$?@!_`.Y/)/^2.,(Y +M@!/E1C#B`].``<.2.<(X@`3".,(Y,$<$KR>`!.4G]/\"%W[E1V0,8`;E1V0+ +M<'J0`BG@5/WPY3H48"`48"$48"LD_&!%)/E@$B0.<$KE1A,35#]U\`.$Y?"` +M*=(Y@#KE1C#B`].``<.2.8`MY48PX@U4.,.4,%`&?@!_`8`$?@!_`.Y/)/^2 +M.8`/Y48PX@/3@`'#DCF``L(Y,$<$KR>`!.4G]/^0`BCO\"+E1[0+$)`"*>!4 +MZ_#E)U3K147U)R+DD`(I\#!'!*]%@`3E1?3_D`(H[_`BCU#262*/5-)8(N3U +M8L*OY5$48$@48&8D`F`#`AC4TEEU50&0`J+@5'_PH^`@YR.0!#3@M`(<H^"T +M`A>CX+0"$G\@$A>OD!`$X%3S\'51`0(8U.50<`9U8@,"&-20$@#@5`-P$G\@ +M$A>OD`*BX%2_\'51`@(8U.50<`,"&,^0`J/@,.8#`AC+D`0WX&0B8`,"&,N0 +M`8IT?O"0`9;PD!($=`KPY5BT<A7E6;0U$.20!0#PHW0(\*-T`?!T`_!_`1(- +M2)`3*."0<!KPD!,IX)!P&_"0$RC@5/#PH^!4\/#E6;0U%.4\]&`&H^!4\X`4 +MD!,JX%3[\(`4Y3STD!,J8`C@5/)%//"`!.!4^O"0!`'@5/WP=6(!=54"Y/51 +M@`GE4'`%=6(#]5'E8F`5P@'D]5'"6:UBKT`2&93E8K0#`M(#TJ\BPJ\P`1+D +MD`&6\/51PEG"`7T"KT`2&93E4A1@#`1@`P(9D752`755`Y`$`>!$#O"0<!K@ +MD!,H\)!P&^"0$RGPY3ST8`CE/$0!H_"`!I`3*G0%\)`2!'0#\.58M'(6Y5FT +M-1&0!0!TXO"C=`CPHW0!\'0#\'\!$@U(D`*BX$3`\)`0!.!$#/#D]5+U53`" +M"<("?0&O01(9E#`#`L(#Y)`!EO#2KR+O]&`MY/YT%"[U@N0T</6#X+3_&704 +M+O6"Y#1P]8/O\'0<+O6"Y#1P]8/M\"(.O@35(B(BD'`JX##A3<*OD'`HX)`0 +M'/"0<"G@D!`=\)!P*N"0$![PD!`<X/5BD!`>X"#A\Y`0'."0<"CPD!`=X)!P +M*?"0$![@D'`J\#!*!Y!P).!$`?#"!=*O(B(B```````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` @@ -219,7 +226,7 @@ M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````" -"F\`` +M```````````````````````````````````````````````````````````1 +"=X$` ` end diff --git a/sys/dev/usb/wlan/if_run.c b/sys/dev/usb/wlan/if_run.c index 3ab607f..b74b17e 100644 --- a/sys/dev/usb/wlan/if_run.c +++ b/sys/dev/usb/wlan/if_run.c @@ -1,5 +1,3 @@ -/* $FreeBSD$ */ - /*- * Copyright (c) 2008,2010 Damien Bergamini <damien.bergamini@free.fr> * ported to FreeBSD by Akinori Furukoshi <moonlightakkiy@yahoo.ca> @@ -39,7 +37,6 @@ __FBSDID("$FreeBSD$"); #include <sys/module.h> #include <sys/bus.h> #include <sys/endian.h> -#include <sys/systm.h> #include <sys/linker.h> #include <sys/firmware.h> #include <sys/kdb.h> @@ -74,7 +71,7 @@ __FBSDID("$FreeBSD$"); #define USB_DEBUG_VAR run_debug #include <dev/usb/usb_debug.h> -#include "if_runreg.h" /* shared with ral(4) */ +#include "if_runreg.h" #include "if_runvar.h" #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) @@ -93,6 +90,12 @@ SYSCTL_INT(_hw_usb_run, OID_AUTO, debug, CTLFLAG_RW, &run_debug, 0, #define IEEE80211_HAS_ADDR4(wh) \ (((wh)->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) +/* + * Because of LOR in run_key_delete(), use atomic instead. + * '& RUN_CMDQ_MASQ' is to loop cmdq[]. + */ +#define RUN_CMDQ_GET(c) (atomic_fetchadd_32((c), 1) & RUN_CMDQ_MASQ) + static const struct usb_device_id run_devs[] = { { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2770) }, { USB_VP(USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RT2870) }, @@ -312,6 +315,7 @@ static struct ieee80211vap *run_vap_create(struct ieee80211com *, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]); static void run_vap_delete(struct ieee80211vap *); +static void run_cmdq_cb(void *, int); static void run_setup_tx_list(struct run_softc *, struct run_endpoint_queue *); static void run_unsetup_tx_list(struct run_softc *, @@ -342,23 +346,24 @@ static struct ieee80211_node *run_node_alloc(struct ieee80211vap *, static int run_media_change(struct ifnet *); static int run_newstate(struct ieee80211vap *, enum ieee80211_state, int); static int run_wme_update(struct ieee80211com *); -static void run_wme_update_cb(void *, int); +static void run_wme_update_cb(void *); static void run_key_update_begin(struct ieee80211vap *); static void run_key_update_end(struct ieee80211vap *); -static int run_key_set(struct ieee80211vap *, const struct ieee80211_key *, +static void run_key_set_cb(void *); +static int run_key_set(struct ieee80211vap *, struct ieee80211_key *, const uint8_t mac[IEEE80211_ADDR_LEN]); -static int run_key_delete(struct ieee80211vap *, - const struct ieee80211_key *); -static void run_ratectl_start(struct run_softc *, struct ieee80211_node *); +static void run_key_delete_cb(void *); +static int run_key_delete(struct ieee80211vap *, struct ieee80211_key *); static void run_ratectl_to(void *); static void run_ratectl_cb(void *, int); +static void run_drain_fifo(void *); static void run_iter_func(void *, struct ieee80211_node *); +static void run_newassoc_cb(void *); static void run_newassoc(struct ieee80211_node *, int); static void run_rx_frame(struct run_softc *, struct mbuf *, uint32_t); static void run_tx_free(struct run_endpoint_queue *pq, struct run_tx_data *, int); -static void run_set_tx_desc(struct run_softc *, struct run_tx_data *, - uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t); +static void run_set_tx_desc(struct run_softc *, struct run_tx_data *); static int run_tx(struct run_softc *, struct mbuf *, struct ieee80211_node *); static int run_tx_mgt(struct run_softc *, struct mbuf *, @@ -382,11 +387,10 @@ static int run_set_chan(struct run_softc *, struct ieee80211_channel *); static void run_set_channel(struct ieee80211com *); static void run_scan_start(struct ieee80211com *); static void run_scan_end(struct ieee80211com *); -static uint8_t run_rate2mcs(uint8_t); static void run_update_beacon(struct ieee80211vap *, int); -static void run_update_beacon_locked(struct ieee80211vap *, int); +static void run_update_beacon_cb(void *); static void run_updateprot(struct ieee80211com *); -static void run_usb_timeout_cb(void *, int); +static void run_usb_timeout_cb(void *); static void run_reset_livelock(struct run_softc *); static void run_enable_tsf_sync(struct run_softc *); static void run_enable_mrr(struct run_softc *); @@ -396,6 +400,7 @@ static void run_set_leds(struct run_softc *, uint16_t); static void run_set_bssid(struct run_softc *, const uint8_t *); static void run_set_macaddr(struct run_softc *, const uint8_t *); static void run_updateslot(struct ifnet *); +static void run_update_mcast(struct ifnet *); static int8_t run_rssi2dbm(struct run_softc *, uint8_t, uint8_t); static void run_update_promisc_locked(struct ifnet *); static void run_update_promisc(struct ifnet *); @@ -411,7 +416,7 @@ static void run_stop(void *); static void run_delay(struct run_softc *, unsigned int); static const struct { - uint32_t reg; + uint16_t reg; uint32_t val; } rt2870_def_mac[] = { RT2870_DEF_MAC @@ -551,6 +556,7 @@ run_attach(device_t self) MTX_NETWORK_LOCK, MTX_DEF); iface_index = RT2860_IFACE_INDEX; + error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer, run_config, RUN_N_XFER, sc, &sc->sc_mtx); if (error) { @@ -616,15 +622,15 @@ run_attach(device_t self) ic->ic_ifp = ifp; ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ -#if 0 - ic->ic_state = IEEE80211_S_INIT; -#endif + /* set device capabilities */ ic->ic_caps = IEEE80211_C_STA | /* station mode supported */ IEEE80211_C_MONITOR | /* monitor mode supported */ IEEE80211_C_IBSS | IEEE80211_C_HOSTAP | + IEEE80211_C_WDS | /* 4-address traffic works */ + IEEE80211_C_MBSS | IEEE80211_C_SHPREAMBLE | /* short preamble supported */ IEEE80211_C_SHSLOT | /* short slot time supported */ IEEE80211_C_WME | /* WME */ @@ -671,6 +677,7 @@ run_attach(device_t self) ic->ic_node_alloc = run_node_alloc; ic->ic_newassoc = run_newassoc; //ic->ic_updateslot = run_updateslot; + ic->ic_update_mcast = run_update_mcast; ic->ic_wme.wme_update = run_wme_update; ic->ic_raw_xmit = run_raw_xmit; ic->ic_update_promisc = run_update_promisc; @@ -684,6 +691,10 @@ run_attach(device_t self) &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), RUN_RX_RADIOTAP_PRESENT); + TASK_INIT(&sc->cmdq_task, 0, run_cmdq_cb, sc); + TASK_INIT(&sc->ratectl_task, 0, run_ratectl_cb, sc); + callout_init((struct callout *)&sc->ratectl_ch, 1); + if (bootverbose) ieee80211_announce(ic); @@ -713,6 +724,10 @@ run_detach(device_t self) if (ifp) { ic = ifp->if_l2com; + /* drain tasks */ + usb_callout_drain(&sc->ratectl_ch); + ieee80211_draintask(ic, &sc->cmdq_task); + ieee80211_draintask(ic, &sc->ratectl_task); ieee80211_ifdetach(ic); if_free(ifp); } @@ -728,41 +743,92 @@ run_vap_create(struct ieee80211com *ic, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct run_softc *sc = ic->ic_ifp->if_softc; + struct ifnet *ifp = ic->ic_ifp; + struct run_softc *sc = ifp->if_softc; struct run_vap *rvp; struct ieee80211vap *vap; + int i; - if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ + if(sc->rvp_cnt >= RUN_VAP_MAX){ + if_printf(ifp, "number of VAPs maxed out\n"); return NULL; - sc->sc_rvp = rvp = (struct run_vap *) malloc(sizeof(struct run_vap), + } + + switch (opmode) { + case IEEE80211_M_STA: + /* enable s/w bmiss handling for sta mode */ + flags |= IEEE80211_CLONE_NOBEACONS; + /* fall though */ + case IEEE80211_M_IBSS: + case IEEE80211_M_MONITOR: + case IEEE80211_M_HOSTAP: + case IEEE80211_M_MBSS: + /* other than WDS vaps, only one at a time */ + if (!TAILQ_EMPTY(&ic->ic_vaps)) + return NULL; + break; + case IEEE80211_M_WDS: + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next){ + if(vap->iv_opmode != IEEE80211_M_HOSTAP) + continue; + /* WDS vap's always share the local mac address. */ + flags &= ~IEEE80211_CLONE_BSSID; + break; + } + if(vap == NULL){ + if_printf(ifp, "wds only supported in ap mode\n"); + return NULL; + } + break; + default: + if_printf(ifp, "unknown opmode %d\n", opmode); + return NULL; + } + + rvp = (struct run_vap *) malloc(sizeof(struct run_vap), M_80211_VAP, M_NOWAIT | M_ZERO); if (rvp == NULL) return NULL; vap = &rvp->vap; - /* enable s/w bmiss handling for sta mode */ - ieee80211_vap_setup(ic, vap, name, unit, opmode, - flags | IEEE80211_CLONE_NOBEACONS, bssid, mac); + ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac); vap->iv_key_update_begin = run_key_update_begin; vap->iv_key_update_end = run_key_update_end; - vap->iv_key_delete = run_key_delete; - vap->iv_key_set = run_key_set; vap->iv_update_beacon = run_update_beacon; + vap->iv_max_aid = RT2870_WCID_MAX; + /* + * To delete the right key from h/w, we need wcid. + * Luckily, there is unused space in ieee80211_key{}, wk_pad, + * and matching wcid will be written into there. So, cast + * some spells to remove 'const' from ieee80211_key{} + */ + vap->iv_key_delete = (void *)run_key_delete; + vap->iv_key_set = (void *)run_key_set; /* override state transition machine */ rvp->newstate = vap->iv_newstate; vap->iv_newstate = run_newstate; - TASK_INIT(&rvp->ratectl_task, 0, run_ratectl_cb, rvp); - TASK_INIT(&sc->wme_task, 0, run_wme_update_cb, ic); - TASK_INIT(&sc->usb_timeout_task, 0, run_usb_timeout_cb, sc); - callout_init((struct callout *)&rvp->ratectl_ch, 1); ieee80211_ratectl_init(vap); ieee80211_ratectl_setinterval(vap, 1000 /* 1 sec */); /* complete setup */ ieee80211_vap_attach(vap, run_media_change, ieee80211_media_status); - ic->ic_opmode = opmode; + + /* make sure id is always unique */ + for(i = 0; i < RUN_VAP_MAX; i++){ + if((sc->rvp_bmap & 1 << i) == 0){ + sc->rvp_bmap |= 1 << i; + rvp->rvp_id = i; + break; + } + } + if(sc->rvp_cnt++ == 0) + ic->ic_opmode = opmode; + + DPRINTF("rvp_id=%d bmap=%x rvp_cnt=%d\n", + rvp->rvp_id, sc->rvp_bmap, sc->rvp_cnt); + return vap; } @@ -773,6 +839,7 @@ run_vap_delete(struct ieee80211vap *vap) struct ifnet *ifp; struct ieee80211com *ic; struct run_softc *sc; + uint8_t rvp_id; if(vap == NULL) return; @@ -783,19 +850,59 @@ run_vap_delete(struct ieee80211vap *vap) sc = ifp->if_softc; RUN_LOCK(sc); - sc->sc_rvp->ratectl_run = RUN_RATECTL_OFF; - RUN_UNLOCK(sc); - /* drain them all */ - usb_callout_drain(&sc->sc_rvp->ratectl_ch); - ieee80211_draintask(ic, &sc->sc_rvp->ratectl_task); - ieee80211_draintask(ic, &sc->wme_task); - ieee80211_draintask(ic, &sc->usb_timeout_task); + rvp_id = rvp->rvp_id; + sc->ratectl_run &= ~(1 << rvp_id); + sc->rvp_bmap &= ~(1 << rvp_id); + run_set_region_4(sc, RT2860_SKEY(rvp_id, 0), 0, 128); + run_set_region_4(sc, RT2860_BCN_BASE(rvp_id), 0, 512); + --sc->rvp_cnt; + + DPRINTF("vap=%p rvp_id=%d bmap=%x rvp_cnt=%d\n", + vap, rvp_id, sc->rvp_bmap, sc->rvp_cnt); + + RUN_UNLOCK(sc); ieee80211_ratectl_deinit(vap); ieee80211_vap_detach(vap); free(rvp, M_80211_VAP); - sc->sc_rvp = NULL; +} + +/* + * There are numbers of functions need to be called in context thread. + * Rather than creating taskqueue event for each of those functions, + * here is all-for-one taskqueue callback function. This function + * gurantees deferred functions are executed in the same order they + * were enqueued. + * '& RUN_CMDQ_MASQ' is to loop cmdq[]. + */ +static void +run_cmdq_cb(void *arg, int pending) +{ + struct run_softc *sc = arg; + uint8_t i; + + /* call cmdq[].func locked */ + RUN_LOCK(sc); + for(i = sc->cmdq_exec; sc->cmdq[i].func && pending; + i = sc->cmdq_exec, pending--){ + DPRINTFN(6, "cmdq_exec=%d pending=%d\n", i, pending); + if(sc->cmdq_run == RUN_CMDQ_GO){ + /* + * If arg0 is NULL, callback func needs more + * than one arg. So, pass ptr to cmdq struct. + */ + if(sc->cmdq[i].arg0) + sc->cmdq[i].func(sc->cmdq[i].arg0); + else + sc->cmdq[i].func(&sc->cmdq[i]); + } + sc->cmdq[i].arg0 = NULL; + sc->cmdq[i].func = NULL; + sc->cmdq_exec++; + sc->cmdq_exec &= RUN_CMDQ_MASQ; + } + RUN_UNLOCK(sc); } static void @@ -1415,6 +1522,7 @@ run_read_eeprom(struct run_softc *sc) DPRINTF("EEPROM RF rev=0x%02x chains=%dT%dR\n", sc->rf_rev, sc->ntxchains, sc->nrxchains); + /* check if RF supports automatic Tx access gain control */ run_srom_read(sc, RT2860_EEPROM_CONFIG, &val); DPRINTF("EEPROM CFG 0x%04x\n", val); /* check if driver should patch the DAC issue */ @@ -1489,10 +1597,10 @@ run_read_eeprom(struct run_softc *sc) for (ridx = 0; ridx < 5; ridx++) { uint32_t reg; - run_srom_read(sc, RT2860_EEPROM_RPWR + ridx, &val); - reg = (uint32_t)val << 16; - run_srom_read(sc, RT2860_EEPROM_RPWR + ridx + 1, &val); - reg |= val; + run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2, &val); + reg = val; + run_srom_read(sc, RT2860_EEPROM_RPWR + ridx * 2 + 1, &val); + reg |= (uint32_t)val << 16; sc->txpow20mhz[ridx] = reg; sc->txpow40mhz_2ghz[ridx] = b4inc(reg, delta_2ghz); @@ -1575,19 +1683,21 @@ run_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN]) static int run_media_change(struct ifnet *ifp) { + struct ieee80211vap *vap = ifp->if_softc; + struct ieee80211com *ic = vap->iv_ic; const struct ieee80211_txparam *tp; - struct run_softc *sc = ifp->if_softc; - struct ieee80211com *ic = sc->sc_ifp->if_l2com; - struct ieee80211vap *vap = &sc->sc_rvp->vap; + struct run_softc *sc = ic->ic_ifp->if_softc; + struct run_node *rn = (void *)vap->iv_bss; uint8_t rate, ridx; int error; RUN_LOCK(sc); error = ieee80211_media_change(ifp); - if (error != ENETRESET) + if (error != ENETRESET){ RUN_UNLOCK(sc); return error; + } tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { @@ -1596,13 +1706,16 @@ run_media_change(struct ifnet *ifp) for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) if (rt2860_rates[ridx].rate == rate) break; - sc->fixed_ridx = ridx; + rn->fix_ridx = ridx; + DPRINTF("rate=%d, fix_ridx=%d\n", rate, rn->fix_ridx); } +#if 0 if ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)){ run_init_locked(sc); } +#endif RUN_UNLOCK(sc); @@ -1618,8 +1731,11 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) struct run_vap *rvp = RUN_VAP(vap); enum ieee80211_state ostate; struct ieee80211_node *ni; + uint32_t sta[3]; uint32_t tmp; - uint8_t wcid; + uint8_t ratectl; + uint8_t restart_ratectl = 0; + uint8_t bid = 1 << rvp->rvp_id; ostate = vap->iv_state; DPRINTF("%s -> %s\n", @@ -1629,8 +1745,9 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) IEEE80211_UNLOCK(ic); RUN_LOCK(sc); - sc->sc_rvp->ratectl_run = RUN_RATECTL_OFF; - usb_callout_stop(&rvp->ratectl_ch); + ratectl = sc->ratectl_run; /* remember current state */ + sc->ratectl_run = RUN_RATECTL_OFF; + usb_callout_stop(&sc->ratectl_ch); if (ostate == IEEE80211_S_RUN) { /* turn link LED off */ @@ -1639,8 +1756,16 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) switch (nstate) { case IEEE80211_S_INIT: - if (ostate == IEEE80211_S_RUN) { - /* abort TSF synchronization */ + restart_ratectl = 1; + + if (ostate != IEEE80211_S_RUN) + break; + + ratectl &= ~bid; + sc->runbmap &= ~bid; + + /* abort TSF synchronization if there is no vap running */ + if(--sc->running == 0){ run_read(sc, RT2860_BCN_TIME_CFG, &tmp); run_write(sc, RT2860_BCN_TIME_CFG, tmp & ~(RT2860_BCN_TX_EN | RT2860_TSF_TIMER_EN | @@ -1648,8 +1773,42 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) } break; + case IEEE80211_S_RUN: ni = vap->iv_bss; + if(!(sc->runbmap & bid)){ + if(sc->running++) + restart_ratectl = 1; + sc->runbmap |= bid; + } + + switch(vap->iv_opmode){ + case IEEE80211_M_HOSTAP: + case IEEE80211_M_MBSS: + sc->ap_running |= bid; + ic->ic_opmode = vap->iv_opmode; + run_update_beacon_cb(vap); + break; + case IEEE80211_M_IBSS: + sc->adhoc_running |= bid; + if(!sc->ap_running) + ic->ic_opmode = vap->iv_opmode; + run_update_beacon_cb(vap); + break; + case IEEE80211_M_STA: + sc->sta_running |= bid; + if(!sc->ap_running && !sc->adhoc_running) + ic->ic_opmode = vap->iv_opmode; + + /* read statistic counters (clear on read) */ + run_read_region_1(sc, RT2860_TX_STA_CNT0, + (uint8_t *)sta, sizeof sta); + + break; + default: + ic->ic_opmode = vap->iv_opmode; + break; + } if (vap->iv_opmode != IEEE80211_M_MONITOR) { run_updateslot(ic->ic_ifp); @@ -1658,31 +1817,17 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) run_set_basicrates(sc); IEEE80211_ADDR_COPY(sc->sc_bssid, ni->ni_bssid); run_set_bssid(sc, ni->ni_bssid); - } - - if (vap->iv_opmode == IEEE80211_M_STA) { - /* add BSS entry to the WCID table */ - wcid = RUN_AID2WCID(ni->ni_associd); - run_write_region_1(sc, RT2860_WCID_ENTRY(wcid), - ni->ni_macaddr, IEEE80211_ADDR_LEN); - } - - if (vap->iv_opmode == IEEE80211_M_HOSTAP || - vap->iv_opmode == IEEE80211_M_IBSS) - run_update_beacon_locked(vap, 0); - - if (vap->iv_opmode != IEEE80211_M_MONITOR) { run_enable_tsf_sync(sc); - } /* else tsf */ - /* enable automatic rate adaptation */ - tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; - if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) - run_ratectl_start(sc, ni); + /* enable automatic rate adaptation */ + tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; + if (tp->ucastrate == IEEE80211_FIXED_RATE_NONE) + ratectl |= bid; + } /* turn link LED on */ run_set_leds(sc, RT2860_LED_RADIO | - (IEEE80211_IS_CHAN_2GHZ(vap->iv_bss->ni_chan) ? + (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? RT2860_LED_LINK_2GHZ : RT2860_LED_LINK_5GHZ)); break; @@ -1691,34 +1836,26 @@ run_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) break; } + /* restart amrr for running VAPs */ + if((sc->ratectl_run = ratectl) && restart_ratectl) + usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); + RUN_UNLOCK(sc); IEEE80211_LOCK(ic); return(rvp->newstate(vap, nstate, arg)); } -/* another taskqueue, so usbd_do_request() can go sleep */ -static int -run_wme_update(struct ieee80211com *ic) -{ - struct run_softc *sc = ic->ic_ifp->if_softc; - - ieee80211_runtask(ic, &sc->wme_task); - - /* return whatever, upper layer desn't care anyway */ - return 0; -} - /* ARGSUSED */ static void -run_wme_update_cb(void *arg, int pending) +run_wme_update_cb(void *arg) { struct ieee80211com *ic = arg; struct run_softc *sc = ic->ic_ifp->if_softc; struct ieee80211_wme_state *wmesp = &ic->ic_wme; int aci, error = 0; - RUN_LOCK(sc); + RUN_LOCK_ASSERT(sc, MA_OWNED); /* update MAC TX configuration registers */ for (aci = 0; aci < WME_NUM_AC; aci++) { @@ -1761,19 +1898,39 @@ err: if(error) DPRINTF("WME update failed\n"); - RUN_UNLOCK(sc); return; } +static int +run_wme_update(struct ieee80211com *ic) +{ + struct run_softc *sc = ic->ic_ifp->if_softc; + + /* sometime called wothout lock */ + if(mtx_owned(&ic->ic_comlock.mtx)){ + uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTF("cmdq_store=%d\n", i); + sc->cmdq[i].func = run_wme_update_cb; + sc->cmdq[i].arg0 = ic; + ieee80211_runtask(ic, &sc->cmdq_task); + return (0); + } + + RUN_LOCK(sc); + run_wme_update_cb(ic); + RUN_UNLOCK(sc); + + /* return whatever, upper layer desn't care anyway */ + return (0); +} + static void run_key_update_begin(struct ieee80211vap *vap) { /* - * Because run_key_delete() needs special attention - * on lock related operation, lock handling is being done - * differently in run_key_set and _delete. - * - * So, we don't use key_update_begin and _end. + * To avoid out-of-order events, both run_key_set() and + * _delete() are deferred and handled by run_cmdq_cb(). + * So, there is nothing we need to do here. */ } @@ -1783,37 +1940,31 @@ run_key_update_end(struct ieee80211vap *vap) /* null */ } -/* - * return 0 on error - */ -static int -run_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, - const uint8_t mac[IEEE80211_ADDR_LEN]) +static void +run_key_set_cb(void *arg) { + struct run_cmdq *cmdq = arg; + struct ieee80211vap *vap = cmdq->arg1; + struct ieee80211_key *k = cmdq->k; struct ieee80211com *ic = vap->iv_ic; - struct ifnet *ifp = ic->ic_ifp; - struct run_softc *sc = ifp->if_softc; + struct run_softc *sc = ic->ic_ifp->if_softc; struct ieee80211_node *ni; uint32_t attr; uint16_t base, associd; uint8_t mode, wcid, txmic, rxmic, iv[8]; - int error = 0; - RUN_LOCK(sc); + RUN_LOCK_ASSERT(sc, MA_OWNED); if(vap->iv_opmode == IEEE80211_M_HOSTAP){ - ni = ieee80211_find_vap_node(&ic->ic_sta, vap, mac); - associd = (ni != NULL) ? ni->ni_associd : 0; - if(ni != NULL) - ieee80211_free_node(ni); + ni = ieee80211_find_vap_node(&ic->ic_sta, vap, cmdq->mac); txmic = 24; rxmic = 16; } else { ni = vap->iv_bss; - associd = (ni != NULL) ? ni->ni_associd : 0; txmic = 16; rxmic = 24; } + associd = (ni != NULL) ? ni->ni_associd : 0; /* map net80211 cipher to RT2860 security mode */ switch (k->wk_cipher->ic_cipher) { @@ -1831,16 +1982,18 @@ run_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, break; default: DPRINTF("undefined case\n"); - goto fail; + return; } - DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s\n", + DPRINTFN(1, "associd=%x, keyix=%d, mode=%x, type=%s, tx=%s, rx=%s\n", associd, k->wk_keyix, mode, - (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise"); + (k->wk_flags & IEEE80211_KEY_GROUP) ? "group" : "pairwise", + (k->wk_flags & IEEE80211_KEY_XMIT) ? "on" : "off", + (k->wk_flags & IEEE80211_KEY_RECV) ? "on" : "off"); if (k->wk_flags & IEEE80211_KEY_GROUP) { wcid = 0; /* NB: update WCID0 for group keys */ - base = RT2860_SKEY(0, k->wk_keyix); + base = RT2860_SKEY(RUN_VAP(vap)->rvp_id, k->wk_keyix); } else { wcid = RUN_AID2WCID(associd); base = RT2860_PKEY(wcid); @@ -1848,15 +2001,15 @@ run_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { if(run_write_region_1(sc, base, k->wk_key, 16)) - goto fail; + return; if(run_write_region_1(sc, base + 16, &k->wk_key[txmic], 8)) /* wk_txmic */ - goto fail; + return; if(run_write_region_1(sc, base + 24, &k->wk_key[rxmic], 8)) /* wk_rxmic */ - goto fail; + return; } else { /* roundup len to 16-bit: XXX fix write_region_1() instead */ if(run_write_region_1(sc, base, k->wk_key, (k->wk_keylen + 1) & ~1)) - goto fail; + return; } if (!(k->wk_flags & IEEE80211_KEY_GROUP) || @@ -1864,7 +2017,7 @@ run_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, /* set initial packet number in IV+EIV */ if (k->wk_cipher == IEEE80211_CIPHER_WEP){ memset(iv, 0, sizeof iv); - iv[3] = sc->sc_rvp->vap.iv_def_txkey << 6; + iv[3] = vap->iv_def_txkey << 6; } else { if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP) { iv[0] = k->wk_keytsc >> 8; @@ -1882,111 +2035,134 @@ run_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k, iv[7] = k->wk_keytsc >> 40; } if(run_write_region_1(sc, RT2860_IVEIV(wcid), iv, 8)) - goto fail; + return; } if (k->wk_flags & IEEE80211_KEY_GROUP) { /* install group key */ if(run_read(sc, RT2860_SKEY_MODE_0_7, &attr)) - goto fail; + return; attr &= ~(0xf << (k->wk_keyix * 4)); attr |= mode << (k->wk_keyix * 4); if(run_write(sc, RT2860_SKEY_MODE_0_7, attr)) - goto fail; + return; } else { /* install pairwise key */ if(run_read(sc, RT2860_WCID_ATTR(wcid), &attr)) - goto fail; + return; attr = (attr & ~0xf) | (mode << 1) | RT2860_RX_PKEY_EN; if(run_write(sc, RT2860_WCID_ATTR(wcid), attr)) - goto fail; + return; } /* TODO create a pass-thru key entry? */ -fail: - RUN_UNLOCK(sc); - return (error? 0 : 1); + /* need wcid to delete the right key later */ + k->wk_pad = wcid; } /* + * Don't have to be deferred, but in order to keep order of + * execution, i.e. with run_key_delete(), defer this and let + * run_cmdq_cb() maintain the order. + * * return 0 on error */ static int -run_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) +run_key_set(struct ieee80211vap *vap, struct ieee80211_key *k, + const uint8_t mac[IEEE80211_ADDR_LEN]) { struct ieee80211com *ic = vap->iv_ic; struct run_softc *sc = ic->ic_ifp->if_softc; - struct ieee80211_node *ni = vap->iv_bss; - struct ieee80211_node_table *nt = &ic->ic_sta; + uint32_t i; + + i = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTF("cmdq_store=%d\n", i); + sc->cmdq[i].func = run_key_set_cb; + sc->cmdq[i].arg0 = NULL; + sc->cmdq[i].arg1 = vap; + sc->cmdq[i].k = k; + IEEE80211_ADDR_COPY(sc->cmdq[i].mac, mac); + ieee80211_runtask(ic, &sc->cmdq_task); + + return(1); +} + +/* + * If wlan is destroyed without being brought down i.e. without + * wlan down or wpa_cli terminate, this function is called after + * vap is gone. Don't refer it. + */ +static void +run_key_delete_cb(void *arg) +{ + struct run_cmdq *cmdq = arg; + struct run_softc *sc = cmdq->arg1; + struct ieee80211_key *k = &cmdq->key; uint32_t attr; uint8_t wcid; - int error = 0; - uint8_t nislocked, cislocked; - if((nislocked = IEEE80211_NODE_IS_LOCKED(nt))) - IEEE80211_NODE_UNLOCK(nt); - if((cislocked = mtx_owned(&ic->ic_comlock.mtx))) - IEEE80211_UNLOCK(ic); - RUN_LOCK(sc); + RUN_LOCK_ASSERT(sc, MA_OWNED); if (k->wk_flags & IEEE80211_KEY_GROUP) { /* remove group key */ - if(run_read(sc, RT2860_SKEY_MODE_0_7, &attr)) - goto fail; + DPRINTF("removing group key\n"); + run_read(sc, RT2860_SKEY_MODE_0_7, &attr); attr &= ~(0xf << (k->wk_keyix * 4)); - if(run_write(sc, RT2860_SKEY_MODE_0_7, attr)) - goto fail; + run_write(sc, RT2860_SKEY_MODE_0_7, attr); } else { /* remove pairwise key */ - wcid = RUN_AID2WCID((ni != NULL) ? ni->ni_associd : 0); - if(run_read(sc, RT2860_WCID_ATTR(wcid), &attr)) - goto fail; + DPRINTF("removing key for wcid %x\n", k->wk_pad); + /* matching wcid was written to wk_pad in run_key_set() */ + wcid = k->wk_pad; + run_read(sc, RT2860_WCID_ATTR(wcid), &attr); attr &= ~0xf; - if(run_write(sc, RT2860_WCID_ATTR(wcid), attr)) - goto fail; + run_write(sc, RT2860_WCID_ATTR(wcid), attr); + run_set_region_4(sc, RT2860_WCID_ENTRY(wcid), 0, 8); } -fail: - RUN_UNLOCK(sc); - if(cislocked) - IEEE80211_LOCK(ic); - if(nislocked) - IEEE80211_NODE_LOCK(nt); - - return (error? 0 : 1); + k->wk_pad = 0; } -static void -run_ratectl_start(struct run_softc *sc, struct ieee80211_node *ni) +/* + * return 0 on error + */ +static int +run_key_delete(struct ieee80211vap *vap, struct ieee80211_key *k) { - struct ieee80211vap *vap = ni->ni_vap; - struct run_vap *rvp = RUN_VAP(vap); - uint32_t sta[3]; - - RUN_LOCK_ASSERT(sc, MA_OWNED); - - /* read statistic counters (clear on read) and update AMRR state */ - run_read_region_1(sc, RT2860_TX_STA_CNT0, - (uint8_t *)sta, sizeof sta); - - ieee80211_ratectl_node_init(ni); + struct ieee80211com *ic = vap->iv_ic; + struct run_softc *sc = ic->ic_ifp->if_softc; + struct ieee80211_key *k0; + uint32_t i; - /* start at lowest available bit-rate, AMRR will raise */ - ni->ni_txrate = 2; + /* + * When called back, key might be gone. So, make a copy + * of some values need to delete keys before deferring. + * But, because of LOR with node lock, cannot use lock here. + * So, use atomic instead. + */ + i = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTF("cmdq_store=%d\n", i); + sc->cmdq[i].func = run_key_delete_cb; + sc->cmdq[i].arg0 = NULL; + sc->cmdq[i].arg1 = sc; + k0 = &sc->cmdq[i].key; + k0->wk_flags = k->wk_flags; + k0->wk_keyix = k->wk_keyix; + /* matching wcid was written to wk_pad in run_key_set() */ + k0->wk_pad = k->wk_pad; + ieee80211_runtask(ic, &sc->cmdq_task); + return (1); /* return fake success */ - /* start calibration timer */ - rvp->ratectl_run = RUN_RATECTL_ON; - usb_callout_reset(&rvp->ratectl_ch, hz, run_ratectl_to, rvp); } static void run_ratectl_to(void *arg) { - struct run_vap *rvp = arg; + struct run_softc *sc = arg; /* do it in a process context, so it can go sleep */ - ieee80211_runtask(rvp->vap.iv_ic, &rvp->ratectl_task); + ieee80211_runtask(sc->sc_ifp->if_l2com, &sc->ratectl_task); /* next timeout will be rescheduled in the callback task */ } @@ -1994,13 +2170,15 @@ run_ratectl_to(void *arg) static void run_ratectl_cb(void *arg, int pending) { - struct run_vap *rvp = arg; - struct ieee80211vap *vap = &rvp->vap; - struct ieee80211com *ic = vap->iv_ic; - struct run_softc *sc = ic->ic_ifp->if_softc; + struct run_softc *sc = arg; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; + struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - if (ic->ic_opmode == IEEE80211_M_STA) - run_iter_func(rvp, vap->iv_bss); + if(vap == NULL) + return; + + if(sc->rvp_cnt <= 1 && vap->iv_opmode == IEEE80211_M_STA) + run_iter_func(sc, vap->iv_bss); else { /* * run_reset_livelock() doesn't do anything with AMRR, @@ -2011,77 +2189,95 @@ run_ratectl_cb(void *arg, int pending) */ RUN_LOCK(sc); run_reset_livelock(sc); + /* just in case, there are some stats to drain */ + run_drain_fifo(sc); RUN_UNLOCK(sc); - ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, rvp); + ieee80211_iterate_nodes(&ic->ic_sta, run_iter_func, sc); } - if(rvp->ratectl_run == RUN_RATECTL_ON) - usb_callout_reset(&rvp->ratectl_ch, hz, run_ratectl_to, rvp); + if(sc->ratectl_run != RUN_RATECTL_OFF) + usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); } - static void -run_iter_func(void *arg, struct ieee80211_node *ni) +run_drain_fifo(void *arg) { - struct run_vap *rvp = arg; - struct ieee80211com *ic = rvp->vap.iv_ic; - struct ifnet *ifp = ic->ic_ifp; - struct run_softc *sc = ifp->if_softc; - struct ieee80211_node_table *nt = &ic->ic_sta; - uint32_t sta[3], stat; - int error; + struct run_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ieee80211_node *ni = sc->sc_ni[0]; /* make compiler happy */ + uint32_t stat; + int retrycnt = 0; uint8_t wcid, mcs, pid; - struct ieee80211vap *vap = ni->ni_vap; - int txcnt = 0, success = 0, retrycnt = 0; - - if(ic->ic_opmode != IEEE80211_M_STA) - IEEE80211_NODE_ITERATE_UNLOCK(nt); - RUN_LOCK(sc); + RUN_LOCK_ASSERT(sc, MA_OWNED); - if(ic->ic_opmode != IEEE80211_M_STA){ + for (;;) { /* drain Tx status FIFO (maxsize = 16) */ run_read(sc, RT2860_TX_STAT_FIFO, &stat); - while (stat & RT2860_TXQ_VLD) { - DPRINTFN(4, "tx stat 0x%08x\n", stat); + DPRINTFN(4, "tx stat 0x%08x\n", stat); + if(!(stat & RT2860_TXQ_VLD)) + break; - wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff; + wcid = (stat >> RT2860_TXQ_WCID_SHIFT) & 0xff; - /* if no ACK was requested, no feedback is available */ - if (!(stat & RT2860_TXQ_ACKREQ) || wcid == 0xff) - continue; + /* if no ACK was requested, no feedback is available */ + if (!(stat & RT2860_TXQ_ACKREQ) || wcid > RT2870_WCID_MAX || + wcid == 0) + continue; - /* update per-STA AMRR stats */ - if (stat & RT2860_TXQ_OK) { - /* - * Check if there were retries, ie if the Tx - * success rate is different from the requested - * rate. Note that it works only because we do - * not allow rate fallback from OFDM to CCK. - */ - mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f; - pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf; - if (mcs + 1 != pid) - retrycnt = 1; - ieee80211_ratectl_tx_complete(vap, ni, - IEEE80211_RATECTL_TX_SUCCESS, - &retrycnt, NULL); - } else { + ni = sc->sc_ni[wcid]; + if(ni->ni_rctls == NULL) + continue; + + /* update per-STA AMRR stats */ + if (stat & RT2860_TXQ_OK) { + /* + * Check if there were retries, ie if the Tx + * success rate is different from the requested + * rate. Note that it works only because we do + * not allow rate fallback from OFDM to CCK. + */ + mcs = (stat >> RT2860_TXQ_MCS_SHIFT) & 0x7f; + pid = (stat >> RT2860_TXQ_PID_SHIFT) & 0xf; + if (mcs + 1 != pid) retrycnt = 1; - ieee80211_ratectl_tx_complete(vap, ni, - IEEE80211_RATECTL_TX_SUCCESS, - &retrycnt, NULL); - ifp->if_oerrors++; - } - run_read_region_1(sc, RT2860_TX_STAT_FIFO, - (uint8_t *)&stat, sizeof stat); + ieee80211_ratectl_tx_complete(ni->ni_vap, ni, + IEEE80211_RATECTL_TX_SUCCESS, + &retrycnt, NULL); + } else { + retrycnt = 1; + ieee80211_ratectl_tx_complete(ni->ni_vap, ni, + IEEE80211_RATECTL_TX_FAILURE, + &retrycnt, NULL); + ifp->if_oerrors++; } - } else { + } + DPRINTFN(3, "count=%d\n", sc->fifo_cnt); + + sc->fifo_cnt = 0; +} + +static void +run_iter_func(void *arg, struct ieee80211_node *ni) +{ + struct run_softc *sc = arg; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = ic->ic_ifp; + struct run_node *rn = (void *)ni; + uint32_t sta[3]; + int txcnt = 0, success = 0, retrycnt = 0; + int error; + + if(sc->rvp_cnt <= 1 && (vap->iv_opmode == IEEE80211_M_IBSS || + vap->iv_opmode == IEEE80211_M_STA)){ + RUN_LOCK(sc); + /* read statistic counters (clear on read) and update AMRR state */ error = run_read_region_1(sc, RT2860_TX_STA_CNT0, (uint8_t *)sta, sizeof sta); if (error != 0) - goto skip; + return; DPRINTFN(3, "retrycnt=%d txcnt=%d failcnt=%d\n", le32toh(sta[1]) >> 16, le32toh(sta[1]) & 0xffff, @@ -2101,17 +2297,29 @@ run_iter_func(void *arg, struct ieee80211_node *ni) success = (le32toh(sta[1]) >> 16) + (le32toh(sta[1]) & 0xffff); + ieee80211_ratectl_tx_update(vap, ni, &txcnt, &success, &retrycnt); + + RUN_UNLOCK(sc); } - ieee80211_ratectl_rate(ni, NULL, 0); + rn->amrr_ridx = ieee80211_ratectl_rate(ni, NULL, 0); + DPRINTFN(3, "ridx=%d\n", rn->amrr_ridx); +} -skip:; - RUN_UNLOCK(sc); +static void +run_newassoc_cb(void *arg) +{ + struct run_cmdq *cmdq = arg; + struct ieee80211_node *ni = cmdq->arg1; + struct run_softc *sc = ni->ni_vap->iv_ic->ic_ifp->if_softc; + uint8_t wcid = cmdq->wcid; - if(ic->ic_opmode != IEEE80211_M_STA) - IEEE80211_NODE_ITERATE_LOCK(nt); + RUN_LOCK_ASSERT(sc, MA_OWNED); + + run_write_region_1(sc, RT2860_WCID_ENTRY(wcid), + ni->ni_macaddr, IEEE80211_ADDR_LEN); } static void @@ -2119,11 +2327,40 @@ run_newassoc(struct ieee80211_node *ni, int isnew) { struct run_node *rn = (void *)ni; struct ieee80211_rateset *rs = &ni->ni_rates; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211com *ic = vap->iv_ic; + struct run_softc *sc = ic->ic_ifp->if_softc; uint8_t rate; - int ridx, i, j; + uint8_t ridx; + uint8_t wcid = RUN_AID2WCID(ni->ni_associd); + int i, j; + + if(wcid > RT2870_WCID_MAX){ + device_printf(sc->sc_dev, "wcid=%d out of range\n", wcid); + return; + } - DPRINTF("new assoc isnew=%d addr=%s\n", - isnew, ether_sprintf(ni->ni_macaddr)); + /* only interested in true associations */ + if (isnew && ni->ni_associd != 0){ + + /* + * This function could is called though timeout function. + * Need to defer. + */ + uint32_t cnt = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTF("cmdq_store=%d\n", cnt); + sc->cmdq[cnt].func = run_newassoc_cb; + sc->cmdq[cnt].arg0 = NULL; + sc->cmdq[cnt].arg1 = ni; + sc->cmdq[cnt].wcid = wcid; + ieee80211_runtask(ic, &sc->cmdq_task); + } + + DPRINTF("new assoc isnew=%d associd=%x addr=%s\n", + isnew, ni->ni_associd, ether_sprintf(ni->ni_macaddr)); + + ieee80211_ratectl_node_init(ni); + sc->sc_ni[wcid] = ni; for (i = 0; i < rs->rs_nrates; i++) { rate = rs->rs_rates[i] & IEEE80211_RATE_VAL; @@ -2148,6 +2385,14 @@ run_newassoc(struct ieee80211_node *ni, int isnew) DPRINTF("rate=0x%02x ridx=%d ctl_ridx=%d\n", rs->rs_rates[i], rn->ridx[i], rn->ctl_ridx[i]); } + rate = vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)].mgmtrate; + for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) + if (rt2860_rates[ridx].rate == rate) + break; + rn->mgt_ridx = ridx; + DPRINTF("rate=%d, mgmt_ridx=%d\n", rate, rn->mgt_ridx); + + usb_callout_reset(&sc->ratectl_ch, hz, run_ratectl_to, sc); } /* @@ -2172,7 +2417,6 @@ static void run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) { struct ifnet *ifp = sc->sc_ifp; - struct ieee80211vap *vap = &sc->sc_rvp->vap; struct ieee80211com *ic = ifp->if_l2com; struct ieee80211_frame *wh; struct ieee80211_node *ni; @@ -2217,9 +2461,13 @@ run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) len += 2; } + ni = ieee80211_find_rxnode(ic, + mtod(m, struct ieee80211_frame_min *)); + if (__predict_false(flags & RT2860_RX_MICERR)) { /* report MIC failures to net80211 for TKIP */ - ieee80211_notify_michael_failure(vap, wh, rxwi->keyidx); + if(ni != NULL) + ieee80211_notify_michael_failure(ni->ni_vap, wh, rxwi->keyidx); m_freem(m); ifp->if_ierrors++; DPRINTF("MIC error. Someone is lying.\n"); @@ -2233,8 +2481,6 @@ run_rx_frame(struct run_softc *sc, struct mbuf *m, uint32_t dmalen) m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = len; - ni = ieee80211_find_rxnode(ic, - mtod(m, struct ieee80211_frame_min *)); if (ni != NULL) { (void)ieee80211_input(ni, m, rssi, nf); ieee80211_free_node(ni); @@ -2431,6 +2677,7 @@ run_bulk_tx_callbackN(struct usb_xfer *xfer, usb_error_t error, unsigned int ind { struct run_softc *sc = usbd_xfer_softc(xfer); struct ifnet *ifp = sc->sc_ifp; + struct ieee80211com *ic = ifp->if_l2com; struct run_tx_data *data; struct ieee80211vap *vap = NULL; struct usb_page_cache *pc; @@ -2486,20 +2733,22 @@ tr_setup: vap = data->ni->ni_vap; if (ieee80211_radiotap_active_vap(vap)) { struct run_tx_radiotap_header *tap = &sc->sc_txtap; + struct rt2860_txwi *txwi = + (struct rt2860_txwi *)(&data->desc + sizeof(struct rt2870_txd)); tap->wt_flags = 0; tap->wt_rate = rt2860_rates[data->ridx].rate; tap->wt_chan_freq = htole16(vap->iv_bss->ni_chan->ic_freq); tap->wt_chan_flags = htole16(vap->iv_bss->ni_chan->ic_flags); tap->wt_hwqueue = index; - if (data->mcs & RT2860_PHY_SHPRE) + if (le16toh(txwi->phy) & RT2860_PHY_SHPRE) tap->wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; ieee80211_radiotap_tx(vap, m); } /* align end on a 4-bytes boundary */ - len = (size + m->m_pkthdr.len + 3) & ~3; + len = (size + IEEE80211_CRC_LEN + m->m_pkthdr.len + 3) & ~3; DPRINTFN(11, "sending frame len=%u xferlen=%u @ index %d\n", m->m_pkthdr.len, len, index); @@ -2524,14 +2773,22 @@ tr_setup: ifp->if_oerrors++; if (data != NULL) { + if(data->ni != NULL) + vap = data->ni->ni_vap; run_tx_free(pq, data, error); usbd_xfer_set_priv(xfer, NULL); } + if(vap == NULL) + vap = TAILQ_FIRST(&ic->ic_vaps); if (error != USB_ERR_CANCELLED) { if (error == USB_ERR_TIMEOUT) { device_printf(sc->sc_dev, "device timeout\n"); - ieee80211_runtask(ifp->if_l2com, &sc->usb_timeout_task); + uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTF("cmdq_store=%d\n", i); + sc->cmdq[i].func = run_usb_timeout_cb; + sc->cmdq[i].arg0 = vap; + ieee80211_runtask(ic, &sc->cmdq_task); } /* @@ -2583,22 +2840,21 @@ run_bulk_tx_callback5(struct usb_xfer *xfer, usb_error_t error) } static void -run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data, - uint8_t wflags, uint8_t xflags, uint8_t opflags, uint8_t dflags, - uint8_t type, uint8_t pad) +run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data) { struct mbuf *m = data->m; struct ieee80211com *ic = sc->sc_ifp->if_l2com; - struct ieee80211vap *vap = &sc->sc_rvp->vap; + struct ieee80211vap *vap = data->ni->ni_vap; struct ieee80211_frame *wh; struct rt2870_txd *txd; struct rt2860_txwi *txwi; - int xferlen; - uint8_t mcs; + uint16_t xferlen; + uint16_t mcs; uint8_t ridx = data->ridx; + uint8_t pad; /* get MCS code from rate index */ - data->mcs = mcs = rt2860_rates[ridx].mcs; + mcs = rt2860_rates[ridx].mcs; xferlen = sizeof(*txwi) + m->m_pkthdr.len; @@ -2606,15 +2862,21 @@ run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data, xferlen = (xferlen + 3) & ~3; txd = (struct rt2870_txd *)&data->desc; - txd->flags = dflags; txd->len = htole16(xferlen); + wh = mtod(m, struct ieee80211_frame *); + + /* + * Ether both are true or both are false, the header + * are nicely aligned to 32-bit. So, no L2 padding. + */ + if(IEEE80211_HAS_ADDR4(wh) == IEEE80211_QOS_HAS_SEQ(wh)) + pad = 0; + else + pad = 2; + /* setup TX Wireless Information */ txwi = (struct rt2860_txwi *)(txd + 1); - txwi->flags = wflags; - txwi->xflags = xflags; - txwi->wcid = (type == IEEE80211_FC0_TYPE_DATA) ? - RUN_AID2WCID(data->ni->ni_associd) : 0xff; txwi->len = htole16(m->m_pkthdr.len - pad); if (rt2860_rates[ridx].phy == IEEE80211_T_DS) { txwi->phy = htole16(RT2860_PHY_CCK); @@ -2625,16 +2887,14 @@ run_set_tx_desc(struct run_softc *sc, struct run_tx_data *data, txwi->phy = htole16(RT2860_PHY_OFDM); txwi->phy |= htole16(mcs); - wh = mtod(m, struct ieee80211_frame *); - /* check if RTS/CTS or CTS-to-self protection is required */ if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && (m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold || ((ic->ic_flags & IEEE80211_F_USEPROT) && rt2860_rates[ridx].phy == IEEE80211_T_OFDM))) - txwi->txop = RT2860_TX_TXOP_HT | opflags; + txwi->txop |= RT2860_TX_TXOP_HT; else - txwi->txop = RT2860_TX_TXOP_BACKOFF | opflags; + txwi->txop |= RT2860_TX_TXOP_BACKOFF; } /* This function must be called locked */ @@ -2642,21 +2902,24 @@ static int run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { struct ieee80211com *ic = sc->sc_ifp->if_l2com; - struct ieee80211vap *vap = &sc->sc_rvp->vap; + struct ieee80211vap *vap = ni->ni_vap; struct ieee80211_frame *wh; + struct ieee80211_channel *chan; const struct ieee80211_txparam *tp; + struct run_node *rn = (void *)ni; struct run_tx_data *data; + struct rt2870_txd *txd; + struct rt2860_txwi *txwi; uint16_t qos; uint16_t dur; + uint16_t qid; uint8_t type; uint8_t tid; - uint8_t qid; + uint8_t ridx; + uint8_t ctl_ridx; uint8_t qflags; - uint8_t pad; uint8_t xflags = 0; int hasqos; - int ridx; - int ctl_ridx; RUN_LOCK_ASSERT(sc, MA_OWNED); @@ -2681,19 +2944,18 @@ run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) qos = le16toh(*(const uint16_t *)frm); tid = qos & IEEE80211_QOS_TID; qid = TID_TO_WME_AC(tid); - pad = 2; } else { qos = 0; tid = 0; qid = WME_AC_BE; - pad = 0; } qflags = (qid < 4) ? RT2860_TX_QSEL_EDCA : RT2860_TX_QSEL_HCCA; DPRINTFN(8, "qos %d\tqid %d\ttid %d\tqflags %x\n", qos, qid, tid, qflags); - tp = &vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)]; + chan = (ni->ni_chan != IEEE80211_CHAN_ANYC)?ni->ni_chan:ic->ic_curchan; + tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; /* pickup a rate index */ if (IEEE80211_IS_MULTICAST(wh->i_addr1) || @@ -2701,25 +2963,22 @@ run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; ctl_ridx = rt2860_rates[ridx].ctl_ridx; - } else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) { - ridx = sc->fixed_ridx; - ctl_ridx = rt2860_rates[ridx].ctl_ridx; } else { - for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++){ - if (rt2860_rates[ridx].rate == ni->ni_txrate) - break; - } + if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) + ridx = rn->fix_ridx; + else + ridx = rn->amrr_ridx; ctl_ridx = rt2860_rates[ridx].ctl_ridx; } if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && (!hasqos || (qos & IEEE80211_QOS_ACKPOLICY) != IEEE80211_QOS_ACKPOLICY_NOACK)) { - xflags |= RT2860_TX_ACK; + xflags = RT2860_TX_ACK; if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) - dur = rt2860_rates[ridx].sp_ack_dur; + dur = rt2860_rates[ctl_ridx].sp_ack_dur; else - dur = rt2860_rates[ridx].lp_ack_dur; + dur = rt2860_rates[ctl_ridx].lp_ack_dur; *(uint16_t *)wh->i_dur = htole16(dur); } @@ -2733,11 +2992,64 @@ run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) STAILQ_REMOVE_HEAD(&sc->sc_epq[qid].tx_fh, next); sc->sc_epq[qid].tx_nfree--; + txd = (struct rt2870_txd *)&data->desc; + txd->flags = qflags; + txwi = (struct rt2860_txwi *)(txd + 1); + txwi->xflags = xflags; + txwi->wcid = (type == IEEE80211_FC0_TYPE_DATA) ? + RUN_AID2WCID(ni->ni_associd) : 0xff; + /* clear leftover garbage bits */ + txwi->flags = 0; + txwi->txop = 0; + data->m = m; data->ni = ni; data->ridx = ridx; - run_set_tx_desc(sc, data, 0, xflags, 0, qflags, type, pad); + run_set_tx_desc(sc, data); + + /* + * The chip keeps track of 2 kind of Tx stats, + * * TX_STAT_FIFO, for per WCID stats, and + * * TX_STA_CNT0 for all-TX-in-one stats. + * + * To use FIFO stats, we need to store MCS into the driver-private + * PacketID field. So that, we can tell whose stats when we read them. + * We add 1 to the MCS because setting the PacketID field to 0 means + * that we don't want feedback in TX_STAT_FIFO. + * And, that's what we want for STA mode, since TX_STA_CNT0 does the job. + * + * FIFO stats doesn't count Tx with WCID 0xff, so we do this in run_tx(). + */ + if(sc->rvp_cnt > 1 || vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_MBSS){ + uint16_t pid = (rt2860_rates[ridx].mcs + 1) & 0xf; + txwi->len |= htole16(pid << RT2860_TX_PID_SHIFT); + + /* + * Unlike PCI based devices, we don't get any interrupt from + * USB devices, so we simulate FIFO-is-full interrupt here. + * Ralink recomends to drain FIFO stats every 100 ms, but 16 slots + * quickly get fulled. To prevent overflow, increment a counter on + * every FIFO stat request, so we know how many slots are left. + * We do this only in HOSTAP or multiple vap mode since FIFO stats + * are used only in those modes. + * We just drain stats. AMRR gets updated every 1 sec by + * run_ratectl_cb() via callout. + * Call it early. Otherwise overflow. + */ + if(sc->fifo_cnt++ == 10){ + /* + * With multiple vaps or if_bridge, if_start() is called + * with a non-sleepable lock, tcpinp. So, need to defer. + */ + uint32_t i = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTFN(6, "cmdq_store=%d\n", i); + sc->cmdq[i].func = run_drain_fifo; + sc->cmdq[i].arg0 = sc; + ieee80211_runtask(ic, &sc->cmdq_task); + } + } STAILQ_INSERT_TAIL(&sc->sc_epq[qid].tx_qh, data, next); @@ -2753,36 +3065,36 @@ run_tx(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) static int run_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { - const struct ieee80211_txparam *tp; struct ifnet *ifp = sc->sc_ifp; - struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ifp->if_l2com; + struct run_node *rn = (void *)ni; struct run_tx_data *data; struct ieee80211_frame *wh; - int ridx; + struct rt2870_txd *txd; + struct rt2860_txwi *txwi; uint16_t dur; + uint8_t ridx = rn->mgt_ridx; uint8_t type; uint8_t xflags = 0; + uint8_t wflags = 0; RUN_LOCK_ASSERT(sc, MA_OWNED); wh = mtod(m, struct ieee80211_frame *); type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; - tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; - if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + /* tell hardware to add timestamp for probe responses */ + if ((wh->i_fc[0] & + (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == + (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) + wflags |= RT2860_TX_TS; + else if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { xflags |= RT2860_TX_ACK; - dur = ieee80211_ack_duration(ic->ic_rt, tp->mgmtrate, + dur = ieee80211_ack_duration(ic->ic_rt, rt2860_rates[ridx].rate, ic->ic_flags & IEEE80211_F_SHPREAMBLE); *(uint16_t *)wh->i_dur = htole16(dur); - - /* tell hardware to add timestamp for probe responses */ - if ((wh->i_fc[0] & - (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == - (IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP)) - xflags |= RT2860_TX_TS; } if (sc->sc_epq[0].tx_nfree == 0) { @@ -2794,19 +3106,23 @@ run_tx_mgt(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni) STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); sc->sc_epq[0].tx_nfree--; + txd = (struct rt2870_txd *)&data->desc; + txd->flags = RT2860_TX_QSEL_EDCA; + txwi = (struct rt2860_txwi *)(txd + 1); + txwi->wcid = 0xff; + txwi->flags = wflags; + txwi->xflags = xflags; + txwi->txop = 0; /* clear leftover garbage bits */ + data->m = m; data->ni = ni; - for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) - if (rt2860_rates[ridx].rate == tp->mgmtrate) - break; data->ridx = ridx; - run_set_tx_desc(sc, data, 0, xflags, 0, RT2860_TX_QSEL_MGMT, - wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, 0); + run_set_tx_desc(sc, data); DPRINTFN(10, "sending mgt frame len=%d rate=%d\n", m->m_pkthdr.len + (int)(sizeof (struct rt2870_txd) + sizeof (struct rt2860_rxwi)), - tp->mgmtrate); + rt2860_rates[ridx].rate); STAILQ_INSERT_TAIL(&sc->sc_epq[0].tx_qh, data, next); @@ -2822,6 +3138,8 @@ run_sendprot(struct run_softc *sc, struct ieee80211com *ic = ni->ni_ic; struct ieee80211_frame *wh; struct run_tx_data *data; + struct rt2870_txd *txd; + struct rt2860_txwi *txwi; struct mbuf *mprot; int ridx; int protrate; @@ -2830,8 +3148,8 @@ run_sendprot(struct run_softc *sc, int isshort; uint16_t dur; uint8_t type; - uint8_t wflags; - uint8_t txflags = 0; + uint8_t wflags = 0; + uint8_t xflags = 0; RUN_LOCK_ASSERT(sc, MA_OWNED); @@ -2860,7 +3178,7 @@ run_sendprot(struct run_softc *sc, if (prot == IEEE80211_PROT_RTSCTS) { /* NB: CTS is the same size as an ACK */ dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); - txflags |= RT2860_TX_ACK; + xflags |= RT2860_TX_ACK; mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); } else { mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur); @@ -2875,6 +3193,14 @@ run_sendprot(struct run_softc *sc, STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); sc->sc_epq[0].tx_nfree--; + txd = (struct rt2870_txd *)&data->desc; + txd->flags = RT2860_TX_QSEL_EDCA; + txwi = (struct rt2860_txwi *)(txd + 1); + txwi->wcid = 0xff; + txwi->flags = wflags; + txwi->xflags = xflags; + txwi->txop = 0; /* clear leftover garbage bits */ + data->m = mprot; data->ni = ieee80211_ref_node(ni); @@ -2883,8 +3209,7 @@ run_sendprot(struct run_softc *sc, break; data->ridx = ridx; - run_set_tx_desc(sc, data, wflags, txflags, 0, - RT2860_TX_QSEL_EDCA, type, 0); + run_set_tx_desc(sc, data); DPRINTFN(1, "sending prot len=%u rate=%u\n", m->m_pkthdr.len, rate); @@ -2903,11 +3228,13 @@ run_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, struct ieee80211com *ic = ni->ni_ic; struct ieee80211_frame *wh; struct run_tx_data *data; + struct rt2870_txd *txd; + struct rt2860_txwi *txwi; uint8_t type; - uint8_t opflags; - uint8_t txflags; - int ridx; - int rate; + uint8_t ridx; + uint8_t rate; + uint8_t opflags = 0; + uint8_t xflags = 0; int error; RUN_LOCK_ASSERT(sc, MA_OWNED); @@ -2923,10 +3250,8 @@ run_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, return (EINVAL); } - opflags = 0; - txflags = 0; if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) - txflags |= RT2860_TX_ACK; + xflags |= RT2860_TX_ACK; if (params->ibp_flags & (IEEE80211_BPF_RTS|IEEE80211_BPF_CTS)) { error = run_sendprot(sc, m, ni, params->ibp_flags & IEEE80211_BPF_RTS ? @@ -2949,6 +3274,14 @@ run_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, STAILQ_REMOVE_HEAD(&sc->sc_epq[0].tx_fh, next); sc->sc_epq[0].tx_nfree--; + txd = (struct rt2870_txd *)&data->desc; + txd->flags = RT2860_TX_QSEL_EDCA; + txwi = (struct rt2860_txwi *)(txd + 1); + txwi->wcid = 0xff; + txwi->xflags = xflags; + txwi->txop = opflags; + txwi->flags = 0; /* clear leftover garbage bits */ + data->m = m; data->ni = ni; for (ridx = 0; ridx < RT2860_RIDX_MAX; ridx++) @@ -2956,8 +3289,7 @@ run_tx_param(struct run_softc *sc, struct mbuf *m, struct ieee80211_node *ni, break; data->ridx = ridx; - run_set_tx_desc(sc, data, 0, txflags, opflags, - RT2860_TX_QSEL_EDCA, type, 0); + run_set_tx_desc(sc, data); DPRINTFN(10, "sending raw frame len=%u rate=%u\n", m->m_pkthdr.len, rate); @@ -2975,14 +3307,14 @@ run_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, { struct ifnet *ifp = ni->ni_ic->ic_ifp; struct run_softc *sc = ifp->if_softc; - int error; - + int error = 0; + RUN_LOCK(sc); /* prevent management frames from being sent if we're not ready */ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { error = ENETDOWN; - goto bad; + goto done; } if (params == NULL) { @@ -2990,28 +3322,27 @@ run_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, if ((error = run_tx_mgt(sc, m, ni)) != 0){ ifp->if_oerrors++; DPRINTF("mgt tx failed\n"); - goto bad; + goto done; } } else { /* tx raw packet with param */ if ((error = run_tx_param(sc, m, ni, params)) != 0){ ifp->if_oerrors++; DPRINTF("tx with param failed\n"); - goto bad; + goto done; } } ifp->if_opackets++; +done: RUN_UNLOCK(sc); - return (0); - -bad: - RUN_UNLOCK(sc); - if(m != NULL) - m_freem(m); - ieee80211_free_node(ni); + if(error != 0){ + if(m != NULL) + m_freem(m); + ieee80211_free_node(ni); + } return (error); } @@ -3053,24 +3384,27 @@ run_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) struct run_softc *sc = ifp->if_softc; struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ifreq *ifr = (struct ifreq *) data; - int error = 0, startall = 0; + int startall = 0; + int error = 0; switch (cmd) { case SIOCSIFFLAGS: RUN_LOCK(sc); if (ifp->if_flags & IFF_UP) { if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)){ - run_init_locked(sc); startall = 1; + run_init_locked(sc); } else run_update_promisc_locked(ifp); } else { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) - run_stop(sc); + if(ifp->if_drv_flags & IFF_DRV_RUNNING && + (ic->ic_nrunning == 0 || sc->rvp_cnt <= 1)){ + run_stop(sc); + } } RUN_UNLOCK(sc); if(startall) - ieee80211_start_all(ic); + ieee80211_start_all(ic); break; case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); @@ -3138,19 +3472,17 @@ run_select_chan_group(struct run_softc *sc, int group) run_write(sc, RT2860_TX_BAND_CFG, tmp); /* enable appropriate Power Amplifiers and Low Noise Amplifiers */ - tmp = RT2860_RFTR_EN | RT2860_TRSW_EN; + tmp = RT2860_RFTR_EN | RT2860_TRSW_EN | RT2860_LNA_PE0_EN; + if (sc->nrxchains > 1) + tmp |= RT2860_LNA_PE1_EN; if (group == 0) { /* 2GHz */ - tmp |= RT2860_PA_PE_G0_EN | RT2860_LNA_PE_G0_EN; + tmp |= RT2860_PA_PE_G0_EN; if (sc->ntxchains > 1) tmp |= RT2860_PA_PE_G1_EN; - if (sc->nrxchains > 1) - tmp |= RT2860_LNA_PE_G1_EN; } else { /* 5GHz */ - tmp |= RT2860_PA_PE_A0_EN | RT2860_LNA_PE_A0_EN; + tmp |= RT2860_PA_PE_A0_EN; if (sc->ntxchains > 1) tmp |= RT2860_PA_PE_A1_EN; - if (sc->nrxchains > 1) - tmp |= RT2860_LNA_PE_A1_EN; } if (sc->mac_ver == 0x3572) { run_rt3070_rf_write(sc, 8, 0x00); @@ -3198,13 +3530,13 @@ run_rt2870_set_chan(struct run_softc *sc, uint32_t chan) txpow2 = sc->txpow2[i]; if (chan > 14) { if (txpow1 >= 0) - txpow1 = txpow1 << 1; + txpow1 = txpow1 << 1 | 1; else - txpow1 = (7 + txpow1) << 1 | 1; + txpow1 = (7 + txpow1) << 1; if (txpow2 >= 0) - txpow2 = txpow2 << 1; + txpow2 = txpow2 << 1 | 1; else - txpow2 = (7 + txpow2) << 1 | 1; + txpow2 = (7 + txpow2) << 1; } r3 = rfprog[i].r3 | txpow1 << 7; r4 = rfprog[i].r4 | sc->freq << 13 | txpow2 << 4; @@ -3541,36 +3873,38 @@ run_scan_end(struct ieee80211com *ic) return; } -static uint8_t -run_rate2mcs(uint8_t rate) +/* + * Could be called from ieee80211_node_timeout() + * (non-sleepable thread) + */ +static void +run_update_beacon(struct ieee80211vap *vap, int item) { - switch (rate) { - /* CCK rates */ - case 2: return 0; - case 4: return 1; - case 11: return 2; - case 22: return 3; - /* OFDM rates */ - case 12: return 0; - case 18: return 1; - case 24: return 2; - case 36: return 3; - case 48: return 4; - case 72: return 5; - case 96: return 6; - case 108: return 7; - } - return 0; /* shouldn't get here */ + struct ieee80211com *ic = vap->iv_ic; + struct run_softc *sc = ic->ic_ifp->if_softc; + uint32_t i; + + i = RUN_CMDQ_GET(&sc->cmdq_store); + DPRINTF("cmdq_store=%d\n", i); + sc->cmdq[i].func = run_update_beacon_cb; + sc->cmdq[i].arg0 = vap; + ieee80211_runtask(ic, &sc->cmdq_task); + + return; } static void -run_update_beacon_locked(struct ieee80211vap *vap, int item) +run_update_beacon_cb(void *arg) { + struct ieee80211vap *vap = arg; struct ieee80211com *ic = vap->iv_ic; struct run_softc *sc = ic->ic_ifp->if_softc; struct rt2860_txwi txwi; struct mbuf *m; - int rate; + uint8_t ridx; + + if(vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC) + return; if ((m = ieee80211_beacon_alloc(vap->iv_bss, &RUN_VAP(vap)->bo)) == NULL) return; @@ -3579,16 +3913,17 @@ run_update_beacon_locked(struct ieee80211vap *vap, int item) txwi.wcid = 0xff; txwi.len = htole16(m->m_pkthdr.len); /* send beacons at the lowest available rate */ - rate = (ic->ic_curmode == IEEE80211_MODE_11A) ? 12 : 2; - txwi.phy = htole16(run_rate2mcs(rate)); - if (rate == 12) + ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? + RT2860_RIDX_OFDM6 : RT2860_RIDX_CCK1; + txwi.phy = htole16(rt2860_rates[ridx].mcs); + if (rt2860_rates[ridx].phy == IEEE80211_T_OFDM) txwi.phy |= htole16(RT2860_PHY_OFDM); txwi.txop = RT2860_TX_TXOP_HT; txwi.flags = RT2860_TX_TS; - run_write_region_1(sc, RT2860_BCN_BASE(0), - (u_int8_t *)&txwi, sizeof txwi); - run_write_region_1(sc, RT2860_BCN_BASE(0) + sizeof txwi, + run_write_region_1(sc, RT2860_BCN_BASE(RUN_VAP(vap)->rvp_id), + (uint8_t *)&txwi, sizeof txwi); + run_write_region_1(sc, RT2860_BCN_BASE(RUN_VAP(vap)->rvp_id) + sizeof txwi, mtod(m, uint8_t *), (m->m_pkthdr.len + 1) & ~1); /* roundup len */ m_freem(m); @@ -3597,21 +3932,6 @@ run_update_beacon_locked(struct ieee80211vap *vap, int item) } static void -run_update_beacon(struct ieee80211vap *vap, int item) -{ - struct ieee80211com *ic = vap->iv_ic; - struct run_softc *sc = ic->ic_ifp->if_softc; - - IEEE80211_UNLOCK(ic); - RUN_LOCK(sc); - run_update_beacon_locked(vap, item); - RUN_UNLOCK(sc); - IEEE80211_LOCK(ic); - - return; -} - -static void run_updateprot(struct ieee80211com *ic) { struct run_softc *sc = ic->ic_ifp->if_softc; @@ -3635,12 +3955,12 @@ run_updateprot(struct ieee80211com *ic) } static void -run_usb_timeout_cb(void *arg, int pending) +run_usb_timeout_cb(void *arg) { - struct run_softc *sc = arg; - struct ieee80211vap *vap = &sc->sc_rvp->vap; + struct ieee80211vap *vap = arg; + struct run_softc *sc = vap->iv_ic->ic_ifp->if_softc; - RUN_LOCK(sc); + RUN_LOCK_ASSERT(sc, MA_OWNED); if(vap->iv_state == IEEE80211_S_RUN && vap->iv_opmode != IEEE80211_M_STA) @@ -3651,8 +3971,6 @@ run_usb_timeout_cb(void *arg, int pending) ieee80211_cancel_scan(vap); } else DPRINTF("timeout by unknown cause\n"); - - RUN_UNLOCK(sc); } static void @@ -3660,12 +3978,15 @@ run_reset_livelock(struct run_softc *sc) { uint32_t tmp; + RUN_LOCK_ASSERT(sc, MA_OWNED); + /* * In IBSS or HostAP modes (when the hardware sends beacons), the MAC * can run into a livelock and start sending CTS-to-self frames like * crazy if protection is enabled. Reset MAC/BBP for a while */ run_read(sc, RT2860_DEBUG, &tmp); + DPRINTFN(3, "debug reg %08x\n", tmp); if((tmp & (1 << 29)) && (tmp & (1 << 7 | 1 << 5))){ DPRINTF("CTS-to-self livelock detected\n"); run_write(sc, RT2860_MAC_SYS_CTRL, RT2860_MAC_SRST); @@ -3709,35 +4030,39 @@ run_update_promisc(struct ifnet *ifp) static void run_enable_tsf_sync(struct run_softc *sc) { - struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; + struct ieee80211com *ic = sc->sc_ifp->if_l2com; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); uint32_t tmp; + DPRINTF("rvp_id=%d ic_opmode=%d\n", RUN_VAP(vap)->rvp_id, ic->ic_opmode); + run_read(sc, RT2860_BCN_TIME_CFG, &tmp); tmp &= ~0x1fffff; tmp |= vap->iv_bss->ni_intval * 16; tmp |= RT2860_TSF_TIMER_EN | RT2860_TBTT_TIMER_EN; - if (vap->iv_opmode == IEEE80211_M_STA) { + if (ic->ic_opmode == IEEE80211_M_STA) { /* * Local TSF is always updated with remote TSF on beacon * reception. */ tmp |= 1 << RT2860_TSF_SYNC_MODE_SHIFT; - } else if (vap->iv_opmode == IEEE80211_M_IBSS) { + } else if (ic->ic_opmode == IEEE80211_M_IBSS) { tmp |= RT2860_BCN_TX_EN; /* * Local TSF is updated with remote TSF on beacon reception * only if the remote TSF is greater than local TSF. */ tmp |= 2 << RT2860_TSF_SYNC_MODE_SHIFT; - } else if (vap->iv_opmode == IEEE80211_M_HOSTAP) { + } else if (ic->ic_opmode == IEEE80211_M_HOSTAP || + ic->ic_opmode == IEEE80211_M_MBSS) { tmp |= RT2860_BCN_TX_EN; /* SYNC with nobody */ tmp |= 3 << RT2860_TSF_SYNC_MODE_SHIFT; - } else + } else { DPRINTF("Enabling TSF failed. undefined opmode\n"); + return; + } run_write(sc, RT2860_BCN_TIME_CFG, tmp); } @@ -3833,6 +4158,13 @@ run_updateslot(struct ifnet *ifp) run_write(sc, RT2860_BKOFF_SLOT_CFG, tmp); } +static void +run_update_mcast(struct ifnet *ifp) +{ + /* h/w filter supports getting everything or nothing */ + ifp->if_flags |= IFF_ALLMULTI; +} + static int8_t run_rssi2dbm(struct run_softc *sc, uint8_t rssi, uint8_t rxchain) { @@ -3942,23 +4274,18 @@ run_rt3070_rf_init(struct run_softc *sc) /* patch LNA_PE_G1 */ run_read(sc, RT3070_GPIO_SWITCH, &tmp); run_write(sc, RT3070_GPIO_SWITCH, tmp & ~0x20); + } else if(sc->mac_ver == 0x3572){ run_rt3070_rf_read(sc, 6, &rf); run_rt3070_rf_write(sc, 6, rf | 0x40); - if (sc->mac_rev < 0x0211){ - /* increase voltage from 1.2V to 1.35V */ - run_read(sc, RT3070_LDO_CFG0, &tmp); - tmp = (tmp & ~0x0f000000) | 0x0d000000; - run_write(sc, RT3070_LDO_CFG0, tmp); - } else { - /* increase voltage from 1.2V to 1.35V */ - run_read(sc, RT3070_LDO_CFG0, &tmp); - tmp = (tmp & ~0x1f000000) | 0x0d000000; - run_write(sc, RT3070_LDO_CFG0, tmp); + /* increase voltage from 1.2V to 1.35V */ + run_read(sc, RT3070_LDO_CFG0, &tmp); + tmp = (tmp & ~0x1f000000) | 0x0d000000; + run_write(sc, RT3070_LDO_CFG0, tmp); + if (sc->mac_rev < 0x0211 || !sc->patch_dac){ run_delay(sc, 1); /* wait for 1msec */ - /* decrease voltage back to 1.2V */ tmp = (tmp & ~0x1f000000) | 0x01000000; run_write(sc, RT3070_LDO_CFG0, tmp); @@ -4240,6 +4567,9 @@ run_init_locked(struct run_softc *sc) int ridx; int ntries; + if(ic->ic_nrunning > 1) + return; + run_stop(sc); for (ntries = 0; ntries < 100; ntries++) { @@ -4353,7 +4683,7 @@ run_init_locked(struct run_softc *sc) run_write(sc, RT2860_WMM_TXOP1_CFG, 48 << 16 | 96); /* write vendor-specific BBP values (from EEPROM) */ - for (i = 0; i < 8; i++) { + for (i = 0; i < 10; i++) { if (sc->bbp[i].reg == 0 || sc->bbp[i].reg == 0xff) continue; run_bbp_write(sc, sc->bbp[i].reg, sc->bbp[i].val); @@ -4400,6 +4730,7 @@ run_init_locked(struct run_softc *sc) ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_drv_flags |= IFF_DRV_RUNNING; + sc->cmdq_run = RUN_CMDQ_GO; for(i = 0; i != RUN_N_XFER; i++) usbd_xfer_set_stall(sc->sc_xfer[i]); @@ -4427,7 +4758,7 @@ run_init(void *arg) RUN_UNLOCK(sc); if (ifp->if_drv_flags & IFF_DRV_RUNNING) - ieee80211_start_all(ic); + ieee80211_start_all(ic); } static void @@ -4435,24 +4766,20 @@ run_stop(void *arg) { struct run_softc *sc = (struct run_softc *)arg; struct ifnet *ifp = sc->sc_ifp; - struct ieee80211com *ic = ifp->if_l2com; uint32_t tmp; int i; int ntries; RUN_LOCK_ASSERT(sc, MA_OWNED); - if(sc->sc_rvp != NULL){ - sc->sc_rvp->ratectl_run = RUN_RATECTL_OFF; - if (ic->ic_flags & IEEE80211_F_SCAN) - ieee80211_cancel_scan(&sc->sc_rvp->vap); - } - if (ifp->if_drv_flags & IFF_DRV_RUNNING) run_set_leds(sc, 0); /* turn all LEDs off */ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + sc->ratectl_run = RUN_RATECTL_OFF; + sc->cmdq_run = RUN_CMDQ_ABORT; + RUN_UNLOCK(sc); for(i = 0; i < RUN_N_XFER; i++) diff --git a/sys/dev/usb/wlan/if_runreg.h b/sys/dev/usb/wlan/if_runreg.h index f872fad..33f3b94 100644 --- a/sys/dev/usb/wlan/if_runreg.h +++ b/sys/dev/usb/wlan/if_runreg.h @@ -517,8 +517,10 @@ #define RT2860_LNA_PE_A0_POL (1 << 12) #define RT2860_LNA_PE_G1_EN (1 << 11) #define RT2860_LNA_PE_A1_EN (1 << 10) +#define RT2860_LNA_PE1_EN (RT2860_LNA_PE_A1_EN | RT2860_LNA_PE_G1_EN) #define RT2860_LNA_PE_G0_EN (1 << 9) #define RT2860_LNA_PE_A0_EN (1 << 8) +#define RT2860_LNA_PE0_EN (RT2860_LNA_PE_A0_EN | RT2860_LNA_PE_G0_EN) #define RT2860_PA_PE_G1_POL (1 << 7) #define RT2860_PA_PE_A1_POL (1 << 6) #define RT2860_PA_PE_G0_POL (1 << 5) @@ -896,7 +898,7 @@ struct rt2860_rxwi { #define RT2860_RIDX_CCK1 0 #define RT2860_RIDX_CCK11 3 #define RT2860_RIDX_OFDM6 4 -#define RT2860_RIDX_MAX 11 +#define RT2860_RIDX_MAX 12 static const struct rt2860_rate { uint8_t rate; uint8_t mcs; @@ -1097,24 +1099,6 @@ static const struct rt2860_rate { { 171, 0x100bb1, 0x1300f5, 0x05e014, 0x001401 }, \ { 173, 0x100bb1, 0x1300f5, 0x05e014, 0x001403 } -#if 0 -#define RT3070_RF3020 \ - { 241, 2, 2 }, \ - { 241, 2, 7 }, \ - { 242, 2, 2 }, \ - { 242, 2, 7 }, \ - { 243, 2, 2 }, \ - { 243, 2, 7 }, \ - { 244, 2, 2 }, \ - { 244, 2, 7 }, \ - { 245, 2, 2 }, \ - { 245, 2, 7 }, \ - { 246, 2, 2 }, \ - { 246, 2, 7 }, \ - { 247, 2, 2 }, \ - { 248, 2, 4 } -#endif - #define RT3070_RF3052 \ { 0xf1, 2, 2 }, \ { 0xf1, 2, 7 }, \ diff --git a/sys/dev/usb/wlan/if_runvar.h b/sys/dev/usb/wlan/if_runvar.h index a7f8f1f..7349eaf 100644 --- a/sys/dev/usb/wlan/if_runvar.h +++ b/sys/dev/usb/wlan/if_runvar.h @@ -44,16 +44,18 @@ #define RUN_TX_RING_COUNT 32 #define RUN_RX_RING_COUNT 1 -#define RT2870_WCID_MAX 253 +#define RT2870_WCID_MAX 64 #define RUN_AID2WCID(aid) ((aid) & 0xff) +#define RUN_VAP_MAX 8 + struct run_rx_radiotap_header { struct ieee80211_radiotap_header wr_ihdr; uint8_t wr_flags; uint8_t wr_rate; uint16_t wr_chan_freq; uint16_t wr_chan_flags; - uint8_t wr_dbm_antsignal; + int8_t wr_dbm_antsignal; uint8_t wr_antenna; uint8_t wr_antsignal; } __packed; @@ -93,8 +95,7 @@ struct run_tx_data { uint32_t align[0]; /* dummy field */ uint8_t desc[sizeof(struct rt2870_txd) + sizeof(struct rt2860_txwi)]; - int ridx; - uint8_t mcs; + uint8_t ridx; }; STAILQ_HEAD(run_tx_data_head, run_tx_data); @@ -102,19 +103,29 @@ struct run_node { struct ieee80211_node ni; uint8_t ridx[IEEE80211_RATE_MAXSIZE]; uint8_t ctl_ridx[IEEE80211_RATE_MAXSIZE]; + uint8_t amrr_ridx; + uint8_t mgt_ridx; + uint8_t fix_ridx; +}; + +struct run_cmdq { + void *arg0; + void *arg1; + void (*func)(void *); + struct ieee80211_key *k; + struct ieee80211_key key; + uint8_t mac[IEEE80211_ADDR_LEN]; + uint8_t wcid; }; struct run_vap { struct ieee80211vap vap; struct ieee80211_beacon_offsets bo; - struct usb_callout ratectl_ch; - struct task ratectl_task; - uint8_t ratectl_run; -#define RUN_RATECTL_ON 1 -#define RUN_RATECTL_OFF 0 int (*newstate)(struct ieee80211vap *, enum ieee80211_state, int); + + uint8_t rvp_id; }; #define RUN_VAP(vap) ((struct run_vap *)(vap)) @@ -148,7 +159,7 @@ struct run_softc { device_t sc_dev; struct usb_device *sc_udev; struct ifnet *sc_ifp; - struct run_vap *sc_rvp; + struct ieee80211_node *sc_ni[RT2870_WCID_MAX + 1]; int (*sc_srom_read)(struct run_softc *, uint16_t, uint16_t *); @@ -159,7 +170,6 @@ struct run_softc { uint8_t freq; uint8_t ntxchains; uint8_t nrxchains; - int fixed_ridx; uint8_t bbp25; uint8_t bbp26; @@ -182,7 +192,7 @@ struct run_softc { struct { uint8_t reg; uint8_t val; - } bbp[8], rf[10]; + } bbp[10], rf[10]; uint8_t leds; uint16_t led[3]; uint32_t txpow20mhz[5]; @@ -195,13 +205,36 @@ struct run_softc { struct run_endpoint_queue sc_epq[RUN_EP_QUEUES]; - struct task wme_task; - struct task usb_timeout_task; + struct task ratectl_task; + struct usb_callout ratectl_ch; + uint8_t ratectl_run; +#define RUN_RATECTL_OFF 0 + +/* need to be power of 2, otherwise RUN_CMDQ_GET fails */ +#define RUN_CMDQ_MAX 16 +#define RUN_CMDQ_MASQ (RUN_CMDQ_MAX - 1) + struct run_cmdq cmdq[RUN_CMDQ_MAX]; + struct task cmdq_task; + uint32_t cmdq_store; + uint8_t cmdq_exec; + uint8_t cmdq_run; +#define RUN_CMDQ_ABORT 0 +#define RUN_CMDQ_GO 1 struct usb_xfer *sc_xfer[RUN_N_XFER]; struct mbuf *rx_m; + uint8_t fifo_cnt; + + uint8_t running; + uint8_t runbmap; + uint8_t ap_running; + uint8_t adhoc_running; + uint8_t sta_running; + uint8_t rvp_cnt; + uint8_t rvp_bmap; + union { struct run_rx_radiotap_header th; uint8_t pad[64]; |