diff --git a/Makefile.inc1 b/Makefile.inc1 index 6d20a55dbe4f..f31febdbd4f5 100644 --- a/Makefile.inc1 +++ b/Makefile.inc1 @@ -1586,7 +1586,7 @@ _strfile= usr.bin/fortune/strfile _gperf= gnu/usr.bin/gperf .endif -.if ${MK_SHAREDOCS} != "no" || ${MK_GROFF} != "no" +.if ${MK_SHAREDOCS} != "no" && ${MK_GROFF} != "no" _groff= gnu/usr.bin/groff \ usr.bin/soelim .endif @@ -1982,7 +1982,10 @@ libraries: .MAKE .PHONY # # static libgcc.a prerequisite for shared libc # -_prereq_libs= gnu/lib/libssp/libssp_nonshared gnu/lib/libgcc lib/libcompiler_rt +_prereq_libs= gnu/lib/libgcc lib/libcompiler_rt +.if ${MK_SSP} != "no" +_prereq_libs+= gnu/lib/libssp/libssp_nonshared +.endif # These dependencies are not automatically generated: # diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index d57406ffaca7..be16a54ef305 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -130,6 +130,9 @@ OLD_FILES+=usr/lib/clang/3.8.0/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_ OLD_DIRS+=usr/lib/clang/3.8.0/lib/freebsd OLD_DIRS+=usr/lib/clang/3.8.0/lib OLD_DIRS+=usr/lib/clang/3.8.0 +# 20161017: urtwn(4) was merged into rtwn(4) +OLD_FILES+=usr/share/man/man4/urtwn.4.gz +OLD_FILES+=usr/share/man/man4/urtwnfw.4.gz # 20161015: Remove GNU rcs OLD_FILES+=usr/bin/ci OLD_FILES+=usr/bin/co diff --git a/UPDATING b/UPDATING index 3e4aa3d61976..20a82940a5c8 100644 --- a/UPDATING +++ b/UPDATING @@ -31,6 +31,30 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 12.x IS SLOW: disable the most expensive debugging functionality run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) + +****************************** SPECIAL WARNING: ****************************** + + Due to a bug in some versions of clang that's very hard to workaround in + the upgrade process, to upgrade to -current you must first upgrade + either stable/9 after r286035 or stable/10 after r286033 (including + 10.3-RELEASE) or current after r286007 (including stable/11 and + 11.0-RELEASE). These revisions post-date the 10.2 and 9.3 releases, so + you'll need to take the unusual step of upgrading to the tip of the + stable branch before moving to 11 or -current via a source upgrade. + stable/11 and 11.0-RELEASE post-date the fix so you can move from them + to -current. This differs from the historical situation where one could + upgrade from anywhere on the last couple of stable branches, so be + careful. + +****************************** SPECIAL WARNING: ****************************** + +20161017: + The urtwn(4) driver was merged into rtwn(4) and now consists of + rtwn(4) main module + rtwn_usb(4) and rtwn_pci(4) bus-specific + parts. + Also, firmware for RTL8188CE was renamed due to possible name + conflict (rtwnrtl8192cU(B) -> rtwnrtl8192cE(B)) + 20161015: GNU rcs has been removed from base. It is available as packages: - rcs: Latest GPLv3 GNU rcs version. @@ -1460,11 +1484,15 @@ COMMON ITEMS: your build attempts in an "environmental clean room", prefix all make commands with 'env -i '. See the env(1) manual page for more details. - When upgrading from one major version to another it is generally best - to upgrade to the latest code in the currently installed branch first, - then do an upgrade to the new branch. This is the best-tested upgrade - path, and has the highest probability of being successful. Please try - this approach before reporting problems with a major version upgrade. + When upgrading from one major version to another it is generally best to + upgrade to the latest code in the currently installed branch first, then + do an upgrade to the new branch. This is the best-tested upgrade path, + and has the highest probability of being successful. Please try this + approach if you encounter problems with a major version upgrade. Since + the stable 4.x branch point, one has generally been able to upgade from + anywhere in the most recent stable branch to head / current (or even the + last couple of stable branches). See the top of this file when there's + an exception. When upgrading a live system, having a root shell around before installing anything can help undo problems. Not having a root shell diff --git a/bin/pkill/tests/pgrep-j_test.sh b/bin/pkill/tests/pgrep-j_test.sh index 1d6281368075..0e54fd1106a7 100644 --- a/bin/pkill/tests/pgrep-j_test.sh +++ b/bin/pkill/tests/pgrep-j_test.sh @@ -20,12 +20,13 @@ sleep=$(pwd)/sleep.txt ln -sf /bin/sleep $sleep name="pgrep -j " -sleep_amount=5 +sleep_amount=15 jail -c path=/ name=${base}_1_1 ip4.addr=127.0.0.1 \ command=daemon -p ${PWD}/${base}_1_1.pid $sleep $sleep_amount & jail -c path=/ name=${base}_1_2 ip4.addr=127.0.0.1 \ command=daemon -p ${PWD}/${base}_1_2.pid $sleep $sleep_amount & +sleep 0.5 for i in `seq 1 10`; do jid1=$(jail_name_to_jid ${base}_1_1) @@ -53,7 +54,7 @@ fi wait name="pgrep -j any" -sleep_amount=6 +sleep_amount=16 jail -c path=/ name=${base}_2_1 ip4.addr=127.0.0.1 \ command=daemon -p ${PWD}/${base}_2_1.pid $sleep $sleep_amount & @@ -74,7 +75,7 @@ fi wait name="pgrep -j none" -sleep_amount=7 +sleep_amount=17 daemon -p ${PWD}/${base}_3_1.pid $sleep $sleep_amount & jail -c path=/ name=${base}_3_2 ip4.addr=127.0.0.1 \ command=daemon -p ${PWD}/${base}_3_2.pid $sleep $sleep_amount & @@ -91,7 +92,7 @@ wait # test 4 is like test 1 except with jname instead of jid. name="pgrep -j " -sleep_amount=8 +sleep_amount=18 jail -c path=/ name=${base}_4_1 ip4.addr=127.0.0.1 \ command=daemon -p ${PWD}/${base}_4_1.pid $sleep $sleep_amount & diff --git a/bin/pkill/tests/pkill-j_test.sh b/bin/pkill/tests/pkill-j_test.sh index 0af24cfc86fa..442d9d23885e 100644 --- a/bin/pkill/tests/pkill-j_test.sh +++ b/bin/pkill/tests/pkill-j_test.sh @@ -20,7 +20,7 @@ sleep=$(pwd)/sleep.txt ln -sf /bin/sleep $sleep name="pkill -j " -sleep_amount=5 +sleep_amount=15 jail -c path=/ name=${base}_1_1 ip4.addr=127.0.0.1 \ command=daemon -p ${PWD}/${base}_1_1.pid $sleep $sleep_amount & @@ -54,7 +54,7 @@ fi 2>/dev/null wait name="pkill -j any" -sleep_amount=6 +sleep_amount=16 jail -c path=/ name=${base}_2_1 ip4.addr=127.0.0.1 \ command=daemon -p ${PWD}/${base}_2_1.pid $sleep $sleep_amount & @@ -76,7 +76,7 @@ fi 2>/dev/null wait name="pkill -j none" -sleep_amount=7 +sleep_amount=17 daemon -p ${PWD}/${base}_3_1.pid $sleep $sleep_amount jail -c path=/ name=${base}_3_2 ip4.addr=127.0.0.1 \ command=daemon -p ${PWD}/${base}_3_2.pid $sleep $sleep_amount & @@ -94,7 +94,7 @@ wait # test 4 is like test 1 except with jname instead of jid. name="pkill -j " -sleep_amount=8 +sleep_amount=18 jail -c path=/ name=${base}_4_1 ip4.addr=127.0.0.1 \ command=daemon -p ${PWD}/${base}_4_1.pid $sleep $sleep_amount & diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.args1.c b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.args1.c index 28d0677ca5d2..e26485005271 100644 --- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.args1.c +++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/pid/tst.args1.c @@ -31,8 +31,8 @@ #include int -go(int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, - int arg7, int arg8, int arg9) +go(long arg0, long arg1, long arg2, long arg3, long arg4, long arg5, long arg6, + long arg7, long arg8, long arg9) { return (arg1); } diff --git a/cddl/usr.sbin/dtrace/tests/tools/exclude.sh b/cddl/usr.sbin/dtrace/tests/tools/exclude.sh index 38180da97c69..8c8fe5e77a02 100755 --- a/cddl/usr.sbin/dtrace/tests/tools/exclude.sh +++ b/cddl/usr.sbin/dtrace/tests/tools/exclude.sh @@ -72,6 +72,7 @@ exclude EXFAIL common/mib/tst.udp.ksh exclude SKIP common/privs/tst.fds.ksh exclude SKIP common/privs/tst.func_access.ksh exclude SKIP common/privs/tst.getf.ksh +exclude SKIP common/privs/tst.kpriv.ksh exclude SKIP common/privs/tst.op_access.ksh exclude SKIP common/privs/tst.procpriv.ksh exclude SKIP common/privs/tst.providers.ksh diff --git a/contrib/mdocml/mandocdb.c b/contrib/mdocml/mandocdb.c index d727ce0e9a37..3b9bda0d612b 100644 --- a/contrib/mdocml/mandocdb.c +++ b/contrib/mdocml/mandocdb.c @@ -1146,10 +1146,8 @@ mpages_merge(struct mparse *mp) for (mpage = mpage_head; mpage != NULL; mpage = mpage->next) { mlinks_undupe(mpage); - if ((mlink = mpage->mlinks) == NULL) { - mpage = mpage->next; + if ((mlink = mpage->mlinks) == NULL) continue; - } name_mask = NAME_MASK; mandoc_ohash_init(&names, 4, offsetof(struct str, key)); diff --git a/contrib/netbsd-tests/fs/tmpfs/t_link.sh b/contrib/netbsd-tests/fs/tmpfs/t_link.sh index 660f3f2a2462..9e0ef7bcb4b0 100755 --- a/contrib/netbsd-tests/fs/tmpfs/t_link.sh +++ b/contrib/netbsd-tests/fs/tmpfs/t_link.sh @@ -93,7 +93,18 @@ subdirs_body() { test_unmount } +# Begin FreeBSD +if true; then +atf_test_case kqueue cleanup +kqueue_cleanup() { + Mount_Point=$(pwd)/mntpt test_unmount || : +} +else +# End FreeBSD atf_test_case kqueue +# Begin FreeBSD +fi +# End FreeBSD kqueue_head() { atf_set "descr" "Verifies that creating a link raises the correct" \ "kqueue events" @@ -102,6 +113,10 @@ kqueue_head() { kqueue_body() { test_mount + # Begin FreeBSD + atf_expect_fail "fails with: dir/b did not receive NOTE_LINK - bug 213662" + # End FreeBSD + atf_check -s eq:0 -o empty -e empty mkdir dir atf_check -s eq:0 -o empty -e empty touch dir/a echo 'ln dir/a dir/b' | kqueue_monitor 2 dir dir/a diff --git a/contrib/netbsd-tests/lib/libpthread/t_swapcontext.c b/contrib/netbsd-tests/lib/libpthread/t_swapcontext.c index c0c375f77331..dc1897c68d02 100644 --- a/contrib/netbsd-tests/lib/libpthread/t_swapcontext.c +++ b/contrib/netbsd-tests/lib/libpthread/t_swapcontext.c @@ -97,6 +97,15 @@ ATF_TC_BODY(swapcontext1, tc) { pthread_t thread; +#if defined(__FreeBSD__) && defined(__mips__) + /* + * MIPS modifies TLS pointer in set_mcontext(), so + * swapping contexts obtained from different threads + * gives us different pthread_self() return value. + */ + atf_tc_skip("Platform is not supported."); +#endif + oself = (void *)&val1; nself = (void *)&val2; diff --git a/etc/devd.conf b/etc/devd.conf index e7654e45ad25..e4bd915d6ab3 100644 --- a/etc/devd.conf +++ b/etc/devd.conf @@ -24,7 +24,7 @@ options { [0-9]+"; set wifi-driver-regex "(ath|bwi|bwn|ipw|iwi|iwm|iwn|malo|mwl|ral|rsu|rum|run|uath|\ - upgt|ural|urtw|urtwn|wi|wpi|wtap|zyd)[0-9]+"; + upgt|ural|urtw|rtwn_usb|wi|wpi|wtap|zyd)[0-9]+"; }; # Note that the attach/detach with the highest value wins, so that one can diff --git a/etc/devd/usb.conf b/etc/devd/usb.conf index 45e28feb7826..3d8858b95d7a 100644 --- a/etc/devd/usb.conf +++ b/etc/devd/usb.conf @@ -181,6 +181,14 @@ nomatch 32 { action "kldload -n if_otus"; }; +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0409"; + match "product" "0x0408"; + action "kldload -n if_rtwn_usb"; +}; + nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; @@ -301,6 +309,14 @@ nomatch 32 { action "kldload -n if_run"; }; +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0411"; + match "product" "(0x0242|0x025d)"; + action "kldload -n if_rtwn_usb"; +}; + nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; @@ -549,6 +565,14 @@ nomatch 32 { action "kldload -n if_run"; }; +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x04bb"; + match "product" "0x0952"; + action "kldload -n if_rtwn_usb"; +}; + nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; @@ -682,7 +706,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x04f2"; match "product" "(0xaff7|0xaff8|0xaff9|0xaffa|0xaffa)"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -754,7 +778,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x050d"; match "product" "0x1102"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -778,7 +802,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x050d"; match "product" "(0x2102|0x2103)"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -1050,7 +1074,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x056e"; match "product" "0x4008"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -1146,7 +1170,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x0586"; match "product" "0x341f"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -1157,6 +1181,14 @@ nomatch 32 { action "kldload -n if_run"; }; +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0586"; + match "product" "0x3426"; + action "kldload -n if_rtwn_usb"; +}; + nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; @@ -1442,7 +1474,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x06f8"; match "product" "0xe033"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -1658,7 +1690,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x07aa"; match "product" "0x0056"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -1722,7 +1754,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x07b8"; match "product" "(0x8178|0x8179|0x8188|0x8189)"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -2026,7 +2058,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x0846"; match "product" "0x9021"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -2041,8 +2073,8 @@ nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; match "vendor" "0x0846"; - match "product" "0x9041"; - action "kldload -n if_urtwn"; + match "product" "(0x9041|0x9052)"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -2498,7 +2530,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x0b05"; match "product" "0x17ab"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -2522,7 +2554,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x0b05"; match "product" "0x17ba"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -2533,6 +2565,14 @@ nomatch 32 { action "kldload -n ng_ubt"; }; +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0b05"; + match "product" "0x17d2"; + action "kldload -n if_rtwn_usb"; +}; + nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; @@ -2658,7 +2698,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x0bda"; match "product" "(0x0179|0x018a|0x317f)"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -2682,7 +2722,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x0bda"; match "product" "0x8170"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -2698,7 +2738,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x0bda"; match "product" "(0x8176|0x8177|0x8178|0x8179|0x817a|0x817b|0x817c|0x817d|0x817e|0x817f)"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -2714,7 +2754,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x0bda"; match "product" "(0x818a|0x8191)"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -2738,7 +2778,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x0bda"; match "product" "0x8754"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -3162,7 +3202,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x0df6"; match "product" "0x0052"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -3178,7 +3218,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x0df6"; match "product" "(0x005c|0x0061)"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -3189,6 +3229,14 @@ nomatch 32 { action "kldload -n if_axge"; }; +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x0df6"; + match "product" "0x0074"; + action "kldload -n if_rtwn_usb"; +}; + nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; @@ -3257,8 +3305,8 @@ nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; match "vendor" "0x0e66"; - match "product" "0x0019"; - action "kldload -n if_urtwn"; + match "product" "(0x0019|0x0023)"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -3330,7 +3378,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x0eb0"; match "product" "0x9071"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -3490,7 +3538,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x103c"; match "product" "0x1629"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -3973,6 +4021,14 @@ nomatch 32 { action "kldload -n if_run"; }; +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x13b1"; + match "product" "0x003f"; + action "kldload -n if_rtwn_usb"; +}; + nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; @@ -4018,7 +4074,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x13d3"; match "product" "(0x3357|0x3358|0x3359)"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -4565,6 +4621,14 @@ nomatch 32 { action "kldload -n if_run"; }; +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x1740"; + match "product" "0x0100"; + action "kldload -n if_rtwn_usb"; +}; + nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; @@ -4961,8 +5025,8 @@ nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; match "vendor" "0x2001"; - match "product" "(0x3307|0x3308|0x3309|0x330a|0x330d|0x330f|0x3310)"; - action "kldload -n if_urtwn"; + match "product" "(0x3307|0x3308|0x3309|0x330a|0x330d|0x330f|0x3310|0x3314|0x3315|0x3316|0x3318)"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -5042,7 +5106,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x2019"; match "product" "(0x1201|0x4902)"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -5089,8 +5153,8 @@ nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; match "vendor" "0x2019"; - match "product" "(0xab2a|0xab2b|0xab2e)"; - action "kldload -n if_urtwn"; + match "product" "(0xab2a|0xab2b|0xab2e|0xab30)"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -5130,7 +5194,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x2019"; match "product" "0xed17"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -5170,7 +5234,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x20f4"; match "product" "0x624d"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -5185,8 +5249,8 @@ nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; match "vendor" "0x20f4"; - match "product" "0x648b"; - action "kldload -n if_urtwn"; + match "product" "(0x648b|0x805b)"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -5229,6 +5293,14 @@ nomatch 32 { action "kldload -n u3g"; }; +nomatch 32 { + match "bus" "uhub[0-9]+"; + match "mode" "host"; + match "vendor" "0x2357"; + match "product" "0x0101"; + action "kldload -n if_rtwn_usb"; +}; + nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; @@ -5354,7 +5426,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x4855"; match "product" "(0x0090|0x0091)"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -5465,8 +5537,8 @@ nomatch 32 { match "bus" "uhub[0-9]+"; match "mode" "host"; match "vendor" "0x7392"; - match "product" "(0x7811|0x7822)"; - action "kldload -n if_urtwn"; + match "product" "(0x7811|0x7822|0xa811|0xa812|0xa822)"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -5522,7 +5594,7 @@ nomatch 32 { match "mode" "host"; match "vendor" "0x9846"; match "product" "0x9041"; - action "kldload -n if_urtwn"; + action "kldload -n if_rtwn_usb"; }; nomatch 32 { @@ -5817,5 +5889,5 @@ nomatch 32 { action "kldload -n umass"; }; -# 2722 USB entries processed +# 2743 USB entries processed diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index bb8d849d4836..ea5791af17f5 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -396,6 +396,10 @@ .. file .. + fs + tmpfs + .. + .. geom class concat diff --git a/etc/rc b/etc/rc index 576ddf937af4..278c9de494c3 100644 --- a/etc/rc +++ b/etc/rc @@ -135,16 +135,16 @@ done # Note: this assumes firstboot_sentinel is on / when we have # a read-only /, or that it is on media that's writable. if [ -e ${firstboot_sentinel} ]; then - [ ${root_rw_mount} = "yes" ] || mount -uw / + [ ${root_rw_mount#[Yy][Ee][Ss]} = "" ] || mount -uw / chflags -R 0 ${firstboot_sentinel} rm -rf ${firstboot_sentinel} if [ -e ${firstboot_sentinel}-reboot ]; then chflags -R 0 ${firstboot_sentinel}-reboot rm -rf ${firstboot_sentinel}-reboot - [ ${root_rw_mount} = "yes" ] || mount -ur / + [ ${root_rw_mount#[Yy][Ee][Ss]} = "" ] || mount -ur / kill -INT 1 fi - [ ${root_rw_mount} = "yes" ] || mount -ur / + [ ${root_rw_mount#[Yy][Ee][Ss]} = "" ] || mount -ur / fi echo '' diff --git a/gnu/lib/Makefile b/gnu/lib/Makefile index fa2a6218f170..0e17c229ed23 100644 --- a/gnu/lib/Makefile +++ b/gnu/lib/Makefile @@ -2,26 +2,23 @@ .include -SUBDIR= csu libgcc libregex +SUBDIR= csu +SUBDIR+= libgcc SUBDIR.${MK_DIALOG}+= libdialog - -.if ${MK_GCC} != "no" -SUBDIR+= libgcov libgomp -.endif - -.if ${MK_SSP} != "no" -SUBDIR+= libssp -.endif - -.if ${MK_TESTS} != "no" -SUBDIR+= tests -.endif +SUBDIR.${MK_GCC}+= libgcov libgomp +SUBDIR.${MK_SSP}+= libssp +SUBDIR.${MK_TESTS}+= tests .if ${MK_BINUTILS} != "no" && ${MK_GDB} != "no" SUBDIR+= libreadline .endif +.if ${MK_GNU_DIFF} != "no" || ${MK_GNU_GREP} != "no" || \ + ${MK_GNU_GREP_COMPAT} != "no" || ${MK_GDB} != "no" +SUBDIR+= libregex +.endif + # libsupc++ uses libstdc++ headers, although 'make includes' should # have taken care of that already. .if ${MK_GNUCXX} != "no" diff --git a/gnu/usr.bin/Makefile b/gnu/usr.bin/Makefile index 8e42053c08ab..6ed33cd1295d 100644 --- a/gnu/usr.bin/Makefile +++ b/gnu/usr.bin/Makefile @@ -2,48 +2,25 @@ .include -SUBDIR= ${_binutils} \ - ${_cc} \ - diff \ - diff3 \ - ${_dtc} \ - ${_gdb} \ - ${_gperf} \ - grep \ - ${_groff} \ - ${_tests} - SUBDIR_DEPEND_gdb= ${_binutils} .if ${MK_CXX} != "no" -.if ${MK_GCC} != "no" -_gperf= gperf -.endif -.if ${MK_GROFF} != "no" -_groff= groff -.endif +SUBDIR.${MK_GCC}+= gperf +SUBDIR.${MK_GROFF}+= groff .endif -.if ${MK_GPL_DTC} != "no" -_dtc= dtc -.endif - -.if ${MK_TESTS} != "no" -_tests= tests -.endif +SUBDIR.${MK_BINUTILS}+= binutils +SUBDIR.${MK_DIALOG}+= dialog .if ${MK_BINUTILS} != "no" -_binutils= binutils -.if ${MK_GDB} != "no" -_gdb= gdb -.endif +SUBDIR.${MK_GDB}+= gdb .endif -.if ${MK_GCC} != "no" -_cc= cc -.endif - -SUBDIR.${MK_DIALOG}+= dialog +SUBDIR.${MK_GCC}+= cc +SUBDIR.${MK_GNU_DIFF}+= diff diff3 +SUBDIR.${MK_GNU_GREP}+= grep +SUBDIR.${MK_GPL_DTC}+= dtc +SUBDIR.${MK_TESTS}+= tests SUBDIR_PARALLEL= diff --git a/lib/libc/sys/kldsym.2 b/lib/libc/sys/kldsym.2 index 917a92ad210d..422feaa268fd 100644 --- a/lib/libc/sys/kldsym.2 +++ b/lib/libc/sys/kldsym.2 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 26, 2001 +.Dd October 17, 2016 .Dt KLDSYM 2 .Os .Sh NAME @@ -36,7 +36,7 @@ .In sys/param.h .In sys/linker.h .Ft int -.Fn kldsym "int fileid" "int command" "void *data" +.Fn kldsym "int fileid" "int cmd" "void *data" .Sh DESCRIPTION The .Fn kldsym @@ -48,7 +48,7 @@ If .Fa fileid is 0, all loaded modules are searched. Currently, the only -.Fa command +.Fa cmd implemented is .Dv KLDSYM_LOOKUP . .Pp @@ -96,7 +96,7 @@ system call will fail if: Invalid value in .Fa data->version or -.Fa command . +.Fa cmd . .It Bq Er ENOENT The .Fa fileid diff --git a/lib/libc/tests/Makefile b/lib/libc/tests/Makefile index 4ead70aceaa0..3e71350d82a9 100644 --- a/lib/libc/tests/Makefile +++ b/lib/libc/tests/Makefile @@ -8,7 +8,6 @@ TESTS_SUBDIRS= c063 TESTS_SUBDIRS+= db TESTS_SUBDIRS+= gen TESTS_SUBDIRS+= hash -TESTS_SUBDIRS+= iconv TESTS_SUBDIRS+= inet TESTS_SUBDIRS+= net TESTS_SUBDIRS+= nss @@ -26,6 +25,10 @@ TESTS_SUBDIRS+= ttyio SUBDIR_DEPEND_tls= tls_dso +.if ${MK_ICONV} != "no" +TESTS_SUBDIRS+= iconv +.endif + .if ${MK_LOCALES} != "no" TESTS_SUBDIRS+= locale .endif diff --git a/lib/libmd/md4.h b/lib/libmd/md4.h index 086a27b6ba22..b6e6ebab7e95 100644 --- a/lib/libmd/md4.h +++ b/lib/libmd/md4.h @@ -53,6 +53,12 @@ __BEGIN_DECLS #ifndef MD4End #define MD4End _libmd_MD4End #endif +#ifndef MD4Fd +#define MD4Fd _libmd_MD4Fd +#endif +#ifndef MD4FdChunk +#define MD4FdChunk _libmd_MD4FdChunk +#endif #ifndef MD4File #define MD4File _libmd_MD4File #endif @@ -68,6 +74,8 @@ void MD4Update(MD4_CTX *, const void *, unsigned int); void MD4Pad(MD4_CTX *); void MD4Final(unsigned char [16], MD4_CTX *); char * MD4End(MD4_CTX *, char *); +char * MD4Fd(int, char *); +char * MD4FdChunk(int, char *, off_t, off_t); char * MD4File(const char *, char *); char * MD4FileChunk(const char *, char *, off_t, off_t); char * MD4Data(const void *, unsigned int, char *); diff --git a/lib/libmd/md5.h b/lib/libmd/md5.h index 1d125a82c3dd..631dec819e79 100644 --- a/lib/libmd/md5.h +++ b/lib/libmd/md5.h @@ -25,6 +25,12 @@ #ifndef MD5End #define MD5End _libmd_MD5End #endif +#ifndef MD5Fd +#define MD5Fd _libmd_MD5Fd +#endif +#ifndef MD5FdChunk +#define MD5FdChunk _libmd_MD5FdChunk +#endif #ifndef MD5File #define MD5File _libmd_MD5File #endif @@ -37,13 +43,5 @@ #endif -#ifdef __cplusplus -#define static -#endif - #include - -#ifdef __cplusplus -#undef static -#endif #endif /* _MD5_H_ */ diff --git a/lib/libmd/mdXhl.c b/lib/libmd/mdXhl.c index 6ed214bce844..397c85bd5e2d 100644 --- a/lib/libmd/mdXhl.c +++ b/lib/libmd/mdXhl.c @@ -42,18 +42,18 @@ MDXEnd(MDX_CTX *ctx, char *buf) } char * -MDXFile(const char *filename, char *buf) +MDXFd(int fd, char *buf) { - return (MDXFileChunk(filename, buf, 0, 0)); + return MDXFdChunk(fd, buf, 0, 0); } char * -MDXFileChunk(const char *filename, char *buf, off_t ofs, off_t len) +MDXFdChunk(int fd, char *buf, off_t ofs, off_t len) { unsigned char buffer[16*1024]; MDX_CTX ctx; struct stat stbuf; - int fd, readrv, e; + int readrv, e; off_t remain; if (len < 0) { @@ -62,9 +62,6 @@ MDXFileChunk(const char *filename, char *buf, off_t ofs, off_t len) } MDXInit(&ctx); - fd = open(filename, O_RDONLY); - if (fd < 0) - return NULL; if (ofs != 0) { errno = 0; if (lseek(fd, ofs, SEEK_SET) != ofs || @@ -86,14 +83,33 @@ MDXFileChunk(const char *filename, char *buf, off_t ofs, off_t len) remain -= readrv; } error: - e = errno; - close(fd); - errno = e; if (readrv < 0) return NULL; return (MDXEnd(&ctx, buf)); } +char * +MDXFile(const char *filename, char *buf) +{ + return (MDXFileChunk(filename, buf, 0, 0)); +} + +char * +MDXFileChunk(const char *filename, char *buf, off_t ofs, off_t len) +{ + char *ret; + int e, fd; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + ret = MDXFdChunk(fd, buf, ofs, len); + e = errno; + close (fd); + errno = e; + return ret; +} + char * MDXData (const void *data, unsigned int len, char *buf) { diff --git a/lib/libmd/ripemd.h b/lib/libmd/ripemd.h index 778808f7c9f8..f7d0de013273 100644 --- a/lib/libmd/ripemd.h +++ b/lib/libmd/ripemd.h @@ -96,6 +96,12 @@ __BEGIN_DECLS #ifndef RIPEMD160_End #define RIPEMD160_End _libmd_RIPEMD160_End #endif +#ifndef RIPEMD160_Fd +#define RIPEMD160_Fd _libmd_RIPEMD160_Fd +#endif +#ifndef RIPEMD160_FdChunk +#define RIPEMD160_FdChunk _libmd_RIPEMD160_FdChunk +#endif #ifndef RIPEMD160_File #define RIPEMD160_File _libmd_RIPEMD160_File #endif @@ -121,6 +127,8 @@ void RIPEMD160_Update(RIPEMD160_CTX *c, const void *data, size_t len); void RIPEMD160_Final(unsigned char *md, RIPEMD160_CTX *c); char *RIPEMD160_End(RIPEMD160_CTX *, char *); +char *RIPEMD160_Fd(int, char *); +char *RIPEMD160_FdChunk(int, char *, off_t, off_t); char *RIPEMD160_File(const char *, char *); char *RIPEMD160_FileChunk(const char *, char *, off_t, off_t); char *RIPEMD160_Data(const void *, unsigned int, char *); diff --git a/lib/libmd/sha.h b/lib/libmd/sha.h index c608c5ba85b3..9e4a5c496657 100644 --- a/lib/libmd/sha.h +++ b/lib/libmd/sha.h @@ -94,6 +94,12 @@ __BEGIN_DECLS #ifndef SHA_End #define SHA_End _libmd_SHA_End #endif +#ifndef SHA_Fd +#define SHA_Fd _libmd_SHA_Fd +#endif +#ifndef SHA_FdChunk +#define SHA_FdChunk _libmd_SHA_FdChunk +#endif #ifndef SHA_File #define SHA_File _libmd_SHA_File #endif @@ -126,6 +132,12 @@ __BEGIN_DECLS #ifndef SHA1_End #define SHA1_End _libmd_SHA1_End #endif +#ifndef SHA1_Fd +#define SHA1_Fd _libmd_SHA1_Fd +#endif +#ifndef SHA1_FdChunk +#define SHA1_FdChunk _libmd_SHA1_FdChunk +#endif #ifndef SHA1_File #define SHA1_File _libmd_SHA1_File #endif @@ -150,6 +162,8 @@ void SHA_Init(SHA_CTX *c); void SHA_Update(SHA_CTX *c, const void *data, size_t len); void SHA_Final(unsigned char *md, SHA_CTX *c); char *SHA_End(SHA_CTX *, char *); +char *SHA_Fd(int, char *); +char *SHA_FdChunk(int, char *, off_t, off_t); char *SHA_File(const char *, char *); char *SHA_FileChunk(const char *, char *, off_t, off_t); char *SHA_Data(const void *, unsigned int, char *); @@ -158,6 +172,8 @@ void SHA1_Init(SHA_CTX *c); void SHA1_Update(SHA_CTX *c, const void *data, size_t len); void SHA1_Final(unsigned char *md, SHA_CTX *c); char *SHA1_End(SHA_CTX *, char *); +char *SHA1_Fd(int, char *); +char *SHA1_FdChunk(int, char *, off_t, off_t); char *SHA1_File(const char *, char *); char *SHA1_FileChunk(const char *, char *, off_t, off_t); char *SHA1_Data(const void *, unsigned int, char *); diff --git a/lib/libsysdecode/Makefile b/lib/libsysdecode/Makefile index 123ea49ca572..5e0590e912f8 100644 --- a/lib/libsysdecode/Makefile +++ b/lib/libsysdecode/Makefile @@ -5,20 +5,94 @@ PACKAGE=lib${LIB} LIB= sysdecode -SRCS= errno.c ioctl.c syscallnames.c utrace.c +SRCS= errno.c flags.c ioctl.c signal.c syscallnames.c utrace.c INCS= sysdecode.h +CFLAGS+= -I${.OBJDIR} CFLAGS+= -I${.CURDIR}/../../sys CFLAGS+= -I${.CURDIR}/../../libexec/rtld-elf -MAN+= sysdecode.3 \ +MAN= sysdecode.3 \ sysdecode_abi_to_freebsd_errno.3 \ + sysdecode_cap_rights.3 \ + sysdecode_enum.3 \ + sysdecode_fcntl_arg.3 \ sysdecode_ioctlname.3 \ + sysdecode_mask.3 \ + sysdecode_quotactl_cmd.3 \ + sysdecode_sigcode.3 \ + sysdecode_sockopt_name.3 \ sysdecode_syscallnames.3 \ sysdecode_utrace.3 -MLINKS+= sysdecode_abi_to_freebsd_errno.3 sysdecode_freebsd_to_abi_errno.3 +MLINKS= sysdecode_abi_to_freebsd_errno.3 sysdecode_freebsd_to_abi_errno.3 +MLINKS+=sysdecode_enum.3 sysdecode_acltype.3 \ + sysdecode_enum.3 sysdecode_atfd.3 \ + sysdecode_enum.3 sysdecode_extattrnamespace.3 \ + sysdecode_enum.3 sysdecode_fadvice.3 \ + sysdecode_enum.3 sysdecode_fcntl_cmd.3 \ + sysdecode_enum.3 sysdecode_idtype.3 \ + sysdecode_enum.3 sysdecode_ipproto.3 \ + sysdecode_enum.3 sysdecode_kldsym_cmd.3 \ + sysdecode_enum.3 sysdecode_kldunload_flags.3 \ + sysdecode_enum.3 sysdecode_lio_listio_mode.3 \ + sysdecode_enum.3 sysdecode_madvice.3 \ + sysdecode_enum.3 sysdecode_minherit_flags.3 \ + sysdecode_enum.3 sysdecode_msgctl_cmd.3 \ + sysdecode_enum.3 sysdecode_nfssvc_flags.3 \ + sysdecode_enum.3 sysdecode_prio_which.3 \ + sysdecode_enum.3 sysdecode_procctl_cmd.3 \ + sysdecode_enum.3 sysdecode_ptrace_request.3 \ + sysdecode_enum.3 sysdecode_rlimit.3 \ + sysdecode_enum.3 sysdecode_rtprio_function.3 \ + sysdecode_enum.3 sysdecode_scheduler_policy.3 \ + sysdecode_enum.3 sysdecode_semctl_cmd.3 \ + sysdecode_enum.3 sysdecode_shmctl_cmd.3 \ + sysdecode_enum.3 sysdecode_shutdown_how.3 \ + sysdecode_enum.3 sysdecode_sigbus_code.3 \ + sysdecode_enum.3 sysdecode_sigchld_code.3 \ + sysdecode_enum.3 sysdecode_sigfpe_code.3 \ + sysdecode_enum.3 sysdecode_sigill_code.3 \ + sysdecode_enum.3 sysdecode_signal.3 \ + sysdecode_enum.3 sysdecode_sigprocmask_how.3 \ + sysdecode_enum.3 sysdecode_sigsegv_code.3 \ + sysdecode_enum.3 sysdecode_sigtrap_code.3 \ + sysdecode_enum.3 sysdecode_sockaddr_family.3 \ + sysdecode_enum.3 sysdecode_socketdomain.3 \ + sysdecode_enum.3 sysdecode_sockettype.3 \ + sysdecode_enum.3 sysdecode_sockopt_level.3 \ + sysdecode_enum.3 sysdecode_umtx_op.3 \ + sysdecode_enum.3 sysdecode_vmresult.3 \ + sysdecode_enum.3 sysdecode_whence.3 +MLINKS+=sysdecode_fcntl_arg.3 sysdecode_fcntl_arg_p.3 +MLINKS+=sysdecode_mask.3 sysdecode_accessmode.3 \ + sysdecode_mask.3 sysdecode_capfcntlrights.3 \ + sysdecode_mask.3 sysdecode_fcntl_fileflags.3 \ + sysdecode_mask.3 sysdecode_fileflags.3 \ + sysdecode_mask.3 sysdecode_filemode.3 \ + sysdecode_mask.3 sysdecode_flock_operation.3 \ + sysdecode_mask.3 sysdecode_getfsstat_flags.3 \ + sysdecode_mask.3 sysdecode_mlockall_flags.3 \ + sysdecode_mask.3 sysdecode_mmap_flags.3 \ + sysdecode_mask.3 sysdecode_mmap_prot.3 \ + sysdecode_mask.3 sysdecode_mount_flags.3 \ + sysdecode_mask.3 sysdecode_msg_flags.3 \ + sysdecode_mask.3 sysdecode_msync_flags.3 \ + sysdecode_mask.3 sysdecode_open_flags.3 \ + sysdecode_mask.3 sysdecode_pipe2_flags.3 \ + sysdecode_mask.3 sysdecode_reboot_howto.3 \ + sysdecode_mask.3 sysdecode_rfork_flags.3 \ + sysdecode_mask.3 sysdecode_semget_flags.3 \ + sysdecode_mask.3 sysdecode_sendfile_flags.3 \ + sysdecode_mask.3 sysdecode_shmat_flags.3 \ + sysdecode_mask.3 sysdecode_socket_type.3 \ + sysdecode_mask.3 sysdecode_thr_create_flags.3 \ + sysdecode_mask.3 sysdecode_umtx_cvwait_flags.3 \ + sysdecode_mask.3 sysdecode_umtx_rwlock_flags.3 \ + sysdecode_mask.3 sysdecode_vmprot.3 \ + sysdecode_mask.3 sysdecode_wait4_options.3 \ + sysdecode_mask.3 sysdecode_wait6_options.3 -CLEANFILES= ioctl.c +CLEANFILES= ioctl.c tables.h .if defined(COMPAT_32BIT) CPP+= -m32 @@ -36,10 +110,13 @@ CFLAGS.gcc.ioctl.c+= -Wno-unused CFLAGS.gcc+= ${CFLAGS.gcc.${.IMPSRC}} +tables.h: mktables + sh ${.CURDIR}/mktables ${DESTDIR}${INCLUDEDIR} > ${.TARGET} + ioctl.c: mkioctls env MACHINE=${MACHINE} CPP="${CPP}" \ /bin/sh ${.CURDIR}/mkioctls ${DESTDIR}${INCLUDEDIR} > ${.TARGET} -beforedepend: ioctl.c +beforedepend: ioctl.c tables.h .include diff --git a/lib/libsysdecode/errno.c b/lib/libsysdecode/errno.c index c21d21616ba3..9f404e0af0b2 100644 --- a/lib/libsysdecode/errno.c +++ b/lib/libsysdecode/errno.c @@ -28,8 +28,11 @@ __FBSDID("$FreeBSD$"); #include +#include +#include #include #include +#include #include #include diff --git a/lib/libsysdecode/flags.c b/lib/libsysdecode/flags.c new file mode 100644 index 000000000000..3a705c7e9c5f --- /dev/null +++ b/lib/libsysdecode/flags.c @@ -0,0 +1,982 @@ +/* + * Copyright (c) 2006 "David Kirchner" . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#define L2CAP_SOCKET_CHECKED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This is taken from the xlat tables originally in truss which were + * in turn taken from strace. + */ +struct name_table { + uintmax_t val; + const char *str; +}; + +#define X(a) { a, #a }, +#define XEND { 0, NULL } + +#define TABLE_START(n) static struct name_table n[] = { +#define TABLE_ENTRY X +#define TABLE_END XEND }; + +#include "tables.h" + +#undef TABLE_START +#undef TABLE_ENTRY +#undef TABLE_END + +/* + * These are simple support macros. print_or utilizes a variable + * defined in the calling function to track whether or not it should + * print a logical-OR character ('|') before a string. if_print_or + * simply handles the necessary "if" statement used in many lines + * of this file. + */ +#define print_or(fp,str,orflag) do { \ + if (orflag) fputc(fp, '|'); else orflag = true; \ + fprintf(fp, str); } \ + while (0) +#define if_print_or(fp,i,flag,orflag) do { \ + if ((i & flag) == flag) \ + print_or(fp,#flag,orflag); } \ + while (0) + +static const char * +lookup_value(struct name_table *table, uintmax_t val) +{ + + for (; table->str != NULL; table++) + if (table->val == val) + return (table->str); + return (NULL); +} + +/* + * Used when the value maps to a bitmask of #definition values in the + * table. This is a helper routine which outputs a symbolic mask of + * matched masks. Multiple masks are separated by a pipe ('|'). + * The value is modified on return to only hold unmatched bits. + */ +static void +print_mask_part(FILE *fp, struct name_table *table, uintmax_t *valp, + bool *printed) +{ + uintmax_t rem; + + rem = *valp; + for (; table->str != NULL; table++) { + if ((table->val & rem) == table->val) { + /* + * Only print a zero mask if the raw value is + * zero. + */ + if (table->val == 0 && *valp != 0) + continue; + fprintf(fp, "%s%s", *printed ? "|" : "", table->str); + *printed = true; + rem &= ~table->val; + } + } + + *valp = rem; +} + +/* + * Used when the value maps to a bitmask of #definition values in the + * table. The return value is true if something was printed. If + * rem is not NULL, *rem holds any bits not decoded if something was + * printed. If nothing was printed and rem is not NULL, *rem holds + * the original value. + */ +static bool +print_mask_int(FILE *fp, struct name_table *table, int ival, int *rem) +{ + uintmax_t val; + bool printed; + + printed = false; + val = (unsigned)ival; + print_mask_part(fp, table, &val, &printed); + if (rem != NULL) + *rem = val; + return (printed); +} + +/* + * Used for a mask of optional flags where a value of 0 is valid. + */ +static bool +print_mask_0(FILE *fp, struct name_table *table, int val, int *rem) +{ + + if (val == 0) { + fputs("0", fp); + if (rem != NULL) + *rem = 0; + return (true); + } + return (print_mask_int(fp, table, val, rem)); +} + +/* + * Like print_mask_0 but for a unsigned long instead of an int. + */ +static bool +print_mask_0ul(FILE *fp, struct name_table *table, u_long lval, u_long *rem) +{ + uintmax_t val; + bool printed; + + if (lval == 0) { + fputs("0", fp); + if (rem != NULL) + *rem = 0; + return (true); + } + + printed = false; + val = lval; + print_mask_part(fp, table, &val, &printed); + if (rem != NULL) + *rem = val; + return (printed); +} + +static void +print_integer(FILE *fp, int val, int base) +{ + + switch (base) { + case 8: + fprintf(fp, "0%o", val); + break; + case 10: + fprintf(fp, "%d", val); + break; + case 16: + fprintf(fp, "0x%x", val); + break; + default: + abort2("bad base", 0, NULL); + break; + } +} + +static bool +print_value(FILE *fp, struct name_table *table, uintmax_t val) +{ + const char *str; + + str = lookup_value(table, val); + if (str != NULL) { + fputs(str, fp); + return (true); + } + return (false); +} + +const char * +sysdecode_atfd(int fd) +{ + + if (fd == AT_FDCWD) + return ("AT_FDCWD"); + return (NULL); +} + +static struct name_table semctlops[] = { + X(GETNCNT) X(GETPID) X(GETVAL) X(GETALL) X(GETZCNT) X(SETVAL) X(SETALL) + X(IPC_RMID) X(IPC_SET) X(IPC_STAT) XEND +}; + +const char * +sysdecode_semctl_cmd(int cmd) +{ + + return (lookup_value(semctlops, cmd)); +} + +static struct name_table shmctlops[] = { + X(IPC_RMID) X(IPC_SET) X(IPC_STAT) XEND +}; + +const char * +sysdecode_shmctl_cmd(int cmd) +{ + + return (lookup_value(shmctlops, cmd)); +} + +const char * +sysdecode_msgctl_cmd(int cmd) +{ + + return (sysdecode_shmctl_cmd(cmd)); +} + +static struct name_table semgetflags[] = { + X(IPC_CREAT) X(IPC_EXCL) X(SEM_R) X(SEM_A) X((SEM_R>>3)) X((SEM_A>>3)) + X((SEM_R>>6)) X((SEM_A>>6)) XEND +}; + +bool +sysdecode_semget_flags(FILE *fp, int flag, int *rem) +{ + + return (print_mask_int(fp, semgetflags, flag, rem)); +} + +static struct name_table idtypes[] = { + X(P_PID) X(P_PPID) X(P_PGID) X(P_SID) X(P_CID) X(P_UID) X(P_GID) + X(P_ALL) X(P_LWPID) X(P_TASKID) X(P_PROJID) X(P_POOLID) X(P_JAILID) + X(P_CTID) X(P_CPUID) X(P_PSETID) XEND +}; + +/* XXX: idtype is really an idtype_t */ +const char * +sysdecode_idtype(int idtype) +{ + + return (lookup_value(idtypes, idtype)); +} + +/* + * [g|s]etsockopt's level argument can either be SOL_SOCKET or a + * protocol-specific value. + */ +const char * +sysdecode_sockopt_level(int level) +{ + const char *str; + + if (level == SOL_SOCKET) + return ("SOL_SOCKET"); + + /* SOL_* constants for Bluetooth sockets. */ + str = lookup_value(ngbtsolevel, level); + if (str != NULL) + return (str); + + /* + * IP and Infiniband sockets use IP protocols as levels. Not all + * protocols are valid but it is simpler to just allow all of them. + * + * XXX: IPPROTO_IP == 0, but UNIX domain sockets use a level of 0 + * for private options. + */ + str = sysdecode_ipproto(level); + if (str != NULL) + return (str); + + return (NULL); +} + +bool +sysdecode_vmprot(FILE *fp, int type, int *rem) +{ + + return (print_mask_int(fp, vmprot, type, rem)); +} + +static struct name_table sockflags[] = { + X(SOCK_CLOEXEC) X(SOCK_NONBLOCK) XEND +}; + +bool +sysdecode_socket_type(FILE *fp, int type, int *rem) +{ + const char *str; + uintmax_t val; + bool printed; + + str = lookup_value(socktype, type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)); + if (str != NULL) { + fputs(str, fp); + *rem = 0; + printed = true; + } else { + *rem = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK); + printed = false; + } + val = type & (SOCK_CLOEXEC | SOCK_NONBLOCK); + print_mask_part(fp, sockflags, &val, &printed); + return (printed); +} + +bool +sysdecode_access_mode(FILE *fp, int mode, int *rem) +{ + + return (print_mask_int(fp, accessmode, mode, rem)); +} + +/* XXX: 'type' is really an acl_type_t. */ +const char * +sysdecode_acltype(int type) +{ + + return (lookup_value(acltype, type)); +} + +bool +sysdecode_cap_fcntlrights(FILE *fp, uint32_t rights, uint32_t *rem) +{ + + return (print_mask_int(fp, capfcntl, rights, rem)); +} + +const char * +sysdecode_extattrnamespace(int namespace) +{ + + return (lookup_value(extattrns, namespace)); +} + +const char * +sysdecode_fadvice(int advice) +{ + + return (lookup_value(fadvisebehav, advice)); +} + +bool +sysdecode_open_flags(FILE *fp, int flags, int *rem) +{ + bool printed; + int mode; + uintmax_t val; + + mode = flags & O_ACCMODE; + flags &= ~O_ACCMODE; + switch (mode) { + case O_RDONLY: + if (flags & O_EXEC) { + flags &= ~O_EXEC; + fputs("O_EXEC", fp); + } else + fputs("O_RDONLY", fp); + printed = true; + mode = 0; + break; + case O_WRONLY: + fputs("O_WRONLY", fp); + printed = true; + mode = 0; + break; + case O_RDWR: + fputs("O_RDWR", fp); + printed = true; + mode = 0; + break; + default: + printed = false; + } + val = (unsigned)flags; + print_mask_part(fp, openflags, &val, &printed); + if (rem != NULL) + *rem = val | mode; + return (printed); +} + +bool +sysdecode_fcntl_fileflags(FILE *fp, int flags, int *rem) +{ + bool printed; + int oflags; + + /* + * The file flags used with F_GETFL/F_SETFL mostly match the + * flags passed to open(2). However, a few open-only flag + * bits have been repurposed for fcntl-only flags. + */ + oflags = flags & ~(O_NOFOLLOW | FRDAHEAD); + printed = sysdecode_open_flags(fp, oflags, rem); + if (flags & O_NOFOLLOW) { + fprintf(fp, "%sFPOIXSHM", printed ? "|" : ""); + printed = true; + } + if (flags & FRDAHEAD) { + fprintf(fp, "%sFRDAHEAD", printed ? "|" : ""); + printed = true; + } + return (printed); +} + +bool +sysdecode_flock_operation(FILE *fp, int operation, int *rem) +{ + + return (print_mask_int(fp, flockops, operation, rem)); +} + +bool +sysdecode_getfsstat_flags(FILE *fp, int flags, int *rem) +{ + + return (print_mask_int(fp, getfsstatflags, flags, rem)); +} + +const char * +sysdecode_kldsym_cmd(int cmd) +{ + + return (lookup_value(kldsymcmd, cmd)); +} + +const char * +sysdecode_kldunload_flags(int flags) +{ + + return (lookup_value(kldunloadfflags, flags)); +} + +const char * +sysdecode_lio_listio_mode(int mode) +{ + + return (lookup_value(lio_listiomodes, mode)); +} + +const char * +sysdecode_madvice(int advice) +{ + + return (lookup_value(madvisebehav, advice)); +} + +const char * +sysdecode_minherit_inherit(int inherit) +{ + + return (lookup_value(minheritflags, inherit)); +} + +bool +sysdecode_mlockall_flags(FILE *fp, int flags, int *rem) +{ + + return (print_mask_int(fp, mlockallflags, flags, rem)); +} + +bool +sysdecode_mmap_prot(FILE *fp, int prot, int *rem) +{ + + return (print_mask_int(fp, mmapprot, prot, rem)); +} + +bool +sysdecode_fileflags(FILE *fp, fflags_t flags, fflags_t *rem) +{ + + return (print_mask_0(fp, fileflags, flags, rem)); +} + +bool +sysdecode_filemode(FILE *fp, int mode, int *rem) +{ + + return (print_mask_0(fp, filemode, mode, rem)); +} + +bool +sysdecode_mount_flags(FILE *fp, int flags, int *rem) +{ + + return (print_mask_int(fp, mountflags, flags, rem)); +} + +bool +sysdecode_msync_flags(FILE *fp, int flags, int *rem) +{ + + return (print_mask_int(fp, msyncflags, flags, rem)); +} + +const char * +sysdecode_nfssvc_flags(int flags) +{ + + return (lookup_value(nfssvcflags, flags)); +} + +static struct name_table pipe2flags[] = { + X(O_CLOEXEC) X(O_NONBLOCK) XEND +}; + +bool +sysdecode_pipe2_flags(FILE *fp, int flags, int *rem) +{ + + return (print_mask_0(fp, pipe2flags, flags, rem)); +} + +const char * +sysdecode_prio_which(int which) +{ + + return (lookup_value(prio, which)); +} + +const char * +sysdecode_procctl_cmd(int cmd) +{ + + return (lookup_value(procctlcmd, cmd)); +} + +const char * +sysdecode_ptrace_request(int request) +{ + + return (lookup_value(ptraceop, request)); +} + +static struct name_table quotatypes[] = { + X(GRPQUOTA) X(USRQUOTA) XEND +}; + +bool +sysdecode_quotactl_cmd(FILE *fp, int cmd) +{ + const char *primary, *type; + + primary = lookup_value(quotactlcmds, cmd >> SUBCMDSHIFT); + if (primary == NULL) + return (false); + fprintf(fp, "QCMD(%s,", primary); + type = lookup_value(quotatypes, cmd & SUBCMDMASK); + if (type != NULL) + fprintf(fp, "%s", type); + else + fprintf(fp, "%#x", cmd & SUBCMDMASK); + fprintf(fp, ")"); + return (true); +} + +bool +sysdecode_reboot_howto(FILE *fp, int howto, int *rem) +{ + + return (print_mask_int(fp, rebootopt, howto, rem)); +} + +bool +sysdecode_rfork_flags(FILE *fp, int flags, int *rem) +{ + + return (print_mask_int(fp, rforkflags, flags, rem)); +} + +const char * +sysdecode_rlimit(int resource) +{ + + return (lookup_value(rlimit, resource)); +} + +const char * +sysdecode_scheduler_policy(int policy) +{ + + return (lookup_value(schedpolicy, policy)); +} + +bool +sysdecode_sendfile_flags(FILE *fp, int flags, int *rem) +{ + + return (print_mask_int(fp, sendfileflags, flags, rem)); +} + +bool +sysdecode_shmat_flags(FILE *fp, int flags, int *rem) +{ + + return (print_mask_int(fp, shmatflags, flags, rem)); +} + +const char * +sysdecode_shutdown_how(int how) +{ + + return (lookup_value(shutdownhow, how)); +} + +const char * +sysdecode_sigbus_code(int si_code) +{ + + return (lookup_value(sigbuscode, si_code)); +} + +const char * +sysdecode_sigchld_code(int si_code) +{ + + return (lookup_value(sigchldcode, si_code)); +} + +const char * +sysdecode_sigfpe_code(int si_code) +{ + + return (lookup_value(sigfpecode, si_code)); +} + +const char * +sysdecode_sigill_code(int si_code) +{ + + return (lookup_value(sigillcode, si_code)); +} + +const char * +sysdecode_sigsegv_code(int si_code) +{ + + return (lookup_value(sigsegvcode, si_code)); +} + +const char * +sysdecode_sigtrap_code(int si_code) +{ + + return (lookup_value(sigtrapcode, si_code)); +} + +const char * +sysdecode_sigprocmask_how(int how) +{ + + return (lookup_value(sigprocmaskhow, how)); +} + +const char * +sysdecode_socketdomain(int domain) +{ + + return (lookup_value(sockdomain, domain)); +} + +const char * +sysdecode_sockaddr_family(int sa_family) +{ + + return (lookup_value(sockfamily, sa_family)); +} + +const char * +sysdecode_ipproto(int protocol) +{ + + return (lookup_value(sockipproto, protocol)); +} + +const char * +sysdecode_sockopt_name(int level, int optname) +{ + + if (level == SOL_SOCKET) + return (lookup_value(sockopt, optname)); + if (level == IPPROTO_IP) + /* XXX: UNIX domain socket options use a level of 0 also. */ + return (lookup_value(sockoptip, optname)); + if (level == IPPROTO_TCP) + return (lookup_value(sockopttcp, optname)); + if (level == IPPROTO_UDP) + return (lookup_value(sockoptudp, optname)); + return (NULL); +} + +bool +sysdecode_thr_create_flags(FILE *fp, int flags, int *rem) +{ + + return (print_mask_int(fp, thrcreateflags, flags, rem)); +} + +const char * +sysdecode_umtx_op(int op) +{ + + return (lookup_value(umtxop, op)); +} + +const char * +sysdecode_vmresult(int result) +{ + + return (lookup_value(vmresult, result)); +} + +bool +sysdecode_wait4_options(FILE *fp, int options, int *rem) +{ + bool printed; + int opt6; + + /* A flags value of 0 is normal. */ + if (options == 0) { + fputs("0", fp); + if (rem != NULL) + *rem = 0; + return (true); + } + + /* + * These flags are implicit and aren't valid flags for wait4() + * directly (though they don't fail with EINVAL). + */ + opt6 = options & (WEXITED | WTRAPPED); + options &= ~opt6; + printed = print_mask_int(fp, wait6opt, options, rem); + if (rem != NULL) + *rem |= opt6; + return (printed); +} + +bool +sysdecode_wait6_options(FILE *fp, int options, int *rem) +{ + + return (print_mask_int(fp, wait6opt, options, rem)); +} + +const char * +sysdecode_whence(int whence) +{ + + return (lookup_value(seekwhence, whence)); +} + +const char * +sysdecode_fcntl_cmd(int cmd) +{ + + return (lookup_value(fcntlcmd, cmd)); +} + +static struct name_table fcntl_fd_arg[] = { + X(FD_CLOEXEC) X(0) XEND +}; + +bool +sysdecode_fcntl_arg_p(int cmd) +{ + + switch (cmd) { + case F_GETFD: + case F_GETFL: + case F_GETOWN: + return (false); + default: + return (true); + } +} + +void +sysdecode_fcntl_arg(FILE *fp, int cmd, uintptr_t arg, int base) +{ + int rem; + + switch (cmd) { + case F_SETFD: + if (!print_value(fp, fcntl_fd_arg, arg)) + print_integer(fp, arg, base); + break; + case F_SETFL: + if (!sysdecode_fcntl_fileflags(fp, arg, &rem)) + fprintf(fp, "%#x", rem); + else if (rem != 0) + fprintf(fp, "|%#x", rem); + break; + case F_GETLK: + case F_SETLK: + case F_SETLKW: + fprintf(fp, "%p", (void *)arg); + break; + default: + print_integer(fp, arg, base); + break; + } +} + +bool +sysdecode_mmap_flags(FILE *fp, int flags, int *rem) +{ + uintmax_t val; + bool printed; + int align; + + /* + * MAP_ALIGNED can't be handled directly by print_mask_int(). + * MAP_32BIT is also problematic since it isn't defined for + * all platforms. + */ + printed = false; + align = flags & MAP_ALIGNMENT_MASK; + val = (unsigned)flags & ~MAP_ALIGNMENT_MASK; + print_mask_part(fp, mmapflags, &val, &printed); +#ifdef MAP_32BIT + if (val & MAP_32BIT) { + fprintf(fp, "%sMAP_32BIT", printed ? "|" : ""); + printed = true; + val &= ~MAP_32BIT; + } +#endif + if (align != 0) { + if (printed) + fputc('|', fp); + if (align == MAP_ALIGNED_SUPER) + fputs("MAP_ALIGNED_SUPER", fp); + else + fprintf(fp, "MAP_ALIGNED(%d)", + align >> MAP_ALIGNMENT_SHIFT); + printed = true; + } + if (rem != NULL) + *rem = val; + return (printed); +} + +const char * +sysdecode_rtprio_function(int function) +{ + + return (lookup_value(rtpriofuncs, function)); +} + +bool +sysdecode_msg_flags(FILE *fp, int flags, int *rem) +{ + + return (print_mask_0(fp, msgflags, flags, rem)); +} + +const char * +sysdecode_sigcode(int sig, int si_code) +{ + const char *str; + + str = lookup_value(sigcode, si_code); + if (str != NULL) + return (str); + + switch (sig) { + case SIGILL: + return (sysdecode_sigill_code(si_code)); + case SIGBUS: + return (sysdecode_sigbus_code(si_code)); + case SIGSEGV: + return (sysdecode_sigsegv_code(si_code)); + case SIGFPE: + return (sysdecode_sigfpe_code(si_code)); + case SIGTRAP: + return (sysdecode_sigtrap_code(si_code)); + case SIGCHLD: + return (sysdecode_sigchld_code(si_code)); + default: + return (NULL); + } +} + +bool +sysdecode_umtx_cvwait_flags(FILE *fp, u_long flags, u_long *rem) +{ + + return (print_mask_0ul(fp, umtxcvwaitflags, flags, rem)); +} + +bool +sysdecode_umtx_rwlock_flags(FILE *fp, u_long flags, u_long *rem) +{ + + return (print_mask_0ul(fp, umtxrwlockflags, flags, rem)); +} + +/* XXX: This should be in */ +#define CAPMASK(right) ((right) && (((uint64_t)1 << 57) - 1)) + +void +sysdecode_cap_rights(FILE *fp, cap_rights_t *rightsp) +{ + struct name_table *t; + int idx; + bool comma; + + comma = false; + for (t = caprights; t->str != NULL; t++) { + idx = ffs(CAPIDXBIT(t->val)) - 1; + if (CAPARSIZE(rightsp) < idx) + continue; + if ((rightsp->cr_rights[CAPIDXBIT(t->val)] & CAPMASK(t->val)) == + CAPMASK(t->val)) { + fprintf(fp, "%s%s", comma ? "," : "", t->str); + comma = true; + } + } +} diff --git a/lib/libsysdecode/mkioctls b/lib/libsysdecode/mkioctls index e174d30928bd..b99ff19f2486 100644 --- a/lib/libsysdecode/mkioctls +++ b/lib/libsysdecode/mkioctls @@ -62,6 +62,7 @@ BEGIN { print "#include " print "#include " print "#include " + print "#include " print "#include " print "#include " print "#include " diff --git a/lib/libsysdecode/mktables b/lib/libsysdecode/mktables new file mode 100644 index 000000000000..0cc2ff3dc770 --- /dev/null +++ b/lib/libsysdecode/mktables @@ -0,0 +1,144 @@ +#!/bin/sh +# +# Copyright (c) 2006 "David Kirchner" . All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +# +# $FreeBSD$ +# +# Generates tables.h +# +# Originally this script was 'mksubr' for kdump which generated a complete +# C file along with function definitions. Now this script generates tables +# of constants and names extracted from header files. + +set -e + +LC_ALL=C; export LC_ALL + +if [ -z "$1" ] +then + echo "usage: sh $0 include-dir" + exit 1 +fi +include_dir=$1 + +# +# Generate a table C #definitions. The including file can define the +# TABLE_NAME(n), TABLE_ENTRY(x), and TABLE_END macros to define what +# the tables map to. +# +gen_table() +{ + local name grep file excl filter + name=$1 + grep=$2 + file=$3 + excl=$4 + + if [ -z "$excl" ]; then + filter="cat" + else + filter="egrep -v" + fi + cat <<_EOF_ +TABLE_START(${name}) +_EOF_ + egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \ + $include_dir/$file | ${filter} ${excl} | \ + awk '{ for (i = 1; i <= NF; i++) \ + if ($i ~ /define/) \ + break; \ + ++i; \ + printf "TABLE_ENTRY(%s)\n", $i }' +cat <<_EOF_ +TABLE_END + +_EOF_ +} + +cat <<_EOF_ +/* This file is auto-generated. */ + +_EOF_ + +gen_table "accessmode" "[A-Z]_OK[[:space:]]+0?x?[0-9A-Fa-f]+" "sys/unistd.h" +gen_table "acltype" "ACL_TYPE_[A-Z4_]+[[:space:]]+0x[0-9]+" "sys/acl.h" +gen_table "capfcntl" "CAP_FCNTL_[A-Z]+[[:space:]]+\(1" "sys/capsicum.h" +gen_table "extattrns" "EXTATTR_NAMESPACE_[A-Z]+[[:space:]]+0x[0-9]+" "sys/extattr.h" +gen_table "fadvisebehav" "POSIX_FADV_[A-Z]+[[:space:]]+[0-9]+" "sys/fcntl.h" +gen_table "openflags" "O_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/fcntl.h" "O_RDONLY|O_RDWR|O_WRONLY" +gen_table "flockops" "LOCK_[A-Z]+[[:space:]]+0x[0-9]+" "sys/fcntl.h" +gen_table "getfsstatflags" "MNT_[A-Z]+[[:space:]]+[1-9][0-9]*" "sys/mount.h" +gen_table "kldsymcmd" "KLDSYM_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h" +gen_table "kldunloadfflags" "LINKER_UNLOAD_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h" +gen_table "lio_listiomodes" "LIO_(NO)?WAIT[[:space:]]+[0-9]+" "aio.h" +gen_table "madvisebehav" "_?MADV_[A-Z]+[[:space:]]+[0-9]+" "sys/mman.h" +gen_table "minheritflags" "INHERIT_[A-Z]+[[:space:]]+[0-9]+" "sys/mman.h" +gen_table "mlockallflags" "MCL_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mman.h" +gen_table "mmapprot" "PROT_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/mman.h" +gen_table "ngbtsolevel" "SOL_[A-Z0-9]+[[:space:]]+0x[0-9A-Fa-f]+" "netgraph/bluetooth/include/ng_btsocket.h" +gen_table "fileflags" "[SU]F_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/stat.h" "UF_COMPRESSED|UF_TRACKED|UF_SETTABLE|SF_SETTABLE" +gen_table "filemode" "S_[A-Z]+[[:space:]]+[0-6]{7}" "sys/stat.h" +gen_table "mountflags" "MNT_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mount.h" +gen_table "msyncflags" "MS_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mman.h" +gen_table "nfssvcflags" "NFSSVC_[A-Z0-9]+[[:space:]]+0x[0-9]+" "nfs/nfssvc.h" +gen_table "prio" "PRIO_[A-Z]+[[:space:]]+[0-9]" "sys/resource.h" +gen_table "procctlcmd" "PROC_[A-Z_]+[[:space:]]+[0-9]" "sys/procctl.h" "PROC_TRACE_CTL_" +gen_table "ptraceop" "PT_[[:alnum:]_]+[[:space:]]+[0-9]+" "sys/ptrace.h" +gen_table "quotactlcmds" "Q_[A-Z]+[[:space:]]+0x[0-9]+" "ufs/ufs/quota.h" +gen_table "rebootopt" "RB_[A-Z]+[[:space:]]+0x[0-9]+" "sys/reboot.h" +gen_table "rforkflags" "RF[A-Z]+[[:space:]]+\([0-9]+<<[0-9]+\)" "sys/unistd.h" +gen_table "rlimit" "RLIMIT_[A-Z]+[[:space:]]+[0-9]+" "sys/resource.h" +gen_table "schedpolicy" "SCHED_[A-Z]+[[:space:]]+[0-9]+" "sched.h" +gen_table "sendfileflags" "SF_[A-Z]+[[:space:]]+[0-9]+" "sys/socket.h" +gen_table "shmatflags" "SHM_[A-Z]+[[:space:]]+[0-9]{6}+" "sys/shm.h" +gen_table "shutdownhow" "SHUT_[A-Z]+[[:space:]]+[0-9]+" "sys/socket.h" +gen_table "sigbuscode" "BUS_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" +gen_table "sigchldcode" "CLD_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" +gen_table "sigfpecode" "FPE_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" +gen_table "sigprocmaskhow" "SIG_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" +gen_table "sigillcode" "ILL_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" +gen_table "sigsegvcode" "SEGV_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" +gen_table "sigtrapcode" "TRAP_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" +gen_table "sockdomain" "PF_[[:alnum:]]+[[:space:]]+" "sys/socket.h" +gen_table "sockfamily" "AF_[[:alnum:]]+[[:space:]]+" "sys/socket.h" +gen_table "sockipproto" "IPPROTO_[[:alnum:]]+[[:space:]]+" "netinet/in.h" +gen_table "sockopt" "SO_[A-Z]+[[:space:]]+0x[0-9]+" "sys/socket.h" +gen_table "sockoptip" "(IP_[[:alnum:]_]+|MCAST_[[:alnum:]_]+_GROUP)[[:space:]]+" "netinet/in.h" "IP_DEFAULT|IP_MIN|IP_MAX|IP_PORTRANGE" +gen_table "sockopttcp" "TCP_[[:alnum:]_]+[[:space:]]+[0-9]+" "netinet/tcp.h" "TCP_MIN|TCP_MAX[^S]|TCP_MSS|TCP_[[:alnum:]_]+_MAX" +gen_table "sockoptudp" "UDP_[[:alnum:]]+[[:space:]]+[0-9]+" "netinet/udp.h" "UDP_ENCAP_" +gen_table "socktype" "SOCK_[A-Z]+[[:space:]]+[1-9]+[0-9]*" "sys/socket.h" +gen_table "thrcreateflags" "THR_[A-Z]+[[:space:]]+0x[0-9]+" "sys/thr.h" +gen_table "umtxop" "UMTX_OP_[[:alnum:]_]+[[:space:]]+[0-9]+" "sys/umtx.h" +gen_table "vmprot" "VM_PROT_[A-Z]+[[:space:]]+\(\(vm_prot_t\)\)" "vm/vm.h" +gen_table "vmresult" "KERN_[A-Z]+[[:space:]]+[0-9]+" "vm/vm_param.h" +gen_table "wait6opt" "W[A-Z]+[[:space:]]+[0-9]+" "sys/wait.h" +gen_table "seekwhence" "SEEK_[A-Z]+[[:space:]]+[0-9]+" "sys/unistd.h" +gen_table "fcntlcmd" "F_[A-Z0-9_]+[[:space:]]+[0-9]+[[:space:]]+" "sys/fcntl.h" "F_CANCEL|F_..LCK" +gen_table "mmapflags" "MAP_[A-Z_]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/mman.h" +gen_table "rtpriofuncs" "RTP_[A-Z]+[[:space:]]+[0-9]+" "sys/rtprio.h" +gen_table "msgflags" "MSG_[A-Z]+[[:space:]]+0x[0-9]+" "sys/socket.h" "MSG_SOCALLBCK" +gen_table "sigcode" "SI_[A-Z]+[[:space:]]+0(x[0-9abcdef]+)?" "sys/signal.h" +gen_table "umtxcvwaitflags" "CVWAIT_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/umtx.h" +gen_table "umtxrwlockflags" "URWLOCK_PREFER_READER[[:space:]]+0x[0-9]+" "sys/umtx.h" +gen_table "caprights" "CAP_[A-Z_]+[[:space:]]+CAPRIGHT\([0-9],[[:space:]]+0x[0-9]{16}ULL\)" "sys/capsicum.h" diff --git a/lib/libsysdecode/signal.c b/lib/libsysdecode/signal.c new file mode 100644 index 000000000000..e764a5a35155 --- /dev/null +++ b/lib/libsysdecode/signal.c @@ -0,0 +1,143 @@ +/*- + * Copyright (c) 2016 John H. Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +static const char *signames[] = { + [SIGHUP] = "SIGHUP", + [SIGINT] = "SIGINT", + [SIGQUIT] = "SIGQUIT", + [SIGILL] = "SIGILL", + [SIGTRAP] = "SIGTRAP", + [SIGABRT] = "SIGABRT", + [SIGEMT] = "SIGEMT", + [SIGFPE] = "SIGFPE", + [SIGKILL] = "SIGKILL", + [SIGBUS] = "SIGBUS", + [SIGSEGV] = "SIGSEGV", + [SIGSYS] = "SIGSYS", + [SIGPIPE] = "SIGPIPE", + [SIGALRM] = "SIGALRM", + [SIGTERM] = "SIGTERM", + [SIGURG] = "SIGURG", + [SIGSTOP] = "SIGSTOP", + [SIGTSTP] = "SIGTSTP", + [SIGCONT] = "SIGCONT", + [SIGCHLD] = "SIGCHLD", + [SIGTTIN] = "SIGTTIN", + [SIGTTOU] = "SIGTTOU", + [SIGIO] = "SIGIO", + [SIGXCPU] = "SIGXCPU", + [SIGXFSZ] = "SIGXFSZ", + [SIGVTALRM] = "SIGVTALRM", + [SIGPROF] = "SIGPROF", + [SIGWINCH] = "SIGWINCH", + [SIGINFO] = "SIGINFO", + [SIGUSR1] = "SIGUSR1", + [SIGUSR2] = "SIGUSR2", + [SIGTHR] = "SIGTHR", + [SIGLIBRT] = "SIGLIBRT", + + /* XXX: Solaris uses SIGRTMIN, SIGRTMIN+...SIGRTMAX-, SIGRTMAX */ + [SIGRTMIN] = "SIGRT0", + [SIGRTMIN + 1] = "SIGRT1", + [SIGRTMIN + 2] = "SIGRT2", + [SIGRTMIN + 3] = "SIGRT3", + [SIGRTMIN + 4] = "SIGRT4", + [SIGRTMIN + 5] = "SIGRT5", + [SIGRTMIN + 6] = "SIGRT6", + [SIGRTMIN + 7] = "SIGRT7", + [SIGRTMIN + 8] = "SIGRT8", + [SIGRTMIN + 9] = "SIGRT9", + [SIGRTMIN + 10] = "SIGRT10", + [SIGRTMIN + 11] = "SIGRT11", + [SIGRTMIN + 12] = "SIGRT12", + [SIGRTMIN + 13] = "SIGRT13", + [SIGRTMIN + 14] = "SIGRT14", + [SIGRTMIN + 15] = "SIGRT15", + [SIGRTMIN + 16] = "SIGRT16", + [SIGRTMIN + 17] = "SIGRT17", + [SIGRTMIN + 18] = "SIGRT18", + [SIGRTMIN + 19] = "SIGRT19", + [SIGRTMIN + 20] = "SIGRT20", + [SIGRTMIN + 21] = "SIGRT21", + [SIGRTMIN + 22] = "SIGRT22", + [SIGRTMIN + 23] = "SIGRT23", + [SIGRTMIN + 24] = "SIGRT24", + [SIGRTMIN + 25] = "SIGRT25", + [SIGRTMIN + 26] = "SIGRT26", + [SIGRTMIN + 27] = "SIGRT27", + [SIGRTMIN + 28] = "SIGRT28", + [SIGRTMIN + 29] = "SIGRT29", + [SIGRTMIN + 30] = "SIGRT30", + [SIGRTMIN + 31] = "SIGRT31", + [SIGRTMIN + 32] = "SIGRT32", + [SIGRTMIN + 33] = "SIGRT33", + [SIGRTMIN + 34] = "SIGRT34", + [SIGRTMIN + 35] = "SIGRT35", + [SIGRTMIN + 36] = "SIGRT36", + [SIGRTMIN + 37] = "SIGRT37", + [SIGRTMIN + 38] = "SIGRT38", + [SIGRTMIN + 39] = "SIGRT39", + [SIGRTMIN + 40] = "SIGRT40", + [SIGRTMIN + 41] = "SIGRT41", + [SIGRTMIN + 42] = "SIGRT42", + [SIGRTMIN + 43] = "SIGRT43", + [SIGRTMIN + 44] = "SIGRT44", + [SIGRTMIN + 45] = "SIGRT45", + [SIGRTMIN + 46] = "SIGRT46", + [SIGRTMIN + 47] = "SIGRT47", + [SIGRTMIN + 48] = "SIGRT48", + [SIGRTMIN + 49] = "SIGRT49", + [SIGRTMIN + 50] = "SIGRT50", + [SIGRTMIN + 51] = "SIGRT51", + [SIGRTMIN + 52] = "SIGRT52", + [SIGRTMIN + 53] = "SIGRT53", + [SIGRTMIN + 54] = "SIGRT54", + [SIGRTMIN + 55] = "SIGRT55", + [SIGRTMIN + 56] = "SIGRT56", + [SIGRTMIN + 57] = "SIGRT57", + [SIGRTMIN + 58] = "SIGRT58", + [SIGRTMIN + 59] = "SIGRT59", + [SIGRTMIN + 60] = "SIGRT60", + [SIGRTMIN + 61] = "SIGRT61", +}; + +const char * +sysdecode_signal(int sig) +{ + + if ((unsigned)sig < nitems(signames)) + return (signames[sig]); + return (NULL); +} diff --git a/lib/libsysdecode/syscallnames.c b/lib/libsysdecode/syscallnames.c index 4ec2cd76ac73..df588c257663 100644 --- a/lib/libsysdecode/syscallnames.c +++ b/lib/libsysdecode/syscallnames.c @@ -35,6 +35,9 @@ __FBSDID("$FreeBSD$"); */ #include +#include +#include +#include #include #include diff --git a/lib/libsysdecode/sysdecode.3 b/lib/libsysdecode/sysdecode.3 index ab7e972b2f93..b5ed3c1471a8 100644 --- a/lib/libsysdecode/sysdecode.3 +++ b/lib/libsysdecode/sysdecode.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 29, 2016 +.Dd October 17, 2016 .Dt SYSDECODE 3 .Os .Sh NAME @@ -33,6 +33,10 @@ .Nd system argument decoding library .Sh LIBRARY .Lb libsysdecode +.Sh SYNOPSIS +.In sys/types.h +.In stdbool.h +.In sysdecode.h .Sh DESCRIPTION The .Nm @@ -65,7 +69,14 @@ A placeholder for use when the ABI is not known. .El .Sh SEE ALSO .Xr sysdecode_abi_to_freebsd_errno 3 , +.Xr sysdecode_cap_rights 3 , +.Xr sysdecode_enum 3 , +.Xr sysdecode_fcntl_arg 3 , .Xr sysdecode_ioctlname 3 , +.Xr sysdecode_mask 3 , +.Xr sysdecode_quotactl_cmd 3 , +.Xr sysdecode_sigcode 3 , +.Xr sysdecode_sockopt_name 3 , .Xr sysdecode_syscallnames 3 , .Xr sysdecode_utrace 3 .Sh HISTORY diff --git a/lib/libsysdecode/sysdecode.h b/lib/libsysdecode/sysdecode.h index 8a30206f66fb..5bdb30a45741 100644 --- a/lib/libsysdecode/sysdecode.h +++ b/lib/libsysdecode/sysdecode.h @@ -39,9 +39,79 @@ enum sysdecode_abi { }; int sysdecode_abi_to_freebsd_errno(enum sysdecode_abi _abi, int _error); +bool sysdecode_access_mode(FILE *_fp, int _mode, int *_rem); +const char *sysdecode_acltype(int _type); +const char *sysdecode_atfd(int _fd); +bool sysdecode_cap_fcntlrights(FILE *_fp, uint32_t _rights, uint32_t *_rem); +void sysdecode_cap_rights(FILE *_fp, cap_rights_t *_rightsp); +const char *sysdecode_extattrnamespace(int _namespace); +const char *sysdecode_fadvice(int _advice); +void sysdecode_fcntl_arg(FILE *_fp, int _cmd, uintptr_t _arg, int _base); +bool sysdecode_fcntl_arg_p(int _cmd); +const char *sysdecode_fcntl_cmd(int _cmd); +bool sysdecode_fcntl_fileflags(FILE *_fp, int _flags, int *_rem); +bool sysdecode_fileflags(FILE *_fp, fflags_t _flags, fflags_t *_rem); +bool sysdecode_filemode(FILE *_fp, int _mode, int *_rem); +bool sysdecode_flock_operation(FILE *_fp, int _operation, int *_rem); int sysdecode_freebsd_to_abi_errno(enum sysdecode_abi _abi, int _error); +bool sysdecode_getfsstat_flags(FILE *_fp, int _flags, int *_rem); +const char *sysdecode_idtype(int _idtype); const char *sysdecode_ioctlname(unsigned long _val); +const char *sysdecode_ipproto(int _protocol); +const char *sysdecode_kldsym_cmd(int _cmd); +const char *sysdecode_kldunload_flags(int _flags); +const char *sysdecode_lio_listio_mode(int _mode); +const char *sysdecode_madvice(int _advice); +const char *sysdecode_minherit_inherit(int _inherit); +const char *sysdecode_msgctl_cmd(int _cmd); +bool sysdecode_mlockall_flags(FILE *_fp, int _flags, int *_rem); +bool sysdecode_mmap_flags(FILE *_fp, int _flags, int *_rem); +bool sysdecode_mmap_prot(FILE *_fp, int _prot, int *_rem); +bool sysdecode_mount_flags(FILE *_fp, int _flags, int *_rem); +bool sysdecode_msg_flags(FILE *_fp, int _flags, int *_rem); +bool sysdecode_msync_flags(FILE *_fp, int _flags, int *_rem); +const char *sysdecode_nfssvc_flags(int _flags); +bool sysdecode_open_flags(FILE *_fp, int _flags, int *_rem); +bool sysdecode_pipe2_flags(FILE *_fp, int _flags, int *_rem); +const char *sysdecode_prio_which(int _which); +const char *sysdecode_procctl_cmd(int _cmd); +const char *sysdecode_ptrace_request(int _request); +bool sysdecode_quotactl_cmd(FILE *_fp, int _cmd); +bool sysdecode_reboot_howto(FILE *_fp, int _howto, int *_rem); +bool sysdecode_rfork_flags(FILE *_fp, int _flags, int *_rem); +const char *sysdecode_rlimit(int _resource); +const char *sysdecode_rtprio_function(int _function); +const char *sysdecode_scheduler_policy(int _policy); +const char *sysdecode_semctl_cmd(int _cmd); +bool sysdecode_semget_flags(FILE *_fp, int _flag, int *_rem); +bool sysdecode_sendfile_flags(FILE *_fp, int _flags, int *_rem); +bool sysdecode_shmat_flags(FILE *_fp, int _flags, int *_rem); +const char *sysdecode_shmctl_cmd(int _cmd); +const char *sysdecode_shutdown_how(int _how); +const char *sysdecode_sigbus_code(int _si_code); +const char *sysdecode_sigchld_code(int _si_code); +const char *sysdecode_sigcode(int _sig, int _si_code); +const char *sysdecode_sigfpe_code(int _si_code); +const char *sysdecode_sigill_code(int _si_code); +const char *sysdecode_signal(int _sig); +const char *sysdecode_sigprocmask_how(int _how); +const char *sysdecode_sigsegv_code(int _si_code); +const char *sysdecode_sigtrap_code(int _si_code); +const char *sysdecode_sockaddr_family(int _sa_family); +const char *sysdecode_socketdomain(int _domain); +bool sysdecode_socket_type(FILE *_fp, int _type, int *_rem); +const char *sysdecode_sockopt_level(int _level); +const char *sysdecode_sockopt_name(int _level, int _optname); const char *sysdecode_syscallname(enum sysdecode_abi _abi, unsigned int _code); +bool sysdecode_thr_create_flags(FILE *_fp, int _flags, int *_rem); +bool sysdecode_umtx_cvwait_flags(FILE *_fp, u_long _flags, u_long *_rem); +const char *sysdecode_umtx_op(int _op); +bool sysdecode_umtx_rwlock_flags(FILE *_fp, u_long _flags, u_long *_rem); int sysdecode_utrace(FILE *_fp, void *_buf, size_t _len); +bool sysdecode_vmprot(FILE *_fp, int _type, int *_rem); +const char *sysdecode_vmresult(int _result); +bool sysdecode_wait4_options(FILE *_fp, int _options, int *_rem); +bool sysdecode_wait6_options(FILE *_fp, int _options, int *_rem); +const char *sysdecode_whence(int _whence); #endif /* !__SYSDECODE_H__ */ diff --git a/lib/libsysdecode/sysdecode_abi_to_freebsd_errno.3 b/lib/libsysdecode/sysdecode_abi_to_freebsd_errno.3 index fdee211d36fb..78eb858ed5c4 100644 --- a/lib/libsysdecode/sysdecode_abi_to_freebsd_errno.3 +++ b/lib/libsysdecode/sysdecode_abi_to_freebsd_errno.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 23, 2016 +.Dd October 17, 2016 .Dt sysdecode_abi_to_freebsd_errno 3 .Os .Sh NAME @@ -35,6 +35,9 @@ .Sh LIBRARY .Lb libsysdecode .Sh SYNOPSIS +.In sys/types.h +.In stdbool.h +.In sysdecode.h .Ft int .Fn sysdecode_abi_to_freebsd_errno "enum sysdecode_abi abi" "int error" .Ft int diff --git a/lib/libsysdecode/sysdecode_cap_rights.3 b/lib/libsysdecode/sysdecode_cap_rights.3 new file mode 100644 index 000000000000..7d916bbf2c53 --- /dev/null +++ b/lib/libsysdecode/sysdecode_cap_rights.3 @@ -0,0 +1,50 @@ +.\" +.\" Copyright (c) 2016 John Baldwin +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd October 17, 2016 +.Dt sysdecode_cap_rights 3 +.Os +.Sh NAME +.Nm sysdecode_cap_rights +.Nd output list of capability rights +.Sh LIBRARY +.Lb libsysdecode +.Sh SYNOPSIS +.In sys/types.h +.In stdbool.h +.In sysdecode.h +.Ft void +.Fn sysdecode_cap_rights "FILE *fp" "cap_rights_t *rightsp" +.Sh DESCRIPTION +The +.Fn sysdecode_cap_rights +function outputs a comma-separated list of capability rights at +.Fa rightsp +to the stream +.Fa fp . +.Sh SEE ALSO +.Xr sysdecode 3 diff --git a/lib/libsysdecode/sysdecode_enum.3 b/lib/libsysdecode/sysdecode_enum.3 new file mode 100644 index 000000000000..f0fce4d04c07 --- /dev/null +++ b/lib/libsysdecode/sysdecode_enum.3 @@ -0,0 +1,235 @@ +.\" +.\" Copyright (c) 2016 John Baldwin +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd October 17, 2016 +.Dt sysdecode_enum 3 +.Os +.Sh NAME +.Nm sysdecode_enum , +.Nm sysdecode_acltype , +.Nm sysdecode_atfd , +.Nm sysdecode_extattrnamespace , +.Nm sysdecode_fadvice , +.Nm sysdecode_fcntl_cmd , +.Nm sysdecode_idtype , +.Nm sysdecode_ipproto , +.Nm sysdecode_kldsym_cmd , +.Nm sysdecode_kldunload_flags , +.Nm sysdecode_lio_listio_mode , +.Nm sysdecode_madvice , +.Nm sysdecode_minherit_flags , +.Nm sysdecode_msgctl_cmd , +.Nm sysdecode_nfssvc_flags , +.Nm sysdecode_prio_which , +.Nm sysdecode_procctl_cmd , +.Nm sysdecode_ptrace_request , +.Nm sysdecode_rlimit , +.Nm sysdecode_rtprio_function , +.Nm sysdecode_scheduler_policy , +.Nm sysdecode_semctl_cmd , +.Nm sysdecode_shmctl_cmd , +.Nm sysdecode_shutdown_how , +.Nm sysdecode_sigbus_code , +.Nm sysdecode_sigchld_code , +.Nm sysdecode_sigfpe_code , +.Nm sysdecode_sigill_code , +.Nm sysdecode_signal , +.Nm sysdecode_sigprocmask_how , +.Nm sysdecode_sigsegv_code , +.Nm sysdecode_sigtrap_code , +.Nm sysdecode_sockaddr_family , +.Nm sysdecode_socketdomain , +.Nm sysdecode_sockettype , +.Nm sysdecode_sockopt_level , +.Nm sysdecode_umtx_op , +.Nm sysdecode_vmresult , +.Nm sysdecode_whence +.Nd lookup name of various enumerated values +.Sh LIBRARY +.Lb libsysdecode +.Sh SYNOPSIS +.In sys/types.h +.In stdbool.h +.In sysdecode.h +.Ft const char * +.Fn sysdecode_acltype "int type" +.Ft const char * +.Fn sysdecode_atfd "int fd" +.Ft const char * +.Fn sysdecode_extattrnamespace "int namespace" +.Ft const char * +.Fn sysdecode_fadvice "int advice" +.Ft const char * +.Fn sysdecode_fcntl_cmd "int cmd" +.Ft const char * +.Fn sysdecode_idtype "int idtype" +.Ft const char * +.Fn sysdecode_ipproto "int protocol" +.Ft const char * +.Fn sysdecode_kldsym_cmd "int cmd" +.Ft const char * +.Fn sysdecode_kldunload_flags "int flags" +.Ft const char * +.Fn sysdecode_lio_listio_mode "int mode" +.Ft const char * +.Fn sysdecode_madvice "int advice" +.Ft const char * +.Fn sysdecode_minherit_flags "int inherit" +.Ft const char * +.Fn sysdecode_msgctl_cmd "int cmd" +.Ft const char * +.Fn sysdecode_nfssvc_flags "int flags" +.Ft const char * +.Fn sysdecode_prio_which "int which" +.Ft const char * +.Fn sysdecode_procctl_cmd "int cmd" +.Ft const char * +.Fn sysdecode_ptrace_request "int request" +.Ft const char * +.Fn sysdecode_rlimit "int resource" +.Ft const char * +.Fn sysdecode_rtprio_function "int function" +.Ft const char * +.Fn sysdecode_scheduler_policy "int policy" +.Ft const char * +.Fn sysdecode_semctl_cmd "int cmd" +.Ft const char * +.Fn sysdecode_shmctl_cmd "int cmd" +.Ft const char * +.Fn sysdecode_shutdown_how "int how" +.Ft const char * +.Fn sysdecode_sigbus_code "int si_code" +.Ft const char * +.Fn sysdecode_sigchld_code "int si_code" +.Ft const char * +.Fn sysdecode_sigfpe_code "int si_code" +.Ft const char * +.Fn sysdecode_sigill_code "int si_code" +.Ft const char * +.Fn sysdecode_signal "int sig" +.Ft const char * +.Fn sysdecode_sigprocmask_how "int how" +.Ft const char * +.Fn sysdecode_sigsegv_code "int si_code" +.Ft const char * +.Fn sysdecode_sigtrap_code "int si_code" +.Ft const char * +.Fn sysdecode_sockaddr_family "int sa_family" +.Ft const char * +.Fn sysdecode_socketdomain "int domain" +.Ft const char * +.Fn sysdecode_sockettype "int type" +.Ft const char * +.Fn sysdecode_sockopt_level "int level" +.Ft const char * +.Fn sysdecode_umtx_op "int op" +.Ft const char * +.Fn sysdecode_vmresult "int result" +.Ft const char * +.Fn sysdecode_whence "int whence" +.Sh DESCRIPTION +The +.Nm +functions return a text description of an integer value. +The text description matches the name of a C macro with the same value as the +sole function argument. +.Dv NULL +is returned if there is no matching C macro name. +.Pp +Most of these functions decode an argument passed to a system call: +.Bl -column "Fn sysdecode_extattrnamespace" "Xr sched_setscheduler 2" +.It Sy Function Ta Sy System Call Ta Sy Argument +.It Fn sysdecode_acltype Ta Xr acl_get_file 3 Ta Fa type +.It Fn sysdecode_atfd Ta Xr openat 2 Ta Fa fd +.It Fn sysdecode_extattrnamespace Ta Xr extattr_get_fd 2 Ta Fa attrnamespace +.It Fn sysdecode_fadvice Ta Xr posix_fadvise 2 Ta Fa advice +.It Fn sysdecode_fcntl_cmd Ta Xr fcntl 2 Ta Fa cmd +.It Fn sysdecode_idtype Ta +.Xr procctl 2 , +.Xr waitid 2 +.Ta Fa idtype +.It Fn sysdecode_kldsym_cmd Ta Xr kldsym 2 Ta Fa cmd +.It Fn sysdecode_kldunload_flags Ta Xr kldunloadf 2 Ta Fa flags +.It Fn sysdecode_lio_listio_mode Ta Xr lio_listio 2 Ta Fa mode +.It Fn sysdecode_madvice Ta Xr madvise 2 Ta Fa advice +.It Fn sysdecode_minherit_inherit Ta Xr minherit 2 Ta Fa inherit +.It Fn sysdecode_msgctl_cmd Ta Xr msgctl 2 Ta Fa cmd +.It Fn sysdecode_nfssvc_flags Ta Xr nfssvc 2 Ta Fa flags +.It Fn sysdecode_prio_which Ta Xr getpriority 2 Ta Fa which +.It Fn sysdecode_procctl_cmd Ta Xr procctl 2 Ta Fa cmd +.It Fn sysdecode_ptrace_request Ta Xr ptrace 2 Ta Fa request +.It Fn sysdecode_rlimit Ta Xr getrlimit 2 Ta Fa resource +.It Fn sysdecode_rtprio_function Ta Xr rtprio 2 Ta Fa function +.It Fn sysdecode_scheduler_policy Ta Xr sched_setscheduler 2 Ta Fa policy +.It Fn sysdecode_semctl_cmd Ta Xr semctl 2 Ta Fa cmd +.It Fn sysdecode_shmctl_cmd Ta Xr shmctl 2 Ta Fa cmd +.It Fn sysdecode_shutdown_how Ta Xr shutdown 2 Ta Fa how +.It Fn sysdecode_sigprocmask_how Ta Xr sigprocmask 2 Ta Fa how +.It Fn sysdecode_sockopt_level Ta Xr getsockopt 2 Ta Fa level +.It Fn sysdecode_umtx_op Ta Xr _umtx_op 2 Ta Fa op +.It Fn sysdecode_whence Ta Xr lseek 2 Ta Fa whence +.El +.Pp +These functions decode signal-specific signal codes stored in the +.Fa si_code +field of the +.Vt siginfo_t +object associated with an instance of signal: +.Bl -column "Fn sysdecode_sigchld_code" +.It Sy Function Ta Sy Signal +.It Fn sysdecode_sigbus_code Ta Dv SIGBUS +.It Fn sysdecode_sigchld_code Ta Dv SIGCHLD +.It Fn sysdecode_sigfpe_code Ta Dv SIGFPE +.It Fn sysdecode_sigill_code Ta Dv SIGILL +.It Fn sysdecode_sigsegv_code Ta Dv SIGSEGV +.It Fn sysdecode_sigtrap_code Ta Dv SIGBTRAP +.El +.Pp +Other functions decode the values described below: +.Bl -tag -width "Fn sysdecode_sockaddr_family" +.It Fn sysdecode_ipproto +An IP protocol. +.It Fn sysdecode_signal +A process signal. +.It Fn sysdecode_sockaddr_family +A socket address family. +.It Fn sysdecode_socketdomain +A socket domain. +.It Fn sysdecode_vmresult +The return value of a function in the virtual memory subsystem of the kernel +indicating the status of the associated request. +.El +.Sh RETURN VALUES +The +.Nm +functions return the name of a matching C macro or +.Dv NULL +if no matching C macro was found. +.Sh SEE ALSO +.Xr sysdecode 3 , +.Xr sysdecode_mask 3 , +.Xr sysdecode_sigcode 3 diff --git a/lib/libsysdecode/sysdecode_fcntl_arg.3 b/lib/libsysdecode/sysdecode_fcntl_arg.3 new file mode 100644 index 000000000000..2dacb01ceb8f --- /dev/null +++ b/lib/libsysdecode/sysdecode_fcntl_arg.3 @@ -0,0 +1,121 @@ +.\" +.\" Copyright (c) 2016 John Baldwin +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd October 17, 2016 +.Dt sysdecode_fcntl_arg 3 +.Os +.Sh NAME +.Nm sysdecode_fcntl_arg , +.Nm sysdecode_fcntl_arg_p +.Nd output description of fcntl argument +.Sh LIBRARY +.Lb libsysdecode +.Sh SYNOPSIS +.In sys/types.h +.In stdbool.h +.In sysdecode.h +.Ft void +.Fn sysdecode_fcntl_arg "FILE *fp" "int cmd" "uintptr_t arg" "int base" +.Ft bool +.Fn sysdecode_fcntl_arg_p "int cmd" +.Sh DESCRIPTION +The +.Fn sysdecode_fcntl_arg +function outputs a text description of the optional +.Fa arg +argument to +.Xr fcntl 2 +to the stream +.Fa fp . +The type and format of +.Fa arg +are determined by +.Fa cmd : +.Bl -column ".Dv F_SETLKW" "Vt struct flock *" +.It Sy Command Ta Fa arg Sy Type Ta Sy Output Format +.It +.It Dv F_SETFD Ta Vt int Ta +.Dq FD_CLOEXEC +or the value of +.Fa arg +in the indicated +.Fa base +.Pq one of 8, 10, or 16 . +.It +.It Dv F_SETFL Ta Vt int Ta +File flags as output by +.Xr sysdecode_fcntl_fileflags 3 +with any unknown or remaining bits output in hexadecimal. +.It +.It Dv F_GETLK Ta Vt struct flock * Ta +.It Dv F_SETLK Ta Vt struct flock * Ta +.It Dv F_SETLKW Ta Vt struct flock * Ta +The value of +.Fa arg +using the +.Dq %p +conversion specification. +.It +.It Others Ta Vt int Ta +The value of +.Fa arg +in the indicated +.Fa base +.Pq one of 8, 10, or 16 . +.El +.Pp +The +.Fn sysdecode_fcntl_arg_p +function can be used to determine if a +.Xr fcntl 2 +command uses the optional third argument to +.Xr fcntl 2 . +The function returns +.Dv true +if +.Fa cmd +accepts a third argument to +.Xr fcntl 2 +and +.Dv false +if it does not. +.Sh RETURN VALUES +The +.Nm sysdecode_fcntl_arg_p +function returns +.Dv true +if +.Fa cmd +accepts a third argument to +.Xr fcntl 2 +and +.Dv false +if it does not. +.Sh SEE ALSO +.Xr sysdecode 3 , +.Xr sysdecode_fcntl_cmd 3 , +.Xr sysdecode_fcntl_fileflags 3 diff --git a/lib/libsysdecode/sysdecode_ioctlname.3 b/lib/libsysdecode/sysdecode_ioctlname.3 index 6479f03befd8..0baf1152c4b4 100644 --- a/lib/libsysdecode/sysdecode_ioctlname.3 +++ b/lib/libsysdecode/sysdecode_ioctlname.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 12, 2015 +.Dd October 17, 2016 .Dt sysdecode_ioctlname 3 .Os .Sh NAME @@ -34,6 +34,9 @@ .Sh LIBRARY .Lb libsysdecode .Sh SYNOPSIS +.In sys/types.h +.In stdbool.h +.In sysdecode.h .Ft conts char * .Fn sysdecode_ioctlname "unsigned long request" .Sh DESCRIPTION diff --git a/lib/libsysdecode/sysdecode_mask.3 b/lib/libsysdecode/sysdecode_mask.3 new file mode 100644 index 000000000000..5810fc8d3597 --- /dev/null +++ b/lib/libsysdecode/sysdecode_mask.3 @@ -0,0 +1,216 @@ +.\" +.\" Copyright (c) 2016 John Baldwin +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd October 17, 2016 +.Dt sysdecode_mask 3 +.Os +.Sh NAME +.Nm sysdecode_mask , +.Nm sysdecode_accessmode , +.Nm sysdecode_capfcntlrights , +.Nm sysdecode_fcntl_fileflags , +.Nm sysdecode_fileflags , +.Nm sysdecode_filemode , +.Nm sysdecode_flock_operation , +.Nm sysdecode_getfsstat_flags , +.Nm sysdecode_mlockall_flags , +.Nm sysdecode_mmap_flags , +.Nm sysdecode_mmap_prot , +.Nm sysdecode_mount_flags , +.Nm sysdecode_msg_flags , +.Nm sysdecode_msync_flags , +.Nm sysdecode_open_flags , +.Nm sysdecode_pipe2_flags , +.Nm sysdecode_reboot_howto , +.Nm sysdecode_rfork_flags , +.Nm sysdecode_semget_flags , +.Nm sysdecode_sendfile_flags , +.Nm sysdecode_shmat_flags , +.Nm sysdecode_socket_type , +.Nm sysdecode_thr_create_flags , +.Nm sysdecode_umtx_cvwait_flags , +.Nm sysdecode_umtx_rwlock_flags , +.Nm sysdecode_vmprot , +.Nm sysdecode_wait4_options , +.Nm sysdecode_wait6_options +.Nd print name of various bitmask values +.Sh LIBRARY +.Lb libsysdecode +.Sh SYNOPSIS +.In sys/types.h +.In stdbool.h +.In sysdecode.h +.Ft bool +.Fn sysdecode_access_mode "FILE *fp" "int mode" "int *rem" +.Ft bool +.Fn sysdecode_cap_fcntlrights "FILE *fp" "uint32_t rights" "uint32_t *rem" +.Ft bool +.Fn sysdecode_fcntl_fileflags "FILE *fp" "int flags" "int *rem" +.Ft bool +.Fn sysdecode_fileflags "FILE *fp" "fflags_t flags" "fflags_t *rem" +.Ft bool +.Fn sysdecode_filemode "FILE *fp" "int mode" "int *rem" +.Ft bool +.Fn sysdecode_flock_operation "FILE *fp" "int operation" "int *rem" +.Ft bool +.Fn sysdecode_mlockall_flags "FILE *fp" "int flags" "int *rem" +.Ft bool +.Fn sysdecode_mmap_flags "FILE *fp" "int flags" "int *rem" +.Ft bool +.Fn sysdecode_mmap_prot "FILE *fp" "int prot" "int *rem" +.Ft bool +.Fn sysdecode_mount_flags "FILE *fp" "int flags" "int *rem" +.Ft bool +.Fn sysdecode_msg_flags "FILE *fp" "int flags" "int *rem" +.Ft bool +.Fn sysdecode_msync_flags "FILE *fp" "int flags" "int *rem" +.Ft bool +.Fn sysdecode_open_flags "FILE *fp" "int flags" "int *rem" +.Ft bool +.Fn sysdecode_pipe2_flags "FILE *fp" "int flags" "int *rem" +.Ft bool +.Fn sysdecode_reboot_howto "FILE *fp" "int howto" "int *rem" +.Ft bool +.Fn sysdecode_rfork_flags "FILE *fp" "int flags" "int *rem" +.Ft bool +.Fn sysdecode_semget_flags "FILE *fp" "int flags" "int *rem" +.Ft bool +.Fn sysdecode_sendfile_flags "FILE *fp" "int flags" "int *rem" +.Ft bool +.Fn sysdecode_shmat_flags "FILE *fp" "int flags" "int *rem" +.Ft bool +.Fn sysdecode_socket_type "FILE *fp" "int type" "int *rem" +.Ft bool +.Fn sysdecode_thr_create_flags "FILE *fp" "int flags" "int *rem" +.Ft bool +.Fn sysdecode_umtx_cvwait_flags "FILE *fp" "u_long flags" "u_long *rem" +.Ft bool +.Fn sysdecode_umtx_rwlock_flags "FILE *fp" "u_long flags" "u_long *rem" +.Ft bool +.Fn sysdecode_vmprot "FILE *fp" "int type" "int *rem" +.Ft bool +.Fn sysdecode_wait4_options "FILE *fp" "int options" "int *rem" +.Ft bool +.Fn sysdecode_wait6_options "FILE *fp" "int options" "int *rem" +.Sh DESCRIPTION +The +.Nm +functions are used to generate a text description of an integer value +built from a mask of bitfields. +The text description lists the C macros for field values joined by pipe +.Sq | +characters matching the format used in C source code. +Most of the values decoded by these functions are passed as arguments to +system calls, +though some of these values are used internally in the kernel. +.Pp +Each function writes the text description to +.Fa fp . +The second argument should contain the integer value to be decoded. +The +.Fa rem +argument is set to the value of any bits that were not decoded +.Pq bit fields that do not have a corresponding C macro . +.Fa rem +may be set to +.Dv NULL +if the caller does not need this value. +Each function returns +.Dv true +if any bit fields in the value were decoded and +.Dv false +if no bit fields were decoded. +.Pp +Most of these functions decode an argument passed to a system call: +.Bl -column "Fn sysdecode_flock_operation" "Xr cap_fcntls_limit 2" +.It Sy Function Ta Sy System Call Ta Sy Argument +.It Fn sysdecode_access_mode Ta Xr access 2 Ta Fa mode +.It Fn sysdecode_cap_fcntlrights Ta Xr cap_fcntls_limit 2 Ta Fa fcntlrights +.It Fn sysdecode_fileflags Ta Xr chflags 2 Ta Fa flags +.It Fn sysdecode_filemode Ta Xr chmod 2 , Xr open 2 Ta mode +.It Fn sysdecode_flock_operation Ta Xr flock 2 Ta Fa operation +.It Fn sysdecode_getfsstat_flags Ta Xr getfsstatflags 2 Ta Fa flags +.It Fn sysdecode_mlockall_flags Ta Xr mlockall 2 Ta Fa flags +.It Fn sysdecode_mmap_flags Ta Xr mmap 2 Ta Fa flags +.It Fn sysdecode_mmap_prot Ta Xr mmap 2 Ta Fa prot +.It Fn sysdecode_mount_flags Ta Xr mount 2 Ta Fa flags +.It Fn sysdecode_msg_flags Ta Xr recv 2 , Xr send 2 Ta Fa flags +.It Fn sysdecode_msync_flags Ta Xr msync 2 Ta Fa flags +.It Fn sysdecode_open_flags Ta Xr open 2 Ta Fa flags +.It Fn sysdecode_pipe2_flags Ta Xr pipe2 Ta Fa flags +.It Fn sysdecode_reboot_howto Ta Xr reboot 2 Ta Fa howto +.It Fn sysdecode_rfork_flags Ta Xr rfork 2 Ta Fa flags +.It Fn sysdecode_semget_flags Ta Xr semget 2 Ta Fa flags +.It Fn sysdecode_sendfile_flags Ta Xr sendfile 2 Ta Fa flags +.It Fn sysdecode_shmat_flags Ta Xr shmat 2 Ta Fa flags +.It Fn sysdecode_socket_type Ta Xr socket 2 Ta Fa type +.It Fn sysdecode_thr_create_flags Ta Xr thr_create 2 Ta Fa flags +.It Fn sysdecode_wait4_options Ta Xr wait4 2 Ta Fa options +.It Fn sysdecode_wait6_options Ta Xr wait6 2 Ta Fa options +.El +.Pp +Other functions decode the values described below: +.Bl -tag -width ".Fn sysdecode_umtx_cvwait_flags" +.It Fn sysdecode_fcntl_fileflags +The file flags used with the +.Dv F_GETFL +and +.Dv F_SETFL +.Xr fcntl 2 +commands. +.It Fn sysdecode_umtx_cvwait_flags +The +.Fa val +argument to +.Xr _umtx_op 2 +for +.Dv UMTX_OP_CV_WAIT +operations. +.It Fn sysdecode_umtx_rwlock_flags +The +.Fa val +argument to +.Xr _umtx_op 2 +for +.Dv UMTX_OP_RW_RDLOCK +operations. +.It Fn sysdecode_vmprot +The memory protection flags stored in +.Vt vm_prot_t +variables. +.El +.Sh RETURN VALUES +The +.Nm +functions return +.Dv true +if any bit fields in the value were decoded and +.Dv false +if no bit fields were decoded. +.Sh SEE ALSO +.Xr sysdecode 3 , +.Xr sysdecode_enum 3 diff --git a/lib/libsysdecode/sysdecode_quotactl_cmd.3 b/lib/libsysdecode/sysdecode_quotactl_cmd.3 new file mode 100644 index 000000000000..362da170b704 --- /dev/null +++ b/lib/libsysdecode/sysdecode_quotactl_cmd.3 @@ -0,0 +1,93 @@ +.\" +.\" Copyright (c) 2016 John Baldwin +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd October 17, 2016 +.Dt sysdecode_quotactl_cmd 3 +.Os +.Sh NAME +.Nm sysdecode_quotactl_cmd +.Nd output name of quotactl command +.Sh LIBRARY +.Lb libsysdecode +.Sh SYNOPSIS +.In sys/types.h +.In stdbool.h +.In sysdecode.h +.Ft bool +.Fn sysdecode_quotactl_cmd "FILE *fp" "int cmd" +.Sh DESCRIPTION +The +.Fn sysdecode_quotactl_cmd +function outputs a text description of the +.Fa cmd +argument to +.Xr quotactl 2 +to the stream +.Fa fp . +The description is formatted as an invocation of the +.Dv QCMD +macro defined in the +.In ufs/ufs/quota.h +header. +.Pp +The function first computes the primary and secondary values used by +.Dv QCMD +to construct +.Fa cmd . +If the primary command value does not represent a known constant, +.Fn sysdecode_quotactl_cmd +does not generate any output and returns +.Dv false . +Otherwise, +.Fn sysdecode_quotactl_cmd +outputs text depicting an invocation of +.Dv QCMD +with the associated constants for the primary and secondary command values +and returns +.Dv true . +If the secondary command values does not represent a known constant, +its value is output as a hexadecimal integer. +.Sh RETURN VALUES +The +.Nm sysdecode_quotactl_cmd +function returns +.Dv true +if it outputs a description of +.Fa cmd +and +.Dv false +if it does not. +.Sh EXAMPLES +The statement +.Pp +.Dl sysdecode_quotatcl_cmd(stdout, QCMD(Q_GETQUOTA, USRQUOTA); +.Pp +outputs the text +.Dq QCMD(Q_GETQUOTA, USRQUOTA) +to standard output. +.Sh SEE ALSO +.Xr sysdecode 3 diff --git a/lib/libsysdecode/sysdecode_sigcode.3 b/lib/libsysdecode/sysdecode_sigcode.3 new file mode 100644 index 000000000000..5675662956af --- /dev/null +++ b/lib/libsysdecode/sysdecode_sigcode.3 @@ -0,0 +1,83 @@ +.\" +.\" Copyright (c) 2016 John Baldwin +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd October 17, 2016 +.Dt sysdecode_sigcode 3 +.Os +.Sh NAME +.Nm sysdecode_sigcode +.Nd lookup name of signal code +.Sh LIBRARY +.Lb libsysdecode +.Sh SYNOPSIS +.In sys/types.h +.In stdbool.h +.In sysdecode.h +.Ft const char * +.Fn sysdecode_sigcode "int signal" "int si_code" +.Sh DESCRIPTION +The +.Fn sysdecode_sigcode +function returns a text description of the +.Fa si_code +field of the +.Vt siginfo_t +object associated with an instance of signal +.Fa sig . +The text description contains the name of the C macro whose value matches +.Fa si_code . +General purpose signal codes such as +.Dv SI_USER +are handled as well as signal-specific codes for +.Dv SIGBUS , +.Dv SIGCHLD , +.Dv SIGFPE , +.Dv SIGILL , +.Dv SIGSEGV +and +.Dv SIGTRAP . +If +.Fa si_code +does not represent a known signal code, +.Fn sysdecode_sigcode +returns +.Dv NULL . +.Sh RETURN VALUES +The +.Fn sysdecode_sigcode +function returns a pointer to a signal code description or +.Dv NULL +if +.Fa si_code +is not a known signal code. +.Sh SEE ALSO +.Xr sysdecode_sigbus_code 3 , +.Xr sysdecode_sigchld_code 3 , +.Xr sysdecode_sigfpe_code 3 , +.Xr sysdecode_sigill_code 3 , +.Xr sysdecode_sigsegv_code 3 , +.Xr sysdecode_sigtrap_code 3 diff --git a/lib/libsysdecode/sysdecode_sockopt_name.3 b/lib/libsysdecode/sysdecode_sockopt_name.3 new file mode 100644 index 000000000000..3db6e0ef9545 --- /dev/null +++ b/lib/libsysdecode/sysdecode_sockopt_name.3 @@ -0,0 +1,61 @@ +.\" +.\" Copyright (c) 2016 John Baldwin +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd October 17, 2016 +.Dt sysdecode_sockopt_name 3 +.Os +.Sh NAME +.Nm sysdecode_sockopt_name +.Nd lookup name of socket option +.Sh LIBRARY +.Lb libsysdecode +.Sh SYNOPSIS +.In sys/types.h +.In stdbool.h +.In sysdecode.h +.Ft const char * +.Fn sysdecode_sockopt_name "int level" "int optname" +.Sh DESCRIPTION +The +.Fn sysdecode_sockopt_name +function returns a text description of the socket option name passed in the +.Fa optname +argument to +.Xr getsockopt 2 . +.Fn sysdecode_sockopt_name +takes the socket option +.Fa level +as well as the option name to uniquely identify the option. +.Sh SEE ALSO +.Xr sysdecode_sockopt_level 3 +.Sh BUGS +Socket option levels and names are protocol-specific. +Both +.Fn sysdecode_sockopt_level +and +.Fn sysdecode_sockopt_name +should possibly accept the protocol family as an additional argument. diff --git a/lib/libsysdecode/sysdecode_syscallnames.3 b/lib/libsysdecode/sysdecode_syscallnames.3 index e920edb29c55..9a571648247d 100644 --- a/lib/libsysdecode/sysdecode_syscallnames.3 +++ b/lib/libsysdecode/sysdecode_syscallnames.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 30, 2016 +.Dd October 17, 2016 .Dt sysdecode_syscallnames 3 .Os .Sh NAME @@ -34,6 +34,9 @@ .Sh LIBRARY .Lb libsysdecode .Sh SYNOPSIS +.In sys/types.h +.In stdbool.h +.In sysdecode.h .Ft const char * .Fn sysdecode_syscallnames "enum sysdecode_abi abi" "unsigned int code" .Sh DESCRIPTION diff --git a/lib/libsysdecode/sysdecode_utrace.3 b/lib/libsysdecode/sysdecode_utrace.3 index 8bf2e8595677..bf3f5e427bbf 100644 --- a/lib/libsysdecode/sysdecode_utrace.3 +++ b/lib/libsysdecode/sysdecode_utrace.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 11, 2015 +.Dd October 17, 2016 .Dt sysdecode_utrace 3 .Os .Sh NAME @@ -34,6 +34,9 @@ .Sh LIBRARY .Lb libsysdecode .Sh SYNOPSIS +.In sys/types.h +.In stdbool.h +.In sysdecode.h .Ft int .Fn sysdecode_utrace "FILE *fp" "void *buf" "size_t len" "int decimal" .Sh DESCRIPTION diff --git a/lib/libsysdecode/utrace.c b/lib/libsysdecode/utrace.c index dfd0e70380b0..87458190b4ea 100644 --- a/lib/libsysdecode/utrace.c +++ b/lib/libsysdecode/utrace.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include diff --git a/libexec/ypxfr/ypxfr_getmap.c b/libexec/ypxfr/ypxfr_getmap.c index 458971f893c5..1bde10efe3d4 100644 --- a/libexec/ypxfr/ypxfr_getmap.c +++ b/libexec/ypxfr/ypxfr_getmap.c @@ -43,8 +43,8 @@ __FBSDID("$FreeBSD$"); extern bool_t xdr_ypresp_all_seq(XDR *, unsigned long *); -static int (*ypresp_allfn)(); -static void *ypresp_data; +extern int (*ypresp_allfn)(); +extern void *ypresp_data; extern DB *specdbp; extern enum ypstat yp_errno; diff --git a/release/doc/en_US.ISO8859-1/hardware/article.xml b/release/doc/en_US.ISO8859-1/hardware/article.xml index 2334ad8b4856..5d644385866e 100644 --- a/release/doc/en_US.ISO8859-1/hardware/article.xml +++ b/release/doc/en_US.ISO8859-1/hardware/article.xml @@ -1013,8 +1013,6 @@ &hwlist.urtw; - &hwlist.urtwn; - [&arch.amd64;, &arch.i386;, &arch.pc98;] Lucent Technologies WaveLAN/IEEE 802.11b wireless network adapters and workalikes using the Lucent Hermes, Intersil PRISM-II, diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c index 2c3778dce65a..aebb90371436 100644 --- a/sbin/camcontrol/camcontrol.c +++ b/sbin/camcontrol/camcontrol.c @@ -3139,6 +3139,8 @@ rescan_or_reset_bus(path_id_t bus, int rescan) return(1); } + bzero(&ccb, sizeof(ccb)); + if (bus != CAM_BUS_WILDCARD) { ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS : XPT_RESET_BUS; ccb.ccb_h.path_id = bus; @@ -3181,7 +3183,7 @@ rescan_or_reset_bus(path_id_t bus, int rescan) * no-op, sending a rescan to the xpt bus would result in a status of * CAM_REQ_INVALID. */ - CCB_CLEAR_ALL_EXCEPT_HDR(&matchccb.cdm); + bzero(&matchccb, sizeof(matchccb)); matchccb.ccb_h.func_code = XPT_DEV_MATCH; matchccb.ccb_h.path_id = CAM_BUS_WILDCARD; bufsize = sizeof(struct dev_match_result) * 20; diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index 7577f9413d29..dd8f34b3b6a0 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -1,7 +1,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 21, 2016 +.Dd October 18, 2016 .Dt IPFW 8 .Os .Sh NAME @@ -1357,6 +1357,24 @@ or a hostname) and mask width of .Cm masklen bits. +.It Ar addr Ns / Ns Ar mask +Matches all IPv6 addresses with base +.Ar addr +(specified as allowed by +.Xr inet_pton +or a hostname) +and the mask of +.Ar mask , +specified as allowed by +.Xr inet_pton. +As an example, fe::640:0:0/ffff::ffff:ffff:0:0 will match +fe:*:*:*:0:640:*:*. +This form is advised only for non-contiguous +masks. +It is better to resort to the +.Ar addr Ns / Ns Ar masklen +format for contiguous masks, which is more compact and less +error-prone. .El .Pp No support for sets of IPv6 addresses is provided because IPv6 addresses diff --git a/sbin/ipfw/ipv6.c b/sbin/ipfw/ipv6.c index 6d884ee9100c..e54ad512d943 100644 --- a/sbin/ipfw/ipv6.c +++ b/sbin/ipfw/ipv6.c @@ -124,8 +124,8 @@ print_ip6(struct buf_pr *bp, ipfw_insn_ip6 *cmd, char const *s) if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL) bprintf(bp, "Error ntop in print_ip6\n"); bprintf(bp, "%s", trad ); - if (mb < 0) /* XXX not really legal... */ - bprintf(bp, ":%s", + if (mb < 0) /* mask not contiguous */ + bprintf(bp, "/%s", inet_ntop(AF_INET6, &a[1], trad, sizeof(trad))); else if (mb < 128) bprintf(bp, "/%d", mb); @@ -325,9 +325,10 @@ lookup_host6 (char *host, struct in6_addr *ip6addr) * any matches any IP6. Actually returns an empty instruction. * me returns O_IP6_*_ME * - * 03f1::234:123:0342 single IP6 address - * 03f1::234:123:0342/24 address/mask - * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address + * 03f1::234:123:0342 single IP6 address + * 03f1::234:123:0342/24 address/masklen + * 03f1::234:123:0342/ffff::ffff:ffff address/mask + * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address * * Set of address (as in ipv6) not supported because ipv6 address * are typically random past the initial prefix. @@ -382,13 +383,18 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen) * or ',' indicating another address follows. */ - char *p; + char *p, *q; int masklen; char md = '\0'; CHECK_LENGTH(cblen, 1 + len + 2 * F_INSN_SIZE(struct in6_addr)); - if ((p = strpbrk(av, "/,")) ) { + if ((q = strchr(av, ',')) ) { + *q = '\0'; + q++; + } + + if ((p = strchr(av, '/')) ) { md = *p; /* save the separator */ *p = '\0'; /* terminate address string */ p++; /* and skip past it */ @@ -401,22 +407,22 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen) errx(EX_DATAERR, "bad address \"%s\"", av); } /* next, look at the mask, if any */ - masklen = (md == '/') ? atoi(p) : 128; - if (masklen > 128 || masklen < 0) - errx(EX_DATAERR, "bad width \"%s\''", p); - else - n2mask(&d[1], masklen); + if (md == '/' && strchr(p, ':')) { + if (!inet_pton(AF_INET6, p, &d[1])) + errx(EX_DATAERR, "bad mask \"%s\"", p); + + masklen = contigmask((uint8_t *)&(d[1]), 128); + } else { + masklen = (md == '/') ? atoi(p) : 128; + if (masklen > 128 || masklen < 0) + errx(EX_DATAERR, "bad width \"%s\''", p); + else + n2mask(&d[1], masklen); + } APPLY_MASK(d, &d[1]) /* mask base address with mask */ - /* find next separator */ - - if (md == '/') { /* find separator past the mask */ - p = strpbrk(p, ","); - if (p != NULL) - p++; - } - av = p; + av = q; /* Check this entry */ if (masklen == 0) { diff --git a/sbin/md5/md5.c b/sbin/md5/md5.c index ddf3a3cca768..9f54d60c193a 100644 --- a/sbin/md5/md5.c +++ b/sbin/md5/md5.c @@ -21,8 +21,10 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include +#include #include #include #include @@ -74,7 +76,7 @@ typedef struct Algorithm_t { DIGEST_Update *Update; DIGEST_End *End; char *(*Data)(const void *, unsigned int, char *); - char *(*File)(const char *, char *); + char *(*Fd)(int, char *); } Algorithm_t; static void MD5_Update(MD5_CTX *, const unsigned char *, size_t); @@ -106,34 +108,34 @@ typedef union { static const struct Algorithm_t Algorithm[] = { { "md5", "MD5", &MD5TestOutput, (DIGEST_Init*)&MD5Init, (DIGEST_Update*)&MD5_Update, (DIGEST_End*)&MD5End, - &MD5Data, &MD5File }, + &MD5Data, &MD5Fd }, { "sha1", "SHA1", &SHA1_TestOutput, (DIGEST_Init*)&SHA1_Init, (DIGEST_Update*)&SHA1_Update, (DIGEST_End*)&SHA1_End, - &SHA1_Data, &SHA1_File }, + &SHA1_Data, &SHA1_Fd }, { "sha256", "SHA256", &SHA256_TestOutput, (DIGEST_Init*)&SHA256_Init, (DIGEST_Update*)&SHA256_Update, (DIGEST_End*)&SHA256_End, - &SHA256_Data, &SHA256_File }, + &SHA256_Data, &SHA256_Fd }, { "sha384", "SHA384", &SHA384_TestOutput, (DIGEST_Init*)&SHA384_Init, (DIGEST_Update*)&SHA384_Update, (DIGEST_End*)&SHA384_End, - &SHA384_Data, &SHA384_File }, + &SHA384_Data, &SHA384_Fd }, { "sha512", "SHA512", &SHA512_TestOutput, (DIGEST_Init*)&SHA512_Init, (DIGEST_Update*)&SHA512_Update, (DIGEST_End*)&SHA512_End, - &SHA512_Data, &SHA512_File }, + &SHA512_Data, &SHA512_Fd }, { "sha512t256", "SHA512t256", &SHA512t256_TestOutput, (DIGEST_Init*)&SHA512_256_Init, (DIGEST_Update*)&SHA512_256_Update, (DIGEST_End*)&SHA512_256_End, - &SHA512_256_Data, &SHA512_256_File }, + &SHA512_256_Data, &SHA512_256_Fd }, { "rmd160", "RMD160", &RIPEMD160_TestOutput, (DIGEST_Init*)&RIPEMD160_Init, (DIGEST_Update*)&RIPEMD160_Update, - (DIGEST_End*)&RIPEMD160_End, &RIPEMD160_Data, &RIPEMD160_File }, + (DIGEST_End*)&RIPEMD160_End, &RIPEMD160_Data, &RIPEMD160_Fd }, { "skein256", "Skein256", &SKEIN256_TestOutput, (DIGEST_Init*)&SKEIN256_Init, (DIGEST_Update*)&SKEIN256_Update, - (DIGEST_End*)&SKEIN256_End, &SKEIN256_Data, &SKEIN256_File }, + (DIGEST_End*)&SKEIN256_End, &SKEIN256_Data, &SKEIN256_Fd }, { "skein512", "Skein512", &SKEIN512_TestOutput, (DIGEST_Init*)&SKEIN512_Init, (DIGEST_Update*)&SKEIN512_Update, - (DIGEST_End*)&SKEIN512_End, &SKEIN512_Data, &SKEIN512_File }, + (DIGEST_End*)&SKEIN512_End, &SKEIN512_Data, &SKEIN512_Fd }, { "skein1024", "Skein1024", &SKEIN1024_TestOutput, (DIGEST_Init*)&SKEIN1024_Init, (DIGEST_Update*)&SKEIN1024_Update, - (DIGEST_End*)&SKEIN1024_End, &SKEIN1024_Data, &SKEIN1024_File } + (DIGEST_End*)&SKEIN1024_End, &SKEIN1024_Data, &SKEIN1024_Fd } }; static void @@ -154,7 +156,8 @@ Arguments (may be any combination): int main(int argc, char *argv[]) { - int ch; + cap_rights_t rights; + int ch, fd; char *p; char buf[HEX_DIGEST_LENGTH]; int failed; @@ -206,10 +209,30 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; + if (caph_limit_stdout() < 0 || caph_limit_stderr() < 0) + err(1, "unable to limit rights for stdio"); + if (*argv) { do { - p = Algorithm[digest].File(*argv, buf); - if (!p) { + if ((fd = open(*argv, O_RDONLY)) < 0) { + warn("%s", *argv); + failed++; + continue; + } + /* + * XXX Enter capability mode on the last argv file. + * When a casper file service or other approach is + * available, switch to that and enter capability mode + * earlier. + */ + if (*(argv + 1) == NULL) { + cap_rights_init(&rights, CAP_READ); + if ((cap_rights_limit(fd, &rights) < 0 && + errno != ENOSYS) || + (cap_enter() < 0 && errno != ENOSYS)) + err(1, "capsicum"); + } + if ((p = Algorithm[digest].Fd(fd, buf)) == NULL) { warn("%s", *argv); failed++; } else { @@ -229,8 +252,12 @@ main(int argc, char *argv[]) printf("\n"); } } while (*++argv); - } else if (!sflag && (optind == 1 || qflag || rflag)) + } else if (!sflag && (optind == 1 || qflag || rflag)) { + if (caph_limit_stdin() < 0 || + (cap_enter() < 0 && errno != ENOSYS)) + err(1, "capsicum"); MDFilter(&Algorithm[digest], 0); + } if (failed != 0) return (1); diff --git a/share/doc/legal/realtek/Makefile b/share/doc/legal/realtek/Makefile index e168a18290df..f98d46e5f858 100644 --- a/share/doc/legal/realtek/Makefile +++ b/share/doc/legal/realtek/Makefile @@ -1,6 +1,6 @@ # $FreeBSD$ -FILES= ${.CURDIR}/../../../../sys/contrib/dev/urtwn/LICENSE +FILES= ${.CURDIR}/../../../../sys/contrib/dev/rtwn/LICENSE FILESDIR= ${SHAREDIR}/doc/legal FILESNAME= realtek.LICENSE diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile index 2a9061a634a8..61f1a89c5f27 100644 --- a/share/man/man4/Makefile +++ b/share/man/man4/Makefile @@ -433,6 +433,7 @@ MAN= aac.4 \ rp.4 \ rtwn.4 \ rtwnfw.4 \ + rtwn_pci.4 \ rue.4 \ rum.4 \ run.4 \ @@ -692,6 +693,8 @@ MLINKS+=pms.4 pmspcv.4 MLINKS+=ral.4 if_ral.4 MLINKS+=re.4 if_re.4 MLINKS+=rl.4 if_rl.4 +MLINKS+=rtwn.4 if_rtwn.4 +MLINKS+=rtwn_pci.4 if_rtwn_pci.4 MLINKS+=rue.4 if_rue.4 MLINKS+=rum.4 if_rum.4 MLINKS+=run.4 if_run.4 @@ -886,6 +889,7 @@ MAN+= \ otusfw.4 \ rsu.4 \ rsufw.4 \ + rtwn_usb.4 \ u3g.4 \ uark.4 \ uart.4 \ @@ -928,8 +932,6 @@ MAN+= \ urio.4 \ urndis.4 \ ${_urtw.4} \ - urtwn.4 \ - urtwnfw.4 \ usb.4 \ usb_quirk.4 \ usb_template.4 \ @@ -941,6 +943,7 @@ MAN+= \ MLINKS+=otus.4 if_otus.4 MLINKS+=rsu.4 if_rsu.4 +MLINKS+=rtwn_usb.4 if_rtwn_usb.4 MLINKS+=u3g.4 u3gstub.4 MLINKS+=uath.4 if_uath.4 MLINKS+=udav.4 if_udav.4 @@ -948,7 +951,6 @@ MLINKS+=upgt.4 if_upgt.4 MLINKS+=ural.4 if_ural.4 MLINKS+=urndis.4 if_urndis.4 MLINKS+=${_urtw.4} ${_if_urtw.4} -MLINKS+=urtwn.4 if_urtwn.4 .endif .include diff --git a/share/man/man4/bpf.4 b/share/man/man4/bpf.4 index e63b3a6ce73e..0d95c322784f 100644 --- a/share/man/man4/bpf.4 +++ b/share/man/man4/bpf.4 @@ -49,7 +49,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 15, 2010 +.Dd October 21, 2016 .Dt BPF 4 .Os .Sh NAME @@ -881,16 +881,20 @@ BPF_ALU+BPF_ADD+BPF_K A <- A + k BPF_ALU+BPF_SUB+BPF_K A <- A - k BPF_ALU+BPF_MUL+BPF_K A <- A * k BPF_ALU+BPF_DIV+BPF_K A <- A / k +BPF_ALU+BPF_MOD+BPF_K A <- A % k BPF_ALU+BPF_AND+BPF_K A <- A & k BPF_ALU+BPF_OR+BPF_K A <- A | k +BPF_ALU+BPF_XOR+BPF_K A <- A ^ k BPF_ALU+BPF_LSH+BPF_K A <- A << k BPF_ALU+BPF_RSH+BPF_K A <- A >> k BPF_ALU+BPF_ADD+BPF_X A <- A + X BPF_ALU+BPF_SUB+BPF_X A <- A - X BPF_ALU+BPF_MUL+BPF_X A <- A * X BPF_ALU+BPF_DIV+BPF_X A <- A / X +BPF_ALU+BPF_MOD+BPF_X A <- A % X BPF_ALU+BPF_AND+BPF_X A <- A & X BPF_ALU+BPF_OR+BPF_X A <- A | X +BPF_ALU+BPF_XOR+BPF_X A <- A ^ X BPF_ALU+BPF_LSH+BPF_X A <- A << X BPF_ALU+BPF_RSH+BPF_X A <- A >> X BPF_ALU+BPF_NEG A <- -A diff --git a/share/man/man4/netmap.4 b/share/man/man4/netmap.4 index 4d4ed32ef75c..229a112943b9 100644 --- a/share/man/man4/netmap.4 +++ b/share/man/man4/netmap.4 @@ -33,10 +33,10 @@ .Sh NAME .Nm netmap .Nd a framework for fast packet I/O -.Pp +.br .Nm VALE .Nd a fast VirtuAl Local Ethernet using the netmap API -.Pp +.br .Nm netmap pipes .Nd a shared memory packet transport channel .Sh SYNOPSIS @@ -44,28 +44,49 @@ .Sh DESCRIPTION .Nm is a framework for extremely fast and efficient packet I/O -for both userspace and kernel clients. +for userspace and kernel clients, and for Virtual Machines. It runs on .Fx -and Linux, and includes -.Nm VALE , -a very fast and modular in-kernel software switch/dataplane, -and -.Nm netmap pipes , -a shared memory packet transport channel. -All these are accessed interchangeably with the same API. +Linux and some versions of Windows, and supports a variety of +.Nm netmap ports , +including +.Bl -tag -width XXXX +.It Nm physical NIC ports +to access individual queues of network interfaces; +.It Nm host ports +to inject packets into the host stack; +.It Nm VALE ports +implementing a very fast and modular in-kernel software switch/dataplane; +.It Nm netmap pipes +a shared memory packet transport channel; +.It Nm netmap monitors +a mechanism similar to +.Xr bpf +to capture traffic +.El .Pp -.Nm , -.Nm VALE -and -.Nm netmap pipes -are at least one order of magnitude faster than +All these +.Nm netmap ports +are accessed interchangeably with the same API, +and are at least one order of magnitude faster than standard OS mechanisms -(sockets, bpf, tun/tap interfaces, native switches, pipes), -reaching 14.88 million packets per second (Mpps) -with much less than one core on a 10 Gbit NIC, -about 20 Mpps per core for VALE ports, -and over 100 Mpps for netmap pipes. +(sockets, bpf, tun/tap interfaces, native switches, pipes). +With suitably fast hardware (NICs, PCIe buses, CPUs), +packet I/O using +.Nm +on supported NICs +reaches 14.88 million packets per second (Mpps) +with much less than one core on 10 Gbit/s NICs; +35-40 Mpps on 40 Gbit/s NICs (limited by the hardware); +about 20 Mpps per core for VALE ports; +and over 100 Mpps for +.Nm netmap pipes. +NICs without native +.Nm +support can still use the API in emulated mode, +which uses unmodified device drivers and is 3-5 times faster than +.Xr bpf +or raw sockets. .Pp Userspace clients can dynamically switch NICs into .Nm @@ -73,8 +94,10 @@ mode and send and receive raw packets through memory mapped buffers. Similarly, .Nm VALE -switch instances and ports, and +switch instances and ports, .Nm netmap pipes +and +.Nm netmap monitors can be created dynamically, providing high speed packet I/O between processes, virtual machines, NICs and the host stack. @@ -89,17 +112,17 @@ and standard OS mechanisms such as .Xr epoll 2 , and .Xr kqueue 2 . -.Nm VALE -and -.Nm netmap pipes +All types of +.Nm netmap ports +and the +.Nm VALE switch are implemented by a single kernel module, which also emulates the .Nm -API over standard drivers for devices without native -.Nm -support. +API over standard drivers. For best performance, .Nm -requires explicit support in device drivers. +requires native support in device drivers. +A list of such devices is at the end of this document. .Pp In the rest of this (long) manual page we document various aspects of the @@ -116,7 +139,7 @@ which can be connected to a physical interface to the host stack, or to a .Nm VALE -switch). +switch. Ports use preallocated circular queues of buffers .Em ( rings ) residing in an mmapped region. @@ -166,16 +189,18 @@ has multiple modes of operation controlled by the .Vt struct nmreq argument. .Va arg.nr_name -specifies the port name, as follows: +specifies the netmap port name, as follows: .Bl -tag -width XXXX .It Dv OS network interface name (e.g. 'em0', 'eth1', ... ) the data path of the NIC is disconnected from the host stack, and the file descriptor is bound to the NIC (one or all queues), or to the host stack; -.It Dv valeXXX:YYY (arbitrary XXX and YYY) -the file descriptor is bound to port YYY of a VALE switch called XXX, -both dynamically created if necessary. -The string cannot exceed IFNAMSIZ characters, and YYY cannot +.It Dv valeSSS:PPP +the file descriptor is bound to port PPP of VALE switch SSS. +Switch instances and ports are dynamically created if necessary. +.br +Both SSS and PPP have the form [0-9a-zA-Z_]+ , the string +cannot exceed IFNAMSIZ characters, and PPP cannot be the name of any existing OS network interface. .El .Pp @@ -312,9 +337,6 @@ one slot is always kept empty. The ring size .Va ( num_slots ) should not be assumed to be a power of two. -.br -(NOTE: older versions of netmap used head/count format to indicate -the content of a ring). .Pp .Va head is the first slot available to userspace; @@ -585,6 +607,15 @@ it from the host stack. Multiple file descriptors can be bound to the same port, with proper synchronization left to the user. .Pp +The recommended way to bind a file descriptor to a port is +to use function +.Va nm_open(..) +(see +.Xr LIBRARIES ) +which parses names to access specific port types and +enable features. +In the following we document the main features. +.Pp .Dv NIOCREGIF can also bind a file descriptor to one endpoint of a .Em netmap pipe , consisting of two netmap ports with a crossover connection. @@ -734,7 +765,7 @@ similar to binds a file descriptor to a port. .Bl -tag -width XX .It Va ifname -is a port name, in the form "netmap:XXX" for a NIC and "valeXXX:YYY" for a +is a port name, in the form "netmap:PPP" for a NIC and "valeSSS:PPP" for a .Nm VALE port. .It Va req @@ -774,28 +805,39 @@ similar to pcap_next(), fetches the next packet natively supports the following devices: .Pp On FreeBSD: +.Xr cxgbe 4 , .Xr em 4 , .Xr igb 4 , .Xr ixgbe 4 , +.Xr ixl 4 , .Xr lem 4 , .Xr re 4 . .Pp On Linux .Xr e1000 4 , .Xr e1000e 4 , +.Xr i40e 4 , .Xr igb 4 , .Xr ixgbe 4 , -.Xr mlx4 4 , -.Xr forcedeth 4 , .Xr r8169 4 . .Pp NICs without native support can still be used in .Nm mode through emulation. Performance is inferior to native netmap -mode but still significantly higher than sockets, and approaching -that of in-kernel solutions such as Linux's -.Xr pktgen . +mode but still significantly higher than various raw socket types +(bpf, PF_PACKET, etc.). +Note that for slow devices (such as 1 Gbit/s and slower NICs, +or several 10 Gbit/s NICs whose hardware is unable to sustain line rate), +emulated and native mode will likely have similar or same throughput. +.br +When emulation is in use, packet sniffer programs such as tcpdump +could see received packets before they are diverted by netmap. This behaviour +is not intentional, being just an artifact of the implementation of emulation. +Note that in case the netmap application subsequently moves packets received +from the emulated adapter onto the host RX ring, the sniffer will intercept +those packets again, since the packets are injected to the host stack as they +were received by the network interface. .Pp Emulation is also available for devices with native netmap support, which can be used for testing or performance comparison. @@ -812,8 +854,12 @@ and module parameters on Linux .Bl -tag -width indent .It Va dev.netmap.admode: 0 Controls the use of native or emulated adapter mode. -0 uses the best available option, 1 forces native and -fails if not available, 2 forces emulated hence never fails. +.br +0 uses the best available option; +.br +1 forces native mode and fails if not available; +.br +2 forces emulated hence never fails. .It Va dev.netmap.generic_ringsize: 1024 Ring size used for emulated netmap mode .It Va dev.netmap.generic_mit: 100000 @@ -861,9 +907,9 @@ performance. uses .Xr select 2 , .Xr poll 2 , -.Xr epoll +.Xr epoll 2 and -.Xr kqueue +.Xr kqueue 2 to wake up processes when significant events occur, and .Xr mmap 2 to map memory. @@ -1015,8 +1061,8 @@ e.g. running the following in two different terminals: .Dl pkt-gen -i vale1:b -f tx # sender The same example can be used to test netmap pipes, by simply changing port names, e.g. -.Dl pkt-gen -i vale:x{3 -f rx # receiver on the master side -.Dl pkt-gen -i vale:x}3 -f tx # sender on the slave side +.Dl pkt-gen -i vale2:x{3 -f rx # receiver on the master side +.Dl pkt-gen -i vale2:x}3 -f tx # sender on the slave side .Pp The following command attaches an interface and the host stack to a switch: diff --git a/share/man/man4/rtwn.4 b/share/man/man4/rtwn.4 index 10258494f3ef..e43053fcef9e 100644 --- a/share/man/man4/rtwn.4 +++ b/share/man/man4/rtwn.4 @@ -2,6 +2,7 @@ .\" .\" Copyright (c) 2010 Damien Bergamini .\" Copyright (c) 2015 Stefan Sperling +.\" Copyright (c) 2016 Andriy Voskoboinyk .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -17,89 +18,88 @@ .\" .\" $FreeBSD$ .\" -.Dd October 28, 2015 +.Dd October 17, 2016 .Dt RTWN 4 .Os .Sh NAME .Nm rtwn -.Nd Realtek RTL8188CE PCIe IEEE 802.11b/g/n wireless network device +.Nd Realtek IEEE 802.11 wireless network driver .Sh SYNOPSIS +.Cd "options RTWN_DEBUG" +.Cd "options RTWN_WITHOUT_UCODE" +.Pp To compile this driver into the kernel, place the following lines in your kernel configuration file: .Bd -ragged -offset indent .Cd "device rtwn" .Cd "device rtwnfw" +.Cd "device rtwn_usb" +.Cd "device rtwn_pci" .Cd "device wlan" .Cd "device firmware" .Ed .Pp Alternatively, to load the driver as a -module at boot time, place the following line in +module at boot time, place following lines in .Xr loader.conf 5 : .Bd -literal -offset indent if_rtwn_load="YES" -.Ed -.Pp -After you have read the license in -.Pa /usr/share/doc/legal/realtek.LICENSE -you will want to add the following lines to -.Xr loader.conf 5 : -.Bd -literal -offset indent -legal.realtek.license_ack=1 -rtwn-rtl8192cfwU_load="YES" -rtwn-rtl8192cfwU_B_load="YES" +if_rtwn_pci_load="YES" +if_rtwn_usb_load="YES" .Ed .Sh DESCRIPTION The .Nm -driver supports PCIe wireless network devices based on the Realtek -RTL8188CE chipset. +driver provides support for wireless network devices based on +the Realtek RTL8192C, RTL8188E, RTL8812A and RTL8821A programming APIs. +These APIs are used by a wide variety of chips; most chips with USB +and some with PCI interface are supported. .Pp -The RTL8188CE is a highly integrated 802.11n adapter that combines a MAC, -a 1T1R capable baseband and an RF in a single chip. -It operates in the 2GHz spectrum only. +To enable use for PCI/PCIe systems, see the rtwn_pci(4) driver; +for USB devices, use the rtwn_usb(4) driver. .Pp -These are the modes the -.Nm -driver can operate in: -.Bl -tag -width "IBSS-masterXX" -.It BSS mode -Also known as -.Em infrastructure -mode, this is used when associating with an access point, through -which all traffic passes. -This mode is the default. -.It monitor mode -In this mode the driver is able to receive packets without -associating with an access point. -This disables the internal receive filter and enables the card to -capture packets from networks which it wouldn't normally have access to, -or to scan for access points. -.El +The driver supports +.Cm station , +.Cm adhoc , +.Cm hostap +and +.Cm monitor +mode operation. +There are no limitations for number of +.Cm monitor +mode +virtual interfaces; in addition to any other virtual interface +one +.Cm station +interface can be added (Note: RTL8821AU supports two non-monitor +mode interfaces at the same time). .Pp -The -.Nm -driver can be configured to use -Wired Equivalent Privacy (WEP) or -Wi-Fi Protected Access (WPA-PSK and WPA2-PSK). -WPA is the current encryption standard for wireless networks. -It is strongly recommended that WEP -not be used as the sole mechanism -to secure wireless communication, -due to serious weaknesses in it. +All chips have hardware support for WEP, AES-CCM and TKIP encryption. .Pp The .Nm driver can be configured at runtime with .Xr ifconfig 8 . .Sh FILES -The driver needs at least version 1.0 of the following firmware files, -which are loaded when an interface is brought up: +.Bl -tag -width ".Pa /usr/share/doc/legal/realtek.LICENSE" -compact +.It Pa /usr/share/doc/legal/realtek.LICENSE +.Nm +firmware license +.El .Pp +The driver (if not compiled with +.Cd options RTWN_WITHOUT_UCODE +) may use following firmware files, which are loaded +when an interface is brought up: .Bl -tag -width Ds -offset indent -compact +.It Pa /boot/kernel/rtwn-rtl8188eufw.ko +.It Pa /boot/kernel/rtwn-rtl8192cfwE_B.ko +.It Pa /boot/kernel/rtwn-rtl8192cfwE.ko +.It Pa /boot/kernel/rtwn-rtl8192cfwT.ko .It Pa /boot/kernel/rtwn-rtl8192cfwU.ko -.It Pa /boot/kernel/rtwn-rtl8192cfwU_B.ko +.It Pa /boot/kernel/rtwn-rtl8812aufw.ko +.It Pa /boot/kernel/rtwn-rtl8821aufw.ko .El .Sh EXAMPLES Join an existing BSS network (i.e., connect to an access point): @@ -118,48 +118,124 @@ Join a specific BSS network with 64-bit WEP encryption: ifconfig wlan create wlandev rtwn0 ssid my_net \e wepmode on wepkey 0x1234567890 weptxkey 1 up .Ed +.Pp +Create an IBSS network with 128-bit WEP encryption on the channel 4: +.Bd -literal -offset indent +ifconfig wlan create wlandev rtwn0 wlanmode adhoc ssid my_net \e + wepmode on wepkey 0x01020304050607080910111213 weptxkey 1 \e + channel 4 +.Ed +.Pp +Join/create an 802.11b IBSS network with network name +.Dq Li my_net : +.Bd -literal -offset indent +ifconfig wlan0 create wlandev rtwn0 wlanmode adhoc +ifconfig wlan0 inet 192.168.0.22 netmask 0xffffff00 ssid my_net \e + mode 11b +.Ed +.Pp +Create a host-based access point: +.Bd -literal -offset indent +ifconfig wlan0 create wlandev rtwn0 wlanmode hostap +ifconfig wlan0 inet 192.168.0.10 netmask 0xffffff00 ssid my_ap +.Ed +.Sh LOADER TUNABLES +Tunables can be set at the +.Xr loader 8 +prompt before booting the kernel or stored in +.Xr loader.conf 5 . +.Bl -tag -width indent +.It Va dev.rtwn.%d.hwcrypto +This tunable controls how key slots are assigned: +.br +0 - disable h/w crypto support. Features that require access +to frame contents (e.g., TCP/UDP/IP Rx checksum validation) +will not work; +.br +1 - use h/w crypto support for pairwise keys only; +.br +2 - use h/w crypto support for all keys; may not work for +multi-vap configurations. +.br +By default it is set to 1. +.It Va dev.rtwn.%d.ratectl +This tunable switches between rate control implementations: +.br +0 - no rate control; +.br +1 - driver sends 'tx complete' reports to net80211; algorithm +is controlled via net80211; +.br +2 - firmware-based rate control. +.br +By default it is set to 1; however driver may choose another +algorithm in case if it is not implemented +.br +Currently selected algorithm is reported via +.Em Va dev.rtwn.%d.ratectl_selected +read-only OID. +.El .Sh DIAGNOSTICS .Bl -diag -.It "could not read firmware %s" +.It "rtwn%d: could not read efuse byte at address 0x%x" +.It "rtwn%d: %s: cannot read rom, error %d" +There was an error while reading ROM; device attach will be aborted. +This should not happen. +.It "rtwn%d: failed loadfirmware of file %s" For some reason, the driver was unable to read the microcode file from the filesystem. The file might be missing or corrupted. -.It "device timeout" +The driver will disable firmware-dependent features. +.It "rtwn%d: wrong firmware size (%zu)" +.It "rtwn%d: %s: failed to upload firmware %s (error %d)" +.It "rtwn%d: timeout waiting for firmware readiness" +Firmware upload failed; the file might be corrupted. +The driver will disable firmware-dependent features. +This should not happen. +.It "rtwn%d: device timeout" A frame dispatched to the hardware for transmission did not complete in time. The driver will reset the hardware. This should not happen. .El .Sh SEE ALSO -.Xr pci 4 , +.Xr intro 4 , +.Xr netintro 4 , +.Xr rtwn_pci 4 , +.Xr rtwn_usb 4 , .Xr rtwnfw 4 , .Xr wlan 4 , +.Xr wlan_amrr 4 , .Xr wlan_ccmp 4 , .Xr wlan_tkip 4 , .Xr wlan_wep 4 , +.Xr wlan_xauth 4 , +.Xr hostapd 4 , .Xr ifconfig 8 , .Xr wpa_supplicant 8 .Sh HISTORY The +.Cm urtwn +driver first appeared in +.Ox 4.9 +and +.Fx 10.0 ; +the .Nm driver first appeared in .Ox 5.8 . .Sh AUTHORS The .Nm -driver was written by +driver was initially written by .An -nosplit .An Stefan Sperling Aq Mt stsp@openbsd.org and ported by .An Kevin Lo Aq Mt kevlo@freebsd.org . It was based on the -.Xr urtwn 4 +.Cm urtwn driver written by .An Damien Bergamini Aq Mt damien.bergamini@free.fr . -.Sh CAVEATS +.Sh BUGS The .Nm -driver does not support any of the 802.11n capabilities offered by the -adapters. -Additional work is required in -.Xr ieee80211 9 -before those features can be supported. +driver currently does not implement firmware-based rate control. diff --git a/share/man/man4/rtwn_pci.4 b/share/man/man4/rtwn_pci.4 new file mode 100644 index 000000000000..71fa1669233e --- /dev/null +++ b/share/man/man4/rtwn_pci.4 @@ -0,0 +1,63 @@ +.\"- +.\" Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd +.\" Copyright (c) 2016 Andriy Voskoboinyk +.\" All rights reserved. +.\"" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer, +.\" without modification. +.\" 2. Redistributions in binary form must reproduce at minimum a disclaimer +.\" similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any +.\" redistribution must be conditioned upon including a substantially +.\" similar Disclaimer requirement for further binary redistribution. +.\" +.\" NO WARRANTY +.\" 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 NONINFRINGEMENT, MERCHANTIBILITY +.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +.\" THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. +.\" +.\" $FreeBSD$ +.\"/ +.Dd October 17, 2016 +.Dt RTWN_PCI 4 +.Os +.Sh NAME +.Nm rtwn_pci +.Nd "Realtek PCI device glue" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device rtwn_pci" +.Cd "device pci" +.Cd "device wlan" +.Ed +.Sh DESCRIPTION +The +.Nm +driver supports PCIe wireless network devices based on the Realtek +RTL8188CE chipset. +.Pp +The RTL8188CE is a highly integrated 802.11n adapter that combines a MAC, +a 1T1R capable baseband and an RF in a single chip. +It operates in the 2GHz spectrum only. +.Sh SEE ALSO +.Xr rtwn 4 , +.Xr rtwnfw 4 , +.Xr rtwn_usb 4 , +.Xr pci 4 +.Sh CAVEATS +Most 802.11 capabilities were turned off; some more testing +is required to re-enable them. diff --git a/share/man/man4/rtwn_usb.4 b/share/man/man4/rtwn_usb.4 new file mode 100644 index 000000000000..8d157edc4300 --- /dev/null +++ b/share/man/man4/rtwn_usb.4 @@ -0,0 +1,111 @@ +.\"- +.\" Copyright (c) 2011 Adrian Chadd, Xenion Pty Ltd +.\" Copyright (c) 2016 Andriy Voskoboinyk +.\" All rights reserved. +.\"" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer, +.\" without modification. +.\" 2. Redistributions in binary form must reproduce at minimum a disclaimer +.\" similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any +.\" redistribution must be conditioned upon including a substantially +.\" similar Disclaimer requirement for further binary redistribution. +.\" +.\" NO WARRANTY +.\" 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 NONINFRINGEMENT, MERCHANTIBILITY +.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +.\" THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. +.\" +.\" $FreeBSD$ +.\"/ +.Dd October 17, 2016 +.Dt RTWN_USB 4 +.Os +.Sh NAME +.Nm rtwn_usb +.Nd "Realtek USB device glue" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device xhci" +.Cd "device ehci" +.Cd "device uhci" +.Cd "device ohci" +.Cd "device usb" +.Cd "device rtwn_usb" +.Cd "device wlan" +.Ed +.Sh DESCRIPTION +This module provides the USB bus glue needed for the devices supported +by the +.Xr rtwn 4 +driver. +.Sh HARDWARE +The +.Nm +driver supports Realtek RTL8188CU/RTL8188RU/RTL8188EU/RTL8192CU/RTL8812AU/RTL8821AU +based USB wireless network adapters, including: +.Pp +.Bl -column -compact "Belkin F7D1102 Surf Wireless Micro" "Bus" +.It Em Card Ta Em Bus +.It "Alfa AWUS036NHR v2" Ta USB 2.0 +.It "ASUS USB-AC56" Ta USB 3.0 +.It "ASUS USB-N10 NANO" Ta USB 2.0 +.It "Belkin F7D1102 Surf Wireless Micro" Ta USB 2.0 +.It "Buffalo WI-U2-433DM" Ta USB 2.0 +.It "Buffalo WI-U3-866D" Ta USB 3.0 +.It "D-Link DWA-123 rev D1" Ta USB 2.0 +.It "D-Link DWA-125 rev D1" Ta USB 2.0 +.It "D-Link DWA-131" Ta USB 2.0 +.It "D-Link DWA-171 rev A1" Ta USB 2.0 +.It "D-Link DWA-172 rev A1" Ta USB 2.0 +.It "D-Link DWA-180 rev A1" Ta USB 2.0 +.It "D-Link DWA-182 rev C1" Ta USB 3.0 +.It "Edimax EW-7811Un" Ta USB 2.0 +.It "Edimax EW-7811UTC" Ta USB 2.0 +.It "Edimax EW-7822UAC" Ta USB 3.0 +.It "Elecom WDC-150SU2M" Ta USB 2.0 +.It "EnGenius EUB1200AC" Ta USB 3.0 +.It "Hawking HD65U" Ta USB 2.0 +.It "Hercules Wireless N USB Pico" Ta USB 2.0 +.It "I-O Data WN-AC867U" Ta USB 3.0 +.It "Linksys WUSB6300" Ta USB 3.0 +.It "NEC AtermWL900U PA-WL900U" Ta USB 3.0 +.It "Netgear A6100" Ta USB 2.0 +.It "Netgear WNA1000M" Ta USB 2.0 +.It "Planex GW-900D" Ta USB 3.0 +.It "Realtek RTL8192CU" Ta USB 2.0 +.It "Realtek RTL8188CUS" Ta USB 2.0 +.It "Sitecom WLA-7100" Ta USB 3.0 +.It "TP-Link Archer T4U" Ta USB 3.0 +.It "TP-LINK TL-WN723N v3" Ta USB 2.0 +.It "TP-LINK TL-WN725N v2" Ta USB 2.0 +.It "TRENDnet TEW-805UB" Ta USB 3.0 +.It "ZyXEL NWD6605" Ta USB 3.0 +.El +.Sh SEE ALSO +.Xr rtwn 4 , +.Xr rtwnfw 4 , +.Xr rtwn_pci 4 , +.Xr usb 4 +.Sh BUGS +The +.Nm +driver does not support any of the 802.11ac capabilities offered by the +adapters. +Additional work is required in +.Xr ieee80211 9 +before those features can be supported. diff --git a/share/man/man4/rtwnfw.4 b/share/man/man4/rtwnfw.4 index e4ab346874f3..ee35484a0ccc 100644 --- a/share/man/man4/rtwnfw.4 +++ b/share/man/man4/rtwnfw.4 @@ -1,4 +1,5 @@ .\" Copyright (c) 2015 Kevin Lo +.\" Copyright (c) 2016 Andriy Voskoboinyk .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -36,26 +37,39 @@ kernel configuration file: .Cd "device rtwnfw" .Ed .Pp -This will include three firmware images inside the kernel. +This will include all firmware images inside the kernel. If you want to pick only the firmware image for your network adapter choose one of the following: .Bd -ragged -offset indent +.Cd "device rtwn-rtl8188eufw" +.Cd "device rtwn-rtl8192cfwE_B" +.Cd "device rtwn-rtl8192cfwE" +.Cd "device rtwn-rtl8192cfwT" .Cd "device rtwn-rtl8192cfwU" -.Cd "device rtwn-rtl8192cfwU_B" +.Cd "device rtwn-rtl8812aufw" +.Cd "device rtwn-rtl8821aufw" .Ed .Pp -Alternatively, to load the driver as a +Alternatively, to load all firmware images as a module at boot time, place the following line in .Xr loader.conf 5 : .Bd -literal -offset indent +rtwn-rtl8188eufw_load="YES" +rtwn-rtl8192cfwE_B_load="YES" +rtwn-rtl8192cfwE_load="YES" +rtwn-rtl8192cfwT_load="YES" rtwn-rtl8192cfwU_load="YES" -rtwn-rtl8192cfwU_B_load="YES" +rtwn-rtl8812aufw_load="YES" +rtwn-rtl8821aufw_load="YES" .Ed .Sh DESCRIPTION -This module provides access to firmware sets for the -Realtek RTL8188CE chip based PCIe adapters. -It may be -statically linked into the kernel, or loaded as a module. +rtwn-rtl8192cfwE and rtl8192cfwE_B modules provide access +to firmware sets for the Realtek RTL8188CE chip based PCIe adapters. +Other modules provide access to firmware sets for the Realtek RTL8188CUS, +RTL8188CE-VAU, RTL8188EUS, RTL8188RU, RTL8192CU, RTL8812AU and RTL8821AU +chip based USB WiFi adapters. +They may be +statically linked into the kernel, or loaded as a modules. .Pp For the loaded firmware to be enabled for use the license at .Pa /usr/share/doc/legal/realtek.LICENSE diff --git a/share/man/man4/tcp.4 b/share/man/man4/tcp.4 index 54f503f5c2c8..4d1473082b36 100644 --- a/share/man/man4/tcp.4 +++ b/share/man/man4/tcp.4 @@ -34,7 +34,7 @@ .\" From: @(#)tcp.4 8.1 (Berkeley) 6/5/93 .\" $FreeBSD$ .\" -.Dd June 28, 2016 +.Dd October 21, 2016 .Dt TCP 4 .Os .Sh NAME @@ -586,6 +586,12 @@ downshift. List of available TCP function blocks (TCP stacks). .It Va functions_default The default TCP function block (TCP stack). +.It Va insecure_rst +Use criterias defined in RFC793 instead of RFC5961 for accepting RST segments. +Default is false. +.It Va insecure_syn +Use criterias defined in RFC793 instead of RFC5961 for accepting SYN segments. +Default is false. .El .Sh ERRORS A socket operation may fail with one of the following errors returned: diff --git a/share/man/man4/urtwn.4 b/share/man/man4/urtwn.4 deleted file mode 100644 index 026c98190aed..000000000000 --- a/share/man/man4/urtwn.4 +++ /dev/null @@ -1,190 +0,0 @@ -.\" Copyright (c) 2010 Damien Bergamini -.\" -.\" Permission to use, copy, modify, and distribute this software for any -.\" purpose with or without fee is hereby granted, provided that the above -.\" copyright notice and this permission notice appear in all copies. -.\" -.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.\" -.\" $FreeBSD$ -.\" -.Dd June 9, 2016 -.Dt URTWN 4 -.Os -.Sh NAME -.Nm urtwn -.Nd Realtek RTL8188CU/RTL8188RU/RTL8188EU/RTL8192CU USB IEEE 802.11b/g/n wireless network device -.Sh SYNOPSIS -.Cd "options URTWN_WITHOUT_UCODE" -.Pp -To compile this driver into the kernel, -place the following lines in your -kernel configuration file: -.Bd -ragged -offset indent -.Cd "device ehci" -.Cd "device uhci" -.Cd "device ohci" -.Cd "device usb" -.Cd "device urtwn" -.Cd "device wlan" -.Ed -.Pp -Alternatively, to load the driver as a -module at boot time, place the following line in -.Xr loader.conf 5 : -.Bd -literal -offset indent -if_urtwn_load="YES" -.Ed -.Sh DESCRIPTION -The -.Nm -driver supports USB 2.0 wireless network devices based on Realtek -RTL8188CUS, RTL8188CE-VAU, RTL8188EUS, RTL8188RU and RTL8192CU chipsets. -.Pp -The RTL8188CUS and RTL8188EUS are highly integrated 802.11n adapters that -combine a MAC, a 1T1R capable baseband and an RF in a single chip. -They operate in the 2GHz spectrum only. -The RTL8188RU is a high-power variant of the RTL8188CUS. -The RTL8188CE-VAU is a PCI Express Mini Card adapter that attaches -to the USB interface. -.Pp -The RTL8192CU is a highly integrated multiple-in, multiple-out (MIMO) -802.11n adapter that combines a MAC, a 2T2R capable baseband and an -RF in a single chip. -It operates in the 2GHz spectrum only. -.Pp -All chips have hardware support for WEP, AES-CCM and TKIP encryption. -.Pp -The driver supports -.Cm station , -.Cm adhoc , -.Cm hostap , -and -.Cm monitor -mode operation. -Only one virtual interface may be configured at any time. -.Pp -This driver may use the firmware built with the -.Nm urtwnfw -module for some additional features -(when URTWN_WITHOUT_UCODE kernel option is not set). -.Sh FILES -.Bl -tag -width ".Pa /usr/share/doc/legal/realtek.LICENSE" -compact -.It Pa /usr/share/doc/legal/realtek.LICENSE -.Nm -firmware license -.El -.Sh HARDWARE -The -.Nm -driver supports Realtek RTL8188CU/RTL8188RU/RTL8188EU/RTL8192CU based USB -IEEE 802.11b/g/n wireless network adapters, including: -.Pp -.Bl -tag -width Ds -offset indent -compact -.It Alfa AWUS036NHR v2 -.It ASUS USB-N10 NANO -.It Belkin F7D1102 Surf Wireless Micro -.It D-Link DWA-123 rev D1 -.It D-Link DWA-125 rev D1 -.It D-Link DWA-131 -.It Edimax EW-7811Un -.It Elecom WDC-150SU2M -.It Netgear WNA1000M -.It Realtek RTL8192CU -.It Realtek RTL8188CUS -.It TP-LINK TL-WN723N v3 -.It TP-LINK TL-WN725N v2 -.El -.Sh EXAMPLES -Join an existing BSS network (i.e., connect to an access point): -.Bd -literal -offset indent -ifconfig wlan create wlandev urtwn0 inet 192.168.0.20 \e - netmask 0xffffff00 -.Ed -.Pp -Join a specific BSS network with network name -.Dq Li my_net : -.Pp -.Dl "ifconfig wlan create wlandev urtwn0 ssid my_net up" -.Pp -Join a specific BSS network with 64-bit WEP encryption: -.Bd -literal -offset indent -ifconfig wlan create wlandev urtwn0 ssid my_net \e - wepmode on wepkey 0x1234567890 weptxkey 1 up -.Ed -.Pp -Create an IBSS network with 128-bit WEP encryption on the channel 4: -.Bd -literal -offset indent -ifconfig wlan0 create wlandev urtwn0 wlanmode adhoc ssid my_net \e - wepmode on wepkey 0x01020304050607080910111213 weptxkey 1 \e - channel 4 -.Ed -.Pp -Join/create an 802.11b IBSS network with network name -.Dq Li my_net : -.Bd -literal -offset indent -ifconfig wlan0 create wlandev urtwn0 wlanmode adhoc -ifconfig wlan0 inet 192.168.0.22 netmask 0xffffff00 ssid my_net \e - mode 11b -.Ed -.Pp -Create an 802.11g host-based access point: -.Bd -literal -offset indent -ifconfig wlan0 create wlandev urtwn0 wlanmode hostap -ifconfig wlan0 inet 192.168.0.10 netmask 0xffffff00 ssid my_ap \e - mode 11g -.Ed -.Sh DIAGNOSTICS -.Bl -diag -.It "urtwn%d: error %d, could not read firmware %s" -For some reason, the driver was unable to read the microcode file from the -filesystem. -The file might be missing or corrupted. -.It "urtwn%d: device timeout" -A frame dispatched to the hardware for transmission did not complete in time. -The driver will reset the hardware. -This should not happen. -.El -.Sh SEE ALSO -.Xr intro 4 , -.Xr netintro 4 , -.Xr urtwnfw 4 , -.Xr usb 4 , -.Xr wlan 4 , -.Xr wlan_amrr 4 , -.Xr wlan_ccmp 4 , -.Xr wlan_tkip 4 , -.Xr wlan_wep 4 , -.Xr ifconfig 8 , -.Xr wpa_supplicant 8 -.Rs -.%T Realtek -.%U http://www.realtek.com.tw -.Re -.Sh HISTORY -The -.Nm -driver first appeared in -.Ox 4.9 -and -.Fx 10.0 . -.Sh AUTHORS -The -.Nm -driver was written by -.An Damien Bergamini Aq Mt damien@openbsd.org . -.Sh CAVEATS -The -.Nm -driver currently does not support A-MPDU 802.11n transmit aggregation. -.Pp -For non-RTL8188EUS chips -.Dq "rate control" -algorithm is absent; this may result in increased packet loss in noisy -networks. diff --git a/share/man/man4/urtwnfw.4 b/share/man/man4/urtwnfw.4 deleted file mode 100644 index 70e6e67f20ed..000000000000 --- a/share/man/man4/urtwnfw.4 +++ /dev/null @@ -1,77 +0,0 @@ -.\" Copyright (c) 2013 Kevin Lo -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. The name of the author may not be used to endorse or promote products -.\" derived from this software without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. -.\" -.\" $FreeBSD$ -.\" -.Dd October 15, 2015 -.Dt URTWNFW 4 -.Os -.Sh NAME -.Nm urtwnfw -.Nd "Firmware Module for Realtek Wireless driver" -.Sh SYNOPSIS -To compile this module into the kernel, -place the following line in your -kernel configuration file: -.Bd -ragged -offset indent -.Cd "device urtwnfw" -.Ed -.Pp -This will include three firmware images inside the kernel. -If you want to pick only the firmware image for your network adapter choose one -of the following: -.Bd -ragged -offset indent -.Cd "device urtwn-rtl8192cfwT" -.Cd "device urtwn-rtl8192cfwU" -.Cd "device urtwn-rtl8188eufw" -.Ed -.Pp -Alternatively, to load the driver as a -module at boot time, place the following line in -.Xr loader.conf 5 : -.Bd -literal -offset indent -urtwn-rtl8192cfwT_load="YES" -urtwn-rtl8192cfwU_load="YES" -urtwn-rtl8188eufw_load="YES" -.Ed -.Sh DESCRIPTION -This module provides access to firmware sets for the -Realtek RTL8188CUS, RTL8188CE-VAU, RTL8188EUS, RTL8188RU and RTL8192CU -chip based USB WiFi adapters. -It may be -statically linked into the kernel, or loaded as a module. -.Pp -For the loaded firmware to be enabled for use the license at -.Pa /usr/share/doc/legal/realtek.LICENSE -must be agreed to by adding the following line to -.Xr loader.conf 5 : -.Pp -.Dl "legal.realtek.license_ack=1" -.Sh FILES -.Bl -tag -width ".Pa /usr/share/doc/legal/realtek.LICENSE" -compact -.It Pa /usr/share/doc/legal/realtek.LICENSE -.Nm -firmware license -.El -.Sh SEE ALSO -.Xr urtwn 4 , -.Xr firmware 9 diff --git a/share/man/man4/wlan.4 b/share/man/man4/wlan.4 index 747e040d78b0..4d29bca5d084 100644 --- a/share/man/man4/wlan.4 +++ b/share/man/man4/wlan.4 @@ -185,13 +185,13 @@ may not interoperate. .Xr otus 4 , .Xr ral 4 , .Xr rsu 4 , +.Xr rtwn 4 , .Xr rum 4 , .Xr run 4 , .Xr uath 4 , .Xr upgt 4 , .Xr ural 4 , .Xr urtw 4 , -.Xr urtwn 4 , .Xr wi 4 , .Xr wlan_acl 4 , .Xr wlan_ccmp 4 , diff --git a/share/man/man7/arch.7 b/share/man/man7/arch.7 index d1d4522e2041..488cd05b1f90 100644 --- a/share/man/man7/arch.7 +++ b/share/man/man7/arch.7 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 19, 2016 +.Dd October 20, 2016 .Dt ARCH 7 .Os .Sh NAME @@ -130,7 +130,7 @@ included here. .Pp The full set of predefined macros can be obtained with this command: .Bd -literal -offset indent -cc -x c -Dm -E /dev/null +cc -x c -dM -E /dev/null .Ed .Pp Common type size and endianness macros: diff --git a/share/man/man9/fpu_kern.9 b/share/man/man9/fpu_kern.9 index 378362f690c3..2651e12a2b49 100644 --- a/share/man/man9/fpu_kern.9 +++ b/share/man/man9/fpu_kern.9 @@ -23,7 +23,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 23, 2014 +.Dd October 20, 2016 .Dt FPU_KERN 9 .Os .Sh NAME @@ -134,11 +134,11 @@ of increased system latency. .El .Pp The function does not sleep or block. -It could cause the +It could cause an FPU trap during execution, and on the first FPU access +after the function returns, as well as after each context switch. +On i386 and amd64 this will be the .Nm Device Not Available -exception during execution, and on the first FPU access after the -function returns, as well as after each context switch -(see Intel Software Developer Manual for the reference). +exception (see Intel Software Developer Manual for the reference). Currently, no errors are defined which can be returned by .Fn fpu_kern_enter to the caller. @@ -190,7 +190,7 @@ and false otherwise. .Sh NOTES The .Nm -is currently implemented only for the i386 and amd64 architectures. +is currently implemented only for the i386, amd64, and arm64 architectures. .Pp There is no way to handle floating point exceptions raised from kernel mode. @@ -208,3 +208,5 @@ The .Nm facitily and this manual page were written by .An Konstantin Belousov Aq Mt kib@FreeBSD.org . +The arm64 support was added by +.An Andrew Turner Aq Mt andrew@FreeBSD.org . diff --git a/share/mk/bsd.lib.mk b/share/mk/bsd.lib.mk index aa8ed225c58d..0126a020e999 100644 --- a/share/mk/bsd.lib.mk +++ b/share/mk/bsd.lib.mk @@ -178,7 +178,8 @@ _LIBS= lib${LIB_PRIVATE}${LIB}.a lib${LIB_PRIVATE}${LIB}.a: ${OBJS} ${STATICOBJS} @${ECHO} building static ${LIB} library @rm -f ${.TARGET} - ${AR} ${ARFLAGS} ${.TARGET} `NM='${NM}' NMFLAGS='${NMFLAGS}' lorder ${OBJS} ${STATICOBJS} | tsort -q` ${ARADD} + ${AR} ${ARFLAGS} ${.TARGET} `NM='${NM}' NMFLAGS='${NMFLAGS}' \ + ${LORDER} ${OBJS} ${STATICOBJS} | ${TSORT} ${TSORTFLAGS}` ${ARADD} ${RANLIB} ${RANLIBFLAGS} ${.TARGET} .endif @@ -193,7 +194,8 @@ CLEANFILES+= ${POBJS} lib${LIB_PRIVATE}${LIB}_p.a: ${POBJS} @${ECHO} building profiled ${LIB} library @rm -f ${.TARGET} - ${AR} ${ARFLAGS} ${.TARGET} `NM='${NM}' NMFLAGS='${NMFLAGS}' lorder ${POBJS} | tsort -q` ${ARADD} + ${AR} ${ARFLAGS} ${.TARGET} `NM='${NM}' NMFLAGS='${NMFLAGS}' \ + ${LORDER} ${POBJS} | ${TSORT} ${TSORTFLAGS}` ${ARADD} ${RANLIB} ${RANLIBFLAGS} ${.TARGET} .endif @@ -241,7 +243,8 @@ ${SHLIB_NAME_FULL}: ${SOBJS} .endif ${_LD:N${CCACHE_BIN}} ${LDFLAGS} ${SSP_CFLAGS} ${SOLINKOPTS} \ -o ${.TARGET} -Wl,-soname,${SONAME} \ - `NM='${NM}' NMFLAGS='${NMFLAGS}' lorder ${SOBJS} | tsort -q` ${LDADD} + `NM='${NM}' NMFLAGS='${NMFLAGS}' ${LORDER} ${SOBJS} | \ + ${TSORT} ${TSORTFLAGS}` ${LDADD} .if ${MK_CTF} != "no" ${CTFMERGE} ${CTFFLAGS} -o ${.TARGET} ${SOBJS} .endif diff --git a/share/mk/bsd.suffixes.mk b/share/mk/bsd.suffixes.mk index 551356bc3020..9ca583b0b952 100644 --- a/share/mk/bsd.suffixes.mk +++ b/share/mk/bsd.suffixes.mk @@ -20,12 +20,24 @@ ${CC} ${STATIC_CFLAGS} ${CFLAGS} -c ${.IMPSRC} -o ${.TARGET} ${CTFCONVERT_CMD} +.c.bco: + ${CC} -emit-llvm ${IR_CFLAGS} -c ${.IMPSRC} -o ${.TARGET} + +.c.llo: + ${CC} -emit-llvm ${IR_CFLAGS} -S ${.IMPSRC} -o ${.TARGET} + .cc .cpp .cxx .C: ${CXX} ${CXXFLAGS} ${LDFLAGS} ${.IMPSRC} ${LDLIBS} -o ${.TARGET} .cc.o .cpp.o .cxx.o .C.o: ${CXX} ${STATIC_CXXFLAGS} ${CXXFLAGS} -c ${.IMPSRC} -o ${.TARGET} +.cc.bco .cpp.bco .cxx.bco .C.bco: + ${CXX} -emit-llvm ${IR_CXXFLAGS} -c ${.IMPSRC} -o ${.TARGET} + +.cc.llo .cpp.llo .cxx.llo .C.llo: + ${CXX} -emit-llvm ${IR_CXXFLAGS} -S ${.IMPSRC} -o ${.TARGET} + .m.o: ${OBJC} ${OBJCFLAGS} -c ${.IMPSRC} -o ${.TARGET} ${CTFCONVERT_CMD} diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk index d55319de1a99..a0fd48b2d7f5 100644 --- a/share/mk/src.opts.mk +++ b/share/mk/src.opts.mk @@ -98,6 +98,8 @@ __DEFAULT_YES_OPTIONS = \ GCOV \ GDB \ GNU \ + GNU_DIFF \ + GNU_GREP \ GNU_GREP_COMPAT \ GPIO \ GPL_DTC \ @@ -300,6 +302,10 @@ MK_${var}:= no MK_LLVM_LIBUNWIND:= no .endif +.if ${MK_BINUTILS} == "no" +MK_GDB:= no +.endif + .if ${MK_LIBPTHREAD} == "no" MK_LIBTHR:= no .endif diff --git a/share/mk/sys.mk b/share/mk/sys.mk index 73350e71f5a6..3f768844794c 100644 --- a/share/mk/sys.mk +++ b/share/mk/sys.mk @@ -153,6 +153,7 @@ CFLAGS ?= -O2 -pipe CFLAGS += -fno-strict-aliasing .endif .endif +IR_CFLAGS ?= ${STATIC_CFLAGS:N-O*} ${CFLAGS:N-O*} PO_CFLAGS ?= ${CFLAGS} # cp(1) is used to copy source files to ${.OBJDIR}, make sure it can handle @@ -173,6 +174,7 @@ CTFFLAGS += -g CXX ?= c++ CXXFLAGS ?= ${CFLAGS:N-std=*:N-Wnested-externs:N-W*-prototypes:N-Wno-pointer-sign:N-Wold-style-definition} +IR_CXXFLAGS ?= ${STATIC_CXXFLAGS:N-O*} ${CXXFLAGS:N-O*} PO_CXXFLAGS ?= ${CXXFLAGS} DTRACE ?= dtrace @@ -229,6 +231,8 @@ LINTLIBFLAGS ?= -cghapbxu -C ${LIB} MAKE ?= make .if !defined(%POSIX) +LORDER ?= lorder + NM ?= nm NMFLAGS ?= @@ -242,6 +246,9 @@ PFLAGS ?= RC ?= f77 RFLAGS ?= + +TSORT ?= tsort +TSORTFLAGS ?= -q .endif SHELL ?= sh diff --git a/sys/amd64/amd64/bpf_jit_machdep.c b/sys/amd64/amd64/bpf_jit_machdep.c index ff5ca5f90e9a..f199c80b2922 100644 --- a/sys/amd64/amd64/bpf_jit_machdep.c +++ b/sys/amd64/amd64/bpf_jit_machdep.c @@ -1,6 +1,6 @@ /*- * Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy) - * Copyright (C) 2005-2009 Jung-uk Kim + * Copyright (C) 2005-2016 Jung-uk Kim * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -83,12 +83,13 @@ emit_code(bpf_bin_stream *stream, u_int value, u_int len) break; case 2: - *((u_short *)(stream->ibuf + stream->cur_ip)) = (u_short)value; + *((u_short *)(void *)(stream->ibuf + stream->cur_ip)) = + (u_short)value; stream->cur_ip += 2; break; case 4: - *((u_int *)(stream->ibuf + stream->cur_ip)) = value; + *((u_int *)(void *)(stream->ibuf + stream->cur_ip)) = value; stream->cur_ip += 4; break; } @@ -424,75 +425,58 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) break; case BPF_JMP|BPF_JGT|BPF_K: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - CMPid(ins->k, EAX); - JCC(JA, JBE); - break; - case BPF_JMP|BPF_JGE|BPF_K: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - CMPid(ins->k, EAX); - JCC(JAE, JB); - break; - case BPF_JMP|BPF_JEQ|BPF_K: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - CMPid(ins->k, EAX); - JCC(JE, JNE); - break; - case BPF_JMP|BPF_JSET|BPF_K: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - TESTid(ins->k, EAX); - JCC(JNE, JE); - break; - case BPF_JMP|BPF_JGT|BPF_X: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - CMPrd(EDX, EAX); - JCC(JA, JBE); - break; - case BPF_JMP|BPF_JGE|BPF_X: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - CMPrd(EDX, EAX); - JCC(JAE, JB); - break; - case BPF_JMP|BPF_JEQ|BPF_X: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - CMPrd(EDX, EAX); - JCC(JE, JNE); - break; - case BPF_JMP|BPF_JSET|BPF_X: if (ins->jt == ins->jf) { JUMP(ins->jt); break; } - TESTrd(EDX, EAX); - JCC(JNE, JE); + switch (ins->code) { + case BPF_JMP|BPF_JGT|BPF_K: + CMPid(ins->k, EAX); + JCC(JA, JBE); + break; + + case BPF_JMP|BPF_JGE|BPF_K: + CMPid(ins->k, EAX); + JCC(JAE, JB); + break; + + case BPF_JMP|BPF_JEQ|BPF_K: + CMPid(ins->k, EAX); + JCC(JE, JNE); + break; + + case BPF_JMP|BPF_JSET|BPF_K: + TESTid(ins->k, EAX); + JCC(JNE, JE); + break; + + case BPF_JMP|BPF_JGT|BPF_X: + CMPrd(EDX, EAX); + JCC(JA, JBE); + break; + + case BPF_JMP|BPF_JGE|BPF_X: + CMPrd(EDX, EAX); + JCC(JAE, JB); + break; + + case BPF_JMP|BPF_JEQ|BPF_X: + CMPrd(EDX, EAX); + JCC(JE, JNE); + break; + + case BPF_JMP|BPF_JSET|BPF_X: + TESTrd(EDX, EAX); + JCC(JNE, JE); + break; + } break; case BPF_ALU|BPF_ADD|BPF_X: @@ -510,6 +494,7 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) break; case BPF_ALU|BPF_DIV|BPF_X: + case BPF_ALU|BPF_MOD|BPF_X: TESTrd(EDX, EDX); if (fmem) { JNEb(4); @@ -523,6 +508,8 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) MOVrd(EDX, ECX); ZEROrd(EDX); DIVrd(ECX); + if (BPF_OP(ins->code) == BPF_MOD) + MOVrd(EDX, EAX); MOVrd(ECX, EDX); break; @@ -534,6 +521,10 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) ORrd(EDX, EAX); break; + case BPF_ALU|BPF_XOR|BPF_X: + XORrd(EDX, EAX); + break; + case BPF_ALU|BPF_LSH|BPF_X: MOVrd(EDX, ECX); SHL_CLrb(EAX); @@ -560,10 +551,13 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) break; case BPF_ALU|BPF_DIV|BPF_K: + case BPF_ALU|BPF_MOD|BPF_K: MOVrd(EDX, ECX); ZEROrd(EDX); MOVid(ins->k, ESI); DIVrd(ESI); + if (BPF_OP(ins->code) == BPF_MOD) + MOVrd(EDX, EAX); MOVrd(ECX, EDX); break; @@ -575,6 +569,10 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) ORid(ins->k, EAX); break; + case BPF_ALU|BPF_XOR|BPF_K: + XORid(ins->k, EAX); + break; + case BPF_ALU|BPF_LSH|BPF_K: SHLib((ins->k) & 0xff, EAX); break; @@ -650,5 +648,5 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) } #endif - return ((bpf_filter_func)stream.ibuf); + return ((bpf_filter_func)(void *)stream.ibuf); } diff --git a/sys/amd64/amd64/bpf_jit_machdep.h b/sys/amd64/amd64/bpf_jit_machdep.h index 01c251f6db91..ad1e84629894 100644 --- a/sys/amd64/amd64/bpf_jit_machdep.h +++ b/sys/amd64/amd64/bpf_jit_machdep.h @@ -1,6 +1,6 @@ /*- * Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy) - * Copyright (C) 2005-2009 Jung-uk Kim + * Copyright (C) 2005-2016 Jung-uk Kim * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -357,6 +357,24 @@ typedef void (*emit_func)(bpf_bin_stream *stream, u_int value, u_int n); emitm(&stream, i32, 4); \ } while (0) +/* xorl sr32,dr32 */ +#define XORrd(sr32, dr32) do { \ + emitm(&stream, 0x31, 1); \ + emitm(&stream, \ + (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \ +} while (0) + +/* xorl i32,r32 */ +#define XORid(i32, r32) do { \ + if (r32 == EAX) { \ + emitm(&stream, 0x35, 1); \ + } else { \ + emitm(&stream, 0x81, 1); \ + emitm(&stream, (25 << 3) | r32, 1); \ + } \ + emitm(&stream, i32, 4); \ +} while (0) + /* shll i8,r32 */ #define SHLib(i8, r32) do { \ emitm(&stream, 0xc1, 1); \ diff --git a/sys/amd64/amd64/efirt.c b/sys/amd64/amd64/efirt.c index 4c0454c1f84e..4540625d2d74 100644 --- a/sys/amd64/amd64/efirt.c +++ b/sys/amd64/amd64/efirt.c @@ -61,7 +61,6 @@ __FBSDID("$FreeBSD$"); static struct efi_systbl *efi_systbl; static struct efi_cfgtbl *efi_cfgtbl; static struct efi_rt *efi_runtime; -static struct cdev *efi_cdev; static int efi_status2err[25] = { 0, /* EFI_SUCCESS */ @@ -403,15 +402,13 @@ efi_init(void) return (ENXIO); } - return (efidev_init(&efi_cdev)); + return (0); } static void efi_uninit(void) { - efidev_uninit(efi_cdev); - efi_destroy_1t1_map(); efi_systbl = NULL; @@ -566,7 +563,6 @@ efirt_modevents(module_t m, int event, void *arg __unused) switch (event) { case MOD_LOAD: return (efi_init()); - break; case MOD_UNLOAD: efi_uninit(); diff --git a/sys/amd64/amd64/minidump_machdep.c b/sys/amd64/amd64/minidump_machdep.c index 442819b35973..11bcf5f863ca 100644 --- a/sys/amd64/amd64/minidump_machdep.c +++ b/sys/amd64/amd64/minidump_machdep.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -68,6 +69,9 @@ static void *dump_va; static size_t counter, progress, dumpsize; CTASSERT(sizeof(*vm_page_dump) == 8); +static int dump_retry_count = 5; +SYSCTL_INT(_machdep, OID_AUTO, dump_retry_count, CTLFLAG_RWTUN, + &dump_retry_count, 0, "Number of times dump has to retry before bailing out"); static int is_dumpable(vm_paddr_t pa) @@ -447,7 +451,7 @@ minidumpsys(struct dumperinfo *di) printf("\n"); if (error == ENOSPC) { printf("Dump map grown while dumping. "); - if (retry_count < 5) { + if (retry_count < dump_retry_count) { printf("Retrying...\n"); goto retry; } diff --git a/sys/arm/allwinner/a10_ehci.c b/sys/arm/allwinner/a10_ehci.c index 301e53c038f5..21e4bcc7e987 100644 --- a/sys/arm/allwinner/a10_ehci.c +++ b/sys/arm/allwinner/a10_ehci.c @@ -275,17 +275,11 @@ a10_ehci_detach(device_t self) struct aw_ehci_softc *aw_sc = device_get_softc(self); ehci_softc_t *sc = &aw_sc->sc; const struct aw_ehci_conf *conf; - device_t bdev; int err; uint32_t reg_value = 0; conf = USB_CONF(self); - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/arm/allwinner/aw_ccu.c b/sys/arm/allwinner/aw_ccu.c index 09ae89af7b5f..52d9cdacbfe4 100644 --- a/sys/arm/allwinner/aw_ccu.c +++ b/sys/arm/allwinner/aw_ccu.c @@ -82,7 +82,7 @@ static struct ofw_compat_data compat_data[] = { { "allwinner,sun6i-a31s", CLOCK_CCU }, { "allwinner,sun50i-a64", CLOCK_CCU }, { "allwinner,sun8i-a83t", CLOCK_CCU|CLOCK_PRCM|CLOCK_SYSCTRL }, - { "allwinner,sun8i-h3", CLOCK_CCU }, + { "allwinner,sun8i-h3", CLOCK_CCU|CLOCK_PRCM }, { NULL, 0 } }; diff --git a/sys/arm/annapurna/alpine/alpine_pci_msix.c b/sys/arm/annapurna/alpine/alpine_pci_msix.c new file mode 100644 index 000000000000..125dfa1ee999 --- /dev/null +++ b/sys/arm/annapurna/alpine/alpine_pci_msix.c @@ -0,0 +1,394 @@ +/*- + * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates + * All rights reserved. + * + * Developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "msi_if.h" +#include "pic_if.h" + +#define AL_SPI_INTR 0 +#define AL_EDGE_HIGH 1 +#define ERR_NOT_IN_MAP -1 +#define IRQ_OFFSET 1 +#define GIC_INTR_CELL_CNT 3 +#define INTR_RANGE_COUNT 2 +#define MAX_MSIX_COUNT 160 + +static int al_msix_attach(device_t); +static int al_msix_probe(device_t); + +static msi_alloc_msi_t al_msix_alloc_msi; +static msi_release_msi_t al_msix_release_msi; +static msi_alloc_msix_t al_msix_alloc_msix; +static msi_release_msix_t al_msix_release_msix; +static msi_map_msi_t al_msix_map_msi; + +static int al_find_intr_pos_in_map(device_t, struct intr_irqsrc *); + +static struct ofw_compat_data compat_data[] = { + {"annapurna-labs,al-msix", true}, + {"annapurna-labs,alpine-msix", true}, + {NULL, false} +}; + +/* + * Bus interface definitions. + */ +static device_method_t al_msix_methods[] = { + DEVMETHOD(device_probe, al_msix_probe), + DEVMETHOD(device_attach, al_msix_attach), + + /* Interrupt controller interface */ + DEVMETHOD(msi_alloc_msi, al_msix_alloc_msi), + DEVMETHOD(msi_release_msi, al_msix_release_msi), + DEVMETHOD(msi_alloc_msix, al_msix_alloc_msix), + DEVMETHOD(msi_release_msix, al_msix_release_msix), + DEVMETHOD(msi_map_msi, al_msix_map_msi), + + DEVMETHOD_END +}; + +struct al_msix_softc { + bus_addr_t base_addr; + struct resource *res; + uint32_t irq_min; + uint32_t irq_max; + uint32_t irq_count; + struct mtx msi_mtx; + vmem_t *irq_alloc; + device_t gic_dev; + /* Table of isrcs maps isrc pointer to vmem_alloc'd irq number */ + struct intr_irqsrc *isrcs[MAX_MSIX_COUNT]; +}; + +static driver_t al_msix_driver = { + "al_msix", + al_msix_methods, + sizeof(struct al_msix_softc), +}; + +devclass_t al_msix_devclass; + +DRIVER_MODULE(al_msix, ofwbus, al_msix_driver, al_msix_devclass, 0, 0); +DRIVER_MODULE(al_msix, simplebus, al_msix_driver, al_msix_devclass, 0, 0); + +MALLOC_DECLARE(M_AL_MSIX); +MALLOC_DEFINE(M_AL_MSIX, "al_msix", "Alpine MSIX"); + +static int +al_msix_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) + return (ENXIO); + + device_set_desc(dev, "Annapurna-Labs MSI-X Controller"); + return (BUS_PROBE_DEFAULT); +} + +static int +al_msix_attach(device_t dev) +{ + struct al_msix_softc *sc; + device_t gic_dev; + phandle_t iparent; + phandle_t node; + intptr_t xref; + int interrupts[INTR_RANGE_COUNT]; + int nintr, i, rid; + uint32_t icells, *intr; + + sc = device_get_softc(dev); + + node = ofw_bus_get_node(dev); + xref = OF_xref_from_node(node); + OF_device_register_xref(xref, dev); + + rid = 0; + sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (sc->res == NULL) { + device_printf(dev, "Failed to allocate resource\n"); + return (ENXIO); + } + + sc->base_addr = (bus_addr_t)rman_get_start(sc->res); + + /* Register this device to handle MSI interrupts */ + if (intr_msi_register(dev, xref) != 0) { + device_printf(dev, "could not register MSI-X controller\n"); + return (ENXIO); + } + else + device_printf(dev, "MSI-X controller registered\n"); + + /* Find root interrupt controller */ + iparent = ofw_bus_find_iparent(node); + if (iparent == 0) { + device_printf(dev, "No interrupt-parrent found. " + "Error in DTB\n"); + return (ENXIO); + } else { + /* While at parent - store interrupt cells prop */ + if (OF_searchencprop(OF_node_from_xref(iparent), + "#interrupt-cells", &icells, sizeof(icells)) == -1) { + device_printf(dev, "DTB: Missing #interrupt-cells " + "property in GIC node\n"); + return (ENXIO); + } + } + + gic_dev = OF_device_from_xref(iparent); + if (gic_dev == NULL) { + device_printf(dev, "Cannot find GIC device\n"); + return (ENXIO); + } + sc->gic_dev = gic_dev; + + /* Manually read range of interrupts from DTB */ + nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr), + (void **)&intr); + if (nintr == 0) { + device_printf(dev, "Cannot read interrupts prop from DTB\n"); + return (ENXIO); + } else if ((nintr / icells) != INTR_RANGE_COUNT) { + /* Supposed to have min and max value only */ + device_printf(dev, "Unexpected count of interrupts " + "in DTB node\n"); + return (EINVAL); + } + + /* Read interrupt range values */ + for (i = 0; i < INTR_RANGE_COUNT; i++) + interrupts[i] = intr[(i * icells) + IRQ_OFFSET]; + + sc->irq_min = interrupts[0]; + sc->irq_max = interrupts[1]; + sc->irq_count = (sc->irq_max - sc->irq_min + 1); + + if (sc->irq_count > MAX_MSIX_COUNT) { + device_printf(dev, "Available MSI-X count exceeds buffer size." + " Capping to %d\n", MAX_MSIX_COUNT); + sc->irq_count = MAX_MSIX_COUNT; + } + + mtx_init(&sc->msi_mtx, "msi_mtx", NULL, MTX_DEF); + + sc->irq_alloc = vmem_create("Alpine MSI-X IRQs", 0, sc->irq_count, + 1, 0, M_FIRSTFIT | M_WAITOK); + + device_printf(dev, "MSI-X SPI IRQ %d-%d\n", sc->irq_min, sc->irq_max); + + return (bus_generic_attach(dev)); +} + +static int +al_find_intr_pos_in_map(device_t dev, struct intr_irqsrc *isrc) +{ + struct al_msix_softc *sc; + int i; + + sc = device_get_softc(dev); + for (i = 0; i < MAX_MSIX_COUNT; i++) + if (sc->isrcs[i] == isrc) + return (i); + return (ERR_NOT_IN_MAP); +} + +static int +al_msix_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc, + uint64_t *addr, uint32_t *data) +{ + struct al_msix_softc *sc; + int i, spi; + + sc = device_get_softc(dev); + + i = al_find_intr_pos_in_map(dev, isrc); + if (i == ERR_NOT_IN_MAP) + return (EINVAL); + + spi = sc->irq_min + i; + + /* + * MSIX message address format: + * [63:20] - MSIx TBAR + * Same value as the MSIx Translation Base Address Register + * [19] - WFE_EXIT + * Once set by MSIx message, an EVENTI is signal to the CPUs + * cluster specified by ‘Local GIC Target List’ + * [18:17] - Target GIC ID + * Specifies which IO-GIC (external shared GIC) is targeted + * 0: Local GIC, as specified by the Local GIC Target List + * 1: IO-GIC 0 + * 2: Reserved + * 3: Reserved + * [16:13] - Local GIC Target List + * Specifies the Local GICs list targeted by this MSIx + * message. + * [16] If set, SPIn is set in Cluster 0 local GIC + * [15:13] Reserved + * [15] If set, SPIn is set in Cluster 1 local GIC + * [14] If set, SPIn is set in Cluster 2 local GIC + * [13] If set, SPIn is set in Cluster 3 local GIC + * [12:3] - SPIn + * Specifies the SPI (Shared Peripheral Interrupt) index to + * be set in target GICs + * Notes: + * If targeting any local GIC than only SPI[249:0] are valid + * [2] - Function vector + * MSI Data vector extension hint + * [1:0] - Reserved + * Must be set to zero + */ + *addr = (uint64_t)sc->base_addr + (uint64_t)((1 << 16) + (spi << 3)); + *data = 0; + + if (bootverbose) + device_printf(dev, "MSI mapping: SPI: %d addr: %jx data: %x\n", + spi, (uintmax_t)*addr, *data); + return (0); +} + +static int +al_msix_alloc_msi(device_t dev, device_t child, int count, int maxcount, + device_t *pic, struct intr_irqsrc **srcs) +{ + struct intr_map_data_fdt *fdt_data; + struct al_msix_softc *sc; + vmem_addr_t irq_base; + int error; + u_int i, j; + + sc = device_get_softc(dev); + + if ((powerof2(count) == 0) || (count > 8)) + return (EINVAL); + + if (vmem_alloc(sc->irq_alloc, count, M_FIRSTFIT | M_NOWAIT, + &irq_base) != 0) + return (ENOMEM); + + /* Fabricate OFW data to get ISRC from GIC and return it */ + fdt_data = malloc(sizeof(*fdt_data) + + GIC_INTR_CELL_CNT * sizeof(pcell_t), M_AL_MSIX, M_WAITOK); + fdt_data->hdr.type = INTR_MAP_DATA_FDT; + fdt_data->iparent = 0; + fdt_data->ncells = GIC_INTR_CELL_CNT; + fdt_data->cells[0] = AL_SPI_INTR; /* code for SPI interrupt */ + fdt_data->cells[1] = 0; /* SPI number (uninitialized) */ + fdt_data->cells[2] = AL_EDGE_HIGH; /* trig = edge, pol = high */ + + mtx_lock(&sc->msi_mtx); + + for (i = irq_base; i < irq_base + count; i++) { + fdt_data->cells[1] = sc->irq_min + i; + error = PIC_MAP_INTR(sc->gic_dev, + (struct intr_map_data *)fdt_data, srcs); + if (error) { + for (j = irq_base; j < i; j++) + sc->isrcs[j] = NULL; + mtx_unlock(&sc->msi_mtx); + vmem_free(sc->irq_alloc, irq_base, count); + free(fdt_data, M_AL_MSIX); + return (error); + } + + sc->isrcs[i] = *srcs; + srcs++; + } + + mtx_unlock(&sc->msi_mtx); + free(fdt_data, M_AL_MSIX); + + if (bootverbose) + device_printf(dev, + "MSI-X allocation: start SPI %d, count %d\n", + (int)irq_base + sc->irq_min, count); + + *pic = sc->gic_dev; + + return (0); +} + +static int +al_msix_release_msi(device_t dev, device_t child, int count, + struct intr_irqsrc **srcs) +{ + struct al_msix_softc *sc; + int i, pos; + + sc = device_get_softc(dev); + + mtx_lock(&sc->msi_mtx); + + pos = al_find_intr_pos_in_map(dev, *srcs); + vmem_free(sc->irq_alloc, pos, count); + for (i = 0; i < count; i++) { + pos = al_find_intr_pos_in_map(dev, *srcs); + if (pos != ERR_NOT_IN_MAP) + sc->isrcs[pos] = NULL; + srcs++; + } + + mtx_unlock(&sc->msi_mtx); + + return (0); +} + +static int +al_msix_alloc_msix(device_t dev, device_t child, device_t *pic, + struct intr_irqsrc **isrcp) +{ + + return (al_msix_alloc_msi(dev, child, 1, 1, pic, isrcp)); +} + +static int +al_msix_release_msix(device_t dev, device_t child, struct intr_irqsrc *isrc) +{ + + return (al_msix_release_msi(dev, child, 1, &isrc)); +} diff --git a/sys/arm/annapurna/alpine/alpine_serdes.c b/sys/arm/annapurna/alpine/alpine_serdes.c new file mode 100644 index 000000000000..882b01a8da4f --- /dev/null +++ b/sys/arm/annapurna/alpine/alpine_serdes.c @@ -0,0 +1,225 @@ +/*- + * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates + * All rights reserved. + * + * Developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "al_serdes.h" +#include "alpine_serdes.h" + +#define SERDES_NUM_GROUPS 5 + +static void *serdes_base; +static uint32_t serdes_grp_offset[] = {0, 0x400, 0x800, 0xc00, 0x2000}; + +static struct alpine_serdes_eth_group_mode { + struct mtx lock; + enum alpine_serdes_eth_mode mode; + bool mode_set; +} alpine_serdes_eth_group_mode[SERDES_NUM_GROUPS]; + +static int al_serdes_probe(device_t dev); +static int al_serdes_attach(device_t dev); +static int al_serdes_detach(device_t dev); + +static struct resource_spec al_serdes_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, 0 } +}; + +struct al_serdes_softc { + struct resource *res; +}; + +static device_method_t al_serdes_methods[] = { + DEVMETHOD(device_probe, al_serdes_probe), + DEVMETHOD(device_attach, al_serdes_attach), + DEVMETHOD(device_detach, al_serdes_detach), + + DEVMETHOD_END +}; + +static driver_t al_serdes_driver = { + "serdes", + al_serdes_methods, + sizeof(struct al_serdes_softc) +}; + +static devclass_t al_serdes_devclass; + +DRIVER_MODULE(al_serdes, simplebus, al_serdes_driver, + al_serdes_devclass, 0, 0); +DRIVER_MODULE(al_serdes, ofwbus, al_serdes_driver, + al_serdes_devclass, 0, 0); + +static int +al_serdes_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "annapurna-labs,al-serdes")) + return (ENXIO); + + device_set_desc(dev, "Alpine Serdes"); + + return (BUS_PROBE_DEFAULT); +} + +static int +al_serdes_attach(device_t dev) +{ + struct al_serdes_softc *sc; + int err; + + sc = device_get_softc(dev); + + err = bus_alloc_resources(dev, al_serdes_spec, &sc->res); + if (err != 0) { + device_printf(dev, "could not allocate resources\n"); + return (err); + } + + /* Initialize Serdes group locks and mode */ + for (int i = 0; i < nitems(alpine_serdes_eth_group_mode); i++) { + mtx_init(&alpine_serdes_eth_group_mode[i].lock, "AlSerdesMtx", + NULL, MTX_DEF); + alpine_serdes_eth_group_mode[i].mode_set = false; + } + + serdes_base = (void *)rman_get_bushandle(sc->res); + + return (0); +} + +static int +al_serdes_detach(device_t dev) +{ + struct al_serdes_softc *sc; + + sc = device_get_softc(dev); + + bus_release_resources(dev, al_serdes_spec, &sc->res); + + for (int i = 0; i < nitems(alpine_serdes_eth_group_mode); i++) { + mtx_destroy(&alpine_serdes_eth_group_mode[i].lock); + alpine_serdes_eth_group_mode[i].mode_set = false; + } + + return (0); +} + +void * +alpine_serdes_resource_get(uint32_t group) +{ + void *base; + + base = NULL; + if (group >= SERDES_NUM_GROUPS) + return (NULL); + + if (serdes_base != NULL) + base = (void *)((uintptr_t)serdes_base + + serdes_grp_offset[group]); + + return (base); +} + +int +alpine_serdes_eth_mode_set(uint32_t group, enum alpine_serdes_eth_mode mode) +{ + struct alpine_serdes_eth_group_mode *group_mode; + + group_mode = &alpine_serdes_eth_group_mode[group]; + + if (serdes_base == NULL) + return (EINVAL); + + if (group >= SERDES_NUM_GROUPS) + return (EINVAL); + + mtx_lock(&group_mode->lock); + + if (!group_mode->mode_set || (group_mode->mode != mode)) { + struct al_serdes_grp_obj obj; + + al_serdes_handle_grp_init(alpine_serdes_resource_get(group), + group, &obj); + + if (mode == ALPINE_SERDES_ETH_MODE_SGMII) + obj.mode_set_sgmii(&obj); + else + obj.mode_set_kr(&obj); + + group_mode->mode = mode; + group_mode->mode_set = true; + } + + mtx_unlock(&group_mode->lock); + + return (0); +} + +void +alpine_serdes_eth_group_lock(uint32_t group) +{ + struct alpine_serdes_eth_group_mode *group_mode; + + group_mode = &alpine_serdes_eth_group_mode[group]; + + if (mtx_initialized(&group_mode->lock) == 0) + return; + + mtx_lock(&group_mode->lock); +} + +void +alpine_serdes_eth_group_unlock(uint32_t group) +{ + struct alpine_serdes_eth_group_mode *group_mode; + + group_mode = &alpine_serdes_eth_group_mode[group]; + + if (mtx_initialized(&group_mode->lock) == 0) + return; + + mtx_unlock(&group_mode->lock); +} diff --git a/sys/arm/annapurna/alpine/alpine_serdes.h b/sys/arm/annapurna/alpine/alpine_serdes.h new file mode 100644 index 000000000000..034bdadfb15e --- /dev/null +++ b/sys/arm/annapurna/alpine/alpine_serdes.h @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates + * All rights reserved. + * + * Developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef __ALPINE_SERDES_H__ +#define __ALPINE_SERDES_H__ + +/* SerDes ETH mode */ +enum alpine_serdes_eth_mode { + ALPINE_SERDES_ETH_MODE_SGMII, + ALPINE_SERDES_ETH_MODE_KR, +}; + +/* + * Get SerDes group regs base, to be used in relevant Alpine drivers. + * Valid group is 0..3. + * Returns virtual base address of the group regs base. + */ +void *alpine_serdes_resource_get(uint32_t group); + +/* + * Set SerDes ETH mode for an entire group, unless already set + * Valid group is 0..3. + * Returns 0 upon success. + */ +int alpine_serdes_eth_mode_set(uint32_t group, + enum alpine_serdes_eth_mode mode); + +/* Lock the all serdes group for using common registers */ +void alpine_serdes_eth_group_lock(uint32_t group); + +/* Unlock the all serdes group for using common registers */ +void alpine_serdes_eth_group_unlock(uint32_t group); + +#endif /* __ALPINE_SERDES_H__ */ diff --git a/sys/arm/at91/at91_ohci.c b/sys/arm/at91/at91_ohci.c index 3e39f5115450..4d8e30150767 100644 --- a/sys/arm/at91/at91_ohci.c +++ b/sys/arm/at91/at91_ohci.c @@ -165,14 +165,8 @@ static int ohci_atmelarm_detach(device_t dev) { struct at91_ohci_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_ohci.sc_bus.bdev) { - bdev = sc->sc_ohci.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/arm/at91/at91_ohci_fdt.c b/sys/arm/at91/at91_ohci_fdt.c index de3d3574deb2..51d9509fedcd 100644 --- a/sys/arm/at91/at91_ohci_fdt.c +++ b/sys/arm/at91/at91_ohci_fdt.c @@ -171,14 +171,8 @@ static int ohci_at91_fdt_detach(device_t dev) { struct at91_ohci_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_ohci.sc_bus.bdev) { - bdev = sc->sc_ohci.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/arm/cavium/cns11xx/ehci_ebus.c b/sys/arm/cavium/cns11xx/ehci_ebus.c index 18f6a144fd1f..51c4f2c76f59 100644 --- a/sys/arm/cavium/cns11xx/ehci_ebus.c +++ b/sys/arm/cavium/cns11xx/ehci_ebus.c @@ -184,14 +184,8 @@ static int ehci_ebus_detach(device_t self) { ehci_softc_t *sc = device_get_softc(self); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/arm/cavium/cns11xx/ohci_ec.c b/sys/arm/cavium/cns11xx/ohci_ec.c index 9c49b1ea1121..78183ea80e02 100644 --- a/sys/arm/cavium/cns11xx/ohci_ec.c +++ b/sys/arm/cavium/cns11xx/ohci_ec.c @@ -177,14 +177,8 @@ static int ohci_ec_detach(device_t dev) { struct ec_ohci_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_ohci.sc_bus.bdev) { - bdev = sc->sc_ohci.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/arm/conf/ALPINE b/sys/arm/conf/ALPINE index b231df14f3c3..7ef285bf82f9 100644 --- a/sys/arm/conf/ALPINE +++ b/sys/arm/conf/ALPINE @@ -35,6 +35,9 @@ options INTRNG # Annapurna Alpine drivers device al_ccu # Alpine Cache Coherency Unit device al_nb_service # Alpine North Bridge Service +device al_iofic # I/O Fabric Interrupt Controller +device al_serdes # Serializer/Deserializer +device al_udma # Universal DMA # Pseudo devices device loop @@ -69,6 +72,7 @@ device al_pci # Annapurna Alpine PCI-E device ether device mii device bpf +device al_eth # Annapurna Alpine Ethernet NIC options DEVICE_POLLING # USB ethernet support, requires miibus diff --git a/sys/arm/conf/PANDABOARD b/sys/arm/conf/PANDABOARD index b98c4b020396..4848cea6b034 100644 --- a/sys/arm/conf/PANDABOARD +++ b/sys/arm/conf/PANDABOARD @@ -30,6 +30,8 @@ hints "PANDABOARD.hints" include "std.armv6" include "../ti/omap4/pandaboard/std.pandaboard" +makeoptions MODULES_EXTRA=dtb/omap4 + options SCHED_ULE # ULE scheduler options PLATFORM options SMP # Enable multiple cores diff --git a/sys/arm/nvidia/as3722_regulators.c b/sys/arm/nvidia/as3722_regulators.c index 314428faa9b6..8ea00d902cab 100644 --- a/sys/arm/nvidia/as3722_regulators.c +++ b/sys/arm/nvidia/as3722_regulators.c @@ -71,13 +71,6 @@ enum as3722_reg_id { AS3722_REG_ID_LDO11, }; -struct regulator_range { - u_int min_uvolt; - u_int step_uvolt; - u_int min_sel; - u_int max_sel; -}; - /* Regulator HW definition. */ struct reg_def { @@ -107,40 +100,32 @@ struct as3722_reg_sc { int enable_usec; }; -#define RANGE_INIT(_min_sel, _max_sel, _min_uvolt, _step_uvolt) \ -{ \ - .min_sel = _min_sel, \ - .max_sel = _max_sel, \ - .min_uvolt = _min_uvolt, \ - .step_uvolt = _step_uvolt, \ -} - static struct regulator_range as3722_sd016_ranges[] = { - RANGE_INIT(0x00, 0x00, 0, 0), - RANGE_INIT(0x01, 0x5A, 610000, 10000), + REG_RANGE_INIT(0x00, 0x00, 0, 0), + REG_RANGE_INIT(0x01, 0x5A, 610000, 10000), }; static struct regulator_range as3722_sd0_lv_ranges[] = { - RANGE_INIT(0x00, 0x00, 0, 0), - RANGE_INIT(0x01, 0x6E, 410000, 10000), + REG_RANGE_INIT(0x00, 0x00, 0, 0), + REG_RANGE_INIT(0x01, 0x6E, 410000, 10000), }; static struct regulator_range as3722_sd_ranges[] = { - RANGE_INIT(0x00, 0x00, 0, 0), - RANGE_INIT(0x01, 0x40, 612500, 12500), - RANGE_INIT(0x41, 0x70, 1425000, 25000), - RANGE_INIT(0x71, 0x7F, 2650000, 50000), + REG_RANGE_INIT(0x00, 0x00, 0, 0), + REG_RANGE_INIT(0x01, 0x40, 612500, 12500), + REG_RANGE_INIT(0x41, 0x70, 1425000, 25000), + REG_RANGE_INIT(0x71, 0x7F, 2650000, 50000), }; static struct regulator_range as3722_ldo3_ranges[] = { - RANGE_INIT(0x00, 0x00, 0, 0), - RANGE_INIT(0x01, 0x2D, 620000, 20000), + REG_RANGE_INIT(0x00, 0x00, 0, 0), + REG_RANGE_INIT(0x01, 0x2D, 620000, 20000), }; static struct regulator_range as3722_ldo_ranges[] = { - RANGE_INIT(0x00, 0x00, 0, 0), - RANGE_INIT(0x01, 0x24, 825000, 25000), - RANGE_INIT(0x40, 0x7F, 1725000, 25000), + REG_RANGE_INIT(0x00, 0x00, 0, 0), + REG_RANGE_INIT(0x01, 0x24, 825000, 25000), + REG_RANGE_INIT(0x40, 0x7F, 1725000, 25000), }; static struct reg_def as3722s_def[] = { @@ -401,87 +386,6 @@ static regnode_method_t as3722_regnode_methods[] = { DEFINE_CLASS_1(as3722_regnode, as3722_regnode_class, as3722_regnode_methods, sizeof(struct as3722_reg_sc), regnode_class); -static int -regulator_range_sel_to_volt(struct as3722_reg_sc *sc, uint8_t sel, int *volt) -{ - struct regulator_range *range; - struct reg_def *def; - int i; - - def = sc->def; - if (def->nranges == 0) - panic("Voltage regulator have zero ranges\n"); - - for (i = 0; i < def->nranges ; i++) { - range = def->ranges + i; - - if (!(sel >= range->min_sel && - sel <= range->max_sel)) - continue; - - sel -= range->min_sel; - - *volt = range->min_uvolt + sel * range->step_uvolt; - return (0); - } - - return (ERANGE); -} - -static int -regulator_range_volt_to_sel(struct as3722_reg_sc *sc, int min_uvolt, - int max_uvolt, uint8_t *out_sel) -{ - struct regulator_range *range; - struct reg_def *def; - uint8_t sel; - int uvolt; - int rv, i; - - def = sc->def; - if (def->nranges == 0) - panic("Voltage regulator have zero ranges\n"); - - for (i = 0; i < def->nranges; i++) { - range = def->ranges + i; - uvolt = range->min_uvolt + - (range->max_sel - range->min_sel) * range->step_uvolt; - - if ((min_uvolt > uvolt) || - (max_uvolt < range->min_uvolt)) - continue; - - if (min_uvolt <= range->min_uvolt) - min_uvolt = range->min_uvolt; - - /* If step is zero then range is fixed voltage range. */ - if (range->step_uvolt == 0) - sel = 0; - else - sel = DIV_ROUND_UP(min_uvolt - range->min_uvolt, - range->step_uvolt); - - - sel += range->min_sel; - - break; - } - - if (i >= def->nranges) - return (ERANGE); - - /* Verify new settings. */ - rv = regulator_range_sel_to_volt(sc, sel, &uvolt); - if (rv != 0) - return (rv); - if ((uvolt < min_uvolt) || (uvolt > max_uvolt)) - return (ERANGE); - - *out_sel = sel; - return (0); -} - - static int as3722_read_sel(struct as3722_reg_sc *sc, uint8_t *sel) { @@ -783,7 +687,8 @@ as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt, sc = regnode_get_softc(regnode); *udelay = 0; - rv = regulator_range_volt_to_sel(sc, min_uvolt, max_uvolt, &sel); + rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges, + min_uvolt, max_uvolt, &sel); if (rv != 0) return (rv); rv = as3722_write_sel(sc, sel); @@ -806,6 +711,7 @@ as3722_regnode_get_volt(struct regnode *regnode, int *uvolt) /* LDO6 have bypass. */ if (sc->def->id == AS3722_REG_ID_LDO6 && sel == AS3722_LDO6_SEL_BYPASS) return (ENOENT); - rv = regulator_range_sel_to_volt(sc, sel, uvolt); + rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges, + sel, uvolt); return (rv); } diff --git a/sys/arm/nvidia/tegra124/tegra124_coretemp.c b/sys/arm/nvidia/tegra124/tegra124_coretemp.c index 1ad86326a27c..0becdb06626a 100644 --- a/sys/arm/nvidia/tegra124/tegra124_coretemp.c +++ b/sys/arm/nvidia/tegra124/tegra124_coretemp.c @@ -178,10 +178,14 @@ tegra124_coretemp_ofw_parse(struct tegra124_coretemp_softc *sc) static void tegra124_coretemp_identify(driver_t *driver, device_t parent) { + phandle_t root; - if (device_find_child(parent, "coretemp", -1) != NULL) + root = OF_finddevice("/"); + if (!ofw_bus_node_is_compatible(root, "nvidia,tegra124")) return; - if (BUS_ADD_CHILD(parent, 0, "coretemp", -1) == NULL) + if (device_find_child(parent, "tegra124_coretemp", -1) != NULL) + return; + if (BUS_ADD_CHILD(parent, 0, "tegra124_coretemp", -1) == NULL) device_printf(parent, "add child failed\n"); } @@ -262,7 +266,7 @@ static device_method_t tegra124_coretemp_methods[] = { }; static devclass_t tegra124_coretemp_devclass; -static DEFINE_CLASS_0(coretemp, tegra124_coretemp_driver, +static DEFINE_CLASS_0(tegra124_coretemp, tegra124_coretemp_driver, tegra124_coretemp_methods, sizeof(struct tegra124_coretemp_softc)); DRIVER_MODULE(tegra124_coretemp, cpu, tegra124_coretemp_driver, tegra124_coretemp_devclass, NULL, NULL); diff --git a/sys/arm/nvidia/tegra124/tegra124_cpufreq.c b/sys/arm/nvidia/tegra124/tegra124_cpufreq.c index 2fc9c2bf0589..4de8603dee8a 100644 --- a/sys/arm/nvidia/tegra124/tegra124_cpufreq.c +++ b/sys/arm/nvidia/tegra124/tegra124_cpufreq.c @@ -141,7 +141,7 @@ static struct speedo_entry tegra124_speedo_pllx_tbl[] = static struct cpu_volt_def tegra124_cpu_volt_pllx_def = { - .min_uvolt = 900000, /* 0.9 V */ + .min_uvolt = 1000000, /* XXX 0.9 V doesn't work on all boards */ .max_uvolt = 1260000, /* 1.26 */ .step_uvolt = 10000, /* 10 mV */ .speedo_scale = 100, @@ -172,7 +172,6 @@ static uint64_t cpu_freq_tbl[] = { 2116000000ULL, 2218000000ULL, 2320000000ULL, - 2320000000ULL, 2422000000ULL, 2524000000ULL, }; @@ -475,6 +474,11 @@ get_fdt_resources(struct tegra124_cpufreq_softc *sc, phandle_t node) static void tegra124_cpufreq_identify(driver_t *driver, device_t parent) { + phandle_t root; + + root = OF_finddevice("/"); + if (!ofw_bus_node_is_compatible(root, "nvidia,tegra124")) + return; if (device_get_unit(parent) != 0) return; diff --git a/sys/arm/nvidia/tegra124/tegra124_machdep.c b/sys/arm/nvidia/tegra124/tegra124_machdep.c index 292892cba699..0e881cc83ad1 100644 --- a/sys/arm/nvidia/tegra124/tegra124_machdep.c +++ b/sys/arm/nvidia/tegra124/tegra124_machdep.c @@ -120,18 +120,18 @@ tegra124_cpu_reset(platform_t plat) /* * Early putc routine for EARLY_PRINTF support. To use, add to kernel config: - * option SOCDEV_PA=0x02000000 - * option SOCDEV_VA=0x02000000 + * option SOCDEV_PA=0x70000000 + * option SOCDEV_VA=0x70000000 * option EARLY_PRINTF */ -#if 0 +#ifdef EARLY_PRINTF static void tegra124_early_putc(int c) { - volatile uint32_t * UART_STAT_REG = (uint32_t *)0x02020098; - volatile uint32_t * UART_TX_REG = (uint32_t *)0x02020040; - const uint32_t UART_TXRDY = (1 << 3); + volatile uint32_t * UART_STAT_REG = (uint32_t *)(0x70006314); + volatile uint32_t * UART_TX_REG = (uint32_t *)(0x70006300); + const uint32_t UART_TXRDY = (1 << 6); while ((*UART_STAT_REG & UART_TXRDY) == 0) continue; *UART_TX_REG = c; diff --git a/sys/arm/samsung/exynos/exynos5_xhci.c b/sys/arm/samsung/exynos/exynos5_xhci.c index 2accd4c04268..dbb8d3c54dea 100644 --- a/sys/arm/samsung/exynos/exynos5_xhci.c +++ b/sys/arm/samsung/exynos/exynos5_xhci.c @@ -288,14 +288,8 @@ static int exynos_xhci_detach(device_t dev) { struct exynos_xhci_softc *esc = device_get_softc(dev); - device_t bdev; int err; - if (esc->base.sc_bus.bdev != NULL) { - bdev = esc->base.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* During module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/arm/ti/am335x/am335x_musb.c b/sys/arm/ti/am335x/am335x_musb.c index 4dc96c35a114..c168493d0867 100644 --- a/sys/arm/ti/am335x/am335x_musb.c +++ b/sys/arm/ti/am335x/am335x_musb.c @@ -366,14 +366,10 @@ static int musbotg_detach(device_t dev) { struct musbotg_super_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_otg.sc_bus.bdev) { - bdev = sc->sc_otg.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } + /* during module unload there are lots of children leftover */ + device_delete_children(dev); if (sc->sc_otg.sc_irq_res && sc->sc_otg.sc_intr_hdl) { /* @@ -397,9 +393,6 @@ musbotg_detach(device_t dev) bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irq_rid, sc->sc_otg.sc_irq_res); - /* during module unload there are lots of children leftover */ - device_delete_children(dev); - return (0); } diff --git a/sys/arm/ti/usb/omap_ehci.c b/sys/arm/ti/usb/omap_ehci.c index 7ce957f55711..f7e2057b852c 100644 --- a/sys/arm/ti/usb/omap_ehci.c +++ b/sys/arm/ti/usb/omap_ehci.c @@ -392,15 +392,8 @@ omap_ehci_detach(device_t dev) { struct omap_ehci_softc *isc = device_get_softc(dev); ehci_softc_t *sc = &isc->base; - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } - /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/arm/xilinx/zy7_ehci.c b/sys/arm/xilinx/zy7_ehci.c index f03c131adb4b..6468faa7ac13 100644 --- a/sys/arm/xilinx/zy7_ehci.c +++ b/sys/arm/xilinx/zy7_ehci.c @@ -323,20 +323,17 @@ zy7_ehci_detach(device_t dev) { ehci_softc_t *sc = device_get_softc(dev); + /* during module unload there are lots of children leftover */ + device_delete_children(dev); + sc->sc_flags &= ~EHCI_SCFLG_DONEINIT; - if (device_is_attached(dev)) - bus_generic_detach(dev); - if (sc->sc_irq_res && sc->sc_intr_hdl) /* call ehci_detach() after ehci_init() called after * successful bus_setup_intr(). */ ehci_detach(sc); - if (sc->sc_bus.bdev) { - device_detach(sc->sc_bus.bdev); - device_delete_child(dev, sc->sc_bus.bdev); - } + if (sc->sc_irq_res) { if (sc->sc_intr_hdl != NULL) bus_teardown_intr(dev, sc->sc_irq_res, diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c index 9813fec4aca4..da2af94cae8b 100644 --- a/sys/arm64/arm64/machdep.c +++ b/sys/arm64/arm64/machdep.c @@ -341,6 +341,8 @@ get_fpcontext(struct thread *td, mcontext_t *mcp) KASSERT(curpcb->pcb_fpusaved == &curpcb->pcb_fpustate, ("Called get_fpcontext while the kernel is using the VFP")); + KASSERT((curpcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0, + ("Non-userspace FPU flags set in get_fpcontext")); memcpy(mcp->mc_fpregs.fp_q, curpcb->pcb_fpustate.vfp_regs, sizeof(mcp->mc_fpregs)); mcp->mc_fpregs.fp_cr = curpcb->pcb_fpustate.vfp_fpcr; @@ -376,7 +378,7 @@ set_fpcontext(struct thread *td, mcontext_t *mcp) sizeof(mcp->mc_fpregs)); curpcb->pcb_fpustate.vfp_fpcr = mcp->mc_fpregs.fp_cr; curpcb->pcb_fpustate.vfp_fpsr = mcp->mc_fpregs.fp_sr; - curpcb->pcb_fpflags = mcp->mc_fpregs.fp_flags; + curpcb->pcb_fpflags = mcp->mc_fpregs.fp_flags & PCB_FP_USERMASK; } critical_exit(); diff --git a/sys/arm64/arm64/trap.c b/sys/arm64/arm64/trap.c index 1748ece48316..07752a90e036 100644 --- a/sys/arm64/arm64/trap.c +++ b/sys/arm64/arm64/trap.c @@ -282,9 +282,17 @@ do_el1h_sync(struct trapframe *frame) switch(exception) { case EXCP_FP_SIMD: case EXCP_TRAP_FP: - print_registers(frame); - printf(" esr: %.8lx\n", esr); - panic("VFP exception in the kernel"); +#ifdef VFP + if ((curthread->td_pcb->pcb_fpflags & PCB_FP_KERN) != 0) { + vfp_restore_state(); + } else +#endif + { + print_registers(frame); + printf(" esr: %.8lx\n", esr); + panic("VFP exception in the kernel"); + } + break; case EXCP_INSN_ABORT: case EXCP_DATA_ABORT: far = READ_SPECIALREG(far_el1); @@ -409,6 +417,12 @@ do_el0_sync(struct trapframe *frame) userret(td, frame); break; } + + KASSERT((curthread->td_pcb->pcb_fpflags & ~PCB_FP_USERMASK) == 0, + ("Kernel VFP flags set while entering userspace")); + KASSERT( + curthread->td_pcb->pcb_fpusaved == &curthread->td_pcb->pcb_fpustate, + ("Kernel VFP state in use when entering userspace")); } void diff --git a/sys/arm64/arm64/vfp.c b/sys/arm64/arm64/vfp.c index f1fbb56a3521..e901ea7b27cf 100644 --- a/sys/arm64/arm64/vfp.c +++ b/sys/arm64/arm64/vfp.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2015 The FreeBSD Foundation + * Copyright (c) 2015-2016 The FreeBSD Foundation * All rights reserved. * * This software was developed by Andrew Turner under @@ -48,6 +48,14 @@ CTASSERT(sizeof(((struct pcb *)0)->pcb_fpustate.vfp_regs) == 16 * 32); static MALLOC_DEFINE(M_FPUKERN_CTX, "fpukern_ctx", "Kernel contexts for VFP state"); +struct fpu_kern_ctx { + struct vfpstate *prev; +#define FPU_KERN_CTX_DUMMY 0x01 /* avoided save for the kern thread */ +#define FPU_KERN_CTX_INUSE 0x02 + uint32_t flags; + struct vfpstate state; +}; + static void vfp_enable(void) { @@ -71,9 +79,10 @@ vfp_disable(void) } /* - * Called when the thread is dying. If the thread was the last to use the - * VFP unit mark it as unused to tell the kernel the fp state is unowned. - * Ensure the VFP unit is off so we get an exception on the next access. + * Called when the thread is dying or when discarding the kernel VFP state. + * If the thread was the last to use the VFP unit mark it as unused to tell + * the kernel the fp state is unowned. Ensure the VFP unit is off so we get + * an exception on the next access. */ void vfp_discard(struct thread *td) @@ -226,4 +235,111 @@ vfp_init(void) SYSINIT(vfp, SI_SUB_CPU, SI_ORDER_ANY, vfp_init, NULL); +struct fpu_kern_ctx * +fpu_kern_alloc_ctx(u_int flags) +{ + struct fpu_kern_ctx *res; + size_t sz; + + sz = sizeof(struct fpu_kern_ctx); + res = malloc(sz, M_FPUKERN_CTX, ((flags & FPU_KERN_NOWAIT) ? + M_NOWAIT : M_WAITOK) | M_ZERO); + return (res); +} + +void +fpu_kern_free_ctx(struct fpu_kern_ctx *ctx) +{ + + KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) == 0, ("free'ing inuse ctx")); + /* XXXAndrew clear the memory ? */ + free(ctx, M_FPUKERN_CTX); +} + +int +fpu_kern_enter(struct thread *td, struct fpu_kern_ctx *ctx, u_int flags) +{ + struct pcb *pcb; + + pcb = td->td_pcb; + KASSERT(ctx == NULL || (ctx->flags & FPU_KERN_CTX_INUSE) == 0, + ("using inuse ctx")); + + if ((flags & FPU_KERN_KTHR) != 0 && is_fpu_kern_thread(0)) { + ctx->flags = FPU_KERN_CTX_DUMMY | FPU_KERN_CTX_INUSE; + return (0); + } + /* + * Check either we are already using the VFP in the kernel, or + * the the saved state points to the default user space. + */ + KASSERT((pcb->pcb_fpflags & PCB_FP_KERN) != 0 || + pcb->pcb_fpusaved == &pcb->pcb_fpustate, + ("Mangled pcb_fpusaved %x %p %p", pcb->pcb_fpflags, pcb->pcb_fpusaved, &pcb->pcb_fpustate)); + ctx->flags = FPU_KERN_CTX_INUSE; + vfp_save_state(curthread, pcb); + ctx->prev = pcb->pcb_fpusaved; + pcb->pcb_fpusaved = &ctx->state; + pcb->pcb_fpflags |= PCB_FP_KERN; + pcb->pcb_fpflags &= ~PCB_FP_STARTED; + + return (0); +} + +int +fpu_kern_leave(struct thread *td, struct fpu_kern_ctx *ctx) +{ + struct pcb *pcb; + + pcb = td->td_pcb; + + KASSERT((ctx->flags & FPU_KERN_CTX_INUSE) != 0, + ("FPU context not inuse")); + ctx->flags &= ~FPU_KERN_CTX_INUSE; + + if (is_fpu_kern_thread(0) && + (ctx->flags & FPU_KERN_CTX_DUMMY) != 0) + return (0); + KASSERT((ctx->flags & FPU_KERN_CTX_DUMMY) == 0, ("dummy ctx")); + critical_enter(); + vfp_discard(td); + critical_exit(); + pcb->pcb_fpflags &= ~PCB_FP_STARTED; + pcb->pcb_fpusaved = ctx->prev; + + if (pcb->pcb_fpusaved == &pcb->pcb_fpustate) { + pcb->pcb_fpflags &= ~PCB_FP_KERN; + } else { + KASSERT((pcb->pcb_fpflags & PCB_FP_KERN) != 0, + ("unpaired fpu_kern_leave")); + } + + return (0); +} + +int +fpu_kern_thread(u_int flags) +{ + struct pcb *pcb = curthread->td_pcb; + + KASSERT((curthread->td_pflags & TDP_KTHREAD) != 0, + ("Only kthread may use fpu_kern_thread")); + KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate, + ("Mangled pcb_fpusaved")); + KASSERT((pcb->pcb_fpflags & PCB_FP_KERN) == 0, + ("Thread already setup for the VFP")); + pcb->pcb_fpflags |= PCB_FP_KERN; + return (0); +} + +int +is_fpu_kern_thread(u_int flags) +{ + struct pcb *curpcb; + + if ((curthread->td_pflags & TDP_KTHREAD) == 0) + return (0); + curpcb = curthread->td_pcb; + return ((curpcb->pcb_fpflags & PCB_FP_KERN) != 0); +} #endif diff --git a/sys/arm64/conf/GENERIC b/sys/arm64/conf/GENERIC index 1c8b73bea458..4502dc8fb1bf 100644 --- a/sys/arm64/conf/GENERIC +++ b/sys/arm64/conf/GENERIC @@ -94,6 +94,9 @@ options SOC_HISI_HI6220 # Annapurna Alpine drivers device al_ccu # Alpine Cache Coherency Unit device al_nb_service # Alpine North Bridge Service +device al_iofic # I/O Fabric Interrupt Controller +device al_serdes # Serializer/Deserializer +device al_udma # Universal DMA # VirtIO support device virtio @@ -119,6 +122,7 @@ device igb # Intel PRO/1000 PCIE Server Gigabit Family device ix # Intel 10Gb Ethernet Family device msk # Marvell/SysKonnect Yukon II Gigabit Ethernet device vnic # Cavium ThunderX NIC +device al_eth # Annapurna Alpine Ethernet NIC # Block devices device ahci @@ -129,6 +133,7 @@ device da device pass # Passthrough device (direct ATA/SCSI access) # MMC/SD/SDIO Card slot support +device sdhci device aw_mmc # Allwinner SD/MMC controller device mmc # mmc/sd bus device mmcsd # mmc/sd flash cards @@ -152,13 +157,19 @@ device usb # USB Bus (required) device ukbd # Keyboard device umass # Disks/Mass storage - Requires scbus and da +# USB ethernet support +device smcphy +device smsc + # GPIO device aw_gpio # Allwinner GPIO controller device gpio +device gpioled device fdt_pinctrl # I2C device aw_rsb # Allwinner Reduced Serial Bus +device bcm2835_bsc # Broadcom BCM283x I2C bus device iicbus # Clock and reset controllers @@ -182,6 +193,14 @@ device aw_sid # Allwinner Secure ID EFUSE # Thermal sensors device aw_thermal # Allwinner Thermal Sensor Controller +# SPI +device spibus +device bcm2835_spi # Broadcom BCM283x SPI bus + +# Console +device vt +device kbdmux + # Pseudo devices. device loop # Network loopback device random # Entropy device diff --git a/sys/arm64/conf/GENERIC-UP b/sys/arm64/conf/GENERIC-UP new file mode 100644 index 000000000000..566c7892705c --- /dev/null +++ b/sys/arm64/conf/GENERIC-UP @@ -0,0 +1,25 @@ +# +# GENERIC -- Generic kernel configuration file for FreeBSD/arm64 with SMP disabled +# +# For more information on this file, please read the config(5) manual page, +# and/or the handbook section on Kernel Configuration Files: +# +# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html +# +# The handbook is also available locally in /usr/share/doc/handbook +# if you've installed the doc distribution, otherwise always see the +# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the +# latest information. +# +# An exhaustive list of options and more detailed explanations of the +# device lines is also present in the ../../conf/NOTES and NOTES files. +# If you are in doubt as to the purpose or necessity of a line, check first +# in NOTES. +# +# $FreeBSD$ + +include GENERIC +ident GENERIC-UP +nooptions SMP + +options SOC_BRCM_BCM2837 diff --git a/sys/arm64/conf/RPI3 b/sys/arm64/conf/RPI3 deleted file mode 100644 index 0ae44b16367a..000000000000 --- a/sys/arm64/conf/RPI3 +++ /dev/null @@ -1,157 +0,0 @@ -# -# -# RPI3 -- Custom configuration for the Raspberry Pi 3 -# -# For more information on this file, please read the config(5) manual page, -# and/or the handbook section on Kernel Configuration Files: -# -# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html -# -# The handbook is also available locally in /usr/share/doc/handbook -# if you've installed the doc distribution, otherwise always see the -# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the -# latest information. -# -# An exhaustive list of options and more detailed explanations of the -# device lines is also present in the ../../conf/NOTES and NOTES files. -# If you are in doubt as to the purpose or necessity of a line, check first -# in NOTES. -# -# $FreeBSD$ - -cpu ARM64 -ident RPI3 - -makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols -#makeoptions WITH_CTF=1 # Run ctfconvert(1) for DTrace support - -options SCHED_ULE # ULE scheduler -options PREEMPTION # Enable kernel thread preemption -options INET # InterNETworking -options INET6 # IPv6 communications protocols -options IPSEC # IP (v4/v6) security -options TCP_HHOOK # hhook(9) framework for TCP -options TCP_OFFLOAD # TCP offload -options SCTP # Stream Control Transmission Protocol -options FFS # Berkeley Fast Filesystem -options SOFTUPDATES # Enable FFS soft updates support -options UFS_ACL # Support for access control lists -options UFS_DIRHASH # Improve performance on big directories -options UFS_GJOURNAL # Enable gjournal-based UFS journaling -options QUOTA # Enable disk quotas for UFS -options MD_ROOT # MD is a potential root device -options NFSCL # Network Filesystem Client -options NFSD # Network Filesystem Server -options NFSLOCKD # Network Lock Manager -options NFS_ROOT # NFS usable as /, requires NFSCL -options MSDOSFS # MSDOS Filesystem -options CD9660 # ISO 9660 Filesystem -options PROCFS # Process filesystem (requires PSEUDOFS) -options PSEUDOFS # Pseudo-filesystem framework -options GEOM_PART_GPT # GUID Partition Tables. -options GEOM_RAID # Soft RAID functionality. -options GEOM_LABEL # Provides labelization -options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI -options KTRACE # ktrace(1) support -options STACK # stack(9) support -options SYSVSHM # SYSV-style shared memory -options SYSVMSG # SYSV-style message queues -options SYSVSEM # SYSV-style semaphores -options _KPOSIX_PRIORITY_SCHEDULING # POSIX P1003_1B real-time extensions -options PRINTF_BUFR_SIZE=128 # Prevent printf output being interspersed. -options KBD_INSTALL_CDEV # install a CDEV entry in /dev -options HWPMC_HOOKS # Necessary kernel hooks for hwpmc(4) -options AUDIT # Security event auditing -options CAPABILITY_MODE # Capsicum capability mode -options CAPABILITIES # Capsicum capabilities -options MAC # TrustedBSD MAC Framework -options KDTRACE_FRAME # Ensure frames are compiled in -options KDTRACE_HOOKS # Kernel DTrace hooks -options VFP # Floating-point support -options RACCT # Resource accounting framework -options RACCT_DEFAULT_TO_DISABLED # Set kern.racct.enable=0 by default -options RCTL # Resource limits -# SMP is not there yet -# options SMP -options INTRNG - -# Debugging support. Always need this: -options KDB # Enable kernel debugger support. -options KDB_TRACE # Print a stack trace for a panic. -# For full debugger support use (turn off in stable branch): -options DDB # Support DDB. -#options GDB # Support remote GDB. -options DEADLKRES # Enable the deadlock resolver -options INVARIANTS # Enable calls of extra sanity checking -options INVARIANT_SUPPORT # Extra sanity checks of internal structures, required by INVARIANTS -options WITNESS # Enable checks to detect deadlocks and cycles -options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed -options MALLOC_DEBUG_MAXZONES=8 # Separate malloc(9) zones - -options SOC_BRCM_BCM2837 - -options ROOTDEVNAME=\"ufs:mmcsd0s2\" - -# SPI -device spibus -device bcm2835_spi - -# MMC/SD/SDIO Card slot support -device sdhci -device mmc # mmc/sd bus -device mmcsd # mmc/sd flash cards - -# Serial (COM) ports -device uart # Generic UART driver -device uart_ns8250 # ns8250-type UART driver -device pl011 - -# USB support -options USB_DEBUG # enable debug msgs -device usb # USB Bus (required) -device dwcotg # DWC OTG controller - -# USB storage support -device scbus -device da -device umass - -# USB ethernet support -device smcphy -device mii -device smsc - -# Comment following lines for boot console on serial port -device vt -device kbdmux -device ukbd # Keyboard - -# GPIO -device gpio -device fdt_pinctrl -device gpioled - -# I2C -device iicbus -device bcm2835_bsc - -# Not ready for ARM64 yet -# device vchiq -# device sound - -# Pseudo devices. -device bpf -device loop # Network loopback -device random # Entropy device -device ether # Ethernet support -device vlan # 802.1Q VLAN support -device tun # Packet tunnel. -device md # Memory "disks" -device gif # IPv6 and IPv4 tunneling -device firmware # firmware assist module -device psci # Support for ARM PSCI - -options FDT - -# The crypto framework is required by IPSEC -device crypto # Required by IPSEC diff --git a/sys/arm64/include/pcb.h b/sys/arm64/include/pcb.h index e76183409ae0..c1d1420ed190 100644 --- a/sys/arm64/include/pcb.h +++ b/sys/arm64/include/pcb.h @@ -54,6 +54,9 @@ struct pcb { struct vfpstate *pcb_fpusaved; int pcb_fpflags; #define PCB_FP_STARTED 0x01 +#define PCB_FP_KERN 0x02 +/* The bits passed to userspace in get_fpcontext */ +#define PCB_FP_USERMASK (PCB_FP_STARTED) u_int pcb_vfpcpu; /* Last cpu this thread ran VFP code */ /* diff --git a/sys/arm64/include/vfp.h b/sys/arm64/include/vfp.h index e22640862f33..99de6eef6c5b 100644 --- a/sys/arm64/include/vfp.h +++ b/sys/arm64/include/vfp.h @@ -45,6 +45,23 @@ void vfp_init(void); void vfp_discard(struct thread *); void vfp_restore_state(void); void vfp_save_state(struct thread *, struct pcb *); + +struct fpu_kern_ctx; + +/* + * Flags for fpu_kern_alloc_ctx(), fpu_kern_enter() and fpu_kern_thread(). + */ +#define FPU_KERN_NORMAL 0x0000 +#define FPU_KERN_NOWAIT 0x0001 +#define FPU_KERN_KTHR 0x0002 + +struct fpu_kern_ctx *fpu_kern_alloc_ctx(u_int); +void fpu_kern_free_ctx(struct fpu_kern_ctx *); +int fpu_kern_enter(struct thread *, struct fpu_kern_ctx *, u_int); +int fpu_kern_leave(struct thread *, struct fpu_kern_ctx *); +int fpu_kern_thread(u_int); +int is_fpu_kern_thread(u_int); + #endif #endif diff --git a/sys/boot/fdt/dts/arm/annapurna-alpine.dts b/sys/boot/fdt/dts/arm/annapurna-alpine.dts index 2172ed3a45a1..0bca6059501f 100644 --- a/sys/boot/fdt/dts/arm/annapurna-alpine.dts +++ b/sys/boot/fdt/dts/arm/annapurna-alpine.dts @@ -159,6 +159,12 @@ interrupt-parent = <&MPIC>; }; + /* SerDes */ + serdes { + compatible = "annapurna-labs,al-serdes"; + reg = <0x28c0000 0x1000>; + }; + serial0: serial@2883000 { compatible = "ns16550"; reg = <0x2883000 0x20>; @@ -170,6 +176,16 @@ }; }; + /* MSIX Configuration */ + msix: msix { + compatible = "annapurna-labs,al-msix"; + #address-cells = <2>; + #size-cells = <1>; + reg = <0xfbe00000 0x100000>; + interrupts = <0 96 1 0 159 1>; + interrupt-parent = <&MPIC>; + }; + pcie-internal { compatible = "annapurna-labs,al-internal-pcie"; device_type = "pci"; @@ -182,6 +198,7 @@ <0x3800 0 0 1 &MPIC 0 36 4>, <0x4000 0 0 1 &MPIC 0 43 4>, // SATA 0 (PCIe expander) <0x4800 0 0 1 &MPIC 0 44 1>; // SATA 1 (onboard) + msi-parent = <&msix>; // ranges: // - ECAM - non prefetchable config space diff --git a/sys/boot/kshim/bsd_kernel.c b/sys/boot/kshim/bsd_kernel.c index 36a6d820aa41..c94b755e9eaf 100644 --- a/sys/boot/kshim/bsd_kernel.c +++ b/sys/boot/kshim/bsd_kernel.c @@ -817,8 +817,12 @@ device_delete_child(device_t dev, device_t child) int error = 0; device_t grandchild; - /* remove children first */ + /* detach parent before deleting children, if any */ + error = device_detach(child); + if (error) + goto done; + /* remove children second */ while ((grandchild = TAILQ_FIRST(&child->dev_children))) { error = device_delete_child(child, grandchild); if (error) { @@ -827,11 +831,6 @@ device_delete_child(device_t dev, device_t child) } } - error = device_detach(child); - - if (error) - goto done; - devclass_delete_device(child->dev_module, child); if (dev != NULL) { diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c index b59c6492f3c6..808dc72afcb3 100644 --- a/sys/cam/ata/ata_da.c +++ b/sys/cam/ata/ata_da.c @@ -926,8 +926,7 @@ adaclose(struct disk *dp) if (error != 0) xpt_print(periph->path, "Synchronize cache failed\n"); - else - softc->flags &= ~ADA_FLAG_DIRTY; + softc->flags &= ~ADA_FLAG_DIRTY; xpt_release_ccb(ccb); cam_periph_unhold(periph); } diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c index 8bf3ed0241a1..977ac8d6252b 100644 --- a/sys/cam/scsi/scsi_da.c +++ b/sys/cam/scsi/scsi_da.c @@ -1492,8 +1492,7 @@ daclose(struct disk *dp) error = cam_periph_runccb(ccb, daerror, /*cam_flags*/0, /*sense_flags*/SF_RETRY_UA | SF_QUIET_IR, softc->disk->d_devstat); - if (error == 0) - softc->flags &= ~DA_FLAG_DIRTY; + softc->flags &= ~DA_FLAG_DIRTY; xpt_release_ccb(ccb); } diff --git a/sys/cam/scsi/scsi_pass.c b/sys/cam/scsi/scsi_pass.c index d7fa73b9fc69..68412b4a1157 100644 --- a/sys/cam/scsi/scsi_pass.c +++ b/sys/cam/scsi/scsi_pass.c @@ -1876,6 +1876,18 @@ passdoioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread break; } + if (ccb->ccb_h.flags & CAM_CDB_POINTER) { + if (ccb->csio.cdb_len > IOCDBLEN) { + error = EINVAL; + break; + } + error = copyin(ccb->csio.cdb_io.cdb_ptr, + ccb->csio.cdb_io.cdb_bytes, ccb->csio.cdb_len); + if (error) + break; + ccb->ccb_h.flags &= ~CAM_CDB_POINTER; + } + /* * Some CCB types, like scan bus and scan lun can only go * through the transport layer device. @@ -2143,6 +2155,7 @@ passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) { struct pass_softc *softc; struct cam_periph_map_info mapinfo; + uint8_t *cmd; xpt_opcode fc; int error; @@ -2154,6 +2167,14 @@ passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) */ xpt_merge_ccb(ccb, inccb); + if (ccb->ccb_h.flags & CAM_CDB_POINTER) { + cmd = __builtin_alloca(ccb->csio.cdb_len); + error = copyin(ccb->csio.cdb_io.cdb_ptr, cmd, ccb->csio.cdb_len); + if (error) + return (error); + ccb->csio.cdb_io.cdb_ptr = cmd; + } + /* */ ccb->ccb_h.cbfcnp = passdone; diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c index 8cf274115b2f..dbff8bd66dbd 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zil.c @@ -924,6 +924,8 @@ uint64_t zil_block_buckets[] = { * Limit checking is disabled by setting zil_slog_limit to UINT64_MAX. */ uint64_t zil_slog_limit = 1024 * 1024; +SYSCTL_QUAD(_vfs_zfs, OID_AUTO, zil_slog_limit, CTLFLAG_RWTUN, + &zil_slog_limit, 0, "Maximal commit size to use SLOG"); #define USE_SLOG(zilog) (((zilog)->zl_logbias == ZFS_LOGBIAS_LATENCY) && \ (((zilog)->zl_cur_used < zil_slog_limit) || \ ((zilog)->zl_itx_list_sz < (zil_slog_limit << 1)))) @@ -1142,6 +1144,11 @@ zil_itx_create(uint64_t txtype, size_t lrsize) lrsize = P2ROUNDUP_TYPED(lrsize, sizeof (uint64_t), size_t); +#ifdef __FreeBSD__ + if (offsetof(itx_t, itx_lr) + lrsize > PAGE_SIZE) + itx = zio_buf_alloc(offsetof(itx_t, itx_lr) + lrsize); + else +#endif itx = kmem_alloc(offsetof(itx_t, itx_lr) + lrsize, KM_SLEEP); itx->itx_lr.lrc_txtype = txtype; itx->itx_lr.lrc_reclen = lrsize; @@ -1155,6 +1162,11 @@ zil_itx_create(uint64_t txtype, size_t lrsize) void zil_itx_destroy(itx_t *itx) { +#ifdef __FreeBSD__ + if (offsetof(itx_t, itx_lr) + itx->itx_lr.lrc_reclen > PAGE_SIZE) + zio_buf_free(itx, offsetof(itx_t, itx_lr) + itx->itx_lr.lrc_reclen); + else +#endif kmem_free(itx, offsetof(itx_t, itx_lr) + itx->itx_lr.lrc_reclen); } @@ -1174,8 +1186,7 @@ zil_itxg_clean(itxs_t *itxs) list = &itxs->i_sync_list; while ((itx = list_head(list)) != NULL) { list_remove(list, itx); - kmem_free(itx, offsetof(itx_t, itx_lr) + - itx->itx_lr.lrc_reclen); + zil_itx_destroy(itx); } cookie = NULL; @@ -1184,8 +1195,7 @@ zil_itxg_clean(itxs_t *itxs) list = &ian->ia_list; while ((itx = list_head(list)) != NULL) { list_remove(list, itx); - kmem_free(itx, offsetof(itx_t, itx_lr) + - itx->itx_lr.lrc_reclen); + zil_itx_destroy(itx); } list_destroy(list); kmem_free(ian, sizeof (itx_async_node_t)); @@ -1250,8 +1260,7 @@ zil_remove_async(zilog_t *zilog, uint64_t oid) } while ((itx = list_head(&clean_list)) != NULL) { list_remove(&clean_list, itx); - kmem_free(itx, offsetof(itx_t, itx_lr) + - itx->itx_lr.lrc_reclen); + zil_itx_destroy(itx); } list_destroy(&clean_list); } @@ -1501,8 +1510,7 @@ zil_commit_writer(zilog_t *zilog) if (txg > spa_last_synced_txg(spa) || txg > spa_freeze_txg(spa)) lwb = zil_lwb_commit(zilog, itx, lwb); list_remove(&zilog->zl_itx_commit_list, itx); - kmem_free(itx, offsetof(itx_t, itx_lr) - + itx->itx_lr.lrc_reclen); + zil_itx_destroy(itx); } DTRACE_PROBE1(zil__cw2, zilog_t *, zilog); diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c index f2015705fcfd..22d6b78f38fb 100644 --- a/sys/compat/ia32/ia32_sysvec.c +++ b/sys/compat/ia32/ia32_sysvec.c @@ -120,13 +120,11 @@ struct sysentvec ia32_freebsd_sysvec = { .sv_setregs = ia32_setregs, .sv_fixlimit = ia32_fixlimit, .sv_maxssiz = &ia32_maxssiz, - .sv_flags = SV_ABI_FREEBSD | SV_IA32 | SV_ILP32 | + .sv_flags = #ifdef __amd64__ - SV_SHP | SV_TIMEKEEP -#else - 0 + SV_SHP | SV_TIMEKEEP | #endif - , + SV_ABI_FREEBSD | SV_IA32 | SV_ILP32, .sv_set_syscall_retval = ia32_set_syscall_retval, .sv_fetch_syscall_args = ia32_fetch_syscall_args, .sv_syscallnames = freebsd32_syscallnames, diff --git a/sys/conf/Makefile.arm b/sys/conf/Makefile.arm index 009bce89f6ca..41f82c67085a 100644 --- a/sys/conf/Makefile.arm +++ b/sys/conf/Makefile.arm @@ -74,7 +74,7 @@ FILES_CPU_FUNC = \ $S/$M/$M/cpufunc_asm_pj4b.S $S/$M/$M/cpufunc_asm_armv6.S \ $S/$M/$M/cpufunc_asm_armv7.S -.if ${TARGET_ARCH} != "armv6" && defined(KERNPHYSADDR) +.if ${MACHINE_ARCH} != "armv6" && defined(KERNPHYSADDR) KERNEL_EXTRA=trampoline KERNEL_EXTRA_INSTALL=kernel.gz.tramp trampoline: ${KERNEL_KO}.tramp diff --git a/sys/conf/WITHOUT_SOURCELESS_UCODE b/sys/conf/WITHOUT_SOURCELESS_UCODE index 7747d3dfbe5b..277fba518db3 100644 --- a/sys/conf/WITHOUT_SOURCELESS_UCODE +++ b/sys/conf/WITHOUT_SOURCELESS_UCODE @@ -11,6 +11,7 @@ nodevice fxp nodevice ispfw nodevice mwlfw nodevice ralfw +nodevice rtwnfw nodevice runfw nodevice sf nodevice ti @@ -41,5 +42,3 @@ nodevice rum nodevice uath nodevice zyd nodevice kue -nodevice urtwn -nodevice urtwnfw diff --git a/sys/conf/files b/sys/conf/files index 8e2ce6bb671d..ef6ac4b6de5d 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -709,6 +709,45 @@ dev/aic7xxx/aic7xxx_93cx6.c optional ahc dev/aic7xxx/aic7xxx_osm.c optional ahc dev/aic7xxx/aic7xxx_pci.c optional ahc pci dev/aic7xxx/aic7xxx_reg_print.c optional ahc ahc_reg_pretty_print +dev/al_eth/al_eth.c optional al_eth \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +dev/al_eth/al_init_eth_lm.c optional al_eth \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +dev/al_eth/al_init_eth_kr.c optional al_eth \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_iofic.c optional al_iofic \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_serdes_25g.c optional al_serdes \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_serdes_hssp.c optional al_serdes \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_udma_config.c optional al_udma \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_udma_debug.c optional al_udma \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_udma_iofic.c optional al_udma \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_hal_udma_main.c optional al_udma \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/al_serdes.c optional al_serdes \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/eth/al_hal_eth_kr.c optional al_eth \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" +contrib/alpine-hal/eth/al_hal_eth_main.c optional al_eth \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" dev/alc/if_alc.c optional alc pci dev/ale/if_ale.c optional ale pci dev/alpm/alpm.c optional alpm pci @@ -2187,6 +2226,7 @@ dev/nand/nfc_if.m optional nand dev/ncr/ncr.c optional ncr pci dev/ncv/ncr53c500.c optional ncv dev/ncv/ncr53c500_pccard.c optional ncv pccard +dev/netmap/if_ptnet.c optional netmap inet dev/netmap/netmap.c optional netmap dev/netmap/netmap_freebsd.c optional netmap dev/netmap/netmap_generic.c optional netmap @@ -2195,6 +2235,7 @@ dev/netmap/netmap_mem2.c optional netmap dev/netmap/netmap_monitor.c optional netmap dev/netmap/netmap_offloadings.c optional netmap dev/netmap/netmap_pipe.c optional netmap +dev/netmap/netmap_pt.c optional netmap dev/netmap/netmap_vale.c optional netmap # compile-with "${NORMAL_C} -Wconversion -Wextra" dev/nfsmb/nfsmb.c optional nfsmb pci @@ -2488,7 +2529,147 @@ dev/rndtest/rndtest.c optional rndtest dev/rp/rp.c optional rp dev/rp/rp_isa.c optional rp isa dev/rp/rp_pci.c optional rp pci +# dev/rtwn/if_rtwn.c optional rtwn +dev/rtwn/if_rtwn_beacon.c optional rtwn +dev/rtwn/if_rtwn_calib.c optional rtwn +dev/rtwn/if_rtwn_cam.c optional rtwn +dev/rtwn/if_rtwn_efuse.c optional rtwn +dev/rtwn/if_rtwn_fw.c optional rtwn +dev/rtwn/if_rtwn_rx.c optional rtwn +dev/rtwn/if_rtwn_task.c optional rtwn +dev/rtwn/if_rtwn_tx.c optional rtwn +# +dev/rtwn/pci/rtwn_pci_attach.c optional rtwn_pci pci +dev/rtwn/pci/rtwn_pci_reg.c optional rtwn_pci pci +dev/rtwn/pci/rtwn_pci_rx.c optional rtwn_pci pci +dev/rtwn/pci/rtwn_pci_tx.c optional rtwn_pci pci +# +dev/rtwn/usb/rtwn_usb_attach.c optional rtwn_usb +dev/rtwn/usb/rtwn_usb_ep.c optional rtwn_usb +dev/rtwn/usb/rtwn_usb_reg.c optional rtwn_usb +dev/rtwn/usb/rtwn_usb_rx.c optional rtwn_usb +dev/rtwn/usb/rtwn_usb_tx.c optional rtwn_usb +# RTL8188E +dev/rtwn/rtl8188e/r88e_beacon.c optional rtwn +dev/rtwn/rtl8188e/r88e_calib.c optional rtwn +dev/rtwn/rtl8188e/r88e_chan.c optional rtwn +dev/rtwn/rtl8188e/r88e_fw.c optional rtwn +dev/rtwn/rtl8188e/r88e_init.c optional rtwn +dev/rtwn/rtl8188e/r88e_led.c optional rtwn +dev/rtwn/rtl8188e/r88e_tx.c optional rtwn +dev/rtwn/rtl8188e/r88e_rf.c optional rtwn +dev/rtwn/rtl8188e/r88e_rom.c optional rtwn +dev/rtwn/rtl8188e/r88e_rx.c optional rtwn +dev/rtwn/rtl8188e/usb/r88eu_attach.c optional rtwn_usb +dev/rtwn/rtl8188e/usb/r88eu_init.c optional rtwn_usb +dev/rtwn/rtl8188e/usb/r88eu_rx.c optional rtwn_usb +# RTL8192C +dev/rtwn/rtl8192c/r92c_attach.c optional rtwn +dev/rtwn/rtl8192c/r92c_beacon.c optional rtwn +dev/rtwn/rtl8192c/r92c_calib.c optional rtwn +dev/rtwn/rtl8192c/r92c_chan.c optional rtwn +dev/rtwn/rtl8192c/r92c_fw.c optional rtwn +dev/rtwn/rtl8192c/r92c_init.c optional rtwn +dev/rtwn/rtl8192c/r92c_rf.c optional rtwn +dev/rtwn/rtl8192c/r92c_rom.c optional rtwn +dev/rtwn/rtl8192c/r92c_rx.c optional rtwn +dev/rtwn/rtl8192c/r92c_tx.c optional rtwn +dev/rtwn/rtl8192c/pci/r92ce_attach.c optional rtwn_pci pci +dev/rtwn/rtl8192c/pci/r92ce_calib.c optional rtwn_pci pci +dev/rtwn/rtl8192c/pci/r92ce_fw.c optional rtwn_pci pci +dev/rtwn/rtl8192c/pci/r92ce_init.c optional rtwn_pci pci +dev/rtwn/rtl8192c/pci/r92ce_led.c optional rtwn_pci pci +dev/rtwn/rtl8192c/pci/r92ce_rx.c optional rtwn_pci pci +dev/rtwn/rtl8192c/pci/r92ce_tx.c optional rtwn_pci pci +dev/rtwn/rtl8192c/usb/r92cu_attach.c optional rtwn_usb +dev/rtwn/rtl8192c/usb/r92cu_init.c optional rtwn_usb +dev/rtwn/rtl8192c/usb/r92cu_led.c optional rtwn_usb +dev/rtwn/rtl8192c/usb/r92cu_rx.c optional rtwn_usb +dev/rtwn/rtl8192c/usb/r92cu_tx.c optional rtwn_usb +# RTL8812A +dev/rtwn/rtl8812a/r12a_beacon.c optional rtwn +dev/rtwn/rtl8812a/r12a_calib.c optional rtwn +dev/rtwn/rtl8812a/r12a_caps.c optional rtwn +dev/rtwn/rtl8812a/r12a_chan.c optional rtwn +dev/rtwn/rtl8812a/r12a_fw.c optional rtwn +dev/rtwn/rtl8812a/r12a_init.c optional rtwn +dev/rtwn/rtl8812a/r12a_led.c optional rtwn +dev/rtwn/rtl8812a/r12a_rf.c optional rtwn +dev/rtwn/rtl8812a/r12a_rom.c optional rtwn +dev/rtwn/rtl8812a/r12a_rx.c optional rtwn +dev/rtwn/rtl8812a/r12a_tx.c optional rtwn +dev/rtwn/rtl8812a/usb/r12au_attach.c optional rtwn_usb +dev/rtwn/rtl8812a/usb/r12au_init.c optional rtwn_usb +dev/rtwn/rtl8812a/usb/r12au_rx.c optional rtwn_usb +dev/rtwn/rtl8812a/usb/r12au_tx.c optional rtwn_usb +# RTL8821A +dev/rtwn/rtl8821a/r21a_beacon.c optional rtwn +dev/rtwn/rtl8821a/r21a_calib.c optional rtwn +dev/rtwn/rtl8821a/r21a_chan.c optional rtwn +dev/rtwn/rtl8821a/r21a_fw.c optional rtwn +dev/rtwn/rtl8821a/r21a_init.c optional rtwn +dev/rtwn/rtl8821a/r21a_led.c optional rtwn +dev/rtwn/rtl8821a/r21a_rom.c optional rtwn +dev/rtwn/rtl8821a/r21a_rx.c optional rtwn +dev/rtwn/rtl8821a/usb/r21au_attach.c optional rtwn_usb +dev/rtwn/rtl8821a/usb/r21au_init.c optional rtwn_usb +rtwn-rtl8188eufw.c optional rtwn-rtl8188eufw | rtwnfw \ + compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8188eufw.fw:rtwn-rtl8188eufw:111 -mrtwn-rtl8188eufw -c${.TARGET}" \ + no-implicit-rule before-depend local \ + clean "rtwn-rtl8188eufw.c" +rtwn-rtl8188eufw.fwo optional rtwn-rtl8188eufw | rtwnfw \ + dependency "rtwn-rtl8188eufw.fw" \ + compile-with "${NORMAL_FWO}" \ + no-implicit-rule \ + clean "rtwn-rtl8188eufw.fwo" +rtwn-rtl8188eufw.fw optional rtwn-rtl8188eufw | rtwnfw \ + dependency "$S/contrib/dev/rtwn/rtwn-rtl8188eufw.fw.uu" \ + compile-with "${NORMAL_FW}" \ + no-obj no-implicit-rule \ + clean "rtwn-rtl8188eufw.fw" +rtwn-rtl8192cfwE.c optional rtwn-rtl8192cfwE | rtwnfw \ + compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8192cfwE.fw:rtwn-rtl8192cfwE:111 -mrtwn-rtl8192cfwE -c${.TARGET}" \ + no-implicit-rule before-depend local \ + clean "rtwn-rtl8192cfwE.c" +rtwn-rtl8192cfwE.fwo optional rtwn-rtl8192cfwE | rtwnfw \ + dependency "rtwn-rtl8192cfwE.fw" \ + compile-with "${NORMAL_FWO}" \ + no-implicit-rule \ + clean "rtwn-rtl8192cfwE.fwo" +rtwn-rtl8192cfwE.fw optional rtwn-rtl8192cfwE | rtwnfw \ + dependency "$S/contrib/dev/rtwn/rtwn-rtl8192cfwE.fw.uu" \ + compile-with "${NORMAL_FW}" \ + no-obj no-implicit-rule \ + clean "rtwn-rtl8192cfwE.fw" +rtwn-rtl8192cfwE_B.c optional rtwn-rtl8192cfwE_B | rtwnfw \ + compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8192cfwE_B.fw:rtwn-rtl8192cfwE_B:111 -mrtwn-rtl8192cfwE_B -c${.TARGET}" \ + no-implicit-rule before-depend local \ + clean "rtwn-rtl8192cfwE_B.c" +rtwn-rtl8192cfwE_B.fwo optional rtwn-rtl8192cfwE_B | rtwnfw \ + dependency "rtwn-rtl8192cfwE_B.fw" \ + compile-with "${NORMAL_FWO}" \ + no-implicit-rule \ + clean "rtwn-rtl8192cfwE_B.fwo" +rtwn-rtl8192cfwE_B.fw optional rtwn-rtl8192cfwE_B | rtwnfw \ + dependency "$S/contrib/dev/rtwn/rtwn-rtl8192cfwE_B.fw.uu" \ + compile-with "${NORMAL_FW}" \ + no-obj no-implicit-rule \ + clean "rtwn-rtl8192cfwE_B.fw" +rtwn-rtl8192cfwT.c optional rtwn-rtl8192cfwT | rtwnfw \ + compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8192cfwT.fw:rtwn-rtl8192cfwT:111 -mrtwn-rtl8192cfwT -c${.TARGET}" \ + no-implicit-rule before-depend local \ + clean "rtwn-rtl8192cfwT.c" +rtwn-rtl8192cfwT.fwo optional rtwn-rtl8192cfwT | rtwnfw \ + dependency "rtwn-rtl8192cfwT.fw" \ + compile-with "${NORMAL_FWO}" \ + no-implicit-rule \ + clean "rtwn-rtl8192cfwT.fwo" +rtwn-rtl8192cfwT.fw optional rtwn-rtl8192cfwT | rtwnfw \ + dependency "$S/contrib/dev/rtwn/rtwn-rtl8192cfwT.fw.uu" \ + compile-with "${NORMAL_FW}" \ + no-obj no-implicit-rule \ + clean "rtwn-rtl8192cfwT.fw" rtwn-rtl8192cfwU.c optional rtwn-rtl8192cfwU | rtwnfw \ compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8192cfwU.fw:rtwn-rtl8192cfwU:111 -mrtwn-rtl8192cfwU -c${.TARGET}" \ no-implicit-rule before-depend local \ @@ -2503,20 +2684,34 @@ rtwn-rtl8192cfwU.fw optional rtwn-rtl8192cfwU | rtwnfw \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rtwn-rtl8192cfwU.fw" -rtwn-rtl8192cfwU_B.c optional rtwn-rtl8192cfwU_B | rtwnfw \ - compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8192cfwU_B.fw:rtwn-rtl8192cfwU_B:111 -mrtwn-rtl8192cfwU_B -c${.TARGET}" \ +rtwn-rtl8812aufw.c optional rtwn-rtl8812aufw | rtwnfw \ + compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8812aufw.fw:rtwn-rtl8812aufw:111 -mrtwn-rtl8812aufw -c${.TARGET}" \ no-implicit-rule before-depend local \ - clean "rtwn-rtl8192cfwU_B.c" -rtwn-rtl8192cfwU_B.fwo optional rtwn-rtl8192cfwU_B | rtwnfw \ - dependency "rtwn-rtl8192cfwU_B.fw" \ + clean "rtwn-rtl8812aufw.c" +rtwn-rtl8812aufw.fwo optional rtwn-rtl8812aufw | rtwnfw \ + dependency "rtwn-rtl8812aufw.fw" \ compile-with "${NORMAL_FWO}" \ no-implicit-rule \ - clean "rtwn-rtl8192cfwU_B.fwo" -rtwn-rtl8192cfwU_B.fw optional rtwn-rtl8192cfwU_B | rtwnfw \ - dependency "$S/contrib/dev/rtwn/rtwn-rtl8192cfwU_B.fw.uu" \ + clean "rtwn-rtl8812aufw.fwo" +rtwn-rtl8812aufw.fw optional rtwn-rtl8812aufw | rtwnfw \ + dependency "$S/contrib/dev/rtwn/rtwn-rtl8812aufw.fw.uu" \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ - clean "rtwn-rtl8192cfwU_B.fw" + clean "rtwn-rtl8812aufw.fw" +rtwn-rtl8821aufw.c optional rtwn-rtl8821aufw | rtwnfw \ + compile-with "${AWK} -f $S/tools/fw_stub.awk rtwn-rtl8821aufw.fw:rtwn-rtl8821aufw:111 -mrtwn-rtl8821aufw -c${.TARGET}" \ + no-implicit-rule before-depend local \ + clean "rtwn-rtl8821aufw.c" +rtwn-rtl8821aufw.fwo optional rtwn-rtl8821aufw | rtwnfw \ + dependency "rtwn-rtl8821aufw.fw" \ + compile-with "${NORMAL_FWO}" \ + no-implicit-rule \ + clean "rtwn-rtl8821aufw.fwo" +rtwn-rtl8821aufw.fw optional rtwn-rtl8821aufw | rtwnfw \ + dependency "$S/contrib/dev/rtwn/rtwn-rtl8821aufw.fw.uu" \ + compile-with "${NORMAL_FW}" \ + no-obj no-implicit-rule \ + clean "rtwn-rtl8821aufw.fw" dev/safe/safe.c optional safe dev/scc/scc_if.m optional scc dev/scc/scc_bfe_ebus.c optional scc ebus diff --git a/sys/conf/files.arm b/sys/conf/files.arm index 9e50cf938e8d..c4c0f0aa4778 100644 --- a/sys/conf/files.arm +++ b/sys/conf/files.arm @@ -14,6 +14,10 @@ cloudabi32_vdso_blob.o optional compat_cloudabi32 \ arm/annapurna/alpine/alpine_ccu.c optional al_ccu fdt arm/annapurna/alpine/alpine_nb_service.c optional al_nb_service fdt arm/annapurna/alpine/alpine_pci.c optional al_pci fdt +arm/annapurna/alpine/alpine_pci_msix.c optional al_pci fdt +arm/annapurna/alpine/alpine_serdes.c optional al_serdes fdt \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" arm/arm/autoconf.c standard arm/arm/bcopy_page.S standard arm/arm/bcopyinout.S standard diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index 1aa1ce1546e4..2feac5041985 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -41,13 +41,17 @@ arm/allwinner/if_awg.c optional awg arm/annapurna/alpine/alpine_ccu.c optional al_ccu fdt arm/annapurna/alpine/alpine_nb_service.c optional al_nb_service fdt arm/annapurna/alpine/alpine_pci.c optional al_pci fdt +arm/annapurna/alpine/alpine_pci_msix.c optional al_pci fdt +arm/annapurna/alpine/alpine_serdes.c optional al_serdes fdt \ + no-depend \ + compile-with "${CC} -c -o ${.TARGET} ${CFLAGS} -I$S/contrib/alpine-hal -I$S/contrib/alpine-hal/eth ${PROF} ${.IMPSRC}" arm/arm/generic_timer.c standard arm/arm/gic.c standard arm/arm/gic_fdt.c optional fdt arm/arm/pmu.c standard arm/broadcom/bcm2835/bcm2835_audio.c optional sound vchiq \ compile-with "${NORMAL_C} -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 -I$S/contrib/vchiq" -arm/broadcom/bcm2835/bcm2835_bsc.c optional bcm2835_bsc +arm/broadcom/bcm2835/bcm2835_bsc.c optional bcm2835_bsc soc_brcm_bcm2837 arm/broadcom/bcm2835/bcm2835_common.c optional fdt soc_brcm_bcm2837 arm/broadcom/bcm2835/bcm2835_cpufreq.c optional soc_brcm_bcm2837 arm/broadcom/bcm2835/bcm2835_dma.c optional soc_brcm_bcm2837 diff --git a/sys/conf/makeLINT.mk b/sys/conf/makeLINT.mk index 3b418edcbd98..e2c7e5e00aff 100644 --- a/sys/conf/makeLINT.mk +++ b/sys/conf/makeLINT.mk @@ -21,6 +21,7 @@ LINT: ${NOTES} ../../conf/makeLINT.sed echo 'makeoptions MKMODULESENV+="WITHOUT_INET_SUPPORT="' >> ${.TARGET}-NOINET echo "nooptions INET" >> ${.TARGET}-NOINET echo "nodevice gre" >> ${.TARGET}-NOINET + echo "nodevice netmap" >> ${.TARGET}-NOINET echo "include ${.TARGET}" > ${.TARGET}-NOINET6 echo "ident ${.TARGET}-NOINET6" >> ${.TARGET}-NOINET6 echo 'makeoptions MKMODULESENV+="WITHOUT_INET6_SUPPORT="' >> ${.TARGET}-NOINET6 @@ -45,6 +46,7 @@ LINT: ${NOTES} ../../conf/makeLINT.sed echo "nodevice sk" >> ${.TARGET}-NOIP echo "nodevice txp" >> ${.TARGET}-NOIP echo "nodevice vxge" >> ${.TARGET}-NOIP + echo "nodevice netmap" >> ${.TARGET}-NOIP .endif .if ${TARGET} == "mips" echo "machine ${TARGET} ${TARGET_ARCH}" >> ${.TARGET} diff --git a/sys/conf/options b/sys/conf/options index 39e26a333d3b..9004832b1b36 100644 --- a/sys/conf/options +++ b/sys/conf/options @@ -678,8 +678,9 @@ UPLCOM_INTR_INTERVAL opt_uplcom.h UVSCOM_DEFAULT_OPKTSIZE opt_uvscom.h UVSCOM_INTR_INTERVAL opt_uvscom.h -# options for the Realtek RTL8188*U/RTL8192CU driver (urtwn) -URTWN_WITHOUT_UCODE opt_urtwn.h +# options for the Realtek rtwn driver +RTWN_DEBUG opt_rtwn.h +RTWN_WITHOUT_UCODE opt_rtwn.h # Embedded system options INIT_PATH diff --git a/sys/contrib/dev/rtwn/LICENSE b/sys/contrib/dev/rtwn/LICENSE index d70921f49379..e80b78949d0b 100644 --- a/sys/contrib/dev/rtwn/LICENSE +++ b/sys/contrib/dev/rtwn/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2010, Realtek Semiconductor Corporation +Copyright (c) 2010-2011, Realtek Semiconductor Corporation All rights reserved. Redistribution. Redistribution and use in binary form, without diff --git a/sys/contrib/dev/urtwn/urtwn-rtl8188eufw.fw.uu b/sys/contrib/dev/rtwn/rtwn-rtl8188eufw.fw.uu similarity index 99% rename from sys/contrib/dev/urtwn/urtwn-rtl8188eufw.fw.uu rename to sys/contrib/dev/rtwn/rtwn-rtl8188eufw.fw.uu index 1039230f8cd6..4945886e295a 100644 --- a/sys/contrib/dev/urtwn/urtwn-rtl8188eufw.fw.uu +++ b/sys/contrib/dev/rtwn/rtwn-rtl8188eufw.fw.uu @@ -1,4 +1,4 @@ -begin 644 urtwn-rtl8188eufw.fw.uu +begin 644 rtwn-rtl8188eufw.fw.uu MX8@0``L``0`!(1$G,#8``"T'```````````````````"14X````````````` M````````P6\````````````````````````````````````````````````` M````````````H>8````````"5O<````````````````````````````````` diff --git a/sys/contrib/dev/rtwn/rtwn-rtl8192cfwE.fw.uu b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwE.fw.uu new file mode 100644 index 000000000000..8e49f4a2b926 --- /dev/null +++ b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwE.fw.uu @@ -0,0 +1,333 @@ +begin 444 rtwn-rtl8192cfwE.fw.uu +MP8@"`$@````%$!!3PCD!`(%C`0`````````````````"0[H````````````` +M`````````E!$```````````````````````````````````````````````` +M`````````````E;@```````"2VH```4$`P(``P8%!`,`!`8%!`(`!`@'!@0` +M!@H)"`8`"`H)"`0`"`H)"`(`"`H)"```"!(1$`@`$!H9&!``&"(A(!@`("(A +M(!``("(A(`@`("(A'`@`("(A%`@`("(@&`@`(#$P(!``,#$P&```,#$O$!`` +M,#$L$!``,#$H$```,#$@$```,#$0$```,`0$!`4$!`0%!04&!@0$!`4%!08& +M!`0%!04%!@8$!`4%!04&!PH+#1`$!04&!@D,$0@("0D*#!`1!`0$!00$!0<' +M!P@*!`0$!`8*"PT%!0<'"`L-#P0$!`4'!PD)#`X0$@0$!04&"A$3"0D)"0P. +M$1,````````````D)BH8&AT?(2`"@`,@!0`&0`>`",`$L`4`!X`+0`^@$L`9`!]```@`" +M``0`"``,`!(`&``D`#``2`!@`&P`*``\`%``9`"@`,@`\`$8`&0`H`#P`6@! +M]`)8`R`#Z`("`@("`@,#!`0%!P0$!PH*#`P2!0<'"`L2)#P!`0$!`0(#!`4& +M!P@!`@,$!08'"`4&!P@)"@L,(!X<&!`8````````````````NP$,Y8(I]8+E +M@SKU@^`B4`;I)8+XYB*[_@;I)8+XXB+E@BGU@N6#.O6#Y),BNP$&B8**@_`B +M4`+W(KO^`?,B^+L!#>6"*?6"Y8,Z]8/H\")0!NDE@LCV(KO^!>DE@LCR(L7P +M^*/@*/#%\/CE@A6"<`(5@^`X\"*[`0J)@HJ#X/7PH^`B4`:'\`GG&2*[_@?C +M]?`)XQDBB8**@^23]?!T`9,BNP$0Y8(I]8+E@SKU@^#U\*/@(E`)Z26"^(;P +M".8BN_X*Z26"^.+U\`CB(N6#*O6#Z9/U\*/IDR*[`0J)@HJ#\.7PH_`B4`;W +M":?P&2*[_@;SY?`)\QDB^+L!$>6"*?6"Y8,Z]8/H\.7PH_`B4`GI)8+(]@BF +M\"*[_@GI)8+(\N7P"/(B[TO_[DK^[4G][$C\(N#\H^#]H^#^H^#_(J0E@O6" +MY?`U@_6#(N#[H^#ZH^#Y(OC@^Z.CX/DE\/#E@A6"<`(5@^#Z./`BZ_"CZO"C +MZ?`BT(/0@OCDDW`2=`&3<`VCHY/X=`&3]8*(@^1S=`*3:&#OHZ.C@-\"0_@" +M2"_DDZ/XY).C0`/V@`'R"-_T@"GDDZ/X5`1^`9-@O*/_5#\PY0E4'_[DDZ-@`0[/5,`EX&"H +M0+CDDZ/ZY).C^.23H\C%@LC*Q8/*\*/(Q8+(RL6#RM_IWN>`OD&7?P!!EZ$` +M09=K@$&7HP``CX*.@Z.CH^3P(N3U(W]@?@&`[=,0KP'#P-"0EUUQBY"777%K +MD``!4<+ZY?`D`/_D.OZ0EUUQ:Y```>Z/\'$9$B1B_V`HM2,4D)==<6N0``%1 +MPF4E<`3E)&7P8!^0EUUQ:Y```5'"_Z[PL5.`#I"777%K$B1B92-@`I%8T-"2 +MKR+T_Y``0^!?\-,0KP'#P-!_$-_^T-"2KR*0`=,0KP'#P-"+8(IAB6*0EXAQBZMCJF2I99"7BW&+ +MKV859N]@&Y"7B^1U\`%Q=!(D8O^0EXCD=?`!<73O44V`WJM@JF&I8M#0DJ\B +MD)=@[O"C[_!U(P&.)/4EY/U_"[&6Y/U_`K&6$FU;Y/^1YN3U)Y`!R>4G\)"7 +M8.#\H^#][/N-1.3U17T!?V!^`0(P8M,0KP'#P-"0EV/M\)"78N_PTY0'4$ZC +MX'`:D)=BX/]T`:@'"(`"PS/8_/3_D`!'X%_P@!>0EV+@_W0!J`<(@`+#,]C\ +M_Y``1^!/\)'6D)=BX/]T`:@'"(`"PS/8_/3_D`!&@%F0EV+@)/CPH^!P'9"7 +M8N#_=`&H!PB``L,SV/S$5/#T_Y``0^!?\(`:D)=BX/]T`:@'"(`"PS/8_,14 +M\/^0`$/@3_"1UI"78N#_=`&H!PB``L,SV/ST_Y``0^!?\)'6T-"2KR+@_WT! +MD)>4[_"C[?#DH_"C\.5J8`7D_Q).>9"7E.`PX`F0EY;D\*-T@/"0!!W@8!V0 +M!2+@D)>8\.#_5)!@[)`!R'3\\.]4;Y`%(O"`W9"7E.#_PQ.0_1#PD`0E[_"0 +MEY7@8!^CH^#_)`_U@N0T_/6#X$2`\'00+_6"Y#3\]8/@1(#PD)>6H^#__20( +M]8+D-/SU@^3P=`DM]8+D-/SU@^!4\/!T(2_U@N0T_/6#X%3W\)"7EN#^H^#_ +M(O"0`$7@5/[]?T73$*\!P\#0CX)U@P#M\)'6T-"2KR+O%&`P%&!E)`)@`N': +MD)!$$/U_18!OY)"7./"0 +MES1Q4Y"`EA(E"'^`?@@2*PB0`$7@1._]?T7Q()``1>!4[_U_1?$@D`!&X$00 +M_7]&@#>0ESAT`?"0ESYQ4Y"`EA(E"'^`?@@2*PB0`$7@1"#]?T7Q()``1>!$ +M$/U_1?$@D`!&X$00_7]&\2`BD`!)X)"7I/#@5`_P1/#]?TGQ()"7I.!$L/U_ +M2>$@=2@SY/4I=2H"]2N0`3#E*/"CY2GPH^4J\*/E*_`B=3`?=3$!Y/4RD`$X +MY3#PH^4Q\*/E,O`BY)"73_"C\'6.`A)LK9```N!4X)"7AF`%=`'P@`-T`O"0 +M`//@,.,(D)>'=`'P@`7DD)>'\)"7A^"T`1.0`/+@,.<,D)=]=/WPHW0S\(`* +MD)=]=/WPHW0O\.3U5Q)JZQ)O\A)?K!(N`1)M5Q)'^9``\^`PX@V0!4%T$/"0 +M!5KPH^3PD`%D=*#P=43_Y/5%^WT!?U!^`1(P8A$7$D4"$G=(D)=1Y=GP$E`5 +MPJ^0`(#@1$#P$D36=>@#0ZB%TJ^0ET_@9`'P)"^0`<3P=$BC\.57,.0*PJ]3 +M5^_2KQ)7@.57,.86PJ]35[_2KQ)A9)"7/.#_8`.T`0(Q8)"7/.!P`Q)WIC$S +M@+B0!C3@8"8435_^7X!$FSUOP$)D`8UX%0/\(`%@``";)[DD`8T +M\"*0ES/@PY044`7@!/!!&)"7,^!D%&`"01B0ET+@<"60ET7@0!/W@5/[PD)="X)`$1/"0ET/@D`1%\)"71."0 +M!$;PH^3PD)=%X)`$2/"0ET;@D`1)\)"71^"0!$KPH^3PD)#^TY]0"Y"72^##GM.4`4`0D)"0ETGPD`5BX)"72O"0!6/@D)=+\,-T_Y_^D)=)X-.>0![@+_"CX+3_#^3P +MH^"T_P/D\"*0ETN``Y"72N`$\"*0ETG@+_`BD)#_46*0ETQT`1)'%H!`D)=,X&0!<#B0ESW@_U%BY)"73/"0`$7@1`']?T42 +M1R"0ES+@8!60ES020U.0@)82)0A_@'X($BL(@`60!2+D\)`%A^!D@/"0ETC@ +MD`6$\)"72>"0!87PD)=*X)`%AO"0ETO@D`6'\"+`X,#PP(/`@L#0==``P`#` +M`<`"P`/`!,`%P`;`!Y`!Q'1J\'1+H_!3D=^0`3S@53#U-*/@53'U-:/@53+U +M-J/@53/U-^4T,.`&D`$\=`'PY30PX0B0`3QT`O#QJ^4T,.(RD`$\=`3PD`:2 +MX##@'G5$%'5%`.3[_7]8?@$2,&*0`5MT!?"0!I)T`?"`!Y"7=N3PD8KE-##C +M,I`!/'0(\)`&DN`PX1YU1!1U10#D^_U_7'X!$C!BD`%?=`7PD`:2=`+P@`>0 +MEW7D\)&*Y30PY`F0`3QT$/`2;7?E-##E")`!/'0@\%&TY34PX!"0`3UT`?"0 +M`(/@D)=Y\)&*=&H$D`'$\'1+H_#0!]`&T`70!-`#T`+0`=``T-#0@M"#T/#0 +MX#*0EWG@_WT!@`1]`7\,CV>-:.5G5`__D)=WX%0/;V!QY6]@*[%.D)=WX%0/_[\$#>5G(.(($E8Q[V`4T920EW?@5`__ +MOP(($F`)[V`"T>!4O_`BD`8$X$1`\.5IM`$$?P'Q2)"7=^!4\/#@1`3P +M(N]D`7`N?7U_`A(Q+'T"?P,2,2R0`5?D\)`!/'0"\)&3Y/_1>9`&!.!4?_"0 +M!@K@5/CP(I`!-G1]\*-T`O!]??\2,9U]`G\#$C&=D`8$X$2`\)`&"N!$!_"0 +MEW+@H^"0!5CPY6DPX!J0EV_@%&`O)`-P0'\!@#JK$:H2J1.0 +M``(20B#]Y/_14X`GJQ&J$JD3D``"$D(@_7\!T5,?@!.K$:H2J1.0``(20B#] +M?P+14^3_L6HB[R3^8`L$V0EWAP!70%\(`"[?"0EWC@D)=M +M\"+O8`N0EX?@M`$0Y/^`"9"7A^"T`05_`1)O^R*0`3=T`O"0!2)T__`2;E_O +M<`:0`BX&`%D`4BY/"0EW?@ +M5/#PX$0$\"*0!@3@5+_P[V`)Y6FT`03D__%(D)=WX%3P\.!$#/`B$E/\OP$: +MD)=VX'`4D)=UX'`.D)=YX%0/TY0$4`-_`2)_`"*/:Y"7@A)&7>5K8!!T(2_U +M@N0T_/6#X$00\(`.="$O]8+D-/SU@^!4[_"0!!]T`?`B?0)_`Q(Q+.5J%"3] +M4`*`(9"7>N!@!GT!?PR`#Y"7=^!4#\.4!%`&?0%_!)&7Y/_1>2*0EWO@8`[D +M\*/@5/WPX%0'<">`(Y"7;N`$\)"7?.!4[_"0EV[@TY0!0`WE:;0!"J/@<`;@ +M!/`BD8HBD`$PY/"C\*/PH_"0`3CPH_"C\*/P_7]0$D<@Y/U_41)'(.3]?U(2 +M1R#D_7]3`D<@D`$\=/_PH_"C\)`!-/"C\*/PH_#]?U021R!]_W]5$D<@??]_ +M5A)'('W_?U<"1R#`X,#PP(/`@L#0==``P`#``<`"P`/`!,`%P`;`!Y`!Q'1$ +M\'10H_"0`33@52CU+)`!-N!5*O4NH^!5*_4OY2P@X`(AVY`!-'0!\(713872 +M3H733X744(7548764H774X795.545$##$__E4U0@;W`"(9+E5##E`B&2Y5)4 +M'_4(Y4U4/_4)Y5%4'__E""7@)./U@N0TE/6#Y(_P$D*!Y5-4'__E""7@),#U +M@N0TD?6#Y(_P$D*!Y0G3E`1``W4)!'7P"N4(D)``$D-?=?`"Y0D20U_@_J/@ +M_^535!\O_^0^_G7P"N4(D)``$D-?=?`"Y0D20U_N\*/O\.54(.8CY5-4'__E +M""7@)&/U@N0TE/6#Y(_P$D*!Y4\PYS2O"+'#@"[E4U0?_^4()>`DH_6"Y#24 +M]8/DC_`20H'E3S#G$>5/5'_]Y5-4'_4-JPFO")&PY6H4)/U0`H!`D)=ZX&`R +MD`%;Y/"0`3QT!/!Q_.]D`7`H=404]47[_7]8?@$2,&*0`5MT!?"0!I)T`?"0 +MEW;P@`AQ_+\!`Q),BN4L,.$FD`$T=`+PD/T0='_PA=%8A=)9A=-:A=1;A=5< +MA=9=A==>A=E?D0OE+##C!I`!-'0(\.4L,.0)D`$T=!#P0U<0Y2PPY2:0`<_@ +M,.4?X%3?\)`!-'0@\'6H`'7H`!)/Y9```^!4^_`21-:`_N4L,.8&D`$T=$#P +MY2XPX3R0`39T`O!#5T"0`0+@5`-D`7`ID`$WX##@"G0!\)"7?^3P@!B0EW_@ +M!/#@PY0*0`SD\)`$&>`PX`,21/+E+C#@")`!-G0!\-%EY2XPXG&0`39T!/#E +M:60!<&7E:F!AY6ID`F`&Y6ID!7`GD`:KX)"7;?"0!JK@D)=X\)"7;>!P!Y"7 +M>.#_@`60EVW@_Y"7;>_PD)=OX&`#X!3PD)=NY/"0`5?PD`$\=`+PD)=\X%3] +M\.!4[_#E:A0D_5`"@`*Q$.4N,.,QD`$V=`CPY6ED`7`EY6I@(9`!5^3PD`$\ +M=`+P=40#=44`Y/O]?U1^`1(P8I`!5W0%\.4N,.0OD`$V=!#PY6ED`7`CY6I@ +M'Y`!5^3PD`$\=`+PD)=[Y/"0EWS@5/WPX%0'<`,23(KE+C#E'9`!-G0@\.5I +MM`$2Y6I@#I"7>N!D`F`$L7B``K&)Y2XPYAZ0`39T0/#E:;0!$^5J8`^0EWS@ +M5/[PX%0'<`,23(KE+S#A"9`!-W0"\!)/>71$!)`!Q/!T4*/PT`?0!M`%T`30 +M`]`"T`'0`-#0T(+0@]#PT.`RD`0;X%1_9']_`6`"?P`BD)=-X%3P1`/P5`]$ +M@/![`'H`>5B0EY$20XL+>I=Y3=,0KP'#P-"0EXX20XN0EX;@9`)@;)`!K^!@ +M"9`!Q^`$\/"`\9"7H^#_!/"0EXX20VN0``'O$D)?D)>.$D-KBV.*9(EE=68" +M>P%Z`7F@$D4)D)>1$D-KBV.*9(EED)>.$D-K$B1B_\14#_5F>P%Z`7FB$D4) +MD`&O=/_PD`'+X&2`\-#0DJ\BJ07I5!_U#W0!+_6"Y#22]8/@]0Z0!/W@M`$% +M=1`#@`-U$`'KPY400`*AP^4.)0W^Y0^00=:3_>[3G70!0!0EWS@1`'PD)=ZX&0"8`2Q>(`+L8F`!Y"7?.!4_O#E"I"7?##G +M(.!$`O!U1`/D]47[_7]4?@$2,&*0`5=T!?"0EWMT`?`BX%3]\"*0EX'@_^3] +M$D9AD`0?=`'P(I`!7^3PD`$\=`CP=404Y/5%^_U_7'X!$C!BD`%?=`7PD`:2 +M=`+PD)=U%/"0EW?@5`_#E`Q0`Q),DR*M!W7P">V0DR<20U_@_W2E+?6"Y#26 +M]8/@5!_\TY]``JP'["7@))[U@N0T0?6#Y)/^=`&3_^PEX"1F]8+D-$'U@W0! +MDR__Y),^PQ/^[Q/_[27@).'U@N0TDO6#[O"C[_!TA"WU@N0T!/6#[/#_(G'\ +M[V0!<"J0EWS@5`-P(I"7>>!4#].4`E`7D)=\X"#B$)"7?.`@Y`F0EV_@<`-_ +M`2)_`"+DD)=-\.5J8''E:60!<&OE:A1@*23]8"4D`B3[4`*`(Y"7;>`4\.!@ +M!*/@8!:0EVW@<`J0EWC@D)=M\(``D)=-=`'PD)=-X&`QD)=\X$00\)"7=.#U +M1.3U1?O]?U1^`1(P8I`!5W0%\)"7=^!4#\.4!%`'?0%_!!),ER+`X,#PP(/` +M@L#0==``P`#``<`"P`/`!,`%P`;`!Y`!Q'3@\'16H_!3D>^0`%'@_Y``5>!? +M]3WE/3#F&'1`\)"7.^!4`_^_`PN0ESC@8`5_`1)'->4],.<5D`!5=(#PD)<[ +MX%0#_[\#!7\"$D0EZ'@_W0! +M?@"H!PB`!<,SSC/.V/G_[UUP`P)8O9"7H>!U\`20`=`20U_@D)=3\'5C`75D +MEW5E4W5F`7L!>I=Y5!)%"9"75.#_Q!,3$U0!D)>A,.!9X'7P`I``B!)#7^"0 +MEU7PD)>AX'7P`I``B1)#7^"0EU;PD)>AX'7P!)`!T1)#7^"0EU?PD)>AX'7P +M!)`!TA)#7^"0EUCPD)>AX'7P!)`!TQ)#7^"0EUGP@#/@=?`$D`'1$D-?X)"7 +M5?"0EZ'@=?`$D`'2$D-?X)"75O"0EZ'@=?`$D`'3$D-?X)"75_#O5'__>P%Z +MEWE5$#^=`&H!@B``L,SV/ST7Y"74O"0EZ'@_W0!J`<(@`+# +M,]C\D`',\)"7H>`$\.!4`_`"5XJ0`<;@1`+P`E>*(I"76A)#B^\20Y18]`%8 +M_`)9!`-9#`59%`991@=9'`E9)0Q9+@U9-@X``%D_D)=:$D-KP=B0EUH20VO! +MTI"76A)#:^%DD)=:$D-KX0*0EUH20VN`*Y"76A)#:P)$89"76A)#:P)X?Y"7 +M6A)#:^$QD)=:$D-K`G9PD`'&X$0!\"*0``020B#_5!_^[U0@Q!-4!_VO!I"7 +M7>_PH^WPHQ)#BY"77Q)#:Y```Q)"(%3PQ%0/D)=B\)``!!)"(%1`Q!,35`.0 +MEV/PD)==X/]U\`F0DR420U^M@JR#D)=D[/"C[?#O=?`)I"0C^723-?#Z>P&C +M$D.+D)=?$D-KD``#$D(@5`__D)=F$D-K[Q)"39"77Q)#:Y```A)"(/^0EV82 +M0VN0``'O$D)?D)=?$D-KD``!$D(@_Y"79.#\H^#]]8*,@^_P$B1BC8*,@Z/P +MD)=BX/Z0EUW@_R3!]8+D-)+U@^[PD)=>X/YU\`GOD),I$D-?[O!U\`GOD),J +M$D-?=`'PD)=CX/YU\`GOD),K$D-?[O"/$>\EX"3D]8+D-)6O@O43CQ3E$77P +M`J0D@?ETDC7P=14!]1:)%W7P">41D),E$D-?KX*%@QB/&>41=?`)I"0C^723 +M-?!U&@'U&XD<=,$E$?6"Y#22]8/@$D.46M4`6NH!6O\"6Q0#6ST$6U(%6V<& +M6XT,6[H-6^<.7!0/``!<2.41)>`DY/6"Y#25]8-T\/"C=!6`/.41)>`DY/6" +MY#25]8-T\/"C=!"`)^41)>`DY/6"Y#25]8-T\/"C=`6`$N41)>`DY/6"Y#25 +M]8-T\/"CY/#E$27@)('U@N0TDO6#=`_PHW2/\(%(Y1$EX"3D]8+D-)7U@W0/ +M\*-T]8`GY1$EX"3D]8+D-)7U@W0/\*-T\(`2Y1$EX"3D]8+D-)7U@^3PHW0- +M\.41)>`D@?6"Y#22]8/D\*/P@4B0!$?@JQ6J%JD7$D)-D`1&X*L5JA:I%Y`` +M`1)"7Y`$1>"%%(*%$X/PD`1$@3^0!$O@JQ6J%JD7$D)-D`1*X*L5JA:I%Y`` +M`1)"7Y`$2>"%%(*%$X/PD`1(@%B0!$_@JQ6J%JD7$D)-D`1.X*L5JA:I%Y`` +M`1)"7Y`$3>"%%(*%$X/PD`1,@"N0!%/@JQ6J%JD7$D)-D`12X*L5JA:I%Y`` +M`1)"7Y`$4>"%%(*%$X/PD`10X(44@H43@Z/PJQ6J%JD7P`/``L`!$B1B_ZL: +MJANI'!(D8E_0`=`"T`,20DVK%>47)`'YY#46^L`#P`+``1(D8O^K&JH;J1R0 +M``$20B!?T`'0`M`#$D)-A12"A1.#P(/`@N#_A1F"A1B#X/[O7M""T(/PA12" +MA1.#H\"#P(+@_X49@H48@Z/@_N]>T(+0@_#E$27@)('U@N0TDO6#X/ZCX$Y@ +M.W42"W0!?@"H$@B`!<,SSC/.V/G_Y1$EX"2!]8+D-)+U@^!>_J/@7TY@!N42 +M)!"`7142Y1+#E`!0RH!6Y1$EX"3D]8+D-)7U@^#^H^!.8#UU$@]T`7X`J!(( +M@`7#,\XSSMCY_^41)>`DY/6"Y#25]8/@7OZCX%].8`B0EVGE$O"`$!42Y1+# +ME`!0R(`%Y)"7:?#E$27@).3U@N0TE?6#X/ZCX$Y@.^3U$G0!?@"H$@B`!<,S +MSC/.V/G_Y1$EX"3D]8+D-)7U@^!>_J/@7TY@")"7:N42\(!;!1+E$K00RH!2 +MY1$EX"2!]8+D-)+U@^#^H^!.8#GD]1)T`7X`J!((@`7#,\XSSMCY_^41)>`D +M@?6"Y#22]8/@7OZCX%].8`;E$B00@`H%$N42M`S,@`7DD)=J\)"7:>#_=?`) +MY1&0DR<20U_O\)"7:N#^=?`)Y1&0DR@20U_N\'2$)1'U@N0T!/6#X-.?0!^0 +MEVG@_W2$)1'U@N0TEO6#[_!TA"41]8+D-`3U@^_P=(0E$?6"Y#0$]8/@PYY0 +M'Y"7:N#_=(0E$?6"Y#26]8/O\'2$)1'U@N0T!/6#[_"0EVG@_].4$T`(D),B +M=`/P@"'OTY0+0`B0DR)T`O"`$^_3E`-`")"3(G0!\(`%Y)"3(O"0DR+@D`2Q +M\"(2)&+U:2+3$*\!P\#0D``!$D(@D)=Z\)```Q)"()"7;/`2)&)E:F`#$DWQ +MT-"2KR(2)&+U$<.4(%`5D``"$D(@_W0C)1'U@N0TE?6#[_`BY1&T(`J0``(2 +M0B"0DR'P(I```A)"()"7//#@8`3@]'`AHJ_D,_41PJ^0`$?@5/O]?T<21R!] +M0'\!$C%FY1$D_Y*O(I`"">#]$B1B_J\%[2Z0EX#PD``!$D(@_^TOD)>!\)`` +M`A)"(/_M+Y"7@O"0``,20B#_[2^0EX/PD``$$D(@_ZX%[2^0EX3P(N3U:9"7 +M?/#U:I"7>70,\)"7=_#DD)=Z\)"7=O"0EW7PD)=X!/"0EVWPY)"7>_"0EV_P +MD)=T=`?PY)"7;O"0EW+PHW0"\.20EW'PD)=L\"+DD)=[\)"7;O"0EWSP(N57 +M<#>0EWG@5`_3E`%0+)`"A^!P)I"7AN"T`A"0EWW@_J/@]8*.@^!@"(`/D`&O +MX'`)D)=QX&`#?P$B?P`BD``KX$0!\'_H?@,2,A60``C@1!#]?P@21R"0``G@ +M5/?]?PD21R"0`"C@5/[]?R@21R"0`"#@5/[]?R`21R"0`"7@1$#]?R421R"0 +M``G@5._]?PD"1R"0`"7@5+_]?R421R"0`"#@1`']?R`21R"0`"C@1`']?R@2 +M1R"0`/#@,.'YD``)X$0(_7\)$D<@D``(X%3O_7\($D<@D``KX%3^_7\K$D<@ +M?^A^`P(R%8]LD)>#$D9=Y6Q@$'0A+_6"Y#3\]8/@1!#P@`YT(2_U@N0T_/6# +MX%3O\)`$'W0!\"+OPY0@4#GO,.`7[<14\/WOPQ/^)*3U@N0T!/6#X%0/@!#O +MPQ/^)*3U@N0T!/6#X%3P\'2D+O6"Y#0$]8/@3?`BY/41=?`)Y1&0DRH20U_@ +M9`%@`N%AY1$EX"3`]8+D-)'U@^#^H^#3E`#NE`!0`N%AY1%U\`JD)`#Y=)`U +M\'46`?47B1CE$27@),#U@N0TD?6#X/^CX)"75L_PH^_PY1$EX"1C]8+D-)3U +M@^#_H^"0EUC/\*/O\'2$)1'U@N0T!/6#X%0_D)=2\.#^5!^C\'7P">41D),G +M$D-?X)"76_!T9"41]8+D-);U@^##E`5``H$[D)=;X/^0EU/@GT`3D)=;X)"7 +M4_#N5$#^D)=2\.].\)`$_>!D`7`ID)=3X/^004J3_G0C)1'U@N0TE?6#X,.> +M0`;OD$#:@#"0EU/@D$#V@">0EU/@_Y!!2I/^=",E$?6"Y#25]8/@PYY`!N^0 +M01*`!Y"74^"002Z3D)=:\)"76N!U\`:D)%#Y=$`U\'43__44B160EU+@D$'R +MD__3D)=9X)^0EUC@E`!`">3]KQ$2:5K!^.41)>`DX?6"Y#22]8/@]1FCX/4: +MJQ.J%*D5$B1B_WX`JQ:J%ZD8$D*7_:SP$B1[[R4:]1KN-1GU&:L3JA2I%9`` +M`1)"(/]^`*L6JA>I&)```A)"POVL\!(D>^\E&O4:[C49]1FK$ZH4J160``(2 +M0B#_?@"K%JH7J1B0``020L+]K/`2)'OO)1KU&NXU&?49JQ.J%*D5D``#$D(@ +M_WX`JQ:J%ZD8D``&$D+"_:SP$B1[[R4:]1KN-1GU&:L3JA2I%9``!!)"(/]^ +M`*L6JA>I&)``"!)"POVL\!(D>^\E&O4:[C49]1FK$ZH4J160``420B#_?@"0 +MEU;@_*/@_1(D>]/E&I_E&9Y`#.4:G_4:Y1F>]1F`!>3U&?4:Y1$EX"3A]8+D +M-)+U@^49\*/E&O"0EU+@)>`D9O6"Y#1!]8/#=`&3E1KDDY494`:O$?%MP`DGO6"Y#1!]8/3=`&3E1KDDY494`+!S'T!KQ$2:5K!S'1D)1'U@N0T +MEO6#X/QD!6`"H=:0DR+@_[0#"Y"74^##E!E`/8`N[[0""Y"74^##E!%`+H`? +MD),BX/^T`0N0EU/@PY0*0!N`#.]P$9"74^##E`-`#9"50W0!\(`%Y)"50_!T +M0R41]8+D-)3U@^#U&W0C)1'U@N0TE?6#X/_#E#!0`J&#D)5#X&0!8`*A@W1$ +M)1'U@N0TE?6#X&0*8%'O)`7_Y#/^="$E$?6"Y#22]8/@_=.?[F2`^'2`F%`R +M[20%_^0S_G0C)1'U@N0TE?6#X-.?[F2`^'2`F%`4=(0E$?6"Y#26]8/@_Y"7 +M4^!O8#UT(R41]8+D-)7U@^#_TY1"0`5U&P6`#N_3E#E`!74;`X`#=1L!="$E +M$?6"Y#22]8/O\'1$)1'U@N0TE8`I=&0E$?6"Y#26]8/D\'1$)1'U@N0TE?6# +MX`3P@!#D]1MT9"41]8+D-);U@^3PD)=3X/]TA"41]8+D-);U@^_P=$,E$?6" +MY#24]8/E&_!U\`GE$9"3*Q)#7^"T`1#D]1MT9"41]8+D-);U@^3PK1O!R.QD +M!F`"PI&'7P`N42I/6"A?"#$D+"_:SPY1*00@Z3_WX`$B1[[R4: +M]1KN-1GU&<.0EU7@E1J0EU3@E1E`!P42Y1*T!;WE$L,3]1+E&[0!!N42<$:` +M$^4;M`,5Y1)P!74;`X`YY1*T`05U&P&`+X`JY1NT!2CE$G`%=1L%@`WE$K0! +M!74;`X`#=1L!TY"76>"4`Y"76."4`$`#Y/4;TY"76>"4`Y"76."4`$`#Y/4; +M=$,E$?6"Y#24]8/E&_#]KQ$Q)'1D)1'U@N0TEO6#X-.4!71D4`XE$?6"Y#26 +M]8/@!/"`"R41]8+D-);U@^3PJQ:J%ZD8Y/7P$D+ZJQ:J%ZD8D``"Y/7P$D,9 +MD``$Y/7P$D,9D``&Y/7P$D,9D``(Y/7P$D,9Y1$EX"3`]8+D-)'U@^3PH_#E +M$27@)&/U@N0TE/6#Y/"C\.41)>`DH_6"Y#24]8/D\*/P!1'E$<.4(%`"(6S#E!!`(>PD\/]T`7X`J`<(@`7#,\XSSMCY +M_Y"77>!>_J/@7TYP(^S#E!!0.70!?@"H!`B`!<,SSC/.V/G_D)=?X%[^H^!? +M3F`<[&038`CL9!)@`[P1"9"77>`PX`)\&*T$C1R`-`R`BY"77.#\;7!I=*4I +M]8+D-);U@^WP=?`)Z9"3*1)#7^"T`0SE'"#F!^U$0/4<@`.O'"+M)>`DGO6" +MY#1!]8/DD_YT`9/_[27@)&;U@N0T0?6#=`&3+__DDS[#$_[O$__I)>`DX?6" +MY#22]8/N\*/O\(!;[=.<0%:0EUS@_W2E*?6"Y#26]8/O\*T'CQSM)>`DGO6" +MY#1!]8/DD_YT`9/_[27@)&;U@N0T0?6#=`&3+__DDS[#$_[O$__I)>`DX?6" +MY#22]8/N\*/O\*\<(G0!*?6"Y#22]8/D\.4<1(#_=(0I]8+D-`3U@^_P(JH' +M=(0J]8+D-`3U@^!4?_M4'_F0EU[P=?`)ZI"3*!)#7^"0EV#P=?`)ZI"3)Q)# +M7^"0EV'P_.HEX"3D]8+D-)7U@^#_H^"0EV+/\*/O\.HEX"2!]8+D-)+U@^#_ +MH^"0EV3/\*/O\.G3G$`)D)=AX)"77O#[[7`"09V0EU_M\.LPY@F0EU[@^Z/@ +M%/"0EU_@<`)!G9"77N#_TY0`4`)!G>20EUWP[Q20EUSPD)=@X/F0EUS@_M.9 +M0'+NE!!`)>XD\/]T`7X`J`<(@`7#,\XSSMCY_Y"79.#\H^#][%[^[5].<"N0 +MEUS@_\.4$%`V=`%^`*@'"(`%PS/.,\[8^?^0EV+@_*/@_>Q>_NU?3F`5D)=< +MX/NCX`3PD)=?X/^0EUW@;V`(D)=##GU`,D)=`DX?6"Y#22]8/N\*/O\'2$*O6"Y#0$]8/K\/\BD`1$=!'P +MHW3P\*-T#_"CY/#]=*0M]8+D-`3U@^3P#;T0\.3]=?`*[9"0`!)#7^3PH_!U +M\`KMD)`"$D-?Y/"C\'7P"NV0D`020U_D\*/P=?`*[9"0!A)#7^3PH_!U\`KM +MD)`($D-?Y/"C\'2$+?6"Y#26]8-T$_!T1"WU@N0TE?6#Y/!T0RWU@N0TE/6# +MY/#M)>`DP/6"Y#21]8/D\*/P[27@)&/U@N0TE/6#Y/"C\.TEX"3C]8+D-)3U +M@^3PH_#M)>`DH_6"Y#24]8/D\*/P[27@)&3U@N0TE?6#Y/"C\.TEX"2D]8+D +M-)7U@^3PH_!T1"WU@N0TEO6#Y/!T)"WU@N0TEO6#Y/!T9"WU@N0TEO6#Y/"0 +M0<23_G0!D_^008QT`9,O_^23/L,3_N\3_^TEX"3A]8+D-)+U@^[PH^_P=?`) +M[9"3*A)#7W0!\'7P">V0DRD20U]T`?!TP2WU@N0TDO6#=`SP=?`)[9"3)1)# +M7W3_\*/P=?`)[9"3(Q)#7^3PHW0/\'7P">V0DR<20U]T$_!U\`GMD),H$D-? +MY/!TA"WU@N0T!/6#=!/P#>UD(&`"80\BD`8T=/_PY*/PH_"C\"(BY)"7A?"B +MKS.0EU/PD`"`X"#A&A(R*Q(R*Y"74N!D`?#@)*V0`<3P=&RC\(#?D`8P=`'P +MPJ^0`(#@1(#P$D36D)=3X"3_DJ\BCA&/$HL3BA2)%>20EU+P[Y``,?`21-;E +M$50#_Y``,N!4_$_P$D36D``SX%1_\!)$UI``,^`@YPZ0EU+@PY1D4`7@!/"` +MZY"74N##E&10$)``,."K$ZH4J1420DU_`2)_`"+D]28B?PNQON]E)F`0Y2:T +M`07D]2:``W4F`7\!(G\`(N4C9`%P0+%;OP$%?P$21.:0`$;@1`3]?T821R"0 +M`$3@5/O]?T021R"0`$;@5/O]?T821R!_`K&^CR>0`_PTY0'4$?@_W0!J`<(@`+#,]C\]/^0`$;@7_`21-:0EZ7@_70! +M?@"H!0B`!<,SSC/.V/G_D`!$X/OD_N];J`4(@`;.HN<3SA/8^/^`1)"7I>`D +M^/#@_W0!J`<(@`+#,]C\$D3.D)>EX/UT`7X`J`4(@`7#,\XSSMCY_Y``0N#[ +MY/[O6Z@%"(`&SJ+G$\X3V/C_T-"2KR+DD)>=\*/PD`7XX'`/H^!P"Z/@<`>C +MX'`#?P$BTY"7GN"4Z)"7G>"4`T`#?P`B?S)^`!(R%9"7G>1U\`$20H&`QI`` +M$>!$"?`21-:0EQT20U.0@)82)0A_>'X($BL(D)3]_Q(P+)"7A^"T`1&0@&@2)10``RV5Y/U_`1(P+")_>'X($B)ED)<= +M$B4(?P1^#!(B99"7(1(E"'\`?@@2(F60ER42)0B0EX?@D)<=M`$-$D-3[U3' +M_^U4Q_V`!Q)#4^]4Q__LD("6$B4(?WA^"!(K")"7(1)#4^]4#__LD("6$B4( +M?P1^#!(K")"7)1)#4^]$`O_LD("6$B4(?P!^"!(K"']P?@X2(F60ERD2)0B0 +M@)82)10`&R6@?W!^#A(K")"`:!(E%`````#D_?\2,"R0EX?@M`$1D(!H$B44 +M`````.3]?P$2,"R0`!'@5/;P`D36D)>'X)"7+?`B[W`"(;&0ERW@8`*A?)"7 +M&1)#4Y"`EA(E"'^,?@@2*PB0EL420U.0@)82)0A_1'X($BL(D);)$D-3D("6 +M$B4(?UQ^"!(K")"6S1)#4Y"`EA(E"']L?@X2*PB0EM$20U.0@)82)0A_<'X. +M$BL(D);5$D-3D("6$B4(?W1^#A(K")"6V1)#4Y"`EA(E"']X?@X2*PB0EMT2 +M0U.0@)82)0A_?'X.$BL(D);A$D-3D("6$B4(?X!^#A(K")"6Y1)#4Y"`EA(E +M"'^$?@X2*PB0END20U.0@)82)0A_B'X.$BL(D);M$D-3D("6$B4(?XQ^#A(K +M")"6\1)#4Y"`EA(E"'_0?@X2*PB0EO420U.0@)82)0A_U'X.$BL(D);Y$D-3 +MD("6$B4(?]A^#A(K")"6_1)#4Y"`EA(E"'_9$B4(D)>9$D-3[43`_>R0EYD2)0B0EYD20U.0@)82)0A_C'X( +M$BL(D("6$B44``$``']$?@@2*PB0@)82)10`VR6D?UQ^"!(K")"`EA(E%"#; +M):1_;'X.$BL(D("6$B44(-LEI']P?@X2*PB0@)82)10$&R6D?W1^#A(K")"` +MEA(E%`0;):1_>'X.$BL(D("6$B44!!LEI']\?@X2*PB0@)82)10$&R6D?X!^ +M#A(K")"`EA(E%&/;):1_A'X.$BL(D("6$B44!!LEI'^(?@X2*PB0@)82)10@ +MVR6D?XQ^#A(K")"`EA(E%"#;):1_T'X.$BL(D("6$B44(-LEI'_4?@X2*PB0 +M@)82)10@VR6D?]A^#A(K")"`EA(E%``;):1_W'X.$BL(D("6$B44`!LEI'_@ +M?@X2*PB0@)82)10DVR6D?^Q^#A(K"'\$?@P2(F60EYD2)0B0EYD20U/D_^R0 +MEYD2)0B0EYD20U/O1!'_[)"7F1(E")"7F1)#4Y"`EA(E"'\$?@P2*PA_!'X- +M$B)ED)>9$B4(D)>9$D-3[U3P_^R0EYD2)0B0EYD20U/O1`'_[)"7F1(E")"7 +MF1)#4Y"`EA(E"'\$?@T2*PA_#'X)$B)ED)>9$B4(D)>9$D-3Y/_LD)>9$B4( +MD)>9$D-3[T01_^R0EYD2)0B0EYD20U.0@)82)0A_#'X)$BL(?PQ^"1(B99"7 +MF1(E")"7F1)#4^U4#_WL5/#\D)>9$B4(D)>9$D-3[400_>Q$`?R0EYD2)0B0 +MEYD20U.0@)82)0A_#'X)$BL(?P1^"!(B99"7F1(E")"7F1)#4^]4\/_LD)>9 +M$B4(D)>9$D-3[T0!_^R0EYD2)0B0EYD20U.0@)82)0A_!'X($BL(Y)"7+?`B +MTQ"O`?[_#3E`=09>#_=`&H!PB``L,SV/ST_Y``1^!?\!)$ +MUI"7G^#_=`&H!PB``L,SV/S_D`!&X$_P$D36D)>@X&`6D)>?X/]T`:@'"(`" +MPS/8_/^0`$6`:)"7G^#_=`&H!PB``L,SV/ST_Y``18!MD)>?X"3X\.#_=`&H +M!PB``L,SV/S$5/`21,Z0EY_@_W0!J`<(@`+#,]C\_Y``0^!/\!)$UI"7H.!@ +M&Y"7G^#_=`&H!PB``L,SV/S$5/#_D`!"X$^`&I"7G^#_=`&H!PB``L,SV/S$ +M5/#T_Y``0N!?\!)$UM#0DJ\BBQ&*$HD3D``"$D(@D)<[\.`PX$N0ES)T`?!_ +M@'X($B)ED)D`!'X%3S_7]'$D<@D`!(X%3S_7]($D<@D`!&X%3O_7]& +M$D<@Y)"7./`BY/U_11)'()`$_>3PH_"0ESSPD)="\)"71?"0ET/PD)=&\)"7 +M1/"0ET?PD)!$P/U_40)'()"73.!D`6`)D)`$\(`DD)=#X,.4 +M_U`&X`3PY(`1D)=$X,.4_U`,X`3PY)"70_"0ET+PD`!$X##C,I"71>##E/]0 +M!>`$\(`DD)=&X,.4_U`&X`3PY(`1D)='X,.4_U`,X`3PY)"71O"0ET7PD`3] +MX$0!\"*0``(20B"0ESKPD``!$D(@)>`EX)"7.?`2)&(EX"7@D)<]\)`%8."0 +METCPD`5AX)"72?"0!6+@D)=*\)`%8^"0ETOPHJ_D,Y"77?#"KY"7.>#_$DIB +MD)==X"3_DJ^0ESK@<`(AB9"7.>!P`B&)D)<]X'`"(8FBK^0SD)==\,*OD)=, +M=`'PD)==X"3_DJ\21Q>0`$;@1`']?T821R"0ES+@8!60ESX20U.0@)82)0A_ +M@'X($BL(@`:0!2)T?_"0`$7@5._]?T421R"0!8?@9(#PD)=(X)`%A/"0ETG@ +MD`6%\)"72N"0!8;PD)=+X)`%A_"BK^0SD)==\,*OD`$\X$0@\'T@Y/\2,;>` +M+9"7.N!P+Y"73!)'%I``1N!4_OU_1A)'()`%(N3PHJ\SD)==\,*O?2#D_Q(Q +-29"77>`D_Y*O(@"'%P`` +` +end diff --git a/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU_B.fw.uu b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwE_B.fw.uu similarity index 99% rename from sys/contrib/dev/rtwn/rtwn-rtl8192cfwU_B.fw.uu rename to sys/contrib/dev/rtwn/rtwn-rtl8192cfwE_B.fw.uu index f10422445ca6..a4dd52165dee 100644 --- a/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU_B.fw.uu +++ b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwE_B.fw.uu @@ -1,4 +1,4 @@ -begin 444 rtwn-rtl8192cfwU_B.fw.uu +begin 444 rtwn-rtl8192cfwE_B.fw.uu MPH@"`%@``@`'%11$K#\!`,S,S,P````````````````"19L````````````` M`````````EE4```````````````````````````````````````````````` M`````````````F2,```````"2[(```4$`P(``P8%!`,`!`8%!`(`!`@'!@0` diff --git a/sys/contrib/dev/rtwn/rtwn-rtl8192cfwT.fw.uu b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwT.fw.uu new file mode 100644 index 000000000000..19a506265932 --- /dev/null +++ b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwT.fw.uu @@ -0,0 +1,362 @@ +begin 644 rtwn-rtl8192cfwT.fw.uu +MP8@"!5@``@`2!1<2WCX``)08`@`````````````````"1C`````````````` +M`````````F#R```````````````````````````````````````````````` +M`````````````FB1```````"2X<```4$`P(``P8%!`,`!`8%!`(`!`@'!@0` +M!@H)"`8`"`H)"`0`"`H)"`(`"`H)"```"!(1$`@`$!H9&!``&"(A(!@`("(A +M(!``("(A(`@`("(A'`@`("(A%`@`("(@&`@`(#$P(!``,#$P&```,#$O$!`` +M,#$L$!``,#$H$```,#$@$```,#$0$```,`0$!`4$!`4'!P<("@0$!`0&"@L- +M!04'!P@+#0\$!`0%!P<)"0P.$!(&!PD*#`X1$PD)"0D,#A$3```````````` +M)"8J&!H='R$G*2H````?(R@J+``$``0`"``0`!@`)``P`$@`8`"0`,``V`!0 +M`'@`H`#(`4`!D`'@`C`!+`%``>`"T`/H!+`&0`?0``(``@`$``@`#``2`!@` +M)``P`$@`8`!L`"@`/`!0`&0`H`#(`/`!&`!D`*``\`%H`?0"6`,@`^@"`@(" +M`@(#`P0$!0<"`P0*#`X0$@4'!P@+$B0\`0$!`0$"`P0%!@<(`0(#!`4&!P@% +M!@<("0H+#"`>'!@0&``````````````````````````````````````````` +M````````````````````````````````````````````````NP$,Y8(I]8+E +M@SKU@^`B4`;I)8+XYB*[_@;I)8+XXB+E@BGU@N6#.O6#Y),BNP$&B8**@_`B +M4`+W(KO^`?,B^+L!#>6"*?6"Y8,Z]8/H\")0!NDE@LCV(KO^!>DE@LCR(L7P +M^*/@*/#%\/CE@A6"<`(5@^`X\"*[`0J)@HJ#X/7PH^`B4`:'\`GG&2*[_@?C +M]?`)XQDBB8**@^23]?!T`9,BNP$0Y8(I]8+E@SKU@^#U\*/@(E`)Z26"^(;P +M".8BN_X*Z26"^.+U\`CB(N6#*O6#Z9/U\*/IDR*[`0J)@HJ#\.7PH_`B4`;W +M":?P&2*[_@;SY?`)\QDB^+L!$>6"*?6"Y8,Z]8/H\.7PH_`B4`GI)8+(]@BF +M\"*[_@GI)8+(\N7P"/(B[TO_[DK^[4G][$C\(N#\H^#]H^#^H^#_(J0E@O6" +MY?`U@_6#(N#[H^#ZH^#Y(OC@^Z.CX/DE\/#E@A6"<`(5@^#Z./`BZ_"CZO"C +MZ?`BT(/0@OCDDW`2=`&3<`VCHY/X=`&3]8*(@^1S=`*3:&#OHZ.C@-_0@]"" +M^.23`OD(L^\.3[_7]4 +M?@$22VR0`5=T!?#E(E0/PY0$4`=]`7\$$D6BD(LLX##@"1)]P9`%(G3_\"+D +M]27U)'4C#'4B#)"+&O"0BQCPD(L7\)"+&03PD(L+\.20BQOPD(L-\)"+%70% +M\.20BPSPD(L3\*-T`_"0BQ#PHW0%\)"+#W04\)"+%G0%\.20BP[PD(L*\)"+ +M"/"0BQ+P(G\`(@)%`P)%!HYDCV6M9:QDKV,22ENO9:YDD`2`X%0/_:P'=!$L +M]8+D-/SU@^!$`?!T$2SU@N0T_/6#X%3[\*P'=!8L]8+D-/SU@^!$^O!T%2SU +M@N0T_/6#X$0?\*P'=`8L]8+D-/SU@^!$#_"0!%/D\)`$4O"0!%%T__"0!%!T +M_?!T%"SU@N0T_/6#X%3`3?UT%"_U@N0T_/6#[?`B?0%_#-,0KP'#P-"/9XUH +MY6=4#__E(E0/;V!RY6]@4Q)* +MS(!.Y2(@XTGE9S#C1*]H$DI\@#WE(E0/_[\,#N5G(.,)$DG5[V`J$DK,Y2)4 +M#_^_!`[E9R#B"1))D^]@%!)*,N4B5`__OP()$D4`[V`#$DL0T-"2KR("1FX" +M4,;DDZ/XY).C0`/V@`'R"-_T@"GDDZ/X5``ON4A9`%P9^4D +M8&/E)&0"8`;E)&0%<">0!JO@D(L+\)`&JN"0BQGPD(L+X'`'D(L9X/^`!9"+ +M"^#_D(L+[_"0BPW@8`+D\.20BPSPD`58=`/PD`%7Y/"0`3QT`O!3)?U3)>_E +M)!0D_5`"@`,21XXB[V0!<#5]>'\"$C9U?0)_`Q(V=9`!5^3PD`$\=`+P$D6> +MD(LLX##@`Q)]P9`&!.!4?_"0!@K@5/CP(I`!-G1[\*-T`O!]>_\2-N9]`G\# +M$C;FD`8$X$2`\)`&"N!$!_`22T_E(2#@!>20BPWP(N20BL7PD`:IX)"*Q?#@ +M5,!P"5,E_E,E_1)*_)"*Q>`PYA5#)0&0BQK@9`)@!1)*EX`($DE)@`-3)?Z0 +MBL7@,.`*9"*WA)#:Y```A)"(/U_`1)*!Q^`%)"*WA)#:Y`` +M`A)"(/U_`A)*!^3_$D3P4R7]Y254!W`X@#.0 +MBPS@!/!3)>^0BLO@_Y"+$.`O_^0S_I"+#.#3G^YD@/AT@)A`#>4AM`$+H^!P +M!^`$\"(22OPBTQ"O`Y)"+/?"0BP_@D(L^\.3[_7]8?@$22VR0`5MT!?"0!I)T +M`?"0BQCP(N4B5`_#E`10!WT!?P021:(BD`%?Y/"0`3QT"/#DD(L]\)"+#^"0 +MBS[PY/O]?UQ^`1)+;)`!7W0%\)`&DG0"\)"+%Q3PY2)4#\.4#%`-$D6>D(LL +MX##@`Q)]P2(22S3O9`%P-^4E5`-P,>4C5`_3E`)0*.4E(.(CY24@Y!Z0BPW@ +M3_$DBS4R+P0R(,(I`$ +M'>!P%)"*^.#_Y/T27_V.:8]JD`0?="#P(I"+4N_P$GU"D(M2X&`%D`4BY/!3 +M(O!#(@0BD`8$X$1`\.4AM`$%?P$22+-3(O!#(@0BY2,PYA+E(U0/_Y`!+^!4 +M@$]D@/!3([\BD(LLX##@!:\C`GX&?0&O(Q)%HB)3(O!#(@$22UH22UM3(O!# +M(@(B08KV`$&+!0!!BU$`08M3``"0!!O@5']D?W\!8`)_`"+DD(L;\)"+#/#U +M)2*0BQ/@H^"0!5CP(B(B\)"+#^"0BS[PY/O]?UA^`=,0KP'#P-"0BSW@^Z/@ +M]43D]442-:O0T)*O(L#@P/#`@\""P-!UT`#``,`!P`+``\`$P`7`!L`'=0X` +MD`'$=(?P=$NC\%.1WY`!/.!5,/4TH^!5,?4UH^!5,O4VH^!5,_4WY30PX%&0 +M`3QT`?"0BS+@,.`?$Q-4/S#@&)"+-.3PD(LSX&0#8`M_`;'@[W`$?P+1B9"+ +M+.#_,.`=$Q-4/S#@%I"++N3PD(LMX&0&8`GD_['@[W`"T5;E-##A")`!/'0" +M\!%@Y30PXBB0`3QT!/"0!I+@,.`4D(L]Y'%0BQCD +M\%'\Y30PXSB0`3QT"/"0!I+@,.$DD(L]Y/"0BP_@D(L^\.3[_7]#O8`1_`=&)D(LLX##@29"+,.3P_['@[V`^$F5?D(LMX/]D!F`R +M[[0$`H`'D(LMX+0%!.3_@!20BRW@M`,$?P&`"9"++>"T`@5_`1)E@GT!KR,2 +M1:(2?<'E-C#A1Y`!/G0"\)"+,N`PX!F0BS9T`?"0BS/@9`-@"W\!L>#O<`1_ +M`M&)D(LLX##@&I"+,'0!\!)^*Y"++>!D!F`)Y/^QX.]P`M%6=(<$D`'$\'1+ +MH_#0!]`&T`70!-`#T`+0`=``T-#0@M"#T/#0X#+O9`%P/9"+->!@`W\`(I"+ +M".!@`W\!(I"+-.!@`W\!(I"+,N#_$Q-4/S#@"^_$$U0',.`#?P`BD(LVX'\! +M8#9_`"*0BR_@8`-_`"*0BPC@8`-_`2*0BR[@8`-_`2*0BRS@$Q-4/S#@`W\` +M(I"+,.!_`6`"?P`BD(L-X&`6D(LMX'`$?P6`'Y"++>!D`7`:?P*`$Y"++>"T +M`01_`X`(D(LMX'`%?P0298(BTQ"O`"T`@3QK^%5D(M5X+0$!/'&X560 +MBU7@9`%P??&Q@'F0BU7@_[0#!/'*@&WOM`($\:&`99"+5>#_M`0$\=6`6>]P +M5O&.@%*0BU7@M`,%$GQ!@$:0BU7@M`$$\7*`.Y"+5>"T!`42?2.`+Y"+5>!P +M*?%P@"60BU7@_[0!!/%:@!GOM`($\6N`$9"+5>#_M`0$\5J`!>]P`O%GT-"2 +MKR*0!2)T;_"0BS-T`_`B\8Z`[Q)]0H#J\8Z0!2)T__`2?IKO<`:0`UP!/[_@`1^`7\`[RWN/'T`_(`U[%0!37`$_O^`!'X"?P#O+>X\ +MPQ-]`(`:[%0#37`$_O^`!'X$?P#O+>X\$Q-4/WT`)>`EX/RN!*\%(I`!Y'18 +M\*-T`O`BY)"*S/"C\'6.`I$.$FA$D(L'[_`2:%&0BPGO\!)H79"*].[PH^_P +MY/55]2$255,.;9`%P +M.W%.OP$$?P%Q0I``1N!$!/U_1C&(D`!$X%3[_7]$,8B0`$;@5/O]?T8QB'\" +M<6J/8I`!R>5B\+0!`E'B(N!?\-,0KP'#P-!_$-_^T-"2KR+3$*\!P\#0D(K@ +M[?"0BM_O\-.4!U!.H^!P&I"*W^#_=`&H!PB``L,SV/ST_Y``1^!?\(`7D(K? +MX/]T`:@'"(`"PS/8_/^0`$?@3_!1#I"*W^#_=`&H!PB``L,SV/ST_Y``1H!9 +MD(K?X"3X\*/@Y/U_`E$><4[D_W%"Y/5BD`')Y6+PD(K=X/RCX/WL^XU$ +MY/5%?0%_8'X!`C6KD`'*Y6'P[V`"4>(B?PMQ:N]E86`0Y6&T`07D]6&``W5A +M`7\!(G\`(M,0KP'#P-"0BU?O\-.4!U!#X/]T`:@'"(`"PS/8_/3_D`!&40N0 +MBU?@_70!?@"H!0B`!<,SSC/.V/G_D`!$X/OD_N];J`4(@`;.HN<3SA/8^/^` +M2Y"+5^`D^/#@_W0!J`<(@`+#,]C\]/^0`$/@7_!1#I"+5^#]=`%^`*@%"(`% +MPS/.,\[8^?^0`$+@^^3^[UNH!0B`!LZBYQ/.$]CX_]#0DJ\BY)"+!/"0`(#@ +M1(#]?X`AB-,0KP'#P-"0BMH20XN0BMH20VN0``$20L+ZY?`D`/_D.OZ0BMH2 +M0VN0``'NC_`20QD2*=G_8"RU7A:0BMH20VN0``$20L)E8'`$Y5]E\&`BD(K: +M$D-KD``!$D+"_Z[P<0"`#Y"*VA)#:Q(IV65>8`*1E=#0DJ\BY/5>?V!^`8^" +MCH.CHZ/D\"*0BM<20XOO$D.45.(&0BM<20VL">L*0BM<20VL"?"N0 +M`<;@1`'P(M,0KP'#P-"0`!U\`20`=`20U_@D(K0\'4=`74>BG4?T'4@ +M`7L!>HIYT1)>Y)"*T>#_Q!,3$U0!D(M1,.!9X'7P`I``B!)#7^"0BM+PD(M1 +MX'7P`I``B1)#7^"0BM/PD(M1X'7P!)`!T1)#7^"0BM3PD(M1X'7P!)`!TA)# +M7^"0BM7PD(M1X'7P!)`!TQ)#7^"0BM;P@#/@=?`$D`'1$D-?X)"*TO"0BU'@ +M=?`$D`'2$D-?X)"*T_"0BU'@=?`$D`'3$D-?X)"*U/#O5'__>P%ZBGG2D::0 +MBL_@_Y"+4>#^=`&H!@B``L,SV/ST7Y"*S_"0BU'@_W0!J`<(@`+#,]C\D`', +M\)"+4>`$\.!4`_"A:I`!QN!$`O#0T)*O(I``!!)"(/]4'_[O5"#$$U0'_:\& +MD(K:[_"C[?"C$D.+D(K<$D-KD``#$D(@5/#$5`^0BM_PD``$$D(@5$#$$Q-4 +M`Y"*X/"0BMK@_W7P"9"')1)#7ZV"K(.0BN'L\*/M\.]U\`FD)"/Y=(\20E^0BMP20VN0``$20B#_D(KAX/RCX/WU@HR#[_`2*=F-@HR# +MH_"0BM_@_I"*VN#_),'U@N0TAO6#[O"0BMO@_G7P">^0ARD20U_N\'7P">^0 +MARH20U]T`?"0BN#@_G7P">^0ARL20U_N\(\/[R7@).3U@N0TB:^"]1"/$>4/ +M=?`"I"2!^72&-?!U$@'U$XD4=?`)Y0^0AR420U^O@H6#%8\6Y0]U\`FD)"/Y +M=(`D@?6"Y#2&]8-T#_"C=(_P(:?E#R7@).3U@N0TB?6# +M=`_PHW3U@"?E#R7@).3U@N0TB?6#=`_PHW3P@!+E#R7@).3U@N0TB?6#Y/"C +M=`WPY0\EX"2!]8+D-(;U@^3PH_`AIY`$1^"K$JH3J1020DV0!$;@JQ*J$ZD4 +MD``!$D)?D`1%X(41@H40@_"0!$0AGI`$2^"K$JH3J1020DV0!$K@JQ*J$ZD4 +MD``!$D)?D`1)X(41@H40@_"0!$B`6)`$3^"K$JH3J1020DV0!$[@JQ*J$ZD4 +MD``!$D)?D`1-X(41@H40@_"0!$R`*Y`$4^"K$JH3J1020DV0!%+@JQ*J$ZD4 +MD``!$D)?D`11X(41@H40@_"0!%#@A1&"A1"#H_"K$JH3J13``\`"P`$2*=G_ +MJQ>J&*D9$BG97]`!T`+0`Q)"3:L2Y10D`?GD-1/ZP`/``L`!$BG9_ZL7JABI +M&9```1)"(%_0`=`"T`,20DV%$8*%$(/`@\""X/^%%H*%%8/@_N]>T(+0@_"% +M$8*%$(.CP(/`@N#_A1:"A16#H^#^[U[0@M"#\.4/)>`D@?6"Y#2&]8/@_J/@ +M3F!+D(KF=`OPD(KFX/_#E`!0`D'L=`%^`*@'"(`%PS/.,\[8^?_E#R7@)('U +M@N0TAO6#X%[^H^!?3F`*D(KFX"00H_"`:)"*YN`4\("[Y0\EX"3D]8+D-(GU +M@^#^H^!.8$>0BN9T#_"0BN;@_\.4`$`\=`%^`*@'"(`%PS/.,\[8^?_E#R7@ +M).3U@N0TB?6#X%[^H^!?3F`(D(KFX*/P@`V0BN;@%/"`O^20BN?PY0\EX"3D +M]8+D-(GU@^#^H^!.8$;DD(KF\)"*YN#_PY000`)AI70!?@"H!PB`!<,SSC/. +MV/G_Y0\EX"3D]8+D-(GU@^!>_J/@7TY@!I"*YN"`8Y"*YN`$\("_Y0\EX"2! +M]8+D-(;U@^#^H^!.8$;DD(KF\)"*YN#_PY0,4#QT`7X`J`<(@`7#,\XSSMCY +M_^4/)>`D@?6"Y#2&]8/@7OZCX%].8`B0BN;@)!"`"9"*YN`$\("_Y)"*Z/"0 +MBN?@_W7P">4/D(4/D(0AR)T`?`BY)"'(O`BTQ"O`0BL7@)0W_H_"CX)!!GI/^[].>0!!T`2SU@N0TAO6#Y/"O!("=D(K& +MX/]T`2SU@N0TAO6#[_`BK0=U\`GMD(`D+O6" +MY#1!]8-T`9,K_^23.L,3_N\3_^TEX"3A]8+D-(;U@^[PH^_PKP60BLG@_9%. +MD(K)X/\BK`=TA"SU@N0T!/6#X%1_D(K>\.!4'_^0BN'P=?`)[)"'*!)#7^"0 +MBN/P=?`)[)"')Q)#7^#^D(KD\.PEX"3D]8+D-(GU@^#[H^"0BN7+\*/K\.PE +MX"2!]8+D-(;U@^#[H^"0BN?+\*/K\._3GD`,D(KDX)"*X?"0BM[P[7`"P9.0 +MBN+M\)"*WN`PY@Z0BN'@D(K>\)"*XN`4\)"*XN!P`L&3D(KAX/_3E`!0`L&3 +MY)"*X/#O%)"*W_"0BN/@_9"*W^#_TYU`;^^4$$`A[R3P_W0!?@"H!PB`!<,S +MSC/.V/G_D(KGX%[^H^!?3G`GD(K?X/_#E!!0-W0!?@"H!PB`!<,SSC/.V/G_ +MD(KEX%[^H^!?3F`:D(K?X)"*WO"0BN#@!/"0BN+@_Y"*X.!O8`B0BM_@%/"` +M@Y"*XN#_D(K@X,.?4`^0BM_@M04(D(KCX)"*WO"0BM[@_R7@)&;U@N0T0?6# +MY)/Z=`&3^^\EX"0N]8+D-$'U@W0!DRO_Y),ZPQ/^[Q/_["7@).'U@N0TAO6# +M[O"C[_"O!)"*WN#]D4Z0BM[@_R+3$*\!P\#0BQJ*&XD@%YH-'DD(M($D-KBQV*'HD?D(M%$D-K$BG9 +M_\14#_4@>P%Z`7FBT>20`:]T__"0`@!Y5I"+2!)#BPMZBGG%X3/3$*\!P\#0D`'$=,7P=%^C\)`$'>!@&I`% +M(N!4D&`'D`'&X$1`\)`!Q^`PX>1_`(`"?P'0T)*O(M,0KP'#P-#D^_KO,.`" +M>X#OPQ.0_1#PD`0E[_#M8!ZO`W0/+_6"Y#3\]8/@1(#P=!`O]8+D-/SU@^!$ +M@/"O`W0(+_6"Y#3\]8/D\'0)+_6"Y#3\]8/@5/#P="$K]8+D-/SU@^!4]_"N +M`J\#T-"2KR(27\6_`1"0`@G@_WT!$E_]D`0?="#P(I`!`N!4`__@5`P3$U0_ +M_N]D`6`$[[0##I"*Q70!\*-T-_!Y`8`8[F0!8`>O!NYD`W`[D(K%=`'PHW0] +M\'E`D(K%X/ZCX/_U@HZ#X%E@".GPY)"*]O`BD(KVX`3PX,.4"D`+Y/"0!!G@ +M,.`"$6TBP.#`\,"#P(+`T'70`,``P`'``L`#P`3`!<`&P`>0`<1T\O!T8*/P +MD`$TX%4H]2RCX%4I]2VCX%4J]2ZCX%4K]2_E+"#@`D&)D`$T=`'PA=%-A=). +MA=-/A=10A=51A=92A==3A=E4Y5140,,3_^535"!O<`)!1N54,.4"04;E4E0? +M]0CE350_]0GE450?_^4()>`DX_6"Y#2(]8/DC_`20H'E4U0?_^4()>`DP/6" +MY#2%]8/DC_`20H'E"=.4!$`#=0D$=?`*Y0B0A``20U]U\`+E"1)#7^#^H^#_ +MY5-4'R__Y#[^=?`*Y0B0A``20U]U\`+E"1)#7^[PH^_PY50@YB3E4U0?_^4( +M)>`D8_6"Y#2(]8/DC_`20H'E3S#G-J\($ES#@"_E4U0?_^4()>`DH_6"Y#2( +M]8/DC_`20H'E3S#G$N5/5'_]Y5-4'_4-JPFO"!)<9N4D%"3]4`*`.I"+&N!@ +M*Y`!6^3PD`$\=`3P$DLT[V0!<"&0BST22UR0`5MT!?"0!I)T`?"0BQCP@`D2 +M2S2_`0,22OSE+##A(9`!-'0"\(715H725X736(7468756H766X777(7971)? +MI.4L,.,&D`$T=`CPY2PPY`F0`31T$/!#51#E+##E)I`!S^`PY1_@5-_PD`$T +M="#P=:@`=>@`$E&=D``#X%3[\!)2#H#^Y2PPYBV0`31T0/"0BS+@,.`,$Q-4 +M/S#@!9"+-.3PD(LLX/\PX`P3$U0_,.`%D(LNY/#E+B#@`F'FD(L(=`'PD`$V +M\)"+!N!@#^3PD`53X$0"\)`%_.`$\)"+,N`PX"^0BS=T`?"0BS+@_Q,35#\P +MX!V0BS1T`?"Q.9"+,^!D`V`-?P$23>#O8`5_!!).B9"++.#_,.!5$Q-4/S#@ +M3I"++G0!\+$YY/\23>#O8#ZQ7Y`%(G3_\)"++>#_9`9@+>^T!`*`!Y"++>"T +M!03D_X`4D(LMX+0#!'\!@`F0BRW@M`($?P&Q@I`%(G3_\!)#YY"+".3PY2XP +MX2^0`39T`O!#54`1A)"+-^"T`0F0!2+D\)"+-_"0BRS@,.`-Y/\23>#O8`60 +M!2+D\.4N,.(6D`$V=`3PD(LLX##@!J/@9`9@`Q)&L^4N,.,XD`$V=`CPY2%D +M`7`LY21@*)`!5^3PD`$\=`+PD(L]Y/"0BQ'@D(L^\.3[_7]4?@$22VR0`5=T +M!?#E+C#D*Y`!-G00\.4AM`$@Y21@')`!5^3PD`$\=`+PD(L;Y/!3)?WE)50' +M<`,22OSE+C#E'Y`!-G0@\.4AM`$4Y21@$)"+&N!D`F`%$DJ7@`,224GE+C#F +M&Y`!-G1`\.4AM`$0Y21@#%,E_N4E5`=P`Q)*_.4O,.$HD`$W=`+PD(LLX##@ +M&.3_$DW@[V`($DC^$GW!@`N0BS%T`?"``Q)(_G3R!)`!Q/!T8*/PT`?0!M`% +MT`30`]`"T`'0`-#0T(+0@]#PT.`RY)"+/?"0!5C@_Y"+..`O)/Z0BS[PY/O] +M?U!^`1)+;)`!4W0%\"*0BRS@_\03$U0#,.`*H^!D!F`$?P:Q@I"++>!D!F`# +M$G@U(M,0KP'#P-"0BRW@_F]P`N%.[Q)#E&6P`&7J`68P`F9J`V:B!&;;!6<6 +M!@``9T[NM`0&?P'Q@>%.D(LMX/^T!03Q7>%.[[0&!G\!\7*`%I"++>"T`P9_ +M`?%3@`F0BRW@M`("\6?QI.%.D(LMX+0$!G\!\8&`"9"++>"T!0+Q79"++>!P +M!/&:X4Z0BRW@_K0&!G\!\7+A3NZT`P9_`?%3X4Z0BRW@9`)@`N%.\6?A3I"+ +M+>"T!`9_`?&!@`F0BRW@M`4"\5V0BRW@<`3QFH`6D(LMX/ZT!@9_`?%R@`CN +MM`,$?P'Q4_'0X4Z0BRW@M`0&?P'Q@8`)D(LMX+0%`O%=D(LMX'`$\9J`%)"+ +M+>#^M`8&Y/_Q#^M`8&Y/_Q"T`@+Q9Y"++>"T`03QI(`)D(LMX+0%`O%=\:^`#^M`8&Y/_Q +M"T`@+Q9Y"++>"T`03QI(`+D(LMX+0$!'\!\8'Q +MPX`XD(LMX+0$!G\!\8&`"9"++>"T!0+Q79"++>!P!/&:@!:0BRW@M`,&Y/_Q +M4X`)D(LMX+0"`O%G\=W0T)*O(A)*LI"++70!\"*0!2+D\)"++?`BD`4BY/"0 +MBRT$\"+O8`60!2+D\)"++70!\"*0BU;O\!)]0I"+5N!@!9`%(N3PY)"++?`B +M$DK,D(LM=`'P(G\!$DI\Y)"++?`B$GQ*D(LM=`3P(A)*,I"++70#\"*0!2)T +M__"0BRUT!?`BD`4B=/_PD(LM=`+P(I`%(G1O\)"++70&\"+3$*\!P\#0Y/W\ +M[S#@`GV`[\,3D/T0\*X$KP70T)*O(G4H,^3U*74J!_4KD`$PY2CPH^4I\*/E +M*O"CY2OP(G4P'W4Q`4,Q$.3U,I`!..4P\*/E,?"CY3+P(B*0``+@5.!_`6`" +M?P`BD`#SX'\`,.,"?P$BD(L)X+0!#)``\N`PYP5^_7\S(G[]?R\BD`#SX##B +M#9`%0700\)`%6O"CY/`BD`%D=*#P(L#@P(/`@L#0==``P`7`!L`'?9&0`<3M +M\'1H_Z/P4Y'OD`!1X/Z0`%7@7O4]D`!2X/Z0`%;@7O4^Y3TPY`:0`%5T$/#E +M/3#E!I``570@\.4],.8&D`!5=$#PY3TPYP:0`%5T@/#E/C#@!I``5G0!\.4^ +M,.$&D`!6=`+PY3XPX@:0`%9T!/#E/C#C!I``5G0(\)`!Q.WPH^_PT`?0!M`% +MT-#0@M"#T.`R[\.4(%`Y[S#@%^W$5/#][\,3_B2D]8+D-`3U@^!4#X`0[\,3 +M_B2D]8+D-`3U@^!4\/!TI"[U@N0T!/6#X$WP(JT'=(0M]8+D-`3U@^!4?Y"* +MWO#@^50?H_!U\`GMD(`DX?6"Y#2&]8/J\*/K\.[#GT`"0;F0BM_@_W2E+?6"Y#2*]8/O +M\.\$D(K@\)"*X>#_D(K@X/[3GT`"0?/NPY000"'N)/#_=`%^`*@'"(`%PS/. +M,\[8^?^0BN+@7OZCX%].<">0BN#@_\.4$%!9=`%^`*@'"(`%PS/.,\[8^?^0 +MBN3@7OZCX%].8#R0BN#@M!$-D(KCX##G!I"*X'07\)"*X.#_9!-@!.^T$@V0 +MBN+@,.`&D(K@=!CPD(K@X)"*W_"0BM[P@$*0BN#@!/!!%Y"*X>#\D(K?X/]L +M<'%TI2WU@N0TBO6#[_!U\`GMD(D(KAX/]TI2WU@N0T +MBO6#[_"0BM_O\)"*WO#\H^#_)>`D9O6"Y#1!]8/DD_IT`9/[[R7@)"[U@N0T +M0?6#=`&3*__DDSK#$_[O$__M)>`DX?6"Y#2&]8/N\*/O\*\$(G0!+?6"Y#2& +M]8/D\*\%D(K>X$2`_1)<3I"*WN!$@/\BY)"*S_"0BL_@_\.4($`#`G)4=?`) +M[Y"'*A)#7^!D`6`#`G)+D(K/X"7@),#U@N0TA?6#X/RCX-.4`.R4`%`#`G)+ +M[W7P"J0D`/ETA#7P=1(!]1.)%)"*S^`EX"3`]8+D-(7U@^#]H^"0BM3-\*/M +M\.\EX"1C]8+D-(CU@^#_H^"0BM;/\*/O\)"*S^#^)(3U@N0T!/6#X%0_D(K0 +M\.#]5!^C\'7P">Z0AR<20U_@D(K9\)"*S^#[)&3U@N0TBO6#X,.4!4`"P9R0 +MBMG@_I"*T>">0!.0BMG@D(K1\.U40/V0BM#P[DWPD(K1X/^001*3_G0C*_6" +MY#2)]8/@PYY`!N^00-J`!Y"*T>"00/:3D(K8\)"*V.!U\`:D)%#Y=$`U\'4/ +M__40B1&0BM#@D$&ZD__3D(K7X)^0BM;@E`!`#9"*S^#_Y/T274$"<>&0BL_@ +M)>`DX?6"Y#2&]8/@_Z/@D(K2S_"C[_"K#ZH0J1$2*=G_?@"K$JH3J1020I?] +MK/`2*?*0BM+NC_`20H&K#ZH0J1&0``$20B#_?@"K$JH3J120``(20L+]K/`2 +M*?*0BM+NC_`20H&K#ZH0J1&0``(20B#_?@"K$JH3J120``020L+]K/`2*?*0 +MBM+NC_`20H&K#ZH0J1&0``,20B#_?@"K$JH3J120``820L+]K/`2*?*0BM+N +MC_`20H&K#ZH0J1&0``020B#_?@"K$JH3J120``@20L+]K/`2*?*0BM+NC_`2 +M0H&K#ZH0J1&0``420B#_?@"0BM3@_*/@_1(I\M.0BM/@GY"*TN">0`RCX)_P +MD(K2X)[P@`?DD(K2\*/PD(K2X/RCX/V0BL_@_R7@).'U@N0TAO6#[/"C[?"0 +MBM#@)>`D+O6"Y#1!]8/DD_IT`9/[T^V;[)I`!3%X`G&OD(K0X"7@)&;U@N0T +M0?6#Y)/^=`&3_\.0BM/@GY"*TN">0`,"<:^0BL_@_WT!$EU!`G&OD(K/X/\D +M9/6"Y#2*]8/@_&0%8`,"<'V0AR+@_K0#"Y"*T>##E!E`/8`N[K0""Y"*T>## +ME!%`+H`?D(##E`-`#9")0W0!\(`% +MY)")0_"0BL_@_B1#]8+D-(CU@^"0BMWP=",N]8+D-(GU@^#^PY0P4`ODD(K= +M\'1D+P)P*)")0^!D`6`#`G`=D(K/X"1$]8+D-(GU@^!D"F!;D(K/X/_N)`7[ +MY#/Z="$O]8+D-(;U@^#_TYOJ9(#X=("84#B0BL_@_N\D!?OD,_IT(R[U@N0T +MB?6#X-.;ZF2`^'2`F%`6D(K/X"2$]8+D-(KU@^#_D(K1X&]@5I"*S^`D(_6" +MY#2)]8/@_].40D`(D(K==`7P@!'OTY0YD(K=0`5T`_"``W0!\)"*S^#_)"/U +M@N0TB?6#X/YT(2_U@N0TAO6#[O"0BL_@)$3U@N0TB8`OD(K/X/\D9/6"Y#2* +M]8/D\'1$+_6"Y#2)]8/@!/"`%.20BMWPD(K/X"1D]8+D-(KU@^3PD(K1X/Z0 +MBL_@_R2$]8+D-(KU@^[PD(K=X/YT0R_U@N0TB/6#[O!U\`GOD(20BMWP=&0O]8+D-(KU@^3PD(K=X/TAK.QD!F`"(:^0BM+PH_"00=N3_WX` +MD(K4X/RCX/T2*?*0BMON\*/O\)"*S^`D0_6"Y#2(]8/@D(K=\.20BMKPD(K: +MX/_3E`101ZL2JA.I%'7P`N^D]8*%\(,20L+]K/#OD$'6D_]^`!(I\I"*TNZ/ +M\!)"@9"*V^#^H^#_TY"*T^"?D(K2X)Y0")"*VN`$\("OD(K:X,,3\)"*W>#_ +MM`$-D(K:X'!=D(K=!/"`6^^T`QV0BMK@_W`(D(K==`/P@$COM`$(D(K==`'P +M@#R`-9"*W>!D!7`RD(K:X/]P")"*W70%\(`/[Y"*W;0!!70#\(`#=`'PTY"* +MU^"4`Y"*UN"4`$`%Y)"*W?#3D(K7X)0#D(K6X)0`0`7DD(K=\)"*W>#]D(K/ +MX/\D0_6"Y#2(]8/M\!)I.)"*S^#_)&3U@N0TBO6#X-.4!5`/=&0O]8+D-(KU +M@^`$\(`/D(K/X"1D]8+D-(KU@^3PJQ*J$ZD4Y/7P$D+ZJQ*J$ZD4D``"Y/7P +M$D,9D``$Y/7P$D,9D``&Y/7P$D,9D``(Y/7P$D,9D(K/X/\EX"3`]8+D-(7U +M@^3PH_#O)>`D8_6"Y#2(]8/D\*/P[R7@)*/U@N0TB/6#Y/"C\)"*S^`$\`)K +MPB+DD(K/\)"*S^#_PY004!1TI"_U@N0T!/6#Y/"0BL_@!/"`XN20BL_PD(K/ +MX/_#E"!``H$.=?`*[Y"$`!)#7^3PH_!U\`KOD(0"$D-?Y/"C\'7P"N^0A`02 +M0U_D\*/P=?`*[Y"$!A)#7^3PH_!U\`KOD(0($D-?Y/"C\'2$+_6"Y#2*]8-T +M$_!T1"_U@N0TB?6#Y/!T0R_U@N0TB/6#Y/#O)>`DP/6"Y#2%]8/D\*/P[R7@ +M)&/U@N0TB/6#Y/"C\.\EX"3C]8+D-(CU@^3PH_#O)>`DH_6"Y#2(]8/D\*/P +M[R7@)&3U@N0TB?6#Y/"C\.\EX"2D]8+D-(GU@^3PH_!T1"_U@N0TBO6#Y/!T +M)"_U@N0TBO6#Y/!T9"_U@N0TBO6#Y/"008R3_G0!D_^0051T`9,O_^23/L,3 +M_N\3_Y"*S^#])>`DX?6"Y#2&]8/N\*/O\'7P">V0ARD20U]T`?!TP2WU@N0T +MAO6#=`SP=?`)[9"')1)#7W3_\*/P=?`)[9"'(Q)#7^3PHW0/\'7P">V0AR<2 +M0U]T$_!U\`GMD(TND(KW\)```1)"(/_M+Y"*^/"0``(20B#_[2^0BOGP +MD``#$D(@_^TOD(KZ\)``!!)"(/^N!>TOD(K[\"+3$*\!P\#0D(K:$D.+Y)"* +MW?`2*=G#$R#@`L'MD(K:$D-K$BG9_U0"_I"+,N!4_4[^\.]4`?_N5/Y/__`2 +M*=G^5`C][U3W3?^0BS+P[E00_N]4[T[_\!(IV?Y4(/WO5-]-_Y"+,O#N5$#^ +M[U2_3O`@X`+!V9"*W70A\)"*VA)#:Q(IV?\3$U0!_I"+,N#]$Q-4`6Y@*N]4 +M!/_M5/M/\.`3$U0_,.`.D`$T=$#P_>3_$C;F@`ODD(LT\'U`_Q(V=9"+,N#] +M$Q,35!\PX`>0BMW@1!+P[<14#S#@!Y"*W>!$%/"0BS+@Q!-4!S#@!Y"*W>!$ +M@/"0BS+@Q!,35`,@X`>0BMW@1$#PD(K=X)`%)_"0BS/@<`5_`1).B9"+,N#$ +M$Q-4`S#@!'\#@`Y_`1)-X.]@!'\!@`)_`A).B7\"`G@ND(K==`'PD`4G\.3_ +M$DZ)?P,">"Z0BMH20VL2*=G_5`+^D(LLX%3]3O[P[U0!_^Y4_D__\!(IV?Y4 +M"/WO5/=-_Y"++/#N5!#^[U3O3O_P$BG9_E1`_>]4OTW_D(LL\.Y4!/[O5/M. +M\"#@`N'BD(K==#'PD(LLX!,35#\@X`ODD(LN\'U`_Q(V=9"++.#]$Q,35!\P +MX`>0BMW@1`+P[<14#S#@!Y"*W>!$!/"0BMW@5`9@#)`!/G0#\/U_`A(W`)"* +MW>"0!2?PD(LLX/_$$Q-4`S#@#:/@9`9@+'\&$F6"@"60BRW@M`8;?P$298+D +M_Q)-X.]@"7T!KR,21:*`!1).5H`#$GW!?P&`3)"*W70!\)`%)_!]`W\"$C:2 +MD(LMX+0&`H`;D(LMX+0$`H`'D(LMX+0%!.3_@!20BRW@M`,$?P&`"9"++>"T +M`@5_`1)E@A$U$DK\?P,10M#0DJ\BD(LQX+0!!>3P$DC^(JT'[V0!8`3OM`,5 +MD(LRX%3^\%3[\.2C\*/PH_"C\*/P[60"8`3MM`,5D(LLX%3^\%3[\.2C\*/P +MH_"C\*/P(A(IV9"+./`BTQ"O`"0BNCPD(K^X/^CX)"*Z<_PH^_P +MY)"*Y/"0BN3@_R0`]8+D-(OU@^#^=.LO]8+D-(KU@^[PD(KDX`3PX+0$VI"* +MZ.`20Y1X^`!Z:P%Y`0)Y`0-Y`01Z:P5Z-8!Z3H%Z:X(``'IGD(KNX/]1.20BN3P +MD(KEX/^0BN3@PY]``D%KD(KIX/ZCX/_#[I0!D(KDX%`?_B__[OW#=`.=_>24 +M`/QTZRWU@G2*//6#X/T248B`*__]PW0#G?WDE`#\=.LM]8)TBCSU@^#^[_V0 +MBNK@+?V0BNG@-`"-@O6#[O"0BN3@!/"`C<.0BNG@E!!``D%KD(KHX&0$8`)! +M:Y"*[.#_Y/S]_G@0$BILP`3`!<`&P`>0BNO@_^3\_?YX&!(J;-`#T`+0`=`` +M$D-&P`3`!<`&P`>0BNW@_^3\_?YX"!(J;-`#T`+0`=``$D-&J`2I!:H&JP>C +MX/_D_/W^$D-&HQ(J?Y"*[Q)#4Y"`A1(J?Y"*Z>#^H^#_$B_9@#:0BNW@_J/@ +M)`#_Y#[^D(KF\*/O\!(W5(`=D(KMX/ZCX"0`_^0^_I"*YO"C[_`2-LN`!'\` +M@`)_`=#0DJ\BCP_DD(KS\.4/%/Z0BO/@_\.>4`[O!/T2-+>0BO/@!/"`Y>4/ +M%/]]_Q(TMY"*\^4/\)"*\^##E/]0#^#_!/T2-+>0BO/@!/"`Z*T/?_\"-+?3 +M$*\!P\#0Y)"*W?"C=`3PH^3PD(KB\*/PD`()X)"*X?`2*=G_D(KAX"^0BN#P +M,.`+D(K;Y/"C=(#P@`?DD(K;\*/PD(K@X,,3D/T0\)"*W>`D(/"0BMNCX/VC +MX/PM_R0!]8+D-/SU@^"0BOWP=`(O]8+D-/SU@^#^["TD`_6"Y#3\]8/@)`#_ +MY#Z0BO[PH^_PD(K:=`3PD(K;H^#_H^`O_Y"*VN#^+R0`]8+D-/SU@^#_=/PN +M]8+D-(KU@^_PD(K:X`3PX+0(SQ&)[W!%D`'#X&`KPY"*X^"4Z)"*XN"4`T`) +MD`'&X$00\(!YD(KBY'7P`1)"@7\*?@`2-U2`SY`!QN"0`<,PX@5T_O"`5W3_ +M\(!2D(K=X+1X+N3PD(K@X`3PD(K;X'`$H^!D@)"*VW`%\*/P@`;D\*-T@/"0 +MBN#@PQ.0_1#P@`>0BMW@)`CPD(K>=/_U\!)"@9"*WN!P`J/@8`)A%M#0DJ\B +M$BG9D(L%\)```1)"()"+!O`BY/5A(I%*D(LS=`+P(I`%(G3_\']X?@@2)]Z0 +MBQP2*G]_!'X,$B?>D(L@$BI_?P!^"!(GWI"+)!(J?Y"+">"0BQRT`0T20U/O +M5,?_[53'_8`'$D-3[U3'_^R0@(42*G]_>'X($B_9D(L@$D-3[U0/_^R0@(42 +M*G]_!'X,$B_9D(LD$D-3[T0"_^R0@(42*G]_`'X($B_9?W!^#A(GWI"+*!(J +M?Y"`A1(JBP`;):!_<'X.$B_9D(!9$BJ+`````.3]_Q(T@9"+">"T`1&0@%D2 +M*HL`````Y/U_`1(T@9``$>!4]O`"4@Z14)"+,W0"\"*0!2)T__"0BS-T!/`B +ML4*0BS-T!/`BD``1X$0)\!)2#I"+'!)#4Y"`A1(J?W]X?@@2+]F0BR`20U.0 +M@(42*G]_!'X,$B_9D(LD$D-3D("%$BI_?P!^"!(OV9"+*!)#4Y"`A1(J?W]P +M?@X2+]F0@%D2*HL``RV5Y/W_$C2!D(L)X+0!$9"`61(JBP`#+97D_7\!$C2! +M(I"++>!D!F`\Y2)4#Q1@+A1@'B3^8`XD^'`JY)"++?"0!2+P(I"++70!\)`% +M(N3P(I"++70#\)`%(G3_\"*0`<;@1`CP(JX'Y/\23>#O8!B0BRS@Q!,35`,@ +MX`RO!GT!$D6BL<%_`2)_`"*0`5?@8#R0`5?D\)`!/'0"\)"+&^!@!^3P4R7] +M@"20BPS@!/!3)>^0BQ#@_Y"+#.#3GT`.Y2&T`0F0BPW@<`/@!/"0`5O@8!"0 +M`5OD\)`!/'0$\.20BQCPD`%?X&`0D`%?Y/"0`3QT"/#DD(L7\"+DD(M/\*/P +MD`7XX'`/H^!P"Z/@<`>CX'`#?P$BTY"+4."4Z)"+3^"4`T`#?P`B?S)^`!(W +05)"+3^1U\`$20H&`Q@"2```` +` +end diff --git a/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu index d542b2ea3fff..90cd7dc442f3 100644 --- a/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu +++ b/sys/contrib/dev/rtwn/rtwn-rtl8192cfwU.fw.uu @@ -1,17 +1,17 @@ -begin 444 rtwn-rtl8192cfwU.fw.uu -MP8@"`$@````%$!!3PCD!`(%C`0`````````````````"0[H````````````` -M`````````E!$```````````````````````````````````````````````` -M`````````````E;@```````"2VH```4$`P(``P8%!`,`!`8%!`(`!`@'!@0` +begin 644 rtwn-rtl8192cfwU.fw.uu +MP8@"!5@``@`2!1<1WCX!`)08`@`````````````````"1C`````````````` +M`````````F#R```````````````````````````````````````````````` +M`````````````FB1```````"2X<```4$`P(``P8%!`,`!`8%!`(`!`@'!@0` M!@H)"`8`"`H)"`0`"`H)"`(`"`H)"```"!(1$`@`$!H9&!``&"(A(!@`("(A M(!``("(A(`@`("(A'`@`("(A%`@`("(@&`@`(#$P(!``,#$P&```,#$O$!`` -M,#$L$!``,#$H$```,#$@$```,#$0$```,`0$!`4$!`0%!04&!@0$!`4%!08& -M!`0%!04%!@8$!`4%!04&!PH+#1`$!04&!@D,$0@("0D*#!`1!`0$!00$!0<' -M!P@*!`0$!`8*"PT%!0<'"`L-#P0$!`4'!PD)#`X0$@0$!04&"A$3"0D)"0P. -M$1,````````````D)BH8&AT?(2`"@`,@!0`&0`>`",`$L`4`!X`+0`^@$L`9`!]```@`" -M``0`"``,`!(`&``D`#``2`!@`&P`*``\`%``9`"@`,@`\`$8`&0`H`#P`6@! -M]`)8`R`#Z`("`@("`@,#!`0%!P0$!PH*#`P2!0<'"`L2)#P!`0$!`0(#!`4& -M!P@!`@,$!08'"`4&!P@)"@L,(!X<&!`8````````````````NP$,Y8(I]8+E +M,#$L$!``,#$H$```,#$@$```,#$0$```,`0$!`4$!`4'!P<("@0$!`0&"@L- +M!04'!P@+#0\$!`0%!P<)"0P.$!(&!PD*#`X1$PD)"0D,#A$3```````````` +M)"8J&!H='R$G*2H````?(R@J+``$``0`"``0`!@`)``P`$@`8`"0`,``V`!0 +M`'@`H`#(`4`!D`'@`C`!+`%``>`"T`/H!+`&0`?0``(``@`$``@`#``2`!@` +M)``P`$@`8`!L`"@`/`!0`&0`H`#(`/`!&`!D`*``\`%H`?0"6`,@`^@"`@(" +M`@(#`P0$!0<"`P0*#`X0$@4'!P@+$B0\`0$!`0$"`P0%!@<(`0(#!`4&!P@% +M!@<("0H+#"`>'!@0&``````````````````````````````````````````` +M````````````````````````````````````````````````NP$,Y8(I]8+E M@SKU@^`B4`;I)8+XYB*[_@;I)8+XXB+E@BGU@N6#.O6#Y),BNP$&B8**@_`B M4`+W(KO^`?,B^+L!#>6"*?6"Y8,Z]8/H\")0!NDE@LCV(KO^!>DE@LCR(L7P M^*/@*/#%\/CE@A6"<`(5@^`X\"*[`0J)@HJ#X/7PH^`B4`:'\`GG&2*[_@?C @@ -20,314 +20,343 @@ M".8BN_X*Z26"^.+U\`CB(N6#*O6#Z9/U\*/IDR*[`0J)@HJ#\.7PH_`B4`;W M":?P&2*[_@;SY?`)\QDB^+L!$>6"*?6"Y8,Z]8/H\.7PH_`B4`GI)8+(]@BF M\"*[_@GI)8+(\N7P"/(B[TO_[DK^[4G][$C\(N#\H^#]H^#^H^#_(J0E@O6" MY?`U@_6#(N#[H^#ZH^#Y(OC@^Z.CX/DE\/#E@A6"<`(5@^#Z./`BZ_"CZO"C -MZ?`BT(/0@OCDDW`2=`&3<`VCHY/X=`&3]8*(@^1S=`*3:&#OHZ.C@-\"0_@" -M2"_DDZ/XY).C0`/V@`'R"-_T@"GDDZ/X5`1^`9-@O*/_5#\PY0E4'_[DDZ-@`0[/5,`EX&"H -M0+CDDZ/ZY).C^.23H\C%@LC*Q8/*\*/(Q8+(RL6#RM_IWN>`OD&7?P!!EZ$` -M09=K@$&7HP``CX*.@Z.CH^3P(N3U(W]@?@&`[=,0KP'#P-"0EUUQBY"777%K -MD``!4<+ZY?`D`/_D.OZ0EUUQ:Y```>Z/\'$9$B1B_V`HM2,4D)==<6N0``%1 -MPF4E<`3E)&7P8!^0EUUQ:Y```5'"_Z[PL5.`#I"777%K$B1B92-@`I%8T-"2 -MKR+T_Y``0^!?\-,0KP'#P-!_$-_^T-"2KR*0`=,0KP'#P-"+8(IAB6*0EXAQBZMCJF2I99"7BW&+ -MKV859N]@&Y"7B^1U\`%Q=!(D8O^0EXCD=?`!<73O44V`WJM@JF&I8M#0DJ\B -MD)=@[O"C[_!U(P&.)/4EY/U_"[&6Y/U_`K&6$FU;Y/^1YN3U)Y`!R>4G\)"7 -M8.#\H^#][/N-1.3U17T!?V!^`0(P8M,0KP'#P-"0EV/M\)"78N_PTY0'4$ZC -MX'`:D)=BX/]T`:@'"(`"PS/8_/3_D`!'X%_P@!>0EV+@_W0!J`<(@`+#,]C\ -M_Y``1^!/\)'6D)=BX/]T`:@'"(`"PS/8_/3_D`!&@%F0EV+@)/CPH^!P'9"7 -M8N#_=`&H!PB``L,SV/S$5/#T_Y``0^!?\(`:D)=BX/]T`:@'"(`"PS/8_,14 -M\/^0`$/@3_"1UI"78N#_=`&H!PB``L,SV/ST_Y``0^!?\)'6T-"2KR+@_WT! -MD)>4[_"C[?#DH_"C\.5J8`7D_Q).>9"7E.`PX`F0EY;D\*-T@/"0!!W@8!V0 -M!2+@D)>8\.#_5)!@[)`!R'3\\.]4;Y`%(O"`W9"7E.#_PQ.0_1#PD`0E[_"0 -MEY7@8!^CH^#_)`_U@N0T_/6#X$2`\'00+_6"Y#3\]8/@1(#PD)>6H^#__20( -M]8+D-/SU@^3P=`DM]8+D-/SU@^!4\/!T(2_U@N0T_/6#X%3W\)"7EN#^H^#_ -M(O"0`$7@5/[]?T73$*\!P\#0CX)U@P#M\)'6T-"2KR+O%&`P%&!E)`)@`N': -MD)!$$/U_18!OY)"7./"0 -MES1Q4Y"`EA(E"'^`?@@2*PB0`$7@1._]?T7Q()``1>!4[_U_1?$@D`!&X$00 -M_7]&@#>0ESAT`?"0ESYQ4Y"`EA(E"'^`?@@2*PB0`$7@1"#]?T7Q()``1>!$ -M$/U_1?$@D`!&X$00_7]&\2`BD`!)X)"7I/#@5`_P1/#]?TGQ()"7I.!$L/U_ -M2>$@=2@SY/4I=2H"]2N0`3#E*/"CY2GPH^4J\*/E*_`B=3`?=3$!Y/4RD`$X -MY3#PH^4Q\*/E,O`BY)"73_"C\'6.`A)LK9```N!4X)"7AF`%=`'P@`-T`O"0 -M`//@,.,(D)>'=`'P@`7DD)>'\)"7A^"T`1.0`/+@,.<,D)=]=/WPHW0S\(`* -MD)=]=/WPHW0O\.3U5Q)JZQ)O\A)?K!(N`1)M5Q)'^9``\^`PX@V0!4%T$/"0 -M!5KPH^3PD`%D=*#P=43_Y/5%^WT!?U!^`1(P8A$7$D4"$G=(D)=1Y=GP$E`5 -MPJ^0`(#@1$#P$D36=>@#0ZB%TJ^0ET_@9`'P)"^0`<3P=$BC\.57,.0*PJ]3 -M5^_2KQ)7@.57,.86PJ]35[_2KQ)A9)"7/.#_8`.T`0(Q8)"7/.!P`Q)WIC$S -M@+B0!C3@8"8435_^7X!$FSUOP$)D`8UX%0/\(`%@``";)[DD`8T -M\"*0ES/@PY044`7@!/!!&)"7,^!D%&`"01B0ET+@<"60ET7@0!/W@5/[PD)="X)`$1/"0ET/@D`1%\)"71."0 -M!$;PH^3PD)=%X)`$2/"0ET;@D`1)\)"71^"0!$KPH^3PD)#^TY]0"Y"72^##GM.4`4`0D)"0ETGPD`5BX)"72O"0!6/@D)=+\,-T_Y_^D)=)X-.>0![@+_"CX+3_#^3P -MH^"T_P/D\"*0ETN``Y"72N`$\"*0ETG@+_`BD)#_46*0ETQT`1)'%H!`D)=,X&0!<#B0ESW@_U%BY)"73/"0`$7@1`']?T42 -M1R"0ES+@8!60ES020U.0@)82)0A_@'X($BL(@`60!2+D\)`%A^!D@/"0ETC@ -MD`6$\)"72>"0!87PD)=*X)`%AO"0ETO@D`6'\"+`X,#PP(/`@L#0==``P`#` -M`<`"P`/`!,`%P`;`!Y`!Q'1J\'1+H_!3D=^0`3S@53#U-*/@53'U-:/@53+U -M-J/@53/U-^4T,.`&D`$\=`'PY30PX0B0`3QT`O#QJ^4T,.(RD`$\=`3PD`:2 -MX##@'G5$%'5%`.3[_7]8?@$2,&*0`5MT!?"0!I)T`?"`!Y"7=N3PD8KE-##C -M,I`!/'0(\)`&DN`PX1YU1!1U10#D^_U_7'X!$C!BD`%?=`7PD`:2=`+P@`>0 -MEW7D\)&*Y30PY`F0`3QT$/`2;7?E-##E")`!/'0@\%&TY34PX!"0`3UT`?"0 -M`(/@D)=Y\)&*=&H$D`'$\'1+H_#0!]`&T`70!-`#T`+0`=``T-#0@M"#T/#0 -MX#*0EWG@_WT!@`1]`7\,CV>-:.5G5`__D)=WX%0/;V!QY6]@*[%.D)=WX%0/_[\$#>5G(.(($E8Q[V`4T920EW?@5`__ -MOP(($F`)[V`"T>!4O_`BD`8$X$1`\.5IM`$$?P'Q2)"7=^!4\/#@1`3P -M(N]D`7`N?7U_`A(Q+'T"?P,2,2R0`5?D\)`!/'0"\)&3Y/_1>9`&!.!4?_"0 -M!@K@5/CP(I`!-G1]\*-T`O!]??\2,9U]`G\#$C&=D`8$X$2`\)`&"N!$!_"0 -MEW+@H^"0!5CPY6DPX!J0EV_@%&`O)`-P0'\!@#JK$:H2J1.0 -M``(20B#]Y/_14X`GJQ&J$JD3D``"$D(@_7\!T5,?@!.K$:H2J1.0``(20B#] -M?P+14^3_L6HB[R3^8`L$V0EWAP!70%\(`"[?"0EWC@D)=M -M\"+O8`N0EX?@M`$0Y/^`"9"7A^"T`05_`1)O^R*0`3=T`O"0!2)T__`2;E_O -M<`:0`BX&`%D`4BY/"0EW?@ -M5/#PX$0$\"*0!@3@5+_P[V`)Y6FT`03D__%(D)=WX%3P\.!$#/`B$E/\OP$: -MD)=VX'`4D)=UX'`.D)=YX%0/TY0$4`-_`2)_`"*/:Y"7@A)&7>5K8!!T(2_U -M@N0T_/6#X$00\(`.="$O]8+D-/SU@^!4[_"0!!]T`?`B?0)_`Q(Q+.5J%"3] -M4`*`(9"7>N!@!GT!?PR`#Y"7=^!4#\.4!%`&?0%_!)&7Y/_1>2*0EWO@8`[D -M\*/@5/WPX%0'<">`(Y"7;N`$\)"7?.!4[_"0EV[@TY0!0`WE:;0!"J/@<`;@ -M!/`BD8HBD`$PY/"C\*/PH_"0`3CPH_"C\*/P_7]0$D<@Y/U_41)'(.3]?U(2 -M1R#D_7]3`D<@D`$\=/_PH_"C\)`!-/"C\*/PH_#]?U021R!]_W]5$D<@??]_ -M5A)'('W_?U<"1R#`X,#PP(/`@L#0==``P`#``<`"P`/`!,`%P`;`!Y`!Q'1$ -M\'10H_"0`33@52CU+)`!-N!5*O4NH^!5*_4OY2P@X`(AVY`!-'0!\(713872 -M3H733X744(7548764H774X795.545$##$__E4U0@;W`"(9+E5##E`B&2Y5)4 -M'_4(Y4U4/_4)Y5%4'__E""7@)./U@N0TE/6#Y(_P$D*!Y5-4'__E""7@),#U -M@N0TD?6#Y(_P$D*!Y0G3E`1``W4)!'7P"N4(D)``$D-?=?`"Y0D20U_@_J/@ -M_^535!\O_^0^_G7P"N4(D)``$D-?=?`"Y0D20U_N\*/O\.54(.8CY5-4'__E -M""7@)&/U@N0TE/6#Y(_P$D*!Y4\PYS2O"+'#@"[E4U0?_^4()>`DH_6"Y#24 -M]8/DC_`20H'E3S#G$>5/5'_]Y5-4'_4-JPFO")&PY6H4)/U0`H!`D)=ZX&`R -MD`%;Y/"0`3QT!/!Q_.]D`7`H=404]47[_7]8?@$2,&*0`5MT!?"0!I)T`?"0 -MEW;P@`AQ_+\!`Q),BN4L,.$FD`$T=`+PD/T0='_PA=%8A=)9A=-:A=1;A=5< -MA=9=A==>A=E?D0OE+##C!I`!-'0(\.4L,.0)D`$T=!#P0U<0Y2PPY2:0`<_@ -M,.4?X%3?\)`!-'0@\'6H`'7H`!)/Y9```^!4^_`21-:`_N4L,.8&D`$T=$#P -MY2XPX3R0`39T`O!#5T"0`0+@5`-D`7`ID`$WX##@"G0!\)"7?^3P@!B0EW_@ -M!/#@PY0*0`SD\)`$&>`PX`,21/+E+C#@")`!-G0!\-%EY2XPXG&0`39T!/#E -M:60!<&7E:F!AY6ID`F`&Y6ID!7`GD`:KX)"7;?"0!JK@D)=X\)"7;>!P!Y"7 -M>.#_@`60EVW@_Y"7;>_PD)=OX&`#X!3PD)=NY/"0`5?PD`$\=`+PD)=\X%3] -M\.!4[_#E:A0D_5`"@`*Q$.4N,.,QD`$V=`CPY6ED`7`EY6I@(9`!5^3PD`$\ -M=`+P=40#=44`Y/O]?U1^`1(P8I`!5W0%\.4N,.0OD`$V=!#PY6ED`7`CY6I@ -M'Y`!5^3PD`$\=`+PD)=[Y/"0EWS@5/WPX%0'<`,23(KE+C#E'9`!-G0@\.5I -MM`$2Y6I@#I"7>N!D`F`$L7B``K&)Y2XPYAZ0`39T0/#E:;0!$^5J8`^0EWS@ -M5/[PX%0'<`,23(KE+S#A"9`!-W0"\!)/>71$!)`!Q/!T4*/PT`?0!M`%T`30 -M`]`"T`'0`-#0T(+0@]#PT.`RD`0;X%1_9']_`6`"?P`BD)=-X%3P1`/P5`]$ -M@/![`'H`>5B0EY$20XL+>I=Y3=,0KP'#P-"0EXX20XN0EX;@9`)@;)`!K^!@ -M"9`!Q^`$\/"`\9"7H^#_!/"0EXX20VN0``'O$D)?D)>.$D-KBV.*9(EE=68" -M>P%Z`7F@$D4)D)>1$D-KBV.*9(EED)>.$D-K$B1B_\14#_5F>P%Z`7FB$D4) -MD`&O=/_PD`'+X&2`\-#0DJ\BJ07I5!_U#W0!+_6"Y#22]8/@]0Z0!/W@M`$% -M=1`#@`-U$`'KPY400`*AP^4.)0W^Y0^00=:3_>[3G70!0!0EWS@1`'PD)=ZX&0"8`2Q>(`+L8F`!Y"7?.!4_O#E"I"7?##G -M(.!$`O!U1`/D]47[_7]4?@$2,&*0`5=T!?"0EWMT`?`BX%3]\"*0EX'@_^3] -M$D9AD`0?=`'P(I`!7^3PD`$\=`CP=404Y/5%^_U_7'X!$C!BD`%?=`7PD`:2 -M=`+PD)=U%/"0EW?@5`_#E`Q0`Q),DR*M!W7P">V0DR<20U_@_W2E+?6"Y#26 -M]8/@5!_\TY]``JP'["7@))[U@N0T0?6#Y)/^=`&3_^PEX"1F]8+D-$'U@W0! -MDR__Y),^PQ/^[Q/_[27@).'U@N0TDO6#[O"C[_!TA"WU@N0T!/6#[/#_(G'\ -M[V0!<"J0EWS@5`-P(I"7>>!4#].4`E`7D)=\X"#B$)"7?.`@Y`F0EV_@<`-_ -M`2)_`"+DD)=-\.5J8''E:60!<&OE:A1@*23]8"4D`B3[4`*`(Y"7;>`4\.!@ -M!*/@8!:0EVW@<`J0EWC@D)=M\(``D)=-=`'PD)=-X&`QD)=\X$00\)"7=.#U -M1.3U1?O]?U1^`1(P8I`!5W0%\)"7=^!4#\.4!%`'?0%_!!),ER+`X,#PP(/` -M@L#0==``P`#``<`"P`/`!,`%P`;`!Y`!Q'3@\'16H_!3D>^0`%'@_Y``5>!? -M]3WE/3#F&'1`\)"7.^!4`_^_`PN0ESC@8`5_`1)'->4],.<5D`!5=(#PD)<[ -MX%0#_[\#!7\"$D0EZ'@_W0! -M?@"H!PB`!<,SSC/.V/G_[UUP`P)8O9"7H>!U\`20`=`20U_@D)=3\'5C`75D -MEW5E4W5F`7L!>I=Y5!)%"9"75.#_Q!,3$U0!D)>A,.!9X'7P`I``B!)#7^"0 -MEU7PD)>AX'7P`I``B1)#7^"0EU;PD)>AX'7P!)`!T1)#7^"0EU?PD)>AX'7P -M!)`!TA)#7^"0EUCPD)>AX'7P!)`!TQ)#7^"0EUGP@#/@=?`$D`'1$D-?X)"7 -M5?"0EZ'@=?`$D`'2$D-?X)"75O"0EZ'@=?`$D`'3$D-?X)"75_#O5'__>P%Z -MEWE5$#^=`&H!@B``L,SV/ST7Y"74O"0EZ'@_W0!J`<(@`+# -M,]C\D`',\)"7H>`$\.!4`_`"5XJ0`<;@1`+P`E>*(I"76A)#B^\20Y18]`%8 -M_`)9!`-9#`59%`991@=9'`E9)0Q9+@U9-@X``%D_D)=:$D-KP=B0EUH20VO! -MTI"76A)#:^%DD)=:$D-KX0*0EUH20VN`*Y"76A)#:P)$89"76A)#:P)X?Y"7 -M6A)#:^$QD)=:$D-K`G9PD`'&X$0!\"*0``020B#_5!_^[U0@Q!-4!_VO!I"7 -M7>_PH^WPHQ)#BY"77Q)#:Y```Q)"(%3PQ%0/D)=B\)``!!)"(%1`Q!,35`.0 -MEV/PD)==X/]U\`F0DR420U^M@JR#D)=D[/"C[?#O=?`)I"0C^723-?#Z>P&C -M$D.+D)=?$D-KD``#$D(@5`__D)=F$D-K[Q)"39"77Q)#:Y```A)"(/^0EV82 -M0VN0``'O$D)?D)=?$D-KD``!$D(@_Y"79.#\H^#]]8*,@^_P$B1BC8*,@Z/P -MD)=BX/Z0EUW@_R3!]8+D-)+U@^[PD)=>X/YU\`GOD),I$D-?[O!U\`GOD),J -M$D-?=`'PD)=CX/YU\`GOD),K$D-?[O"/$>\EX"3D]8+D-)6O@O43CQ3E$77P -M`J0D@?ETDC7P=14!]1:)%W7P">41D),E$D-?KX*%@QB/&>41=?`)I"0C^723 -M-?!U&@'U&XD<=,$E$?6"Y#22]8/@$D.46M4`6NH!6O\"6Q0#6ST$6U(%6V<& -M6XT,6[H-6^<.7!0/``!<2.41)>`DY/6"Y#25]8-T\/"C=!6`/.41)>`DY/6" -MY#25]8-T\/"C=!"`)^41)>`DY/6"Y#25]8-T\/"C=`6`$N41)>`DY/6"Y#25 -M]8-T\/"CY/#E$27@)('U@N0TDO6#=`_PHW2/\(%(Y1$EX"3D]8+D-)7U@W0/ -M\*-T]8`GY1$EX"3D]8+D-)7U@W0/\*-T\(`2Y1$EX"3D]8+D-)7U@^3PHW0- -M\.41)>`D@?6"Y#22]8/D\*/P@4B0!$?@JQ6J%JD7$D)-D`1&X*L5JA:I%Y`` -M`1)"7Y`$1>"%%(*%$X/PD`1$@3^0!$O@JQ6J%JD7$D)-D`1*X*L5JA:I%Y`` -M`1)"7Y`$2>"%%(*%$X/PD`1(@%B0!$_@JQ6J%JD7$D)-D`1.X*L5JA:I%Y`` -M`1)"7Y`$3>"%%(*%$X/PD`1,@"N0!%/@JQ6J%JD7$D)-D`12X*L5JA:I%Y`` -M`1)"7Y`$4>"%%(*%$X/PD`10X(44@H43@Z/PJQ6J%JD7P`/``L`!$B1B_ZL: -MJANI'!(D8E_0`=`"T`,20DVK%>47)`'YY#46^L`#P`+``1(D8O^K&JH;J1R0 -M``$20B!?T`'0`M`#$D)-A12"A1.#P(/`@N#_A1F"A1B#X/[O7M""T(/PA12" -MA1.#H\"#P(+@_X49@H48@Z/@_N]>T(+0@_#E$27@)('U@N0TDO6#X/ZCX$Y@ -M.W42"W0!?@"H$@B`!<,SSC/.V/G_Y1$EX"2!]8+D-)+U@^!>_J/@7TY@!N42 -M)!"`7142Y1+#E`!0RH!6Y1$EX"3D]8+D-)7U@^#^H^!.8#UU$@]T`7X`J!(( -M@`7#,\XSSMCY_^41)>`DY/6"Y#25]8/@7OZCX%].8`B0EVGE$O"`$!42Y1+# -ME`!0R(`%Y)"7:?#E$27@).3U@N0TE?6#X/ZCX$Y@.^3U$G0!?@"H$@B`!<,S -MSC/.V/G_Y1$EX"3D]8+D-)7U@^!>_J/@7TY@")"7:N42\(!;!1+E$K00RH!2 -MY1$EX"2!]8+D-)+U@^#^H^!.8#GD]1)T`7X`J!((@`7#,\XSSMCY_^41)>`D -M@?6"Y#22]8/@7OZCX%].8`;E$B00@`H%$N42M`S,@`7DD)=J\)"7:>#_=?`) -MY1&0DR<20U_O\)"7:N#^=?`)Y1&0DR@20U_N\'2$)1'U@N0T!/6#X-.?0!^0 -MEVG@_W2$)1'U@N0TEO6#[_!TA"41]8+D-`3U@^_P=(0E$?6"Y#0$]8/@PYY0 -M'Y"7:N#_=(0E$?6"Y#26]8/O\'2$)1'U@N0T!/6#[_"0EVG@_].4$T`(D),B -M=`/P@"'OTY0+0`B0DR)T`O"`$^_3E`-`")"3(G0!\(`%Y)"3(O"0DR+@D`2Q -M\"(2)&+U:2+3$*\!P\#0D``!$D(@D)=Z\)```Q)"()"7;/`2)&)E:F`#$DWQ -MT-"2KR(2)&+U$<.4(%`5D``"$D(@_W0C)1'U@N0TE?6#[_`BY1&T(`J0``(2 -M0B"0DR'P(I```A)"()"7//#@8`3@]'`AHJ_D,_41PJ^0`$?@5/O]?T<21R!] -M0'\!$C%FY1$D_Y*O(I`"">#]$B1B_J\%[2Z0EX#PD``!$D(@_^TOD)>!\)`` -M`A)"(/_M+Y"7@O"0``,20B#_[2^0EX/PD``$$D(@_ZX%[2^0EX3P(N3U:9"7 -M?/#U:I"7>70,\)"7=_#DD)=Z\)"7=O"0EW7PD)=X!/"0EVWPY)"7>_"0EV_P -MD)=T=`?PY)"7;O"0EW+PHW0"\.20EW'PD)=L\"+DD)=[\)"7;O"0EWSP(N57 -M<#>0EWG@5`_3E`%0+)`"A^!P)I"7AN"T`A"0EWW@_J/@]8*.@^!@"(`/D`&O -MX'`)D)=QX&`#?P$B?P`BD``KX$0!\'_H?@,2,A60``C@1!#]?P@21R"0``G@ -M5/?]?PD21R"0`"C@5/[]?R@21R"0`"#@5/[]?R`21R"0`"7@1$#]?R421R"0 -M``G@5._]?PD"1R"0`"7@5+_]?R421R"0`"#@1`']?R`21R"0`"C@1`']?R@2 -M1R"0`/#@,.'YD``)X$0(_7\)$D<@D``(X%3O_7\($D<@D``KX%3^_7\K$D<@ -M?^A^`P(R%8]LD)>#$D9=Y6Q@$'0A+_6"Y#3\]8/@1!#P@`YT(2_U@N0T_/6# -MX%3O\)`$'W0!\"+OPY0@4#GO,.`7[<14\/WOPQ/^)*3U@N0T!/6#X%0/@!#O -MPQ/^)*3U@N0T!/6#X%3P\'2D+O6"Y#0$]8/@3?`BY/41=?`)Y1&0DRH20U_@ -M9`%@`N%AY1$EX"3`]8+D-)'U@^#^H^#3E`#NE`!0`N%AY1%U\`JD)`#Y=)`U -M\'46`?47B1CE$27@),#U@N0TD?6#X/^CX)"75L_PH^_PY1$EX"1C]8+D-)3U -M@^#_H^"0EUC/\*/O\'2$)1'U@N0T!/6#X%0_D)=2\.#^5!^C\'7P">41D),G -M$D-?X)"76_!T9"41]8+D-);U@^##E`5``H$[D)=;X/^0EU/@GT`3D)=;X)"7 -M4_#N5$#^D)=2\.].\)`$_>!D`7`ID)=3X/^004J3_G0C)1'U@N0TE?6#X,.> -M0`;OD$#:@#"0EU/@D$#V@">0EU/@_Y!!2I/^=",E$?6"Y#25]8/@PYY`!N^0 -M01*`!Y"74^"002Z3D)=:\)"76N!U\`:D)%#Y=$`U\'43__44B160EU+@D$'R -MD__3D)=9X)^0EUC@E`!`">3]KQ$2:5K!^.41)>`DX?6"Y#22]8/@]1FCX/4: -MJQ.J%*D5$B1B_WX`JQ:J%ZD8$D*7_:SP$B1[[R4:]1KN-1GU&:L3JA2I%9`` -M`1)"(/]^`*L6JA>I&)```A)"POVL\!(D>^\E&O4:[C49]1FK$ZH4J160``(2 -M0B#_?@"K%JH7J1B0``020L+]K/`2)'OO)1KU&NXU&?49JQ.J%*D5D``#$D(@ -M_WX`JQ:J%ZD8D``&$D+"_:SP$B1[[R4:]1KN-1GU&:L3JA2I%9``!!)"(/]^ -M`*L6JA>I&)``"!)"POVL\!(D>^\E&O4:[C49]1FK$ZH4J160``420B#_?@"0 -MEU;@_*/@_1(D>]/E&I_E&9Y`#.4:G_4:Y1F>]1F`!>3U&?4:Y1$EX"3A]8+D -M-)+U@^49\*/E&O"0EU+@)>`D9O6"Y#1!]8/#=`&3E1KDDY494`:O$?%MP`DGO6"Y#1!]8/3=`&3E1KDDY494`+!S'T!KQ$2:5K!S'1D)1'U@N0T -MEO6#X/QD!6`"H=:0DR+@_[0#"Y"74^##E!E`/8`N[[0""Y"74^##E!%`+H`? -MD),BX/^T`0N0EU/@PY0*0!N`#.]P$9"74^##E`-`#9"50W0!\(`%Y)"50_!T -M0R41]8+D-)3U@^#U&W0C)1'U@N0TE?6#X/_#E#!0`J&#D)5#X&0!8`*A@W1$ -M)1'U@N0TE?6#X&0*8%'O)`7_Y#/^="$E$?6"Y#22]8/@_=.?[F2`^'2`F%`R -M[20%_^0S_G0C)1'U@N0TE?6#X-.?[F2`^'2`F%`4=(0E$?6"Y#26]8/@_Y"7 -M4^!O8#UT(R41]8+D-)7U@^#_TY1"0`5U&P6`#N_3E#E`!74;`X`#=1L!="$E -M$?6"Y#22]8/O\'1$)1'U@N0TE8`I=&0E$?6"Y#26]8/D\'1$)1'U@N0TE?6# -MX`3P@!#D]1MT9"41]8+D-);U@^3PD)=3X/]TA"41]8+D-);U@^_P=$,E$?6" -MY#24]8/E&_!U\`GE$9"3*Q)#7^"T`1#D]1MT9"41]8+D-);U@^3PK1O!R.QD -M!F`"PI&'7P`N42I/6"A?"#$D+"_:SPY1*00@Z3_WX`$B1[[R4: -M]1KN-1GU&<.0EU7@E1J0EU3@E1E`!P42Y1*T!;WE$L,3]1+E&[0!!N42<$:` -M$^4;M`,5Y1)P!74;`X`YY1*T`05U&P&`+X`JY1NT!2CE$G`%=1L%@`WE$K0! -M!74;`X`#=1L!TY"76>"4`Y"76."4`$`#Y/4;TY"76>"4`Y"76."4`$`#Y/4; -M=$,E$?6"Y#24]8/E&_#]KQ$Q)'1D)1'U@N0TEO6#X-.4!71D4`XE$?6"Y#26 -M]8/@!/"`"R41]8+D-);U@^3PJQ:J%ZD8Y/7P$D+ZJQ:J%ZD8D``"Y/7P$D,9 -MD``$Y/7P$D,9D``&Y/7P$D,9D``(Y/7P$D,9Y1$EX"3`]8+D-)'U@^3PH_#E -M$27@)&/U@N0TE/6#Y/"C\.41)>`DH_6"Y#24]8/D\*/P!1'E$<.4(%`"(6S#E!!`(>PD\/]T`7X`J`<(@`7#,\XSSMCY -M_Y"77>!>_J/@7TYP(^S#E!!0.70!?@"H!`B`!<,SSC/.V/G_D)=?X%[^H^!? -M3F`<[&038`CL9!)@`[P1"9"77>`PX`)\&*T$C1R`-`R`BY"77.#\;7!I=*4I -M]8+D-);U@^WP=?`)Z9"3*1)#7^"T`0SE'"#F!^U$0/4<@`.O'"+M)>`DGO6" -MY#1!]8/DD_YT`9/_[27@)&;U@N0T0?6#=`&3+__DDS[#$_[O$__I)>`DX?6" -MY#22]8/N\*/O\(!;[=.<0%:0EUS@_W2E*?6"Y#26]8/O\*T'CQSM)>`DGO6" -MY#1!]8/DD_YT`9/_[27@)&;U@N0T0?6#=`&3+__DDS[#$_[O$__I)>`DX?6" -MY#22]8/N\*/O\*\<(G0!*?6"Y#22]8/D\.4<1(#_=(0I]8+D-`3U@^_P(JH' -M=(0J]8+D-`3U@^!4?_M4'_F0EU[P=?`)ZI"3*!)#7^"0EV#P=?`)ZI"3)Q)# -M7^"0EV'P_.HEX"3D]8+D-)7U@^#_H^"0EV+/\*/O\.HEX"2!]8+D-)+U@^#_ -MH^"0EV3/\*/O\.G3G$`)D)=AX)"77O#[[7`"09V0EU_M\.LPY@F0EU[@^Z/@ -M%/"0EU_@<`)!G9"77N#_TY0`4`)!G>20EUWP[Q20EUSPD)=@X/F0EUS@_M.9 -M0'+NE!!`)>XD\/]T`7X`J`<(@`7#,\XSSMCY_Y"79.#\H^#][%[^[5].<"N0 -MEUS@_\.4$%`V=`%^`*@'"(`%PS/.,\[8^?^0EV+@_*/@_>Q>_NU?3F`5D)=< -MX/NCX`3PD)=?X/^0EUW@;V`(D)=##GU`,D)=`DX?6"Y#22]8/N\*/O\'2$*O6"Y#0$]8/K\/\BD`1$=!'P -MHW3P\*-T#_"CY/#]=*0M]8+D-`3U@^3P#;T0\.3]=?`*[9"0`!)#7^3PH_!U -M\`KMD)`"$D-?Y/"C\'7P"NV0D`020U_D\*/P=?`*[9"0!A)#7^3PH_!U\`KM -MD)`($D-?Y/"C\'2$+?6"Y#26]8-T$_!T1"WU@N0TE?6#Y/!T0RWU@N0TE/6# -MY/#M)>`DP/6"Y#21]8/D\*/P[27@)&/U@N0TE/6#Y/"C\.TEX"3C]8+D-)3U -M@^3PH_#M)>`DH_6"Y#24]8/D\*/P[27@)&3U@N0TE?6#Y/"C\.TEX"2D]8+D -M-)7U@^3PH_!T1"WU@N0TEO6#Y/!T)"WU@N0TEO6#Y/!T9"WU@N0TEO6#Y/"0 -M0<23_G0!D_^008QT`9,O_^23/L,3_N\3_^TEX"3A]8+D-)+U@^[PH^_P=?`) -M[9"3*A)#7W0!\'7P">V0DRD20U]T`?!TP2WU@N0TDO6#=`SP=?`)[9"3)1)# -M7W3_\*/P=?`)[9"3(Q)#7^3PHW0/\'7P">V0DR<20U]T$_!U\`GMD),H$D-? -MY/!TA"WU@N0T!/6#=!/P#>UD(&`"80\BD`8T=/_PY*/PH_"C\"(BY)"7A?"B -MKS.0EU/PD`"`X"#A&A(R*Q(R*Y"74N!D`?#@)*V0`<3P=&RC\(#?D`8P=`'P -MPJ^0`(#@1(#P$D36D)=3X"3_DJ\BCA&/$HL3BA2)%>20EU+P[Y``,?`21-;E -M$50#_Y``,N!4_$_P$D36D``SX%1_\!)$UI``,^`@YPZ0EU+@PY1D4`7@!/"` -MZY"74N##E&10$)``,."K$ZH4J1420DU_`2)_`"+D]28B?PNQON]E)F`0Y2:T -M`07D]2:``W4F`7\!(G\`(N4C9`%P0+%;OP$%?P$21.:0`$;@1`3]?T821R"0 -M`$3@5/O]?T021R"0`$;@5/O]?T821R!_`K&^CR>0`_PTY0'4$?@_W0!J`<(@`+#,]C\]/^0`$;@7_`21-:0EZ7@_70! -M?@"H!0B`!<,SSC/.V/G_D`!$X/OD_N];J`4(@`;.HN<3SA/8^/^`1)"7I>`D -M^/#@_W0!J`<(@`+#,]C\$D3.D)>EX/UT`7X`J`4(@`7#,\XSSMCY_Y``0N#[ -MY/[O6Z@%"(`&SJ+G$\X3V/C_T-"2KR+DD)>=\*/PD`7XX'`/H^!P"Z/@<`>C -MX'`#?P$BTY"7GN"4Z)"7G>"4`T`#?P`B?S)^`!(R%9"7G>1U\`$20H&`QI`` -M$>!$"?`21-:0EQT20U.0@)82)0A_>'X($BL(D)3]_Q(P+)"7A^"T`1&0@&@2)10``RV5Y/U_`1(P+")_>'X($B)ED)<= -M$B4(?P1^#!(B99"7(1(E"'\`?@@2(F60ER42)0B0EX?@D)<=M`$-$D-3[U3' -M_^U4Q_V`!Q)#4^]4Q__LD("6$B4(?WA^"!(K")"7(1)#4^]4#__LD("6$B4( -M?P1^#!(K")"7)1)#4^]$`O_LD("6$B4(?P!^"!(K"']P?@X2(F60ERD2)0B0 -M@)82)10`&R6@?W!^#A(K")"`:!(E%`````#D_?\2,"R0EX?@M`$1D(!H$B44 -M`````.3]?P$2,"R0`!'@5/;P`D36D)>'X)"7+?`B[W`"(;&0ERW@8`*A?)"7 -M&1)#4Y"`EA(E"'^,?@@2*PB0EL420U.0@)82)0A_1'X($BL(D);)$D-3D("6 -M$B4(?UQ^"!(K")"6S1)#4Y"`EA(E"']L?@X2*PB0EM$20U.0@)82)0A_<'X. -M$BL(D);5$D-3D("6$B4(?W1^#A(K")"6V1)#4Y"`EA(E"']X?@X2*PB0EMT2 -M0U.0@)82)0A_?'X.$BL(D);A$D-3D("6$B4(?X!^#A(K")"6Y1)#4Y"`EA(E -M"'^$?@X2*PB0END20U.0@)82)0A_B'X.$BL(D);M$D-3D("6$B4(?XQ^#A(K -M")"6\1)#4Y"`EA(E"'_0?@X2*PB0EO420U.0@)82)0A_U'X.$BL(D);Y$D-3 -MD("6$B4(?]A^#A(K")"6_1)#4Y"`EA(E"'_9$B4(D)>9$D-3[43`_>R0EYD2)0B0EYD20U.0@)82)0A_C'X( -M$BL(D("6$B44``$``']$?@@2*PB0@)82)10`VR6D?UQ^"!(K")"`EA(E%"#; -M):1_;'X.$BL(D("6$B44(-LEI']P?@X2*PB0@)82)10$&R6D?W1^#A(K")"` -MEA(E%`0;):1_>'X.$BL(D("6$B44!!LEI']\?@X2*PB0@)82)10$&R6D?X!^ -M#A(K")"`EA(E%&/;):1_A'X.$BL(D("6$B44!!LEI'^(?@X2*PB0@)82)10@ -MVR6D?XQ^#A(K")"`EA(E%"#;):1_T'X.$BL(D("6$B44(-LEI'_4?@X2*PB0 -M@)82)10@VR6D?]A^#A(K")"`EA(E%``;):1_W'X.$BL(D("6$B44`!LEI'_@ -M?@X2*PB0@)82)10DVR6D?^Q^#A(K"'\$?@P2(F60EYD2)0B0EYD20U/D_^R0 -MEYD2)0B0EYD20U/O1!'_[)"7F1(E")"7F1)#4Y"`EA(E"'\$?@P2*PA_!'X- -M$B)ED)>9$B4(D)>9$D-3[U3P_^R0EYD2)0B0EYD20U/O1`'_[)"7F1(E")"7 -MF1)#4Y"`EA(E"'\$?@T2*PA_#'X)$B)ED)>9$B4(D)>9$D-3Y/_LD)>9$B4( -MD)>9$D-3[T01_^R0EYD2)0B0EYD20U.0@)82)0A_#'X)$BL(?PQ^"1(B99"7 -MF1(E")"7F1)#4^U4#_WL5/#\D)>9$B4(D)>9$D-3[400_>Q$`?R0EYD2)0B0 -MEYD20U.0@)82)0A_#'X)$BL(?P1^"!(B99"7F1(E")"7F1)#4^]4\/_LD)>9 -M$B4(D)>9$D-3[T0!_^R0EYD2)0B0EYD20U.0@)82)0A_!'X($BL(Y)"7+?`B -MTQ"O`?[_#3E`=09>#_=`&H!PB``L,SV/ST_Y``1^!?\!)$ -MUI"7G^#_=`&H!PB``L,SV/S_D`!&X$_P$D36D)>@X&`6D)>?X/]T`:@'"(`" -MPS/8_/^0`$6`:)"7G^#_=`&H!PB``L,SV/ST_Y``18!MD)>?X"3X\.#_=`&H -M!PB``L,SV/S$5/`21,Z0EY_@_W0!J`<(@`+#,]C\_Y``0^!/\!)$UI"7H.!@ -M&Y"7G^#_=`&H!PB``L,SV/S$5/#_D`!"X$^`&I"7G^#_=`&H!PB``L,SV/S$ -M5/#T_Y``0N!?\!)$UM#0DJ\BBQ&*$HD3D``"$D(@D)<[\.`PX$N0ES)T`?!_ -M@'X($B)ED)D`!'X%3S_7]'$D<@D`!(X%3S_7]($D<@D`!&X%3O_7]& -M$D<@Y)"7./`BY/U_11)'()`$_>3PH_"0ESSPD)="\)"71?"0ET/PD)=&\)"7 -M1/"0ET?PD)!$P/U_40)'()"73.!D`6`)D)`$\(`DD)=#X,.4 -M_U`&X`3PY(`1D)=$X,.4_U`,X`3PY)"70_"0ET+PD`!$X##C,I"71>##E/]0 -M!>`$\(`DD)=&X,.4_U`&X`3PY(`1D)='X,.4_U`,X`3PY)"71O"0ET7PD`3] -MX$0!\"*0``(20B"0ESKPD``!$D(@)>`EX)"7.?`2)&(EX"7@D)<]\)`%8."0 -METCPD`5AX)"72?"0!6+@D)=*\)`%8^"0ETOPHJ_D,Y"77?#"KY"7.>#_$DIB -MD)==X"3_DJ^0ESK@<`(AB9"7.>!P`B&)D)<]X'`"(8FBK^0SD)==\,*OD)=, -M=`'PD)==X"3_DJ\21Q>0`$;@1`']?T821R"0ES+@8!60ESX20U.0@)82)0A_ -M@'X($BL(@`:0!2)T?_"0`$7@5._]?T421R"0!8?@9(#PD)=(X)`%A/"0ETG@ -MD`6%\)"72N"0!8;PD)=+X)`%A_"BK^0SD)==\,*OD`$\X$0@\'T@Y/\2,;>` -M+9"7.N!P+Y"73!)'%I``1N!4_OU_1A)'()`%(N3PHJ\SD)==\,*O?2#D_Q(Q --29"77>`D_Y*O(@"'%P`` +MZ?`BT(/0@OCDDW`2=`&3<`VCHY/X=`&3]8*(@^1S=`*3:&#OHZ.C@-_0@]"" +M^.23`OD(L^\.3[_7]4 +M?@$22VR0`5=T!?#E(E0/PY0$4`=]`7\$$D6BD(LLX##@"1)]P9`%(G3_\"+D +M]27U)'4C#'4B#)"+&O"0BQCPD(L7\)"+&03PD(L+\.20BQOPD(L-\)"+%70% +M\.20BPSPD(L3\*-T`_"0BQ#PHW0%\)"+#W04\)"+%G0%\.20BP[PD(L*\)"+ +M"/"0BQ+P(G\`(@)%`P)%!HYDCV6M9:QDKV,22ENO9:YDD`2`X%0/_:P'=!$L +M]8+D-/SU@^!$`?!T$2SU@N0T_/6#X%3[\*P'=!8L]8+D-/SU@^!$^O!T%2SU +M@N0T_/6#X$0?\*P'=`8L]8+D-/SU@^!$#_"0!%/D\)`$4O"0!%%T__"0!%!T +M_?!T%"SU@N0T_/6#X%3`3?UT%"_U@N0T_/6#[?`B?0%_#-,0KP'#P-"/9XUH +MY6=4#__E(E0/;V!RY6]@4Q)* +MS(!.Y2(@XTGE9S#C1*]H$DI\@#WE(E0/_[\,#N5G(.,)$DG5[V`J$DK,Y2)4 +M#_^_!`[E9R#B"1))D^]@%!)*,N4B5`__OP()$D4`[V`#$DL0T-"2KR("1FX" +M4,;DDZ/XY).C0`/V@`'R"-_T@"GDDZ/X5``ON4A9`%P9^4D +M8&/E)&0"8`;E)&0%<">0!JO@D(L+\)`&JN"0BQGPD(L+X'`'D(L9X/^`!9"+ +M"^#_D(L+[_"0BPW@8`+D\.20BPSPD`58=`/PD`%7Y/"0`3QT`O!3)?U3)>_E +M)!0D_5`"@`,21XXB[V0!<#5]>'\"$C$L?0)_`Q(Q+)`!5^3PD`$\=`+P$D6> +MD(LLX##@`Q)]P9`&!.!4?_"0!@K@5/CP(I`!-G1[\*-T`O!]>_\2,9U]`G\# +M$C&=D`8$X$2`\)`&"N!$!_`22T_E(2#@!>20BPWP(N20BL7PD`:IX)"*Q?#@ +M5,!P"5,E_E,E_1)*_)"*Q>`PYA5#)0&0BQK@9`)@!1)*EX`($DE)@`-3)?Z0 +MBL7@,.`*9"*WA)#:Y```A)"(/U_`1)*!Q^`%)"*WA)#:Y`` +M`A)"(/U_`A)*!^3_$D3P4R7]Y254!W`X@#.0 +MBPS@!/!3)>^0BLO@_Y"+$.`O_^0S_I"+#.#3G^YD@/AT@)A`#>4AM`$+H^!P +M!^`$\"(22OPBTQ"O`Y)"+/?"0BP_@D(L^\.3[_7]8?@$22VR0`5MT!?"0!I)T +M`?"0BQCP(N4B5`_#E`10!WT!?P021:(BD`%?Y/"0`3QT"/#DD(L]\)"+#^"0 +MBS[PY/O]?UQ^`1)+;)`!7W0%\)`&DG0"\)"+%Q3PY2)4#\.4#%`-$D6>D(LL +MX##@`Q)]P2(22S3O9`%P-^4E5`-P,>4C5`_3E`)0*.4E(.(CY24@Y!Z0BPW@ +M3_$DBS4R+P0R(,(I`$ +M'>!P%)"*^.#_Y/T27_V.:8]JD`0?="#P(I"+4N_P$GU"D(M2X&`%D`4BY/!3 +M(O!#(@0BD`8$X$1`\.4AM`$%?P$22+-3(O!#(@0BY2,PYA+E(U0/_Y`!+^!4 +M@$]D@/!3([\BD(LLX##@!:\C`GX&?0&O(Q)%HB)3(O!#(@$22UH22UM3(O!# +M(@(B08KV`$&+!0!!BU$`08M3``"0!!O@5']D?W\!8`)_`"+DD(L;\)"+#/#U +M)2*0BQ/@H^"0!5CP(B(B\)"+#^"0BS[PY/O]?UA^`=,0KP'#P-"0BSW@^Z/@ +M]43D]442,&+0T)*O(L#@P/#`@\""P-!UT`#``,`!P`+``\`$P`7`!L`'=0X` +MD`'$=(?P=$NC\%.1WY`!/.!5,/4TH^!5,?4UH^!5,O4VH^!5,_4WY30PX%&0 +M`3QT`?"0BS+@,.`?$Q-4/S#@&)"+-.3PD(LSX&0#8`M_`;'@[W`$?P+1B9"+ +M+.#_,.`=$Q-4/S#@%I"++N3PD(LMX&0&8`GD_['@[W`"T5;E-##A")`!/'0" +M\!%@Y30PXBB0`3QT!/"0!I+@,.`4D(L]Y'%0BQCD +M\%'\Y30PXSB0`3QT"/"0!I+@,.$DD(L]Y/"0BP_@D(L^\.3[_7]#O8`1_`=&)D(LLX##@29"+,.3P_['@[V`^$F5?D(LMX/]D!F`R +M[[0$`H`'D(LMX+0%!.3_@!20BRW@M`,$?P&`"9"++>"T`@5_`1)E@GT!KR,2 +M1:(2?<'E-C#A1Y`!/G0"\)"+,N`PX!F0BS9T`?"0BS/@9`-@"W\!L>#O<`1_ +M`M&)D(LLX##@&I"+,'0!\!)^*Y"++>!D!F`)Y/^QX.]P`M%6=(<$D`'$\'1+ +MH_#0!]`&T`70!-`#T`+0`=``T-#0@M"#T/#0X#+O9`%P/9"+->!@`W\`(I"+ +M".!@`W\!(I"+-.!@`W\!(I"+,N#_$Q-4/S#@"^_$$U0',.`#?P`BD(LVX'\! +M8#9_`"*0BR_@8`-_`"*0BPC@8`-_`2*0BR[@8`-_`2*0BRS@$Q-4/S#@`W\` +M(I"+,.!_`6`"?P`BD(L-X&`6D(LMX'`$?P6`'Y"++>!D`7`:?P*`$Y"++>"T +M`01_`X`(D(LMX'`%?P0298(BTQ"O`"T`@3QK^%5D(M5X+0$!/'&X560 +MBU7@9`%P??&Q@'F0BU7@_[0#!/'*@&WOM`($\:&`99"+5>#_M`0$\=6`6>]P +M5O&.@%*0BU7@M`,%$GQ!@$:0BU7@M`$$\7*`.Y"+5>"T!`42?2.`+Y"+5>!P +M*?%P@"60BU7@_[0!!/%:@!GOM`($\6N`$9"+5>#_M`0$\5J`!>]P`O%GT-"2 +MKR*0!2)T;_"0BS-T`_`B\8Z`[Q)]0H#J\8Z0!2)T__`2?IKO<`:0`UP!/[_@`1^`7\`[RWN/'T`_(`U[%0!37`$_O^`!'X"?P#O+>X\ +MPQ-]`(`:[%0#37`$_O^`!'X$?P#O+>X\$Q-4/WT`)>`EX/RN!*\%(I`!Y'18 +M\*-T`O`BY)"*S/"C\'6.`I$.$FA$D(L'[_`2:%&0BPGO\!)H79"*].[PH^_P +MY/55]2$255,.;9`%P +M.W%.OP$$?P%Q0I``1N!$!/U_1C&(D`!$X%3[_7]$,8B0`$;@5/O]?T8QB'\" +M<6J/8I`!R>5B\+0!`E'B(N!?\-,0KP'#P-!_$-_^T-"2KR+3$*\!P\#0D(K@ +M[?"0BM_O\-.4!U!.H^!P&I"*W^#_=`&H!PB``L,SV/ST_Y``1^!?\(`7D(K? +MX/]T`:@'"(`"PS/8_/^0`$?@3_!1#I"*W^#_=`&H!PB``L,SV/ST_Y``1H!9 +MD(K?X"3X\*/@Y/U_`E$><4[D_W%"Y/5BD`')Y6+PD(K=X/RCX/WL^XU$ +MY/5%?0%_8'X!`C!BD`'*Y6'P[V`"4>(B?PMQ:N]E86`0Y6&T`07D]6&``W5A +M`7\!(G\`(M,0KP'#P-"0BU?O\-.4!U!#X/]T`:@'"(`"PS/8_/3_D`!&40N0 +MBU?@_70!?@"H!0B`!<,SSC/.V/G_D`!$X/OD_N];J`4(@`;.HN<3SA/8^/^` +M2Y"+5^`D^/#@_W0!J`<(@`+#,]C\]/^0`$/@7_!1#I"+5^#]=`%^`*@%"(`% +MPS/.,\[8^?^0`$+@^^3^[UNH!0B`!LZBYQ/.$]CX_]#0DJ\BY)"+!/"0`(#@ +M1(#]?X`AB-,0KP'#P-"0BMH20XN0BMH20VN0``$20L+ZY?`D`/_D.OZ0BMH2 +M0VN0``'NC_`20QD2)&+_8"RU7A:0BMH20VN0``$20L)E8'`$Y5]E\&`BD(K: +M$D-KD``!$D+"_Z[P<0"`#Y"*VA)#:Q(D8F5>8`*1E=#0DJ\BY/5>?V!^`8^" +MCH.CHZ/D\"*0BM<20XOO$D.45.(&0BM<20VL">L*0BM<20VL"?"N0 +M`<;@1`'P(M,0KP'#P-"0`!U\`20`=`20U_@D(K0\'4=`74>BG4?T'4@ +M`7L!>HIYT1)>Y)"*T>#_Q!,3$U0!D(M1,.!9X'7P`I``B!)#7^"0BM+PD(M1 +MX'7P`I``B1)#7^"0BM/PD(M1X'7P!)`!T1)#7^"0BM3PD(M1X'7P!)`!TA)# +M7^"0BM7PD(M1X'7P!)`!TQ)#7^"0BM;P@#/@=?`$D`'1$D-?X)"*TO"0BU'@ +M=?`$D`'2$D-?X)"*T_"0BU'@=?`$D`'3$D-?X)"*U/#O5'__>P%ZBGG2D::0 +MBL_@_Y"+4>#^=`&H!@B``L,SV/ST7Y"*S_"0BU'@_W0!J`<(@`+#,]C\D`', +M\)"+4>`$\.!4`_"A:I`!QN!$`O#0T)*O(I``!!)"(/]4'_[O5"#$$U0'_:\& +MD(K:[_"C[?"C$D.+D(K<$D-KD``#$D(@5/#$5`^0BM_PD``$$D(@5$#$$Q-4 +M`Y"*X/"0BMK@_W7P"9"')1)#7ZV"K(.0BN'L\*/M\.]U\`FD)"/Y=(\20E^0BMP20VN0``$20B#_D(KAX/RCX/WU@HR#[_`2)&*-@HR# +MH_"0BM_@_I"*VN#_),'U@N0TAO6#[O"0BMO@_G7P">^0ARD20U_N\'7P">^0 +MARH20U]T`?"0BN#@_G7P">^0ARL20U_N\(\/[R7@).3U@N0TB:^"]1"/$>4/ +M=?`"I"2!^72&-?!U$@'U$XD4=?`)Y0^0AR420U^O@H6#%8\6Y0]U\`FD)"/Y +M=(`D@?6"Y#2&]8-T#_"C=(_P(:?E#R7@).3U@N0TB?6# +M=`_PHW3U@"?E#R7@).3U@N0TB?6#=`_PHW3P@!+E#R7@).3U@N0TB?6#Y/"C +M=`WPY0\EX"2!]8+D-(;U@^3PH_`AIY`$1^"K$JH3J1020DV0!$;@JQ*J$ZD4 +MD``!$D)?D`1%X(41@H40@_"0!$0AGI`$2^"K$JH3J1020DV0!$K@JQ*J$ZD4 +MD``!$D)?D`1)X(41@H40@_"0!$B`6)`$3^"K$JH3J1020DV0!$[@JQ*J$ZD4 +MD``!$D)?D`1-X(41@H40@_"0!$R`*Y`$4^"K$JH3J1020DV0!%+@JQ*J$ZD4 +MD``!$D)?D`11X(41@H40@_"0!%#@A1&"A1"#H_"K$JH3J13``\`"P`$2)&+_ +MJQ>J&*D9$B1B7]`!T`+0`Q)"3:L2Y10D`?GD-1/ZP`/``L`!$B1B_ZL7JABI +M&9```1)"(%_0`=`"T`,20DV%$8*%$(/`@\""X/^%%H*%%8/@_N]>T(+0@_"% +M$8*%$(.CP(/`@N#_A1:"A16#H^#^[U[0@M"#\.4/)>`D@?6"Y#2&]8/@_J/@ +M3F!+D(KF=`OPD(KFX/_#E`!0`D'L=`%^`*@'"(`%PS/.,\[8^?_E#R7@)('U +M@N0TAO6#X%[^H^!?3F`*D(KFX"00H_"`:)"*YN`4\("[Y0\EX"3D]8+D-(GU +M@^#^H^!.8$>0BN9T#_"0BN;@_\.4`$`\=`%^`*@'"(`%PS/.,\[8^?_E#R7@ +M).3U@N0TB?6#X%[^H^!?3F`(D(KFX*/P@`V0BN;@%/"`O^20BN?PY0\EX"3D +M]8+D-(GU@^#^H^!.8$;DD(KF\)"*YN#_PY000`)AI70!?@"H!PB`!<,SSC/. +MV/G_Y0\EX"3D]8+D-(GU@^!>_J/@7TY@!I"*YN"`8Y"*YN`$\("_Y0\EX"2! +M]8+D-(;U@^#^H^!.8$;DD(KF\)"*YN#_PY0,4#QT`7X`J`<(@`7#,\XSSMCY +M_^4/)>`D@?6"Y#2&]8/@7OZCX%].8`B0BN;@)!"`"9"*YN`$\("_Y)"*Z/"0 +MBN?@_W7P">4/D(4/D(0AR)T`?`BY)"'(O`BTQ"O`0BL7@)0W_H_"CX)!!GI/^[].>0!!T`2SU@N0TAO6#Y/"O!("=D(K& +MX/]T`2SU@N0TAO6#[_`BK0=U\`GMD(`D+O6" +MY#1!]8-T`9,K_^23.L,3_N\3_^TEX"3A]8+D-(;U@^[PH^_PKP60BLG@_9%. +MD(K)X/\BK`=TA"SU@N0T!/6#X%1_D(K>\.!4'_^0BN'P=?`)[)"'*!)#7^"0 +MBN/P=?`)[)"')Q)#7^#^D(KD\.PEX"3D]8+D-(GU@^#[H^"0BN7+\*/K\.PE +MX"2!]8+D-(;U@^#[H^"0BN?+\*/K\._3GD`,D(KDX)"*X?"0BM[P[7`"P9.0 +MBN+M\)"*WN`PY@Z0BN'@D(K>\)"*XN`4\)"*XN!P`L&3D(KAX/_3E`!0`L&3 +MY)"*X/#O%)"*W_"0BN/@_9"*W^#_TYU`;^^4$$`A[R3P_W0!?@"H!PB`!<,S +MSC/.V/G_D(KGX%[^H^!?3G`GD(K?X/_#E!!0-W0!?@"H!PB`!<,SSC/.V/G_ +MD(KEX%[^H^!?3F`:D(K?X)"*WO"0BN#@!/"0BN+@_Y"*X.!O8`B0BM_@%/"` +M@Y"*XN#_D(K@X,.?4`^0BM_@M04(D(KCX)"*WO"0BM[@_R7@)&;U@N0T0?6# +MY)/Z=`&3^^\EX"0N]8+D-$'U@W0!DRO_Y),ZPQ/^[Q/_["7@).'U@N0TAO6# +M[O"C[_"O!)"*WN#]D4Z0BM[@_R+3$*\!P\#0BQJ*&XD@%YH-'DD(M($D-KBQV*'HD?D(M%$D-K$B1B +M_\14#_4@>P%Z`7FBT>20`:]T__"0`@!Y5I"+2!)#BPMZBGG%X3/3$*\!P\#0D`'$=,7P=%^C\)`$'>!@&I`% +M(N!4D&`'D`'&X$1`\)`!Q^`PX>1_`(`"?P'0T)*O(M,0KP'#P-#D^_KO,.`" +M>X#OPQ.0_1#PD`0E[_#M8!ZO`W0/+_6"Y#3\]8/@1(#P=!`O]8+D-/SU@^!$ +M@/"O`W0(+_6"Y#3\]8/D\'0)+_6"Y#3\]8/@5/#P="$K]8+D-/SU@^!4]_"N +M`J\#T-"2KR(27\6_`1"0`@G@_WT!$E_]D`0?="#P(I`!`N!4`__@5`P3$U0_ +M_N]D`6`$[[0##I"*Q70!\*-T-_!Y`8`8[F0!8`>O!NYD`W`[D(K%=`'PHW0] +M\'E`D(K%X/ZCX/_U@HZ#X%E@".GPY)"*]O`BD(KVX`3PX,.4"D`+Y/"0!!G@ +M,.`"$6TBP.#`\,"#P(+`T'70`,``P`'``L`#P`3`!<`&P`>0`<1T\O!T8*/P +MD`$TX%4H]2RCX%4I]2VCX%4J]2ZCX%4K]2_E+"#@`D&)D`$T=`'PA=%-A=). +MA=-/A=10A=51A=92A==3A=E4Y5140,,3_^535"!O<`)!1N54,.4"04;E4E0? +M]0CE350_]0GE450?_^4()>`DX_6"Y#2(]8/DC_`20H'E4U0?_^4()>`DP/6" +MY#2%]8/DC_`20H'E"=.4!$`#=0D$=?`*Y0B0A``20U]U\`+E"1)#7^#^H^#_ +MY5-4'R__Y#[^=?`*Y0B0A``20U]U\`+E"1)#7^[PH^_PY50@YB3E4U0?_^4( +M)>`D8_6"Y#2(]8/DC_`20H'E3S#G-J\($ES#@"_E4U0?_^4()>`DH_6"Y#2( +M]8/DC_`20H'E3S#G$N5/5'_]Y5-4'_4-JPFO"!)<9N4D%"3]4`*`.I"+&N!@ +M*Y`!6^3PD`$\=`3P$DLT[V0!<"&0BST22UR0`5MT!?"0!I)T`?"0BQCP@`D2 +M2S2_`0,22OSE+##A(9`!-'0"\(715H725X736(7468756H766X777(7971)? +MI.4L,.,&D`$T=`CPY2PPY`F0`31T$/!#51#E+##E)I`!S^`PY1_@5-_PD`$T +M="#P=:@`=>@`$E&=D``#X%3[\!)2#H#^Y2PPYBV0`31T0/"0BS+@,.`,$Q-4 +M/S#@!9"+-.3PD(LLX/\PX`P3$U0_,.`%D(LNY/#E+B#@`F'FD(L(=`'PD`$V +M\)"+!N!@#^3PD`53X$0"\)`%_.`$\)"+,N`PX"^0BS=T`?"0BS+@_Q,35#\P +MX!V0BS1T`?"Q.9"+,^!D`V`-?P$23>#O8`5_!!).B9"++.#_,.!5$Q-4/S#@ +M3I"++G0!\+$YY/\23>#O8#ZQ7Y`%(G3_\)"++>#_9`9@+>^T!`*`!Y"++>"T +M!03D_X`4D(LMX+0#!'\!@`F0BRW@M`($?P&Q@I`%(G3_\!)#YY"+".3PY2XP +MX2^0`39T`O!#54`1A)"+-^"T`0F0!2+D\)"+-_"0BRS@,.`-Y/\23>#O8`60 +M!2+D\.4N,.(6D`$V=`3PD(LLX##@!J/@9`9@`Q)&L^4N,.,XD`$V=`CPY2%D +M`7`LY21@*)`!5^3PD`$\=`+PD(L]Y/"0BQ'@D(L^\.3[_7]4?@$22VR0`5=T +M!?#E+C#D*Y`!-G00\.4AM`$@Y21@')`!5^3PD`$\=`+PD(L;Y/!3)?WE)50' +M<`,22OSE+C#E'Y`!-G0@\.4AM`$4Y21@$)"+&N!D`F`%$DJ7@`,224GE+C#F +M&Y`!-G1`\.4AM`$0Y21@#%,E_N4E5`=P`Q)*_.4O,.$HD`$W=`+PD(LLX##@ +M&.3_$DW@[V`($DC^$GW!@`N0BS%T`?"``Q)(_G3R!)`!Q/!T8*/PT`?0!M`% +MT`30`]`"T`'0`-#0T(+0@]#PT.`RY)"+/?"0!5C@_Y"+..`O)/Z0BS[PY/O] +M?U!^`1)+;)`!4W0%\"*0BRS@_\03$U0#,.`*H^!D!F`$?P:Q@I"++>!D!F`# +M$G@U(M,0KP'#P-"0BRW@_F]P`N%.[Q)#E&6P`&7J`68P`F9J`V:B!&;;!6<6 +M!@``9T[NM`0&?P'Q@>%.D(LMX/^T!03Q7>%.[[0&!G\!\7*`%I"++>"T`P9_ +M`?%3@`F0BRW@M`("\6?QI.%.D(LMX+0$!G\!\8&`"9"++>"T!0+Q79"++>!P +M!/&:X4Z0BRW@_K0&!G\!\7+A3NZT`P9_`?%3X4Z0BRW@9`)@`N%.\6?A3I"+ +M+>"T!`9_`?&!@`F0BRW@M`4"\5V0BRW@<`3QFH`6D(LMX/ZT!@9_`?%R@`CN +MM`,$?P'Q4_'0X4Z0BRW@M`0&?P'Q@8`)D(LMX+0%`O%=D(LMX'`$\9J`%)"+ +M+>#^M`8&Y/_Q#^M`8&Y/_Q"T`@+Q9Y"++>"T`03QI(`)D(LMX+0%`O%=\:^`#^M`8&Y/_Q +M"T`@+Q9Y"++>"T`03QI(`+D(LMX+0$!'\!\8'Q +MPX`XD(LMX+0$!G\!\8&`"9"++>"T!0+Q79"++>!P!/&:@!:0BRW@M`,&Y/_Q +M4X`)D(LMX+0"`O%G\=W0T)*O(A)*LI"++70!\"*0!2+D\)"++?`BD`4BY/"0 +MBRT$\"+O8`60!2+D\)"++70!\"*0BU;O\!)]0I"+5N!@!9`%(N3PY)"++?`B +M$DK,D(LM=`'P(G\!$DI\Y)"++?`B$GQ*D(LM=`3P(A)*,I"++70#\"*0!2)T +M__"0BRUT!?`BD`4B=/_PD(LM=`+P(I`%(G1O\)"++70&\"+3$*\!P\#0Y/W\ +M[S#@`GV`[\,3D/T0\*X$KP70T)*O(G4H,^3U*74J!_4KD`$PY2CPH^4I\*/E +M*O"CY2OP(G4P'W4Q`4,Q$.3U,I`!..4P\*/E,?"CY3+P(B*0``+@5.!_`6`" +M?P`BD`#SX'\`,.,"?P$BD(L)X+0!#)``\N`PYP5^_7\S(G[]?R\BD`#SX##B +M#9`%0700\)`%6O"CY/`BD`%D=*#P(L#@P(/`@L#0==``P`7`!L`'?9&0`<3M +M\'1H_Z/P4Y'OD`!1X/Z0`%7@7O4]D`!2X/Z0`%;@7O4^Y3TPY`:0`%5T$/#E +M/3#E!I``570@\.4],.8&D`!5=$#PY3TPYP:0`%5T@/#E/C#@!I``5G0!\.4^ +M,.$&D`!6=`+PY3XPX@:0`%9T!/#E/C#C!I``5G0(\)`!Q.WPH^_PT`?0!M`% +MT-#0@M"#T.`R[\.4(%`Y[S#@%^W$5/#][\,3_B2D]8+D-`3U@^!4#X`0[\,3 +M_B2D]8+D-`3U@^!4\/!TI"[U@N0T!/6#X$WP(JT'=(0M]8+D-`3U@^!4?Y"* +MWO#@^50?H_!U\`GMD(`DX?6"Y#2&]8/J\*/K\.[#GT`"0;F0BM_@_W2E+?6"Y#2*]8/O +M\.\$D(K@\)"*X>#_D(K@X/[3GT`"0?/NPY000"'N)/#_=`%^`*@'"(`%PS/. +M,\[8^?^0BN+@7OZCX%].<">0BN#@_\.4$%!9=`%^`*@'"(`%PS/.,\[8^?^0 +MBN3@7OZCX%].8#R0BN#@M!$-D(KCX##G!I"*X'07\)"*X.#_9!-@!.^T$@V0 +MBN+@,.`&D(K@=!CPD(K@X)"*W_"0BM[P@$*0BN#@!/!!%Y"*X>#\D(K?X/]L +M<'%TI2WU@N0TBO6#[_!U\`GMD(D(KAX/]TI2WU@N0T +MBO6#[_"0BM_O\)"*WO#\H^#_)>`D9O6"Y#1!]8/DD_IT`9/[[R7@)"[U@N0T +M0?6#=`&3*__DDSK#$_[O$__M)>`DX?6"Y#2&]8/N\*/O\*\$(G0!+?6"Y#2& +M]8/D\*\%D(K>X$2`_1)<3I"*WN!$@/\BY)"*S_"0BL_@_\.4($`#`G)4=?`) +M[Y"'*A)#7^!D`6`#`G)+D(K/X"7@),#U@N0TA?6#X/RCX-.4`.R4`%`#`G)+ +M[W7P"J0D`/ETA#7P=1(!]1.)%)"*S^`EX"3`]8+D-(7U@^#]H^"0BM3-\*/M +M\.\EX"1C]8+D-(CU@^#_H^"0BM;/\*/O\)"*S^#^)(3U@N0T!/6#X%0_D(K0 +M\.#]5!^C\'7P">Z0AR<20U_@D(K9\)"*S^#[)&3U@N0TBO6#X,.4!4`"P9R0 +MBMG@_I"*T>">0!.0BMG@D(K1\.U40/V0BM#P[DWPD(K1X/^001*3_G0C*_6" +MY#2)]8/@PYY`!N^00-J`!Y"*T>"00/:3D(K8\)"*V.!U\`:D)%#Y=$`U\'4/ +M__40B1&0BM#@D$&ZD__3D(K7X)^0BM;@E`!`#9"*S^#_Y/T274$"<>&0BL_@ +M)>`DX?6"Y#2&]8/@_Z/@D(K2S_"C[_"K#ZH0J1$2)&+_?@"K$JH3J1020I?] +MK/`2)'N0BM+NC_`20H&K#ZH0J1&0``$20B#_?@"K$JH3J120``(20L+]K/`2 +M)'N0BM+NC_`20H&K#ZH0J1&0``(20B#_?@"K$JH3J120``020L+]K/`2)'N0 +MBM+NC_`20H&K#ZH0J1&0``,20B#_?@"K$JH3J120``820L+]K/`2)'N0BM+N +MC_`20H&K#ZH0J1&0``020B#_?@"K$JH3J120``@20L+]K/`2)'N0BM+NC_`2 +M0H&K#ZH0J1&0``420B#_?@"0BM3@_*/@_1(D>].0BM/@GY"*TN">0`RCX)_P +MD(K2X)[P@`?DD(K2\*/PD(K2X/RCX/V0BL_@_R7@).'U@N0TAO6#[/"C[?"0 +MBM#@)>`D+O6"Y#1!]8/DD_IT`9/[T^V;[)I`!3%X`G&OD(K0X"7@)&;U@N0T +M0?6#Y)/^=`&3_\.0BM/@GY"*TN">0`,"<:^0BL_@_WT!$EU!`G&OD(K/X/\D +M9/6"Y#2*]8/@_&0%8`,"<'V0AR+@_K0#"Y"*T>##E!E`/8`N[K0""Y"*T>## +ME!%`+H`?D(##E`-`#9")0W0!\(`% +MY)")0_"0BL_@_B1#]8+D-(CU@^"0BMWP=",N]8+D-(GU@^#^PY0P4`ODD(K= +M\'1D+P)P*)")0^!D`6`#`G`=D(K/X"1$]8+D-(GU@^!D"F!;D(K/X/_N)`7[ +MY#/Z="$O]8+D-(;U@^#_TYOJ9(#X=("84#B0BL_@_N\D!?OD,_IT(R[U@N0T +MB?6#X-.;ZF2`^'2`F%`6D(K/X"2$]8+D-(KU@^#_D(K1X&]@5I"*S^`D(_6" +MY#2)]8/@_].40D`(D(K==`7P@!'OTY0YD(K=0`5T`_"``W0!\)"*S^#_)"/U +M@N0TB?6#X/YT(2_U@N0TAO6#[O"0BL_@)$3U@N0TB8`OD(K/X/\D9/6"Y#2* +M]8/D\'1$+_6"Y#2)]8/@!/"`%.20BMWPD(K/X"1D]8+D-(KU@^3PD(K1X/Z0 +MBL_@_R2$]8+D-(KU@^[PD(K=X/YT0R_U@N0TB/6#[O!U\`GOD(20BMWP=&0O]8+D-(KU@^3PD(K=X/TAK.QD!F`"(:^0BM+PH_"00=N3_WX` +MD(K4X/RCX/T2)'N0BMON\*/O\)"*S^`D0_6"Y#2(]8/@D(K=\.20BMKPD(K: +MX/_3E`101ZL2JA.I%'7P`N^D]8*%\(,20L+]K/#OD$'6D_]^`!(D>Y"*TNZ/ +M\!)"@9"*V^#^H^#_TY"*T^"?D(K2X)Y0")"*VN`$\("OD(K:X,,3\)"*W>#_ +MM`$-D(K:X'!=D(K=!/"`6^^T`QV0BMK@_W`(D(K==`/P@$COM`$(D(K==`'P +M@#R`-9"*W>!D!7`RD(K:X/]P")"*W70%\(`/[Y"*W;0!!70#\(`#=`'PTY"* +MU^"4`Y"*UN"4`$`%Y)"*W?#3D(K7X)0#D(K6X)0`0`7DD(K=\)"*W>#]D(K/ +MX/\D0_6"Y#2(]8/M\!)I.)"*S^#_)&3U@N0TBO6#X-.4!5`/=&0O]8+D-(KU +M@^`$\(`/D(K/X"1D]8+D-(KU@^3PJQ*J$ZD4Y/7P$D+ZJQ*J$ZD4D``"Y/7P +M$D,9D``$Y/7P$D,9D``&Y/7P$D,9D``(Y/7P$D,9D(K/X/\EX"3`]8+D-(7U +M@^3PH_#O)>`D8_6"Y#2(]8/D\*/P[R7@)*/U@N0TB/6#Y/"C\)"*S^`$\`)K +MPB+DD(K/\)"*S^#_PY004!1TI"_U@N0T!/6#Y/"0BL_@!/"`XN20BL_PD(K/ +MX/_#E"!``H$.=?`*[Y"$`!)#7^3PH_!U\`KOD(0"$D-?Y/"C\'7P"N^0A`02 +M0U_D\*/P=?`*[Y"$!A)#7^3PH_!U\`KOD(0($D-?Y/"C\'2$+_6"Y#2*]8-T +M$_!T1"_U@N0TB?6#Y/!T0R_U@N0TB/6#Y/#O)>`DP/6"Y#2%]8/D\*/P[R7@ +M)&/U@N0TB/6#Y/"C\.\EX"3C]8+D-(CU@^3PH_#O)>`DH_6"Y#2(]8/D\*/P +M[R7@)&3U@N0TB?6#Y/"C\.\EX"2D]8+D-(GU@^3PH_!T1"_U@N0TBO6#Y/!T +M)"_U@N0TBO6#Y/!T9"_U@N0TBO6#Y/"008R3_G0!D_^0051T`9,O_^23/L,3 +M_N\3_Y"*S^#])>`DX?6"Y#2&]8/N\*/O\'7P">V0ARD20U]T`?!TP2WU@N0T +MAO6#=`SP=?`)[9"')1)#7W3_\*/P=?`)[9"'(Q)#7^3PHW0/\'7P">V0AR<2 +M0U]T$_!U\`GMD(TND(KW\)```1)"(/_M+Y"*^/"0``(20B#_[2^0BOGP +MD``#$D(@_^TOD(KZ\)``!!)"(/^N!>TOD(K[\"+3$*\!P\#0D(K:$D.+Y)"* +MW?`2)&+#$R#@`L'MD(K:$D-K$B1B_U0"_I"+,N!4_4[^\.]4`?_N5/Y/__`2 +M)&+^5`C][U3W3?^0BS+P[E00_N]4[T[_\!(D8OY4(/WO5-]-_Y"+,O#N5$#^ +M[U2_3O`@X`+!V9"*W70A\)"*VA)#:Q(D8O\3$U0!_I"+,N#]$Q-4`6Y@*N]4 +M!/_M5/M/\.`3$U0_,.`.D`$T=$#P_>3_$C&=@`ODD(LT\'U`_Q(Q+)"+,N#] +M$Q,35!\PX`>0BMW@1!+P[<14#S#@!Y"*W>!$%/"0BS+@Q!-4!S#@!Y"*W>!$ +M@/"0BS+@Q!,35`,@X`>0BMW@1$#PD(K=X)`%)_"0BS/@<`5_`1).B9"+,N#$ +M$Q-4`S#@!'\#@`Y_`1)-X.]@!'\!@`)_`A).B7\"`G@ND(K==`'PD`4G\.3_ +M$DZ)?P,">"Z0BMH20VL2)&+_5`+^D(LLX%3]3O[P[U0!_^Y4_D__\!(D8OY4 +M"/WO5/=-_Y"++/#N5!#^[U3O3O_P$B1B_E1`_>]4OTW_D(LL\.Y4!/[O5/M. +M\"#@`N'BD(K==#'PD(LLX!,35#\@X`ODD(LN\'U`_Q(Q+)"++.#]$Q,35!\P +MX`>0BMW@1`+P[<14#S#@!Y"*W>!$!/"0BMW@5`9@#)`!/G0#\/U_`A(QMY"* +MW>"0!2?PD(LLX/_$$Q-4`S#@#:/@9`9@+'\&$F6"@"60BRW@M`8;?P$298+D +M_Q)-X.]@"7T!KR,21:*`!1).5H`#$GW!?P&`3)"*W70!\)`%)_!]`W\"$C%) +MD(LMX+0&`H`;D(LMX+0$`H`'D(LMX+0%!.3_@!20BRW@M`,$?P&`"9"++>"T +M`@5_`1)E@A$U$DK\?P,10M#0DJ\BD(LQX+0!!>3P$DC^(JT'[V0!8`3OM`,5 +MD(LRX%3^\%3[\.2C\*/PH_"C\*/P[60"8`3MM`,5D(LLX%3^\%3[\.2C\*/P +MH_"C\*/P(A(D8I"+./`BTQ"O`"0BNCPD(K^X/^CX)"*Z<_PH^_P +MY)"*Y/"0BN3@_R0`]8+D-(OU@^#^=.LO]8+D-(KU@^[PD(KDX`3PX+0$VI"* +MZ.`20Y1X^`!Z:P%Y`0)Y`0-Y`01Z:P5Z-8!Z3H%Z:X(``'IGD(KNX/]1.20BN3P +MD(KEX/^0BN3@PY]``D%KD(KIX/ZCX/_#[I0!D(KDX%`?_B__[OW#=`.=_>24 +M`/QTZRWU@G2*//6#X/T248B`*__]PW0#G?WDE`#\=.LM]8)TBCSU@^#^[_V0 +MBNK@+?V0BNG@-`"-@O6#[O"0BN3@!/"`C<.0BNG@E!!``D%KD(KHX&0$8`)! +M:Y"*[.#_Y/S]_G@0$B3UP`3`!<`&P`>0BNO@_^3\_?YX&!(D]=`#T`+0`=`` +M$D-&P`3`!<`&P`>0BNW@_^3\_?YX"!(D]=`#T`+0`=``$D-&J`2I!:H&JP>C +MX/_D_/W^$D-&HQ(E")"*[Q)#4Y"`EA(E")"*Z>#^H^#_$BL(@#:0BNW@_J/@ +M)`#_Y#[^D(KF\*/O\!(R%8`=D(KMX/ZCX"0`_^0^_I"*YO"C[_`2,8*`!'\` +M@`)_`=#0DJ\BCP_DD(KS\.4/%/Z0BO/@_\.>4`[O!/T2+4V0BO/@!/"`Y>4/ +M%/]]_Q(M39"*\^4/\)"*\^##E/]0#^#_!/T2+4V0BO/@!/"`Z*T/?_\"+4W3 +M$*\!P\#0Y)"*W?"C=`3PH^3PD(KB\*/PD`()X)"*X?`2)&+_D(KAX"^0BN#P +M,.`+D(K;Y/"C=(#P@`?DD(K;\*/PD(K@X,,3D/T0\)"*W>`D(/"0BMNCX/VC +MX/PM_R0!]8+D-/SU@^"0BOWP=`(O]8+D-/SU@^#^["TD`_6"Y#3\]8/@)`#_ +MY#Z0BO[PH^_PD(K:=`3PD(K;H^#_H^`O_Y"*VN#^+R0`]8+D-/SU@^#_=/PN +M]8+D-(KU@^_PD(K:X`3PX+0(SQ&)[W!%D`'#X&`KPY"*X^"4Z)"*XN"4`T`) +MD`'&X$00\(!YD(KBY'7P`1)"@7\*?@`2,A6`SY`!QN"0`<,PX@5T_O"`5W3_ +M\(!2D(K=X+1X+N3PD(K@X`3PD(K;X'`$H^!D@)"*VW`%\*/P@`;D\*-T@/"0 +MBN#@PQ.0_1#P@`>0BMW@)`CPD(K>=/_U\!)"@9"*WN!P`J/@8`)A%M#0DJ\B +M$B1BD(L%\)```1)"()"+!O`BY/5A(I%*D(LS=`+P(I`%(G3_\']X?@@2(F60 +MBQP2)0A_!'X,$B)ED(L@$B4(?P!^"!(B99"+)!(E")"+">"0BQRT`0T20U/O +M5,?_[53'_8`'$D-3[U3'_^R0@)82)0A_>'X($BL(D(L@$D-3[U0/_^R0@)82 +M)0A_!'X,$BL(D(LD$D-3[T0"_^R0@)82)0A_`'X($BL(?W!^#A(B99"+*!(E +M")"`EA(E%``;):!_<'X.$BL(D(!H$B44`````.3]_Q(P+)"+">"T`1&0@&@2 +M)10`````Y/U_`1(P+)``$>!4]O`"4@Z14)"+,W0"\"*0!2)T__"0BS-T!/`B +ML4*0BS-T!/`BD``1X$0)\!)2#I"+'!)#4Y"`EA(E"']X?@@2*PB0BR`20U.0 +M@)82)0A_!'X,$BL(D(LD$D-3D("6$B4(?P!^"!(K")"+*!)#4Y"`EA(E"']P +M?@X2*PB0@&@2)10``RV5Y/W_$C`LD(L)X+0!$9"`:!(E%``#+97D_7\!$C`L +M(I"++>!D!F`\Y2)4#Q1@+A1@'B3^8`XD^'`JY)"++?"0!2+P(I"++70!\)`% +M(N3P(I"++70#\)`%(G3_\"*0`<;@1`CP(JX'Y/\23>#O8!B0BRS@Q!,35`,@ +MX`RO!GT!$D6BL<%_`2)_`"*0`5?@8#R0`5?D\)`!/'0"\)"+&^!@!^3P4R7] +M@"20BPS@!/!3)>^0BQ#@_Y"+#.#3GT`.Y2&T`0F0BPW@<`/@!/"0`5O@8!"0 +M`5OD\)`!/'0$\.20BQCPD`%?X&`0D`%?Y/"0`3QT"/#DD(L7\"+DD(M/\*/P +MD`7XX'`/H^!P"Z/@<`>CX'`#?P$BTY"+4."4Z)"+3^"4`T`#?P`B?S)^`!(R +0%9"+3^1U\`$20H&`Q@#[F``` ` end diff --git a/sys/contrib/dev/rtwn/rtwn-rtl8812aufw.fw.uu b/sys/contrib/dev/rtwn/rtwn-rtl8812aufw.fw.uu new file mode 100644 index 000000000000..0d58e4030cee --- /dev/null +++ b/sys/contrib/dev/rtwn/rtwn-rtl8812aufw.fw.uu @@ -0,0 +1,716 @@ +begin 644 rtwn-rtl8812aufw.fw.uu +M`940`!D````'(Q,D''T``/X)```````````````````"2Z`":%0````````` +M`````````FES``````````````````)P_0`````````````````````````` +M`````````````FC7```````";Y@``!7P_P\````5\`\`````!?#_#P````7P +M#P`````0\/\/````$/`/`````/4/``````#P#P``````#0```````!#P__\` +M```0\#\`````%?`_`````!7PS_\````6#1<.%P\8$!D1&A(:$QH4&A4;_Q<. +M&!`9$1(:&Q4<_QW_'O\?____%`T.%14/%A`7$1@2&!,8_Q4-%A`0%Q@2&?\: +M_QO_'/\`````!`0,#`T,#@T7#Q@0&1$9$1D2&A0,#!8-%P\8$!D3&A0;%1P; +M'1P>'00$#!0-%`X4#Q40%A<1$A<,#!0.%0\6$!<2&!@9&1H9"@@#`P`$"0<# +M`P`$"`8#`@`$"`4#`0`$#0H'!0`(#`H'!``("PH&!0`("PH%`P`("PH#`@`( +M%!(,!``0%!()!``0)"(<$@`@)"(8#``@)"(4!@`@)"(/!``@)"$*!``@(R$, +M!``@(Q\*!``@(A\/!``@(1\6#``@,2\@%``P,2\8$``P,2P8#``P,2H4#``P +M,2@4```P,204```P,1X4```P!`0$!00$!0<'!P@*!`<*#A$3%!4#!`<'"`L- +M#P4%!P<("PT/!04'!P@+#0\'"`@*"@P.$!$1!PD)"PL-#Q$1$@4%!P<("PT/ +M#P\%!0<'"`L-#P\/!`0$!0<'"0D,#A`2!08'#1`1$A('"`D)#`X1$PD)"0D, +M#A$3"0D)"0P.$1,%!@@)#`X2$A,4!P@*"PT0$1$4%@D)"0D,#A$3$Q,)"0D) +M#`X1$Q,3````````````)"8J````'R$E)R@`````(R8H*@`````C)B@J```` +M`",F*"H`````("4G*2DJ`````"`E)RDI*@`````C)B@J*BH````?(R8H*BHJ +M````!`````0````(````$````!@````D````,````$@```!@````D````,`` +M``#8````/````&0```!X````H````/````%````!D````>````"@````\``` +M`4````&0```"6````R````2P```&0````,@```$8```!X````M````/H```$ +ML```!D````?0````R````1@```'@```"T````^@```2P```&0```!]`````\ +M````9````'@```"@````\````4````&0```!X````E@```,@````R````1@` +M``'@```"T````^@```?0```+N```$X@``!=P```?0````,@```$8```!X``` +M`M````/H```$L```!D````?0```'T```!]````#(```!&````>````+0```# +MZ```!+````9````'T```!]````?0``(``@`$``@`#``2`!@`)``P`$@`8`!L +M`!0`,@`\`%``>`"@`,@`\`!0`'@`H`#(`2P!D`)8`R``9`",`/`!:`'T`E@# +M(`/H`&0`C`#P`6@!]`)8`R`#Z``>`#(`/`!0`'@`H`#(`/`!+`&0`&0`C`#P +M`6@!]`/H!=P)Q`NX#Z``9`",`/`!:`'T`E@#(`/H`^@#Z`!D`(P`\`%H`?0" +M6`,@`^@#Z`/H`@0&"`H,$!@@,$!0`0$!`@$"`P,$!`4%`@0&!P<("`@"`@,# +M!04&!@4&!@<'"`D*!08&!P<("0H!`P8'!P<("`H*`@4&!P<'"`@*"P4&!@<' +M"`D*"@L%!@8'!P@)"@H+`0$!`0$"`P0%!@<(`0(#!`4&!P@"!`8'"`H+#`,% +M!@<("@L,!08'"`D*"PP"!`8'"`D+#`P,`P4&!P@)"PP,#`4&!P@)"@L,#`P% +M!@<("0H+#`P,&08$`@`8!2(%4`51"P`("`D,#``.``C$"#@(+`Q<#&`,9`QH +M#+@,L`RT#EP.8`YD#F@.N`ZP#K0,``R4#(@,C`SH#!`-``R0#,0,R`S,#-0, +M@`R$#@`.E`Z(#HP.Z`X0#4`.D`[$#L@.S`[4#H`.A``!!`(#!0#G"?8(W_J` +M1N<)\@C?^H`^B(*,@^<)\*/?^H`RXPGV"-_Z@'CC"?((W_J`<(B"C(/C"?"C +MW_J`9(F"BH/@H_8(W_J`6(F"BH/@H_((W_J`3(#2@/J`QH#4@&F`\H`S@!"` +MIH#J@)J`J(#:@.*`RH`SB8**@^SZY).CR,6"R,S%@\SPH\C%@LC,Q8/,W^G> +MYX`-B8**@^23H_8(W_GL^JGP[?LBB8**@^SZX*/(Q8+(S,6#S/"CR,6"R,S% +M@\S?ZM[H@-N)@HJ#Y).C\@C?^8#,B/#O8`$.3F##B/#M)`*T!`!0N?6"ZR0" +MM`0`4*\C(T6"(Y!&4'/%\/BCX"CPQ?#XY8(5@G`"%8/@./`BNP$*B8**@^#U +M\*/@(E`&A_`)YQDBN_X'X_7P">,9(HF"BH/DD_7P=`&3(KL!$.6"*?6"Y8,Z +M]8/@]?"CX")0">DE@OB&\`CF(KO^"NDE@OCB]?`(XB+E@RKU@^F3]?"CZ9,B +M[RO_[CK^[3G][#C\(N];_^Y:_NU9_>Q8_"+O2__N2O[M2?WL2/PBZY_U\.J> +M0O#IG4+P[&2`R&2`F$7P(NN?]?#JGD+PZ9U"\.B<1?`BNP$'B8**@P)(2U`% +MZ?@"2,>[_@7I^`)(TXF"BH,"2%>[`0WE@BGU@N6#.O6#`DA+4`?I)8+X`DC' +MN_X'Z26"^`)(T^6"*?6"Y8,Z]8,"2%>[`0>)@HJ#`B=(4`7I^`)(W[O^!>GX +M`DCK(KL!#>6"*?6"Y8,Z]8,")TA0!^DE@O@"2-^[_@?I)8+X`DCK(N#\H^#] +MH^#^H^#_(N23_'0!D_UT`I/^=`.3_R+@^*/@^:/@^J/@^R+DD_AT`9/Y=`*3 +M^G0#D_LBI"6"]8+E\#6#]8,BX/NCX/JCX/DBZ_"CZO"CZ?`BT(/0@OCDDW`2 +M=`&3<`VCHY/X=`&3]8*(@^1S=`*3:&#OHZ.C@-_F_`CF_0CF_@CF_R+B_`CB +M_0CB_@CB_R+L]@CM]@CN]@CO]B+L\@CM\@CN\@CO\B+"KX#^,A)(^X70"W70 +M"*K@PHSEBB1G]8KEC#1Y]8S2C.PDA_CFO`("=/_#E8&T0`!`SGD#>(`6Y@AP +M"\*OYC#A`T08]M*O"-GMZHO0(N4,_R,D@?@/"`B_`P1_`'B!YC#D\@#E#,.? +M4"`%#'2&)0SXYOVF@0CFK@R^`@)T_\WXZ&U@X`CFP."`]N4,TY]`)^4,)(?X +MYJX,O@("=/_]&.;-^.6!;6`&T.#V&(#UY0PDALCV%0R`T^4,(R2!^'\$PJ_F +M,.`#$.(,?P`PX0(#V"/8(W_IX@78PD$QB=`&3P.#DD\#@0XD!=8I@=8QYTHS2KR("[].4`D`# +M?_\B=($O+_CF(.7TPJ_F1##VTJ^N#.[#GU`A#G2&+OCF^0CF&+X"`G3__>UI +M8`D)YQD9]PD)@/,6%H#:[M.?0`0%@06![M.?0")TAB[X".;Y[K4,`JF!&`8& +MYOWM:6`)&1GG"0GW&8#S'H#9[R2&^.8$^.\O!)!,8I/V".\OD_9_`"+OTY0" +M0`-__R+O(R2!^.8PY?3"K^94C/;2K^4,M0<*=(8O^.;U@0))1%`N=(`O@!!IKH`0::[`$&F +MO`!@)J8<`0(#!`4&!P@)"@L,#0XD*"PP-#@\0&1H;'!T>'R`A(B,E9F=H:5! +MIN(`0:;E`$WH4`A7\=,0KP'#P-#DD*2!\)"DAO"0I(3PD*2$X/_#E`)``J$7 +MPW3]G_]T`Y0`_GL!>J1Y@!(SQ^]D`6`"H8"0I(#@_U3`_F`%[U0,P%ZI'F%$C/'[V0! +M<$*0I(7@_U3@_G`3[U0.<`B0I(3@8#6``)"DAG0!\)"DAN!P">[$$U0'H_"` +M#)"DA>!4#L,3D*2'\)"DA^"0I'[P@!"0I(AT`?"`0)"DA.`$\(",D*1]X"7@ +M)>!4#/^0I'S@5`-/_Y"D?N#^Q%1P3T2`_7^+$CJ6D*1\X&`(H^!@!*/@<"&0 +MI(AT`_"0`<1T:/!T3*/PD*2(X)`!R/#D_7\?$CJ6@.70T)*O(I``@.!$@/U_ +M@!(ZEM'$$CJX$G>`T;A_`5$,D*.]=`+P_U$,D*.]X`3PT3'19I%HD`"`X$1` +M_7^`$CJ6=2C_T9L2=[#1HN3_0971K)"B*N_PT4.0`61T`?`"-97QI1)W3_$5 +M\33Q4^3U47526*M1?0)_`1(Y!*M2?0-_`0(Y!-&5T=$2>U(2F_$2NF[1W]'N +M\0"0I'1T__#DH_"C\*/PH^!4_$0"\.2C\*/PH_`BY)"C'?`B=>@#=:B%(I`! +MY'09\*/D\"*0`/#@?P$@X@)_`R+DD*(F\*/PH_"C\"*0`93@1`'PD`''Y/`B +MY)"C&/"C\)"B@/"C\"*0H[G@5/[PY*/PH_"C\"*0H[[@5/[P5'_PHW0*\.2C +M\"*0H\'@5/[PHW0#\*/PY*/PH_"C\")U71+D]5YU7P=U8'*0`3#E7?"CY5[P +MH^5?\*/E8/`B=64.=68!=6<#=6ABD`$XY67PH^5F\*/E9_"CY6CP(N3U5?56 +M]5=U6("M57]0$CJ6K59_41(ZEJU7?U(2.I:M6']3`CJ6\0`2)A[_5`'^D*/! +MX%3^3O#OPQ,PX!20``$2)C>0H\+PD``"$B8WD*/#\"*0`3#D\*/PH_"C\)`! +M./"C\*/PH_#]?U`2.I;D_7]1$CJ6Y/U_4A(ZEN3]?U,".I;3$*\!P\#0D*2= +M[_"C=`+PD`'$=-7P=$^C\)"DGN"0`!D`?`D")`!Q/!T4*/P$CKKOP$#$C%ID*.AX&`.D*.DX/^0HZ/@;V`" +M$4["KQ)X$[\!`E&PTJ]1NQ))1("_D*.CX/]]`8`$?0%_!-,0KP'#P-"0IN3M +M\)"CGN#^Q!,35`,PX`(AI^[$$Q,35`$PX`(AIY"CI.#^;W`"(:?O<`(A'"3^ +M<`(A5B3^8$DD_'`"(9$D_&`"(:?NM`X"41B0HZ3@<`1_`5%`D*.DX+0&`C'R +MD*.DX+0$#Y"FY.#_8`42O`F``Q)R5)"CI.!D"&`"(:?11B&GD*.DX'`$?P%1 +M0)"CI."T!@(Q\I"CI."T#@0HZ3@M`X',:R_`0)1&)"CI."T!@(Q\I"CI."T#`X!,3$U0?,.`(D`&X=`+P +M@!F0HZ/@TY0$0`B0`;AT"/"`")`!N.3P?P$BD`&Y=`+P?P`BD*.?X)`&!"#@ +M#.!$0/"0HZ1T!/"`"N!4?_"0HZ1T#/"0!2+D\"*0HY_@PQ,@X`B0HZ1T#/"` +M$9`&!.!$0/#@1(#PD*.D=`3PD`4BY/`BD*;C[_#15)"FX^!@!9`%(N3PD*.D +M=`3P(I"C'>!D`7`MD*.?X%3]\)`%(G1O\'\!\::_`0Z0HY[@1(#PD*.D=`[P +M(I`!N70!\)`!N`3P(I"CH>!D`7`8D*.@X%0/8`CD_7\,$5OA:I"CI.!P`A%7 +M(I"CGN`PX`,2>IXB$IMF$IJE<133$*\!P\#0Y/^0IGSPD`''X&2M<#?PD*:) +M=`_PD*9[=`KPH^`$\)"F?.`O_G1]+_6"Y#2F]8/N\`_OM`_ID`$_=`3P>P%Z +MIGE[$EC[T-"2KR+3$*\!P\#0D`"/X"#F`J&CD`",X)"FP_"0`(W@D*;$\)`` +MCN"0IL7PD*;$X"3^8"(48"@48"\D_'`"@9@D\G`"H50D%6`"H960IL/@_Q*; +M!:&5D*;#X/^QUJ&5D*;#X/\2FYBAE9"FP^`DEO6"Y#29]8/@^^3]_[&ND*;# +MX'7P!)"6&1)(@^`3$U0#^PWD_[&ND*;#X'7P!)"6&1)(@^#$$Q,35`'[#>3_ +ML:Z0IL/@=?`$D)89$DB#X,14`_L-Y/^QKI"FP^!U\`20EA822(/@^^3]#[&N +MD*;#X'7P!)"6%[&HD*;#X'7P!)"6&!)(@^#$$U0!^PU_`;&ND*;#X'7P!)"6 +M&!)(@^!4'_L-L:Z0IL/@=?`(D(D`$DB#X/OD_0^QKI"FP^!U\`B0B0&QJ)"F +MP^!U\`B0B0*QJ)"FP^!U\`B0B0.QJ)"FP^!U\`B0B0022(/@^^3]#[&ND*;# +MX'7P")")!;&HD*;#X'7P")")!K&HD*;#X'7P")")!Q)(@^#[#:&3D*.AX/OD +M_?^QKI"CH.!4#_L-L:Z0HZ/@^PVQKI"CI.#[#;&ND*;#X"0=]8+D-*/U@^#[ +MY/T/L:Z0HY[@5`'[#;&ND*.>X,03$U0!^PU_`;&ND*.>X,03$Q-4`?L-?P&Q +MKI"B*.#[Y/T/L:Z0HBG@^PVQKI"CJ.#[#;&ND*.GX/L-L:Z0HZ#@Q%0/^^3] +M?P.QKI"CG^`3$U0!^PU_`[&ND*.?X!,3$U0!^PU_`[&ND*.>X!,35`'[#7\# +M@#^0I'3@^^3]_[&ND*1UH^#[#;&ND*1WX/L-L:Z0I'C@5`/[#;&ND*1YH^#[ +MY/T/L:Z0I'G@^PVQKI"D>^#['0^QKI``C^`PX`?D_7^-$CJ6T-"2KR(22(/@ +M^PWO<`1T\(`6[[0!!'3T@`[OM`($=/B`!N^T`PQT_"WU@N0T`O6#Z_`BD*;7 +M[_"0`(_@,.9CD`"-X&0"<%N0IMCPD*;8X/V0IM?@=?`(I"0`]8+D-(#U@^6" +M+?6"Y#6#]8/@^^3_L:Z0IMC@!/#@PY0(0,Z0IMC@_<.4$%`-Y/O_L:Z0IMC@ +M!/"`Z9``C^`PX`?D_7^-$CJ6(M%4D`4BY/"0HZ1T#/`BTQ"O`X$0(\"+3$*\!P\#0CR20!!W@8!^0!2+@]2=T__`29G>_`0BO)!*\ +MKQ)G%I`%(N4G\(`#$F<6D`0?="#P?P'0T)*O(N3_@+Z0HZ'@8`)1CR+D^_K] +M?P$22T60I(WO\&#PD*(GX/^0HB;@_D]@X\*O[C#@"U3^\.3_$FQW$HI,TJ_" +MKY"B)N#_,.$%5/WP$9?2K\*OD*(FX/\PX@54^_`11=*O@+S3$*\!P\#0Y/^0 +MHQG@_I"C&.#]M08$?@&``GX`[F0!8"SM=?`/I"2"^72B-?#Z>P$1^W\![V`6 +MD*,8X`3PX+0*`H`"?P#O8`7DD*,8\-#0DJ\BTQ"O`#_D**`X+4' +M!'\!@`)_`.]P0Y"B@.#^=?`(D*(P$DB#X/WN=?`(I"0Q^72B-?#Z>P&O!3%Q +MD**`X`3PX'\`M`H"?P'O8`7DD**`\!)SE9"B)N!$`O#0T)*O(M,0KP'#P-"0 +MIK(22)A_EGX"$G33[V!:D`$7X/Z0`1;@?``D`/_L/O[O)`'_Y#[^D*:U[_#N +M_Y#]$?"0IK7@_9`"E/"C[_"0IK(22(^0``X2)C(26>H46?(@6?LA6@0C6@PE6A0G6AU`6CA!6B9"6B]#6D%%6DF'``!:49"D +MCA)(CP)Q29"DCA)(CP)QD9"DCA)(CP)R9Y"DCA)(CP*Z$)"DCA)(CP)/>9"D +MCA)(CX!OD*2.$DB/X;Z0I(X22(\"_Y"C'/"_`0@2=I7DD*,< +M\"*0``$2)C>0H\?PD``"$B8WD*/(\!*B:W\!D*21=!'PD*2?=`'PD*23[_![ +M`7JD>9'QW7\$D*;?[_!_`A)+'I"B)N#_D*;?X/[O3I"B)O`BD*21$DB8$B8> +M_Y"DD1)(CY```A(F-Y"FJ/#D^_UQ`)"DE'00\)"DHG0'\)"DD1)(CQ(F'I"D +MEO![`7JD>93QW7\$@*&0IJ;M\*/K\)"FI>_PD*:HX/T2G820IJ7@PY0.4$:0 +MIFL2)U0?_@``D*9O$B=4$M0``']@?@C1JI"F61(G5``'`P"0IET2)U0````` +ML9^0IED2)U0`!P,`D*9=$B=4`````(&HD*:EX/]T)-.?4!OOE#!0%I"F:Q(G +M5!_^``"0IF\2)U0)*```@&N0IJ7@_W0RTY]0&^^40%`6D*9K$B=4'_X``)"F +M;Q(G5`BF``"`19"FI>#_=&33GU`;[Y1T4!:0IFL2)U0?_@``D*9O$B=4"*0` +M`(`?D*:EX/]T=M.?4!J0IFL2)U0?_@``D*9O$B=4""0``']@?@C1JI"FI>#_ +M="33GU`Q[Y1`4"R0IED2)U0`!P,`D*9=$B=4``$!`+&?D*99$B=4``<#`)"F +M71(G5``!`0"`<9"FI>#_=&33GU`Q[Y2,4"R0IED2)U0`!P,`D*9=$B=4``,! +M`+&?D*99$B=4``<#`)"F71(G5``#`0"`-9"FI>#_=(S#GU`RD*99$B=4``<# +M`)"F71(G5``%`0"QGY"F61(G5``'`P"0IET2)U0`!0$`?1A\`'\!L:60IJ7@ +M_Z/@_1*<1)"FIN!D`G!FD*:EX/_3E#!0")"FJ70J\(!P[].40%`(D*:I=#KP +M@&+OTY1P4`B0IJET:O"`5._3E(!0")"FJ71Z\(!&[].4D%`(D*:I=(KP@#CO +MTY2A4`B0IJETF_"`*N_3E+%0))"FJ72K\(``D +M`H`#X"3^D*:I\)"F61(G5````/^0IJFQDY"F61(G5````/^0IJF`')"F61(G +M5````/^0IJ6QDY"F61(G5````/^0IJ7@_^3\_?Z0IET2)TA]&'P`?P&`$N#_ +MY/S]_I"F71(G2'T8?`#D_Y"F5^SPH^WPD*96[_"CH^#]T1:0IF$2)TB0IED2 +M2$L2)Q60IF$22&<21WS`!,`%P`;`!Y"F61)(2Y"F71)(9Q)'?-`#T`+0`=`` +M$D>)D*9E$B=(D*97H^#]P`60IF422$N0K)82)TB0IE;@_]`%`CFZTQ"O`[PH^_P$C;.D*9S$B=(D*9K$DA+$B<5D*9S$DAG$D=\P`3` +M!<`&P`>0IFL22$N0IF\22&<21WS0`]`"T`'0`!)'B9"F=Q(G2)"F=Q)(2Y"L +MN1(G2)"F:>#^H^#_`C==D*4$[_"C$DB8D*9K$B=4@````)"F;Q(G5`````#1 +MII"E!1)(CQ)'O9"E2!(G2)"E!.#_?67QDY"E!1)(CY``!!)'W9"E2!(G2)"E +M!.#_?8_QDY"E!1)(CY``"!)'W9"E2!(G2)"E!.#_Y/WQDY"E2!(G5`````"0 +MI03@_WWO@`>0I03@_WWOTQ"O`"U!P1_`8`"?P#O8`F0`<'@1`+P +M@#7``9"C&>!U\`^D)(+Y=*(U\*@!_'T!T`%^`'\/$D;0D*,9X`3PX'\`M`H" +M?P'O8`7DD*,9\-#0DJ\B\.3U(I"CL^#U(^3[_7]4?@'3$*\!P\#0CAZ/'X4B +M.X4C/!(TC(4?@H4>@Z.CHW0%\-#0DJ\B,9C3D*1VX)0`D*1UX)0`0!/@_*/@ +M_>SU(HTCY/O]?UQ^`8"WD`%?Y/`BY)"E3_"0!JG@D*5/\.!4P'`-D*.EX%3^ +M\%3]\`)03I"E3^`PYB*0HZ'@9`%P(9"CI>!$`?"0HZ#@5`]D`F`$,1*`#!)7 +M58`'D*.EX%3^\)"E3^"0HZ4PYPW@1`(11Y"CGN!$!/`BX%3]\"*0!!W@_PY/W\$KS\?`"M +M!Y"FS>"0!"7PD*;.X&`.="$O]8+D-/SU@^!$@/"O!70@+_6"Y#3\]8/@5,#P +M="$O]8+D-/SU@^!4P/!T*2WU@N0T_/6#X%3W\*X$KP70T)*O(N3U!@-J!G0H+_6"Y#3\ +M]8/@M%0#$KE_=!0K]8+D-/SU@^#$$U0#_Y"D>.!4_$_PY7-4[Y`%(O"0!!]T +M(/"0I'GD=?`!$D;VD*1[=`'P(I"C'>!D`6`"00HY_@$Q,35!\PX`Z0HZ?@_Z/@M0<$L:Q1U")]`G\"4=A]`7\"=%TO +M^.;^[?1>_O9T,"_U@N0T`?6#[O`BD*/&X`3PD*.DX&0"8"A1.I"CG^`3$Q-4 +M'S#@%)"CI^#_H^!O<`JQK%'.D*.HX!3PD`'FX`3P(N]P,WUX?P)1V'T"?P-1 +MV'W(?P+1`9`!5^3PD`$\=`+P?0%_#!)06Y"CGN!4]_"0!@K@5/CP(I`!-G1X +M\*-T`O!]>/]QJGT"?P-QJI`&"N!$!_"0HZRCX)`%6/"0HQW@M`$5D*.?X%3[ +M\)"CI.`@X@Y]`7\$`E!;D*.?X$0$\")]`G\"=%TO^.9-_O9T,"_U@N0T`?6# +M[O`BD*.YX##@+9"CN^"0!7/PD*.\X&`$%/"!<9"CNN`4D*.\\)`%P%ZIGF;T<60IIO@1!@2>;G0T)*O +M(N\4D`5S\)`!/W00\/U_`W1E+_CF3?[V=#@O]8+D-`'U@^[P(JP'[U0!_I"C +MN>!4_D[P[Y`!4[0!$>3P?1!_`[&[D*.[X)`%<_`B=`/P?1#_T0$"5D9T92_X +MYO[M]%[^]G0X+_6"Y#0!]8/N\"*0HZ'@8"B0HQW@9`%P()"CJ/`$8!F0HZ7@ +M1!#PY/4BD*.I$4Z0HZ3@(.(#$E!7(I"DD1)(F/',D*.AX/]Q)Y"CH>!@&9"D +MD1)(CY```1(F-U0/_Y```A(F-_T2N]@BY)"FT?"C\)`%^.!P#Z/@<`NCX'`' +MH^!P`W\!(M.0IM+@E.B0IM'@E`-`"I`!P.!$(/!_`")_,GX`$CKWD*;1Y'7P +M`1)&]H"_>P%ZIGF:?0A_`9"FMA)(F.]P!Y"FN03P@`OO9`%P+I"FN71`\'_B +M$CJ6D*:YX/U_XQ(ZEI``X>#_D*:V$DB/[Q(F9.3]?^,2.I9_`2*0`<+@1`'P +M?P`BD*(MX/]]`3$LCB6/)JTFK"6O)!*\9*\FKB60@0#@5`_]K`=T#2SU@N0T +M_/6#X$0!\'0-+/6"Y#3\]8/@5/OPK`=T$BSU@N0T_/6#X$3Z\'01+/6"Y#3\ +M]8/@1!_PK`=T!BSU@N0T_/6#X$0.\)`$I^3PD`2F\)`$I73_\)`$I'3]\'04 +M+/6"Y#3\]8/@5,!-_704+_6"Y#3\]8/M\"(!?8]X?P(22QZ0HB;@17CP(A)S +ME7\"@.J0HY[@5/OPY)"CJO"0HZ7P(I"E1N_PH^WP^WT`?`#DD*5,\.N0I4?P +M?[!^"!(VSN3_[)"E2!(G2)"E2!)(9Y"E1^#_Y/S]_A)'B:,2)TB0I4@22$N0 +MK+D2)TA_L'X($C==?Q1^`!(Z]Y"E1N!U\`BD)'/U@N0TK_6#X/ZCX/\2-L[M +M5`_]Y/PBP.#`\,"#P(+`T'70`,``P`'``L`#P`3`!<`&P`>0`<1T5/!T:*/P +M$:-T5`20`<3P=&BC\-`'T`;0!=`$T`/0`M`!T`#0T-""T(/0\-#@,GL`>@!Y +M4^3]?P$2.3/E45)3>P!Z`'E4?0%_`1(Y,^524E2K4^3]?P$2.02K5'T!?P$" +M.03`X,#PP(/`@L#0==``P`#``<`"P`/`!,`%P`;`!Y`!Q'37\'1HH_`Q.>5< +M,.<",2UTUP20`<3P=&BC\-`'T`;0!=`$T`/0`M`!T`#0T-""T(/0\-#@,I`` +M!>!$@/U_!0(ZEI``5.!55?59H^!55O5:H^!55_5;H^!56/5_E83#D`Q)GQ>5A,.4"\5SE8S#@ +M`E$HY6,PX0,29`/E8S#B`Q)B\.5C,.,"T:KE8S#D`O$MY6,PY0+1XN5C,.8" +MT<;E9##A`Q)7Z.5D,.0"D77E9##E`E&DY60PY@)QJW1S!)`!Q/!T::/PT`?0 +M!M`%T`30`]`"T`'0`-#0T(+0@]#PT.`RY/^0HZ'@8'.0HQW@9`%P:Y"CH.#$ +M5`]@)"3^8`,$3U(I"CJN"`#>3U(I"CJN!U\`.D)/[_D*.IX"\2 +M8$^0HZ3@(.(#$E!7(N3U&I`$,."T`0:0!,]T,/!T'24:]8+D-*/U@^!P`F&? +MY1H3$Q-4'__E&E0'_G0!+_6"Y#24]8/@_:\&=`%^`*@'"(`%PS/.,\[8^?_O +M77`"89]U\!#E&I"!`1)(@^`@YP*`$'7P$.4:D($"$DB#X/\@YPF0`<'@1"#P +M@'_O,.8C=?`0Y1J0@0`22(/@_77P$.4:D($%$DB#X%0#D*:-\.3[@%-TIB4: +M]8+D-*#U@^`$\'2F)1KU@N0TH/6#X-.4`T`3KQJQHG2F)1KU@N0TH/6#Y/"` +M)G7P$.4:D($`$DB#X/UU\!#E&I"!!1)(@^!4`Y"FC?![`:\:$H?/!1KE&L.4 +M@%`"0:!$`O"`$)`$+>!$!O"`!Y`$+>!$#O#DD*1[\"+D_Y"E3^_PD`1^X/4;H^#U +M'&4;8'"0I5!T`_"0I5YT"/#E'`14#_4=Y/4:Y1UU\`BD)`#U@N0T@/6#Y8(E +M&O6"Y#6#]8/@_W12)1KU@N0TI?6#[_`%&N4:M`C0>P%ZI7E0$E_=Y1P$5`_U +M'+0/`^3U')`$?^4<\)"E3^!_!'`#`F>V$EJA(N3_D*5C[_#D]7!T9"5P]8+D +M-*7U@^3P=?`0Y7"0@0,22(/@_S#G"N5P#_ +MY#/^[R0>_^0^_NTEX"2F]8+D-)KU@^[PH^_P="8M]8+D-)_U@^#U'.4;TY4= +M0`.%'1MTIBWU@N0TH?6#X%2`0ANO!9"FC>4<\.3[K1L2A\^O&R)U\!#OD($# +M$DB#X$1`\"*0HQW@9`%P$Y"CH>!@#9`!5^3PD`$\=`(28$!@#I"CI>!4_O!4!W`#$E!.(I"C'>"T`1:0HZ'@8!"0HZ#@5`]D`F`#`F$2 +M$E=5(I`!-.!57?5AH^!57O5BH^!57_5CH^!58/5DD`$TY6'PH^5B\*/E8_"C +MY63P(I"C'>!D`7`FD*.AX&`@D`%7Y/"0`3QT`O"0HY[@5/OPD*.EX%3]\%0' +M<`,24$XBD`'/X)"E3_#@_S#@!Y`!S^!4_O#O,.4CD`'/X%3?\)`!-'0@\.3U +MJ/7H$D^ED``#X%3[_7\#$CJ6@/XBP.#`\,"#P(+`T'70`,``P`'``L`#P`3` +M!<`&P`>0`<1TF/!T;Z/P$G@ZY6DPX0,2>'GE:3#B`Q)XX.5I,.,#$F>TY6HP +MX`,2>/OE;##A!7\$$F>VY6PPY`,28_3E;##E`Q)P*>5L,.8"$:]TF`20`<3P +M=&^C\-`'T`;0!=`$T`/0`M`!T`#0T-""T(/0\-#@,I"CGN#_Q!,35`,PX"?O +M5+_PD`3@X)"CGS#@!N!$`?"`$.!4_O"0`;ET`?"0`;AT!/`24$[D_Y"CP>`P +MX$B0H\7@_6!!=`%^`*@'"(`%PS/.,\[8^?^0!.#@^^];8`;DD*/%\"*0H\/@ +MTYU0$)`!QW00\!'MD*/!X%3^\"(25^20H\7@!/`BD*.>X/_$$Q,35`$PX"SO +M5'_PD`3@X)"CGS#A!N!$`O"`#^!4_?"0`;ET`?"0`;@$\)"CH>!@`Q)03G\! +M`5^0HBK@9`)@!Y`&D.!$`?`BP.#`@\""P-!UT`#`!<`'??V0`<3M\'1P_Z/P +M[020`<3PH^_PT`?0!=#0T(+0@]#@,I"FX._P?P(22QZ0HB?@_Y"FX.#^[TZ0 +MHB?P(I`"">#]$B8>_J\%[2Z0HBOPD``!$B8W_^TOD*(L\)```A(F-__M+Y"B +M+?"0``,2)C?_[2^0HB[PD``$$B8W_ZX%[2^0HB_P(I"DD1)(F)```1(F-__^ +M$B8>_<,3,.`2D*21$DB/D``"$B8WD*25\(`%D*25[_"0I)3N\)"DE>#^D*24 +MX/_3GE`XD*21$DB/$B8>5`'^=!TO]8+D-*/U@^[P=!TO]8+D-*/U@^!P!%%# +M@`>0I)3@_U$RD*24X`3P@+J0HQW@<"&0HZ3@<`3_$E)`D*.DX&0,8`)15)"C +MGN!4]_!4O_!4?_`BCP]U\!#OD($%$DB#X%3[\"*/#W7P$.^0@0422(/@1`3P +M(I`&!.!4?_"0!2+D\)"CI'0,\"+3$*\!P\#0$B8>_Y"CG?"_`1*0``$2)C=D +M`6`7D`4B=&_P@`^0``$2)C=D`6`%D`4BY/#0T)*O(A(F'O]4?Y"CH?#OQ!,3 +M$U0!H_"0``$2)C?_5/#$5`_^D*.@X%3P3O"0``,2)C=4`27@_I"CGN!4_4[P +M[U0/Q%3P_Y"CH.!4#T_PD``$$B8WD*.C\!)F2)`!N70!\)`!N/"0HZ'@D`&Z +M\)"CH^"0`;OPD*.@X%0/D`&^\"*0``(2)C?_,.`F$B8>D*.R\)```1(F-Y"C +ML_#O5/[_H^!4`4_PD``#$B8WD*.U\"*0H[)T`?"C=`7PH^!4`40H\*-T!?`B +M$B8>5`'_D*.YX%3^3_"0``$2)C>0H[KPD``"$B8WD*.[\)"CNN"0H[SPD*.Y +MX%0!_P)ET)`!S.!4#Y"FR?"0ILG@_7`"@=*0HH#@_W`&H^!D"6`*[Q3_D**! +MX+4'!'\!@`)_`.]@")`!P>!$`?`BD*:ZX/]T`7X`J`<(@`7#,\XSSMCY_^]= +M<`*!P>20ILKPD*;*X/G#E`10]P`F&?Y)"B@?!AGY`!P.!$`O"0 +MIKK@1("0`(KP(M,0KP'#P-"0IJKN\*/O\.2C\*/PD*:JX/ZCX/6"CH/@8"W# +MD*:MX)3HD*:LX)0#0`N0`<#@1(#P?P"`%9"FK.1U\`$21O9_"GX`$CKW@,5_ +M`=#0DJ\BTQ"O`@%YH!(T+)"FO1)(CY``#A(F-Y`!KO"C +M=/_PD`'+X&2`\-#0DJ\BY/SM+"0`]8+D-/OU@^3P#.RT&.YT`"WU@N0T^_6# +M[_#N5#__=`$M]8+D-/OU@^_P=`(M]8+D-/OU@^!4\/!T`RWU@N0T^_6#X$2` +M\'0++?6"Y#3[]8/@1!#P(I"FKN_PHQ)(F)"FN^#^!/"0``'N$B9V=``O^>0T +M^_I[`<`#P`+``9"FKQ)(CXM`BD&)0G5#`M`!T`+0`Q(T+)"FKN`D`OGD-/OZ +M>P'``\`"P`&C$DB/Z20"^>0ZBT#U08E"D*:O$DB/D``.$B8W]4/0`=`"T`," +M-"R0I)QT$O"0I*IT!?"0I)[O\*/M\*/K\)"DFN"0I*'PD*2;X)"DHO![`7JD +M>9P27]U_!`):H7L!>J1YD7_U?@,2,\>_`0:0I)'@H_![`7JD>9%_]GX#$C/' +MOP$(D*21X)"DD_![`7JD>9%_]'X#$C/'OP$(D*21X)"DE/![`7JD>9%_\WX# +M$C/'OP$(D*21X)"DE?![`7JD>9%_\GX#$C/'OP$(D*21X)"DEO"0I)+@_Z/@ +M_:/@^Z/@D*2:\)"DEN"0I)OPP6"0IL`22)CD_Y"FP!)(CX^"=8,`$B8W_G3P +M+_6"Y#0"]8/N\`_OM!#@(I`!-'3_\*/PH_"C\)`!//"C\*/PH_#]?U02.I9] +M_W]5$CJ6??]_5A(ZEGW_?U<".I:0`0'@1`3PD`&<='[PHW22\*-TH/"C="3P +MD`&;=$GPD`&:=.#PD`&9Y/"0`9@$\"+DD*2`\*/PD`&8X'\`,.0"?P'O9`%@ +M1<.0I('@E(B0I(#@E!-`#Y`!P>!$$/"0`<=T`_"`)Y"D@.1U\`$21O9_%'X` +M$CKWTY"D@>"4,I"D@."4`$"RD`'&X##CJY`!QW0%\")_`I"CO>#^[\.>4!CO +M)>`D@?CF,.0+D`&X=`CPH_!_`"(/@-Y_`2*0`3S@567U::/@56;U:J/@56?U +M:Z/@56CU;)`!/.5I\*/E:O"CY6OPH^5L\%.1WR*/>7\"$DL>D*(GX$5Y\"*0 +MHZ'@8`(1@B*0HY[@_Q,35#\PX!'O5/OPD*.EX%3]\%0'<$*`/9"CJN`$\)"C +MI>!4[_"0HZK@_[0!`H`$[[0"!I`%6.`$\)"CLN#_D*.JX-.?0`^0HQW@M`$+ +MD*.?X%3[\"(24$XBD*.AX&`4D`:2X##A`P)7:I"CGN!4]_`24$XB,420I5_O +M\)"CGC#@!N!$`?"`!.!4_O"0I5_@,.81D`$OX##G!.3P@`:0`2]T@/"0HY[@ +M,.`2D*.LY/"C=`3PD*.LH^"0!5CP(N20I6#PH_"C\)``@^"0I6#PD`"#X/Z0 +MI6#@_[4&`2+#D*5BX)1DD*5AX)0`0`V0`<#@1$#PD*5@X/\BD*5AY'7P`1)& +M]H#"TQ"O`!@&I`%(N!4D&`'D`'`X$0(\)`!QN`PX>1_`(`"?P'0 +MT)*O(OM]"'\!D*;/Z_#O<`:C=`/P@`OO9`%P-9"FT'1"\'_B$CJ6D*;/X/U_ +MX!(ZEI"FT.#]?^,2.I:0IM#@5/W]?^,2.I;D_7_C$CJ6?P$BD`'"X$0!\'\` +M(H]ZY)"FT_"C\)`!">!_`##G`G\![V5Z8#[#D*;4X)2(D*;3X)030`B0`<#@ +M1!#P(I"FT^1U\`$21O9_%'X`$CKWTY"FU."4,I"FT^"4`$"YD`'&X##@LB)Q +M#I``".!4[_U_"!(ZEN3_41"0HBK@M`,,D`!PX%1__7]P$CJ6(M,0KP'#P-!1 +MME%HT-"2KR*0HZ3@_V`#M`@-<1:_`0A1CI`!Y>`$\"*0HBK@M`,,D`!PX$2` +M_7]P$CJ6D*.KX/U_DQ(ZEI"CHN!@$I`!+^`PYP5T$/"`!I`!+W20\)``".!$ +M$/U_"!(ZEG\!41"0`)#@1`']?Y`2.I9_%'X``CKWD`"0X"#@^2*0`H?@8`B0 +M`;AT`?"`)9`"EN!@")`!N'00\(`7D`*&X"#A")`!N'0$\(`(D`&XY/!_`2*0 +M`;ET"/!_`"+DD*2`\.20I('PD*2!X/_#E!!0=9"D@.#^)!;U@N0TF?6#X%3^ +M\.^0I(&T`QO@_W7P$.Z0@0`22(/E@B_U@N0U@_6#=(#P@!O@_Y"D@.!U\!"0 +M@0`22(/E@B_U@N0U@_6#Y/"0I('@_Y"D@.!U\`B0B0`22(/E@B_U@N0U@_6# +MY/"0I('@!/"`@9"D@.`$\.!D@&`"85?DD*]]\)"4D1(G5`````#DD*2`\)"D +M@.#_PY2`0`*A7^20I(+PD*2"X/[#E`50()"D@.!U\`J0C0$22(-U\`+N$DB# +MY/"C\)"D@N`$\(#6Y)"<)O"0I(#@_B0F]8+D-*#U@W0_\'0F+O6"Y#2<]8/D +M\'0!+O6"Y#23]8-TP/#N)>`D`?6"Y#22]8/D\*/P=!8N]8+D-)CU@^3P[B7@ +M)*;U@N0TG/6#Y/"C\.XEX"2F]8+D-)WU@^3PH_!U\`3ND)86$DB#=#_P=?`$ +M[I"6%Q)(@W0#\'7P!.Z0EA@22(/@5.!$"?"0I(#@_G7P!)"6&1)(@^!4\_!U +M\`3ND)89$DB#X%3\\)"D@.#^=?`$D)88$DB#X$0@\'7P!.Z0EAD22(/@5,_P +MD*2`X/YU\`20EAD22(/@1$#P=?`$[I"6&1)(@^!4?_"0I(#@_G7P!)"6%A)( +M@^#]=?`0[I"!`!)(@^WPD*2`X"06]8+D-)GU@^3PD*2`X`3P8?R0!$ET\/"C +MY/"C=/_PD`0S=`+PHW0$\*,$\*,$\*,$\'26+_6"Y#28]8-T__`B]8/DD_^0 +MI+3@_:P'[!,3$U0?_W7P".V0B0`22(/E@B_U@N0U@_6#X/MZ`.Q4!_]T`7X` +MJ`<(@`7#,\XSSMCY_^Y:_N];3G__8`*O!"*0I+3K\.]4?R3TD*2X\.UP29"D +MM>"0I+AP(.`EX"33]8+D-$"QC9"DMN_PD*2XX"7@)-3U@N0T0(!GX"7@)*OU +M@N0T0+&-D*2V[_"0I+C@)>`DK/6"Y#1`@$>0I+7@D*2X<"#@)>`D'_6"Y#1! +ML8V0I+;O\)"DN.`EX"0@]8+D-$&`'N`EX"3W]8+D-$"QC9"DMN_PD*2XX"7@ +M)/CU@N0T0+&-J0=_#'X2?1"0I+;@_/1@*NGT8";IPY]`(>G3G5`]8-T +M__"`#Y"DM.`DIO6"Y#2>]8/I\)"DMN#_(G[_=*8O]8+D-)[U@W3_\.VT/A%^ +MO72F+_6"Y#2>]8-T/?"`)>VT/R%U\`3OD)88$DB#X,035`]8-T/O"O!B+M5'_\[52`8`.O!"+LM#T"@!_LPY0^0"+LTY0_4!QU\`3O +MD)88$DB#X,035`#[[&M@1I"F2>OPH^[PK@7N)>!/H_"0ID;@D*9-\)"F1W0, +M\)"F570$\'L!>J9Y1Q)?W7\$$EJAD*9%X/^0ID3@));U@N0TF/6#[_`B[V`* +M[<.4+$`$?B"``N3^P^V>_R*0I*;O\)`!Q'0:\'2`H_"0I*;@_W7P$)"!`!)( +M@^"0I*?PY)"DK/"0I*?@_E1_^:/P[E2`^W7P!.^0EA822(/@D*2J\)"DIN#Z +M=?`$D)89$DB#X/_$5`.0I*OP=?`$Z9!"W1)(@Q)(5^HEX"25]8+D-)3U@^[P +MH^_PKP.0I*?@3_Z0I*;@_R2F]8+D-*'U@^[P=?`0[Y"!!1)(@^!4`_Z0I*GP +M="8O]8+D-)_U@^[P=!8O]8+D-)GU@^`PX#^0I*C@9#]P-W0^\'7P!.^0EA@2 +M2(/@_L035`0 +MI*;@_Z/@_1)_8._T8!"0I*?O\##G`F%ED*2GX*/PD*2HX/^T+2N0I*;@_G7P +M!)"6&1)(@^!4`_V0I*G@PYU0$9"DIW0L\)"DJ>`$\'2F+H`0[[0L&)"DIW0M +M\)"DIN`DIO6"Y#2>]8-T__!A99"DJN#_D*2HX/W#GT`"0?B0I*O@_Q$&D*2H +M[_"0I*O@_Y"DJN#]$0;O\)"DJ.#_TY0+0!F0I*;@^Y"DJ^"0I+7PY/T2?=J0 +MI*?O\(`6D*2G=/_PD*2FX"2F]8+D-)[U@W3_\)"DI^#T8`)!?9"DIN`DIO6" +MY#2>]8/@]'!\D*2HX`3]D*2JX/_MTY]0;.T3$Q-4'_^0I*;@_'7P")")`!)( +M@^6"+_6"Y#6#]8/@^WH`[50'_W0!?@"H!PB`!<,SSC/.V/G_[EK^[UM.8"F0 +MI*C@M!,7=!CPD*2G\'06+/6"Y#29]8/@1`3P@`Z0I*CM\)"DI_"``PV`BI"D +MJ^#_D*2GX/UQ?^_PD*2FX"2F]8+D-)[U@^#]]&`6D*2KX/]Q?Y"DIN`DIO6" +MY#2>]8/O\)"DIN#_)!;U@N0TF?6#X"#@`F%ED*2HX&0_8`)A970^\'7P!.^0 +MEA@22(/@Q!-4!S#@")"DIW2^\(!WD*2HX)"DI_"`;9"DJN#_D*2HX/YO<$>0 +MI*;@^W7P!)"6&!)(@^#_Q!-4!S#@#9"DI^`@YP;N1(#P@#R0I*C@=?`$D$+= +M$DB#$DA7ZR7@))7U@N0TE/6#[O"C[_"`+9"DJN#_D*2FX"2F]8+D-*'U@^_P +MD*2G[_"0I*;@_Z/@_9"DJ>"0IHWP>P'QSY"DI^#_(N]@"NW3E`M`!'X@@`+D +M_NTN_R)]`:\/CQFL!9`!Q'26\'2#H_#E&27@)*;U@N0TFO6#Y/"C\'7P$.49 +MD($`$DB#X)"DI_"0I*;P5'^0I*SP=?`$Y1F0EA<22(/@D*2N\'7P!.49D)86 +M$DB#X/F0I*_P=?`0Y1F0@0422(/@5`.0I*CP^I"DK.#[)>`D+?6"Y#1$]8/D +MD_YT`9/_Y1DEX"25]8+D-)3U@^[PH^_P=?`$Y1F0EAD22(/@Q%0#D*2I\'2F +M)1GU@N0TH?6#Z_!T)B49]8+D-)_U@^KPD*2LX-.90!J0I*_@_Y"DK/"0I*;P +M=*8E&?6"Y#2>]8/O\.QP`L']D*2M[/"0I*;@,.<]8/O\)"DK>`4\)"DK>!P`L']D*2FX/VO&1)_%)"DL>_P]&`BX)"DIO"0 +MI*W@%/#@^7`-=*8E&?6"Y#2>]8/!Y*T!KQEQEI"DIN!D+'!-D*2HX/_3E`!` +M0^_3E`)0/>`4\)"DIG0M\)"DJ.!4`R7@)>#_=?`$Y1F0EAD22(/@5/-/\'2F +M)1GU@N0TGO6#=/_PD*2MX!3PX'`"P?V0I*;@M"THD*2HX-.4`E`?D*2F="SP +M=*8E&?6"Y#2>]8-T__"0I*W@%/#@<`+!_9"DK>!P`L']D*2NX/^0I*S@_M.? +M4`+!]>20I*OPD*2IX/^M!A$&D*2L[_"0I*;PD*2IX/^0I*[@_1$&[_"0I*;@ +MTY0+0!N0I*S@_Y"DJ>"0I+7PJQE]`1)]VI"DIN_P@`YTIB49]8+D-)[U@W3_ +M\'2F)1GU@N0TGO6#X/1@`L&=D*2FX)"DL/"0I*S@%)"DJO"0I*[@_Y"DJN## +MGT!\X/L3$Q-4'_]U\`CE&9")`!)(@^6"+_6"Y#6#]8/@_7P`ZU0'_W0!?@"H +M!PB`!<,SSC/.V/G_[ES^[UU.8#:0I*S@M!0(D*2P=`SP@`B0I*K@D*2P\)"D +MJ^`$\)"DK>#_D*2KX&]@%9"DKN#_D*2PX-.?0`B0I*K@%/"A^9"DL.#]=*8E +M&?6"Y#2>]8/M\)"DIN"T_P+M\)"DJ>#_D*2FX/UQ?^_P=*8E&?6"Y#2>]8/@ +M_O1@)I"DJ>#_K09Q?W2F)1GU@N0TH?6#[_!TIB49]8+D-)[U@W3_\(`W#E#M` +M8`Z`7>RT!`KMPY0Q0%-^`8!/=)8O]8+D-)7U@^#\M`,*[<.4&4`Z?@&`-NRT +M`@KMPY010"Q^`8`H=)8O]8+D-)7U@^#\M`$*[<.4"D`3?@&`#^QP"NW#E`-` +M!GX!@`+D_J\&(M,0KP'#P-"0IHKO\*/M\*/K\.20II/PD*:*X/\3$Q-4'Y"F +MCO#O5`>0II#PD*:*X'7P$)"!`1)(@^"0II'P=?`$[Y"6%A)(@^!4?Y"FE/"0 +MIHK@=?`$D)87$DB#X)"FE?#M5'^0IH_PZW!`X/LEX"0M]8+D-$3U@^23_G0! +MD__D_/UU\`3KD$+=$DB#$DAS$D=O>`$2)R*0IHK@)>`DE?6"Y#24]8/N\*/O +M\)"FE.#_D*:/X/[3GT`,D*:+X%2`_>]-\(`/D*:5X/_NPY]0!9"FB^_PD*:+ +MX/]4?_Z0IH_P_>]4@)"FDO"0IHK@_Q*'%I"FC.!P.9`$SW0P\)"FCN`D`?6" +MY#24]8/`@\""X/^0II#@_G0!J`8(@`+#,]C\]%_0@M"#\)"FD>!4?_"`;)"F +MBN#_)!;U@N0TF?6#X)`$SS#@!70@\(`"Y/"0IH[@)`'U@N0TE/6#P(/`@N#^ +MD*:0X/UT`:@%"(`"PS/8_$[0@M"#\'7P$.^0@0$22(/@5`?_D*:1\)"FC^"0 +M1.&3,S,S5/A/D*:1\$2`\)"FB^#_D*:*X/YU\!"0@0`22(/O\)"FD>#_=?`0 +M[I"!`1)(@^_P=?`0[I"!!1)(@^!4_/^0IHW@5`-/_I"FBN#_=?`0D($%$DB# +M[O!]`3&_T-"2KR+3$*\!P\#0[6!B=?`*[Y"-`1)(@^3PH_!U\`KOD(T#$DB# +MY/"C\'7P"N^0C0422(/D\*/P=?`*[Y"-!Q)(@^3PH_!U\`KOD(T)$DB#Y/"C +M\.\EX"0!]8+D-)+U@^3PH_!T%B_U@N0TF/6#Y/!U\!#OD($#$DB#X%2_1(#^ +M=?`0[Y"!`Q)(@^[PT-"2KR*0`<1T3/!TBJ/PY/4/=!TE#_6"Y#2C]8/@<`," +MDYUU\`3E#Y"6&1)(@^#$$Q,35`$PX`,"DYWE#R7@)`'U@N0TDO6#X/ZCX-.4 +M`.Z4`%`#`I.=Y0]U\`JD)`'Y=(TU\/I[`8L3]12)%>4/)>`D`?6"Y#22]8/@ +M_Z/@D*21S_"C[_!T%B4/]8+D-)CU@^#_D*23Y/"C[_"0``(21S?_KO`21PPO +M_^7P/OZ0``021S&`!Y"DC^"00C63D*29\)"DF>!U +M\`:D)#_Y=$$U\'40__41B1*0I([@D$4UD__3D*24X)^0I)/@E`!`!A*#D@*2 +MLL.0I)+@E`^0I)'@E`!09*L3JA2I%9``!A)'-_^N\)``"!)'-R_]Y?`^_)"D +MD>##$_ZCX!/_T^V?[)Y``N$OD*21X/RCX/VN!'@"SL,3SA/8^?NJ!NS#$_[M +M$RO_[CK^JQ.J%*D5$D<,TY_E\)Y0`N$RX0WE#Q,3$U0?D*2C\.4/5`>C\.#_ +M=`%^`*@'"(`%PS/.,\[8^4Y_`&`"?P&0I*/@));U@N0TFO6#X%]@=72F)0_U +M@N0TGO6#X/WT8#N0I)S@D*:-\'L!KP\2A\^0I*/@));U@N0TFO6#P(/`@N#_ +MD*2DX/YT`:@&"(`"PS/8_/1?T(+0@_#A,I"DH^`DEO6"Y#2:]8/`@\""X/^0 +MI*3@_G0!J`8(@`+#,]C\]%_0@M"#\)"DD>#^H^#_TY3H[I0#0`B0I)MT!?"` +M%M/OE,CNE`!`")"DFW0"\(`%Y)"DF_#E#R7@))7U@N0TE/6#X/46H^#U%^20 +MI*7PJQ.J%*D5D*2EX/UU\`*D]8*%\(,21S?_KO"0I)O@_.^H!`B`!<[#$\X3 +MV/G_JQ"J$:D2C8)U@P`2)C?]?``2)ICO)1?U%^XU%O46D*2EX`3PX+0%JZL0 +MJA&I$I``!1(F-_U\`)"DF^#_D*21X/ZCX*@'"(`%SL,3SA/8^?\2)IC3Y1>? +MY1:>0`SE%Y_U%^46GO46@`7D]1;U%W2F)0_U@N0TF_6#X&`0=*8E#_6"Y#2; +M]8/@%/#A,N4/)>`DE?6"Y#24]8/E%O"CY1?PKA:O%^3\_9"DC^!U\`200MT2 +M2(,22'/#$D>L0`+A%'01)0_U@N0TE/6#X/]TEB4/]8+D-)GU@^#^TY]``^Z` +M&G26)0_U@N0TF?6#X/]T$24/]8+D-)3U@^##GY"DG?"0I)W@TY0$0!/E#R7@ +M)*;U@N0TFO6#Y/"C\(`HY0\EX"2F]8+D-)KU@^#^H^!.8!3E#R7@)*;U@N0T +MFO6#=/_U\!)&]I"DC^!U\`200MT22(,22%?E#R7@))7U@N0TE/6#[O"C[_#E +M#R7@)*;U@N0TFO6#X/ZCX$YP):\/$H`:@!Z0I(_@)>`D+?6"Y#1$]8/3=`&3 +ME1?DDY460`,2@Y+E#R7@))7U@N0TE/6#H^"0ID;PD*2.X)"F1?"K#^3]_Q)_ +MG^3U%O47`I*&=*8E#_6"Y#2?]8/@^V0%8`,"D.J0I(_@_:\/$H=5=!8E#_6" +MY#2:]8/O\'7P$.4/D($!$DB#X%0'D*2>\'26)0_U@N0TF?6#X/_#E#!0%.20 +MI)[P=*8E#_6"Y#2?]8/D`I!G=!8E#_6"Y#2:]8/@9`%@`P*0D'0F)0_U@N0T +MG/6#X&0*8%'O)`7_Y#/^=($E#_6"Y#23]8/@_=.?[F2`^'2`F%`R[20%_^0S +M_G26)0_U@N0TF?6#X-.?[F2`^'2`F%`4="8E#_6"Y#2@]8/@_Y"DC^!O8#^0 +MI)[@_W`$!/"`#^^0I)ZT`05T`_"``W0%\'26)0_U@N0TF?6#X/]T@24/]8+D +M-)/U@^_P="8E#_6"Y#2<@"MTIB4/]8+D-)_U@^3P="8E#_6"Y#2<]8/@!/"` +M$N20I)[P=*8E#_6"Y#2?]8/D\)"DC^#_="8E#_6"Y#2@]8/O\'7P!.4/D)89 +M$DB#X,03$U0#(.`"05QT)B4/]8+D-)SU@^3PD*2>\'2F)0_U@N0TG_6#Y/!! +M7.MD!F`"08;U%O47=?`0Y0^0@0$22(/@5`>0I)[PD*21X/ZCX/_3E.CNE`-` +M")"DFW0%\(`6T^^4^NZ4`$`(D*2;=`+P@`7DD*2;\)"DF^#][Z@%"(`%SL,3 +MSA/8^?^018[DD_U\`!(FF)"DG^[PH^_PY/48JQ.J%*D5=?`"Y1BD]8*%\(,2 +M1S?_KO"0I)O@_>^H!0B`!<[#$\X3V/G_Y1B018F3_7P`$B:8[R47]1?N-1;U +M%L.0I*#@E1>0I)_@E19`!P48Y1BT!:KE&,,3]1B0I)[@)`'_Y#.BYQ/O$Y"D +MHO#3E1A`!N"5&/"`!>20I*+P=`$E#_6"Y#23]8/@PQ/_D*2BX,0S5.`O!/]T +M`24/]8+D-)/U@^_P=`$E#_6"Y#23]8/@PY3`0`YT`24/]8+D-)/U@W3`\'0! +M)0_U@N0TD_6#X,03$U0#D*2B\.`EX/!P`H`%D*2BX!20I)[PTY"DE."4`Y"D +MD^"4`$`%Y)"DGO!U\!#E#Y"!`1)(@^!4^/^0I*'PD*2>X$__D*2A\'7P$.4/ +MD($!$DB#[_!TIB4/]8+D-)_U@^#3E`5TIE`.)0_U@N0TG_6#X`3P@`LE#_6" +MY#2?]8/D\)"DD^#^H^#_PW3_G_UT_Y[\Y0\EX"2F]8+D-)SU@^#ZH^#3G>J< +MY0]0$R7@)*;U@N0TG/6#[H_P$D;V@!`EX"2F]8+D-)SU@W3_\*/PD*25X/ZC +MX/_#=/^?_73_GOSE#R7@)*;U@N0TG?6#X/JCX-.=ZISE#U`3)>`DIO6"Y#2= +M]8/NC_`21O:`$"7@)*;U@N0TG?6#=/_PH_"0I)?@_J/@^\-T_YO_=/^>_G3_ +ME`#]=/^4`/R0E)$22&?3$D>LD)214!D22&>0I)?@_J/@_^3\_1)';Y"4D1(G +M2(`'$B=4_____^3]KP\2B;\%#^4/PY2`4`,"BEDBTQ"O`20IJ'P_'7P".5TD(D`O`82 +M$DB#Y8(L]8+D-8/U@^!4#X`.$DB#Y8(L]8+D-8/U@^"0IJ/PD*:CX&`^Y/5U +M=`%^`*AU"(`%PS/.,\[8^?^0IJ/@^^];8!KL=?`(I"5UD*:A\.U@&>#3E`M` +M$^`D(/"`#05UY76T",4,[&0'<(>0IJ#@_W7P!.5TD)86$DB#[_"0IJ'@_G7P +M!.5TD)87$DB#[O!U\!#E=)"!`!)(@^#\5'_][%2`_.W3GT`%D*:@@`CMPYY0 +M!I"FH>!,_70F)73U@N0TH/6#[?!U\`3E=)"6&1)(@^`3$U0#D*:-\.3[KW02 +MA\]U\!#E=)"!`Q)(@^3PD*:@X/_#E#9`$'26)73U@N0TE?6#=`7P@&KOPY0L +M0!!TEB5T]8+D-)7U@W0$\(!4D*:@X/_#E!1`$'26)73U@N0TE?6#=`/P@#KO +MPY0,0!!TEB5T]8+D-)7U@W0"\(`DD*:@X,.4!'260`XE=/6"Y#25]8-T`?"` +M"R5T]8+D-)7U@^3PT-"2KR*0I)$22)@2)AY4?Y"DE/"0``$2)C?_5!^0I);P +M[U2`Q!,3$U0!D*25\)```A(F-_]4`Y"DE_#O5##$5`^0I)KPD``"$B8W_U1` +MQ!,35`.0I)CP[U2`Q!,3$U0!H_"0``(2)C?_5`C^$Q,35!^0I)OP[U0$$Q-4 +M/Z/PD*1]X+0""Y"DFN!@!>3_$D_5D*1^X+0!'9"DD1)(CY``!1(F-U3P<`B0 +M``82)C=@!7\!$D_5D*29X%0!Q#,S,U2`_Y"DE.#^=?`$D)89$DB#X%1_3_"0 +MI)C@5`'$,S-4P/]U\`3ND)89$DB#X%2_3_"0I)O@8`,"F$Z0I);@5!__D*24 +MX/YU\`20EA@22(/@5.!/\)"DE^!4`_]U\`3ND)89$DB#X%3\3_#O)>`EX/^0 +MI)3@_G7P!)"6&1)(@^!4\T_PD*25X%0!Q#-4X/]U\`3ND)88$DB#X%3?3_"0 +MI)K@5`/$5/#_D*24X/YU\`20EAD22(/@5,]/\'06+O6"Y#29]8/@5/OPD*24 +MX"06]8+D-)GU@\"#P(+@_Y"DG.`EX"7@_N].T(+0@_#D_^\D`_WD,_R0I)$2 +M2(^-@HR#$B8W_I"DE.!U\`B0B0`22(/E@B_U@N0U@_6#[O`/[[0$S9"DE.#_ +M$I.J(I"DD1)(F!(F'O4/)!;U@N0TF?6#X%2\\'06)0_U@N0TF?6#P(/`@N#_ +MD*21$DB/D``#$B8W5`'^[T[0@M"#\'06)0_U@N0TF?6#P(/`@N#_D*21$DB/ +MD``#$B8W5`+^[T[0@M"#\'06)0_U@N0TF?6#P(/`@N#_D*21$DB/D``#$B8W +M5$#^[T[0@M"#\.4/PY2`4!60``(2)C?_=)8E#_6"Y#29]8/O\"+E#[2`"I`` +M`A(F-Y"5E?`B$B8>D*21\)```1(F-Y"DDO"0``(2)C=4`?]@:)"DD>#3E(!` +M7Z/@TY2`0%B0I)7O\)"4D1)(2Y"DEN_PD)21$DA+>`@2)R*0I)?O\)"4D1)( +M2W@0$B_PD*23=`WPD*2A=`7PD)21$B=4 +M`````$&7[V`"09>0I)'@_].4@%!'D*25[_`EX"2F]8+D-)WU@^#^H^"0I);P +M[J/PD*21X/TEX"2F]8+D-)SU@^#^H^"0I)CP[J/P=?`0[9"!`!)(@^"0I)KP +M@`B0I)'@D*25\)"DDN#_TY2`4$>0I)OO\"7@)*;U@N0TG?6#X/ZCX)"DG/#N +MH_"0I)+@_27@)*;U@N0TG/6#X/ZCX)"DGO#NH_!U\!#MD($`$DB#X)"DH/"` +M")"DDN"0I)OPD*23=`3PD*2A=`SPD*21X/\EX"2F]8+D-)WU@^3PH_"0I)+@ +M_B7@)*;U@N0TG?6#Y/"C\.\EX"2F]8+D-)SU@^3PH_#N)>`DIO6"Y#2<]8/D +M\*/P>P%ZI'F3$E_=?P0"6J&0`(_@,.98D`"-X&0#<%"0`(_@_I``CN#][?^0 +MI(ON\*/O\.20I(KPD*2*X/W_D*2,X"__D*2+X#0`CX+U@^#[Y/\25:Z0I(K@ +M!/#@PY000->0`(_@,.`'Y/U_C1(ZEB+3$*\!P\#0D*;5[_"0`(_@,.9)D`"- +MX&0!<$&0IM;PD*;6X/V0IM7@=?`0D($`$DB#Y8(M]8+D-8/U@^#[Y/\25:Z0 +MIM;@!/#@PY000-&0`(_@,.`'Y/U_C1(ZEM#0DJ\BD`"/X##E*I``CN!D!7`B +MH^#_D`".X/YT`"_U@N0T@?6#[O"0`(_@,.`'Y/U_CA(ZEB*0I(KO\)``C^`P +MYDR0`(W@9`-P1)"DB_"0I(O@_9"DBN#$5/`D@/6"Y#2`]8/E@BWU@N0U@_6# +MX/OD_Q)5KI"DB^`$\.##E!!`SI``C^`PX`?D_7^-$CJ6(N3U#>3U#N4.M`,> +M_^4-Q%3P)(#U@N0T@/6#Y8(O]8+D-8/U@W1`\(`;Y0W$5/`D@/6"Y#2`]8/E +M@B4.]8+D-8/U@^3P!0[E#K00NP4-Y0VT"+$BD*;9[_"C[?"0`/'@5/!D(&`" +MH2B0IMK@M`$=D*;9X+0+%I"F:Q(G5```#`"0IF\2)U0```P`@!20IFL2)U0` +M``P`D*9O$B=4```(`'^L?@@27JJ0IMK@<"J0IMG@_V0-8`3OM`X=D*9K$B=4 +M```#`)"F;Q(G5````P!_K'X($EZJ@`Z0IMK@M`$=D*;9X+0+%I"F:Q(G5$`` +M``"0IF\2)U1`````@#F0IMK@9`)P`J%WD*9K$B=4```#`)"F;Q(G5````@!_ +MK'X($EZJD*9K$B=40````)"F;Q(G5`````!_Q(!*D*;:X'`ED*;9X/]D#6`$ +M[[0.&)"F:Q(G5````P"0IF\2)U0```,`?ZR`'Y"FV>#3E`Y0&Y"F:Q(G5``` +M`P"0IF\2)U0```(`?ZQ^"!)>JB*0!%3@?P`PYP)_`2*0IMSM\)"FV^_PTY0. +M4!6Q>.]@*;%X[V0!<"*0IMS@_>3_@!60IMO@TY0.0!"Q>.]P"9"FW.#]?P&` +M`[%X(I"FQ^WPD*;&[_!P=Y"F:Q(G5#````"0IF\2)U0`````=`C__A)>JI"F +M:Q(G5`````Z0IF\2)U0````(?S!^"!)>JI"F:Q(G5`````.0IF\2)U0````! +MT<20IFL2)U0P````D*9O$B=4,````'0(__X27JJ0!%3@5'^0ILCPX)`$5/`B +MD*;&X&0!<':0!%3@1("0ILCPX)`$5/"0IFL2)U0P````D*9O$B=4`````'0( +M__X27JJ0IFL2)U0````.D*9O$B=4````!G\P?@@27JJ0IFL2)U0````#D*9O +M$B=4`````M'$D*9K$B=4,````)"F;Q(G5"````!T"/_^$EZJ(G\T?@@27JJ0 +MIL;@_Z/@_9"FX>WP[V`"X=W@)/U0#6`I%&!$%'`"X7\"H<^0K+D2)U1W=W=W +M?[!^#!(W79"LN1(G5'=W=W<"H'"0K+D2)U14,W=P?[!^#!(W79"LN1(G5%0S +M=W`"H1:0K+D2)U1W=W=W?[!^#!(W79"LN1(G5'=W=W=_L'X.$C==D*9K$B=4 +M/_```)"F;Q(G5``0``!_M'X,$EZJD*9K$B=4/_```)"F;Q(G5``0```"HJI"F:Q(G5#_P``"0IF\2)U0````` +M`J'(D*;AX!1@<11P`P*@J!1P`P*@^Q1P`P*@J!1P`P*A;20%8`(ASY"LN1(G +M5'JI"F:Q(G5#_P``"0IF\2)U0`````(JI"LN1(G5'J1YE)"E!Q)( +MF'JD>9$QT'L!>J1YT)"E!Q)(F'JD>;1Q4WL!>J1Y^)"E!Q)(F'JD>>P27B51 +M].3_$JOV>P%ZI'GLY/\27PQ_`1*K]GL!>J1Y^'\!$E\,>P%ZI'G0D*4'$DB8 +M>J1YM)&(>P%ZI'F4D*4'$DB8>J1YD7'CT-"2KR*0IFL2)U2`````D*9O$B=4 +M`````!)>II`%(G0_\)`%4.!4]_"CX%3W\)"F:Q(G5````/^0IF\2)U0````` +M=`C__A)>JI"F:Q(G5`````^0IF\2)U0````,?SA^"`)>JI"E!!)(F)"F:Q(G +M5(````"0IF\2)U0`````$EZFY)"E"O"0I0K@_\.4!U!C[R7@)*7U@N0T1?6# +MY)/^=`&3_Q(VSI"E!!)(CY"E"N!U\`2D]8*%\(,22">0I0K@)>`DL_6"Y#1% +M]8/DD_YT`9/_$C;.D*4'$DB/D*4*X'7P!*3U@H7P@Q)()Y"E"N`$\("3(I"E +M!!)(F)"F:Q(G5(````"0IF\2)U0`````$EZFY)"E"O"0I0022(^0I0K@__6" +M=8,`$B8W_N\EX"2/]8+D-$7U@^23_'0!D_6"C(/N\)"E"N`$\."T`\KDD*4* +M\)"E"N#])>`DE?6"Y#1%]8/DD_YT`9/_P`;`!Y"E!Q)(CW7P!.VD]8*%\(,2 +M1]V0K+D2)TC0!]`&$C==D*4*X`3PX,.4"$"Y(I"E!!)(F)"F:Q(G5(````"0 +MIF\2)U0`````$EZFY)"E"O"0I0K@_27@)*7U@N0T1?6#Y)/^=`&3_\`&P`>0 +MI0022(]U\`3MI/6"A?"#$D?=D*RY$B=(T`?0!A(W79"E"N#])>`DL_6"Y#1% +M]8/DD_YT`9/_P`;`!Y"E!Q)(CW7P!.VD]8*%\(,21]V0K+D2)TC0!]`&$C== +MD*4*X`3PX,.4!U`"@:J0IFL2)U2`````D*9O$B=4@````!)>II"LN1(G5``` +M``!_@'X,$C==D*RY$B=4`````'^$?@P2-UV0K+D2)U0`````?XA^#!(W79"L +MN1(G5#P```!_C'X,$C==D*RY$B=4`````'^X?@P2-UV0K+D2)U0```"`?Y!^ +M#!(W79"LN1(G5`````!_E'X,$C==D*RY$B=4(`0``'_$?@P2-UV0K+D2)U0@ +M````?\A^#!(W79"LN1(G5`````!_@'X.$C==D*RY$B=4`````'^$?@X2-UV0 +MK+D2)U0`````?XA^#A(W79"LN1(G5#P```!_C'X.$C==D*RY$B=4`````'^X +M?@X2-UV0K+D2)U0```"`?Y!^#A(W79"LN1(G5`````!_E'X.$C==D*RY$B=4 +M(`0``'_$?@X2-UV0K+D2)U0@````?\A^#@(W79"E1N_PD*9K$B=4@````)"F +M;Q(G5``````27J:0I4<22$MX`1(G(N1[$GH!^?C#$D>L8!>0I4L22$MX`1(G +M(N1[[GH#^,,21ZQP:9"E1N!U\!RD),OU@N0T1?6#Y)/^=`&3_\`&P`>0IFL2 +M)U0```/_D*9O$B=4```!`-`'T`827JJ0I4;@=?`0IFL2)U0```/_D*5'$DA+D*9O$B=(T`?0!A)>JI"E1N!U +M\!RD),OU@N0T1?6#Y)/^=`&3_\`&P`>0IFL2)U0#_P``D*5+$DA+>!`2)S60 +MIF\2)TC0!]`&`EZJD*5&[_"0IFL2)U2`````D*9O$B=4@````!)>II"E1N!U +M\!RD),_U@N0T1?6#Y)/^=`&3_\`&P`>0K+D2)U0```"`T`?0!A(W79"E1N!U +M\!RD)-'U@N0T1?6#Y)/^=`&3_\`&P`>0K+D2)U0@!```T`?0!A(W79"E1N!U +M\!RD)-/U@N0T1?6#Y)/^=`&3_\`&P`>0K+D2)U0@````T`?0!A(W79"E1N!U +M\!RD)-7U@N0T1?6#Y)/^=`&3_\`&P`>0IFL2)U0```?_D*5+$DA+D*9O$B=( +MT`?0!A)>JI"E1N!U\!RD)-?U@N0T1?6#Y)/^=`&3_\`&P`>0IFL2)U0```?_ +MD*5'$DA+D*9O$B=(T`?0!@)>JI"E1N_PH^WPY*/PD*5&X'7P#J0DK?6"Y#1% +M]8/DD_YT`9/_P`;`!Y"LN1(G5``0``#0!]`&$C==D*RY$B=4^@```'^`?@D2 +M-UV0K+D2)U3X````?X!^"1(W77\#?@`2.FF0I4;@=?`.I"2M]8+D-$7U@^23 +M_G0!D__`!L`'D*RY$B=4`````-`'T`82-UWDD*5)\)"E1N!U\!RD),WU@N0T +M1?6#Y)/^=`&3_Q(VSN3_[E0$_N3]_'@*$B`$\("\D*5)X,.4%$`"8=Z0I4?@8`)!;9"E1N!U\!RD),WU@N0T1?6# +MY)/^=`&3_Q(VSN3_[E00_N3]_)"E2A(G2.3__OW\D*5*$DAGPQ)'K'!]D*5& +MX'7P#J0DK?6"Y#1%]8/DD_YT`9/_P`;`!Y"LN1(G5`(```#0!]`&$C==D*5& +MX'7P'*0DS?6"Y#1%]8/DD_YT`9/_$C;.Y/_^[%0'_)"F%!(G2)"E1N!U\`ZD +M)*WU@N0T1?6#Y)/^=`&3_\`&P`>0K+D2)U0$````827DD*5.\)"E2.`$\.!D +M"F`"`<)A\)"E1N!U\!RD),WU@N0T1?6#Y)/^=`&3_Q(VSN3_[E0(_N3]_)"E +M2A(G2.3__OW\D*5*$DAGPQ)'K&`"85R0I4;@=?`.I"2M]8+D-$7U@^23_G0! +MD__`!L`'D*RY$B=4!@```-`'T`82-UV0I4;@=?`JI"E1N!U\!RD),OU@N0T +M1?6#Y)/^=`&3_\`&P`>0IFL2)U0#_P``D*9O$B=4`````-`'T`827JKDD*5. +M\)"E2.`$\.!D"F`"`<*`$N20I4[PD*5(X`3PX&0*8`(!PI"E3N#_(I"E!._P +MY*/PD*4A\*/PH_"C\'@H?*5]`7O_>D5Y^?Y_!A)&T.20I27PH_"0H\?@D*4G +M\)"F:Q(G5(````"0IF\2)U0`````$EZFD*4$X)"LN7!.$B=4=W=W=Y!%I^23 +M_G0!D_\2-UV0K+D2)U1W=W=WD$6IY)/^=`&3_Q(W79"LN1(G5`````"01;7D +MD_YT`9/_$C==D*RY$B=4`````(!,$B=4`````)!%I^23_G0!D_\2-UV0K+D2 +M)U0`````D$6IY)/^=`&3_Q(W79"LN1(G5'=W=W>01;7DD_YT`9/_$C==D*RY +M$B=4=W=W=Y!%M^23_G0!D_\2-UV0I03@=?`.I"2K]8+D-$7U@^23_G0!D__` +M!L`'D*RY$B=4&7D9>=`'T`82-UV0I03@=?`JI"F:Q(G +M5$````"0IF\2)U1`````?\1^"!)>JI"E!.!U\`ZD)+/U@N0T1?6#Y)/^=`&3 +M_\`&P`>0IFL2)U0```#_D*9O$B=4````!-`'T`827JJ0IFL2)U2`````D*9O +M$B=4`````!)>II"E2!(G5``(``(27XR0I4@2)U0``@``D*4$X/]],!)?DY"E +M2!(G5``#__V0I03@_WTQ$E^3D*5($B=4``_H/Y"E!.#_?3(27Y.0I4@2)U0` +M"3'5D*4$X/]]91)?DY"E2!(G5``(H`&0I03@_WV/$E^3D*RY$B=4``"``'\, +M?@D2-UV0K+D2)U0#``$`?P!^"Q(W79"E!.!U\!RD),/U@N0T1?6#Y)/^=`&3 +M_\`&P`>0IFL2)U0````!D*9O$B=4`````=`'T`827JJ0K+D2)U0I`"``?WA^ +M"1(W79"LN1(G5*D`(`!_?'X)$C==D*RY$B=4`$8I$'^$?@D2-UV0IFL2)U2` +M````D*9O$B=4@````!)>II"CR."0I00PX"7@=?`0K+D2)U1H%CZ6@"V0H\?@,.0MD*4$X'7P'*0DQ_6"Y#1%]8/DD_YT +M`9/_P`;`!Y"LN1(G5"@6/I;0!]`&$C==D*4$X'7P'*0DV?6"Y#1%]8/DD_YT +M`9/_P`;`!Y"LN1(G5!@`C!#0!]`&$C==D*4$X'7P'*0DV_6"Y#1%]8/DD_YT +M`9/_P`;`!Y"LN1(G5#@`C!#0!]`&$C==D*4$X'7P'*0DR?6"Y#1%]8/DD_YT +M`9/_P`;`!Y"LN1(G5`````#0!]`&$C==Y)"E!?"0I03@_^3]$JBWD*4E[_#[ +MD*84$DA+D*4%X/HEX"7@).3U@N0TI?6#$B=(D*88$DA+ZB7@)>`D\/6"Y#2E +M]8,2)TCK8`:0I2'@!/"0I07@!/#@PY0#0*F0IFL2)U2`````D*9O$B=4```` +M`!)>II"E!.#_?0@27A;D_^Y4_/[M5`_]Y/R0IET2)TB0IED2)U0`!_X`D*4$ +MX/]]6'P`$EVED*9K$B=4@````)"F;Q(G5(`````27J:0I27@<`)A\)"F:Q(G +M5(````"0IF\2)U0`````$EZFD*5($B=4``@``!)?C)"E2!(G5``#``"0I03@ +M_WTP$E^3D*5($B=4``/W_Y"E!.#_?3$27Y.0I4@2)U0`#^>_D*4$X/]],A)? +MDY"E2!(G5``(@`&0I03@_WV/$E^3D*5($B=4``DQT)"E!.#_?6427Y.0I4@2 +M)U0`````$E^,D*9K$B=4@````)"F;Q(G5(````!_>'X)$EZJD*9K$B=4@``` +M`)"F;Q(G5`````!_?'X)$EZJD*RY$B=4``"``'\,?@D2-UV0K+D2)U0`1JB1 +M?X1^"1(W79"F:Q(G5(````"0IF\2)U2`````$EZFD*4$X'7P'*0DV?6"Y#1% +M]8/DD_YT`9/_P`;`!Y"LN1(G5#@`C!#0!]`&$C==D*4$X'7P'*0DV_6"Y#1% +M]8/DD_YT`9/_P`;`!Y"LN1(G5!@`C!#0!]`&$C==D*4$X'7P'*0DQ?6"Y#1% +M]8/DD_YT`9/_P`;`!Y"LN1(G5`(4`1G0!]`&$C==D*4$X/]P)>]U\!RD),?U +M@N0T1?6#Y)/^=`&3_\`&P`>0K+D2)U0H%@U`@":0I03@=?``$2 +M)R+D_^Y4@/[L5`/\D*9O$B=(?WA^"1)>JI"F:Q(G5```!_^0I0?@)>`EX"3P +M]8+D-*7U@Q)(2W@0$BII"E!.#_?0$2J+>0I2;O\/N0IA022$N0I0?@^B7@)>`D +M_/6"Y#2E]8,2)TB0IA@22$OJ)>`EX"0(]8+D-*;U@Q(G2.M@!I"E(N`$\)"E +M!^`$\.##E`-0`D'XD*4AX'`!`2)R+K)>`D+O6"Y#2E]8/N +M\*/O\)"E!^#[)>`EX"3P]8+D-*7U@Q)(2W@0$B`D_/6"Y#2E]8,22$MX$1(G(NLEX"0Z]8+D-*7U@^[PH^_P +MD*4'X/LEX"7@)`CU@N0TIO6#$DA+>!$2)R+K)>`D0/6"Y#2E]8/N\*/O\)"E +M!^`$\.!D`V`"@1?DD*4&\)"E(>#_D*4&X/[#GT`"P5+N!)"E"/"0I2'@_Y"E +M".#^PY]``L%"[B7@)"[U@N0TI?6#X/ZCX/^0I0;@)>`D+O6"Y#2E]8/@_*/@ +MPY__[)[^,Y7@_?R0I1D2)TCD?P3^_?R0I1D22&?#$D>60`+!.G3_?_S^_?R0 +MI1D22&?3$D>64`+!.I"E".`EX"0T]8+D-*7U@^#^H^#_D*4&X"7@)#3U@N0T +MI?6#X/RCX,.?_^R>_C.5X/W\D*4=$B=(Y'\$_OW\D*4=$DAGPQ)'ED`"P3IT +M_W_\_OW\D*4=$DAGTQ)'EE`"P3J0I0C@^R7@)"[U@N0TI?6#X/ZCX/^0I0;@ +M^B7@)"[U@N0TI?6#X/RCX"__[#ZBYQ/^[Q/_[C.5X/W\D*4)$B=(ZR7@)#3U +M@N0TI?6#X/ZCX/_J)>`D-/6"Y#2E]8/@_*/@+__L/J+G$_[O$__N,Y7@_?R0 +MI0T2)TB0I2-T`?"`")"E".`$\('KD*4CX&0!8`B0I0;@!/"!U9"E(^"T`1J0 +MI0D22$N0I4<2)TB0I0T22$N0I4L2)TB`%)"E1Q(G5````@"0I4L2)U0````` +MD*4$X/\2IZ*0I2+@0I4<2)U0```$`D*5+$B=4``````*X:^20I0;PD*4B +MX/^0I0;@_L.?0`,"N#;N!)"E"/"0I2+@_Y"E".#^PY]``P*X)>XEX"0Z]8+D +M-*7U@^#^H^#_D*4&X"7@)#KU@N0TI?6#X/RCX,.?_^R>_C.5X/W\D*49$B=( +MY'\$_OW\D*49$DAGPQ)'ED`#`K@<=/]__/[]_)"E&1)(9],21Y90`P*X')"E +M".`EX"1`]8+D-*7U@^#^H^#_D*4&X"7@)$#U@N0TI?6#X/RCX,.?_^R>_C.5 +MX/W\D*4=$B=(Y'\$_OW\D*4=$DAGPQ)'ED`#`K@<=/]__/[]_)"E'1)(9],2 +M1Y90`P*X')"E".#[)>`D.O6"Y#2E]8/@_J/@_Y"E!N#Z)>`D.O6"Y#2E]8/@ +M_*/@+__L/J+G$_[O$__N,Y7@_?R0I1$2)TCK)>`D0/6"Y#2E]8/@_J/@_^HE +MX"1`]8+D-*7U@^#\H^`O_^P^HN<3_N\3_^XSE>#]_)"E%1(G2)"E)'0!\(`) +MD*4(X`3P`K;(D*4DX&0!8`F0I0;@!/`"MK&0I23@M`$:D*41$DA+D*5'$B=( +MD*45$DA+D*5+$B=(@!20I4<2)U0```$`D*5+$B=4`````)"E!.#_`J9WTQ"O +M`#_=`&H!PB` +M`L,SV/S_D`!%X$^`%Y"FW>#_=`&H!PB``L,SV/ST_Y``1>!?_7]%@'Z0IMW@ +M)/CPX"0$_W0!J`<(@`+#,]C\]/^0`$/@7_U_0Q(ZEI"FW>#_=`&H!PB``L,S +MV/S_D`!#X$_]?T,2.I:0IM[@8!V0IMW@)`3_=`&H!PB``L,SV/S_D`!"X$_] +M?T*`')"FW>`D!/]T`:@'"(`"PS/8_/3_D`!"X%_]?T(2.I;0T)*O(I"D=^!U +M\#^$K?#M)>`EX/UT."_U@N0T_/6#[?"0I'?@!/`B$B8>D*21\/1@'."0I'3P +MD``"$B8W=?`*I/^0I'7E\/"C[_`"8'V0I)'@D*1T\.2C\*/PD`%?\"*0H[[@ +M,.`ND*,=X+0!)Y"FXN`$\."T"@N0H\#@!/#DD*;B\)"CP.#_D*._X+4'!N2C +M\!)7Y"(2)A[_5`'^D*.^X%3^3O#OPQ,PX`J0``$2)C>0H[_P(I"CP>`PX#:0 +MH\3@!/#@_Y"CPN!O<">0!I+@(.(1D*/&X'`+$E?DD*/%X`3P@`:0!I)T!/#D +MD*/$\)"CQO`BY)"CH?"C\)"CH.!4#_!4\/"0HY[@5/WP5/?PD*.G=`'PH_"0 +MHY[@5/OPH^!4^_#DD*.J\)"CJ70'\)"CK.3PHW0"\.20HZ7PD*.>X%3^\)"C +MHW0,\)"CGN!4W_"0HZ1T#/"0HY[@5+_P5'_PH^!4_O!4_?!4]_"0HZX2)U0` +M````D*(JX+0!")"CJW3_\(`2D*(JX)"CJ[0#!734\(`#=$'PD*.R=`'PHW0% +M\*/@5`%$*/"C=`7PY*/PH^!4_?!4^_!4]_!4[_!4W_!4O_#DH_`BD`0:X/1@ +M`W\`(I`$&^!4!V0'?P%@`G\`(G%`[V0!8`B0`;AT`?"`9Y"CI>#_5`-@")`! +MN'0"\(!6D*.CX/[DPYY0")`!N'0$\(!$[S#B")`!N'0(\(`XD*.EX##D")`! +MN'00\(`ID*.?X!,35#\@X`B0`;AT(/"`%I"CN.!@")`!N'2`\(`(D`&XY/!_ +M`2*0`;ET!/!_`"+O)/Y@#`1P*)"CIW0!\*/P(NUP"I"CM>"0HZ?P@`60HZ?M +M\)"CI^"C\)"CG^!$"/`B[V`^D*,=X&0!<#:0HY_@5/[PD`4B=`_PD`8$X%2_ +M\.3_$E>FOP$.D*.>X$1`\)"CI'0&\"*0`;ET`?"0`;AT"/`BD`4B=&_PD*.D +M=`+P(I`%(N3PD*.D=`3P(G0)+?6"Y#3\]8/@5#_P[V`=="DM]8+D-/SU@^!$ +M$/!T"2WU@N0T_/6#X$2`\")T*2WU@N0T_/6#X%3O\'0)+?6"Y#3\]8/@1$#P +M(I"B+>#^D`0X%1_\)`&!.!4?_"0HZ1T#/`B +M[F0&#][\.4@)#] +4$E`$Y/"``W0!\)#]$.WPKP8BCIL` +` +end diff --git a/sys/contrib/dev/rtwn/rtwn-rtl8821aufw.fw.uu b/sys/contrib/dev/rtwn/rtwn-rtl8821aufw.fw.uu new file mode 100644 index 000000000000..5d9138eed7f3 --- /dev/null +++ b/sys/contrib/dev/rtwn/rtwn-rtl8821aufw.fw.uu @@ -0,0 +1,621 @@ +begin 644 rtwn-rtl8821aufw.fw.uu +M`2$0`!8````1(A,Q?&P``%H-```````````````````"2;$"9],````````` +M`````````FA<``````````````````)OO@`````````````````````````` +M`````````````F@$```````"7GD```````)OO17P_P\````5\`\`````!?#_ +M#P````7P#P`````0\/\/````$/`/`````/4/``````#P#P``````#0`````` +M`!#P__\````0\#\`````%?`_`````!7PS_\````*"`,#``0)!P,#``0(!@," +M``0(!0,!``0-"@<%``@,"@<$``@+"@8%``@+"@4#``@+"@,"``@4$@P$`!`4 +M$@D$`!`D(AP2`"`D(A@,`"`D(A0&`"`D(@\$`"`D(0H$`"`C(0P$`"`C'PH$ +M`"`B'P\$`"`A'Q8,`"`Q+R`4`#`Q+Q@0`#`Q+!@,`#`Q*A0,`#`Q*!0``#`Q +M)!0``#`Q'A0``#`$!`0%!`0%!P<'"`H$!PH.$1,4%0,$!P<("PT/!04'!P@+ +M#0\%!0<'"`L-#P<("`H*#`X0$1$'"0D+"PT/$1$2!04'!P@+#0\/#P4%!P<( +M"PT/#P\$!`0%!P<)"0P.$!(%!@<-$!$2$@<("0D,#A$3"0D)"0P.$1,)"0D) +M#`X1$P4&"`D,#A(2$Q0'"`H+#1`1$106"0D)"0P.$1,3$PD)"0D,#A$3$Q,` +M```````````D)BH````?(24G*``````C)B@J`````",F*"H`````(R8H*@`` +M```@)2````+0```#Z```!+````9````'T````#P```!D```` +M>````*````#P```!0````9````'@```"6````R````#(```!&````>````+0 +M```#Z```!]````NX```3B```%W```!]`````R````1@```'@```"T````^@` +M``2P```&0```!]````?0```'T````,@```$8```!X````M````/H```$L``` +M!D````?0```'T```!]```@`"``0`"``,`!(`&``D`#``2`!@`&P`%``R`#P` +M4`!X`*``R`#P`%``>`"@`,@!+`&0`E@#(`!D`(P`\`%H`?0"6`,@`^@`9`", +M`/`!:`'T`E@#(`/H`!X`,@`\`%``>`"@`,@`\`$L`9``9`",`/`!:`'T`^@% +MW`G$"[@/H`!D`(P`\`%H`?0"6`,@`^@#Z`/H`&0`C`#P`6@!]`)8`R`#Z`/H +M`^@"!`8("@P0&"`P0%`!`0$"`0(#`P0$!04"!`8'!P@("`("`P,%!08&!08& +M!P<("0H%!@8'!P@)"@$#!@<'!P@("@H"!08'!P<("`H+!08&!P<("0H*"P4& +M!@<'"`D*"@L!`0$!`0(#!`4&!P@!`@,$!08'"`($!@<("@L,`P4&!P@*"PP% +M!@<("0H+#`($!@<("0L,#`P#!08'"`D+#`P,!08'"`D*"PP,#`4&!P@)"@L, +M#`P9!@0"`!@%(@50!5$+``@("0P,``X`",0(.`@L#%P,8`QD#&@,N`RP#+0. +M7`Y@#F0.:`ZX#K`.M`P`#)0,B`R,#.@,$`T`#)`,Q`S(#,P,U`R`#(0.``Z4 +M#H@.C`[H#A`-0`Z0#L0.R`[,#M0.@`Z$``$$`@,%```````````````````` +MPJ^`_C(2182%T`MUT`BJX,*,Y8HD9_6*Y8PT>?6,THSL)(?XYKP"`G3_PY6! +MM$``0,YY`WB`%N8(<`O"K^8PX0-$&/;2KPC9[>J+T"+E#/\C)('X#P@(OP,$ +M?P!X@>8PY/(`Y0S#GU`@!0QTAB4,^.;]IH$(YJX,O@("=/_-^.AM8.`(YL#@ +M@/;E#-.?0"?E#"2'^.:N#+X"`G3__1CFS?CE@6U@!M#@]AB`]>4,)(;(]A4, +M@-/E#",D@?A_!,*OYC#@`Q#B#'\`,.$',.,$?PA4]%1\QM*O5(!"!R)XAJ:! +M=`)@!O\(=O_?^W\#Y'B`]@CV"-_Z>(%V,)!*:W0!D\#@Y)/`X$.)`76*8'6, +M>=*,TJ\B`N_3E`)``W__(G2!+R_XYB#E],*OYD0P]M*OK@SNPY]0(0YTAB[X +MYOD(YAB^`@)T__WM:6`)"><9&?<)"8#S%A:`VN[3GT`$!8$%@>[3GT`B=(8N +M^`CF^>ZU#`*I@1@&!N;][6E@"1D9YPD)]QF`\QZ`V>\DAOCF!/CO+P202FN3 +M]@CO+Y/V?P`B[].4`D`#?_\B[R,D@?CF,.7TPJ_F5(SVTJ_E#+4'"G2&+_CF +M]8$"1?V'1F`]*@#I@4? +MY0RU!^-_`")TAR_XYOT8A@$/=(8O^*8!"(8$Y0RU!P*L@>UL8`@-":@%YO>` +M].4,M0?>B8%_`"+OTY0"0`-__R+O(R2!^,*OYC#E!3#@`M+DTN+&TJ]_`##B +M`0\"1Q8_"+O2__N2O[M2?WL2/PB +MZY_U\.J>0O#IG4+P[&2`R&2`F$7P(NN?]?#JGD+PZ9U"\.B<1?`BNP$'B8** +M@P))!5`%Z?@"28&[_@7I^`))C8F"BH,"21&[`0WE@BGU@N6#.O6#`DD%4`?I +M)8+X`DF!N_X'Z26"^`))C>6"*?6"Y8,Z]8,"21&[`0>)@HJ#`@AM4`7I^`)) +MF;O^!>GX`DFE(KL!#>6"*?6"Y8,Z]8,""&U0!^DE@O@"29F[_@?I)8+X`DFE +M(N#\H^#]H^#^H^#_(N23_'0!D_UT`I/^=`.3_R+@^*/@^:/@^J/@^R+DD_AT +M`9/Y=`*3^G0#D_LBI"6"]8+E\#6#]8,BX/NCX/JCX/DBZ_"CZO"CZ?`BT(/0 +M@OCDDW`2=`&3<`VCHY/X=`&3]8*(@^1S=`*3:&#OHZ.C@-_F_`CF_0CF_@CF +M_R+B_`CB_0CB_@CB_R+L]@CM]@CN]@CO]B+L\@CM\@CN\@CO\B("2>\"1EWD +MDZ/XY).C0`/V@`'R"-_T@"GDDZ/X5``O@!!I#D`0:0Z`&`F +MH[@!`@,$!08'"`D*"PP-#B0H+#`T.#Q`9&AL<'1X?("$B(R5F9VAI4&D2`!, +M_%@.7_1_`I&:[T0!_7\"48=_`I&:[U3^_7\"TQ"O`#$5`/[ +M#>3_<=QU\`3E)I"6%C$]X/OD_0]QW'7P!.4FD)87<==U\`3E)I"6&#$]X,03 +M5`'[#7\!<=QU\`3E)I"6&#$]X%0?^PUQW'7P".4FD(D`,3W@^^3]#W'<=?`( +MY2:0B0%QUW7P".4FD(D"<==U\`CE)I")`W'7=?`(Y2:0B00Q/>#[Y/T/<=QU +M\`CE)I")!7'7=?`(Y2:0B09QUW7P".4FD(D'<==_CY&:[S#@!N3]?XU1A]#0 +MDJ\B,3W@^PWO<`1T\(`6[[0!!'3T@`[OM`($=/B`!N^T`PQT_"WU@N0T`O6# +MZ_`B?__QV-,0KP'#P-#Q_G\`?@P2-[SO5/S_[)"D)!((;9"D)#$%D*JY$@AM +M?P!^#!(X!W\`?@X2-[SO5/S_[)"D)!((;9"D)#$%D*JY$@AM?P!^#A(X!U%] +M47%1<7^T?@@2-[SO1$#_[)"D)!((;9"D)#$%D*JY$@AM?[1^"!(X!Y`!`'0_ +M\*/@5/WPD`53X$0@\-#0DJ\BTQ"O`D*$DX/U_ +MDU&'D*$;X&`2D`$OX##G!700\(`&D`$O=)#P?PB1FN]$$/U_"%&'?P$2B*]_ +MD)&:[T0!_7^048=_%'X``CUZTQ"O`_P?X^1FN\PYDA_C9&:[V0! +M<#^0I$+PD*1"X/V0I$'@=?`0D($`,3WE@BWU@N0U@_6#X/OD_W'0`0'@1`+PD`$`=/_PD`:W=`GPD`:T=(;P?[1^"!(WO.]4 +MO__LD*0@$@AMD*0@,060JKD2"&U_M'X($C@'?P*1FN]$`?U_`E&'?P!^#!(W +MO.]$`__LD*0@$@AMD*0@,060JKD2"&U_`'X,$C@'?P!^#A(WO.]$`__LD*0@ +M$@AMD*0@,060JKD2"&U_`'X.$C@'T-"2KR+D]0WU#O4/=1"`K0U_4%&'K0Y_ +M45&'K0]_4E&'K1!_4T&'D`$PY/"C\*/PH_"0`3CPH_"C\*/P_7]048?D_7]1 +M48?D_7]248?D_7]308>0`31T__"C\*/PH_"0`3SPH_"C\*/P_7]448=]_W]5 +M48=]_W]648=]_W]708?1X/$,$H9*$H9IP;[Q7I"?G._P\3F0`61T`?"0!"/@ +M1(#P`C:#?_21FN\@Y0U_])&:[W\!(.0%?P(B?P,B?P%^`!(\['_RD9KO(.8, +M?P61FN]$@/U_!5&'(A*)"G\(D9KO5._]?PA1A^3_$HBOD*$6X/_$5`\PX`,2 +M8U0B?2"1!)"A%'0"\"+1">3]__'8D*$4=`'P(N3]?PP24.[D_?^0!2+O\)"? +MF^WP(M,0KP'#P-"Q8_&2T-"2KR)!H1*IJ8"[?__QV.20I#_PH_"0!?C@<`^C +MX'`+H^!P!Z/@<`-_`2+3D*1`X)3HD*0_X)0#0`J0`<#@1"#P?P`B?S)^`!(] +M>I"D/^1U\`$2"-:`O^!$`O#DD*0-\)"A1N"0I`[PY/O]?U1^`=,0KP'#P-"0 +MI`GN\*/O\)"D#>#U.Z/@]3P2-7J0I`G@_J/@]8*.@Z.CHW0%\-#0DJ\BY)"B +M^O"0H1K@8$Z0H)#@9`%P1I"B^@3PY)"A(?"0H1'@,.`5D*$5X+0"!>20HOKP +ML:#O<`20HOKPD*+ZX&`:D*$>X$00\.20I`WPD*$B$5*0H1W@(.("$>HB?0%_ +M!-,0KP'#P-"0I$SM\)"A%N#^Q!,35`,PX`)!1^[$$Q,35`$PX`)!1Y"A'>#^ +M;W`"04?O<`(AKB3^<`(AYR3^8$@D_'`"02(D_&`"03?NM`X"4;R0H1W@<`1_ +M`5'MD*$=X+0&`E&1D*$=X+0$#I"D3.#_8`42J\N``O%XD*$=X&0(8`)!-_'; +M03>0H1W@<`1_`5'MD*$=X+0&`E&1D*$=X+0.!U%,OP$"4;R0H1W@9`Q@`D$W +M44SO9`%@`D$W<85!-Y"A'>"T#@=13+\!`E&\D*$=X+0&`E&1D*$=X+0,!U%, +MOP$"<860H1W@9`1P7!*JZN]D`7!4T9^`4)"A'>"T#@=13+\!`E&\D*$=X+0& +M`E&1D*$=X+0,!U%,OP$"<860H1W@<`1_`5'MD*$=X+0$&A*L$X`5D*$=X+0, +M#I"A%^#_$Q-4/S#@`M$5D*$=X)`!NO"0H1S@D`&[\-#0DJ\BT8;O9`%@")`! +MN'0!\(`MD*$6X!,3$U0?,.`(D`&X=`+P@!F0H1S@TY0$0`B0`;AT"/"`")`! +MN.3P?P$BD`&Y=`+P?P`BD*$7X)`&!"#@#.!$0/!]!'\!<1:`#W$.D`4GX%1_ +M\)"A%70,\.3]_P)/V)"A%^##$R#@!'$2@!Z0!@3@1$#PX$2`\'T$?P%Q%I`% +M)^!$@/"0H15T!/#D_?\"3]B0I$OO\!)."9"D2^!@!N3]_Q)/V'T$?P%Q%I"A +M%70$\"+@5'_P?0Q_`=,0KP'#P-"0I$KO\!1@%11@&20"WP@`60H1SM\'^/$DR:[S#D,9"D2N`48`<48!TD`G`CD*$6X%0! +MQ#,S,U2`_Y"A'>!4?T_]?XB`!Y"A'.#]?XD22H?0T)*O(I"@D.!D`7`WD*$7 +MX%3]\'TL?V\23]A]"'\!$EEKOP$4D*$6X$2`\'T.?P%Q%I"A%70.\"*0`;ET +M`?"0`;@$\"+3$*\!P\#0BU&*4HE3D`4GX/54$@:)_U0!_I"A$>!4_D[^\.]4 +M`O_N5/U/__`2!HG^5`3][U3[3?^0H1'P[E0(_N]4]T[_\!(&B?Y4$/WO5.]- +M_Y"A$?#N5"#^[U3?3O_P$@:)_E1`_>]4OTV0H1'P[L,3(.`"@=_@(.`"@<9U +M5"$3$U0_,.`'L:Q#5`B`#.20H1+PH_!]0/_1R)"A$>#_$Q,35!\PX`-#5!+O +MQ%0/,.`#0U04D*$1X,035`#_Q!,35`,PX`1_!(`AL:#O8`1_`8`8?P*`%'54`9`% +M)^54\)"A%.!D!&`"H9O_$JB+H9N0H1'@_R#@`J%J0U0Q$Q-4/S#@![&L0U0( +M@`9]0.3_T#_ +MQ!,35`,PX`Z0H17@9`)@9N3]?P*`(9`%)^!$0/"0H17@M`(7\>VQH+\!"9"A +M'.#_?0&``^3]_Q'N@#N0H1W@D*$5\(`Q=50!D`4GY53PD*$5X+0"!GT!?P2` +M"Y"A%>"T"`9]`7\,$>[119"A'.#_?0$1[A*H3=#0DJ\BD`5#X'\`,.<"?P$B +MD`$T=$#P_>3_=!4O^.9-_O9T,"_U@N0T`?6#[O`B$9"0H2#@%)`%<_!]`G\" +ML;60H4S@,.`RD*%.X)`%<_"0H4_@8`04\(`AD*%-X!20H4_PD`5S=`'PY/\2 +M7D=]`G\"L;5]`7\"L;4B?2\23`1]"'\!<1:0H15T"/`BD*$:X&0!HBT8;O<`+1)R*0H1K@<`>0H1'@,.`0D*$1X##@ +M![&@OP$$@`/1)R*0H1K@9`)@$I"A&.!4#V`*T8;O<`7]?PP1[B*0!!K@]&`# +M?P`BD`0;X%0'9`=_`6`"?P`B?2T23_J0`3=T`O#]?P.QM1),".3]?P%Q%N20 +MH17P(GT"?P+1R'T!?P)T%2_XYO[M]%[^]G0P+_6"Y#0!]8/N\"+O<$U]>'\" +MT)"A%N!4]_!4 +MO_!4?_"`!GT!?PP1[I"A%N!4]_"0!@K@5/CP(I`!-G1X\*-T`O!]>/^QM7T" +M?P.QM9`&"N!$!_"0H26CX)`%6/"0H)#@M`$4D*$7X%3[\)"A'>`@X@U]`7\$ +M`>Z0H1?@1`3P(I`&!.!4?_#D_?\23]A]#'\!81;QG)"A'>!D#&`&$D_.$EEG +M(I"A%N`3$Q-4'S#@!9`!6^3PD`:2=`+PD`$\=`3PY)"D#?"0H4?@PQ-4?Y"D +M#O#D^_U_6'X!$5Z0H1;@1`CP(A).">3]_Q)/V'$2D*$5=`SP(N3]_Q)/V'T$ +M?P%Q%I`%)^!$0/"0H15T!/`B=>@#=:B%(N20HA3PD*(4X&0!\"0.D`'$\'18 +MH_`2/6Z_`0,2,3B0H1K@8`Z0H1W@_Y"A'.!O8`(15<*O$H#_`JI2X/]]`0)0[I"A%N`PX!B0H1'@_S#@#L,3 +M,.`'\=&_`0:``H``$8LBD*$=X/]@`[0(#Q*KC[\!"1)/XY`!Y>`$\"*0H1;@ +M_\03$U0#,.`F[U2_\)`$X."0H10H6+@!/`BD*$6X/_$ +M$Q,35`$PX"OO5'_PD`3@X)"A%S#A!N!$`O"`#^!4_?"0`;ET`?"0`;@$\)"A +M&N!@`A%5?P$!VGT(Y/_3$*\!P\#0D*0/[_"C[?"0GYG@!/"0!!W@8"*0!2+@ +MD*03\'TF$D_Z[V0!<`)1PY"D$^#_?2<23]AQJX`$<:M1PY`$'W0@\'\!T-"2 +MKR*0GZ#@_WL(?0%1'I"D+>[P_*/O\/V0I"S@_W0)+?6"Y#3\]8/@5#_P[V`= +M="DM]8+D-/SU@^!$$/!T"2WU@N0T_/6#X$2`\")T*2WU@N0T_/6#X%3O\'0) +M+?6"Y#3\]8/@1$#P(M,0KP'#P-"0I#3M\*/K\)"D,^_PY/W\\D*01[O#\H^_P_9"D#^#_,=.0I!'@_J/@_Y"!`.!4#_VL +M!W0-+/6"Y#3\]8/@1`'P=`TL]8+D-/SU@^!4^_"L!W02+/6"Y#3\]8/@1/KP +M=!$L]8+D-/SU@^!$'_"L!W0&+/6"Y#3\]8/@1`[PD`2GY/"0!*;PD`2E=/_P +MD`2D=/WP=!0L]8+D-/SU@^!4P$W]=!0O]8+D-/SU@^WP(M,0KP'#P-"0I"SO +M\)`$'>!@'I`%(N"0I"_P?2D23_J_`0(QN9"D+^#_?2H23]B``C&YD`0?="#P +MT-"2KR*0I`_@_],0KP'#P-"0I$WO\)"?G^#_D`0!D#G`5D*1- +MX'`[D*$6X%1_\)`&!!)3#H`FD*$=X&0&<"20I$W@8!Z0H1;@5+_PD`8$X$1` +M\.!$@/"0H1UT!/#D_?\23]C0T)*O(N3U9)`&J>#U9%3`<`R0H1[@5/[P5/WP +M`57E9##F(I"A&N!D`7`AD*$>X$0!\)"A&.!4#V0"8`21=8`,$E>+@`>0H1[@ +M5/[PY620H1XPYPL24$:0H1;@1`3P(N!4_?`BD`0=X'`9D)^>X/][&.3]41Z0 +MI$/N\*/O\)`$'W0@\"*0!JG@D*+J\.#]5,!P"9"A'N!4_O"`;>TPYDR0H1K@ +M9`)P*I"A%N#_PQ,@X`F0H1[@1`'P@"B0H1C@5`]D`7`ND*$>X$0$\'\!<6Z` +M(9"A'N!$`?"0H1C@5`]D`F`$D76`#!)7BX`'D*$>X%3^\)"BZN"0H1XPYPL2 +M4$:0H1;@1`3P(N!4_?`BD*"0X&0!8`*AP)"A&N!P`J'`D*$8X,14#V0!<":0 +M!JO@D*$A\)`&JN`$D*$@\*/@_W`(D*$@X/[_@`/O!/^0H2'O\)"A%^!$!/#D +MD*$C\)"A):/@D`58\)`!5^3PD`$\=`+PD*$>X%3]\%3O\)"A&.#_Q%0/)/U0 +M`H`-D*$1X##@!)&5@`*1%I"A%^`3$Q-4'S#@#Y"A(.#_H^"U!P71(Q)6Q)"A +M$>##$R#@!Y"A%^!$!/`BD*%CX`3PD*$1X/\PX`B0H17@9`)@.Y"A&N!P!.\P +MX`J0H1W@9`)@*;$=D*$7X!,3$U0?,.`5D*$@X/^CX&]P"]$C$E:^D*$AX!3P +MD`'FX`3P(N\4D`5S\)`!/W00\/U_`W0=+_CF3?[V=#@O]8+D-`'U@^[P(JP' +M[U0!_I"A3.!4_D[P[Y`!4[0!$>3P?1!_`]$RD*%.X)`%<_`B=`/P?1#_$I_E +M`E?;P.#`\,"#P(+`T'70`,``P`'``L`#P`3`!<`&P`>0`<1T>?!T7J/P$H=Y +MY2$PX0+Q%.4A,.("\1[E(C#@`O$XY2,PX0,29RCE(S#@`Q)FX>4C,.,"\<+E +M)##A!'\$\=[E)##D`Q)5RN4D,.4"$:7E)##F`C$J='D$D`'$\'1>H_#0!]`& +MT`70!-`#T`+0`=``T-#0@M"#T/#0X#*0H1K@8`,2K"\BD*$:X&`3D`:2X##A +M`P)7G)"A%N!4]_`152(2B&20HOKO\##@!7T!Y(`"Y/W_$E,6D*+ZX##F$9`! +M+^`PYP3D\(`&D`$O=(#PD*$KX/^CX/V0H3#@^ZP'D*$6X##@+I"A+.#3E`-0 +M!Y"A(NOP@`KM)/TKD*$B\'T#PW0$G2S_D*$O\)"A)>3PH^_P@`Z0H27D\*-T +M`O"0H2+K\)"A):/@D`58\"(B?0CD_R%KD/T0[_!_`"*0H13@9`)_`6`"?P`B +MCV]_`A)'IY"?E^!%;_`B$H,5?P*`ZN3[^OU_`1)'SI"B%>_P8/"0GYC@_Y"? +ME^#^3V#CPJ_N,.`+5/[PY/\2;$42DY72K\*OD)^7X/\PX054_?`1FM*OPJ^0 +MGY?@_S#B!53[\!%(TJ^`O-,0KP'#P-#D_Y"@C.#^D*"+X/VU!@1^`8`"?@#N +M9`%@+.UU\`^D)/7Y=)\U\/I[`1'^?P'O8!:0H(O@!/#@M`H"@`)_`.]@!>20 +MH(OPT-"2KR+3$*\!P\#0D)_TX/^0G_/@M0<$?P&``G\`[W!#D)_SX/YU\`B0 +MGZ,223W@_>YU\`BD)*3Y=)\U\/I[`:\%,720G_/@!/#@?P"T"@)_`>]@!>20 +MG_/P$H,5D)^7X$0"\-#0DJ\BTQ"O`028>P48?0@8?TA8@8C +M8@XD8A&.D*(7$DE) +M`H$KD*(7$DE)`H*;D*(7$DE)X7B0HA<224D"4\60HA<224GAK)"B%Q))20*" +MX9"B%Q))24&]D*(7$DE)`IY[D*(7$DE)`HZ@D*(7$DE)@"20`<#@1`'PD*(6 +MX)`!PO`B$@:)_Y"@C_"_`0@2A8_DD*"/\"*0``$2!J*0H63PD``"$@:BD*%E +M\!)RLG\!D*(:=!'PD*(H=`'PD*(<[_![`7JB>1JQ4G\$D*1&[_!_`A)'IY"? +ME^#_D*1&X/[O3I"?E_`B$@:)_U0!_I"A4.!4_D[P[U0",S,S5/C_D*$6X%3O +M3_"0H5#@5`'_[V0!<&L25I^0`3C@D*%1\)`!.>"0H5+PD`$ZX)"A4_"0`3O@ +MD*%4\)`!,."0H57PD`$QX)"A5O"0`3+@D*%7\)`!,^"0H5CPD`$XY/"C\*/P +MH_"0`3#PH_"C\*/PD`$P=!#PD`$Y=`'PD`!3=(#P(I"A4>"0`3CPD*%2X)`! +M.?"0H5/@D`$Z\)"A5."0`3OPD*%5X)`!,/"0H5;@D`$Q\)"A5^"0`3+PD*%8 +MX)`!,_!_`1)2[>20H1KPH_"0H1C@5`_PHW0"\)"A&.!4\/"0H1;@5/WP5._P +M5/?PD*$@=`'PH_"0H1;@5/OPH^!4^_#DD*$C\)"A(G0(\)"A)>3PHW0"\.20 +MH1[PD*$6X%3?\.3]_Q)3%GT,?P(24Q824Q*0H1;@5+_P5'_PH^!4_O!4_?!4 +M]_"0H2<2"'D`````Y)"A*_"C\)"A+W0$\*-T"/#DH_"0H5#@5/[PD)^>JQ4G\$0:*1M!(& +MB?]4`?Z0H5[@5/Y.\._#$S#@%)```1(&HI"A7_"0``(2!J*0H6#P(I"B)702 +M\)"B,W0%\)"B)^_PH^WPH^OPD*(CX)"B*O"0HB3@D*(K\'L!>J)Y);%2?P1! +MHM,0KP'#P-"0H(O@_W`&H^!D"6`*[Q3_D*",X+4'!'\!@`)_`.]@"9`!P>!$ +M`O"`-<`!D*",X'7P#Z0D]?ETGS7PJ`'\?0'0`7X`?P\2!F.0H(S@!/#@?P"T +M"@)_`>]@!>20H(SPT-"2KR+3$*\!P\#0BU&*4HE3$@:)_Y"A$/"_`0R0``$2 +M!J)D`6`B@!ZK4:I2J5.0``$2!J)D`6`0D*$1X"#@!^3_$JB+@`+1!=#0DJ\B +MTQ"O`#_PQ,PX`+1!>3U9)"A&N!P`L'@D*"0X&0!8`+!X)"A&.#_Q%0/ +M8"(D_F`#!'`>D*$AX!3PX/]@!I"A(^!@#N]P")"A(."C\(``=60!D*$1X##@ +M$I"A%>"T`@/D]6025:#O<`+U9.5D8#V0H1[@1!#PD*$CX&`#M`$+Y)"D#?"0 +MH2/@@`_DD*0-\)"A(^!U\`.D)/[_D*$BX"\24%.0H1W@(.(#$E#J(I"A$>#_ +M,.`^D*$5X'X`M`("?@&0H13@?0"T!`)]`>U.<"3OPQ,PX`+!!1*J"T +M"`;D_7\,@`F0H17@<`;]?P024.XBD*$1X/\PX#^0H17@?@"T`@)^`9"A%.!] +M`+0$`GT![4YP)>_#$S#@`L$%$JJ;D*$5X+0,!N3]?PB`"I"A%>"T!`;D_?\2 +M4.XB@?P(I"A6N!4_O!4?_!4 +M^_"C=`KPY*/PH_`BP.#`@\""P-!UT`#`!<`'?=.0`<3M\'1G_Z/P[020`<3P +MH^_PT`?0!=#0T(+0@]#@,L#@P/#`@\""P-!UT`#``,`!P`+``\`$P`7`!L`' +MD`'$=`3P=&BC\!),O.44,.<#$D]V=`0$D`'$\'1HH_#0!]`&T`70!-`#T`+0 +M`=``T-#0@M"#T/#0X#+`X,#PP(/`@L#0==``P`#``<`"P`/`!,`%P`;`!Y`! +MQ'1<\'1HH_#Q8>49,.$"<;WE&3#D`Q)?[>49,.4#$H>IY1DPY@+1[^4;,.`# +M$F8KY1LPX0*QW^4;,.(#$EW1Y1LPXP+Q"^4;,.0"\8[E&S#E`O%#Y1LPY@+Q +M)^4<,.$#$E9-Y1PPY`*10^4<,.4",1KE'##F`Q)G<'1#_(.<)D`'!X$0@\(!Z +M[S#F(77P$.5DD($`$DD]X/UU\!#E9)"!!1))/>!4`_5KY/N`4726)63U@N0T +MGO6#X`3P=)8E9/6"Y#2>]8/@TY0#0!.O9+&<=)8E9/6"Y#2>]8/D\(`C=?`0 +MY620@0`223W@_77P$.5DD($%$DD]X%0#]6M[`:]D41,%9.5DPY2`4`(A'2*M +M7J]=TQ"O``DG_6"Y#1#]8/DD_YT`9/_Y/S]=?`$ZY!"3Q))/1)) +M+1)(*7@!$@A'Y6@EX"25]8+D-)3U@^[PH^_PD*0'X/^0I`+@_M.?0`OE:52` +M_>]-]6F`#)"D".#_[L.?4`*/:>5I5'^0I`+PY6E4@)"D!?#E:G`SD*0!X"2! +M]8+D-)3U@\"#P(+@_Y"D`^#^=`&H!@B``L,SV/ST7]""T(/PD*0$X%1_\(!2 +MD*0!X"2!]8+D-)3U@\"#P(+@_Y"D`^#^=`&H!@B``L,SV/Q/T(+0@_!U\!#E +M:)"!`1))/>!4!_^0I`3PD*0"X)!$4Y/^,S,S5/A/D*0$\$2`\'7P$.5HD($` +M$DD]Y6GPD*0$X/]U\!#E:)"!`1))/>_P=?`0Y6B0@04223W@5/S_Y6M4`T__ +M=?`0Y6B0@04223WO\'T!KVC18M#0DJ\BY/^0HNKO\)`$?N#U9:/@]69E96!P +MD*+K=`/PD*+Y=`CPY68$5`_U9^3U9.5G=?`(I"0`]8+D-(#U@^6")63U@N0U +M@_6#X/]T[25D]8+D-*+U@^_P!63E9+0(T'L!>J)YZQ)E4N5F!%0/]6:T#P/D +M]6:0!'_E9O"0HNK@?P1P`P)?WA)BHB+D_Y"B_N_PY*/PD*+_X/_#E(!01W0` +M+_6"Y#2C]8/D\'7P$.^0@0,223W@D*+_,.<.X"2!]8+D-)/U@^3P@!3@_]'\ +MD*+_X"0`]8+D-*/U@W0!\)"B_^`$\("O?PQ^`!(]>N20HO_PD*+_X/_#E(!` +M`J&;=``O]8+D-*/U@^!P`J&3D*+_X/]U\!"0@08223W@_77P$.^0@0<223W@ +M_NW_D*+_X/PEX"0!]8+D-)+U@^[PH^_P=?`0[)"!"A))/>#]=?`0[)"!"Q)) +M/>#^[?^0HO_@=?`*D(T!$DD][O"C[_!_`9"B_^#^=?`0D($+$DD]Y8(O]8+D +M-8/U@^#]=?`*[I"-`1))/77P`N\223WD\*/M\`_OM`7+D*+_X/]U\!"0@0D2 +M23W@_G06+_6"Y#28]8/N\)"B_^#_D*+^X/W18I"B_^`D@?6"Y#23]8-T`?"0 +MHO_@!/"!JB)U\!#OD($%$DD]=?`$[Y"6%A))/>#\=!8O]8+D-)_U@^#[5'_] +M=!8O]8+D-)WU@^#^[=.<0`*M!.M4@$(%CFOD^T$3D*$1X##@!I"A$W0!\)"A +M&N!@1I"A%^#_$Q,35!\PX!.0`3O@,.0,$E:^D*$@X!20!7/PD*0]Y'7P`1(( +MUL.0I#[@E("0I#W@9("4@$`+D`&8X%3^\.!$`?`2J`42IYGDD*%=\'\!$E_> +MD*%,X##@$I`!.^`PY`L25KZ0H4[@D`5S\"+3$*\!P\#0[6!B=?`*[Y"-`1)) +M/>3PH_!U\`KOD(T#$DD]Y/"C\'7P"N^0C04223WD\*/P=?`*[Y"-!Q))/>3P +MH_!U\`KOD(T)$DD]Y/"C\.\EX"0!]8+D-)+U@^3PH_!T%B_U@N0TF/6#Y/!U +M\!#OD($#$DD]X%2_1(#^=?`0[Y"!`Q))/>[PT-"2KR*0H1'@,.`%Y*/PH_`B +M=?`0[Y"!`Q))/>!$0/`BD*"0X&0!\Y/_L +MD*+D$@AMD*+D$DDAD*+CX/_D_/W^$DA#HQ((;9"BY!))!9"JN1((;7^P?@@2 +M.`=_%'X`$CUZD*+BX'7P"*0DM?6"Y#2M]8/@_J/@_Q(WO.U4#_WD_"+3$*\! +MP\#0$F_OT-"2KR*0HHT225*0HMH2"'F`````D*+>$@AY`````!&]?67D_Q%@ +MD**-$DE)$DC'?8_D_Q%@D**-$DE)D``$$DCAY/W_$6"0HHT224F0``@"2.%_ +M+'X(TQ"O`\D*+B$@AMD*+:$DD%$@@ZD*+B$DDA$D@V +MP`3`!<`&P`>0HMH22060HMX222$22#;0`]`"T`'0`!)(0Y"BYA((;9"BYA)) +M!9"JN1((;9"BV.#^H^#_$C@'T-"2KR*0HL_O\)"BVA((>8````"0HMX2"'D` +M````$;V0HM`2205X`1((1^1[$GH!^?C#$DAF8!>0HM02205X`1((1^1[[GH# +M^,,22&9P:)"BS^!U\!RD)#WU@N0T1?6#Y)/^=`&3_\`&P`>0HMH2"'D```/_ +MD*+>$@AY```!`-`'T`81P9"BS^!U\!RD)#WU@N0T1?6#Y)/^=`&3_\`&P`>0 +MHMH2"'D#_P``D*+>$@AY`````(!OD*+/X'7P'*0D/?6"Y#1%]8/DD_YT`9/_ +MP`;`!Y"BVA((>0```_^0HM`22060HMX2"&W0!]`&$<&0HL_@=?`$@AMT`?0 +M!@'!D*+:$@AY@````)"BWA((>0`````1O9`%(G0_\)`%4.!4]_"CX%3W\)"B +MVA((>0```/^0HMX2"'D`````=`C__A'!D*+:$@AY````#Y"BWA((>0````Q_ +M.'X(`<'3$*\!P\#0>P%ZHGD=D**0$DE2>J)Y&A*@>WL!>J)Y69"BD!))4GJB +M>3T2H19[`7JB>8&0HI`225)ZHGEU$6]15N3_<=9[`7JB>77D_W$L>P%ZHGE9 +MD**0$DE2>J)Y/1*F<'L!>J)Y'9"BD!))4GJB>1H2I_PHQ)) +M4I"BVA((>8````"0HMX2"'D`````$;V0HHX224D22'>0HM$2"&V0HHW@_WUE +M<;.0HHX224F0``022)>0HM$2"&V0HHW@_WV/<;.0HHX224F0``@22)>0HM$2 +M"&V0HHW@_^3]<;.0HM$2"'D`````D**-X/]][X`'D**-X/]][],0KP'#P-#` +M!\`%D*+1$DD%D*J<$@AMT`70!Q(R--#0DJ\BD**-[_#DH_"0HJKPH_"C\*/P +M>+%\HGT!>_]Z17EK_G\&$@9CY)"BKO"C\)"A9."0HK#PD*+:$@AY@````)"B +MWA((>0`````1O9"BC>!U\`ZD)!GU@N0T1?6#Y)/^=`&3_\`&P`>0JKD2"'EW +M=W=WT`?0!A(X!Y"BC>!U\`ZD)!OU@N0T1?6#Y)/^=`&3_\`&P`>0JKD2"'EW +M=W=WT`?0!A(X!Y"BC>!U\`ZD)!WU@N0T1?6#Y)/^=`&3_\`&P`>0JKD2"'D9 +M>1EYT`?0!A(X!Y"BC>!U\!RD)#/U@N0T1?6#Y)/^=`&3_\`&P`>0HMH2"'D` +M```/D*+>$@AY````!-`'T`81P9"BC>!U\`ZD)!?U@N0T1?6#Y)/^=`&3_\`& +MP`>0HMH2"'D'````D*+>$@AY!P```-`'T`81P9"BVA((>4````"0HMX2"'E` +M````?\1^"!'!D**-X'7P#J0D(?6"Y#1%]8/DD_YT`9/_P`;`!Y"BVA((>0#_ +M``"0HMX2"'D`=P``T`?0!A'!D**-X'7P#J0D(_6"Y#1%]8/DD_YT`9/_P`;` +M!Y"BVA((>0,```"0HMX2"'D`````T`?0!A'!D**-X'7P#J0D)?6"Y#1%]8/D +MD_YT`9/_P`;`!Y"BVA((>0```/^0HMX2"'D````$T`?0!A'!D*+:$@AY@``` +M`)"BWA((>0`````1O9"BT1((>0`(``)QK)"BT1((>0`"``"0HHW@_WTP<;.0 +MHM$2"'D````_D**-X/]],7&SD*+1$@AY``\_PY"BC>#_?3)QLY"BT1((>0`) +M,=60HHW@_WUE<;.0HM$2"'D`"*`!D**-X/]]CW&SD*JY$@AY``"``'\,?@D2 +M.`>0JKD2"'D#``$`?P!^"Q(X!Y"BC>!U\!RD)#7U@N0T1?6#Y)/^=`&3_\`& +MP`>0HMH2"'D````!D*+>$@AY`````=`'T`81P9"JN1((>2D`(`!_>'X)$C@' +MD*JY$@AYJ0`@`']\?@D2.`>0JKD2"'D`1BD0?X1^"1(X!Y"BVA((>8````"0 +MHMX2"'F`````$;V0H67@D**-,.`EX'7P'*0D-_6"Y#1%]8/DD_YT`9/_P`;` +M!Y"JN1((>8(4`_>`(^!U\!RD)#?U@N0T1?6#Y)/^=`&3_\`&P`>0JKD2"'F" +M%`/QT`?0!A(X!Y"A9.`PY2B0HHW@=?`!U\!RD)#GU@N0T1?6#Y)/^=`&3_\`& +MP`>0JKD2"'D`%CZ6T`?0!A(X!Y"BC>!U\!RD)$OU@N0T1?6#Y)/^=`&3_\`& +MP`>0JKD2"'D8`(P0T`?0!A(X!Y"BC>!U\!RD)$WU@N0T1?6#Y)/^=`&3_\`& +MP`>0JKD2"'DX`(P0T`?0!A(X!Y"BC>!U\!RD)#OU@N0T1?6#Y)/^=`&3_\`& +MP`>0JKD2"'D`````T`?0!A(X!^20HH[PD**-X/_D_1*BC)"BKN_P^Y"CL!)) +M!9"BCN#Z)>`EX"2`]8+D-*/U@Q((;9"CM!))!>HEX"7@)(SU@N0TH_6#$@AM +MZV`&D**JX`3PD**.X`3PX,.4`T"ID*+:$@AY@````)"BWA((>0`````2<+V0 +MHHW@_WT($G!@Y/_N5/S^[50/_>3\D*+6$@AMD*+2$@AY``?^`)"BC>#_?5A\ +M`!*?_9"BVA((>8````"0HMX2"'F`````$G"]D**NX'`"8:R0HMH2"'F````` +MD*+>$@AY`````!)PO9"BT1((>0`(```20```"^0HHW@_WTQ$G.SD*+1$@AY``__NY"BC>#_?3(2<[.0HM$2 +M"'D`"(`!D**-X/]]CQ)SLY"BT1((>0`),=B0HHW@_WUE$G.SD*+1$@AY```` +M`!)SK)"BVA((>8````"0HMX2"'F`````?WA^"1)PP9"BVA((>8````"0HMX2 +M"'D`````?WQ^"1)PP9"JN1((>0``@`!_#'X)$C@'D*JY$@AY`$:I$7^$?@D2 +M.`>0HMH2"'F`````D*+>$@AY@````!)PO9"BC>!U\!RD)$OU@N0T1?6#Y)/^ +M=`&3_\`&P`>0JKD2"'DX`(P0T`?0!A(X!Y"BC>!U\!RD)$WU@N0T1?6#Y)/^ +M=`&3_\`&P`>0JKD2"'D8`(P0T`?0!A(X!Y"BC>!U\!RD)#?U@N0T1?6#Y)/^ +M=`&3_\`&P`>0JKD2"'D"%`$9T`?0!A(X!Y"BC>!U\!RD)#GU@N0T1?6#Y)/^ +M=`&3_\`&P`>0JKD2"'DH%A1`T`?0!A(X!^20HI#PD*+:$@AY@````)"BWA(( +M>0`````2<+V0HMH2"'D#_X``D**0X"7@)>`D@/6"Y#2C]8,2205X`1((1^3_ +M[E2`_NQ4`_R0HMX2"&U_>'X)$G#!D*+:$@AY```'_Y"BD.`EX"7@)(SU@N0T +MH_6#$DD%>!`2"$?N5`?^Y/W\D*+>$@AM?WA^"1)PP9"BVA((>8````"0HMX2 +M"'F`````$G"]D**-X/]]`1*BC)"BK^_P^Y"CL!))!9"BD.#Z)>`EX"28]8+D +M-*/U@Q((;9"CM!))!>HEX"7@)*3U@N0TH_6#$@AMZV`&D**KX`3PD**0X`3P +MX,.4`U`"0;20HJK@#_`J%WY)"B +MD/"0HI#@^R7@)>`D@/6"Y#2C]8,2205X$!((1^LEX"2W]8+D-*+U@^[PH^_P +MD**0X/LEX"7@)(SU@N0TH_6#$DD%>!`2"$?K)>`DO?6"Y#2B]8/N\*/O\)"B +MD.#[)>`EX"28]8+D-*/U@Q))!7@1$@A'ZR7@),/U@N0THO6#[O"C[_"0HI#@ +M^R7@)>`DI/6"Y#2C]8,2205X$1((1^LEX"3)]8+D-*+U@^[PH^_PD**0X`3P +MX&0#8`)AT^20HH_PD**JX/^0HH_@_L.?0`+!#NX$D**1\)"BJN#_D**1X/[# +MGT`"H?[N)>`DM_6"Y#2B]8/@_J/@_Y"BC^`EX"2W]8+D-*+U@^#\H^##G__L +MGOXSE>#]_)"BHA((;>1_!/[]_)"BHA))(<,22%!``J'V=/]__/[]_)"BHA)) +M(=,22%!0`J'VD**1X"7@)+WU@N0THO6#X/ZCX/^0HH_@)>`DO?6"Y#2B]8/@ +M_*/@PY__[)[^,Y7@_?R0HJ82"&WD?P3^_?R0HJ8222'#$DA00`*A]G3_?_S^ +M_?R0HJ8222'3$DA04`*A]I"BD>#[)>`DM_6"Y#2B]8/@_J/@_Y"BC^#Z)>`D +MM_6"Y#2B]8/@_*/@+__L/J+G$_[O$__N,Y7@_?R0HI(2"&WK)>`DO?6"Y#2B +M]8/@_J/@_^HEX"2]]8+D-*+U@^#\H^`O_^P^HN<3_N\3_^XSE>#]_)"BEA(( +M;9"BK'0!\(`(D**1X`3P@:>0HJS@9`%@")"BC^`$\(&1D**LX+0!&I"BDA)) +M!9"BT!((;9"BEA))!9"BU!((;8`4D*+0$@AY```"`)"BU!((>0````"0HHW@ +M_Q*A=Y"BJ^!P%Y"BT!((>0```0"0HM02"'D``````H`?Y)"BC_"0HJO@_Y"B +MC^#^PY]``N'J[@20HI'PD**KX/^0HI'@_L.?0`+AVNXEX"3#]8+D-*+U@^#^ +MH^#_D**/X"7@),/U@N0THO6#X/RCX,.?_^R>_C.5X/W\D**B$@AMY'\$_OW\ +MD**B$DDAPQ)(4$`"X=)T_W_\_OW\D**B$DDATQ)(4%`"X=*0HI'@)>`DR?6" +MY#2B]8/@_J/@_Y"BC^`EX"3)]8+D-*+U@^#\H^##G__LGOXSE>#]_)"BIA(( +M;>1_!/[]_)"BIA))(<,22%!``N'2=/]__/[]_)"BIA))(=,22%!0`N'2D**1 +MX/LEX"3#]8+D-*+U@^#^H^#_D**/X/HEX"3#]8+D-*+U@^#\H^`O_^P^HN<3 +M_N\3_^XSE>#]_)"BFA((;>LEX"3)]8+D-*+U@^#^H^#_ZB7@),GU@N0THO6# +MX/RCX"__[#ZBYQ/^[Q/_[C.5X/W\D**>$@AMD**M=`'P@`B0HI'@!/#!@Y"B +MK>!D`6`(D**/X`3PP6V0HJW@M`$:D**:$DD%D*+0$@AMD**>$DD%D*+4$@AM +M@!20HM`2"'D```$`D*+4$@AY`````)"BC>#_`G$OD*1'[_!_`A)'IY"?F.#_ +MD*1'X/[O3I"?F/`BD`()X/51$@:))5&0GYWPD``!$@:B)5&0GY[PD``"$@:B +M)5&0GY_PD``#$@:B)5&0GZ#PD``$$@:B)5&0GZ'PD``%$@:B)5&0GZ+P(HM1 +MBE*)4Y```1(&HO_U51(&B?[#$S#@"I```A(&HO56@`*/5H555.54TY564#.K +M4:I2J5,2!HE4`?]TD"54]8+D-*#U@^_P=)`E5/6"Y#2@]8/@KU1P!#$:@`(Q +M"054@,:0H)#@!4 +M^_`BCU=U\!#OD($%$DD]X$0$\"*0HAH225(2!HG_5'^0H1KP[\03$Q-4`:/P +MD``!$@:B_U3PQ%0/_I"A&.!4\$[PD``#$@:B5`$EX/Z0H1;@5/U.\.]4#\14 +M\/^0H1C@5`]/\)```A(&HI"A&?"0``82!J(PX%[#$U0'_\.4!)"A+%`$[_"` +M+G0#\)"B&A))2>DD!OGD.OH2!HG_=`,D_?[OQ%0/_>]4#__M+E0/_L14\$\2 +M!L^0HAH224F0``82!J+$5`__PY0$D*$B4`5T!/"``N_PD*(:$DE)D``$$@:B +M_7\"$E,6D*(:$DE)42N0`;ET`?"0`;CPD*$:X)`!NO"0H1S@D`&[\)"A&.!4 +M#Y`!OO`BD*(=$DE245J0H1K@_Q)6X)"A&N!@&)"B'1))29```1(&HE0/_Y`` +M`A(&HOU1:R*0H1;@5/OPY)"A(_"0H1[P(N\D_F`+!'`GD*$@=`+P@!;M<`J0 +MH4C@D*$@\(`%D*$@[?"0H2#@H_"0H1?@1`CP(I```A(&HO\PX"82!HF0H47P +MD``!$@:BD*%&\.]4_O^CX%0!3_"0``,2!J*0H4CP(I"A170#\*-T!?"CX%0! +M1"CPHW0%\"(2!HE4`?^0H4S@5/Y/\)```1(&HI"A3?"0``(2!J*0H4[PD*%- +MX)"A3_"0H4S@5`'_`EY'D`',X%0/D*0[\)"D.^#]<`*!9)"?\^#_<`:CX&0) +M8`KO%/^0G_3@M0<$?P&``G\`[V`(D`'!X$0!\"*0I#G@_W0!?@"H!PB`!<,S +MSC/.V/G_[UUP`H%!Y)"D//"0I#S@^<.4!%!SD*0YX'7P!*3_Z?U\`"__[#7P +M_G30+_6"=`$^]8/@_Y"?].!U\`B0GZ,223WE@BGU@N0U@_6#[_"0I#G@=?`$ +MI"W_[#7P_G3P+_6"=`$^]8/@_Y"?].!U\`B0GZ<223WE@BGU@N0U@_6#[_"0 +MI#S@!/"`@Y"D.^#_D*0YX/YT`:@&"(`"PS/8_/1?D*0[\)"D.>#_=`&H!PB` +M`L,SV/R0`!$@)``BO"0I#G@=?`$D`'0$DD]X)`!P_`BTQ"O`X2!N%T`"_YY#3[^GL!P`/``L`!D*09$DE)BT"*08E"=4,"T`'0 +M`M`#$C1BD*08X"0"^>0T^_I[`<`#P`+``:,224GI)`+YY#J+0/5!B4*0I!D2 +M24F0``X2!J+U0]`!T`+0`P(T8GL!>J)Y&G_U?@$2,_V_`0:0HAK@H_![`7JB +M>1I_]GX!$C/]OP$(D*(:X)"B'/![`7JB>1I_]'X!$C/]OP$(D*(:X)"B'?![ +M`7JB>1I_\WX!$C/]OP$(D*(:X)"B'O![`7JB>1I_\GX!$C/]OP$(D*(:X)"B +M'_"0HAO@_Z/@_:/@^Z/@D*(C\)"B'^"0HB3P`F4?D*0P$DE2Y/^0I#`224F/ +M@G6#`!(&HOYT\"_U@N0T`O6#[O`/[[00X")U%1+D]19U%P=U&'*0`3#E%?"C +MY1;PH^47\*/E&/`B=1T&=1X!=1\#=2!BD`$XY1WPH^4>\*/E'_"CY2#P(I`! +ME.!$`?"0`C\)"A +M6>#_[<.?4!CM)>`D@?CF,.0+D`&X=`CPH_!_`"(-@-Y_`2+DD)^7\*/PH_"C +M\*/P(I`!Y'06\*/D\"*0`3S@51WU(:/@51[U(J/@51_U(Z/@52#U))`!/.4A +M\*/E(O"CY2/PH^4D\%.1WR*0`<_@D*+J\.#_,.`'D`'/X%3^\.\PY2.0`<_@ +M5-_PD`$T="#PY/6H]>@23N"0``/@5/O]?P,22H>`_B+3$*\!P\#0Y/^0H_/P +MD`''X&2M<#?PD*0`=`_PD*/R=`KPH^`$\)"C\^`O_G3T+_6"Y#2C]8/N\`_O +MM`_ID`$_=`3P>P%ZHWGR$F#^T-"2KR+3$*\!P\#0D`0=X&`:D`4BX%208`>0 +M`<#@1`CPD`'&X##AY'\`@`)_`=#0DJ\BY)"B^_"C\*/P?X,23)J0HOOO\'^# +M$DR:K@>0HOO@_[4&`2+#D*+]X)1DD*+\X)0`0`V0`<#@1$#PD*+[X/\BD*+\ +MY'7P`1((UH"^D*0V[_#DH_"C\)`!">!_`##G`G\!D*0VX&]@/L.0I#C@E(B0 +MI#?@E!-`")`!P.!$$/`BD*0WY'7P`1((UG\4?@`2/7K3D*0XX)0RD*0WX)0` +M0+>0`<;@,."P(I`!Q'0*\'2)H_!_D!),FN\@X/=T"@20`<3P=(FC\"+D_^3^ +M=!8O]8+D-)GU@^!4_O!U\!#OD($`O@,2$DD]Y8(N]8+D-8/U@W2`\(`/$DD] +MY8(N]8+D-8/U@^3P=?`([Y")`!))/>6"+O6"Y#6#]8/D\`Z^$*T/OX"GY)"M +MXO"0E)$2"'D`````Y/_D_G7P"N^0C0$223UU\`+N$DD]Y/"C\`Z^!>=T%B_U +M@N0TGO6#=#_P=)8O]8+D-)KU@^3P=`$O]8+D-)/U@W3`\.\EX"0!]8+D-)+U +M@^3PH_!T%B_U@N0TF/6#Y/#O)>`D%O6"Y#2;]8/D\*/P[R7@)!;U@N0TG/6# +MY/"C\'7P!.^0EA8223UT/_!U\`3OD)87$DD]Y/!U\`3OD)88$DD]X%3@1`GP +M=?`$[Y"6&1))/>!4\_!U\`3OD)89$DD]X%3\\'7P!.^0EA@223W@1"#P=?`$ +M[Y"6&1))/>!4S_!U\`3OD)89$DD]X$1`\'7P!.^0EAD223W@5'_P=?`$[Y"6 +M%Q))/>#^=?`0[Y"!`!))/>[P=!8O]8+D-)GU@^3P#^]D@&`"(960!$ET\/"C +MY/"C=/_PD`0S=`+PHW0$\*,$\*,$\*,$\'26+_6"Y#28]8-T__`B?O_MPY0S +M0!WMTY0U4!=U\`3OD)88$DD]X,035`#U751_]5]U\`3ND)87$DD]X)"B*O"0HBC@=?`$D)86$DD]X/UU +M\!#ND($%$DD]X%0#]5[E7R7@))_U@N0T0_6#Y)/Z=`&3^^\EX"25]8+D-)3U +M@^KPH^OP=?`$[Y"6&1))/>#^Q%0#D*(I\'06+_6"Y#2?]8/E7_!T%B_U@N0T +MG?6#Y5[PY5_3G4`&C5^O!8]=['`"@?&O!(]@Y5TPYP6%7UT58.5@<`*!\9"B +M*.#_K5U1Z>_T8!./715@Y6!P`H'QD*(HX/^M8'$1Y5UD+'`VY5[3E`!`+^5> +MTY0"4"@57G5=+>5>5`,EX"7@_Y"B*.!U\`20EAD223W@5/-/\!5@Y6!P`H'Q +MY5VT+1+E7M.4`E`+=5TL%6#E8'`"@?'E8'`"@?&0HBK@_^5?TY]0`H'KY/R0 +MHBG@_ZU?L0"/7X5?7>#_H^#]L0#O\*U=Y5\4^Y"B*N#_Z\.?0%_K$Q,35!__ +MD*(HX'7P")")`!))/>6"+_6"Y#6#]8/@]8)U@P#K5`?_=`%^`*@'"(`%PS/. +M,\[8^?_N58/^[U6"3F`9Y5^M`[04`GT,#.QE8&`-D*(JX/_MTY]``QN`EZ\% +MCUV0HBG@_[$4CUV`!I"B*N#U79"B*.#_A5YKY/NM70)J$^]@"NW#E"Q`!'X@ +M@`+D_L/MGO\B[V`*[=.4"T`$?B"``N3^[2[_(NU4?_SM5(!@`Z\$(NS#E#-` +M(NS3E#50''7P!.^0EA@223W@Q!-4!S#@!NQ$@/Z`!G[_@`)^_Z\&(I"CX.OP +M<&R0H^#@_B26]8+D-)CU@^#\D*/AX/OL:V!3D*/EZ_"C[O"N!>XEX$__D)^6 +MX/XEX"7@3Y"CY_"0H^+@D*/I\)"CXW0,\)"C\70$\'L!>J-YXQ)E4G\$$F*B +MD*/AX/^0H^#@));U@N0TF/6#[_`BY/5==)8O]8+D-)7U@^#^M`4([<.4.T!9 +M@$_NM`0([<.4,4!-@$-TEB_U@N0TE?6#X/ZT`PCMPY090#:`+.ZT`@CMPY01 +M0"J`('26+_6"Y#25]8/@_K0!".W#E`I`$X`)[G`+[<.4`T`(=5T!@`/D]5VO +M72*/4HU3BU1U\`3OD)87$DD]X/]U\`3E4I"6%A))/>#]+__D,Z+G$^\3D*(= +M\.53TY0M0`*`&>53TY090`60HAV`"W7P!.52D)87$DD]X/V%5&OD^Z]2`FH3 +MD*(:$DE2$@:)]5$D%O6"Y#29]8/@5)SP=!8E4?6"Y#29]8/`@\""X/^0HAH2 +M24F0``,2!J)4`?[O3M""T(/P=!8E4?6"Y#29]8/`@\""X/^0HAH224F0``,2 +M!J)4`O[O3M""T(/P=!8E4?6"Y#29]8/`@\""X/^0HAH224F0``,2!J)40/[O +M3M""T(/P=!8E4?6"Y#29]8/`@\""X/^0HAH224F0``,2!J)4(/[O3M""T(/P +MY5'#E(!0%I```A(&HO]TEB51]8+D-)GU@^_P@`_E4;2`"I```A(&HI"5E?!T +M%B51]8+D-)GU@^`PY2)U\`3E49"6&1))/>`3$U0#^W26)5'U@N0TF?6#X/VO +M4=%((H]==?`0[Y"!`!))/>#U7N3U8^5>5'_U7^5>5(#[=?`$[Y"6%A))/>#U +M877P!.^0EAD223W@_\14`_5B=?`$Y5^00D\223T221'E727@))7U@N0TE/6# +M[O"C[_#E7DO_=!8E7?6"Y#2?]8/O\'7P$.5=D($%$DD]X%0#]6!T%B5=]8+D +M-)WU@^5@\'06)5WU@N0TF?6#X##@+.5?9#]P)G5?/G7P!.5=D)88$DD]X,03 +M5`!4`__E8,.? +M4`=U7BP%8&&)Y5^T+`5U7BUAB>5?PY5A0`)A,.5?PY0,0!OE7Y034!5T%B5= +M]8+D-)GU@^#_(.,%=6,!@"#E7\.4+$`JY5^4-5`D=!8E7?6"Y#29]8/@_R#C +M%'5C`G06)5WU@N0TF?6#[T0(\(`2Y/5C=!8E7?6"Y#29]8/@5/?P=!8E7?6" +MY#29]8/@(.8#,.$2Y/5C=!8E7?6"Y#29]8/@5/?PY6-D`6`"(`@YQ@@YA4@Y1(@Y`]U\`CE79")`Q))/>`PX&5T%B5=]8+D-)GU@^!$ +M!/#E7[0,"'5?%'5>%$%8Y5^T#0*`!>5?M`X(=5\5=5X505CE7[0/"'5?%G5> +M%D%8Y5_#E!!`"'5?%W5>%T%8Y5_#E!%0`D%8Y5^4$T`"05AU7QAU7AA!6.5C +M9`)@`D%B=?`(Y5V0B0(223W@(.88(.<5=?`(Y5V0B0,223W@(.`&(.$#,.)K +MY5]D+&`%Y5^T+0AU7S9U7C:`3N5?9"Y@!>5?M"\(=5\W=5XW@#OE7[0P"'5? +M.'5>.(`NY5^T,0AU7SEU7CF`(>5?PY0R0`_E7].4-%`(=5\Z=5XZ@`OE7[0U +M!G5?.W5>.X5@:WL!$FH/@`]T%B5=]8+D-)GU@^!4^_"M7Z]B$HT`CU^M8:]B +M$HT`CV'E7P3][=.585!C[1,3$U0?_W7P".5=D(D`$DD]Y8(O]8+D-8/U@^#[ +M>@#M5`?_=`%^`*@'"(`%PS/.,\[8^?_N6O[O6TY@(^5?M!,7=5\8A5]>=!8E +M7?6"Y#29]8/@1`3P@`J-7X5?7H`##8"7K5ZO8A*-%(]>=!8E7?6"Y#29]8/@ +M(.`"88GE7V0_<'EU7SYU\`3E79"6&!))/>#$$U0',.`%=5Z^@%Z%7UZ`6>5? +M96%P0W7P!.5=D)88$DD]X/_$$U0',.`-Y5X@YPCE7T2`]5Z`,G7P!.5?D$)/ +M$DD]$DD1Y5TEX"25]8+D-)3U@^[PH^_P@!!T%B5=]8+D-)_U@^5A\/5>A6!K +M>P&M7J]=`FH3Y/51=)`E4?6"Y#2@]8/@<`,"FV]U\`3E49"6&1))/>#_Q!,3 +M$U0!,.`#`IMOY5$EX"0!]8+D-)+U@^#^H^#3E`#NE`!0`P*;;^51=?`*I"0! +M^72--?#Z>P&0HAD225+E427@)`'U@N0TDO6#X/56H^#U5W06)5'U@N0TF/6# +MX/^0HASD\*/O\)```A('J_^N\!('@"__Y?`^_I``!!('JR__[C7P_I``!A(' +MJR__[C7P_I``"!('JR__[C7P_I"B'O"C[_`2!X#]P^^=_^Z5\)"B(/"C[_!U +M\!#E49"!`!))/>#U4E1_]5-U\`3E49"6%A))/>"0HB+P=?`$Y5&0EAD223W@ +M_Q,35`.0HB/P=)8E4?6"Y#2=]8/@PY0%0`+A9I"B(N#_Y5.?0`B/4U-2@.]" +M4N53D$'[D_]TEB51]8+D-)GU@^##G^530`6005.``Y!!IY/U6.58=?`&I"2Q +M^71`-?#Z>_^0HA8225+E4I!$IY/_TY"B'>"?D*(7P/OSE5L,3_N57 +M$__3[9_LGD`$?0'A..57KE9X`L[#$\X3V/G]K`;E5L,3_N57$RW_[CS^D*(9 +M$DE)$@>`TY_E\)Y0`N$]P<[E47!0D*(9$DE)D``($@>K_:SPY5;#$_[E5Q/_ +MP^V?[)Y0")"?EG0!\(`IY5>N5G@#SL,3SA/8^?NJ!N56PQ/^Y5<3*__N.O[3 +M[9_LGD`%Y)"?EO#3Y5>4Z.56E`-`!759!8`3T^57E,CE5I0`0`5U60*``^3U +M6>51)>`DE?6"Y#24]8/@]52CX/55Y/5XU5/54 +M!5SE7+0%MY"B%A))29``!1(&HOU\`.57KE:H60B`!<[#$\X3V/G_$@<#T^55 +MG^54GD`,Y56?]57E5)[U5(`%Y/54]57E427@))7U@N0TE/6#Y53PH^55\*Y4 +M_^3\_77P!.53D$)/$DD]$DDMPQ)(9E`'KU$2C[*`:.53)>`DG_6"Y#1#]8/3 +M=`&3E57DDY540$]T%B51]8+D-)GU@^`@Y@,PX0?DD*(D\(`&D*(D=`'PY5.T +M.@N0HB3@M`$$?0B`&^53M!@+D*(DX+0!!'T'@`OE4[0V!'T)@`)]`:]1$HL1 +MY5$EX"25]8+D-)3U@Z/@D*/B\)"CX>52\*M1Y/W_$HU@Y/54]54"FD9TEB51 +M]8+D-)WU@^#\9`5@`P*8W*U3KU$2C=1T%B51]8+D-)KU@^_P=?`0Y5&0@0$2 +M23W@5`?U6W26)5'U@N0TF?6#X/_#E#!0$N3U6W26)5'U@N0TG?6#Y`*88706 +M)5'U@N0TFO6#X&0!8`,"F(ITEB51]8+D-)KU@^!D"F!-[R0%_^0S_G0!)5'U +M@N0TE/6#X/W3G^YD@/AT@)A0+NTD!?_D,_YTEB51]8+D-)GU@^#3G^YD@/AT +M@)A0$'06)5'U@N0TGO6#X&538#OE6W`%=5L!@`WE6[0!!75;`X`#=5L%=)8E +M4?6"Y#29]8/@_W0!)5'U@N0TE/6#[_!TEB51]8+D-)J`*726)5'U@N0TG?6# +MY/!TEB51]8+D-)KU@^`$\(`0Y/5;=)8E4?6"Y#2=]8/D\'06)5'U@N0TGO6# +MY5/P=?`$Y5&0EAD223W@Q!,35`,@X`)!(W26)5'U@N0TFO6#Y/#U6W26)5'U +M@N0TG?6#Y/!!(^QD!F`"04;U5/55=?`0Y5&0@0$223W@5`?U6]/E5Y3HY5:4 +M`T`%=5D%@!/3Y5>4^N56E`!`!759`H`#Y/59Y5>N5JA9"(`%SL,3SA/8^?^0 +M10#DD_U\`!('`Y"B)>[PH^_PY/5:D*(9$DE)=?`"Y5JD]8*%\(,2!ZNN\*A9 +M"(`%SL,3SA/8^?_E6I!$^Y/]?``2!P/O)57U5>XU5/54PY"B)N"559"B)>"5 +M5$`'!5KE6K0%L>5:PQ/U6N5;)`'_Y#.BYQ/O$__3E5I`!N^56O^``N3_=`$E +M4?6"Y#23]8/@PQ/^[\0S5.`N!/YT`251]8+D-)/U@^[P=`$E4?6"Y#23]8/@ +MPY3`0`YT`251]8+D-)/U@W3`\'0!)5'U@N0TD_6#X,03$U0#)>#_<`3U6X`$ +M[Q3U6].0HAW@E`.0HAS@E`!``^3U6W7P$.51D($!$DD]X%3XD*(G\$5;__!U +M\!#E49"!`1))/>_P=)8E4?6"Y#2=]8/@TY0%=)90#B51]8+D-)WU@^`$\(`+ +M)5'U@N0TG?6#Y/!T@251]8+D-)/U@^!D`6`"86B0HAS@_J/@_\-T_Y_]=/^> +M_.51)>`D%O6"Y#2;]8/@^J/@TYWJG.514!,EX"06]8+D-)OU@^Z/\!((UH`0 +M)>`D%O6"Y#2;]8-T__"C\)"B'N#^H^#_PW3_G_UT_Y[\Y5$EX"06]8+D-)SU +M@^#ZH^#3G>J?_____D_:]1$FYB!5'E4<.4 +M@%`#`I.8(M,0KP'#P-"0I"CO\'7P!)"6&!))/>!4'_LD\5`"@1[D]6R0I"C@ +M_77P")")`!))/>6")6SU@N0U@_6#X/[K=?`'I"16]8+D-$#U@^6")6SU@N0U +M@_6#Y)/\[ER0I"OP=?`$[9"6&1))/>!4`_^_`@OE;'`'D*0KX%3P\)"D*^#_ +MD*0HX'7P")")`!))/>6")6SU@N0U@_6#[_`%;.5L9`=P@)"D*.!U\`20EAD2 +M23W@_\14`_WDD*0I\'5M!N5MM`8=_Y"D*.!U\`B0B0`223WE@B_U@N0U@_6# +MX%0/@!F0I"C@=?`(D(D`$DD]Y8(E;?6"Y#6#]8/@D*0J\)"D*N!@075L!W0! +M?@"H;`B`!<,SSC/.V/G_D*0JX/OO6V`;Y6UU\`BD)6R0I"GP[6`DX-.4"T`> +MX"0@\(`8%6SE;,.4`%#"Y6U@"Q5MY6W#E`!``H$YY/SU;>5MM`8=_Y"D*.!U +M\`B0B0`223WE@B_U@N0U@_6#X%0/@!F0I"C@=?`(D(D`$DD]Y8(E;?6"Y#6# +M]8/@D*0J\)"D*N!@/.3U;'0!?@"H;`B`!<,SSC/.V/G_D*0JX/OO6V`8Y6UU +M\`BD)6S\[6`=[-.4"T`7="`L_(`1!6SE;+0(QP5MY6UD!V`"@=*0I"G@_Y"D +M*.#^=?`$D)86$DD][_!U\`3ND)87$DD][/!U\!#ND($`$DD]X/Y4?_5N[E2` +M_N5NTY]`"9"D*>!.]6Z`#.5NPYQ0!J\&[$_U;I"D*.#_)!;U@N0TGO6#Y6[P +M=?`$[Y"6&1))/>`3$U0#]6N0I"C@_^3[K6X2:A.0I"C@_W7P$)"!`Q))/>3P +MD*0IX/[#E#9`#W26+_6"Y#25]8-T!?"`#_PY040!*0I"C@));U@N0TE?6#=`/P@#[OPY0,0!*0I"C@));U +M@N0TE?6#=`+P@":0I"G@PY0$D*0HX$`.));U@N0TE?6#=`'P@`LDEO6"Y#25 +M]8/D\-#0DJ\B$@:)5'_U49```1(&HO]4'_53[U2`Q!,3$U0!]5*0``(2!J+_ +M5`/U5.]4,,14#_57D``"$@:B_U1`Q!,35`/U5>]4@,03$Q-4`?56D``"$@:B +M_U0($Q,35!_U6>]4!!,35#_U6N565`'$,S,S5(#_=?`$Y5&0EAD223W@5']/ +M\.555`'$,S-4P/]U\`3E49"6&1))/>!4OT_PY5E@`N'DY5-4'_]U\`3E49"6 +M&!))/>!4X$_PY514`_]U\`3E49"6&1))/>!4_$_P[R7@)>#_=?`$Y5&0EAD2 +M23W@5/-/\.525`'$,U3@_W7P!.51D)88$DD]X%3?3_#E5U0#Q%3P_W7P!.51 +MD)89$DD]X%3/3_!T%B51]8+D-)GU@^!4^_!T%B51]8+D-)GU@^#_Y5HEX"7@ +M_N].\.3U6(58@G6#`*.CHQ(&HO]U\`CE49")`!))/>6")5CU@N0U@_6#[_`% +M6.58M`34KU%Q?")T'2_XYO[M]%[^]G0X+_6"Y#0!]8/N\"+3$*\!P\#0D*+0 +M[/"C[?"0HL_O\*.CX/T2<&"0HMH2"&V0HM(22042"#J0HMH222$22#;`!,`% +MP`;`!Y"BTA))!9"BUA))(1)(-M`#T`+0`=``$DA#D*+>$@AMD*+0H^#]P`60 +MHMX22060JI82"&V0HL_@_]`%$CPST-"2KR*0HHT225*0HMH2"'F`````D*+> +M$@AY`````!)PO>20HI/PD**3X/\EX"0!]8+D-$7U@^23_'0!D_6"C(/@_I"B +MC1))28^"=8,`[A(&X9"BD^`$\."T`\ODD**3\)"BD^#_PY0(4#3O)>`D!_6" +MY#1%]8/DD_YT`9/_$C>\D**0$DE)D**3X'7P!*3U@H7P@Q)(X9"BD^`$\(#" +M(I"BC1))4I"BVA((>8````"0HMX2"'D`````$G"]Y)"BD_"0HI/@_\.4!U`T +M[R7@)!?U@N0T1?6#Y)/^=`&3_Q(WO)"BC1))29"BD^!U\`2D]8*%\(,22.&0 +MHI/@!/"`PB*0HL_O\)"BVA((>8````"0HMX2"'F`````$G"]D*+/X'7P'*0D +M0?6"Y#1%]8/DD_YT`9/_P`;`!Y"JN1((>0```(#0!]`&$C@'D*+/X'7P'*0D +M0_6"Y#1%]8/DD_YT`9/_P`;`!Y"JN1((>2`$``#0!]`&$C@'D*+/X'7P'*0D +M1?6"Y#1%]8/DD_YT`9/_P`;`!Y"JN1((>2````#0!]`&$C@'D*+/X'7P'*0D +M1_6"Y#1%]8/DD_YT`9/_P`;`!Y"BVA((>0``!_^0HM022060HMX2"&W0!]`& +M$G#!D*+/X'7P'*0D2?6"Y#1%]8/DD_YT`9/_P`;`!Y"BVA((>0``!_^0HM`2 +M2060HMX2"&W0!]`&`G#!D*+/[_"C[?#DH_"0HL_@=?`.I"0?]8+D-$7U@^23 +M_G0!D__`!L`'D*JY$@AY`!```-`'T`82.`>0JKD2"'GZ````?X!^"1(X!Y"J +MN1((>?@```!_@'X)$C@'?P-^`!(\[)"BS^!U\`ZD)!_U@N0T1?6#Y)/^=`&3 +M_\`&P`>0JKD2"'D`````T`?0!A(X!^20HM+PD*+/X'7P'*0D/_6"Y#1%]8/D +MD_YT`9/_$C>\Y/_N5`3^Y/W\>`H2"$?O\Y/_N5!#^Y/W\D*+3$@AMY/_^_?R0HM,222'#$DAF<'V0HL_@=?`. +MI"0?]8+D-$7U@^23_G0!D__`!L`'D*JY$@AY`@```-`'T`82.`>0HL_@=?`< +MI"0_]8+D-$7U@^23_G0!D_\2-[SD__[L5`?\D*.P$@AMD*+/X'7P#J0D'_6" +MY#1%]8/DD_YT`9/_P`;`!Y"JN1((>00```"!^N20HM?PD*+1X`3PX&0*8`)! +MEZ'%D*+/X'7P'*0D/_6"Y#1%]8/DD_YT`9/_$C>\Y/_N5`C^Y/W\D*+3$@AM +MY/_^_?R0HM,222'#$DAF8`*A,9"BS^!U\`ZD)!_U@N0T1?6#Y)/^=`&3_\`& +MP`>0JKD2"'D&````T`?0!A(X!Y"BS^!U\!RD)#_U@N0T1?6#Y)/^=`&3_Q(W +MO.3__NQ4!_R0H[`2"&V0HL_@=?`.I"0?]8+D-$7U@^23_G0!D__`!L`'D*JY +M$@AY"````-`'T`82.`>0HL_@=?`0```0#0!]`&$G#!D*+/X'7P'*0D/?6"Y#1%]8/D +MD_YT`9/_P`;`!Y"BVA((>0/_``"0HMX2"'D`````T`?0!A)PP>20HM?PD*+1 +MX`3PX&0*8`)!EX`2Y)"BU_"0HM'@!/#@9`I@`D&7D*+7X/\BD**-$DE2D*+: +M$@AY@````)"BWA((>0`````2<+WDD**3\)"BC1))29"BD^#_]8)U@P`2!J+^ +M[R7@)`'U@N0T1?6#Y)/\=`&3]8*,@^[PD**3X`3PX+0#RN20HI/PD**3X/TE +MX"0']8+D-$7U@^23_G0!D__`!L`'D**0$DE)=?`$[:3U@H7P@Q)(EY"JN1(( +M;=`'T`82.`>0HI/@!/#@PY0(0+DBD**-$DE2D*+:$@AY@````)"BWA((>0`` +M```2<+WDD**3\)"BD^#])>`D%_6"Y#1%]8/DD_YT`9/_P`;`!Y"BC1))277P +M!.VD]8*%\(,22)>0JKD2"&W0!]`&$C@'D**3X`3PX,.4!T"YD*+:$@AY@``` +M`)"BWA((>8`````2<+V0JKD2"'D`````?X!^#!(X!Y"JN1((>0````!_A'X, +M$C@'D*JY$@AY`````'^(?@P2.`>0JKD2"'D\````?XQ^#!(X!Y"JN1((>0`` +M``!_N'X,$C@'D*JY$@AY````@'^0?@P2.`>0JKD2"'D`````?Y1^#!(X!Y"J +MN1((>2`$``!_Q'X,$C@'D*JY$@AY(````'_(?@P".`>0GYS@9`)@!Y`&D.!$ +M`?`BD*%:X##@.)"@D.!D`7`PD*1(X`3PX+0*"Y"A7.`$\.20I$CPD*%!P".20H5SP$E_#(A(&B?]4`?Z0H5K@5/Y._O#O5`3_[E3[ +M3_`2!HG#$S#@"I```1(&HI"A6_`BD*%>X##@0)"A8>`$\.#_D*%?X-.?4#"0 +M!I+@(.(:D*%CX'`4?0C_$EEKD*%BX`3PD*%=X`3P@`:0!I)T!/#DD*%A\)"A +M8_`BD*$1X%3^\%3]\%3[\%3W\%3O\%3?\%2_\.2C\*/PH_"C=`SP(GT??V\2 +M3]B0!2?@5+_PD*$4=`3P(C&I@.?3$*\!P\#0D*$4X)"D2?!O<`(AE.\48$(4 +M8&T4<`(A0!1P`B%K)`1@`B&4D*1)X+0$!#&P(920I$G@M`($,<,AE)"D2>"T +M`P0QOR&4D*1)X&0!8`(AE#&R(920I$G@M`0$,=4AE)"D2>"T`@423\`AE)"D +M2>"T`P0QR"&4D*1)X&`"(90QJ2&4D*1)X+0$!#']@':0I$G@M`$%$D^U@&J0 +MI$G@M`,$,?.`7Y"D2>!P61)/]8!4D*1)X+0$!%$0@$F0I$G@M`$$,9N`/I"D +M2>"T`@0QZ8`SD*1)X'`M,9F`*9"D2>"T`P11)8`>D*1)X+0!!!%R@!.0I$G@ +MM`($43J`")"D2>!P`A&'T-"2KR(QJ7TA?_\23]B0H11T`_`BD*$4=`'P(C'5 +MD`4GX%2_\.20H13P(C'(@.\23\"`ZN3]_Q)/V)"A%'0!\"+D_?\23]B0!2?@ +M1$#PD*$4=`'P(A)."9"A%'0#\"(23`B0H11T`O`BD`4GX$1`\'TC$DP$D*$4 +M=`+P(GTB?_\23]B0!2?@1$#PD*$4=`/P(GTE?V\23]B0!2?@5+_PD*$4=`3P +M(A)."7TD?V\23]B0!2?@5+_PD*$4=`3P(JX'$E6@OP$6D*$1X,03$U0#(.`* +MKP9]`1)0[G\!(G\`(I"A$>#_Q!,35`,PX`^0H17@9`)@!WT!?P(24.Z0H17@ +M9`)@`Q)6:R*0`5?@8$CD\)`!/'0"\)"A%N#_$Q-4/S#@#.]4^_"0H1[@5/WP +M(I"A(^`$\)"A'N!4[_"0H47@_Y"A(^#3GT`.D*"0X+0!!Y"A%^!4^_`B$E:& +M[V0!8`B0`;AT`?!AAI"A'N#_5`-@")`!N'0"\(![D*$X##D")`!N'00\(!.D*$7X!,35#\@X`B0`;AT +M(/"`.Y"A2^!@")`!N'2`\(`MD`9BX##A")`!N'01\(`>D`9BX##@#^!4_/^_ +M@`B0`;AT$O"`")`!N.3P?P$BD`&Y=`3P?P`BD`*'X&`(D`&X=`'P@"60`I;@ +M8`B0`;AT$/"`%Y`"AN`@X0B0`;AT!/"`")`!N.3P?P$BD`&Y=`CP?P`B[V!$ +MD*"0X&0!<#R0H1?@5/[P?2M_#Q)/V)`&!.!4O_`266>_`160H1;@1$#P?09_ +M`1)3%I"A%70&\"*0`;ET`?"0`;AT"/`B?2Y_;Q)/V'T"?P$24Q:0!2?@5+_P +MD*$5=`+P(I"A%N#_$Q-4/S#@$>]4^_"0H1[@5/WP5`=P+H`ID*$CX`3PD*$> +GX%3O\)"A1>#_D*$CX-.?0`^0H)#@M`$+D*$7X%3[\"(26%4B`!Y3 +` +end diff --git a/sys/contrib/dev/urtwn/LICENSE b/sys/contrib/dev/urtwn/LICENSE deleted file mode 100644 index d70921f49379..000000000000 --- a/sys/contrib/dev/urtwn/LICENSE +++ /dev/null @@ -1,39 +0,0 @@ -Copyright (c) 2010, Realtek Semiconductor Corporation -All rights reserved. - -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. -* Neither the name of Realtek Semiconductor 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 - is permitted. - -Limited patent license. Realtek Semiconductor 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 -DAMAGE. diff --git a/sys/contrib/dev/urtwn/urtwn-rtl8192cfwT.fw.uu b/sys/contrib/dev/urtwn/urtwn-rtl8192cfwT.fw.uu deleted file mode 100644 index dbcbadbd14b1..000000000000 --- a/sys/contrib/dev/urtwn/urtwn-rtl8192cfwT.fw.uu +++ /dev/null @@ -1,285 +0,0 @@ -begin-base64 644 urtwn-rtl8192cfwT.fw.uu -wYgCADwAAAAKKBQZrD4AAEM0AQAAAAAAAAAAAAAAAAACdFwAAAAAAAAAAAAAAAAAAAAAAlmZAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnK6AAAAAAACaAEAAAUE -AwIAAwYFBAMABAYFBAIABAgHBgQABgoJCAYACAoJCAQACAoJCAIACAoJCAAACBIREAgAEBoZGBAA -GCIhIBgAICIhIBAAICIhIAgAICIhHAgAICIhFAgAICIgGAgAIDEwIBAAMDEwGAAAMDEvEBAAMDEs -EBAAMDEoEAAAMDEgEAAAMDEQEAAAMAQEBAUEBAUHBwcICgQEBAQGCg0OBQUHBwgMFBQEBAQFBwcJ -CQwOExMEBAQEBQoREwkJCQkMExQVBQUFBQUFBQYGBgYGBQUFBgYGBgYFBQYGBgYGBgUFBQUJCQkJ -Cw0QEgUJCgwNDhASCQkODhAQEhIAAAAAAAAAAAAkJioYGh0fIScpKgAAAB8jKCosAAQABAAIABAA -GAAkADAASABgAJAAwADYAFAAeACgAMgBQAGQAeACMAEsAUAB4ALQA+gEsAZAB9AAAgACAAQACAAM -ABIAGAAkADAASABgAGwAKAA8AFAAZACgAMgA8AEYAGQAoADwAWgB9AJYAyAD6AAAAAABAgICAwQF -CAECAgIEBw8eBQYHDxIjRmQBAQEBAQIDBAUGBwgBAgMEBQYHCAUGBwgJCgsMIh8eGAAgAAAAAAAA -AAAAAAAAqwd0hCv1guQ0BPWD4FR/kJd08OBUH6Pw+nXwCeukJGf1guXwNJP1g+D5kJd38Osl4CSB -9YLkNJL1g+D/o+CQl3jP8KPv8Osl4CQE9YLkNJb1g+D/o+CQl3rP8KPv8Ool4CRm9YLkNEH1g+ST -/nQBk//k/P3rJeAl4CTh9YLkNJL1gxIqf+rDmUADAkNZkJd14P90xSv1guQ0lvWD7/DvBJCXdvCQ -l3fg/5CXduD+059AAwJDmO7DlBBAIe4k8P90AX4AqAcIgAXDM84zztj5/5CXeOBe/qPgX05wJ5CX -duD/w5QQUEp0AX4AqAcIgAXDM84zztj5/5CXeuBe/qPgX05gLZCXduD/ZBNgCe9kEmAE77QRDZCX -eOAw4AaQl3Z0GPCQl3bgkJd18JCXdPCASJCXduAE8AJCxJCXd+D6kJd14P9qcHl0xSv1guQ0lvWD -7/B18AnrpCRp9YLl8DST9YPgtAETkJd04P8w5gEikJd14ERAkJd08JCXdeD/JeAknvWC5DRB9YPk -k/x0AZP97yXgJGb1guQ0QfWDdAGTLf/kkzzDE/7vE//k/P3rJeAl4CTh9YLkNJL1gxIqf4BpkJd1 -4NOaQGGQl3fg/3TFK/WC5DSW9YPv8JCXde/wkJd08Pqj4P8l4CSe9YLkNEH1g+ST/HQBk/3vJeAk -ZvWC5DRB9YN0AZMt/+STPMMT/u8T/+T8/esl4CXgJOH1guQ0kvWDEip/rwIidAEr9YLkNJL1g+Tw -kJd04ESA/3SEK/WC5DQE9YPv8CKQl2br8KPq8KPp8KKv5DOj8MKvkJdm4Puj4Pqj4PmQAAESYzf6 -5fAkAP/kOv6Ql2aj4PqQAAHuj/ASY44SKdn/YDe1IhuQl2bg+6Pg+qPg+ZAAARJjN2UkcATlI2Xw -YC6Ql2bg+6Pg+qPg+ZAAARJjN/+u8BJ79IAVkJdm4Puj4Pqj4PkSKdllImADEn6CkJdp4CT/kq8i -5PUlIgJ+lQJ+nOSQl1rwkJda4P/DlCBAAwJOXHXwCe+kJGr1guXwNJP1g+BkAWADAk5TkJda4CXg -JMD1guQ0kfWD4Pyj4NOUAOyUAFADAk5T73XwCqQkAPl0kDXw+nsBixT1FYkWkJda4CXgJMD1guQ0 -kfWD4P2j4JCXZs3wo+3w7yXgJIP1guQ0lPWD4P+j4JCXaM/wo+/wkAACEmM3/67wEmMML//l8D6Q -l2/wo+/wkAAGEmM3/67wkAAEEmM3L//l8D6Ql23wo+/wkAAIEmM3/5CXa+Xw8KPv8JCXWuD+JIT1 -guQ0BPWD4FQ/kJdc8OD9VB+j8HXwCe6kJGf1guXwNJP1g+CQl3HwkJda4PskhPWC5DSW9YPgw5QF -QAMCSbqQl3Hg/pCXXeCeQBOQl3HgkJdd8O1UQP2Ql1zw7k3wkAT94GQBcCiQl13g/5BBSpP+dEMr -9YLkNJX1g+DDnkAG75BBEoAykJdd4JBBLoApkJdd4P+QQUqT/pCXWuAkQ/WC5DSV9YPgw55ABu+Q -QNqAB5CXXeCQQPaTkJdq8JCXauB18AakJFD5dEA18HUR//USiROQl1zgkEHyk//TkJdp4J+Ql2jg -lABADZCXWuD/5P0SXzICTemQl1rgJeAl4CTh9YLkNJL1g+D8o+D9o+D+o+D/kJdeEip/kJde4Pij -4Pmj4Pqj4PvAAMABwALAA6sRqhKpExIp2f9+AKsUqhWpFhJjDP2s8BIp8uT8/dAD0ALQAdAA6y// -6j7+7Tn97Dj8kJdeEip/kJde4Pij4Pmj4Pqj4PvAAMABwALAA6sRqhKpE5AAARJif/9+AKsUqhWp -FpAAAhJjN/2s8BIp8uT8/dAD0ALQAdAA6y//6j7+7Tn97Dj8kJdeEip/kJde4Pij4Pmj4Pqj4PvA -AMABwALAA6sRqhKpE5AAAhJif/9+AKsUqhWpFpAABBJjN/2s8BIp8uT8/dAD0ALQAdAA6y//6j7+ -7Tn97Dj8kJdeEip/kJde4Pij4Pmj4Pqj4PvAAMABwALAA6sRqhKpE5AAAxJif/9+AKsUqhWpFpAA -BhJjN/2s8BIp8uT8/dAD0ALQAdAA6y//6j7+7Tn97Dj8kJdeEip/kJde4Pij4Pmj4Pqj4PvAAMAB -wALAA6sRqhKpE5AABBJif/9+AKsUqhWpFpAACBJjN/2s8BIp8uT8/dAD0ALQAdAA6y//6j7+7Tn9 -7Dj8kJdeEip/qxGqEqkTkAAFEmJ//34AkJdm4Pyj4P0SKfLk/P2Ql17g+KPg+aPg+qPg+9MSY7uQ -l15AUOD8o+D9o+D+o+D/wATABcAGwAerEaoSqROQAAUSYn//fgCQl2bg/KPg/RIp8qsHqgbQB9AG -0AXQBMPvm//umv7tlAD97JQA/JCXXhIqf4AHEiqLAAAAAJCXXuD8o+D9o+D+o+D/kJda4CXgJeAk -4fWC5DSS9YMSKn+Ql1zgJeAkZvWC5DRB9YPkk/50AZP/5Pz9kJde4Pij4Pmj4Pqj4PvTEmO7QAuQ -l1rg/xJCIAJNYJCXXOAl4CSe9YLkNEH1g+ST/nQBk//k/P2Ql17g+KPg+aPg+qPg+8MSY7tAAwJN -YJCXWuD/fQESXzICTWCQl1rg/ySE9YLkNJb1g+BkBWADAkujdfAJ76Qka/WC5fA0k/WD4GQBcAMC -S6OQk2Lg/7QDC5CXXeDDlBlAPYAu77QCC5CXXeDDlBFALoAfkJNi4P+0AQuQl13gw5QKQBuADO9w -EZCXXeDDlANADZCVY3QB8IAF5JCVY/CQl1rg/yRD9YLkNJX1g+D+w5QwUAvkkJdy8HSELwJLTZCV -Y+BkAWADAktCkJda4CRk9YLkNJX1g+BkCmBbkJda4P/uJAX95DP8dCEv9YLkNJL1g+D/053sZID4 -dICYUDiQl1rg/u8kBf3kM/x0Qy71guQ0lfWD4NOd7GSA+HSAmFAWkJda4CSk9YLkNJb1g+D/kJdd -4G9gVpCXWuAkQ/WC5DSV9YPg/9OURkAIkJdydAXwgBHv05Q8kJdyQAV0A/CAA3QB8JCXWuD/JEP1 -guQ0lfWD4P50IS/1guQ0kvWD7vCQl1rgJGT1guQ0lYAvkJda4P8khPWC5DSW9YPk8HRkL/WC5DSV -9YPgBPCAFOSQl3LwkJda4CSE9YLkNJb1g+TwkJdd4P+Ql1rg/iSk9YLkNJb1g+/w7jDgHpCXcuDE -VPDwkJda4MMT/ySk9YLkNAT1g+BUDwJNQ5CXWuDDE/8kpPWC5DQE9YPgVPACTUOQl1rg/ySE9YLk -NJb1g+BkBmADAk1gdfAJ76Qka/WC5fA0k/WD4GQBcAMCTWCQl14SKosAAAAAkEIT5JP/fgCQl2bg -/KPg/RIp8uT8/ZCXYhIqf+SQl1vwkJde4Pij4Pmj4Pqj4PvAAMABwALAA6sUqhWpFpCXW+D/dfAC -pPWChfCDEmM3/azw75BCDpP/fgASKfLk/P3QA9AC0AHQAOsv/+o+/u05/ew4/JCXXhIqf5CXYuD8 -o+D9o+D+o+D/kJde4Pij4Pmj4Pqj4PvTEmO7UA6Ql1vgBPDgZAVgAwJL+5CXW+DDE/CQl3Lg/7QB -DZCXW+BwXZCXcgTwgFvvtAMdkJdb4P9wCJCXcnQD8IBI77QBCJCXcnQB8IA8gDWQl3LgZAVwMpCX -W+D/cAiQl3J0BfCAD++Ql3K0AQV0A/CAA3QB8NOQl2nglAOQl2jglABABeSQl3Lw05CXaeCUA5CX -aOCUAEAF5JCXcvCQl1rg/zDgGpCXcuDEVPDw78MT/ySk9YLkNAT1g+BUD4ATkJda4MMT/ySk9YLk -NAT1g+BU8PB0pC/1guQ0BPWDwIPAguD/kJdy4P7vTtCC0IPwkJda4P8khPWC5DSW9YPg05QFUA90 -hC/1guQ0lvWD4ATwgA+Ql1rgJIT1guQ0lvWD5PCQl1rg/ySE9YLkNAT1g+BUH8OUCVAFkJIAgBF0 -hC/1guQ0BPWD4JCSACDiBXQI8IADdATwkJda4GANkJbE4P+QkgDgw59QCJCSAOCQlsTwkJbE4JAE -gPCrFKoVqRbk9fASY2+rFKoVqRaQAALk9fASY46QAATk9fASY46QAAbk9fASY46QAAjk9fASY46Q -l1rg/yXgJMD1guQ0kfWD5PCj8O8l4CSD9YLkNJT1g+Two/DvJeAkw/WC5DSU9YPk8KPwkJda4ATw -AkUOIu9wAwJQxZCXTeBgAwJVB5CXOeD8o+D9o+D+o+D/kICFEip/f4x+CBIv2ZCW5eD8o+D9o+D+ -o+D/kICFEip/f0R+CBIv2ZCW6eD8o+D9o+D+o+D/kICFEip/f1x+CBIv2ZCW7eD8o+D9o+D+o+D/ -kICFEip/f2x+DhIv2ZCW8eD8o+D9o+D+o+D/kICFEip/f3B+DhIv2ZCW9eD8o+D9o+D+o+D/kICF -Eip/f3R+DhIv2ZCW+eD8o+D9o+D+o+D/kICFEip/f3h+DhIv2ZCW/eD8o+D9o+D+o+D/kICFEip/ -f3x+DhIv2ZCXAeD8o+D9o+D+o+D/kICFEip/f4B+DhIv2ZCXBeD8o+D9o+D+o+D/kICFEip/f4R+ -DhIv2ZCXCeD8o+D9o+D+o+D/kICFEip/f4h+DhIv2ZCXDeD8o+D9o+D+o+D/kICFEip/f4x+DhIv -2ZCXEeD8o+D9o+D+o+D/kICFEip/f9B+DhIv2ZCXFeD8o+D9o+D+o+D/kICFEip/f9R+DhIv2ZCX -GeD8o+D9o+D+o+D/kICFEip/f9h+DhIv2ZCXHeD8o+D9o+D+o+D/kICFEip/f9x+DhIv2ZCXIeD8 -o+D9o+D+o+D/kICFEip/f+B+DhIv2ZCXJeD8o+D9o+D+o+D/kICFEip/f+x+DhIv2ZCXKeD8o+D9 -o+D+o+D/kICFEip/fwR+DBIv2ZCXLeD8o+D9o+D+o+D/kICFEip/fwR+DRIv2ZCXMeD8o+D9o+D+ -o+D/kICFEip/fwx+CRIv2ZCXNeD8o+D9o+D+o+D/kICFEip/fwR+CBIv2ZCXTXQB8CKQl03gZAFg -AwJVB3+MfggSJ96QlzkSKn9/RH4IEifekJblEip/f1x+CBIn3pCW6RIqf39sfg4SJ96Qlu0SKn9/ -cH4OEifekJbxEip/f3R+DhIn3pCW9RIqf394fg4SJ96QlvkSKn9/fH4OEifekJb9Eip/f4B+DhIn -3pCXARIqf3+Efg4SJ96QlwUSKn9/iH4OEifekJcJEip/f4x+DhIn3pCXDRIqf3/Qfg4SJ96QlxES -Kn9/1H4OEifekJcVEip/f9h+DhIn3pCXGRIqf3/cfg4SJ96Qlx0SKn9/4H4OEifekJchEip/f+x+ -DhIn3pCXJRIqf38EfgwSJ96QlykSKn9/BH4NEifekJctEip/fwx+CRIn3pCXMRIqf38EfggSJ96Q -lzUSKn9/jH4IEifekJfDEip/kJfD4Pyj4P2j4P6j4P/tRMD97JCXwxIqf5CXw+D8o+D9o+D+o+D/ -kICFEip/f4x+CBIv2ZCAhRIqiwABAAB/RH4IEi/ZkICFEiqLANslpH9cfggSL9mQgIUSKosg2yWk -f2x+DhIv2ZCAhRIqiyDbJaR/cH4OEi/ZkICFEiqLBBslpH90fg4SL9mQgIUSKosEGyWkf3h+DhIv -2ZCAhRIqiwQbJaR/fH4OEi/ZkICFEiqLBBslpH+Afg4SL9mQgIUSKotj2yWkf4R+DhIv2ZCAhRIq -iwQbJaR/iH4OEi/ZkICFEiqLINslpH+Mfg4SL9mQgIUSKosg2yWkf9B+DhIv2ZCAhRIqiyDbJaR/ -1H4OEi/ZkICFEiqLINslpH/Yfg4SL9mQgIUSKosAGyWkf9x+DhIv2ZCAhRIqiwAbJaR/4H4OEi/Z -kICFEiqLJNslpH/sfg4SL9l/BH4MEifekJfDEip/kJfD4Pyj4P2j4P7k/+yQl8MSKn+Ql8Pg/KPg -/aPg/qPgRBH/7JCXwxIqf5CXw+D8o+D9o+D+o+D/kICFEip/fwR+DBIv2X8Efg0SJ96Ql8MSKn+Q -l8Pg/KPg/aPg/qPgVPD/7JCXwxIqf5CXw+D8o+D9o+D+o+BEAf/skJfDEip/kJfD4Pyj4P2j4P6j -4P+QgIUSKn9/BH4NEi/Zfwx+CRIn3pCXwxIqf5CXw+D8o+D9o+D+5P/skJfDEip/kJfD4Pyj4P2j -4P6j4EQR/+yQl8MSKn+Ql8Pg/KPg/aPg/qPg/5CAhRIqf38MfgkSL9l/DH4JEifekJfDEip/kJfD -4Pyj4P2j4P6j4P/tVA/97FTw/JCXwxIqf5CXw+D8o+D9o+D+o+D/7UQQ/exEAfyQl8MSKn+Ql8Pg -/KPg/aPg/qPg/5CAhRIqf38MfgkSL9l/BH4IEifekJfDEip/kJfD4Pyj4P2j4P6j4FTw/+yQl8MS -Kn+Ql8Pg/KPg/aPg/qPgRAH/7JCXwxIqf5CXw+D8o+D9o+D+o+D/kICFEip/fwR+CBIv2eSQl03w -Io8R7yXgJAT1guQ0lq+C9RKPE+URdfACpCSB+XSSNfB1FAH1FYkWdfAJ5RGkJGX1guXwNJOvgvUX -jxjlEXXwCaQkY/l0kzXwdRkB9RqJG3TBJRH1guQ0kvWD4BJj2FWKAFWfAVW0AlXJA1XzBFYIBVYd -BlZEDFZyDVafDlbMDwAAVwDlESXgJAT1guQ0lvWDdPDwo3QVgDzlESXgJAT1guQ0lvWDdPDwo3QQ -gCflESXgJAT1guQ0lvWDdPDwo3QFgBLlESXgJAT1guQ0lvWDdPDwo+Tw5REl4CSB9YLkNJL1g3QP -8KN0j/ACVwDlESXgJAT1guQ0lvWDdA/wo3T1gCflESXgJAT1guQ0lvWDdA/wo3TwgBLlESXgJAT1 -guQ0lvWD5PCjdA3w5REl4CSB9YLkNJL1g+Two/ACVwCQBEfgqxSqFakWEmKskARG4KsUqhWpFpAA -ARJivpAEReCFE4KFEoPwkAREAlb3kARL4KsUqhWpFhJirJAESuCrFKoVqRaQAAESYr6QBEnghROC -hRKD8JAESIBYkARP4KsUqhWpFhJirJAETuCrFKoVqRaQAAESYr6QBE3ghROChRKD8JAETIArkART -4KsUqhWpFhJirJAEUuCrFKoVqRaQAAESYr6QBFHghROChRKD8JAEUOCFE4KFEoOj8KsUqhWpFsAD -wALAARIp2f+rGaoaqRsSKdlf0AHQAtADEmKsqxTlFiQB+eQ1FfrAA8ACwAESKdn/qxmqGqkbkAAB -EmJ/X9AB0ALQAxJirIUTgoUSg8CDwILg/4UYgoUXg+D+717QgtCD8IUTgoUSg6PAg8CC4P+FGIKF -F4Oj4P7vXtCC0IPw5REl4CSB9YLkNJL1g+D+o+BOYEyQl3J0C/CQl3Lg/8OUAFADAlhGdAF+AKgH -CIAFwzPOM87Y+f/lESXgJIH1guQ0kvWD4F7+o+BfTmAKkJdy4CQQo/CAaJCXcuAU8IC65REl4CQE -9YLkNJb1g+D+o+BOYEeQl3J0D/CQl3Lg/8OUAEA8dAF+AKgHCIAFwzPOM87Y+f/lESXgJAT1guQ0 -lvWD4F7+o+BfTmAIkJdy4KPwgA2Ql3LgFPCAv+SQl3Pw5REl4CQE9YLkNJb1g+D+o+BOYEfkkJdy -8JCXcuD/w5QQQAMCWQB0AX4AqAcIgAXDM84zztj5/+URJeAkBPWC5DSW9YPgXv6j4F9OYAaQl3Lg -gGOQl3LgBPCAvuURJeAkgfWC5DSS9YPg/qPgTmBG5JCXcvCQl3Lg/8OUDFA8dAF+AKgHCIAFwzPO -M87Y+f/lESXgJIH1guQ0kvWD4F7+o+BfTmAIkJdy4CQQgAmQl3LgBPCAv+SQl3TwkJdz4P918Anl -EaQkZ/WC5fA0k/WD7/CQl3Tg/nXwCeURpCRo9YLl8DST9YPu8HSEJRH1guQ0BPWD4NOfQB+Ql3Pg -/3SkJRH1guQ0lvWD7/B0hCUR9YLkNAT1g+/wkJdz4P/TlBNACJCTYnQD8IAh79OUC0AIkJNidALw -gBPv05QDQAiQk2J0AfCABeSQk2LwkJNi4JAEsfAiwODA8MCDwILA0HXQAMAAwAHAAsADwATABcAG -wAeQAcR0mfB0WaPwkAE34FUr9S+QATTgVSj1LJABNuBVKvUu5Swg4AMCW0uQATR0AfCF0U2F0k6F -00+F1FCF1VGF1lKF11OF2VTlVFRAwxP/5VNUIG9wAwJa+OVUMOUDAlr45VJUH/UI5U1UP/UJ5VFU -H//lCCXgJAP1guQ0lfWD5I/wEmLg5VNUH//lCCXgJMD1guQ0kfWD5I/wEmLg5QnTlARAA3UJBHXw -CuUIpCQA9YLl8DSQ9YN18ALlCRJjzOD+o+D/5VNUHy//5D7+dfAK5QikJAD1guXwNJD1g3XwAuUJ -EmPM7vCj7/DlVCDmJOVTVB//5Qgl4CSD9YLkNJT1g+SP8BJi4OVPMOc2rwgSddiAL+VTVB//5Qgl -4CTD9YLkNJT1g+SP8BJi4OVPMOcS5U9Uf/3lU1Qf9Q2rCa8IEna65WZgT5CXreBgNZABW+TwkAE8 -dATwkAQb4FR/ZH9wNHVEFPVF+/1/WH4BEjWrkAFbdAXwkAaSdAHwkJen8IAUkAQb4FR//79/CpCX -q+D/fQESb0nlLDDhIZABNHQC8IXRVoXSV4XTWIXUWYXVWoXWW4XXXIXZXRJ82eUsMOMGkAE0dAjw -5Sww5AmQATR0EPBDVRDlLDDlIZABz+Aw5RrgVN/wkAE0dCDwkAAD4FT78H8QfgASN1SA/uUsMOYG -kAE0dEDw5S4w4QmQATZ0AvBDVUDlLjDgCZABNnQB8BJ1YuUuMOJjkAE2dATw5WVkAXBX5WZgU+Vm -ZAJwJ5AGq+CQl5/wkAaq4JCXqvCQl5/gcAeQl6rg/4AFkJef4P+Ql5/v8JCXoeBgA+AU8JCXoOTw -kAFX8JABPHQC8JCXr+BU/fDgVO/wEnZO5S4w4zGQATZ0CPDlZWQBcCXlZmAhkAFX5PCQATx0AvB1 -RAN1RQDk+/1/VH4BEjWrkAFXdAXw5S4w5DqQATZ0EPDlZWQBcC7lZmAqkAFX5PCQATx0AvCQl67k -8JCXr+BU/fDgVANwDpCXqfCQl6vg/30BEm9J5S4w5RKQATZ0IPDlZbQBB+VmYAMSffrlLjDmKpAB -NnRA8OVlZAFwHuVmYBqQl6/gVP7w4FQDcA6Ql6nwkJer4P99ARJvSeUvMOEJkAE3dALwEnwodJkE -kAHE8HRZo/DQB9AG0AXQBNAD0ALQAdAA0NDQgtCD0PDQ4DKQBER0EfCjdPDwo3QP8KPk8JCXWvCQ -l1rg/8OUEFAUdKQv9YLkNAT1g+TwkJda4ATwgOLkkJda8JCXWuD7w5QgQAMCXzHg/3XwCqQkAPWC -5fA0kPWD5PCj8HXwCu+kJAL1guXwNJD1g+Two/B18ArvpCQE9YLl8DSQ9YPk8KPwdfAK76QkBvWC -5fA0kPWD5PCj8HXwCu+kJAj1guXwNJD1g+Two/B0pC/1guQ0lvWDdBPwdGQv9YLkNJX1g+Tw7yXg -JMD1guQ0kfWD5PCj8O8l4CSD9YLkNJT1g+Two/DvJeAkA/WC5DSV9YPk8KPw7yXgJMP1guQ0lPWD -5PCj8O8l4CSE9YLkNJX1g+Two/DvJeAkxPWC5DSV9YPk8KPwdGQv9YLkNJb1g+TwdEQv9YLkNJb1 -g+TwdIQv9YLkNJb1g+TwkEHEk/50AZP/kEGMdAGTL//kkz7DE/7vE//k/P3rJeAl4CTh9YLkNJL1 -gxIqf3XwCeukJGr1guXwNJP1g3QB8HXwCeukJGn1guXwNJP1g3QB8HTBK/WC5DSS9YN0DPB18Anr -pCRl9YLl8DST9YN0//Cj8HXwCeukJGP1guXwNJP1g+Two3QP8HXwCeukJGf1guXwNJP1g3QT8HXw -CeukJGj1guXwNJP1g+TwdIQr9YLkNAT1g3QT8JCXWuAE8AJdZiKpB3SEKfWC5DQE9YPgVH+Ql3Tw -4FQf/5CXd/B18AnppCRo9YLl8DST9YPgkJd58HXwCemkJGf1guXwNJP1g+D+kJd68Okl4CQE9YLk -NJb1g+D7o+CQl3vL8KPr8Okl4CSB9YLkNJL1g+D7o+CQl33L8KPr8O/TnkAMkJd64JCXd/CQl3Tw -7XADAmCRkJd47fCQl3TgMOYOkJd34JCXdPCQl3jgFPCQl3jgcAMCYJGQl3fg/9OUAFADAmCR5JCX -dvDvFJCXdfCQl3ng/ZCXdeD/051Ab++UEEAh7yTw/3QBfgCoBwiABcMzzjPO2Pn/kJd94F7+o+Bf -TnAnkJd14P/DlBBQN3QBfgCoBwiABcMzzjPO2Pn/kJd74F7+o+BfTmAakJd14JCXdPCQl3bgBPCQ -l3jg/5CXduBvYAiQl3XgFPCAg5CXeOD/kJd24MOfUA+Ql3XgtQUIkJd54JCXdPCQl3Tg/yXgJJ71 -guQ0QfWD5JP8dAGT/e8l4CRm9YLkNEH1g3QBky3/5JM8wxP+7xP/5Pz96SXgJeAk4fWC5DSS9YMS -Kn+Ql3Tg/3SEKfWC5DQE9YPv8CKQAczgVA+Ql1rwkJda4P1wAwJifpCX0eD/dAF+AKgHCIAFwzPO -M87Y+f/vXXADAmJfkJfR4HXwBKQk0PWC5fA0AfWD4JCXW/Cir+Qzo/DCr3VhAXVil3VjW3VkAXsB -epd5XRJ4j5CXXOAk/5Kvo+D/xBMTE1QBkJfRMOBw4HXwAqQkiPWC5DXw9YPgkJde8JCX0eB18AKk -JIn1guQ18PWD4JCXX/CQl9HgdfAEpCTR9YLl8DQB9YPgkJdg8JCX0eB18ASkJNL1guXwNAH1g+CQ -l2HwkJfR4HXwBKQk0/WC5fA0AfWD4JCXYvCAQuB18ASkJNH1guXwNAH1g+CQl17wkJfR4HXwBKQk -0vWC5fA0AfWD4JCXX/CQl9HgdfAEpCTT9YLl8DQB9YPgkJdg8O9Uf/97AXqXeV4SbbmQl1rg/5CX -0eD+dAGoBgiAAsMz2Pz0X5CXWvCQl9Hg/3QBqAcIgALDM9j8kAHM8JCX0eAE8OBUA/ACYPLCr3To -BJABxPB0YKPwkJda4JABxvCQl9HgkAHH8ID+IrsBDOWCKfWC5YM69YPgIlAG6SWC+OYiu/4G6SWC -+OIi5YIp9YLlgzr1g+STIrsBBomCioPwIlAC9yK7/gHzIvi7AQ3lgin1guWDOvWD6PAiUAbpJYLI -9iK7/gXpJYLI8iLF8Pij4CjwxfD45YIVgnACFYPgOPAio/jgxfAl8PDlghWCcAIVg+DIOPDoIrsB -ComCioPg9fCj4CJQBofwCecZIrv+B+P18AnjGSKJgoqD5JP18HQBkyK7ARDlgin1guWDOvWD4PXw -o+AiUAnpJYL4hvAI5iK7/grpJYL44vXwCOIi5YMq9YPpk/Xwo+mTIrsBComCioPw5fCj8CJQBvcJ -p/AZIrv+BvPl8AnzGSL4uwER5YIp9YLlgzr1g+jw5fCj8CJQCeklgsj2CKbwIrv+Ceklgsjy5fAI -8iLrn/Xw6p5C8OmdQvDonEXwIqQlgvWC5fA1g/WDItCD0IL45JNwEnQBk3ANo6OT+HQBk/WCiIPk -c3QCk2hg76Ojo4Df5JCXV/Cj8BJ5hZAAAuBU4JCXtmAFdAHwgAN0AvCQAPPgMOMIkJe3dAHwgAXk -kJe38JCXt+C0AROQAPLgMOcMkJewdP3wo3Qz8IAKkJewdP3wo3Qv8OT1VRJdLhJ+jBJ5NhIyPRJE -/3UoM+T1KXUqAvUrkAEw5Sjwo+Up8KPlKvCj5SvwkADz4DDiDZAFQXQQ8JAFWvCj5PCQAWR0oPB1 -RP/k9UX7fQF/UH4BEjWrdTAfdTEB5PUykAE45TDwo+Ux8KPlMvASeDiQl1nl2fCQATx0//Cj8KPw -kAE08KPwo/Cj8MKvkACA4ERA8H8QfgASN1R16ANDqIXSr5ABwOTwo/Cj8KPwkAHG8KPwkJdX4GQB -8CT+kAHE8HRjo/DlVTDmF8KvU1W/0q8SRQmQl43g/2ADtAEDEmkS5VUw5wfCr1NVf9Kv5VUw5ArC -r1NV79KvEmDokJeN4HADEmwKEnyFgKqQAAISYn+Ql4vwkAABEmJ/JeAl4JCXivASKdkl4CXgkJeO -8JCXi+CQBJjwkJeK4BMTVD+QBJnwkJeO4BMTVD+QBJrwkAVg4JCXmfCQBWHgkJea8JAFYuCQl5vw -kAVj4JCXnPCir+QzkJdp8MKvkJeK4P8SeOSQl2ngJP+Sr5CXi+BwAwJmjJCXiuBwAwJmjJCXjuBw -AwJmjKKv5DOQl2nwwq+Ql510AfCQl2ngJP+Sr5AAReBU/vCj4EQB8JCXg+BgHZCXj+D8o+D9o+D+ -o+D/kICFEip/f4B+CBIv2YAGkAUidH/wkABF4FTv8JAFh+BkgPCQl5ngkAWE8JCXmuCQBYXwkJeb -4JAFhvCQl5zgkAWH8KKv5DOQl2nwwq+QATzgRCDwfSDk/xI3AIArkJeL4HAtkJed8JAAReBU/vCj -4FT+8JAFIuTwoq8zkJdp8MKvfSDk/xI2kpCXaeAk/5KvIpCXZuvwo+rwo+nwkJdm4Puj4Pqj4PmQ -AAQSYn//VB+Ql2nwkAADEmJ/VPDEVA+Ql2rw71QgxBNUB6PwkAAEEmJ/VEDEExNUA5CXbPCQl2ng -/3XwCaQkZfWC5fA0k62CkJdt8KPt8O918AmkJGP5dJM18PqjdAHwo+rwo+nwkJdmo+D6o+D5kAAD -EmJ/VA//kJdv4Puj4Pqj4PnvEmKskJdm4Puj4Pqj4PmQAAISYn//kJdv4Puj4Pqj4PmQAAHvEmK+ -kJdm4Puj4Pqj4PmQAAESYn//kJdt4Pyj4P31goyD7/ASKdmNgoyDo/CQl2rg/pCXaeD/JMH1guQ0 -kvWD7vCQl2vg/nXwCe+kJGn1guXwNJP1g+7wdfAJ76QkavWC5fA0k/WDdAHwkJds4P518AnvpCRr -9YLl8DST9YPu8AJVCMDgwPDAg8CCwNB10ADAAMABwALAA8AEwAXABsAHkAHEdAHwdGij8FOR35AB -POBVMPU0o+BVMfU1o+BVMvU25TQw4A+QATx0AfCQAVN0B/BDVYDlNDDhCZABPHQC8BJ50eU0MOI6 -kAE8dATwkAaS4DDgHnVEFHVFAOT7/X9YfgESNauQAVt0BfCQBpJ0AfCAD5CXp+TwkJer4P99ARJv -SeU0MOMGkAE8dAjw5TQw5AmQATx0EPASfgvlNDDlCZABPHQg8BJuheU1MOAVkAE9dAHwkACD4JCX -q/Dg/30BEm9J5TYw4waQAT50CPB0AQSQAcTwdGij8NAH0AbQBdAE0APQAtAB0ADQ0NCC0IPQ8NDg -MpCXhODDlBRQBuAE8AJpzJCXhOBkFGADAmnMkJeT4HAlkJeW4HAfkJeU4HAZkJeX4HATkJeV4HAN -kJeY4HAHkAT94FT+8JCXk+CQBIjwkJeU4JAEifCQl5XgkASK8KPk8JCXluCQBIzwkJeX4JAEjfCQ -l5jgkASO8KPk8JCXf+CQBJDwkJeA4JAEkfCQl4HgkASS8JCXguCQBJPw5JCXhPCQl38E8OSj8KPw -o/CQl5Pwo/Cj8KPwo/Cj8JAFYOCQl1rwkAVh4JCXW/CQBWLgkJdc8JAFY+CQl13wkJec4P+Ql13g -/tOfUAuQl5zgw57TlAFAEZCXiuC0AQKAA5CXjuD/EnjkIpCX0O3wkJfP7/DTlAdQbeD/dAGoBwiA -AsMz2Pz0/5AAR+Bf8H8QfgASN1SQl8/g/3QBqAcIgALDM9j8/5AARuBP8H8QfgASN1SQl9DgYBaQ -l8/g/3QBqAcIgALDM9j8/5AARYB4kJfP4P90AagHCIACwzPY/PT/kABFgH2Ql8/gJPjw4P90AagH -CIACwzPY/MRU8PT/kABD4F/wfxB+ABI3VJCXz+D/dAGoBwiAAsMz2Pz/kABD4E/wfxB+ABI3VJCX -0OBgG5CXz+D/dAGoBwiAAsMz2PzEVPD/kABC4E+AGpCXz+D/dAGoBwiAAsMz2PzEVPD0/5AAQuBf -8H8QfgASN1Qif3h+CBIn3pCXPRIqf38EfgwSJ96Ql0ESKn9/AH4IEifekJdFEip/kJe34JCXPbQB -E+D8o+D9o+D+o+BUx//tVMf9gA3g/KPg/aPg/qPgVMf/7JCAhRIqf394fggSL9mQl0Hg/KPg/aPg -/qPgVA//7JCAhRIqf38EfgwSL9mQl0Xg/KPg/aPg/qPgRAL/7JCAhRIqf38AfggSL9l/cH4OEife -kJdJEip/kICFEiqLABsloH9wfg4SL9mQgFkSKosAAAAA5P3/EjSBkJe34LQBEZCAWRIqiwAAAADk -/X8BEjSBkAAR4FT28H8QfgACN1SQl53gZAFgCZCXi+BgAwJs4pCXf+DDlP9QBeAE8IA7kJeA4MOU -/1AG4ATw5IAokJeB4MOU/1AK4ATw5JCXgPCAFZCXguDDlP9QEOAE8OSQl4HwkJeA8JCXf/CQAETg -VAxgduAw4jKQl5Pgw5T/UAXgBPCAJJCXlODDlP9QBuAE8OSAEZCXleDDlP9QDOAE8OSQl5TwkJeT -8JAAROAw4zKQl5bgw5T/UAXgBPCAJJCXl+DDlP9QBuAE8OSAEZCXmODDlP9QDOAE8OSQl5fwkJeW -8JAE/eBEAfAiixGKEokTkAACEmJ/kJeM8OAw4FyQl4N0AfB/gH4IEifekJeFEip/qxGqEqkTkAAB -EmJ//+T8/f54GhIqbKgEqQWqBqsHkJeF4Pyj4P2j4P6j4P/sVAP860//6k7+6U396Ez8kJePEip/ -kAUi5PCANeSQl4Pwf4B+CBIn3uxUA/zsRMD8kJeFEip/kJeF4Pyj4P2j4P6j4P+QgIUSKn9/gH4I -Ei/ZkJeM4JAARzDhEXQM8KPgRAzwkABG4EQQ8IAQ4FTz8KPgVPPwkABG4FTv8OSQl4nwIpCXY+vw -o+rwo+nw7xJj2G3qAW34Am4GA24UBW4iBm4wB24+CW5MDG5aDW5oDgAAbnaQl2Pg+6Pg+qPg+QJ8 -spCXY+D7o+D6o+D5An6jkJdj4Puj4Pqj4PkCfFeQl2Pg+6Pg+qPg+QJ63pCXY+D7o+D6o+D5AmbA -kJdj4Puj4Pqj4PkCflSQl2Pg+6Pg+qPg+QJEaJCXY+D7o+D6o+D5AmVfkJdj4Puj4Pqj4PkCe4mQ -l2Pg+6Pg+qPg+QJs48KvdLkEkAHE8HRto/CA/pCXi+BkAWADAm9IkABG4EQB8JCXneBwQJCXg+Bg -HZCXj+D8o+D9o+D+o+D/kICFEip/f4B+CBIv2YAGkAUidH/wkJeK4P8SeOSQl510AfCQAEXgVP7w -gESQl53gZAFwPJCXjuD/Enjk5JCXnfCQAEXgRAHwkJeD4GAdkJeF4Pyj4P2j4P6j4P+QgIUSKn9/ -gH4IEi/ZgAWQBSLk8JAFh+BkgPCQl5ngkAWE8JCXmuCQBYXwkJeb4JAFhvCQl5zgkAWH8CKPJo0n -5SZUD/+Ql6jgVA9vYHjlJjDiMJCXqOAg4gV/ARJ9PpCXqOAw4wrlJiDjBRJ9XYBWkJeo4CDjT+Um -MONKrycSfR6AQ5CXqOBUD/+/DA7lJiDjCRJ8/e9gLhJ9XZCXqOBUD/+/BA7lJiDiCRJ7Gu9gFhJ7 -UpCXqOBUD/+/AgkSeqDvYAMSfXqQl6jgVA//kJer4FQPb3Aj4DDmH5CXqOBUD/+Ql57g/k+QAS/w -7mSAkJee8JCXq+BUv/AikJdQ6/Cj6vCj6fCQl7bgZAJwAwJwvJABr+BgCZABx+AE8PCA8ZCX0+D/ -BPCQl1Dg+6Pg+qPg+ZAAAe8SYr6ir+QzkJdW8MKvkJdQ4Puj4Pqj4IthimL1Y3VkAnsBegF5oBJ4 -j5CXVuAk/5Kvoq/kM/DCr5CXU+D7o+D6o+CLYYpi9WOQl1Dg+6Pg+qPg+RIp2f/EVA/1ZHsBegF5 -ohJ4j5CXVuAk/5KvkAGvdP/wkAHL4GSA8CKQl77v8KPt8OSj8KPw5WZgBeT/En20kJe+4DDgCZCX -wOTwo3SA8JAEHeBgHZAFIuCQl8Lw4P9UkGDskAHIdPzw71RvkAUi8IDdkJe+4P/DE5D9EPCQBCXv -8JCXv+BgH6Oj4P8kD/WC5DT89YPgRIDwdBAv9YLkNPz1g+BEgPCQl8Cj4P/9JAj1guQ0/PWD5PB0 -CS31guQ0/PWD4FTw8HQhL/WC5DT89YPgVPfwkJfA4P6j4P8ikJfV7/DTlAdQSuD/dAGoBwiAAsMz -2Pz0/5AARuBf8H8QfgASN1SQl9Xg/XQBfgCoBQiABcMzzjPO2Pn/kABE4Pvk/u9bqAUIgAbOoucT -zhPY+P8ikJfV4CT48OD/dAGoBwiAAsMz2Pz0/5AAQ+Bf8H8QfgASN1SQl9Xg/XQBfgCoBQiABcMz -zjPO2Pn/kABC4Pvk/u9bqAUIgAbOoucTzhPY+P8ikAAR4EQJ8H8QfgASN1SQlz3g/KPg/aPg/qPg -/5CAhRIqf394fggSL9mQl0Hg/KPg/aPg/qPg/5CAhRIqf38EfgwSL9mQl0Xg/KPg/aPg/qPg/5CA -hRIqf38AfggSL9mQl0ng/KPg/aPg/qPg/5CAhRIqf39wfg4SL9mQgFkSKosAAy2V5P3/EjSBkJe3 -4LQBEZCAWRIqiwADLZXk/X8BEjSBIsDgwPDAg8CCwNB10ADAAMABwALAA8AEwAXABsAHkAHEdLrw -dHKj8FOR75AAUeD/kABV4F/1PeU9MOYYdEDwkJeM4FQD/78DC5CXieBgBX8BEnPY5T0w5xWQAFV0 -gPCQl4zgVAP/vwMFfwISc9iQAcR0uvB0cqPw0AfQBtAF0ATQA9AC0AHQANDQ0ILQg9Dw0OAy72A0 -fX1/AhI2dX0CfwMSNnWQAVfk8JABPHQC8H0BfwwSb0nk/xJ9tJAGBOBUf/CQBgrgVPjwIpABNnR9 -8KN0AvB9ff8SNuZ9An8DEjbmkAYE4ESA8JAGCuBEB/CQl6Pgo+CQBVjw5WUw4BuQl6HgcBrgBPCQ -l6jgVA/DlARQDH0BfwQCb0nkkJeh8CLvFGAgFGBLJAJweJCXiXQC8JAASOBEDPCQAEfgRAjwkABF -gFvkkJeJ8JCXheD8o+D9o+D+o+D/kICFEip/f4B+CBIv2ZAAReBE7/DgVO/wo4AtkJeJdAHwkJeP -4Pyj4P2j4P6j4P+QgIUSKn9/gH4IEi/ZkABF4EQg8OBEEPCj4EQQ8CICdJoCY/7kk6P45JOjQAP2 -gAHyCN/0gCnkk6P4VAckDMjDM8RUD0QgyINABPRWgAFG9t/kgAsBAgQIECBAgJB+OuR+AZNgvKP/ -VD8w5QlUH/7kk6NgAQ7PVMAl4GCoQLjkk6P65JOj+OSTo8jFgsjKxYPK8KPIxYLIysWDyt/p3ueA -vpCXbO/w05QHUDPg/3QBqAcIgALDM9j89P+QAEfgX/B/EH4AEjdUkJds4P90AagHCIACwzPY/PT/ -kABGgDuQl2zgJPjw4P90AagHCIACwzPY/MRU8PT/kABD4F/wfxB+ABI3VJCXbOD/dAGoBwiAAsMz -2Pz0/5AAQ+Bf8H8QfgASN1Qi5JCXTvDlZmBs5WVkAXBm5WZkAmAG5WZkA3AdkJef4BTw4GAEo+Bg -FpCXn+BwCpCXquCQl5/wgACQl050AfCQl07gYDGQl6/gRBDwkJel4PVE5PVF+/1/VH4BEjWrkAFX -dAXwkJeo4FQPw5QEUAd9AX8EEm9JIqsHdfAJ66QkZ/WC5fA0k/WD4P90xSv1guQ0lvWD4FQf+tOf -QAKqB+ol4CSe9YLkNEH1g+ST/nQBk//qJeAkZvWC5DRB9YN0AZMv/+STPsMT/u8T/+T8/esl4CXg -JOH1guQ0kvWDEip/dIQr9YLkNAT1g+rw/yKQBqng9QpUwHAOkJep8JCXq+D/fQECb0nlCjDmEpCX -qXQB8JCXr+BEAfASffqAB5CXr+BU/vDlCjDnKZCXqXQB8JCXr+BEAvB1RAPk9UX7/X9UfgESNauQ -AVd0BfCQl650AfAikJev4FT98CKNC+ULVB/1D3QBL/WC5DSS9YPg9Q6QBP3gtAEFdRADgAN1EAHr -05UQQAMCddjlDiUN/uUPkEHWk/3u0510AUAYL/WC5DSS9YPk8HSEL/WC5DQE9YPlC/AiL/WC5DSS -9YPu8CKQACvgRAHwf+h+AxI3VJAACOBEEPB/EH4AEjdUkAAJ4FT38H8QfgASN1SQACjgVP7wfxB+ -ABI3VJAAIOBU/vB/EH4AEjdUkAAl4ERA8H8QfgASN1SQAAngVO/wfxB+AAI3VIsRihKJExJ96KsR -qhKpExIp2fVmFGAOFGAPFGAaJANwPH8BgDXk/4AxkJeqdAHwkJef8OT/gCOrEaoSqROQAAISYn// -kJeqcAV0BfCAAu/wkJeq4JCXn/Dk/xJzTCKQACXgVL/wfxB+ABI3VJAAIOBEAfB/EH4AEjdUkAAo -4EQB8H8QfgASN1SQAPDgMOH5kAAJ4EQI8H8QfgASN1SQAAjgVO/wfxB+ABI3VJAAK+BU/vB/6H4D -AjdUkABF5PCQBP3wo/CQl43wkJeT8JCXlvCQl5TwkJeX8JCXlfCQl5jwkJd/BPDko/Cj8KPwkJeE -8JCXifCQl4vwkJed8JCXjvCQl4rwkJeD8JAAUeBEwPAii16KX4lgkJe46/Cj6vCj6fCj5WHwo+Vi -8KPlY/CvZBVk72AqkJe74Puj5HXwARJi9qnw+hIp2f+Ql7jg+6PkdfABEmL2qfD67xJirIDPq16q -X6lgIpAFYOCQl5nwkAVh4JCXmvCQBWLgkJeb8JAFY+CQl5zww3T/n/6Ql5rg055AHuAv8KPgtP8P -5PCj4LT/A+TwIpCXnIADkJeb4ATwIpCXmuAv8CLk9WWQl6/w9WaQl6t0DPCQl6jw5JCXrfCQl6fw -kJem8JCXqgTwkJef8OSQl67wkJep8JCXofCQl6V0B/DkkJeg8JCXo/CjdALw5JCXrPAi5JCXtfCi -rzOQl1vwkACA4CDhGhI3ehI3epCXWuBkAfDgJIWQAcTwdHmj8IDfkAYwdAHwwq+QAIDgRIDwfxB+ -ABI3VJCXW+Ak/5KvIpCXruBgEuTwo+BU/fDgVANwM5CXqfCAI5CXoOAE8JCXr+BU7/CQl6Dg05QB -QA3lZbQBEqPgcA7gBPAikJer4P99ARJvSSLkkJfN8KPwkAX44HAPo+BwC6PgcAej4HADfwEi05CX -zuCU6JCXzeCUA0ADfwAifzJ+ABI3VJCXzuAE8HDKkJfN4ATwgMLkkJda8O+QADHw7lQD/6PgVPxP -8KPgVH/wkAAw4CDnDpCXWuDDlGRQBeAE8IDrkJda4MOUZFAKkAAw4BJirH8BIn8AIuVVcDeQl6vg -VA/TlAFQLJACh+BwJpCXtuC0AhCQl7Dg/qPg9YKOg+BgCIAPkAGv4HAJkJes4GADfwEifwAiEinZ -/8OUIFAVkAACEmJ//nRDL/WC5DSV9YPu8IAO77QgCpAAAhJif5CTYfB0Qy/1guQ0lfWD4JAEsvAi -kAQb4FR/ZH9wK5CXqeBkAWAjkJer4FQP05QCUBiQl6/gIOQRkJen4GQBYAmQl6HgcAN/ASJ/ACKQ -ATd0AvCQBSJ0//ASehfvcAaQAch0/fB9An8DEjbm5WZgBX8BEn20EmsbkJeo4FTw8OBEAvAikAAC -EmJ/kJeN8OCQBJvwkJeN4GAE4LT/HKKv5DP1EcKvkABH4FT78H1AfwESNq/lEST/kq8ij2eQl7Tg -/30BEnC95WdgEHQhL/WC5DT89YPgRBDwgA50IS/1guQ0/PWD4FTv8JAEH3QB8CKQl2ru8KPv8HUi -AY4j9SR/CxJ03xJ9l+T/En5HkJdq4Pyj4P3s+41E5PVFfQF/YH4BAjWrfQJ/AxI2deVmYCOQl63g -YAZ9AX8MgA+Ql6jgVA/DlARQB30BfwQSb0nk/xJ9tCKQAgng/RIp2f6vBe0ukJey8JAAARJif//t -L5CXs/CQAAISYn//rgXtL5CXtPAikAY04GAmFHAbewF6Bnk1f/l+ARJ6XL8BCZAGNeBUD/CABYAA -An4s5JAGNPAikAABEmJ/kJet8BIp2WVmYBWir+QzkJdm8MKvEnd/kJdm4CT/kq8ikJdO4FTwRAPw -VA9EgPCQl1Pk8KN0APCjdFbwewF6l3lOAnAHkAQb4FR//79/FJCXp+BwDpCXq+BUD9OUBFADfwEi -fwAikAYE4FS/8O9gCuVltAEF5P8Se7+Ql6jgVPDw4EQM8CKQl9Lv8BJyF5CX0uBgBZAFIuTwkJeo -4FTw8OBEBPAikAYE4ERA8OVltAEFfwESe7+Ql6jgVPDw4EQE8CKQl6jgVPDw4EQB8BJ3HRJ33ZCX -qOBU8PDgRALwIn8LEnFy72UlYBDlJbQBBeT1JYADdSUBfwEifwAi72ALkJe34LQBEOT/gAmQl7fg -tAEFfwESTl0ikABJ4JCX1PDgVA/w4P9E8JAASfDvRLDwIuSQl67wkJeg8JCXqfCQl6/wIpCXs+D/ -5P0ScL2QBB90AfAi5SK0AQsSfZe/AQV/ARJ+RyKQCSjv8KPwo/Cj8KPwo/AikAY0dP/w5KPwo/Cj -8CJBl9EAQZeegEGX0wAAkAHK5SXw72ADEn3PIpCXZuvwo+rwo+nwIpCXx+vwo+rwo+nwIpCXyuvw -o+rwo+nwIo+CjoOjo6Pk8CLk9SJ/YH4BAn54kJe34JCXTfAijxyMHY0eIo8fjCCNISISKdn1ZSIi -4fs= -==== diff --git a/sys/contrib/dev/urtwn/urtwn-rtl8192cfwU.fw.uu b/sys/contrib/dev/urtwn/urtwn-rtl8192cfwU.fw.uu deleted file mode 100644 index 8859c82a137b..000000000000 --- a/sys/contrib/dev/urtwn/urtwn-rtl8192cfwU.fw.uu +++ /dev/null @@ -1,285 +0,0 @@ -begin-base64 644 urtwn-rtl8192cfwU.fw.uu -wYgCADwAAAAKKBQkrD4BAEM0AQAAAAAAAAAAAAAAAAACdFwAAAAAAAAAAAAAAAAAAAAAAlmZAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnK6AAAAAAACaAEAAAUE -AwIAAwYFBAMABAYFBAIABAgHBgQABgoJCAYACAoJCAQACAoJCAIACAoJCAAACBIREAgAEBoZGBAA -GCIhIBgAICIhIBAAICIhIAgAICIhHAgAICIhFAgAICIgGAgAIDEwIBAAMDEwGAAAMDEvEBAAMDEs -EBAAMDEoEAAAMDEgEAAAMDEQEAAAMAQEBAUEBAUHBwcICgQEBAQGCg0OBQUHBwgMFBQEBAQFBwcJ -CQwOExMEBAQEBQoREwkJCQkMExQVBQUFBQUFBQYGBgYGBQUFBgYGBgYFBQYGBgYGBgUFBQUJCQkJ -Cw0QEgUJCgwNDhASCQkODhAQEhIAAAAAAAAAAAAkJioYGh0fIScpKgAAAB8jKCosAAQABAAIABAA -GAAkADAASABgAJAAwADYAFAAeACgAMgBQAGQAeACMAEsAUAB4ALQA+gEsAZAB9AAAgACAAQACAAM -ABIAGAAkADAASABgAGwAKAA8AFAAZACgAMgA8AEYAGQAoADwAWgB9AJYAyAD6AAAAAABAgICAwQF -CAECAgIEBw8eBQYHDxIjRmQBAQEBAQIDBAUGBwgBAgMEBQYHCAUGBwgJCgsMIh8eGAAgAAAAAAAA -AAAAAAAAqwd0hCv1guQ0BPWD4FR/kJd08OBUH6Pw+nXwCeukJGf1guXwNJP1g+D5kJd38Osl4CSB -9YLkNJL1g+D/o+CQl3jP8KPv8Osl4CQE9YLkNJb1g+D/o+CQl3rP8KPv8Ool4CRm9YLkNEH1g+ST -/nQBk//k/P3rJeAl4CTh9YLkNJL1gxIlCOrDmUADAkNZkJd14P90xSv1guQ0lvWD7/DvBJCXdvCQ -l3fg/5CXduD+059AAwJDmO7DlBBAIe4k8P90AX4AqAcIgAXDM84zztj5/5CXeOBe/qPgX05wJ5CX -duD/w5QQUEp0AX4AqAcIgAXDM84zztj5/5CXeuBe/qPgX05gLZCXduD/ZBNgCe9kEmAE77QRDZCX -eOAw4AaQl3Z0GPCQl3bgkJd18JCXdPCASJCXduAE8AJCxJCXd+D6kJd14P9qcHl0xSv1guQ0lvWD -7/B18AnrpCRp9YLl8DST9YPgtAETkJd04P8w5gEikJd14ERAkJd08JCXdeD/JeAknvWC5DRB9YPk -k/x0AZP97yXgJGb1guQ0QfWDdAGTLf/kkzzDE/7vE//k/P3rJeAl4CTh9YLkNJL1gxIlCIBpkJd1 -4NOaQGGQl3fg/3TFK/WC5DSW9YPv8JCXde/wkJd08Pqj4P8l4CSe9YLkNEH1g+ST/HQBk/3vJeAk -ZvWC5DRB9YN0AZMt/+STPMMT/u8T/+T8/esl4CXgJOH1guQ0kvWDEiUIrwIidAEr9YLkNJL1g+Tw -kJd04ESA/3SEK/WC5DQE9YPv8CKQl2br8KPq8KPp8KKv5DOj8MKvkJdm4Puj4Pqj4PmQAAESYzf6 -5fAkAP/kOv6Ql2aj4PqQAAHuj/ASY44SJGL/YDe1IhuQl2bg+6Pg+qPg+ZAAARJjN2UkcATlI2Xw -YC6Ql2bg+6Pg+qPg+ZAAARJjN/+u8BJ79IAVkJdm4Puj4Pqj4PkSJGJlImADEn6CkJdp4CT/kq8i -5PUlIgJ+lQJ+nOSQl1rwkJda4P/DlCBAAwJOXHXwCe+kJGr1guXwNJP1g+BkAWADAk5TkJda4CXg -JMD1guQ0kfWD4Pyj4NOUAOyUAFADAk5T73XwCqQkAPl0kDXw+nsBixT1FYkWkJda4CXgJMD1guQ0 -kfWD4P2j4JCXZs3wo+3w7yXgJIP1guQ0lPWD4P+j4JCXaM/wo+/wkAACEmM3/67wEmMML//l8D6Q -l2/wo+/wkAAGEmM3/67wkAAEEmM3L//l8D6Ql23wo+/wkAAIEmM3/5CXa+Xw8KPv8JCXWuD+JIT1 -guQ0BPWD4FQ/kJdc8OD9VB+j8HXwCe6kJGf1guXwNJP1g+CQl3HwkJda4PskhPWC5DSW9YPgw5QF -QAMCSbqQl3Hg/pCXXeCeQBOQl3HgkJdd8O1UQP2Ql1zw7k3wkAT94GQBcCiQl13g/5BBSpP+dEMr -9YLkNJX1g+DDnkAG75BBEoAykJdd4JBBLoApkJdd4P+QQUqT/pCXWuAkQ/WC5DSV9YPgw55ABu+Q -QNqAB5CXXeCQQPaTkJdq8JCXauB18AakJFD5dEA18HUR//USiROQl1zgkEHyk//TkJdp4J+Ql2jg -lABADZCXWuD/5P0SXzICTemQl1rgJeAl4CTh9YLkNJL1g+D8o+D9o+D+o+D/kJdeEiUIkJde4Pij -4Pmj4Pqj4PvAAMABwALAA6sRqhKpExIkYv9+AKsUqhWpFhJjDP2s8BIke+T8/dAD0ALQAdAA6y// -6j7+7Tn97Dj8kJdeEiUIkJde4Pij4Pmj4Pqj4PvAAMABwALAA6sRqhKpE5AAARJif/9+AKsUqhWp -FpAAAhJjN/2s8BIke+T8/dAD0ALQAdAA6y//6j7+7Tn97Dj8kJdeEiUIkJde4Pij4Pmj4Pqj4PvA -AMABwALAA6sRqhKpE5AAAhJif/9+AKsUqhWpFpAABBJjN/2s8BIke+T8/dAD0ALQAdAA6y//6j7+ -7Tn97Dj8kJdeEiUIkJde4Pij4Pmj4Pqj4PvAAMABwALAA6sRqhKpE5AAAxJif/9+AKsUqhWpFpAA -BhJjN/2s8BIke+T8/dAD0ALQAdAA6y//6j7+7Tn97Dj8kJdeEiUIkJde4Pij4Pmj4Pqj4PvAAMAB -wALAA6sRqhKpE5AABBJif/9+AKsUqhWpFpAACBJjN/2s8BIke+T8/dAD0ALQAdAA6y//6j7+7Tn9 -7Dj8kJdeEiUIqxGqEqkTkAAFEmJ//34AkJdm4Pyj4P0SJHvk/P2Ql17g+KPg+aPg+qPg+9MSY7uQ -l15AUOD8o+D9o+D+o+D/wATABcAGwAerEaoSqROQAAUSYn//fgCQl2bg/KPg/RIke6sHqgbQB9AG -0AXQBMPvm//umv7tlAD97JQA/JCXXhIlCIAHEiUUAAAAAJCXXuD8o+D9o+D+o+D/kJda4CXgJeAk -4fWC5DSS9YMSJQiQl1zgJeAkZvWC5DRB9YPkk/50AZP/5Pz9kJde4Pij4Pmj4Pqj4PvTEmO7QAuQ -l1rg/xJCIAJNYJCXXOAl4CSe9YLkNEH1g+ST/nQBk//k/P2Ql17g+KPg+aPg+qPg+8MSY7tAAwJN -YJCXWuD/fQESXzICTWCQl1rg/ySE9YLkNJb1g+BkBWADAkujdfAJ76Qka/WC5fA0k/WD4GQBcAMC -S6OQk2Lg/7QDC5CXXeDDlBlAPYAu77QCC5CXXeDDlBFALoAfkJNi4P+0AQuQl13gw5QKQBuADO9w -EZCXXeDDlANADZCVY3QB8IAF5JCVY/CQl1rg/yRD9YLkNJX1g+D+w5QwUAvkkJdy8HSELwJLTZCV -Y+BkAWADAktCkJda4CRk9YLkNJX1g+BkCmBbkJda4P/uJAX95DP8dCEv9YLkNJL1g+D/053sZID4 -dICYUDiQl1rg/u8kBf3kM/x0Qy71guQ0lfWD4NOd7GSA+HSAmFAWkJda4CSk9YLkNJb1g+D/kJdd -4G9gVpCXWuAkQ/WC5DSV9YPg/9OURkAIkJdydAXwgBHv05Q8kJdyQAV0A/CAA3QB8JCXWuD/JEP1 -guQ0lfWD4P50IS/1guQ0kvWD7vCQl1rgJGT1guQ0lYAvkJda4P8khPWC5DSW9YPk8HRkL/WC5DSV -9YPgBPCAFOSQl3LwkJda4CSE9YLkNJb1g+TwkJdd4P+Ql1rg/iSk9YLkNJb1g+/w7jDgHpCXcuDE -VPDwkJda4MMT/ySk9YLkNAT1g+BUDwJNQ5CXWuDDE/8kpPWC5DQE9YPgVPACTUOQl1rg/ySE9YLk -NJb1g+BkBmADAk1gdfAJ76Qka/WC5fA0k/WD4GQBcAMCTWCQl14SJRQAAAAAkEIT5JP/fgCQl2bg -/KPg/RIke+T8/ZCXYhIlCOSQl1vwkJde4Pij4Pmj4Pqj4PvAAMABwALAA6sUqhWpFpCXW+D/dfAC -pPWChfCDEmM3/azw75BCDpP/fgASJHvk/P3QA9AC0AHQAOsv/+o+/u05/ew4/JCXXhIlCJCXYuD8 -o+D9o+D+o+D/kJde4Pij4Pmj4Pqj4PvTEmO7UA6Ql1vgBPDgZAVgAwJL+5CXW+DDE/CQl3Lg/7QB -DZCXW+BwXZCXcgTwgFvvtAMdkJdb4P9wCJCXcnQD8IBI77QBCJCXcnQB8IA8gDWQl3LgZAVwMpCX -W+D/cAiQl3J0BfCAD++Ql3K0AQV0A/CAA3QB8NOQl2nglAOQl2jglABABeSQl3Lw05CXaeCUA5CX -aOCUAEAF5JCXcvCQl1rg/zDgGpCXcuDEVPDw78MT/ySk9YLkNAT1g+BUD4ATkJda4MMT/ySk9YLk -NAT1g+BU8PB0pC/1guQ0BPWDwIPAguD/kJdy4P7vTtCC0IPwkJda4P8khPWC5DSW9YPg05QFUA90 -hC/1guQ0lvWD4ATwgA+Ql1rgJIT1guQ0lvWD5PCQl1rg/ySE9YLkNAT1g+BUH8OUCVAFkJIAgBF0 -hC/1guQ0BPWD4JCSACDiBXQI8IADdATwkJda4GANkJbE4P+QkgDgw59QCJCSAOCQlsTwkJbE4JAE -gPCrFKoVqRbk9fASY2+rFKoVqRaQAALk9fASY46QAATk9fASY46QAAbk9fASY46QAAjk9fASY46Q -l1rg/yXgJMD1guQ0kfWD5PCj8O8l4CSD9YLkNJT1g+Two/DvJeAkw/WC5DSU9YPk8KPwkJda4ATw -AkUOIu9wAwJQxZCXTeBgAwJVB5CXOeD8o+D9o+D+o+D/kICWEiUIf4x+CBIrCJCW5eD8o+D9o+D+ -o+D/kICWEiUIf0R+CBIrCJCW6eD8o+D9o+D+o+D/kICWEiUIf1x+CBIrCJCW7eD8o+D9o+D+o+D/ -kICWEiUIf2x+DhIrCJCW8eD8o+D9o+D+o+D/kICWEiUIf3B+DhIrCJCW9eD8o+D9o+D+o+D/kICW -EiUIf3R+DhIrCJCW+eD8o+D9o+D+o+D/kICWEiUIf3h+DhIrCJCW/eD8o+D9o+D+o+D/kICWEiUI -f3x+DhIrCJCXAeD8o+D9o+D+o+D/kICWEiUIf4B+DhIrCJCXBeD8o+D9o+D+o+D/kICWEiUIf4R+ -DhIrCJCXCeD8o+D9o+D+o+D/kICWEiUIf4h+DhIrCJCXDeD8o+D9o+D+o+D/kICWEiUIf4x+DhIr -CJCXEeD8o+D9o+D+o+D/kICWEiUIf9B+DhIrCJCXFeD8o+D9o+D+o+D/kICWEiUIf9R+DhIrCJCX -GeD8o+D9o+D+o+D/kICWEiUIf9h+DhIrCJCXHeD8o+D9o+D+o+D/kICWEiUIf9x+DhIrCJCXIeD8 -o+D9o+D+o+D/kICWEiUIf+B+DhIrCJCXJeD8o+D9o+D+o+D/kICWEiUIf+x+DhIrCJCXKeD8o+D9 -o+D+o+D/kICWEiUIfwR+DBIrCJCXLeD8o+D9o+D+o+D/kICWEiUIfwR+DRIrCJCXMeD8o+D9o+D+ -o+D/kICWEiUIfwx+CRIrCJCXNeD8o+D9o+D+o+D/kICWEiUIfwR+CBIrCJCXTXQB8CKQl03gZAFg -AwJVB3+MfggSImWQlzkSJQh/RH4IEiJlkJblEiUIf1x+CBIiZZCW6RIlCH9sfg4SImWQlu0SJQh/ -cH4OEiJlkJbxEiUIf3R+DhIiZZCW9RIlCH94fg4SImWQlvkSJQh/fH4OEiJlkJb9EiUIf4B+DhIi -ZZCXARIlCH+Efg4SImWQlwUSJQh/iH4OEiJlkJcJEiUIf4x+DhIiZZCXDRIlCH/Qfg4SImWQlxES -JQh/1H4OEiJlkJcVEiUIf9h+DhIiZZCXGRIlCH/cfg4SImWQlx0SJQh/4H4OEiJlkJchEiUIf+x+ -DhIiZZCXJRIlCH8EfgwSImWQlykSJQh/BH4NEiJlkJctEiUIfwx+CRIiZZCXMRIlCH8EfggSImWQ -lzUSJQh/jH4IEiJlkJfDEiUIkJfD4Pyj4P2j4P6j4P/tRMD97JCXwxIlCJCXw+D8o+D9o+D+o+D/ -kICWEiUIf4x+CBIrCJCAlhIlFAABAAB/RH4IEisIkICWEiUUANslpH9cfggSKwiQgJYSJRQg2yWk -f2x+DhIrCJCAlhIlFCDbJaR/cH4OEisIkICWEiUUBBslpH90fg4SKwiQgJYSJRQEGyWkf3h+DhIr -CJCAlhIlFAQbJaR/fH4OEisIkICWEiUUBBslpH+Afg4SKwiQgJYSJRRj2yWkf4R+DhIrCJCAlhIl -FAQbJaR/iH4OEisIkICWEiUUINslpH+Mfg4SKwiQgJYSJRQg2yWkf9B+DhIrCJCAlhIlFCDbJaR/ -1H4OEisIkICWEiUUINslpH/Yfg4SKwiQgJYSJRQAGyWkf9x+DhIrCJCAlhIlFAAbJaR/4H4OEisI -kICWEiUUJNslpH/sfg4SKwh/BH4MEiJlkJfDEiUIkJfD4Pyj4P2j4P7k/+yQl8MSJQiQl8Pg/KPg -/aPg/qPgRBH/7JCXwxIlCJCXw+D8o+D9o+D+o+D/kICWEiUIfwR+DBIrCH8Efg0SImWQl8MSJQiQ -l8Pg/KPg/aPg/qPgVPD/7JCXwxIlCJCXw+D8o+D9o+D+o+BEAf/skJfDEiUIkJfD4Pyj4P2j4P6j -4P+QgJYSJQh/BH4NEisIfwx+CRIiZZCXwxIlCJCXw+D8o+D9o+D+5P/skJfDEiUIkJfD4Pyj4P2j -4P6j4EQR/+yQl8MSJQiQl8Pg/KPg/aPg/qPg/5CAlhIlCH8MfgkSKwh/DH4JEiJlkJfDEiUIkJfD -4Pyj4P2j4P6j4P/tVA/97FTw/JCXwxIlCJCXw+D8o+D9o+D+o+D/7UQQ/exEAfyQl8MSJQiQl8Pg -/KPg/aPg/qPg/5CAlhIlCH8MfgkSKwh/BH4IEiJlkJfDEiUIkJfD4Pyj4P2j4P6j4FTw/+yQl8MS -JQiQl8Pg/KPg/aPg/qPgRAH/7JCXwxIlCJCXw+D8o+D9o+D+o+D/kICWEiUIfwR+CBIrCOSQl03w -Io8R7yXgJAT1guQ0lq+C9RKPE+URdfACpCSB+XSSNfB1FAH1FYkWdfAJ5RGkJGX1guXwNJOvgvUX -jxjlEXXwCaQkY/l0kzXwdRkB9RqJG3TBJRH1guQ0kvWD4BJj2FWKAFWfAVW0AlXJA1XzBFYIBVYd -BlZEDFZyDVafDlbMDwAAVwDlESXgJAT1guQ0lvWDdPDwo3QVgDzlESXgJAT1guQ0lvWDdPDwo3QQ -gCflESXgJAT1guQ0lvWDdPDwo3QFgBLlESXgJAT1guQ0lvWDdPDwo+Tw5REl4CSB9YLkNJL1g3QP -8KN0j/ACVwDlESXgJAT1guQ0lvWDdA/wo3T1gCflESXgJAT1guQ0lvWDdA/wo3TwgBLlESXgJAT1 -guQ0lvWD5PCjdA3w5REl4CSB9YLkNJL1g+Two/ACVwCQBEfgqxSqFakWEmKskARG4KsUqhWpFpAA -ARJivpAEReCFE4KFEoPwkAREAlb3kARL4KsUqhWpFhJirJAESuCrFKoVqRaQAAESYr6QBEnghROC -hRKD8JAESIBYkARP4KsUqhWpFhJirJAETuCrFKoVqRaQAAESYr6QBE3ghROChRKD8JAETIArkART -4KsUqhWpFhJirJAEUuCrFKoVqRaQAAESYr6QBFHghROChRKD8JAEUOCFE4KFEoOj8KsUqhWpFsAD -wALAARIkYv+rGaoaqRsSJGJf0AHQAtADEmKsqxTlFiQB+eQ1FfrAA8ACwAESJGL/qxmqGqkbkAAB -EmJ/X9AB0ALQAxJirIUTgoUSg8CDwILg/4UYgoUXg+D+717QgtCD8IUTgoUSg6PAg8CC4P+FGIKF -F4Oj4P7vXtCC0IPw5REl4CSB9YLkNJL1g+D+o+BOYEyQl3J0C/CQl3Lg/8OUAFADAlhGdAF+AKgH -CIAFwzPOM87Y+f/lESXgJIH1guQ0kvWD4F7+o+BfTmAKkJdy4CQQo/CAaJCXcuAU8IC65REl4CQE -9YLkNJb1g+D+o+BOYEeQl3J0D/CQl3Lg/8OUAEA8dAF+AKgHCIAFwzPOM87Y+f/lESXgJAT1guQ0 -lvWD4F7+o+BfTmAIkJdy4KPwgA2Ql3LgFPCAv+SQl3Pw5REl4CQE9YLkNJb1g+D+o+BOYEfkkJdy -8JCXcuD/w5QQQAMCWQB0AX4AqAcIgAXDM84zztj5/+URJeAkBPWC5DSW9YPgXv6j4F9OYAaQl3Lg -gGOQl3LgBPCAvuURJeAkgfWC5DSS9YPg/qPgTmBG5JCXcvCQl3Lg/8OUDFA8dAF+AKgHCIAFwzPO -M87Y+f/lESXgJIH1guQ0kvWD4F7+o+BfTmAIkJdy4CQQgAmQl3LgBPCAv+SQl3TwkJdz4P918Anl -EaQkZ/WC5fA0k/WD7/CQl3Tg/nXwCeURpCRo9YLl8DST9YPu8HSEJRH1guQ0BPWD4NOfQB+Ql3Pg -/3SkJRH1guQ0lvWD7/B0hCUR9YLkNAT1g+/wkJdz4P/TlBNACJCTYnQD8IAh79OUC0AIkJNidALw -gBPv05QDQAiQk2J0AfCABeSQk2LwkJNi4JAEsfAiwODA8MCDwILA0HXQAMAAwAHAAsADwATABcAG -wAeQAcR0mfB0WaPwkAE34FUr9S+QATTgVSj1LJABNuBVKvUu5Swg4AMCW0uQATR0AfCF0U2F0k6F -00+F1FCF1VGF1lKF11OF2VTlVFRAwxP/5VNUIG9wAwJa+OVUMOUDAlr45VJUH/UI5U1UP/UJ5VFU -H//lCCXgJAP1guQ0lfWD5I/wEmLg5VNUH//lCCXgJMD1guQ0kfWD5I/wEmLg5QnTlARAA3UJBHXw -CuUIpCQA9YLl8DSQ9YN18ALlCRJjzOD+o+D/5VNUHy//5D7+dfAK5QikJAD1guXwNJD1g3XwAuUJ -EmPM7vCj7/DlVCDmJOVTVB//5Qgl4CSD9YLkNJT1g+SP8BJi4OVPMOc2rwgSddiAL+VTVB//5Qgl -4CTD9YLkNJT1g+SP8BJi4OVPMOcS5U9Uf/3lU1Qf9Q2rCa8IEna65WZgT5CXreBgNZABW+TwkAE8 -dATwkAQb4FR/ZH9wNHVEFPVF+/1/WH4BEjBikAFbdAXwkAaSdAHwkJen8IAUkAQb4FR//79/CpCX -q+D/fQESb0nlLDDhIZABNHQC8IXRVoXSV4XTWIXUWYXVWoXWW4XXXIXZXRJ82eUsMOMGkAE0dAjw -5Sww5AmQATR0EPBDVRDlLDDlIZABz+Aw5RrgVN/wkAE0dCDwkAAD4FT78H8QfgASMhWA/uUsMOYG -kAE0dEDw5S4w4QmQATZ0AvBDVUDlLjDgCZABNnQB8BJ1YuUuMOJjkAE2dATw5WVkAXBX5WZgU+Vm -ZAJwJ5AGq+CQl5/wkAaq4JCXqvCQl5/gcAeQl6rg/4AFkJef4P+Ql5/v8JCXoeBgA+AU8JCXoOTw -kAFX8JABPHQC8JCXr+BU/fDgVO/wEnZO5S4w4zGQATZ0CPDlZWQBcCXlZmAhkAFX5PCQATx0AvB1 -RAN1RQDk+/1/VH4BEjBikAFXdAXw5S4w5DqQATZ0EPDlZWQBcC7lZmAqkAFX5PCQATx0AvCQl67k -8JCXr+BU/fDgVANwDpCXqfCQl6vg/30BEm9J5S4w5RKQATZ0IPDlZbQBB+VmYAMSffrlLjDmKpAB -NnRA8OVlZAFwHuVmYBqQl6/gVP7w4FQDcA6Ql6nwkJer4P99ARJvSeUvMOEJkAE3dALwEnwodJkE -kAHE8HRZo/DQB9AG0AXQBNAD0ALQAdAA0NDQgtCD0PDQ4DKQBER0EfCjdPDwo3QP8KPk8JCXWvCQ -l1rg/8OUEFAUdKQv9YLkNAT1g+TwkJda4ATwgOLkkJda8JCXWuD7w5QgQAMCXzHg/3XwCqQkAPWC -5fA0kPWD5PCj8HXwCu+kJAL1guXwNJD1g+Two/B18ArvpCQE9YLl8DSQ9YPk8KPwdfAK76QkBvWC -5fA0kPWD5PCj8HXwCu+kJAj1guXwNJD1g+Two/B0pC/1guQ0lvWDdBPwdGQv9YLkNJX1g+Tw7yXg -JMD1guQ0kfWD5PCj8O8l4CSD9YLkNJT1g+Two/DvJeAkA/WC5DSV9YPk8KPw7yXgJMP1guQ0lPWD -5PCj8O8l4CSE9YLkNJX1g+Two/DvJeAkxPWC5DSV9YPk8KPwdGQv9YLkNJb1g+TwdEQv9YLkNJb1 -g+TwdIQv9YLkNJb1g+TwkEHEk/50AZP/kEGMdAGTL//kkz7DE/7vE//k/P3rJeAl4CTh9YLkNJL1 -gxIlCHXwCeukJGr1guXwNJP1g3QB8HXwCeukJGn1guXwNJP1g3QB8HTBK/WC5DSS9YN0DPB18Anr -pCRl9YLl8DST9YN0//Cj8HXwCeukJGP1guXwNJP1g+Two3QP8HXwCeukJGf1guXwNJP1g3QT8HXw -CeukJGj1guXwNJP1g+TwdIQr9YLkNAT1g3QT8JCXWuAE8AJdZiKpB3SEKfWC5DQE9YPgVH+Ql3Tw -4FQf/5CXd/B18AnppCRo9YLl8DST9YPgkJd58HXwCemkJGf1guXwNJP1g+D+kJd68Okl4CQE9YLk -NJb1g+D7o+CQl3vL8KPr8Okl4CSB9YLkNJL1g+D7o+CQl33L8KPr8O/TnkAMkJd64JCXd/CQl3Tw -7XADAmCRkJd47fCQl3TgMOYOkJd34JCXdPCQl3jgFPCQl3jgcAMCYJGQl3fg/9OUAFADAmCR5JCX -dvDvFJCXdfCQl3ng/ZCXdeD/051Ab++UEEAh7yTw/3QBfgCoBwiABcMzzjPO2Pn/kJd94F7+o+Bf -TnAnkJd14P/DlBBQN3QBfgCoBwiABcMzzjPO2Pn/kJd74F7+o+BfTmAakJd14JCXdPCQl3bgBPCQ -l3jg/5CXduBvYAiQl3XgFPCAg5CXeOD/kJd24MOfUA+Ql3XgtQUIkJd54JCXdPCQl3Tg/yXgJJ71 -guQ0QfWD5JP8dAGT/e8l4CRm9YLkNEH1g3QBky3/5JM8wxP+7xP/5Pz96SXgJeAk4fWC5DSS9YMS -JQiQl3Tg/3SEKfWC5DQE9YPv8CKQAczgVA+Ql1rwkJda4P1wAwJifpCX0eD/dAF+AKgHCIAFwzPO -M87Y+f/vXXADAmJfkJfR4HXwBKQk0PWC5fA0AfWD4JCXW/Cir+Qzo/DCr3VhAXVil3VjW3VkAXsB -epd5XRJ4j5CXXOAk/5Kvo+D/xBMTE1QBkJfRMOBw4HXwAqQkiPWC5DXw9YPgkJde8JCX0eB18AKk -JIn1guQ18PWD4JCXX/CQl9HgdfAEpCTR9YLl8DQB9YPgkJdg8JCX0eB18ASkJNL1guXwNAH1g+CQ -l2HwkJfR4HXwBKQk0/WC5fA0AfWD4JCXYvCAQuB18ASkJNH1guXwNAH1g+CQl17wkJfR4HXwBKQk -0vWC5fA0AfWD4JCXX/CQl9HgdfAEpCTT9YLl8DQB9YPgkJdg8O9Uf/97AXqXeV4SbbmQl1rg/5CX -0eD+dAGoBgiAAsMz2Pz0X5CXWvCQl9Hg/3QBqAcIgALDM9j8kAHM8JCX0eAE8OBUA/ACYPLCr3To -BJABxPB0YKPwkJda4JABxvCQl9HgkAHH8ID+IrsBDOWCKfWC5YM69YPgIlAG6SWC+OYiu/4G6SWC -+OIi5YIp9YLlgzr1g+STIrsBBomCioPwIlAC9yK7/gHzIvi7AQ3lgin1guWDOvWD6PAiUAbpJYLI -9iK7/gXpJYLI8iLF8Pij4CjwxfD45YIVgnACFYPgOPAio/jgxfAl8PDlghWCcAIVg+DIOPDoIrsB -ComCioPg9fCj4CJQBofwCecZIrv+B+P18AnjGSKJgoqD5JP18HQBkyK7ARDlgin1guWDOvWD4PXw -o+AiUAnpJYL4hvAI5iK7/grpJYL44vXwCOIi5YMq9YPpk/Xwo+mTIrsBComCioPw5fCj8CJQBvcJ -p/AZIrv+BvPl8AnzGSL4uwER5YIp9YLlgzr1g+jw5fCj8CJQCeklgsj2CKbwIrv+Ceklgsjy5fAI -8iLrn/Xw6p5C8OmdQvDonEXwIqQlgvWC5fA1g/WDItCD0IL45JNwEnQBk3ANo6OT+HQBk/WCiIPk -c3QCk2hg76Ojo4Df5JCXV/Cj8BJ5hZAAAuBU4JCXtmAFdAHwgAN0AvCQAPPgMOMIkJe3dAHwgAXk -kJe38JCXt+C0AROQAPLgMOcMkJewdP3wo3Qz8IAKkJewdP3wo3Qv8OT1VRJdLhJ+jBJ5NhIuARJE -/3UoM+T1KXUqAvUrkAEw5Sjwo+Up8KPlKvCj5SvwkADz4DDiDZAFQXQQ8JAFWvCj5PCQAWR0oPB1 -RP/k9UX7fQF/UH4BEjBidTAfdTEB5PUykAE45TDwo+Ux8KPlMvASeDiQl1nl2fCQATx0//Cj8KPw -kAE08KPwo/Cj8MKvkACA4ERA8H8QfgASMhV16ANDqIXSr5ABwOTwo/Cj8KPwkAHG8KPwkJdX4GQB -8CT+kAHE8HRjo/DlVTDmF8KvU1W/0q8SRQmQl43g/2ADtAEDEmkS5VUw5wfCr1NVf9Kv5VUw5ArC -r1NV79KvEmDokJeN4HADEmwKEnyFgKqQAAISYn+Ql4vwkAABEmJ/JeAl4JCXivASJGIl4CXgkJeO -8JCXi+CQBJjwkJeK4BMTVD+QBJnwkJeO4BMTVD+QBJrwkAVg4JCXmfCQBWHgkJea8JAFYuCQl5vw -kAVj4JCXnPCir+QzkJdp8MKvkJeK4P8SeOSQl2ngJP+Sr5CXi+BwAwJmjJCXiuBwAwJmjJCXjuBw -AwJmjKKv5DOQl2nwwq+Ql510AfCQl2ngJP+Sr5AAReBU/vCj4EQB8JCXg+BgHZCXj+D8o+D9o+D+ -o+D/kICWEiUIf4B+CBIrCIAGkAUidH/wkABF4FTv8JAFh+BkgPCQl5ngkAWE8JCXmuCQBYXwkJeb -4JAFhvCQl5zgkAWH8KKv5DOQl2nwwq+QATzgRCDwfSDk/xIxt4ArkJeL4HAtkJed8JAAReBU/vCj -4FT+8JAFIuTwoq8zkJdp8MKvfSDk/xIxSZCXaeAk/5KvIpCXZuvwo+rwo+nwkJdm4Puj4Pqj4PmQ -AAQSYn//VB+Ql2nwkAADEmJ/VPDEVA+Ql2rw71QgxBNUB6PwkAAEEmJ/VEDEExNUA5CXbPCQl2ng -/3XwCaQkZfWC5fA0k62CkJdt8KPt8O918AmkJGP5dJM18PqjdAHwo+rwo+nwkJdmo+D6o+D5kAAD -EmJ/VA//kJdv4Puj4Pqj4PnvEmKskJdm4Puj4Pqj4PmQAAISYn//kJdv4Puj4Pqj4PmQAAHvEmK+ -kJdm4Puj4Pqj4PmQAAESYn//kJdt4Pyj4P31goyD7/ASJGKNgoyDo/CQl2rg/pCXaeD/JMH1guQ0 -kvWD7vCQl2vg/nXwCe+kJGn1guXwNJP1g+7wdfAJ76QkavWC5fA0k/WDdAHwkJds4P518AnvpCRr -9YLl8DST9YPu8AJVCMDgwPDAg8CCwNB10ADAAMABwALAA8AEwAXABsAHkAHEdAHwdGij8FOR35AB -POBVMPU0o+BVMfU1o+BVMvU25TQw4A+QATx0AfCQAVN0B/BDVYDlNDDhCZABPHQC8BJ50eU0MOI6 -kAE8dATwkAaS4DDgHnVEFHVFAOT7/X9YfgESMGKQAVt0BfCQBpJ0AfCAD5CXp+TwkJer4P99ARJv -SeU0MOMGkAE8dAjw5TQw5AmQATx0EPASfgvlNDDlCZABPHQg8BJuheU1MOAVkAE9dAHwkACD4JCX -q/Dg/30BEm9J5TYw4waQAT50CPB0AQSQAcTwdGij8NAH0AbQBdAE0APQAtAB0ADQ0NCC0IPQ8NDg -MpCXhODDlBRQBuAE8AJpzJCXhOBkFGADAmnMkJeT4HAlkJeW4HAfkJeU4HAZkJeX4HATkJeV4HAN -kJeY4HAHkAT94FT+8JCXk+CQBIjwkJeU4JAEifCQl5XgkASK8KPk8JCXluCQBIzwkJeX4JAEjfCQ -l5jgkASO8KPk8JCXf+CQBJDwkJeA4JAEkfCQl4HgkASS8JCXguCQBJPw5JCXhPCQl38E8OSj8KPw -o/CQl5Pwo/Cj8KPwo/Cj8JAFYOCQl1rwkAVh4JCXW/CQBWLgkJdc8JAFY+CQl13wkJec4P+Ql13g -/tOfUAuQl5zgw57TlAFAEZCXiuC0AQKAA5CXjuD/EnjkIpCX0O3wkJfP7/DTlAdQbeD/dAGoBwiA -AsMz2Pz0/5AAR+Bf8H8QfgASMhWQl8/g/3QBqAcIgALDM9j8/5AARuBP8H8QfgASMhWQl9DgYBaQ -l8/g/3QBqAcIgALDM9j8/5AARYB4kJfP4P90AagHCIACwzPY/PT/kABFgH2Ql8/gJPjw4P90AagH -CIACwzPY/MRU8PT/kABD4F/wfxB+ABIyFZCXz+D/dAGoBwiAAsMz2Pz/kABD4E/wfxB+ABIyFZCX -0OBgG5CXz+D/dAGoBwiAAsMz2PzEVPD/kABC4E+AGpCXz+D/dAGoBwiAAsMz2PzEVPD0/5AAQuBf -8H8QfgASMhUif3h+CBIiZZCXPRIlCH8EfgwSImWQl0ESJQh/AH4IEiJlkJdFEiUIkJe34JCXPbQB -E+D8o+D9o+D+o+BUx//tVMf9gA3g/KPg/aPg/qPgVMf/7JCAlhIlCH94fggSKwiQl0Hg/KPg/aPg -/qPgVA//7JCAlhIlCH8EfgwSKwiQl0Xg/KPg/aPg/qPgRAL/7JCAlhIlCH8AfggSKwh/cH4OEiJl -kJdJEiUIkICWEiUUABsloH9wfg4SKwiQgGgSJRQAAAAA5P3/EjAskJe34LQBEZCAaBIlFAAAAADk -/X8BEjAskAAR4FT28H8QfgACMhWQl53gZAFgCZCXi+BgAwJs4pCXf+DDlP9QBeAE8IA7kJeA4MOU -/1AG4ATw5IAokJeB4MOU/1AK4ATw5JCXgPCAFZCXguDDlP9QEOAE8OSQl4HwkJeA8JCXf/CQAETg -VAxgduAw4jKQl5Pgw5T/UAXgBPCAJJCXlODDlP9QBuAE8OSAEZCXleDDlP9QDOAE8OSQl5TwkJeT -8JAAROAw4zKQl5bgw5T/UAXgBPCAJJCXl+DDlP9QBuAE8OSAEZCXmODDlP9QDOAE8OSQl5fwkJeW -8JAE/eBEAfAiixGKEokTkAACEmJ/kJeM8OAw4FyQl4N0AfB/gH4IEiJlkJeFEiUIqxGqEqkTkAAB -EmJ//+T8/f54GhIk9agEqQWqBqsHkJeF4Pyj4P2j4P6j4P/sVAP860//6k7+6U396Ez8kJePEiUI -kAUi5PCANeSQl4Pwf4B+CBIiZexUA/zsRMD8kJeFEiUIkJeF4Pyj4P2j4P6j4P+QgJYSJQh/gH4I -EisIkJeM4JAARzDhEXQM8KPgRAzwkABG4EQQ8IAQ4FTz8KPgVPPwkABG4FTv8OSQl4nwIpCXY+vw -o+rwo+nw7xJj2G3qAW34Am4GA24UBW4iBm4wB24+CW5MDG5aDW5oDgAAbnaQl2Pg+6Pg+qPg+QJ8 -spCXY+D7o+D6o+D5An6jkJdj4Puj4Pqj4PkCfFeQl2Pg+6Pg+qPg+QJ63pCXY+D7o+D6o+D5AmbA -kJdj4Puj4Pqj4PkCflSQl2Pg+6Pg+qPg+QJEaJCXY+D7o+D6o+D5AmVfkJdj4Puj4Pqj4PkCe4mQ -l2Pg+6Pg+qPg+QJs48KvdLkEkAHE8HRto/CA/pCXi+BkAWADAm9IkABG4EQB8JCXneBwQJCXg+Bg -HZCXj+D8o+D9o+D+o+D/kICWEiUIf4B+CBIrCIAGkAUidH/wkJeK4P8SeOSQl510AfCQAEXgVP7w -gESQl53gZAFwPJCXjuD/Enjk5JCXnfCQAEXgRAHwkJeD4GAdkJeF4Pyj4P2j4P6j4P+QgJYSJQh/ -gH4IEisIgAWQBSLk8JAFh+BkgPCQl5ngkAWE8JCXmuCQBYXwkJeb4JAFhvCQl5zgkAWH8CKPJo0n -5SZUD/+Ql6jgVA9vYHjlJjDiMJCXqOAg4gV/ARJ9PpCXqOAw4wrlJiDjBRJ9XYBWkJeo4CDjT+Um -MONKrycSfR6AQ5CXqOBUD/+/DA7lJiDjCRJ8/e9gLhJ9XZCXqOBUD/+/BA7lJiDiCRJ7Gu9gFhJ7 -UpCXqOBUD/+/AgkSeqDvYAMSfXqQl6jgVA//kJer4FQPb3Aj4DDmH5CXqOBUD/+Ql57g/k+QAS/w -7mSAkJee8JCXq+BUv/AikJdQ6/Cj6vCj6fCQl7bgZAJwAwJwvJABr+BgCZABx+AE8PCA8ZCX0+D/ -BPCQl1Dg+6Pg+qPg+ZAAAe8SYr6ir+QzkJdW8MKvkJdQ4Puj4Pqj4IthimL1Y3VkAnsBegF5oBJ4 -j5CXVuAk/5Kvoq/kM/DCr5CXU+D7o+D6o+CLYYpi9WOQl1Dg+6Pg+qPg+RIkYv/EVA/1ZHsBegF5 -ohJ4j5CXVuAk/5KvkAGvdP/wkAHL4GSA8CKQl77v8KPt8OSj8KPw5WZgBeT/En20kJe+4DDgCZCX -wOTwo3SA8JAEHeBgHZAFIuCQl8Lw4P9UkGDskAHIdPzw71RvkAUi8IDdkJe+4P/DE5D9EPCQBCXv -8JCXv+BgH6Oj4P8kD/WC5DT89YPgRIDwdBAv9YLkNPz1g+BEgPCQl8Cj4P/9JAj1guQ0/PWD5PB0 -CS31guQ0/PWD4FTw8HQhL/WC5DT89YPgVPfwkJfA4P6j4P8ikJfV7/DTlAdQSuD/dAGoBwiAAsMz -2Pz0/5AARuBf8H8QfgASMhWQl9Xg/XQBfgCoBQiABcMzzjPO2Pn/kABE4Pvk/u9bqAUIgAbOoucT -zhPY+P8ikJfV4CT48OD/dAGoBwiAAsMz2Pz0/5AAQ+Bf8H8QfgASMhWQl9Xg/XQBfgCoBQiABcMz -zjPO2Pn/kABC4Pvk/u9bqAUIgAbOoucTzhPY+P8ikAAR4EQJ8H8QfgASMhWQlz3g/KPg/aPg/qPg -/5CAlhIlCH94fggSKwiQl0Hg/KPg/aPg/qPg/5CAlhIlCH8EfgwSKwiQl0Xg/KPg/aPg/qPg/5CA -lhIlCH8AfggSKwiQl0ng/KPg/aPg/qPg/5CAlhIlCH9wfg4SKwiQgGgSJRQAAy2V5P3/EjAskJe3 -4LQBEZCAaBIlFAADLZXk/X8BEjAsIsDgwPDAg8CCwNB10ADAAMABwALAA8AEwAXABsAHkAHEdLrw -dHKj8FOR75AAUeD/kABV4F/1PeU9MOYYdEDwkJeM4FQD/78DC5CXieBgBX8BEnPY5T0w5xWQAFV0 -gPCQl4zgVAP/vwMFfwISc9iQAcR0uvB0cqPw0AfQBtAF0ATQA9AC0AHQANDQ0ILQg9Dw0OAy72A0 -fX1/AhIxLH0CfwMSMSyQAVfk8JABPHQC8H0BfwwSb0nk/xJ9tJAGBOBUf/CQBgrgVPjwIpABNnR9 -8KN0AvB9ff8SMZ19An8DEjGdkAYE4ESA8JAGCuBEB/CQl6Pgo+CQBVjw5WUw4BuQl6HgcBrgBPCQ -l6jgVA/DlARQDH0BfwQCb0nkkJeh8CLvFGAgFGBLJAJweJCXiXQC8JAASOBEDPCQAEfgRAjwkABF -gFvkkJeJ8JCXheD8o+D9o+D+o+D/kICWEiUIf4B+CBIrCJAAReBE7/DgVO/wo4AtkJeJdAHwkJeP -4Pyj4P2j4P6j4P+QgJYSJQh/gH4IEisIkABF4EQg8OBEEPCj4EQQ8CICdJoCY/7kk6P45JOjQAP2 -gAHyCN/0gCnkk6P4VAckDMjDM8RUD0QgyINABPRWgAFG9t/kgAsBAgQIECBAgJB+OuR+AZNgvKP/ -VD8w5QlUH/7kk6NgAQ7PVMAl4GCoQLjkk6P65JOj+OSTo8jFgsjKxYPK8KPIxYLIysWDyt/p3ueA -vpCXbO/w05QHUDPg/3QBqAcIgALDM9j89P+QAEfgX/B/EH4AEjIVkJds4P90AagHCIACwzPY/PT/ -kABGgDuQl2zgJPjw4P90AagHCIACwzPY/MRU8PT/kABD4F/wfxB+ABIyFZCXbOD/dAGoBwiAAsMz -2Pz0/5AAQ+Bf8H8QfgASMhUi5JCXTvDlZmBs5WVkAXBm5WZkAmAG5WZkA3AdkJef4BTw4GAEo+Bg -FpCXn+BwCpCXquCQl5/wgACQl050AfCQl07gYDGQl6/gRBDwkJel4PVE5PVF+/1/VH4BEjBikAFX -dAXwkJeo4FQPw5QEUAd9AX8EEm9JIqsHdfAJ66QkZ/WC5fA0k/WD4P90xSv1guQ0lvWD4FQf+tOf -QAKqB+ol4CSe9YLkNEH1g+ST/nQBk//qJeAkZvWC5DRB9YN0AZMv/+STPsMT/u8T/+T8/esl4CXg -JOH1guQ0kvWDEiUIdIQr9YLkNAT1g+rw/yKQBqng9QpUwHAOkJep8JCXq+D/fQECb0nlCjDmEpCX -qXQB8JCXr+BEAfASffqAB5CXr+BU/vDlCjDnKZCXqXQB8JCXr+BEAvB1RAPk9UX7/X9UfgESMGKQ -AVd0BfCQl650AfAikJev4FT98CKNC+ULVB/1D3QBL/WC5DSS9YPg9Q6QBP3gtAEFdRADgAN1EAHr -05UQQAMCddjlDiUN/uUPkEHWk/3u0510AUAYL/WC5DSS9YPk8HSEL/WC5DQE9YPlC/AiL/WC5DSS -9YPu8CKQACvgRAHwf+h+AxIyFZAACOBEEPB/EH4AEjIVkAAJ4FT38H8QfgASMhWQACjgVP7wfxB+ -ABIyFZAAIOBU/vB/EH4AEjIVkAAl4ERA8H8QfgASMhWQAAngVO/wfxB+AAIyFYsRihKJExJ96KsR -qhKpExIkYvVmFGAOFGAPFGAaJANwPH8BgDXk/4AxkJeqdAHwkJef8OT/gCOrEaoSqROQAAISYn// -kJeqcAV0BfCAAu/wkJeq4JCXn/Dk/xJzTCKQACXgVL/wfxB+ABIyFZAAIOBEAfB/EH4AEjIVkAAo -4EQB8H8QfgASMhWQAPDgMOH5kAAJ4EQI8H8QfgASMhWQAAjgVO/wfxB+ABIyFZAAK+BU/vB/6H4D -AjIVkABF5PCQBP3wo/CQl43wkJeT8JCXlvCQl5TwkJeX8JCXlfCQl5jwkJd/BPDko/Cj8KPwkJeE -8JCXifCQl4vwkJed8JCXjvCQl4rwkJeD8JAAUeBEwPAii16KX4lgkJe46/Cj6vCj6fCj5WHwo+Vi -8KPlY/CvZBVk72AqkJe74Puj5HXwARJi9qnw+hIkYv+Ql7jg+6PkdfABEmL2qfD67xJirIDPq16q -X6lgIpAFYOCQl5nwkAVh4JCXmvCQBWLgkJeb8JAFY+CQl5zww3T/n/6Ql5rg055AHuAv8KPgtP8P -5PCj4LT/A+TwIpCXnIADkJeb4ATwIpCXmuAv8CLk9WWQl6/w9WaQl6t0DPCQl6jw5JCXrfCQl6fw -kJem8JCXqgTwkJef8OSQl67wkJep8JCXofCQl6V0B/DkkJeg8JCXo/CjdALw5JCXrPAi5JCXtfCi -rzOQl1vwkACA4CDhGhIyKxIyK5CXWuBkAfDgJIWQAcTwdHmj8IDfkAYwdAHwwq+QAIDgRIDwfxB+ -ABIyFZCXW+Ak/5KvIpCXruBgEuTwo+BU/fDgVANwM5CXqfCAI5CXoOAE8JCXr+BU7/CQl6Dg05QB -QA3lZbQBEqPgcA7gBPAikJer4P99ARJvSSLkkJfN8KPwkAX44HAPo+BwC6PgcAej4HADfwEi05CX -zuCU6JCXzeCUA0ADfwAifzJ+ABIyFZCXzuAE8HDKkJfN4ATwgMLkkJda8O+QADHw7lQD/6PgVPxP -8KPgVH/wkAAw4CDnDpCXWuDDlGRQBeAE8IDrkJda4MOUZFAKkAAw4BJirH8BIn8AIuVVcDeQl6vg -VA/TlAFQLJACh+BwJpCXtuC0AhCQl7Dg/qPg9YKOg+BgCIAPkAGv4HAJkJes4GADfwEifwAiEiRi -/8OUIFAVkAACEmJ//nRDL/WC5DSV9YPu8IAO77QgCpAAAhJif5CTYfB0Qy/1guQ0lfWD4JAEsvAi -kAQb4FR/ZH9wK5CXqeBkAWAjkJer4FQP05QCUBiQl6/gIOQRkJen4GQBYAmQl6HgcAN/ASJ/ACKQ -ATd0AvCQBSJ0//ASehfvcAaQAch0/fB9An8DEjGd5WZgBX8BEn20EmsbkJeo4FTw8OBEAvAikAAC -EmJ/kJeN8OCQBJvwkJeN4GAE4LT/HKKv5DP1EcKvkABH4FT78H1AfwESMWblEST/kq8ij2eQl7Tg -/30BEnC95WdgEHQhL/WC5DT89YPgRBDwgA50IS/1guQ0/PWD4FTv8JAEH3QB8CKQl2ru8KPv8HUi -AY4j9SR/CxJ03xJ9l+T/En5HkJdq4Pyj4P3s+41E5PVFfQF/YH4BAjBifQJ/AxIxLOVmYCOQl63g -YAZ9AX8MgA+Ql6jgVA/DlARQB30BfwQSb0nk/xJ9tCKQAgng/RIkYv6vBe0ukJey8JAAARJif//t -L5CXs/CQAAISYn//rgXtL5CXtPAikAY04GAmFHAbewF6Bnk1f/l+ARJ6XL8BCZAGNeBUD/CABYAA -An4s5JAGNPAikAABEmJ/kJet8BIkYmVmYBWir+QzkJdm8MKvEnd/kJdm4CT/kq8ikJdO4FTwRAPw -VA9EgPCQl1Pk8KN0APCjdFbwewF6l3lOAnAHkAQb4FR//79/FJCXp+BwDpCXq+BUD9OUBFADfwEi -fwAikAYE4FS/8O9gCuVltAEF5P8Se7+Ql6jgVPDw4EQM8CKQl9Lv8BJyF5CX0uBgBZAFIuTwkJeo -4FTw8OBEBPAikAYE4ERA8OVltAEFfwESe7+Ql6jgVPDw4EQE8CKQl6jgVPDw4EQB8BJ3HRJ33ZCX -qOBU8PDgRALwIn8LEnFy72UlYBDlJbQBBeT1JYADdSUBfwEifwAi72ALkJe34LQBEOT/gAmQl7fg -tAEFfwESTl0ikABJ4JCX1PDgVA/w4P9E8JAASfDvRLDwIuSQl67wkJeg8JCXqfCQl6/wIpCXs+D/ -5P0ScL2QBB90AfAi5SK0AQsSfZe/AQV/ARJ+RyKQCSjv8KPwo/Cj8KPwo/AikAY0dP/w5KPwo/Cj -8CJBl9EAQZeegEGX0wAAkAHK5SXw72ADEn3PIpCXZuvwo+rwo+nwIpCXx+vwo+rwo+nwIpCXyuvw -o+rwo+nwIo+CjoOjo6Pk8CLk9SJ/YH4BAn54kJe34JCXTfAijxyMHY0eIo8fjCCNISISJGL1ZSIi -po4= -==== diff --git a/sys/contrib/ncsw/Peripherals/BM/bman_low.c b/sys/contrib/ncsw/Peripherals/BM/bman_low.c index 740277feb8cd..e3a83c83f2b3 100644 --- a/sys/contrib/ncsw/Peripherals/BM/bman_low.c +++ b/sys/contrib/ncsw/Peripherals/BM/bman_low.c @@ -51,45 +51,45 @@ /***************************/ /* Cache-inhibited register offsets */ -#define REG_RCR_PI_CINH (void *)0x0000 -#define REG_RCR_CI_CINH (void *)0x0004 -#define REG_RCR_ITR (void *)0x0008 -#define REG_CFG (void *)0x0100 -#define REG_SCN(n) ((void *)(0x0200 + ((n) << 2))) -#define REG_ISR (void *)0x0e00 -#define REG_IER (void *)0x0e04 -#define REG_ISDR (void *)0x0e08 -#define REG_IIR (void *)0x0e0c +#define REG_RCR_PI_CINH 0x0000 +#define REG_RCR_CI_CINH 0x0004 +#define REG_RCR_ITR 0x0008 +#define REG_CFG 0x0100 +#define REG_SCN(n) (0x0200 + ((n) << 2)) +#define REG_ISR 0x0e00 +#define REG_IER 0x0e04 +#define REG_ISDR 0x0e08 +#define REG_IIR 0x0e0c /* Cache-enabled register offsets */ -#define CL_CR (void *)0x0000 -#define CL_RR0 (void *)0x0100 -#define CL_RR1 (void *)0x0140 -#define CL_RCR (void *)0x1000 -#define CL_RCR_PI_CENA (void *)0x3000 -#define CL_RCR_CI_CENA (void *)0x3100 +#define CL_CR 0x0000 +#define CL_RR0 0x0100 +#define CL_RR1 0x0140 +#define CL_RCR 0x1000 +#define CL_RCR_PI_CENA 0x3000 +#define CL_RCR_CI_CENA 0x3100 /* The h/w design requires mappings to be size-aligned so that "add"s can be * reduced to "or"s. The primitives below do the same for s/w. */ -static __inline__ void *ptr_ADD(void *a, void *b) +static __inline__ void *ptr_ADD(void *a, uintptr_t b) { - return (void *)((uintptr_t)a + (uintptr_t)b); + return (void *)((uintptr_t)a + b); } /* Bitwise-OR two pointers */ -static __inline__ void *ptr_OR(void *a, void *b) +static __inline__ void *ptr_OR(void *a, uintptr_t b) { - return (void *)((uintptr_t)a | (uintptr_t)b); + return (void *)((uintptr_t)a | b); } /* Cache-inhibited register access */ -static __inline__ uint32_t __bm_in(struct bm_addr *bm, void *offset) +static __inline__ uint32_t __bm_in(struct bm_addr *bm, uintptr_t offset) { uint32_t *tmp = (uint32_t *)ptr_ADD(bm->addr_ci, offset); return GET_UINT32(*tmp); } -static __inline__ void __bm_out(struct bm_addr *bm, void *offset, uint32_t val) +static __inline__ void __bm_out(struct bm_addr *bm, uintptr_t offset, uint32_t val) { uint32_t *tmp = (uint32_t *)ptr_ADD(bm->addr_ci, offset); WRITE_UINT32(*tmp, val); @@ -101,26 +101,26 @@ static __inline__ void __bm_out(struct bm_addr *bm, void *offset, uint32_t val) #define bm_cl(n) (void *)((n) << 6) /* Cache-enabled (index) register access */ -static __inline__ void __bm_cl_touch_ro(struct bm_addr *bm, void *offset) +static __inline__ void __bm_cl_touch_ro(struct bm_addr *bm, uintptr_t offset) { dcbt_ro(ptr_ADD(bm->addr_ce, offset)); } -static __inline__ void __bm_cl_touch_rw(struct bm_addr *bm, void *offset) +static __inline__ void __bm_cl_touch_rw(struct bm_addr *bm, uintptr_t offset) { dcbt_rw(ptr_ADD(bm->addr_ce, offset)); } -static __inline__ uint32_t __bm_cl_in(struct bm_addr *bm, void *offset) +static __inline__ uint32_t __bm_cl_in(struct bm_addr *bm, uintptr_t offset) { uint32_t *tmp = (uint32_t *)ptr_ADD(bm->addr_ce, offset); return GET_UINT32(*tmp); } -static __inline__ void __bm_cl_out(struct bm_addr *bm, void *offset, uint32_t val) +static __inline__ void __bm_cl_out(struct bm_addr *bm, uintptr_t offset, uint32_t val) { uint32_t *tmp = (uint32_t *)ptr_ADD(bm->addr_ce, offset); WRITE_UINT32(*tmp, val); dcbf(tmp); } -static __inline__ void __bm_cl_invalidate(struct bm_addr *bm, void *offset) +static __inline__ void __bm_cl_invalidate(struct bm_addr *bm, uintptr_t offset) { dcbi(ptr_ADD(bm->addr_ce, offset)); } @@ -156,7 +156,7 @@ static __inline__ uint8_t cyc_diff(uint8_t ringsize, uint8_t first, uint8_t last /* Bit-wise logic to convert a ring pointer to a ring index */ static __inline__ uint8_t RCR_PTR2IDX(struct bm_rcr_entry *e) { - return (uint8_t)(((uint32_t)e >> 6) & (BM_RCR_SIZE - 1)); + return (uint8_t)(((uintptr_t)e >> 6) & (BM_RCR_SIZE - 1)); } /* Increment the 'cursor' ring pointer, taking 'vbit' into account */ @@ -483,12 +483,12 @@ void bm_isr_bscn_mask(struct bm_portal *portal, uint8_t bpid, int enable) uint32_t __bm_isr_read(struct bm_portal *portal, enum bm_isr_reg n) { - return __bm_in(&portal->addr, PTR_MOVE(REG_ISR, (n << 2))); + return __bm_in(&portal->addr, REG_ISR + (n << 2)); } void __bm_isr_write(struct bm_portal *portal, enum bm_isr_reg n, uint32_t val) { - __bm_out(&portal->addr, PTR_MOVE(REG_ISR, (n << 2)), val); + __bm_out(&portal->addr, REG_ISR + (n << 2), val); } diff --git a/sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c b/sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c index 021139453130..f1c23ac74671 100644 --- a/sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c +++ b/sys/contrib/ncsw/Peripherals/QM/qm_portal_fqr.c @@ -568,8 +568,8 @@ static uint32_t LoopMessageRing(t_QmPortal *p_QmPortal, uint32_t is) qmPortalMrPvbUpdate(p_QmPortal->p_LowQmPortal); p_Msg = qm_mr_current(p_QmPortal->p_LowQmPortal); if (p_Msg) { - struct qman_fq *p_FqFqs = (void *)p_Msg->fq.contextB; - struct qman_fq *p_FqErn = (void *)p_Msg->ern.tag; + struct qman_fq *p_FqFqs = UINT_TO_PTR(p_Msg->fq.contextB); + struct qman_fq *p_FqErn = UINT_TO_PTR(p_Msg->ern.tag); uint8_t verb =(uint8_t)(p_Msg->verb & QM_MR_VERB_TYPE_MASK); t_QmRejectedFrameInfo rejectedFrameInfo; @@ -646,7 +646,7 @@ static void LoopDequeueRing(t_Handle h_QmPortal) p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal); if (!p_Dq) break; - p_Fq = (void *)p_Dq->contextB; + p_Fq = UINT_TO_PTR(p_Dq->contextB); if (p_Dq->stat & QM_DQRR_STAT_UNSCHEDULED) { /* We only set QMAN_FQ_STATE_NE when retiring, so we only need * to check for clearing it when doing volatile dequeues. It's @@ -728,7 +728,7 @@ static void LoopDequeueRingDcaOptimized(t_Handle h_QmPortal) p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal); if (!p_Dq) break; - p_Fq = (void *)p_Dq->contextB; + p_Fq = UINT_TO_PTR(p_Dq->contextB); if (p_Dq->stat & QM_DQRR_STAT_UNSCHEDULED) { /* We only set QMAN_FQ_STATE_NE when retiring, so we only need * to check for clearing it when doing volatile dequeues. It's @@ -802,7 +802,7 @@ static void LoopDequeueRingOptimized(t_Handle h_QmPortal) p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal); if (!p_Dq) break; - p_Fq = (void *)p_Dq->contextB; + p_Fq = UINT_TO_PTR(p_Dq->contextB); if (p_Dq->stat & QM_DQRR_STAT_UNSCHEDULED) { /* We only set QMAN_FQ_STATE_NE when retiring, so we only need * to check for clearing it when doing volatile dequeues. It's @@ -1483,7 +1483,7 @@ static t_Error QmPortalPullFrame(t_Handle h_QmPortal, uint32_t pdqcr, t_DpaaFD * p_Dq = qm_dqrr_current(p_QmPortal->p_LowQmPortal); if (!p_Dq) continue; - p_Fq = (void *)p_Dq->contextB; + p_Fq = UINT_TO_PTR(p_Dq->contextB); ASSERT_COND(p_Dq->fqid); p_Dst = (uint32_t *)p_Frame; p_Src = (uint32_t *)&p_Dq->fd; @@ -1811,7 +1811,7 @@ t_Error QM_PORTAL_PollFrame(t_Handle h_QmPortal, t_QmPortalFrameInfo *p_frameInf PUNLOCK(p_QmPortal); return ERROR_CODE(E_EMPTY); } - p_Fq = (void *)p_Dq->contextB; + p_Fq = UINT_TO_PTR(p_Dq->contextB); ASSERT_COND(p_Dq->fqid); if (p_Fq) { @@ -2141,7 +2141,7 @@ t_Error QM_FQR_Enqueue(t_Handle h_QmFqr, t_Handle h_QmPortal, uint32_t fqidOffse } p_Eq->fqid = p_Fq->fqid; - p_Eq->tag = (uint32_t)p_Fq; + p_Eq->tag = (uintptr_t)p_Fq; /* gcc does a dreadful job of the following; * eq->fd = *fd; * It causes the entire function to save/restore a wider range of diff --git a/sys/contrib/ncsw/Peripherals/QM/qman_low.h b/sys/contrib/ncsw/Peripherals/QM/qman_low.h index ea0051467dbd..612f4cac8848 100644 --- a/sys/contrib/ncsw/Peripherals/QM/qman_low.h +++ b/sys/contrib/ncsw/Peripherals/QM/qman_low.h @@ -51,61 +51,61 @@ /***************************/ /* Cache-inhibited register offsets */ -#define REG_EQCR_PI_CINH (void *)0x0000 -#define REG_EQCR_CI_CINH (void *)0x0004 -#define REG_EQCR_ITR (void *)0x0008 -#define REG_DQRR_PI_CINH (void *)0x0040 -#define REG_DQRR_CI_CINH (void *)0x0044 -#define REG_DQRR_ITR (void *)0x0048 -#define REG_DQRR_DCAP (void *)0x0050 -#define REG_DQRR_SDQCR (void *)0x0054 -#define REG_DQRR_VDQCR (void *)0x0058 -#define REG_DQRR_PDQCR (void *)0x005c -#define REG_MR_PI_CINH (void *)0x0080 -#define REG_MR_CI_CINH (void *)0x0084 -#define REG_MR_ITR (void *)0x0088 -#define REG_CFG (void *)0x0100 -#define REG_ISR (void *)0x0e00 -#define REG_IER (void *)0x0e04 -#define REG_ISDR (void *)0x0e08 -#define REG_IIR (void *)0x0e0c -#define REG_ITPR (void *)0x0e14 +#define REG_EQCR_PI_CINH 0x0000 +#define REG_EQCR_CI_CINH 0x0004 +#define REG_EQCR_ITR 0x0008 +#define REG_DQRR_PI_CINH 0x0040 +#define REG_DQRR_CI_CINH 0x0044 +#define REG_DQRR_ITR 0x0048 +#define REG_DQRR_DCAP 0x0050 +#define REG_DQRR_SDQCR 0x0054 +#define REG_DQRR_VDQCR 0x0058 +#define REG_DQRR_PDQCR 0x005c +#define REG_MR_PI_CINH 0x0080 +#define REG_MR_CI_CINH 0x0084 +#define REG_MR_ITR 0x0088 +#define REG_CFG 0x0100 +#define REG_ISR 0x0e00 +#define REG_IER 0x0e04 +#define REG_ISDR 0x0e08 +#define REG_IIR 0x0e0c +#define REG_ITPR 0x0e14 /* Cache-enabled register offsets */ -#define CL_EQCR (void *)0x0000 -#define CL_DQRR (void *)0x1000 -#define CL_MR (void *)0x2000 -#define CL_EQCR_PI_CENA (void *)0x3000 -#define CL_EQCR_CI_CENA (void *)0x3100 -#define CL_DQRR_PI_CENA (void *)0x3200 -#define CL_DQRR_CI_CENA (void *)0x3300 -#define CL_MR_PI_CENA (void *)0x3400 -#define CL_MR_CI_CENA (void *)0x3500 -#define CL_RORI_CENA (void *)0x3600 -#define CL_CR (void *)0x3800 -#define CL_RR0 (void *)0x3900 -#define CL_RR1 (void *)0x3940 +#define CL_EQCR 0x0000 +#define CL_DQRR 0x1000 +#define CL_MR 0x2000 +#define CL_EQCR_PI_CENA 0x3000 +#define CL_EQCR_CI_CENA 0x3100 +#define CL_DQRR_PI_CENA 0x3200 +#define CL_DQRR_CI_CENA 0x3300 +#define CL_MR_PI_CENA 0x3400 +#define CL_MR_CI_CENA 0x3500 +#define CL_RORI_CENA 0x3600 +#define CL_CR 0x3800 +#define CL_RR0 0x3900 +#define CL_RR1 0x3940 -static __inline__ void *ptr_ADD(void *a, void *b) +static __inline__ void *ptr_ADD(void *a, uintptr_t b) { - return (void *)((uintptr_t)a + (uintptr_t)b); + return (void *)((uintptr_t)a + b); } /* The h/w design requires mappings to be size-aligned so that "add"s can be * reduced to "or"s. The primitives below do the same for s/w. */ /* Bitwise-OR two pointers */ -static __inline__ void *ptr_OR(void *a, void *b) +static __inline__ void *ptr_OR(void *a, uintptr_t b) { - return (void *)((uintptr_t)a + (uintptr_t)b); + return (void *)((uintptr_t)a + b); } /* Cache-inhibited register access */ -static __inline__ uint32_t __qm_in(struct qm_addr *qm, void *offset) +static __inline__ uint32_t __qm_in(struct qm_addr *qm, uintptr_t offset) { uint32_t *tmp = (uint32_t *)ptr_ADD(qm->addr_ci, offset); return GET_UINT32(*tmp); } -static __inline__ void __qm_out(struct qm_addr *qm, void *offset, uint32_t val) +static __inline__ void __qm_out(struct qm_addr *qm, uintptr_t offset, uint32_t val) { uint32_t *tmp = (uint32_t *)ptr_ADD(qm->addr_ci, offset); WRITE_UINT32(*tmp, val); @@ -114,29 +114,29 @@ static __inline__ void __qm_out(struct qm_addr *qm, void *offset, uint32_t val) #define qm_out(reg, val) __qm_out(&portal->addr, REG_##reg, (uint32_t)val) /* Convert 'n' cachelines to a pointer value for bitwise OR */ -#define qm_cl(n) (void *)((n) << 6) +#define qm_cl(n) ((n) << 6) /* Cache-enabled (index) register access */ -static __inline__ void __qm_cl_touch_ro(struct qm_addr *qm, void *offset) +static __inline__ void __qm_cl_touch_ro(struct qm_addr *qm, uintptr_t offset) { dcbt_ro(ptr_ADD(qm->addr_ce, offset)); } -static __inline__ void __qm_cl_touch_rw(struct qm_addr *qm, void *offset) +static __inline__ void __qm_cl_touch_rw(struct qm_addr *qm, uintptr_t offset) { dcbt_rw(ptr_ADD(qm->addr_ce, offset)); } -static __inline__ uint32_t __qm_cl_in(struct qm_addr *qm, void *offset) +static __inline__ uint32_t __qm_cl_in(struct qm_addr *qm, uintptr_t offset) { uint32_t *tmp = (uint32_t *)ptr_ADD(qm->addr_ce, offset); return GET_UINT32(*tmp); } -static __inline__ void __qm_cl_out(struct qm_addr *qm, void *offset, uint32_t val) +static __inline__ void __qm_cl_out(struct qm_addr *qm, uintptr_t offset, uint32_t val) { uint32_t *tmp = (uint32_t *)ptr_ADD(qm->addr_ce, offset); WRITE_UINT32(*tmp, val); dcbf(tmp); } -static __inline__ void __qm_cl_invalidate(struct qm_addr *qm, void *offset) +static __inline__ void __qm_cl_invalidate(struct qm_addr *qm, uintptr_t offset) { dcbi(ptr_ADD(qm->addr_ce, offset)); } @@ -190,7 +190,7 @@ static __inline__ void __qm_portal_unbind(struct qm_portal *portal, uint8_t ifac /* Bit-wise logic to convert a ring pointer to a ring index */ static __inline__ uint8_t EQCR_PTR2IDX(struct qm_eqcr_entry *e) { - return (uint8_t)(((uint32_t)e >> 6) & (QM_EQCR_SIZE - 1)); + return (uint8_t)(((uintptr_t)e >> 6) & (QM_EQCR_SIZE - 1)); } /* Increment the 'cursor' ring pointer, taking 'vbit' into account */ @@ -459,7 +459,7 @@ static __inline__ uint8_t qm_eqcr_get_fill(struct qm_portal *portal) static __inline__ uint8_t DQRR_PTR2IDX(struct qm_dqrr_entry *e) { - return (uint8_t)(((uint32_t)e >> 6) & (QM_DQRR_SIZE - 1)); + return (uint8_t)(((uintptr_t)e >> 6) & (QM_DQRR_SIZE - 1)); } static __inline__ struct qm_dqrr_entry *DQRR_INC(struct qm_dqrr_entry *e) @@ -829,7 +829,7 @@ static __inline__ uint8_t qm_dqrr_get_maxfill(struct qm_portal *portal) static __inline__ uint8_t MR_PTR2IDX(struct qm_mr_entry *e) { - return (uint8_t)(((uint32_t)e >> 6) & (QM_MR_SIZE - 1)); + return (uint8_t)(((uintptr_t)e >> 6) & (QM_MR_SIZE - 1)); } static __inline__ struct qm_mr_entry *MR_INC(struct qm_mr_entry *e) @@ -1139,10 +1139,10 @@ static __inline__ void qm_isr_set_iperiod(struct qm_portal *portal, uint16_t ipe static __inline__ uint32_t __qm_isr_read(struct qm_portal *portal, enum qm_isr_reg n) { - return __qm_in(&portal->addr, PTR_MOVE(REG_ISR, (n << 2))); + return __qm_in(&portal->addr, REG_ISR + (n << 2)); } static __inline__ void __qm_isr_write(struct qm_portal *portal, enum qm_isr_reg n, uint32_t val) { - __qm_out(&portal->addr, PTR_MOVE(REG_ISR, (n << 2)), val); + __qm_out(&portal->addr, REG_ISR + (n << 2), val); } diff --git a/sys/contrib/ncsw/inc/Peripherals/bm_ext.h b/sys/contrib/ncsw/inc/Peripherals/bm_ext.h index 4585bbacc8a5..140cf58831d3 100644 --- a/sys/contrib/ncsw/inc/Peripherals/bm_ext.h +++ b/sys/contrib/ncsw/inc/Peripherals/bm_ext.h @@ -124,7 +124,7 @@ typedef struct { t_Handle h_App; /**< A handle to an application layer object; This handle will be passed by the driver upon calling the above callbacks. NOTE: this parameter relevant only for BM in master mode ('guestId'=NCSW_MASTER_ID). */ - int errIrq; /**< BM error interrupt line; NO_IRQ if interrupts not used. + uintptr_t errIrq; /**< BM error interrupt line; NO_IRQ if interrupts not used. NOTE: this parameter relevant only for BM in master mode ('guestId'=NCSW_MASTER_ID). */ uint8_t partBpidBase; /**< The first buffer-pool-id dedicated to this partition. diff --git a/sys/contrib/ncsw/inc/Peripherals/fm_ext.h b/sys/contrib/ncsw/inc/Peripherals/fm_ext.h index 9b5db04f392f..a3f56f885bc1 100644 --- a/sys/contrib/ncsw/inc/Peripherals/fm_ext.h +++ b/sys/contrib/ncsw/inc/Peripherals/fm_ext.h @@ -322,9 +322,9 @@ typedef struct t_FmParams { t_Handle h_App; /**< Relevant when guestId = NCSW_MASSTER_ID only. A handle to an application layer object; This handle will be passed by the driver upon calling the above callbacks */ - int irq; /**< Relevant when guestId = NCSW_MASSTER_ID only. + uintptr_t irq; /**< Relevant when guestId = NCSW_MASSTER_ID only. FM interrupt source for normal events */ - int errIrq; /**< Relevant when guestId = NCSW_MASSTER_ID only. + uintptr_t errIrq; /**< Relevant when guestId = NCSW_MASSTER_ID only. FM interrupt source for errors */ t_FmPcdFirmwareParams firmware; /**< Relevant when guestId = NCSW_MASSTER_ID only. Ucode */ diff --git a/sys/contrib/ncsw/inc/Peripherals/qm_ext.h b/sys/contrib/ncsw/inc/Peripherals/qm_ext.h index e5674f4ccda9..98f4b37892d7 100644 --- a/sys/contrib/ncsw/inc/Peripherals/qm_ext.h +++ b/sys/contrib/ncsw/inc/Peripherals/qm_ext.h @@ -249,7 +249,7 @@ typedef struct { t_QmExceptionsCallback *f_Exception; /**< An application callback routine to handle exceptions.*/ t_Handle h_App; /**< A handle to an application layer object; This handle will be passed by the driver upon calling the above callbacks */ - int errIrq; /**< error interrupt line; NO_IRQ if interrupts not used */ + uintptr_t errIrq; /**< error interrupt line; NO_IRQ if interrupts not used */ uint32_t partFqidBase; /**< The first frame-queue-id dedicated to this partition. NOTE: this parameter relevant only when working with multiple partitions. */ uint32_t partNumOfFqids; /**< Number of frame-queue-ids dedicated to this partition. diff --git a/sys/contrib/ncsw/inc/error_ext.h b/sys/contrib/ncsw/inc/error_ext.h index 29a793080a70..3963b843e309 100644 --- a/sys/contrib/ncsw/inc/error_ext.h +++ b/sys/contrib/ncsw/inc/error_ext.h @@ -353,7 +353,8 @@ int ERROR_DYNAMIC_LEVEL = ERROR_GLOBAL_LEVEL; #define PRINT_FORMAT "[CPU%02d, %s:%d %s]" #define PRINT_FMT_PARAMS CORE_GetId(), __FILE__, __LINE__, __FUNCTION__ -#define ERR_STRING(err) #err +#define _ERR_STRING(err) #err +#define ERR_STRING(err) _ERR_STRING(err) #if (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) /* No debug/error/event messages at all */ diff --git a/sys/contrib/ncsw/inc/xx_ext.h b/sys/contrib/ncsw/inc/xx_ext.h index 8eea5e5f97dd..ce8cae310059 100644 --- a/sys/contrib/ncsw/inc/xx_ext.h +++ b/sys/contrib/ncsw/inc/xx_ext.h @@ -197,7 +197,7 @@ char XX_GetChar(void); @Return E_OK on success; error code otherwise.. *//***************************************************************************/ -t_Error XX_PreallocAndBindIntr(int irq, unsigned int cpu); +t_Error XX_PreallocAndBindIntr(uintptr_t irq, unsigned int cpu); /**************************************************************************//** @Function XX_DeallocIntr @@ -208,7 +208,7 @@ t_Error XX_PreallocAndBindIntr(int irq, unsigned int cpu); @Return E_OK on success; error code otherwise.. *//***************************************************************************/ -t_Error XX_DeallocIntr(int irq); +t_Error XX_DeallocIntr(uintptr_t irq); /**************************************************************************//** @Function XX_SetIntr @@ -221,7 +221,7 @@ t_Error XX_DeallocIntr(int irq); @Return E_OK on success; error code otherwise.. *//***************************************************************************/ -t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle); +t_Error XX_SetIntr(uintptr_t irq, t_Isr *f_Isr, t_Handle handle); /**************************************************************************//** @Function XX_FreeIntr @@ -232,7 +232,7 @@ t_Error XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle); @Return E_OK on success; error code otherwise.. *//***************************************************************************/ -t_Error XX_FreeIntr(int irq); +t_Error XX_FreeIntr(uintptr_t irq); /**************************************************************************//** @Function XX_EnableIntr @@ -243,7 +243,7 @@ t_Error XX_FreeIntr(int irq); @Return E_OK on success; error code otherwise.. *//***************************************************************************/ -t_Error XX_EnableIntr(int irq); +t_Error XX_EnableIntr(uintptr_t irq); /**************************************************************************//** @Function XX_DisableIntr @@ -254,7 +254,7 @@ t_Error XX_EnableIntr(int irq); @Return E_OK on success; error code otherwise.. *//***************************************************************************/ -t_Error XX_DisableIntr(int irq); +t_Error XX_DisableIntr(uintptr_t irq); #if !(defined(__MWERKS__) && defined(OPTIMIZED_FOR_SPEED)) /**************************************************************************//** diff --git a/sys/contrib/ncsw/user/env/xx.c b/sys/contrib/ncsw/user/env/xx.c index 87eba48d096a..621c2025e16c 100644 --- a/sys/contrib/ncsw/user/env/xx.c +++ b/sys/contrib/ncsw/user/env/xx.c @@ -368,7 +368,7 @@ XX_Dispatch(void *arg) } t_Error -XX_PreallocAndBindIntr(int irq, unsigned int cpu) +XX_PreallocAndBindIntr(uintptr_t irq, unsigned int cpu) { struct resource *r; unsigned int inum; @@ -388,7 +388,7 @@ XX_PreallocAndBindIntr(int irq, unsigned int cpu) } t_Error -XX_DeallocIntr(int irq) +XX_DeallocIntr(uintptr_t irq) { struct resource *r; unsigned int inum; @@ -404,7 +404,7 @@ XX_DeallocIntr(int irq) } t_Error -XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle) +XX_SetIntr(uintptr_t irq, t_Isr *f_Isr, t_Handle handle) { device_t dev; struct resource *r; @@ -453,7 +453,7 @@ XX_SetIntr(int irq, t_Isr *f_Isr, t_Handle handle) } t_Error -XX_FreeIntr(int irq) +XX_FreeIntr(uintptr_t irq) { device_t dev; struct resource *r; @@ -477,7 +477,7 @@ XX_FreeIntr(int irq) } t_Error -XX_EnableIntr(int irq) +XX_EnableIntr(uintptr_t irq) { struct resource *r; @@ -490,7 +490,7 @@ XX_EnableIntr(int irq) } t_Error -XX_DisableIntr(int irq) +XX_DisableIntr(uintptr_t irq) { struct resource *r; diff --git a/sys/crypto/aesni/aesni.h b/sys/crypto/aesni/aesni.h index b327c01cea66..c3e113d12001 100644 --- a/sys/crypto/aesni/aesni.h +++ b/sys/crypto/aesni/aesni.h @@ -79,23 +79,25 @@ void aesni_set_deckey(const uint8_t *encrypt_schedule /*__aligned(16)*/, */ void aesni_encrypt_cbc(int rounds, const void *key_schedule /*__aligned(16)*/, size_t len, const uint8_t *from, uint8_t *to, - const uint8_t iv[static AES_BLOCK_LEN]); + const uint8_t iv[__min_size(AES_BLOCK_LEN)]); void aesni_decrypt_cbc(int rounds, const void *key_schedule /*__aligned(16)*/, - size_t len, uint8_t *buf, const uint8_t iv[static AES_BLOCK_LEN]); + size_t len, uint8_t *buf, const uint8_t iv[__min_size(AES_BLOCK_LEN)]); void aesni_encrypt_ecb(int rounds, const void *key_schedule /*__aligned(16)*/, size_t len, const uint8_t *from, uint8_t *to); void aesni_decrypt_ecb(int rounds, const void *key_schedule /*__aligned(16)*/, size_t len, const uint8_t *from, uint8_t *to); void aesni_encrypt_icm(int rounds, const void *key_schedule /*__aligned(16)*/, size_t len, const uint8_t *from, uint8_t *to, - const uint8_t iv[static AES_BLOCK_LEN]); + const uint8_t iv[__min_size(AES_BLOCK_LEN)]); void aesni_encrypt_xts(int rounds, const void *data_schedule /*__aligned(16)*/, const void *tweak_schedule /*__aligned(16)*/, size_t len, - const uint8_t *from, uint8_t *to, const uint8_t iv[static AES_BLOCK_LEN]); + const uint8_t *from, uint8_t *to, + const uint8_t iv[__min_size(AES_BLOCK_LEN)]); void aesni_decrypt_xts(int rounds, const void *data_schedule /*__aligned(16)*/, const void *tweak_schedule /*__aligned(16)*/, size_t len, - const uint8_t *from, uint8_t *to, const uint8_t iv[static AES_BLOCK_LEN]); + const uint8_t *from, uint8_t *to, + const uint8_t iv[__min_size(AES_BLOCK_LEN)]); /* GCM & GHASH functions */ void AES_GCM_encrypt(const unsigned char *in, unsigned char *out, diff --git a/sys/crypto/sha1.h b/sys/crypto/sha1.h index d61709e2f6af..c1bc1a3a9021 100644 --- a/sys/crypto/sha1.h +++ b/sys/crypto/sha1.h @@ -61,7 +61,7 @@ typedef struct sha1_ctxt SHA1_CTX; extern void sha1_init(struct sha1_ctxt *); extern void sha1_pad(struct sha1_ctxt *); extern void sha1_loop(struct sha1_ctxt *, const u_int8_t *, size_t); -extern void sha1_result(struct sha1_ctxt *, char[static SHA1_RESULTLEN]); +extern void sha1_result(struct sha1_ctxt *, char[__min_size(SHA1_RESULTLEN)]); /* compatibilty with other SHA1 source codes */ #define SHA1Init(x) sha1_init((x)) diff --git a/sys/crypto/sha2/sha256.h b/sys/crypto/sha2/sha256.h index 17aae7def122..bd31a6210ac6 100644 --- a/sys/crypto/sha2/sha256.h +++ b/sys/crypto/sha2/sha256.h @@ -59,6 +59,12 @@ __BEGIN_DECLS #ifndef SHA256_End #define SHA256_End _libmd_SHA256_End #endif +#ifndef SHA256_Fd +#define SHA256_Fd _libmd_SHA256_Fd +#endif +#ifndef SHA256_FdChunk +#define SHA256_FdChunk _libmd_SHA256_FdChunk +#endif #ifndef SHA256_File #define SHA256_File _libmd_SHA256_File #endif @@ -78,10 +84,13 @@ __BEGIN_DECLS void SHA256_Init(SHA256_CTX *); void SHA256_Update(SHA256_CTX *, const void *, size_t); -void SHA256_Final(unsigned char [static SHA256_DIGEST_LENGTH], SHA256_CTX *); +void SHA256_Final(unsigned char [__min_size(SHA256_DIGEST_LENGTH)], + SHA256_CTX *); #ifndef _KERNEL char *SHA256_End(SHA256_CTX *, char *); char *SHA256_Data(const void *, unsigned int, char *); +char *SHA256_Fd(int, char *); +char *SHA256_FdChunk(int, char *, off_t, off_t); char *SHA256_File(const char *, char *); char *SHA256_FileChunk(const char *, char *, off_t, off_t); #endif diff --git a/sys/crypto/sha2/sha384.h b/sys/crypto/sha2/sha384.h index 63dd948b3a8f..01345592522b 100644 --- a/sys/crypto/sha2/sha384.h +++ b/sys/crypto/sha2/sha384.h @@ -58,6 +58,12 @@ __BEGIN_DECLS #ifndef SHA384_End #define SHA384_End _libmd_SHA384_End #endif +#ifndef SHA384_Fd +#define SHA384_Fd _libmd_SHA384_Fd +#endif +#ifndef SHA384_FdChunk +#define SHA384_FdChunk _libmd_SHA384_FdChunk +#endif #ifndef SHA384_File #define SHA384_File _libmd_SHA384_File #endif @@ -74,10 +80,13 @@ __BEGIN_DECLS void SHA384_Init(SHA384_CTX *); void SHA384_Update(SHA384_CTX *, const void *, size_t); -void SHA384_Final(unsigned char [static SHA384_DIGEST_LENGTH], SHA384_CTX *); +void SHA384_Final(unsigned char [__min_size(SHA384_DIGEST_LENGTH)], + SHA384_CTX *); #ifndef _KERNEL char *SHA384_End(SHA384_CTX *, char *); char *SHA384_Data(const void *, unsigned int, char *); +char *SHA384_Fd(int, char *); +char *SHA384_FdChunk(int, char *, off_t, off_t); char *SHA384_File(const char *, char *); char *SHA384_FileChunk(const char *, char *, off_t, off_t); #endif diff --git a/sys/crypto/sha2/sha512.h b/sys/crypto/sha2/sha512.h index b008aeaed752..8b3e17cc00f6 100644 --- a/sys/crypto/sha2/sha512.h +++ b/sys/crypto/sha2/sha512.h @@ -58,6 +58,12 @@ __BEGIN_DECLS #ifndef SHA512_End #define SHA512_End _libmd_SHA512_End #endif +#ifndef SHA512_Fd +#define SHA512_Fd _libmd_SHA512_Fd +#endif +#ifndef SHA512_FdChunk +#define SHA512_FdChunk _libmd_SHA512_FdChunk +#endif #ifndef SHA512_File #define SHA512_File _libmd_SHA512_File #endif @@ -77,10 +83,13 @@ __BEGIN_DECLS void SHA512_Init(SHA512_CTX *); void SHA512_Update(SHA512_CTX *, const void *, size_t); -void SHA512_Final(unsigned char [static SHA512_DIGEST_LENGTH], SHA512_CTX *); +void SHA512_Final(unsigned char [__min_size(SHA512_DIGEST_LENGTH)], + SHA512_CTX *); #ifndef _KERNEL char *SHA512_End(SHA512_CTX *, char *); char *SHA512_Data(const void *, unsigned int, char *); +char *SHA512_Fd(int, char *); +char *SHA512_FdChunk(int, char *, off_t, off_t); char *SHA512_File(const char *, char *); char *SHA512_FileChunk(const char *, char *, off_t, off_t); #endif diff --git a/sys/crypto/sha2/sha512t.h b/sys/crypto/sha2/sha512t.h index 3f0c921f9208..1ae490f5a3ed 100644 --- a/sys/crypto/sha2/sha512t.h +++ b/sys/crypto/sha2/sha512t.h @@ -55,6 +55,12 @@ __BEGIN_DECLS #ifndef SHA512_224_End #define SHA512_224_End _libmd_SHA512_224_End #endif +#ifndef SHA512_224_Fd +#define SHA512_224_Fd _libmd_SHA512_224_Fd +#endif +#ifndef SHA512_224_FdChunk +#define SHA512_224_FdChunk _libmd_SHA512_224_FdChunk +#endif #ifndef SHA512_224_File #define SHA512_224_File _libmd_SHA512_224_File #endif @@ -84,6 +90,12 @@ __BEGIN_DECLS #ifndef SHA512_256_End #define SHA512_256_End _libmd_SHA512_256_End #endif +#ifndef SHA512_256_Fd +#define SHA512_256_Fd _libmd_SHA512_256_Fd +#endif +#ifndef SHA512_256_FdChunk +#define SHA512_256_FdChunk _libmd_SHA512_256_FdChunk +#endif #ifndef SHA512_256_File #define SHA512_256_File _libmd_SHA512_256_File #endif @@ -103,19 +115,25 @@ __BEGIN_DECLS void SHA512_224_Init(SHA512_CTX *); void SHA512_224_Update(SHA512_CTX *, const void *, size_t); -void SHA512_224_Final(unsigned char [static SHA512_224_DIGEST_LENGTH], SHA512_CTX *); +void SHA512_224_Final(unsigned char [__min_size(SHA512_224_DIGEST_LENGTH)], + SHA512_CTX *); #ifndef _KERNEL char *SHA512_224_End(SHA512_CTX *, char *); char *SHA512_224_Data(const void *, unsigned int, char *); +char *SHA512_224_Fd(int, char *); +char *SHA512_224_FdChunk(int, char *, off_t, off_t); char *SHA512_224_File(const char *, char *); char *SHA512_224_FileChunk(const char *, char *, off_t, off_t); #endif void SHA512_256_Init(SHA512_CTX *); void SHA512_256_Update(SHA512_CTX *, const void *, size_t); -void SHA512_256_Final(unsigned char [static SHA512_256_DIGEST_LENGTH], SHA512_CTX *); +void SHA512_256_Final(unsigned char [__min_size(SHA512_256_DIGEST_LENGTH)], + SHA512_CTX *); #ifndef _KERNEL char *SHA512_256_End(SHA512_CTX *, char *); char *SHA512_256_Data(const void *, unsigned int, char *); +char *SHA512_256_Fd(int, char *); +char *SHA512_256_FdChunk(int, char *, off_t, off_t); char *SHA512_256_File(const char *, char *); char *SHA512_256_FileChunk(const char *, char *, off_t, off_t); #endif diff --git a/sys/crypto/siphash/siphash.h b/sys/crypto/siphash/siphash.h index 8bbda4f3e920..235818b5da48 100644 --- a/sys/crypto/siphash/siphash.h +++ b/sys/crypto/siphash/siphash.h @@ -68,15 +68,16 @@ typedef struct _SIPHASH_CTX { #define SipHash24_Init(x) SipHash_InitX((x), 2, 4) #define SipHash48_Init(x) SipHash_InitX((x), 4, 8) void SipHash_InitX(SIPHASH_CTX *, int, int); -void SipHash_SetKey(SIPHASH_CTX *, const uint8_t[static SIPHASH_KEY_LENGTH]); +void SipHash_SetKey(SIPHASH_CTX *, + const uint8_t[__min_size(SIPHASH_KEY_LENGTH)]); void SipHash_Update(SIPHASH_CTX *, const void *, size_t); -void SipHash_Final(uint8_t[static SIPHASH_DIGEST_LENGTH], SIPHASH_CTX *); +void SipHash_Final(uint8_t[__min_size(SIPHASH_DIGEST_LENGTH)], SIPHASH_CTX *); uint64_t SipHash_End(SIPHASH_CTX *); #define SipHash24(x, y, z, i) SipHashX((x), 2, 4, (y), (z), (i)); #define SipHash48(x, y, z, i) SipHashX((x), 4, 8, (y), (z), (i)); -uint64_t SipHashX(SIPHASH_CTX *, int, int, const uint8_t[static SIPHASH_KEY_LENGTH], const void *, - size_t); +uint64_t SipHashX(SIPHASH_CTX *, int, int, + const uint8_t[__min_size(SIPHASH_KEY_LENGTH)], const void *, size_t); int SipHash24_TestVectors(void); diff --git a/sys/crypto/skein/skein_freebsd.h b/sys/crypto/skein/skein_freebsd.h index 935fa0903f7e..676b79bc6994 100644 --- a/sys/crypto/skein/skein_freebsd.h +++ b/sys/crypto/skein/skein_freebsd.h @@ -57,9 +57,12 @@ void SKEIN256_Update(SKEIN256_CTX *ctx, const void *in, size_t len); void SKEIN512_Update(SKEIN512_CTX *ctx, const void *in, size_t len); void SKEIN1024_Update(SKEIN1024_CTX *ctx, const void *in, size_t len); -void SKEIN256_Final(unsigned char digest[static SKEIN256_DIGEST_LENGTH], SKEIN256_CTX *ctx); -void SKEIN512_Final(unsigned char digest[static SKEIN512_DIGEST_LENGTH], SKEIN512_CTX *ctx); -void SKEIN1024_Final(unsigned char digest[static SKEIN1024_DIGEST_LENGTH], SKEIN1024_CTX *ctx); +void SKEIN256_Final(unsigned char digest[__min_size(SKEIN256_DIGEST_LENGTH)], + SKEIN256_CTX *ctx); +void SKEIN512_Final(unsigned char digest[__min_size(SKEIN512_DIGEST_LENGTH)], + SKEIN512_CTX *ctx); +void SKEIN1024_Final(unsigned char digest[__min_size(SKEIN1024_DIGEST_LENGTH)], + SKEIN1024_CTX *ctx); #ifndef _KERNEL char *SKEIN256_End(SKEIN256_CTX *, char *); @@ -68,6 +71,12 @@ char *SKEIN1024_End(SKEIN1024_CTX *, char *); char *SKEIN256_Data(const void *, unsigned int, char *); char *SKEIN512_Data(const void *, unsigned int, char *); char *SKEIN1024_Data(const void *, unsigned int, char *); +char *SKEIN256_Fd(int, char *); +char *SKEIN512_Fd(int, char *); +char *SKEIN1024_Fd(int, char *); +char *SKEIN256_FdChunk(int, char *, off_t, off_t); +char *SKEIN512_FdChunk(int, char *, off_t, off_t); +char *SKEIN1024_FdChunk(int, char *, off_t, off_t); char *SKEIN256_File(const char *, char *); char *SKEIN512_File(const char *, char *); char *SKEIN1024_File(const char *, char *); diff --git a/sys/crypto/skein/skein_port.h b/sys/crypto/skein/skein_port.h index 7025a51673ff..ab320b29d335 100644 --- a/sys/crypto/skein/skein_port.h +++ b/sys/crypto/skein/skein_port.h @@ -137,6 +137,16 @@ void Skein_Get64_LSB_First(u64b_t *dst,const u08b_t *src,size_t wCnt) #define SKEIN512_End _libmd_SKEIN512_End #define SKEIN1024_End _libmd_SKEIN1024_End #endif +#ifndef SKEIN256_Fd +#define SKEIN256_Fd _libmd_SKEIN256_Fd +#define SKEIN512_Fd _libmd_SKEIN512_Fd +#define SKEIN1024_Fd _libmd_SKEIN1024_Fd +#endif +#ifndef SKEIN256_FdChunk +#define SKEIN256_FdChunk _libmd_SKEIN256_FdChunk +#define SKEIN512_FdChunk _libmd_SKEIN512_FdChunk +#define SKEIN1024_FdChunk _libmd_SKEIN1024_FdChunk +#endif #ifndef SKEIN256_File #define SKEIN256_File _libmd_SKEIN256_File #define SKEIN512_File _libmd_SKEIN512_File diff --git a/sys/dev/al_eth/al_eth.c b/sys/dev/al_eth/al_eth.c new file mode 100644 index 000000000000..6a58fb5c5319 --- /dev/null +++ b/sys/dev/al_eth/al_eth.c @@ -0,0 +1,3584 @@ +/*- + * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates + * All rights reserved. + * + * Developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "opt_inet.h" +#include "opt_inet6.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef INET +#include +#include +#include +#include +#endif + +#ifdef INET6 +#include +#endif + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "al_eth.h" +#include "al_init_eth_lm.h" +#include "arm/annapurna/alpine/alpine_serdes.h" + +#include "miibus_if.h" + +#define device_printf_dbg(fmt, ...) do { \ + if (AL_DBG_LEVEL >= AL_DBG_LEVEL_DBG) { AL_DBG_LOCK(); \ + device_printf(fmt, __VA_ARGS__); AL_DBG_UNLOCK();} \ + } while (0) + +MALLOC_DEFINE(M_IFAL, "if_al_malloc", "All allocated data for AL ETH driver"); + +/* move out to some pci header file */ +#define PCI_VENDOR_ID_ANNAPURNA_LABS 0x1c36 +#define PCI_DEVICE_ID_AL_ETH 0x0001 +#define PCI_DEVICE_ID_AL_ETH_ADVANCED 0x0002 +#define PCI_DEVICE_ID_AL_ETH_NIC 0x0003 +#define PCI_DEVICE_ID_AL_ETH_FPGA_NIC 0x0030 +#define PCI_DEVICE_ID_AL_CRYPTO 0x0011 +#define PCI_DEVICE_ID_AL_CRYPTO_VF 0x8011 +#define PCI_DEVICE_ID_AL_RAID_DMA 0x0021 +#define PCI_DEVICE_ID_AL_RAID_DMA_VF 0x8021 +#define PCI_DEVICE_ID_AL_USB 0x0041 + +#define MAC_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_ADDR(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] + +#define AL_ETH_MAC_TABLE_UNICAST_IDX_BASE 0 +#define AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT 4 +#define AL_ETH_MAC_TABLE_ALL_MULTICAST_IDX (AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + \ + AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT) + +#define AL_ETH_MAC_TABLE_DROP_IDX (AL_ETH_FWD_MAC_NUM - 1) +#define AL_ETH_MAC_TABLE_BROADCAST_IDX (AL_ETH_MAC_TABLE_DROP_IDX - 1) + +#define AL_ETH_THASH_UDMA_SHIFT 0 +#define AL_ETH_THASH_UDMA_MASK (0xF << AL_ETH_THASH_UDMA_SHIFT) + +#define AL_ETH_THASH_Q_SHIFT 4 +#define AL_ETH_THASH_Q_MASK (0x3 << AL_ETH_THASH_Q_SHIFT) + +/* the following defines should be moved to hal */ +#define AL_ETH_FSM_ENTRY_IPV4_TCP 0 +#define AL_ETH_FSM_ENTRY_IPV4_UDP 1 +#define AL_ETH_FSM_ENTRY_IPV6_TCP 2 +#define AL_ETH_FSM_ENTRY_IPV6_UDP 3 +#define AL_ETH_FSM_ENTRY_IPV6_NO_UDP_TCP 4 +#define AL_ETH_FSM_ENTRY_IPV4_NO_UDP_TCP 5 + +/* FSM DATA format */ +#define AL_ETH_FSM_DATA_OUTER_2_TUPLE 0 +#define AL_ETH_FSM_DATA_OUTER_4_TUPLE 1 +#define AL_ETH_FSM_DATA_INNER_2_TUPLE 2 +#define AL_ETH_FSM_DATA_INNER_4_TUPLE 3 + +#define AL_ETH_FSM_DATA_HASH_SEL (1 << 2) + +#define AL_ETH_FSM_DATA_DEFAULT_Q 0 +#define AL_ETH_FSM_DATA_DEFAULT_UDMA 0 + +#define AL_BR_SIZE 512 +#define AL_TSO_SIZE 65500 +#define AL_DEFAULT_MTU 1500 + +#define CSUM_OFFLOAD (CSUM_IP|CSUM_TCP|CSUM_UDP|CSUM_SCTP) + +#define AL_IP_ALIGNMENT_OFFSET 2 + +#define SFP_I2C_ADDR 0x50 + +#define AL_MASK_GROUP_A_INT 0x7 +#define AL_MASK_GROUP_B_INT 0xF +#define AL_MASK_GROUP_C_INT 0xF +#define AL_MASK_GROUP_D_INT 0xFFFFFFFF + +#define AL_REG_OFFSET_FORWARD_INTR (0x1800000 + 0x1210) +#define AL_EN_FORWARD_INTR 0x1FFFF +#define AL_DIS_FORWARD_INTR 0 + +#define AL_M2S_MASK_INIT 0x480 +#define AL_S2M_MASK_INIT 0x1E0 +#define AL_M2S_S2M_MASK_NOT_INT (0x3f << 25) + +#define AL_10BASE_T_SPEED 10 +#define AL_100BASE_TX_SPEED 100 +#define AL_1000BASE_T_SPEED 1000 + +static devclass_t al_devclass; + +#define AL_RX_LOCK_INIT(_sc) mtx_init(&((_sc)->if_rx_lock), "ALRXL", "ALRXL", MTX_DEF) +#define AL_RX_LOCK(_sc) mtx_lock(&((_sc)->if_rx_lock)) +#define AL_RX_UNLOCK(_sc) mtx_unlock(&((_sc)->if_rx_lock)) + +/* helper functions */ +static int al_is_device_supported(device_t); + +static void al_eth_init_rings(struct al_eth_adapter *); +static void al_eth_flow_ctrl_disable(struct al_eth_adapter *); +int al_eth_fpga_read_pci_config(void *, int, uint32_t *); +int al_eth_fpga_write_pci_config(void *, int, uint32_t); +int al_eth_read_pci_config(void *, int, uint32_t *); +int al_eth_write_pci_config(void *, int, uint32_t); +void al_eth_irq_config(uint32_t *, uint32_t); +void al_eth_forward_int_config(uint32_t *, uint32_t); +static void al_eth_start_xmit(void *, int); +static void al_eth_rx_recv_work(void *, int); +static int al_eth_up(struct al_eth_adapter *); +static void al_eth_down(struct al_eth_adapter *); +static void al_eth_interrupts_unmask(struct al_eth_adapter *); +static void al_eth_interrupts_mask(struct al_eth_adapter *); +static int al_eth_check_mtu(struct al_eth_adapter *, int); +static uint64_t al_get_counter(struct ifnet *, ift_counter); +static void al_eth_req_rx_buff_size(struct al_eth_adapter *, int); +static int al_eth_board_params_init(struct al_eth_adapter *); +static int al_media_update(struct ifnet *); +static void al_media_status(struct ifnet *, struct ifmediareq *); +static int al_eth_function_reset(struct al_eth_adapter *); +static int al_eth_hw_init_adapter(struct al_eth_adapter *); +static void al_eth_serdes_init(struct al_eth_adapter *); +static void al_eth_lm_config(struct al_eth_adapter *); +static int al_eth_hw_init(struct al_eth_adapter *); + +static void al_tick_stats(void *); + +/* ifnet entry points */ +static void al_init(void *); +static int al_mq_start(struct ifnet *, struct mbuf *); +static void al_qflush(struct ifnet *); +static int al_ioctl(struct ifnet * ifp, u_long, caddr_t); + +/* bus entry points */ +static int al_probe(device_t); +static int al_attach(device_t); +static int al_detach(device_t); +static int al_shutdown(device_t); + +/* mii bus support routines */ +static int al_miibus_readreg(device_t, int, int); +static int al_miibus_writereg(device_t, int, int, int); +static void al_miibus_statchg(device_t); +static void al_miibus_linkchg(device_t); + +struct al_eth_adapter* g_adapters[16]; +uint32_t g_adapters_count; + +/* flag for napi-like mbuf processing, controlled from sysctl */ +static int napi = 0; + +static device_method_t al_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, al_probe), + DEVMETHOD(device_attach, al_attach), + DEVMETHOD(device_detach, al_detach), + DEVMETHOD(device_shutdown, al_shutdown), + + DEVMETHOD(miibus_readreg, al_miibus_readreg), + DEVMETHOD(miibus_writereg, al_miibus_writereg), + DEVMETHOD(miibus_statchg, al_miibus_statchg), + DEVMETHOD(miibus_linkchg, al_miibus_linkchg), + { 0, 0 } +}; + +static driver_t al_driver = { + "al", + al_methods, + sizeof(struct al_eth_adapter), +}; + +DRIVER_MODULE(al, pci, al_driver, al_devclass, 0, 0); +DRIVER_MODULE(miibus, al, miibus_driver, miibus_devclass, 0, 0); + +static int +al_probe(device_t dev) +{ + if ((al_is_device_supported(dev)) != 0) { + device_set_desc(dev, "al"); + return (BUS_PROBE_DEFAULT); + } + return (ENXIO); +} + +static int +al_attach(device_t dev) +{ + struct al_eth_lm_context *lm_context; + struct al_eth_adapter *adapter; + struct sysctl_oid_list *child; + struct sysctl_ctx_list *ctx; + struct sysctl_oid *tree; + struct ifnet *ifp; + uint32_t dev_id; + uint32_t rev_id; + int bar_udma; + int bar_mac; + int bar_ec; + int err; + + err = 0; + ifp = NULL; + dev_id = rev_id = 0; + ctx = device_get_sysctl_ctx(dev); + tree = SYSCTL_PARENT(device_get_sysctl_tree(dev)); + child = SYSCTL_CHILDREN(tree); + + if (g_adapters_count == 0) { + SYSCTL_ADD_INT(ctx, child, OID_AUTO, "napi", + CTLFLAG_RW, &napi, 0, "Use pseudo-napi mechanism"); + } + adapter = device_get_softc(dev); + adapter->dev = dev; + adapter->board_type = ALPINE_INTEGRATED; + snprintf(adapter->name, AL_ETH_NAME_MAX_LEN, "%s", + device_get_nameunit(dev)); + AL_RX_LOCK_INIT(adapter); + + g_adapters[g_adapters_count] = adapter; + + lm_context = &adapter->lm_context; + + bar_udma = PCIR_BAR(AL_ETH_UDMA_BAR); + adapter->udma_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &bar_udma, RF_ACTIVE); + if (adapter->udma_res == NULL) { + device_printf(adapter->dev, + "could not allocate memory resources for DMA.\n"); + err = ENOMEM; + goto err_res_dma; + } + adapter->udma_base = al_bus_dma_to_va(rman_get_bustag(adapter->udma_res), + rman_get_bushandle(adapter->udma_res)); + bar_mac = PCIR_BAR(AL_ETH_MAC_BAR); + adapter->mac_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &bar_mac, RF_ACTIVE); + if (adapter->mac_res == NULL) { + device_printf(adapter->dev, + "could not allocate memory resources for MAC.\n"); + err = ENOMEM; + goto err_res_mac; + } + adapter->mac_base = al_bus_dma_to_va(rman_get_bustag(adapter->mac_res), + rman_get_bushandle(adapter->mac_res)); + + bar_ec = PCIR_BAR(AL_ETH_EC_BAR); + adapter->ec_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &bar_ec, + RF_ACTIVE); + if (adapter->ec_res == NULL) { + device_printf(adapter->dev, + "could not allocate memory resources for EC.\n"); + err = ENOMEM; + goto err_res_ec; + } + adapter->ec_base = al_bus_dma_to_va(rman_get_bustag(adapter->ec_res), + rman_get_bushandle(adapter->ec_res)); + + adapter->netdev = ifp = if_alloc(IFT_ETHER); + + adapter->netdev->if_link_state = LINK_STATE_DOWN; + + ifp->if_softc = adapter; + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + ifp->if_flags = ifp->if_drv_flags; + ifp->if_flags |= IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI; + ifp->if_transmit = al_mq_start; + ifp->if_qflush = al_qflush; + ifp->if_ioctl = al_ioctl; + ifp->if_init = al_init; + ifp->if_get_counter = al_get_counter; + ifp->if_mtu = AL_DEFAULT_MTU; + + adapter->if_flags = ifp->if_flags; + + ifp->if_capabilities = ifp->if_capenable = 0; + + ifp->if_capabilities |= IFCAP_HWCSUM | + IFCAP_HWCSUM_IPV6 | IFCAP_TSO | + IFCAP_LRO | IFCAP_JUMBO_MTU; + + ifp->if_capenable = ifp->if_capabilities; + + adapter->id_number = g_adapters_count; + + if (adapter->board_type == ALPINE_INTEGRATED) { + dev_id = pci_get_device(adapter->dev); + rev_id = pci_get_revid(adapter->dev); + } else { + al_eth_fpga_read_pci_config(adapter->internal_pcie_base, + PCIR_DEVICE, &dev_id); + al_eth_fpga_read_pci_config(adapter->internal_pcie_base, + PCIR_REVID, &rev_id); + } + + adapter->dev_id = dev_id; + adapter->rev_id = rev_id; + + /* set default ring sizes */ + adapter->tx_ring_count = AL_ETH_DEFAULT_TX_SW_DESCS; + adapter->tx_descs_count = AL_ETH_DEFAULT_TX_HW_DESCS; + adapter->rx_ring_count = AL_ETH_DEFAULT_RX_DESCS; + adapter->rx_descs_count = AL_ETH_DEFAULT_RX_DESCS; + + adapter->num_tx_queues = AL_ETH_NUM_QUEUES; + adapter->num_rx_queues = AL_ETH_NUM_QUEUES; + + adapter->small_copy_len = AL_ETH_DEFAULT_SMALL_PACKET_LEN; + adapter->link_poll_interval = AL_ETH_DEFAULT_LINK_POLL_INTERVAL; + adapter->max_rx_buff_alloc_size = AL_ETH_DEFAULT_MAX_RX_BUFF_ALLOC_SIZE; + + al_eth_req_rx_buff_size(adapter, adapter->netdev->if_mtu); + + adapter->link_config.force_1000_base_x = AL_ETH_DEFAULT_FORCE_1000_BASEX; + + err = al_eth_board_params_init(adapter); + if (err != 0) + goto err; + + if (adapter->mac_mode == AL_ETH_MAC_MODE_10GbE_Serial) { + ifmedia_init(&adapter->media, IFM_IMASK, + al_media_update, al_media_status); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_1000_LX, 0, NULL); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_10G_LR, 0, NULL); + ifmedia_add(&adapter->media, IFM_ETHER | IFM_AUTO, 0, NULL); + ifmedia_set(&adapter->media, IFM_ETHER | IFM_AUTO); + } + + al_eth_function_reset(adapter); + + err = al_eth_hw_init_adapter(adapter); + if (err != 0) + goto err; + + al_eth_init_rings(adapter); + g_adapters_count++; + + al_eth_lm_config(adapter); + mtx_init(&adapter->stats_mtx, "AlStatsMtx", NULL, MTX_DEF); + mtx_init(&adapter->wd_mtx, "AlWdMtx", NULL, MTX_DEF); + callout_init_mtx(&adapter->stats_callout, &adapter->stats_mtx, 0); + callout_init_mtx(&adapter->wd_callout, &adapter->wd_mtx, 0); + + ether_ifattach(ifp, adapter->mac_addr); + ifp->if_mtu = AL_DEFAULT_MTU; + + if (adapter->mac_mode == AL_ETH_MAC_MODE_RGMII) { + al_eth_hw_init(adapter); + + /* Attach PHY(s) */ + err = mii_attach(adapter->dev, &adapter->miibus, adapter->netdev, + al_media_update, al_media_status, BMSR_DEFCAPMASK, 0, + MII_OFFSET_ANY, 0); + if (err != 0) { + device_printf(adapter->dev, "attaching PHYs failed\n"); + return (err); + } + + adapter->mii = device_get_softc(adapter->miibus); + } + + return (err); + +err: + bus_release_resource(dev, SYS_RES_MEMORY, bar_ec, adapter->ec_res); +err_res_ec: + bus_release_resource(dev, SYS_RES_MEMORY, bar_mac, adapter->mac_res); +err_res_mac: + bus_release_resource(dev, SYS_RES_MEMORY, bar_udma, adapter->udma_res); +err_res_dma: + return (err); +} + +static int +al_detach(device_t dev) +{ + struct al_eth_adapter *adapter; + + adapter = device_get_softc(dev); + ether_ifdetach(adapter->netdev); + + mtx_destroy(&adapter->stats_mtx); + mtx_destroy(&adapter->wd_mtx); + + al_eth_down(adapter); + + bus_release_resource(dev, SYS_RES_IRQ, 0, adapter->irq_res); + bus_release_resource(dev, SYS_RES_MEMORY, 0, adapter->ec_res); + bus_release_resource(dev, SYS_RES_MEMORY, 0, adapter->mac_res); + bus_release_resource(dev, SYS_RES_MEMORY, 0, adapter->udma_res); + + return (0); +} + +int +al_eth_fpga_read_pci_config(void *handle, int where, uint32_t *val) +{ + + /* handle is the base address of the adapter */ + *val = al_reg_read32((void*)((u_long)handle + where)); + + return (0); +} + +int +al_eth_fpga_write_pci_config(void *handle, int where, uint32_t val) +{ + + /* handle is the base address of the adapter */ + al_reg_write32((void*)((u_long)handle + where), val); + return (0); +} + +int +al_eth_read_pci_config(void *handle, int where, uint32_t *val) +{ + + /* handle is a pci_dev */ + *val = pci_read_config((device_t)handle, where, sizeof(*val)); + return (0); +} + +int +al_eth_write_pci_config(void *handle, int where, uint32_t val) +{ + + /* handle is a pci_dev */ + pci_write_config((device_t)handle, where, val, sizeof(val)); + return (0); +} + +void +al_eth_irq_config(uint32_t *offset, uint32_t value) +{ + + al_reg_write32_relaxed(offset, value); +} + +void +al_eth_forward_int_config(uint32_t *offset, uint32_t value) +{ + + al_reg_write32(offset, value); +} + +static void +al_eth_serdes_init(struct al_eth_adapter *adapter) +{ + void __iomem *serdes_base; + + adapter->serdes_init = false; + + serdes_base = alpine_serdes_resource_get(adapter->serdes_grp); + if (serdes_base == NULL) { + device_printf(adapter->dev, "serdes_base get failed!\n"); + return; + } + + serdes_base = al_bus_dma_to_va(serdes_tag, serdes_base); + + al_serdes_handle_grp_init(serdes_base, adapter->serdes_grp, + &adapter->serdes_obj); + + adapter->serdes_init = true; +} + +static void +al_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + bus_addr_t *paddr; + + paddr = arg; + *paddr = segs->ds_addr; +} + +static int +al_dma_alloc_coherent(struct device *dev, bus_dma_tag_t *tag, bus_dmamap_t *map, + bus_addr_t *baddr, void **vaddr, uint32_t size) +{ + int ret; + uint32_t maxsize = ((size - 1)/PAGE_SIZE + 1) * PAGE_SIZE; + + ret = bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0, + BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, + maxsize, 1, maxsize, BUS_DMA_COHERENT, NULL, NULL, tag); + if (ret != 0) { + device_printf(dev, + "failed to create bus tag, ret = %d\n", ret); + return (ret); + } + + ret = bus_dmamem_alloc(*tag, vaddr, + BUS_DMA_COHERENT | BUS_DMA_ZERO, map); + if (ret != 0) { + device_printf(dev, + "failed to allocate dmamem, ret = %d\n", ret); + return (ret); + } + + ret = bus_dmamap_load(*tag, *map, *vaddr, + size, al_dma_map_addr, baddr, 0); + if (ret != 0) { + device_printf(dev, + "failed to allocate bus_dmamap_load, ret = %d\n", ret); + return (ret); + } + + return (0); +} + +static void +al_dma_free_coherent(bus_dma_tag_t tag, bus_dmamap_t map, void *vaddr) +{ + + bus_dmamap_unload(tag, map); + bus_dmamem_free(tag, vaddr, map); + bus_dma_tag_destroy(tag); +} + +static void +al_eth_mac_table_unicast_add(struct al_eth_adapter *adapter, + uint8_t idx, uint8_t *addr, uint8_t udma_mask) +{ + struct al_eth_fwd_mac_table_entry entry = { { 0 } }; + + memcpy(entry.addr, adapter->mac_addr, sizeof(adapter->mac_addr)); + + memset(entry.mask, 0xff, sizeof(entry.mask)); + entry.rx_valid = true; + entry.tx_valid = false; + entry.udma_mask = udma_mask; + entry.filter = false; + + device_printf_dbg(adapter->dev, + "%s: [%d]: addr "MAC_ADDR_STR" mask "MAC_ADDR_STR"\n", + __func__, idx, MAC_ADDR(entry.addr), MAC_ADDR(entry.mask)); + + al_eth_fwd_mac_table_set(&adapter->hal_adapter, idx, &entry); +} + +static void +al_eth_mac_table_all_multicast_add(struct al_eth_adapter *adapter, uint8_t idx, + uint8_t udma_mask) +{ + struct al_eth_fwd_mac_table_entry entry = { { 0 } }; + + memset(entry.addr, 0x00, sizeof(entry.addr)); + memset(entry.mask, 0x00, sizeof(entry.mask)); + entry.mask[0] |= 1; + entry.addr[0] |= 1; + + entry.rx_valid = true; + entry.tx_valid = false; + entry.udma_mask = udma_mask; + entry.filter = false; + + device_printf_dbg(adapter->dev, + "%s: [%d]: addr "MAC_ADDR_STR" mask "MAC_ADDR_STR"\n", + __func__, idx, MAC_ADDR(entry.addr), MAC_ADDR(entry.mask)); + + al_eth_fwd_mac_table_set(&adapter->hal_adapter, idx, &entry); +} + +static void +al_eth_mac_table_broadcast_add(struct al_eth_adapter *adapter, + uint8_t idx, uint8_t udma_mask) +{ + struct al_eth_fwd_mac_table_entry entry = { { 0 } }; + + memset(entry.addr, 0xff, sizeof(entry.addr)); + memset(entry.mask, 0xff, sizeof(entry.mask)); + + entry.rx_valid = true; + entry.tx_valid = false; + entry.udma_mask = udma_mask; + entry.filter = false; + + device_printf_dbg(adapter->dev, + "%s: [%d]: addr "MAC_ADDR_STR" mask "MAC_ADDR_STR"\n", + __func__, idx, MAC_ADDR(entry.addr), MAC_ADDR(entry.mask)); + + al_eth_fwd_mac_table_set(&adapter->hal_adapter, idx, &entry); +} + +static void +al_eth_mac_table_promiscuous_set(struct al_eth_adapter *adapter, + boolean_t promiscuous) +{ + struct al_eth_fwd_mac_table_entry entry = { { 0 } }; + + memset(entry.addr, 0x00, sizeof(entry.addr)); + memset(entry.mask, 0x00, sizeof(entry.mask)); + + entry.rx_valid = true; + entry.tx_valid = false; + entry.udma_mask = (promiscuous) ? 1 : 0; + entry.filter = (promiscuous) ? false : true; + + device_printf_dbg(adapter->dev, "%s: %s promiscuous mode\n", + __func__, (promiscuous) ? "enter" : "exit"); + + al_eth_fwd_mac_table_set(&adapter->hal_adapter, + AL_ETH_MAC_TABLE_DROP_IDX, &entry); +} + +static void +al_eth_set_thash_table_entry(struct al_eth_adapter *adapter, uint8_t idx, + uint8_t udma, uint32_t queue) +{ + + if (udma != 0) + panic("only UDMA0 is supporter"); + + if (queue >= AL_ETH_NUM_QUEUES) + panic("invalid queue number"); + + al_eth_thash_table_set(&adapter->hal_adapter, idx, udma, queue); +} + +/* init FSM, no tunneling supported yet, if packet is tcp/udp over ipv4/ipv6, use 4 tuple hash */ +static void +al_eth_fsm_table_init(struct al_eth_adapter *adapter) +{ + uint32_t val; + int i; + + for (i = 0; i < AL_ETH_RX_FSM_TABLE_SIZE; i++) { + uint8_t outer_type = AL_ETH_FSM_ENTRY_OUTER(i); + switch (outer_type) { + case AL_ETH_FSM_ENTRY_IPV4_TCP: + case AL_ETH_FSM_ENTRY_IPV4_UDP: + case AL_ETH_FSM_ENTRY_IPV6_TCP: + case AL_ETH_FSM_ENTRY_IPV6_UDP: + val = AL_ETH_FSM_DATA_OUTER_4_TUPLE | + AL_ETH_FSM_DATA_HASH_SEL; + break; + case AL_ETH_FSM_ENTRY_IPV6_NO_UDP_TCP: + case AL_ETH_FSM_ENTRY_IPV4_NO_UDP_TCP: + val = AL_ETH_FSM_DATA_OUTER_2_TUPLE | + AL_ETH_FSM_DATA_HASH_SEL; + break; + default: + val = AL_ETH_FSM_DATA_DEFAULT_Q | + AL_ETH_FSM_DATA_DEFAULT_UDMA; + } + al_eth_fsm_table_set(&adapter->hal_adapter, i, val); + } +} + +static void +al_eth_mac_table_entry_clear(struct al_eth_adapter *adapter, + uint8_t idx) +{ + struct al_eth_fwd_mac_table_entry entry = { { 0 } }; + + device_printf_dbg(adapter->dev, "%s: clear entry %d\n", __func__, idx); + + al_eth_fwd_mac_table_set(&adapter->hal_adapter, idx, &entry); +} + +static int +al_eth_hw_init_adapter(struct al_eth_adapter *adapter) +{ + struct al_eth_adapter_params *params = &adapter->eth_hal_params; + int rc; + + /* params->dev_id = adapter->dev_id; */ + params->rev_id = adapter->rev_id; + params->udma_id = 0; + params->enable_rx_parser = 1; /* enable rx epe parser*/ + params->udma_regs_base = adapter->udma_base; /* UDMA register base address */ + params->ec_regs_base = adapter->ec_base; /* Ethernet controller registers base address */ + params->mac_regs_base = adapter->mac_base; /* Ethernet MAC registers base address */ + params->name = adapter->name; + params->serdes_lane = adapter->serdes_lane; + + rc = al_eth_adapter_init(&adapter->hal_adapter, params); + if (rc != 0) + device_printf(adapter->dev, "%s failed at hal init!\n", + __func__); + + if ((adapter->board_type == ALPINE_NIC) || + (adapter->board_type == ALPINE_FPGA_NIC)) { + /* in pcie NIC mode, force eth UDMA to access PCIE0 using the vmid */ + struct al_udma_gen_tgtid_conf conf; + int i; + for (i = 0; i < DMA_MAX_Q; i++) { + conf.tx_q_conf[i].queue_en = AL_TRUE; + conf.tx_q_conf[i].desc_en = AL_FALSE; + conf.tx_q_conf[i].tgtid = 0x100; /* for access from PCIE0 */ + conf.rx_q_conf[i].queue_en = AL_TRUE; + conf.rx_q_conf[i].desc_en = AL_FALSE; + conf.rx_q_conf[i].tgtid = 0x100; /* for access from PCIE0 */ + } + al_udma_gen_tgtid_conf_set(adapter->udma_base, &conf); + } + + return (rc); +} + +static void +al_eth_lm_config(struct al_eth_adapter *adapter) +{ + struct al_eth_lm_init_params params = {0}; + + params.adapter = &adapter->hal_adapter; + params.serdes_obj = &adapter->serdes_obj; + params.lane = adapter->serdes_lane; + params.sfp_detection = adapter->sfp_detection_needed; + if (adapter->sfp_detection_needed == true) { + params.sfp_bus_id = adapter->i2c_adapter_id; + params.sfp_i2c_addr = SFP_I2C_ADDR; + } + + if (adapter->sfp_detection_needed == false) { + switch (adapter->mac_mode) { + case AL_ETH_MAC_MODE_10GbE_Serial: + if ((adapter->lt_en != 0) && (adapter->an_en != 0)) + params.default_mode = AL_ETH_LM_MODE_10G_DA; + else + params.default_mode = AL_ETH_LM_MODE_10G_OPTIC; + break; + case AL_ETH_MAC_MODE_SGMII: + params.default_mode = AL_ETH_LM_MODE_1G; + break; + default: + params.default_mode = AL_ETH_LM_MODE_10G_DA; + } + } else + params.default_mode = AL_ETH_LM_MODE_10G_DA; + + params.link_training = adapter->lt_en; + params.rx_equal = true; + params.static_values = !adapter->dont_override_serdes; + params.i2c_context = adapter; + params.kr_fec_enable = false; + + params.retimer_exist = adapter->retimer.exist; + params.retimer_bus_id = adapter->retimer.bus_id; + params.retimer_i2c_addr = adapter->retimer.i2c_addr; + params.retimer_channel = adapter->retimer.channel; + + al_eth_lm_init(&adapter->lm_context, ¶ms); +} + +static int +al_eth_board_params_init(struct al_eth_adapter *adapter) +{ + + if (adapter->board_type == ALPINE_NIC) { + adapter->mac_mode = AL_ETH_MAC_MODE_10GbE_Serial; + adapter->sfp_detection_needed = false; + adapter->phy_exist = false; + adapter->an_en = false; + adapter->lt_en = false; + adapter->ref_clk_freq = AL_ETH_REF_FREQ_375_MHZ; + adapter->mdio_freq = AL_ETH_DEFAULT_MDIO_FREQ_KHZ; + } else if (adapter->board_type == ALPINE_FPGA_NIC) { + adapter->mac_mode = AL_ETH_MAC_MODE_SGMII; + adapter->sfp_detection_needed = false; + adapter->phy_exist = false; + adapter->an_en = false; + adapter->lt_en = false; + adapter->ref_clk_freq = AL_ETH_REF_FREQ_375_MHZ; + adapter->mdio_freq = AL_ETH_DEFAULT_MDIO_FREQ_KHZ; + } else { + struct al_eth_board_params params; + int rc; + + adapter->auto_speed = false; + + rc = al_eth_board_params_get(adapter->mac_base, ¶ms); + if (rc != 0) { + device_printf(adapter->dev, + "board info not available\n"); + return (-1); + } + + adapter->phy_exist = params.phy_exist == TRUE; + adapter->phy_addr = params.phy_mdio_addr; + adapter->an_en = params.autoneg_enable; + adapter->lt_en = params.kr_lt_enable; + adapter->serdes_grp = params.serdes_grp; + adapter->serdes_lane = params.serdes_lane; + adapter->sfp_detection_needed = params.sfp_plus_module_exist; + adapter->i2c_adapter_id = params.i2c_adapter_id; + adapter->ref_clk_freq = params.ref_clk_freq; + adapter->dont_override_serdes = params.dont_override_serdes; + adapter->link_config.active_duplex = !params.half_duplex; + adapter->link_config.autoneg = !params.an_disable; + adapter->link_config.force_1000_base_x = params.force_1000_base_x; + adapter->retimer.exist = params.retimer_exist; + adapter->retimer.bus_id = params.retimer_bus_id; + adapter->retimer.i2c_addr = params.retimer_i2c_addr; + adapter->retimer.channel = params.retimer_channel; + + switch (params.speed) { + default: + device_printf(adapter->dev, + "%s: invalid speed (%d)\n", __func__, params.speed); + case AL_ETH_BOARD_1G_SPEED_1000M: + adapter->link_config.active_speed = 1000; + break; + case AL_ETH_BOARD_1G_SPEED_100M: + adapter->link_config.active_speed = 100; + break; + case AL_ETH_BOARD_1G_SPEED_10M: + adapter->link_config.active_speed = 10; + break; + } + + switch (params.mdio_freq) { + default: + device_printf(adapter->dev, + "%s: invalid mdio freq (%d)\n", __func__, + params.mdio_freq); + case AL_ETH_BOARD_MDIO_FREQ_2_5_MHZ: + adapter->mdio_freq = AL_ETH_DEFAULT_MDIO_FREQ_KHZ; + break; + case AL_ETH_BOARD_MDIO_FREQ_1_MHZ: + adapter->mdio_freq = AL_ETH_MDIO_FREQ_1000_KHZ; + break; + } + + switch (params.media_type) { + case AL_ETH_BOARD_MEDIA_TYPE_RGMII: + if (params.sfp_plus_module_exist == TRUE) + /* Backward compatibility */ + adapter->mac_mode = AL_ETH_MAC_MODE_SGMII; + else + adapter->mac_mode = AL_ETH_MAC_MODE_RGMII; + + adapter->use_lm = false; + break; + case AL_ETH_BOARD_MEDIA_TYPE_SGMII: + adapter->mac_mode = AL_ETH_MAC_MODE_SGMII; + adapter->use_lm = true; + break; + case AL_ETH_BOARD_MEDIA_TYPE_10GBASE_SR: + adapter->mac_mode = AL_ETH_MAC_MODE_10GbE_Serial; + adapter->use_lm = true; + break; + case AL_ETH_BOARD_MEDIA_TYPE_AUTO_DETECT: + adapter->sfp_detection_needed = TRUE; + adapter->auto_speed = false; + adapter->use_lm = true; + break; + case AL_ETH_BOARD_MEDIA_TYPE_AUTO_DETECT_AUTO_SPEED: + adapter->sfp_detection_needed = TRUE; + adapter->auto_speed = true; + adapter->mac_mode_set = false; + adapter->use_lm = true; + + adapter->mac_mode = AL_ETH_MAC_MODE_10GbE_Serial; + break; + default: + device_printf(adapter->dev, + "%s: unsupported media type %d\n", + __func__, params.media_type); + return (-1); + } + + device_printf(adapter->dev, + "Board info: phy exist %s. phy addr %d. mdio freq %u Khz. " + "SFP connected %s. media %d\n", + params.phy_exist == TRUE ? "Yes" : "No", + params.phy_mdio_addr, adapter->mdio_freq, + params.sfp_plus_module_exist == TRUE ? "Yes" : "No", + params.media_type); + } + + al_eth_mac_addr_read(adapter->ec_base, 0, adapter->mac_addr); + + return (0); +} + +static int +al_eth_function_reset(struct al_eth_adapter *adapter) +{ + struct al_eth_board_params params; + int rc; + + /* save board params so we restore it after reset */ + al_eth_board_params_get(adapter->mac_base, ¶ms); + al_eth_mac_addr_read(adapter->ec_base, 0, adapter->mac_addr); + if (adapter->board_type == ALPINE_INTEGRATED) + rc = al_eth_flr_rmn(&al_eth_read_pci_config, + &al_eth_write_pci_config, + adapter->dev, adapter->mac_base); + else + rc = al_eth_flr_rmn(&al_eth_fpga_read_pci_config, + &al_eth_fpga_write_pci_config, + adapter->internal_pcie_base, adapter->mac_base); + + /* restore params */ + al_eth_board_params_set(adapter->mac_base, ¶ms); + al_eth_mac_addr_store(adapter->ec_base, 0, adapter->mac_addr); + + return (rc); +} + +static void +al_eth_init_rings(struct al_eth_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) { + struct al_eth_ring *ring = &adapter->tx_ring[i]; + + ring->ring_id = i; + ring->dev = adapter->dev; + ring->adapter = adapter; + ring->netdev = adapter->netdev; + al_udma_q_handle_get(&adapter->hal_adapter.tx_udma, i, + &ring->dma_q); + ring->sw_count = adapter->tx_ring_count; + ring->hw_count = adapter->tx_descs_count; + ring->unmask_reg_offset = al_udma_iofic_unmask_offset_get((struct unit_regs *)adapter->udma_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, AL_INT_GROUP_C); + ring->unmask_val = ~(1 << i); + } + + for (i = 0; i < adapter->num_rx_queues; i++) { + struct al_eth_ring *ring = &adapter->rx_ring[i]; + + ring->ring_id = i; + ring->dev = adapter->dev; + ring->adapter = adapter; + ring->netdev = adapter->netdev; + al_udma_q_handle_get(&adapter->hal_adapter.rx_udma, i, &ring->dma_q); + ring->sw_count = adapter->rx_ring_count; + ring->hw_count = adapter->rx_descs_count; + ring->unmask_reg_offset = al_udma_iofic_unmask_offset_get( + (struct unit_regs *)adapter->udma_base, + AL_UDMA_IOFIC_LEVEL_PRIMARY, AL_INT_GROUP_B); + ring->unmask_val = ~(1 << i); + } +} + +static void +al_init_locked(void *arg) +{ + struct al_eth_adapter *adapter = arg; + if_t ifp = adapter->netdev; + int rc = 0; + + al_eth_down(adapter); + rc = al_eth_up(adapter); + + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + if (rc == 0) + ifp->if_drv_flags |= IFF_DRV_RUNNING; +} + +static void +al_init(void *arg) +{ + struct al_eth_adapter *adapter = arg; + + al_init_locked(adapter); +} + +static inline int +al_eth_alloc_rx_buf(struct al_eth_adapter *adapter, + struct al_eth_ring *rx_ring, + struct al_eth_rx_buffer *rx_info) +{ + struct al_buf *al_buf; + bus_dma_segment_t segs[2]; + int error; + int nsegs; + + if (rx_info->m != NULL) + return (0); + + rx_info->data_size = adapter->rx_mbuf_sz; + + AL_RX_LOCK(adapter); + + /* Get mbuf using UMA allocator */ + rx_info->m = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, + rx_info->data_size); + AL_RX_UNLOCK(adapter); + + if (rx_info->m == NULL) + return (ENOMEM); + + rx_info->m->m_pkthdr.len = rx_info->m->m_len = adapter->rx_mbuf_sz; + + /* Map packets for DMA */ + error = bus_dmamap_load_mbuf_sg(rx_ring->dma_buf_tag, rx_info->dma_map, + rx_info->m, segs, &nsegs, BUS_DMA_NOWAIT); + if (__predict_false(error)) { + device_printf(rx_ring->dev, "failed to map mbuf, error = %d\n", + error); + m_freem(rx_info->m); + rx_info->m = NULL; + return (EFAULT); + } + + al_buf = &rx_info->al_buf; + al_buf->addr = segs[0].ds_addr + AL_IP_ALIGNMENT_OFFSET; + al_buf->len = rx_info->data_size - AL_IP_ALIGNMENT_OFFSET; + + return (0); +} + +static int +al_eth_refill_rx_bufs(struct al_eth_adapter *adapter, unsigned int qid, + unsigned int num) +{ + struct al_eth_ring *rx_ring = &adapter->rx_ring[qid]; + uint16_t next_to_use; + unsigned int i; + + next_to_use = rx_ring->next_to_use; + + for (i = 0; i < num; i++) { + int rc; + struct al_eth_rx_buffer *rx_info = + &rx_ring->rx_buffer_info[next_to_use]; + + if (__predict_false(al_eth_alloc_rx_buf(adapter, + rx_ring, rx_info) < 0)) { + device_printf(adapter->dev, + "failed to alloc buffer for rx queue %d\n", qid); + break; + } + + rc = al_eth_rx_buffer_add(rx_ring->dma_q, + &rx_info->al_buf, AL_ETH_RX_FLAGS_INT, NULL); + if (__predict_false(rc)) { + device_printf(adapter->dev, + "failed to add buffer for rx queue %d\n", qid); + break; + } + + next_to_use = AL_ETH_RX_RING_IDX_NEXT(rx_ring, next_to_use); + } + + if (__predict_false(i < num)) + device_printf(adapter->dev, + "refilled rx queue %d with %d pages only - available %d\n", + qid, i, al_udma_available_get(rx_ring->dma_q)); + + if (__predict_true(i)) + al_eth_rx_buffer_action(rx_ring->dma_q, i); + + rx_ring->next_to_use = next_to_use; + + return (i); +} + +/* + * al_eth_refill_all_rx_bufs - allocate all queues Rx buffers + * @adapter: board private structure + */ +static void +al_eth_refill_all_rx_bufs(struct al_eth_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + al_eth_refill_rx_bufs(adapter, i, AL_ETH_DEFAULT_RX_DESCS - 1); +} + +static void +al_eth_tx_do_cleanup(struct al_eth_ring *tx_ring) +{ + unsigned int total_done; + uint16_t next_to_clean; + int qid = tx_ring->ring_id; + + total_done = al_eth_comp_tx_get(tx_ring->dma_q); + device_printf_dbg(tx_ring->dev, + "tx_poll: q %d total completed descs %x\n", qid, total_done); + next_to_clean = tx_ring->next_to_clean; + + while (total_done != 0) { + struct al_eth_tx_buffer *tx_info; + struct mbuf *mbuf; + + tx_info = &tx_ring->tx_buffer_info[next_to_clean]; + /* stop if not all descriptors of the packet are completed */ + if (tx_info->tx_descs > total_done) + break; + + mbuf = tx_info->m; + + tx_info->m = NULL; + + device_printf_dbg(tx_ring->dev, + "tx_poll: q %d mbuf %p completed\n", qid, mbuf); + + /* map is no longer required */ + bus_dmamap_unload(tx_ring->dma_buf_tag, tx_info->dma_map); + + m_freem(mbuf); + total_done -= tx_info->tx_descs; + next_to_clean = AL_ETH_TX_RING_IDX_NEXT(tx_ring, next_to_clean); + } + + tx_ring->next_to_clean = next_to_clean; + + device_printf_dbg(tx_ring->dev, "tx_poll: q %d done next to clean %x\n", + qid, next_to_clean); + + /* + * need to make the rings circular update visible to + * al_eth_start_xmit() before checking for netif_queue_stopped(). + */ + al_smp_data_memory_barrier(); +} + +static void +al_eth_tx_csum(struct al_eth_ring *tx_ring, struct al_eth_tx_buffer *tx_info, + struct al_eth_pkt *hal_pkt, struct mbuf *m) +{ + uint32_t mss = m->m_pkthdr.tso_segsz; + struct ether_vlan_header *eh; + uint16_t etype; + struct ip *ip; + struct ip6_hdr *ip6; + struct tcphdr *th = NULL; + int ehdrlen, ip_hlen = 0; + uint8_t ipproto = 0; + uint32_t offload = 0; + + if (mss != 0) + offload = 1; + + if ((m->m_pkthdr.csum_flags & CSUM_TSO) != 0) + offload = 1; + + if ((m->m_pkthdr.csum_flags & CSUM_OFFLOAD) != 0) + offload = 1; + + if (offload != 0) { + struct al_eth_meta_data *meta = &tx_ring->hal_meta; + + if (mss != 0) + hal_pkt->flags |= (AL_ETH_TX_FLAGS_TSO | + AL_ETH_TX_FLAGS_L4_CSUM); + else + hal_pkt->flags |= (AL_ETH_TX_FLAGS_L4_CSUM | + AL_ETH_TX_FLAGS_L4_PARTIAL_CSUM); + + /* + * Determine where frame payload starts. + * Jump over vlan headers if already present, + * helpful for QinQ too. + */ + eh = mtod(m, struct ether_vlan_header *); + if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { + etype = ntohs(eh->evl_proto); + ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; + } else { + etype = ntohs(eh->evl_encap_proto); + ehdrlen = ETHER_HDR_LEN; + } + + switch (etype) { + case ETHERTYPE_IP: + ip = (struct ip *)(m->m_data + ehdrlen); + ip_hlen = ip->ip_hl << 2; + ipproto = ip->ip_p; + hal_pkt->l3_proto_idx = AL_ETH_PROTO_ID_IPv4; + th = (struct tcphdr *)((caddr_t)ip + ip_hlen); + if (mss != 0) + hal_pkt->flags |= AL_ETH_TX_FLAGS_IPV4_L3_CSUM; + if (ipproto == IPPROTO_TCP) + hal_pkt->l4_proto_idx = AL_ETH_PROTO_ID_TCP; + else + hal_pkt->l4_proto_idx = AL_ETH_PROTO_ID_UDP; + break; + case ETHERTYPE_IPV6: + ip6 = (struct ip6_hdr *)(m->m_data + ehdrlen); + hal_pkt->l3_proto_idx = AL_ETH_PROTO_ID_IPv6; + ip_hlen = sizeof(struct ip6_hdr); + th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); + ipproto = ip6->ip6_nxt; + if (ipproto == IPPROTO_TCP) + hal_pkt->l4_proto_idx = AL_ETH_PROTO_ID_TCP; + else + hal_pkt->l4_proto_idx = AL_ETH_PROTO_ID_UDP; + break; + default: + break; + } + + meta->words_valid = 4; + meta->l3_header_len = ip_hlen; + meta->l3_header_offset = ehdrlen; + if (th != NULL) + meta->l4_header_len = th->th_off; /* this param needed only for TSO */ + meta->mss_idx_sel = 0; /* check how to select MSS */ + meta->mss_val = mss; + hal_pkt->meta = meta; + } else + hal_pkt->meta = NULL; +} + +#define XMIT_QUEUE_TIMEOUT 100 + +static void +al_eth_xmit_mbuf(struct al_eth_ring *tx_ring, struct mbuf *m) +{ + struct al_eth_tx_buffer *tx_info; + int error; + int nsegs, a; + uint16_t next_to_use; + bus_dma_segment_t segs[AL_ETH_PKT_MAX_BUFS + 1]; + struct al_eth_pkt *hal_pkt; + struct al_buf *al_buf; + boolean_t remap; + + /* Check if queue is ready */ + if (unlikely(tx_ring->stall) != 0) { + for (a = 0; a < XMIT_QUEUE_TIMEOUT; a++) { + if (al_udma_available_get(tx_ring->dma_q) >= + (AL_ETH_DEFAULT_TX_HW_DESCS - + AL_ETH_TX_WAKEUP_THRESH)) { + tx_ring->stall = 0; + break; + } + pause("stall", 1); + } + if (a == XMIT_QUEUE_TIMEOUT) { + device_printf(tx_ring->dev, + "timeout waiting for queue %d ready!\n", + tx_ring->ring_id); + return; + } else { + device_printf_dbg(tx_ring->dev, + "queue %d is ready!\n", tx_ring->ring_id); + } + } + + next_to_use = tx_ring->next_to_use; + tx_info = &tx_ring->tx_buffer_info[next_to_use]; + tx_info->m = m; + hal_pkt = &tx_info->hal_pkt; + + if (m == NULL) { + device_printf(tx_ring->dev, "mbuf is NULL\n"); + return; + } + + remap = TRUE; + /* Map packets for DMA */ +retry: + error = bus_dmamap_load_mbuf_sg(tx_ring->dma_buf_tag, tx_info->dma_map, + m, segs, &nsegs, BUS_DMA_NOWAIT); + if (__predict_false(error)) { + struct mbuf *m_new; + + if (error == EFBIG) { + /* Try it again? - one try */ + if (remap == TRUE) { + remap = FALSE; + m_new = m_defrag(m, M_NOWAIT); + if (m_new == NULL) { + device_printf(tx_ring->dev, + "failed to defrag mbuf\n"); + goto exit; + } + m = m_new; + goto retry; + } else { + device_printf(tx_ring->dev, + "failed to map mbuf, error %d\n", error); + goto exit; + } + } else { + device_printf(tx_ring->dev, + "failed to map mbuf, error %d\n", error); + goto exit; + } + } + + /* set flags and meta data */ + hal_pkt->flags = AL_ETH_TX_FLAGS_INT; + al_eth_tx_csum(tx_ring, tx_info, hal_pkt, m); + + al_buf = hal_pkt->bufs; + for (a = 0; a < nsegs; a++) { + al_buf->addr = segs[a].ds_addr; + al_buf->len = segs[a].ds_len; + + al_buf++; + } + + hal_pkt->num_of_bufs = nsegs; + + /* prepare the packet's descriptors to dma engine */ + tx_info->tx_descs = al_eth_tx_pkt_prepare(tx_ring->dma_q, hal_pkt); + + if (tx_info->tx_descs == 0) + goto exit; + + /* + * stop the queue when no more space available, the packet can have up + * to AL_ETH_PKT_MAX_BUFS + 1 buffers and a meta descriptor + */ + if (unlikely(al_udma_available_get(tx_ring->dma_q) < + (AL_ETH_PKT_MAX_BUFS + 2))) { + tx_ring->stall = 1; + device_printf_dbg(tx_ring->dev, "stall, stopping queue %d...\n", + tx_ring->ring_id); + al_data_memory_barrier(); + } + + tx_ring->next_to_use = AL_ETH_TX_RING_IDX_NEXT(tx_ring, next_to_use); + + /* trigger the dma engine */ + al_eth_tx_dma_action(tx_ring->dma_q, tx_info->tx_descs); + return; + +exit: + m_freem(m); +} + +static void +al_eth_tx_cmpl_work(void *arg, int pending) +{ + struct al_eth_ring *tx_ring = arg; + + if (napi != 0) { + tx_ring->cmpl_is_running = 1; + al_data_memory_barrier(); + } + + al_eth_tx_do_cleanup(tx_ring); + + if (napi != 0) { + tx_ring->cmpl_is_running = 0; + al_data_memory_barrier(); + } + /* all work done, enable IRQs */ + al_eth_irq_config(tx_ring->unmask_reg_offset, tx_ring->unmask_val); +} + +static int +al_eth_tx_cmlp_irq_filter(void *arg) +{ + struct al_eth_ring *tx_ring = arg; + + /* Interrupt should be auto-masked upon arrival */ + + device_printf_dbg(tx_ring->dev, "%s for ring ID = %d\n", __func__, + tx_ring->ring_id); + + /* + * For napi, if work is not running, schedule it. Always schedule + * for casual (non-napi) packet handling. + */ + if ((napi == 0) || (napi && tx_ring->cmpl_is_running == 0)) + taskqueue_enqueue(tx_ring->cmpl_tq, &tx_ring->cmpl_task); + + /* Do not run bottom half */ + return (FILTER_HANDLED); +} + +static int +al_eth_rx_recv_irq_filter(void *arg) +{ + struct al_eth_ring *rx_ring = arg; + + /* Interrupt should be auto-masked upon arrival */ + + device_printf_dbg(rx_ring->dev, "%s for ring ID = %d\n", __func__, + rx_ring->ring_id); + + /* + * For napi, if work is not running, schedule it. Always schedule + * for casual (non-napi) packet handling. + */ + if ((napi == 0) || (napi && rx_ring->enqueue_is_running == 0)) + taskqueue_enqueue(rx_ring->enqueue_tq, &rx_ring->enqueue_task); + + /* Do not run bottom half */ + return (FILTER_HANDLED); +} + +/* + * al_eth_rx_checksum - indicate in mbuf if hw indicated a good cksum + * @adapter: structure containing adapter specific data + * @hal_pkt: HAL structure for the packet + * @mbuf: mbuf currently being received and modified + */ +static inline void +al_eth_rx_checksum(struct al_eth_adapter *adapter, + struct al_eth_pkt *hal_pkt, struct mbuf *mbuf) +{ + + /* if IPv4 and error */ + if (unlikely((adapter->netdev->if_capenable & IFCAP_RXCSUM) && + (hal_pkt->l3_proto_idx == AL_ETH_PROTO_ID_IPv4) && + (hal_pkt->flags & AL_ETH_RX_FLAGS_L3_CSUM_ERR))) { + device_printf(adapter->dev,"rx ipv4 header checksum error\n"); + return; + } + + /* if IPv6 and error */ + if (unlikely((adapter->netdev->if_capenable & IFCAP_RXCSUM_IPV6) && + (hal_pkt->l3_proto_idx == AL_ETH_PROTO_ID_IPv6) && + (hal_pkt->flags & AL_ETH_RX_FLAGS_L3_CSUM_ERR))) { + device_printf(adapter->dev,"rx ipv6 header checksum error\n"); + return; + } + + /* if TCP/UDP */ + if (likely((hal_pkt->l4_proto_idx == AL_ETH_PROTO_ID_TCP) || + (hal_pkt->l4_proto_idx == AL_ETH_PROTO_ID_UDP))) { + if (unlikely(hal_pkt->flags & AL_ETH_RX_FLAGS_L4_CSUM_ERR)) { + device_printf_dbg(adapter->dev, "rx L4 checksum error\n"); + + /* TCP/UDP checksum error */ + mbuf->m_pkthdr.csum_flags = 0; + } else { + device_printf_dbg(adapter->dev, "rx checksum correct\n"); + + /* IP Checksum Good */ + mbuf->m_pkthdr.csum_flags = CSUM_IP_CHECKED; + mbuf->m_pkthdr.csum_flags |= CSUM_IP_VALID; + } + } +} + +static struct mbuf* +al_eth_rx_mbuf(struct al_eth_adapter *adapter, + struct al_eth_ring *rx_ring, struct al_eth_pkt *hal_pkt, + unsigned int descs, uint16_t *next_to_clean) +{ + struct mbuf *mbuf; + struct al_eth_rx_buffer *rx_info = + &rx_ring->rx_buffer_info[*next_to_clean]; + unsigned int len; + + len = hal_pkt->bufs[0].len; + device_printf_dbg(adapter->dev, "rx_info %p data %p\n", rx_info, + rx_info->m); + + if (rx_info->m == NULL) { + *next_to_clean = AL_ETH_RX_RING_IDX_NEXT(rx_ring, + *next_to_clean); + return (NULL); + } + + mbuf = rx_info->m; + mbuf->m_pkthdr.len = len; + mbuf->m_len = len; + mbuf->m_pkthdr.rcvif = rx_ring->netdev; + mbuf->m_flags |= M_PKTHDR; + + if (len <= adapter->small_copy_len) { + struct mbuf *smbuf; + device_printf_dbg(adapter->dev, "rx small packet. len %d\n", len); + + AL_RX_LOCK(adapter); + smbuf = m_gethdr(M_NOWAIT, MT_DATA); + AL_RX_UNLOCK(adapter); + if (__predict_false(smbuf == NULL)) { + device_printf(adapter->dev, "smbuf is NULL\n"); + return (NULL); + } + + smbuf->m_data = smbuf->m_data + AL_IP_ALIGNMENT_OFFSET; + memcpy(smbuf->m_data, mbuf->m_data + AL_IP_ALIGNMENT_OFFSET, len); + + smbuf->m_len = len; + smbuf->m_pkthdr.rcvif = rx_ring->netdev; + + /* first desc of a non-ps chain */ + smbuf->m_flags |= M_PKTHDR; + smbuf->m_pkthdr.len = smbuf->m_len; + + *next_to_clean = AL_ETH_RX_RING_IDX_NEXT(rx_ring, + *next_to_clean); + + return (smbuf); + } + mbuf->m_data = mbuf->m_data + AL_IP_ALIGNMENT_OFFSET; + + /* Unmap the buffer */ + bus_dmamap_unload(rx_ring->dma_buf_tag, rx_info->dma_map); + + rx_info->m = NULL; + *next_to_clean = AL_ETH_RX_RING_IDX_NEXT(rx_ring, *next_to_clean); + + return (mbuf); +} + +static void +al_eth_rx_recv_work(void *arg, int pending) +{ + struct al_eth_ring *rx_ring = arg; + struct mbuf *mbuf; + struct lro_entry *queued; + unsigned int qid = rx_ring->ring_id; + struct al_eth_pkt *hal_pkt = &rx_ring->hal_pkt; + uint16_t next_to_clean = rx_ring->next_to_clean; + uint32_t refill_required; + uint32_t refill_actual; + uint32_t do_if_input; + + if (napi != 0) { + rx_ring->enqueue_is_running = 1; + al_data_memory_barrier(); + } + + do { + unsigned int descs; + + descs = al_eth_pkt_rx(rx_ring->dma_q, hal_pkt); + if (unlikely(descs == 0)) + break; + + device_printf_dbg(rx_ring->dev, "rx_poll: q %d got packet " + "from hal. descs %d\n", qid, descs); + device_printf_dbg(rx_ring->dev, "rx_poll: q %d flags %x. " + "l3 proto %d l4 proto %d\n", qid, hal_pkt->flags, + hal_pkt->l3_proto_idx, hal_pkt->l4_proto_idx); + + /* ignore if detected dma or eth controller errors */ + if ((hal_pkt->flags & (AL_ETH_RX_ERROR | + AL_UDMA_CDESC_ERROR)) != 0) { + device_printf(rx_ring->dev, "receive packet with error. " + "flags = 0x%x\n", hal_pkt->flags); + next_to_clean = AL_ETH_RX_RING_IDX_ADD(rx_ring, + next_to_clean, descs); + continue; + } + + /* allocate mbuf and fill it */ + mbuf = al_eth_rx_mbuf(rx_ring->adapter, rx_ring, hal_pkt, descs, + &next_to_clean); + + /* exit if we failed to retrieve a buffer */ + if (unlikely(mbuf == NULL)) { + next_to_clean = AL_ETH_RX_RING_IDX_ADD(rx_ring, + next_to_clean, descs); + break; + } + + if (__predict_true(rx_ring->netdev->if_capenable & IFCAP_RXCSUM || + rx_ring->netdev->if_capenable & IFCAP_RXCSUM_IPV6)) { + al_eth_rx_checksum(rx_ring->adapter, hal_pkt, mbuf); + } + +#if __FreeBSD_version >= 800000 + mbuf->m_pkthdr.flowid = qid; + M_HASHTYPE_SET(mbuf, M_HASHTYPE_OPAQUE); +#endif + + /* + * LRO is only for IP/TCP packets and TCP checksum of the packet + * should be computed by hardware. + */ + do_if_input = 1; + if ((rx_ring->lro_enabled != 0) && + ((mbuf->m_pkthdr.csum_flags & CSUM_IP_VALID) != 0) && + hal_pkt->l4_proto_idx == AL_ETH_PROTO_ID_TCP) { + /* + * Send to the stack if: + * - LRO not enabled, or + * - no LRO resources, or + * - lro enqueue fails + */ + if (rx_ring->lro.lro_cnt != 0) { + if (tcp_lro_rx(&rx_ring->lro, mbuf, 0) == 0) + do_if_input = 0; + } + } + + if (do_if_input) + (*rx_ring->netdev->if_input)(rx_ring->netdev, mbuf); + + } while (1); + + rx_ring->next_to_clean = next_to_clean; + + refill_required = al_udma_available_get(rx_ring->dma_q); + refill_actual = al_eth_refill_rx_bufs(rx_ring->adapter, qid, + refill_required); + + if (unlikely(refill_actual < refill_required)) { + device_printf_dbg(rx_ring->dev, + "%s: not filling rx queue %d\n", __func__, qid); + } + + while (((queued = LIST_FIRST(&rx_ring->lro.lro_active)) != NULL)) { + LIST_REMOVE(queued, next); + tcp_lro_flush(&rx_ring->lro, queued); + } + + if (napi != 0) { + rx_ring->enqueue_is_running = 0; + al_data_memory_barrier(); + } + /* unmask irq */ + al_eth_irq_config(rx_ring->unmask_reg_offset, rx_ring->unmask_val); +} + +static void +al_eth_start_xmit(void *arg, int pending) +{ + struct al_eth_ring *tx_ring = arg; + struct mbuf *mbuf; + + if (napi != 0) { + tx_ring->enqueue_is_running = 1; + al_data_memory_barrier(); + } + + while (1) { + mtx_lock(&tx_ring->br_mtx); + mbuf = drbr_dequeue(NULL, tx_ring->br); + mtx_unlock(&tx_ring->br_mtx); + + if (mbuf == NULL) + break; + + al_eth_xmit_mbuf(tx_ring, mbuf); + } + + if (napi != 0) { + tx_ring->enqueue_is_running = 0; + al_data_memory_barrier(); + while (1) { + mtx_lock(&tx_ring->br_mtx); + mbuf = drbr_dequeue(NULL, tx_ring->br); + mtx_unlock(&tx_ring->br_mtx); + if (mbuf == NULL) + break; + al_eth_xmit_mbuf(tx_ring, mbuf); + } + } +} + +static int +al_mq_start(struct ifnet *ifp, struct mbuf *m) +{ + struct al_eth_adapter *adapter = ifp->if_softc; + struct al_eth_ring *tx_ring; + int i; + int ret; + + /* Which queue to use */ + if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) + i = m->m_pkthdr.flowid % adapter->num_tx_queues; + else + i = curcpu % adapter->num_tx_queues; + + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING) { + return (EFAULT); + } + + tx_ring = &adapter->tx_ring[i]; + + device_printf_dbg(adapter->dev, "dgb start() - assuming link is active, " + "sending packet to queue %d\n", i); + + ret = drbr_enqueue(ifp, tx_ring->br, m); + + /* + * For napi, if work is not running, schedule it. Always schedule + * for casual (non-napi) packet handling. + */ + if ((napi == 0) || ((napi != 0) && (tx_ring->enqueue_is_running == 0))) + taskqueue_enqueue(tx_ring->enqueue_tq, &tx_ring->enqueue_task); + + return (ret); +} + +static void +al_qflush(struct ifnet * ifp) +{ + + /* unused */ +} + +static inline void +al_eth_flow_ctrl_init(struct al_eth_adapter *adapter) +{ + uint8_t default_flow_ctrl; + + default_flow_ctrl = AL_ETH_FLOW_CTRL_TX_PAUSE; + default_flow_ctrl |= AL_ETH_FLOW_CTRL_RX_PAUSE; + + adapter->link_config.flow_ctrl_supported = default_flow_ctrl; +} + +static int +al_eth_flow_ctrl_config(struct al_eth_adapter *adapter) +{ + struct al_eth_flow_control_params *flow_ctrl_params; + uint8_t active = adapter->link_config.flow_ctrl_active; + int i; + + flow_ctrl_params = &adapter->flow_ctrl_params; + + flow_ctrl_params->type = AL_ETH_FLOW_CONTROL_TYPE_LINK_PAUSE; + flow_ctrl_params->obay_enable = + ((active & AL_ETH_FLOW_CTRL_RX_PAUSE) != 0); + flow_ctrl_params->gen_enable = + ((active & AL_ETH_FLOW_CTRL_TX_PAUSE) != 0); + + flow_ctrl_params->rx_fifo_th_high = AL_ETH_FLOW_CTRL_RX_FIFO_TH_HIGH; + flow_ctrl_params->rx_fifo_th_low = AL_ETH_FLOW_CTRL_RX_FIFO_TH_LOW; + flow_ctrl_params->quanta = AL_ETH_FLOW_CTRL_QUANTA; + flow_ctrl_params->quanta_th = AL_ETH_FLOW_CTRL_QUANTA_TH; + + /* map priority to queue index, queue id = priority/2 */ + for (i = 0; i < AL_ETH_FWD_PRIO_TABLE_NUM; i++) + flow_ctrl_params->prio_q_map[0][i] = 1 << (i >> 1); + + al_eth_flow_control_config(&adapter->hal_adapter, flow_ctrl_params); + + return (0); +} + +static void +al_eth_flow_ctrl_enable(struct al_eth_adapter *adapter) +{ + + /* + * change the active configuration to the default / force by ethtool + * and call to configure + */ + adapter->link_config.flow_ctrl_active = + adapter->link_config.flow_ctrl_supported; + + al_eth_flow_ctrl_config(adapter); +} + +static void +al_eth_flow_ctrl_disable(struct al_eth_adapter *adapter) +{ + + adapter->link_config.flow_ctrl_active = 0; + al_eth_flow_ctrl_config(adapter); +} + +static int +al_eth_hw_init(struct al_eth_adapter *adapter) +{ + int rc; + + rc = al_eth_hw_init_adapter(adapter); + if (rc != 0) + return (rc); + + rc = al_eth_mac_config(&adapter->hal_adapter, adapter->mac_mode); + if (rc < 0) { + device_printf(adapter->dev, "%s failed to configure mac!\n", + __func__); + return (rc); + } + + if ((adapter->mac_mode == AL_ETH_MAC_MODE_SGMII) || + (adapter->mac_mode == AL_ETH_MAC_MODE_RGMII && + adapter->phy_exist == FALSE)) { + rc = al_eth_mac_link_config(&adapter->hal_adapter, + adapter->link_config.force_1000_base_x, + adapter->link_config.autoneg, + adapter->link_config.active_speed, + adapter->link_config.active_duplex); + if (rc != 0) { + device_printf(adapter->dev, + "%s failed to configure link parameters!\n", + __func__); + return (rc); + } + } + + rc = al_eth_mdio_config(&adapter->hal_adapter, + AL_ETH_MDIO_TYPE_CLAUSE_22, TRUE /* shared_mdio_if */, + adapter->ref_clk_freq, adapter->mdio_freq); + if (rc != 0) { + device_printf(adapter->dev, "%s failed at mdio config!\n", + __func__); + return (rc); + } + + al_eth_flow_ctrl_init(adapter); + + return (rc); +} + +static int +al_eth_hw_stop(struct al_eth_adapter *adapter) +{ + + al_eth_mac_stop(&adapter->hal_adapter); + + /* + * wait till pending rx packets written and UDMA becomes idle, + * the MAC has ~10KB fifo, 10us should be enought time for the + * UDMA to write to the memory + */ + DELAY(10); + + al_eth_adapter_stop(&adapter->hal_adapter); + + adapter->flags |= AL_ETH_FLAG_RESET_REQUESTED; + + /* disable flow ctrl to avoid pause packets*/ + al_eth_flow_ctrl_disable(adapter); + + return (0); +} + +/* + * al_eth_intr_intx_all - Legacy Interrupt Handler for all interrupts + * @irq: interrupt number + * @data: pointer to a network interface device structure + */ +static int +al_eth_intr_intx_all(void *data) +{ + struct al_eth_adapter *adapter = data; + + struct unit_regs __iomem *regs_base = + (struct unit_regs __iomem *)adapter->udma_base; + uint32_t reg; + + reg = al_udma_iofic_read_cause(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, + AL_INT_GROUP_A); + if (likely(reg)) + device_printf_dbg(adapter->dev, "%s group A cause %x\n", + __func__, reg); + + if (unlikely(reg & AL_INT_GROUP_A_GROUP_D_SUM)) { + struct al_iofic_grp_ctrl __iomem *sec_ints_base; + uint32_t cause_d = al_udma_iofic_read_cause(regs_base, + AL_UDMA_IOFIC_LEVEL_PRIMARY, AL_INT_GROUP_D); + + sec_ints_base = + ®s_base->gen.interrupt_regs.secondary_iofic_ctrl[0]; + if (cause_d != 0) { + device_printf_dbg(adapter->dev, + "got interrupt from group D. cause %x\n", cause_d); + + cause_d = al_iofic_read_cause(sec_ints_base, + AL_INT_GROUP_A); + device_printf(adapter->dev, + "secondary A cause %x\n", cause_d); + + cause_d = al_iofic_read_cause(sec_ints_base, + AL_INT_GROUP_B); + + device_printf_dbg(adapter->dev, + "secondary B cause %x\n", cause_d); + } + } + if ((reg & AL_INT_GROUP_A_GROUP_B_SUM) != 0 ) { + uint32_t cause_b = al_udma_iofic_read_cause(regs_base, + AL_UDMA_IOFIC_LEVEL_PRIMARY, AL_INT_GROUP_B); + int qid; + device_printf_dbg(adapter->dev, "secondary B cause %x\n", + cause_b); + for (qid = 0; qid < adapter->num_rx_queues; qid++) { + if (cause_b & (1 << qid)) { + /* mask */ + al_udma_iofic_mask( + (struct unit_regs __iomem *)adapter->udma_base, + AL_UDMA_IOFIC_LEVEL_PRIMARY, + AL_INT_GROUP_B, 1 << qid); + } + } + } + if ((reg & AL_INT_GROUP_A_GROUP_C_SUM) != 0) { + uint32_t cause_c = al_udma_iofic_read_cause(regs_base, + AL_UDMA_IOFIC_LEVEL_PRIMARY, AL_INT_GROUP_C); + int qid; + device_printf_dbg(adapter->dev, "secondary C cause %x\n", cause_c); + for (qid = 0; qid < adapter->num_tx_queues; qid++) { + if ((cause_c & (1 << qid)) != 0) { + al_udma_iofic_mask( + (struct unit_regs __iomem *)adapter->udma_base, + AL_UDMA_IOFIC_LEVEL_PRIMARY, + AL_INT_GROUP_C, 1 << qid); + } + } + } + + al_eth_tx_cmlp_irq_filter(adapter->tx_ring); + + return (0); +} + +static int +al_eth_intr_msix_all(void *data) +{ + struct al_eth_adapter *adapter = data; + + device_printf_dbg(adapter->dev, "%s\n", __func__); + return (0); +} + +static int +al_eth_intr_msix_mgmt(void *data) +{ + struct al_eth_adapter *adapter = data; + + device_printf_dbg(adapter->dev, "%s\n", __func__); + return (0); +} + +static int +al_eth_enable_msix(struct al_eth_adapter *adapter) +{ + int i, msix_vecs, rc, count; + + device_printf_dbg(adapter->dev, "%s\n", __func__); + msix_vecs = 1 + adapter->num_rx_queues + adapter->num_tx_queues; + + device_printf_dbg(adapter->dev, + "Try to enable MSIX, vector numbers = %d\n", msix_vecs); + + adapter->msix_entries = malloc(msix_vecs*sizeof(*adapter->msix_entries), + M_IFAL, M_ZERO | M_WAITOK); + + if (adapter->msix_entries == 0) { + device_printf_dbg(adapter->dev, "failed to allocate" + " msix_entries %d\n", msix_vecs); + rc = ENOMEM; + goto exit; + } + + /* management vector (GROUP_A) @2*/ + adapter->msix_entries[AL_ETH_MGMT_IRQ_IDX].entry = 2; + adapter->msix_entries[AL_ETH_MGMT_IRQ_IDX].vector = 0; + + /* rx queues start @3 */ + for (i = 0; i < adapter->num_rx_queues; i++) { + int irq_idx = AL_ETH_RXQ_IRQ_IDX(adapter, i); + + adapter->msix_entries[irq_idx].entry = 3 + i; + adapter->msix_entries[irq_idx].vector = 0; + } + /* tx queues start @7 */ + for (i = 0; i < adapter->num_tx_queues; i++) { + int irq_idx = AL_ETH_TXQ_IRQ_IDX(adapter, i); + + adapter->msix_entries[irq_idx].entry = 3 + + AL_ETH_MAX_HW_QUEUES + i; + adapter->msix_entries[irq_idx].vector = 0; + } + + count = msix_vecs + 2; /* entries start from 2 */ + rc = pci_alloc_msix(adapter->dev, &count); + + if (rc != 0) { + device_printf_dbg(adapter->dev, "failed to allocate MSIX " + "vectors %d\n", msix_vecs+2); + device_printf_dbg(adapter->dev, "ret = %d\n", rc); + goto msix_entries_exit; + } + + if (count != msix_vecs + 2) { + device_printf_dbg(adapter->dev, "failed to allocate all MSIX " + "vectors %d, allocated %d\n", msix_vecs+2, count); + rc = ENOSPC; + goto msix_entries_exit; + } + + for (i = 0; i < msix_vecs; i++) + adapter->msix_entries[i].vector = 2 + 1 + i; + + device_printf_dbg(adapter->dev, "successfully enabled MSIX," + " vectors %d\n", msix_vecs); + + adapter->msix_vecs = msix_vecs; + adapter->flags |= AL_ETH_FLAG_MSIX_ENABLED; + goto exit; + +msix_entries_exit: + adapter->msix_vecs = 0; + free(adapter->msix_entries, M_IFAL); + adapter->msix_entries = NULL; + +exit: + return (rc); +} + +static int +al_eth_setup_int_mode(struct al_eth_adapter *adapter) +{ + int i, rc; + + rc = al_eth_enable_msix(adapter); + if (rc != 0) { + device_printf(adapter->dev, "Failed to enable MSIX mode.\n"); + return (rc); + } + + adapter->irq_vecs = max(1, adapter->msix_vecs); + /* single INTX mode */ + if (adapter->msix_vecs == 0) { + snprintf(adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].name, + AL_ETH_IRQNAME_SIZE, "al-eth-intx-all@pci:%s", + device_get_name(adapter->dev)); + adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].handler = + al_eth_intr_intx_all; + /* IRQ vector will be resolved from device resources */ + adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].vector = 0; + adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].data = adapter; + + device_printf(adapter->dev, "%s and vector %d \n", __func__, + adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].vector); + + return (0); + } + /* single MSI-X mode */ + if (adapter->msix_vecs == 1) { + snprintf(adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].name, + AL_ETH_IRQNAME_SIZE, "al-eth-msix-all@pci:%s", + device_get_name(adapter->dev)); + adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].handler = + al_eth_intr_msix_all; + adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].vector = + adapter->msix_entries[AL_ETH_MGMT_IRQ_IDX].vector; + adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].data = adapter; + + return (0); + } + /* MSI-X per queue */ + snprintf(adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].name, AL_ETH_IRQNAME_SIZE, + "al-eth-msix-mgmt@pci:%s", device_get_name(adapter->dev)); + adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].handler = al_eth_intr_msix_mgmt; + + adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].data = adapter; + adapter->irq_tbl[AL_ETH_MGMT_IRQ_IDX].vector = + adapter->msix_entries[AL_ETH_MGMT_IRQ_IDX].vector; + + for (i = 0; i < adapter->num_rx_queues; i++) { + int irq_idx = AL_ETH_RXQ_IRQ_IDX(adapter, i); + + snprintf(adapter->irq_tbl[irq_idx].name, AL_ETH_IRQNAME_SIZE, + "al-eth-rx-comp-%d@pci:%s", i, + device_get_name(adapter->dev)); + adapter->irq_tbl[irq_idx].handler = al_eth_rx_recv_irq_filter; + adapter->irq_tbl[irq_idx].data = &adapter->rx_ring[i]; + adapter->irq_tbl[irq_idx].vector = + adapter->msix_entries[irq_idx].vector; + } + + for (i = 0; i < adapter->num_tx_queues; i++) { + int irq_idx = AL_ETH_TXQ_IRQ_IDX(adapter, i); + + snprintf(adapter->irq_tbl[irq_idx].name, + AL_ETH_IRQNAME_SIZE, "al-eth-tx-comp-%d@pci:%s", i, + device_get_name(adapter->dev)); + adapter->irq_tbl[irq_idx].handler = al_eth_tx_cmlp_irq_filter; + adapter->irq_tbl[irq_idx].data = &adapter->tx_ring[i]; + adapter->irq_tbl[irq_idx].vector = + adapter->msix_entries[irq_idx].vector; + } + + return (0); +} + +static void +__al_eth_free_irq(struct al_eth_adapter *adapter) +{ + struct al_eth_irq *irq; + int i, rc; + + for (i = 0; i < adapter->irq_vecs; i++) { + irq = &adapter->irq_tbl[i]; + if (irq->requested != 0) { + device_printf_dbg(adapter->dev, "tear down irq: %d\n", + irq->vector); + rc = bus_teardown_intr(adapter->dev, irq->res, + irq->cookie); + if (rc != 0) + device_printf(adapter->dev, "failed to tear " + "down irq: %d\n", irq->vector); + + } + irq->requested = 0; + } +} + +static void +al_eth_free_irq(struct al_eth_adapter *adapter) +{ + struct al_eth_irq *irq; + int i, rc; +#ifdef CONFIG_RFS_ACCEL + if (adapter->msix_vecs >= 1) { + free_irq_cpu_rmap(adapter->netdev->rx_cpu_rmap); + adapter->netdev->rx_cpu_rmap = NULL; + } +#endif + + __al_eth_free_irq(adapter); + + for (i = 0; i < adapter->irq_vecs; i++) { + irq = &adapter->irq_tbl[i]; + if (irq->res == NULL) + continue; + device_printf_dbg(adapter->dev, "release resource irq: %d\n", + irq->vector); + rc = bus_release_resource(adapter->dev, SYS_RES_IRQ, irq->vector, + irq->res); + irq->res = NULL; + if (rc != 0) + device_printf(adapter->dev, "dev has no parent while " + "releasing res for irq: %d\n", irq->vector); + } + + pci_release_msi(adapter->dev); + + adapter->flags &= ~AL_ETH_FLAG_MSIX_ENABLED; + + adapter->msix_vecs = 0; + free(adapter->msix_entries, M_IFAL); + adapter->msix_entries = NULL; +} + +static int +al_eth_request_irq(struct al_eth_adapter *adapter) +{ + unsigned long flags; + struct al_eth_irq *irq; + int rc = 0, i, v; + + if ((adapter->flags & AL_ETH_FLAG_MSIX_ENABLED) != 0) + flags = RF_ACTIVE; + else + flags = RF_ACTIVE | RF_SHAREABLE; + + for (i = 0; i < adapter->irq_vecs; i++) { + irq = &adapter->irq_tbl[i]; + + if (irq->requested != 0) + continue; + + irq->res = bus_alloc_resource_any(adapter->dev, SYS_RES_IRQ, + &irq->vector, flags); + if (irq->res == NULL) { + device_printf(adapter->dev, "could not allocate " + "irq vector=%d\n", irq->vector); + rc = ENXIO; + goto exit_res; + } + + if ((rc = bus_setup_intr(adapter->dev, irq->res, + INTR_TYPE_NET | INTR_MPSAFE, irq->handler, + NULL, irq->data, &irq->cookie)) != 0) { + device_printf(adapter->dev, "failed to register " + "interrupt handler for irq %ju: %d\n", + (uintmax_t)rman_get_start(irq->res), rc); + goto exit_intr; + } + irq->requested = 1; + } + goto exit; + +exit_intr: + v = i - 1; /* -1 because we omit the operation that failed */ + while (v-- >= 0) { + int bti; + irq = &adapter->irq_tbl[v]; + bti = bus_teardown_intr(adapter->dev, irq->res, irq->cookie); + if (bti != 0) { + device_printf(adapter->dev, "failed to tear " + "down irq: %d\n", irq->vector); + } + + irq->requested = 0; + device_printf_dbg(adapter->dev, "exit_intr: releasing irq %d\n", + irq->vector); + } + +exit_res: + v = i - 1; /* -1 because we omit the operation that failed */ + while (v-- >= 0) { + int brr; + irq = &adapter->irq_tbl[v]; + device_printf_dbg(adapter->dev, "exit_res: releasing resource" + " for irq %d\n", irq->vector); + brr = bus_release_resource(adapter->dev, SYS_RES_IRQ, + irq->vector, irq->res); + if (brr != 0) + device_printf(adapter->dev, "dev has no parent while " + "releasing res for irq: %d\n", irq->vector); + irq->res = NULL; + } + +exit: + return (rc); +} + +/** + * al_eth_setup_tx_resources - allocate Tx resources (Descriptors) + * @adapter: network interface device structure + * @qid: queue index + * + * Return 0 on success, negative on failure + **/ +static int +al_eth_setup_tx_resources(struct al_eth_adapter *adapter, int qid) +{ + struct al_eth_ring *tx_ring = &adapter->tx_ring[qid]; + struct device *dev = tx_ring->dev; + struct al_udma_q_params *q_params = &tx_ring->q_params; + int size; + int ret; + + if (adapter->up) + return (0); + + size = sizeof(struct al_eth_tx_buffer) * tx_ring->sw_count; + + tx_ring->tx_buffer_info = malloc(size, M_IFAL, M_ZERO | M_WAITOK); + if (tx_ring->tx_buffer_info == NULL) + return (ENOMEM); + + tx_ring->descs_size = tx_ring->hw_count * sizeof(union al_udma_desc); + q_params->size = tx_ring->hw_count; + + ret = al_dma_alloc_coherent(dev, &q_params->desc_phy_base_tag, + (bus_dmamap_t *)&q_params->desc_phy_base_map, + (bus_addr_t *)&q_params->desc_phy_base, + (void**)&q_params->desc_base, tx_ring->descs_size); + if (ret != 0) { + device_printf(dev, "failed to al_dma_alloc_coherent," + " ret = %d\n", ret); + return (ENOMEM); + } + + if (q_params->desc_base == NULL) + return (ENOMEM); + + device_printf_dbg(dev, "Initializing ring queues %d\n", qid); + + /* Allocate Ring Queue */ + mtx_init(&tx_ring->br_mtx, "AlRingMtx", NULL, MTX_DEF); + tx_ring->br = buf_ring_alloc(AL_BR_SIZE, M_DEVBUF, M_WAITOK, + &tx_ring->br_mtx); + if (tx_ring->br == NULL) { + device_printf(dev, "Critical Failure setting up buf ring\n"); + return (ENOMEM); + } + + /* Allocate taskqueues */ + TASK_INIT(&tx_ring->enqueue_task, 0, al_eth_start_xmit, tx_ring); + tx_ring->enqueue_tq = taskqueue_create_fast("al_tx_enque", M_NOWAIT, + taskqueue_thread_enqueue, &tx_ring->enqueue_tq); + taskqueue_start_threads(&tx_ring->enqueue_tq, 1, PI_NET, "%s txeq", + device_get_nameunit(adapter->dev)); + TASK_INIT(&tx_ring->cmpl_task, 0, al_eth_tx_cmpl_work, tx_ring); + tx_ring->cmpl_tq = taskqueue_create_fast("al_tx_cmpl", M_NOWAIT, + taskqueue_thread_enqueue, &tx_ring->cmpl_tq); + taskqueue_start_threads(&tx_ring->cmpl_tq, 1, PI_REALTIME, "%s txcq", + device_get_nameunit(adapter->dev)); + + /* Setup DMA descriptor areas. */ + ret = bus_dma_tag_create(bus_get_dma_tag(dev), + 1, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + AL_TSO_SIZE, /* maxsize */ + AL_ETH_PKT_MAX_BUFS, /* nsegments */ + PAGE_SIZE, /* maxsegsize */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockfuncarg */ + &tx_ring->dma_buf_tag); + + if (ret != 0) { + device_printf(dev,"Unable to allocate dma_buf_tag, ret = %d\n", + ret); + return (ret); + } + + for (size = 0; size < tx_ring->sw_count; size++) { + ret = bus_dmamap_create(tx_ring->dma_buf_tag, 0, + &tx_ring->tx_buffer_info[size].dma_map); + if (ret != 0) { + device_printf(dev, "Unable to map DMA TX " + "buffer memory [iter=%d]\n", size); + return (ret); + } + } + + /* completion queue not used for tx */ + q_params->cdesc_base = NULL; + /* size in bytes of the udma completion ring descriptor */ + q_params->cdesc_size = 8; + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + + return (0); +} + +/* + * al_eth_free_tx_resources - Free Tx Resources per Queue + * @adapter: network interface device structure + * @qid: queue index + * + * Free all transmit software resources + */ +static void +al_eth_free_tx_resources(struct al_eth_adapter *adapter, int qid) +{ + struct al_eth_ring *tx_ring = &adapter->tx_ring[qid]; + struct al_udma_q_params *q_params = &tx_ring->q_params; + int size; + + /* At this point interrupts' handlers must be deactivated */ + while (taskqueue_cancel(tx_ring->cmpl_tq, &tx_ring->cmpl_task, NULL)) + taskqueue_drain(tx_ring->cmpl_tq, &tx_ring->cmpl_task); + + taskqueue_free(tx_ring->cmpl_tq); + while (taskqueue_cancel(tx_ring->enqueue_tq, + &tx_ring->enqueue_task, NULL)) { + taskqueue_drain(tx_ring->enqueue_tq, &tx_ring->enqueue_task); + } + + taskqueue_free(tx_ring->enqueue_tq); + + if (tx_ring->br != NULL) { + drbr_flush(adapter->netdev, tx_ring->br); + buf_ring_free(tx_ring->br, M_DEVBUF); + } + + for (size = 0; size < tx_ring->sw_count; size++) { + m_freem(tx_ring->tx_buffer_info[size].m); + tx_ring->tx_buffer_info[size].m = NULL; + + bus_dmamap_unload(tx_ring->dma_buf_tag, + tx_ring->tx_buffer_info[size].dma_map); + bus_dmamap_destroy(tx_ring->dma_buf_tag, + tx_ring->tx_buffer_info[size].dma_map); + } + bus_dma_tag_destroy(tx_ring->dma_buf_tag); + + free(tx_ring->tx_buffer_info, M_IFAL); + tx_ring->tx_buffer_info = NULL; + + mtx_destroy(&tx_ring->br_mtx); + + /* if not set, then don't free */ + if (q_params->desc_base == NULL) + return; + + al_dma_free_coherent(q_params->desc_phy_base_tag, + q_params->desc_phy_base_map, q_params->desc_base); + + q_params->desc_base = NULL; +} + +/* + * al_eth_free_all_tx_resources - Free Tx Resources for All Queues + * @adapter: board private structure + * + * Free all transmit software resources + */ +static void +al_eth_free_all_tx_resources(struct al_eth_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + if (adapter->tx_ring[i].q_params.desc_base) + al_eth_free_tx_resources(adapter, i); +} + +/* + * al_eth_setup_rx_resources - allocate Rx resources (Descriptors) + * @adapter: network interface device structure + * @qid: queue index + * + * Returns 0 on success, negative on failure + */ +static int +al_eth_setup_rx_resources(struct al_eth_adapter *adapter, unsigned int qid) +{ + struct al_eth_ring *rx_ring = &adapter->rx_ring[qid]; + struct device *dev = rx_ring->dev; + struct al_udma_q_params *q_params = &rx_ring->q_params; + int size; + int ret; + + size = sizeof(struct al_eth_rx_buffer) * rx_ring->sw_count; + + /* alloc extra element so in rx path we can always prefetch rx_info + 1 */ + size += 1; + + rx_ring->rx_buffer_info = malloc(size, M_IFAL, M_ZERO | M_WAITOK); + if (rx_ring->rx_buffer_info == NULL) + return (ENOMEM); + + rx_ring->descs_size = rx_ring->hw_count * sizeof(union al_udma_desc); + q_params->size = rx_ring->hw_count; + + ret = al_dma_alloc_coherent(dev, &q_params->desc_phy_base_tag, + &q_params->desc_phy_base_map, + (bus_addr_t *)&q_params->desc_phy_base, + (void**)&q_params->desc_base, rx_ring->descs_size); + + if ((q_params->desc_base == NULL) || (ret != 0)) + return (ENOMEM); + + /* size in bytes of the udma completion ring descriptor */ + q_params->cdesc_size = 16; + rx_ring->cdescs_size = rx_ring->hw_count * q_params->cdesc_size; + ret = al_dma_alloc_coherent(dev, &q_params->cdesc_phy_base_tag, + &q_params->cdesc_phy_base_map, + (bus_addr_t *)&q_params->cdesc_phy_base, + (void**)&q_params->cdesc_base, rx_ring->cdescs_size); + + if ((q_params->cdesc_base == NULL) || (ret != 0)) + return (ENOMEM); + + /* Allocate taskqueues */ + TASK_INIT(&rx_ring->enqueue_task, 0, al_eth_rx_recv_work, rx_ring); + rx_ring->enqueue_tq = taskqueue_create_fast("al_rx_enque", M_NOWAIT, + taskqueue_thread_enqueue, &rx_ring->enqueue_tq); + taskqueue_start_threads(&rx_ring->enqueue_tq, 1, PI_NET, "%s rxeq", + device_get_nameunit(adapter->dev)); + + /* Setup DMA descriptor areas. */ + ret = bus_dma_tag_create(bus_get_dma_tag(dev), + 1, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + AL_TSO_SIZE, /* maxsize */ + 1, /* nsegments */ + AL_TSO_SIZE, /* maxsegsize */ + 0, /* flags */ + NULL, /* lockfunc */ + NULL, /* lockfuncarg */ + &rx_ring->dma_buf_tag); + + if (ret != 0) { + device_printf(dev,"Unable to allocate RX dma_buf_tag\n"); + return (ret); + } + + for (size = 0; size < rx_ring->sw_count; size++) { + ret = bus_dmamap_create(rx_ring->dma_buf_tag, 0, + &rx_ring->rx_buffer_info[size].dma_map); + if (ret != 0) { + device_printf(dev,"Unable to map DMA RX buffer memory\n"); + return (ret); + } + } + + /* Zero out the descriptor ring */ + memset(q_params->cdesc_base, 0, rx_ring->cdescs_size); + + /* Create LRO for the ring */ + if ((adapter->netdev->if_capenable & IFCAP_LRO) != 0) { + int err = tcp_lro_init(&rx_ring->lro); + if (err != 0) { + device_printf(adapter->dev, + "LRO[%d] Initialization failed!\n", qid); + } else { + device_printf_dbg(adapter->dev, + "RX Soft LRO[%d] Initialized\n", qid); + rx_ring->lro_enabled = TRUE; + rx_ring->lro.ifp = adapter->netdev; + } + } + + rx_ring->next_to_clean = 0; + rx_ring->next_to_use = 0; + + return (0); +} + +/* + * al_eth_free_rx_resources - Free Rx Resources + * @adapter: network interface device structure + * @qid: queue index + * + * Free all receive software resources + */ +static void +al_eth_free_rx_resources(struct al_eth_adapter *adapter, unsigned int qid) +{ + struct al_eth_ring *rx_ring = &adapter->rx_ring[qid]; + struct al_udma_q_params *q_params = &rx_ring->q_params; + int size; + + /* At this point interrupts' handlers must be deactivated */ + while (taskqueue_cancel(rx_ring->enqueue_tq, + &rx_ring->enqueue_task, NULL)) { + taskqueue_drain(rx_ring->enqueue_tq, &rx_ring->enqueue_task); + } + + taskqueue_free(rx_ring->enqueue_tq); + + for (size = 0; size < rx_ring->sw_count; size++) { + m_freem(rx_ring->rx_buffer_info[size].m); + rx_ring->rx_buffer_info[size].m = NULL; + bus_dmamap_unload(rx_ring->dma_buf_tag, + rx_ring->rx_buffer_info[size].dma_map); + bus_dmamap_destroy(rx_ring->dma_buf_tag, + rx_ring->rx_buffer_info[size].dma_map); + } + bus_dma_tag_destroy(rx_ring->dma_buf_tag); + + free(rx_ring->rx_buffer_info, M_IFAL); + rx_ring->rx_buffer_info = NULL; + + /* if not set, then don't free */ + if (q_params->desc_base == NULL) + return; + + al_dma_free_coherent(q_params->desc_phy_base_tag, + q_params->desc_phy_base_map, q_params->desc_base); + + q_params->desc_base = NULL; + + /* if not set, then don't free */ + if (q_params->cdesc_base == NULL) + return; + + al_dma_free_coherent(q_params->cdesc_phy_base_tag, + q_params->cdesc_phy_base_map, q_params->cdesc_base); + + q_params->cdesc_phy_base = 0; + + /* Free LRO resources */ + tcp_lro_free(&rx_ring->lro); +} + +/* + * al_eth_free_all_rx_resources - Free Rx Resources for All Queues + * @adapter: board private structure + * + * Free all receive software resources + */ +static void +al_eth_free_all_rx_resources(struct al_eth_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_rx_queues; i++) + if (adapter->rx_ring[i].q_params.desc_base != 0) + al_eth_free_rx_resources(adapter, i); +} + +/* + * al_eth_setup_all_rx_resources - allocate all queues Rx resources + * @adapter: board private structure + * + * Return 0 on success, negative on failure + */ +static int +al_eth_setup_all_rx_resources(struct al_eth_adapter *adapter) +{ + int i, rc = 0; + + for (i = 0; i < adapter->num_rx_queues; i++) { + rc = al_eth_setup_rx_resources(adapter, i); + if (rc == 0) + continue; + + device_printf(adapter->dev, "Allocation for Rx Queue %u failed\n", i); + goto err_setup_rx; + } + return (0); + +err_setup_rx: + /* rewind the index freeing the rings as we go */ + while (i--) + al_eth_free_rx_resources(adapter, i); + return (rc); +} + +/* + * al_eth_setup_all_tx_resources - allocate all queues Tx resources + * @adapter: private structure + * + * Return 0 on success, negative on failure + */ +static int +al_eth_setup_all_tx_resources(struct al_eth_adapter *adapter) +{ + int i, rc = 0; + + for (i = 0; i < adapter->num_tx_queues; i++) { + rc = al_eth_setup_tx_resources(adapter, i); + if (rc == 0) + continue; + + device_printf(adapter->dev, + "Allocation for Tx Queue %u failed\n", i); + goto err_setup_tx; + } + + return (0); + +err_setup_tx: + /* rewind the index freeing the rings as we go */ + while (i--) + al_eth_free_tx_resources(adapter, i); + + return (rc); +} + +static void +al_eth_disable_int_sync(struct al_eth_adapter *adapter) +{ + + /* disable forwarding interrupts from eth through pci end point */ + if ((adapter->board_type == ALPINE_FPGA_NIC) || + (adapter->board_type == ALPINE_NIC)) { + al_eth_forward_int_config((uint32_t*)adapter->internal_pcie_base + + AL_REG_OFFSET_FORWARD_INTR, AL_DIS_FORWARD_INTR); + } + + /* mask hw interrupts */ + al_eth_interrupts_mask(adapter); +} + +static void +al_eth_interrupts_unmask(struct al_eth_adapter *adapter) +{ + uint32_t group_a_mask = AL_INT_GROUP_A_GROUP_D_SUM; /* enable group D summery */ + uint32_t group_b_mask = (1 << adapter->num_rx_queues) - 1;/* bit per Rx q*/ + uint32_t group_c_mask = (1 << adapter->num_tx_queues) - 1;/* bit per Tx q*/ + uint32_t group_d_mask = 3 << 8; + struct unit_regs __iomem *regs_base = + (struct unit_regs __iomem *)adapter->udma_base; + + if (adapter->int_mode == AL_IOFIC_MODE_LEGACY) + group_a_mask |= AL_INT_GROUP_A_GROUP_B_SUM | + AL_INT_GROUP_A_GROUP_C_SUM | + AL_INT_GROUP_A_GROUP_D_SUM; + + al_udma_iofic_unmask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, + AL_INT_GROUP_A, group_a_mask); + al_udma_iofic_unmask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, + AL_INT_GROUP_B, group_b_mask); + al_udma_iofic_unmask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, + AL_INT_GROUP_C, group_c_mask); + al_udma_iofic_unmask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, + AL_INT_GROUP_D, group_d_mask); +} + +static void +al_eth_interrupts_mask(struct al_eth_adapter *adapter) +{ + struct unit_regs __iomem *regs_base = + (struct unit_regs __iomem *)adapter->udma_base; + + /* mask all interrupts */ + al_udma_iofic_mask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, + AL_INT_GROUP_A, AL_MASK_GROUP_A_INT); + al_udma_iofic_mask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, + AL_INT_GROUP_B, AL_MASK_GROUP_B_INT); + al_udma_iofic_mask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, + AL_INT_GROUP_C, AL_MASK_GROUP_C_INT); + al_udma_iofic_mask(regs_base, AL_UDMA_IOFIC_LEVEL_PRIMARY, + AL_INT_GROUP_D, AL_MASK_GROUP_D_INT); +} + +static int +al_eth_configure_int_mode(struct al_eth_adapter *adapter) +{ + enum al_iofic_mode int_mode; + uint32_t m2s_errors_disable = AL_M2S_MASK_INIT; + uint32_t m2s_aborts_disable = AL_M2S_MASK_INIT; + uint32_t s2m_errors_disable = AL_S2M_MASK_INIT; + uint32_t s2m_aborts_disable = AL_S2M_MASK_INIT; + + /* single INTX mode */ + if (adapter->msix_vecs == 0) + int_mode = AL_IOFIC_MODE_LEGACY; + else if (adapter->msix_vecs > 1) + int_mode = AL_IOFIC_MODE_MSIX_PER_Q; + else { + device_printf(adapter->dev, + "udma doesn't support single MSI-X mode yet.\n"); + return (EIO); + } + + if (adapter->board_type != ALPINE_INTEGRATED) { + m2s_errors_disable |= AL_M2S_S2M_MASK_NOT_INT; + m2s_errors_disable |= AL_M2S_S2M_MASK_NOT_INT; + s2m_aborts_disable |= AL_M2S_S2M_MASK_NOT_INT; + s2m_aborts_disable |= AL_M2S_S2M_MASK_NOT_INT; + } + + if (al_udma_iofic_config((struct unit_regs __iomem *)adapter->udma_base, + int_mode, m2s_errors_disable, m2s_aborts_disable, + s2m_errors_disable, s2m_aborts_disable)) { + device_printf(adapter->dev, + "al_udma_unit_int_config failed!.\n"); + return (EIO); + } + adapter->int_mode = int_mode; + device_printf_dbg(adapter->dev, "using %s interrupt mode\n", + int_mode == AL_IOFIC_MODE_LEGACY ? "INTx" : + int_mode == AL_IOFIC_MODE_MSIX_PER_Q ? "MSI-X per Queue" : "Unknown"); + /* set interrupt moderation resolution to 15us */ + al_iofic_moder_res_config(&((struct unit_regs *)(adapter->udma_base))->gen.interrupt_regs.main_iofic, AL_INT_GROUP_B, 15); + al_iofic_moder_res_config(&((struct unit_regs *)(adapter->udma_base))->gen.interrupt_regs.main_iofic, AL_INT_GROUP_C, 15); + /* by default interrupt coalescing is disabled */ + adapter->tx_usecs = 0; + adapter->rx_usecs = 0; + + return (0); +} + +/* + * ethtool_rxfh_indir_default - get default value for RX flow hash indirection + * @index: Index in RX flow hash indirection table + * @n_rx_rings: Number of RX rings to use + * + * This function provides the default policy for RX flow hash indirection. + */ +static inline uint32_t +ethtool_rxfh_indir_default(uint32_t index, uint32_t n_rx_rings) +{ + + return (index % n_rx_rings); +} + +static void* +al_eth_update_stats(struct al_eth_adapter *adapter) +{ + struct al_eth_mac_stats *mac_stats = &adapter->mac_stats; + + if (adapter->up == 0) + return (NULL); + + al_eth_mac_stats_get(&adapter->hal_adapter, mac_stats); + + return (NULL); +} + +static uint64_t +al_get_counter(struct ifnet *ifp, ift_counter cnt) +{ + struct al_eth_adapter *adapter; + struct al_eth_mac_stats *mac_stats; + uint64_t rv; + + adapter = if_getsoftc(ifp); + mac_stats = &adapter->mac_stats; + + switch (cnt) { + case IFCOUNTER_IPACKETS: + return (mac_stats->aFramesReceivedOK); /* including pause frames */ + case IFCOUNTER_OPACKETS: + return (mac_stats->aFramesTransmittedOK); + case IFCOUNTER_IBYTES: + return (mac_stats->aOctetsReceivedOK); + case IFCOUNTER_OBYTES: + return (mac_stats->aOctetsTransmittedOK); + case IFCOUNTER_IMCASTS: + return (mac_stats->ifInMulticastPkts); + case IFCOUNTER_OMCASTS: + return (mac_stats->ifOutMulticastPkts); + case IFCOUNTER_COLLISIONS: + return (0); + case IFCOUNTER_IQDROPS: + return (mac_stats->etherStatsDropEvents); + case IFCOUNTER_IERRORS: + rv = mac_stats->ifInErrors + + mac_stats->etherStatsUndersizePkts + /* good but short */ + mac_stats->etherStatsFragments + /* short and bad*/ + mac_stats->etherStatsJabbers + /* with crc errors */ + mac_stats->etherStatsOversizePkts + + mac_stats->aFrameCheckSequenceErrors + + mac_stats->aAlignmentErrors; + return (rv); + case IFCOUNTER_OERRORS: + return (mac_stats->ifOutErrors); + default: + return (if_get_counter_default(ifp, cnt)); + } +} + +/* + * Unicast, Multicast and Promiscuous mode set + * + * The set_rx_mode entry point is called whenever the unicast or multicast + * address lists or the network interface flags are updated. This routine is + * responsible for configuring the hardware for proper unicast, multicast, + * promiscuous mode, and all-multi behavior. + */ +#define MAX_NUM_MULTICAST_ADDRESSES 32 +#define MAX_NUM_ADDRESSES 32 + +static void +al_eth_set_rx_mode(struct al_eth_adapter *adapter) +{ + struct ifnet *ifp = adapter->netdev; + struct ifmultiaddr *ifma; /* multicast addresses configured */ + struct ifaddr *ifua; /* unicast address */ + int mc = 0; + int uc = 0; + uint8_t i; + unsigned char *mac; + + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + if (mc == MAX_NUM_MULTICAST_ADDRESSES) + break; + + mac = LLADDR((struct sockaddr_dl *) ifma->ifma_addr); + /* default mc address inside mac address */ + if (mac[3] != 0 && mac[4] != 0 && mac[5] != 1) + mc++; + } + if_maddr_runlock(ifp); + + if_addr_rlock(ifp); + TAILQ_FOREACH(ifua, &ifp->if_addrhead, ifa_link) { + if (ifua->ifa_addr->sa_family != AF_LINK) + continue; + if (uc == MAX_NUM_ADDRESSES) + break; + uc++; + } + if_addr_runlock(ifp); + + if ((ifp->if_flags & IFF_PROMISC) != 0) { + al_eth_mac_table_promiscuous_set(adapter, true); + } else { + if ((ifp->if_flags & IFF_ALLMULTI) != 0) { + /* This interface is in all-multicasts mode (used by multicast routers). */ + al_eth_mac_table_all_multicast_add(adapter, + AL_ETH_MAC_TABLE_ALL_MULTICAST_IDX, 1); + } else { + if (mc == 0) { + al_eth_mac_table_entry_clear(adapter, + AL_ETH_MAC_TABLE_ALL_MULTICAST_IDX); + } else { + al_eth_mac_table_all_multicast_add(adapter, + AL_ETH_MAC_TABLE_ALL_MULTICAST_IDX, 1); + } + } + if (uc != 0) { + i = AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + 1; + if (uc > AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT) { + /* + * In this case there are more addresses then + * entries in the mac table - set promiscuous + */ + al_eth_mac_table_promiscuous_set(adapter, true); + return; + } + + /* clear the last configuration */ + while (i < (AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + + AL_ETH_MAC_TABLE_UNICAST_MAX_COUNT)) { + al_eth_mac_table_entry_clear(adapter, i); + i++; + } + + /* set new addresses */ + i = AL_ETH_MAC_TABLE_UNICAST_IDX_BASE + 1; + if_addr_rlock(ifp); + TAILQ_FOREACH(ifua, &ifp->if_addrhead, ifa_link) { + if (ifua->ifa_addr->sa_family != AF_LINK) { + continue; + } + al_eth_mac_table_unicast_add(adapter, i, + (unsigned char *)ifua->ifa_addr, 1); + i++; + } + if_addr_runlock(ifp); + + } + al_eth_mac_table_promiscuous_set(adapter, false); + } +} + +static void +al_eth_config_rx_fwd(struct al_eth_adapter *adapter) +{ + struct al_eth_fwd_ctrl_table_entry entry; + int i; + + /* let priority be equal to pbits */ + for (i = 0; i < AL_ETH_FWD_PBITS_TABLE_NUM; i++) + al_eth_fwd_pbits_table_set(&adapter->hal_adapter, i, i); + + /* map priority to queue index, queue id = priority/2 */ + for (i = 0; i < AL_ETH_FWD_PRIO_TABLE_NUM; i++) + al_eth_fwd_priority_table_set(&adapter->hal_adapter, i, i >> 1); + + entry.prio_sel = AL_ETH_CTRL_TABLE_PRIO_SEL_VAL_0; + entry.queue_sel_1 = AL_ETH_CTRL_TABLE_QUEUE_SEL_1_THASH_TABLE; + entry.queue_sel_2 = AL_ETH_CTRL_TABLE_QUEUE_SEL_2_NO_PRIO; + entry.udma_sel = AL_ETH_CTRL_TABLE_UDMA_SEL_MAC_TABLE; + entry.filter = FALSE; + + al_eth_ctrl_table_def_set(&adapter->hal_adapter, FALSE, &entry); + + /* + * By default set the mac table to forward all unicast packets to our + * MAC address and all broadcast. all the rest will be dropped. + */ + al_eth_mac_table_unicast_add(adapter, AL_ETH_MAC_TABLE_UNICAST_IDX_BASE, + adapter->mac_addr, 1); + al_eth_mac_table_broadcast_add(adapter, AL_ETH_MAC_TABLE_BROADCAST_IDX, 1); + al_eth_mac_table_promiscuous_set(adapter, false); + + /* set toeplitz hash keys */ + for (i = 0; i < sizeof(adapter->toeplitz_hash_key); i++) + *((uint8_t*)adapter->toeplitz_hash_key + i) = (uint8_t)random(); + + for (i = 0; i < AL_ETH_RX_HASH_KEY_NUM; i++) + al_eth_hash_key_set(&adapter->hal_adapter, i, + htonl(adapter->toeplitz_hash_key[i])); + + for (i = 0; i < AL_ETH_RX_RSS_TABLE_SIZE; i++) { + adapter->rss_ind_tbl[i] = ethtool_rxfh_indir_default(i, + AL_ETH_NUM_QUEUES); + al_eth_set_thash_table_entry(adapter, i, 0, + adapter->rss_ind_tbl[i]); + } + + al_eth_fsm_table_init(adapter); +} + +static void +al_eth_req_rx_buff_size(struct al_eth_adapter *adapter, int size) +{ + + /* + * Determine the correct mbuf pool + * for doing jumbo frames + * Try from the smallest up to maximum supported + */ + adapter->rx_mbuf_sz = MCLBYTES; + if (size > 2048) { + if (adapter->max_rx_buff_alloc_size > 2048) + adapter->rx_mbuf_sz = MJUMPAGESIZE; + else + return; + } + if (size > 4096) { + if (adapter->max_rx_buff_alloc_size > 4096) + adapter->rx_mbuf_sz = MJUM9BYTES; + else + return; + } + if (size > 9216) { + if (adapter->max_rx_buff_alloc_size > 9216) + adapter->rx_mbuf_sz = MJUM16BYTES; + else + return; + } +} + +static int +al_eth_change_mtu(struct al_eth_adapter *adapter, int new_mtu) +{ + int max_frame = new_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + + ETHER_VLAN_ENCAP_LEN; + + al_eth_req_rx_buff_size(adapter, new_mtu); + + device_printf_dbg(adapter->dev, "set MTU to %d\n", new_mtu); + al_eth_rx_pkt_limit_config(&adapter->hal_adapter, + AL_ETH_MIN_FRAME_LEN, max_frame); + + al_eth_tso_mss_config(&adapter->hal_adapter, 0, new_mtu - 100); + + return (0); +} + +static int +al_eth_check_mtu(struct al_eth_adapter *adapter, int new_mtu) +{ + int max_frame = new_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + ETHER_VLAN_ENCAP_LEN; + + if ((new_mtu < AL_ETH_MIN_FRAME_LEN) || + (max_frame > AL_ETH_MAX_FRAME_LEN)) { + return (EINVAL); + } + + return (0); +} + +static int +al_eth_udma_queue_enable(struct al_eth_adapter *adapter, enum al_udma_type type, + int qid) +{ + int rc = 0; + char *name = (type == UDMA_TX) ? "Tx" : "Rx"; + struct al_udma_q_params *q_params; + + if (type == UDMA_TX) + q_params = &adapter->tx_ring[qid].q_params; + else + q_params = &adapter->rx_ring[qid].q_params; + + rc = al_eth_queue_config(&adapter->hal_adapter, type, qid, q_params); + if (rc < 0) { + device_printf(adapter->dev, "config %s queue %u failed\n", name, + qid); + return (rc); + } + return (rc); +} + +static int +al_eth_udma_queues_enable_all(struct al_eth_adapter *adapter) +{ + int i; + + for (i = 0; i < adapter->num_tx_queues; i++) + al_eth_udma_queue_enable(adapter, UDMA_TX, i); + + for (i = 0; i < adapter->num_rx_queues; i++) + al_eth_udma_queue_enable(adapter, UDMA_RX, i); + + return (0); +} + +static void +al_eth_up_complete(struct al_eth_adapter *adapter) +{ + + al_eth_configure_int_mode(adapter); + al_eth_config_rx_fwd(adapter); + al_eth_change_mtu(adapter, adapter->netdev->if_mtu); + al_eth_udma_queues_enable_all(adapter); + al_eth_refill_all_rx_bufs(adapter); + al_eth_interrupts_unmask(adapter); + + /* enable forwarding interrupts from eth through pci end point */ + if ((adapter->board_type == ALPINE_FPGA_NIC) || + (adapter->board_type == ALPINE_NIC)) { + al_eth_forward_int_config((uint32_t*)adapter->internal_pcie_base + + AL_REG_OFFSET_FORWARD_INTR, AL_EN_FORWARD_INTR); + } + + al_eth_flow_ctrl_enable(adapter); + + mtx_lock(&adapter->stats_mtx); + callout_reset(&adapter->stats_callout, hz, al_tick_stats, (void*)adapter); + mtx_unlock(&adapter->stats_mtx); + + al_eth_mac_start(&adapter->hal_adapter); +} + +static int +al_media_update(struct ifnet *ifp) +{ + struct al_eth_adapter *adapter = ifp->if_softc; + + if ((ifp->if_flags & IFF_UP) != 0) + mii_mediachg(adapter->mii); + + return (0); +} + +static void +al_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct al_eth_adapter *sc = ifp->if_softc; + struct mii_data *mii; + + if (sc->mii == NULL) { + ifmr->ifm_active = IFM_ETHER | IFM_NONE; + ifmr->ifm_status = 0; + + return; + } + + mii = sc->mii; + mii_pollstat(mii); + + ifmr->ifm_active = mii->mii_media_active; + ifmr->ifm_status = mii->mii_media_status; +} + +static void +al_tick(void *arg) +{ + struct al_eth_adapter *adapter = arg; + + mii_tick(adapter->mii); + + /* Schedule another timeout one second from now */ + callout_schedule(&adapter->wd_callout, hz); +} + +static void +al_tick_stats(void *arg) +{ + struct al_eth_adapter *adapter = arg; + + al_eth_update_stats(adapter); + + callout_schedule(&adapter->stats_callout, hz); +} + +static int +al_eth_up(struct al_eth_adapter *adapter) +{ + struct ifnet *ifp = adapter->netdev; + int rc; + + if (adapter->up) + return (0); + + if ((adapter->flags & AL_ETH_FLAG_RESET_REQUESTED) != 0) { + al_eth_function_reset(adapter); + adapter->flags &= ~AL_ETH_FLAG_RESET_REQUESTED; + } + + ifp->if_hwassist = 0; + if ((ifp->if_capenable & IFCAP_TSO) != 0) + ifp->if_hwassist |= CSUM_TSO; + if ((ifp->if_capenable & IFCAP_TXCSUM) != 0) + ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); + if ((ifp->if_capenable & IFCAP_TXCSUM_IPV6) != 0) + ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6); + + al_eth_serdes_init(adapter); + + rc = al_eth_hw_init(adapter); + if (rc != 0) + goto err_hw_init_open; + + rc = al_eth_setup_int_mode(adapter); + if (rc != 0) { + device_printf(adapter->dev, + "%s failed at setup interrupt mode!\n", __func__); + goto err_setup_int; + } + + /* allocate transmit descriptors */ + rc = al_eth_setup_all_tx_resources(adapter); + if (rc != 0) + goto err_setup_tx; + + /* allocate receive descriptors */ + rc = al_eth_setup_all_rx_resources(adapter); + if (rc != 0) + goto err_setup_rx; + + rc = al_eth_request_irq(adapter); + if (rc != 0) + goto err_req_irq; + + al_eth_up_complete(adapter); + + adapter->up = true; + + if (adapter->mac_mode == AL_ETH_MAC_MODE_10GbE_Serial) + adapter->netdev->if_link_state = LINK_STATE_UP; + + if (adapter->mac_mode == AL_ETH_MAC_MODE_RGMII) { + mii_mediachg(adapter->mii); + + /* Schedule watchdog timeout */ + mtx_lock(&adapter->wd_mtx); + callout_reset(&adapter->wd_callout, hz, al_tick, adapter); + mtx_unlock(&adapter->wd_mtx); + + mii_pollstat(adapter->mii); + } + + return (rc); + +err_req_irq: + al_eth_free_all_rx_resources(adapter); +err_setup_rx: + al_eth_free_all_tx_resources(adapter); +err_setup_tx: + al_eth_free_irq(adapter); +err_setup_int: + al_eth_hw_stop(adapter); +err_hw_init_open: + al_eth_function_reset(adapter); + + return (rc); +} + +static int +al_shutdown(device_t dev) +{ + struct al_eth_adapter *adapter = device_get_softc(dev); + + al_eth_down(adapter); + + return (0); +} + +static void +al_eth_down(struct al_eth_adapter *adapter) +{ + + device_printf_dbg(adapter->dev, "al_eth_down: begin\n"); + + adapter->up = false; + + mtx_lock(&adapter->wd_mtx); + callout_stop(&adapter->wd_callout); + mtx_unlock(&adapter->wd_mtx); + + al_eth_disable_int_sync(adapter); + + mtx_lock(&adapter->stats_mtx); + callout_stop(&adapter->stats_callout); + mtx_unlock(&adapter->stats_mtx); + + al_eth_free_irq(adapter); + al_eth_hw_stop(adapter); + + al_eth_free_all_tx_resources(adapter); + al_eth_free_all_rx_resources(adapter); +} + +static int +al_ioctl(struct ifnet *ifp, u_long command, caddr_t data) +{ + struct al_eth_adapter *adapter = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + int error = 0; + + switch (command) { + case SIOCSIFMTU: + { + error = al_eth_check_mtu(adapter, ifr->ifr_mtu); + if (error != 0) { + device_printf(adapter->dev, "ioctl wrong mtu %u\n", + adapter->netdev->if_mtu); + break; + } + + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + adapter->netdev->if_mtu = ifr->ifr_mtu; + al_init(adapter); + break; + } + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP) != 0) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { + if (((ifp->if_flags ^ adapter->if_flags) & + (IFF_PROMISC | IFF_ALLMULTI)) != 0) { + device_printf_dbg(adapter->dev, + "ioctl promisc/allmulti\n"); + al_eth_set_rx_mode(adapter); + } + } else { + error = al_eth_up(adapter); + if (error == 0) + ifp->if_drv_flags |= IFF_DRV_RUNNING; + } + } else { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { + al_eth_down(adapter); + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + } + } + + adapter->if_flags = ifp->if_flags; + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { + device_printf_dbg(adapter->dev, + "ioctl add/del multi before\n"); + al_eth_set_rx_mode(adapter); +#ifdef DEVICE_POLLING + if ((ifp->if_capenable & IFCAP_POLLING) == 0) +#endif + } + break; + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + if (adapter->mii != NULL) + error = ifmedia_ioctl(ifp, ifr, + &adapter->mii->mii_media, command); + else + error = ifmedia_ioctl(ifp, ifr, + &adapter->media, command); + break; + case SIOCSIFCAP: + { + int mask, reinit; + + reinit = 0; + mask = ifr->ifr_reqcap ^ ifp->if_capenable; +#ifdef DEVICE_POLLING + if ((mask & IFCAP_POLLING) != 0) { + if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) { + if (error != 0) + return (error); + ifp->if_capenable |= IFCAP_POLLING; + } else { + error = ether_poll_deregister(ifp); + /* Enable interrupt even in error case */ + ifp->if_capenable &= ~IFCAP_POLLING; + } + } +#endif + if ((mask & IFCAP_HWCSUM) != 0) { + /* apply to both rx and tx */ + ifp->if_capenable ^= IFCAP_HWCSUM; + reinit = 1; + } + if ((mask & IFCAP_HWCSUM_IPV6) != 0) { + ifp->if_capenable ^= IFCAP_HWCSUM_IPV6; + reinit = 1; + } + if ((mask & IFCAP_TSO) != 0) { + ifp->if_capenable ^= IFCAP_TSO; + reinit = 1; + } + if ((mask & IFCAP_LRO) != 0) { + ifp->if_capenable ^= IFCAP_LRO; + } + if ((mask & IFCAP_VLAN_HWTAGGING) != 0) { + ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; + reinit = 1; + } + if ((mask & IFCAP_VLAN_HWFILTER) != 0) { + ifp->if_capenable ^= IFCAP_VLAN_HWFILTER; + reinit = 1; + } + if ((mask & IFCAP_VLAN_HWTSO) != 0) { + ifp->if_capenable ^= IFCAP_VLAN_HWTSO; + reinit = 1; + } + if ((reinit != 0) && + ((ifp->if_drv_flags & IFF_DRV_RUNNING)) != 0) + { + al_init(adapter); + } + break; + } + + default: + error = ether_ioctl(ifp, command, data); + break; + } + + return (error); +} + +static int +al_is_device_supported(device_t dev) +{ + uint16_t pci_vendor_id = pci_get_vendor(dev); + uint16_t pci_device_id = pci_get_device(dev); + + return (pci_vendor_id == PCI_VENDOR_ID_ANNAPURNA_LABS && + (pci_device_id == PCI_DEVICE_ID_AL_ETH || + pci_device_id == PCI_DEVICE_ID_AL_ETH_ADVANCED || + pci_device_id == PCI_DEVICE_ID_AL_ETH_NIC || + pci_device_id == PCI_DEVICE_ID_AL_ETH_FPGA_NIC)); +} + +/* Time in mSec to keep trying to read / write from MDIO in case of error */ +#define MDIO_TIMEOUT_MSEC 100 +#define MDIO_PAUSE_MSEC 10 + +static int +al_miibus_readreg(device_t dev, int phy, int reg) +{ + struct al_eth_adapter *adapter = device_get_softc(dev); + uint16_t value = 0; + int rc; + int timeout = MDIO_TIMEOUT_MSEC; + + while (timeout > 0) { + rc = al_eth_mdio_read(&adapter->hal_adapter, adapter->phy_addr, + -1, reg, &value); + + if (rc == 0) + return (value); + + device_printf_dbg(adapter->dev, + "mdio read failed. try again in 10 msec\n"); + + timeout -= MDIO_PAUSE_MSEC; + pause("readred pause", MDIO_PAUSE_MSEC); + } + + if (rc != 0) + device_printf(adapter->dev, "MDIO read failed on timeout\n"); + + return (value); +} + +static int +al_miibus_writereg(device_t dev, int phy, int reg, int value) +{ + struct al_eth_adapter *adapter = device_get_softc(dev); + int rc; + int timeout = MDIO_TIMEOUT_MSEC; + + while (timeout > 0) { + rc = al_eth_mdio_write(&adapter->hal_adapter, adapter->phy_addr, + -1, reg, value); + + if (rc == 0) + return (0); + + device_printf(adapter->dev, + "mdio write failed. try again in 10 msec\n"); + + timeout -= MDIO_PAUSE_MSEC; + pause("miibus writereg", MDIO_PAUSE_MSEC); + } + + if (rc != 0) + device_printf(adapter->dev, "MDIO write failed on timeout\n"); + + return (rc); +} + +static void +al_miibus_statchg(device_t dev) +{ + struct al_eth_adapter *adapter = device_get_softc(dev); + + device_printf_dbg(adapter->dev, + "al_miibus_statchg: state has changed!\n"); + device_printf_dbg(adapter->dev, + "al_miibus_statchg: active = 0x%x status = 0x%x\n", + adapter->mii->mii_media_active, adapter->mii->mii_media_status); + + if (adapter->up == 0) + return; + + if ((adapter->mii->mii_media_status & IFM_AVALID) != 0) { + if (adapter->mii->mii_media_status & IFM_ACTIVE) { + device_printf(adapter->dev, "link is UP\n"); + adapter->netdev->if_link_state = LINK_STATE_UP; + } else { + device_printf(adapter->dev, "link is DOWN\n"); + adapter->netdev->if_link_state = LINK_STATE_DOWN; + } + } +} + +static void +al_miibus_linkchg(device_t dev) +{ + struct al_eth_adapter *adapter = device_get_softc(dev); + uint8_t duplex = 0; + uint8_t speed = 0; + + if (adapter->mii == 0) + return; + + if ((adapter->netdev->if_flags & IFF_UP) == 0) + return; + + /* Ignore link changes when link is not ready */ + if ((adapter->mii->mii_media_status & (IFM_AVALID | IFM_ACTIVE)) != + (IFM_AVALID | IFM_ACTIVE)) { + return; + } + + if ((adapter->mii->mii_media_active & IFM_FDX) != 0) + duplex = 1; + + speed = IFM_SUBTYPE(adapter->mii->mii_media_active); + + if (speed == IFM_10_T) { + al_eth_mac_link_config(&adapter->hal_adapter, 0, 1, + AL_10BASE_T_SPEED, duplex); + return; + } + + if (speed == IFM_100_TX) { + al_eth_mac_link_config(&adapter->hal_adapter, 0, 1, + AL_100BASE_TX_SPEED, duplex); + return; + } + + if (speed == IFM_1000_T) { + al_eth_mac_link_config(&adapter->hal_adapter, 0, 1, + AL_1000BASE_T_SPEED, duplex); + return; + } + + device_printf(adapter->dev, "ERROR: unknown MII media active 0x%08x\n", + adapter->mii->mii_media_active); +} diff --git a/sys/dev/al_eth/al_eth.h b/sys/dev/al_eth/al_eth.h new file mode 100644 index 000000000000..1f8d4528b545 --- /dev/null +++ b/sys/dev/al_eth/al_eth.h @@ -0,0 +1,366 @@ +/*- + * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates + * All rights reserved. + * + * Developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef __AL_ETH_H__ +#define __AL_ETH_H__ + +#include "al_init_eth_lm.h" +#include "al_hal_eth.h" +#include "al_hal_udma_iofic.h" +#include "al_hal_udma_debug.h" +#include "al_serdes.h" + +enum board_t { + ALPINE_INTEGRATED = 0, + ALPINE_NIC = 1, + ALPINE_FPGA_NIC = 2, +}; + +#define AL_ETH_MAX_HW_QUEUES 4 +#define AL_ETH_NUM_QUEUES 4 +#define AL_ETH_MAX_MSIX_VEC (1 + 2 * AL_ETH_MAX_HW_QUEUES) + +#define AL_ETH_DEFAULT_TX_SW_DESCS (512) +#define AL_ETH_DEFAULT_TX_HW_DESCS (512) +#define AL_ETH_DEFAULT_RX_DESCS (512) + +#if ((AL_ETH_DEFAULT_TX_SW_DESCS / 4) < (AL_ETH_PKT_MAX_BUFS + 2)) +#define AL_ETH_TX_WAKEUP_THRESH (AL_ETH_DEFAULT_TX_SW_DESCS / 4) +#else +#define AL_ETH_TX_WAKEUP_THRESH (AL_ETH_PKT_MAX_BUFS + 2) +#endif + +#define NET_IP_ALIGN 2 +#define AL_ETH_DEFAULT_SMALL_PACKET_LEN (128 - NET_IP_ALIGN) +#define AL_ETH_HEADER_COPY_SIZE (128 - NET_IP_ALIGN) + +#define AL_ETH_DEFAULT_MAX_RX_BUFF_ALLOC_SIZE 9216 +/* + * Minimum the buffer size to 600 to avoid situation the mtu will be changed + * from too little buffer to very big one and then the number of buffer per + * packet could reach the maximum AL_ETH_PKT_MAX_BUFS + */ +#define AL_ETH_DEFAULT_MIN_RX_BUFF_ALLOC_SIZE 600 +#define AL_ETH_DEFAULT_FORCE_1000_BASEX FALSE + +#define AL_ETH_DEFAULT_LINK_POLL_INTERVAL 100 +#define AL_ETH_FIRST_LINK_POLL_INTERVAL 1 + +#define AL_ETH_NAME_MAX_LEN 20 +#define AL_ETH_IRQNAME_SIZE 40 + +#define AL_ETH_DEFAULT_MDIO_FREQ_KHZ 2500 +#define AL_ETH_MDIO_FREQ_1000_KHZ 1000 + +struct al_eth_irq { + driver_filter_t *handler; + void *data; + unsigned int vector; + uint8_t requested; + char name[AL_ETH_IRQNAME_SIZE]; + struct resource *res; + void *cookie; +}; + +struct al_eth_tx_buffer { + struct mbuf *m; + struct al_eth_pkt hal_pkt; + bus_dmamap_t dma_map; + unsigned int tx_descs; +}; + +struct al_eth_rx_buffer { + struct mbuf *m; + unsigned int data_size; + bus_dmamap_t dma_map; + struct al_buf al_buf; +}; + +struct al_eth_ring { + device_t dev; + struct al_eth_adapter *adapter; + /* Used to get rx packets from hal */ + struct al_eth_pkt hal_pkt; + /* Udma queue handler */ + struct al_udma_q *dma_q; + uint32_t ring_id; + uint16_t next_to_use; + uint16_t next_to_clean; + /* The offset of the interrupt unmask register */ + uint32_t *unmask_reg_offset; + /* + * The value to write to the above register to + * unmask the interrupt of this ring + */ + uint32_t unmask_val; + struct al_eth_meta_data hal_meta; + /* Contex of tx packet */ + struct al_eth_tx_buffer *tx_buffer_info; + /* Contex of rx packet */ + struct al_eth_rx_buffer *rx_buffer_info; + /* Number of tx/rx_buffer_info's entries */ + int sw_count; + /* Number of hw descriptors */ + int hw_count; + /* Size (in bytes) of hw descriptors */ + size_t descs_size; + /* Size (in bytes) of hw completion descriptors, used for rx */ + size_t cdescs_size; + struct ifnet *netdev; + struct al_udma_q_params q_params; + struct buf_ring *br; + struct mtx br_mtx; + struct task enqueue_task; + struct taskqueue *enqueue_tq; + volatile uint32_t enqueue_is_running; + struct task cmpl_task; + struct taskqueue *cmpl_tq; + volatile uint32_t cmpl_is_running; + uint32_t lro_enabled; + struct lro_ctrl lro; + bus_dma_tag_t dma_buf_tag; + volatile uint32_t stall; +}; + +#define AL_ETH_TX_RING_IDX_NEXT(tx_ring, idx) (((idx) + 1) & (AL_ETH_DEFAULT_TX_SW_DESCS - 1)) + +#define AL_ETH_RX_RING_IDX_NEXT(rx_ring, idx) (((idx) + 1) & (AL_ETH_DEFAULT_RX_DESCS - 1)) +#define AL_ETH_RX_RING_IDX_ADD(rx_ring, idx, n) (((idx) + (n)) & (AL_ETH_DEFAULT_RX_DESCS - 1)) + +/* flow control configuration */ +#define AL_ETH_FLOW_CTRL_RX_FIFO_TH_HIGH 0x160 +#define AL_ETH_FLOW_CTRL_RX_FIFO_TH_LOW 0x90 +#define AL_ETH_FLOW_CTRL_QUANTA 0xffff +#define AL_ETH_FLOW_CTRL_QUANTA_TH 0x8000 + +#define AL_ETH_FLOW_CTRL_AUTONEG 1 +#define AL_ETH_FLOW_CTRL_RX_PAUSE 2 +#define AL_ETH_FLOW_CTRL_TX_PAUSE 4 + +/* link configuration for 1G port */ +struct al_eth_link_config { + int old_link; + /* Describes what we actually have. */ + int active_duplex; + int active_speed; + + /* current flow control status */ + uint8_t flow_ctrl_active; + /* supported configuration (can be changed from ethtool) */ + uint8_t flow_ctrl_supported; + + /* the following are not relevant to RGMII */ + boolean_t force_1000_base_x; + boolean_t autoneg; +}; + +/* SFP detection event */ +enum al_eth_sfp_detect_evt { + /* No change (no connect, disconnect, or new SFP module */ + AL_ETH_SFP_DETECT_EVT_NO_CHANGE, + /* SFP module connected */ + AL_ETH_SFP_DETECT_EVT_CONNECTED, + /* SFP module disconnected */ + AL_ETH_SFP_DETECT_EVT_DISCONNECTED, + /* SFP module replaced */ + AL_ETH_SFP_DETECT_EVT_CHANGED, +}; + +/* SFP detection status */ +struct al_eth_sfp_detect_stat { + /* Status is valid (i.e. rest of fields are valid) */ + boolean_t valid; + boolean_t connected; + uint8_t sfp_10g; + uint8_t sfp_1g; + uint8_t sfp_cable_tech; + boolean_t lt_en; + boolean_t an_en; + enum al_eth_mac_mode mac_mode; +}; + +struct al_eth_retimer_params { + boolean_t exist; + uint8_t bus_id; + uint8_t i2c_addr; + enum al_eth_retimer_channel channel; +}; + +struct msix_entry { + int entry; + int vector; +}; + +/* board specific private data structure */ +struct al_eth_adapter { + enum board_t board_type; + device_t miibus; + struct mii_data *mii; + uint16_t dev_id; + uint8_t rev_id; + + device_t dev; + struct ifnet *netdev; + struct ifmedia media; + struct resource *udma_res; + struct resource *mac_res; + struct resource *ec_res; + int if_flags; + struct callout wd_callout; + struct mtx wd_mtx; + struct callout stats_callout; + struct mtx stats_mtx; + + /* this is for intx mode */ + void *irq_cookie; + struct resource *irq_res; + + /* + * Some features need tri-state capability, + * thus the additional *_CAPABLE flags. + */ + uint32_t flags; +#define AL_ETH_FLAG_MSIX_CAPABLE (uint32_t)(1 << 1) +#define AL_ETH_FLAG_MSIX_ENABLED (uint32_t)(1 << 2) +#define AL_ETH_FLAG_IN_NETPOLL (uint32_t)(1 << 3) +#define AL_ETH_FLAG_MQ_CAPABLE (uint32_t)(1 << 4) +#define AL_ETH_FLAG_SRIOV_CAPABLE (uint32_t)(1 << 5) +#define AL_ETH_FLAG_SRIOV_ENABLED (uint32_t)(1 << 6) +#define AL_ETH_FLAG_RESET_REQUESTED (uint32_t)(1 << 7) + + struct al_hal_eth_adapter hal_adapter; + + /* + * Rx packets that shorter that this len will be copied to the mbuf + */ + unsigned int small_copy_len; + + /* Maximum size for rx buffer */ + unsigned int max_rx_buff_alloc_size; + uint32_t rx_mbuf_sz; + + /* Tx fast path data */ + int num_tx_queues; + + /* Rx fast path data */ + int num_rx_queues; + + /* TX */ + struct al_eth_ring tx_ring[AL_ETH_NUM_QUEUES]; + + /* RX */ + struct al_eth_ring rx_ring[AL_ETH_NUM_QUEUES]; + + enum al_iofic_mode int_mode; + +#define AL_ETH_MGMT_IRQ_IDX 0 +#define AL_ETH_RXQ_IRQ_IDX(adapter, q) (1 + (q)) +#define AL_ETH_TXQ_IRQ_IDX(adapter, q) (1 + (adapter)->num_rx_queues + (q)) + struct al_eth_irq irq_tbl[AL_ETH_MAX_MSIX_VEC]; + struct msix_entry *msix_entries; + int msix_vecs; + int irq_vecs; + + unsigned int tx_usecs, rx_usecs; /* interrupt coalescing */ + + unsigned int tx_ring_count; + unsigned int tx_descs_count; + unsigned int rx_ring_count; + unsigned int rx_descs_count; + + /* RSS */ + uint32_t toeplitz_hash_key[AL_ETH_RX_HASH_KEY_NUM]; +#define AL_ETH_RX_RSS_TABLE_SIZE AL_ETH_RX_THASH_TABLE_SIZE + uint8_t rss_ind_tbl[AL_ETH_RX_RSS_TABLE_SIZE]; + + uint32_t msg_enable; + struct al_eth_mac_stats mac_stats; + + enum al_eth_mac_mode mac_mode; + boolean_t mac_mode_set; /* Relevant only when 'auto_speed' is set */ + uint8_t mac_addr[ETHER_ADDR_LEN]; + /* mdio and phy*/ + boolean_t phy_exist; + struct mii_bus *mdio_bus; + struct phy_device *phydev; + uint8_t phy_addr; + struct al_eth_link_config link_config; + + /* HAL layer data */ + int id_number; + char name[AL_ETH_NAME_MAX_LEN]; + void *internal_pcie_base; /* use for ALPINE_NIC devices */ + void *udma_base; + void *ec_base; + void *mac_base; + + struct al_eth_flow_control_params flow_ctrl_params; + + struct al_eth_adapter_params eth_hal_params; + + struct task link_status_task; + uint32_t link_poll_interval; /* task interval in mSec */ + + boolean_t serdes_init; + struct al_serdes_grp_obj serdes_obj; + uint8_t serdes_grp; + uint8_t serdes_lane; + + boolean_t an_en; /* run kr auto-negotiation */ + boolean_t lt_en; /* run kr link-training */ + + boolean_t sfp_detection_needed; /* true if need to run sfp detection */ + boolean_t auto_speed; /* true if allowed to change SerDes speed configuration */ + uint8_t i2c_adapter_id; /* identifier for the i2c adapter to use to access SFP+ module */ + enum al_eth_ref_clk_freq ref_clk_freq; /* reference clock frequency */ + unsigned int mdio_freq; /* MDIO frequency [Khz] */ + + boolean_t up; + + boolean_t last_link; + boolean_t last_establish_failed; + struct al_eth_lm_context lm_context; + boolean_t use_lm; + + boolean_t dont_override_serdes; /* avoid overriding serdes parameters + to preset static values */ + struct mtx serdes_config_lock; + struct mtx if_rx_lock; + + uint32_t wol; + + struct al_eth_retimer_params retimer; + + bool phy_fixup_needed; + + enum al_eth_lm_max_speed max_speed; +}; + +#endif /* !(AL_ETH_H) */ diff --git a/sys/dev/al_eth/al_init_eth_kr.c b/sys/dev/al_eth/al_init_eth_kr.c new file mode 100644 index 000000000000..ee8a4914189d --- /dev/null +++ b/sys/dev/al_eth/al_init_eth_kr.c @@ -0,0 +1,841 @@ +/*- + * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates + * All rights reserved. + * + * Developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "al_init_eth_kr.h" +#include "al_serdes.h" + +/** + * Ethernet + * @{ + * @file al_init_eth_kr.c + * + * @brief auto-negotiation and link training algorithms and state machines + * + * The link training algorithm implemented in this file going over the + * coefficients and looking for the best eye measurement possible for every one + * of them. it's using state machine to move between the different states. + * the state machine has 3 parts: + * - preparation - waiting till the link partner (lp) will be ready and + * change his state to preset. + * - measurement (per coefficient) - issue decrement for the coefficient + * under control till the eye measurement not increasing + * and remains in the optimum. + * - completion - indicate the receiver is ready and wait for the lp to + * finish his work. + */ + +/* TODO: fix with more reasonable numbers */ +/* timeout in mSec before auto-negotiation will be terminated */ +#define AL_ETH_KR_AN_TIMEOUT (500) +#define AL_ETH_KR_EYE_MEASURE_TIMEOUT (100) +/* timeout in uSec before the process will be terminated */ +#define AL_ETH_KR_FRAME_LOCK_TIMEOUT (500 * 1000) +#define AL_ETH_KR_LT_DONE_TIMEOUT (500 * 1000) +/* number of times the receiver and transmitter tasks will be called before the + * algorithm will be terminated */ +#define AL_ETH_KR_LT_MAX_ROUNDS (50000) + +/* mac algorithm state machine */ +enum al_eth_kr_mac_lt_state { + TX_INIT = 0, /* start of all */ + WAIT_BEGIN, /* wait for initial training lock */ + DO_PRESET, /* issue PRESET to link partner */ + DO_HOLD, /* issue HOLD to link partner */ + /* preparation is done, start testing the coefficient. */ + QMEASURE, /* EyeQ measurement. */ + QCHECK, /* Check if measurement shows best value. */ + DO_NEXT_TRY, /* issue DEC command to coeff for next measurement. */ + END_STEPS, /* perform last steps to go back to optimum. */ + END_STEPS_HOLD, /* perform last steps HOLD command. */ + COEFF_DONE, /* done with the current coefficient updates. + * Check if another should be done. */ + /* end of training to all coefficients */ + SET_READY, /* indicate local receiver ready */ + TX_DONE /* transmit process completed, training can end. */ +}; + +static const char * const al_eth_kr_mac_sm_name[] = { + "TX_INIT", "WAIT_BEGIN", "DO_PRESET", + "DO_HOLD", "QMEASURE", "QCHECK", + "DO_NEXT_TRY", "END_STEPS", "END_STEPS_HOLD", + "COEFF_DONE", "SET_READY", "TX_DONE" +}; + +/* Constants used for the measurement. */ +enum al_eth_kr_coef { + AL_ETH_KR_COEF_C_MINUS, + AL_ETH_KR_COEF_C_ZERO, + AL_ETH_KR_COEF_C_PLUS, +}; + +/* + * test coefficients from COEFF_TO_MANIPULATE to COEFF_TO_MANIPULATE_LAST. + */ +#define COEFF_TO_MANIPULATE AL_ETH_KR_COEF_C_MINUS +#define COEFF_TO_MANIPULATE_LAST AL_ETH_KR_COEF_C_MINUS +#define QARRAY_SIZE 3 /**< how many entries we want in our history array. */ + +struct al_eth_kr_data { + struct al_hal_eth_adapter *adapter; + struct al_serdes_grp_obj *serdes_obj; + enum al_serdes_lane lane; + + /* Receiver side data */ + struct al_eth_kr_status_report_data status_report; /* report to response */ + struct al_eth_kr_coef_up_data last_lpcoeff; /* last coeff received */ + + /* Transmitter side data */ + enum al_eth_kr_mac_lt_state algo_state; /* Statemachine. */ + unsigned int qarray[QARRAY_SIZE]; /* EyeQ measurements history */ + /* How many entries in the array are valid for compares yet. */ + unsigned int qarray_cnt; + enum al_eth_kr_coef curr_coeff; + /* + * Status of coefficient during the last + * DEC/INC command (before issuing HOLD again). + */ + unsigned int coeff_status_step; + unsigned int end_steps_cnt; /* Number of end steps needed */ +}; + +static int +al_eth_kr_an_run(struct al_eth_kr_data *kr_data, struct al_eth_an_adv *an_adv, + struct al_eth_an_adv *an_partner_adv) +{ + int rc; + boolean_t page_received = FALSE; + boolean_t an_completed = FALSE; + boolean_t error = FALSE; + int timeout = AL_ETH_KR_AN_TIMEOUT; + + rc = al_eth_kr_an_init(kr_data->adapter, an_adv); + if (rc != 0) { + al_err("%s %s autonegotiation init failed\n", + kr_data->adapter->name, __func__); + return (rc); + } + + rc = al_eth_kr_an_start(kr_data->adapter, AL_ETH_AN__LT_LANE_0, + FALSE, TRUE); + if (rc != 0) { + al_err("%s %s autonegotiation enable failed\n", + kr_data->adapter->name, __func__); + return (rc); + } + + do { + DELAY(10000); + timeout -= 10; + if (timeout <= 0) { + al_info("%s %s autonegotiation failed on timeout\n", + kr_data->adapter->name, __func__); + + return (ETIMEDOUT); + } + + al_eth_kr_an_status_check(kr_data->adapter, &page_received, + &an_completed, &error); + } while (page_received == FALSE); + + if (error != 0) { + al_info("%s %s autonegotiation failed (status error)\n", + kr_data->adapter->name, __func__); + + return (EIO); + } + + al_eth_kr_an_read_adv(kr_data->adapter, an_partner_adv); + + al_dbg("%s %s autonegotiation completed. error = %d\n", + kr_data->adapter->name, __func__, error); + + return (0); +} + +/***************************** receiver side *********************************/ +static enum al_eth_kr_cl72_cstate +al_eth_lt_coeff_set(struct al_eth_kr_data *kr_data, + enum al_serdes_tx_deemph_param param, uint32_t op) +{ + enum al_eth_kr_cl72_cstate status = 0; + + switch (op) { + case AL_PHY_KR_COEF_UP_HOLD: + /* no need to update the serdes - return not updated*/ + status = C72_CSTATE_NOT_UPDATED; + break; + case AL_PHY_KR_COEF_UP_INC: + status = C72_CSTATE_UPDATED; + + if (kr_data->serdes_obj->tx_deemph_inc( + kr_data->serdes_obj, + kr_data->lane, + param) == 0) + status = C72_CSTATE_MAX; + break; + case AL_PHY_KR_COEF_UP_DEC: + status = C72_CSTATE_UPDATED; + + if (kr_data->serdes_obj->tx_deemph_dec( + kr_data->serdes_obj, + kr_data->lane, + param) == 0) + status = C72_CSTATE_MIN; + break; + default: /* 3=reserved */ + break; + } + + return (status); +} + +/* + * Inspect the received coefficient update request and update all coefficients + * in the serdes accordingly. + */ +static void +al_eth_coeff_req_handle(struct al_eth_kr_data *kr_data, + struct al_eth_kr_coef_up_data *lpcoeff) +{ + struct al_eth_kr_status_report_data *report = &kr_data->status_report; + + /* First check for Init and Preset commands. */ + if ((lpcoeff->preset != 0) || (lpcoeff->initialize) != 0) { + kr_data->serdes_obj->tx_deemph_preset( + kr_data->serdes_obj, + kr_data->lane); + + /* + * in case of preset c(0) should be set to maximum and both c(1) + * and c(-1) should be updated + */ + report->c_minus = C72_CSTATE_UPDATED; + + report->c_plus = C72_CSTATE_UPDATED; + + report->c_zero = C72_CSTATE_MAX; + + return; + } + + /* + * in case preset and initialize are false need to perform per + * coefficient action. + */ + report->c_minus = al_eth_lt_coeff_set(kr_data, + AL_SERDES_TX_DEEMP_C_MINUS, lpcoeff->c_minus); + + report->c_zero = al_eth_lt_coeff_set(kr_data, + AL_SERDES_TX_DEEMP_C_ZERO, lpcoeff->c_zero); + + report->c_plus = al_eth_lt_coeff_set(kr_data, + AL_SERDES_TX_DEEMP_C_PLUS, lpcoeff->c_plus); + + al_dbg("%s: c(0) = 0x%x c(-1) = 0x%x c(1) = 0x%x\n", + __func__, report->c_zero, report->c_plus, report->c_minus); +} + +static void +al_eth_kr_lt_receiver_task_init(struct al_eth_kr_data *kr_data) +{ + + al_memset(&kr_data->last_lpcoeff, 0, + sizeof(struct al_eth_kr_coef_up_data)); + al_memset(&kr_data->status_report, 0, + sizeof(struct al_eth_kr_status_report_data)); +} + +static boolean_t +al_eth_lp_coeff_up_change(struct al_eth_kr_data *kr_data, + struct al_eth_kr_coef_up_data *lpcoeff) +{ + struct al_eth_kr_coef_up_data *last_lpcoeff = &kr_data->last_lpcoeff; + + if (al_memcmp(last_lpcoeff, lpcoeff, + sizeof(struct al_eth_kr_coef_up_data)) == 0) { + return (FALSE); + } + + al_memcpy(last_lpcoeff, lpcoeff, sizeof(struct al_eth_kr_coef_up_data)); + + return (TRUE); +} + +/* + * Run the receiver task for one cycle. + * The receiver task continuously inspects the received coefficient update + * requests and acts upon. + * + * @return <0 if error occur + */ +static int +al_eth_kr_lt_receiver_task_run(struct al_eth_kr_data *kr_data) +{ + struct al_eth_kr_coef_up_data new_lpcoeff; + + /* + * First inspect status of the link. It may have dropped frame lock as + * the remote did some reconfiguration of its serdes. + * Then we simply have nothing to do and return immediately as caller + * will call us continuously until lock comes back. + */ + + if (al_eth_kr_receiver_frame_lock_get(kr_data->adapter, + AL_ETH_AN__LT_LANE_0) != 0) { + return (0); + } + + /* check if a new update command was received */ + al_eth_lp_coeff_up_get(kr_data->adapter, + AL_ETH_AN__LT_LANE_0, &new_lpcoeff); + + if (al_eth_lp_coeff_up_change(kr_data, &new_lpcoeff) != 0) { + /* got some new coefficient update request. */ + al_eth_coeff_req_handle(kr_data, &new_lpcoeff); + } + + return (0); +} + +/******************************** transmitter side ***************************/ +static int +al_eth_kr_lt_transmitter_task_init(struct al_eth_kr_data *kr_data) +{ + int i; + int rc; + unsigned int temp_val; + + for (i = 0; i < QARRAY_SIZE; i++) + kr_data->qarray[i] = 0; + + kr_data->qarray_cnt = 0; + kr_data->algo_state = TX_INIT; + kr_data->curr_coeff = COEFF_TO_MANIPULATE; /* first coeff to test. */ + kr_data->coeff_status_step = C72_CSTATE_NOT_UPDATED; + kr_data->end_steps_cnt = QARRAY_SIZE-1; /* go back to first entry */ + + /* + * Perform measure eye here to run the rx equalizer + * for the first time to get init values + */ + rc = kr_data->serdes_obj->eye_measure_run( + kr_data->serdes_obj, + kr_data->lane, + AL_ETH_KR_EYE_MEASURE_TIMEOUT, + &temp_val); + if (rc != 0) { + al_warn("%s: Failed to run Rx equalizer (rc = 0x%x)\n", + __func__, rc); + + return (rc); + } + + return (0); +} + +static boolean_t +al_eth_kr_lt_all_not_updated(struct al_eth_kr_status_report_data *report) +{ + + if ((report->c_zero == C72_CSTATE_NOT_UPDATED) && + (report->c_minus == C72_CSTATE_NOT_UPDATED) && + (report->c_plus == C72_CSTATE_NOT_UPDATED)) { + return (TRUE); + } + + return (FALSE); +} + +static void +al_eth_kr_lt_coef_set(struct al_eth_kr_coef_up_data *ldcoeff, + enum al_eth_kr_coef coef, enum al_eth_kr_cl72_coef_op op) +{ + + switch (coef) { + case AL_ETH_KR_COEF_C_MINUS: + ldcoeff->c_minus = op; + break; + case AL_ETH_KR_COEF_C_PLUS: + ldcoeff->c_plus = op; + break; + case AL_ETH_KR_COEF_C_ZERO: + ldcoeff->c_zero = op; + break; + } +} + +static enum al_eth_kr_cl72_cstate +al_eth_kr_lt_coef_report_get(struct al_eth_kr_status_report_data *report, + enum al_eth_kr_coef coef) +{ + + switch (coef) { + case AL_ETH_KR_COEF_C_MINUS: + return (report->c_minus); + case AL_ETH_KR_COEF_C_PLUS: + return (report->c_plus); + case AL_ETH_KR_COEF_C_ZERO: + return (report->c_zero); + } + + return (0); +} + +/* + * Run the transmitter_task for one cycle. + * + * @return <0 if error occurs + */ +static int +al_eth_kr_lt_transmitter_task_run(struct al_eth_kr_data *kr_data) +{ + struct al_eth_kr_status_report_data report; + unsigned int coeff_status_cur; + struct al_eth_kr_coef_up_data ldcoeff = { 0, 0, 0, 0, 0 }; + unsigned int val; + int i; + enum al_eth_kr_mac_lt_state nextstate; + int rc = 0; + + /* + * do nothing if currently there is no frame lock (which may happen + * when remote updates its analogs). + */ + if (al_eth_kr_receiver_frame_lock_get(kr_data->adapter, + AL_ETH_AN__LT_LANE_0) == 0) { + return (0); + } + + al_eth_lp_status_report_get(kr_data->adapter, + AL_ETH_AN__LT_LANE_0, &report); + + /* extract curr status of the coefficient in use */ + coeff_status_cur = al_eth_kr_lt_coef_report_get(&report, + kr_data->curr_coeff); + + nextstate = kr_data->algo_state; /* default we stay in curr state; */ + + switch (kr_data->algo_state) { + case TX_INIT: + /* waiting for start */ + if (al_eth_kr_startup_proto_prog_get(kr_data->adapter, + AL_ETH_AN__LT_LANE_0) != 0) { + /* training is on and frame lock */ + nextstate = WAIT_BEGIN; + } + break; + case WAIT_BEGIN: + kr_data->qarray_cnt = 0; + kr_data->curr_coeff = COEFF_TO_MANIPULATE; + kr_data->coeff_status_step = C72_CSTATE_NOT_UPDATED; + coeff_status_cur = C72_CSTATE_NOT_UPDATED; + kr_data->end_steps_cnt = QARRAY_SIZE-1; + + /* Wait for not_updated for all coefficients from remote */ + if (al_eth_kr_lt_all_not_updated(&report) != 0) { + ldcoeff.preset = TRUE; + nextstate = DO_PRESET; + } + break; + case DO_PRESET: + /* + * Send PRESET and wait for for updated for all + * coefficients from remote + */ + if (al_eth_kr_lt_all_not_updated(&report) == 0) + nextstate = DO_HOLD; + else /* as long as the lp didn't response to the preset + * we should continue sending it */ + ldcoeff.preset = TRUE; + break; + case DO_HOLD: + /* + * clear the PRESET, issue HOLD command and wait for + * hold handshake + */ + if (al_eth_kr_lt_all_not_updated(&report) != 0) + nextstate = QMEASURE; + break; + + case QMEASURE: + /* makes a measurement and fills the new value into the array */ + rc = kr_data->serdes_obj->eye_measure_run( + kr_data->serdes_obj, + kr_data->lane, + AL_ETH_KR_EYE_MEASURE_TIMEOUT, + &val); + if (rc != 0) { + al_warn("%s: Rx eye measurement failed\n", __func__); + + return (rc); + } + + al_dbg("%s: Rx Measure eye returned 0x%x\n", __func__, val); + + /* put the new value into the array at the top. */ + for (i = 0; i < QARRAY_SIZE-1; i++) + kr_data->qarray[i] = kr_data->qarray[i+1]; + + kr_data->qarray[QARRAY_SIZE-1] = val; + + if (kr_data->qarray_cnt < QARRAY_SIZE) + kr_data->qarray_cnt++; + + nextstate = QCHECK; + break; + case QCHECK: + /* check if we reached the best link quality yet. */ + if (kr_data->qarray_cnt < QARRAY_SIZE) { + /* keep going until at least the history is + * filled. check that we can keep going or if + * coefficient has already reached minimum. + */ + + if (kr_data->coeff_status_step == C72_CSTATE_MIN) + nextstate = COEFF_DONE; + else { + /* + * request a DECREMENT of the + * coefficient under control + */ + al_eth_kr_lt_coef_set(&ldcoeff, + kr_data->curr_coeff, AL_PHY_KR_COEF_UP_DEC); + + nextstate = DO_NEXT_TRY; + } + } else { + /* + * check if current value and last both are worse than + * the 2nd last. This we take as an ending condition + * assuming the minimum was reached two tries before + * so we will now go back to that point. + */ + if ((kr_data->qarray[0] < kr_data->qarray[1]) && + (kr_data->qarray[0] < kr_data->qarray[2])) { + /* + * request a INCREMENT of the + * coefficient under control + */ + al_eth_kr_lt_coef_set(&ldcoeff, + kr_data->curr_coeff, AL_PHY_KR_COEF_UP_INC); + + /* start going back to the maximum */ + nextstate = END_STEPS; + if (kr_data->end_steps_cnt > 0) + kr_data->end_steps_cnt--; + } else { + if (kr_data->coeff_status_step == + C72_CSTATE_MIN) { + nextstate = COEFF_DONE; + } else { + /* + * request a DECREMENT of the + * coefficient under control + */ + al_eth_kr_lt_coef_set(&ldcoeff, + kr_data->curr_coeff, + AL_PHY_KR_COEF_UP_DEC); + + nextstate = DO_NEXT_TRY; + } + } + } + break; + case DO_NEXT_TRY: + /* + * save the status when we issue the DEC step to the remote, + * before the HOLD is done again. + */ + kr_data->coeff_status_step = coeff_status_cur; + + if (coeff_status_cur != C72_CSTATE_NOT_UPDATED) + nextstate = DO_HOLD; /* go to next measurement round */ + else + al_eth_kr_lt_coef_set(&ldcoeff, + kr_data->curr_coeff, AL_PHY_KR_COEF_UP_DEC); + break; + /* + * Coefficient iteration completed, go back to the optimum step + * In this algorithm we assume 2 before curr was best hence need to do + * two INC runs. + */ + case END_STEPS: + if (coeff_status_cur != C72_CSTATE_NOT_UPDATED) + nextstate = END_STEPS_HOLD; + else + al_eth_kr_lt_coef_set(&ldcoeff, + kr_data->curr_coeff, AL_PHY_KR_COEF_UP_INC); + break; + case END_STEPS_HOLD: + if (coeff_status_cur == C72_CSTATE_NOT_UPDATED) { + if (kr_data->end_steps_cnt != 0) { + /* + * request a INCREMENT of the + * coefficient under control + */ + al_eth_kr_lt_coef_set(&ldcoeff, + kr_data->curr_coeff, AL_PHY_KR_COEF_UP_INC); + + /* go 2nd time - dec the end step count */ + nextstate = END_STEPS; + + if (kr_data->end_steps_cnt > 0) + kr_data->end_steps_cnt--; + + } else { + nextstate = COEFF_DONE; + } + } + break; + case COEFF_DONE: + /* + * now this coefficient is done. + * We can now either choose to finish here, + * or keep going with another coefficient. + */ + if ((int)kr_data->curr_coeff < COEFF_TO_MANIPULATE_LAST) { + int i; + + for (i = 0; i < QARRAY_SIZE; i++) + kr_data->qarray[i] = 0; + + kr_data->qarray_cnt = 0; + kr_data->end_steps_cnt = QARRAY_SIZE-1; + kr_data->coeff_status_step = C72_CSTATE_NOT_UPDATED; + kr_data->curr_coeff++; + + al_dbg("[%s]: doing next coefficient: %d ---\n\n", + kr_data->adapter->name, kr_data->curr_coeff); + + nextstate = QMEASURE; + } else { + nextstate = SET_READY; + } + break; + case SET_READY: + /* + * our receiver is ready for data. + * no training will occur any more. + */ + kr_data->status_report.receiver_ready = TRUE; + /* + * in addition to the status we transmit, we also must tell our + * local hardware state-machine that we are done, so the + * training can eventually complete when the remote indicates + * it is ready also. The hardware will then automatically + * give control to the PCS layer completing training. + */ + al_eth_receiver_ready_set(kr_data->adapter, + AL_ETH_AN__LT_LANE_0); + + nextstate = TX_DONE; + break; + case TX_DONE: + break; /* nothing else to do */ + default: + nextstate = kr_data->algo_state; + break; + } + + /* + * The status we want to transmit to remote. + * Note that the status combines the receiver status of all coefficients + * with the transmitter's rx ready status. + */ + if (kr_data->algo_state != nextstate) { + al_dbg("[%s] [al_eth_kr_lt_transmit_run] STM changes %s -> %s: " + " Qarray=%d/%d/%d\n", kr_data->adapter->name, + al_eth_kr_mac_sm_name[kr_data->algo_state], + al_eth_kr_mac_sm_name[nextstate], + kr_data->qarray[0], kr_data->qarray[1], kr_data->qarray[2]); + } + + kr_data->algo_state = nextstate; + + /* + * write fields for transmission into hardware. + * Important: this must be done always, as the receiver may have + * received update commands and wants to return its status. + */ + al_eth_ld_coeff_up_set(kr_data->adapter, AL_ETH_AN__LT_LANE_0, &ldcoeff); + al_eth_ld_status_report_set(kr_data->adapter, AL_ETH_AN__LT_LANE_0, + &kr_data->status_report); + + return (0); +} + +/*****************************************************************************/ +static int +al_eth_kr_run_lt(struct al_eth_kr_data *kr_data) +{ + unsigned int cnt; + int ret = 0; + boolean_t page_received = FALSE; + boolean_t an_completed = FALSE; + boolean_t error = FALSE; + boolean_t training_failure = FALSE; + + al_eth_kr_lt_initialize(kr_data->adapter, AL_ETH_AN__LT_LANE_0); + + if (al_eth_kr_lt_frame_lock_wait(kr_data->adapter, AL_ETH_AN__LT_LANE_0, + AL_ETH_KR_FRAME_LOCK_TIMEOUT) == TRUE) { + + /* + * when locked, for the first time initialize the receiver and + * transmitter tasks to prepare it for detecting coefficient + * update requests. + */ + al_eth_kr_lt_receiver_task_init(kr_data); + ret = al_eth_kr_lt_transmitter_task_init(kr_data); + if (ret != 0) + goto error; + + cnt = 0; + do { + ret = al_eth_kr_lt_receiver_task_run(kr_data); + if (ret != 0) + break; /* stop the link training */ + + ret = al_eth_kr_lt_transmitter_task_run(kr_data); + if (ret != 0) + break; /* stop the link training */ + + cnt++; + DELAY(100); + + } while ((al_eth_kr_startup_proto_prog_get(kr_data->adapter, + AL_ETH_AN__LT_LANE_0)) && (cnt <= AL_ETH_KR_LT_MAX_ROUNDS)); + + training_failure = + al_eth_kr_training_status_fail_get(kr_data->adapter, + AL_ETH_AN__LT_LANE_0); + al_dbg("[%s] training ended after %d rounds, failed = %s\n", + kr_data->adapter->name, cnt, + (training_failure) ? "Yes" : "No"); + if (training_failure || cnt > AL_ETH_KR_LT_MAX_ROUNDS) { + al_warn("[%s] Training Fail: status: %s, timeout: %s\n", + kr_data->adapter->name, + (training_failure) ? "Failed" : "OK", + (cnt > AL_ETH_KR_LT_MAX_ROUNDS) ? "Yes" : "No"); + + /* + * note: link is now disabled, + * until training becomes disabled (see below). + */ + ret = EIO; + goto error; + } + + } else { + + al_info("[%s] FAILED: did not achieve initial frame lock...\n", + kr_data->adapter->name); + + ret = EIO; + goto error; + } + + /* + * ensure to stop link training at the end to allow normal PCS + * datapath to operate in case of training failure. + */ + al_eth_kr_lt_stop(kr_data->adapter, AL_ETH_AN__LT_LANE_0); + + cnt = AL_ETH_KR_LT_DONE_TIMEOUT; + while (an_completed == FALSE) { + al_eth_kr_an_status_check(kr_data->adapter, &page_received, + &an_completed, &error); + DELAY(1); + if ((cnt--) == 0) { + al_info("%s: wait for an complete timeout!\n", __func__); + ret = ETIMEDOUT; + goto error; + } + } + +error: + al_eth_kr_an_stop(kr_data->adapter); + + return (ret); +} + +/* execute Autonegotiation process */ +int al_eth_an_lt_execute(struct al_hal_eth_adapter *adapter, + struct al_serdes_grp_obj *serdes_obj, + enum al_serdes_lane lane, + struct al_eth_an_adv *an_adv, + struct al_eth_an_adv *partner_adv) +{ + struct al_eth_kr_data kr_data; + int rc; + struct al_serdes_adv_rx_params rx_params; + + al_memset(&kr_data, 0, sizeof(struct al_eth_kr_data)); + + kr_data.adapter = adapter; + kr_data.serdes_obj = serdes_obj; + kr_data.lane = lane; + + /* + * the link training progress will run rx equalization so need to make + * sure rx parameters is not been override + */ + rx_params.override = FALSE; + kr_data.serdes_obj->rx_advanced_params_set( + kr_data.serdes_obj, + kr_data.lane, + &rx_params); + + rc = al_eth_kr_an_run(&kr_data, an_adv, partner_adv); + if (rc != 0) { + al_eth_kr_lt_stop(adapter, AL_ETH_AN__LT_LANE_0); + al_eth_kr_an_stop(adapter); + al_dbg("%s: auto-negotiation failed!\n", __func__); + return (rc); + } + + if (partner_adv->technology != AL_ETH_AN_TECH_10GBASE_KR) { + al_eth_kr_lt_stop(adapter, AL_ETH_AN__LT_LANE_0); + al_eth_kr_an_stop(adapter); + al_dbg("%s: link partner isn't 10GBASE_KR.\n", __func__); + return (rc); + } + + rc = al_eth_kr_run_lt(&kr_data); + if (rc != 0) { + al_eth_kr_lt_stop(adapter, AL_ETH_AN__LT_LANE_0); + al_eth_kr_an_stop(adapter); + al_dbg("%s: Link-training failed!\n", __func__); + return (rc); + } + + return (0); +} diff --git a/sys/dev/al_eth/al_init_eth_kr.h b/sys/dev/al_eth/al_init_eth_kr.h new file mode 100644 index 000000000000..388275b272f7 --- /dev/null +++ b/sys/dev/al_eth/al_init_eth_kr.h @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates + * All rights reserved. + * + * Developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +/** + * Ethernet + * @{ + * @file al_init_eth_kr.h + * + * @brief auto-negotiation and link training activation sequence + * + * + */ + +#ifndef __AL_INIT_ETH_KR_H__ +#define __AL_INIT_ETH_KR_H__ + +#include +#include + +/** + * execute Auto-negotiation process + * + * @param adapter pointer to the private structure + * @param serdes_obj pointer to serdes private structure + * @param grp serdes's group + * @param lane serdes's lane + * @param an_adv pointer to the AN Advertisement Registers structure + * when NULL, the registers will not be updated. + * @param partner_adv pointer to the AN Advertisement received from the lp + * + * @return 0 on success. otherwise on failure. + */ +int al_eth_an_lt_execute(struct al_hal_eth_adapter *adapter, + struct al_serdes_grp_obj *serdes_obj, + enum al_serdes_lane lane, + struct al_eth_an_adv *an_adv, + struct al_eth_an_adv *partner_adv); + +#endif /*__AL_INIT_ETH_KR_H__*/ diff --git a/sys/dev/al_eth/al_init_eth_lm.c b/sys/dev/al_eth/al_init_eth_lm.c new file mode 100644 index 000000000000..f6aebda6f105 --- /dev/null +++ b/sys/dev/al_eth/al_init_eth_lm.c @@ -0,0 +1,1537 @@ +/*- + * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates + * All rights reserved. + * + * Developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "al_init_eth_lm.h" +#include "al_serdes.h" +#include "al_hal_eth.h" +#include "al_init_eth_kr.h" + +/** + * @{ + * @file al_init_eth_lm.c + * + * @brief ethernet link management common utilities + * + */ + +/* delay before checking link status with new serdes parameters (uSec) */ +#define AL_ETH_LM_LINK_STATUS_DELAY 1000 +/* delay before checking link status after reconfiguring the retimer (uSec) */ +#define AL_ETH_LM_RETIMER_LINK_STATUS_DELAY 50000 + +#define AL_ETH_LM_EQ_ITERATIONS 15 +#define AL_ETH_LM_MAX_DCGAIN 8 + +/* num of link training failures till serdes reset */ +#define AL_ETH_LT_FAILURES_TO_RESET 10 + +#define MODULE_IDENTIFIER_IDX 0 +#define MODULE_IDENTIFIER_SFP 0x3 +#define MODULE_IDENTIFIER_QSFP 0xd + +#define SFP_PRESENT 0 +#define SFP_NOT_PRESENT 1 + +/* SFP+ module */ +#define SFP_I2C_HEADER_10G_IDX 3 +#define SFP_I2C_HEADER_10G_DA_IDX 8 +#define SFP_I2C_HEADER_10G_DA_LEN_IDX 18 +#define SFP_I2C_HEADER_1G_IDX 6 +#define SFP_I2C_HEADER_SIGNAL_RATE 12 /* Nominal signaling rate, units of 100MBd. */ + +#define SFP_MIN_SIGNAL_RATE_25G 250 +#define SFP_MIN_SIGNAL_RATE_10G 100 + +/* QSFP+ module */ +#define QSFP_COMPLIANCE_CODE_IDX 131 +/* 40GBASE-LR4 and 40GBASE-SR4 are optic modules */ +#define QSFP_COMPLIANCE_CODE_OPTIC ((1 << 1) | (1 << 2)) +#define QSFP_COMPLIANCE_CODE_DAC (1 << 3) +#define QSFP_CABLE_LEN_IDX 146 + +/* TODO: need to check the necessary delay */ +#define AL_ETH_LM_RETIMER_WAIT_FOR_LOCK 500 /* delay after retimer reset to lock (mSec) */ +#define AL_ETH_LM_SERDES_WAIT_FOR_LOCK 50 /* delay after signal detect to lock (mSec) */ + +#define AL_ETH_LM_GEARBOX_RESET_DELAY 1000 /* (uSec) */ + +static const uint32_t +al_eth_retimer_boost_addr[AL_ETH_RETIMER_CHANNEL_MAX][AL_ETH_RETIMER_TYPE_MAX] = { + /* BR_210 | BR_410 */ + /* AL_ETH_RETIMER_CHANNEL_A */ {0xf, 0x1a}, + /* AL_ETH_RETIMER_CHANNEL_B */ {0x16, 0x18}, + /* AL_ETH_RETIMER_CHANNEL_C */ {0x0, 0x16}, + /* AL_ETH_RETIMER_CHANNEL_D */ {0x0, 0x14}, +}; + +#define RETIMER_LENS_MAX 5 +static const uint32_t +al_eth_retimer_boost_lens[RETIMER_LENS_MAX] = {0, 1, 2, 3, 5}; + +static const uint32_t +al_eth_retimer_boost_value[RETIMER_LENS_MAX + 1][AL_ETH_RETIMER_TYPE_MAX] = { + /* BR_210 | BR_410 */ + /* 0 */ {0x0, 0x0}, + /* 1 */ {0x1, 0x1}, + /* 2 */ {0x2, 0x1}, + /* 3 */ {0x3, 0x3}, + /* 5 */ {0x7, 0x3}, + /* 5+ */{0xb, 0x7}, +}; + +struct retimer_config_reg { + uint8_t addr; + uint8_t value; + uint8_t mask; +}; + +static struct retimer_config_reg retimer_ds25_25g_mode_tx_ch[] = { + {.addr = 0x0A, .value = 0x0C, .mask = 0xff }, + {.addr = 0x2F, .value = 0x54, .mask = 0xff }, + {.addr = 0x31, .value = 0x20, .mask = 0xff }, + {.addr = 0x1E, .value = 0xE9, .mask = 0xff }, + {.addr = 0x1F, .value = 0x0B, .mask = 0xff }, + {.addr = 0xA6, .value = 0x43, .mask = 0xff }, + {.addr = 0x2A, .value = 0x5A, .mask = 0xff }, + {.addr = 0x2B, .value = 0x0A, .mask = 0xff }, + {.addr = 0x2C, .value = 0xF6, .mask = 0xff }, + {.addr = 0x70, .value = 0x05, .mask = 0xff }, + {.addr = 0x6A, .value = 0x21, .mask = 0xff }, + {.addr = 0x35, .value = 0x0F, .mask = 0xff }, + {.addr = 0x12, .value = 0x83, .mask = 0xff }, + {.addr = 0x9C, .value = 0x24, .mask = 0xff }, + {.addr = 0x98, .value = 0x00, .mask = 0xff }, + {.addr = 0x42, .value = 0x50, .mask = 0xff }, + {.addr = 0x44, .value = 0x90, .mask = 0xff }, + {.addr = 0x45, .value = 0xC0, .mask = 0xff }, + {.addr = 0x46, .value = 0xD0, .mask = 0xff }, + {.addr = 0x47, .value = 0xD1, .mask = 0xff }, + {.addr = 0x48, .value = 0xD5, .mask = 0xff }, + {.addr = 0x49, .value = 0xD8, .mask = 0xff }, + {.addr = 0x4A, .value = 0xEA, .mask = 0xff }, + {.addr = 0x4B, .value = 0xF7, .mask = 0xff }, + {.addr = 0x4C, .value = 0xFD, .mask = 0xff }, + {.addr = 0x8E, .value = 0x00, .mask = 0xff }, + {.addr = 0x3D, .value = 0x94, .mask = 0xff }, + {.addr = 0x3F, .value = 0x40, .mask = 0xff }, + {.addr = 0x3E, .value = 0x43, .mask = 0xff }, + {.addr = 0x0A, .value = 0x00, .mask = 0xff }, +}; + +static struct retimer_config_reg retimer_ds25_25g_mode_rx_ch[] = { + {.addr = 0x0A, .value = 0x0C, .mask = 0xff}, + {.addr = 0x2F, .value = 0x54, .mask = 0xff}, + {.addr = 0x31, .value = 0x40, .mask = 0xff}, + {.addr = 0x1E, .value = 0xE3, .mask = 0xff}, + {.addr = 0x1F, .value = 0x0B, .mask = 0xff}, + {.addr = 0xA6, .value = 0x43, .mask = 0xff}, + {.addr = 0x2A, .value = 0x5A, .mask = 0xff}, + {.addr = 0x2B, .value = 0x0A, .mask = 0xff}, + {.addr = 0x2C, .value = 0xF6, .mask = 0xff}, + {.addr = 0x70, .value = 0x05, .mask = 0xff}, + {.addr = 0x6A, .value = 0x21, .mask = 0xff}, + {.addr = 0x35, .value = 0x0F, .mask = 0xff}, + {.addr = 0x12, .value = 0x83, .mask = 0xff}, + {.addr = 0x9C, .value = 0x24, .mask = 0xff}, + {.addr = 0x98, .value = 0x00, .mask = 0xff}, + {.addr = 0x42, .value = 0x50, .mask = 0xff}, + {.addr = 0x44, .value = 0x90, .mask = 0xff}, + {.addr = 0x45, .value = 0xC0, .mask = 0xff}, + {.addr = 0x46, .value = 0xD0, .mask = 0xff}, + {.addr = 0x47, .value = 0xD1, .mask = 0xff}, + {.addr = 0x48, .value = 0xD5, .mask = 0xff}, + {.addr = 0x49, .value = 0xD8, .mask = 0xff}, + {.addr = 0x4A, .value = 0xEA, .mask = 0xff}, + {.addr = 0x4B, .value = 0xF7, .mask = 0xff}, + {.addr = 0x4C, .value = 0xFD, .mask = 0xff}, + {.addr = 0x8E, .value = 0x00, .mask = 0xff}, + {.addr = 0x3D, .value = 0x94, .mask = 0xff}, + {.addr = 0x3F, .value = 0x40, .mask = 0xff}, + {.addr = 0x3E, .value = 0x43, .mask = 0xff}, + {.addr = 0x0A, .value = 0x00, .mask = 0xff}, +}; + +static struct retimer_config_reg retimer_ds25_10g_mode[] = { + /* Assert CDR reset (6.3) */ + {.addr = 0x0A, .value = 0x0C, .mask = 0x0C}, + /* Select 10.3125Gbps standard rate mode (6.6) */ + {.addr = 0x2F, .value = 0x00, .mask = 0xF0}, + /* Enable loop filter auto-adjust */ + {.addr = 0x1F, .value = 0x08, .mask = 0x08}, + /* Set Adapt Mode 1 (6.13) */ + {.addr = 0x31, .value = 0x20, .mask = 0x60}, + /* Disable the DFE since most applications do not need it (6.18) */ + {.addr = 0x1E, .value = 0x08, .mask = 0x08}, + /* Release CDR reset (6.4) */ + {.addr = 0x0A, .value = 0x00, .mask = 0x0C}, + /* Enable FIR (6.12) */ + {.addr = 0x3D, .value = 0x80, .mask = 0x80}, + /* Set Main-cursor tap sign to positive (6.12) */ + {.addr = 0x3D, .value = 0x00, .mask = 0x40}, + /* Set Post-cursor tap sign to negative (6.12) */ + {.addr = 0x3F, .value = 0x40, .mask = 0x40}, + /* Set Pre-cursor tap sign to negative (6.12) */ + {.addr = 0x3E, .value = 0x40, .mask = 0x40}, + /* Set Main-cursor tap magnitude to 13 (6.12) */ + {.addr = 0x3D, .value = 0x0D, .mask = 0x1F}, +}; + +static int al_eth_lm_retimer_boost_config(struct al_eth_lm_context *lm_context); +static int al_eth_lm_retimer_ds25_full_config(struct al_eth_lm_context *lm_context); +static al_bool al_eth_lm_retimer_ds25_signal_detect( + struct al_eth_lm_context *lm_context, uint32_t channel); +static int al_eth_lm_retimer_ds25_cdr_reset(struct al_eth_lm_context *lm_context, uint32_t channel); +static al_bool al_eth_lm_retimer_ds25_cdr_lock( + struct al_eth_lm_context *lm_context, uint32_t channel); +static int al_eth_lm_retimer_25g_rx_adaptation(struct al_eth_lm_context *lm_context); + +struct al_eth_lm_retimer { + int (*config)(struct al_eth_lm_context *lm_context); + int (*reset)(struct al_eth_lm_context *lm_context, uint32_t channel); + int (*signal_detect)(struct al_eth_lm_context *lm_context, uint32_t channel); + int (*cdr_lock)(struct al_eth_lm_context *lm_context, uint32_t channel); + int (*rx_adaptation)(struct al_eth_lm_context *lm_context); +}; + +static struct al_eth_lm_retimer retimer[] = { + {.config = al_eth_lm_retimer_boost_config, .signal_detect = NULL, + .reset = NULL, .cdr_lock = NULL, .rx_adaptation = NULL}, + {.config = al_eth_lm_retimer_boost_config, .signal_detect = NULL, + .reset = NULL, .cdr_lock = NULL, .rx_adaptation = NULL}, + {.config = al_eth_lm_retimer_ds25_full_config, + .signal_detect = al_eth_lm_retimer_ds25_signal_detect, + .reset = al_eth_lm_retimer_ds25_cdr_reset, + .cdr_lock = al_eth_lm_retimer_ds25_cdr_lock, + .rx_adaptation = al_eth_lm_retimer_25g_rx_adaptation}, +}; + +#define SFP_10G_DA_ACTIVE 0x8 +#define SFP_10G_DA_PASSIVE 0x4 + +#define lm_debug(...) \ + do { \ + if (lm_context->debug) \ + al_warn(__VA_ARGS__); \ + else \ + al_dbg(__VA_ARGS__); \ + } while (0) + +static int +al_eth_sfp_detect(struct al_eth_lm_context *lm_context, + enum al_eth_lm_link_mode *new_mode) +{ + int rc = 0; + uint8_t sfp_10g; + uint8_t sfp_1g; + uint8_t sfp_cable_tech; + uint8_t sfp_da_len; + uint8_t signal_rate; + + do { + rc = lm_context->i2c_read(lm_context->i2c_context, + lm_context->sfp_bus_id, lm_context->sfp_i2c_addr, + SFP_I2C_HEADER_10G_IDX, &sfp_10g); + if (rc != 0) + break; + + rc = lm_context->i2c_read(lm_context->i2c_context, + lm_context->sfp_bus_id, lm_context->sfp_i2c_addr, + SFP_I2C_HEADER_1G_IDX, &sfp_1g); + if (rc != 0) + break; + + rc = lm_context->i2c_read(lm_context->i2c_context, + lm_context->sfp_bus_id, lm_context->sfp_i2c_addr, + SFP_I2C_HEADER_10G_DA_IDX, &sfp_cable_tech); + if (rc != 0) + break; + + rc = lm_context->i2c_read(lm_context->i2c_context, + lm_context->sfp_bus_id, lm_context->sfp_i2c_addr, + SFP_I2C_HEADER_10G_DA_LEN_IDX, &sfp_da_len); + if (rc != 0) + break; + + rc = lm_context->i2c_read(lm_context->i2c_context, + lm_context->sfp_bus_id, + lm_context->sfp_i2c_addr, + SFP_I2C_HEADER_SIGNAL_RATE, + &signal_rate); + } while (0); + + if (rc != 0) { + if (rc == ETIMEDOUT) { + /* ETIMEDOUT is returned when no SFP is connected */ + if (lm_context->mode != AL_ETH_LM_MODE_DISCONNECTED) + lm_debug("%s: SFP Disconnected\n", __func__); + *new_mode = AL_ETH_LM_MODE_DISCONNECTED; + } else { + return (rc); + } + } else if ((sfp_cable_tech & (SFP_10G_DA_PASSIVE | SFP_10G_DA_ACTIVE)) != 0) { + if ((signal_rate >= SFP_MIN_SIGNAL_RATE_25G) && + ((lm_context->max_speed == AL_ETH_LM_MAX_SPEED_25G) || + (lm_context->max_speed == AL_ETH_LM_MAX_SPEED_MAX))) + *new_mode = AL_ETH_LM_MODE_25G; + else if ((signal_rate >= SFP_MIN_SIGNAL_RATE_10G) && + ((lm_context->max_speed == AL_ETH_LM_MAX_SPEED_10G) || + (lm_context->max_speed == AL_ETH_LM_MAX_SPEED_MAX))) + *new_mode = AL_ETH_LM_MODE_10G_DA; + else + *new_mode = AL_ETH_LM_MODE_1G; + + lm_debug("%s: %s DAC (%d M) detected (max signal rate %d)\n", + __func__, + (sfp_cable_tech & SFP_10G_DA_PASSIVE) ? "Passive" : "Active", + sfp_da_len, + signal_rate); + + /* for active direct attached need to use len 0 in the retimer configuration */ + lm_context->da_len = (sfp_cable_tech & SFP_10G_DA_PASSIVE) ? sfp_da_len : 0; + } else if (sfp_10g != 0) { + lm_debug("%s: 10 SFP detected\n", __func__); + *new_mode = AL_ETH_LM_MODE_10G_OPTIC; + } else if (sfp_1g != 0) { + lm_debug("%s: 1G SFP detected\n", __func__); + *new_mode = AL_ETH_LM_MODE_1G; + } else { + al_warn("%s: unknown SFP inserted. eeprom content: 10G compliance 0x%x," + " 1G compliance 0x%x, sfp+cable 0x%x. default to %s\n", + __func__, sfp_10g, sfp_1g, sfp_cable_tech, + al_eth_lm_mode_convert_to_str(lm_context->default_mode)); + *new_mode = lm_context->default_mode; + lm_context->da_len = lm_context->default_dac_len; + } + + if ((lm_context->sfp_detect_force_mode) && (*new_mode != AL_ETH_LM_MODE_DISCONNECTED) && + (*new_mode != lm_context->default_mode)) { + al_warn("%s: Force mode to default (%s). mode based of the SFP EEPROM %s\n", + __func__, al_eth_lm_mode_convert_to_str(lm_context->default_mode), + al_eth_lm_mode_convert_to_str(*new_mode)); + + *new_mode = lm_context->default_mode; + } + + lm_context->mode = *new_mode; + + return (0); +} + +static int +al_eth_qsfp_detect(struct al_eth_lm_context *lm_context, + enum al_eth_lm_link_mode *new_mode) +{ + int rc = 0; + uint8_t qsfp_comp_code; + uint8_t qsfp_da_len; + + do { + rc = lm_context->i2c_read(lm_context->i2c_context, + lm_context->sfp_bus_id, lm_context->sfp_i2c_addr, + QSFP_COMPLIANCE_CODE_IDX, &qsfp_comp_code); + if (rc != 0) + break; + + rc = lm_context->i2c_read(lm_context->i2c_context, + lm_context->sfp_bus_id, lm_context->sfp_i2c_addr, + QSFP_CABLE_LEN_IDX, &qsfp_da_len); + if (rc != 0) + break; + } while (0); + + if (rc != 0) { + if (rc == ETIMEDOUT) { + /* ETIMEDOUT is returned when no SFP is connected */ + lm_debug("%s: SFP Disconnected\n", __func__); + *new_mode = AL_ETH_LM_MODE_DISCONNECTED; + } else { + return (rc); + } + } else if ((qsfp_comp_code & QSFP_COMPLIANCE_CODE_DAC) != 0) { + lm_debug("%s: 10G passive DAC (%d M) detected\n", + __func__, qsfp_da_len); + *new_mode = AL_ETH_LM_MODE_10G_DA; + lm_context->da_len = qsfp_da_len; + } else if ((qsfp_comp_code & QSFP_COMPLIANCE_CODE_OPTIC) != 0) { + lm_debug("%s: 10G optic module detected\n", __func__); + *new_mode = AL_ETH_LM_MODE_10G_OPTIC; + } else { + al_warn("%s: unknown QSFP inserted. eeprom content: 10G " + "compliance 0x%x default to %s\n", __func__, qsfp_comp_code, + al_eth_lm_mode_convert_to_str(lm_context->default_mode)); + *new_mode = lm_context->default_mode; + lm_context->da_len = lm_context->default_dac_len; + } + + lm_context->mode = *new_mode; + + return (0); +} + +static int +al_eth_module_detect(struct al_eth_lm_context *lm_context, + enum al_eth_lm_link_mode *new_mode) +{ + int rc = 0; + uint8_t module_idx; + int sfp_present = SFP_PRESENT; + + if ((lm_context->gpio_get) && (lm_context->gpio_present != 0)) + sfp_present = lm_context->gpio_get(lm_context->gpio_present); + + if (sfp_present == SFP_NOT_PRESENT) { + lm_debug("%s: SFP not exist\n", __func__); + *new_mode = AL_ETH_LM_MODE_DISCONNECTED; + + return 0; + } + + rc = lm_context->i2c_read(lm_context->i2c_context, + lm_context->sfp_bus_id, lm_context->sfp_i2c_addr, + MODULE_IDENTIFIER_IDX, &module_idx); + if (rc != 0) { + if (rc == ETIMEDOUT) { + /* ETIMEDOUT is returned when no SFP is connected */ + if (lm_context->mode != AL_ETH_LM_MODE_DISCONNECTED) + lm_debug("%s: SFP Disconnected\n", __func__); + *new_mode = AL_ETH_LM_MODE_DISCONNECTED; + return (0); + } else { + return (rc); + } + } + + if (module_idx == MODULE_IDENTIFIER_QSFP) + return (al_eth_qsfp_detect(lm_context, new_mode)); + else + return (al_eth_sfp_detect(lm_context, new_mode)); + + return (0); +} + +static struct al_serdes_adv_tx_params da_tx_params = { + .override = TRUE, + .amp = 0x1, + .total_driver_units = 0x13, + .c_plus_1 = 0x2, + .c_plus_2 = 0, + .c_minus_1 = 0x2, + .slew_rate = 0, +}; + +static struct al_serdes_adv_rx_params da_rx_params = { + .override = TRUE, + .dcgain = 0x4, + .dfe_3db_freq = 0x4, + .dfe_gain = 0x3, + .dfe_first_tap_ctrl = 0x5, + .dfe_secound_tap_ctrl = 0x1, + .dfe_third_tap_ctrl = 0x8, + .dfe_fourth_tap_ctrl = 0x1, + .low_freq_agc_gain = 0x7, + .precal_code_sel = 0, + .high_freq_agc_boost = 0x1d, +}; + +static struct al_serdes_adv_tx_params optic_tx_params = { + .override = TRUE, + .amp = 0x1, + .total_driver_units = 0x13, + .c_plus_1 = 0x2, + .c_plus_2 = 0, + .c_minus_1 = 0, + .slew_rate = 0, +}; + +static struct al_serdes_adv_rx_params optic_rx_params = { + .override = TRUE, + .dcgain = 0x0, + .dfe_3db_freq = 0x7, + .dfe_gain = 0x0, + .dfe_first_tap_ctrl = 0x0, + .dfe_secound_tap_ctrl = 0x8, + .dfe_third_tap_ctrl = 0x0, + .dfe_fourth_tap_ctrl = 0x8, + .low_freq_agc_gain = 0x7, + .precal_code_sel = 0, + .high_freq_agc_boost = 0x4, +}; + +static void +al_eth_serdes_static_tx_params_set(struct al_eth_lm_context *lm_context) +{ + + if (lm_context->tx_param_dirty == 0) + return; + + if (lm_context->serdes_tx_params_valid != 0) { + lm_context->tx_param_dirty = 0; + + lm_context->tx_params_override.override = TRUE; + + if ((lm_context->serdes_obj->tx_advanced_params_set) == 0) { + al_err("tx_advanced_params_set is not supported for this serdes group\n"); + return; + } + + lm_context->serdes_obj->tx_advanced_params_set( + lm_context->serdes_obj, + lm_context->lane, + &lm_context->tx_params_override); + + } else if (lm_context->static_values != 0) { + lm_context->tx_param_dirty = 0; + + if ((lm_context->serdes_obj->tx_advanced_params_set) == 0) { + al_err("tx_advanced_params_set is not supported for this serdes group\n"); + return; + } + + if ((lm_context->retimer_exist == 0) && + (lm_context->mode == AL_ETH_LM_MODE_10G_DA)) + lm_context->serdes_obj->tx_advanced_params_set( + lm_context->serdes_obj, + lm_context->lane, + &da_tx_params); + else + lm_context->serdes_obj->tx_advanced_params_set( + lm_context->serdes_obj, + lm_context->lane, + &optic_tx_params); + } +} + +static void +al_eth_serdes_static_rx_params_set(struct al_eth_lm_context *lm_context) +{ + + if (lm_context->rx_param_dirty == 0) + return; + + if (lm_context->serdes_rx_params_valid != 0) { + lm_context->rx_param_dirty = 0; + + lm_context->rx_params_override.override = TRUE; + + if ((lm_context->serdes_obj->rx_advanced_params_set) == 0) { + al_err("rx_advanced_params_set is not supported for this serdes group\n"); + return; + } + + lm_context->serdes_obj->rx_advanced_params_set( + lm_context->serdes_obj, + lm_context->lane, + &lm_context->rx_params_override); + + + } else if (lm_context->static_values != 0) { + lm_context->rx_param_dirty = 0; + + if ((lm_context->serdes_obj->rx_advanced_params_set) == 0) { + al_err("rx_advanced_params_set is not supported for this serdes group\n"); + return; + } + + if ((lm_context->retimer_exist == 0) && + (lm_context->mode == AL_ETH_LM_MODE_10G_DA)) + lm_context->serdes_obj->rx_advanced_params_set( + lm_context->serdes_obj, + lm_context->lane, + &da_rx_params); + else + lm_context->serdes_obj->rx_advanced_params_set( + lm_context->serdes_obj, + lm_context->lane, + &optic_rx_params); + } +} + +static int +al_eth_rx_equal_run(struct al_eth_lm_context *lm_context) +{ + struct al_serdes_adv_rx_params rx_params; + int dcgain; + int best_dcgain = -1; + int i; + int best_score = -1; + int test_score = -1; + + rx_params.override = FALSE; + lm_context->serdes_obj->rx_advanced_params_set(lm_context->serdes_obj, + lm_context->lane, &rx_params); + + lm_debug("score | dcgain | dfe3db | dfegain | tap1 | tap2 | tap3 | " + "tap4 | low freq | high freq\n"); + + for (dcgain = 0; dcgain < AL_ETH_LM_MAX_DCGAIN; dcgain++) { + lm_context->serdes_obj->dcgain_set( + lm_context->serdes_obj, + dcgain); + + test_score = lm_context->serdes_obj->rx_equalization( + lm_context->serdes_obj, + lm_context->lane); + + if (test_score < 0) { + al_warn("serdes rx equalization failed on error\n"); + return (test_score); + } + + if (test_score > best_score) { + best_score = test_score; + best_dcgain = dcgain; + } + + lm_context->serdes_obj->rx_advanced_params_get( + lm_context->serdes_obj, + lm_context->lane, + &rx_params); + + lm_debug("%6d|%8x|%8x|%9x|%6x|%6x|%6x|%6x|%10x|%10x|\n", + test_score, rx_params.dcgain, rx_params.dfe_3db_freq, + rx_params.dfe_gain, rx_params.dfe_first_tap_ctrl, + rx_params.dfe_secound_tap_ctrl, rx_params.dfe_third_tap_ctrl, + rx_params.dfe_fourth_tap_ctrl, rx_params.low_freq_agc_gain, + rx_params.high_freq_agc_boost); + } + + lm_context->serdes_obj->dcgain_set( + lm_context->serdes_obj, + best_dcgain); + + best_score = -1; + for(i = 0; i < AL_ETH_LM_EQ_ITERATIONS; i++) { + test_score = lm_context->serdes_obj->rx_equalization( + lm_context->serdes_obj, + lm_context->lane); + + if (test_score < 0) { + al_warn("serdes rx equalization failed on error\n"); + return (test_score); + } + + if (test_score > best_score) { + best_score = test_score; + lm_context->serdes_obj->rx_advanced_params_get( + lm_context->serdes_obj, + lm_context->lane, + &rx_params); + } + } + + rx_params.precal_code_sel = 0; + rx_params.override = TRUE; + lm_context->serdes_obj->rx_advanced_params_set( + lm_context->serdes_obj, + lm_context->lane, + &rx_params); + + lm_debug("-------------------- best dcgain %d ------------------------------------\n", best_dcgain); + lm_debug("%6d|%8x|%8x|%9x|%6x|%6x|%6x|%6x|%10x|%10x|\n", + best_score, rx_params.dcgain, rx_params.dfe_3db_freq, + rx_params.dfe_gain, rx_params.dfe_first_tap_ctrl, + rx_params.dfe_secound_tap_ctrl, rx_params.dfe_third_tap_ctrl, + rx_params.dfe_fourth_tap_ctrl, rx_params.low_freq_agc_gain, + rx_params.high_freq_agc_boost); + + return (0); +} + +static int al_eth_lm_retimer_boost_config(struct al_eth_lm_context *lm_context) +{ + int i; + int rc = 0; + uint8_t boost = 0; + uint32_t boost_addr = + al_eth_retimer_boost_addr[lm_context->retimer_channel][lm_context->retimer_type]; + + if (lm_context->mode != AL_ETH_LM_MODE_10G_DA) { + boost = al_eth_retimer_boost_value[0][lm_context->retimer_type]; + } else { + for (i = 0; i < RETIMER_LENS_MAX; i++) { + if (lm_context->da_len <= al_eth_retimer_boost_lens[i]) { + boost = al_eth_retimer_boost_value[i][lm_context->retimer_type]; + break; + } + } + + if (i == RETIMER_LENS_MAX) + boost = al_eth_retimer_boost_value[RETIMER_LENS_MAX][lm_context->retimer_type]; + } + + lm_debug("config retimer boost in channel %d (addr %x) to 0x%x\n", + lm_context->retimer_channel, boost_addr, boost); + + rc = lm_context->i2c_write(lm_context->i2c_context, + lm_context->retimer_bus_id, lm_context->retimer_i2c_addr, + boost_addr, boost); + + if (rc != 0) { + al_err("%s: Error occurred (%d) while writing retimer " + "configuration (bus-id %x i2c-addr %x)\n", + __func__, rc, lm_context->retimer_bus_id, + lm_context->retimer_i2c_addr); + return (rc); + } + + return (0); +} + +/******************************************************************************* + ************************** retimer DS25 *************************************** + ******************************************************************************/ +#define LM_DS25_CHANNEL_EN_REG 0xff +#define LM_DS25_CHANNEL_EN_MASK 0x03 +#define LM_DS25_CHANNEL_EN_VAL 0x01 + +#define LM_DS25_CHANNEL_SEL_REG 0xfc +#define LM_DS25_CHANNEL_SEL_MASK 0xff + +#define LM_DS25_CDR_RESET_REG 0x0a +#define LM_DS25_CDR_RESET_MASK 0x0c +#define LM_DS25_CDR_RESET_ASSERT 0x0c +#define LM_DS25_CDR_RESET_RELEASE 0x00 + +#define LM_DS25_SIGNAL_DETECT_REG 0x78 +#define LM_DS25_SIGNAL_DETECT_MASK 0x20 + +#define LM_DS25_CDR_LOCK_REG 0x78 +#define LM_DS25_CDR_LOCK_MASK 0x10 + +#define LM_DS25_DRV_PD_REG 0x15 +#define LM_DS25_DRV_PD_MASK 0x08 + +static int al_eth_lm_retimer_ds25_write_reg(struct al_eth_lm_context *lm_context, + uint8_t reg_addr, + uint8_t reg_mask, + uint8_t reg_value) +{ + uint8_t reg; + int rc; + + rc = lm_context->i2c_read(lm_context->i2c_context, + lm_context->retimer_bus_id, + lm_context->retimer_i2c_addr, + reg_addr, + ®); + + if (rc != 0) + return (EIO); + + reg &= ~(reg_mask); + reg |= reg_value; + + rc = lm_context->i2c_write(lm_context->i2c_context, + lm_context->retimer_bus_id, + lm_context->retimer_i2c_addr, + reg_addr, + reg); + + if (rc != 0) + return (EIO); + + return (0); +} + +static int al_eth_lm_retimer_ds25_channel_select(struct al_eth_lm_context *lm_context, + uint8_t channel) +{ + int rc = 0; + + /* Write to specific channel */ + rc = al_eth_lm_retimer_ds25_write_reg(lm_context, + LM_DS25_CHANNEL_EN_REG, + LM_DS25_CHANNEL_EN_MASK, + LM_DS25_CHANNEL_EN_VAL); + + if (rc != 0) + return (rc); + + rc = al_eth_lm_retimer_ds25_write_reg(lm_context, + LM_DS25_CHANNEL_SEL_REG, + LM_DS25_CHANNEL_SEL_MASK, + (1 << channel)); + + return (rc); +} + +static int al_eth_lm_retimer_ds25_channel_config(struct al_eth_lm_context *lm_context, + uint8_t channel, + struct retimer_config_reg *config, + uint8_t config_size) +{ + uint8_t i; + int rc; + + rc = al_eth_lm_retimer_ds25_channel_select(lm_context, channel); + if (rc != 0) + goto config_error; + + for (i = 0; i < config_size; i++) { + rc = al_eth_lm_retimer_ds25_write_reg(lm_context, + config[i].addr, + config[i].mask, + config[i].value); + + if (rc != 0) + goto config_error; + } + + lm_debug("%s: retimer channel config done for channel %d\n", __func__, channel); + + return (0); + +config_error: + al_err("%s: failed to access to the retimer\n", __func__); + + return (rc); +} + +static int al_eth_lm_retimer_ds25_cdr_reset(struct al_eth_lm_context *lm_context, uint32_t channel) +{ + int rc; + + lm_debug("Perform CDR reset to channel %d\n", channel); + + rc = al_eth_lm_retimer_ds25_channel_select(lm_context, channel); + if (rc) + goto config_error; + + rc = al_eth_lm_retimer_ds25_write_reg(lm_context, + LM_DS25_CDR_RESET_REG, + LM_DS25_CDR_RESET_MASK, + LM_DS25_CDR_RESET_ASSERT); + + if (rc) + goto config_error; + + rc = al_eth_lm_retimer_ds25_write_reg(lm_context, + LM_DS25_CDR_RESET_REG, + LM_DS25_CDR_RESET_MASK, + LM_DS25_CDR_RESET_RELEASE); + + if (rc) + goto config_error; + + return 0; + +config_error: + al_err("%s: failed to access to the retimer\n", __func__); + + return rc; +} + +static boolean_t al_eth_lm_retimer_ds25_signal_detect(struct al_eth_lm_context *lm_context, + uint32_t channel) +{ + int rc = 0; + uint8_t reg; + + rc = al_eth_lm_retimer_ds25_channel_select(lm_context, channel); + if (rc) + goto config_error; + + rc = lm_context->i2c_read(lm_context->i2c_context, + lm_context->retimer_bus_id, + lm_context->retimer_i2c_addr, + LM_DS25_SIGNAL_DETECT_REG, + ®); + + if (rc) + goto config_error; + + if (reg & LM_DS25_SIGNAL_DETECT_MASK) + return TRUE; + + return FALSE; + +config_error: + al_err("%s: failed to access to the retimer\n", __func__); + + return FALSE; +} + +static boolean_t al_eth_lm_retimer_ds25_cdr_lock(struct al_eth_lm_context *lm_context, + uint32_t channel) +{ + int rc = 0; + uint8_t reg; + + rc = al_eth_lm_retimer_ds25_channel_select(lm_context, channel); + if (rc) + goto config_error; + + rc = lm_context->i2c_read(lm_context->i2c_context, + lm_context->retimer_bus_id, + lm_context->retimer_i2c_addr, + LM_DS25_CDR_LOCK_REG, + ®); + + if (rc) + goto config_error; + + if (reg & LM_DS25_CDR_LOCK_MASK) + return TRUE; + + return FALSE; + +config_error: + al_err("%s: failed to access to the retimer\n", __func__); + + return FALSE; +} + +static boolean_t al_eth_lm_wait_for_lock(struct al_eth_lm_context *lm_context, + uint32_t channel) +{ + uint32_t timeout = AL_ETH_LM_RETIMER_WAIT_FOR_LOCK; + al_bool lock = AL_FALSE; + + while ((timeout > 0) && (lock == FALSE)) { + al_msleep(10); + timeout -= 10; + + lock = retimer[lm_context->retimer_type].cdr_lock(lm_context, channel); + } + + lm_debug("%s: %s to achieve CDR lock in %d msec\n", + __func__, (lock) ? "succeed" : "FAILED", + (AL_ETH_LM_RETIMER_WAIT_FOR_LOCK - timeout)); + + return lock; +} + +static void al_eth_lm_retimer_signal_lock_check(struct al_eth_lm_context *lm_context, + uint32_t channel, + boolean_t *ready) +{ + al_bool signal_detect = TRUE; + al_bool cdr_lock = TRUE; + + if (retimer[lm_context->retimer_type].signal_detect) { + if (!retimer[lm_context->retimer_type].signal_detect(lm_context, channel)) { + lm_debug("no signal detected on retimer channel %d\n", channel); + + signal_detect = AL_FALSE; + } else { + if (retimer[lm_context->retimer_type].cdr_lock) { + cdr_lock = retimer[lm_context->retimer_type].cdr_lock( + lm_context, + channel); + if (!cdr_lock) { + if (retimer[lm_context->retimer_type].reset) { + retimer[lm_context->retimer_type].reset(lm_context, + channel); + + cdr_lock = al_eth_lm_wait_for_lock(lm_context, + channel); + } + } + } + } + } + + al_info("%s: (channel %d) signal %d cdr lock %d\n", + __func__, channel, signal_detect, (signal_detect) ? cdr_lock : 0); + + *ready = ((cdr_lock == TRUE) && (signal_detect == TRUE)); +} + +static int al_eth_lm_retimer_ds25_full_config(struct al_eth_lm_context *lm_context) +{ + int rc = 0; + al_bool ready; + struct retimer_config_reg *config_tx; + uint32_t config_tx_size; + struct retimer_config_reg *config_rx; + uint32_t config_rx_size; + + if (lm_context->mode == AL_ETH_LM_MODE_25G) { + config_tx = retimer_ds25_25g_mode_tx_ch; + config_tx_size = AL_ARR_SIZE(retimer_ds25_25g_mode_tx_ch); + + config_rx = retimer_ds25_25g_mode_rx_ch; + config_rx_size = AL_ARR_SIZE(retimer_ds25_25g_mode_rx_ch); + + } else { + config_tx = retimer_ds25_10g_mode; + config_tx_size = AL_ARR_SIZE(retimer_ds25_10g_mode); + + config_rx = retimer_ds25_10g_mode; + config_rx_size = AL_ARR_SIZE(retimer_ds25_10g_mode); + } + + + rc = al_eth_lm_retimer_ds25_channel_config(lm_context, + lm_context->retimer_channel, + config_rx, + config_rx_size); + + if (rc) + return rc; + + rc = al_eth_lm_retimer_ds25_channel_config(lm_context, + lm_context->retimer_tx_channel, + config_tx, + config_tx_size); + + if (rc) + return rc; + + if (lm_context->serdes_obj->type_get() == AL_SRDS_TYPE_25G) { + lm_debug("%s: serdes 25G - perform tx and rx gearbox reset\n", __func__); + al_eth_gearbox_reset(lm_context->adapter, TRUE, TRUE); + DELAY(AL_ETH_LM_GEARBOX_RESET_DELAY); + } + + al_eth_lm_retimer_signal_lock_check(lm_context, lm_context->retimer_tx_channel, &ready); + + if (!ready) { + lm_debug("%s: Failed to lock tx channel!\n", __func__); + return (1); + } + + lm_debug("%s: retimer full configuration done\n", __func__); + + return rc; +} + +static int al_eth_lm_retimer_25g_rx_adaptation(struct al_eth_lm_context *lm_context) +{ + int rc = 0; + al_bool ready; + + al_eth_lm_retimer_signal_lock_check(lm_context, lm_context->retimer_channel, &ready); + + if (!ready) { + lm_debug("%s: no signal detected on retimer Rx channel (%d)\n", + __func__, lm_context->retimer_channel); + + return rc; + } + + al_msleep(AL_ETH_LM_SERDES_WAIT_FOR_LOCK); + + return 0; +} + +static int al_eth_lm_check_for_link(struct al_eth_lm_context *lm_context, boolean_t *link_up) +{ + struct al_eth_link_status status; + int ret = 0; + + al_eth_link_status_clear(lm_context->adapter); + al_eth_link_status_get(lm_context->adapter, &status); + + if (status.link_up == AL_TRUE) { + lm_debug("%s: >>>> Link state DOWN ==> UP\n", __func__); + al_eth_led_set(lm_context->adapter, AL_TRUE); + lm_context->link_state = AL_ETH_LM_LINK_UP; + *link_up = AL_TRUE; + + return 0; + } else if (status.local_fault) { + lm_context->link_state = AL_ETH_LM_LINK_DOWN; + al_eth_led_set(lm_context->adapter, AL_FALSE); + + al_err("%s: Failed to establish link\n", __func__); + ret = 1; + } else { + lm_debug("%s: >>>> Link state DOWN ==> DOWN_RF\n", __func__); + lm_context->link_state = AL_ETH_LM_LINK_DOWN_RF; + al_eth_led_set(lm_context->adapter, AL_FALSE); + + ret = 0; + } + + *link_up = AL_FALSE; + return ret; +} + +/*****************************************************************************/ +/***************************** API functions *********************************/ +/*****************************************************************************/ +int +al_eth_lm_init(struct al_eth_lm_context *lm_context, + struct al_eth_lm_init_params *params) +{ + + lm_context->adapter = params->adapter; + lm_context->serdes_obj = params->serdes_obj; + lm_context->lane = params->lane; + lm_context->sfp_detection = params->sfp_detection; + lm_context->sfp_bus_id = params->sfp_bus_id; + lm_context->sfp_i2c_addr = params->sfp_i2c_addr; + + lm_context->retimer_exist = params->retimer_exist; + lm_context->retimer_type = params->retimer_type; + lm_context->retimer_bus_id = params->retimer_bus_id; + lm_context->retimer_i2c_addr = params->retimer_i2c_addr; + lm_context->retimer_channel = params->retimer_channel; + lm_context->retimer_tx_channel = params->retimer_tx_channel; + + lm_context->default_mode = params->default_mode; + lm_context->default_dac_len = params->default_dac_len; + lm_context->link_training = params->link_training; + lm_context->rx_equal = params->rx_equal; + lm_context->static_values = params->static_values; + lm_context->i2c_read = params->i2c_read; + lm_context->i2c_write = params->i2c_write; + lm_context->i2c_context = params->i2c_context; + lm_context->get_random_byte = params->get_random_byte; + + /* eeprom_read must be provided if sfp_detection is true */ + al_assert((lm_context->sfp_detection == FALSE) || + (lm_context->i2c_read != NULL)); + + al_assert((lm_context->retimer_exist == FALSE) || + (lm_context->i2c_write != NULL)); + + lm_context->local_adv.selector_field = 1; + lm_context->local_adv.capability = 0; + lm_context->local_adv.remote_fault = 0; + lm_context->local_adv.acknowledge = 0; + lm_context->local_adv.next_page = 0; + lm_context->local_adv.technology = AL_ETH_AN_TECH_10GBASE_KR; + lm_context->local_adv.fec_capability = params->kr_fec_enable; + + lm_context->mode = AL_ETH_LM_MODE_DISCONNECTED; + lm_context->serdes_tx_params_valid = FALSE; + lm_context->serdes_rx_params_valid = FALSE; + + lm_context->rx_param_dirty = 1; + lm_context->tx_param_dirty = 1; + + lm_context->gpio_get = params->gpio_get; + lm_context->gpio_present = params->gpio_present; + + lm_context->max_speed = params->max_speed; + lm_context->sfp_detect_force_mode = params->sfp_detect_force_mode; + + lm_context->lm_pause = params->lm_pause; + + lm_context->led_config = params->led_config; + + lm_context->retimer_configured = FALSE; + + lm_context->link_state = AL_ETH_LM_LINK_DOWN; + + return (0); +} + +int +al_eth_lm_link_detection(struct al_eth_lm_context *lm_context, + boolean_t *link_fault, enum al_eth_lm_link_mode *old_mode, + enum al_eth_lm_link_mode *new_mode) +{ + int err; + struct al_eth_link_status status; + + al_assert(lm_context != NULL); + al_assert(old_mode != NULL); + al_assert(new_mode != NULL); + + /** + * if Link management is disabled, report no link fault in case the link was up + * before and set new mode to disconnected to avoid calling to link establish + * if the link wasn't up. + */ + if (lm_context->lm_pause != NULL) { + boolean_t lm_pause = lm_context->lm_pause(lm_context->i2c_context); + if (lm_pause == TRUE) { + *new_mode = AL_ETH_LM_MODE_DISCONNECTED; + if (link_fault != 0) { + if (lm_context->link_state == AL_ETH_LM_LINK_UP) + *link_fault = FALSE; + else + *link_fault = TRUE; + } + + return 0; + } + } + + *old_mode = lm_context->mode; + *new_mode = lm_context->mode; + + if (link_fault != NULL) + *link_fault = TRUE; + + switch (lm_context->link_state) { + case AL_ETH_LM_LINK_UP: + al_eth_link_status_get(lm_context->adapter, &status); + + if (status.link_up) { + if (link_fault != NULL) + *link_fault = FALSE; + + al_eth_led_set(lm_context->adapter, TRUE); + + return (0); + } else if (status.local_fault) { + lm_debug("%s: >>>> Link state UP ==> DOWN\n", __func__); + lm_context->link_state = AL_ETH_LM_LINK_DOWN; + } else { + lm_debug("%s: >>>> Link state UP ==> DOWN_RF\n", __func__); + lm_context->link_state = AL_ETH_LM_LINK_DOWN_RF; + } + + break; + case AL_ETH_LM_LINK_DOWN_RF: + al_eth_link_status_get(lm_context->adapter, &status); + + if (status.local_fault) { + lm_debug("%s: >>>> Link state DOWN_RF ==> DOWN\n", __func__); + lm_context->link_state = AL_ETH_LM_LINK_DOWN; + + break; + } else if (status.remote_fault == FALSE) { + lm_debug("%s: >>>> Link state DOWN_RF ==> UP\n", __func__); + lm_context->link_state = AL_ETH_LM_LINK_UP; + } + /* in case of remote fault only no need to check SFP again */ + return (0); + case AL_ETH_LM_LINK_DOWN: + break; + }; + + al_eth_led_set(lm_context->adapter, FALSE); + + if (lm_context->sfp_detection) { + err = al_eth_module_detect(lm_context, new_mode); + if (err != 0) { + al_err("module_detection failed!\n"); + return (err); + } + + lm_context->mode = *new_mode; + } else { + lm_context->mode = lm_context->default_mode; + *new_mode = lm_context->mode; + } + + if (*old_mode != *new_mode) { + al_info("%s: New SFP mode detected %s -> %s\n", + __func__, al_eth_lm_mode_convert_to_str(*old_mode), + al_eth_lm_mode_convert_to_str(*new_mode)); + + lm_context->rx_param_dirty = 1; + lm_context->tx_param_dirty = 1; + + lm_context->new_port = TRUE; + + if ((*new_mode != AL_ETH_LM_MODE_DISCONNECTED) && (lm_context->led_config)) { + struct al_eth_lm_led_config_data data = {0}; + + switch (*new_mode) { + case AL_ETH_LM_MODE_10G_OPTIC: + case AL_ETH_LM_MODE_10G_DA: + data.speed = AL_ETH_LM_LED_CONFIG_10G; + break; + case AL_ETH_LM_MODE_1G: + data.speed = AL_ETH_LM_LED_CONFIG_1G; + break; + case AL_ETH_LM_MODE_25G: + data.speed = AL_ETH_LM_LED_CONFIG_25G; + break; + default: + al_err("%s: unknown LM mode!\n", __func__); + }; + + lm_context->led_config(lm_context->i2c_context, &data); + } + } + + return (0); +} + +int +al_eth_lm_link_establish(struct al_eth_lm_context *lm_context, boolean_t *link_up) +{ + boolean_t signal_detected; + int ret = 0; + + switch (lm_context->link_state) { + case AL_ETH_LM_LINK_UP: + *link_up = TRUE; + lm_debug("%s: return link up\n", __func__); + + return (0); + case AL_ETH_LM_LINK_DOWN_RF: + *link_up = FALSE; + lm_debug("%s: return link down (DOWN_RF)\n", __func__); + + return (0); + case AL_ETH_LM_LINK_DOWN: + break; + }; + + /** + * At this point we will get LM disable only if changed to disable after link detection + * finished. in this case link will not be established until LM will be enable again. + */ + if (lm_context->lm_pause) { + boolean_t lm_pause = lm_context->lm_pause(lm_context->i2c_context); + if (lm_pause == TRUE) { + *link_up = FALSE; + + return (0); + } + } + + if ((lm_context->new_port) && (lm_context->retimer_exist)) { + al_eth_serdes_static_rx_params_set(lm_context); + al_eth_serdes_static_tx_params_set(lm_context); +#if 0 + al_eth_lm_retimer_config(lm_context); + DELAY(AL_ETH_LM_RETIMER_LINK_STATUS_DELAY); +#endif + + if (retimer[lm_context->retimer_type].config(lm_context)) { + al_info("%s: failed to configure the retimer\n", __func__); + + *link_up = FALSE; + return (1); + } + + lm_context->new_port = FALSE; + + DELAY(1000); + } + + if (lm_context->retimer_exist) { + if (retimer[lm_context->retimer_type].rx_adaptation) { + ret = retimer[lm_context->retimer_type].rx_adaptation(lm_context); + + if (ret != 0) { + lm_debug("retimer rx is not ready\n"); + *link_up = FALSE; + + return (0); + } + } + } + + signal_detected = lm_context->serdes_obj->signal_is_detected( + lm_context->serdes_obj, + lm_context->lane); + + if (signal_detected == FALSE) { + /* if no signal detected there is nothing to do */ + lm_debug("serdes signal is down\n"); + *link_up = AL_FALSE; + return 0; + } + + if (lm_context->serdes_obj->type_get() == AL_SRDS_TYPE_25G) { + lm_debug("%s: serdes 25G - perform rx gearbox reset\n", __func__); + al_eth_gearbox_reset(lm_context->adapter, FALSE, TRUE); + DELAY(AL_ETH_LM_GEARBOX_RESET_DELAY); + } + + + if (lm_context->retimer_exist) { + DELAY(AL_ETH_LM_RETIMER_LINK_STATUS_DELAY); + + ret = al_eth_lm_check_for_link(lm_context, link_up); + + if (ret == 0) { + lm_debug("%s: link is up with retimer\n", __func__); + return 0; + } + + return ret; + } + + if ((lm_context->mode == AL_ETH_LM_MODE_10G_DA) && (lm_context->link_training)) { + lm_context->local_adv.transmitted_nonce = lm_context->get_random_byte(); + lm_context->local_adv.transmitted_nonce &= 0x1f; + + ret = al_eth_an_lt_execute(lm_context->adapter, + lm_context->serdes_obj, + lm_context->lane, + &lm_context->local_adv, + &lm_context->partner_adv); + + lm_context->rx_param_dirty = 1; + lm_context->tx_param_dirty = 1; + + if (ret == 0) { + al_info("%s: link training finished successfully\n", __func__); + lm_context->link_training_failures = 0; + ret = al_eth_lm_check_for_link(lm_context, link_up); + + if (ret == 0) { + lm_debug("%s: link is up with LT\n", __func__); + return (0); + } + + } + + lm_context->link_training_failures++; + if (lm_context->link_training_failures > AL_ETH_LT_FAILURES_TO_RESET) { + lm_debug("%s: failed to establish LT %d times. reset serdes\n", + __func__, AL_ETH_LT_FAILURES_TO_RESET); + + lm_context->serdes_obj->pma_hard_reset_lane( + lm_context->serdes_obj, + lm_context->lane, + TRUE); + lm_context->serdes_obj->pma_hard_reset_lane( + lm_context->serdes_obj, + lm_context->lane, + FALSE); + lm_context->link_training_failures = 0; + } + } + + al_eth_serdes_static_tx_params_set(lm_context); + + if ((lm_context->mode == AL_ETH_LM_MODE_10G_DA) && + (lm_context->rx_equal)) { + ret = al_eth_rx_equal_run(lm_context); + + if (ret == 0) { + DELAY(AL_ETH_LM_LINK_STATUS_DELAY); + ret = al_eth_lm_check_for_link(lm_context, link_up); + + if (ret == 0) { + lm_debug("%s: link is up with Rx Equalization\n", __func__); + return (0); + } + } + } + + al_eth_serdes_static_rx_params_set(lm_context); + + DELAY(AL_ETH_LM_LINK_STATUS_DELAY); + + ret = al_eth_lm_check_for_link(lm_context, link_up); + + if (ret == 0) { + lm_debug("%s: link is up with static parameters\n", __func__); + return (0); + } + + *link_up = FALSE; + return (1); +} + +int +al_eth_lm_static_parameters_override(struct al_eth_lm_context *lm_context, + struct al_serdes_adv_tx_params *tx_params, + struct al_serdes_adv_rx_params *rx_params) +{ + + if (tx_params != NULL) { + lm_context->tx_params_override = *tx_params; + lm_context->tx_param_dirty = 1; + lm_context->serdes_tx_params_valid = TRUE; + } + + if (rx_params != NULL) { + lm_context->rx_params_override = *rx_params; + lm_context->rx_param_dirty = 1; + lm_context->serdes_rx_params_valid = TRUE; + } + + return (0); +} + +int +al_eth_lm_static_parameters_override_disable(struct al_eth_lm_context *lm_context, + boolean_t tx_params, boolean_t rx_params) +{ + + if (tx_params != 0) + lm_context->serdes_tx_params_valid = FALSE; + if (rx_params != 0) + lm_context->serdes_tx_params_valid = FALSE; + + return (0); +} + +int +al_eth_lm_static_parameters_get(struct al_eth_lm_context *lm_context, + struct al_serdes_adv_tx_params *tx_params, + struct al_serdes_adv_rx_params *rx_params) +{ + + if (tx_params != NULL) { + if (lm_context->serdes_tx_params_valid) + *tx_params = lm_context->tx_params_override; + else + lm_context->serdes_obj->tx_advanced_params_get( + lm_context->serdes_obj, + lm_context->lane, + tx_params); + } + + if (rx_params != NULL) { + if (lm_context->serdes_rx_params_valid) + *rx_params = lm_context->rx_params_override; + else + lm_context->serdes_obj->rx_advanced_params_get( + lm_context->serdes_obj, + lm_context->lane, + rx_params); + } + + return (0); +} + +const char * +al_eth_lm_mode_convert_to_str(enum al_eth_lm_link_mode val) +{ + + switch (val) { + case AL_ETH_LM_MODE_DISCONNECTED: + return ("AL_ETH_LM_MODE_DISCONNECTED"); + case AL_ETH_LM_MODE_10G_OPTIC: + return ("AL_ETH_LM_MODE_10G_OPTIC"); + case AL_ETH_LM_MODE_10G_DA: + return ("AL_ETH_LM_MODE_10G_DA"); + case AL_ETH_LM_MODE_1G: + return ("AL_ETH_LM_MODE_1G"); + case AL_ETH_LM_MODE_25G: + return ("AL_ETH_LM_MODE_25G"); + } + + return ("N/A"); +} + +void +al_eth_lm_debug_mode_set(struct al_eth_lm_context *lm_context, + boolean_t enable) +{ + + lm_context->debug = enable; +} diff --git a/sys/dev/al_eth/al_init_eth_lm.h b/sys/dev/al_eth/al_init_eth_lm.h new file mode 100644 index 000000000000..fbe70115f2f1 --- /dev/null +++ b/sys/dev/al_eth/al_init_eth_lm.h @@ -0,0 +1,376 @@ +/*- + * Copyright (c) 2015,2016 Annapurna Labs Ltd. and affiliates + * All rights reserved. + * + * Developed by Semihalf. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +/** + * Ethernet + * @{ + * @file al_init_eth_lm.h + * + * @brief ethernet link management common utilities + * + * Common operation example: + * @code + * int main() + * { + * struct al_eth_lm_context lm_context; + * struct al_eth_lm_init_params lm_params; + * enum al_eth_lm_link_mode old_mode; + * enum al_eth_lm_link_mode new_mode; + * al_bool fault; + * al_bool link_up; + * int rc = 0; + * + * lm_params.adapter = hal_adapter; + * lm_params.serdes_obj = serdes; + * lm_params.grp = grp; + * lm_params.lane = lane; + * lm_params.sfp_detection = true; + * lm_params.link_training = true; + * lm_params.rx_equal = true + * lm_params.static_values = true; + * lm_params.kr_fec_enable = false; + * lm_params.eeprom_read = &my_eeprom_read; + * lm_params.eeprom_context = context; + * lm_params.get_random_byte = &my_rand_byte; + * lm_params.default_mode = AL_ETH_LM_MODE_10G_DA; + * + * al_eth_lm_init(&lm_context, &lm_params); + * + * rc = al_eth_lm_link_detection(&lm_context, &fault, &old_mode, &new_mode); + * if (fault == false) + * return; // in this case the link is still up + * + * if (rc) { + * printf("link detection failed on error\n"); + * return; + * } + * + * if (old_mode != new_mode) { + * // perform serdes configuration if needed + * + * // mac stop / start / config if needed + * } + * + * spin_lock(lock); + * rc = al_eth_lm_link_establish($lm_context, &link_up); + * spin_unlock(lock); + * if (rc) { + * printf("establish link failed\n"); + * return; + * } + * + * if (link_up) + * printf("Link established successfully\n"); + * else + * printf("No signal found. probably the link partner is disconnected\n"); + * } + * @endcode + * + */ + +#ifndef __AL_INIT_ETH_LM_H__ +#define __AL_INIT_ETH_LM_H__ + +#include +#include +#include "al_init_eth_kr.h" + +enum al_eth_lm_link_mode { + AL_ETH_LM_MODE_DISCONNECTED, + AL_ETH_LM_MODE_10G_OPTIC, + AL_ETH_LM_MODE_10G_DA, + AL_ETH_LM_MODE_1G, + AL_ETH_LM_MODE_25G, +}; + +enum al_eth_lm_max_speed { + AL_ETH_LM_MAX_SPEED_MAX, + AL_ETH_LM_MAX_SPEED_25G, + AL_ETH_LM_MAX_SPEED_10G, + AL_ETH_LM_MAX_SPEED_1G, +}; + +enum al_eth_lm_link_state { + AL_ETH_LM_LINK_DOWN, + AL_ETH_LM_LINK_DOWN_RF, + AL_ETH_LM_LINK_UP, +}; + +enum al_eth_lm_led_config_speed { + AL_ETH_LM_LED_CONFIG_1G, + AL_ETH_LM_LED_CONFIG_10G, + AL_ETH_LM_LED_CONFIG_25G, +}; + +struct al_eth_lm_led_config_data { + enum al_eth_lm_led_config_speed speed; +}; + + +struct al_eth_lm_context { + struct al_hal_eth_adapter *adapter; + struct al_serdes_grp_obj *serdes_obj; + enum al_serdes_lane lane; + + uint32_t link_training_failures; + + boolean_t tx_param_dirty; + boolean_t serdes_tx_params_valid; + struct al_serdes_adv_tx_params tx_params_override; + boolean_t rx_param_dirty; + boolean_t serdes_rx_params_valid; + struct al_serdes_adv_rx_params rx_params_override; + + struct al_eth_an_adv local_adv; + struct al_eth_an_adv partner_adv; + + enum al_eth_lm_link_mode mode; + uint8_t da_len; + boolean_t debug; + + /* configurations */ + boolean_t sfp_detection; + uint8_t sfp_bus_id; + uint8_t sfp_i2c_addr; + + enum al_eth_lm_link_mode default_mode; + uint8_t default_dac_len; + boolean_t link_training; + boolean_t rx_equal; + boolean_t static_values; + + boolean_t retimer_exist; + enum al_eth_retimer_type retimer_type; + uint8_t retimer_bus_id; + uint8_t retimer_i2c_addr; + enum al_eth_retimer_channel retimer_channel; + + /* services */ + int (*i2c_read)(void *handle, uint8_t bus_id, uint8_t i2c_addr, + uint8_t reg_addr, uint8_t *val); + int (*i2c_write)(void *handle, uint8_t bus_id, uint8_t i2c_addr, + uint8_t reg_addr, uint8_t val); + void *i2c_context; + uint8_t (*get_random_byte)(void); + + int (*gpio_get)(unsigned int gpio); + uint32_t gpio_present; + + enum al_eth_retimer_channel retimer_tx_channel; + boolean_t retimer_configured; + + enum al_eth_lm_max_speed max_speed; + + boolean_t sfp_detect_force_mode; + + enum al_eth_lm_link_state link_state; + boolean_t new_port; + + boolean_t (*lm_pause)(void *handle); + + void (*led_config)(void *handle, struct al_eth_lm_led_config_data *data); +}; + +struct al_eth_lm_init_params { + /* pointer to HAL context */ + struct al_hal_eth_adapter *adapter; + /* pointer to serdes object */ + struct al_serdes_grp_obj *serdes_obj; + /* serdes lane for this port */ + enum al_serdes_lane lane; + + /* + * set to true to perform sfp detection if the link is down. + * when set to true, eeprom_read below should NOT be NULL. + */ + boolean_t sfp_detection; + /* i2c bus id of the SFP for this port */ + uint8_t sfp_bus_id; + /* i2c addr of the SFP for this port */ + uint8_t sfp_i2c_addr; + /* + * default mode, and dac length will be used in case sfp_detection + * is not set or in case the detection failed. + */ + enum al_eth_lm_link_mode default_mode; + uint8_t default_dac_len; + + /* the i2c bus id and addr of the retimer in case it exist */ + uint8_t retimer_bus_id; + uint8_t retimer_i2c_addr; + /* retimer channel connected to this port */ + enum al_eth_retimer_channel retimer_channel; + enum al_eth_retimer_channel retimer_tx_channel; + /* retimer type if exist */ + enum al_eth_retimer_type retimer_type; + + /* + * the following parameters control what mechanisms to run + * on link_establish with the following steps: + * - if retimer_exist is set, the retimer will be configured based on DA len. + * - if link_training is set and DA detected run link training. if succeed return 0 + * - if rx_equal is set serdes equalization will be run to configure the rx parameters. + * - if static_values is set, tx and rx values will be set based on static values. + */ + boolean_t retimer_exist; + boolean_t link_training; + boolean_t rx_equal; + boolean_t static_values; + + /* enable / disable fec capabilities in AN */ + boolean_t kr_fec_enable; + + /* + * pointer to function that's read 1 byte from eeprom + * in case no eeprom is connected should return -ETIMEDOUT + */ + int (*i2c_read)(void *handle, uint8_t bus_id, uint8_t i2c_addr, + uint8_t reg_addr, uint8_t *val); + int (*i2c_write)(void *handle, uint8_t bus_id, uint8_t i2c_addr, + uint8_t reg_addr, uint8_t val); + void *i2c_context; + /* pointer to function that return 1 rand byte */ + uint8_t (*get_random_byte)(void); + + /* pointer to function that gets GPIO value - if NULL gpio present won't be used */ + int (*gpio_get)(unsigned int gpio); + /* gpio number connected to the SFP present pin */ + uint32_t gpio_present; + + enum al_eth_lm_max_speed max_speed; + + /* in case force mode is true - the default mode will be set regardless to + * the SFP EEPROM content */ + boolean_t sfp_detect_force_mode; + + /* lm pause callback - in case it return true the LM will try to preserve + * the current link status and will not try to establish new link (and will not + * access to i2c bus) */ + boolean_t (*lm_pause)(void *handle); + + /* config ethernet LEDs according to data. can be NULL if no configuration needed */ + void (*led_config)(void *handle, struct al_eth_lm_led_config_data *data); +}; + +/** + * initialize link management context and set configuration + * + * @param lm_context pointer to link management context + * @param params parameters passed from upper layer + * + * @return 0 in case of success. otherwise on failure. + */ +int al_eth_lm_init(struct al_eth_lm_context *lm_context, + struct al_eth_lm_init_params *params); + +/** + * perform link status check. in case link is down perform sfp detection + * + * @param lm_context pointer to link management context + * @param link_fault indicate if the link is down + * @param old_mode the last working mode + * @param new_mode the new mode detected in this call + * + * @return 0 in case of success. otherwise on failure. + */ +int al_eth_lm_link_detection(struct al_eth_lm_context *lm_context, + boolean_t *link_fault, enum al_eth_lm_link_mode *old_mode, + enum al_eth_lm_link_mode *new_mode); + +/** + * run LT, rx equalization and static values override according to configuration + * This function MUST be called inside a lock as it using common serdes registers + * + * @param lm_context pointer to link management context + * @param link_up set to true in case link is establish successfully + * + * @return < 0 in case link was failed to be established + */ +int al_eth_lm_link_establish(struct al_eth_lm_context *lm_context, + boolean_t *link_up); + +/** + * override the default static parameters + * + * @param lm_context pointer to link management context + * @param tx_params pointer to new tx params + * @param rx_params pointer to new rx params + * + * @return 0 in case of success. otherwise on failure. + **/ +int al_eth_lm_static_parameters_override(struct al_eth_lm_context *lm_context, + struct al_serdes_adv_tx_params *tx_params, + struct al_serdes_adv_rx_params *rx_params); + +/** + * disable serdes parameters override + * + * @param lm_context pointer to link management context + * @param tx_params set to true to disable override of tx params + * @param rx_params set to true to disable override of rx params + * + * @return 0 in case of success. otherwise on failure. + **/ +int al_eth_lm_static_parameters_override_disable(struct al_eth_lm_context *lm_context, + boolean_t tx_params, boolean_t rx_params); + +/** + * get the static parameters that are being used + * if the parameters was override - return the override values + * else return the current values of the parameters + * + * @param lm_context pointer to link management context + * @param tx_params pointer to new tx params + * @param rx_params pointer to new rx params + * + * @return 0 in case of success. otherwise on failure. + */ +int al_eth_lm_static_parameters_get(struct al_eth_lm_context *lm_context, + struct al_serdes_adv_tx_params *tx_params, + struct al_serdes_adv_rx_params *rx_params); + +/** + * convert link management mode to string + * + * @param val link management mode + * + * @return string of the mode + */ +const char *al_eth_lm_mode_convert_to_str(enum al_eth_lm_link_mode val); + +/** + * print all debug messages + * + * @param lm_context pointer to link management context + * @param enable set to true to enable debug mode + */ +void al_eth_lm_debug_mode_set(struct al_eth_lm_context *lm_context, + boolean_t enable); +#endif diff --git a/sys/dev/atkbdc/atkbdc.c b/sys/dev/atkbdc/atkbdc.c index 695e6bfd84ab..d9190f8bdbe2 100644 --- a/sys/dev/atkbdc/atkbdc.c +++ b/sys/dev/atkbdc/atkbdc.c @@ -122,7 +122,7 @@ struct atkbdc_quirks { }; static struct atkbdc_quirks quirks[] = { - {"coreboot", "Acer", "Peppy", + {"coreboot", NULL, NULL, KBDC_QUIRK_KEEP_ACTIVATED | KBDC_QUIRK_IGNORE_PROBE_RESULT | KBDC_QUIRK_RESET_AFTER_PROBE | KBDC_QUIRK_SETLEDS_ON_INIT}, diff --git a/sys/dev/bhnd/cores/usb/bhnd_ehci.c b/sys/dev/bhnd/cores/usb/bhnd_ehci.c index deb67b05c2fc..51c69f67230c 100644 --- a/sys/dev/bhnd/cores/usb/bhnd_ehci.c +++ b/sys/dev/bhnd/cores/usb/bhnd_ehci.c @@ -191,16 +191,10 @@ static int bhnd_ehci_detach(device_t self) { ehci_softc_t *sc; - device_t bdev; int err; sc = device_get_softc(self); - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/dev/bhnd/cores/usb/bhnd_ohci.c b/sys/dev/bhnd/cores/usb/bhnd_ohci.c index b368cc583e0c..1f3d345b4b1d 100644 --- a/sys/dev/bhnd/cores/usb/bhnd_ohci.c +++ b/sys/dev/bhnd/cores/usb/bhnd_ohci.c @@ -163,15 +163,9 @@ static int bhnd_ohci_detach(device_t self) { ohci_softc_t *sc; - device_t bdev; sc = device_get_softc(self); - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/dev/bxe/bxe.c b/sys/dev/bxe/bxe.c index a5c13ea600f3..c5daac58da56 100644 --- a/sys/dev/bxe/bxe.c +++ b/sys/dev/bxe/bxe.c @@ -27,7 +27,7 @@ #include __FBSDID("$FreeBSD$"); -#define BXE_DRIVER_VERSION "1.78.81" +#define BXE_DRIVER_VERSION "1.78.89" #include "bxe.h" #include "ecore_sp.h" @@ -489,7 +489,14 @@ static const struct { { STATS_OFFSET32(mbuf_alloc_tpa), 4, STATS_FLAGS_FUNC, "mbuf_alloc_tpa"}, { STATS_OFFSET32(tx_queue_full_return), - 4, STATS_FLAGS_FUNC, "tx_queue_full_return"} + 4, STATS_FLAGS_FUNC, "tx_queue_full_return"}, + { STATS_OFFSET32(tx_request_link_down_failures), + 4, STATS_FLAGS_FUNC, "tx_request_link_down_failures"}, + { STATS_OFFSET32(bd_avail_too_less_failures), + 4, STATS_FLAGS_FUNC, "bd_avail_too_less_failures"}, + { STATS_OFFSET32(tx_mq_not_empty), + 4, STATS_FLAGS_FUNC, "tx_mq_not_empty"} + }; static const struct { @@ -602,7 +609,14 @@ static const struct { { Q_STATS_OFFSET32(mbuf_alloc_tpa), 4, "mbuf_alloc_tpa"}, { Q_STATS_OFFSET32(tx_queue_full_return), - 4, "tx_queue_full_return"} + 4, "tx_queue_full_return"}, + { Q_STATS_OFFSET32(tx_request_link_down_failures), + 4, "tx_request_link_down_failures"}, + { Q_STATS_OFFSET32(bd_avail_too_less_failures), + 4, "bd_avail_too_less_failures"}, + { Q_STATS_OFFSET32(tx_mq_not_empty), + 4, "tx_mq_not_empty"} + }; #define BXE_NUM_ETH_STATS ARRAY_SIZE(bxe_eth_stats_arr) @@ -5599,7 +5613,7 @@ bxe_tx_start(if_t ifp) BXE_FP_TX_UNLOCK(fp); } -#if __FreeBSD_version >= 800000 +#if __FreeBSD_version >= 901504 static int bxe_tx_mq_start_locked(struct bxe_softc *sc, @@ -5621,11 +5635,16 @@ bxe_tx_mq_start_locked(struct bxe_softc *sc, return (EINVAL); } - if (!sc->link_vars.link_up || - (if_getdrvflags(ifp) & - (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) { - if (m != NULL) - rc = drbr_enqueue(ifp, tx_br, m); + if (m != NULL) { + rc = drbr_enqueue(ifp, tx_br, m); + if (rc != 0) { + fp->eth_q_stats.tx_soft_errors++; + goto bxe_tx_mq_start_locked_exit; + } + } + + if (!sc->link_vars.link_up || !(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + fp->eth_q_stats.tx_request_link_down_failures++; goto bxe_tx_mq_start_locked_exit; } @@ -5635,24 +5654,22 @@ bxe_tx_mq_start_locked(struct bxe_softc *sc, fp->eth_q_stats.tx_max_drbr_queue_depth = depth; } - if (m == NULL) { - /* no new work, check for pending frames */ - next = drbr_dequeue_drv(ifp, tx_br); - } else if (drbr_needs_enqueue_drv(ifp, tx_br)) { - /* have both new and pending work, maintain packet order */ - rc = drbr_enqueue(ifp, tx_br, m); - if (rc != 0) { - fp->eth_q_stats.tx_soft_errors++; - goto bxe_tx_mq_start_locked_exit; - } - next = drbr_dequeue_drv(ifp, tx_br); - } else { - /* new work only and nothing pending */ - next = m; - } - /* keep adding entries while there are frames to send */ - while (next != NULL) { + while ((next = drbr_peek(ifp, tx_br)) != NULL) { + /* handle any completions if we're running low */ + tx_bd_avail = bxe_tx_avail(sc, fp); + if (tx_bd_avail < BXE_TX_CLEANUP_THRESHOLD) { + /* bxe_txeof will set IFF_DRV_OACTIVE appropriately */ + bxe_txeof(sc, fp); + tx_bd_avail = bxe_tx_avail(sc, fp); + if (tx_bd_avail < (BXE_TSO_MAX_SEGMENTS + 1)) { + fp->eth_q_stats.bd_avail_too_less_failures++; + m_freem(next); + drbr_advance(ifp, tx_br); + rc = ENOBUFS; + break; + } + } /* the mbuf now belongs to us */ fp->eth_q_stats.mbuf_alloc_tx++; @@ -5668,11 +5685,11 @@ bxe_tx_mq_start_locked(struct bxe_softc *sc, if (next != NULL) { /* mark the TX queue as full and save the frame */ if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); - /* XXX this may reorder the frame */ - rc = drbr_enqueue(ifp, tx_br, next); + drbr_putback(ifp, tx_br, next); fp->eth_q_stats.mbuf_alloc_tx--; fp->eth_q_stats.tx_frames_deferred++; - } + } else + drbr_advance(ifp, tx_br); /* stop looking for more work */ break; @@ -5684,18 +5701,7 @@ bxe_tx_mq_start_locked(struct bxe_softc *sc, /* send a copy of the frame to any BPF listeners */ if_etherbpfmtap(ifp, next); - tx_bd_avail = bxe_tx_avail(sc, fp); - - /* handle any completions if we're running low */ - if (tx_bd_avail < BXE_TX_CLEANUP_THRESHOLD) { - /* bxe_txeof will set IFF_DRV_OACTIVE appropriately */ - bxe_txeof(sc, fp); - if (if_getdrvflags(ifp) & IFF_DRV_OACTIVE) { - break; - } - } - - next = drbr_dequeue_drv(ifp, tx_br); + drbr_advance(ifp, tx_br); } /* all TX packets were dequeued and/or the tx ring is full */ @@ -5705,10 +5711,28 @@ bxe_tx_mq_start_locked(struct bxe_softc *sc, } bxe_tx_mq_start_locked_exit: + /* If we didn't drain the drbr, enqueue a task in the future to do it. */ + if (!drbr_empty(ifp, tx_br)) { + fp->eth_q_stats.tx_mq_not_empty++; + taskqueue_enqueue_timeout(fp->tq, &fp->tx_timeout_task, 1); + } return (rc); } +static void +bxe_tx_mq_start_deferred(void *arg, + int pending) +{ + struct bxe_fastpath *fp = (struct bxe_fastpath *)arg; + struct bxe_softc *sc = fp->sc; + if_t ifp = sc->ifp; + + BXE_FP_TX_LOCK(fp); + bxe_tx_mq_start_locked(sc, ifp, fp, NULL); + BXE_FP_TX_UNLOCK(fp); +} + /* Multiqueue (TSS) dispatch routine. */ static int bxe_tx_mq_start(struct ifnet *ifp, @@ -5730,8 +5754,10 @@ bxe_tx_mq_start(struct ifnet *ifp, if (BXE_FP_TX_TRYLOCK(fp)) { rc = bxe_tx_mq_start_locked(sc, ifp, fp, m); BXE_FP_TX_UNLOCK(fp); - } else + } else { rc = drbr_enqueue(ifp, fp->tx_br, m); + taskqueue_enqueue(fp->tq, &fp->tx_task); + } return (rc); } @@ -5766,7 +5792,7 @@ bxe_mq_flush(struct ifnet *ifp) if_qflush(ifp); } -#endif /* FreeBSD_version >= 800000 */ +#endif /* FreeBSD_version >= 901504 */ static uint16_t bxe_cid_ilt_lines(struct bxe_softc *sc) @@ -6126,7 +6152,7 @@ bxe_free_fp_buffers(struct bxe_softc *sc) for (i = 0; i < sc->num_queues; i++) { fp = &sc->fp[i]; -#if __FreeBSD_version >= 800000 +#if __FreeBSD_version >= 901504 if (fp->tx_br != NULL) { /* just in case bxe_mq_flush() wasn't called */ if (mtx_initialized(&fp->tx_mtx)) { @@ -6953,6 +6979,8 @@ bxe_link_attn(struct bxe_softc *sc) uint32_t pause_enabled = 0; struct host_port_stats *pstats; int cmng_fns; + struct bxe_fastpath *fp; + int i; /* Make sure that we are synced with the current statistics */ bxe_stats_handle(sc, STATS_EVENT_STOP); @@ -6984,6 +7012,12 @@ bxe_link_attn(struct bxe_softc *sc) if (sc->state == BXE_STATE_OPEN) { bxe_stats_handle(sc, STATS_EVENT_LINK_UP); } + + /* Restart tx when the link comes back. */ + FOR_EACH_ETH_QUEUE(sc, i) { + fp = &sc->fp[i]; + taskqueue_enqueue(fp->tq, &fp->tx_task); + } } if (sc->link_vars.link_up && sc->link_vars.line_speed) { @@ -9035,6 +9069,10 @@ bxe_interrupt_detach(struct bxe_softc *sc) fp = &sc->fp[i]; if (fp->tq) { taskqueue_drain(fp->tq, &fp->tq_task); + taskqueue_drain(fp->tq, &fp->tx_task); + while (taskqueue_cancel_timeout(fp->tq, &fp->tx_timeout_task, + NULL)) + taskqueue_drain_timeout(fp->tq, &fp->tx_timeout_task); taskqueue_free(fp->tq); fp->tq = NULL; } @@ -9067,9 +9105,9 @@ bxe_interrupt_attach(struct bxe_softc *sc) snprintf(sc->sp_tq_name, sizeof(sc->sp_tq_name), "bxe%d_sp_tq", sc->unit); TASK_INIT(&sc->sp_tq_task, 0, bxe_handle_sp_tq, sc); - sc->sp_tq = taskqueue_create_fast(sc->sp_tq_name, M_NOWAIT, - taskqueue_thread_enqueue, - &sc->sp_tq); + sc->sp_tq = taskqueue_create(sc->sp_tq_name, M_NOWAIT, + taskqueue_thread_enqueue, + &sc->sp_tq); taskqueue_start_threads(&sc->sp_tq, 1, PWAIT, /* lower priority */ "%s", sc->sp_tq_name); @@ -9079,9 +9117,12 @@ bxe_interrupt_attach(struct bxe_softc *sc) snprintf(fp->tq_name, sizeof(fp->tq_name), "bxe%d_fp%d_tq", sc->unit, i); TASK_INIT(&fp->tq_task, 0, bxe_handle_fp_tq, fp); - fp->tq = taskqueue_create_fast(fp->tq_name, M_NOWAIT, - taskqueue_thread_enqueue, - &fp->tq); + TASK_INIT(&fp->tx_task, 0, bxe_tx_mq_start_deferred, fp); + fp->tq = taskqueue_create(fp->tq_name, M_NOWAIT, + taskqueue_thread_enqueue, + &fp->tq); + TIMEOUT_TASK_INIT(fp->tq, &fp->tx_timeout_task, 0, + bxe_tx_mq_start_deferred, fp); taskqueue_start_threads(&fp->tq, 1, PI_NET, /* higher priority */ "%s", fp->tq_name); } @@ -12114,8 +12155,6 @@ static void bxe_periodic_callout_func(void *xsc) { struct bxe_softc *sc = (struct bxe_softc *)xsc; - struct bxe_fastpath *fp; - uint16_t tx_bd_avail; int i; if (!BXE_CORE_TRYLOCK(sc)) { @@ -12136,49 +12175,8 @@ bxe_periodic_callout_func(void *xsc) BLOGW(sc, "periodic callout exit (state=0x%x)\n", sc->state); BXE_CORE_UNLOCK(sc); return; - } - -#if __FreeBSD_version >= 800000 - - FOR_EACH_QUEUE(sc, i) { - fp = &sc->fp[i]; - - if (BXE_FP_TX_TRYLOCK(fp)) { - if_t ifp = sc->ifp; - /* - * If interface was stopped due to unavailable - * bds, try to process some tx completions - */ - (void) bxe_txeof(sc, fp); - - tx_bd_avail = bxe_tx_avail(sc, fp); - if (tx_bd_avail >= BXE_TX_CLEANUP_THRESHOLD) { - bxe_tx_mq_start_locked(sc, ifp, fp, NULL); - } - BXE_FP_TX_UNLOCK(fp); } - } -#else - - fp = &sc->fp[0]; - if (BXE_FP_TX_TRYLOCK(fp)) { - struct ifnet *ifp = sc->ifnet; - /* - * If interface was stopped due to unavailable - * bds, try to process some tx completions - */ - (void) bxe_txeof(sc, fp); - - tx_bd_avail = bxe_tx_avail(sc, fp); - if (tx_bd_avail >= BXE_TX_CLEANUP_THRESHOLD) { - bxe_tx_start_locked(sc, ifp, fp); - } - - BXE_FP_TX_UNLOCK(fp); - } - -#endif /* #if __FreeBSD_version >= 800000 */ /* Check for TX timeouts on any fastpath. */ FOR_EACH_QUEUE(sc, i) { @@ -12656,7 +12654,7 @@ bxe_init_ifnet(struct bxe_softc *sc) if_setioctlfn(ifp, bxe_ioctl); if_setstartfn(ifp, bxe_tx_start); if_setgetcounterfn(ifp, bxe_get_counter); -#if __FreeBSD_version >= 800000 +#if __FreeBSD_version >= 901504 if_settransmitfn(ifp, bxe_tx_mq_start); if_setqflushfn(ifp, bxe_mq_flush); #endif @@ -15699,7 +15697,7 @@ bxe_add_sysctls(struct bxe_softc *sc) static int bxe_alloc_buf_rings(struct bxe_softc *sc) { -#if __FreeBSD_version >= 800000 +#if __FreeBSD_version >= 901504 int i; struct bxe_fastpath *fp; @@ -15720,7 +15718,7 @@ bxe_alloc_buf_rings(struct bxe_softc *sc) static void bxe_free_buf_rings(struct bxe_softc *sc) { -#if __FreeBSD_version >= 800000 +#if __FreeBSD_version >= 901504 int i; struct bxe_fastpath *fp; diff --git a/sys/dev/bxe/bxe.h b/sys/dev/bxe/bxe.h index 40c9a36d93e7..3424ce834c0e 100644 --- a/sys/dev/bxe/bxe.h +++ b/sys/dev/bxe/bxe.h @@ -644,6 +644,9 @@ struct bxe_fastpath { struct taskqueue *tq; char tq_name[32]; + struct task tx_task; + struct timeout_task tx_timeout_task; + /* ethernet client ID (each fastpath set of RX/TX/CQE is a client) */ uint8_t cl_id; #define FP_CL_ID(fp) (fp->cl_id) @@ -2300,7 +2303,8 @@ void bxe_dump_mbuf_data(struct bxe_softc *sc, char *pTag, extern int bxe_grc_dump(struct bxe_softc *sc); #if __FreeBSD_version >= 800000 -#if __FreeBSD_version >= 1000000 +#if (__FreeBSD_version >= 1001513 && __FreeBSD_version < 1100000) ||\ + __FreeBSD_version >= 1100048 #define BXE_SET_FLOWID(m) M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE) #define BXE_VALID_FLOWID(m) (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) #else diff --git a/sys/dev/bxe/bxe_stats.h b/sys/dev/bxe/bxe_stats.h index a0f5792f9248..ad8cc139b950 100644 --- a/sys/dev/bxe/bxe_stats.h +++ b/sys/dev/bxe/bxe_stats.h @@ -266,6 +266,10 @@ struct bxe_eth_stats { /* num. of times tx queue full occurred */ uint32_t tx_queue_full_return; + /* debug stats */ + uint32_t tx_request_link_down_failures; + uint32_t bd_avail_too_less_failures; + uint32_t tx_mq_not_empty; }; @@ -372,6 +376,11 @@ struct bxe_eth_q_stats { /* num. of times tx queue full occurred */ uint32_t tx_queue_full_return; + + /* debug stats */ + uint32_t tx_request_link_down_failures; + uint32_t bd_avail_too_less_failures; + uint32_t tx_mq_not_empty; }; struct bxe_eth_stats_old { diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c index b863fb4a3e87..b960c2ebc649 100644 --- a/sys/dev/cxgbe/t4_main.c +++ b/sys/dev/cxgbe/t4_main.c @@ -6156,7 +6156,8 @@ sysctl_cim_qcfg(SYSCTL_HANDLER_ARGS) if (sb == NULL) return (ENOMEM); - sbuf_printf(sb, "Queue Base Size Thres RdPtr WrPtr SOP EOP Avail"); + sbuf_printf(sb, + " Queue Base Size Thres RdPtr WrPtr SOP EOP Avail"); for (i = 0; i < CIM_NUM_IBQ; i++, p += 4) sbuf_printf(sb, "\n%7s %5x %5u %5u %6x %4x %4u %4u %5u", diff --git a/sys/dev/dpaa/bman.c b/sys/dev/dpaa/bman.c index 02499c4902f4..dabdad4eb18a 100644 --- a/sys/dev/dpaa/bman.c +++ b/sys/dev/dpaa/bman.c @@ -114,10 +114,9 @@ bman_attach(device_t dev) bp.totalNumOfBuffers = BMAN_MAX_BUFFERS; bp.f_Exception = bman_exception; bp.h_App = sc; - bp.errIrq = (int)sc->sc_ires; + bp.errIrq = (uintptr_t)sc->sc_ires; bp.partBpidBase = 0; bp.partNumOfPools = BM_MAX_NUM_OF_POOLS; - printf("base address: %llx\n", (uint64_t)bp.baseAddress); sc->sc_bh = BM_Config(&bp); if (sc->sc_bh == NULL) diff --git a/sys/dev/dpaa/bman_portals.c b/sys/dev/dpaa/bman_portals.c index ba9997f5cb74..c0822d42d47c 100644 --- a/sys/dev/dpaa/bman_portals.c +++ b/sys/dev/dpaa/bman_portals.c @@ -95,7 +95,7 @@ bman_portals_detach(device_t dev) } if (sc->sc_dp[i].dp_ires != NULL) { - XX_DeallocIntr((int)sc->sc_dp[i].dp_ires); + XX_DeallocIntr((uintptr_t)sc->sc_dp[i].dp_ires); bus_release_resource(dev, SYS_RES_IRQ, sc->sc_dp[i].dp_irid, sc->sc_dp[i].dp_ires); } @@ -116,7 +116,8 @@ bman_portal_setup(struct bman_softc *bsc) struct dpaa_portals_softc *sc; t_BmPortalParam bpp; t_Handle portal; - unsigned int cpu, p; + unsigned int cpu; + uintptr_t p; /* Return NULL if we're not ready or while detach */ if (bp_sc == NULL) @@ -129,9 +130,9 @@ bman_portal_setup(struct bman_softc *bsc) cpu = PCPU_GET(cpuid); /* Check if portal is ready */ - while (atomic_cmpset_acq_32((uint32_t *)&sc->sc_dp[cpu].dp_ph, + while (atomic_cmpset_acq_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph, 0, -1) == 0) { - p = atomic_load_acq_32((uint32_t *)&sc->sc_dp[cpu].dp_ph); + p = atomic_load_acq_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph); /* Return if portal is already initialized */ if (p != 0 && p != -1) { @@ -153,7 +154,7 @@ bman_portal_setup(struct bman_softc *bsc) bpp.ciBaseAddress = rman_get_bushandle(sc->sc_rres[1]); bpp.h_Bm = bsc->sc_bh; bpp.swPortalId = cpu; - bpp.irq = (int)sc->sc_dp[cpu].dp_ires; + bpp.irq = (uintptr_t)sc->sc_dp[cpu].dp_ires; portal = BM_PORTAL_Config(&bpp); if (portal == NULL) @@ -162,8 +163,7 @@ bman_portal_setup(struct bman_softc *bsc) if (BM_PORTAL_Init(portal) != E_OK) goto err; - atomic_store_rel_32((uint32_t *)&sc->sc_dp[cpu].dp_ph, - (uint32_t)portal); + atomic_store_rel_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph, (uintptr_t)portal); sched_unpin(); @@ -173,7 +173,7 @@ bman_portal_setup(struct bman_softc *bsc) if (portal != NULL) BM_PORTAL_Free(portal); - atomic_store_rel_32((uint32_t *)&sc->sc_dp[cpu].dp_ph, 0); + atomic_store_rel_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph, 0); sched_unpin(); return (NULL); diff --git a/sys/dev/dpaa/fman.c b/sys/dev/dpaa/fman.c index 3e44db89580c..ee1f0cd8bf2e 100644 --- a/sys/dev/dpaa/fman.c +++ b/sys/dev/dpaa/fman.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -66,8 +67,8 @@ enum fman_mu_ram_map { struct fman_config { device_t fman_device; uintptr_t mem_base_addr; - int irq_num; - int err_irq_num; + uintptr_t irq_num; + uintptr_t err_irq_num; uint8_t fm_id; t_FmExceptionsCallback *exception_callback; t_FmBusErrorCallback *bus_error_callback; @@ -88,6 +89,8 @@ static struct fman_softc *fm_sc = NULL; static t_Handle fman_init(struct fman_softc *sc, struct fman_config *cfg) { + struct ofw_bus_devinfo obd; + phandle_t node; t_FmParams fm_params; t_Handle muram_handle, fm_handle; t_Error error; @@ -158,6 +161,16 @@ fman_init(struct fman_softc *sc, struct fman_config *cfg) device_printf(cfg->fman_device, "Hardware version: %d.%d.\n", revision_info.majorRev, revision_info.minorRev); + /* Initialize the simplebus part of things */ + simplebus_init(sc->sc_base.dev, 0); + + node = ofw_bus_get_node(sc->sc_base.dev); + for (node = OF_child(node); node > 0; node = OF_peer(node)) { + if (ofw_bus_gen_setup_devinfo(&obd, node) != 0) + continue; + simplebus_add_device(sc->sc_base.dev, node, 0, NULL, -1, NULL); + } + return (fm_handle); err2: @@ -173,7 +186,7 @@ fman_exception_callback(t_Handle app_handle, e_FmExceptions exception) struct fman_softc *sc; sc = app_handle; - device_printf(sc->dev, "FMan exception occurred.\n"); + device_printf(sc->sc_base.dev, "FMan exception occurred.\n"); } static void @@ -183,7 +196,7 @@ fman_error_callback(t_Handle app_handle, e_FmPortType port_type, struct fman_softc *sc; sc = app_handle; - device_printf(sc->dev, "FMan error occurred.\n"); + device_printf(sc->sc_base.dev, "FMan error occurred.\n"); } /** @} */ @@ -229,6 +242,18 @@ fman_get_bushandle(vm_offset_t *fm_base) return (0); } +int +fman_get_dev(device_t *fm_dev) +{ + + if (fm_sc == NULL) + return (ENOMEM); + + *fm_dev = fm_sc->sc_base.dev; + + return (0); +} + int fman_attach(device_t dev) { @@ -236,7 +261,7 @@ fman_attach(device_t dev) struct fman_config cfg; sc = device_get_softc(dev); - sc->dev = dev; + sc->sc_base.dev = dev; fm_sc = sc; /* Check if MallocSmart allocator is ready */ @@ -249,7 +274,7 @@ fman_attach(device_t dev) sc->mem_rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, - RF_ACTIVE); + RF_ACTIVE | RF_SHAREABLE); if (!sc->mem_res) { device_printf(dev, "could not allocate memory.\n"); return (ENXIO); @@ -282,8 +307,8 @@ fman_attach(device_t dev) cfg.fman_device = dev; cfg.fm_id = device_get_unit(dev); cfg.mem_base_addr = rman_get_bushandle(sc->mem_res); - cfg.irq_num = (int)sc->irq_res; - cfg.err_irq_num = (int)sc->err_irq_res; + cfg.irq_num = (uintptr_t)sc->irq_res; + cfg.err_irq_num = (uintptr_t)sc->err_irq_res; cfg.exception_callback = fman_exception_callback; cfg.bus_error_callback = fman_error_callback; diff --git a/sys/dev/dpaa/fman.h b/sys/dev/dpaa/fman.h index 5a421e056423..52bc61762c2b 100644 --- a/sys/dev/dpaa/fman.h +++ b/sys/dev/dpaa/fman.h @@ -29,11 +29,13 @@ #ifndef FMAN_H_ #define FMAN_H_ +#include + /** * FMan driver instance data. */ struct fman_softc { - device_t dev; + struct simplebus_softc sc_base; struct resource *mem_res; struct resource *irq_res; struct resource *err_irq_res; @@ -63,5 +65,6 @@ uint32_t fman_get_clock(struct fman_softc *sc); int fman_get_handle(t_Handle *fmh); int fman_get_muram_handle(t_Handle *muramh); int fman_get_bushandle(vm_offset_t *fm_base); +int fman_get_dev(device_t *fmd); #endif /* FMAN_H_ */ diff --git a/sys/dev/dpaa/fman_fdt.c b/sys/dev/dpaa/fman_fdt.c index 89c9eca1cb5b..b4693b5de956 100644 --- a/sys/dev/dpaa/fman_fdt.c +++ b/sys/dev/dpaa/fman_fdt.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -58,12 +59,8 @@ static device_method_t fman_methods[] = { { 0, 0 } }; -static driver_t fman_driver = { - "fman", - fman_methods, - sizeof(struct fman_softc), -}; - +DEFINE_CLASS_1(fman, fman_driver, fman_methods, + sizeof(struct fman_softc), simplebus_driver); static devclass_t fman_devclass; EARLY_DRIVER_MODULE(fman, simplebus, fman_driver, fman_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); @@ -88,7 +85,7 @@ fman_get_clock(struct fman_softc *sc) phandle_t node; pcell_t fman_clock; - dev = sc->dev; + dev = sc->sc_base.dev; node = ofw_bus_get_node(dev); if ((OF_getprop(node, "clock-frequency", &fman_clock, diff --git a/sys/dev/dpaa/fman_mdio.c b/sys/dev/dpaa/fman_mdio.c new file mode 100644 index 000000000000..fad7fea5e8ec --- /dev/null +++ b/sys/dev/dpaa/fman_mdio.c @@ -0,0 +1,211 @@ +/*- + * Copyright (c) 2016 Justin Hibbits + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include "fman.h" +#include "miibus_if.h" + +#define MDIO_LOCK() mtx_lock(&sc->sc_lock) +#define MDIO_UNLOCK() mtx_unlock(&sc->sc_lock) +#define MDIO_WRITE4(sc,r,v) \ + bus_space_write_4(&bs_be_tag, sc->sc_handle, sc->sc_offset + r, v) +#define MDIO_READ4(sc, r) \ + bus_space_read_4(&bs_be_tag, sc->sc_handle, sc->sc_offset + r) + +#define MDIO_MIIMCFG 0x0 +#define MDIO_MIIMCOM 0x4 +#define MIIMCOM_SCAN_CYCLE 0x00000002 +#define MIIMCOM_READ_CYCLE 0x00000001 +#define MDIO_MIIMADD 0x8 +#define MDIO_MIIMCON 0xc +#define MDIO_MIIMSTAT 0x10 +#define MDIO_MIIMIND 0x14 +#define MIIMIND_BUSY 0x1 + +static int pqmdio_fdt_probe(device_t dev); +static int pqmdio_fdt_attach(device_t dev); +static int pqmdio_detach(device_t dev); +static int pqmdio_miibus_readreg(device_t dev, int phy, int reg); +static int pqmdio_miibus_writereg(device_t dev, int phy, int reg, int value); + +struct pqmdio_softc { + struct mtx sc_lock; + bus_space_handle_t sc_handle; + int sc_offset; +}; + +static device_method_t pqmdio_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, pqmdio_fdt_probe), + DEVMETHOD(device_attach, pqmdio_fdt_attach), + DEVMETHOD(device_detach, pqmdio_detach), + + /* MII interface */ + DEVMETHOD(miibus_readreg, pqmdio_miibus_readreg), + DEVMETHOD(miibus_writereg, pqmdio_miibus_writereg), + + { 0, 0 } +}; + +static struct ofw_compat_data mdio_compat_data[] = { + {"fsl,fman-mdio", 0}, + {NULL, 0} +}; + +static driver_t pqmdio_driver = { + "pq_mdio", + pqmdio_methods, + sizeof(struct pqmdio_softc), +}; + +static int +pqmdio_fdt_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_search_compatible(dev, mdio_compat_data)->ocd_str) + return (ENXIO); + + device_set_desc(dev, "Freescale QorIQ MDIO"); + + return (BUS_PROBE_DEFAULT); +} + +static int +pqmdio_fdt_attach(device_t dev) +{ + struct pqmdio_softc *sc; + rman_res_t start, count; + + sc = device_get_softc(dev); + + fman_get_bushandle(&sc->sc_handle); + bus_get_resource(dev, SYS_RES_MEMORY, 0, &start, &count); + sc->sc_offset = start; + + mtx_init(&sc->sc_lock, device_get_nameunit(dev), "QorIQ MDIO lock", + MTX_DEF); + + return (0); +} + +static int +pqmdio_detach(device_t dev) +{ + struct pqmdio_softc *sc; + + sc = device_get_softc(dev); + + mtx_destroy(&sc->sc_lock); + + return (0); +} + +int +pqmdio_miibus_readreg(device_t dev, int phy, int reg) +{ + struct pqmdio_softc *sc; + int rv; + + sc = device_get_softc(dev); + + MDIO_LOCK(); + + MDIO_WRITE4(sc, MDIO_MIIMADD, (phy << 8) | reg); + MDIO_WRITE4(sc, MDIO_MIIMCOM, MIIMCOM_READ_CYCLE); + + MDIO_READ4(sc, MDIO_MIIMCOM); + + while ((MDIO_READ4(sc, MDIO_MIIMIND)) & MIIMIND_BUSY) + ; + + rv = MDIO_READ4(sc, MDIO_MIIMSTAT); + + MDIO_WRITE4(sc, MDIO_MIIMCOM, 0); + MDIO_READ4(sc, MDIO_MIIMCOM); + MDIO_UNLOCK(); + + return (rv); +} + +int +pqmdio_miibus_writereg(device_t dev, int phy, int reg, int value) +{ + struct pqmdio_softc *sc; + + sc = device_get_softc(dev); + + MDIO_LOCK(); + /* Stop the MII management read cycle */ + MDIO_WRITE4(sc, MDIO_MIIMCOM, 0); + MDIO_READ4(sc, MDIO_MIIMCOM); + + MDIO_WRITE4(sc, MDIO_MIIMADD, (phy << 8) | reg); + + MDIO_WRITE4(sc, MDIO_MIIMCON, value); + MDIO_READ4(sc, MDIO_MIIMCON); + + /* Wait till MII management write is complete */ + while ((MDIO_READ4(sc, MDIO_MIIMIND)) & MIIMIND_BUSY) + ; + MDIO_UNLOCK(); + + return (0); +} + +static devclass_t pqmdio_devclass; +DRIVER_MODULE(pqmdio, fman, pqmdio_driver, pqmdio_devclass, 0, 0); +DRIVER_MODULE(miibus, pqmdio, miibus_driver, miibus_devclass, 0, 0); +MODULE_DEPEND(pqmdio, miibus, 1, 1, 1); + diff --git a/sys/dev/dpaa/if_dtsec.c b/sys/dev/dpaa/if_dtsec.c index 249d605bb42e..d5f771251e3e 100644 --- a/sys/dev/dpaa/if_dtsec.c +++ b/sys/dev/dpaa/if_dtsec.c @@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -79,13 +80,6 @@ struct dtsec_fm_mac_ex_str { const int num; const char *str; }; - -/* XXX: Handle to FM_MAC instance of dTSEC0 */ -/* From QorIQ Data Path Acceleration Architecture Reference Manual, Rev 2, page - * 3-37, "The MII management hardware is shared by all dTSECs... only through - * the MIIM registers of dTSEC1 can external PHY's be accessed and configured." - */ -static t_Handle dtsec_mdio_mac_handle; /** @} */ @@ -205,8 +199,6 @@ dtsec_fm_mac_init(struct dtsec_softc *sc, uint8_t *mac) params.h_Fm = sc->sc_fmh; sc->sc_mach = FM_MAC_Config(¶ms); - if (sc->sc_hidden) - return (0); if (sc->sc_mach == NULL) { device_printf(sc->sc_dev, "couldn't configure FM_MAC module.\n" ); @@ -647,20 +639,6 @@ dtsec_attach(device_t dev) return (ENXIO); } - /* - * XXX: All phys are connected to MDIO interface of the first dTSEC - * device (dTSEC0). We have to save handle to the FM_MAC instance of - * dTSEC0, which is used later during phy's registers accesses. Another - * option would be adding new property to DTS pointing to correct dTSEC - * instance, of which FM_MAC handle has to be used for phy's registers - * accesses. We did not want to add new properties to DTS, thus this - * quite ugly hack. - */ - if (sc->sc_eth_id == 0) - dtsec_mdio_mac_handle = sc->sc_mach; - if (sc->sc_hidden) - return (0); - /* Init FMan TX port */ error = sc->sc_port_tx_init(sc, device_get_unit(sc->sc_dev)); if (error != 0) { @@ -797,47 +775,21 @@ int dtsec_miibus_readreg(device_t dev, int phy, int reg) { struct dtsec_softc *sc; - uint16_t data; - t_Error error; sc = device_get_softc(dev); - if (phy != sc->sc_phy_addr) - return (0xFFFF); - - DTSEC_MII_LOCK(sc); - error = FM_MAC_MII_ReadPhyReg(dtsec_mdio_mac_handle, phy, reg, &data); - DTSEC_MII_UNLOCK(sc); - if (error != E_OK) { - device_printf(dev, "Error while reading from PHY (NetCommSw " - "error: %d)\n", error); - return (0xFFFF); - } - - return ((int)data); + return (MIIBUS_READREG(sc->sc_mdio, phy, reg)); } int dtsec_miibus_writereg(device_t dev, int phy, int reg, int value) { + struct dtsec_softc *sc; - t_Error error; sc = device_get_softc(dev); - if (phy != sc->sc_phy_addr) - return (EINVAL); - - DTSEC_MII_LOCK(sc); - error = FM_MAC_MII_WritePhyReg(dtsec_mdio_mac_handle, phy, reg, value); - DTSEC_MII_UNLOCK(sc); - if (error != E_OK) { - device_printf(dev, "Error while writing to PHY (NetCommSw " - "error: %d).\n", error); - return (EIO); - } - - return (0); + return (MIIBUS_WRITEREG(sc->sc_mdio, phy, reg, value)); } void diff --git a/sys/dev/dpaa/if_dtsec.h b/sys/dev/dpaa/if_dtsec.h index 2e2e28fe24f9..0f9aa341d97e 100644 --- a/sys/dev/dpaa/if_dtsec.h +++ b/sys/dev/dpaa/if_dtsec.h @@ -75,6 +75,7 @@ struct dtsec_softc { uint32_t sc_port_tx_qman_chan; int sc_phy_addr; bool sc_hidden; + device_t sc_mdio; /* Params from fman_bus driver */ vm_offset_t sc_fm_base; diff --git a/sys/dev/dpaa/if_dtsec_fdt.c b/sys/dev/dpaa/if_dtsec_fdt.c index 25b2cfc2a712..49666f155a1d 100644 --- a/sys/dev/dpaa/if_dtsec_fdt.c +++ b/sys/dev/dpaa/if_dtsec_fdt.c @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$"); #include #include "if_dtsec.h" +#include "fman.h" static int dtsec_fdt_probe(device_t dev); @@ -105,6 +106,28 @@ dtsec_fdt_probe(device_t dev) return (BUS_PROBE_DEFAULT); } +static int +find_mdio(phandle_t phy_node, device_t mac, device_t *mdio_dev) +{ + device_t bus; + + while (phy_node > 0) { + if (ofw_bus_node_is_compatible(phy_node, "fsl,fman-mdio")) + break; + phy_node = OF_parent(phy_node); + } + + if (phy_node <= 0) + return (ENOENT); + + if (fman_get_dev(&bus) < 0) + return (ENOENT); + + *mdio_dev = ofw_bus_find_child_device_by_phandle(bus, phy_node); + + return (0); +} + static int dtsec_fdt_attach(device_t dev) { @@ -127,13 +150,9 @@ dtsec_fdt_attach(device_t dev) if (OF_getprop(enet_node, "local-mac-address", (void *)sc->sc_mac_addr, 6) == -1) { - if (device_get_unit(dev) != 0) { - device_printf(dev, - "Could not load local-mac-addr property " - "from DTS\n"); - return (ENXIO); - } - sc->sc_hidden = true; + device_printf(dev, + "Could not load local-mac-addr property from DTS\n"); + return (ENXIO); } /* Get link speed */ @@ -160,6 +179,9 @@ dtsec_fdt_attach(device_t dev) sizeof(sc->sc_phy_addr)) <= 0) return (ENXIO); + if (find_mdio(phy_node, dev, &sc->sc_mdio) != 0) + return (ENXIO); + /* Get PHY connection type */ if (OF_getprop(enet_node, "phy-connection-type", (void *)phy_type, sizeof(phy_type)) <= 0) diff --git a/sys/dev/dpaa/portals_common.c b/sys/dev/dpaa/portals_common.c index 207fcbdc6dbd..02729f2fcb7d 100644 --- a/sys/dev/dpaa/portals_common.c +++ b/sys/dev/dpaa/portals_common.c @@ -121,7 +121,7 @@ dpaa_portal_alloc_res(device_t dev, struct dpaa_portals_devinfo *di, int cpu) return (ENXIO); } - err = XX_PreallocAndBindIntr((int)sc->sc_dp[cpu].dp_ires, cpu); + err = XX_PreallocAndBindIntr((uintptr_t)sc->sc_dp[cpu].dp_ires, cpu); if (err != E_OK) { device_printf(dev, "Could not prealloc and bind interrupt\n"); diff --git a/sys/dev/dpaa/qman.c b/sys/dev/dpaa/qman.c index 69de8ab11cbd..a090d49adea1 100644 --- a/sys/dev/dpaa/qman.c +++ b/sys/dev/dpaa/qman.c @@ -205,7 +205,7 @@ qman_attach(device_t dev) qp.pfdrMemPartitionId = NCSW_MASTER_ID; qp.f_Exception = qman_exception; qp.h_App = sc; - qp.errIrq = (int)sc->sc_ires; + qp.errIrq = (uintptr_t)sc->sc_ires; qp.partFqidBase = QMAN_FQID_BASE; qp.partNumOfFqids = QMAN_MAX_FQIDS; qp.partCgsBase = 0; @@ -255,7 +255,7 @@ qman_detach(device_t dev) QM_Free(sc->sc_qh); if (sc->sc_ires != NULL) - XX_DeallocIntr((int)sc->sc_ires); + XX_DeallocIntr((uintptr_t)sc->sc_ires); if (sc->sc_ires != NULL) bus_release_resource(dev, SYS_RES_IRQ, diff --git a/sys/dev/dpaa/qman_portals.c b/sys/dev/dpaa/qman_portals.c index 8f39307aeb96..0baf64bad9fe 100644 --- a/sys/dev/dpaa/qman_portals.c +++ b/sys/dev/dpaa/qman_portals.c @@ -100,7 +100,7 @@ qman_portals_detach(device_t dev) } if (sc->sc_dp[i].dp_ires != NULL) { - XX_DeallocIntr((int)sc->sc_dp[i].dp_ires); + XX_DeallocIntr((uintptr_t)sc->sc_dp[i].dp_ires); bus_release_resource(dev, SYS_RES_IRQ, sc->sc_dp[i].dp_irid, sc->sc_dp[i].dp_ires); } @@ -120,7 +120,8 @@ qman_portal_setup(struct qman_softc *qsc) { struct dpaa_portals_softc *sc; t_QmPortalParam qpp; - unsigned int cpu, p; + unsigned int cpu; + uintptr_t p; t_Handle portal; /* Return NULL if we're not ready or while detach */ @@ -134,9 +135,9 @@ qman_portal_setup(struct qman_softc *qsc) cpu = PCPU_GET(cpuid); /* Check if portal is ready */ - while (atomic_cmpset_acq_32((uint32_t *)&sc->sc_dp[cpu].dp_ph, + while (atomic_cmpset_acq_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph, 0, -1) == 0) { - p = atomic_load_acq_32((uint32_t *)&sc->sc_dp[cpu].dp_ph); + p = atomic_load_acq_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph); /* Return if portal is already initialized */ if (p != 0 && p != -1) { @@ -158,7 +159,7 @@ qman_portal_setup(struct qman_softc *qsc) qpp.ciBaseAddress = rman_get_bushandle(sc->sc_rres[1]); qpp.h_Qm = qsc->sc_qh; qpp.swPortalId = cpu; - qpp.irq = (int)sc->sc_dp[cpu].dp_ires; + qpp.irq = (uintptr_t)sc->sc_dp[cpu].dp_ires; qpp.fdLiodnOffset = 0; qpp.f_DfltFrame = qman_received_frame_callback; qpp.f_RejectedFrame = qman_rejected_frame_callback; @@ -174,8 +175,8 @@ qman_portal_setup(struct qman_softc *qsc) if (QM_PORTAL_AddPoolChannel(portal, QMAN_COMMON_POOL_CHANNEL) != E_OK) goto err; - atomic_store_rel_32((uint32_t *)&sc->sc_dp[cpu].dp_ph, - (uint32_t)portal); + atomic_store_rel_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph, + (uintptr_t)portal); sched_unpin(); return (portal); diff --git a/sys/dev/e1000/if_lem.c b/sys/dev/e1000/if_lem.c index 1bfde10004f7..537ccbe5ff11 100644 --- a/sys/dev/e1000/if_lem.c +++ b/sys/dev/e1000/if_lem.c @@ -39,7 +39,6 @@ */ // #define BATCH_DISPATCH // #define NIC_SEND_COMBINING -// #define NIC_PARAVIRT /* enable virtio-like synchronization */ #include "opt_inet.h" #include "opt_inet6.h" @@ -486,10 +485,6 @@ lem_attach(device_t dev) lem_add_rx_process_limit(adapter, "batch_enable", "driver rx batch", &adapter->batch_enable, 0); #endif /* BATCH_DISPATCH */ -#ifdef NIC_PARAVIRT - lem_add_rx_process_limit(adapter, "rx_retries", - "driver rx retries", &adapter->rx_retries, 0); -#endif /* NIC_PARAVIRT */ /* Sysctl for setting the interface flow control */ lem_set_flow_cntrl(adapter, "flow_control", @@ -548,51 +543,16 @@ lem_attach(device_t dev) */ adapter->hw.mac.report_tx_early = 1; -#ifdef NIC_PARAVIRT - device_printf(dev, "driver supports paravirt, subdev 0x%x\n", - adapter->hw.subsystem_device_id); - if (adapter->hw.subsystem_device_id == E1000_PARA_SUBDEV) { - uint64_t bus_addr; - - device_printf(dev, "paravirt support on dev %p\n", adapter); - tsize = 4096; // XXX one page for the csb - if (lem_dma_malloc(adapter, tsize, &adapter->csb_mem, BUS_DMA_NOWAIT)) { - device_printf(dev, "Unable to allocate csb memory\n"); - error = ENOMEM; - goto err_csb; - } - /* Setup the Base of the CSB */ - adapter->csb = (struct paravirt_csb *)adapter->csb_mem.dma_vaddr; - /* force the first kick */ - adapter->csb->host_need_txkick = 1; /* txring empty */ - adapter->csb->guest_need_rxkick = 1; /* no rx packets */ - bus_addr = adapter->csb_mem.dma_paddr; - lem_add_rx_process_limit(adapter, "csb_on", - "enable paravirt.", &adapter->csb->guest_csb_on, 0); - lem_add_rx_process_limit(adapter, "txc_lim", - "txc_lim", &adapter->csb->host_txcycles_lim, 1); - - /* some stats */ -#define PA_SC(name, var, val) \ - lem_add_rx_process_limit(adapter, name, name, var, val) - PA_SC("host_need_txkick",&adapter->csb->host_need_txkick, 1); - PA_SC("host_rxkick_at",&adapter->csb->host_rxkick_at, ~0); - PA_SC("guest_need_txkick",&adapter->csb->guest_need_txkick, 0); - PA_SC("guest_need_rxkick",&adapter->csb->guest_need_rxkick, 1); - PA_SC("tdt_reg_count",&adapter->tdt_reg_count, 0); - PA_SC("tdt_csb_count",&adapter->tdt_csb_count, 0); - PA_SC("tdt_int_count",&adapter->tdt_int_count, 0); - PA_SC("guest_need_kick_count",&adapter->guest_need_kick_count, 0); - /* tell the host where the block is */ - E1000_WRITE_REG(&adapter->hw, E1000_CSBAH, - (u32)(bus_addr >> 32)); - E1000_WRITE_REG(&adapter->hw, E1000_CSBAL, - (u32)bus_addr); - } -#endif /* NIC_PARAVIRT */ - - tsize = roundup2(adapter->num_tx_desc * sizeof(struct e1000_tx_desc), - EM_DBA_ALIGN); + /* + * It seems that the descriptor DMA engine on some PCI cards + * fetches memory past the end of the last descriptor in the + * ring. These reads are problematic when VT-d (DMAR) busdma + * is used. Allocate the scratch space to avoid getting + * faults from DMAR, by requesting scratch memory for one more + * descriptor. + */ + tsize = roundup2((adapter->num_tx_desc + 1) * + sizeof(struct e1000_tx_desc), EM_DBA_ALIGN); /* Allocate Transmit Descriptor ring */ if (lem_dma_malloc(adapter, tsize, &adapter->txdma, BUS_DMA_NOWAIT)) { @@ -603,8 +563,11 @@ lem_attach(device_t dev) adapter->tx_desc_base = (struct e1000_tx_desc *)adapter->txdma.dma_vaddr; - rsize = roundup2(adapter->num_rx_desc * sizeof(struct e1000_rx_desc), - EM_DBA_ALIGN); + /* + * See comment above txdma allocation for rationale behind +1. + */ + rsize = roundup2((adapter->num_rx_desc + 1) * + sizeof(struct e1000_rx_desc), EM_DBA_ALIGN); /* Allocate Receive Descriptor ring */ if (lem_dma_malloc(adapter, rsize, &adapter->rxdma, BUS_DMA_NOWAIT)) { @@ -749,11 +712,6 @@ lem_attach(device_t dev) err_rx_desc: lem_dma_free(adapter, &adapter->txdma); err_tx_desc: -#ifdef NIC_PARAVIRT - lem_dma_free(adapter, &adapter->csb_mem); -err_csb: -#endif /* NIC_PARAVIRT */ - err_pci: if (adapter->ifp != (void *)NULL) if_free(adapter->ifp); @@ -841,12 +799,6 @@ lem_detach(device_t dev) adapter->rx_desc_base = NULL; } -#ifdef NIC_PARAVIRT - if (adapter->csb) { - lem_dma_free(adapter, &adapter->csb_mem); - adapter->csb = NULL; - } -#endif /* NIC_PARAVIRT */ lem_release_hw_control(adapter); free(adapter->mta, M_DEVBUF); EM_TX_LOCK_DESTROY(adapter); @@ -956,16 +908,6 @@ lem_start_locked(if_t ifp) } if (adapter->num_tx_desc_avail <= EM_TX_OP_THRESHOLD) if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0); -#ifdef NIC_PARAVIRT - if (if_getdrvflags(ifp) & IFF_DRV_OACTIVE && adapter->csb && - adapter->csb->guest_csb_on && - !(adapter->csb->guest_need_txkick & 1)) { - adapter->csb->guest_need_txkick = 1; - adapter->guest_need_kick_count++; - // XXX memory barrier - lem_txeof(adapter); // XXX possibly clear IFF_DRV_OACTIVE - } -#endif /* NIC_PARAVIRT */ return; } @@ -1813,24 +1755,6 @@ lem_xmit(struct adapter *adapter, struct mbuf **m_headp) bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); -#ifdef NIC_PARAVIRT - if (adapter->csb) { - adapter->csb->guest_tdt = i; - /* XXX memory barrier ? */ - if (adapter->csb->guest_csb_on && - !(adapter->csb->host_need_txkick & 1)) { - /* XXX maybe useless - * clean the ring. maybe do it before ? - * maybe a little bit of histeresys ? - */ - if (adapter->num_tx_desc_avail <= 64) {// XXX - lem_txeof(adapter); - } - return (0); - } - } -#endif /* NIC_PARAVIRT */ - #ifdef NIC_SEND_COMBINING if (adapter->sc_enable) { if (adapter->shadow_tdt & MIT_PENDING_INT) { @@ -2086,20 +2010,6 @@ lem_local_timer(void *arg) lem_smartspeed(adapter); -#ifdef NIC_PARAVIRT - /* recover space if needed */ - if (adapter->csb && adapter->csb->guest_csb_on && - (adapter->watchdog_check == TRUE) && - (ticks - adapter->watchdog_time > EM_WATCHDOG) && - (adapter->num_tx_desc_avail != adapter->num_tx_desc) ) { - lem_txeof(adapter); - /* - * lem_txeof() normally (except when space in the queue - * runs low XXX) cleans watchdog_check so that - * we do not hung. - */ - } -#endif /* NIC_PARAVIRT */ /* * We check the watchdog: the time since * the last TX descriptor was cleaned. @@ -3176,12 +3086,6 @@ lem_txeof(struct adapter *adapter) */ if (adapter->num_tx_desc_avail > EM_TX_CLEANUP_THRESHOLD) { if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); -#ifdef NIC_PARAVIRT - if (adapter->csb) { // XXX also csb_on ? - adapter->csb->guest_need_txkick = 2; /* acked */ - // XXX memory barrier - } -#endif /* NIC_PARAVIRT */ if (adapter->num_tx_desc_avail == adapter->num_tx_desc) { adapter->watchdog_check = FALSE; return; @@ -3570,15 +3474,6 @@ lem_rxeof(struct adapter *adapter, int count, int *done) #ifdef BATCH_DISPATCH struct mbuf *mh = NULL, *mt = NULL; #endif /* BATCH_DISPATCH */ -#ifdef NIC_PARAVIRT - int retries = 0; - struct paravirt_csb* csb = adapter->csb; - int csb_mode = csb && csb->guest_csb_on; - - //ND("clear guest_rxkick at %d", adapter->next_rx_desc_to_check); - if (csb_mode && csb->guest_need_rxkick) - csb->guest_need_rxkick = 0; -#endif /* NIC_PARAVIRT */ EM_RX_LOCK(adapter); #ifdef BATCH_DISPATCH @@ -3596,45 +3491,20 @@ lem_rxeof(struct adapter *adapter, int count, int *done) } #endif /* DEV_NETMAP */ -#if 1 // XXX optimization ? if (!((current_desc->status) & E1000_RXD_STAT_DD)) { if (done != NULL) *done = rx_sent; EM_RX_UNLOCK(adapter); return (FALSE); } -#endif /* 0 */ while (count != 0 && if_getdrvflags(ifp) & IFF_DRV_RUNNING) { struct mbuf *m = NULL; status = current_desc->status; if ((status & E1000_RXD_STAT_DD) == 0) { -#ifdef NIC_PARAVIRT - if (csb_mode) { - /* buffer not ready yet. Retry a few times before giving up */ - if (++retries <= adapter->rx_retries) { - continue; - } - if (csb->guest_need_rxkick == 0) { - // ND("set guest_rxkick at %d", adapter->next_rx_desc_to_check); - csb->guest_need_rxkick = 1; - // XXX memory barrier, status volatile ? - continue; /* double check */ - } - } - /* no buffer ready, give up */ -#endif /* NIC_PARAVIRT */ break; } -#ifdef NIC_PARAVIRT - if (csb_mode) { - if (csb->guest_need_rxkick) - // ND("clear again guest_rxkick at %d", adapter->next_rx_desc_to_check); - csb->guest_need_rxkick = 0; - retries = 0; - } -#endif /* NIC_PARAVIRT */ mp = adapter->rx_buffer_area[i].m_head; /* @@ -3759,18 +3629,6 @@ lem_rxeof(struct adapter *adapter, int count, int *done) bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); -#ifdef NIC_PARAVIRT - if (csb_mode) { - /* the buffer at i has been already replaced by lem_get_buf() - * so it is safe to set guest_rdt = i and possibly send a kick. - * XXX see if we can optimize it later. - */ - csb->guest_rdt = i; - // XXX memory barrier - if (i == csb->host_rxkick_at) - E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), i); - } -#endif /* NIC_PARAVIRT */ /* Advance our pointers to the next descriptor. */ if (++i == adapter->num_rx_desc) i = 0; @@ -3817,9 +3675,6 @@ lem_rxeof(struct adapter *adapter, int count, int *done) /* Advance the E1000's Receive Queue #0 "Tail Pointer". */ if (--i < 0) i = adapter->num_rx_desc - 1; -#ifdef NIC_PARAVIRT - if (!csb_mode) /* filter out writes */ -#endif /* NIC_PARAVIRT */ E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), i); if (done != NULL) *done = rx_sent; diff --git a/sys/dev/efidev/efidev.c b/sys/dev/efidev/efidev.c index abceec8087d6..d6e0e06468e5 100644 --- a/sys/dev/efidev/efidev.c +++ b/sys/dev/efidev/efidev.c @@ -47,7 +47,6 @@ static struct cdevsw efi_cdevsw = { .d_ioctl = efidev_ioctl, }; -/* ARGSUSED */ static int efidev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, int flags __unused, struct thread *td __unused) @@ -173,21 +172,45 @@ efidev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, return (error); } -int -efidev_init(struct cdev **cdev) -{ - - *cdev = make_dev(&efi_cdevsw, 0, UID_ROOT, GID_WHEEL, 0700, - "efi"); +static struct cdev *efidev; - return (0); +static int +efidev_modevents(module_t m, int event, void *arg __unused) +{ + struct make_dev_args mda; + int error; + + switch (event) { + case MOD_LOAD: + make_dev_args_init(&mda); + mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME; + mda.mda_devsw = &efi_cdevsw; + mda.mda_uid = UID_ROOT; + mda.mda_gid = GID_WHEEL; + mda.mda_mode = 0700; + error = make_dev_s(&mda, &efidev, "efi"); + return (error); + + case MOD_UNLOAD: + if (efidev != NULL) + destroy_dev(efidev); + efidev = NULL; + return (0); + + case MOD_SHUTDOWN: + return (0); + + default: + return (EOPNOTSUPP); + } } -int -efidev_uninit(struct cdev *cdev) -{ - - destroy_dev(cdev); +static moduledata_t efidev_moddata = { + .name = "efidev", + .evhand = efidev_modevents, + .priv = NULL, +}; - return (0); -} +DECLARE_MODULE(efidev, efidev_moddata, SI_SUB_DEVFS, SI_ORDER_ANY); +MODULE_VERSION(efidev, 1); +MODULE_DEPEND(efidev, efirt, 1, 1, 1); diff --git a/sys/dev/extres/regulator/regulator.c b/sys/dev/extres/regulator/regulator.c index 729de6b69b10..10307b135dea 100644 --- a/sys/dev/extres/regulator/regulator.c +++ b/sys/dev/extres/regulator/regulator.c @@ -53,6 +53,8 @@ __FBSDID("$FreeBSD$"); MALLOC_DEFINE(M_REGULATOR, "regulator", "Regulator framework"); +#define DIV_ROUND_UP(n,d) howmany(n, d) + /* Forward declarations. */ struct regulator; struct regnode; @@ -984,3 +986,87 @@ regulator_get_by_ofw_property(device_t cdev, phandle_t cnode, char *name, return (regulator_get_by_id(cdev, regdev, id, reg)); } #endif + +/* -------------------------------------------------------------------------- + * + * Regulator utility functions. + * + */ + +/* Convert raw selector value to real voltage */ +int +regulator_range_sel8_to_volt(struct regulator_range *ranges, int nranges, + uint8_t sel, int *volt) +{ + struct regulator_range *range; + int i; + + if (nranges == 0) + panic("Voltage regulator have zero ranges\n"); + + for (i = 0; i < nranges ; i++) { + range = ranges + i; + + if (!(sel >= range->min_sel && + sel <= range->max_sel)) + continue; + + sel -= range->min_sel; + + *volt = range->min_uvolt + sel * range->step_uvolt; + return (0); + } + + return (ERANGE); +} + +int +regulator_range_volt_to_sel8(struct regulator_range *ranges, int nranges, + int min_uvolt, int max_uvolt, uint8_t *out_sel) +{ + struct regulator_range *range; + uint8_t sel; + int uvolt; + int rv, i; + + if (nranges == 0) + panic("Voltage regulator have zero ranges\n"); + + for (i = 0; i < nranges; i++) { + range = ranges + i; + uvolt = range->min_uvolt + + (range->max_sel - range->min_sel) * range->step_uvolt; + + if ((min_uvolt > uvolt) || + (max_uvolt < range->min_uvolt)) + continue; + + if (min_uvolt <= range->min_uvolt) + min_uvolt = range->min_uvolt; + + /* if step == 0 -> fixed voltage range. */ + if (range->step_uvolt == 0) + sel = 0; + else + sel = DIV_ROUND_UP(min_uvolt - range->min_uvolt, + range->step_uvolt); + + + sel += range->min_sel; + + break; + } + + if (i >= nranges) + return (ERANGE); + + /* Verify new settings. */ + rv = regulator_range_sel8_to_volt(ranges, nranges, sel, &uvolt); + if (rv != 0) + return (rv); + if ((uvolt < min_uvolt) || (uvolt > max_uvolt)) + return (ERANGE); + + *out_sel = sel; + return (0); +} diff --git a/sys/dev/extres/regulator/regulator.h b/sys/dev/extres/regulator/regulator.h index e509a7e74349..75d673d37c00 100644 --- a/sys/dev/extres/regulator/regulator.h +++ b/sys/dev/extres/regulator/regulator.h @@ -67,9 +67,22 @@ struct regnode_init_def { #ifdef FDT phandle_t ofw_node; /* OFW node of regulator */ #endif - }; +struct regulator_range { + int min_uvolt; + int step_uvolt; + uint8_t min_sel; + uint8_t max_sel; +}; + +#define REG_RANGE_INIT(_min_sel, _max_sel, _min_uvolt, _step_uvolt) { \ + .min_sel = _min_sel, \ + .max_sel = _max_sel, \ + .min_uvolt = _min_uvolt, \ + .step_uvolt = _step_uvolt, \ +} + /* * Shorthands for constructing method tables. */ @@ -125,4 +138,10 @@ int regulator_parse_ofw_stdparam(device_t dev, phandle_t node, struct regnode_init_def *def); #endif +/* Utility functions */ +int regulator_range_volt_to_sel8(struct regulator_range *ranges, int nranges, + int min_uvolt, int max_uvolt, uint8_t *out_sel); +int regulator_range_sel8_to_volt(struct regulator_range *ranges, int nranges, + uint8_t sel, int *volt); + #endif /* _DEV_EXTRES_REGULATOR_H_ */ diff --git a/sys/dev/hyperv/include/vmbus.h b/sys/dev/hyperv/include/vmbus.h index e4cb78e60428..4dd0a9a39b19 100644 --- a/sys/dev/hyperv/include/vmbus.h +++ b/sys/dev/hyperv/include/vmbus.h @@ -118,6 +118,7 @@ struct vmbus_chan_br { struct vmbus_channel; struct hyperv_guid; struct task; +struct taskqueue; typedef void (*vmbus_chan_callback_t)(struct vmbus_channel *, void *); @@ -179,5 +180,7 @@ int vmbus_chan_prplist_nelem(int br_size, int prpcnt_max, int dlen_max); bool vmbus_chan_rx_empty(const struct vmbus_channel *chan); bool vmbus_chan_tx_empty(const struct vmbus_channel *chan); +struct taskqueue * + vmbus_chan_mgmt_tq(const struct vmbus_channel *chan); #endif /* !_VMBUS_H_ */ diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.c b/sys/dev/hyperv/netvsc/hv_net_vsc.c index 21504c3584c6..2676222541e3 100644 --- a/sys/dev/hyperv/netvsc/hv_net_vsc.c +++ b/sys/dev/hyperv/netvsc/hv_net_vsc.c @@ -544,8 +544,9 @@ hn_nvs_init(struct hn_softc *sc) if (error) { if_printf(sc->hn_ifp, "reinit NVS version 0x%x " "failed: %d\n", sc->hn_nvs_ver, error); + return (error); } - return (error); + goto done; } /* @@ -567,11 +568,16 @@ hn_nvs_init(struct hn_softc *sc) HN_NDIS_VERSION_MAJOR(sc->hn_ndis_ver), HN_NDIS_VERSION_MINOR(sc->hn_ndis_ver)); } - return (0); + goto done; } } if_printf(sc->hn_ifp, "no NVS available\n"); return (ENXIO); + +done: + if (sc->hn_nvs_ver >= HN_NVS_VERSION_5) + sc->hn_caps |= HN_CAP_HASHVAL; + return (0); } int diff --git a/sys/dev/hyperv/netvsc/hv_net_vsc.h b/sys/dev/hyperv/netvsc/hv_net_vsc.h index 71f0d72424a6..06a6dfe8c98b 100644 --- a/sys/dev/hyperv/netvsc/hv_net_vsc.h +++ b/sys/dev/hyperv/netvsc/hv_net_vsc.h @@ -207,7 +207,6 @@ struct hn_softc { struct ifnet *hn_ifp; struct ifmedia hn_media; device_t hn_dev; - int hn_carrier; int hn_if_flags; struct sx hn_lock; struct vmbus_channel *hn_prichan; @@ -236,6 +235,9 @@ struct hn_softc { struct taskqueue *hn_mgmt_taskq; struct taskqueue *hn_mgmt_taskq0; struct task hn_link_task; + struct task hn_netchg_init; + struct timeout_task hn_netchg_status; + uint32_t hn_link_flags; /* HN_LINK_FLAG_ */ uint32_t hn_caps; /* HN_CAP_ */ uint32_t hn_flags; /* HN_FLAG_ */ @@ -269,6 +271,10 @@ struct hn_softc { #define HN_CAP_UDP6CS 0x0040 #define HN_CAP_TSO4 0x0080 #define HN_CAP_TSO6 0x0100 +#define HN_CAP_HASHVAL 0x0200 + +#define HN_LINK_FLAG_LINKUP 0x0001 +#define HN_LINK_FLAG_NETCHG 0x0002 /* * Externs diff --git a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c index 67c13e532a0f..336fee8b3b4e 100644 --- a/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c +++ b/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c @@ -335,6 +335,8 @@ static void hn_destroy_tx_data(struct hn_softc *); static void hn_start_taskfunc(void *, int); static void hn_start_txeof_taskfunc(void *, int); static void hn_link_taskfunc(void *, int); +static void hn_netchg_init_taskfunc(void *, int); +static void hn_netchg_status_taskfunc(void *, int); static void hn_suspend_mgmt_taskfunc(void *, int); static int hn_encap(struct hn_tx_ring *, struct hn_txdesc *, struct mbuf **); static int hn_create_rx_data(struct hn_softc *sc, int); @@ -360,6 +362,7 @@ static void hn_rx_drain(struct vmbus_channel *); static void hn_tx_resume(struct hn_softc *, int); static void hn_tx_ring_qflush(struct hn_tx_ring *); static int netvsc_detach(device_t dev); +static void hn_link_status(struct hn_softc *); static void hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt); @@ -482,7 +485,7 @@ hn_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; - if (!sc->hn_carrier) { + if ((sc->hn_link_flags & HN_LINK_FLAG_LINKUP) == 0) { ifmr->ifm_active |= IFM_NONE; return; } @@ -563,6 +566,9 @@ netvsc_attach(device_t dev) taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt", device_get_nameunit(dev)); TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc); + TASK_INIT(&sc->hn_netchg_init, 0, hn_netchg_init_taskfunc, sc); + TIMEOUT_TASK_INIT(sc->hn_mgmt_taskq0, &sc->hn_netchg_status, 0, + hn_netchg_status_taskfunc, sc); /* * Allocate ifnet and setup its name earlier, so that if_printf @@ -808,10 +814,8 @@ netvsc_shutdown(device_t dev) } static void -hn_link_taskfunc(void *xsc, int pending __unused) +hn_link_status(struct hn_softc *sc) { - struct hn_softc *sc = xsc; - struct ifnet *ifp = sc->hn_ifp; uint32_t link_status; int error; @@ -822,11 +826,51 @@ hn_link_taskfunc(void *xsc, int pending __unused) } if (link_status == NDIS_MEDIA_STATE_CONNECTED) - sc->hn_carrier = 1; + sc->hn_link_flags |= HN_LINK_FLAG_LINKUP; else - sc->hn_carrier = 0; - if_link_state_change(ifp, - sc->hn_carrier ? LINK_STATE_UP : LINK_STATE_DOWN); + sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; + if_link_state_change(sc->hn_ifp, + (sc->hn_link_flags & HN_LINK_FLAG_LINKUP) ? + LINK_STATE_UP : LINK_STATE_DOWN); +} + +static void +hn_link_taskfunc(void *xsc, int pending __unused) +{ + struct hn_softc *sc = xsc; + + if (sc->hn_link_flags & HN_LINK_FLAG_NETCHG) + return; + hn_link_status(sc); +} + +static void +hn_netchg_init_taskfunc(void *xsc, int pending __unused) +{ + struct hn_softc *sc = xsc; + + /* Prevent any link status checks from running. */ + sc->hn_link_flags |= HN_LINK_FLAG_NETCHG; + + /* + * Fake up a [link down --> link up] state change; 5 seconds + * delay is used, which closely simulates miibus reaction + * upon link down event. + */ + sc->hn_link_flags &= ~HN_LINK_FLAG_LINKUP; + if_link_state_change(sc->hn_ifp, LINK_STATE_DOWN); + taskqueue_enqueue_timeout(sc->hn_mgmt_taskq0, + &sc->hn_netchg_status, 5 * hz); +} + +static void +hn_netchg_status_taskfunc(void *xsc, int pending __unused) +{ + struct hn_softc *sc = xsc; + + /* Re-allow link status checks. */ + sc->hn_link_flags &= ~HN_LINK_FLAG_NETCHG; + hn_link_status(sc); } void @@ -837,6 +881,14 @@ hn_link_status_update(struct hn_softc *sc) taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task); } +void +hn_network_change(struct hn_softc *sc) +{ + + if (sc->hn_mgmt_taskq != NULL) + taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_netchg_init); +} + static __inline int hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd, struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs) @@ -2233,7 +2285,8 @@ hn_caps_sysctl(SYSCTL_HANDLER_ARGS) "\006UDP4CS" "\007UDP6CS" "\010TSO4" - "\011TSO6"); + "\011TSO6" + "\012HASHVAL"); return sysctl_handle_string(oidp, caps_str, sizeof(caps_str), req); } @@ -3008,12 +3061,15 @@ hn_fixup_tx_data(struct hn_softc *sc) if (sc->hn_caps & HN_CAP_UDP6CS) csum_assist |= CSUM_IP6_UDP; #endif - for (i = 0; i < sc->hn_tx_ring_cnt; ++i) sc->hn_tx_ring[i].hn_csum_assist = csum_assist; - if (sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30) { - /* Support HASHVAL pktinfo on TX path. */ + if (sc->hn_caps & HN_CAP_HASHVAL) { + /* + * Support HASHVAL pktinfo on TX path. + */ + if (bootverbose) + if_printf(sc->hn_ifp, "support HASHVAL pktinfo\n"); for (i = 0; i < sc->hn_tx_ring_cnt; ++i) sc->hn_tx_ring[i].hn_tx_flags |= HN_TX_FLAG_HASHVAL; } @@ -3408,20 +3464,19 @@ hn_synth_alloc_subchans(struct hn_softc *sc, int *nsubch) int nchan, rxr_cnt, error; nchan = *nsubch + 1; - if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30 || nchan == 1) { + if (nchan == 1) { /* - * Either RSS is not supported, or multiple RX/TX rings - * are not requested. + * Multiple RX/TX rings are not requested. */ *nsubch = 0; return (0); } /* - * Get RSS capabilities, e.g. # of RX rings, and # of indirect + * Query RSS capabilities, e.g. # of RX rings, and # of indirect * table entries. */ - error = hn_rndis_get_rsscaps(sc, &rxr_cnt); + error = hn_rndis_query_rsscaps(sc, &rxr_cnt); if (error) { /* No RSS; this is benign. */ *nsubch = 0; @@ -3716,6 +3771,8 @@ hn_suspend_mgmt(struct hn_softc *sc) /* * Make sure that all pending management tasks are completed. */ + taskqueue_drain(sc->hn_mgmt_taskq0, &sc->hn_netchg_init); + taskqueue_drain_timeout(sc->hn_mgmt_taskq0, &sc->hn_netchg_status); taskqueue_drain_all(sc->hn_mgmt_taskq0); } @@ -3793,10 +3850,11 @@ hn_resume_mgmt(struct hn_softc *sc) { /* - * Kick off link status check. + * Kick off network change detection, which will + * do link status check too. */ sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0; - hn_link_status_update(sc); + hn_network_change(sc); } static void diff --git a/sys/dev/hyperv/netvsc/hv_rndis_filter.c b/sys/dev/hyperv/netvsc/hv_rndis_filter.c index d176c4b4359f..16f292a22bba 100644 --- a/sys/dev/hyperv/netvsc/hv_rndis_filter.c +++ b/sys/dev/hyperv/netvsc/hv_rndis_filter.c @@ -158,6 +158,7 @@ static void hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen) { const struct rndis_status_msg *msg; + int ofs; if (dlen < sizeof(*msg)) { if_printf(sc->hn_ifp, "invalid RNDIS status\n"); @@ -176,8 +177,19 @@ hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen) break; case RNDIS_STATUS_NETWORK_CHANGE: - /* TODO */ - if_printf(sc->hn_ifp, "network changed\n"); + ofs = RNDIS_STBUFOFFSET_ABS(msg->rm_stbufoffset); + if (dlen < ofs + msg->rm_stbuflen || + msg->rm_stbuflen < sizeof(uint32_t)) { + if_printf(sc->hn_ifp, "network changed\n"); + } else { + uint32_t change; + + memcpy(&change, ((const uint8_t *)msg) + ofs, + sizeof(change)); + if_printf(sc->hn_ifp, "network changed, change %u\n", + change); + } + hn_network_change(sc); break; default: @@ -736,7 +748,7 @@ hn_rndis_query2(struct hn_softc *sc, uint32_t oid, } int -hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt) +hn_rndis_query_rsscaps(struct hn_softc *sc, int *rxr_cnt) { struct ndis_rss_caps in, caps; size_t caps_len; @@ -744,15 +756,13 @@ hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt) *rxr_cnt = 0; + if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_20) + return (EOPNOTSUPP); + memset(&in, 0, sizeof(in)); in.ndis_hdr.ndis_type = NDIS_OBJTYPE_RSS_CAPS; - if (sc->hn_ndis_ver < HN_NDIS_VERSION_6_30) { - in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_1; - in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE_6_0; - } else { - in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2; - in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE; - } + in.ndis_hdr.ndis_rev = NDIS_RSS_CAPS_REV_2; + in.ndis_hdr.ndis_size = NDIS_RSS_CAPS_SIZE; caps_len = NDIS_RSS_CAPS_SIZE; error = hn_rndis_query2(sc, OID_GEN_RECEIVE_SCALE_CAPABILITIES, @@ -1027,10 +1037,12 @@ hn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags) int error; /* - * Only NDIS 6.30+ is supported. + * Only NDIS 6.20+ is supported: + * We only support 4bytes element in indirect table, which has been + * adopted since NDIS 6.20. */ - KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_30, - ("NDIS 6.30+ is required, NDIS version 0x%08x", sc->hn_ndis_ver)); + KASSERT(sc->hn_ndis_ver >= HN_NDIS_VERSION_6_20, + ("NDIS 6.20+ is required, NDIS version 0x%08x", sc->hn_ndis_ver)); /* * NOTE: diff --git a/sys/dev/hyperv/netvsc/if_hnreg.h b/sys/dev/hyperv/netvsc/if_hnreg.h index 53f59ec61fa1..a3b2b8bab665 100644 --- a/sys/dev/hyperv/netvsc/if_hnreg.h +++ b/sys/dev/hyperv/netvsc/if_hnreg.h @@ -36,6 +36,7 @@ * NDIS protocol version numbers */ #define HN_NDIS_VERSION_6_1 0x00060001 +#define HN_NDIS_VERSION_6_20 0x00060014 #define HN_NDIS_VERSION_6_30 0x0006001e #define HN_NDIS_VERSION_MAJOR(ver) (((ver) & 0xffff0000) >> 16) #define HN_NDIS_VERSION_MINOR(ver) ((ver) & 0xffff) diff --git a/sys/dev/hyperv/netvsc/if_hnvar.h b/sys/dev/hyperv/netvsc/if_hnvar.h index 517d2815908b..d25d5f2b7d53 100644 --- a/sys/dev/hyperv/netvsc/if_hnvar.h +++ b/sys/dev/hyperv/netvsc/if_hnvar.h @@ -122,7 +122,7 @@ void hn_rndis_detach(struct hn_softc *sc); int hn_rndis_conf_rss(struct hn_softc *sc, uint16_t flags); void *hn_rndis_pktinfo_append(struct rndis_packet_msg *, size_t pktsize, size_t pi_dlen, uint32_t pi_type); -int hn_rndis_get_rsscaps(struct hn_softc *sc, int *rxr_cnt); +int hn_rndis_query_rsscaps(struct hn_softc *sc, int *rxr_cnt); int hn_rndis_get_eaddr(struct hn_softc *sc, uint8_t *eaddr); int hn_rndis_get_linkstatus(struct hn_softc *sc, uint32_t *link_status); @@ -139,6 +139,7 @@ int hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen, const struct hn_recvinfo *info); void hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr); void hn_link_status_update(struct hn_softc *sc); +void hn_network_change(struct hn_softc *sc); extern struct hn_send_ctx hn_send_ctx_none; diff --git a/sys/dev/hyperv/netvsc/ndis.h b/sys/dev/hyperv/netvsc/ndis.h index fed262dddf67..5c741c6db330 100644 --- a/sys/dev/hyperv/netvsc/ndis.h +++ b/sys/dev/hyperv/netvsc/ndis.h @@ -32,6 +32,10 @@ #define NDIS_MEDIA_STATE_CONNECTED 0 #define NDIS_MEDIA_STATE_DISCONNECTED 1 +#define NDIS_NETCHANGE_TYPE_POSSIBLE 1 +#define NDIS_NETCHANGE_TYPE_DEFINITE 2 +#define NDIS_NETCHANGE_TYPE_FROMMEDIA 3 + #define NDIS_OFFLOAD_SET_NOCHG 0 #define NDIS_OFFLOAD_SET_ON 1 #define NDIS_OFFLOAD_SET_OFF 2 diff --git a/sys/dev/hyperv/vmbus/vmbus_chan.c b/sys/dev/hyperv/vmbus/vmbus_chan.c index 34b07eeff735..a889962b0b49 100644 --- a/sys/dev/hyperv/vmbus/vmbus_chan.c +++ b/sys/dev/hyperv/vmbus/vmbus_chan.c @@ -1721,3 +1721,10 @@ vmbus_chan_run_task(struct vmbus_channel *chan, struct task *task) taskqueue_enqueue(chan->ch_tq, task); taskqueue_drain(chan->ch_tq, task); } + +struct taskqueue * +vmbus_chan_mgmt_tq(const struct vmbus_channel *chan) +{ + + return (chan->ch_mgmt_tq); +} diff --git a/sys/dev/netmap/if_ixl_netmap.h b/sys/dev/netmap/if_ixl_netmap.h index 2c7f9be541b3..223dc06e36ab 100644 --- a/sys/dev/netmap/if_ixl_netmap.h +++ b/sys/dev/netmap/if_ixl_netmap.h @@ -59,7 +59,7 @@ extern int ixl_rx_miss, ixl_rx_miss_bufs, ixl_crcstrip; /* * device-specific sysctl variables: * - * ixl_crcstrip: 0: keep CRC in rx frames (default), 1: strip it. + * ixl_crcstrip: 0: NIC keeps CRC in rx frames, 1: NIC strips it (default). * During regular operations the CRC is stripped, but on some * hardware reception of frames not multiple of 64 is slower, * so using crcstrip=0 helps in benchmarks. @@ -73,7 +73,7 @@ SYSCTL_DECL(_dev_netmap); */ #if 0 SYSCTL_INT(_dev_netmap, OID_AUTO, ixl_crcstrip, - CTLFLAG_RW, &ixl_crcstrip, 1, "strip CRC on rx frames"); + CTLFLAG_RW, &ixl_crcstrip, 1, "NIC strips CRC on rx frames"); #endif SYSCTL_INT(_dev_netmap, OID_AUTO, ixl_rx_miss, CTLFLAG_RW, &ixl_rx_miss, 0, "potentially missed rx intr"); diff --git a/sys/dev/netmap/if_lem_netmap.h b/sys/dev/netmap/if_lem_netmap.h index 0ec9b1346609..91c637a8b3f8 100644 --- a/sys/dev/netmap/if_lem_netmap.h +++ b/sys/dev/netmap/if_lem_netmap.h @@ -35,12 +35,8 @@ #include #include -#include -#include /* vtophys ? */ #include -extern int netmap_adaptive_io; - /* * Register/unregister. We are already under netmap lock. */ @@ -81,6 +77,22 @@ lem_netmap_reg(struct netmap_adapter *na, int onoff) } +static void +lem_netmap_intr(struct netmap_adapter *na, int onoff) +{ + struct ifnet *ifp = na->ifp; + struct adapter *adapter = ifp->if_softc; + + EM_CORE_LOCK(adapter); + if (onoff) { + lem_enable_intr(adapter); + } else { + lem_disable_intr(adapter); + } + EM_CORE_UNLOCK(adapter); +} + + /* * Reconcile kernel and user view of the transmit ring. */ @@ -99,10 +111,6 @@ lem_netmap_txsync(struct netmap_kring *kring, int flags) /* device-specific */ struct adapter *adapter = ifp->if_softc; -#ifdef NIC_PARAVIRT - struct paravirt_csb *csb = adapter->csb; - uint64_t *csbd = (uint64_t *)(csb + 1); -#endif /* NIC_PARAVIRT */ bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, BUS_DMASYNC_POSTREAD); @@ -113,19 +121,6 @@ lem_netmap_txsync(struct netmap_kring *kring, int flags) nm_i = kring->nr_hwcur; if (nm_i != head) { /* we have new packets to send */ -#ifdef NIC_PARAVIRT - int do_kick = 0; - uint64_t t = 0; // timestamp - int n = head - nm_i; - if (n < 0) - n += lim + 1; - if (csb) { - t = rdtsc(); /* last timestamp */ - csbd[16] += t - csbd[0]; /* total Wg */ - csbd[17] += n; /* Wg count */ - csbd[0] = t; - } -#endif /* NIC_PARAVIRT */ nic_i = netmap_idx_k2n(kring, nm_i); while (nm_i != head) { struct netmap_slot *slot = &ring->slot[nm_i]; @@ -166,38 +161,8 @@ lem_netmap_txsync(struct netmap_kring *kring, int flags) bus_dmamap_sync(adapter->txdma.dma_tag, adapter->txdma.dma_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); -#ifdef NIC_PARAVIRT - /* set unconditionally, then also kick if needed */ - if (csb) { - t = rdtsc(); - if (csb->host_need_txkick == 2) { - /* can compute an update of delta */ - int64_t delta = t - csbd[3]; - if (delta < 0) - delta = -delta; - if (csbd[8] == 0 || delta < csbd[8]) { - csbd[8] = delta; - csbd[9]++; - } - csbd[10]++; - } - csb->guest_tdt = nic_i; - csbd[18] += t - csbd[0]; // total wp - csbd[19] += n; - } - if (!csb || !csb->guest_csb_on || (csb->host_need_txkick & 1)) - do_kick = 1; - if (do_kick) -#endif /* NIC_PARAVIRT */ /* (re)start the tx unit up to slot nic_i (excluded) */ E1000_WRITE_REG(&adapter->hw, E1000_TDT(0), nic_i); -#ifdef NIC_PARAVIRT - if (do_kick) { - uint64_t t1 = rdtsc(); - csbd[20] += t1 - t; // total Np - csbd[21]++; - } -#endif /* NIC_PARAVIRT */ } /* @@ -206,93 +171,6 @@ lem_netmap_txsync(struct netmap_kring *kring, int flags) if (ticks != kring->last_reclaim || flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) { kring->last_reclaim = ticks; /* record completed transmissions using TDH */ -#ifdef NIC_PARAVIRT - /* host updates tdh unconditionally, and we have - * no side effects on reads, so we can read from there - * instead of exiting. - */ - if (csb) { - static int drain = 0, nodrain=0, good = 0, bad = 0, fail = 0; - u_int x = adapter->next_tx_to_clean; - csbd[19]++; // XXX count reclaims - nic_i = csb->host_tdh; - if (csb->guest_csb_on) { - if (nic_i == x) { - bad++; - csbd[24]++; // failed reclaims - /* no progress, request kick and retry */ - csb->guest_need_txkick = 1; - mb(); // XXX barrier - nic_i = csb->host_tdh; - } else { - good++; - } - if (nic_i != x) { - csb->guest_need_txkick = 2; - if (nic_i == csb->guest_tdt) - drain++; - else - nodrain++; -#if 1 - if (netmap_adaptive_io) { - /* new mechanism: last half ring (or so) - * released one slot at a time. - * This effectively makes the system spin. - * - * Take next_to_clean + 1 as a reference. - * tdh must be ahead or equal - * On entry, the logical order is - * x < tdh = nic_i - * We first push tdh up to avoid wraps. - * The limit is tdh-ll (half ring). - * if tdh-256 < x we report x; - * else we report tdh-256 - */ - u_int tdh = nic_i; - u_int ll = csbd[15]; - u_int delta = lim/8; - if (netmap_adaptive_io == 2 || ll > delta) - csbd[15] = ll = delta; - else if (netmap_adaptive_io == 1 && ll > 1) { - csbd[15]--; - } - - if (nic_i >= kring->nkr_num_slots) { - RD(5, "bad nic_i %d on input", nic_i); - } - x = nm_next(x, lim); - if (tdh < x) - tdh += lim + 1; - if (tdh <= x + ll) { - nic_i = x; - csbd[25]++; //report n + 1; - } else { - tdh = nic_i; - if (tdh < ll) - tdh += lim + 1; - nic_i = tdh - ll; - csbd[26]++; // report tdh - ll - } - } -#endif - } else { - /* we stop, count whether we are idle or not */ - int bh_active = csb->host_need_txkick & 2 ? 4 : 0; - csbd[27+ csb->host_need_txkick]++; - if (netmap_adaptive_io == 1) { - if (bh_active && csbd[15] > 1) - csbd[15]--; - else if (!bh_active && csbd[15] < lim/2) - csbd[15]++; - } - bad--; - fail++; - } - } - RD(1, "drain %d nodrain %d good %d retry %d fail %d", - drain, nodrain, good, bad, fail); - } else -#endif /* !NIC_PARAVIRT */ nic_i = E1000_READ_REG(&adapter->hw, E1000_TDH(0)); if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */ D("TDH wrap %d", nic_i); @@ -324,21 +202,10 @@ lem_netmap_rxsync(struct netmap_kring *kring, int flags) /* device-specific */ struct adapter *adapter = ifp->if_softc; -#ifdef NIC_PARAVIRT - struct paravirt_csb *csb = adapter->csb; - uint32_t csb_mode = csb && csb->guest_csb_on; - uint32_t do_host_rxkick = 0; -#endif /* NIC_PARAVIRT */ if (head > lim) return netmap_ring_reinit(kring); -#ifdef NIC_PARAVIRT - if (csb_mode) { - force_update = 1; - csb->guest_need_rxkick = 0; - } -#endif /* NIC_PARAVIRT */ /* XXX check sync modes */ bus_dmamap_sync(adapter->rxdma.dma_tag, adapter->rxdma.dma_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); @@ -357,23 +224,6 @@ lem_netmap_rxsync(struct netmap_kring *kring, int flags) uint32_t staterr = le32toh(curr->status); int len; -#ifdef NIC_PARAVIRT - if (csb_mode) { - if ((staterr & E1000_RXD_STAT_DD) == 0) { - /* don't bother to retry if more than 1 pkt */ - if (n > 1) - break; - csb->guest_need_rxkick = 1; - wmb(); - staterr = le32toh(curr->status); - if ((staterr & E1000_RXD_STAT_DD) == 0) { - break; - } else { /* we are good */ - csb->guest_need_rxkick = 0; - } - } - } else -#endif /* NIC_PARAVIRT */ if ((staterr & E1000_RXD_STAT_DD) == 0) break; len = le16toh(curr->length) - 4; // CRC @@ -390,18 +240,6 @@ lem_netmap_rxsync(struct netmap_kring *kring, int flags) nic_i = nm_next(nic_i, lim); } if (n) { /* update the state variables */ -#ifdef NIC_PARAVIRT - if (csb_mode) { - if (n > 1) { - /* leave one spare buffer so we avoid rxkicks */ - nm_i = nm_prev(nm_i, lim); - nic_i = nm_prev(nic_i, lim); - n--; - } else { - csb->guest_need_rxkick = 1; - } - } -#endif /* NIC_PARAVIRT */ ND("%d new packets at nic %d nm %d tail %d", n, adapter->next_rx_desc_to_check, @@ -440,10 +278,6 @@ lem_netmap_rxsync(struct netmap_kring *kring, int flags) curr->status = 0; bus_dmamap_sync(adapter->rxtag, rxbuf->map, BUS_DMASYNC_PREREAD); -#ifdef NIC_PARAVIRT - if (csb_mode && csb->host_rxkick_at == nic_i) - do_host_rxkick = 1; -#endif /* NIC_PARAVIRT */ nm_i = nm_next(nm_i, lim); nic_i = nm_next(nic_i, lim); } @@ -455,12 +289,6 @@ lem_netmap_rxsync(struct netmap_kring *kring, int flags) * so move nic_i back by one unit */ nic_i = nm_prev(nic_i, lim); -#ifdef NIC_PARAVIRT - /* set unconditionally, then also kick if needed */ - if (csb) - csb->guest_rdt = nic_i; - if (!csb_mode || do_host_rxkick) -#endif /* NIC_PARAVIRT */ E1000_WRITE_REG(&adapter->hw, E1000_RDT(0), nic_i); } @@ -486,6 +314,7 @@ lem_netmap_attach(struct adapter *adapter) na.nm_rxsync = lem_netmap_rxsync; na.nm_register = lem_netmap_reg; na.num_tx_rings = na.num_rx_rings = 1; + na.nm_intr = lem_netmap_intr; netmap_attach(&na); } diff --git a/sys/dev/netmap/if_ptnet.c b/sys/dev/netmap/if_ptnet.c new file mode 100644 index 000000000000..90a90e984a5a --- /dev/null +++ b/sys/dev/netmap/if_ptnet.c @@ -0,0 +1,2283 @@ +/*- + * Copyright (c) 2016, Vincenzo Maffione + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + * $FreeBSD$ + */ + +/* Driver for ptnet paravirtualized network device. */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "opt_inet.h" +#include "opt_inet6.h" + +#include +#include +#include +#include +#include +#include + +#ifndef PTNET_CSB_ALLOC +#error "No support for on-device CSB" +#endif + +#ifndef INET +#error "INET not defined, cannot support offloadings" +#endif + +#if __FreeBSD_version >= 1100000 +static uint64_t ptnet_get_counter(if_t, ift_counter); +#else +typedef struct ifnet *if_t; +#define if_getsoftc(_ifp) (_ifp)->if_softc +#endif + +//#define PTNETMAP_STATS +//#define DEBUG +#ifdef DEBUG +#define DBG(x) x +#else /* !DEBUG */ +#define DBG(x) +#endif /* !DEBUG */ + +extern int ptnet_vnet_hdr; /* Tunable parameter */ + +struct ptnet_softc; + +struct ptnet_queue_stats { + uint64_t packets; /* if_[io]packets */ + uint64_t bytes; /* if_[io]bytes */ + uint64_t errors; /* if_[io]errors */ + uint64_t iqdrops; /* if_iqdrops */ + uint64_t mcasts; /* if_[io]mcasts */ +#ifdef PTNETMAP_STATS + uint64_t intrs; + uint64_t kicks; +#endif /* PTNETMAP_STATS */ +}; + +struct ptnet_queue { + struct ptnet_softc *sc; + struct resource *irq; + void *cookie; + int kring_id; + struct ptnet_ring *ptring; + unsigned int kick; + struct mtx lock; + struct buf_ring *bufring; /* for TX queues */ + struct ptnet_queue_stats stats; +#ifdef PTNETMAP_STATS + struct ptnet_queue_stats last_stats; +#endif /* PTNETMAP_STATS */ + struct taskqueue *taskq; + struct task task; + char lock_name[16]; +}; + +#define PTNET_Q_LOCK(_pq) mtx_lock(&(_pq)->lock) +#define PTNET_Q_TRYLOCK(_pq) mtx_trylock(&(_pq)->lock) +#define PTNET_Q_UNLOCK(_pq) mtx_unlock(&(_pq)->lock) + +struct ptnet_softc { + device_t dev; + if_t ifp; + struct ifmedia media; + struct mtx lock; + char lock_name[16]; + char hwaddr[ETHER_ADDR_LEN]; + + /* Mirror of PTFEAT register. */ + uint32_t ptfeatures; + unsigned int vnet_hdr_len; + + /* PCI BARs support. */ + struct resource *iomem; + struct resource *msix_mem; + + unsigned int num_rings; + unsigned int num_tx_rings; + struct ptnet_queue *queues; + struct ptnet_queue *rxqueues; + struct ptnet_csb *csb; + + unsigned int min_tx_space; + + struct netmap_pt_guest_adapter *ptna; + + struct callout tick; +#ifdef PTNETMAP_STATS + struct timeval last_ts; +#endif /* PTNETMAP_STATS */ +}; + +#define PTNET_CORE_LOCK(_sc) mtx_lock(&(_sc)->lock) +#define PTNET_CORE_UNLOCK(_sc) mtx_unlock(&(_sc)->lock) + +static int ptnet_probe(device_t); +static int ptnet_attach(device_t); +static int ptnet_detach(device_t); +static int ptnet_suspend(device_t); +static int ptnet_resume(device_t); +static int ptnet_shutdown(device_t); + +static void ptnet_init(void *opaque); +static int ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data); +static int ptnet_init_locked(struct ptnet_softc *sc); +static int ptnet_stop(struct ptnet_softc *sc); +static int ptnet_transmit(if_t ifp, struct mbuf *m); +static int ptnet_drain_transmit_queue(struct ptnet_queue *pq, + unsigned int budget, + bool may_resched); +static void ptnet_qflush(if_t ifp); +static void ptnet_tx_task(void *context, int pending); + +static int ptnet_media_change(if_t ifp); +static void ptnet_media_status(if_t ifp, struct ifmediareq *ifmr); +#ifdef PTNETMAP_STATS +static void ptnet_tick(void *opaque); +#endif + +static int ptnet_irqs_init(struct ptnet_softc *sc); +static void ptnet_irqs_fini(struct ptnet_softc *sc); + +static uint32_t ptnet_nm_ptctl(if_t ifp, uint32_t cmd); +static int ptnet_nm_config(struct netmap_adapter *na, unsigned *txr, + unsigned *txd, unsigned *rxr, unsigned *rxd); +static void ptnet_update_vnet_hdr(struct ptnet_softc *sc); +static int ptnet_nm_register(struct netmap_adapter *na, int onoff); +static int ptnet_nm_txsync(struct netmap_kring *kring, int flags); +static int ptnet_nm_rxsync(struct netmap_kring *kring, int flags); + +static void ptnet_tx_intr(void *opaque); +static void ptnet_rx_intr(void *opaque); + +static unsigned ptnet_rx_discard(struct netmap_kring *kring, + unsigned int head); +static int ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, + bool may_resched); +static void ptnet_rx_task(void *context, int pending); + +#ifdef DEVICE_POLLING +static poll_handler_t ptnet_poll; +#endif + +static device_method_t ptnet_methods[] = { + DEVMETHOD(device_probe, ptnet_probe), + DEVMETHOD(device_attach, ptnet_attach), + DEVMETHOD(device_detach, ptnet_detach), + DEVMETHOD(device_suspend, ptnet_suspend), + DEVMETHOD(device_resume, ptnet_resume), + DEVMETHOD(device_shutdown, ptnet_shutdown), + DEVMETHOD_END +}; + +static driver_t ptnet_driver = { + "ptnet", + ptnet_methods, + sizeof(struct ptnet_softc) +}; + +/* We use (SI_ORDER_MIDDLE+2) here, see DEV_MODULE_ORDERED() invocation. */ +static devclass_t ptnet_devclass; +DRIVER_MODULE_ORDERED(ptnet, pci, ptnet_driver, ptnet_devclass, + NULL, NULL, SI_ORDER_MIDDLE + 2); + +static int +ptnet_probe(device_t dev) +{ + if (pci_get_vendor(dev) != PTNETMAP_PCI_VENDOR_ID || + pci_get_device(dev) != PTNETMAP_PCI_NETIF_ID) { + return (ENXIO); + } + + device_set_desc(dev, "ptnet network adapter"); + + return (BUS_PROBE_DEFAULT); +} + +static inline void ptnet_kick(struct ptnet_queue *pq) +{ +#ifdef PTNETMAP_STATS + pq->stats.kicks ++; +#endif /* PTNETMAP_STATS */ + bus_write_4(pq->sc->iomem, pq->kick, 0); +} + +#define PTNET_BUF_RING_SIZE 4096 +#define PTNET_RX_BUDGET 512 +#define PTNET_RX_BATCH 1 +#define PTNET_TX_BUDGET 512 +#define PTNET_TX_BATCH 64 +#define PTNET_HDR_SIZE sizeof(struct virtio_net_hdr_mrg_rxbuf) +#define PTNET_MAX_PKT_SIZE 65536 + +#define PTNET_CSUM_OFFLOAD (CSUM_TCP | CSUM_UDP | CSUM_SCTP) +#define PTNET_CSUM_OFFLOAD_IPV6 (CSUM_TCP_IPV6 | CSUM_UDP_IPV6 |\ + CSUM_SCTP_IPV6) +#define PTNET_ALL_OFFLOAD (CSUM_TSO | PTNET_CSUM_OFFLOAD |\ + PTNET_CSUM_OFFLOAD_IPV6) + +static int +ptnet_attach(device_t dev) +{ + uint32_t ptfeatures = PTNETMAP_F_BASE; + unsigned int num_rx_rings, num_tx_rings; + struct netmap_adapter na_arg; + unsigned int nifp_offset; + struct ptnet_softc *sc; + if_t ifp; + uint32_t macreg; + int err, rid; + int i; + + sc = device_get_softc(dev); + sc->dev = dev; + + /* Setup PCI resources. */ + pci_enable_busmaster(dev); + + rid = PCIR_BAR(PTNETMAP_IO_PCI_BAR); + sc->iomem = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, + RF_ACTIVE); + if (sc->iomem == NULL) { + device_printf(dev, "Failed to map I/O BAR\n"); + return (ENXIO); + } + + /* Check if we are supported by the hypervisor. If not, + * bail out immediately. */ + if (ptnet_vnet_hdr) { + ptfeatures |= PTNETMAP_F_VNET_HDR; + } + bus_write_4(sc->iomem, PTNET_IO_PTFEAT, ptfeatures); /* wanted */ + ptfeatures = bus_read_4(sc->iomem, PTNET_IO_PTFEAT); /* acked */ + if (!(ptfeatures & PTNETMAP_F_BASE)) { + device_printf(dev, "Hypervisor does not support netmap " + "passthorugh\n"); + err = ENXIO; + goto err_path; + } + sc->ptfeatures = ptfeatures; + + /* Allocate CSB and carry out CSB allocation protocol (CSBBAH first, + * then CSBBAL). */ + sc->csb = malloc(sizeof(struct ptnet_csb), M_DEVBUF, + M_NOWAIT | M_ZERO); + if (sc->csb == NULL) { + device_printf(dev, "Failed to allocate CSB\n"); + err = ENOMEM; + goto err_path; + } + + { + /* + * We use uint64_t rather than vm_paddr_t since we + * need 64 bit addresses even on 32 bit platforms. + */ + uint64_t paddr = vtophys(sc->csb); + + bus_write_4(sc->iomem, PTNET_IO_CSBBAH, + (paddr >> 32) & 0xffffffff); + bus_write_4(sc->iomem, PTNET_IO_CSBBAL, paddr & 0xffffffff); + } + + num_tx_rings = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_RINGS); + num_rx_rings = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_RINGS); + sc->num_rings = num_tx_rings + num_rx_rings; + sc->num_tx_rings = num_tx_rings; + + /* Allocate and initialize per-queue data structures. */ + sc->queues = malloc(sizeof(struct ptnet_queue) * sc->num_rings, + M_DEVBUF, M_NOWAIT | M_ZERO); + if (sc->queues == NULL) { + err = ENOMEM; + goto err_path; + } + sc->rxqueues = sc->queues + num_tx_rings; + + for (i = 0; i < sc->num_rings; i++) { + struct ptnet_queue *pq = sc->queues + i; + + pq->sc = sc; + pq->kring_id = i; + pq->kick = PTNET_IO_KICK_BASE + 4 * i; + pq->ptring = sc->csb->rings + i; + snprintf(pq->lock_name, sizeof(pq->lock_name), "%s-%d", + device_get_nameunit(dev), i); + mtx_init(&pq->lock, pq->lock_name, NULL, MTX_DEF); + if (i >= num_tx_rings) { + /* RX queue: fix kring_id. */ + pq->kring_id -= num_tx_rings; + } else { + /* TX queue: allocate buf_ring. */ + pq->bufring = buf_ring_alloc(PTNET_BUF_RING_SIZE, + M_DEVBUF, M_NOWAIT, &pq->lock); + if (pq->bufring == NULL) { + err = ENOMEM; + goto err_path; + } + } + } + + sc->min_tx_space = 64; /* Safe initial value. */ + + err = ptnet_irqs_init(sc); + if (err) { + goto err_path; + } + + /* Setup Ethernet interface. */ + sc->ifp = ifp = if_alloc(IFT_ETHER); + if (ifp == NULL) { + device_printf(dev, "Failed to allocate ifnet\n"); + err = ENOMEM; + goto err_path; + } + + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_baudrate = IF_Gbps(10); + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX; + ifp->if_init = ptnet_init; + ifp->if_ioctl = ptnet_ioctl; +#if __FreeBSD_version >= 1100000 + ifp->if_get_counter = ptnet_get_counter; +#endif + ifp->if_transmit = ptnet_transmit; + ifp->if_qflush = ptnet_qflush; + + ifmedia_init(&sc->media, IFM_IMASK, ptnet_media_change, + ptnet_media_status); + ifmedia_add(&sc->media, IFM_ETHER | IFM_10G_T | IFM_FDX, 0, NULL); + ifmedia_set(&sc->media, IFM_ETHER | IFM_10G_T | IFM_FDX); + + macreg = bus_read_4(sc->iomem, PTNET_IO_MAC_HI); + sc->hwaddr[0] = (macreg >> 8) & 0xff; + sc->hwaddr[1] = macreg & 0xff; + macreg = bus_read_4(sc->iomem, PTNET_IO_MAC_LO); + sc->hwaddr[2] = (macreg >> 24) & 0xff; + sc->hwaddr[3] = (macreg >> 16) & 0xff; + sc->hwaddr[4] = (macreg >> 8) & 0xff; + sc->hwaddr[5] = macreg & 0xff; + + ether_ifattach(ifp, sc->hwaddr); + + ifp->if_hdrlen = sizeof(struct ether_vlan_header); + ifp->if_capabilities |= IFCAP_JUMBO_MTU | IFCAP_VLAN_MTU; + + if (sc->ptfeatures & PTNETMAP_F_VNET_HDR) { + /* Similarly to what the vtnet driver does, we can emulate + * VLAN offloadings by inserting and removing the 802.1Q + * header during transmit and receive. We are then able + * to do checksum offloading of VLAN frames. */ + ifp->if_capabilities |= IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 + | IFCAP_VLAN_HWCSUM + | IFCAP_TSO | IFCAP_LRO + | IFCAP_VLAN_HWTSO + | IFCAP_VLAN_HWTAGGING; + } + + ifp->if_capenable = ifp->if_capabilities; +#ifdef DEVICE_POLLING + /* Don't enable polling by default. */ + ifp->if_capabilities |= IFCAP_POLLING; +#endif + snprintf(sc->lock_name, sizeof(sc->lock_name), + "%s", device_get_nameunit(dev)); + mtx_init(&sc->lock, sc->lock_name, "ptnet core lock", MTX_DEF); + callout_init_mtx(&sc->tick, &sc->lock, 0); + + /* Prepare a netmap_adapter struct instance to do netmap_attach(). */ + nifp_offset = bus_read_4(sc->iomem, PTNET_IO_NIFP_OFS); + memset(&na_arg, 0, sizeof(na_arg)); + na_arg.ifp = ifp; + na_arg.num_tx_desc = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_SLOTS); + na_arg.num_rx_desc = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_SLOTS); + na_arg.num_tx_rings = num_tx_rings; + na_arg.num_rx_rings = num_rx_rings; + na_arg.nm_config = ptnet_nm_config; + na_arg.nm_krings_create = ptnet_nm_krings_create; + na_arg.nm_krings_delete = ptnet_nm_krings_delete; + na_arg.nm_dtor = ptnet_nm_dtor; + na_arg.nm_register = ptnet_nm_register; + na_arg.nm_txsync = ptnet_nm_txsync; + na_arg.nm_rxsync = ptnet_nm_rxsync; + + netmap_pt_guest_attach(&na_arg, sc->csb, nifp_offset, ptnet_nm_ptctl); + + /* Now a netmap adapter for this ifp has been allocated, and it + * can be accessed through NA(ifp). We also have to initialize the CSB + * pointer. */ + sc->ptna = (struct netmap_pt_guest_adapter *)NA(ifp); + + /* If virtio-net header was negotiated, set the virt_hdr_len field in + * the netmap adapter, to inform users that this netmap adapter requires + * the application to deal with the headers. */ + ptnet_update_vnet_hdr(sc); + + device_printf(dev, "%s() completed\n", __func__); + + return (0); + +err_path: + ptnet_detach(dev); + return err; +} + +static int +ptnet_detach(device_t dev) +{ + struct ptnet_softc *sc = device_get_softc(dev); + int i; + +#ifdef DEVICE_POLLING + if (sc->ifp->if_capenable & IFCAP_POLLING) { + ether_poll_deregister(sc->ifp); + } +#endif + callout_drain(&sc->tick); + + if (sc->queues) { + /* Drain taskqueues before calling if_detach. */ + for (i = 0; i < sc->num_rings; i++) { + struct ptnet_queue *pq = sc->queues + i; + + if (pq->taskq) { + taskqueue_drain(pq->taskq, &pq->task); + } + } + } + + if (sc->ifp) { + ether_ifdetach(sc->ifp); + + /* Uninitialize netmap adapters for this device. */ + netmap_detach(sc->ifp); + + ifmedia_removeall(&sc->media); + if_free(sc->ifp); + sc->ifp = NULL; + } + + ptnet_irqs_fini(sc); + + if (sc->csb) { + bus_write_4(sc->iomem, PTNET_IO_CSBBAH, 0); + bus_write_4(sc->iomem, PTNET_IO_CSBBAL, 0); + free(sc->csb, M_DEVBUF); + sc->csb = NULL; + } + + if (sc->queues) { + for (i = 0; i < sc->num_rings; i++) { + struct ptnet_queue *pq = sc->queues + i; + + if (mtx_initialized(&pq->lock)) { + mtx_destroy(&pq->lock); + } + if (pq->bufring != NULL) { + buf_ring_free(pq->bufring, M_DEVBUF); + } + } + free(sc->queues, M_DEVBUF); + sc->queues = NULL; + } + + if (sc->iomem) { + bus_release_resource(dev, SYS_RES_IOPORT, + PCIR_BAR(PTNETMAP_IO_PCI_BAR), sc->iomem); + sc->iomem = NULL; + } + + mtx_destroy(&sc->lock); + + device_printf(dev, "%s() completed\n", __func__); + + return (0); +} + +static int +ptnet_suspend(device_t dev) +{ + struct ptnet_softc *sc; + + sc = device_get_softc(dev); + (void)sc; + + return (0); +} + +static int +ptnet_resume(device_t dev) +{ + struct ptnet_softc *sc; + + sc = device_get_softc(dev); + (void)sc; + + return (0); +} + +static int +ptnet_shutdown(device_t dev) +{ + /* + * Suspend already does all of what we need to + * do here; we just never expect to be resumed. + */ + return (ptnet_suspend(dev)); +} + +static int +ptnet_irqs_init(struct ptnet_softc *sc) +{ + int rid = PCIR_BAR(PTNETMAP_MSIX_PCI_BAR); + int nvecs = sc->num_rings; + device_t dev = sc->dev; + int err = ENOSPC; + int cpu_cur; + int i; + + if (pci_find_cap(dev, PCIY_MSIX, NULL) != 0) { + device_printf(dev, "Could not find MSI-X capability\n"); + return (ENXIO); + } + + sc->msix_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &rid, RF_ACTIVE); + if (sc->msix_mem == NULL) { + device_printf(dev, "Failed to allocate MSIX PCI BAR\n"); + return (ENXIO); + } + + if (pci_msix_count(dev) < nvecs) { + device_printf(dev, "Not enough MSI-X vectors\n"); + goto err_path; + } + + err = pci_alloc_msix(dev, &nvecs); + if (err) { + device_printf(dev, "Failed to allocate MSI-X vectors\n"); + goto err_path; + } + + for (i = 0; i < nvecs; i++) { + struct ptnet_queue *pq = sc->queues + i; + + rid = i + 1; + pq->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE); + if (pq->irq == NULL) { + device_printf(dev, "Failed to allocate interrupt " + "for queue #%d\n", i); + err = ENOSPC; + goto err_path; + } + } + + cpu_cur = CPU_FIRST(); + for (i = 0; i < nvecs; i++) { + struct ptnet_queue *pq = sc->queues + i; + void (*handler)(void *) = ptnet_tx_intr; + + if (i >= sc->num_tx_rings) { + handler = ptnet_rx_intr; + } + err = bus_setup_intr(dev, pq->irq, INTR_TYPE_NET | INTR_MPSAFE, + NULL /* intr_filter */, handler, + pq, &pq->cookie); + if (err) { + device_printf(dev, "Failed to register intr handler " + "for queue #%d\n", i); + goto err_path; + } + + bus_describe_intr(dev, pq->irq, pq->cookie, "q%d", i); +#if 0 + bus_bind_intr(sc->dev, pq->irq, cpu_cur); +#endif + cpu_cur = CPU_NEXT(cpu_cur); + } + + device_printf(dev, "Allocated %d MSI-X vectors\n", nvecs); + + cpu_cur = CPU_FIRST(); + for (i = 0; i < nvecs; i++) { + struct ptnet_queue *pq = sc->queues + i; + static void (*handler)(void *context, int pending); + + handler = (i < sc->num_tx_rings) ? ptnet_tx_task : ptnet_rx_task; + + TASK_INIT(&pq->task, 0, handler, pq); + pq->taskq = taskqueue_create_fast("ptnet_queue", M_NOWAIT, + taskqueue_thread_enqueue, &pq->taskq); + taskqueue_start_threads(&pq->taskq, 1, PI_NET, "%s-pq-%d", + device_get_nameunit(sc->dev), cpu_cur); + cpu_cur = CPU_NEXT(cpu_cur); + } + + return 0; +err_path: + ptnet_irqs_fini(sc); + return err; +} + +static void +ptnet_irqs_fini(struct ptnet_softc *sc) +{ + device_t dev = sc->dev; + int i; + + for (i = 0; i < sc->num_rings; i++) { + struct ptnet_queue *pq = sc->queues + i; + + if (pq->taskq) { + taskqueue_free(pq->taskq); + pq->taskq = NULL; + } + + if (pq->cookie) { + bus_teardown_intr(dev, pq->irq, pq->cookie); + pq->cookie = NULL; + } + + if (pq->irq) { + bus_release_resource(dev, SYS_RES_IRQ, i + 1, pq->irq); + pq->irq = NULL; + } + } + + if (sc->msix_mem) { + pci_release_msi(dev); + + bus_release_resource(dev, SYS_RES_MEMORY, + PCIR_BAR(PTNETMAP_MSIX_PCI_BAR), + sc->msix_mem); + sc->msix_mem = NULL; + } +} + +static void +ptnet_init(void *opaque) +{ + struct ptnet_softc *sc = opaque; + + PTNET_CORE_LOCK(sc); + ptnet_init_locked(sc); + PTNET_CORE_UNLOCK(sc); +} + +static int +ptnet_ioctl(if_t ifp, u_long cmd, caddr_t data) +{ + struct ptnet_softc *sc = if_getsoftc(ifp); + device_t dev = sc->dev; + struct ifreq *ifr = (struct ifreq *)data; + int mask, err = 0; + + switch (cmd) { + case SIOCSIFFLAGS: + device_printf(dev, "SIOCSIFFLAGS %x\n", ifp->if_flags); + PTNET_CORE_LOCK(sc); + if (ifp->if_flags & IFF_UP) { + /* Network stack wants the iff to be up. */ + err = ptnet_init_locked(sc); + } else { + /* Network stack wants the iff to be down. */ + err = ptnet_stop(sc); + } + /* We don't need to do nothing to support IFF_PROMISC, + * since that is managed by the backend port. */ + PTNET_CORE_UNLOCK(sc); + break; + + case SIOCSIFCAP: + device_printf(dev, "SIOCSIFCAP %x %x\n", + ifr->ifr_reqcap, ifp->if_capenable); + mask = ifr->ifr_reqcap ^ ifp->if_capenable; +#ifdef DEVICE_POLLING + if (mask & IFCAP_POLLING) { + struct ptnet_queue *pq; + int i; + + if (ifr->ifr_reqcap & IFCAP_POLLING) { + err = ether_poll_register(ptnet_poll, ifp); + if (err) { + break; + } + /* Stop queues and sync with taskqueues. */ + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + for (i = 0; i < sc->num_rings; i++) { + pq = sc-> queues + i; + /* Make sure the worker sees the + * IFF_DRV_RUNNING down. */ + PTNET_Q_LOCK(pq); + pq->ptring->guest_need_kick = 0; + PTNET_Q_UNLOCK(pq); + /* Wait for rescheduling to finish. */ + if (pq->taskq) { + taskqueue_drain(pq->taskq, + &pq->task); + } + } + ifp->if_drv_flags |= IFF_DRV_RUNNING; + } else { + err = ether_poll_deregister(ifp); + for (i = 0; i < sc->num_rings; i++) { + pq = sc-> queues + i; + PTNET_Q_LOCK(pq); + pq->ptring->guest_need_kick = 1; + PTNET_Q_UNLOCK(pq); + } + } + } +#endif /* DEVICE_POLLING */ + ifp->if_capenable = ifr->ifr_reqcap; + break; + + case SIOCSIFMTU: + /* We support any reasonable MTU. */ + if (ifr->ifr_mtu < ETHERMIN || + ifr->ifr_mtu > PTNET_MAX_PKT_SIZE) { + err = EINVAL; + } else { + PTNET_CORE_LOCK(sc); + ifp->if_mtu = ifr->ifr_mtu; + PTNET_CORE_UNLOCK(sc); + } + break; + + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + err = ifmedia_ioctl(ifp, ifr, &sc->media, cmd); + break; + + default: + err = ether_ioctl(ifp, cmd, data); + break; + } + + return err; +} + +static int +ptnet_init_locked(struct ptnet_softc *sc) +{ + if_t ifp = sc->ifp; + struct netmap_adapter *na_dr = &sc->ptna->dr.up; + struct netmap_adapter *na_nm = &sc->ptna->hwup.up; + unsigned int nm_buf_size; + int ret; + + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + return 0; /* nothing to do */ + } + + device_printf(sc->dev, "%s\n", __func__); + + /* Translate offload capabilities according to if_capenable. */ + ifp->if_hwassist = 0; + if (ifp->if_capenable & IFCAP_TXCSUM) + ifp->if_hwassist |= PTNET_CSUM_OFFLOAD; + if (ifp->if_capenable & IFCAP_TXCSUM_IPV6) + ifp->if_hwassist |= PTNET_CSUM_OFFLOAD_IPV6; + if (ifp->if_capenable & IFCAP_TSO4) + ifp->if_hwassist |= CSUM_IP_TSO; + if (ifp->if_capenable & IFCAP_TSO6) + ifp->if_hwassist |= CSUM_IP6_TSO; + + /* + * Prepare the interface for netmap mode access. + */ + netmap_update_config(na_dr); + + ret = netmap_mem_finalize(na_dr->nm_mem, na_dr); + if (ret) { + device_printf(sc->dev, "netmap_mem_finalize() failed\n"); + return ret; + } + + if (sc->ptna->backend_regifs == 0) { + ret = ptnet_nm_krings_create(na_nm); + if (ret) { + device_printf(sc->dev, "ptnet_nm_krings_create() " + "failed\n"); + goto err_mem_finalize; + } + + ret = netmap_mem_rings_create(na_dr); + if (ret) { + device_printf(sc->dev, "netmap_mem_rings_create() " + "failed\n"); + goto err_rings_create; + } + + ret = netmap_mem_get_lut(na_dr->nm_mem, &na_dr->na_lut); + if (ret) { + device_printf(sc->dev, "netmap_mem_get_lut() " + "failed\n"); + goto err_get_lut; + } + } + + ret = ptnet_nm_register(na_dr, 1 /* on */); + if (ret) { + goto err_register; + } + + nm_buf_size = NETMAP_BUF_SIZE(na_dr); + + KASSERT(nm_buf_size > 0, ("Invalid netmap buffer size")); + sc->min_tx_space = PTNET_MAX_PKT_SIZE / nm_buf_size + 2; + device_printf(sc->dev, "%s: min_tx_space = %u\n", __func__, + sc->min_tx_space); +#ifdef PTNETMAP_STATS + callout_reset(&sc->tick, hz, ptnet_tick, sc); +#endif + + ifp->if_drv_flags |= IFF_DRV_RUNNING; + + return 0; + +err_register: + memset(&na_dr->na_lut, 0, sizeof(na_dr->na_lut)); +err_get_lut: + netmap_mem_rings_delete(na_dr); +err_rings_create: + ptnet_nm_krings_delete(na_nm); +err_mem_finalize: + netmap_mem_deref(na_dr->nm_mem, na_dr); + + return ret; +} + +/* To be called under core lock. */ +static int +ptnet_stop(struct ptnet_softc *sc) +{ + if_t ifp = sc->ifp; + struct netmap_adapter *na_dr = &sc->ptna->dr.up; + struct netmap_adapter *na_nm = &sc->ptna->hwup.up; + int i; + + device_printf(sc->dev, "%s\n", __func__); + + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + return 0; /* nothing to do */ + } + + /* Clear the driver-ready flag, and synchronize with all the queues, + * so that after this loop we are sure nobody is working anymore with + * the device. This scheme is taken from the vtnet driver. */ + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + callout_stop(&sc->tick); + for (i = 0; i < sc->num_rings; i++) { + PTNET_Q_LOCK(sc->queues + i); + PTNET_Q_UNLOCK(sc->queues + i); + } + + ptnet_nm_register(na_dr, 0 /* off */); + + if (sc->ptna->backend_regifs == 0) { + netmap_mem_rings_delete(na_dr); + ptnet_nm_krings_delete(na_nm); + } + netmap_mem_deref(na_dr->nm_mem, na_dr); + + return 0; +} + +static void +ptnet_qflush(if_t ifp) +{ + struct ptnet_softc *sc = if_getsoftc(ifp); + int i; + + /* Flush all the bufrings and do the interface flush. */ + for (i = 0; i < sc->num_rings; i++) { + struct ptnet_queue *pq = sc->queues + i; + struct mbuf *m; + + PTNET_Q_LOCK(pq); + if (pq->bufring) { + while ((m = buf_ring_dequeue_sc(pq->bufring))) { + m_freem(m); + } + } + PTNET_Q_UNLOCK(pq); + } + + if_qflush(ifp); +} + +static int +ptnet_media_change(if_t ifp) +{ + struct ptnet_softc *sc = if_getsoftc(ifp); + struct ifmedia *ifm = &sc->media; + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) { + return EINVAL; + } + + return 0; +} + +#if __FreeBSD_version >= 1100000 +static uint64_t +ptnet_get_counter(if_t ifp, ift_counter cnt) +{ + struct ptnet_softc *sc = if_getsoftc(ifp); + struct ptnet_queue_stats stats[2]; + int i; + + /* Accumulate statistics over the queues. */ + memset(stats, 0, sizeof(stats)); + for (i = 0; i < sc->num_rings; i++) { + struct ptnet_queue *pq = sc->queues + i; + int idx = (i < sc->num_tx_rings) ? 0 : 1; + + stats[idx].packets += pq->stats.packets; + stats[idx].bytes += pq->stats.bytes; + stats[idx].errors += pq->stats.errors; + stats[idx].iqdrops += pq->stats.iqdrops; + stats[idx].mcasts += pq->stats.mcasts; + } + + switch (cnt) { + case IFCOUNTER_IPACKETS: + return (stats[1].packets); + case IFCOUNTER_IQDROPS: + return (stats[1].iqdrops); + case IFCOUNTER_IERRORS: + return (stats[1].errors); + case IFCOUNTER_OPACKETS: + return (stats[0].packets); + case IFCOUNTER_OBYTES: + return (stats[0].bytes); + case IFCOUNTER_OMCASTS: + return (stats[0].mcasts); + default: + return (if_get_counter_default(ifp, cnt)); + } +} +#endif + + +#ifdef PTNETMAP_STATS +/* Called under core lock. */ +static void +ptnet_tick(void *opaque) +{ + struct ptnet_softc *sc = opaque; + int i; + + for (i = 0; i < sc->num_rings; i++) { + struct ptnet_queue *pq = sc->queues + i; + struct ptnet_queue_stats cur = pq->stats; + struct timeval now; + unsigned int delta; + + microtime(&now); + delta = now.tv_usec - sc->last_ts.tv_usec + + (now.tv_sec - sc->last_ts.tv_sec) * 1000000; + delta /= 1000; /* in milliseconds */ + + if (delta == 0) + continue; + + device_printf(sc->dev, "#%d[%u ms]:pkts %lu, kicks %lu, " + "intr %lu\n", i, delta, + (cur.packets - pq->last_stats.packets), + (cur.kicks - pq->last_stats.kicks), + (cur.intrs - pq->last_stats.intrs)); + pq->last_stats = cur; + } + microtime(&sc->last_ts); + callout_schedule(&sc->tick, hz); +} +#endif /* PTNETMAP_STATS */ + +static void +ptnet_media_status(if_t ifp, struct ifmediareq *ifmr) +{ + /* We are always active, as the backend netmap port is + * always open in netmap mode. */ + ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; + ifmr->ifm_active = IFM_ETHER | IFM_10G_T | IFM_FDX; +} + +static uint32_t +ptnet_nm_ptctl(if_t ifp, uint32_t cmd) +{ + struct ptnet_softc *sc = if_getsoftc(ifp); + int ret; + + bus_write_4(sc->iomem, PTNET_IO_PTCTL, cmd); + ret = bus_read_4(sc->iomem, PTNET_IO_PTSTS); + device_printf(sc->dev, "PTCTL %u, ret %u\n", cmd, ret); + + return ret; +} + +static int +ptnet_nm_config(struct netmap_adapter *na, unsigned *txr, unsigned *txd, + unsigned *rxr, unsigned *rxd) +{ + struct ptnet_softc *sc = if_getsoftc(na->ifp); + + *txr = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_RINGS); + *rxr = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_RINGS); + *txd = bus_read_4(sc->iomem, PTNET_IO_NUM_TX_SLOTS); + *rxd = bus_read_4(sc->iomem, PTNET_IO_NUM_RX_SLOTS); + + device_printf(sc->dev, "txr %u, rxr %u, txd %u, rxd %u\n", + *txr, *rxr, *txd, *rxd); + + return 0; +} + +static void +ptnet_sync_from_csb(struct ptnet_softc *sc, struct netmap_adapter *na) +{ + int i; + + /* Sync krings from the host, reading from + * CSB. */ + for (i = 0; i < sc->num_rings; i++) { + struct ptnet_ring *ptring = sc->queues[i].ptring; + struct netmap_kring *kring; + + if (i < na->num_tx_rings) { + kring = na->tx_rings + i; + } else { + kring = na->rx_rings + i - na->num_tx_rings; + } + kring->rhead = kring->ring->head = ptring->head; + kring->rcur = kring->ring->cur = ptring->cur; + kring->nr_hwcur = ptring->hwcur; + kring->nr_hwtail = kring->rtail = + kring->ring->tail = ptring->hwtail; + + ND("%d,%d: csb {hc %u h %u c %u ht %u}", t, i, + ptring->hwcur, ptring->head, ptring->cur, + ptring->hwtail); + ND("%d,%d: kring {hc %u rh %u rc %u h %u c %u ht %u rt %u t %u}", + t, i, kring->nr_hwcur, kring->rhead, kring->rcur, + kring->ring->head, kring->ring->cur, kring->nr_hwtail, + kring->rtail, kring->ring->tail); + } +} + +static void +ptnet_update_vnet_hdr(struct ptnet_softc *sc) +{ + unsigned int wanted_hdr_len = ptnet_vnet_hdr ? PTNET_HDR_SIZE : 0; + + bus_write_4(sc->iomem, PTNET_IO_VNET_HDR_LEN, wanted_hdr_len); + sc->vnet_hdr_len = bus_read_4(sc->iomem, PTNET_IO_VNET_HDR_LEN); + sc->ptna->hwup.up.virt_hdr_len = sc->vnet_hdr_len; +} + +static int +ptnet_nm_register(struct netmap_adapter *na, int onoff) +{ + /* device-specific */ + if_t ifp = na->ifp; + struct ptnet_softc *sc = if_getsoftc(ifp); + int native = (na == &sc->ptna->hwup.up); + struct ptnet_queue *pq; + enum txrx t; + int ret = 0; + int i; + + if (!onoff) { + sc->ptna->backend_regifs--; + } + + /* If this is the last netmap client, guest interrupt enable flags may + * be in arbitrary state. Since these flags are going to be used also + * by the netdevice driver, we have to make sure to start with + * notifications enabled. Also, schedule NAPI to flush pending packets + * in the RX rings, since we will not receive further interrupts + * until these will be processed. */ + if (native && !onoff && na->active_fds == 0) { + D("Exit netmap mode, re-enable interrupts"); + for (i = 0; i < sc->num_rings; i++) { + pq = sc->queues + i; + pq->ptring->guest_need_kick = 1; + } + } + + if (onoff) { + if (sc->ptna->backend_regifs == 0) { + /* Initialize notification enable fields in the CSB. */ + for (i = 0; i < sc->num_rings; i++) { + pq = sc->queues + i; + pq->ptring->host_need_kick = 1; + pq->ptring->guest_need_kick = + (!(ifp->if_capenable & IFCAP_POLLING) + && i >= sc->num_tx_rings); + } + + /* Set the virtio-net header length. */ + ptnet_update_vnet_hdr(sc); + + /* Make sure the host adapter passed through is ready + * for txsync/rxsync. */ + ret = ptnet_nm_ptctl(ifp, PTNETMAP_PTCTL_REGIF); + if (ret) { + return ret; + } + } + + /* Sync from CSB must be done after REGIF PTCTL. Skip this + * step only if this is a netmap client and it is not the + * first one. */ + if ((!native && sc->ptna->backend_regifs == 0) || + (native && na->active_fds == 0)) { + ptnet_sync_from_csb(sc, na); + } + + /* If not native, don't call nm_set_native_flags, since we don't want + * to replace if_transmit method, nor set NAF_NETMAP_ON */ + if (native) { + for_rx_tx(t) { + for (i = 0; i <= nma_get_nrings(na, t); i++) { + struct netmap_kring *kring = &NMR(na, t)[i]; + + if (nm_kring_pending_on(kring)) { + kring->nr_mode = NKR_NETMAP_ON; + } + } + } + nm_set_native_flags(na); + } + + } else { + if (native) { + nm_clear_native_flags(na); + for_rx_tx(t) { + for (i = 0; i <= nma_get_nrings(na, t); i++) { + struct netmap_kring *kring = &NMR(na, t)[i]; + + if (nm_kring_pending_off(kring)) { + kring->nr_mode = NKR_NETMAP_OFF; + } + } + } + } + + /* Sync from CSB must be done before UNREGIF PTCTL, on the last + * netmap client. */ + if (native && na->active_fds == 0) { + ptnet_sync_from_csb(sc, na); + } + + if (sc->ptna->backend_regifs == 0) { + ret = ptnet_nm_ptctl(ifp, PTNETMAP_PTCTL_UNREGIF); + } + } + + if (onoff) { + sc->ptna->backend_regifs++; + } + + return ret; +} + +static int +ptnet_nm_txsync(struct netmap_kring *kring, int flags) +{ + struct ptnet_softc *sc = if_getsoftc(kring->na->ifp); + struct ptnet_queue *pq = sc->queues + kring->ring_id; + bool notify; + + notify = netmap_pt_guest_txsync(pq->ptring, kring, flags); + if (notify) { + ptnet_kick(pq); + } + + return 0; +} + +static int +ptnet_nm_rxsync(struct netmap_kring *kring, int flags) +{ + struct ptnet_softc *sc = if_getsoftc(kring->na->ifp); + struct ptnet_queue *pq = sc->rxqueues + kring->ring_id; + bool notify; + + notify = netmap_pt_guest_rxsync(pq->ptring, kring, flags); + if (notify) { + ptnet_kick(pq); + } + + return 0; +} + +static void +ptnet_tx_intr(void *opaque) +{ + struct ptnet_queue *pq = opaque; + struct ptnet_softc *sc = pq->sc; + + DBG(device_printf(sc->dev, "Tx interrupt #%d\n", pq->kring_id)); +#ifdef PTNETMAP_STATS + pq->stats.intrs ++; +#endif /* PTNETMAP_STATS */ + + if (netmap_tx_irq(sc->ifp, pq->kring_id) != NM_IRQ_PASS) { + return; + } + + /* Schedule the tasqueue to flush process transmissions requests. + * However, vtnet, if_em and if_igb just call ptnet_transmit() here, + * at least when using MSI-X interrupts. The if_em driver, instead + * schedule taskqueue when using legacy interrupts. */ + taskqueue_enqueue(pq->taskq, &pq->task); +} + +static void +ptnet_rx_intr(void *opaque) +{ + struct ptnet_queue *pq = opaque; + struct ptnet_softc *sc = pq->sc; + unsigned int unused; + + DBG(device_printf(sc->dev, "Rx interrupt #%d\n", pq->kring_id)); +#ifdef PTNETMAP_STATS + pq->stats.intrs ++; +#endif /* PTNETMAP_STATS */ + + if (netmap_rx_irq(sc->ifp, pq->kring_id, &unused) != NM_IRQ_PASS) { + return; + } + + /* Like vtnet, if_igb and if_em drivers when using MSI-X interrupts, + * receive-side processing is executed directly in the interrupt + * service routine. Alternatively, we may schedule the taskqueue. */ + ptnet_rx_eof(pq, PTNET_RX_BUDGET, true); +} + +/* The following offloadings-related functions are taken from the vtnet + * driver, but the same functionality is required for the ptnet driver. + * As a temporary solution, I copied this code from vtnet and I started + * to generalize it (taking away driver-specific statistic accounting), + * making as little modifications as possible. + * In the future we need to share these functions between vtnet and ptnet. + */ +static int +ptnet_tx_offload_ctx(struct mbuf *m, int *etype, int *proto, int *start) +{ + struct ether_vlan_header *evh; + int offset; + + evh = mtod(m, struct ether_vlan_header *); + if (evh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { + /* BMV: We should handle nested VLAN tags too. */ + *etype = ntohs(evh->evl_proto); + offset = sizeof(struct ether_vlan_header); + } else { + *etype = ntohs(evh->evl_encap_proto); + offset = sizeof(struct ether_header); + } + + switch (*etype) { +#if defined(INET) + case ETHERTYPE_IP: { + struct ip *ip, iphdr; + if (__predict_false(m->m_len < offset + sizeof(struct ip))) { + m_copydata(m, offset, sizeof(struct ip), + (caddr_t) &iphdr); + ip = &iphdr; + } else + ip = (struct ip *)(m->m_data + offset); + *proto = ip->ip_p; + *start = offset + (ip->ip_hl << 2); + break; + } +#endif +#if defined(INET6) + case ETHERTYPE_IPV6: + *proto = -1; + *start = ip6_lasthdr(m, offset, IPPROTO_IPV6, proto); + /* Assert the network stack sent us a valid packet. */ + KASSERT(*start > offset, + ("%s: mbuf %p start %d offset %d proto %d", __func__, m, + *start, offset, *proto)); + break; +#endif + default: + /* Here we should increment the tx_csum_bad_ethtype counter. */ + return (EINVAL); + } + + return (0); +} + +static int +ptnet_tx_offload_tso(if_t ifp, struct mbuf *m, int eth_type, + int offset, bool allow_ecn, struct virtio_net_hdr *hdr) +{ + static struct timeval lastecn; + static int curecn; + struct tcphdr *tcp, tcphdr; + + if (__predict_false(m->m_len < offset + sizeof(struct tcphdr))) { + m_copydata(m, offset, sizeof(struct tcphdr), (caddr_t) &tcphdr); + tcp = &tcphdr; + } else + tcp = (struct tcphdr *)(m->m_data + offset); + + hdr->hdr_len = offset + (tcp->th_off << 2); + hdr->gso_size = m->m_pkthdr.tso_segsz; + hdr->gso_type = eth_type == ETHERTYPE_IP ? VIRTIO_NET_HDR_GSO_TCPV4 : + VIRTIO_NET_HDR_GSO_TCPV6; + + if (tcp->th_flags & TH_CWR) { + /* + * Drop if VIRTIO_NET_F_HOST_ECN was not negotiated. In FreeBSD, + * ECN support is not on a per-interface basis, but globally via + * the net.inet.tcp.ecn.enable sysctl knob. The default is off. + */ + if (!allow_ecn) { + if (ppsratecheck(&lastecn, &curecn, 1)) + if_printf(ifp, + "TSO with ECN not negotiated with host\n"); + return (ENOTSUP); + } + hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN; + } + + /* Here we should increment tx_tso counter. */ + + return (0); +} + +static struct mbuf * +ptnet_tx_offload(if_t ifp, struct mbuf *m, bool allow_ecn, + struct virtio_net_hdr *hdr) +{ + int flags, etype, csum_start, proto, error; + + flags = m->m_pkthdr.csum_flags; + + error = ptnet_tx_offload_ctx(m, &etype, &proto, &csum_start); + if (error) + goto drop; + + if ((etype == ETHERTYPE_IP && flags & PTNET_CSUM_OFFLOAD) || + (etype == ETHERTYPE_IPV6 && flags & PTNET_CSUM_OFFLOAD_IPV6)) { + /* + * We could compare the IP protocol vs the CSUM_ flag too, + * but that really should not be necessary. + */ + hdr->flags |= VIRTIO_NET_HDR_F_NEEDS_CSUM; + hdr->csum_start = csum_start; + hdr->csum_offset = m->m_pkthdr.csum_data; + /* Here we should increment the tx_csum counter. */ + } + + if (flags & CSUM_TSO) { + if (__predict_false(proto != IPPROTO_TCP)) { + /* Likely failed to correctly parse the mbuf. + * Here we should increment the tx_tso_not_tcp + * counter. */ + goto drop; + } + + KASSERT(hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM, + ("%s: mbuf %p TSO without checksum offload %#x", + __func__, m, flags)); + + error = ptnet_tx_offload_tso(ifp, m, etype, csum_start, + allow_ecn, hdr); + if (error) + goto drop; + } + + return (m); + +drop: + m_freem(m); + return (NULL); +} + +static void +ptnet_vlan_tag_remove(struct mbuf *m) +{ + struct ether_vlan_header *evh; + + evh = mtod(m, struct ether_vlan_header *); + m->m_pkthdr.ether_vtag = ntohs(evh->evl_tag); + m->m_flags |= M_VLANTAG; + + /* Strip the 802.1Q header. */ + bcopy((char *) evh, (char *) evh + ETHER_VLAN_ENCAP_LEN, + ETHER_HDR_LEN - ETHER_TYPE_LEN); + m_adj(m, ETHER_VLAN_ENCAP_LEN); +} + +/* + * Use the checksum offset in the VirtIO header to set the + * correct CSUM_* flags. + */ +static int +ptnet_rx_csum_by_offset(struct mbuf *m, uint16_t eth_type, int ip_start, + struct virtio_net_hdr *hdr) +{ +#if defined(INET) || defined(INET6) + int offset = hdr->csum_start + hdr->csum_offset; +#endif + + /* Only do a basic sanity check on the offset. */ + switch (eth_type) { +#if defined(INET) + case ETHERTYPE_IP: + if (__predict_false(offset < ip_start + sizeof(struct ip))) + return (1); + break; +#endif +#if defined(INET6) + case ETHERTYPE_IPV6: + if (__predict_false(offset < ip_start + sizeof(struct ip6_hdr))) + return (1); + break; +#endif + default: + /* Here we should increment the rx_csum_bad_ethtype counter. */ + return (1); + } + + /* + * Use the offset to determine the appropriate CSUM_* flags. This is + * a bit dirty, but we can get by with it since the checksum offsets + * happen to be different. We assume the host host does not do IPv4 + * header checksum offloading. + */ + switch (hdr->csum_offset) { + case offsetof(struct udphdr, uh_sum): + case offsetof(struct tcphdr, th_sum): + m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xFFFF; + break; + case offsetof(struct sctphdr, checksum): + m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; + break; + default: + /* Here we should increment the rx_csum_bad_offset counter. */ + return (1); + } + + return (0); +} + +static int +ptnet_rx_csum_by_parse(struct mbuf *m, uint16_t eth_type, int ip_start, + struct virtio_net_hdr *hdr) +{ + int offset, proto; + + switch (eth_type) { +#if defined(INET) + case ETHERTYPE_IP: { + struct ip *ip; + if (__predict_false(m->m_len < ip_start + sizeof(struct ip))) + return (1); + ip = (struct ip *)(m->m_data + ip_start); + proto = ip->ip_p; + offset = ip_start + (ip->ip_hl << 2); + break; + } +#endif +#if defined(INET6) + case ETHERTYPE_IPV6: + if (__predict_false(m->m_len < ip_start + + sizeof(struct ip6_hdr))) + return (1); + offset = ip6_lasthdr(m, ip_start, IPPROTO_IPV6, &proto); + if (__predict_false(offset < 0)) + return (1); + break; +#endif + default: + /* Here we should increment the rx_csum_bad_ethtype counter. */ + return (1); + } + + switch (proto) { + case IPPROTO_TCP: + if (__predict_false(m->m_len < offset + sizeof(struct tcphdr))) + return (1); + m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xFFFF; + break; + case IPPROTO_UDP: + if (__predict_false(m->m_len < offset + sizeof(struct udphdr))) + return (1); + m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xFFFF; + break; + case IPPROTO_SCTP: + if (__predict_false(m->m_len < offset + sizeof(struct sctphdr))) + return (1); + m->m_pkthdr.csum_flags |= CSUM_SCTP_VALID; + break; + default: + /* + * For the remaining protocols, FreeBSD does not support + * checksum offloading, so the checksum will be recomputed. + */ +#if 0 + if_printf(ifp, "cksum offload of unsupported " + "protocol eth_type=%#x proto=%d csum_start=%d " + "csum_offset=%d\n", __func__, eth_type, proto, + hdr->csum_start, hdr->csum_offset); +#endif + break; + } + + return (0); +} + +/* + * Set the appropriate CSUM_* flags. Unfortunately, the information + * provided is not directly useful to us. The VirtIO header gives the + * offset of the checksum, which is all Linux needs, but this is not + * how FreeBSD does things. We are forced to peek inside the packet + * a bit. + * + * It would be nice if VirtIO gave us the L4 protocol or if FreeBSD + * could accept the offsets and let the stack figure it out. + */ +static int +ptnet_rx_csum(struct mbuf *m, struct virtio_net_hdr *hdr) +{ + struct ether_header *eh; + struct ether_vlan_header *evh; + uint16_t eth_type; + int offset, error; + + eh = mtod(m, struct ether_header *); + eth_type = ntohs(eh->ether_type); + if (eth_type == ETHERTYPE_VLAN) { + /* BMV: We should handle nested VLAN tags too. */ + evh = mtod(m, struct ether_vlan_header *); + eth_type = ntohs(evh->evl_proto); + offset = sizeof(struct ether_vlan_header); + } else + offset = sizeof(struct ether_header); + + if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) + error = ptnet_rx_csum_by_offset(m, eth_type, offset, hdr); + else + error = ptnet_rx_csum_by_parse(m, eth_type, offset, hdr); + + return (error); +} +/* End of offloading-related functions to be shared with vtnet. */ + +static inline void +ptnet_sync_tail(struct ptnet_ring *ptring, struct netmap_kring *kring) +{ + struct netmap_ring *ring = kring->ring; + + /* Update hwcur and hwtail as known by the host. */ + ptnetmap_guest_read_kring_csb(ptring, kring); + + /* nm_sync_finalize */ + ring->tail = kring->rtail = kring->nr_hwtail; +} + +static void +ptnet_ring_update(struct ptnet_queue *pq, struct netmap_kring *kring, + unsigned int head, unsigned int sync_flags) +{ + struct netmap_ring *ring = kring->ring; + struct ptnet_ring *ptring = pq->ptring; + + /* Some packets have been pushed to the netmap ring. We have + * to tell the host to process the new packets, updating cur + * and head in the CSB. */ + ring->head = ring->cur = head; + + /* Mimic nm_txsync_prologue/nm_rxsync_prologue. */ + kring->rcur = kring->rhead = head; + + ptnetmap_guest_write_kring_csb(ptring, kring->rcur, kring->rhead); + + /* Kick the host if needed. */ + if (NM_ACCESS_ONCE(ptring->host_need_kick)) { + ptring->sync_flags = sync_flags; + ptnet_kick(pq); + } +} + +#define PTNET_TX_NOSPACE(_h, _k, _min) \ + ((((_h) < (_k)->rtail) ? 0 : (_k)->nkr_num_slots) + \ + (_k)->rtail - (_h)) < (_min) + +/* This function may be called by the network stack, or by + * by the taskqueue thread. */ +static int +ptnet_drain_transmit_queue(struct ptnet_queue *pq, unsigned int budget, + bool may_resched) +{ + struct ptnet_softc *sc = pq->sc; + bool have_vnet_hdr = sc->vnet_hdr_len; + struct netmap_adapter *na = &sc->ptna->dr.up; + if_t ifp = sc->ifp; + unsigned int batch_count = 0; + struct ptnet_ring *ptring; + struct netmap_kring *kring; + struct netmap_ring *ring; + struct netmap_slot *slot; + unsigned int count = 0; + unsigned int minspace; + unsigned int head; + unsigned int lim; + struct mbuf *mhead; + struct mbuf *mf; + int nmbuf_bytes; + uint8_t *nmbuf; + + if (!PTNET_Q_TRYLOCK(pq)) { + /* We failed to acquire the lock, schedule the taskqueue. */ + RD(1, "Deferring TX work"); + if (may_resched) { + taskqueue_enqueue(pq->taskq, &pq->task); + } + + return 0; + } + + if (unlikely(!(ifp->if_drv_flags & IFF_DRV_RUNNING))) { + PTNET_Q_UNLOCK(pq); + RD(1, "Interface is down"); + return ENETDOWN; + } + + ptring = pq->ptring; + kring = na->tx_rings + pq->kring_id; + ring = kring->ring; + lim = kring->nkr_num_slots - 1; + head = ring->head; + minspace = sc->min_tx_space; + + while (count < budget) { + if (PTNET_TX_NOSPACE(head, kring, minspace)) { + /* We ran out of slot, let's see if the host has + * freed up some, by reading hwcur and hwtail from + * the CSB. */ + ptnet_sync_tail(ptring, kring); + + if (PTNET_TX_NOSPACE(head, kring, minspace)) { + /* Still no slots available. Reactivate the + * interrupts so that we can be notified + * when some free slots are made available by + * the host. */ + ptring->guest_need_kick = 1; + + /* Double-check. */ + ptnet_sync_tail(ptring, kring); + if (likely(PTNET_TX_NOSPACE(head, kring, + minspace))) { + break; + } + + RD(1, "Found more slots by doublecheck"); + /* More slots were freed before reactivating + * the interrupts. */ + ptring->guest_need_kick = 0; + } + } + + mhead = drbr_peek(ifp, pq->bufring); + if (!mhead) { + break; + } + + /* Initialize transmission state variables. */ + slot = ring->slot + head; + nmbuf = NMB(na, slot); + nmbuf_bytes = 0; + + /* If needed, prepare the virtio-net header at the beginning + * of the first slot. */ + if (have_vnet_hdr) { + struct virtio_net_hdr *vh = + (struct virtio_net_hdr *)nmbuf; + + /* For performance, we could replace this memset() with + * two 8-bytes-wide writes. */ + memset(nmbuf, 0, PTNET_HDR_SIZE); + if (mhead->m_pkthdr.csum_flags & PTNET_ALL_OFFLOAD) { + mhead = ptnet_tx_offload(ifp, mhead, false, + vh); + if (unlikely(!mhead)) { + /* Packet dropped because errors + * occurred while preparing the vnet + * header. Let's go ahead with the next + * packet. */ + pq->stats.errors ++; + drbr_advance(ifp, pq->bufring); + continue; + } + } + ND(1, "%s: [csum_flags %lX] vnet hdr: flags %x " + "csum_start %u csum_ofs %u hdr_len = %u " + "gso_size %u gso_type %x", __func__, + mhead->m_pkthdr.csum_flags, vh->flags, + vh->csum_start, vh->csum_offset, vh->hdr_len, + vh->gso_size, vh->gso_type); + + nmbuf += PTNET_HDR_SIZE; + nmbuf_bytes += PTNET_HDR_SIZE; + } + + for (mf = mhead; mf; mf = mf->m_next) { + uint8_t *mdata = mf->m_data; + int mlen = mf->m_len; + + for (;;) { + int copy = NETMAP_BUF_SIZE(na) - nmbuf_bytes; + + if (mlen < copy) { + copy = mlen; + } + memcpy(nmbuf, mdata, copy); + + mdata += copy; + mlen -= copy; + nmbuf += copy; + nmbuf_bytes += copy; + + if (!mlen) { + break; + } + + slot->len = nmbuf_bytes; + slot->flags = NS_MOREFRAG; + + head = nm_next(head, lim); + KASSERT(head != ring->tail, + ("Unexpectedly run out of TX space")); + slot = ring->slot + head; + nmbuf = NMB(na, slot); + nmbuf_bytes = 0; + } + } + + /* Complete last slot and update head. */ + slot->len = nmbuf_bytes; + slot->flags = 0; + head = nm_next(head, lim); + + /* Consume the packet just processed. */ + drbr_advance(ifp, pq->bufring); + + /* Copy the packet to listeners. */ + ETHER_BPF_MTAP(ifp, mhead); + + pq->stats.packets ++; + pq->stats.bytes += mhead->m_pkthdr.len; + if (mhead->m_flags & M_MCAST) { + pq->stats.mcasts ++; + } + + m_freem(mhead); + + count ++; + if (++batch_count == PTNET_TX_BATCH) { + ptnet_ring_update(pq, kring, head, NAF_FORCE_RECLAIM); + batch_count = 0; + } + } + + if (batch_count) { + ptnet_ring_update(pq, kring, head, NAF_FORCE_RECLAIM); + } + + if (count >= budget && may_resched) { + DBG(RD(1, "out of budget: resched, %d mbufs pending\n", + drbr_inuse(ifp, pq->bufring))); + taskqueue_enqueue(pq->taskq, &pq->task); + } + + PTNET_Q_UNLOCK(pq); + + return count; +} + +static int +ptnet_transmit(if_t ifp, struct mbuf *m) +{ + struct ptnet_softc *sc = if_getsoftc(ifp); + struct ptnet_queue *pq; + unsigned int queue_idx; + int err; + + DBG(device_printf(sc->dev, "transmit %p\n", m)); + + /* Insert 802.1Q header if needed. */ + if (m->m_flags & M_VLANTAG) { + m = ether_vlanencap(m, m->m_pkthdr.ether_vtag); + if (m == NULL) { + return ENOBUFS; + } + m->m_flags &= ~M_VLANTAG; + } + + /* Get the flow-id if available. */ + queue_idx = (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) ? + m->m_pkthdr.flowid : curcpu; + + if (unlikely(queue_idx >= sc->num_tx_rings)) { + queue_idx %= sc->num_tx_rings; + } + + pq = sc->queues + queue_idx; + + err = drbr_enqueue(ifp, pq->bufring, m); + if (err) { + /* ENOBUFS when the bufring is full */ + RD(1, "%s: drbr_enqueue() failed %d\n", + __func__, err); + pq->stats.errors ++; + return err; + } + + if (ifp->if_capenable & IFCAP_POLLING) { + /* If polling is on, the transmit queues will be + * drained by the poller. */ + return 0; + } + + err = ptnet_drain_transmit_queue(pq, PTNET_TX_BUDGET, true); + + return (err < 0) ? err : 0; +} + +static unsigned int +ptnet_rx_discard(struct netmap_kring *kring, unsigned int head) +{ + struct netmap_ring *ring = kring->ring; + struct netmap_slot *slot = ring->slot + head; + + for (;;) { + head = nm_next(head, kring->nkr_num_slots - 1); + if (!(slot->flags & NS_MOREFRAG) || head == ring->tail) { + break; + } + slot = ring->slot + head; + } + + return head; +} + +static inline struct mbuf * +ptnet_rx_slot(struct mbuf *mtail, uint8_t *nmbuf, unsigned int nmbuf_len) +{ + uint8_t *mdata = mtod(mtail, uint8_t *) + mtail->m_len; + + do { + unsigned int copy; + + if (mtail->m_len == MCLBYTES) { + struct mbuf *mf; + + mf = m_getcl(M_NOWAIT, MT_DATA, 0); + if (unlikely(!mf)) { + return NULL; + } + + mtail->m_next = mf; + mtail = mf; + mdata = mtod(mtail, uint8_t *); + mtail->m_len = 0; + } + + copy = MCLBYTES - mtail->m_len; + if (nmbuf_len < copy) { + copy = nmbuf_len; + } + + memcpy(mdata, nmbuf, copy); + + nmbuf += copy; + nmbuf_len -= copy; + mdata += copy; + mtail->m_len += copy; + } while (nmbuf_len); + + return mtail; +} + +static int +ptnet_rx_eof(struct ptnet_queue *pq, unsigned int budget, bool may_resched) +{ + struct ptnet_softc *sc = pq->sc; + bool have_vnet_hdr = sc->vnet_hdr_len; + struct ptnet_ring *ptring = pq->ptring; + struct netmap_adapter *na = &sc->ptna->dr.up; + struct netmap_kring *kring = na->rx_rings + pq->kring_id; + struct netmap_ring *ring = kring->ring; + unsigned int const lim = kring->nkr_num_slots - 1; + unsigned int head = ring->head; + unsigned int batch_count = 0; + if_t ifp = sc->ifp; + unsigned int count = 0; + + PTNET_Q_LOCK(pq); + + if (unlikely(!(ifp->if_drv_flags & IFF_DRV_RUNNING))) { + goto unlock; + } + + kring->nr_kflags &= ~NKR_PENDINTR; + + while (count < budget) { + unsigned int prev_head = head; + struct mbuf *mhead, *mtail; + struct virtio_net_hdr *vh; + struct netmap_slot *slot; + unsigned int nmbuf_len; + uint8_t *nmbuf; +host_sync: + if (head == ring->tail) { + /* We ran out of slot, let's see if the host has + * added some, by reading hwcur and hwtail from + * the CSB. */ + ptnet_sync_tail(ptring, kring); + + if (head == ring->tail) { + /* Still no slots available. Reactivate + * interrupts as they were disabled by the + * host thread right before issuing the + * last interrupt. */ + ptring->guest_need_kick = 1; + + /* Double-check. */ + ptnet_sync_tail(ptring, kring); + if (likely(head == ring->tail)) { + break; + } + ptring->guest_need_kick = 0; + } + } + + /* Initialize ring state variables, possibly grabbing the + * virtio-net header. */ + slot = ring->slot + head; + nmbuf = NMB(na, slot); + nmbuf_len = slot->len; + + vh = (struct virtio_net_hdr *)nmbuf; + if (have_vnet_hdr) { + if (unlikely(nmbuf_len < PTNET_HDR_SIZE)) { + /* There is no good reason why host should + * put the header in multiple netmap slots. + * If this is the case, discard. */ + RD(1, "Fragmented vnet-hdr: dropping"); + head = ptnet_rx_discard(kring, head); + pq->stats.iqdrops ++; + goto skip; + } + ND(1, "%s: vnet hdr: flags %x csum_start %u " + "csum_ofs %u hdr_len = %u gso_size %u " + "gso_type %x", __func__, vh->flags, + vh->csum_start, vh->csum_offset, vh->hdr_len, + vh->gso_size, vh->gso_type); + nmbuf += PTNET_HDR_SIZE; + nmbuf_len -= PTNET_HDR_SIZE; + } + + /* Allocate the head of a new mbuf chain. + * We use m_getcl() to allocate an mbuf with standard cluster + * size (MCLBYTES). In the future we could use m_getjcl() + * to choose different sizes. */ + mhead = mtail = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); + if (unlikely(mhead == NULL)) { + device_printf(sc->dev, "%s: failed to allocate mbuf " + "head\n", __func__); + pq->stats.errors ++; + break; + } + + /* Initialize the mbuf state variables. */ + mhead->m_pkthdr.len = nmbuf_len; + mtail->m_len = 0; + + /* Scan all the netmap slots containing the current packet. */ + for (;;) { + DBG(device_printf(sc->dev, "%s: h %u t %u rcv frag " + "len %u, flags %u\n", __func__, + head, ring->tail, slot->len, + slot->flags)); + + mtail = ptnet_rx_slot(mtail, nmbuf, nmbuf_len); + if (unlikely(!mtail)) { + /* Ouch. We ran out of memory while processing + * a packet. We have to restore the previous + * head position, free the mbuf chain, and + * schedule the taskqueue to give the packet + * another chance. */ + device_printf(sc->dev, "%s: failed to allocate" + " mbuf frag, reset head %u --> %u\n", + __func__, head, prev_head); + head = prev_head; + m_freem(mhead); + pq->stats.errors ++; + if (may_resched) { + taskqueue_enqueue(pq->taskq, + &pq->task); + } + goto escape; + } + + /* We have to increment head irrespective of the + * NS_MOREFRAG being set or not. */ + head = nm_next(head, lim); + + if (!(slot->flags & NS_MOREFRAG)) { + break; + } + + if (unlikely(head == ring->tail)) { + /* The very last slot prepared by the host has + * the NS_MOREFRAG set. Drop it and continue + * the outer cycle (to do the double-check). */ + RD(1, "Incomplete packet: dropping"); + m_freem(mhead); + pq->stats.iqdrops ++; + goto host_sync; + } + + slot = ring->slot + head; + nmbuf = NMB(na, slot); + nmbuf_len = slot->len; + mhead->m_pkthdr.len += nmbuf_len; + } + + mhead->m_pkthdr.rcvif = ifp; + mhead->m_pkthdr.csum_flags = 0; + + /* Store the queue idx in the packet header. */ + mhead->m_pkthdr.flowid = pq->kring_id; + M_HASHTYPE_SET(mhead, M_HASHTYPE_OPAQUE); + + if (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) { + struct ether_header *eh; + + eh = mtod(mhead, struct ether_header *); + if (eh->ether_type == htons(ETHERTYPE_VLAN)) { + ptnet_vlan_tag_remove(mhead); + /* + * With the 802.1Q header removed, update the + * checksum starting location accordingly. + */ + if (vh->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) + vh->csum_start -= ETHER_VLAN_ENCAP_LEN; + } + } + + if (have_vnet_hdr && (vh->flags & (VIRTIO_NET_HDR_F_NEEDS_CSUM + | VIRTIO_NET_HDR_F_DATA_VALID))) { + if (unlikely(ptnet_rx_csum(mhead, vh))) { + m_freem(mhead); + RD(1, "Csum offload error: dropping"); + pq->stats.iqdrops ++; + goto skip; + } + } + + pq->stats.packets ++; + pq->stats.bytes += mhead->m_pkthdr.len; + + PTNET_Q_UNLOCK(pq); + (*ifp->if_input)(ifp, mhead); + PTNET_Q_LOCK(pq); + + if (unlikely(!(ifp->if_drv_flags & IFF_DRV_RUNNING))) { + /* The interface has gone down while we didn't + * have the lock. Stop any processing and exit. */ + goto unlock; + } +skip: + count ++; + if (++batch_count == PTNET_RX_BATCH) { + /* Some packets have been pushed to the network stack. + * We need to update the CSB to tell the host about the new + * ring->cur and ring->head (RX buffer refill). */ + ptnet_ring_update(pq, kring, head, NAF_FORCE_READ); + batch_count = 0; + } + } +escape: + if (batch_count) { + ptnet_ring_update(pq, kring, head, NAF_FORCE_READ); + + } + + if (count >= budget && may_resched) { + /* If we ran out of budget or the double-check found new + * slots to process, schedule the taskqueue. */ + DBG(RD(1, "out of budget: resched h %u t %u\n", + head, ring->tail)); + taskqueue_enqueue(pq->taskq, &pq->task); + } +unlock: + PTNET_Q_UNLOCK(pq); + + return count; +} + +static void +ptnet_rx_task(void *context, int pending) +{ + struct ptnet_queue *pq = context; + + DBG(RD(1, "%s: pq #%u\n", __func__, pq->kring_id)); + ptnet_rx_eof(pq, PTNET_RX_BUDGET, true); +} + +static void +ptnet_tx_task(void *context, int pending) +{ + struct ptnet_queue *pq = context; + + DBG(RD(1, "%s: pq #%u\n", __func__, pq->kring_id)); + ptnet_drain_transmit_queue(pq, PTNET_TX_BUDGET, true); +} + +#ifdef DEVICE_POLLING +/* We don't need to handle differently POLL_AND_CHECK_STATUS and + * POLL_ONLY, since we don't have an Interrupt Status Register. */ +static int +ptnet_poll(if_t ifp, enum poll_cmd cmd, int budget) +{ + struct ptnet_softc *sc = if_getsoftc(ifp); + unsigned int queue_budget; + unsigned int count = 0; + bool borrow = false; + int i; + + KASSERT(sc->num_rings > 0, ("Found no queues in while polling ptnet")); + queue_budget = MAX(budget / sc->num_rings, 1); + RD(1, "Per-queue budget is %d", queue_budget); + + while (budget) { + unsigned int rcnt = 0; + + for (i = 0; i < sc->num_rings; i++) { + struct ptnet_queue *pq = sc->queues + i; + + if (borrow) { + queue_budget = MIN(queue_budget, budget); + if (queue_budget == 0) { + break; + } + } + + if (i < sc->num_tx_rings) { + rcnt += ptnet_drain_transmit_queue(pq, + queue_budget, false); + } else { + rcnt += ptnet_rx_eof(pq, queue_budget, + false); + } + } + + if (!rcnt) { + /* A scan of the queues gave no result, we can + * stop here. */ + break; + } + + if (rcnt > budget) { + /* This may happen when initial budget < sc->num_rings, + * since one packet budget is given to each queue + * anyway. Just pretend we didn't eat "so much". */ + rcnt = budget; + } + count += rcnt; + budget -= rcnt; + borrow = true; + } + + + return count; +} +#endif /* DEVICE_POLLING */ diff --git a/sys/dev/netmap/if_vtnet_netmap.h b/sys/dev/netmap/if_vtnet_netmap.h index 791cee56bcee..4bed0e718dd4 100644 --- a/sys/dev/netmap/if_vtnet_netmap.h +++ b/sys/dev/netmap/if_vtnet_netmap.h @@ -127,7 +127,7 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags) * First part: process new packets to send. */ rmb(); - + nm_i = kring->nr_hwcur; if (nm_i != head) { /* we have new packets to send */ struct sglist *sg = txq->vtntx_sg; @@ -182,7 +182,7 @@ vtnet_netmap_txsync(struct netmap_kring *kring, int flags) virtqueue_enable_intr(vq); // like postpone with 0 } - + /* Free used slots. We only consider our own used buffers, recognized * by the token we passed to virtqueue_add_outbuf. */ diff --git a/sys/dev/netmap/ixgbe_netmap.h b/sys/dev/netmap/ixgbe_netmap.h index 0f34e7218503..7986c9965173 100644 --- a/sys/dev/netmap/ixgbe_netmap.h +++ b/sys/dev/netmap/ixgbe_netmap.h @@ -53,7 +53,7 @@ void ixgbe_netmap_attach(struct adapter *adapter); /* * device-specific sysctl variables: * - * ix_crcstrip: 0: keep CRC in rx frames (default), 1: strip it. + * ix_crcstrip: 0: NIC keeps CRC in rx frames (default), 1: NIC strips it. * During regular operations the CRC is stripped, but on some * hardware reception of frames not multiple of 64 is slower, * so using crcstrip=0 helps in benchmarks. @@ -65,7 +65,7 @@ SYSCTL_DECL(_dev_netmap); static int ix_rx_miss, ix_rx_miss_bufs; int ix_crcstrip; SYSCTL_INT(_dev_netmap, OID_AUTO, ix_crcstrip, - CTLFLAG_RW, &ix_crcstrip, 0, "strip CRC on rx frames"); + CTLFLAG_RW, &ix_crcstrip, 0, "NIC strips CRC on rx frames"); SYSCTL_INT(_dev_netmap, OID_AUTO, ix_rx_miss, CTLFLAG_RW, &ix_rx_miss, 0, "potentially missed rx intr"); SYSCTL_INT(_dev_netmap, OID_AUTO, ix_rx_miss_bufs, @@ -109,6 +109,20 @@ set_crcstrip(struct ixgbe_hw *hw, int onoff) IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rxc); } +static void +ixgbe_netmap_intr(struct netmap_adapter *na, int onoff) +{ + struct ifnet *ifp = na->ifp; + struct adapter *adapter = ifp->if_softc; + + IXGBE_CORE_LOCK(adapter); + if (onoff) { + ixgbe_enable_intr(adapter); // XXX maybe ixgbe_stop ? + } else { + ixgbe_disable_intr(adapter); // XXX maybe ixgbe_stop ? + } + IXGBE_CORE_UNLOCK(adapter); +} /* * Register/unregister. We are already under netmap lock. @@ -311,7 +325,7 @@ ixgbe_netmap_txsync(struct netmap_kring *kring, int flags) * good way. */ nic_i = IXGBE_READ_REG(&adapter->hw, IXGBE_IS_VF(adapter) ? - IXGBE_VFTDH(kring->ring_id) : IXGBE_TDH(kring->ring_id)); + IXGBE_VFTDH(kring->ring_id) : IXGBE_TDH(kring->ring_id)); if (nic_i >= kring->nkr_num_slots) { /* XXX can it happen ? */ D("TDH wrap %d", nic_i); nic_i -= kring->nkr_num_slots; @@ -486,6 +500,7 @@ ixgbe_netmap_attach(struct adapter *adapter) na.nm_rxsync = ixgbe_netmap_rxsync; na.nm_register = ixgbe_netmap_reg; na.num_tx_rings = na.num_rx_rings = adapter->num_queues; + na.nm_intr = ixgbe_netmap_intr; netmap_attach(&na); } diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index aff757bdadfe..46aca2eab5e2 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -1,5 +1,9 @@ /* - * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved. + * Copyright (C) 2011-2014 Matteo Landi + * Copyright (C) 2011-2016 Luigi Rizzo + * Copyright (C) 2011-2016 Giuseppe Lettieri + * Copyright (C) 2011-2016 Vincenzo Maffione + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -133,13 +137,12 @@ ports attached to the switch) * > select()able file descriptor on which events are reported. * * Internally, we allocate a netmap_priv_d structure, that will be - * initialized on ioctl(NIOCREGIF). + * initialized on ioctl(NIOCREGIF). There is one netmap_priv_d + * structure for each open(). * * os-specific: - * FreeBSD: netmap_open (netmap_freebsd.c). The priv is - * per-thread. - * linux: linux_netmap_open (netmap_linux.c). The priv is - * per-open. + * FreeBSD: see netmap_open() (netmap_freebsd.c) + * linux: see linux_netmap_open() (netmap_linux.c) * * > 2. on each descriptor, the process issues an ioctl() to identify * > the interface that should report events to the file descriptor. @@ -299,18 +302,17 @@ ports attached to the switch) * netmap_transmit() * na->nm_notify == netmap_notify() * 2) ioctl(NIOCRXSYNC)/netmap_poll() in process context - * kring->nm_sync() == netmap_rxsync_from_host_compat + * kring->nm_sync() == netmap_rxsync_from_host * netmap_rxsync_from_host(na, NULL, NULL) * - tx to host stack * ioctl(NIOCTXSYNC)/netmap_poll() in process context - * kring->nm_sync() == netmap_txsync_to_host_compat + * kring->nm_sync() == netmap_txsync_to_host * netmap_txsync_to_host(na) - * NM_SEND_UP() - * FreeBSD: na->if_input() == ?? XXX + * nm_os_send_up() + * FreeBSD: na->if_input() == ether_input() * linux: netif_rx() with NM_MAGIC_PRIORITY_RX * * - * * -= SYSTEM DEVICE WITH GENERIC SUPPORT =- * * na == NA(ifp) == generic_netmap_adapter created in generic_netmap_attach() @@ -319,10 +321,11 @@ ports attached to the switch) * concurrently: * 1) ioctl(NIOCTXSYNC)/netmap_poll() in process context * kring->nm_sync() == generic_netmap_txsync() - * linux: dev_queue_xmit() with NM_MAGIC_PRIORITY_TX - * generic_ndo_start_xmit() - * orig. dev. start_xmit - * FreeBSD: na->if_transmit() == orig. dev if_transmit + * nm_os_generic_xmit_frame() + * linux: dev_queue_xmit() with NM_MAGIC_PRIORITY_TX + * ifp->ndo_start_xmit == generic_ndo_start_xmit() + * gna->save_start_xmit == orig. dev. start_xmit + * FreeBSD: na->if_transmit() == orig. dev if_transmit * 2) generic_mbuf_destructor() * na->nm_notify() == netmap_notify() * - rx from netmap userspace: @@ -333,24 +336,15 @@ ports attached to the switch) * generic_rx_handler() * mbq_safe_enqueue() * na->nm_notify() == netmap_notify() - * - rx from host stack: - * concurrently: + * - rx from host stack + * FreeBSD: same as native + * Linux: same as native except: * 1) host stack - * linux: generic_ndo_start_xmit() - * netmap_transmit() - * FreeBSD: ifp->if_input() == netmap_transmit - * both: - * na->nm_notify() == netmap_notify() - * 2) ioctl(NIOCRXSYNC)/netmap_poll() in process context - * kring->nm_sync() == netmap_rxsync_from_host_compat - * netmap_rxsync_from_host(na, NULL, NULL) - * - tx to host stack: - * ioctl(NIOCTXSYNC)/netmap_poll() in process context - * kring->nm_sync() == netmap_txsync_to_host_compat - * netmap_txsync_to_host(na) - * NM_SEND_UP() - * FreeBSD: na->if_input() == ??? XXX - * linux: netif_rx() with NM_MAGIC_PRIORITY_RX + * dev_queue_xmit() without NM_MAGIC_PRIORITY_TX + * ifp->ndo_start_xmit == generic_ndo_start_xmit() + * netmap_transmit() + * na->nm_notify() == netmap_notify() + * - tx to host stack (same as native): * * * -= VALE =- @@ -371,7 +365,7 @@ ports attached to the switch) * from host stack: * netmap_transmit() * na->nm_notify() == netmap_bwrap_intr_notify(ring_nr == host ring) - * kring->nm_sync() == netmap_rxsync_from_host_compat() + * kring->nm_sync() == netmap_rxsync_from_host() * netmap_vp_txsync() * * - system device with generic support: @@ -384,7 +378,7 @@ ports attached to the switch) * from host stack: * netmap_transmit() * na->nm_notify() == netmap_bwrap_intr_notify(ring_nr == host ring) - * kring->nm_sync() == netmap_rxsync_from_host_compat() + * kring->nm_sync() == netmap_rxsync_from_host() * netmap_vp_txsync() * * (all cases) --> nm_bdg_flush() @@ -407,7 +401,7 @@ ports attached to the switch) * netmap_vp_rxsync() * to host stack: * netmap_vp_rxsync() - * kring->nm_sync() == netmap_txsync_to_host_compat + * kring->nm_sync() == netmap_txsync_to_host * netmap_vp_rxsync_locked() * * - system device with generic adapter: @@ -418,7 +412,7 @@ ports attached to the switch) * netmap_vp_rxsync() * to host stack: * netmap_vp_rxsync() - * kring->nm_sync() == netmap_txsync_to_host_compat + * kring->nm_sync() == netmap_txsync_to_host * netmap_vp_rxsync() * */ @@ -455,29 +449,19 @@ ports attached to the switch) #include -/* reduce conditional code */ -// linux API, use for the knlist in FreeBSD -/* use a private mutex for the knlist */ -#define init_waitqueue_head(x) do { \ - struct mtx *m = &(x)->m; \ - mtx_init(m, "nm_kn_lock", NULL, MTX_DEF); \ - knlist_init_mtx(&(x)->si.si_note, m); \ - } while (0) - -#define OS_selrecord(a, b) selrecord(a, &((b)->si)) -#define OS_selwakeup(a, b) freebsd_selwakeup(a, b) - #elif defined(linux) #include "bsd_glue.h" - - #elif defined(__APPLE__) #warning OSX support is only partial #include "osx_glue.h" +#elif defined (_WIN32) + +#include "win_glue.h" + #else #error Unsupported platform @@ -492,47 +476,69 @@ ports attached to the switch) #include -MALLOC_DEFINE(M_NETMAP, "netmap", "Network memory map"); - /* user-controlled variables */ int netmap_verbose; static int netmap_no_timestamp; /* don't timestamp on rxsync */ - -SYSCTL_NODE(_dev, OID_AUTO, netmap, CTLFLAG_RW, 0, "Netmap args"); -SYSCTL_INT(_dev_netmap, OID_AUTO, verbose, - CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode"); -SYSCTL_INT(_dev_netmap, OID_AUTO, no_timestamp, - CTLFLAG_RW, &netmap_no_timestamp, 0, "no_timestamp"); int netmap_mitigate = 1; -SYSCTL_INT(_dev_netmap, OID_AUTO, mitigate, CTLFLAG_RW, &netmap_mitigate, 0, ""); int netmap_no_pendintr = 1; -SYSCTL_INT(_dev_netmap, OID_AUTO, no_pendintr, - CTLFLAG_RW, &netmap_no_pendintr, 0, "Always look for new received packets."); int netmap_txsync_retry = 2; -SYSCTL_INT(_dev_netmap, OID_AUTO, txsync_retry, CTLFLAG_RW, - &netmap_txsync_retry, 0 , "Number of txsync loops in bridge's flush."); - -int netmap_adaptive_io = 0; -SYSCTL_INT(_dev_netmap, OID_AUTO, adaptive_io, CTLFLAG_RW, - &netmap_adaptive_io, 0 , "Adaptive I/O on paravirt"); - int netmap_flags = 0; /* debug flags */ -int netmap_fwd = 0; /* force transparent mode */ +static int netmap_fwd = 0; /* force transparent mode */ /* * netmap_admode selects the netmap mode to use. * Invalid values are reset to NETMAP_ADMODE_BEST */ -enum { NETMAP_ADMODE_BEST = 0, /* use native, fallback to generic */ +enum { NETMAP_ADMODE_BEST = 0, /* use native, fallback to generic */ NETMAP_ADMODE_NATIVE, /* either native or none */ NETMAP_ADMODE_GENERIC, /* force generic */ NETMAP_ADMODE_LAST }; static int netmap_admode = NETMAP_ADMODE_BEST; -int netmap_generic_mit = 100*1000; /* Generic mitigation interval in nanoseconds. */ -int netmap_generic_ringsize = 1024; /* Generic ringsize. */ -int netmap_generic_rings = 1; /* number of queues in generic. */ +/* netmap_generic_mit controls mitigation of RX notifications for + * the generic netmap adapter. The value is a time interval in + * nanoseconds. */ +int netmap_generic_mit = 100*1000; + +/* We use by default netmap-aware qdiscs with generic netmap adapters, + * even if there can be a little performance hit with hardware NICs. + * However, using the qdisc is the safer approach, for two reasons: + * 1) it prevents non-fifo qdiscs to break the TX notification + * scheme, which is based on mbuf destructors when txqdisc is + * not used. + * 2) it makes it possible to transmit over software devices that + * change skb->dev, like bridge, veth, ... + * + * Anyway users looking for the best performance should + * use native adapters. + */ +int netmap_generic_txqdisc = 1; + +/* Default number of slots and queues for generic adapters. */ +int netmap_generic_ringsize = 1024; +int netmap_generic_rings = 1; + +/* Non-zero if ptnet devices are allowed to use virtio-net headers. */ +int ptnet_vnet_hdr = 1; + +/* + * SYSCTL calls are grouped between SYSBEGIN and SYSEND to be emulated + * in some other operating systems + */ +SYSBEGIN(main_init); + +SYSCTL_DECL(_dev_netmap); +SYSCTL_NODE(_dev, OID_AUTO, netmap, CTLFLAG_RW, 0, "Netmap args"); +SYSCTL_INT(_dev_netmap, OID_AUTO, verbose, + CTLFLAG_RW, &netmap_verbose, 0, "Verbose mode"); +SYSCTL_INT(_dev_netmap, OID_AUTO, no_timestamp, + CTLFLAG_RW, &netmap_no_timestamp, 0, "no_timestamp"); +SYSCTL_INT(_dev_netmap, OID_AUTO, mitigate, CTLFLAG_RW, &netmap_mitigate, 0, ""); +SYSCTL_INT(_dev_netmap, OID_AUTO, no_pendintr, + CTLFLAG_RW, &netmap_no_pendintr, 0, "Always look for new received packets."); +SYSCTL_INT(_dev_netmap, OID_AUTO, txsync_retry, CTLFLAG_RW, + &netmap_txsync_retry, 0 , "Number of txsync loops in bridge's flush."); SYSCTL_INT(_dev_netmap, OID_AUTO, flags, CTLFLAG_RW, &netmap_flags, 0 , ""); SYSCTL_INT(_dev_netmap, OID_AUTO, fwd, CTLFLAG_RW, &netmap_fwd, 0 , ""); @@ -540,19 +546,24 @@ SYSCTL_INT(_dev_netmap, OID_AUTO, admode, CTLFLAG_RW, &netmap_admode, 0 , ""); SYSCTL_INT(_dev_netmap, OID_AUTO, generic_mit, CTLFLAG_RW, &netmap_generic_mit, 0 , ""); SYSCTL_INT(_dev_netmap, OID_AUTO, generic_ringsize, CTLFLAG_RW, &netmap_generic_ringsize, 0 , ""); SYSCTL_INT(_dev_netmap, OID_AUTO, generic_rings, CTLFLAG_RW, &netmap_generic_rings, 0 , ""); +SYSCTL_INT(_dev_netmap, OID_AUTO, generic_txqdisc, CTLFLAG_RW, &netmap_generic_txqdisc, 0 , ""); +SYSCTL_INT(_dev_netmap, OID_AUTO, ptnet_vnet_hdr, CTLFLAG_RW, &ptnet_vnet_hdr, 0 , ""); + +SYSEND; NMG_LOCK_T netmap_global_lock; -int netmap_use_count = 0; /* number of active netmap instances */ /* * mark the ring as stopped, and run through the locks * to make sure other users get to see it. + * stopped must be either NR_KR_STOPPED (for unbounded stop) + * of NR_KR_LOCKED (brief stop for mutual exclusion purposes) */ static void -netmap_disable_ring(struct netmap_kring *kr) +netmap_disable_ring(struct netmap_kring *kr, int stopped) { - kr->nkr_stopped = 1; - nm_kr_get(kr); + nm_kr_stop(kr, stopped); + // XXX check if nm_kr_stop is sufficient mtx_lock(&kr->q_lock); mtx_unlock(&kr->q_lock); nm_kr_put(kr); @@ -563,7 +574,7 @@ void netmap_set_ring(struct netmap_adapter *na, u_int ring_id, enum txrx t, int stopped) { if (stopped) - netmap_disable_ring(NMR(na, t) + ring_id); + netmap_disable_ring(NMR(na, t) + ring_id, stopped); else NMR(na, t)[ring_id].nkr_stopped = 0; } @@ -590,13 +601,14 @@ netmap_set_all_rings(struct netmap_adapter *na, int stopped) * Convenience function used in drivers. Waits for current txsync()s/rxsync()s * to finish and prevents any new one from starting. Call this before turning * netmap mode off, or before removing the hardware rings (e.g., on module - * onload). As a rule of thumb for linux drivers, this should be placed near - * each napi_disable(). + * onload). */ void netmap_disable_all_rings(struct ifnet *ifp) { - netmap_set_all_rings(NA(ifp), 1 /* stopped */); + if (NM_NA_VALID(ifp)) { + netmap_set_all_rings(NA(ifp), NM_KR_STOPPED); + } } /* @@ -607,9 +619,34 @@ netmap_disable_all_rings(struct ifnet *ifp) void netmap_enable_all_rings(struct ifnet *ifp) { - netmap_set_all_rings(NA(ifp), 0 /* enabled */); + if (NM_NA_VALID(ifp)) { + netmap_set_all_rings(NA(ifp), 0 /* enabled */); + } } +void +netmap_make_zombie(struct ifnet *ifp) +{ + if (NM_NA_VALID(ifp)) { + struct netmap_adapter *na = NA(ifp); + netmap_set_all_rings(na, NM_KR_LOCKED); + na->na_flags |= NAF_ZOMBIE; + netmap_set_all_rings(na, 0); + } +} + +void +netmap_undo_zombie(struct ifnet *ifp) +{ + if (NM_NA_VALID(ifp)) { + struct netmap_adapter *na = NA(ifp); + if (na->na_flags & NAF_ZOMBIE) { + netmap_set_all_rings(na, NM_KR_LOCKED); + na->na_flags &= ~NAF_ZOMBIE; + netmap_set_all_rings(na, 0); + } + } +} /* * generic bound_checking function @@ -727,28 +764,9 @@ netmap_update_config(struct netmap_adapter *na) return 1; } -static void netmap_txsync_to_host(struct netmap_adapter *na); -static int netmap_rxsync_from_host(struct netmap_adapter *na, struct thread *td, void *pwait); - -/* kring->nm_sync callback for the host tx ring */ -static int -netmap_txsync_to_host_compat(struct netmap_kring *kring, int flags) -{ - (void)flags; /* unused */ - netmap_txsync_to_host(kring->na); - return 0; -} - -/* kring->nm_sync callback for the host rx ring */ -static int -netmap_rxsync_from_host_compat(struct netmap_kring *kring, int flags) -{ - (void)flags; /* unused */ - netmap_rxsync_from_host(kring->na, NULL, NULL); - return 0; -} - - +/* nm_sync callbacks for the host rings */ +static int netmap_txsync_to_host(struct netmap_kring *kring, int flags); +static int netmap_rxsync_from_host(struct netmap_kring *kring, int flags); /* create the krings array and initialize the fields common to all adapters. * The array layout is this: @@ -809,12 +827,14 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom) kring->ring_id = i; kring->tx = t; kring->nkr_num_slots = ndesc; + kring->nr_mode = NKR_NETMAP_OFF; + kring->nr_pending_mode = NKR_NETMAP_OFF; if (i < nma_get_nrings(na, t)) { kring->nm_sync = (t == NR_TX ? na->nm_txsync : na->nm_rxsync); - } else if (i == na->num_tx_rings) { + } else { kring->nm_sync = (t == NR_TX ? - netmap_txsync_to_host_compat : - netmap_rxsync_from_host_compat); + netmap_txsync_to_host: + netmap_rxsync_from_host); } kring->nm_notify = na->nm_notify; kring->rhead = kring->rcur = kring->nr_hwcur = 0; @@ -822,14 +842,14 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom) * IMPORTANT: Always keep one slot empty. */ kring->rtail = kring->nr_hwtail = (t == NR_TX ? ndesc - 1 : 0); - snprintf(kring->name, sizeof(kring->name) - 1, "%s %s%d", na->name, + snprintf(kring->name, sizeof(kring->name) - 1, "%s %s%d", na->name, nm_txrx2str(t), i); ND("ktx %s h %d c %d t %d", kring->name, kring->rhead, kring->rcur, kring->rtail); mtx_init(&kring->q_lock, (t == NR_TX ? "nm_txq_lock" : "nm_rxq_lock"), NULL, MTX_DEF); - init_waitqueue_head(&kring->si); + nm_os_selinfo_init(&kring->si); } - init_waitqueue_head(&na->si[t]); + nm_os_selinfo_init(&na->si[t]); } na->tailroom = na->rx_rings + n[NR_RX]; @@ -838,19 +858,6 @@ netmap_krings_create(struct netmap_adapter *na, u_int tailroom) } -#ifdef __FreeBSD__ -static void -netmap_knlist_destroy(NM_SELINFO_T *si) -{ - /* XXX kqueue(9) needed; these will mirror knlist_init. */ - knlist_delete(&si->si.si_note, curthread, 0 /* not locked */ ); - knlist_destroy(&si->si.si_note); - /* now we don't need the mutex anymore */ - mtx_destroy(&si->m); -} -#endif /* __FreeBSD__ */ - - /* undo the actions performed by netmap_krings_create */ /* call with NMG_LOCK held */ void @@ -860,12 +867,12 @@ netmap_krings_delete(struct netmap_adapter *na) enum txrx t; for_rx_tx(t) - netmap_knlist_destroy(&na->si[t]); + nm_os_selinfo_uninit(&na->si[t]); /* we rely on the krings layout described above */ for ( ; kring != na->tailroom; kring++) { mtx_destroy(&kring->q_lock); - netmap_knlist_destroy(&kring->si); + nm_os_selinfo_uninit(&kring->si); } free(na->tx_rings, M_DEVBUF); na->tx_rings = na->rx_rings = na->tailroom = NULL; @@ -878,14 +885,14 @@ netmap_krings_delete(struct netmap_adapter *na) * them first. */ /* call with NMG_LOCK held */ -static void +void netmap_hw_krings_delete(struct netmap_adapter *na) { struct mbq *q = &na->rx_rings[na->num_rx_rings].rx_queue; ND("destroy sw mbq with len %d", mbq_len(q)); mbq_purge(q); - mbq_safe_destroy(q); + mbq_safe_fini(q); netmap_krings_delete(na); } @@ -898,29 +905,38 @@ netmap_hw_krings_delete(struct netmap_adapter *na) */ /* call with NMG_LOCK held */ static void netmap_unset_ringid(struct netmap_priv_d *); -static void netmap_rel_exclusive(struct netmap_priv_d *); -static void +static void netmap_krings_put(struct netmap_priv_d *); +void netmap_do_unregif(struct netmap_priv_d *priv) { struct netmap_adapter *na = priv->np_na; NMG_LOCK_ASSERT(); na->active_fds--; - /* release exclusive use if it was requested on regif */ - netmap_rel_exclusive(priv); - if (na->active_fds <= 0) { /* last instance */ - - if (netmap_verbose) - D("deleting last instance for %s", na->name); + /* unset nr_pending_mode and possibly release exclusive mode */ + netmap_krings_put(priv); #ifdef WITH_MONITOR + /* XXX check whether we have to do something with monitor + * when rings change nr_mode. */ + if (na->active_fds <= 0) { /* walk through all the rings and tell any monitor * that the port is going to exit netmap mode */ netmap_monitor_stop(na); + } #endif + + if (na->active_fds <= 0 || nm_kring_pending(priv)) { + na->nm_register(na, 0); + } + + /* delete rings and buffers that are no longer needed */ + netmap_mem_rings_delete(na); + + if (na->active_fds <= 0) { /* last instance */ /* - * (TO CHECK) This function is only called + * (TO CHECK) We enter here * when the last reference to this file descriptor goes * away. This means we cannot have any pending poll() * or interrupt routine operating on the structure. @@ -933,16 +949,16 @@ netmap_do_unregif(struct netmap_priv_d *priv) * happens if the close() occurs while a concurrent * syscall is running. */ - na->nm_register(na, 0); /* off, clear flags */ - /* Wake up any sleeping threads. netmap_poll will - * then return POLLERR - * XXX The wake up now must happen during *_down(), when - * we order all activities to stop. -gl - */ - /* delete rings and buffers */ - netmap_mem_rings_delete(na); + if (netmap_verbose) + D("deleting last instance for %s", na->name); + + if (nm_netmap_on(na)) { + D("BUG: netmap on while going to delete the krings"); + } + na->nm_krings_delete(na); } + /* possibily decrement counter of tx_si/rx_si users */ netmap_unset_ringid(priv); /* delete the nifp */ @@ -962,6 +978,20 @@ nm_si_user(struct netmap_priv_d *priv, enum txrx t) (priv->np_qlast[t] - priv->np_qfirst[t] > 1)); } +struct netmap_priv_d* +netmap_priv_new(void) +{ + struct netmap_priv_d *priv; + + priv = malloc(sizeof(struct netmap_priv_d), M_DEVBUF, + M_NOWAIT | M_ZERO); + if (priv == NULL) + return NULL; + priv->np_refs = 1; + nm_os_get_module(); + return priv; +} + /* * Destructor of the netmap_priv_d, called when the fd is closed * Action: undo all the things done by NIOCREGIF, @@ -971,22 +1001,22 @@ nm_si_user(struct netmap_priv_d *priv, enum txrx t) * */ /* call with NMG_LOCK held */ -int -netmap_dtor_locked(struct netmap_priv_d *priv) +void +netmap_priv_delete(struct netmap_priv_d *priv) { struct netmap_adapter *na = priv->np_na; /* number of active references to this fd */ if (--priv->np_refs > 0) { - return 0; + return; } - netmap_use_count--; - if (!na) { - return 1; //XXX is it correct? + nm_os_put_module(); + if (na) { + netmap_do_unregif(priv); } - netmap_do_unregif(priv); - netmap_adapter_put(na); - return 1; + netmap_unget_na(na, priv->np_ifp); + bzero(priv, sizeof(*priv)); /* for safety */ + free(priv, M_DEVBUF); } @@ -995,15 +1025,10 @@ void netmap_dtor(void *data) { struct netmap_priv_d *priv = data; - int last_instance; NMG_LOCK(); - last_instance = netmap_dtor_locked(priv); + netmap_priv_delete(priv); NMG_UNLOCK(); - if (last_instance) { - bzero(priv, sizeof(*priv)); /* for safety */ - free(priv, M_DEVBUF); - } } @@ -1036,14 +1061,19 @@ static void netmap_send_up(struct ifnet *dst, struct mbq *q) { struct mbuf *m; + struct mbuf *head = NULL, *prev = NULL; /* send packets up, outside the lock */ while ((m = mbq_dequeue(q)) != NULL) { if (netmap_verbose & NM_VERB_HOST) D("sending up pkt %p size %d", m, MBUF_LEN(m)); - NM_SEND_UP(dst, m); + prev = nm_os_send_up(dst, m, prev); + if (head == NULL) + head = prev; } - mbq_destroy(q); + if (head) + nm_os_send_up(dst, NULL, head); + mbq_fini(q); } @@ -1081,6 +1111,27 @@ netmap_grab_packets(struct netmap_kring *kring, struct mbq *q, int force) } } +static inline int +_nm_may_forward(struct netmap_kring *kring) +{ + return ((netmap_fwd || kring->ring->flags & NR_FORWARD) && + kring->na->na_flags & NAF_HOST_RINGS && + kring->tx == NR_RX); +} + +static inline int +nm_may_forward_up(struct netmap_kring *kring) +{ + return _nm_may_forward(kring) && + kring->ring_id != kring->na->num_rx_rings; +} + +static inline int +nm_may_forward_down(struct netmap_kring *kring) +{ + return _nm_may_forward(kring) && + kring->ring_id == kring->na->num_rx_rings; +} /* * Send to the NIC rings packets marked NS_FORWARD between @@ -1107,7 +1158,7 @@ netmap_sw_to_nic(struct netmap_adapter *na) for (; rxcur != head && !nm_ring_empty(rdst); rxcur = nm_next(rxcur, src_lim) ) { struct netmap_slot *src, *dst, tmp; - u_int dst_cur = rdst->cur; + u_int dst_head = rdst->head; src = &rxslot[rxcur]; if ((src->flags & NS_FORWARD) == 0 && !netmap_fwd) @@ -1115,7 +1166,7 @@ netmap_sw_to_nic(struct netmap_adapter *na) sent++; - dst = &rdst->slot[dst_cur]; + dst = &rdst->slot[dst_head]; tmp = *src; @@ -1126,7 +1177,7 @@ netmap_sw_to_nic(struct netmap_adapter *na) dst->len = tmp.len; dst->flags = NS_BUF_CHANGED; - rdst->cur = nm_next(dst_cur, dst_lim); + rdst->head = rdst->cur = nm_next(dst_head, dst_lim); } /* if (sent) XXX txsync ? */ } @@ -1140,10 +1191,10 @@ netmap_sw_to_nic(struct netmap_adapter *na) * can be among multiple user threads erroneously calling * this routine concurrently. */ -static void -netmap_txsync_to_host(struct netmap_adapter *na) +static int +netmap_txsync_to_host(struct netmap_kring *kring, int flags) { - struct netmap_kring *kring = &na->tx_rings[na->num_tx_rings]; + struct netmap_adapter *na = kring->na; u_int const lim = kring->nkr_num_slots - 1; u_int const head = kring->rhead; struct mbq q; @@ -1162,6 +1213,7 @@ netmap_txsync_to_host(struct netmap_adapter *na) kring->nr_hwtail -= lim + 1; netmap_send_up(na->ifp, &q); + return 0; } @@ -1171,17 +1223,15 @@ netmap_txsync_to_host(struct netmap_adapter *na) * We protect access to the kring using kring->rx_queue.lock * * This routine also does the selrecord if called from the poll handler - * (we know because td != NULL). + * (we know because sr != NULL). * - * NOTE: on linux, selrecord() is defined as a macro and uses pwait - * as an additional hidden argument. * returns the number of packets delivered to tx queues in * transparent mode, or a negative value if error */ static int -netmap_rxsync_from_host(struct netmap_adapter *na, struct thread *td, void *pwait) +netmap_rxsync_from_host(struct netmap_kring *kring, int flags) { - struct netmap_kring *kring = &na->rx_rings[na->num_rx_rings]; + struct netmap_adapter *na = kring->na; struct netmap_ring *ring = kring->ring; u_int nm_i, n; u_int const lim = kring->nkr_num_slots - 1; @@ -1189,9 +1239,6 @@ netmap_rxsync_from_host(struct netmap_adapter *na, struct thread *td, void *pwai int ret = 0; struct mbq *q = &kring->rx_queue, fq; - (void)pwait; /* disable unused warnings */ - (void)td; - mbq_init(&fq); /* fq holds packets to be freed */ mbq_lock(q); @@ -1226,19 +1273,20 @@ netmap_rxsync_from_host(struct netmap_adapter *na, struct thread *td, void *pwai */ nm_i = kring->nr_hwcur; if (nm_i != head) { /* something was released */ - if (netmap_fwd || kring->ring->flags & NR_FORWARD) + if (nm_may_forward_down(kring)) { ret = netmap_sw_to_nic(na); + if (ret > 0) { + kring->nr_kflags |= NR_FORWARD; + ret = 0; + } + } kring->nr_hwcur = head; } - /* access copies of cur,tail in the kring */ - if (kring->rcur == kring->rtail && td) /* no bufs available */ - OS_selrecord(td, &kring->si); - mbq_unlock(q); mbq_purge(&fq); - mbq_destroy(&fq); + mbq_fini(&fq); return ret; } @@ -1267,17 +1315,14 @@ netmap_rxsync_from_host(struct netmap_adapter *na, struct thread *td, void *pwai * 0 NETMAP_ADMODE_GENERIC GENERIC GENERIC * */ - +static void netmap_hw_dtor(struct netmap_adapter *); /* needed by NM_IS_NATIVE() */ int netmap_get_hw_na(struct ifnet *ifp, struct netmap_adapter **na) { /* generic support */ int i = netmap_admode; /* Take a snapshot. */ struct netmap_adapter *prev_na; -#ifdef WITH_GENERIC - struct netmap_generic_adapter *gna; int error = 0; -#endif *na = NULL; /* default */ @@ -1285,7 +1330,7 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_adapter **na) if (i < NETMAP_ADMODE_BEST || i >= NETMAP_ADMODE_LAST) i = netmap_admode = NETMAP_ADMODE_BEST; - if (NETMAP_CAPABLE(ifp)) { + if (NM_NA_VALID(ifp)) { prev_na = NA(ifp); /* If an adapter already exists, return it if * there are active file descriptors or if @@ -1310,10 +1355,9 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_adapter **na) /* If there isn't native support and netmap is not allowed * to use generic adapters, we cannot satisfy the request. */ - if (!NETMAP_CAPABLE(ifp) && i == NETMAP_ADMODE_NATIVE) + if (!NM_IS_NATIVE(ifp) && i == NETMAP_ADMODE_NATIVE) return EOPNOTSUPP; -#ifdef WITH_GENERIC /* Otherwise, create a generic adapter and return it, * saving the previously used netmap adapter, if any. * @@ -1328,25 +1372,12 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_adapter **na) * the branches above. This ensures that we never override * a generic adapter with another generic adapter. */ - prev_na = NA(ifp); error = generic_netmap_attach(ifp); if (error) return error; *na = NA(ifp); - gna = (struct netmap_generic_adapter*)NA(ifp); - gna->prev = prev_na; /* save old na */ - if (prev_na != NULL) { - ifunit_ref(ifp->if_xname); - // XXX add a refcount ? - netmap_adapter_get(prev_na); - } - ND("Created generic NA %p (prev %p)", gna, gna->prev); - return 0; -#else /* !WITH_GENERIC */ - return EOPNOTSUPP; -#endif } @@ -1364,21 +1395,22 @@ netmap_get_hw_na(struct ifnet *ifp, struct netmap_adapter **na) * could not be allocated. * If successful, hold a reference to the netmap adapter. * - * No reference is kept on the real interface, which may then - * disappear at any time. + * If the interface specified by nmr is a system one, also keep + * a reference to it and return a valid *ifp. */ int -netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, int create) +netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, + struct ifnet **ifp, int create) { - struct ifnet *ifp = NULL; int error = 0; struct netmap_adapter *ret = NULL; *na = NULL; /* default return value */ + *ifp = NULL; NMG_LOCK_ASSERT(); - /* we cascade through all possible types of netmap adapter. + /* We cascade through all possible types of netmap adapter. * All netmap_get_*_na() functions return an error and an na, * with the following combinations: * @@ -1389,6 +1421,11 @@ netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, int create) * !0 !NULL impossible */ + /* try to see if this is a ptnetmap port */ + error = netmap_get_pt_host_na(nmr, na, create); + if (error || *na != NULL) + return error; + /* try to see if this is a monitor port */ error = netmap_get_monitor_na(nmr, na, create); if (error || *na != NULL) @@ -1413,12 +1450,12 @@ netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, int create) * This may still be a tap, a veth/epair, or even a * persistent VALE port. */ - ifp = ifunit_ref(nmr->nr_name); - if (ifp == NULL) { + *ifp = ifunit_ref(nmr->nr_name); + if (*ifp == NULL) { return ENXIO; } - error = netmap_get_hw_na(ifp, &ret); + error = netmap_get_hw_na(*ifp, &ret); if (error) goto out; @@ -1426,15 +1463,42 @@ netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, int create) netmap_adapter_get(ret); out: - if (error && ret != NULL) - netmap_adapter_put(ret); - - if (ifp) - if_rele(ifp); /* allow live unloading of drivers modules */ + if (error) { + if (ret) + netmap_adapter_put(ret); + if (*ifp) { + if_rele(*ifp); + *ifp = NULL; + } + } return error; } +/* undo netmap_get_na() */ +void +netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp) +{ + if (ifp) + if_rele(ifp); + if (na) + netmap_adapter_put(na); +} + + +#define NM_FAIL_ON(t) do { \ + if (unlikely(t)) { \ + RD(5, "%s: fail '" #t "' " \ + "h %d c %d t %d " \ + "rh %d rc %d rt %d " \ + "hc %d ht %d", \ + kring->name, \ + head, cur, ring->tail, \ + kring->rhead, kring->rcur, kring->rtail, \ + kring->nr_hwcur, kring->nr_hwtail); \ + return kring->nkr_num_slots; \ + } \ +} while (0) /* * validate parameters on entry for *_txsync() @@ -1449,11 +1513,9 @@ netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, int create) * * hwcur, rhead, rtail and hwtail are reliable */ -static u_int -nm_txsync_prologue(struct netmap_kring *kring) +u_int +nm_txsync_prologue(struct netmap_kring *kring, struct netmap_ring *ring) { -#define NM_ASSERT(t) if (t) { D("fail " #t); goto error; } - struct netmap_ring *ring = kring->ring; u_int head = ring->head; /* read only once */ u_int cur = ring->cur; /* read only once */ u_int n = kring->nkr_num_slots; @@ -1463,54 +1525,44 @@ nm_txsync_prologue(struct netmap_kring *kring) kring->nr_hwcur, kring->nr_hwtail, ring->head, ring->cur, ring->tail); #if 1 /* kernel sanity checks; but we can trust the kring. */ - if (kring->nr_hwcur >= n || kring->rhead >= n || - kring->rtail >= n || kring->nr_hwtail >= n) - goto error; + NM_FAIL_ON(kring->nr_hwcur >= n || kring->rhead >= n || + kring->rtail >= n || kring->nr_hwtail >= n); #endif /* kernel sanity checks */ /* - * user sanity checks. We only use 'cur', - * A, B, ... are possible positions for cur: + * user sanity checks. We only use head, + * A, B, ... are possible positions for head: * - * 0 A cur B tail C n-1 - * 0 D tail E cur F n-1 + * 0 A rhead B rtail C n-1 + * 0 D rtail E rhead F n-1 * * B, F, D are valid. A, C, E are wrong */ if (kring->rtail >= kring->rhead) { /* want rhead <= head <= rtail */ - NM_ASSERT(head < kring->rhead || head > kring->rtail); + NM_FAIL_ON(head < kring->rhead || head > kring->rtail); /* and also head <= cur <= rtail */ - NM_ASSERT(cur < head || cur > kring->rtail); + NM_FAIL_ON(cur < head || cur > kring->rtail); } else { /* here rtail < rhead */ /* we need head outside rtail .. rhead */ - NM_ASSERT(head > kring->rtail && head < kring->rhead); + NM_FAIL_ON(head > kring->rtail && head < kring->rhead); /* two cases now: head <= rtail or head >= rhead */ if (head <= kring->rtail) { /* want head <= cur <= rtail */ - NM_ASSERT(cur < head || cur > kring->rtail); + NM_FAIL_ON(cur < head || cur > kring->rtail); } else { /* head >= rhead */ /* cur must be outside rtail..head */ - NM_ASSERT(cur > kring->rtail && cur < head); + NM_FAIL_ON(cur > kring->rtail && cur < head); } } if (ring->tail != kring->rtail) { - RD(5, "tail overwritten was %d need %d", + RD(5, "%s tail overwritten was %d need %d", kring->name, ring->tail, kring->rtail); ring->tail = kring->rtail; } kring->rhead = head; kring->rcur = cur; return head; - -error: - RD(5, "%s kring error: head %d cur %d tail %d rhead %d rcur %d rtail %d hwcur %d hwtail %d", - kring->name, - head, cur, ring->tail, - kring->rhead, kring->rcur, kring->rtail, - kring->nr_hwcur, kring->nr_hwtail); - return n; -#undef NM_ASSERT } @@ -1525,10 +1577,9 @@ nm_txsync_prologue(struct netmap_kring *kring) * hwcur and hwtail are reliable. * */ -static u_int -nm_rxsync_prologue(struct netmap_kring *kring) +u_int +nm_rxsync_prologue(struct netmap_kring *kring, struct netmap_ring *ring) { - struct netmap_ring *ring = kring->ring; uint32_t const n = kring->nkr_num_slots; uint32_t head, cur; @@ -1546,30 +1597,24 @@ nm_rxsync_prologue(struct netmap_kring *kring) cur = kring->rcur = ring->cur; /* read only once */ head = kring->rhead = ring->head; /* read only once */ #if 1 /* kernel sanity checks */ - if (kring->nr_hwcur >= n || kring->nr_hwtail >= n) - goto error; + NM_FAIL_ON(kring->nr_hwcur >= n || kring->nr_hwtail >= n); #endif /* kernel sanity checks */ /* user sanity checks */ if (kring->nr_hwtail >= kring->nr_hwcur) { /* want hwcur <= rhead <= hwtail */ - if (head < kring->nr_hwcur || head > kring->nr_hwtail) - goto error; + NM_FAIL_ON(head < kring->nr_hwcur || head > kring->nr_hwtail); /* and also rhead <= rcur <= hwtail */ - if (cur < head || cur > kring->nr_hwtail) - goto error; + NM_FAIL_ON(cur < head || cur > kring->nr_hwtail); } else { /* we need rhead outside hwtail..hwcur */ - if (head < kring->nr_hwcur && head > kring->nr_hwtail) - goto error; + NM_FAIL_ON(head < kring->nr_hwcur && head > kring->nr_hwtail); /* two cases now: head <= hwtail or head >= hwcur */ if (head <= kring->nr_hwtail) { /* want head <= cur <= hwtail */ - if (cur < head || cur > kring->nr_hwtail) - goto error; + NM_FAIL_ON(cur < head || cur > kring->nr_hwtail); } else { /* cur must be outside hwtail..head */ - if (cur < head && cur > kring->nr_hwtail) - goto error; + NM_FAIL_ON(cur < head && cur > kring->nr_hwtail); } } if (ring->tail != kring->rtail) { @@ -1579,13 +1624,6 @@ nm_rxsync_prologue(struct netmap_kring *kring) ring->tail = kring->rtail; } return head; - -error: - RD(5, "kring error: hwcur %d rcur %d hwtail %d head %d cur %d tail %d", - kring->nr_hwcur, - kring->rcur, kring->nr_hwtail, - kring->rhead, kring->rcur, ring->tail); - return n; } @@ -1659,6 +1697,7 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags struct netmap_adapter *na = priv->np_na; u_int j, i = ringid & NETMAP_RING_MASK; u_int reg = flags & NR_REG_MASK; + int excluded_direction[] = { NR_TX_RINGS_ONLY, NR_RX_RINGS_ONLY }; enum txrx t; if (reg == NR_REG_DEFAULT) { @@ -1672,48 +1711,58 @@ netmap_interp_ringid(struct netmap_priv_d *priv, uint16_t ringid, uint32_t flags } D("deprecated API, old ringid 0x%x -> ringid %x reg %d", ringid, i, reg); } - switch (reg) { - case NR_REG_ALL_NIC: - case NR_REG_PIPE_MASTER: - case NR_REG_PIPE_SLAVE: - for_rx_tx(t) { + + if ((flags & NR_PTNETMAP_HOST) && (reg != NR_REG_ALL_NIC || + flags & (NR_RX_RINGS_ONLY|NR_TX_RINGS_ONLY))) { + D("Error: only NR_REG_ALL_NIC supported with netmap passthrough"); + return EINVAL; + } + + for_rx_tx(t) { + if (flags & excluded_direction[t]) { + priv->np_qfirst[t] = priv->np_qlast[t] = 0; + continue; + } + switch (reg) { + case NR_REG_ALL_NIC: + case NR_REG_PIPE_MASTER: + case NR_REG_PIPE_SLAVE: priv->np_qfirst[t] = 0; priv->np_qlast[t] = nma_get_nrings(na, t); - } - ND("%s %d %d", "ALL/PIPE", - priv->np_qfirst[NR_RX], priv->np_qlast[NR_RX]); - break; - case NR_REG_SW: - case NR_REG_NIC_SW: - if (!(na->na_flags & NAF_HOST_RINGS)) { - D("host rings not supported"); - return EINVAL; - } - for_rx_tx(t) { + ND("ALL/PIPE: %s %d %d", nm_txrx2str(t), + priv->np_qfirst[t], priv->np_qlast[t]); + break; + case NR_REG_SW: + case NR_REG_NIC_SW: + if (!(na->na_flags & NAF_HOST_RINGS)) { + D("host rings not supported"); + return EINVAL; + } priv->np_qfirst[t] = (reg == NR_REG_SW ? nma_get_nrings(na, t) : 0); priv->np_qlast[t] = nma_get_nrings(na, t) + 1; - } - ND("%s %d %d", reg == NR_REG_SW ? "SW" : "NIC+SW", - priv->np_qfirst[NR_RX], priv->np_qlast[NR_RX]); - break; - case NR_REG_ONE_NIC: - if (i >= na->num_tx_rings && i >= na->num_rx_rings) { - D("invalid ring id %d", i); - return EINVAL; - } - for_rx_tx(t) { + ND("%s: %s %d %d", reg == NR_REG_SW ? "SW" : "NIC+SW", + nm_txrx2str(t), + priv->np_qfirst[t], priv->np_qlast[t]); + break; + case NR_REG_ONE_NIC: + if (i >= na->num_tx_rings && i >= na->num_rx_rings) { + D("invalid ring id %d", i); + return EINVAL; + } /* if not enough rings, use the first one */ j = i; if (j >= nma_get_nrings(na, t)) j = 0; priv->np_qfirst[t] = j; priv->np_qlast[t] = j + 1; + ND("ONE_NIC: %s %d %d", nm_txrx2str(t), + priv->np_qfirst[t], priv->np_qlast[t]); + break; + default: + D("invalid regif type %d", reg); + return EINVAL; } - break; - default: - D("invalid regif type %d", reg); - return EINVAL; } priv->np_flags = (flags & ~NR_REG_MASK) | reg; @@ -1776,11 +1825,12 @@ netmap_unset_ringid(struct netmap_priv_d *priv) } -/* check that the rings we want to bind are not exclusively owned by a previous - * bind. If exclusive ownership has been requested, we also mark the rings. +/* Set the nr_pending_mode for the requested rings. + * If requested, also try to get exclusive access to the rings, provided + * the rings we want to bind are not exclusively owned by a previous bind. */ static int -netmap_get_exclusive(struct netmap_priv_d *priv) +netmap_krings_get(struct netmap_priv_d *priv) { struct netmap_adapter *na = priv->np_na; u_int i; @@ -1811,16 +1861,16 @@ netmap_get_exclusive(struct netmap_priv_d *priv) } } - /* second round: increment usage cound and possibly - * mark as exclusive + /* second round: increment usage count (possibly marking them + * as exclusive) and set the nr_pending_mode */ - for_rx_tx(t) { for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) { kring = &NMR(na, t)[i]; kring->users++; if (excl) kring->nr_kflags |= NKR_EXCLUSIVE; + kring->nr_pending_mode = NKR_NETMAP_ON; } } @@ -1828,9 +1878,11 @@ netmap_get_exclusive(struct netmap_priv_d *priv) } -/* undo netmap_get_ownership() */ +/* Undo netmap_krings_get(). This is done by clearing the exclusive mode + * if was asked on regif, and unset the nr_pending_mode if we are the + * last users of the involved rings. */ static void -netmap_rel_exclusive(struct netmap_priv_d *priv) +netmap_krings_put(struct netmap_priv_d *priv) { struct netmap_adapter *na = priv->np_na; u_int i; @@ -1852,6 +1904,8 @@ netmap_rel_exclusive(struct netmap_priv_d *priv) if (excl) kring->nr_kflags &= ~NKR_EXCLUSIVE; kring->users--; + if (kring->users == 0) + kring->nr_pending_mode = NKR_NETMAP_OFF; } } } @@ -1899,9 +1953,8 @@ netmap_rel_exclusive(struct netmap_priv_d *priv) * (put the adapter in netmap mode) * * This may be one of the following: - * (XXX these should be either all *_register or all *_reg 2014-03-15) * - * * netmap_hw_register (hw ports) + * * netmap_hw_reg (hw ports) * checks that the ifp is still there, then calls * the hardware specific callback; * @@ -1919,7 +1972,7 @@ netmap_rel_exclusive(struct netmap_priv_d *priv) * intercept the sync callbacks of the monitored * rings * - * * netmap_bwrap_register (bwraps) + * * netmap_bwrap_reg (bwraps) * cross-link the bwrap and hwna rings, * forward the request to the hwna, override * the hwna notify callback (to get the frames @@ -1948,7 +2001,7 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na, if (na->active_fds == 0) { /* * If this is the first registration of the adapter, - * also create the netmap rings and their in-kernel view, + * create the in-kernel view of the netmap rings, * the netmap krings. */ @@ -1960,39 +2013,48 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na, if (error) goto err_drop_mem; - /* create all missing netmap rings */ - error = netmap_mem_rings_create(na); - if (error) - goto err_del_krings; } - /* now the kring must exist and we can check whether some - * previous bind has exclusive ownership on them + /* now the krings must exist and we can check whether some + * previous bind has exclusive ownership on them, and set + * nr_pending_mode */ - error = netmap_get_exclusive(priv); + error = netmap_krings_get(priv); if (error) - goto err_del_rings; + goto err_del_krings; + + /* create all needed missing netmap rings */ + error = netmap_mem_rings_create(na); + if (error) + goto err_rel_excl; /* in all cases, create a new netmap if */ nifp = netmap_mem_if_new(na); if (nifp == NULL) { error = ENOMEM; - goto err_rel_excl; + goto err_del_rings; } - na->active_fds++; - if (!nm_netmap_on(na)) { - /* Netmap not active, set the card in netmap mode - * and make it use the shared buffers. - */ + if (na->active_fds == 0) { /* cache the allocator info in the na */ - netmap_mem_get_lut(na->nm_mem, &na->na_lut); - ND("%p->na_lut == %p", na, na->na_lut.lut); - error = na->nm_register(na, 1); /* mode on */ - if (error) + error = netmap_mem_get_lut(na->nm_mem, &na->na_lut); + if (error) goto err_del_if; + ND("lut %p bufs %u size %u", na->na_lut.lut, na->na_lut.objtotal, + na->na_lut.objsize); } + if (nm_kring_pending(priv)) { + /* Some kring is switching mode, tell the adapter to + * react on this. */ + error = na->nm_register(na, 1); + if (error) + goto err_put_lut; + } + + /* Commit the reference. */ + na->active_fds++; + /* * advertise that the interface is ready by setting np_nifp. * The barrier is needed because readers (poll, *SYNC and mmap) @@ -2003,15 +2065,15 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na, return 0; +err_put_lut: + if (na->active_fds == 0) + memset(&na->na_lut, 0, sizeof(na->na_lut)); err_del_if: - memset(&na->na_lut, 0, sizeof(na->na_lut)); - na->active_fds--; netmap_mem_if_delete(na, nifp); err_rel_excl: - netmap_rel_exclusive(priv); + netmap_krings_put(priv); err_del_rings: - if (na->active_fds == 0) - netmap_mem_rings_delete(na); + netmap_mem_rings_delete(na); err_del_krings: if (na->active_fds == 0) na->nm_krings_delete(na); @@ -2024,41 +2086,23 @@ netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na, /* - * update kring and ring at the end of txsync. + * update kring and ring at the end of rxsync/txsync. */ static inline void -nm_txsync_finalize(struct netmap_kring *kring) +nm_sync_finalize(struct netmap_kring *kring) { - /* update ring tail to what the kernel knows */ + /* + * Update ring tail to what the kernel knows + * After txsync: head/rhead/hwcur might be behind cur/rcur + * if no carrier. + */ kring->ring->tail = kring->rtail = kring->nr_hwtail; - /* note, head/rhead/hwcur might be behind cur/rcur - * if no carrier - */ ND(5, "%s now hwcur %d hwtail %d head %d cur %d tail %d", kring->name, kring->nr_hwcur, kring->nr_hwtail, kring->rhead, kring->rcur, kring->rtail); } - -/* - * update kring and ring at the end of rxsync - */ -static inline void -nm_rxsync_finalize(struct netmap_kring *kring) -{ - /* tell userspace that there might be new packets */ - //struct netmap_ring *ring = kring->ring; - ND("head %d cur %d tail %d -> %d", ring->head, ring->cur, ring->tail, - kring->nr_hwtail); - kring->ring->tail = kring->rtail = kring->nr_hwtail; - /* make a copy of the state for next round */ - kring->rhead = kring->ring->head; - kring->rcur = kring->ring->cur; -} - - - /* * ioctl(2) support for the "netmap" device. * @@ -2072,21 +2116,17 @@ nm_rxsync_finalize(struct netmap_kring *kring) * Return 0 on success, errno otherwise. */ int -netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, - int fflag, struct thread *td) +netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *td) { - struct netmap_priv_d *priv = NULL; struct nmreq *nmr = (struct nmreq *) data; struct netmap_adapter *na = NULL; - int error; + struct ifnet *ifp = NULL; + int error = 0; u_int i, qfirst, qlast; struct netmap_if *nifp; struct netmap_kring *krings; enum txrx t; - (void)dev; /* UNUSED */ - (void)fflag; /* UNUSED */ - if (cmd == NIOCGINFO || cmd == NIOCREGIF) { /* truncate name */ nmr->nr_name[sizeof(nmr->nr_name) - 1] = '\0'; @@ -2101,15 +2141,6 @@ netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, return EINVAL; } } - CURVNET_SET(TD_TO_VNET(td)); - - error = devfs_get_cdevpriv((void **)&priv); - if (error) { - CURVNET_RESTORE(); - /* XXX ENOENT should be impossible, since the priv - * is now created in the open */ - return (error == ENOENT ? ENXIO : error); - } switch (cmd) { case NIOCGINFO: /* return capabilities etc */ @@ -2125,10 +2156,14 @@ netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, u_int memflags; if (nmr->nr_name[0] != '\0') { + /* get a refcount */ - error = netmap_get_na(nmr, &na, 1 /* create */); - if (error) + error = netmap_get_na(nmr, &na, &ifp, 1 /* create */); + if (error) { + na = NULL; + ifp = NULL; break; + } nmd = na->nm_mem; /* get memory allocator */ } @@ -2145,8 +2180,8 @@ netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, nmr->nr_tx_rings = na->num_tx_rings; nmr->nr_rx_slots = na->num_rx_desc; nmr->nr_tx_slots = na->num_tx_desc; - netmap_adapter_put(na); } while (0); + netmap_unget_na(na, ifp); NMG_UNLOCK(); break; @@ -2156,9 +2191,25 @@ netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, if (i == NETMAP_BDG_ATTACH || i == NETMAP_BDG_DETACH || i == NETMAP_BDG_VNET_HDR || i == NETMAP_BDG_NEWIF - || i == NETMAP_BDG_DELIF) { + || i == NETMAP_BDG_DELIF + || i == NETMAP_BDG_POLLING_ON + || i == NETMAP_BDG_POLLING_OFF) { error = netmap_bdg_ctl(nmr, NULL); break; + } else if (i == NETMAP_PT_HOST_CREATE || i == NETMAP_PT_HOST_DELETE) { + error = ptnetmap_ctl(nmr, priv->np_na); + break; + } else if (i == NETMAP_VNET_HDR_GET) { + struct ifnet *ifp; + + NMG_LOCK(); + error = netmap_get_na(nmr, &na, &ifp, 0); + if (na && !error) { + nmr->nr_arg1 = na->virt_hdr_len; + } + netmap_unget_na(na, ifp); + NMG_UNLOCK(); + break; } else if (i != 0) { D("nr_cmd must be 0 not %d", i); error = EINVAL; @@ -2169,23 +2220,32 @@ netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, NMG_LOCK(); do { u_int memflags; + struct ifnet *ifp; if (priv->np_nifp != NULL) { /* thread already registered */ error = EBUSY; break; } /* find the interface and a reference */ - error = netmap_get_na(nmr, &na, 1 /* create */); /* keep reference */ + error = netmap_get_na(nmr, &na, &ifp, + 1 /* create */); /* keep reference */ if (error) break; if (NETMAP_OWNED_BY_KERN(na)) { - netmap_adapter_put(na); + netmap_unget_na(na, ifp); error = EBUSY; break; } + + if (na->virt_hdr_len && !(nmr->nr_flags & NR_ACCEPT_VNET_HDR)) { + netmap_unget_na(na, ifp); + error = EIO; + break; + } + error = netmap_do_regif(priv, na, nmr->nr_ringid, nmr->nr_flags); if (error) { /* reg. failed, release priv and ref */ - netmap_adapter_put(na); + netmap_unget_na(na, ifp); break; } nifp = priv->np_nifp; @@ -2200,7 +2260,7 @@ netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, &nmr->nr_arg2); if (error) { netmap_do_unregif(priv); - netmap_adapter_put(na); + netmap_unget_na(na, ifp); break; } if (memflags & NETMAP_MEM_PRIVATE) { @@ -2212,12 +2272,17 @@ netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, } if (nmr->nr_arg3) { - D("requested %d extra buffers", nmr->nr_arg3); + if (netmap_verbose) + D("requested %d extra buffers", nmr->nr_arg3); nmr->nr_arg3 = netmap_extra_alloc(na, &nifp->ni_bufs_head, nmr->nr_arg3); - D("got %d extra buffers", nmr->nr_arg3); + if (netmap_verbose) + D("got %d extra buffers", nmr->nr_arg3); } nmr->nr_offset = netmap_mem_if_offset(na->nm_mem, nifp); + + /* store ifp reference so that priv destructor may release it */ + priv->np_ifp = ifp; } while (0); NMG_UNLOCK(); break; @@ -2240,11 +2305,6 @@ netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, break; } - if (!nm_netmap_on(na)) { - error = ENXIO; - break; - } - t = (cmd == NIOCTXSYNC ? NR_TX : NR_RX); krings = NMR(na, t); qfirst = priv->np_qfirst[t]; @@ -2252,31 +2312,34 @@ netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, for (i = qfirst; i < qlast; i++) { struct netmap_kring *kring = krings + i; - if (nm_kr_tryget(kring)) { - error = EBUSY; - goto out; + struct netmap_ring *ring = kring->ring; + + if (unlikely(nm_kr_tryget(kring, 1, &error))) { + error = (error ? EIO : 0); + continue; } + if (cmd == NIOCTXSYNC) { if (netmap_verbose & NM_VERB_TXSYNC) D("pre txsync ring %d cur %d hwcur %d", - i, kring->ring->cur, + i, ring->cur, kring->nr_hwcur); - if (nm_txsync_prologue(kring) >= kring->nkr_num_slots) { + if (nm_txsync_prologue(kring, ring) >= kring->nkr_num_slots) { netmap_ring_reinit(kring); } else if (kring->nm_sync(kring, NAF_FORCE_RECLAIM) == 0) { - nm_txsync_finalize(kring); + nm_sync_finalize(kring); } if (netmap_verbose & NM_VERB_TXSYNC) D("post txsync ring %d cur %d hwcur %d", - i, kring->ring->cur, + i, ring->cur, kring->nr_hwcur); } else { - if (nm_rxsync_prologue(kring) >= kring->nkr_num_slots) { + if (nm_rxsync_prologue(kring, ring) >= kring->nkr_num_slots) { netmap_ring_reinit(kring); } else if (kring->nm_sync(kring, NAF_FORCE_READ) == 0) { - nm_rxsync_finalize(kring); + nm_sync_finalize(kring); } - microtime(&na->rx_rings[i].ring->ts); + microtime(&ring->ts); } nm_kr_put(kring); } @@ -2323,9 +2386,7 @@ netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, error = EOPNOTSUPP; #endif /* linux */ } -out: - CURVNET_RESTORE(); return (error); } @@ -2345,17 +2406,15 @@ netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, * hidden argument. */ int -netmap_poll(struct cdev *dev, int events, struct thread *td) +netmap_poll(struct netmap_priv_d *priv, int events, NM_SELRECORD_T *sr) { - struct netmap_priv_d *priv = NULL; struct netmap_adapter *na; struct netmap_kring *kring; + struct netmap_ring *ring; u_int i, check_all_tx, check_all_rx, want[NR_TXRX], revents = 0; #define want_tx want[NR_TX] #define want_rx want[NR_RX] struct mbq q; /* packets from hw queues to host stack */ - void *pwait = dev; /* linux compatibility */ - int is_kevent = 0; enum txrx t; /* @@ -2365,23 +2424,13 @@ netmap_poll(struct cdev *dev, int events, struct thread *td) */ int retry_tx = 1, retry_rx = 1; - (void)pwait; - mbq_init(&q); - - /* - * XXX kevent has curthread->tp_fop == NULL, - * so devfs_get_cdevpriv() fails. We circumvent this by passing - * priv as the first argument, which is also useful to avoid - * the selrecord() which are not necessary in that case. + /* transparent mode: send_down is 1 if we have found some + * packets to forward during the rx scan and we have not + * sent them down to the nic yet */ - if (devfs_get_cdevpriv((void **)&priv) != 0) { - is_kevent = 1; - if (netmap_verbose) - D("called from kevent"); - priv = (struct netmap_priv_d *)dev; - } - if (priv == NULL) - return POLLERR; + int send_down = 0; + + mbq_init(&q); if (priv->np_nifp == NULL) { D("No if registered"); @@ -2399,7 +2448,6 @@ netmap_poll(struct cdev *dev, int events, struct thread *td) want_tx = events & (POLLOUT | POLLWRNORM); want_rx = events & (POLLIN | POLLRDNORM); - /* * check_all_{tx|rx} are set if the card has more than one queue AND * the file descriptor is bound to all of them. If so, we sleep on @@ -2421,6 +2469,32 @@ netmap_poll(struct cdev *dev, int events, struct thread *td) * slots available. If this fails, then lock and call the sync * routines. */ +#if 1 /* new code- call rx if any of the ring needs to release or read buffers */ + if (want_tx) { + t = NR_TX; + for (i = priv->np_qfirst[t]; want[t] && i < priv->np_qlast[t]; i++) { + kring = &NMR(na, t)[i]; + /* XXX compare ring->cur and kring->tail */ + if (!nm_ring_empty(kring->ring)) { + revents |= want[t]; + want[t] = 0; /* also breaks the loop */ + } + } + } + if (want_rx) { + want_rx = 0; /* look for a reason to run the handlers */ + t = NR_RX; + for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) { + kring = &NMR(na, t)[i]; + if (kring->ring->cur == kring->ring->tail /* try fetch new buffers */ + || kring->rhead != kring->ring->head /* release buffers */) { + want_rx = 1; + } + } + if (!want_rx) + revents |= events & (POLLIN | POLLRDNORM); /* we have data */ + } +#else /* old code */ for_rx_tx(t) { for (i = priv->np_qfirst[t]; want[t] && i < priv->np_qlast[t]; i++) { kring = &NMR(na, t)[i]; @@ -2431,6 +2505,7 @@ netmap_poll(struct cdev *dev, int events, struct thread *td) } } } +#endif /* old code */ /* * If we want to push packets out (priv->np_txpoll) or @@ -2447,32 +2522,26 @@ netmap_poll(struct cdev *dev, int events, struct thread *td) * used to skip rings with no pending transmissions. */ flush_tx: - for (i = priv->np_qfirst[NR_TX]; i < priv->np_qlast[NR_RX]; i++) { + for (i = priv->np_qfirst[NR_TX]; i < priv->np_qlast[NR_TX]; i++) { int found = 0; kring = &na->tx_rings[i]; - if (!want_tx && kring->ring->cur == kring->nr_hwcur) + ring = kring->ring; + + if (!send_down && !want_tx && ring->cur == kring->nr_hwcur) continue; - /* only one thread does txsync */ - if (nm_kr_tryget(kring)) { - /* either busy or stopped - * XXX if the ring is stopped, sleeping would - * be better. In current code, however, we only - * stop the rings for brief intervals (2014-03-14) - */ - if (netmap_verbose) - RD(2, "%p lost race on txring %d, ok", - priv, i); + + if (nm_kr_tryget(kring, 1, &revents)) continue; - } - if (nm_txsync_prologue(kring) >= kring->nkr_num_slots) { + + if (nm_txsync_prologue(kring, ring) >= kring->nkr_num_slots) { netmap_ring_reinit(kring); revents |= POLLERR; } else { if (kring->nm_sync(kring, 0)) revents |= POLLERR; else - nm_txsync_finalize(kring); + nm_sync_finalize(kring); } /* @@ -2489,8 +2558,10 @@ netmap_poll(struct cdev *dev, int events, struct thread *td) kring->nm_notify(kring, 0); } } - if (want_tx && retry_tx && !is_kevent) { - OS_selrecord(td, check_all_tx ? + /* if there were any packet to forward we must have handled them by now */ + send_down = 0; + if (want_tx && retry_tx && sr) { + nm_os_selrecord(sr, check_all_tx ? &na->si[NR_TX] : &na->tx_rings[priv->np_qfirst[NR_TX]].si); retry_tx = 0; goto flush_tx; @@ -2502,22 +2573,18 @@ netmap_poll(struct cdev *dev, int events, struct thread *td) * Do it on all rings because otherwise we starve. */ if (want_rx) { - int send_down = 0; /* transparent mode */ /* two rounds here for race avoidance */ do_retry_rx: for (i = priv->np_qfirst[NR_RX]; i < priv->np_qlast[NR_RX]; i++) { int found = 0; kring = &na->rx_rings[i]; + ring = kring->ring; - if (nm_kr_tryget(kring)) { - if (netmap_verbose) - RD(2, "%p lost race on rxring %d, ok", - priv, i); + if (unlikely(nm_kr_tryget(kring, 1, &revents))) continue; - } - if (nm_rxsync_prologue(kring) >= kring->nkr_num_slots) { + if (nm_rxsync_prologue(kring, ring) >= kring->nkr_num_slots) { netmap_ring_reinit(kring); revents |= POLLERR; } @@ -2526,22 +2593,22 @@ netmap_poll(struct cdev *dev, int events, struct thread *td) /* * transparent mode support: collect packets * from the rxring(s). - * XXX NR_FORWARD should only be read on - * physical or NIC ports */ - if (netmap_fwd ||kring->ring->flags & NR_FORWARD) { + if (nm_may_forward_up(kring)) { ND(10, "forwarding some buffers up %d to %d", - kring->nr_hwcur, kring->ring->cur); + kring->nr_hwcur, ring->cur); netmap_grab_packets(kring, &q, netmap_fwd); } + kring->nr_kflags &= ~NR_FORWARD; if (kring->nm_sync(kring, 0)) revents |= POLLERR; else - nm_rxsync_finalize(kring); + nm_sync_finalize(kring); + send_down |= (kring->nr_kflags & NR_FORWARD); /* host ring only */ if (netmap_no_timestamp == 0 || - kring->ring->flags & NR_TIMESTAMP) { - microtime(&kring->ring->ts); + ring->flags & NR_TIMESTAMP) { + microtime(&ring->ts); } found = kring->rcur != kring->rtail; nm_kr_put(kring); @@ -2552,22 +2619,10 @@ netmap_poll(struct cdev *dev, int events, struct thread *td) } } - /* transparent mode XXX only during first pass ? */ - if (na->na_flags & NAF_HOST_RINGS) { - kring = &na->rx_rings[na->num_rx_rings]; - if (check_all_rx - && (netmap_fwd || kring->ring->flags & NR_FORWARD)) { - /* XXX fix to use kring fields */ - if (nm_ring_empty(kring->ring)) - send_down = netmap_rxsync_from_host(na, td, dev); - if (!nm_ring_empty(kring->ring)) - revents |= want_rx; - } - } - - if (retry_rx && !is_kevent) - OS_selrecord(td, check_all_rx ? + if (retry_rx && sr) { + nm_os_selrecord(sr, check_all_rx ? &na->si[NR_RX] : &na->rx_rings[priv->np_qfirst[NR_RX]].si); + } if (send_down > 0 || retry_rx) { retry_rx = 0; if (send_down) @@ -2582,15 +2637,14 @@ netmap_poll(struct cdev *dev, int events, struct thread *td) * kring->nr_hwcur and ring->head * are passed to the other endpoint. * - * In this mode we also scan the sw rxring, which in - * turn passes packets up. - * - * XXX Transparent mode at the moment requires to bind all + * Transparent mode requires to bind all * rings to a single file descriptor. */ - if (q.head && na->ifp != NULL) + if (q.head && !nm_kr_tryget(&na->tx_rings[na->num_tx_rings], 1, &revents)) { netmap_send_up(na->ifp, &q); + nm_kr_put(&na->tx_rings[na->num_tx_rings]); + } return (revents); #undef want_tx @@ -2600,8 +2654,6 @@ netmap_poll(struct cdev *dev, int events, struct thread *td) /*-------------------- driver support routines -------------------*/ -static int netmap_hw_krings_create(struct netmap_adapter *); - /* default notify callback */ static int netmap_notify(struct netmap_kring *kring, int flags) @@ -2609,51 +2661,51 @@ netmap_notify(struct netmap_kring *kring, int flags) struct netmap_adapter *na = kring->na; enum txrx t = kring->tx; - OS_selwakeup(&kring->si, PI_NET); + nm_os_selwakeup(&kring->si); /* optimization: avoid a wake up on the global * queue if nobody has registered for more * than one ring */ if (na->si_users[t] > 0) - OS_selwakeup(&na->si[t], PI_NET); + nm_os_selwakeup(&na->si[t]); - return 0; + return NM_IRQ_COMPLETED; } +#if 0 +static int +netmap_notify(struct netmap_adapter *na, u_int n_ring, +enum txrx tx, int flags) +{ + if (tx == NR_TX) { + KeSetEvent(notes->TX_EVENT, 0, FALSE); + } + else + { + KeSetEvent(notes->RX_EVENT, 0, FALSE); + } + return 0; +} +#endif /* called by all routines that create netmap_adapters. - * Attach na to the ifp (if any) and provide defaults - * for optional callbacks. Defaults assume that we - * are creating an hardware netmap_adapter. + * provide some defaults and get a reference to the + * memory allocator */ int netmap_attach_common(struct netmap_adapter *na) { - struct ifnet *ifp = na->ifp; - if (na->num_tx_rings == 0 || na->num_rx_rings == 0) { D("%s: invalid rings tx %d rx %d", na->name, na->num_tx_rings, na->num_rx_rings); return EINVAL; } - /* ifp is NULL for virtual adapters (bwrap, non-persistent VALE ports, - * pipes, monitors). For bwrap we actually have a non-null ifp for - * use by the external modules, but that is set after this - * function has been called. - * XXX this is ugly, maybe split this function in two (2014-03-14) - */ - if (ifp != NULL) { - WNA(ifp) = na; - /* the following is only needed for na that use the host port. - * XXX do we have something similar for linux ? - */ #ifdef __FreeBSD__ - na->if_input = ifp->if_input; /* for netmap_send_up */ -#endif /* __FreeBSD__ */ - - NETMAP_SET_CAPABLE(ifp); + if (na->na_flags & NAF_HOST_RINGS && na->ifp) { + na->if_input = na->ifp->if_input; /* for netmap_send_up */ } +#endif /* __FreeBSD__ */ if (na->nm_krings_create == NULL) { /* we assume that we have been called by a driver, * since other port types all provide their own @@ -2677,6 +2729,7 @@ netmap_attach_common(struct netmap_adapter *na) */ na->nm_bdg_attach = netmap_bwrap_attach; #endif + return 0; } @@ -2685,9 +2738,6 @@ netmap_attach_common(struct netmap_adapter *na) void netmap_detach_common(struct netmap_adapter *na) { - if (na->ifp != NULL) - WNA(na->ifp) = NULL; /* XXX do we need this? */ - if (na->tx_rings) { /* XXX should not happen */ D("freeing leftover tx_rings"); na->nm_krings_delete(na); @@ -2699,31 +2749,52 @@ netmap_detach_common(struct netmap_adapter *na) free(na, M_DEVBUF); } -/* Wrapper for the register callback provided hardware drivers. - * na->ifp == NULL means the driver module has been +/* Wrapper for the register callback provided netmap-enabled + * hardware drivers. + * nm_iszombie(na) means that the driver module has been * unloaded, so we cannot call into it. - * Note that module unloading, in our patched linux drivers, - * happens under NMG_LOCK and after having stopped all the - * nic rings (see netmap_detach). This provides sufficient - * protection for the other driver-provied callbacks - * (i.e., nm_config and nm_*xsync), that therefore don't need - * to wrapped. + * nm_os_ifnet_lock() must guarantee mutual exclusion with + * module unloading. */ static int -netmap_hw_register(struct netmap_adapter *na, int onoff) +netmap_hw_reg(struct netmap_adapter *na, int onoff) { struct netmap_hw_adapter *hwna = (struct netmap_hw_adapter*)na; + int error = 0; - if (na->ifp == NULL) - return onoff ? ENXIO : 0; + nm_os_ifnet_lock(); - return hwna->nm_hw_register(na, onoff); + if (nm_iszombie(na)) { + if (onoff) { + error = ENXIO; + } else if (na != NULL) { + na->na_flags &= ~NAF_NETMAP_ON; + } + goto out; + } + + error = hwna->nm_hw_register(na, onoff); + +out: + nm_os_ifnet_unlock(); + + return error; +} + +static void +netmap_hw_dtor(struct netmap_adapter *na) +{ + if (nm_iszombie(na) || na->ifp == NULL) + return; + + WNA(na->ifp) = NULL; } /* - * Initialize a ``netmap_adapter`` object created by driver on attach. + * Allocate a ``netmap_adapter`` object, and initialize it from the + * 'arg' passed by the driver on attach. * We allocate a block of memory with room for a struct netmap_adapter * plus two sets of N+2 struct netmap_kring (where N is the number * of hardware rings): @@ -2732,29 +2803,31 @@ netmap_hw_register(struct netmap_adapter *na, int onoff) * kring N+1 is only used for the selinfo for all queues. // XXX still true ? * Return 0 on success, ENOMEM otherwise. */ -int -netmap_attach(struct netmap_adapter *arg) +static int +_netmap_attach(struct netmap_adapter *arg, size_t size) { struct netmap_hw_adapter *hwna = NULL; - // XXX when is arg == NULL ? - struct ifnet *ifp = arg ? arg->ifp : NULL; + struct ifnet *ifp = NULL; - if (arg == NULL || ifp == NULL) + if (arg == NULL || arg->ifp == NULL) goto fail; - hwna = malloc(sizeof(*hwna), M_DEVBUF, M_NOWAIT | M_ZERO); + ifp = arg->ifp; + hwna = malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO); if (hwna == NULL) goto fail; hwna->up = *arg; hwna->up.na_flags |= NAF_HOST_RINGS | NAF_NATIVE; strncpy(hwna->up.name, ifp->if_xname, sizeof(hwna->up.name)); hwna->nm_hw_register = hwna->up.nm_register; - hwna->up.nm_register = netmap_hw_register; + hwna->up.nm_register = netmap_hw_reg; if (netmap_attach_common(&hwna->up)) { free(hwna, M_DEVBUF); goto fail; } netmap_adapter_get(&hwna->up); + NM_ATTACH_NA(ifp, &hwna->up); + #ifdef linux if (ifp->netdev_ops) { /* prepare a clone of the netdev ops */ @@ -2762,7 +2835,7 @@ netmap_attach(struct netmap_adapter *arg) hwna->nm_ndo.ndo_start_xmit = ifp->netdev_ops; #else hwna->nm_ndo = *ifp->netdev_ops; -#endif +#endif /* NETMAP_LINUX_HAVE_NETDEV_OPS */ } hwna->nm_ndo.ndo_start_xmit = linux_netmap_start_xmit; if (ifp->ethtool_ops) { @@ -2771,11 +2844,14 @@ netmap_attach(struct netmap_adapter *arg) hwna->nm_eto.set_ringparam = linux_netmap_set_ringparam; #ifdef NETMAP_LINUX_HAVE_SET_CHANNELS hwna->nm_eto.set_channels = linux_netmap_set_channels; -#endif +#endif /* NETMAP_LINUX_HAVE_SET_CHANNELS */ if (arg->nm_config == NULL) { hwna->up.nm_config = netmap_linux_config; } #endif /* linux */ + if (arg->nm_dtor == NULL) { + hwna->up.nm_dtor = netmap_hw_dtor; + } if_printf(ifp, "netmap queues/slots: TX %d/%d, RX %d/%d\n", hwna->up.num_tx_rings, hwna->up.num_tx_desc, @@ -2784,12 +2860,57 @@ netmap_attach(struct netmap_adapter *arg) fail: D("fail, arg %p ifp %p na %p", arg, ifp, hwna); - if (ifp) - netmap_detach(ifp); return (hwna ? EINVAL : ENOMEM); } +int +netmap_attach(struct netmap_adapter *arg) +{ + return _netmap_attach(arg, sizeof(struct netmap_hw_adapter)); +} + + +#ifdef WITH_PTNETMAP_GUEST +int +netmap_pt_guest_attach(struct netmap_adapter *arg, + void *csb, + unsigned int nifp_offset, + nm_pt_guest_ptctl_t ptctl) +{ + struct netmap_pt_guest_adapter *ptna; + struct ifnet *ifp = arg ? arg->ifp : NULL; + int error; + + /* get allocator */ + arg->nm_mem = netmap_mem_pt_guest_new(ifp, nifp_offset, ptctl); + if (arg->nm_mem == NULL) + return ENOMEM; + arg->na_flags |= NAF_MEM_OWNER; + error = _netmap_attach(arg, sizeof(struct netmap_pt_guest_adapter)); + if (error) + return error; + + /* get the netmap_pt_guest_adapter */ + ptna = (struct netmap_pt_guest_adapter *) NA(ifp); + ptna->csb = csb; + + /* Initialize a separate pass-through netmap adapter that is going to + * be used by the ptnet driver only, and so never exposed to netmap + * applications. We only need a subset of the available fields. */ + memset(&ptna->dr, 0, sizeof(ptna->dr)); + ptna->dr.up.ifp = ifp; + ptna->dr.up.nm_mem = ptna->hwup.up.nm_mem; + netmap_mem_get(ptna->dr.up.nm_mem); + ptna->dr.up.nm_config = ptna->hwup.up.nm_config; + + ptna->backend_regifs = 0; + + return 0; +} +#endif /* WITH_PTNETMAP_GUEST */ + + void NM_DBG(netmap_adapter_get)(struct netmap_adapter *na) { @@ -2841,28 +2962,29 @@ void netmap_detach(struct ifnet *ifp) { struct netmap_adapter *na = NA(ifp); - int skip; if (!na) return; - skip = 0; NMG_LOCK(); - netmap_disable_all_rings(ifp); - na->ifp = NULL; - na->na_flags &= ~NAF_NETMAP_ON; + netmap_set_all_rings(na, NM_KR_LOCKED); + na->na_flags |= NAF_ZOMBIE; /* * if the netmap adapter is not native, somebody * changed it, so we can not release it here. - * The NULL na->ifp will notify the new owner that + * The NAF_ZOMBIE flag will notify the new owner that * the driver is gone. */ if (na->na_flags & NAF_NATIVE) { - skip = netmap_adapter_put(na); + netmap_adapter_put(na); } - /* give them a chance to notice */ - if (skip == 0) - netmap_enable_all_rings(ifp); + /* give active users a chance to notice that NAF_ZOMBIE has been + * turned on, so that they can stop and return an error to userspace. + * Note that this becomes a NOP if there are no active users and, + * therefore, the put() above has deleted the na, since now NA(ifp) is + * NULL. + */ + netmap_enable_all_rings(ifp); NMG_UNLOCK(); } @@ -2883,9 +3005,10 @@ int netmap_transmit(struct ifnet *ifp, struct mbuf *m) { struct netmap_adapter *na = NA(ifp); - struct netmap_kring *kring; + struct netmap_kring *kring, *tx_kring; u_int len = MBUF_LEN(m); u_int error = ENOBUFS; + unsigned int txr; struct mbq *q; int space; @@ -2900,6 +3023,16 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m) goto done; } + txr = MBUF_TXQ(m); + if (txr >= na->num_tx_rings) { + txr %= na->num_tx_rings; + } + tx_kring = &NMR(na, NR_TX)[txr]; + + if (tx_kring->nr_mode == NKR_NETMAP_OFF) { + return MBUF_TRANSMIT(na, ifp, m); + } + q = &kring->rx_queue; // XXX reconsider long packets if we handle fragments @@ -2909,6 +3042,11 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m) goto done; } + if (nm_os_mbuf_has_offld(m)) { + RD(1, "%s drop mbuf requiring offloadings", na->name); + goto done; + } + /* protect against rxsync_from_host(), netmap_sw_to_nic() * and maybe other instances of netmap_transmit (the latter * not possible on Linux). @@ -2951,6 +3089,8 @@ netmap_transmit(struct ifnet *ifp, struct mbuf *m) * netmap_reset() is called by the driver routines when reinitializing * a ring. The driver is in charge of locking to protect the kring. * If native netmap mode is not set just return NULL. + * If native netmap mode is set, in particular, we have to set nr_mode to + * NKR_NETMAP_ON. */ struct netmap_slot * netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n, @@ -2975,13 +3115,26 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n, if (tx == NR_TX) { if (n >= na->num_tx_rings) return NULL; + kring = na->tx_rings + n; + + if (kring->nr_pending_mode == NKR_NETMAP_OFF) { + kring->nr_mode = NKR_NETMAP_OFF; + return NULL; + } + // XXX check whether we should use hwcur or rcur new_hwofs = kring->nr_hwcur - new_cur; } else { if (n >= na->num_rx_rings) return NULL; kring = na->rx_rings + n; + + if (kring->nr_pending_mode == NKR_NETMAP_OFF) { + kring->nr_mode = NKR_NETMAP_OFF; + return NULL; + } + new_hwofs = kring->nr_hwtail - new_cur; } lim = kring->nkr_num_slots - 1; @@ -3018,6 +3171,7 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n, * We do the wakeup here, but the ring is not yet reconfigured. * However, we are under lock so there are no races. */ + kring->nr_mode = NKR_NETMAP_ON; kring->nm_notify(kring, 0); return kring->ring->slot; } @@ -3037,10 +3191,9 @@ netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n, * - for a nic connected to a switch, call the proper forwarding routine * (see netmap_bwrap_intr_notify) */ -void -netmap_common_irq(struct ifnet *ifp, u_int q, u_int *work_done) +int +netmap_common_irq(struct netmap_adapter *na, u_int q, u_int *work_done) { - struct netmap_adapter *na = NA(ifp); struct netmap_kring *kring; enum txrx t = (work_done ? NR_RX : NR_TX); @@ -3051,15 +3204,20 @@ netmap_common_irq(struct ifnet *ifp, u_int q, u_int *work_done) } if (q >= nma_get_nrings(na, t)) - return; // not a physical queue + return NM_IRQ_PASS; // not a physical queue kring = NMR(na, t) + q; + if (kring->nr_mode == NKR_NETMAP_OFF) { + return NM_IRQ_PASS; + } + if (t == NR_RX) { kring->nr_kflags |= NKR_PENDINTR; // XXX atomic ? *work_done = 1; /* do not fire napi again */ } - kring->nm_notify(kring, 0); + + return kring->nm_notify(kring, 0); } @@ -3067,17 +3225,17 @@ netmap_common_irq(struct ifnet *ifp, u_int q, u_int *work_done) * Default functions to handle rx/tx interrupts from a physical device. * "work_done" is non-null on the RX path, NULL for the TX path. * - * If the card is not in netmap mode, simply return 0, + * If the card is not in netmap mode, simply return NM_IRQ_PASS, * so that the caller proceeds with regular processing. - * Otherwise call netmap_common_irq() and return 1. + * Otherwise call netmap_common_irq(). * * If the card is connected to a netmap file descriptor, * do a selwakeup on the individual queue, plus one on the global one * if needed (multiqueue card _and_ there are multiqueue listeners), - * and return 1. + * and return NR_IRQ_COMPLETED. * * Finally, if called on rx from an interface connected to a switch, - * calls the proper forwarding routine, and return 1. + * calls the proper forwarding routine. */ int netmap_rx_irq(struct ifnet *ifp, u_int q, u_int *work_done) @@ -3091,15 +3249,14 @@ netmap_rx_irq(struct ifnet *ifp, u_int q, u_int *work_done) * nm_native_on() here. */ if (!nm_netmap_on(na)) - return 0; + return NM_IRQ_PASS; if (na->na_flags & NAF_SKIP_INTR) { ND("use regular interrupt"); - return 0; + return NM_IRQ_PASS; } - netmap_common_irq(ifp, q, work_done); - return 1; + return netmap_common_irq(na, q, work_done); } @@ -3120,9 +3277,11 @@ extern struct cdevsw netmap_cdevsw; void netmap_fini(void) { - netmap_uninit_bridges(); if (netmap_dev) destroy_dev(netmap_dev); + /* we assume that there are no longer netmap users */ + nm_os_ifnet_fini(); + netmap_uninit_bridges(); netmap_mem_fini(); NMG_LOCK_DESTROY(); printf("netmap: unloaded module.\n"); @@ -3155,9 +3314,13 @@ netmap_init(void) goto fail; #ifdef __FreeBSD__ - nm_vi_init_index(); + nm_os_vi_init_index(); #endif + error = nm_os_ifnet_init(); + if (error) + goto fail; + printf("netmap: loaded module\n"); return (0); fail: diff --git a/sys/dev/netmap/netmap_freebsd.c b/sys/dev/netmap/netmap_freebsd.c index 8490ae85670b..d83f21e255ec 100644 --- a/sys/dev/netmap/netmap_freebsd.c +++ b/sys/dev/netmap/netmap_freebsd.c @@ -27,14 +27,15 @@ #include "opt_inet.h" #include "opt_inet6.h" -#include +#include #include #include -#include /* defines used in kernel.h */ +#include #include /* POLLIN, POLLOUT */ #include /* types used in module initialization */ -#include /* DEV_MODULE */ +#include /* DEV_MODULE_ORDERED */ #include +#include /* kern_ioctl() */ #include @@ -50,6 +51,11 @@ #include #include /* sockaddrs */ #include +#include /* kthread_add() */ +#include /* PROC_LOCK() */ +#include /* RFNOWAIT */ +#include /* sched_bind() */ +#include /* mp_maxid */ #include #include #include /* IFT_ETHER */ @@ -61,13 +67,94 @@ #include #include +#include #include /* ======================== FREEBSD-SPECIFIC ROUTINES ================== */ +void nm_os_selinfo_init(NM_SELINFO_T *si) { + struct mtx *m = &si->m; + mtx_init(m, "nm_kn_lock", NULL, MTX_DEF); + knlist_init_mtx(&si->si.si_note, m); +} + +void +nm_os_selinfo_uninit(NM_SELINFO_T *si) +{ + /* XXX kqueue(9) needed; these will mirror knlist_init. */ + knlist_delete(&si->si.si_note, curthread, 0 /* not locked */ ); + knlist_destroy(&si->si.si_note); + /* now we don't need the mutex anymore */ + mtx_destroy(&si->m); +} + +void +nm_os_ifnet_lock(void) +{ + IFNET_WLOCK(); +} + +void +nm_os_ifnet_unlock(void) +{ + IFNET_WUNLOCK(); +} + +static int netmap_use_count = 0; + +void +nm_os_get_module(void) +{ + netmap_use_count++; +} + +void +nm_os_put_module(void) +{ + netmap_use_count--; +} + +static void +netmap_ifnet_arrival_handler(void *arg __unused, struct ifnet *ifp) +{ + netmap_undo_zombie(ifp); +} + +static void +netmap_ifnet_departure_handler(void *arg __unused, struct ifnet *ifp) +{ + netmap_make_zombie(ifp); +} + +static eventhandler_tag nm_ifnet_ah_tag; +static eventhandler_tag nm_ifnet_dh_tag; + +int +nm_os_ifnet_init(void) +{ + nm_ifnet_ah_tag = + EVENTHANDLER_REGISTER(ifnet_arrival_event, + netmap_ifnet_arrival_handler, + NULL, EVENTHANDLER_PRI_ANY); + nm_ifnet_dh_tag = + EVENTHANDLER_REGISTER(ifnet_departure_event, + netmap_ifnet_departure_handler, + NULL, EVENTHANDLER_PRI_ANY); + return 0; +} + +void +nm_os_ifnet_fini(void) +{ + EVENTHANDLER_DEREGISTER(ifnet_arrival_event, + nm_ifnet_ah_tag); + EVENTHANDLER_DEREGISTER(ifnet_departure_event, + nm_ifnet_dh_tag); +} + rawsum_t -nm_csum_raw(uint8_t *data, size_t len, rawsum_t cur_sum) +nm_os_csum_raw(uint8_t *data, size_t len, rawsum_t cur_sum) { /* TODO XXX please use the FreeBSD implementation for this. */ uint16_t *words = (uint16_t *)data; @@ -87,7 +174,7 @@ nm_csum_raw(uint8_t *data, size_t len, rawsum_t cur_sum) * return value is in network byte order. */ uint16_t -nm_csum_fold(rawsum_t cur_sum) +nm_os_csum_fold(rawsum_t cur_sum) { /* TODO XXX please use the FreeBSD implementation for this. */ while (cur_sum >> 16) @@ -96,17 +183,17 @@ nm_csum_fold(rawsum_t cur_sum) return htobe16((~cur_sum) & 0xFFFF); } -uint16_t nm_csum_ipv4(struct nm_iphdr *iph) +uint16_t nm_os_csum_ipv4(struct nm_iphdr *iph) { #if 0 return in_cksum_hdr((void *)iph); #else - return nm_csum_fold(nm_csum_raw((uint8_t*)iph, sizeof(struct nm_iphdr), 0)); + return nm_os_csum_fold(nm_os_csum_raw((uint8_t*)iph, sizeof(struct nm_iphdr), 0)); #endif } void -nm_csum_tcpudp_ipv4(struct nm_iphdr *iph, void *data, +nm_os_csum_tcpudp_ipv4(struct nm_iphdr *iph, void *data, size_t datalen, uint16_t *check) { #ifdef INET @@ -118,7 +205,7 @@ nm_csum_tcpudp_ipv4(struct nm_iphdr *iph, void *data, /* Compute the checksum on TCP/UDP header + payload * (includes the pseudo-header). */ - *check = nm_csum_fold(nm_csum_raw(data, datalen, 0)); + *check = nm_os_csum_fold(nm_os_csum_raw(data, datalen, 0)); #else static int notsupported = 0; if (!notsupported) { @@ -129,12 +216,12 @@ nm_csum_tcpudp_ipv4(struct nm_iphdr *iph, void *data, } void -nm_csum_tcpudp_ipv6(struct nm_ipv6hdr *ip6h, void *data, +nm_os_csum_tcpudp_ipv6(struct nm_ipv6hdr *ip6h, void *data, size_t datalen, uint16_t *check) { #ifdef INET6 *check = in6_cksum_pseudo((void*)ip6h, datalen, ip6h->nexthdr, 0); - *check = nm_csum_fold(nm_csum_raw(data, datalen, 0)); + *check = nm_os_csum_fold(nm_os_csum_raw(data, datalen, 0)); #else static int notsupported = 0; if (!notsupported) { @@ -144,13 +231,41 @@ nm_csum_tcpudp_ipv6(struct nm_ipv6hdr *ip6h, void *data, #endif } +/* on FreeBSD we send up one packet at a time */ +void * +nm_os_send_up(struct ifnet *ifp, struct mbuf *m, struct mbuf *prev) +{ + + NA(ifp)->if_input(ifp, m); + return NULL; +} + +int +nm_os_mbuf_has_offld(struct mbuf *m) +{ + return m->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP | CSUM_SCTP | + CSUM_TCP_IPV6 | CSUM_UDP_IPV6 | + CSUM_SCTP_IPV6 | CSUM_TSO); +} + +static void +freebsd_generic_rx_handler(struct ifnet *ifp, struct mbuf *m) +{ + struct netmap_generic_adapter *gna = + (struct netmap_generic_adapter *)NA(ifp); + int stolen = generic_rx_handler(ifp, m); + + if (!stolen) { + gna->save_if_input(ifp, m); + } +} /* * Intercept the rx routine in the standard device driver. * Second argument is non-zero to intercept, 0 to restore */ int -netmap_catch_rx(struct netmap_generic_adapter *gna, int intercept) +nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept) { struct netmap_adapter *na = &gna->up.up; struct ifnet *ifp = na->ifp; @@ -161,7 +276,7 @@ netmap_catch_rx(struct netmap_generic_adapter *gna, int intercept) return EINVAL; /* already set */ } gna->save_if_input = ifp->if_input; - ifp->if_input = generic_rx_handler; + ifp->if_input = freebsd_generic_rx_handler; } else { if (!gna->save_if_input){ D("cannot restore"); @@ -181,18 +296,20 @@ netmap_catch_rx(struct netmap_generic_adapter *gna, int intercept) * Second argument is non-zero to intercept, 0 to restore. * On freebsd we just intercept if_transmit. */ -void -netmap_catch_tx(struct netmap_generic_adapter *gna, int enable) +int +nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept) { struct netmap_adapter *na = &gna->up.up; struct ifnet *ifp = netmap_generic_getifp(gna); - if (enable) { + if (intercept) { na->if_transmit = ifp->if_transmit; ifp->if_transmit = netmap_transmit; } else { ifp->if_transmit = na->if_transmit; } + + return 0; } @@ -213,40 +330,44 @@ netmap_catch_tx(struct netmap_generic_adapter *gna, int enable) * */ int -generic_xmit_frame(struct ifnet *ifp, struct mbuf *m, - void *addr, u_int len, u_int ring_nr) +nm_os_generic_xmit_frame(struct nm_os_gen_arg *a) { int ret; + u_int len = a->len; + struct ifnet *ifp = a->ifp; + struct mbuf *m = a->m; +#if __FreeBSD_version < 1100000 /* - * The mbuf should be a cluster from our special pool, - * so we do not need to do an m_copyback but just copy - * (and eventually, just reference the netmap buffer) + * Old FreeBSD versions. The mbuf has a cluster attached, + * we need to copy from the cluster to the netmap buffer. */ - - if (GET_MBUF_REFCNT(m) != 1) { - D("invalid refcnt %d for %p", - GET_MBUF_REFCNT(m), m); + if (MBUF_REFCNT(m) != 1) { + D("invalid refcnt %d for %p", MBUF_REFCNT(m), m); panic("in generic_xmit_frame"); } - // XXX the ext_size check is unnecessary if we link the netmap buf if (m->m_ext.ext_size < len) { RD(5, "size %d < len %d", m->m_ext.ext_size, len); len = m->m_ext.ext_size; } - if (0) { /* XXX seems to have negligible benefits */ - m->m_ext.ext_buf = m->m_data = addr; - } else { - bcopy(addr, m->m_data, len); - } + bcopy(a->addr, m->m_data, len); +#else /* __FreeBSD_version >= 1100000 */ + /* New FreeBSD versions. Link the external storage to + * the netmap buffer, so that no copy is necessary. */ + m->m_ext.ext_buf = m->m_data = a->addr; + m->m_ext.ext_size = len; +#endif /* __FreeBSD_version >= 1100000 */ + m->m_len = m->m_pkthdr.len = len; - // inc refcount. All ours, we could skip the atomic - atomic_fetchadd_int(PNT_MBUF_REFCNT(m), 1); + + /* mbuf refcnt is not contended, no need to use atomic + * (a memory barrier is enough). */ + SET_MBUF_REFCNT(m, 2); M_HASHTYPE_SET(m, M_HASHTYPE_OPAQUE); - m->m_pkthdr.flowid = ring_nr; + m->m_pkthdr.flowid = a->ring_nr; m->m_pkthdr.rcvif = ifp; /* used for tx notification */ ret = NA(ifp)->if_transmit(ifp, m); - return ret; + return ret ? -1 : 0; } @@ -263,7 +384,7 @@ netmap_getna(if_t ifp) * way to extract the info from the ifp */ int -generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *rx) +nm_os_generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *rx) { D("called, in tx %d rx %d", *tx, *rx); return 0; @@ -271,16 +392,23 @@ generic_find_num_desc(struct ifnet *ifp, unsigned int *tx, unsigned int *rx) void -generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq) +nm_os_generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq) { D("called, in txq %d rxq %d", *txq, *rxq); *txq = netmap_generic_rings; *rxq = netmap_generic_rings; } +void +nm_os_generic_set_features(struct netmap_generic_adapter *gna) +{ + + gna->rxsg = 1; /* Supported through m_copydata. */ + gna->txqdisc = 0; /* Not supported. */ +} void -netmap_mitigation_init(struct nm_generic_mit *mit, int idx, struct netmap_adapter *na) +nm_os_mitigation_init(struct nm_generic_mit *mit, int idx, struct netmap_adapter *na) { ND("called"); mit->mit_pending = 0; @@ -290,21 +418,21 @@ netmap_mitigation_init(struct nm_generic_mit *mit, int idx, struct netmap_adapte void -netmap_mitigation_start(struct nm_generic_mit *mit) +nm_os_mitigation_start(struct nm_generic_mit *mit) { ND("called"); } void -netmap_mitigation_restart(struct nm_generic_mit *mit) +nm_os_mitigation_restart(struct nm_generic_mit *mit) { ND("called"); } int -netmap_mitigation_active(struct nm_generic_mit *mit) +nm_os_mitigation_active(struct nm_generic_mit *mit) { ND("called"); return 0; @@ -312,7 +440,7 @@ netmap_mitigation_active(struct nm_generic_mit *mit) void -netmap_mitigation_cleanup(struct nm_generic_mit *mit) +nm_os_mitigation_cleanup(struct nm_generic_mit *mit) { ND("called"); } @@ -342,7 +470,7 @@ static struct { } nm_vi_indices; void -nm_vi_init_index(void) +nm_os_vi_init_index(void) { int i; for (i = 0; i < NM_VI_MAX; i++) @@ -398,7 +526,7 @@ nm_vi_free_index(uint8_t val) * increment this refcount on if_attach(). */ int -nm_vi_persist(const char *name, struct ifnet **ret) +nm_os_vi_persist(const char *name, struct ifnet **ret) { struct ifnet *ifp; u_short macaddr_hi; @@ -438,15 +566,221 @@ nm_vi_persist(const char *name, struct ifnet **ret) *ret = ifp; return 0; } + /* unregister from the system and drop the final refcount */ void -nm_vi_detach(struct ifnet *ifp) +nm_os_vi_detach(struct ifnet *ifp) { nm_vi_free_index(((char *)IF_LLADDR(ifp))[5]); ether_ifdetach(ifp); if_free(ifp); } +/* ======================== PTNETMAP SUPPORT ========================== */ + +#ifdef WITH_PTNETMAP_GUEST +#include +#include +#include /* bus_dmamap_* */ +#include +#include +#include +/* + * ptnetmap memory device (memdev) for freebsd guest, + * ssed to expose host netmap memory to the guest through a PCI BAR. + */ + +/* + * ptnetmap memdev private data structure + */ +struct ptnetmap_memdev { + device_t dev; + struct resource *pci_io; + struct resource *pci_mem; + struct netmap_mem_d *nm_mem; +}; + +static int ptn_memdev_probe(device_t); +static int ptn_memdev_attach(device_t); +static int ptn_memdev_detach(device_t); +static int ptn_memdev_shutdown(device_t); + +static device_method_t ptn_memdev_methods[] = { + DEVMETHOD(device_probe, ptn_memdev_probe), + DEVMETHOD(device_attach, ptn_memdev_attach), + DEVMETHOD(device_detach, ptn_memdev_detach), + DEVMETHOD(device_shutdown, ptn_memdev_shutdown), + DEVMETHOD_END +}; + +static driver_t ptn_memdev_driver = { + PTNETMAP_MEMDEV_NAME, + ptn_memdev_methods, + sizeof(struct ptnetmap_memdev), +}; + +/* We use (SI_ORDER_MIDDLE+1) here, see DEV_MODULE_ORDERED() invocation + * below. */ +static devclass_t ptnetmap_devclass; +DRIVER_MODULE_ORDERED(ptn_memdev, pci, ptn_memdev_driver, ptnetmap_devclass, + NULL, NULL, SI_ORDER_MIDDLE + 1); + +/* + * I/O port read/write wrappers. + * Some are not used, so we keep them commented out until needed + */ +#define ptn_ioread16(ptn_dev, reg) bus_read_2((ptn_dev)->pci_io, (reg)) +#define ptn_ioread32(ptn_dev, reg) bus_read_4((ptn_dev)->pci_io, (reg)) +#if 0 +#define ptn_ioread8(ptn_dev, reg) bus_read_1((ptn_dev)->pci_io, (reg)) +#define ptn_iowrite8(ptn_dev, reg, val) bus_write_1((ptn_dev)->pci_io, (reg), (val)) +#define ptn_iowrite16(ptn_dev, reg, val) bus_write_2((ptn_dev)->pci_io, (reg), (val)) +#define ptn_iowrite32(ptn_dev, reg, val) bus_write_4((ptn_dev)->pci_io, (reg), (val)) +#endif /* unused */ + +/* + * Map host netmap memory through PCI-BAR in the guest OS, + * returning physical (nm_paddr) and virtual (nm_addr) addresses + * of the netmap memory mapped in the guest. + */ +int +nm_os_pt_memdev_iomap(struct ptnetmap_memdev *ptn_dev, vm_paddr_t *nm_paddr, + void **nm_addr) +{ + uint32_t mem_size; + int rid; + + D("ptn_memdev_driver iomap"); + + rid = PCIR_BAR(PTNETMAP_MEM_PCI_BAR); + mem_size = ptn_ioread32(ptn_dev, PTNETMAP_IO_PCI_MEMSIZE); + + /* map memory allocator */ + ptn_dev->pci_mem = bus_alloc_resource(ptn_dev->dev, SYS_RES_MEMORY, + &rid, 0, ~0, mem_size, RF_ACTIVE); + if (ptn_dev->pci_mem == NULL) { + *nm_paddr = 0; + *nm_addr = 0; + return ENOMEM; + } + + *nm_paddr = rman_get_start(ptn_dev->pci_mem); + *nm_addr = rman_get_virtual(ptn_dev->pci_mem); + + D("=== BAR %d start %lx len %lx mem_size %x ===", + PTNETMAP_MEM_PCI_BAR, + (unsigned long)(*nm_paddr), + (unsigned long)rman_get_size(ptn_dev->pci_mem), + mem_size); + return (0); +} + +/* Unmap host netmap memory. */ +void +nm_os_pt_memdev_iounmap(struct ptnetmap_memdev *ptn_dev) +{ + D("ptn_memdev_driver iounmap"); + + if (ptn_dev->pci_mem) { + bus_release_resource(ptn_dev->dev, SYS_RES_MEMORY, + PCIR_BAR(PTNETMAP_MEM_PCI_BAR), ptn_dev->pci_mem); + ptn_dev->pci_mem = NULL; + } +} + +/* Device identification routine, return BUS_PROBE_DEFAULT on success, + * positive on failure */ +static int +ptn_memdev_probe(device_t dev) +{ + char desc[256]; + + if (pci_get_vendor(dev) != PTNETMAP_PCI_VENDOR_ID) + return (ENXIO); + if (pci_get_device(dev) != PTNETMAP_PCI_DEVICE_ID) + return (ENXIO); + + snprintf(desc, sizeof(desc), "%s PCI adapter", + PTNETMAP_MEMDEV_NAME); + device_set_desc_copy(dev, desc); + + return (BUS_PROBE_DEFAULT); +} + +/* Device initialization routine. */ +static int +ptn_memdev_attach(device_t dev) +{ + struct ptnetmap_memdev *ptn_dev; + int rid; + uint16_t mem_id; + + D("ptn_memdev_driver attach"); + + ptn_dev = device_get_softc(dev); + ptn_dev->dev = dev; + + pci_enable_busmaster(dev); + + rid = PCIR_BAR(PTNETMAP_IO_PCI_BAR); + ptn_dev->pci_io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, + RF_ACTIVE); + if (ptn_dev->pci_io == NULL) { + device_printf(dev, "cannot map I/O space\n"); + return (ENXIO); + } + + mem_id = ptn_ioread16(ptn_dev, PTNETMAP_IO_PCI_HOSTID); + + /* create guest allocator */ + ptn_dev->nm_mem = netmap_mem_pt_guest_attach(ptn_dev, mem_id); + if (ptn_dev->nm_mem == NULL) { + ptn_memdev_detach(dev); + return (ENOMEM); + } + netmap_mem_get(ptn_dev->nm_mem); + + D("ptn_memdev_driver probe OK - host_id: %d", mem_id); + + return (0); +} + +/* Device removal routine. */ +static int +ptn_memdev_detach(device_t dev) +{ + struct ptnetmap_memdev *ptn_dev; + + D("ptn_memdev_driver detach"); + ptn_dev = device_get_softc(dev); + + if (ptn_dev->nm_mem) { + netmap_mem_put(ptn_dev->nm_mem); + ptn_dev->nm_mem = NULL; + } + if (ptn_dev->pci_mem) { + bus_release_resource(dev, SYS_RES_MEMORY, + PCIR_BAR(PTNETMAP_MEM_PCI_BAR), ptn_dev->pci_mem); + ptn_dev->pci_mem = NULL; + } + if (ptn_dev->pci_io) { + bus_release_resource(dev, SYS_RES_IOPORT, + PCIR_BAR(PTNETMAP_IO_PCI_BAR), ptn_dev->pci_io); + ptn_dev->pci_io = NULL; + } + + return (0); +} + +static int +ptn_memdev_shutdown(device_t dev) +{ + D("ptn_memdev_driver shutdown"); + return bus_generic_shutdown(dev); +} + +#endif /* WITH_PTNETMAP_GUEST */ + /* * In order to track whether pages are still mapped, we hook into * the standard cdev_pager and intercept the constructor and @@ -606,7 +940,7 @@ netmap_mmap_single(struct cdev *cdev, vm_ooffset_t *foff, * the device (/dev/netmap) so we cannot do anything useful. * To track close() on individual file descriptors we pass netmap_dtor() to * devfs_set_cdevpriv() on open(). The FreeBSD kernel will call the destructor - * when the last fd pointing to the device is closed. + * when the last fd pointing to the device is closed. * * Note that FreeBSD does not even munmap() on close() so we also have * to track mmap() ourselves, and postpone the call to @@ -634,26 +968,275 @@ netmap_open(struct cdev *dev, int oflags, int devtype, struct thread *td) (void)devtype; (void)td; - priv = malloc(sizeof(struct netmap_priv_d), M_DEVBUF, - M_NOWAIT | M_ZERO); - if (priv == NULL) - return ENOMEM; - priv->np_refs = 1; + NMG_LOCK(); + priv = netmap_priv_new(); + if (priv == NULL) { + error = ENOMEM; + goto out; + } error = devfs_set_cdevpriv(priv, netmap_dtor); if (error) { - free(priv, M_DEVBUF); - } else { - NMG_LOCK(); - netmap_use_count++; - NMG_UNLOCK(); + netmap_priv_delete(priv); } +out: + NMG_UNLOCK(); return error; } +/******************** kthread wrapper ****************/ +#include +u_int +nm_os_ncpus(void) +{ + return mp_maxid + 1; +} + +struct nm_kthread_ctx { + struct thread *user_td; /* thread user-space (kthread creator) to send ioctl */ + /* notification to guest (interrupt) */ + int irq_fd; /* ioctl fd */ + struct nm_kth_ioctl irq_ioctl; /* ioctl arguments */ + + /* notification from guest */ + void *ioevent_file; /* tsleep() argument */ + + /* worker function and parameter */ + nm_kthread_worker_fn_t worker_fn; + void *worker_private; + + struct nm_kthread *nmk; + + /* integer to manage multiple worker contexts (e.g., RX or TX on ptnetmap) */ + long type; +}; + +struct nm_kthread { + struct thread *worker; + struct mtx worker_lock; + uint64_t scheduled; /* pending wake_up request */ + struct nm_kthread_ctx worker_ctx; + int run; /* used to stop kthread */ + int attach_user; /* kthread attached to user_process */ + int affinity; +}; + +void inline +nm_os_kthread_wakeup_worker(struct nm_kthread *nmk) +{ + /* + * There may be a race between FE and BE, + * which call both this function, and worker kthread, + * that reads nmk->scheduled. + * + * For us it is not important the counter value, + * but simply that it has changed since the last + * time the kthread saw it. + */ + mtx_lock(&nmk->worker_lock); + nmk->scheduled++; + if (nmk->worker_ctx.ioevent_file) { + wakeup(nmk->worker_ctx.ioevent_file); + } + mtx_unlock(&nmk->worker_lock); +} + +void inline +nm_os_kthread_send_irq(struct nm_kthread *nmk) +{ + struct nm_kthread_ctx *ctx = &nmk->worker_ctx; + int err; + + if (ctx->user_td && ctx->irq_fd > 0) { + err = kern_ioctl(ctx->user_td, ctx->irq_fd, ctx->irq_ioctl.com, (caddr_t)&ctx->irq_ioctl.data.msix); + if (err) { + D("kern_ioctl error: %d ioctl parameters: fd %d com %ju data %p", + err, ctx->irq_fd, (uintmax_t)ctx->irq_ioctl.com, &ctx->irq_ioctl.data); + } + } +} + +static void +nm_kthread_worker(void *data) +{ + struct nm_kthread *nmk = data; + struct nm_kthread_ctx *ctx = &nmk->worker_ctx; + uint64_t old_scheduled = nmk->scheduled; + + if (nmk->affinity >= 0) { + thread_lock(curthread); + sched_bind(curthread, nmk->affinity); + thread_unlock(curthread); + } + + while (nmk->run) { + /* + * check if the parent process dies + * (when kthread is attached to user process) + */ + if (ctx->user_td) { + PROC_LOCK(curproc); + thread_suspend_check(0); + PROC_UNLOCK(curproc); + } else { + kthread_suspend_check(); + } + + /* + * if ioevent_file is not defined, we don't have notification + * mechanism and we continually execute worker_fn() + */ + if (!ctx->ioevent_file) { + ctx->worker_fn(ctx->worker_private); /* worker body */ + } else { + /* checks if there is a pending notification */ + mtx_lock(&nmk->worker_lock); + if (likely(nmk->scheduled != old_scheduled)) { + old_scheduled = nmk->scheduled; + mtx_unlock(&nmk->worker_lock); + + ctx->worker_fn(ctx->worker_private); /* worker body */ + + continue; + } else if (nmk->run) { + /* wait on event with one second timeout */ + msleep_spin(ctx->ioevent_file, &nmk->worker_lock, + "nmk_ev", hz); + nmk->scheduled++; + } + mtx_unlock(&nmk->worker_lock); + } + } + + kthread_exit(); +} + +static int +nm_kthread_open_files(struct nm_kthread *nmk, struct nm_kthread_cfg *cfg) +{ + /* send irq through ioctl to bhyve (vmm.ko) */ + if (cfg->event.irqfd) { + nmk->worker_ctx.irq_fd = cfg->event.irqfd; + nmk->worker_ctx.irq_ioctl = cfg->event.ioctl; + } + /* ring.ioeventfd contains the chan where do tsleep to wait events */ + if (cfg->event.ioeventfd) { + nmk->worker_ctx.ioevent_file = (void *)cfg->event.ioeventfd; + } + + return 0; +} + +static void +nm_kthread_close_files(struct nm_kthread *nmk) +{ + nmk->worker_ctx.irq_fd = 0; + nmk->worker_ctx.ioevent_file = NULL; +} + +void +nm_os_kthread_set_affinity(struct nm_kthread *nmk, int affinity) +{ + nmk->affinity = affinity; +} + +struct nm_kthread * +nm_os_kthread_create(struct nm_kthread_cfg *cfg) +{ + struct nm_kthread *nmk = NULL; + int error; + + nmk = malloc(sizeof(*nmk), M_DEVBUF, M_NOWAIT | M_ZERO); + if (!nmk) + return NULL; + + mtx_init(&nmk->worker_lock, "nm_kthread lock", NULL, MTX_SPIN); + nmk->worker_ctx.worker_fn = cfg->worker_fn; + nmk->worker_ctx.worker_private = cfg->worker_private; + nmk->worker_ctx.type = cfg->type; + nmk->affinity = -1; + + /* attach kthread to user process (ptnetmap) */ + nmk->attach_user = cfg->attach_user; + + /* open event fd */ + error = nm_kthread_open_files(nmk, cfg); + if (error) + goto err; + + return nmk; +err: + free(nmk, M_DEVBUF); + return NULL; +} + +int +nm_os_kthread_start(struct nm_kthread *nmk) +{ + struct proc *p = NULL; + int error = 0; + + if (nmk->worker) { + return EBUSY; + } + + /* check if we want to attach kthread to user process */ + if (nmk->attach_user) { + nmk->worker_ctx.user_td = curthread; + p = curthread->td_proc; + } + + /* enable kthread main loop */ + nmk->run = 1; + /* create kthread */ + if((error = kthread_add(nm_kthread_worker, nmk, p, + &nmk->worker, RFNOWAIT /* to be checked */, 0, "nm-kthread-%ld", + nmk->worker_ctx.type))) { + goto err; + } + + D("nm_kthread started td 0x%p", nmk->worker); + + return 0; +err: + D("nm_kthread start failed err %d", error); + nmk->worker = NULL; + return error; +} + +void +nm_os_kthread_stop(struct nm_kthread *nmk) +{ + if (!nmk->worker) { + return; + } + /* tell to kthread to exit from main loop */ + nmk->run = 0; + + /* wake up kthread if it sleeps */ + kthread_resume(nmk->worker); + nm_os_kthread_wakeup_worker(nmk); + + nmk->worker = NULL; +} + +void +nm_os_kthread_delete(struct nm_kthread *nmk) +{ + if (!nmk) + return; + if (nmk->worker) { + nm_os_kthread_stop(nmk); + } + + nm_kthread_close_files(nmk); + + free(nmk, M_DEVBUF); +} + /******************** kqueue support ****************/ /* - * The OS_selwakeup also needs to issue a KNOTE_UNLOCKED. + * nm_os_selwakeup also needs to issue a KNOTE_UNLOCKED. * We use a non-zero argument to distinguish the call from the one * in kevent_scan() which instead also needs to run netmap_poll(). * The knote uses a global mutex for the time being. We might @@ -672,17 +1255,23 @@ netmap_open(struct cdev *dev, int oflags, int devtype, struct thread *td) void -freebsd_selwakeup(struct nm_selinfo *si, int pri) +nm_os_selwakeup(struct nm_selinfo *si) { if (netmap_verbose) D("on knote %p", &si->si.si_note); - selwakeuppri(&si->si, pri); + selwakeuppri(&si->si, PI_NET); /* use a non-zero hint to tell the notification from the * call done in kqueue_scan() which uses 0 */ KNOTE_UNLOCKED(&si->si.si_note, 0x100 /* notification */); } +void +nm_os_selrecord(struct thread *td, struct nm_selinfo *si) +{ + selrecord(td, &si->si); +} + static void netmap_knrdetach(struct knote *kn) { @@ -728,7 +1317,7 @@ netmap_knrw(struct knote *kn, long hint, int events) RD(5, "curthread changed %p %p", curthread, priv->np_td); return 1; } else { - revents = netmap_poll((void *)priv, events, curthread); + revents = netmap_poll(priv, events, NULL); return (events & revents) ? 1 : 0; } } @@ -801,13 +1390,47 @@ netmap_kqfilter(struct cdev *dev, struct knote *kn) return 0; } +static int +freebsd_netmap_poll(struct cdev *cdevi __unused, int events, struct thread *td) +{ + struct netmap_priv_d *priv; + if (devfs_get_cdevpriv((void **)&priv)) { + return POLLERR; + } + return netmap_poll(priv, events, td); +} + +static int +freebsd_netmap_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, + int ffla __unused, struct thread *td) +{ + int error; + struct netmap_priv_d *priv; + + CURVNET_SET(TD_TO_VNET(td)); + error = devfs_get_cdevpriv((void **)&priv); + if (error) { + /* XXX ENOENT should be impossible, since the priv + * is now created in the open */ + if (error == ENOENT) + error = ENXIO; + goto out; + } + error = netmap_ioctl(priv, cmd, data, td); +out: + CURVNET_RESTORE(); + + return error; +} + +extern struct cdevsw netmap_cdevsw; /* XXX used in netmap.c, should go elsewhere */ struct cdevsw netmap_cdevsw = { .d_version = D_VERSION, .d_name = "netmap", .d_open = netmap_open, .d_mmap_single = netmap_mmap_single, - .d_ioctl = netmap_ioctl, - .d_poll = netmap_poll, + .d_ioctl = freebsd_netmap_ioctl, + .d_poll = freebsd_netmap_poll, .d_kqfilter = netmap_kqfilter, .d_close = netmap_close, }; @@ -852,6 +1475,24 @@ netmap_loader(__unused struct module *module, int event, __unused void *arg) return (error); } - +#ifdef DEV_MODULE_ORDERED +/* + * The netmap module contains three drivers: (i) the netmap character device + * driver; (ii) the ptnetmap memdev PCI device driver, (iii) the ptnet PCI + * device driver. The attach() routines of both (ii) and (iii) need the + * lock of the global allocator, and such lock is initialized in netmap_init(), + * which is part of (i). + * Therefore, we make sure that (i) is loaded before (ii) and (iii), using + * the 'order' parameter of driver declaration macros. For (i), we specify + * SI_ORDER_MIDDLE, while higher orders are used with the DRIVER_MODULE_ORDERED + * macros for (ii) and (iii). + */ +DEV_MODULE_ORDERED(netmap, netmap_loader, NULL, SI_ORDER_MIDDLE); +#else /* !DEV_MODULE_ORDERED */ DEV_MODULE(netmap, netmap_loader, NULL); +#endif /* DEV_MODULE_ORDERED */ +MODULE_DEPEND(netmap, pci, 1, 1, 1); MODULE_VERSION(netmap, 1); +/* reduce conditional code */ +// linux API, use for the knlist in FreeBSD +/* use a private mutex for the knlist */ diff --git a/sys/dev/netmap/netmap_generic.c b/sys/dev/netmap/netmap_generic.c index 85a6a9f76ea2..87072069fbcf 100644 --- a/sys/dev/netmap/netmap_generic.c +++ b/sys/dev/netmap/netmap_generic.c @@ -1,5 +1,7 @@ /* - * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved. + * Copyright (C) 2013-2016 Vincenzo Maffione + * Copyright (C) 2013-2016 Luigi Rizzo + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -83,25 +85,25 @@ __FBSDID("$FreeBSD$"); #define rtnl_lock() ND("rtnl_lock called") #define rtnl_unlock() ND("rtnl_unlock called") -#define MBUF_TXQ(m) ((m)->m_pkthdr.flowid) #define MBUF_RXQ(m) ((m)->m_pkthdr.flowid) #define smp_mb() /* * FreeBSD mbuf allocator/deallocator in emulation mode: + */ +#if __FreeBSD_version < 1100000 + +/* + * For older versions of FreeBSD: * * We allocate EXT_PACKET mbuf+clusters, but need to set M_NOFREE * so that the destructor, if invoked, will not free the packet. - * In principle we should set the destructor only on demand, + * In principle we should set the destructor only on demand, * but since there might be a race we better do it on allocation. * As a consequence, we also need to set the destructor or we * would leak buffers. */ -/* - * mbuf wrappers - */ - /* mbuf destructor, also need to change the type to EXT_EXTREF, * add an M_NOFREE flag, and then clear the flag and * chain into uma_zfree(zone_pack, mf) @@ -112,35 +114,93 @@ __FBSDID("$FreeBSD$"); (m)->m_ext.ext_type = EXT_EXTREF; \ } while (0) -static void -netmap_default_mbuf_destructor(struct mbuf *m) +static int +void_mbuf_dtor(struct mbuf *m, void *arg1, void *arg2) { /* restore original mbuf */ m->m_ext.ext_buf = m->m_data = m->m_ext.ext_arg1; m->m_ext.ext_arg1 = NULL; m->m_ext.ext_type = EXT_PACKET; m->m_ext.ext_free = NULL; - if (GET_MBUF_REFCNT(m) == 0) + if (MBUF_REFCNT(m) == 0) SET_MBUF_REFCNT(m, 1); uma_zfree(zone_pack, m); + + return 0; } static inline struct mbuf * -netmap_get_mbuf(int len) +nm_os_get_mbuf(struct ifnet *ifp, int len) { struct mbuf *m; + + (void)ifp; m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m) { - m->m_flags |= M_NOFREE; /* XXXNP: Almost certainly incorrect. */ + /* m_getcl() (mb_ctor_mbuf) has an assert that checks that + * M_NOFREE flag is not specified as third argument, + * so we have to set M_NOFREE after m_getcl(). */ + m->m_flags |= M_NOFREE; m->m_ext.ext_arg1 = m->m_ext.ext_buf; // XXX save - m->m_ext.ext_free = (void *)netmap_default_mbuf_destructor; + m->m_ext.ext_free = (void *)void_mbuf_dtor; m->m_ext.ext_type = EXT_EXTREF; - ND(5, "create m %p refcnt %d", m, GET_MBUF_REFCNT(m)); + ND(5, "create m %p refcnt %d", m, MBUF_REFCNT(m)); } return m; } +#else /* __FreeBSD_version >= 1100000 */ +/* + * Newer versions of FreeBSD, using a straightforward scheme. + * + * We allocate mbufs with m_gethdr(), since the mbuf header is needed + * by the driver. We also attach a customly-provided external storage, + * which in this case is a netmap buffer. When calling m_extadd(), however + * we pass a NULL address, since the real address (and length) will be + * filled in by nm_os_generic_xmit_frame() right before calling + * if_transmit(). + * + * The dtor function does nothing, however we need it since mb_free_ext() + * has a KASSERT(), checking that the mbuf dtor function is not NULL. + */ + +#define SET_MBUF_DESTRUCTOR(m, fn) do { \ + (m)->m_ext.ext_free = (void *)fn; \ +} while (0) + +static void void_mbuf_dtor(struct mbuf *m, void *arg1, void *arg2) { } + +static inline struct mbuf * +nm_os_get_mbuf(struct ifnet *ifp, int len) +{ + struct mbuf *m; + + (void)ifp; + (void)len; + + m = m_gethdr(M_NOWAIT, MT_DATA); + if (m == NULL) { + return m; + } + + m_extadd(m, NULL /* buf */, 0 /* size */, void_mbuf_dtor, + NULL, NULL, 0, EXT_NET_DRV); + + return m; +} + +#endif /* __FreeBSD_version >= 1100000 */ + +#elif defined _WIN32 + +#include "win_glue.h" + +#define rtnl_lock() ND("rtnl_lock called") +#define rtnl_unlock() ND("rtnl_unlock called") +#define MBUF_TXQ(m) 0//((m)->m_pkthdr.flowid) +#define MBUF_RXQ(m) 0//((m)->m_pkthdr.flowid) +#define smp_mb() //XXX: to be correctly defined #else /* linux */ @@ -150,7 +210,12 @@ netmap_get_mbuf(int len) #include /* struct ethtool_ops, get_ringparam */ #include -//#define REG_RESET +static inline struct mbuf * +nm_os_get_mbuf(struct ifnet *ifp, int len) +{ + return alloc_skb(ifp->needed_headroom + len + + ifp->needed_tailroom, GFP_ATOMIC); +} #endif /* linux */ @@ -161,8 +226,21 @@ netmap_get_mbuf(int len) #include +#define for_each_kring_n(_i, _k, _karr, _n) \ + for (_k=_karr, _i = 0; _i < _n; (_k)++, (_i)++) -/* ======================== usage stats =========================== */ +#define for_each_tx_kring(_i, _k, _na) \ + for_each_kring_n(_i, _k, (_na)->tx_rings, (_na)->num_tx_rings) +#define for_each_tx_kring_h(_i, _k, _na) \ + for_each_kring_n(_i, _k, (_na)->tx_rings, (_na)->num_tx_rings + 1) + +#define for_each_rx_kring(_i, _k, _na) \ + for_each_kring_n(_i, _k, (_na)->rx_rings, (_na)->num_rx_rings) +#define for_each_rx_kring_h(_i, _k, _na) \ + for_each_kring_n(_i, _k, (_na)->rx_rings, (_na)->num_rx_rings + 1) + + +/* ======================== PERFORMANCE STATISTICS =========================== */ #ifdef RATE_GENERIC #define IFRATE(x) x @@ -170,6 +248,8 @@ struct rate_stats { unsigned long txpkt; unsigned long txsync; unsigned long txirq; + unsigned long txrepl; + unsigned long txdrop; unsigned long rxpkt; unsigned long rxirq; unsigned long rxsync; @@ -194,6 +274,8 @@ static void rate_callback(unsigned long arg) RATE_PRINTK(txpkt); RATE_PRINTK(txsync); RATE_PRINTK(txirq); + RATE_PRINTK(txrepl); + RATE_PRINTK(txdrop); RATE_PRINTK(rxpkt); RATE_PRINTK(rxsync); RATE_PRINTK(rxirq); @@ -230,94 +312,222 @@ void generic_rate(int txp, int txs, int txi, int rxp, int rxs, int rxi) * the poller threads. Differently from netmap_rx_irq(), we check * only NAF_NETMAP_ON instead of NAF_NATIVE_ON to enable the irq. */ -static void -netmap_generic_irq(struct ifnet *ifp, u_int q, u_int *work_done) +void +netmap_generic_irq(struct netmap_adapter *na, u_int q, u_int *work_done) { - struct netmap_adapter *na = NA(ifp); if (unlikely(!nm_netmap_on(na))) return; - netmap_common_irq(ifp, q, work_done); + netmap_common_irq(na, q, work_done); +#ifdef RATE_GENERIC + if (work_done) + rate_ctx.new.rxirq++; + else + rate_ctx.new.txirq++; +#endif /* RATE_GENERIC */ } +static int +generic_netmap_unregister(struct netmap_adapter *na) +{ + struct netmap_generic_adapter *gna = (struct netmap_generic_adapter *)na; + struct netmap_kring *kring = NULL; + int i, r; + + if (na->active_fds == 0) { + D("Generic adapter %p goes off", na); + rtnl_lock(); + + na->na_flags &= ~NAF_NETMAP_ON; + + /* Release packet steering control. */ + nm_os_catch_tx(gna, 0); + + /* Stop intercepting packets on the RX path. */ + nm_os_catch_rx(gna, 0); + + rtnl_unlock(); + } + + for_each_rx_kring_h(r, kring, na) { + if (nm_kring_pending_off(kring)) { + D("RX ring %d of generic adapter %p goes off", r, na); + kring->nr_mode = NKR_NETMAP_OFF; + } + } + for_each_tx_kring_h(r, kring, na) { + if (nm_kring_pending_off(kring)) { + kring->nr_mode = NKR_NETMAP_OFF; + D("TX ring %d of generic adapter %p goes off", r, na); + } + } + + for_each_rx_kring(r, kring, na) { + /* Free the mbufs still pending in the RX queues, + * that did not end up into the corresponding netmap + * RX rings. */ + mbq_safe_purge(&kring->rx_queue); + nm_os_mitigation_cleanup(&gna->mit[r]); + } + + /* Decrement reference counter for the mbufs in the + * TX pools. These mbufs can be still pending in drivers, + * (e.g. this happens with virtio-net driver, which + * does lazy reclaiming of transmitted mbufs). */ + for_each_tx_kring(r, kring, na) { + /* We must remove the destructor on the TX event, + * because the destructor invokes netmap code, and + * the netmap module may disappear before the + * TX event is consumed. */ + mtx_lock_spin(&kring->tx_event_lock); + if (kring->tx_event) { + SET_MBUF_DESTRUCTOR(kring->tx_event, NULL); + } + kring->tx_event = NULL; + mtx_unlock_spin(&kring->tx_event_lock); + } + + if (na->active_fds == 0) { + free(gna->mit, M_DEVBUF); + + for_each_rx_kring(r, kring, na) { + mbq_safe_fini(&kring->rx_queue); + } + + for_each_tx_kring(r, kring, na) { + mtx_destroy(&kring->tx_event_lock); + if (kring->tx_pool == NULL) { + continue; + } + + for (i=0; inum_tx_desc; i++) { + if (kring->tx_pool[i]) { + m_freem(kring->tx_pool[i]); + } + } + free(kring->tx_pool, M_DEVBUF); + kring->tx_pool = NULL; + } + +#ifdef RATE_GENERIC + if (--rate_ctx.refcount == 0) { + D("del_timer()"); + del_timer(&rate_ctx.timer); + } +#endif + } + + return 0; +} /* Enable/disable netmap mode for a generic network interface. */ static int generic_netmap_register(struct netmap_adapter *na, int enable) { struct netmap_generic_adapter *gna = (struct netmap_generic_adapter *)na; - struct mbuf *m; + struct netmap_kring *kring = NULL; int error; int i, r; - if (!na) + if (!na) { return EINVAL; - -#ifdef REG_RESET - error = ifp->netdev_ops->ndo_stop(ifp); - if (error) { - return error; } -#endif /* REG_RESET */ - if (enable) { /* Enable netmap mode. */ - /* Init the mitigation support on all the rx queues. */ + if (!enable) { + /* This is actually an unregif. */ + return generic_netmap_unregister(na); + } + + if (na->active_fds == 0) { + D("Generic adapter %p goes on", na); + /* Do all memory allocations when (na->active_fds == 0), to + * simplify error management. */ + + /* Allocate memory for mitigation support on all the rx queues. */ gna->mit = malloc(na->num_rx_rings * sizeof(struct nm_generic_mit), - M_DEVBUF, M_NOWAIT | M_ZERO); + M_DEVBUF, M_NOWAIT | M_ZERO); if (!gna->mit) { D("mitigation allocation failed"); error = ENOMEM; goto out; } - for (r=0; rnum_rx_rings; r++) - netmap_mitigation_init(&gna->mit[r], r, na); - /* Initialize the rx queue, as generic_rx_handler() can - * be called as soon as netmap_catch_rx() returns. - */ - for (r=0; rnum_rx_rings; r++) { - mbq_safe_init(&na->rx_rings[r].rx_queue); + for_each_rx_kring(r, kring, na) { + /* Init mitigation support. */ + nm_os_mitigation_init(&gna->mit[r], r, na); + + /* Initialize the rx queue, as generic_rx_handler() can + * be called as soon as nm_os_catch_rx() returns. + */ + mbq_safe_init(&kring->rx_queue); } /* - * Preallocate packet buffers for the tx rings. + * Prepare mbuf pools (parallel to the tx rings), for packet + * transmission. Don't preallocate the mbufs here, it's simpler + * to leave this task to txsync. */ - for (r=0; rnum_tx_rings; r++) - na->tx_rings[r].tx_pool = NULL; - for (r=0; rnum_tx_rings; r++) { - na->tx_rings[r].tx_pool = malloc(na->num_tx_desc * sizeof(struct mbuf *), - M_DEVBUF, M_NOWAIT | M_ZERO); - if (!na->tx_rings[r].tx_pool) { + for_each_tx_kring(r, kring, na) { + kring->tx_pool = NULL; + } + for_each_tx_kring(r, kring, na) { + kring->tx_pool = + malloc(na->num_tx_desc * sizeof(struct mbuf *), + M_DEVBUF, M_NOWAIT | M_ZERO); + if (!kring->tx_pool) { D("tx_pool allocation failed"); error = ENOMEM; goto free_tx_pools; } - for (i=0; inum_tx_desc; i++) - na->tx_rings[r].tx_pool[i] = NULL; - for (i=0; inum_tx_desc; i++) { - m = netmap_get_mbuf(NETMAP_BUF_SIZE(na)); - if (!m) { - D("tx_pool[%d] allocation failed", i); - error = ENOMEM; - goto free_tx_pools; - } - na->tx_rings[r].tx_pool[i] = m; - } + mtx_init(&kring->tx_event_lock, "tx_event_lock", + NULL, MTX_SPIN); } + } + + for_each_rx_kring_h(r, kring, na) { + if (nm_kring_pending_on(kring)) { + D("RX ring %d of generic adapter %p goes on", r, na); + kring->nr_mode = NKR_NETMAP_ON; + } + + } + for_each_tx_kring_h(r, kring, na) { + if (nm_kring_pending_on(kring)) { + D("TX ring %d of generic adapter %p goes on", r, na); + kring->nr_mode = NKR_NETMAP_ON; + } + } + + for_each_tx_kring(r, kring, na) { + /* Initialize tx_pool and tx_event. */ + for (i=0; inum_tx_desc; i++) { + kring->tx_pool[i] = NULL; + } + + kring->tx_event = NULL; + } + + if (na->active_fds == 0) { rtnl_lock(); + /* Prepare to intercept incoming traffic. */ - error = netmap_catch_rx(gna, 1); + error = nm_os_catch_rx(gna, 1); if (error) { - D("netdev_rx_handler_register() failed (%d)", error); + D("nm_os_catch_rx(1) failed (%d)", error); goto register_handler; } - na->na_flags |= NAF_NETMAP_ON; /* Make netmap control the packet steering. */ - netmap_catch_tx(gna, 1); + error = nm_os_catch_tx(gna, 1); + if (error) { + D("nm_os_catch_tx(1) failed (%d)", error); + goto catch_rx; + } rtnl_unlock(); + na->na_flags |= NAF_NETMAP_ON; + #ifdef RATE_GENERIC if (rate_ctx.refcount == 0) { D("setup_timer()"); @@ -329,73 +539,26 @@ generic_netmap_register(struct netmap_adapter *na, int enable) } rate_ctx.refcount++; #endif /* RATE */ - - } else if (na->tx_rings[0].tx_pool) { - /* Disable netmap mode. We enter here only if the previous - generic_netmap_register(na, 1) was successful. - If it was not, na->tx_rings[0].tx_pool was set to NULL by the - error handling code below. */ - rtnl_lock(); - - na->na_flags &= ~NAF_NETMAP_ON; - - /* Release packet steering control. */ - netmap_catch_tx(gna, 0); - - /* Do not intercept packets on the rx path. */ - netmap_catch_rx(gna, 0); - - rtnl_unlock(); - - /* Free the mbufs going to the netmap rings */ - for (r=0; rnum_rx_rings; r++) { - mbq_safe_purge(&na->rx_rings[r].rx_queue); - mbq_safe_destroy(&na->rx_rings[r].rx_queue); - } - - for (r=0; rnum_rx_rings; r++) - netmap_mitigation_cleanup(&gna->mit[r]); - free(gna->mit, M_DEVBUF); - - for (r=0; rnum_tx_rings; r++) { - for (i=0; inum_tx_desc; i++) { - m_freem(na->tx_rings[r].tx_pool[i]); - } - free(na->tx_rings[r].tx_pool, M_DEVBUF); - } - -#ifdef RATE_GENERIC - if (--rate_ctx.refcount == 0) { - D("del_timer()"); - del_timer(&rate_ctx.timer); - } -#endif } -#ifdef REG_RESET - error = ifp->netdev_ops->ndo_open(ifp); - if (error) { - goto free_tx_pools; - } -#endif - return 0; + /* Here (na->active_fds == 0) holds. */ +catch_rx: + nm_os_catch_rx(gna, 0); register_handler: rtnl_unlock(); free_tx_pools: - for (r=0; rnum_tx_rings; r++) { - if (na->tx_rings[r].tx_pool == NULL) + for_each_tx_kring(r, kring, na) { + mtx_destroy(&kring->tx_event_lock); + if (kring->tx_pool == NULL) { continue; - for (i=0; inum_tx_desc; i++) - if (na->tx_rings[r].tx_pool[i]) - m_freem(na->tx_rings[r].tx_pool[i]); - free(na->tx_rings[r].tx_pool, M_DEVBUF); - na->tx_rings[r].tx_pool = NULL; + } + free(kring->tx_pool, M_DEVBUF); + kring->tx_pool = NULL; } - for (r=0; rnum_rx_rings; r++) { - netmap_mitigation_cleanup(&gna->mit[r]); - mbq_safe_destroy(&na->rx_rings[r].rx_queue); + for_each_rx_kring(r, kring, na) { + mbq_safe_fini(&kring->rx_queue); } free(gna->mit, M_DEVBUF); out: @@ -411,16 +574,59 @@ generic_netmap_register(struct netmap_adapter *na, int enable) static void generic_mbuf_destructor(struct mbuf *m) { - netmap_generic_irq(MBUF_IFP(m), MBUF_TXQ(m), NULL); -#ifdef __FreeBSD__ - if (netmap_verbose) - RD(5, "Tx irq (%p) queue %d index %d" , m, MBUF_TXQ(m), (int)(uintptr_t)m->m_ext.ext_arg1); - netmap_default_mbuf_destructor(m); -#endif /* __FreeBSD__ */ - IFRATE(rate_ctx.new.txirq++); -} + struct netmap_adapter *na = NA(GEN_TX_MBUF_IFP(m)); + struct netmap_kring *kring; + unsigned int r = MBUF_TXQ(m); + unsigned int r_orig = r; -extern int netmap_adaptive_io; + if (unlikely(!nm_netmap_on(na) || r >= na->num_tx_rings)) { + D("Error: no netmap adapter on device %p", + GEN_TX_MBUF_IFP(m)); + return; + } + + /* + * First, clear the event mbuf. + * In principle, the event 'm' should match the one stored + * on ring 'r'. However we check it explicitely to stay + * safe against lower layers (qdisc, driver, etc.) changing + * MBUF_TXQ(m) under our feet. If the match is not found + * on 'r', we try to see if it belongs to some other ring. + */ + for (;;) { + bool match = false; + + kring = &na->tx_rings[r]; + mtx_lock_spin(&kring->tx_event_lock); + if (kring->tx_event == m) { + kring->tx_event = NULL; + match = true; + } + mtx_unlock_spin(&kring->tx_event_lock); + + if (match) { + if (r != r_orig) { + RD(1, "event %p migrated: ring %u --> %u", + m, r_orig, r); + } + break; + } + + if (++r == na->num_tx_rings) r = 0; + + if (r == r_orig) { + RD(1, "Cannot match event %p", m); + return; + } + } + + /* Second, wake up clients. They will reclaim the event through + * txsync. */ + netmap_generic_irq(na, r, NULL); +#ifdef __FreeBSD__ + void_mbuf_dtor(m, NULL, NULL); +#endif +} /* Record completed transmissions and update hwtail. * @@ -428,7 +634,7 @@ extern int netmap_adaptive_io; * nr_hwcur is the first unsent buffer. */ static u_int -generic_netmap_tx_clean(struct netmap_kring *kring) +generic_netmap_tx_clean(struct netmap_kring *kring, int txqdisc) { u_int const lim = kring->nkr_num_slots - 1; u_int nm_i = nm_next(kring->nr_hwtail, lim); @@ -436,39 +642,52 @@ generic_netmap_tx_clean(struct netmap_kring *kring) u_int n = 0; struct mbuf **tx_pool = kring->tx_pool; + ND("hwcur = %d, hwtail = %d", kring->nr_hwcur, kring->nr_hwtail); + while (nm_i != hwcur) { /* buffers not completed */ struct mbuf *m = tx_pool[nm_i]; - if (unlikely(m == NULL)) { - /* this is done, try to replenish the entry */ - tx_pool[nm_i] = m = netmap_get_mbuf(NETMAP_BUF_SIZE(kring->na)); - if (unlikely(m == NULL)) { - D("mbuf allocation failed, XXX error"); - // XXX how do we proceed ? break ? - return -ENOMEM; + if (txqdisc) { + if (m == NULL) { + /* Nothing to do, this is going + * to be replenished. */ + RD(3, "Is this happening?"); + + } else if (MBUF_QUEUED(m)) { + break; /* Not dequeued yet. */ + + } else if (MBUF_REFCNT(m) != 1) { + /* This mbuf has been dequeued but is still busy + * (refcount is 2). + * Leave it to the driver and replenish. */ + m_freem(m); + tx_pool[nm_i] = NULL; + } + + } else { + if (unlikely(m == NULL)) { + int event_consumed; + + /* This slot was used to place an event. */ + mtx_lock_spin(&kring->tx_event_lock); + event_consumed = (kring->tx_event == NULL); + mtx_unlock_spin(&kring->tx_event_lock); + if (!event_consumed) { + /* The event has not been consumed yet, + * still busy in the driver. */ + break; + } + /* The event has been consumed, we can go + * ahead. */ + + } else if (MBUF_REFCNT(m) != 1) { + /* This mbuf is still busy: its refcnt is 2. */ + break; } - } else if (GET_MBUF_REFCNT(m) != 1) { - break; /* This mbuf is still busy: its refcnt is 2. */ } + n++; nm_i = nm_next(nm_i, lim); -#if 0 /* rate adaptation */ - if (netmap_adaptive_io > 1) { - if (n >= netmap_adaptive_io) - break; - } else if (netmap_adaptive_io) { - /* if hwcur - nm_i < lim/8 do an early break - * so we prevent the sender from stalling. See CVT. - */ - if (hwcur >= nm_i) { - if (hwcur - nm_i < lim/2) - break; - } else { - if (hwcur + lim + 1 - nm_i < lim/2) - break; - } - } -#endif } kring->nr_hwtail = nm_prev(nm_i, lim); ND("tx completed [%d] -> hwtail %d", n, kring->nr_hwtail); @@ -476,23 +695,17 @@ generic_netmap_tx_clean(struct netmap_kring *kring) return n; } - -/* - * We have pending packets in the driver between nr_hwtail +1 and hwcur. - * Compute a position in the middle, to be used to generate - * a notification. - */ +/* Compute a slot index in the middle between inf and sup. */ static inline u_int -generic_tx_event_middle(struct netmap_kring *kring, u_int hwcur) +ring_middle(u_int inf, u_int sup, u_int lim) { - u_int n = kring->nkr_num_slots; - u_int ntc = nm_next(kring->nr_hwtail, n-1); + u_int n = lim + 1; u_int e; - if (hwcur >= ntc) { - e = (hwcur + ntc) / 2; + if (sup >= inf) { + e = (sup + inf) / 2; } else { /* wrap around */ - e = (hwcur + n + ntc) / 2; + e = (sup + n + inf) / 2; if (e >= n) { e -= n; } @@ -506,35 +719,59 @@ generic_tx_event_middle(struct netmap_kring *kring, u_int hwcur) return e; } -/* - * We have pending packets in the driver between nr_hwtail+1 and hwcur. - * Schedule a notification approximately in the middle of the two. - * There is a race but this is only called within txsync which does - * a double check. - */ static void generic_set_tx_event(struct netmap_kring *kring, u_int hwcur) { + u_int lim = kring->nkr_num_slots - 1; struct mbuf *m; u_int e; + u_int ntc = nm_next(kring->nr_hwtail, lim); /* next to clean */ - if (nm_next(kring->nr_hwtail, kring->nkr_num_slots -1) == hwcur) { + if (ntc == hwcur) { return; /* all buffers are free */ } - e = generic_tx_event_middle(kring, hwcur); + + /* + * We have pending packets in the driver between hwtail+1 + * and hwcur, and we have to chose one of these slot to + * generate a notification. + * There is a race but this is only called within txsync which + * does a double check. + */ +#if 0 + /* Choose a slot in the middle, so that we don't risk ending + * up in a situation where the client continuously wake up, + * fills one or a few TX slots and go to sleep again. */ + e = ring_middle(ntc, hwcur, lim); +#else + /* Choose the first pending slot, to be safe against driver + * reordering mbuf transmissions. */ + e = ntc; +#endif m = kring->tx_pool[e]; - ND(5, "Request Event at %d mbuf %p refcnt %d", e, m, m ? GET_MBUF_REFCNT(m) : -2 ); if (m == NULL) { - /* This can happen if there is already an event on the netmap - slot 'e': There is nothing to do. */ + /* An event is already in place. */ return; } - kring->tx_pool[e] = NULL; - SET_MBUF_DESTRUCTOR(m, generic_mbuf_destructor); - // XXX wmb() ? - /* Decrement the refcount an free it if we have the last one. */ + mtx_lock_spin(&kring->tx_event_lock); + if (kring->tx_event) { + /* An event is already in place. */ + mtx_unlock_spin(&kring->tx_event_lock); + return; + } + + SET_MBUF_DESTRUCTOR(m, generic_mbuf_destructor); + kring->tx_event = m; + mtx_unlock_spin(&kring->tx_event_lock); + + kring->tx_pool[e] = NULL; + + ND(5, "Request Event at %d mbuf %p refcnt %d", e, m, m ? MBUF_REFCNT(m) : -2 ); + + /* Decrement the refcount. This will free it if we lose the race + * with the driver. */ m_freem(m); smp_mb(); } @@ -551,6 +788,7 @@ static int generic_netmap_txsync(struct netmap_kring *kring, int flags) { struct netmap_adapter *na = kring->na; + struct netmap_generic_adapter *gna = (struct netmap_generic_adapter *)na; struct ifnet *ifp = na->ifp; struct netmap_ring *ring = kring->ring; u_int nm_i; /* index into the netmap ring */ // j @@ -560,8 +798,6 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags) IFRATE(rate_ctx.new.txsync++); - // TODO: handle the case of mbuf allocation failure - rmb(); /* @@ -569,72 +805,121 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags) */ nm_i = kring->nr_hwcur; if (nm_i != head) { /* we have new packets to send */ + struct nm_os_gen_arg a; + u_int event = -1; + + if (gna->txqdisc && nm_kr_txempty(kring)) { + /* In txqdisc mode, we ask for a delayed notification, + * but only when cur == hwtail, which means that the + * client is going to block. */ + event = ring_middle(nm_i, head, lim); + ND(3, "Place txqdisc event (hwcur=%u,event=%u," + "head=%u,hwtail=%u)", nm_i, event, head, + kring->nr_hwtail); + } + + a.ifp = ifp; + a.ring_nr = ring_nr; + a.head = a.tail = NULL; + while (nm_i != head) { struct netmap_slot *slot = &ring->slot[nm_i]; u_int len = slot->len; void *addr = NMB(na, slot); - /* device-specific */ struct mbuf *m; int tx_ret; NM_CHECK_ADDR_LEN(na, addr, len); - /* Tale a mbuf from the tx pool and copy in the user packet. */ + /* Tale a mbuf from the tx pool (replenishing the pool + * entry if necessary) and copy in the user packet. */ m = kring->tx_pool[nm_i]; - if (unlikely(!m)) { - RD(5, "This should never happen"); - kring->tx_pool[nm_i] = m = netmap_get_mbuf(NETMAP_BUF_SIZE(na)); - if (unlikely(m == NULL)) { - D("mbuf allocation failed"); + if (unlikely(m == NULL)) { + kring->tx_pool[nm_i] = m = + nm_os_get_mbuf(ifp, NETMAP_BUF_SIZE(na)); + if (m == NULL) { + RD(2, "Failed to replenish mbuf"); + /* Here we could schedule a timer which + * retries to replenish after a while, + * and notifies the client when it + * manages to replenish some slots. In + * any case we break early to avoid + * crashes. */ break; } + IFRATE(rate_ctx.new.txrepl++); } - /* XXX we should ask notifications when NS_REPORT is set, - * or roughly every half frame. We can optimize this - * by lazily requesting notifications only when a - * transmission fails. Probably the best way is to - * break on failures and set notifications when - * ring->cur == ring->tail || nm_i != cur + + a.m = m; + a.addr = addr; + a.len = len; + a.qevent = (nm_i == event); + /* When not in txqdisc mode, we should ask + * notifications when NS_REPORT is set, or roughly + * every half ring. To optimize this, we set a + * notification event when the client runs out of + * TX ring space, or when transmission fails. In + * the latter case we also break early. */ - tx_ret = generic_xmit_frame(ifp, m, addr, len, ring_nr); + tx_ret = nm_os_generic_xmit_frame(&a); if (unlikely(tx_ret)) { - ND(5, "start_xmit failed: err %d [nm_i %u, head %u, hwtail %u]", - tx_ret, nm_i, head, kring->nr_hwtail); - /* - * No room for this mbuf in the device driver. - * Request a notification FOR A PREVIOUS MBUF, - * then call generic_netmap_tx_clean(kring) to do the - * double check and see if we can free more buffers. - * If there is space continue, else break; - * NOTE: the double check is necessary if the problem - * occurs in the txsync call after selrecord(). - * Also, we need some way to tell the caller that not - * all buffers were queued onto the device (this was - * not a problem with native netmap driver where space - * is preallocated). The bridge has a similar problem - * and we solve it there by dropping the excess packets. - */ - generic_set_tx_event(kring, nm_i); - if (generic_netmap_tx_clean(kring)) { /* space now available */ - continue; - } else { - break; + if (!gna->txqdisc) { + /* + * No room for this mbuf in the device driver. + * Request a notification FOR A PREVIOUS MBUF, + * then call generic_netmap_tx_clean(kring) to do the + * double check and see if we can free more buffers. + * If there is space continue, else break; + * NOTE: the double check is necessary if the problem + * occurs in the txsync call after selrecord(). + * Also, we need some way to tell the caller that not + * all buffers were queued onto the device (this was + * not a problem with native netmap driver where space + * is preallocated). The bridge has a similar problem + * and we solve it there by dropping the excess packets. + */ + generic_set_tx_event(kring, nm_i); + if (generic_netmap_tx_clean(kring, gna->txqdisc)) { + /* space now available */ + continue; + } else { + break; + } } + + /* In txqdisc mode, the netmap-aware qdisc + * queue has the same length as the number of + * netmap slots (N). Since tail is advanced + * only when packets are dequeued, qdisc + * queue overrun cannot happen, so + * nm_os_generic_xmit_frame() did not fail + * because of that. + * However, packets can be dropped because + * carrier is off, or because our qdisc is + * being deactivated, or possibly for other + * reasons. In these cases, we just let the + * packet to be dropped. */ + IFRATE(rate_ctx.new.txdrop++); } + slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED); nm_i = nm_next(nm_i, lim); - IFRATE(rate_ctx.new.txpkt ++); + IFRATE(rate_ctx.new.txpkt++); } - - /* Update hwcur to the next slot to transmit. */ - kring->nr_hwcur = nm_i; /* not head, we could break early */ + if (a.head != NULL) { + a.addr = NULL; + nm_os_generic_xmit_frame(&a); + } + /* Update hwcur to the next slot to transmit. Here nm_i + * is not necessarily head, we could break early. */ + kring->nr_hwcur = nm_i; } /* * Second, reclaim completed buffers */ - if (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring)) { + if (!gna->txqdisc && (flags & NAF_FORCE_RECLAIM || nm_kr_txempty(kring))) { /* No more available slots? Set a notification event * on a netmap slot that will be cleaned in the future. * No doublecheck is performed, since txsync() will be @@ -642,58 +927,74 @@ generic_netmap_txsync(struct netmap_kring *kring, int flags) */ generic_set_tx_event(kring, nm_i); } - ND("tx #%d, hwtail = %d", n, kring->nr_hwtail); - generic_netmap_tx_clean(kring); + generic_netmap_tx_clean(kring, gna->txqdisc); return 0; } /* - * This handler is registered (through netmap_catch_rx()) + * This handler is registered (through nm_os_catch_rx()) * within the attached network interface * in the RX subsystem, so that every mbuf passed up by * the driver can be stolen to the network stack. * Stolen packets are put in a queue where the * generic_netmap_rxsync() callback can extract them. + * Returns 1 if the packet was stolen, 0 otherwise. */ -void +int generic_rx_handler(struct ifnet *ifp, struct mbuf *m) { struct netmap_adapter *na = NA(ifp); struct netmap_generic_adapter *gna = (struct netmap_generic_adapter *)na; + struct netmap_kring *kring; u_int work_done; - u_int rr = MBUF_RXQ(m); // receive ring number + u_int r = MBUF_RXQ(m); /* receive ring number */ - if (rr >= na->num_rx_rings) { - rr = rr % na->num_rx_rings; // XXX expensive... + if (r >= na->num_rx_rings) { + r = r % na->num_rx_rings; + } + + kring = &na->rx_rings[r]; + + if (kring->nr_mode == NKR_NETMAP_OFF) { + /* We must not intercept this mbuf. */ + return 0; } /* limit the size of the queue */ - if (unlikely(mbq_len(&na->rx_rings[rr].rx_queue) > 1024)) { + if (unlikely(!gna->rxsg && MBUF_LEN(m) > NETMAP_BUF_SIZE(na))) { + /* This may happen when GRO/LRO features are enabled for + * the NIC driver when the generic adapter does not + * support RX scatter-gather. */ + RD(2, "Warning: driver pushed up big packet " + "(size=%d)", (int)MBUF_LEN(m)); + m_freem(m); + } else if (unlikely(mbq_len(&kring->rx_queue) > 1024)) { m_freem(m); } else { - mbq_safe_enqueue(&na->rx_rings[rr].rx_queue, m); + mbq_safe_enqueue(&kring->rx_queue, m); } if (netmap_generic_mit < 32768) { /* no rx mitigation, pass notification up */ - netmap_generic_irq(na->ifp, rr, &work_done); - IFRATE(rate_ctx.new.rxirq++); + netmap_generic_irq(na, r, &work_done); } else { /* same as send combining, filter notification if there is a * pending timer, otherwise pass it up and start a timer. */ - if (likely(netmap_mitigation_active(&gna->mit[rr]))) { + if (likely(nm_os_mitigation_active(&gna->mit[r]))) { /* Record that there is some pending work. */ - gna->mit[rr].mit_pending = 1; + gna->mit[r].mit_pending = 1; } else { - netmap_generic_irq(na->ifp, rr, &work_done); - IFRATE(rate_ctx.new.rxirq++); - netmap_mitigation_start(&gna->mit[rr]); + netmap_generic_irq(na, r, &work_done); + nm_os_mitigation_start(&gna->mit[r]); } } + + /* We have intercepted the mbuf. */ + return 1; } /* @@ -713,54 +1014,23 @@ generic_netmap_rxsync(struct netmap_kring *kring, int flags) u_int const head = kring->rhead; int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR; + /* Adapter-specific variables. */ + uint16_t slot_flags = kring->nkr_slot_flags; + u_int nm_buf_len = NETMAP_BUF_SIZE(na); + struct mbq tmpq; + struct mbuf *m; + int avail; /* in bytes */ + int mlen; + int copy; + if (head > lim) return netmap_ring_reinit(kring); + IFRATE(rate_ctx.new.rxsync++); + /* - * First part: import newly received packets. - */ - if (netmap_no_pendintr || force_update) { - /* extract buffers from the rx queue, stop at most one - * slot before nr_hwcur (stop_i) - */ - uint16_t slot_flags = kring->nkr_slot_flags; - u_int stop_i = nm_prev(kring->nr_hwcur, lim); - - nm_i = kring->nr_hwtail; /* first empty slot in the receive ring */ - for (n = 0; nm_i != stop_i; n++) { - int len; - void *addr = NMB(na, &ring->slot[nm_i]); - struct mbuf *m; - - /* we only check the address here on generic rx rings */ - if (addr == NETMAP_BUF_BASE(na)) { /* Bad buffer */ - return netmap_ring_reinit(kring); - } - /* - * Call the locked version of the function. - * XXX Ideally we could grab a batch of mbufs at once - * and save some locking overhead. - */ - m = mbq_safe_dequeue(&kring->rx_queue); - if (!m) /* no more data */ - break; - len = MBUF_LEN(m); - m_copydata(m, 0, len, addr); - ring->slot[nm_i].len = len; - ring->slot[nm_i].flags = slot_flags; - m_freem(m); - nm_i = nm_next(nm_i, lim); - } - if (n) { - kring->nr_hwtail = nm_i; - IFRATE(rate_ctx.new.rxpkt += n); - } - kring->nr_kflags &= ~NKR_PENDINTR; - } - - // XXX should we invert the order ? - /* - * Second part: skip past packets that userspace has released. + * First part: skip past packets that userspace has released. + * This can possibly make room for the second part. */ nm_i = kring->nr_hwcur; if (nm_i != head) { @@ -773,7 +1043,106 @@ generic_netmap_rxsync(struct netmap_kring *kring, int flags) } kring->nr_hwcur = head; } - IFRATE(rate_ctx.new.rxsync++); + + /* + * Second part: import newly received packets. + */ + if (!netmap_no_pendintr && !force_update) { + return 0; + } + + nm_i = kring->nr_hwtail; /* First empty slot in the receive ring. */ + + /* Compute the available space (in bytes) in this netmap ring. + * The first slot that is not considered in is the one before + * nr_hwcur. */ + + avail = nm_prev(kring->nr_hwcur, lim) - nm_i; + if (avail < 0) + avail += lim + 1; + avail *= nm_buf_len; + + /* First pass: While holding the lock on the RX mbuf queue, + * extract as many mbufs as they fit the available space, + * and put them in a temporary queue. + * To avoid performing a per-mbuf division (mlen / nm_buf_len) to + * to update avail, we do the update in a while loop that we + * also use to set the RX slots, but without performing the copy. */ + mbq_init(&tmpq); + mbq_lock(&kring->rx_queue); + for (n = 0;; n++) { + m = mbq_peek(&kring->rx_queue); + if (!m) { + /* No more packets from the driver. */ + break; + } + + mlen = MBUF_LEN(m); + if (mlen > avail) { + /* No more space in the ring. */ + break; + } + + mbq_dequeue(&kring->rx_queue); + + while (mlen) { + copy = nm_buf_len; + if (mlen < copy) { + copy = mlen; + } + mlen -= copy; + avail -= nm_buf_len; + + ring->slot[nm_i].len = copy; + ring->slot[nm_i].flags = slot_flags | (mlen ? NS_MOREFRAG : 0); + nm_i = nm_next(nm_i, lim); + } + + mbq_enqueue(&tmpq, m); + } + mbq_unlock(&kring->rx_queue); + + /* Second pass: Drain the temporary queue, going over the used RX slots, + * and perform the copy out of the RX queue lock. */ + nm_i = kring->nr_hwtail; + + for (;;) { + void *nmaddr; + int ofs = 0; + int morefrag; + + m = mbq_dequeue(&tmpq); + if (!m) { + break; + } + + do { + nmaddr = NMB(na, &ring->slot[nm_i]); + /* We only check the address here on generic rx rings. */ + if (nmaddr == NETMAP_BUF_BASE(na)) { /* Bad buffer */ + m_freem(m); + mbq_purge(&tmpq); + mbq_fini(&tmpq); + return netmap_ring_reinit(kring); + } + + copy = ring->slot[nm_i].len; + m_copydata(m, ofs, copy, nmaddr); + ofs += copy; + morefrag = ring->slot[nm_i].flags & NS_MOREFRAG; + nm_i = nm_next(nm_i, lim); + } while (morefrag); + + m_freem(m); + } + + mbq_fini(&tmpq); + + if (n) { + kring->nr_hwtail = nm_i; + IFRATE(rate_ctx.new.rxpkt += n); + } + kring->nr_kflags &= ~NKR_PENDINTR; return 0; } @@ -787,9 +1156,8 @@ generic_netmap_dtor(struct netmap_adapter *na) if (prev_na != NULL) { D("Released generic NA %p", gna); - if_rele(ifp); netmap_adapter_put(prev_na); - if (na->ifp == NULL) { + if (nm_iszombie(na)) { /* * The driver has been removed without releasing * the reference so we need to do it here. @@ -797,9 +1165,13 @@ generic_netmap_dtor(struct netmap_adapter *na) netmap_adapter_put(prev_na); } } - WNA(ifp) = prev_na; - D("Restored native NA %p", prev_na); + NM_ATTACH_NA(ifp, prev_na); + /* + * netmap_detach_common(), that it's called after this function, + * overrides WNA(ifp) if na->ifp is not NULL. + */ na->ifp = NULL; + D("Restored native NA %p", prev_na); } /* @@ -823,7 +1195,7 @@ generic_netmap_attach(struct ifnet *ifp) num_tx_desc = num_rx_desc = netmap_generic_ringsize; /* starting point */ - generic_find_num_desc(ifp, &num_tx_desc, &num_rx_desc); /* ignore errors */ + nm_os_generic_find_num_desc(ifp, &num_tx_desc, &num_rx_desc); /* ignore errors */ ND("Netmap ring size: TX = %d, RX = %d", num_tx_desc, num_rx_desc); if (num_tx_desc == 0 || num_rx_desc == 0) { D("Device has no hw slots (tx %u, rx %u)", num_tx_desc, num_rx_desc); @@ -855,12 +1227,23 @@ generic_netmap_attach(struct ifnet *ifp) ND("[GNA] num_rx_queues(%d), real_num_rx_queues(%d)", ifp->num_rx_queues, ifp->real_num_rx_queues); - generic_find_num_queues(ifp, &na->num_tx_rings, &na->num_rx_rings); + nm_os_generic_find_num_queues(ifp, &na->num_tx_rings, &na->num_rx_rings); retval = netmap_attach_common(na); if (retval) { free(gna, M_DEVBUF); + return retval; } + gna->prev = NA(ifp); /* save old na */ + if (gna->prev != NULL) { + netmap_adapter_get(gna->prev); + } + NM_ATTACH_NA(ifp, na); + + nm_os_generic_set_features(gna); + + D("Created generic NA %p (prev %p)", gna, gna->prev); + return retval; } diff --git a/sys/dev/netmap/netmap_kern.h b/sys/dev/netmap/netmap_kern.h index 4aead85285fd..28e69d7ab093 100644 --- a/sys/dev/netmap/netmap_kern.h +++ b/sys/dev/netmap/netmap_kern.h @@ -1,6 +1,7 @@ /* - * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved. - * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved. + * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo + * Copyright (C) 2013-2016 Universita` di Pisa + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -48,17 +49,27 @@ #if defined(CONFIG_NETMAP_GENERIC) #define WITH_GENERIC #endif -#if defined(CONFIG_NETMAP_V1000) -#define WITH_V1000 +#if defined(CONFIG_NETMAP_PTNETMAP_GUEST) +#define WITH_PTNETMAP_GUEST +#endif +#if defined(CONFIG_NETMAP_PTNETMAP_HOST) +#define WITH_PTNETMAP_HOST #endif -#else /* not linux */ - +#elif defined (_WIN32) #define WITH_VALE // comment out to disable VALE support #define WITH_PIPES #define WITH_MONITOR #define WITH_GENERIC +#else /* neither linux nor windows */ +#define WITH_VALE // comment out to disable VALE support +#define WITH_PIPES +#define WITH_MONITOR +#define WITH_GENERIC +#define WITH_PTNETMAP_HOST /* ptnetmap host support */ +#define WITH_PTNETMAP_GUEST /* ptnetmap guest support */ + #endif #if defined(__FreeBSD__) @@ -66,6 +77,7 @@ #define likely(x) __builtin_expect((long)!!(x), 1L) #define unlikely(x) __builtin_expect((long)!!(x), 0L) +#define __user #define NM_LOCK_T struct mtx /* low level spinlock, used to protect queues */ @@ -77,9 +89,11 @@ #define NM_MTX_ASSERT(m) sx_assert(&(m), SA_XLOCKED) #define NM_SELINFO_T struct nm_selinfo +#define NM_SELRECORD_T struct thread #define MBUF_LEN(m) ((m)->m_pkthdr.len) -#define MBUF_IFP(m) ((m)->m_pkthdr.rcvif) -#define NM_SEND_UP(ifp, m) ((NA(ifp))->if_input)(ifp, m) +#define MBUF_TXQ(m) ((m)->m_pkthdr.flowid) +#define MBUF_TRANSMIT(na, ifp, m) ((na)->if_transmit(ifp, m)) +#define GEN_TX_MBUF_IFP(m) ((m)->m_pkthdr.rcvif) #define NM_ATOMIC_T volatile int // XXX ? /* atomic operations */ @@ -98,23 +112,20 @@ struct netmap_adapter *netmap_getna(if_t ifp); #endif #if __FreeBSD_version >= 1100027 -#define GET_MBUF_REFCNT(m) ((m)->m_ext.ext_cnt ? *((m)->m_ext.ext_cnt) : -1) -#define SET_MBUF_REFCNT(m, x) *((m)->m_ext.ext_cnt) = x -#define PNT_MBUF_REFCNT(m) ((m)->m_ext.ext_cnt) +#define MBUF_REFCNT(m) ((m)->m_ext.ext_count) +#define SET_MBUF_REFCNT(m, x) (m)->m_ext.ext_count = x #else -#define GET_MBUF_REFCNT(m) ((m)->m_ext.ref_cnt ? *((m)->m_ext.ref_cnt) : -1) +#define MBUF_REFCNT(m) ((m)->m_ext.ref_cnt ? *((m)->m_ext.ref_cnt) : -1) #define SET_MBUF_REFCNT(m, x) *((m)->m_ext.ref_cnt) = x -#define PNT_MBUF_REFCNT(m) ((m)->m_ext.ref_cnt) #endif -MALLOC_DECLARE(M_NETMAP); +#define MBUF_QUEUED(m) 1 struct nm_selinfo { struct selinfo si; struct mtx m; }; -void freebsd_selwakeup(struct nm_selinfo *si, int pri); // XXX linux struct, not used in FreeBSD struct net_device_ops { @@ -131,12 +142,16 @@ struct hrtimer { #define NM_LOCK_T safe_spinlock_t // see bsd_glue.h #define NM_SELINFO_T wait_queue_head_t #define MBUF_LEN(m) ((m)->len) -#define MBUF_IFP(m) ((m)->dev) -#define NM_SEND_UP(ifp, m) \ - do { \ - m->priority = NM_MAGIC_PRIORITY_RX; \ - netif_rx(m); \ - } while (0) +#define MBUF_TRANSMIT(na, ifp, m) \ + ({ \ + /* Avoid infinite recursion with generic. */ \ + m->priority = NM_MAGIC_PRIORITY_TX; \ + (((struct net_device_ops *)(na)->if_transmit)->ndo_start_xmit(m, ifp)); \ + 0; \ + }) + +/* See explanation in nm_os_generic_xmit_frame. */ +#define GEN_TX_MBUF_IFP(m) ((struct ifnet *)skb_shinfo(m)->destructor_arg) #define NM_ATOMIC_T volatile long unsigned int @@ -159,7 +174,51 @@ struct hrtimer { #define NM_LOCK_T IOLock * #define NM_SELINFO_T struct selinfo #define MBUF_LEN(m) ((m)->m_pkthdr.len) -#define NM_SEND_UP(ifp, m) ((ifp)->if_input)(ifp, m) + +#elif defined (_WIN32) +#include "../../../WINDOWS/win_glue.h" + +#define NM_SELRECORD_T IO_STACK_LOCATION +#define NM_SELINFO_T win_SELINFO // see win_glue.h +#define NM_LOCK_T win_spinlock_t // see win_glue.h +#define NM_MTX_T KGUARDED_MUTEX /* OS-specific mutex (sleepable) */ + +#define NM_MTX_INIT(m) KeInitializeGuardedMutex(&m); +#define NM_MTX_DESTROY(m) do { (void)(m); } while (0) +#define NM_MTX_LOCK(m) KeAcquireGuardedMutex(&(m)) +#define NM_MTX_UNLOCK(m) KeReleaseGuardedMutex(&(m)) +#define NM_MTX_ASSERT(m) assert(&m.Count>0) + +//These linknames are for the NDIS driver +#define NETMAP_NDIS_LINKNAME_STRING L"\\DosDevices\\NMAPNDIS" +#define NETMAP_NDIS_NTDEVICE_STRING L"\\Device\\NMAPNDIS" + +//Definition of internal driver-to-driver ioctl codes +#define NETMAP_KERNEL_XCHANGE_POINTERS _IO('i', 180) +#define NETMAP_KERNEL_SEND_SHUTDOWN_SIGNAL _IO_direct('i', 195) + +//Empty data structures are not permitted by MSVC compiler +//XXX_ale, try to solve this problem +struct net_device_ops{ + char data[1]; +}; +typedef struct ethtool_ops{ + char data[1]; +}; +typedef struct hrtimer{ + KTIMER timer; + BOOLEAN active; + KDPC deferred_proc; +}; + +/* MSVC does not have likely/unlikely support */ +#ifdef _MSC_VER +#define likely(x) (x) +#define unlikely(x) (x) +#else +#define likely(x) __builtin_expect((long)!!(x), 1L) +#define unlikely(x) __builtin_expect((long)!!(x), 0L) +#endif //_MSC_VER #else @@ -167,6 +226,13 @@ struct hrtimer { #endif /* end - platform-specific code */ +#ifndef _WIN32 /* support for emulated sysctl */ +#define SYSBEGIN(x) +#define SYSEND +#endif /* _WIN32 */ + +#define NM_ACCESS_ONCE(x) (*(volatile __typeof__(x) *)&(x)) + #define NMG_LOCK_T NM_MTX_T #define NMG_LOCK_INIT() NM_MTX_INIT(netmap_global_lock) #define NMG_LOCK_DESTROY() NM_MTX_DESTROY(netmap_global_lock) @@ -201,8 +267,36 @@ struct nm_bdg_fwd; struct nm_bridge; struct netmap_priv_d; +/* os-specific NM_SELINFO_T initialzation/destruction functions */ +void nm_os_selinfo_init(NM_SELINFO_T *); +void nm_os_selinfo_uninit(NM_SELINFO_T *); + const char *nm_dump_buf(char *p, int len, int lim, char *dst); +void nm_os_selwakeup(NM_SELINFO_T *si); +void nm_os_selrecord(NM_SELRECORD_T *sr, NM_SELINFO_T *si); + +int nm_os_ifnet_init(void); +void nm_os_ifnet_fini(void); +void nm_os_ifnet_lock(void); +void nm_os_ifnet_unlock(void); + +void nm_os_get_module(void); +void nm_os_put_module(void); + +void netmap_make_zombie(struct ifnet *); +void netmap_undo_zombie(struct ifnet *); + +/* passes a packet up to the host stack. + * If the packet is sent (or dropped) immediately it returns NULL, + * otherwise it links the packet to prev and returns m. + * In this case, a final call with m=NULL and prev != NULL will send up + * the entire chain to the host stack. + */ +void *nm_os_send_up(struct ifnet *, struct mbuf *m, struct mbuf *prev); + +int nm_os_mbuf_has_offld(struct mbuf *m); + #include "netmap_mbq.h" extern NMG_LOCK_T netmap_global_lock; @@ -299,6 +393,19 @@ struct netmap_kring { uint32_t nr_kflags; /* private driver flags */ #define NKR_PENDINTR 0x1 // Pending interrupt. #define NKR_EXCLUSIVE 0x2 /* exclusive binding */ +#define NKR_FORWARD 0x4 /* (host ring only) there are + packets to forward + */ +#define NKR_NEEDRING 0x8 /* ring needed even if users==0 + * (used internally by pipes and + * by ptnetmap host ports) + */ + + uint32_t nr_mode; + uint32_t nr_pending_mode; +#define NKR_NETMAP_OFF 0x0 +#define NKR_NETMAP_ON 0x1 + uint32_t nkr_num_slots; /* @@ -344,13 +451,14 @@ struct netmap_kring { * store incoming mbufs in a queue that is drained by * a rxsync. */ - struct mbuf **tx_pool; - // u_int nr_ntc; /* Emulation of a next-to-clean RX ring pointer. */ - struct mbq rx_queue; /* intercepted rx mbufs. */ + struct mbuf **tx_pool; + struct mbuf *tx_event; /* TX event used as a notification */ + NM_LOCK_T tx_event_lock; /* protects the tx_event mbuf */ + struct mbq rx_queue; /* intercepted rx mbufs. */ uint32_t users; /* existing bindings for this ring */ - uint32_t ring_id; /* debugging */ + uint32_t ring_id; /* kring identifier */ enum txrx tx; /* kind of ring (tx or rx) */ char name[64]; /* diagnostic */ @@ -372,9 +480,6 @@ struct netmap_kring { struct netmap_kring *pipe; /* if this is a pipe ring, * pointer to the other end */ - struct netmap_ring *save_ring; /* pointer to hidden rings - * (see netmap_pipe.c for details) - */ #endif /* WITH_PIPES */ #ifdef WITH_VALE @@ -397,8 +502,28 @@ struct netmap_kring { uint32_t mon_tail; /* last seen slot on rx */ uint32_t mon_pos; /* index of this ring in the monitored ring array */ #endif -} __attribute__((__aligned__(64))); +} +#ifdef _WIN32 +__declspec(align(64)); +#else +__attribute__((__aligned__(64))); +#endif +/* return 1 iff the kring needs to be turned on */ +static inline int +nm_kring_pending_on(struct netmap_kring *kring) +{ + return kring->nr_pending_mode == NKR_NETMAP_ON && + kring->nr_mode == NKR_NETMAP_OFF; +} + +/* return 1 iff the kring needs to be turned off */ +static inline int +nm_kring_pending_off(struct netmap_kring *kring) +{ + return kring->nr_pending_mode == NKR_NETMAP_OFF && + kring->nr_mode == NKR_NETMAP_ON; +} /* return the next index, with wraparound */ static inline uint32_t @@ -514,6 +639,8 @@ struct netmap_adapter { */ #define NAF_HOST_RINGS 64 /* the adapter supports the host rings */ #define NAF_FORCE_NATIVE 128 /* the adapter is always NATIVE */ +#define NAF_PTNETMAP_HOST 256 /* the adapter supports ptnetmap in the host */ +#define NAF_ZOMBIE (1U<<30) /* the nic driver has been unloaded */ #define NAF_BUSY (1U<<31) /* the adapter is used internally and * cannot be registered from userspace */ @@ -592,10 +719,14 @@ struct netmap_adapter { * For hw devices this is typically a selwakeup(), * but for NIC/host ports attached to a switch (or vice-versa) * we also need to invoke the 'txsync' code downstream. + * This callback pointer is actually used only to initialize + * kring->nm_notify. + * Return values are the same as for netmap_rx_irq(). */ void (*nm_dtor)(struct netmap_adapter *); int (*nm_register)(struct netmap_adapter *, int onoff); + void (*nm_intr)(struct netmap_adapter *, int onoff); int (*nm_txsync)(struct netmap_kring *kring, int flags); int (*nm_rxsync)(struct netmap_kring *kring, int flags); @@ -640,14 +771,14 @@ struct netmap_adapter { /* memory allocator (opaque) * We also cache a pointer to the lut_entry for translating - * buffer addresses, and the total number of buffers. + * buffer addresses, the total number of buffers and the buffer size. */ struct netmap_mem_d *nm_mem; struct netmap_lut na_lut; /* additional information attached to this adapter * by other netmap subsystems. Currently used by - * bwrap and LINUX/v1000. + * bwrap, LINUX/v1000 and ptnetmap */ void *na_private; @@ -656,6 +787,9 @@ struct netmap_adapter { int na_next_pipe; /* next free slot in the array */ int na_max_pipes; /* size of the array */ + /* Offset of ethernet header for each packet. */ + u_int virt_hdr_len; + char name[64]; }; @@ -721,8 +855,6 @@ struct netmap_vp_adapter { /* VALE software port */ struct nm_bridge *na_bdg; int retry; - /* Offset of ethernet header for each packet. */ - u_int virt_hdr_len; /* Maximum Frame Size, used in bdg_mismatch_datapath() */ u_int mfs; /* Last source MAC on this port */ @@ -767,6 +899,13 @@ struct netmap_generic_adapter { /* emulated device */ #ifdef linux netdev_tx_t (*save_start_xmit)(struct mbuf *, struct ifnet *); #endif + /* Is the adapter able to use multiple RX slots to scatter + * each packet pushed up by the driver? */ + int rxsg; + + /* Is the transmission path controlled by a netmap-aware + * device queue (i.e. qdisc on linux)? */ + int txqdisc; }; #endif /* WITH_GENERIC */ @@ -777,7 +916,7 @@ netmap_real_rings(struct netmap_adapter *na, enum txrx t) } #ifdef WITH_VALE - +struct nm_bdg_polling_state; /* * Bridge wrapper for non VALE ports attached to a VALE switch. * @@ -827,9 +966,6 @@ struct netmap_bwrap_adapter { struct netmap_vp_adapter host; /* for host rings */ struct netmap_adapter *hwna; /* the underlying device */ - /* backup of the hwna memory allocator */ - struct netmap_mem_d *save_nmd; - /* * When we attach a physical interface to the bridge, we * allow the controlling process to terminate, so we need @@ -838,10 +974,10 @@ struct netmap_bwrap_adapter { * are attached to a bridge. */ struct netmap_priv_d *na_kpriv; + struct nm_bdg_polling_state *na_polling_state; }; int netmap_bwrap_attach(const char *name, struct netmap_adapter *); - #endif /* WITH_VALE */ #ifdef WITH_PIPES @@ -876,56 +1012,122 @@ nm_kr_rxspace(struct netmap_kring *k) return space; } +/* return slots reserved to tx clients */ +#define nm_kr_txspace(_k) nm_kr_rxspace(_k) -/* True if no space in the tx ring. only valid after txsync_prologue */ + +/* True if no space in the tx ring, only valid after txsync_prologue */ static inline int nm_kr_txempty(struct netmap_kring *kring) { return kring->rcur == kring->nr_hwtail; } +/* True if no more completed slots in the rx ring, only valid after + * rxsync_prologue */ +#define nm_kr_rxempty(_k) nm_kr_txempty(_k) /* * protect against multiple threads using the same ring. - * also check that the ring has not been stopped. - * We only care for 0 or !=0 as a return code. + * also check that the ring has not been stopped or locked */ -#define NM_KR_BUSY 1 -#define NM_KR_STOPPED 2 +#define NM_KR_BUSY 1 /* some other thread is syncing the ring */ +#define NM_KR_STOPPED 2 /* unbounded stop (ifconfig down or driver unload) */ +#define NM_KR_LOCKED 3 /* bounded, brief stop for mutual exclusion */ +/* release the previously acquired right to use the *sync() methods of the ring */ static __inline void nm_kr_put(struct netmap_kring *kr) { NM_ATOMIC_CLEAR(&kr->nr_busy); } -static __inline int nm_kr_tryget(struct netmap_kring *kr) +/* true if the ifp that backed the adapter has disappeared (e.g., the + * driver has been unloaded) + */ +static inline int nm_iszombie(struct netmap_adapter *na); + +/* try to obtain exclusive right to issue the *sync() operations on the ring. + * The right is obtained and must be later relinquished via nm_kr_put() if and + * only if nm_kr_tryget() returns 0. + * If can_sleep is 1 there are only two other possible outcomes: + * - the function returns NM_KR_BUSY + * - the function returns NM_KR_STOPPED and sets the POLLERR bit in *perr + * (if non-null) + * In both cases the caller will typically skip the ring, possibly collecting + * errors along the way. + * If the calling context does not allow sleeping, the caller must pass 0 in can_sleep. + * In the latter case, the function may also return NM_KR_LOCKED and leave *perr + * untouched: ideally, the caller should try again at a later time. + */ +static __inline int nm_kr_tryget(struct netmap_kring *kr, int can_sleep, int *perr) { + int busy = 1, stopped; /* check a first time without taking the lock * to avoid starvation for nm_kr_get() */ - if (unlikely(kr->nkr_stopped)) { - ND("ring %p stopped (%d)", kr, kr->nkr_stopped); - return NM_KR_STOPPED; +retry: + stopped = kr->nkr_stopped; + if (unlikely(stopped)) { + goto stop; } - if (unlikely(NM_ATOMIC_TEST_AND_SET(&kr->nr_busy))) - return NM_KR_BUSY; - /* check a second time with lock held */ - if (unlikely(kr->nkr_stopped)) { - ND("ring %p stopped (%d)", kr, kr->nkr_stopped); + busy = NM_ATOMIC_TEST_AND_SET(&kr->nr_busy); + /* we should not return NM_KR_BUSY if the ring was + * actually stopped, so check another time after + * the barrier provided by the atomic operation + */ + stopped = kr->nkr_stopped; + if (unlikely(stopped)) { + goto stop; + } + + if (unlikely(nm_iszombie(kr->na))) { + stopped = NM_KR_STOPPED; + goto stop; + } + + return unlikely(busy) ? NM_KR_BUSY : 0; + +stop: + if (!busy) nm_kr_put(kr); - return NM_KR_STOPPED; + if (stopped == NM_KR_STOPPED) { +/* if POLLERR is defined we want to use it to simplify netmap_poll(). + * Otherwise, any non-zero value will do. + */ +#ifdef POLLERR +#define NM_POLLERR POLLERR +#else +#define NM_POLLERR 1 +#endif /* POLLERR */ + if (perr) + *perr |= NM_POLLERR; +#undef NM_POLLERR + } else if (can_sleep) { + tsleep(kr, 0, "NM_KR_TRYGET", 4); + goto retry; } - return 0; + return stopped; } -static __inline void nm_kr_get(struct netmap_kring *kr) +/* put the ring in the 'stopped' state and wait for the current user (if any) to + * notice. stopped must be either NM_KR_STOPPED or NM_KR_LOCKED + */ +static __inline void nm_kr_stop(struct netmap_kring *kr, int stopped) { + kr->nkr_stopped = stopped; while (NM_ATOMIC_TEST_AND_SET(&kr->nr_busy)) tsleep(kr, 0, "NM_KR_GET", 4); } +/* restart a ring after a stop */ +static __inline void nm_kr_start(struct netmap_kring *kr) +{ + kr->nkr_stopped = 0; + nm_kr_put(kr); +} + /* * The following functions are used by individual drivers to @@ -953,10 +1155,26 @@ struct netmap_slot *netmap_reset(struct netmap_adapter *na, enum txrx tx, u_int n, u_int new_cur); int netmap_ring_reinit(struct netmap_kring *); +/* Return codes for netmap_*x_irq. */ +enum { + /* Driver should do normal interrupt processing, e.g. because + * the interface is not in netmap mode. */ + NM_IRQ_PASS = 0, + /* Port is in netmap mode, and the interrupt work has been + * completed. The driver does not have to notify netmap + * again before the next interrupt. */ + NM_IRQ_COMPLETED = -1, + /* Port is in netmap mode, but the interrupt work has not been + * completed. The driver has to make sure netmap will be + * notified again soon, even if no more interrupts come (e.g. + * on Linux the driver should not call napi_complete()). */ + NM_IRQ_RESCHED = -2, +}; + /* default functions to handle rx/tx interrupts */ int netmap_rx_irq(struct ifnet *, u_int, u_int *); #define netmap_tx_irq(_n, _q) netmap_rx_irq(_n, _q, NULL) -void netmap_common_irq(struct ifnet *, u_int, u_int *work_done); +int netmap_common_irq(struct netmap_adapter *, u_int, u_int *work_done); #ifdef WITH_VALE @@ -986,35 +1204,74 @@ nm_native_on(struct netmap_adapter *na) return nm_netmap_on(na) && (na->na_flags & NAF_NATIVE); } +static inline int +nm_iszombie(struct netmap_adapter *na) +{ + return na == NULL || (na->na_flags & NAF_ZOMBIE); +} + +static inline void +nm_update_hostrings_mode(struct netmap_adapter *na) +{ + /* Process nr_mode and nr_pending_mode for host rings. */ + na->tx_rings[na->num_tx_rings].nr_mode = + na->tx_rings[na->num_tx_rings].nr_pending_mode; + na->rx_rings[na->num_rx_rings].nr_mode = + na->rx_rings[na->num_rx_rings].nr_pending_mode; +} + /* set/clear native flags and if_transmit/netdev_ops */ static inline void nm_set_native_flags(struct netmap_adapter *na) { struct ifnet *ifp = na->ifp; + /* We do the setup for intercepting packets only if we are the + * first user of this adapapter. */ + if (na->active_fds > 0) { + return; + } + na->na_flags |= NAF_NETMAP_ON; #ifdef IFCAP_NETMAP /* or FreeBSD ? */ ifp->if_capenable |= IFCAP_NETMAP; #endif -#ifdef __FreeBSD__ +#if defined (__FreeBSD__) na->if_transmit = ifp->if_transmit; ifp->if_transmit = netmap_transmit; +#elif defined (_WIN32) + (void)ifp; /* prevent a warning */ + //XXX_ale can we just comment those? + //na->if_transmit = ifp->if_transmit; + //ifp->if_transmit = netmap_transmit; #else na->if_transmit = (void *)ifp->netdev_ops; ifp->netdev_ops = &((struct netmap_hw_adapter *)na)->nm_ndo; ((struct netmap_hw_adapter *)na)->save_ethtool = ifp->ethtool_ops; ifp->ethtool_ops = &((struct netmap_hw_adapter*)na)->nm_eto; #endif + nm_update_hostrings_mode(na); } - static inline void nm_clear_native_flags(struct netmap_adapter *na) { struct ifnet *ifp = na->ifp; -#ifdef __FreeBSD__ + /* We undo the setup for intercepting packets only if we are the + * last user of this adapapter. */ + if (na->active_fds > 0) { + return; + } + + nm_update_hostrings_mode(na); + +#if defined(__FreeBSD__) ifp->if_transmit = na->if_transmit; +#elif defined(_WIN32) + (void)ifp; /* prevent a warning */ + //XXX_ale can we just comment those? + //ifp->if_transmit = na->if_transmit; #else ifp->netdev_ops = (void *)na->if_transmit; ifp->ethtool_ops = ((struct netmap_hw_adapter*)na)->save_ethtool; @@ -1025,6 +1282,28 @@ nm_clear_native_flags(struct netmap_adapter *na) #endif } +/* + * nm_*sync_prologue() functions are used in ioctl/poll and ptnetmap + * kthreads. + * We need netmap_ring* parameter, because in ptnetmap it is decoupled + * from host kring. + * The user-space ring pointers (head/cur/tail) are shared through + * CSB between host and guest. + */ + +/* + * validates parameters in the ring/kring, returns a value for head + * If any error, returns ring_size to force a reinit. + */ +uint32_t nm_txsync_prologue(struct netmap_kring *, struct netmap_ring *); + + +/* + * validates parameters in the ring/kring, returns a value for head + * If any error, returns ring_size lim to force a reinit. + */ +uint32_t nm_rxsync_prologue(struct netmap_kring *, struct netmap_ring *); + /* check/fix address and len in tx rings */ #if 1 /* debug version */ @@ -1080,6 +1359,9 @@ int netmap_krings_create(struct netmap_adapter *na, u_int tailroom); */ void netmap_krings_delete(struct netmap_adapter *na); +int netmap_hw_krings_create(struct netmap_adapter *na); +void netmap_hw_krings_delete(struct netmap_adapter *na); + /* set the stopped/enabled status of ring * When stopping, they also wait for all current activity on the ring to * terminate. The status change is then notified using the na nm_notify @@ -1088,16 +1370,18 @@ void netmap_krings_delete(struct netmap_adapter *na); void netmap_set_ring(struct netmap_adapter *, u_int ring_id, enum txrx, int stopped); /* set the stopped/enabled status of all rings of the adapter. */ void netmap_set_all_rings(struct netmap_adapter *, int stopped); -/* convenience wrappers for netmap_set_all_rings, used in drivers */ +/* convenience wrappers for netmap_set_all_rings */ void netmap_disable_all_rings(struct ifnet *); void netmap_enable_all_rings(struct ifnet *); int netmap_do_regif(struct netmap_priv_d *priv, struct netmap_adapter *na, uint16_t ringid, uint32_t flags); - +void netmap_do_unregif(struct netmap_priv_d *priv); u_int nm_bound_var(u_int *v, u_int dflt, u_int lo, u_int hi, const char *msg); -int netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, int create); +int netmap_get_na(struct nmreq *nmr, struct netmap_adapter **na, + struct ifnet **ifp, int create); +void netmap_unget_na(struct netmap_adapter *na, struct ifnet *ifp); int netmap_get_hw_na(struct ifnet *ifp, struct netmap_adapter **na); @@ -1124,12 +1408,11 @@ struct netmap_bdg_ops { u_int netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring, struct netmap_vp_adapter *); +#define NM_BRIDGES 8 /* number of bridges */ #define NM_BDG_MAXPORTS 254 /* up to 254 */ #define NM_BDG_BROADCAST NM_BDG_MAXPORTS #define NM_BDG_NOPORT (NM_BDG_MAXPORTS+1) -#define NM_NAME "vale" /* prefix for bridge port name */ - /* these are redefined in case of no VALE support */ int netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create); struct nm_bridge *netmap_init_bridges2(u_int); @@ -1181,14 +1464,13 @@ void netmap_bns_getbridges(struct nm_bridge **, u_int *); #endif /* Various prototypes */ -int netmap_poll(struct cdev *dev, int events, struct thread *td); +int netmap_poll(struct netmap_priv_d *, int events, NM_SELRECORD_T *td); int netmap_init(void); void netmap_fini(void); int netmap_get_memory(struct netmap_priv_d* p); void netmap_dtor(void *data); -int netmap_dtor_locked(struct netmap_priv_d *priv); -int netmap_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td); +int netmap_ioctl(struct netmap_priv_d *priv, u_long cmd, caddr_t data, struct thread *); /* netmap_adapter creation/destruction */ @@ -1228,11 +1510,11 @@ int netmap_adapter_put(struct netmap_adapter *na); /* * module variables */ -#define NETMAP_BUF_BASE(na) ((na)->na_lut.lut[0].vaddr) -#define NETMAP_BUF_SIZE(na) ((na)->na_lut.objsize) -extern int netmap_mitigate; // XXX not really used +#define NETMAP_BUF_BASE(_na) ((_na)->na_lut.lut[0].vaddr) +#define NETMAP_BUF_SIZE(_na) ((_na)->na_lut.objsize) extern int netmap_no_pendintr; -extern int netmap_verbose; // XXX debugging +extern int netmap_mitigate; +extern int netmap_verbose; /* for debugging */ enum { /* verbose flags */ NM_VERB_ON = 1, /* generic verbose */ NM_VERB_HOST = 0x2, /* verbose host stack */ @@ -1245,10 +1527,11 @@ enum { /* verbose flags */ }; extern int netmap_txsync_retry; +extern int netmap_flags; extern int netmap_generic_mit; extern int netmap_generic_ringsize; extern int netmap_generic_rings; -extern int netmap_use_count; +extern int netmap_generic_txqdisc; /* * NA returns a pointer to the struct netmap adapter from the ifp, @@ -1257,37 +1540,27 @@ extern int netmap_use_count; #define NA(_ifp) ((struct netmap_adapter *)WNA(_ifp)) /* - * Macros to determine if an interface is netmap capable or netmap enabled. - * See the magic field in struct netmap_adapter. - */ -#ifdef __FreeBSD__ -/* - * on FreeBSD just use if_capabilities and if_capenable. - */ -#define NETMAP_CAPABLE(ifp) (NA(ifp) && \ - (ifp)->if_capabilities & IFCAP_NETMAP ) - -#define NETMAP_SET_CAPABLE(ifp) \ - (ifp)->if_capabilities |= IFCAP_NETMAP - -#else /* linux */ - -/* - * on linux: - * we check if NA(ifp) is set and its first element has a related + * On old versions of FreeBSD, NA(ifp) is a pspare. On linux we + * overload another pointer in the netdev. + * + * We check if NA(ifp) is set and its first element has a related * magic value. The capenable is within the struct netmap_adapter. */ #define NETMAP_MAGIC 0x52697a7a -#define NETMAP_CAPABLE(ifp) (NA(ifp) && \ +#define NM_NA_VALID(ifp) (NA(ifp) && \ ((uint32_t)(uintptr_t)NA(ifp) ^ NA(ifp)->magic) == NETMAP_MAGIC ) -#define NETMAP_SET_CAPABLE(ifp) \ - NA(ifp)->magic = ((uint32_t)(uintptr_t)NA(ifp)) ^ NETMAP_MAGIC +#define NM_ATTACH_NA(ifp, na) do { \ + WNA(ifp) = na; \ + if (NA(ifp)) \ + NA(ifp)->magic = \ + ((uint32_t)(uintptr_t)NA(ifp)) ^ NETMAP_MAGIC; \ +} while(0) -#endif /* linux */ +#define NM_IS_NATIVE(ifp) (NM_NA_VALID(ifp) && NA(ifp)->nm_dtor == netmap_hw_dtor) -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) /* Assigns the device IOMMU domain to an allocator. * Returns -ENOMEM in case the domain is different */ @@ -1331,6 +1604,8 @@ netmap_reload_map(struct netmap_adapter *na, } } +#elif defined(_WIN32) + #else /* linux */ int nm_iommu_group_id(bus_dma_tag_t dev); @@ -1341,8 +1616,8 @@ netmap_load_map(struct netmap_adapter *na, bus_dma_tag_t tag, bus_dmamap_t map, void *buf) { if (0 && map) { - *map = dma_map_single(na->pdev, buf, na->na_lut.objsize, - DMA_BIDIRECTIONAL); + *map = dma_map_single(na->pdev, buf, NETMAP_BUF_SIZE(na), + DMA_BIDIRECTIONAL); } } @@ -1350,11 +1625,11 @@ static inline void netmap_unload_map(struct netmap_adapter *na, bus_dma_tag_t tag, bus_dmamap_t map) { - u_int sz = na->na_lut.objsize; + u_int sz = NETMAP_BUF_SIZE(na); if (*map) { dma_unmap_single(na->pdev, *map, sz, - DMA_BIDIRECTIONAL); + DMA_BIDIRECTIONAL); } } @@ -1362,7 +1637,7 @@ static inline void netmap_reload_map(struct netmap_adapter *na, bus_dma_tag_t tag, bus_dmamap_t map, void *buf) { - u_int sz = na->na_lut.objsize; + u_int sz = NETMAP_BUF_SIZE(na); if (*map) { dma_unmap_single(na->pdev, *map, sz, @@ -1473,7 +1748,11 @@ PNMB(struct netmap_adapter *na, struct netmap_slot *slot, uint64_t *pp) struct lut_entry *lut = na->na_lut.lut; void *ret = (i >= na->na_lut.objtotal) ? lut[0].vaddr : lut[i].vaddr; +#ifndef _WIN32 *pp = (i >= na->na_lut.objtotal) ? lut[0].paddr : lut[i].paddr; +#else + *pp = (i >= na->na_lut.objtotal) ? (uint64_t)lut[0].paddr.QuadPart : (uint64_t)lut[i].paddr.QuadPart; +#endif return ret; } @@ -1497,8 +1776,9 @@ struct netmap_priv_d { struct netmap_if * volatile np_nifp; /* netmap if descriptor. */ struct netmap_adapter *np_na; + struct ifnet *np_ifp; uint32_t np_flags; /* from the ioctl */ - u_int np_qfirst[NR_TXRX], + u_int np_qfirst[NR_TXRX], np_qlast[NR_TXRX]; /* range of tx/rx rings to scan */ uint16_t np_txpoll; /* XXX and also np_rxpoll ? */ @@ -1512,6 +1792,26 @@ struct netmap_priv_d { struct thread *np_td; /* kqueue, just debugging */ }; +struct netmap_priv_d *netmap_priv_new(void); +void netmap_priv_delete(struct netmap_priv_d *); + +static inline int nm_kring_pending(struct netmap_priv_d *np) +{ + struct netmap_adapter *na = np->np_na; + enum txrx t; + int i; + + for_rx_tx(t) { + for (i = np->np_qfirst[t]; i < np->np_qlast[t]; i++) { + struct netmap_kring *kring = &NMR(na, t)[i]; + if (kring->nr_mode != kring->nr_pending_mode) { + return 1; + } + } + } + return 0; +} + #ifdef WITH_MONITOR struct netmap_monitor_adapter { @@ -1530,13 +1830,36 @@ struct netmap_monitor_adapter { * native netmap support. */ int generic_netmap_attach(struct ifnet *ifp); +int generic_rx_handler(struct ifnet *ifp, struct mbuf *m);; + +int nm_os_catch_rx(struct netmap_generic_adapter *gna, int intercept); +int nm_os_catch_tx(struct netmap_generic_adapter *gna, int intercept); + +/* + * the generic transmit routine is passed a structure to optionally + * build a queue of descriptors, in an OS-specific way. + * The payload is at addr, if non-null, and the routine should send or queue + * the packet, returning 0 if successful, 1 on failure. + * + * At the end, if head is non-null, there will be an additional call + * to the function with addr = NULL; this should tell the OS-specific + * routine to send the queue and free any resources. Failure is ignored. + */ +struct nm_os_gen_arg { + struct ifnet *ifp; + void *m; /* os-specific mbuf-like object */ + void *head, *tail; /* tailq, if the OS-specific routine needs to build one */ + void *addr; /* payload of current packet */ + u_int len; /* packet length */ + u_int ring_nr; /* packet length */ + u_int qevent; /* in txqdisc mode, place an event on this mbuf */ +}; + +int nm_os_generic_xmit_frame(struct nm_os_gen_arg *); +int nm_os_generic_find_num_desc(struct ifnet *ifp, u_int *tx, u_int *rx); +void nm_os_generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq); +void nm_os_generic_set_features(struct netmap_generic_adapter *gna); -int netmap_catch_rx(struct netmap_generic_adapter *na, int intercept); -void generic_rx_handler(struct ifnet *ifp, struct mbuf *m);; -void netmap_catch_tx(struct netmap_generic_adapter *na, int enable); -int generic_xmit_frame(struct ifnet *ifp, struct mbuf *m, void *addr, u_int len, u_int ring_nr); -int generic_find_num_desc(struct ifnet *ifp, u_int *tx, u_int *rx); -void generic_find_num_queues(struct ifnet *ifp, u_int *txq, u_int *rxq); static inline struct ifnet* netmap_generic_getifp(struct netmap_generic_adapter *gna) { @@ -1546,6 +1869,8 @@ netmap_generic_getifp(struct netmap_generic_adapter *gna) return gna->up.up.ifp; } +void netmap_generic_irq(struct netmap_adapter *na, u_int q, u_int *work_done); + //#define RATE_GENERIC /* Enables communication statistics for generic. */ #ifdef RATE_GENERIC void generic_rate(int txp, int txs, int txi, int rxp, int rxs, int rxi); @@ -1558,16 +1883,16 @@ void generic_rate(int txp, int txs, int txi, int rxp, int rxs, int rxi); * to reduce the number of interrupt requests/selwakeup * to clients on incoming packets. */ -void netmap_mitigation_init(struct nm_generic_mit *mit, int idx, +void nm_os_mitigation_init(struct nm_generic_mit *mit, int idx, struct netmap_adapter *na); -void netmap_mitigation_start(struct nm_generic_mit *mit); -void netmap_mitigation_restart(struct nm_generic_mit *mit); -int netmap_mitigation_active(struct nm_generic_mit *mit); -void netmap_mitigation_cleanup(struct nm_generic_mit *mit); +void nm_os_mitigation_start(struct nm_generic_mit *mit); +void nm_os_mitigation_restart(struct nm_generic_mit *mit); +int nm_os_mitigation_active(struct nm_generic_mit *mit); +void nm_os_mitigation_cleanup(struct nm_generic_mit *mit); +#else /* !WITH_GENERIC */ +#define generic_netmap_attach(ifp) (EOPNOTSUPP) #endif /* WITH_GENERIC */ - - /* Shared declarations for the VALE switch. */ /* @@ -1656,22 +1981,111 @@ struct nm_ipv6hdr { */ #define rawsum_t uint32_t -rawsum_t nm_csum_raw(uint8_t *data, size_t len, rawsum_t cur_sum); -uint16_t nm_csum_ipv4(struct nm_iphdr *iph); -void nm_csum_tcpudp_ipv4(struct nm_iphdr *iph, void *data, +rawsum_t nm_os_csum_raw(uint8_t *data, size_t len, rawsum_t cur_sum); +uint16_t nm_os_csum_ipv4(struct nm_iphdr *iph); +void nm_os_csum_tcpudp_ipv4(struct nm_iphdr *iph, void *data, size_t datalen, uint16_t *check); -void nm_csum_tcpudp_ipv6(struct nm_ipv6hdr *ip6h, void *data, +void nm_os_csum_tcpudp_ipv6(struct nm_ipv6hdr *ip6h, void *data, size_t datalen, uint16_t *check); -uint16_t nm_csum_fold(rawsum_t cur_sum); +uint16_t nm_os_csum_fold(rawsum_t cur_sum); void bdg_mismatch_datapath(struct netmap_vp_adapter *na, struct netmap_vp_adapter *dst_na, - struct nm_bdg_fwd *ft_p, struct netmap_ring *ring, + const struct nm_bdg_fwd *ft_p, + struct netmap_ring *dst_ring, u_int *j, u_int lim, u_int *howmany); /* persistent virtual port routines */ -int nm_vi_persist(const char *, struct ifnet **); -void nm_vi_detach(struct ifnet *); -void nm_vi_init_index(void); +int nm_os_vi_persist(const char *, struct ifnet **); +void nm_os_vi_detach(struct ifnet *); +void nm_os_vi_init_index(void); + +/* + * kernel thread routines + */ +struct nm_kthread; /* OS-specific kthread - opaque */ +typedef void (*nm_kthread_worker_fn_t)(void *data); + +/* kthread configuration */ +struct nm_kthread_cfg { + long type; /* kthread type/identifier */ + struct ptnet_ring_cfg event; /* event/ioctl fd */ + nm_kthread_worker_fn_t worker_fn; /* worker function */ + void *worker_private;/* worker parameter */ + int attach_user; /* attach kthread to user process */ +}; +/* kthread configuration */ +struct nm_kthread *nm_os_kthread_create(struct nm_kthread_cfg *cfg); +int nm_os_kthread_start(struct nm_kthread *); +void nm_os_kthread_stop(struct nm_kthread *); +void nm_os_kthread_delete(struct nm_kthread *); +void nm_os_kthread_wakeup_worker(struct nm_kthread *nmk); +void nm_os_kthread_send_irq(struct nm_kthread *); +void nm_os_kthread_set_affinity(struct nm_kthread *, int); +u_int nm_os_ncpus(void); + +#ifdef WITH_PTNETMAP_HOST +/* + * netmap adapter for host ptnetmap ports + */ +struct netmap_pt_host_adapter { + struct netmap_adapter up; + + struct netmap_adapter *parent; + int (*parent_nm_notify)(struct netmap_kring *kring, int flags); + void *ptns; +}; +/* ptnetmap HOST routines */ +int netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na, int create); +int ptnetmap_ctl(struct nmreq *nmr, struct netmap_adapter *na); +static inline int +nm_ptnetmap_host_on(struct netmap_adapter *na) +{ + return na && na->na_flags & NAF_PTNETMAP_HOST; +} +#else /* !WITH_PTNETMAP_HOST */ +#define netmap_get_pt_host_na(nmr, _2, _3) \ + ((nmr)->nr_flags & (NR_PTNETMAP_HOST) ? EOPNOTSUPP : 0) +#define ptnetmap_ctl(_1, _2) EINVAL +#define nm_ptnetmap_host_on(_1) EINVAL +#endif /* !WITH_PTNETMAP_HOST */ + +#ifdef WITH_PTNETMAP_GUEST +/* ptnetmap GUEST routines */ + +typedef uint32_t (*nm_pt_guest_ptctl_t)(struct ifnet *, uint32_t); + +/* + * netmap adapter for guest ptnetmap ports + */ +struct netmap_pt_guest_adapter { + /* The netmap adapter to be used by netmap applications. + * This field must be the first, to allow upcast. */ + struct netmap_hw_adapter hwup; + + /* The netmap adapter to be used by the driver. */ + struct netmap_hw_adapter dr; + + void *csb; + + /* Reference counter to track users of backend netmap port: the + * network stack and netmap clients. + * Used to decide when we need (de)allocate krings/rings and + * start (stop) ptnetmap kthreads. */ + int backend_regifs; + +}; + +int netmap_pt_guest_attach(struct netmap_adapter *, void *, + unsigned int, nm_pt_guest_ptctl_t); +struct ptnet_ring; +bool netmap_pt_guest_txsync(struct ptnet_ring *ptring, struct netmap_kring *kring, + int flags); +bool netmap_pt_guest_rxsync(struct ptnet_ring *ptring, struct netmap_kring *kring, + int flags); +int ptnet_nm_krings_create(struct netmap_adapter *na); +void ptnet_nm_krings_delete(struct netmap_adapter *na); +void ptnet_nm_dtor(struct netmap_adapter *na); +#endif /* WITH_PTNETMAP_GUEST */ #endif /* _NET_NETMAP_KERN_H_ */ diff --git a/sys/dev/netmap/netmap_mbq.c b/sys/dev/netmap/netmap_mbq.c index 503f5a13aa95..3eb971b74561 100644 --- a/sys/dev/netmap/netmap_mbq.c +++ b/sys/dev/netmap/netmap_mbq.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013-2014 Vincenzo Maffione. All rights reserved. + * Copyright (C) 2013-2014 Vincenzo Maffione + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,6 +31,8 @@ #ifdef linux #include "bsd_glue.h" +#elif defined (_WIN32) +#include "win_glue.h" #else /* __FreeBSD__ */ #include #include @@ -152,12 +155,12 @@ void mbq_safe_purge(struct mbq *q) } -void mbq_safe_destroy(struct mbq *q) +void mbq_safe_fini(struct mbq *q) { mtx_destroy(&q->lock); } -void mbq_destroy(struct mbq *q) +void mbq_fini(struct mbq *q) { } diff --git a/sys/dev/netmap/netmap_mbq.h b/sys/dev/netmap/netmap_mbq.h index 455ca8a2c3ac..9dafa8b1149b 100644 --- a/sys/dev/netmap/netmap_mbq.h +++ b/sys/dev/netmap/netmap_mbq.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013-2014 Vincenzo Maffione. All rights reserved. + * Copyright (C) 2013-2014 Vincenzo Maffione + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -40,6 +41,8 @@ /* XXX probably rely on a previous definition of SPINLOCK_T */ #ifdef linux #define SPINLOCK_T safe_spinlock_t +#elif defined (_WIN32) +#define SPINLOCK_T win_spinlock_t #else #define SPINLOCK_T struct mtx #endif @@ -52,16 +55,21 @@ struct mbq { SPINLOCK_T lock; }; -/* XXX "destroy" does not match "init" as a name. - * We should also clarify whether init can be used while +/* We should clarify whether init can be used while * holding a lock, and whether mbq_safe_destroy() is a NOP. */ void mbq_init(struct mbq *q); -void mbq_destroy(struct mbq *q); +void mbq_fini(struct mbq *q); void mbq_enqueue(struct mbq *q, struct mbuf *m); struct mbuf *mbq_dequeue(struct mbq *q); void mbq_purge(struct mbq *q); +static inline struct mbuf * +mbq_peek(struct mbq *q) +{ + return q->head ? q->head : NULL; +} + static inline void mbq_lock(struct mbq *q) { @@ -76,7 +84,7 @@ mbq_unlock(struct mbq *q) void mbq_safe_init(struct mbq *q); -void mbq_safe_destroy(struct mbq *q); +void mbq_safe_fini(struct mbq *q); void mbq_safe_enqueue(struct mbq *q, struct mbuf *m); struct mbuf *mbq_safe_dequeue(struct mbq *q); void mbq_safe_purge(struct mbq *q); diff --git a/sys/dev/netmap/netmap_mem2.c b/sys/dev/netmap/netmap_mem2.c index fd0c06bb8b57..bb0f9c8b6f39 100644 --- a/sys/dev/netmap/netmap_mem2.c +++ b/sys/dev/netmap/netmap_mem2.c @@ -1,5 +1,8 @@ /* - * Copyright (C) 2012-2014 Matteo Landi, Luigi Rizzo, Giuseppe Lettieri. All rights reserved. + * Copyright (C) 2012-2014 Matteo Landi + * Copyright (C) 2012-2016 Luigi Rizzo + * Copyright (C) 2012-2016 Giuseppe Lettieri + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include /* MALLOC_DEFINE */ #include #include /* vtophys */ #include /* vtophys */ @@ -48,13 +52,26 @@ __FBSDID("$FreeBSD$"); #include #include /* bus_dmamap_* */ +/* M_NETMAP only used in here */ +MALLOC_DECLARE(M_NETMAP); +MALLOC_DEFINE(M_NETMAP, "netmap", "Network memory map"); + #endif /* __FreeBSD__ */ +#ifdef _WIN32 +#include +#endif + #include #include +#include #include "netmap_mem2.h" -#define NETMAP_BUF_MAX_NUM 20*4096*2 /* large machine */ +#ifdef _WIN32_USE_SMALL_GENERIC_DEVICES_MEMORY +#define NETMAP_BUF_MAX_NUM 8*4096 /* if too big takes too much time to allocate */ +#else +#define NETMAP_BUF_MAX_NUM 20*4096*2 /* large machine */ +#endif #define NETMAP_POOL_MAX_NAMSZ 32 @@ -111,7 +128,7 @@ struct netmap_obj_pool { struct netmap_mem_ops { - void (*nmd_get_lut)(struct netmap_mem_d *, struct netmap_lut*); + int (*nmd_get_lut)(struct netmap_mem_d *, struct netmap_lut*); int (*nmd_get_info)(struct netmap_mem_d *, u_int *size, u_int *memflags, uint16_t *id); @@ -130,6 +147,39 @@ struct netmap_mem_ops { typedef uint16_t nm_memid_t; +/* + * Shared info for netmap allocator + * + * Each allocator contains this structur as first netmap_if. + * In this way, we can share same details about allocator + * to the VM. + * Used in ptnetmap. + */ +struct netmap_mem_shared_info { +#ifndef _WIN32 + struct netmap_if up; /* ends with a 0-sized array, which VSC does not like */ +#else /* !_WIN32 */ + char up[sizeof(struct netmap_if)]; +#endif /* !_WIN32 */ + uint64_t features; +#define NMS_FEAT_BUF_POOL 0x0001 +#define NMS_FEAT_MEMSIZE 0x0002 + + uint32_t buf_pool_offset; + uint32_t buf_pool_objtotal; + uint32_t buf_pool_objsize; + uint32_t totalsize; +}; + +#define NMS_NAME "nms_info" +#define NMS_VERSION 1 +static const struct netmap_if nms_if_blueprint = { + .ni_name = NMS_NAME, + .ni_version = NMS_VERSION, + .ni_tx_rings = 0, + .ni_rx_rings = 0 +}; + struct netmap_mem_d { NMA_LOCK_T nm_mtx; /* protect the allocator */ u_int nm_totalsize; /* shorthand */ @@ -151,6 +201,9 @@ struct netmap_mem_d { struct netmap_mem_ops *ops; }; +/* + * XXX need to fix the case of t0 == void + */ #define NMD_DEFCB(t0, name) \ t0 \ netmap_mem_##name(struct netmap_mem_d *nmd) \ @@ -186,7 +239,7 @@ netmap_mem_##name(struct netmap_adapter *na, t1 a1) \ return na->nm_mem->ops->nmd_##name(na, a1); \ } -NMD_DEFCB1(void, get_lut, struct netmap_lut *); +NMD_DEFCB1(int, get_lut, struct netmap_lut *); NMD_DEFCB3(int, get_info, u_int *, u_int *, uint16_t *); NMD_DEFCB1(vm_paddr_t, ofstophys, vm_ooffset_t); static int netmap_mem_config(struct netmap_mem_d *); @@ -201,7 +254,7 @@ NMD_DEFNACB(void, rings_delete); static int netmap_mem_map(struct netmap_obj_pool *, struct netmap_adapter *); static int netmap_mem_unmap(struct netmap_obj_pool *, struct netmap_adapter *); -static int nm_mem_assign_group(struct netmap_mem_d *, device_t); +static int nm_mem_assign_group(struct netmap_mem_d *, struct device *); #define NMA_LOCK_INIT(n) NM_MTX_INIT((n)->nm_mtx) #define NMA_LOCK_DESTROY(n) NM_MTX_DESTROY((n)->nm_mtx) @@ -248,7 +301,9 @@ netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na) if (nm_mem_assign_group(nmd, na->pdev) < 0) { return ENOMEM; } else { - nmd->ops->nmd_finalize(nmd); + NMA_LOCK(nmd); + nmd->lasterr = nmd->ops->nmd_finalize(nmd); + NMA_UNLOCK(nmd); } if (!nmd->lasterr && na->pdev) @@ -257,26 +312,83 @@ netmap_mem_finalize(struct netmap_mem_d *nmd, struct netmap_adapter *na) return nmd->lasterr; } +static int netmap_mem_init_shared_info(struct netmap_mem_d *nmd); + void netmap_mem_deref(struct netmap_mem_d *nmd, struct netmap_adapter *na) { NMA_LOCK(nmd); netmap_mem_unmap(&nmd->pools[NETMAP_BUF_POOL], na); + if (nmd->active == 1) { + u_int i; + + /* + * Reset the allocator when it falls out of use so that any + * pool resources leaked by unclean application exits are + * reclaimed. + */ + for (i = 0; i < NETMAP_POOLS_NR; i++) { + struct netmap_obj_pool *p; + u_int j; + + p = &nmd->pools[i]; + p->objfree = p->objtotal; + /* + * Reproduce the net effect of the M_ZERO malloc() + * and marking of free entries in the bitmap that + * occur in finalize_obj_allocator() + */ + memset(p->bitmap, + '\0', + sizeof(uint32_t) * ((p->objtotal + 31) / 32)); + + /* + * Set all the bits in the bitmap that have + * corresponding buffers to 1 to indicate they are + * free. + */ + for (j = 0; j < p->objtotal; j++) { + if (p->lut[j].vaddr != NULL) { + p->bitmap[ (j>>5) ] |= ( 1 << (j & 31) ); + } + } + } + + /* + * Per netmap_mem_finalize_all(), + * buffers 0 and 1 are reserved + */ + nmd->pools[NETMAP_BUF_POOL].objfree -= 2; + if (nmd->pools[NETMAP_BUF_POOL].bitmap) { + /* XXX This check is a workaround that prevents a + * NULL pointer crash which currently happens only + * with ptnetmap guests. Also, + * netmap_mem_init_shared_info must not be called + * by ptnetmap guest. */ + nmd->pools[NETMAP_BUF_POOL].bitmap[0] = ~3; + + /* expose info to the ptnetmap guest */ + netmap_mem_init_shared_info(nmd); + } + } + nmd->ops->nmd_deref(nmd); + NMA_UNLOCK(nmd); - return nmd->ops->nmd_deref(nmd); } /* accessor functions */ -static void +static int netmap_mem2_get_lut(struct netmap_mem_d *nmd, struct netmap_lut *lut) { lut->lut = nmd->pools[NETMAP_BUF_POOL].lut; lut->objtotal = nmd->pools[NETMAP_BUF_POOL].objtotal; lut->objsize = nmd->pools[NETMAP_BUF_POOL]._objsize; + + return 0; } -struct netmap_obj_params netmap_params[NETMAP_POOLS_NR] = { +static struct netmap_obj_params netmap_params[NETMAP_POOLS_NR] = { [NETMAP_IF_POOL] = { .size = 1024, .num = 100, @@ -291,10 +403,10 @@ struct netmap_obj_params netmap_params[NETMAP_POOLS_NR] = { }, }; -struct netmap_obj_params netmap_min_priv_params[NETMAP_POOLS_NR] = { +static struct netmap_obj_params netmap_min_priv_params[NETMAP_POOLS_NR] = { [NETMAP_IF_POOL] = { .size = 1024, - .num = 1, + .num = 2, }, [NETMAP_RING_POOL] = { .size = 5*PAGE_SIZE, @@ -348,11 +460,12 @@ struct netmap_mem_d nm_mem = { /* Our memory allocator. */ }; -struct netmap_mem_d *netmap_last_mem_d = &nm_mem; +static struct netmap_mem_d *netmap_last_mem_d = &nm_mem; /* blueprint for the private memory allocators */ extern struct netmap_mem_ops netmap_mem_private_ops; /* forward */ -const struct netmap_mem_d nm_blueprint = { +/* XXX clang is not happy about using name as a print format */ +static const struct netmap_mem_d nm_blueprint = { .pools = { [NETMAP_IF_POOL] = { .name = "%s_if", @@ -388,6 +501,7 @@ const struct netmap_mem_d nm_blueprint = { #define DECLARE_SYSCTLS(id, name) \ + SYSBEGIN(mem2_ ## name); \ SYSCTL_INT(_dev_netmap, OID_AUTO, name##_size, \ CTLFLAG_RW, &netmap_params[id].size, 0, "Requested size of netmap " STRINGIFY(name) "s"); \ SYSCTL_INT(_dev_netmap, OID_AUTO, name##_curr_size, \ @@ -401,22 +515,22 @@ const struct netmap_mem_d nm_blueprint = { "Default size of private netmap " STRINGIFY(name) "s"); \ SYSCTL_INT(_dev_netmap, OID_AUTO, priv_##name##_num, \ CTLFLAG_RW, &netmap_min_priv_params[id].num, 0, \ - "Default number of private netmap " STRINGIFY(name) "s") + "Default number of private netmap " STRINGIFY(name) "s"); \ + SYSEND SYSCTL_DECL(_dev_netmap); DECLARE_SYSCTLS(NETMAP_IF_POOL, if); DECLARE_SYSCTLS(NETMAP_RING_POOL, ring); DECLARE_SYSCTLS(NETMAP_BUF_POOL, buf); +/* call with NMA_LOCK(&nm_mem) held */ static int -nm_mem_assign_id(struct netmap_mem_d *nmd) +nm_mem_assign_id_locked(struct netmap_mem_d *nmd) { nm_memid_t id; struct netmap_mem_d *scan = netmap_last_mem_d; int error = ENOMEM; - NMA_LOCK(&nm_mem); - do { /* we rely on unsigned wrap around */ id = scan->nm_id + 1; @@ -435,10 +549,22 @@ nm_mem_assign_id(struct netmap_mem_d *nmd) } } while (scan != netmap_last_mem_d); - NMA_UNLOCK(&nm_mem); return error; } +/* call with NMA_LOCK(&nm_mem) *not* held */ +static int +nm_mem_assign_id(struct netmap_mem_d *nmd) +{ + int ret; + + NMA_LOCK(&nm_mem); + ret = nm_mem_assign_id_locked(nmd); + NMA_UNLOCK(&nm_mem); + + return ret; +} + static void nm_mem_release_id(struct netmap_mem_d *nmd) { @@ -456,7 +582,7 @@ nm_mem_release_id(struct netmap_mem_d *nmd) } static int -nm_mem_assign_group(struct netmap_mem_d *nmd, device_t dev) +nm_mem_assign_group(struct netmap_mem_d *nmd, struct device *dev) { int err = 0, id; id = nm_iommu_group_id(dev); @@ -494,8 +620,13 @@ netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset) if (offset >= p[i].memtotal) continue; // now lookup the cluster's address +#ifndef _WIN32 pa = vtophys(p[i].lut[offset / p[i]._objsize].vaddr) + offset % p[i]._objsize; +#else + pa = vtophys(p[i].lut[offset / p[i]._objsize].vaddr); + pa.QuadPart += offset % p[i]._objsize; +#endif NMA_UNLOCK(nmd); return pa; } @@ -508,7 +639,110 @@ netmap_mem2_ofstophys(struct netmap_mem_d* nmd, vm_ooffset_t offset) + p[NETMAP_RING_POOL].memtotal + p[NETMAP_BUF_POOL].memtotal); NMA_UNLOCK(nmd); +#ifndef _WIN32 return 0; // XXX bad address +#else + vm_paddr_t res; + res.QuadPart = 0; + return res; +#endif +} + +#ifdef _WIN32 + +/* + * win32_build_virtual_memory_for_userspace + * + * This function get all the object making part of the pools and maps + * a contiguous virtual memory space for the userspace + * It works this way + * 1 - allocate a Memory Descriptor List wide as the sum + * of the memory needed for the pools + * 2 - cycle all the objects in every pool and for every object do + * + * 2a - cycle all the objects in every pool, get the list + * of the physical address descriptors + * 2b - calculate the offset in the array of pages desciptor in the + * main MDL + * 2c - copy the descriptors of the object in the main MDL + * + * 3 - return the resulting MDL that needs to be mapped in userland + * + * In this way we will have an MDL that describes all the memory for the + * objects in a single object +*/ + +PMDL +win32_build_user_vm_map(struct netmap_mem_d* nmd) +{ + int i, j; + u_int memsize, memflags, ofs = 0; + PMDL mainMdl, tempMdl; + + if (netmap_mem_get_info(nmd, &memsize, &memflags, NULL)) { + D("memory not finalised yet"); + return NULL; + } + + mainMdl = IoAllocateMdl(NULL, memsize, FALSE, FALSE, NULL); + if (mainMdl == NULL) { + D("failed to allocate mdl"); + return NULL; + } + + NMA_LOCK(nmd); + for (i = 0; i < NETMAP_POOLS_NR; i++) { + struct netmap_obj_pool *p = &nmd->pools[i]; + int clsz = p->_clustsize; + int clobjs = p->_clustentries; /* objects per cluster */ + int mdl_len = sizeof(PFN_NUMBER) * BYTES_TO_PAGES(clsz); + PPFN_NUMBER pSrc, pDst; + + /* each pool has a different cluster size so we need to reallocate */ + tempMdl = IoAllocateMdl(p->lut[0].vaddr, clsz, FALSE, FALSE, NULL); + if (tempMdl == NULL) { + NMA_UNLOCK(nmd); + D("fail to allocate tempMdl"); + IoFreeMdl(mainMdl); + return NULL; + } + pSrc = MmGetMdlPfnArray(tempMdl); + /* create one entry per cluster, the lut[] has one entry per object */ + for (j = 0; j < p->numclusters; j++, ofs += clsz) { + pDst = &MmGetMdlPfnArray(mainMdl)[BYTES_TO_PAGES(ofs)]; + MmInitializeMdl(tempMdl, p->lut[j*clobjs].vaddr, clsz); + MmBuildMdlForNonPagedPool(tempMdl); /* compute physical page addresses */ + RtlCopyMemory(pDst, pSrc, mdl_len); /* copy the page descriptors */ + mainMdl->MdlFlags = tempMdl->MdlFlags; /* XXX what is in here ? */ + } + IoFreeMdl(tempMdl); + } + NMA_UNLOCK(nmd); + return mainMdl; +} + +#endif /* _WIN32 */ + +/* + * helper function for OS-specific mmap routines (currently only windows). + * Given an nmd and a pool index, returns the cluster size and number of clusters. + * Returns 0 if memory is finalised and the pool is valid, otherwise 1. + * It should be called under NMA_LOCK(nmd) otherwise the underlying info can change. + */ + +int +netmap_mem2_get_pool_info(struct netmap_mem_d* nmd, u_int pool, u_int *clustsize, u_int *numclusters) +{ + if (!nmd || !clustsize || !numclusters || pool >= NETMAP_POOLS_NR) + return 1; /* invalid arguments */ + // NMA_LOCK_ASSERT(nmd); + if (!(nmd->flags & NETMAP_MEM_FINALIZED)) { + *clustsize = *numclusters = 0; + return 1; /* not ready yet */ + } + *clustsize = nmd->pools[pool]._clustsize; + *numclusters = nmd->pools[pool].numclusters; + return 0; /* success */ } static int @@ -578,12 +812,6 @@ netmap_obj_offset(struct netmap_obj_pool *p, const void *vaddr) ((n)->pools[NETMAP_IF_POOL].memtotal + \ netmap_obj_offset(&(n)->pools[NETMAP_RING_POOL], (v))) -#define netmap_buf_offset(n, v) \ - ((n)->pools[NETMAP_IF_POOL].memtotal + \ - (n)->pools[NETMAP_RING_POOL].memtotal + \ - netmap_obj_offset(&(n)->pools[NETMAP_BUF_POOL], (v))) - - static ssize_t netmap_mem2_if_offset(struct netmap_mem_d *nmd, const void *addr) { @@ -602,7 +830,7 @@ static void * netmap_obj_malloc(struct netmap_obj_pool *p, u_int len, uint32_t *start, uint32_t *index) { uint32_t i = 0; /* index in the bitmap */ - uint32_t mask, j; /* slot counter */ + uint32_t mask, j = 0; /* slot counter */ void *vaddr = NULL; if (len > p->_objsize) { @@ -636,7 +864,7 @@ netmap_obj_malloc(struct netmap_obj_pool *p, u_int len, uint32_t *start, uint32_ if (index) *index = i * 32 + j; } - ND("%s allocator: allocated object @ [%d][%d]: vaddr %p", i, j, vaddr); + ND("%s allocator: allocated object @ [%d][%d]: vaddr %p",p->name, i, j, vaddr); if (start) *start = i; @@ -733,7 +961,7 @@ netmap_extra_alloc(struct netmap_adapter *na, uint32_t *head, uint32_t n) *head = cur; /* restore */ break; } - RD(5, "allocate buffer %d -> %d", *head, cur); + ND(5, "allocate buffer %d -> %d", *head, cur); *p = cur; /* link to previous head */ } @@ -750,7 +978,7 @@ netmap_extra_free(struct netmap_adapter *na, uint32_t head) struct netmap_obj_pool *p = &nmd->pools[NETMAP_BUF_POOL]; uint32_t i, cur, *buf; - D("freeing the extra list"); + ND("freeing the extra list"); for (i = 0; head >=2 && head < p->objtotal; i++) { cur = head; buf = lut[head].vaddr; @@ -761,7 +989,8 @@ netmap_extra_free(struct netmap_adapter *na, uint32_t head) } if (head != 0) D("breaking with head %d", head); - D("freed %d buffers", i); + if (netmap_verbose) + D("freed %d buffers", i); } @@ -846,7 +1075,6 @@ netmap_reset_obj_allocator(struct netmap_obj_pool *p) p->bitmap = NULL; if (p->lut) { u_int i; - size_t sz = p->_clustsize; /* * Free each cluster allocated in @@ -856,7 +1084,7 @@ netmap_reset_obj_allocator(struct netmap_obj_pool *p) */ for (i = 0; i < p->objtotal; i += p->_clustentries) { if (p->lut[i].vaddr) - contigfree(p->lut[i].vaddr, sz, M_NETMAP); + contigfree(p->lut[i].vaddr, p->_clustsize, M_NETMAP); } bzero(p->lut, sizeof(struct lut_entry) * p->objtotal); #ifdef linux @@ -973,6 +1201,18 @@ netmap_config_obj_allocator(struct netmap_obj_pool *p, u_int objtotal, u_int obj return 0; } +static struct lut_entry * +nm_alloc_lut(u_int nobj) +{ + size_t n = sizeof(struct lut_entry) * nobj; + struct lut_entry *lut; +#ifdef linux + lut = vmalloc(n); +#else + lut = malloc(n, M_NETMAP, M_NOWAIT | M_ZERO); +#endif + return lut; +} /* call with NMA_LOCK held */ static int @@ -985,14 +1225,9 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p) p->numclusters = p->_numclusters; p->objtotal = p->_objtotal; - n = sizeof(struct lut_entry) * p->objtotal; -#ifdef linux - p->lut = vmalloc(n); -#else - p->lut = malloc(n, M_NETMAP, M_NOWAIT | M_ZERO); -#endif + p->lut = nm_alloc_lut(p->objtotal); if (p->lut == NULL) { - D("Unable to create lookup table (%d bytes) for '%s'", (int)n, p->name); + D("Unable to create lookup table for '%s'", p->name); goto clean; } @@ -1015,6 +1250,13 @@ netmap_finalize_obj_allocator(struct netmap_obj_pool *p) int lim = i + p->_clustentries; char *clust; + /* + * XXX Note, we only need contigmalloc() for buffers attached + * to native interfaces. In all other cases (nifp, netmap rings + * and even buffers for VALE ports or emulated interfaces) we + * can live with standard malloc, because the hardware will not + * access the pages directly. + */ clust = contigmalloc(n, M_NETMAP, M_NOWAIT | M_ZERO, (size_t)0, -1UL, PAGE_SIZE, 0); if (clust == NULL) { @@ -1108,10 +1350,15 @@ netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na) if (na->pdev == NULL) return 0; -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) (void)i; (void)lim; D("unsupported on FreeBSD"); + +#elif defined(_WIN32) + (void)i; + (void)lim; + D("unsupported on Windows"); //XXX_ale, really? #else /* linux */ for (i = 2; i < lim; i++) { netmap_unload_map(na, (bus_dma_tag_t) na->pdev, &p->lut[i].paddr); @@ -1124,8 +1371,10 @@ netmap_mem_unmap(struct netmap_obj_pool *p, struct netmap_adapter *na) static int netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na) { -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) D("unsupported on FreeBSD"); +#elif defined(_WIN32) + D("unsupported on Windows"); //XXX_ale, really? #else /* linux */ int i, lim = p->_objtotal; @@ -1141,6 +1390,30 @@ netmap_mem_map(struct netmap_obj_pool *p, struct netmap_adapter *na) return 0; } +static int +netmap_mem_init_shared_info(struct netmap_mem_d *nmd) +{ + struct netmap_mem_shared_info *nms_info; + ssize_t base; + + /* Use the first slot in IF_POOL */ + nms_info = netmap_if_malloc(nmd, sizeof(*nms_info)); + if (nms_info == NULL) { + return ENOMEM; + } + + base = netmap_if_offset(nmd, nms_info); + + memcpy(&nms_info->up, &nms_if_blueprint, sizeof(nms_if_blueprint)); + nms_info->buf_pool_offset = nmd->pools[NETMAP_IF_POOL].memtotal + nmd->pools[NETMAP_RING_POOL].memtotal; + nms_info->buf_pool_objtotal = nmd->pools[NETMAP_BUF_POOL].objtotal; + nms_info->buf_pool_objsize = nmd->pools[NETMAP_BUF_POOL]._objsize; + nms_info->totalsize = nmd->nm_totalsize; + nms_info->features = NMS_FEAT_BUF_POOL | NMS_FEAT_MEMSIZE; + + return 0; +} + static int netmap_mem_finalize_all(struct netmap_mem_d *nmd) { @@ -1160,6 +1433,11 @@ netmap_mem_finalize_all(struct netmap_mem_d *nmd) nmd->pools[NETMAP_BUF_POOL].bitmap[0] = ~3; nmd->flags |= NETMAP_MEM_FINALIZED; + /* expose info to the ptnetmap guest */ + nmd->lasterr = netmap_mem_init_shared_info(nmd); + if (nmd->lasterr) + goto error; + if (netmap_verbose) D("interfaces %d KB, rings %d KB, buffers %d MB", nmd->pools[NETMAP_IF_POOL].memtotal >> 10, @@ -1207,10 +1485,9 @@ static int netmap_mem_private_finalize(struct netmap_mem_d *nmd) { int err; - NMA_LOCK(nmd); - nmd->active++; err = netmap_mem_finalize_all(nmd); - NMA_UNLOCK(nmd); + if (!err) + nmd->active++; return err; } @@ -1218,10 +1495,8 @@ netmap_mem_private_finalize(struct netmap_mem_d *nmd) static void netmap_mem_private_deref(struct netmap_mem_d *nmd) { - NMA_LOCK(nmd); if (--nmd->active <= 0) netmap_mem_reset_all(nmd); - NMA_UNLOCK(nmd); } @@ -1238,7 +1513,7 @@ netmap_mem_private_new(const char *name, u_int txr, u_int txd, u_int v, maxd; d = malloc(sizeof(struct netmap_mem_d), - M_DEVBUF, M_NOWAIT | M_ZERO); + M_DEVBUF, M_NOWAIT | M_ZERO); if (d == NULL) { err = ENOMEM; goto error; @@ -1357,10 +1632,10 @@ static int netmap_mem_global_finalize(struct netmap_mem_d *nmd) { int err; - + /* update configuration if changed */ if (netmap_mem_global_config(nmd)) - goto out; + return nmd->lasterr; nmd->active++; @@ -1417,13 +1692,17 @@ netmap_free_rings(struct netmap_adapter *na) for_rx_tx(t) { u_int i; - for (i = 0; i < netmap_real_rings(na, t); i++) { + for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { struct netmap_kring *kring = &NMR(na, t)[i]; struct netmap_ring *ring = kring->ring; - if (ring == NULL) + if (ring == NULL || kring->users > 0 || (kring->nr_kflags & NKR_NEEDRING)) { + ND("skipping ring %s (ring %p, users %d)", + kring->name, ring, kring->users); continue; - netmap_free_bufs(na->nm_mem, ring->slot, kring->nkr_num_slots); + } + if (i != nma_get_nrings(na, t) || na->na_flags & NAF_HOST_RINGS) + netmap_free_bufs(na->nm_mem, ring->slot, kring->nkr_num_slots); netmap_ring_free(na->nm_mem, ring); kring->ring = NULL; } @@ -1452,9 +1731,10 @@ netmap_mem2_rings_create(struct netmap_adapter *na) struct netmap_ring *ring = kring->ring; u_int len, ndesc; - if (ring) { - ND("%s already created", kring->name); - continue; /* already created by somebody else */ + if (ring || (!kring->users && !(kring->nr_kflags & NKR_NEEDRING))) { + /* uneeded, or already created by somebody else */ + ND("skipping ring %s", kring->name); + continue; } ndesc = kring->nkr_num_slots; len = sizeof(struct netmap_ring) + @@ -1569,10 +1849,22 @@ netmap_mem2_if_new(struct netmap_adapter *na) */ base = netmap_if_offset(na->nm_mem, nifp); for (i = 0; i < n[NR_TX]; i++) { + if (na->tx_rings[i].ring == NULL) { + // XXX maybe use the offset of an error ring, + // like we do for buffers? + *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i] = 0; + continue; + } *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i] = netmap_ring_offset(na->nm_mem, na->tx_rings[i].ring) - base; } for (i = 0; i < n[NR_RX]; i++) { + if (na->rx_rings[i].ring == NULL) { + // XXX maybe use the offset of an error ring, + // like we do for buffers? + *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i+n[NR_TX]] = 0; + continue; + } *(ssize_t *)(uintptr_t)&nifp->ring_ofs[i+n[NR_TX]] = netmap_ring_offset(na->nm_mem, na->rx_rings[i].ring) - base; } @@ -1636,3 +1928,531 @@ struct netmap_mem_ops netmap_mem_private_ops = { .nmd_rings_create = netmap_mem2_rings_create, .nmd_rings_delete = netmap_mem2_rings_delete }; + +#ifdef WITH_PTNETMAP_GUEST +struct mem_pt_if { + struct mem_pt_if *next; + struct ifnet *ifp; + unsigned int nifp_offset; + nm_pt_guest_ptctl_t ptctl; +}; + +/* Netmap allocator for ptnetmap guests. */ +struct netmap_mem_ptg { + struct netmap_mem_d up; + + vm_paddr_t nm_paddr; /* physical address in the guest */ + void *nm_addr; /* virtual address in the guest */ + struct netmap_lut buf_lut; /* lookup table for BUF pool in the guest */ + nm_memid_t nm_host_id; /* allocator identifier in the host */ + struct ptnetmap_memdev *ptn_dev; + struct mem_pt_if *pt_ifs; /* list of interfaces in passthrough */ +}; + +/* Link a passthrough interface to a passthrough netmap allocator. */ +static int +netmap_mem_pt_guest_ifp_add(struct netmap_mem_d *nmd, struct ifnet *ifp, + unsigned int nifp_offset, + nm_pt_guest_ptctl_t ptctl) +{ + struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; + struct mem_pt_if *ptif = malloc(sizeof(*ptif), M_NETMAP, + M_NOWAIT | M_ZERO); + + if (!ptif) { + return ENOMEM; + } + + NMA_LOCK(nmd); + + ptif->ifp = ifp; + ptif->nifp_offset = nifp_offset; + ptif->ptctl = ptctl; + + if (ptnmd->pt_ifs) { + ptif->next = ptnmd->pt_ifs; + } + ptnmd->pt_ifs = ptif; + + NMA_UNLOCK(nmd); + + D("added (ifp=%p,nifp_offset=%u)", ptif->ifp, ptif->nifp_offset); + + return 0; +} + +/* Called with NMA_LOCK(nmd) held. */ +static struct mem_pt_if * +netmap_mem_pt_guest_ifp_lookup(struct netmap_mem_d *nmd, struct ifnet *ifp) +{ + struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; + struct mem_pt_if *curr; + + for (curr = ptnmd->pt_ifs; curr; curr = curr->next) { + if (curr->ifp == ifp) { + return curr; + } + } + + return NULL; +} + +/* Unlink a passthrough interface from a passthrough netmap allocator. */ +int +netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *nmd, struct ifnet *ifp) +{ + struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; + struct mem_pt_if *prev = NULL; + struct mem_pt_if *curr; + int ret = -1; + + NMA_LOCK(nmd); + + for (curr = ptnmd->pt_ifs; curr; curr = curr->next) { + if (curr->ifp == ifp) { + if (prev) { + prev->next = curr->next; + } else { + ptnmd->pt_ifs = curr->next; + } + D("removed (ifp=%p,nifp_offset=%u)", + curr->ifp, curr->nifp_offset); + free(curr, M_NETMAP); + ret = 0; + break; + } + prev = curr; + } + + NMA_UNLOCK(nmd); + + return ret; +} + +/* Read allocator info from the first netmap_if (only on finalize) */ +static int +netmap_mem_pt_guest_read_shared_info(struct netmap_mem_d *nmd) +{ + struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; + struct netmap_mem_shared_info *nms_info; + uint32_t bufsize; + uint32_t nbuffers; + char *vaddr; + vm_paddr_t paddr; + int i; + + nms_info = (struct netmap_mem_shared_info *)ptnmd->nm_addr; + if (strncmp(nms_info->up.ni_name, NMS_NAME, sizeof(NMS_NAME)) != 0) { + D("error, the first slot does not contain shared info"); + return EINVAL; + } + /* check features mem_shared info */ + if ((nms_info->features & (NMS_FEAT_BUF_POOL | NMS_FEAT_MEMSIZE)) != + (NMS_FEAT_BUF_POOL | NMS_FEAT_MEMSIZE)) { + D("error, the shared info does not contain BUF_POOL and MEMSIZE"); + return EINVAL; + } + + bufsize = nms_info->buf_pool_objsize; + nbuffers = nms_info->buf_pool_objtotal; + + /* allocate the lut */ + if (ptnmd->buf_lut.lut == NULL) { + D("allocating lut"); + ptnmd->buf_lut.lut = nm_alloc_lut(nbuffers); + if (ptnmd->buf_lut.lut == NULL) { + D("lut allocation failed"); + return ENOMEM; + } + } + + /* we have physically contiguous memory mapped through PCI BAR */ + vaddr = (char *)(ptnmd->nm_addr) + nms_info->buf_pool_offset; + paddr = ptnmd->nm_paddr + nms_info->buf_pool_offset; + + for (i = 0; i < nbuffers; i++) { + ptnmd->buf_lut.lut[i].vaddr = vaddr; + ptnmd->buf_lut.lut[i].paddr = paddr; + vaddr += bufsize; + paddr += bufsize; + } + + ptnmd->buf_lut.objtotal = nbuffers; + ptnmd->buf_lut.objsize = bufsize; + + nmd->nm_totalsize = nms_info->totalsize; + + return 0; +} + +static int +netmap_mem_pt_guest_get_lut(struct netmap_mem_d *nmd, struct netmap_lut *lut) +{ + struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; + + if (!(nmd->flags & NETMAP_MEM_FINALIZED)) { + return EINVAL; + } + + *lut = ptnmd->buf_lut; + return 0; +} + +static int +netmap_mem_pt_guest_get_info(struct netmap_mem_d *nmd, u_int *size, + u_int *memflags, uint16_t *id) +{ + int error = 0; + + NMA_LOCK(nmd); + + error = nmd->ops->nmd_config(nmd); + if (error) + goto out; + + if (size) + *size = nmd->nm_totalsize; + if (memflags) + *memflags = nmd->flags; + if (id) + *id = nmd->nm_id; + +out: + NMA_UNLOCK(nmd); + + return error; +} + +static vm_paddr_t +netmap_mem_pt_guest_ofstophys(struct netmap_mem_d *nmd, vm_ooffset_t off) +{ + struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; + vm_paddr_t paddr; + /* if the offset is valid, just return csb->base_addr + off */ + paddr = (vm_paddr_t)(ptnmd->nm_paddr + off); + ND("off %lx padr %lx", off, (unsigned long)paddr); + return paddr; +} + +static int +netmap_mem_pt_guest_config(struct netmap_mem_d *nmd) +{ + /* nothing to do, we are configured on creation + * and configuration never changes thereafter + */ + return 0; +} + +static int +netmap_mem_pt_guest_finalize(struct netmap_mem_d *nmd) +{ + struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; + int error = 0; + + nmd->active++; + + if (nmd->flags & NETMAP_MEM_FINALIZED) + goto out; + + if (ptnmd->ptn_dev == NULL) { + D("ptnetmap memdev not attached"); + error = ENOMEM; + goto err; + } + /* map memory through ptnetmap-memdev BAR */ + error = nm_os_pt_memdev_iomap(ptnmd->ptn_dev, &ptnmd->nm_paddr, + &ptnmd->nm_addr); + if (error) + goto err; + + /* read allcator info and create lut */ + error = netmap_mem_pt_guest_read_shared_info(nmd); + if (error) + goto err; + + nmd->flags |= NETMAP_MEM_FINALIZED; +out: + return 0; +err: + nmd->active--; + return error; +} + +static void +netmap_mem_pt_guest_deref(struct netmap_mem_d *nmd) +{ + struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; + + nmd->active--; + if (nmd->active <= 0 && + (nmd->flags & NETMAP_MEM_FINALIZED)) { + nmd->flags &= ~NETMAP_MEM_FINALIZED; + /* unmap ptnetmap-memdev memory */ + if (ptnmd->ptn_dev) { + nm_os_pt_memdev_iounmap(ptnmd->ptn_dev); + } + ptnmd->nm_addr = 0; + ptnmd->nm_paddr = 0; + } +} + +static ssize_t +netmap_mem_pt_guest_if_offset(struct netmap_mem_d *nmd, const void *vaddr) +{ + struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)nmd; + + return (const char *)(vaddr) - (char *)(ptnmd->nm_addr); +} + +static void +netmap_mem_pt_guest_delete(struct netmap_mem_d *nmd) +{ + if (nmd == NULL) + return; + if (netmap_verbose) + D("deleting %p", nmd); + if (nmd->active > 0) + D("bug: deleting mem allocator with active=%d!", nmd->active); + nm_mem_release_id(nmd); + if (netmap_verbose) + D("done deleting %p", nmd); + NMA_LOCK_DESTROY(nmd); + free(nmd, M_DEVBUF); +} + +static struct netmap_if * +netmap_mem_pt_guest_if_new(struct netmap_adapter *na) +{ + struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)na->nm_mem; + struct mem_pt_if *ptif; + struct netmap_if *nifp = NULL; + + NMA_LOCK(na->nm_mem); + + ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem, na->ifp); + if (ptif == NULL) { + D("Error: interface %p is not in passthrough", na->ifp); + goto out; + } + + nifp = (struct netmap_if *)((char *)(ptnmd->nm_addr) + + ptif->nifp_offset); + NMA_UNLOCK(na->nm_mem); +out: + return nifp; +} + +static void +netmap_mem_pt_guest_if_delete(struct netmap_adapter *na, struct netmap_if *nifp) +{ + struct mem_pt_if *ptif; + + NMA_LOCK(na->nm_mem); + + ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem, na->ifp); + if (ptif == NULL) { + D("Error: interface %p is not in passthrough", na->ifp); + goto out; + } + + ptif->ptctl(na->ifp, PTNETMAP_PTCTL_IFDELETE); +out: + NMA_UNLOCK(na->nm_mem); +} + +static int +netmap_mem_pt_guest_rings_create(struct netmap_adapter *na) +{ + struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)na->nm_mem; + struct mem_pt_if *ptif; + struct netmap_if *nifp; + int i, error = -1; + + NMA_LOCK(na->nm_mem); + + ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem, na->ifp); + if (ptif == NULL) { + D("Error: interface %p is not in passthrough", na->ifp); + goto out; + } + + + /* point each kring to the corresponding backend ring */ + nifp = (struct netmap_if *)((char *)ptnmd->nm_addr + ptif->nifp_offset); + for (i = 0; i <= na->num_tx_rings; i++) { + struct netmap_kring *kring = na->tx_rings + i; + if (kring->ring) + continue; + kring->ring = (struct netmap_ring *) + ((char *)nifp + nifp->ring_ofs[i]); + } + for (i = 0; i <= na->num_rx_rings; i++) { + struct netmap_kring *kring = na->rx_rings + i; + if (kring->ring) + continue; + kring->ring = (struct netmap_ring *) + ((char *)nifp + + nifp->ring_ofs[i + na->num_tx_rings + 1]); + } + + //error = ptif->ptctl->nm_ptctl(ifp, PTNETMAP_PTCTL_RINGSCREATE); + error = 0; +out: + NMA_UNLOCK(na->nm_mem); + + return error; +} + +static void +netmap_mem_pt_guest_rings_delete(struct netmap_adapter *na) +{ + /* TODO: remove?? */ +#if 0 + struct netmap_mem_ptg *ptnmd = (struct netmap_mem_ptg *)na->nm_mem; + struct mem_pt_if *ptif = netmap_mem_pt_guest_ifp_lookup(na->nm_mem, + na->ifp); +#endif +} + +static struct netmap_mem_ops netmap_mem_pt_guest_ops = { + .nmd_get_lut = netmap_mem_pt_guest_get_lut, + .nmd_get_info = netmap_mem_pt_guest_get_info, + .nmd_ofstophys = netmap_mem_pt_guest_ofstophys, + .nmd_config = netmap_mem_pt_guest_config, + .nmd_finalize = netmap_mem_pt_guest_finalize, + .nmd_deref = netmap_mem_pt_guest_deref, + .nmd_if_offset = netmap_mem_pt_guest_if_offset, + .nmd_delete = netmap_mem_pt_guest_delete, + .nmd_if_new = netmap_mem_pt_guest_if_new, + .nmd_if_delete = netmap_mem_pt_guest_if_delete, + .nmd_rings_create = netmap_mem_pt_guest_rings_create, + .nmd_rings_delete = netmap_mem_pt_guest_rings_delete +}; + +/* Called with NMA_LOCK(&nm_mem) held. */ +static struct netmap_mem_d * +netmap_mem_pt_guest_find_hostid(nm_memid_t host_id) +{ + struct netmap_mem_d *mem = NULL; + struct netmap_mem_d *scan = netmap_last_mem_d; + + do { + /* find ptnetmap allocator through host ID */ + if (scan->ops->nmd_deref == netmap_mem_pt_guest_deref && + ((struct netmap_mem_ptg *)(scan))->nm_host_id == host_id) { + mem = scan; + break; + } + scan = scan->next; + } while (scan != netmap_last_mem_d); + + return mem; +} + +/* Called with NMA_LOCK(&nm_mem) held. */ +static struct netmap_mem_d * +netmap_mem_pt_guest_create(nm_memid_t host_id) +{ + struct netmap_mem_ptg *ptnmd; + int err = 0; + + ptnmd = malloc(sizeof(struct netmap_mem_ptg), + M_DEVBUF, M_NOWAIT | M_ZERO); + if (ptnmd == NULL) { + err = ENOMEM; + goto error; + } + + ptnmd->up.ops = &netmap_mem_pt_guest_ops; + ptnmd->nm_host_id = host_id; + ptnmd->pt_ifs = NULL; + + /* Assign new id in the guest (We have the lock) */ + err = nm_mem_assign_id_locked(&ptnmd->up); + if (err) + goto error; + + ptnmd->up.flags &= ~NETMAP_MEM_FINALIZED; + ptnmd->up.flags |= NETMAP_MEM_IO; + + NMA_LOCK_INIT(&ptnmd->up); + + return &ptnmd->up; +error: + netmap_mem_pt_guest_delete(&ptnmd->up); + return NULL; +} + +/* + * find host id in guest allocators and create guest allocator + * if it is not there + */ +static struct netmap_mem_d * +netmap_mem_pt_guest_get(nm_memid_t host_id) +{ + struct netmap_mem_d *nmd; + + NMA_LOCK(&nm_mem); + nmd = netmap_mem_pt_guest_find_hostid(host_id); + if (nmd == NULL) { + nmd = netmap_mem_pt_guest_create(host_id); + } + NMA_UNLOCK(&nm_mem); + + return nmd; +} + +/* + * The guest allocator can be created by ptnetmap_memdev (during the device + * attach) or by ptnetmap device (e1000/virtio), during the netmap_attach. + * + * The order is not important (we have different order in LINUX and FreeBSD). + * The first one, creates the device, and the second one simply attaches it. + */ + +/* Called when ptnetmap_memdev is attaching, to attach a new allocator in + * the guest */ +struct netmap_mem_d * +netmap_mem_pt_guest_attach(struct ptnetmap_memdev *ptn_dev, nm_memid_t host_id) +{ + struct netmap_mem_d *nmd; + struct netmap_mem_ptg *ptnmd; + + nmd = netmap_mem_pt_guest_get(host_id); + + /* assign this device to the guest allocator */ + if (nmd) { + ptnmd = (struct netmap_mem_ptg *)nmd; + ptnmd->ptn_dev = ptn_dev; + } + + return nmd; +} + +/* Called when ptnetmap device (virtio/e1000) is attaching */ +struct netmap_mem_d * +netmap_mem_pt_guest_new(struct ifnet *ifp, + unsigned int nifp_offset, + nm_pt_guest_ptctl_t ptctl) +{ + struct netmap_mem_d *nmd; + nm_memid_t host_id; + + if (ifp == NULL || ptctl == NULL) { + return NULL; + } + + /* Get the host id allocator. */ + host_id = ptctl(ifp, PTNETMAP_PTCTL_HOSTMEMID); + + nmd = netmap_mem_pt_guest_get(host_id); + + if (nmd) { + netmap_mem_pt_guest_ifp_add(nmd, ifp, nifp_offset, + ptctl); + } + + return nmd; +} + +#endif /* WITH_PTNETMAP_GUEST */ diff --git a/sys/dev/netmap/netmap_mem2.h b/sys/dev/netmap/netmap_mem2.h index ef0ff96d8e7f..7f4c5e9e9624 100644 --- a/sys/dev/netmap/netmap_mem2.h +++ b/sys/dev/netmap/netmap_mem2.h @@ -1,5 +1,8 @@ /* - * Copyright (C) 2012-2014 Matteo Landi, Luigi Rizzo, Giuseppe Lettieri. All rights reserved. + * Copyright (C) 2012-2014 Matteo Landi + * Copyright (C) 2012-2016 Luigi Rizzo + * Copyright (C) 2012-2016 Giuseppe Lettieri + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -117,8 +120,11 @@ extern struct netmap_mem_d nm_mem; -void netmap_mem_get_lut(struct netmap_mem_d *, struct netmap_lut *); +int netmap_mem_get_lut(struct netmap_mem_d *, struct netmap_lut *); vm_paddr_t netmap_mem_ofstophys(struct netmap_mem_d *, vm_ooffset_t); +#ifdef _WIN32 +PMDL win32_build_user_vm_map(struct netmap_mem_d* nmd); +#endif int netmap_mem_finalize(struct netmap_mem_d *, struct netmap_adapter *); int netmap_mem_init(void); void netmap_mem_fini(void); @@ -127,6 +133,7 @@ void netmap_mem_if_delete(struct netmap_adapter *, struct netmap_if *); int netmap_mem_rings_create(struct netmap_adapter *); void netmap_mem_rings_delete(struct netmap_adapter *); void netmap_mem_deref(struct netmap_mem_d *, struct netmap_adapter *); +int netmap_mem2_get_pool_info(struct netmap_mem_d *, u_int, u_int *, u_int *); int netmap_mem_get_info(struct netmap_mem_d *, u_int *size, u_int *memflags, uint16_t *id); ssize_t netmap_mem_if_offset(struct netmap_mem_d *, const void *vaddr); struct netmap_mem_d* netmap_mem_private_new(const char *name, @@ -157,6 +164,15 @@ void netmap_mem_put(struct netmap_mem_d *); #endif /* !NM_DEBUG_PUTGET */ +#ifdef WITH_PTNETMAP_GUEST +struct netmap_mem_d* netmap_mem_pt_guest_new(struct ifnet *, + unsigned int nifp_offset, + nm_pt_guest_ptctl_t); +struct ptnetmap_memdev; +struct netmap_mem_d* netmap_mem_pt_guest_attach(struct ptnetmap_memdev *, uint16_t); +int netmap_mem_pt_guest_ifp_del(struct netmap_mem_d *, struct ifnet *); +#endif /* WITH_PTNETMAP_GUEST */ + #define NETMAP_MEM_PRIVATE 0x2 /* allocator uses private address space */ #define NETMAP_MEM_IO 0x4 /* the underlying memory is mmapped I/O */ diff --git a/sys/dev/netmap/netmap_monitor.c b/sys/dev/netmap/netmap_monitor.c index c303952417ff..bf6e23f5546e 100644 --- a/sys/dev/netmap/netmap_monitor.c +++ b/sys/dev/netmap/netmap_monitor.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2014 Giuseppe Lettieri. All rights reserved. + * Copyright (C) 2014-2016 Giuseppe Lettieri + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -101,6 +102,8 @@ #warning OSX support is only partial #include "osx_glue.h" +#elif defined(_WIN32) +#include "win_glue.h" #else #error Unsupported platform @@ -151,13 +154,17 @@ netmap_monitor_rxsync(struct netmap_kring *kring, int flags) } /* nm_krings_create callbacks for monitors. - * We could use the default netmap_hw_krings_zmon, but - * we don't need the mbq. */ static int netmap_monitor_krings_create(struct netmap_adapter *na) { - return netmap_krings_create(na, 0); + int error = netmap_krings_create(na, 0); + if (error) + return error; + /* override the host rings callbacks */ + na->tx_rings[na->num_tx_rings].nm_sync = netmap_monitor_txsync; + na->rx_rings[na->num_rx_rings].nm_sync = netmap_monitor_rxsync; + return 0; } /* nm_krings_delete callback for monitors */ @@ -184,9 +191,13 @@ nm_monitor_alloc(struct netmap_kring *kring, u_int n) if (n <= kring->max_monitors) /* we already have more entries that requested */ return 0; - + len = sizeof(struct netmap_kring *) * n; +#ifndef _WIN32 nm = realloc(kring->monitors, len, M_DEVBUF, M_NOWAIT | M_ZERO); +#else + nm = realloc(kring->monitors, len, sizeof(struct netmap_kring *)*kring->max_monitors); +#endif if (nm == NULL) return ENOMEM; @@ -229,10 +240,10 @@ static int netmap_monitor_parent_notify(struct netmap_kring *, int); static int netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int zcopy) { - int error = 0; + int error = NM_IRQ_COMPLETED; /* sinchronize with concurrently running nm_sync()s */ - nm_kr_get(kring); + nm_kr_stop(kring, NM_KR_LOCKED); /* make sure the monitor array exists and is big enough */ error = nm_monitor_alloc(kring, kring->n_monitors + 1); if (error) @@ -242,7 +253,7 @@ netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int kring->n_monitors++; if (kring->n_monitors == 1) { /* this is the first monitor, intercept callbacks */ - D("%s: intercept callbacks on %s", mkring->name, kring->name); + ND("%s: intercept callbacks on %s", mkring->name, kring->name); kring->mon_sync = kring->nm_sync; /* zcopy monitors do not override nm_notify(), but * we save the original one regardless, so that @@ -265,7 +276,7 @@ netmap_monitor_add(struct netmap_kring *mkring, struct netmap_kring *kring, int } out: - nm_kr_put(kring); + nm_kr_start(kring); return error; } @@ -277,7 +288,7 @@ static void netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring) { /* sinchronize with concurrently running nm_sync()s */ - nm_kr_get(kring); + nm_kr_stop(kring, NM_KR_LOCKED); kring->n_monitors--; if (mkring->mon_pos != kring->n_monitors) { kring->monitors[mkring->mon_pos] = kring->monitors[kring->n_monitors]; @@ -286,18 +297,18 @@ netmap_monitor_del(struct netmap_kring *mkring, struct netmap_kring *kring) kring->monitors[kring->n_monitors] = NULL; if (kring->n_monitors == 0) { /* this was the last monitor, restore callbacks and delete monitor array */ - D("%s: restoring sync on %s: %p", mkring->name, kring->name, kring->mon_sync); + ND("%s: restoring sync on %s: %p", mkring->name, kring->name, kring->mon_sync); kring->nm_sync = kring->mon_sync; kring->mon_sync = NULL; if (kring->tx == NR_RX) { - D("%s: restoring notify on %s: %p", + ND("%s: restoring notify on %s: %p", mkring->name, kring->name, kring->mon_notify); kring->nm_notify = kring->mon_notify; kring->mon_notify = NULL; } nm_monitor_dealloc(kring); } - nm_kr_put(kring); + nm_kr_start(kring); } @@ -316,7 +327,7 @@ netmap_monitor_stop(struct netmap_adapter *na) for_rx_tx(t) { u_int i; - for (i = 0; i < nma_get_nrings(na, t); i++) { + for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { struct netmap_kring *kring = &NMR(na, t)[i]; u_int j; @@ -360,23 +371,32 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon) for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) { kring = &NMR(pna, t)[i]; mkring = &na->rx_rings[i]; - netmap_monitor_add(mkring, kring, zmon); + if (nm_kring_pending_on(mkring)) { + netmap_monitor_add(mkring, kring, zmon); + mkring->nr_mode = NKR_NETMAP_ON; + } } } } na->na_flags |= NAF_NETMAP_ON; } else { - if (pna == NULL) { - D("%s: parent left netmap mode, nothing to restore", na->name); - return 0; - } - na->na_flags &= ~NAF_NETMAP_ON; + if (na->active_fds == 0) + na->na_flags &= ~NAF_NETMAP_ON; for_rx_tx(t) { if (mna->flags & nm_txrx2flag(t)) { for (i = priv->np_qfirst[t]; i < priv->np_qlast[t]; i++) { - kring = &NMR(pna, t)[i]; mkring = &na->rx_rings[i]; - netmap_monitor_del(mkring, kring); + if (nm_kring_pending_off(mkring)) { + mkring->nr_mode = NKR_NETMAP_OFF; + /* we cannot access the parent krings if the parent + * has left netmap mode. This is signaled by a NULL + * pna pointer + */ + if (pna) { + kring = &NMR(pna, t)[i]; + netmap_monitor_del(mkring, kring); + } + } } } } @@ -386,7 +406,7 @@ netmap_monitor_reg_common(struct netmap_adapter *na, int onoff, int zmon) /* **************************************************************** - * functions specific for zero-copy monitors + * functions specific for zero-copy monitors **************************************************************** */ @@ -534,7 +554,7 @@ netmap_zmon_dtor(struct netmap_adapter *na) /* **************************************************************** - * functions specific for copy monitors + * functions specific for copy monitors **************************************************************** */ @@ -652,17 +672,27 @@ netmap_monitor_parent_rxsync(struct netmap_kring *kring, int flags) static int netmap_monitor_parent_notify(struct netmap_kring *kring, int flags) { + int (*notify)(struct netmap_kring*, int); ND(5, "%s %x", kring->name, flags); /* ?xsync callbacks have tryget called by their callers * (NIOCREGIF and poll()), but here we have to call it * by ourself */ - if (nm_kr_tryget(kring)) - goto out; - netmap_monitor_parent_rxsync(kring, NAF_FORCE_READ); + if (nm_kr_tryget(kring, 0, NULL)) { + /* in all cases, just skip the sync */ + return NM_IRQ_COMPLETED; + } + if (kring->n_monitors > 0) { + netmap_monitor_parent_rxsync(kring, NAF_FORCE_READ); + notify = kring->mon_notify; + } else { + /* we are no longer monitoring this ring, so both + * mon_sync and mon_notify are NULL + */ + notify = kring->nm_notify; + } nm_kr_put(kring); -out: - return kring->mon_notify(kring, flags); + return notify(kring, flags); } @@ -691,18 +721,25 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na, int create) struct nmreq pnmr; struct netmap_adapter *pna; /* parent adapter */ struct netmap_monitor_adapter *mna; + struct ifnet *ifp = NULL; int i, error; enum txrx t; int zcopy = (nmr->nr_flags & NR_ZCOPY_MON); char monsuff[10] = ""; if ((nmr->nr_flags & (NR_MONITOR_TX | NR_MONITOR_RX)) == 0) { + if (nmr->nr_flags & NR_ZCOPY_MON) { + /* the flag makes no sense unless you are + * creating a monitor + */ + return EINVAL; + } ND("not a monitor"); return 0; } /* this is a request for a monitor adapter */ - D("flags %x", nmr->nr_flags); + ND("flags %x", nmr->nr_flags); mna = malloc(sizeof(*mna), M_DEVBUF, M_NOWAIT | M_ZERO); if (mna == NULL) { @@ -716,13 +753,14 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na, int create) * except other monitors. */ memcpy(&pnmr, nmr, sizeof(pnmr)); - pnmr.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX); - error = netmap_get_na(&pnmr, &pna, create); + pnmr.nr_flags &= ~(NR_MONITOR_TX | NR_MONITOR_RX | NR_ZCOPY_MON); + error = netmap_get_na(&pnmr, &pna, &ifp, create); if (error) { D("parent lookup failed: %d", error); + free(mna, M_DEVBUF); return error; } - D("found parent: %s", pna->name); + ND("found parent: %s", pna->name); if (!nm_netmap_on(pna)) { /* parent not in netmap mode */ @@ -829,19 +867,17 @@ netmap_get_monitor_na(struct nmreq *nmr, struct netmap_adapter **na, int create) *na = &mna->up; netmap_adapter_get(*na); - /* write the configuration back */ - nmr->nr_tx_rings = mna->up.num_tx_rings; - nmr->nr_rx_rings = mna->up.num_rx_rings; - nmr->nr_tx_slots = mna->up.num_tx_desc; - nmr->nr_rx_slots = mna->up.num_rx_desc; - /* keep the reference to the parent */ - D("monitor ok"); + ND("monitor ok"); + + /* drop the reference to the ifp, if any */ + if (ifp) + if_rele(ifp); return 0; put_out: - netmap_adapter_put(pna); + netmap_unget_na(pna, ifp); free(mna, M_DEVBUF); return error; } diff --git a/sys/dev/netmap/netmap_offloadings.c b/sys/dev/netmap/netmap_offloadings.c index dadc1dcbc14c..f8da672ffa53 100644 --- a/sys/dev/netmap/netmap_offloadings.c +++ b/sys/dev/netmap/netmap_offloadings.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2014 Vincenzo Maffione. All rights reserved. + * Copyright (C) 2014-2015 Vincenzo Maffione + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,9 +32,9 @@ #include #include #include /* defines used in kernel.h */ -#include /* types used in module initialization */ #include /* types used in module initialization */ #include +#include #include /* struct socket */ #include /* sockaddrs */ #include @@ -64,21 +65,21 @@ /* This routine is called by bdg_mismatch_datapath() when it finishes * accumulating bytes for a segment, in order to fix some fields in the * segment headers (which still contain the same content as the header - * of the original GSO packet). 'buf' points to the beginning (e.g. - * the ethernet header) of the segment, and 'len' is its length. + * of the original GSO packet). 'pkt' points to the beginning of the IP + * header of the segment, while 'len' is the length of the IP packet. */ -static void gso_fix_segment(uint8_t *buf, size_t len, u_int idx, - u_int segmented_bytes, u_int last_segment, - u_int tcp, u_int iphlen) +static void +gso_fix_segment(uint8_t *pkt, size_t len, u_int ipv4, u_int iphlen, u_int tcp, + u_int idx, u_int segmented_bytes, u_int last_segment) { - struct nm_iphdr *iph = (struct nm_iphdr *)(buf + 14); - struct nm_ipv6hdr *ip6h = (struct nm_ipv6hdr *)(buf + 14); + struct nm_iphdr *iph = (struct nm_iphdr *)(pkt); + struct nm_ipv6hdr *ip6h = (struct nm_ipv6hdr *)(pkt); uint16_t *check = NULL; uint8_t *check_data = NULL; - if (iphlen == 20) { + if (ipv4) { /* Set the IPv4 "Total Length" field. */ - iph->tot_len = htobe16(len-14); + iph->tot_len = htobe16(len); ND("ip total length %u", be16toh(ip->tot_len)); /* Set the IPv4 "Identification" field. */ @@ -87,15 +88,15 @@ static void gso_fix_segment(uint8_t *buf, size_t len, u_int idx, /* Compute and insert the IPv4 header checksum. */ iph->check = 0; - iph->check = nm_csum_ipv4(iph); + iph->check = nm_os_csum_ipv4(iph); ND("IP csum %x", be16toh(iph->check)); - } else {/* if (iphlen == 40) */ + } else { /* Set the IPv6 "Payload Len" field. */ - ip6h->payload_len = htobe16(len-14-iphlen); + ip6h->payload_len = htobe16(len-iphlen); } if (tcp) { - struct nm_tcphdr *tcph = (struct nm_tcphdr *)(buf + 14 + iphlen); + struct nm_tcphdr *tcph = (struct nm_tcphdr *)(pkt + iphlen); /* Set the TCP sequence number. */ tcph->seq = htobe32(be32toh(tcph->seq) + segmented_bytes); @@ -110,10 +111,10 @@ static void gso_fix_segment(uint8_t *buf, size_t len, u_int idx, check = &tcph->check; check_data = (uint8_t *)tcph; } else { /* UDP */ - struct nm_udphdr *udph = (struct nm_udphdr *)(buf + 14 + iphlen); + struct nm_udphdr *udph = (struct nm_udphdr *)(pkt + iphlen); /* Set the UDP 'Length' field. */ - udph->len = htobe16(len-14-iphlen); + udph->len = htobe16(len-iphlen); check = &udph->check; check_data = (uint8_t *)udph; @@ -121,48 +122,80 @@ static void gso_fix_segment(uint8_t *buf, size_t len, u_int idx, /* Compute and insert TCP/UDP checksum. */ *check = 0; - if (iphlen == 20) - nm_csum_tcpudp_ipv4(iph, check_data, len-14-iphlen, check); + if (ipv4) + nm_os_csum_tcpudp_ipv4(iph, check_data, len-iphlen, check); else - nm_csum_tcpudp_ipv6(ip6h, check_data, len-14-iphlen, check); + nm_os_csum_tcpudp_ipv6(ip6h, check_data, len-iphlen, check); ND("TCP/UDP csum %x", be16toh(*check)); } +static int +vnet_hdr_is_bad(struct nm_vnet_hdr *vh) +{ + uint8_t gso_type = vh->gso_type & ~VIRTIO_NET_HDR_GSO_ECN; + + return ( + (gso_type != VIRTIO_NET_HDR_GSO_NONE && + gso_type != VIRTIO_NET_HDR_GSO_TCPV4 && + gso_type != VIRTIO_NET_HDR_GSO_UDP && + gso_type != VIRTIO_NET_HDR_GSO_TCPV6) + || + (vh->flags & ~(VIRTIO_NET_HDR_F_NEEDS_CSUM + | VIRTIO_NET_HDR_F_DATA_VALID)) + ); +} /* The VALE mismatch datapath implementation. */ -void bdg_mismatch_datapath(struct netmap_vp_adapter *na, - struct netmap_vp_adapter *dst_na, - struct nm_bdg_fwd *ft_p, struct netmap_ring *ring, - u_int *j, u_int lim, u_int *howmany) +void +bdg_mismatch_datapath(struct netmap_vp_adapter *na, + struct netmap_vp_adapter *dst_na, + const struct nm_bdg_fwd *ft_p, + struct netmap_ring *dst_ring, + u_int *j, u_int lim, u_int *howmany) { - struct netmap_slot *slot = NULL; + struct netmap_slot *dst_slot = NULL; struct nm_vnet_hdr *vh = NULL; - /* Number of source slots to process. */ - u_int frags = ft_p->ft_frags; - struct nm_bdg_fwd *ft_end = ft_p + frags; + const struct nm_bdg_fwd *ft_end = ft_p + ft_p->ft_frags; /* Source and destination pointers. */ uint8_t *dst, *src; size_t src_len, dst_len; + /* Indices and counters for the destination ring. */ u_int j_start = *j; + u_int j_cur = j_start; u_int dst_slots = 0; - /* If the source port uses the offloadings, while destination doesn't, - * we grab the source virtio-net header and do the offloadings here. - */ - if (na->virt_hdr_len && !dst_na->virt_hdr_len) { - vh = (struct nm_vnet_hdr *)ft_p->ft_buf; + if (unlikely(ft_p == ft_end)) { + RD(3, "No source slots to process"); + return; } /* Init source and dest pointers. */ src = ft_p->ft_buf; src_len = ft_p->ft_len; - slot = &ring->slot[*j]; - dst = NMB(&dst_na->up, slot); + dst_slot = &dst_ring->slot[j_cur]; + dst = NMB(&dst_na->up, dst_slot); dst_len = src_len; + /* If the source port uses the offloadings, while destination doesn't, + * we grab the source virtio-net header and do the offloadings here. + */ + if (na->up.virt_hdr_len && !dst_na->up.virt_hdr_len) { + vh = (struct nm_vnet_hdr *)src; + /* Initial sanity check on the source virtio-net header. If + * something seems wrong, just drop the packet. */ + if (src_len < na->up.virt_hdr_len) { + RD(3, "Short src vnet header, dropping"); + return; + } + if (vnet_hdr_is_bad(vh)) { + RD(3, "Bad src vnet header, dropping"); + return; + } + } + /* We are processing the first input slot and there is a mismatch * between source and destination virt_hdr_len (SHL and DHL). * When the a client is using virtio-net headers, the header length @@ -185,14 +218,14 @@ void bdg_mismatch_datapath(struct netmap_vp_adapter *na, * 12 | 0 | doesn't exist * 12 | 10 | copied from the first 10 bytes of source header */ - bzero(dst, dst_na->virt_hdr_len); - if (na->virt_hdr_len && dst_na->virt_hdr_len) + bzero(dst, dst_na->up.virt_hdr_len); + if (na->up.virt_hdr_len && dst_na->up.virt_hdr_len) memcpy(dst, src, sizeof(struct nm_vnet_hdr)); /* Skip the virtio-net headers. */ - src += na->virt_hdr_len; - src_len -= na->virt_hdr_len; - dst += dst_na->virt_hdr_len; - dst_len = dst_na->virt_hdr_len + src_len; + src += na->up.virt_hdr_len; + src_len -= na->up.virt_hdr_len; + dst += dst_na->up.virt_hdr_len; + dst_len = dst_na->up.virt_hdr_len + src_len; /* Here it could be dst_len == 0 (which implies src_len == 0), * so we avoid passing a zero length fragment. @@ -214,16 +247,27 @@ void bdg_mismatch_datapath(struct netmap_vp_adapter *na, u_int gso_idx = 0; /* Payload data bytes segmented so far (e.g. TCP data bytes). */ u_int segmented_bytes = 0; + /* Is this an IPv4 or IPv6 GSO packet? */ + u_int ipv4 = 0; /* Length of the IP header (20 if IPv4, 40 if IPv6). */ u_int iphlen = 0; + /* Length of the Ethernet header (18 if 802.1q, otherwise 14). */ + u_int ethhlen = 14; /* Is this a TCP or an UDP GSO packet? */ u_int tcp = ((vh->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) == VIRTIO_NET_HDR_GSO_UDP) ? 0 : 1; /* Segment the GSO packet contained into the input slots (frags). */ - while (ft_p != ft_end) { + for (;;) { size_t copy; + if (dst_slots >= *howmany) { + /* We still have work to do, but we've run out of + * dst slots, so we have to drop the packet. */ + RD(3, "Not enough slots, dropping GSO packet"); + return; + } + /* Grab the GSO header if we don't have it. */ if (!gso_hdr) { uint16_t ethertype; @@ -231,28 +275,75 @@ void bdg_mismatch_datapath(struct netmap_vp_adapter *na, gso_hdr = src; /* Look at the 'Ethertype' field to see if this packet - * is IPv4 or IPv6. - */ - ethertype = be16toh(*((uint16_t *)(gso_hdr + 12))); - if (ethertype == 0x0800) - iphlen = 20; - else /* if (ethertype == 0x86DD) */ - iphlen = 40; + * is IPv4 or IPv6, taking into account VLAN + * encapsulation. */ + for (;;) { + if (src_len < ethhlen) { + RD(3, "Short GSO fragment [eth], dropping"); + return; + } + ethertype = be16toh(*((uint16_t *) + (gso_hdr + ethhlen - 2))); + if (ethertype != 0x8100) /* not 802.1q */ + break; + ethhlen += 4; + } + switch (ethertype) { + case 0x0800: /* IPv4 */ + { + struct nm_iphdr *iph = (struct nm_iphdr *) + (gso_hdr + ethhlen); + + if (src_len < ethhlen + 20) { + RD(3, "Short GSO fragment " + "[IPv4], dropping"); + return; + } + ipv4 = 1; + iphlen = 4 * (iph->version_ihl & 0x0F); + break; + } + case 0x86DD: /* IPv6 */ + ipv4 = 0; + iphlen = 40; + break; + default: + RD(3, "Unsupported ethertype, " + "dropping GSO packet"); + return; + } ND(3, "type=%04x", ethertype); + if (src_len < ethhlen + iphlen) { + RD(3, "Short GSO fragment [IP], dropping"); + return; + } + /* Compute gso_hdr_len. For TCP we need to read the * content of the 'Data Offset' field. */ if (tcp) { - struct nm_tcphdr *tcph = - (struct nm_tcphdr *)&gso_hdr[14+iphlen]; + struct nm_tcphdr *tcph = (struct nm_tcphdr *) + (gso_hdr + ethhlen + iphlen); - gso_hdr_len = 14 + iphlen + 4*(tcph->doff >> 4); - } else - gso_hdr_len = 14 + iphlen + 8; /* UDP */ + if (src_len < ethhlen + iphlen + 20) { + RD(3, "Short GSO fragment " + "[TCP], dropping"); + return; + } + gso_hdr_len = ethhlen + iphlen + + 4 * (tcph->doff >> 4); + } else { + gso_hdr_len = ethhlen + iphlen + 8; /* UDP */ + } + + if (src_len < gso_hdr_len) { + RD(3, "Short GSO fragment [TCP/UDP], dropping"); + return; + } ND(3, "gso_hdr_len %u gso_mtu %d", gso_hdr_len, - dst_na->mfs); + dst_na->mfs); /* Advance source pointers. */ src += gso_hdr_len; @@ -263,7 +354,6 @@ void bdg_mismatch_datapath(struct netmap_vp_adapter *na, break; src = ft_p->ft_buf; src_len = ft_p->ft_len; - continue; } } @@ -289,25 +379,24 @@ void bdg_mismatch_datapath(struct netmap_vp_adapter *na, /* After raw segmentation, we must fix some header * fields and compute checksums, in a protocol dependent * way. */ - gso_fix_segment(dst, gso_bytes, gso_idx, - segmented_bytes, - src_len == 0 && ft_p + 1 == ft_end, - tcp, iphlen); + gso_fix_segment(dst + ethhlen, gso_bytes - ethhlen, + ipv4, iphlen, tcp, + gso_idx, segmented_bytes, + src_len == 0 && ft_p + 1 == ft_end); ND("frame %u completed with %d bytes", gso_idx, (int)gso_bytes); - slot->len = gso_bytes; - slot->flags = 0; - segmented_bytes += gso_bytes - gso_hdr_len; - + dst_slot->len = gso_bytes; + dst_slot->flags = 0; dst_slots++; - - /* Next destination slot. */ - *j = nm_next(*j, lim); - slot = &ring->slot[*j]; - dst = NMB(&dst_na->up, slot); + segmented_bytes += gso_bytes - gso_hdr_len; gso_bytes = 0; gso_idx++; + + /* Next destination slot. */ + j_cur = nm_next(j_cur, lim); + dst_slot = &dst_ring->slot[j_cur]; + dst = NMB(&dst_na->up, dst_slot); } /* Next input slot. */ @@ -342,10 +431,10 @@ void bdg_mismatch_datapath(struct netmap_vp_adapter *na, /* Init/update the packet checksum if needed. */ if (vh && (vh->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) { if (!dst_slots) - csum = nm_csum_raw(src + vh->csum_start, + csum = nm_os_csum_raw(src + vh->csum_start, src_len - vh->csum_start, 0); else - csum = nm_csum_raw(src, src_len, csum); + csum = nm_os_csum_raw(src, src_len, csum); } /* Round to a multiple of 64 */ @@ -359,44 +448,43 @@ void bdg_mismatch_datapath(struct netmap_vp_adapter *na, } else { memcpy(dst, src, (int)src_len); } - slot->len = dst_len; - + dst_slot->len = dst_len; dst_slots++; /* Next destination slot. */ - *j = nm_next(*j, lim); - slot = &ring->slot[*j]; - dst = NMB(&dst_na->up, slot); + j_cur = nm_next(j_cur, lim); + dst_slot = &dst_ring->slot[j_cur]; + dst = NMB(&dst_na->up, dst_slot); /* Next source slot. */ ft_p++; src = ft_p->ft_buf; dst_len = src_len = ft_p->ft_len; - } /* Finalize (fold) the checksum if needed. */ if (check && vh && (vh->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)) { - *check = nm_csum_fold(csum); + *check = nm_os_csum_fold(csum); } ND(3, "using %u dst_slots", dst_slots); - /* A second pass on the desitations slots to set the slot flags, + /* A second pass on the destination slots to set the slot flags, * using the right number of destination slots. */ - while (j_start != *j) { - slot = &ring->slot[j_start]; - slot->flags = (dst_slots << 8)| NS_MOREFRAG; + while (j_start != j_cur) { + dst_slot = &dst_ring->slot[j_start]; + dst_slot->flags = (dst_slots << 8)| NS_MOREFRAG; j_start = nm_next(j_start, lim); } /* Clear NS_MOREFRAG flag on last entry. */ - slot->flags = (dst_slots << 8); + dst_slot->flags = (dst_slots << 8); } - /* Update howmany. */ + /* Update howmany and j. This is to commit the use of + * those slots in the destination ring. */ if (unlikely(dst_slots > *howmany)) { - dst_slots = *howmany; - D("Slot allocation error: Should never happen"); + D("Slot allocation error: This is a bug"); } + *j = j_cur; *howmany -= dst_slots; } diff --git a/sys/dev/netmap/netmap_pipe.c b/sys/dev/netmap/netmap_pipe.c index 67e840248c88..f00f73f8b9b2 100644 --- a/sys/dev/netmap/netmap_pipe.c +++ b/sys/dev/netmap/netmap_pipe.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2014 Giuseppe Lettieri. All rights reserved. + * Copyright (C) 2014-2016 Giuseppe Lettieri + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -54,6 +55,9 @@ #warning OSX support is only partial #include "osx_glue.h" +#elif defined(_WIN32) +#include "win_glue.h" + #else #error Unsupported platform @@ -72,9 +76,11 @@ #define NM_PIPE_MAXSLOTS 4096 -int netmap_default_pipes = 0; /* ignored, kept for compatibility */ +static int netmap_default_pipes = 0; /* ignored, kept for compatibility */ +SYSBEGIN(vars_pipes); SYSCTL_DECL(_dev_netmap); SYSCTL_INT(_dev_netmap, OID_AUTO, default_pipes, CTLFLAG_RW, &netmap_default_pipes, 0 , ""); +SYSEND; /* allocate the pipe array in the parent adapter */ static int @@ -86,12 +92,16 @@ nm_pipe_alloc(struct netmap_adapter *na, u_int npipes) if (npipes <= na->na_max_pipes) /* we already have more entries that requested */ return 0; - + if (npipes < na->na_next_pipe || npipes > NM_MAXPIPES) return EINVAL; len = sizeof(struct netmap_pipe_adapter *) * npipes; +#ifndef _WIN32 npa = realloc(na->na_pipes, len, M_DEVBUF, M_NOWAIT | M_ZERO); +#else + npa = realloc(na->na_pipes, len, sizeof(struct netmap_pipe_adapter *)*na->na_max_pipes); +#endif if (npa == NULL) return ENOMEM; @@ -199,7 +209,7 @@ netmap_pipe_txsync(struct netmap_kring *txkring, int flags) } while (limit-- > 0) { - struct netmap_slot *rs = &rxkring->save_ring->slot[j]; + struct netmap_slot *rs = &rxkring->ring->slot[j]; struct netmap_slot *ts = &txkring->ring->slot[k]; struct netmap_slot tmp; @@ -295,7 +305,7 @@ netmap_pipe_rxsync(struct netmap_kring *rxkring, int flags) * usr1 --> e1 --> e2 * * and we are e2. e1 is certainly registered and our - * krings already exist, but they may be hidden. + * krings already exist. Nothing to do. */ static int netmap_pipe_krings_create(struct netmap_adapter *na) @@ -310,65 +320,28 @@ netmap_pipe_krings_create(struct netmap_adapter *na) int i; /* case 1) above */ - ND("%p: case 1, create everything", na); + D("%p: case 1, create both ends", na); error = netmap_krings_create(na, 0); if (error) goto err; - /* we also create all the rings, since we need to - * update the save_ring pointers. - * netmap_mem_rings_create (called by our caller) - * will not create the rings again - */ - - error = netmap_mem_rings_create(na); + /* create the krings of the other end */ + error = netmap_krings_create(ona, 0); if (error) goto del_krings1; - /* update our hidden ring pointers */ - for_rx_tx(t) { - for (i = 0; i < nma_get_nrings(na, t) + 1; i++) - NMR(na, t)[i].save_ring = NMR(na, t)[i].ring; - } - - /* now, create krings and rings of the other end */ - error = netmap_krings_create(ona, 0); - if (error) - goto del_rings1; - - error = netmap_mem_rings_create(ona); - if (error) - goto del_krings2; - - for_rx_tx(t) { - for (i = 0; i < nma_get_nrings(ona, t) + 1; i++) - NMR(ona, t)[i].save_ring = NMR(ona, t)[i].ring; - } - /* cross link the krings */ for_rx_tx(t) { - enum txrx r= nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */ + enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */ for (i = 0; i < nma_get_nrings(na, t); i++) { NMR(na, t)[i].pipe = NMR(&pna->peer->up, r) + i; NMR(&pna->peer->up, r)[i].pipe = NMR(na, t) + i; } } - } else { - int i; - /* case 2) above */ - /* recover the hidden rings */ - ND("%p: case 2, hidden rings", na); - for_rx_tx(t) { - for (i = 0; i < nma_get_nrings(na, t) + 1; i++) - NMR(na, t)[i].ring = NMR(na, t)[i].save_ring; - } + } return 0; -del_krings2: - netmap_krings_delete(ona); -del_rings1: - netmap_mem_rings_delete(na); del_krings1: netmap_krings_delete(na); err: @@ -383,7 +356,8 @@ netmap_pipe_krings_create(struct netmap_adapter *na) * * usr1 --> e1 --> e2 * - * and we are e1. Nothing special to do. + * and we are e1. Create the needed rings of the + * other end. * * 1.b) state is * @@ -412,14 +386,65 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff) { struct netmap_pipe_adapter *pna = (struct netmap_pipe_adapter *)na; + struct netmap_adapter *ona = &pna->peer->up; + int i, error = 0; enum txrx t; ND("%p: onoff %d", na, onoff); if (onoff) { - na->na_flags |= NAF_NETMAP_ON; + for_rx_tx(t) { + for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { + struct netmap_kring *kring = &NMR(na, t)[i]; + + if (nm_kring_pending_on(kring)) { + /* mark the partner ring as needed */ + kring->pipe->nr_kflags |= NKR_NEEDRING; + } + } + } + + /* create all missing needed rings on the other end */ + error = netmap_mem_rings_create(ona); + if (error) + return error; + + /* In case of no error we put our rings in netmap mode */ + for_rx_tx(t) { + for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { + struct netmap_kring *kring = &NMR(na, t)[i]; + + if (nm_kring_pending_on(kring)) { + kring->nr_mode = NKR_NETMAP_ON; + } + } + } + if (na->active_fds == 0) + na->na_flags |= NAF_NETMAP_ON; } else { - na->na_flags &= ~NAF_NETMAP_ON; + if (na->active_fds == 0) + na->na_flags &= ~NAF_NETMAP_ON; + for_rx_tx(t) { + for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { + struct netmap_kring *kring = &NMR(na, t)[i]; + + if (nm_kring_pending_off(kring)) { + kring->nr_mode = NKR_NETMAP_OFF; + /* mark the peer ring as no longer needed by us + * (it may still be kept if sombody else is using it) + */ + kring->pipe->nr_kflags &= ~NKR_NEEDRING; + } + } + } + /* delete all the peer rings that are no longer needed */ + netmap_mem_rings_delete(ona); } + + if (na->active_fds) { + D("active_fds %d", na->active_fds); + return 0; + } + if (pna->peer_ref) { ND("%p: case 1.a or 2.a, nothing to do", na); return 0; @@ -429,18 +454,11 @@ netmap_pipe_reg(struct netmap_adapter *na, int onoff) pna->peer->peer_ref = 0; netmap_adapter_put(na); } else { - int i; ND("%p: case 2.b, grab peer", na); netmap_adapter_get(na); pna->peer->peer_ref = 1; - /* hide our rings from netmap_mem_rings_delete */ - for_rx_tx(t) { - for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { - NMR(na, t)[i].ring = NULL; - } - } } - return 0; + return error; } /* netmap_pipe_krings_delete. @@ -470,8 +488,6 @@ netmap_pipe_krings_delete(struct netmap_adapter *na) struct netmap_pipe_adapter *pna = (struct netmap_pipe_adapter *)na; struct netmap_adapter *ona; /* na of the other end */ - int i; - enum txrx t; if (!pna->peer_ref) { ND("%p: case 2, kept alive by peer", na); @@ -480,18 +496,12 @@ netmap_pipe_krings_delete(struct netmap_adapter *na) /* case 1) above */ ND("%p: case 1, deleting everyhing", na); netmap_krings_delete(na); /* also zeroes tx_rings etc. */ - /* restore the ring to be deleted on the peer */ ona = &pna->peer->up; if (ona->tx_rings == NULL) { /* already deleted, we must be on an * cleanup-after-error path */ return; } - for_rx_tx(t) { - for (i = 0; i < nma_get_nrings(ona, t) + 1; i++) - NMR(ona, t)[i].ring = NMR(ona, t)[i].save_ring; - } - netmap_mem_rings_delete(ona); netmap_krings_delete(ona); } @@ -519,6 +529,7 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na, int create) struct nmreq pnmr; struct netmap_adapter *pna; /* parent adapter */ struct netmap_pipe_adapter *mna, *sna, *req; + struct ifnet *ifp = NULL; u_int pipe_id; int role = nmr->nr_flags & NR_REG_MASK; int error; @@ -536,7 +547,7 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na, int create) memcpy(&pnmr.nr_name, nmr->nr_name, IFNAMSIZ); /* pass to parent the requested number of pipes */ pnmr.nr_arg1 = nmr->nr_arg1; - error = netmap_get_na(&pnmr, &pna, create); + error = netmap_get_na(&pnmr, &pna, &ifp, create); if (error) { ND("parent lookup failed: %d", error); return error; @@ -652,16 +663,15 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na, int create) *na = &req->up; netmap_adapter_get(*na); - /* write the configuration back */ - nmr->nr_tx_rings = req->up.num_tx_rings; - nmr->nr_rx_rings = req->up.num_rx_rings; - nmr->nr_tx_slots = req->up.num_tx_desc; - nmr->nr_rx_slots = req->up.num_rx_desc; - /* keep the reference to the parent. * It will be released by the req destructor */ + /* drop the ifp reference, if any */ + if (ifp) { + if_rele(ifp); + } + return 0; free_sna: @@ -671,7 +681,7 @@ netmap_get_pipe_na(struct nmreq *nmr, struct netmap_adapter **na, int create) free_mna: free(mna, M_DEVBUF); put_out: - netmap_adapter_put(pna); + netmap_unget_na(pna, ifp); return error; } diff --git a/sys/dev/netmap/netmap_pt.c b/sys/dev/netmap/netmap_pt.c new file mode 100644 index 000000000000..56434a236145 --- /dev/null +++ b/sys/dev/netmap/netmap_pt.c @@ -0,0 +1,1438 @@ +/* + * Copyright (C) 2015 Stefano Garzarella + * Copyright (C) 2016 Vincenzo Maffione + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +/* + * common headers + */ +#if defined(__FreeBSD__) +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define usleep_range(_1, _2) +#define usleep_range(_1, _2) \ + pause_sbt("ptnetmap-sleep", SBT_1US * _1, SBT_1US * 1, C_ABSOLUTE) + +#elif defined(linux) +#include +#endif + +#include +#include +#include +#include + +#ifdef WITH_PTNETMAP_HOST + +/* RX cycle without receive any packets */ +#define PTN_RX_DRY_CYCLES_MAX 10 + +/* Limit Batch TX to half ring. + * Currently disabled, since it does not manage NS_MOREFRAG, which + * results in random drops in the VALE txsync. */ +//#define PTN_TX_BATCH_LIM(_n) ((_n >> 1)) + +//#define BUSY_WAIT + +#define NETMAP_PT_DEBUG /* Enables communication debugging. */ +#ifdef NETMAP_PT_DEBUG +#define DBG(x) x +#else +#define DBG(x) +#endif + + +#undef RATE +//#define RATE /* Enables communication statistics. */ +#ifdef RATE +#define IFRATE(x) x +struct rate_batch_stats { + unsigned long sync; + unsigned long sync_dry; + unsigned long pkt; +}; + +struct rate_stats { + unsigned long gtxk; /* Guest --> Host Tx kicks. */ + unsigned long grxk; /* Guest --> Host Rx kicks. */ + unsigned long htxk; /* Host --> Guest Tx kicks. */ + unsigned long hrxk; /* Host --> Guest Rx Kicks. */ + unsigned long btxwu; /* Backend Tx wake-up. */ + unsigned long brxwu; /* Backend Rx wake-up. */ + struct rate_batch_stats txbs; + struct rate_batch_stats rxbs; +}; + +struct rate_context { + struct timer_list timer; + struct rate_stats new; + struct rate_stats old; +}; + +#define RATE_PERIOD 2 +static void +rate_callback(unsigned long arg) +{ + struct rate_context * ctx = (struct rate_context *)arg; + struct rate_stats cur = ctx->new; + struct rate_batch_stats *txbs = &cur.txbs; + struct rate_batch_stats *rxbs = &cur.rxbs; + struct rate_batch_stats *txbs_old = &ctx->old.txbs; + struct rate_batch_stats *rxbs_old = &ctx->old.rxbs; + uint64_t tx_batch, rx_batch; + unsigned long txpkts, rxpkts; + unsigned long gtxk, grxk; + int r; + + txpkts = txbs->pkt - txbs_old->pkt; + rxpkts = rxbs->pkt - rxbs_old->pkt; + + tx_batch = ((txbs->sync - txbs_old->sync) > 0) ? + txpkts / (txbs->sync - txbs_old->sync): 0; + rx_batch = ((rxbs->sync - rxbs_old->sync) > 0) ? + rxpkts / (rxbs->sync - rxbs_old->sync): 0; + + /* Fix-up gtxk and grxk estimates. */ + gtxk = (cur.gtxk - ctx->old.gtxk) - (cur.btxwu - ctx->old.btxwu); + grxk = (cur.grxk - ctx->old.grxk) - (cur.brxwu - ctx->old.brxwu); + + printk("txpkts = %lu Hz\n", txpkts/RATE_PERIOD); + printk("gtxk = %lu Hz\n", gtxk/RATE_PERIOD); + printk("htxk = %lu Hz\n", (cur.htxk - ctx->old.htxk)/RATE_PERIOD); + printk("btxw = %lu Hz\n", (cur.btxwu - ctx->old.btxwu)/RATE_PERIOD); + printk("rxpkts = %lu Hz\n", rxpkts/RATE_PERIOD); + printk("grxk = %lu Hz\n", grxk/RATE_PERIOD); + printk("hrxk = %lu Hz\n", (cur.hrxk - ctx->old.hrxk)/RATE_PERIOD); + printk("brxw = %lu Hz\n", (cur.brxwu - ctx->old.brxwu)/RATE_PERIOD); + printk("txbatch = %llu avg\n", tx_batch); + printk("rxbatch = %llu avg\n", rx_batch); + printk("\n"); + + ctx->old = cur; + r = mod_timer(&ctx->timer, jiffies + + msecs_to_jiffies(RATE_PERIOD * 1000)); + if (unlikely(r)) + D("[ptnetmap] Error: mod_timer()\n"); +} + +static void +rate_batch_stats_update(struct rate_batch_stats *bf, uint32_t pre_tail, + uint32_t act_tail, uint32_t num_slots) +{ + int n = (int)act_tail - pre_tail; + + if (n) { + if (n < 0) + n += num_slots; + + bf->sync++; + bf->pkt += n; + } else { + bf->sync_dry++; + } +} + +#else /* !RATE */ +#define IFRATE(x) +#endif /* RATE */ + +struct ptnetmap_state { + /* Kthreads. */ + struct nm_kthread **kthreads; + + /* Shared memory with the guest (TX/RX) */ + struct ptnet_ring __user *ptrings; + + bool stopped; + + /* Netmap adapter wrapping the backend. */ + struct netmap_pt_host_adapter *pth_na; + + IFRATE(struct rate_context rate_ctx;) +}; + +static inline void +ptnetmap_kring_dump(const char *title, const struct netmap_kring *kring) +{ + RD(1, "%s - name: %s hwcur: %d hwtail: %d rhead: %d rcur: %d \ + rtail: %d head: %d cur: %d tail: %d", + title, kring->name, kring->nr_hwcur, + kring->nr_hwtail, kring->rhead, kring->rcur, kring->rtail, + kring->ring->head, kring->ring->cur, kring->ring->tail); +} + +/* + * TX functions to set/get and to handle host/guest kick. + */ + + +/* Enable or disable guest --> host kicks. */ +static inline void +ptring_kick_enable(struct ptnet_ring __user *ptring, uint32_t val) +{ + CSB_WRITE(ptring, host_need_kick, val); +} + +/* Are guest interrupt enabled or disabled? */ +static inline uint32_t +ptring_intr_enabled(struct ptnet_ring __user *ptring) +{ + uint32_t v; + + CSB_READ(ptring, guest_need_kick, v); + + return v; +} + +/* Enable or disable guest interrupts. */ +static inline void +ptring_intr_enable(struct ptnet_ring __user *ptring, uint32_t val) +{ + CSB_WRITE(ptring, guest_need_kick, val); +} + +/* Handle TX events: from the guest or from the backend */ +static void +ptnetmap_tx_handler(void *data) +{ + struct netmap_kring *kring = data; + struct netmap_pt_host_adapter *pth_na = + (struct netmap_pt_host_adapter *)kring->na->na_private; + struct ptnetmap_state *ptns = pth_na->ptns; + struct ptnet_ring __user *ptring; + struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */ + bool more_txspace = false; + struct nm_kthread *kth; + uint32_t num_slots; + int batch; + IFRATE(uint32_t pre_tail); + + if (unlikely(!ptns)) { + D("ERROR ptnetmap state is NULL"); + return; + } + + if (unlikely(ptns->stopped)) { + RD(1, "backend netmap is being stopped"); + return; + } + + if (unlikely(nm_kr_tryget(kring, 1, NULL))) { + D("ERROR nm_kr_tryget()"); + return; + } + + /* This is a guess, to be fixed in the rate callback. */ + IFRATE(ptns->rate_ctx.new.gtxk++); + + /* Get TX ptring pointer from the CSB. */ + ptring = ptns->ptrings + kring->ring_id; + kth = ptns->kthreads[kring->ring_id]; + + num_slots = kring->nkr_num_slots; + shadow_ring.head = kring->rhead; + shadow_ring.cur = kring->rcur; + + /* Disable guest --> host notifications. */ + ptring_kick_enable(ptring, 0); + /* Copy the guest kring pointers from the CSB */ + ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots); + + for (;;) { + /* If guest moves ahead too fast, let's cut the move so + * that we don't exceed our batch limit. */ + batch = shadow_ring.head - kring->nr_hwcur; + if (batch < 0) + batch += num_slots; + +#ifdef PTN_TX_BATCH_LIM + if (batch > PTN_TX_BATCH_LIM(num_slots)) { + uint32_t head_lim = kring->nr_hwcur + PTN_TX_BATCH_LIM(num_slots); + + if (head_lim >= num_slots) + head_lim -= num_slots; + ND(1, "batch: %d head: %d head_lim: %d", batch, shadow_ring.head, + head_lim); + shadow_ring.head = head_lim; + batch = PTN_TX_BATCH_LIM(num_slots); + } +#endif /* PTN_TX_BATCH_LIM */ + + if (nm_kr_txspace(kring) <= (num_slots >> 1)) { + shadow_ring.flags |= NAF_FORCE_RECLAIM; + } + + /* Netmap prologue */ + shadow_ring.tail = kring->rtail; + if (unlikely(nm_txsync_prologue(kring, &shadow_ring) >= num_slots)) { + /* Reinit ring and enable notifications. */ + netmap_ring_reinit(kring); + ptring_kick_enable(ptring, 1); + break; + } + + if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) { + ptnetmap_kring_dump("pre txsync", kring); + } + + IFRATE(pre_tail = kring->rtail); + if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) { + /* Reenable notifications. */ + ptring_kick_enable(ptring, 1); + D("ERROR txsync()"); + break; + } + + /* + * Finalize + * Copy host hwcur and hwtail into the CSB for the guest sync(), and + * do the nm_sync_finalize. + */ + ptnetmap_host_write_kring_csb(ptring, kring->nr_hwcur, + kring->nr_hwtail); + if (kring->rtail != kring->nr_hwtail) { + /* Some more room available in the parent adapter. */ + kring->rtail = kring->nr_hwtail; + more_txspace = true; + } + + IFRATE(rate_batch_stats_update(&ptns->rate_ctx.new.txbs, pre_tail, + kring->rtail, num_slots)); + + if (unlikely(netmap_verbose & NM_VERB_TXSYNC)) { + ptnetmap_kring_dump("post txsync", kring); + } + +#ifndef BUSY_WAIT + /* Interrupt the guest if needed. */ + if (more_txspace && ptring_intr_enabled(ptring)) { + /* Disable guest kick to avoid sending unnecessary kicks */ + ptring_intr_enable(ptring, 0); + nm_os_kthread_send_irq(kth); + IFRATE(ptns->rate_ctx.new.htxk++); + more_txspace = false; + } +#endif + /* Read CSB to see if there is more work to do. */ + ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots); +#ifndef BUSY_WAIT + if (shadow_ring.head == kring->rhead) { + /* + * No more packets to transmit. We enable notifications and + * go to sleep, waiting for a kick from the guest when new + * new slots are ready for transmission. + */ + usleep_range(1,1); + /* Reenable notifications. */ + ptring_kick_enable(ptring, 1); + /* Doublecheck. */ + ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots); + if (shadow_ring.head != kring->rhead) { + /* We won the race condition, there are more packets to + * transmit. Disable notifications and do another cycle */ + ptring_kick_enable(ptring, 0); + continue; + } + break; + } + + if (nm_kr_txempty(kring)) { + /* No more available TX slots. We stop waiting for a notification + * from the backend (netmap_tx_irq). */ + ND(1, "TX ring"); + break; + } +#endif + if (unlikely(ptns->stopped)) { + D("backend netmap is being stopped"); + break; + } + } + + nm_kr_put(kring); + + if (more_txspace && ptring_intr_enabled(ptring)) { + ptring_intr_enable(ptring, 0); + nm_os_kthread_send_irq(kth); + IFRATE(ptns->rate_ctx.new.htxk++); + } +} + +/* + * We need RX kicks from the guest when (tail == head-1), where we wait + * for the guest to refill. + */ +#ifndef BUSY_WAIT +static inline int +ptnetmap_norxslots(struct netmap_kring *kring, uint32_t g_head) +{ + return (NM_ACCESS_ONCE(kring->nr_hwtail) == nm_prev(g_head, + kring->nkr_num_slots - 1)); +} +#endif /* !BUSY_WAIT */ + +/* Handle RX events: from the guest or from the backend */ +static void +ptnetmap_rx_handler(void *data) +{ + struct netmap_kring *kring = data; + struct netmap_pt_host_adapter *pth_na = + (struct netmap_pt_host_adapter *)kring->na->na_private; + struct ptnetmap_state *ptns = pth_na->ptns; + struct ptnet_ring __user *ptring; + struct netmap_ring shadow_ring; /* shadow copy of the netmap_ring */ + struct nm_kthread *kth; + uint32_t num_slots; + int dry_cycles = 0; + bool some_recvd = false; + IFRATE(uint32_t pre_tail); + + if (unlikely(!ptns || !ptns->pth_na)) { + D("ERROR ptnetmap state %p, ptnetmap host adapter %p", ptns, + ptns ? ptns->pth_na : NULL); + return; + } + + if (unlikely(ptns->stopped)) { + RD(1, "backend netmap is being stopped"); + return; + } + + if (unlikely(nm_kr_tryget(kring, 1, NULL))) { + D("ERROR nm_kr_tryget()"); + return; + } + + /* This is a guess, to be fixed in the rate callback. */ + IFRATE(ptns->rate_ctx.new.grxk++); + + /* Get RX ptring pointer from the CSB. */ + ptring = ptns->ptrings + (pth_na->up.num_tx_rings + kring->ring_id); + kth = ptns->kthreads[pth_na->up.num_tx_rings + kring->ring_id]; + + num_slots = kring->nkr_num_slots; + shadow_ring.head = kring->rhead; + shadow_ring.cur = kring->rcur; + + /* Disable notifications. */ + ptring_kick_enable(ptring, 0); + /* Copy the guest kring pointers from the CSB */ + ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots); + + for (;;) { + uint32_t hwtail; + + /* Netmap prologue */ + shadow_ring.tail = kring->rtail; + if (unlikely(nm_rxsync_prologue(kring, &shadow_ring) >= num_slots)) { + /* Reinit ring and enable notifications. */ + netmap_ring_reinit(kring); + ptring_kick_enable(ptring, 1); + break; + } + + if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) { + ptnetmap_kring_dump("pre rxsync", kring); + } + + IFRATE(pre_tail = kring->rtail); + if (unlikely(kring->nm_sync(kring, shadow_ring.flags))) { + /* Reenable notifications. */ + ptring_kick_enable(ptring, 1); + D("ERROR rxsync()"); + break; + } + /* + * Finalize + * Copy host hwcur and hwtail into the CSB for the guest sync() + */ + hwtail = NM_ACCESS_ONCE(kring->nr_hwtail); + ptnetmap_host_write_kring_csb(ptring, kring->nr_hwcur, hwtail); + if (kring->rtail != hwtail) { + kring->rtail = hwtail; + some_recvd = true; + dry_cycles = 0; + } else { + dry_cycles++; + } + + IFRATE(rate_batch_stats_update(&ptns->rate_ctx.new.rxbs, pre_tail, + kring->rtail, num_slots)); + + if (unlikely(netmap_verbose & NM_VERB_RXSYNC)) { + ptnetmap_kring_dump("post rxsync", kring); + } + +#ifndef BUSY_WAIT + /* Interrupt the guest if needed. */ + if (some_recvd && ptring_intr_enabled(ptring)) { + /* Disable guest kick to avoid sending unnecessary kicks */ + ptring_intr_enable(ptring, 0); + nm_os_kthread_send_irq(kth); + IFRATE(ptns->rate_ctx.new.hrxk++); + some_recvd = false; + } +#endif + /* Read CSB to see if there is more work to do. */ + ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots); +#ifndef BUSY_WAIT + if (ptnetmap_norxslots(kring, shadow_ring.head)) { + /* + * No more slots available for reception. We enable notification and + * go to sleep, waiting for a kick from the guest when new receive + * slots are available. + */ + usleep_range(1,1); + /* Reenable notifications. */ + ptring_kick_enable(ptring, 1); + /* Doublecheck. */ + ptnetmap_host_read_kring_csb(ptring, &shadow_ring, num_slots); + if (!ptnetmap_norxslots(kring, shadow_ring.head)) { + /* We won the race condition, more slots are available. Disable + * notifications and do another cycle. */ + ptring_kick_enable(ptring, 0); + continue; + } + break; + } + + hwtail = NM_ACCESS_ONCE(kring->nr_hwtail); + if (unlikely(hwtail == kring->rhead || + dry_cycles >= PTN_RX_DRY_CYCLES_MAX)) { + /* No more packets to be read from the backend. We stop and + * wait for a notification from the backend (netmap_rx_irq). */ + ND(1, "nr_hwtail: %d rhead: %d dry_cycles: %d", + hwtail, kring->rhead, dry_cycles); + break; + } +#endif + if (unlikely(ptns->stopped)) { + D("backend netmap is being stopped"); + break; + } + } + + nm_kr_put(kring); + + /* Interrupt the guest if needed. */ + if (some_recvd && ptring_intr_enabled(ptring)) { + ptring_intr_enable(ptring, 0); + nm_os_kthread_send_irq(kth); + IFRATE(ptns->rate_ctx.new.hrxk++); + } +} + +#ifdef NETMAP_PT_DEBUG +static void +ptnetmap_print_configuration(struct ptnetmap_cfg *cfg) +{ + int k; + + D("[PTN] configuration:"); + D(" CSB ptrings @%p, num_rings=%u, features %08x", cfg->ptrings, + cfg->num_rings, cfg->features); + for (k = 0; k < cfg->num_rings; k++) { + D(" ring #%d: iofd=%llu, irqfd=%llu", k, + (unsigned long long)cfg->entries[k].ioeventfd, + (unsigned long long)cfg->entries[k].irqfd); + } + +} +#endif /* NETMAP_PT_DEBUG */ + +/* Copy actual state of the host ring into the CSB for the guest init */ +static int +ptnetmap_kring_snapshot(struct netmap_kring *kring, struct ptnet_ring __user *ptring) +{ + if(CSB_WRITE(ptring, head, kring->rhead)) + goto err; + if(CSB_WRITE(ptring, cur, kring->rcur)) + goto err; + + if(CSB_WRITE(ptring, hwcur, kring->nr_hwcur)) + goto err; + if(CSB_WRITE(ptring, hwtail, NM_ACCESS_ONCE(kring->nr_hwtail))) + goto err; + + DBG(ptnetmap_kring_dump("ptnetmap_kring_snapshot", kring);) + + return 0; +err: + return EFAULT; +} + +static struct netmap_kring * +ptnetmap_kring(struct netmap_pt_host_adapter *pth_na, int k) +{ + if (k < pth_na->up.num_tx_rings) { + return pth_na->up.tx_rings + k; + } + return pth_na->up.rx_rings + k - pth_na->up.num_tx_rings; +} + +static int +ptnetmap_krings_snapshot(struct netmap_pt_host_adapter *pth_na) +{ + struct ptnetmap_state *ptns = pth_na->ptns; + struct netmap_kring *kring; + unsigned int num_rings; + int err = 0, k; + + num_rings = pth_na->up.num_tx_rings + + pth_na->up.num_rx_rings; + + for (k = 0; k < num_rings; k++) { + kring = ptnetmap_kring(pth_na, k); + err |= ptnetmap_kring_snapshot(kring, ptns->ptrings + k); + } + + return err; +} + +/* + * Functions to create, start and stop the kthreads + */ + +static int +ptnetmap_create_kthreads(struct netmap_pt_host_adapter *pth_na, + struct ptnetmap_cfg *cfg) +{ + struct ptnetmap_state *ptns = pth_na->ptns; + struct nm_kthread_cfg nmk_cfg; + unsigned int num_rings; + int k; + + num_rings = pth_na->up.num_tx_rings + + pth_na->up.num_rx_rings; + + for (k = 0; k < num_rings; k++) { + nmk_cfg.attach_user = 1; /* attach kthread to user process */ + nmk_cfg.worker_private = ptnetmap_kring(pth_na, k); + nmk_cfg.event = *(cfg->entries + k); + nmk_cfg.type = k; + if (k < pth_na->up.num_tx_rings) { + nmk_cfg.worker_fn = ptnetmap_tx_handler; + } else { + nmk_cfg.worker_fn = ptnetmap_rx_handler; + } + + ptns->kthreads[k] = nm_os_kthread_create(&nmk_cfg); + if (ptns->kthreads[k] == NULL) { + goto err; + } + } + + return 0; +err: + for (k = 0; k < num_rings; k++) { + if (ptns->kthreads[k]) { + nm_os_kthread_delete(ptns->kthreads[k]); + ptns->kthreads[k] = NULL; + } + } + return EFAULT; +} + +static int +ptnetmap_start_kthreads(struct netmap_pt_host_adapter *pth_na) +{ + struct ptnetmap_state *ptns = pth_na->ptns; + int num_rings; + int error; + int k; + + if (!ptns) { + D("BUG ptns is NULL"); + return EFAULT; + } + + ptns->stopped = false; + + num_rings = ptns->pth_na->up.num_tx_rings + + ptns->pth_na->up.num_rx_rings; + for (k = 0; k < num_rings; k++) { + //nm_os_kthread_set_affinity(ptns->kthreads[k], xxx); + error = nm_os_kthread_start(ptns->kthreads[k]); + if (error) { + return error; + } + } + + return 0; +} + +static void +ptnetmap_stop_kthreads(struct netmap_pt_host_adapter *pth_na) +{ + struct ptnetmap_state *ptns = pth_na->ptns; + int num_rings; + int k; + + if (!ptns) { + /* Nothing to do. */ + return; + } + + ptns->stopped = true; + + num_rings = ptns->pth_na->up.num_tx_rings + + ptns->pth_na->up.num_rx_rings; + for (k = 0; k < num_rings; k++) { + nm_os_kthread_stop(ptns->kthreads[k]); + } +} + +static struct ptnetmap_cfg * +ptnetmap_read_cfg(struct nmreq *nmr) +{ + uintptr_t *nmr_ptncfg = (uintptr_t *)&nmr->nr_arg1; + struct ptnetmap_cfg *cfg; + struct ptnetmap_cfg tmp; + size_t cfglen; + + if (copyin((const void *)*nmr_ptncfg, &tmp, sizeof(tmp))) { + D("Partial copyin() failed"); + return NULL; + } + + cfglen = sizeof(tmp) + tmp.num_rings * sizeof(struct ptnet_ring_cfg); + cfg = malloc(cfglen, M_DEVBUF, M_NOWAIT | M_ZERO); + if (!cfg) { + return NULL; + } + + if (copyin((const void *)*nmr_ptncfg, cfg, cfglen)) { + D("Full copyin() failed"); + free(cfg, M_DEVBUF); + return NULL; + } + + return cfg; +} + +static int nm_unused_notify(struct netmap_kring *, int); +static int nm_pt_host_notify(struct netmap_kring *, int); + +/* Create ptnetmap state and switch parent adapter to ptnetmap mode. */ +static int +ptnetmap_create(struct netmap_pt_host_adapter *pth_na, + struct ptnetmap_cfg *cfg) +{ + unsigned ft_mask = (PTNETMAP_CFG_FEAT_CSB | PTNETMAP_CFG_FEAT_EVENTFD); + struct ptnetmap_state *ptns; + unsigned int num_rings; + int ret, i; + + /* Check if ptnetmap state is already there. */ + if (pth_na->ptns) { + D("ERROR adapter %p already in ptnetmap mode", pth_na->parent); + return EINVAL; + } + + if ((cfg->features & ft_mask) != ft_mask) { + D("ERROR ptnetmap_cfg(%x) does not contain CSB and EVENTFD", + cfg->features); + return EINVAL; + } + + num_rings = pth_na->up.num_tx_rings + pth_na->up.num_rx_rings; + + if (num_rings != cfg->num_rings) { + D("ERROR configuration mismatch, expected %u rings, found %u", + num_rings, cfg->num_rings); + return EINVAL; + } + + ptns = malloc(sizeof(*ptns) + num_rings * sizeof(*ptns->kthreads), + M_DEVBUF, M_NOWAIT | M_ZERO); + if (!ptns) { + return ENOMEM; + } + + ptns->kthreads = (struct nm_kthread **)(ptns + 1); + ptns->stopped = true; + + /* Cross-link data structures. */ + pth_na->ptns = ptns; + ptns->pth_na = pth_na; + + /* Store the CSB address provided by the hypervisor. */ + ptns->ptrings = cfg->ptrings; + + DBG(ptnetmap_print_configuration(cfg)); + + /* Create kthreads */ + if ((ret = ptnetmap_create_kthreads(pth_na, cfg))) { + D("ERROR ptnetmap_create_kthreads()"); + goto err; + } + /* Copy krings state into the CSB for the guest initialization */ + if ((ret = ptnetmap_krings_snapshot(pth_na))) { + D("ERROR ptnetmap_krings_snapshot()"); + goto err; + } + + /* Overwrite parent nm_notify krings callback. */ + pth_na->parent->na_private = pth_na; + pth_na->parent_nm_notify = pth_na->parent->nm_notify; + pth_na->parent->nm_notify = nm_unused_notify; + + for (i = 0; i < pth_na->parent->num_rx_rings; i++) { + pth_na->up.rx_rings[i].save_notify = + pth_na->up.rx_rings[i].nm_notify; + pth_na->up.rx_rings[i].nm_notify = nm_pt_host_notify; + } + for (i = 0; i < pth_na->parent->num_tx_rings; i++) { + pth_na->up.tx_rings[i].save_notify = + pth_na->up.tx_rings[i].nm_notify; + pth_na->up.tx_rings[i].nm_notify = nm_pt_host_notify; + } + +#ifdef RATE + memset(&ptns->rate_ctx, 0, sizeof(ptns->rate_ctx)); + setup_timer(&ptns->rate_ctx.timer, &rate_callback, + (unsigned long)&ptns->rate_ctx); + if (mod_timer(&ptns->rate_ctx.timer, jiffies + msecs_to_jiffies(1500))) + D("[ptn] Error: mod_timer()\n"); +#endif + + DBG(D("[%s] ptnetmap configuration DONE", pth_na->up.name)); + + return 0; + +err: + pth_na->ptns = NULL; + free(ptns, M_DEVBUF); + return ret; +} + +/* Switch parent adapter back to normal mode and destroy + * ptnetmap state. */ +static void +ptnetmap_delete(struct netmap_pt_host_adapter *pth_na) +{ + struct ptnetmap_state *ptns = pth_na->ptns; + int num_rings; + int i; + + if (!ptns) { + /* Nothing to do. */ + return; + } + + /* Restore parent adapter callbacks. */ + pth_na->parent->nm_notify = pth_na->parent_nm_notify; + pth_na->parent->na_private = NULL; + + for (i = 0; i < pth_na->parent->num_rx_rings; i++) { + pth_na->up.rx_rings[i].nm_notify = + pth_na->up.rx_rings[i].save_notify; + pth_na->up.rx_rings[i].save_notify = NULL; + } + for (i = 0; i < pth_na->parent->num_tx_rings; i++) { + pth_na->up.tx_rings[i].nm_notify = + pth_na->up.tx_rings[i].save_notify; + pth_na->up.tx_rings[i].save_notify = NULL; + } + + /* Delete kthreads. */ + num_rings = ptns->pth_na->up.num_tx_rings + + ptns->pth_na->up.num_rx_rings; + for (i = 0; i < num_rings; i++) { + nm_os_kthread_delete(ptns->kthreads[i]); + ptns->kthreads[i] = NULL; + } + + IFRATE(del_timer(&ptns->rate_ctx.timer)); + + free(ptns, M_DEVBUF); + + pth_na->ptns = NULL; + + DBG(D("[%s] ptnetmap deleted", pth_na->up.name)); +} + +/* + * Called by netmap_ioctl(). + * Operation is indicated in nmr->nr_cmd. + * + * Called without NMG_LOCK. + */ +int +ptnetmap_ctl(struct nmreq *nmr, struct netmap_adapter *na) +{ + struct netmap_pt_host_adapter *pth_na; + struct ptnetmap_cfg *cfg; + char *name; + int cmd, error = 0; + + name = nmr->nr_name; + cmd = nmr->nr_cmd; + + DBG(D("name: %s", name)); + + if (!nm_ptnetmap_host_on(na)) { + D("ERROR Netmap adapter %p is not a ptnetmap host adapter", na); + error = ENXIO; + goto done; + } + pth_na = (struct netmap_pt_host_adapter *)na; + + NMG_LOCK(); + switch (cmd) { + case NETMAP_PT_HOST_CREATE: + /* Read hypervisor configuration from userspace. */ + cfg = ptnetmap_read_cfg(nmr); + if (!cfg) + break; + /* Create ptnetmap state (kthreads, ...) and switch parent + * adapter to ptnetmap mode. */ + error = ptnetmap_create(pth_na, cfg); + free(cfg, M_DEVBUF); + if (error) + break; + /* Start kthreads. */ + error = ptnetmap_start_kthreads(pth_na); + if (error) + ptnetmap_delete(pth_na); + break; + + case NETMAP_PT_HOST_DELETE: + /* Stop kthreads. */ + ptnetmap_stop_kthreads(pth_na); + /* Switch parent adapter back to normal mode and destroy + * ptnetmap state (kthreads, ...). */ + ptnetmap_delete(pth_na); + break; + + default: + D("ERROR invalid cmd (nmr->nr_cmd) (0x%x)", cmd); + error = EINVAL; + break; + } + NMG_UNLOCK(); + +done: + return error; +} + +/* nm_notify callbacks for ptnetmap */ +static int +nm_pt_host_notify(struct netmap_kring *kring, int flags) +{ + struct netmap_adapter *na = kring->na; + struct netmap_pt_host_adapter *pth_na = + (struct netmap_pt_host_adapter *)na->na_private; + struct ptnetmap_state *ptns; + int k; + + /* First check that the passthrough port is not being destroyed. */ + if (unlikely(!pth_na)) { + return NM_IRQ_COMPLETED; + } + + ptns = pth_na->ptns; + if (unlikely(!ptns || ptns->stopped)) { + return NM_IRQ_COMPLETED; + } + + k = kring->ring_id; + + /* Notify kthreads (wake up if needed) */ + if (kring->tx == NR_TX) { + ND(1, "TX backend irq"); + IFRATE(ptns->rate_ctx.new.btxwu++); + } else { + k += pth_na->up.num_tx_rings; + ND(1, "RX backend irq"); + IFRATE(ptns->rate_ctx.new.brxwu++); + } + nm_os_kthread_wakeup_worker(ptns->kthreads[k]); + + return NM_IRQ_COMPLETED; +} + +static int +nm_unused_notify(struct netmap_kring *kring, int flags) +{ + D("BUG this should never be called"); + return ENXIO; +} + +/* nm_config callback for bwrap */ +static int +nm_pt_host_config(struct netmap_adapter *na, u_int *txr, u_int *txd, + u_int *rxr, u_int *rxd) +{ + struct netmap_pt_host_adapter *pth_na = + (struct netmap_pt_host_adapter *)na; + struct netmap_adapter *parent = pth_na->parent; + int error; + + //XXX: maybe calling parent->nm_config is better + + /* forward the request */ + error = netmap_update_config(parent); + + *rxr = na->num_rx_rings = parent->num_rx_rings; + *txr = na->num_tx_rings = parent->num_tx_rings; + *txd = na->num_tx_desc = parent->num_tx_desc; + *rxd = na->num_rx_desc = parent->num_rx_desc; + + DBG(D("rxr: %d txr: %d txd: %d rxd: %d", *rxr, *txr, *txd, *rxd)); + + return error; +} + +/* nm_krings_create callback for ptnetmap */ +static int +nm_pt_host_krings_create(struct netmap_adapter *na) +{ + struct netmap_pt_host_adapter *pth_na = + (struct netmap_pt_host_adapter *)na; + struct netmap_adapter *parent = pth_na->parent; + enum txrx t; + int error; + + DBG(D("%s", pth_na->up.name)); + + /* create the parent krings */ + error = parent->nm_krings_create(parent); + if (error) { + return error; + } + + /* A ptnetmap host adapter points the very same krings + * as its parent adapter. These pointer are used in the + * TX/RX worker functions. */ + na->tx_rings = parent->tx_rings; + na->rx_rings = parent->rx_rings; + na->tailroom = parent->tailroom; + + for_rx_tx(t) { + struct netmap_kring *kring; + + /* Parent's kring_create function will initialize + * its own na->si. We have to init our na->si here. */ + nm_os_selinfo_init(&na->si[t]); + + /* Force the mem_rings_create() method to create the + * host rings independently on what the regif asked for: + * these rings are needed by the guest ptnetmap adapter + * anyway. */ + kring = &NMR(na, t)[nma_get_nrings(na, t)]; + kring->nr_kflags |= NKR_NEEDRING; + } + + return 0; +} + +/* nm_krings_delete callback for ptnetmap */ +static void +nm_pt_host_krings_delete(struct netmap_adapter *na) +{ + struct netmap_pt_host_adapter *pth_na = + (struct netmap_pt_host_adapter *)na; + struct netmap_adapter *parent = pth_na->parent; + + DBG(D("%s", pth_na->up.name)); + + parent->nm_krings_delete(parent); + + na->tx_rings = na->rx_rings = na->tailroom = NULL; +} + +/* nm_register callback */ +static int +nm_pt_host_register(struct netmap_adapter *na, int onoff) +{ + struct netmap_pt_host_adapter *pth_na = + (struct netmap_pt_host_adapter *)na; + struct netmap_adapter *parent = pth_na->parent; + int error; + DBG(D("%s onoff %d", pth_na->up.name, onoff)); + + if (onoff) { + /* netmap_do_regif has been called on the ptnetmap na. + * We need to pass the information about the + * memory allocator to the parent before + * putting it in netmap mode + */ + parent->na_lut = na->na_lut; + } + + /* forward the request to the parent */ + error = parent->nm_register(parent, onoff); + if (error) + return error; + + + if (onoff) { + na->na_flags |= NAF_NETMAP_ON | NAF_PTNETMAP_HOST; + } else { + ptnetmap_delete(pth_na); + na->na_flags &= ~(NAF_NETMAP_ON | NAF_PTNETMAP_HOST); + } + + return 0; +} + +/* nm_dtor callback */ +static void +nm_pt_host_dtor(struct netmap_adapter *na) +{ + struct netmap_pt_host_adapter *pth_na = + (struct netmap_pt_host_adapter *)na; + struct netmap_adapter *parent = pth_na->parent; + + DBG(D("%s", pth_na->up.name)); + + /* The equivalent of NETMAP_PT_HOST_DELETE if the hypervisor + * didn't do it. */ + ptnetmap_stop_kthreads(pth_na); + ptnetmap_delete(pth_na); + + parent->na_flags &= ~NAF_BUSY; + + netmap_adapter_put(pth_na->parent); + pth_na->parent = NULL; +} + +/* check if nmr is a request for a ptnetmap adapter that we can satisfy */ +int +netmap_get_pt_host_na(struct nmreq *nmr, struct netmap_adapter **na, int create) +{ + struct nmreq parent_nmr; + struct netmap_adapter *parent; /* target adapter */ + struct netmap_pt_host_adapter *pth_na; + struct ifnet *ifp = NULL; + int error; + + /* Check if it is a request for a ptnetmap adapter */ + if ((nmr->nr_flags & (NR_PTNETMAP_HOST)) == 0) { + return 0; + } + + D("Requesting a ptnetmap host adapter"); + + pth_na = malloc(sizeof(*pth_na), M_DEVBUF, M_NOWAIT | M_ZERO); + if (pth_na == NULL) { + D("ERROR malloc"); + return ENOMEM; + } + + /* first, try to find the adapter that we want to passthrough + * We use the same nmr, after we have turned off the ptnetmap flag. + * In this way we can potentially passthrough everything netmap understands. + */ + memcpy(&parent_nmr, nmr, sizeof(parent_nmr)); + parent_nmr.nr_flags &= ~(NR_PTNETMAP_HOST); + error = netmap_get_na(&parent_nmr, &parent, &ifp, create); + if (error) { + D("parent lookup failed: %d", error); + goto put_out_noputparent; + } + DBG(D("found parent: %s", parent->name)); + + /* make sure the interface is not already in use */ + if (NETMAP_OWNED_BY_ANY(parent)) { + D("NIC %s busy, cannot ptnetmap", parent->name); + error = EBUSY; + goto put_out; + } + + pth_na->parent = parent; + + /* Follow netmap_attach()-like operations for the host + * ptnetmap adapter. */ + + //XXX pth_na->up.na_flags = parent->na_flags; + pth_na->up.num_rx_rings = parent->num_rx_rings; + pth_na->up.num_tx_rings = parent->num_tx_rings; + pth_na->up.num_tx_desc = parent->num_tx_desc; + pth_na->up.num_rx_desc = parent->num_rx_desc; + + pth_na->up.nm_dtor = nm_pt_host_dtor; + pth_na->up.nm_register = nm_pt_host_register; + + /* Reuse parent's adapter txsync and rxsync methods. */ + pth_na->up.nm_txsync = parent->nm_txsync; + pth_na->up.nm_rxsync = parent->nm_rxsync; + + pth_na->up.nm_krings_create = nm_pt_host_krings_create; + pth_na->up.nm_krings_delete = nm_pt_host_krings_delete; + pth_na->up.nm_config = nm_pt_host_config; + + /* Set the notify method only or convenience, it will never + * be used, since - differently from default krings_create - we + * ptnetmap krings_create callback inits kring->nm_notify + * directly. */ + pth_na->up.nm_notify = nm_unused_notify; + + pth_na->up.nm_mem = parent->nm_mem; + + pth_na->up.na_flags |= NAF_HOST_RINGS; + + error = netmap_attach_common(&pth_na->up); + if (error) { + D("ERROR netmap_attach_common()"); + goto put_out; + } + + *na = &pth_na->up; + netmap_adapter_get(*na); + + /* set parent busy, because attached for ptnetmap */ + parent->na_flags |= NAF_BUSY; + + strncpy(pth_na->up.name, parent->name, sizeof(pth_na->up.name)); + strcat(pth_na->up.name, "-PTN"); + + DBG(D("%s ptnetmap request DONE", pth_na->up.name)); + + /* drop the reference to the ifp, if any */ + if (ifp) + if_rele(ifp); + + return 0; + +put_out: + netmap_adapter_put(parent); + if (ifp) + if_rele(ifp); +put_out_noputparent: + free(pth_na, M_DEVBUF); + return error; +} +#endif /* WITH_PTNETMAP_HOST */ + +#ifdef WITH_PTNETMAP_GUEST +/* + * GUEST ptnetmap generic txsync()/rxsync() used in e1000/virtio-net device + * driver notify is set when we need to send notification to the host + * (driver-specific) + */ + +/* + * Reconcile host and guest views of the transmit ring. + * + * Guest user wants to transmit packets up to the one before ring->head, + * and guest kernel knows tx_ring->hwcur is the first packet unsent + * by the host kernel. + * + * We push out as many packets as possible, and possibly + * reclaim buffers from previously completed transmission. + * + * Notifications from the host are enabled only if the user guest would + * block (no space in the ring). + */ +bool +netmap_pt_guest_txsync(struct ptnet_ring *ptring, struct netmap_kring *kring, + int flags) +{ + bool notify = false; + + /* Disable notifications */ + ptring->guest_need_kick = 0; + + /* + * First part: tell the host (updating the CSB) to process the new + * packets. + */ + kring->nr_hwcur = ptring->hwcur; + ptnetmap_guest_write_kring_csb(ptring, kring->rcur, kring->rhead); + + /* Ask for a kick from a guest to the host if needed. */ + if ((kring->rhead != kring->nr_hwcur && + NM_ACCESS_ONCE(ptring->host_need_kick)) || + (flags & NAF_FORCE_RECLAIM)) { + ptring->sync_flags = flags; + notify = true; + } + + /* + * Second part: reclaim buffers for completed transmissions. + */ + if (nm_kr_txempty(kring) || (flags & NAF_FORCE_RECLAIM)) { + ptnetmap_guest_read_kring_csb(ptring, kring); + } + + /* + * No more room in the ring for new transmissions. The user thread will + * go to sleep and we need to be notified by the host when more free + * space is available. + */ + if (nm_kr_txempty(kring)) { + /* Reenable notifications. */ + ptring->guest_need_kick = 1; + /* Double check */ + ptnetmap_guest_read_kring_csb(ptring, kring); + /* If there is new free space, disable notifications */ + if (unlikely(!nm_kr_txempty(kring))) { + ptring->guest_need_kick = 0; + } + } + + ND(1, "TX - CSB: head:%u cur:%u hwtail:%u - KRING: head:%u cur:%u tail: %u", + ptring->head, ptring->cur, ptring->hwtail, + kring->rhead, kring->rcur, kring->nr_hwtail); + + return notify; +} + +/* + * Reconcile host and guest view of the receive ring. + * + * Update hwcur/hwtail from host (reading from CSB). + * + * If guest user has released buffers up to the one before ring->head, we + * also give them to the host. + * + * Notifications from the host are enabled only if the user guest would + * block (no more completed slots in the ring). + */ +bool +netmap_pt_guest_rxsync(struct ptnet_ring *ptring, struct netmap_kring *kring, + int flags) +{ + bool notify = false; + + /* Disable notifications */ + ptring->guest_need_kick = 0; + + /* + * First part: import newly received packets, by updating the kring + * hwtail to the hwtail known from the host (read from the CSB). + * This also updates the kring hwcur. + */ + ptnetmap_guest_read_kring_csb(ptring, kring); + kring->nr_kflags &= ~NKR_PENDINTR; + + /* + * Second part: tell the host about the slots that guest user has + * released, by updating cur and head in the CSB. + */ + if (kring->rhead != kring->nr_hwcur) { + ptnetmap_guest_write_kring_csb(ptring, kring->rcur, + kring->rhead); + /* Ask for a kick from the guest to the host if needed. */ + if (NM_ACCESS_ONCE(ptring->host_need_kick)) { + ptring->sync_flags = flags; + notify = true; + } + } + + /* + * No more completed RX slots. The user thread will go to sleep and + * we need to be notified by the host when more RX slots have been + * completed. + */ + if (nm_kr_rxempty(kring)) { + /* Reenable notifications. */ + ptring->guest_need_kick = 1; + /* Double check */ + ptnetmap_guest_read_kring_csb(ptring, kring); + /* If there are new slots, disable notifications. */ + if (!nm_kr_rxempty(kring)) { + ptring->guest_need_kick = 0; + } + } + + ND(1, "RX - CSB: head:%u cur:%u hwtail:%u - KRING: head:%u cur:%u", + ptring->head, ptring->cur, ptring->hwtail, + kring->rhead, kring->rcur); + + return notify; +} + +/* + * Callbacks for ptnet drivers: nm_krings_create, nm_krings_delete, nm_dtor. + */ +int +ptnet_nm_krings_create(struct netmap_adapter *na) +{ + struct netmap_pt_guest_adapter *ptna = + (struct netmap_pt_guest_adapter *)na; /* Upcast. */ + struct netmap_adapter *na_nm = &ptna->hwup.up; + struct netmap_adapter *na_dr = &ptna->dr.up; + int ret; + + if (ptna->backend_regifs) { + return 0; + } + + /* Create krings on the public netmap adapter. */ + ret = netmap_hw_krings_create(na_nm); + if (ret) { + return ret; + } + + /* Copy krings into the netmap adapter private to the driver. */ + na_dr->tx_rings = na_nm->tx_rings; + na_dr->rx_rings = na_nm->rx_rings; + + return 0; +} + +void +ptnet_nm_krings_delete(struct netmap_adapter *na) +{ + struct netmap_pt_guest_adapter *ptna = + (struct netmap_pt_guest_adapter *)na; /* Upcast. */ + struct netmap_adapter *na_nm = &ptna->hwup.up; + struct netmap_adapter *na_dr = &ptna->dr.up; + + if (ptna->backend_regifs) { + return; + } + + na_dr->tx_rings = NULL; + na_dr->rx_rings = NULL; + + netmap_hw_krings_delete(na_nm); +} + +void +ptnet_nm_dtor(struct netmap_adapter *na) +{ + struct netmap_pt_guest_adapter *ptna = + (struct netmap_pt_guest_adapter *)na; + + netmap_mem_put(ptna->dr.up.nm_mem); + memset(&ptna->dr, 0, sizeof(ptna->dr)); + netmap_mem_pt_guest_ifp_del(na->nm_mem, na->ifp); +} + +#endif /* WITH_PTNETMAP_GUEST */ diff --git a/sys/dev/netmap/netmap_vale.c b/sys/dev/netmap/netmap_vale.c index ddd7334a8378..78c53409c0b3 100644 --- a/sys/dev/netmap/netmap_vale.c +++ b/sys/dev/netmap/netmap_vale.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved. + * Copyright (C) 2013-2016 Universita` di Pisa + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -101,6 +102,9 @@ __FBSDID("$FreeBSD$"); #warning OSX support is only partial #include "osx_glue.h" +#elif defined(_WIN32) +#include "win_glue.h" + #else #error Unsupported platform @@ -119,7 +123,7 @@ __FBSDID("$FreeBSD$"); /* * system parameters (most of them in netmap_kern.h) - * NM_NAME prefix for switch port names, default "vale" + * NM_BDG_NAME prefix for switch port names, default "vale" * NM_BDG_MAXPORTS number of ports * NM_BRIDGES max number of switches in the system. * XXX should become a sysctl or tunable @@ -144,7 +148,6 @@ __FBSDID("$FreeBSD$"); #define NM_BDG_BATCH_MAX (NM_BDG_BATCH + NM_MULTISEG) /* NM_FT_NULL terminates a list of slots in the ft */ #define NM_FT_NULL NM_BDG_BATCH_MAX -#define NM_BRIDGES 8 /* number of bridges */ /* @@ -152,14 +155,15 @@ __FBSDID("$FreeBSD$"); * used in the bridge. The actual value may be larger as the * last packet in the block may overflow the size. */ -int bridge_batch = NM_BDG_BATCH; /* bridge batch size */ +static int bridge_batch = NM_BDG_BATCH; /* bridge batch size */ +SYSBEGIN(vars_vale); SYSCTL_DECL(_dev_netmap); SYSCTL_INT(_dev_netmap, OID_AUTO, bridge_batch, CTLFLAG_RW, &bridge_batch, 0 , ""); - +SYSEND; static int netmap_vp_create(struct nmreq *, struct ifnet *, struct netmap_vp_adapter **); static int netmap_vp_reg(struct netmap_adapter *na, int onoff); -static int netmap_bwrap_register(struct netmap_adapter *, int onoff); +static int netmap_bwrap_reg(struct netmap_adapter *, int onoff); /* * For each output interface, nm_bdg_q is used to construct a list. @@ -213,7 +217,7 @@ struct nm_bridge { * forward this packet. ring_nr is the source ring index, and the * function may overwrite this value to forward this packet to a * different ring index. - * This function must be set by netmap_bdgctl(). + * This function must be set by netmap_bdg_ctl(). */ struct netmap_bdg_ops bdg_ops; @@ -244,7 +248,7 @@ netmap_bdg_name(struct netmap_vp_adapter *vp) * Right now we have a static array and deletions are protected * by an exclusive lock. */ -struct nm_bridge *nm_bridges; +static struct nm_bridge *nm_bridges; #endif /* !CONFIG_NET_NS */ @@ -278,6 +282,45 @@ pkt_copy(void *_src, void *_dst, int l) } +static int +nm_is_id_char(const char c) +{ + return (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + (c == '_'); +} + +/* Validate the name of a VALE bridge port and return the + * position of the ":" character. */ +static int +nm_vale_name_validate(const char *name) +{ + int colon_pos = -1; + int i; + + if (!name || strlen(name) < strlen(NM_BDG_NAME)) { + return -1; + } + + for (i = 0; name[i]; i++) { + if (name[i] == ':') { + if (colon_pos != -1) { + return -1; + } + colon_pos = i; + } else if (!nm_is_id_char(name[i])) { + return -1; + } + } + + if (i >= IFNAMSIZ) { + return -1; + } + + return colon_pos; +} + /* * locate a bridge among the existing ones. * MUST BE CALLED WITH NMG_LOCK() @@ -288,7 +331,7 @@ pkt_copy(void *_src, void *_dst, int l) static struct nm_bridge * nm_find_bridge(const char *name, int create) { - int i, l, namelen; + int i, namelen; struct nm_bridge *b = NULL, *bridges; u_int num_bridges; @@ -296,21 +339,11 @@ nm_find_bridge(const char *name, int create) netmap_bns_getbridges(&bridges, &num_bridges); - namelen = strlen(NM_NAME); /* base length */ - l = name ? strlen(name) : 0; /* actual length */ - if (l < namelen) { + namelen = nm_vale_name_validate(name); + if (namelen < 0) { D("invalid bridge name %s", name ? name : NULL); return NULL; } - for (i = namelen + 1; i < l; i++) { - if (name[i] == ':') { - namelen = i; - break; - } - } - if (namelen >= IFNAMSIZ) - namelen = IFNAMSIZ; - ND("--- prefix is '%.*s' ---", namelen, name); /* lookup the name, remember empty slot if there is one */ for (i = 0; i < num_bridges; i++) { @@ -479,6 +512,7 @@ netmap_vp_bdg_ctl(struct netmap_adapter *na, struct nmreq *nmr, int attach) struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter *)na; struct nm_bridge *b = vpna->na_bdg; + (void)nmr; // XXX merge ? if (attach) return 0; /* nothing to do */ if (b) { @@ -518,7 +552,7 @@ nm_vi_destroy(const char *name) return ENXIO; NMG_LOCK(); /* make sure this is actually a VALE port */ - if (!NETMAP_CAPABLE(ifp) || NA(ifp)->nm_register != netmap_vp_reg) { + if (!NM_NA_VALID(ifp) || NA(ifp)->nm_register != netmap_vp_reg) { error = EINVAL; goto err; } @@ -535,7 +569,7 @@ nm_vi_destroy(const char *name) */ if_rele(ifp); netmap_detach(ifp); - nm_vi_detach(ifp); + nm_os_vi_detach(ifp); return 0; err: @@ -556,14 +590,14 @@ nm_vi_create(struct nmreq *nmr) int error; /* don't include VALE prefix */ - if (!strncmp(nmr->nr_name, NM_NAME, strlen(NM_NAME))) + if (!strncmp(nmr->nr_name, NM_BDG_NAME, strlen(NM_BDG_NAME))) return EINVAL; ifp = ifunit_ref(nmr->nr_name); if (ifp) { /* already exist, cannot create new one */ if_rele(ifp); return EEXIST; } - error = nm_vi_persist(nmr->nr_name, &ifp); + error = nm_os_vi_persist(nmr->nr_name, &ifp); if (error) return error; @@ -572,12 +606,13 @@ nm_vi_create(struct nmreq *nmr) error = netmap_vp_create(nmr, ifp, &vpna); if (error) { D("error %d", error); - nm_vi_detach(ifp); + nm_os_vi_detach(ifp); return error; } /* persist-specific routines */ vpna->up.nm_bdg_ctl = netmap_vp_bdg_ctl; netmap_adapter_get(&vpna->up); + NM_ATTACH_NA(ifp, &vpna->up); NMG_UNLOCK(); D("created %s", ifp->if_xname); return 0; @@ -608,7 +643,7 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create) /* first try to see if this is a bridge port. */ NMG_LOCK_ASSERT(); - if (strncmp(nr_name, NM_NAME, sizeof(NM_NAME) - 1)) { + if (strncmp(nr_name, NM_BDG_NAME, sizeof(NM_BDG_NAME) - 1)) { return 0; /* no error, but no VALE prefix */ } @@ -693,7 +728,6 @@ netmap_get_bdg_na(struct nmreq *nmr, struct netmap_adapter **na, int create) goto out; vpna = hw->na_vp; hostna = hw->na_hostvp; - if_rele(ifp); if (nmr->nr_arg1 != NETMAP_BDG_HOST) hostna = NULL; } @@ -768,6 +802,11 @@ nm_bdg_ctl_attach(struct nmreq *nmr) return error; } +static inline int +nm_is_bwrap(struct netmap_adapter *na) +{ + return na->nm_register == netmap_bwrap_reg; +} /* process NETMAP_BDG_DETACH */ static int @@ -785,8 +824,13 @@ nm_bdg_ctl_detach(struct nmreq *nmr) if (na == NULL) { /* VALE prefix missing */ error = EINVAL; goto unlock_exit; + } else if (nm_is_bwrap(na) && + ((struct netmap_bwrap_adapter *)na)->na_polling_state) { + /* Don't detach a NIC with polling */ + error = EBUSY; + netmap_adapter_put(na); + goto unlock_exit; } - if (na->nm_bdg_ctl) { /* remove the port from bridge. The bwrap * also needs to put the hwna in normal mode @@ -801,6 +845,267 @@ nm_bdg_ctl_detach(struct nmreq *nmr) } +struct nm_bdg_polling_state; +struct +nm_bdg_kthread { + struct nm_kthread *nmk; + u_int qfirst; + u_int qlast; + struct nm_bdg_polling_state *bps; +}; + +struct nm_bdg_polling_state { + bool configured; + bool stopped; + struct netmap_bwrap_adapter *bna; + u_int reg; + u_int qfirst; + u_int qlast; + u_int cpu_from; + u_int ncpus; + struct nm_bdg_kthread *kthreads; +}; + +static void +netmap_bwrap_polling(void *data) +{ + struct nm_bdg_kthread *nbk = data; + struct netmap_bwrap_adapter *bna; + u_int qfirst, qlast, i; + struct netmap_kring *kring0, *kring; + + if (!nbk) + return; + qfirst = nbk->qfirst; + qlast = nbk->qlast; + bna = nbk->bps->bna; + kring0 = NMR(bna->hwna, NR_RX); + + for (i = qfirst; i < qlast; i++) { + kring = kring0 + i; + kring->nm_notify(kring, 0); + } +} + +static int +nm_bdg_create_kthreads(struct nm_bdg_polling_state *bps) +{ + struct nm_kthread_cfg kcfg; + int i, j; + + bps->kthreads = malloc(sizeof(struct nm_bdg_kthread) * bps->ncpus, + M_DEVBUF, M_NOWAIT | M_ZERO); + if (bps->kthreads == NULL) + return ENOMEM; + + bzero(&kcfg, sizeof(kcfg)); + kcfg.worker_fn = netmap_bwrap_polling; + for (i = 0; i < bps->ncpus; i++) { + struct nm_bdg_kthread *t = bps->kthreads + i; + int all = (bps->ncpus == 1 && bps->reg == NR_REG_ALL_NIC); + int affinity = bps->cpu_from + i; + + t->bps = bps; + t->qfirst = all ? bps->qfirst /* must be 0 */: affinity; + t->qlast = all ? bps->qlast : t->qfirst + 1; + D("kthread %d a:%u qf:%u ql:%u", i, affinity, t->qfirst, + t->qlast); + + kcfg.type = i; + kcfg.worker_private = t; + t->nmk = nm_os_kthread_create(&kcfg); + if (t->nmk == NULL) { + goto cleanup; + } + nm_os_kthread_set_affinity(t->nmk, affinity); + } + return 0; + +cleanup: + for (j = 0; j < i; j++) { + struct nm_bdg_kthread *t = bps->kthreads + i; + nm_os_kthread_delete(t->nmk); + } + free(bps->kthreads, M_DEVBUF); + return EFAULT; +} + +/* a version of ptnetmap_start_kthreads() */ +static int +nm_bdg_polling_start_kthreads(struct nm_bdg_polling_state *bps) +{ + int error, i, j; + + if (!bps) { + D("polling is not configured"); + return EFAULT; + } + bps->stopped = false; + + for (i = 0; i < bps->ncpus; i++) { + struct nm_bdg_kthread *t = bps->kthreads + i; + error = nm_os_kthread_start(t->nmk); + if (error) { + D("error in nm_kthread_start()"); + goto cleanup; + } + } + return 0; + +cleanup: + for (j = 0; j < i; j++) { + struct nm_bdg_kthread *t = bps->kthreads + i; + nm_os_kthread_stop(t->nmk); + } + bps->stopped = true; + return error; +} + +static void +nm_bdg_polling_stop_delete_kthreads(struct nm_bdg_polling_state *bps) +{ + int i; + + if (!bps) + return; + + for (i = 0; i < bps->ncpus; i++) { + struct nm_bdg_kthread *t = bps->kthreads + i; + nm_os_kthread_stop(t->nmk); + nm_os_kthread_delete(t->nmk); + } + bps->stopped = true; +} + +static int +get_polling_cfg(struct nmreq *nmr, struct netmap_adapter *na, + struct nm_bdg_polling_state *bps) +{ + int req_cpus, avail_cpus, core_from; + u_int reg, i, qfirst, qlast; + + avail_cpus = nm_os_ncpus(); + req_cpus = nmr->nr_arg1; + + if (req_cpus == 0) { + D("req_cpus must be > 0"); + return EINVAL; + } else if (req_cpus >= avail_cpus) { + D("for safety, we need at least one core left in the system"); + return EINVAL; + } + reg = nmr->nr_flags & NR_REG_MASK; + i = nmr->nr_ringid & NETMAP_RING_MASK; + /* + * ONE_NIC: dedicate one core to one ring. If multiple cores + * are specified, consecutive rings are also polled. + * For example, if ringid=2 and 2 cores are given, + * ring 2 and 3 are polled by core 2 and 3, respectively. + * ALL_NIC: poll all the rings using a core specified by ringid. + * the number of cores must be 1. + */ + if (reg == NR_REG_ONE_NIC) { + if (i + req_cpus > nma_get_nrings(na, NR_RX)) { + D("only %d rings exist (ring %u-%u is given)", + nma_get_nrings(na, NR_RX), i, i+req_cpus); + return EINVAL; + } + qfirst = i; + qlast = qfirst + req_cpus; + core_from = qfirst; + } else if (reg == NR_REG_ALL_NIC) { + if (req_cpus != 1) { + D("ncpus must be 1 not %d for REG_ALL_NIC", req_cpus); + return EINVAL; + } + qfirst = 0; + qlast = nma_get_nrings(na, NR_RX); + core_from = i; + } else { + D("reg must be ALL_NIC or ONE_NIC"); + return EINVAL; + } + + bps->reg = reg; + bps->qfirst = qfirst; + bps->qlast = qlast; + bps->cpu_from = core_from; + bps->ncpus = req_cpus; + D("%s qfirst %u qlast %u cpu_from %u ncpus %u", + reg == NR_REG_ALL_NIC ? "REG_ALL_NIC" : "REG_ONE_NIC", + qfirst, qlast, core_from, req_cpus); + return 0; +} + +static int +nm_bdg_ctl_polling_start(struct nmreq *nmr, struct netmap_adapter *na) +{ + struct nm_bdg_polling_state *bps; + struct netmap_bwrap_adapter *bna; + int error; + + bna = (struct netmap_bwrap_adapter *)na; + if (bna->na_polling_state) { + D("ERROR adapter already in polling mode"); + return EFAULT; + } + + bps = malloc(sizeof(*bps), M_DEVBUF, M_NOWAIT | M_ZERO); + if (!bps) + return ENOMEM; + bps->configured = false; + bps->stopped = true; + + if (get_polling_cfg(nmr, na, bps)) { + free(bps, M_DEVBUF); + return EINVAL; + } + + if (nm_bdg_create_kthreads(bps)) { + free(bps, M_DEVBUF); + return EFAULT; + } + + bps->configured = true; + bna->na_polling_state = bps; + bps->bna = bna; + + /* disable interrupt if possible */ + if (bna->hwna->nm_intr) + bna->hwna->nm_intr(bna->hwna, 0); + /* start kthread now */ + error = nm_bdg_polling_start_kthreads(bps); + if (error) { + D("ERROR nm_bdg_polling_start_kthread()"); + free(bps->kthreads, M_DEVBUF); + free(bps, M_DEVBUF); + bna->na_polling_state = NULL; + if (bna->hwna->nm_intr) + bna->hwna->nm_intr(bna->hwna, 1); + } + return error; +} + +static int +nm_bdg_ctl_polling_stop(struct nmreq *nmr, struct netmap_adapter *na) +{ + struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter *)na; + struct nm_bdg_polling_state *bps; + + if (!bna->na_polling_state) { + D("ERROR adapter is not in polling mode"); + return EFAULT; + } + bps = bna->na_polling_state; + nm_bdg_polling_stop_delete_kthreads(bna->na_polling_state); + bps->configured = false; + free(bps, M_DEVBUF); + bna->na_polling_state = NULL; + /* reenable interrupt */ + if (bna->hwna->nm_intr) + bna->hwna->nm_intr(bna->hwna, 1); + return 0; +} /* Called by either user's context (netmap_ioctl()) * or external kernel modules (e.g., Openvswitch). @@ -843,7 +1148,7 @@ netmap_bdg_ctl(struct nmreq *nmr, struct netmap_bdg_ops *bdg_ops) case NETMAP_BDG_LIST: /* this is used to enumerate bridges and ports */ if (namelen) { /* look up indexes of bridge and port */ - if (strncmp(name, NM_NAME, strlen(NM_NAME))) { + if (strncmp(name, NM_BDG_NAME, strlen(NM_BDG_NAME))) { error = EINVAL; break; } @@ -855,7 +1160,9 @@ netmap_bdg_ctl(struct nmreq *nmr, struct netmap_bdg_ops *bdg_ops) break; } - error = ENOENT; + error = 0; + nmr->nr_arg1 = b - bridges; /* bridge index */ + nmr->nr_arg2 = NM_BDG_NOPORT; for (j = 0; j < b->bdg_active_ports; j++) { i = b->bdg_port_index[j]; vpna = b->bdg_ports[i]; @@ -867,10 +1174,7 @@ netmap_bdg_ctl(struct nmreq *nmr, struct netmap_bdg_ops *bdg_ops) * virtual port and a NIC, respectively */ if (!strcmp(vpna->up.name, name)) { - /* bridge index */ - nmr->nr_arg1 = b - bridges; nmr->nr_arg2 = i; /* port index */ - error = 0; break; } } @@ -937,10 +1241,34 @@ netmap_bdg_ctl(struct nmreq *nmr, struct netmap_bdg_ops *bdg_ops) error = netmap_get_bdg_na(nmr, &na, 0); if (na && !error) { vpna = (struct netmap_vp_adapter *)na; - vpna->virt_hdr_len = nmr->nr_arg1; - if (vpna->virt_hdr_len) + na->virt_hdr_len = nmr->nr_arg1; + if (na->virt_hdr_len) { vpna->mfs = NETMAP_BUF_SIZE(na); - D("Using vnet_hdr_len %d for %p", vpna->virt_hdr_len, vpna); + } + D("Using vnet_hdr_len %d for %p", na->virt_hdr_len, na); + netmap_adapter_put(na); + } else if (!na) { + error = ENXIO; + } + NMG_UNLOCK(); + break; + + case NETMAP_BDG_POLLING_ON: + case NETMAP_BDG_POLLING_OFF: + NMG_LOCK(); + error = netmap_get_bdg_na(nmr, &na, 0); + if (na && !error) { + if (!nm_is_bwrap(na)) { + error = EOPNOTSUPP; + } else if (cmd == NETMAP_BDG_POLLING_ON) { + error = nm_bdg_ctl_polling_start(nmr, na); + if (!error) + netmap_adapter_get(na); + } else { + error = nm_bdg_ctl_polling_stop(nmr, na); + if (!error) + netmap_adapter_put(na); + } netmap_adapter_put(na); } NMG_UNLOCK(); @@ -1097,10 +1425,12 @@ nm_bdg_preflush(struct netmap_kring *kring, u_int end) ft_i = nm_bdg_flush(ft, ft_i, na, ring_nr); } if (frags > 1) { - D("truncate incomplete fragment at %d (%d frags)", ft_i, frags); - // ft_i > 0, ft[ft_i-1].flags has NS_MOREFRAG - ft[ft_i - 1].ft_frags &= ~NS_MOREFRAG; - ft[ft_i - frags].ft_frags = frags - 1; + /* Here ft_i > 0, ft[ft_i-1].flags has NS_MOREFRAG, and we + * have to fix frags count. */ + frags--; + ft[ft_i - 1].ft_flags &= ~NS_MOREFRAG; + ft[ft_i - frags].ft_frags = frags; + D("Truncate incomplete fragment at %d (%d frags)", ft_i, frags); } if (ft_i) ft_i = nm_bdg_flush(ft, ft_i, na, ring_nr); @@ -1157,6 +1487,8 @@ netmap_vp_reg(struct netmap_adapter *na, int onoff) { struct netmap_vp_adapter *vpna = (struct netmap_vp_adapter*)na; + enum txrx t; + int i; /* persistent ports may be put in netmap mode * before being attached to a bridge @@ -1164,12 +1496,30 @@ netmap_vp_reg(struct netmap_adapter *na, int onoff) if (vpna->na_bdg) BDG_WLOCK(vpna->na_bdg); if (onoff) { - na->na_flags |= NAF_NETMAP_ON; + for_rx_tx(t) { + for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { + struct netmap_kring *kring = &NMR(na, t)[i]; + + if (nm_kring_pending_on(kring)) + kring->nr_mode = NKR_NETMAP_ON; + } + } + if (na->active_fds == 0) + na->na_flags |= NAF_NETMAP_ON; /* XXX on FreeBSD, persistent VALE ports should also * toggle IFCAP_NETMAP in na->ifp (2014-03-16) */ } else { - na->na_flags &= ~NAF_NETMAP_ON; + if (na->active_fds == 0) + na->na_flags &= ~NAF_NETMAP_ON; + for_rx_tx(t) { + for (i = 0; i < nma_get_nrings(na, t) + 1; i++) { + struct netmap_kring *kring = &NMR(na, t)[i]; + + if (nm_kring_pending_off(kring)) + kring->nr_mode = NKR_NETMAP_OFF; + } + } } if (vpna->na_bdg) BDG_WUNLOCK(vpna->na_bdg); @@ -1193,13 +1543,14 @@ netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring, uint32_t sh, dh; u_int dst, mysrc = na->bdg_port; uint64_t smac, dmac; + uint8_t indbuf[12]; /* safety check, unfortunately we have many cases */ - if (buf_len >= 14 + na->virt_hdr_len) { + if (buf_len >= 14 + na->up.virt_hdr_len) { /* virthdr + mac_hdr in the same slot */ - buf += na->virt_hdr_len; - buf_len -= na->virt_hdr_len; - } else if (buf_len == na->virt_hdr_len && ft->ft_flags & NS_MOREFRAG) { + buf += na->up.virt_hdr_len; + buf_len -= na->up.virt_hdr_len; + } else if (buf_len == na->up.virt_hdr_len && ft->ft_flags & NS_MOREFRAG) { /* only header in first fragment */ ft++; buf = ft->ft_buf; @@ -1208,6 +1559,14 @@ netmap_bdg_learning(struct nm_bdg_fwd *ft, uint8_t *dst_ring, RD(5, "invalid buf format, length %d", buf_len); return NM_BDG_NOPORT; } + + if (ft->ft_flags & NS_INDIRECT) { + if (copyin(buf, indbuf, sizeof(indbuf))) { + return NM_BDG_NOPORT; + } + buf = indbuf; + } + dmac = le64toh(*(uint64_t *)(buf)) & 0xffffffffffff; smac = le64toh(*(uint64_t *)(buf + 4)); smac >>= 16; @@ -1321,7 +1680,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na, struct nm_bdg_q *dst_ents, *brddst; uint16_t num_dsts = 0, *dsts; struct nm_bridge *b = na->na_bdg; - u_int i, j, me = na->bdg_port; + u_int i, me = na->bdg_port; /* * The work area (pointed by ft) is followed by an array of @@ -1341,7 +1700,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na, ND("slot %d frags %d", i, ft[i].ft_frags); /* Drop the packet if the virtio-net header is not into the first fragment nor at the very beginning of the second. */ - if (unlikely(na->virt_hdr_len > ft[i].ft_len)) + if (unlikely(na->up.virt_hdr_len > ft[i].ft_len)) continue; dst_port = b->bdg_ops.lookup(&ft[i], &dst_ring, na); if (netmap_verbose > 255) @@ -1382,6 +1741,7 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na, */ brddst = dst_ents + NM_BDG_BROADCAST * NM_BDG_MAXRINGS; if (brddst->bq_head != NM_FT_NULL) { + u_int j; for (j = 0; likely(j < b->bdg_active_ports); j++) { uint16_t d_i; i = b->bdg_port_index[j]; @@ -1441,8 +1801,9 @@ nm_bdg_flush(struct nm_bdg_fwd *ft, u_int n, struct netmap_vp_adapter *na, */ needed = d->bq_len + brddst->bq_len; - if (unlikely(dst_na->virt_hdr_len != na->virt_hdr_len)) { - RD(3, "virt_hdr_mismatch, src %d dst %d", na->virt_hdr_len, dst_na->virt_hdr_len); + if (unlikely(dst_na->up.virt_hdr_len != na->up.virt_hdr_len)) { + RD(3, "virt_hdr_mismatch, src %d dst %d", na->up.virt_hdr_len, + dst_na->up.virt_hdr_len); /* There is a virtio-net header/offloadings mismatch between * source and destination. The slower mismatch datapath will * be used to cope with all the mismatches. @@ -1803,7 +2164,6 @@ netmap_vp_create(struct nmreq *nmr, struct ifnet *ifp, struct netmap_vp_adapter nm_bound_var(&nmr->nr_arg3, 0, 0, 128*NM_BDG_MAXSLOTS, NULL); na->num_rx_desc = nmr->nr_rx_slots; - vpna->virt_hdr_len = 0; vpna->mfs = 1514; vpna->last_smac = ~0llu; /*if (vpna->mfs > netmap_buf_size) TODO netmap_buf_size is zero?? @@ -1880,19 +2240,17 @@ netmap_bwrap_dtor(struct netmap_adapter *na) { struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter*)na; struct netmap_adapter *hwna = bna->hwna; + struct nm_bridge *b = bna->up.na_bdg, + *bh = bna->host.na_bdg; + + if (b) { + netmap_bdg_detach_common(b, bna->up.bdg_port, + (bh ? bna->host.bdg_port : -1)); + } ND("na %p", na); - /* drop reference to hwna->ifp. - * If we don't do this, netmap_detach_common(na) - * will think it has set NA(na->ifp) to NULL - */ na->ifp = NULL; - /* for safety, also drop the possible reference - * in the hostna - */ bna->host.up.ifp = NULL; - - hwna->nm_mem = bna->save_nmd; hwna->na_private = NULL; hwna->na_vp = hwna->na_hostvp = NULL; hwna->na_flags &= ~NAF_BUSY; @@ -1916,7 +2274,8 @@ netmap_bwrap_dtor(struct netmap_adapter *na) * (part as a receive ring, part as a transmit ring). * * callback that overwrites the hwna notify callback. - * Packets come from the outside or from the host stack and are put on an hwna rx ring. + * Packets come from the outside or from the host stack and are put on an + * hwna rx ring. * The bridge wrapper then sends the packets through the bridge. */ static int @@ -1927,19 +2286,18 @@ netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags) struct netmap_kring *bkring; struct netmap_vp_adapter *vpna = &bna->up; u_int ring_nr = kring->ring_id; - int error = 0; + int ret = NM_IRQ_COMPLETED; + int error; if (netmap_verbose) D("%s %s 0x%x", na->name, kring->name, flags); - if (!nm_netmap_on(na)) - return 0; - bkring = &vpna->up.tx_rings[ring_nr]; /* make sure the ring is not disabled */ - if (nm_kr_tryget(kring)) - return 0; + if (nm_kr_tryget(kring, 0 /* can't sleep */, NULL)) { + return EIO; + } if (netmap_verbose) D("%s head %d cur %d tail %d", na->name, @@ -1951,9 +2309,10 @@ netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags) error = kring->nm_sync(kring, 0); if (error) goto put_out; - if (kring->nr_hwcur == kring->nr_hwtail && netmap_verbose) { - D("how strange, interrupt with no packets on %s", - na->name); + if (kring->nr_hwcur == kring->nr_hwtail) { + if (netmap_verbose) + D("how strange, interrupt with no packets on %s", + na->name); goto put_out; } @@ -1970,28 +2329,32 @@ netmap_bwrap_intr_notify(struct netmap_kring *kring, int flags) /* another call to actually release the buffers */ error = kring->nm_sync(kring, 0); + /* The second rxsync may have further advanced hwtail. If this happens, + * return NM_IRQ_RESCHED, otherwise just return NM_IRQ_COMPLETED. */ + if (kring->rcur != kring->nr_hwtail) { + ret = NM_IRQ_RESCHED; + } put_out: nm_kr_put(kring); - return error; + + return error ? error : ret; } /* nm_register callback for bwrap */ static int -netmap_bwrap_register(struct netmap_adapter *na, int onoff) +netmap_bwrap_reg(struct netmap_adapter *na, int onoff) { struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter *)na; struct netmap_adapter *hwna = bna->hwna; struct netmap_vp_adapter *hostna = &bna->host; - int error; + int error, i; enum txrx t; ND("%s %s", na->name, onoff ? "on" : "off"); if (onoff) { - int i; - /* netmap_do_regif has been called on the bwrap na. * We need to pass the information about the * memory allocator down to the hwna before @@ -2010,16 +2373,32 @@ netmap_bwrap_register(struct netmap_adapter *na, int onoff) /* cross-link the netmap rings * The original number of rings comes from hwna, * rx rings on one side equals tx rings on the other. - * We need to do this now, after the initialization - * of the kring->ring pointers */ for_rx_tx(t) { - enum txrx r= nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */ - for (i = 0; i < nma_get_nrings(na, r) + 1; i++) { - NMR(hwna, t)[i].nkr_num_slots = NMR(na, r)[i].nkr_num_slots; - NMR(hwna, t)[i].ring = NMR(na, r)[i].ring; + enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */ + for (i = 0; i < nma_get_nrings(hwna, r) + 1; i++) { + NMR(hwna, r)[i].ring = NMR(na, t)[i].ring; } } + + if (na->na_flags & NAF_HOST_RINGS) { + struct netmap_adapter *hna = &hostna->up; + /* the hostna rings are the host rings of the bwrap. + * The corresponding krings must point back to the + * hostna + */ + hna->tx_rings = &na->tx_rings[na->num_tx_rings]; + hna->tx_rings[0].na = hna; + hna->rx_rings = &na->rx_rings[na->num_rx_rings]; + hna->rx_rings[0].na = hna; + } + } + + /* pass down the pending ring state information */ + for_rx_tx(t) { + for (i = 0; i < nma_get_nrings(na, t) + 1; i++) + NMR(hwna, t)[i].nr_pending_mode = + NMR(na, t)[i].nr_pending_mode; } /* forward the request to the hwna */ @@ -2027,6 +2406,13 @@ netmap_bwrap_register(struct netmap_adapter *na, int onoff) if (error) return error; + /* copy up the current ring state information */ + for_rx_tx(t) { + for (i = 0; i < nma_get_nrings(na, t) + 1; i++) + NMR(na, t)[i].nr_mode = + NMR(hwna, t)[i].nr_mode; + } + /* impersonate a netmap_vp_adapter */ netmap_vp_reg(na, onoff); if (hostna->na_bdg) @@ -2046,8 +2432,14 @@ netmap_bwrap_register(struct netmap_adapter *na, int onoff) /* also intercept the host ring notify */ hwna->rx_rings[i].nm_notify = netmap_bwrap_intr_notify; } + if (na->active_fds == 0) + na->na_flags |= NAF_NETMAP_ON; } else { u_int i; + + if (na->active_fds == 0) + na->na_flags &= ~NAF_NETMAP_ON; + /* reset all notify callbacks (including host ring) */ for (i = 0; i <= hwna->num_rx_rings; i++) { hwna->rx_rings[i].nm_notify = hwna->rx_rings[i].save_notify; @@ -2089,8 +2481,8 @@ netmap_bwrap_krings_create(struct netmap_adapter *na) struct netmap_bwrap_adapter *bna = (struct netmap_bwrap_adapter *)na; struct netmap_adapter *hwna = bna->hwna; - struct netmap_adapter *hostna = &bna->host.up; - int error; + int i, error = 0; + enum txrx t; ND("%s", na->name); @@ -2102,26 +2494,23 @@ netmap_bwrap_krings_create(struct netmap_adapter *na) /* also create the hwna krings */ error = hwna->nm_krings_create(hwna); if (error) { - netmap_vp_krings_delete(na); - return error; + goto err_del_vp_rings; } - /* the connection between the bwrap krings and the hwna krings - * will be perfomed later, in the nm_register callback, since - * now the kring->ring pointers have not been initialized yet - */ - if (na->na_flags & NAF_HOST_RINGS) { - /* the hostna rings are the host rings of the bwrap. - * The corresponding krings must point back to the - * hostna - */ - hostna->tx_rings = &na->tx_rings[na->num_tx_rings]; - hostna->tx_rings[0].na = hostna; - hostna->rx_rings = &na->rx_rings[na->num_rx_rings]; - hostna->rx_rings[0].na = hostna; + /* get each ring slot number from the corresponding hwna ring */ + for_rx_tx(t) { + enum txrx r = nm_txrx_swap(t); /* swap NR_TX <-> NR_RX */ + for (i = 0; i < nma_get_nrings(hwna, r) + 1; i++) { + NMR(na, t)[i].nkr_num_slots = NMR(hwna, r)[i].nkr_num_slots; + } } return 0; + +err_del_vp_rings: + netmap_vp_krings_delete(na); + + return error; } @@ -2149,19 +2538,18 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags) u_int ring_n = kring->ring_id; u_int lim = kring->nkr_num_slots - 1; struct netmap_kring *hw_kring; - int error = 0; + int error; - ND("%s: na %s hwna %s", + ND("%s: na %s hwna %s", (kring ? kring->name : "NULL!"), (na ? na->name : "NULL!"), (hwna ? hwna->name : "NULL!")); hw_kring = &hwna->tx_rings[ring_n]; - if (nm_kr_tryget(hw_kring)) - return 0; + if (nm_kr_tryget(hw_kring, 0, NULL)) { + return ENXIO; + } - if (!nm_netmap_on(hwna)) - return 0; /* first step: simulate a user wakeup on the rx ring */ netmap_vp_rxsync(kring, flags); ND("%s[%d] PRE rx(c%3d t%3d l%3d) ring(h%3d c%3d t%3d) tx(c%3d ht%3d t%3d)", @@ -2175,7 +2563,7 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags) hw_kring->rhead = hw_kring->rcur = kring->nr_hwtail; error = hw_kring->nm_sync(hw_kring, flags); if (error) - goto out; + goto put_out; /* third step: now we are back the rx ring */ /* claim ownership on all hw owned bufs */ @@ -2188,9 +2576,10 @@ netmap_bwrap_notify(struct netmap_kring *kring, int flags) kring->nr_hwcur, kring->nr_hwtail, kring->nkr_hwlease, ring->head, ring->cur, ring->tail, hw_kring->nr_hwcur, hw_kring->nr_hwtail, hw_kring->rtail); -out: +put_out: nm_kr_put(hw_kring); - return error; + + return error ? error : NM_IRQ_COMPLETED; } @@ -2217,44 +2606,23 @@ netmap_bwrap_bdg_ctl(struct netmap_adapter *na, struct nmreq *nmr, int attach) /* nothing to do */ return 0; } - npriv = malloc(sizeof(*npriv), M_DEVBUF, M_NOWAIT|M_ZERO); + npriv = netmap_priv_new(); if (npriv == NULL) return ENOMEM; - error = netmap_do_regif(npriv, na, nmr->nr_ringid, nmr->nr_flags); + npriv->np_ifp = na->ifp; /* let the priv destructor release the ref */ + error = netmap_do_regif(npriv, na, 0, NR_REG_NIC_SW); if (error) { - bzero(npriv, sizeof(*npriv)); - free(npriv, M_DEVBUF); + netmap_priv_delete(npriv); return error; } bna->na_kpriv = npriv; na->na_flags |= NAF_BUSY; } else { - int last_instance; - if (na->active_fds == 0) /* not registered */ return EINVAL; - last_instance = netmap_dtor_locked(bna->na_kpriv); - if (!last_instance) { - D("--- error, trying to detach an entry with active mmaps"); - error = EINVAL; - } else { - struct nm_bridge *b = bna->up.na_bdg, - *bh = bna->host.na_bdg; - npriv = bna->na_kpriv; - bna->na_kpriv = NULL; - D("deleting priv"); - - bzero(npriv, sizeof(*npriv)); - free(npriv, M_DEVBUF); - if (b) { - /* XXX the bwrap dtor should take care - * of this (2014-06-16) - */ - netmap_bdg_detach_common(b, bna->up.bdg_port, - (bh ? bna->host.bdg_port : -1)); - } - na->na_flags &= ~NAF_BUSY; - } + netmap_priv_delete(bna->na_kpriv); + bna->na_kpriv = NULL; + na->na_flags &= ~NAF_BUSY; } return error; @@ -2282,6 +2650,8 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna) } na = &bna->up.up; + /* make bwrap ifp point to the real ifp */ + na->ifp = hwna->ifp; na->na_private = bna; strncpy(na->name, nr_name, sizeof(na->name)); /* fill the ring data for the bwrap adapter with rx/tx meanings @@ -2294,7 +2664,7 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna) nma_set_ndesc(na, t, nma_get_ndesc(hwna, r)); } na->nm_dtor = netmap_bwrap_dtor; - na->nm_register = netmap_bwrap_register; + na->nm_register = netmap_bwrap_reg; // na->nm_txsync = netmap_bwrap_txsync; // na->nm_rxsync = netmap_bwrap_rxsync; na->nm_config = netmap_bwrap_config; @@ -2303,13 +2673,8 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna) na->nm_notify = netmap_bwrap_notify; na->nm_bdg_ctl = netmap_bwrap_bdg_ctl; na->pdev = hwna->pdev; - na->nm_mem = netmap_mem_private_new(na->name, - na->num_tx_rings, na->num_tx_desc, - na->num_rx_rings, na->num_rx_desc, - 0, 0, &error); - na->na_flags |= NAF_MEM_OWNER; - if (na->nm_mem == NULL) - goto err_put; + na->nm_mem = hwna->nm_mem; + na->virt_hdr_len = hwna->virt_hdr_len; bna->up.retry = 1; /* XXX maybe this should depend on the hwna */ bna->hwna = hwna; @@ -2349,24 +2714,10 @@ netmap_bwrap_attach(const char *nr_name, struct netmap_adapter *hwna) if (error) { goto err_free; } - /* make bwrap ifp point to the real ifp - * NOTE: netmap_attach_common() interprets a non-NULL na->ifp - * as a request to make the ifp point to the na. Since we - * do not want to change the na already pointed to by hwna->ifp, - * the following assignment has to be delayed until now - */ - na->ifp = hwna->ifp; hwna->na_flags |= NAF_BUSY; - /* make hwna point to the allocator we are actually using, - * so that monitors will be able to find it - */ - bna->save_nmd = hwna->nm_mem; - hwna->nm_mem = na->nm_mem; return 0; err_free: - netmap_mem_delete(na->nm_mem); -err_put: hwna->na_vp = hwna->na_hostvp = NULL; netmap_adapter_put(hwna); free(bna, M_DEVBUF); diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c index 8de548f0e2cc..be668c5e52b4 100644 --- a/sys/dev/pci/pci.c +++ b/sys/dev/pci/pci.c @@ -4608,6 +4608,9 @@ static const struct {PCIC_CRYPTO, PCIS_CRYPTO_ENTERTAIN, 1, "entertainment crypto"}, {PCIC_DASP, -1, 0, "dasp"}, {PCIC_DASP, PCIS_DASP_DPIO, 1, "DPIO module"}, + {PCIC_DASP, PCIS_DASP_PERFCNTRS, 1, "performance counters"}, + {PCIC_DASP, PCIS_DASP_COMM_SYNC, 1, "communication synchronizer"}, + {PCIC_DASP, PCIS_DASP_MGMT_CARD, 1, "signal processing management"}, {0, 0, 0, NULL} }; diff --git a/sys/dev/puc/puc.c b/sys/dev/puc/puc.c index d3b14fb8f9ab..3d3c3fabfbad 100644 --- a/sys/dev/puc/puc.c +++ b/sys/dev/puc/puc.c @@ -414,8 +414,7 @@ puc_bfe_detach(device_t dev) port = &sc->sc_port[idx]; if (port->p_dev == NULL) continue; - if (device_detach(port->p_dev) == 0) { - device_delete_child(dev, port->p_dev); + if (device_delete_child(dev, port->p_dev) == 0) { if (port->p_rres != NULL) rman_release_resource(port->p_rres); if (port->p_ires != NULL) diff --git a/sys/dev/rtwn/if_rtwn.c b/sys/dev/rtwn/if_rtwn.c index 88c23b2346d1..54381cf1642f 100644 --- a/sys/dev/rtwn/if_rtwn.c +++ b/sys/dev/rtwn/if_rtwn.c @@ -1,8 +1,9 @@ -/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini - * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,30 +22,26 @@ __FBSDID("$FreeBSD$"); /* - * Driver for Realtek RTL8188CE + * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU/RTL8812AU/RTL8821AU. */ +#include "opt_wlan.h" #include -#include #include +#include +#include +#include #include #include #include #include #include -#include -#include #include #include #include +#include #include - -#include -#include -#include - -#include -#include +#include #include #include @@ -55,962 +52,600 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include -#include -#include - #include #include #include -#include #include +#include + +#include +#include +#include +#include #include +#include -#define RTWN_DEBUG -#ifdef RTWN_DEBUG -#define DPRINTF(x) do { if (sc->sc_debug > 0) printf x; } while (0) -#define DPRINTFN(n, x) do { if (sc->sc_debug >= (n)) printf x; } while (0) -#else -#define DPRINTF(x) -#define DPRINTFN(n, x) -#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -/* - * PCI configuration space registers. - */ -#define RTWN_PCI_IOBA 0x10 /* i/o mapped base */ -#define RTWN_PCI_MMBA 0x18 /* memory mapped base */ - -#define RTWN_INT_ENABLE (R92C_IMR_ROK | R92C_IMR_VODOK | R92C_IMR_VIDOK | \ - R92C_IMR_BEDOK | R92C_IMR_BKDOK | R92C_IMR_MGNTDOK | \ - R92C_IMR_HIGHDOK | R92C_IMR_BDOK | R92C_IMR_RDU | \ - R92C_IMR_RXFOVW) - -struct rtwn_ident { - uint16_t vendor; - uint16_t device; - const char *name; -}; +#include -static const struct rtwn_ident rtwn_ident_table[] = { - { 0x10ec, 0x8176, "Realtek RTL8188CE" }, - { 0, 0, NULL } -}; - - -static void rtwn_dma_map_addr(void *, bus_dma_segment_t *, int, int); -static void rtwn_setup_rx_desc(struct rtwn_softc *, struct r92c_rx_desc *, - bus_addr_t, size_t, int); -static int rtwn_alloc_rx_list(struct rtwn_softc *); -static void rtwn_reset_rx_list(struct rtwn_softc *); -static void rtwn_free_rx_list(struct rtwn_softc *); -static int rtwn_alloc_tx_list(struct rtwn_softc *, int); -static void rtwn_reset_tx_list(struct rtwn_softc *, int); -static void rtwn_free_tx_list(struct rtwn_softc *, int); +static void rtwn_radiotap_attach(struct rtwn_softc *); +static void rtwn_vap_decrement_counters(struct rtwn_softc *, + enum ieee80211_opmode, int); +static void rtwn_set_ic_opmode(struct rtwn_softc *); static struct ieee80211vap *rtwn_vap_create(struct ieee80211com *, - const char [IFNAMSIZ], int, enum ieee80211_opmode, int, - const uint8_t [IEEE80211_ADDR_LEN], - const uint8_t [IEEE80211_ADDR_LEN]); -static void rtwn_vap_delete(struct ieee80211vap *); -static void rtwn_write_1(struct rtwn_softc *, uint16_t, uint8_t); -static void rtwn_write_2(struct rtwn_softc *, uint16_t, uint16_t); -static void rtwn_write_4(struct rtwn_softc *, uint16_t, uint32_t); -static uint8_t rtwn_read_1(struct rtwn_softc *, uint16_t); -static uint16_t rtwn_read_2(struct rtwn_softc *, uint16_t); -static uint32_t rtwn_read_4(struct rtwn_softc *, uint16_t); -static int rtwn_fw_cmd(struct rtwn_softc *, uint8_t, const void *, int); -static void rtwn_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t); -static uint32_t rtwn_rf_read(struct rtwn_softc *, int, uint8_t); -static int rtwn_llt_write(struct rtwn_softc *, uint32_t, uint32_t); -static uint8_t rtwn_efuse_read_1(struct rtwn_softc *, uint16_t); -static void rtwn_efuse_read(struct rtwn_softc *); -static int rtwn_read_chipid(struct rtwn_softc *); -static void rtwn_read_rom(struct rtwn_softc *); -static int rtwn_ra_init(struct rtwn_softc *); -static void rtwn_tsf_sync_enable(struct rtwn_softc *); -static void rtwn_set_led(struct rtwn_softc *, int, int); -static void rtwn_calib_to(void *); -static int rtwn_newstate(struct ieee80211vap *, enum ieee80211_state, int); -static int rtwn_updateedca(struct ieee80211com *); -static void rtwn_update_avgrssi(struct rtwn_softc *, int, int8_t); -static int8_t rtwn_get_rssi(struct rtwn_softc *, int, void *); -static void rtwn_rx_frame(struct rtwn_softc *, struct r92c_rx_desc *, - struct rtwn_rx_data *, int); -static int rtwn_tx(struct rtwn_softc *, struct mbuf *, - struct ieee80211_node *); -static void rtwn_tx_done(struct rtwn_softc *, int); -static int rtwn_raw_xmit(struct ieee80211_node *, struct mbuf *, - const struct ieee80211_bpf_params *); -static int rtwn_transmit(struct ieee80211com *, struct mbuf *); -static void rtwn_parent(struct ieee80211com *); -static void rtwn_start(struct rtwn_softc *sc); -static void rtwn_watchdog(void *); -static int rtwn_power_on(struct rtwn_softc *); -static int rtwn_llt_init(struct rtwn_softc *); -static void rtwn_fw_reset(struct rtwn_softc *); -static void rtwn_fw_loadpage(struct rtwn_softc *, int, const uint8_t *, - int); -static int rtwn_load_firmware(struct rtwn_softc *); -static int rtwn_dma_init(struct rtwn_softc *); -static void rtwn_mac_init(struct rtwn_softc *); -static void rtwn_bb_init(struct rtwn_softc *); -static void rtwn_rf_init(struct rtwn_softc *); -static void rtwn_cam_init(struct rtwn_softc *); -static void rtwn_pa_bias_init(struct rtwn_softc *); -static void rtwn_rxfilter_init(struct rtwn_softc *); -static void rtwn_edca_init(struct rtwn_softc *); -static void rtwn_write_txpower(struct rtwn_softc *, int, uint16_t[]); -static void rtwn_get_txpower(struct rtwn_softc *, int, - struct ieee80211_channel *, struct ieee80211_channel *, - uint16_t[]); -static void rtwn_set_txpower(struct rtwn_softc *, - struct ieee80211_channel *, struct ieee80211_channel *); -static void rtwn_set_rx_bssid_all(struct rtwn_softc *, int); -static void rtwn_set_gain(struct rtwn_softc *, uint8_t); -static void rtwn_scan_start(struct ieee80211com *); -static void rtwn_scan_end(struct ieee80211com *); -static void rtwn_getradiocaps(struct ieee80211com *, int, int *, - struct ieee80211_channel[]); -static void rtwn_set_channel(struct ieee80211com *); -static void rtwn_update_mcast(struct ieee80211com *); -static void rtwn_set_chan(struct rtwn_softc *, - struct ieee80211_channel *, struct ieee80211_channel *); -static int rtwn_iq_calib_chain(struct rtwn_softc *, int, uint16_t[2], - uint16_t[2]); -static void rtwn_iq_calib_run(struct rtwn_softc *, int, uint16_t[2][2], - uint16_t[2][2]); -static int rtwn_iq_calib_compare_results(uint16_t[2][2], uint16_t[2][2], - uint16_t[2][2], uint16_t[2][2], int); -static void rtwn_iq_calib_write_results(struct rtwn_softc *, uint16_t[2], - uint16_t[2], int); -static void rtwn_iq_calib(struct rtwn_softc *); -static void rtwn_lc_calib(struct rtwn_softc *); -static void rtwn_temp_calib(struct rtwn_softc *); -static int rtwn_init(struct rtwn_softc *); -static void rtwn_stop_locked(struct rtwn_softc *); -static void rtwn_stop(struct rtwn_softc *); -static void rtwn_intr(void *); + const char [IFNAMSIZ], int, enum ieee80211_opmode, + int, const uint8_t [IEEE80211_ADDR_LEN], + const uint8_t [IEEE80211_ADDR_LEN]); +static void rtwn_vap_delete(struct ieee80211vap *); +static int rtwn_read_chipid(struct rtwn_softc *); +static int rtwn_ioctl_reset(struct ieee80211vap *, u_long); +#ifndef RTWN_WITHOUT_UCODE +static void rtwn_set_media_status(struct rtwn_softc *, + union sec_param *); +static int rtwn_tx_fwpkt_check(struct rtwn_softc *, + struct ieee80211vap *); +static int rtwn_construct_nulldata(struct rtwn_softc *, + struct ieee80211vap *, uint8_t *, int); +static int rtwn_push_nulldata(struct rtwn_softc *, + struct ieee80211vap *); +static void rtwn_pwrmode_init(void *); +static void rtwn_set_pwrmode_cb(struct rtwn_softc *, + union sec_param *); +#endif +static void rtwn_tsf_sync_adhoc(void *); +static void rtwn_tsf_sync_adhoc_task(void *, int); +static void rtwn_tsf_sync_enable(struct rtwn_softc *, + struct ieee80211vap *); +static void rtwn_set_ack_preamble(struct rtwn_softc *); +static void rtwn_set_mode(struct rtwn_softc *, uint8_t, int); +static int rtwn_monitor_newstate(struct ieee80211vap *, + enum ieee80211_state, int); +static int rtwn_newstate(struct ieee80211vap *, + enum ieee80211_state, int); +static void rtwn_calc_basicrates(struct rtwn_softc *); +static int rtwn_run(struct rtwn_softc *, + struct ieee80211vap *); +#ifndef D4054 +static void rtwn_watchdog(void *); +#endif +static void rtwn_parent(struct ieee80211com *); +static int rtwn_llt_write(struct rtwn_softc *, uint32_t, + uint32_t); +static int rtwn_llt_init(struct rtwn_softc *); +static int rtwn_dma_init(struct rtwn_softc *); +static int rtwn_mac_init(struct rtwn_softc *); +static void rtwn_mrr_init(struct rtwn_softc *); +static void rtwn_scan_start(struct ieee80211com *); +static void rtwn_scan_curchan(struct ieee80211_scan_state *, + unsigned long); +static void rtwn_scan_end(struct ieee80211com *); +static void rtwn_getradiocaps(struct ieee80211com *, int, int *, + struct ieee80211_channel[]); +static void rtwn_update_chw(struct ieee80211com *); +static void rtwn_set_channel(struct ieee80211com *); +static int rtwn_wme_update(struct ieee80211com *); +static void rtwn_update_slot(struct ieee80211com *); +static void rtwn_update_slot_cb(struct rtwn_softc *, + union sec_param *); +static void rtwn_update_aifs(struct rtwn_softc *, uint8_t); +static void rtwn_update_promisc(struct ieee80211com *); +static void rtwn_update_mcast(struct ieee80211com *); +static int rtwn_set_bssid(struct rtwn_softc *, + const uint8_t *, int); +static int rtwn_set_macaddr(struct rtwn_softc *, + const uint8_t *, int); +static struct ieee80211_node *rtwn_node_alloc(struct ieee80211vap *, + const uint8_t mac[IEEE80211_ADDR_LEN]); +static void rtwn_newassoc(struct ieee80211_node *, int); +static void rtwn_node_free(struct ieee80211_node *); +static void rtwn_init_beacon_reg(struct rtwn_softc *); +static int rtwn_init(struct rtwn_softc *); +static void rtwn_stop(struct rtwn_softc *); -/* Aliases. */ -#define rtwn_bb_write rtwn_write_4 -#define rtwn_bb_read rtwn_read_4 - -static int rtwn_probe(device_t); -static int rtwn_attach(device_t); -static int rtwn_detach(device_t); -static int rtwn_shutdown(device_t); -static int rtwn_suspend(device_t); -static int rtwn_resume(device_t); - -static device_method_t rtwn_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, rtwn_probe), - DEVMETHOD(device_attach, rtwn_attach), - DEVMETHOD(device_detach, rtwn_detach), - DEVMETHOD(device_shutdown, rtwn_shutdown), - DEVMETHOD(device_suspend, rtwn_suspend), - DEVMETHOD(device_resume, rtwn_resume), - - DEVMETHOD_END -}; - -static driver_t rtwn_driver = { - "rtwn", - rtwn_methods, - sizeof (struct rtwn_softc) -}; -static devclass_t rtwn_devclass; - -DRIVER_MODULE(rtwn, pci, rtwn_driver, rtwn_devclass, NULL, NULL); - -MODULE_VERSION(rtwn, 1); - -MODULE_DEPEND(rtwn, pci, 1, 1, 1); -MODULE_DEPEND(rtwn, wlan, 1, 1, 1); -MODULE_DEPEND(rtwn, firmware, 1, 1, 1); +MALLOC_DEFINE(M_RTWN_PRIV, "rtwn_priv", "rtwn driver private state"); static const uint8_t rtwn_chan_2ghz[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; -static int -rtwn_probe(device_t dev) -{ - const struct rtwn_ident *ident; +static const uint16_t wme2reg[] = + { R92C_EDCA_BE_PARAM, R92C_EDCA_BK_PARAM, + R92C_EDCA_VI_PARAM, R92C_EDCA_VO_PARAM }; - for (ident = rtwn_ident_table; ident->name != NULL; ident++) { - if (pci_get_vendor(dev) == ident->vendor && - pci_get_device(dev) == ident->device) { - device_set_desc(dev, ident->name); - return (BUS_PROBE_DEFAULT); - } - } - return (ENXIO); -} - -static int -rtwn_attach(device_t dev) +int +rtwn_attach(struct rtwn_softc *sc) { - struct rtwn_softc *sc = device_get_softc(dev); struct ieee80211com *ic = &sc->sc_ic; - uint32_t lcsr; - int i, count, error, rid; + int error; - sc->sc_dev = dev; - sc->sc_debug = 0; + sc->cur_bcnq_id = RTWN_VAP_ID_INVALID; - /* - * Get the offset of the PCI Express Capability Structure in PCI - * Configuration Space. - */ - error = pci_find_cap(dev, PCIY_EXPRESS, &sc->sc_cap_off); - if (error != 0) { - device_printf(dev, "PCIe capability structure not found!\n"); - return (error); - } - - /* Enable bus-mastering. */ - pci_enable_busmaster(dev); - - rid = PCIR_BAR(2); - sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, - RF_ACTIVE); - if (sc->mem == NULL) { - device_printf(dev, "can't map mem space\n"); - return (ENOMEM); - } - sc->sc_st = rman_get_bustag(sc->mem); - sc->sc_sh = rman_get_bushandle(sc->mem); - - /* Install interrupt handler. */ - count = 1; - rid = 0; - if (pci_alloc_msi(dev, &count) == 0) - rid = 1; - sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | - (rid != 0 ? 0 : RF_SHAREABLE)); - if (sc->irq == NULL) { - device_printf(dev, "can't map interrupt\n"); - return (ENXIO); - } - - RTWN_LOCK_INIT(sc); - callout_init_mtx(&sc->calib_to, &sc->sc_mtx, 0); - callout_init_mtx(&sc->watchdog_to, &sc->sc_mtx, 0); + RTWN_NT_LOCK_INIT(sc); + rtwn_cmdq_init(sc); +#ifndef D4054 + callout_init_mtx(&sc->sc_watchdog_to, &sc->sc_mtx, 0); +#endif + callout_init(&sc->sc_calib_to, 0); + callout_init(&sc->sc_pwrmode_init, 0); mbufq_init(&sc->sc_snd, ifqmaxlen); + RTWN_LOCK(sc); error = rtwn_read_chipid(sc); + RTWN_UNLOCK(sc); if (error != 0) { - device_printf(dev, "unsupported test chip\n"); - goto fail; + device_printf(sc->sc_dev, "unsupported test chip\n"); + goto detach; } - /* Disable PCIe Active State Power Management (ASPM). */ - lcsr = pci_read_config(sc->sc_dev, sc->sc_cap_off + PCIER_LINK_CTL, 4); - lcsr &= ~PCIEM_LINK_CTL_ASPMC; - pci_write_config(sc->sc_dev, sc->sc_cap_off + PCIER_LINK_CTL, lcsr, 4); - - /* Allocate Tx/Rx buffers. */ - error = rtwn_alloc_rx_list(sc); + error = rtwn_read_rom(sc); if (error != 0) { - device_printf(dev, "could not allocate Rx buffers\n"); - goto fail; - } - for (i = 0; i < RTWN_NTXQUEUES; i++) { - error = rtwn_alloc_tx_list(sc, i); - if (error != 0) { - device_printf(dev, "could not allocate Tx buffers\n"); - goto fail; - } + device_printf(sc->sc_dev, "%s: cannot read rom, error %d\n", + __func__, error); + goto detach; } - /* Determine number of Tx/Rx chains. */ - if (sc->chip & RTWN_CHIP_92C) { - sc->ntxchains = (sc->chip & RTWN_CHIP_92C_1T2R) ? 1 : 2; - sc->nrxchains = 2; - } else { - sc->ntxchains = 1; - sc->nrxchains = 1; + if (sc->macid_limit > RTWN_MACID_LIMIT) { + device_printf(sc->sc_dev, + "macid limit will be reduced from %d to %d\n", + sc->macid_limit, RTWN_MACID_LIMIT); + sc->macid_limit = RTWN_MACID_LIMIT; + } + if (sc->cam_entry_limit > RTWN_CAM_ENTRY_LIMIT) { + device_printf(sc->sc_dev, + "cam entry limit will be reduced from %d to %d\n", + sc->cam_entry_limit, RTWN_CAM_ENTRY_LIMIT); + sc->cam_entry_limit = RTWN_CAM_ENTRY_LIMIT; + } + if (sc->txdesc_len > RTWN_TX_DESC_SIZE) { + device_printf(sc->sc_dev, + "adjust size for Tx descriptor (current %d, needed %d)\n", + RTWN_TX_DESC_SIZE, sc->txdesc_len); + goto detach; } - rtwn_read_rom(sc); - device_printf(sc->sc_dev, "MAC/BB RTL%s, RF 6052 %dT%dR\n", - (sc->chip & RTWN_CHIP_92C) ? "8192CE" : "8188CE", - sc->ntxchains, sc->nrxchains); + device_printf(sc->sc_dev, "MAC/BB %s, RF 6052 %dT%dR\n", + sc->name, sc->ntxchains, sc->nrxchains); ic->ic_softc = sc; - ic->ic_name = device_get_nameunit(dev); - ic->ic_opmode = IEEE80211_M_STA; - ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ + ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ + ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ /* set device capabilities */ ic->ic_caps = IEEE80211_C_STA /* station mode */ | IEEE80211_C_MONITOR /* monitor mode */ + | IEEE80211_C_IBSS /* adhoc mode */ + | IEEE80211_C_HOSTAP /* hostap mode */ +#if 0 /* TODO: HRPWM register setup */ +#ifndef RTWN_WITHOUT_UCODE + | IEEE80211_C_PMGT /* Station-side power mgmt */ +#endif +#endif | IEEE80211_C_SHPREAMBLE /* short preamble supported */ | IEEE80211_C_SHSLOT /* short slot time supported */ - | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ +#if 0 | IEEE80211_C_BGSCAN /* capable of bg scanning */ +#endif + | IEEE80211_C_WPA /* 802.11i */ | IEEE80211_C_WME /* 802.11e */ + | IEEE80211_C_SWAMSDUTX /* Do software A-MSDU TX */ + | IEEE80211_C_FF /* Atheros fast-frames */ ; - /* XXX TODO: setup regdomain if R92C_CHANNEL_PLAN_BY_HW bit is set. */ + if (sc->sc_hwcrypto != RTWN_CRYPTO_SW) { + ic->ic_cryptocaps = + IEEE80211_CRYPTO_WEP | + IEEE80211_CRYPTO_TKIP | + IEEE80211_CRYPTO_AES_CCM; + } + + ic->ic_htcaps = + IEEE80211_HTCAP_SHORTGI20 /* short GI in 20MHz */ + | IEEE80211_HTCAP_MAXAMSDU_3839 /* max A-MSDU length */ + | IEEE80211_HTCAP_SMPS_OFF /* SM PS mode disabled */ + /* s/w capabilities */ + | IEEE80211_HTC_HT /* HT operation */ + | IEEE80211_HTC_AMPDU /* A-MPDU tx */ + | IEEE80211_HTC_AMSDU /* A-MSDU tx */ + ; + + if (sc->sc_ht40) { + ic->ic_htcaps |= + IEEE80211_HTCAP_CHWIDTH40 /* 40 MHz channel width */ + | IEEE80211_HTCAP_SHORTGI40 /* short GI in 40MHz */ + ; + } + + ic->ic_txstream = sc->ntxchains; + ic->ic_rxstream = sc->nrxchains; + + /* Enable TX watchdog */ +#ifdef D4054 + ic->ic_flags_ext |= IEEE80211_FEXT_WATCHDOG; +#endif + + /* Adjust capabilities. */ + rtwn_adj_devcaps(sc); rtwn_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, ic->ic_channels); - ieee80211_ifattach(ic); + /* XXX TODO: setup regdomain if R92C_CHANNEL_PLAN_BY_HW bit is set. */ - ic->ic_wme.wme_update = rtwn_updateedca; - ic->ic_update_mcast = rtwn_update_mcast; + ieee80211_ifattach(ic); + ic->ic_raw_xmit = rtwn_raw_xmit; ic->ic_scan_start = rtwn_scan_start; + sc->sc_scan_curchan = ic->ic_scan_curchan; + ic->ic_scan_curchan = rtwn_scan_curchan; ic->ic_scan_end = rtwn_scan_end; ic->ic_getradiocaps = rtwn_getradiocaps; + ic->ic_update_chw = rtwn_update_chw; ic->ic_set_channel = rtwn_set_channel; - ic->ic_raw_xmit = rtwn_raw_xmit; ic->ic_transmit = rtwn_transmit; ic->ic_parent = rtwn_parent; ic->ic_vap_create = rtwn_vap_create; ic->ic_vap_delete = rtwn_vap_delete; + ic->ic_wme.wme_update = rtwn_wme_update; + ic->ic_updateslot = rtwn_update_slot; + ic->ic_update_promisc = rtwn_update_promisc; + ic->ic_update_mcast = rtwn_update_mcast; + ic->ic_node_alloc = rtwn_node_alloc; + ic->ic_newassoc = rtwn_newassoc; + sc->sc_node_free = ic->ic_node_free; + ic->ic_node_free = rtwn_node_free; - ieee80211_radiotap_attach(ic, - &sc->sc_txtap.wt_ihdr, sizeof(sc->sc_txtap), - RTWN_TX_RADIOTAP_PRESENT, - &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), - RTWN_RX_RADIOTAP_PRESENT); - - /* - * Hook our interrupt after all initialization is complete. - */ - error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, - NULL, rtwn_intr, sc, &sc->sc_ih); - if (error != 0) { - device_printf(dev, "can't establish interrupt, error %d\n", - error); - goto fail; - } + rtwn_postattach(sc); + rtwn_radiotap_attach(sc); if (bootverbose) ieee80211_announce(ic); return (0); -fail: - rtwn_detach(dev); - return (error); -} - - -static int -rtwn_detach(device_t dev) -{ - struct rtwn_softc *sc = device_get_softc(dev); - int i; - - if (sc->sc_ic.ic_softc != NULL) { - rtwn_stop(sc); - - callout_drain(&sc->calib_to); - callout_drain(&sc->watchdog_to); - ieee80211_ifdetach(&sc->sc_ic); - mbufq_drain(&sc->sc_snd); - } - - /* Uninstall interrupt handler. */ - if (sc->irq != NULL) { - bus_teardown_intr(dev, sc->irq, sc->sc_ih); - bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq), - sc->irq); - pci_release_msi(dev); - } - - /* Free Tx/Rx buffers. */ - for (i = 0; i < RTWN_NTXQUEUES; i++) - rtwn_free_tx_list(sc, i); - rtwn_free_rx_list(sc); - - if (sc->mem != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, - rman_get_rid(sc->mem), sc->mem); - - RTWN_LOCK_DESTROY(sc); - return (0); -} - -static int -rtwn_shutdown(device_t dev) -{ - - return (0); -} - -static int -rtwn_suspend(device_t dev) -{ - return (0); -} - -static int -rtwn_resume(device_t dev) -{ - - return (0); +detach: + return (ENXIO); /* failure */ } static void -rtwn_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +rtwn_radiotap_attach(struct rtwn_softc *sc) { + struct rtwn_rx_radiotap_header *rxtap = &sc->sc_rxtap; + struct rtwn_tx_radiotap_header *txtap = &sc->sc_txtap; - if (error != 0) - return; - KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs)); - *(bus_addr_t *)arg = segs[0].ds_addr; + ieee80211_radiotap_attach(&sc->sc_ic, + &txtap->wt_ihdr, sizeof(*txtap), RTWN_TX_RADIOTAP_PRESENT, + &rxtap->wr_ihdr, sizeof(*rxtap), RTWN_RX_RADIOTAP_PRESENT); +} + +void +rtwn_sysctlattach(struct rtwn_softc *sc) +{ + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); + struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); + +#if 1 + sc->sc_ht40 = 0; + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "ht40", CTLFLAG_RDTUN, &sc->sc_ht40, + sc->sc_ht40, "Enable 40 MHz mode support"); +#endif + +#ifdef RTWN_DEBUG + SYSCTL_ADD_U32(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "debug", CTLFLAG_RWTUN, &sc->sc_debug, sc->sc_debug, + "Control debugging printfs"); +#endif + + sc->sc_hwcrypto = RTWN_CRYPTO_PAIR; + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "hwcrypto", CTLFLAG_RDTUN, &sc->sc_hwcrypto, + sc->sc_hwcrypto, "Enable h/w crypto: " + "0 - disable, 1 - pairwise keys, 2 - all keys"); + if (sc->sc_hwcrypto >= RTWN_CRYPTO_MAX) + sc->sc_hwcrypto = RTWN_CRYPTO_FULL; + + sc->sc_ratectl_sysctl = RTWN_RATECTL_NET80211; + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "ratectl", CTLFLAG_RDTUN, &sc->sc_ratectl_sysctl, + sc->sc_ratectl_sysctl, "Select rate control mechanism: " + "0 - disabled, 1 - via net80211, 2 - via firmware"); + if (sc->sc_ratectl_sysctl >= RTWN_RATECTL_MAX) + sc->sc_ratectl_sysctl = RTWN_RATECTL_FW; + + sc->sc_ratectl = sc->sc_ratectl_sysctl; + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "ratectl_selected", CTLFLAG_RD, &sc->sc_ratectl, + sc->sc_ratectl, + "Currently selected rate control mechanism (by the driver)"); +} + +void +rtwn_detach(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + if (ic->ic_softc == sc) { + /* Stop command queue. */ + RTWN_CMDQ_LOCK(sc); + sc->sc_detached = 1; + RTWN_CMDQ_UNLOCK(sc); + + ieee80211_draintask(ic, &sc->cmdq_task); + ieee80211_ifdetach(ic); + } + + rtwn_cmdq_destroy(sc); + if (RTWN_NT_LOCK_INITIALIZED(sc)) + RTWN_NT_LOCK_DESTROY(sc); +} + +void +rtwn_suspend(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + ieee80211_suspend_all(ic); +} + +void +rtwn_resume(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + ieee80211_resume_all(ic); } static void -rtwn_setup_rx_desc(struct rtwn_softc *sc, struct r92c_rx_desc *desc, - bus_addr_t addr, size_t len, int idx) +rtwn_vap_decrement_counters(struct rtwn_softc *sc, + enum ieee80211_opmode opmode, int id) { - memset(desc, 0, sizeof(*desc)); - desc->rxdw0 = htole32(SM(R92C_RXDW0_PKTLEN, len) | - ((idx == RTWN_RX_LIST_COUNT - 1) ? R92C_RXDW0_EOR : 0)); - desc->rxbufaddr = htole32(addr); - bus_space_barrier(sc->sc_st, sc->sc_sh, 0, sc->sc_mapsize, - BUS_SPACE_BARRIER_WRITE); - desc->rxdw0 |= htole32(R92C_RXDW0_OWN); -} + RTWN_ASSERT_LOCKED(sc); -static int -rtwn_alloc_rx_list(struct rtwn_softc *sc) -{ - struct rtwn_rx_ring *rx_ring = &sc->rx_ring; - struct rtwn_rx_data *rx_data; - bus_size_t size; - int i, error; - - /* Allocate Rx descriptors. */ - size = sizeof(struct r92c_rx_desc) * RTWN_RX_LIST_COUNT; - error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, - size, 1, size, 0, NULL, NULL, &rx_ring->desc_dmat); - if (error != 0) { - device_printf(sc->sc_dev, "could not create rx desc DMA tag\n"); - goto fail; + if (id != RTWN_VAP_ID_INVALID) { + KASSERT(id == 0 || id == 1, ("wrong vap id %d!\n", id)); + KASSERT(sc->vaps[id] != NULL, ("vap pointer is NULL\n")); + sc->vaps[id] = NULL; } - error = bus_dmamem_alloc(rx_ring->desc_dmat, (void **)&rx_ring->desc, - BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, - &rx_ring->desc_map); - if (error != 0) { - device_printf(sc->sc_dev, "could not allocate rx desc\n"); - goto fail; - } - error = bus_dmamap_load(rx_ring->desc_dmat, rx_ring->desc_map, - rx_ring->desc, size, rtwn_dma_map_addr, &rx_ring->paddr, 0); - if (error != 0) { - device_printf(sc->sc_dev, "could not load rx desc DMA map\n"); - goto fail; - } - bus_dmamap_sync(rx_ring->desc_dmat, rx_ring->desc_map, - BUS_DMASYNC_PREWRITE); - - /* Create RX buffer DMA tag. */ - error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, - 1, MCLBYTES, 0, NULL, NULL, &rx_ring->data_dmat); - if (error != 0) { - device_printf(sc->sc_dev, "could not create rx buf DMA tag\n"); - goto fail; + switch (opmode) { + case IEEE80211_M_HOSTAP: + sc->ap_vaps--; + /* FALLTHROUGH */ + case IEEE80211_M_IBSS: + sc->bcn_vaps--; + /* FALLTHROUGH */ + case IEEE80211_M_STA: + sc->nvaps--; + break; + case IEEE80211_M_MONITOR: + sc->mon_vaps--; + break; + default: + KASSERT(0, ("wrong opmode %d\n", opmode)); + break; } - /* Allocate Rx buffers. */ - for (i = 0; i < RTWN_RX_LIST_COUNT; i++) { - rx_data = &rx_ring->rx_data[i]; - error = bus_dmamap_create(rx_ring->data_dmat, 0, &rx_data->map); - if (error != 0) { - device_printf(sc->sc_dev, - "could not create rx buf DMA map\n"); - goto fail; - } + KASSERT(sc->vaps_running >= 0 && sc->monvaps_running >= 0, + ("number of running vaps is negative (vaps %d, monvaps %d)\n", + sc->vaps_running, sc->monvaps_running)); + KASSERT(sc->vaps_running - sc->monvaps_running <= RTWN_PORT_COUNT, + ("number of running vaps is too big (vaps %d, monvaps %d)\n", + sc->vaps_running, sc->monvaps_running)); - rx_data->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); - if (rx_data->m == NULL) { - device_printf(sc->sc_dev, - "could not allocate rx mbuf\n"); - error = ENOMEM; - goto fail; - } - - error = bus_dmamap_load(rx_ring->data_dmat, rx_data->map, - mtod(rx_data->m, void *), MCLBYTES, rtwn_dma_map_addr, - &rx_data->paddr, BUS_DMA_NOWAIT); - if (error != 0) { - device_printf(sc->sc_dev, - "could not load rx buf DMA map"); - goto fail; - } - - rtwn_setup_rx_desc(sc, &rx_ring->desc[i], rx_data->paddr, - MCLBYTES, i); - } - return (0); - -fail: - rtwn_free_rx_list(sc); - return (error); + KASSERT(sc->nvaps >= 0 && sc->nvaps <= RTWN_PORT_COUNT, + ("wrong value %d for nvaps\n", sc->nvaps)); + KASSERT(sc->mon_vaps >= 0, ("mon_vaps is negative (%d)\n", + sc->mon_vaps)); + KASSERT(sc->bcn_vaps >= 0 && ((RTWN_CHIP_HAS_BCNQ1(sc) && + sc->bcn_vaps <= RTWN_PORT_COUNT) || sc->bcn_vaps <= 1), + ("bcn_vaps value %d is wrong\n", sc->bcn_vaps)); + KASSERT(sc->ap_vaps >= 0 && ((RTWN_CHIP_HAS_BCNQ1(sc) && + sc->ap_vaps <= RTWN_PORT_COUNT) || sc->ap_vaps <= 1), + ("ap_vaps value %d is wrong\n", sc->ap_vaps)); } static void -rtwn_reset_rx_list(struct rtwn_softc *sc) +rtwn_set_ic_opmode(struct rtwn_softc *sc) { - struct rtwn_rx_ring *rx_ring = &sc->rx_ring; - struct rtwn_rx_data *rx_data; - int i; + struct ieee80211com *ic = &sc->sc_ic; - for (i = 0; i < RTWN_RX_LIST_COUNT; i++) { - rx_data = &rx_ring->rx_data[i]; - rtwn_setup_rx_desc(sc, &rx_ring->desc[i], rx_data->paddr, - MCLBYTES, i); - } + RTWN_ASSERT_LOCKED(sc); + + /* for ieee80211_reset_erp() */ + if (sc->bcn_vaps - sc->ap_vaps > 0) + ic->ic_opmode = IEEE80211_M_IBSS; + else if (sc->ap_vaps > 0) + ic->ic_opmode = IEEE80211_M_HOSTAP; + else if (sc->nvaps > 0) + ic->ic_opmode = IEEE80211_M_STA; + else + ic->ic_opmode = IEEE80211_M_MONITOR; } -static void -rtwn_free_rx_list(struct rtwn_softc *sc) -{ - struct rtwn_rx_ring *rx_ring = &sc->rx_ring; - struct rtwn_rx_data *rx_data; - int i; - - if (rx_ring->desc_dmat != NULL) { - if (rx_ring->desc != NULL) { - bus_dmamap_sync(rx_ring->desc_dmat, - rx_ring->desc_map, - BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(rx_ring->desc_dmat, - rx_ring->desc_map); - bus_dmamem_free(rx_ring->desc_dmat, rx_ring->desc, - rx_ring->desc_map); - rx_ring->desc = NULL; - } - bus_dma_tag_destroy(rx_ring->desc_dmat); - rx_ring->desc_dmat = NULL; - } - - for (i = 0; i < RTWN_RX_LIST_COUNT; i++) { - rx_data = &rx_ring->rx_data[i]; - - if (rx_data->m != NULL) { - bus_dmamap_sync(rx_ring->data_dmat, - rx_data->map, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(rx_ring->data_dmat, rx_data->map); - m_freem(rx_data->m); - rx_data->m = NULL; - } - bus_dmamap_destroy(rx_ring->data_dmat, rx_data->map); - rx_data->map = NULL; - } - if (rx_ring->data_dmat != NULL) { - bus_dma_tag_destroy(rx_ring->data_dmat); - rx_ring->data_dmat = NULL; - } -} - -static int -rtwn_alloc_tx_list(struct rtwn_softc *sc, int qid) -{ - struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid]; - struct rtwn_tx_data *tx_data; - bus_size_t size; - int i, error; - - size = sizeof(struct r92c_tx_desc) * RTWN_TX_LIST_COUNT; - error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), PAGE_SIZE, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, - size, 1, size, 0, NULL, NULL, &tx_ring->desc_dmat); - if (error != 0) { - device_printf(sc->sc_dev, "could not create tx ring DMA tag\n"); - goto fail; - } - - error = bus_dmamem_alloc(tx_ring->desc_dmat, (void **)&tx_ring->desc, - BUS_DMA_NOWAIT | BUS_DMA_ZERO, &tx_ring->desc_map); - if (error != 0) { - device_printf(sc->sc_dev, "can't map tx ring DMA memory\n"); - goto fail; - } - error = bus_dmamap_load(tx_ring->desc_dmat, tx_ring->desc_map, - tx_ring->desc, size, rtwn_dma_map_addr, &tx_ring->paddr, - BUS_DMA_NOWAIT); - if (error != 0) { - device_printf(sc->sc_dev, "could not load desc DMA map\n"); - goto fail; - } - bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, - BUS_DMASYNC_PREWRITE); - - error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, - 1, MCLBYTES, 0, NULL, NULL, &tx_ring->data_dmat); - if (error != 0) { - device_printf(sc->sc_dev, "could not create tx buf DMA tag\n"); - goto fail; - } - - for (i = 0; i < RTWN_TX_LIST_COUNT; i++) { - struct r92c_tx_desc *desc = &tx_ring->desc[i]; - - /* setup tx desc */ - desc->nextdescaddr = htole32(tx_ring->paddr + - + sizeof(struct r92c_tx_desc) - * ((i + 1) % RTWN_TX_LIST_COUNT)); - tx_data = &tx_ring->tx_data[i]; - error = bus_dmamap_create(tx_ring->data_dmat, 0, &tx_data->map); - if (error != 0) { - device_printf(sc->sc_dev, - "could not create tx buf DMA map\n"); - goto fail; - } - tx_data->m = NULL; - tx_data->ni = NULL; - } - return (0); - -fail: - rtwn_free_tx_list(sc, qid); - return (error); -} - -static void -rtwn_reset_tx_list(struct rtwn_softc *sc, int qid) -{ - struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid]; - int i; - - for (i = 0; i < RTWN_TX_LIST_COUNT; i++) { - struct r92c_tx_desc *desc = &tx_ring->desc[i]; - struct rtwn_tx_data *tx_data = &tx_ring->tx_data[i]; - - memset(desc, 0, sizeof(*desc) - - (sizeof(desc->reserved) + sizeof(desc->nextdescaddr64) + - sizeof(desc->nextdescaddr))); - - if (tx_data->m != NULL) { - bus_dmamap_sync(tx_ring->data_dmat, tx_data->map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(tx_ring->data_dmat, tx_data->map); - m_freem(tx_data->m); - tx_data->m = NULL; - } - if (tx_data->ni != NULL) { - ieee80211_free_node(tx_data->ni); - tx_data->ni = NULL; - } - } - - bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, - BUS_DMASYNC_POSTWRITE); - - sc->qfullmsk &= ~(1 << qid); - tx_ring->queued = 0; - tx_ring->cur = 0; -} - -static void -rtwn_free_tx_list(struct rtwn_softc *sc, int qid) -{ - struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid]; - struct rtwn_tx_data *tx_data; - int i; - - if (tx_ring->desc_dmat != NULL) { - if (tx_ring->desc != NULL) { - bus_dmamap_sync(tx_ring->desc_dmat, - tx_ring->desc_map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(tx_ring->desc_dmat, - tx_ring->desc_map); - bus_dmamem_free(tx_ring->desc_dmat, tx_ring->desc, - tx_ring->desc_map); - } - bus_dma_tag_destroy(tx_ring->desc_dmat); - } - - for (i = 0; i < RTWN_TX_LIST_COUNT; i++) { - tx_data = &tx_ring->tx_data[i]; - - if (tx_data->m != NULL) { - bus_dmamap_sync(tx_ring->data_dmat, tx_data->map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(tx_ring->data_dmat, tx_data->map); - m_freem(tx_data->m); - tx_data->m = NULL; - } - } - if (tx_ring->data_dmat != NULL) { - bus_dma_tag_destroy(tx_ring->data_dmat); - tx_ring->data_dmat = NULL; - } - - sc->qfullmsk &= ~(1 << qid); - tx_ring->queued = 0; - tx_ring->cur = 0; -} - - static struct ieee80211vap * rtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, enum ieee80211_opmode opmode, int flags, const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t mac[IEEE80211_ADDR_LEN]) { - struct rtwn_vap *rvp; + struct rtwn_softc *sc = ic->ic_softc; + struct rtwn_vap *uvp; struct ieee80211vap *vap; + int id = RTWN_VAP_ID_INVALID; - if (!TAILQ_EMPTY(&ic->ic_vaps)) - return (NULL); + RTWN_LOCK(sc); + KASSERT(sc->nvaps <= RTWN_PORT_COUNT, + ("nvaps overflow (%d > %d)\n", sc->nvaps, RTWN_PORT_COUNT)); + KASSERT(sc->ap_vaps <= RTWN_PORT_COUNT, + ("ap_vaps overflow (%d > %d)\n", sc->ap_vaps, RTWN_PORT_COUNT)); + KASSERT(sc->bcn_vaps <= RTWN_PORT_COUNT, + ("bcn_vaps overflow (%d > %d)\n", sc->bcn_vaps, RTWN_PORT_COUNT)); + + if (opmode != IEEE80211_M_MONITOR) { + switch (sc->nvaps) { + case 0: + id = 0; + break; + case 1: + if (sc->vaps[1] == NULL) + id = 1; + else if (sc->vaps[0] == NULL) + id = 0; + KASSERT(id != RTWN_VAP_ID_INVALID, + ("no free ports left\n")); + break; + case 2: + default: + goto fail; + } + + if (opmode == IEEE80211_M_IBSS || + opmode == IEEE80211_M_HOSTAP) { + if ((sc->bcn_vaps == 1 && !RTWN_CHIP_HAS_BCNQ1(sc)) || + sc->bcn_vaps == RTWN_PORT_COUNT) + goto fail; + } + } + + switch (opmode) { + case IEEE80211_M_HOSTAP: + sc->ap_vaps++; + /* FALLTHROUGH */ + case IEEE80211_M_IBSS: + sc->bcn_vaps++; + /* FALLTHROUGH */ + case IEEE80211_M_STA: + sc->nvaps++; + break; + case IEEE80211_M_MONITOR: + sc->mon_vaps++; + break; + default: + KASSERT(0, ("unknown opmode %d\n", opmode)); + goto fail; + } + RTWN_UNLOCK(sc); + + uvp = malloc(sizeof(struct rtwn_vap), M_80211_VAP, M_WAITOK | M_ZERO); + uvp->id = id; + if (id != RTWN_VAP_ID_INVALID) { + RTWN_LOCK(sc); + sc->vaps[id] = uvp; + RTWN_UNLOCK(sc); + } + vap = &uvp->vap; + /* enable s/w bmiss handling for sta mode */ - rvp = malloc(sizeof(struct rtwn_vap), M_80211_VAP, M_WAITOK | M_ZERO); - vap = &rvp->vap; if (ieee80211_vap_setup(ic, vap, name, unit, opmode, flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) { /* out of memory */ - free(rvp, M_80211_VAP); - return (NULL); + free(uvp, M_80211_VAP); + + RTWN_LOCK(sc); + rtwn_vap_decrement_counters(sc, opmode, id); + RTWN_UNLOCK(sc); + + return (NULL); } - /* Override state transition machine. */ - rvp->newstate = vap->iv_newstate; - vap->iv_newstate = rtwn_newstate; + rtwn_beacon_init(sc, &uvp->bcn_desc.txd[0], uvp->id); + rtwn_vap_preattach(sc, vap); - /* Complete setup. */ + /* override state transition machine */ + uvp->newstate = vap->iv_newstate; + if (opmode == IEEE80211_M_MONITOR) + vap->iv_newstate = rtwn_monitor_newstate; + else + vap->iv_newstate = rtwn_newstate; + vap->iv_update_beacon = rtwn_update_beacon; + vap->iv_reset = rtwn_ioctl_reset; + vap->iv_key_alloc = rtwn_key_alloc; + vap->iv_key_set = rtwn_key_set; + vap->iv_key_delete = rtwn_key_delete; + vap->iv_max_aid = sc->macid_limit; + + /* 802.11n parameters */ + vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_16; + vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K; + + if (opmode == IEEE80211_M_IBSS) { + uvp->recv_mgmt = vap->iv_recv_mgmt; + vap->iv_recv_mgmt = rtwn_adhoc_recv_mgmt; + TASK_INIT(&uvp->tsf_sync_adhoc_task, 0, + rtwn_tsf_sync_adhoc_task, vap); + callout_init(&uvp->tsf_sync_adhoc, 0); + } + + /* + * NB: driver can select net80211 RA even when user requests + * another mechanism. + */ + ieee80211_ratectl_init(vap); + + /* complete setup */ ieee80211_vap_attach(vap, ieee80211_media_change, ieee80211_media_status, mac); - ic->ic_opmode = opmode; + + RTWN_LOCK(sc); + rtwn_set_ic_opmode(sc); + if (sc->sc_flags & RTWN_RUNNING) { + if (uvp->id != RTWN_VAP_ID_INVALID) + rtwn_set_macaddr(sc, vap->iv_myaddr, uvp->id); + + rtwn_rxfilter_update(sc); + } + RTWN_UNLOCK(sc); + return (vap); + +fail: + RTWN_UNLOCK(sc); + return (NULL); } static void rtwn_vap_delete(struct ieee80211vap *vap) { - struct rtwn_vap *rvp = RTWN_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct rtwn_softc *sc = ic->ic_softc; + struct rtwn_vap *uvp = RTWN_VAP(vap); + /* Put vap into INIT state + stop device if needed. */ + ieee80211_stop(vap); + ieee80211_draintask(ic, &vap->iv_nstate_task); + ieee80211_draintask(ic, &ic->ic_parent_task); + + RTWN_LOCK(sc); + if (uvp->bcn_mbuf != NULL) + m_freem(uvp->bcn_mbuf); + /* Cancel any unfinished Tx. */ + rtwn_reset_lists(sc, vap); + rtwn_vap_decrement_counters(sc, vap->iv_opmode, uvp->id); + rtwn_set_ic_opmode(sc); + if (sc->sc_flags & RTWN_RUNNING) + rtwn_rxfilter_update(sc); + RTWN_UNLOCK(sc); + + if (vap->iv_opmode == IEEE80211_M_IBSS) { + ieee80211_draintask(ic, &uvp->tsf_sync_adhoc_task); + callout_drain(&uvp->tsf_sync_adhoc); + } + + ieee80211_ratectl_deinit(vap); ieee80211_vap_detach(vap); - free(rvp, M_80211_VAP); -} - -static void -rtwn_write_1(struct rtwn_softc *sc, uint16_t addr, uint8_t val) -{ - - bus_space_write_1(sc->sc_st, sc->sc_sh, addr, val); -} - -static void -rtwn_write_2(struct rtwn_softc *sc, uint16_t addr, uint16_t val) -{ - - val = htole16(val); - bus_space_write_2(sc->sc_st, sc->sc_sh, addr, val); -} - -static void -rtwn_write_4(struct rtwn_softc *sc, uint16_t addr, uint32_t val) -{ - - val = htole32(val); - bus_space_write_4(sc->sc_st, sc->sc_sh, addr, val); -} - -static uint8_t -rtwn_read_1(struct rtwn_softc *sc, uint16_t addr) -{ - - return (bus_space_read_1(sc->sc_st, sc->sc_sh, addr)); -} - -static uint16_t -rtwn_read_2(struct rtwn_softc *sc, uint16_t addr) -{ - - return (bus_space_read_2(sc->sc_st, sc->sc_sh, addr)); -} - -static uint32_t -rtwn_read_4(struct rtwn_softc *sc, uint16_t addr) -{ - - return (bus_space_read_4(sc->sc_st, sc->sc_sh, addr)); -} - -static int -rtwn_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len) -{ - struct r92c_fw_cmd cmd; - int ntries; - - /* Wait for current FW box to be empty. */ - for (ntries = 0; ntries < 100; ntries++) { - if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur))) - break; - DELAY(1); - } - if (ntries == 100) { - device_printf(sc->sc_dev, - "could not send firmware command %d\n", id); - return (ETIMEDOUT); - } - memset(&cmd, 0, sizeof(cmd)); - cmd.id = id; - if (len > 3) - cmd.id |= R92C_CMD_FLAG_EXT; - KASSERT(len <= sizeof(cmd.msg), ("rtwn_fw_cmd\n")); - memcpy(cmd.msg, buf, len); - - /* Write the first word last since that will trigger the FW. */ - rtwn_write_2(sc, R92C_HMEBOX_EXT(sc->fwcur), *((uint8_t *)&cmd + 4)); - rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur), *((uint8_t *)&cmd + 0)); - - sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX; - - /* Give firmware some time for processing. */ - DELAY(2000); - - return (0); -} - -static void -rtwn_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr, uint32_t val) -{ - rtwn_bb_write(sc, R92C_LSSI_PARAM(chain), - SM(R92C_LSSI_PARAM_ADDR, addr) | - SM(R92C_LSSI_PARAM_DATA, val)); -} - -static uint32_t -rtwn_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr) -{ - uint32_t reg[R92C_MAX_CHAINS], val; - - reg[0] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)); - if (chain != 0) - reg[chain] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(chain)); - - rtwn_bb_write(sc, R92C_HSSI_PARAM2(0), - reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE); - DELAY(1000); - - rtwn_bb_write(sc, R92C_HSSI_PARAM2(chain), - RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) | - R92C_HSSI_PARAM2_READ_EDGE); - DELAY(1000); - - rtwn_bb_write(sc, R92C_HSSI_PARAM2(0), - reg[0] | R92C_HSSI_PARAM2_READ_EDGE); - DELAY(1000); - - if (rtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI) - val = rtwn_bb_read(sc, R92C_HSPI_READBACK(chain)); - else - val = rtwn_bb_read(sc, R92C_LSSI_READBACK(chain)); - return (MS(val, R92C_LSSI_READBACK_DATA)); -} - -static int -rtwn_llt_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data) -{ - int ntries; - - rtwn_write_4(sc, R92C_LLT_INIT, - SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) | - SM(R92C_LLT_INIT_ADDR, addr) | - SM(R92C_LLT_INIT_DATA, data)); - /* Wait for write operation to complete. */ - for (ntries = 0; ntries < 20; ntries++) { - if (MS(rtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) == - R92C_LLT_INIT_OP_NO_ACTIVE) - return (0); - DELAY(5); - } - return (ETIMEDOUT); -} - -static uint8_t -rtwn_efuse_read_1(struct rtwn_softc *sc, uint16_t addr) -{ - uint32_t reg; - int ntries; - - reg = rtwn_read_4(sc, R92C_EFUSE_CTRL); - reg = RW(reg, R92C_EFUSE_CTRL_ADDR, addr); - reg &= ~R92C_EFUSE_CTRL_VALID; - rtwn_write_4(sc, R92C_EFUSE_CTRL, reg); - /* Wait for read operation to complete. */ - for (ntries = 0; ntries < 100; ntries++) { - reg = rtwn_read_4(sc, R92C_EFUSE_CTRL); - if (reg & R92C_EFUSE_CTRL_VALID) - return (MS(reg, R92C_EFUSE_CTRL_DATA)); - DELAY(5); - } - device_printf(sc->sc_dev, - "could not read efuse byte at address 0x%x\n", addr); - return (0xff); -} - -static void -rtwn_efuse_read(struct rtwn_softc *sc) -{ - uint8_t *rom = (uint8_t *)&sc->rom; - uint16_t addr = 0; - uint32_t reg; - uint8_t off, msk; - int i; - - reg = rtwn_read_2(sc, R92C_SYS_ISO_CTRL); - if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) { - rtwn_write_2(sc, R92C_SYS_ISO_CTRL, - reg | R92C_SYS_ISO_CTRL_PWC_EV12V); - } - reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN); - if (!(reg & R92C_SYS_FUNC_EN_ELDR)) { - rtwn_write_2(sc, R92C_SYS_FUNC_EN, - reg | R92C_SYS_FUNC_EN_ELDR); - } - reg = rtwn_read_2(sc, R92C_SYS_CLKR); - if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) != - (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) { - rtwn_write_2(sc, R92C_SYS_CLKR, - reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M); - } - memset(&sc->rom, 0xff, sizeof(sc->rom)); - while (addr < 512) { - reg = rtwn_efuse_read_1(sc, addr); - if (reg == 0xff) - break; - addr++; - off = reg >> 4; - msk = reg & 0xf; - for (i = 0; i < 4; i++) { - if (msk & (1 << i)) - continue; - rom[off * 8 + i * 2 + 0] = - rtwn_efuse_read_1(sc, addr); - addr++; - rom[off * 8 + i * 2 + 1] = - rtwn_efuse_read_1(sc, addr); - addr++; - } - } -#ifdef RTWN_DEBUG - if (sc->sc_debug >= 2) { - /* Dump ROM content. */ - printf("\n"); - for (i = 0; i < sizeof(sc->rom); i++) - printf("%02x:", rom[i]); - printf("\n"); - } -#endif + free(uvp, M_80211_VAP); } static int @@ -1019,876 +654,687 @@ rtwn_read_chipid(struct rtwn_softc *sc) uint32_t reg; reg = rtwn_read_4(sc, R92C_SYS_CFG); - if (reg & R92C_SYS_CFG_TRP_VAUX_EN) - /* Unsupported test chip. */ - return (EIO); + if (reg & R92C_SYS_CFG_TRP_VAUX_EN) /* test chip */ + return (EOPNOTSUPP); + + rtwn_read_chipid_vendor(sc, reg); - if (reg & R92C_SYS_CFG_TYPE_92C) { - sc->chip |= RTWN_CHIP_92C; - /* Check if it is a castrated 8192C. */ - if (MS(rtwn_read_4(sc, R92C_HPON_FSM), - R92C_HPON_FSM_CHIP_BONDING_ID) == - R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R) - sc->chip |= RTWN_CHIP_92C_1T2R; - } - if (reg & R92C_SYS_CFG_VENDOR_UMC) { - sc->chip |= RTWN_CHIP_UMC; - if (MS(reg, R92C_SYS_CFG_CHIP_VER_RTL) == 0) - sc->chip |= RTWN_CHIP_UMC_A_CUT; - } return (0); } -static void -rtwn_read_rom(struct rtwn_softc *sc) +static int +rtwn_ioctl_reset(struct ieee80211vap *vap, u_long cmd) { - struct r92c_rom *rom = &sc->rom; + int error; - /* Read full ROM image. */ - rtwn_efuse_read(sc); + switch (cmd) { +#ifndef RTWN_WITHOUT_UCODE + case IEEE80211_IOC_POWERSAVE: + case IEEE80211_IOC_POWERSAVESLEEP: + { + struct rtwn_softc *sc = vap->iv_ic->ic_softc; + struct rtwn_vap *uvp = RTWN_VAP(vap); - if (rom->id != 0x8129) - device_printf(sc->sc_dev, "invalid EEPROM ID 0x%x\n", rom->id); + if (vap->iv_opmode == IEEE80211_M_STA && uvp->id == 0) { + RTWN_LOCK(sc); + if (sc->sc_flags & RTWN_RUNNING) + error = rtwn_set_pwrmode(sc, vap, 1); + else + error = 0; + RTWN_UNLOCK(sc); + if (error != 0) + error = ENETRESET; + } else + error = EOPNOTSUPP; + break; + } +#endif + case IEEE80211_IOC_SHORTGI: + case IEEE80211_IOC_RTSTHRESHOLD: + case IEEE80211_IOC_PROTMODE: + case IEEE80211_IOC_HTPROTMODE: + error = 0; + break; + default: + error = ENETRESET; + break; + } - /* XXX Weird but this is what the vendor driver does. */ - sc->pa_setting = rtwn_efuse_read_1(sc, 0x1fa); - DPRINTF(("PA setting=0x%x\n", sc->pa_setting)); - - sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE); - - sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY); - DPRINTF(("regulatory type=%d\n", sc->regulatory)); - - IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr); + return (error); } -static __inline uint8_t -rate2ridx(uint8_t rate) +#ifndef RTWN_WITHOUT_UCODE +static void +rtwn_set_media_status(struct rtwn_softc *sc, union sec_param *data) { - switch (rate) { - case 12: return 4; - case 18: return 5; - case 24: return 6; - case 36: return 7; - case 48: return 8; - case 72: return 9; - case 96: return 10; - case 108: return 11; - case 2: return 0; - case 4: return 1; - case 11: return 2; - case 22: return 3; - default: return RTWN_RIDX_UNKNOWN; + sc->sc_set_media_status(sc, data->macid); +} + +static int +rtwn_tx_fwpkt_check(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + int ntries, error; + + for (ntries = 0; ntries < 5; ntries++) { + error = rtwn_push_nulldata(sc, vap); + if (error == 0) + break; + } + if (ntries == 5) { + device_printf(sc->sc_dev, + "%s: cannot push f/w frames into chip, error %d!\n", + __func__, error); + return (error); + } + + return (0); +} + +static int +rtwn_construct_nulldata(struct rtwn_softc *sc, struct ieee80211vap *vap, + uint8_t *ptr, int qos) +{ + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211com *ic = &sc->sc_ic; + struct rtwn_tx_desc_common *txd; + struct ieee80211_frame *wh; + int pktlen; + + /* XXX obtain from net80211 */ + wh = (struct ieee80211_frame *)(ptr + sc->txdesc_len); + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; + wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; + IEEE80211_ADDR_COPY(wh->i_addr1, vap->iv_bss->ni_bssid); + IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); + IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_macaddr); + + txd = (struct rtwn_tx_desc_common *)ptr; + txd->offset = sc->txdesc_len; + pktlen = sc->txdesc_len; + if (qos) { + struct ieee80211_qosframe *qwh; + const int tid = WME_AC_TO_TID(WME_AC_BE); + + qwh = (struct ieee80211_qosframe *)wh; + qwh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS_NULL; + qwh->i_qos[0] = tid & IEEE80211_QOS_TID; + + txd->pktlen = htole16(sizeof(struct ieee80211_qosframe)); + pktlen += sizeof(struct ieee80211_qosframe); + } else { + wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_NODATA; + + txd->pktlen = htole16(sizeof(struct ieee80211_frame)); + pktlen += sizeof(struct ieee80211_frame); + } + + rtwn_fill_tx_desc_null(sc, ptr, + ic->ic_curmode == IEEE80211_MODE_11B, qos, uvp->id); + + return (pktlen); +} + +static int +rtwn_push_nulldata(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211com *ic = vap->iv_ic; + struct ieee80211_channel *c = ic->ic_curchan; + struct mbuf *m; + uint8_t *ptr; + int required_size, bcn_size, null_size, null_data, error; + + if (!(sc->sc_flags & RTWN_FW_LOADED)) + return (0); /* requires firmware */ + + KASSERT(sc->page_size > 0, ("page size was not set!\n")); + + /* Leave some space for beacon (multi-vap) */ + bcn_size = roundup(RTWN_BCN_MAX_SIZE, sc->page_size); + /* 1 page for Null Data + 1 page for Qos Null Data frames. */ + required_size = bcn_size + sc->page_size * 2; + + m = m_get2(required_size, M_NOWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) + return (ENOMEM); + + /* Setup beacon descriptor. */ + rtwn_beacon_set_rate(sc, &uvp->bcn_desc.txd[0], + IEEE80211_IS_CHAN_5GHZ(c)); + + ptr = mtod(m, uint8_t *); + memset(ptr, 0, required_size - sc->txdesc_len); + + /* Construct Null Data frame. */ + ptr += bcn_size - sc->txdesc_len; + null_size = rtwn_construct_nulldata(sc, vap, ptr, 0); + KASSERT(null_size < sc->page_size, + ("recalculate size for Null Data frame\n")); + + /* Construct Qos Null Data frame. */ + ptr += roundup(null_size, sc->page_size); + null_size = rtwn_construct_nulldata(sc, vap, ptr, 1); + KASSERT(null_size < sc->page_size, + ("recalculate size for Qos Null Data frame\n")); + + /* Do not try to detect a beacon here. */ + rtwn_setbits_1_shift(sc, R92C_CR, 0, R92C_CR_ENSWBCN, 1); + rtwn_setbits_1_shift(sc, R92C_FWHW_TXQ_CTRL, + R92C_FWHW_TXQ_CTRL_REAL_BEACON, 0, 2); + + if (uvp->bcn_mbuf != NULL) + m_freem(uvp->bcn_mbuf); + + m->m_pkthdr.len = m->m_len = required_size - sc->txdesc_len; + uvp->bcn_mbuf = m; + + error = rtwn_tx_beacon_check(sc, uvp); + if (error != 0) { + RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON, + "%s: frame was not recognized!\n", __func__); + goto fail; + } + + /* Setup addresses in firmware. */ + null_data = howmany(bcn_size, sc->page_size); + error = rtwn_set_rsvd_page(sc, 0, null_data, null_data + 1); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: CMD_RSVD_PAGE was not sent, error %d\n", + __func__, error); + goto fail; + } + +fail: + /* Re-enable beacon detection. */ + rtwn_setbits_1_shift(sc, R92C_FWHW_TXQ_CTRL, + 0, R92C_FWHW_TXQ_CTRL_REAL_BEACON, 2); + rtwn_setbits_1_shift(sc, R92C_CR, R92C_CR_ENSWBCN, 0, 1); + + /* Restore beacon (if present). */ + if (sc->bcn_vaps > 0 && sc->vaps[!uvp->id] != NULL) { + struct rtwn_vap *uvp2 = sc->vaps[!uvp->id]; + + if (uvp2->curr_mode != R92C_MSR_NOLINK) + error = rtwn_tx_beacon_check(sc, uvp2); + } + + return (error); +} + +static void +rtwn_pwrmode_init(void *arg) +{ + struct rtwn_softc *sc = arg; + + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_set_pwrmode_cb); +} + +static void +rtwn_set_pwrmode_cb(struct rtwn_softc *sc, union sec_param *data) +{ + struct ieee80211vap *vap = &sc->vaps[0]->vap; + + if (vap != NULL) + rtwn_set_pwrmode(sc, vap, 1); +} +#endif + +static void +rtwn_tsf_sync_adhoc(void *arg) +{ + struct ieee80211vap *vap = arg; + struct ieee80211com *ic = vap->iv_ic; + struct rtwn_vap *uvp = RTWN_VAP(vap); + + if (uvp->curr_mode != R92C_MSR_NOLINK) { + /* Do it in process context. */ + ieee80211_runtask(ic, &uvp->tsf_sync_adhoc_task); } } /* - * Initialize rate adaptation in firmware. + * Workaround for TSF synchronization: + * when BSSID filter in IBSS mode is not set + * (and TSF synchronization is enabled), then any beacon may update it. + * This routine synchronizes it when BSSID matching is enabled (IBSS merge + * is not possible during this period). + * + * NOTE: there is no race with rtwn_newstate(), since it uses the same + * taskqueue. */ -static int -rtwn_ra_init(struct rtwn_softc *sc) +static void +rtwn_tsf_sync_adhoc_task(void *arg, int pending) +{ + struct ieee80211vap *vap = arg; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct rtwn_softc *sc = vap->iv_ic->ic_softc; + struct ieee80211_node *ni; + + RTWN_LOCK(sc); + ni = ieee80211_ref_node(vap->iv_bss); + + /* Accept beacons with the same BSSID. */ + rtwn_set_rx_bssid_all(sc, 0); + + /* Enable synchronization. */ + rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id), + R92C_BCN_CTRL_DIS_TSF_UDT0, 0); + + /* Synchronize. */ + rtwn_delay(sc, ni->ni_intval * 5 * 1000); + + /* Disable synchronization. */ + rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id), + 0, R92C_BCN_CTRL_DIS_TSF_UDT0); + + /* Accept all beacons. */ + rtwn_set_rx_bssid_all(sc, 1); + + /* Schedule next TSF synchronization. */ + callout_reset(&uvp->tsf_sync_adhoc, 60*hz, rtwn_tsf_sync_adhoc, vap); + + ieee80211_free_node(ni); + RTWN_UNLOCK(sc); +} + +static void +rtwn_tsf_sync_enable(struct rtwn_softc *sc, struct ieee80211vap *vap) { struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct ieee80211_node *ni = ieee80211_ref_node(vap->iv_bss); - struct ieee80211_rateset *rs = &ni->ni_rates; - struct r92c_fw_cmd_macid_cfg cmd; - uint32_t rates, basicrates; - uint8_t maxrate, maxbasicrate, mode, ridx; - int error, i; + struct rtwn_vap *uvp = RTWN_VAP(vap); - /* Get normal and basic rates mask. */ - rates = basicrates = 0; - maxrate = maxbasicrate = 0; - for (i = 0; i < rs->rs_nrates; i++) { - /* Convert 802.11 rate to HW rate index. */ - ridx = rate2ridx(IEEE80211_RV(rs->rs_rates[i])); - if (ridx == RTWN_RIDX_UNKNOWN) /* Unknown rate, skip. */ - continue; - rates |= 1 << ridx; - if (ridx > maxrate) - maxrate = ridx; - if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) { - basicrates |= 1 << ridx; - if (ridx > maxbasicrate) - maxbasicrate = ridx; - } + /* Reset TSF. */ + rtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RESET(uvp->id)); + + switch (vap->iv_opmode) { + case IEEE80211_M_STA: + /* Enable TSF synchronization. */ + rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id), + R92C_BCN_CTRL_DIS_TSF_UDT0, 0); + break; + case IEEE80211_M_IBSS: + ieee80211_runtask(ic, &uvp->tsf_sync_adhoc_task); + /* FALLTHROUGH */ + case IEEE80211_M_HOSTAP: + /* Enable beaconing. */ + rtwn_beacon_enable(sc, uvp->id, 1); + break; + default: + device_printf(sc->sc_dev, "undefined opmode %d\n", + vap->iv_opmode); + return; } - if (ic->ic_curmode == IEEE80211_MODE_11B) - mode = R92C_RAID_11B; +} + +static void +rtwn_set_ack_preamble(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint32_t reg; + + reg = rtwn_read_4(sc, R92C_WMAC_TRXPTCL_CTL); + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) + reg |= R92C_WMAC_TRXPTCL_SHPRE; else - mode = R92C_RAID_11BG; - DPRINTF(("mode=0x%x rates=0x%08x, basicrates=0x%08x\n", - mode, rates, basicrates)); - - /* Set rates mask for group addressed frames. */ - cmd.macid = RTWN_MACID_BC | RTWN_MACID_VALID; - cmd.mask = htole32(mode << 28 | basicrates); - error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); - if (error != 0) { - device_printf(sc->sc_dev, - "could not add broadcast station\n"); - return (error); - } - /* Set initial MRR rate. */ - DPRINTF(("maxbasicrate=%d\n", maxbasicrate)); - rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(RTWN_MACID_BC), - maxbasicrate); - - /* Set rates mask for unicast frames. */ - cmd.macid = RTWN_MACID_BSS | RTWN_MACID_VALID; - cmd.mask = htole32(mode << 28 | rates); - error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); - if (error != 0) { - device_printf(sc->sc_dev, "could not add BSS station\n"); - return (error); - } - /* Set initial MRR rate. */ - DPRINTF(("maxrate=%d\n", maxrate)); - rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(RTWN_MACID_BSS), - maxrate); - - /* Configure Automatic Rate Fallback Register. */ - if (ic->ic_curmode == IEEE80211_MODE_11B) { - if (rates & 0x0c) - rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0d)); - else - rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0f)); - } else - rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0ff5)); - - /* Indicate highest supported rate. */ - ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1]; - return (0); + reg &= ~R92C_WMAC_TRXPTCL_SHPRE; + rtwn_write_4(sc, R92C_WMAC_TRXPTCL_CTL, reg); } static void -rtwn_tsf_sync_enable(struct rtwn_softc *sc) +rtwn_set_mode(struct rtwn_softc *sc, uint8_t mode, int id) { - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct ieee80211_node *ni = vap->iv_bss; - uint64_t tsf; - /* Enable TSF synchronization. */ - rtwn_write_1(sc, R92C_BCN_CTRL, - rtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_DIS_TSF_UDT0); - - rtwn_write_1(sc, R92C_BCN_CTRL, - rtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_EN_BCN); - - /* Set initial TSF. */ - memcpy(&tsf, ni->ni_tstamp.data, 8); - tsf = le64toh(tsf); - tsf = tsf - (tsf % (vap->iv_bss->ni_intval * IEEE80211_DUR_TU)); - tsf -= IEEE80211_DUR_TU; - rtwn_write_4(sc, R92C_TSFTR + 0, tsf); - rtwn_write_4(sc, R92C_TSFTR + 4, tsf >> 32); - - rtwn_write_1(sc, R92C_BCN_CTRL, - rtwn_read_1(sc, R92C_BCN_CTRL) | R92C_BCN_CTRL_EN_BCN); + rtwn_setbits_1(sc, R92C_MSR, R92C_MSR_MASK << id * 2, mode << id * 2); + if (sc->vaps[id] != NULL) + sc->vaps[id]->curr_mode = mode; } -static void -rtwn_set_led(struct rtwn_softc *sc, int led, int on) +static int +rtwn_monitor_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, + int arg) { - uint8_t reg; + struct ieee80211com *ic = vap->iv_ic; + struct rtwn_softc *sc = ic->ic_softc; + struct rtwn_vap *uvp = RTWN_VAP(vap); - if (led == RTWN_LED_LINK) { - reg = rtwn_read_1(sc, R92C_LEDCFG2) & 0xf0; - if (!on) - reg |= R92C_LEDCFG2_DIS; - else - reg |= R92C_LEDCFG2_EN; - rtwn_write_1(sc, R92C_LEDCFG2, reg); - sc->ledlink = on; /* Save LED state. */ - } -} + RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s -> %s\n", + ieee80211_state_name[vap->iv_state], + ieee80211_state_name[nstate]); -static void -rtwn_calib_to(void *arg) -{ - struct rtwn_softc *sc = arg; - struct r92c_fw_cmd_rssi cmd; + if (vap->iv_state != nstate) { + IEEE80211_UNLOCK(ic); + RTWN_LOCK(sc); - if (sc->avg_pwdb != -1) { - /* Indicate Rx signal strength to FW for rate adaptation. */ - memset(&cmd, 0, sizeof(cmd)); - cmd.macid = 0; /* BSS. */ - cmd.pwdb = sc->avg_pwdb; - DPRINTFN(3, ("sending RSSI command avg=%d\n", sc->avg_pwdb)); - rtwn_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, sizeof(cmd)); + switch (nstate) { + case IEEE80211_S_INIT: + sc->vaps_running--; + sc->monvaps_running--; + + if (sc->vaps_running == 0) { + /* Turn link LED off. */ + rtwn_set_led(sc, RTWN_LED_LINK, 0); + } + break; + case IEEE80211_S_RUN: + sc->vaps_running++; + sc->monvaps_running++; + + if (sc->vaps_running == 1) { + /* Turn link LED on. */ + rtwn_set_led(sc, RTWN_LED_LINK, 1); + } + break; + default: + /* NOTREACHED */ + break; + } + + RTWN_UNLOCK(sc); + IEEE80211_LOCK(ic); } - /* Do temperature compensation. */ - rtwn_temp_calib(sc); - - callout_reset(&sc->calib_to, hz * 2, rtwn_calib_to, sc); + return (uvp->newstate(vap, nstate, arg)); } static int rtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) { - struct rtwn_vap *rvp = RTWN_VAP(vap); + struct rtwn_vap *uvp = RTWN_VAP(vap); struct ieee80211com *ic = vap->iv_ic; - struct ieee80211_node *ni = vap->iv_bss; struct rtwn_softc *sc = ic->ic_softc; - uint32_t reg; + enum ieee80211_state ostate; + int error, early_newstate; + + ostate = vap->iv_state; + RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s -> %s\n", + ieee80211_state_name[ostate], ieee80211_state_name[nstate]); + + if (vap->iv_bss->ni_chan == IEEE80211_CHAN_ANYC && + ostate == IEEE80211_S_INIT && nstate == IEEE80211_S_RUN) { + /* need to call iv_newstate() firstly */ + error = uvp->newstate(vap, nstate, arg); + if (error != 0) + return (error); + + early_newstate = 1; + } else + early_newstate = 0; IEEE80211_UNLOCK(ic); RTWN_LOCK(sc); - - if (vap->iv_state == IEEE80211_S_RUN) { - /* Stop calibration. */ - callout_stop(&sc->calib_to); - - /* Turn link LED off. */ - rtwn_set_led(sc, RTWN_LED_LINK, 0); + if (ostate == IEEE80211_S_RUN) { + sc->vaps_running--; /* Set media status to 'No Link'. */ - reg = rtwn_read_4(sc, R92C_CR); - reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_NOLINK); - rtwn_write_4(sc, R92C_CR, reg); + rtwn_set_mode(sc, R92C_MSR_NOLINK, uvp->id); - /* Stop Rx of data frames. */ - rtwn_write_2(sc, R92C_RXFLTMAP2, 0); + if (vap->iv_opmode == IEEE80211_M_IBSS) { + /* Stop periodical TSF synchronization. */ + callout_stop(&uvp->tsf_sync_adhoc); + } - /* Rest TSF. */ - rtwn_write_1(sc, R92C_DUAL_TSF_RST, 0x03); + /* Disable TSF synchronization / beaconing. */ + rtwn_beacon_enable(sc, uvp->id, 0); + rtwn_setbits_1(sc, R92C_BCN_CTRL(uvp->id), + 0, R92C_BCN_CTRL_DIS_TSF_UDT0); - /* Disable TSF synchronization. */ - rtwn_write_1(sc, R92C_BCN_CTRL, - rtwn_read_1(sc, R92C_BCN_CTRL) | - R92C_BCN_CTRL_DIS_TSF_UDT0); + /* NB: monitor mode vaps are using port 0. */ + if (uvp->id != 0 || sc->monvaps_running == 0) { + /* Reset TSF. */ + rtwn_write_1(sc, R92C_DUAL_TSF_RST, + R92C_DUAL_TSF_RESET(uvp->id)); + } - /* Reset EDCA parameters. */ - rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217); - rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317); - rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320); - rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444); +#ifndef RTWN_WITHOUT_UCODE + if ((ic->ic_caps & IEEE80211_C_PMGT) != 0 && uvp->id == 0) { + /* Disable power management. */ + callout_stop(&sc->sc_pwrmode_init); + rtwn_set_pwrmode(sc, vap, 0); + } +#endif + if (sc->vaps_running - sc->monvaps_running > 0) { + /* Recalculate basic rates bitmap. */ + rtwn_calc_basicrates(sc); + } + + if (sc->vaps_running == sc->monvaps_running) { + /* Stop calibration. */ + callout_stop(&sc->sc_calib_to); + + /* Stop Rx of data frames. */ + rtwn_write_2(sc, R92C_RXFLTMAP2, 0); + + /* Reset EDCA parameters. */ + rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217); + rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317); + rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320); + rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444); + + if (sc->vaps_running == 0) { + /* Turn link LED off. */ + rtwn_set_led(sc, RTWN_LED_LINK, 0); + } + } } - switch (nstate) { - case IEEE80211_S_INIT: - /* Turn link LED off. */ - rtwn_set_led(sc, RTWN_LED_LINK, 0); - break; - case IEEE80211_S_SCAN: - /* Make link LED blink during scan. */ - rtwn_set_led(sc, RTWN_LED_LINK, !sc->ledlink); + error = 0; + switch (nstate) { + case IEEE80211_S_SCAN: /* Pause AC Tx queues. */ - rtwn_write_1(sc, R92C_TXPAUSE, - rtwn_read_1(sc, R92C_TXPAUSE) | 0x0f); - break; - case IEEE80211_S_AUTH: - rtwn_set_chan(sc, ic->ic_curchan, NULL); + if (sc->vaps_running == 0) + rtwn_setbits_1(sc, R92C_TXPAUSE, 0, R92C_TX_QUEUE_AC); break; case IEEE80211_S_RUN: - if (ic->ic_opmode == IEEE80211_M_MONITOR) { - /* Enable Rx of data frames. */ - rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff); - - /* Turn link LED on. */ - rtwn_set_led(sc, RTWN_LED_LINK, 1); + error = rtwn_run(sc, vap); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not move to RUN state\n", __func__); break; } - /* Set media status to 'Associated'. */ - reg = rtwn_read_4(sc, R92C_CR); - reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA); - rtwn_write_4(sc, R92C_CR, reg); + sc->vaps_running++; + break; + default: + break; + } - /* Set BSSID. */ - rtwn_write_4(sc, R92C_BSSID + 0, le32dec(&ni->ni_bssid[0])); - rtwn_write_4(sc, R92C_BSSID + 4, le16dec(&ni->ni_bssid[4])); + RTWN_UNLOCK(sc); + IEEE80211_LOCK(ic); + if (error != 0) + return (error); - if (ic->ic_curmode == IEEE80211_MODE_11B) - rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0); - else /* 802.11b/g */ - rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3); + return (early_newstate ? 0 : uvp->newstate(vap, nstate, arg)); +} +static void +rtwn_calc_basicrates(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint32_t basicrates; + int i; + + RTWN_ASSERT_LOCKED(sc); + + if (ic->ic_flags & IEEE80211_F_SCAN) + return; /* will be done by rtwn_scan_end(). */ + + basicrates = 0; + for (i = 0; i < nitems(sc->vaps); i++) { + struct rtwn_vap *rvp; + struct ieee80211vap *vap; + struct ieee80211_node *ni; + uint32_t rates; + + rvp = sc->vaps[i]; + if (rvp == NULL || rvp->curr_mode == R92C_MSR_NOLINK) + continue; + + vap = &rvp->vap; + if (vap->iv_bss == NULL) + continue; + + ni = ieee80211_ref_node(vap->iv_bss); + rtwn_get_rates(sc, &ni->ni_rates, NULL, &rates, NULL, 1); + basicrates |= rates; + ieee80211_free_node(ni); + } + + if (basicrates == 0) + return; + + /* XXX initial RTS rate? */ + rtwn_set_basicrates(sc, basicrates); +} + +static int +rtwn_run(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + struct ieee80211com *ic = vap->iv_ic; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211_node *ni; + uint32_t reg; + uint8_t mode; + int error; + + RTWN_ASSERT_LOCKED(sc); + + error = 0; + ni = ieee80211_ref_node(vap->iv_bss); + + if (ic->ic_bsschan == IEEE80211_CHAN_ANYC || + ni->ni_chan == IEEE80211_CHAN_ANYC) { + error = EINVAL; + goto fail; + } + + switch (vap->iv_opmode) { + case IEEE80211_M_STA: + mode = R92C_MSR_INFRA; + break; + case IEEE80211_M_IBSS: + mode = R92C_MSR_ADHOC; + break; + case IEEE80211_M_HOSTAP: + mode = R92C_MSR_AP; + break; + default: + KASSERT(0, ("undefined opmode %d\n", vap->iv_opmode)); + error = EINVAL; + goto fail; + } + + /* Set media status to 'Associated'. */ + rtwn_set_mode(sc, mode, uvp->id); + + /* Set AssocID. */ + /* XXX multi-vap? */ + rtwn_write_2(sc, R92C_BCN_PSR_RPT, + 0xc000 | IEEE80211_NODE_AID(ni)); + + /* Set BSSID. */ + rtwn_set_bssid(sc, ni->ni_bssid, uvp->id); + + /* Set beacon interval. */ + rtwn_write_2(sc, R92C_BCN_INTERVAL(uvp->id), ni->ni_intval); + + if (sc->vaps_running == sc->monvaps_running) { /* Enable Rx of data frames. */ rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff); /* Flush all AC queues. */ rtwn_write_1(sc, R92C_TXPAUSE, 0); - - /* Set beacon interval. */ - rtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval); - - /* Allow Rx from our BSSID only. */ - rtwn_write_4(sc, R92C_RCR, - rtwn_read_4(sc, R92C_RCR) | - R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN); - - /* Enable TSF synchronization. */ - rtwn_tsf_sync_enable(sc); - - rtwn_write_1(sc, R92C_SIFS_CCK + 1, 10); - rtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10); - rtwn_write_1(sc, R92C_SPEC_SIFS + 1, 10); - rtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, 10); - rtwn_write_1(sc, R92C_R2T_SIFS + 1, 10); - rtwn_write_1(sc, R92C_T2T_SIFS + 1, 10); - - /* Intialize rate adaptation. */ - rtwn_ra_init(sc); - /* Turn link LED on. */ - rtwn_set_led(sc, RTWN_LED_LINK, 1); - - sc->avg_pwdb = -1; /* Reset average RSSI. */ - /* Reset temperature calibration state machine. */ - sc->thcal_state = 0; - sc->thcal_lctemp = 0; - /* Start periodic calibration. */ - callout_reset(&sc->calib_to, hz * 2, rtwn_calib_to, sc); - break; - default: - break; } - RTWN_UNLOCK(sc); - IEEE80211_LOCK(ic); - return (rvp->newstate(vap, nstate, arg)); -} -static int -rtwn_updateedca(struct ieee80211com *ic) -{ - struct rtwn_softc *sc = ic->ic_softc; - const uint16_t aci2reg[WME_NUM_AC] = { - R92C_EDCA_BE_PARAM, - R92C_EDCA_BK_PARAM, - R92C_EDCA_VI_PARAM, - R92C_EDCA_VO_PARAM - }; - int aci, aifs, slottime; + /* Allow Rx from our BSSID only. */ + if (ic->ic_promisc == 0) { + reg = rtwn_read_4(sc, R92C_RCR); - IEEE80211_LOCK(ic); - slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20; - for (aci = 0; aci < WME_NUM_AC; aci++) { - const struct wmeParams *ac = - &ic->ic_wme.wme_chanParams.cap_wmeParams[aci]; - /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */ - aifs = ac->wmep_aifsn * slottime + 10; - rtwn_write_4(sc, aci2reg[aci], - SM(R92C_EDCA_PARAM_TXOP, ac->wmep_txopLimit) | - SM(R92C_EDCA_PARAM_ECWMIN, ac->wmep_logcwmin) | - SM(R92C_EDCA_PARAM_ECWMAX, ac->wmep_logcwmax) | - SM(R92C_EDCA_PARAM_AIFS, aifs)); + if (sc->bcn_vaps == 0) + reg |= R92C_RCR_CBSSID_BCN; + if (sc->ap_vaps == 0) + reg |= R92C_RCR_CBSSID_DATA; + + rtwn_write_4(sc, R92C_RCR, reg); } - IEEE80211_UNLOCK(ic); - return (0); -} -static void -rtwn_update_avgrssi(struct rtwn_softc *sc, int rate, int8_t rssi) -{ - int pwdb; +#ifndef RTWN_WITHOUT_UCODE + /* Upload (QoS) Null Data frame to firmware. */ + /* Note: do this for port 0 only. */ + if ((ic->ic_caps & IEEE80211_C_PMGT) != 0 && + vap->iv_opmode == IEEE80211_M_STA && uvp->id == 0) { + error = rtwn_tx_fwpkt_check(sc, vap); + if (error != 0) + goto fail; - /* Convert antenna signal to percentage. */ - if (rssi <= -100 || rssi >= 20) - pwdb = 0; - else if (rssi >= 0) - pwdb = 100; - else - pwdb = 100 + rssi; - if (RTWN_RATE_IS_CCK(rate)) { - /* CCK gain is smaller than OFDM/MCS gain. */ - pwdb += 6; - if (pwdb > 100) - pwdb = 100; - if (pwdb <= 14) - pwdb -= 4; - else if (pwdb <= 26) - pwdb -= 8; - else if (pwdb <= 34) - pwdb -= 6; - else if (pwdb <= 42) - pwdb -= 2; - } - if (sc->avg_pwdb == -1) /* Init. */ - sc->avg_pwdb = pwdb; - else if (sc->avg_pwdb < pwdb) - sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1; - else - sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20); - DPRINTFN(4, ("PWDB=%d EMA=%d\n", pwdb, sc->avg_pwdb)); -} - -static int8_t -rtwn_get_rssi(struct rtwn_softc *sc, int rate, void *physt) -{ - static const int8_t cckoff[] = { 16, -12, -26, -46 }; - struct r92c_rx_phystat *phy; - struct r92c_rx_cck *cck; - uint8_t rpt; - int8_t rssi; - - if (RTWN_RATE_IS_CCK(rate)) { - cck = (struct r92c_rx_cck *)physt; - if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR) { - rpt = (cck->agc_rpt >> 5) & 0x3; - rssi = (cck->agc_rpt & 0x1f) << 1; - } else { - rpt = (cck->agc_rpt >> 6) & 0x3; - rssi = cck->agc_rpt & 0x3e; - } - rssi = cckoff[rpt] - rssi; - } else { /* OFDM/HT. */ - phy = (struct r92c_rx_phystat *)physt; - rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110; - } - return (rssi); -} - -static void -rtwn_rx_frame(struct rtwn_softc *sc, struct r92c_rx_desc *rx_desc, - struct rtwn_rx_data *rx_data, int desc_idx) -{ - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211_frame_min *wh; - struct ieee80211_node *ni; - struct r92c_rx_phystat *phy = NULL; - uint32_t rxdw0, rxdw3; - struct mbuf *m, *m1; - bus_dma_segment_t segs[1]; - bus_addr_t physaddr; - uint8_t rate; - int8_t rssi = 0, nf; - int infosz, nsegs, pktlen, shift, error; - - rxdw0 = le32toh(rx_desc->rxdw0); - rxdw3 = le32toh(rx_desc->rxdw3); - - if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) { + /* Setup power management. */ /* - * This should not happen since we setup our Rx filter - * to not receive these frames. + * NB: it will be enabled immediately - delay it, + * so 4-Way handshake will not be interrupted. */ - counter_u64_add(ic->ic_ierrors, 1); - return; + callout_reset(&sc->sc_pwrmode_init, 5*hz, + rtwn_pwrmode_init, sc); } +#endif - pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); - if (__predict_false(pktlen < sizeof(struct ieee80211_frame_ack) || - pktlen > MCLBYTES)) { - counter_u64_add(ic->ic_ierrors, 1); - return; - } - - rate = MS(rxdw3, R92C_RXDW3_RATE); - infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; - if (infosz > sizeof(struct r92c_rx_phystat)) - infosz = sizeof(struct r92c_rx_phystat); - shift = MS(rxdw0, R92C_RXDW0_SHIFT); - - /* Get RSSI from PHY status descriptor if present. */ - if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { - phy = mtod(rx_data->m, struct r92c_rx_phystat *); - rssi = rtwn_get_rssi(sc, rate, phy); - /* Update our average RSSI. */ - rtwn_update_avgrssi(sc, rate, rssi); - } - - DPRINTFN(5, ("Rx frame len=%d rate=%d infosz=%d shift=%d rssi=%d\n", - pktlen, rate, infosz, shift, rssi)); - - m1 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); - if (m1 == NULL) { - counter_u64_add(ic->ic_ierrors, 1); - return; - } - bus_dmamap_unload(sc->rx_ring.data_dmat, rx_data->map); - - error = bus_dmamap_load(sc->rx_ring.data_dmat, rx_data->map, - mtod(m1, void *), MCLBYTES, rtwn_dma_map_addr, - &physaddr, 0); - if (error != 0) { - m_freem(m1); - - if (bus_dmamap_load_mbuf_sg(sc->rx_ring.data_dmat, - rx_data->map, rx_data->m, segs, &nsegs, 0)) - panic("%s: could not load old RX mbuf", - device_get_name(sc->sc_dev)); - - /* Physical address may have changed. */ - rtwn_setup_rx_desc(sc, rx_desc, physaddr, MCLBYTES, desc_idx); - counter_u64_add(ic->ic_ierrors, 1); - return; - } - - /* Finalize mbuf. */ - m = rx_data->m; - rx_data->m = m1; - m->m_pkthdr.len = m->m_len = pktlen + infosz + shift; - - /* Update RX descriptor. */ - rtwn_setup_rx_desc(sc, rx_desc, physaddr, MCLBYTES, desc_idx); - - /* Get ieee80211 frame header. */ - if (rxdw0 & R92C_RXDW0_PHYST) - m_adj(m, infosz + shift); - else - m_adj(m, shift); - - nf = -95; - if (ieee80211_radiotap_active(ic)) { - struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap; - - tap->wr_flags = 0; - if (!(rxdw3 & R92C_RXDW3_HT)) { - tap->wr_rate = ridx2rate[rate]; - } else if (rate >= 12) { /* MCS0~15. */ - /* Bit 7 set means HT MCS instead of rate. */ - tap->wr_rate = 0x80 | (rate - 12); - } - tap->wr_dbm_antsignal = rssi; - tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq); - tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags); - } - - RTWN_UNLOCK(sc); - wh = mtod(m, struct ieee80211_frame_min *); - if (m->m_len >= sizeof(*wh)) - ni = ieee80211_find_rxnode(ic, wh); - else - ni = NULL; - - /* Send the frame to the 802.11 layer. */ - if (ni != NULL) { - (void)ieee80211_input(ni, m, rssi - nf, nf); - /* Node is no longer needed. */ - ieee80211_free_node(ni); - } else - (void)ieee80211_input_all(ic, m, rssi - nf, nf); - - RTWN_LOCK(sc); -} - -static int -rtwn_tx(struct rtwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) -{ - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211_frame *wh; - struct ieee80211_key *k = NULL; - struct rtwn_tx_ring *tx_ring; - struct rtwn_tx_data *data; - struct r92c_tx_desc *txd; - bus_dma_segment_t segs[1]; - uint16_t qos; - uint8_t raid, type, tid, qid; - int nsegs, error; - - wh = mtod(m, struct ieee80211_frame *); - type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; - - /* Encrypt the frame if need be. */ - if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { - k = ieee80211_crypto_encap(ni, m); - if (k == NULL) { - m_freem(m); - return (ENOBUFS); - } - /* 802.11 header may have moved. */ - wh = mtod(m, struct ieee80211_frame *); - } - - if (IEEE80211_QOS_HAS_SEQ(wh)) { - qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; - tid = qos & IEEE80211_QOS_TID; - } else { - qos = 0; - tid = 0; - } - - switch (type) { - case IEEE80211_FC0_TYPE_CTL: - case IEEE80211_FC0_TYPE_MGT: - qid = RTWN_VO_QUEUE; - break; - default: - qid = M_WME_GETAC(m); - break; - } - - /* Grab a Tx buffer from the ring. */ - tx_ring = &sc->tx_ring[qid]; - data = &tx_ring->tx_data[tx_ring->cur]; - if (data->m != NULL) { - m_freem(m); - return (ENOBUFS); - } - - /* Fill Tx descriptor. */ - txd = &tx_ring->desc[tx_ring->cur]; - if (htole32(txd->txdw0) & R92C_RXDW0_OWN) { - m_freem(m); - return (ENOBUFS); - } - txd->txdw0 = htole32( - SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len) | - SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | - R92C_TXDW0_FSG | R92C_TXDW0_LSG); - if (IEEE80211_IS_MULTICAST(wh->i_addr1)) - txd->txdw0 |= htole32(R92C_TXDW0_BMCAST); - - txd->txdw1 = 0; - txd->txdw4 = 0; - txd->txdw5 = 0; - - /* XXX TODO: rate control; implement low-rate for EAPOL */ - if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && - type == IEEE80211_FC0_TYPE_DATA) { - if (ic->ic_curmode == IEEE80211_MODE_11B) - raid = R92C_RAID_11B; - else - raid = R92C_RAID_11BG; - txd->txdw1 |= htole32( - SM(R92C_TXDW1_MACID, RTWN_MACID_BSS) | - SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BE) | - SM(R92C_TXDW1_RAID, raid) | - R92C_TXDW1_AGGBK); - - if (ic->ic_flags & IEEE80211_F_USEPROT) { - if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) { - txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF | - R92C_TXDW4_HWRTSEN); - } else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) { - txd->txdw4 |= htole32(R92C_TXDW4_RTSEN | - R92C_TXDW4_HWRTSEN); - } - } - - /* XXX TODO: implement rate control */ - - /* Send RTS at OFDM24. */ - txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, - RTWN_RIDX_OFDM24)); - txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FBLIMIT, 0xf)); - /* Send data at OFDM54. */ - txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, - RTWN_RIDX_OFDM54)); - txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FBLIMIT, 0x1f)); - - } else { - txd->txdw1 |= htole32( - SM(R92C_TXDW1_MACID, 0) | - SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT) | - SM(R92C_TXDW1_RAID, R92C_RAID_11B)); - - /* Force CCK1. */ - txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); - txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, RTWN_RIDX_CCK1)); - } - /* Set sequence number (already little endian). */ - txd->txdseq = htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE); - - if (!qos) { - /* Use HW sequence numbering for non-QoS frames. */ - txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ); - txd->txdseq |= htole16(0x8000); - } else - txd->txdw4 |= htole32(R92C_TXDW4_QOS); - - error = bus_dmamap_load_mbuf_sg(tx_ring->data_dmat, data->map, m, segs, - &nsegs, BUS_DMA_NOWAIT); - if (error != 0 && error != EFBIG) { - device_printf(sc->sc_dev, "can't map mbuf (error %d)\n", error); - m_freem(m); - return (error); - } - if (error != 0) { - struct mbuf *mnew; - - mnew = m_defrag(m, M_NOWAIT); - if (mnew == NULL) { - device_printf(sc->sc_dev, - "can't defragment mbuf\n"); - m_freem(m); - return (ENOBUFS); - } - m = mnew; - - error = bus_dmamap_load_mbuf_sg(tx_ring->data_dmat, data->map, - m, segs, &nsegs, BUS_DMA_NOWAIT); + if (vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_IBSS) { + error = rtwn_setup_beacon(sc, ni); if (error != 0) { device_printf(sc->sc_dev, - "can't map mbuf (error %d)\n", error); - m_freem(m); - return (error); + "unable to push beacon into the chip, " + "error %d\n", error); + goto fail; } } - txd->txbufaddr = htole32(segs[0].ds_addr); - txd->txbufsize = htole16(m->m_pkthdr.len); - bus_space_barrier(sc->sc_st, sc->sc_sh, 0, sc->sc_mapsize, - BUS_SPACE_BARRIER_WRITE); - txd->txdw0 |= htole32(R92C_TXDW0_OWN); + /* Set ACK preamble type. */ + rtwn_set_ack_preamble(sc); - bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_sync(tx_ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); + /* Enable TSF synchronization. */ + rtwn_tsf_sync_enable(sc, vap); - data->m = m; - data->ni = ni; + /* Set basic rates mask. */ + rtwn_calc_basicrates(sc); - if (ieee80211_radiotap_active_vap(vap)) { - struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; +#ifdef RTWN_TODO + rtwn_write_1(sc, R92C_SIFS_CCK + 1, 10); + rtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10); + rtwn_write_1(sc, R92C_SPEC_SIFS + 1, 10); + rtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, 10); + rtwn_write_1(sc, R92C_R2T_SIFS + 1, 10); + rtwn_write_1(sc, R92C_T2T_SIFS + 1, 10); +#endif - tap->wt_flags = 0; - tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); - tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); + if (sc->vaps_running == sc->monvaps_running) { + /* Reset temperature calibration state machine. */ + sc->sc_flags &= ~RTWN_TEMP_MEASURED; + sc->thcal_temp = sc->thermal_meter; - ieee80211_radiotap_tx(vap, m); - } + /* Start periodic calibration. */ + callout_reset(&sc->sc_calib_to, 2*hz, rtwn_calib_to, + sc); - tx_ring->cur = (tx_ring->cur + 1) % RTWN_TX_LIST_COUNT; - tx_ring->queued++; - - if (tx_ring->queued >= (RTWN_TX_LIST_COUNT - 1)) - sc->qfullmsk |= (1 << qid); - - /* Kick TX. */ - rtwn_write_2(sc, R92C_PCIE_CTRL_REG, (1 << qid)); - return (0); -} - -static void -rtwn_tx_done(struct rtwn_softc *sc, int qid) -{ - struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid]; - struct rtwn_tx_data *tx_data; - struct r92c_tx_desc *tx_desc; - int i; - - bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, - BUS_DMASYNC_POSTREAD); - - for (i = 0; i < RTWN_TX_LIST_COUNT; i++) { - tx_data = &tx_ring->tx_data[i]; - if (tx_data->m == NULL) - continue; - - tx_desc = &tx_ring->desc[i]; - if (le32toh(tx_desc->txdw0) & R92C_TXDW0_OWN) - continue; - - /* Unmap and free mbuf. */ - bus_dmamap_sync(tx_ring->data_dmat, tx_data->map, - BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(tx_ring->data_dmat, tx_data->map); - - /* - * XXX TODO: figure out whether the transmit succeeded or not. - * .. and then notify rate control. - */ - ieee80211_tx_complete(tx_data->ni, tx_data->m, 0); - tx_data->ni = NULL; - tx_data->m = NULL; - - if (--tx_ring->queued) - sc->sc_tx_timer = 5; - else - sc->sc_tx_timer = 0; - } - - if (tx_ring->queued < (RTWN_TX_LIST_COUNT - 1)) - sc->qfullmsk &= ~(1 << qid); - rtwn_start(sc); -} - -static int -rtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, - const struct ieee80211_bpf_params *params) -{ - struct ieee80211com *ic = ni->ni_ic; - struct rtwn_softc *sc = ic->ic_softc; - - RTWN_LOCK(sc); - - /* Prevent management frames from being sent if we're not ready. */ - if (!(sc->sc_flags & RTWN_RUNNING)) { - RTWN_UNLOCK(sc); - m_freem(m); - return (ENETDOWN); - } - - if (rtwn_tx(sc, m, ni) != 0) { - RTWN_UNLOCK(sc); - return (EIO); - } - sc->sc_tx_timer = 5; - RTWN_UNLOCK(sc); - return (0); -} - -static int -rtwn_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct rtwn_softc *sc = ic->ic_softc; - int error; - - RTWN_LOCK(sc); - if ((sc->sc_flags & RTWN_RUNNING) == 0) { - RTWN_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - RTWN_UNLOCK(sc); - return (error); - } - rtwn_start(sc); - RTWN_UNLOCK(sc); - return (0); -} - -static void -rtwn_parent(struct ieee80211com *ic) -{ - struct rtwn_softc *sc = ic->ic_softc; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - if (ic->ic_nrunning > 0) { - if (rtwn_init(sc) == 0) - ieee80211_start_all(ic); - else - ieee80211_stop(vap); - } else - rtwn_stop(sc); -} - -static void -rtwn_start(struct rtwn_softc *sc) -{ - struct ieee80211_node *ni; - struct mbuf *m; - - RTWN_LOCK_ASSERT(sc); - - if ((sc->sc_flags & RTWN_RUNNING) == 0) - return; - - while (sc->qfullmsk == 0 && (m = mbufq_dequeue(&sc->sc_snd)) != NULL) { - ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; - if (rtwn_tx(sc, m, ni) != 0) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); - ieee80211_free_node(ni); - continue; + if (sc->vaps_running == 0) { + /* Turn link LED on. */ + rtwn_set_led(sc, RTWN_LED_LINK, 1); } - sc->sc_tx_timer = 5; } + +fail: + ieee80211_free_node(ni); + + return (error); } +#ifndef D4054 static void rtwn_watchdog(void *arg) { struct rtwn_softc *sc = arg; struct ieee80211com *ic = &sc->sc_ic; - RTWN_LOCK_ASSERT(sc); + RTWN_ASSERT_LOCKED(sc); KASSERT(sc->sc_flags & RTWN_RUNNING, ("not running")); @@ -1897,136 +1343,48 @@ rtwn_watchdog(void *arg) ieee80211_restart_all(ic); return; } - callout_reset(&sc->watchdog_to, hz, rtwn_watchdog, sc); + callout_reset(&sc->sc_watchdog_to, hz, rtwn_watchdog, sc); +} +#endif + +static void +rtwn_parent(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + struct ieee80211vap *vap; + + if (ic->ic_nrunning > 0) { + if (rtwn_init(sc) != 0) { + IEEE80211_LOCK(ic); + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) + ieee80211_stop_locked(vap); + IEEE80211_UNLOCK(ic); + } else + ieee80211_start_all(ic); + } else + rtwn_stop(sc); } + static int -rtwn_power_on(struct rtwn_softc *sc) +rtwn_llt_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data) { - uint32_t reg; - int ntries; + int ntries, error; - /* Wait for autoload done bit. */ - for (ntries = 0; ntries < 1000; ntries++) { - if (rtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN) - break; - DELAY(5); + error = rtwn_write_4(sc, R92C_LLT_INIT, + SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) | + SM(R92C_LLT_INIT_ADDR, addr) | + SM(R92C_LLT_INIT_DATA, data)); + if (error != 0) + return (error); + /* Wait for write operation to complete. */ + for (ntries = 0; ntries < 20; ntries++) { + if (MS(rtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) == + R92C_LLT_INIT_OP_NO_ACTIVE) + return (0); + rtwn_delay(sc, 10); } - if (ntries == 1000) { - device_printf(sc->sc_dev, - "timeout waiting for chip autoload\n"); - return (ETIMEDOUT); - } - - /* Unlock ISO/CLK/Power control register. */ - rtwn_write_1(sc, R92C_RSV_CTRL, 0); - - /* TODO: check if we need this for 8188CE */ - if (sc->board_type != R92C_BOARD_TYPE_DONGLE) { - /* bt coex */ - reg = rtwn_read_4(sc, R92C_APS_FSMCO); - reg |= (R92C_APS_FSMCO_SOP_ABG | - R92C_APS_FSMCO_SOP_AMB | - R92C_APS_FSMCO_XOP_BTCK); - rtwn_write_4(sc, R92C_APS_FSMCO, reg); - } - - /* Move SPS into PWM mode. */ - rtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b); - - /* Set low byte to 0x0f, leave others unchanged. */ - rtwn_write_4(sc, R92C_AFE_XTAL_CTRL, - (rtwn_read_4(sc, R92C_AFE_XTAL_CTRL) & 0xffffff00) | 0x0f); - - /* TODO: check if we need this for 8188CE */ - if (sc->board_type != R92C_BOARD_TYPE_DONGLE) { - /* bt coex */ - reg = rtwn_read_4(sc, R92C_AFE_XTAL_CTRL); - reg &= (~0x00024800); /* XXX magic from linux */ - rtwn_write_4(sc, R92C_AFE_XTAL_CTRL, reg); - } - - rtwn_write_2(sc, R92C_SYS_ISO_CTRL, - (rtwn_read_2(sc, R92C_SYS_ISO_CTRL) & 0xff) | - R92C_SYS_ISO_CTRL_PWC_EV12V | R92C_SYS_ISO_CTRL_DIOR); - DELAY(200); - - /* TODO: linux does additional btcoex stuff here */ - - /* Auto enable WLAN. */ - rtwn_write_2(sc, R92C_APS_FSMCO, - rtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); - for (ntries = 0; ntries < 1000; ntries++) { - if (!(rtwn_read_2(sc, R92C_APS_FSMCO) & - R92C_APS_FSMCO_APFM_ONMAC)) - break; - DELAY(5); - } - if (ntries == 1000) { - device_printf(sc->sc_dev, "timeout waiting for MAC auto ON\n"); - return (ETIMEDOUT); - } - - /* Enable radio, GPIO and LED functions. */ - rtwn_write_2(sc, R92C_APS_FSMCO, - R92C_APS_FSMCO_AFSM_PCIE | - R92C_APS_FSMCO_PDN_EN | - R92C_APS_FSMCO_PFM_ALDN); - /* Release RF digital isolation. */ - rtwn_write_2(sc, R92C_SYS_ISO_CTRL, - rtwn_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR); - - if (sc->chip & RTWN_CHIP_92C) - rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x77); - else - rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x22); - - rtwn_write_4(sc, R92C_INT_MIG, 0); - - if (sc->board_type != R92C_BOARD_TYPE_DONGLE) { - /* bt coex */ - reg = rtwn_read_4(sc, R92C_AFE_XTAL_CTRL + 2); - reg &= 0xfd; /* XXX magic from linux */ - rtwn_write_4(sc, R92C_AFE_XTAL_CTRL + 2, reg); - } - - rtwn_write_1(sc, R92C_GPIO_MUXCFG, - rtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_RFKILL); - - reg = rtwn_read_1(sc, R92C_GPIO_IO_SEL); - if (!(reg & R92C_GPIO_IO_SEL_RFKILL)) { - device_printf(sc->sc_dev, - "radio is disabled by hardware switch\n"); - return (EPERM); - } - - /* Initialize MAC. */ - reg = rtwn_read_1(sc, R92C_APSD_CTRL); - rtwn_write_1(sc, R92C_APSD_CTRL, - rtwn_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF); - for (ntries = 0; ntries < 200; ntries++) { - if (!(rtwn_read_1(sc, R92C_APSD_CTRL) & - R92C_APSD_CTRL_OFF_STATUS)) - break; - DELAY(500); - } - if (ntries == 200) { - device_printf(sc->sc_dev, - "timeout waiting for MAC initialization\n"); - return (ETIMEDOUT); - } - - /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ - reg = rtwn_read_2(sc, R92C_CR); - reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | - R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | - R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN | - R92C_CR_ENSEC; - rtwn_write_2(sc, R92C_CR, reg); - - rtwn_write_1(sc, 0xfe10, 0x19); - - return (0); + return (ETIMEDOUT); } static int @@ -2034,8 +1392,8 @@ rtwn_llt_init(struct rtwn_softc *sc) { int i, error; - /* Reserve pages [0; R92C_TX_PAGE_COUNT]. */ - for (i = 0; i < R92C_TX_PAGE_COUNT; i++) { + /* Reserve pages [0; page_count]. */ + for (i = 0; i < sc->page_count; i++) { if ((error = rtwn_llt_write(sc, i, i + 1)) != 0) return (error); } @@ -2043,674 +1401,110 @@ rtwn_llt_init(struct rtwn_softc *sc) if ((error = rtwn_llt_write(sc, i, 0xff)) != 0) return (error); /* - * Use pages [R92C_TX_PAGE_COUNT + 1; R92C_TXPKTBUF_COUNT - 1] + * Use pages [page_count + 1; pktbuf_count - 1] * as ring buffer. */ - for (++i; i < R92C_TXPKTBUF_COUNT - 1; i++) { + for (++i; i < sc->pktbuf_count - 1; i++) { if ((error = rtwn_llt_write(sc, i, i + 1)) != 0) return (error); } /* Make the last page point to the beginning of the ring buffer. */ - error = rtwn_llt_write(sc, i, R92C_TX_PAGE_COUNT + 1); - return (error); -} - -static void -rtwn_fw_reset(struct rtwn_softc *sc) -{ - uint16_t reg; - int ntries; - - /* Tell 8051 to reset itself. */ - rtwn_write_1(sc, R92C_HMETFR + 3, 0x20); - - /* Wait until 8051 resets by itself. */ - for (ntries = 0; ntries < 100; ntries++) { - reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN); - if (!(reg & R92C_SYS_FUNC_EN_CPUEN)) - goto sleep; - DELAY(50); - } - /* Force 8051 reset. */ - rtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN); -sleep: - /* - * We must sleep for one second to let the firmware settle. - * Accessing registers too early will hang the whole system. - */ - if (msleep(®, &sc->sc_mtx, 0, "rtwnrst", hz)) { - device_printf(sc->sc_dev, "timeout waiting for firmware " - "initialization to complete\n"); - } -} - -static void -rtwn_fw_loadpage(struct rtwn_softc *sc, int page, const uint8_t *buf, int len) -{ - uint32_t reg; - int off, mlen, i; - - reg = rtwn_read_4(sc, R92C_MCUFWDL); - reg = RW(reg, R92C_MCUFWDL_PAGE, page); - rtwn_write_4(sc, R92C_MCUFWDL, reg); - - DELAY(5); - - off = R92C_FW_START_ADDR; - while (len > 0) { - if (len > 196) - mlen = 196; - else if (len > 4) - mlen = 4; - else - mlen = 1; - for (i = 0; i < mlen; i++) - rtwn_write_1(sc, off++, buf[i]); - buf += mlen; - len -= mlen; - } -} - -static int -rtwn_load_firmware(struct rtwn_softc *sc) -{ - const struct firmware *fw; - const struct r92c_fw_hdr *hdr; - const char *name; - const u_char *ptr; - size_t len; - uint32_t reg; - int mlen, ntries, page, error = 0; - - /* Read firmware image from the filesystem. */ - if ((sc->chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) == - RTWN_CHIP_UMC_A_CUT) - name = "rtwn-rtl8192cfwU"; - else - name = "rtwn-rtl8192cfwU_B"; - RTWN_UNLOCK(sc); - fw = firmware_get(name); - RTWN_LOCK(sc); - if (fw == NULL) { - device_printf(sc->sc_dev, - "could not read firmware %s\n", name); - return (ENOENT); - } - len = fw->datasize; - if (len < sizeof(*hdr)) { - device_printf(sc->sc_dev, "firmware too short\n"); - error = EINVAL; - goto fail; - } - ptr = fw->data; - hdr = (const struct r92c_fw_hdr *)ptr; - /* Check if there is a valid FW header and skip it. */ - if ((le16toh(hdr->signature) >> 4) == 0x88c || - (le16toh(hdr->signature) >> 4) == 0x92c) { - DPRINTF(("FW V%d.%d %02d-%02d %02d:%02d\n", - le16toh(hdr->version), le16toh(hdr->subversion), - hdr->month, hdr->date, hdr->hour, hdr->minute)); - ptr += sizeof(*hdr); - len -= sizeof(*hdr); - } - - if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) - rtwn_fw_reset(sc); - - /* Enable FW download. */ - rtwn_write_2(sc, R92C_SYS_FUNC_EN, - rtwn_read_2(sc, R92C_SYS_FUNC_EN) | - R92C_SYS_FUNC_EN_CPUEN); - rtwn_write_1(sc, R92C_MCUFWDL, - rtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_EN); - rtwn_write_1(sc, R92C_MCUFWDL + 2, - rtwn_read_1(sc, R92C_MCUFWDL + 2) & ~0x08); - - /* Reset the FWDL checksum. */ - rtwn_write_1(sc, R92C_MCUFWDL, - rtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_CHKSUM_RPT); - - for (page = 0; len > 0; page++) { - mlen = MIN(len, R92C_FW_PAGE_SIZE); - rtwn_fw_loadpage(sc, page, ptr, mlen); - ptr += mlen; - len -= mlen; - } - - /* Disable FW download. */ - rtwn_write_1(sc, R92C_MCUFWDL, - rtwn_read_1(sc, R92C_MCUFWDL) & ~R92C_MCUFWDL_EN); - rtwn_write_1(sc, R92C_MCUFWDL + 1, 0); - - /* Wait for checksum report. */ - for (ntries = 0; ntries < 1000; ntries++) { - if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT) - break; - DELAY(5); - } - if (ntries == 1000) { - device_printf(sc->sc_dev, - "timeout waiting for checksum report\n"); - error = ETIMEDOUT; - goto fail; - } - - reg = rtwn_read_4(sc, R92C_MCUFWDL); - reg = (reg & ~R92C_MCUFWDL_WINTINI_RDY) | R92C_MCUFWDL_RDY; - rtwn_write_4(sc, R92C_MCUFWDL, reg); - /* Wait for firmware readiness. */ - for (ntries = 0; ntries < 2000; ntries++) { - if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY) - break; - DELAY(50); - } - if (ntries == 2000) { - device_printf(sc->sc_dev, - "timeout waiting for firmware readiness\n"); - error = ETIMEDOUT; - goto fail; - } -fail: - firmware_put(fw, FIRMWARE_UNLOAD); + error = rtwn_llt_write(sc, i, sc->page_count + 1); return (error); } static int rtwn_dma_init(struct rtwn_softc *sc) { - uint32_t reg; +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while(0) + uint16_t reg; + uint8_t tx_boundary; int error; /* Initialize LLT table. */ error = rtwn_llt_init(sc); if (error != 0) - return error; + return (error); - /* Set number of pages for normal priority queue. */ - rtwn_write_2(sc, R92C_RQPN_NPQ, 0); - rtwn_write_4(sc, R92C_RQPN, + /* Set the number of pages for each queue. */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "%s: pages per queue: high %d, normal %d, low %d, public %d\n", + __func__, sc->nhqpages, sc->nnqpages, sc->nlqpages, + sc->npubqpages); + + RTWN_CHK(rtwn_write_1(sc, R92C_RQPN_NPQ, sc->nnqpages)); + RTWN_CHK(rtwn_write_4(sc, R92C_RQPN, /* Set number of pages for public queue. */ - SM(R92C_RQPN_PUBQ, R92C_PUBQ_NPAGES) | + SM(R92C_RQPN_PUBQ, sc->npubqpages) | /* Set number of pages for high priority queue. */ - SM(R92C_RQPN_HPQ, R92C_HPQ_NPAGES) | + SM(R92C_RQPN_HPQ, sc->nhqpages) | /* Set number of pages for low priority queue. */ - SM(R92C_RQPN_LPQ, R92C_LPQ_NPAGES) | + SM(R92C_RQPN_LPQ, sc->nlqpages) | /* Load values. */ - R92C_RQPN_LD); + R92C_RQPN_LD)); - rtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, R92C_TX_PAGE_BOUNDARY); - rtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, R92C_TX_PAGE_BOUNDARY); - rtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, R92C_TX_PAGE_BOUNDARY); - rtwn_write_1(sc, R92C_TRXFF_BNDY, R92C_TX_PAGE_BOUNDARY); - rtwn_write_1(sc, R92C_TDECTRL + 1, R92C_TX_PAGE_BOUNDARY); + /* Initialize TX buffer boundary. */ + KASSERT(sc->page_count < 255 && sc->page_count > 0, + ("page_count is %d\n", sc->page_count)); + tx_boundary = sc->page_count + 1; + RTWN_CHK(rtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, tx_boundary)); + RTWN_CHK(rtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, tx_boundary)); + RTWN_CHK(rtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, tx_boundary)); + RTWN_CHK(rtwn_write_1(sc, R92C_TRXFF_BNDY, tx_boundary)); + RTWN_CHK(rtwn_write_1(sc, R92C_TDECTRL + 1, tx_boundary)); - reg = rtwn_read_2(sc, R92C_TRXDMA_CTRL); - reg &= ~R92C_TRXDMA_CTRL_QMAP_M; - reg |= 0xF771; - rtwn_write_2(sc, R92C_TRXDMA_CTRL, reg); + error = rtwn_init_bcnq1_boundary(sc); + if (error != 0) + return (error); - rtwn_write_4(sc, R92C_TCR, R92C_TCR_CFENDFORM | (1 << 12) | (1 << 13)); + /* Set queue to USB pipe mapping. */ + /* Note: PCIe devices are using some magic number here. */ + reg = rtwn_get_qmap(sc); + RTWN_CHK(rtwn_setbits_2(sc, R92C_TRXDMA_CTRL, + R92C_TRXDMA_CTRL_QMAP_M, reg)); - /* Configure Tx DMA. */ - rtwn_write_4(sc, R92C_BKQ_DESA, sc->tx_ring[RTWN_BK_QUEUE].paddr); - rtwn_write_4(sc, R92C_BEQ_DESA, sc->tx_ring[RTWN_BE_QUEUE].paddr); - rtwn_write_4(sc, R92C_VIQ_DESA, sc->tx_ring[RTWN_VI_QUEUE].paddr); - rtwn_write_4(sc, R92C_VOQ_DESA, sc->tx_ring[RTWN_VO_QUEUE].paddr); - rtwn_write_4(sc, R92C_BCNQ_DESA, sc->tx_ring[RTWN_BEACON_QUEUE].paddr); - rtwn_write_4(sc, R92C_MGQ_DESA, sc->tx_ring[RTWN_MGNT_QUEUE].paddr); - rtwn_write_4(sc, R92C_HQ_DESA, sc->tx_ring[RTWN_HIGH_QUEUE].paddr); - - /* Configure Rx DMA. */ - rtwn_write_4(sc, R92C_RX_DESA, sc->rx_ring.paddr); + /* Configure Tx/Rx DMA (PCIe). */ + rtwn_set_desc_addr(sc); /* Set Tx/Rx transfer page boundary. */ - rtwn_write_2(sc, R92C_TRXFF_BNDY + 2, 0x27ff); + RTWN_CHK(rtwn_write_2(sc, R92C_TRXFF_BNDY + 2, + sc->rx_dma_size - 1)); /* Set Tx/Rx transfer page size. */ - rtwn_write_1(sc, R92C_PBP, - SM(R92C_PBP_PSRX, R92C_PBP_128) | - SM(R92C_PBP_PSTX, R92C_PBP_128)); + rtwn_set_page_size(sc); + + return (0); +} + +static int +rtwn_mac_init(struct rtwn_softc *sc) +{ + int i, error; + + /* Write MAC initialization values. */ + for (i = 0; i < sc->mac_size; i++) { + error = rtwn_write_1(sc, sc->mac_prog[i].reg, + sc->mac_prog[i].val); + if (error != 0) + return (error); + } + return (0); } static void -rtwn_mac_init(struct rtwn_softc *sc) +rtwn_mrr_init(struct rtwn_softc *sc) { int i; - /* Write MAC initialization values. */ - for (i = 0; i < nitems(rtl8192ce_mac); i++) - rtwn_write_1(sc, rtl8192ce_mac[i].reg, rtl8192ce_mac[i].val); -} - -static void -rtwn_bb_init(struct rtwn_softc *sc) -{ - const struct rtwn_bb_prog *prog; - uint32_t reg; - int i; - - /* Enable BB and RF. */ - rtwn_write_2(sc, R92C_SYS_FUNC_EN, - rtwn_read_2(sc, R92C_SYS_FUNC_EN) | - R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | - R92C_SYS_FUNC_EN_DIO_RF); - - rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83); - - rtwn_write_1(sc, R92C_RF_CTRL, - R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); - - rtwn_write_1(sc, R92C_SYS_FUNC_EN, - R92C_SYS_FUNC_EN_DIO_PCIE | R92C_SYS_FUNC_EN_PCIEA | - R92C_SYS_FUNC_EN_PPLL | R92C_SYS_FUNC_EN_BB_GLB_RST | - R92C_SYS_FUNC_EN_BBRSTB); - - rtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80); - - rtwn_write_4(sc, R92C_LEDCFG0, - rtwn_read_4(sc, R92C_LEDCFG0) | 0x00800000); - - /* Select BB programming. */ - prog = (sc->chip & RTWN_CHIP_92C) ? - &rtl8192ce_bb_prog_2t : &rtl8192ce_bb_prog_1t; - - /* Write BB initialization values. */ - for (i = 0; i < prog->count; i++) { - rtwn_bb_write(sc, prog->regs[i], prog->vals[i]); - DELAY(1); + /* Drop rate index by 1 per retry. */ + for (i = 0; i < R92C_DARFRC_SIZE; i++) { + rtwn_write_1(sc, R92C_DARFRC + i, i + 1); + rtwn_write_1(sc, R92C_RARFRC + i, i + 1); } - - if (sc->chip & RTWN_CHIP_92C_1T2R) { - /* 8192C 1T only configuration. */ - reg = rtwn_bb_read(sc, R92C_FPGA0_TXINFO); - reg = (reg & ~0x00000003) | 0x2; - rtwn_bb_write(sc, R92C_FPGA0_TXINFO, reg); - - reg = rtwn_bb_read(sc, R92C_FPGA1_TXINFO); - reg = (reg & ~0x00300033) | 0x00200022; - rtwn_bb_write(sc, R92C_FPGA1_TXINFO, reg); - - reg = rtwn_bb_read(sc, R92C_CCK0_AFESETTING); - reg = (reg & ~0xff000000) | 0x45 << 24; - rtwn_bb_write(sc, R92C_CCK0_AFESETTING, reg); - - reg = rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA); - reg = (reg & ~0x000000ff) | 0x23; - rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, reg); - - reg = rtwn_bb_read(sc, R92C_OFDM0_AGCPARAM1); - reg = (reg & ~0x00000030) | 1 << 4; - rtwn_bb_write(sc, R92C_OFDM0_AGCPARAM1, reg); - - reg = rtwn_bb_read(sc, 0xe74); - reg = (reg & ~0x0c000000) | 2 << 26; - rtwn_bb_write(sc, 0xe74, reg); - reg = rtwn_bb_read(sc, 0xe78); - reg = (reg & ~0x0c000000) | 2 << 26; - rtwn_bb_write(sc, 0xe78, reg); - reg = rtwn_bb_read(sc, 0xe7c); - reg = (reg & ~0x0c000000) | 2 << 26; - rtwn_bb_write(sc, 0xe7c, reg); - reg = rtwn_bb_read(sc, 0xe80); - reg = (reg & ~0x0c000000) | 2 << 26; - rtwn_bb_write(sc, 0xe80, reg); - reg = rtwn_bb_read(sc, 0xe88); - reg = (reg & ~0x0c000000) | 2 << 26; - rtwn_bb_write(sc, 0xe88, reg); - } - - /* Write AGC values. */ - for (i = 0; i < prog->agccount; i++) { - rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE, - prog->agcvals[i]); - DELAY(1); - } - - if (rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) & - R92C_HSSI_PARAM2_CCK_HIPWR) - sc->sc_flags |= RTWN_FLAG_CCK_HIPWR; -} - -static void -rtwn_rf_init(struct rtwn_softc *sc) -{ - const struct rtwn_rf_prog *prog; - uint32_t reg, type; - int i, j, idx, off; - - /* Select RF programming based on board type. */ - if (!(sc->chip & RTWN_CHIP_92C)) { - if (sc->board_type == R92C_BOARD_TYPE_MINICARD) - prog = rtl8188ce_rf_prog; - else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) - prog = rtl8188ru_rf_prog; - else - prog = rtl8188cu_rf_prog; - } else - prog = rtl8192ce_rf_prog; - - for (i = 0; i < sc->nrxchains; i++) { - /* Save RF_ENV control type. */ - idx = i / 2; - off = (i % 2) * 16; - reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx)); - type = (reg >> off) & 0x10; - - /* Set RF_ENV enable. */ - reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i)); - reg |= 0x100000; - rtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg); - DELAY(1); - /* Set RF_ENV output high. */ - reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i)); - reg |= 0x10; - rtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg); - DELAY(1); - /* Set address and data lengths of RF registers. */ - reg = rtwn_bb_read(sc, R92C_HSSI_PARAM2(i)); - reg &= ~R92C_HSSI_PARAM2_ADDR_LENGTH; - rtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg); - DELAY(1); - reg = rtwn_bb_read(sc, R92C_HSSI_PARAM2(i)); - reg &= ~R92C_HSSI_PARAM2_DATA_LENGTH; - rtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg); - DELAY(1); - - /* Write RF initialization values for this chain. */ - for (j = 0; j < prog[i].count; j++) { - if (prog[i].regs[j] >= 0xf9 && - prog[i].regs[j] <= 0xfe) { - /* - * These are fake RF registers offsets that - * indicate a delay is required. - */ - DELAY(50); - continue; - } - rtwn_rf_write(sc, i, prog[i].regs[j], - prog[i].vals[j]); - DELAY(1); - } - - /* Restore RF_ENV control type. */ - reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx)); - reg &= ~(0x10 << off) | (type << off); - rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(idx), reg); - - /* Cache RF register CHNLBW. */ - sc->rf_chnlbw[i] = rtwn_rf_read(sc, i, R92C_RF_CHNLBW); - } - - if ((sc->chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) == - RTWN_CHIP_UMC_A_CUT) { - rtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255); - rtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x50a00); - } -} - -static void -rtwn_cam_init(struct rtwn_softc *sc) -{ - /* Invalidate all CAM entries. */ - rtwn_write_4(sc, R92C_CAMCMD, - R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR); -} - -static void -rtwn_pa_bias_init(struct rtwn_softc *sc) -{ - uint8_t reg; - int i; - - for (i = 0; i < sc->nrxchains; i++) { - if (sc->pa_setting & (1 << i)) - continue; - rtwn_rf_write(sc, i, R92C_RF_IPA, 0x0f406); - rtwn_rf_write(sc, i, R92C_RF_IPA, 0x4f406); - rtwn_rf_write(sc, i, R92C_RF_IPA, 0x8f406); - rtwn_rf_write(sc, i, R92C_RF_IPA, 0xcf406); - } - if (!(sc->pa_setting & 0x10)) { - reg = rtwn_read_1(sc, 0x16); - reg = (reg & ~0xf0) | 0x90; - rtwn_write_1(sc, 0x16, reg); - } -} - -static void -rtwn_rxfilter_init(struct rtwn_softc *sc) -{ - /* Initialize Rx filter. */ - /* TODO: use better filter for monitor mode. */ - rtwn_write_4(sc, R92C_RCR, - R92C_RCR_AAP | R92C_RCR_APM | R92C_RCR_AM | R92C_RCR_AB | - R92C_RCR_APP_ICV | R92C_RCR_AMF | R92C_RCR_HTC_LOC_CTRL | - R92C_RCR_APP_MIC | R92C_RCR_APP_PHYSTS); - /* Accept all multicast frames. */ - rtwn_write_4(sc, R92C_MAR + 0, 0xffffffff); - rtwn_write_4(sc, R92C_MAR + 4, 0xffffffff); - /* Accept all management frames. */ - rtwn_write_2(sc, R92C_RXFLTMAP0, 0xffff); - /* Reject all control frames. */ - rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000); - /* Accept all data frames. */ - rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff); -} - -static void -rtwn_edca_init(struct rtwn_softc *sc) -{ - - rtwn_write_2(sc, R92C_SPEC_SIFS, 0x1010); - rtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x1010); - rtwn_write_2(sc, R92C_SIFS_CCK, 0x1010); - rtwn_write_2(sc, R92C_SIFS_OFDM, 0x0e0e); - rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b); - rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f); - rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4322); - rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3222); -} - -static void -rtwn_write_txpower(struct rtwn_softc *sc, int chain, - uint16_t power[RTWN_RIDX_COUNT]) -{ - uint32_t reg; - - /* Write per-CCK rate Tx power. */ - if (chain == 0) { - reg = rtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32); - reg = RW(reg, R92C_TXAGC_A_CCK1, power[0]); - rtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg); - reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); - reg = RW(reg, R92C_TXAGC_A_CCK2, power[1]); - reg = RW(reg, R92C_TXAGC_A_CCK55, power[2]); - reg = RW(reg, R92C_TXAGC_A_CCK11, power[3]); - rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); - } else { - reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32); - reg = RW(reg, R92C_TXAGC_B_CCK1, power[0]); - reg = RW(reg, R92C_TXAGC_B_CCK2, power[1]); - reg = RW(reg, R92C_TXAGC_B_CCK55, power[2]); - rtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg); - reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); - reg = RW(reg, R92C_TXAGC_B_CCK11, power[3]); - rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); - } - /* Write per-OFDM rate Tx power. */ - rtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain), - SM(R92C_TXAGC_RATE06, power[ 4]) | - SM(R92C_TXAGC_RATE09, power[ 5]) | - SM(R92C_TXAGC_RATE12, power[ 6]) | - SM(R92C_TXAGC_RATE18, power[ 7])); - rtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain), - SM(R92C_TXAGC_RATE24, power[ 8]) | - SM(R92C_TXAGC_RATE36, power[ 9]) | - SM(R92C_TXAGC_RATE48, power[10]) | - SM(R92C_TXAGC_RATE54, power[11])); - /* Write per-MCS Tx power. */ - rtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain), - SM(R92C_TXAGC_MCS00, power[12]) | - SM(R92C_TXAGC_MCS01, power[13]) | - SM(R92C_TXAGC_MCS02, power[14]) | - SM(R92C_TXAGC_MCS03, power[15])); - rtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain), - SM(R92C_TXAGC_MCS04, power[16]) | - SM(R92C_TXAGC_MCS05, power[17]) | - SM(R92C_TXAGC_MCS06, power[18]) | - SM(R92C_TXAGC_MCS07, power[19])); - rtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain), - SM(R92C_TXAGC_MCS08, power[20]) | - SM(R92C_TXAGC_MCS09, power[21]) | - SM(R92C_TXAGC_MCS10, power[22]) | - SM(R92C_TXAGC_MCS11, power[23])); - rtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain), - SM(R92C_TXAGC_MCS12, power[24]) | - SM(R92C_TXAGC_MCS13, power[25]) | - SM(R92C_TXAGC_MCS14, power[26]) | - SM(R92C_TXAGC_MCS15, power[27])); -} - -static void -rtwn_get_txpower(struct rtwn_softc *sc, int chain, - struct ieee80211_channel *c, struct ieee80211_channel *extc, - uint16_t power[RTWN_RIDX_COUNT]) -{ - struct ieee80211com *ic = &sc->sc_ic; - struct r92c_rom *rom = &sc->rom; - uint16_t cckpow, ofdmpow, htpow, diff, max; - const struct rtwn_txpwr *base; - int ridx, chan, group; - - /* Determine channel group. */ - chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ - if (chan <= 3) - group = 0; - else if (chan <= 9) - group = 1; - else - group = 2; - - /* Get original Tx power based on board type and RF chain. */ - if (!(sc->chip & RTWN_CHIP_92C)) { - if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) - base = &rtl8188ru_txagc[chain]; - else - base = &rtl8192cu_txagc[chain]; - } else - base = &rtl8192cu_txagc[chain]; - - memset(power, 0, RTWN_RIDX_COUNT * sizeof(power[0])); - if (sc->regulatory == 0) { - for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) - power[ridx] = base->pwr[0][ridx]; - } - for (ridx = RTWN_RIDX_OFDM6; ridx < RTWN_RIDX_COUNT; ridx++) { - if (sc->regulatory == 3) { - power[ridx] = base->pwr[0][ridx]; - /* Apply vendor limits. */ - if (extc != NULL) - max = rom->ht40_max_pwr[group]; - else - max = rom->ht20_max_pwr[group]; - max = (max >> (chain * 4)) & 0xf; - if (power[ridx] > max) - power[ridx] = max; - } else if (sc->regulatory == 1) { - if (extc == NULL) - power[ridx] = base->pwr[group][ridx]; - } else if (sc->regulatory != 2) - power[ridx] = base->pwr[0][ridx]; - } - - /* Compute per-CCK rate Tx power. */ - cckpow = rom->cck_tx_pwr[chain][group]; - for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) { - power[ridx] += cckpow; - if (power[ridx] > R92C_MAX_TX_PWR) - power[ridx] = R92C_MAX_TX_PWR; - } - - htpow = rom->ht40_1s_tx_pwr[chain][group]; - if (sc->ntxchains > 1) { - /* Apply reduction for 2 spatial streams. */ - diff = rom->ht40_2s_tx_pwr_diff[group]; - diff = (diff >> (chain * 4)) & 0xf; - htpow = (htpow > diff) ? htpow - diff : 0; - } - - /* Compute per-OFDM rate Tx power. */ - diff = rom->ofdm_tx_pwr_diff[group]; - diff = (diff >> (chain * 4)) & 0xf; - ofdmpow = htpow + diff; /* HT->OFDM correction. */ - for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) { - power[ridx] += ofdmpow; - if (power[ridx] > R92C_MAX_TX_PWR) - power[ridx] = R92C_MAX_TX_PWR; - } - - /* Compute per-MCS Tx power. */ - if (extc == NULL) { - diff = rom->ht20_tx_pwr_diff[group]; - diff = (diff >> (chain * 4)) & 0xf; - htpow += diff; /* HT40->HT20 correction. */ - } - for (ridx = RTWN_RIDX_MCS0; ridx <= RTWN_RIDX_MCS15; ridx++) { - power[ridx] += htpow; - if (power[ridx] > R92C_MAX_TX_PWR) - power[ridx] = R92C_MAX_TX_PWR; - } -#ifdef RTWN_DEBUG - if (sc->sc_debug >= 4) { - /* Dump per-rate Tx power values. */ - printf("Tx power for chain %d:\n", chain); - for (ridx = RTWN_RIDX_CCK1; ridx < RTWN_RIDX_COUNT; ridx++) - printf("Rate %d = %u\n", ridx, power[ridx]); - } -#endif -} - -static void -rtwn_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c, - struct ieee80211_channel *extc) -{ - uint16_t power[RTWN_RIDX_COUNT]; - int i; - - for (i = 0; i < sc->ntxchains; i++) { - /* Compute per-rate Tx power values. */ - rtwn_get_txpower(sc, i, c, extc, power); - /* Write per-rate Tx power values to hardware. */ - rtwn_write_txpower(sc, i, power); - } -} - -static void -rtwn_set_rx_bssid_all(struct rtwn_softc *sc, int enable) -{ - uint32_t reg; - - reg = rtwn_read_4(sc, R92C_RCR); - if (enable) - reg &= ~R92C_RCR_CBSSID_BCN; - else - reg |= R92C_RCR_CBSSID_BCN; - rtwn_write_4(sc, R92C_RCR, reg); -} - -static void -rtwn_set_gain(struct rtwn_softc *sc, uint8_t gain) -{ - uint32_t reg; - - reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0)); - reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, gain); - rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg); - - reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1)); - reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, gain); - rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg); } static void @@ -2720,12 +1514,24 @@ rtwn_scan_start(struct ieee80211com *ic) RTWN_LOCK(sc); /* Receive beacons / probe responses from any BSSID. */ - rtwn_set_rx_bssid_all(sc, 1); - /* Set gain for scanning. */ - rtwn_set_gain(sc, 0x20); + if (sc->bcn_vaps == 0) + rtwn_set_rx_bssid_all(sc, 1); RTWN_UNLOCK(sc); } +static void +rtwn_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell) +{ + struct rtwn_softc *sc = ss->ss_ic->ic_softc; + + /* Make link LED blink during scan. */ + RTWN_LOCK(sc); + rtwn_set_led(sc, RTWN_LED_LINK, !sc->ledlink); + RTWN_UNLOCK(sc); + + sc->sc_scan_curchan(ss, maxdwell); +} + static void rtwn_scan_end(struct ieee80211com *ic) { @@ -2733,9 +1539,14 @@ rtwn_scan_end(struct ieee80211com *ic) RTWN_LOCK(sc); /* Restore limitations. */ - rtwn_set_rx_bssid_all(sc, 0); - /* Set gain under link. */ - rtwn_set_gain(sc, 0x32); + if (ic->ic_promisc == 0 && sc->bcn_vaps == 0) + rtwn_set_rx_bssid_all(sc, 0); + + /* Restore LED state. */ + rtwn_set_led(sc, RTWN_LED_LINK, (sc->vaps_running != 0)); + + /* Restore basic rates mask. */ + rtwn_calc_basicrates(sc); RTWN_UNLOCK(sc); } @@ -2743,787 +1554,442 @@ static void rtwn_getradiocaps(struct ieee80211com *ic, int maxchans, int *nchans, struct ieee80211_channel chans[]) { + struct rtwn_softc *sc = ic->ic_softc; uint8_t bands[IEEE80211_MODE_BYTES]; + int i; memset(bands, 0, sizeof(bands)); setbit(bands, IEEE80211_MODE_11B); setbit(bands, IEEE80211_MODE_11G); + setbit(bands, IEEE80211_MODE_11NG); ieee80211_add_channel_list_2ghz(chans, maxchans, nchans, - rtwn_chan_2ghz, nitems(rtwn_chan_2ghz), bands, 0); + rtwn_chan_2ghz, nitems(rtwn_chan_2ghz), bands, + !!(ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40)); + + /* XXX workaround add_channel_list() limitations */ + setbit(bands, IEEE80211_MODE_11A); + setbit(bands, IEEE80211_MODE_11NA); + for (i = 0; i < nitems(sc->chan_num_5ghz); i++) { + if (sc->chan_num_5ghz[i] == 0) + continue; + + ieee80211_add_channel_list_5ghz(chans, maxchans, nchans, + sc->chan_list_5ghz[i], sc->chan_num_5ghz[i], bands, + !!(ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40)); + } +} + +static void +rtwn_update_chw(struct ieee80211com *ic) +{ } static void rtwn_set_channel(struct ieee80211com *ic) { struct rtwn_softc *sc = ic->ic_softc; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); + struct ieee80211_channel *c = ic->ic_curchan; RTWN_LOCK(sc); - if (vap->iv_state == IEEE80211_S_SCAN) { - /* Make link LED blink during scan. */ - rtwn_set_led(sc, RTWN_LED_LINK, !sc->ledlink); + rtwn_set_chan(sc, c); + sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq); + sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags); + sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq); + sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags); + RTWN_UNLOCK(sc); +} + +static int +rtwn_wme_update(struct ieee80211com *ic) +{ + struct ieee80211_channel *c = ic->ic_curchan; + struct rtwn_softc *sc = ic->ic_softc; + struct wmeParams *wmep = sc->cap_wmeParams; + uint8_t aifs, acm, slottime; + int ac; + + /* Prevent possible races. */ + IEEE80211_LOCK(ic); /* XXX */ + RTWN_LOCK(sc); + memcpy(wmep, ic->ic_wme.wme_chanParams.cap_wmeParams, + sizeof(sc->cap_wmeParams)); + RTWN_UNLOCK(sc); + IEEE80211_UNLOCK(ic); + + acm = 0; + slottime = IEEE80211_GET_SLOTTIME(ic); + + RTWN_LOCK(sc); + for (ac = WME_AC_BE; ac < WME_NUM_AC; ac++) { + /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */ + aifs = wmep[ac].wmep_aifsn * slottime + + (IEEE80211_IS_CHAN_5GHZ(c) ? + IEEE80211_DUR_OFDM_SIFS : IEEE80211_DUR_SIFS); + rtwn_write_4(sc, wme2reg[ac], + SM(R92C_EDCA_PARAM_TXOP, wmep[ac].wmep_txopLimit) | + SM(R92C_EDCA_PARAM_ECWMIN, wmep[ac].wmep_logcwmin) | + SM(R92C_EDCA_PARAM_ECWMAX, wmep[ac].wmep_logcwmax) | + SM(R92C_EDCA_PARAM_AIFS, aifs)); + if (ac != WME_AC_BE) + acm |= wmep[ac].wmep_acm << ac; } - rtwn_set_chan(sc, ic->ic_curchan, NULL); + + if (acm != 0) + acm |= R92C_ACMHWCTRL_EN; + rtwn_setbits_1(sc, R92C_ACMHWCTRL, R92C_ACMHWCTRL_ACM_MASK, acm); + RTWN_UNLOCK(sc); + + return 0; +} + +static void +rtwn_update_slot(struct ieee80211com *ic) +{ + rtwn_cmd_sleepable(ic->ic_softc, NULL, 0, rtwn_update_slot_cb); +} + +static void +rtwn_update_slot_cb(struct rtwn_softc *sc, union sec_param *data) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint8_t slottime; + + slottime = IEEE80211_GET_SLOTTIME(ic); + + RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: setting slot time to %uus\n", + __func__, slottime); + + rtwn_write_1(sc, R92C_SLOT, slottime); + rtwn_update_aifs(sc, slottime); +} + +static void +rtwn_update_aifs(struct rtwn_softc *sc, uint8_t slottime) +{ + struct ieee80211_channel *c = sc->sc_ic.ic_curchan; + const struct wmeParams *wmep = sc->cap_wmeParams; + uint8_t aifs, ac; + + for (ac = WME_AC_BE; ac < WME_NUM_AC; ac++) { + /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */ + aifs = wmep[ac].wmep_aifsn * slottime + + (IEEE80211_IS_CHAN_5GHZ(c) ? + IEEE80211_DUR_OFDM_SIFS : IEEE80211_DUR_SIFS); + rtwn_write_1(sc, wme2reg[ac], aifs); + } +} + +static void +rtwn_update_promisc(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + + RTWN_LOCK(sc); + if (sc->sc_flags & RTWN_RUNNING) + rtwn_set_promisc(sc); RTWN_UNLOCK(sc); } static void rtwn_update_mcast(struct ieee80211com *ic) { + struct rtwn_softc *sc = ic->ic_softc; - /* XXX do nothing? */ -} - -static void -rtwn_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c, - struct ieee80211_channel *extc) -{ - struct ieee80211com *ic = &sc->sc_ic; - u_int chan; - int i; - - chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ - if (chan == 0 || chan == IEEE80211_CHAN_ANY) { - device_printf(sc->sc_dev, - "%s: invalid channel %x\n", __func__, chan); - return; - } - - /* Set Tx power for this new channel. */ - rtwn_set_txpower(sc, c, extc); - - for (i = 0; i < sc->nrxchains; i++) { - rtwn_rf_write(sc, i, R92C_RF_CHNLBW, - RW(sc->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan)); - } -#ifndef IEEE80211_NO_HT - if (extc != NULL) { - uint32_t reg; - - /* Is secondary channel below or above primary? */ - int prichlo = c->ic_freq < extc->ic_freq; - - rtwn_write_1(sc, R92C_BWOPMODE, - rtwn_read_1(sc, R92C_BWOPMODE) & ~R92C_BWOPMODE_20MHZ); - - reg = rtwn_read_1(sc, R92C_RRSR + 2); - reg = (reg & ~0x6f) | (prichlo ? 1 : 2) << 5; - rtwn_write_1(sc, R92C_RRSR + 2, reg); - - rtwn_bb_write(sc, R92C_FPGA0_RFMOD, - rtwn_bb_read(sc, R92C_FPGA0_RFMOD) | R92C_RFMOD_40MHZ); - rtwn_bb_write(sc, R92C_FPGA1_RFMOD, - rtwn_bb_read(sc, R92C_FPGA1_RFMOD) | R92C_RFMOD_40MHZ); - - /* Set CCK side band. */ - reg = rtwn_bb_read(sc, R92C_CCK0_SYSTEM); - reg = (reg & ~0x00000010) | (prichlo ? 0 : 1) << 4; - rtwn_bb_write(sc, R92C_CCK0_SYSTEM, reg); - - reg = rtwn_bb_read(sc, R92C_OFDM1_LSTF); - reg = (reg & ~0x00000c00) | (prichlo ? 1 : 2) << 10; - rtwn_bb_write(sc, R92C_OFDM1_LSTF, reg); - - rtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2, - rtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) & - ~R92C_FPGA0_ANAPARAM2_CBW20); - - reg = rtwn_bb_read(sc, 0x818); - reg = (reg & ~0x0c000000) | (prichlo ? 2 : 1) << 26; - rtwn_bb_write(sc, 0x818, reg); - - /* Select 40MHz bandwidth. */ - rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, - (sc->rf_chnlbw[0] & ~0xfff) | chan); - } else -#endif - { - rtwn_write_1(sc, R92C_BWOPMODE, - rtwn_read_1(sc, R92C_BWOPMODE) | R92C_BWOPMODE_20MHZ); - - rtwn_bb_write(sc, R92C_FPGA0_RFMOD, - rtwn_bb_read(sc, R92C_FPGA0_RFMOD) & ~R92C_RFMOD_40MHZ); - rtwn_bb_write(sc, R92C_FPGA1_RFMOD, - rtwn_bb_read(sc, R92C_FPGA1_RFMOD) & ~R92C_RFMOD_40MHZ); - - rtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2, - rtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) | - R92C_FPGA0_ANAPARAM2_CBW20); - - /* Select 20MHz bandwidth. */ - rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, - (sc->rf_chnlbw[0] & ~0xfff) | R92C_RF_CHNLBW_BW20 | chan); - } + RTWN_LOCK(sc); + if (sc->sc_flags & RTWN_RUNNING) + rtwn_set_multi(sc); + RTWN_UNLOCK(sc); } static int -rtwn_iq_calib_chain(struct rtwn_softc *sc, int chain, uint16_t tx[2], - uint16_t rx[2]) +rtwn_set_bssid(struct rtwn_softc *sc, const uint8_t *bssid, int id) { - uint32_t status; - int offset = chain * 0x20; + int error; - if (chain == 0) { /* IQ calibration for chain 0. */ - /* IQ calibration settings for chain 0. */ - rtwn_bb_write(sc, 0xe30, 0x10008c1f); - rtwn_bb_write(sc, 0xe34, 0x10008c1f); - rtwn_bb_write(sc, 0xe38, 0x82140102); + error = rtwn_write_4(sc, R92C_BSSID(id), le32dec(&bssid[0])); + if (error != 0) + return (error); + error = rtwn_write_2(sc, R92C_BSSID(id) + 4, le16dec(&bssid[4])); - if (sc->ntxchains > 1) { - rtwn_bb_write(sc, 0xe3c, 0x28160202); /* 2T */ - /* IQ calibration settings for chain 1. */ - rtwn_bb_write(sc, 0xe50, 0x10008c22); - rtwn_bb_write(sc, 0xe54, 0x10008c22); - rtwn_bb_write(sc, 0xe58, 0x82140102); - rtwn_bb_write(sc, 0xe5c, 0x28160202); - } else - rtwn_bb_write(sc, 0xe3c, 0x28160502); /* 1T */ - - /* LO calibration settings. */ - rtwn_bb_write(sc, 0xe4c, 0x001028d1); - /* We're doing LO and IQ calibration in one shot. */ - rtwn_bb_write(sc, 0xe48, 0xf9000000); - rtwn_bb_write(sc, 0xe48, 0xf8000000); - - } else { /* IQ calibration for chain 1. */ - /* We're doing LO and IQ calibration in one shot. */ - rtwn_bb_write(sc, 0xe60, 0x00000002); - rtwn_bb_write(sc, 0xe60, 0x00000000); - } - - /* Give LO and IQ calibrations the time to complete. */ - DELAY(1000); - - /* Read IQ calibration status. */ - status = rtwn_bb_read(sc, 0xeac); - - if (status & (1 << (28 + chain * 3))) - return (0); /* Tx failed. */ - /* Read Tx IQ calibration results. */ - tx[0] = (rtwn_bb_read(sc, 0xe94 + offset) >> 16) & 0x3ff; - tx[1] = (rtwn_bb_read(sc, 0xe9c + offset) >> 16) & 0x3ff; - if (tx[0] == 0x142 || tx[1] == 0x042) - return (0); /* Tx failed. */ - - if (status & (1 << (27 + chain * 3))) - return (1); /* Rx failed. */ - /* Read Rx IQ calibration results. */ - rx[0] = (rtwn_bb_read(sc, 0xea4 + offset) >> 16) & 0x3ff; - rx[1] = (rtwn_bb_read(sc, 0xeac + offset) >> 16) & 0x3ff; - if (rx[0] == 0x132 || rx[1] == 0x036) - return (1); /* Rx failed. */ - - return (3); /* Both Tx and Rx succeeded. */ + return (error); } -static void -rtwn_iq_calib_run(struct rtwn_softc *sc, int n, uint16_t tx[2][2], - uint16_t rx[2][2]) -{ - /* Registers to save and restore during IQ calibration. */ - struct iq_cal_regs { - uint32_t adda[16]; - uint8_t txpause; - uint8_t bcn_ctrl; - uint8_t ustime_tsf; - uint32_t gpio_muxcfg; - uint32_t ofdm0_trxpathena; - uint32_t ofdm0_trmuxpar; - uint32_t fpga0_rfifacesw1; - } iq_cal_regs; - static const uint16_t reg_adda[16] = { - 0x85c, 0xe6c, 0xe70, 0xe74, - 0xe78, 0xe7c, 0xe80, 0xe84, - 0xe88, 0xe8c, 0xed0, 0xed4, - 0xed8, 0xedc, 0xee0, 0xeec - }; - int i, chain; - uint32_t hssi_param1; - - if (n == 0) { - for (i = 0; i < nitems(reg_adda); i++) - iq_cal_regs.adda[i] = rtwn_bb_read(sc, reg_adda[i]); - - iq_cal_regs.txpause = rtwn_read_1(sc, R92C_TXPAUSE); - iq_cal_regs.bcn_ctrl = rtwn_read_1(sc, R92C_BCN_CTRL); - iq_cal_regs.ustime_tsf = rtwn_read_1(sc, R92C_USTIME_TSF); - iq_cal_regs.gpio_muxcfg = rtwn_read_4(sc, R92C_GPIO_MUXCFG); - } - - if (sc->ntxchains == 1) { - rtwn_bb_write(sc, reg_adda[0], 0x0b1b25a0); - for (i = 1; i < nitems(reg_adda); i++) - rtwn_bb_write(sc, reg_adda[i], 0x0bdb25a0); - } else { - for (i = 0; i < nitems(reg_adda); i++) - rtwn_bb_write(sc, reg_adda[i], 0x04db25a4); - } - - hssi_param1 = rtwn_bb_read(sc, R92C_HSSI_PARAM1(0)); - if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) { - rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), - hssi_param1 | R92C_HSSI_PARAM1_PI); - rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), - hssi_param1 | R92C_HSSI_PARAM1_PI); - } - - if (n == 0) { - iq_cal_regs.ofdm0_trxpathena = - rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA); - iq_cal_regs.ofdm0_trmuxpar = - rtwn_bb_read(sc, R92C_OFDM0_TRMUXPAR); - iq_cal_regs.fpga0_rfifacesw1 = - rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(1)); - } - - rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, 0x03a05600); - rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, 0x000800e4); - rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), 0x22204000); - if (sc->ntxchains > 1) { - rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000); - rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00010000); - } - - rtwn_write_1(sc, R92C_TXPAUSE, 0x3f); - rtwn_write_1(sc, R92C_BCN_CTRL, iq_cal_regs.bcn_ctrl & ~(0x08)); - rtwn_write_1(sc, R92C_USTIME_TSF, iq_cal_regs.ustime_tsf & ~(0x08)); - rtwn_write_1(sc, R92C_GPIO_MUXCFG, - iq_cal_regs.gpio_muxcfg & ~(0x20)); - - rtwn_bb_write(sc, 0x0b68, 0x00080000); - if (sc->ntxchains > 1) - rtwn_bb_write(sc, 0x0b6c, 0x00080000); - - rtwn_bb_write(sc, 0x0e28, 0x80800000); - rtwn_bb_write(sc, 0x0e40, 0x01007c00); - rtwn_bb_write(sc, 0x0e44, 0x01004800); - - rtwn_bb_write(sc, 0x0b68, 0x00080000); - - for (chain = 0; chain < sc->ntxchains; chain++) { - if (chain > 0) { - /* Put chain 0 on standby. */ - rtwn_bb_write(sc, 0x0e28, 0x00); - rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000); - rtwn_bb_write(sc, 0x0e28, 0x80800000); - - /* Enable chain 1. */ - for (i = 0; i < nitems(reg_adda); i++) - rtwn_bb_write(sc, reg_adda[i], 0x0b1b25a4); - } - - /* Run IQ calibration twice. */ - for (i = 0; i < 2; i++) { - int ret; - - ret = rtwn_iq_calib_chain(sc, chain, - tx[chain], rx[chain]); - if (ret == 0) { - DPRINTF(("%s: chain %d: Tx failed.\n", - __func__, chain)); - tx[chain][0] = 0xff; - tx[chain][1] = 0xff; - rx[chain][0] = 0xff; - rx[chain][1] = 0xff; - } else if (ret == 1) { - DPRINTF(("%s: chain %d: Rx failed.\n", - __func__, chain)); - rx[chain][0] = 0xff; - rx[chain][1] = 0xff; - } else if (ret == 3) { - DPRINTF(("%s: chain %d: Both Tx and Rx " - "succeeded.\n", __func__, chain)); - } - } - - DPRINTF(("%s: results for run %d chain %d: tx[0]=0x%x, " - "tx[1]=0x%x rx[0]=0x%x rx[1]=0x%x\n", __func__, n, chain, - tx[chain][0], tx[chain][1], rx[chain][0], rx[chain][1])); - } - - rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, - iq_cal_regs.ofdm0_trxpathena); - rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), - iq_cal_regs.fpga0_rfifacesw1); - rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, iq_cal_regs.ofdm0_trmuxpar); - - rtwn_bb_write(sc, 0x0e28, 0x00); - rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00032ed3); - if (sc->ntxchains > 1) - rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00032ed3); - - if (n != 0) { - if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) { - rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), hssi_param1); - rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), hssi_param1); - } - - for (i = 0; i < nitems(reg_adda); i++) - rtwn_bb_write(sc, reg_adda[i], iq_cal_regs.adda[i]); - - rtwn_write_1(sc, R92C_TXPAUSE, iq_cal_regs.txpause); - rtwn_write_1(sc, R92C_BCN_CTRL, iq_cal_regs.bcn_ctrl); - rtwn_write_1(sc, R92C_USTIME_TSF, iq_cal_regs.ustime_tsf); - rtwn_write_4(sc, R92C_GPIO_MUXCFG, iq_cal_regs.gpio_muxcfg); - } -} - -#define RTWN_IQ_CAL_MAX_TOLERANCE 5 static int -rtwn_iq_calib_compare_results(uint16_t tx1[2][2], uint16_t rx1[2][2], - uint16_t tx2[2][2], uint16_t rx2[2][2], int ntxchains) +rtwn_set_macaddr(struct rtwn_softc *sc, const uint8_t *addr, int id) { - int chain, i, tx_ok[2], rx_ok[2]; + int error; - tx_ok[0] = tx_ok[1] = rx_ok[0] = rx_ok[1] = 0; - for (chain = 0; chain < ntxchains; chain++) { - for (i = 0; i < 2; i++) { - if (tx1[chain][i] == 0xff || tx2[chain][i] == 0xff || - rx1[chain][i] == 0xff || rx2[chain][i] == 0xff) - continue; + error = rtwn_write_4(sc, R92C_MACID(id), le32dec(&addr[0])); + if (error != 0) + return (error); + error = rtwn_write_2(sc, R92C_MACID(id) + 4, le16dec(&addr[4])); - tx_ok[chain] = (abs(tx1[chain][i] - tx2[chain][i]) <= - RTWN_IQ_CAL_MAX_TOLERANCE); - - rx_ok[chain] = (abs(rx1[chain][i] - rx2[chain][i]) <= - RTWN_IQ_CAL_MAX_TOLERANCE); - } - } - - if (ntxchains > 1) - return (tx_ok[0] && tx_ok[1] && rx_ok[0] && rx_ok[1]); - else - return (tx_ok[0] && rx_ok[0]); -} -#undef RTWN_IQ_CAL_MAX_TOLERANCE - -static void -rtwn_iq_calib_write_results(struct rtwn_softc *sc, uint16_t tx[2], - uint16_t rx[2], int chain) -{ - uint32_t reg, val, x; - long y, tx_c; - - if (tx[0] == 0xff || tx[1] == 0xff) - return; - - reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain)); - val = ((reg >> 22) & 0x3ff); - x = tx[0]; - if (x & 0x0200) - x |= 0xfc00; - reg = (((x * val) >> 8) & 0x3ff); - rtwn_bb_write(sc, R92C_OFDM0_TXIQIMBALANCE(chain), reg); - - reg = rtwn_bb_read(sc, R92C_OFDM0_ECCATHRESHOLD); - if (((x * val) >> 7) & 0x01) - reg |= 0x80000000; - else - reg &= ~0x80000000; - rtwn_bb_write(sc, R92C_OFDM0_ECCATHRESHOLD, reg); - - y = tx[1]; - if (y & 0x00000200) - y |= 0xfffffc00; - tx_c = (y * val) >> 8; - reg = rtwn_bb_read(sc, R92C_OFDM0_TXAFE(chain)); - reg |= ((((tx_c & 0x3c0) >> 6) << 24) & 0xf0000000); - rtwn_bb_write(sc, R92C_OFDM0_TXAFE(chain), reg); - - reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain)); - reg |= (((tx_c & 0x3f) << 16) & 0x003F0000); - rtwn_bb_write(sc, R92C_OFDM0_TXIQIMBALANCE(chain), reg); - - reg = rtwn_bb_read(sc, R92C_OFDM0_ECCATHRESHOLD); - if (((y * val) >> 7) & 0x01) - reg |= 0x20000000; - else - reg &= ~0x20000000; - rtwn_bb_write(sc, R92C_OFDM0_ECCATHRESHOLD, reg); - - if (rx[0] == 0xff || rx[1] == 0xff) - return; - - reg = rtwn_bb_read(sc, R92C_OFDM0_RXIQIMBALANCE(chain)); - reg |= (rx[0] & 0x3ff); - rtwn_bb_write(sc, R92C_OFDM0_RXIQIMBALANCE(chain), reg); - reg |= (((rx[1] & 0x03f) << 8) & 0xFC00); - rtwn_bb_write(sc, R92C_OFDM0_RXIQIMBALANCE(chain), reg); - - if (chain == 0) { - reg = rtwn_bb_read(sc, R92C_OFDM0_RXIQEXTANTA); - reg |= (((rx[1] & 0xf) >> 6) & 0x000f); - rtwn_bb_write(sc, R92C_OFDM0_RXIQEXTANTA, reg); - } else { - reg = rtwn_bb_read(sc, R92C_OFDM0_AGCRSSITABLE); - reg |= ((((rx[1] & 0xf) >> 6) << 12) & 0xf000); - rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE, reg); - } + return (error); } -#define RTWN_IQ_CAL_NRUN 3 -static void -rtwn_iq_calib(struct rtwn_softc *sc) +static struct ieee80211_node * +rtwn_node_alloc(struct ieee80211vap *vap, + const uint8_t mac[IEEE80211_ADDR_LEN]) { - uint16_t tx[RTWN_IQ_CAL_NRUN][2][2], rx[RTWN_IQ_CAL_NRUN][2][2]; - int n, valid; + struct rtwn_node *un; - valid = 0; - for (n = 0; n < RTWN_IQ_CAL_NRUN; n++) { - rtwn_iq_calib_run(sc, n, tx[n], rx[n]); + un = malloc(sizeof (struct rtwn_node), M_80211_NODE, + M_NOWAIT | M_ZERO); - if (n == 0) - continue; + if (un == NULL) + return NULL; - /* Valid results remain stable after consecutive runs. */ - valid = rtwn_iq_calib_compare_results(tx[n - 1], rx[n - 1], - tx[n], rx[n], sc->ntxchains); - if (valid) + un->id = RTWN_MACID_UNDEFINED; + un->avg_pwdb = -1; + + return &un->ni; +} + +static void +rtwn_newassoc(struct ieee80211_node *ni, int isnew) +{ + struct rtwn_softc *sc = ni->ni_ic->ic_softc; + struct rtwn_node *un = RTWN_NODE(ni); + int id; + + if (!isnew) + return; + + RTWN_NT_LOCK(sc); + for (id = 0; id <= sc->macid_limit; id++) { + if (id != RTWN_MACID_BC && sc->node_list[id] == NULL) { + un->id = id; + sc->node_list[id] = ni; break; - } - - if (valid) { - rtwn_iq_calib_write_results(sc, tx[n][0], rx[n][0], 0); - if (sc->ntxchains > 1) - rtwn_iq_calib_write_results(sc, tx[n][1], rx[n][1], 1); - } -} -#undef RTWN_IQ_CAL_NRUN - -static void -rtwn_lc_calib(struct rtwn_softc *sc) -{ - uint32_t rf_ac[2]; - uint8_t txmode; - int i; - - txmode = rtwn_read_1(sc, R92C_OFDM1_LSTF + 3); - if ((txmode & 0x70) != 0) { - /* Disable all continuous Tx. */ - rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70); - - /* Set RF mode to standby mode. */ - for (i = 0; i < sc->nrxchains; i++) { - rf_ac[i] = rtwn_rf_read(sc, i, R92C_RF_AC); - rtwn_rf_write(sc, i, R92C_RF_AC, - RW(rf_ac[i], R92C_RF_AC_MODE, - R92C_RF_AC_MODE_STANDBY)); } - } else { - /* Block all Tx queues. */ - rtwn_write_1(sc, R92C_TXPAUSE, 0xff); } - /* Start calibration. */ - rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, - rtwn_rf_read(sc, 0, R92C_RF_CHNLBW) | R92C_RF_CHNLBW_LCSTART); + RTWN_NT_UNLOCK(sc); - /* Give calibration the time to complete. */ - DELAY(100); - - /* Restore configuration. */ - if ((txmode & 0x70) != 0) { - /* Restore Tx mode. */ - rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode); - /* Restore RF mode. */ - for (i = 0; i < sc->nrxchains; i++) - rtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]); - } else { - /* Unblock all Tx queues. */ - rtwn_write_1(sc, R92C_TXPAUSE, 0x00); + if (id > sc->macid_limit) { + device_printf(sc->sc_dev, "%s: node table is full\n", + __func__); + return; } + +#ifndef RTWN_WITHOUT_UCODE + /* Notify firmware. */ + id |= RTWN_MACID_VALID; + rtwn_cmd_sleepable(sc, &id, sizeof(id), rtwn_set_media_status); +#endif } static void -rtwn_temp_calib(struct rtwn_softc *sc) +rtwn_node_free(struct ieee80211_node *ni) { - int temp; + struct rtwn_softc *sc = ni->ni_ic->ic_softc; + struct rtwn_node *un = RTWN_NODE(ni); - if (sc->thcal_state == 0) { - /* Start measuring temperature. */ - rtwn_rf_write(sc, 0, R92C_RF_T_METER, 0x60); - sc->thcal_state = 1; - return; + RTWN_NT_LOCK(sc); + if (un->id != RTWN_MACID_UNDEFINED) { + sc->node_list[un->id] = NULL; +#ifndef RTWN_WITHOUT_UCODE + rtwn_cmd_sleepable(sc, &un->id, sizeof(un->id), + rtwn_set_media_status); +#endif } - sc->thcal_state = 0; + RTWN_NT_UNLOCK(sc); - /* Read measured temperature. */ - temp = rtwn_rf_read(sc, 0, R92C_RF_T_METER) & 0x1f; - if (temp == 0) /* Read failed, skip. */ - return; - DPRINTFN(2, ("temperature=%d\n", temp)); + sc->sc_node_free(ni); +} - /* - * Redo IQ and LC calibration if temperature changed significantly - * since last calibration. - */ - if (sc->thcal_lctemp == 0) { - /* First calibration is performed in rtwn_init(). */ - sc->thcal_lctemp = temp; - } else if (abs(temp - sc->thcal_lctemp) > 1) { - DPRINTF(("IQ/LC calib triggered by temp: %d -> %d\n", - sc->thcal_lctemp, temp)); - rtwn_iq_calib(sc); - rtwn_lc_calib(sc); - /* Record temperature of last calibration. */ - sc->thcal_lctemp = temp; - } +static void +rtwn_init_beacon_reg(struct rtwn_softc *sc) +{ + rtwn_write_1(sc, R92C_BCN_CTRL(0), R92C_BCN_CTRL_DIS_TSF_UDT0); + rtwn_write_1(sc, R92C_BCN_CTRL(1), R92C_BCN_CTRL_DIS_TSF_UDT0); + rtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404); + rtwn_write_1(sc, R92C_DRVERLYINT, 0x05); + rtwn_write_1(sc, R92C_BCNDMATIM, 0x02); + rtwn_write_2(sc, R92C_BCNTCFG, 0x660f); } static int rtwn_init(struct rtwn_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - uint32_t reg; - uint8_t macaddr[IEEE80211_ADDR_LEN]; int i, error; RTWN_LOCK(sc); - if (sc->sc_flags & RTWN_RUNNING) { RTWN_UNLOCK(sc); - return 0; + return (0); } - sc->sc_flags |= RTWN_RUNNING; - - /* Init firmware commands ring. */ - sc->fwcur = 0; + sc->sc_flags |= RTWN_STARTED; /* Power on adapter. */ error = rtwn_power_on(sc); + if (error != 0) + goto fail; + +#ifndef RTWN_WITHOUT_UCODE + /* Load 8051 microcode. */ + error = rtwn_load_firmware(sc); + if (error == 0) + sc->sc_flags |= RTWN_FW_LOADED; + + /* Init firmware commands ring. */ + sc->fwcur = 0; +#endif + + /* Initialize MAC block. */ + error = rtwn_mac_init(sc); if (error != 0) { - device_printf(sc->sc_dev, "could not power on adapter\n"); + device_printf(sc->sc_dev, + "%s: error while initializing MAC block\n", __func__); goto fail; } /* Initialize DMA. */ error = rtwn_dma_init(sc); - if (error != 0) { - device_printf(sc->sc_dev, "could not initialize DMA\n"); + if (error != 0) goto fail; - } + + /* Drop incorrect TX (USB). */ + rtwn_drop_incorrect_tx(sc); /* Set info size in Rx descriptors (in 64-bit words). */ - rtwn_write_1(sc, R92C_RX_DRVINFO_SZ, 4); + rtwn_write_1(sc, R92C_RX_DRVINFO_SZ, R92C_RX_DRVINFO_SZ_DEF); - /* Disable interrupts. */ - rtwn_write_4(sc, R92C_HISR, 0x00000000); - rtwn_write_4(sc, R92C_HIMR, 0x00000000); + /* Init interrupts. */ + rtwn_init_intr(sc); - /* Set MAC address. */ - IEEE80211_ADDR_COPY(macaddr, vap ? vap->iv_myaddr : ic->ic_macaddr); - for (i = 0; i < IEEE80211_ADDR_LEN; i++) - rtwn_write_1(sc, R92C_MACID + i, macaddr[i]); + for (i = 0; i < nitems(sc->vaps); i++) { + struct rtwn_vap *uvp = sc->vaps[i]; - /* Set initial network type. */ - reg = rtwn_read_4(sc, R92C_CR); - reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA); - rtwn_write_4(sc, R92C_CR, reg); + /* Set initial network type. */ + rtwn_set_mode(sc, R92C_MSR_NOLINK, i); + if (uvp == NULL) + continue; + + /* Set MAC address. */ + error = rtwn_set_macaddr(sc, uvp->vap.iv_myaddr, uvp->id); + if (error != 0) + goto fail; + } + + /* Initialize Rx filter. */ rtwn_rxfilter_init(sc); - reg = rtwn_read_4(sc, R92C_RRSR); - reg = RW(reg, R92C_RRSR_RATE_BITMAP, R92C_RRSR_RATE_ALL); - rtwn_write_4(sc, R92C_RRSR, reg); - /* Set short/long retry limits. */ rtwn_write_2(sc, R92C_RL, - SM(R92C_RL_SRL, 0x07) | SM(R92C_RL_LRL, 0x07)); + SM(R92C_RL_SRL, 0x30) | SM(R92C_RL_LRL, 0x30)); /* Initialize EDCA parameters. */ - rtwn_edca_init(sc); - - /* Set data and response automatic rate fallback retry counts. */ - rtwn_write_4(sc, R92C_DARFRC + 0, 0x01000000); - rtwn_write_4(sc, R92C_DARFRC + 4, 0x07060504); - rtwn_write_4(sc, R92C_RARFRC + 0, 0x01000000); - rtwn_write_4(sc, R92C_RARFRC + 4, 0x07060504); - - rtwn_write_2(sc, R92C_FWHW_TXQ_CTRL, 0x1f80); + rtwn_init_edca(sc); + rtwn_setbits_1(sc, R92C_FWHW_TXQ_CTRL, 0, + R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW); /* Set ACK timeout. */ - rtwn_write_1(sc, R92C_ACKTO, 0x40); + rtwn_write_1(sc, R92C_ACKTO, sc->ackto); + + /* Setup aggregation. */ + /* Tx aggregation. */ + rtwn_init_tx_agg(sc); + rtwn_init_rx_agg(sc); /* Initialize beacon parameters. */ - rtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404); - rtwn_write_1(sc, R92C_DRVERLYINT, 0x05); - rtwn_write_1(sc, R92C_BCNDMATIM, 0x02); - rtwn_write_2(sc, R92C_BCNTCFG, 0x660f); + rtwn_init_beacon_reg(sc); - /* Setup AMPDU aggregation. */ - rtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */ - rtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16); + /* Init A-MPDU parameters. */ + rtwn_init_ampdu(sc); - rtwn_write_1(sc, R92C_BCN_MAX_ERR, 0xff); - rtwn_write_1(sc, R92C_BCN_CTRL, R92C_BCN_CTRL_DIS_TSF_UDT0); + /* Init MACTXEN / MACRXEN after setting RxFF boundary. */ + rtwn_setbits_1(sc, R92C_CR, 0, R92C_CR_MACTXEN | R92C_CR_MACRXEN); - rtwn_write_4(sc, R92C_PIFS, 0x1c); - rtwn_write_4(sc, R92C_MCUTST_1, 0x0); + /* Initialize BB/RF blocks. */ + rtwn_init_bb(sc); + rtwn_init_rf(sc); - /* Load 8051 microcode. */ - error = rtwn_load_firmware(sc); - if (error != 0) - goto fail; - - /* Initialize MAC/BB/RF blocks. */ - rtwn_mac_init(sc); - rtwn_bb_init(sc); - rtwn_rf_init(sc); - - /* Turn CCK and OFDM blocks on. */ - reg = rtwn_bb_read(sc, R92C_FPGA0_RFMOD); - reg |= R92C_RFMOD_CCK_EN; - rtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg); - reg = rtwn_bb_read(sc, R92C_FPGA0_RFMOD); - reg |= R92C_RFMOD_OFDM_EN; - rtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg); + /* Initialize wireless band. */ + rtwn_set_chan(sc, ic->ic_curchan); /* Clear per-station keys table. */ - rtwn_cam_init(sc); + rtwn_init_cam(sc); + + /* Enable decryption / encryption. */ + rtwn_init_seccfg(sc); + + /* Install static keys (if any). */ + for (i = 0; i < nitems(sc->vaps); i++) { + if (sc->vaps[i] != NULL) { + error = rtwn_init_static_keys(sc, sc->vaps[i]); + if (error != 0) + goto fail; + } + } + + /* Initialize antenna selection. */ + rtwn_init_antsel(sc); /* Enable hardware sequence numbering. */ - rtwn_write_1(sc, R92C_HWSEQ_CTRL, 0xff); + rtwn_write_1(sc, R92C_HWSEQ_CTRL, R92C_TX_QUEUE_ALL); - /* Perform LO and IQ calibrations. */ - rtwn_iq_calib(sc); - /* Perform LC calibration. */ - rtwn_lc_calib(sc); + /* Disable BAR. */ + rtwn_write_4(sc, R92C_BAR_MODE_CTRL, 0x0201ffff); - rtwn_pa_bias_init(sc); + /* NAV limit. */ + rtwn_write_1(sc, R92C_NAV_UPPER, 0); /* Initialize GPIO setting. */ - rtwn_write_1(sc, R92C_GPIO_MUXCFG, - rtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_ENBT); + rtwn_setbits_1(sc, R92C_GPIO_MUXCFG, R92C_GPIO_MUXCFG_ENBT, 0); - /* Fix for lower temperature. */ - rtwn_write_1(sc, 0x15, 0xe9); + /* Initialize MRR. */ + rtwn_mrr_init(sc); - /* CLear pending interrupts. */ - rtwn_write_4(sc, R92C_HISR, 0xffffffff); + /* Device-specific post initialization. */ + rtwn_post_init(sc); - /* Enable interrupts. */ - rtwn_write_4(sc, R92C_HIMR, RTWN_INT_ENABLE); + rtwn_start_xfers(sc); - callout_reset(&sc->watchdog_to, hz, rtwn_watchdog, sc); +#ifndef D4054 + callout_reset(&sc->sc_watchdog_to, hz, rtwn_watchdog, sc); +#endif + sc->sc_flags |= RTWN_RUNNING; fail: - if (error != 0) - rtwn_stop_locked(sc); - RTWN_UNLOCK(sc); - return error; -} - -static void -rtwn_stop_locked(struct rtwn_softc *sc) -{ - uint16_t reg; - int i; - - RTWN_LOCK_ASSERT(sc); - - if (!(sc->sc_flags & RTWN_RUNNING)) - return; - - sc->sc_tx_timer = 0; - callout_stop(&sc->watchdog_to); - callout_stop(&sc->calib_to); - sc->sc_flags &= ~RTWN_RUNNING; - - /* Disable interrupts. */ - rtwn_write_4(sc, R92C_HISR, 0x00000000); - rtwn_write_4(sc, R92C_HIMR, 0x00000000); - - /* Stop hardware. */ - rtwn_write_1(sc, R92C_TXPAUSE, 0xff); - rtwn_write_1(sc, R92C_RF_CTRL, 0x00); - reg = rtwn_read_1(sc, R92C_SYS_FUNC_EN); - reg |= R92C_SYS_FUNC_EN_BB_GLB_RST; - rtwn_write_1(sc, R92C_SYS_FUNC_EN, reg); - reg &= ~R92C_SYS_FUNC_EN_BB_GLB_RST; - rtwn_write_1(sc, R92C_SYS_FUNC_EN, reg); - reg = rtwn_read_2(sc, R92C_CR); - reg &= ~(R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | - R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | - R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN | - R92C_CR_ENSEC); - rtwn_write_2(sc, R92C_CR, reg); - if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) - rtwn_fw_reset(sc); - /* TODO: linux does additional btcoex stuff here */ - rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0x80); /* linux magic number */ - rtwn_write_1(sc, R92C_SPS0_CTRL, 0x23); /* ditto */ - rtwn_write_1(sc, R92C_AFE_XTAL_CTRL, 0x0e); /* different with btcoex */ - rtwn_write_1(sc, R92C_RSV_CTRL, 0x0e); - rtwn_write_1(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_PDN_EN); - - for (i = 0; i < RTWN_NTXQUEUES; i++) - rtwn_reset_tx_list(sc, i); - rtwn_reset_rx_list(sc); + return (error); } static void rtwn_stop(struct rtwn_softc *sc) { - RTWN_LOCK(sc); - rtwn_stop_locked(sc); - RTWN_UNLOCK(sc); -} - -static void -rtwn_intr(void *arg) -{ - struct rtwn_softc *sc = arg; - uint32_t status; - int i; RTWN_LOCK(sc); - status = rtwn_read_4(sc, R92C_HISR); - if (status == 0 || status == 0xffffffff) { + if (!(sc->sc_flags & RTWN_STARTED)) { RTWN_UNLOCK(sc); return; } - /* Disable interrupts. */ - rtwn_write_4(sc, R92C_HIMR, 0x00000000); +#ifndef D4054 + callout_stop(&sc->sc_watchdog_to); +#endif + sc->sc_flags &= ~(RTWN_STARTED | RTWN_RUNNING | RTWN_FW_LOADED); + sc->sc_flags &= ~RTWN_TEMP_MEASURED; + sc->fwver = 0; + sc->thcal_temp = 0; + sc->cur_bcnq_id = RTWN_VAP_ID_INVALID; - /* Ack interrupts. */ - rtwn_write_4(sc, R92C_HISR, status); - - /* Vendor driver treats RX errors like ROK... */ - if (status & (R92C_IMR_ROK | R92C_IMR_RXFOVW | R92C_IMR_RDU)) { - bus_dmamap_sync(sc->rx_ring.desc_dmat, sc->rx_ring.desc_map, - BUS_DMASYNC_POSTREAD); - - for (i = 0; i < RTWN_RX_LIST_COUNT; i++) { - struct r92c_rx_desc *rx_desc = &sc->rx_ring.desc[i]; - struct rtwn_rx_data *rx_data = &sc->rx_ring.rx_data[i]; - - if (le32toh(rx_desc->rxdw0) & R92C_RXDW0_OWN) - continue; - - rtwn_rx_frame(sc, rx_desc, rx_data, i); - } - } - - if (status & R92C_IMR_BDOK) - rtwn_tx_done(sc, RTWN_BEACON_QUEUE); - if (status & R92C_IMR_HIGHDOK) - rtwn_tx_done(sc, RTWN_HIGH_QUEUE); - if (status & R92C_IMR_MGNTDOK) - rtwn_tx_done(sc, RTWN_MGNT_QUEUE); - if (status & R92C_IMR_BKDOK) - rtwn_tx_done(sc, RTWN_BK_QUEUE); - if (status & R92C_IMR_BEDOK) - rtwn_tx_done(sc, RTWN_BE_QUEUE); - if (status & R92C_IMR_VIDOK) - rtwn_tx_done(sc, RTWN_VI_QUEUE); - if (status & R92C_IMR_VODOK) - rtwn_tx_done(sc, RTWN_VO_QUEUE); - - /* Enable interrupts. */ - rtwn_write_4(sc, R92C_HIMR, RTWN_INT_ENABLE); +#ifdef D4054 + ieee80211_tx_watchdog_stop(&sc->sc_ic); +#endif + rtwn_abort_xfers(sc); + rtwn_drain_mbufq(sc); + rtwn_power_off(sc); + rtwn_reset_lists(sc, NULL); RTWN_UNLOCK(sc); } + +MODULE_VERSION(rtwn, 2); +MODULE_DEPEND(rtwn, wlan, 1, 1, 1); +#ifndef RTWN_WITHOUT_UCODE +MODULE_DEPEND(rtwn, firmware, 1, 1, 1); +#endif diff --git a/sys/dev/rtwn/if_rtwn_beacon.c b/sys/dev/rtwn/if_rtwn_beacon.c new file mode 100644 index 000000000000..c2329ad517a0 --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_beacon.c @@ -0,0 +1,213 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + + +static void +rtwn_reset_beacon_valid(struct rtwn_softc *sc, int id) +{ + + KASSERT (id == 0 || id == 1, ("wrong port id %d\n", id)); + + rtwn_setbits_1_shift(sc, sc->bcn_status_reg[id], + R92C_TDECTRL_BCN_VALID, 0, 2); + + RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON, + "%s: 'beacon valid' bit for vap %d was unset\n", + __func__, id); +} + +static int +rtwn_check_beacon_valid(struct rtwn_softc *sc, int id) +{ + uint16_t reg; + int ntries; + + if (id == RTWN_VAP_ID_INVALID) + return (0); + + reg = sc->bcn_status_reg[id]; + for (ntries = 0; ntries < 10; ntries++) { + if (rtwn_read_4(sc, reg) & R92C_TDECTRL_BCN_VALID) { + RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON, + "%s: beacon for vap %d was recognized\n", + __func__, id); + break; + } + rtwn_delay(sc, 100); + } + if (ntries == 10) + return (ETIMEDOUT); + + return (0); +} + +void +rtwn_switch_bcnq(struct rtwn_softc *sc, int id) +{ + + if (sc->cur_bcnq_id != id) { + /* Wait until any previous transmit completes. */ + (void) rtwn_check_beacon_valid(sc, sc->cur_bcnq_id); + + /* Change current port. */ + rtwn_beacon_select(sc, id); + sc->cur_bcnq_id = id; + } + + /* Reset 'beacon valid' bit. */ + rtwn_reset_beacon_valid(sc, id); +} + +int +rtwn_setup_beacon(struct rtwn_softc *sc, struct ieee80211_node *ni) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct mbuf *m; + + RTWN_ASSERT_LOCKED(sc); + + if (ni->ni_chan == IEEE80211_CHAN_ANYC) + return (EINVAL); + + m = ieee80211_beacon_alloc(ni); + if (m == NULL) { + device_printf(sc->sc_dev, + "%s: could not allocate beacon frame\n", __func__); + return (ENOMEM); + } + + if (uvp->bcn_mbuf != NULL) + m_freem(uvp->bcn_mbuf); + + uvp->bcn_mbuf = m; + + rtwn_beacon_set_rate(sc, &uvp->bcn_desc.txd[0], + IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)); + + return (rtwn_tx_beacon_check(sc, uvp)); +} + +/* + * Push a beacon frame into the chip. Beacon will + * be repeated by the chip every R92C_BCN_INTERVAL. + */ +static int +rtwn_tx_beacon(struct rtwn_softc *sc, struct rtwn_vap *uvp) +{ + int error; + + RTWN_ASSERT_LOCKED(sc); + + RTWN_DPRINTF(sc, RTWN_DEBUG_BEACON, + "%s: sending beacon for vap %d\n", __func__, uvp->id); + + error = rtwn_tx_start(sc, NULL, uvp->bcn_mbuf, &uvp->bcn_desc.txd[0], + IEEE80211_FC0_TYPE_MGT, uvp->id); + + return (error); +} + +void +rtwn_update_beacon(struct ieee80211vap *vap, int item) +{ + struct rtwn_softc *sc = vap->iv_ic->ic_softc; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; + struct ieee80211_node *ni = vap->iv_bss; + int mcast = 0; + + RTWN_LOCK(sc); + if (uvp->bcn_mbuf == NULL) { + uvp->bcn_mbuf = ieee80211_beacon_alloc(ni); + if (uvp->bcn_mbuf == NULL) { + device_printf(sc->sc_dev, + "%s: could not allocate beacon frame\n", __func__); + RTWN_UNLOCK(sc); + return; + } + } + RTWN_UNLOCK(sc); + + if (item == IEEE80211_BEACON_TIM) + mcast = 1; /* XXX */ + + setbit(bo->bo_flags, item); + ieee80211_beacon_update(ni, uvp->bcn_mbuf, mcast); + + RTWN_LOCK(sc); + rtwn_tx_beacon(sc, uvp); + RTWN_UNLOCK(sc); +} + +int +rtwn_tx_beacon_check(struct rtwn_softc *sc, struct rtwn_vap *uvp) +{ + int ntries, error; + + for (ntries = 0; ntries < 5; ntries++) { + rtwn_reset_beacon_valid(sc, uvp->id); + + error = rtwn_tx_beacon(sc, uvp); + if (error != 0) + continue; + + error = rtwn_check_beacon_valid(sc, uvp->id); + if (error == 0) + break; + } + if (ntries == 5) { + device_printf(sc->sc_dev, + "%s: cannot push beacon into chip, error %d!\n", + __func__, error); + return (error); + } + + return (0); +} diff --git a/sys/dev/rtwn/if_rtwn_beacon.h b/sys/dev/rtwn/if_rtwn_beacon.h new file mode 100644 index 000000000000..5bbbcbca07fb --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_beacon.h @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_BEACON_H +#define IF_RTWN_BEACON_H + +void rtwn_switch_bcnq(struct rtwn_softc *, int); +int rtwn_setup_beacon(struct rtwn_softc *, struct ieee80211_node *); +void rtwn_update_beacon(struct ieee80211vap *, int); +int rtwn_tx_beacon_check(struct rtwn_softc *, struct rtwn_vap *); + +#endif /* IF_RTWN_BEACON_H */ diff --git a/sys/dev/rtwn/if_rtwn_calib.c b/sys/dev/rtwn/if_rtwn_calib.c new file mode 100644 index 000000000000..5c3ed7e6491e --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_calib.c @@ -0,0 +1,128 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +static void +rtwn_temp_calib(struct rtwn_softc *sc) +{ + uint8_t temp; + + RTWN_ASSERT_LOCKED(sc); + + if (!(sc->sc_flags & RTWN_TEMP_MEASURED)) { + /* Start measuring temperature. */ + RTWN_DPRINTF(sc, RTWN_DEBUG_TEMP, + "%s: start measuring temperature\n", __func__); + rtwn_temp_measure(sc); + sc->sc_flags |= RTWN_TEMP_MEASURED; + return; + } + sc->sc_flags &= ~RTWN_TEMP_MEASURED; + + /* Read measured temperature. */ + temp = rtwn_temp_read(sc); + if (temp == 0) { /* Read failed, skip. */ + RTWN_DPRINTF(sc, RTWN_DEBUG_TEMP, + "%s: temperature read failed, skipping\n", __func__); + return; + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_TEMP, + "temperature: previous %u, current %u\n", + sc->thcal_temp, temp); + + /* + * Redo LC/IQ calibration if temperature changed significantly since + * last calibration. + */ + if (sc->thcal_temp == 0xff) { + /* efuse value is absent; do LCK at initial status. */ + rtwn_lc_calib(sc); + + sc->thcal_temp = temp; + } else if (abs(temp - sc->thcal_temp) > sc->temp_delta) { + RTWN_DPRINTF(sc, RTWN_DEBUG_TEMP, + "%s: LC/IQ calib triggered by temp: %u -> %u\n", + __func__, sc->thcal_temp, temp); + + rtwn_lc_calib(sc); + rtwn_iq_calib(sc); + + /* Record temperature of last calibration. */ + sc->thcal_temp = temp; + } +} + +static void +rtwn_calib_cb(struct rtwn_softc *sc, union sec_param *data) +{ + /* Do temperature compensation. */ + rtwn_temp_calib(sc); + +#ifndef RTWN_WITHOUT_UCODE + if (sc->sc_ratectl == RTWN_RATECTL_FW) { + /* Refresh per-node RSSI. */ + rtwn_set_rssi(sc); + } +#endif + + if (sc->vaps_running > sc->monvaps_running) + callout_reset(&sc->sc_calib_to, 2*hz, rtwn_calib_to, sc); +} + +void +rtwn_calib_to(void *arg) +{ + struct rtwn_softc *sc = arg; + + /* Do it in a process context. */ + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_calib_cb); +} diff --git a/sys/dev/rtwn/if_rtwn_calib.h b/sys/dev/rtwn/if_rtwn_calib.h new file mode 100644 index 000000000000..ee50fd06b379 --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_calib.h @@ -0,0 +1,24 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_CALIB_H +#define IF_RTWN_CALIB_H + +void rtwn_calib_to(void *); + +#endif /* IF_RTWN_CALIB_H */ diff --git a/sys/dev/rtwn/if_rtwn_cam.c b/sys/dev/rtwn/if_rtwn_cam.c new file mode 100644 index 000000000000..c817a6ea9435 --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_cam.c @@ -0,0 +1,360 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include + + +void +rtwn_init_cam(struct rtwn_softc *sc) +{ + /* Invalidate all CAM entries. */ + rtwn_write_4(sc, R92C_CAMCMD, + R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR); +} + +static int +rtwn_cam_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data) +{ + int error; + + error = rtwn_write_4(sc, R92C_CAMWRITE, data); + if (error != 0) + return (error); + error = rtwn_write_4(sc, R92C_CAMCMD, + R92C_CAMCMD_POLLING | R92C_CAMCMD_WRITE | + SM(R92C_CAMCMD_ADDR, addr)); + + return (error); +} + +void +rtwn_init_seccfg(struct rtwn_softc *sc) +{ + uint16_t seccfg; + + /* Select decryption / encryption flags. */ + seccfg = 0; + switch (sc->sc_hwcrypto) { + case RTWN_CRYPTO_SW: + break; /* nothing to do */ + case RTWN_CRYPTO_PAIR: + /* NB: TXUCKEY_DEF / RXUCKEY_DEF are required for RTL8192C */ + seccfg = R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF | + R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXDEC_ENA | + R92C_SECCFG_MC_SRCH_DIS; + break; + case RTWN_CRYPTO_FULL: + seccfg = R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF | + R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXDEC_ENA | + R92C_SECCFG_TXBCKEY_DEF | R92C_SECCFG_RXBCKEY_DEF; + break; + default: + KASSERT(0, ("%s: case %d was not handled\n", __func__, + sc->sc_hwcrypto)); + break; + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_KEY, "%s: seccfg %04X, hwcrypto %d\n", + __func__, seccfg, sc->sc_hwcrypto); + + rtwn_write_2(sc, R92C_SECCFG, seccfg); +} + +int +rtwn_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, + ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) +{ + struct rtwn_softc *sc = vap->iv_ic->ic_softc; + int i, start; + + if (&vap->iv_nw_keys[0] <= k && + k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) { + *keyix = k - vap->iv_nw_keys; + if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL) + k->wk_flags |= IEEE80211_KEY_SWCRYPT; + else { + RTWN_LOCK(sc); + if (isset(sc->keys_bmap, *keyix)) { + device_printf(sc->sc_dev, + "%s: group key slot %d is already used!\n", + __func__, *keyix); + /* XXX recover? */ + RTWN_UNLOCK(sc); + return (0); + } + + setbit(sc->keys_bmap, *keyix); + RTWN_UNLOCK(sc); + } + + goto end; + } + + start = sc->cam_entry_limit; + switch (sc->sc_hwcrypto) { + case RTWN_CRYPTO_SW: + k->wk_flags |= IEEE80211_KEY_SWCRYPT; + *keyix = 0; + goto end; + case RTWN_CRYPTO_PAIR: + /* all slots for pairwise keys. */ + start = 0; + RTWN_LOCK(sc); + if (sc->sc_flags & RTWN_FLAG_CAM_FIXED) + start = 4; + RTWN_UNLOCK(sc); + break; + case RTWN_CRYPTO_FULL: + /* first 4 - for group keys, others for pairwise. */ + start = 4; + break; + default: + KASSERT(0, ("%s: case %d was not handled!\n", + __func__, sc->sc_hwcrypto)); + break; + } + + RTWN_LOCK(sc); + for (i = start; i < sc->cam_entry_limit; i++) { + if (isclr(sc->keys_bmap, i)) { + setbit(sc->keys_bmap, i); + *keyix = i; + break; + } + } + RTWN_UNLOCK(sc); + if (i == sc->cam_entry_limit) { +#if __FreeBSD_version > 1200008 + /* XXX check and remove keys with the same MAC address */ + k->wk_flags |= IEEE80211_KEY_SWCRYPT; + *keyix = 0; +#else + device_printf(sc->sc_dev, + "%s: no free space in the key table\n", __func__); + return (0); +#endif + } + +end: + *rxkeyix = *keyix; + return (1); +} + +static int +rtwn_key_set_cb0(struct rtwn_softc *sc, const struct ieee80211_key *k) +{ + uint8_t algo, keyid; + int i, error; + + if (sc->sc_hwcrypto == RTWN_CRYPTO_FULL && + k->wk_keyix < IEEE80211_WEP_NKID) + keyid = k->wk_keyix; + else + keyid = 0; + + /* Map net80211 cipher to HW crypto algorithm. */ + switch (k->wk_cipher->ic_cipher) { + case IEEE80211_CIPHER_WEP: + if (k->wk_keylen < 8) + algo = R92C_CAM_ALGO_WEP40; + else + algo = R92C_CAM_ALGO_WEP104; + break; + case IEEE80211_CIPHER_TKIP: + algo = R92C_CAM_ALGO_TKIP; + break; + case IEEE80211_CIPHER_AES_CCM: + algo = R92C_CAM_ALGO_AES; + break; + default: + device_printf(sc->sc_dev, "%s: unknown cipher %u\n", + __func__, k->wk_cipher->ic_cipher); + return (EINVAL); + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_KEY, + "%s: keyix %u, keyid %u, algo %u/%u, flags %04X, len %u, " + "macaddr %s\n", __func__, k->wk_keyix, keyid, + k->wk_cipher->ic_cipher, algo, k->wk_flags, k->wk_keylen, + ether_sprintf(k->wk_macaddr)); + + /* Clear high bits. */ + rtwn_cam_write(sc, R92C_CAM_CTL6(k->wk_keyix), 0); + rtwn_cam_write(sc, R92C_CAM_CTL7(k->wk_keyix), 0); + + /* Write key. */ + for (i = 0; i < 4; i++) { + error = rtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i), + le32dec(&k->wk_key[i * 4])); + if (error != 0) + goto fail; + } + + /* Write CTL0 last since that will validate the CAM entry. */ + error = rtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix), + le32dec(&k->wk_macaddr[2])); + if (error != 0) + goto fail; + error = rtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix), + SM(R92C_CAM_ALGO, algo) | + SM(R92C_CAM_KEYID, keyid) | + SM(R92C_CAM_MACLO, le16dec(&k->wk_macaddr[0])) | + R92C_CAM_VALID); + if (error != 0) + goto fail; + + return (0); + +fail: + device_printf(sc->sc_dev, "%s fails, error %d\n", __func__, error); + return (error); +} + +static void +rtwn_key_set_cb(struct rtwn_softc *sc, union sec_param *data) +{ + const struct ieee80211_key *k = &data->key; + + (void) rtwn_key_set_cb0(sc, k); +} + +int +rtwn_init_static_keys(struct rtwn_softc *sc, struct rtwn_vap *rvp) +{ + int i, error; + + if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL) + return (0); /* nothing to do */ + + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + const struct ieee80211_key *k = rvp->keys[i]; + if (k != NULL) { + error = rtwn_key_set_cb0(sc, k); + if (error != 0) + return (error); + } + } + + return (0); +} + +static void +rtwn_key_del_cb(struct rtwn_softc *sc, union sec_param *data) +{ + struct ieee80211_key *k = &data->key; + int i; + + RTWN_DPRINTF(sc, RTWN_DEBUG_KEY, + "%s: keyix %u, flags %04X, macaddr %s\n", __func__, + k->wk_keyix, k->wk_flags, ether_sprintf(k->wk_macaddr)); + + rtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix), 0); + rtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix), 0); + + /* Clear key. */ + for (i = 0; i < 4; i++) + rtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i), 0); + clrbit(sc->keys_bmap, k->wk_keyix); +} + +static int +rtwn_process_key(struct ieee80211vap *vap, const struct ieee80211_key *k, + int set) +{ + struct rtwn_softc *sc = vap->iv_ic->ic_softc; + + if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { + /* Not for us. */ + return (1); + } + + if (&vap->iv_nw_keys[0] <= k && + k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) { +#if __FreeBSD_version <= 1200008 + struct ieee80211_key *k1 = &vap->iv_nw_keys[k->wk_keyix]; + + if (sc->sc_hwcrypto != RTWN_CRYPTO_FULL) { + k1->wk_flags |= IEEE80211_KEY_SWCRYPT; + return (k->wk_cipher->ic_setkey(k1)); + } else { +#else + if (sc->sc_hwcrypto == RTWN_CRYPTO_FULL) { +#endif + struct rtwn_vap *rvp = RTWN_VAP(vap); + + RTWN_LOCK(sc); + rvp->keys[k->wk_keyix] = (set ? k : NULL); + if ((sc->sc_flags & RTWN_RUNNING) == 0) { + if (!set) + clrbit(sc->keys_bmap, k->wk_keyix); + RTWN_UNLOCK(sc); + return (1); + } + RTWN_UNLOCK(sc); + } + } + + return (!rtwn_cmd_sleepable(sc, k, sizeof(*k), + set ? rtwn_key_set_cb : rtwn_key_del_cb)); +} + +int +rtwn_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k) +{ + return (rtwn_process_key(vap, k, 1)); +} + +int +rtwn_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) +{ + return (rtwn_process_key(vap, k, 0)); +} diff --git a/sys/dev/rtwn/if_rtwn_cam.h b/sys/dev/rtwn/if_rtwn_cam.h new file mode 100644 index 000000000000..280509b95ed4 --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_cam.h @@ -0,0 +1,30 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_CAM_H +#define IF_RTWN_CAM_H + +void rtwn_init_cam(struct rtwn_softc *); +void rtwn_init_seccfg(struct rtwn_softc *); +int rtwn_key_alloc(struct ieee80211vap *, struct ieee80211_key *, + ieee80211_keyix *, ieee80211_keyix *); +int rtwn_key_set(struct ieee80211vap *, const struct ieee80211_key *); +int rtwn_init_static_keys(struct rtwn_softc *, struct rtwn_vap *); +int rtwn_key_delete(struct ieee80211vap *, const struct ieee80211_key *); + +#endif /* IF_RTWN_CAM_H */ diff --git a/sys/dev/rtwn/if_rtwn_debug.h b/sys/dev/rtwn/if_rtwn_debug.h new file mode 100644 index 000000000000..daf628a68763 --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_debug.h @@ -0,0 +1,59 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_DEBUG_H +#define IF_RTWN_DEBUG_H + +#include "opt_rtwn.h" + +#ifdef RTWN_DEBUG +enum { + RTWN_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ + RTWN_DEBUG_XMIT_DESC = 0x00000002, /* xmit descriptors */ + RTWN_DEBUG_RECV = 0x00000004, /* basic recv operation */ + RTWN_DEBUG_RECV_DESC = 0x00000008, /* recv descriptors */ + RTWN_DEBUG_STATE = 0x00000010, /* 802.11 state transitions */ + RTWN_DEBUG_RA = 0x00000020, /* f/w rate adaptation setup */ + RTWN_DEBUG_USB = 0x00000040, /* usb requests */ + RTWN_DEBUG_FIRMWARE = 0x00000080, /* firmware(9) loading debug */ + RTWN_DEBUG_BEACON = 0x00000100, /* beacon handling */ + RTWN_DEBUG_INTR = 0x00000200, /* ISR */ + RTWN_DEBUG_TEMP = 0x00000400, /* temperature calibration */ + RTWN_DEBUG_ROM = 0x00000800, /* various ROM info */ + RTWN_DEBUG_KEY = 0x00001000, /* crypto keys management */ + RTWN_DEBUG_TXPWR = 0x00002000, /* dump Tx power values */ + RTWN_DEBUG_RSSI = 0x00004000, /* dump RSSI lookups */ + RTWN_DEBUG_RESET = 0x00008000, /* initialization progress */ + RTWN_DEBUG_CALIB = 0x00010000, /* calibration progress */ + RTWN_DEBUG_ANY = 0xffffffff +}; + +#define RTWN_DPRINTF(_sc, _m, ...) do { \ + if ((_sc)->sc_debug & (_m)) \ + device_printf((_sc)->sc_dev, __VA_ARGS__); \ +} while(0) + +#else +#define RTWN_DPRINTF(_sc, _m, ...) do { (void) _sc; } while (0) +#endif + +#endif /* IF_RTWN_DEBUG_H */ diff --git a/sys/dev/rtwn/if_rtwn_efuse.c b/sys/dev/rtwn/if_rtwn_efuse.c new file mode 100644 index 000000000000..b14f97377dd4 --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_efuse.c @@ -0,0 +1,265 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + + +static int +rtwn_efuse_switch_power(struct rtwn_softc *sc) +{ + uint32_t reg; + int error; + + error = rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_ON); + if (error != 0) + return (error); + + reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN); + if (!(reg & R92C_SYS_FUNC_EN_ELDR)) { + error = rtwn_write_2(sc, R92C_SYS_FUNC_EN, + reg | R92C_SYS_FUNC_EN_ELDR); + if (error != 0) + return (error); + } + reg = rtwn_read_2(sc, R92C_SYS_CLKR); + if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) != + (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) { + error = rtwn_write_2(sc, R92C_SYS_CLKR, + reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M); + if (error != 0) + return (error); + } + + return (0); +} + +int +rtwn_efuse_read_next(struct rtwn_softc *sc, uint8_t *val) +{ + uint32_t reg; + int ntries, error; + + if (sc->next_rom_addr >= sc->efuse_maxlen) + return (EFAULT); + + reg = rtwn_read_4(sc, R92C_EFUSE_CTRL); + reg = RW(reg, R92C_EFUSE_CTRL_ADDR, sc->next_rom_addr); + reg &= ~R92C_EFUSE_CTRL_VALID; + + error = rtwn_write_4(sc, R92C_EFUSE_CTRL, reg); + if (error != 0) + return (error); + /* Wait for read operation to complete. */ + for (ntries = 0; ntries < 100; ntries++) { + reg = rtwn_read_4(sc, R92C_EFUSE_CTRL); + if (reg & R92C_EFUSE_CTRL_VALID) + break; + rtwn_delay(sc, 10); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "could not read efuse byte at address 0x%x\n", + sc->next_rom_addr); + return (ETIMEDOUT); + } + + *val = MS(reg, R92C_EFUSE_CTRL_DATA); + sc->next_rom_addr++; + + return (0); +} + +static int +rtwn_efuse_read_data(struct rtwn_softc *sc, uint8_t *rom, uint8_t off, + uint8_t msk) +{ + uint8_t reg; + int addr, i, error; + + for (i = 0; i < 4; i++) { + if (msk & (1 << i)) + continue; + + addr = off * 8 + i * 2; + if (addr + 1 >= sc->efuse_maplen) + return (EFAULT); + + error = rtwn_efuse_read_next(sc, ®); + if (error != 0) + return (error); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n", + addr, reg); + rom[addr] = reg; + + error = rtwn_efuse_read_next(sc, ®); + if (error != 0) + return (error); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n", + addr + 1, reg); + rom[addr + 1] = reg; + } + + return (0); +} + +#ifdef RTWN_DEBUG +static void +rtwn_dump_rom_contents(struct rtwn_softc *sc, uint8_t *rom, uint16_t size) +{ + int i; + + /* Dump ROM contents. */ + device_printf(sc->sc_dev, "%s:", __func__); + for (i = 0; i < size; i++) { + if (i % 32 == 0) + printf("\n%03X: ", i); + else if (i % 4 == 0) + printf(" "); + + printf("%02X", rom[i]); + } + printf("\n"); +} +#endif + +static int +rtwn_efuse_read(struct rtwn_softc *sc, uint8_t *rom, uint16_t size) +{ +#define RTWN_CHK(res) do { \ + if ((error = res) != 0) \ + goto end; \ +} while(0) + uint8_t msk, off, reg; + int error; + + /* Read full ROM image. */ + sc->next_rom_addr = 0; + memset(rom, 0xff, size); + + RTWN_CHK(rtwn_efuse_read_next(sc, ®)); + while (reg != 0xff) { + /* check for extended header */ + if ((sc->sc_flags & RTWN_FLAG_EXT_HDR) && + (reg & 0x1f) == 0x0f) { + off = reg >> 5; + RTWN_CHK(rtwn_efuse_read_next(sc, ®)); + + if ((reg & 0x0f) != 0x0f) + off = ((reg & 0xf0) >> 1) | off; + else + continue; + } else + off = reg >> 4; + msk = reg & 0xf; + + RTWN_CHK(rtwn_efuse_read_data(sc, rom, off, msk)); + RTWN_CHK(rtwn_efuse_read_next(sc, ®)); + } + +end: + +#ifdef RTWN_DEBUG + if (sc->sc_debug & RTWN_DEBUG_ROM) + rtwn_dump_rom_contents(sc, rom, size); +#endif + + /* Device-specific. */ + rtwn_efuse_postread(sc); + + if (error != 0) { + device_printf(sc->sc_dev, "%s: error while reading ROM\n", + __func__); + } + + return (error); +#undef RTWN_CHK +} + +static int +rtwn_efuse_read_prepare(struct rtwn_softc *sc, uint8_t *rom, uint16_t size) +{ + int error; + + error = rtwn_efuse_switch_power(sc); + if (error != 0) + goto fail; + + error = rtwn_efuse_read(sc, rom, size); + +fail: + rtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_OFF); + + return (error); +} + +int +rtwn_read_rom(struct rtwn_softc *sc) +{ + uint8_t *rom; + int error; + + rom = malloc(sc->efuse_maplen, M_TEMP, M_WAITOK); + + /* Read full ROM image. */ + RTWN_LOCK(sc); + error = rtwn_efuse_read_prepare(sc, rom, sc->efuse_maplen); + RTWN_UNLOCK(sc); + if (error != 0) + goto fail; + + /* Parse & save data in softc. */ + rtwn_parse_rom(sc, rom); + +fail: + free(rom, M_TEMP); + + return (error); +} diff --git a/sys/dev/rtwn/if_rtwn_efuse.h b/sys/dev/rtwn/if_rtwn_efuse.h new file mode 100644 index 000000000000..62125c248496 --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_efuse.h @@ -0,0 +1,25 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_EFUSE_H +#define IF_RTWN_EFUSE_H + +int rtwn_efuse_read_next(struct rtwn_softc *, uint8_t *); +int rtwn_read_rom(struct rtwn_softc *); + +#endif /* IF_RTWN_EFUSE_H */ diff --git a/sys/dev/rtwn/if_rtwn_fw.c b/sys/dev/rtwn/if_rtwn_fw.c new file mode 100644 index 000000000000..5cc71d2b8043 --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_fw.c @@ -0,0 +1,224 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + + +#ifndef RTWN_WITHOUT_UCODE +static int +rtwn_fw_loadpage(struct rtwn_softc *sc, int page, const uint8_t *buf, + int len) +{ + uint32_t reg; + uint16_t off; + int mlen, error; + + reg = rtwn_read_4(sc, R92C_MCUFWDL); + reg = RW(reg, R92C_MCUFWDL_PAGE, page); + rtwn_write_4(sc, R92C_MCUFWDL, reg); + + error = 0; + off = R92C_FW_START_ADDR; + while (len > 0) { + if (len > R92C_FW_MAX_BLOCK_SIZE) + mlen = R92C_FW_MAX_BLOCK_SIZE; + else if (len > 4) + mlen = 4; + else + mlen = 1; + error = rtwn_fw_write_block(sc, buf, off, mlen); + if (error != 0) + break; + off += mlen; + buf += mlen; + len -= mlen; + } + + if (error != 0) { + RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, + "%s: could not load firmware page %d (offset %u)\n", + __func__, page, off); + } + + return (error); +} + +static int +rtwn_fw_checksum_report(struct rtwn_softc *sc) +{ + int ntries; + + for (ntries = 0; ntries < 25; ntries++) { + if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT) + break; + rtwn_delay(sc, 10000); + } + if (ntries == 25) { + RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, + "timeout waiting for checksum report\n"); + return (ETIMEDOUT); + } + + return (0); +} + +int +rtwn_load_firmware(struct rtwn_softc *sc) +{ + const struct firmware *fw; + const struct r92c_fw_hdr *hdr; + const u_char *ptr; + size_t len; + int ntries, error; + + /* Read firmware image from the filesystem. */ + RTWN_UNLOCK(sc); + fw = firmware_get(sc->fwname); + RTWN_LOCK(sc); + if (fw == NULL) { + device_printf(sc->sc_dev, + "failed loadfirmware of file %s\n", sc->fwname); + return (ENOENT); + } + + len = fw->datasize; + if (len < sizeof(*hdr) || len > sc->fwsize_limit) { + device_printf(sc->sc_dev, "wrong firmware size (%zu)\n", len); + error = EINVAL; + goto fail; + } + ptr = fw->data; + hdr = (const struct r92c_fw_hdr *)ptr; + /* Check if there is a valid FW header and skip it. */ + if ((le16toh(hdr->signature) >> 4) == sc->fwsig) { + sc->fwver = le16toh(hdr->version); + + RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, + "FW V%u.%u %02u-%02u %02u:%02u\n", + le16toh(hdr->version), le16toh(hdr->subversion), + hdr->month, hdr->date, hdr->hour, hdr->minute); + ptr += sizeof(*hdr); + len -= sizeof(*hdr); + } + + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) { + rtwn_write_1(sc, R92C_MCUFWDL, 0); + rtwn_fw_reset(sc, RTWN_FW_RESET_DOWNLOAD); + } + + /* Enable firmware download. */ + rtwn_fw_download_enable(sc, 1); + + error = 0; /* compiler warning */ + for (ntries = 0; ntries < 3; ntries++) { + const u_char *curr_ptr = ptr; + const int maxpages = len / R92C_FW_PAGE_SIZE; + int page; + + /* Reset the FWDL checksum. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_CHKSUM_RPT); + + for (page = 0; page < maxpages; page++) { + error = rtwn_fw_loadpage(sc, page, curr_ptr, + R92C_FW_PAGE_SIZE); + if (error != 0) + break; + curr_ptr += R92C_FW_PAGE_SIZE; + } + if (page != maxpages) + continue; + + if (len % R92C_FW_PAGE_SIZE != 0) { + error = rtwn_fw_loadpage(sc, page, curr_ptr, + len % R92C_FW_PAGE_SIZE); + if (error != 0) + continue; + } + + /* Wait for checksum report. */ + error = rtwn_fw_checksum_report(sc); + if (error == 0) + break; + } + if (ntries == 3) { + device_printf(sc->sc_dev, + "%s: failed to upload firmware %s (error %d)\n", + __func__, sc->fwname, error); + goto fail; + } + + /* Disable firmware download. */ + rtwn_fw_download_enable(sc, 0); + + rtwn_setbits_4(sc, R92C_MCUFWDL, R92C_MCUFWDL_WINTINI_RDY, + R92C_MCUFWDL_RDY); + + rtwn_fw_reset(sc, RTWN_FW_RESET_CHECKSUM); + + /* Wait for firmware readiness. */ + for (ntries = 0; ntries < 20; ntries++) { + if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY) + break; + rtwn_delay(sc, 10000); + } + if (ntries == 20) { + device_printf(sc->sc_dev, + "timeout waiting for firmware readiness\n"); + error = ETIMEDOUT; + goto fail; + } +fail: + firmware_put(fw, FIRMWARE_UNLOAD); + return (error); +} +#endif diff --git a/sys/dev/rtwn/if_rtwn_fw.h b/sys/dev/rtwn/if_rtwn_fw.h new file mode 100644 index 000000000000..41e84ee82f17 --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_fw.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef IF_RTWN_FW_H +#define IF_RTWN_FW_H + +/* + * Firmware base address. + */ +#define R92C_FW_START_ADDR 0x1000 +#define R92C_FW_PAGE_SIZE 4096 +#define R92C_FW_MAX_BLOCK_SIZE 196 + +/* + * Firmware image header. + */ +struct r92c_fw_hdr { + /* QWORD0 */ + uint16_t signature; + uint8_t category; + uint8_t function; + uint16_t version; + uint16_t subversion; + /* QWORD1 */ + uint8_t month; + uint8_t date; + uint8_t hour; + uint8_t minute; + uint16_t ramcodesize; + uint16_t reserved2; + /* QWORD2 */ + uint32_t svnidx; + uint32_t reserved3; + /* QWORD3 */ + uint32_t reserved4; + uint32_t reserved5; +} __packed; + + +int rtwn_load_firmware(struct rtwn_softc *); + +#endif /* IF_RTWN_FW_H */ diff --git a/sys/dev/rtwn/if_rtwn_nop.h b/sys/dev/rtwn/if_rtwn_nop.h new file mode 100644 index 000000000000..2b8b3e1a067a --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_nop.h @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_NOP_H +#define IF_RTWN_NOP_H + +static __inline void +rtwn_nop_softc(struct rtwn_softc *sc) +{ +} + +static __inline int +rtwn_nop_int_softc(struct rtwn_softc *sc) +{ + return (0); +} + +static __inline int +rtwn_nop_int_softc_mbuf(struct rtwn_softc *sc, struct mbuf *m) +{ + return (0); +} + +static __inline void +rtwn_nop_softc_int(struct rtwn_softc *sc, int id) +{ +} + +static __inline void +rtwn_nop_softc_uint32(struct rtwn_softc *sc, uint32_t reg) +{ +} + +static __inline void +rtwn_nop_softc_chan(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ +} + +static __inline void +rtwn_nop_softc_vap(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ +} + +static __inline void +rtwn_nop_softc_uint8_int(struct rtwn_softc *sc, uint8_t *buf, int len) +{ +} + +static __inline void +rtwn_nop_void_int(void *buf, int is5ghz) +{ +} + +#endif /* IF_RTWN_NOP_H */ diff --git a/sys/dev/rtwn/if_rtwn_ridx.h b/sys/dev/rtwn/if_rtwn_ridx.h new file mode 100644 index 000000000000..eef438984f56 --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_ridx.h @@ -0,0 +1,94 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_RIDX_H +#define IF_RTWN_RIDX_H + +/* HW rate indices. */ +#define RTWN_RIDX_CCK1 0 +#define RTWN_RIDX_CCK2 1 +#define RTWN_RIDX_CCK55 2 +#define RTWN_RIDX_CCK11 3 +#define RTWN_RIDX_OFDM6 4 +#define RTWN_RIDX_OFDM9 5 +#define RTWN_RIDX_OFDM12 6 +#define RTWN_RIDX_OFDM18 7 +#define RTWN_RIDX_OFDM24 8 +#define RTWN_RIDX_OFDM36 9 +#define RTWN_RIDX_OFDM48 10 +#define RTWN_RIDX_OFDM54 11 +#define RTWN_RIDX_MCS(i) (12 + (i)) + +#define RTWN_RIDX_COUNT 28 +#define RTWN_RIDX_UNKNOWN (uint8_t)-1 + +#define RTWN_RATE_IS_CCK(rate) ((rate) <= RTWN_RIDX_CCK11) +#define RTWN_RATE_IS_OFDM(rate) \ + ((rate) >= RTWN_RIDX_OFDM6 && (rate) != RTWN_RIDX_UNKNOWN) + + +static const uint8_t ridx2rate[] = + { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; + +static __inline uint8_t +rate2ridx(uint8_t rate) +{ + if (rate & IEEE80211_RATE_MCS) { + /* 11n rates start at idx 12 */ + return ((rate & 0xf) + 12); + } + switch (rate) { + /* 11g */ + case 12: return 4; + case 18: return 5; + case 24: return 6; + case 36: return 7; + case 48: return 8; + case 72: return 9; + case 96: return 10; + case 108: return 11; + /* 11b */ + case 2: return 0; + case 4: return 1; + case 11: return 2; + case 22: return 3; + default: return RTWN_RIDX_UNKNOWN; + } +} + +/* XXX move to net80211 */ +static __inline__ uint8_t +rtwn_ctl_mcsrate(const struct ieee80211_rate_table *rt, uint8_t ridx) +{ + uint8_t cix, rate; + + /* Check if we are using MCS rate. */ + KASSERT(ridx >= RTWN_RIDX_MCS(0) && ridx != RTWN_RIDX_UNKNOWN, + ("bad mcs rate index %d", ridx)); + + rate = (ridx - RTWN_RIDX_MCS(0)) | IEEE80211_RATE_MCS; + cix = rt->info[rt->rateCodeToIndex[rate]].ctlRateIndex; + KASSERT(cix != (uint8_t)-1, ("rate %d (%d) has no info", rate, ridx)); + return rt->info[cix].dot11Rate; +} + +#endif /* IF_RTWN_RIDX_H */ diff --git a/sys/dev/rtwn/if_rtwn_rx.c b/sys/dev/rtwn/if_rtwn_rx.c new file mode 100644 index 000000000000..6ee05a3ff4a1 --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_rx.c @@ -0,0 +1,452 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + + +void +rtwn_get_rates(struct rtwn_softc *sc, const struct ieee80211_rateset *rs, + const struct ieee80211_htrateset *rs_ht, uint32_t *rates_p, + int *maxrate_p, int basic_rates) +{ + uint32_t rates; + uint8_t ridx; + int i, maxrate; + + /* Get rates mask. */ + rates = 0; + maxrate = 0; + + /* This is for 11bg */ + for (i = 0; i < rs->rs_nrates; i++) { + /* Convert 802.11 rate to HW rate index. */ + ridx = rate2ridx(IEEE80211_RV(rs->rs_rates[i])); + if (ridx == RTWN_RIDX_UNKNOWN) /* Unknown rate, skip. */ + continue; + if (((rs->rs_rates[i] & IEEE80211_RATE_BASIC) != 0) || + !basic_rates) { + rates |= 1 << ridx; + if (ridx > maxrate) + maxrate = ridx; + } + } + + /* If we're doing 11n, enable 11n rates */ + if (rs_ht != NULL && !basic_rates) { + for (i = 0; i < rs_ht->rs_nrates; i++) { + if ((rs_ht->rs_rates[i] & 0x7f) > 0xf) + continue; + /* 11n rates start at index 12 */ + ridx = RTWN_RIDX_MCS((rs_ht->rs_rates[i]) & 0xf); + rates |= (1 << ridx); + + /* Guard against the rate table being oddly ordered */ + if (ridx > maxrate) + maxrate = ridx; + } + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_RA, + "%s: rates 0x%08X, maxrate %d\n", __func__, rates, maxrate); + + if (rates_p != NULL) + *rates_p = rates; + if (maxrate_p != NULL) + *maxrate_p = maxrate; +} + +void +rtwn_set_basicrates(struct rtwn_softc *sc, uint32_t rates) +{ + + RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: rates 0x%08X\n", __func__, rates); + + rtwn_setbits_4(sc, R92C_RRSR, R92C_RRSR_RATE_BITMAP_M, rates); +} + +static void +rtwn_update_avgrssi(struct rtwn_softc *sc, struct rtwn_node *un, int rate) +{ + int pwdb; + + /* Convert antenna signal to percentage. */ + if (un->last_rssi <= -100 || un->last_rssi >= 20) + pwdb = 0; + else if (un->last_rssi >= 0) + pwdb = 100; + else + pwdb = 100 + un->last_rssi; + if (RTWN_RATE_IS_CCK(rate)) { + /* CCK gain is smaller than OFDM/MCS gain. */ + pwdb += 6; + if (pwdb > 100) + pwdb = 100; + if (pwdb <= 14) + pwdb -= 4; + else if (pwdb <= 26) + pwdb -= 8; + else if (pwdb <= 34) + pwdb -= 6; + else if (pwdb <= 42) + pwdb -= 2; + } + + if (un->avg_pwdb == -1) /* Init. */ + un->avg_pwdb = pwdb; + else if (un->avg_pwdb < pwdb) + un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20) + 1; + else + un->avg_pwdb = ((un->avg_pwdb * 19 + pwdb) / 20); + + RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, + "MACID %d, PWDB %d, EMA %d\n", un->id, pwdb, un->avg_pwdb); +} + +static int8_t +rtwn_get_rssi(struct rtwn_softc *sc, int rate, void *physt) +{ + int8_t rssi; + + if (RTWN_RATE_IS_CCK(rate)) + rssi = rtwn_get_rssi_cck(sc, physt); + else /* OFDM/HT. */ + rssi = rtwn_get_rssi_ofdm(sc, physt); + + return (rssi); +} + +static uint32_t +rtwn_get_tsf_low(struct rtwn_softc *sc, int id) +{ + return (rtwn_read_4(sc, R92C_TSFTR(id))); +} + +static uint32_t +rtwn_get_tsf_high(struct rtwn_softc *sc, int id) +{ + return (rtwn_read_4(sc, R92C_TSFTR(id) + 4)); +} + +static void +rtwn_get_tsf(struct rtwn_softc *sc, uint64_t *buf, int id) +{ + /* NB: we cannot read it at once. */ + *buf = rtwn_get_tsf_high(sc, id); + *buf <<= 32; + *buf += rtwn_get_tsf_low(sc, id); +} + +struct ieee80211_node * +rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc, + int8_t *rssi) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni; + struct ieee80211_frame_min *wh; + struct rtwn_node *un; + struct r92c_rx_stat *stat; + uint32_t rxdw0, rxdw3; + int cipher, infosz, pktlen, rate, shift; + + stat = desc; + rxdw0 = le32toh(stat->rxdw0); + rxdw3 = le32toh(stat->rxdw3); + + cipher = MS(rxdw0, R92C_RXDW0_CIPHER); + infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; + pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); + shift = MS(rxdw0, R92C_RXDW0_SHIFT); + rate = MS(rxdw3, R92C_RXDW3_RATE); + + wh = (struct ieee80211_frame_min *)(mtodo(m, shift + infosz)); + if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && + cipher != R92C_CAM_ALGO_NONE) + m->m_flags |= M_WEP; + + if (pktlen >= sizeof(*wh)) + ni = ieee80211_find_rxnode(ic, wh); + else + ni = NULL; + un = RTWN_NODE(ni); + + /* Get RSSI from PHY status descriptor if present. */ + if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { + *rssi = rtwn_get_rssi(sc, rate, mtod(m, void *)); + RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, "%s: rssi %d, ridx %d\n", + __func__, *rssi, rate); + + sc->last_rssi = *rssi; + if (un != NULL) { + un->last_rssi = *rssi; + + /* Update our average RSSI. */ + rtwn_update_avgrssi(sc, un, rate); + } + } else + *rssi = (un != NULL) ? un->last_rssi : sc->last_rssi; + + if (ieee80211_radiotap_active(ic)) { + struct rtwn_rx_radiotap_header *tap = &sc->sc_rxtap; + int id = RTWN_VAP_ID_INVALID; + + if (ni != NULL) + id = RTWN_VAP(ni->ni_vap)->id; + if (id == RTWN_VAP_ID_INVALID) + id = 0; + + tap->wr_flags = rtwn_rx_radiotap_flags(sc, desc); + tap->wr_tsft = rtwn_get_tsf_high(sc, id); + if (le32toh(stat->tsf_low) > rtwn_get_tsf_low(sc, id)) + tap->wr_tsft--; + tap->wr_tsft = (uint64_t)htole32(tap->wr_tsft) << 32; + tap->wr_tsft += stat->tsf_low; + + /* XXX 20/40? */ + + /* Map HW rate index to 802.11 rate. */ + if (rate < RTWN_RIDX_MCS(0)) + tap->wr_rate = ridx2rate[rate]; + else /* MCS0~15. */ + tap->wr_rate = IEEE80211_RATE_MCS | (rate - 12); + + tap->wr_dbm_antsignal = *rssi; + tap->wr_dbm_antnoise = RTWN_NOISE_FLOOR; + } + + /* Drop PHY descriptor. */ + m_adj(m, infosz + shift); + + return (ni); +} + +void +rtwn_adhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, + const struct ieee80211_rx_stats *rxs, + int rssi, int nf) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct rtwn_softc *sc = vap->iv_ic->ic_softc; + struct rtwn_vap *uvp = RTWN_VAP(vap); + uint64_t ni_tstamp, curr_tstamp; + + uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf); + + if (vap->iv_state == IEEE80211_S_RUN && + (subtype == IEEE80211_FC0_SUBTYPE_BEACON || + subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) { + ni_tstamp = le64toh(ni->ni_tstamp.tsf); + RTWN_LOCK(sc); + rtwn_get_tsf(sc, &curr_tstamp, uvp->id); + RTWN_UNLOCK(sc); + + if (ni_tstamp >= curr_tstamp) + (void) ieee80211_ibss_merge(ni); + } +} + +static uint8_t +rtwn_get_multi_pos(const uint8_t maddr[]) +{ + uint64_t mask = 0x00004d101df481b4; + uint8_t pos = 0x27; /* initial value */ + int i, j; + + for (i = 0; i < IEEE80211_ADDR_LEN; i++) + for (j = (i == 0) ? 1 : 0; j < 8; j++) + if ((maddr[i] >> j) & 1) + pos ^= (mask >> (i * 8 + j - 1)); + + pos &= 0x3f; + + return (pos); +} + +void +rtwn_set_multi(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint32_t mfilt[2]; + + RTWN_ASSERT_LOCKED(sc); + + /* general structure was copied from ath(4). */ + if (ic->ic_allmulti == 0) { + struct ieee80211vap *vap; + struct ifnet *ifp; + struct ifmultiaddr *ifma; + + /* + * Merge multicast addresses to form the hardware filter. + */ + mfilt[0] = mfilt[1] = 0; + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + ifp = vap->iv_ifp; + if_maddr_rlock(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + caddr_t dl; + uint8_t pos; + + dl = LLADDR((struct sockaddr_dl *) + ifma->ifma_addr); + pos = rtwn_get_multi_pos(dl); + + mfilt[pos / 32] |= (1 << (pos % 32)); + } + if_maddr_runlock(ifp); + } + } else + mfilt[0] = mfilt[1] = ~0; + + + rtwn_write_4(sc, R92C_MAR + 0, mfilt[0]); + rtwn_write_4(sc, R92C_MAR + 4, mfilt[1]); + + RTWN_DPRINTF(sc, RTWN_DEBUG_STATE, "%s: MC filter %08x:%08x\n", + __func__, mfilt[0], mfilt[1]); +} + +static void +rtwn_rxfilter_update_mgt(struct rtwn_softc *sc) +{ + uint16_t filter; + + filter = 0x7f3f; + if (sc->bcn_vaps == 0) { /* STA and/or MONITOR mode vaps */ + filter &= ~( + R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) | + R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) | + R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ)); + } + if (sc->ap_vaps == sc->nvaps - sc->mon_vaps) { /* AP vaps only */ + filter &= ~( + R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) | + R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP)); + } + rtwn_write_2(sc, R92C_RXFLTMAP0, filter); +} + +void +rtwn_rxfilter_update(struct rtwn_softc *sc) +{ + + RTWN_ASSERT_LOCKED(sc); + + /* Filter for management frames. */ + rtwn_rxfilter_update_mgt(sc); + + /* Update Rx filter. */ + rtwn_set_promisc(sc); +} + +void +rtwn_rxfilter_init(struct rtwn_softc *sc) +{ + uint32_t rcr; + + RTWN_ASSERT_LOCKED(sc); + + /* Setup multicast filter. */ + rtwn_set_multi(sc); + + /* Reject all control frames. */ + rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000); + + /* Reject all data frames. */ + rtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000); + + rcr = sc->rcr; + rcr |= R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM | + R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS | + R92C_RCR_APP_ICV | R92C_RCR_APP_MIC; + + /* Set Rx filter. */ + rtwn_write_4(sc, R92C_RCR, rcr); + + /* Update dynamic Rx filter parts. */ + rtwn_rxfilter_update(sc); +} + +void +rtwn_set_rx_bssid_all(struct rtwn_softc *sc, int enable) +{ + if (enable) + rtwn_setbits_4(sc, R92C_RCR, R92C_RCR_CBSSID_BCN, 0); + else + rtwn_setbits_4(sc, R92C_RCR, 0, R92C_RCR_CBSSID_BCN); +} + +void +rtwn_set_promisc(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint32_t mask1, mask2; + + RTWN_ASSERT_LOCKED(sc); + + mask1 = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP; + mask2 = R92C_RCR_APM; + + if (sc->vaps_running != 0) { + if (sc->bcn_vaps == 0) + mask2 |= R92C_RCR_CBSSID_BCN; + if (sc->ap_vaps == 0) + mask2 |= R92C_RCR_CBSSID_DATA; + } + + if (ic->ic_promisc == 0 && sc->mon_vaps == 0) + rtwn_setbits_4(sc, R92C_RCR, mask1, mask2); + else + rtwn_setbits_4(sc, R92C_RCR, mask2, mask1); +} diff --git a/sys/dev/rtwn/if_rtwn_rx.h b/sys/dev/rtwn/if_rtwn_rx.h new file mode 100644 index 000000000000..1f2031cf889a --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_rx.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_RX_H +#define IF_RTWN_RX_H + +#define RTWN_NOISE_FLOOR -95 + + +void rtwn_get_rates(struct rtwn_softc *, const struct ieee80211_rateset *, + const struct ieee80211_htrateset *, uint32_t *, int *, int); +void rtwn_set_basicrates(struct rtwn_softc *, uint32_t); +struct ieee80211_node * rtwn_rx_common(struct rtwn_softc *, struct mbuf *, + void *, int8_t *); +void rtwn_adhoc_recv_mgmt(struct ieee80211_node *, struct mbuf *, int, + const struct ieee80211_rx_stats *, int, int); +void rtwn_set_multi(struct rtwn_softc *); +void rtwn_rxfilter_update(struct rtwn_softc *); +void rtwn_rxfilter_init(struct rtwn_softc *); +void rtwn_set_rx_bssid_all(struct rtwn_softc *, int); +void rtwn_set_promisc(struct rtwn_softc *); + +#endif /* IF_RTWN_RX_H */ diff --git a/sys/dev/rtwn/if_rtwn_task.c b/sys/dev/rtwn/if_rtwn_task.c new file mode 100644 index 000000000000..87f695f1020c --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_task.c @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + + +static void +rtwn_cmdq_cb(void *arg, int pending) +{ + struct rtwn_softc *sc = arg; + struct rtwn_cmdq *item; + + /* + * Device must be powered on (via rtwn_power_on()) + * before any command may be sent. + */ + RTWN_LOCK(sc); + if (!(sc->sc_flags & RTWN_RUNNING)) { + RTWN_UNLOCK(sc); + return; + } + + RTWN_CMDQ_LOCK(sc); + while (sc->cmdq[sc->cmdq_first].func != NULL) { + item = &sc->cmdq[sc->cmdq_first]; + sc->cmdq_first = (sc->cmdq_first + 1) % RTWN_CMDQ_SIZE; + RTWN_CMDQ_UNLOCK(sc); + + item->func(sc, &item->data); + + RTWN_CMDQ_LOCK(sc); + memset(item, 0, sizeof (*item)); + } + RTWN_CMDQ_UNLOCK(sc); + RTWN_UNLOCK(sc); +} + +void +rtwn_cmdq_init(struct rtwn_softc *sc) +{ + RTWN_CMDQ_LOCK_INIT(sc); + TASK_INIT(&sc->cmdq_task, 0, rtwn_cmdq_cb, sc); +} + +void +rtwn_cmdq_destroy(struct rtwn_softc *sc) +{ + if (RTWN_CMDQ_LOCK_INITIALIZED(sc)) + RTWN_CMDQ_LOCK_DESTROY(sc); +} + +int +rtwn_cmd_sleepable(struct rtwn_softc *sc, const void *ptr, size_t len, + CMD_FUNC_PROTO) +{ + struct ieee80211com *ic = &sc->sc_ic; + + KASSERT(len <= sizeof(union sec_param), ("buffer overflow")); + + RTWN_CMDQ_LOCK(sc); + if (sc->sc_detached) { + RTWN_CMDQ_UNLOCK(sc); + return (ESHUTDOWN); + } + + if (sc->cmdq[sc->cmdq_last].func != NULL) { + device_printf(sc->sc_dev, "%s: cmdq overflow\n", __func__); + RTWN_CMDQ_UNLOCK(sc); + + return (EAGAIN); + } + + if (ptr != NULL) + memcpy(&sc->cmdq[sc->cmdq_last].data, ptr, len); + sc->cmdq[sc->cmdq_last].func = func; + sc->cmdq_last = (sc->cmdq_last + 1) % RTWN_CMDQ_SIZE; + RTWN_CMDQ_UNLOCK(sc); + + ieee80211_runtask(ic, &sc->cmdq_task); + + return (0); +} diff --git a/sys/dev/rtwn/if_rtwn_task.h b/sys/dev/rtwn/if_rtwn_task.h new file mode 100644 index 000000000000..a9d60c209ccf --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_task.h @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_TASK_H +#define IF_RTWN_TASK_H + +void rtwn_cmdq_init(struct rtwn_softc *); +void rtwn_cmdq_destroy(struct rtwn_softc *); +int rtwn_cmd_sleepable(struct rtwn_softc *, const void *, size_t, + CMD_FUNC_PROTO); + +#endif /* IF_RTWN_TASK_H */ diff --git a/sys/dev/rtwn/if_rtwn_tx.c b/sys/dev/rtwn/if_rtwn_tx.c new file mode 100644 index 000000000000..90cb3bcc3edd --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_tx.c @@ -0,0 +1,346 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#ifdef IEEE80211_SUPPORT_SUPERG +#include +#endif + +#include +#include + +#include +#include +#include +#include + + +void +rtwn_drain_mbufq(struct rtwn_softc *sc) +{ + struct mbuf *m; + struct ieee80211_node *ni; + RTWN_ASSERT_LOCKED(sc); + while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + m->m_pkthdr.rcvif = NULL; + ieee80211_free_node(ni); + m_freem(m); + } +} + +#ifdef IEEE80211_SUPPORT_SUPERG +void +rtwn_ff_flush_all(struct rtwn_softc *sc, union sec_param *data) +{ + struct ieee80211com *ic = &sc->sc_ic; + + RTWN_UNLOCK(sc); + ieee80211_ff_flush_all(ic); + RTWN_LOCK(sc); +} +#endif + +static uint8_t +rtwn_get_cipher(u_int ic_cipher) +{ + uint8_t cipher; + + switch (ic_cipher) { + case IEEE80211_CIPHER_NONE: + cipher = RTWN_TXDW1_CIPHER_NONE; + break; + case IEEE80211_CIPHER_WEP: + case IEEE80211_CIPHER_TKIP: + cipher = RTWN_TXDW1_CIPHER_RC4; + break; + case IEEE80211_CIPHER_AES_CCM: + cipher = RTWN_TXDW1_CIPHER_AES; + break; + default: + KASSERT(0, ("%s: unknown cipher %d\n", __func__, + ic_cipher)); + return (RTWN_TXDW1_CIPHER_SM4); + } + + return (cipher); +} + +static int +rtwn_tx_data(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m) +{ + const struct ieee80211_txparam *tp; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_key *k = NULL; + struct ieee80211_channel *chan; + struct ieee80211_frame *wh; + struct rtwn_tx_desc_common *txd; + struct rtwn_tx_buf buf; + uint8_t rate, ridx, type; + u_int cipher; + int ismcast, maxretry; + + RTWN_ASSERT_LOCKED(sc); + + wh = mtod(m, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + + chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? + ni->ni_chan : ic->ic_curchan; + tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; + maxretry = tp->maxretry; + + /* Choose a TX rate index. */ + if (type == IEEE80211_FC0_TYPE_MGT) + rate = tp->mgmtrate; + else if (ismcast) + rate = tp->mcastrate; + else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) + rate = tp->ucastrate; + else if (m->m_flags & M_EAPOL) + rate = tp->mgmtrate; + else { + if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { + /* XXX pass pktlen */ + (void) ieee80211_ratectl_rate(ni, NULL, 0); + rate = ni->ni_txrate; + } else { + if (ni->ni_flags & IEEE80211_NODE_HT) + rate = IEEE80211_RATE_MCS | 0x4; /* MCS4 */ + else if (ic->ic_curmode != IEEE80211_MODE_11B) + rate = ridx2rate[RTWN_RIDX_OFDM36]; + else + rate = ridx2rate[RTWN_RIDX_CCK55]; + } + } + + ridx = rate2ridx(rate); + + cipher = IEEE80211_CIPHER_NONE; + if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { + k = ieee80211_crypto_encap(ni, m); + if (k == NULL) { + device_printf(sc->sc_dev, + "ieee80211_crypto_encap returns NULL.\n"); + return (ENOBUFS); + } + if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) + cipher = k->wk_cipher->ic_cipher; + + /* in case packet header moved, reset pointer */ + wh = mtod(m, struct ieee80211_frame *); + } + + /* Fill Tx descriptor. */ + txd = (struct rtwn_tx_desc_common *)&buf; + memset(txd, 0, sc->txdesc_len); + txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher))); + + rtwn_fill_tx_desc(sc, ni, m, txd, ridx, maxretry); + + if (ieee80211_radiotap_active_vap(vap)) { + struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; + + tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd); + if (k != NULL) + tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; + ieee80211_radiotap_tx(vap, m); + } + + return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0)); +} + +static int +rtwn_tx_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, const struct ieee80211_bpf_params *params) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_key *k = NULL; + struct ieee80211_frame *wh; + struct rtwn_tx_desc_common *txd; + struct rtwn_tx_buf buf; + uint8_t type; + u_int cipher; + + /* Encrypt the frame if need be. */ + cipher = IEEE80211_CIPHER_NONE; + if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { + /* Retrieve key for TX. */ + k = ieee80211_crypto_encap(ni, m); + if (k == NULL) { + device_printf(sc->sc_dev, + "ieee80211_crypto_encap returns NULL.\n"); + return (ENOBUFS); + } + if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) + cipher = k->wk_cipher->ic_cipher; + } + + wh = mtod(m, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + + /* Fill Tx descriptor. */ + txd = (struct rtwn_tx_desc_common *)&buf; + memset(txd, 0, sc->txdesc_len); + txd->txdw1 = htole32(SM(RTWN_TXDW1_CIPHER, rtwn_get_cipher(cipher))); + + rtwn_fill_tx_desc_raw(sc, ni, m, txd, params); + + if (ieee80211_radiotap_active_vap(vap)) { + struct rtwn_tx_radiotap_header *tap = &sc->sc_txtap; + + tap->wt_flags = rtwn_tx_radiotap_flags(sc, txd); + if (k != NULL) + tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; + ieee80211_radiotap_tx(vap, m); + } + + return (rtwn_tx_start(sc, ni, m, (uint8_t *)txd, type, 0)); +} + +int +rtwn_transmit(struct ieee80211com *ic, struct mbuf *m) +{ + struct rtwn_softc *sc = ic->ic_softc; + int error; + + RTWN_LOCK(sc); + if ((sc->sc_flags & RTWN_RUNNING) == 0) { + RTWN_UNLOCK(sc); + return (ENXIO); + } + error = mbufq_enqueue(&sc->sc_snd, m); + if (error) { + RTWN_UNLOCK(sc); + return (error); + } + rtwn_start(sc); + RTWN_UNLOCK(sc); + + return (0); +} + +void +rtwn_start(struct rtwn_softc *sc) +{ + struct ieee80211_node *ni; + struct mbuf *m; + + RTWN_ASSERT_LOCKED(sc); + while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { + if (sc->qfullmsk != 0) { + mbufq_prepend(&sc->sc_snd, m); + break; + } + ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; + m->m_pkthdr.rcvif = NULL; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: called; m %p, ni %p\n", __func__, m, ni); + + if (rtwn_tx_data(sc, ni, m) != 0) { + if_inc_counter(ni->ni_vap->iv_ifp, + IFCOUNTER_OERRORS, 1); + m_freem(m); +#ifdef D4054 + ieee80211_tx_watchdog_refresh(ni->ni_ic, -1, 0); +#endif + ieee80211_free_node(ni); + break; + } + } +} + +int +rtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, + const struct ieee80211_bpf_params *params) +{ + struct ieee80211com *ic = ni->ni_ic; + struct rtwn_softc *sc = ic->ic_softc; + int error; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: called; m %p, ni %p\n", + __func__, m, ni); + + /* prevent management frames from being sent if we're not ready */ + RTWN_LOCK(sc); + if (!(sc->sc_flags & RTWN_RUNNING)) { + error = ENETDOWN; + goto end; + } + + if (sc->qfullmsk != 0) { + error = ENOBUFS; + goto end; + } + + if (params == NULL) { + /* + * Legacy path; interpret frame contents to decide + * precisely how to send the frame. + */ + error = rtwn_tx_data(sc, ni, m); + } else { + /* + * Caller supplied explicit parameters to use in + * sending the frame. + */ + error = rtwn_tx_raw(sc, ni, m, params); + } + +end: + if (error != 0) { + if (m->m_flags & M_TXCB) + ieee80211_process_callback(ni, m, 1); + m_freem(m); + } + + RTWN_UNLOCK(sc); + + return (error); +} diff --git a/sys/dev/rtwn/if_rtwn_tx.h b/sys/dev/rtwn/if_rtwn_tx.h new file mode 100644 index 000000000000..d38a8550f2c4 --- /dev/null +++ b/sys/dev/rtwn/if_rtwn_tx.h @@ -0,0 +1,29 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_TX_H +#define IF_RTWN_TX_H + +void rtwn_drain_mbufq(struct rtwn_softc *); +void rtwn_ff_flush_all(struct rtwn_softc *, union sec_param *); +int rtwn_transmit(struct ieee80211com *, struct mbuf *); +void rtwn_start(struct rtwn_softc *); +int rtwn_raw_xmit(struct ieee80211_node *, struct mbuf *, + const struct ieee80211_bpf_params *); + +#endif /* IF_RTWN_TX_H */ diff --git a/sys/dev/rtwn/if_rtwnreg.h b/sys/dev/rtwn/if_rtwnreg.h index ae209378bd4e..9dc830a2be0a 100644 --- a/sys/dev/rtwn/if_rtwnreg.h +++ b/sys/dev/rtwn/if_rtwnreg.h @@ -1,8 +1,6 @@ -/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ - /*- * Copyright (c) 2010 Damien Bergamini - * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,885 +13,40 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ * $FreeBSD$ */ -#define R92C_MAX_CHAINS 2 - -/* Maximum number of output pipes is 3. */ -#define R92C_MAX_EPOUT 3 - -#define R92C_MAX_TX_PWR 0x3f - -#define R92C_PUBQ_NPAGES 176 -#define R92C_HPQ_NPAGES 41 -#define R92C_LPQ_NPAGES 28 -#define R92C_TXPKTBUF_COUNT 256 -#define R92C_TX_PAGE_COUNT \ - (R92C_PUBQ_NPAGES + R92C_HPQ_NPAGES + R92C_LPQ_NPAGES) -#define R92C_TX_PAGE_BOUNDARY (R92C_TX_PAGE_COUNT + 1) - -#define R92C_H2C_NBOX 4 - -/* USB Requests. */ -#define R92C_REQ_REGS 0x05 - -/* - * MAC registers. - */ -/* System Configuration. */ -#define R92C_SYS_ISO_CTRL 0x000 -#define R92C_SYS_FUNC_EN 0x002 -#define R92C_APS_FSMCO 0x004 -#define R92C_SYS_CLKR 0x008 -#define R92C_AFE_MISC 0x010 -#define R92C_SPS0_CTRL 0x011 -#define R92C_SPS_OCP_CFG 0x018 -#define R92C_RSV_CTRL 0x01c -#define R92C_RF_CTRL 0x01f -#define R92C_LDOA15_CTRL 0x020 -#define R92C_LDOV12D_CTRL 0x021 -#define R92C_LDOHCI12_CTRL 0x022 -#define R92C_LPLDO_CTRL 0x023 -#define R92C_AFE_XTAL_CTRL 0x024 -#define R92C_AFE_PLL_CTRL 0x028 -#define R92C_EFUSE_CTRL 0x030 -#define R92C_EFUSE_TEST 0x034 -#define R92C_PWR_DATA 0x038 -#define R92C_CAL_TIMER 0x03c -#define R92C_ACLK_MON 0x03e -#define R92C_GPIO_MUXCFG 0x040 -#define R92C_GPIO_IO_SEL 0x042 -#define R92C_MAC_PINMUX_CFG 0x043 -#define R92C_GPIO_PIN_CTRL 0x044 -#define R92C_GPIO_INTM 0x048 -#define R92C_LEDCFG0 0x04c -#define R92C_LEDCFG1 0x04d -#define R92C_LEDCFG2 0x04e -#define R92C_LEDCFG3 0x04f -#define R92C_FSIMR 0x050 -#define R92C_FSISR 0x054 -#define R92C_HSIMR 0x058 -#define R92C_HSISR 0x05c -#define R92C_MCUFWDL 0x080 -#define R92C_HMEBOX_EXT(idx) (0x088 + (idx) * 2) -#define R92C_BIST_SCAN 0x0d0 -#define R92C_BIST_RPT 0x0d4 -#define R92C_BIST_ROM_RPT 0x0d8 -#define R92C_USB_SIE_INTF 0x0e0 -#define R92C_PCIE_MIO_INTF 0x0e4 -#define R92C_PCIE_MIO_INTD 0x0e8 -#define R92C_HPON_FSM 0x0ec -#define R92C_SYS_CFG 0x0f0 -/* MAC General Configuration. */ -#define R92C_CR 0x100 -#define R92C_PBP 0x104 -#define R92C_TRXDMA_CTRL 0x10c -#define R92C_TRXFF_BNDY 0x114 -#define R92C_TRXFF_STATUS 0x118 -#define R92C_RXFF_PTR 0x11c -#define R92C_HIMR 0x120 -#define R92C_HISR 0x124 -#define R92C_HIMRE 0x128 -#define R92C_HISRE 0x12c -#define R92C_CPWM 0x12f -#define R92C_FWIMR 0x130 -#define R92C_FWISR 0x134 -#define R92C_PKTBUF_DBG_CTRL 0x140 -#define R92C_PKTBUF_DBG_DATA_L 0x144 -#define R92C_PKTBUF_DBG_DATA_H 0x148 -#define R92C_TC0_CTRL(i) (0x150 + (i) * 4) -#define R92C_TCUNIT_BASE 0x164 -#define R92C_MBIST_START 0x174 -#define R92C_MBIST_DONE 0x178 -#define R92C_MBIST_FAIL 0x17c -#define R92C_C2HEVT_MSG_NORMAL 0x1a0 -#define R92C_C2HEVT_MSG_TEST 0x1b8 -#define R92C_C2HEVT_CLEAR 0x1bf -#define R92C_MCUTST_1 0x1c0 -#define R92C_FMETHR 0x1c8 -#define R92C_HMETFR 0x1cc -#define R92C_HMEBOX(idx) (0x1d0 + (idx) * 4) -#define R92C_LLT_INIT 0x1e0 -#define R92C_BB_ACCESS_CTRL 0x1e8 -#define R92C_BB_ACCESS_DATA 0x1ec -/* Tx DMA Configuration. */ -#define R92C_RQPN 0x200 -#define R92C_FIFOPAGE 0x204 -#define R92C_TDECTRL 0x208 -#define R92C_TXDMA_OFFSET_CHK 0x20c -#define R92C_TXDMA_STATUS 0x210 -#define R92C_RQPN_NPQ 0x214 -/* Rx DMA Configuration. */ -#define R92C_RXDMA_AGG_PG_TH 0x280 -#define R92C_RXPKT_NUM 0x284 -#define R92C_RXDMA_STATUS 0x288 - -#define R92C_PCIE_CTRL_REG 0x300 -#define R92C_INT_MIG 0x304 -#define R92C_BCNQ_DESA 0x308 -#define R92C_HQ_DESA 0x310 -#define R92C_MGQ_DESA 0x318 -#define R92C_VOQ_DESA 0x320 -#define R92C_VIQ_DESA 0x328 -#define R92C_BEQ_DESA 0x330 -#define R92C_BKQ_DESA 0x338 -#define R92C_RX_DESA 0x340 -#define R92C_DBI 0x348 -#define R92C_MDIO 0x354 -#define R92C_DBG_SEL 0x360 -#define R92C_PCIE_HRPWM 0x361 -#define R92C_PCIE_HCPWM 0x363 -#define R92C_UART_CTRL 0x364 -#define R92C_UART_TX_DES 0x370 -#define R92C_UART_RX_DES 0x378 - -#define R92C_VOQ_INFORMATION 0x0400 -#define R92C_VIQ_INFORMATION 0x0404 -#define R92C_BEQ_INFORMATION 0x0408 -#define R92C_BKQ_INFORMATION 0x040C -#define R92C_MGQ_INFORMATION 0x0410 -#define R92C_HGQ_INFORMATION 0x0414 -#define R92C_BCNQ_INFORMATION 0x0418 -#define R92C_CPU_MGQ_INFORMATION 0x041C - -/* Protocol Configuration. */ -#define R92C_FWHW_TXQ_CTRL 0x420 -#define R92C_HWSEQ_CTRL 0x423 -#define R92C_TXPKTBUF_BCNQ_BDNY 0x424 -#define R92C_TXPKTBUF_MGQ_BDNY 0x425 -#define R92C_SPEC_SIFS 0x428 -#define R92C_RL 0x42a -#define R92C_DARFRC 0x430 -#define R92C_RARFRC 0x438 -#define R92C_RRSR 0x440 -#define R92C_ARFR(i) (0x444 + (i) * 4) -#define R92C_AGGLEN_LMT 0x458 -#define R92C_AMPDU_MIN_SPACE 0x45c -#define R92C_TXPKTBUF_WMAC_LBK_BF_HD 0x45d -#define R92C_FAST_EDCA_CTRL 0x460 -#define R92C_RD_RESP_PKT_TH 0x463 -#define R92C_INIRTS_RATE_SEL 0x480 -#define R92C_INIDATA_RATE_SEL(macid) (0x484 + (macid)) -/* EDCA Configuration. */ -#define R92C_EDCA_VO_PARAM 0x500 -#define R92C_EDCA_VI_PARAM 0x504 -#define R92C_EDCA_BE_PARAM 0x508 -#define R92C_EDCA_BK_PARAM 0x50c -#define R92C_BCNTCFG 0x510 -#define R92C_PIFS 0x512 -#define R92C_RDG_PIFS 0x513 -#define R92C_SIFS_CCK 0x514 -#define R92C_SIFS_OFDM 0x516 -#define R92C_AGGR_BREAK_TIME 0x51a -#define R92C_SLOT 0x51b -#define R92C_TX_PTCL_CTRL 0x520 -#define R92C_TXPAUSE 0x522 -#define R92C_DIS_TXREQ_CLR 0x523 -#define R92C_RD_CTRL 0x524 -#define R92C_TBTT_PROHIBIT 0x540 -#define R92C_RD_NAV_NXT 0x544 -#define R92C_NAV_PROT_LEN 0x546 -#define R92C_BCN_CTRL 0x550 -#define R92C_USTIME_TSF 0x551 -#define R92C_MBID_NUM 0x552 -#define R92C_DUAL_TSF_RST 0x553 -#define R92C_BCN_INTERVAL 0x554 -#define R92C_DRVERLYINT 0x558 -#define R92C_BCNDMATIM 0x559 -#define R92C_ATIMWND 0x55a -#define R92C_BCN_MAX_ERR 0x55d -#define R92C_RXTSF_OFFSET_CCK 0x55e -#define R92C_RXTSF_OFFSET_OFDM 0x55f -#define R92C_TSFTR 0x560 -#define R92C_INIT_TSFTR 0x564 -#define R92C_PSTIMER 0x580 -#define R92C_TIMER0 0x584 -#define R92C_TIMER1 0x588 -#define R92C_ACMHWCTRL 0x5c0 -#define R92C_ACMRSTCTRL 0x5c1 -#define R92C_ACMAVG 0x5c2 -#define R92C_VO_ADMTIME 0x5c4 -#define R92C_VI_ADMTIME 0x5c6 -#define R92C_BE_ADMTIME 0x5c8 -#define R92C_EDCA_RANDOM_GEN 0x5cc -#define R92C_SCH_TXCMD 0x5d0 -/* WMAC Configuration. */ -#define R92C_APSD_CTRL 0x600 -#define R92C_BWOPMODE 0x603 -#define R92C_TCR 0x604 -#define R92C_RCR 0x608 -#define R92C_RX_DRVINFO_SZ 0x60f -#define R92C_MACID 0x610 -#define R92C_BSSID 0x618 -#define R92C_MAR 0x620 -#define R92C_MAC_SPEC_SIFS 0x63a -#define R92C_R2T_SIFS 0x63c -#define R92C_T2T_SIFS 0x63e -#define R92C_ACKTO 0x640 -#define R92C_CAMCMD 0x670 -#define R92C_CAMWRITE 0x674 -#define R92C_CAMREAD 0x678 -#define R92C_CAMDBG 0x67c -#define R92C_SECCFG 0x680 -#define R92C_RXFLTMAP0 0x6a0 -#define R92C_RXFLTMAP1 0x6a2 -#define R92C_RXFLTMAP2 0x6a4 - -/* Bits for R92C_SYS_ISO_CTRL. */ -#define R92C_SYS_ISO_CTRL_MD2PP 0x0001 -#define R92C_SYS_ISO_CTRL_UA2USB 0x0002 -#define R92C_SYS_ISO_CTRL_UD2CORE 0x0004 -#define R92C_SYS_ISO_CTRL_PA2PCIE 0x0008 -#define R92C_SYS_ISO_CTRL_PD2CORE 0x0010 -#define R92C_SYS_ISO_CTRL_IP2MAC 0x0020 -#define R92C_SYS_ISO_CTRL_DIOP 0x0040 -#define R92C_SYS_ISO_CTRL_DIOE 0x0080 -#define R92C_SYS_ISO_CTRL_EB2CORE 0x0100 -#define R92C_SYS_ISO_CTRL_DIOR 0x0200 -#define R92C_SYS_ISO_CTRL_PWC_EV25V 0x4000 -#define R92C_SYS_ISO_CTRL_PWC_EV12V 0x8000 - -/* Bits for R92C_SYS_FUNC_EN. */ -#define R92C_SYS_FUNC_EN_BBRSTB 0x0001 -#define R92C_SYS_FUNC_EN_BB_GLB_RST 0x0002 -#define R92C_SYS_FUNC_EN_USBA 0x0004 -#define R92C_SYS_FUNC_EN_UPLL 0x0008 -#define R92C_SYS_FUNC_EN_USBD 0x0010 -#define R92C_SYS_FUNC_EN_DIO_PCIE 0x0020 -#define R92C_SYS_FUNC_EN_PCIEA 0x0040 -#define R92C_SYS_FUNC_EN_PPLL 0x0080 -#define R92C_SYS_FUNC_EN_PCIED 0x0100 -#define R92C_SYS_FUNC_EN_DIOE 0x0200 -#define R92C_SYS_FUNC_EN_CPUEN 0x0400 -#define R92C_SYS_FUNC_EN_DCORE 0x0800 -#define R92C_SYS_FUNC_EN_ELDR 0x1000 -#define R92C_SYS_FUNC_EN_DIO_RF 0x2000 -#define R92C_SYS_FUNC_EN_HWPDN 0x4000 -#define R92C_SYS_FUNC_EN_MREGEN 0x8000 - -/* Bits for R92C_APS_FSMCO. */ -#define R92C_APS_FSMCO_PFM_LDALL 0x00000001 -#define R92C_APS_FSMCO_PFM_ALDN 0x00000002 -#define R92C_APS_FSMCO_PFM_LDKP 0x00000004 -#define R92C_APS_FSMCO_PFM_WOWL 0x00000008 -#define R92C_APS_FSMCO_PDN_EN 0x00000010 -#define R92C_APS_FSMCO_PDN_PL 0x00000020 -#define R92C_APS_FSMCO_APFM_ONMAC 0x00000100 -#define R92C_APS_FSMCO_APFM_OFF 0x00000200 -#define R92C_APS_FSMCO_APFM_RSM 0x00000400 -#define R92C_APS_FSMCO_AFSM_HSUS 0x00000800 -#define R92C_APS_FSMCO_AFSM_PCIE 0x00001000 -#define R92C_APS_FSMCO_APDM_MAC 0x00002000 -#define R92C_APS_FSMCO_APDM_HOST 0x00004000 -#define R92C_APS_FSMCO_APDM_HPDN 0x00008000 -#define R92C_APS_FSMCO_RDY_MACON 0x00010000 -#define R92C_APS_FSMCO_SUS_HOST 0x00020000 -#define R92C_APS_FSMCO_ROP_ALD 0x00100000 -#define R92C_APS_FSMCO_ROP_PWR 0x00200000 -#define R92C_APS_FSMCO_ROP_SPS 0x00400000 -#define R92C_APS_FSMCO_SOP_MRST 0x02000000 -#define R92C_APS_FSMCO_SOP_FUSE 0x04000000 -#define R92C_APS_FSMCO_SOP_ABG 0x08000000 -#define R92C_APS_FSMCO_SOP_AMB 0x10000000 -#define R92C_APS_FSMCO_SOP_RCK 0x20000000 -#define R92C_APS_FSMCO_SOP_A8M 0x40000000 -#define R92C_APS_FSMCO_XOP_BTCK 0x80000000 - -/* Bits for R92C_SYS_CLKR. */ -#define R92C_SYS_CLKR_ANAD16V_EN 0x00000001 -#define R92C_SYS_CLKR_ANA8M 0x00000002 -#define R92C_SYS_CLKR_MACSLP 0x00000010 -#define R92C_SYS_CLKR_LOADER_EN 0x00000020 -#define R92C_SYS_CLKR_80M_SSC_DIS 0x00000080 -#define R92C_SYS_CLKR_80M_SSC_EN_HO 0x00000100 -#define R92C_SYS_CLKR_PHY_SSC_RSTB 0x00000200 -#define R92C_SYS_CLKR_SEC_EN 0x00000400 -#define R92C_SYS_CLKR_MAC_EN 0x00000800 -#define R92C_SYS_CLKR_SYS_EN 0x00001000 -#define R92C_SYS_CLKR_RING_EN 0x00002000 - -/* Bits for R92C_RF_CTRL. */ -#define R92C_RF_CTRL_EN 0x01 -#define R92C_RF_CTRL_RSTB 0x02 -#define R92C_RF_CTRL_SDMRSTB 0x04 - -/* Bits for R92C_LDOV12D_CTRL. */ -#define R92C_LDOV12D_CTRL_LDV12_EN 0x01 - -/* Bits for R92C_EFUSE_CTRL. */ -#define R92C_EFUSE_CTRL_DATA_M 0x000000ff -#define R92C_EFUSE_CTRL_DATA_S 0 -#define R92C_EFUSE_CTRL_ADDR_M 0x0003ff00 -#define R92C_EFUSE_CTRL_ADDR_S 8 -#define R92C_EFUSE_CTRL_VALID 0x80000000 - -/* Bits for R92C_GPIO_MUXCFG. */ -#define R92C_GPIO_MUXCFG_RFKILL 0x0008 -#define R92C_GPIO_MUXCFG_ENBT 0x0020 - -/* Bits for R92C_GPIO_IO_SEL. */ -#define R92C_GPIO_IO_SEL_RFKILL 0x0008 - -/* Bits for R92C_LEDCFG0. */ -#define R92C_LEDCFG0_DIS 0x08 - -/* Bits for R92C_LEDCFG2. */ -#define R92C_LEDCFG2_EN 0x60 -#define R92C_LEDCFG2_DIS 0x68 - -/* Bits for R92C_MCUFWDL. */ -#define R92C_MCUFWDL_EN 0x00000001 -#define R92C_MCUFWDL_RDY 0x00000002 -#define R92C_MCUFWDL_CHKSUM_RPT 0x00000004 -#define R92C_MCUFWDL_MACINI_RDY 0x00000008 -#define R92C_MCUFWDL_BBINI_RDY 0x00000010 -#define R92C_MCUFWDL_RFINI_RDY 0x00000020 -#define R92C_MCUFWDL_WINTINI_RDY 0x00000040 -#define R92C_MCUFWDL_RAM_DL_SEL 0x00000080 /* 1: RAM, 0: ROM */ -#define R92C_MCUFWDL_PAGE_M 0x00070000 -#define R92C_MCUFWDL_PAGE_S 16 -#define R92C_MCUFWDL_CPRST 0x00800000 - -/* Bits for R92C_HPON_FSM. */ -#define R92C_HPON_FSM_CHIP_BONDING_ID_S 22 -#define R92C_HPON_FSM_CHIP_BONDING_ID_M 0x00c00000 -#define R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R 1 - -/* Bits for R92C_SYS_CFG. */ -#define R92C_SYS_CFG_XCLK_VLD 0x00000001 -#define R92C_SYS_CFG_ACLK_VLD 0x00000002 -#define R92C_SYS_CFG_UCLK_VLD 0x00000004 -#define R92C_SYS_CFG_PCLK_VLD 0x00000008 -#define R92C_SYS_CFG_PCIRSTB 0x00000010 -#define R92C_SYS_CFG_V15_VLD 0x00000020 -#define R92C_SYS_CFG_TRP_B15V_EN 0x00000080 -#define R92C_SYS_CFG_SIC_IDLE 0x00000100 -#define R92C_SYS_CFG_BD_MAC2 0x00000200 -#define R92C_SYS_CFG_BD_MAC1 0x00000400 -#define R92C_SYS_CFG_IC_MACPHY_MODE 0x00000800 -#define R92C_SYS_CFG_CHIP_VER_RTL_M 0x0000f000 -#define R92C_SYS_CFG_CHIP_VER_RTL_S 12 -#define R92C_SYS_CFG_BT_FUNC 0x00010000 -#define R92C_SYS_CFG_VENDOR_UMC 0x00080000 -#define R92C_SYS_CFG_PAD_HWPD_IDN 0x00400000 -#define R92C_SYS_CFG_TRP_VAUX_EN 0x00800000 -#define R92C_SYS_CFG_TRP_BT_EN 0x01000000 -#define R92C_SYS_CFG_BD_PKG_SEL 0x02000000 -#define R92C_SYS_CFG_BD_HCI_SEL 0x04000000 -#define R92C_SYS_CFG_TYPE_92C 0x08000000 - -/* Bits for R92C_CR. */ -#define R92C_CR_HCI_TXDMA_EN 0x00000001 -#define R92C_CR_HCI_RXDMA_EN 0x00000002 -#define R92C_CR_TXDMA_EN 0x00000004 -#define R92C_CR_RXDMA_EN 0x00000008 -#define R92C_CR_PROTOCOL_EN 0x00000010 -#define R92C_CR_SCHEDULE_EN 0x00000020 -#define R92C_CR_MACTXEN 0x00000040 -#define R92C_CR_MACRXEN 0x00000080 -#define R92C_CR_ENSEC 0x00000200 -#define R92C_CR_NETTYPE_S 16 -#define R92C_CR_NETTYPE_M 0x00030000 -#define R92C_CR_NETTYPE_NOLINK 0 -#define R92C_CR_NETTYPE_ADHOC 1 -#define R92C_CR_NETTYPE_INFRA 2 -#define R92C_CR_NETTYPE_AP 3 - -/* Bits for R92C_PBP. */ -#define R92C_PBP_PSRX_M 0x0f -#define R92C_PBP_PSRX_S 0 -#define R92C_PBP_PSTX_M 0xf0 -#define R92C_PBP_PSTX_S 4 -#define R92C_PBP_64 0 -#define R92C_PBP_128 1 -#define R92C_PBP_256 2 -#define R92C_PBP_512 3 -#define R92C_PBP_1024 4 - -/* Bits for R92C_TRXDMA_CTRL. */ -#define R92C_TRXDMA_CTRL_RXDMA_AGG_EN 0x0004 -#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_M 0x0030 -#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_S 4 -#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_M 0x00c0 -#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_S 6 -#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_M 0x0300 -#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_S 8 -#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_M 0x0c00 -#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_S 10 -#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_M 0x3000 -#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_S 12 -#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_M 0xc000 -#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_S 14 -#define R92C_TRXDMA_CTRL_QUEUE_LOW 1 -#define R92C_TRXDMA_CTRL_QUEUE_NORMAL 2 -#define R92C_TRXDMA_CTRL_QUEUE_HIGH 3 -#define R92C_TRXDMA_CTRL_QMAP_M 0xfff0 -#define R92C_TRXDMA_CTRL_QMAP_S 4 -/* Shortcuts. */ -#define R92C_TRXDMA_CTRL_QMAP_3EP 0xf5b0 -#define R92C_TRXDMA_CTRL_QMAP_HQ_LQ 0xf5f0 -#define R92C_TRXDMA_CTRL_QMAP_HQ_NQ 0xfaf0 -#define R92C_TRXDMA_CTRL_QMAP_LQ 0x5550 -#define R92C_TRXDMA_CTRL_QMAP_NQ 0xaaa0 -#define R92C_TRXDMA_CTRL_QMAP_HQ 0xfff0 - -/* Bits for R92C_LLT_INIT. */ -#define R92C_LLT_INIT_DATA_M 0x000000ff -#define R92C_LLT_INIT_DATA_S 0 -#define R92C_LLT_INIT_ADDR_M 0x0000ff00 -#define R92C_LLT_INIT_ADDR_S 8 -#define R92C_LLT_INIT_OP_M 0xc0000000 -#define R92C_LLT_INIT_OP_S 30 -#define R92C_LLT_INIT_OP_NO_ACTIVE 0 -#define R92C_LLT_INIT_OP_WRITE 1 - -/* Bits for R92C_RQPN. */ -#define R92C_RQPN_HPQ_M 0x000000ff -#define R92C_RQPN_HPQ_S 0 -#define R92C_RQPN_LPQ_M 0x0000ff00 -#define R92C_RQPN_LPQ_S 8 -#define R92C_RQPN_PUBQ_M 0x00ff0000 -#define R92C_RQPN_PUBQ_S 16 -#define R92C_RQPN_LD 0x80000000 - -/* Bits for R92C_TDECTRL. */ -#define R92C_TDECTRL_BLK_DESC_NUM_M 0x0000000f -#define R92C_TDECTRL_BLK_DESC_NUM_S 4 - -/* Bits for R92C_FWHW_TXQ_CTRL. */ -#define R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW 0x80 - -/* Bits for R92C_SPEC_SIFS. */ -#define R92C_SPEC_SIFS_CCK_M 0x00ff -#define R92C_SPEC_SIFS_CCK_S 0 -#define R92C_SPEC_SIFS_OFDM_M 0xff00 -#define R92C_SPEC_SIFS_OFDM_S 8 - -/* Bits for R92C_RL. */ -#define R92C_RL_LRL_M 0x003f -#define R92C_RL_LRL_S 0 -#define R92C_RL_SRL_M 0x3f00 -#define R92C_RL_SRL_S 8 - -/* Bits for R92C_RRSR. */ -#define R92C_RRSR_RATE_BITMAP_M 0x000fffff -#define R92C_RRSR_RATE_BITMAP_S 0 -#define R92C_RRSR_RATE_CCK_ONLY_1M 0xffff1 -#define R92C_RRSR_RATE_ALL 0xfffff -#define R92C_RRSR_RSC_LOWSUBCHNL 0x00200000 -#define R92C_RRSR_RSC_UPSUBCHNL 0x00400000 -#define R92C_RRSR_SHORT 0x00800000 - -/* Bits for R92C_EDCA_XX_PARAM. */ -#define R92C_EDCA_PARAM_AIFS_M 0x000000ff -#define R92C_EDCA_PARAM_AIFS_S 0 -#define R92C_EDCA_PARAM_ECWMIN_M 0x00000f00 -#define R92C_EDCA_PARAM_ECWMIN_S 8 -#define R92C_EDCA_PARAM_ECWMAX_M 0x0000f000 -#define R92C_EDCA_PARAM_ECWMAX_S 12 -#define R92C_EDCA_PARAM_TXOP_M 0xffff0000 -#define R92C_EDCA_PARAM_TXOP_S 16 - -/* Bits for R92C_TXPAUSE. */ -#define R92C_TXPAUSE_AC_VO 0x01 -#define R92C_TXPAUSE_AC_VI 0x02 -#define R92C_TXPAUSE_AC_BE 0x04 -#define R92C_TXPAUSE_AC_BK 0x08 - -/* Bits for R92C_BCN_CTRL. */ -#define R92C_BCN_CTRL_EN_MBSSID 0x02 -#define R92C_BCN_CTRL_TXBCN_RPT 0x04 -#define R92C_BCN_CTRL_EN_BCN 0x08 -#define R92C_BCN_CTRL_DIS_TSF_UDT0 0x10 - -/* Bits for R92C_APSD_CTRL. */ -#define R92C_APSD_CTRL_OFF 0x40 -#define R92C_APSD_CTRL_OFF_STATUS 0x80 - -/* Bits for R92C_BWOPMODE. */ -#define R92C_BWOPMODE_11J 0x01 -#define R92C_BWOPMODE_5G 0x02 -#define R92C_BWOPMODE_20MHZ 0x04 - -/* Bits for R92C_TCR. */ -#define R92C_TCR_TSFRST 0x00000001 -#define R92C_TCR_DIS_GCLK 0x00000002 -#define R92C_TCR_PAD_SEL 0x00000004 -#define R92C_TCR_PWR_ST 0x00000040 -#define R92C_TCR_PWRBIT_OW_EN 0x00000080 -#define R92C_TCR_ACRC 0x00000100 -#define R92C_TCR_CFENDFORM 0x00000200 -#define R92C_TCR_ICV 0x00000400 - -/* Bits for R92C_RCR. */ -#define R92C_RCR_AAP 0x00000001 -#define R92C_RCR_APM 0x00000002 -#define R92C_RCR_AM 0x00000004 -#define R92C_RCR_AB 0x00000008 -#define R92C_RCR_ADD3 0x00000010 -#define R92C_RCR_APWRMGT 0x00000020 -#define R92C_RCR_CBSSID_DATA 0x00000040 -#define R92C_RCR_CBSSID_BCN 0x00000080 -#define R92C_RCR_ACRC32 0x00000100 -#define R92C_RCR_AICV 0x00000200 -#define R92C_RCR_ADF 0x00000800 -#define R92C_RCR_ACF 0x00001000 -#define R92C_RCR_AMF 0x00002000 -#define R92C_RCR_HTC_LOC_CTRL 0x00004000 -#define R92C_RCR_MFBEN 0x00400000 -#define R92C_RCR_LSIGEN 0x00800000 -#define R92C_RCR_ENMBID 0x01000000 -#define R92C_RCR_APP_BA_SSN 0x08000000 -#define R92C_RCR_APP_PHYSTS 0x10000000 -#define R92C_RCR_APP_ICV 0x20000000 -#define R92C_RCR_APP_MIC 0x40000000 -#define R92C_RCR_APPFCS 0x80000000 - -/* Bits for R92C_CAMCMD. */ -#define R92C_CAMCMD_ADDR_M 0x0000ffff -#define R92C_CAMCMD_ADDR_S 0 -#define R92C_CAMCMD_WRITE 0x00010000 -#define R92C_CAMCMD_CLR 0x40000000 -#define R92C_CAMCMD_POLLING 0x80000000 - -/* IMR */ - -/*Beacon DMA interrupt 6 */ -#define R92C_IMR_BCNDMAINT6 0x80000000 -/*Beacon DMA interrupt 5 */ -#define R92C_IMR_BCNDMAINT5 0x40000000 -/*Beacon DMA interrupt 4 */ -#define R92C_IMR_BCNDMAINT4 0x20000000 -/*Beacon DMA interrupt 3 */ -#define R92C_IMR_BCNDMAINT3 0x10000000 -/*Beacon DMA interrupt 2 */ -#define R92C_IMR_BCNDMAINT2 0x08000000 -/*Beacon DMA interrupt 1 */ -#define R92C_IMR_BCNDMAINT1 0x04000000 -/*Beacon Queue DMA OK interrupt 8 */ -#define R92C_IMR_BCNDOK8 0x02000000 -/*Beacon Queue DMA OK interrupt 7 */ -#define R92C_IMR_BCNDOK7 0x01000000 -/*Beacon Queue DMA OK interrupt 6 */ -#define R92C_IMR_BCNDOK6 0x00800000 -/*Beacon Queue DMA OK interrupt 5 */ -#define R92C_IMR_BCNDOK5 0x00400000 -/*Beacon Queue DMA OK interrupt 4 */ -#define R92C_IMR_BCNDOK4 0x00200000 -/*Beacon Queue DMA OK interrupt 3 */ -#define R92C_IMR_BCNDOK3 0x00100000 -/*Beacon Queue DMA OK interrupt 2 */ -#define R92C_IMR_BCNDOK2 0x00080000 -/*Beacon Queue DMA OK interrupt 1 */ -#define R92C_IMR_BCNDOK1 0x00040000 -/*Timeout interrupt 2 */ -#define R92C_IMR_TIMEOUT2 0x00020000 -/*Timeout interrupt 1 */ -#define R92C_IMR_TIMEOUT1 0x00010000 -/*Transmit FIFO Overflow */ -#define R92C_IMR_TXFOVW 0x00008000 -/*Power save time out interrupt */ -#define R92C_IMR_PSTIMEOUT 0x00004000 -/*Beacon DMA interrupt 0 */ -#define R92C_IMR_BCNINT 0x00002000 -/*Receive FIFO Overflow */ -#define R92C_IMR_RXFOVW 0x00001000 -/*Receive Descriptor Unavailable */ -#define R92C_IMR_RDU 0x00000800 -/*For 92C,ATIM Window End interrupt */ -#define R92C_IMR_ATIMEND 0x00000400 -/*Beacon Queue DMA OK interrupt */ -#define R92C_IMR_BDOK 0x00000200 -/*High Queue DMA OK interrupt */ -#define R92C_IMR_HIGHDOK 0x00000100 -/*Transmit Beacon OK interrupt */ -#define R92C_IMR_TBDOK 0x00000080 -/*Management Queue DMA OK interrupt */ -#define R92C_IMR_MGNTDOK 0x00000040 -/*For 92C,Transmit Beacon Error interrupt */ -#define R92C_IMR_TBDER 0x00000020 -/*AC_BK DMA OK interrupt */ -#define R92C_IMR_BKDOK 0x00000010 -/*AC_BE DMA OK interrupt */ -#define R92C_IMR_BEDOK 0x00000008 -/*AC_VI DMA OK interrupt */ -#define R92C_IMR_VIDOK 0x00000004 -/*AC_VO DMA interrupt */ -#define R92C_IMR_VODOK 0x00000002 -/*Receive DMA OK interrupt */ -#define R92C_IMR_ROK 0x00000001 - -#define R92C_IBSS_INT_MASK (R92C_IMR_BCNINT | R92C_IMR_TBDOK | R92C_IMR_TBDER) - -/* - * Baseband registers. - */ -#define R92C_FPGA0_RFMOD 0x800 -#define R92C_FPGA0_TXINFO 0x804 -#define R92C_HSSI_PARAM1(chain) (0x820 + (chain) * 8) -#define R92C_HSSI_PARAM2(chain) (0x824 + (chain) * 8) -#define R92C_TXAGC_RATE18_06(i) (((i) == 0) ? 0xe00 : 0x830) -#define R92C_TXAGC_RATE54_24(i) (((i) == 0) ? 0xe04 : 0x834) -#define R92C_TXAGC_A_CCK1_MCS32 0xe08 -#define R92C_TXAGC_B_CCK1_55_MCS32 0x838 -#define R92C_TXAGC_B_CCK11_A_CCK2_11 0x86c -#define R92C_TXAGC_MCS03_MCS00(i) (((i) == 0) ? 0xe10 : 0x83c) -#define R92C_TXAGC_MCS07_MCS04(i) (((i) == 0) ? 0xe14 : 0x848) -#define R92C_TXAGC_MCS11_MCS08(i) (((i) == 0) ? 0xe18 : 0x84c) -#define R92C_TXAGC_MCS15_MCS12(i) (((i) == 0) ? 0xe1c : 0x868) -#define R92C_LSSI_PARAM(chain) (0x840 + (chain) * 4) -#define R92C_FPGA0_RFIFACEOE(chain) (0x860 + (chain) * 4) -#define R92C_FPGA0_RFIFACESW(idx) (0x870 + (idx) * 4) -#define R92C_FPGA0_RFPARAM(idx) (0x878 + (idx) * 4) -#define R92C_FPGA0_ANAPARAM2 0x884 -#define R92C_LSSI_READBACK(chain) (0x8a0 + (chain) * 4) -#define R92C_HSPI_READBACK(chain) (0x8b8 + (chain) * 4) -#define R92C_FPGA1_RFMOD 0x900 -#define R92C_FPGA1_TXINFO 0x90c -#define R92C_CCK0_SYSTEM 0xa00 -#define R92C_CCK0_AFESETTING 0xa04 -#define R92C_OFDM0_TRXPATHENA 0xc04 -#define R92C_OFDM0_TRMUXPAR 0xc08 -#define R92C_OFDM0_RXIQIMBALANCE(chain) (0xc14 + (chain) * 8) -#define R92C_OFDM0_ECCATHRESHOLD 0xc4c -#define R92C_OFDM0_AGCCORE1(chain) (0xc50 + (chain) * 8) -#define R92C_OFDM0_AGCPARAM1 0xc70 -#define R92C_OFDM0_AGCRSSITABLE 0xc78 -#define R92C_OFDM0_TXIQIMBALANCE(chain) (0xc80 + (chain) * 8) -#define R92C_OFDM0_TXAFE(chain) (0xc94 + (chain) * 8) -#define R92C_OFDM0_RXIQEXTANTA 0xca0 -#define R92C_OFDM1_LSTF 0xd00 - -/* Bits for R92C_FPGA[01]_RFMOD. */ -#define R92C_RFMOD_40MHZ 0x00000001 -#define R92C_RFMOD_JAPAN 0x00000002 -#define R92C_RFMOD_CCK_TXSC 0x00000030 -#define R92C_RFMOD_CCK_EN 0x01000000 -#define R92C_RFMOD_OFDM_EN 0x02000000 - -/* Bits for R92C_HSSI_PARAM1(i). */ -#define R92C_HSSI_PARAM1_PI 0x00000100 - -/* Bits for R92C_HSSI_PARAM2(i). */ -#define R92C_HSSI_PARAM2_CCK_HIPWR 0x00000200 -#define R92C_HSSI_PARAM2_ADDR_LENGTH 0x00000400 -#define R92C_HSSI_PARAM2_DATA_LENGTH 0x00000800 -#define R92C_HSSI_PARAM2_READ_ADDR_M 0x7f800000 -#define R92C_HSSI_PARAM2_READ_ADDR_S 23 -#define R92C_HSSI_PARAM2_READ_EDGE 0x80000000 - -/* Bits for R92C_TXAGC_A_CCK1_MCS32. */ -#define R92C_TXAGC_A_CCK1_M 0x0000ff00 -#define R92C_TXAGC_A_CCK1_S 8 - -/* Bits for R92C_TXAGC_B_CCK11_A_CCK2_11. */ -#define R92C_TXAGC_B_CCK11_M 0x000000ff -#define R92C_TXAGC_B_CCK11_S 0 -#define R92C_TXAGC_A_CCK2_M 0x0000ff00 -#define R92C_TXAGC_A_CCK2_S 8 -#define R92C_TXAGC_A_CCK55_M 0x00ff0000 -#define R92C_TXAGC_A_CCK55_S 16 -#define R92C_TXAGC_A_CCK11_M 0xff000000 -#define R92C_TXAGC_A_CCK11_S 24 - -/* Bits for R92C_TXAGC_B_CCK1_55_MCS32. */ -#define R92C_TXAGC_B_CCK1_M 0x0000ff00 -#define R92C_TXAGC_B_CCK1_S 8 -#define R92C_TXAGC_B_CCK2_M 0x00ff0000 -#define R92C_TXAGC_B_CCK2_S 16 -#define R92C_TXAGC_B_CCK55_M 0xff000000 -#define R92C_TXAGC_B_CCK55_S 24 - -/* Bits for R92C_TXAGC_RATE18_06(x). */ -#define R92C_TXAGC_RATE06_M 0x000000ff -#define R92C_TXAGC_RATE06_S 0 -#define R92C_TXAGC_RATE09_M 0x0000ff00 -#define R92C_TXAGC_RATE09_S 8 -#define R92C_TXAGC_RATE12_M 0x00ff0000 -#define R92C_TXAGC_RATE12_S 16 -#define R92C_TXAGC_RATE18_M 0xff000000 -#define R92C_TXAGC_RATE18_S 24 - -/* Bits for R92C_TXAGC_RATE54_24(x). */ -#define R92C_TXAGC_RATE24_M 0x000000ff -#define R92C_TXAGC_RATE24_S 0 -#define R92C_TXAGC_RATE36_M 0x0000ff00 -#define R92C_TXAGC_RATE36_S 8 -#define R92C_TXAGC_RATE48_M 0x00ff0000 -#define R92C_TXAGC_RATE48_S 16 -#define R92C_TXAGC_RATE54_M 0xff000000 -#define R92C_TXAGC_RATE54_S 24 - -/* Bits for R92C_TXAGC_MCS03_MCS00(x). */ -#define R92C_TXAGC_MCS00_M 0x000000ff -#define R92C_TXAGC_MCS00_S 0 -#define R92C_TXAGC_MCS01_M 0x0000ff00 -#define R92C_TXAGC_MCS01_S 8 -#define R92C_TXAGC_MCS02_M 0x00ff0000 -#define R92C_TXAGC_MCS02_S 16 -#define R92C_TXAGC_MCS03_M 0xff000000 -#define R92C_TXAGC_MCS03_S 24 - -/* Bits for R92C_TXAGC_MCS07_MCS04(x). */ -#define R92C_TXAGC_MCS04_M 0x000000ff -#define R92C_TXAGC_MCS04_S 0 -#define R92C_TXAGC_MCS05_M 0x0000ff00 -#define R92C_TXAGC_MCS05_S 8 -#define R92C_TXAGC_MCS06_M 0x00ff0000 -#define R92C_TXAGC_MCS06_S 16 -#define R92C_TXAGC_MCS07_M 0xff000000 -#define R92C_TXAGC_MCS07_S 24 - -/* Bits for R92C_TXAGC_MCS11_MCS08(x). */ -#define R92C_TXAGC_MCS08_M 0x000000ff -#define R92C_TXAGC_MCS08_S 0 -#define R92C_TXAGC_MCS09_M 0x0000ff00 -#define R92C_TXAGC_MCS09_S 8 -#define R92C_TXAGC_MCS10_M 0x00ff0000 -#define R92C_TXAGC_MCS10_S 16 -#define R92C_TXAGC_MCS11_M 0xff000000 -#define R92C_TXAGC_MCS11_S 24 - -/* Bits for R92C_TXAGC_MCS15_MCS12(x). */ -#define R92C_TXAGC_MCS12_M 0x000000ff -#define R92C_TXAGC_MCS12_S 0 -#define R92C_TXAGC_MCS13_M 0x0000ff00 -#define R92C_TXAGC_MCS13_S 8 -#define R92C_TXAGC_MCS14_M 0x00ff0000 -#define R92C_TXAGC_MCS14_S 16 -#define R92C_TXAGC_MCS15_M 0xff000000 -#define R92C_TXAGC_MCS15_S 24 - -/* Bits for R92C_LSSI_PARAM(i). */ -#define R92C_LSSI_PARAM_DATA_M 0x000fffff -#define R92C_LSSI_PARAM_DATA_S 0 -#define R92C_LSSI_PARAM_ADDR_M 0x03f00000 -#define R92C_LSSI_PARAM_ADDR_S 20 - -/* Bits for R92C_FPGA0_ANAPARAM2. */ -#define R92C_FPGA0_ANAPARAM2_CBW20 0x00000400 - -/* Bits for R92C_LSSI_READBACK(i). */ -#define R92C_LSSI_READBACK_DATA_M 0x000fffff -#define R92C_LSSI_READBACK_DATA_S 0 - -/* Bits for R92C_OFDM0_AGCCORE1(i). */ -#define R92C_OFDM0_AGCCORE1_GAIN_M 0x0000007f -#define R92C_OFDM0_AGCCORE1_GAIN_S 0 - - -/* - * USB registers. - */ -#define R92C_USB_INFO 0xfe17 -#define R92C_USB_SPECIAL_OPTION 0xfe55 -#define R92C_USB_HCPWM 0xfe57 -#define R92C_USB_HRPWM 0xfe58 -#define R92C_USB_DMA_AGG_TO 0xfe5b -#define R92C_USB_AGG_TO 0xfe5c -#define R92C_USB_AGG_TH 0xfe5d -#define R92C_USB_VID 0xfe60 -#define R92C_USB_PID 0xfe62 -#define R92C_USB_OPTIONAL 0xfe64 -#define R92C_USB_EP 0xfe65 -#define R92C_USB_PHY 0xfe68 -#define R92C_USB_MAC_ADDR 0xfe70 -#define R92C_USB_STRING 0xfe80 - -/* Bits for R92C_USB_SPECIAL_OPTION. */ -#define R92C_USB_SPECIAL_OPTION_AGG_EN 0x08 - -/* Bits for R92C_USB_EP. */ -#define R92C_USB_EP_HQ_M 0x000f -#define R92C_USB_EP_HQ_S 0 -#define R92C_USB_EP_NQ_M 0x00f0 -#define R92C_USB_EP_NQ_S 4 -#define R92C_USB_EP_LQ_M 0x0f00 -#define R92C_USB_EP_LQ_S 8 - - -/* - * Firmware base address. - */ -#define R92C_FW_START_ADDR 0x1000 -#define R92C_FW_PAGE_SIZE 4096 - - -/* - * RF (6052) registers. - */ -#define R92C_RF_AC 0x00 -#define R92C_RF_IQADJ_G(i) (0x01 + (i)) -#define R92C_RF_POW_TRSW 0x05 -#define R92C_RF_GAIN_RX 0x06 -#define R92C_RF_GAIN_TX 0x07 -#define R92C_RF_TXM_IDAC 0x08 -#define R92C_RF_BS_IQGEN 0x0f -#define R92C_RF_MODE1 0x10 -#define R92C_RF_MODE2 0x11 -#define R92C_RF_RX_AGC_HP 0x12 -#define R92C_RF_TX_AGC 0x13 -#define R92C_RF_BIAS 0x14 -#define R92C_RF_IPA 0x15 -#define R92C_RF_POW_ABILITY 0x17 -#define R92C_RF_CHNLBW 0x18 -#define R92C_RF_RX_G1 0x1a -#define R92C_RF_RX_G2 0x1b -#define R92C_RF_RX_BB2 0x1c -#define R92C_RF_RX_BB1 0x1d -#define R92C_RF_RCK1 0x1e -#define R92C_RF_RCK2 0x1f -#define R92C_RF_TX_G(i) (0x20 + (i)) -#define R92C_RF_TX_BB1 0x23 -#define R92C_RF_T_METER 0x24 -#define R92C_RF_SYN_G(i) (0x25 + (i)) -#define R92C_RF_RCK_OS 0x30 -#define R92C_RF_TXPA_G(i) (0x31 + (i)) - -/* Bits for R92C_RF_AC. */ -#define R92C_RF_AC_MODE_M 0x70000 -#define R92C_RF_AC_MODE_S 16 -#define R92C_RF_AC_MODE_STANDBY 1 - -/* Bits for R92C_RF_CHNLBW. */ -#define R92C_RF_CHNLBW_CHNL_M 0x003ff -#define R92C_RF_CHNLBW_CHNL_S 0 -#define R92C_RF_CHNLBW_BW20 0x00400 -#define R92C_RF_CHNLBW_LCSTART 0x08000 - - -/* - * CAM entries. - */ -#define R92C_CAM_ENTRY_COUNT 32 - -#define R92C_CAM_CTL0(entry) ((entry) * 8 + 0) -#define R92C_CAM_CTL1(entry) ((entry) * 8 + 1) -#define R92C_CAM_KEY(entry, i) ((entry) * 8 + 2 + (i)) - -/* Bits for R92C_CAM_CTL0(i). */ -#define R92C_CAM_KEYID_M 0x00000003 -#define R92C_CAM_KEYID_S 0 -#define R92C_CAM_ALGO_M 0x0000001c -#define R92C_CAM_ALGO_S 2 -#define R92C_CAM_ALGO_NONE 0 -#define R92C_CAM_ALGO_WEP40 1 -#define R92C_CAM_ALGO_TKIP 2 -#define R92C_CAM_ALGO_AES 4 -#define R92C_CAM_ALGO_WEP104 5 -#define R92C_CAM_VALID 0x00008000 -#define R92C_CAM_MACLO_M 0xffff0000 -#define R92C_CAM_MACLO_S 16 - -/* Rate adaptation modes. */ -#define R92C_RAID_11GN 1 -#define R92C_RAID_11N 3 -#define R92C_RAID_11BG 4 -#define R92C_RAID_11G 5 /* "pure" 11g */ -#define R92C_RAID_11B 6 - +#define R92C_MIN_TX_PWR 0x00 +#define R92C_MAX_TX_PWR 0x3f + +#define R92C_H2C_NBOX 4 + + +/* Common part of Tx descriptor (named only!). */ +struct rtwn_tx_desc_common { + uint16_t pktlen; + uint8_t offset; + uint8_t flags0; +#define RTWN_FLAGS0_OWN 0x80 + + uint32_t txdw1; +/* NB: qsel is shared too; however, it looks better at the lower level */ +#define RTWN_TXDW1_CIPHER_M 0x00c00000 +#define RTWN_TXDW1_CIPHER_S 22 +#define RTWN_TXDW1_CIPHER_NONE 0 +#define RTWN_TXDW1_CIPHER_RC4 1 +#define RTWN_TXDW1_CIPHER_SM4 2 +#define RTWN_TXDW1_CIPHER_AES 3 + + uint32_t reserved[5]; + + union txdw7_shared { + uint16_t usb_checksum; + uint16_t pci_txbufsize; + } txdw7; +} __packed __attribute__((aligned(4))); /* * Macros to access subfields in registers. @@ -910,1192 +63,56 @@ #define RW(var, field, val) \ (((var) & ~field##_M) | SM(field, val)) -/* - * Firmware image header. - */ -struct r92c_fw_hdr { - /* QWORD0 */ - uint16_t signature; - uint8_t category; - uint8_t function; - uint16_t version; - uint16_t subversion; - /* QWORD1 */ - uint8_t month; - uint8_t date; - uint8_t hour; - uint8_t minute; - uint16_t ramcodesize; - uint16_t reserved2; - /* QWORD2 */ - uint32_t svnidx; - uint32_t reserved3; - /* QWORD3 */ - uint32_t reserved4; - uint32_t reserved5; -} __packed; + +#define RTWN_MAX_CONDITIONS 3 /* - * Host to firmware commands. + * Structure for MAC initialization values. */ -struct r92c_fw_cmd { - uint8_t id; -#define R92C_CMD_AP_OFFLOAD 0 -#define R92C_CMD_SET_PWRMODE 1 -#define R92C_CMD_JOINBSS_RPT 2 -#define R92C_CMD_RSVD_PAGE 3 -#define R92C_CMD_RSSI 4 -#define R92C_CMD_RSSI_SETTING 5 -#define R92C_CMD_MACID_CONFIG 6 -#define R92C_CMD_MACID_PS_MODE 7 -#define R92C_CMD_P2P_PS_OFFLOAD 8 -#define R92C_CMD_SELECTIVE_SUSPEND 9 -#define R92C_CMD_FLAG_EXT 0x80 - - uint8_t msg[5]; -} __packed; - -/* Structure for R92C_CMD_RSSI_SETTING. */ -struct r92c_fw_cmd_rssi { - uint8_t macid; - uint8_t reserved; - uint8_t pwdb; -} __packed; - -/* Structure for R92C_CMD_MACID_CONFIG. */ -struct r92c_fw_cmd_macid_cfg { - uint32_t mask; - uint8_t macid; -#define RTWN_MACID_BSS 0 -#define RTWN_MACID_BC 4 /* Broadcast. */ -#define RTWN_MACID_VALID 0x80 -} __packed; - -/* - * RTL8192CU ROM image. - */ -struct r92c_rom { - uint16_t id; /* 0x8129 */ - uint8_t reserved1[5]; - uint8_t dbg_sel; - uint16_t reserved2; - uint16_t vid; - uint16_t pid; - uint8_t usb_opt; - uint8_t ep_setting; - uint16_t reserved3; - uint8_t usb_phy; - uint8_t reserved4[3]; - uint8_t macaddr[6]; - uint8_t string[61]; /* "Realtek" */ - uint8_t subcustomer_id; - uint8_t cck_tx_pwr[R92C_MAX_CHAINS][3]; - uint8_t ht40_1s_tx_pwr[R92C_MAX_CHAINS][3]; - uint8_t ht40_2s_tx_pwr_diff[3]; - uint8_t ht20_tx_pwr_diff[3]; - uint8_t ofdm_tx_pwr_diff[3]; - uint8_t ht40_max_pwr[3]; - uint8_t ht20_max_pwr[3]; - uint8_t xtal_calib; - uint8_t tssi[R92C_MAX_CHAINS]; - uint8_t thermal_meter; - uint8_t rf_opt1; -#define R92C_ROM_RF1_REGULATORY_M 0x07 -#define R92C_ROM_RF1_REGULATORY_S 0 -#define R92C_ROM_RF1_BOARD_TYPE_M 0xe0 -#define R92C_ROM_RF1_BOARD_TYPE_S 5 -#define R92C_BOARD_TYPE_DONGLE 0 -#define R92C_BOARD_TYPE_HIGHPA 1 -#define R92C_BOARD_TYPE_MINICARD 2 -#define R92C_BOARD_TYPE_SOLO 3 -#define R92C_BOARD_TYPE_COMBO 4 - - uint8_t rf_opt2; - uint8_t rf_opt3; - uint8_t rf_opt4; - uint8_t channel_plan; -#define R92C_CHANNEL_PLAN_BY_HW 0x80 - - uint8_t version; - uint8_t curstomer_id; -} __packed; - -/* Rx MAC descriptor. */ -struct r92c_rx_desc { - uint32_t rxdw0; -#define R92C_RXDW0_PKTLEN_M 0x00003fff -#define R92C_RXDW0_PKTLEN_S 0 -#define R92C_RXDW0_CRCERR 0x00004000 -#define R92C_RXDW0_ICVERR 0x00008000 -#define R92C_RXDW0_INFOSZ_M 0x000f0000 -#define R92C_RXDW0_INFOSZ_S 16 -#define R92C_RXDW0_QOS 0x00800000 -#define R92C_RXDW0_SHIFT_M 0x03000000 -#define R92C_RXDW0_SHIFT_S 24 -#define R92C_RXDW0_PHYST 0x04000000 -#define R92C_RXDW0_DECRYPTED 0x08000000 -#define R92C_RXDW0_LS 0x10000000 -#define R92C_RXDW0_FS 0x20000000 -#define R92C_RXDW0_EOR 0x40000000 -#define R92C_RXDW0_OWN 0x80000000 - - uint32_t rxdw1; - uint32_t rxdw2; -#define R92C_RXDW2_PKTCNT_M 0x00ff0000 -#define R92C_RXDW2_PKTCNT_S 16 - - uint32_t rxdw3; -#define R92C_RXDW3_RATE_M 0x0000003f -#define R92C_RXDW3_RATE_S 0 -#define R92C_RXDW3_HT 0x00000040 -#define R92C_RXDW3_HTC 0x00000400 - - uint32_t rxdw4; - uint32_t rxdw5; - - uint32_t rxbufaddr; - uint32_t rxbufaddr64; -} __packed __attribute__((aligned(4))); - -/* Rx PHY descriptor. */ -struct r92c_rx_phystat { - uint32_t phydw0; - uint32_t phydw1; - uint32_t phydw2; - uint32_t phydw3; - uint32_t phydw4; - uint32_t phydw5; - uint32_t phydw6; - uint32_t phydw7; -} __packed __attribute__((aligned(4))); - -/* Rx PHY CCK descriptor. */ -struct r92c_rx_cck { - uint8_t adc_pwdb[4]; - uint8_t sq_rpt; - uint8_t agc_rpt; -} __packed; - -/* Tx MAC descriptor. */ -struct r92c_tx_desc { - uint32_t txdw0; -#define R92C_TXDW0_PKTLEN_M 0x0000ffff -#define R92C_TXDW0_PKTLEN_S 0 -#define R92C_TXDW0_OFFSET_M 0x00ff0000 -#define R92C_TXDW0_OFFSET_S 16 -#define R92C_TXDW0_BMCAST 0x01000000 -#define R92C_TXDW0_LSG 0x04000000 -#define R92C_TXDW0_FSG 0x08000000 -#define R92C_TXDW0_OWN 0x80000000 - - uint32_t txdw1; -#define R92C_TXDW1_MACID_M 0x0000001f -#define R92C_TXDW1_MACID_S 0 -#define R92C_TXDW1_AGGEN 0x00000020 -#define R92C_TXDW1_AGGBK 0x00000040 -#define R92C_TXDW1_QSEL_M 0x00001f00 -#define R92C_TXDW1_QSEL_S 8 -#define R92C_TXDW1_QSEL_BE 0x00 -#define R92C_TXDW1_QSEL_BK 0x02 -#define R92C_TXDW1_QSEL_VI 0x05 -#define R92C_TXDW1_QSEL_VO 0x07 -#define R92C_TXDW1_QSEL_BEACON 0x10 -#define R92C_TXDW1_QSEL_HIGH 0x11 -#define R92C_TXDW1_QSEL_MGNT 0x12 -#define R92C_TXDW1_QSEL_CMD 0x13 -#define R92C_TXDW1_RAID_M 0x000f0000 -#define R92C_TXDW1_RAID_S 16 -#define R92C_TXDW1_CIPHER_M 0x00c00000 -#define R92C_TXDW1_CIPHER_S 22 -#define R92C_TXDW1_CIPHER_NONE 0 -#define R92C_TXDW1_CIPHER_RC4 1 -#define R92C_TXDW1_CIPHER_AES 3 -#define R92C_TXDW1_PKTOFF_M 0x7c000000 -#define R92C_TXDW1_PKTOFF_S 26 - - uint32_t txdw2; - uint16_t txdw3; - uint16_t txdseq; - - uint32_t txdw4; -#define R92C_TXDW4_RTSRATE_M 0x0000003f -#define R92C_TXDW4_RTSRATE_S 0 -#define R92C_TXDW4_QOS 0x00000040 -#define R92C_TXDW4_HWSEQ 0x00000080 -#define R92C_TXDW4_DRVRATE 0x00000100 -#define R92C_TXDW4_CTS2SELF 0x00000800 -#define R92C_TXDW4_RTSEN 0x00001000 -#define R92C_TXDW4_HWRTSEN 0x00002000 -#define R92C_TXDW4_SCO_M 0x003f0000 -#define R92C_TXDW4_SCO_S 20 -#define R92C_TXDW4_SCO_SCA 1 -#define R92C_TXDW4_SCO_SCB 2 -#define R92C_TXDW4_40MHZ 0x02000000 - - uint32_t txdw5; -#define R92C_TXDW5_DATARATE_M 0x0000003f -#define R92C_TXDW5_DATARATE_S 0 -#define R92C_TXDW5_SGI 0x00000040 -#define R92C_TXDW5_DATARATE_FBLIMIT_M 0x00001f00 -#define R92C_TXDW5_DATARATE_FBLIMIT_S 8 -#define R92C_TXDW5_RTSRATE_FBLIMIT_M 0x0001e000 -#define R92C_TXDW5_RTSRATE_FBLIMIT_S 13 -#define R92C_TXDW5_RETRY_LIMIT_ENABLE 0x00020000 -#define R92C_TXDW5_DATA_RETRY_LIMIT_M 0x00fc0000 -#define R92C_TXDW5_DATA_RETRY_LIMIT_S 18 -#define R92C_TXDW5_AGGNUM_M 0xff000000 -#define R92C_TXDW5_AGGNUM_S 24 - - uint32_t txdw6; - - uint16_t txbufsize; - uint16_t pad; - - uint32_t txbufaddr; - uint32_t txbufaddr64; - - uint32_t nextdescaddr; - uint32_t nextdescaddr64; - - uint32_t reserved[4]; -} __packed __attribute__((aligned(4))); - -static const uint8_t ridx2rate[] = - { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; - -/* HW rate indices. */ -#define RTWN_RIDX_CCK1 0 -#define RTWN_RIDX_CCK11 3 -#define RTWN_RIDX_OFDM6 4 -#define RTWN_RIDX_OFDM24 8 -#define RTWN_RIDX_OFDM54 11 -#define RTWN_RIDX_MCS0 12 -#define RTWN_RIDX_MCS15 27 - -#define RTWN_RIDX_COUNT 28 -#define RTWN_RIDX_UNKNOWN (uint8_t)-1 - -#define RTWN_RATE_IS_CCK(rate) ((rate) <= RTWN_RIDX_CCK11) -#define RTWN_RATE_IS_OFDM(rate) ((rate) >= RTWN_RIDX_OFDM6 && \ - (rate) <= RTWN_RIDX_OFDM54) - - -/* - * Driver definitions. - */ -#define RTWN_NTXQUEUES 9 -#define RTWN_RX_LIST_COUNT 256 -#define RTWN_TX_LIST_COUNT 256 -#define RTWN_HOST_CMD_RING_COUNT 32 - -/* TX queue indices. */ -#define RTWN_BK_QUEUE 0 -#define RTWN_BE_QUEUE 1 -#define RTWN_VI_QUEUE 2 -#define RTWN_VO_QUEUE 3 -#define RTWN_BEACON_QUEUE 4 -#define RTWN_TXCMD_QUEUE 5 -#define RTWN_MGNT_QUEUE 6 -#define RTWN_HIGH_QUEUE 7 -#define RTWN_HCCA_QUEUE 8 - -/* RX queue indices. */ -#define RTWN_RX_QUEUE 0 - -#define RTWN_RXBUFSZ (16 * 1024) -#define RTWN_TXBUFSZ (sizeof(struct r92c_tx_desc) + IEEE80211_MAX_LEN) - -#define RTWN_TX_TIMEOUT 5000 /* ms */ - -#define RTWN_LED_LINK 0 -#define RTWN_LED_DATA 1 - -struct rtwn_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; -} __packed; - -#define RTWN_RX_RADIOTAP_PRESENT \ - (1 << IEEE80211_RADIOTAP_FLAGS | \ - 1 << IEEE80211_RADIOTAP_RATE | \ - 1 << IEEE80211_RADIOTAP_CHANNEL | \ - 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) - -struct rtwn_tx_radiotap_header { - struct ieee80211_radiotap_header wt_ihdr; - uint8_t wt_flags; - uint16_t wt_chan_freq; - uint16_t wt_chan_flags; -} __packed; - -#define RTWN_TX_RADIOTAP_PRESENT \ - (1 << IEEE80211_RADIOTAP_FLAGS | \ - 1 << IEEE80211_RADIOTAP_CHANNEL) - -struct rtwn_rx_data { - bus_dmamap_t map; - struct mbuf *m; - bus_addr_t paddr; -}; - -struct rtwn_rx_ring { - struct r92c_rx_desc *desc; - bus_addr_t paddr; - bus_dma_tag_t desc_dmat; - bus_dmamap_t desc_map; - bus_dma_tag_t data_dmat; - bus_dma_segment_t seg; - struct rtwn_rx_data rx_data[RTWN_RX_LIST_COUNT]; - -}; -struct rtwn_tx_data { - bus_dmamap_t map; - struct mbuf *m; - struct ieee80211_node *ni; -}; - -struct rtwn_tx_ring { - bus_addr_t paddr; - bus_dma_tag_t desc_dmat; - bus_dmamap_t desc_map; - bus_dma_tag_t data_dmat; - bus_dma_segment_t seg; - struct r92c_tx_desc *desc; - struct rtwn_tx_data tx_data[RTWN_TX_LIST_COUNT]; - int queued; - int cur; -}; - -struct rtwn_vap { - struct ieee80211vap vap; - int (*newstate)(struct ieee80211vap *, - enum ieee80211_state, int); -}; -#define RTWN_VAP(vap) ((struct rtwn_vap *)(vap)) - -struct rtwn_softc { - device_t sc_dev; - struct mtx sc_mtx; - struct ieee80211com sc_ic; - struct mbufq sc_snd; - - struct resource *irq; - struct resource *mem; - bus_space_tag_t sc_st; - bus_space_handle_t sc_sh; - void *sc_ih; - bus_size_t sc_mapsize; - int sc_cap_off; - - struct callout calib_to; - struct callout watchdog_to; - - int sc_debug; - - u_int sc_flags; -#define RTWN_FLAG_CCK_HIPWR 0x01 -#define RTWN_FLAG_BUSY 0x02 -#define RTWN_RUNNING 0x04 - - u_int chip; -#define RTWN_CHIP_88C 0x00 -#define RTWN_CHIP_92C 0x01 -#define RTWN_CHIP_92C_1T2R 0x02 -#define RTWN_CHIP_UMC 0x04 -#define RTWN_CHIP_UMC_A_CUT 0x08 - - uint8_t board_type; - uint8_t regulatory; - uint8_t pa_setting; - int avg_pwdb; - int thcal_state; - int thcal_lctemp; - int ntxchains; - int nrxchains; - int ledlink; - - int sc_tx_timer; - int fwcur; - struct rtwn_rx_ring rx_ring; - struct rtwn_tx_ring tx_ring[RTWN_NTXQUEUES]; - uint32_t qfullmsk; - struct r92c_rom rom; - - uint32_t rf_chnlbw[R92C_MAX_CHAINS]; - - struct rtwn_rx_radiotap_header sc_rxtap; - struct rtwn_tx_radiotap_header sc_txtap; -}; - -/* - * MAC initialization values. - */ -static const struct { +struct rtwn_mac_prog { uint16_t reg; uint8_t val; -} rtl8192ce_mac[] = { - { 0x420, 0x80 }, { 0x423, 0x00 }, { 0x430, 0x00 }, { 0x431, 0x00 }, - { 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 }, { 0x435, 0x05 }, - { 0x436, 0x06 }, { 0x437, 0x07 }, { 0x438, 0x00 }, { 0x439, 0x00 }, - { 0x43a, 0x00 }, { 0x43b, 0x01 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, - { 0x43e, 0x06 }, { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 }, - { 0x442, 0x00 }, { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f }, - { 0x447, 0x00 }, { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 }, - { 0x45b, 0xb9 }, { 0x460, 0x88 }, { 0x461, 0x88 }, { 0x462, 0x06 }, - { 0x463, 0x03 }, { 0x4c8, 0x04 }, { 0x4c9, 0x08 }, { 0x4cc, 0x02 }, - { 0x4cd, 0x28 }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, - { 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, - { 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, - { 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, - { 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, - { 0x515, 0x10 }, { 0x516, 0x0a }, { 0x517, 0x10 }, { 0x51a, 0x16 }, - { 0x524, 0x0f }, { 0x525, 0x4f }, { 0x546, 0x20 }, { 0x547, 0x00 }, - { 0x559, 0x02 }, { 0x55a, 0x02 }, { 0x55d, 0xff }, { 0x605, 0x30 }, - { 0x608, 0x0e }, { 0x609, 0x2a }, { 0x652, 0x20 }, { 0x63c, 0x0a }, - { 0x63d, 0x0e }, { 0x700, 0x21 }, { 0x701, 0x43 }, { 0x702, 0x65 }, - { 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 }, { 0x70a, 0x65 }, - { 0x70b, 0x87 } }; /* - * Baseband initialization values. + * Structure for baseband initialization values. */ struct rtwn_bb_prog { int count; - const uint16_t *regs; - const uint32_t *vals; - int agccount; - const uint32_t *agcvals; + const uint16_t *reg; + const uint32_t *val; + const uint8_t cond[RTWN_MAX_CONDITIONS]; + const struct rtwn_bb_prog *next; +}; + +struct rtwn_agc_prog { + int count; + const uint32_t *val; + const uint8_t cond[RTWN_MAX_CONDITIONS]; + const struct rtwn_agc_prog *next; }; /* - * RTL8192CU and RTL8192CE-VAU. - */ -static const uint16_t rtl8192ce_bb_regs[] = { - 0x024, 0x028, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, - 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, - 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, - 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, 0x884, - 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, 0x908, - 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, - 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04, 0xc08, - 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, 0xc2c, - 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, - 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, 0xc74, - 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, 0xc98, - 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, 0xcbc, - 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc, 0xce0, - 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, 0xd08, 0xd0c, 0xd10, 0xd14, - 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c, 0xd40, 0xd44, 0xd48, - 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, 0xd60, 0xd64, 0xd68, 0xd6c, - 0xd70, 0xd74, 0xd78, 0xe00, 0xe04, 0xe08, 0xe10, 0xe14, 0xe18, - 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, 0xe48, - 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c, 0xe60, 0xe68, 0xe6c, 0xe70, - 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, 0xed0, 0xed4, - 0xed8, 0xedc, 0xee0, 0xeec, 0xf14, 0xf4c, 0xf00 -}; - -static const uint32_t rtl8192ce_bb_vals_2t[] = { - 0x0011800f, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00, - 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, - 0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727, - 0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000, - 0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a, - 0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27, - 0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070, - 0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe, - 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, - 0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, - 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, - 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, - 0x48071d40, 0x03a05633, 0x000000e4, 0x6c6c6c6c, 0x08800000, - 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, - 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, - 0x69543420, 0x43bc0094, 0x69543420, 0x433c0094, 0x00000000, - 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db, - 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100, - 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, - 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, - 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, - 0x00080740, 0x00020403, 0x0000907f, 0x20010201, 0xa0633333, - 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, - 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, - 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, - 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, - 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, - 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, - 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, - 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, 0x63db25a4, - 0x63db25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, - 0x63db25a4, 0x0c1b25a4, 0x63db25a4, 0x63db25a4, 0x63db25a4, - 0x63db25a4, 0x001b25a4, 0x001b25a4, 0x6fdb25a4, 0x00000003, - 0x00000000, 0x00000300 -}; - -static const uint32_t rtl8192ce_bb_vals_1t[] = { - 0x0011800f, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00, - 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, - 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a, - 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200, - 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070, - 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe, - 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, - 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, - 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, - 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, - 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, - 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, - 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, - 0x69543420, 0x43bc0094, 0x69543420, 0x433c0094, 0x00000000, - 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db, - 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100, - 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, - 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, - 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, - 0x00080740, 0x00020401, 0x0000907f, 0x20010201, 0xa0633333, - 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, - 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, - 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, - 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, - 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, - 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, - 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, - 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, 0x631b25a0, - 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, - 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, - 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, 0x00000003, - 0x00000000, 0x00000300, -}; - -static const uint32_t rtl8192ce_agc_vals[] = { - 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, - 0x7b050001, 0x7a060001, 0x79070001, 0x78080001, 0x77090001, - 0x760a0001, 0x750b0001, 0x740c0001, 0x730d0001, 0x720e0001, - 0x710f0001, 0x70100001, 0x6f110001, 0x6e120001, 0x6d130001, - 0x6c140001, 0x6b150001, 0x6a160001, 0x69170001, 0x68180001, - 0x67190001, 0x661a0001, 0x651b0001, 0x641c0001, 0x631d0001, - 0x621e0001, 0x611f0001, 0x60200001, 0x49210001, 0x48220001, - 0x47230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, - 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, - 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, - 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, - 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, - 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, - 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, - 0x7a460001, 0x79470001, 0x78480001, 0x77490001, 0x764a0001, - 0x754b0001, 0x744c0001, 0x734d0001, 0x724e0001, 0x714f0001, - 0x70500001, 0x6f510001, 0x6e520001, 0x6d530001, 0x6c540001, - 0x6b550001, 0x6a560001, 0x69570001, 0x68580001, 0x67590001, - 0x665a0001, 0x655b0001, 0x645c0001, 0x635d0001, 0x625e0001, - 0x615f0001, 0x60600001, 0x49610001, 0x48620001, 0x47630001, - 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, - 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, - 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, - 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, - 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, - 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, - 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, - 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, - 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, - 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, - 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, - 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e -}; - -static const struct rtwn_bb_prog rtl8192ce_bb_prog_2t = { - nitems(rtl8192ce_bb_regs), - rtl8192ce_bb_regs, - rtl8192ce_bb_vals_2t, - nitems(rtl8192ce_agc_vals), - rtl8192ce_agc_vals -}; - -static const struct rtwn_bb_prog rtl8192ce_bb_prog_1t = { - nitems(rtl8192ce_bb_regs), - rtl8192ce_bb_regs, - rtl8192ce_bb_vals_1t, - nitems(rtl8192ce_agc_vals), - rtl8192ce_agc_vals -}; - -/* - * RTL8188CU. - */ -static const uint32_t rtl8192cu_bb_vals[] = { - 0x0011800d, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00, - 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, - 0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727, - 0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000, - 0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a, - 0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27, - 0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070, - 0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe, - 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, - 0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, - 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, - 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, - 0x48071d40, 0x03a05633, 0x000000e4, 0x6c6c6c6c, 0x08800000, - 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, - 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, - 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, - 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x0186115b, - 0x0000001f, 0x00b99612, 0x40000100, 0x20f60000, 0x40000100, - 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, - 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, - 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, - 0x00080740, 0x00020403, 0x0000907f, 0x20010201, 0xa0633333, - 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, - 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, - 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, - 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, - 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, - 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, - 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, - 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, 0x63db25a4, - 0x63db25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, - 0x63db25a4, 0x0c1b25a4, 0x63db25a4, 0x63db25a4, 0x63db25a4, - 0x63db25a4, 0x001b25a4, 0x001b25a4, 0x6fdb25a4, 0x00000003, - 0x00000000, 0x00000300 -}; - -static const struct rtwn_bb_prog rtl8192cu_bb_prog = { - nitems(rtl8192ce_bb_regs), - rtl8192ce_bb_regs, - rtl8192cu_bb_vals, - nitems(rtl8192ce_agc_vals), - rtl8192ce_agc_vals -}; - -/* - * RTL8188CE-VAU. - */ -static const uint32_t rtl8188ce_bb_vals[] = { - 0x0011800d, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00, - 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, - 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a, - 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200, - 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070, - 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe, - 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, - 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, - 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, - 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, - 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, - 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, - 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, - 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, - 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db, - 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100, - 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, - 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, - 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, - 0x00080740, 0x00020401, 0x0000907f, 0x20010201, 0xa0633333, - 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, - 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, - 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, - 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, - 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, - 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, - 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, - 0x02140102, 0x28160d05, 0x00000008, 0x001b25a4, 0x631b25a0, - 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, - 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, - 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, 0x00000003, - 0x00000000, 0x00000300 -}; - -static const uint32_t rtl8188ce_agc_vals[] = { - 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, - 0x7b050001, 0x7a060001, 0x79070001, 0x78080001, 0x77090001, - 0x760a0001, 0x750b0001, 0x740c0001, 0x730d0001, 0x720e0001, - 0x710f0001, 0x70100001, 0x6f110001, 0x6e120001, 0x6d130001, - 0x6c140001, 0x6b150001, 0x6a160001, 0x69170001, 0x68180001, - 0x67190001, 0x661a0001, 0x651b0001, 0x641c0001, 0x631d0001, - 0x621e0001, 0x611f0001, 0x60200001, 0x49210001, 0x48220001, - 0x47230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, - 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, - 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, - 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, - 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, - 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, - 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, - 0x7a460001, 0x79470001, 0x78480001, 0x77490001, 0x764a0001, - 0x754b0001, 0x744c0001, 0x734d0001, 0x724e0001, 0x714f0001, - 0x70500001, 0x6f510001, 0x6e520001, 0x6d530001, 0x6c540001, - 0x6b550001, 0x6a560001, 0x69570001, 0x68580001, 0x67590001, - 0x665a0001, 0x655b0001, 0x645c0001, 0x635d0001, 0x625e0001, - 0x615f0001, 0x60600001, 0x49610001, 0x48620001, 0x47630001, - 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, - 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, - 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, - 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, - 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, - 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, - 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, - 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, - 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, - 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, - 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, - 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e -}; - -static const struct rtwn_bb_prog rtl8188ce_bb_prog = { - nitems(rtl8192ce_bb_regs), - rtl8192ce_bb_regs, - rtl8188ce_bb_vals, - nitems(rtl8188ce_agc_vals), - rtl8188ce_agc_vals -}; - -static const uint32_t rtl8188cu_bb_vals[] = { - 0x0011800d, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00, - 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, - 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a, - 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200, - 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070, - 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe, - 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, - 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, - 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, - 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, - 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, - 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, - 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, - 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, - 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db, - 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100, - 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, - 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, - 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, - 0x00080740, 0x00020401, 0x0000907f, 0x20010201, 0xa0633333, - 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, - 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, - 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, - 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, - 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, - 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, - 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, - 0x02140102, 0x28160d05, 0x00000008, 0x001b25a4, 0x631b25a0, - 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, - 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, - 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, 0x00000003, - 0x00000000, 0x00000300 -}; - -static const struct rtwn_bb_prog rtl8188cu_bb_prog = { - nitems(rtl8192ce_bb_regs), - rtl8192ce_bb_regs, - rtl8188cu_bb_vals, - nitems(rtl8188ce_agc_vals), - rtl8188ce_agc_vals -}; - -/* - * RTL8188RU. - */ -static const uint16_t rtl8188ru_bb_regs[] = { - 0x024, 0x028, 0x040, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, - 0x818, 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, - 0x83c, 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, - 0x860, 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, - 0x884, 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, - 0x908, 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, - 0xa1c, 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04, - 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, - 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, - 0xc50, 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, - 0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, - 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, - 0xcbc, 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc, - 0xce0, 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, 0xd08, 0xd0c, 0xd10, - 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c, 0xd40, 0xd44, - 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, 0xd60, 0xd64, 0xd68, - 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00, 0xe04, 0xe08, 0xe10, 0xe14, - 0xe18, 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, - 0xe48, 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c, 0xe60, 0xe68, 0xe6c, - 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, 0xed0, - 0xed4, 0xed8, 0xedc, 0xee0, 0xeec, 0xee8, 0xf14, 0xf4c, 0xf00 -}; - -static const uint32_t rtl8188ru_bb_vals[] = { - 0x0011800d, 0x00ffdb83, 0x000c0004, 0x80040000, 0x00000001, - 0x0000fc00, 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, - 0x00000000, 0x01000100, 0x00390204, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x569a569a, 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, - 0x32323200, 0x03000300, 0x22004000, 0x00000808, 0x00ffc3f1, - 0xc0083070, 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, - 0xfffffffe, 0x40302010, 0x00706050, 0x00000000, 0x00000023, - 0x00000000, 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, - 0x2e68120f, 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, - 0x15160000, 0x070b0f12, 0x00000104, 0x00d30000, 0x101fbf00, - 0x00000007, 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, - 0x08800000, 0x40000100, 0x08800000, 0x40000100, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, - 0x49795994, 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, - 0x007f037f, 0x6954342e, 0x43bc0094, 0x6954342f, 0x433c0094, - 0x00000000, 0x5116848b, 0x47c00bff, 0x00000036, 0x2c56000d, - 0x018610db, 0x0000001f, 0x00b91612, 0x24000090, 0x20f60000, - 0x24000090, 0x20200000, 0x00121820, 0x00000000, 0x00121820, - 0x00007f7f, 0x00000000, 0x00000080, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x28000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x64b22427, 0x00766932, 0x00222222, 0x00000000, 0x37644302, - 0x2f97d40c, 0x00080740, 0x00020401, 0x0000907f, 0x20010201, - 0xa0633333, 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, - 0x80608000, 0x00000000, 0x00027293, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x6437140a, 0x00000000, 0x00000000, - 0x30032064, 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, - 0x1812362e, 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, - 0x03902a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, - 0x00000000, 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, - 0x01007c00, 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, - 0x10008c1f, 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, - 0x631b25a0, 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, - 0x081b25a0, 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, - 0x631b25a0, 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, - 0x31555448, 0x00000003, 0x00000000, 0x00000300 -}; - -static const uint32_t rtl8188ru_agc_vals[] = { - 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, - 0x7b050001, 0x7b060001, 0x7b070001, 0x7b080001, 0x7a090001, - 0x790a0001, 0x780b0001, 0x770c0001, 0x760d0001, 0x750e0001, - 0x740f0001, 0x73100001, 0x72110001, 0x71120001, 0x70130001, - 0x6f140001, 0x6e150001, 0x6d160001, 0x6c170001, 0x6b180001, - 0x6a190001, 0x691a0001, 0x681b0001, 0x671c0001, 0x661d0001, - 0x651e0001, 0x641f0001, 0x63200001, 0x62210001, 0x61220001, - 0x60230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, - 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, - 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, - 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, - 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, - 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, - 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, - 0x7b460001, 0x7b470001, 0x7b480001, 0x7a490001, 0x794a0001, - 0x784b0001, 0x774c0001, 0x764d0001, 0x754e0001, 0x744f0001, - 0x73500001, 0x72510001, 0x71520001, 0x70530001, 0x6f540001, - 0x6e550001, 0x6d560001, 0x6c570001, 0x6b580001, 0x6a590001, - 0x695a0001, 0x685b0001, 0x675c0001, 0x665d0001, 0x655e0001, - 0x645f0001, 0x63600001, 0x62610001, 0x61620001, 0x60630001, - 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, - 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, - 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, - 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, - 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, - 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, - 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, - 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, - 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, - 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, - 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, - 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e -}; - -static const struct rtwn_bb_prog rtl8188ru_bb_prog = { - nitems(rtl8188ru_bb_regs), - rtl8188ru_bb_regs, - rtl8188ru_bb_vals, - nitems(rtl8188ru_agc_vals), - rtl8188ru_agc_vals -}; - -/* - * RF initialization values. + * Structure for RF initialization values. */ struct rtwn_rf_prog { int count; - const uint8_t *regs; - const uint32_t *vals; -}; - -/* - * RTL8192CU and RTL8192CE-VAU. - */ -static const uint8_t rtl8192ce_rf1_regs[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, - 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2a, 0x2b, - 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, - 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, - 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, - 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, - 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, - 0x2c, 0x2a, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, - 0x11, 0x10, 0x11, 0x10, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, - 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x00, - 0x18, 0xfe, 0xfe, 0x1f, 0xfe, 0xfe, 0x1e, 0x1f, 0x00 -}; - -static const uint32_t rtl8192ce_rf1_vals[] = { - 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, - 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255, - 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000, - 0x00000, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x577c0, - 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, - 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, - 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, - 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, - 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, - 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, - 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, - 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, - 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, - 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, - 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0x32000, - 0x71000, 0xb0000, 0xfc000, 0x287af, 0x244b7, 0x204ab, 0x1c49f, - 0x18493, 0x14297, 0x10295, 0x0c298, 0x0819c, 0x040a8, 0x0001c, - 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424, - 0xcf424, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, - 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000, - 0x30159 -}; - -static const uint8_t rtl8192ce_rf2_regs[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, - 0x15, 0x15, 0x16, 0x16, 0x16, 0x16 -}; - -static const uint32_t rtl8192ce_rf2_vals[] = { - 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, - 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x32000, 0x71000, - 0xb0000, 0xfc000, 0x287af, 0x244b7, 0x204ab, 0x1c49f, 0x18493, - 0x14297, 0x10295, 0x0c298, 0x0819c, 0x040a8, 0x0001c, 0x1944c, - 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424, 0xcf424, - 0xe0330, 0xa0330, 0x60330, 0x20330 -}; - -static const struct rtwn_rf_prog rtl8192ce_rf_prog[] = { - { - nitems(rtl8192ce_rf1_regs), - rtl8192ce_rf1_regs, - rtl8192ce_rf1_vals - }, - { - nitems(rtl8192ce_rf2_regs), - rtl8192ce_rf2_regs, - rtl8192ce_rf2_vals - } -}; - -/* - * RTL8188CE-VAU. - */ -static const uint32_t rtl8188ce_rf_vals[] = { - 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, - 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255, - 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000, - 0x00000, 0x01558, 0x00060, 0x00483, 0x4f200, 0xec7d9, 0x577c0, - 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, - 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, - 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, - 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, - 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, - 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, - 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, - 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, - 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, - 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, - 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0x32000, - 0x71000, 0xb0000, 0xfc000, 0x287b3, 0x244b7, 0x204ab, 0x1c49f, - 0x18493, 0x1429b, 0x10299, 0x0c29c, 0x081a0, 0x040ac, 0x00020, - 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424, - 0xcf424, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, - 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000, - 0x30159 -}; - -static const struct rtwn_rf_prog rtl8188ce_rf_prog[] = { - { - nitems(rtl8192ce_rf1_regs), - rtl8192ce_rf1_regs, - rtl8188ce_rf_vals - } + const uint8_t *reg; + const uint32_t *val; + const uint8_t cond[RTWN_MAX_CONDITIONS]; + const struct rtwn_rf_prog *next; }; -/* - * RTL8188CU. - */ -static const uint32_t rtl8188cu_rf_vals[] = { - 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, - 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255, - 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000, - 0x00000, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x577c0, - 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, - 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, - 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, - 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, - 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, - 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, - 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, - 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, - 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, - 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, - 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0x32000, - 0x71000, 0xb0000, 0xfc000, 0x287b3, 0x244b7, 0x204ab, 0x1c49f, - 0x18493, 0x1429b, 0x10299, 0x0c29c, 0x081a0, 0x040ac, 0x00020, - 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f405, 0x4f405, 0x8f405, - 0xcf405, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, - 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000, - 0x30159 -}; +/* XXX move to net80211. */ +static __inline int +rtwn_chan2centieee(const struct ieee80211_channel *c) +{ + int chan; -static const struct rtwn_rf_prog rtl8188cu_rf_prog[] = { - { - nitems(rtl8192ce_rf1_regs), - rtl8192ce_rf1_regs, - rtl8188cu_rf_vals - } -}; - -/* - * RTL8188RU. - */ -static const uint32_t rtl8188ru_rf_vals[] = { - 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb0, - 0x54867, 0x8992e, 0x0e529, 0x39ce7, 0x00451, 0x00000, 0x00255, - 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000, - 0x0083c, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x977c0, - 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, - 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, - 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, - 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, - 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, - 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, - 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, - 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, - 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, - 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, - 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0xd8000, - 0x90000, 0x51000, 0x12000, 0x28fb4, 0x24fa8, 0x207a4, 0x1c798, - 0x183a4, 0x14398, 0x101a4, 0x0c198, 0x080a4, 0x04098, 0x00014, - 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f405, 0x4f405, 0x8f405, - 0xcf405, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, - 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000, - 0x30159 -}; - -static const struct rtwn_rf_prog rtl8188ru_rf_prog[] = { - { - nitems(rtl8192ce_rf1_regs), - rtl8192ce_rf1_regs, - rtl8188ru_rf_vals - } -}; - -struct rtwn_txpwr { - uint8_t pwr[3][28]; -}; - -/* - * Per RF chain/group/rate Tx gain values. - */ -static const struct rtwn_txpwr rtl8192cu_txagc[] = { - { { /* Chain 0. */ - { /* Group 0. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x0c, 0x0c, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* OFDM6~54. */ - 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* MCS0~7. */ - 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02 /* MCS8~15. */ - }, - { /* Group 1. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - }, - { /* Group 2. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - } - } }, - { { /* Chain 1. */ - { /* Group 0. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - }, - { /* Group 1. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - }, - { /* Group 2. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - } - } } -}; - -static const struct rtwn_txpwr rtl8188ru_txagc[] = { - { { /* Chain 0. */ - { /* Group 0. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x08, 0x08, 0x08, 0x06, 0x06, 0x04, 0x04, 0x00, /* OFDM6~54. */ - 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00, /* MCS0~7. */ - 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00 /* MCS8~15. */ - }, - { /* Group 1. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - }, - { /* Group 2. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - } - } } -}; - -#define RTWN_LOCK_INIT(_sc) \ - mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \ - MTX_NETWORK_LOCK, MTX_DEF) -#define RTWN_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) -#define RTWN_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) -#define RTWN_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) -#define RTWN_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) + chan = c->ic_ieee; + if (c->ic_extieee != 0) + chan = (chan + c->ic_extieee) / 2; + return (chan); +} diff --git a/sys/dev/rtwn/if_rtwnvar.h b/sys/dev/rtwn/if_rtwnvar.h new file mode 100644 index 000000000000..c07fd2f5002e --- /dev/null +++ b/sys/dev/rtwn/if_rtwnvar.h @@ -0,0 +1,609 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef IF_RTWNVAR_H +#define IF_RTWNVAR_H + +#include "opt_rtwn.h" + +#define RTWN_TX_DESC_SIZE 64 + +#define RTWN_RXBUFSZ (8 * 1024) +#define RTWN_TXBUFSZ (RTWN_TX_DESC_SIZE + IEEE80211_MAX_LEN) + +#define RTWN_BCN_MAX_SIZE 512 +#define RTWN_CAM_ENTRY_LIMIT 64 + +#define RTWN_MACID_BC 1 /* Broadcast. */ +#define RTWN_MACID_UNDEFINED 0x7fff +#define RTWN_MACID_VALID 0x8000 +#define RTWN_MACID_LIMIT 128 + +#define RTWN_TX_TIMEOUT 5000 /* ms */ +#define RTWN_MAX_EPOUT 4 +#define RTWN_PORT_COUNT 2 + +#define RTWN_LED_LINK 0 +#define RTWN_LED_DATA 1 + +struct rtwn_rx_radiotap_header { + struct ieee80211_radiotap_header wr_ihdr; + uint64_t wr_tsft; + uint8_t wr_flags; + uint8_t wr_rate; + uint16_t wr_chan_freq; + uint16_t wr_chan_flags; + int8_t wr_dbm_antsignal; + int8_t wr_dbm_antnoise; +} __packed __aligned(8); + +#define RTWN_RX_RADIOTAP_PRESENT \ + (1 << IEEE80211_RADIOTAP_TSFT | \ + 1 << IEEE80211_RADIOTAP_FLAGS | \ + 1 << IEEE80211_RADIOTAP_RATE | \ + 1 << IEEE80211_RADIOTAP_CHANNEL | \ + 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL | \ + 1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) + +struct rtwn_tx_radiotap_header { + struct ieee80211_radiotap_header wt_ihdr; + uint8_t wt_flags; + uint16_t wt_chan_freq; + uint16_t wt_chan_flags; +} __packed __aligned(8); + +#define RTWN_TX_RADIOTAP_PRESENT \ + (1 << IEEE80211_RADIOTAP_FLAGS | \ + 1 << IEEE80211_RADIOTAP_CHANNEL) + +struct rtwn_tx_buf { + uint8_t txd[RTWN_TX_DESC_SIZE]; +} __attribute__((aligned(4))); + +struct rtwn_softc; + +union sec_param { + struct ieee80211_key key; + int macid; +}; + +#define CMD_FUNC_PROTO void (*func)(struct rtwn_softc *, \ + union sec_param *) + +struct rtwn_cmdq { + union sec_param data; + CMD_FUNC_PROTO; +}; +#define RTWN_CMDQ_SIZE 16 + +struct rtwn_node { + struct ieee80211_node ni; /* must be the first */ + int id; + int8_t last_rssi; + int avg_pwdb; +}; +#define RTWN_NODE(ni) ((struct rtwn_node *)(ni)) + +struct rtwn_vap { + struct ieee80211vap vap; + int id; +#define RTWN_VAP_ID_INVALID -1 + int curr_mode; + + struct rtwn_tx_buf bcn_desc; + struct mbuf *bcn_mbuf; + + struct callout tsf_sync_adhoc; + struct task tsf_sync_adhoc_task; + + const struct ieee80211_key *keys[IEEE80211_WEP_NKID]; + + int (*newstate)(struct ieee80211vap *, + enum ieee80211_state, int); + void (*recv_mgmt)(struct ieee80211_node *, + struct mbuf *, int, + const struct ieee80211_rx_stats *, + int, int); +}; +#define RTWN_VAP(vap) ((struct rtwn_vap *)(vap)) + +/* + * Rx data types. + */ +enum { + RTWN_RX_DATA, + RTWN_RX_TX_REPORT, + RTWN_RX_OTHER +}; + +/* + * Firmware reset reasons. + */ +enum { + RTWN_FW_RESET_DOWNLOAD, + RTWN_FW_RESET_CHECKSUM, + RTWN_FW_RESET_SHUTDOWN +}; + +/* + * Rate control algorithm selection. + */ +enum { + RTWN_RATECTL_NONE, + RTWN_RATECTL_NET80211, + RTWN_RATECTL_FW, + RTWN_RATECTL_MAX +}; + +/* + * Control h/w crypto usage. + */ +enum { + RTWN_CRYPTO_SW, + RTWN_CRYPTO_PAIR, + RTWN_CRYPTO_FULL, + RTWN_CRYPTO_MAX, +}; + +struct rtwn_softc { + struct ieee80211com sc_ic; + struct mbufq sc_snd; + device_t sc_dev; + +#if 1 + int sc_ht40; +#endif + uint32_t sc_debug; + int sc_hwcrypto; + int sc_ratectl_sysctl; + int sc_ratectl; + + uint8_t sc_detached; + uint8_t sc_flags; +/* Device flags */ +#define RTWN_FLAG_CCK_HIPWR 0x01 +#define RTWN_FLAG_EXT_HDR 0x02 +#define RTWN_FLAG_CAM_FIXED 0x04 +/* Driver state */ +#define RTWN_STARTED 0x08 +#define RTWN_RUNNING 0x10 +#define RTWN_FW_LOADED 0x20 +#define RTWN_TEMP_MEASURED 0x40 + +#define RTWN_CHIP_HAS_BCNQ1(_sc) \ + ((_sc)->bcn_status_reg[0] != (_sc)->bcn_status_reg[1]) + + void *sc_priv; + const char *name; + int sc_ant; + + int8_t last_rssi; + uint8_t thcal_temp; + int cur_bcnq_id; + + int nvaps; + int ap_vaps; + int bcn_vaps; + int mon_vaps; + + int vaps_running; + int monvaps_running; + + uint16_t next_rom_addr; + uint8_t keys_bmap[roundup2(RTWN_CAM_ENTRY_LIMIT, NBBY)]; + + struct rtwn_vap *vaps[RTWN_PORT_COUNT]; + struct ieee80211_node *node_list[RTWN_MACID_LIMIT]; + struct mtx nt_mtx; + + struct callout sc_calib_to; + struct callout sc_pwrmode_init; +#ifndef D4054 + struct callout sc_watchdog_to; + int sc_tx_timer; +#endif + + struct mtx sc_mtx; + + struct rtwn_cmdq cmdq[RTWN_CMDQ_SIZE]; + struct mtx cmdq_mtx; + struct task cmdq_task; + uint8_t cmdq_first; + uint8_t cmdq_last; + + struct wmeParams cap_wmeParams[WME_NUM_AC]; + + struct rtwn_rx_radiotap_header sc_rxtap; + struct rtwn_tx_radiotap_header sc_txtap; + + int ntxchains; + int nrxchains; + + int ledlink; + uint8_t thermal_meter; + + int sc_tx_n_active; + uint8_t qfullmsk; + + /* Firmware-specific */ + const char *fwname; + uint16_t fwver; + uint16_t fwsig; + int fwcur; + + void (*sc_node_free)(struct ieee80211_node *); + void (*sc_scan_curchan)(struct ieee80211_scan_state *, + unsigned long); + + /* Interface-specific. */ + int (*sc_write_1)(struct rtwn_softc *, uint16_t, + uint8_t); + int (*sc_write_2)(struct rtwn_softc *, uint16_t, + uint16_t); + int (*sc_write_4)(struct rtwn_softc *, uint16_t, + uint32_t); + uint8_t (*sc_read_1)(struct rtwn_softc *, uint16_t); + uint16_t (*sc_read_2)(struct rtwn_softc *, uint16_t); + uint32_t (*sc_read_4)(struct rtwn_softc *, uint16_t); + /* XXX eliminate */ + void (*sc_delay)(struct rtwn_softc *, int); + int (*sc_tx_start)(struct rtwn_softc *, + struct ieee80211_node *, struct mbuf *, uint8_t *, + uint8_t, int); + void (*sc_start_xfers)(struct rtwn_softc *); + void (*sc_reset_lists)(struct rtwn_softc *, + struct ieee80211vap *); + void (*sc_abort_xfers)(struct rtwn_softc *); + int (*sc_fw_write_block)(struct rtwn_softc *, + const uint8_t *, uint16_t, int); + uint16_t (*sc_get_qmap)(struct rtwn_softc *); + void (*sc_set_desc_addr)(struct rtwn_softc *); + void (*sc_drop_incorrect_tx)(struct rtwn_softc *); + + /* Device-specific. */ + uint32_t (*sc_rf_read)(struct rtwn_softc *, int, uint8_t); + void (*sc_rf_write)(struct rtwn_softc *, int, uint8_t, + uint32_t); + int (*sc_check_condition)(struct rtwn_softc *, + const uint8_t[]); + void (*sc_efuse_postread)(struct rtwn_softc *); + void (*sc_parse_rom)(struct rtwn_softc *, uint8_t *); + void (*sc_set_led)(struct rtwn_softc *, int, int); + int (*sc_power_on)(struct rtwn_softc *); + void (*sc_power_off)(struct rtwn_softc *); +#ifndef RTWN_WITHOUT_UCODE + void (*sc_fw_reset)(struct rtwn_softc *, int); + void (*sc_fw_download_enable)(struct rtwn_softc *, int); +#endif + int (*sc_set_page_size)(struct rtwn_softc *); + void (*sc_lc_calib)(struct rtwn_softc *); + void (*sc_iq_calib)(struct rtwn_softc *); + void (*sc_read_chipid_vendor)(struct rtwn_softc *, + uint32_t); + void (*sc_adj_devcaps)(struct rtwn_softc *); + void (*sc_vap_preattach)(struct rtwn_softc *, + struct ieee80211vap *); + void (*sc_postattach)(struct rtwn_softc *); + void (*sc_detach_private)(struct rtwn_softc *); + void (*sc_fill_tx_desc)(struct rtwn_softc *, + struct ieee80211_node *, struct mbuf *, + void *, uint8_t, int); + void (*sc_fill_tx_desc_raw)(struct rtwn_softc *, + struct ieee80211_node *, struct mbuf *, + void *, const struct ieee80211_bpf_params *); + void (*sc_fill_tx_desc_null)(struct rtwn_softc *, + void *, int, int, int); + void (*sc_dump_tx_desc)(struct rtwn_softc *, const void *); + uint8_t (*sc_tx_radiotap_flags)(const void *); + uint8_t (*sc_rx_radiotap_flags)(const void *); + void (*sc_beacon_init)(struct rtwn_softc *, void *, int); + void (*sc_beacon_enable)(struct rtwn_softc *, int, int); + void (*sc_beacon_set_rate)(void *, int); + void (*sc_beacon_select)(struct rtwn_softc *, int); + void (*sc_set_chan)(struct rtwn_softc *, + struct ieee80211_channel *); + void (*sc_set_media_status)(struct rtwn_softc *, int); +#ifndef RTWN_WITHOUT_UCODE + int (*sc_set_rsvd_page)(struct rtwn_softc *, int, int, + int); + int (*sc_set_pwrmode)(struct rtwn_softc *, + struct ieee80211vap *, int); + void (*sc_set_rssi)(struct rtwn_softc *); +#endif + int8_t (*sc_get_rssi_cck)(struct rtwn_softc *, void *); + int8_t (*sc_get_rssi_ofdm)(struct rtwn_softc *, void *); + int (*sc_classify_intr)(struct rtwn_softc *, void *, int); + void (*sc_handle_tx_report)(struct rtwn_softc *, uint8_t *, + int); + void (*sc_handle_c2h_report)(struct rtwn_softc *, + uint8_t *, int); + int (*sc_check_frame)(struct rtwn_softc *, struct mbuf *); + void (*sc_temp_measure)(struct rtwn_softc *); + uint8_t (*sc_temp_read)(struct rtwn_softc *); + void (*sc_init_tx_agg)(struct rtwn_softc *); + void (*sc_init_rx_agg)(struct rtwn_softc *); + void (*sc_init_intr)(struct rtwn_softc *); + void (*sc_init_ampdu)(struct rtwn_softc *); + void (*sc_init_edca)(struct rtwn_softc *); + void (*sc_init_bb)(struct rtwn_softc *); + void (*sc_init_rf)(struct rtwn_softc *); + void (*sc_init_antsel)(struct rtwn_softc *); + void (*sc_post_init)(struct rtwn_softc *); + int (*sc_init_bcnq1_boundary)(struct rtwn_softc *); + + const uint8_t *chan_list_5ghz[3]; + int chan_num_5ghz[3]; + + const struct rtwn_mac_prog *mac_prog; + int mac_size; + const struct rtwn_bb_prog *bb_prog; + int bb_size; + const struct rtwn_agc_prog *agc_prog; + int agc_size; + const struct rtwn_rf_prog *rf_prog; + + int page_count; + int pktbuf_count; + + int ackto; + + int npubqpages; + int nhqpages; + int nnqpages; + int nlqpages; + int page_size; + + int txdesc_len; + int efuse_maxlen; + int efuse_maplen; + + uint16_t rx_dma_size; + + int macid_limit; + int cam_entry_limit; + int fwsize_limit; + int temp_delta; + + uint16_t bcn_status_reg[RTWN_PORT_COUNT]; + uint32_t rcr; /* Rx filter */ +}; +MALLOC_DECLARE(M_RTWN_PRIV); + +#define RTWN_LOCK(sc) mtx_lock(&(sc)->sc_mtx) +#define RTWN_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) +#define RTWN_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) + +#define RTWN_CMDQ_LOCK_INIT(sc) \ + mtx_init(&(sc)->cmdq_mtx, "cmdq lock", NULL, MTX_DEF) +#define RTWN_CMDQ_LOCK(sc) mtx_lock(&(sc)->cmdq_mtx) +#define RTWN_CMDQ_UNLOCK(sc) mtx_unlock(&(sc)->cmdq_mtx) +#define RTWN_CMDQ_LOCK_INITIALIZED(sc) mtx_initialized(&(sc)->cmdq_mtx) +#define RTWN_CMDQ_LOCK_DESTROY(sc) mtx_destroy(&(sc)->cmdq_mtx) + +#define RTWN_NT_LOCK_INIT(sc) \ + mtx_init(&(sc)->nt_mtx, "node table lock", NULL, MTX_DEF) +#define RTWN_NT_LOCK(sc) mtx_lock(&(sc)->nt_mtx) +#define RTWN_NT_UNLOCK(sc) mtx_unlock(&(sc)->nt_mtx) +#define RTWN_NT_LOCK_INITIALIZED(sc) mtx_initialized(&(sc)->nt_mtx) +#define RTWN_NT_LOCK_DESTROY(sc) mtx_destroy(&(sc)->nt_mtx) + + +void rtwn_sysctlattach(struct rtwn_softc *); + +int rtwn_attach(struct rtwn_softc *); +void rtwn_detach(struct rtwn_softc *); +void rtwn_resume(struct rtwn_softc *); +void rtwn_suspend(struct rtwn_softc *); + + +/* Interface-specific. */ +#define rtwn_write_1(_sc, _addr, _val) \ + (((_sc)->sc_write_1)((_sc), (_addr), (_val))) +#define rtwn_write_2(_sc, _addr, _val) \ + (((_sc)->sc_write_2)((_sc), (_addr), (_val))) +#define rtwn_write_4(_sc, _addr, _val) \ + (((_sc)->sc_write_4)((_sc), (_addr), (_val))) +#define rtwn_read_1(_sc, _addr) \ + (((_sc)->sc_read_1)((_sc), (_addr))) +#define rtwn_read_2(_sc, _addr) \ + (((_sc)->sc_read_2)((_sc), (_addr))) +#define rtwn_read_4(_sc, _addr) \ + (((_sc)->sc_read_4)((_sc), (_addr))) +#define rtwn_delay(_sc, _usec) \ + (((_sc)->sc_delay)((_sc), (_usec))) +#define rtwn_tx_start(_sc, _ni, _m, _desc, _type, _id) \ + (((_sc)->sc_tx_start)((_sc), (_ni), (_m), (_desc), (_type), (_id))) +#define rtwn_start_xfers(_sc) \ + (((_sc)->sc_start_xfers)((_sc))) +#define rtwn_reset_lists(_sc, _vap) \ + (((_sc)->sc_reset_lists)((_sc), (_vap))) +#define rtwn_abort_xfers(_sc) \ + (((_sc)->sc_abort_xfers)((_sc))) +#define rtwn_fw_write_block(_sc, _buf, _reg, _len) \ + (((_sc)->sc_fw_write_block)((_sc), (_buf), (_reg), (_len))) +#define rtwn_get_qmap(_sc) \ + (((_sc)->sc_get_qmap)((_sc))) +#define rtwn_set_desc_addr(_sc) \ + (((_sc)->sc_set_desc_addr)((_sc))) +#define rtwn_drop_incorrect_tx(_sc) \ + (((_sc)->sc_drop_incorrect_tx)((_sc))) + +/* Aliases. */ +#define rtwn_bb_write rtwn_write_4 +#define rtwn_bb_read rtwn_read_4 +#define rtwn_bb_setbits rtwn_setbits_4 + +/* Device-specific. */ +#define rtwn_rf_read(_sc, _chain, _addr) \ + (((_sc)->sc_rf_read)((_sc), (_chain), (_addr))) +#define rtwn_rf_write(_sc, _chain, _addr, _val) \ + (((_sc)->sc_rf_write)((_sc), (_chain), (_addr), (_val))) +#define rtwn_check_condition(_sc, _cond) \ + (((_sc)->sc_check_condition)((_sc), (_cond))) +#define rtwn_efuse_postread(_sc) \ + (((_sc)->sc_efuse_postread)((_sc))) +#define rtwn_parse_rom(_sc, _rom) \ + (((_sc)->sc_parse_rom)((_sc), (_rom))) +#define rtwn_set_led(_sc, _led, _on) \ + (((_sc)->sc_set_led)((_sc), (_led), (_on))) +#define rtwn_get_rssi_cck(_sc, _physt) \ + (((_sc)->sc_get_rssi_cck)((_sc), (_physt))) +#define rtwn_get_rssi_ofdm(_sc, _physt) \ + (((_sc)->sc_get_rssi_ofdm)((_sc), (_physt))) +#define rtwn_power_on(_sc) \ + (((_sc)->sc_power_on)((_sc))) +#define rtwn_power_off(_sc) \ + (((_sc)->sc_power_off)((_sc))) +#ifndef RTWN_WITHOUT_UCODE +#define rtwn_fw_reset(_sc, _reason) \ + (((_sc)->sc_fw_reset)((_sc), (_reason))) +#define rtwn_fw_download_enable(_sc, _enable) \ + (((_sc)->sc_fw_download_enable)((_sc), (_enable))) +#endif +#define rtwn_set_page_size(_sc) \ + (((_sc)->sc_set_page_size)((_sc))) +#define rtwn_lc_calib(_sc) \ + (((_sc)->sc_lc_calib)((_sc))) +#define rtwn_iq_calib(_sc) \ + (((_sc)->sc_iq_calib)((_sc))) +#define rtwn_read_chipid_vendor(_sc, _reg) \ + (((_sc)->sc_read_chipid_vendor)((_sc), (_reg))) +#define rtwn_adj_devcaps(_sc) \ + (((_sc)->sc_adj_devcaps)((_sc))) +#define rtwn_vap_preattach(_sc, _vap) \ + (((_sc)->sc_vap_preattach)((_sc), (_vap))) +#define rtwn_postattach(_sc) \ + (((_sc)->sc_postattach)((_sc))) +#define rtwn_detach_private(_sc) \ + (((_sc)->sc_detach_private)((_sc))) +#define rtwn_fill_tx_desc(_sc, _ni, _m, \ + _buf, _ridx, _maxretry) \ + (((_sc)->sc_fill_tx_desc)((_sc), (_ni), \ + (_m), (_buf), (_ridx), (_maxretry))) +#define rtwn_fill_tx_desc_raw(_sc, _ni, _m, \ + _buf, _params) \ + (((_sc)->sc_fill_tx_desc_raw)((_sc), (_ni), \ + (_m), (_buf), (_params))) +#define rtwn_fill_tx_desc_null(_sc, _buf, _11b, _qos, _id) \ + (((_sc)->sc_fill_tx_desc_null)((_sc), \ + (_buf), (_11b), (_qos), (_id))) +#define rtwn_dump_tx_desc(_sc, _desc) \ + (((_sc)->sc_dump_tx_desc)((_sc), (_desc))) +#define rtwn_tx_radiotap_flags(_sc, _buf) \ + (((_sc)->sc_tx_radiotap_flags)((_buf))) +#define rtwn_rx_radiotap_flags(_sc, _buf) \ + (((_sc)->sc_rx_radiotap_flags)((_buf))) +#define rtwn_set_chan(_sc, _c) \ + (((_sc)->sc_set_chan)((_sc), (_c))) +#ifndef RTWN_WITHOUT_UCODE +#define rtwn_set_rsvd_page(_sc, _resp, _null, _qos_null) \ + (((_sc)->sc_set_rsvd_page)((_sc), \ + (_resp), (_null), (_qos_null))) +#define rtwn_set_pwrmode(_sc, _vap, _off) \ + (((_sc)->sc_set_pwrmode)((_sc), (_vap), (_off))) +#define rtwn_set_rssi(_sc) \ + (((_sc)->sc_set_rssi)((_sc))) +#endif +#define rtwn_classify_intr(_sc, _buf, _len) \ + (((_sc)->sc_classify_intr)((_sc), (_buf), (_len))) +#define rtwn_handle_tx_report(_sc, _buf, _len) \ + (((_sc)->sc_handle_tx_report)((_sc), (_buf), (_len))) +#define rtwn_handle_c2h_report(_sc, _buf, _len) \ + (((_sc)->sc_handle_c2h_report)((_sc), (_buf), (_len))) +#define rtwn_check_frame(_sc, _m) \ + (((_sc)->sc_check_frame)((_sc), (_m))) +#define rtwn_beacon_init(_sc, _buf, _id) \ + (((_sc)->sc_beacon_init)((_sc), (_buf), (_id))) +#define rtwn_beacon_enable(_sc, _id, _enable) \ + (((_sc)->sc_beacon_enable)((_sc), (_id), (_enable))) +#define rtwn_beacon_set_rate(_sc, _buf, _is5ghz) \ + (((_sc)->sc_beacon_set_rate)((_buf), (_is5ghz))) +#define rtwn_beacon_select(_sc, _id) \ + (((_sc)->sc_beacon_select)((_sc), (_id))) +#define rtwn_temp_measure(_sc) \ + (((_sc)->sc_temp_measure)((_sc))) +#define rtwn_temp_read(_sc) \ + (((_sc)->sc_temp_read)((_sc))) +#define rtwn_init_tx_agg(_sc) \ + (((_sc)->sc_init_tx_agg)((_sc))) +#define rtwn_init_rx_agg(_sc) \ + (((_sc)->sc_init_rx_agg)((_sc))) +#define rtwn_init_intr(_sc) \ + (((_sc)->sc_init_intr)((_sc))) +#define rtwn_init_ampdu(_sc) \ + (((_sc)->sc_init_ampdu)((_sc))) +#define rtwn_init_edca(_sc) \ + (((_sc)->sc_init_edca)((_sc))) +#define rtwn_init_bb(_sc) \ + (((_sc)->sc_init_bb)((_sc))) +#define rtwn_init_rf(_sc) \ + (((_sc)->sc_init_rf)((_sc))) +#define rtwn_init_antsel(_sc) \ + (((_sc)->sc_init_antsel)((_sc))) +#define rtwn_post_init(_sc) \ + (((_sc)->sc_post_init)((_sc))) +#define rtwn_init_bcnq1_boundary(_sc) \ + (((_sc)->sc_init_bcnq1_boundary)((_sc))) + + +/* + * Methods to access subfields in registers. + */ +static __inline int +rtwn_setbits_1(struct rtwn_softc *sc, uint16_t addr, uint8_t clr, + uint8_t set) +{ + return (rtwn_write_1(sc, addr, + (rtwn_read_1(sc, addr) & ~clr) | set)); +} + +static __inline int +rtwn_setbits_1_shift(struct rtwn_softc *sc, uint16_t addr, uint32_t clr, + uint32_t set, int shift) +{ + return (rtwn_setbits_1(sc, addr + shift, clr >> shift * NBBY, + set >> shift * NBBY)); +} + +static __inline int +rtwn_setbits_2(struct rtwn_softc *sc, uint16_t addr, uint16_t clr, + uint16_t set) +{ + return (rtwn_write_2(sc, addr, + (rtwn_read_2(sc, addr) & ~clr) | set)); +} + +static __inline int +rtwn_setbits_4(struct rtwn_softc *sc, uint16_t addr, uint32_t clr, + uint32_t set) +{ + return (rtwn_write_4(sc, addr, + (rtwn_read_4(sc, addr) & ~clr) | set)); +} + +static __inline void +rtwn_rf_setbits(struct rtwn_softc *sc, int chain, uint8_t addr, + uint32_t clr, uint32_t set) +{ + rtwn_rf_write(sc, chain, addr, + (rtwn_rf_read(sc, chain, addr) & ~clr) | set); +} + +#endif /* IF_RTWNVAR_H */ diff --git a/sys/dev/rtwn/pci/rtwn_pci_attach.c b/sys/dev/rtwn/pci/rtwn_pci_attach.c new file mode 100644 index 000000000000..e48ae8141291 --- /dev/null +++ b/sys/dev/rtwn/pci/rtwn_pci_attach.c @@ -0,0 +1,687 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + + +static device_probe_t rtwn_pci_probe; +static device_attach_t rtwn_pci_attach; +static device_detach_t rtwn_pci_detach; +static device_shutdown_t rtwn_pci_shutdown; +static device_suspend_t rtwn_pci_suspend; +static device_resume_t rtwn_pci_resume; + +static int rtwn_pci_alloc_rx_list(struct rtwn_softc *); +static void rtwn_pci_reset_rx_list(struct rtwn_softc *); +static void rtwn_pci_free_rx_list(struct rtwn_softc *); +static int rtwn_pci_alloc_tx_list(struct rtwn_softc *, int); +static void rtwn_pci_reset_tx_list(struct rtwn_softc *, + struct ieee80211vap *, int); +static void rtwn_pci_free_tx_list(struct rtwn_softc *, int); +static void rtwn_pci_reset_lists(struct rtwn_softc *, + struct ieee80211vap *); +static int rtwn_pci_fw_write_block(struct rtwn_softc *, + const uint8_t *, uint16_t, int); +static uint16_t rtwn_pci_get_qmap(struct rtwn_softc *); +static void rtwn_pci_set_desc_addr(struct rtwn_softc *); +static void rtwn_pci_attach_methods(struct rtwn_softc *); + + +static int matched_chip = RTWN_CHIP_MAX_PCI; + +static int +rtwn_pci_probe(device_t dev) +{ + const struct rtwn_pci_ident *ident; + + for (ident = rtwn_pci_ident_table; ident->name != NULL; ident++) { + if (pci_get_vendor(dev) == ident->vendor && + pci_get_device(dev) == ident->device) { + matched_chip = ident->chip; + device_set_desc(dev, ident->name); + return (BUS_PROBE_DEFAULT); + } + } + return (ENXIO); +} + +static int +rtwn_pci_alloc_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_rx_ring *rx_ring = &pc->rx_ring; + struct rtwn_rx_data *rx_data; + bus_size_t size; + int i, error; + + /* Allocate Rx descriptors. */ + size = sizeof(struct r92ce_rx_stat) * RTWN_PCI_RX_LIST_COUNT; + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + size, 1, size, 0, NULL, NULL, &rx_ring->desc_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create rx desc DMA tag\n"); + goto fail; + } + + error = bus_dmamem_alloc(rx_ring->desc_dmat, (void **)&rx_ring->desc, + BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, + &rx_ring->desc_map); + if (error != 0) { + device_printf(sc->sc_dev, "could not allocate rx desc\n"); + goto fail; + } + error = bus_dmamap_load(rx_ring->desc_dmat, rx_ring->desc_map, + rx_ring->desc, size, rtwn_pci_dma_map_addr, &rx_ring->paddr, 0); + if (error != 0) { + device_printf(sc->sc_dev, "could not load rx desc DMA map\n"); + goto fail; + } + bus_dmamap_sync(rx_ring->desc_dmat, rx_ring->desc_map, + BUS_DMASYNC_PREWRITE); + + /* Create RX buffer DMA tag. */ + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, + 1, MCLBYTES, 0, NULL, NULL, &rx_ring->data_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create rx buf DMA tag\n"); + goto fail; + } + + /* Allocate Rx buffers. */ + for (i = 0; i < RTWN_PCI_RX_LIST_COUNT; i++) { + rx_data = &rx_ring->rx_data[i]; + error = bus_dmamap_create(rx_ring->data_dmat, 0, &rx_data->map); + if (error != 0) { + device_printf(sc->sc_dev, + "could not create rx buf DMA map\n"); + goto fail; + } + + rx_data->m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); + if (rx_data->m == NULL) { + device_printf(sc->sc_dev, + "could not allocate rx mbuf\n"); + error = ENOMEM; + goto fail; + } + + error = bus_dmamap_load(rx_ring->data_dmat, rx_data->map, + mtod(rx_data->m, void *), MCLBYTES, rtwn_pci_dma_map_addr, + &rx_data->paddr, BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->sc_dev, + "could not load rx buf DMA map"); + goto fail; + } + + rtwn_pci_setup_rx_desc(pc, &rx_ring->desc[i], rx_data->paddr, + MCLBYTES, i); + } + rx_ring->cur = 0; + + return (0); + +fail: + rtwn_pci_free_rx_list(sc); + return (error); +} + +static void +rtwn_pci_reset_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_rx_ring *rx_ring = &pc->rx_ring; + struct rtwn_rx_data *rx_data; + int i; + + for (i = 0; i < RTWN_PCI_RX_LIST_COUNT; i++) { + rx_data = &rx_ring->rx_data[i]; + rtwn_pci_setup_rx_desc(pc, &rx_ring->desc[i], + rx_data->paddr, MCLBYTES, i); + } + rx_ring->cur = 0; +} + +static void +rtwn_pci_free_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_rx_ring *rx_ring = &pc->rx_ring; + struct rtwn_rx_data *rx_data; + int i; + + if (rx_ring->desc_dmat != NULL) { + if (rx_ring->desc != NULL) { + bus_dmamap_sync(rx_ring->desc_dmat, + rx_ring->desc_map, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(rx_ring->desc_dmat, + rx_ring->desc_map); + bus_dmamem_free(rx_ring->desc_dmat, rx_ring->desc, + rx_ring->desc_map); + rx_ring->desc = NULL; + } + bus_dma_tag_destroy(rx_ring->desc_dmat); + rx_ring->desc_dmat = NULL; + } + + for (i = 0; i < RTWN_PCI_RX_LIST_COUNT; i++) { + rx_data = &rx_ring->rx_data[i]; + + if (rx_data->m != NULL) { + bus_dmamap_sync(rx_ring->data_dmat, + rx_data->map, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rx_ring->data_dmat, rx_data->map); + m_freem(rx_data->m); + rx_data->m = NULL; + } + bus_dmamap_destroy(rx_ring->data_dmat, rx_data->map); + rx_data->map = NULL; + } + if (rx_ring->data_dmat != NULL) { + bus_dma_tag_destroy(rx_ring->data_dmat); + rx_ring->data_dmat = NULL; + } +} + +static int +rtwn_pci_alloc_tx_list(struct rtwn_softc *sc, int qid) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *tx_ring = &pc->tx_ring[qid]; + bus_size_t size; + int i, error; + + size = sc->txdesc_len * RTWN_PCI_TX_LIST_COUNT; + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), PAGE_SIZE, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + size, 1, size, 0, NULL, NULL, &tx_ring->desc_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create tx ring DMA tag\n"); + goto fail; + } + + error = bus_dmamem_alloc(tx_ring->desc_dmat, &tx_ring->desc, + BUS_DMA_NOWAIT | BUS_DMA_ZERO, &tx_ring->desc_map); + if (error != 0) { + device_printf(sc->sc_dev, "can't map tx ring DMA memory\n"); + goto fail; + } + error = bus_dmamap_load(tx_ring->desc_dmat, tx_ring->desc_map, + tx_ring->desc, size, rtwn_pci_dma_map_addr, &tx_ring->paddr, + BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->sc_dev, "could not load desc DMA map\n"); + goto fail; + } + bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, + BUS_DMASYNC_PREWRITE); + + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, + 1, MCLBYTES, 0, NULL, NULL, &tx_ring->data_dmat); + if (error != 0) { + device_printf(sc->sc_dev, "could not create tx buf DMA tag\n"); + goto fail; + } + + for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { + struct rtwn_tx_data *tx_data = &tx_ring->tx_data[i]; + void *tx_desc = (uint8_t *)tx_ring->desc + sc->txdesc_len * i; + uint32_t next_desc_addr = tx_ring->paddr + + sc->txdesc_len * ((i + 1) % RTWN_PCI_TX_LIST_COUNT); + + rtwn_pci_setup_tx_desc(pc, tx_desc, next_desc_addr); + + error = bus_dmamap_create(tx_ring->data_dmat, 0, &tx_data->map); + if (error != 0) { + device_printf(sc->sc_dev, + "could not create tx buf DMA map\n"); + return (error); + } + tx_data->m = NULL; + tx_data->ni = NULL; + } + return (0); + +fail: + rtwn_pci_free_tx_list(sc, qid); + return (error); +} + +static void +rtwn_pci_reset_tx_list(struct rtwn_softc *sc, struct ieee80211vap *vap, + int qid) +{ + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *tx_ring = &pc->tx_ring[qid]; + int i, id; + + id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID); + + for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { + struct rtwn_tx_data *tx_data = &tx_ring->tx_data[i]; + + if (vap == NULL || (tx_data->ni == NULL && + (tx_data->id == id || id == RTWN_VAP_ID_INVALID)) || + (tx_data->ni != NULL && tx_data->ni->ni_vap == vap)) { + void *tx_desc = + (uint8_t *)tx_ring->desc + sc->txdesc_len * i; + + rtwn_pci_copy_tx_desc(pc, tx_desc, NULL); + + if (tx_data->m != NULL) { + bus_dmamap_sync(tx_ring->data_dmat, + tx_data->map, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(tx_ring->data_dmat, + tx_data->map); + m_freem(tx_data->m); + tx_data->m = NULL; + } + if (tx_data->ni != NULL) { + ieee80211_free_node(tx_data->ni); + tx_data->ni = NULL; + } + } + } + + bus_dmamap_sync(tx_ring->desc_dmat, tx_ring->desc_map, + BUS_DMASYNC_POSTWRITE); + + sc->qfullmsk &= ~(1 << qid); + tx_ring->queued = 0; + tx_ring->last = tx_ring->cur = 0; +} + +static void +rtwn_pci_free_tx_list(struct rtwn_softc *sc, int qid) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *tx_ring = &pc->tx_ring[qid]; + struct rtwn_tx_data *tx_data; + int i; + + if (tx_ring->desc_dmat != NULL) { + if (tx_ring->desc != NULL) { + bus_dmamap_sync(tx_ring->desc_dmat, + tx_ring->desc_map, BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(tx_ring->desc_dmat, + tx_ring->desc_map); + bus_dmamem_free(tx_ring->desc_dmat, tx_ring->desc, + tx_ring->desc_map); + } + bus_dma_tag_destroy(tx_ring->desc_dmat); + } + + for (i = 0; i < RTWN_PCI_TX_LIST_COUNT; i++) { + tx_data = &tx_ring->tx_data[i]; + + if (tx_data->m != NULL) { + bus_dmamap_sync(tx_ring->data_dmat, tx_data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(tx_ring->data_dmat, tx_data->map); + m_freem(tx_data->m); + tx_data->m = NULL; + } + } + if (tx_ring->data_dmat != NULL) { + bus_dma_tag_destroy(tx_ring->data_dmat); + tx_ring->data_dmat = NULL; + } + + sc->qfullmsk &= ~(1 << qid); + tx_ring->queued = 0; + tx_ring->last = tx_ring->cur = 0; +} + +static void +rtwn_pci_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + int i; + + for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) + rtwn_pci_reset_tx_list(sc, vap, i); + + if (vap == NULL) { + sc->qfullmsk = 0; + rtwn_pci_reset_rx_list(sc); + } +} + +static int +rtwn_pci_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf, + uint16_t reg, int mlen) +{ + int i; + + for (i = 0; i < mlen; i++) + rtwn_pci_write_1(sc, reg++, buf[i]); + + /* NB: cannot fail */ + return (0); +} + +static uint16_t +rtwn_pci_get_qmap(struct rtwn_softc *sc) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + + KASSERT(pc->pc_qmap != 0, ("%s: qmap is not set!\n", __func__)); + + return (pc->pc_qmap); +} + +static void +rtwn_pci_set_desc_addr(struct rtwn_softc *sc) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, "%s: addresses:\n" + "bk: %08jX, be: %08jX, vi: %08jX, vo: %08jX\n" + "bcn: %08jX, mgt: %08jX, high: %08jX, rx: %08jX\n", + __func__, (uintmax_t)pc->tx_ring[RTWN_PCI_BK_QUEUE].paddr, + (uintmax_t)pc->tx_ring[RTWN_PCI_BE_QUEUE].paddr, + (uintmax_t)pc->tx_ring[RTWN_PCI_VI_QUEUE].paddr, + (uintmax_t)pc->tx_ring[RTWN_PCI_VO_QUEUE].paddr, + (uintmax_t)pc->tx_ring[RTWN_PCI_BEACON_QUEUE].paddr, + (uintmax_t)pc->tx_ring[RTWN_PCI_MGNT_QUEUE].paddr, + (uintmax_t)pc->tx_ring[RTWN_PCI_HIGH_QUEUE].paddr, + (uintmax_t)pc->rx_ring.paddr); + + /* Set Tx Configuration Register. */ + rtwn_pci_write_4(sc, R92C_TCR, pc->tcr); + + /* Configure Tx DMA. */ + rtwn_pci_write_4(sc, R92C_BKQ_DESA, + pc->tx_ring[RTWN_PCI_BK_QUEUE].paddr); + rtwn_pci_write_4(sc, R92C_BEQ_DESA, + pc->tx_ring[RTWN_PCI_BE_QUEUE].paddr); + rtwn_pci_write_4(sc, R92C_VIQ_DESA, + pc->tx_ring[RTWN_PCI_VI_QUEUE].paddr); + rtwn_pci_write_4(sc, R92C_VOQ_DESA, + pc->tx_ring[RTWN_PCI_VO_QUEUE].paddr); + rtwn_pci_write_4(sc, R92C_BCNQ_DESA, + pc->tx_ring[RTWN_PCI_BEACON_QUEUE].paddr); + rtwn_pci_write_4(sc, R92C_MGQ_DESA, + pc->tx_ring[RTWN_PCI_MGNT_QUEUE].paddr); + rtwn_pci_write_4(sc, R92C_HQ_DESA, + pc->tx_ring[RTWN_PCI_HIGH_QUEUE].paddr); + + /* Configure Rx DMA. */ + rtwn_pci_write_4(sc, R92C_RX_DESA, pc->rx_ring.paddr); +} + +static void +rtwn_pci_attach_methods(struct rtwn_softc *sc) +{ + sc->sc_write_1 = rtwn_pci_write_1; + sc->sc_write_2 = rtwn_pci_write_2; + sc->sc_write_4 = rtwn_pci_write_4; + sc->sc_read_1 = rtwn_pci_read_1; + sc->sc_read_2 = rtwn_pci_read_2; + sc->sc_read_4 = rtwn_pci_read_4; + sc->sc_delay = rtwn_pci_delay; + sc->sc_tx_start = rtwn_pci_tx_start; + sc->sc_reset_lists = rtwn_pci_reset_lists; + sc->sc_abort_xfers = rtwn_nop_softc; + sc->sc_fw_write_block = rtwn_pci_fw_write_block; + sc->sc_get_qmap = rtwn_pci_get_qmap; + sc->sc_set_desc_addr = rtwn_pci_set_desc_addr; + sc->sc_drop_incorrect_tx = rtwn_nop_softc; +} + +static int +rtwn_pci_attach(device_t dev) +{ + struct rtwn_pci_softc *pc = device_get_softc(dev); + struct rtwn_softc *sc = &pc->pc_sc; + struct ieee80211com *ic = &sc->sc_ic; + uint32_t lcsr; + int cap_off, i, error, rid; + + if (matched_chip >= RTWN_CHIP_MAX_PCI) + return (ENXIO); + + /* + * Get the offset of the PCI Express Capability Structure in PCI + * Configuration Space. + */ + error = pci_find_cap(dev, PCIY_EXPRESS, &cap_off); + if (error != 0) { + device_printf(dev, "PCIe capability structure not found!\n"); + return (error); + } + + /* Enable bus-mastering. */ + pci_enable_busmaster(dev); + + rid = PCIR_BAR(2); + pc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (pc->mem == NULL) { + device_printf(dev, "can't map mem space\n"); + return (ENOMEM); + } + pc->pc_st = rman_get_bustag(pc->mem); + pc->pc_sh = rman_get_bushandle(pc->mem); + + /* Install interrupt handler. */ + rid = 1; + if (pci_alloc_msi(dev, &rid) == 0) + rid = 1; + else + rid = 0; + pc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | + (rid != 0 ? 0 : RF_SHAREABLE)); + if (pc->irq == NULL) { + device_printf(dev, "can't map interrupt\n"); + goto detach; + } + + /* Disable PCIe Active State Power Management (ASPM). */ + lcsr = pci_read_config(dev, cap_off + PCIER_LINK_CTL, 4); + lcsr &= ~PCIEM_LINK_CTL_ASPMC; + pci_write_config(dev, cap_off + PCIER_LINK_CTL, lcsr, 4); + + sc->sc_dev = dev; + ic->ic_name = device_get_nameunit(dev); + + /* Need to be initialized early. */ + rtwn_sysctlattach(sc); + mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF); + + rtwn_pci_attach_methods(sc); + /* XXX something similar to USB_GET_DRIVER_INFO() */ + rtwn_pci_attach_private(pc, matched_chip); + + /* Allocate Tx/Rx buffers. */ + error = rtwn_pci_alloc_rx_list(sc); + if (error != 0) { + device_printf(dev, + "could not allocate Rx buffers, error %d\n", + error); + goto detach; + } + for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) { + error = rtwn_pci_alloc_tx_list(sc, i); + if (error != 0) { + device_printf(dev, + "could not allocate Tx buffers, error %d\n", + error); + goto detach; + } + } + + /* Generic attach. */ + error = rtwn_attach(sc); + if (error != 0) + goto detach; + + /* + * Hook our interrupt after all initialization is complete. + */ + error = bus_setup_intr(dev, pc->irq, INTR_TYPE_NET | INTR_MPSAFE, + NULL, rtwn_pci_intr, sc, &pc->pc_ih); + if (error != 0) { + device_printf(dev, "can't establish interrupt, error %d\n", + error); + goto detach; + } + + return (0); + +detach: + rtwn_pci_detach(dev); /* failure */ + return (ENXIO); +} + +static int +rtwn_pci_detach(device_t dev) +{ + struct rtwn_pci_softc *pc = device_get_softc(dev); + struct rtwn_softc *sc = &pc->pc_sc; + int i; + + /* Generic detach. */ + rtwn_detach(sc); + + /* Uninstall interrupt handler. */ + if (pc->irq != NULL) { + bus_teardown_intr(dev, pc->irq, pc->pc_ih); + bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(pc->irq), + pc->irq); + pci_release_msi(dev); + } + + /* Free Tx/Rx buffers. */ + for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) + rtwn_pci_free_tx_list(sc, i); + rtwn_pci_free_rx_list(sc); + + if (pc->mem != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, + rman_get_rid(pc->mem), pc->mem); + + rtwn_detach_private(sc); + mtx_destroy(&sc->sc_mtx); + + return (0); +} + +static int +rtwn_pci_shutdown(device_t self) +{ + struct rtwn_pci_softc *pc = device_get_softc(self); + + ieee80211_stop_all(&pc->pc_sc.sc_ic); + return (0); +} + +static int +rtwn_pci_suspend(device_t self) +{ + struct rtwn_pci_softc *pc = device_get_softc(self); + + rtwn_suspend(&pc->pc_sc); + + return (0); +} + +static int +rtwn_pci_resume(device_t self) +{ + struct rtwn_pci_softc *pc = device_get_softc(self); + + rtwn_resume(&pc->pc_sc); + + return (0); +} + +static device_method_t rtwn_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, rtwn_pci_probe), + DEVMETHOD(device_attach, rtwn_pci_attach), + DEVMETHOD(device_detach, rtwn_pci_detach), + DEVMETHOD(device_shutdown, rtwn_pci_shutdown), + DEVMETHOD(device_suspend, rtwn_pci_suspend), + DEVMETHOD(device_resume, rtwn_pci_resume), + + DEVMETHOD_END +}; + +static driver_t rtwn_pci_driver = { + "rtwn", + rtwn_pci_methods, + sizeof(struct rtwn_pci_softc) +}; + +static devclass_t rtwn_pci_devclass; + +DRIVER_MODULE(rtwn_pci, pci, rtwn_pci_driver, rtwn_pci_devclass, NULL, NULL); +MODULE_VERSION(rtwn_pci, 1); +MODULE_DEPEND(rtwn_pci, pci, 1, 1, 1); +MODULE_DEPEND(rtwn_pci, wlan, 1, 1, 1); +MODULE_DEPEND(rtwn_pci, rtwn, 2, 2, 2); diff --git a/sys/dev/rtwn/pci/rtwn_pci_attach.h b/sys/dev/rtwn/pci/rtwn_pci_attach.h new file mode 100644 index 000000000000..6df5812e4cd2 --- /dev/null +++ b/sys/dev/rtwn/pci/rtwn_pci_attach.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +void r92ce_attach(struct rtwn_pci_softc *); + +enum { + RTWN_CHIP_RTL8192CE, + RTWN_CHIP_MAX_PCI +}; + +struct rtwn_pci_ident { + uint16_t vendor; + uint16_t device; + const char *name; + int chip; +}; + +static const struct rtwn_pci_ident rtwn_pci_ident_table[] = { + { 0x10ec, 0x8176, "Realtek RTL8188CE", RTWN_CHIP_RTL8192CE }, + { 0, 0, NULL, RTWN_CHIP_MAX_PCI } +}; + +typedef void (*chip_pci_attach)(struct rtwn_pci_softc *); + +static const chip_pci_attach rtwn_chip_pci_attach[RTWN_CHIP_MAX_PCI] = { + [RTWN_CHIP_RTL8192CE] = r92ce_attach +}; + +static __inline void +rtwn_pci_attach_private(struct rtwn_pci_softc *pc, int chip) +{ + rtwn_chip_pci_attach[chip](pc); +} diff --git a/sys/dev/rtwn/pci/rtwn_pci_reg.c b/sys/dev/rtwn/pci/rtwn_pci_reg.c new file mode 100644 index 000000000000..664fb33e6db8 --- /dev/null +++ b/sys/dev/rtwn/pci/rtwn_pci_reg.c @@ -0,0 +1,123 @@ +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + + +int +rtwn_pci_write_1(struct rtwn_softc *sc, uint16_t addr, uint8_t val) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + + bus_space_write_1(pc->pc_st, pc->pc_sh, addr, val); + + return (0); +} + +int +rtwn_pci_write_2(struct rtwn_softc *sc, uint16_t addr, uint16_t val) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + + val = htole16(val); + bus_space_write_2(pc->pc_st, pc->pc_sh, addr, val); + + return (0); +} + +int +rtwn_pci_write_4(struct rtwn_softc *sc, uint16_t addr, uint32_t val) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + + val = htole32(val); + bus_space_write_4(pc->pc_st, pc->pc_sh, addr, val); + + return (0); +} + +uint8_t +rtwn_pci_read_1(struct rtwn_softc *sc, uint16_t addr) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + + return (bus_space_read_1(pc->pc_st, pc->pc_sh, addr)); +} + +uint16_t +rtwn_pci_read_2(struct rtwn_softc *sc, uint16_t addr) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + uint16_t val; + + val = bus_space_read_2(pc->pc_st, pc->pc_sh, addr); + return le16toh(val); +} + +uint32_t +rtwn_pci_read_4(struct rtwn_softc *sc, uint16_t addr) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + uint32_t val; + + val = bus_space_read_4(pc->pc_st, pc->pc_sh, addr); + return le32toh(val); +} + +void +rtwn_pci_delay(struct rtwn_softc *sc, int usec) +{ + if (usec < 1000) + DELAY(usec); + else { + (void) mtx_sleep(sc, &sc->sc_mtx, 0, "rtwn_pci", + MAX(msecs_to_ticks(usec / 1000), 1)); + } +} diff --git a/sys/dev/rtwn/pci/rtwn_pci_reg.h b/sys/dev/rtwn/pci/rtwn_pci_reg.h new file mode 100644 index 000000000000..7c900345f46b --- /dev/null +++ b/sys/dev/rtwn/pci/rtwn_pci_reg.h @@ -0,0 +1,30 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_PCI_REG_H +#define RTWN_PCI_REG_H + +int rtwn_pci_write_1(struct rtwn_softc *, uint16_t, uint8_t); +int rtwn_pci_write_2(struct rtwn_softc *, uint16_t, uint16_t); +int rtwn_pci_write_4(struct rtwn_softc *, uint16_t, uint32_t); +uint8_t rtwn_pci_read_1(struct rtwn_softc *, uint16_t); +uint16_t rtwn_pci_read_2(struct rtwn_softc *, uint16_t); +uint32_t rtwn_pci_read_4(struct rtwn_softc *, uint16_t); +void rtwn_pci_delay(struct rtwn_softc *, int); + +#endif /* RTWN_PCI_REG_H */ diff --git a/sys/dev/rtwn/pci/rtwn_pci_rx.c b/sys/dev/rtwn/pci/rtwn_pci_rx.c new file mode 100644 index 000000000000..4425b4005a1a --- /dev/null +++ b/sys/dev/rtwn/pci/rtwn_pci_rx.c @@ -0,0 +1,293 @@ +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + + +void +rtwn_pci_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nsegs, + int error) +{ + + if (error != 0) + return; + KASSERT(nsegs == 1, ("too many DMA segments, %d should be 1", nsegs)); + *(bus_addr_t *)arg = segs[0].ds_addr; +} + +void +rtwn_pci_setup_rx_desc(struct rtwn_pci_softc *pc, struct r92ce_rx_stat *desc, + bus_addr_t addr, size_t len, int idx) +{ + + memset(desc, 0, sizeof(*desc)); + desc->rxdw0 = htole32(SM(R92C_RXDW0_PKTLEN, len) | + ((idx == RTWN_PCI_RX_LIST_COUNT - 1) ? R92C_RXDW0_EOR : 0)); + desc->rxbufaddr = htole32(addr); + bus_space_barrier(pc->pc_st, pc->pc_sh, 0, pc->pc_mapsize, + BUS_SPACE_BARRIER_WRITE); + desc->rxdw0 |= htole32(R92C_RXDW0_OWN); +} + +static void +rtwn_pci_rx_frame(struct rtwn_softc *sc, struct r92ce_rx_stat *rx_desc, + int desc_idx) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_rx_ring *ring = &pc->rx_ring; + struct rtwn_rx_data *rx_data = &ring->rx_data[desc_idx]; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni; + uint32_t rxdw0; + struct mbuf *m, *m1; + int8_t rssi = 0, nf; + int infosz, pktlen, shift, error; + + /* Dump Rx descriptor. */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC, + "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, tsfl %08X, " + "addr: %08X (64: %08X)\n", + __func__, le32toh(rx_desc->rxdw0), le32toh(rx_desc->rxdw1), + le32toh(rx_desc->rxdw2), le32toh(rx_desc->rxdw3), + le32toh(rx_desc->rxdw4), le32toh(rx_desc->tsf_low), + le32toh(rx_desc->rxbufaddr), le32toh(rx_desc->rxbufaddr64)); + + rxdw0 = le32toh(rx_desc->rxdw0); + if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) { + /* + * This should not happen since we setup our Rx filter + * to not receive these frames. + */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, + "%s: RX flags error (%s)\n", __func__, + rxdw0 & R92C_RXDW0_CRCERR ? "CRC" : "ICV"); + goto fail; + } + + pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); + if (__predict_false(pktlen < sizeof(struct ieee80211_frame_ack) || + pktlen > MCLBYTES)) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, + "%s: frame is too short/long: %d\n", __func__, pktlen); + goto fail; + } + + infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; + shift = MS(rxdw0, R92C_RXDW0_SHIFT); + + m1 = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); + if (__predict_false(m1 == NULL)) { + device_printf(sc->sc_dev, "%s: could not allocate RX mbuf\n", + __func__); + goto fail; + } + bus_dmamap_sync(ring->data_dmat, rx_data->map, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(ring->data_dmat, rx_data->map); + + error = bus_dmamap_load(ring->data_dmat, rx_data->map, mtod(m1, void *), + MCLBYTES, rtwn_pci_dma_map_addr, &rx_data->paddr, 0); + if (error != 0) { + m_freem(m1); + + error = bus_dmamap_load(ring->data_dmat, rx_data->map, + mtod(rx_data->m, void *), MCLBYTES, rtwn_pci_dma_map_addr, + &rx_data->paddr, BUS_DMA_NOWAIT); + if (error != 0) + panic("%s: could not load old RX mbuf", + device_get_name(sc->sc_dev)); + + /* Physical address may have changed. */ + rtwn_pci_setup_rx_desc(pc, rx_desc, rx_data->paddr, MCLBYTES, + desc_idx); + goto fail; + } + + /* Finalize mbuf. */ + m = rx_data->m; + rx_data->m = m1; + m->m_pkthdr.len = m->m_len = pktlen + infosz + shift; + + nf = RTWN_NOISE_FLOOR; + ni = rtwn_rx_common(sc, m, rx_desc, &rssi); + + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, + "%s: Rx frame len %d, infosz %d, shift %d, rssi %d\n", + __func__, pktlen, infosz, shift, rssi); + + /* Update RX descriptor. */ + rtwn_pci_setup_rx_desc(pc, rx_desc, rx_data->paddr, MCLBYTES, + desc_idx); + + /* Send the frame to the 802.11 layer. */ + RTWN_UNLOCK(sc); + if (ni != NULL) { + (void)ieee80211_input(ni, m, rssi - nf, nf); + /* Node is no longer needed. */ + ieee80211_free_node(ni); + } else + (void)ieee80211_input_all(ic, m, rssi - nf, nf); + + RTWN_LOCK(sc); + + return; + +fail: + counter_u64_add(ic->ic_ierrors, 1); +} + +static void +rtwn_pci_tx_done(struct rtwn_softc *sc, int qid) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *ring = &pc->tx_ring[qid]; + struct rtwn_tx_desc_common *desc; + struct rtwn_tx_data *data; + + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: qid %d, last %d, cur %d\n", + __func__, qid, ring->last, ring->cur); + + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD); + + while(ring->last != ring->cur) { + data = &ring->tx_data[ring->last]; + desc = (struct rtwn_tx_desc_common *) + ((uint8_t *)ring->desc + sc->txdesc_len * ring->last); + + KASSERT(data->m != NULL, ("no mbuf")); + + if (desc->flags0 & RTWN_FLAGS0_OWN) + break; + + /* Unmap and free mbuf. */ + bus_dmamap_sync(ring->data_dmat, data->map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(ring->data_dmat, data->map); + + if (data->ni != NULL) { /* not a beacon frame */ + ieee80211_tx_complete(data->ni, data->m, 0); + + data->ni = NULL; + ring->queued--; + } else + m_freem(data->m); + + data->m = NULL; + ring->last = (ring->last + 1) % RTWN_PCI_TX_LIST_COUNT; +#ifndef D4054 + if (ring->queued > 0) + sc->sc_tx_timer = 5; + else + sc->sc_tx_timer = 0; +#endif + } + + if (ring->queued < (RTWN_PCI_TX_LIST_COUNT - 1)) + sc->qfullmsk &= ~(1 << qid); + rtwn_start(sc); +} + +static void +rtwn_pci_rx_done(struct rtwn_softc *sc) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_rx_ring *ring = &pc->rx_ring; + + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, BUS_DMASYNC_POSTREAD); + + for (;;) { + struct r92ce_rx_stat *rx_desc = &ring->desc[ring->cur]; + + if (le32toh(rx_desc->rxdw0) & R92C_RXDW0_OWN) + break; + + rtwn_pci_rx_frame(sc, rx_desc, ring->cur); + + if (!(sc->sc_flags & RTWN_RUNNING)) + return; + + ring->cur = (ring->cur + 1) % RTWN_PCI_RX_LIST_COUNT; + } +} + +void +rtwn_pci_intr(void *arg) +{ + struct rtwn_softc *sc = arg; + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + int i, status, tx_rings; + + RTWN_LOCK(sc); + status = rtwn_classify_intr(sc, &tx_rings, 0); + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: status %08X, tx_rings %08X\n", + __func__, status, tx_rings); + if (status == 0 && tx_rings == 0) { + RTWN_UNLOCK(sc); + return; + } + + if (status & RTWN_PCI_INTR_RX) + rtwn_pci_rx_done(sc); + + if (tx_rings != 0) + for (i = 0; i < RTWN_PCI_NTXQUEUES; i++) + if (tx_rings & (1 << i)) + rtwn_pci_tx_done(sc, i); + + if (sc->sc_flags & RTWN_RUNNING) + rtwn_pci_enable_intr(pc); + RTWN_UNLOCK(sc); +} diff --git a/sys/dev/rtwn/pci/rtwn_pci_rx.h b/sys/dev/rtwn/pci/rtwn_pci_rx.h new file mode 100644 index 000000000000..265d32d8a117 --- /dev/null +++ b/sys/dev/rtwn/pci/rtwn_pci_rx.h @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_PCI_RX_H +#define RTWN_PCI_RX_H + +void rtwn_pci_dma_map_addr(void *, bus_dma_segment_t *, int, int); +void rtwn_pci_setup_rx_desc(struct rtwn_pci_softc *, + struct r92ce_rx_stat *, bus_addr_t, size_t, int); +void rtwn_pci_intr(void *); + +#endif /* RTWN_PCI_RX_H */ diff --git a/sys/dev/rtwn/pci/rtwn_pci_tx.c b/sys/dev/rtwn/pci/rtwn_pci_tx.c new file mode 100644 index 000000000000..c1da8f648554 --- /dev/null +++ b/sys/dev/rtwn/pci/rtwn_pci_tx.c @@ -0,0 +1,195 @@ +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include + + +static int +rtwn_pci_tx_start_common(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, uint8_t *tx_desc, uint8_t type, int id) +{ + struct rtwn_pci_softc *pc = RTWN_PCI_SOFTC(sc); + struct rtwn_tx_ring *ring; + struct rtwn_tx_data *data; + struct rtwn_tx_desc_common *txd; + bus_dma_segment_t segs[1]; + uint8_t qid; + int nsegs, error; + + RTWN_ASSERT_LOCKED(sc); + + switch (type) { + case IEEE80211_FC0_TYPE_CTL: + case IEEE80211_FC0_TYPE_MGT: + qid = RTWN_PCI_VO_QUEUE; + break; + default: + qid = M_WME_GETAC(m); + break; + } + + if (ni == NULL) /* beacon frame */ + qid = RTWN_PCI_BEACON_QUEUE; + + ring = &pc->tx_ring[qid]; + data = &ring->tx_data[ring->cur]; + if (data->m != NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: ring #%u is full (m %p)\n", __func__, qid, data->m); + return (ENOBUFS); + } + + txd = (struct rtwn_tx_desc_common *) + ((uint8_t *)ring->desc + sc->txdesc_len * ring->cur); + if (txd->flags0 & RTWN_FLAGS0_OWN) { + device_printf(sc->sc_dev, + "%s: OWN bit is set (tx desc %d, ring %u)!\n", + __func__, ring->cur, qid); + return (ENOBUFS); + } + + /* Copy Tx descriptor. */ + rtwn_pci_copy_tx_desc(pc, txd, tx_desc); + txd->pktlen = htole16(m->m_pkthdr.len); + txd->offset = sc->txdesc_len; + + error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs, + &nsegs, BUS_DMA_NOWAIT); + if (error != 0 && error != EFBIG) { + device_printf(sc->sc_dev, "can't map mbuf (error %d)\n", + error); + return (error); + } + if (error != 0) { + struct mbuf *mnew; + + mnew = m_defrag(m, M_NOWAIT); + if (mnew == NULL) { + device_printf(sc->sc_dev, "can't defragment mbuf\n"); + return (ENOBUFS); + } + m = mnew; + + error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, + segs, &nsegs, BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->sc_dev, + "can't map mbuf (error %d)\n", error); + if (ni != NULL) { + if_inc_counter(ni->ni_vap->iv_ifp, + IFCOUNTER_OERRORS, 1); + ieee80211_free_node(ni); + } + m_freem(m); + return (0); /* XXX */ + } + } + + rtwn_pci_tx_postsetup(pc, txd, segs); + txd->flags0 |= RTWN_FLAGS0_OWN; + + /* Dump Tx descriptor. */ + rtwn_dump_tx_desc(sc, txd); + + bus_dmamap_sync(ring->desc_dmat, ring->desc_map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTWRITE); + + data->m = m; + data->ni = ni; + data->id = id; + + ring->cur = (ring->cur + 1) % RTWN_PCI_TX_LIST_COUNT; + + if (qid != RTWN_PCI_BEACON_QUEUE) { + ring->queued++; + if (ring->queued >= (RTWN_PCI_TX_LIST_COUNT - 1)) + sc->qfullmsk |= (1 << qid); + +#ifndef D4054 + sc->sc_tx_timer = 5; +#endif + } + + /* Kick TX. */ + rtwn_write_2(sc, R92C_PCIE_CTRL_REG, (1 << qid)); + + return (0); +} + +int +rtwn_pci_tx_start(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, uint8_t *tx_desc, uint8_t type, int id) +{ + int error = 0; + + if (ni == NULL) { /* beacon frame */ + m = m_dup(m, M_NOWAIT); + if (__predict_false(m == NULL)) { + device_printf(sc->sc_dev, + "%s: could not copy beacon frame\n", __func__); + return (ENOMEM); + } + + error = rtwn_pci_tx_start_common(sc, ni, m, tx_desc, type, id); + if (error != 0) + m_freem(m); + } else + error = rtwn_pci_tx_start_common(sc, ni, m, tx_desc, type, id); + + return (error); +} diff --git a/sys/dev/rtwn/pci/rtwn_pci_tx.h b/sys/dev/rtwn/pci/rtwn_pci_tx.h new file mode 100644 index 000000000000..9b9d2e33693e --- /dev/null +++ b/sys/dev/rtwn/pci/rtwn_pci_tx.h @@ -0,0 +1,25 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_PCI_TX_H +#define RTWN_PCI_TX_H + +int rtwn_pci_tx_start(struct rtwn_softc *, struct ieee80211_node *, + struct mbuf *, uint8_t *, uint8_t, int); + +#endif /* RTWN_PCI_TX_H */ diff --git a/sys/dev/rtwn/pci/rtwn_pci_var.h b/sys/dev/rtwn/pci/rtwn_pci_var.h new file mode 100644 index 000000000000..4a6d54c21da8 --- /dev/null +++ b/sys/dev/rtwn/pci/rtwn_pci_var.h @@ -0,0 +1,141 @@ +/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_PCI_VAR_H +#define RTWN_PCI_VAR_H + +#include + + +#define RTWN_PCI_RX_LIST_COUNT 256 +#define RTWN_PCI_TX_LIST_COUNT 256 + +struct rtwn_rx_data { + bus_dmamap_t map; + struct mbuf *m; + bus_addr_t paddr; +}; + +struct rtwn_rx_ring { + struct r92ce_rx_stat *desc; + bus_addr_t paddr; + bus_dma_tag_t desc_dmat; + bus_dmamap_t desc_map; + bus_dma_tag_t data_dmat; + bus_dma_segment_t seg; + struct rtwn_rx_data rx_data[RTWN_PCI_RX_LIST_COUNT]; + int cur; +}; + +struct rtwn_tx_data { + bus_dmamap_t map; + struct mbuf *m; + struct ieee80211_node *ni; + uint8_t id; +}; + +struct rtwn_tx_ring { + bus_addr_t paddr; + bus_dma_tag_t desc_dmat; + bus_dmamap_t desc_map; + bus_dma_tag_t data_dmat; + bus_dma_segment_t seg; + void *desc; + struct rtwn_tx_data tx_data[RTWN_PCI_TX_LIST_COUNT]; + int queued; + int cur; + int last; +}; + +/* + * TX queue indices. + */ +enum { + RTWN_PCI_BK_QUEUE, + RTWN_PCI_BE_QUEUE, + RTWN_PCI_VI_QUEUE, + RTWN_PCI_VO_QUEUE, + RTWN_PCI_BEACON_QUEUE, + RTWN_PCI_TXCMD_QUEUE, + RTWN_PCI_MGNT_QUEUE, + RTWN_PCI_HIGH_QUEUE, + RTWN_PCI_HCCA_QUEUE, + RTWN_PCI_NTXQUEUES +}; + +/* + * Interrupt events. + */ +enum { + RTWN_PCI_INTR_RX_ERROR = 0x00000001, + RTWN_PCI_INTR_RX_OVERFLOW = 0x00000002, + RTWN_PCI_INTR_RX_DESC_UNAVAIL = 0x00000004, + RTWN_PCI_INTR_RX_DONE = 0x00000008, + RTWN_PCI_INTR_TX_ERROR = 0x00000010, + RTWN_PCI_INTR_TX_OVERFLOW = 0x00000020, + RTWN_PCI_INTR_TX_REPORT = 0x00000040, + RTWN_PCI_INTR_PS_TIMEOUT = 0x00000080 +}; + +/* Shortcuts */ +/* Vendor driver treats RX errors like ROK... */ +#define RTWN_PCI_INTR_RX \ + (RTWN_PCI_INTR_RX_OVERFLOW | RTWN_PCI_INTR_RX_DESC_UNAVAIL | \ + RTWN_PCI_INTR_RX_DONE) + + +struct rtwn_pci_softc { + struct rtwn_softc pc_sc; /* must be the first */ + + struct resource *irq; + struct resource *mem; + bus_space_tag_t pc_st; + bus_space_handle_t pc_sh; + void *pc_ih; + bus_size_t pc_mapsize; + + struct rtwn_rx_ring rx_ring; + struct rtwn_tx_ring tx_ring[RTWN_PCI_NTXQUEUES]; + + /* must be set by the driver. */ + uint16_t pc_qmap; + uint32_t tcr; + + void (*pc_setup_tx_desc)(struct rtwn_pci_softc *, + void *, uint32_t); + void (*pc_tx_postsetup)(struct rtwn_pci_softc *, + void *, bus_dma_segment_t *); + void (*pc_copy_tx_desc)(void *, const void *); + void (*pc_enable_intr)(struct rtwn_pci_softc *); +}; +#define RTWN_PCI_SOFTC(sc) ((struct rtwn_pci_softc *)(sc)) + +#define rtwn_pci_setup_tx_desc(_pc, _desc, _addr) \ + (((_pc)->pc_setup_tx_desc)((_pc), (_desc), (_addr))) +#define rtwn_pci_tx_postsetup(_pc, _txd, _segs) \ + (((_pc)->pc_tx_postsetup)((_pc), (_txd), (_segs))) +#define rtwn_pci_copy_tx_desc(_pc, _dest, _src) \ + (((_pc)->pc_copy_tx_desc)((_dest), (_src))) +#define rtwn_pci_enable_intr(_pc) \ + (((_pc)->pc_enable_intr)((_pc))) + +#endif /* RTWN_PCI_VAR_H */ diff --git a/sys/dev/rtwn/rtl8188e/r88e.h b/sys/dev/rtwn/rtl8188e/r88e.h new file mode 100644 index 000000000000..999ab4005756 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e.h @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef RTL8188E_H +#define RTL8188E_H + +/* + * Global definitions. + */ +#define R88E_PUBQ_NPAGES 142 +#define R88E_TXPKTBUF_COUNT 177 +#define R88E_TX_PAGE_COUNT 169 + +#define R88E_MACID_MAX 63 +#define R88E_RX_DMA_BUFFER_SIZE 0x2400 + +#define R88E_INTR_MSG_LEN 60 + +#define R88E_CALIB_THRESHOLD 4 + + +/* + * Function declarations. + */ +/* r88e_beacon.c */ +void r88e_beacon_enable(struct rtwn_softc *, int, int); + +/* r88e_calib.c */ +void r88e_iq_calib(struct rtwn_softc *); +void r88e_temp_measure(struct rtwn_softc *); +uint8_t r88e_temp_read(struct rtwn_softc *); + +/* r88e_chan.c */ +void r88e_get_txpower(struct rtwn_softc *, int, + struct ieee80211_channel *, uint16_t[]); +void r88e_set_bw20(struct rtwn_softc *, uint8_t); +void r88e_set_gain(struct rtwn_softc *, uint8_t); + +/* r88e_fw.c */ +#ifndef RTWN_WITHOUT_UCODE +int r88e_fw_cmd(struct rtwn_softc *, uint8_t, const void *, int); +void r88e_fw_reset(struct rtwn_softc *, int); +void r88e_fw_download_enable(struct rtwn_softc *, int); +#endif +void r88e_macid_enable_link(struct rtwn_softc *, int, int); +void r88e_set_media_status(struct rtwn_softc *, int); +#ifndef RTWN_WITHOUT_UCODE +int r88e_set_rsvd_page(struct rtwn_softc *, int, int, int); +int r88e_set_pwrmode(struct rtwn_softc *, struct ieee80211vap *, int); +#endif + +/* r88e_init.c */ +void r88e_init_bb(struct rtwn_softc *); +void r88e_init_rf(struct rtwn_softc *); +int r88e_power_on(struct rtwn_softc *); + +/* r88e_led.c */ +void r88e_set_led(struct rtwn_softc *, int, int); + +/* r88e_rf.c */ +void r88e_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t); + +/* r88e_rom.c */ +void r88e_parse_rom(struct rtwn_softc *, uint8_t *); + +/* r88e_rx.c */ +void r88e_ratectl_tx_complete(struct rtwn_softc *, uint8_t *, int); +void r88e_handle_c2h_report(struct rtwn_softc *, uint8_t *, int); +int8_t r88e_get_rssi_cck(struct rtwn_softc *, void *); +int8_t r88e_get_rssi_ofdm(struct rtwn_softc *, void *); + +/* r88e_tx.c */ +void r88e_tx_enable_ampdu(void *, int); +void r88e_tx_setup_hwseq(void *); +void r88e_tx_setup_macid(void *, int); + +#endif /* RTL8188E_H */ diff --git a/sys/dev/rtwn/rtl8188e/r88e_beacon.c b/sys/dev/rtwn/rtl8188e/r88e_beacon.c new file mode 100644 index 000000000000..4c29d37fab24 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_beacon.c @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + + +void +r88e_beacon_enable(struct rtwn_softc *sc, int id, int enable) +{ + + if (enable) { + rtwn_setbits_1(sc, R92C_MBID_NUM, 0, R88E_MBID_TXBCN_RPT(id)); + rtwn_setbits_1(sc, R92C_BCN_CTRL(id), + 0, R92C_BCN_CTRL_EN_BCN); + } else { + rtwn_setbits_1(sc, R92C_MBID_NUM, R88E_MBID_TXBCN_RPT(id), 0); + rtwn_setbits_1(sc, R92C_BCN_CTRL(id), + R92C_BCN_CTRL_EN_BCN, 0); + } +} diff --git a/sys/dev/rtwn/rtl8188e/r88e_calib.c b/sys/dev/rtwn/rtl8188e/r88e_calib.c new file mode 100644 index 000000000000..e8af13e7da9e --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_calib.c @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r88e_iq_calib(struct rtwn_softc *sc) +{ + /* XXX TODO */ +} + +void +r88e_temp_measure(struct rtwn_softc *sc) +{ + rtwn_rf_write(sc, 0, R88E_RF_T_METER, R88E_RF_T_METER_START); +} + +uint8_t +r88e_temp_read(struct rtwn_softc *sc) +{ + return (MS(rtwn_rf_read(sc, 0, R88E_RF_T_METER), + R88E_RF_T_METER_VAL)); +} diff --git a/sys/dev/rtwn/rtl8188e/r88e_chan.c b/sys/dev/rtwn/rtl8188e/r88e_chan.c new file mode 100644 index 000000000000..94d5445f258d --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_chan.c @@ -0,0 +1,167 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +static int +r88e_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + uint8_t chan; + int group; + + chan = rtwn_chan2centieee(c); + if (IEEE80211_IS_CHAN_2GHZ(c)) { + if (chan <= 2) group = 0; + else if (chan <= 5) group = 1; + else if (chan <= 8) group = 2; + else if (chan <= 11) group = 3; + else if (chan <= 13) group = 4; + else if (chan <= 14) group = 5; + else { + KASSERT(0, ("wrong 2GHz channel %d!\n", chan)); + return (-1); + } + } else { + KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags)); + return (-1); + } + + return (group); +} + +void +r88e_get_txpower(struct rtwn_softc *sc, int chain, + struct ieee80211_channel *c, uint16_t power[RTWN_RIDX_COUNT]) +{ + struct r92c_softc *rs = sc->sc_priv; + const struct rtwn_r88e_txpwr *rt = rs->rs_txpwr; + const struct rtwn_r88e_txagc *base = rs->rs_txagc; + uint16_t cckpow, ofdmpow, bw20pow, htpow; + int max_mcs, ridx, group; + + /* Determine channel group. */ + group = r88e_get_power_group(sc, c); + if (group == -1) { /* shouldn't happen */ + device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__); + return; + } + + /* XXX net80211 regulatory */ + + max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + KASSERT(max_mcs <= RTWN_RIDX_COUNT, ("increase ridx limit\n")); + + memset(power, 0, max_mcs * sizeof(power[0])); + if (rs->regulatory == 0) { + for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) + power[ridx] = base->pwr[0][ridx]; + } + for (ridx = RTWN_RIDX_OFDM6; ridx < RTWN_RIDX_COUNT; ridx++) { + if (rs->regulatory == 3) + power[ridx] = base->pwr[0][ridx]; + else if (rs->regulatory == 1) { + if (!IEEE80211_IS_CHAN_HT40(c)) + power[ridx] = base->pwr[group][ridx]; + } else if (rs->regulatory != 2) + power[ridx] = base->pwr[0][ridx]; + } + + /* Compute per-CCK rate Tx power. */ + cckpow = rt->cck_tx_pwr[group]; + for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) + power[ridx] += cckpow; + + htpow = rt->ht40_tx_pwr[group]; + + /* Compute per-OFDM rate Tx power. */ + ofdmpow = htpow + rt->ofdm_tx_pwr_diff; + for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) + power[ridx] += ofdmpow; + + bw20pow = htpow + rt->bw20_tx_pwr_diff; + for (ridx = RTWN_RIDX_MCS(0); ridx <= max_mcs; ridx++) + power[ridx] += bw20pow; + + /* Apply max limit. */ + for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) { + if (power[ridx] > R92C_MAX_TX_PWR) + power[ridx] = R92C_MAX_TX_PWR; + } +} + +void +r88e_set_bw20(struct rtwn_softc *sc, uint8_t chan) +{ + struct r92c_softc *rs = sc->sc_priv; + + rtwn_setbits_1(sc, R92C_BWOPMODE, 0, R92C_BWOPMODE_20MHZ); + + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, R92C_RFMOD_40MHZ, 0); + rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, R92C_RFMOD_40MHZ, 0); + + /* Select 20MHz bandwidth. */ + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, + (rs->rf_chnlbw[0] & ~0xfff) | chan | R88E_RF_CHNLBW_BW20); +} + +void +r88e_set_gain(struct rtwn_softc *sc, uint8_t gain) +{ + + rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(0), + R92C_OFDM0_AGCCORE1_GAIN_M, gain); +} diff --git a/sys/dev/rtwn/rtl8188e/r88e_fw.c b/sys/dev/rtwn/rtl8188e/r88e_fw.c new file mode 100644 index 000000000000..435fb650238b --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_fw.c @@ -0,0 +1,225 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +#ifndef RTWN_WITHOUT_UCODE +int +r88e_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len) +{ + struct r88e_fw_cmd cmd; + int ntries, error; + + if (!(sc->sc_flags & RTWN_FW_LOADED)) { + RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, "%s: firmware " + "was not loaded; command (id %d) will be discarded\n", + __func__, id); + return (0); + } + + /* Wait for current FW box to be empty. */ + for (ntries = 0; ntries < 50; ntries++) { + if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur))) + break; + rtwn_delay(sc, 2000); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "could not send firmware command\n"); + return (ETIMEDOUT); + } + memset(&cmd, 0, sizeof(cmd)); + cmd.id = id; + KASSERT(len <= sizeof(cmd.msg), + ("%s: firmware command too long (%d > %zu)\n", + __func__, len, sizeof(cmd.msg))); + memcpy(cmd.msg, buf, len); + + /* Write the first word last since that will trigger the FW. */ + if (len > 3) { + error = rtwn_write_4(sc, R88E_HMEBOX_EXT(sc->fwcur), + *(uint32_t *)((uint8_t *)&cmd + 4)); + if (error != 0) + return (error); + } + error = rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur), *(uint32_t *)&cmd); + if (error != 0) + return (error); + + sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX; + + return (0); +} + +void +r88e_fw_reset(struct rtwn_softc *sc, int reason) +{ + uint16_t reg; + + reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN); + rtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN); + rtwn_write_2(sc, R92C_SYS_FUNC_EN, reg | R92C_SYS_FUNC_EN_CPUEN); +} + +void +r88e_fw_download_enable(struct rtwn_softc *sc, int enable) +{ + if (enable) { + /* MCU firmware download enable. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN); + /* 8051 reset. */ + rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN, + 0, 2); + } else { + /* MCU download disable. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0); + /* Reserved for f/w extension. */ + rtwn_write_1(sc, R92C_MCUFWDL + 1, 0); + } +} +#endif + +void +r88e_macid_enable_link(struct rtwn_softc *sc, int id, int enable) +{ + uint32_t reg; + + reg = R88E_MACID_NO_LINK; + if (id > 32) + reg += 4; + + if (enable) + rtwn_setbits_4(sc, reg, 1 << (id % 32), 0); + else + rtwn_setbits_4(sc, reg, 0, 1 << (id % 32)); + + /* XXX max macid for tx reports */ +} + +void +r88e_set_media_status(struct rtwn_softc *sc, int macid) +{ + struct r88e_fw_cmd_msrrpt status; + + if (macid & RTWN_MACID_VALID) + status.msrb0 = R88E_MSRRPT_B0_ASSOC; + else + status.msrb0 = R88E_MSRRPT_B0_DISASSOC; + status.macid = (macid & ~RTWN_MACID_VALID); + + r88e_macid_enable_link(sc, status.macid, + (macid & RTWN_MACID_VALID) != 0); + +#ifndef RTWN_WITHOUT_UCODE + if (r88e_fw_cmd(sc, R88E_CMD_MSR_RPT, &status, sizeof(status)) != 0) { + device_printf(sc->sc_dev, "%s: cannot change media status!\n", + __func__); + } +#endif +} + +#ifndef RTWN_WITHOUT_UCODE +int +r88e_set_rsvd_page(struct rtwn_softc *sc, int probe_resp, int null, + int qos_null) +{ + struct r88e_fw_cmd_rsvdpage rsvd; + + rsvd.probe_resp = probe_resp; + rsvd.ps_poll = 0; + rsvd.null_data = null; + rsvd.null_data_qos = qos_null; + rsvd.null_data_qos_bt = 0; + return (r88e_fw_cmd(sc, R88E_CMD_RSVD_PAGE, &rsvd, sizeof(rsvd))); +} + +int +r88e_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap, + int off) +{ + struct r88e_fw_cmd_pwrmode mode; + int error; + + if (off && vap->iv_state == IEEE80211_S_RUN && + (vap->iv_flags & IEEE80211_F_PMGTON)) { + mode.mode = R88E_PWRMODE_LEG; + /* + * TODO: switch to RFOFF state + * (something is missing here - Rx stops with it). + */ +#ifdef RTWN_TODO + mode.pwr_state = R88E_PWRMODE_STATE_RFOFF; +#else + mode.pwr_state = R88E_PWRMODE_STATE_RFON; +#endif + } else { + mode.mode = R88E_PWRMODE_CAM; + mode.pwr_state = R88E_PWRMODE_STATE_ALLON; + } + mode.pwrb1 = + SM(R88E_PWRMODE_B1_SMART_PS, R88E_PWRMODE_B1_LEG_NULLDATA) | + SM(R88E_PWRMODE_B1_RLBM, R88E_PWRMODE_B1_MODE_MIN); + /* XXX ignored */ + mode.bcn_pass = 0; + mode.queue_uapsd = 0; + error = r88e_fw_cmd(sc, R88E_CMD_SET_PWRMODE, &mode, sizeof(mode)); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: CMD_SET_PWRMODE was not sent, error %d\n", + __func__, error); + } + + return (error); +} +#endif diff --git a/sys/dev/rtwn/rtl8188e/r88e_fw_cmd.h b/sys/dev/rtwn/rtl8188e/r88e_fw_cmd.h new file mode 100644 index 000000000000..c152729c1ee4 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_fw_cmd.h @@ -0,0 +1,84 @@ +/*- + * Copyright (c) 2015 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R88E_FW_CMD_H +#define R88E_FW_CMD_H + +/* + * Host to firmware commands. + */ +struct r88e_fw_cmd { + uint8_t id; +#define R88E_CMD_RSVD_PAGE 0x00 +#define R88E_CMD_MSR_RPT 0x01 +#define R88E_CMD_SET_PWRMODE 0x20 + + uint8_t msg[7]; +} __packed __attribute__((aligned(4))); + +/* Structure for R88E_CMD_RSVD_PAGE. */ +struct r88e_fw_cmd_rsvdpage { + uint8_t probe_resp; + uint8_t ps_poll; + uint8_t null_data; + uint8_t null_data_qos; + uint8_t null_data_qos_bt; +} __packed; + +/* Structure for R88E_CMD_MSR_RPT. */ +struct r88e_fw_cmd_msrrpt { + uint8_t msrb0; +#define R88E_MSRRPT_B0_DISASSOC 0x00 +#define R88E_MSRRPT_B0_ASSOC 0x01 + + uint8_t macid; +} __packed; + +/* Structure for R88E_CMD_SET_PWRMODE. */ +struct r88e_fw_cmd_pwrmode { + uint8_t mode; +#define R88E_PWRMODE_CAM 0 +#define R88E_PWRMODE_LEG 1 +#define R88E_PWRMODE_UAPSD 2 + + uint8_t pwrb1; +#define R88E_PWRMODE_B1_RLBM_M 0x0f +#define R88E_PWRMODE_B1_RLBM_S 0 +#define R88E_PWRMODE_B1_MODE_MIN 0 +#define R88E_PWRMODE_B1_MODE_MAX 1 +#define R88E_PWRMODE_B1_MODE_DTIM 2 + +#define R88E_PWRMODE_B1_SMART_PS_M 0xf0 +#define R88E_PWRMODE_B1_SMART_PS_S 4 +#define R88E_PWRMODE_B1_LEG_PSPOLL0 0 +#define R88E_PWRMODE_B1_LEG_PSPOLL1 1 +#define R88E_PWRMODE_B1_LEG_NULLDATA 2 +#define R88E_PWRMODE_B1_WMM_PSPOLL 0 +#define R88E_PWRMODE_B1_WMM_NULLDATA 1 + + uint8_t bcn_pass; + uint8_t queue_uapsd; + uint8_t pwr_state; +#define R88E_PWRMODE_STATE_RFOFF 0x00 +#define R88E_PWRMODE_STATE_RFON 0x04 +#define R88E_PWRMODE_STATE_ALLON 0x0c +} __packed; + +#endif /* R88E_FW_CMD_H */ diff --git a/sys/dev/rtwn/rtl8188e/r88e_init.c b/sys/dev/rtwn/rtl8188e/r88e_init.c new file mode 100644 index 000000000000..202cec154aa2 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_init.c @@ -0,0 +1,158 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include + + +static void +r88e_crystalcap_write(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + uint32_t reg; + uint8_t val; + + val = rs->crystalcap & 0x3f; + reg = rtwn_bb_read(sc, R92C_AFE_XTAL_CTRL); + rtwn_bb_write(sc, R92C_AFE_XTAL_CTRL, + RW(reg, R92C_AFE_XTAL_CTRL_ADDR, val | val << 6)); +} + +void +r88e_init_bb(struct rtwn_softc *sc) +{ + + /* Enable BB and RF. */ + rtwn_setbits_2(sc, R92C_SYS_FUNC_EN, 0, + R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | + R92C_SYS_FUNC_EN_DIO_RF); + + rtwn_write_1(sc, R92C_RF_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); + rtwn_write_1(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_USBA | R92C_SYS_FUNC_EN_USBD | + R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB); + + r92c_init_bb_common(sc); + + rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553422); + rtwn_delay(sc, 1); + rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553420); + rtwn_delay(sc, 1); + + r88e_crystalcap_write(sc); +} + +int +r88e_power_on(struct rtwn_softc *sc) +{ +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while(0) + int ntries; + + /* Wait for power ready bit. */ + for (ntries = 0; ntries < 5000; ntries++) { + if (rtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) { + device_printf(sc->sc_dev, + "timeout waiting for chip power up\n"); + return (ETIMEDOUT); + } + + /* Reset BB. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST, 0)); + + RTWN_CHK(rtwn_setbits_1(sc, R92C_AFE_XTAL_CTRL + 2, 0, 0x80)); + + /* Disable HWPDN. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_APDM_HPDN, 0, 1)); + + /* Disable WL suspend. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE, 0, 1)); + + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + 0, R92C_APS_FSMCO_APFM_ONMAC, 1)); + for (ntries = 0; ntries < 5000; ntries++) { + if (!(rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_ONMAC)) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) + return (ETIMEDOUT); + + /* Enable LDO normal mode. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_LPLDO_CTRL, + R92C_LPLDO_CTRL_SLEEP, 0)); + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + RTWN_CHK(rtwn_write_2(sc, R92C_CR, 0)); + RTWN_CHK(rtwn_setbits_2(sc, R92C_CR, 0, + R92C_CR_HCI_TXDMA_EN | R92C_CR_TXDMA_EN | + R92C_CR_HCI_RXDMA_EN | R92C_CR_RXDMA_EN | + R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN | + ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) | + R92C_CR_CALTMR_EN)); + + return (0); +#undef RTWN_CHK +} diff --git a/sys/dev/rtwn/rtl8188e/r88e_led.c b/sys/dev/rtwn/rtl8188e/r88e_led.c new file mode 100644 index 000000000000..2bbcdb15cab6 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_led.c @@ -0,0 +1,68 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + + +void +r88e_set_led(struct rtwn_softc *sc, int led, int on) +{ + + if (led == RTWN_LED_LINK) { + if (!on) { + rtwn_setbits_1(sc, R92C_LEDCFG2, 0x6f, + R92C_LEDCFG0_DIS); + rtwn_setbits_1(sc, R92C_MAC_PINMUX_CFG, 0x01, 0); + } else + rtwn_setbits_1(sc, R92C_LEDCFG2, 0x0f, 0x60); + sc->ledlink = on; /* Save LED state. */ + } + + /* XXX led #1? */ +} diff --git a/sys/dev/rtwn/rtl8188e/r88e_priv.h b/sys/dev/rtwn/rtl8188e/r88e_priv.h new file mode 100644 index 000000000000..cb4f7edbb192 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_priv.h @@ -0,0 +1,273 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R88E_PRIV_H +#define R88E_PRIV_H + +#include + +/* + * Parsed Tx power (diff) values. + */ +struct rtwn_r88e_txpwr { + uint8_t cck_tx_pwr[R88E_GROUP_2G]; + uint8_t ht40_tx_pwr[R88E_GROUP_2G - 1]; + int8_t ofdm_tx_pwr_diff; + int8_t bw20_tx_pwr_diff; +}; + + +/* + * MAC initialization values. + */ +static const struct rtwn_mac_prog rtl8188eu_mac[] = { + { 0x026, 0x41 }, { 0x027, 0x35 }, { 0x040, 0x00 }, { 0x428, 0x0a }, + { 0x429, 0x10 }, { 0x430, 0x00 }, { 0x431, 0x01 }, { 0x432, 0x02 }, + { 0x433, 0x04 }, { 0x434, 0x05 }, { 0x435, 0x06 }, { 0x436, 0x07 }, + { 0x437, 0x08 }, { 0x438, 0x00 }, { 0x439, 0x00 }, { 0x43a, 0x01 }, + { 0x43b, 0x02 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, { 0x43e, 0x06 }, + { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 }, { 0x442, 0x00 }, + { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f }, { 0x447, 0x00 }, + { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 }, { 0x45b, 0xb9 }, + { 0x460, 0x66 }, { 0x461, 0x66 }, { 0x480, 0x08 }, { 0x4c8, 0xff }, + { 0x4c9, 0x08 }, { 0x4cc, 0xff }, { 0x4cd, 0xff }, { 0x4ce, 0x01 }, + { 0x4d3, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, { 0x502, 0x2f }, + { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, { 0x506, 0x5e }, + { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, { 0x50a, 0x5e }, + { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, { 0x50e, 0x00 }, + { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, { 0x516, 0x0a }, + { 0x525, 0x4f }, { 0x550, 0x10 }, { 0x551, 0x10 }, { 0x559, 0x02 }, + { 0x55d, 0xff }, { 0x605, 0x30 }, { 0x608, 0x0e }, { 0x609, 0x2a }, + { 0x620, 0xff }, { 0x621, 0xff }, { 0x622, 0xff }, { 0x623, 0xff }, + { 0x624, 0xff }, { 0x625, 0xff }, { 0x626, 0xff }, { 0x627, 0xff }, + { 0x652, 0x20 }, { 0x63c, 0x0a }, { 0x63d, 0x0a }, { 0x63e, 0x0e }, + { 0x63f, 0x0e }, { 0x640, 0x40 }, { 0x66e, 0x05 }, { 0x700, 0x21 }, + { 0x701, 0x43 }, { 0x702, 0x65 }, { 0x703, 0x87 }, { 0x708, 0x21 }, + { 0x709, 0x43 }, { 0x70a, 0x65 }, { 0x70b, 0x87 } +}; + +/* + * Baseband initialization values. + */ +static const uint16_t rtl8188eu_bb_regs[] = { + 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, 0x81c, + 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, + 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, + 0x860, 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, + 0x880, 0x884, 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, + 0x900, 0x904, 0x908, 0x90c, 0x910, 0x914, 0xa00, 0xa04, + 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, 0xa20, 0xa24, + 0xa28, 0xa2c, 0xa70, 0xa74, 0xa78, 0xa7c, 0xa80, 0xb2c, + 0xc00, 0xc04, 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, + 0xc20, 0xc24, 0xc28, 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, + 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, 0xc54, 0xc58, 0xc5c, + 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, 0xc74, 0xc78, 0xc7c, + 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, 0xc98, 0xc9c, + 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, 0xcbc, + 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc, + 0xce0, 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, 0xd08, 0xd0c, + 0xd10, 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c, + 0xd40, 0xd44, 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, + 0xd60, 0xd64, 0xd68, 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00, + 0xe04, 0xe08, 0xe10, 0xe14, 0xe18, 0xe1c, 0xe28, 0xe30, + 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, 0xe48, 0xe4c, 0xe50, + 0xe54, 0xe58, 0xe5c, 0xe60, 0xe68, 0xe6c, 0xe70, 0xe74, + 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, 0xed0, 0xed4, + 0xed8, 0xedc, 0xee0, 0xee8, 0xeec, 0xf14, 0xf4c, 0xf00 +}; + +static const uint32_t rtl8188eu_bb_vals[] = { + 0x80040000, 0x00000003, 0x0000fc00, 0x0000000a, 0x10001331, + 0x020c3d10, 0x02200385, 0x00000000, 0x01000100, 0x00390204, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00010000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x569a11a9, 0x01000014, 0x66f60110, + 0x061f0649, 0x00000000, 0x27272700, 0x07000760, 0x25004000, + 0x00000808, 0x00000000, 0xb0000c1c, 0x00000001, 0x00000000, + 0xccc000c0, 0x00000800, 0xfffffffe, 0x40302010, 0x00706050, + 0x00000000, 0x00000023, 0x00000000, 0x81121111, 0x00000002, + 0x00000201, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e7f120f, + 0x9500bb78, 0x1114d028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x00000900, 0x225b0606, 0x218075b1, 0x80000000, 0x48071d40, + 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, 0x40000100, + 0x08800000, 0x40000100, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x69e9ac47, 0x469652af, 0x49795994, 0x0a97971c, + 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, 0x69553420, + 0x43bc0094, 0x00013169, 0x00250492, 0x00000000, 0x7112848b, + 0x47c00bff, 0x00000036, 0x2c7f000d, 0x020610db, 0x0000001f, + 0x00b91612, 0x390000e4, 0x20f60000, 0x40000100, 0x20200000, + 0x00091521, 0x00000000, 0x00121820, 0x00007f7f, 0x00000000, + 0x000300a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x28000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x64b22427, 0x00766932, + 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, 0x00000740, + 0x00020401, 0x0000907f, 0x20010201, 0xa0633333, 0x3333bc43, + 0x7a8f5b6f, 0xcc979975, 0x00000000, 0x80608000, 0x00000000, + 0x00127353, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x6437140a, 0x00000000, 0x00000282, 0x30032064, 0x4653de68, + 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, 0x322c2220, + 0x000e3c24, 0x2d2d2d2d, 0x2d2d2d2d, 0x0390272d, 0x2d2d2d2d, + 0x2d2d2d2d, 0x2d2d2d2d, 0x2d2d2d2d, 0x00000000, 0x1000dc1f, + 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, 0x01004800, + 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, 0x02140102, + 0x28160d05, 0x00000008, 0x001b25a4, 0x00c00014, 0x00c00014, + 0x01000014, 0x01000014, 0x01000014, 0x01000014, 0x00c00014, + 0x01000014, 0x00c00014, 0x00c00014, 0x00c00014, 0x00c00014, + 0x00000014, 0x00000014, 0x21555448, 0x01c00014, 0x00000003, + 0x00000000, 0x00000300 +}; + +static const struct rtwn_bb_prog rtl8188eu_bb[] = { + { + nitems(rtl8188eu_bb_regs), + rtl8188eu_bb_regs, + rtl8188eu_bb_vals, + { 0 }, + NULL + } +}; + +static const uint32_t rtl8188eu_agc_vals[] = { + 0xfb000001, 0xfb010001, 0xfb020001, 0xfb030001, 0xfb040001, + 0xfb050001, 0xfa060001, 0xf9070001, 0xf8080001, 0xf7090001, + 0xf60a0001, 0xf50b0001, 0xf40c0001, 0xf30d0001, 0xf20e0001, + 0xf10f0001, 0xf0100001, 0xef110001, 0xee120001, 0xed130001, + 0xec140001, 0xeb150001, 0xea160001, 0xe9170001, 0xe8180001, + 0xe7190001, 0xe61a0001, 0xe51b0001, 0xe41c0001, 0xe31d0001, + 0xe21e0001, 0xe11f0001, 0x8a200001, 0x89210001, 0x88220001, + 0x87230001, 0x86240001, 0x85250001, 0x84260001, 0x83270001, + 0x82280001, 0x6b290001, 0x6a2a0001, 0x692b0001, 0x682c0001, + 0x672d0001, 0x662e0001, 0x652f0001, 0x64300001, 0x63310001, + 0x62320001, 0x61330001, 0x46340001, 0x45350001, 0x44360001, + 0x43370001, 0x42380001, 0x41390001, 0x403a0001, 0x403b0001, + 0x403c0001, 0x403d0001, 0x403e0001, 0x403f0001, 0xfb400001, + 0xfb410001, 0xfb420001, 0xfb430001, 0xfb440001, 0xfb450001, + 0xfb460001, 0xfb470001, 0xfb480001, 0xfa490001, 0xf94a0001, + 0xf84B0001, 0xf74c0001, 0xf64d0001, 0xf54e0001, 0xf44f0001, + 0xf3500001, 0xf2510001, 0xf1520001, 0xf0530001, 0xef540001, + 0xee550001, 0xed560001, 0xec570001, 0xeb580001, 0xea590001, + 0xe95a0001, 0xe85b0001, 0xe75c0001, 0xe65d0001, 0xe55e0001, + 0xe45f0001, 0xe3600001, 0xe2610001, 0xc3620001, 0xc2630001, + 0xc1640001, 0x8b650001, 0x8a660001, 0x89670001, 0x88680001, + 0x87690001, 0x866a0001, 0x856b0001, 0x846c0001, 0x676d0001, + 0x666e0001, 0x656f0001, 0x64700001, 0x63710001, 0x62720001, + 0x61730001, 0x60740001, 0x46750001, 0x45760001, 0x44770001, + 0x43780001, 0x42790001, 0x417a0001, 0x407b0001, 0x407c0001, + 0x407d0001, 0x407e0001, 0x407f0001 +}; + +static const struct rtwn_agc_prog rtl8188eu_agc[] = { + { + nitems(rtl8188eu_agc_vals), + rtl8188eu_agc_vals, + { 0 }, + NULL + } +}; + +/* + * RF initialization values. + */ +static const uint8_t rtl8188eu_rf_regs[] = { + 0x00, 0x08, 0x18, 0x19, 0x1e, 0x1f, 0x2f, 0x3f, 0x42, 0x57, + 0x58, 0x67, 0x83, 0xb0, 0xb1, 0xb2, 0xb4, 0xb6, 0xb7, 0xb8, + 0xb9, 0xba, 0xbb, 0xbf, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xdf, 0xef, 0x51, 0x52, 0x53, 0x56, + 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0xb6, 0x18, 0x5a, + 0x19, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x00, 0x84, 0x86, 0x87, 0x8e, 0x8f, 0xef, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xef, 0x00, 0x18, 0xfe, 0xfe, + 0x1f, 0xfe, 0xfe, 0x1e, 0x1f, 0x00 +}; + +static const uint32_t rtl8188eu_rf_vals[] = { + 0x30000, 0x84000, 0x00407, 0x00012, 0x80009, 0x00880, 0x1a060, + 0x00000, 0x060c0, 0xd0000, 0xbe180, 0x01552, 0x00000, 0xff8fc, + 0x54400, 0xccc19, 0x43003, 0x4953e, 0x1c718, 0x060ff, 0x80001, + 0x40000, 0x00400, 0xc0000, 0x02400, 0x00009, 0x40c91, 0x99999, + 0x000a3, 0x88820, 0x76c06, 0x00000, 0x80000, 0x00180, 0x001a0, + 0x6b27d, 0x7e49d, 0x00073, 0x51ff3, 0x00086, 0x00186, + 0x00286, 0x01c25, 0x09c25, 0x11c25, 0x19c25, 0x48538, 0x00c07, + 0x4bd00, 0x739d0, 0x0adf3, 0x09df0, 0x08ded, 0x07dea, 0x06de7, + 0x054ee, 0x044eb, 0x034e8, 0x0246b, 0x01468, 0x0006d, 0x30159, + 0x68200, 0x000ce, 0x48a00, 0x65540, 0x88000, 0x020a0, 0xf02b0, + 0xef7b0, 0xd4fb0, 0xcf060, 0xb0090, 0xa0080, 0x90080, 0x8f780, + 0x722b0, 0x6f7b0, 0x54fb0, 0x4f060, 0x30090, 0x20080, 0x10080, + 0x0f780, 0x000a0, 0x10159, 0x0f407, 0x0c350, 0x0c350, 0x80003, + 0x0c350, 0x0c350, 0x00001, 0x80000, 0x33e60 +}; + +static const struct rtwn_rf_prog rtl8188eu_rf[] = { + { + nitems(rtl8188eu_rf_regs), + rtl8188eu_rf_regs, + rtl8188eu_rf_vals, + { 0 }, + NULL + }, + { 0, NULL, NULL, { 0 }, NULL } +}; + + +struct rtwn_r88e_txagc { + uint8_t pwr[R88E_GROUP_2G][20]; /* RTWN_RIDX_MCS(7) + 1 */ +}; + +/* + * Per RF chain/group/rate Tx gain values. + */ +static const struct rtwn_r88e_txagc r88e_txagc[] = { + { { /* Chain 0. */ + { /* Group 0. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + }, + { /* Group 1. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + }, + { /* Group 2. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + }, + { /* Group 3. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + }, + { /* Group 4. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + }, + { /* Group 5. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + } + } } +}; + +#endif /* R88E_PRIV_H */ diff --git a/sys/dev/rtwn/rtl8188e/r88e_reg.h b/sys/dev/rtwn/rtl8188e/r88e_reg.h new file mode 100644 index 000000000000..f6f26fa4515a --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_reg.h @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R88E_REG_H +#define R88E_REG_H + +#include + +/* + * MAC registers. + */ +/* System Configuration. */ +#define R88E_BB_PAD_CTRL 0x064 +#define R88E_HIMR 0x0b0 +#define R88E_HISR 0x0b4 +#define R88E_HIMRE 0x0b8 +#define R88E_HISRE 0x0bc +/* MAC General Configuration. */ +#define R88E_32K_CTRL 0x194 +#define R88E_HMEBOX_EXT(idx) (0x1f0 + (idx) * 4) +/* Protocol Configuration. */ +#define R88E_TXPKTBUF_BCNQ1_BDNY 0x457 +#define R88E_MACID_NO_LINK 0x484 +#define R88E_TX_RPT_CTRL 0x4ec +#define R88E_TX_RPT_MACID_MAX 0x4ed +#define R88E_TX_RPT_TIME 0x4f0 +#define R88E_SCH_TXCMD 0x5f8 + + +/* Bits for R88E_HIMR. */ +#define R88E_HIMR_CPWM 0x00000100 +#define R88E_HIMR_CPWM2 0x00000200 +#define R88E_HIMR_TBDER 0x04000000 +#define R88E_HIMR_PSTIMEOUT 0x20000000 + +/* Bits for R88E_HIMRE.*/ +#define R88E_HIMRE_RXFOVW 0x00000100 +#define R88E_HIMRE_TXFOVW 0x00000200 +#define R88E_HIMRE_RXERR 0x00000400 +#define R88E_HIMRE_TXERR 0x00000800 + +/* Bits for R88E_TX_RPT_CTRL. */ +#define R88E_TX_RPT1_ENA 0x01 +#define R88E_TX_RPT2_ENA 0x02 + +/* Bits for R92C_MBID_NUM. */ +#define R88E_MBID_TXBCN_RPT(id) (0x08 << (id)) + +/* Bits for R92C_SECCFG. */ +#define R88E_SECCFG_CHK_KEYID 0x0100 + + +/* + * Baseband registers. + */ +/* Bits for R92C_LSSI_PARAM(i). */ +#define R88E_LSSI_PARAM_ADDR_M 0x0ff00000 +#define R88E_LSSI_PARAM_ADDR_S 20 + + +/* + * RF (6052) registers. + */ +#define R88E_RF_T_METER 0x42 + +/* Bits for R92C_RF_CHNLBW. */ +#define R88E_RF_CHNLBW_BW20 0x00c00 + +/* Bits for R88E_RF_T_METER. */ +#define R88E_RF_T_METER_VAL_M 0x0fc00 +#define R88E_RF_T_METER_VAL_S 10 +#define R88E_RF_T_METER_START 0x30000 + +#endif /* R88E_REG_H */ diff --git a/sys/dev/rtwn/rtl8188e/r88e_rf.c b/sys/dev/rtwn/rtl8188e/r88e_rf.c new file mode 100644 index 000000000000..a836f138aeb5 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_rf.c @@ -0,0 +1,60 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r88e_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr, uint32_t val) +{ + rtwn_bb_write(sc, R92C_LSSI_PARAM(chain), + SM(R88E_LSSI_PARAM_ADDR, addr) | + SM(R92C_LSSI_PARAM_DATA, val)); +} diff --git a/sys/dev/rtwn/rtl8188e/r88e_rom.c b/sys/dev/rtwn/rtl8188e/r88e_rom.c new file mode 100644 index 000000000000..b12d7db83d42 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_rom.c @@ -0,0 +1,85 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + + +void +r88e_parse_rom(struct rtwn_softc *sc, uint8_t *buf) +{ + struct r92c_softc *rs = sc->sc_priv; + struct rtwn_r88e_txpwr *rt = rs->rs_txpwr; + struct r88e_rom *rom = (struct r88e_rom *)buf; + int i; + + rt->bw20_tx_pwr_diff = RTWN_SIGN4TO8(MS(rom->tx_pwr_diff, HIGH_PART)); + rt->ofdm_tx_pwr_diff = RTWN_SIGN4TO8(MS(rom->tx_pwr_diff, LOW_PART)); + for (i = 0; i < nitems(rom->cck_tx_pwr); i++) + rt->cck_tx_pwr[i] = rom->cck_tx_pwr[i]; + for (i = 0; i < nitems(rom->ht40_tx_pwr); i++) + rt->ht40_tx_pwr[i] = rom->ht40_tx_pwr[i]; + + rs->crystalcap = RTWN_GET_ROM_VAR(rom->crystalcap, + R88E_ROM_CRYSTALCAP_DEF); + rs->regulatory = MS(rom->rf_board_opt, R92C_ROM_RF1_REGULATORY); + rs->board_type = + MS(RTWN_GET_ROM_VAR(rom->rf_board_opt, R92C_BOARD_TYPE_DONGLE), + R92C_ROM_RF1_BOARD_TYPE); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "%s: regulatory type %d\n", + __func__,rs->regulatory); + + sc->thermal_meter = rom->thermal_meter; + IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr); +} diff --git a/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h b/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h new file mode 100644 index 000000000000..5734246fae70 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_rom_defs.h @@ -0,0 +1,29 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef R88E_ROM_DEFS_H +#define R88E_ROM_DEFS_H + +#include + +#define R88E_GROUP_2G 6 + +#define R88E_EFUSE_MAX_LEN 512 +#define R88E_EFUSE_MAP_LEN 512 + +#endif /* R88E_ROM_DEFS_H */ diff --git a/sys/dev/rtwn/rtl8188e/r88e_rom_image.h b/sys/dev/rtwn/rtl8188e/r88e_rom_image.h new file mode 100644 index 000000000000..c80028e00d6b --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_rom_image.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef R88E_ROM_IMAGE_H +#define R88E_ROM_IMAGE_H + +#include + +/* + * RTL8188EU ROM image. + */ +struct r88e_rom { + uint8_t reserved1[16]; + uint8_t cck_tx_pwr[R88E_GROUP_2G]; + uint8_t ht40_tx_pwr[R88E_GROUP_2G - 1]; + uint8_t tx_pwr_diff; + uint8_t reserved2[156]; + uint8_t channel_plan; + uint8_t crystalcap; +#define R88E_ROM_CRYSTALCAP_DEF 0x20 + + uint8_t thermal_meter; + uint8_t reserved3[6]; + uint8_t rf_board_opt; + uint8_t rf_feature_opt; + uint8_t rf_bt_opt; + uint8_t version; + uint8_t customer_id; + uint8_t reserved4[3]; + uint8_t rf_ant_opt; + uint8_t reserved5[6]; + uint16_t vid; + uint16_t pid; + uint8_t usb_opt; + uint8_t reserved6[2]; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + uint8_t reserved7[2]; + uint8_t string[33]; /* "realtek 802.11n NIC" */ + uint8_t reserved8[256]; +} __packed; + +_Static_assert(sizeof(struct r88e_rom) == R88E_EFUSE_MAP_LEN, + "R88E_EFUSE_MAP_LEN must be equal to sizeof(struct r88e_rom)!"); + +#endif /* R88E_ROM_IMAGE_H */ diff --git a/sys/dev/rtwn/rtl8188e/r88e_rx.c b/sys/dev/rtwn/rtl8188e/r88e_rx.c new file mode 100644 index 000000000000..3f31393deb74 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_rx.c @@ -0,0 +1,211 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r88e_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) +{ +#if __FreeBSD_version >= 1200012 + struct ieee80211_ratectl_tx_status txs; +#endif + struct r88e_tx_rpt_ccx *rpt; + struct ieee80211_node *ni; + uint8_t macid; + int ntries; + + /* Skip Rx descriptor. */ + buf += sizeof(struct r92c_rx_stat); + len -= sizeof(struct r92c_rx_stat); + + rpt = (struct r88e_tx_rpt_ccx *)buf; + if (len != sizeof(*rpt)) { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: wrong report size (%d, must be %zu)\n", + __func__, len, sizeof(*rpt)); + return; + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: ccx report dump: 0: %02X, 1: %02X, 2: %02X, queue time: " + "low %02X, high %02X, final ridx: %02X, 6: %02X, 7: %02X\n", + __func__, rpt->rptb0, rpt->rptb1, rpt->rptb2, rpt->queue_time_low, + rpt->queue_time_high, rpt->final_rate, rpt->rptb6, rpt->rptb7); + + macid = MS(rpt->rptb1, R88E_RPTB1_MACID); + if (macid > sc->macid_limit) { + device_printf(sc->sc_dev, + "macid %u is too big; increase MACID_MAX limit\n", + macid); + return; + } + + ntries = MS(rpt->rptb2, R88E_RPTB2_RETRY_CNT); + + ni = sc->node_list[macid]; + if (ni != NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was" + "%s sent (%d retries)\n", __func__, macid, + (rpt->rptb1 & R88E_RPTB1_PKT_OK) ? "" : " not", + ntries); + +#if __FreeBSD_version >= 1200012 + txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY | + IEEE80211_RATECTL_STATUS_FINAL_RATE; + txs.long_retries = ntries; + if (rpt->final_rate > RTWN_RIDX_OFDM54) { /* MCS */ + txs.final_rate = + (rpt->final_rate - 12) | IEEE80211_RATE_MCS; + } else + txs.final_rate = ridx2rate[rpt->final_rate]; + if (rpt->rptb1 & R88E_RPTB1_PKT_OK) + txs.status = IEEE80211_RATECTL_TX_SUCCESS; + else if (rpt->rptb2 & R88E_RPTB2_RETRY_OVER) + txs.status = IEEE80211_RATECTL_TX_FAIL_LONG; + else if (rpt->rptb2 & R88E_RPTB2_LIFE_EXPIRE) + txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED; + else + txs.status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED; + ieee80211_ratectl_tx_complete(ni, &txs); +#else + struct ieee80211vap *vap = ni->ni_vap; + if (rpt->rptb1 & R88E_RPTB1_PKT_OK) { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL); + } else { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL); + } +#endif + } else { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: macid %u, ni is NULL\n", + __func__, macid); + } +} + +void +r88e_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len) +{ + + /* Skip Rx descriptor. */ + buf += sizeof(struct r92c_rx_stat); + len -= sizeof(struct r92c_rx_stat); + + if (len != R88E_INTR_MSG_LEN) { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: wrong interrupt message size (%d, must be %d)\n", + __func__, len, R88E_INTR_MSG_LEN); + return; + } + + /* XXX TODO */ +} + +int8_t +r88e_get_rssi_cck(struct rtwn_softc *sc, void *physt) +{ + struct r88e_rx_phystat *phy = (struct r88e_rx_phystat *)physt; + int8_t lna_idx, vga_idx, rssi; + + lna_idx = (phy->agc_rpt & 0xe0) >> 5; + vga_idx = (phy->agc_rpt & 0x1f); + rssi = 6 - 2 * vga_idx; + + switch (lna_idx) { + case 7: + if (vga_idx > 27) + rssi = -100 + 6; + else + rssi += -100 + 2 * 27; + break; + case 6: + rssi += -48 + 2 * 2; + break; + case 5: + rssi += -42 + 2 * 7; + break; + case 4: + rssi += -36 + 2 * 7; + break; + case 3: + rssi += -24 + 2 * 7; + break; + case 2: + rssi += -6 + 2 * 5; + if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR) + rssi -= 6; + break; + case 1: + rssi += 8; + break; + case 0: + rssi += 14; + break; + } + + return (rssi); +} + +int8_t +r88e_get_rssi_ofdm(struct rtwn_softc *sc, void *physt) +{ + struct r88e_rx_phystat *phy = (struct r88e_rx_phystat *)physt; + int rssi; + + /* Get average RSSI. */ + rssi = ((phy->sig_qual >> 1) & 0x7f) - 110; + + return (rssi); +} diff --git a/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h b/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h new file mode 100644 index 000000000000..2b72f3dd79b4 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_rx_desc.h @@ -0,0 +1,100 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R88E_RX_DESC_H +#define R88E_RX_DESC_H + +#include + +/* Rx MAC descriptor defines (chip-specific). */ +/* Rx dword 3 */ +#define R88E_RXDW3_RPT_M 0x0000c000 +#define R88E_RXDW3_RPT_S 14 +#define R88E_RXDW3_RPT_RX 0 +#define R88E_RXDW3_RPT_TX1 1 +#define R88E_RXDW3_RPT_TX2 2 +#define R88E_RXDW3_RPT_HIS 3 + +/* Rx PHY descriptor. */ +struct r88e_rx_phystat { + uint8_t path_agc[2]; + uint8_t chan; + uint8_t reserved1; + uint8_t sig_qual; + uint8_t agc_rpt; + uint8_t rpt_b; + uint8_t reserved2; + uint8_t noise_power; + uint8_t path_cfotail[2]; + uint8_t pcts_mask[2]; + uint8_t stream_rxevm[2]; + uint8_t path_rxsnr[2]; + uint8_t noise_power_db_lsb; + uint8_t reserved3[3]; + uint8_t stream_csi[2]; + uint8_t stream_target_csi[2]; + uint8_t sig_evm; +} __packed; + +/* Tx report (type 1). */ +struct r88e_tx_rpt_ccx { + uint8_t rptb0; +#define R88E_RPTB6_PKT_NUM_M 0x0e +#define R88E_RPTB6_PKT_NUM_S 1 +#define R88E_RPTB0_INT_CCX 0x80 + + uint8_t rptb1; +#define R88E_RPTB1_MACID_M 0x3f +#define R88E_RPTB1_MACID_S 0 +#define R88E_RPTB1_PKT_OK 0x40 +#define R88E_RPTB1_BMC 0x80 + + uint8_t rptb2; +#define R88E_RPTB2_RETRY_CNT_M 0x3f +#define R88E_RPTB2_RETRY_CNT_S 0 +#define R88E_RPTB2_LIFE_EXPIRE 0x40 +#define R88E_RPTB2_RETRY_OVER 0x80 + + uint8_t queue_time_low; + uint8_t queue_time_high; + uint8_t final_rate; + uint8_t rptb6; +#define R88E_RPTB6_QSEL_M 0xf0 +#define R88E_RPTB6_QSEL_S 4 + + uint8_t rptb7; +} __packed; + +/* Interrupt message format. */ +/* XXX recheck */ +struct r88e_intr_msg { + uint8_t c2h_id; + uint8_t c2h_seq; + uint8_t c2h_evt; + uint8_t reserved1[13]; + uint8_t cpwm1; + uint8_t reserved2[3]; + uint8_t cpwm2; + uint8_t reserved3[27]; + uint32_t hisr; + uint32_t hisr_ex; +}; + +#endif /* R88E_RX_DESC_H */ diff --git a/sys/dev/rtwn/rtl8188e/r88e_tx.c b/sys/dev/rtwn/rtl8188e/r88e_tx.c new file mode 100644 index 000000000000..dd3aaecefa44 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_tx.c @@ -0,0 +1,79 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r88e_tx_enable_ampdu(void *buf, int enable) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + if (enable) + txd->txdw2 |= htole32(R88E_TXDW2_AGGEN); + else + txd->txdw2 |= htole32(R88E_TXDW2_AGGBK); +} + +void +r88e_tx_setup_hwseq(void *buf) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + txd->txdseq |= htole16(R88E_TXDSEQ_HWSEQ_EN); +} + +void +r88e_tx_setup_macid(void *buf, int id) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, id)); +} diff --git a/sys/dev/rtwn/rtl8188e/r88e_tx_desc.h b/sys/dev/rtwn/rtl8188e/r88e_tx_desc.h new file mode 100644 index 000000000000..98338fb732f3 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/r88e_tx_desc.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R88E_TX_DESC_H +#define R88E_TX_DESC_H + +#include + +/* Tx MAC descriptor defines (chip-specific). */ +/* Tx dword 1. */ +#define R88E_TXDW1_MACID_M 0x0000003f +#define R88E_TXDW1_MACID_S 0 + +/* Tx dword 2. */ +#define R88E_TXDW2_AGGEN 0x00001000 +#define R88E_TXDW2_AGGBK 0x00010000 + +/* Tx dword 3. */ +#define R88E_TXDSEQ_HWSEQ_EN 0x8000 + +#endif /* R88E_TX_DESC_H */ diff --git a/sys/dev/rtwn/rtl8188e/usb/r88eu.h b/sys/dev/rtwn/rtl8188e/usb/r88eu.h new file mode 100644 index 000000000000..85b637cb7cc2 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/usb/r88eu.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef RTL8188EU_H +#define RTL8188EU_H + +#include + + +/* + * Function declarations. + */ +/* r88eu_init.c */ +void r88eu_power_off(struct rtwn_softc *); +void r88eu_init_intr(struct rtwn_softc *); +void r88eu_init_rx_agg(struct rtwn_softc *); +void r88eu_post_init(struct rtwn_softc *); + +/* r88eu_rx.c */ +int r88eu_classify_intr(struct rtwn_softc *, void *, int); + +#endif /* RTL8188EU_H */ diff --git a/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c b/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c new file mode 100644 index 000000000000..aabdeb151ee0 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c @@ -0,0 +1,216 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +#include + + +static struct rtwn_r88e_txpwr r88e_txpwr; + +void r88eu_attach(struct rtwn_usb_softc *); + +static void +r88e_postattach(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + struct ieee80211com *ic = &sc->sc_ic; + + rs->rs_scan_start = ic->ic_scan_start; + ic->ic_scan_start = r92c_scan_start; + rs->rs_scan_end = ic->ic_scan_end; + ic->ic_scan_end = r92c_scan_end; +} + +static void +r88eu_attach_private(struct rtwn_softc *sc) +{ + struct r92c_softc *rs; + + rs = malloc(sizeof(struct r92c_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO); + + rs->rs_txpwr = &r88e_txpwr; + rs->rs_txagc = &r88e_txagc; + + rs->rs_set_bw20 = r88e_set_bw20; + rs->rs_get_txpower = r88e_get_txpower; + rs->rs_set_gain = r88e_set_gain; + rs->rs_tx_enable_ampdu = r88e_tx_enable_ampdu; + rs->rs_tx_setup_hwseq = r88e_tx_setup_hwseq; + rs->rs_tx_setup_macid = r88e_tx_setup_macid; + rs->rs_set_name = rtwn_nop_softc; /* not used */ + + rs->rf_read_delay[0] = 10; + rs->rf_read_delay[1] = 100; + rs->rf_read_delay[2] = 10; + + sc->sc_priv = rs; +} + +static void +r88eu_adj_devcaps(struct rtwn_softc *sc) +{ + /* XXX TODO? */ +} + +void +r88eu_attach(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + + /* USB part. */ + uc->uc_align_rx = r92cu_align_rx; + uc->tx_agg_desc_num = 6; + + /* Common part. */ + sc->sc_flags = RTWN_FLAG_EXT_HDR; + + sc->sc_set_chan = r92c_set_chan; + sc->sc_fill_tx_desc = r92c_fill_tx_desc; + sc->sc_fill_tx_desc_raw = r92c_fill_tx_desc_raw; + sc->sc_fill_tx_desc_null = r92c_fill_tx_desc_null; + sc->sc_dump_tx_desc = r92cu_dump_tx_desc; + sc->sc_tx_radiotap_flags = r92c_tx_radiotap_flags; + sc->sc_rx_radiotap_flags = r92c_rx_radiotap_flags; + sc->sc_get_rssi_cck = r88e_get_rssi_cck; + sc->sc_get_rssi_ofdm = r88e_get_rssi_ofdm; + sc->sc_classify_intr = r88eu_classify_intr; + sc->sc_handle_tx_report = r88e_ratectl_tx_complete; + sc->sc_handle_c2h_report = r88e_handle_c2h_report; + sc->sc_check_frame = rtwn_nop_int_softc_mbuf; + sc->sc_rf_read = r92c_rf_read; + sc->sc_rf_write = r88e_rf_write; + sc->sc_check_condition = r92c_check_condition; + sc->sc_efuse_postread = rtwn_nop_softc; + sc->sc_parse_rom = r88e_parse_rom; + sc->sc_set_led = r88e_set_led; + sc->sc_power_on = r88e_power_on; + sc->sc_power_off = r88eu_power_off; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_fw_reset = r88e_fw_reset; + sc->sc_fw_download_enable = r88e_fw_download_enable; +#endif + sc->sc_set_page_size = r92c_set_page_size; + sc->sc_lc_calib = r92c_lc_calib; + sc->sc_iq_calib = r88e_iq_calib; /* XXX TODO */ + sc->sc_read_chipid_vendor = rtwn_nop_softc_uint32; + sc->sc_adj_devcaps = r88eu_adj_devcaps; + sc->sc_vap_preattach = rtwn_nop_softc_vap; + sc->sc_postattach = r88e_postattach; + sc->sc_detach_private = r92c_detach_private; + sc->sc_set_media_status = r88e_set_media_status; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_set_rsvd_page = r88e_set_rsvd_page; + sc->sc_set_pwrmode = r88e_set_pwrmode; + sc->sc_set_rssi = rtwn_nop_softc; /* XXX TODO? */ +#endif + sc->sc_beacon_init = r92c_beacon_init; + sc->sc_beacon_enable = r88e_beacon_enable; + sc->sc_beacon_set_rate = rtwn_nop_void_int; + sc->sc_beacon_select = rtwn_nop_softc_int; + sc->sc_temp_measure = r88e_temp_measure; + sc->sc_temp_read = r88e_temp_read; + sc->sc_init_tx_agg = r92cu_init_tx_agg; + sc->sc_init_rx_agg = r88eu_init_rx_agg; + sc->sc_init_ampdu = rtwn_nop_softc; + sc->sc_init_intr = r88eu_init_intr; + sc->sc_init_edca = r92c_init_edca; + sc->sc_init_bb = r88e_init_bb; + sc->sc_init_rf = r92c_init_rf_common; + sc->sc_init_antsel = rtwn_nop_softc; + sc->sc_post_init = r88eu_post_init; + sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc; + + sc->mac_prog = &rtl8188eu_mac[0]; + sc->mac_size = nitems(rtl8188eu_mac); + sc->bb_prog = &rtl8188eu_bb[0]; + sc->bb_size = nitems(rtl8188eu_bb); + sc->agc_prog = &rtl8188eu_agc[0]; + sc->agc_size = nitems(rtl8188eu_agc); + sc->rf_prog = &rtl8188eu_rf[0]; + + sc->name = "RTL8188EU"; + sc->fwname = "rtwn-rtl8188eufw"; + sc->fwsig = 0x88e; + + sc->page_count = R88E_TX_PAGE_COUNT; + sc->pktbuf_count = R88E_TXPKTBUF_COUNT; + + sc->ackto = 0x40; + sc->npubqpages = R88E_PUBQ_NPAGES; + sc->page_size = R92C_TX_PAGE_SIZE; + + sc->txdesc_len = sizeof(struct r92cu_tx_desc); + sc->efuse_maxlen = R88E_EFUSE_MAX_LEN; + sc->efuse_maplen = R88E_EFUSE_MAP_LEN; + sc->rx_dma_size = R88E_RX_DMA_BUFFER_SIZE; + + sc->macid_limit = R88E_MACID_MAX + 1; + sc->cam_entry_limit = R92C_CAM_ENTRY_COUNT; + sc->fwsize_limit = R92C_MAX_FW_SIZE; + sc->temp_delta = R88E_CALIB_THRESHOLD; + + sc->bcn_status_reg[0] = R92C_TDECTRL; + sc->bcn_status_reg[1] = R92C_TDECTRL; + sc->rcr = 0; + + sc->ntxchains = 1; + sc->nrxchains = 1; + + r88eu_attach_private(sc); +} diff --git a/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c b/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c new file mode 100644 index 000000000000..318a827e6fe9 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c @@ -0,0 +1,227 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r88eu_power_off(struct rtwn_softc *sc) +{ + uint8_t reg; + int error, ntries; + + /* Disable any kind of TX reports. */ + error = rtwn_setbits_1(sc, R88E_TX_RPT_CTRL, + R88E_TX_RPT1_ENA | R88E_TX_RPT2_ENA, 0); + if (error == ENXIO) /* hardware gone */ + return; + + /* Stop Rx. */ + rtwn_write_1(sc, R92C_CR, 0); + + /* Move card to Low Power State. */ + /* Block all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + + for (ntries = 0; ntries < 10; ntries++) { + /* Should be zero if no packet is transmitting. */ + if (rtwn_read_4(sc, R88E_SCH_TXCMD) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: failed to block Tx queues\n", + __func__); + return; + } + + /* CCK and OFDM are disabled, and clock are gated. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BBRSTB, 0); + + rtwn_delay(sc, 1); + + /* Reset MAC TRX */ + rtwn_write_1(sc, R92C_CR, + R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | + R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | + R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN); + + /* check if removed later */ + rtwn_setbits_1_shift(sc, R92C_CR, R92C_CR_ENSEC, 0, 1); + + /* Respond TxOK to scheduler */ + rtwn_setbits_1(sc, R92C_DUAL_TSF_RST, 0, 0x20); + + /* If firmware in ram code, do reset. */ +#ifndef RTWN_WITHOUT_UCODE + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RDY) + r88e_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN); +#endif + + /* Reset MCU ready status. */ + rtwn_write_1(sc, R92C_MCUFWDL, 0); + + /* Disable 32k. */ + rtwn_setbits_1(sc, R88E_32K_CTRL, 0x01, 0); + + /* Move card to Disabled state. */ + /* Turn off RF. */ + rtwn_write_1(sc, R92C_RF_CTRL, 0); + + /* LDO Sleep mode. */ + rtwn_setbits_1(sc, R92C_LPLDO_CTRL, 0, R92C_LPLDO_CTRL_SLEEP); + + /* Turn off MAC by HW state machine */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_APFM_OFF, 1); + + for (ntries = 0; ntries < 10; ntries++) { + /* Wait until it will be disabled. */ + if ((rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_OFF) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: could not turn off MAC\n", + __func__); + return; + } + + /* schmit trigger */ + rtwn_setbits_1(sc, R92C_AFE_XTAL_CTRL + 2, 0, 0x80); + + /* Enable WL suspend. */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_PCIE, R92C_APS_FSMCO_AFSM_HSUS, 1); + + /* Enable bandgap mbias in suspend. */ + rtwn_write_1(sc, R92C_APS_FSMCO + 3, 0); + + /* Clear SIC_EN register. */ + rtwn_setbits_1(sc, R92C_GPIO_MUXCFG + 1, 0x10, 0); + + /* Set USB suspend enable local register */ + rtwn_setbits_1(sc, R92C_USB_SUSPEND, 0, 0x10); + + /* Reset MCU IO Wrapper. */ + reg = rtwn_read_1(sc, R92C_RSV_CTRL + 1); + rtwn_write_1(sc, R92C_RSV_CTRL + 1, reg & ~0x08); + rtwn_write_1(sc, R92C_RSV_CTRL + 1, reg | 0x08); + + /* marked as 'For Power Consumption' code. */ + rtwn_write_1(sc, R92C_GPIO_OUT, rtwn_read_1(sc, R92C_GPIO_IN)); + rtwn_write_1(sc, R92C_GPIO_IOSEL, 0xff); + + rtwn_write_1(sc, R92C_GPIO_IO_SEL, + rtwn_read_1(sc, R92C_GPIO_IO_SEL) << 4); + rtwn_setbits_1(sc, R92C_GPIO_MOD, 0, 0x0f); + + /* Set LNA, TRSW, EX_PA Pin to output mode. */ + rtwn_write_4(sc, R88E_BB_PAD_CTRL, 0x00080808); +} + +void +r88eu_init_intr(struct rtwn_softc *sc) +{ + /* TODO: adjust */ + rtwn_write_4(sc, R88E_HISR, 0xffffffff); + rtwn_write_4(sc, R88E_HIMR, R88E_HIMR_CPWM | R88E_HIMR_CPWM2 | + R88E_HIMR_TBDER | R88E_HIMR_PSTIMEOUT); + rtwn_write_4(sc, R88E_HIMRE, R88E_HIMRE_RXFOVW | + R88E_HIMRE_TXFOVW | R88E_HIMRE_RXERR | R88E_HIMRE_TXERR); + rtwn_setbits_1(sc, R92C_USB_SPECIAL_OPTION, 0, + R92C_USB_SPECIAL_OPTION_INT_BULK_SEL); +} + +void +r88eu_init_rx_agg(struct rtwn_softc *sc) +{ + /* XXX merge? */ + rtwn_setbits_1(sc, R92C_TRXDMA_CTRL, 0, + R92C_TRXDMA_CTRL_RXDMA_AGG_EN); + /* XXX dehardcode */ + rtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH, 48); + rtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH + 1, 4); +} + +void +r88eu_post_init(struct rtwn_softc *sc) +{ + /* Turn CCK and OFDM blocks on. */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_CCK_EN); + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_OFDM_EN); + + /* Enable per-packet TX report. */ + rtwn_setbits_1(sc, R88E_TX_RPT_CTRL, 0, R88E_TX_RPT1_ENA); + + /* Disable Tx if MACID is not associated. */ + rtwn_write_4(sc, R88E_MACID_NO_LINK, 0xffffffff); + rtwn_write_4(sc, R88E_MACID_NO_LINK + 4, 0xffffffff); + r88e_macid_enable_link(sc, RTWN_MACID_BC, 1); + + /* Perform LO and IQ calibrations. */ + r88e_iq_calib(sc); + /* Perform LC calibration. */ + r92c_lc_calib(sc); + + rtwn_write_1(sc, R92C_USB_HRPWM, 0); + + if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) { + /* No support (yet?) for f/w rate adaptation. */ + sc->sc_ratectl = RTWN_RATECTL_NET80211; + } else + sc->sc_ratectl = sc->sc_ratectl_sysctl; +} diff --git a/sys/dev/rtwn/rtl8188e/usb/r88eu_reg.h b/sys/dev/rtwn/rtl8188e/usb/r88eu_reg.h new file mode 100644 index 000000000000..fc61eaae5851 --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/usb/r88eu_reg.h @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R88EU_REG_H +#define R88EU_REG_H + +#include +#include + +#endif /* R88EU_REG_H */ diff --git a/sys/dev/rtwn/rtl8188e/usb/r88eu_rx.c b/sys/dev/rtwn/rtl8188e/usb/r88eu_rx.c new file mode 100644 index 000000000000..a5d26b426e7e --- /dev/null +++ b/sys/dev/rtwn/rtl8188e/usb/r88eu_rx.c @@ -0,0 +1,74 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include + + +int +r88eu_classify_intr(struct rtwn_softc *sc, void *buf, int len) +{ + struct r92c_rx_stat *stat = buf; + int report_sel = MS(le32toh(stat->rxdw3), R88E_RXDW3_RPT); + + switch (report_sel) { + case R88E_RXDW3_RPT_RX: + return (RTWN_RX_DATA); + case R88E_RXDW3_RPT_TX1: /* per-packet Tx report */ + case R88E_RXDW3_RPT_TX2: /* periodical Tx report */ + return (RTWN_RX_TX_REPORT); + case R88E_RXDW3_RPT_HIS: + return (RTWN_RX_OTHER); + default: /* shut up the compiler */ + return (RTWN_RX_DATA); + } +} diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce.h b/sys/dev/rtwn/rtl8192c/pci/r92ce.h new file mode 100644 index 000000000000..93379f8bb539 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/pci/r92ce.h @@ -0,0 +1,74 @@ +/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTL8192CE_H +#define RTL8192CE_H + +#include + + +/* + * Global definitions. + */ +#define R92CE_PUBQ_NPAGES 176 +#define R92CE_HPQ_NPAGES 41 +#define R92CE_LPQ_NPAGES 28 +#define R92CE_TX_PAGE_COUNT \ + (R92CE_PUBQ_NPAGES + R92CE_HPQ_NPAGES + R92CE_LPQ_NPAGES) + + +/* + * Function declarations. + */ +/* r92ce_calib.c */ +void r92ce_iq_calib(struct rtwn_softc *); + +/* r92ce_fw.c */ +#ifndef RTWN_WITHOUT_UCODE +void r92ce_fw_reset(struct rtwn_softc *, int); +#endif + +/* r92ce_init.c */ +void r92ce_init_intr(struct rtwn_softc *); +void r92ce_init_edca(struct rtwn_softc *); +void r92ce_init_bb(struct rtwn_softc *); +int r92ce_power_on(struct rtwn_softc *); +void r92ce_power_off(struct rtwn_softc *); +void r92ce_init_ampdu(struct rtwn_softc *); +void r92ce_post_init(struct rtwn_softc *); + +/* r92ce_led.c */ +void r92ce_set_led(struct rtwn_softc *, int, int); + +/* r92ce_rx.c */ +int r92ce_classify_intr(struct rtwn_softc *, void *, int); +void r92ce_enable_intr(struct rtwn_pci_softc *); +void r92ce_start_xfers(struct rtwn_softc *); + +/* r92ce_tx.c */ +void r92ce_setup_tx_desc(struct rtwn_pci_softc *, void *, uint32_t); +void r92ce_tx_postsetup(struct rtwn_pci_softc *, void *, + bus_dma_segment_t[]); +void r92ce_copy_tx_desc(void *, const void *); +void r92ce_dump_tx_desc(struct rtwn_softc *, const void *); + +#endif /* RTL8192CE_H */ diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c b/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c new file mode 100644 index 000000000000..b324d5c2022b --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/pci/r92ce_attach.c @@ -0,0 +1,263 @@ +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + + +static struct rtwn_r92c_txpwr r92c_txpwr; + +void r92ce_attach(struct rtwn_pci_softc *); + +static void +r92ce_postattach(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + struct ieee80211com *ic = &sc->sc_ic; + + if (!(rs->chip & R92C_CHIP_92C) && + rs->board_type == R92C_BOARD_TYPE_HIGHPA) + rs->rs_txagc = &rtl8188ru_txagc[0]; + else + rs->rs_txagc = &rtl8192cu_txagc[0]; + + if ((rs->chip & (R92C_CHIP_UMC_A_CUT | R92C_CHIP_92C)) == + R92C_CHIP_UMC_A_CUT) + sc->fwname = "rtwn-rtl8192cfwE"; + else + sc->fwname = "rtwn-rtl8192cfwE_B"; + sc->fwsig = 0x88c; + + rs->rs_scan_start = ic->ic_scan_start; + ic->ic_scan_start = r92c_scan_start; + rs->rs_scan_end = ic->ic_scan_end; + ic->ic_scan_end = r92c_scan_end; +} + +static void +r92ce_set_name(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + + if (rs->chip & R92C_CHIP_92C) + sc->name = "RTL8192CE"; + else + sc->name = "RTL8188CE"; +} + +static void +r92ce_attach_private(struct rtwn_softc *sc) +{ + struct r92c_softc *rs; + + rs = malloc(sizeof(struct r92c_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO); + + rs->rs_txpwr = &r92c_txpwr; + + rs->rs_set_bw20 = r92c_set_bw20; + rs->rs_get_txpower = r92c_get_txpower; + rs->rs_set_gain = r92c_set_gain; + rs->rs_tx_enable_ampdu = r92c_tx_enable_ampdu; + rs->rs_tx_setup_hwseq = r92c_tx_setup_hwseq; + rs->rs_tx_setup_macid = r92c_tx_setup_macid; + rs->rs_set_name = r92ce_set_name; + + /* XXX TODO: test with net80211 ratectl! */ +#ifndef RTWN_WITHOUT_UCODE + rs->rs_c2h_timeout = hz; + + callout_init_mtx(&rs->rs_c2h_report, &sc->sc_mtx, 0); +#endif + + rs->rf_read_delay[0] = 1000; + rs->rf_read_delay[1] = 1000; + rs->rf_read_delay[2] = 1000; + + sc->sc_priv = rs; +} + +static void +r92ce_adj_devcaps(struct rtwn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + /* XXX TODO: test everything that removed here before enabling. */ + /* XX do NOT enable PMGT until RSVD_PAGE command will not be fixed. */ + ic->ic_caps &= ~( + IEEE80211_C_IBSS /* check beaconing / tsf */ + | IEEE80211_C_HOSTAP /* the same */ + | IEEE80211_C_PMGT /* check null frame / device usability */ + | IEEE80211_C_SWAMSDUTX + | IEEE80211_C_FF + ); + + ic->ic_htcaps = 0; +} + +void +r92ce_attach(struct rtwn_pci_softc *pc) +{ + struct rtwn_softc *sc = &pc->pc_sc; + + /* PCIe part. */ + pc->pc_setup_tx_desc = r92ce_setup_tx_desc; + pc->pc_tx_postsetup = r92ce_tx_postsetup; + pc->pc_copy_tx_desc = r92ce_copy_tx_desc; + pc->pc_enable_intr = r92ce_enable_intr; + + pc->pc_qmap = 0xf771; + pc->tcr = + R92C_TCR_CFENDFORM | (1 << 12) | (1 << 13); + + /* Common part. */ + /* RTL8192C* cannot use pairwise keys from first 4 slots */ + sc->sc_flags = RTWN_FLAG_CAM_FIXED; + + sc->sc_start_xfers = r92ce_start_xfers; + sc->sc_set_chan = r92c_set_chan; + sc->sc_fill_tx_desc = r92c_fill_tx_desc; + sc->sc_fill_tx_desc_raw = r92c_fill_tx_desc_raw; + sc->sc_fill_tx_desc_null = r92c_fill_tx_desc_null; /* XXX recheck */ + sc->sc_dump_tx_desc = r92ce_dump_tx_desc; + sc->sc_tx_radiotap_flags = r92c_tx_radiotap_flags; + sc->sc_rx_radiotap_flags = r92c_rx_radiotap_flags; + sc->sc_get_rssi_cck = r92c_get_rssi_cck; + sc->sc_get_rssi_ofdm = r92c_get_rssi_ofdm; + sc->sc_classify_intr = r92ce_classify_intr; + sc->sc_handle_tx_report = rtwn_nop_softc_uint8_int; + sc->sc_handle_c2h_report = rtwn_nop_softc_uint8_int; + sc->sc_check_frame = rtwn_nop_int_softc_mbuf; + sc->sc_rf_read = r92c_rf_read; + sc->sc_rf_write = r92c_rf_write; + sc->sc_check_condition = r92c_check_condition; + sc->sc_efuse_postread = r92c_efuse_postread; + sc->sc_parse_rom = r92c_parse_rom; + sc->sc_set_led = r92ce_set_led; + sc->sc_power_on = r92ce_power_on; + sc->sc_power_off = r92ce_power_off; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_fw_reset = r92ce_fw_reset; + sc->sc_fw_download_enable = r92c_fw_download_enable; +#endif + sc->sc_set_page_size = r92c_set_page_size; + sc->sc_lc_calib = r92c_lc_calib; + sc->sc_iq_calib = r92ce_iq_calib; + sc->sc_read_chipid_vendor = r92c_read_chipid_vendor; + sc->sc_adj_devcaps = r92ce_adj_devcaps; + sc->sc_vap_preattach = rtwn_nop_softc_vap; + sc->sc_postattach = r92ce_postattach; + sc->sc_detach_private = r92c_detach_private; + sc->sc_set_media_status = r92c_joinbss_rpt; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_set_rsvd_page = r92c_set_rsvd_page; + sc->sc_set_pwrmode = r92c_set_pwrmode; + sc->sc_set_rssi = r92c_set_rssi; +#endif + sc->sc_beacon_init = r92c_beacon_init; + sc->sc_beacon_enable = r92c_beacon_enable; + sc->sc_beacon_set_rate = rtwn_nop_void_int; + sc->sc_beacon_select = rtwn_nop_softc_int; + sc->sc_temp_measure = r92c_temp_measure; + sc->sc_temp_read = r92c_temp_read; + sc->sc_init_tx_agg = rtwn_nop_softc; + sc->sc_init_rx_agg = rtwn_nop_softc; + sc->sc_init_ampdu = r92ce_init_ampdu; + sc->sc_init_intr = r92ce_init_intr; + sc->sc_init_edca = r92ce_init_edca; + sc->sc_init_bb = r92ce_init_bb; + sc->sc_init_rf = r92c_init_rf; + sc->sc_init_antsel = rtwn_nop_softc; + sc->sc_post_init = r92ce_post_init; + sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc; + + sc->mac_prog = &rtl8192ce_mac[0]; + sc->mac_size = nitems(rtl8192ce_mac); + sc->bb_prog = &rtl8192ce_bb[0]; + sc->bb_size = nitems(rtl8192ce_bb); + sc->agc_prog = &rtl8192ce_agc[0]; + sc->agc_size = nitems(rtl8192ce_agc); + sc->rf_prog = &rtl8192c_rf[0]; + + sc->page_count = R92CE_TX_PAGE_COUNT; + sc->pktbuf_count = R92C_TXPKTBUF_COUNT; + + sc->ackto = 0x40; + sc->npubqpages = R92CE_PUBQ_NPAGES; + sc->nhqpages = R92CE_HPQ_NPAGES; + sc->nnqpages = 0; + sc->nlqpages = R92CE_LPQ_NPAGES; + sc->page_size = R92C_TX_PAGE_SIZE; + + sc->txdesc_len = sizeof(struct r92ce_tx_desc); + sc->efuse_maxlen = R92C_EFUSE_MAX_LEN; + sc->efuse_maplen = R92C_EFUSE_MAP_LEN; + sc->rx_dma_size = R92C_RX_DMA_BUFFER_SIZE; + + sc->macid_limit = R92C_MACID_MAX + 1; + sc->cam_entry_limit = R92C_CAM_ENTRY_COUNT; + sc->fwsize_limit = R92C_MAX_FW_SIZE; + sc->temp_delta = R92C_CALIB_THRESHOLD; + + sc->bcn_status_reg[0] = R92C_TDECTRL; + sc->bcn_status_reg[1] = R92C_TDECTRL; + sc->rcr = 0; + + r92ce_attach_private(sc); +} diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c b/sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c new file mode 100644 index 000000000000..a786c1b8e156 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/pci/r92ce_calib.c @@ -0,0 +1,386 @@ +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + + +/* Registers to save and restore during IQ calibration. */ +struct r92ce_iq_cal_reg_vals { + uint32_t adda[16]; + uint8_t txpause; + uint8_t bcn_ctrl[2]; + uint32_t gpio_muxcfg; + uint32_t ofdm0_trxpathena; + uint32_t ofdm0_trmuxpar; + uint32_t fpga0_rfifacesw1; +}; + +/* XXX 92CU? */ +static int +r92ce_iq_calib_chain(struct rtwn_softc *sc, int chain, uint16_t tx[2], + uint16_t rx[2]) +{ + uint32_t status; + int offset = chain * 0x20; + + if (chain == 0) { /* IQ calibration for chain 0. */ + /* IQ calibration settings for chain 0. */ + rtwn_bb_write(sc, 0xe30, 0x10008c1f); + rtwn_bb_write(sc, 0xe34, 0x10008c1f); + rtwn_bb_write(sc, 0xe38, 0x82140102); + + if (sc->ntxchains > 1) { + rtwn_bb_write(sc, 0xe3c, 0x28160202); /* 2T */ + /* IQ calibration settings for chain 1. */ + rtwn_bb_write(sc, 0xe50, 0x10008c22); + rtwn_bb_write(sc, 0xe54, 0x10008c22); + rtwn_bb_write(sc, 0xe58, 0x82140102); + rtwn_bb_write(sc, 0xe5c, 0x28160202); + } else + rtwn_bb_write(sc, 0xe3c, 0x28160502); /* 1T */ + + /* LO calibration settings. */ + rtwn_bb_write(sc, 0xe4c, 0x001028d1); + /* We're doing LO and IQ calibration in one shot. */ + rtwn_bb_write(sc, 0xe48, 0xf9000000); + rtwn_bb_write(sc, 0xe48, 0xf8000000); + + } else { /* IQ calibration for chain 1. */ + /* We're doing LO and IQ calibration in one shot. */ + rtwn_bb_write(sc, 0xe60, 0x00000002); + rtwn_bb_write(sc, 0xe60, 0x00000000); + } + + /* Give LO and IQ calibrations the time to complete. */ + rtwn_delay(sc, 1000); + + /* Read IQ calibration status. */ + status = rtwn_bb_read(sc, 0xeac); + + if (status & (1 << (28 + chain * 3))) + return (0); /* Tx failed. */ + /* Read Tx IQ calibration results. */ + tx[0] = (rtwn_bb_read(sc, 0xe94 + offset) >> 16) & 0x3ff; + tx[1] = (rtwn_bb_read(sc, 0xe9c + offset) >> 16) & 0x3ff; + if (tx[0] == 0x142 || tx[1] == 0x042) + return (0); /* Tx failed. */ + + if (status & (1 << (27 + chain * 3))) + return (1); /* Rx failed. */ + /* Read Rx IQ calibration results. */ + rx[0] = (rtwn_bb_read(sc, 0xea4 + offset) >> 16) & 0x3ff; + rx[1] = (rtwn_bb_read(sc, 0xeac + offset) >> 16) & 0x3ff; + if (rx[0] == 0x132 || rx[1] == 0x036) + return (1); /* Rx failed. */ + + return (3); /* Both Tx and Rx succeeded. */ +} + +static void +r92ce_iq_calib_run(struct rtwn_softc *sc, int n, uint16_t tx[2][2], + uint16_t rx[2][2], struct r92ce_iq_cal_reg_vals *vals) +{ + /* Registers to save and restore during IQ calibration. */ + static const uint16_t reg_adda[16] = { + 0x85c, 0xe6c, 0xe70, 0xe74, + 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, + 0xed8, 0xedc, 0xee0, 0xeec + }; + int i, chain; + uint32_t hssi_param1; + + if (n == 0) { + for (i = 0; i < nitems(reg_adda); i++) + vals->adda[i] = rtwn_bb_read(sc, reg_adda[i]); + + vals->txpause = rtwn_read_1(sc, R92C_TXPAUSE); + vals->bcn_ctrl[0] = rtwn_read_1(sc, R92C_BCN_CTRL(0)); + vals->bcn_ctrl[1] = rtwn_read_1(sc, R92C_BCN_CTRL(1)); + vals->gpio_muxcfg = rtwn_read_4(sc, R92C_GPIO_MUXCFG); + } + + if (sc->ntxchains == 1) { + rtwn_bb_write(sc, reg_adda[0], 0x0b1b25a0); + for (i = 1; i < nitems(reg_adda); i++) + rtwn_bb_write(sc, reg_adda[i], 0x0bdb25a0); + } else { + for (i = 0; i < nitems(reg_adda); i++) + rtwn_bb_write(sc, reg_adda[i], 0x04db25a4); + } + + hssi_param1 = rtwn_bb_read(sc, R92C_HSSI_PARAM1(0)); + if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) { + rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), + hssi_param1 | R92C_HSSI_PARAM1_PI); + rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), + hssi_param1 | R92C_HSSI_PARAM1_PI); + } + + if (n == 0) { + vals->ofdm0_trxpathena = + rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA); + vals->ofdm0_trmuxpar = rtwn_bb_read(sc, R92C_OFDM0_TRMUXPAR); + vals->fpga0_rfifacesw1 = + rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(1)); + } + + rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, 0x03a05600); + rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, 0x000800e4); + rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), 0x22204000); + if (sc->ntxchains > 1) { + rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000); + rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00010000); + } + + rtwn_write_1(sc, R92C_TXPAUSE, + R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT | R92C_TX_QUEUE_HIGH); + rtwn_write_1(sc, R92C_BCN_CTRL(0), + vals->bcn_ctrl[0] & ~R92C_BCN_CTRL_EN_BCN); + rtwn_write_1(sc, R92C_BCN_CTRL(1), + vals->bcn_ctrl[1] & ~R92C_BCN_CTRL_EN_BCN); + rtwn_write_1(sc, R92C_GPIO_MUXCFG, + vals->gpio_muxcfg & ~R92C_GPIO_MUXCFG_ENBT); + + rtwn_bb_write(sc, 0x0b68, 0x00080000); + if (sc->ntxchains > 1) + rtwn_bb_write(sc, 0x0b6c, 0x00080000); + + rtwn_bb_write(sc, 0x0e28, 0x80800000); + rtwn_bb_write(sc, 0x0e40, 0x01007c00); + rtwn_bb_write(sc, 0x0e44, 0x01004800); + + rtwn_bb_write(sc, 0x0b68, 0x00080000); + + for (chain = 0; chain < sc->ntxchains; chain++) { + if (chain > 0) { + /* Put chain 0 on standby. */ + rtwn_bb_write(sc, 0x0e28, 0x00); + rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000); + rtwn_bb_write(sc, 0x0e28, 0x80800000); + + /* Enable chain 1. */ + for (i = 0; i < nitems(reg_adda); i++) + rtwn_bb_write(sc, reg_adda[i], 0x0b1b25a4); + } + + /* Run IQ calibration twice. */ + for (i = 0; i < 2; i++) { + int ret; + + ret = r92ce_iq_calib_chain(sc, chain, + tx[chain], rx[chain]); + if (ret == 0) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: chain %d: Tx failed.\n", + __func__, chain); + tx[chain][0] = 0xff; + tx[chain][1] = 0xff; + rx[chain][0] = 0xff; + rx[chain][1] = 0xff; + } else if (ret == 1) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: chain %d: Rx failed.\n", + __func__, chain); + rx[chain][0] = 0xff; + rx[chain][1] = 0xff; + } else if (ret == 3) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: chain %d: Both Tx and Rx " + "succeeded.\n", __func__, chain); + } + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: results for run %d chain %d: tx[0] 0x%x, " + "tx[1] 0x%x, rx[0] 0x%x, rx[1] 0x%x\n", __func__, n, chain, + tx[chain][0], tx[chain][1], rx[chain][0], rx[chain][1]); + } + + rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, + vals->ofdm0_trxpathena); + rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), + vals->fpga0_rfifacesw1); + rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, vals->ofdm0_trmuxpar); + + rtwn_bb_write(sc, 0x0e28, 0x00); + rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00032ed3); + if (sc->ntxchains > 1) + rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00032ed3); + + if (n != 0) { + if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) { + rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), hssi_param1); + rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), hssi_param1); + } + + for (i = 0; i < nitems(reg_adda); i++) + rtwn_bb_write(sc, reg_adda[i], vals->adda[i]); + + rtwn_write_1(sc, R92C_TXPAUSE, vals->txpause); + rtwn_write_1(sc, R92C_BCN_CTRL(0), vals->bcn_ctrl[0]); + rtwn_write_1(sc, R92C_BCN_CTRL(1), vals->bcn_ctrl[1]); + rtwn_write_4(sc, R92C_GPIO_MUXCFG, vals->gpio_muxcfg); + } +} + +#define RTWN_IQ_CAL_MAX_TOLERANCE 5 +static int +r92ce_iq_calib_compare_results(struct rtwn_softc *sc, uint16_t tx1[2][2], + uint16_t rx1[2][2], uint16_t tx2[2][2], uint16_t rx2[2][2]) +{ + int chain, i, tx_ok[2], rx_ok[2]; + + tx_ok[0] = tx_ok[1] = rx_ok[0] = rx_ok[1] = 0; + for (chain = 0; chain < sc->ntxchains; chain++) { + for (i = 0; i < 2; i++) { + if (tx1[chain][i] == 0xff || tx2[chain][i] == 0xff || + rx1[chain][i] == 0xff || rx2[chain][i] == 0xff) + continue; + + tx_ok[chain] = (abs(tx1[chain][i] - tx2[chain][i]) <= + RTWN_IQ_CAL_MAX_TOLERANCE); + + rx_ok[chain] = (abs(rx1[chain][i] - rx2[chain][i]) <= + RTWN_IQ_CAL_MAX_TOLERANCE); + } + } + + if (sc->ntxchains > 1) + return (tx_ok[0] && tx_ok[1] && rx_ok[0] && rx_ok[1]); + else + return (tx_ok[0] && rx_ok[0]); +} +#undef RTWN_IQ_CAL_MAX_TOLERANCE + +static void +r92ce_iq_calib_write_results(struct rtwn_softc *sc, uint16_t tx[2], + uint16_t rx[2], int chain) +{ + uint32_t reg, val, x; + long y, tx_c; + + if (tx[0] == 0xff || tx[1] == 0xff) + return; + + reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain)); + val = ((reg >> 22) & 0x3ff); + x = tx[0]; + if (x & 0x00000200) + x |= 0xfffffc00; + reg = (((x * val) >> 8) & 0x3ff); + rtwn_bb_setbits(sc, R92C_OFDM0_TXIQIMBALANCE(chain), 0x3ff, reg); + rtwn_bb_setbits(sc, R92C_OFDM0_ECCATHRESHOLD, 0x80000000, + ((x * val) & 0x80) << 24); + + y = tx[1]; + if (y & 0x00000200) + y |= 0xfffffc00; + tx_c = (y * val) >> 8; + rtwn_bb_setbits(sc, R92C_OFDM0_TXAFE(chain), 0xf0000000, + (tx_c & 0x3c0) << 22); + rtwn_bb_setbits(sc, R92C_OFDM0_TXIQIMBALANCE(chain), 0x003f0000, + (tx_c & 0x3f) << 16); + rtwn_bb_setbits(sc, R92C_OFDM0_ECCATHRESHOLD, 0x20000000, + ((y * val) & 0x80) << 22); + + if (rx[0] == 0xff || rx[1] == 0xff) + return; + + rtwn_bb_setbits(sc, R92C_OFDM0_RXIQIMBALANCE(chain), 0x3ff, + rx[0] & 0x3ff); + rtwn_bb_setbits(sc, R92C_OFDM0_RXIQIMBALANCE(chain), 0xfc00, + (rx[1] & 0x3f) << 10); + + if (chain == 0) { + rtwn_bb_setbits(sc, R92C_OFDM0_RXIQEXTANTA, 0xf0000000, + (rx[1] & 0x3c0) << 22); + } else { + rtwn_bb_setbits(sc, R92C_OFDM0_AGCRSSITABLE, 0xf000, + (rx[1] & 0x3c0) << 6); + } +} + +#define RTWN_IQ_CAL_NRUN 3 +void +r92ce_iq_calib(struct rtwn_softc *sc) +{ + struct r92ce_iq_cal_reg_vals vals; + uint16_t tx[RTWN_IQ_CAL_NRUN][2][2], rx[RTWN_IQ_CAL_NRUN][2][2]; + int n, valid; + + valid = 0; + for (n = 0; n < RTWN_IQ_CAL_NRUN; n++) { + r92ce_iq_calib_run(sc, n, tx[n], rx[n], &vals); + + if (n == 0) + continue; + + /* Valid results remain stable after consecutive runs. */ + valid = r92ce_iq_calib_compare_results(sc, tx[n - 1], + rx[n - 1], tx[n], rx[n]); + if (valid) + break; + } + + if (valid) { + r92ce_iq_calib_write_results(sc, tx[n][0], rx[n][0], 0); + if (sc->ntxchains > 1) + r92ce_iq_calib_write_results(sc, tx[n][1], rx[n][1], 1); + } +} +#undef RTWN_IQ_CAL_NRUN diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce_fw.c b/sys/dev/rtwn/rtl8192c/pci/r92ce_fw.c new file mode 100644 index 000000000000..b7f8d4ac2f34 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/pci/r92ce_fw.c @@ -0,0 +1,74 @@ +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include + + +#ifndef RTWN_WITHOUT_UCODE +void +r92ce_fw_reset(struct rtwn_softc *sc, int reason) +{ + + if (reason == RTWN_FW_RESET_CHECKSUM) + return; + + r92c_fw_reset(sc, reason); + + /* + * We must sleep for one second to let the firmware settle. + * Accessing registers too early will hang the whole system. + */ + rtwn_delay(sc, 1000 * 1000); +} +#endif diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce_init.c b/sys/dev/rtwn/rtl8192c/pci/r92ce_init.c new file mode 100644 index 000000000000..92845aab162f --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/pci/r92ce_init.c @@ -0,0 +1,327 @@ +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include +#include + + +void +r92ce_init_intr(struct rtwn_softc *sc) +{ + /* Disable interrupts. */ + rtwn_write_4(sc, R92C_HISR, 0x00000000); + rtwn_write_4(sc, R92C_HIMR, 0x00000000); +} + +void +r92ce_init_edca(struct rtwn_softc *sc) +{ + /* SIFS */ + rtwn_write_2(sc, R92C_SPEC_SIFS, 0x1010); + rtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x1010); + rtwn_write_2(sc, R92C_SIFS_CCK, 0x1010); + rtwn_write_2(sc, R92C_SIFS_OFDM, 0x0e0e); + /* TXOP */ + rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b); + rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f); + rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4322); + rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3222); +} + +void +r92ce_init_bb(struct rtwn_softc *sc) +{ + + /* Enable BB and RF. */ + rtwn_setbits_2(sc, R92C_SYS_FUNC_EN, 0, + R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | + R92C_SYS_FUNC_EN_DIO_RF); + + rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83); + + rtwn_write_1(sc, R92C_RF_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); + + rtwn_write_1(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_DIO_PCIE | R92C_SYS_FUNC_EN_PCIEA | + R92C_SYS_FUNC_EN_PPLL | R92C_SYS_FUNC_EN_BB_GLB_RST | + R92C_SYS_FUNC_EN_BBRSTB); + + rtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80); + + rtwn_setbits_4(sc, R92C_LEDCFG0, 0, 0x00800000); + + r92c_init_bb_common(sc); + + if (rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) & + R92C_HSSI_PARAM2_CCK_HIPWR) + sc->sc_flags |= RTWN_FLAG_CCK_HIPWR; +} + +int +r92ce_power_on(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + uint32_t reg; + int ntries; + + /* Wait for autoload done bit. */ + for (ntries = 0; ntries < 1000; ntries++) { + if (rtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN) + break; + DELAY(5); + } + if (ntries == 1000) { + device_printf(sc->sc_dev, + "timeout waiting for chip autoload\n"); + return (ETIMEDOUT); + } + + /* Unlock ISO/CLK/Power control register. */ + rtwn_write_1(sc, R92C_RSV_CTRL, 0); + + if (rs->board_type != R92C_BOARD_TYPE_DONGLE) { + /* bt coex */ + rtwn_setbits_4(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_SOP_ABG | + R92C_APS_FSMCO_SOP_AMB | + R92C_APS_FSMCO_XOP_BTCK); + } + + /* Move SPS into PWM mode. */ + rtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b); + + /* Set low byte to 0x0f, leave others unchanged. */ + rtwn_write_1(sc, R92C_AFE_XTAL_CTRL, 0x0f); + + /* TODO: check if we need this for 8188CE */ + if (rs->board_type != R92C_BOARD_TYPE_DONGLE) { + /* bt coex */ + /* XXX magic from linux */ + rtwn_setbits_4(sc, R92C_AFE_XTAL_CTRL, 0x024800, 0); + } + + rtwn_setbits_2(sc, R92C_SYS_ISO_CTRL, 0xff00, + R92C_SYS_ISO_CTRL_PWC_EV12V | R92C_SYS_ISO_CTRL_DIOR); + + DELAY(200); + + /* TODO: linux does additional btcoex stuff here */ + + /* Auto enable WLAN. */ + rtwn_setbits_2(sc, R92C_APS_FSMCO, 0, R92C_APS_FSMCO_APFM_ONMAC); + for (ntries = 0; ntries < 1000; ntries++) { + if (!(rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_ONMAC)) + break; + DELAY(5); + } + if (ntries == 1000) { + device_printf(sc->sc_dev, "timeout waiting for MAC auto ON\n"); + return (ETIMEDOUT); + } + + /* Enable radio, GPIO and LED functions. */ + rtwn_write_2(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_PCIE | + R92C_APS_FSMCO_PDN_EN | + R92C_APS_FSMCO_PFM_ALDN); + /* Release RF digital isolation. */ + rtwn_setbits_2(sc, R92C_SYS_ISO_CTRL, R92C_SYS_ISO_CTRL_DIOR, 0); + + if (rs->chip & R92C_CHIP_92C) + rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x77); + else + rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x22); + + rtwn_write_4(sc, R92C_INT_MIG, 0); + + if (rs->board_type != R92C_BOARD_TYPE_DONGLE) { + /* bt coex */ + /* XXX magic from linux */ + rtwn_setbits_1(sc, R92C_AFE_XTAL_CTRL + 2, 0x02, 0); + } + + rtwn_setbits_1(sc, R92C_GPIO_MUXCFG, R92C_GPIO_MUXCFG_RFKILL, 0); + + reg = rtwn_read_1(sc, R92C_GPIO_IO_SEL); + if (!(reg & R92C_GPIO_IO_SEL_RFKILL)) { + device_printf(sc->sc_dev, + "radio is disabled by hardware switch\n"); + /* XXX how driver will know when radio will be enabled? */ + return (EPERM); + } + + /* Initialize MAC. */ + rtwn_setbits_1(sc, R92C_APSD_CTRL, R92C_APSD_CTRL_OFF, 0); + for (ntries = 0; ntries < 200; ntries++) { + if (!(rtwn_read_1(sc, R92C_APSD_CTRL) & + R92C_APSD_CTRL_OFF_STATUS)) + break; + DELAY(500); + } + if (ntries == 200) { + device_printf(sc->sc_dev, + "timeout waiting for MAC initialization\n"); + return (ETIMEDOUT); + } + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + rtwn_setbits_2(sc, R92C_CR, 0, + R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | + R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | + R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN | + ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0)); + + rtwn_write_4(sc, R92C_MCUTST_1, 0x0); + + return (0); +} + +void +r92ce_power_off(struct rtwn_softc *sc) +{ +#ifndef RTWN_WITHOUT_UCODE + struct r92c_softc *rs = sc->sc_priv; + + /* Deinit C2H event handler. */ + callout_stop(&rs->rs_c2h_report); + rs->rs_c2h_paused = 0; + rs->rs_c2h_pending = 0; + rs->rs_c2h_timeout = hz; +#endif + + /* Stop hardware. */ + /* Disable interrupts. */ + rtwn_write_4(sc, R92C_HISR, 0); + rtwn_write_4(sc, R92C_HIMR, 0); + + /* Stop hardware. */ + rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + + /* Turn off RF. */ + rtwn_write_1(sc, R92C_RF_CTRL, 0); + + /* Reset BB state machine */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, 0, R92C_SYS_FUNC_EN_BB_GLB_RST); + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BB_GLB_RST, 0); + + /* Disable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + rtwn_setbits_2(sc, R92C_CR, + R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | + R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | + R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN | + R92C_CR_ENSEC, + 0); + + /* If firmware in ram code, do reset. */ +#ifndef RTWN_WITHOUT_UCODE + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) + r92ce_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN); +#endif + + /* TODO: linux does additional btcoex stuff here */ + rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0x80); /* linux magic number */ + rtwn_write_1(sc, R92C_SPS0_CTRL, 0x23); /* ditto */ + rtwn_write_1(sc, R92C_AFE_XTAL_CTRL, 0x0e); /* different with btcoex */ + rtwn_write_1(sc, R92C_RSV_CTRL, 0x0e); + rtwn_write_1(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_PDN_EN); +} + +void +r92ce_init_ampdu(struct rtwn_softc *sc) +{ + + /* Setup AMPDU aggregation. */ + rtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */ + rtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16); +} + +void +r92ce_post_init(struct rtwn_softc *sc) +{ + rtwn_write_2(sc, R92C_FWHW_TXQ_CTRL, + 0x1f00 | R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW); + + rtwn_write_1(sc, R92C_BCN_MAX_ERR, 0xff); + + /* Perform LO and IQ calibrations. */ + r92ce_iq_calib(sc); + /* Perform LC calibration. */ + r92c_lc_calib(sc); + + r92c_pa_bias_init(sc); + + /* Fix for lower temperature. */ + rtwn_write_1(sc, 0x15, 0xe9); + +#ifndef RTWN_WITHOUT_UCODE + if (sc->sc_flags & RTWN_FW_LOADED) { + struct r92c_softc *rs = sc->sc_priv; + + if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) { + /* XXX TODO: fix (see comment in r92cu_init.c) */ + sc->sc_ratectl = RTWN_RATECTL_NET80211; + } else + sc->sc_ratectl = sc->sc_ratectl_sysctl; + + /* Start C2H event handling. */ + callout_reset(&rs->rs_c2h_report, rs->rs_c2h_timeout, + r92c_handle_c2h_report, sc); + } else +#endif + sc->sc_ratectl = RTWN_RATECTL_NONE; +} diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce_led.c b/sys/dev/rtwn/rtl8192c/pci/r92ce_led.c new file mode 100644 index 000000000000..5959473842ca --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/pci/r92ce_led.c @@ -0,0 +1,67 @@ +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include + +void +r92ce_set_led(struct rtwn_softc *sc, int led, int on) +{ + + if (led == RTWN_LED_LINK) { + rtwn_setbits_1(sc, R92C_LEDCFG2, 0x0f, + on ? R92C_LEDCFG2_EN : R92C_LEDCFG2_DIS); + sc->ledlink = on; /* Save LED state. */ + } +} diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce_priv.h b/sys/dev/rtwn/rtl8192c/pci/r92ce_priv.h new file mode 100644 index 000000000000..7416516cd986 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/pci/r92ce_priv.h @@ -0,0 +1,182 @@ +/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef R92CE_PRIV_H +#define R92CE_PRIV_H + +#include + + +/* + * MAC initialization values. + */ +static const struct rtwn_mac_prog rtl8192ce_mac[] = { + { 0x420, 0x80 }, { 0x423, 0x00 }, { 0x430, 0x00 }, { 0x431, 0x00 }, + { 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 }, { 0x435, 0x05 }, + { 0x436, 0x06 }, { 0x437, 0x07 }, { 0x438, 0x00 }, { 0x439, 0x00 }, + { 0x43a, 0x00 }, { 0x43b, 0x01 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, + { 0x43e, 0x06 }, { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 }, + { 0x442, 0x00 }, { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f }, + { 0x447, 0x00 }, { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 }, + { 0x45b, 0xb9 }, { 0x460, 0x88 }, { 0x461, 0x88 }, { 0x462, 0x06 }, + { 0x463, 0x03 }, { 0x4c8, 0x04 }, { 0x4c9, 0x08 }, { 0x4cc, 0x02 }, + { 0x4cd, 0x28 }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, + { 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, + { 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, + { 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, + { 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, + { 0x515, 0x10 }, { 0x516, 0x0a }, { 0x517, 0x10 }, { 0x51a, 0x16 }, + { 0x524, 0x0f }, { 0x525, 0x4f }, { 0x546, 0x20 }, { 0x547, 0x00 }, + { 0x559, 0x02 }, { 0x55a, 0x02 }, { 0x55d, 0xff }, { 0x605, 0x30 }, + { 0x608, 0x0e }, { 0x609, 0x2a }, { 0x652, 0x20 }, { 0x63c, 0x0a }, + { 0x63d, 0x0e }, { 0x700, 0x21 }, { 0x701, 0x43 }, { 0x702, 0x65 }, + { 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 }, { 0x70a, 0x65 }, + { 0x70b, 0x87 } +}; + + +/* + * Baseband initialization values. + */ +static const uint16_t rtl8192ce_bb_regs0[] = { + 0x024, 0x028, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, + 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, + 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, + 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, 0x884, + 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, 0x908, + 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, + 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04 +}, rtl8192ce_bb_regs1[] = { + 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, + 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, + 0xc50, 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, + 0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, + 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, + 0xcbc, 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc, + 0xce0, 0xce4, 0xce8, 0xcec, 0xd00 +}; + +static const uint32_t rtl8192ce_bb_vals0_2t[] = { + 0x0011800f, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00, + 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, + 0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727, + 0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000, + 0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a, + 0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27, + 0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070, + 0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe, + 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, + 0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, + 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x48071d40, 0x03a05633 +}, rtl8192ce_bb_vals0_1t[] = { + 0x0011800f, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00, + 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, + 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a, + 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200, + 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070, + 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe, + 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, + 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, + 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x48071d40, 0x03a05611 +}, rtl8192ce_bb_vals1[] = { + 0x000000e4, 0x6c6c6c6c, 0x08800000, 0x40000100, 0x08800000, + 0x40000100, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x69e9ac44, 0x469652cf, 0x49795994, 0x0a97971c, 0x1f7c403f, + 0x000100b7, 0xec020107, 0x007f037f, 0x69543420, 0x43bc0094, + 0x69543420, 0x433c0094, 0x00000000, 0x5116848b, 0x47c00bff, + 0x00000036, 0x2c7f000d, 0x018610db, 0x0000001f, 0x00b91612, + 0x40000100, 0x20f60000, 0x40000100, 0x20200000, 0x00121820, + 0x00000000, 0x00121820, 0x00007f7f, 0x00000000, 0x00000080, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x28000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x64b22427, 0x00766932, 0x00222222, + 0x00000000, 0x37644302, 0x2f97d40c, 0x00080740 +}, rtl8192ce_bb_vals4_1t[] = { + 0x00000010, 0x001b25a4, 0x631b25a0, 0x631b25a0, 0x081b25a0, + 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x631b25a0, 0x081b25a0, + 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x001b25a0, + 0x001b25a0, 0x6b1b25a0, 0x00000003, 0x00000000, 0x00000300 +}; + +static const struct rtwn_bb_prog rtl8192ce_bb[] = { + { + nitems(rtl8192ce_bb_regs0), + rtl8192ce_bb_regs0, + rtl8192ce_bb_vals0_2t, + { R92C_COND_RTL8192C }, + &(const struct rtwn_bb_prog){ + nitems(rtl8192ce_bb_regs0), + rtl8192ce_bb_regs0, + rtl8192ce_bb_vals0_1t, + { 0 }, + NULL + } + }, + { + nitems(rtl8192ce_bb_regs1), + rtl8192ce_bb_regs1, + rtl8192ce_bb_vals1, + { 0 }, + NULL + }, + { + nitems(rtl8192c_bb_regs3), + rtl8192c_bb_regs3, + rtl8192c_bb_vals3_92ce_92cu, + { R92C_COND_RTL8192C }, + &(const struct rtwn_bb_prog){ + nitems(rtl8192c_bb_regs3), + rtl8192c_bb_regs3, + rtl8192c_bb_vals3_88cu_88ru, + { 0 }, + NULL + } + }, + { + nitems(rtl8192c_bb_regs4), + rtl8192c_bb_regs4, + rtl8192c_bb_vals4, + { 0 }, + NULL + }, + { + nitems(rtl8192c_bb_regs5), + rtl8192c_bb_regs5, + rtl8192c_bb_vals5_92ce_92cu, + { R92C_COND_RTL8192C }, + &(const struct rtwn_bb_prog){ + nitems(rtl8192c_bb_regs5), + rtl8192c_bb_regs5, + rtl8192ce_bb_vals4_1t, + { 0 }, + NULL + } + } +}; + +#endif /* R92CE_PRIV_H */ diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce_reg.h b/sys/dev/rtwn/rtl8192c/pci/r92ce_reg.h new file mode 100644 index 000000000000..355d8f4622cd --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/pci/r92ce_reg.h @@ -0,0 +1,103 @@ +/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef R92CE_REG_H +#define R92CE_REG_H + +#include + +/* + * MAC registers. + */ +/* System Configuration. */ +#define R92C_PCIE_MIO_INTF 0x0e4 +#define R92C_PCIE_MIO_INTD 0x0e8 +/* PCIe Configuration. */ +#define R92C_PCIE_CTRL_REG 0x300 +#define R92C_INT_MIG 0x304 +#define R92C_BCNQ_DESA 0x308 +#define R92C_HQ_DESA 0x310 +#define R92C_MGQ_DESA 0x318 +#define R92C_VOQ_DESA 0x320 +#define R92C_VIQ_DESA 0x328 +#define R92C_BEQ_DESA 0x330 +#define R92C_BKQ_DESA 0x338 +#define R92C_RX_DESA 0x340 +#define R92C_DBI 0x348 +#define R92C_MDIO 0x354 +#define R92C_DBG_SEL 0x360 +#define R92C_PCIE_HRPWM 0x361 +#define R92C_PCIE_HCPWM 0x363 +#define R92C_UART_CTRL 0x364 +#define R92C_UART_TX_DES 0x370 +#define R92C_UART_RX_DES 0x378 + + +/* Bits for R92C_GPIO_MUXCFG. */ +#define R92C_GPIO_MUXCFG_RFKILL 0x0008 + +/* Bits for R92C_GPIO_IO_SEL. */ +#define R92C_GPIO_IO_SEL_RFKILL 0x0008 + +/* Bits for R92C_LEDCFG2. */ +#define R92C_LEDCFG2_EN 0x60 +#define R92C_LEDCFG2_DIS 0x68 + +/* Bits for R92C_HIMR. */ +#define R92C_IMR_ROK 0x00000001 /* receive DMA OK */ +#define R92C_IMR_VODOK 0x00000002 /* AC_VO DMA OK */ +#define R92C_IMR_VIDOK 0x00000004 /* AC_VI DMA OK */ +#define R92C_IMR_BEDOK 0x00000008 /* AC_BE DMA OK */ +#define R92C_IMR_BKDOK 0x00000010 /* AC_BK DMA OK */ +#define R92C_IMR_TXBDER 0x00000020 /* beacon transmit error */ +#define R92C_IMR_MGNTDOK 0x00000040 /* management queue DMA OK */ +#define R92C_IMR_TBDOK 0x00000080 /* beacon transmit OK */ +#define R92C_IMR_HIGHDOK 0x00000100 /* high queue DMA OK */ +#define R92C_IMR_BDOK 0x00000200 /* beacon queue DMA OK */ +#define R92C_IMR_ATIMEND 0x00000400 /* ATIM window end interrupt */ +#define R92C_IMR_RDU 0x00000800 /* Rx descriptor unavailable */ +#define R92C_IMR_RXFOVW 0x00001000 /* receive FIFO overflow */ +#define R92C_IMR_BCNINT 0x00002000 /* beacon DMA interrupt 0 */ +#define R92C_IMR_PSTIMEOUT 0x00004000 /* powersave timeout */ +#define R92C_IMR_TXFOVW 0x00008000 /* transmit FIFO overflow */ +#define R92C_IMR_TIMEOUT1 0x00010000 /* timeout interrupt 1 */ +#define R92C_IMR_TIMEOUT2 0x00020000 /* timeout interrupt 2 */ +#define R92C_IMR_BCNDOK1 0x00040000 /* beacon queue DMA OK (1) */ +#define R92C_IMR_BCNDOK2 0x00080000 /* beacon queue DMA OK (2) */ +#define R92C_IMR_BCNDOK3 0x00100000 /* beacon queue DMA OK (3) */ +#define R92C_IMR_BCNDOK4 0x00200000 /* beacon queue DMA OK (4) */ +#define R92C_IMR_BCNDOK5 0x00400000 /* beacon queue DMA OK (5) */ +#define R92C_IMR_BCNDOK6 0x00800000 /* beacon queue DMA OK (6) */ +#define R92C_IMR_BCNDOK7 0x01000000 /* beacon queue DMA OK (7) */ +#define R92C_IMR_BCNDOK8 0x02000000 /* beacon queue DMA OK (8) */ +#define R92C_IMR_BCNDMAINT1 0x04000000 /* beacon DMA interrupt 1 */ +#define R92C_IMR_BCNDMAINT2 0x08000000 /* beacon DMA interrupt 2 */ +#define R92C_IMR_BCNDMAINT3 0x10000000 /* beacon DMA interrupt 3 */ +#define R92C_IMR_BCNDMAINT4 0x20000000 /* beacon DMA interrupt 4 */ +#define R92C_IMR_BCNDMAINT5 0x40000000 /* beacon DMA interrupt 5 */ +#define R92C_IMR_BCNDMAINT6 0x80000000 /* beacon DMA interrupt 6 */ + +/* Shortcut. */ +#define R92C_IBSS_INT_MASK \ + (R92C_IMR_BCNINT | R92C_IMR_TBDOK | R92C_IMR_TBDER) + +#endif /* R92CE_REG_H */ diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce_rx.c b/sys/dev/rtwn/rtl8192c/pci/r92ce_rx.c new file mode 100644 index 000000000000..cdd62200c35a --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/pci/r92ce_rx.c @@ -0,0 +1,132 @@ +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + + +int +r92ce_classify_intr(struct rtwn_softc *sc, void *arg, int len __unused) +{ + uint32_t status; + int *rings = arg; + int ret; + + *rings = 0; + status = rtwn_read_4(sc, R92C_HISR); + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: HISR %08X, HISRE %04X\n", + __func__, status, rtwn_read_2(sc, R92C_HISRE)); + if (status == 0 || status == 0xffffffff) + return (0); + + /* Disable interrupts. */ + rtwn_write_4(sc, R92C_HIMR, 0); + + /* Ack interrupts. */ + rtwn_write_4(sc, R92C_HISR, status); + + if (status & R92C_IMR_BDOK) + *rings |= (1 << RTWN_PCI_BEACON_QUEUE); + if (status & R92C_IMR_HIGHDOK) + *rings |= (1 << RTWN_PCI_HIGH_QUEUE); + if (status & R92C_IMR_MGNTDOK) + *rings |= (1 << RTWN_PCI_MGNT_QUEUE); + if (status & R92C_IMR_BKDOK) + *rings |= (1 << RTWN_PCI_BK_QUEUE); + if (status & R92C_IMR_BEDOK) + *rings |= (1 << RTWN_PCI_BE_QUEUE); + if (status & R92C_IMR_VIDOK) + *rings |= (1 << RTWN_PCI_VI_QUEUE); + if (status & R92C_IMR_VODOK) + *rings |= (1 << RTWN_PCI_VO_QUEUE); + + ret = 0; + if (status & R92C_IMR_RXFOVW) + ret |= RTWN_PCI_INTR_RX_OVERFLOW; + if (status & R92C_IMR_RDU) + ret |= RTWN_PCI_INTR_RX_DESC_UNAVAIL; + if (status & R92C_IMR_ROK) + ret |= RTWN_PCI_INTR_RX_DONE; + if (status & R92C_IMR_TXFOVW) + ret |= RTWN_PCI_INTR_TX_OVERFLOW; + if (status & R92C_IMR_PSTIMEOUT) + ret |= RTWN_PCI_INTR_PS_TIMEOUT; + + return (ret); +} + +#define R92C_INT_ENABLE (R92C_IMR_ROK | R92C_IMR_VODOK | R92C_IMR_VIDOK | \ + R92C_IMR_BEDOK | R92C_IMR_BKDOK | R92C_IMR_MGNTDOK | \ + R92C_IMR_HIGHDOK | R92C_IMR_BDOK | R92C_IMR_RDU | \ + R92C_IMR_RXFOVW) +void +r92ce_enable_intr(struct rtwn_pci_softc *pc) +{ + struct rtwn_softc *sc = &pc->pc_sc; + + /* Enable interrupts. */ + rtwn_write_4(sc, R92C_HIMR, R92C_INT_ENABLE); +} + +void +r92ce_start_xfers(struct rtwn_softc *sc) +{ + /* Clear pending interrupts. */ + rtwn_write_4(sc, R92C_HISR, 0xffffffff); + + /* Enable interrupts. */ + rtwn_write_4(sc, R92C_HIMR, R92C_INT_ENABLE); +} +#undef R92C_INT_ENABLE diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h b/sys/dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h new file mode 100644 index 000000000000..476a9e882b6d --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/pci/r92ce_rx_desc.h @@ -0,0 +1,41 @@ +/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef R92CE_RX_DESC_H +#define R92CE_RX_DESC_H + +#include + +/* Rx MAC descriptor (PCIe). */ +struct r92ce_rx_stat { + uint32_t rxdw0; + uint32_t rxdw1; + uint32_t rxdw2; + uint32_t rxdw3; + uint32_t rxdw4; + uint32_t tsf_low; + + uint32_t rxbufaddr; + uint32_t rxbufaddr64; +} __packed __attribute__((aligned(4))); + +#endif /* R92CE_RX_DESC_H */ diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce_tx.c b/sys/dev/rtwn/rtl8192c/pci/r92ce_tx.c new file mode 100644 index 000000000000..19de15b5a63e --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/pci/r92ce_tx.c @@ -0,0 +1,115 @@ +/* $OpenBSD: if_rtwn.c,v 1.6 2015/08/28 00:03:53 deraadt Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + + +void +r92ce_setup_tx_desc(struct rtwn_pci_softc *pc, void *desc, + uint32_t next_desc_addr) +{ + struct r92ce_tx_desc *txd = desc; + + /* setup tx desc */ + txd->nextdescaddr = htole32(next_desc_addr); +} + +void +r92ce_tx_postsetup(struct rtwn_pci_softc *pc, void *desc, + bus_dma_segment_t segs[]) +{ + struct r92ce_tx_desc *txd = desc; + + txd->txbufaddr = htole32(segs[0].ds_addr); + txd->txbufsize = txd->pktlen; + bus_space_barrier(pc->pc_st, pc->pc_sh, 0, pc->pc_mapsize, + BUS_SPACE_BARRIER_WRITE); +} + +void +r92ce_copy_tx_desc(void *dest, const void *src) +{ + struct r92ce_tx_desc *txd = dest; + size_t len = sizeof(struct r92c_tx_desc) + + sizeof(txd->txbufsize) + sizeof(txd->pad); + + if (src != NULL) + memcpy(dest, src, len); + else + memset(dest, 0, len); +} + +void +r92ce_dump_tx_desc(struct rtwn_softc *sc, const void *desc) +{ +#ifdef RTWN_DEBUG + const struct r92ce_tx_desc *txd = desc; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT_DESC, + "%s: len %d, off %d, flags0 %02X, dw: 1 %08X, 2 %08X, 3 %04X " + "(seq %04X), 4 %08X, 5 %08X, 6 %08X, size %04X, pad %04X, " + "addr: %08X (64: %08X), next: %08X (64: %08X), " + "rsvd: %08X %08X %08X %08X\n", + __func__, le16toh(txd->pktlen), txd->offset, txd->flags0, + le32toh(txd->txdw1), le32toh(txd->txdw2), le16toh(txd->txdw3), + le16toh(txd->txdseq), le32toh(txd->txdw4), le32toh(txd->txdw5), + le32toh(txd->txdw6), le16toh(txd->txbufsize), le16toh(txd->pad), + le32toh(txd->txbufaddr), le32toh(txd->txbufaddr64), + le32toh(txd->nextdescaddr), le32toh(txd->nextdescaddr64), + le32toh(txd->reserved[0]), le32toh(txd->reserved[1]), + le32toh(txd->reserved[2]), le32toh(txd->reserved[3])); +#endif +} diff --git a/sys/dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h b/sys/dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h new file mode 100644 index 000000000000..4153710a8428 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/pci/r92ce_tx_desc.h @@ -0,0 +1,55 @@ +/* $OpenBSD: if_rtwnreg.h,v 1.3 2015/06/14 08:02:47 stsp Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef R92CE_TX_DESC_H +#define R92CE_TX_DESC_H + +#include + +/* Tx MAC descriptor (PCIe). */ +struct r92ce_tx_desc { + uint16_t pktlen; + uint8_t offset; + uint8_t flags0; + + uint32_t txdw1; + uint32_t txdw2; + uint16_t txdw3; + uint16_t txdseq; + + uint32_t txdw4; + uint32_t txdw5; + uint32_t txdw6; + + uint16_t txbufsize; + uint16_t pad; + + uint32_t txbufaddr; + uint32_t txbufaddr64; + + uint32_t nextdescaddr; + uint32_t nextdescaddr64; + + uint32_t reserved[4]; +} __packed __attribute__((aligned(4))); + +#endif /* R92CE_TX_DESC_H */ diff --git a/sys/dev/rtwn/rtl8192c/r92c.h b/sys/dev/rtwn/rtl8192c/r92c.h new file mode 100644 index 000000000000..cd0c88db2ea4 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c.h @@ -0,0 +1,115 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef RTL8192C_H +#define RTL8192C_H + +/* + * Global definitions. + */ +#define R92C_TXPKTBUF_COUNT 256 + +#define R92C_TX_PAGE_SIZE 128 +#define R92C_RX_DMA_BUFFER_SIZE 0x2800 + +#define R92C_MAX_FW_SIZE 0x4000 +#define R92C_MACID_MAX 31 +#define R92C_CAM_ENTRY_COUNT 32 + +#define R92C_CALIB_THRESHOLD 2 + + +/* + * Function declarations. + */ +/* r92c_attach.c */ +void r92c_detach_private(struct rtwn_softc *); +void r92c_read_chipid_vendor(struct rtwn_softc *, uint32_t); + +/* r92c_beacon.c */ +void r92c_beacon_init(struct rtwn_softc *, void *, int); +void r92c_beacon_enable(struct rtwn_softc *, int, int); + +/* r92c_calib.c */ +void r92c_iq_calib(struct rtwn_softc *); +void r92c_lc_calib(struct rtwn_softc *); +void r92c_temp_measure(struct rtwn_softc *); +uint8_t r92c_temp_read(struct rtwn_softc *); + +/* r92c_chan.c */ +void r92c_get_txpower(struct rtwn_softc *, int, + struct ieee80211_channel *, uint16_t[]); +void r92c_set_bw20(struct rtwn_softc *, uint8_t); +void r92c_set_chan(struct rtwn_softc *, struct ieee80211_channel *); +void r92c_set_gain(struct rtwn_softc *, uint8_t); +void r92c_scan_start(struct ieee80211com *); +void r92c_scan_end(struct ieee80211com *); + +/* r92c_fw.c */ +#ifndef RTWN_WITHOUT_UCODE +void r92c_fw_reset(struct rtwn_softc *, int); +void r92c_fw_download_enable(struct rtwn_softc *, int); +#endif +void r92c_joinbss_rpt(struct rtwn_softc *, int); +#ifndef RTWN_WITHOUT_UCODE +int r92c_set_rsvd_page(struct rtwn_softc *, int, int, int); +int r92c_set_pwrmode(struct rtwn_softc *, struct ieee80211vap *, int); +void r92c_set_rssi(struct rtwn_softc *); +void r92c_handle_c2h_report(void *); +#endif + +/* r92c_init.c */ +int r92c_check_condition(struct rtwn_softc *, const uint8_t[]); +int r92c_set_page_size(struct rtwn_softc *); +void r92c_init_bb_common(struct rtwn_softc *); +int r92c_init_rf_chain(struct rtwn_softc *, + const struct rtwn_rf_prog *, int); +void r92c_init_rf_common(struct rtwn_softc *); +void r92c_init_rf(struct rtwn_softc *); +void r92c_init_edca(struct rtwn_softc *); +void r92c_init_ampdu(struct rtwn_softc *); +void r92c_init_antsel(struct rtwn_softc *); +void r92c_pa_bias_init(struct rtwn_softc *); + +/* r92c_rf.c */ +uint32_t r92c_rf_read(struct rtwn_softc *, int, uint8_t); +void r92c_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t); + +/* r92c_rom.c */ +void r92c_efuse_postread(struct rtwn_softc *); +void r92c_parse_rom(struct rtwn_softc *, uint8_t *); + +/* r92c_rx.c */ +int8_t r92c_get_rssi_cck(struct rtwn_softc *, void *); +int8_t r92c_get_rssi_ofdm(struct rtwn_softc *, void *); +uint8_t r92c_rx_radiotap_flags(const void *); + +/* r92c_tx.c */ +void r92c_tx_enable_ampdu(void *, int); +void r92c_tx_setup_hwseq(void *); +void r92c_tx_setup_macid(void *, int); +void r92c_fill_tx_desc(struct rtwn_softc *, struct ieee80211_node *, + struct mbuf *, void *, uint8_t, int); +void r92c_fill_tx_desc_raw(struct rtwn_softc *, struct ieee80211_node *, + struct mbuf *, void *, const struct ieee80211_bpf_params *); +void r92c_fill_tx_desc_null(struct rtwn_softc *, void *, int, int, int); +uint8_t r92c_tx_radiotap_flags(const void *); + +#endif /* RTL8192C_H */ diff --git a/sys/dev/rtwn/rtl8192c/r92c_attach.c b/sys/dev/rtwn/rtl8192c/r92c_attach.c new file mode 100644 index 000000000000..a0df8ec7688d --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_attach.c @@ -0,0 +1,80 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + + +void +r92c_detach_private(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + + free(rs, M_RTWN_PRIV); +} + +void +r92c_read_chipid_vendor(struct rtwn_softc *sc, uint32_t reg_sys_cfg) +{ + struct r92c_softc *rs = sc->sc_priv; + + if (reg_sys_cfg & R92C_SYS_CFG_TYPE_92C) { + rs->chip |= R92C_CHIP_92C; + /* Check if it is a castrated 8192C. */ + if (MS(rtwn_read_4(sc, R92C_HPON_FSM), + R92C_HPON_FSM_CHIP_BONDING_ID) == + R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R) + rs->chip |= R92C_CHIP_92C_1T2R; + } + if (reg_sys_cfg & R92C_SYS_CFG_VENDOR_UMC) { + if (MS(reg_sys_cfg, R92C_SYS_CFG_CHIP_VER_RTL) == 0) + rs->chip |= R92C_CHIP_UMC_A_CUT; + } +} diff --git a/sys/dev/rtwn/rtl8192c/r92c_beacon.c b/sys/dev/rtwn/rtl8192c/r92c_beacon.c new file mode 100644 index 000000000000..54b882b6707c --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_beacon.c @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + + +void +r92c_beacon_init(struct rtwn_softc *sc, void *buf, int id) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + /* + * NB: there is no need to setup HWSEQ_EN bit; + * QSEL_BEACON already implies it. + */ + txd->flags0 |= R92C_FLAGS0_BMCAST | R92C_FLAGS0_FSG | R92C_FLAGS0_LSG; + txd->txdw1 |= htole32( + SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BEACON) | + SM(R92C_TXDW1_RAID, R92C_RAID_11B)); + + rtwn_r92c_tx_setup_macid(sc, buf, id); + txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); + txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, id)); + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, RTWN_RIDX_CCK1)); +} + +void +r92c_beacon_enable(struct rtwn_softc *sc, int id, int enable) +{ + + if (enable) { + rtwn_setbits_1(sc, R92C_BCN_CTRL(id), + 0, R92C_BCN_CTRL_EN_BCN); + } else { + rtwn_setbits_1(sc, R92C_BCN_CTRL(id), + R92C_BCN_CTRL_EN_BCN, 0); + } +} diff --git a/sys/dev/rtwn/rtl8192c/r92c_calib.c b/sys/dev/rtwn/rtl8192c/r92c_calib.c new file mode 100644 index 000000000000..ded410eb9f09 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_calib.c @@ -0,0 +1,113 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r92c_iq_calib(struct rtwn_softc *sc) +{ + /* XXX TODO */ +} + +void +r92c_lc_calib(struct rtwn_softc *sc) +{ + uint32_t rf_ac[2]; + uint8_t txmode; + int i; + + txmode = rtwn_read_1(sc, R92C_OFDM1_LSTF + 3); + if ((txmode & 0x70) != 0) { + /* Disable all continuous Tx. */ + rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70); + + /* Set RF mode to standby mode. */ + for (i = 0; i < sc->nrxchains; i++) { + rf_ac[i] = rtwn_rf_read(sc, i, R92C_RF_AC); + rtwn_rf_write(sc, i, R92C_RF_AC, + RW(rf_ac[i], R92C_RF_AC_MODE, + R92C_RF_AC_MODE_STANDBY)); + } + } else { + /* Block all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + } + /* Start calibration. */ + rtwn_rf_setbits(sc, 0, R92C_RF_CHNLBW, 0, R92C_RF_CHNLBW_LCSTART); + + /* Give calibration the time to complete. */ + rtwn_delay(sc, 100000); /* 100ms */ + + /* Restore configuration. */ + if ((txmode & 0x70) != 0) { + /* Restore Tx mode. */ + rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode); + /* Restore RF mode. */ + for (i = 0; i < sc->nrxchains; i++) + rtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]); + } else { + /* Unblock all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, 0x00); + } +} + +void +r92c_temp_measure(struct rtwn_softc *sc) +{ + rtwn_rf_write(sc, 0, R92C_RF_T_METER, R92C_RF_T_METER_START); +} + +uint8_t +r92c_temp_read(struct rtwn_softc *sc) +{ + return (MS(rtwn_rf_read(sc, 0, R92C_RF_T_METER), + R92C_RF_T_METER_VAL)); +} diff --git a/sys/dev/rtwn/rtl8192c/r92c_chan.c b/sys/dev/rtwn/rtl8192c/r92c_chan.c new file mode 100644 index 000000000000..59443faf205f --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_chan.c @@ -0,0 +1,351 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + + +static int +r92c_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + uint8_t chan; + int group; + + chan = rtwn_chan2centieee(c); + if (IEEE80211_IS_CHAN_2GHZ(c)) { + if (chan <= 3) group = 0; + else if (chan <= 9) group = 1; + else if (chan <= 14) group = 2; + else { + KASSERT(0, ("wrong 2GHz channel %d!\n", chan)); + return (-1); + } + } else { + KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags)); + return (-1); + } + + return (group); +} + +/* XXX recheck */ +void +r92c_get_txpower(struct rtwn_softc *sc, int chain, + struct ieee80211_channel *c, uint16_t power[RTWN_RIDX_COUNT]) +{ + struct r92c_softc *rs = sc->sc_priv; + struct rtwn_r92c_txpwr *rt = rs->rs_txpwr; + const struct rtwn_r92c_txagc *base = rs->rs_txagc; + uint8_t ofdmpow, htpow, diff, max; + int max_mcs, ridx, group; + + /* Determine channel group. */ + group = r92c_get_power_group(sc, c); + if (group == -1) { /* shouldn't happen */ + device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__); + return; + } + + /* XXX net80211 regulatory */ + + max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + KASSERT(max_mcs <= RTWN_RIDX_COUNT, ("increase ridx limit\n")); + + memset(power, 0, max_mcs * sizeof(power[0])); + if (rs->regulatory == 0) { + for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) + power[ridx] = base[chain].pwr[0][ridx]; + } + for (ridx = RTWN_RIDX_OFDM6; ridx < RTWN_RIDX_COUNT; ridx++) { + if (rs->regulatory == 3) { + power[ridx] = base[chain].pwr[0][ridx]; + /* Apply vendor limits. */ + if (IEEE80211_IS_CHAN_HT40(c)) + max = rt->ht40_max_pwr[chain][group]; + else + max = rt->ht20_max_pwr[chain][group]; + if (power[ridx] > max) + power[ridx] = max; + } else if (rs->regulatory == 1) { + if (!IEEE80211_IS_CHAN_HT40(c)) + power[ridx] = base[chain].pwr[group][ridx]; + } else if (rs->regulatory != 2) + power[ridx] = base[chain].pwr[0][ridx]; + } + + /* Compute per-CCK rate Tx power. */ + for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) + power[ridx] += rt->cck_tx_pwr[chain][group]; + + htpow = rt->ht40_1s_tx_pwr[chain][group]; + if (sc->ntxchains > 1) { + /* Apply reduction for 2 spatial streams. */ + diff = rt->ht40_2s_tx_pwr_diff[chain][group]; + htpow = (htpow > diff) ? htpow - diff : 0; + } + + /* Compute per-OFDM rate Tx power. */ + diff = rt->ofdm_tx_pwr_diff[chain][group]; + ofdmpow = htpow + diff; /* HT->OFDM correction. */ + for (ridx = RTWN_RIDX_OFDM6; ridx <= RTWN_RIDX_OFDM54; ridx++) + power[ridx] += ofdmpow; + + /* Compute per-MCS Tx power. */ + if (!IEEE80211_IS_CHAN_HT40(c)) { + diff = rt->ht20_tx_pwr_diff[chain][group]; + htpow += diff; /* HT40->HT20 correction. */ + } + for (ridx = RTWN_RIDX_MCS(0); ridx <= max_mcs; ridx++) + power[ridx] += htpow; + + /* Apply max limit. */ + for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) { + if (power[ridx] > R92C_MAX_TX_PWR) + power[ridx] = R92C_MAX_TX_PWR; + } +} + +static void +r92c_write_txpower(struct rtwn_softc *sc, int chain, + uint16_t power[RTWN_RIDX_COUNT]) +{ + uint32_t reg; + + /* Write per-CCK rate Tx power. */ + if (chain == 0) { + reg = rtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32); + reg = RW(reg, R92C_TXAGC_A_CCK1, power[RTWN_RIDX_CCK1]); + rtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg); + reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); + reg = RW(reg, R92C_TXAGC_A_CCK2, power[RTWN_RIDX_CCK2]); + reg = RW(reg, R92C_TXAGC_A_CCK55, power[RTWN_RIDX_CCK55]); + reg = RW(reg, R92C_TXAGC_A_CCK11, power[RTWN_RIDX_CCK11]); + rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); + } else { + reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32); + reg = RW(reg, R92C_TXAGC_B_CCK1, power[RTWN_RIDX_CCK1]); + reg = RW(reg, R92C_TXAGC_B_CCK2, power[RTWN_RIDX_CCK2]); + reg = RW(reg, R92C_TXAGC_B_CCK55, power[RTWN_RIDX_CCK55]); + rtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg); + reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); + reg = RW(reg, R92C_TXAGC_B_CCK11, power[RTWN_RIDX_CCK11]); + rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); + } + /* Write per-OFDM rate Tx power. */ + rtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain), + SM(R92C_TXAGC_RATE06, power[RTWN_RIDX_OFDM6]) | + SM(R92C_TXAGC_RATE09, power[RTWN_RIDX_OFDM9]) | + SM(R92C_TXAGC_RATE12, power[RTWN_RIDX_OFDM12]) | + SM(R92C_TXAGC_RATE18, power[RTWN_RIDX_OFDM18])); + rtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain), + SM(R92C_TXAGC_RATE24, power[RTWN_RIDX_OFDM24]) | + SM(R92C_TXAGC_RATE36, power[RTWN_RIDX_OFDM36]) | + SM(R92C_TXAGC_RATE48, power[RTWN_RIDX_OFDM48]) | + SM(R92C_TXAGC_RATE54, power[RTWN_RIDX_OFDM54])); + /* Write per-MCS Tx power. */ + rtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain), + SM(R92C_TXAGC_MCS00, power[RTWN_RIDX_MCS(0)]) | + SM(R92C_TXAGC_MCS01, power[RTWN_RIDX_MCS(1)]) | + SM(R92C_TXAGC_MCS02, power[RTWN_RIDX_MCS(2)]) | + SM(R92C_TXAGC_MCS03, power[RTWN_RIDX_MCS(3)])); + rtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain), + SM(R92C_TXAGC_MCS04, power[RTWN_RIDX_MCS(4)]) | + SM(R92C_TXAGC_MCS05, power[RTWN_RIDX_MCS(5)]) | + SM(R92C_TXAGC_MCS06, power[RTWN_RIDX_MCS(6)]) | + SM(R92C_TXAGC_MCS07, power[RTWN_RIDX_MCS(7)])); + if (sc->ntxchains >= 2) { + rtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain), + SM(R92C_TXAGC_MCS08, power[RTWN_RIDX_MCS(8)]) | + SM(R92C_TXAGC_MCS09, power[RTWN_RIDX_MCS(9)]) | + SM(R92C_TXAGC_MCS10, power[RTWN_RIDX_MCS(10)]) | + SM(R92C_TXAGC_MCS11, power[RTWN_RIDX_MCS(11)])); + rtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain), + SM(R92C_TXAGC_MCS12, power[RTWN_RIDX_MCS(12)]) | + SM(R92C_TXAGC_MCS13, power[RTWN_RIDX_MCS(13)]) | + SM(R92C_TXAGC_MCS14, power[RTWN_RIDX_MCS(14)]) | + SM(R92C_TXAGC_MCS15, power[RTWN_RIDX_MCS(15)])); + } +} + +static void +r92c_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + uint16_t power[RTWN_RIDX_COUNT]; + int i; + + for (i = 0; i < sc->ntxchains; i++) { + /* Compute per-rate Tx power values. */ + rtwn_r92c_get_txpower(sc, i, c, power); +#ifdef RTWN_DEBUG + if (sc->sc_debug & RTWN_DEBUG_TXPWR) { + int ridx; + + /* Dump per-rate Tx power values. */ + printf("Tx power for chain %d:\n", i); + for (ridx = RTWN_RIDX_CCK1; + ridx < RTWN_RIDX_COUNT; + ridx++) + printf("Rate %d = %u\n", ridx, power[ridx]); + } +#endif + /* Write per-rate Tx power values to hardware. */ + r92c_write_txpower(sc, i, power); + } +} + +static void +r92c_set_bw40(struct rtwn_softc *sc, uint8_t chan, int prichlo) +{ + struct r92c_softc *rs = sc->sc_priv; + + rtwn_setbits_1(sc, R92C_BWOPMODE, R92C_BWOPMODE_20MHZ, 0); + rtwn_setbits_1(sc, R92C_RRSR + 2, 0x6f, (prichlo ? 1 : 2) << 5); + + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_40MHZ); + rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, 0, R92C_RFMOD_40MHZ); + + /* Set CCK side band. */ + rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0x10, + (prichlo ? 0 : 1) << 4); + + rtwn_bb_setbits(sc, R92C_OFDM1_LSTF, 0x0c00, + (prichlo ? 1 : 2) << 10); + + rtwn_bb_setbits(sc, R92C_FPGA0_ANAPARAM2, + R92C_FPGA0_ANAPARAM2_CBW20, 0); + + rtwn_bb_setbits(sc, 0x818, 0x0c000000, (prichlo ? 2 : 1) << 26); + + /* Select 40MHz bandwidth. */ + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, + (rs->rf_chnlbw[0] & ~0xfff) | chan); +} + +void +r92c_set_bw20(struct rtwn_softc *sc, uint8_t chan) +{ + struct r92c_softc *rs = sc->sc_priv; + + rtwn_setbits_1(sc, R92C_BWOPMODE, 0, R92C_BWOPMODE_20MHZ); + + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, R92C_RFMOD_40MHZ, 0); + rtwn_bb_setbits(sc, R92C_FPGA1_RFMOD, R92C_RFMOD_40MHZ, 0); + + rtwn_bb_setbits(sc, R92C_FPGA0_ANAPARAM2, 0, + R92C_FPGA0_ANAPARAM2_CBW20); + + /* Select 20MHz bandwidth. */ + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, + (rs->rf_chnlbw[0] & ~0xfff) | chan | R92C_RF_CHNLBW_BW20); +} + +void +r92c_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + struct r92c_softc *rs = sc->sc_priv; + u_int chan; + int i; + + chan = rtwn_chan2centieee(c); + + /* Set Tx power for this new channel. */ + r92c_set_txpower(sc, c); + + for (i = 0; i < sc->nrxchains; i++) { + rtwn_rf_write(sc, i, R92C_RF_CHNLBW, + RW(rs->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan)); + } + if (IEEE80211_IS_CHAN_HT40(c)) + r92c_set_bw40(sc, chan, IEEE80211_IS_CHAN_HT40U(c)); + else + rtwn_r92c_set_bw20(sc, chan); +} + +void +r92c_set_gain(struct rtwn_softc *sc, uint8_t gain) +{ + + rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(0), + R92C_OFDM0_AGCCORE1_GAIN_M, gain); + rtwn_bb_setbits(sc, R92C_OFDM0_AGCCORE1(1), + R92C_OFDM0_AGCCORE1_GAIN_M, gain); +} + +void +r92c_scan_start(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + struct r92c_softc *rs = sc->sc_priv; + + RTWN_LOCK(sc); + /* Set gain for scanning. */ + rtwn_r92c_set_gain(sc, 0x20); + RTWN_UNLOCK(sc); + + rs->rs_scan_start(ic); +} + +void +r92c_scan_end(struct ieee80211com *ic) +{ + struct rtwn_softc *sc = ic->ic_softc; + struct r92c_softc *rs = sc->sc_priv; + + RTWN_LOCK(sc); + /* Set gain under link. */ + rtwn_r92c_set_gain(sc, 0x32); + RTWN_UNLOCK(sc); + + rs->rs_scan_end(ic); +} diff --git a/sys/dev/rtwn/rtl8192c/r92c_fw.c b/sys/dev/rtwn/rtl8192c/r92c_fw.c new file mode 100644 index 000000000000..b6de795e37ac --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_fw.c @@ -0,0 +1,520 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +#ifndef RTWN_WITHOUT_UCODE +static int +r92c_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len) +{ + struct r92c_fw_cmd cmd; + int ntries, error; + + KASSERT(len <= sizeof(cmd.msg), + ("%s: firmware command too long (%d > %zu)\n", + __func__, len, sizeof(cmd.msg))); + + if (!(sc->sc_flags & RTWN_FW_LOADED)) { + RTWN_DPRINTF(sc, RTWN_DEBUG_FIRMWARE, "%s: firmware " + "was not loaded; command (id %u) will be discarded\n", + __func__, id); + return (0); + } + + /* Wait for current FW box to be empty. */ + for (ntries = 0; ntries < 50; ntries++) { + if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur))) + break; + rtwn_delay(sc, 2000); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "could not send firmware command\n"); + return (ETIMEDOUT); + } + memset(&cmd, 0, sizeof(cmd)); + cmd.id = id; + if (len > 3) { + /* Ext command: [id : byte2 : byte3 : byte4 : byte0 : byte1] */ + cmd.id |= R92C_CMD_FLAG_EXT; + memcpy(cmd.msg, (const uint8_t *)buf + 2, len - 2); + memcpy(cmd.msg + 3, buf, 2); + } else + memcpy(cmd.msg, buf, len); + + /* Write the first word last since that will trigger the FW. */ + if (len > 3) { + error = rtwn_write_2(sc, R92C_HMEBOX_EXT(sc->fwcur), + *(uint16_t *)((uint8_t *)&cmd + 4)); + if (error != 0) + return (error); + } + error = rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur), + *(uint32_t *)&cmd); + if (error != 0) + return (error); + + sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX; + + return (0); +} + +void +r92c_fw_reset(struct rtwn_softc *sc, int reason) +{ + int ntries; + + if (reason == RTWN_FW_RESET_CHECKSUM) + return; + + /* Tell 8051 to reset itself. */ + rtwn_write_1(sc, R92C_HMETFR + 3, 0x20); + + /* Wait until 8051 resets by itself. */ + for (ntries = 0; ntries < 100; ntries++) { + if ((rtwn_read_2(sc, R92C_SYS_FUNC_EN) & + R92C_SYS_FUNC_EN_CPUEN) == 0) + return; + rtwn_delay(sc, 50); + } + /* Force 8051 reset. */ + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_CPUEN, 0, 1); +} + +void +r92c_fw_download_enable(struct rtwn_softc *sc, int enable) +{ + if (enable) { + /* 8051 enable. */ + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, 0, + R92C_SYS_FUNC_EN_CPUEN, 1); + /* MCU firmware download enable. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN); + /* 8051 reset. */ + rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN, + 0, 2); + } else { + /* MCU download disable. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0); + /* Reserved for f/w extension. */ + rtwn_write_1(sc, R92C_MCUFWDL + 1, 0); + } +} +#endif + +/* + * Initialize firmware rate adaptation. + */ +#ifndef RTWN_WITHOUT_UCODE +static int +r92c_send_ra_cmd(struct rtwn_softc *sc, int macid, uint32_t rates, + int maxrate) +{ + struct r92c_fw_cmd_macid_cfg cmd; + uint8_t mode; + int error = 0; + + /* XXX should be called directly from iv_newstate() for MACID_BC */ + /* XXX joinbss, not send_ra_cmd() */ +#ifdef RTWN_TODO + /* NB: group addressed frames are done at 11bg rates for now */ + if (ic->ic_curmode == IEEE80211_MODE_11B) + mode = R92C_RAID_11B; + else + mode = R92C_RAID_11BG; + /* XXX misleading 'mode' value here for unicast frames */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RA, + "%s: mode 0x%x, rates 0x%08x, basicrates 0x%08x\n", __func__, + mode, rates, basicrates); + + /* Set rates mask for group addressed frames. */ + cmd.macid = RTWN_MACID_BC | R92C_CMD_MACID_VALID; + cmd.mask = htole32(mode << 28 | basicrates); + error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); + if (error != 0) { + device_printf(sc->sc_dev, + "could not set RA mask for broadcast station\n"); + return (error); + } +#endif + + /* Set rates mask for unicast frames. */ + if (maxrate >= RTWN_RIDX_MCS(0)) + mode = R92C_RAID_11GN; + else if (maxrate >= RTWN_RIDX_OFDM6) + mode = R92C_RAID_11BG; + else + mode = R92C_RAID_11B; + cmd.macid = macid | R92C_CMD_MACID_VALID; + cmd.mask = htole32(mode << 28 | rates); + error = r92c_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: could not set RA mask for %d station\n", + __func__, macid); + return (error); + } + + return (0); +} +#endif + +static void +r92c_init_ra(struct rtwn_softc *sc, int macid) +{ + struct ieee80211_htrateset *rs_ht; + struct ieee80211_node *ni; + uint32_t rates; + int maxrate; + + RTWN_NT_LOCK(sc); + if (sc->node_list[macid] == NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RA, "%s: macid %d, ni is NULL\n", + __func__, macid); + RTWN_NT_UNLOCK(sc); + return; + } + + ni = ieee80211_ref_node(sc->node_list[macid]); + if (ni->ni_flags & IEEE80211_NODE_HT) + rs_ht = &ni->ni_htrates; + else + rs_ht = NULL; + /* XXX MACID_BC */ + rtwn_get_rates(sc, &ni->ni_rates, rs_ht, &rates, &maxrate, 0); + RTWN_NT_UNLOCK(sc); + +#ifndef RTWN_WITHOUT_UCODE + if (sc->sc_ratectl == RTWN_RATECTL_FW) { + r92c_send_ra_cmd(sc, macid, rates, maxrate); + } +#endif + + rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(macid), maxrate); + + ieee80211_free_node(ni); +} + +void +r92c_joinbss_rpt(struct rtwn_softc *sc, int macid) +{ +#ifndef RTWN_WITHOUT_UCODE + struct r92c_softc *rs = sc->sc_priv; + struct ieee80211vap *vap; + struct r92c_fw_cmd_joinbss_rpt cmd; + + if (sc->vaps[0] == NULL) /* XXX fix */ + goto end; + + vap = &sc->vaps[0]->vap; + if ((vap->iv_state == IEEE80211_S_RUN) ^ + !(rs->rs_flags & R92C_FLAG_ASSOCIATED)) + goto end; + + if (rs->rs_flags & R92C_FLAG_ASSOCIATED) { + cmd.mstatus = R92C_MSTATUS_DISASSOC; + rs->rs_flags &= ~R92C_FLAG_ASSOCIATED; + } else { + cmd.mstatus = R92C_MSTATUS_ASSOC; + rs->rs_flags |= R92C_FLAG_ASSOCIATED; + } + + if (r92c_fw_cmd(sc, R92C_CMD_JOINBSS_RPT, &cmd, sizeof(cmd)) != 0) { + device_printf(sc->sc_dev, "%s: cannot change media status!\n", + __func__); + } + +end: +#endif + + /* TODO: init rates for RTWN_MACID_BC. */ + if (macid & RTWN_MACID_VALID) + r92c_init_ra(sc, macid & ~RTWN_MACID_VALID); +} + +#ifndef RTWN_WITHOUT_UCODE +int +r92c_set_rsvd_page(struct rtwn_softc *sc, int probe_resp, int null, + int qos_null) +{ + struct r92c_fw_cmd_rsvdpage rsvd; + + rsvd.probe_resp = probe_resp; + rsvd.ps_poll = 0; + rsvd.null_data = null; + + return (r92c_fw_cmd(sc, R92C_CMD_RSVD_PAGE, &rsvd, sizeof(rsvd))); +} + +int +r92c_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap, + int off) +{ + struct r92c_fw_cmd_pwrmode mode; + int error; + + /* XXX dm_RF_saving */ + + if (off && vap->iv_state == IEEE80211_S_RUN && + (vap->iv_flags & IEEE80211_F_PMGTON)) + mode.mode = R92C_PWRMODE_MIN; + else + mode.mode = R92C_PWRMODE_CAM; + mode.smart_ps = R92C_PWRMODE_SMARTPS_NULLDATA; + mode.bcn_pass = 1; /* XXX */ + error = r92c_fw_cmd(sc, R92C_CMD_SET_PWRMODE, &mode, sizeof(mode)); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: CMD_SET_PWRMODE was not sent, error %d\n", + __func__, error); + } + + return (error); +} + +void +r92c_set_rssi(struct rtwn_softc *sc) +{ + struct ieee80211_node *ni; + struct rtwn_node *rn; + struct r92c_fw_cmd_rssi cmd; + int i; + + cmd.reserved = 0; + + RTWN_NT_LOCK(sc); + for (i = 0; i < sc->macid_limit; i++) { + /* XXX optimize? */ + ni = sc->node_list[i]; + if (ni == NULL) + continue; + + rn = RTWN_NODE(ni); + cmd.macid = i; + cmd.pwdb = rn->avg_pwdb; + RTWN_DPRINTF(sc, RTWN_DEBUG_RSSI, + "%s: sending RSSI command (macid %d, rssi %d)\n", + __func__, i, rn->avg_pwdb); + + RTWN_NT_UNLOCK(sc); + r92c_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, sizeof(cmd)); + RTWN_NT_LOCK(sc); + } + RTWN_NT_UNLOCK(sc); +} + +static void +r92c_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) +{ +#if __FreeBSD_version >= 1200012 + struct ieee80211_ratectl_tx_status txs; +#endif + struct r92c_c2h_tx_rpt *rpt; + struct ieee80211_node *ni; + uint8_t macid; + int ntries; + + if (sc->sc_ratectl != RTWN_RATECTL_NET80211) { + /* shouldn't happen */ + device_printf(sc->sc_dev, "%s called while ratectl = %d!\n", + __func__, sc->sc_ratectl); + return; + } + + rpt = (struct r92c_c2h_tx_rpt *)buf; + if (len != sizeof(*rpt)) { + device_printf(sc->sc_dev, + "%s: wrong report size (%d, must be %zu)\n", + __func__, len, sizeof(*rpt)); + return; + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: ccx report dump: 0: %02X, 1: %02X, queue time: " + "low %02X, high %02X, 4: %02X, 5: %02X, 6: %02X, 7: %02X\n", + __func__, rpt->rptb0, rpt->rptb1, rpt->queue_time_low, + rpt->queue_time_high, rpt->rptb4, rpt->rptb5, rpt->rptb6, + rpt->rptb7); + + macid = MS(rpt->rptb5, R92C_RPTB5_MACID); + if (macid > sc->macid_limit) { + device_printf(sc->sc_dev, + "macid %u is too big; increase MACID_MAX limit\n", + macid); + return; + } + + ntries = MS(rpt->rptb0, R92C_RPTB0_RETRY_CNT); + + RTWN_NT_LOCK(sc); + ni = sc->node_list[macid]; + if (ni != NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was" + "%s sent (%d retries)\n", __func__, macid, + (rpt->rptb7 & R92C_RPTB7_PKT_OK) ? "" : " not", + ntries); + +#if __FreeBSD_version >= 1200012 + txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY; + txs.long_retries = ntries; + if (rpt->rptb7 & R92C_RPTB7_PKT_OK) + txs.status = IEEE80211_RATECTL_TX_SUCCESS; + else if (rpt->rptb6 & R92C_RPTB6_RETRY_OVER) + txs.status = IEEE80211_RATECTL_TX_FAIL_LONG; /* XXX */ + else if (rpt->rptb6 & R92C_RPTB6_LIFE_EXPIRE) + txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED; + else + txs.status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED; + ieee80211_ratectl_tx_complete(ni, &txs); +#else + struct ieee80211vap *vap = ni->ni_vap; + if (rpt->rptb7 & R92C_RPTB7_PKT_OK) { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL); + } else { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL); + } +#endif + } else { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: macid %u, ni is NULL\n", + __func__, macid); + } + RTWN_NT_UNLOCK(sc); + +#ifdef IEEE80211_SUPPORT_SUPERG + if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1) + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); +#endif +} + +static void +r92c_handle_c2h_task(struct rtwn_softc *sc, union sec_param *data) +{ + const uint16_t off = R92C_C2H_EVT_MSG + sizeof(struct r92c_c2h_evt); + struct r92c_softc *rs = sc->sc_priv; + uint16_t buf[R92C_C2H_MSG_MAX_LEN / 2 + 1]; + uint8_t id, len, status; + int i; + + /* Do not reschedule the task if device is not running. */ + if (!(sc->sc_flags & RTWN_RUNNING)) + return; + + /* Read current status. */ + status = rtwn_read_1(sc, R92C_C2H_EVT_CLEAR); + if (status == R92C_C2H_EVT_HOST_CLOSE) + goto end; /* nothing to do */ + else if (status == R92C_C2H_EVT_FW_CLOSE) { + len = rtwn_read_1(sc, R92C_C2H_EVT_MSG); + id = MS(len, R92C_C2H_EVTB0_ID); + len = MS(len, R92C_C2H_EVTB0_LEN); + + memset(buf, 0, sizeof(buf)); + /* Try to optimize event reads. */ + for (i = 0; i < len; i += 2) + buf[i / 2] = rtwn_read_2(sc, off + i); + KASSERT(i < sizeof(buf), ("%s: buffer overrun (%d >= %zu)!", + __func__, i, sizeof(buf))); + + switch (id) { + case R92C_C2H_EVT_TX_REPORT: + r92c_ratectl_tx_complete(sc, (uint8_t *)buf, len); + break; + default: + device_printf(sc->sc_dev, + "%s: C2H report %u (len %u) was not handled\n", + __func__, id, len); + break; + } + } + + /* Prepare for next event. */ + rtwn_write_1(sc, R92C_C2H_EVT_CLEAR, R92C_C2H_EVT_HOST_CLOSE); + +end: + /* Adjust timeout for next call. */ + if (rs->rs_c2h_pending != 0) { + rs->rs_c2h_pending = 0; + rs->rs_c2h_paused = 0; + } else + rs->rs_c2h_paused++; + + if (rs->rs_c2h_paused > R92C_TX_PAUSED_THRESHOLD) + rs->rs_c2h_timeout = hz; + else + rs->rs_c2h_timeout = MAX(hz / 100, 1); + + /* Reschedule the task. */ + callout_reset(&rs->rs_c2h_report, rs->rs_c2h_timeout, + r92c_handle_c2h_report, sc); +} + +void +r92c_handle_c2h_report(void *arg) +{ + struct rtwn_softc *sc = arg; + + rtwn_cmd_sleepable(sc, NULL, 0, r92c_handle_c2h_task); +} + +#endif /* RTWN_WITHOUT_UCODE */ diff --git a/sys/dev/rtwn/rtl8192c/r92c_fw_cmd.h b/sys/dev/rtwn/rtl8192c/r92c_fw_cmd.h new file mode 100644 index 000000000000..998a7805fd27 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_fw_cmd.h @@ -0,0 +1,148 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_FW_CMD_H +#define R92C_FW_CMD_H + +/* + * Host to firmware commands. + */ +struct r92c_fw_cmd { + uint8_t id; +#define R92C_CMD_SET_PWRMODE 1 +#define R92C_CMD_JOINBSS_RPT 2 +#define R92C_CMD_RSVD_PAGE 3 +#define R92C_CMD_RSSI_SETTING 5 +#define R92C_CMD_MACID_CONFIG 6 + +#define R92C_CMD_FLAG_EXT 0x80 + + uint8_t msg[5]; +} __packed __attribute__((aligned(4))); + +/* Structure for R92C_CMD_JOINBSS_RPT. */ +struct r92c_fw_cmd_joinbss_rpt { + uint8_t mstatus; +#define R92C_MSTATUS_DISASSOC 0x00 +#define R92C_MSTATUS_ASSOC 0x01 +} __packed; + +/* Structure for R92C_CMD_SET_PWRMODE. */ +struct r92c_fw_cmd_pwrmode { + uint8_t mode; +#define R92C_PWRMODE_CAM 0 +#define R92C_PWRMODE_MIN 1 +#define R92C_PWRMODE_MAX 2 +#define R92C_PWRMODE_DTIM 3 +#define R92C_PWRMODE_UAPSD_WMM 5 +#define R92C_PWRMODE_UAPSD 6 +#define R92C_PWRMODE_IBSS 7 + + uint8_t smart_ps; +/* XXX undocumented */ +#define R92C_PWRMODE_SMARTPS_NULLDATA 2 + + uint8_t bcn_pass; /* unit: beacon interval */ +} __packed; + +/* Structure for R92C_CMD_RSVD_PAGE. */ +struct r92c_fw_cmd_rsvdpage { + uint8_t probe_resp; + uint8_t ps_poll; + uint8_t null_data; +} __packed; + +/* Structure for R92C_CMD_RSSI_SETTING. */ +struct r92c_fw_cmd_rssi { + uint8_t macid; + uint8_t reserved; + uint8_t pwdb; +} __packed; + +/* Structure for R92C_CMD_MACID_CONFIG. */ +struct r92c_fw_cmd_macid_cfg { + uint32_t mask; + uint8_t macid; +#define R92C_CMD_MACID_VALID 0x80 +} __packed; + +/* + * C2H event structure. + */ +/* Bigger value is used to prevent buffer overrun. */ +#define R92C_C2H_MSG_MAX_LEN 16 + +struct r92c_c2h_evt { + uint8_t evtb0; +#define R92C_C2H_EVTB0_ID_M 0x0f +#define R92C_C2H_EVTB0_ID_S 0 +#define R92C_C2H_EVTB0_LEN_M 0xf0 +#define R92C_C2H_EVTB0_LEN_S 4 + + uint8_t seq; + + /* Followed by payload (see below). */ +} __packed; + +/* + * C2H event types. + */ +#define R92C_C2H_EVT_DEBUG 0 +#define R92C_C2H_EVT_TX_REPORT 3 +#define R92C_C2H_EVT_EXT_RA_RPT 6 + +/* Structure for R92C_C2H_EVT_TX_REPORT event. */ +struct r92c_c2h_tx_rpt { + uint8_t rptb0; +#define R92C_RPTB0_RETRY_CNT_M 0x3f +#define R92C_RPTB0_RETRY_CNT_S 0 + + uint8_t rptb1; /* XXX junk */ +#define R92C_RPTB1_RTS_RETRY_CNT_M 0x3f +#define R92C_RPTB1_RTS_RETRY_CNT_S 0 + + uint8_t queue_time_low; + uint8_t queue_time_high; + uint8_t rptb4; +#define R92C_RPTB4_MISSED_PKT_NUM_M 0x1f +#define R92C_RPTB4_MISSED_PKT_NUM_S 0 + + uint8_t rptb5; +#define R92C_RPTB5_MACID_M 0x1f +#define R92C_RPTB5_MACID_S 0 +#define R92C_RPTB5_DES1_FRAGSSN_M 0xe0 +#define R92C_RPTB5_DES1_FRAGSSN_S 5 + + uint8_t rptb6; +#define R92C_RPTB6_RPT_PKT_NUM_M 0x1f +#define R92C_RPTB6_RPT_PKT_NUM_S 0 +#define R92C_RPTB6_PKT_DROP 0x20 +#define R92C_RPTB6_LIFE_EXPIRE 0x40 +#define R92C_RPTB6_RETRY_OVER 0x80 + + uint8_t rptb7; +#define R92C_RPTB7_EDCA_M 0x0f +#define R92C_RPTB7_EDCA_S 0 +#define R92C_RPTB7_BMC 0x20 +#define R92C_RPTB7_PKT_OK 0x40 +#define R92C_RPTB7_INT_CCX 0x80 +} __packed; + +#endif /* R92C_FW_CMD_H */ diff --git a/sys/dev/rtwn/rtl8192c/r92c_init.c b/sys/dev/rtwn/rtl8192c/r92c_init.c new file mode 100644 index 000000000000..3b9d8d9370b1 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_init.c @@ -0,0 +1,322 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + + +int +r92c_check_condition(struct rtwn_softc *sc, const uint8_t cond[]) +{ + struct r92c_softc *rs = sc->sc_priv; + uint8_t mask; + int i; + + if (cond[0] == 0) + return (1); + + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "%s: condition byte 0: %02X; chip %02X, board %02X\n", + __func__, cond[0], rs->chip, rs->board_type); + + if (!(rs->chip & R92C_CHIP_92C)) { + if (rs->board_type == R92C_BOARD_TYPE_HIGHPA) + mask = R92C_COND_RTL8188RU; + else if (rs->board_type == R92C_BOARD_TYPE_MINICARD) + mask = R92C_COND_RTL8188CE; + else + mask = R92C_COND_RTL8188CU; + } else { + if (rs->board_type == R92C_BOARD_TYPE_MINICARD) + mask = R92C_COND_RTL8192CE; + else + mask = R92C_COND_RTL8192CU; + } + + for (i = 0; i < RTWN_MAX_CONDITIONS && cond[i] != 0; i++) + if ((cond[i] & mask) == mask) + return (1); + + return (0); +} + +int +r92c_set_page_size(struct rtwn_softc *sc) +{ + return (rtwn_write_1(sc, R92C_PBP, SM(R92C_PBP_PSRX, R92C_PBP_128) | + SM(R92C_PBP_PSTX, R92C_PBP_128)) == 0); +} + +void +r92c_init_bb_common(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + int i, j; + + /* Write BB initialization values. */ + for (i = 0; i < sc->bb_size; i++) { + const struct rtwn_bb_prog *bb_prog = &sc->bb_prog[i]; + + while (!rtwn_check_condition(sc, bb_prog->cond)) { + KASSERT(bb_prog->next != NULL, + ("%s: wrong condition value (i %d)\n", + __func__, i)); + bb_prog = bb_prog->next; + } + + for (j = 0; j < bb_prog->count; j++) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "BB: reg 0x%03x, val 0x%08x\n", + bb_prog->reg[j], bb_prog->val[j]); + + rtwn_bb_write(sc, bb_prog->reg[j], bb_prog->val[j]); + rtwn_delay(sc, 1); + } + } + + if (rs->chip & R92C_CHIP_92C_1T2R) { + /* 8192C 1T only configuration. */ + rtwn_bb_setbits(sc, R92C_FPGA0_TXINFO, 0x03, 0x02); + rtwn_bb_setbits(sc, R92C_FPGA1_TXINFO, 0x300033, 0x200022); + rtwn_bb_setbits(sc, R92C_CCK0_AFESETTING, 0xff000000, + 0x45000000); + rtwn_bb_setbits(sc, R92C_OFDM0_TRXPATHENA, 0xff, 0x23); + rtwn_bb_setbits(sc, R92C_OFDM0_AGCPARAM1, 0x30, 0x10); + + rtwn_bb_setbits(sc, 0xe74, 0x0c000000, 0x08000000); + rtwn_bb_setbits(sc, 0xe78, 0x0c000000, 0x08000000); + rtwn_bb_setbits(sc, 0xe7c, 0x0c000000, 0x08000000); + rtwn_bb_setbits(sc, 0xe80, 0x0c000000, 0x08000000); + rtwn_bb_setbits(sc, 0xe88, 0x0c000000, 0x08000000); + } + + /* Write AGC values. */ + for (i = 0; i < sc->agc_size; i++) { + const struct rtwn_agc_prog *agc_prog = &sc->agc_prog[i]; + + while (!rtwn_check_condition(sc, agc_prog->cond)) { + KASSERT(agc_prog->next != NULL, + ("%s: wrong condition value (2) (i %d)\n", + __func__, i)); + agc_prog = agc_prog->next; + } + + for (j = 0; j < agc_prog->count; j++) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "AGC: val 0x%08x\n", agc_prog->val[j]); + + rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE, + agc_prog->val[j]); + rtwn_delay(sc, 1); + } + } +} + +int +r92c_init_rf_chain(struct rtwn_softc *sc, + const struct rtwn_rf_prog *rf_prog, int chain) +{ + int i, j; + + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, "%s: chain %d\n", + __func__, chain); + + for (i = 0; rf_prog[i].reg != NULL; i++) { + const struct rtwn_rf_prog *prog = &rf_prog[i]; + + while (!rtwn_check_condition(sc, prog->cond)) { + KASSERT(prog->next != NULL, + ("%s: wrong condition value (i %d)\n", + __func__, i)); + prog = prog->next; + } + + for (j = 0; j < prog->count; j++) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "RF: reg 0x%02x, val 0x%05x\n", + prog->reg[j], prog->val[j]); + + /* + * These are fake RF registers offsets that + * indicate a delay is required. + */ + /* NB: we are using 'value' to store required delay. */ + if (prog->reg[j] > 0xf8) { + rtwn_delay(sc, prog->val[j]); + continue; + } + + rtwn_rf_write(sc, chain, prog->reg[j], prog->val[j]); + rtwn_delay(sc, 1); + } + } + + return (i); +} + +void +r92c_init_rf_common(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + uint32_t reg, type; + int i, chain, idx, off; + + for (chain = 0, i = 0; chain < sc->nrxchains; chain++, i++) { + /* Save RF_ENV control type. */ + idx = chain / 2; + off = (chain % 2) * 16; + reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx)); + type = (reg >> off) & 0x10; + + /* Set RF_ENV enable. */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACEOE(chain), + 0, 0x100000); + rtwn_delay(sc, 1); + /* Set RF_ENV output high. */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACEOE(chain), + 0, 0x10); + rtwn_delay(sc, 1); + /* Set address and data lengths of RF registers. */ + rtwn_bb_setbits(sc, R92C_HSSI_PARAM2(chain), + R92C_HSSI_PARAM2_ADDR_LENGTH, 0); + rtwn_delay(sc, 1); + rtwn_bb_setbits(sc, R92C_HSSI_PARAM2(chain), + R92C_HSSI_PARAM2_DATA_LENGTH, 0); + rtwn_delay(sc, 1); + + /* Write RF initialization values for this chain. */ + i += r92c_init_rf_chain(sc, &sc->rf_prog[i], chain); + + /* Restore RF_ENV control type. */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFIFACESW(idx), + 0x10 << off, type << off); + + /* Cache RF register CHNLBW. */ + rs->rf_chnlbw[chain] = rtwn_rf_read(sc, chain, + R92C_RF_CHNLBW); + } +} + +void +r92c_init_rf(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + + r92c_init_rf_common(sc); + + if ((rs->chip & (R92C_CHIP_UMC_A_CUT | R92C_CHIP_92C)) == + R92C_CHIP_UMC_A_CUT) { + rtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255); + rtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x50a00); + } + + /* Turn CCK and OFDM blocks on. */ + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_CCK_EN); + rtwn_bb_setbits(sc, R92C_FPGA0_RFMOD, 0, R92C_RFMOD_OFDM_EN); +} + +void +r92c_init_edca(struct rtwn_softc *sc) +{ + /* SIFS */ + rtwn_write_2(sc, R92C_SPEC_SIFS, 0x100a); + rtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x100a); + rtwn_write_2(sc, R92C_SIFS_CCK, 0x100a); + rtwn_write_2(sc, R92C_SIFS_OFDM, 0x100a); + /* TXOP */ + rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b); + rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f); + rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005ea324); + rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002fa226); +} + +void +r92c_init_ampdu(struct rtwn_softc *sc) +{ + + /* Setup AMPDU aggregation. */ + rtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */ + rtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16); + rtwn_write_2(sc, R92C_MAX_AGGR_NUM, 0x0708); +} + +void +r92c_init_antsel(struct rtwn_softc *sc) +{ + uint32_t reg; + + if (sc->ntxchains != 1 || sc->nrxchains != 1) + return; + + rtwn_setbits_1(sc, R92C_LEDCFG2, 0, 0x80); + rtwn_bb_setbits(sc, R92C_FPGA0_RFPARAM(0), 0, 0x2000); + reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(0)); + sc->sc_ant = MS(reg, R92C_FPGA0_RFIFACEOE0_ANT); /* XXX */ +} + +void +r92c_pa_bias_init(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + int i; + + for (i = 0; i < sc->nrxchains; i++) { + if (rs->pa_setting & (1 << i)) + continue; + r92c_rf_write(sc, i, R92C_RF_IPA, 0x0f406); + r92c_rf_write(sc, i, R92C_RF_IPA, 0x4f406); + r92c_rf_write(sc, i, R92C_RF_IPA, 0x8f406); + r92c_rf_write(sc, i, R92C_RF_IPA, 0xcf406); + } + if (!(rs->pa_setting & 0x10)) + rtwn_setbits_1(sc, 0x16, 0xf0, 0x90); +} diff --git a/sys/dev/rtwn/rtl8192c/r92c_priv.h b/sys/dev/rtwn/rtl8192c/r92c_priv.h new file mode 100644 index 000000000000..13c38fb20def --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_priv.h @@ -0,0 +1,408 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_PRIV_H +#define R92C_PRIV_H + +#include + +/* + * Parsed Tx power (diff) values. + */ +struct rtwn_r92c_txpwr { + uint8_t cck_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; + uint8_t ht40_1s_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; + int8_t ht40_2s_tx_pwr_diff[R92C_MAX_CHAINS][R92C_GROUP_2G]; + int8_t ht20_tx_pwr_diff[R92C_MAX_CHAINS][R92C_GROUP_2G]; + int8_t ofdm_tx_pwr_diff[R92C_MAX_CHAINS][R92C_GROUP_2G]; + int8_t ht40_max_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; + int8_t ht20_max_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; +}; + + +/* + * Baseband initialization values (shared parts). + */ +#define R92C_COND_RTL8188CE 0x01 +#define R92C_COND_RTL8188CU 0x02 +#define R92C_COND_RTL8188RU 0x04 +#define R92C_COND_RTL8192CE 0x08 +#define R92C_COND_RTL8192CU 0x10 + +/* Shortcut. */ +#define R92C_COND_RTL8192C (R92C_COND_RTL8192CE | R92C_COND_RTL8192CU) + +static const uint16_t rtl8192c_bb_regs3[] = { + 0xd04 +}, rtl8192c_bb_regs4[] = { + 0xd08, 0xd0c, 0xd10, 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, + 0xd3c, 0xd40, 0xd44, 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, + 0xd60, 0xd64, 0xd68, 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00, 0xe04, + 0xe08, 0xe10, 0xe14, 0xe18, 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38, + 0xe3c, 0xe40, 0xe44, 0xe48, 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c +}, rtl8192c_bb_regs5[] = { + 0xe60, 0xe68, 0xe6c, 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, 0xed8, 0xedc, 0xee0, 0xeec, 0xf14, + 0xf4c, 0xf00 +}; + +static const uint32_t rtl8192c_bb_vals3_88cu_88ru[] = { + 0x00020401 +}, rtl8192c_bb_vals3_92ce_92cu[] = { + 0x00020403 +}, rtl8192c_bb_vals4[] = { + 0x0000907f, 0x20010201, 0xa0633333, 0x3333bc43, 0x7a8f5b6b, + 0xcc979975, 0x00000000, 0x80608000, 0x00000000, 0x00027293, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6437140a, + 0x00000000, 0x00000000, 0x30032064, 0x4653de68, 0x04518a3c, + 0x00002101, 0x2a201c16, 0x1812362e, 0x322c2220, 0x000e3c24, + 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, 0x2a2a2a2a, 0x2a2a2a2a, + 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, 0x1000dc1f, 0x10008c1f, + 0x02140102, 0x681604c2, 0x01007c00, 0x01004800, 0xfb000000, + 0x000028d1, 0x1000dc1f, 0x10008c1f, 0x02140102, 0x28160d05 +},rtl8192c_bb_vals5_92ce_92cu[] = { + 0x00000010, 0x001b25a4, 0x63db25a4, 0x63db25a4, 0x0c1b25a4, + 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, 0x63db25a4, 0x0c1b25a4, + 0x63db25a4, 0x63db25a4, 0x63db25a4, 0x63db25a4, 0x001b25a4, + 0x001b25a4, 0x6fdb25a4, 0x00000003, 0x00000000, 0x00000300 +}; + +/* + * RTL8192CU and RTL8192CE-VAU. + */ + +static const uint32_t rtl8192ce_agc_vals[] = { + 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, + 0x7b050001, 0x7a060001, 0x79070001, 0x78080001, 0x77090001, + 0x760a0001, 0x750b0001, 0x740c0001, 0x730d0001, 0x720e0001, + 0x710f0001, 0x70100001, 0x6f110001, 0x6e120001, 0x6d130001, + 0x6c140001, 0x6b150001, 0x6a160001, 0x69170001, 0x68180001, + 0x67190001, 0x661a0001, 0x651b0001, 0x641c0001, 0x631d0001, + 0x621e0001, 0x611f0001, 0x60200001, 0x49210001, 0x48220001, + 0x47230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, + 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, + 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, + 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, + 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, + 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, + 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, + 0x7a460001, 0x79470001, 0x78480001, 0x77490001, 0x764a0001, + 0x754b0001, 0x744c0001, 0x734d0001, 0x724e0001, 0x714f0001, + 0x70500001, 0x6f510001, 0x6e520001, 0x6d530001, 0x6c540001, + 0x6b550001, 0x6a560001, 0x69570001, 0x68580001, 0x67590001, + 0x665a0001, 0x655b0001, 0x645c0001, 0x635d0001, 0x625e0001, + 0x615f0001, 0x60600001, 0x49610001, 0x48620001, 0x47630001, + 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, + 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, + 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, + 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, + 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, + 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, + 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, + 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, + 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, + 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, + 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, + 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e +}; + +static const struct rtwn_agc_prog rtl8192ce_agc[] = { + { + nitems(rtl8192ce_agc_vals), + rtl8192ce_agc_vals, + { 0 }, + NULL + } +}; + + +/* + * RF initialization values. + */ +static const uint8_t rtl8192c_rf0_regs0[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21 +}, rtl8192c_rf0_regs1[] = { + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28 +}, rtl8192c_rf0_regs2[] = { + 0x29, 0x2a, 0x2b, 0x2a, 0x2b, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, + 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, + 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, + 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, + 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, + 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x10, 0x11, 0x10, 0x11, + 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11 +}, rtl8192c_rf0_regs3[] = { + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13 +}, rtl8192c_rf0_regs4[] = { + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15 +}, rtl8192c_rf0_regs5[] = { + 0x16, 0x16, 0x16, 0x16, 0x00, 0x18, 0xfe, 0xfe, 0x1f, 0xfe, 0xfe, + 0x1e, 0x1f, 0x00 +}; + +static const uint32_t rtl8192c_rf0_vals0_88ce_88cu_92ce[] = { + 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, + 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255, + 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000 +}, rtl8192c_rf0_vals0_88ru[] = { + 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb0, + 0x54867, 0x8992e, 0x0e529, 0x39ce7, 0x00451, 0x00000, 0x00255, + 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000 +}, rtl8192c_rf0_vals1_88ru[] = { + 0x0083c, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x977c0 +}, rtl8192c_rf0_vals1_88ce[] = { + 0x00000, 0x01558, 0x00060, 0x00483, 0x4f200, 0xec7d9, 0x577c0 +}, rtl8192c_rf0_vals1_88cu_92ce[] = { + 0x00000, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x577c0 +}, rtl8192c_rf0_vals2[] = { + 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, + 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, + 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, + 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, + 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, + 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, + 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, + 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, + 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, + 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, + 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100 +}, rtl8192c_rf0_vals3_88ru[] = { + 0xd8000, 0x90000, 0x51000, 0x12000, 0x28fb4, 0x24fa8, 0x207a4, + 0x1c798, 0x183a4, 0x14398, 0x101a4, 0x0c198, 0x080a4, 0x04098, + 0x00014 +}, rtl8192c_rf0_vals3_92ce[] = { + 0x32000, 0x71000, 0xb0000, 0xfc000, 0x287af, 0x244b7, 0x204ab, + 0x1c49f, 0x18493, 0x14297, 0x10295, 0x0c298, 0x0819c, 0x040a8, + 0x0001c +}, rtl8192c_rf0_vals3_88cu_88ce[] = { + 0x32000, 0x71000, 0xb0000, 0xfc000, 0x287b3, 0x244b7, 0x204ab, + 0x1c49f, 0x18493, 0x1429b, 0x10299, 0x0c29c, 0x081a0, 0x040ac, + 0x00020 +}, rtl8192c_rf0_vals4_92ce_88ce[] = { + 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424, + 0xcf424 +}, rtl8192c_rf0_vals4_88cu_88ru[] = { + 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f405, 0x4f405, 0x8f405, + 0xcf405 +}, rtl8192c_rf0_vals5[] = { + 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, 0x0c350, + 0x0c350, 0x80003, 0x0c350, 0x0c350, 0x44457, 0x80000, 0x30159 +}; + +static const struct rtwn_rf_prog rtl8192c_rf[] = { + /* RF chain 0 */ + /* RTL8188RU. */ + { + nitems(rtl8192c_rf0_regs0), + rtl8192c_rf0_regs0, + rtl8192c_rf0_vals0_88ru, + { R92C_COND_RTL8188RU }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8192c_rf0_regs0), + rtl8192c_rf0_regs0, + rtl8192c_rf0_vals0_88ce_88cu_92ce, + { 0 }, + NULL + } + }, + /* RTL8188RU. */ + { + nitems(rtl8192c_rf0_regs1), + rtl8192c_rf0_regs1, + rtl8192c_rf0_vals1_88ru, + { R92C_COND_RTL8188RU }, + /* RTL8188CE. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8192c_rf0_regs1), + rtl8192c_rf0_regs1, + rtl8192c_rf0_vals1_88ce, + { R92C_COND_RTL8188CE }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8192c_rf0_regs1), + rtl8192c_rf0_regs1, + rtl8192c_rf0_vals1_88cu_92ce, + { 0 }, + NULL + } + } + }, + { + nitems(rtl8192c_rf0_regs2), + rtl8192c_rf0_regs2, + rtl8192c_rf0_vals2, + { 0 }, + NULL + }, + /* RTL8188RU. */ + { + nitems(rtl8192c_rf0_regs3), + rtl8192c_rf0_regs3, + rtl8192c_rf0_vals3_88ru, + { R92C_COND_RTL8188RU }, + /* RTL8192C. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8192c_rf0_regs3), + rtl8192c_rf0_regs3, + rtl8192c_rf0_vals3_92ce, + { R92C_COND_RTL8192C }, + /* Others. */ + &(struct rtwn_rf_prog){ + nitems(rtl8192c_rf0_regs3), + rtl8192c_rf0_regs3, + rtl8192c_rf0_vals3_88cu_88ce, + { 0 }, + NULL + } + } + }, + /* RTL8188CE / RTL8192C. */ + { + nitems(rtl8192c_rf0_regs4), + rtl8192c_rf0_regs4, + rtl8192c_rf0_vals4_92ce_88ce, + { R92C_COND_RTL8188CE | R92C_COND_RTL8192C }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8192c_rf0_regs4), + rtl8192c_rf0_regs4, + rtl8192c_rf0_vals4_88cu_88ru, + { 0 }, + NULL + } + }, + { + nitems(rtl8192c_rf0_regs5), + rtl8192c_rf0_regs5, + rtl8192c_rf0_vals5, + { 0 }, + NULL + }, + { 0, NULL, NULL, { 0 }, NULL }, + /* RF chain 1 (RTL8192C). */ + { + 12, /* 0x00 - 0x0f */ + rtl8192c_rf0_regs0, + rtl8192c_rf0_vals0_88ce_88cu_92ce, + { 0 }, + NULL + }, + { + nitems(rtl8192c_rf0_regs3), /* 0x12 - 0x13 */ + rtl8192c_rf0_regs3, + rtl8192c_rf0_vals3_92ce, + { 0 }, + NULL + }, + { + nitems(rtl8192c_rf0_regs4), /* 0x14 - 0x15 */ + rtl8192c_rf0_regs4, + rtl8192c_rf0_vals4_92ce_88ce, + { 0 }, + NULL + }, + { + 4, /* 0x16 */ + rtl8192c_rf0_regs5, + rtl8192c_rf0_vals5, + { 0 }, + NULL + }, + { 0, NULL, NULL, { 0 }, NULL } +}; + + +struct rtwn_r92c_txagc { + uint8_t pwr[R92C_GROUP_2G][28]; /* RTWN_RIDX_MCS(15) + 1 */ +}; + +/* + * Per RF chain/group/rate Tx gain values. + */ +static const struct rtwn_r92c_txagc rtl8192cu_txagc[] = { + { { /* Chain 0. */ + { /* Group 0. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x0c, 0x0c, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* OFDM6~54. */ + 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* MCS0~7. */ + 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02 /* MCS8~15. */ + }, + { /* Group 1. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + }, + { /* Group 2. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + } + } }, + { { /* Chain 1. */ + { /* Group 0. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + }, + { /* Group 1. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + }, + { /* Group 2. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + } + } } +}; + +static const struct rtwn_r92c_txagc rtl8188ru_txagc[] = { + { { /* Chain 0. */ + { /* Group 0. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x08, 0x08, 0x08, 0x06, 0x06, 0x04, 0x04, 0x00, /* OFDM6~54. */ + 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00, /* MCS0~7. */ + 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00 /* MCS8~15. */ + }, + { /* Group 1. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + }, + { /* Group 2. */ + 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ + } + } } +}; + +#endif /* R92C_PRIV_H */ diff --git a/sys/dev/rtwn/rtl8192c/r92c_reg.h b/sys/dev/rtwn/rtl8192c/r92c_reg.h new file mode 100644 index 000000000000..ff03d191b4e4 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_reg.h @@ -0,0 +1,855 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015 Stefan Sperling + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_REG_H +#define R92C_REG_H + +/* + * MAC registers. + */ +/* System Configuration. */ +#define R92C_SYS_ISO_CTRL 0x000 +#define R92C_SYS_FUNC_EN 0x002 +#define R92C_APS_FSMCO 0x004 +#define R92C_SYS_CLKR 0x008 +#define R92C_AFE_MISC 0x010 +#define R92C_SPS0_CTRL 0x011 +#define R92C_SPS_OCP_CFG 0x018 +#define R92C_RSV_CTRL 0x01c +#define R92C_RF_CTRL 0x01f +#define R92C_LDOA15_CTRL 0x020 +#define R92C_LDOV12D_CTRL 0x021 +#define R92C_LDOHCI12_CTRL 0x022 +#define R92C_LPLDO_CTRL 0x023 +#define R92C_AFE_XTAL_CTRL 0x024 +#define R92C_AFE_PLL_CTRL 0x028 +#define R92C_APE_PLL_CTRL_EXT 0x02c +#define R92C_MAC_PHY_CTRL R92C_APE_PLL_CTRL_EXT +#define R92C_EFUSE_CTRL 0x030 +#define R92C_EFUSE_TEST 0x034 +#define R92C_PWR_DATA 0x038 +#define R92C_CAL_TIMER 0x03c +#define R92C_ACLK_MON 0x03e +#define R92C_GPIO_MUXCFG 0x040 +#define R92C_GPIO_IO_SEL 0x042 +#define R92C_MAC_PINMUX_CFG 0x043 +#define R92C_GPIO_PIN_CTRL 0x044 +#define R92C_GPIO_IN 0x044 +#define R92C_GPIO_OUT 0x045 +#define R92C_GPIO_IOSEL 0x046 +#define R92C_GPIO_MOD 0x047 +#define R92C_GPIO_INTM 0x048 +#define R92C_LEDCFG0 0x04c +#define R92C_LEDCFG1 0x04d +#define R92C_LEDCFG2 0x04e +#define R92C_LEDCFG3 0x04f +#define R92C_FSIMR 0x050 +#define R92C_FSISR 0x054 +#define R92C_HSIMR 0x058 +#define R92C_HSISR 0x05c +#define R92C_MULTI_FUNC_CTRL 0x068 +#define R92C_MCUFWDL 0x080 +#define R92C_HMEBOX_EXT(idx) (0x088 + (idx) * 2) +#define R92C_EFUSE_ACCESS 0x0cf +#define R92C_BIST_SCAN 0x0d0 +#define R92C_BIST_RPT 0x0d4 +#define R92C_BIST_ROM_RPT 0x0d8 +#define R92C_HPON_FSM 0x0ec +#define R92C_SYS_CFG 0x0f0 +#define R92C_TYPE_ID 0x0fc +/* MAC General Configuration. */ +#define R92C_CR 0x100 +#define R92C_MSR 0x102 +#define R92C_PBP 0x104 +#define R92C_TRXDMA_CTRL 0x10c +#define R92C_TRXFF_BNDY 0x114 +#define R92C_TRXFF_STATUS 0x118 +#define R92C_RXFF_PTR 0x11c +#define R92C_HIMR 0x120 +#define R92C_HISR 0x124 +#define R92C_HIMRE 0x128 +#define R92C_HISRE 0x12c +#define R92C_CPWM 0x12f +#define R92C_FWIMR 0x130 +#define R92C_FWISR 0x134 +#define R92C_PKTBUF_DBG_CTRL 0x140 +#define R92C_PKTBUF_DBG_DATA_L 0x144 +#define R92C_PKTBUF_DBG_DATA_H 0x148 +#define R92C_TC0_CTRL(i) (0x150 + (i) * 4) +#define R92C_TCUNIT_BASE 0x164 +#define R92C_MBIST_START 0x174 +#define R92C_MBIST_DONE 0x178 +#define R92C_MBIST_FAIL 0x17c +#define R92C_C2H_EVT_MSG 0x1a0 +#define R92C_C2H_EVT_CLEAR 0x1af +#define R92C_C2H_EVT_MSG_TEST 0x1b8 +#define R92C_MCUTST_1 0x1c0 +#define R92C_FMETHR 0x1c8 +#define R92C_HMETFR 0x1cc +#define R92C_HMEBOX(idx) (0x1d0 + (idx) * 4) +#define R92C_LLT_INIT 0x1e0 +#define R92C_BB_ACCESS_CTRL 0x1e8 +#define R92C_BB_ACCESS_DATA 0x1ec +/* Tx DMA Configuration. */ +#define R92C_RQPN 0x200 +#define R92C_FIFOPAGE 0x204 +#define R92C_TDECTRL 0x208 +#define R92C_TXDMA_OFFSET_CHK 0x20c +#define R92C_TXDMA_STATUS 0x210 +#define R92C_RQPN_NPQ 0x214 +/* Rx DMA Configuration. */ +#define R92C_RXDMA_AGG_PG_TH 0x280 +#define R92C_RXPKT_NUM 0x284 +#define R92C_RXDMA_STATUS 0x288 +/* Protocol Configuration. */ +#define R92C_VOQ_INFORMATION 0x400 +#define R92C_VIQ_INFORMATION 0x404 +#define R92C_BEQ_INFORMATION 0x408 +#define R92C_BKQ_INFORMATION 0x40c +#define R92C_MGQ_INFORMATION 0x410 +#define R92C_HGQ_INFORMATION 0x414 +#define R92C_BCNQ_INFORMATION 0x418 +#define R92C_CPU_MGQ_INFORMATION 0x41c +#define R92C_FWHW_TXQ_CTRL 0x420 +#define R92C_HWSEQ_CTRL 0x423 +#define R92C_TXPKTBUF_BCNQ_BDNY 0x424 +#define R92C_TXPKTBUF_MGQ_BDNY 0x425 +#define R92C_SPEC_SIFS 0x428 +#define R92C_RL 0x42a +#define R92C_DARFRC 0x430 +#define R92C_RARFRC 0x438 +#define R92C_RRSR 0x440 +#define R92C_ARFR(i) (0x444 + (i) * 4) +#define R92C_AGGLEN_LMT 0x458 +#define R92C_AMPDU_MIN_SPACE 0x45c +#define R92C_TXPKTBUF_WMAC_LBK_BF_HD 0x45d +#define R92C_FAST_EDCA_CTRL 0x460 +#define R92C_RD_RESP_PKT_TH 0x463 +#define R92C_INIRTS_RATE_SEL 0x480 +#define R92C_INIDATA_RATE_SEL(macid) (0x484 + (macid)) +#define R92C_QUEUE_CTRL 0x4c6 +#define R92C_MAX_AGGR_NUM 0x4ca +#define R92C_BAR_MODE_CTRL 0x4cc +/* EDCA Configuration. */ +#define R92C_EDCA_VO_PARAM 0x500 +#define R92C_EDCA_VI_PARAM 0x504 +#define R92C_EDCA_BE_PARAM 0x508 +#define R92C_EDCA_BK_PARAM 0x50c +#define R92C_BCNTCFG 0x510 +#define R92C_PIFS 0x512 +#define R92C_RDG_PIFS 0x513 +#define R92C_SIFS_CCK 0x514 +#define R92C_SIFS_OFDM 0x516 +#define R92C_AGGR_BREAK_TIME 0x51a +#define R92C_SLOT 0x51b +#define R92C_TX_PTCL_CTRL 0x520 +#define R92C_TXPAUSE 0x522 +#define R92C_DIS_TXREQ_CLR 0x523 +#define R92C_RD_CTRL 0x524 +#define R92C_TBTT_PROHIBIT 0x540 +#define R92C_RD_NAV_NXT 0x544 +#define R92C_NAV_PROT_LEN 0x546 +#define R92C_BCN_CTRL(id) ((id) + 0x550) +/* WARNING: R92C_USTIME_TSF == 0x55c, not 0x551 */ +#define R92C_MBID_NUM 0x552 +#define R92C_DUAL_TSF_RST 0x553 +#define R92C_BCN_INTERVAL(id) (0x554 + (id) * 2) +#define R92C_DRVERLYINT 0x558 +#define R92C_BCNDMATIM 0x559 +#define R92C_ATIMWND 0x55a +#define R92C_USTIME_TSF 0x55c +#define R92C_BCN_MAX_ERR 0x55d +#define R92C_RXTSF_OFFSET_CCK 0x55e +#define R92C_RXTSF_OFFSET_OFDM 0x55f +#define R92C_TSFTR(i) (0x560 + (i) * 8) +#define R92C_PSTIMER 0x580 +#define R92C_TIMER0 0x584 +#define R92C_TIMER1 0x588 +#define R92C_ACMHWCTRL 0x5c0 +#define R92C_ACMRSTCTRL 0x5c1 +#define R92C_ACMAVG 0x5c2 +#define R92C_VO_ADMTIME 0x5c4 +#define R92C_VI_ADMTIME 0x5c6 +#define R92C_BE_ADMTIME 0x5c8 +#define R92C_EDCA_RANDOM_GEN 0x5cc +#define R92C_SCH_TXCMD 0x5d0 +/* WMAC Configuration. */ +#define R92C_APSD_CTRL 0x600 +#define R92C_BWOPMODE 0x603 +#define R92C_TCR 0x604 +#define R92C_RCR 0x608 +#define R92C_RX_PKT_LIMIT 0x60c +#define R92C_RX_DRVINFO_SZ 0x60f +#define R92C_MACID0 0x610 +#define R92C_BSSID0 0x618 +#define R92C_MAR 0x620 +#define R92C_USTIME_EDCA 0x638 +#define R92C_MAC_SPEC_SIFS 0x63a +#define R92C_R2T_SIFS 0x63c +#define R92C_T2T_SIFS 0x63e +#define R92C_ACKTO 0x640 +#define R92C_NAV_UPPER 0x652 +#define R92C_WMAC_TRXPTCL_CTL 0x668 +#define R92C_CAMCMD 0x670 +#define R92C_CAMWRITE 0x674 +#define R92C_CAMREAD 0x678 +#define R92C_CAMDBG 0x67c +#define R92C_SECCFG 0x680 +#define R92C_RXFLTMAP0 0x6a0 +#define R92C_RXFLTMAP1 0x6a2 +#define R92C_RXFLTMAP2 0x6a4 +#define R92C_BCN_PSR_RPT 0x6a8 +#define R92C_MACID1 0x700 +#define R92C_BSSID1 0x708 + + +#define R92C_MACID(id) ((id) == 0 ? R92C_MACID0 : R92C_MACID1) +#define R92C_BSSID(id) ((id) == 0 ? R92C_BSSID0 : R92C_BSSID1) + +/* Bits for R92C_SYS_ISO_CTRL. */ +#define R92C_SYS_ISO_CTRL_MD2PP 0x0001 +#define R92C_SYS_ISO_CTRL_UA2USB 0x0002 +#define R92C_SYS_ISO_CTRL_UD2CORE 0x0004 +#define R92C_SYS_ISO_CTRL_PA2PCIE 0x0008 +#define R92C_SYS_ISO_CTRL_PD2CORE 0x0010 +#define R92C_SYS_ISO_CTRL_IP2MAC 0x0020 +#define R92C_SYS_ISO_CTRL_DIOP 0x0040 +#define R92C_SYS_ISO_CTRL_DIOE 0x0080 +#define R92C_SYS_ISO_CTRL_EB2CORE 0x0100 +#define R92C_SYS_ISO_CTRL_DIOR 0x0200 +#define R92C_SYS_ISO_CTRL_PWC_EV25V 0x4000 +#define R92C_SYS_ISO_CTRL_PWC_EV12V 0x8000 + +/* Bits for R92C_SYS_FUNC_EN. */ +#define R92C_SYS_FUNC_EN_BBRSTB 0x0001 +#define R92C_SYS_FUNC_EN_BB_GLB_RST 0x0002 +#define R92C_SYS_FUNC_EN_USBA 0x0004 +#define R92C_SYS_FUNC_EN_UPLL 0x0008 +#define R92C_SYS_FUNC_EN_USBD 0x0010 +#define R92C_SYS_FUNC_EN_DIO_PCIE 0x0020 +#define R92C_SYS_FUNC_EN_PCIEA 0x0040 +#define R92C_SYS_FUNC_EN_PPLL 0x0080 +#define R92C_SYS_FUNC_EN_PCIED 0x0100 +#define R92C_SYS_FUNC_EN_DIOE 0x0200 +#define R92C_SYS_FUNC_EN_CPUEN 0x0400 +#define R92C_SYS_FUNC_EN_DCORE 0x0800 +#define R92C_SYS_FUNC_EN_ELDR 0x1000 +#define R92C_SYS_FUNC_EN_DIO_RF 0x2000 +#define R92C_SYS_FUNC_EN_HWPDN 0x4000 +#define R92C_SYS_FUNC_EN_MREGEN 0x8000 + +/* Bits for R92C_APS_FSMCO. */ +#define R92C_APS_FSMCO_PFM_LDALL 0x00000001 +#define R92C_APS_FSMCO_PFM_ALDN 0x00000002 +#define R92C_APS_FSMCO_PFM_LDKP 0x00000004 +#define R92C_APS_FSMCO_PFM_WOWL 0x00000008 +#define R92C_APS_FSMCO_PDN_EN 0x00000010 +#define R92C_APS_FSMCO_PDN_PL 0x00000020 +#define R92C_APS_FSMCO_APFM_ONMAC 0x00000100 +#define R92C_APS_FSMCO_APFM_OFF 0x00000200 +#define R92C_APS_FSMCO_APFM_RSM 0x00000400 +#define R92C_APS_FSMCO_AFSM_HSUS 0x00000800 +#define R92C_APS_FSMCO_AFSM_PCIE 0x00001000 +#define R92C_APS_FSMCO_APDM_MAC 0x00002000 +#define R92C_APS_FSMCO_APDM_HOST 0x00004000 +#define R92C_APS_FSMCO_APDM_HPDN 0x00008000 +#define R92C_APS_FSMCO_RDY_MACON 0x00010000 +#define R92C_APS_FSMCO_SUS_HOST 0x00020000 +#define R92C_APS_FSMCO_ROP_ALD 0x00100000 +#define R92C_APS_FSMCO_ROP_PWR 0x00200000 +#define R92C_APS_FSMCO_ROP_SPS 0x00400000 +#define R92C_APS_FSMCO_SOP_MRST 0x02000000 +#define R92C_APS_FSMCO_SOP_FUSE 0x04000000 +#define R92C_APS_FSMCO_SOP_ABG 0x08000000 +#define R92C_APS_FSMCO_SOP_AMB 0x10000000 +#define R92C_APS_FSMCO_SOP_RCK 0x20000000 +#define R92C_APS_FSMCO_SOP_A8M 0x40000000 +#define R92C_APS_FSMCO_XOP_BTCK 0x80000000 + +/* Bits for R92C_SYS_CLKR. */ +#define R92C_SYS_CLKR_ANAD16V_EN 0x00000001 +#define R92C_SYS_CLKR_ANA8M 0x00000002 +#define R92C_SYS_CLKR_MACSLP 0x00000010 +#define R92C_SYS_CLKR_LOADER_EN 0x00000020 +#define R92C_SYS_CLKR_80M_SSC_DIS 0x00000080 +#define R92C_SYS_CLKR_80M_SSC_EN_HO 0x00000100 +#define R92C_SYS_CLKR_PHY_SSC_RSTB 0x00000200 +#define R92C_SYS_CLKR_SEC_EN 0x00000400 +#define R92C_SYS_CLKR_MAC_EN 0x00000800 +#define R92C_SYS_CLKR_SYS_EN 0x00001000 +#define R92C_SYS_CLKR_RING_EN 0x00002000 + +/* Bits for R92C_RF_CTRL. */ +#define R92C_RF_CTRL_EN 0x01 +#define R92C_RF_CTRL_RSTB 0x02 +#define R92C_RF_CTRL_SDMRSTB 0x04 + +/* Bits for R92C_LDOA15_CTRL. */ +#define R92C_LDOA15_CTRL_EN 0x01 +#define R92C_LDOA15_CTRL_STBY 0x02 +#define R92C_LDOA15_CTRL_OBUF 0x04 +#define R92C_LDOA15_CTRL_REG_VOS 0x08 + +/* Bits for R92C_LDOV12D_CTRL. */ +#define R92C_LDOV12D_CTRL_LDV12_EN 0x01 + +/* Bits for R92C_LPLDO_CTRL. */ +#define R92C_LPLDO_CTRL_SLEEP 0x10 + +/* Bits for R92C_AFE_XTAL_CTRL. */ +#define R92C_AFE_XTAL_CTRL_ADDR_M 0x007ff800 +#define R92C_AFE_XTAL_CTRL_ADDR_S 11 + +/* Bits for R92C_AFE_PLL_CTRL. */ +#define R92C_AFE_PLL_CTRL_EN 0x0001 +#define R92C_AFE_PLL_CTRL_320_EN 0x0002 +#define R92C_AFE_PLL_CTRL_FREF_SEL 0x0004 +#define R92C_AFE_PLL_CTRL_EDGE_SEL 0x0008 +#define R92C_AFE_PLL_CTRL_WDOGB 0x0010 +#define R92C_AFE_PLL_CTRL_LPFEN 0x0020 + +/* Bits for R92C_EFUSE_CTRL. */ +#define R92C_EFUSE_CTRL_DATA_M 0x000000ff +#define R92C_EFUSE_CTRL_DATA_S 0 +#define R92C_EFUSE_CTRL_ADDR_M 0x0003ff00 +#define R92C_EFUSE_CTRL_ADDR_S 8 +#define R92C_EFUSE_CTRL_VALID 0x80000000 + +/* Bits for R92C_GPIO_MUXCFG. */ +#define R92C_GPIO_MUXCFG_ENBT 0x0020 + +/* Bits for R92C_LEDCFG0. */ +#define R92C_LEDCFG0_DIS 0x08 + +/* Bits for R92C_MULTI_FUNC_CTRL. */ +#define R92C_MULTI_BT_FUNC_EN 0x00040000 + +/* Bits for R92C_MCUFWDL. */ +#define R92C_MCUFWDL_EN 0x00000001 +#define R92C_MCUFWDL_RDY 0x00000002 +#define R92C_MCUFWDL_CHKSUM_RPT 0x00000004 +#define R92C_MCUFWDL_MACINI_RDY 0x00000008 +#define R92C_MCUFWDL_BBINI_RDY 0x00000010 +#define R92C_MCUFWDL_RFINI_RDY 0x00000020 +#define R92C_MCUFWDL_WINTINI_RDY 0x00000040 +#define R92C_MCUFWDL_RAM_DL_SEL 0x00000080 /* 1: RAM, 0: ROM */ +#define R92C_MCUFWDL_PAGE_M 0x00070000 +#define R92C_MCUFWDL_PAGE_S 16 +#define R92C_MCUFWDL_ROM_DLEN 0x00080000 +#define R92C_MCUFWDL_CPRST 0x00800000 + +/* Bits for R92C_EFUSE_ACCESS. */ +#define R92C_EFUSE_ACCESS_OFF 0x00 +#define R92C_EFUSE_ACCESS_ON 0x69 + +/* Bits for R92C_HPON_FSM. */ +#define R92C_HPON_FSM_CHIP_BONDING_ID_S 22 +#define R92C_HPON_FSM_CHIP_BONDING_ID_M 0x00c00000 +#define R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R 1 + +/* Bits for R92C_SYS_CFG. */ +#define R92C_SYS_CFG_XCLK_VLD 0x00000001 +#define R92C_SYS_CFG_ACLK_VLD 0x00000002 +#define R92C_SYS_CFG_UCLK_VLD 0x00000004 +#define R92C_SYS_CFG_PCLK_VLD 0x00000008 +#define R92C_SYS_CFG_PCIRSTB 0x00000010 +#define R92C_SYS_CFG_V15_VLD 0x00000020 +#define R92C_SYS_CFG_TRP_B15V_EN 0x00000080 +#define R92C_SYS_CFG_SIC_IDLE 0x00000100 +#define R92C_SYS_CFG_BD_MAC2 0x00000200 +#define R92C_SYS_CFG_BD_MAC1 0x00000400 +#define R92C_SYS_CFG_IC_MACPHY_MODE 0x00000800 +#define R92C_SYS_CFG_CHIP_VER_RTL_M 0x0000f000 +#define R92C_SYS_CFG_CHIP_VER_RTL_S 12 +#define R92C_SYS_CFG_BT_FUNC 0x00010000 +#define R92C_SYS_CFG_VENDOR_UMC 0x00080000 +#define R92C_SYS_CFG_PAD_HWPD_IDN 0x00400000 +#define R92C_SYS_CFG_TRP_VAUX_EN 0x00800000 +#define R92C_SYS_CFG_TRP_BT_EN 0x01000000 +#define R92C_SYS_CFG_BD_PKG_SEL 0x02000000 +#define R92C_SYS_CFG_BD_HCI_SEL 0x04000000 +#define R92C_SYS_CFG_TYPE_92C 0x08000000 + +/* Bits for R92C_CR. */ +#define R92C_CR_HCI_TXDMA_EN 0x0001 +#define R92C_CR_HCI_RXDMA_EN 0x0002 +#define R92C_CR_TXDMA_EN 0x0004 +#define R92C_CR_RXDMA_EN 0x0008 +#define R92C_CR_PROTOCOL_EN 0x0010 +#define R92C_CR_SCHEDULE_EN 0x0020 +#define R92C_CR_MACTXEN 0x0040 +#define R92C_CR_MACRXEN 0x0080 +#define R92C_CR_ENSWBCN 0x0100 +#define R92C_CR_ENSEC 0x0200 +#define R92C_CR_CALTMR_EN 0x0400 + +/* Bits for R92C_MSR. */ +#define R92C_MSR_NOLINK 0x00 +#define R92C_MSR_ADHOC 0x01 +#define R92C_MSR_INFRA 0x02 +#define R92C_MSR_AP 0x03 +#define R92C_MSR_MASK (R92C_MSR_AP) + +/* Bits for R92C_PBP. */ +#define R92C_PBP_PSRX_M 0x0f +#define R92C_PBP_PSRX_S 0 +#define R92C_PBP_PSTX_M 0xf0 +#define R92C_PBP_PSTX_S 4 +#define R92C_PBP_64 0 +#define R92C_PBP_128 1 +#define R92C_PBP_256 2 +#define R92C_PBP_512 3 +#define R92C_PBP_1024 4 + +/* Bits for R92C_TRXDMA_CTRL. */ +#define R92C_TRXDMA_CTRL_RXDMA_AGG_EN 0x0004 +#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_M 0x0030 +#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_S 4 +#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_M 0x00c0 +#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_S 6 +#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_M 0x0300 +#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_S 8 +#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_M 0x0c00 +#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_S 10 +#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_M 0x3000 +#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_S 12 +#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_M 0xc000 +#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_S 14 +#define R92C_TRXDMA_CTRL_QUEUE_LOW 1 +#define R92C_TRXDMA_CTRL_QUEUE_NORMAL 2 +#define R92C_TRXDMA_CTRL_QUEUE_HIGH 3 +#define R92C_TRXDMA_CTRL_QMAP_M 0xfff0 +/* Shortcuts. */ +#define R92C_TRXDMA_CTRL_QMAP_3EP 0xf5b0 +#define R92C_TRXDMA_CTRL_QMAP_HQ_LQ 0xf5f0 +#define R92C_TRXDMA_CTRL_QMAP_HQ_NQ 0xfaf0 +#define R92C_TRXDMA_CTRL_QMAP_LQ 0x5550 +#define R92C_TRXDMA_CTRL_QMAP_NQ 0xaaa0 +#define R92C_TRXDMA_CTRL_QMAP_HQ 0xfff0 + +/* Bits for R92C_C2H_EVT_CLEAR. */ +#define R92C_C2H_EVT_HOST_CLOSE 0x00 +#define R92C_C2H_EVT_FW_CLOSE 0xff + +/* Bits for R92C_LLT_INIT. */ +#define R92C_LLT_INIT_DATA_M 0x000000ff +#define R92C_LLT_INIT_DATA_S 0 +#define R92C_LLT_INIT_ADDR_M 0x0000ff00 +#define R92C_LLT_INIT_ADDR_S 8 +#define R92C_LLT_INIT_OP_M 0xc0000000 +#define R92C_LLT_INIT_OP_S 30 +#define R92C_LLT_INIT_OP_NO_ACTIVE 0 +#define R92C_LLT_INIT_OP_WRITE 1 + +/* Bits for R92C_RQPN. */ +#define R92C_RQPN_HPQ_M 0x000000ff +#define R92C_RQPN_HPQ_S 0 +#define R92C_RQPN_LPQ_M 0x0000ff00 +#define R92C_RQPN_LPQ_S 8 +#define R92C_RQPN_PUBQ_M 0x00ff0000 +#define R92C_RQPN_PUBQ_S 16 +#define R92C_RQPN_LD 0x80000000 + +/* Bits for R92C_TDECTRL. */ +#define R92C_TDECTRL_BLK_DESC_NUM_M 0x000000f0 +#define R92C_TDECTRL_BLK_DESC_NUM_S 4 +#define R92C_TDECTRL_BCN_VALID 0x00010000 + +/* Bits for R92C_TXDMA_OFFSET_CHK. */ +#define R92C_TXDMA_OFFSET_DROP_DATA_EN 0x00000200 + +/* Bits for R92C_FWHW_TXQ_CTRL. */ +#define R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW 0x80 +#define R92C_FWHW_TXQ_CTRL_REAL_BEACON 0x400000 + +/* Bits for R92C_SPEC_SIFS. */ +#define R92C_SPEC_SIFS_CCK_M 0x00ff +#define R92C_SPEC_SIFS_CCK_S 0 +#define R92C_SPEC_SIFS_OFDM_M 0xff00 +#define R92C_SPEC_SIFS_OFDM_S 8 + +/* Bits for R92C_RL. */ +#define R92C_RL_LRL_M 0x003f +#define R92C_RL_LRL_S 0 +#define R92C_RL_SRL_M 0x3f00 +#define R92C_RL_SRL_S 8 + +/* Size of R92C_DARFRC. */ +#define R92C_DARFRC_SIZE 8 + +/* Bits for R92C_RRSR. */ +#define R92C_RRSR_RATE_BITMAP_M 0x000fffff +#define R92C_RRSR_RATE_BITMAP_S 0 +#define R92C_RRSR_RATE_CCK_ONLY_1M 0xffff1 +#define R92C_RRSR_RATE_ALL 0xfffff +#define R92C_RRSR_RSC_LOWSUBCHNL 0x00200000 +#define R92C_RRSR_RSC_UPSUBCHNL 0x00400000 +#define R92C_RRSR_SHORT 0x00800000 + +/* Bits for R92C_EDCA_XX_PARAM. */ +#define R92C_EDCA_PARAM_AIFS_M 0x000000ff +#define R92C_EDCA_PARAM_AIFS_S 0 +#define R92C_EDCA_PARAM_ECWMIN_M 0x00000f00 +#define R92C_EDCA_PARAM_ECWMIN_S 8 +#define R92C_EDCA_PARAM_ECWMAX_M 0x0000f000 +#define R92C_EDCA_PARAM_ECWMAX_S 12 +#define R92C_EDCA_PARAM_TXOP_M 0xffff0000 +#define R92C_EDCA_PARAM_TXOP_S 16 + +/* Bits for R92C_HWSEQ_CTRL / R92C_TXPAUSE. */ +#define R92C_TX_QUEUE_VO 0x01 +#define R92C_TX_QUEUE_VI 0x02 +#define R92C_TX_QUEUE_BE 0x04 +#define R92C_TX_QUEUE_BK 0x08 +#define R92C_TX_QUEUE_MGT 0x10 +#define R92C_TX_QUEUE_HIGH 0x20 +#define R92C_TX_QUEUE_BCN 0x40 + +/* Shortcuts. */ +#define R92C_TX_QUEUE_AC \ + (R92C_TX_QUEUE_VO | R92C_TX_QUEUE_VI | \ + R92C_TX_QUEUE_BE | R92C_TX_QUEUE_BK) + +#define R92C_TX_QUEUE_ALL \ + (R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT | \ + R92C_TX_QUEUE_HIGH | R92C_TX_QUEUE_BCN | 0x80) /* XXX */ + +/* Bits for R92C_BCN_CTRL. */ +#define R92C_BCN_CTRL_EN_MBSSID 0x02 +#define R92C_BCN_CTRL_TXBCN_RPT 0x04 +#define R92C_BCN_CTRL_EN_BCN 0x08 +#define R92C_BCN_CTRL_DIS_TSF_UDT0 0x10 + +/* Bits for R92C_DUAL_TSF_RST. */ +#define R92C_DUAL_TSF_RESET(id) (0x01 << (id)) +#define R92C_DUAL_TSF_RST_TXOK 0x20 + +/* Bits for R92C_ACMHWCTRL. */ +#define R92C_ACMHWCTRL_EN 0x01 +#define R92C_ACMHWCTRL_BE 0x02 +#define R92C_ACMHWCTRL_VI 0x04 +#define R92C_ACMHWCTRL_VO 0x08 +#define R92C_ACMHWCTRL_ACM_MASK 0x0f + +/* Bits for R92C_APSD_CTRL. */ +#define R92C_APSD_CTRL_OFF 0x40 +#define R92C_APSD_CTRL_OFF_STATUS 0x80 + +/* Bits for R92C_BWOPMODE. */ +#define R92C_BWOPMODE_11J 0x01 +#define R92C_BWOPMODE_5G 0x02 +#define R92C_BWOPMODE_20MHZ 0x04 + +/* Bits for R92C_TCR. */ +#define R92C_TCR_TSFRST 0x00000001 +#define R92C_TCR_DIS_GCLK 0x00000002 +#define R92C_TCR_PAD_SEL 0x00000004 +#define R92C_TCR_PWR_ST 0x00000040 +#define R92C_TCR_PWRBIT_OW_EN 0x00000080 +#define R92C_TCR_ACRC 0x00000100 +#define R92C_TCR_CFENDFORM 0x00000200 +#define R92C_TCR_ICV 0x00000400 + +/* Bits for R92C_RCR. */ +#define R92C_RCR_AAP 0x00000001 +#define R92C_RCR_APM 0x00000002 +#define R92C_RCR_AM 0x00000004 +#define R92C_RCR_AB 0x00000008 +#define R92C_RCR_ADD3 0x00000010 +#define R92C_RCR_APWRMGT 0x00000020 +#define R92C_RCR_CBSSID_DATA 0x00000040 +#define R92C_RCR_CBSSID_BCN 0x00000080 +#define R92C_RCR_ACRC32 0x00000100 +#define R92C_RCR_AICV 0x00000200 +#define R92C_RCR_ADF 0x00000800 +#define R92C_RCR_ACF 0x00001000 +#define R92C_RCR_AMF 0x00002000 +#define R92C_RCR_HTC_LOC_CTRL 0x00004000 +#define R92C_RCR_MFBEN 0x00400000 +#define R92C_RCR_LSIGEN 0x00800000 +#define R92C_RCR_ENMBID 0x01000000 +#define R92C_RCR_APP_BA_SSN 0x08000000 +#define R92C_RCR_APP_PHYSTS 0x10000000 +#define R92C_RCR_APP_ICV 0x20000000 +#define R92C_RCR_APP_MIC 0x40000000 +#define R92C_RCR_APPFCS 0x80000000 + +/* Bits for R92C_RX_DRVINFO_SZ. */ +#define R92C_RX_DRVINFO_SZ_DEF 4 /* XXX other values will not work */ + +/* Bits for R92C_WMAC_TRXPTCL_CTL. */ +#define R92C_WMAC_TRXPTCL_SHPRE 0x00020000 + +/* Bits for R92C_CAMCMD. */ +#define R92C_CAMCMD_ADDR_M 0x0000ffff +#define R92C_CAMCMD_ADDR_S 0 +#define R92C_CAMCMD_WRITE 0x00010000 +#define R92C_CAMCMD_CLR 0x40000000 +#define R92C_CAMCMD_POLLING 0x80000000 + + +/* + * CAM entries. + */ +#define R92C_CAM_CTL0(entry) ((entry) * 8 + 0) +#define R92C_CAM_CTL1(entry) ((entry) * 8 + 1) +#define R92C_CAM_KEY(entry, i) ((entry) * 8 + 2 + (i)) +#define R92C_CAM_CTL6(entry) ((entry) * 8 + 6) +#define R92C_CAM_CTL7(entry) ((entry) * 8 + 7) + +/* Bits for R92C_CAM_CTL0(i). */ +#define R92C_CAM_KEYID_M 0x00000003 +#define R92C_CAM_KEYID_S 0 +#define R92C_CAM_ALGO_M 0x0000001c +#define R92C_CAM_ALGO_S 2 +#define R92C_CAM_ALGO_NONE 0 +#define R92C_CAM_ALGO_WEP40 1 +#define R92C_CAM_ALGO_TKIP 2 +#define R92C_CAM_ALGO_AES 4 +#define R92C_CAM_ALGO_WEP104 5 +#define R92C_CAM_VALID 0x00008000 +#define R92C_CAM_MACLO_M 0xffff0000 +#define R92C_CAM_MACLO_S 16 + +/* Bits for R92C_SECCFG. */ +#define R92C_SECCFG_TXUCKEY_DEF 0x0001 +#define R92C_SECCFG_RXUCKEY_DEF 0x0002 +#define R92C_SECCFG_TXENC_ENA 0x0004 +#define R92C_SECCFG_RXDEC_ENA 0x0008 +#define R92C_SECCFG_CMP_A2 0x0010 +#define R92C_SECCFG_MC_SRCH_DIS 0x0020 +#define R92C_SECCFG_TXBCKEY_DEF 0x0040 +#define R92C_SECCFG_RXBCKEY_DEF 0x0080 + +/* Bits for R92C_RXFLTMAP*. */ +#define R92C_RXFLTMAP_SUBTYPE(subtype) \ + (1 << ((subtype) >> IEEE80211_FC0_SUBTYPE_SHIFT)) + + +/* + * Baseband registers. + */ +#define R92C_FPGA0_RFMOD 0x800 +#define R92C_FPGA0_TXINFO 0x804 +#define R92C_HSSI_PARAM1(chain) (0x820 + (chain) * 8) +#define R92C_HSSI_PARAM2(chain) (0x824 + (chain) * 8) +#define R92C_TXAGC_RATE18_06(i) (((i) == 0) ? 0xe00 : 0x830) +#define R92C_TXAGC_RATE54_24(i) (((i) == 0) ? 0xe04 : 0x834) +#define R92C_TXAGC_A_CCK1_MCS32 0xe08 +#define R92C_TXAGC_B_CCK1_55_MCS32 0x838 +#define R92C_TXAGC_B_CCK11_A_CCK2_11 0x86c +#define R92C_TXAGC_MCS03_MCS00(i) (((i) == 0) ? 0xe10 : 0x83c) +#define R92C_TXAGC_MCS07_MCS04(i) (((i) == 0) ? 0xe14 : 0x848) +#define R92C_TXAGC_MCS11_MCS08(i) (((i) == 0) ? 0xe18 : 0x84c) +#define R92C_TXAGC_MCS15_MCS12(i) (((i) == 0) ? 0xe1c : 0x868) +#define R92C_LSSI_PARAM(chain) (0x840 + (chain) * 4) +#define R92C_FPGA0_RFIFACEOE(chain) (0x860 + (chain) * 4) +#define R92C_FPGA0_RFIFACESW(idx) (0x870 + (idx) * 4) +#define R92C_FPGA0_RFPARAM(idx) (0x878 + (idx) * 4) +#define R92C_FPGA0_ANAPARAM2 0x884 +#define R92C_LSSI_READBACK(chain) (0x8a0 + (chain) * 4) +#define R92C_HSPI_READBACK(chain) (0x8b8 + (chain) * 4) +#define R92C_FPGA1_RFMOD 0x900 +#define R92C_FPGA1_TXINFO 0x90c +#define R92C_CCK0_SYSTEM 0xa00 +#define R92C_CCK0_AFESETTING 0xa04 +#define R92C_OFDM0_TRXPATHENA 0xc04 +#define R92C_OFDM0_TRMUXPAR 0xc08 +#define R92C_OFDM0_RXIQIMBALANCE(chain) (0xc14 + (chain) * 8) +#define R92C_OFDM0_ECCATHRESHOLD 0xc4c +#define R92C_OFDM0_AGCCORE1(chain) (0xc50 + (chain) * 8) +#define R92C_OFDM0_AGCPARAM1 0xc70 +#define R92C_OFDM0_AGCRSSITABLE 0xc78 +#define R92C_OFDM0_TXIQIMBALANCE(chain) (0xc80 + (chain) * 8) +#define R92C_OFDM0_TXAFE(chain) (0xc94 + (chain) * 8) +#define R92C_OFDM0_RXIQEXTANTA 0xca0 +#define R92C_OFDM1_LSTF 0xd00 + +/* Bits for R92C_FPGA[01]_RFMOD. */ +#define R92C_RFMOD_40MHZ 0x00000001 +#define R92C_RFMOD_JAPAN 0x00000002 +#define R92C_RFMOD_CCK_TXSC 0x00000030 +#define R92C_RFMOD_CCK_EN 0x01000000 +#define R92C_RFMOD_OFDM_EN 0x02000000 + +/* Bits for R92C_HSSI_PARAM1(i). */ +#define R92C_HSSI_PARAM1_PI 0x00000100 + +/* Bits for R92C_HSSI_PARAM2(i). */ +#define R92C_HSSI_PARAM2_CCK_HIPWR 0x00000200 +#define R92C_HSSI_PARAM2_ADDR_LENGTH 0x00000400 +#define R92C_HSSI_PARAM2_DATA_LENGTH 0x00000800 +#define R92C_HSSI_PARAM2_READ_ADDR_M 0x7f800000 +#define R92C_HSSI_PARAM2_READ_ADDR_S 23 +#define R92C_HSSI_PARAM2_READ_EDGE 0x80000000 + +/* Bits for R92C_TXAGC_A_CCK1_MCS32. */ +#define R92C_TXAGC_A_CCK1_M 0x0000ff00 +#define R92C_TXAGC_A_CCK1_S 8 + +/* Bits for R92C_TXAGC_B_CCK11_A_CCK2_11. */ +#define R92C_TXAGC_B_CCK11_M 0x000000ff +#define R92C_TXAGC_B_CCK11_S 0 +#define R92C_TXAGC_A_CCK2_M 0x0000ff00 +#define R92C_TXAGC_A_CCK2_S 8 +#define R92C_TXAGC_A_CCK55_M 0x00ff0000 +#define R92C_TXAGC_A_CCK55_S 16 +#define R92C_TXAGC_A_CCK11_M 0xff000000 +#define R92C_TXAGC_A_CCK11_S 24 + +/* Bits for R92C_TXAGC_B_CCK1_55_MCS32. */ +#define R92C_TXAGC_B_CCK1_M 0x0000ff00 +#define R92C_TXAGC_B_CCK1_S 8 +#define R92C_TXAGC_B_CCK2_M 0x00ff0000 +#define R92C_TXAGC_B_CCK2_S 16 +#define R92C_TXAGC_B_CCK55_M 0xff000000 +#define R92C_TXAGC_B_CCK55_S 24 + +/* Bits for R92C_TXAGC_RATE18_06(x). */ +#define R92C_TXAGC_RATE06_M 0x000000ff +#define R92C_TXAGC_RATE06_S 0 +#define R92C_TXAGC_RATE09_M 0x0000ff00 +#define R92C_TXAGC_RATE09_S 8 +#define R92C_TXAGC_RATE12_M 0x00ff0000 +#define R92C_TXAGC_RATE12_S 16 +#define R92C_TXAGC_RATE18_M 0xff000000 +#define R92C_TXAGC_RATE18_S 24 + +/* Bits for R92C_TXAGC_RATE54_24(x). */ +#define R92C_TXAGC_RATE24_M 0x000000ff +#define R92C_TXAGC_RATE24_S 0 +#define R92C_TXAGC_RATE36_M 0x0000ff00 +#define R92C_TXAGC_RATE36_S 8 +#define R92C_TXAGC_RATE48_M 0x00ff0000 +#define R92C_TXAGC_RATE48_S 16 +#define R92C_TXAGC_RATE54_M 0xff000000 +#define R92C_TXAGC_RATE54_S 24 + +/* Bits for R92C_TXAGC_MCS03_MCS00(x). */ +#define R92C_TXAGC_MCS00_M 0x000000ff +#define R92C_TXAGC_MCS00_S 0 +#define R92C_TXAGC_MCS01_M 0x0000ff00 +#define R92C_TXAGC_MCS01_S 8 +#define R92C_TXAGC_MCS02_M 0x00ff0000 +#define R92C_TXAGC_MCS02_S 16 +#define R92C_TXAGC_MCS03_M 0xff000000 +#define R92C_TXAGC_MCS03_S 24 + +/* Bits for R92C_TXAGC_MCS07_MCS04(x). */ +#define R92C_TXAGC_MCS04_M 0x000000ff +#define R92C_TXAGC_MCS04_S 0 +#define R92C_TXAGC_MCS05_M 0x0000ff00 +#define R92C_TXAGC_MCS05_S 8 +#define R92C_TXAGC_MCS06_M 0x00ff0000 +#define R92C_TXAGC_MCS06_S 16 +#define R92C_TXAGC_MCS07_M 0xff000000 +#define R92C_TXAGC_MCS07_S 24 + +/* Bits for R92C_TXAGC_MCS11_MCS08(x). */ +#define R92C_TXAGC_MCS08_M 0x000000ff +#define R92C_TXAGC_MCS08_S 0 +#define R92C_TXAGC_MCS09_M 0x0000ff00 +#define R92C_TXAGC_MCS09_S 8 +#define R92C_TXAGC_MCS10_M 0x00ff0000 +#define R92C_TXAGC_MCS10_S 16 +#define R92C_TXAGC_MCS11_M 0xff000000 +#define R92C_TXAGC_MCS11_S 24 + +/* Bits for R92C_TXAGC_MCS15_MCS12(x). */ +#define R92C_TXAGC_MCS12_M 0x000000ff +#define R92C_TXAGC_MCS12_S 0 +#define R92C_TXAGC_MCS13_M 0x0000ff00 +#define R92C_TXAGC_MCS13_S 8 +#define R92C_TXAGC_MCS14_M 0x00ff0000 +#define R92C_TXAGC_MCS14_S 16 +#define R92C_TXAGC_MCS15_M 0xff000000 +#define R92C_TXAGC_MCS15_S 24 + +/* Bits for R92C_LSSI_PARAM(i). */ +#define R92C_LSSI_PARAM_DATA_M 0x000fffff +#define R92C_LSSI_PARAM_DATA_S 0 +#define R92C_LSSI_PARAM_ADDR_M 0x03f00000 +#define R92C_LSSI_PARAM_ADDR_S 20 + +/* Bits for R92C_FPGA0_RFIFACEOE(0). */ +#define R92C_FPGA0_RFIFACEOE0_ANT_M 0x00000300 +#define R92C_FPGA0_RFIFACEOE0_ANT_S 8 + +/* Bits for R92C_FPGA0_ANAPARAM2. */ +#define R92C_FPGA0_ANAPARAM2_CBW20 0x00000400 + +/* Bits for R92C_LSSI_READBACK(i). */ +#define R92C_LSSI_READBACK_DATA_M 0x000fffff +#define R92C_LSSI_READBACK_DATA_S 0 + +/* Bits for R92C_OFDM0_AGCCORE1(i). */ +#define R92C_OFDM0_AGCCORE1_GAIN_M 0x0000007f +#define R92C_OFDM0_AGCCORE1_GAIN_S 0 + + +/* + * RF (6052) registers. + */ +#define R92C_RF_AC 0x00 +#define R92C_RF_IQADJ_G(i) (0x01 + (i)) +#define R92C_RF_POW_TRSW 0x05 +#define R92C_RF_GAIN_RX 0x06 +#define R92C_RF_GAIN_TX 0x07 +#define R92C_RF_TXM_IDAC 0x08 +#define R92C_RF_BS_IQGEN 0x0f +#define R92C_RF_MODE1 0x10 +#define R92C_RF_MODE2 0x11 +#define R92C_RF_RX_AGC_HP 0x12 +#define R92C_RF_TX_AGC 0x13 +#define R92C_RF_BIAS 0x14 +#define R92C_RF_IPA 0x15 +#define R92C_RF_POW_ABILITY 0x17 +#define R92C_RF_CHNLBW 0x18 +#define R92C_RF_RX_G1 0x1a +#define R92C_RF_RX_G2 0x1b +#define R92C_RF_RX_BB2 0x1c +#define R92C_RF_RX_BB1 0x1d +#define R92C_RF_RCK1 0x1e +#define R92C_RF_RCK2 0x1f +#define R92C_RF_TX_G(i) (0x20 + (i)) +#define R92C_RF_TX_BB1 0x23 +#define R92C_RF_T_METER 0x24 +#define R92C_RF_SYN_G(i) (0x25 + (i)) +#define R92C_RF_RCK_OS 0x30 +#define R92C_RF_TXPA_G(i) (0x31 + (i)) + +/* Bits for R92C_RF_AC. */ +#define R92C_RF_AC_MODE_M 0x70000 +#define R92C_RF_AC_MODE_S 16 +#define R92C_RF_AC_MODE_STANDBY 1 + +/* Bits for R92C_RF_CHNLBW. */ +#define R92C_RF_CHNLBW_CHNL_M 0x003ff +#define R92C_RF_CHNLBW_CHNL_S 0 +#define R92C_RF_CHNLBW_BW20 0x00400 +#define R92C_RF_CHNLBW_LCSTART 0x08000 + +/* Bits for R92C_RF_T_METER. */ +#define R92C_RF_T_METER_START 0x60 +#define R92C_RF_T_METER_VAL_M 0x1f +#define R92C_RF_T_METER_VAL_S 0 + +#endif /* R92C_REG_H */ diff --git a/sys/dev/rtwn/rtl8192c/r92c_rf.c b/sys/dev/rtwn/rtl8192c/r92c_rf.c new file mode 100644 index 000000000000..f36f035f2a9b --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_rf.c @@ -0,0 +1,93 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + + +uint32_t +r92c_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr) +{ + struct r92c_softc *rs = sc->sc_priv; + uint32_t reg[R92C_MAX_CHAINS], val; + + reg[0] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)); + if (chain != 0) + reg[chain] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(chain)); + + rtwn_bb_write(sc, R92C_HSSI_PARAM2(0), + reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE); + rtwn_delay(sc, rs->rf_read_delay[0]); + + rtwn_bb_write(sc, R92C_HSSI_PARAM2(chain), + RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) | + R92C_HSSI_PARAM2_READ_EDGE); + rtwn_delay(sc, rs->rf_read_delay[1]); + + rtwn_bb_write(sc, R92C_HSSI_PARAM2(0), + reg[0] | R92C_HSSI_PARAM2_READ_EDGE); + rtwn_delay(sc, rs->rf_read_delay[2]); + + if (rtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI) + val = rtwn_bb_read(sc, R92C_HSPI_READBACK(chain)); + else + val = rtwn_bb_read(sc, R92C_LSSI_READBACK(chain)); + return (MS(val, R92C_LSSI_READBACK_DATA)); +} + +void +r92c_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr, + uint32_t val) +{ + rtwn_bb_write(sc, R92C_LSSI_PARAM(chain), + SM(R92C_LSSI_PARAM_ADDR, addr) | + SM(R92C_LSSI_PARAM_DATA, val)); +} diff --git a/sys/dev/rtwn/rtl8192c/r92c_rom.c b/sys/dev/rtwn/rtl8192c/r92c_rom.c new file mode 100644 index 000000000000..0a427455806d --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_rom.c @@ -0,0 +1,139 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + + +static void +r92c_set_chains(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + + if (rs->chip & R92C_CHIP_92C) { + sc->ntxchains = (rs->chip & R92C_CHIP_92C_1T2R) ? 1 : 2; + sc->nrxchains = 2; + } else { + sc->ntxchains = 1; + sc->nrxchains = 1; + } +} + +void +r92c_efuse_postread(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + + /* XXX Weird but this is what the vendor driver does. */ + sc->next_rom_addr = 0x1fa; + (void) rtwn_efuse_read_next(sc, &rs->pa_setting); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "%s: PA setting=0x%x\n", __func__, + rs->pa_setting); +} + +void +r92c_parse_rom(struct rtwn_softc *sc, uint8_t *buf) +{ + struct r92c_softc *rs = sc->sc_priv; + struct rtwn_r92c_txpwr *rt = rs->rs_txpwr; + struct r92c_rom *rom = (struct r92c_rom *)buf; + int i, j; + + rs->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE); + rs->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "%s: regulatory type=%d\n", + __func__, rs->regulatory); + + /* Need to be set before postinit() (but after preinit()). */ + rtwn_r92c_set_name(sc); + r92c_set_chains(sc); + + for (j = 0; j < R92C_GROUP_2G; j++) { + for (i = 0; i < sc->ntxchains; i++) { + rt->cck_tx_pwr[i][j] = rom->cck_tx_pwr[i][j]; + rt->ht40_1s_tx_pwr[i][j] = rom->ht40_1s_tx_pwr[i][j]; + } + + rt->ht40_2s_tx_pwr_diff[0][j] = + MS(rom->ht40_2s_tx_pwr_diff[j], LOW_PART); + rt->ht20_tx_pwr_diff[0][j] = + RTWN_SIGN4TO8(MS(rom->ht20_tx_pwr_diff[j], + LOW_PART)); + rt->ofdm_tx_pwr_diff[0][j] = + MS(rom->ofdm_tx_pwr_diff[j], LOW_PART); + rt->ht40_max_pwr[0][j] = + MS(rom->ht40_max_pwr[j], LOW_PART); + rt->ht20_max_pwr[0][j] = + MS(rom->ht20_max_pwr[j], LOW_PART); + + if (sc->ntxchains > 1) { + rt->ht40_2s_tx_pwr_diff[1][j] = + MS(rom->ht40_2s_tx_pwr_diff[j], HIGH_PART); + rt->ht20_tx_pwr_diff[1][j] = + RTWN_SIGN4TO8(MS(rom->ht20_tx_pwr_diff[j], + HIGH_PART)); + rt->ofdm_tx_pwr_diff[1][j] = + MS(rom->ofdm_tx_pwr_diff[j], HIGH_PART); + rt->ht40_max_pwr[1][j] = + MS(rom->ht40_max_pwr[j], HIGH_PART); + rt->ht20_max_pwr[1][j] = + MS(rom->ht20_max_pwr[j], HIGH_PART); + } + } + + sc->thermal_meter = MS(rom->thermal_meter, R92C_ROM_THERMAL_METER); + if (sc->thermal_meter == R92C_ROM_THERMAL_METER_M) + sc->thermal_meter = 0xff; + IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr); +} diff --git a/sys/dev/rtwn/rtl8192c/r92c_rom_defs.h b/sys/dev/rtwn/rtl8192c/r92c_rom_defs.h new file mode 100644 index 000000000000..35fc42df7878 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_rom_defs.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_ROM_DEFS_H +#define R92C_ROM_DEFS_H + +#define R92C_MAX_CHAINS 2 +#define R92C_GROUP_2G 3 + +#define R92C_EFUSE_MAX_LEN 512 +#define R92C_EFUSE_MAP_LEN 128 + +/* + * Some generic rom parsing macros. + */ +#define RTWN_GET_ROM_VAR(var, def) (((var) != 0xff) ? (var) : (def)) +#define RTWN_SIGN4TO8(val) (((val) & 0x08) ? (val) | 0xf0 : (val)) + +#define LOW_PART_M 0x0f +#define LOW_PART_S 0 +#define HIGH_PART_M 0xf0 +#define HIGH_PART_S 4 + +/* Bits for rf_board_opt (rf_opt1) field. */ +#define R92C_ROM_RF1_REGULATORY_M 0x07 +#define R92C_ROM_RF1_REGULATORY_S 0 +#define R92C_ROM_RF1_BOARD_TYPE_M 0xe0 +#define R92C_ROM_RF1_BOARD_TYPE_S 5 + +/* Generic board types. */ +#define R92C_BOARD_TYPE_DONGLE 0 +#define R92C_BOARD_TYPE_HIGHPA 1 +#define R92C_BOARD_TYPE_MINICARD 2 +#define R92C_BOARD_TYPE_SOLO 3 +#define R92C_BOARD_TYPE_COMBO 4 + +/* Bits for channel_plan field. */ +#define R92C_CHANNEL_PLAN_BY_HW 0x80 + +#endif /* R92C_ROM_DEFS_H */ diff --git a/sys/dev/rtwn/rtl8192c/r92c_rom_image.h b/sys/dev/rtwn/rtl8192c/r92c_rom_image.h new file mode 100644 index 000000000000..304324e67e75 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_rom_image.h @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_ROM_IMAGE_H +#define R92C_ROM_IMAGE_H + +#include + +/* + * RTL8192CU ROM image. + */ +struct r92c_rom { + uint16_t id; /* 0x8192 */ + uint8_t reserved1[5]; + uint8_t dbg_sel; + uint16_t reserved2; + uint16_t vid; + uint16_t pid; + uint8_t usb_opt; + uint8_t ep_setting; + uint16_t reserved3; + uint8_t usb_phy; + uint8_t reserved4[3]; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + uint8_t string[61]; /* "Realtek" */ + uint8_t subcustomer_id; + uint8_t cck_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; + uint8_t ht40_1s_tx_pwr[R92C_MAX_CHAINS][R92C_GROUP_2G]; + uint8_t ht40_2s_tx_pwr_diff[R92C_GROUP_2G]; + uint8_t ht20_tx_pwr_diff[R92C_GROUP_2G]; + uint8_t ofdm_tx_pwr_diff[R92C_GROUP_2G]; + uint8_t ht40_max_pwr[R92C_GROUP_2G]; + uint8_t ht20_max_pwr[R92C_GROUP_2G]; + uint8_t xtal_calib; + uint8_t tssi[R92C_MAX_CHAINS]; + uint8_t thermal_meter; +#define R92C_ROM_THERMAL_METER_M 0x1f +#define R92C_ROM_THERMAL_METER_S 0 + + uint8_t rf_opt1; + uint8_t rf_opt2; + uint8_t rf_opt3; + uint8_t rf_opt4; + uint8_t channel_plan; +#define R92C_CHANNEL_PLAN_BY_HW 0x80 + + uint8_t version; + uint8_t customer_id; +} __packed; + +_Static_assert(sizeof(struct r92c_rom) == R92C_EFUSE_MAP_LEN, + "R92C_EFUSE_MAP_LEN must be equal to sizeof(struct r92c_rom)!"); + +#endif /* R92C_ROM_IMAGE_H */ diff --git a/sys/dev/rtwn/rtl8192c/r92c_rx.c b/sys/dev/rtwn/rtl8192c/r92c_rx.c new file mode 100644 index 000000000000..aa9da3ebc5a5 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_rx.c @@ -0,0 +1,102 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + + +int8_t +r92c_get_rssi_cck(struct rtwn_softc *sc, void *physt) +{ + static const int8_t cckoff[] = { 16, -12, -26, -46 }; + struct r92c_rx_cck *cck = (struct r92c_rx_cck *)physt; + uint8_t rpt; + int8_t rssi; + + if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR) { + rpt = (cck->agc_rpt >> 5) & 0x03; + rssi = (cck->agc_rpt & 0x1f) << 1; + } else { + rpt = (cck->agc_rpt >> 6) & 0x03; + rssi = cck->agc_rpt & 0x3e; + } + rssi = cckoff[rpt] - rssi; + + return (rssi); +} + +int8_t +r92c_get_rssi_ofdm(struct rtwn_softc *sc, void *physt) +{ + struct r92c_rx_phystat *phy = (struct r92c_rx_phystat *)physt; + int rssi; + + /* Get average RSSI. */ + rssi = ((phy->pwdb_all >> 1) & 0x7f) - 110; + + return (rssi); +} + +uint8_t +r92c_rx_radiotap_flags(const void *buf) +{ + const struct r92c_rx_stat *stat = buf; + uint8_t flags, rate; + + if (!(stat->rxdw3 & htole32(R92C_RXDW3_SPLCP))) + return (0); + + rate = MS(le32toh(stat->rxdw3), R92C_RXDW3_RATE); + if (RTWN_RATE_IS_CCK(rate)) + flags = IEEE80211_RADIOTAP_F_SHORTPRE; + else + flags = IEEE80211_RADIOTAP_F_SHORTGI; + return (flags); +} diff --git a/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h b/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h new file mode 100644 index 000000000000..7fec70bec0c8 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_rx_desc.h @@ -0,0 +1,95 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_RX_DESC_H +#define R92C_RX_DESC_H + +/* Rx MAC descriptor (common parts / USB). */ +struct r92c_rx_stat { + uint32_t rxdw0; +#define R92C_RXDW0_PKTLEN_M 0x00003fff +#define R92C_RXDW0_PKTLEN_S 0 +#define R92C_RXDW0_CRCERR 0x00004000 +#define R92C_RXDW0_ICVERR 0x00008000 +#define R92C_RXDW0_INFOSZ_M 0x000f0000 +#define R92C_RXDW0_INFOSZ_S 16 +#define R92C_RXDW0_CIPHER_M 0x00700000 +#define R92C_RXDW0_CIPHER_S 20 +#define R92C_RXDW0_QOS 0x00800000 +#define R92C_RXDW0_SHIFT_M 0x03000000 +#define R92C_RXDW0_SHIFT_S 24 +#define R92C_RXDW0_PHYST 0x04000000 +#define R92C_RXDW0_SWDEC 0x08000000 +#define R92C_RXDW0_LS 0x10000000 +#define R92C_RXDW0_FS 0x20000000 +#define R92C_RXDW0_EOR 0x40000000 +#define R92C_RXDW0_OWN 0x80000000 + + uint32_t rxdw1; +#define R92C_RXDW1_MACID_M 0x0000001f +#define R92C_RXDW1_MACID_S 0 +#define R92C_RXDW1_MC 0x40000000 +#define R92C_RXDW1_BC 0x80000000 + + uint32_t rxdw2; + uint32_t rxdw3; +#define R92C_RXDW3_RATE_M 0x0000003f +#define R92C_RXDW3_RATE_S 0 +#define R92C_RXDW3_HT 0x00000040 +#define R92C_RXDW3_SPLCP 0x00000100 +#define R92C_RXDW3_HT40 0x00000200 +#define R92C_RXDW3_HTC 0x00000400 + + uint32_t rxdw4; + uint32_t tsf_low; +} __packed __attribute__((aligned(4))); + +/* Rx PHY CCK descriptor. */ +struct r92c_rx_cck { + uint8_t adc_pwdb[4]; + uint8_t sq_rpt; + uint8_t agc_rpt; +} __packed; + +/* Rx PHY descriptor. */ +struct r92c_rx_phystat { + uint8_t trsw_gain[4]; + uint8_t pwdb_all; + uint8_t cfosho[4]; + uint8_t cfotail[4]; + uint8_t rxevm[2]; + uint8_t rxsnr[4]; + uint8_t pdsnr[2]; + uint8_t csi_current[2]; + uint8_t csi_target[2]; + uint8_t sigevm; + uint8_t max_ex_pwr; + uint8_t phy_byte28; +#define R92C_PHY_BYTE28_ANTSEL 0x01 +#define R92C_PHY_BYTE28_ANTSEL_B 0x02 +#define R92C_PHY_BYTE28_ANT_TRAIN_EN 0x04 +#define R92C_PHY_BYTE28_IDLE_LONG 0x08 +#define R92C_PHY_BYTE28_RXSC_M 0x30 +#define R92C_PHY_BYTE28_RXSC_S 4 +#define R92C_PHY_BYTE28_SGI_EN 0x40 +#define R92C_PHY_BYTE28_EX_INTF_FLG 0x80 +} __packed; + +#endif /* R92C_RX_DESC_H */ diff --git a/sys/dev/rtwn/rtl8192c/r92c_tx.c b/sys/dev/rtwn/rtl8192c/r92c_tx.c new file mode 100644 index 000000000000..138bf196e253 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_tx.c @@ -0,0 +1,436 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + + +static int +r92c_tx_get_sco(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + if (IEEE80211_IS_CHAN_HT40U(c)) + return (R92C_TXDW4_SCO_SCA); + else + return (R92C_TXDW4_SCO_SCB); +} + +static void +r92c_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + if (ni->ni_chan != IEEE80211_CHAN_ANYC && + IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { + int extc_offset; + + extc_offset = r92c_tx_get_sco(sc, ni->ni_chan); + txd->txdw4 |= htole32(R92C_TXDW4_DATA_BW40); + txd->txdw4 |= htole32(SM(R92C_TXDW4_DATA_SCO, extc_offset)); + } +} + +static void +r92c_tx_protection(struct rtwn_softc *sc, struct r92c_tx_desc *txd, + enum ieee80211_protmode mode, uint8_t ridx) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint8_t rate; + + switch (mode) { + case IEEE80211_PROT_CTSONLY: + txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF); + break; + case IEEE80211_PROT_RTSCTS: + txd->txdw4 |= htole32(R92C_TXDW4_RTSEN); + break; + default: + break; + } + + if (mode == IEEE80211_PROT_CTSONLY || + mode == IEEE80211_PROT_RTSCTS) { + if (ridx >= RTWN_RIDX_MCS(0)) + rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); + else + rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); + ridx = rate2ridx(rate); + + txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, ridx)); + /* RTS rate fallback limit (max). */ + txd->txdw5 |= htole32(SM(R92C_TXDW5_RTSRATE_FB_LMT, 0xf)); + + if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + txd->txdw4 |= htole32(R92C_TXDW4_RTS_SHORT); + } +} + +static void +r92c_tx_raid(struct rtwn_softc *sc, struct r92c_tx_desc *txd, + struct ieee80211_node *ni, int ismcast) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_channel *chan; + enum ieee80211_phymode mode; + uint8_t raid; + + chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? + ni->ni_chan : ic->ic_curchan; + mode = ieee80211_chan2mode(chan); + + /* NB: group addressed frames are done at 11bg rates for now */ + if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) { + switch (mode) { + case IEEE80211_MODE_11B: + case IEEE80211_MODE_11G: + break; + case IEEE80211_MODE_11NG: + mode = IEEE80211_MODE_11G; + break; + default: + device_printf(sc->sc_dev, "unknown mode(1) %d!\n", + ic->ic_curmode); + return; + } + } + + switch (mode) { + case IEEE80211_MODE_11B: + raid = R92C_RAID_11B; + break; + case IEEE80211_MODE_11G: + if (vap->iv_flags & IEEE80211_F_PUREG) + raid = R92C_RAID_11G; + else + raid = R92C_RAID_11BG; + break; + case IEEE80211_MODE_11NG: + if (vap->iv_flags_ht & IEEE80211_FHT_PUREN) + raid = R92C_RAID_11N; + else + raid = R92C_RAID_11BGN; + break; + default: + device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode); + return; + } + + txd->txdw1 |= htole32(SM(R92C_TXDW1_RAID, raid)); +} + +/* XXX move to device-independent layer */ +static void +r92c_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + struct ieee80211vap *vap = ni->ni_vap; + + if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) && /* HT20 */ + (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)) + txd->txdw5 |= htole32(R92C_TXDW5_SGI); + else if (ni->ni_chan != IEEE80211_CHAN_ANYC && /* HT40 */ + IEEE80211_IS_CHAN_HT40(ni->ni_chan) && + (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) && + (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)) + txd->txdw5 |= htole32(R92C_TXDW5_SGI); +} + +void +r92c_tx_enable_ampdu(void *buf, int enable) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + if (enable) + txd->txdw1 |= htole32(R92C_TXDW1_AGGEN); + else + txd->txdw1 |= htole32(R92C_TXDW1_AGGBK); +} + +void +r92c_tx_setup_hwseq(void *buf) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); +} + +void +r92c_tx_setup_macid(void *buf, int id) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, id)); +} + +void +r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, void *buf, uint8_t ridx, int maxretry) +{ +#ifndef RTWN_WITHOUT_UCODE + struct r92c_softc *rs = sc->sc_priv; +#endif + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211_frame *wh; + struct r92c_tx_desc *txd; + enum ieee80211_protmode prot; + uint8_t type, tid, qos, qsel; + int hasqos, ismcast, macid; + + wh = mtod(m, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + hasqos = IEEE80211_QOS_HAS_SEQ(wh); + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + + /* Select TX ring for this frame. */ + if (hasqos) { + qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; + tid = qos & IEEE80211_QOS_TID; + } else { + qos = 0; + tid = 0; + } + + /* Fill Tx descriptor. */ + txd = (struct r92c_tx_desc *)buf; + txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; + if (ismcast) + txd->flags0 |= R92C_FLAGS0_BMCAST; + + if (!ismcast) { + /* Unicast frame, check if an ACK is expected. */ + if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != + IEEE80211_QOS_ACKPOLICY_NOACK) { + txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); + txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, + maxretry)); + } + + struct rtwn_node *un = RTWN_NODE(ni); + macid = un->id; + + if (type == IEEE80211_FC0_TYPE_DATA) { + qsel = tid % RTWN_MAX_TID; + + rtwn_r92c_tx_enable_ampdu(sc, buf, + (m->m_flags & M_AMPDU_MPDU) != 0); + if (m->m_flags & M_AMPDU_MPDU) { + txd->txdw2 |= htole32(SM(R92C_TXDW2_AMPDU_DEN, + vap->iv_ampdu_density)); + txd->txdw6 |= htole32(SM(R92C_TXDW6_MAX_AGG, + 0x1f)); /* XXX */ + } + if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { + txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT); + sc->sc_tx_n_active++; +#ifndef RTWN_WITHOUT_UCODE + rs->rs_c2h_pending++; +#endif + } + + if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + txd->txdw4 |= htole32(R92C_TXDW4_DATA_SHPRE); + + prot = IEEE80211_PROT_NONE; + if (ridx >= RTWN_RIDX_MCS(0)) { + r92c_tx_set_ht40(sc, txd, ni); + r92c_tx_set_sgi(sc, txd, ni); + prot = ic->ic_htprotmode; + } else if (ic->ic_flags & IEEE80211_F_USEPROT) + prot = ic->ic_protmode; + + /* XXX fix last comparison for A-MSDU (in net80211) */ + /* XXX A-MPDU? */ + if (m->m_pkthdr.len + IEEE80211_CRC_LEN > + vap->iv_rtsthreshold && + vap->iv_rtsthreshold != IEEE80211_RTS_MAX) + prot = IEEE80211_PROT_RTSCTS; + + /* NB: checks for ht40 / short bits (set above). */ + if (prot != IEEE80211_PROT_NONE) + r92c_tx_protection(sc, txd, prot, ridx); + } else /* IEEE80211_FC0_TYPE_MGT */ + qsel = R92C_TXDW1_QSEL_MGNT; + } else { + macid = RTWN_MACID_BC; + qsel = R92C_TXDW1_QSEL_MGNT; + } + + txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, qsel)); + + rtwn_r92c_tx_setup_macid(sc, txd, macid); + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); + /* Data rate fallback limit (max). */ + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); + txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); + r92c_tx_raid(sc, txd, ni, ismcast); + + /* Force this rate if needed. */ + if (sc->sc_ratectl != RTWN_RATECTL_FW) + txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); + + if (!hasqos) { + /* Use HW sequence numbering for non-QoS frames. */ + rtwn_r92c_tx_setup_hwseq(sc, txd); + txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id)); + } else { + uint16_t seqno; + + if (m->m_flags & M_AMPDU_MPDU) { + seqno = ni->ni_txseqs[tid]; + /* NB: clear Fragment Number field. */ + *(uint16_t *)wh->i_seq = 0; + ni->ni_txseqs[tid]++; + } else + seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE; + + /* Set sequence number. */ + txd->txdseq = htole16(seqno); + } +} + +void +r92c_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211_frame *wh; + struct r92c_tx_desc *txd; + uint8_t ridx; + int ismcast; + + /* XXX TODO: 11n checks, matching r92c_fill_tx_desc() */ + + wh = mtod(m, struct ieee80211_frame *); + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + ridx = rate2ridx(params->ibp_rate0); + + /* Fill Tx descriptor. */ + txd = (struct r92c_tx_desc *)buf; + txd->flags0 |= R92C_FLAGS0_LSG | R92C_FLAGS0_FSG; + if (ismcast) + txd->flags0 |= R92C_FLAGS0_BMCAST; + + if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { + txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); + txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, + params->ibp_try0)); + } + if (params->ibp_flags & IEEE80211_BPF_RTS) + r92c_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); + if (params->ibp_flags & IEEE80211_BPF_CTS) + r92c_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); + + rtwn_r92c_tx_setup_macid(sc, txd, RTWN_MACID_BC); + txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); + + /* Set TX rate index. */ + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); + txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE_FB_LMT, 0x1f)); + txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, uvp->id)); + txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); + r92c_tx_raid(sc, txd, ni, ismcast); + + if (!IEEE80211_QOS_HAS_SEQ(wh)) { + /* Use HW sequence numbering for non-QoS frames. */ + rtwn_r92c_tx_setup_hwseq(sc, txd); + txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, uvp->id)); + } else { + /* Set sequence number. */ + txd->txdseq |= htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE); + } +} + +void +r92c_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b, + int qos, int id) +{ + struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; + + txd->flags0 = R92C_FLAGS0_FSG | R92C_FLAGS0_LSG | R92C_FLAGS0_OWN; + txd->txdw1 = htole32( + SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); + + txd->txdw4 = htole32(R92C_TXDW4_DRVRATE); + txd->txdw4 |= htole32(SM(R92C_TXDW4_PORT_ID, id)); + if (is11b) { + txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, + RTWN_RIDX_CCK1)); + } else { + txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, + RTWN_RIDX_OFDM6)); + } + + if (!qos) { + rtwn_r92c_tx_setup_hwseq(sc, txd); + txd->txdw4 |= htole32(SM(R92C_TXDW4_SEQ_SEL, id)); + } +} + +uint8_t +r92c_tx_radiotap_flags(const void *buf) +{ + const struct r92c_tx_desc *txd = buf; + uint8_t flags; + + flags = 0; + if (txd->txdw4 & htole32(R92C_TXDW4_DATA_SHPRE)) + flags |= IEEE80211_RADIOTAP_F_SHORTPRE; + if (txd->txdw5 & htole32(R92C_TXDW5_SGI)) + flags |= IEEE80211_RADIOTAP_F_SHORTGI; + return (flags); +} diff --git a/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h b/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h new file mode 100644 index 000000000000..037ac0e2066f --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_tx_desc.h @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_TX_DESC_H +#define R92C_TX_DESC_H + +/* Tx MAC descriptor (common part). */ +struct r92c_tx_desc { + uint16_t pktlen; + uint8_t offset; + uint8_t flags0; +#define R92C_FLAGS0_BMCAST 0x01 +#define R92C_FLAGS0_LSG 0x04 +#define R92C_FLAGS0_FSG 0x08 +#define R92C_FLAGS0_OWN 0x80 + + uint32_t txdw1; +#define R92C_TXDW1_MACID_M 0x0000001f +#define R92C_TXDW1_MACID_S 0 +#define R92C_TXDW1_AGGEN 0x00000020 +#define R92C_TXDW1_AGGBK 0x00000040 + +#define R92C_TXDW1_QSEL_M 0x00001f00 +#define R92C_TXDW1_QSEL_S 8 + +#define R92C_TXDW1_QSEL_BE 0x00 /* or 0x03 */ +#define R92C_TXDW1_QSEL_BK 0x01 /* or 0x02 */ +#define R92C_TXDW1_QSEL_VI 0x04 /* or 0x05 */ +#define R92C_TXDW1_QSEL_VO 0x06 /* or 0x07 */ +#define RTWN_MAX_TID 8 + +#define R92C_TXDW1_QSEL_BEACON 0x10 +#define R92C_TXDW1_QSEL_MGNT 0x12 + +#define R92C_TXDW1_RAID_M 0x000f0000 +#define R92C_TXDW1_RAID_S 16 +#define R92C_TXDW1_CIPHER_M 0x00c00000 +#define R92C_TXDW1_CIPHER_S 22 +#define R92C_TXDW1_CIPHER_NONE 0 +#define R92C_TXDW1_CIPHER_RC4 1 +#define R92C_TXDW1_CIPHER_AES 3 +#define R92C_TXDW1_PKTOFF_M 0x7c000000 +#define R92C_TXDW1_PKTOFF_S 26 + + uint32_t txdw2; +#define R92C_TXDW2_CCX_RPT 0x00080000 +#define R92C_TXDW2_AMPDU_DEN_M 0x00700000 +#define R92C_TXDW2_AMPDU_DEN_S 20 + + uint16_t txdw3; + uint16_t txdseq; + + uint32_t txdw4; +#define R92C_TXDW4_RTSRATE_M 0x0000003f +#define R92C_TXDW4_RTSRATE_S 0 +#define R92C_TXDW4_SEQ_SEL_M 0x00000040 +#define R92C_TXDW4_SEQ_SEL_S 6 +#define R92C_TXDW4_HWSEQ_EN 0x00000080 +#define R92C_TXDW4_DRVRATE 0x00000100 +#define R92C_TXDW4_CTS2SELF 0x00000800 +#define R92C_TXDW4_RTSEN 0x00001000 +#define R92C_TXDW4_HWRTSEN 0x00002000 +#define R92C_TXDW4_PORT_ID_M 0x00004000 +#define R92C_TXDW4_PORT_ID_S 14 +#define R92C_TXDW4_DATA_SCO_M 0x00300000 +#define R92C_TXDW4_DATA_SCO_S 20 +#define R92C_TXDW4_SCO_SCA 1 +#define R92C_TXDW4_SCO_SCB 2 +#define R92C_TXDW4_DATA_SHPRE 0x01000000 +#define R92C_TXDW4_DATA_BW40 0x02000000 +#define R92C_TXDW4_RTS_SHORT 0x04000000 +#define R92C_TXDW4_RTS_BW40 0x08000000 +#define R92C_TXDW4_RTS_SCO_M 0x30000000 +#define R92C_TXDW4_RTS_SCO_S 28 + + uint32_t txdw5; +#define R92C_TXDW5_DATARATE_M 0x0000003f +#define R92C_TXDW5_DATARATE_S 0 +#define R92C_TXDW5_SGI 0x00000040 +#define R92C_TXDW5_DATARATE_FB_LMT_M 0x00001f00 +#define R92C_TXDW5_DATARATE_FB_LMT_S 8 +#define R92C_TXDW5_RTSRATE_FB_LMT_M 0x0001e000 +#define R92C_TXDW5_RTSRATE_FB_LMT_S 13 +#define R92C_TXDW5_RTY_LMT_ENA 0x00020000 +#define R92C_TXDW5_RTY_LMT_M 0x00fc0000 +#define R92C_TXDW5_RTY_LMT_S 18 +#define R92C_TXDW5_AGGNUM_M 0xff000000 +#define R92C_TXDW5_AGGNUM_S 24 + + uint32_t txdw6; +#define R92C_TXDW6_MAX_AGG_M 0x0000f800 +#define R92C_TXDW6_MAX_AGG_S 11 +} __packed __attribute__((aligned(4))); + + +/* Rate adaptation modes. */ +#define R92C_RAID_11BGN 0 +#define R92C_RAID_11GN 1 +#define R92C_RAID_11BN 2 +#define R92C_RAID_11N 3 +#define R92C_RAID_11BG 4 +#define R92C_RAID_11G 5 /* "pure" 11g */ +#define R92C_RAID_11B 6 + +#endif /* R92C_TX_DESC_H */ diff --git a/sys/dev/rtwn/rtl8192c/r92c_var.h b/sys/dev/rtwn/rtl8192c/r92c_var.h new file mode 100644 index 000000000000..c48318d9feb3 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/r92c_var.h @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92C_VAR_H +#define R92C_VAR_H + +#include + +struct r92c_softc { + uint8_t rs_flags; +#define R92C_FLAG_ASSOCIATED 0x01 + + uint8_t chip; +#define R92C_CHIP_92C 0x01 +#define R92C_CHIP_92C_1T2R 0x02 +#define R92C_CHIP_UMC_A_CUT 0x04 + +#ifndef RTWN_WITHOUT_UCODE + struct callout rs_c2h_report; + int rs_c2h_timeout; + int rs_c2h_pending; + int rs_c2h_paused; +#endif +#define R92C_TX_PAUSED_THRESHOLD 20 + + void *rs_txpwr; + const void *rs_txagc; + + uint8_t board_type; + uint8_t regulatory; + uint8_t crystalcap; + uint8_t pa_setting; + + void (*rs_scan_start)(struct ieee80211com *); + void (*rs_scan_end)(struct ieee80211com *); + + void (*rs_set_bw20)(struct rtwn_softc *, uint8_t); + void (*rs_get_txpower)(struct rtwn_softc *, int, + struct ieee80211_channel *, uint16_t[]); + void (*rs_set_gain)(struct rtwn_softc *, uint8_t); + void (*rs_tx_enable_ampdu)(void *, int); + void (*rs_tx_setup_hwseq)(void *); + void (*rs_tx_setup_macid)(void *, int); + void (*rs_set_name)(struct rtwn_softc *); + + int rf_read_delay[3]; + uint32_t rf_chnlbw[R92C_MAX_CHAINS]; +}; +#define R92C_SOFTC(_sc) ((struct r92c_softc *)((_sc)->sc_priv)) + +#define rtwn_r92c_set_bw20(_sc, _chan) \ + ((R92C_SOFTC(_sc)->rs_set_bw20)((_sc), (_chan))) +#define rtwn_r92c_get_txpower(_sc, _chain, _c, _power) \ + ((R92C_SOFTC(_sc)->rs_get_txpower)((_sc), (_chain), (_c), (_power))) +#define rtwn_r92c_set_gain(_sc, _gain) \ + ((R92C_SOFTC(_sc)->rs_set_gain)((_sc), (_gain))) +#define rtwn_r92c_tx_enable_ampdu(_sc, _buf, _enable) \ + ((R92C_SOFTC(_sc)->rs_tx_enable_ampdu)((_buf), (_enable))) +#define rtwn_r92c_tx_setup_hwseq(_sc, _buf) \ + ((R92C_SOFTC(_sc)->rs_tx_setup_hwseq)((_buf))) +#define rtwn_r92c_tx_setup_macid(_sc, _buf, _id) \ + ((R92C_SOFTC(_sc)->rs_tx_setup_macid)((_buf), (_id))) +#define rtwn_r92c_set_name(_sc) \ + ((R92C_SOFTC(_sc)->rs_set_name)((_sc))) + +#endif /* R92C_VAR_H */ diff --git a/sys/dev/rtwn/rtl8192c/usb/r92cu.h b/sys/dev/rtwn/rtl8192c/usb/r92cu.h new file mode 100644 index 000000000000..2486d7fa5933 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/usb/r92cu.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef RTL8192CU_H +#define RTL8192CU_H + +#include + + +/* + * Global definitions. + */ +#define R92CU_PUBQ_NPAGES 231 +#define R92CU_TX_PAGE_COUNT 248 + + +/* + * Function declarations. + */ +/* r92cu_init.c */ +void r92cu_init_bb(struct rtwn_softc *); +int r92cu_power_on(struct rtwn_softc *); +void r92cu_power_off(struct rtwn_softc *); +void r92cu_init_intr(struct rtwn_softc *); +void r92cu_init_tx_agg(struct rtwn_softc *); +void r92cu_init_rx_agg(struct rtwn_softc *); +void r92cu_post_init(struct rtwn_softc *); + +/* r92cu_led.c */ +void r92cu_set_led(struct rtwn_softc *, int, int); + +/* r92cu_rx.c */ +int r92cu_classify_intr(struct rtwn_softc *, void *, int); +int r92cu_align_rx(int, int); + +/* r92cu_tx.c */ +void r92cu_dump_tx_desc(struct rtwn_softc *, const void *); + +#endif /* RTL8192CU_H */ diff --git a/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c b/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c new file mode 100644 index 000000000000..e6edea7af49d --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c @@ -0,0 +1,246 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + + +static struct rtwn_r92c_txpwr r92c_txpwr; + +void r92cu_attach(struct rtwn_usb_softc *); + +static void +r92cu_postattach(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + struct ieee80211com *ic = &sc->sc_ic; + + if (!(rs->chip & R92C_CHIP_92C) && + rs->board_type == R92C_BOARD_TYPE_HIGHPA) { + sc->agc_prog = &rtl8188ru_agc[0]; + sc->agc_size = nitems(rtl8188ru_agc); + rs->rs_txagc = &rtl8188ru_txagc[0]; + } else { + sc->agc_prog = &rtl8192ce_agc[0]; + sc->agc_size = nitems(rtl8192ce_agc); + rs->rs_txagc = &rtl8192cu_txagc[0]; + } + + if ((rs->chip & (R92C_CHIP_UMC_A_CUT | R92C_CHIP_92C)) == + R92C_CHIP_UMC_A_CUT) { + sc->fwname = "rtwn-rtl8192cfwU"; + } else { + sc->fwname = "rtwn-rtl8192cfwT"; + } + sc->fwsig = 0x88c; + + rs->rs_scan_start = ic->ic_scan_start; + ic->ic_scan_start = r92c_scan_start; + rs->rs_scan_end = ic->ic_scan_end; + ic->ic_scan_end = r92c_scan_end; +} + +static void +r92cu_set_name(struct rtwn_softc *sc) +{ + struct r92c_softc *rs = sc->sc_priv; + + if (!(rs->chip & R92C_CHIP_92C)) { + if (rs->board_type == R92C_BOARD_TYPE_HIGHPA) + sc->name = "RTL8188RU"; + else if (rs->board_type == R92C_BOARD_TYPE_MINICARD) + sc->name = "RTL8188CU-VAU"; + else + sc->name = "RTL8188CUS"; + } else + sc->name = "RTL8192CU"; +} + +static void +r92cu_attach_private(struct rtwn_softc *sc) +{ + struct r92c_softc *rs; + + rs = malloc(sizeof(struct r92c_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO); + + rs->rs_txpwr = &r92c_txpwr; + + rs->rs_set_bw20 = r92c_set_bw20; + rs->rs_get_txpower = r92c_get_txpower; + rs->rs_set_gain = r92c_set_gain; + rs->rs_tx_enable_ampdu = r92c_tx_enable_ampdu; + rs->rs_tx_setup_hwseq = r92c_tx_setup_hwseq; + rs->rs_tx_setup_macid = r92c_tx_setup_macid; + rs->rs_set_name = r92cu_set_name; + +#ifndef RTWN_WITHOUT_UCODE + rs->rs_c2h_timeout = hz; + + callout_init_mtx(&rs->rs_c2h_report, &sc->sc_mtx, 0); +#endif + + rs->rf_read_delay[0] = 10; + rs->rf_read_delay[1] = 100; + rs->rf_read_delay[2] = 10; + + sc->sc_priv = rs; +} + +static void +r92cu_adj_devcaps(struct rtwn_softc *sc) +{ + /* XXX Currently broken / incomplete. */ + sc->sc_ic.ic_caps &= ~IEEE80211_C_PMGT; +} + +void +r92cu_attach(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + + /* USB part. */ + uc->uc_align_rx = r92cu_align_rx; + uc->tx_agg_desc_num = 6; + + /* Common part. */ + sc->sc_flags = RTWN_FLAG_CAM_FIXED; + + sc->sc_set_chan = r92c_set_chan; + sc->sc_fill_tx_desc = r92c_fill_tx_desc; + sc->sc_fill_tx_desc_raw = r92c_fill_tx_desc_raw; + sc->sc_fill_tx_desc_null = r92c_fill_tx_desc_null; + sc->sc_dump_tx_desc = r92cu_dump_tx_desc; + sc->sc_tx_radiotap_flags = r92c_tx_radiotap_flags; + sc->sc_rx_radiotap_flags = r92c_rx_radiotap_flags; + sc->sc_get_rssi_cck = r92c_get_rssi_cck; + sc->sc_get_rssi_ofdm = r92c_get_rssi_ofdm; + sc->sc_classify_intr = r92cu_classify_intr; + sc->sc_handle_tx_report = rtwn_nop_softc_uint8_int; + sc->sc_handle_c2h_report = rtwn_nop_softc_uint8_int; + sc->sc_check_frame = rtwn_nop_int_softc_mbuf; + sc->sc_rf_read = r92c_rf_read; + sc->sc_rf_write = r92c_rf_write; + sc->sc_check_condition = r92c_check_condition; + sc->sc_efuse_postread = r92c_efuse_postread; + sc->sc_parse_rom = r92c_parse_rom; + sc->sc_set_led = r92cu_set_led; + sc->sc_power_on = r92cu_power_on; + sc->sc_power_off = r92cu_power_off; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_fw_reset = r92c_fw_reset; + sc->sc_fw_download_enable = r92c_fw_download_enable; +#endif + sc->sc_set_page_size = r92c_set_page_size; + sc->sc_lc_calib = r92c_lc_calib; + sc->sc_iq_calib = r92c_iq_calib; /* XXX TODO */ + sc->sc_read_chipid_vendor = r92c_read_chipid_vendor; + sc->sc_adj_devcaps = r92cu_adj_devcaps; + sc->sc_vap_preattach = rtwn_nop_softc_vap; + sc->sc_postattach = r92cu_postattach; + sc->sc_detach_private = r92c_detach_private; + sc->sc_set_media_status = r92c_joinbss_rpt; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_set_rsvd_page = r92c_set_rsvd_page; + sc->sc_set_pwrmode = r92c_set_pwrmode; + sc->sc_set_rssi = r92c_set_rssi; +#endif + sc->sc_beacon_init = r92c_beacon_init; + sc->sc_beacon_enable = r92c_beacon_enable; + sc->sc_beacon_set_rate = rtwn_nop_void_int; + sc->sc_beacon_select = rtwn_nop_softc_int; + sc->sc_temp_measure = r92c_temp_measure; + sc->sc_temp_read = r92c_temp_read; + sc->sc_init_tx_agg = r92cu_init_tx_agg; + sc->sc_init_rx_agg = r92cu_init_rx_agg; + sc->sc_init_ampdu = r92c_init_ampdu; + sc->sc_init_intr = r92cu_init_intr; + sc->sc_init_edca = r92c_init_edca; + sc->sc_init_bb = r92cu_init_bb; + sc->sc_init_rf = r92c_init_rf; + sc->sc_init_antsel = r92c_init_antsel; + sc->sc_post_init = r92cu_post_init; + sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc; + + sc->mac_prog = &rtl8192cu_mac[0]; + sc->mac_size = nitems(rtl8192cu_mac); + sc->bb_prog = &rtl8192cu_bb[0]; + sc->bb_size = nitems(rtl8192cu_bb); + sc->rf_prog = &rtl8192c_rf[0]; + + sc->page_count = R92CU_TX_PAGE_COUNT; + sc->pktbuf_count = R92C_TXPKTBUF_COUNT; + + sc->ackto = 0x40; + sc->npubqpages = R92CU_PUBQ_NPAGES; + sc->page_size = R92C_TX_PAGE_SIZE; + + sc->txdesc_len = sizeof(struct r92cu_tx_desc); + sc->efuse_maxlen = R92C_EFUSE_MAX_LEN; + sc->efuse_maplen = R92C_EFUSE_MAP_LEN; + sc->rx_dma_size = R92C_RX_DMA_BUFFER_SIZE; + + sc->macid_limit = R92C_MACID_MAX + 1; + sc->cam_entry_limit = R92C_CAM_ENTRY_COUNT; + sc->fwsize_limit = R92C_MAX_FW_SIZE; + sc->temp_delta = R92C_CALIB_THRESHOLD; + + sc->bcn_status_reg[0] = R92C_TDECTRL; + sc->bcn_status_reg[1] = R92C_TDECTRL; + sc->rcr = 0; + + r92cu_attach_private(sc); +} diff --git a/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c b/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c new file mode 100644 index 000000000000..faf179e3e483 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/usb/r92cu_init.c @@ -0,0 +1,393 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +#include +#include + + +void +r92cu_init_bb(struct rtwn_softc *sc) +{ + + /* Enable BB and RF. */ + rtwn_setbits_2(sc, R92C_SYS_FUNC_EN, 0, + R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | + R92C_SYS_FUNC_EN_DIO_RF); + + rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83); + + rtwn_write_1(sc, R92C_RF_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); + rtwn_write_1(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_USBA | R92C_SYS_FUNC_EN_USBD | + R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB); + + rtwn_write_1(sc, R92C_LDOHCI12_CTRL, 0x0f); + rtwn_write_1(sc, 0x15, 0xe9); + rtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80); + + r92c_init_bb_common(sc); + + if (rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) & + R92C_HSSI_PARAM2_CCK_HIPWR) + sc->sc_flags |= RTWN_FLAG_CCK_HIPWR; +} + +int +r92cu_power_on(struct rtwn_softc *sc) +{ +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while(0) + uint32_t reg; + int ntries; + + /* Wait for autoload done bit. */ + for (ntries = 0; ntries < 5000; ntries++) { + if (rtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) { + device_printf(sc->sc_dev, + "timeout waiting for chip autoload\n"); + return (ETIMEDOUT); + } + + /* Unlock ISO/CLK/Power control register. */ + RTWN_CHK(rtwn_write_1(sc, R92C_RSV_CTRL, 0)); + + /* Move SPS into PWM mode. */ + RTWN_CHK(rtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b)); + + /* just in case if power_off() was not properly executed. */ + rtwn_delay(sc, 100); + + reg = rtwn_read_1(sc, R92C_LDOV12D_CTRL); + if (!(reg & R92C_LDOV12D_CTRL_LDV12_EN)) { + RTWN_CHK(rtwn_write_1(sc, R92C_LDOV12D_CTRL, + reg | R92C_LDOV12D_CTRL_LDV12_EN)); + + rtwn_delay(sc, 100); + + RTWN_CHK(rtwn_setbits_1(sc, R92C_SYS_ISO_CTRL, + R92C_SYS_ISO_CTRL_MD2PP, 0)); + } + + /* Auto enable WLAN. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_APFM_ONMAC, 1)); + + for (ntries = 0; ntries < 5000; ntries++) { + if (!(rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_ONMAC)) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) { + device_printf(sc->sc_dev, + "timeout waiting for MAC auto ON\n"); + return (ETIMEDOUT); + } + + /* Enable radio, GPIO and LED functions. */ + RTWN_CHK(rtwn_write_2(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS | + R92C_APS_FSMCO_PDN_EN | + R92C_APS_FSMCO_PFM_ALDN)); + + /* Release RF digital isolation. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_SYS_ISO_CTRL, + R92C_SYS_ISO_CTRL_DIOR, 0, 1)); + + /* Initialize MAC. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_APSD_CTRL, + R92C_APSD_CTRL_OFF, 0)); + for (ntries = 0; ntries < 1000; ntries++) { + if (!(rtwn_read_1(sc, R92C_APSD_CTRL) & + R92C_APSD_CTRL_OFF_STATUS)) + break; + rtwn_delay(sc, 50); + } + if (ntries == 1000) { + device_printf(sc->sc_dev, + "timeout waiting for MAC initialization\n"); + return (ETIMEDOUT); + } + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + RTWN_CHK(rtwn_setbits_2(sc, R92C_CR, 0, + R92C_CR_HCI_TXDMA_EN | R92C_CR_TXDMA_EN | + R92C_CR_HCI_RXDMA_EN | R92C_CR_RXDMA_EN | + R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN | + ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) | + R92C_CR_CALTMR_EN)); + + RTWN_CHK(rtwn_write_1(sc, 0xfe10, 0x19)); + + return (0); +#undef RTWN_CHK +} + +void +r92cu_power_off(struct rtwn_softc *sc) +{ +#ifndef RTWN_WITHOUT_UCODE + struct r92c_softc *rs = sc->sc_priv; +#endif + uint32_t reg; + int error; + + /* Deinit C2H event handler. */ +#ifndef RTWN_WITHOUT_UCODE + callout_stop(&rs->rs_c2h_report); + rs->rs_c2h_paused = 0; + rs->rs_c2h_pending = 0; + rs->rs_c2h_timeout = hz; +#endif + + /* Block all Tx queues. */ + error = rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + if (error == ENXIO) /* hardware gone */ + return; + + /* Disable RF */ + rtwn_rf_write(sc, 0, 0, 0); + + rtwn_write_1(sc, R92C_APSD_CTRL, R92C_APSD_CTRL_OFF); + + /* Reset BB state machine */ + rtwn_write_1(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_USBD | R92C_SYS_FUNC_EN_USBA | + R92C_SYS_FUNC_EN_BB_GLB_RST); + rtwn_write_1(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_USBD | R92C_SYS_FUNC_EN_USBA); + + /* + * Reset digital sequence + */ +#ifndef RTWN_WITHOUT_UCODE + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RDY) { + /* Reset MCU ready status */ + rtwn_write_1(sc, R92C_MCUFWDL, 0); + + /* If firmware in ram code, do reset */ + r92c_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN); + } +#endif + + /* Reset MAC and Enable 8051 */ + rtwn_write_1(sc, R92C_SYS_FUNC_EN + 1, + (R92C_SYS_FUNC_EN_CPUEN | + R92C_SYS_FUNC_EN_ELDR | + R92C_SYS_FUNC_EN_HWPDN) >> 8); + + /* Reset MCU ready status */ + rtwn_write_1(sc, R92C_MCUFWDL, 0); + + /* Disable MAC clock */ + rtwn_write_2(sc, R92C_SYS_CLKR, + R92C_SYS_CLKR_ANAD16V_EN | + R92C_SYS_CLKR_ANA8M | + R92C_SYS_CLKR_LOADER_EN | + R92C_SYS_CLKR_80M_SSC_DIS | + R92C_SYS_CLKR_SYS_EN | + R92C_SYS_CLKR_RING_EN | + 0x4000); + + /* Disable AFE PLL */ + rtwn_write_1(sc, R92C_AFE_PLL_CTRL, 0x80); + + /* Gated AFE DIG_CLOCK */ + rtwn_write_2(sc, R92C_AFE_XTAL_CTRL, 0x880F); + + /* Isolated digital to PON */ + rtwn_write_1(sc, R92C_SYS_ISO_CTRL, + R92C_SYS_ISO_CTRL_MD2PP | + R92C_SYS_ISO_CTRL_PA2PCIE | + R92C_SYS_ISO_CTRL_PD2CORE | + R92C_SYS_ISO_CTRL_IP2MAC | + R92C_SYS_ISO_CTRL_DIOP | + R92C_SYS_ISO_CTRL_DIOE); + + /* + * Pull GPIO PIN to balance level and LED control + */ + /* 1. Disable GPIO[7:0] */ + rtwn_write_2(sc, R92C_GPIO_IOSEL, 0x0000); + + reg = rtwn_read_4(sc, R92C_GPIO_PIN_CTRL) & ~0x0000ff00; + reg |= ((reg << 8) & 0x0000ff00) | 0x00ff0000; + rtwn_write_4(sc, R92C_GPIO_PIN_CTRL, reg); + + /* Disable GPIO[10:8] */ + rtwn_write_1(sc, R92C_MAC_PINMUX_CFG, 0x00); + + reg = rtwn_read_2(sc, R92C_GPIO_IO_SEL) & ~0x00f0; + reg |= (((reg & 0x000f) << 4) | 0x0780); + rtwn_write_2(sc, R92C_GPIO_IO_SEL, reg); + + /* Disable LED0 & 1 */ + rtwn_write_2(sc, R92C_LEDCFG0, 0x8080); + + /* + * Reset digital sequence + */ + /* Disable ELDR clock */ + rtwn_write_2(sc, R92C_SYS_CLKR, + R92C_SYS_CLKR_ANAD16V_EN | + R92C_SYS_CLKR_ANA8M | + R92C_SYS_CLKR_LOADER_EN | + R92C_SYS_CLKR_80M_SSC_DIS | + R92C_SYS_CLKR_SYS_EN | + R92C_SYS_CLKR_RING_EN | + 0x4000); + + /* Isolated ELDR to PON */ + rtwn_write_1(sc, R92C_SYS_ISO_CTRL + 1, + (R92C_SYS_ISO_CTRL_DIOR | + R92C_SYS_ISO_CTRL_PWC_EV12V) >> 8); + + /* + * Disable analog sequence + */ + /* Disable A15 power */ + rtwn_write_1(sc, R92C_LDOA15_CTRL, R92C_LDOA15_CTRL_OBUF); + /* Disable digital core power */ + rtwn_setbits_1(sc, R92C_LDOV12D_CTRL, + R92C_LDOV12D_CTRL_LDV12_EN, 0); + + /* Enter PFM mode */ + rtwn_write_1(sc, R92C_SPS0_CTRL, 0x23); + + /* Set USB suspend */ + rtwn_write_2(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_APDM_HOST | + R92C_APS_FSMCO_AFSM_HSUS | + R92C_APS_FSMCO_PFM_ALDN); + + /* Lock ISO/CLK/Power control register. */ + rtwn_write_1(sc, R92C_RSV_CTRL, 0x0E); +} + +void +r92cu_init_intr(struct rtwn_softc *sc) +{ + rtwn_write_4(sc, R92C_HISR, 0xffffffff); + rtwn_write_4(sc, R92C_HIMR, 0xffffffff); +} + +void +r92cu_init_tx_agg(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + rtwn_setbits_4(sc, R92C_TDECTRL, + R92C_TDECTRL_BLK_DESC_NUM_M, uc->tx_agg_desc_num); +} + +void +r92cu_init_rx_agg(struct rtwn_softc *sc) +{ + + /* Rx aggregation (DMA & USB). */ + rtwn_setbits_1(sc, R92C_TRXDMA_CTRL, 0, + R92C_TRXDMA_CTRL_RXDMA_AGG_EN); + rtwn_setbits_1(sc, R92C_USB_SPECIAL_OPTION, 0, + R92C_USB_SPECIAL_OPTION_AGG_EN); + + /* XXX dehardcode */ + rtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH, 48); + rtwn_write_1(sc, R92C_USB_DMA_AGG_TO, 4); + rtwn_write_1(sc, R92C_USB_AGG_TH, 8); + rtwn_write_1(sc, R92C_USB_AGG_TO, 6); +} + +void +r92cu_post_init(struct rtwn_softc *sc) +{ + + /* Perform LO and IQ calibrations. */ + r92c_iq_calib(sc); + /* Perform LC calibration. */ + r92c_lc_calib(sc); + + /* Fix USB interference issue. */ + rtwn_write_1(sc, 0xfe40, 0xe0); + rtwn_write_1(sc, 0xfe41, 0x8d); + rtwn_write_1(sc, 0xfe42, 0x80); + + r92c_pa_bias_init(sc); + + /* Fix for lower temperature. */ + rtwn_write_1(sc, 0x15, 0xe9); + +#ifndef RTWN_WITHOUT_UCODE + if (sc->sc_flags & RTWN_FW_LOADED) { + struct r92c_softc *rs = sc->sc_priv; + + if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) { + /* XXX firmware RA does not work yet */ + sc->sc_ratectl = RTWN_RATECTL_NET80211; + } else + sc->sc_ratectl = sc->sc_ratectl_sysctl; + + /* Start C2H event handling. */ + callout_reset(&rs->rs_c2h_report, rs->rs_c2h_timeout, + r92c_handle_c2h_report, sc); + } else +#endif + sc->sc_ratectl = RTWN_RATECTL_NONE; +} diff --git a/sys/dev/rtwn/rtl8192c/usb/r92cu_led.c b/sys/dev/rtwn/rtl8192c/usb/r92cu_led.c new file mode 100644 index 000000000000..724320946639 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/usb/r92cu_led.c @@ -0,0 +1,66 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include + + +void +r92cu_set_led(struct rtwn_softc *sc, int led, int on) +{ + uint8_t reg; + + if (led == RTWN_LED_LINK) { + reg = rtwn_read_1(sc, R92C_LEDCFG0) & 0x70; + if (!on) + reg |= R92C_LEDCFG0_DIS; + rtwn_write_1(sc, R92C_LEDCFG0, reg); + sc->ledlink = on; /* Save LED state. */ + } +} diff --git a/sys/dev/rtwn/rtl8192c/usb/r92cu_priv.h b/sys/dev/rtwn/rtl8192c/usb/r92cu_priv.h new file mode 100644 index 000000000000..8e3203f082f3 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/usb/r92cu_priv.h @@ -0,0 +1,322 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92CU_PRIV_H +#define R92CU_PRIV_H + +#include + + +/* + * MAC initialization values. + */ +static const struct rtwn_mac_prog rtl8192cu_mac[] = { + { 0x420, 0x80 }, { 0x423, 0x00 }, { 0x430, 0x00 }, { 0x431, 0x00 }, + { 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 }, { 0x435, 0x05 }, + { 0x436, 0x06 }, { 0x437, 0x07 }, { 0x438, 0x00 }, { 0x439, 0x00 }, + { 0x43a, 0x00 }, { 0x43b, 0x01 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, + { 0x43e, 0x06 }, { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 }, + { 0x442, 0x00 }, { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f }, + { 0x447, 0x00 }, { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 }, + { 0x45b, 0xb9 }, { 0x460, 0x66 }, { 0x461, 0x66 }, { 0x462, 0x08 }, + { 0x463, 0x03 }, { 0x4c8, 0xff }, { 0x4c9, 0x08 }, { 0x4cc, 0xff }, + { 0x4cd, 0xff }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, + { 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, + { 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, + { 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, + { 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, + { 0x515, 0x10 }, { 0x516, 0x0a }, { 0x517, 0x10 }, { 0x51a, 0x16 }, + { 0x524, 0x0f }, { 0x525, 0x4f }, { 0x546, 0x40 }, { 0x547, 0x00 }, + { 0x550, 0x10 }, { 0x551, 0x10 }, { 0x559, 0x02 }, { 0x55a, 0x02 }, + { 0x55d, 0xff }, { 0x605, 0x30 }, { 0x608, 0x0e }, { 0x609, 0x2a }, + { 0x652, 0x20 }, { 0x63c, 0x0a }, { 0x63d, 0x0e }, { 0x63e, 0x0a }, + { 0x63f, 0x0e }, { 0x66e, 0x05 }, { 0x700, 0x21 }, { 0x701, 0x43 }, + { 0x702, 0x65 }, { 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 }, + { 0x70a, 0x65 }, { 0x70b, 0x87 } +}; + + +/* + * Baseband initialization values. + */ +static const uint16_t rtl8192cu_bb_regs0_88ru[] = { + 0x024, 0x028, 0x040, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, + 0x818, 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, + 0x83c, 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, + 0x860, 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, + 0x884, 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, + 0x908, 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, + 0xa1c, 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04, + 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, + 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, + 0xc50, 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70 +}, rtl8192cu_bb_regs0[] = { + 0x024, 0x028, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, + 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, + 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, + 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, 0x884, + 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, 0x908, + 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, + 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04, 0xc08, + 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, 0xc2c, + 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, + 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70 +}, rtl8192cu_bb_regs1[] = { + 0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88 +}, rtl8192cu_bb_regs2[] = { + 0xc8c, 0xc90, 0xc94, 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, + 0xcb0, 0xcb4, 0xcb8, 0xcbc, 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, + 0xcd4, 0xcd8, 0xcdc, 0xce0, 0xce4, 0xce8, 0xcec, 0xd00 +}, rtl8192cu_bb_regs5_88ru[] = { + 0xe60, 0xe68, 0xe6c, 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, + 0xe88, 0xe8c, 0xed0, 0xed4, 0xed8, 0xedc, 0xee0, 0xeec, 0xee8, + 0xf14, 0xf4c, 0xf00 +}; + +static const uint32_t rtl8192cu_bb_vals0_88cu[] = { + 0x0011800d, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00, + 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, + 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a, + 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200, + 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070, + 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe, + 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, + 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, + 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, + 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, + 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, + 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, + 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d +}, rtl8192cu_bb_vals0_88ru[] = { + 0x0011800d, 0x00ffdb83, 0x000c0004, 0x80040000, 0x00000001, + 0x0000fc00, 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, + 0x00000000, 0x01000100, 0x00390204, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x569a569a, 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, + 0x32323200, 0x03000300, 0x22004000, 0x00000808, 0x00ffc3f1, + 0xc0083070, 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, + 0xfffffffe, 0x40302010, 0x00706050, 0x00000000, 0x00000023, + 0x00000000, 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, + 0x2e68120f, 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, + 0x15160000, 0x070b0f12, 0x00000104, 0x00d30000, 0x101fbf00, + 0x00000007, 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, + 0x08800000, 0x40000100, 0x08800000, 0x40000100, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, + 0x49795994, 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, + 0x007f037f, 0x6954342e, 0x43bc0094, 0x6954342f, 0x433c0094, + 0x00000000, 0x5116848b, 0x47c00bff, 0x00000036, 0x2c56000d +}, rtl8192cu_bb_vals0_92ce_92cu[] = { + 0x0011800d, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00, + 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, + 0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727, + 0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000, + 0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a, + 0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27, + 0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070, + 0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe, + 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, + 0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, + 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, + 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, + 0x48071d40, 0x03a05633, 0x000000e4, 0x6c6c6c6c, 0x08800000, + 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, + 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, + 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, + 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d +}, rtl8192cu_bb_vals1_88ru[] = { + 0x018610db, 0x0000001f, 0x00b91612, 0x24000090, 0x20f60000, + 0x24000090 +}, rtl8192cu_bb_vals1_92cu[] = { + 0x0186115b, 0x0000001f, 0x00b99612, 0x40000100, 0x20f60000, + 0x40000100 +}, rtl8192cu_bb_vals1_88cu_92ce[] = { + 0x018610db, 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, + 0x40000100 +}, rtl8192cu_bb_vals2[] = { + 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, + 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, + 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, + 0x00080740 +}, rtl8192cu_bb_vals5_88cu[] = { + 0x00000008, 0x001b25a4, 0x631b25a0, 0x631b25a0, 0x081b25a0, + 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x631b25a0, 0x081b25a0, + 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x001b25a0, + 0x001b25a0, 0x6b1b25a0, 0x00000003, 0x00000000, 0x00000300 +}, rtl8192cu_bb_vals5_88ru[] = { + 0x00000010, 0x001b25a4, 0x631b25a0, 0x631b25a0, 0x081b25a0, + 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x631b25a0, 0x081b25a0, + 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, 0x001b25a0, + 0x001b25a0, 0x6b1b25a0, 0x31555448, 0x00000003, 0x00000000, + 0x00000300 +}; + +static const struct rtwn_bb_prog rtl8192cu_bb[] = { + /* RTL8188CE / RTL8188CU. */ + { + nitems(rtl8192cu_bb_regs0), + rtl8192cu_bb_regs0, + rtl8192cu_bb_vals0_88cu, + { R92C_COND_RTL8188CU | R92C_COND_RTL8188CE }, + /* RTL8188RU. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192cu_bb_regs0_88ru), + rtl8192cu_bb_regs0_88ru, + rtl8192cu_bb_vals0_88ru, + { R92C_COND_RTL8188RU }, + /* Others. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192cu_bb_regs0), + rtl8192cu_bb_regs0, + rtl8192cu_bb_vals0_92ce_92cu, + { 0 }, + NULL + } + } + }, + /* RTL8188RU. */ + { + nitems(rtl8192cu_bb_regs1), + rtl8192cu_bb_regs1, + rtl8192cu_bb_vals1_88ru, + { R92C_COND_RTL8188RU }, + /* RTL8192CU. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192cu_bb_regs1), + rtl8192cu_bb_regs1, + rtl8192cu_bb_vals1_92cu, + { R92C_COND_RTL8192CU }, + /* Others. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192cu_bb_regs1), + rtl8192cu_bb_regs1, + rtl8192cu_bb_vals1_88cu_92ce, + { 0 }, + NULL + } + } + }, + { + nitems(rtl8192cu_bb_regs2), + rtl8192cu_bb_regs2, + rtl8192cu_bb_vals2, + { 0 }, + NULL + }, + /* RTL8192CE / RTL8192CU. */ + { + nitems(rtl8192c_bb_regs3), + rtl8192c_bb_regs3, + rtl8192c_bb_vals3_92ce_92cu, + { R92C_COND_RTL8192C }, + /* Others. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192c_bb_regs3), + rtl8192c_bb_regs3, + rtl8192c_bb_vals3_88cu_88ru, + { 0 }, + NULL + } + }, + { + nitems(rtl8192c_bb_regs4), + rtl8192c_bb_regs4, + rtl8192c_bb_vals4, + { 0 }, + NULL + }, + /* RTL8188CE / RTL8188CU. */ + { + nitems(rtl8192c_bb_regs5), + rtl8192c_bb_regs5, + rtl8192cu_bb_vals5_88cu, + { R92C_COND_RTL8188CU | R92C_COND_RTL8188CE }, + /* RTL8188RU. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192cu_bb_regs5_88ru), + rtl8192cu_bb_regs5_88ru, + rtl8192cu_bb_vals5_88ru, + { R92C_COND_RTL8188RU }, + /* Others. */ + &(const struct rtwn_bb_prog){ + nitems(rtl8192c_bb_regs5), + rtl8192c_bb_regs5, + rtl8192c_bb_vals5_92ce_92cu, + { 0 }, + NULL + } + } + } +}; + + +static const uint32_t rtl8188ru_agc_vals[] = { + 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, + 0x7b050001, 0x7b060001, 0x7b070001, 0x7b080001, 0x7a090001, + 0x790a0001, 0x780b0001, 0x770c0001, 0x760d0001, 0x750e0001, + 0x740f0001, 0x73100001, 0x72110001, 0x71120001, 0x70130001, + 0x6f140001, 0x6e150001, 0x6d160001, 0x6c170001, 0x6b180001, + 0x6a190001, 0x691a0001, 0x681b0001, 0x671c0001, 0x661d0001, + 0x651e0001, 0x641f0001, 0x63200001, 0x62210001, 0x61220001, + 0x60230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, + 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, + 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, + 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, + 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, + 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, + 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, + 0x7b460001, 0x7b470001, 0x7b480001, 0x7a490001, 0x794a0001, + 0x784b0001, 0x774c0001, 0x764d0001, 0x754e0001, 0x744f0001, + 0x73500001, 0x72510001, 0x71520001, 0x70530001, 0x6f540001, + 0x6e550001, 0x6d560001, 0x6c570001, 0x6b580001, 0x6a590001, + 0x695a0001, 0x685b0001, 0x675c0001, 0x665d0001, 0x655e0001, + 0x645f0001, 0x63600001, 0x62610001, 0x61620001, 0x60630001, + 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, + 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, + 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, + 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, + 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, + 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, + 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, + 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, + 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, + 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, + 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, + 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e +}; + +static const struct rtwn_agc_prog rtl8188ru_agc[] = { + { + nitems(rtl8188ru_agc_vals), + rtl8188ru_agc_vals, + { 0 }, + NULL + } +}; + +#endif /* R92CU_PRIV_H */ diff --git a/sys/dev/rtwn/rtl8192c/usb/r92cu_reg.h b/sys/dev/rtwn/rtl8192c/usb/r92cu_reg.h new file mode 100644 index 000000000000..a9db29ccbca4 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/usb/r92cu_reg.h @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92CU_REG_H +#define R92CU_REG_H + +#include + + +/* + * MAC registers. + */ +/* System Configuration. */ +#define R92C_USB_SIE_INTF 0x0e0 + + +/* + * USB registers. + */ +#define R92C_USB_SUSPEND 0xfe10 +#define R92C_USB_INFO 0xfe17 +#define R92C_USB_SPECIAL_OPTION 0xfe55 +#define R92C_USB_HCPWM 0xfe57 +#define R92C_USB_HRPWM 0xfe58 +#define R92C_USB_DMA_AGG_TO 0xfe5b +#define R92C_USB_AGG_TO 0xfe5c +#define R92C_USB_AGG_TH 0xfe5d +#define R92C_USB_VID 0xfe60 +#define R92C_USB_PID 0xfe62 +#define R92C_USB_OPTIONAL 0xfe64 +#define R92C_USB_EP 0xfe65 +#define R92C_USB_PHY 0xfe68 +#define R92C_USB_MAC_ADDR 0xfe70 +#define R92C_USB_STRING 0xfe80 + +/* Bits for R92C_USB_SPECIAL_OPTION. */ +#define R92C_USB_SPECIAL_OPTION_AGG_EN 0x08 +#define R92C_USB_SPECIAL_OPTION_INT_BULK_SEL 0x10 + +/* Bits for R92C_USB_EP. */ +#define R92C_USB_EP_HQ_M 0x000f +#define R92C_USB_EP_HQ_S 0 +#define R92C_USB_EP_NQ_M 0x00f0 +#define R92C_USB_EP_NQ_S 4 +#define R92C_USB_EP_LQ_M 0x0f00 +#define R92C_USB_EP_LQ_S 8 + +#endif /* R92CU_REG_H */ diff --git a/sys/dev/rtwn/rtl8192c/usb/r92cu_rx.c b/sys/dev/rtwn/rtl8192c/usb/r92cu_rx.c new file mode 100644 index 000000000000..d8a11dc36ef3 --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/usb/r92cu_rx.c @@ -0,0 +1,63 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + + +int +r92cu_classify_intr(struct rtwn_softc *sc, void *buf, int len) +{ + /* NB: reports are fetched from C2H_MSG register. */ + return (RTWN_RX_DATA); +} + +int +r92cu_align_rx(int totlen, int len) +{ + return (roundup2(totlen, 128)); +} diff --git a/sys/dev/rtwn/rtl8192c/usb/r92cu_tx.c b/sys/dev/rtwn/rtl8192c/usb/r92cu_tx.c new file mode 100644 index 000000000000..04dbade0651a --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/usb/r92cu_tx.c @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r92cu_dump_tx_desc(struct rtwn_softc *sc, const void *desc) +{ +#ifdef RTWN_DEBUG + const struct r92cu_tx_desc *txd = desc; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT_DESC, + "%s: len %d, off %d, flags0 %02X, dw: 1 %08X, 2 %08X, 3 %04X " + "(seq %04X), 4 %08X, 5 %08X, 6 %08X, sum %04X, pad %04X\n", + __func__, le16toh(txd->pktlen), txd->offset, txd->flags0, + le32toh(txd->txdw1), le32toh(txd->txdw2), le16toh(txd->txdw3), + le16toh(txd->txdseq), le32toh(txd->txdw4), le32toh(txd->txdw5), + le32toh(txd->txdw6), le16toh(txd->txdsum), le16toh(txd->pad)); +#endif +} diff --git a/sys/dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h b/sys/dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h new file mode 100644 index 000000000000..16c2d0587e4c --- /dev/null +++ b/sys/dev/rtwn/rtl8192c/usb/r92cu_tx_desc.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef R92CU_TX_DESC_H +#define R92CU_TX_DESC_H + +#include + +/* Tx MAC descriptor (USB). */ +struct r92cu_tx_desc { + uint16_t pktlen; + uint8_t offset; + uint8_t flags0; + + uint32_t txdw1; + uint32_t txdw2; + uint16_t txdw3; + uint16_t txdseq; + + uint32_t txdw4; + uint32_t txdw5; + uint32_t txdw6; + + uint16_t txdsum; + uint16_t pad; +} __packed __attribute__((aligned(4))); + +#endif /* R92CU_TX_DESC_H */ \ No newline at end of file diff --git a/sys/dev/rtwn/rtl8812a/r12a.h b/sys/dev/rtwn/rtl8812a/r12a.h new file mode 100644 index 000000000000..ec1d61e1e336 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a.h @@ -0,0 +1,140 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef RTL8812A_H +#define RTL8812A_H + +/* + * Global definitions. + */ +#define R12A_PUBQ_NPAGES 219 +#define R12A_TXPKTBUF_COUNT 255 +#define R12A_TX_PAGE_COUNT 248 + +#define R12A_TX_PAGE_SIZE 512 +#define R12A_RX_DMA_BUFFER_SIZE 0x3e80 + +#define R12A_MAX_FW_SIZE 0x8000 +#define R12A_MACID_MAX 127 +#define R12A_CAM_ENTRY_COUNT 64 + +#define R12A_INTR_MSG_LEN 60 + +static const uint8_t r12a_chan_5ghz_0[] = + { 36, 40, 44, 48, 52, 56, 60, 64 }; +static const uint8_t r12a_chan_5ghz_1[] = + { 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144 }; +static const uint8_t r12a_chan_5ghz_2[] = + { 149, 153, 157, 161, 165, 169, 173, 177 }; + + +/* + * Function declarations. + */ +/* r12a_attach.c */ +void r12a_vap_preattach(struct rtwn_softc *, struct ieee80211vap *); +void r12a_detach_private(struct rtwn_softc *); + +/* r12a_beacon.c */ +void r12a_beacon_init(struct rtwn_softc *, void *, int); +void r12a_beacon_set_rate(void *, int); + +/* r12a_calib.c */ +void r12a_save_bb_afe_vals(struct rtwn_softc *, uint32_t[], + const uint16_t[], int); +void r12a_restore_bb_afe_vals(struct rtwn_softc *, uint32_t[], + const uint16_t[], int); +void r12a_save_rf_vals(struct rtwn_softc *, uint32_t[], + const uint8_t[], int); +void r12a_restore_rf_vals(struct rtwn_softc *, uint32_t[], + const uint8_t[], int); +void r12a_lc_calib(struct rtwn_softc *); +#ifndef RTWN_WITHOUT_UCODE +int r12a_iq_calib_fw_supported(struct rtwn_softc *); +#endif +void r12a_iq_calib_sw(struct rtwn_softc *); +void r12a_iq_calib(struct rtwn_softc *); + +/* r12a_caps.c */ +int r12a_ioctl_net(struct ieee80211com *, u_long, void *); + +/* r12a_chan.c */ +void r12a_fix_spur(struct rtwn_softc *, struct ieee80211_channel *); +void r12a_set_chan(struct rtwn_softc *, struct ieee80211_channel *); +void r12a_set_band_2ghz(struct rtwn_softc *, uint32_t); +void r12a_set_band_5ghz(struct rtwn_softc *, uint32_t); + +/* r12a_fw.c */ +#ifndef RTWN_WITHOUT_UCODE +void r12a_fw_reset(struct rtwn_softc *, int); +void r12a_fw_download_enable(struct rtwn_softc *, int); +void r12a_set_media_status(struct rtwn_softc *, int); +int r12a_set_pwrmode(struct rtwn_softc *, struct ieee80211vap *, + int); +void r12a_iq_calib_fw(struct rtwn_softc *); +#endif + +/* r12a_init.c */ +int r12a_check_condition(struct rtwn_softc *, const uint8_t[]); +int r12a_set_page_size(struct rtwn_softc *); +void r12a_init_edca(struct rtwn_softc *); +void r12a_init_bb(struct rtwn_softc *); +void r12a_init_rf(struct rtwn_softc *); +void r12a_crystalcap_write(struct rtwn_softc *); +int r12a_power_on(struct rtwn_softc *); +void r12a_power_off(struct rtwn_softc *); +void r12a_init_intr(struct rtwn_softc *); +void r12a_init_antsel(struct rtwn_softc *); + +/* r12a_led.c */ +void r12a_set_led(struct rtwn_softc *, int, int); + +/* r12a_rf.c */ +uint32_t r12a_rf_read(struct rtwn_softc *, int, uint8_t); +uint32_t r12a_c_cut_rf_read(struct rtwn_softc *, int, uint8_t); +void r12a_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t); + +/* r12a_rom.c */ +void r12a_parse_rom_common(struct rtwn_softc *, uint8_t *); +void r12a_parse_rom(struct rtwn_softc *, uint8_t *); + +/* r12a_rx.c */ +void r12a_ratectl_tx_complete(struct rtwn_softc *, uint8_t *, int); +void r12a_handle_c2h_report(struct rtwn_softc *, uint8_t *, int); +int r12a_check_frame_checksum(struct rtwn_softc *, struct mbuf *); +uint8_t r12a_rx_radiotap_flags(const void *); + +/* r12a_tx.c */ +void r12a_fill_tx_desc(struct rtwn_softc *, struct ieee80211_node *, + struct mbuf *, void *, uint8_t, int); +void r12a_fill_tx_desc_raw(struct rtwn_softc *, struct ieee80211_node *, + struct mbuf *, void *, const struct ieee80211_bpf_params *); +void r12a_fill_tx_desc_null(struct rtwn_softc *, void *, int, int, int); +uint8_t r12a_tx_radiotap_flags(const void *); + +#endif /* RTL8812A_H */ diff --git a/sys/dev/rtwn/rtl8812a/r12a_beacon.c b/sys/dev/rtwn/rtl8812a/r12a_beacon.c new file mode 100644 index 000000000000..9360e4f99fdf --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_beacon.c @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +void +r12a_beacon_init(struct rtwn_softc *sc, void *buf, int id) +{ + struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; + + txd->flags0 = R12A_FLAGS0_LSG | R12A_FLAGS0_FSG | R12A_FLAGS0_BMCAST; + + /* + * NB: there is no need to setup HWSEQ_EN bit; + * QSEL_BEACON already implies it. + */ + txd->txdw1 = htole32(SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_BEACON)); + txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, RTWN_MACID_BC)); + + txd->txdw3 = htole32(R12A_TXDW3_DRVRATE); + txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, id)); + + txd->txdw6 = htole32(SM(R21A_TXDW6_MBSSID, id)); +} + +void +r12a_beacon_set_rate(void *buf, int is5ghz) +{ + struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; + + txd->txdw4 &= ~htole32(R12A_TXDW4_DATARATE_M); + if (is5ghz) { + txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE, + RTWN_RIDX_OFDM6)); + } else + txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE, RTWN_RIDX_CCK1)); +} diff --git a/sys/dev/rtwn/rtl8812a/r12a_calib.c b/sys/dev/rtwn/rtl8812a/r12a_calib.c new file mode 100644 index 000000000000..c87151b5355a --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_calib.c @@ -0,0 +1,286 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + + +void +r12a_lc_calib(struct rtwn_softc *sc) +{ + uint32_t chnlbw; + uint8_t txmode; + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: LC calibration started\n", __func__); + + txmode = rtwn_read_1(sc, R12A_SINGLETONE_CONT_TX + 2); + + if ((txmode & 0x07) != 0) { + /* Disable all continuous Tx. */ + /* + * Skipped because BB turns off continuous Tx until + * next packet comes in. + */ + } else { + /* Block all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + } + + /* Enter LCK mode. */ + rtwn_rf_setbits(sc, 0, R12A_RF_LCK, 0, R12A_RF_LCK_MODE); + + /* Start calibration. */ + chnlbw = rtwn_rf_read(sc, 0, R92C_RF_CHNLBW); + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, chnlbw | R92C_RF_CHNLBW_LCSTART); + + /* Give calibration the time to complete. */ + rtwn_delay(sc, 150000); /* 150 ms */ + + /* Leave LCK mode. */ + rtwn_rf_setbits(sc, 0, R12A_RF_LCK, R12A_RF_LCK_MODE, 0); + + /* Restore configuration. */ + if ((txmode & 0x07) != 0) { + /* Continuous Tx case. */ + /* + * Skipped because BB turns off continuous Tx until + * next packet comes in. + */ + } else { + /* Unblock all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, 0); + } + + /* Recover channel number. */ + rtwn_rf_write(sc, 0, R92C_RF_CHNLBW, chnlbw); + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "%s: LC calibration finished\n", __func__); +} + +#ifndef RTWN_WITHOUT_UCODE +int +r12a_iq_calib_fw_supported(struct rtwn_softc *sc) +{ + if (sc->fwver == 0x19) + return (1); + + return (0); +} +#endif + +void +r12a_save_bb_afe_vals(struct rtwn_softc *sc, uint32_t vals[], + const uint16_t regs[], int size) +{ + int i; + + /* Select page C. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0); + + for (i = 0; i < size; i++) + vals[i] = rtwn_bb_read(sc, regs[i]); +} + +void +r12a_restore_bb_afe_vals(struct rtwn_softc *sc, uint32_t vals[], + const uint16_t regs[], int size) +{ + int i; + + /* Select page C. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0); + + for (i = 0; i < size; i++) + rtwn_bb_write(sc, regs[i], vals[i]); +} + +void +r12a_save_rf_vals(struct rtwn_softc *sc, uint32_t vals[], + const uint8_t regs[], int size) +{ + int c, i; + + /* Select page C. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0); + + for (c = 0; c < sc->nrxchains; c++) + for (i = 0; i < size; i++) + vals[c * size + i] = rtwn_rf_read(sc, c, regs[i]); +} + +void +r12a_restore_rf_vals(struct rtwn_softc *sc, uint32_t vals[], + const uint8_t regs[], int size) +{ + int c, i; + + /* Select page C. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0); + + for (c = 0; c < sc->nrxchains; c++) + for (i = 0; i < size; i++) + rtwn_rf_write(sc, c, regs[i], vals[c * size + i]); +} + +#ifdef RTWN_TODO +static void +r12a_iq_tx(struct rtwn_softc *sc) +{ + /* TODO */ +} + +static void +r12a_iq_config_mac(struct rtwn_softc *sc) +{ + + /* Select page C. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x80000000, 0); + rtwn_write_1(sc, R92C_TXPAUSE, + R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT | R92C_TX_QUEUE_HIGH); + /* BCN_CTRL & BCN_CTRL1 */ + rtwn_setbits_1(sc, R92C_BCN_CTRL(0), R92C_BCN_CTRL_EN_BCN, 0); + rtwn_setbits_1(sc, R92C_BCN_CTRL(1), R92C_BCN_CTRL_EN_BCN, 0); + /* Rx ant off */ + rtwn_write_1(sc, R12A_OFDMCCK_EN, 0); + /* CCA off */ + rtwn_bb_setbits(sc, R12A_CCA_ON_SEC, 0x03, 0x0c); + /* CCK RX Path off */ + rtwn_write_1(sc, R12A_CCK_RX_PATH + 3, 0x0f); +} +#endif + +void +r12a_iq_calib_sw(struct rtwn_softc *sc) +{ +#define R12A_MAX_NRXCHAINS 2 + uint32_t bb_vals[nitems(r12a_iq_bb_regs)]; + uint32_t afe_vals[nitems(r12a_iq_afe_regs)]; + uint32_t rf_vals[nitems(r12a_iq_rf_regs) * R12A_MAX_NRXCHAINS]; + uint32_t rfe[2]; + + KASSERT(sc->nrxchains <= R12A_MAX_NRXCHAINS, + ("nrxchains > %d (%d)\n", R12A_MAX_NRXCHAINS, sc->nrxchains)); + + /* Save registers. */ + r12a_save_bb_afe_vals(sc, bb_vals, r12a_iq_bb_regs, + nitems(r12a_iq_bb_regs)); + + /* Select page C1. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0, 0x80000000); + rfe[0] = rtwn_bb_read(sc, R12A_RFE(0)); + rfe[1] = rtwn_bb_read(sc, R12A_RFE(1)); + + r12a_save_bb_afe_vals(sc, afe_vals, r12a_iq_afe_regs, + nitems(r12a_iq_afe_regs)); + r12a_save_rf_vals(sc, rf_vals, r12a_iq_rf_regs, + nitems(r12a_iq_rf_regs)); + +#ifdef RTWN_TODO + /* Configure MAC. */ + rtwn_iq_config_mac(sc); + rtwn_iq_tx(sc); +#endif + + r12a_restore_rf_vals(sc, rf_vals, r12a_iq_rf_regs, + nitems(r12a_iq_rf_regs)); + r12a_restore_bb_afe_vals(sc, afe_vals, r12a_iq_afe_regs, + nitems(r12a_iq_afe_regs)); + + /* Select page C1. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0, 0x80000000); + + /* Chain 0. */ + rtwn_bb_write(sc, R12A_SLEEP_NAV(0), 0); + rtwn_bb_write(sc, R12A_PMPD(0), 0); + rtwn_bb_write(sc, 0xc88, 0); + rtwn_bb_write(sc, 0xc8c, 0x3c000000); + rtwn_bb_setbits(sc, 0xc90, 0, 0x00000080); + rtwn_bb_setbits(sc, 0xcc4, 0, 0x20040000); + rtwn_bb_setbits(sc, 0xcc8, 0, 0x20000000); + + /* Chain 1. */ + rtwn_bb_write(sc, R12A_SLEEP_NAV(1), 0); + rtwn_bb_write(sc, R12A_PMPD(1), 0); + rtwn_bb_write(sc, 0xe88, 0); + rtwn_bb_write(sc, 0xe8c, 0x3c000000); + rtwn_bb_setbits(sc, 0xe90, 0, 0x00000080); + rtwn_bb_setbits(sc, 0xec4, 0, 0x20040000); + rtwn_bb_setbits(sc, 0xec8, 0, 0x20000000); + + rtwn_bb_write(sc, R12A_RFE(0), rfe[0]); + rtwn_bb_write(sc, R12A_RFE(1), rfe[1]); + + r12a_restore_bb_afe_vals(sc, bb_vals, r12a_iq_bb_regs, + nitems(r12a_iq_bb_regs)); +#undef R12A_MAX_NRXCHAINS +} + +void +r12a_iq_calib(struct rtwn_softc *sc) +{ +#ifndef RTWN_WITHOUT_UCODE + if ((sc->sc_flags & RTWN_FW_LOADED) && + rtwn_r12a_iq_calib_fw_supported(sc)) + r12a_iq_calib_fw(sc); + else +#endif + rtwn_r12a_iq_calib_sw(sc); +} diff --git a/sys/dev/rtwn/rtl8812a/r12a_caps.c b/sys/dev/rtwn/rtl8812a/r12a_caps.c new file mode 100644 index 000000000000..a8b738e7f887 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_caps.c @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +int +r12a_ioctl_net(struct ieee80211com *ic, u_long cmd, void *data) +{ + struct rtwn_softc *sc = ic->ic_softc; + struct r12a_softc *rs = sc->sc_priv; + struct ifreq *ifr = (struct ifreq *)data; + int error; + + error = 0; + switch (cmd) { + case SIOCSIFCAP: + { + struct ieee80211vap *vap; + int changed, rxmask; + + rxmask = ifr->ifr_reqcap & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6); + + RTWN_LOCK(sc); + changed = 0; + if (!(rs->rs_flags & R12A_RXCKSUM_EN) ^ + !(ifr->ifr_reqcap & IFCAP_RXCSUM)) { + rs->rs_flags ^= R12A_RXCKSUM_EN; + changed = 1; + } + if (!(rs->rs_flags & R12A_RXCKSUM6_EN) ^ + !(ifr->ifr_reqcap & IFCAP_RXCSUM_IPV6)) { + rs->rs_flags ^= R12A_RXCKSUM6_EN; + changed = 1; + } + if (changed) { + if (rxmask == 0) { + sc->rcr &= ~R12A_RCR_TCP_OFFLD_EN; + if (sc->sc_flags & RTWN_RUNNING) { + rtwn_setbits_4(sc, R92C_RCR, + R12A_RCR_TCP_OFFLD_EN, 0); + } + } else { + sc->rcr |= R12A_RCR_TCP_OFFLD_EN; + if (sc->sc_flags & RTWN_RUNNING) { + rtwn_setbits_4(sc, R92C_RCR, + 0, R12A_RCR_TCP_OFFLD_EN); + } + } + } + RTWN_UNLOCK(sc); + + IEEE80211_LOCK(ic); /* XXX */ + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + struct ifnet *ifp = vap->iv_ifp; + + ifp->if_capenable &= + ~(IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6); + ifp->if_capenable |= rxmask; + } + IEEE80211_UNLOCK(ic); + break; + } + default: + error = ENOTTY; /* for net80211 */ + break; + } + + return (error); +} diff --git a/sys/dev/rtwn/rtl8812a/r12a_chan.c b/sys/dev/rtwn/rtl8812a/r12a_chan.c new file mode 100644 index 000000000000..50bb09db18f3 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_chan.c @@ -0,0 +1,601 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + + +static void +r12a_write_txpower(struct rtwn_softc *sc, int chain, + struct ieee80211_channel *c, uint16_t power[RTWN_RIDX_COUNT]) +{ + + if (IEEE80211_IS_CHAN_2GHZ(c)) { + /* Write per-CCK rate Tx power. */ + rtwn_bb_write(sc, R12A_TXAGC_CCK11_1(chain), + SM(R12A_TXAGC_CCK1, power[RTWN_RIDX_CCK1]) | + SM(R12A_TXAGC_CCK2, power[RTWN_RIDX_CCK2]) | + SM(R12A_TXAGC_CCK55, power[RTWN_RIDX_CCK55]) | + SM(R12A_TXAGC_CCK11, power[RTWN_RIDX_CCK11])); + } + + /* Write per-OFDM rate Tx power. */ + rtwn_bb_write(sc, R12A_TXAGC_OFDM18_6(chain), + SM(R12A_TXAGC_OFDM06, power[RTWN_RIDX_OFDM6]) | + SM(R12A_TXAGC_OFDM09, power[RTWN_RIDX_OFDM9]) | + SM(R12A_TXAGC_OFDM12, power[RTWN_RIDX_OFDM12]) | + SM(R12A_TXAGC_OFDM18, power[RTWN_RIDX_OFDM18])); + rtwn_bb_write(sc, R12A_TXAGC_OFDM54_24(chain), + SM(R12A_TXAGC_OFDM24, power[RTWN_RIDX_OFDM24]) | + SM(R12A_TXAGC_OFDM36, power[RTWN_RIDX_OFDM36]) | + SM(R12A_TXAGC_OFDM48, power[RTWN_RIDX_OFDM48]) | + SM(R12A_TXAGC_OFDM54, power[RTWN_RIDX_OFDM54])); + /* Write per-MCS Tx power. */ + rtwn_bb_write(sc, R12A_TXAGC_MCS3_0(chain), + SM(R12A_TXAGC_MCS0, power[RTWN_RIDX_MCS(0)]) | + SM(R12A_TXAGC_MCS1, power[RTWN_RIDX_MCS(1)]) | + SM(R12A_TXAGC_MCS2, power[RTWN_RIDX_MCS(2)]) | + SM(R12A_TXAGC_MCS3, power[RTWN_RIDX_MCS(3)])); + rtwn_bb_write(sc, R12A_TXAGC_MCS7_4(chain), + SM(R12A_TXAGC_MCS4, power[RTWN_RIDX_MCS(4)]) | + SM(R12A_TXAGC_MCS5, power[RTWN_RIDX_MCS(5)]) | + SM(R12A_TXAGC_MCS6, power[RTWN_RIDX_MCS(6)]) | + SM(R12A_TXAGC_MCS7, power[RTWN_RIDX_MCS(7)])); + if (sc->ntxchains >= 2) { + rtwn_bb_write(sc, R12A_TXAGC_MCS11_8(chain), + SM(R12A_TXAGC_MCS8, power[RTWN_RIDX_MCS(8)]) | + SM(R12A_TXAGC_MCS9, power[RTWN_RIDX_MCS(9)]) | + SM(R12A_TXAGC_MCS10, power[RTWN_RIDX_MCS(10)]) | + SM(R12A_TXAGC_MCS11, power[RTWN_RIDX_MCS(11)])); + rtwn_bb_write(sc, R12A_TXAGC_MCS15_12(chain), + SM(R12A_TXAGC_MCS12, power[RTWN_RIDX_MCS(12)]) | + SM(R12A_TXAGC_MCS13, power[RTWN_RIDX_MCS(13)]) | + SM(R12A_TXAGC_MCS14, power[RTWN_RIDX_MCS(14)]) | + SM(R12A_TXAGC_MCS15, power[RTWN_RIDX_MCS(15)])); + } + + /* TODO: VHT rates */ +} + +static int +r12a_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + uint8_t chan; + int group; + + chan = rtwn_chan2centieee(c); + if (IEEE80211_IS_CHAN_2GHZ(c)) { + if (chan <= 2) group = 0; + else if (chan <= 5) group = 1; + else if (chan <= 8) group = 2; + else if (chan <= 11) group = 3; + else if (chan <= 14) group = 4; + else { + KASSERT(0, ("wrong 2GHz channel %d!\n", chan)); + return (-1); + } + } else if (IEEE80211_IS_CHAN_5GHZ(c)) { + if (chan < 36) + return (-1); + + if (chan <= 42) group = 0; + else if (chan <= 48) group = 1; + else if (chan <= 58) group = 2; + else if (chan <= 64) group = 3; + else if (chan <= 106) group = 4; + else if (chan <= 114) group = 5; + else if (chan <= 122) group = 6; + else if (chan <= 130) group = 7; + else if (chan <= 138) group = 8; + else if (chan <= 144) group = 9; + else if (chan <= 155) group = 10; + else if (chan <= 161) group = 11; + else if (chan <= 171) group = 12; + else if (chan <= 177) group = 13; + else { + KASSERT(0, ("wrong 5GHz channel %d!\n", chan)); + return (-1); + } + } else { + KASSERT(0, ("wrong channel band (flags %08X)\n", c->ic_flags)); + return (-1); + } + + return (group); +} + +static void +r12a_get_txpower(struct rtwn_softc *sc, int chain, + struct ieee80211_channel *c, uint16_t power[RTWN_RIDX_COUNT]) +{ + struct r12a_softc *rs = sc->sc_priv; + int i, ridx, group, max_mcs; + + /* Determine channel group. */ + group = r12a_get_power_group(sc, c); + if (group == -1) { /* shouldn't happen */ + device_printf(sc->sc_dev, "%s: incorrect channel\n", __func__); + return; + } + + /* TODO: VHT rates. */ + max_mcs = RTWN_RIDX_MCS(sc->ntxchains * 8 - 1); + + /* XXX regulatory */ + /* XXX net80211 regulatory */ + + if (IEEE80211_IS_CHAN_2GHZ(c)) { + for (ridx = RTWN_RIDX_CCK1; ridx <= RTWN_RIDX_CCK11; ridx++) + power[ridx] = rs->cck_tx_pwr[chain][group]; + for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++) + power[ridx] = rs->ht40_tx_pwr_2g[chain][group]; + + if (RTWN_RATE_IS_OFDM(ridx)) { + uint8_t pwr_diff = rs->ofdm_tx_pwr_diff_2g[chain][0]; + for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) + power[ridx] += pwr_diff; + } + + for (i = 0; i < sc->ntxchains; i++) { + uint8_t min_mcs; + uint8_t pwr_diff; + +#ifdef notyet + if (IEEE80211_IS_CHAN_HT80(c)) { + /* Vendor driver uses HT40 values here. */ + pwr_diff = rs->bw40_tx_pwr_diff_2g[chain][i]; + } else +#endif + if (IEEE80211_IS_CHAN_HT40(c)) + pwr_diff = rs->bw40_tx_pwr_diff_2g[chain][i]; + else + pwr_diff = rs->bw20_tx_pwr_diff_2g[chain][i]; + + min_mcs = RTWN_RIDX_MCS(i * 8 + 7); + for (ridx = min_mcs; ridx <= max_mcs; ridx++) + power[ridx] += pwr_diff; + } + } else { /* 5GHz */ + for (ridx = RTWN_RIDX_OFDM6; ridx <= max_mcs; ridx++) + power[ridx] = rs->ht40_tx_pwr_5g[chain][group]; + + for (i = 0; i < sc->ntxchains; i++) { + uint8_t min_mcs; + uint8_t pwr_diff; + +#ifdef notyet + if (IEEE80211_IS_CHAN_HT80(c)) { + /* TODO: calculate base value. */ + pwr_diff = rs->bw80_tx_pwr_diff_5g[chain][i]; + } else +#endif + if (IEEE80211_IS_CHAN_HT40(c)) + pwr_diff = rs->bw40_tx_pwr_diff_5g[chain][i]; + else + pwr_diff = rs->bw20_tx_pwr_diff_5g[chain][i]; + + min_mcs = RTWN_RIDX_MCS(i * 8 + 7); + for (ridx = min_mcs; ridx <= max_mcs; ridx++) + power[ridx] += pwr_diff; + } + } + + /* Apply max limit. */ + for (ridx = RTWN_RIDX_CCK1; ridx <= max_mcs; ridx++) { + if (power[ridx] > R92C_MAX_TX_PWR) + power[ridx] = R92C_MAX_TX_PWR; + } + +#ifdef RTWN_DEBUG + if (sc->sc_debug & RTWN_DEBUG_TXPWR) { + /* Dump per-rate Tx power values. */ + printf("Tx power for chain %d:\n", chain); + for (ridx = RTWN_RIDX_CCK1; ridx < RTWN_RIDX_COUNT; ridx++) + printf("Rate %d = %u\n", ridx, power[ridx]); + } +#endif +} + +static void +r12a_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + uint16_t power[RTWN_RIDX_COUNT]; + int i; + + for (i = 0; i < sc->ntxchains; i++) { + memset(power, 0, sizeof(power)); + /* Compute per-rate Tx power values. */ + r12a_get_txpower(sc, i, c, power); + /* Write per-rate Tx power values to hardware. */ + r12a_write_txpower(sc, i, c, power); + } +} + +void +r12a_fix_spur(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + struct r12a_softc *rs = sc->sc_priv; + uint16_t chan = rtwn_chan2centieee(c); + + if (rs->chip & R12A_CHIP_C_CUT) { + if (IEEE80211_IS_CHAN_HT40(c) && chan == 11) { + rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0xc00); + rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0, 0x40000000); + } else { + rtwn_bb_setbits(sc, R12A_RFMOD, 0x400, 0x800); + + if (!IEEE80211_IS_CHAN_HT40(c) && /* 20 MHz */ + (chan == 13 || chan == 14)) { + rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0x300); + rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, + 0, 0x40000000); + } else { /* !80 Mhz */ + rtwn_bb_setbits(sc, R12A_RFMOD, 0x100, 0x200); + rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, + 0x40000000, 0); + } + } + } else { + /* Set ADC clock to 160M to resolve 2480 MHz spur. */ + if (!IEEE80211_IS_CHAN_HT40(c) && /* 20 MHz */ + (chan == 13 || chan == 14)) + rtwn_bb_setbits(sc, R12A_RFMOD, 0, 0x300); + else if (IEEE80211_IS_CHAN_2GHZ(c)) + rtwn_bb_setbits(sc, R12A_RFMOD, 0x100, 0x200); + } +} + +static void +r12a_set_band(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct r12a_softc *rs = sc->sc_priv; + uint32_t basicrates; + uint8_t swing; + int i; + + /* Check if band was changed. */ + if ((sc->sc_flags & (RTWN_STARTED | RTWN_RUNNING)) != + RTWN_STARTED && IEEE80211_IS_CHAN_5GHZ(c) ^ + !(rtwn_read_1(sc, R12A_CCK_CHECK) & R12A_CCK_CHECK_5GHZ)) + return; + + rtwn_get_rates(sc, ieee80211_get_suprates(ic, c), NULL, &basicrates, + NULL, 1); + if (IEEE80211_IS_CHAN_2GHZ(c)) { + rtwn_r12a_set_band_2ghz(sc, basicrates); + swing = rs->tx_bbswing_2g; + } else if (IEEE80211_IS_CHAN_5GHZ(c)) { + rtwn_r12a_set_band_5ghz(sc, basicrates); + swing = rs->tx_bbswing_5g; + } else { + KASSERT(0, ("wrong channel flags %08X\n", c->ic_flags)); + return; + } + + /* XXX PATH_B is set by vendor driver. */ + for (i = 0; i < 2; i++) { + uint16_t val; + + switch ((swing >> i * 2) & 0x3) { + case 0: + val = 0x200; /* 0 dB */ + break; + case 1: + val = 0x16a; /* -3 dB */ + break; + case 2: + val = 0x101; /* -6 dB */ + break; + case 3: + val = 0xb6; /* -9 dB */ + break; + } + + rtwn_bb_setbits(sc, R12A_TX_SCALE(i), R12A_TX_SCALE_SWING_M, + val << R12A_TX_SCALE_SWING_S); + } +} + +void +r12a_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + uint32_t val; + uint16_t chan; + int i; + + r12a_set_band(sc, c); + + chan = rtwn_chan2centieee(c); + if (36 <= chan && chan <= 48) + val = 0x09280000; + else if (50 <= chan && chan <= 64) + val = 0x08a60000; + else if (100 <= chan && chan <= 116) + val = 0x08a40000; + else if (118 <= chan) + val = 0x08240000; + else + val = 0x12d40000; + + rtwn_bb_setbits(sc, R12A_FC_AREA, 0x1ffe0000, val); + + for (i = 0; i < sc->nrxchains; i++) { + if (36 <= chan && chan <= 64) + val = 0x10100; + else if (100 <= chan && chan <= 140) + val = 0x30100; + else if (140 < chan) + val = 0x50100; + else + val = 0x00000; + + rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0x70300, val); + + /* RTL8812AU-specific */ + rtwn_r12a_fix_spur(sc, c); + + KASSERT(chan <= 0xff, ("%s: chan %d\n", __func__, chan)); + rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0xff, chan); + } + +#ifdef notyet + if (IEEE80211_IS_CHAN_HT80(c)) { /* 80 MHz */ + rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x80, 0x100); + + /* TODO */ + + val = 0x0; + } else +#endif + if (IEEE80211_IS_CHAN_HT40(c)) { /* 40 MHz */ + uint8_t ext_chan; + + if (IEEE80211_IS_CHAN_HT40U(c)) + ext_chan = R12A_DATA_SEC_PRIM_DOWN_20; + else + ext_chan = R12A_DATA_SEC_PRIM_UP_20; + + rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x100, 0x80); + rtwn_write_1(sc, R12A_DATA_SEC, ext_chan); + + rtwn_bb_setbits(sc, R12A_RFMOD, 0x003003c3, 0x00300201); + rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0x40000000, 0); + + /* discard high 4 bits */ + val = rtwn_bb_read(sc, R12A_RFMOD); + val = RW(val, R12A_RFMOD_EXT_CHAN, ext_chan); + rtwn_bb_write(sc, R12A_RFMOD, val); + + val = rtwn_bb_read(sc, R12A_CCA_ON_SEC); + val = RW(val, R12A_CCA_ON_SEC_EXT_CHAN, ext_chan); + rtwn_bb_write(sc, R12A_CCA_ON_SEC, val); + + if (rtwn_read_1(sc, 0x837) & 0x04) + val = 0x01800000; + else if (sc->nrxchains == 2 && sc->ntxchains == 2) + val = 0x01c00000; + else + val = 0x02000000; + + rtwn_bb_setbits(sc, R12A_L1_PEAK_TH, 0x03c00000, val); + + if (IEEE80211_IS_CHAN_HT40U(c)) + rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0x10, 0); + else + rtwn_bb_setbits(sc, R92C_CCK0_SYSTEM, 0, 0x10); + + val = 0x400; + } else { /* 20 MHz */ + rtwn_setbits_2(sc, R92C_WMAC_TRXPTCL_CTL, 0x180, 0); + rtwn_write_1(sc, R12A_DATA_SEC, R12A_DATA_SEC_NO_EXT); + + rtwn_bb_setbits(sc, R12A_RFMOD, 0x003003c3, 0x00300200); + rtwn_bb_setbits(sc, R12A_ADC_BUF_CLK, 0x40000000, 0); + + if (sc->nrxchains == 2 && sc->ntxchains == 2) + val = 0x01c00000; + else + val = 0x02000000; + + rtwn_bb_setbits(sc, R12A_L1_PEAK_TH, 0x03c00000, val); + + val = 0xc00; + } + + /* RTL8812AU-specific */ + rtwn_r12a_fix_spur(sc, c); + + for (i = 0; i < 2; i++) + rtwn_rf_setbits(sc, i, R92C_RF_CHNLBW, 0xc00, val); + + /* Set Tx power for this new channel. */ + r12a_set_txpower(sc, c); +} + +void +r12a_set_band_2ghz(struct rtwn_softc *sc, uint32_t basicrates) +{ + struct r12a_softc *rs = sc->sc_priv; + + /* Enable CCK / OFDM. */ + rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, + 0, R12A_OFDMCCK_EN_CCK | R12A_OFDMCCK_EN_OFDM); + + rtwn_bb_setbits(sc, R12A_BW_INDICATION, 0x02, 0x01); + rtwn_bb_setbits(sc, R12A_PWED_TH, 0x3e000, 0x2e000); + + /* Select AGC table. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x03, 0); + + switch (rs->rfe_type) { + case 0: + case 1: + case 2: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77777777); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0); + break; + case 3: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x54337770); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x54337770); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); + rtwn_bb_setbits(sc, R12A_ANTSEL_SW, 0x0303, 0x01); + break; + case 4: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77777777); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x00100000); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x00100000); + break; + case 5: + rtwn_write_1(sc, R12A_RFE_PINMUX(0) + 2, 0x77); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77777777); + rtwn_setbits_1(sc, R12A_RFE_INV(0) + 3, 0x01, 0); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0); + break; + default: + break; + } + + rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0x10); + rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0x0f000000, 0x01000000); + + /* Write basic rates. */ + rtwn_set_basicrates(sc, basicrates); + + rtwn_write_1(sc, R12A_CCK_CHECK, 0); +} + +void +r12a_set_band_5ghz(struct rtwn_softc *sc, uint32_t basicrates) +{ + struct r12a_softc *rs = sc->sc_priv; + int ntries; + + rtwn_write_1(sc, R12A_CCK_CHECK, R12A_CCK_CHECK_5GHZ); + + for (ntries = 0; ntries < 100; ntries++) { + if ((rtwn_read_2(sc, R12A_TXPKT_EMPTY) & 0x30) == 0x30) + break; + + rtwn_delay(sc, 25); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "%s: TXPKT_EMPTY check failed (%04X)\n", + __func__, rtwn_read_2(sc, R12A_TXPKT_EMPTY)); + } + + /* Enable OFDM. */ + rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, R12A_OFDMCCK_EN_CCK, + R12A_OFDMCCK_EN_OFDM); + + rtwn_bb_setbits(sc, R12A_BW_INDICATION, 0x01, 0x02); + rtwn_bb_setbits(sc, R12A_PWED_TH, 0x3e000, 0x2a000); + + /* Select AGC table. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0x03, 0x01); + + switch (rs->rfe_type) { + case 0: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337717); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337717); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); + break; + case 1: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337717); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337717); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0); + break; + case 2: + case 4: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x77337777); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337777); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); + break; + case 3: + rtwn_bb_write(sc, R12A_RFE_PINMUX(0), 0x54337717); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x54337717); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x3ff00000, 0x01000000); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); + rtwn_bb_setbits(sc, R12A_ANTSEL_SW, 0x0303, 0x01); + break; + case 5: + rtwn_write_1(sc, R12A_RFE_PINMUX(0) + 2, 0x33); + rtwn_bb_write(sc, R12A_RFE_PINMUX(1), 0x77337777); + rtwn_setbits_1(sc, R12A_RFE_INV(0) + 3, 0, 0x01); + rtwn_bb_setbits(sc, R12A_RFE_INV(1), 0x3ff00000, 0x01000000); + break; + default: + break; + } + + rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0); + rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0, 0x0f000000); + + /* Write basic rates. */ + rtwn_set_basicrates(sc, basicrates); +} diff --git a/sys/dev/rtwn/rtl8812a/r12a_fw.c b/sys/dev/rtwn/rtl8812a/r12a_fw.c new file mode 100644 index 000000000000..93362bab1a57 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_fw.c @@ -0,0 +1,194 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include + + +#ifndef RTWN_WITHOUT_UCODE +void +r12a_fw_reset(struct rtwn_softc *sc, int reason) +{ + /* Reset MCU IO wrapper. */ + rtwn_setbits_1(sc, R92C_RSV_CTRL, 0x02, 0); + rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0x08, 0); + + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_CPUEN, 0, 1); + + /* Enable MCU IO wrapper. */ + rtwn_setbits_1(sc, R92C_RSV_CTRL, 0x02, 0); + rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0, 0x08); + + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, + 0, R92C_SYS_FUNC_EN_CPUEN, 1); +} + +void +r12a_fw_download_enable(struct rtwn_softc *sc, int enable) +{ + if (enable) { + /* MCU firmware download enable. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, 0, R92C_MCUFWDL_EN); + /* 8051 reset. */ + rtwn_setbits_1_shift(sc, R92C_MCUFWDL, R92C_MCUFWDL_ROM_DLEN, + 0, 2); + } else { + /* MCU download disable. */ + rtwn_setbits_1(sc, R92C_MCUFWDL, R92C_MCUFWDL_EN, 0); + } +} + +void +r12a_set_media_status(struct rtwn_softc *sc, int macid) +{ + struct r12a_fw_cmd_msrrpt status; + int error; + + if (macid & RTWN_MACID_VALID) + status.msrb0 = R12A_MSRRPT_B0_ASSOC; + else + status.msrb0 = R12A_MSRRPT_B0_DISASSOC; + + status.macid = (macid & ~RTWN_MACID_VALID); + status.macid_end = 0; + + error = r88e_fw_cmd(sc, R12A_CMD_MSR_RPT, &status, sizeof(status)); + if (error != 0) + device_printf(sc->sc_dev, "cannot change media status!\n"); +} + +int +r12a_set_pwrmode(struct rtwn_softc *sc, struct ieee80211vap *vap, + int off) +{ + struct r12a_fw_cmd_pwrmode mode; + int error; + + if (off && vap->iv_state == IEEE80211_S_RUN && + (vap->iv_flags & IEEE80211_F_PMGTON)) { + mode.mode = R88E_PWRMODE_LEG; + /* + * TODO: switch to RFOFF state + * (something is missing here - Rx stops with it). + */ +#ifdef RTWN_TODO + mode.pwr_state = R88E_PWRMODE_STATE_RFOFF; +#else + mode.pwr_state = R88E_PWRMODE_STATE_RFON; +#endif + } else { + mode.mode = R88E_PWRMODE_CAM; + mode.pwr_state = R88E_PWRMODE_STATE_ALLON; + } + mode.pwrb1 = + SM(R88E_PWRMODE_B1_SMART_PS, R88E_PWRMODE_B1_LEG_NULLDATA) | + SM(R88E_PWRMODE_B1_RLBM, R88E_PWRMODE_B1_MODE_MIN); + /* XXX ignored */ + mode.bcn_pass = 0; + mode.queue_uapsd = 0; + mode.pwrb5 = R12A_PWRMODE_B5_NO_BTCOEX; + error = r88e_fw_cmd(sc, R12A_CMD_SET_PWRMODE, &mode, sizeof(mode)); + if (error != 0) { + device_printf(sc->sc_dev, + "%s: CMD_SET_PWRMODE was not sent, error %d\n", + __func__, error); + } + + return (error); +} + +void +r12a_iq_calib_fw(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + struct ieee80211_channel *c = sc->sc_ic.ic_curchan; + struct r12a_fw_cmd_iq_calib cmd; + + if (rs->rs_flags & R12A_IQK_RUNNING) + return; + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "Starting IQ calibration (FW)\n"); + + cmd.chan = rtwn_chan2centieee(c); + if (IEEE80211_IS_CHAN_5GHZ(c)) + cmd.band_bw = RTWN_CMD_IQ_BAND_5GHZ; + else + cmd.band_bw = RTWN_CMD_IQ_BAND_2GHZ; + + /* TODO: 80/160 MHz. */ + if (IEEE80211_IS_CHAN_HT40(c)) + cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_40; + else + cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_20; + + cmd.ext_5g_pa_lna = RTWN_CMD_IQ_EXT_PA_5G(rs->ext_pa_5g); + cmd.ext_5g_pa_lna |= RTWN_CMD_IQ_EXT_LNA_5G(rs->ext_lna_5g); + + if (r88e_fw_cmd(sc, R12A_CMD_IQ_CALIBRATE, &cmd, sizeof(cmd)) != 0) { + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "error while sending IQ calibration command to FW!\n"); + return; + } + + rs->rs_flags |= R12A_IQK_RUNNING; +} +#endif diff --git a/sys/dev/rtwn/rtl8812a/r12a_fw_cmd.h b/sys/dev/rtwn/rtl8812a/r12a_fw_cmd.h new file mode 100644 index 000000000000..58b82ed14268 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_fw_cmd.h @@ -0,0 +1,123 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef R12A_FW_CMD_H +#define R12A_FW_CMD_H + +#include + +/* + * Host to firmware commands. + */ +/* Note: some parts are shared with RTL8188EU. */ +#define R12A_CMD_MSR_RPT 0x01 +#define R12A_CMD_SET_PWRMODE 0x20 +#define R12A_CMD_IQ_CALIBRATE 0x45 + +/* Structure for R12A_CMD_MSR_RPT. */ +struct r12a_fw_cmd_msrrpt { + uint8_t msrb0; +#define R12A_MSRRPT_B0_DISASSOC 0x00 +#define R12A_MSRRPT_B0_ASSOC 0x01 +#define R12A_MSRRPT_B0_MACID_IND 0x02 + + uint8_t macid; + uint8_t macid_end; +} __packed; + +/* Structure for R12A_CMD_SET_PWRMODE. */ +struct r12a_fw_cmd_pwrmode { + uint8_t mode; + uint8_t pwrb1; + uint8_t bcn_pass; + uint8_t queue_uapsd; + uint8_t pwr_state; + uint8_t pwrb5; +#define R12A_PWRMODE_B5_NO_BTCOEX 0x40 +} __packed; + +/* Structure for R12A_CMD_IQ_CALIBRATE. */ +struct r12a_fw_cmd_iq_calib { + uint8_t chan; + uint8_t band_bw; +#define RTWN_CMD_IQ_CHAN_WIDTH_20 0x01 +#define RTWN_CMD_IQ_CHAN_WIDTH_40 0x02 +#define RTWN_CMD_IQ_CHAN_WIDTH_80 0x04 +#define RTWN_CMD_IQ_CHAN_WIDTH_160 0x08 +#define RTWN_CMD_IQ_BAND_2GHZ 0x10 +#define RTWN_CMD_IQ_BAND_5GHZ 0x20 + + uint8_t ext_5g_pa_lna; +#define RTWN_CMD_IQ_EXT_PA_5G(pa) (pa) +#define RTWN_CMD_IQ_EXT_LNA_5G(lna) ((lna) << 1) +} __packed; + + +/* + * C2H event types. + */ +#define R12A_C2H_DEBUG 0x00 +#define R12A_C2H_TX_REPORT 0x03 +#define R12A_C2H_BT_INFO 0x09 +#define R12A_C2H_RA_REPORT 0x0c +#define R12A_C2H_IQK_FINISHED 0x11 + +/* Structure for R12A_C2H_TX_REPORT event. */ +struct r12a_c2h_tx_rpt { + uint8_t txrptb0; +#define R12A_TXRPTB0_QSEL_M 0x1f +#define R12A_TXRPTB0_QSEL_S 0 +#define R12A_TXRPTB0_BC 0x20 +#define R12A_TXRPTB0_LIFE_EXPIRE 0x40 +#define R12A_TXRPTB0_RETRY_OVER 0x80 + + uint8_t macid; + uint8_t txrptb2; +#define R12A_TXRPTB2_RETRY_CNT_M 0x3f +#define R12A_TXRPTB2_RETRY_CNT_S 0 + + uint8_t queue_time_low; /* 256 msec unit */ + uint8_t queue_time_high; + uint8_t final_rate; + uint16_t reserved; +} __packed; + +/* Structure for R12A_C2H_RA_REPORT event. */ +struct r12a_c2h_ra_report { + uint8_t rarptb0; +#define R12A_RARPTB0_RATE_M 0x3f +#define R12A_RARPTB0_RATE_S 0 + + uint8_t macid; + uint8_t rarptb2; +#define R12A_RARPTB0_LDPC 0x01 +#define R12A_RARPTB0_TXBF 0x02 +#define R12A_RARPTB0_NOISE 0x04 +} __packed; + +#endif /* R12A_FW_CMD_H */ diff --git a/sys/dev/rtwn/rtl8812a/r12a_init.c b/sys/dev/rtwn/rtl8812a/r12a_init.c new file mode 100644 index 000000000000..8ec401d9d0e4 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_init.c @@ -0,0 +1,486 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include + + +int +r12a_check_condition(struct rtwn_softc *sc, const uint8_t cond[]) +{ + struct r12a_softc *rs = sc->sc_priv; + uint8_t mask[4]; + int i, j, nmasks; + + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "%s: condition byte 0: %02X; ext PA/LNA: %d/%d (2 GHz), " + "%d/%d (5 GHz)\n", __func__, cond[0], rs->ext_pa_2g, + rs->ext_lna_2g, rs->ext_pa_5g, rs->ext_lna_5g); + + if (cond[0] == 0) + return (1); + + if (!rs->ext_pa_2g && !rs->ext_lna_2g && + !rs->ext_pa_5g && !rs->ext_lna_5g) + return (0); + + nmasks = 0; + if (rs->ext_pa_2g) { + mask[nmasks] = R12A_COND_GPA; + mask[nmasks] |= R12A_COND_TYPE(rs->type_pa_2g); + nmasks++; + } + if (rs->ext_pa_5g) { + mask[nmasks] = R12A_COND_APA; + mask[nmasks] |= R12A_COND_TYPE(rs->type_pa_5g); + nmasks++; + } + if (rs->ext_lna_2g) { + mask[nmasks] = R12A_COND_GLNA; + mask[nmasks] |= R12A_COND_TYPE(rs->type_lna_2g); + nmasks++; + } + if (rs->ext_lna_5g) { + mask[nmasks] = R12A_COND_ALNA; + mask[nmasks] |= R12A_COND_TYPE(rs->type_lna_5g); + nmasks++; + } + + for (i = 0; i < RTWN_MAX_CONDITIONS && cond[i] != 0; i++) + for (j = 0; j < nmasks; j++) + if ((cond[i] & mask[j]) == mask[j]) + return (1); + + return (0); +} + +int +r12a_set_page_size(struct rtwn_softc *sc) +{ + return (rtwn_setbits_1(sc, R92C_PBP, R92C_PBP_PSTX_M, + R92C_PBP_512 << R92C_PBP_PSTX_S) == 0); +} + +void +r12a_init_edca(struct rtwn_softc *sc) +{ + r92c_init_edca(sc); + + /* 80 MHz clock */ + rtwn_write_1(sc, R92C_USTIME_TSF, 0x50); + rtwn_write_1(sc, R92C_USTIME_EDCA, 0x50); +} + +void +r12a_init_bb(struct rtwn_softc *sc) +{ + int i, j; + + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, 0, R92C_SYS_FUNC_EN_USBA); + + /* Enable BB and RF. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, 0, + R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST); + + /* PathA RF Power On. */ + rtwn_write_1(sc, R92C_RF_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); + + /* PathB RF Power On. */ + rtwn_write_1(sc, R12A_RF_B_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); + + /* Write BB initialization values. */ + for (i = 0; i < sc->bb_size; i++) { + const struct rtwn_bb_prog *bb_prog = &sc->bb_prog[i]; + + while (!rtwn_check_condition(sc, bb_prog->cond)) { + KASSERT(bb_prog->next != NULL, + ("%s: wrong condition value (i %d)\n", + __func__, i)); + bb_prog = bb_prog->next; + } + + for (j = 0; j < bb_prog->count; j++) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "BB: reg 0x%03x, val 0x%08x\n", + bb_prog->reg[j], bb_prog->val[j]); + + rtwn_bb_write(sc, bb_prog->reg[j], bb_prog->val[j]); + rtwn_delay(sc, 1); + } + } + + /* XXX meshpoint mode? */ + + /* Write AGC values. */ + for (i = 0; i < sc->agc_size; i++) { + const struct rtwn_agc_prog *agc_prog = &sc->agc_prog[i]; + + while (!rtwn_check_condition(sc, agc_prog->cond)) { + KASSERT(agc_prog->next != NULL, + ("%s: wrong condition value (2) (i %d)\n", + __func__, i)); + agc_prog = agc_prog->next; + } + + for (j = 0; j < agc_prog->count; j++) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "AGC: val 0x%08x\n", agc_prog->val[j]); + + rtwn_bb_write(sc, 0x81c, agc_prog->val[j]); + rtwn_delay(sc, 1); + } + } + + for (i = 0; i < sc->nrxchains; i++) { + rtwn_bb_write(sc, R12A_INITIAL_GAIN(i), 0x22); + rtwn_delay(sc, 1); + rtwn_bb_write(sc, R12A_INITIAL_GAIN(i), 0x20); + rtwn_delay(sc, 1); + } + + rtwn_r12a_crystalcap_write(sc); + + if (rtwn_bb_read(sc, R12A_CCK_RPT_FORMAT) & R12A_CCK_RPT_FORMAT_HIPWR) + sc->sc_flags |= RTWN_FLAG_CCK_HIPWR; +} + +void +r12a_init_rf(struct rtwn_softc *sc) +{ + int chain, i; + + for (chain = 0, i = 0; chain < sc->nrxchains; chain++, i++) { + /* Write RF initialization values for this chain. */ + i += r92c_init_rf_chain(sc, &sc->rf_prog[i], chain); + } +} + +void +r12a_crystalcap_write(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + uint32_t reg; + uint8_t val; + + val = rs->crystalcap & 0x3f; + reg = rtwn_bb_read(sc, R92C_MAC_PHY_CTRL); + reg = RW(reg, R12A_MAC_PHY_CRYSTALCAP, val | (val << 6)); + rtwn_bb_write(sc, R92C_MAC_PHY_CTRL, reg); +} + +static void +r12a_rf_init_workaround(struct rtwn_softc *sc) +{ + + rtwn_write_1(sc, R92C_RF_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_SDMRSTB); + rtwn_write_1(sc, R92C_RF_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | + R92C_RF_CTRL_SDMRSTB); + rtwn_write_1(sc, R12A_RF_B_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_SDMRSTB); + rtwn_write_1(sc, R12A_RF_B_CTRL, + R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | + R92C_RF_CTRL_SDMRSTB); +} + +int +r12a_power_on(struct rtwn_softc *sc) +{ +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while(0) + int ntries; + + r12a_rf_init_workaround(sc); + + /* Force PWM mode. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_SPS0_CTRL + 1, 0, 0x01)); + + /* Turn off ZCD. */ + RTWN_CHK(rtwn_setbits_2(sc, 0x014, 0x0180, 0)); + + /* Enable LDO normal mode. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_LPLDO_CTRL, R92C_LPLDO_CTRL_SLEEP, + 0)); + + /* GPIO 0...7 input mode. */ + RTWN_CHK(rtwn_write_1(sc, R92C_GPIO_IOSEL, 0)); + + /* GPIO 11...8 input mode. */ + RTWN_CHK(rtwn_write_1(sc, R92C_MAC_PINMUX_CFG, 0)); + + /* Enable WL suspend. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS, 0, 1)); + + /* Enable 8051. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, + 0, R92C_SYS_FUNC_EN_CPUEN, 1)); + + /* Disable SW LPS. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_APFM_RSM, 0, 1)); + + /* Wait for power ready bit. */ + for (ntries = 0; ntries < 5000; ntries++) { + if (rtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) { + device_printf(sc->sc_dev, + "timeout waiting for chip power up\n"); + return (ETIMEDOUT); + } + + /* Disable WL suspend. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS, 0, 1)); + + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_APFM_ONMAC, 1)); + for (ntries = 0; ntries < 5000; ntries++) { + if (!(rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_ONMAC)) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) + return (ETIMEDOUT); + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + RTWN_CHK(rtwn_write_2(sc, R92C_CR, 0x0000)); + RTWN_CHK(rtwn_setbits_2(sc, R92C_CR, 0, + R92C_CR_HCI_TXDMA_EN | R92C_CR_TXDMA_EN | + R92C_CR_HCI_RXDMA_EN | R92C_CR_RXDMA_EN | + R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN | + ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) | + R92C_CR_CALTMR_EN)); + + return (0); +} + +void +r12a_power_off(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + int error, ntries; + + /* Stop Rx. */ + error = rtwn_write_1(sc, R92C_CR, 0); + if (error == ENXIO) /* hardware gone */ + return; + + /* Move card to Low Power state. */ + /* Block all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + + for (ntries = 0; ntries < 10; ntries++) { + /* Should be zero if no packet is transmitting. */ + if (rtwn_read_4(sc, R88E_SCH_TXCMD) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: failed to block Tx queues\n", + __func__); + return; + } + + /* Turn off 3-wire. */ + rtwn_write_1(sc, R12A_HSSI_PARAM1(0), 0x04); + rtwn_write_1(sc, R12A_HSSI_PARAM1(1), 0x04); + + /* CCK and OFDM are disabled, and clock are gated. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BBRSTB, 0); + + rtwn_delay(sc, 1); + + /* Reset whole BB. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BB_GLB_RST, 0); + + /* Reset MAC TRX. */ + rtwn_write_1(sc, R92C_CR, + R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN); + + /* check if removed later. (?) */ + rtwn_setbits_1_shift(sc, R92C_CR, R92C_CR_ENSEC, 0, 1); + + /* Respond TxOK to scheduler */ + rtwn_setbits_1(sc, R92C_DUAL_TSF_RST, 0, R92C_DUAL_TSF_RST_TXOK); + + /* If firmware in ram code, do reset. */ +#ifndef RTWN_WITHOUT_UCODE + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) + r12a_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN); +#endif + + /* Reset MCU. */ + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_CPUEN, + 0, 1); + rtwn_write_1(sc, R92C_MCUFWDL, 0); + + /* Move card to Disabled state. */ + /* Turn off 3-wire. */ + rtwn_write_1(sc, R12A_HSSI_PARAM1(0), 0x04); + rtwn_write_1(sc, R12A_HSSI_PARAM1(1), 0x04); + + /* Reset BB, close RF. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BB_GLB_RST, 0); + + rtwn_delay(sc, 1); + + /* SPS PWM mode. */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0xff, + R92C_APS_FSMCO_SOP_RCK | R92C_APS_FSMCO_SOP_ABG, 3); + + /* ANA clock = 500k. */ + rtwn_setbits_1(sc, R92C_SYS_CLKR, R92C_SYS_CLKR_ANA8M, 0); + + /* Turn off MAC by HW state machine */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, R92C_APS_FSMCO_APFM_OFF, + 1); + for (ntries = 0; ntries < 10; ntries++) { + /* Wait until it will be disabled. */ + if ((rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_OFF) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: could not turn off MAC\n", + __func__); + return; + } + + /* Reset 8051. */ + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_CPUEN, + 0, 1); + + /* Fill the default value of host_CPU handshake field. */ + rtwn_write_1(sc, R92C_MCUFWDL, + R92C_MCUFWDL_EN | R92C_MCUFWDL_CHKSUM_RPT); + + rtwn_setbits_1(sc, R92C_GPIO_IO_SEL, 0xf0, 0xc0); + + /* GPIO 11 input mode, 10...8 output mode. */ + rtwn_write_1(sc, R92C_MAC_PINMUX_CFG, 0x07); + + /* GPIO 7...0, output = input */ + rtwn_write_1(sc, R92C_GPIO_OUT, 0); + + /* GPIO 7...0 output mode. */ + rtwn_write_1(sc, R92C_GPIO_IOSEL, 0xff); + + rtwn_write_1(sc, R92C_GPIO_MOD, 0); + + /* Turn on ZCD. */ + rtwn_setbits_2(sc, 0x014, 0, 0x0180); + + /* Force PFM mode. */ + rtwn_setbits_1(sc, R92C_SPS0_CTRL + 1, 0x01, 0); + + /* LDO sleep mode. */ + rtwn_setbits_1(sc, R92C_LPLDO_CTRL, 0, R92C_LPLDO_CTRL_SLEEP); + + /* ANA clock = 500k. */ + rtwn_setbits_1(sc, R92C_SYS_CLKR, R92C_SYS_CLKR_ANA8M, 0); + + /* SOP option to disable BG/MB. */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0xff, + R92C_APS_FSMCO_SOP_RCK, 3); + + /* Disable RFC_0. */ + rtwn_setbits_1(sc, R92C_RF_CTRL, R92C_RF_CTRL_RSTB, 0); + + /* Disable RFC_1. */ + rtwn_setbits_1(sc, R12A_RF_B_CTRL, R92C_RF_CTRL_RSTB, 0); + + /* Enable WL suspend. */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, R92C_APS_FSMCO_AFSM_HSUS, + 1); + + rs->rs_flags &= ~R12A_IQK_RUNNING; +} + +void +r12a_init_intr(struct rtwn_softc *sc) +{ + rtwn_write_4(sc, R88E_HIMR, 0); + rtwn_write_4(sc, R88E_HIMRE, 0); +} + +void +r12a_init_antsel(struct rtwn_softc *sc) +{ + uint32_t reg; + + rtwn_write_1(sc, R92C_LEDCFG2, 0x82); + rtwn_bb_setbits(sc, R92C_FPGA0_RFPARAM(0), 0, 0x2000); + reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(0)); + sc->sc_ant = MS(reg, R92C_FPGA0_RFIFACEOE0_ANT); +} diff --git a/sys/dev/rtwn/rtl8812a/r12a_led.c b/sys/dev/rtwn/rtl8812a/r12a_led.c new file mode 100644 index 000000000000..aa67c67b97a7 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_led.c @@ -0,0 +1,72 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + + +void +r12a_set_led(struct rtwn_softc *sc, int led, int on) +{ + /* XXX assume led #0 == LED_LINK */ + /* XXX antenna diversity */ + + if (led == RTWN_LED_LINK) { + rtwn_setbits_1(sc, R92C_LEDCFG0, 0x8f, + R12A_LEDCFG2_ENA | (on ? 0 : R92C_LEDCFG0_DIS)); + sc->ledlink = on; /* Save LED state. */ + } + + /* XXX leds #1/#2 ? */ +} diff --git a/sys/dev/rtwn/rtl8812a/r12a_priv.h b/sys/dev/rtwn/rtl8812a/r12a_priv.h new file mode 100644 index 000000000000..8df869687344 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_priv.h @@ -0,0 +1,852 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef R12A_PRIV_H +#define R12A_PRIV_H + +/* + * MAC initialization values. + */ +#define RTL8812AU_MAC_PROG_START \ + { 0x010, 0x0c }, + +#define RTL8812AU_MAC_PROG_END \ + { 0x025, 0x0f }, { 0x072, 0x00 }, { 0x420, 0x80 }, { 0x428, 0x0a }, \ + { 0x429, 0x10 }, { 0x430, 0x00 }, { 0x431, 0x00 }, { 0x432, 0x00 }, \ + { 0x433, 0x01 }, { 0x434, 0x04 }, { 0x435, 0x05 }, { 0x436, 0x07 }, \ + { 0x437, 0x08 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, { 0x43e, 0x07 }, \ + { 0x43f, 0x08 }, { 0x440, 0x5d }, { 0x441, 0x01 }, { 0x442, 0x00 }, \ + { 0x444, 0x10 }, { 0x445, 0x00 }, { 0x446, 0x00 }, { 0x447, 0x00 }, \ + { 0x448, 0x00 }, { 0x449, 0xf0 }, { 0x44a, 0x0f }, { 0x44b, 0x3e }, \ + { 0x44c, 0x10 }, { 0x44d, 0x00 }, { 0x44e, 0x00 }, { 0x44f, 0x00 }, \ + { 0x450, 0x00 }, { 0x451, 0xf0 }, { 0x452, 0x0f }, { 0x453, 0x00 }, \ + { 0x45b, 0x80 }, { 0x460, 0x66 }, { 0x461, 0x66 }, { 0x4c8, 0xff }, \ + { 0x4c9, 0x08 }, { 0x4cc, 0xff }, { 0x4cd, 0xff }, { 0x4ce, 0x01 }, \ + { 0x500, 0x26 }, { 0x501, 0xa2 }, { 0x502, 0x2f }, { 0x503, 0x00 }, \ + { 0x504, 0x28 }, { 0x505, 0xa3 }, { 0x506, 0x5e }, { 0x507, 0x00 }, \ + { 0x508, 0x2b }, { 0x509, 0xa4 }, { 0x50a, 0x5e }, { 0x50b, 0x00 }, \ + { 0x50c, 0x4f }, { 0x50d, 0xa4 }, { 0x50e, 0x00 }, { 0x50f, 0x00 }, \ + { 0x512, 0x1c }, { 0x514, 0x0a }, { 0x516, 0x0a }, { 0x525, 0x4f }, \ + { 0x550, 0x10 }, { 0x551, 0x10 }, { 0x559, 0x02 }, { 0x55c, 0x50 }, \ + { 0x55d, 0xff }, { 0x604, 0x09 }, { 0x605, 0x30 }, { 0x607, 0x03 }, \ + { 0x608, 0x0e }, { 0x609, 0x2a }, { 0x620, 0xff }, { 0x621, 0xff }, \ + { 0x622, 0xff }, { 0x623, 0xff }, { 0x624, 0xff }, { 0x625, 0xff }, \ + { 0x626, 0xff }, { 0x627, 0xff }, { 0x638, 0x50 }, { 0x63c, 0x0a }, \ + { 0x63d, 0x0a }, { 0x63e, 0x0e }, { 0x63f, 0x0e }, { 0x640, 0x80 }, \ + { 0x642, 0x40 }, { 0x643, 0x00 }, { 0x652, 0xc8 }, { 0x66e, 0x05 }, \ + { 0x700, 0x21 }, { 0x701, 0x43 }, { 0x702, 0x65 }, { 0x703, 0x87 }, \ + { 0x708, 0x21 }, { 0x709, 0x43 }, { 0x70a, 0x65 }, { 0x70b, 0x87 }, \ + { 0x718, 0x40 } + +static const struct rtwn_mac_prog rtl8812au_mac_no_ext_pa_lna[] = { + RTL8812AU_MAC_PROG_START + { 0x11, 0x66 }, + RTL8812AU_MAC_PROG_END +}, rtl8812au_mac[] = { + RTL8812AU_MAC_PROG_START + { 0x11, 0x5a }, + RTL8812AU_MAC_PROG_END +}; + + +/* + * Baseband initialization values. + */ +#define R12A_COND_GPA 0x01 +#define R12A_COND_APA 0x02 +#define R12A_COND_GLNA 0x04 +#define R12A_COND_ALNA 0x08 +#define R12A_COND_TYPE(t) ((t) << 4) + +static const uint16_t rtl8812au_bb_regs0[] = { + 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, 0x820, 0x824, + 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, 0x840, 0x844, 0x848, + 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, 0x864, 0x868, 0x86c, + 0x870, 0x874, 0x878, 0x87c, 0x8a0, 0x8a4, 0x8a8, 0x8ac, 0x8b0, + 0x8b4, 0x8b8, 0x8bc, 0x8c0, 0x8c4, 0x8c8, 0x8cc, 0x8d0, 0x8dc, + 0x8d4, 0x8d8, 0x8f8, 0x8fc, 0x900, 0x90c, 0x910, 0x914, 0x918, + 0x91c, 0x920, 0x924, 0x928, 0x92c, 0x930, 0x934, 0x960, 0x964, + 0x968, 0x96c, 0x970, 0x978, 0x97c, 0x980, 0x984, 0x988, 0x990, + 0x994, 0x998, 0x99c, 0x9a0, 0x9a4, 0x9a8, 0x9ac, 0x9b0, 0x9b4, + 0x9b8, 0x9bc, 0x9d0, 0x9d4, 0x9d8, 0x9dc, 0x9e4, 0x9e8, 0xa00, + 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, 0xa20, 0xa24, + 0xa28, 0xa2c, 0xa70, 0xa74, 0xa78, 0xa7c, 0xa80, 0xa84, 0xb00, + 0xb04, 0xb08, 0xb0c, 0xb10, 0xb14, 0xb18, 0xb1c, 0xb20, 0xb24, + 0xb28, 0xb2c, 0xb30, 0xb34, 0xb38, 0xb3c, 0xb40, 0xb44, 0xb48, + 0xb4c, 0xb50, 0xb54, 0xb58, 0xb5c, 0xc00, 0xc04, 0xc08, 0xc0c, + 0xc10, 0xc14, 0xc1c, 0xc20, 0xc24, 0xc28, 0xc2c, 0xc30, 0xc34, + 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, 0xc54, 0xc58, + 0xc5c, 0xc60, 0xc64 +}, rtl8812au_bb_regs1[] = { + 0xc68 +}, rtl8812au_bb_regs2[] = { + 0xc6c, 0xc70, 0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc94, 0xc98, + 0xc9c, 0xca0, 0xca4, 0xca8, 0xcb0, 0xcb4, 0xcb8, 0xe00, 0xe04, + 0xe08, 0xe0c, 0xe10, 0xe14, 0xe1c, 0xe20, 0xe24, 0xe28, 0xe2c, + 0xe30, 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, 0xe48, 0xe4c, 0xe50, + 0xe54, 0xe58, 0xe5c, 0xe60, 0xe64, 0xe68, 0xe6c, 0xe70, 0xe74, + 0xe78, 0xe7c, 0xe80, 0xe84, 0xe94, 0xe98, 0xe9c, 0xea0, 0xea4, + 0xea8, 0xeb0, 0xeb4, 0xeb8 +}; + +static const uint32_t rtl8812au_bb_vals0[] = { + 0x8020d010, 0x080112e0, 0x0e028233, 0x12131113, 0x20101263, + 0x020c3d10, 0x03a00385, 0x00000000, 0x00030fe0, 0x00000000, + 0x002083dd, 0x2eaaeeb8, 0x0037a706, 0x06c89b44, 0x0000095b, + 0xc0000001, 0x40003cde, 0x6210ff8b, 0x6cfdffb8, 0x28874706, + 0x0001520c, 0x8060e000, 0x74210168, 0x6929c321, 0x79727432, + 0x8ca7a314, 0x338c2878, 0x03333333, 0x31602c2e, 0x00003152, + 0x000fc000, 0x00000013, 0x7f7f7f7f, 0xa202033e, 0x0ff0fa0a, + 0x00000600, 0x000fc080, 0x6c0057ff, 0x4ca520a3, 0x27f00020, + 0x00000000, 0x00012d69, 0x08248492, 0x0000b800, 0x00000000, + 0x940008a0, 0x290b5612, 0x400002c0, 0x00000000, 0x00000701, + 0x00000000, 0x0000fc00, 0x00000404, 0x1c1028c0, 0x64b11a1c, + 0xe0767233, 0x055aa500, 0x00000004, 0xfffe0000, 0xfffffffe, + 0x001fffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x801fffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x27100000, 0xffff0100, 0xffffff5c, 0xffffffff, + 0x000000ff, 0x00080080, 0x00000000, 0x00000000, 0x81081008, + 0x00000000, 0x01081008, 0x01081008, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000003, 0x000002d5, 0x00d047c8, + 0x01ff000c, 0x8c838300, 0x2e7f000f, 0x9500bb78, 0x11144028, + 0x00881117, 0x89140f00, 0x1a1b0000, 0x090e1217, 0x00000305, + 0x00900000, 0x101fff00, 0x00000008, 0x00000900, 0x225b0606, + 0x218075b2, 0x001f8c80, 0x03100000, 0x0000b000, 0xae0201eb, + 0x01003207, 0x00009807, 0x01000000, 0x00000002, 0x00000002, + 0x0000001f, 0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c, + 0x13121110, 0x17161514, 0x0000003a, 0x00000000, 0x00000000, + 0x13000032, 0x48080000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000007, 0x00042020, 0x80410231, 0x00000000, + 0x00000100, 0x01000000, 0x40000003, 0x12121212, 0x12121212, + 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, + 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, + 0x00000020, 0x0008121c, 0x30000c1c, 0x00000058, 0x34344443, + 0x07003333 +}, rtl8812au_bb_vals1_ext_pa_lna[] = { + 0x59791979 +}, rtl8812au_bb_vals1[] = { + 0x59799979 +}, rtl8812au_bb_vals2[] = { + 0x59795979, 0x19795979, 0x19795979, 0x19791979, 0x19791979, + 0x19791979, 0x19791979, 0x0100005c, 0x00000000, 0x00000000, + 0x00000029, 0x08040201, 0x80402010, 0x77547777, 0x00000077, + 0x00508242, 0x00000007, 0x00042020, 0x80410231, 0x00000000, + 0x00000100, 0x01000000, 0x40000003, 0x12121212, 0x12121212, + 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, + 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, + 0x00000020, 0x0008121c, 0x30000c1c, 0x00000058, 0x34344443, + 0x07003333, 0x59791979, 0x59795979, 0x19795979, 0x19795979, + 0x19791979, 0x19791979, 0x19791979, 0x19791979, 0x0100005c, + 0x00000000, 0x00000000, 0x00000029, 0x08040201, 0x80402010, + 0x77547777, 0x00000077, 0x00508242 +}; + +static const struct rtwn_bb_prog rtl8812au_bb[] = { + { + nitems(rtl8812au_bb_regs0), + rtl8812au_bb_regs0, + rtl8812au_bb_vals0, + { 0 }, + NULL + }, + /* + * Devices with: + * * External 2GHz PA, type 0; + * * External 5GHz PA, type 0 or 5; + * * External 2GHz LNA, type 0 or 5; + * * External 5GHz LNA, type 0; + */ + { + nitems(rtl8812au_bb_regs1), + rtl8812au_bb_regs1, + rtl8812au_bb_vals1_ext_pa_lna, + { + R12A_COND_GPA | R12A_COND_GLNA | + R12A_COND_APA | R12A_COND_ALNA | + R12A_COND_TYPE(0x0), + R12A_COND_APA | R12A_COND_GLNA | + R12A_COND_TYPE(0x5), 0 + }, + /* + * Others. + */ + &(const struct rtwn_bb_prog){ + nitems(rtl8812au_bb_regs1), + rtl8812au_bb_regs1, + rtl8812au_bb_vals1, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_bb_regs2), + rtl8812au_bb_regs2, + rtl8812au_bb_vals2, + { 0 }, + NULL + } +}; + + +static const uint32_t rtl8812au_agc_vals0_lna_g0[] = { + 0xfc000001, 0xfb020001, 0xfa040001, 0xf9060001, 0xf8080001, + 0xf70a0001, 0xf60c0001, 0xf50e0001, 0xf4100001, 0xf3120001, + 0xf2140001, 0xf1160001, 0xf0180001, 0xef1a0001, 0xee1c0001, + 0xed1e0001, 0xec200001, 0xeb220001, 0xea240001, 0xcd260001, + 0xcc280001, 0xcb2a0001, 0xca2c0001, 0xc92e0001, 0xc8300001, + 0xa6320001, 0xa5340001, 0xa4360001, 0xa3380001, 0xa23a0001, + 0x883c0001, 0x873e0001, 0x86400001, 0x85420001, 0x84440001, + 0x83460001, 0x82480001, 0x814a0001, 0x484c0001, 0x474e0001, + 0x46500001, 0x45520001, 0x44540001, 0x43560001, 0x42580001, + 0x415a0001, 0x255c0001, 0x245e0001, 0x23600001, 0x22620001, + 0x21640001, 0x21660001, 0x21680001, 0x216a0001, 0x216c0001, + 0x216e0001, 0x21700001, 0x21720001, 0x21740001, 0x21760001, + 0x21780001, 0x217a0001, 0x217c0001, 0x217e0001 +}, rtl8812au_agc_vals0_lna_g5[] = { + 0xf9000001, 0xf8020001, 0xf7040001, 0xf6060001, 0xf5080001, + 0xf40a0001, 0xf30c0001, 0xf20e0001, 0xf1100001, 0xf0120001, + 0xef140001, 0xee160001, 0xed180001, 0xec1a0001, 0xeb1c0001, + 0xea1e0001, 0xcd200001, 0xcc220001, 0xcb240001, 0xca260001, + 0xc9280001, 0xc82a0001, 0xc72c0001, 0xc62e0001, 0xa5300001, + 0xa4320001, 0xa3340001, 0xa2360001, 0x88380001, 0x873a0001, + 0x863c0001, 0x853e0001, 0x84400001, 0x83420001, 0x82440001, + 0x81460001, 0x48480001, 0x474a0001, 0x464c0001, 0x454e0001, + 0x44500001, 0x43520001, 0x42540001, 0x41560001, 0x25580001, + 0x245a0001, 0x235c0001, 0x225e0001, 0x21600001, 0x21620001, + 0x21640001, 0x21660001, 0x21680001, 0x216a0001, 0x236c0001, + 0x226e0001, 0x21700001, 0x21720001, 0x21740001, 0x21760001, + 0x21780001, 0x217a0001, 0x217c0001, 0x217e0001 +}, rtl8812au_agc_vals0[] = { + 0xff000001, 0xff020001, 0xff040001, 0xff060001, 0xff080001, + 0xfe0a0001, 0xfd0c0001, 0xfc0e0001, 0xfb100001, 0xfa120001, + 0xf9140001, 0xf8160001, 0xf7180001, 0xf61a0001, 0xf51c0001, + 0xf41e0001, 0xf3200001, 0xf2220001, 0xf1240001, 0xf0260001, + 0xef280001, 0xee2a0001, 0xed2c0001, 0xec2e0001, 0xeb300001, + 0xea320001, 0xe9340001, 0xe8360001, 0xe7380001, 0xe63a0001, + 0xe53c0001, 0xc73e0001, 0xc6400001, 0xc5420001, 0xc4440001, + 0xc3460001, 0xc2480001, 0xc14a0001, 0xa74c0001, 0xa64e0001, + 0xa5500001, 0xa4520001, 0xa3540001, 0xa2560001, 0xa1580001, + 0x675a0001, 0x665c0001, 0x655e0001, 0x64600001, 0x63620001, + 0x48640001, 0x47660001, 0x46680001, 0x456a0001, 0x446c0001, + 0x436e0001, 0x42700001, 0x41720001, 0x41740001, 0x41760001, + 0x41780001, 0x417a0001, 0x417c0001, 0x417e0001 +}, rtl8812au_agc_vals1_lna_a0[] = { + 0xfc800001, 0xfb820001, 0xfa840001, 0xf9860001, 0xf8880001, + 0xf78a0001, 0xf68c0001, 0xf58e0001, 0xf4900001, 0xf3920001, + 0xf2940001, 0xf1960001, 0xf0980001, 0xef9a0001, 0xee9c0001, + 0xed9e0001, 0xeca00001, 0xeba20001, 0xeaa40001, 0xe9a60001, + 0xe8a80001, 0xe7aa0001, 0xe6ac0001, 0xe5ae0001, 0xe4b00001, + 0xe3b20001, 0xa8b40001, 0xa7b60001, 0xa6b80001, 0xa5ba0001, + 0xa4bc0001, 0xa3be0001, 0xa2c00001, 0xa1c20001, 0x68c40001, + 0x67c60001, 0x66c80001, 0x65ca0001, 0x64cc0001, 0x47ce0001, + 0x46d00001, 0x45d20001, 0x44d40001, 0x43d60001, 0x42d80001, + 0x08da0001, 0x07dc0001, 0x06de0001, 0x05e00001, 0x04e20001, + 0x03e40001, 0x02e60001, 0x01e80001, 0x01ea0001, 0x01ec0001, + 0x01ee0001, 0x01f00001, 0x01f20001, 0x01f40001, 0x01f60001, + 0x01f80001, 0x01fa0001, 0x01fc0001, 0x01fe0001 +}, rtl8812au_agc_vals1[] = { + 0xff800001, 0xff820001, 0xff840001, 0xfe860001, 0xfd880001, + 0xfc8a0001, 0xfb8c0001, 0xfa8e0001, 0xf9900001, 0xf8920001, + 0xf7940001, 0xf6960001, 0xf5980001, 0xf49a0001, 0xf39c0001, + 0xf29e0001, 0xf1a00001, 0xf0a20001, 0xefa40001, 0xeea60001, + 0xeda80001, 0xecaa0001, 0xebac0001, 0xeaae0001, 0xe9b00001, + 0xe8b20001, 0xe7b40001, 0xe6b60001, 0xe5b80001, 0xe4ba0001, + 0xe3bc0001, 0xa8be0001, 0xa7c00001, 0xa6c20001, 0xa5c40001, + 0xa4c60001, 0xa3c80001, 0xa2ca0001, 0xa1cc0001, 0x68ce0001, + 0x67d00001, 0x66d20001, 0x65d40001, 0x64d60001, 0x47d80001, + 0x46da0001, 0x45dc0001, 0x44de0001, 0x43e00001, 0x42e20001, + 0x08e40001, 0x07e60001, 0x06e80001, 0x05ea0001, 0x04ec0001, + 0x03ee0001, 0x02f00001, 0x01f20001, 0x01f40001, 0x01f60001, + 0x01f80001, 0x01fa0001, 0x01fc0001, 0x01fe0001 +}; + +static const struct rtwn_agc_prog rtl8812au_agc[] = { + /* + * External 2GHz LNA (type 0). + */ + { + nitems(rtl8812au_agc_vals0_lna_g0), + rtl8812au_agc_vals0_lna_g0, + { R12A_COND_GLNA | R12A_COND_TYPE(0x0), 0 }, + /* + * External 2GHz LNA (type 5). + */ + &(const struct rtwn_agc_prog){ + nitems(rtl8812au_agc_vals0_lna_g5), + rtl8812au_agc_vals0_lna_g5, + { R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0 }, + /* + * Others. + */ + &(const struct rtwn_agc_prog){ + nitems(rtl8812au_agc_vals0), + rtl8812au_agc_vals0, + { 0 }, + NULL + } + } + }, + /* + * External 5GHz LNA (type 0). + */ + { + nitems(rtl8812au_agc_vals1_lna_a0), + rtl8812au_agc_vals1_lna_a0, + { R12A_COND_ALNA | R12A_COND_TYPE(0x0), 0 }, + /* + * Others. + */ + &(const struct rtwn_agc_prog){ + nitems(rtl8812au_agc_vals1), + rtl8812au_agc_vals1, + { 0 }, + NULL + } + } +}; + +/* + * RF initialization values. + */ +static const uint8_t rtl8812au_rf0_regs0[] = { + 0x00, 0x18, 0x56, 0x66, 0x1e, 0x89 +}, rtl8812au_rf0_regs1[] = { + 0x86 +}, rtl8812au_rf0_regs2[] = { + 0x8b +}, rtl8812au_rf0_regs3[] = { + 0xb1, 0xb3, 0xb4, 0xba, 0x18, 0xef +}, rtl8812au_rf0_regs4[] = { + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b +}, rtl8812au_rf0_regs5[] = { + 0xef, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34 +}, rtl8812au_rf0_regs6[] = { + 0xef, 0xef, 0xdf, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0xef, + 0x51, 0x52, 0x53, 0x54, 0xef, 0x08, 0x18, 0xef, 0x3a, 0x3b, 0x3c, + 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, + 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, + 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, + 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, + 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, + 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, + 0x3a, 0x3b, 0x3c, 0xef +}, rtl8812au_rf0_regs7[] = { + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34 +}, rtl8812au_rf0_regs8[] = { + 0xef, 0x18, 0xef, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0xef, 0x18, 0xef, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0xef, 0xef, 0x3c, 0x3c, 0x3c, +}, rtl8812au_rf0_regs9[] = { + 0xef, 0x18, 0xef, 0xdf, 0x1f +}, rtl8812au_rf0_regs10[] = { + 0x61, 0x62, 0x63, 0x64, 0x65 +}, rtl8812au_rf0_regs11[] = { + 0x08, 0x1c, 0xb4, 0x18, 0xfe, 0xfe, 0xfe, 0xfe, 0xb4, 0x18 +}, rtl8812au_rf1_regs0[] = { + 0x56, 0x66, 0x89 +}, rtl8812au_rf1_regs3[] = { + 0xb1, 0xb3, 0xb4, 0xba, 0x18, 0xef +}; + +static const uint32_t rtl8812au_rf0_vals0[] = { + 0x10000, 0x1712a, 0x51cf2, 0x40000, 0x80000, 0x00080 +}, rtl8812au_rf0_vals1_lna_g0_g5[] = { + 0x14b3a +}, rtl8812au_rf0_vals1[] = { + 0x14b38 +}, rtl8812au_rf0_vals2_lna_a0[] = { + 0x80180 +}, rtl8812au_rf0_vals2[] = { + 0x87180 +}, rtl8812au_rf0_vals3[] = { + 0x1fc1a, 0xf0810, 0x1a78d, 0x86180, 0x00006, 0x02000 +}, rtl8812au_rf0_vals4_lna_g0_g5[] = { + 0x3f218, 0x30a58, 0x2fa58, 0x22590, 0x1fa50, 0x10248, 0x08240 +}, rtl8812au_rf0_vals4[] = { + 0x38a58, 0x37a58, 0x2a590, 0x27a50, 0x18248, 0x10240, 0x08240 +}, rtl8812au_rf0_vals5_pa_g0[] = { + 0x00100, 0x0a4ee, 0x09076, 0x08073, 0x07070, 0x0606d, 0x0506a, + 0x04049, 0x03046, 0x02028, 0x01025, 0x00022 +}, rtl8812au_rf0_vals5[] = { + 0x00100, 0x0adf4, 0x09df1, 0x08dee, 0x07deb, 0x06de8, 0x05de5, + 0x04de2, 0x03ce6, 0x024e7, 0x014e4, 0x004e1 +}, rtl8812au_rf0_vals6[] = { + 0x00000, 0x020a2, 0x00080, 0x00192, 0x08192, 0x10192, 0x00024, + 0x08024, 0x10024, 0x18024, 0x00000, 0x00c21, 0x006d9, 0xfc649, + 0x0017e, 0x00002, 0x08400, 0x1712a, 0x01000, 0x00080, 0x3a02c, + 0x04000, 0x00400, 0x3202c, 0x10000, 0x000a0, 0x2b064, 0x04000, + 0x000d8, 0x23070, 0x04000, 0x00468, 0x1b870, 0x10000, 0x00098, + 0x12085, 0xe4000, 0x00418, 0x0a080, 0xf0000, 0x00418, 0x02080, + 0x10000, 0x00080, 0x7a02c, 0x04000, 0x00400, 0x7202c, 0x10000, + 0x000a0, 0x6b064, 0x04000, 0x000d8, 0x63070, 0x04000, 0x00468, + 0x5b870, 0x10000, 0x00098, 0x52085, 0xe4000, 0x00418, 0x4a080, + 0xf0000, 0x00418, 0x42080, 0x10000, 0x00080, 0xba02c, 0x04000, + 0x00400, 0xb202c, 0x10000, 0x000a0, 0xab064, 0x04000, 0x000d8, + 0xa3070, 0x04000, 0x00468, 0x9b870, 0x10000, 0x00098, 0x92085, + 0xe4000, 0x00418, 0x8a080, 0xf0000, 0x00418, 0x82080, 0x10000, + 0x01100 +}, rtl8812au_rf0_vals7_pa_a0[] = { + 0x4a0b2, 0x490af, 0x48070, 0x4706d, 0x46050, 0x4504d, 0x4404a, + 0x43047, 0x4200a, 0x41007, 0x40004, 0x2a0b2, 0x290af, 0x28070, + 0x2706d, 0x26050, 0x2504d, 0x2404a, 0x23047, 0x2200a, 0x21007, + 0x20004, 0x0a0b2, 0x090af, 0x08070, 0x0706d, 0x06050, 0x0504d, + 0x0404a, 0x03047, 0x0200a, 0x01007, 0x00004 +}, rtl8812au_rf0_vals7_pa_a5[] = { + 0x4a0b2, 0x490af, 0x48070, 0x4706d, 0x4604d, 0x4504a, 0x44047, + 0x43044, 0x42007, 0x41004, 0x40001, 0x2a0b4, 0x290b1, 0x28072, + 0x2706f, 0x2604f, 0x2504c, 0x24049, 0x23046, 0x22009, 0x21006, + 0x20003, 0x0a0b2, 0x090af, 0x08070, 0x0706d, 0x0604d, 0x0504a, + 0x04047, 0x03044, 0x02007, 0x01004, 0x00001 +}, rtl8812au_rf0_vals7[] = { + 0x4adf5, 0x49df2, 0x48def, 0x47dec, 0x46de9, 0x45de6, 0x44de3, + 0x438c8, 0x428c5, 0x418c2, 0x408c0, 0x2adf5, 0x29df2, 0x28def, + 0x27dec, 0x26de9, 0x25de6, 0x24de3, 0x238c8, 0x228c5, 0x218c2, + 0x208c0, 0x0aff7, 0x09df7, 0x08df4, 0x07df1, 0x06dee, 0x05deb, + 0x04de8, 0x038cc, 0x028c9, 0x018c6, 0x008c3 +}, rtl8812au_rf0_vals8_pa_a0_a5[] = { + 0x00000, 0x1712a, 0x00040, 0x001d4, 0x081d4, 0x101d4, 0x201b4, + 0x281b4, 0x301b4, 0x401b4, 0x481b4, 0x501b4, 0x00000, 0x1712a, + 0x00010, 0x04bfb, 0x0cbfb, 0x14bfb, 0x1cbfb, 0x24f4b, 0x2cf4b, + 0x34f4b, 0x3cf4b, 0x44f4b, 0x4cf4b, 0x54f4b, 0x5cf4b, 0x00000, + 0x00008, 0x002cc, 0x00522, 0x00902 +}, rtl8812au_rf0_vals8[] = { + 0x00000, 0x1712a, 0x00040, 0x00188, 0x08147, 0x10147, 0x201d7, + 0x281d7, 0x301d7, 0x401d8, 0x481d8, 0x501d8, 0x00000, 0x1712a, + 0x00010, 0x84eb4, 0x8cc35, 0x94c35, 0x9cc35, 0xa4c35, 0xacc35, + 0xb4c35, 0xbcc35, 0xc4c34, 0xccc35, 0xd4c35, 0xdcc35, 0x00000, + 0x00008, 0x002a8, 0x005a2, 0x00880 +}, rtl8812au_rf0_vals9[] = { + 0x00000, 0x1712a, 0x00002, 0x00080, 0x00064 +}, rtl8812au_rf0_vals10_pa_a0[] = { + 0xfdd43, 0x38f4b, 0x32117, 0x194ac, 0x931d1 +}, rtl8812au_rf0_vals10_pa_a5[] = { + 0xfdd43, 0x38f4b, 0x32117, 0x194ac, 0x931d2 +}, rtl8812au_rf0_vals10[] = { + 0xe5d53, 0x38fcd, 0x114eb, 0x196ac, 0x911d7 +}, rtl8812au_rf0_vals11[] = { + 0x08400, 0x739d2, 0x1e78d, 0x1f12a, 0x0c350, 0x0c350, 0x0c350, + 0x0c350, 0x1a78d, 0x1712a +}, rtl8812au_rf1_vals0[] = { + 0x51cf2, 0x40000, 0x00080 +}, rtl8812au_rf1_vals3[] = { + 0x1fc1a, 0xf0810, 0x1a78d, 0x86180, 0x00006, 0x02000 +}, rtl8812au_rf1_vals6[] = { + 0x00000, 0x020a2, 0x00080, 0x00192, 0x08192, 0x10192, 0x00024, + 0x08024, 0x10024, 0x18024, 0x00000, 0x00c21, 0x006d9, 0xfc649, + 0x0017e, 0x00002, 0x08400, 0x1712a, 0x01000, 0x00080, 0x3a02c, + 0x04000, 0x00400, 0x3202c, 0x10000, 0x000a0, 0x2b064, 0x04000, + 0x000d8, 0x23070, 0x04000, 0x00468, 0x1b870, 0x10000, 0x00098, + 0x12085, 0xe4000, 0x00418, 0x0a080, 0xf0000, 0x00418, 0x02080, + 0x10000, 0x00080, 0x7a02c, 0x04000, 0x00400, 0x7202c, 0x10000, + 0x000a0, 0x6b064, 0x04000, 0x000d8, 0x63070, 0x04000, 0x00468, + 0x5b870, 0x10000, 0x00098, 0x52085, 0xe4000, 0x00418, 0x4a080, + 0xf0000, 0x00418, 0x42080, 0x10000, 0x00080, 0xba02c, 0x04000, + 0x00400, 0xb202c, 0x10000, 0x000a0, 0xab064, 0x04000, 0x000d8, + 0xa3070, 0x04000, 0x00468, 0x9b870, 0x10000, 0x00098, 0x92085, + 0xe4000, 0x00418, 0x8a080, 0xf0000, 0x00418, 0x82080, 0x10000, + 0x01100 +}, rtl8812au_rf1_vals7_pa_a5[] = { + 0x4a0b1, 0x490ae, 0x4806f, 0x4706c, 0x4604c, 0x45049, 0x44046, + 0x43043, 0x42006, 0x41003, 0x40000, 0x2a0b3, 0x290b0, 0x28071, + 0x2706e, 0x2604e, 0x2504b, 0x24048, 0x23045, 0x22008, 0x21005, + 0x20002, 0x0a0b3, 0x090b0, 0x08070, 0x0706d, 0x0604d, 0x0504a, + 0x04047, 0x03044, 0x02007, 0x01004, 0x00001 +}, rtl8812au_rf1_vals8_pa_a0_a5[] = { + 0x00000, 0x1712a, 0x00040, 0x001c5, 0x081c5, 0x101c5, 0x20174, + 0x28174, 0x30174, 0x40185, 0x48185, 0x50185, 0x00000, 0x1712a, + 0x00010, 0x05b8b, 0x0db8b, 0x15b8b, 0x1db8b, 0x262db, 0x2e2db, + 0x362db, 0x3e2db, 0x4553b, 0x4d53b, 0x5553b, 0x5d53b, 0x00000, + 0x00008, 0x002dc, 0x00524, 0x00902 +}, rtl8812au_rf1_vals10_pa_g0_a0[] = { + 0xeac43, 0x38f47, 0x31157, 0x1c4ac, 0x931d1 +}, rtl8812au_rf1_vals10_pa_a5[] = { + 0xeac43, 0x38f47, 0x31157, 0x1c4ac, 0x931d2 +}; + +static const struct rtwn_rf_prog rtl8812au_rf[] = { + /* RF chain 0. */ + { + nitems(rtl8812au_rf0_regs0), + rtl8812au_rf0_regs0, + rtl8812au_rf0_vals0, + { 0 }, + NULL + }, + /* External 2GHz LNA, type 0 or 5. */ + { + nitems(rtl8812au_rf0_regs1), + rtl8812au_rf0_regs1, + rtl8812au_rf0_vals1_lna_g0_g5, + { + R12A_COND_GLNA | R12A_COND_TYPE(0x0), + R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0 + }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs1), + rtl8812au_rf0_regs1, + rtl8812au_rf0_vals1, + { 0 }, + NULL + } + }, + /* External 5GHz LNA, type 0. */ + { + nitems(rtl8812au_rf0_regs2), + rtl8812au_rf0_regs2, + rtl8812au_rf0_vals2_lna_a0, + { R12A_COND_ALNA | R12A_COND_TYPE(0x0), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs2), + rtl8812au_rf0_regs2, + rtl8812au_rf0_vals2, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_rf0_regs3), + rtl8812au_rf0_regs3, + rtl8812au_rf0_vals3, + { 0 }, + NULL + }, + /* External 2GHz LNA, type 0 or 5. */ + { + nitems(rtl8812au_rf0_regs4), + rtl8812au_rf0_regs4, + rtl8812au_rf0_vals4_lna_g0_g5, + { + R12A_COND_GLNA | R12A_COND_TYPE(0x0), + R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0 + }, + /* Others */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs4), + rtl8812au_rf0_regs4, + rtl8812au_rf0_vals4, + { 0 }, + NULL + } + }, + /* External 2GHz PA, type 0. */ + { + nitems(rtl8812au_rf0_regs5), + rtl8812au_rf0_regs5, + rtl8812au_rf0_vals5_pa_g0, + { R12A_COND_GPA | R12A_COND_TYPE(0x0), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs5), + rtl8812au_rf0_regs5, + rtl8812au_rf0_vals5, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_rf0_regs6), + rtl8812au_rf0_regs6, + rtl8812au_rf0_vals6, + { 0 }, + NULL + }, + /* External 5GHz PA, type 0. */ + { + nitems(rtl8812au_rf0_regs7), + rtl8812au_rf0_regs7, + rtl8812au_rf0_vals7_pa_a0, + { R12A_COND_APA | R12A_COND_TYPE(0x0), 0 }, + /* External 5GHz PA, type 5. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs7), + rtl8812au_rf0_regs7, + rtl8812au_rf0_vals7_pa_a5, + { R12A_COND_APA | R12A_COND_TYPE(0x5), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs7), + rtl8812au_rf0_regs7, + rtl8812au_rf0_vals7, + { 0 }, + NULL + } + } + }, + /* External 5GHz PA, type 0 or 5. */ + { + nitems(rtl8812au_rf0_regs8), + rtl8812au_rf0_regs8, + rtl8812au_rf0_vals8_pa_a0_a5, + { + R12A_COND_APA | R12A_COND_TYPE(0x0), + R12A_COND_APA | R12A_COND_TYPE(0x5), 0 + }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs8), + rtl8812au_rf0_regs8, + rtl8812au_rf0_vals8, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_rf0_regs9), + rtl8812au_rf0_regs9, + rtl8812au_rf0_vals9, + { 0 }, + NULL + }, + /* External 5GHz PA, type 0. */ + { + nitems(rtl8812au_rf0_regs10), + rtl8812au_rf0_regs10, + rtl8812au_rf0_vals10_pa_a0, + { R12A_COND_APA | R12A_COND_TYPE(0x0), 0 }, + /* External 5GHz PA, type 5. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs10), + rtl8812au_rf0_regs10, + rtl8812au_rf0_vals10_pa_a5, + { R12A_COND_APA | R12A_COND_TYPE(0x5), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs10), + rtl8812au_rf0_regs10, + rtl8812au_rf0_vals10, + { 0 }, + NULL + } + } + }, + { + nitems(rtl8812au_rf0_regs11), + rtl8812au_rf0_regs11, + rtl8812au_rf0_vals11, + { 0 }, + NULL + }, + { 0, NULL, NULL, { 0 }, NULL }, + /* RF path 2. */ + { + nitems(rtl8812au_rf1_regs0), + rtl8812au_rf1_regs0, + rtl8812au_rf1_vals0, + { 0 }, + NULL + }, + /* rtl8812au_rf[1] */ + /* External 2GHz LNA, type 0 or 5. */ + { + nitems(rtl8812au_rf0_regs1), + rtl8812au_rf0_regs1, + rtl8812au_rf0_vals1_lna_g0_g5, + { + R12A_COND_GLNA | R12A_COND_TYPE(0x0), + R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0 + }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs1), + rtl8812au_rf0_regs1, + rtl8812au_rf0_vals1, + { 0 }, + NULL + } + }, + /* rtl8812au_rf[2] */ + /* External 5GHz LNA, type 0. */ + { + nitems(rtl8812au_rf0_regs2), + rtl8812au_rf0_regs2, + rtl8812au_rf0_vals2_lna_a0, + { R12A_COND_ALNA | R12A_COND_TYPE(0x0), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs2), + rtl8812au_rf0_regs2, + rtl8812au_rf0_vals2, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_rf1_regs3), + rtl8812au_rf1_regs3, + rtl8812au_rf1_vals3, + { 0 }, + NULL + }, + /* rtl8812au_rf[4] */ + /* External 2GHz LNA, type 0 or 5. */ + { + nitems(rtl8812au_rf0_regs4), + rtl8812au_rf0_regs4, + rtl8812au_rf0_vals4_lna_g0_g5, + { + R12A_COND_GLNA | R12A_COND_TYPE(0x0), + R12A_COND_GLNA | R12A_COND_TYPE(0x5), 0 + }, + /* Others */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs4), + rtl8812au_rf0_regs4, + rtl8812au_rf0_vals4, + { 0 }, + NULL + } + }, + /* rtl8812au_rf[5] */ + /* External 2GHz PA, type 0. */ + { + nitems(rtl8812au_rf0_regs5), + rtl8812au_rf0_regs5, + rtl8812au_rf0_vals5_pa_g0, + { R12A_COND_GPA | R12A_COND_TYPE(0x0), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs5), + rtl8812au_rf0_regs5, + rtl8812au_rf0_vals5, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_rf0_regs6), + rtl8812au_rf0_regs6, + rtl8812au_rf1_vals6, + { 0 }, + NULL + }, + /* External 5GHz PA, type 0. */ + { + nitems(rtl8812au_rf0_regs7), + rtl8812au_rf0_regs7, + rtl8812au_rf0_vals7_pa_a0, + { R12A_COND_APA | R12A_COND_TYPE(0x0), 0 }, + /* External 5GHz PA, type 5. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs7), + rtl8812au_rf0_regs7, + rtl8812au_rf1_vals7_pa_a5, + { R12A_COND_APA | R12A_COND_TYPE(0x5), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs7), + rtl8812au_rf0_regs7, + rtl8812au_rf0_vals7, + { 0 }, + NULL + } + } + }, + /* External 5GHz PA, type 0 or 5. */ + { + nitems(rtl8812au_rf0_regs8), + rtl8812au_rf0_regs8, + rtl8812au_rf1_vals8_pa_a0_a5, + { + R12A_COND_APA | R12A_COND_TYPE(0x0), + R12A_COND_APA | R12A_COND_TYPE(0x5), 0 + }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs8), + rtl8812au_rf0_regs8, + rtl8812au_rf0_vals8, + { 0 }, + NULL + } + }, + { + nitems(rtl8812au_rf0_regs9) - 1, + rtl8812au_rf0_regs9, + rtl8812au_rf0_vals9, + { 0 }, + NULL + }, + + /* External 2GHz or 5GHz PA, type 0. */ + { + nitems(rtl8812au_rf0_regs10), + rtl8812au_rf0_regs10, + rtl8812au_rf1_vals10_pa_g0_a0, + { + R12A_COND_GPA | R12A_COND_TYPE(0x0), + R12A_COND_APA | R12A_COND_TYPE(0x0), 0 + }, + /* External 5GHz PA, type 5. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs10), + rtl8812au_rf0_regs10, + rtl8812au_rf1_vals10_pa_a5, + { R12A_COND_APA | R12A_COND_TYPE(0x5), 0 }, + /* Others. */ + &(const struct rtwn_rf_prog){ + nitems(rtl8812au_rf0_regs10), + rtl8812au_rf0_regs10, + rtl8812au_rf0_vals10, + { 0 }, + NULL + } + } + }, + { + 1, + rtl8812au_rf0_regs11, + rtl8812au_rf0_vals11, + { 0 }, + NULL + }, + { 0, NULL, NULL, { 0 }, NULL } +}; + + +/* + * Registers to save before IQ calibration. + */ +static const uint16_t r12a_iq_bb_regs[] = { + 0x520, 0x550, 0x808, 0xa04, 0x90c, 0xc00, 0xe00, 0x838, 0x82c +}; + +static const uint16_t r12a_iq_afe_regs[] = { + 0xc5c, 0xc60, 0xc64, 0xc68, 0xcb0, 0xcb4, 0xe5c, 0xe60, 0xe64, + 0xe68, 0xeb0, 0xeb4 +}; + +static const uint8_t r12a_iq_rf_regs[] = { + 0x65, 0x8f, 0x0 +}; + +#endif /* R12A_PRIV_H */ diff --git a/sys/dev/rtwn/rtl8812a/r12a_reg.h b/sys/dev/rtwn/rtl8812a/r12a_reg.h new file mode 100644 index 000000000000..41cc160f9d16 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_reg.h @@ -0,0 +1,236 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef R12A_REG_H +#define R12A_REG_H + +#include + +/* + * MAC registers. + */ +/* System Configuration. */ +#define R12A_SDIO_CTRL 0x070 +#define R12A_RF_B_CTRL 0x076 +/* Rx DMA Configuration. */ +#define R12A_RXDMA_PRO 0x290 +#define R12A_EARLY_MODE_CONTROL 0x2bc +/* Protocol Configuration. */ +#define R12A_TXPKT_EMPTY 0x41a +#define R12A_ARFR_5G(i) (0x444 + (i) * 8) +#define R12A_CCK_CHECK 0x454 +#define R12A_AMPDU_MAX_TIME 0x456 +#define R12A_AMPDU_MAX_LENGTH R92C_AGGLEN_LMT +#define R12A_DATA_SEC 0x483 +#define R12A_ARFR_2G(i) (0x48c + (i) * 8) +#define R12A_HT_SINGLE_AMPDU 0x4c7 + + +/* Bits for R92C_MAC_PHY_CTRL. */ +#define R12A_MAC_PHY_CRYSTALCAP_M 0x7ff80000 +#define R12A_MAC_PHY_CRYSTALCAP_S 19 + +/* Bits for R92C_LEDCFG2. */ +#define R12A_LEDCFG2_ENA 0x20 + +/* Bits for R12A_CCK_CHECK. */ +#define R12A_CCK_CHECK_BCN1 0x20 +#define R12A_CCK_CHECK_5GHZ 0x80 + +/* Bits for R12A_DATA_SEC. */ +#define R12A_DATA_SEC_NO_EXT 0x00 +#define R12A_DATA_SEC_PRIM_UP_20 0x01 +#define R12A_DATA_SEC_PRIM_DOWN_20 0x02 +#define R12A_DATA_SEC_PRIM_UPPER_20 0x03 +#define R12A_DATA_SEC_PRIM_LOWER_20 0x04 +#define R12A_DATA_SEC_PRIM_UP_40 0x90 +#define R12A_DATA_SEC_PRIM_DOWN_40 0xa0 + +/* Bits for R12A_HT_SINGLE_AMPDU. */ +#define R12A_HT_SINGLE_AMPDU_PKT_ENA 0x80 + +/* Bits for R92C_RCR. */ +#define R12A_RCR_DIS_CHK_14 0x00200000 +#define R12A_RCR_TCP_OFFLD_EN 0x02000000 +#define R12A_RCR_VHT_ACK 0x04000000 + + +/* + * Baseband registers. + */ +#define R12A_CCK_RPT_FORMAT 0x804 +#define R12A_OFDMCCK_EN 0x808 +#define R12A_RX_PATH R12A_OFDMCCK_EN +#define R12A_TX_PATH 0x80c +#define R12A_TXAGC_TABLE_SELECT 0x82c +#define R12A_PWED_TH 0x830 +#define R12A_BW_INDICATION 0x834 +#define R12A_CCA_ON_SEC 0x838 +#define R12A_L1_PEAK_TH 0x848 +#define R12A_FC_AREA 0x860 +#define R12A_RFMOD 0x8ac +#define R12A_HSSI_PARAM2 0x8b0 +#define R12A_ADC_BUF_CLK 0x8c4 +#define R12A_ANTSEL_SW 0x900 +#define R12A_SINGLETONE_CONT_TX 0x914 +#define R12A_CCK_RX_PATH 0xa04 +#define R12A_HSSI_PARAM1(chain) (0xc00 + (chain) * 0x200) +#define R12A_TX_SCALE(chain) (0xc1c + (chain) * 0x200) +#define R12A_TXAGC_CCK11_1(chain) (0xc20 + (chain) * 0x200) +#define R12A_TXAGC_OFDM18_6(chain) (0xc24 + (chain) * 0x200) +#define R12A_TXAGC_OFDM54_24(chain) (0xc28 + (chain) * 0x200) +#define R12A_TXAGC_MCS3_0(chain) (0xc2c + (chain) * 0x200) +#define R12A_TXAGC_MCS7_4(chain) (0xc30 + (chain) * 0x200) +#define R12A_TXAGC_MCS11_8(chain) (0xc34 + (chain) * 0x200) +#define R12A_TXAGC_MCS15_12(chain) (0xc38 + (chain) * 0x200) +#define R12A_TXAGC_NSS1IX3_1IX0(chain) (0xc3c + (chain) * 0x200) +#define R12A_TXAGC_NSS1IX7_1IX4(chain) (0xc40 + (chain) * 0x200) +#define R12A_TXAGC_NSS2IX1_1IX8(chain) (0xc44 + (chain) * 0x200) +#define R12A_TXAGC_NSS2IX5_2IX2(chain) (0xc48 + (chain) * 0x200) +#define R12A_TXAGC_NSS2IX9_2IX6(chain) (0xc4c + (chain) * 0x200) +#define R12A_INITIAL_GAIN(chain) (0xc50 + (chain) * 0x200) +#define R12A_AFE_POWER_1(chain) (0xc60 + (chain) * 0x200) +#define R12A_AFE_POWER_2(chain) (0xc64 + (chain) * 0x200) +#define R12A_SLEEP_NAV(chain) (0xc80 + (chain) * 0x200) +#define R12A_PMPD(chain) (0xc84 + (chain) * 0x200) +#define R12A_LSSI_PARAM(chain) (0xc90 + (chain) * 0x200) +#define R12A_RFE_PINMUX(chain) (0xcb0 + (chain) * 0x200) +#define R12A_RFE_INV(chain) (0xcb4 + (chain) * 0x200) +#define R12A_RFE(chain) (0xcb8 + (chain) * 0x200) +#define R12A_HSPI_READBACK(chain) (0xd04 + (chain) * 0x40) +#define R12A_LSSI_READBACK(chain) (0xd08 + (chain) * 0x40) + +/* Bits for R12A_CCK_RPT_FORMAT. */ +#define R12A_CCK_RPT_FORMAT_HIPWR 0x00010000 + +/* Bits for R12A_OFDMCCK_EN. */ +#define R12A_OFDMCCK_EN_CCK 0x10000000 +#define R12A_OFDMCCK_EN_OFDM 0x20000000 + +/* Bits for R12A_CCA_ON_SEC. */ +#define R12A_CCA_ON_SEC_EXT_CHAN_M 0xf0000000 +#define R12A_CCA_ON_SEC_EXT_CHAN_S 28 + +/* Bits for R12A_RFE_PINMUX(i). */ +#define R12A_RFE_PINMUX_PA_A_MASK 0x000000f0 +#define R12A_RFE_PINMUX_LNA_MASK 0x0000f000 + +/* Bits for R12A_RFMOD. */ +#define R12A_RFMOD_EXT_CHAN_M 0x3C +#define R12A_RFMOD_EXT_CHAN_S 2 + +/* Bits for R12A_HSSI_PARAM2. */ +#define R12A_HSSI_PARAM2_READ_ADDR_MASK 0xff + +/* Bits for R12A_HSSI_PARAM1(i). */ +#define R12A_HSSI_PARAM1_PI 0x00000004 + +/* Bits for R12A_TX_SCALE(i). */ +#define R12A_TX_SCALE_SWING_M 0xffe00000 +#define R12A_TX_SCALE_SWING_S 21 + +/* Bits for R12A_TXAGC_CCK11_1(i). */ +#define R12A_TXAGC_CCK1_M 0x000000ff +#define R12A_TXAGC_CCK1_S 0 +#define R12A_TXAGC_CCK2_M 0x0000ff00 +#define R12A_TXAGC_CCK2_S 8 +#define R12A_TXAGC_CCK55_M 0x00ff0000 +#define R12A_TXAGC_CCK55_S 16 +#define R12A_TXAGC_CCK11_M 0xff000000 +#define R12A_TXAGC_CCK11_S 24 + +/* Bits for R12A_TXAGC_OFDM18_6(i). */ +#define R12A_TXAGC_OFDM06_M 0x000000ff +#define R12A_TXAGC_OFDM06_S 0 +#define R12A_TXAGC_OFDM09_M 0x0000ff00 +#define R12A_TXAGC_OFDM09_S 8 +#define R12A_TXAGC_OFDM12_M 0x00ff0000 +#define R12A_TXAGC_OFDM12_S 16 +#define R12A_TXAGC_OFDM18_M 0xff000000 +#define R12A_TXAGC_OFDM18_S 24 + +/* Bits for R12A_TXAGC_OFDM54_24(i). */ +#define R12A_TXAGC_OFDM24_M 0x000000ff +#define R12A_TXAGC_OFDM24_S 0 +#define R12A_TXAGC_OFDM36_M 0x0000ff00 +#define R12A_TXAGC_OFDM36_S 8 +#define R12A_TXAGC_OFDM48_M 0x00ff0000 +#define R12A_TXAGC_OFDM48_S 16 +#define R12A_TXAGC_OFDM54_M 0xff000000 +#define R12A_TXAGC_OFDM54_S 24 + +/* Bits for R12A_TXAGC_MCS3_0(i). */ +#define R12A_TXAGC_MCS0_M 0x000000ff +#define R12A_TXAGC_MCS0_S 0 +#define R12A_TXAGC_MCS1_M 0x0000ff00 +#define R12A_TXAGC_MCS1_S 8 +#define R12A_TXAGC_MCS2_M 0x00ff0000 +#define R12A_TXAGC_MCS2_S 16 +#define R12A_TXAGC_MCS3_M 0xff000000 +#define R12A_TXAGC_MCS3_S 24 + +/* Bits for R12A_TXAGC_MCS7_4(i). */ +#define R12A_TXAGC_MCS4_M 0x000000ff +#define R12A_TXAGC_MCS4_S 0 +#define R12A_TXAGC_MCS5_M 0x0000ff00 +#define R12A_TXAGC_MCS5_S 8 +#define R12A_TXAGC_MCS6_M 0x00ff0000 +#define R12A_TXAGC_MCS6_S 16 +#define R12A_TXAGC_MCS7_M 0xff000000 +#define R12A_TXAGC_MCS7_S 24 + +/* Bits for R12A_TXAGC_MCS11_8(i). */ +#define R12A_TXAGC_MCS8_M 0x000000ff +#define R12A_TXAGC_MCS8_S 0 +#define R12A_TXAGC_MCS9_M 0x0000ff00 +#define R12A_TXAGC_MCS9_S 8 +#define R12A_TXAGC_MCS10_M 0x00ff0000 +#define R12A_TXAGC_MCS10_S 16 +#define R12A_TXAGC_MCS11_M 0xff000000 +#define R12A_TXAGC_MCS11_S 24 + +/* Bits for R12A_TXAGC_MCS15_12(i). */ +#define R12A_TXAGC_MCS12_M 0x000000ff +#define R12A_TXAGC_MCS12_S 0 +#define R12A_TXAGC_MCS13_M 0x0000ff00 +#define R12A_TXAGC_MCS13_S 8 +#define R12A_TXAGC_MCS14_M 0x00ff0000 +#define R12A_TXAGC_MCS14_S 16 +#define R12A_TXAGC_MCS15_M 0xff000000 +#define R12A_TXAGC_MCS15_S 24 + + +/* + * RF (6052) registers. + */ +#define R12A_RF_LCK 0xb4 + +/* Bits for R12A_RF_LCK. */ +#define R12A_RF_LCK_MODE 0x4000 + +#endif /* R12A_REG_H */ diff --git a/sys/dev/rtwn/rtl8812a/r12a_rf.c b/sys/dev/rtwn/rtl8812a/r12a_rf.c new file mode 100644 index 000000000000..43bd7b9ae608 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_rf.c @@ -0,0 +1,110 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +uint32_t +r12a_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr) +{ + uint32_t pi_mode, val; + + /* Turn off CCA (avoids reading the wrong value). */ + if (addr != R92C_RF_AC) + rtwn_bb_setbits(sc, R12A_CCA_ON_SEC, 0, 0x08); + + val = rtwn_bb_read(sc, R12A_HSSI_PARAM1(chain)); + pi_mode = (val & R12A_HSSI_PARAM1_PI) ? 1 : 0; + + rtwn_bb_setbits(sc, R12A_HSSI_PARAM2, + R12A_HSSI_PARAM2_READ_ADDR_MASK, addr); + + val = rtwn_bb_read(sc, pi_mode ? R12A_HSPI_READBACK(chain) : + R12A_LSSI_READBACK(chain)); + + /* Turn on CCA (when exiting). */ + if (addr != R92C_RF_AC) + rtwn_bb_setbits(sc, R12A_CCA_ON_SEC, 0x08, 0); + + return (MS(val, R92C_LSSI_READBACK_DATA)); +} + +uint32_t +r12a_c_cut_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr) +{ + uint32_t pi_mode, val; + + val = rtwn_bb_read(sc, R12A_HSSI_PARAM1(chain)); + pi_mode = (val & R12A_HSSI_PARAM1_PI) ? 1 : 0; + + rtwn_bb_setbits(sc, R12A_HSSI_PARAM2, + R12A_HSSI_PARAM2_READ_ADDR_MASK, addr); + rtwn_delay(sc, 20); + + val = rtwn_bb_read(sc, pi_mode ? R12A_HSPI_READBACK(chain) : + R12A_LSSI_READBACK(chain)); + + return (MS(val, R92C_LSSI_READBACK_DATA)); +} + +void +r12a_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr, + uint32_t val) +{ + rtwn_bb_write(sc, R12A_LSSI_PARAM(chain), + SM(R88E_LSSI_PARAM_ADDR, addr) | + SM(R92C_LSSI_PARAM_DATA, val)); +} diff --git a/sys/dev/rtwn/rtl8812a/r12a_rom.c b/sys/dev/rtwn/rtl8812a/r12a_rom.c new file mode 100644 index 000000000000..df8bea64653f --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_rom.c @@ -0,0 +1,221 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +void +r12a_parse_rom_common(struct rtwn_softc *sc, uint8_t *buf) +{ + struct r12a_softc *rs = sc->sc_priv; + struct r12a_rom *rom = (struct r12a_rom *)buf; + int i, j; + + sc->thermal_meter = rom->thermal_meter; + rs->crystalcap = RTWN_GET_ROM_VAR(rom->crystalcap, + R12A_ROM_CRYSTALCAP_DEF); + rs->tx_bbswing_2g = RTWN_GET_ROM_VAR(rom->tx_bbswing_2g, 0); + rs->tx_bbswing_5g = RTWN_GET_ROM_VAR(rom->tx_bbswing_5g, 0); + + for (i = 0; i < sc->ntxchains; i++) { + struct r12a_tx_pwr_2g *pwr_2g = &rom->tx_pwr[i].pwr_2g; + struct r12a_tx_pwr_5g *pwr_5g = &rom->tx_pwr[i].pwr_5g; + struct r12a_tx_pwr_diff_2g *pwr_diff_2g = + &rom->tx_pwr[i].pwr_diff_2g; + struct r12a_tx_pwr_diff_5g *pwr_diff_5g = + &rom->tx_pwr[i].pwr_diff_5g; + + for (j = 0; j < R12A_GROUP_2G - 1; j++) { + rs->cck_tx_pwr[i][j] = + RTWN_GET_ROM_VAR(pwr_2g->cck[j], + R12A_DEF_TX_PWR_2G); + rs->ht40_tx_pwr_2g[i][j] = + RTWN_GET_ROM_VAR(pwr_2g->ht40[j], + R12A_DEF_TX_PWR_2G); + } + rs->cck_tx_pwr[i][j] = RTWN_GET_ROM_VAR(pwr_2g->cck[j], + R12A_DEF_TX_PWR_2G); + + rs->cck_tx_pwr_diff_2g[i][0] = 0; + rs->ofdm_tx_pwr_diff_2g[i][0] = RTWN_SIGN4TO8( + MS(pwr_diff_2g->ht20_ofdm, LOW_PART)); + rs->bw20_tx_pwr_diff_2g[i][0] = RTWN_SIGN4TO8( + MS(pwr_diff_2g->ht20_ofdm, HIGH_PART)); + rs->bw40_tx_pwr_diff_2g[i][0] = 0; + + for (j = 1; j < nitems(pwr_diff_2g->diff123); j++) { + rs->cck_tx_pwr_diff_2g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_2g->diff123[j].ofdm_cck, LOW_PART)); + rs->ofdm_tx_pwr_diff_2g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_2g->diff123[j].ofdm_cck, HIGH_PART)); + rs->bw20_tx_pwr_diff_2g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_2g->diff123[j].ht40_ht20, LOW_PART)); + rs->bw40_tx_pwr_diff_2g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_2g->diff123[j].ht40_ht20, HIGH_PART)); + } + + for (j = 0; j < R12A_GROUP_5G; j++) { + rs->ht40_tx_pwr_5g[i][j] = + RTWN_GET_ROM_VAR(pwr_5g->ht40[j], + R12A_DEF_TX_PWR_5G); + } + + rs->ofdm_tx_pwr_diff_5g[i][0] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ht20_ofdm, LOW_PART)); + rs->ofdm_tx_pwr_diff_5g[i][1] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ofdm_ofdm[0], HIGH_PART)); + rs->ofdm_tx_pwr_diff_5g[i][2] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ofdm_ofdm[0], LOW_PART)); + rs->ofdm_tx_pwr_diff_5g[i][3] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ofdm_ofdm[1], LOW_PART)); + + rs->bw20_tx_pwr_diff_5g[i][0] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ht20_ofdm, HIGH_PART)); + rs->bw40_tx_pwr_diff_5g[i][0] = 0; + for (j = 1; j < nitems(pwr_diff_5g->ht40_ht20); j++) { + rs->bw20_tx_pwr_diff_5g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ht40_ht20[j], LOW_PART)); + rs->bw40_tx_pwr_diff_5g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ht40_ht20[j], HIGH_PART)); + } + + for (j = 0; j < nitems(pwr_diff_5g->ht80_ht160); j++) { + rs->bw80_tx_pwr_diff_5g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ht80_ht160[j], HIGH_PART)); + rs->bw160_tx_pwr_diff_5g[i][j] = RTWN_SIGN4TO8( + MS(pwr_diff_5g->ht80_ht160[j], LOW_PART)); + } + } + + rs->regulatory = MS(rom->rf_board_opt, R92C_ROM_RF1_REGULATORY); + rs->board_type = + MS(RTWN_GET_ROM_VAR(rom->rf_board_opt, R92C_BOARD_TYPE_DONGLE), + R92C_ROM_RF1_BOARD_TYPE); + RTWN_DPRINTF(sc, RTWN_DEBUG_ROM, "%s: regulatory type=%d\n", + __func__, rs->regulatory); +} + +void +r12a_parse_rom(struct rtwn_softc *sc, uint8_t *buf) +{ + struct r12a_softc *rs = sc->sc_priv; + struct r12a_rom *rom = (struct r12a_rom *)buf; + uint8_t pa_type, lna_type_2g, lna_type_5g; + + /* Read PA/LNA types. */ + pa_type = RTWN_GET_ROM_VAR(rom->pa_type, 0); + lna_type_2g = RTWN_GET_ROM_VAR(rom->lna_type_2g, 0); + lna_type_5g = RTWN_GET_ROM_VAR(rom->lna_type_5g, 0); + + rs->ext_pa_2g = R12A_ROM_IS_PA_EXT_2GHZ(pa_type); + rs->ext_pa_5g = R12A_ROM_IS_PA_EXT_5GHZ(pa_type); + rs->ext_lna_2g = R21A_ROM_IS_LNA_EXT(lna_type_2g); + rs->ext_lna_5g = R21A_ROM_IS_LNA_EXT(lna_type_5g); + rs->bt_coex = (MS(rom->rf_board_opt, R92C_ROM_RF1_BOARD_TYPE) == + R92C_BOARD_TYPE_HIGHPA); + rs->bt_ant_num = (rom->rf_bt_opt & R12A_RF_BT_OPT_ANT_NUM); + + if (rs->ext_pa_2g) { + rs->type_pa_2g = + R12A_GET_ROM_PA_TYPE(lna_type_2g, 0) | + (R12A_GET_ROM_PA_TYPE(lna_type_2g, 1) << 2); + } + if (rs->ext_pa_5g) { + rs->type_pa_5g = + R12A_GET_ROM_PA_TYPE(lna_type_5g, 0) | + (R12A_GET_ROM_PA_TYPE(lna_type_5g, 1) << 2); + } + if (rs->ext_lna_2g) { + rs->type_lna_2g = + R12A_GET_ROM_LNA_TYPE(lna_type_2g, 0) | + (R12A_GET_ROM_LNA_TYPE(lna_type_2g, 1) << 2); + } + if (rs->ext_lna_5g) { + rs->type_lna_5g = + R12A_GET_ROM_LNA_TYPE(lna_type_5g, 0) | + (R12A_GET_ROM_LNA_TYPE(lna_type_5g, 1) << 2); + } + + if (rom->rfe_option & 0x80) { + if (rs->ext_lna_5g) { + if (rs->ext_pa_5g) { + if (rs->ext_pa_2g && rs->ext_lna_2g) + rs->rfe_type = 3; + else + rs->rfe_type = 0; + } else + rs->rfe_type = 2; + } else + rs->rfe_type = 4; + } else { + rs->rfe_type = rom->rfe_option & 0x3f; + + /* workaround for incorrect EFUSE map */ + if (rs->rfe_type == 4 && + rs->ext_pa_2g && rs->ext_lna_2g && + rs->ext_pa_5g && rs->ext_lna_5g) + rs->rfe_type = 0; + } + + /* Read MAC address. */ + IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr_12a); + + /* Execute common part of initialization. */ + r12a_parse_rom_common(sc, buf); +} diff --git a/sys/dev/rtwn/rtl8812a/r12a_rom_defs.h b/sys/dev/rtwn/rtl8812a/r12a_rom_defs.h new file mode 100644 index 000000000000..4cdb8b54381f --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_rom_defs.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef R12A_ROM_DEFS_H +#define R12A_ROM_DEFS_H + +#include + +#define R12A_GROUP_2G 6 +#define R12A_GROUP_5G 14 + +#define R12A_MAX_TX_COUNT 4 +#define R12A_MAX_RF_PATH 4 + +#define R12A_EFUSE_MAX_LEN 512 +#define R12A_EFUSE_MAP_LEN 512 + +#endif /* R12A_ROM_DEFS_H */ diff --git a/sys/dev/rtwn/rtl8812a/r12a_rom_image.h b/sys/dev/rtwn/rtl8812a/r12a_rom_image.h new file mode 100644 index 000000000000..2349ea5ed1ac --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_rom_image.h @@ -0,0 +1,133 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef R12A_ROM_IMAGE_H +#define R12A_ROM_IMAGE_H + +#include + +#define R12A_DEF_TX_PWR_2G 0x2d +#define R12A_DEF_TX_PWR_5G 0xfe + +struct r12a_tx_pwr_2g { + uint8_t cck[R12A_GROUP_2G]; + uint8_t ht40[R12A_GROUP_2G - 1]; +} __packed; + +struct r12a_tx_pwr_diff_2g { + uint8_t ht20_ofdm; + struct { + uint8_t ht40_ht20; + uint8_t ofdm_cck; + } __packed diff123[R12A_MAX_TX_COUNT - 1]; +} __packed; + +struct r12a_tx_pwr_5g { + uint8_t ht40[R12A_GROUP_5G]; +} __packed; + +struct r12a_tx_pwr_diff_5g { + uint8_t ht20_ofdm; + uint8_t ht40_ht20[R12A_MAX_TX_COUNT - 1]; + uint8_t ofdm_ofdm[2]; + uint8_t ht80_ht160[R12A_MAX_TX_COUNT]; +} __packed; + +struct r12a_tx_pwr { + struct r12a_tx_pwr_2g pwr_2g; + struct r12a_tx_pwr_diff_2g pwr_diff_2g; + struct r12a_tx_pwr_5g pwr_5g; + struct r12a_tx_pwr_diff_5g pwr_diff_5g; +} __packed; + +/* + * RTL8812AU/RTL8821AU ROM image. + */ +struct r12a_rom { + uint8_t reserved1[16]; + struct r12a_tx_pwr tx_pwr[R12A_MAX_RF_PATH]; + uint8_t channel_plan; + uint8_t crystalcap; +#define R12A_ROM_CRYSTALCAP_DEF 0x20 + + uint8_t thermal_meter; + uint8_t iqk_lck; + uint8_t pa_type; +#define R12A_ROM_IS_PA_EXT_2GHZ(pa_type) (((pa_type) & 0x30) == 0x30) +#define R12A_ROM_IS_PA_EXT_5GHZ(pa_type) (((pa_type) & 0x03) == 0x03) +#define R21A_ROM_IS_PA_EXT_2GHZ(pa_type) (((pa_type) & 0x10) == 0x10) +#define R21A_ROM_IS_PA_EXT_5GHZ(pa_type) (((pa_type) & 0x01) == 0x01) + + uint8_t lna_type_2g; +#define R12A_ROM_IS_LNA_EXT(lna_type) (((lna_type) & 0x88) == 0x88) +#define R21A_ROM_IS_LNA_EXT(lna_type) (((lna_type) & 0x08) == 0x08) + +#define R12A_GET_ROM_PA_TYPE(lna_type, chain) \ + (((lna_type) >> ((chain) * 4 + 2)) & 0x01) +#define R12A_GET_ROM_LNA_TYPE(lna_type, chain) \ + (((lna_type) >> ((chain) * 4)) & 0x03) + + uint8_t reserved2; + uint8_t lna_type_5g; + uint8_t reserved3; + uint8_t rf_board_opt; +#define R12A_BOARD_TYPE_COMBO_MF 5 + + uint8_t rf_feature_opt; + uint8_t rf_bt_opt; +#define R12A_RF_BT_OPT_ANT_NUM 0x01 + + uint8_t version; + uint8_t customer_id; + uint8_t tx_bbswing_2g; + uint8_t tx_bbswing_5g; + uint8_t tx_pwr_calib_rate; + uint8_t rf_ant_opt; + uint8_t rfe_option; + uint8_t reserved4[5]; + uint16_t vid_12a; + uint16_t pid_12a; + uint8_t reserved5[3]; + uint8_t macaddr_12a[IEEE80211_ADDR_LEN]; + uint8_t reserved6[35]; + uint16_t vid_21a; + uint16_t pid_21a; + uint8_t reserved7[3]; + uint8_t macaddr_21a[IEEE80211_ADDR_LEN]; + uint8_t reserved8[2]; + /* XXX check on RTL8812AU. */ + uint8_t string[8]; /* "Realtek " */ + uint8_t reserved9[2]; + uint8_t string_ven[23]; /* XXX variable length? */ + uint8_t reserved10[208]; +} __packed; + +_Static_assert(sizeof(struct r12a_rom) == R12A_EFUSE_MAP_LEN, + "R12A_EFUSE_MAP_LEN must be equal to sizeof(struct r12a_rom)!"); + +#endif /* R12A_ROM_IMAGE_H */ diff --git a/sys/dev/rtwn/rtl8812a/r12a_rx.c b/sys/dev/rtwn/rtl8812a/r12a_rx.c new file mode 100644 index 000000000000..319fcd58fb8c --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_rx.c @@ -0,0 +1,238 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + + +#ifndef RTWN_WITHOUT_UCODE +void +r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) +{ +#if __FreeBSD_version >= 1200012 + struct ieee80211_ratectl_tx_status txs; +#endif + struct r12a_c2h_tx_rpt *rpt; + struct ieee80211_node *ni; + int ntries; + + /* Skip Rx descriptor / report id / sequence fields. */ + buf += sizeof(struct r92c_rx_stat) + 2; + len -= sizeof(struct r92c_rx_stat) + 2; + + rpt = (struct r12a_c2h_tx_rpt *)buf; + if (len != sizeof(*rpt)) { + device_printf(sc->sc_dev, + "%s: wrong report size (%d, must be %zu)\n", + __func__, len, sizeof(*rpt)); + return; + } + + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: ccx report dump: 0: %02X, id: %02X, 2: %02X, queue time: " + "low %02X, high %02X, final ridx: %02X, rsvd: %04X\n", + __func__, rpt->txrptb0, rpt->macid, rpt->txrptb2, + rpt->queue_time_low, rpt->queue_time_high, rpt->final_rate, + rpt->reserved); + + if (rpt->macid > sc->macid_limit) { + device_printf(sc->sc_dev, + "macid %u is too big; increase MACID_MAX limit\n", + rpt->macid); + return; + } + + ntries = MS(rpt->txrptb2, R12A_TXRPTB2_RETRY_CNT); + + ni = sc->node_list[rpt->macid]; + if (ni != NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, "%s: frame for macid %u was" + "%s sent (%d retries)\n", __func__, rpt->macid, + (rpt->txrptb0 & (R12A_TXRPTB0_RETRY_OVER | + R12A_TXRPTB0_LIFE_EXPIRE)) ? " not" : "", ntries); + +#if __FreeBSD_version >= 1200012 + txs.flags = IEEE80211_RATECTL_STATUS_LONG_RETRY | + IEEE80211_RATECTL_STATUS_FINAL_RATE; + txs.long_retries = ntries; + if (rpt->final_rate > RTWN_RIDX_OFDM54) { /* MCS */ + txs.final_rate = + (rpt->final_rate - 12) | IEEE80211_RATE_MCS; + } else + txs.final_rate = ridx2rate[rpt->final_rate]; + if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER) + txs.status = IEEE80211_RATECTL_TX_FAIL_LONG; + else if (rpt->txrptb0 & R12A_TXRPTB0_LIFE_EXPIRE) + txs.status = IEEE80211_RATECTL_TX_FAIL_EXPIRED; + else + txs.status = IEEE80211_RATECTL_TX_SUCCESS; + ieee80211_ratectl_tx_complete(ni, &txs); +#else + struct ieee80211vap *vap = ni->ni_vap; + if (rpt->txrptb0 & R12A_TXRPTB0_RETRY_OVER) { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_FAILURE, &ntries, NULL); + } else { + ieee80211_ratectl_tx_complete(vap, ni, + IEEE80211_RATECTL_TX_SUCCESS, &ntries, NULL); + } +#endif + } else { + RTWN_DPRINTF(sc, RTWN_DEBUG_INTR, + "%s: macid %u, ni is NULL\n", __func__, rpt->macid); + } +} + +void +r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len) +{ + struct r12a_softc *rs = sc->sc_priv; + + /* Skip Rx descriptor. */ + buf += sizeof(struct r92c_rx_stat); + len -= sizeof(struct r92c_rx_stat); + + if (len < 2) { + device_printf(sc->sc_dev, "C2H report too short (len %d)\n", + len); + return; + } + len -= 2; + + switch (buf[0]) { /* command id */ + case R12A_C2H_TX_REPORT: + /* NOTREACHED */ + KASSERT(0, ("use handle_tx_report() instead of %s\n", + __func__)); + break; + case R12A_C2H_IQK_FINISHED: + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, + "FW IQ calibration finished\n"); + rs->rs_flags &= ~R12A_IQK_RUNNING; + break; + default: + device_printf(sc->sc_dev, + "%s: C2H report %u was not handled\n", + __func__, buf[0]); + } +} +#else +void +r12a_ratectl_tx_complete(struct rtwn_softc *sc, uint8_t *buf, int len) +{ + /* Should not happen. */ + device_printf(sc->sc_dev, "%s: called\n", __func__); +} + +void +r12a_handle_c2h_report(struct rtwn_softc *sc, uint8_t *buf, int len) +{ + /* Should not happen. */ + device_printf(sc->sc_dev, "%s: called\n", __func__); +} +#endif + +int +r12a_check_frame_checksum(struct rtwn_softc *sc, struct mbuf *m) +{ + struct r12a_softc *rs = sc->sc_priv; + struct r92c_rx_stat *stat; + uint32_t rxdw1; + + stat = mtod(m, struct r92c_rx_stat *); + rxdw1 = le32toh(stat->rxdw1); + if (rxdw1 & R12A_RXDW1_CKSUM) { + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, + "%s: %s/%s checksum is %s\n", __func__, + (rxdw1 & R12A_RXDW1_UDP) ? "UDP" : "TCP", + (rxdw1 & R12A_RXDW1_IPV6) ? "IPv6" : "IP", + (rxdw1 & R12A_RXDW1_CKSUM_ERR) ? "invalid" : "valid"); + + if (rxdw1 & R12A_RXDW1_CKSUM_ERR) + return (-1); + + if ((rxdw1 & R12A_RXDW1_IPV6) ? + (rs->rs_flags & R12A_RXCKSUM6_EN) : + (rs->rs_flags & R12A_RXCKSUM_EN)) { + m->m_pkthdr.csum_flags = CSUM_IP_CHECKED | + CSUM_IP_VALID | CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xffff; + } + } + + return (0); +} + +uint8_t +r12a_rx_radiotap_flags(const void *buf) +{ + const struct r92c_rx_stat *stat = buf; + uint8_t flags, rate; + + if (!(stat->rxdw4 & htole32(R12A_RXDW4_SPLCP))) + return (0); + rate = MS(le32toh(stat->rxdw3), R92C_RXDW3_RATE); + if (RTWN_RATE_IS_CCK(rate)) + flags = IEEE80211_RADIOTAP_F_SHORTPRE; + else + flags = IEEE80211_RADIOTAP_F_SHORTGI; + return (flags); +} diff --git a/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h b/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h new file mode 100644 index 000000000000..8642ca85245f --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_rx_desc.h @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef R12A_RX_DESC_H +#define R12A_RX_DESC_H + +#include + +/* Rx MAC descriptor defines (chip-specific). */ +/* Rx dword 1 */ +#define R12A_RXDW1_AMSDU 0x00002000 +#define R12A_RXDW1_CKSUM_ERR 0x00100000 +#define R12A_RXDW1_IPV6 0x00200000 +#define R12A_RXDW1_UDP 0x00400000 +#define R12A_RXDW1_CKSUM 0x00800000 +/* Rx dword 2 */ +#define R12A_RXDW2_RPT_C2H 0x10000000 +/* Rx dword 4 */ +#define R12A_RXDW4_SPLCP 0x00000001 +#define R12A_RXDW4_LDPC 0x00000002 +#define R12A_RXDW4_STBC 0x00000004 +#define R12A_RXDW4_BW_M 0x00000030 +#define R12A_RXDW4_BW_S 4 + +/* Rx PHY descriptor. */ +struct r12a_rx_phystat { + uint8_t gain_trsw[2]; + uint16_t phyw1; +#define R12A_PHYW1_CHAN_M 0x03ff +#define R12A_PHYW1_CHAN_S 0 +#define R12A_PHYW1_CHAN_EXT_M 0x3c00 +#define R12A_PHYW1_CHAN_EXT_S 10 +#define R12A_PHYW1_RFMOD_M 0xc000 +#define R12A_PHYW1_RFMOD_S 14 + + uint8_t pwdb_all; + uint8_t cfosho[4]; + uint8_t cfotail[4]; + uint8_t rxevm[2]; + uint8_t rxsnr[2]; + uint8_t pcts_msk_rpt[2]; + uint8_t pdsnr[2]; + uint8_t csi_current[2]; + uint8_t rx_gain_c; + uint8_t rx_gain_d; + uint8_t sigevm; + uint16_t phyw13; +#define R12A_PHYW13_ANTIDX_A_M 0x0700 +#define R12A_PHYW13_ANTIDX_A_S 8 +#define R12A_PHYW13_ANTIDX_B_M 0x3800 +#define R12A_PHYW13_ANTIDX_B_S 11 +} __packed; + +#endif /* R12A_RX_DESC_H */ diff --git a/sys/dev/rtwn/rtl8812a/r12a_tx.c b/sys/dev/rtwn/rtl8812a/r12a_tx.c new file mode 100644 index 000000000000..3a286828a902 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_tx.c @@ -0,0 +1,436 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + + +static int +r12a_get_primary_channel(struct rtwn_softc *sc, struct ieee80211_channel *c) +{ + /* XXX 80 MHz */ + if (IEEE80211_IS_CHAN_HT40U(c)) + return (R12A_TXDW5_PRIM_CHAN_20_80_2); + else + return (R12A_TXDW5_PRIM_CHAN_20_80_3); +} + +static void +r12a_tx_set_ht40(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) +{ + struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; + + /* XXX 80 Mhz */ + if (ni->ni_chan != IEEE80211_CHAN_ANYC && + IEEE80211_IS_CHAN_HT40(ni->ni_chan)) { + int prim_chan; + + prim_chan = r12a_get_primary_channel(sc, ni->ni_chan); + txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_BW, + R12A_TXDW5_DATA_BW40)); + txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_PRIM_CHAN, + prim_chan)); + } +} + +static void +r12a_tx_protection(struct rtwn_softc *sc, struct r12a_tx_desc *txd, + enum ieee80211_protmode mode, uint8_t ridx) +{ + struct ieee80211com *ic = &sc->sc_ic; + uint8_t rate; + + switch (mode) { + case IEEE80211_PROT_CTSONLY: + txd->txdw3 |= htole32(R12A_TXDW3_CTS2SELF); + break; + case IEEE80211_PROT_RTSCTS: + txd->txdw3 |= htole32(R12A_TXDW3_RTSEN); + break; + default: + break; + } + + if (mode == IEEE80211_PROT_CTSONLY || + mode == IEEE80211_PROT_RTSCTS) { + if (ridx >= RTWN_RIDX_MCS(0)) + rate = rtwn_ctl_mcsrate(ic->ic_rt, ridx); + else + rate = ieee80211_ctl_rate(ic->ic_rt, ridx2rate[ridx]); + ridx = rate2ridx(rate); + + txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE, ridx)); + /* RTS rate fallback limit (max). */ + txd->txdw4 |= htole32(SM(R12A_TXDW4_RTSRATE_FB_LMT, 0xf)); + + if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + txd->txdw5 |= htole32(R12A_TXDW5_RTS_SHORT); + } +} + +static void +r12a_tx_raid(struct rtwn_softc *sc, struct r12a_tx_desc *txd, + struct ieee80211_node *ni, int ismcast) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct ieee80211_channel *chan; + enum ieee80211_phymode mode; + uint8_t raid; + + chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? + ni->ni_chan : ic->ic_curchan; + mode = ieee80211_chan2mode(chan); + + /* NB: group addressed frames are done at 11bg rates for now */ + if (ismcast || !(ni->ni_flags & IEEE80211_NODE_HT)) { + switch (mode) { + case IEEE80211_MODE_11A: + case IEEE80211_MODE_11B: + case IEEE80211_MODE_11G: + break; + case IEEE80211_MODE_11NA: + mode = IEEE80211_MODE_11A; + break; + case IEEE80211_MODE_11NG: + mode = IEEE80211_MODE_11G; + break; + default: + device_printf(sc->sc_dev, "unknown mode(1) %d!\n", + ic->ic_curmode); + return; + } + } + + switch (mode) { + case IEEE80211_MODE_11A: + raid = R12A_RAID_11G; + break; + case IEEE80211_MODE_11B: + raid = R12A_RAID_11B; + break; + case IEEE80211_MODE_11G: + if (vap->iv_flags & IEEE80211_F_PUREG) + raid = R12A_RAID_11G; + else + raid = R12A_RAID_11BG; + break; + case IEEE80211_MODE_11NA: + if (sc->ntxchains == 1) + raid = R12A_RAID_11GN_1; + else + raid = R12A_RAID_11GN_2; + break; + case IEEE80211_MODE_11NG: + if (sc->ntxchains == 1) { + if (IEEE80211_IS_CHAN_HT40(chan)) + raid = R12A_RAID_11BGN_1_40; + else + raid = R12A_RAID_11BGN_1; + } else { + if (IEEE80211_IS_CHAN_HT40(chan)) + raid = R12A_RAID_11BGN_2_40; + else + raid = R12A_RAID_11BGN_2; + } + break; + default: + /* TODO: 80 MHz / 11ac */ + device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode); + return; + } + + txd->txdw1 |= htole32(SM(R12A_TXDW1_RAID, raid)); +} + +static void +r12a_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) +{ + struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; + struct ieee80211vap *vap = ni->ni_vap; + + if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) && /* HT20 */ + (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)) + txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); + else if (ni->ni_chan != IEEE80211_CHAN_ANYC && /* HT40 */ + IEEE80211_IS_CHAN_HT40(ni->ni_chan) && + (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) && + (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)) + txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); +} + +void +r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, void *buf, uint8_t ridx, int maxretry) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211vap *vap = ni->ni_vap; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211_frame *wh; + struct r12a_tx_desc *txd; + enum ieee80211_protmode prot; + uint8_t type, tid, qos, qsel; + int hasqos, ismcast, macid; + + wh = mtod(m, struct ieee80211_frame *); + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + hasqos = IEEE80211_QOS_HAS_SEQ(wh); + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + + /* Select TX ring for this frame. */ + if (hasqos) { + qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; + tid = qos & IEEE80211_QOS_TID; + } else { + qos = 0; + tid = 0; + } + + /* Fill Tx descriptor. */ + txd = (struct r12a_tx_desc *)buf; + txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG; + if (ismcast) + txd->flags0 |= R12A_FLAGS0_BMCAST; + + if (!ismcast) { + /* Unicast frame, check if an ACK is expected. */ + if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != + IEEE80211_QOS_ACKPOLICY_NOACK) { + txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA); + txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT, + maxretry)); + } + + struct rtwn_node *un = RTWN_NODE(ni); + macid = un->id; + + if (type == IEEE80211_FC0_TYPE_DATA) { + qsel = tid % RTWN_MAX_TID; + + if (m->m_flags & M_AMPDU_MPDU) { + txd->txdw2 |= htole32(R12A_TXDW2_AGGEN); + txd->txdw2 |= htole32(SM(R12A_TXDW2_AMPDU_DEN, + vap->iv_ampdu_density)); + txd->txdw3 |= htole32(SM(R12A_TXDW3_MAX_AGG, + 0x1f)); /* XXX */ + } else + txd->txdw2 |= htole32(R12A_TXDW2_AGGBK); + + if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { + txd->txdw2 |= htole32(R12A_TXDW2_SPE_RPT); + sc->sc_tx_n_active++; + } + + if (RTWN_RATE_IS_CCK(ridx) && ridx != RTWN_RIDX_CCK1 && + (ic->ic_flags & IEEE80211_F_SHPREAMBLE)) + txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); + + prot = IEEE80211_PROT_NONE; + if (ridx >= RTWN_RIDX_MCS(0)) { + r12a_tx_set_ht40(sc, txd, ni); + r12a_tx_set_sgi(sc, txd, ni); + prot = ic->ic_htprotmode; + } else if (ic->ic_flags & IEEE80211_F_USEPROT) + prot = ic->ic_protmode; + + /* XXX fix last comparison for A-MSDU (in net80211) */ + /* XXX A-MPDU? */ + if (m->m_pkthdr.len + IEEE80211_CRC_LEN > + vap->iv_rtsthreshold && + vap->iv_rtsthreshold != IEEE80211_RTS_MAX) + prot = IEEE80211_PROT_RTSCTS; + + if (prot != IEEE80211_PROT_NONE) + r12a_tx_protection(sc, txd, prot, ridx); + } else /* IEEE80211_FC0_TYPE_MGT */ + qsel = R12A_TXDW1_QSEL_MGNT; + } else { + macid = RTWN_MACID_BC; + qsel = R12A_TXDW1_QSEL_MGNT; + } + + txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, qsel)); + txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, macid)); + txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx)); + /* Data rate fallback limit (max). */ + txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f)); + /* XXX recheck for non-21au */ + txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id)); + r12a_tx_raid(sc, txd, ni, ismcast); + + /* Force this rate if needed. */ + if (sc->sc_ratectl != RTWN_RATECTL_FW) + txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE); + + if (!hasqos) { + /* Use HW sequence numbering for non-QoS frames. */ + txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN); + txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id)); + } else { + uint16_t seqno; + + if (m->m_flags & M_AMPDU_MPDU) { + seqno = ni->ni_txseqs[tid]; + /* NB: clear Fragment Number field. */ + *(uint16_t *)wh->i_seq = 0; + ni->ni_txseqs[tid]++; + } else + seqno = M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE; + + /* Set sequence number. */ + txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, seqno)); + } +} + +void +r12a_fill_tx_desc_raw(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, void *buf, const struct ieee80211_bpf_params *params) +{ + struct ieee80211vap *vap = ni->ni_vap; + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct ieee80211_frame *wh; + struct r12a_tx_desc *txd; + uint8_t ridx; + int ismcast; + + /* XXX TODO: 11n checks, matching rtwn_fill_tx_desc() */ + + wh = mtod(m, struct ieee80211_frame *); + ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); + ridx = rate2ridx(params->ibp_rate0); + + /* Fill Tx descriptor. */ + txd = (struct r12a_tx_desc *)buf; + txd->flags0 |= R12A_FLAGS0_LSG | R12A_FLAGS0_FSG; + if (ismcast) + txd->flags0 |= R12A_FLAGS0_BMCAST; + + if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { + txd->txdw4 = htole32(R12A_TXDW4_RETRY_LMT_ENA); + txd->txdw4 |= htole32(SM(R12A_TXDW4_RETRY_LMT, + params->ibp_try0)); + } + if (params->ibp_flags & IEEE80211_BPF_RTS) + r12a_tx_protection(sc, txd, IEEE80211_PROT_RTSCTS, ridx); + if (params->ibp_flags & IEEE80211_BPF_CTS) + r12a_tx_protection(sc, txd, IEEE80211_PROT_CTSONLY, ridx); + + txd->txdw1 |= htole32(SM(R12A_TXDW1_MACID, RTWN_MACID_BC)); + txd->txdw1 |= htole32(SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT)); + + /* Set TX rate index. */ + txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE, ridx)); + txd->txdw4 |= htole32(SM(R12A_TXDW4_DATARATE_FB_LMT, 0x1f)); + txd->txdw6 |= htole32(SM(R21A_TXDW6_MBSSID, uvp->id)); + txd->txdw3 |= htole32(R12A_TXDW3_DRVRATE); + r12a_tx_raid(sc, txd, ni, ismcast); + + if (!IEEE80211_QOS_HAS_SEQ(wh)) { + /* Use HW sequence numbering for non-QoS frames. */ + txd->txdw8 |= htole32(R12A_TXDW8_HWSEQ_EN); + txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, uvp->id)); + } else { + /* Set sequence number. */ + txd->txdw9 |= htole32(SM(R12A_TXDW9_SEQ, + M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE)); + } +} + +void +r12a_fill_tx_desc_null(struct rtwn_softc *sc, void *buf, int is11b, int qos, + int id) +{ + struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; + + txd->flags0 = R12A_FLAGS0_FSG | R12A_FLAGS0_LSG | R12A_FLAGS0_OWN; + txd->txdw1 = htole32( + SM(R12A_TXDW1_QSEL, R12A_TXDW1_QSEL_MGNT)); + + txd->txdw3 = htole32(R12A_TXDW3_DRVRATE); + txd->txdw6 = htole32(SM(R21A_TXDW6_MBSSID, id)); + if (is11b) { + txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE, + RTWN_RIDX_CCK1)); + } else { + txd->txdw4 = htole32(SM(R12A_TXDW4_DATARATE, + RTWN_RIDX_OFDM6)); + } + + if (!qos) { + txd->txdw8 = htole32(R12A_TXDW8_HWSEQ_EN); + txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, id)); + + } +} + +uint8_t +r12a_tx_radiotap_flags(const void *buf) +{ + const struct r12a_tx_desc *txd = buf; + uint8_t flags, rate; + + if (!(txd->txdw5 & htole32(R12A_TXDW5_DATA_SHORT))) + return (0); + + rate = MS(le32toh(txd->txdw4), R12A_TXDW4_DATARATE); + if (RTWN_RATE_IS_CCK(rate)) + flags = IEEE80211_RADIOTAP_F_SHORTPRE; + else + flags = IEEE80211_RADIOTAP_F_SHORTGI; + return (flags); +} diff --git a/sys/dev/rtwn/rtl8812a/r12a_tx_desc.h b/sys/dev/rtwn/rtl8812a/r12a_tx_desc.h new file mode 100644 index 000000000000..9d3ad8b18162 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_tx_desc.h @@ -0,0 +1,149 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef R12A_TX_DESC_H +#define R12A_TX_DESC_H + +/* Tx MAC descriptor (common part). */ +struct r12a_tx_desc { + uint16_t pktlen; + uint8_t offset; + uint8_t flags0; +#define R12A_FLAGS0_BMCAST 0x01 +#define R12A_FLAGS0_LSG 0x04 +#define R12A_FLAGS0_FSG 0x08 +#define R12A_FLAGS0_OWN 0x80 + + uint32_t txdw1; +#define R12A_TXDW1_MACID_M 0x0000003f +#define R12A_TXDW1_MACID_S 0 +#define R12A_TXDW1_QSEL_M 0x00001f00 +#define R12A_TXDW1_QSEL_S 8 + +#define R12A_TXDW1_QSEL_BE 0x00 /* or 0x03 */ +#define R12A_TXDW1_QSEL_BK 0x01 /* or 0x02 */ +#define R12A_TXDW1_QSEL_VI 0x04 /* or 0x05 */ +#define R12A_TXDW1_QSEL_VO 0x06 /* or 0x07 */ +#define RTWN_MAX_TID 8 + +#define R12A_TXDW1_QSEL_BEACON 0x10 +#define R12A_TXDW1_QSEL_MGNT 0x12 + +#define R12A_TXDW1_RAID_M 0x001f0000 +#define R12A_TXDW1_RAID_S 16 +#define R12A_TXDW1_CIPHER_M 0x00c00000 +#define R12A_TXDW1_CIPHER_S 22 +#define R12A_TXDW1_CIPHER_NONE 0 +#define R12A_TXDW1_CIPHER_RC4 1 +#define R12A_TXDW1_CIPHER_SM4 2 +#define R12A_TXDW1_CIPHER_AES 3 +#define R12A_TXDW1_PKTOFF_M 0x1f000000 +#define R12A_TXDW1_PKTOFF_S 24 + + uint32_t txdw2; +#define R12A_TXDW2_AGGEN 0x00001000 +#define R12A_TXDW2_AGGBK 0x00010000 +#define R12A_TXDW2_MOREFRAG 0x00020000 +#define R12A_TXDW2_SPE_RPT 0x00080000 +#define R12A_TXDW2_AMPDU_DEN_M 0x00700000 +#define R12A_TXDW2_AMPDU_DEN_S 20 + + uint32_t txdw3; +#define R12A_TXDW3_SEQ_SEL_M 0x000000c0 +#define R12A_TXDW3_SEQ_SEL_S 6 +#define R12A_TXDW3_DRVRATE 0x00000100 +#define R12A_TXDW3_DISRTSFB 0x00000200 +#define R12A_TXDW3_DISDATAFB 0x00000400 +#define R12A_TXDW3_CTS2SELF 0x00000800 +#define R12A_TXDW3_RTSEN 0x00001000 +#define R12A_TXDW3_HWRTSEN 0x00002000 +#define R12A_TXDW3_MAX_AGG_M 0x003e0000 +#define R12A_TXDW3_MAX_AGG_S 17 + + uint32_t txdw4; +#define R12A_TXDW4_DATARATE_M 0x0000007f +#define R12A_TXDW4_DATARATE_S 0 +#define R12A_TXDW4_DATARATE_FB_LMT_M 0x00001f00 +#define R12A_TXDW4_DATARATE_FB_LMT_S 8 +#define R12A_TXDW4_RTSRATE_FB_LMT_M 0x0001e000 +#define R12A_TXDW4_RTSRATE_FB_LMT_S 13 +#define R12A_TXDW4_RETRY_LMT_ENA 0x00020000 +#define R12A_TXDW4_RETRY_LMT_M 0x00fc0000 +#define R12A_TXDW4_RETRY_LMT_S 18 +#define R12A_TXDW4_RTSRATE_M 0x1f000000 +#define R12A_TXDW4_RTSRATE_S 24 + + uint32_t txdw5; +#define R12A_TXDW5_DATA_PRIM_CHAN_M 0x0000000f +#define R12A_TXDW5_DATA_PRIM_CHAN_S 0 +#define R12A_TXDW5_PRIM_CHAN_20_80_3 1 +#define R12A_TXDW5_PRIM_CHAN_20_80_2 2 +#define R12A_TXDW5_PRIM_CHAN_20_80_4 3 +#define R12A_TXDW5_PRIM_CHAN_20_80_1 4 +#define R12A_TXDW5_PRIM_CHAN_40_80_1 9 +#define R12A_TXDW5_PRIM_CHAN_40_80_2 10 +#define R12A_TXDW5_DATA_SHORT 0x00000010 +#define R12A_TXDW5_DATA_BW_M 0x00000060 +#define R12A_TXDW5_DATA_BW_S 5 +#define R12A_TXDW5_DATA_BW40 1 +#define R12A_TXDW5_DATA_BW80 2 +#define R12A_TXDW5_DATA_LDPC 0x00000080 +#define R12A_TXDW5_RTS_SHORT 0x00001000 +#define R12A_TXDW5_RTS_PRIM_CHAN_M 0x0001e000 +#define R12A_TXDW5_RTS_PRIM_CHAN_S 13 + + uint32_t txdw6; +#define R21A_TXDW6_MBSSID_M 0x0000f000 +#define R21A_TXDW6_MBSSID_S 12 + + uint32_t reserved; + uint32_t txdw8; +#define R12A_TXDW8_HWSEQ_EN 0x00008000 + + uint32_t txdw9; +#define R12A_TXDW9_SEQ_M 0x00fff000 +#define R12A_TXDW9_SEQ_S 12 +} __packed __attribute__((aligned(4))); + + +/* Rate adaptation modes. */ +#define R12A_RAID_11BGN_2_40 0 +#define R12A_RAID_11BGN_1_40 1 +#define R12A_RAID_11BGN_2 2 +#define R12A_RAID_11BGN_1 3 +#define R12A_RAID_11GN_2 4 +#define R12A_RAID_11GN_1 5 +#define R12A_RAID_11BG 6 +#define R12A_RAID_11G 7 /* "pure" 11g */ +#define R12A_RAID_11B 8 +#define R12A_RAID_11AC_2_80 9 +#define R12A_RAID_11AC_1_80 10 +#define R12A_RAID_11AC_1 11 +#define R12A_RAID_11AC_2 12 + +#endif /* R12A_TX_DESC_H */ diff --git a/sys/dev/rtwn/rtl8812a/r12a_var.h b/sys/dev/rtwn/rtl8812a/r12a_var.h new file mode 100644 index 000000000000..9c22cf98ddb7 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/r12a_var.h @@ -0,0 +1,117 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef R12A_VAR_H +#define R12A_VAR_H + +#include + +struct r12a_softc { + uint8_t chip; +#define R12A_CHIP_C_CUT 0x01 + + uint8_t rs_flags; +#define R12A_RXCKSUM_EN 0x01 +#define R12A_RXCKSUM6_EN 0x02 +#define R12A_IQK_RUNNING 0x04 + + /* ROM variables */ + int ext_pa_2g:1, + ext_pa_5g:1, + ext_lna_2g:1, + ext_lna_5g:1, + type_pa_2g:4, + type_pa_5g:4, + type_lna_2g:4, + type_lna_5g:4, + bt_coex:1, + bt_ant_num:1; + + uint8_t board_type; + uint8_t regulatory; + uint8_t crystalcap; + + uint8_t rfe_type; + uint8_t tx_bbswing_2g; + uint8_t tx_bbswing_5g; + + uint8_t cck_tx_pwr[R12A_MAX_RF_PATH][R12A_GROUP_2G]; + uint8_t ht40_tx_pwr_2g[R12A_MAX_RF_PATH][R12A_GROUP_2G]; + uint8_t ht40_tx_pwr_5g[R12A_MAX_RF_PATH][R12A_GROUP_5G]; + + uint8_t cck_tx_pwr_diff_2g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + uint8_t ofdm_tx_pwr_diff_2g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + uint8_t bw20_tx_pwr_diff_2g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + uint8_t bw40_tx_pwr_diff_2g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + + uint8_t ofdm_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + uint8_t bw20_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + uint8_t bw40_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + uint8_t bw80_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + uint8_t bw160_tx_pwr_diff_5g[R12A_MAX_RF_PATH][R12A_MAX_TX_COUNT]; + + int sc_ant; + + void (*rs_crystalcap_write)(struct rtwn_softc *); + void (*rs_fix_spur)(struct rtwn_softc *, + struct ieee80211_channel *); + void (*rs_set_band_2ghz)(struct rtwn_softc *, uint32_t); + void (*rs_set_band_5ghz)(struct rtwn_softc *, uint32_t); + void (*rs_init_burstlen)(struct rtwn_softc *); + void (*rs_init_ampdu_fwhw)(struct rtwn_softc *); +#ifndef RTWN_WITHOUT_UCODE + int (*rs_iq_calib_fw_supported)(struct rtwn_softc *); +#endif + void (*rs_iq_calib_sw)(struct rtwn_softc *); + + int ac_usb_dma_size; + int ac_usb_dma_time; + int ampdu_max_time; +}; +#define R12A_SOFTC(_sc) ((struct r12a_softc *)((_sc)->sc_priv)) + +#define rtwn_r12a_fix_spur(_sc, _c) \ + ((R12A_SOFTC(_sc)->rs_fix_spur)((_sc), (_c))) +#define rtwn_r12a_set_band_2ghz(_sc, _rates) \ + ((R12A_SOFTC(_sc)->rs_set_band_2ghz)((_sc), (_rates))) +#define rtwn_r12a_set_band_5ghz(_sc, _rates) \ + ((R12A_SOFTC(_sc)->rs_set_band_5ghz)((_sc), (_rates))) +#define rtwn_r12a_init_burstlen(_sc) \ + ((R12A_SOFTC(_sc)->rs_init_burstlen)((_sc))) +#define rtwn_r12a_init_ampdu_fwhw(_sc) \ + ((R12A_SOFTC(_sc)->rs_init_ampdu_fwhw)((_sc))) +#define rtwn_r12a_crystalcap_write(_sc) \ + ((R12A_SOFTC(_sc)->rs_crystalcap_write)((_sc))) +#ifndef RTWN_WITHOUT_UCODE +#define rtwn_r12a_iq_calib_fw_supported(_sc) \ + ((R12A_SOFTC(_sc)->rs_iq_calib_fw_supported)((_sc))) +#endif +#define rtwn_r12a_iq_calib_sw(_sc) \ + ((R12A_SOFTC(_sc)->rs_iq_calib_sw)((_sc))) + +#endif /* R12A_VAR_H */ diff --git a/sys/dev/rtwn/rtl8812a/usb/r12au.h b/sys/dev/rtwn/rtl8812a/usb/r12au.h new file mode 100644 index 000000000000..55d132c7c8d9 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/usb/r12au.h @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef RTL8812AU_H +#define RTL8812AU_H + +#include + + +/* + * Function declarations. + */ +/* r12au_init.c */ +void r12au_init_rx_agg(struct rtwn_softc *); +void r12au_init_burstlen(struct rtwn_softc *); +void r12au_init_ampdu_fwhw(struct rtwn_softc *); +void r12au_init_ampdu(struct rtwn_softc *); +void r12au_post_init(struct rtwn_softc *); + +/* r12au_rx.c */ +int r12au_classify_intr(struct rtwn_softc *, void *, int); +int r12au_align_rx(int, int); + +/* r12au_tx.c */ +void r12au_dump_tx_desc(struct rtwn_softc *, const void *); + +#endif /* RTL8812AU_H */ diff --git a/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c b/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c new file mode 100644 index 000000000000..9134dce51afb --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/usb/r12au_attach.c @@ -0,0 +1,289 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include + +#include + +#include +#include +#include +#include + +#include +#include + + +void r12au_attach(struct rtwn_usb_softc *); + +static void +r12au_postattach(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + struct r12a_softc *rs = sc->sc_priv; + + if (usbd_get_speed(uc->uc_udev) == USB_SPEED_SUPER) { + rs->ac_usb_dma_size = 0x07; + rs->ac_usb_dma_time = 0x1a; + } else { + rs->ac_usb_dma_size = 0x01; + rs->ac_usb_dma_time = 0x10; + } + + if (rs->chip & R12A_CHIP_C_CUT) + sc->sc_rf_read = r12a_c_cut_rf_read; + else + sc->sc_rf_read = r12a_rf_read; + + if (rs->board_type == R92C_BOARD_TYPE_MINICARD || + rs->board_type == R92C_BOARD_TYPE_SOLO || + rs->board_type == R92C_BOARD_TYPE_COMBO) + sc->sc_set_led = r88e_set_led; + else + sc->sc_set_led = r12a_set_led; + + if (!(rs->ext_pa_2g || rs->ext_lna_2g || + rs->ext_pa_5g || rs->ext_lna_5g)) + sc->mac_prog = &rtl8812au_mac_no_ext_pa_lna[0]; + + sc->sc_ic.ic_ioctl = r12a_ioctl_net; +} + +void +r12a_vap_preattach(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + struct r12a_softc *rs = sc->sc_priv; + struct ifnet *ifp = vap->iv_ifp; + + ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6; + RTWN_LOCK(sc); + if (rs->rs_flags & R12A_RXCKSUM_EN) + ifp->if_capenable |= IFCAP_RXCSUM; + if (rs->rs_flags & R12A_RXCKSUM6_EN) + ifp->if_capenable |= IFCAP_RXCSUM_IPV6; + RTWN_UNLOCK(sc); +} + +static void +r12a_attach_private(struct rtwn_softc *sc) +{ + struct r12a_softc *rs; + + rs = malloc(sizeof(struct r12a_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO); + + rs->rs_flags = R12A_RXCKSUM_EN | R12A_RXCKSUM6_EN; + + rs->rs_fix_spur = r12a_fix_spur; + rs->rs_set_band_2ghz = r12a_set_band_2ghz; + rs->rs_set_band_5ghz = r12a_set_band_5ghz; + rs->rs_init_burstlen = r12au_init_burstlen; + rs->rs_init_ampdu_fwhw = r12au_init_ampdu_fwhw; + rs->rs_crystalcap_write = r12a_crystalcap_write; +#ifndef RTWN_WITHOUT_UCODE + rs->rs_iq_calib_fw_supported = r12a_iq_calib_fw_supported; +#endif + rs->rs_iq_calib_sw = r12a_iq_calib_sw; + + rs->ampdu_max_time = 0x70; + + sc->sc_priv = rs; +} + +void +r12a_detach_private(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + + free(rs, M_RTWN_PRIV); +} + +static void +r12a_read_chipid_vendor(struct rtwn_softc *sc, uint32_t reg_sys_cfg) +{ + struct r12a_softc *rs = sc->sc_priv; + + if (MS(reg_sys_cfg, R92C_SYS_CFG_CHIP_VER_RTL) == 1) + rs->chip |= R12A_CHIP_C_CUT; +} + +static void +r12au_adj_devcaps(struct rtwn_softc *sc) +{ + /* TODO: LDPC, STBC etc */ +} + +void +r12au_attach(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + + /* USB part. */ + uc->uc_align_rx = r12au_align_rx; + uc->tx_agg_desc_num = 1; + + /* Common part. */ + sc->sc_flags = RTWN_FLAG_EXT_HDR; + + sc->sc_set_chan = r12a_set_chan; + sc->sc_fill_tx_desc = r12a_fill_tx_desc; + sc->sc_fill_tx_desc_raw = r12a_fill_tx_desc_raw; + sc->sc_fill_tx_desc_null = r12a_fill_tx_desc_null; + sc->sc_dump_tx_desc = r12au_dump_tx_desc; + sc->sc_tx_radiotap_flags = r12a_tx_radiotap_flags; + sc->sc_rx_radiotap_flags = r12a_rx_radiotap_flags; + sc->sc_get_rssi_cck = r88e_get_rssi_cck; + sc->sc_get_rssi_ofdm = r88e_get_rssi_ofdm; + sc->sc_classify_intr = r12au_classify_intr; + sc->sc_handle_tx_report = r12a_ratectl_tx_complete; + sc->sc_handle_c2h_report = r12a_handle_c2h_report; + sc->sc_check_frame = r12a_check_frame_checksum; + sc->sc_rf_write = r12a_rf_write; + sc->sc_check_condition = r12a_check_condition; + sc->sc_efuse_postread = rtwn_nop_softc; + sc->sc_parse_rom = r12a_parse_rom; + sc->sc_power_on = r12a_power_on; + sc->sc_power_off = r12a_power_off; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_fw_reset = r12a_fw_reset; + sc->sc_fw_download_enable = r12a_fw_download_enable; +#endif + sc->sc_set_page_size = r12a_set_page_size; + sc->sc_lc_calib = r12a_lc_calib; + sc->sc_iq_calib = r12a_iq_calib; + sc->sc_read_chipid_vendor = r12a_read_chipid_vendor; + sc->sc_adj_devcaps = r12au_adj_devcaps; + sc->sc_vap_preattach = r12a_vap_preattach; + sc->sc_postattach = r12au_postattach; + sc->sc_detach_private = r12a_detach_private; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_set_media_status = r12a_set_media_status; + sc->sc_set_rsvd_page = r88e_set_rsvd_page; + sc->sc_set_pwrmode = r12a_set_pwrmode; + sc->sc_set_rssi = rtwn_nop_softc; /* XXX TODO */ +#else + sc->sc_set_media_status = rtwn_nop_softc_int; +#endif + sc->sc_beacon_init = r12a_beacon_init; + sc->sc_beacon_enable = r92c_beacon_enable; + sc->sc_beacon_set_rate = r12a_beacon_set_rate; + sc->sc_beacon_select = rtwn_nop_softc_int; + sc->sc_temp_measure = r88e_temp_measure; + sc->sc_temp_read = r88e_temp_read; + sc->sc_init_tx_agg = r92cu_init_tx_agg; + sc->sc_init_rx_agg = r12au_init_rx_agg; + sc->sc_init_ampdu = r12au_init_ampdu; + sc->sc_init_intr = r12a_init_intr; + sc->sc_init_edca = r12a_init_edca; + sc->sc_init_bb = r12a_init_bb; + sc->sc_init_rf = r12a_init_rf; + sc->sc_init_antsel = r12a_init_antsel; + sc->sc_post_init = r12au_post_init; + sc->sc_init_bcnq1_boundary = rtwn_nop_int_softc; + + sc->chan_list_5ghz[0] = r12a_chan_5ghz_0; + sc->chan_list_5ghz[1] = r12a_chan_5ghz_1; + sc->chan_list_5ghz[2] = r12a_chan_5ghz_2; + sc->chan_num_5ghz[0] = nitems(r12a_chan_5ghz_0); + sc->chan_num_5ghz[1] = nitems(r12a_chan_5ghz_1); + sc->chan_num_5ghz[2] = nitems(r12a_chan_5ghz_2); + + sc->mac_prog = &rtl8812au_mac[0]; + sc->mac_size = nitems(rtl8812au_mac); + sc->bb_prog = &rtl8812au_bb[0]; + sc->bb_size = nitems(rtl8812au_bb); + sc->agc_prog = &rtl8812au_agc[0]; + sc->agc_size = nitems(rtl8812au_agc); + sc->rf_prog = &rtl8812au_rf[0]; + + sc->name = "RTL8812AU"; + sc->fwname = "rtwn-rtl8812aufw"; + sc->fwsig = 0x950; + + sc->page_count = R12A_TX_PAGE_COUNT; + sc->pktbuf_count = R12A_TXPKTBUF_COUNT; + + sc->ackto = 0x80; + sc->npubqpages = R12A_PUBQ_NPAGES; + sc->page_size = R12A_TX_PAGE_SIZE; + + sc->txdesc_len = sizeof(struct r12au_tx_desc); + sc->efuse_maxlen = R12A_EFUSE_MAX_LEN; + sc->efuse_maplen = R12A_EFUSE_MAP_LEN; + sc->rx_dma_size = R12A_RX_DMA_BUFFER_SIZE; + + sc->macid_limit = R12A_MACID_MAX + 1; + sc->cam_entry_limit = R12A_CAM_ENTRY_COUNT; + sc->fwsize_limit = R12A_MAX_FW_SIZE; + sc->temp_delta = R88E_CALIB_THRESHOLD; + + sc->bcn_status_reg[0] = R92C_TDECTRL; + sc->bcn_status_reg[1] = R92C_TDECTRL; + sc->rcr = R12A_RCR_DIS_CHK_14 | + R12A_RCR_VHT_ACK | + R12A_RCR_TCP_OFFLD_EN; + + sc->ntxchains = 2; + sc->nrxchains = 2; + + r12a_attach_private(sc); +} diff --git a/sys/dev/rtwn/rtl8812a/usb/r12au_init.c b/sys/dev/rtwn/rtl8812a/usb/r12au_init.c new file mode 100644 index 000000000000..06f9c5d5c201 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/usb/r12au_init.c @@ -0,0 +1,187 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + + +void +r12au_init_rx_agg(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + + /* Rx aggregation (USB). */ + rtwn_write_2(sc, R92C_RXDMA_AGG_PG_TH, + rs->ac_usb_dma_size | (rs->ac_usb_dma_time << 8)); + rtwn_setbits_1(sc, R92C_TRXDMA_CTRL, 0, + R92C_TRXDMA_CTRL_RXDMA_AGG_EN); +} + +void +r12au_init_burstlen(struct rtwn_softc *sc) +{ + if (rtwn_read_1(sc, R92C_TYPE_ID + 3) & 0x80) { + if ((rtwn_read_1(sc, R92C_USB_INFO) & 0x30) == 0) { + /* Set burst packet length to 512 B. */ + rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x20, 0x1e); + } else { + /* Set burst packet length to 64 B. */ + rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x10, 0x2e); + } + } else { /* USB 3.0 */ + /* Set burst packet length to 1 KB. */ + rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x30, 0x0e); + + rtwn_setbits_1(sc, 0xf008, 0x18, 0); + } +} + +static void +r12au_arfb_init(struct rtwn_softc *sc) +{ + /* ARFB table 9 for 11ac 5G 2SS. */ + rtwn_write_4(sc, R12A_ARFR_5G(0), 0x00000010); + rtwn_write_4(sc, R12A_ARFR_5G(0) + 4, 0xfffff000); + + /* ARFB table 10 for 11ac 5G 1SS. */ + rtwn_write_4(sc, R12A_ARFR_5G(1), 0x00000010); + rtwn_write_4(sc, R12A_ARFR_5G(1) + 4, 0x003ff000); + + /* ARFB table 11 for 11ac 2G 1SS. */ + rtwn_write_4(sc, R12A_ARFR_2G(0), 0x00000015); + rtwn_write_4(sc, R12A_ARFR_2G(0) + 4, 0x003ff000); + + /* ARFB table 12 for 11ac 2G 2SS. */ + rtwn_write_4(sc, R12A_ARFR_2G(1), 0x00000015); + rtwn_write_4(sc, R12A_ARFR_2G(1) + 4, 0xffcff000); +} + +void +r12au_init_ampdu_fwhw(struct rtwn_softc *sc) +{ + rtwn_setbits_1(sc, R92C_FWHW_TXQ_CTRL, + R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW, 0); +} + +void +r12au_init_ampdu(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + + /* Rx interval (USB3). */ + rtwn_write_1(sc, 0xf050, 0x01); + + /* burst length = 4 */ + rtwn_write_2(sc, R92C_RXDMA_STATUS, 0x7400); + + rtwn_write_1(sc, R92C_RXDMA_STATUS + 1, 0xf5); + + /* Setup AMPDU aggregation. */ + rtwn_write_1(sc, R12A_AMPDU_MAX_TIME, rs->ampdu_max_time); + rtwn_write_4(sc, R12A_AMPDU_MAX_LENGTH, 0xffffffff); + + /* 80 MHz clock (again?) */ + rtwn_write_1(sc, R92C_USTIME_TSF, 0x50); + rtwn_write_1(sc, R92C_USTIME_EDCA, 0x50); + + rtwn_r12a_init_burstlen(sc); + + /* Enable single packet AMPDU. */ + rtwn_setbits_1(sc, R12A_HT_SINGLE_AMPDU, 0, + R12A_HT_SINGLE_AMPDU_PKT_ENA); + + /* 11K packet length for VHT. */ + rtwn_write_1(sc, R92C_RX_PKT_LIMIT, 0x18); + + rtwn_write_1(sc, R92C_PIFS, 0); + + rtwn_write_2(sc, R92C_MAX_AGGR_NUM, 0x1f1f); + + rtwn_r12a_init_ampdu_fwhw(sc); + + /* Do not reset MAC. */ + rtwn_setbits_1(sc, R92C_RSV_CTRL, 0, 0x60); + + r12au_arfb_init(sc); +} + +void +r12au_post_init(struct rtwn_softc *sc) +{ + + /* Setup RTS BW (equal to data BW). */ + rtwn_setbits_1(sc, R92C_QUEUE_CTRL, 0x08, 0); + + rtwn_write_1(sc, R12A_EARLY_MODE_CONTROL + 3, 0x01); + + /* Reset USB mode switch setting. */ + rtwn_write_1(sc, R12A_SDIO_CTRL, 0); + rtwn_write_1(sc, R92C_ACLK_MON, 0); + + rtwn_write_1(sc, R92C_USB_HRPWM, 0); + +#ifndef RTWN_WITHOUT_UCODE + if (sc->sc_flags & RTWN_FW_LOADED) { + if (sc->sc_ratectl_sysctl == RTWN_RATECTL_FW) { + /* TODO: implement */ + sc->sc_ratectl = RTWN_RATECTL_NET80211; + } else + sc->sc_ratectl = sc->sc_ratectl_sysctl; + } else +#endif + sc->sc_ratectl = RTWN_RATECTL_NONE; +} diff --git a/sys/dev/rtwn/rtl8812a/usb/r12au_reg.h b/sys/dev/rtwn/rtl8812a/usb/r12au_reg.h new file mode 100644 index 000000000000..f768c2624878 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/usb/r12au_reg.h @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef R12AU_REG_H +#define R12AU_REG_H + +#include +#include + +#endif /* R12AU_REG_H */ diff --git a/sys/dev/rtwn/rtl8812a/usb/r12au_rx.c b/sys/dev/rtwn/rtl8812a/usb/r12au_rx.c new file mode 100644 index 000000000000..a38fcd333287 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/usb/r12au_rx.c @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include + + +int +r12au_classify_intr(struct rtwn_softc *sc, void *buf, int len) +{ + struct r92c_rx_stat *stat = buf; + uint32_t rxdw2 = le32toh(stat->rxdw2); + + if (rxdw2 & R12A_RXDW2_RPT_C2H) { + int pos = sizeof(struct r92c_rx_stat); + /* Check if Rx descriptor + command id/sequence fits. */ + if (len < pos + 2) /* unknown, skip */ + return (RTWN_RX_DATA); + + if (((uint8_t *)buf)[pos] == R12A_C2H_TX_REPORT) + return (RTWN_RX_TX_REPORT); + else + return (RTWN_RX_OTHER); + } else + return (RTWN_RX_DATA); +} + +int +r12au_align_rx(int totlen, int len) +{ + if (totlen < len) + return (roundup2(totlen, 8)); + + return (totlen); +} diff --git a/sys/dev/rtwn/rtl8812a/usb/r12au_tx.c b/sys/dev/rtwn/rtl8812a/usb/r12au_tx.c new file mode 100644 index 000000000000..51496681591f --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/usb/r12au_tx.c @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r12au_dump_tx_desc(struct rtwn_softc *sc, const void *desc) +{ +#ifdef RTWN_DEBUG + const struct r12au_tx_desc *txd = desc; + + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT_DESC, + "%s: len %d, off %d, flags0 %02X, dw: 1 %08X, 2 %08X, 3 %08X, " + "4 %08X, 5 %08X, 6 %08X, sum %04X, flags7 %04X, 8 %08X, 9 %08X\n", + __func__, le16toh(txd->pktlen), txd->offset, txd->flags0, + le32toh(txd->txdw1), le32toh(txd->txdw2), le32toh(txd->txdw3), + le32toh(txd->txdw4), le32toh(txd->txdw5), le32toh(txd->txdw6), + le16toh(txd->txdsum), le16toh(txd->flags7), le32toh(txd->txdw8), + le32toh(txd->txdw9)); +#endif +} diff --git a/sys/dev/rtwn/rtl8812a/usb/r12au_tx_desc.h b/sys/dev/rtwn/rtl8812a/usb/r12au_tx_desc.h new file mode 100644 index 000000000000..b7613f2bf189 --- /dev/null +++ b/sys/dev/rtwn/rtl8812a/usb/r12au_tx_desc.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef R12AU_TX_DESC_H +#define R12AU_TX_DESC_H + +#include + +/* Tx MAC descriptor (USB). */ +struct r12au_tx_desc { + uint16_t pktlen; + uint8_t offset; + uint8_t flags0; + + uint32_t txdw1; + uint32_t txdw2; + uint32_t txdw3; + uint32_t txdw4; + uint32_t txdw5; + uint32_t txdw6; + + uint16_t txdsum; + uint16_t flags7; +#define R12AU_FLAGS7_AGGNUM_M 0xff00 +#define R12AU_FLAGS7_AGGNUM_S 8 + + uint32_t txdw8; + uint32_t txdw9; +} __packed __attribute__((aligned(4))); + +#endif /* R12AU_TX_DESC_H */ diff --git a/sys/dev/rtwn/rtl8821a/r21a.h b/sys/dev/rtwn/rtl8821a/r21a.h new file mode 100644 index 000000000000..cfc99cb9fbb8 --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/r21a.h @@ -0,0 +1,80 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef RTL8821A_H +#define RTL8821A_H + +/* + * Global definitions. + */ +#define R21A_TX_PAGE_COUNT 243 +#define R21A_BCNQ0_PAGE_COUNT 8 +#define R21A_BCNQ0_BOUNDARY \ + (R21A_TX_PAGE_COUNT + R21A_BCNQ0_PAGE_COUNT + 1) + +#define R21A_TX_PAGE_SIZE 256 + + +/* + * Function declarations. + */ +/* r21a_beacon.c */ +void r21a_beacon_init(struct rtwn_softc *, void *, int); +void r21a_beacon_select(struct rtwn_softc *, int); + +/* r21a_calib.c */ +#ifndef RTWN_WITHOUT_UCODE +int r21a_iq_calib_fw_supported(struct rtwn_softc *); +#endif +void r21a_iq_calib_sw(struct rtwn_softc *); + +/* r21a_chan.c */ +void r21a_set_band_2ghz(struct rtwn_softc *, uint32_t); +void r21a_set_band_5ghz(struct rtwn_softc *, uint32_t); + +/* r21a_fw.c */ +void r21a_fw_reset(struct rtwn_softc *, int); + +/* r21a_init.c */ +int r21a_power_on(struct rtwn_softc *); +void r21a_power_off(struct rtwn_softc *); +int r21a_check_condition(struct rtwn_softc *, const uint8_t[]); +void r21a_crystalcap_write(struct rtwn_softc *); +int r21a_init_bcnq1_boundary(struct rtwn_softc *); +void r21a_init_ampdu_fwhw(struct rtwn_softc *); + +/* r21a_led.c */ +void r21a_set_led(struct rtwn_softc *, int, int); + +/* r21a_rom.c */ +void r21a_parse_rom(struct rtwn_softc *, uint8_t *); + +/* r21a_rx.c */ +int8_t r21a_get_rssi_cck(struct rtwn_softc *, void *); + +#endif /* RTL8821A_H */ diff --git a/sys/dev/rtwn/rtl8821a/r21a_beacon.c b/sys/dev/rtwn/rtl8821a/r21a_beacon.c new file mode 100644 index 000000000000..f88f6def1baf --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/r21a_beacon.c @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + + +void +r21a_beacon_init(struct rtwn_softc *sc, void *buf, int id) +{ + struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; + + r12a_beacon_init(sc, buf, id); + + /* XXX sequence number for beacon 1 is not stable. */ + txd->txdw3 &= ~htole32(R12A_TXDW3_SEQ_SEL_M); + txd->txdw3 |= htole32(SM(R12A_TXDW3_SEQ_SEL, id * 2)); +} + +void +r21a_beacon_select(struct rtwn_softc *sc, int id) +{ + switch (id) { + case 0: + /* Switch to port 0 beacon. */ + rtwn_setbits_1_shift(sc, R21A_DWBCN1_CTRL, + R21A_DWBCN1_CTRL_SEL_BCN1, 0, 2); + break; + case 1: + /* Switch to port 1 beacon. */ + rtwn_setbits_1_shift(sc, R21A_DWBCN1_CTRL, + 0, R21A_DWBCN1_CTRL_SEL_BCN1, 2); + break; + default: + KASSERT(0, ("wrong port id %d\n", id)); + break; + } +} diff --git a/sys/dev/rtwn/rtl8821a/r21a_calib.c b/sys/dev/rtwn/rtl8821a/r21a_calib.c new file mode 100644 index 000000000000..e1f1522e9ae4 --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/r21a_calib.c @@ -0,0 +1,126 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + + +#ifndef RTWN_WITHOUT_UCODE +int +r21a_iq_calib_fw_supported(struct rtwn_softc *sc) +{ + if (sc->fwver == 0x16) + return (1); + + return (0); +} +#endif + +void +r21a_iq_calib_sw(struct rtwn_softc *sc) +{ +#define R21A_MAX_NRXCHAINS 2 + uint32_t saved_bb_vals[nitems(r21a_iq_bb_regs)]; + uint32_t saved_afe_vals[nitems(r21a_iq_afe_regs)]; + uint32_t saved_rf_vals[nitems(r21a_iq_rf_regs) * R21A_MAX_NRXCHAINS]; + + KASSERT(sc->nrxchains <= R21A_MAX_NRXCHAINS, + ("nrxchains > %d (%d)\n", R21A_MAX_NRXCHAINS, sc->nrxchains)); + + RTWN_DPRINTF(sc, RTWN_DEBUG_CALIB, "%s: SW IQ calibration: TODO\n", + __func__); + + /* Save registers. */ + r12a_save_bb_afe_vals(sc, saved_bb_vals, r21a_iq_bb_regs, + nitems(r21a_iq_bb_regs)); + r12a_save_bb_afe_vals(sc, saved_afe_vals, r21a_iq_afe_regs, + nitems(r21a_iq_afe_regs)); + r12a_save_rf_vals(sc, saved_rf_vals, r21a_iq_rf_regs, + nitems(r21a_iq_rf_regs)); + +#ifdef RTWN_TODO + /* Configure MAC. */ + r12a_iq_config_mac(sc); + r21a_iq_tx(sc); +#endif + + /* Restore registers. */ + r12a_restore_rf_vals(sc, saved_rf_vals, r21a_iq_rf_regs, + nitems(r21a_iq_rf_regs)); + r12a_restore_bb_afe_vals(sc, saved_afe_vals, r21a_iq_afe_regs, + nitems(r21a_iq_afe_regs)); + + /* Select page C1. */ + rtwn_bb_setbits(sc, R12A_TXAGC_TABLE_SELECT, 0, 0x80000000); + + rtwn_bb_write(sc, R12A_SLEEP_NAV(0), 0); + rtwn_bb_write(sc, R12A_PMPD(0), 0); + rtwn_bb_write(sc, 0xc88, 0); + rtwn_bb_write(sc, 0xc8c, 0x3c000000); + rtwn_bb_write(sc, 0xc90, 0x80); + rtwn_bb_write(sc, 0xc94, 0); + rtwn_bb_write(sc, 0xcc4, 0x20040000); + rtwn_bb_write(sc, 0xcc8, 0x20000000); + rtwn_bb_write(sc, 0xcb8, 0); + + r12a_restore_bb_afe_vals(sc, saved_bb_vals, r21a_iq_bb_regs, + nitems(r21a_iq_bb_regs)); +#undef R21A_MAX_NRXCHAINS +} diff --git a/sys/dev/rtwn/rtl8821a/r21a_chan.c b/sys/dev/rtwn/rtl8821a/r21a_chan.c new file mode 100644 index 000000000000..49305057d2c1 --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/r21a_chan.c @@ -0,0 +1,153 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include + + +static void +r21a_bypass_ext_lna_2ghz(struct rtwn_softc *sc) +{ + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x00100000, 0); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x00400000, 0); + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), 0, 0x07); + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), 0, 0x0700); +} + +void +r21a_set_band_2ghz(struct rtwn_softc *sc, uint32_t basicrates) +{ + struct r12a_softc *rs = sc->sc_priv; + + /* Enable CCK / OFDM. */ + rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, + 0, R12A_OFDMCCK_EN_CCK | R12A_OFDMCCK_EN_OFDM); + + /* Turn off RF PA and LNA. */ + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), + R12A_RFE_PINMUX_LNA_MASK, 0x7000); + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), + R12A_RFE_PINMUX_PA_A_MASK, 0x70); + + if (rs->ext_lna_2g) { + /* Turn on 2.4 GHz external LNA. */ + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0, 0x00100000); + rtwn_bb_setbits(sc, R12A_RFE_INV(0), 0x00400000, 0); + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), 0x05, 0x02); + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), 0x0500, 0x0200); + } else { + /* Bypass 2.4 GHz external LNA. */ + r21a_bypass_ext_lna_2ghz(sc); + } + + /* Select AGC table. */ + rtwn_bb_setbits(sc, R12A_TX_SCALE(0), 0x0f00, 0); + + rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0x10); + rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0x0f000000, 0x01000000); + + /* Write basic rates. */ + rtwn_set_basicrates(sc, basicrates); + + rtwn_write_1(sc, R12A_CCK_CHECK, 0); +} + +void +r21a_set_band_5ghz(struct rtwn_softc *sc, uint32_t basicrates) +{ + struct r12a_softc *rs = sc->sc_priv; + int ntries; + + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), + R12A_RFE_PINMUX_LNA_MASK, 0x5000); + rtwn_bb_setbits(sc, R12A_RFE_PINMUX(0), + R12A_RFE_PINMUX_PA_A_MASK, 0x40); + + if (rs->ext_lna_2g) { + /* Bypass 2.4 GHz external LNA. */ + r21a_bypass_ext_lna_2ghz(sc); + } + + rtwn_write_1(sc, R12A_CCK_CHECK, R12A_CCK_CHECK_5GHZ); + + for (ntries = 0; ntries < 100; ntries++) { + if ((rtwn_read_2(sc, R12A_TXPKT_EMPTY) & 0x30) == 0x30) + break; + + rtwn_delay(sc, 25); + } + if (ntries == 100) { + device_printf(sc->sc_dev, + "%s: TXPKT_EMPTY check failed (%04X)\n", + __func__, rtwn_read_2(sc, R12A_TXPKT_EMPTY)); + } + + /* Enable OFDM. */ + rtwn_bb_setbits(sc, R12A_OFDMCCK_EN, R12A_OFDMCCK_EN_CCK, + R12A_OFDMCCK_EN_OFDM); + + /* Select AGC table. */ + rtwn_bb_setbits(sc, R12A_TX_SCALE(0), 0x0f00, 0x0100); + + rtwn_bb_setbits(sc, R12A_TX_PATH, 0xf0, 0); + rtwn_bb_setbits(sc, R12A_CCK_RX_PATH, 0, 0x0f000000); + + /* Write basic rates. */ + rtwn_set_basicrates(sc, basicrates); +} diff --git a/sys/dev/rtwn/rtl8821a/r21a_fw.c b/sys/dev/rtwn/rtl8821a/r21a_fw.c new file mode 100644 index 000000000000..b0d0a5bcabbf --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/r21a_fw.c @@ -0,0 +1,78 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + + +#ifndef RTWN_WITHOUT_UCODE +void +r21a_fw_reset(struct rtwn_softc *sc, int reason) +{ + + /* Reset MCU IO wrapper. */ + rtwn_setbits_1(sc, R92C_RSV_CTRL, 0x02, 0); + rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0x01, 0); + + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, + R92C_SYS_FUNC_EN_CPUEN, 0, 1); + + /* Enable MCU IO wrapper. */ + rtwn_setbits_1(sc, R92C_RSV_CTRL, 0x02, 0); + rtwn_setbits_1(sc, R92C_RSV_CTRL + 1, 0, 0x01); + + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, + 0, R92C_SYS_FUNC_EN_CPUEN, 1); +} +#endif diff --git a/sys/dev/rtwn/rtl8821a/r21a_init.c b/sys/dev/rtwn/rtl8821a/r21a_init.c new file mode 100644 index 000000000000..903a1f97017b --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/r21a_init.c @@ -0,0 +1,358 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + + +int +r21a_power_on(struct rtwn_softc *sc) +{ +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while(0) + int ntries; + + /* Clear suspend and power down bits.*/ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_APDM_HPDN, 0, 1)); + + /* Disable GPIO9 as EXT WAKEUP. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_GPIO_INTM + 2, 0x01, 0)); + + /* Enable WL suspend. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE, 0, 1)); + + /* Enable LDOA12 MACRO block for all interfaces. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_LDOA15_CTRL, 0, R92C_LDOA15_CTRL_EN)); + + /* Disable BT_GPS_SEL pins. */ + RTWN_CHK(rtwn_setbits_1(sc, 0x067, 0x10, 0)); + + /* 1 ms delay. */ + rtwn_delay(sc, 1000); + + /* Release analog Ips to digital isolation. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_SYS_ISO_CTRL, + R92C_SYS_ISO_CTRL_IP2MAC, 0)); + + /* Disable SW LPS and WL suspend. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_APFM_RSM | + R92C_APS_FSMCO_AFSM_HSUS | + R92C_APS_FSMCO_AFSM_PCIE, 0, 1)); + + /* Wait for power ready bit. */ + for (ntries = 0; ntries < 5000; ntries++) { + if (rtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) { + device_printf(sc->sc_dev, + "timeout waiting for chip power up\n"); + return (ETIMEDOUT); + } + + /* Release WLON reset. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_RDY_MACON, 2)); + + /* Disable HWPDN. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_APDM_HPDN, 0, 1)); + + /* Disable WL suspend. */ + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, + R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE, 0, 1)); + + RTWN_CHK(rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_APFM_ONMAC, 1)); + for (ntries = 0; ntries < 5000; ntries++) { + if (!(rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_ONMAC)) + break; + rtwn_delay(sc, 10); + } + if (ntries == 5000) + return (ETIMEDOUT); + + /* Switch DPDT_SEL_P output from WL BB. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_LEDCFG3, 0, 0x01)); + + /* switch for PAPE_G/PAPE_A from WL BB; switch LNAON from WL BB. */ + RTWN_CHK(rtwn_setbits_1(sc, 0x067, 0, 0x30)); + + RTWN_CHK(rtwn_setbits_1(sc, 0x025, 0x40, 0)); + + /* Enable falling edge triggering interrupt. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_GPIO_INTM + 1, 0, 0x02)); + + /* Enable GPIO9 interrupt mode. */ + RTWN_CHK(rtwn_setbits_1(sc, 0x063, 0, 0x02)); + + /* Enable GPIO9 input mode. */ + RTWN_CHK(rtwn_setbits_1(sc, 0x062, 0x02, 0)); + + /* Enable HSISR GPIO interrupt. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_HSIMR, 0, 0x01)); + + /* Enable HSISR GPIO9 interrupt. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_HSIMR + 2, 0, 0x02)); + + /* XTAL trim. */ + RTWN_CHK(rtwn_setbits_1(sc, R92C_APE_PLL_CTRL_EXT + 2, 0xFF, 0x82)); + + RTWN_CHK(rtwn_setbits_1(sc, R92C_AFE_MISC, 0, 0x40)); + + /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ + RTWN_CHK(rtwn_write_2(sc, R92C_CR, 0x0000)); + RTWN_CHK(rtwn_setbits_2(sc, R92C_CR, 0, + R92C_CR_HCI_TXDMA_EN | R92C_CR_TXDMA_EN | + R92C_CR_HCI_RXDMA_EN | R92C_CR_RXDMA_EN | + R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN | + ((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) | + R92C_CR_CALTMR_EN)); + + if (rtwn_read_4(sc, R92C_SYS_CFG) & R92C_SYS_CFG_TRP_BT_EN) + RTWN_CHK(rtwn_setbits_1(sc, 0x07C, 0, 0x40)); + + return (0); +#undef RTWN_CHK +} + +void +r21a_power_off(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + int error, ntries; + + /* Stop Rx. */ + error = rtwn_write_1(sc, R92C_CR, 0); + if (error == ENXIO) /* hardware gone */ + return; + + /* Move card to Low Power state. */ + /* Block all Tx queues. */ + rtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); + + for (ntries = 0; ntries < 10; ntries++) { + /* Should be zero if no packet is transmitting. */ + if (rtwn_read_4(sc, R88E_SCH_TXCMD) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: failed to block Tx queues\n", + __func__); + return; + } + + /* CCK and OFDM are disabled, and clock are gated. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BBRSTB, 0); + + rtwn_delay(sc, 1); + + /* Reset whole BB. */ + rtwn_setbits_1(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_BB_GLB_RST, 0); + + /* Reset MAC TRX. */ + rtwn_write_1(sc, R92C_CR, + R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN); + + /* check if removed later. (?) */ + rtwn_setbits_1_shift(sc, R92C_CR, R92C_CR_ENSEC, 0, 1); + + /* Respond TxOK to scheduler */ + rtwn_setbits_1(sc, R92C_DUAL_TSF_RST, 0, R92C_DUAL_TSF_RST_TXOK); + + /* If firmware in ram code, do reset. */ +#ifndef RTWN_WITHOUT_UCODE + if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) + r21a_fw_reset(sc, RTWN_FW_RESET_SHUTDOWN); +#endif + + /* Reset MCU. */ + rtwn_setbits_1_shift(sc, R92C_SYS_FUNC_EN, R92C_SYS_FUNC_EN_CPUEN, + 0, 1); + rtwn_write_1(sc, R92C_MCUFWDL, 0); + + /* Move card to Disabled state. */ + /* Turn off RF. */ + rtwn_write_1(sc, R92C_RF_CTRL, 0); + + rtwn_setbits_1(sc, R92C_LEDCFG3, 0x01, 0); + + /* Enable rising edge triggering interrupt. */ + rtwn_setbits_1(sc, R92C_GPIO_INTM + 1, 0x02, 0); + + /* Release WLON reset. */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, + R92C_APS_FSMCO_RDY_MACON, 2); + + /* Turn off MAC by HW state machine */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0, R92C_APS_FSMCO_APFM_OFF, + 1); + for (ntries = 0; ntries < 10; ntries++) { + /* Wait until it will be disabled. */ + if ((rtwn_read_2(sc, R92C_APS_FSMCO) & + R92C_APS_FSMCO_APFM_OFF) == 0) + break; + + rtwn_delay(sc, 5000); + } + if (ntries == 10) { + device_printf(sc->sc_dev, "%s: could not turn off MAC\n", + __func__); + return; + } + + /* Analog Ips to digital isolation. */ + rtwn_setbits_1(sc, R92C_SYS_ISO_CTRL, 0, R92C_SYS_ISO_CTRL_IP2MAC); + + /* Disable LDOA12 MACRO block. */ + rtwn_setbits_1(sc, R92C_LDOA15_CTRL, R92C_LDOA15_CTRL_EN, 0); + + /* Enable WL suspend. */ + rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_AFSM_PCIE, + R92C_APS_FSMCO_AFSM_HSUS, 1); + + /* Enable GPIO9 as EXT WAKEUP. */ + rtwn_setbits_1(sc, R92C_GPIO_INTM + 2, 0, 0x01); + + rs->rs_flags &= ~R12A_IQK_RUNNING; +} + +int +r21a_check_condition(struct rtwn_softc *sc, const uint8_t cond[]) +{ + struct r12a_softc *rs = sc->sc_priv; + uint8_t mask; + int i; + + RTWN_DPRINTF(sc, RTWN_DEBUG_RESET, + "%s: condition byte 0: %02X; ext 5ghz pa/lna %d/%d\n", + __func__, cond[0], rs->ext_pa_5g, rs->ext_lna_5g); + + if (cond[0] == 0) + return (1); + + mask = 0; + if (rs->ext_pa_5g) + mask |= R21A_COND_EXT_PA_5G; + if (rs->ext_lna_5g) + mask |= R21A_COND_EXT_LNA_5G; + if (rs->bt_coex) + mask |= R21A_COND_BT; + if (!rs->ext_pa_2g && !rs->ext_lna_2g && + !rs->ext_pa_5g && !rs->ext_lna_5g && !rs->bt_coex) + mask = R21A_COND_BOARD_DEF; + + if (mask == 0) + return (0); + + for (i = 0; i < RTWN_MAX_CONDITIONS && cond[i] != 0; i++) + if (cond[i] == mask) + return (1); + + return (0); +} + +void +r21a_crystalcap_write(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + uint32_t reg; + uint8_t val; + + val = rs->crystalcap & 0x3f; + reg = rtwn_bb_read(sc, R92C_MAC_PHY_CTRL); + reg = RW(reg, R21A_MAC_PHY_CRYSTALCAP, val | (val << 6)); + rtwn_bb_write(sc, R92C_MAC_PHY_CTRL, reg); +} + +int +r21a_init_bcnq1_boundary(struct rtwn_softc *sc) +{ +#define RTWN_CHK(res) do { \ + if (res != 0) \ + return (EIO); \ +} while(0) + RTWN_CHK(rtwn_write_1(sc, R88E_TXPKTBUF_BCNQ1_BDNY, + R21A_BCNQ0_BOUNDARY)); + RTWN_CHK(rtwn_write_1(sc, R21A_DWBCN1_CTRL + 1, + R21A_BCNQ0_BOUNDARY)); + RTWN_CHK(rtwn_setbits_1_shift(sc, R21A_DWBCN1_CTRL, 0, + R21A_DWBCN1_CTRL_SEL_EN, 2)); + + return (0); +#undef RTWN_CHK +} + +void +r21a_init_ampdu_fwhw(struct rtwn_softc *sc) +{ + rtwn_write_1(sc, R92C_FWHW_TXQ_CTRL, + R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW); + rtwn_write_4(sc, R92C_FAST_EDCA_CTRL, 0x03087777); +} diff --git a/sys/dev/rtwn/rtl8821a/r21a_led.c b/sys/dev/rtwn/rtl8821a/r21a_led.c new file mode 100644 index 000000000000..3e682c2a5efd --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/r21a_led.c @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + + +void +r21a_set_led(struct rtwn_softc *sc, int led, int on) +{ + if (led == RTWN_LED_LINK) { + rtwn_write_1(sc, R92C_LEDCFG2, + R12A_LEDCFG2_ENA | (on ? 0 : R92C_LEDCFG0_DIS)); + sc->ledlink = on; /* Save LED state. */ + } +} diff --git a/sys/dev/rtwn/rtl8821a/r21a_priv.h b/sys/dev/rtwn/rtl8821a/r21a_priv.h new file mode 100644 index 000000000000..d4cfa46afecf --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/r21a_priv.h @@ -0,0 +1,464 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef R21A_PRIV_H +#define R21A_PRIV_H + +/* + * MAC initialization values. + */ +static const struct rtwn_mac_prog rtl8821au_mac[] = { + { 0x421, 0x0f }, { 0x428, 0x0a }, { 0x429, 0x10 }, { 0x430, 0x00 }, + { 0x431, 0x00 }, { 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 }, + { 0x435, 0x05 }, { 0x436, 0x07 }, { 0x437, 0x08 }, { 0x43c, 0x04 }, + { 0x43d, 0x05 }, { 0x43e, 0x07 }, { 0x43f, 0x08 }, { 0x440, 0x5d }, + { 0x441, 0x01 }, { 0x442, 0x00 }, { 0x444, 0x10 }, { 0x445, 0x00 }, + { 0x446, 0x00 }, { 0x447, 0x00 }, { 0x448, 0x00 }, { 0x449, 0xf0 }, + { 0x44a, 0x0f }, { 0x44b, 0x3e }, { 0x44c, 0x10 }, { 0x44d, 0x00 }, + { 0x44e, 0x00 }, { 0x44f, 0x00 }, { 0x450, 0x00 }, { 0x451, 0xf0 }, + { 0x452, 0x0f }, { 0x453, 0x00 }, { 0x456, 0x5e }, { 0x460, 0x66 }, + { 0x461, 0x66 }, { 0x4c8, 0x3f }, { 0x4c9, 0xff }, { 0x4cc, 0xff }, + { 0x4cd, 0xff }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, + { 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, + { 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, + { 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, + { 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, + { 0x516, 0x0a }, { 0x525, 0x4f }, { 0x550, 0x10 }, { 0x551, 0x10 }, + { 0x559, 0x02 }, { 0x55c, 0x50 }, { 0x55d, 0xff }, { 0x605, 0x30 }, + { 0x607, 0x07 }, { 0x608, 0x0e }, { 0x609, 0x2a }, { 0x620, 0xff }, + { 0x621, 0xff }, { 0x622, 0xff }, { 0x623, 0xff }, { 0x624, 0xff }, + { 0x625, 0xff }, { 0x626, 0xff }, { 0x627, 0xff }, { 0x638, 0x50 }, + { 0x63c, 0x0a }, { 0x63d, 0x0a }, { 0x63e, 0x0e }, { 0x63f, 0x0e }, + { 0x640, 0x40 }, { 0x642, 0x40 }, { 0x643, 0x00 }, { 0x652, 0xc8 }, + { 0x66e, 0x05 }, { 0x700, 0x21 }, { 0x701, 0x43 }, { 0x702, 0x65 }, + { 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 }, { 0x70a, 0x65 }, + { 0x70b, 0x87 }, { 0x718, 0x40 } +}; + + +/* + * Baseband initialization values. + */ +#define R21A_COND_EXT_PA_5G 0x01 +#define R21A_COND_EXT_LNA_5G 0x02 +#define R21A_COND_BOARD_DEF 0x04 +#define R21A_COND_BT 0x08 + +static const uint16_t rtl8821au_bb_regs[] = { + 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, 0x820, 0x824, + 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, 0x840, 0x844, 0x848, + 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, 0x864, 0x868, 0x86c, + 0x870, 0x874, 0x878, 0x87c, 0x8a0, 0x8a4, 0x8a8, 0x8ac, 0x8b4, + 0x8b8, 0x8bc, 0x8c0, 0x8c4, 0x8c8, 0x8cc, 0x8d4, 0x8d8, 0x8f8, + 0x8fc, 0x900, 0x90c, 0x910, 0x914, 0x918, 0x91c, 0x920, 0x924, + 0x928, 0x92c, 0x930, 0x934, 0x960, 0x964, 0x968, 0x96c, 0x970, + 0x974, 0x978, 0x97c, 0x980, 0x984, 0x988, 0x990, 0x994, 0x998, + 0x99c, 0x9a0, 0x9a4, 0x9a8, 0x9ac, 0x9b0, 0x9b4, 0x9b8, 0x9bc, + 0x9d0, 0x9d4, 0x9d8, 0x9dc, 0x9e0, 0x9e4, 0x9e8, 0xa00, 0xa04, + 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, 0xa20, 0xa24, 0xa28, + 0xa2c, 0xa70, 0xa74, 0xa78, 0xa7c, 0xa80, 0xa84, 0xb00, 0xb04, + 0xb08, 0xb0c, 0xb10, 0xb14, 0xb18, 0xb1c, 0xb20, 0xb24, 0xb28, + 0xb2c, 0xb30, 0xb34, 0xb38, 0xb3c, 0xb40, 0xb44, 0xb48, 0xb4c, + 0xb50, 0xb54, 0xb58, 0xb5c, 0xc00, 0xc04, 0xc08, 0xc0c, 0xc10, + 0xc14, 0xc1c, 0xc20, 0xc24, 0xc28, 0xc2c, 0xc30, 0xc34, 0xc38, + 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, 0xc54, 0xc58, 0xc5c, + 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, 0xc74, 0xc78, 0xc7c, 0xc80, + 0xc84, 0xc94, 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcb0, 0xcb4, + 0xcb8 +}; + +static const uint32_t rtl8821au_bb_vals[] = { + 0x0020d090, 0x080112e0, 0x0e028211, 0x92131111, 0x20101261, + 0x020c3d10, 0x03a00385, 0x00000000, 0x00030fe0, 0x00000000, + 0x002081dd, 0x2aaaeec8, 0x0037a706, 0x06489b44, 0x0000095b, + 0xc0000001, 0x40003cde, 0x62103f8b, 0x6cfdffb8, 0x28874706, + 0x0001520c, 0x8060e000, 0x74210168, 0x6929c321, 0x79727432, + 0x8ca7a314, 0x888c2878, 0x08888888, 0x31612c2e, 0x00000152, + 0x000fd000, 0x00000013, 0x7f7f7f7f, 0xa2000338, 0x0ff0fa0a, + 0x000fc080, 0x6c10d7ff, 0x0ca52090, 0x1bf00020, 0x00000000, + 0x00013169, 0x08248492, 0x940008a0, 0x290b5612, 0x400002c0, + 0x00000000, 0x00000700, 0x00000000, 0x0000fc00, 0x00000404, + 0x1c1028c0, 0x64b11a1c, 0xe0767233, 0x055aa500, 0x00000004, + 0xfffe0000, 0xfffffffe, 0x001fffff, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x801fffff, 0x000003ff, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x27100000, + 0xffff0100, 0xffffff5c, 0xffffffff, 0x000000ff, 0x00480080, + 0x00000000, 0x00000000, 0x81081008, 0x01081008, 0x01081008, + 0x01081008, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00005d00, 0x00000003, 0x00000001, 0x00d047c8, 0x01ff800c, + 0x8c8a8300, 0x2e68000f, 0x9500bb78, 0x11144028, 0x00881117, + 0x89140f00, 0x1a1b0000, 0x090e1317, 0x00000204, 0x00900000, + 0x101fff00, 0x00000008, 0x00000900, 0x225b0606, 0x21805490, + 0x001f0000, 0x03100040, 0x0000b000, 0xae0201eb, 0x01003207, + 0x00009807, 0x01000000, 0x00000002, 0x00000002, 0x0000001f, + 0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c, 0x13121110, + 0x17161514, 0x0000003a, 0x00000000, 0x00000000, 0x13000032, + 0x48080000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000007, 0x00042020, 0x80410231, 0x00000000, 0x00000100, + 0x01000000, 0x40000003, 0x2c2c2c2c, 0x30303030, 0x30303030, + 0x2c2c2c2c, 0x2c2c2c2c, 0x2c2c2c2c, 0x2c2c2c2c, 0x2a2a2a2a, + 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000020, + 0x001c1208, 0x30000c1c, 0x00000058, 0x34344443, 0x07003333, + 0x19791979, 0x19791979, 0x19791979, 0x19791979, 0x19791979, + 0x19791979, 0x19791979, 0x19791979, 0x0100005c, 0x00000000, + 0x00000000, 0x00000029, 0x08040201, 0x80402010, 0x77775747, + 0x10000077, 0x00508240 +}; + +static const struct rtwn_bb_prog rtl8821au_bb[] = { + { + nitems(rtl8821au_bb_regs), + rtl8821au_bb_regs, + rtl8821au_bb_vals, + { 0 }, + NULL + } +}; + +static const uint32_t rtl8821au_agc_vals0[] = { + 0xbf000001, 0xbf020001, 0xbf040001, 0xbf060001, 0xbe080001, + 0xbd0a0001, 0xbc0c0001, 0xba0e0001, 0xb9100001, 0xb8120001, + 0xb7140001, 0xb6160001, 0xb5180001, 0xb41a0001, 0xb31c0001, + 0xb21e0001, 0xb1200001, 0xb0220001, 0xaf240001, 0xae260001, + 0xad280001, 0xac2a0001, 0xab2c0001, 0xaa2e0001, 0xa9300001, + 0xa8320001, 0xa7340001, 0xa6360001, 0xa5380001, 0xa43a0001, + 0x683c0001, 0x673e0001, 0x66400001, 0x65420001, 0x64440001, + 0x63460001, 0x62480001, 0x614a0001, 0x474c0001, 0x464e0001, + 0x45500001, 0x44520001, 0x43540001, 0x42560001, 0x41580001, + 0x285a0001, 0x275c0001, 0x265e0001, 0x25600001, 0x24620001, + 0x0a640001, 0x09660001, 0x08680001, 0x076a0001, 0x066c0001, + 0x056e0001, 0x04700001, 0x03720001, 0x02740001, 0x01760001, + 0x01780001, 0x017a0001, 0x017c0001, 0x017e0001 +}, rtl8821au_agc_vals1_pa_lna_5g[] = { + 0xfb000101, 0xfa020101, 0xf9040101, 0xf8060101, 0xf7080101, + 0xf60a0101, 0xf50c0101, 0xf40e0101, 0xf3100101, 0xf2120101, + 0xf1140101, 0xf0160101, 0xef180101, 0xee1a0101, 0xed1c0101, + 0xec1e0101, 0xeb200101, 0xea220101, 0xe9240101, 0xe8260101, + 0xe7280101, 0xe62a0101, 0xe52c0101, 0xe42e0101, 0xe3300101, + 0xa5320101, 0xa4340101, 0xa3360101, 0x87380101, 0x863a0101, + 0x853c0101, 0x843e0101, 0x69400101, 0x68420101, 0x67440101, + 0x66460101, 0x49480101, 0x484a0101, 0x474c0101, 0x2a4e0101, + 0x29500101, 0x28520101, 0x27540101, 0x26560101, 0x25580101, + 0x245a0101, 0x235c0101, 0x055e0101, 0x04600101, 0x03620101, + 0x02640101, 0x01660101, 0x01680101, 0x016a0101, 0x016c0101, + 0x016e0101, 0x01700101, 0x01720101 +}, rtl8821au_agc_vals1[] = { + 0xff000101, 0xff020101, 0xfe040101, 0xfd060101, 0xfc080101, + 0xfd0a0101, 0xfc0c0101, 0xfb0e0101, 0xfa100101, 0xf9120101, + 0xf8140101, 0xf7160101, 0xf6180101, 0xf51a0101, 0xf41c0101, + 0xf31e0101, 0xf2200101, 0xf1220101, 0xf0240101, 0xef260101, + 0xee280101, 0xed2a0101, 0xec2c0101, 0xeb2e0101, 0xea300101, + 0xe9320101, 0xe8340101, 0xe7360101, 0xe6380101, 0xe53a0101, + 0xe43c0101, 0xe33e0101, 0xa5400101, 0xa4420101, 0xa3440101, + 0x87460101, 0x86480101, 0x854a0101, 0x844c0101, 0x694e0101, + 0x68500101, 0x67520101, 0x66540101, 0x49560101, 0x48580101, + 0x475a0101, 0x2a5c0101, 0x295e0101, 0x28600101, 0x27620101, + 0x26640101, 0x25660101, 0x24680101, 0x236a0101, 0x056c0101, + 0x046e0101, 0x03700101, 0x02720101 +}, rtl8821au_agc_vals2[] = { + 0x01740101, 0x01760101, 0x01780101, 0x017a0101, 0x017c0101, + 0x017e0101 +}; + +static const struct rtwn_agc_prog rtl8821au_agc[] = { + { + nitems(rtl8821au_agc_vals0), + rtl8821au_agc_vals0, + { 0 }, + NULL + }, + /* + * For devices with external 5GHz PA / LNA. + */ + { + nitems(rtl8821au_agc_vals1_pa_lna_5g), + rtl8821au_agc_vals1_pa_lna_5g, + { R21A_COND_EXT_PA_5G | R21A_COND_EXT_LNA_5G, 0 }, + /* + * Others. + */ + &(const struct rtwn_agc_prog){ + nitems(rtl8821au_agc_vals1), + rtl8821au_agc_vals1, + { 0 }, + NULL + } + }, + { + nitems(rtl8821au_agc_vals2), + rtl8821au_agc_vals2, + { 0 }, + NULL + } +}; + + +/* + * RF initialization values. + */ +static const uint8_t rtl8821au_rf_regs0[] = { + 0x18, 0x56, 0x66, 0x00, 0x1e, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0xef, 0x3e, 0x3f, + 0x3e, 0x3f, 0x3e, 0x3f, 0x3e, 0x3f, 0xef, 0x18, 0x89, 0x8b, 0xef, + 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, + 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, + 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, + 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, + 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, + 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0x3a, 0x3b, 0x3c, 0xef, 0xef +}, rtl8821au_rf_regs1[] = { + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34 +}, rtl8821au_rf_regs2[] = { + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0xef, 0x18, + 0xef +}, rtl8821au_rf_regs3[] = { + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0xef, 0x18, + 0xef, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xef, 0xef, 0x3c, 0x3c +}, rtl8821au_rf_regs4[] = { + 0x3c, 0xef, 0x18, 0xef, 0x08, 0xef, 0xdf, 0x1f, 0x58, 0x59, 0x61, + 0x62, 0x63, 0x64, 0x65 +}, rtl8821au_rf_regs5[] = { + 0x18, 0xef, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xef, 0xef, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0xef, 0xed, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0xed, 0xed, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xed, + 0xef, 0xdf, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0xef, 0x51, + 0x52, 0x53, 0x54, 0x56, 0x51, 0x52, 0x53, 0x70, 0x71, 0x72, 0x74, + 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0xed, 0x45, 0x45, 0x45, + 0x46, 0x46, 0x46, 0x46, 0xdf, 0xb3, 0xb4, 0xb7, 0x1c, 0xc4, 0x18, + 0xfe, 0xfe, 0x18, +}; + +static const uint32_t rtl8821au_rf_vals0[] = { + 0x1712a, 0x51cf2, 0x40000, 0x10000, 0x80000, 0x00830, 0x21800, + 0x28000, 0x48000, 0x94838, 0x44980, 0x48000, 0x0d480, 0x42240, + 0xf0380, 0x90000, 0x22852, 0x65540, 0x88001, 0x20000, 0x00380, + 0x90018, 0x20380, 0xa0018, 0x40308, 0xa0018, 0x60018, 0xa0018, + 0x00000, 0x1712a, 0x00080, 0x80180, 0x01000, 0x00244, 0x38027, + 0x82000, 0x00244, 0x30113, 0x82000, 0x0014c, 0x28027, 0x82000, + 0x000cc, 0x27027, 0x42000, 0x0014c, 0x1f913, 0x42000, 0x0010c, + 0x17f10, 0x12000, 0x000d0, 0x08027, 0xca000, 0x00244, 0x78027, + 0x82000, 0x00244, 0x70113, 0x82000, 0x0014c, 0x68027, 0x82000, + 0x000cc, 0x67027, 0x42000, 0x0014c, 0x5f913, 0x42000, 0x0010c, + 0x57f10, 0x12000, 0x000d0, 0x48027, 0xca000, 0x00244, 0xb8027, + 0x82000, 0x00244, 0xb0113, 0x82000, 0x0014c, 0xa8027, 0x82000, + 0x000cc, 0xa7027, 0x42000, 0x0014c, 0x9f913, 0x42000, 0x0010c, + 0x97f10, 0x12000, 0x000d0, 0x88027, 0xca000, 0x00000, 0x01100 +}, rtl8821au_rf_vals1_def_or_bt[] = { + 0x4adf5, 0x49df2, 0x48def, 0x47dec, 0x46de9, 0x45ccb, 0x4488d, + 0x4348d, 0x4248a, 0x4108d, 0x4008a, 0x2adf4, 0x29df1 +}, rtl8821au_rf_vals1_ext_5g[] = { + 0x4a0f3, 0x490b1, 0x480ae, 0x470ab, 0x4608b, 0x45069, 0x44048, + 0x43045, 0x42026, 0x41023, 0x40002, 0x2a0f3, 0x290f0 +}, rtl8821au_rf_vals1[] = { + 0x4adf7, 0x49df3, 0x48def, 0x47dec, 0x46de9, 0x45ccb, 0x4488d, + 0x4348d, 0x4248a, 0x4108d, 0x4008a, 0x2adf7, 0x29df2 +}, rtl8821au_rf_vals2_ext_5g[] = { + 0x280af, 0x270ac, 0x2608b, 0x25069, 0x24048, 0x23045, 0x22026, + 0x21023, 0x20002, 0x0a0d7, 0x090d3, 0x080b1, 0x070ae, 0x0608d, + 0x0506b, 0x0404a, 0x03047, 0x02044, 0x01025, 0x00004, 0x00000, + 0x1712a, 0x00040 +}, rtl8821au_rf_vals2[] = { + 0x28dee, 0x27deb, 0x26ccd, 0x25cca, 0x2488c, 0x2384c, 0x22849, + 0x21449, 0x2004d, 0x0adf7, 0x09df4, 0x08df1, 0x07dee, 0x06dcd, + 0x05ccd, 0x04cca, 0x0388c, 0x02888, 0x01488, 0x00486, 0x00000, + 0x1712a, 0x00040 +}, rtl8821au_rf_vals3_def_or_bt[] = { + 0x00128, 0x08128, 0x10128, 0x201c8, 0x281c8, 0x301c8, 0x401c8, + 0x481c8, 0x501c8, 0x00000, 0x1712a, 0x00010, 0x063b5, 0x0e3b5, + 0x163b5, 0x1e3b5, 0x263b5, 0x2e3b5, 0x363b5, 0x3e3b5, 0x463b5, + 0x4e3b5, 0x563b5, 0x5e3b5, 0x00000, 0x00008, 0x001b6, 0x00492 +}, rtl8821au_rf_vals3[] = { + 0x00145, 0x08145, 0x10145, 0x20196, 0x28196, 0x30196, 0x401c7, + 0x481c7, 0x501c7, 0x00000, 0x1712a, 0x00010, 0x056b3, 0x0d6b3, + 0x156b3, 0x1d6b3, 0x26634, 0x2e634, 0x36634, 0x3e634, 0x467b4, + 0x4e7b4, 0x567b4, 0x5e7b4, 0x00000, 0x00008, 0x0022a, 0x00594 +}, rtl8821au_rf_vals4_def_or_bt[] = { + 0x00800, 0x00000, 0x1712a, 0x00002, 0x02000, 0x00000, 0x000c0, + 0x00064, 0x81184, 0x6016c, 0xefd83, 0x93fcc, 0x110eb, 0x1c27c, + 0x93016 +}, rtl8821au_rf_vals4_ext_5g[] = { + 0x00820, 0x00000, 0x1712a, 0x00002, 0x02000, 0x00000, 0x000c0, + 0x00064, 0x81184, 0x6016c, 0xead53, 0x93bc4, 0x110e9, 0x1c67c, + 0x93015 +}, rtl8821au_rf_vals4[] = { + 0x00900, 0x00000, 0x1712a, 0x00002, 0x02000, 0x00000, 0x000c0, + 0x00064, 0x81184, 0x6016c, 0xead53, 0x93bc4, 0x714e9, 0x1c67c, + 0x91016 +}, rtl8821au_rf_vals5[] = { + 0x00006, 0x02000, 0x3824b, 0x3024b, 0x2844b, 0x20f4b, 0x18f4b, + 0x104b2, 0x08049, 0x00148, 0x7824b, 0x7024b, 0x6824b, 0x60f4b, + 0x58f4b, 0x504b2, 0x48049, 0x40148, 0x00000, 0x00100, 0x0adf3, + 0x09df0, 0x08d70, 0x07d6d, 0x06cee, 0x05ccc, 0x044ec, 0x034ac, + 0x0246d, 0x0106f, 0x0006c, 0x00000, 0x00010, 0x0adf2, 0x09def, + 0x08dec, 0x07de9, 0x06cec, 0x05ce9, 0x044ec, 0x034e9, 0x0246c, + 0x01469, 0x0006c, 0x00000, 0x00001, 0x38da7, 0x300c2, 0x288e2, + 0x200b8, 0x188a5, 0x10fbc, 0x08f71, 0x00240, 0x00000, 0x020a2, + 0x00080, 0x00120, 0x08120, 0x10120, 0x00085, 0x08085, 0x10085, + 0x18085, 0x00000, 0x00c31, 0x00622, 0xfc70b, 0x0017e, 0x51df3, + 0x00c01, 0x006d6, 0xfc649, 0x49661, 0x7843e, 0x00382, 0x51400, + 0x00160, 0x08160, 0x10160, 0x00124, 0x08124, 0x10124, 0x18124, + 0x0000c, 0x00140, 0x08140, 0x10140, 0x00124, 0x08124, 0x10124, + 0x18124, 0x00088, 0xf0e18, 0x1214c, 0x3000c, 0x539d2, 0xafe00, + 0x1f12a, 0x0c350, 0x0c350, 0x1712a, +}; + +static const struct rtwn_rf_prog rtl8821au_rf[] = { + /* RF chain 0. */ + { + nitems(rtl8821au_rf_regs0), + rtl8821au_rf_regs0, + rtl8821au_rf_vals0, + { 0 }, + NULL + }, + /* + * No external PA/LNA; with or without BT. + */ + { + nitems(rtl8821au_rf_regs1), + rtl8821au_rf_regs1, + rtl8821au_rf_vals1_def_or_bt, + { R21A_COND_BOARD_DEF, R21A_COND_BT, 0 }, + /* + * With external 5GHz PA and LNA. + */ + &(const struct rtwn_rf_prog){ + nitems(rtl8821au_rf_regs1), + rtl8821au_rf_regs1, + rtl8821au_rf_vals1_ext_5g, + { R21A_COND_EXT_PA_5G | R21A_COND_EXT_LNA_5G, 0 }, + /* + * Others. + */ + &(const struct rtwn_rf_prog){ + nitems(rtl8821au_rf_regs1), + rtl8821au_rf_regs1, + rtl8821au_rf_vals1, + { 0 }, + NULL + } + } + }, + /* + * With external 5GHz PA and LNA. + */ + { + nitems(rtl8821au_rf_regs2), + rtl8821au_rf_regs2, + rtl8821au_rf_vals2_ext_5g, + { R21A_COND_EXT_PA_5G | R21A_COND_EXT_LNA_5G, 0 }, + /* + * Others. + */ + &(const struct rtwn_rf_prog){ + nitems(rtl8821au_rf_regs2), + rtl8821au_rf_regs2, + rtl8821au_rf_vals2, + { 0 }, + NULL + } + }, + /* + * No external PA/LNA; with or without BT. + */ + { + nitems(rtl8821au_rf_regs3), + rtl8821au_rf_regs3, + rtl8821au_rf_vals3_def_or_bt, + { R21A_COND_BOARD_DEF, R21A_COND_BT, 0 }, + /* + * Others. + */ + &(const struct rtwn_rf_prog){ + nitems(rtl8821au_rf_regs3), + rtl8821au_rf_regs3, + rtl8821au_rf_vals3, + { 0 }, + NULL + } + }, + /* + * No external PA/LNA; with or without BT. + */ + { + nitems(rtl8821au_rf_regs4), + rtl8821au_rf_regs4, + rtl8821au_rf_vals4_def_or_bt, + { R21A_COND_BOARD_DEF, R21A_COND_BT, 0 }, + /* + * With external 5GHz PA and LNA. + */ + &(const struct rtwn_rf_prog){ + nitems(rtl8821au_rf_regs4), + rtl8821au_rf_regs4, + rtl8821au_rf_vals4_ext_5g, + { R21A_COND_EXT_PA_5G | R21A_COND_EXT_LNA_5G, 0 }, + /* + * Others. + */ + &(const struct rtwn_rf_prog){ + nitems(rtl8821au_rf_regs4), + rtl8821au_rf_regs4, + rtl8821au_rf_vals4, + { 0 }, + NULL + } + } + }, + { + nitems(rtl8821au_rf_regs5), + rtl8821au_rf_regs5, + rtl8821au_rf_vals5, + { 0 }, + NULL + }, + { 0, NULL, NULL, { 0 }, NULL } +}; + + +/* + * Registers to save before IQ calibration. + */ +static const uint16_t r21a_iq_bb_regs[] = { + 0x520, 0x550, 0x808, 0xa04, 0x90c, 0xc00, 0x838, 0x82c +}; + +static const uint16_t r21a_iq_afe_regs[] = { + 0xc5c, 0xc60, 0xc64, 0xc68 +}; + +static const uint8_t r21a_iq_rf_regs[] = { + 0x65, 0x8f, 0x0 +}; + +#endif /* R21A_PRIV_H */ diff --git a/sys/dev/rtwn/rtl8821a/r21a_reg.h b/sys/dev/rtwn/rtl8821a/r21a_reg.h new file mode 100644 index 000000000000..d13872d59cbc --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/r21a_reg.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef R21A_REG_H +#define R21A_REG_H + +#include + +/* + * MAC registers. + */ +/* Tx DMA Configuration. */ +#define R21A_DWBCN0_CTRL R92C_TDECTRL +#define R21A_DWBCN1_CTRL 0x228 + + +/* Bits for R92C_MAC_PHY_CTRL. */ +#define R21A_MAC_PHY_CRYSTALCAP_M 0x00fff000 +#define R21A_MAC_PHY_CRYSTALCAP_S 12 + +/* Bits for R21A_DWBCN1_CTRL. */ +#define R21A_DWBCN1_CTRL_SEL_EN 0x00020000 +#define R21A_DWBCN1_CTRL_SEL_BCN1 0x00100000 + +#endif /* R21A_REG_H */ diff --git a/sys/dev/rtwn/rtl8821a/r21a_rom.c b/sys/dev/rtwn/rtl8821a/r21a_rom.c new file mode 100644 index 000000000000..cda5913e9a81 --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/r21a_rom.c @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include + + +void +r21a_parse_rom(struct rtwn_softc *sc, uint8_t *buf) +{ + struct r12a_softc *rs = sc->sc_priv; + struct r12a_rom *rom = (struct r12a_rom *)buf; + uint8_t pa_type, lna_type_2g, lna_type_5g; + + /* Read PA/LNA types. */ + pa_type = RTWN_GET_ROM_VAR(rom->pa_type, 0); + lna_type_2g = RTWN_GET_ROM_VAR(rom->lna_type_2g, 0); + lna_type_5g = RTWN_GET_ROM_VAR(rom->lna_type_5g, 0); + + rs->ext_pa_2g = R21A_ROM_IS_PA_EXT_2GHZ(pa_type); + rs->ext_pa_5g = R21A_ROM_IS_PA_EXT_5GHZ(pa_type); + rs->ext_lna_2g = R21A_ROM_IS_LNA_EXT(lna_type_2g); + rs->ext_lna_5g = R21A_ROM_IS_LNA_EXT(lna_type_5g); + + RTWN_LOCK(sc); + rs->bt_coex = + !!(rtwn_read_4(sc, R92C_MULTI_FUNC_CTRL) & R92C_MULTI_BT_FUNC_EN); + RTWN_UNLOCK(sc); + rs->bt_ant_num = (rom->rf_bt_opt & R12A_RF_BT_OPT_ANT_NUM); + + /* Read MAC address. */ + IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr_21a); + + /* Execute common part of initialization. */ + r12a_parse_rom_common(sc, buf); +} diff --git a/sys/dev/rtwn/rtl8821a/r21a_rx.c b/sys/dev/rtwn/rtl8821a/r21a_rx.c new file mode 100644 index 000000000000..bd0721b3edc7 --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/r21a_rx.c @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include + + +int8_t +r21a_get_rssi_cck(struct rtwn_softc *sc, void *physt) +{ + struct r12a_rx_phystat *stat = (struct r12a_rx_phystat *)physt; + int8_t lna_idx, rssi; + + lna_idx = (stat->cfosho[0] & 0xe0) >> 5; + rssi = -6 - 2*(stat->cfosho[0] & 0x1f); /* Pout - (2 * VGA_idx) */ + + switch (lna_idx) { + case 5: + rssi -= 32; + break; + case 4: + rssi -= 24; + break; + case 2: + rssi -= 11; + break; + case 1: + rssi += 5; + break; + case 0: + rssi += 21; + break; + } + + return (rssi); +} diff --git a/sys/dev/rtwn/rtl8821a/usb/r21au.h b/sys/dev/rtwn/rtl8821a/usb/r21au.h new file mode 100644 index 000000000000..e1e8b4692c57 --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/usb/r21au.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef RTL8821AU_H +#define RTL8821AU_H + +#include + + +/* + * Function declarations. + */ +/* r21au_init.c */ +void r21au_init_tx_agg(struct rtwn_softc *); +void r21au_init_burstlen(struct rtwn_softc *); + +#endif /* RTL8821AU_H */ diff --git a/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c b/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c new file mode 100644 index 000000000000..a9bc47b8969b --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/usb/r21au_attach.c @@ -0,0 +1,241 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +#include + + +void r21au_attach(struct rtwn_usb_softc *); + +static void +r21a_postattach(struct rtwn_softc *sc) +{ + struct r12a_softc *rs = sc->sc_priv; + + if (rs->board_type == R92C_BOARD_TYPE_MINICARD || + rs->board_type == R92C_BOARD_TYPE_SOLO || + rs->board_type == R92C_BOARD_TYPE_COMBO) + sc->sc_set_led = r88e_set_led; + else + sc->sc_set_led = r21a_set_led; + + sc->sc_ic.ic_ioctl = r12a_ioctl_net; +} + +static void +r21a_attach_private(struct rtwn_softc *sc) +{ + struct r12a_softc *rs; + + rs = malloc(sizeof(struct r12a_softc), M_RTWN_PRIV, M_WAITOK | M_ZERO); + + rs->rs_flags = R12A_RXCKSUM_EN | R12A_RXCKSUM6_EN; + + rs->rs_fix_spur = rtwn_nop_softc_chan; + rs->rs_set_band_2ghz = r21a_set_band_2ghz; + rs->rs_set_band_5ghz = r21a_set_band_5ghz; + rs->rs_init_burstlen = r21au_init_burstlen; + rs->rs_init_ampdu_fwhw = r21a_init_ampdu_fwhw; + rs->rs_crystalcap_write = r21a_crystalcap_write; +#ifndef RTWN_WITHOUT_UCODE + rs->rs_iq_calib_fw_supported = r21a_iq_calib_fw_supported; +#endif + rs->rs_iq_calib_sw = r21a_iq_calib_sw; + + rs->ampdu_max_time = 0x5e; + + rs->ac_usb_dma_size = 0x01; + rs->ac_usb_dma_time = 0x10; + + sc->sc_priv = rs; +} + +static void +r21au_adj_devcaps(struct rtwn_softc *sc) +{ + /* TODO: DFS, LDPC etc */ +} + +void +r21au_attach(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + + /* USB part. */ + uc->uc_align_rx = r12au_align_rx; + uc->tx_agg_desc_num = 6; + + /* Common part. */ + sc->sc_flags = RTWN_FLAG_EXT_HDR; + + sc->sc_set_chan = r12a_set_chan; + sc->sc_fill_tx_desc = r12a_fill_tx_desc; + sc->sc_fill_tx_desc_raw = r12a_fill_tx_desc_raw; + sc->sc_fill_tx_desc_null = r12a_fill_tx_desc_null; + sc->sc_dump_tx_desc = r12au_dump_tx_desc; + sc->sc_tx_radiotap_flags = r12a_tx_radiotap_flags; + sc->sc_rx_radiotap_flags = r12a_rx_radiotap_flags; + sc->sc_get_rssi_cck = r21a_get_rssi_cck; + sc->sc_get_rssi_ofdm = r88e_get_rssi_ofdm; + sc->sc_classify_intr = r12au_classify_intr; + sc->sc_handle_tx_report = r12a_ratectl_tx_complete; + sc->sc_handle_c2h_report = r12a_handle_c2h_report; + sc->sc_check_frame = r12a_check_frame_checksum; + sc->sc_rf_read = r12a_c_cut_rf_read; + sc->sc_rf_write = r12a_rf_write; + sc->sc_check_condition = r21a_check_condition; + sc->sc_efuse_postread = rtwn_nop_softc; + sc->sc_parse_rom = r21a_parse_rom; + sc->sc_power_on = r21a_power_on; + sc->sc_power_off = r21a_power_off; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_fw_reset = r21a_fw_reset; + sc->sc_fw_download_enable = r12a_fw_download_enable; +#endif + sc->sc_set_page_size = rtwn_nop_int_softc; + sc->sc_lc_calib = rtwn_nop_softc; /* XXX not used */ + sc->sc_iq_calib = r12a_iq_calib; + sc->sc_read_chipid_vendor = rtwn_nop_softc_uint32; + sc->sc_adj_devcaps = r21au_adj_devcaps; + sc->sc_vap_preattach = r12a_vap_preattach; + sc->sc_postattach = r21a_postattach; + sc->sc_detach_private = r12a_detach_private; +#ifndef RTWN_WITHOUT_UCODE + sc->sc_set_media_status = r12a_set_media_status; + sc->sc_set_rsvd_page = r88e_set_rsvd_page; + sc->sc_set_pwrmode = r12a_set_pwrmode; + sc->sc_set_rssi = rtwn_nop_softc; /* XXX TODO */ +#else + sc->sc_set_media_status = rtwn_nop_softc_int; +#endif + sc->sc_beacon_init = r21a_beacon_init; + sc->sc_beacon_enable = r92c_beacon_enable; + sc->sc_beacon_set_rate = r12a_beacon_set_rate; + sc->sc_beacon_select = r21a_beacon_select; + sc->sc_temp_measure = r88e_temp_measure; + sc->sc_temp_read = r88e_temp_read; + sc->sc_init_tx_agg = r21au_init_tx_agg; + sc->sc_init_rx_agg = r12au_init_rx_agg; + sc->sc_init_ampdu = r12au_init_ampdu; + sc->sc_init_intr = r12a_init_intr; + sc->sc_init_edca = r12a_init_edca; + sc->sc_init_bb = r12a_init_bb; + sc->sc_init_rf = r12a_init_rf; + sc->sc_init_antsel = r12a_init_antsel; + sc->sc_post_init = r12au_post_init; + sc->sc_init_bcnq1_boundary = r21a_init_bcnq1_boundary; + + sc->chan_list_5ghz[0] = r12a_chan_5ghz_0; + sc->chan_list_5ghz[1] = r12a_chan_5ghz_1; + sc->chan_list_5ghz[2] = r12a_chan_5ghz_2; + sc->chan_num_5ghz[0] = nitems(r12a_chan_5ghz_0); + sc->chan_num_5ghz[1] = nitems(r12a_chan_5ghz_1); + sc->chan_num_5ghz[2] = nitems(r12a_chan_5ghz_2); + + sc->mac_prog = &rtl8821au_mac[0]; + sc->mac_size = nitems(rtl8821au_mac); + sc->bb_prog = &rtl8821au_bb[0]; + sc->bb_size = nitems(rtl8821au_bb); + sc->agc_prog = &rtl8821au_agc[0]; + sc->agc_size = nitems(rtl8821au_agc); + sc->rf_prog = &rtl8821au_rf[0]; + + sc->name = "RTL8821AU"; + sc->fwname = "rtwn-rtl8821aufw"; + sc->fwsig = 0x210; + + sc->page_count = R21A_TX_PAGE_COUNT; + sc->pktbuf_count = R12A_TXPKTBUF_COUNT; + + sc->ackto = 0x80; + sc->npubqpages = R12A_PUBQ_NPAGES; + sc->page_size = R21A_TX_PAGE_SIZE; + + sc->txdesc_len = sizeof(struct r12au_tx_desc); + sc->efuse_maxlen = R12A_EFUSE_MAX_LEN; + sc->efuse_maplen = R12A_EFUSE_MAP_LEN; + sc->rx_dma_size = R12A_RX_DMA_BUFFER_SIZE; + + sc->macid_limit = R12A_MACID_MAX + 1; + sc->cam_entry_limit = R12A_CAM_ENTRY_COUNT; + sc->fwsize_limit = R12A_MAX_FW_SIZE; + sc->temp_delta = R88E_CALIB_THRESHOLD; + + sc->bcn_status_reg[0] = R92C_TDECTRL; + sc->bcn_status_reg[1] = R21A_DWBCN1_CTRL; + sc->rcr = R12A_RCR_DIS_CHK_14 | + R12A_RCR_VHT_ACK | + R12A_RCR_TCP_OFFLD_EN; + + sc->ntxchains = 1; + sc->nrxchains = 1; + + r21a_attach_private(sc); +} diff --git a/sys/dev/rtwn/rtl8821a/usb/r21au_init.c b/sys/dev/rtwn/rtl8821a/usb/r21au_init.c new file mode 100644 index 000000000000..08af2af318ca --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/usb/r21au_init.c @@ -0,0 +1,83 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include +#include + + +void +r21au_init_tx_agg(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + r92cu_init_tx_agg(sc); + + rtwn_write_1(sc, R21A_DWBCN1_CTRL, uc->tx_agg_desc_num << 1); +} + +void +r21au_init_burstlen(struct rtwn_softc *sc) +{ + if ((rtwn_read_1(sc, R92C_USB_INFO) & 0x30) == 0) { + /* Set burst packet length to 512 B. */ + rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x20, 0x1e); + } else { + /* Set burst packet length to 64 B. */ + rtwn_setbits_1(sc, R12A_RXDMA_PRO, 0x10, 0x2e); + } +} diff --git a/sys/dev/rtwn/rtl8821a/usb/r21au_reg.h b/sys/dev/rtwn/rtl8821a/usb/r21au_reg.h new file mode 100644 index 000000000000..cd0deb5f7c64 --- /dev/null +++ b/sys/dev/rtwn/rtl8821a/usb/r21au_reg.h @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef R21AU_REG_H +#define R21AU_REG_H + +#include +#include + +#endif /* R21AU_REG_H */ diff --git a/sys/dev/rtwn/usb/rtwn_usb_attach.c b/sys/dev/rtwn/usb/rtwn_usb_attach.c new file mode 100644 index 000000000000..a47797b56af7 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_attach.c @@ -0,0 +1,433 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include "usbdevs.h" + +#include +#include + +#include + +#include +#include +#include +#include + +#include + +static device_probe_t rtwn_usb_match; +static device_attach_t rtwn_usb_attach; +static device_detach_t rtwn_usb_detach; +static device_suspend_t rtwn_usb_suspend; +static device_resume_t rtwn_usb_resume; + +static int rtwn_usb_alloc_list(struct rtwn_softc *, + struct rtwn_data[], int, int); +static int rtwn_usb_alloc_rx_list(struct rtwn_softc *); +static int rtwn_usb_alloc_tx_list(struct rtwn_softc *); +static void rtwn_usb_free_list(struct rtwn_softc *, + struct rtwn_data data[], int); +static void rtwn_usb_free_rx_list(struct rtwn_softc *); +static void rtwn_usb_free_tx_list(struct rtwn_softc *); +static void rtwn_usb_reset_lists(struct rtwn_softc *, + struct ieee80211vap *); +static void rtwn_usb_reset_tx_list(struct rtwn_usb_softc *, + rtwn_datahead *, struct ieee80211vap *); +static void rtwn_usb_start_xfers(struct rtwn_softc *); +static void rtwn_usb_abort_xfers(struct rtwn_softc *); +static int rtwn_usb_fw_write_block(struct rtwn_softc *, + const uint8_t *, uint16_t, int); +static void rtwn_usb_attach_methods(struct rtwn_softc *); + +#define RTWN_CONFIG_INDEX 0 + + +static int +rtwn_usb_match(device_t self) +{ + struct usb_attach_arg *uaa = device_get_ivars(self); + + if (uaa->usb_mode != USB_MODE_HOST) + return (ENXIO); + if (uaa->info.bConfigIndex != RTWN_CONFIG_INDEX) + return (ENXIO); + if (uaa->info.bIfaceIndex != RTWN_IFACE_INDEX) + return (ENXIO); + + return (usbd_lookup_id_by_uaa(rtwn_devs, sizeof(rtwn_devs), uaa)); +} + +static int +rtwn_usb_alloc_list(struct rtwn_softc *sc, struct rtwn_data data[], + int ndata, int maxsz) +{ + int i, error; + + for (i = 0; i < ndata; i++) { + struct rtwn_data *dp = &data[i]; + dp->m = NULL; + dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); + if (dp->buf == NULL) { + device_printf(sc->sc_dev, + "could not allocate buffer\n"); + error = ENOMEM; + goto fail; + } + dp->ni = NULL; + } + + return (0); +fail: + rtwn_usb_free_list(sc, data, ndata); + return (error); +} + +static int +rtwn_usb_alloc_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + int error, i; + + error = rtwn_usb_alloc_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT, + RTWN_RXBUFSZ); + if (error != 0) + return (error); + + STAILQ_INIT(&uc->uc_rx_active); + STAILQ_INIT(&uc->uc_rx_inactive); + + for (i = 0; i < RTWN_USB_RX_LIST_COUNT; i++) + STAILQ_INSERT_HEAD(&uc->uc_rx_inactive, &uc->uc_rx[i], next); + + return (0); +} + +static int +rtwn_usb_alloc_tx_list(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + int error, i; + + error = rtwn_usb_alloc_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT, + RTWN_TXBUFSZ); + if (error != 0) + return (error); + + STAILQ_INIT(&uc->uc_tx_active); + STAILQ_INIT(&uc->uc_tx_inactive); + STAILQ_INIT(&uc->uc_tx_pending); + + for (i = 0; i < RTWN_USB_TX_LIST_COUNT; i++) + STAILQ_INSERT_HEAD(&uc->uc_tx_inactive, &uc->uc_tx[i], next); + + return (0); +} + +static void +rtwn_usb_free_list(struct rtwn_softc *sc, struct rtwn_data data[], int ndata) +{ + int i; + + for (i = 0; i < ndata; i++) { + struct rtwn_data *dp = &data[i]; + + if (dp->buf != NULL) { + free(dp->buf, M_USBDEV); + dp->buf = NULL; + } + if (dp->ni != NULL) { + ieee80211_free_node(dp->ni); + dp->ni = NULL; + } + if (dp->m != NULL) { + m_freem(dp->m); + dp->m = NULL; + } + } +} + +static void +rtwn_usb_free_rx_list(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + rtwn_usb_free_list(sc, uc->uc_rx, RTWN_USB_RX_LIST_COUNT); + + STAILQ_INIT(&uc->uc_rx_active); + STAILQ_INIT(&uc->uc_rx_inactive); +} + +static void +rtwn_usb_free_tx_list(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + rtwn_usb_free_list(sc, uc->uc_tx, RTWN_USB_TX_LIST_COUNT); + + STAILQ_INIT(&uc->uc_tx_active); + STAILQ_INIT(&uc->uc_tx_inactive); + STAILQ_INIT(&uc->uc_tx_pending); +} + +static void +rtwn_usb_reset_lists(struct rtwn_softc *sc, struct ieee80211vap *vap) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + RTWN_ASSERT_LOCKED(sc); + + rtwn_usb_reset_tx_list(uc, &uc->uc_tx_active, vap); + rtwn_usb_reset_tx_list(uc, &uc->uc_tx_pending, vap); + if (vap == NULL) + sc->qfullmsk = 0; +} + +static void +rtwn_usb_reset_tx_list(struct rtwn_usb_softc *uc, + rtwn_datahead *head, struct ieee80211vap *vap) +{ + struct rtwn_vap *uvp = RTWN_VAP(vap); + struct rtwn_data *dp, *tmp; + int id; + + id = (uvp != NULL ? uvp->id : RTWN_VAP_ID_INVALID); + + STAILQ_FOREACH_SAFE(dp, head, next, tmp) { + if (vap == NULL || (dp->ni == NULL && + (dp->id == id || id == RTWN_VAP_ID_INVALID)) || + (dp->ni != NULL && dp->ni->ni_vap == vap)) { + if (dp->ni != NULL) { + ieee80211_free_node(dp->ni); + dp->ni = NULL; + } + + if (dp->m != NULL) { + m_freem(dp->m); + dp->m = NULL; + } + + STAILQ_REMOVE(head, dp, rtwn_data, next); + STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, dp, next); + } + } +} + +static void +rtwn_usb_start_xfers(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + usbd_transfer_start(uc->uc_xfer[RTWN_BULK_RX]); +} + +static void +rtwn_usb_abort_xfers(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + int i; + + RTWN_ASSERT_LOCKED(sc); + + /* abort any pending transfers */ + for (i = 0; i < RTWN_N_TRANSFER; i++) + usbd_transfer_stop(uc->uc_xfer[i]); +} + +static int +rtwn_usb_fw_write_block(struct rtwn_softc *sc, const uint8_t *buf, + uint16_t reg, int mlen) +{ + int error; + + /* XXX fix this deconst */ + error = rtwn_usb_write_region_1(sc, reg, __DECONST(uint8_t *, buf), + mlen); + + return (error); +} + +static void +rtwn_usb_drop_incorrect_tx(struct rtwn_softc *sc) +{ + + rtwn_setbits_1_shift(sc, R92C_TXDMA_OFFSET_CHK, 0, + R92C_TXDMA_OFFSET_DROP_DATA_EN, 1); +} + +static void +rtwn_usb_attach_methods(struct rtwn_softc *sc) +{ + sc->sc_write_1 = rtwn_usb_write_1; + sc->sc_write_2 = rtwn_usb_write_2; + sc->sc_write_4 = rtwn_usb_write_4; + sc->sc_read_1 = rtwn_usb_read_1; + sc->sc_read_2 = rtwn_usb_read_2; + sc->sc_read_4 = rtwn_usb_read_4; + sc->sc_delay = rtwn_usb_delay; + sc->sc_tx_start = rtwn_usb_tx_start; + sc->sc_start_xfers = rtwn_usb_start_xfers; + sc->sc_reset_lists = rtwn_usb_reset_lists; + sc->sc_abort_xfers = rtwn_usb_abort_xfers; + sc->sc_fw_write_block = rtwn_usb_fw_write_block; + sc->sc_get_qmap = rtwn_usb_get_qmap; + sc->sc_set_desc_addr = rtwn_nop_softc; + sc->sc_drop_incorrect_tx = rtwn_usb_drop_incorrect_tx; +} + +static int +rtwn_usb_attach(device_t self) +{ + struct usb_attach_arg *uaa = device_get_ivars(self); + struct rtwn_usb_softc *uc = device_get_softc(self); + struct rtwn_softc *sc = &uc->uc_sc; + struct ieee80211com *ic = &sc->sc_ic; + int error; + + device_set_usb_desc(self); + uc->uc_udev = uaa->device; + sc->sc_dev = self; + ic->ic_name = device_get_nameunit(self); + + /* Need to be initialized early. */ + rtwn_sysctlattach(sc); + mtx_init(&sc->sc_mtx, ic->ic_name, MTX_NETWORK_LOCK, MTX_DEF); + + rtwn_usb_attach_methods(sc); + rtwn_usb_attach_private(uc, USB_GET_DRIVER_INFO(uaa)); + + error = rtwn_usb_setup_endpoints(uc); + if (error != 0) + goto detach; + + /* Allocate Tx/Rx buffers. */ + error = rtwn_usb_alloc_rx_list(sc); + if (error != 0) + goto detach; + + error = rtwn_usb_alloc_tx_list(sc); + if (error != 0) + goto detach; + + /* Generic attach. */ + error = rtwn_attach(sc); + if (error != 0) + goto detach; + + return (0); + +detach: + rtwn_usb_detach(self); /* failure */ + return (ENXIO); +} + +static int +rtwn_usb_detach(device_t self) +{ + struct rtwn_usb_softc *uc = device_get_softc(self); + struct rtwn_softc *sc = &uc->uc_sc; + + /* Generic detach. */ + rtwn_detach(sc); + + /* Free Tx/Rx buffers. */ + rtwn_usb_free_tx_list(sc); + rtwn_usb_free_rx_list(sc); + + /* Detach all USB transfers. */ + usbd_transfer_unsetup(uc->uc_xfer, RTWN_N_TRANSFER); + + rtwn_detach_private(sc); + mtx_destroy(&sc->sc_mtx); + + return (0); +} + +static int +rtwn_usb_suspend(device_t self) +{ + struct rtwn_usb_softc *uc = device_get_softc(self); + + rtwn_suspend(&uc->uc_sc); + + return (0); +} + +static int +rtwn_usb_resume(device_t self) +{ + struct rtwn_usb_softc *uc = device_get_softc(self); + + rtwn_resume(&uc->uc_sc); + + return (0); +} + +static device_method_t rtwn_usb_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, rtwn_usb_match), + DEVMETHOD(device_attach, rtwn_usb_attach), + DEVMETHOD(device_detach, rtwn_usb_detach), + DEVMETHOD(device_suspend, rtwn_usb_suspend), + DEVMETHOD(device_resume, rtwn_usb_resume), + + DEVMETHOD_END +}; + +static driver_t rtwn_usb_driver = { + "rtwn", + rtwn_usb_methods, + sizeof(struct rtwn_usb_softc) +}; + +static devclass_t rtwn_usb_devclass; + +DRIVER_MODULE(rtwn_usb, uhub, rtwn_usb_driver, rtwn_usb_devclass, NULL, NULL); +MODULE_VERSION(rtwn_usb, 1); +MODULE_DEPEND(rtwn_usb, usb, 1, 1, 1); +MODULE_DEPEND(rtwn_usb, wlan, 1, 1, 1); +MODULE_DEPEND(rtwn_usb, rtwn, 2, 2, 2); +USB_PNP_HOST_INFO(rtwn_devs); diff --git a/sys/dev/rtwn/usb/rtwn_usb_attach.h b/sys/dev/rtwn/usb/rtwn_usb_attach.h new file mode 100644 index 000000000000..6bfed2e43a07 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_attach.h @@ -0,0 +1,159 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +void r92cu_attach(struct rtwn_usb_softc *); +void r88eu_attach(struct rtwn_usb_softc *); +void r12au_attach(struct rtwn_usb_softc *); +void r21au_attach(struct rtwn_usb_softc *); + +enum { + RTWN_CHIP_RTL8192CU, + RTWN_CHIP_RTL8188EU, + RTWN_CHIP_RTL8812AU, + RTWN_CHIP_RTL8821AU, + RTWN_CHIP_MAX_USB +}; + +/* various supported device vendors/products */ +static const STRUCT_USB_HOST_ID rtwn_devs[] = { + /* RTL8188CE-VAU/RTL8188CUS/RTL8188RU/RTL8192CU */ +#define RTWN_RTL8192CU_DEV(v,p) \ + { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8192CU) } + RTWN_RTL8192CU_DEV(ABOCOM, RTL8188CU_1), + RTWN_RTL8192CU_DEV(ABOCOM, RTL8188CU_2), + RTWN_RTL8192CU_DEV(ABOCOM, RTL8192CU), + RTWN_RTL8192CU_DEV(ASUS, RTL8192CU), + RTWN_RTL8192CU_DEV(ASUS, USBN10NANO), + RTWN_RTL8192CU_DEV(AZUREWAVE, RTL8188CE_1), + RTWN_RTL8192CU_DEV(AZUREWAVE, RTL8188CE_2), + RTWN_RTL8192CU_DEV(AZUREWAVE, RTL8188CU), + RTWN_RTL8192CU_DEV(BELKIN, F7D2102), + RTWN_RTL8192CU_DEV(BELKIN, RTL8188CU), + RTWN_RTL8192CU_DEV(BELKIN, RTL8192CU), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_1), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_2), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_3), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_4), + RTWN_RTL8192CU_DEV(CHICONY, RTL8188CUS_5), + RTWN_RTL8192CU_DEV(COREGA, RTL8192CU), + RTWN_RTL8192CU_DEV(DLINK, RTL8188CU), + RTWN_RTL8192CU_DEV(DLINK, RTL8192CU_1), + RTWN_RTL8192CU_DEV(DLINK, RTL8192CU_2), + RTWN_RTL8192CU_DEV(DLINK, RTL8192CU_3), + RTWN_RTL8192CU_DEV(DLINK, DWA131B), + RTWN_RTL8192CU_DEV(EDIMAX, EW7811UN), + RTWN_RTL8192CU_DEV(EDIMAX, RTL8192CU), + RTWN_RTL8192CU_DEV(FEIXUN, RTL8188CU), + RTWN_RTL8192CU_DEV(FEIXUN, RTL8192CU), + RTWN_RTL8192CU_DEV(GUILLEMOT, HWNUP150), + RTWN_RTL8192CU_DEV(HAWKING, RTL8192CU), + RTWN_RTL8192CU_DEV(HP3, RTL8188CU), + RTWN_RTL8192CU_DEV(NETGEAR, WNA1000M), + RTWN_RTL8192CU_DEV(NETGEAR, RTL8192CU), + RTWN_RTL8192CU_DEV(NETGEAR4, RTL8188CU), + RTWN_RTL8192CU_DEV(NOVATECH, RTL8188CU), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CU_1), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CU_2), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CU_3), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CU_4), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8188CUS), + RTWN_RTL8192CU_DEV(PLANEX2, RTL8192CU), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CE_0), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CE_1), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CTV), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_0), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_1), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_2), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_3), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CU_COMBO), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188CUS), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188RU_1), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188RU_2), + RTWN_RTL8192CU_DEV(REALTEK, RTL8188RU_3), + RTWN_RTL8192CU_DEV(REALTEK, RTL8191CU), + RTWN_RTL8192CU_DEV(REALTEK, RTL8192CE), + RTWN_RTL8192CU_DEV(REALTEK, RTL8192CU), + RTWN_RTL8192CU_DEV(SITECOMEU, RTL8188CU_1), + RTWN_RTL8192CU_DEV(SITECOMEU, RTL8188CU_2), + RTWN_RTL8192CU_DEV(SITECOMEU, RTL8192CU), + RTWN_RTL8192CU_DEV(TRENDNET, RTL8188CU), + RTWN_RTL8192CU_DEV(TRENDNET, RTL8192CU), + RTWN_RTL8192CU_DEV(ZYXEL, RTL8192CU), +#undef RTWN_RTL8192CU_DEV + + /* RTL8188EU */ +#define RTWN_RTL8188EU_DEV(v,p) \ + { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8188EU) } + RTWN_RTL8188EU_DEV(ABOCOM, RTL8188EU), + RTWN_RTL8188EU_DEV(DLINK, DWA123D1), + RTWN_RTL8188EU_DEV(DLINK, DWA125D1), + RTWN_RTL8188EU_DEV(ELECOM, WDC150SU2M), + RTWN_RTL8188EU_DEV(REALTEK, RTL8188ETV), + RTWN_RTL8188EU_DEV(REALTEK, RTL8188EU), +#undef RTWN_RTL8188EU_DEV + + /* RTL8812AU */ +#define RTWN_RTL8812AU_DEV(v,p) \ + { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8812AU) } + RTWN_RTL8812AU_DEV(ASUS, USBAC56), + RTWN_RTL8812AU_DEV(CISCOLINKSYS, WUSB6300), + RTWN_RTL8812AU_DEV(DLINK, DWA182C1), + RTWN_RTL8812AU_DEV(DLINK, DWA180A1), + RTWN_RTL8812AU_DEV(EDIMAX, EW7822UAC), + RTWN_RTL8812AU_DEV(IODATA, WNAC867U), + RTWN_RTL8812AU_DEV(MELCO, WIU3866D), + RTWN_RTL8812AU_DEV(NEC, WL900U), + RTWN_RTL8812AU_DEV(PLANEX2, GW900D), + RTWN_RTL8812AU_DEV(SENAO, EUB1200AC), + RTWN_RTL8812AU_DEV(SITECOMEU, WLA7100), + RTWN_RTL8812AU_DEV(TPLINK, T4U), + RTWN_RTL8812AU_DEV(TRENDNET, TEW805UB), + RTWN_RTL8812AU_DEV(ZYXEL, NWD6605), +#undef RTWN_RTL8812AU_DEV + + /* RTL8821AU */ +#define RTWN_RTL8821AU_DEV(v,p) \ + { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, RTWN_CHIP_RTL8821AU) } + RTWN_RTL8821AU_DEV(DLINK, DWA171A1), + RTWN_RTL8821AU_DEV(DLINK, DWA172A1), + RTWN_RTL8821AU_DEV(EDIMAX, EW7811UTC_1), + RTWN_RTL8821AU_DEV(EDIMAX, EW7811UTC_2), + RTWN_RTL8821AU_DEV(HAWKING, HD65U), + RTWN_RTL8821AU_DEV(MELCO, WIU2433DM), + RTWN_RTL8821AU_DEV(NETGEAR, A6100) +#undef RTWN_RTL8821AU_DEV +}; + +typedef void (*chip_usb_attach)(struct rtwn_usb_softc *); + +static const chip_usb_attach rtwn_chip_usb_attach[RTWN_CHIP_MAX_USB] = { + [RTWN_CHIP_RTL8192CU] = r92cu_attach, + [RTWN_CHIP_RTL8188EU] = r88eu_attach, + [RTWN_CHIP_RTL8812AU] = r12au_attach, + [RTWN_CHIP_RTL8821AU] = r21au_attach +}; + +static __inline void +rtwn_usb_attach_private(struct rtwn_usb_softc *uc, int chip) +{ + rtwn_chip_usb_attach[chip](uc); +} diff --git a/sys/dev/rtwn/usb/rtwn_usb_ep.c b/sys/dev/rtwn/usb/rtwn_usb_ep.c new file mode 100644 index 000000000000..8694e33dd2d1 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_ep.c @@ -0,0 +1,253 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include + + +static struct usb_config rtwn_config[RTWN_N_TRANSFER] = { + [RTWN_BULK_RX] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .bufsize = RTWN_RXBUFSZ, + .flags = { + .pipe_bof = 1, + .short_xfer_ok = 1 + }, + .callback = rtwn_bulk_rx_callback, + }, + [RTWN_BULK_TX_BE] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = RTWN_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1, + }, + .callback = rtwn_bulk_tx_callback, + .timeout = RTWN_TX_TIMEOUT, /* ms */ + }, + [RTWN_BULK_TX_BK] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = RTWN_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1, + }, + .callback = rtwn_bulk_tx_callback, + .timeout = RTWN_TX_TIMEOUT, /* ms */ + }, + [RTWN_BULK_TX_VI] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = RTWN_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1 + }, + .callback = rtwn_bulk_tx_callback, + .timeout = RTWN_TX_TIMEOUT, /* ms */ + }, + [RTWN_BULK_TX_VO] = { + .type = UE_BULK, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_OUT, + .bufsize = RTWN_TXBUFSZ, + .flags = { + .ext_buffer = 1, + .pipe_bof = 1, + .force_short_xfer = 1 + }, + .callback = rtwn_bulk_tx_callback, + .timeout = RTWN_TX_TIMEOUT, /* ms */ + }, +}; + +static void +rtwn_usb_setup_queues(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + int hasnq, haslq, nqueues, nqpages, nrempages; + + /* Get Tx queues to USB endpoints mapping. */ + hasnq = haslq = 0; + switch (uc->ntx) { + case 4: + case 3: + haslq = 1; + /* FALLTHROUGH */ + case 2: + hasnq = 1; + /* FALLTHROUGH */ + default: + break; + } + nqueues = 1 + hasnq + haslq; + + /* Get the number of pages for each queue. */ + nqpages = (sc->page_count - sc->npubqpages) / nqueues; + + /* + * The remaining pages are assigned to the high priority + * queue. + */ + nrempages = (sc->page_count - sc->npubqpages) % nqueues; + + sc->nhqpages = nqpages + nrempages; + sc->nnqpages = (hasnq ? nqpages : 0); + sc->nlqpages = (haslq ? nqpages : 0); +} + +int +rtwn_usb_setup_endpoints(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + const uint8_t iface_index = RTWN_IFACE_INDEX; + struct usb_endpoint *ep, *ep_end; + uint8_t addr[RTWN_MAX_EPOUT]; + int error; + + /* Determine the number of bulk-out pipes. */ + uc->ntx = 0; + ep = uc->uc_udev->endpoints; + ep_end = uc->uc_udev->endpoints + uc->uc_udev->endpoints_max; + for (; ep != ep_end; ep++) { + uint8_t eaddr; + + if ((ep->edesc == NULL) || (ep->iface_index != iface_index)) + continue; + + eaddr = ep->edesc->bEndpointAddress; + RTWN_DPRINTF(sc, RTWN_DEBUG_USB, + "%s: endpoint: addr %u, direction %s\n", __func__, + UE_GET_ADDR(eaddr), UE_GET_DIR(eaddr) == UE_DIR_OUT ? + "output" : "input"); + + if (UE_GET_DIR(eaddr) == UE_DIR_OUT) { + if (uc->ntx == RTWN_MAX_EPOUT) + break; + + addr[uc->ntx++] = UE_GET_ADDR(eaddr); + } + } + if (uc->ntx == 0 || uc->ntx > RTWN_MAX_EPOUT) { + device_printf(sc->sc_dev, + "%s: invalid number of Tx bulk pipes (%d)\n", __func__, + uc->ntx); + return (EINVAL); + } + + /* NB: keep in sync with rtwn_dma_init(). */ + rtwn_config[RTWN_BULK_TX_VO].endpoint = addr[0]; + switch (uc->ntx) { + case 4: + case 3: + rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[2]; + rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[2]; + rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[1]; + break; + case 2: + rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[1]; + rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[1]; + rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[0]; + break; + case 1: + rtwn_config[RTWN_BULK_TX_BE].endpoint = addr[0]; + rtwn_config[RTWN_BULK_TX_BK].endpoint = addr[0]; + rtwn_config[RTWN_BULK_TX_VI].endpoint = addr[0]; + break; + default: + KASSERT(0, ("unhandled number of endpoints %d\n", uc->ntx)); + break; + } + + error = usbd_transfer_setup(uc->uc_udev, &iface_index, + uc->uc_xfer, rtwn_config, RTWN_N_TRANSFER, uc, &sc->sc_mtx); + if (error) { + device_printf(sc->sc_dev, "could not allocate USB transfers, " + "err=%s\n", usbd_errstr(error)); + return (error); + } + + /* Assign pages for each queue (if not done). */ + if (sc->nhqpages == 0 && sc->nnqpages == 0 && sc->nlqpages == 0) + rtwn_usb_setup_queues(uc); + + return (0); +} + +uint16_t +rtwn_usb_get_qmap(struct rtwn_softc *sc) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + + switch (uc->ntx) { + case 1: + return (R92C_TRXDMA_CTRL_QMAP_HQ); + case 2: + return (R92C_TRXDMA_CTRL_QMAP_HQ_NQ); + default: + return (R92C_TRXDMA_CTRL_QMAP_3EP); + } +} diff --git a/sys/dev/rtwn/usb/rtwn_usb_ep.h b/sys/dev/rtwn/usb/rtwn_usb_ep.h new file mode 100644 index 000000000000..0cdd738e1794 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_ep.h @@ -0,0 +1,25 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef IF_RTWN_EP_H +#define IF_RTWN_EP_H + +int rtwn_usb_setup_endpoints(struct rtwn_usb_softc *); +uint16_t rtwn_usb_get_qmap(struct rtwn_softc *); + +#endif /* IF_RTWN_EP_H */ diff --git a/sys/dev/rtwn/usb/rtwn_usb_reg.c b/sys/dev/rtwn/usb/rtwn_usb_reg.c new file mode 100644 index 000000000000..2091c6ac6444 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_reg.c @@ -0,0 +1,179 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +static int rtwn_do_request(struct rtwn_softc *, + struct usb_device_request *, void *); +static int rtwn_usb_read_region_1(struct rtwn_softc *, + uint16_t, uint8_t *, int); + +/* USB Requests. */ +#define R92C_REQ_REGS 0x05 + + +static int +rtwn_do_request(struct rtwn_softc *sc, struct usb_device_request *req, + void *data) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + usb_error_t err; + int ntries = 10; + + RTWN_ASSERT_LOCKED(sc); + + while (ntries--) { + err = usbd_do_request_flags(uc->uc_udev, &sc->sc_mtx, + req, data, 0, NULL, 250 /* ms */); + if (err == USB_ERR_NORMAL_COMPLETION) + return (0); + + RTWN_DPRINTF(sc, RTWN_DEBUG_USB, + "%s: control request failed, %s (retries left: %d)\n", + __func__, usbd_errstr(err), ntries); + if (err == USB_ERR_NOT_CONFIGURED) + return (ENXIO); + + usb_pause_mtx(&sc->sc_mtx, hz / 100); + } + return (EIO); +} + +/* export for rtwn_fw_write_block() */ +int +rtwn_usb_write_region_1(struct rtwn_softc *sc, uint16_t addr, uint8_t *buf, + int len) +{ + usb_device_request_t req; + + req.bmRequestType = UT_WRITE_VENDOR_DEVICE; + req.bRequest = R92C_REQ_REGS; + USETW(req.wValue, addr); + USETW(req.wIndex, 0); + USETW(req.wLength, len); + return (rtwn_do_request(sc, &req, buf)); +} + +int +rtwn_usb_write_1(struct rtwn_softc *sc, uint16_t addr, uint8_t val) +{ + return (rtwn_usb_write_region_1(sc, addr, &val, sizeof(val))); +} + +int +rtwn_usb_write_2(struct rtwn_softc *sc, uint16_t addr, uint16_t val) +{ + val = htole16(val); + return (rtwn_usb_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val))); +} + +int +rtwn_usb_write_4(struct rtwn_softc *sc, uint16_t addr, uint32_t val) +{ + val = htole32(val); + return (rtwn_usb_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val))); +} + +static int +rtwn_usb_read_region_1(struct rtwn_softc *sc, uint16_t addr, uint8_t *buf, + int len) +{ + usb_device_request_t req; + + req.bmRequestType = UT_READ_VENDOR_DEVICE; + req.bRequest = R92C_REQ_REGS; + USETW(req.wValue, addr); + USETW(req.wIndex, 0); + USETW(req.wLength, len); + return (rtwn_do_request(sc, &req, buf)); +} + +uint8_t +rtwn_usb_read_1(struct rtwn_softc *sc, uint16_t addr) +{ + uint8_t val; + + if (rtwn_usb_read_region_1(sc, addr, &val, 1) != 0) + return (0xff); + return (val); +} + +uint16_t +rtwn_usb_read_2(struct rtwn_softc *sc, uint16_t addr) +{ + uint16_t val; + + if (rtwn_usb_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0) + return (0xffff); + return (le16toh(val)); +} + +uint32_t +rtwn_usb_read_4(struct rtwn_softc *sc, uint16_t addr) +{ + uint32_t val; + + if (rtwn_usb_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0) + return (0xffffffff); + return (le32toh(val)); +} + +void +rtwn_usb_delay(struct rtwn_softc *sc, int usec) +{ + + /* 1ms delay as default is too big. */ + if (usec < 1000) + DELAY(usec); + else { + usb_pause_mtx(&sc->sc_mtx, + MAX(msecs_to_ticks(usec / 1000), 1)); + } +} diff --git a/sys/dev/rtwn/usb/rtwn_usb_reg.h b/sys/dev/rtwn/usb/rtwn_usb_reg.h new file mode 100644 index 000000000000..1149248d71aa --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_reg.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_USB_REG_H +#define RTWN_USB_REG_H + +static __inline uint16_t +rtwn_usb_calc_tx_checksum(void *buf) +{ + uint16_t sum = 0; + int i; + + /* NB: checksum calculation takes into account only first 32 bytes. */ + for (i = 0; i < 32 / 2; i++) + sum ^= ((uint16_t *)buf)[i]; + + return (sum); /* NB: already little endian. */ +} + +int rtwn_usb_write_region_1(struct rtwn_softc *, uint16_t, + uint8_t *, int); +int rtwn_usb_write_1(struct rtwn_softc *, uint16_t, uint8_t); +int rtwn_usb_write_2(struct rtwn_softc *, uint16_t, uint16_t); +int rtwn_usb_write_4(struct rtwn_softc *, uint16_t, uint32_t); +uint8_t rtwn_usb_read_1(struct rtwn_softc *, uint16_t); +uint16_t rtwn_usb_read_2(struct rtwn_softc *, uint16_t); +uint32_t rtwn_usb_read_4(struct rtwn_softc *, uint16_t); +void rtwn_usb_delay(struct rtwn_softc *, int); + +#endif /* RTWN_USB_REG_H */ diff --git a/sys/dev/rtwn/usb/rtwn_usb_rx.c b/sys/dev/rtwn/usb/rtwn_usb_rx.c new file mode 100644 index 000000000000..8c6aa1686794 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_rx.c @@ -0,0 +1,335 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#ifdef IEEE80211_SUPPORT_SUPERG +#include +#endif + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include /* for CAM_ALGO_NONE */ +#include + + +static struct mbuf * +rtwn_rx_copy_to_mbuf(struct rtwn_softc *sc, struct r92c_rx_stat *stat, + int totlen) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct mbuf *m; + uint32_t rxdw0; + int pktlen; + + RTWN_ASSERT_LOCKED(sc); + + /* Dump Rx descriptor. */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV_DESC, + "%s: dw: 0 %08X, 1 %08X, 2 %08X, 3 %08X, 4 %08X, tsfl %08X\n", + __func__, le32toh(stat->rxdw0), le32toh(stat->rxdw1), + le32toh(stat->rxdw2), le32toh(stat->rxdw3), le32toh(stat->rxdw4), + le32toh(stat->tsf_low)); + + /* + * don't pass packets to the ieee80211 framework if the driver isn't + * RUNNING. + */ + if (!(sc->sc_flags & RTWN_RUNNING)) + return (NULL); + + rxdw0 = le32toh(stat->rxdw0); + if (__predict_false(rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR))) { + /* + * This should not happen since we setup our Rx filter + * to not receive these frames. + */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, + "%s: RX flags error (%s)\n", __func__, + rxdw0 & R92C_RXDW0_CRCERR ? "CRC" : "ICV"); + goto fail; + } + + pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); + if (__predict_false(pktlen < sizeof(struct ieee80211_frame_ack))) { + /* + * Should not happen (because of Rx filter setup). + */ + RTWN_DPRINTF(sc, RTWN_DEBUG_RECV, + "%s: frame is too short: %d\n", __func__, pktlen); + goto fail; + } + + m = m_get2(totlen, M_NOWAIT, MT_DATA, M_PKTHDR); + if (__predict_false(m == NULL)) { + device_printf(sc->sc_dev, "%s: could not allocate RX mbuf\n", + __func__); + goto fail; + } + + /* Finalize mbuf. */ + memcpy(mtod(m, uint8_t *), (uint8_t *)stat, totlen); + m->m_pkthdr.len = m->m_len = totlen; + + if (rtwn_check_frame(sc, m) != 0) { + m_freem(m); + goto fail; + } + + return (m); +fail: + counter_u64_add(ic->ic_ierrors, 1); + return (NULL); +} + +static struct mbuf * +rtwn_rxeof(struct rtwn_softc *sc, uint8_t *buf, int len) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + struct r92c_rx_stat *stat; + struct mbuf *m, *m0 = NULL; + uint32_t rxdw0; + int totlen, pktlen, infosz; + + /* Process packets. */ + while (len >= sizeof(*stat)) { + stat = (struct r92c_rx_stat *)buf; + rxdw0 = le32toh(stat->rxdw0); + + pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); + if (__predict_false(pktlen == 0)) + break; + + infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; + + /* Make sure everything fits in xfer. */ + totlen = sizeof(*stat) + infosz + pktlen; + if (totlen > len) + break; + + if (m0 == NULL) + m0 = m = rtwn_rx_copy_to_mbuf(sc, stat, totlen); + else { + m->m_next = rtwn_rx_copy_to_mbuf(sc, stat, totlen); + if (m->m_next != NULL) + m = m->m_next; + } + + /* Align next frame. */ + totlen = rtwn_usb_align_rx(uc, totlen, len); + buf += totlen; + len -= totlen; + } + + return (m0); +} + +static struct mbuf * +rtwn_report_intr(struct rtwn_usb_softc *uc, struct usb_xfer *xfer, + struct rtwn_data *data) +{ + struct rtwn_softc *sc = &uc->uc_sc; + struct ieee80211com *ic = &sc->sc_ic; + uint8_t *buf; + int len; + + usbd_xfer_status(xfer, &len, NULL, NULL, NULL); + + if (__predict_false(len < sizeof(struct r92c_rx_stat))) { + counter_u64_add(ic->ic_ierrors, 1); + return (NULL); + } + + buf = data->buf; + switch (rtwn_classify_intr(sc, buf, len)) { + case RTWN_RX_DATA: + return (rtwn_rxeof(sc, buf, len)); + case RTWN_RX_TX_REPORT: + if (sc->sc_ratectl != RTWN_RATECTL_NET80211) { + /* shouldn't happen */ + device_printf(sc->sc_dev, + "%s called while ratectl = %d!\n", + __func__, sc->sc_ratectl); + break; + } + + RTWN_NT_LOCK(sc); + rtwn_handle_tx_report(sc, buf, len); + RTWN_NT_UNLOCK(sc); + +#ifdef IEEE80211_SUPPORT_SUPERG + /* + * NB: this will executed only when 'report' bit is set. + */ + if (sc->sc_tx_n_active > 0 && --sc->sc_tx_n_active <= 1) + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); +#endif + break; + case RTWN_RX_OTHER: + rtwn_handle_c2h_report(sc, buf, len); + break; + default: + /* NOTREACHED */ + KASSERT(0, ("unknown Rx classification code")); + break; + } + + return (NULL); +} + +static struct ieee80211_node * +rtwn_rx_frame(struct rtwn_softc *sc, struct mbuf *m, int8_t *rssi) +{ + struct r92c_rx_stat stat; + + /* Imitate PCIe layout. */ + m_copydata(m, 0, sizeof(struct r92c_rx_stat), (caddr_t)&stat); + m_adj(m, sizeof(struct r92c_rx_stat)); + + return (rtwn_rx_common(sc, m, &stat, rssi)); +} + +void +rtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct rtwn_usb_softc *uc = usbd_xfer_softc(xfer); + struct rtwn_softc *sc = &uc->uc_sc; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni; + struct mbuf *m = NULL, *next; + struct rtwn_data *data; + int8_t nf, rssi; + + RTWN_ASSERT_LOCKED(sc); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + data = STAILQ_FIRST(&uc->uc_rx_active); + if (data == NULL) + goto tr_setup; + STAILQ_REMOVE_HEAD(&uc->uc_rx_active, next); + m = rtwn_report_intr(uc, xfer, data); + STAILQ_INSERT_TAIL(&uc->uc_rx_inactive, data, next); + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + data = STAILQ_FIRST(&uc->uc_rx_inactive); + if (data == NULL) { + KASSERT(m == NULL, ("mbuf isn't NULL")); + goto finish; + } + STAILQ_REMOVE_HEAD(&uc->uc_rx_inactive, next); + STAILQ_INSERT_TAIL(&uc->uc_rx_active, data, next); + usbd_xfer_set_frame_data(xfer, 0, data->buf, + usbd_xfer_max_len(xfer)); + usbd_transfer_submit(xfer); + + /* + * To avoid LOR we should unlock our private mutex here to call + * ieee80211_input() because here is at the end of a USB + * callback and safe to unlock. + */ + while (m != NULL) { + next = m->m_next; + m->m_next = NULL; + + ni = rtwn_rx_frame(sc, m, &rssi); + + RTWN_UNLOCK(sc); + + nf = RTWN_NOISE_FLOOR; + if (ni != NULL) { + if (ni->ni_flags & IEEE80211_NODE_HT) + m->m_flags |= M_AMPDU; + (void)ieee80211_input(ni, m, rssi - nf, nf); + ieee80211_free_node(ni); + } else { + (void)ieee80211_input_all(ic, m, + rssi - nf, nf); + } + RTWN_LOCK(sc); + m = next; + } + break; + default: + /* needs it to the inactive queue due to a error. */ + data = STAILQ_FIRST(&uc->uc_rx_active); + if (data != NULL) { + STAILQ_REMOVE_HEAD(&uc->uc_rx_active, next); + STAILQ_INSERT_TAIL(&uc->uc_rx_inactive, data, next); + } + if (error != USB_ERR_CANCELLED) { + usbd_xfer_set_stall(xfer); + counter_u64_add(ic->ic_ierrors, 1); + goto tr_setup; + } + break; + } +finish: + /* Finished receive; age anything left on the FF queue by a little bump */ + /* + * XXX TODO: just make this a callout timer schedule so we can + * flush the FF staging queue if we're approaching idle. + */ +#ifdef IEEE80211_SUPPORT_SUPERG + if (!(sc->sc_flags & RTWN_FW_LOADED)) + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); +#endif + + /* Kick-start more transmit in case we stalled */ + rtwn_start(sc); +} diff --git a/sys/dev/rtwn/usb/rtwn_usb_rx.h b/sys/dev/rtwn/usb/rtwn_usb_rx.h new file mode 100644 index 000000000000..e370816969a7 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_rx.h @@ -0,0 +1,24 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_USB_RX_H +#define RTWN_USB_RX_H + +void rtwn_bulk_rx_callback(struct usb_xfer *, usb_error_t); + +#endif /* RTWN_USB_RX_H */ diff --git a/sys/dev/rtwn/usb/rtwn_usb_tx.c b/sys/dev/rtwn/usb/rtwn_usb_tx.c new file mode 100644 index 000000000000..c30e9e746985 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_tx.c @@ -0,0 +1,282 @@ +/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ + +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2014 Kevin Lo + * Copyright (c) 2015-2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_wlan.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +static struct rtwn_data * _rtwn_usb_getbuf(struct rtwn_usb_softc *); +static struct rtwn_data * rtwn_usb_getbuf(struct rtwn_usb_softc *); +static void rtwn_usb_txeof(struct rtwn_usb_softc *, + struct rtwn_data *, int); + + +static const uint8_t wme2qid[] = + { RTWN_BULK_TX_BE, RTWN_BULK_TX_BK, + RTWN_BULK_TX_VI, RTWN_BULK_TX_VO }; + + +static struct rtwn_data * +_rtwn_usb_getbuf(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + struct rtwn_data *bf; + + bf = STAILQ_FIRST(&uc->uc_tx_inactive); + if (bf != NULL) + STAILQ_REMOVE_HEAD(&uc->uc_tx_inactive, next); + else { + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: out of xmit buffers\n", __func__); + } + return (bf); +} + +static struct rtwn_data * +rtwn_usb_getbuf(struct rtwn_usb_softc *uc) +{ + struct rtwn_softc *sc = &uc->uc_sc; + struct rtwn_data *bf; + + RTWN_ASSERT_LOCKED(sc); + + bf = _rtwn_usb_getbuf(uc); + if (bf == NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, "%s: stop queue\n", + __func__); + } + return (bf); +} + +static void +rtwn_usb_txeof(struct rtwn_usb_softc *uc, struct rtwn_data *data, int status) +{ + struct rtwn_softc *sc = &uc->uc_sc; + + RTWN_ASSERT_LOCKED(sc); + + if (data->ni != NULL) /* not a beacon frame */ + ieee80211_tx_complete(data->ni, data->m, status); + + if (sc->sc_ratectl != RTWN_RATECTL_NET80211) + if (sc->sc_tx_n_active > 0) + sc->sc_tx_n_active--; + + data->ni = NULL; + data->m = NULL; + + STAILQ_INSERT_TAIL(&uc->uc_tx_inactive, data, next); + sc->qfullmsk = 0; +#ifndef D4054 + if (STAILQ_EMPTY(&uc->uc_tx_active) && STAILQ_EMPTY(&uc->uc_tx_pending)) + sc->sc_tx_timer = 0; + else + sc->sc_tx_timer = 5; +#endif +} + +void +rtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) +{ + struct rtwn_usb_softc *uc = usbd_xfer_softc(xfer); + struct rtwn_softc *sc = &uc->uc_sc; + struct rtwn_data *data; + + RTWN_ASSERT_LOCKED(sc); + + switch (USB_GET_STATE(xfer)){ + case USB_ST_TRANSFERRED: + data = STAILQ_FIRST(&uc->uc_tx_active); + if (data == NULL) + goto tr_setup; + STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); + rtwn_usb_txeof(uc, data, 0); + /* FALLTHROUGH */ + case USB_ST_SETUP: +tr_setup: + data = STAILQ_FIRST(&uc->uc_tx_pending); + if (data == NULL) { + RTWN_DPRINTF(sc, RTWN_DEBUG_XMIT, + "%s: empty pending queue\n", __func__); + sc->sc_tx_n_active = 0; + goto finish; + } + STAILQ_REMOVE_HEAD(&uc->uc_tx_pending, next); + STAILQ_INSERT_TAIL(&uc->uc_tx_active, data, next); + + /* + * Note: if this is a beacon frame, ensure that it will go + * into appropriate queue. + */ + if (data->ni == NULL && RTWN_CHIP_HAS_BCNQ1(sc)) + rtwn_switch_bcnq(sc, data->id); + usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); + usbd_transfer_submit(xfer); + if (sc->sc_ratectl != RTWN_RATECTL_NET80211) + sc->sc_tx_n_active++; + break; + default: + data = STAILQ_FIRST(&uc->uc_tx_active); + if (data == NULL) + goto tr_setup; + STAILQ_REMOVE_HEAD(&uc->uc_tx_active, next); + rtwn_usb_txeof(uc, data, 1); + if (error != USB_ERR_CANCELLED) { + usbd_xfer_set_stall(xfer); + goto tr_setup; + } + break; + } +finish: +#ifdef IEEE80211_SUPPORT_SUPERG + /* + * If the TX active queue drops below a certain + * threshold, ensure we age fast-frames out so they're + * transmitted. + */ + if (sc->sc_ratectl != RTWN_RATECTL_NET80211 && + sc->sc_tx_n_active <= 1) { + /* XXX ew - net80211 should defer this for us! */ + + /* + * Note: this sc_tx_n_active currently tracks + * the number of pending transmit submissions + * and not the actual depth of the TX frames + * pending to the hardware. That means that + * we're going to end up with some sub-optimal + * aggregation behaviour. + */ + /* + * XXX TODO: just make this a callout timer schedule so we can + * flush the FF staging queue if we're approaching idle. + */ + rtwn_cmd_sleepable(sc, NULL, 0, rtwn_ff_flush_all); + } +#endif + /* Kick-start more transmit */ + rtwn_start(sc); +} + +static void +rtwn_usb_tx_checksum(struct rtwn_tx_desc_common *txd) +{ + txd->txdw7.usb_checksum = 0; + txd->txdw7.usb_checksum = rtwn_usb_calc_tx_checksum(txd); +} + +int +rtwn_usb_tx_start(struct rtwn_softc *sc, struct ieee80211_node *ni, + struct mbuf *m, uint8_t *tx_desc, uint8_t type, int id) +{ + struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); + struct rtwn_tx_desc_common *txd; + struct rtwn_data *data; + struct usb_xfer *xfer; + uint16_t ac; + + RTWN_ASSERT_LOCKED(sc); + + data = rtwn_usb_getbuf(uc); + if (data == NULL) + return (ENOBUFS); + + ac = M_WME_GETAC(m); + + switch (type) { + case IEEE80211_FC0_TYPE_CTL: + case IEEE80211_FC0_TYPE_MGT: + xfer = uc->uc_xfer[RTWN_BULK_TX_VO]; + break; + default: + xfer = uc->uc_xfer[wme2qid[ac]]; + break; + } + + txd = (struct rtwn_tx_desc_common *)tx_desc; + txd->pktlen = htole16(m->m_pkthdr.len); + txd->offset = sc->txdesc_len; + txd->flags0 |= RTWN_FLAGS0_OWN; + rtwn_usb_tx_checksum(txd); + + /* Dump Tx descriptor. */ + rtwn_dump_tx_desc(sc, tx_desc); + + memcpy(data->buf, tx_desc, sc->txdesc_len); + m_copydata(m, 0, m->m_pkthdr.len, + (caddr_t)(data->buf + sc->txdesc_len)); + + data->buflen = m->m_pkthdr.len + sc->txdesc_len; + data->id = id; + data->ni = ni; + if (data->ni != NULL) { + data->m = m; +#ifndef D4054 + sc->sc_tx_timer = 5; +#endif + } + + STAILQ_INSERT_TAIL(&uc->uc_tx_pending, data, next); + if (STAILQ_EMPTY(&uc->uc_tx_inactive)) + sc->qfullmsk = 1; + + usbd_transfer_start(xfer); + + return (0); +} diff --git a/sys/dev/rtwn/usb/rtwn_usb_tx.h b/sys/dev/rtwn/usb/rtwn_usb_tx.h new file mode 100644 index 000000000000..01527080d515 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_tx.h @@ -0,0 +1,26 @@ +/*- + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef RTWN_USB_TX_H +#define RTWN_USB_TX_H + +void rtwn_bulk_tx_callback(struct usb_xfer *, usb_error_t); +int rtwn_usb_tx_start(struct rtwn_softc *, struct ieee80211_node *, + struct mbuf *, uint8_t *, uint8_t, int); + +#endif /* RTWN_USB_TX_H */ diff --git a/sys/dev/rtwn/usb/rtwn_usb_var.h b/sys/dev/rtwn/usb/rtwn_usb_var.h new file mode 100644 index 000000000000..be7f8f198834 --- /dev/null +++ b/sys/dev/rtwn/usb/rtwn_usb_var.h @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 2010 Damien Bergamini + * Copyright (c) 2016 Andriy Voskoboinyk + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ + * $FreeBSD$ + */ + +#ifndef RTWN_USBVAR_H +#define RTWN_USBVAR_H + +#define RTWN_IFACE_INDEX 0 + +#define RTWN_USB_RX_LIST_COUNT 1 +#define RTWN_USB_TX_LIST_COUNT 16 + +struct rtwn_data { + uint8_t *buf; + /* 'id' is meaningful for beacons only */ + int id; + uint16_t buflen; + struct mbuf *m; + struct ieee80211_node *ni; + STAILQ_ENTRY(rtwn_data) next; +}; +typedef STAILQ_HEAD(, rtwn_data) rtwn_datahead; + +enum { + RTWN_BULK_RX, + RTWN_BULK_TX_BE, /* = WME_AC_BE */ + RTWN_BULK_TX_BK, /* = WME_AC_BK */ + RTWN_BULK_TX_VI, /* = WME_AC_VI */ + RTWN_BULK_TX_VO, /* = WME_AC_VO */ + RTWN_N_TRANSFER = 5, +}; + +#define RTWN_EP_QUEUES RTWN_BULK_RX + +struct rtwn_usb_softc { + struct rtwn_softc uc_sc; /* must be the first */ + struct usb_device *uc_udev; + struct usb_xfer *uc_xfer[RTWN_N_TRANSFER]; + + struct rtwn_data uc_rx[RTWN_USB_RX_LIST_COUNT]; + rtwn_datahead uc_rx_active; + rtwn_datahead uc_rx_inactive; + struct rtwn_data uc_tx[RTWN_USB_TX_LIST_COUNT]; + rtwn_datahead uc_tx_active; + rtwn_datahead uc_tx_inactive; + rtwn_datahead uc_tx_pending; + + int (*uc_align_rx)(int, int); + + int ntx; + int tx_agg_desc_num; +}; +#define RTWN_USB_SOFTC(sc) ((struct rtwn_usb_softc *)(sc)) + +#define rtwn_usb_align_rx(_uc, _totlen, _len) \ + (((_uc)->uc_align_rx)((_totlen), (_len))) + +#endif /* RTWN_USBVAR_H */ diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c index 3de87ae7185c..7e32b706c2d7 100644 --- a/sys/dev/sound/usb/uaudio.c +++ b/sys/dev/sound/usb/uaudio.c @@ -95,6 +95,7 @@ __FBSDID("$FreeBSD$"); static int uaudio_default_rate = 0; /* use rate list */ static int uaudio_default_bits = 32; static int uaudio_default_channels = 0; /* use default */ +static int uaudio_buffer_ms = 8; #ifdef USB_DEBUG static int uaudio_debug = 0; @@ -109,9 +110,32 @@ SYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_bits, CTLFLAG_RWTUN, &uaudio_default_bits, 0, "uaudio default sample bits"); SYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_channels, CTLFLAG_RWTUN, &uaudio_default_channels, 0, "uaudio default sample channels"); + +static int +uaudio_buffer_ms_sysctl(SYSCTL_HANDLER_ARGS) +{ + int err, val; + + val = uaudio_buffer_ms; + err = sysctl_handle_int(oidp, &val, 0, req); + + if (err != 0 || req->newptr == NULL || val == uaudio_buffer_ms) + return (err); + + if (val > 8) + val = 8; + else if (val < 2) + val = 2; + + uaudio_buffer_ms = val; + + return (0); +} +SYSCTL_PROC(_hw_usb_uaudio, OID_AUTO, buffer_ms, CTLTYPE_INT | CTLFLAG_RWTUN, + 0, sizeof(int), uaudio_buffer_ms_sysctl, "I", + "uaudio buffering delay from 2ms to 8ms"); #endif -#define UAUDIO_IRQS (8000 / UAUDIO_NFRAMES) /* interrupts per second */ #define UAUDIO_NFRAMES 64 /* must be factor of 8 due HS-USB */ #define UAUDIO_NCHANBUFS 2 /* number of outstanding request */ #define UAUDIO_RECURSE_LIMIT 255 /* rounds */ @@ -1278,10 +1302,10 @@ uaudio_configure_msg_sub(struct uaudio_softc *sc, if (fps < 8000) { /* FULL speed USB */ - frames = 8; + frames = uaudio_buffer_ms; } else { /* HIGH speed USB */ - frames = UAUDIO_NFRAMES; + frames = uaudio_buffer_ms * 8; } fps_shift = usbd_xfer_get_fps_shift(chan->xfer[0]); @@ -2158,8 +2182,9 @@ uaudio_chan_play_callback(struct usb_xfer *xfer, usb_error_t error) } /* start the SYNC transfer one time per second, if any */ - if (++(ch->intr_counter) >= UAUDIO_IRQS) { - ch->intr_counter = 0; + ch->intr_counter += ch->intr_frames; + if (ch->intr_counter >= ch->frames_per_second) { + ch->intr_counter -= ch->frames_per_second; usbd_transfer_start(ch->xfer[UAUDIO_NCHANBUFS]); } diff --git a/sys/dev/urtwn/if_urtwn.c b/sys/dev/urtwn/if_urtwn.c deleted file mode 100644 index 7c22aaa6faa3..000000000000 --- a/sys/dev/urtwn/if_urtwn.c +++ /dev/null @@ -1,5681 +0,0 @@ -/* $OpenBSD: if_urtwn.c,v 1.16 2011/02/10 17:26:40 jakemsr Exp $ */ - -/*- - * Copyright (c) 2010 Damien Bergamini - * Copyright (c) 2014 Kevin Lo - * Copyright (c) 2015 Andriy Voskoboinyk - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -__FBSDID("$FreeBSD$"); - -/* - * Driver for Realtek RTL8188CE-VAU/RTL8188CUS/RTL8188EU/RTL8188RU/RTL8192CU. - */ - -#include "opt_wlan.h" -#include "opt_urtwn.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#ifdef IEEE80211_SUPPORT_SUPERG -#include -#endif - -#include -#include -#include -#include "usbdevs.h" - -#include - -#include -#include - -#ifdef USB_DEBUG -enum { - URTWN_DEBUG_XMIT = 0x00000001, /* basic xmit operation */ - URTWN_DEBUG_RECV = 0x00000002, /* basic recv operation */ - URTWN_DEBUG_STATE = 0x00000004, /* 802.11 state transitions */ - URTWN_DEBUG_RA = 0x00000008, /* f/w rate adaptation setup */ - URTWN_DEBUG_USB = 0x00000010, /* usb requests */ - URTWN_DEBUG_FIRMWARE = 0x00000020, /* firmware(9) loading debug */ - URTWN_DEBUG_BEACON = 0x00000040, /* beacon handling */ - URTWN_DEBUG_INTR = 0x00000080, /* ISR */ - URTWN_DEBUG_TEMP = 0x00000100, /* temperature calibration */ - URTWN_DEBUG_ROM = 0x00000200, /* various ROM info */ - URTWN_DEBUG_KEY = 0x00000400, /* crypto keys management */ - URTWN_DEBUG_TXPWR = 0x00000800, /* dump Tx power values */ - URTWN_DEBUG_RSSI = 0x00001000, /* dump RSSI lookups */ - URTWN_DEBUG_ANY = 0xffffffff -}; - -#define URTWN_DPRINTF(_sc, _m, ...) do { \ - if ((_sc)->sc_debug & (_m)) \ - device_printf((_sc)->sc_dev, __VA_ARGS__); \ -} while(0) - -#else -#define URTWN_DPRINTF(_sc, _m, ...) do { (void) sc; } while (0) -#endif - -#define IEEE80211_HAS_ADDR4(wh) IEEE80211_IS_DSTODS(wh) - -static int urtwn_enable_11n = 1; -TUNABLE_INT("hw.usb.urtwn.enable_11n", &urtwn_enable_11n); - -/* various supported device vendors/products */ -static const STRUCT_USB_HOST_ID urtwn_devs[] = { -#define URTWN_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } -#define URTWN_RTL8188E_DEV(v,p) \ - { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, URTWN_RTL8188E) } -#define URTWN_RTL8188E 1 - URTWN_DEV(ABOCOM, RTL8188CU_1), - URTWN_DEV(ABOCOM, RTL8188CU_2), - URTWN_DEV(ABOCOM, RTL8192CU), - URTWN_DEV(ASUS, RTL8192CU), - URTWN_DEV(ASUS, USBN10NANO), - URTWN_DEV(AZUREWAVE, RTL8188CE_1), - URTWN_DEV(AZUREWAVE, RTL8188CE_2), - URTWN_DEV(AZUREWAVE, RTL8188CU), - URTWN_DEV(BELKIN, F7D2102), - URTWN_DEV(BELKIN, RTL8188CU), - URTWN_DEV(BELKIN, RTL8192CU), - URTWN_DEV(CHICONY, RTL8188CUS_1), - URTWN_DEV(CHICONY, RTL8188CUS_2), - URTWN_DEV(CHICONY, RTL8188CUS_3), - URTWN_DEV(CHICONY, RTL8188CUS_4), - URTWN_DEV(CHICONY, RTL8188CUS_5), - URTWN_DEV(COREGA, RTL8192CU), - URTWN_DEV(DLINK, RTL8188CU), - URTWN_DEV(DLINK, RTL8192CU_1), - URTWN_DEV(DLINK, RTL8192CU_2), - URTWN_DEV(DLINK, RTL8192CU_3), - URTWN_DEV(DLINK, DWA131B), - URTWN_DEV(EDIMAX, EW7811UN), - URTWN_DEV(EDIMAX, RTL8192CU), - URTWN_DEV(FEIXUN, RTL8188CU), - URTWN_DEV(FEIXUN, RTL8192CU), - URTWN_DEV(GUILLEMOT, HWNUP150), - URTWN_DEV(HAWKING, RTL8192CU), - URTWN_DEV(HP3, RTL8188CU), - URTWN_DEV(NETGEAR, WNA1000M), - URTWN_DEV(NETGEAR, RTL8192CU), - URTWN_DEV(NETGEAR4, RTL8188CU), - URTWN_DEV(NOVATECH, RTL8188CU), - URTWN_DEV(PLANEX2, RTL8188CU_1), - URTWN_DEV(PLANEX2, RTL8188CU_2), - URTWN_DEV(PLANEX2, RTL8188CU_3), - URTWN_DEV(PLANEX2, RTL8188CU_4), - URTWN_DEV(PLANEX2, RTL8188CUS), - URTWN_DEV(PLANEX2, RTL8192CU), - URTWN_DEV(REALTEK, RTL8188CE_0), - URTWN_DEV(REALTEK, RTL8188CE_1), - URTWN_DEV(REALTEK, RTL8188CTV), - URTWN_DEV(REALTEK, RTL8188CU_0), - URTWN_DEV(REALTEK, RTL8188CU_1), - URTWN_DEV(REALTEK, RTL8188CU_2), - URTWN_DEV(REALTEK, RTL8188CU_3), - URTWN_DEV(REALTEK, RTL8188CU_COMBO), - URTWN_DEV(REALTEK, RTL8188CUS), - URTWN_DEV(REALTEK, RTL8188RU_1), - URTWN_DEV(REALTEK, RTL8188RU_2), - URTWN_DEV(REALTEK, RTL8188RU_3), - URTWN_DEV(REALTEK, RTL8191CU), - URTWN_DEV(REALTEK, RTL8192CE), - URTWN_DEV(REALTEK, RTL8192CU), - URTWN_DEV(SITECOMEU, RTL8188CU_1), - URTWN_DEV(SITECOMEU, RTL8188CU_2), - URTWN_DEV(SITECOMEU, RTL8192CU), - URTWN_DEV(TRENDNET, RTL8188CU), - URTWN_DEV(TRENDNET, RTL8192CU), - URTWN_DEV(ZYXEL, RTL8192CU), - /* URTWN_RTL8188E */ - URTWN_RTL8188E_DEV(ABOCOM, RTL8188EU), - URTWN_RTL8188E_DEV(DLINK, DWA123D1), - URTWN_RTL8188E_DEV(DLINK, DWA125D1), - URTWN_RTL8188E_DEV(ELECOM, WDC150SU2M), - URTWN_RTL8188E_DEV(REALTEK, RTL8188ETV), - URTWN_RTL8188E_DEV(REALTEK, RTL8188EU), -#undef URTWN_RTL8188E_DEV -#undef URTWN_DEV -}; - -static device_probe_t urtwn_match; -static device_attach_t urtwn_attach; -static device_detach_t urtwn_detach; - -static usb_callback_t urtwn_bulk_tx_callback; -static usb_callback_t urtwn_bulk_rx_callback; - -static void urtwn_sysctlattach(struct urtwn_softc *); -static void urtwn_drain_mbufq(struct urtwn_softc *); -static usb_error_t urtwn_do_request(struct urtwn_softc *, - struct usb_device_request *, void *); -static struct ieee80211vap *urtwn_vap_create(struct ieee80211com *, - const char [IFNAMSIZ], int, enum ieee80211_opmode, int, - const uint8_t [IEEE80211_ADDR_LEN], - const uint8_t [IEEE80211_ADDR_LEN]); -static void urtwn_vap_delete(struct ieee80211vap *); -static void urtwn_vap_clear_tx(struct urtwn_softc *, - struct ieee80211vap *); -static void urtwn_vap_clear_tx_queue(struct urtwn_softc *, - urtwn_datahead *, struct ieee80211vap *); -static struct mbuf * urtwn_rx_copy_to_mbuf(struct urtwn_softc *, - struct r92c_rx_stat *, int); -static struct mbuf * urtwn_report_intr(struct usb_xfer *, - struct urtwn_data *); -static struct mbuf * urtwn_rxeof(struct urtwn_softc *, uint8_t *, int); -static void urtwn_r88e_ratectl_tx_complete(struct urtwn_softc *, - void *); -static struct ieee80211_node *urtwn_rx_frame(struct urtwn_softc *, - struct mbuf *, int8_t *); -static void urtwn_txeof(struct urtwn_softc *, struct urtwn_data *, - int); -static int urtwn_alloc_list(struct urtwn_softc *, - struct urtwn_data[], int, int); -static int urtwn_alloc_rx_list(struct urtwn_softc *); -static int urtwn_alloc_tx_list(struct urtwn_softc *); -static void urtwn_free_list(struct urtwn_softc *, - struct urtwn_data data[], int); -static void urtwn_free_rx_list(struct urtwn_softc *); -static void urtwn_free_tx_list(struct urtwn_softc *); -static struct urtwn_data * _urtwn_getbuf(struct urtwn_softc *); -static struct urtwn_data * urtwn_getbuf(struct urtwn_softc *); -static usb_error_t urtwn_write_region_1(struct urtwn_softc *, uint16_t, - uint8_t *, int); -static usb_error_t urtwn_write_1(struct urtwn_softc *, uint16_t, uint8_t); -static usb_error_t urtwn_write_2(struct urtwn_softc *, uint16_t, uint16_t); -static usb_error_t urtwn_write_4(struct urtwn_softc *, uint16_t, uint32_t); -static usb_error_t urtwn_read_region_1(struct urtwn_softc *, uint16_t, - uint8_t *, int); -static uint8_t urtwn_read_1(struct urtwn_softc *, uint16_t); -static uint16_t urtwn_read_2(struct urtwn_softc *, uint16_t); -static uint32_t urtwn_read_4(struct urtwn_softc *, uint16_t); -static int urtwn_fw_cmd(struct urtwn_softc *, uint8_t, - const void *, int); -static void urtwn_cmdq_cb(void *, int); -static int urtwn_cmd_sleepable(struct urtwn_softc *, const void *, - size_t, CMD_FUNC_PROTO); -static void urtwn_r92c_rf_write(struct urtwn_softc *, int, - uint8_t, uint32_t); -static void urtwn_r88e_rf_write(struct urtwn_softc *, int, - uint8_t, uint32_t); -static uint32_t urtwn_rf_read(struct urtwn_softc *, int, uint8_t); -static int urtwn_llt_write(struct urtwn_softc *, uint32_t, - uint32_t); -static int urtwn_efuse_read_next(struct urtwn_softc *, uint8_t *); -static int urtwn_efuse_read_data(struct urtwn_softc *, uint8_t *, - uint8_t, uint8_t); -#ifdef USB_DEBUG -static void urtwn_dump_rom_contents(struct urtwn_softc *, - uint8_t *, uint16_t); -#endif -static int urtwn_efuse_read(struct urtwn_softc *, uint8_t *, - uint16_t); -static int urtwn_efuse_switch_power(struct urtwn_softc *); -static int urtwn_read_chipid(struct urtwn_softc *); -static int urtwn_read_rom(struct urtwn_softc *); -static int urtwn_r88e_read_rom(struct urtwn_softc *); -static int urtwn_ra_init(struct urtwn_softc *); -static void urtwn_init_beacon(struct urtwn_softc *, - struct urtwn_vap *); -static int urtwn_setup_beacon(struct urtwn_softc *, - struct ieee80211_node *); -static void urtwn_update_beacon(struct ieee80211vap *, int); -static int urtwn_tx_beacon(struct urtwn_softc *sc, - struct urtwn_vap *); -static int urtwn_key_alloc(struct ieee80211vap *, - struct ieee80211_key *, ieee80211_keyix *, - ieee80211_keyix *); -static void urtwn_key_set_cb(struct urtwn_softc *, - union sec_param *); -static void urtwn_key_del_cb(struct urtwn_softc *, - union sec_param *); -static int urtwn_key_set(struct ieee80211vap *, - const struct ieee80211_key *); -static int urtwn_key_delete(struct ieee80211vap *, - const struct ieee80211_key *); -static void urtwn_tsf_task_adhoc(void *, int); -static void urtwn_tsf_sync_enable(struct urtwn_softc *, - struct ieee80211vap *); -static void urtwn_get_tsf(struct urtwn_softc *, uint64_t *); -static void urtwn_set_led(struct urtwn_softc *, int, int); -static void urtwn_set_mode(struct urtwn_softc *, uint8_t); -static void urtwn_ibss_recv_mgmt(struct ieee80211_node *, - struct mbuf *, int, - const struct ieee80211_rx_stats *, int, int); -static int urtwn_newstate(struct ieee80211vap *, - enum ieee80211_state, int); -static void urtwn_calib_to(void *); -static void urtwn_calib_cb(struct urtwn_softc *, - union sec_param *); -static void urtwn_watchdog(void *); -static void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t); -static int8_t urtwn_get_rssi(struct urtwn_softc *, int, void *); -static int8_t urtwn_r88e_get_rssi(struct urtwn_softc *, int, void *); -static int urtwn_tx_data(struct urtwn_softc *, - struct ieee80211_node *, struct mbuf *, - struct urtwn_data *); -static int urtwn_tx_raw(struct urtwn_softc *, - struct ieee80211_node *, struct mbuf *, - struct urtwn_data *, - const struct ieee80211_bpf_params *); -static void urtwn_tx_start(struct urtwn_softc *, struct mbuf *, - uint8_t, struct urtwn_data *); -static int urtwn_transmit(struct ieee80211com *, struct mbuf *); -static void urtwn_start(struct urtwn_softc *); -static void urtwn_parent(struct ieee80211com *); -static int urtwn_r92c_power_on(struct urtwn_softc *); -static int urtwn_r88e_power_on(struct urtwn_softc *); -static void urtwn_r92c_power_off(struct urtwn_softc *); -static void urtwn_r88e_power_off(struct urtwn_softc *); -static int urtwn_llt_init(struct urtwn_softc *); -#ifndef URTWN_WITHOUT_UCODE -static void urtwn_fw_reset(struct urtwn_softc *); -static void urtwn_r88e_fw_reset(struct urtwn_softc *); -static int urtwn_fw_loadpage(struct urtwn_softc *, int, - const uint8_t *, int); -static int urtwn_load_firmware(struct urtwn_softc *); -#endif -static int urtwn_dma_init(struct urtwn_softc *); -static int urtwn_mac_init(struct urtwn_softc *); -static void urtwn_bb_init(struct urtwn_softc *); -static void urtwn_rf_init(struct urtwn_softc *); -static void urtwn_cam_init(struct urtwn_softc *); -static int urtwn_cam_write(struct urtwn_softc *, uint32_t, - uint32_t); -static void urtwn_pa_bias_init(struct urtwn_softc *); -static void urtwn_rxfilter_init(struct urtwn_softc *); -static void urtwn_edca_init(struct urtwn_softc *); -static void urtwn_write_txpower(struct urtwn_softc *, int, - uint16_t[]); -static void urtwn_get_txpower(struct urtwn_softc *, int, - struct ieee80211_channel *, - struct ieee80211_channel *, uint16_t[]); -static void urtwn_r88e_get_txpower(struct urtwn_softc *, int, - struct ieee80211_channel *, - struct ieee80211_channel *, uint16_t[]); -static void urtwn_set_txpower(struct urtwn_softc *, - struct ieee80211_channel *, - struct ieee80211_channel *); -static void urtwn_set_rx_bssid_all(struct urtwn_softc *, int); -static void urtwn_set_gain(struct urtwn_softc *, uint8_t); -static void urtwn_scan_start(struct ieee80211com *); -static void urtwn_scan_end(struct ieee80211com *); -static void urtwn_getradiocaps(struct ieee80211com *, int, int *, - struct ieee80211_channel[]); -static void urtwn_set_channel(struct ieee80211com *); -static int urtwn_wme_update(struct ieee80211com *); -static void urtwn_update_slot(struct ieee80211com *); -static void urtwn_update_slot_cb(struct urtwn_softc *, - union sec_param *); -static void urtwn_update_aifs(struct urtwn_softc *, uint8_t); -static uint8_t urtwn_get_multi_pos(const uint8_t[]); -static void urtwn_set_multi(struct urtwn_softc *); -static void urtwn_set_promisc(struct urtwn_softc *); -static void urtwn_update_promisc(struct ieee80211com *); -static void urtwn_update_mcast(struct ieee80211com *); -static struct ieee80211_node *urtwn_node_alloc(struct ieee80211vap *, - const uint8_t mac[IEEE80211_ADDR_LEN]); -static void urtwn_newassoc(struct ieee80211_node *, int); -static void urtwn_node_free(struct ieee80211_node *); -static void urtwn_set_chan(struct urtwn_softc *, - struct ieee80211_channel *, - struct ieee80211_channel *); -static void urtwn_iq_calib(struct urtwn_softc *); -static void urtwn_lc_calib(struct urtwn_softc *); -static void urtwn_temp_calib(struct urtwn_softc *); -static void urtwn_setup_static_keys(struct urtwn_softc *, - struct urtwn_vap *); -static int urtwn_init(struct urtwn_softc *); -static void urtwn_stop(struct urtwn_softc *); -static void urtwn_abort_xfers(struct urtwn_softc *); -static int urtwn_raw_xmit(struct ieee80211_node *, struct mbuf *, - const struct ieee80211_bpf_params *); -static void urtwn_ms_delay(struct urtwn_softc *); - -/* Aliases. */ -#define urtwn_bb_write urtwn_write_4 -#define urtwn_bb_read urtwn_read_4 - -static const struct usb_config urtwn_config[URTWN_N_TRANSFER] = { - [URTWN_BULK_RX] = { - .type = UE_BULK, - .endpoint = UE_ADDR_ANY, - .direction = UE_DIR_IN, - .bufsize = URTWN_RXBUFSZ, - .flags = { - .pipe_bof = 1, - .short_xfer_ok = 1 - }, - .callback = urtwn_bulk_rx_callback, - }, - [URTWN_BULK_TX_BE] = { - .type = UE_BULK, - .endpoint = 0x03, - .direction = UE_DIR_OUT, - .bufsize = URTWN_TXBUFSZ, - .flags = { - .ext_buffer = 1, - .pipe_bof = 1, - .force_short_xfer = 1 - }, - .callback = urtwn_bulk_tx_callback, - .timeout = URTWN_TX_TIMEOUT, /* ms */ - }, - [URTWN_BULK_TX_BK] = { - .type = UE_BULK, - .endpoint = 0x03, - .direction = UE_DIR_OUT, - .bufsize = URTWN_TXBUFSZ, - .flags = { - .ext_buffer = 1, - .pipe_bof = 1, - .force_short_xfer = 1, - }, - .callback = urtwn_bulk_tx_callback, - .timeout = URTWN_TX_TIMEOUT, /* ms */ - }, - [URTWN_BULK_TX_VI] = { - .type = UE_BULK, - .endpoint = 0x02, - .direction = UE_DIR_OUT, - .bufsize = URTWN_TXBUFSZ, - .flags = { - .ext_buffer = 1, - .pipe_bof = 1, - .force_short_xfer = 1 - }, - .callback = urtwn_bulk_tx_callback, - .timeout = URTWN_TX_TIMEOUT, /* ms */ - }, - [URTWN_BULK_TX_VO] = { - .type = UE_BULK, - .endpoint = 0x02, - .direction = UE_DIR_OUT, - .bufsize = URTWN_TXBUFSZ, - .flags = { - .ext_buffer = 1, - .pipe_bof = 1, - .force_short_xfer = 1 - }, - .callback = urtwn_bulk_tx_callback, - .timeout = URTWN_TX_TIMEOUT, /* ms */ - }, -}; - -static const struct wme_to_queue { - uint16_t reg; - uint8_t qid; -} wme2queue[WME_NUM_AC] = { - { R92C_EDCA_BE_PARAM, URTWN_BULK_TX_BE}, - { R92C_EDCA_BK_PARAM, URTWN_BULK_TX_BK}, - { R92C_EDCA_VI_PARAM, URTWN_BULK_TX_VI}, - { R92C_EDCA_VO_PARAM, URTWN_BULK_TX_VO} -}; - -static const uint8_t urtwn_chan_2ghz[] = - { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }; - -static int -urtwn_match(device_t self) -{ - struct usb_attach_arg *uaa = device_get_ivars(self); - - if (uaa->usb_mode != USB_MODE_HOST) - return (ENXIO); - if (uaa->info.bConfigIndex != URTWN_CONFIG_INDEX) - return (ENXIO); - if (uaa->info.bIfaceIndex != URTWN_IFACE_INDEX) - return (ENXIO); - - return (usbd_lookup_id_by_uaa(urtwn_devs, sizeof(urtwn_devs), uaa)); -} - -static void -urtwn_update_chw(struct ieee80211com *ic) -{ -} - -static int -urtwn_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap) -{ - - /* We're driving this ourselves (eventually); don't involve net80211 */ - return (0); -} - -static int -urtwn_attach(device_t self) -{ - struct usb_attach_arg *uaa = device_get_ivars(self); - struct urtwn_softc *sc = device_get_softc(self); - struct ieee80211com *ic = &sc->sc_ic; - int error; - - device_set_usb_desc(self); - sc->sc_udev = uaa->device; - sc->sc_dev = self; - if (USB_GET_DRIVER_INFO(uaa) == URTWN_RTL8188E) - sc->chip |= URTWN_CHIP_88E; - -#ifdef USB_DEBUG - int debug; - if (resource_int_value(device_get_name(sc->sc_dev), - device_get_unit(sc->sc_dev), "debug", &debug) == 0) - sc->sc_debug = debug; -#endif - - mtx_init(&sc->sc_mtx, device_get_nameunit(self), - MTX_NETWORK_LOCK, MTX_DEF); - URTWN_CMDQ_LOCK_INIT(sc); - URTWN_NT_LOCK_INIT(sc); - callout_init(&sc->sc_calib_to, 0); - callout_init(&sc->sc_watchdog_ch, 0); - mbufq_init(&sc->sc_snd, ifqmaxlen); - - sc->sc_iface_index = URTWN_IFACE_INDEX; - error = usbd_transfer_setup(uaa->device, &sc->sc_iface_index, - sc->sc_xfer, urtwn_config, URTWN_N_TRANSFER, sc, &sc->sc_mtx); - if (error) { - device_printf(self, "could not allocate USB transfers, " - "err=%s\n", usbd_errstr(error)); - goto detach; - } - - URTWN_LOCK(sc); - - error = urtwn_read_chipid(sc); - if (error) { - device_printf(sc->sc_dev, "unsupported test chip\n"); - URTWN_UNLOCK(sc); - goto detach; - } - - /* Determine number of Tx/Rx chains. */ - if (sc->chip & URTWN_CHIP_92C) { - sc->ntxchains = (sc->chip & URTWN_CHIP_92C_1T2R) ? 1 : 2; - sc->nrxchains = 2; - } else { - sc->ntxchains = 1; - sc->nrxchains = 1; - } - - if (sc->chip & URTWN_CHIP_88E) - error = urtwn_r88e_read_rom(sc); - else - error = urtwn_read_rom(sc); - if (error != 0) { - device_printf(sc->sc_dev, "%s: cannot read rom, error %d\n", - __func__, error); - URTWN_UNLOCK(sc); - goto detach; - } - - device_printf(sc->sc_dev, "MAC/BB RTL%s, RF 6052 %dT%dR\n", - (sc->chip & URTWN_CHIP_92C) ? "8192CU" : - (sc->chip & URTWN_CHIP_88E) ? "8188EU" : - (sc->board_type == R92C_BOARD_TYPE_HIGHPA) ? "8188RU" : - (sc->board_type == R92C_BOARD_TYPE_MINICARD) ? "8188CE-VAU" : - "8188CUS", sc->ntxchains, sc->nrxchains); - - URTWN_UNLOCK(sc); - - ic->ic_softc = sc; - ic->ic_name = device_get_nameunit(self); - ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */ - ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */ - - /* set device capabilities */ - ic->ic_caps = - IEEE80211_C_STA /* station mode */ - | IEEE80211_C_MONITOR /* monitor mode */ - | IEEE80211_C_IBSS /* adhoc mode */ - | IEEE80211_C_HOSTAP /* hostap mode */ - | IEEE80211_C_SHPREAMBLE /* short preamble supported */ - | IEEE80211_C_SHSLOT /* short slot time supported */ -#if 0 - | IEEE80211_C_BGSCAN /* capable of bg scanning */ -#endif - | IEEE80211_C_WPA /* 802.11i */ - | IEEE80211_C_WME /* 802.11e */ - | IEEE80211_C_SWAMSDUTX /* Do software A-MSDU TX */ - | IEEE80211_C_FF /* Atheros fast-frames */ - ; - - ic->ic_cryptocaps = - IEEE80211_CRYPTO_WEP | - IEEE80211_CRYPTO_TKIP | - IEEE80211_CRYPTO_AES_CCM; - - /* Assume they're all 11n capable for now */ - if (urtwn_enable_11n) { - device_printf(self, "enabling 11n\n"); - ic->ic_htcaps = IEEE80211_HTC_HT | -#if 0 - IEEE80211_HTC_AMPDU | -#endif - IEEE80211_HTC_AMSDU | - IEEE80211_HTCAP_MAXAMSDU_3839 | - IEEE80211_HTCAP_SMPS_OFF; - /* no HT40 just yet */ - // ic->ic_htcaps |= IEEE80211_HTCAP_CHWIDTH40; - - /* XXX TODO: verify chains versus streams for urtwn */ - ic->ic_txstream = sc->ntxchains; - ic->ic_rxstream = sc->nrxchains; - } - - /* XXX TODO: setup regdomain if R92C_CHANNEL_PLAN_BY_HW bit is set. */ - - urtwn_getradiocaps(ic, IEEE80211_CHAN_MAX, &ic->ic_nchans, - ic->ic_channels); - - ieee80211_ifattach(ic); - ic->ic_raw_xmit = urtwn_raw_xmit; - ic->ic_scan_start = urtwn_scan_start; - ic->ic_scan_end = urtwn_scan_end; - ic->ic_getradiocaps = urtwn_getradiocaps; - ic->ic_set_channel = urtwn_set_channel; - ic->ic_transmit = urtwn_transmit; - ic->ic_parent = urtwn_parent; - ic->ic_vap_create = urtwn_vap_create; - ic->ic_vap_delete = urtwn_vap_delete; - ic->ic_wme.wme_update = urtwn_wme_update; - ic->ic_updateslot = urtwn_update_slot; - ic->ic_update_promisc = urtwn_update_promisc; - ic->ic_update_mcast = urtwn_update_mcast; - if (sc->chip & URTWN_CHIP_88E) { - ic->ic_node_alloc = urtwn_node_alloc; - ic->ic_newassoc = urtwn_newassoc; - sc->sc_node_free = ic->ic_node_free; - ic->ic_node_free = urtwn_node_free; - } - ic->ic_update_chw = urtwn_update_chw; - ic->ic_ampdu_enable = urtwn_ampdu_enable; - - ieee80211_radiotap_attach(ic, &sc->sc_txtap.wt_ihdr, - sizeof(sc->sc_txtap), URTWN_TX_RADIOTAP_PRESENT, - &sc->sc_rxtap.wr_ihdr, sizeof(sc->sc_rxtap), - URTWN_RX_RADIOTAP_PRESENT); - - TASK_INIT(&sc->cmdq_task, 0, urtwn_cmdq_cb, sc); - - urtwn_sysctlattach(sc); - - if (bootverbose) - ieee80211_announce(ic); - - return (0); - -detach: - urtwn_detach(self); - return (ENXIO); /* failure */ -} - -static void -urtwn_sysctlattach(struct urtwn_softc *sc) -{ -#ifdef USB_DEBUG - struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); - struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); - - SYSCTL_ADD_U32(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "debug", CTLFLAG_RW, &sc->sc_debug, sc->sc_debug, - "control debugging printfs"); -#endif -} - -static int -urtwn_detach(device_t self) -{ - struct urtwn_softc *sc = device_get_softc(self); - struct ieee80211com *ic = &sc->sc_ic; - - /* Prevent further ioctls. */ - URTWN_LOCK(sc); - sc->sc_flags |= URTWN_DETACHED; - URTWN_UNLOCK(sc); - - urtwn_stop(sc); - - callout_drain(&sc->sc_watchdog_ch); - callout_drain(&sc->sc_calib_to); - - /* stop all USB transfers */ - usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER); - - if (ic->ic_softc == sc) { - ieee80211_draintask(ic, &sc->cmdq_task); - ieee80211_ifdetach(ic); - } - - URTWN_NT_LOCK_DESTROY(sc); - URTWN_CMDQ_LOCK_DESTROY(sc); - mtx_destroy(&sc->sc_mtx); - - return (0); -} - -static void -urtwn_drain_mbufq(struct urtwn_softc *sc) -{ - struct mbuf *m; - struct ieee80211_node *ni; - URTWN_ASSERT_LOCKED(sc); - while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { - ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; - m->m_pkthdr.rcvif = NULL; - ieee80211_free_node(ni); - m_freem(m); - } -} - -static usb_error_t -urtwn_do_request(struct urtwn_softc *sc, struct usb_device_request *req, - void *data) -{ - usb_error_t err; - int ntries = 10; - - URTWN_ASSERT_LOCKED(sc); - - while (ntries--) { - err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, - req, data, 0, NULL, 250 /* ms */); - if (err == 0) - break; - - URTWN_DPRINTF(sc, URTWN_DEBUG_USB, - "%s: control request failed, %s (retries left: %d)\n", - __func__, usbd_errstr(err), ntries); - usb_pause_mtx(&sc->sc_mtx, hz / 100); - } - return (err); -} - -static struct ieee80211vap * -urtwn_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ], int unit, - enum ieee80211_opmode opmode, int flags, - const uint8_t bssid[IEEE80211_ADDR_LEN], - const uint8_t mac[IEEE80211_ADDR_LEN]) -{ - struct urtwn_softc *sc = ic->ic_softc; - struct urtwn_vap *uvp; - struct ieee80211vap *vap; - - if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */ - return (NULL); - - uvp = malloc(sizeof(struct urtwn_vap), M_80211_VAP, M_WAITOK | M_ZERO); - vap = &uvp->vap; - /* enable s/w bmiss handling for sta mode */ - - if (ieee80211_vap_setup(ic, vap, name, unit, opmode, - flags | IEEE80211_CLONE_NOBEACONS, bssid) != 0) { - /* out of memory */ - free(uvp, M_80211_VAP); - return (NULL); - } - - if (opmode == IEEE80211_M_HOSTAP || opmode == IEEE80211_M_IBSS) - urtwn_init_beacon(sc, uvp); - - /* override state transition machine */ - uvp->newstate = vap->iv_newstate; - vap->iv_newstate = urtwn_newstate; - vap->iv_update_beacon = urtwn_update_beacon; - vap->iv_key_alloc = urtwn_key_alloc; - vap->iv_key_set = urtwn_key_set; - vap->iv_key_delete = urtwn_key_delete; - - /* 802.11n parameters */ - vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_16; - vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_64K; - - if (opmode == IEEE80211_M_IBSS) { - uvp->recv_mgmt = vap->iv_recv_mgmt; - vap->iv_recv_mgmt = urtwn_ibss_recv_mgmt; - TASK_INIT(&uvp->tsf_task_adhoc, 0, urtwn_tsf_task_adhoc, vap); - } - - if (URTWN_CHIP_HAS_RATECTL(sc)) - ieee80211_ratectl_init(vap); - /* complete setup */ - ieee80211_vap_attach(vap, ieee80211_media_change, - ieee80211_media_status, mac); - ic->ic_opmode = opmode; - return (vap); -} - -static void -urtwn_vap_delete(struct ieee80211vap *vap) -{ - struct ieee80211com *ic = vap->iv_ic; - struct urtwn_softc *sc = ic->ic_softc; - struct urtwn_vap *uvp = URTWN_VAP(vap); - - /* Guarantee that nothing will go through this vap. */ - ieee80211_new_state(vap, IEEE80211_S_INIT, -1); - ieee80211_draintask(ic, &vap->iv_nstate_task); - - URTWN_LOCK(sc); - if (uvp->bcn_mbuf != NULL) - m_freem(uvp->bcn_mbuf); - /* Cancel any unfinished Tx. */ - urtwn_vap_clear_tx(sc, vap); - URTWN_UNLOCK(sc); - if (vap->iv_opmode == IEEE80211_M_IBSS) - ieee80211_draintask(ic, &uvp->tsf_task_adhoc); - if (URTWN_CHIP_HAS_RATECTL(sc)) - ieee80211_ratectl_deinit(vap); - ieee80211_vap_detach(vap); - free(uvp, M_80211_VAP); -} - -static void -urtwn_vap_clear_tx(struct urtwn_softc *sc, struct ieee80211vap *vap) -{ - - URTWN_ASSERT_LOCKED(sc); - - urtwn_vap_clear_tx_queue(sc, &sc->sc_tx_active, vap); - urtwn_vap_clear_tx_queue(sc, &sc->sc_tx_pending, vap); -} - -static void -urtwn_vap_clear_tx_queue(struct urtwn_softc *sc, urtwn_datahead *head, - struct ieee80211vap *vap) -{ - struct urtwn_data *dp, *tmp; - - STAILQ_FOREACH_SAFE(dp, head, next, tmp) { - if (dp->ni != NULL) { - if (dp->ni->ni_vap == vap) { - ieee80211_free_node(dp->ni); - dp->ni = NULL; - - if (dp->m != NULL) { - m_freem(dp->m); - dp->m = NULL; - } - - STAILQ_REMOVE(head, dp, urtwn_data, next); - STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, dp, - next); - } - } - } -} - -static struct mbuf * -urtwn_rx_copy_to_mbuf(struct urtwn_softc *sc, struct r92c_rx_stat *stat, - int totlen) -{ - struct ieee80211com *ic = &sc->sc_ic; - struct mbuf *m; - uint32_t rxdw0; - int pktlen; - - /* - * don't pass packets to the ieee80211 framework if the driver isn't - * RUNNING. - */ - if (!(sc->sc_flags & URTWN_RUNNING)) - return (NULL); - - rxdw0 = le32toh(stat->rxdw0); - if (rxdw0 & (R92C_RXDW0_CRCERR | R92C_RXDW0_ICVERR)) { - /* - * This should not happen since we setup our Rx filter - * to not receive these frames. - */ - URTWN_DPRINTF(sc, URTWN_DEBUG_RECV, - "%s: RX flags error (%s)\n", __func__, - rxdw0 & R92C_RXDW0_CRCERR ? "CRC" : "ICV"); - goto fail; - } - - pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); - if (pktlen < sizeof(struct ieee80211_frame_ack)) { - URTWN_DPRINTF(sc, URTWN_DEBUG_RECV, - "%s: frame is too short: %d\n", __func__, pktlen); - goto fail; - } - - m = m_get2(totlen, M_NOWAIT, MT_DATA, M_PKTHDR); - if (__predict_false(m == NULL)) { - device_printf(sc->sc_dev, "%s: could not allocate RX mbuf\n", - __func__); - goto fail; - } - - /* Finalize mbuf. */ - memcpy(mtod(m, uint8_t *), (uint8_t *)stat, totlen); - m->m_pkthdr.len = m->m_len = totlen; - - return (m); -fail: - counter_u64_add(ic->ic_ierrors, 1); - return (NULL); -} - -static struct mbuf * -urtwn_report_intr(struct usb_xfer *xfer, struct urtwn_data *data) -{ - struct urtwn_softc *sc = data->sc; - struct ieee80211com *ic = &sc->sc_ic; - struct r92c_rx_stat *stat; - uint8_t *buf; - int len; - - usbd_xfer_status(xfer, &len, NULL, NULL, NULL); - - if (len < sizeof(*stat)) { - counter_u64_add(ic->ic_ierrors, 1); - return (NULL); - } - - buf = data->buf; - stat = (struct r92c_rx_stat *)buf; - - /* - * For 88E chips we can tie the FF flushing here; - * this is where we do know exactly how deep the - * transmit queue is. - * - * But it won't work for R92 chips, so we can't - * take the easy way out. - */ - - if (sc->chip & URTWN_CHIP_88E) { - int report_sel = MS(le32toh(stat->rxdw3), R88E_RXDW3_RPT); - - switch (report_sel) { - case R88E_RXDW3_RPT_RX: - return (urtwn_rxeof(sc, buf, len)); - case R88E_RXDW3_RPT_TX1: - urtwn_r88e_ratectl_tx_complete(sc, &stat[1]); - break; - default: - URTWN_DPRINTF(sc, URTWN_DEBUG_INTR, - "%s: case %d was not handled\n", __func__, - report_sel); - break; - } - } else - return (urtwn_rxeof(sc, buf, len)); - - return (NULL); -} - -static struct mbuf * -urtwn_rxeof(struct urtwn_softc *sc, uint8_t *buf, int len) -{ - struct r92c_rx_stat *stat; - struct mbuf *m, *m0 = NULL, *prevm = NULL; - uint32_t rxdw0; - int totlen, pktlen, infosz, npkts; - - /* Get the number of encapsulated frames. */ - stat = (struct r92c_rx_stat *)buf; - npkts = MS(le32toh(stat->rxdw2), R92C_RXDW2_PKTCNT); - URTWN_DPRINTF(sc, URTWN_DEBUG_RECV, - "%s: Rx %d frames in one chunk\n", __func__, npkts); - - /* Process all of them. */ - while (npkts-- > 0) { - if (len < sizeof(*stat)) - break; - stat = (struct r92c_rx_stat *)buf; - rxdw0 = le32toh(stat->rxdw0); - - pktlen = MS(rxdw0, R92C_RXDW0_PKTLEN); - if (pktlen == 0) - break; - - infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; - - /* Make sure everything fits in xfer. */ - totlen = sizeof(*stat) + infosz + pktlen; - if (totlen > len) - break; - - m = urtwn_rx_copy_to_mbuf(sc, stat, totlen); - if (m0 == NULL) - m0 = m; - if (prevm == NULL) - prevm = m; - else { - prevm->m_next = m; - prevm = m; - } - - /* Next chunk is 128-byte aligned. */ - totlen = (totlen + 127) & ~127; - buf += totlen; - len -= totlen; - } - - return (m0); -} - -static void -urtwn_r88e_ratectl_tx_complete(struct urtwn_softc *sc, void *arg) -{ - struct r88e_tx_rpt_ccx *rpt = arg; - struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs; - struct ieee80211_node *ni; - uint8_t macid; - int ntries; - - macid = MS(rpt->rptb1, R88E_RPTB1_MACID); - ntries = MS(rpt->rptb2, R88E_RPTB2_RETRY_CNT); - - URTWN_NT_LOCK(sc); - ni = sc->node_list[macid]; - if (ni != NULL) { - URTWN_DPRINTF(sc, URTWN_DEBUG_INTR, "%s: frame for macid %d was" - "%s sent (%d retries)\n", __func__, macid, - (rpt->rptb1 & R88E_RPTB1_PKT_OK) ? "" : " not", - ntries); - - txs->flags = IEEE80211_RATECTL_STATUS_LONG_RETRY | - IEEE80211_RATECTL_STATUS_FINAL_RATE; - txs->long_retries = ntries; - if (rpt->final_rate > URTWN_RIDX_OFDM54) { /* MCS */ - txs->final_rate = - (rpt->final_rate - 12) | IEEE80211_RATE_MCS; - } else - txs->final_rate = ridx2rate[rpt->final_rate]; - if (rpt->rptb1 & R88E_RPTB1_PKT_OK) - txs->status = IEEE80211_RATECTL_TX_SUCCESS; - else if (rpt->rptb2 & R88E_RPTB2_RETRY_OVER) - txs->status = IEEE80211_RATECTL_TX_FAIL_LONG; - else if (rpt->rptb2 & R88E_RPTB2_LIFE_EXPIRE) - txs->status = IEEE80211_RATECTL_TX_FAIL_EXPIRED; - else - txs->status = IEEE80211_RATECTL_TX_FAIL_UNSPECIFIED; - ieee80211_ratectl_tx_complete(ni, txs); - } else { - URTWN_DPRINTF(sc, URTWN_DEBUG_INTR, "%s: macid %d, ni is NULL\n", - __func__, macid); - } - URTWN_NT_UNLOCK(sc); -} - -static struct ieee80211_node * -urtwn_rx_frame(struct urtwn_softc *sc, struct mbuf *m, int8_t *rssi_p) -{ - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211_frame_min *wh; - struct r92c_rx_stat *stat; - uint32_t rxdw0, rxdw3; - uint8_t rate, cipher; - int8_t rssi = -127; - int infosz; - - stat = mtod(m, struct r92c_rx_stat *); - rxdw0 = le32toh(stat->rxdw0); - rxdw3 = le32toh(stat->rxdw3); - - rate = MS(rxdw3, R92C_RXDW3_RATE); - cipher = MS(rxdw0, R92C_RXDW0_CIPHER); - infosz = MS(rxdw0, R92C_RXDW0_INFOSZ) * 8; - - /* Get RSSI from PHY status descriptor if present. */ - if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) { - if (sc->chip & URTWN_CHIP_88E) - rssi = urtwn_r88e_get_rssi(sc, rate, &stat[1]); - else - rssi = urtwn_get_rssi(sc, rate, &stat[1]); - URTWN_DPRINTF(sc, URTWN_DEBUG_RSSI, "%s: rssi=%d\n", __func__, rssi); - /* Update our average RSSI. */ - urtwn_update_avgrssi(sc, rate, rssi); - } - - if (ieee80211_radiotap_active(ic)) { - struct urtwn_rx_radiotap_header *tap = &sc->sc_rxtap; - - tap->wr_flags = 0; - - urtwn_get_tsf(sc, &tap->wr_tsft); - if (__predict_false(le32toh((uint32_t)tap->wr_tsft) < - le32toh(stat->rxdw5))) { - tap->wr_tsft = le32toh(tap->wr_tsft >> 32) - 1; - tap->wr_tsft = (uint64_t)htole32(tap->wr_tsft) << 32; - } else - tap->wr_tsft &= 0xffffffff00000000; - tap->wr_tsft += stat->rxdw5; - - /* XXX 20/40? */ - /* XXX shortgi? */ - - /* Map HW rate index to 802.11 rate. */ - if (!(rxdw3 & R92C_RXDW3_HT)) { - tap->wr_rate = ridx2rate[rate]; - } else if (rate >= 12) { /* MCS0~15. */ - /* Bit 7 set means HT MCS instead of rate. */ - tap->wr_rate = 0x80 | (rate - 12); - } - - /* XXX TODO: this isn't right; should use the last good RSSI */ - tap->wr_dbm_antsignal = rssi; - tap->wr_dbm_antnoise = URTWN_NOISE_FLOOR; - } - - *rssi_p = rssi; - - /* Drop descriptor. */ - m_adj(m, sizeof(*stat) + infosz); - wh = mtod(m, struct ieee80211_frame_min *); - - if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) && - cipher != R92C_CAM_ALGO_NONE) { - m->m_flags |= M_WEP; - } - - if (m->m_len >= sizeof(*wh)) - return (ieee80211_find_rxnode(ic, wh)); - - return (NULL); -} - -static void -urtwn_bulk_rx_callback(struct usb_xfer *xfer, usb_error_t error) -{ - struct urtwn_softc *sc = usbd_xfer_softc(xfer); - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211_node *ni; - struct mbuf *m = NULL, *next; - struct urtwn_data *data; - int8_t nf, rssi; - - URTWN_ASSERT_LOCKED(sc); - - switch (USB_GET_STATE(xfer)) { - case USB_ST_TRANSFERRED: - data = STAILQ_FIRST(&sc->sc_rx_active); - if (data == NULL) - goto tr_setup; - STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); - m = urtwn_report_intr(xfer, data); - STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); - /* FALLTHROUGH */ - case USB_ST_SETUP: -tr_setup: - data = STAILQ_FIRST(&sc->sc_rx_inactive); - if (data == NULL) { - KASSERT(m == NULL, ("mbuf isn't NULL")); - goto finish; - } - STAILQ_REMOVE_HEAD(&sc->sc_rx_inactive, next); - STAILQ_INSERT_TAIL(&sc->sc_rx_active, data, next); - usbd_xfer_set_frame_data(xfer, 0, data->buf, - usbd_xfer_max_len(xfer)); - usbd_transfer_submit(xfer); - - /* - * To avoid LOR we should unlock our private mutex here to call - * ieee80211_input() because here is at the end of a USB - * callback and safe to unlock. - */ - while (m != NULL) { - next = m->m_next; - m->m_next = NULL; - - ni = urtwn_rx_frame(sc, m, &rssi); - - /* Store a global last-good RSSI */ - if (rssi != -127) - sc->last_rssi = rssi; - - URTWN_UNLOCK(sc); - - nf = URTWN_NOISE_FLOOR; - if (ni != NULL) { - if (rssi != -127) - URTWN_NODE(ni)->last_rssi = rssi; - if (ni->ni_flags & IEEE80211_NODE_HT) - m->m_flags |= M_AMPDU; - (void)ieee80211_input(ni, m, - URTWN_NODE(ni)->last_rssi - nf, nf); - ieee80211_free_node(ni); - } else { - /* Use last good global RSSI */ - (void)ieee80211_input_all(ic, m, - sc->last_rssi - nf, nf); - } - URTWN_LOCK(sc); - m = next; - } - break; - default: - /* needs it to the inactive queue due to a error. */ - data = STAILQ_FIRST(&sc->sc_rx_active); - if (data != NULL) { - STAILQ_REMOVE_HEAD(&sc->sc_rx_active, next); - STAILQ_INSERT_TAIL(&sc->sc_rx_inactive, data, next); - } - if (error != USB_ERR_CANCELLED) { - usbd_xfer_set_stall(xfer); - counter_u64_add(ic->ic_ierrors, 1); - goto tr_setup; - } - break; - } -finish: - /* Finished receive; age anything left on the FF queue by a little bump */ - /* - * XXX TODO: just make this a callout timer schedule so we can - * flush the FF staging queue if we're approaching idle. - */ -#ifdef IEEE80211_SUPPORT_SUPERG - URTWN_UNLOCK(sc); - ieee80211_ff_age_all(ic, 1); - URTWN_LOCK(sc); -#endif - - /* Kick-start more transmit in case we stalled */ - urtwn_start(sc); -} - -static void -urtwn_txeof(struct urtwn_softc *sc, struct urtwn_data *data, int status) -{ - - URTWN_ASSERT_LOCKED(sc); - - if (data->ni != NULL) /* not a beacon frame */ - ieee80211_tx_complete(data->ni, data->m, status); - - if (sc->sc_tx_n_active > 0) - sc->sc_tx_n_active--; - - data->ni = NULL; - data->m = NULL; - - sc->sc_txtimer = 0; - - STAILQ_INSERT_TAIL(&sc->sc_tx_inactive, data, next); -} - -static int -urtwn_alloc_list(struct urtwn_softc *sc, struct urtwn_data data[], - int ndata, int maxsz) -{ - int i, error; - - for (i = 0; i < ndata; i++) { - struct urtwn_data *dp = &data[i]; - dp->sc = sc; - dp->m = NULL; - dp->buf = malloc(maxsz, M_USBDEV, M_NOWAIT); - if (dp->buf == NULL) { - device_printf(sc->sc_dev, - "could not allocate buffer\n"); - error = ENOMEM; - goto fail; - } - dp->ni = NULL; - } - - return (0); -fail: - urtwn_free_list(sc, data, ndata); - return (error); -} - -static int -urtwn_alloc_rx_list(struct urtwn_softc *sc) -{ - int error, i; - - error = urtwn_alloc_list(sc, sc->sc_rx, URTWN_RX_LIST_COUNT, - URTWN_RXBUFSZ); - if (error != 0) - return (error); - - STAILQ_INIT(&sc->sc_rx_active); - STAILQ_INIT(&sc->sc_rx_inactive); - - for (i = 0; i < URTWN_RX_LIST_COUNT; i++) - STAILQ_INSERT_HEAD(&sc->sc_rx_inactive, &sc->sc_rx[i], next); - - return (0); -} - -static int -urtwn_alloc_tx_list(struct urtwn_softc *sc) -{ - int error, i; - - error = urtwn_alloc_list(sc, sc->sc_tx, URTWN_TX_LIST_COUNT, - URTWN_TXBUFSZ); - if (error != 0) - return (error); - - STAILQ_INIT(&sc->sc_tx_active); - STAILQ_INIT(&sc->sc_tx_inactive); - STAILQ_INIT(&sc->sc_tx_pending); - - for (i = 0; i < URTWN_TX_LIST_COUNT; i++) - STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, &sc->sc_tx[i], next); - - return (0); -} - -static void -urtwn_free_list(struct urtwn_softc *sc, struct urtwn_data data[], int ndata) -{ - int i; - - for (i = 0; i < ndata; i++) { - struct urtwn_data *dp = &data[i]; - - if (dp->buf != NULL) { - free(dp->buf, M_USBDEV); - dp->buf = NULL; - } - if (dp->ni != NULL) { - ieee80211_free_node(dp->ni); - dp->ni = NULL; - } - } -} - -static void -urtwn_free_rx_list(struct urtwn_softc *sc) -{ - urtwn_free_list(sc, sc->sc_rx, URTWN_RX_LIST_COUNT); - - STAILQ_INIT(&sc->sc_rx_active); - STAILQ_INIT(&sc->sc_rx_inactive); -} - -static void -urtwn_free_tx_list(struct urtwn_softc *sc) -{ - urtwn_free_list(sc, sc->sc_tx, URTWN_TX_LIST_COUNT); - - STAILQ_INIT(&sc->sc_tx_active); - STAILQ_INIT(&sc->sc_tx_inactive); - STAILQ_INIT(&sc->sc_tx_pending); -} - -static void -urtwn_bulk_tx_callback(struct usb_xfer *xfer, usb_error_t error) -{ - struct urtwn_softc *sc = usbd_xfer_softc(xfer); -#ifdef IEEE80211_SUPPORT_SUPERG - struct ieee80211com *ic = &sc->sc_ic; -#endif - struct urtwn_data *data; - - URTWN_ASSERT_LOCKED(sc); - - switch (USB_GET_STATE(xfer)){ - case USB_ST_TRANSFERRED: - data = STAILQ_FIRST(&sc->sc_tx_active); - if (data == NULL) - goto tr_setup; - STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next); - urtwn_txeof(sc, data, 0); - /* FALLTHROUGH */ - case USB_ST_SETUP: -tr_setup: - data = STAILQ_FIRST(&sc->sc_tx_pending); - if (data == NULL) { - URTWN_DPRINTF(sc, URTWN_DEBUG_XMIT, - "%s: empty pending queue\n", __func__); - sc->sc_tx_n_active = 0; - goto finish; - } - STAILQ_REMOVE_HEAD(&sc->sc_tx_pending, next); - STAILQ_INSERT_TAIL(&sc->sc_tx_active, data, next); - usbd_xfer_set_frame_data(xfer, 0, data->buf, data->buflen); - usbd_transfer_submit(xfer); - sc->sc_tx_n_active++; - break; - default: - data = STAILQ_FIRST(&sc->sc_tx_active); - if (data == NULL) - goto tr_setup; - STAILQ_REMOVE_HEAD(&sc->sc_tx_active, next); - urtwn_txeof(sc, data, 1); - if (error != USB_ERR_CANCELLED) { - usbd_xfer_set_stall(xfer); - goto tr_setup; - } - break; - } -finish: -#ifdef IEEE80211_SUPPORT_SUPERG - /* - * If the TX active queue drops below a certain - * threshold, ensure we age fast-frames out so they're - * transmitted. - */ - if (sc->sc_tx_n_active <= 1) { - /* XXX ew - net80211 should defer this for us! */ - - /* - * Note: this sc_tx_n_active currently tracks - * the number of pending transmit submissions - * and not the actual depth of the TX frames - * pending to the hardware. That means that - * we're going to end up with some sub-optimal - * aggregation behaviour. - */ - /* - * XXX TODO: just make this a callout timer schedule so we can - * flush the FF staging queue if we're approaching idle. - */ - URTWN_UNLOCK(sc); - ieee80211_ff_flush(ic, WME_AC_VO); - ieee80211_ff_flush(ic, WME_AC_VI); - ieee80211_ff_flush(ic, WME_AC_BE); - ieee80211_ff_flush(ic, WME_AC_BK); - URTWN_LOCK(sc); - } -#endif - /* Kick-start more transmit */ - urtwn_start(sc); -} - -static struct urtwn_data * -_urtwn_getbuf(struct urtwn_softc *sc) -{ - struct urtwn_data *bf; - - bf = STAILQ_FIRST(&sc->sc_tx_inactive); - if (bf != NULL) - STAILQ_REMOVE_HEAD(&sc->sc_tx_inactive, next); - else { - URTWN_DPRINTF(sc, URTWN_DEBUG_XMIT, - "%s: out of xmit buffers\n", __func__); - } - return (bf); -} - -static struct urtwn_data * -urtwn_getbuf(struct urtwn_softc *sc) -{ - struct urtwn_data *bf; - - URTWN_ASSERT_LOCKED(sc); - - bf = _urtwn_getbuf(sc); - if (bf == NULL) { - URTWN_DPRINTF(sc, URTWN_DEBUG_XMIT, "%s: stop queue\n", - __func__); - } - return (bf); -} - -static usb_error_t -urtwn_write_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, - int len) -{ - usb_device_request_t req; - - req.bmRequestType = UT_WRITE_VENDOR_DEVICE; - req.bRequest = R92C_REQ_REGS; - USETW(req.wValue, addr); - USETW(req.wIndex, 0); - USETW(req.wLength, len); - return (urtwn_do_request(sc, &req, buf)); -} - -static usb_error_t -urtwn_write_1(struct urtwn_softc *sc, uint16_t addr, uint8_t val) -{ - return (urtwn_write_region_1(sc, addr, &val, sizeof(val))); -} - -static usb_error_t -urtwn_write_2(struct urtwn_softc *sc, uint16_t addr, uint16_t val) -{ - val = htole16(val); - return (urtwn_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val))); -} - -static usb_error_t -urtwn_write_4(struct urtwn_softc *sc, uint16_t addr, uint32_t val) -{ - val = htole32(val); - return (urtwn_write_region_1(sc, addr, (uint8_t *)&val, sizeof(val))); -} - -static usb_error_t -urtwn_read_region_1(struct urtwn_softc *sc, uint16_t addr, uint8_t *buf, - int len) -{ - usb_device_request_t req; - - req.bmRequestType = UT_READ_VENDOR_DEVICE; - req.bRequest = R92C_REQ_REGS; - USETW(req.wValue, addr); - USETW(req.wIndex, 0); - USETW(req.wLength, len); - return (urtwn_do_request(sc, &req, buf)); -} - -static uint8_t -urtwn_read_1(struct urtwn_softc *sc, uint16_t addr) -{ - uint8_t val; - - if (urtwn_read_region_1(sc, addr, &val, 1) != 0) - return (0xff); - return (val); -} - -static uint16_t -urtwn_read_2(struct urtwn_softc *sc, uint16_t addr) -{ - uint16_t val; - - if (urtwn_read_region_1(sc, addr, (uint8_t *)&val, 2) != 0) - return (0xffff); - return (le16toh(val)); -} - -static uint32_t -urtwn_read_4(struct urtwn_softc *sc, uint16_t addr) -{ - uint32_t val; - - if (urtwn_read_region_1(sc, addr, (uint8_t *)&val, 4) != 0) - return (0xffffffff); - return (le32toh(val)); -} - -static int -urtwn_fw_cmd(struct urtwn_softc *sc, uint8_t id, const void *buf, int len) -{ - struct r92c_fw_cmd cmd; - usb_error_t error; - int ntries; - - if (!(sc->sc_flags & URTWN_FW_LOADED)) { - URTWN_DPRINTF(sc, URTWN_DEBUG_FIRMWARE, "%s: firmware " - "was not loaded; command (id %d) will be discarded\n", - __func__, id); - return (0); - } - - /* Wait for current FW box to be empty. */ - for (ntries = 0; ntries < 100; ntries++) { - if (!(urtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur))) - break; - urtwn_ms_delay(sc); - } - if (ntries == 100) { - device_printf(sc->sc_dev, - "could not send firmware command\n"); - return (ETIMEDOUT); - } - memset(&cmd, 0, sizeof(cmd)); - cmd.id = id; - if (len > 3) - cmd.id |= R92C_CMD_FLAG_EXT; - KASSERT(len <= sizeof(cmd.msg), ("urtwn_fw_cmd\n")); - memcpy(cmd.msg, buf, len); - - /* Write the first word last since that will trigger the FW. */ - error = urtwn_write_region_1(sc, R92C_HMEBOX_EXT(sc->fwcur), - (uint8_t *)&cmd + 4, 2); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - error = urtwn_write_region_1(sc, R92C_HMEBOX(sc->fwcur), - (uint8_t *)&cmd + 0, 4); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX; - return (0); -} - -static void -urtwn_cmdq_cb(void *arg, int pending) -{ - struct urtwn_softc *sc = arg; - struct urtwn_cmdq *item; - - /* - * Device must be powered on (via urtwn_power_on()) - * before any command may be sent. - */ - URTWN_LOCK(sc); - if (!(sc->sc_flags & URTWN_RUNNING)) { - URTWN_UNLOCK(sc); - return; - } - - URTWN_CMDQ_LOCK(sc); - while (sc->cmdq[sc->cmdq_first].func != NULL) { - item = &sc->cmdq[sc->cmdq_first]; - sc->cmdq_first = (sc->cmdq_first + 1) % URTWN_CMDQ_SIZE; - URTWN_CMDQ_UNLOCK(sc); - - item->func(sc, &item->data); - - URTWN_CMDQ_LOCK(sc); - memset(item, 0, sizeof (*item)); - } - URTWN_CMDQ_UNLOCK(sc); - URTWN_UNLOCK(sc); -} - -static int -urtwn_cmd_sleepable(struct urtwn_softc *sc, const void *ptr, size_t len, - CMD_FUNC_PROTO) -{ - struct ieee80211com *ic = &sc->sc_ic; - - KASSERT(len <= sizeof(union sec_param), ("buffer overflow")); - - URTWN_CMDQ_LOCK(sc); - if (sc->cmdq[sc->cmdq_last].func != NULL) { - device_printf(sc->sc_dev, "%s: cmdq overflow\n", __func__); - URTWN_CMDQ_UNLOCK(sc); - - return (EAGAIN); - } - - if (ptr != NULL) - memcpy(&sc->cmdq[sc->cmdq_last].data, ptr, len); - sc->cmdq[sc->cmdq_last].func = func; - sc->cmdq_last = (sc->cmdq_last + 1) % URTWN_CMDQ_SIZE; - URTWN_CMDQ_UNLOCK(sc); - - ieee80211_runtask(ic, &sc->cmdq_task); - - return (0); -} - -static __inline void -urtwn_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, uint32_t val) -{ - - sc->sc_rf_write(sc, chain, addr, val); -} - -static void -urtwn_r92c_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, - uint32_t val) -{ - urtwn_bb_write(sc, R92C_LSSI_PARAM(chain), - SM(R92C_LSSI_PARAM_ADDR, addr) | - SM(R92C_LSSI_PARAM_DATA, val)); -} - -static void -urtwn_r88e_rf_write(struct urtwn_softc *sc, int chain, uint8_t addr, -uint32_t val) -{ - urtwn_bb_write(sc, R92C_LSSI_PARAM(chain), - SM(R88E_LSSI_PARAM_ADDR, addr) | - SM(R92C_LSSI_PARAM_DATA, val)); -} - -static uint32_t -urtwn_rf_read(struct urtwn_softc *sc, int chain, uint8_t addr) -{ - uint32_t reg[R92C_MAX_CHAINS], val; - - reg[0] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(0)); - if (chain != 0) - reg[chain] = urtwn_bb_read(sc, R92C_HSSI_PARAM2(chain)); - - urtwn_bb_write(sc, R92C_HSSI_PARAM2(0), - reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE); - urtwn_ms_delay(sc); - - urtwn_bb_write(sc, R92C_HSSI_PARAM2(chain), - RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) | - R92C_HSSI_PARAM2_READ_EDGE); - urtwn_ms_delay(sc); - - urtwn_bb_write(sc, R92C_HSSI_PARAM2(0), - reg[0] | R92C_HSSI_PARAM2_READ_EDGE); - urtwn_ms_delay(sc); - - if (urtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI) - val = urtwn_bb_read(sc, R92C_HSPI_READBACK(chain)); - else - val = urtwn_bb_read(sc, R92C_LSSI_READBACK(chain)); - return (MS(val, R92C_LSSI_READBACK_DATA)); -} - -static int -urtwn_llt_write(struct urtwn_softc *sc, uint32_t addr, uint32_t data) -{ - usb_error_t error; - int ntries; - - error = urtwn_write_4(sc, R92C_LLT_INIT, - SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) | - SM(R92C_LLT_INIT_ADDR, addr) | - SM(R92C_LLT_INIT_DATA, data)); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - /* Wait for write operation to complete. */ - for (ntries = 0; ntries < 20; ntries++) { - if (MS(urtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) == - R92C_LLT_INIT_OP_NO_ACTIVE) - return (0); - urtwn_ms_delay(sc); - } - return (ETIMEDOUT); -} - -static int -urtwn_efuse_read_next(struct urtwn_softc *sc, uint8_t *val) -{ - uint32_t reg; - usb_error_t error; - int ntries; - - if (sc->last_rom_addr >= URTWN_EFUSE_MAX_LEN) - return (EFAULT); - - reg = urtwn_read_4(sc, R92C_EFUSE_CTRL); - reg = RW(reg, R92C_EFUSE_CTRL_ADDR, sc->last_rom_addr); - reg &= ~R92C_EFUSE_CTRL_VALID; - - error = urtwn_write_4(sc, R92C_EFUSE_CTRL, reg); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - /* Wait for read operation to complete. */ - for (ntries = 0; ntries < 100; ntries++) { - reg = urtwn_read_4(sc, R92C_EFUSE_CTRL); - if (reg & R92C_EFUSE_CTRL_VALID) - break; - urtwn_ms_delay(sc); - } - if (ntries == 100) { - device_printf(sc->sc_dev, - "could not read efuse byte at address 0x%x\n", - sc->last_rom_addr); - return (ETIMEDOUT); - } - - *val = MS(reg, R92C_EFUSE_CTRL_DATA); - sc->last_rom_addr++; - - return (0); -} - -static int -urtwn_efuse_read_data(struct urtwn_softc *sc, uint8_t *rom, uint8_t off, - uint8_t msk) -{ - uint8_t reg; - int i, error; - - for (i = 0; i < 4; i++) { - if (msk & (1 << i)) - continue; - error = urtwn_efuse_read_next(sc, ®); - if (error != 0) - return (error); - URTWN_DPRINTF(sc, URTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n", - off * 8 + i * 2, reg); - rom[off * 8 + i * 2 + 0] = reg; - - error = urtwn_efuse_read_next(sc, ®); - if (error != 0) - return (error); - URTWN_DPRINTF(sc, URTWN_DEBUG_ROM, "rom[0x%03X] == 0x%02X\n", - off * 8 + i * 2 + 1, reg); - rom[off * 8 + i * 2 + 1] = reg; - } - - return (0); -} - -#ifdef USB_DEBUG -static void -urtwn_dump_rom_contents(struct urtwn_softc *sc, uint8_t *rom, uint16_t size) -{ - int i; - - /* Dump ROM contents. */ - device_printf(sc->sc_dev, "%s:", __func__); - for (i = 0; i < size; i++) { - if (i % 32 == 0) - printf("\n%03X: ", i); - else if (i % 4 == 0) - printf(" "); - - printf("%02X", rom[i]); - } - printf("\n"); -} -#endif - -static int -urtwn_efuse_read(struct urtwn_softc *sc, uint8_t *rom, uint16_t size) -{ -#define URTWN_CHK(res) do { \ - if ((error = res) != 0) \ - goto end; \ -} while(0) - uint8_t msk, off, reg; - int error; - - URTWN_CHK(urtwn_efuse_switch_power(sc)); - - /* Read full ROM image. */ - sc->last_rom_addr = 0; - memset(rom, 0xff, size); - - URTWN_CHK(urtwn_efuse_read_next(sc, ®)); - while (reg != 0xff) { - /* check for extended header */ - if ((sc->chip & URTWN_CHIP_88E) && (reg & 0x1f) == 0x0f) { - off = reg >> 5; - URTWN_CHK(urtwn_efuse_read_next(sc, ®)); - - if ((reg & 0x0f) != 0x0f) - off = ((reg & 0xf0) >> 1) | off; - else - continue; - } else - off = reg >> 4; - msk = reg & 0xf; - - URTWN_CHK(urtwn_efuse_read_data(sc, rom, off, msk)); - URTWN_CHK(urtwn_efuse_read_next(sc, ®)); - } - -end: - -#ifdef USB_DEBUG - if (sc->sc_debug & URTWN_DEBUG_ROM) - urtwn_dump_rom_contents(sc, rom, size); -#endif - - urtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_OFF); - - if (error != 0) { - device_printf(sc->sc_dev, "%s: error while reading ROM\n", - __func__); - } - - return (error); -#undef URTWN_CHK -} - -static int -urtwn_efuse_switch_power(struct urtwn_softc *sc) -{ - usb_error_t error; - uint32_t reg; - - error = urtwn_write_1(sc, R92C_EFUSE_ACCESS, R92C_EFUSE_ACCESS_ON); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - reg = urtwn_read_2(sc, R92C_SYS_ISO_CTRL); - if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) { - error = urtwn_write_2(sc, R92C_SYS_ISO_CTRL, - reg | R92C_SYS_ISO_CTRL_PWC_EV12V); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - } - reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); - if (!(reg & R92C_SYS_FUNC_EN_ELDR)) { - error = urtwn_write_2(sc, R92C_SYS_FUNC_EN, - reg | R92C_SYS_FUNC_EN_ELDR); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - } - reg = urtwn_read_2(sc, R92C_SYS_CLKR); - if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) != - (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) { - error = urtwn_write_2(sc, R92C_SYS_CLKR, - reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - } - - return (0); -} - -static int -urtwn_read_chipid(struct urtwn_softc *sc) -{ - uint32_t reg; - - if (sc->chip & URTWN_CHIP_88E) - return (0); - - reg = urtwn_read_4(sc, R92C_SYS_CFG); - if (reg & R92C_SYS_CFG_TRP_VAUX_EN) - return (EIO); - - if (reg & R92C_SYS_CFG_TYPE_92C) { - sc->chip |= URTWN_CHIP_92C; - /* Check if it is a castrated 8192C. */ - if (MS(urtwn_read_4(sc, R92C_HPON_FSM), - R92C_HPON_FSM_CHIP_BONDING_ID) == - R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R) - sc->chip |= URTWN_CHIP_92C_1T2R; - } - if (reg & R92C_SYS_CFG_VENDOR_UMC) { - sc->chip |= URTWN_CHIP_UMC; - if (MS(reg, R92C_SYS_CFG_CHIP_VER_RTL) == 0) - sc->chip |= URTWN_CHIP_UMC_A_CUT; - } - return (0); -} - -static int -urtwn_read_rom(struct urtwn_softc *sc) -{ - struct r92c_rom *rom = &sc->rom.r92c_rom; - int error; - - /* Read full ROM image. */ - error = urtwn_efuse_read(sc, (uint8_t *)rom, sizeof(*rom)); - if (error != 0) - return (error); - - /* XXX Weird but this is what the vendor driver does. */ - sc->last_rom_addr = 0x1fa; - error = urtwn_efuse_read_next(sc, &sc->pa_setting); - if (error != 0) - return (error); - URTWN_DPRINTF(sc, URTWN_DEBUG_ROM, "%s: PA setting=0x%x\n", __func__, - sc->pa_setting); - - sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE); - - sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY); - URTWN_DPRINTF(sc, URTWN_DEBUG_ROM, "%s: regulatory type=%d\n", - __func__, sc->regulatory); - IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr); - - sc->sc_rf_write = urtwn_r92c_rf_write; - sc->sc_power_on = urtwn_r92c_power_on; - sc->sc_power_off = urtwn_r92c_power_off; - - return (0); -} - -static int -urtwn_r88e_read_rom(struct urtwn_softc *sc) -{ - struct r88e_rom *rom = &sc->rom.r88e_rom; - int error; - - error = urtwn_efuse_read(sc, (uint8_t *)rom, sizeof(sc->rom.r88e_rom)); - if (error != 0) - return (error); - - sc->bw20_tx_pwr_diff = (rom->tx_pwr_diff >> 4); - if (sc->bw20_tx_pwr_diff & 0x08) - sc->bw20_tx_pwr_diff |= 0xf0; - sc->ofdm_tx_pwr_diff = (rom->tx_pwr_diff & 0xf); - if (sc->ofdm_tx_pwr_diff & 0x08) - sc->ofdm_tx_pwr_diff |= 0xf0; - sc->regulatory = MS(rom->rf_board_opt, R92C_ROM_RF1_REGULATORY); - URTWN_DPRINTF(sc, URTWN_DEBUG_ROM, "%s: regulatory type %d\n", - __func__,sc->regulatory); - IEEE80211_ADDR_COPY(sc->sc_ic.ic_macaddr, rom->macaddr); - - sc->sc_rf_write = urtwn_r88e_rf_write; - sc->sc_power_on = urtwn_r88e_power_on; - sc->sc_power_off = urtwn_r88e_power_off; - - return (0); -} - -static __inline uint8_t -rate2ridx(uint8_t rate) -{ - if (rate & IEEE80211_RATE_MCS) { - /* 11n rates start at idx 12 */ - return ((rate & 0xf) + 12); - } - switch (rate) { - /* 11g */ - case 12: return 4; - case 18: return 5; - case 24: return 6; - case 36: return 7; - case 48: return 8; - case 72: return 9; - case 96: return 10; - case 108: return 11; - /* 11b */ - case 2: return 0; - case 4: return 1; - case 11: return 2; - case 22: return 3; - default: return URTWN_RIDX_UNKNOWN; - } -} - -/* - * Initialize rate adaptation in firmware. - */ -static int -urtwn_ra_init(struct urtwn_softc *sc) -{ - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - struct ieee80211_node *ni; - struct ieee80211_rateset *rs, *rs_ht; - struct r92c_fw_cmd_macid_cfg cmd; - uint32_t rates, basicrates; - uint8_t mode, ridx; - int maxrate, maxbasicrate, error, i; - - ni = ieee80211_ref_node(vap->iv_bss); - rs = &ni->ni_rates; - rs_ht = (struct ieee80211_rateset *) &ni->ni_htrates; - - /* Get normal and basic rates mask. */ - rates = basicrates = 0; - maxrate = maxbasicrate = 0; - - /* This is for 11bg */ - for (i = 0; i < rs->rs_nrates; i++) { - /* Convert 802.11 rate to HW rate index. */ - ridx = rate2ridx(IEEE80211_RV(rs->rs_rates[i])); - if (ridx == URTWN_RIDX_UNKNOWN) /* Unknown rate, skip. */ - continue; - rates |= 1 << ridx; - if (ridx > maxrate) - maxrate = ridx; - if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) { - basicrates |= 1 << ridx; - if (ridx > maxbasicrate) - maxbasicrate = ridx; - } - } - - /* If we're doing 11n, enable 11n rates */ - if (ni->ni_flags & IEEE80211_NODE_HT) { - for (i = 0; i < rs_ht->rs_nrates; i++) { - if ((rs_ht->rs_rates[i] & 0x7f) > 0xf) - continue; - /* 11n rates start at index 12 */ - ridx = ((rs_ht->rs_rates[i]) & 0xf) + 12; - rates |= (1 << ridx); - - /* Guard against the rate table being oddly ordered */ - if (ridx > maxrate) - maxrate = ridx; - } - } - -#if 0 - if (ic->ic_curmode == IEEE80211_MODE_11NG) - raid = R92C_RAID_11GN; -#endif - /* NB: group addressed frames are done at 11bg rates for now */ - if (ic->ic_curmode == IEEE80211_MODE_11B) - mode = R92C_RAID_11B; - else - mode = R92C_RAID_11BG; - /* XXX misleading 'mode' value here for unicast frames */ - URTWN_DPRINTF(sc, URTWN_DEBUG_RA, - "%s: mode 0x%x, rates 0x%08x, basicrates 0x%08x\n", __func__, - mode, rates, basicrates); - - /* Set rates mask for group addressed frames. */ - cmd.macid = URTWN_MACID_BC | URTWN_MACID_VALID; - cmd.mask = htole32(mode << 28 | basicrates); - error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); - if (error != 0) { - ieee80211_free_node(ni); - device_printf(sc->sc_dev, - "could not add broadcast station\n"); - return (error); - } - - /* Set initial MRR rate. */ - URTWN_DPRINTF(sc, URTWN_DEBUG_RA, "%s: maxbasicrate %d\n", __func__, - maxbasicrate); - urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BC), - maxbasicrate); - - /* Set rates mask for unicast frames. */ - if (ni->ni_flags & IEEE80211_NODE_HT) - mode = R92C_RAID_11GN; - else if (ic->ic_curmode == IEEE80211_MODE_11B) - mode = R92C_RAID_11B; - else - mode = R92C_RAID_11BG; - cmd.macid = URTWN_MACID_BSS | URTWN_MACID_VALID; - cmd.mask = htole32(mode << 28 | rates); - error = urtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd)); - if (error != 0) { - ieee80211_free_node(ni); - device_printf(sc->sc_dev, "could not add BSS station\n"); - return (error); - } - /* Set initial MRR rate. */ - URTWN_DPRINTF(sc, URTWN_DEBUG_RA, "%s: maxrate %d\n", __func__, - maxrate); - urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BSS), - maxrate); - - /* Indicate highest supported rate. */ - if (ni->ni_flags & IEEE80211_NODE_HT) - ni->ni_txrate = rs_ht->rs_rates[rs_ht->rs_nrates - 1] - | IEEE80211_RATE_MCS; - else - ni->ni_txrate = rs->rs_rates[rs->rs_nrates - 1]; - ieee80211_free_node(ni); - - return (0); -} - -static void -urtwn_init_beacon(struct urtwn_softc *sc, struct urtwn_vap *uvp) -{ - struct r92c_tx_desc *txd = &uvp->bcn_desc; - - txd->txdw0 = htole32( - SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | R92C_TXDW0_BMCAST | - R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG); - txd->txdw1 = htole32( - SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_BEACON) | - SM(R92C_TXDW1_RAID, R92C_RAID_11B)); - - if (sc->chip & URTWN_CHIP_88E) { - txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, URTWN_MACID_BC)); - txd->txdseq |= htole16(R88E_TXDSEQ_HWSEQ_EN); - } else { - txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, URTWN_MACID_BC)); - txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); - } - - txd->txdw4 = htole32(R92C_TXDW4_DRVRATE); - txd->txdw5 = htole32(SM(R92C_TXDW5_DATARATE, URTWN_RIDX_CCK1)); -} - -static int -urtwn_setup_beacon(struct urtwn_softc *sc, struct ieee80211_node *ni) -{ - struct ieee80211vap *vap = ni->ni_vap; - struct urtwn_vap *uvp = URTWN_VAP(vap); - struct mbuf *m; - int error; - - URTWN_ASSERT_LOCKED(sc); - - if (ni->ni_chan == IEEE80211_CHAN_ANYC) - return (EINVAL); - - m = ieee80211_beacon_alloc(ni); - if (m == NULL) { - device_printf(sc->sc_dev, - "%s: could not allocate beacon frame\n", __func__); - return (ENOMEM); - } - - if (uvp->bcn_mbuf != NULL) - m_freem(uvp->bcn_mbuf); - - uvp->bcn_mbuf = m; - - if ((error = urtwn_tx_beacon(sc, uvp)) != 0) - return (error); - - /* XXX bcnq stuck workaround */ - if ((error = urtwn_tx_beacon(sc, uvp)) != 0) - return (error); - - URTWN_DPRINTF(sc, URTWN_DEBUG_BEACON, "%s: beacon was %srecognized\n", - __func__, urtwn_read_1(sc, R92C_TDECTRL + 2) & - (R92C_TDECTRL_BCN_VALID >> 16) ? "" : "not "); - - return (0); -} - -static void -urtwn_update_beacon(struct ieee80211vap *vap, int item) -{ - struct urtwn_softc *sc = vap->iv_ic->ic_softc; - struct urtwn_vap *uvp = URTWN_VAP(vap); - struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; - struct ieee80211_node *ni = vap->iv_bss; - int mcast = 0; - - URTWN_LOCK(sc); - if (uvp->bcn_mbuf == NULL) { - uvp->bcn_mbuf = ieee80211_beacon_alloc(ni); - if (uvp->bcn_mbuf == NULL) { - device_printf(sc->sc_dev, - "%s: could not allocate beacon frame\n", __func__); - URTWN_UNLOCK(sc); - return; - } - } - URTWN_UNLOCK(sc); - - if (item == IEEE80211_BEACON_TIM) - mcast = 1; /* XXX */ - - setbit(bo->bo_flags, item); - ieee80211_beacon_update(ni, uvp->bcn_mbuf, mcast); - - URTWN_LOCK(sc); - urtwn_tx_beacon(sc, uvp); - URTWN_UNLOCK(sc); -} - -/* - * Push a beacon frame into the chip. Beacon will - * be repeated by the chip every R92C_BCN_INTERVAL. - */ -static int -urtwn_tx_beacon(struct urtwn_softc *sc, struct urtwn_vap *uvp) -{ - struct r92c_tx_desc *desc = &uvp->bcn_desc; - struct urtwn_data *bf; - - URTWN_ASSERT_LOCKED(sc); - - bf = urtwn_getbuf(sc); - if (bf == NULL) - return (ENOMEM); - - memcpy(bf->buf, desc, sizeof(*desc)); - urtwn_tx_start(sc, uvp->bcn_mbuf, IEEE80211_FC0_TYPE_MGT, bf); - - sc->sc_txtimer = 5; - callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); - - return (0); -} - -static int -urtwn_key_alloc(struct ieee80211vap *vap, struct ieee80211_key *k, - ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) -{ - struct urtwn_softc *sc = vap->iv_ic->ic_softc; - uint8_t i; - - if (!(&vap->iv_nw_keys[0] <= k && - k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) { - if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) { - URTWN_LOCK(sc); - /* - * First 4 slots for group keys, - * what is left - for pairwise. - * XXX incompatible with IBSS RSN. - */ - for (i = IEEE80211_WEP_NKID; - i < R92C_CAM_ENTRY_COUNT; i++) { - if ((sc->keys_bmap & (1 << i)) == 0) { - sc->keys_bmap |= 1 << i; - *keyix = i; - break; - } - } - URTWN_UNLOCK(sc); - if (i == R92C_CAM_ENTRY_COUNT) { - device_printf(sc->sc_dev, - "%s: no free space in the key table\n", - __func__); - return 0; - } - } else - *keyix = 0; - } else { - *keyix = k - vap->iv_nw_keys; - } - *rxkeyix = *keyix; - return 1; -} - -static void -urtwn_key_set_cb(struct urtwn_softc *sc, union sec_param *data) -{ - struct ieee80211_key *k = &data->key; - uint8_t algo, keyid; - int i, error; - - if (k->wk_keyix < IEEE80211_WEP_NKID) - keyid = k->wk_keyix; - else - keyid = 0; - - /* Map net80211 cipher to HW crypto algorithm. */ - switch (k->wk_cipher->ic_cipher) { - case IEEE80211_CIPHER_WEP: - if (k->wk_keylen < 8) - algo = R92C_CAM_ALGO_WEP40; - else - algo = R92C_CAM_ALGO_WEP104; - break; - case IEEE80211_CIPHER_TKIP: - algo = R92C_CAM_ALGO_TKIP; - break; - case IEEE80211_CIPHER_AES_CCM: - algo = R92C_CAM_ALGO_AES; - break; - default: - device_printf(sc->sc_dev, "%s: undefined cipher %d\n", - __func__, k->wk_cipher->ic_cipher); - return; - } - - URTWN_DPRINTF(sc, URTWN_DEBUG_KEY, - "%s: keyix %d, keyid %d, algo %d/%d, flags %04X, len %d, " - "macaddr %s\n", __func__, k->wk_keyix, keyid, - k->wk_cipher->ic_cipher, algo, k->wk_flags, k->wk_keylen, - ether_sprintf(k->wk_macaddr)); - - /* Clear high bits. */ - urtwn_cam_write(sc, R92C_CAM_CTL6(k->wk_keyix), 0); - urtwn_cam_write(sc, R92C_CAM_CTL7(k->wk_keyix), 0); - - /* Write key. */ - for (i = 0; i < 4; i++) { - error = urtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i), - le32dec(&k->wk_key[i * 4])); - if (error != 0) - goto fail; - } - - /* Write CTL0 last since that will validate the CAM entry. */ - error = urtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix), - le32dec(&k->wk_macaddr[2])); - if (error != 0) - goto fail; - error = urtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix), - SM(R92C_CAM_ALGO, algo) | - SM(R92C_CAM_KEYID, keyid) | - SM(R92C_CAM_MACLO, le16dec(&k->wk_macaddr[0])) | - R92C_CAM_VALID); - if (error != 0) - goto fail; - - return; - -fail: - device_printf(sc->sc_dev, "%s fails, error %d\n", __func__, error); -} - -static void -urtwn_key_del_cb(struct urtwn_softc *sc, union sec_param *data) -{ - struct ieee80211_key *k = &data->key; - int i; - - URTWN_DPRINTF(sc, URTWN_DEBUG_KEY, - "%s: keyix %d, flags %04X, macaddr %s\n", __func__, - k->wk_keyix, k->wk_flags, ether_sprintf(k->wk_macaddr)); - - urtwn_cam_write(sc, R92C_CAM_CTL0(k->wk_keyix), 0); - urtwn_cam_write(sc, R92C_CAM_CTL1(k->wk_keyix), 0); - - /* Clear key. */ - for (i = 0; i < 4; i++) - urtwn_cam_write(sc, R92C_CAM_KEY(k->wk_keyix, i), 0); - sc->keys_bmap &= ~(1 << k->wk_keyix); -} - -static int -urtwn_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k) -{ - struct urtwn_softc *sc = vap->iv_ic->ic_softc; - struct urtwn_vap *uvp = URTWN_VAP(vap); - - if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { - /* Not for us. */ - return (1); - } - - if (&vap->iv_nw_keys[0] <= k && - k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) { - URTWN_LOCK(sc); - uvp->keys[k->wk_keyix] = k; - if ((sc->sc_flags & URTWN_RUNNING) == 0) { - /* - * The device was not started; - * the key will be installed later. - */ - URTWN_UNLOCK(sc); - return (1); - } - URTWN_UNLOCK(sc); - } - - return (!urtwn_cmd_sleepable(sc, k, sizeof(*k), urtwn_key_set_cb)); -} - -static int -urtwn_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k) -{ - struct urtwn_softc *sc = vap->iv_ic->ic_softc; - struct urtwn_vap *uvp = URTWN_VAP(vap); - - if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { - /* Not for us. */ - return (1); - } - - if (&vap->iv_nw_keys[0] <= k && - k < &vap->iv_nw_keys[IEEE80211_WEP_NKID]) { - URTWN_LOCK(sc); - uvp->keys[k->wk_keyix] = NULL; - if ((sc->sc_flags & URTWN_RUNNING) == 0) { - /* All keys are removed on device reset. */ - URTWN_UNLOCK(sc); - return (1); - } - URTWN_UNLOCK(sc); - } - - return (!urtwn_cmd_sleepable(sc, k, sizeof(*k), urtwn_key_del_cb)); -} - -static void -urtwn_tsf_task_adhoc(void *arg, int pending) -{ - struct ieee80211vap *vap = arg; - struct urtwn_softc *sc = vap->iv_ic->ic_softc; - struct ieee80211_node *ni; - uint32_t reg; - - URTWN_LOCK(sc); - ni = ieee80211_ref_node(vap->iv_bss); - reg = urtwn_read_1(sc, R92C_BCN_CTRL); - - /* Accept beacons with the same BSSID. */ - urtwn_set_rx_bssid_all(sc, 0); - - /* Enable synchronization. */ - reg &= ~R92C_BCN_CTRL_DIS_TSF_UDT0; - urtwn_write_1(sc, R92C_BCN_CTRL, reg); - - /* Synchronize. */ - usb_pause_mtx(&sc->sc_mtx, hz * ni->ni_intval * 5 / 1000); - - /* Disable synchronization. */ - reg |= R92C_BCN_CTRL_DIS_TSF_UDT0; - urtwn_write_1(sc, R92C_BCN_CTRL, reg); - - /* Remove beacon filter. */ - urtwn_set_rx_bssid_all(sc, 1); - - /* Enable beaconing. */ - urtwn_write_1(sc, R92C_MBID_NUM, - urtwn_read_1(sc, R92C_MBID_NUM) | R92C_MBID_TXBCN_RPT0); - reg |= R92C_BCN_CTRL_EN_BCN; - - urtwn_write_1(sc, R92C_BCN_CTRL, reg); - ieee80211_free_node(ni); - URTWN_UNLOCK(sc); -} - -static void -urtwn_tsf_sync_enable(struct urtwn_softc *sc, struct ieee80211vap *vap) -{ - struct ieee80211com *ic = &sc->sc_ic; - struct urtwn_vap *uvp = URTWN_VAP(vap); - - /* Reset TSF. */ - urtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RST0); - - switch (vap->iv_opmode) { - case IEEE80211_M_STA: - /* Enable TSF synchronization. */ - urtwn_write_1(sc, R92C_BCN_CTRL, - urtwn_read_1(sc, R92C_BCN_CTRL) & - ~R92C_BCN_CTRL_DIS_TSF_UDT0); - break; - case IEEE80211_M_IBSS: - ieee80211_runtask(ic, &uvp->tsf_task_adhoc); - break; - case IEEE80211_M_HOSTAP: - /* Enable beaconing. */ - urtwn_write_1(sc, R92C_MBID_NUM, - urtwn_read_1(sc, R92C_MBID_NUM) | R92C_MBID_TXBCN_RPT0); - urtwn_write_1(sc, R92C_BCN_CTRL, - urtwn_read_1(sc, R92C_BCN_CTRL) | R92C_BCN_CTRL_EN_BCN); - break; - default: - device_printf(sc->sc_dev, "undefined opmode %d\n", - vap->iv_opmode); - return; - } -} - -static void -urtwn_get_tsf(struct urtwn_softc *sc, uint64_t *buf) -{ - urtwn_read_region_1(sc, R92C_TSFTR, (uint8_t *)buf, sizeof(*buf)); -} - -static void -urtwn_set_led(struct urtwn_softc *sc, int led, int on) -{ - uint8_t reg; - - if (led == URTWN_LED_LINK) { - if (sc->chip & URTWN_CHIP_88E) { - reg = urtwn_read_1(sc, R92C_LEDCFG2) & 0xf0; - urtwn_write_1(sc, R92C_LEDCFG2, reg | 0x60); - if (!on) { - reg = urtwn_read_1(sc, R92C_LEDCFG2) & 0x90; - urtwn_write_1(sc, R92C_LEDCFG2, - reg | R92C_LEDCFG0_DIS); - urtwn_write_1(sc, R92C_MAC_PINMUX_CFG, - urtwn_read_1(sc, R92C_MAC_PINMUX_CFG) & - 0xfe); - } - } else { - reg = urtwn_read_1(sc, R92C_LEDCFG0) & 0x70; - if (!on) - reg |= R92C_LEDCFG0_DIS; - urtwn_write_1(sc, R92C_LEDCFG0, reg); - } - sc->ledlink = on; /* Save LED state. */ - } -} - -static void -urtwn_set_mode(struct urtwn_softc *sc, uint8_t mode) -{ - uint8_t reg; - - reg = urtwn_read_1(sc, R92C_MSR); - reg = (reg & ~R92C_MSR_MASK) | mode; - urtwn_write_1(sc, R92C_MSR, reg); -} - -static void -urtwn_ibss_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m, int subtype, - const struct ieee80211_rx_stats *rxs, - int rssi, int nf) -{ - struct ieee80211vap *vap = ni->ni_vap; - struct urtwn_softc *sc = vap->iv_ic->ic_softc; - struct urtwn_vap *uvp = URTWN_VAP(vap); - uint64_t ni_tstamp, curr_tstamp; - - uvp->recv_mgmt(ni, m, subtype, rxs, rssi, nf); - - if (vap->iv_state == IEEE80211_S_RUN && - (subtype == IEEE80211_FC0_SUBTYPE_BEACON || - subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) { - ni_tstamp = le64toh(ni->ni_tstamp.tsf); - URTWN_LOCK(sc); - urtwn_get_tsf(sc, &curr_tstamp); - URTWN_UNLOCK(sc); - curr_tstamp = le64toh(curr_tstamp); - - if (ni_tstamp >= curr_tstamp) - (void) ieee80211_ibss_merge(ni); - } -} - -static int -urtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) -{ - struct urtwn_vap *uvp = URTWN_VAP(vap); - struct ieee80211com *ic = vap->iv_ic; - struct urtwn_softc *sc = ic->ic_softc; - struct ieee80211_node *ni; - enum ieee80211_state ostate; - uint32_t reg; - uint8_t mode; - int error = 0; - - ostate = vap->iv_state; - URTWN_DPRINTF(sc, URTWN_DEBUG_STATE, "%s -> %s\n", - ieee80211_state_name[ostate], ieee80211_state_name[nstate]); - - IEEE80211_UNLOCK(ic); - URTWN_LOCK(sc); - callout_stop(&sc->sc_watchdog_ch); - - if (ostate == IEEE80211_S_RUN) { - /* Stop calibration. */ - callout_stop(&sc->sc_calib_to); - - /* Turn link LED off. */ - urtwn_set_led(sc, URTWN_LED_LINK, 0); - - /* Set media status to 'No Link'. */ - urtwn_set_mode(sc, R92C_MSR_NOLINK); - - /* Stop Rx of data frames. */ - urtwn_write_2(sc, R92C_RXFLTMAP2, 0); - - /* Disable TSF synchronization. */ - urtwn_write_1(sc, R92C_BCN_CTRL, - (urtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_EN_BCN) | - R92C_BCN_CTRL_DIS_TSF_UDT0); - - /* Disable beaconing. */ - urtwn_write_1(sc, R92C_MBID_NUM, - urtwn_read_1(sc, R92C_MBID_NUM) & ~R92C_MBID_TXBCN_RPT0); - - /* Reset TSF. */ - urtwn_write_1(sc, R92C_DUAL_TSF_RST, R92C_DUAL_TSF_RST0); - - /* Reset EDCA parameters. */ - urtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217); - urtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317); - urtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320); - urtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444); - } - - switch (nstate) { - case IEEE80211_S_INIT: - /* Turn link LED off. */ - urtwn_set_led(sc, URTWN_LED_LINK, 0); - break; - case IEEE80211_S_SCAN: - /* Pause AC Tx queues. */ - urtwn_write_1(sc, R92C_TXPAUSE, - urtwn_read_1(sc, R92C_TXPAUSE) | R92C_TX_QUEUE_AC); - break; - case IEEE80211_S_AUTH: - urtwn_set_chan(sc, ic->ic_curchan, NULL); - break; - case IEEE80211_S_RUN: - if (vap->iv_opmode == IEEE80211_M_MONITOR) { - /* Turn link LED on. */ - urtwn_set_led(sc, URTWN_LED_LINK, 1); - break; - } - - ni = ieee80211_ref_node(vap->iv_bss); - - if (ic->ic_bsschan == IEEE80211_CHAN_ANYC || - ni->ni_chan == IEEE80211_CHAN_ANYC) { - device_printf(sc->sc_dev, - "%s: could not move to RUN state\n", __func__); - error = EINVAL; - goto end_run; - } - - switch (vap->iv_opmode) { - case IEEE80211_M_STA: - mode = R92C_MSR_INFRA; - break; - case IEEE80211_M_IBSS: - mode = R92C_MSR_ADHOC; - break; - case IEEE80211_M_HOSTAP: - mode = R92C_MSR_AP; - break; - default: - device_printf(sc->sc_dev, "undefined opmode %d\n", - vap->iv_opmode); - error = EINVAL; - goto end_run; - } - - /* Set media status to 'Associated'. */ - urtwn_set_mode(sc, mode); - - /* Set BSSID. */ - urtwn_write_4(sc, R92C_BSSID + 0, le32dec(&ni->ni_bssid[0])); - urtwn_write_4(sc, R92C_BSSID + 4, le16dec(&ni->ni_bssid[4])); - - if (ic->ic_curmode == IEEE80211_MODE_11B) - urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0); - else /* 802.11b/g */ - urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3); - - /* Enable Rx of data frames. */ - urtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff); - - /* Flush all AC queues. */ - urtwn_write_1(sc, R92C_TXPAUSE, 0); - - /* Set beacon interval. */ - urtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval); - - /* Allow Rx from our BSSID only. */ - if (ic->ic_promisc == 0) { - reg = urtwn_read_4(sc, R92C_RCR); - - if (vap->iv_opmode != IEEE80211_M_HOSTAP) { - reg |= R92C_RCR_CBSSID_DATA; - if (vap->iv_opmode != IEEE80211_M_IBSS) - reg |= R92C_RCR_CBSSID_BCN; - } - - urtwn_write_4(sc, R92C_RCR, reg); - } - - if (vap->iv_opmode == IEEE80211_M_HOSTAP || - vap->iv_opmode == IEEE80211_M_IBSS) { - error = urtwn_setup_beacon(sc, ni); - if (error != 0) { - device_printf(sc->sc_dev, - "unable to push beacon into the chip, " - "error %d\n", error); - goto end_run; - } - } - - /* Enable TSF synchronization. */ - urtwn_tsf_sync_enable(sc, vap); - - urtwn_write_1(sc, R92C_SIFS_CCK + 1, 10); - urtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10); - urtwn_write_1(sc, R92C_SPEC_SIFS + 1, 10); - urtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, 10); - urtwn_write_1(sc, R92C_R2T_SIFS + 1, 10); - urtwn_write_1(sc, R92C_T2T_SIFS + 1, 10); - - /* Intialize rate adaptation. */ - if (!(sc->chip & URTWN_CHIP_88E)) - urtwn_ra_init(sc); - /* Turn link LED on. */ - urtwn_set_led(sc, URTWN_LED_LINK, 1); - - sc->avg_pwdb = -1; /* Reset average RSSI. */ - /* Reset temperature calibration state machine. */ - sc->sc_flags &= ~URTWN_TEMP_MEASURED; - sc->thcal_lctemp = 0; - /* Start periodic calibration. */ - callout_reset(&sc->sc_calib_to, 2*hz, urtwn_calib_to, sc); - -end_run: - ieee80211_free_node(ni); - break; - default: - break; - } - - URTWN_UNLOCK(sc); - IEEE80211_LOCK(ic); - return (error != 0 ? error : uvp->newstate(vap, nstate, arg)); -} - -static void -urtwn_calib_to(void *arg) -{ - struct urtwn_softc *sc = arg; - - /* Do it in a process context. */ - urtwn_cmd_sleepable(sc, NULL, 0, urtwn_calib_cb); -} - -static void -urtwn_calib_cb(struct urtwn_softc *sc, union sec_param *data) -{ - /* Do temperature compensation. */ - urtwn_temp_calib(sc); - - if ((urtwn_read_1(sc, R92C_MSR) & R92C_MSR_MASK) != R92C_MSR_NOLINK) - callout_reset(&sc->sc_calib_to, 2*hz, urtwn_calib_to, sc); -} - -static void -urtwn_watchdog(void *arg) -{ - struct urtwn_softc *sc = arg; - - if (sc->sc_txtimer > 0) { - if (--sc->sc_txtimer == 0) { - device_printf(sc->sc_dev, "device timeout\n"); - counter_u64_add(sc->sc_ic.ic_oerrors, 1); - return; - } - callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); - } -} - -static void -urtwn_update_avgrssi(struct urtwn_softc *sc, int rate, int8_t rssi) -{ - int pwdb; - - /* Convert antenna signal to percentage. */ - if (rssi <= -100 || rssi >= 20) - pwdb = 0; - else if (rssi >= 0) - pwdb = 100; - else - pwdb = 100 + rssi; - if (!(sc->chip & URTWN_CHIP_88E)) { - if (rate <= URTWN_RIDX_CCK11) { - /* CCK gain is smaller than OFDM/MCS gain. */ - pwdb += 6; - if (pwdb > 100) - pwdb = 100; - if (pwdb <= 14) - pwdb -= 4; - else if (pwdb <= 26) - pwdb -= 8; - else if (pwdb <= 34) - pwdb -= 6; - else if (pwdb <= 42) - pwdb -= 2; - } - } - if (sc->avg_pwdb == -1) /* Init. */ - sc->avg_pwdb = pwdb; - else if (sc->avg_pwdb < pwdb) - sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1; - else - sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20); - URTWN_DPRINTF(sc, URTWN_DEBUG_RSSI, "%s: PWDB %d, EMA %d\n", __func__, - pwdb, sc->avg_pwdb); -} - -static int8_t -urtwn_get_rssi(struct urtwn_softc *sc, int rate, void *physt) -{ - static const int8_t cckoff[] = { 16, -12, -26, -46 }; - struct r92c_rx_phystat *phy; - struct r92c_rx_cck *cck; - uint8_t rpt; - int8_t rssi; - - if (rate <= URTWN_RIDX_CCK11) { - cck = (struct r92c_rx_cck *)physt; - if (sc->sc_flags & URTWN_FLAG_CCK_HIPWR) { - rpt = (cck->agc_rpt >> 5) & 0x3; - rssi = (cck->agc_rpt & 0x1f) << 1; - } else { - rpt = (cck->agc_rpt >> 6) & 0x3; - rssi = cck->agc_rpt & 0x3e; - } - rssi = cckoff[rpt] - rssi; - } else { /* OFDM/HT. */ - phy = (struct r92c_rx_phystat *)physt; - rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110; - } - return (rssi); -} - -static int8_t -urtwn_r88e_get_rssi(struct urtwn_softc *sc, int rate, void *physt) -{ - struct r92c_rx_phystat *phy; - struct r88e_rx_cck *cck; - uint8_t cck_agc_rpt, lna_idx, vga_idx; - int8_t rssi; - - rssi = 0; - if (rate <= URTWN_RIDX_CCK11) { - cck = (struct r88e_rx_cck *)physt; - cck_agc_rpt = cck->agc_rpt; - lna_idx = (cck_agc_rpt & 0xe0) >> 5; - vga_idx = cck_agc_rpt & 0x1f; - switch (lna_idx) { - case 7: - if (vga_idx <= 27) - rssi = -100 + 2* (27 - vga_idx); - else - rssi = -100; - break; - case 6: - rssi = -48 + 2 * (2 - vga_idx); - break; - case 5: - rssi = -42 + 2 * (7 - vga_idx); - break; - case 4: - rssi = -36 + 2 * (7 - vga_idx); - break; - case 3: - rssi = -24 + 2 * (7 - vga_idx); - break; - case 2: - rssi = -12 + 2 * (5 - vga_idx); - break; - case 1: - rssi = 8 - (2 * vga_idx); - break; - case 0: - rssi = 14 - (2 * vga_idx); - break; - } - rssi += 6; - } else { /* OFDM/HT. */ - phy = (struct r92c_rx_phystat *)physt; - rssi = ((le32toh(phy->phydw1) >> 1) & 0x7f) - 110; - } - return (rssi); -} - -static int -urtwn_tx_data(struct urtwn_softc *sc, struct ieee80211_node *ni, - struct mbuf *m, struct urtwn_data *data) -{ - const struct ieee80211_txparam *tp; - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211_key *k = NULL; - struct ieee80211_channel *chan; - struct ieee80211_frame *wh; - struct r92c_tx_desc *txd; - uint8_t macid, raid, rate, ridx, type, tid, qos, qsel; - int hasqos, ismcast; - - URTWN_ASSERT_LOCKED(sc); - - wh = mtod(m, struct ieee80211_frame *); - type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; - hasqos = IEEE80211_QOS_HAS_SEQ(wh); - ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1); - - /* Select TX ring for this frame. */ - if (hasqos) { - qos = ((const struct ieee80211_qosframe *)wh)->i_qos[0]; - tid = qos & IEEE80211_QOS_TID; - } else { - qos = 0; - tid = 0; - } - - chan = (ni->ni_chan != IEEE80211_CHAN_ANYC) ? - ni->ni_chan : ic->ic_curchan; - tp = &vap->iv_txparms[ieee80211_chan2mode(chan)]; - - /* Choose a TX rate index. */ - if (type == IEEE80211_FC0_TYPE_MGT) - rate = tp->mgmtrate; - else if (ismcast) - rate = tp->mcastrate; - else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) - rate = tp->ucastrate; - else if (m->m_flags & M_EAPOL) - rate = tp->mgmtrate; - else { - if (URTWN_CHIP_HAS_RATECTL(sc)) { - /* XXX pass pktlen */ - (void) ieee80211_ratectl_rate(ni, NULL, 0); - rate = ni->ni_txrate; - } else { - /* XXX TODO: drop the default rate for 11b/11g? */ - if (ni->ni_flags & IEEE80211_NODE_HT) - rate = IEEE80211_RATE_MCS | 0x4; /* MCS4 */ - else if (ic->ic_curmode != IEEE80211_MODE_11B) - rate = 108; - else - rate = 22; - } - } - - /* - * XXX TODO: this should be per-node, for 11b versus 11bg - * nodes in hostap mode - */ - ridx = rate2ridx(rate); - if (ni->ni_flags & IEEE80211_NODE_HT) - raid = R92C_RAID_11GN; - else if (ic->ic_curmode != IEEE80211_MODE_11B) - raid = R92C_RAID_11BG; - else - raid = R92C_RAID_11B; - - if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) { - k = ieee80211_crypto_encap(ni, m); - if (k == NULL) { - device_printf(sc->sc_dev, - "ieee80211_crypto_encap returns NULL.\n"); - return (ENOBUFS); - } - - /* in case packet header moved, reset pointer */ - wh = mtod(m, struct ieee80211_frame *); - } - - /* Fill Tx descriptor. */ - txd = (struct r92c_tx_desc *)data->buf; - memset(txd, 0, sizeof(*txd)); - - txd->txdw0 |= htole32( - SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | - R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG); - if (ismcast) - txd->txdw0 |= htole32(R92C_TXDW0_BMCAST); - - if (!ismcast) { - /* Unicast frame, check if an ACK is expected. */ - if (!qos || (qos & IEEE80211_QOS_ACKPOLICY) != - IEEE80211_QOS_ACKPOLICY_NOACK) { - txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); - txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, - tp->maxretry)); - } - - if (sc->chip & URTWN_CHIP_88E) { - struct urtwn_node *un = URTWN_NODE(ni); - macid = un->id; - } else - macid = URTWN_MACID_BSS; - - if (type == IEEE80211_FC0_TYPE_DATA) { - qsel = tid % URTWN_MAX_TID; - - if (sc->chip & URTWN_CHIP_88E) { - txd->txdw2 |= htole32( - R88E_TXDW2_AGGBK | - R88E_TXDW2_CCX_RPT); - } else - txd->txdw1 |= htole32(R92C_TXDW1_AGGBK); - - /* protmode, non-HT */ - /* XXX TODO: noack frames? */ - if ((rate & 0x80) == 0 && - (ic->ic_flags & IEEE80211_F_USEPROT)) { - switch (ic->ic_protmode) { - case IEEE80211_PROT_CTSONLY: - txd->txdw4 |= htole32( - R92C_TXDW4_CTS2SELF); - break; - case IEEE80211_PROT_RTSCTS: - txd->txdw4 |= htole32( - R92C_TXDW4_RTSEN | - R92C_TXDW4_HWRTSEN); - break; - default: - break; - } - } - - /* protmode, HT */ - /* XXX TODO: noack frames? */ - if ((rate & 0x80) && - (ic->ic_htprotmode == IEEE80211_PROT_RTSCTS)) { - txd->txdw4 |= htole32( - R92C_TXDW4_RTSEN | - R92C_TXDW4_HWRTSEN); - } - - /* XXX TODO: rtsrate is configurable? 24mbit may - * be a bit high for RTS rate? */ - txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, - URTWN_RIDX_OFDM24)); - - txd->txdw5 |= htole32(0x0001ff00); - } else /* IEEE80211_FC0_TYPE_MGT */ - qsel = R92C_TXDW1_QSEL_MGNT; - } else { - macid = URTWN_MACID_BC; - qsel = R92C_TXDW1_QSEL_MGNT; - } - - txd->txdw1 |= htole32( - SM(R92C_TXDW1_QSEL, qsel) | - SM(R92C_TXDW1_RAID, raid)); - - /* XXX TODO: 40MHZ flag? */ - /* XXX TODO: AMPDU flag? (AGG_ENABLE or AGG_BREAK?) Density shift? */ - /* XXX Short preamble? */ - /* XXX Short-GI? */ - - if (sc->chip & URTWN_CHIP_88E) - txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, macid)); - else - txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, macid)); - - txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); - - /* Force this rate if needed. */ - if (URTWN_CHIP_HAS_RATECTL(sc) || ismcast || - (tp->ucastrate != IEEE80211_FIXED_RATE_NONE) || - (m->m_flags & M_EAPOL) || type != IEEE80211_FC0_TYPE_DATA) - txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); - - if (!hasqos) { - /* Use HW sequence numbering for non-QoS frames. */ - if (sc->chip & URTWN_CHIP_88E) - txd->txdseq = htole16(R88E_TXDSEQ_HWSEQ_EN); - else - txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); - } else { - /* Set sequence number. */ - txd->txdseq = htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE); - } - - if (k != NULL && !(k->wk_flags & IEEE80211_KEY_SWCRYPT)) { - uint8_t cipher; - - switch (k->wk_cipher->ic_cipher) { - case IEEE80211_CIPHER_WEP: - case IEEE80211_CIPHER_TKIP: - cipher = R92C_TXDW1_CIPHER_RC4; - break; - case IEEE80211_CIPHER_AES_CCM: - cipher = R92C_TXDW1_CIPHER_AES; - break; - default: - device_printf(sc->sc_dev, "%s: unknown cipher %d\n", - __func__, k->wk_cipher->ic_cipher); - return (EINVAL); - } - - txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER, cipher)); - } - - if (ieee80211_radiotap_active_vap(vap)) { - struct urtwn_tx_radiotap_header *tap = &sc->sc_txtap; - - tap->wt_flags = 0; - if (k != NULL) - tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; - ieee80211_radiotap_tx(vap, m); - } - - data->ni = ni; - - urtwn_tx_start(sc, m, type, data); - - return (0); -} - -static int -urtwn_tx_raw(struct urtwn_softc *sc, struct ieee80211_node *ni, - struct mbuf *m, struct urtwn_data *data, - const struct ieee80211_bpf_params *params) -{ - struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211_key *k = NULL; - struct ieee80211_frame *wh; - struct r92c_tx_desc *txd; - uint8_t cipher, ridx, type; - - /* Encrypt the frame if need be. */ - cipher = R92C_TXDW1_CIPHER_NONE; - if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { - /* Retrieve key for TX. */ - k = ieee80211_crypto_encap(ni, m); - if (k == NULL) - return (ENOBUFS); - - if (!(k->wk_flags & IEEE80211_KEY_SWCRYPT)) { - switch (k->wk_cipher->ic_cipher) { - case IEEE80211_CIPHER_WEP: - case IEEE80211_CIPHER_TKIP: - cipher = R92C_TXDW1_CIPHER_RC4; - break; - case IEEE80211_CIPHER_AES_CCM: - cipher = R92C_TXDW1_CIPHER_AES; - break; - default: - device_printf(sc->sc_dev, - "%s: unknown cipher %d\n", - __func__, k->wk_cipher->ic_cipher); - return (EINVAL); - } - } - } - - /* XXX TODO: 11n checks, matching urtwn_tx_data() */ - - wh = mtod(m, struct ieee80211_frame *); - type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; - - /* Fill Tx descriptor. */ - txd = (struct r92c_tx_desc *)data->buf; - memset(txd, 0, sizeof(*txd)); - - txd->txdw0 |= htole32( - SM(R92C_TXDW0_OFFSET, sizeof(*txd)) | - R92C_TXDW0_OWN | R92C_TXDW0_FSG | R92C_TXDW0_LSG); - if (IEEE80211_IS_MULTICAST(wh->i_addr1)) - txd->txdw0 |= htole32(R92C_TXDW0_BMCAST); - - if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) { - txd->txdw5 |= htole32(R92C_TXDW5_RTY_LMT_ENA); - txd->txdw5 |= htole32(SM(R92C_TXDW5_RTY_LMT, - params->ibp_try0)); - } - if (params->ibp_flags & IEEE80211_BPF_RTS) - txd->txdw4 |= htole32(R92C_TXDW4_RTSEN | R92C_TXDW4_HWRTSEN); - if (params->ibp_flags & IEEE80211_BPF_CTS) - txd->txdw4 |= htole32(R92C_TXDW4_CTS2SELF); - if (txd->txdw4 & htole32(R92C_TXDW4_RTSEN | R92C_TXDW4_CTS2SELF)) { - txd->txdw4 |= htole32(SM(R92C_TXDW4_RTSRATE, - URTWN_RIDX_OFDM24)); - } - - if (sc->chip & URTWN_CHIP_88E) - txd->txdw1 |= htole32(SM(R88E_TXDW1_MACID, URTWN_MACID_BC)); - else - txd->txdw1 |= htole32(SM(R92C_TXDW1_MACID, URTWN_MACID_BC)); - - /* XXX TODO: rate index/config (RAID) for 11n? */ - txd->txdw1 |= htole32(SM(R92C_TXDW1_QSEL, R92C_TXDW1_QSEL_MGNT)); - txd->txdw1 |= htole32(SM(R92C_TXDW1_CIPHER, cipher)); - - /* Choose a TX rate index. */ - ridx = rate2ridx(params->ibp_rate0); - txd->txdw5 |= htole32(SM(R92C_TXDW5_DATARATE, ridx)); - txd->txdw5 |= htole32(0x0001ff00); - txd->txdw4 |= htole32(R92C_TXDW4_DRVRATE); - - if (!IEEE80211_QOS_HAS_SEQ(wh)) { - /* Use HW sequence numbering for non-QoS frames. */ - if (sc->chip & URTWN_CHIP_88E) - txd->txdseq = htole16(R88E_TXDSEQ_HWSEQ_EN); - else - txd->txdw4 |= htole32(R92C_TXDW4_HWSEQ_EN); - } else { - /* Set sequence number. */ - txd->txdseq = htole16(M_SEQNO_GET(m) % IEEE80211_SEQ_RANGE); - } - - if (ieee80211_radiotap_active_vap(vap)) { - struct urtwn_tx_radiotap_header *tap = &sc->sc_txtap; - - tap->wt_flags = 0; - if (k != NULL) - tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; - ieee80211_radiotap_tx(vap, m); - } - - data->ni = ni; - - urtwn_tx_start(sc, m, type, data); - - return (0); -} - -static void -urtwn_tx_start(struct urtwn_softc *sc, struct mbuf *m, uint8_t type, - struct urtwn_data *data) -{ - struct usb_xfer *xfer; - struct r92c_tx_desc *txd; - uint16_t ac, sum; - int i, xferlen; - - URTWN_ASSERT_LOCKED(sc); - - ac = M_WME_GETAC(m); - - switch (type) { - case IEEE80211_FC0_TYPE_CTL: - case IEEE80211_FC0_TYPE_MGT: - xfer = sc->sc_xfer[URTWN_BULK_TX_VO]; - break; - default: - xfer = sc->sc_xfer[wme2queue[ac].qid]; - break; - } - - txd = (struct r92c_tx_desc *)data->buf; - txd->txdw0 |= htole32(SM(R92C_TXDW0_PKTLEN, m->m_pkthdr.len)); - - /* Compute Tx descriptor checksum. */ - sum = 0; - for (i = 0; i < sizeof(*txd) / 2; i++) - sum ^= ((uint16_t *)txd)[i]; - txd->txdsum = sum; /* NB: already little endian. */ - - xferlen = sizeof(*txd) + m->m_pkthdr.len; - m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)&txd[1]); - - data->buflen = xferlen; - data->m = m; - - STAILQ_INSERT_TAIL(&sc->sc_tx_pending, data, next); - usbd_transfer_start(xfer); -} - -static int -urtwn_transmit(struct ieee80211com *ic, struct mbuf *m) -{ - struct urtwn_softc *sc = ic->ic_softc; - int error; - - URTWN_LOCK(sc); - if ((sc->sc_flags & URTWN_RUNNING) == 0) { - URTWN_UNLOCK(sc); - return (ENXIO); - } - error = mbufq_enqueue(&sc->sc_snd, m); - if (error) { - URTWN_UNLOCK(sc); - return (error); - } - urtwn_start(sc); - URTWN_UNLOCK(sc); - - return (0); -} - -static void -urtwn_start(struct urtwn_softc *sc) -{ - struct ieee80211_node *ni; - struct mbuf *m; - struct urtwn_data *bf; - - URTWN_ASSERT_LOCKED(sc); - while ((m = mbufq_dequeue(&sc->sc_snd)) != NULL) { - bf = urtwn_getbuf(sc); - if (bf == NULL) { - mbufq_prepend(&sc->sc_snd, m); - break; - } - ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; - m->m_pkthdr.rcvif = NULL; - - URTWN_DPRINTF(sc, URTWN_DEBUG_XMIT, "%s: called; m=%p\n", - __func__, - m); - - if (urtwn_tx_data(sc, ni, m, bf) != 0) { - if_inc_counter(ni->ni_vap->iv_ifp, - IFCOUNTER_OERRORS, 1); - STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); - m_freem(m); - ieee80211_free_node(ni); - break; - } - sc->sc_txtimer = 5; - callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); - } -} - -static void -urtwn_parent(struct ieee80211com *ic) -{ - struct urtwn_softc *sc = ic->ic_softc; - - URTWN_LOCK(sc); - if (sc->sc_flags & URTWN_DETACHED) { - URTWN_UNLOCK(sc); - return; - } - URTWN_UNLOCK(sc); - - if (ic->ic_nrunning > 0) { - if (urtwn_init(sc) != 0) { - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - if (vap != NULL) - ieee80211_stop(vap); - } else - ieee80211_start_all(ic); - } else - urtwn_stop(sc); -} - -static __inline int -urtwn_power_on(struct urtwn_softc *sc) -{ - - return sc->sc_power_on(sc); -} - -static int -urtwn_r92c_power_on(struct urtwn_softc *sc) -{ - uint32_t reg; - usb_error_t error; - int ntries; - - /* Wait for autoload done bit. */ - for (ntries = 0; ntries < 1000; ntries++) { - if (urtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN) - break; - urtwn_ms_delay(sc); - } - if (ntries == 1000) { - device_printf(sc->sc_dev, - "timeout waiting for chip autoload\n"); - return (ETIMEDOUT); - } - - /* Unlock ISO/CLK/Power control register. */ - error = urtwn_write_1(sc, R92C_RSV_CTRL, 0); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - /* Move SPS into PWM mode. */ - error = urtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - urtwn_ms_delay(sc); - - reg = urtwn_read_1(sc, R92C_LDOV12D_CTRL); - if (!(reg & R92C_LDOV12D_CTRL_LDV12_EN)) { - error = urtwn_write_1(sc, R92C_LDOV12D_CTRL, - reg | R92C_LDOV12D_CTRL_LDV12_EN); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - urtwn_ms_delay(sc); - error = urtwn_write_1(sc, R92C_SYS_ISO_CTRL, - urtwn_read_1(sc, R92C_SYS_ISO_CTRL) & - ~R92C_SYS_ISO_CTRL_MD2PP); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - } - - /* Auto enable WLAN. */ - error = urtwn_write_2(sc, R92C_APS_FSMCO, - urtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - for (ntries = 0; ntries < 1000; ntries++) { - if (!(urtwn_read_2(sc, R92C_APS_FSMCO) & - R92C_APS_FSMCO_APFM_ONMAC)) - break; - urtwn_ms_delay(sc); - } - if (ntries == 1000) { - device_printf(sc->sc_dev, - "timeout waiting for MAC auto ON\n"); - return (ETIMEDOUT); - } - - /* Enable radio, GPIO and LED functions. */ - error = urtwn_write_2(sc, R92C_APS_FSMCO, - R92C_APS_FSMCO_AFSM_HSUS | - R92C_APS_FSMCO_PDN_EN | - R92C_APS_FSMCO_PFM_ALDN); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - /* Release RF digital isolation. */ - error = urtwn_write_2(sc, R92C_SYS_ISO_CTRL, - urtwn_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - /* Initialize MAC. */ - error = urtwn_write_1(sc, R92C_APSD_CTRL, - urtwn_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - for (ntries = 0; ntries < 200; ntries++) { - if (!(urtwn_read_1(sc, R92C_APSD_CTRL) & - R92C_APSD_CTRL_OFF_STATUS)) - break; - urtwn_ms_delay(sc); - } - if (ntries == 200) { - device_printf(sc->sc_dev, - "timeout waiting for MAC initialization\n"); - return (ETIMEDOUT); - } - - /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ - reg = urtwn_read_2(sc, R92C_CR); - reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | - R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | - R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN | - R92C_CR_ENSEC; - error = urtwn_write_2(sc, R92C_CR, reg); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - error = urtwn_write_1(sc, 0xfe10, 0x19); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - return (0); -} - -static int -urtwn_r88e_power_on(struct urtwn_softc *sc) -{ - uint32_t reg; - usb_error_t error; - int ntries; - - /* Wait for power ready bit. */ - for (ntries = 0; ntries < 5000; ntries++) { - if (urtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST) - break; - urtwn_ms_delay(sc); - } - if (ntries == 5000) { - device_printf(sc->sc_dev, - "timeout waiting for chip power up\n"); - return (ETIMEDOUT); - } - - /* Reset BB. */ - error = urtwn_write_1(sc, R92C_SYS_FUNC_EN, - urtwn_read_1(sc, R92C_SYS_FUNC_EN) & ~(R92C_SYS_FUNC_EN_BBRSTB | - R92C_SYS_FUNC_EN_BB_GLB_RST)); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - error = urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 2, - urtwn_read_1(sc, R92C_AFE_XTAL_CTRL + 2) | 0x80); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - /* Disable HWPDN. */ - error = urtwn_write_2(sc, R92C_APS_FSMCO, - urtwn_read_2(sc, R92C_APS_FSMCO) & ~R92C_APS_FSMCO_APDM_HPDN); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - /* Disable WL suspend. */ - error = urtwn_write_2(sc, R92C_APS_FSMCO, - urtwn_read_2(sc, R92C_APS_FSMCO) & - ~(R92C_APS_FSMCO_AFSM_HSUS | R92C_APS_FSMCO_AFSM_PCIE)); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - error = urtwn_write_2(sc, R92C_APS_FSMCO, - urtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - for (ntries = 0; ntries < 5000; ntries++) { - if (!(urtwn_read_2(sc, R92C_APS_FSMCO) & - R92C_APS_FSMCO_APFM_ONMAC)) - break; - urtwn_ms_delay(sc); - } - if (ntries == 5000) - return (ETIMEDOUT); - - /* Enable LDO normal mode. */ - error = urtwn_write_1(sc, R92C_LPLDO_CTRL, - urtwn_read_1(sc, R92C_LPLDO_CTRL) & ~R92C_LPLDO_CTRL_SLEEP); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */ - error = urtwn_write_2(sc, R92C_CR, 0); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - reg = urtwn_read_2(sc, R92C_CR); - reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | - R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN | - R92C_CR_SCHEDULE_EN | R92C_CR_ENSEC | R92C_CR_CALTMR_EN; - error = urtwn_write_2(sc, R92C_CR, reg); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - return (0); -} - -static __inline void -urtwn_power_off(struct urtwn_softc *sc) -{ - - return sc->sc_power_off(sc); -} - -static void -urtwn_r92c_power_off(struct urtwn_softc *sc) -{ - uint32_t reg; - - /* Block all Tx queues. */ - urtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); - - /* Disable RF */ - urtwn_rf_write(sc, 0, 0, 0); - - urtwn_write_1(sc, R92C_APSD_CTRL, R92C_APSD_CTRL_OFF); - - /* Reset BB state machine */ - urtwn_write_1(sc, R92C_SYS_FUNC_EN, - R92C_SYS_FUNC_EN_USBD | R92C_SYS_FUNC_EN_USBA | - R92C_SYS_FUNC_EN_BB_GLB_RST); - urtwn_write_1(sc, R92C_SYS_FUNC_EN, - R92C_SYS_FUNC_EN_USBD | R92C_SYS_FUNC_EN_USBA); - - /* - * Reset digital sequence - */ -#ifndef URTWN_WITHOUT_UCODE - if (urtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RDY) { - /* Reset MCU ready status */ - urtwn_write_1(sc, R92C_MCUFWDL, 0); - - /* If firmware in ram code, do reset */ - urtwn_fw_reset(sc); - } -#endif - - /* Reset MAC and Enable 8051 */ - urtwn_write_1(sc, R92C_SYS_FUNC_EN + 1, - (R92C_SYS_FUNC_EN_CPUEN | - R92C_SYS_FUNC_EN_ELDR | - R92C_SYS_FUNC_EN_HWPDN) >> 8); - - /* Reset MCU ready status */ - urtwn_write_1(sc, R92C_MCUFWDL, 0); - - /* Disable MAC clock */ - urtwn_write_2(sc, R92C_SYS_CLKR, - R92C_SYS_CLKR_ANAD16V_EN | - R92C_SYS_CLKR_ANA8M | - R92C_SYS_CLKR_LOADER_EN | - R92C_SYS_CLKR_80M_SSC_DIS | - R92C_SYS_CLKR_SYS_EN | - R92C_SYS_CLKR_RING_EN | - 0x4000); - - /* Disable AFE PLL */ - urtwn_write_1(sc, R92C_AFE_PLL_CTRL, 0x80); - - /* Gated AFE DIG_CLOCK */ - urtwn_write_2(sc, R92C_AFE_XTAL_CTRL, 0x880F); - - /* Isolated digital to PON */ - urtwn_write_1(sc, R92C_SYS_ISO_CTRL, - R92C_SYS_ISO_CTRL_MD2PP | - R92C_SYS_ISO_CTRL_PA2PCIE | - R92C_SYS_ISO_CTRL_PD2CORE | - R92C_SYS_ISO_CTRL_IP2MAC | - R92C_SYS_ISO_CTRL_DIOP | - R92C_SYS_ISO_CTRL_DIOE); - - /* - * Pull GPIO PIN to balance level and LED control - */ - /* 1. Disable GPIO[7:0] */ - urtwn_write_2(sc, R92C_GPIO_IOSEL, 0x0000); - - reg = urtwn_read_4(sc, R92C_GPIO_PIN_CTRL) & ~0x0000ff00; - reg |= ((reg << 8) & 0x0000ff00) | 0x00ff0000; - urtwn_write_4(sc, R92C_GPIO_PIN_CTRL, reg); - - /* Disable GPIO[10:8] */ - urtwn_write_1(sc, R92C_MAC_PINMUX_CFG, 0x00); - - reg = urtwn_read_2(sc, R92C_GPIO_IO_SEL) & ~0x00f0; - reg |= (((reg & 0x000f) << 4) | 0x0780); - urtwn_write_2(sc, R92C_GPIO_IO_SEL, reg); - - /* Disable LED0 & 1 */ - urtwn_write_2(sc, R92C_LEDCFG0, 0x8080); - - /* - * Reset digital sequence - */ - /* Disable ELDR clock */ - urtwn_write_2(sc, R92C_SYS_CLKR, - R92C_SYS_CLKR_ANAD16V_EN | - R92C_SYS_CLKR_ANA8M | - R92C_SYS_CLKR_LOADER_EN | - R92C_SYS_CLKR_80M_SSC_DIS | - R92C_SYS_CLKR_SYS_EN | - R92C_SYS_CLKR_RING_EN | - 0x4000); - - /* Isolated ELDR to PON */ - urtwn_write_1(sc, R92C_SYS_ISO_CTRL + 1, - (R92C_SYS_ISO_CTRL_DIOR | - R92C_SYS_ISO_CTRL_PWC_EV12V) >> 8); - - /* - * Disable analog sequence - */ - /* Disable A15 power */ - urtwn_write_1(sc, R92C_LDOA15_CTRL, R92C_LDOA15_CTRL_OBUF); - /* Disable digital core power */ - urtwn_write_1(sc, R92C_LDOV12D_CTRL, - urtwn_read_1(sc, R92C_LDOV12D_CTRL) & - ~R92C_LDOV12D_CTRL_LDV12_EN); - - /* Enter PFM mode */ - urtwn_write_1(sc, R92C_SPS0_CTRL, 0x23); - - /* Set USB suspend */ - urtwn_write_2(sc, R92C_APS_FSMCO, - R92C_APS_FSMCO_APDM_HOST | - R92C_APS_FSMCO_AFSM_HSUS | - R92C_APS_FSMCO_PFM_ALDN); - - /* Lock ISO/CLK/Power control register. */ - urtwn_write_1(sc, R92C_RSV_CTRL, 0x0E); -} - -static void -urtwn_r88e_power_off(struct urtwn_softc *sc) -{ - uint8_t reg; - int ntries; - - /* Disable any kind of TX reports. */ - urtwn_write_1(sc, R88E_TX_RPT_CTRL, - urtwn_read_1(sc, R88E_TX_RPT_CTRL) & - ~(R88E_TX_RPT1_ENA | R88E_TX_RPT2_ENA)); - - /* Stop Rx. */ - urtwn_write_1(sc, R92C_CR, 0); - - /* Move card to Low Power State. */ - /* Block all Tx queues. */ - urtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); - - for (ntries = 0; ntries < 20; ntries++) { - /* Should be zero if no packet is transmitting. */ - if (urtwn_read_4(sc, R88E_SCH_TXCMD) == 0) - break; - - urtwn_ms_delay(sc); - } - if (ntries == 20) { - device_printf(sc->sc_dev, "%s: failed to block Tx queues\n", - __func__); - return; - } - - /* CCK and OFDM are disabled, and clock are gated. */ - urtwn_write_1(sc, R92C_SYS_FUNC_EN, - urtwn_read_1(sc, R92C_SYS_FUNC_EN) & ~R92C_SYS_FUNC_EN_BBRSTB); - - urtwn_ms_delay(sc); - - /* Reset MAC TRX */ - urtwn_write_1(sc, R92C_CR, - R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN | - R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | - R92C_CR_PROTOCOL_EN | R92C_CR_SCHEDULE_EN); - - /* check if removed later */ - urtwn_write_1(sc, R92C_CR + 1, - urtwn_read_1(sc, R92C_CR + 1) & ~(R92C_CR_ENSEC >> 8)); - - /* Respond TxOK to scheduler */ - urtwn_write_1(sc, R92C_DUAL_TSF_RST, - urtwn_read_1(sc, R92C_DUAL_TSF_RST) | 0x20); - - /* If firmware in ram code, do reset. */ -#ifndef URTWN_WITHOUT_UCODE - if (urtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RDY) - urtwn_r88e_fw_reset(sc); -#endif - - /* Reset MCU ready status. */ - urtwn_write_1(sc, R92C_MCUFWDL, 0x00); - - /* Disable 32k. */ - urtwn_write_1(sc, R88E_32K_CTRL, - urtwn_read_1(sc, R88E_32K_CTRL) & ~0x01); - - /* Move card to Disabled state. */ - /* Turn off RF. */ - urtwn_write_1(sc, R92C_RF_CTRL, 0); - - /* LDO Sleep mode. */ - urtwn_write_1(sc, R92C_LPLDO_CTRL, - urtwn_read_1(sc, R92C_LPLDO_CTRL) | R92C_LPLDO_CTRL_SLEEP); - - /* Turn off MAC by HW state machine */ - urtwn_write_1(sc, R92C_APS_FSMCO + 1, - urtwn_read_1(sc, R92C_APS_FSMCO + 1) | - (R92C_APS_FSMCO_APFM_OFF >> 8)); - - for (ntries = 0; ntries < 20; ntries++) { - /* Wait until it will be disabled. */ - if ((urtwn_read_1(sc, R92C_APS_FSMCO + 1) & - (R92C_APS_FSMCO_APFM_OFF >> 8)) == 0) - break; - - urtwn_ms_delay(sc); - } - if (ntries == 20) { - device_printf(sc->sc_dev, "%s: could not turn off MAC\n", - __func__); - return; - } - - /* schmit trigger */ - urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 2, - urtwn_read_1(sc, R92C_AFE_XTAL_CTRL + 2) | 0x80); - - /* Enable WL suspend. */ - urtwn_write_1(sc, R92C_APS_FSMCO + 1, - (urtwn_read_1(sc, R92C_APS_FSMCO + 1) & ~0x10) | 0x08); - - /* Enable bandgap mbias in suspend. */ - urtwn_write_1(sc, R92C_APS_FSMCO + 3, 0); - - /* Clear SIC_EN register. */ - urtwn_write_1(sc, R92C_GPIO_MUXCFG + 1, - urtwn_read_1(sc, R92C_GPIO_MUXCFG + 1) & ~0x10); - - /* Set USB suspend enable local register */ - urtwn_write_1(sc, R92C_USB_SUSPEND, - urtwn_read_1(sc, R92C_USB_SUSPEND) | 0x10); - - /* Reset MCU IO Wrapper. */ - reg = urtwn_read_1(sc, R92C_RSV_CTRL + 1); - urtwn_write_1(sc, R92C_RSV_CTRL + 1, reg & ~0x08); - urtwn_write_1(sc, R92C_RSV_CTRL + 1, reg | 0x08); - - /* marked as 'For Power Consumption' code. */ - urtwn_write_1(sc, R92C_GPIO_OUT, urtwn_read_1(sc, R92C_GPIO_IN)); - urtwn_write_1(sc, R92C_GPIO_IOSEL, 0xff); - - urtwn_write_1(sc, R92C_GPIO_IO_SEL, - urtwn_read_1(sc, R92C_GPIO_IO_SEL) << 4); - urtwn_write_1(sc, R92C_GPIO_MOD, - urtwn_read_1(sc, R92C_GPIO_MOD) | 0x0f); - - /* Set LNA, TRSW, EX_PA Pin to output mode. */ - urtwn_write_4(sc, R88E_BB_PAD_CTRL, 0x00080808); -} - -static int -urtwn_llt_init(struct urtwn_softc *sc) -{ - int i, error, page_count, pktbuf_count; - - page_count = (sc->chip & URTWN_CHIP_88E) ? - R88E_TX_PAGE_COUNT : R92C_TX_PAGE_COUNT; - pktbuf_count = (sc->chip & URTWN_CHIP_88E) ? - R88E_TXPKTBUF_COUNT : R92C_TXPKTBUF_COUNT; - - /* Reserve pages [0; page_count]. */ - for (i = 0; i < page_count; i++) { - if ((error = urtwn_llt_write(sc, i, i + 1)) != 0) - return (error); - } - /* NB: 0xff indicates end-of-list. */ - if ((error = urtwn_llt_write(sc, i, 0xff)) != 0) - return (error); - /* - * Use pages [page_count + 1; pktbuf_count - 1] - * as ring buffer. - */ - for (++i; i < pktbuf_count - 1; i++) { - if ((error = urtwn_llt_write(sc, i, i + 1)) != 0) - return (error); - } - /* Make the last page point to the beginning of the ring buffer. */ - error = urtwn_llt_write(sc, i, page_count + 1); - return (error); -} - -#ifndef URTWN_WITHOUT_UCODE -static void -urtwn_fw_reset(struct urtwn_softc *sc) -{ - uint16_t reg; - int ntries; - - /* Tell 8051 to reset itself. */ - urtwn_write_1(sc, R92C_HMETFR + 3, 0x20); - - /* Wait until 8051 resets by itself. */ - for (ntries = 0; ntries < 100; ntries++) { - reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); - if (!(reg & R92C_SYS_FUNC_EN_CPUEN)) - return; - urtwn_ms_delay(sc); - } - /* Force 8051 reset. */ - urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN); -} - -static void -urtwn_r88e_fw_reset(struct urtwn_softc *sc) -{ - uint16_t reg; - - reg = urtwn_read_2(sc, R92C_SYS_FUNC_EN); - urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN); - urtwn_write_2(sc, R92C_SYS_FUNC_EN, reg | R92C_SYS_FUNC_EN_CPUEN); -} - -static int -urtwn_fw_loadpage(struct urtwn_softc *sc, int page, const uint8_t *buf, int len) -{ - uint32_t reg; - usb_error_t error = USB_ERR_NORMAL_COMPLETION; - int off, mlen; - - reg = urtwn_read_4(sc, R92C_MCUFWDL); - reg = RW(reg, R92C_MCUFWDL_PAGE, page); - urtwn_write_4(sc, R92C_MCUFWDL, reg); - - off = R92C_FW_START_ADDR; - while (len > 0) { - if (len > 196) - mlen = 196; - else if (len > 4) - mlen = 4; - else - mlen = 1; - /* XXX fix this deconst */ - error = urtwn_write_region_1(sc, off, - __DECONST(uint8_t *, buf), mlen); - if (error != USB_ERR_NORMAL_COMPLETION) - break; - off += mlen; - buf += mlen; - len -= mlen; - } - return (error); -} - -static int -urtwn_load_firmware(struct urtwn_softc *sc) -{ - const struct firmware *fw; - const struct r92c_fw_hdr *hdr; - const char *imagename; - const u_char *ptr; - size_t len; - uint32_t reg; - int mlen, ntries, page, error; - - URTWN_UNLOCK(sc); - /* Read firmware image from the filesystem. */ - if (sc->chip & URTWN_CHIP_88E) - imagename = "urtwn-rtl8188eufw"; - else if ((sc->chip & (URTWN_CHIP_UMC_A_CUT | URTWN_CHIP_92C)) == - URTWN_CHIP_UMC_A_CUT) - imagename = "urtwn-rtl8192cfwU"; - else - imagename = "urtwn-rtl8192cfwT"; - - fw = firmware_get(imagename); - URTWN_LOCK(sc); - if (fw == NULL) { - device_printf(sc->sc_dev, - "failed loadfirmware of file %s\n", imagename); - return (ENOENT); - } - - len = fw->datasize; - - if (len < sizeof(*hdr)) { - device_printf(sc->sc_dev, "firmware too short\n"); - error = EINVAL; - goto fail; - } - ptr = fw->data; - hdr = (const struct r92c_fw_hdr *)ptr; - /* Check if there is a valid FW header and skip it. */ - if ((le16toh(hdr->signature) >> 4) == 0x88c || - (le16toh(hdr->signature) >> 4) == 0x88e || - (le16toh(hdr->signature) >> 4) == 0x92c) { - URTWN_DPRINTF(sc, URTWN_DEBUG_FIRMWARE, - "FW V%d.%d %02d-%02d %02d:%02d\n", - le16toh(hdr->version), le16toh(hdr->subversion), - hdr->month, hdr->date, hdr->hour, hdr->minute); - ptr += sizeof(*hdr); - len -= sizeof(*hdr); - } - - if (urtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL) { - if (sc->chip & URTWN_CHIP_88E) - urtwn_r88e_fw_reset(sc); - else - urtwn_fw_reset(sc); - urtwn_write_1(sc, R92C_MCUFWDL, 0); - } - - if (!(sc->chip & URTWN_CHIP_88E)) { - urtwn_write_2(sc, R92C_SYS_FUNC_EN, - urtwn_read_2(sc, R92C_SYS_FUNC_EN) | - R92C_SYS_FUNC_EN_CPUEN); - } - urtwn_write_1(sc, R92C_MCUFWDL, - urtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_EN); - urtwn_write_1(sc, R92C_MCUFWDL + 2, - urtwn_read_1(sc, R92C_MCUFWDL + 2) & ~0x08); - - /* Reset the FWDL checksum. */ - urtwn_write_1(sc, R92C_MCUFWDL, - urtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_CHKSUM_RPT); - - for (page = 0; len > 0; page++) { - mlen = min(len, R92C_FW_PAGE_SIZE); - error = urtwn_fw_loadpage(sc, page, ptr, mlen); - if (error != 0) { - device_printf(sc->sc_dev, - "could not load firmware page\n"); - goto fail; - } - ptr += mlen; - len -= mlen; - } - urtwn_write_1(sc, R92C_MCUFWDL, - urtwn_read_1(sc, R92C_MCUFWDL) & ~R92C_MCUFWDL_EN); - urtwn_write_1(sc, R92C_MCUFWDL + 1, 0); - - /* Wait for checksum report. */ - for (ntries = 0; ntries < 1000; ntries++) { - if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT) - break; - urtwn_ms_delay(sc); - } - if (ntries == 1000) { - device_printf(sc->sc_dev, - "timeout waiting for checksum report\n"); - error = ETIMEDOUT; - goto fail; - } - - reg = urtwn_read_4(sc, R92C_MCUFWDL); - reg = (reg & ~R92C_MCUFWDL_WINTINI_RDY) | R92C_MCUFWDL_RDY; - urtwn_write_4(sc, R92C_MCUFWDL, reg); - if (sc->chip & URTWN_CHIP_88E) - urtwn_r88e_fw_reset(sc); - /* Wait for firmware readiness. */ - for (ntries = 0; ntries < 1000; ntries++) { - if (urtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY) - break; - urtwn_ms_delay(sc); - } - if (ntries == 1000) { - device_printf(sc->sc_dev, - "timeout waiting for firmware readiness\n"); - error = ETIMEDOUT; - goto fail; - } -fail: - firmware_put(fw, FIRMWARE_UNLOAD); - return (error); -} -#endif - -static int -urtwn_dma_init(struct urtwn_softc *sc) -{ - struct usb_endpoint *ep, *ep_end; - usb_error_t usb_err; - uint32_t reg; - int hashq, hasnq, haslq, nqueues, ntx; - int error, pagecount, npubqpages, nqpages, nrempages, tx_boundary; - - /* Initialize LLT table. */ - error = urtwn_llt_init(sc); - if (error != 0) - return (error); - - /* Determine the number of bulk-out pipes. */ - ntx = 0; - ep = sc->sc_udev->endpoints; - ep_end = sc->sc_udev->endpoints + sc->sc_udev->endpoints_max; - for (; ep != ep_end; ep++) { - if ((ep->edesc == NULL) || - (ep->iface_index != sc->sc_iface_index)) - continue; - if (UE_GET_DIR(ep->edesc->bEndpointAddress) == UE_DIR_OUT) - ntx++; - } - if (ntx == 0) { - device_printf(sc->sc_dev, - "%d: invalid number of Tx bulk pipes\n", ntx); - return (EIO); - } - - /* Get Tx queues to USB endpoints mapping. */ - hashq = hasnq = haslq = nqueues = 0; - switch (ntx) { - case 1: hashq = 1; break; - case 2: hashq = hasnq = 1; break; - case 3: case 4: hashq = hasnq = haslq = 1; break; - } - nqueues = hashq + hasnq + haslq; - if (nqueues == 0) - return (EIO); - - npubqpages = nqpages = nrempages = pagecount = 0; - if (sc->chip & URTWN_CHIP_88E) - tx_boundary = R88E_TX_PAGE_BOUNDARY; - else { - pagecount = R92C_TX_PAGE_COUNT; - npubqpages = R92C_PUBQ_NPAGES; - tx_boundary = R92C_TX_PAGE_BOUNDARY; - } - - /* Set number of pages for normal priority queue. */ - if (sc->chip & URTWN_CHIP_88E) { - usb_err = urtwn_write_2(sc, R92C_RQPN_NPQ, 0xd); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - return (EIO); - usb_err = urtwn_write_4(sc, R92C_RQPN, 0x808e000d); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - return (EIO); - } else { - /* Get the number of pages for each queue. */ - nqpages = (pagecount - npubqpages) / nqueues; - /* - * The remaining pages are assigned to the high priority - * queue. - */ - nrempages = (pagecount - npubqpages) % nqueues; - usb_err = urtwn_write_1(sc, R92C_RQPN_NPQ, hasnq ? nqpages : 0); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - return (EIO); - usb_err = urtwn_write_4(sc, R92C_RQPN, - /* Set number of pages for public queue. */ - SM(R92C_RQPN_PUBQ, npubqpages) | - /* Set number of pages for high priority queue. */ - SM(R92C_RQPN_HPQ, hashq ? nqpages + nrempages : 0) | - /* Set number of pages for low priority queue. */ - SM(R92C_RQPN_LPQ, haslq ? nqpages : 0) | - /* Load values. */ - R92C_RQPN_LD); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - return (EIO); - } - - usb_err = urtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, tx_boundary); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - return (EIO); - usb_err = urtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, tx_boundary); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - return (EIO); - usb_err = urtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, tx_boundary); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - return (EIO); - usb_err = urtwn_write_1(sc, R92C_TRXFF_BNDY, tx_boundary); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - return (EIO); - usb_err = urtwn_write_1(sc, R92C_TDECTRL + 1, tx_boundary); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - /* Set queue to USB pipe mapping. */ - reg = urtwn_read_2(sc, R92C_TRXDMA_CTRL); - reg &= ~R92C_TRXDMA_CTRL_QMAP_M; - if (nqueues == 1) { - if (hashq) - reg |= R92C_TRXDMA_CTRL_QMAP_HQ; - else if (hasnq) - reg |= R92C_TRXDMA_CTRL_QMAP_NQ; - else - reg |= R92C_TRXDMA_CTRL_QMAP_LQ; - } else if (nqueues == 2) { - /* - * All 2-endpoints configs have high and normal - * priority queues. - */ - reg |= R92C_TRXDMA_CTRL_QMAP_HQ_NQ; - } else - reg |= R92C_TRXDMA_CTRL_QMAP_3EP; - usb_err = urtwn_write_2(sc, R92C_TRXDMA_CTRL, reg); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - /* Set Tx/Rx transfer page boundary. */ - usb_err = urtwn_write_2(sc, R92C_TRXFF_BNDY + 2, - (sc->chip & URTWN_CHIP_88E) ? 0x23ff : 0x27ff); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - /* Set Tx/Rx transfer page size. */ - usb_err = urtwn_write_1(sc, R92C_PBP, - SM(R92C_PBP_PSRX, R92C_PBP_128) | - SM(R92C_PBP_PSTX, R92C_PBP_128)); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - return (0); -} - -static int -urtwn_mac_init(struct urtwn_softc *sc) -{ - usb_error_t error; - int i; - - /* Write MAC initialization values. */ - if (sc->chip & URTWN_CHIP_88E) { - for (i = 0; i < nitems(rtl8188eu_mac); i++) { - error = urtwn_write_1(sc, rtl8188eu_mac[i].reg, - rtl8188eu_mac[i].val); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - } - urtwn_write_1(sc, R92C_MAX_AGGR_NUM, 0x07); - } else { - for (i = 0; i < nitems(rtl8192cu_mac); i++) - error = urtwn_write_1(sc, rtl8192cu_mac[i].reg, - rtl8192cu_mac[i].val); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - } - - return (0); -} - -static void -urtwn_bb_init(struct urtwn_softc *sc) -{ - const struct urtwn_bb_prog *prog; - uint32_t reg; - uint8_t crystalcap; - int i; - - /* Enable BB and RF. */ - urtwn_write_2(sc, R92C_SYS_FUNC_EN, - urtwn_read_2(sc, R92C_SYS_FUNC_EN) | - R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST | - R92C_SYS_FUNC_EN_DIO_RF); - - if (!(sc->chip & URTWN_CHIP_88E)) - urtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83); - - urtwn_write_1(sc, R92C_RF_CTRL, - R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB); - urtwn_write_1(sc, R92C_SYS_FUNC_EN, - R92C_SYS_FUNC_EN_USBA | R92C_SYS_FUNC_EN_USBD | - R92C_SYS_FUNC_EN_BB_GLB_RST | R92C_SYS_FUNC_EN_BBRSTB); - - if (!(sc->chip & URTWN_CHIP_88E)) { - urtwn_write_1(sc, R92C_LDOHCI12_CTRL, 0x0f); - urtwn_write_1(sc, 0x15, 0xe9); - urtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80); - } - - /* Select BB programming based on board type. */ - if (sc->chip & URTWN_CHIP_88E) - prog = &rtl8188eu_bb_prog; - else if (!(sc->chip & URTWN_CHIP_92C)) { - if (sc->board_type == R92C_BOARD_TYPE_MINICARD) - prog = &rtl8188ce_bb_prog; - else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) - prog = &rtl8188ru_bb_prog; - else - prog = &rtl8188cu_bb_prog; - } else { - if (sc->board_type == R92C_BOARD_TYPE_MINICARD) - prog = &rtl8192ce_bb_prog; - else - prog = &rtl8192cu_bb_prog; - } - /* Write BB initialization values. */ - for (i = 0; i < prog->count; i++) { - urtwn_bb_write(sc, prog->regs[i], prog->vals[i]); - urtwn_ms_delay(sc); - } - - if (sc->chip & URTWN_CHIP_92C_1T2R) { - /* 8192C 1T only configuration. */ - reg = urtwn_bb_read(sc, R92C_FPGA0_TXINFO); - reg = (reg & ~0x00000003) | 0x2; - urtwn_bb_write(sc, R92C_FPGA0_TXINFO, reg); - - reg = urtwn_bb_read(sc, R92C_FPGA1_TXINFO); - reg = (reg & ~0x00300033) | 0x00200022; - urtwn_bb_write(sc, R92C_FPGA1_TXINFO, reg); - - reg = urtwn_bb_read(sc, R92C_CCK0_AFESETTING); - reg = (reg & ~0xff000000) | 0x45 << 24; - urtwn_bb_write(sc, R92C_CCK0_AFESETTING, reg); - - reg = urtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA); - reg = (reg & ~0x000000ff) | 0x23; - urtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, reg); - - reg = urtwn_bb_read(sc, R92C_OFDM0_AGCPARAM1); - reg = (reg & ~0x00000030) | 1 << 4; - urtwn_bb_write(sc, R92C_OFDM0_AGCPARAM1, reg); - - reg = urtwn_bb_read(sc, 0xe74); - reg = (reg & ~0x0c000000) | 2 << 26; - urtwn_bb_write(sc, 0xe74, reg); - reg = urtwn_bb_read(sc, 0xe78); - reg = (reg & ~0x0c000000) | 2 << 26; - urtwn_bb_write(sc, 0xe78, reg); - reg = urtwn_bb_read(sc, 0xe7c); - reg = (reg & ~0x0c000000) | 2 << 26; - urtwn_bb_write(sc, 0xe7c, reg); - reg = urtwn_bb_read(sc, 0xe80); - reg = (reg & ~0x0c000000) | 2 << 26; - urtwn_bb_write(sc, 0xe80, reg); - reg = urtwn_bb_read(sc, 0xe88); - reg = (reg & ~0x0c000000) | 2 << 26; - urtwn_bb_write(sc, 0xe88, reg); - } - - /* Write AGC values. */ - for (i = 0; i < prog->agccount; i++) { - urtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE, - prog->agcvals[i]); - urtwn_ms_delay(sc); - } - - if (sc->chip & URTWN_CHIP_88E) { - urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553422); - urtwn_ms_delay(sc); - urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), 0x69553420); - urtwn_ms_delay(sc); - - crystalcap = sc->rom.r88e_rom.crystalcap; - if (crystalcap == 0xff) - crystalcap = 0x20; - crystalcap &= 0x3f; - reg = urtwn_bb_read(sc, R92C_AFE_XTAL_CTRL); - urtwn_bb_write(sc, R92C_AFE_XTAL_CTRL, - RW(reg, R92C_AFE_XTAL_CTRL_ADDR, - crystalcap | crystalcap << 6)); - } else { - if (urtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) & - R92C_HSSI_PARAM2_CCK_HIPWR) - sc->sc_flags |= URTWN_FLAG_CCK_HIPWR; - } -} - -static void -urtwn_rf_init(struct urtwn_softc *sc) -{ - const struct urtwn_rf_prog *prog; - uint32_t reg, type; - int i, j, idx, off; - - /* Select RF programming based on board type. */ - if (sc->chip & URTWN_CHIP_88E) - prog = rtl8188eu_rf_prog; - else if (!(sc->chip & URTWN_CHIP_92C)) { - if (sc->board_type == R92C_BOARD_TYPE_MINICARD) - prog = rtl8188ce_rf_prog; - else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) - prog = rtl8188ru_rf_prog; - else - prog = rtl8188cu_rf_prog; - } else - prog = rtl8192ce_rf_prog; - - for (i = 0; i < sc->nrxchains; i++) { - /* Save RF_ENV control type. */ - idx = i / 2; - off = (i % 2) * 16; - reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx)); - type = (reg >> off) & 0x10; - - /* Set RF_ENV enable. */ - reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i)); - reg |= 0x100000; - urtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg); - urtwn_ms_delay(sc); - /* Set RF_ENV output high. */ - reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i)); - reg |= 0x10; - urtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg); - urtwn_ms_delay(sc); - /* Set address and data lengths of RF registers. */ - reg = urtwn_bb_read(sc, R92C_HSSI_PARAM2(i)); - reg &= ~R92C_HSSI_PARAM2_ADDR_LENGTH; - urtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg); - urtwn_ms_delay(sc); - reg = urtwn_bb_read(sc, R92C_HSSI_PARAM2(i)); - reg &= ~R92C_HSSI_PARAM2_DATA_LENGTH; - urtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg); - urtwn_ms_delay(sc); - - /* Write RF initialization values for this chain. */ - for (j = 0; j < prog[i].count; j++) { - if (prog[i].regs[j] >= 0xf9 && - prog[i].regs[j] <= 0xfe) { - /* - * These are fake RF registers offsets that - * indicate a delay is required. - */ - usb_pause_mtx(&sc->sc_mtx, hz / 20); /* 50ms */ - continue; - } - urtwn_rf_write(sc, i, prog[i].regs[j], - prog[i].vals[j]); - urtwn_ms_delay(sc); - } - - /* Restore RF_ENV control type. */ - reg = urtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx)); - reg &= ~(0x10 << off) | (type << off); - urtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(idx), reg); - - /* Cache RF register CHNLBW. */ - sc->rf_chnlbw[i] = urtwn_rf_read(sc, i, R92C_RF_CHNLBW); - } - - if ((sc->chip & (URTWN_CHIP_UMC_A_CUT | URTWN_CHIP_92C)) == - URTWN_CHIP_UMC_A_CUT) { - urtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255); - urtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x50a00); - } -} - -static void -urtwn_cam_init(struct urtwn_softc *sc) -{ - /* Invalidate all CAM entries. */ - urtwn_write_4(sc, R92C_CAMCMD, - R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR); -} - -static int -urtwn_cam_write(struct urtwn_softc *sc, uint32_t addr, uint32_t data) -{ - usb_error_t error; - - error = urtwn_write_4(sc, R92C_CAMWRITE, data); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - error = urtwn_write_4(sc, R92C_CAMCMD, - R92C_CAMCMD_POLLING | R92C_CAMCMD_WRITE | - SM(R92C_CAMCMD_ADDR, addr)); - if (error != USB_ERR_NORMAL_COMPLETION) - return (EIO); - - return (0); -} - -static void -urtwn_pa_bias_init(struct urtwn_softc *sc) -{ - uint8_t reg; - int i; - - for (i = 0; i < sc->nrxchains; i++) { - if (sc->pa_setting & (1 << i)) - continue; - urtwn_rf_write(sc, i, R92C_RF_IPA, 0x0f406); - urtwn_rf_write(sc, i, R92C_RF_IPA, 0x4f406); - urtwn_rf_write(sc, i, R92C_RF_IPA, 0x8f406); - urtwn_rf_write(sc, i, R92C_RF_IPA, 0xcf406); - } - if (!(sc->pa_setting & 0x10)) { - reg = urtwn_read_1(sc, 0x16); - reg = (reg & ~0xf0) | 0x90; - urtwn_write_1(sc, 0x16, reg); - } -} - -static void -urtwn_rxfilter_init(struct urtwn_softc *sc) -{ - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - uint32_t rcr; - uint16_t filter; - - URTWN_ASSERT_LOCKED(sc); - - /* Setup multicast filter. */ - urtwn_set_multi(sc); - - /* Filter for management frames. */ - filter = 0x7f3f; - switch (vap->iv_opmode) { - case IEEE80211_M_STA: - filter &= ~( - R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_REQ) | - R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_REQ) | - R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_PROBE_REQ)); - break; - case IEEE80211_M_HOSTAP: - filter &= ~( - R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_ASSOC_RESP) | - R92C_RXFLTMAP_SUBTYPE(IEEE80211_FC0_SUBTYPE_REASSOC_RESP)); - break; - case IEEE80211_M_MONITOR: - case IEEE80211_M_IBSS: - break; - default: - device_printf(sc->sc_dev, "%s: undefined opmode %d\n", - __func__, vap->iv_opmode); - break; - } - urtwn_write_2(sc, R92C_RXFLTMAP0, filter); - - /* Reject all control frames. */ - urtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000); - - /* Reject all data frames. */ - urtwn_write_2(sc, R92C_RXFLTMAP2, 0x0000); - - rcr = R92C_RCR_AM | R92C_RCR_AB | R92C_RCR_APM | - R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS | - R92C_RCR_APP_ICV | R92C_RCR_APP_MIC; - - if (vap->iv_opmode == IEEE80211_M_MONITOR) { - /* Accept all frames. */ - rcr |= R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | - R92C_RCR_AAP; - } - - /* Set Rx filter. */ - urtwn_write_4(sc, R92C_RCR, rcr); - - if (ic->ic_promisc != 0) { - /* Update Rx filter. */ - urtwn_set_promisc(sc); - } -} - -static void -urtwn_edca_init(struct urtwn_softc *sc) -{ - urtwn_write_2(sc, R92C_SPEC_SIFS, 0x100a); - urtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x100a); - urtwn_write_2(sc, R92C_SIFS_CCK, 0x100a); - urtwn_write_2(sc, R92C_SIFS_OFDM, 0x100a); - urtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b); - urtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f); - urtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005ea324); - urtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002fa226); -} - -static void -urtwn_write_txpower(struct urtwn_softc *sc, int chain, - uint16_t power[URTWN_RIDX_COUNT]) -{ - uint32_t reg; - - /* Write per-CCK rate Tx power. */ - if (chain == 0) { - reg = urtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32); - reg = RW(reg, R92C_TXAGC_A_CCK1, power[0]); - urtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg); - reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); - reg = RW(reg, R92C_TXAGC_A_CCK2, power[1]); - reg = RW(reg, R92C_TXAGC_A_CCK55, power[2]); - reg = RW(reg, R92C_TXAGC_A_CCK11, power[3]); - urtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); - } else { - reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32); - reg = RW(reg, R92C_TXAGC_B_CCK1, power[0]); - reg = RW(reg, R92C_TXAGC_B_CCK2, power[1]); - reg = RW(reg, R92C_TXAGC_B_CCK55, power[2]); - urtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg); - reg = urtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11); - reg = RW(reg, R92C_TXAGC_B_CCK11, power[3]); - urtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg); - } - /* Write per-OFDM rate Tx power. */ - urtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain), - SM(R92C_TXAGC_RATE06, power[ 4]) | - SM(R92C_TXAGC_RATE09, power[ 5]) | - SM(R92C_TXAGC_RATE12, power[ 6]) | - SM(R92C_TXAGC_RATE18, power[ 7])); - urtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain), - SM(R92C_TXAGC_RATE24, power[ 8]) | - SM(R92C_TXAGC_RATE36, power[ 9]) | - SM(R92C_TXAGC_RATE48, power[10]) | - SM(R92C_TXAGC_RATE54, power[11])); - /* Write per-MCS Tx power. */ - urtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain), - SM(R92C_TXAGC_MCS00, power[12]) | - SM(R92C_TXAGC_MCS01, power[13]) | - SM(R92C_TXAGC_MCS02, power[14]) | - SM(R92C_TXAGC_MCS03, power[15])); - urtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain), - SM(R92C_TXAGC_MCS04, power[16]) | - SM(R92C_TXAGC_MCS05, power[17]) | - SM(R92C_TXAGC_MCS06, power[18]) | - SM(R92C_TXAGC_MCS07, power[19])); - urtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain), - SM(R92C_TXAGC_MCS08, power[20]) | - SM(R92C_TXAGC_MCS09, power[21]) | - SM(R92C_TXAGC_MCS10, power[22]) | - SM(R92C_TXAGC_MCS11, power[23])); - urtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain), - SM(R92C_TXAGC_MCS12, power[24]) | - SM(R92C_TXAGC_MCS13, power[25]) | - SM(R92C_TXAGC_MCS14, power[26]) | - SM(R92C_TXAGC_MCS15, power[27])); -} - -static void -urtwn_get_txpower(struct urtwn_softc *sc, int chain, - struct ieee80211_channel *c, struct ieee80211_channel *extc, - uint16_t power[URTWN_RIDX_COUNT]) -{ - struct ieee80211com *ic = &sc->sc_ic; - struct r92c_rom *rom = &sc->rom.r92c_rom; - uint16_t cckpow, ofdmpow, htpow, diff, max; - const struct urtwn_txpwr *base; - int ridx, chan, group; - - /* Determine channel group. */ - chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ - if (chan <= 3) - group = 0; - else if (chan <= 9) - group = 1; - else - group = 2; - - /* Get original Tx power based on board type and RF chain. */ - if (!(sc->chip & URTWN_CHIP_92C)) { - if (sc->board_type == R92C_BOARD_TYPE_HIGHPA) - base = &rtl8188ru_txagc[chain]; - else - base = &rtl8192cu_txagc[chain]; - } else - base = &rtl8192cu_txagc[chain]; - - memset(power, 0, URTWN_RIDX_COUNT * sizeof(power[0])); - if (sc->regulatory == 0) { - for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) - power[ridx] = base->pwr[0][ridx]; - } - for (ridx = URTWN_RIDX_OFDM6; ridx < URTWN_RIDX_COUNT; ridx++) { - if (sc->regulatory == 3) { - power[ridx] = base->pwr[0][ridx]; - /* Apply vendor limits. */ - if (extc != NULL) - max = rom->ht40_max_pwr[group]; - else - max = rom->ht20_max_pwr[group]; - max = (max >> (chain * 4)) & 0xf; - if (power[ridx] > max) - power[ridx] = max; - } else if (sc->regulatory == 1) { - if (extc == NULL) - power[ridx] = base->pwr[group][ridx]; - } else if (sc->regulatory != 2) - power[ridx] = base->pwr[0][ridx]; - } - - /* Compute per-CCK rate Tx power. */ - cckpow = rom->cck_tx_pwr[chain][group]; - for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) { - power[ridx] += cckpow; - if (power[ridx] > R92C_MAX_TX_PWR) - power[ridx] = R92C_MAX_TX_PWR; - } - - htpow = rom->ht40_1s_tx_pwr[chain][group]; - if (sc->ntxchains > 1) { - /* Apply reduction for 2 spatial streams. */ - diff = rom->ht40_2s_tx_pwr_diff[group]; - diff = (diff >> (chain * 4)) & 0xf; - htpow = (htpow > diff) ? htpow - diff : 0; - } - - /* Compute per-OFDM rate Tx power. */ - diff = rom->ofdm_tx_pwr_diff[group]; - diff = (diff >> (chain * 4)) & 0xf; - ofdmpow = htpow + diff; /* HT->OFDM correction. */ - for (ridx = URTWN_RIDX_OFDM6; ridx <= URTWN_RIDX_OFDM54; ridx++) { - power[ridx] += ofdmpow; - if (power[ridx] > R92C_MAX_TX_PWR) - power[ridx] = R92C_MAX_TX_PWR; - } - - /* Compute per-MCS Tx power. */ - if (extc == NULL) { - diff = rom->ht20_tx_pwr_diff[group]; - diff = (diff >> (chain * 4)) & 0xf; - htpow += diff; /* HT40->HT20 correction. */ - } - for (ridx = 12; ridx <= 27; ridx++) { - power[ridx] += htpow; - if (power[ridx] > R92C_MAX_TX_PWR) - power[ridx] = R92C_MAX_TX_PWR; - } -#ifdef USB_DEBUG - if (sc->sc_debug & URTWN_DEBUG_TXPWR) { - /* Dump per-rate Tx power values. */ - printf("Tx power for chain %d:\n", chain); - for (ridx = URTWN_RIDX_CCK1; ridx < URTWN_RIDX_COUNT; ridx++) - printf("Rate %d = %u\n", ridx, power[ridx]); - } -#endif -} - -static void -urtwn_r88e_get_txpower(struct urtwn_softc *sc, int chain, - struct ieee80211_channel *c, struct ieee80211_channel *extc, - uint16_t power[URTWN_RIDX_COUNT]) -{ - struct ieee80211com *ic = &sc->sc_ic; - struct r88e_rom *rom = &sc->rom.r88e_rom; - uint16_t cckpow, ofdmpow, bw20pow, htpow; - const struct urtwn_r88e_txpwr *base; - int ridx, chan, group; - - /* Determine channel group. */ - chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ - if (chan <= 2) - group = 0; - else if (chan <= 5) - group = 1; - else if (chan <= 8) - group = 2; - else if (chan <= 11) - group = 3; - else if (chan <= 13) - group = 4; - else - group = 5; - - /* Get original Tx power based on board type and RF chain. */ - base = &rtl8188eu_txagc[chain]; - - memset(power, 0, URTWN_RIDX_COUNT * sizeof(power[0])); - if (sc->regulatory == 0) { - for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) - power[ridx] = base->pwr[0][ridx]; - } - for (ridx = URTWN_RIDX_OFDM6; ridx < URTWN_RIDX_COUNT; ridx++) { - if (sc->regulatory == 3) - power[ridx] = base->pwr[0][ridx]; - else if (sc->regulatory == 1) { - if (extc == NULL) - power[ridx] = base->pwr[group][ridx]; - } else if (sc->regulatory != 2) - power[ridx] = base->pwr[0][ridx]; - } - - /* Compute per-CCK rate Tx power. */ - cckpow = rom->cck_tx_pwr[group]; - for (ridx = URTWN_RIDX_CCK1; ridx <= URTWN_RIDX_CCK11; ridx++) { - power[ridx] += cckpow; - if (power[ridx] > R92C_MAX_TX_PWR) - power[ridx] = R92C_MAX_TX_PWR; - } - - htpow = rom->ht40_tx_pwr[group]; - - /* Compute per-OFDM rate Tx power. */ - ofdmpow = htpow + sc->ofdm_tx_pwr_diff; - for (ridx = URTWN_RIDX_OFDM6; ridx <= URTWN_RIDX_OFDM54; ridx++) { - power[ridx] += ofdmpow; - if (power[ridx] > R92C_MAX_TX_PWR) - power[ridx] = R92C_MAX_TX_PWR; - } - - bw20pow = htpow + sc->bw20_tx_pwr_diff; - for (ridx = 12; ridx <= 27; ridx++) { - power[ridx] += bw20pow; - if (power[ridx] > R92C_MAX_TX_PWR) - power[ridx] = R92C_MAX_TX_PWR; - } -} - -static void -urtwn_set_txpower(struct urtwn_softc *sc, struct ieee80211_channel *c, - struct ieee80211_channel *extc) -{ - uint16_t power[URTWN_RIDX_COUNT]; - int i; - - for (i = 0; i < sc->ntxchains; i++) { - /* Compute per-rate Tx power values. */ - if (sc->chip & URTWN_CHIP_88E) - urtwn_r88e_get_txpower(sc, i, c, extc, power); - else - urtwn_get_txpower(sc, i, c, extc, power); - /* Write per-rate Tx power values to hardware. */ - urtwn_write_txpower(sc, i, power); - } -} - -static void -urtwn_set_rx_bssid_all(struct urtwn_softc *sc, int enable) -{ - uint32_t reg; - - reg = urtwn_read_4(sc, R92C_RCR); - if (enable) - reg &= ~R92C_RCR_CBSSID_BCN; - else - reg |= R92C_RCR_CBSSID_BCN; - urtwn_write_4(sc, R92C_RCR, reg); -} - -static void -urtwn_set_gain(struct urtwn_softc *sc, uint8_t gain) -{ - uint32_t reg; - - reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0)); - reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, gain); - urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg); - - if (!(sc->chip & URTWN_CHIP_88E)) { - reg = urtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1)); - reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, gain); - urtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg); - } -} - -static void -urtwn_scan_start(struct ieee80211com *ic) -{ - struct urtwn_softc *sc = ic->ic_softc; - - URTWN_LOCK(sc); - /* Receive beacons / probe responses from any BSSID. */ - if (ic->ic_opmode != IEEE80211_M_IBSS && - ic->ic_opmode != IEEE80211_M_HOSTAP) - urtwn_set_rx_bssid_all(sc, 1); - - /* Set gain for scanning. */ - urtwn_set_gain(sc, 0x20); - URTWN_UNLOCK(sc); -} - -static void -urtwn_scan_end(struct ieee80211com *ic) -{ - struct urtwn_softc *sc = ic->ic_softc; - - URTWN_LOCK(sc); - /* Restore limitations. */ - if (ic->ic_promisc == 0 && - ic->ic_opmode != IEEE80211_M_IBSS && - ic->ic_opmode != IEEE80211_M_HOSTAP) - urtwn_set_rx_bssid_all(sc, 0); - - /* Set gain under link. */ - urtwn_set_gain(sc, 0x32); - URTWN_UNLOCK(sc); -} - -static void -urtwn_getradiocaps(struct ieee80211com *ic, - int maxchans, int *nchans, struct ieee80211_channel chans[]) -{ - uint8_t bands[IEEE80211_MODE_BYTES]; - - memset(bands, 0, sizeof(bands)); - setbit(bands, IEEE80211_MODE_11B); - setbit(bands, IEEE80211_MODE_11G); - if (urtwn_enable_11n) - setbit(bands, IEEE80211_MODE_11NG); - ieee80211_add_channel_list_2ghz(chans, maxchans, nchans, - urtwn_chan_2ghz, nitems(urtwn_chan_2ghz), bands, 0); -} - -static void -urtwn_set_channel(struct ieee80211com *ic) -{ - struct urtwn_softc *sc = ic->ic_softc; - struct ieee80211_channel *c = ic->ic_curchan; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - - URTWN_LOCK(sc); - if (vap->iv_state == IEEE80211_S_SCAN) { - /* Make link LED blink during scan. */ - urtwn_set_led(sc, URTWN_LED_LINK, !sc->ledlink); - } - urtwn_set_chan(sc, c, NULL); - sc->sc_rxtap.wr_chan_freq = htole16(c->ic_freq); - sc->sc_rxtap.wr_chan_flags = htole16(c->ic_flags); - sc->sc_txtap.wt_chan_freq = htole16(c->ic_freq); - sc->sc_txtap.wt_chan_flags = htole16(c->ic_flags); - URTWN_UNLOCK(sc); -} - -static int -urtwn_wme_update(struct ieee80211com *ic) -{ - const struct wmeParams *wmep = - ic->ic_wme.wme_chanParams.cap_wmeParams; - struct urtwn_softc *sc = ic->ic_softc; - uint8_t aifs, acm, slottime; - int ac; - - acm = 0; - slottime = IEEE80211_GET_SLOTTIME(ic); - - URTWN_LOCK(sc); - for (ac = WME_AC_BE; ac < WME_NUM_AC; ac++) { - /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */ - aifs = wmep[ac].wmep_aifsn * slottime + IEEE80211_DUR_SIFS; - urtwn_write_4(sc, wme2queue[ac].reg, - SM(R92C_EDCA_PARAM_TXOP, wmep[ac].wmep_txopLimit) | - SM(R92C_EDCA_PARAM_ECWMIN, wmep[ac].wmep_logcwmin) | - SM(R92C_EDCA_PARAM_ECWMAX, wmep[ac].wmep_logcwmax) | - SM(R92C_EDCA_PARAM_AIFS, aifs)); - if (ac != WME_AC_BE) - acm |= wmep[ac].wmep_acm << ac; - } - - if (acm != 0) - acm |= R92C_ACMHWCTRL_EN; - urtwn_write_1(sc, R92C_ACMHWCTRL, - (urtwn_read_1(sc, R92C_ACMHWCTRL) & ~R92C_ACMHWCTRL_ACM_MASK) | - acm); - - URTWN_UNLOCK(sc); - - return 0; -} - -static void -urtwn_update_slot(struct ieee80211com *ic) -{ - urtwn_cmd_sleepable(ic->ic_softc, NULL, 0, urtwn_update_slot_cb); -} - -static void -urtwn_update_slot_cb(struct urtwn_softc *sc, union sec_param *data) -{ - struct ieee80211com *ic = &sc->sc_ic; - uint8_t slottime; - - slottime = IEEE80211_GET_SLOTTIME(ic); - - URTWN_DPRINTF(sc, URTWN_DEBUG_ANY, "%s: setting slot time to %uus\n", - __func__, slottime); - - urtwn_write_1(sc, R92C_SLOT, slottime); - urtwn_update_aifs(sc, slottime); -} - -static void -urtwn_update_aifs(struct urtwn_softc *sc, uint8_t slottime) -{ - const struct wmeParams *wmep = - sc->sc_ic.ic_wme.wme_chanParams.cap_wmeParams; - uint8_t aifs, ac; - - for (ac = WME_AC_BE; ac < WME_NUM_AC; ac++) { - /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */ - aifs = wmep[ac].wmep_aifsn * slottime + IEEE80211_DUR_SIFS; - urtwn_write_1(sc, wme2queue[ac].reg, aifs); - } -} - -static uint8_t -urtwn_get_multi_pos(const uint8_t maddr[]) -{ - uint64_t mask = 0x00004d101df481b4; - uint8_t pos = 0x27; /* initial value */ - int i, j; - - for (i = 0; i < IEEE80211_ADDR_LEN; i++) - for (j = (i == 0) ? 1 : 0; j < 8; j++) - if ((maddr[i] >> j) & 1) - pos ^= (mask >> (i * 8 + j - 1)); - - pos &= 0x3f; - - return (pos); -} - -static void -urtwn_set_multi(struct urtwn_softc *sc) -{ - struct ieee80211com *ic = &sc->sc_ic; - uint32_t mfilt[2]; - - URTWN_ASSERT_LOCKED(sc); - - /* general structure was copied from ath(4). */ - if (ic->ic_allmulti == 0) { - struct ieee80211vap *vap; - struct ifnet *ifp; - struct ifmultiaddr *ifma; - - /* - * Merge multicast addresses to form the hardware filter. - */ - mfilt[0] = mfilt[1] = 0; - TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { - ifp = vap->iv_ifp; - if_maddr_rlock(ifp); - TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { - caddr_t dl; - uint8_t pos; - - dl = LLADDR((struct sockaddr_dl *) - ifma->ifma_addr); - pos = urtwn_get_multi_pos(dl); - - mfilt[pos / 32] |= (1 << (pos % 32)); - } - if_maddr_runlock(ifp); - } - } else - mfilt[0] = mfilt[1] = ~0; - - - urtwn_write_4(sc, R92C_MAR + 0, mfilt[0]); - urtwn_write_4(sc, R92C_MAR + 4, mfilt[1]); - - URTWN_DPRINTF(sc, URTWN_DEBUG_STATE, "%s: MC filter %08x:%08x\n", - __func__, mfilt[0], mfilt[1]); -} - -static void -urtwn_set_promisc(struct urtwn_softc *sc) -{ - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - uint32_t rcr, mask1, mask2; - - URTWN_ASSERT_LOCKED(sc); - - if (vap->iv_opmode == IEEE80211_M_MONITOR) - return; - - mask1 = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP; - mask2 = R92C_RCR_APM; - - if (vap->iv_state == IEEE80211_S_RUN) { - switch (vap->iv_opmode) { - case IEEE80211_M_STA: - mask2 |= R92C_RCR_CBSSID_BCN; - /* FALLTHROUGH */ - case IEEE80211_M_IBSS: - mask2 |= R92C_RCR_CBSSID_DATA; - break; - case IEEE80211_M_HOSTAP: - break; - default: - device_printf(sc->sc_dev, "%s: undefined opmode %d\n", - __func__, vap->iv_opmode); - return; - } - } - - rcr = urtwn_read_4(sc, R92C_RCR); - if (ic->ic_promisc == 0) - rcr = (rcr & ~mask1) | mask2; - else - rcr = (rcr & ~mask2) | mask1; - urtwn_write_4(sc, R92C_RCR, rcr); -} - -static void -urtwn_update_promisc(struct ieee80211com *ic) -{ - struct urtwn_softc *sc = ic->ic_softc; - - URTWN_LOCK(sc); - if (sc->sc_flags & URTWN_RUNNING) - urtwn_set_promisc(sc); - URTWN_UNLOCK(sc); -} - -static void -urtwn_update_mcast(struct ieee80211com *ic) -{ - struct urtwn_softc *sc = ic->ic_softc; - - URTWN_LOCK(sc); - if (sc->sc_flags & URTWN_RUNNING) - urtwn_set_multi(sc); - URTWN_UNLOCK(sc); -} - -static struct ieee80211_node * -urtwn_node_alloc(struct ieee80211vap *vap, - const uint8_t mac[IEEE80211_ADDR_LEN]) -{ - struct urtwn_node *un; - - un = malloc(sizeof (struct urtwn_node), M_80211_NODE, - M_NOWAIT | M_ZERO); - - if (un == NULL) - return NULL; - - un->id = URTWN_MACID_UNDEFINED; - - return &un->ni; -} - -static void -urtwn_newassoc(struct ieee80211_node *ni, int isnew) -{ - struct urtwn_softc *sc = ni->ni_ic->ic_softc; - struct urtwn_node *un = URTWN_NODE(ni); - uint8_t id; - - /* Only do this bit for R88E chips */ - if (! (sc->chip & URTWN_CHIP_88E)) - return; - - if (!isnew) - return; - - URTWN_NT_LOCK(sc); - for (id = 0; id <= URTWN_MACID_MAX(sc); id++) { - if (id != URTWN_MACID_BC && sc->node_list[id] == NULL) { - un->id = id; - sc->node_list[id] = ni; - break; - } - } - URTWN_NT_UNLOCK(sc); - - if (id > URTWN_MACID_MAX(sc)) { - device_printf(sc->sc_dev, "%s: node table is full\n", - __func__); - } -} - -static void -urtwn_node_free(struct ieee80211_node *ni) -{ - struct urtwn_softc *sc = ni->ni_ic->ic_softc; - struct urtwn_node *un = URTWN_NODE(ni); - - URTWN_NT_LOCK(sc); - if (un->id != URTWN_MACID_UNDEFINED) - sc->node_list[un->id] = NULL; - URTWN_NT_UNLOCK(sc); - - sc->sc_node_free(ni); -} - -static void -urtwn_set_chan(struct urtwn_softc *sc, struct ieee80211_channel *c, - struct ieee80211_channel *extc) -{ - struct ieee80211com *ic = &sc->sc_ic; - uint32_t reg; - u_int chan; - int i; - - chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */ - if (chan == 0 || chan == IEEE80211_CHAN_ANY) { - device_printf(sc->sc_dev, - "%s: invalid channel %x\n", __func__, chan); - return; - } - - /* Set Tx power for this new channel. */ - urtwn_set_txpower(sc, c, extc); - - for (i = 0; i < sc->nrxchains; i++) { - urtwn_rf_write(sc, i, R92C_RF_CHNLBW, - RW(sc->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan)); - } -#ifndef IEEE80211_NO_HT - if (extc != NULL) { - /* Is secondary channel below or above primary? */ - int prichlo = c->ic_freq < extc->ic_freq; - - urtwn_write_1(sc, R92C_BWOPMODE, - urtwn_read_1(sc, R92C_BWOPMODE) & ~R92C_BWOPMODE_20MHZ); - - reg = urtwn_read_1(sc, R92C_RRSR + 2); - reg = (reg & ~0x6f) | (prichlo ? 1 : 2) << 5; - urtwn_write_1(sc, R92C_RRSR + 2, reg); - - urtwn_bb_write(sc, R92C_FPGA0_RFMOD, - urtwn_bb_read(sc, R92C_FPGA0_RFMOD) | R92C_RFMOD_40MHZ); - urtwn_bb_write(sc, R92C_FPGA1_RFMOD, - urtwn_bb_read(sc, R92C_FPGA1_RFMOD) | R92C_RFMOD_40MHZ); - - /* Set CCK side band. */ - reg = urtwn_bb_read(sc, R92C_CCK0_SYSTEM); - reg = (reg & ~0x00000010) | (prichlo ? 0 : 1) << 4; - urtwn_bb_write(sc, R92C_CCK0_SYSTEM, reg); - - reg = urtwn_bb_read(sc, R92C_OFDM1_LSTF); - reg = (reg & ~0x00000c00) | (prichlo ? 1 : 2) << 10; - urtwn_bb_write(sc, R92C_OFDM1_LSTF, reg); - - urtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2, - urtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) & - ~R92C_FPGA0_ANAPARAM2_CBW20); - - reg = urtwn_bb_read(sc, 0x818); - reg = (reg & ~0x0c000000) | (prichlo ? 2 : 1) << 26; - urtwn_bb_write(sc, 0x818, reg); - - /* Select 40MHz bandwidth. */ - urtwn_rf_write(sc, 0, R92C_RF_CHNLBW, - (sc->rf_chnlbw[0] & ~0xfff) | chan); - } else -#endif - { - urtwn_write_1(sc, R92C_BWOPMODE, - urtwn_read_1(sc, R92C_BWOPMODE) | R92C_BWOPMODE_20MHZ); - - urtwn_bb_write(sc, R92C_FPGA0_RFMOD, - urtwn_bb_read(sc, R92C_FPGA0_RFMOD) & ~R92C_RFMOD_40MHZ); - urtwn_bb_write(sc, R92C_FPGA1_RFMOD, - urtwn_bb_read(sc, R92C_FPGA1_RFMOD) & ~R92C_RFMOD_40MHZ); - - if (!(sc->chip & URTWN_CHIP_88E)) { - urtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2, - urtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) | - R92C_FPGA0_ANAPARAM2_CBW20); - } - - /* Select 20MHz bandwidth. */ - urtwn_rf_write(sc, 0, R92C_RF_CHNLBW, - (sc->rf_chnlbw[0] & ~0xfff) | chan | - ((sc->chip & URTWN_CHIP_88E) ? R88E_RF_CHNLBW_BW20 : - R92C_RF_CHNLBW_BW20)); - } -} - -static void -urtwn_iq_calib(struct urtwn_softc *sc) -{ - /* TODO */ -} - -static void -urtwn_lc_calib(struct urtwn_softc *sc) -{ - uint32_t rf_ac[2]; - uint8_t txmode; - int i; - - txmode = urtwn_read_1(sc, R92C_OFDM1_LSTF + 3); - if ((txmode & 0x70) != 0) { - /* Disable all continuous Tx. */ - urtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70); - - /* Set RF mode to standby mode. */ - for (i = 0; i < sc->nrxchains; i++) { - rf_ac[i] = urtwn_rf_read(sc, i, R92C_RF_AC); - urtwn_rf_write(sc, i, R92C_RF_AC, - RW(rf_ac[i], R92C_RF_AC_MODE, - R92C_RF_AC_MODE_STANDBY)); - } - } else { - /* Block all Tx queues. */ - urtwn_write_1(sc, R92C_TXPAUSE, R92C_TX_QUEUE_ALL); - } - /* Start calibration. */ - urtwn_rf_write(sc, 0, R92C_RF_CHNLBW, - urtwn_rf_read(sc, 0, R92C_RF_CHNLBW) | R92C_RF_CHNLBW_LCSTART); - - /* Give calibration the time to complete. */ - usb_pause_mtx(&sc->sc_mtx, hz / 10); /* 100ms */ - - /* Restore configuration. */ - if ((txmode & 0x70) != 0) { - /* Restore Tx mode. */ - urtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode); - /* Restore RF mode. */ - for (i = 0; i < sc->nrxchains; i++) - urtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]); - } else { - /* Unblock all Tx queues. */ - urtwn_write_1(sc, R92C_TXPAUSE, 0x00); - } -} - -static void -urtwn_temp_calib(struct urtwn_softc *sc) -{ - uint8_t temp; - - URTWN_ASSERT_LOCKED(sc); - - if (!(sc->sc_flags & URTWN_TEMP_MEASURED)) { - /* Start measuring temperature. */ - URTWN_DPRINTF(sc, URTWN_DEBUG_TEMP, - "%s: start measuring temperature\n", __func__); - if (sc->chip & URTWN_CHIP_88E) { - urtwn_rf_write(sc, 0, R88E_RF_T_METER, - R88E_RF_T_METER_START); - } else { - urtwn_rf_write(sc, 0, R92C_RF_T_METER, - R92C_RF_T_METER_START); - } - sc->sc_flags |= URTWN_TEMP_MEASURED; - return; - } - sc->sc_flags &= ~URTWN_TEMP_MEASURED; - - /* Read measured temperature. */ - if (sc->chip & URTWN_CHIP_88E) { - temp = MS(urtwn_rf_read(sc, 0, R88E_RF_T_METER), - R88E_RF_T_METER_VAL); - } else { - temp = MS(urtwn_rf_read(sc, 0, R92C_RF_T_METER), - R92C_RF_T_METER_VAL); - } - if (temp == 0) { /* Read failed, skip. */ - URTWN_DPRINTF(sc, URTWN_DEBUG_TEMP, - "%s: temperature read failed, skipping\n", __func__); - return; - } - - URTWN_DPRINTF(sc, URTWN_DEBUG_TEMP, - "%s: temperature: previous %u, current %u\n", - __func__, sc->thcal_lctemp, temp); - - /* - * Redo LC calibration if temperature changed significantly since - * last calibration. - */ - if (sc->thcal_lctemp == 0) { - /* First LC calibration is performed in urtwn_init(). */ - sc->thcal_lctemp = temp; - } else if (abs(temp - sc->thcal_lctemp) > 1) { - URTWN_DPRINTF(sc, URTWN_DEBUG_TEMP, - "%s: LC calib triggered by temp: %u -> %u\n", - __func__, sc->thcal_lctemp, temp); - urtwn_lc_calib(sc); - /* Record temperature of last LC calibration. */ - sc->thcal_lctemp = temp; - } -} - -static void -urtwn_setup_static_keys(struct urtwn_softc *sc, struct urtwn_vap *uvp) -{ - int i; - - for (i = 0; i < IEEE80211_WEP_NKID; i++) { - const struct ieee80211_key *k = uvp->keys[i]; - if (k != NULL) { - urtwn_cmd_sleepable(sc, k, sizeof(*k), - urtwn_key_set_cb); - } - } -} - -static int -urtwn_init(struct urtwn_softc *sc) -{ - struct ieee80211com *ic = &sc->sc_ic; - struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - uint8_t macaddr[IEEE80211_ADDR_LEN]; - uint32_t reg; - usb_error_t usb_err = USB_ERR_NORMAL_COMPLETION; - int error; - - URTWN_LOCK(sc); - if (sc->sc_flags & URTWN_RUNNING) { - URTWN_UNLOCK(sc); - return (0); - } - - /* Init firmware commands ring. */ - sc->fwcur = 0; - - /* Allocate Tx/Rx buffers. */ - error = urtwn_alloc_rx_list(sc); - if (error != 0) - goto fail; - - error = urtwn_alloc_tx_list(sc); - if (error != 0) - goto fail; - - /* Power on adapter. */ - error = urtwn_power_on(sc); - if (error != 0) - goto fail; - - /* Initialize DMA. */ - error = urtwn_dma_init(sc); - if (error != 0) - goto fail; - - /* Set info size in Rx descriptors (in 64-bit words). */ - urtwn_write_1(sc, R92C_RX_DRVINFO_SZ, 4); - - /* Init interrupts. */ - if (sc->chip & URTWN_CHIP_88E) { - usb_err = urtwn_write_4(sc, R88E_HISR, 0xffffffff); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - goto fail; - usb_err = urtwn_write_4(sc, R88E_HIMR, R88E_HIMR_CPWM | R88E_HIMR_CPWM2 | - R88E_HIMR_TBDER | R88E_HIMR_PSTIMEOUT); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - goto fail; - usb_err = urtwn_write_4(sc, R88E_HIMRE, R88E_HIMRE_RXFOVW | - R88E_HIMRE_TXFOVW | R88E_HIMRE_RXERR | R88E_HIMRE_TXERR); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - goto fail; - usb_err = urtwn_write_1(sc, R92C_USB_SPECIAL_OPTION, - urtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) | - R92C_USB_SPECIAL_OPTION_INT_BULK_SEL); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - goto fail; - } else { - usb_err = urtwn_write_4(sc, R92C_HISR, 0xffffffff); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - goto fail; - usb_err = urtwn_write_4(sc, R92C_HIMR, 0xffffffff); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - goto fail; - } - - /* Set MAC address. */ - IEEE80211_ADDR_COPY(macaddr, vap ? vap->iv_myaddr : ic->ic_macaddr); - usb_err = urtwn_write_region_1(sc, R92C_MACID, macaddr, IEEE80211_ADDR_LEN); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - goto fail; - - /* Set initial network type. */ - urtwn_set_mode(sc, R92C_MSR_INFRA); - - /* Initialize Rx filter. */ - urtwn_rxfilter_init(sc); - - /* Set response rate. */ - reg = urtwn_read_4(sc, R92C_RRSR); - reg = RW(reg, R92C_RRSR_RATE_BITMAP, R92C_RRSR_RATE_CCK_ONLY_1M); - urtwn_write_4(sc, R92C_RRSR, reg); - - /* Set short/long retry limits. */ - urtwn_write_2(sc, R92C_RL, - SM(R92C_RL_SRL, 0x30) | SM(R92C_RL_LRL, 0x30)); - - /* Initialize EDCA parameters. */ - urtwn_edca_init(sc); - - /* Setup rate fallback. */ - if (!(sc->chip & URTWN_CHIP_88E)) { - urtwn_write_4(sc, R92C_DARFRC + 0, 0x00000000); - urtwn_write_4(sc, R92C_DARFRC + 4, 0x10080404); - urtwn_write_4(sc, R92C_RARFRC + 0, 0x04030201); - urtwn_write_4(sc, R92C_RARFRC + 4, 0x08070605); - } - - urtwn_write_1(sc, R92C_FWHW_TXQ_CTRL, - urtwn_read_1(sc, R92C_FWHW_TXQ_CTRL) | - R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW); - /* Set ACK timeout. */ - urtwn_write_1(sc, R92C_ACKTO, 0x40); - - /* Setup USB aggregation. */ - reg = urtwn_read_4(sc, R92C_TDECTRL); - reg = RW(reg, R92C_TDECTRL_BLK_DESC_NUM, 6); - urtwn_write_4(sc, R92C_TDECTRL, reg); - urtwn_write_1(sc, R92C_TRXDMA_CTRL, - urtwn_read_1(sc, R92C_TRXDMA_CTRL) | - R92C_TRXDMA_CTRL_RXDMA_AGG_EN); - urtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH, 48); - if (sc->chip & URTWN_CHIP_88E) - urtwn_write_1(sc, R92C_RXDMA_AGG_PG_TH + 1, 4); - else { - urtwn_write_1(sc, R92C_USB_DMA_AGG_TO, 4); - urtwn_write_1(sc, R92C_USB_SPECIAL_OPTION, - urtwn_read_1(sc, R92C_USB_SPECIAL_OPTION) | - R92C_USB_SPECIAL_OPTION_AGG_EN); - urtwn_write_1(sc, R92C_USB_AGG_TH, 8); - urtwn_write_1(sc, R92C_USB_AGG_TO, 6); - } - - /* Initialize beacon parameters. */ - urtwn_write_2(sc, R92C_BCN_CTRL, 0x1010); - urtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404); - urtwn_write_1(sc, R92C_DRVERLYINT, 0x05); - urtwn_write_1(sc, R92C_BCNDMATIM, 0x02); - urtwn_write_2(sc, R92C_BCNTCFG, 0x660f); - - if (!(sc->chip & URTWN_CHIP_88E)) { - /* Setup AMPDU aggregation. */ - urtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */ - urtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16); - urtwn_write_2(sc, R92C_MAX_AGGR_NUM, 0x0708); - - urtwn_write_1(sc, R92C_BCN_MAX_ERR, 0xff); - } - -#ifndef URTWN_WITHOUT_UCODE - /* Load 8051 microcode. */ - error = urtwn_load_firmware(sc); - if (error == 0) - sc->sc_flags |= URTWN_FW_LOADED; -#endif - - /* Initialize MAC/BB/RF blocks. */ - error = urtwn_mac_init(sc); - if (error != 0) { - device_printf(sc->sc_dev, - "%s: error while initializing MAC block\n", __func__); - goto fail; - } - urtwn_bb_init(sc); - urtwn_rf_init(sc); - - /* Reinitialize Rx filter (D3845 is not committed yet). */ - urtwn_rxfilter_init(sc); - - if (sc->chip & URTWN_CHIP_88E) { - urtwn_write_2(sc, R92C_CR, - urtwn_read_2(sc, R92C_CR) | R92C_CR_MACTXEN | - R92C_CR_MACRXEN); - } - - /* Turn CCK and OFDM blocks on. */ - reg = urtwn_bb_read(sc, R92C_FPGA0_RFMOD); - reg |= R92C_RFMOD_CCK_EN; - usb_err = urtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - goto fail; - reg = urtwn_bb_read(sc, R92C_FPGA0_RFMOD); - reg |= R92C_RFMOD_OFDM_EN; - usb_err = urtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg); - if (usb_err != USB_ERR_NORMAL_COMPLETION) - goto fail; - - /* Clear per-station keys table. */ - urtwn_cam_init(sc); - - /* Enable decryption / encryption. */ - urtwn_write_2(sc, R92C_SECCFG, - R92C_SECCFG_TXUCKEY_DEF | R92C_SECCFG_RXUCKEY_DEF | - R92C_SECCFG_TXENC_ENA | R92C_SECCFG_RXDEC_ENA | - R92C_SECCFG_TXBCKEY_DEF | R92C_SECCFG_RXBCKEY_DEF); - - /* Enable hardware sequence numbering. */ - urtwn_write_1(sc, R92C_HWSEQ_CTRL, R92C_TX_QUEUE_ALL); - - /* Enable per-packet TX report. */ - if (sc->chip & URTWN_CHIP_88E) { - urtwn_write_1(sc, R88E_TX_RPT_CTRL, - urtwn_read_1(sc, R88E_TX_RPT_CTRL) | R88E_TX_RPT1_ENA); - } - - /* Perform LO and IQ calibrations. */ - urtwn_iq_calib(sc); - /* Perform LC calibration. */ - urtwn_lc_calib(sc); - - /* Fix USB interference issue. */ - if (!(sc->chip & URTWN_CHIP_88E)) { - urtwn_write_1(sc, 0xfe40, 0xe0); - urtwn_write_1(sc, 0xfe41, 0x8d); - urtwn_write_1(sc, 0xfe42, 0x80); - - urtwn_pa_bias_init(sc); - } - - /* Initialize GPIO setting. */ - urtwn_write_1(sc, R92C_GPIO_MUXCFG, - urtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_ENBT); - - /* Fix for lower temperature. */ - if (!(sc->chip & URTWN_CHIP_88E)) - urtwn_write_1(sc, 0x15, 0xe9); - - usbd_transfer_start(sc->sc_xfer[URTWN_BULK_RX]); - - sc->sc_flags |= URTWN_RUNNING; - - /* - * Install static keys (if any). - * Must be called after urtwn_cam_init(). - */ - if (vap != NULL) - urtwn_setup_static_keys(sc, URTWN_VAP(vap)); - - callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); -fail: - if (usb_err != USB_ERR_NORMAL_COMPLETION) - error = EIO; - - URTWN_UNLOCK(sc); - - return (error); -} - -static void -urtwn_stop(struct urtwn_softc *sc) -{ - - URTWN_LOCK(sc); - if (!(sc->sc_flags & URTWN_RUNNING)) { - URTWN_UNLOCK(sc); - return; - } - - sc->sc_flags &= ~(URTWN_RUNNING | URTWN_FW_LOADED | - URTWN_TEMP_MEASURED); - sc->thcal_lctemp = 0; - callout_stop(&sc->sc_watchdog_ch); - - urtwn_abort_xfers(sc); - urtwn_drain_mbufq(sc); - urtwn_free_tx_list(sc); - urtwn_free_rx_list(sc); - urtwn_power_off(sc); - URTWN_UNLOCK(sc); -} - -static void -urtwn_abort_xfers(struct urtwn_softc *sc) -{ - int i; - - URTWN_ASSERT_LOCKED(sc); - - /* abort any pending transfers */ - for (i = 0; i < URTWN_N_TRANSFER; i++) - usbd_transfer_stop(sc->sc_xfer[i]); -} - -static int -urtwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, - const struct ieee80211_bpf_params *params) -{ - struct ieee80211com *ic = ni->ni_ic; - struct urtwn_softc *sc = ic->ic_softc; - struct urtwn_data *bf; - int error; - - URTWN_DPRINTF(sc, URTWN_DEBUG_XMIT, "%s: called; m=%p\n", - __func__, - m); - - /* prevent management frames from being sent if we're not ready */ - URTWN_LOCK(sc); - if (!(sc->sc_flags & URTWN_RUNNING)) { - error = ENETDOWN; - goto end; - } - - bf = urtwn_getbuf(sc); - if (bf == NULL) { - error = ENOBUFS; - goto end; - } - - if (params == NULL) { - /* - * Legacy path; interpret frame contents to decide - * precisely how to send the frame. - */ - error = urtwn_tx_data(sc, ni, m, bf); - } else { - /* - * Caller supplied explicit parameters to use in - * sending the frame. - */ - error = urtwn_tx_raw(sc, ni, m, bf, params); - } - if (error != 0) { - STAILQ_INSERT_HEAD(&sc->sc_tx_inactive, bf, next); - goto end; - } - - sc->sc_txtimer = 5; - callout_reset(&sc->sc_watchdog_ch, hz, urtwn_watchdog, sc); - -end: - if (error != 0) { - if (m->m_flags & M_TXCB) - ieee80211_process_callback(ni, m, 1); - m_freem(m); - } - - URTWN_UNLOCK(sc); - - return (error); -} - -static void -urtwn_ms_delay(struct urtwn_softc *sc) -{ - usb_pause_mtx(&sc->sc_mtx, hz / 1000); -} - -static device_method_t urtwn_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, urtwn_match), - DEVMETHOD(device_attach, urtwn_attach), - DEVMETHOD(device_detach, urtwn_detach), - - DEVMETHOD_END -}; - -static driver_t urtwn_driver = { - "urtwn", - urtwn_methods, - sizeof(struct urtwn_softc) -}; - -static devclass_t urtwn_devclass; - -DRIVER_MODULE(urtwn, uhub, urtwn_driver, urtwn_devclass, NULL, NULL); -MODULE_DEPEND(urtwn, usb, 1, 1, 1); -MODULE_DEPEND(urtwn, wlan, 1, 1, 1); -#ifndef URTWN_WITHOUT_UCODE -MODULE_DEPEND(urtwn, firmware, 1, 1, 1); -#endif -MODULE_VERSION(urtwn, 1); -USB_PNP_HOST_INFO(urtwn_devs); diff --git a/sys/dev/urtwn/if_urtwnreg.h b/sys/dev/urtwn/if_urtwnreg.h deleted file mode 100644 index 1846a967ca4c..000000000000 --- a/sys/dev/urtwn/if_urtwnreg.h +++ /dev/null @@ -1,2183 +0,0 @@ -/*- - * Copyright (c) 2010 Damien Bergamini - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ - * $FreeBSD$ - */ - -#define URTWN_CONFIG_INDEX 0 -#define URTWN_IFACE_INDEX 0 - -#define URTWN_NOISE_FLOOR -95 - -#define R92C_MAX_CHAINS 2 - -/* Maximum number of output pipes is 3. */ -#define R92C_MAX_EPOUT 3 - -#define R92C_MAX_TX_PWR 0x3f - -#define R92C_PUBQ_NPAGES 231 -#define R92C_TXPKTBUF_COUNT 256 -#define R92C_TX_PAGE_COUNT 248 -#define R92C_TX_PAGE_BOUNDARY (R92C_TX_PAGE_COUNT + 1) -#define R88E_TXPKTBUF_COUNT 177 -#define R88E_TX_PAGE_COUNT 169 -#define R88E_TX_PAGE_BOUNDARY (R88E_TX_PAGE_COUNT + 1) - -#define R92C_H2C_NBOX 4 - -/* USB Requests. */ -#define R92C_REQ_REGS 0x05 - -/* - * MAC registers. - */ -/* System Configuration. */ -#define R92C_SYS_ISO_CTRL 0x000 -#define R92C_SYS_FUNC_EN 0x002 -#define R92C_APS_FSMCO 0x004 -#define R92C_SYS_CLKR 0x008 -#define R92C_AFE_MISC 0x010 -#define R92C_SPS0_CTRL 0x011 -#define R92C_SPS_OCP_CFG 0x018 -#define R92C_RSV_CTRL 0x01c -#define R92C_RF_CTRL 0x01f -#define R92C_LDOA15_CTRL 0x020 -#define R92C_LDOV12D_CTRL 0x021 -#define R92C_LDOHCI12_CTRL 0x022 -#define R92C_LPLDO_CTRL 0x023 -#define R92C_AFE_XTAL_CTRL 0x024 -#define R92C_AFE_PLL_CTRL 0x028 -#define R92C_EFUSE_CTRL 0x030 -#define R92C_EFUSE_TEST 0x034 -#define R92C_PWR_DATA 0x038 -#define R92C_CAL_TIMER 0x03c -#define R92C_ACLK_MON 0x03e -#define R92C_GPIO_MUXCFG 0x040 -#define R92C_GPIO_IO_SEL 0x042 -#define R92C_MAC_PINMUX_CFG 0x043 -#define R92C_GPIO_PIN_CTRL 0x044 -#define R92C_GPIO_IN 0x044 -#define R92C_GPIO_OUT 0x045 -#define R92C_GPIO_IOSEL 0x046 -#define R92C_GPIO_MOD 0x047 -#define R92C_GPIO_INTM 0x048 -#define R92C_LEDCFG0 0x04c -#define R92C_LEDCFG1 0x04d -#define R92C_LEDCFG2 0x04e -#define R92C_LEDCFG3 0x04f -#define R92C_FSIMR 0x050 -#define R92C_FSISR 0x054 -#define R92C_HSIMR 0x058 -#define R92C_HSISR 0x05c -#define R88E_BB_PAD_CTRL 0x064 -#define R92C_MCUFWDL 0x080 -#define R92C_HMEBOX_EXT(idx) (0x088 + (idx) * 2) -#define R88E_HIMR 0x0b0 -#define R88E_HISR 0x0b4 -#define R88E_HIMRE 0x0b8 -#define R88E_HISRE 0x0bc -#define R92C_EFUSE_ACCESS 0x0cf -#define R92C_BIST_SCAN 0x0d0 -#define R92C_BIST_RPT 0x0d4 -#define R92C_BIST_ROM_RPT 0x0d8 -#define R92C_USB_SIE_INTF 0x0e0 -#define R92C_PCIE_MIO_INTF 0x0e4 -#define R92C_PCIE_MIO_INTD 0x0e8 -#define R92C_HPON_FSM 0x0ec -#define R92C_SYS_CFG 0x0f0 -/* MAC General Configuration. */ -#define R92C_CR 0x100 -#define R92C_MSR 0x102 -#define R92C_PBP 0x104 -#define R92C_TRXDMA_CTRL 0x10c -#define R92C_TRXFF_BNDY 0x114 -#define R92C_TRXFF_STATUS 0x118 -#define R92C_RXFF_PTR 0x11c -#define R92C_HIMR 0x120 -#define R92C_HISR 0x124 -#define R92C_HIMRE 0x128 -#define R92C_HISRE 0x12c -#define R92C_CPWM 0x12f -#define R92C_FWIMR 0x130 -#define R92C_FWISR 0x134 -#define R92C_PKTBUF_DBG_CTRL 0x140 -#define R92C_PKTBUF_DBG_DATA_L 0x144 -#define R92C_PKTBUF_DBG_DATA_H 0x148 -#define R92C_TC0_CTRL(i) (0x150 + (i) * 4) -#define R92C_TCUNIT_BASE 0x164 -#define R92C_MBIST_START 0x174 -#define R92C_MBIST_DONE 0x178 -#define R92C_MBIST_FAIL 0x17c -#define R88E_32K_CTRL 0x194 -#define R92C_C2HEVT_MSG_NORMAL 0x1a0 -#define R92C_C2HEVT_MSG_TEST 0x1b8 -#define R92C_C2HEVT_CLEAR 0x1bf -#define R92C_MCUTST_1 0x1c0 -#define R92C_FMETHR 0x1c8 -#define R92C_HMETFR 0x1cc -#define R92C_HMEBOX(idx) (0x1d0 + (idx) * 4) -#define R92C_LLT_INIT 0x1e0 -#define R92C_BB_ACCESS_CTRL 0x1e8 -#define R92C_BB_ACCESS_DATA 0x1ec -#define R88E_HMEBOX_EXT(idx) (0x1f0 + (idx) * 4) -/* Tx DMA Configuration. */ -#define R92C_RQPN 0x200 -#define R92C_FIFOPAGE 0x204 -#define R92C_TDECTRL 0x208 -#define R92C_TXDMA_OFFSET_CHK 0x20c -#define R92C_TXDMA_STATUS 0x210 -#define R92C_RQPN_NPQ 0x214 -/* Rx DMA Configuration. */ -#define R92C_RXDMA_AGG_PG_TH 0x280 -#define R92C_RXPKT_NUM 0x284 -#define R92C_RXDMA_STATUS 0x288 -/* Protocol Configuration. */ -#define R92C_FWHW_TXQ_CTRL 0x420 -#define R92C_HWSEQ_CTRL 0x423 -#define R92C_TXPKTBUF_BCNQ_BDNY 0x424 -#define R92C_TXPKTBUF_MGQ_BDNY 0x425 -#define R92C_SPEC_SIFS 0x428 -#define R92C_RL 0x42a -#define R92C_DARFRC 0x430 -#define R92C_RARFRC 0x438 -#define R92C_RRSR 0x440 -#define R92C_ARFR(i) (0x444 + (i) * 4) -#define R92C_AGGLEN_LMT 0x458 -#define R92C_AMPDU_MIN_SPACE 0x45c -#define R92C_TXPKTBUF_WMAC_LBK_BF_HD 0x45d -#define R92C_FAST_EDCA_CTRL 0x460 -#define R92C_RD_RESP_PKT_TH 0x463 -#define R92C_INIRTS_RATE_SEL 0x480 -#define R92C_INIDATA_RATE_SEL(macid) (0x484 + (macid)) -#define R92C_MAX_AGGR_NUM 0x4ca -#define R88E_TX_RPT_CTRL 0x4ec -#define R88E_TX_RPT_MACID_MAX 0x4ed -#define R88E_TX_RPT_TIME 0x4f0 -/* EDCA Configuration. */ -#define R92C_EDCA_VO_PARAM 0x500 -#define R92C_EDCA_VI_PARAM 0x504 -#define R92C_EDCA_BE_PARAM 0x508 -#define R92C_EDCA_BK_PARAM 0x50c -#define R92C_BCNTCFG 0x510 -#define R92C_PIFS 0x512 -#define R92C_RDG_PIFS 0x513 -#define R92C_SIFS_CCK 0x514 -#define R92C_SIFS_OFDM 0x516 -#define R92C_AGGR_BREAK_TIME 0x51a -#define R92C_SLOT 0x51b -#define R92C_TX_PTCL_CTRL 0x520 -#define R92C_TXPAUSE 0x522 -#define R92C_DIS_TXREQ_CLR 0x523 -#define R92C_RD_CTRL 0x524 -#define R92C_TBTT_PROHIBIT 0x540 -#define R92C_RD_NAV_NXT 0x544 -#define R92C_NAV_PROT_LEN 0x546 -#define R92C_BCN_CTRL 0x550 -#define R92C_MBID_NUM 0x552 -#define R92C_DUAL_TSF_RST 0x553 -#define R92C_BCN_INTERVAL 0x554 -#define R92C_DRVERLYINT 0x558 -#define R92C_BCNDMATIM 0x559 -#define R92C_ATIMWND 0x55a -#define R92C_USTIME_TSF 0x55c -#define R92C_BCN_MAX_ERR 0x55d -#define R92C_RXTSF_OFFSET_CCK 0x55e -#define R92C_RXTSF_OFFSET_OFDM 0x55f -#define R92C_TSFTR 0x560 -#define R92C_INIT_TSFTR 0x564 -#define R92C_PSTIMER 0x580 -#define R92C_TIMER0 0x584 -#define R92C_TIMER1 0x588 -#define R92C_ACMHWCTRL 0x5c0 -#define R92C_ACMRSTCTRL 0x5c1 -#define R92C_ACMAVG 0x5c2 -#define R92C_VO_ADMTIME 0x5c4 -#define R92C_VI_ADMTIME 0x5c6 -#define R92C_BE_ADMTIME 0x5c8 -#define R92C_EDCA_RANDOM_GEN 0x5cc -#define R92C_SCH_TXCMD 0x5d0 -#define R88E_SCH_TXCMD 0x5f8 -/* WMAC Configuration. */ -#define R92C_APSD_CTRL 0x600 -#define R92C_BWOPMODE 0x603 -#define R92C_RCR 0x608 -#define R92C_RX_DRVINFO_SZ 0x60f -#define R92C_MACID 0x610 -#define R92C_BSSID 0x618 -#define R92C_MAR 0x620 -#define R92C_MAC_SPEC_SIFS 0x63a -#define R92C_R2T_SIFS 0x63c -#define R92C_T2T_SIFS 0x63e -#define R92C_ACKTO 0x640 -#define R92C_CAMCMD 0x670 -#define R92C_CAMWRITE 0x674 -#define R92C_CAMREAD 0x678 -#define R92C_CAMDBG 0x67c -#define R92C_SECCFG 0x680 -#define R92C_RXFLTMAP0 0x6a0 -#define R92C_RXFLTMAP1 0x6a2 -#define R92C_RXFLTMAP2 0x6a4 - -/* Bits for R92C_SYS_ISO_CTRL. */ -#define R92C_SYS_ISO_CTRL_MD2PP 0x0001 -#define R92C_SYS_ISO_CTRL_UA2USB 0x0002 -#define R92C_SYS_ISO_CTRL_UD2CORE 0x0004 -#define R92C_SYS_ISO_CTRL_PA2PCIE 0x0008 -#define R92C_SYS_ISO_CTRL_PD2CORE 0x0010 -#define R92C_SYS_ISO_CTRL_IP2MAC 0x0020 -#define R92C_SYS_ISO_CTRL_DIOP 0x0040 -#define R92C_SYS_ISO_CTRL_DIOE 0x0080 -#define R92C_SYS_ISO_CTRL_EB2CORE 0x0100 -#define R92C_SYS_ISO_CTRL_DIOR 0x0200 -#define R92C_SYS_ISO_CTRL_PWC_EV25V 0x4000 -#define R92C_SYS_ISO_CTRL_PWC_EV12V 0x8000 - -/* Bits for R92C_SYS_FUNC_EN. */ -#define R92C_SYS_FUNC_EN_BBRSTB 0x0001 -#define R92C_SYS_FUNC_EN_BB_GLB_RST 0x0002 -#define R92C_SYS_FUNC_EN_USBA 0x0004 -#define R92C_SYS_FUNC_EN_UPLL 0x0008 -#define R92C_SYS_FUNC_EN_USBD 0x0010 -#define R92C_SYS_FUNC_EN_DIO_PCIE 0x0020 -#define R92C_SYS_FUNC_EN_PCIEA 0x0040 -#define R92C_SYS_FUNC_EN_PPLL 0x0080 -#define R92C_SYS_FUNC_EN_PCIED 0x0100 -#define R92C_SYS_FUNC_EN_DIOE 0x0200 -#define R92C_SYS_FUNC_EN_CPUEN 0x0400 -#define R92C_SYS_FUNC_EN_DCORE 0x0800 -#define R92C_SYS_FUNC_EN_ELDR 0x1000 -#define R92C_SYS_FUNC_EN_DIO_RF 0x2000 -#define R92C_SYS_FUNC_EN_HWPDN 0x4000 -#define R92C_SYS_FUNC_EN_MREGEN 0x8000 - -/* Bits for R92C_APS_FSMCO. */ -#define R92C_APS_FSMCO_PFM_LDALL 0x00000001 -#define R92C_APS_FSMCO_PFM_ALDN 0x00000002 -#define R92C_APS_FSMCO_PFM_LDKP 0x00000004 -#define R92C_APS_FSMCO_PFM_WOWL 0x00000008 -#define R92C_APS_FSMCO_PDN_EN 0x00000010 -#define R92C_APS_FSMCO_PDN_PL 0x00000020 -#define R92C_APS_FSMCO_APFM_ONMAC 0x00000100 -#define R92C_APS_FSMCO_APFM_OFF 0x00000200 -#define R92C_APS_FSMCO_APFM_RSM 0x00000400 -#define R92C_APS_FSMCO_AFSM_HSUS 0x00000800 -#define R92C_APS_FSMCO_AFSM_PCIE 0x00001000 -#define R92C_APS_FSMCO_APDM_MAC 0x00002000 -#define R92C_APS_FSMCO_APDM_HOST 0x00004000 -#define R92C_APS_FSMCO_APDM_HPDN 0x00008000 -#define R92C_APS_FSMCO_RDY_MACON 0x00010000 -#define R92C_APS_FSMCO_SUS_HOST 0x00020000 -#define R92C_APS_FSMCO_ROP_ALD 0x00100000 -#define R92C_APS_FSMCO_ROP_PWR 0x00200000 -#define R92C_APS_FSMCO_ROP_SPS 0x00400000 -#define R92C_APS_FSMCO_SOP_MRST 0x02000000 -#define R92C_APS_FSMCO_SOP_FUSE 0x04000000 -#define R92C_APS_FSMCO_SOP_ABG 0x08000000 -#define R92C_APS_FSMCO_SOP_AMB 0x10000000 -#define R92C_APS_FSMCO_SOP_RCK 0x20000000 -#define R92C_APS_FSMCO_SOP_A8M 0x40000000 -#define R92C_APS_FSMCO_XOP_BTCK 0x80000000 - -/* Bits for R92C_SYS_CLKR. */ -#define R92C_SYS_CLKR_ANAD16V_EN 0x00000001 -#define R92C_SYS_CLKR_ANA8M 0x00000002 -#define R92C_SYS_CLKR_MACSLP 0x00000010 -#define R92C_SYS_CLKR_LOADER_EN 0x00000020 -#define R92C_SYS_CLKR_80M_SSC_DIS 0x00000080 -#define R92C_SYS_CLKR_80M_SSC_EN_HO 0x00000100 -#define R92C_SYS_CLKR_PHY_SSC_RSTB 0x00000200 -#define R92C_SYS_CLKR_SEC_EN 0x00000400 -#define R92C_SYS_CLKR_MAC_EN 0x00000800 -#define R92C_SYS_CLKR_SYS_EN 0x00001000 -#define R92C_SYS_CLKR_RING_EN 0x00002000 - -/* Bits for R92C_RF_CTRL. */ -#define R92C_RF_CTRL_EN 0x01 -#define R92C_RF_CTRL_RSTB 0x02 -#define R92C_RF_CTRL_SDMRSTB 0x04 - -/* Bits for R92C_LDOA15_CTRL. */ -#define R92C_LDOA15_CTRL_EN 0x01 -#define R92C_LDOA15_CTRL_STBY 0x02 -#define R92C_LDOA15_CTRL_OBUF 0x04 -#define R92C_LDOA15_CTRL_REG_VOS 0x08 - -/* Bits for R92C_LDOV12D_CTRL. */ -#define R92C_LDOV12D_CTRL_LDV12_EN 0x01 - -/* Bits for R92C_LPLDO_CTRL. */ -#define R92C_LPLDO_CTRL_SLEEP 0x10 - -/* Bits for R92C_AFE_XTAL_CTRL. */ -#define R92C_AFE_XTAL_CTRL_ADDR_M 0x007ff800 -#define R92C_AFE_XTAL_CTRL_ADDR_S 11 - -/* Bits for R92C_AFE_PLL_CTRL. */ -#define R92C_AFE_PLL_CTRL_EN 0x0001 -#define R92C_AFE_PLL_CTRL_320_EN 0x0002 -#define R92C_AFE_PLL_CTRL_FREF_SEL 0x0004 -#define R92C_AFE_PLL_CTRL_EDGE_SEL 0x0008 -#define R92C_AFE_PLL_CTRL_WDOGB 0x0010 -#define R92C_AFE_PLL_CTRL_LPFEN 0x0020 - -/* Bits for R92C_EFUSE_CTRL. */ -#define R92C_EFUSE_CTRL_DATA_M 0x000000ff -#define R92C_EFUSE_CTRL_DATA_S 0 -#define R92C_EFUSE_CTRL_ADDR_M 0x0003ff00 -#define R92C_EFUSE_CTRL_ADDR_S 8 -#define R92C_EFUSE_CTRL_VALID 0x80000000 - -/* Bits for R92C_GPIO_MUXCFG. */ -#define R92C_GPIO_MUXCFG_ENBT 0x0020 - -/* Bits for R92C_LEDCFG0. */ -#define R92C_LEDCFG0_DIS 0x08 - -/* Bits for R92C_MCUFWDL. */ -#define R92C_MCUFWDL_EN 0x00000001 -#define R92C_MCUFWDL_RDY 0x00000002 -#define R92C_MCUFWDL_CHKSUM_RPT 0x00000004 -#define R92C_MCUFWDL_MACINI_RDY 0x00000008 -#define R92C_MCUFWDL_BBINI_RDY 0x00000010 -#define R92C_MCUFWDL_RFINI_RDY 0x00000020 -#define R92C_MCUFWDL_WINTINI_RDY 0x00000040 -#define R92C_MCUFWDL_RAM_DL_SEL 0x00000080 -#define R92C_MCUFWDL_PAGE_M 0x00070000 -#define R92C_MCUFWDL_PAGE_S 16 -#define R92C_MCUFWDL_CPRST 0x00800000 - -/* Bits for R88E_HIMR. */ -#define R88E_HIMR_CPWM 0x00000100 -#define R88E_HIMR_CPWM2 0x00000200 -#define R88E_HIMR_TBDER 0x04000000 -#define R88E_HIMR_PSTIMEOUT 0x20000000 - -/* Bits for R88E_HIMRE.*/ -#define R88E_HIMRE_RXFOVW 0x00000100 -#define R88E_HIMRE_TXFOVW 0x00000200 -#define R88E_HIMRE_RXERR 0x00000400 -#define R88E_HIMRE_TXERR 0x00000800 - -/* Bits for R92C_EFUSE_ACCESS. */ -#define R92C_EFUSE_ACCESS_OFF 0x00 -#define R92C_EFUSE_ACCESS_ON 0x69 - -/* Bits for R92C_HPON_FSM. */ -#define R92C_HPON_FSM_CHIP_BONDING_ID_S 22 -#define R92C_HPON_FSM_CHIP_BONDING_ID_M 0x00c00000 -#define R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R 1 - -/* Bits for R92C_SYS_CFG. */ -#define R92C_SYS_CFG_XCLK_VLD 0x00000001 -#define R92C_SYS_CFG_ACLK_VLD 0x00000002 -#define R92C_SYS_CFG_UCLK_VLD 0x00000004 -#define R92C_SYS_CFG_PCLK_VLD 0x00000008 -#define R92C_SYS_CFG_PCIRSTB 0x00000010 -#define R92C_SYS_CFG_V15_VLD 0x00000020 -#define R92C_SYS_CFG_TRP_B15V_EN 0x00000080 -#define R92C_SYS_CFG_SIC_IDLE 0x00000100 -#define R92C_SYS_CFG_BD_MAC2 0x00000200 -#define R92C_SYS_CFG_BD_MAC1 0x00000400 -#define R92C_SYS_CFG_IC_MACPHY_MODE 0x00000800 -#define R92C_SYS_CFG_CHIP_VER_RTL_M 0x0000f000 -#define R92C_SYS_CFG_CHIP_VER_RTL_S 12 -#define R92C_SYS_CFG_BT_FUNC 0x00010000 -#define R92C_SYS_CFG_VENDOR_UMC 0x00080000 -#define R92C_SYS_CFG_PAD_HWPD_IDN 0x00400000 -#define R92C_SYS_CFG_TRP_VAUX_EN 0x00800000 -#define R92C_SYS_CFG_TRP_BT_EN 0x01000000 -#define R92C_SYS_CFG_BD_PKG_SEL 0x02000000 -#define R92C_SYS_CFG_BD_HCI_SEL 0x04000000 -#define R92C_SYS_CFG_TYPE_92C 0x08000000 - -/* Bits for R92C_CR. */ -#define R92C_CR_HCI_TXDMA_EN 0x0001 -#define R92C_CR_HCI_RXDMA_EN 0x0002 -#define R92C_CR_TXDMA_EN 0x0004 -#define R92C_CR_RXDMA_EN 0x0008 -#define R92C_CR_PROTOCOL_EN 0x0010 -#define R92C_CR_SCHEDULE_EN 0x0020 -#define R92C_CR_MACTXEN 0x0040 -#define R92C_CR_MACRXEN 0x0080 -#define R92C_CR_ENSEC 0x0200 -#define R92C_CR_CALTMR_EN 0x0400 - -/* Bits for R92C_MSR. */ -#define R92C_MSR_NOLINK 0x00 -#define R92C_MSR_ADHOC 0x01 -#define R92C_MSR_INFRA 0x02 -#define R92C_MSR_AP 0x03 -#define R92C_MSR_MASK (R92C_MSR_AP) - -/* Bits for R92C_PBP. */ -#define R92C_PBP_PSRX_M 0x0f -#define R92C_PBP_PSRX_S 0 -#define R92C_PBP_PSTX_M 0xf0 -#define R92C_PBP_PSTX_S 4 -#define R92C_PBP_64 0 -#define R92C_PBP_128 1 -#define R92C_PBP_256 2 -#define R92C_PBP_512 3 -#define R92C_PBP_1024 4 - -/* Bits for R92C_TRXDMA_CTRL. */ -#define R92C_TRXDMA_CTRL_RXDMA_AGG_EN 0x0004 -#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_M 0x0030 -#define R92C_TRXDMA_CTRL_TXDMA_VOQ_MAP_S 4 -#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_M 0x00c0 -#define R92C_TRXDMA_CTRL_TXDMA_VIQ_MAP_S 6 -#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_M 0x0300 -#define R92C_TRXDMA_CTRL_TXDMA_BEQ_MAP_S 8 -#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_M 0x0c00 -#define R92C_TRXDMA_CTRL_TXDMA_BKQ_MAP_S 10 -#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_M 0x3000 -#define R92C_TRXDMA_CTRL_TXDMA_MGQ_MAP_S 12 -#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_M 0xc000 -#define R92C_TRXDMA_CTRL_TXDMA_HIQ_MAP_S 14 -#define R92C_TRXDMA_CTRL_QUEUE_LOW 1 -#define R92C_TRXDMA_CTRL_QUEUE_NORMAL 2 -#define R92C_TRXDMA_CTRL_QUEUE_HIGH 3 -#define R92C_TRXDMA_CTRL_QMAP_M 0xfff0 -/* Shortcuts. */ -#define R92C_TRXDMA_CTRL_QMAP_3EP 0xf5b0 -#define R92C_TRXDMA_CTRL_QMAP_HQ_LQ 0xf5f0 -#define R92C_TRXDMA_CTRL_QMAP_HQ_NQ 0xfaf0 -#define R92C_TRXDMA_CTRL_QMAP_LQ 0x5550 -#define R92C_TRXDMA_CTRL_QMAP_NQ 0xaaa0 -#define R92C_TRXDMA_CTRL_QMAP_HQ 0xfff0 - -/* Bits for R92C_LLT_INIT. */ -#define R92C_LLT_INIT_DATA_M 0x000000ff -#define R92C_LLT_INIT_DATA_S 0 -#define R92C_LLT_INIT_ADDR_M 0x0000ff00 -#define R92C_LLT_INIT_ADDR_S 8 -#define R92C_LLT_INIT_OP_M 0xc0000000 -#define R92C_LLT_INIT_OP_S 30 -#define R92C_LLT_INIT_OP_NO_ACTIVE 0 -#define R92C_LLT_INIT_OP_WRITE 1 - -/* Bits for R92C_RQPN. */ -#define R92C_RQPN_HPQ_M 0x000000ff -#define R92C_RQPN_HPQ_S 0 -#define R92C_RQPN_LPQ_M 0x0000ff00 -#define R92C_RQPN_LPQ_S 8 -#define R92C_RQPN_PUBQ_M 0x00ff0000 -#define R92C_RQPN_PUBQ_S 16 -#define R92C_RQPN_LD 0x80000000 - -/* Bits for R92C_TDECTRL. */ -#define R92C_TDECTRL_BLK_DESC_NUM_M 0x000000f0 -#define R92C_TDECTRL_BLK_DESC_NUM_S 4 -#define R92C_TDECTRL_BCN_VALID 0x00010000 - -/* Bits for R92C_FWHW_TXQ_CTRL. */ -#define R92C_FWHW_TXQ_CTRL_AMPDU_RTY_NEW 0x80 - -/* Bits for R92C_SPEC_SIFS. */ -#define R92C_SPEC_SIFS_CCK_M 0x00ff -#define R92C_SPEC_SIFS_CCK_S 0 -#define R92C_SPEC_SIFS_OFDM_M 0xff00 -#define R92C_SPEC_SIFS_OFDM_S 8 - -/* Bits for R92C_RL. */ -#define R92C_RL_LRL_M 0x003f -#define R92C_RL_LRL_S 0 -#define R92C_RL_SRL_M 0x3f00 -#define R92C_RL_SRL_S 8 - -/* Bits for R92C_RRSR. */ -#define R92C_RRSR_RATE_BITMAP_M 0x000fffff -#define R92C_RRSR_RATE_BITMAP_S 0 -#define R92C_RRSR_RATE_CCK_ONLY_1M 0xffff1 -#define R92C_RRSR_RSC_LOWSUBCHNL 0x00200000 -#define R92C_RRSR_RSC_UPSUBCHNL 0x00400000 -#define R92C_RRSR_SHORT 0x00800000 - -/* Bits for R88E_TX_RPT_CTRL. */ -#define R88E_TX_RPT1_ENA 0x01 -#define R88E_TX_RPT2_ENA 0x02 - -/* Bits for R92C_EDCA_XX_PARAM. */ -#define R92C_EDCA_PARAM_AIFS_M 0x000000ff -#define R92C_EDCA_PARAM_AIFS_S 0 -#define R92C_EDCA_PARAM_ECWMIN_M 0x00000f00 -#define R92C_EDCA_PARAM_ECWMIN_S 8 -#define R92C_EDCA_PARAM_ECWMAX_M 0x0000f000 -#define R92C_EDCA_PARAM_ECWMAX_S 12 -#define R92C_EDCA_PARAM_TXOP_M 0xffff0000 -#define R92C_EDCA_PARAM_TXOP_S 16 - -/* Bits for R92C_HWSEQ_CTRL / R92C_TXPAUSE. */ -#define R92C_TX_QUEUE_VO 0x01 -#define R92C_TX_QUEUE_VI 0x02 -#define R92C_TX_QUEUE_BE 0x04 -#define R92C_TX_QUEUE_BK 0x08 -#define R92C_TX_QUEUE_MGT 0x10 -#define R92C_TX_QUEUE_HIGH 0x20 -#define R92C_TX_QUEUE_BCN 0x40 - -/* Shortcuts. */ -#define R92C_TX_QUEUE_AC \ - (R92C_TX_QUEUE_VO | R92C_TX_QUEUE_VI | \ - R92C_TX_QUEUE_BE | R92C_TX_QUEUE_BK) - -#define R92C_TX_QUEUE_ALL \ - (R92C_TX_QUEUE_AC | R92C_TX_QUEUE_MGT | \ - R92C_TX_QUEUE_HIGH | R92C_TX_QUEUE_BCN | 0x80) /* XXX */ - -/* Bits for R92C_BCN_CTRL. */ -#define R92C_BCN_CTRL_EN_MBSSID 0x02 -#define R92C_BCN_CTRL_TXBCN_RPT 0x04 -#define R92C_BCN_CTRL_EN_BCN 0x08 -#define R92C_BCN_CTRL_DIS_TSF_UDT0 0x10 - -/* Bits for R92C_MBID_NUM. */ -#define R92C_MBID_TXBCN_RPT0 0x08 -#define R92C_MBID_TXBCN_RPT1 0x10 - -/* Bits for R92C_DUAL_TSF_RST. */ -#define R92C_DUAL_TSF_RST0 0x01 -#define R92C_DUAL_TSF_RST1 0x02 - -/* Bits for R92C_ACMHWCTRL. */ -#define R92C_ACMHWCTRL_EN 0x01 -#define R92C_ACMHWCTRL_BE 0x02 -#define R92C_ACMHWCTRL_VI 0x04 -#define R92C_ACMHWCTRL_VO 0x08 -#define R92C_ACMHWCTRL_ACM_MASK 0x0f - -/* Bits for R92C_APSD_CTRL. */ -#define R92C_APSD_CTRL_OFF 0x40 -#define R92C_APSD_CTRL_OFF_STATUS 0x80 - -/* Bits for R92C_BWOPMODE. */ -#define R92C_BWOPMODE_11J 0x01 -#define R92C_BWOPMODE_5G 0x02 -#define R92C_BWOPMODE_20MHZ 0x04 - -/* Bits for R92C_RCR. */ -#define R92C_RCR_AAP 0x00000001 -#define R92C_RCR_APM 0x00000002 -#define R92C_RCR_AM 0x00000004 -#define R92C_RCR_AB 0x00000008 -#define R92C_RCR_ADD3 0x00000010 -#define R92C_RCR_APWRMGT 0x00000020 -#define R92C_RCR_CBSSID_DATA 0x00000040 -#define R92C_RCR_CBSSID_BCN 0x00000080 -#define R92C_RCR_ACRC32 0x00000100 -#define R92C_RCR_AICV 0x00000200 -#define R92C_RCR_ADF 0x00000800 -#define R92C_RCR_ACF 0x00001000 -#define R92C_RCR_AMF 0x00002000 -#define R92C_RCR_HTC_LOC_CTRL 0x00004000 -#define R92C_RCR_MFBEN 0x00400000 -#define R92C_RCR_LSIGEN 0x00800000 -#define R92C_RCR_ENMBID 0x01000000 -#define R92C_RCR_APP_BA_SSN 0x08000000 -#define R92C_RCR_APP_PHYSTS 0x10000000 -#define R92C_RCR_APP_ICV 0x20000000 -#define R92C_RCR_APP_MIC 0x40000000 -#define R92C_RCR_APPFCS 0x80000000 - -/* Bits for R92C_CAMCMD. */ -#define R92C_CAMCMD_ADDR_M 0x0000ffff -#define R92C_CAMCMD_ADDR_S 0 -#define R92C_CAMCMD_WRITE 0x00010000 -#define R92C_CAMCMD_CLR 0x40000000 -#define R92C_CAMCMD_POLLING 0x80000000 - -/* Bits for R92C_SECCFG. */ -#define R92C_SECCFG_TXUCKEY_DEF 0x0001 -#define R92C_SECCFG_RXUCKEY_DEF 0x0002 -#define R92C_SECCFG_TXENC_ENA 0x0004 -#define R92C_SECCFG_RXDEC_ENA 0x0008 -#define R92C_SECCFG_CMP_A2 0x0010 -#define R92C_SECCFG_TXBCKEY_DEF 0x0040 -#define R92C_SECCFG_RXBCKEY_DEF 0x0080 -#define R88E_SECCFG_CHK_KEYID 0x0100 - -/* Bits for R92C_RXFLTMAP*. */ -#define R92C_RXFLTMAP_SUBTYPE(subtype) \ - (1 << ((subtype) >> IEEE80211_FC0_SUBTYPE_SHIFT)) - - -/* - * Baseband registers. - */ -#define R92C_FPGA0_RFMOD 0x800 -#define R92C_FPGA0_TXINFO 0x804 -#define R92C_HSSI_PARAM1(chain) (0x820 + (chain) * 8) -#define R92C_HSSI_PARAM2(chain) (0x824 + (chain) * 8) -#define R92C_TXAGC_RATE18_06(i) (((i) == 0) ? 0xe00 : 0x830) -#define R92C_TXAGC_RATE54_24(i) (((i) == 0) ? 0xe04 : 0x834) -#define R92C_TXAGC_A_CCK1_MCS32 0xe08 -#define R92C_TXAGC_B_CCK1_55_MCS32 0x838 -#define R92C_TXAGC_B_CCK11_A_CCK2_11 0x86c -#define R92C_TXAGC_MCS03_MCS00(i) (((i) == 0) ? 0xe10 : 0x83c) -#define R92C_TXAGC_MCS07_MCS04(i) (((i) == 0) ? 0xe14 : 0x848) -#define R92C_TXAGC_MCS11_MCS08(i) (((i) == 0) ? 0xe18 : 0x84c) -#define R92C_TXAGC_MCS15_MCS12(i) (((i) == 0) ? 0xe1c : 0x868) -#define R92C_LSSI_PARAM(chain) (0x840 + (chain) * 4) -#define R92C_FPGA0_RFIFACEOE(chain) (0x860 + (chain) * 4) -#define R92C_FPGA0_RFIFACESW(idx) (0x870 + (idx) * 4) -#define R92C_FPGA0_RFPARAM(idx) (0x878 + (idx) * 4) -#define R92C_FPGA0_ANAPARAM2 0x884 -#define R92C_LSSI_READBACK(chain) (0x8a0 + (chain) * 4) -#define R92C_HSPI_READBACK(chain) (0x8b8 + (chain) * 4) -#define R92C_FPGA1_RFMOD 0x900 -#define R92C_FPGA1_TXINFO 0x90c -#define R92C_CCK0_SYSTEM 0xa00 -#define R92C_CCK0_AFESETTING 0xa04 -#define R92C_OFDM0_TRXPATHENA 0xc04 -#define R92C_OFDM0_TRMUXPAR 0xc08 -#define R92C_OFDM0_AGCCORE1(chain) (0xc50 + (chain) * 8) -#define R92C_OFDM0_AGCPARAM1 0xc70 -#define R92C_OFDM0_AGCRSSITABLE 0xc78 -#define R92C_OFDM1_LSTF 0xd00 - -/* Bits for R92C_FPGA[01]_RFMOD. */ -#define R92C_RFMOD_40MHZ 0x00000001 -#define R92C_RFMOD_JAPAN 0x00000002 -#define R92C_RFMOD_CCK_TXSC 0x00000030 -#define R92C_RFMOD_CCK_EN 0x01000000 -#define R92C_RFMOD_OFDM_EN 0x02000000 - -/* Bits for R92C_HSSI_PARAM1(i). */ -#define R92C_HSSI_PARAM1_PI 0x00000100 - -/* Bits for R92C_HSSI_PARAM2(i). */ -#define R92C_HSSI_PARAM2_CCK_HIPWR 0x00000200 -#define R92C_HSSI_PARAM2_ADDR_LENGTH 0x00000400 -#define R92C_HSSI_PARAM2_DATA_LENGTH 0x00000800 -#define R92C_HSSI_PARAM2_READ_ADDR_M 0x7f800000 -#define R92C_HSSI_PARAM2_READ_ADDR_S 23 -#define R92C_HSSI_PARAM2_READ_EDGE 0x80000000 - -/* Bits for R92C_TXAGC_A_CCK1_MCS32. */ -#define R92C_TXAGC_A_CCK1_M 0x0000ff00 -#define R92C_TXAGC_A_CCK1_S 8 - -/* Bits for R92C_TXAGC_B_CCK11_A_CCK2_11. */ -#define R92C_TXAGC_B_CCK11_M 0x000000ff -#define R92C_TXAGC_B_CCK11_S 0 -#define R92C_TXAGC_A_CCK2_M 0x0000ff00 -#define R92C_TXAGC_A_CCK2_S 8 -#define R92C_TXAGC_A_CCK55_M 0x00ff0000 -#define R92C_TXAGC_A_CCK55_S 16 -#define R92C_TXAGC_A_CCK11_M 0xff000000 -#define R92C_TXAGC_A_CCK11_S 24 - -/* Bits for R92C_TXAGC_B_CCK1_55_MCS32. */ -#define R92C_TXAGC_B_CCK1_M 0x0000ff00 -#define R92C_TXAGC_B_CCK1_S 8 -#define R92C_TXAGC_B_CCK2_M 0x00ff0000 -#define R92C_TXAGC_B_CCK2_S 16 -#define R92C_TXAGC_B_CCK55_M 0xff000000 -#define R92C_TXAGC_B_CCK55_S 24 - -/* Bits for R92C_TXAGC_RATE18_06(x). */ -#define R92C_TXAGC_RATE06_M 0x000000ff -#define R92C_TXAGC_RATE06_S 0 -#define R92C_TXAGC_RATE09_M 0x0000ff00 -#define R92C_TXAGC_RATE09_S 8 -#define R92C_TXAGC_RATE12_M 0x00ff0000 -#define R92C_TXAGC_RATE12_S 16 -#define R92C_TXAGC_RATE18_M 0xff000000 -#define R92C_TXAGC_RATE18_S 24 - -/* Bits for R92C_TXAGC_RATE54_24(x). */ -#define R92C_TXAGC_RATE24_M 0x000000ff -#define R92C_TXAGC_RATE24_S 0 -#define R92C_TXAGC_RATE36_M 0x0000ff00 -#define R92C_TXAGC_RATE36_S 8 -#define R92C_TXAGC_RATE48_M 0x00ff0000 -#define R92C_TXAGC_RATE48_S 16 -#define R92C_TXAGC_RATE54_M 0xff000000 -#define R92C_TXAGC_RATE54_S 24 - -/* Bits for R92C_TXAGC_MCS03_MCS00(x). */ -#define R92C_TXAGC_MCS00_M 0x000000ff -#define R92C_TXAGC_MCS00_S 0 -#define R92C_TXAGC_MCS01_M 0x0000ff00 -#define R92C_TXAGC_MCS01_S 8 -#define R92C_TXAGC_MCS02_M 0x00ff0000 -#define R92C_TXAGC_MCS02_S 16 -#define R92C_TXAGC_MCS03_M 0xff000000 -#define R92C_TXAGC_MCS03_S 24 - -/* Bits for R92C_TXAGC_MCS07_MCS04(x). */ -#define R92C_TXAGC_MCS04_M 0x000000ff -#define R92C_TXAGC_MCS04_S 0 -#define R92C_TXAGC_MCS05_M 0x0000ff00 -#define R92C_TXAGC_MCS05_S 8 -#define R92C_TXAGC_MCS06_M 0x00ff0000 -#define R92C_TXAGC_MCS06_S 16 -#define R92C_TXAGC_MCS07_M 0xff000000 -#define R92C_TXAGC_MCS07_S 24 - -/* Bits for R92C_TXAGC_MCS11_MCS08(x). */ -#define R92C_TXAGC_MCS08_M 0x000000ff -#define R92C_TXAGC_MCS08_S 0 -#define R92C_TXAGC_MCS09_M 0x0000ff00 -#define R92C_TXAGC_MCS09_S 8 -#define R92C_TXAGC_MCS10_M 0x00ff0000 -#define R92C_TXAGC_MCS10_S 16 -#define R92C_TXAGC_MCS11_M 0xff000000 -#define R92C_TXAGC_MCS11_S 24 - -/* Bits for R92C_TXAGC_MCS15_MCS12(x). */ -#define R92C_TXAGC_MCS12_M 0x000000ff -#define R92C_TXAGC_MCS12_S 0 -#define R92C_TXAGC_MCS13_M 0x0000ff00 -#define R92C_TXAGC_MCS13_S 8 -#define R92C_TXAGC_MCS14_M 0x00ff0000 -#define R92C_TXAGC_MCS14_S 16 -#define R92C_TXAGC_MCS15_M 0xff000000 -#define R92C_TXAGC_MCS15_S 24 - -/* Bits for R92C_LSSI_PARAM(i). */ -#define R92C_LSSI_PARAM_DATA_M 0x000fffff -#define R92C_LSSI_PARAM_DATA_S 0 -#define R92C_LSSI_PARAM_ADDR_M 0x03f00000 -#define R92C_LSSI_PARAM_ADDR_S 20 -#define R88E_LSSI_PARAM_ADDR_M 0x0ff00000 -#define R88E_LSSI_PARAM_ADDR_S 20 - -/* Bits for R92C_FPGA0_ANAPARAM2. */ -#define R92C_FPGA0_ANAPARAM2_CBW20 0x00000400 - -/* Bits for R92C_LSSI_READBACK(i). */ -#define R92C_LSSI_READBACK_DATA_M 0x000fffff -#define R92C_LSSI_READBACK_DATA_S 0 - -/* Bits for R92C_OFDM0_AGCCORE1(i). */ -#define R92C_OFDM0_AGCCORE1_GAIN_M 0x0000007f -#define R92C_OFDM0_AGCCORE1_GAIN_S 0 - - -/* - * USB registers. - */ -#define R92C_USB_SUSPEND 0xfe10 -#define R92C_USB_INFO 0xfe17 -#define R92C_USB_SPECIAL_OPTION 0xfe55 -#define R92C_USB_HCPWM 0xfe57 -#define R92C_USB_HRPWM 0xfe58 -#define R92C_USB_DMA_AGG_TO 0xfe5b -#define R92C_USB_AGG_TO 0xfe5c -#define R92C_USB_AGG_TH 0xfe5d -#define R92C_USB_VID 0xfe60 -#define R92C_USB_PID 0xfe62 -#define R92C_USB_OPTIONAL 0xfe64 -#define R92C_USB_EP 0xfe65 -#define R92C_USB_PHY 0xfe68 -#define R92C_USB_MAC_ADDR 0xfe70 -#define R92C_USB_STRING 0xfe80 - -/* Bits for R92C_USB_SPECIAL_OPTION. */ -#define R92C_USB_SPECIAL_OPTION_AGG_EN 0x08 -#define R92C_USB_SPECIAL_OPTION_INT_BULK_SEL 0x10 - -/* Bits for R92C_USB_EP. */ -#define R92C_USB_EP_HQ_M 0x000f -#define R92C_USB_EP_HQ_S 0 -#define R92C_USB_EP_NQ_M 0x00f0 -#define R92C_USB_EP_NQ_S 4 -#define R92C_USB_EP_LQ_M 0x0f00 -#define R92C_USB_EP_LQ_S 8 - - -/* - * Firmware base address. - */ -#define R92C_FW_START_ADDR 0x1000 -#define R92C_FW_PAGE_SIZE 4096 - - -/* - * RF (6052) registers. - */ -#define R92C_RF_AC 0x00 -#define R92C_RF_IQADJ_G(i) (0x01 + (i)) -#define R92C_RF_POW_TRSW 0x05 -#define R92C_RF_GAIN_RX 0x06 -#define R92C_RF_GAIN_TX 0x07 -#define R92C_RF_TXM_IDAC 0x08 -#define R92C_RF_BS_IQGEN 0x0f -#define R92C_RF_MODE1 0x10 -#define R92C_RF_MODE2 0x11 -#define R92C_RF_RX_AGC_HP 0x12 -#define R92C_RF_TX_AGC 0x13 -#define R92C_RF_BIAS 0x14 -#define R92C_RF_IPA 0x15 -#define R92C_RF_POW_ABILITY 0x17 -#define R92C_RF_CHNLBW 0x18 -#define R92C_RF_RX_G1 0x1a -#define R92C_RF_RX_G2 0x1b -#define R92C_RF_RX_BB2 0x1c -#define R92C_RF_RX_BB1 0x1d -#define R92C_RF_RCK1 0x1e -#define R92C_RF_RCK2 0x1f -#define R92C_RF_TX_G(i) (0x20 + (i)) -#define R92C_RF_TX_BB1 0x23 -#define R92C_RF_T_METER 0x24 -#define R92C_RF_SYN_G(i) (0x25 + (i)) -#define R92C_RF_RCK_OS 0x30 -#define R92C_RF_TXPA_G(i) (0x31 + (i)) -#define R88E_RF_T_METER 0x42 - -/* Bits for R92C_RF_AC. */ -#define R92C_RF_AC_MODE_M 0x70000 -#define R92C_RF_AC_MODE_S 16 -#define R92C_RF_AC_MODE_STANDBY 1 - -/* Bits for R92C_RF_CHNLBW. */ -#define R92C_RF_CHNLBW_CHNL_M 0x003ff -#define R92C_RF_CHNLBW_CHNL_S 0 -#define R92C_RF_CHNLBW_BW20 0x00400 -#define R88E_RF_CHNLBW_BW20 0x00c00 -#define R92C_RF_CHNLBW_LCSTART 0x08000 - -/* Bits for R92C_RF_T_METER. */ -#define R92C_RF_T_METER_START 0x60 -#define R92C_RF_T_METER_VAL_M 0x1f -#define R92C_RF_T_METER_VAL_S 0 - -/* Bits for R88E_RF_T_METER. */ -#define R88E_RF_T_METER_VAL_M 0x0fc00 -#define R88E_RF_T_METER_VAL_S 10 -#define R88E_RF_T_METER_START 0x30000 - - -/* - * CAM entries. - */ -#define R92C_CAM_ENTRY_COUNT 32 - -#define R92C_CAM_CTL0(entry) ((entry) * 8 + 0) -#define R92C_CAM_CTL1(entry) ((entry) * 8 + 1) -#define R92C_CAM_KEY(entry, i) ((entry) * 8 + 2 + (i)) -#define R92C_CAM_CTL6(entry) ((entry) * 8 + 6) -#define R92C_CAM_CTL7(entry) ((entry) * 8 + 7) - -/* Bits for R92C_CAM_CTL0(i). */ -#define R92C_CAM_KEYID_M 0x00000003 -#define R92C_CAM_KEYID_S 0 -#define R92C_CAM_ALGO_M 0x0000001c -#define R92C_CAM_ALGO_S 2 -#define R92C_CAM_ALGO_NONE 0 -#define R92C_CAM_ALGO_WEP40 1 -#define R92C_CAM_ALGO_TKIP 2 -#define R92C_CAM_ALGO_AES 4 -#define R92C_CAM_ALGO_WEP104 5 -#define R92C_CAM_VALID 0x00008000 -#define R92C_CAM_MACLO_M 0xffff0000 -#define R92C_CAM_MACLO_S 16 - -/* Rate adaptation modes. */ -#define R92C_RAID_11GN 1 -#define R92C_RAID_11N 3 -#define R92C_RAID_11BG 4 -#define R92C_RAID_11G 5 /* "pure" 11g */ -#define R92C_RAID_11B 6 - - -/* - * Macros to access subfields in registers. - */ -/* Mask and Shift (getter). */ -#define MS(val, field) \ - (((val) & field##_M) >> field##_S) - -/* Shift and Mask (setter). */ -#define SM(field, val) \ - (((val) << field##_S) & field##_M) - -/* Rewrite. */ -#define RW(var, field, val) \ - (((var) & ~field##_M) | SM(field, val)) - -/* - * Firmware image header. - */ -struct r92c_fw_hdr { - /* QWORD0 */ - uint16_t signature; - uint8_t category; - uint8_t function; - uint16_t version; - uint16_t subversion; - /* QWORD1 */ - uint8_t month; - uint8_t date; - uint8_t hour; - uint8_t minute; - uint16_t ramcodesize; - uint16_t reserved2; - /* QWORD2 */ - uint32_t svnidx; - uint32_t reserved3; - /* QWORD3 */ - uint32_t reserved4; - uint32_t reserved5; -} __packed; - -/* - * Host to firmware commands. - */ -struct r92c_fw_cmd { - uint8_t id; -#define R92C_CMD_AP_OFFLOAD 0 -#define R92C_CMD_SET_PWRMODE 1 -#define R92C_CMD_JOINBSS_RPT 2 -#define R92C_CMD_RSVD_PAGE 3 -#define R92C_CMD_RSSI 4 -#define R92C_CMD_RSSI_SETTING 5 -#define R92C_CMD_MACID_CONFIG 6 -#define R92C_CMD_MACID_PS_MODE 7 -#define R92C_CMD_P2P_PS_OFFLOAD 8 -#define R92C_CMD_SELECTIVE_SUSPEND 9 -#define R92C_CMD_FLAG_EXT 0x80 - - uint8_t msg[5]; -} __packed; - -/* Structure for R92C_CMD_RSSI_SETTING. */ -struct r92c_fw_cmd_rssi { - uint8_t macid; - uint8_t reserved; - uint8_t pwdb; -} __packed; - -/* Structure for R92C_CMD_MACID_CONFIG. */ -struct r92c_fw_cmd_macid_cfg { - uint32_t mask; - uint8_t macid; -#define URTWN_MACID_BSS 0 -#define URTWN_MACID_BC 4 /* Broadcast. */ -#define R92C_MACID_MAX 31 -#define R88E_MACID_MAX 63 -#define URTWN_MACID_MAX(sc) (((sc)->chip & URTWN_CHIP_88E) ? \ - R88E_MACID_MAX : R92C_MACID_MAX) -#define URTWN_MACID_UNDEFINED (uint8_t)-1 -#define URTWN_MACID_VALID 0x80 -} __packed; - -/* - * RTL8192CU ROM image. - */ -struct r92c_rom { - uint16_t id; /* 0x8192 */ - uint8_t reserved1[5]; - uint8_t dbg_sel; - uint16_t reserved2; - uint16_t vid; - uint16_t pid; - uint8_t usb_opt; - uint8_t ep_setting; - uint16_t reserved3; - uint8_t usb_phy; - uint8_t reserved4[3]; - uint8_t macaddr[IEEE80211_ADDR_LEN]; - uint8_t string[61]; /* "Realtek" */ - uint8_t subcustomer_id; - uint8_t cck_tx_pwr[R92C_MAX_CHAINS][3]; - uint8_t ht40_1s_tx_pwr[R92C_MAX_CHAINS][3]; - uint8_t ht40_2s_tx_pwr_diff[3]; - uint8_t ht20_tx_pwr_diff[3]; - uint8_t ofdm_tx_pwr_diff[3]; - uint8_t ht40_max_pwr[3]; - uint8_t ht20_max_pwr[3]; - uint8_t xtal_calib; - uint8_t tssi[R92C_MAX_CHAINS]; - uint8_t thermal_meter; - uint8_t rf_opt1; -#define R92C_ROM_RF1_REGULATORY_M 0x07 -#define R92C_ROM_RF1_REGULATORY_S 0 -#define R92C_ROM_RF1_BOARD_TYPE_M 0xe0 -#define R92C_ROM_RF1_BOARD_TYPE_S 5 -#define R92C_BOARD_TYPE_DONGLE 0 -#define R92C_BOARD_TYPE_HIGHPA 1 -#define R92C_BOARD_TYPE_MINICARD 2 -#define R92C_BOARD_TYPE_SOLO 3 -#define R92C_BOARD_TYPE_COMBO 4 - - uint8_t rf_opt2; - uint8_t rf_opt3; - uint8_t rf_opt4; - uint8_t channel_plan; -#define R92C_CHANNEL_PLAN_BY_HW 0x80 - - uint8_t version; - uint8_t customer_id; -} __packed; - -/* - * RTL8188EU ROM image. - */ -struct r88e_rom { - uint8_t reserved1[16]; - uint8_t cck_tx_pwr[6]; - uint8_t ht40_tx_pwr[5]; - uint8_t tx_pwr_diff; - uint8_t reserved2[156]; - uint8_t channel_plan; - uint8_t crystalcap; - uint8_t reserved3[7]; - uint8_t rf_board_opt; - uint8_t rf_feature_opt; - uint8_t rf_bt_opt; - uint8_t version; - uint8_t customer_id; - uint8_t reserved4[3]; - uint8_t rf_ant_opt; - uint8_t reserved5[6]; - uint16_t vid; - uint16_t pid; - uint8_t usb_opt; - uint8_t reserved6[2]; - uint8_t macaddr[IEEE80211_ADDR_LEN]; - uint8_t reserved7[2]; - uint8_t string[33]; /* "realtek 802.11n NIC" */ - uint8_t reserved8[256]; -} __packed; - -#define URTWN_EFUSE_MAX_LEN 512 - -/* Rx MAC descriptor. */ -struct r92c_rx_stat { - uint32_t rxdw0; -#define R92C_RXDW0_PKTLEN_M 0x00003fff -#define R92C_RXDW0_PKTLEN_S 0 -#define R92C_RXDW0_CRCERR 0x00004000 -#define R92C_RXDW0_ICVERR 0x00008000 -#define R92C_RXDW0_INFOSZ_M 0x000f0000 -#define R92C_RXDW0_INFOSZ_S 16 -#define R92C_RXDW0_CIPHER_M 0x00700000 -#define R92C_RXDW0_CIPHER_S 20 -#define R92C_RXDW0_QOS 0x00800000 -#define R92C_RXDW0_SHIFT_M 0x03000000 -#define R92C_RXDW0_SHIFT_S 24 -#define R92C_RXDW0_PHYST 0x04000000 -#define R92C_RXDW0_DECRYPTED 0x08000000 - - uint32_t rxdw1; - uint32_t rxdw2; -#define R92C_RXDW2_PKTCNT_M 0x00ff0000 -#define R92C_RXDW2_PKTCNT_S 16 - - uint32_t rxdw3; -#define R92C_RXDW3_RATE_M 0x0000003f -#define R92C_RXDW3_RATE_S 0 -#define R92C_RXDW3_HT 0x00000040 -#define R92C_RXDW3_HTC 0x00000400 -#define R88E_RXDW3_RPT_M 0x0000c000 -#define R88E_RXDW3_RPT_S 14 -#define R88E_RXDW3_RPT_RX 0 -#define R88E_RXDW3_RPT_TX1 1 -#define R88E_RXDW3_RPT_TX2 2 - - uint32_t rxdw4; - uint32_t rxdw5; -} __packed __attribute__((aligned(4))); - -/* Rx PHY descriptor. */ -struct r92c_rx_phystat { - uint32_t phydw0; - uint32_t phydw1; - uint32_t phydw2; - uint32_t phydw3; - uint32_t phydw4; - uint32_t phydw5; - uint32_t phydw6; - uint32_t phydw7; -} __packed __attribute__((aligned(4))); - -/* Rx PHY CCK descriptor. */ -struct r92c_rx_cck { - uint8_t adc_pwdb[4]; - uint8_t sq_rpt; - uint8_t agc_rpt; -} __packed; - -struct r88e_rx_cck { - uint8_t path_agc[2]; - uint8_t chan; - uint8_t reserved1; - uint8_t sig_qual; - uint8_t agc_rpt; - uint8_t rpt_b; - uint8_t reserved2; - uint8_t noise_power; - uint8_t path_cfotail[2]; - uint8_t pcts_mask[2]; - uint8_t stream_rxevm[2]; - uint8_t path_rxsnr[2]; - uint8_t noise_power_db_lsb; - uint8_t reserved3[3]; - uint8_t stream_csi[2]; - uint8_t stream_target_csi[2]; - uint8_t sig_evm; -} __packed; - -/* Tx MAC descriptor. */ -struct r92c_tx_desc { - uint32_t txdw0; -#define R92C_TXDW0_PKTLEN_M 0x0000ffff -#define R92C_TXDW0_PKTLEN_S 0 -#define R92C_TXDW0_OFFSET_M 0x00ff0000 -#define R92C_TXDW0_OFFSET_S 16 -#define R92C_TXDW0_BMCAST 0x01000000 -#define R92C_TXDW0_LSG 0x04000000 -#define R92C_TXDW0_FSG 0x08000000 -#define R92C_TXDW0_OWN 0x80000000 - - uint32_t txdw1; -#define R92C_TXDW1_MACID_M 0x0000001f -#define R92C_TXDW1_MACID_S 0 -#define R88E_TXDW1_MACID_M 0x0000003f -#define R88E_TXDW1_MACID_S 0 -#define R92C_TXDW1_AGGEN 0x00000020 -#define R92C_TXDW1_AGGBK 0x00000040 -#define R92C_TXDW1_QSEL_M 0x00001f00 -#define R92C_TXDW1_QSEL_S 8 - -#define R92C_TXDW1_QSEL_BE 0x00 /* or 0x03 */ -#define R92C_TXDW1_QSEL_BK 0x01 /* or 0x02 */ -#define R92C_TXDW1_QSEL_VI 0x04 /* or 0x05 */ -#define R92C_TXDW1_QSEL_VO 0x06 /* or 0x07 */ -#define URTWN_MAX_TID 8 - -#define R92C_TXDW1_QSEL_BEACON 0x10 -#define R92C_TXDW1_QSEL_MGNT 0x12 - -#define R92C_TXDW1_RAID_M 0x000f0000 -#define R92C_TXDW1_RAID_S 16 -#define R92C_TXDW1_CIPHER_M 0x00c00000 -#define R92C_TXDW1_CIPHER_S 22 -#define R92C_TXDW1_CIPHER_NONE 0 -#define R92C_TXDW1_CIPHER_RC4 1 -#define R92C_TXDW1_CIPHER_AES 3 -#define R92C_TXDW1_PKTOFF_M 0x7c000000 -#define R92C_TXDW1_PKTOFF_S 26 - - uint32_t txdw2; -#define R88E_TXDW2_AGGBK 0x00010000 -#define R88E_TXDW2_CCX_RPT 0x00080000 - - uint16_t txdw3; - uint16_t txdseq; -#define R88E_TXDSEQ_HWSEQ_EN 0x8000 - - uint32_t txdw4; -#define R92C_TXDW4_RTSRATE_M 0x0000003f -#define R92C_TXDW4_RTSRATE_S 0 -#define R92C_TXDW4_HWSEQ_QOS 0x00000040 -#define R92C_TXDW4_HWSEQ_EN 0x00000080 -#define R92C_TXDW4_DRVRATE 0x00000100 -#define R92C_TXDW4_CTS2SELF 0x00000800 -#define R92C_TXDW4_RTSEN 0x00001000 -#define R92C_TXDW4_HWRTSEN 0x00002000 -#define R92C_TXDW4_SCO_M 0x003f0000 -#define R92C_TXDW4_SCO_S 20 -#define R92C_TXDW4_SCO_SCA 1 -#define R92C_TXDW4_SCO_SCB 2 -#define R92C_TXDW4_40MHZ 0x02000000 - - uint32_t txdw5; -#define R92C_TXDW5_DATARATE_M 0x0000003f -#define R92C_TXDW5_DATARATE_S 0 -#define R92C_TXDW5_SGI 0x00000040 -#define R92C_TXDW5_RTY_LMT_ENA 0x00020000 -#define R92C_TXDW5_RTY_LMT_M 0x00fc0000 -#define R92C_TXDW5_RTY_LMT_S 18 -#define R92C_TXDW5_AGGNUM_M 0xff000000 -#define R92C_TXDW5_AGGNUM_S 24 - - uint32_t txdw6; - uint16_t txdsum; - uint16_t pad; -} __packed __attribute__((aligned(4))); - -struct r88e_tx_rpt_ccx { - uint8_t rptb0; - uint8_t rptb1; -#define R88E_RPTB1_MACID_M 0x3f -#define R88E_RPTB1_MACID_S 0 -#define R88E_RPTB1_PKT_OK 0x40 -#define R88E_RPTB1_BMC 0x80 - - uint8_t rptb2; -#define R88E_RPTB2_RETRY_CNT_M 0x3f -#define R88E_RPTB2_RETRY_CNT_S 0 -#define R88E_RPTB2_LIFE_EXPIRE 0x40 -#define R88E_RPTB2_RETRY_OVER 0x80 - - uint16_t ccx_qtime; - uint8_t final_rate; - uint8_t rptb6; -#define R88E_RPTB6_QSEL_M 0xf0 -#define R88E_RPTB6_QSEL_S 4 - - uint8_t rptb7; -} __packed; - - -static const uint8_t ridx2rate[] = - { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }; - -/* HW rate indices. */ -#define URTWN_RIDX_CCK1 0 -#define URTWN_RIDX_CCK11 3 -#define URTWN_RIDX_OFDM6 4 -#define URTWN_RIDX_OFDM24 8 -#define URTWN_RIDX_OFDM54 11 - -#define URTWN_RIDX_COUNT 28 -#define URTWN_RIDX_UNKNOWN (uint8_t)-1 - - -/* - * MAC initialization values. - */ -static const struct { - uint16_t reg; - uint8_t val; -} rtl8188eu_mac[] = { - { 0x026, 0x41 }, { 0x027, 0x35 }, { 0x040, 0x00 }, { 0x428, 0x0a }, - { 0x429, 0x10 }, { 0x430, 0x00 }, { 0x431, 0x01 }, { 0x432, 0x02 }, - { 0x433, 0x04 }, { 0x434, 0x05 }, { 0x435, 0x06 }, { 0x436, 0x07 }, - { 0x437, 0x08 }, { 0x438, 0x00 }, { 0x439, 0x00 }, { 0x43a, 0x01 }, - { 0x43b, 0x02 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, { 0x43e, 0x06 }, - { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 }, { 0x442, 0x00 }, - { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f }, { 0x447, 0x00 }, - { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 }, { 0x45b, 0xb9 }, - { 0x460, 0x66 }, { 0x461, 0x66 }, { 0x480, 0x08 }, { 0x4c8, 0xff }, - { 0x4c9, 0x08 }, { 0x4cc, 0xff }, { 0x4cd, 0xff }, { 0x4ce, 0x01 }, - { 0x4d3, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, { 0x502, 0x2f }, - { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, { 0x506, 0x5e }, - { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, { 0x50a, 0x5e }, - { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, { 0x50e, 0x00 }, - { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, { 0x516, 0x0a }, - { 0x525, 0x4f }, { 0x550, 0x10 }, { 0x551, 0x10 }, { 0x559, 0x02 }, - { 0x55d, 0xff }, { 0x605, 0x30 }, { 0x608, 0x0e }, { 0x609, 0x2a }, - { 0x620, 0xff }, { 0x621, 0xff }, { 0x622, 0xff }, { 0x623, 0xff }, - { 0x624, 0xff }, { 0x625, 0xff }, { 0x626, 0xff }, { 0x627, 0xff }, - { 0x652, 0x20 }, { 0x63c, 0x0a }, { 0x63d, 0x0a }, { 0x63e, 0x0e }, - { 0x63f, 0x0e }, { 0x640, 0x40 }, { 0x66e, 0x05 }, { 0x700, 0x21 }, - { 0x701, 0x43 }, { 0x702, 0x65 }, { 0x703, 0x87 }, { 0x708, 0x21 }, - { 0x709, 0x43 }, { 0x70a, 0x65 }, { 0x70b, 0x87 } -}, rtl8192cu_mac[] = { - { 0x420, 0x80 }, { 0x423, 0x00 }, { 0x430, 0x00 }, { 0x431, 0x00 }, - { 0x432, 0x00 }, { 0x433, 0x01 }, { 0x434, 0x04 }, { 0x435, 0x05 }, - { 0x436, 0x06 }, { 0x437, 0x07 }, { 0x438, 0x00 }, { 0x439, 0x00 }, - { 0x43a, 0x00 }, { 0x43b, 0x01 }, { 0x43c, 0x04 }, { 0x43d, 0x05 }, - { 0x43e, 0x06 }, { 0x43f, 0x07 }, { 0x440, 0x5d }, { 0x441, 0x01 }, - { 0x442, 0x00 }, { 0x444, 0x15 }, { 0x445, 0xf0 }, { 0x446, 0x0f }, - { 0x447, 0x00 }, { 0x458, 0x41 }, { 0x459, 0xa8 }, { 0x45a, 0x72 }, - { 0x45b, 0xb9 }, { 0x460, 0x66 }, { 0x461, 0x66 }, { 0x462, 0x08 }, - { 0x463, 0x03 }, { 0x4c8, 0xff }, { 0x4c9, 0x08 }, { 0x4cc, 0xff }, - { 0x4cd, 0xff }, { 0x4ce, 0x01 }, { 0x500, 0x26 }, { 0x501, 0xa2 }, - { 0x502, 0x2f }, { 0x503, 0x00 }, { 0x504, 0x28 }, { 0x505, 0xa3 }, - { 0x506, 0x5e }, { 0x507, 0x00 }, { 0x508, 0x2b }, { 0x509, 0xa4 }, - { 0x50a, 0x5e }, { 0x50b, 0x00 }, { 0x50c, 0x4f }, { 0x50d, 0xa4 }, - { 0x50e, 0x00 }, { 0x50f, 0x00 }, { 0x512, 0x1c }, { 0x514, 0x0a }, - { 0x515, 0x10 }, { 0x516, 0x0a }, { 0x517, 0x10 }, { 0x51a, 0x16 }, - { 0x524, 0x0f }, { 0x525, 0x4f }, { 0x546, 0x40 }, { 0x547, 0x00 }, - { 0x550, 0x10 }, { 0x551, 0x10 }, { 0x559, 0x02 }, { 0x55a, 0x02 }, - { 0x55d, 0xff }, { 0x605, 0x30 }, { 0x608, 0x0e }, { 0x609, 0x2a }, - { 0x652, 0x20 }, { 0x63c, 0x0a }, { 0x63d, 0x0e }, { 0x63e, 0x0a }, - { 0x63f, 0x0e }, { 0x66e, 0x05 }, { 0x700, 0x21 }, { 0x701, 0x43 }, - { 0x702, 0x65 }, { 0x703, 0x87 }, { 0x708, 0x21 }, { 0x709, 0x43 }, - { 0x70a, 0x65 }, { 0x70b, 0x87 } -}; - -/* - * Baseband initialization values. - */ -struct urtwn_bb_prog { - int count; - const uint16_t *regs; - const uint32_t *vals; - int agccount; - const uint32_t *agcvals; -}; - -/* - * RTL8192CU and RTL8192CE-VAU. - */ -static const uint16_t rtl8192ce_bb_regs[] = { - 0x024, 0x028, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, - 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, - 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, 0x860, - 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, 0x884, - 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, 0x908, - 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, - 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04, 0xc08, - 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, 0xc2c, - 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, - 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, 0xc74, - 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, 0xc98, - 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, 0xcbc, - 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc, 0xce0, - 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, 0xd08, 0xd0c, 0xd10, 0xd14, - 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c, 0xd40, 0xd44, 0xd48, - 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, 0xd60, 0xd64, 0xd68, 0xd6c, - 0xd70, 0xd74, 0xd78, 0xe00, 0xe04, 0xe08, 0xe10, 0xe14, 0xe18, - 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, 0xe48, - 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c, 0xe60, 0xe68, 0xe6c, 0xe70, - 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, 0xed0, 0xed4, - 0xed8, 0xedc, 0xee0, 0xeec, 0xf14, 0xf4c, 0xf00 -}; - -static const uint32_t rtl8192ce_bb_vals[] = { - 0x0011800d, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00, - 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, - 0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727, - 0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000, - 0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a, - 0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27, - 0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070, - 0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe, - 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, - 0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, - 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, - 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, - 0x48071d40, 0x03a05633, 0x000000e4, 0x6c6c6c6c, 0x08800000, - 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, - 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, - 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, - 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db, - 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100, - 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, - 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, - 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, - 0x00080740, 0x00020403, 0x0000907f, 0x20010201, 0xa0633333, - 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, - 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, - 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, - 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, - 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, - 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, - 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, - 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, 0x63db25a4, - 0x63db25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, - 0x63db25a4, 0x0c1b25a4, 0x63db25a4, 0x63db25a4, 0x63db25a4, - 0x63db25a4, 0x001b25a4, 0x001b25a4, 0x6fdb25a4, 0x00000003, - 0x00000000, 0x00000300 -}; - -static const uint32_t rtl8192ce_agc_vals[] = { - 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, - 0x7b050001, 0x7a060001, 0x79070001, 0x78080001, 0x77090001, - 0x760a0001, 0x750b0001, 0x740c0001, 0x730d0001, 0x720e0001, - 0x710f0001, 0x70100001, 0x6f110001, 0x6e120001, 0x6d130001, - 0x6c140001, 0x6b150001, 0x6a160001, 0x69170001, 0x68180001, - 0x67190001, 0x661a0001, 0x651b0001, 0x641c0001, 0x631d0001, - 0x621e0001, 0x611f0001, 0x60200001, 0x49210001, 0x48220001, - 0x47230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, - 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, - 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, - 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, - 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, - 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, - 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, - 0x7a460001, 0x79470001, 0x78480001, 0x77490001, 0x764a0001, - 0x754b0001, 0x744c0001, 0x734d0001, 0x724e0001, 0x714f0001, - 0x70500001, 0x6f510001, 0x6e520001, 0x6d530001, 0x6c540001, - 0x6b550001, 0x6a560001, 0x69570001, 0x68580001, 0x67590001, - 0x665a0001, 0x655b0001, 0x645c0001, 0x635d0001, 0x625e0001, - 0x615f0001, 0x60600001, 0x49610001, 0x48620001, 0x47630001, - 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, - 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, - 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, - 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, - 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, - 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, - 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, - 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, - 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, - 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, - 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, - 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e -}; - -static const struct urtwn_bb_prog rtl8192ce_bb_prog = { - nitems(rtl8192ce_bb_regs), - rtl8192ce_bb_regs, - rtl8192ce_bb_vals, - nitems(rtl8192ce_agc_vals), - rtl8192ce_agc_vals -}; - -/* - * RTL8188CU. - */ -static const uint32_t rtl8192cu_bb_vals[] = { - 0x0011800d, 0x00ffdb83, 0x80040002, 0x00000003, 0x0000fc00, - 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, - 0x01000100, 0x00390004, 0x01000100, 0x00390004, 0x27272727, - 0x27272727, 0x27272727, 0x27272727, 0x00010000, 0x00010000, - 0x27272727, 0x27272727, 0x00000000, 0x00000000, 0x569a569a, - 0x0c1b25a4, 0x66e60230, 0x061f0130, 0x27272727, 0x2b2b2b27, - 0x07000700, 0x22184000, 0x08080808, 0x00000000, 0xc0083070, - 0x000004d5, 0x00000000, 0xcc0000c0, 0x00000800, 0xfffffffe, - 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, - 0x81121313, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, - 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, - 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, - 0x48071d40, 0x03a05633, 0x000000e4, 0x6c6c6c6c, 0x08800000, - 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, - 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, - 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, - 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x0186115b, - 0x0000001f, 0x00b99612, 0x40000100, 0x20f60000, 0x40000100, - 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, - 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, - 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, - 0x00080740, 0x00020403, 0x0000907f, 0x20010201, 0xa0633333, - 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, - 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, - 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, - 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, - 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, - 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, - 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, - 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, 0x63db25a4, - 0x63db25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, 0x0c1b25a4, - 0x63db25a4, 0x0c1b25a4, 0x63db25a4, 0x63db25a4, 0x63db25a4, - 0x63db25a4, 0x001b25a4, 0x001b25a4, 0x6fdb25a4, 0x00000003, - 0x00000000, 0x00000300 -}; - -static const struct urtwn_bb_prog rtl8192cu_bb_prog = { - nitems(rtl8192ce_bb_regs), - rtl8192ce_bb_regs, - rtl8192cu_bb_vals, - nitems(rtl8192ce_agc_vals), - rtl8192ce_agc_vals -}; - -/* - * RTL8188CE-VAU. - */ -static const uint32_t rtl8188ce_bb_vals[] = { - 0x0011800d, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00, - 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, - 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a, - 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200, - 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070, - 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe, - 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, - 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, - 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, - 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, - 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, - 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, - 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, - 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, - 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db, - 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100, - 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, - 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, - 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, - 0x00080740, 0x00020401, 0x0000907f, 0x20010201, 0xa0633333, - 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, - 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, - 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, - 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, - 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, - 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, - 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, - 0x02140102, 0x28160d05, 0x00000008, 0x001b25a4, 0x631b25a0, - 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, - 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, - 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, 0x00000003, - 0x00000000, 0x00000300 -}; - -static const uint32_t rtl8188ce_agc_vals[] = { - 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, - 0x7b050001, 0x7a060001, 0x79070001, 0x78080001, 0x77090001, - 0x760a0001, 0x750b0001, 0x740c0001, 0x730d0001, 0x720e0001, - 0x710f0001, 0x70100001, 0x6f110001, 0x6e120001, 0x6d130001, - 0x6c140001, 0x6b150001, 0x6a160001, 0x69170001, 0x68180001, - 0x67190001, 0x661a0001, 0x651b0001, 0x641c0001, 0x631d0001, - 0x621e0001, 0x611f0001, 0x60200001, 0x49210001, 0x48220001, - 0x47230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, - 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, - 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, - 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, - 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, - 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, - 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, - 0x7a460001, 0x79470001, 0x78480001, 0x77490001, 0x764a0001, - 0x754b0001, 0x744c0001, 0x734d0001, 0x724e0001, 0x714f0001, - 0x70500001, 0x6f510001, 0x6e520001, 0x6d530001, 0x6c540001, - 0x6b550001, 0x6a560001, 0x69570001, 0x68580001, 0x67590001, - 0x665a0001, 0x655b0001, 0x645c0001, 0x635d0001, 0x625e0001, - 0x615f0001, 0x60600001, 0x49610001, 0x48620001, 0x47630001, - 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, - 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, - 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, - 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, - 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, - 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, - 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, - 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, - 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, - 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, - 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, - 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e -}; - -static const struct urtwn_bb_prog rtl8188ce_bb_prog = { - nitems(rtl8192ce_bb_regs), - rtl8192ce_bb_regs, - rtl8188ce_bb_vals, - nitems(rtl8188ce_agc_vals), - rtl8188ce_agc_vals -}; - -static const uint32_t rtl8188cu_bb_vals[] = { - 0x0011800d, 0x00ffdb83, 0x80040000, 0x00000001, 0x0000fc00, - 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, 0x00000000, - 0x01000100, 0x00390004, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00010000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x569a569a, - 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, 0x32323200, - 0x07000700, 0x22004000, 0x00000808, 0x00000000, 0xc0083070, - 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, 0xfffffffe, - 0x40302010, 0x00706050, 0x00000000, 0x00000023, 0x00000000, - 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e68120f, - 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, 0x1a1b0000, - 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, - 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, - 0x40000100, 0x08800000, 0x40000100, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, 0x49795994, - 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, - 0x6954341e, 0x43bc0094, 0x6954341e, 0x433c0094, 0x00000000, - 0x5116848b, 0x47c00bff, 0x00000036, 0x2c7f000d, 0x018610db, - 0x0000001f, 0x00b91612, 0x40000100, 0x20f60000, 0x40000100, - 0x20200000, 0x00121820, 0x00000000, 0x00121820, 0x00007f7f, - 0x00000000, 0x00000080, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x28000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x64b22427, - 0x00766932, 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, - 0x00080740, 0x00020401, 0x0000907f, 0x20010201, 0xa0633333, - 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, 0x80608000, - 0x00000000, 0x00027293, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x6437140a, 0x00000000, 0x00000000, 0x30032064, - 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, - 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, 0x03902a2a, - 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x00000000, - 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, - 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, - 0x02140102, 0x28160d05, 0x00000008, 0x001b25a4, 0x631b25a0, - 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, - 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, 0x631b25a0, - 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, 0x00000003, - 0x00000000, 0x00000300 -}; - -static const struct urtwn_bb_prog rtl8188cu_bb_prog = { - nitems(rtl8192ce_bb_regs), - rtl8192ce_bb_regs, - rtl8188cu_bb_vals, - nitems(rtl8188ce_agc_vals), - rtl8188ce_agc_vals -}; - -/* - * RTL8188EU. - */ -static const uint16_t rtl8188eu_bb_regs[] = { - 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, 0x818, 0x81c, - 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, 0x83c, - 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, - 0x860, 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, - 0x880, 0x884, 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, - 0x900, 0x904, 0x908, 0x90c, 0x910, 0x914, 0xa00, 0xa04, - 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, 0xa1c, 0xa20, 0xa24, - 0xa28, 0xa2c, 0xa70, 0xa74, 0xa78, 0xa7c, 0xa80, 0xb2c, - 0xc00, 0xc04, 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, - 0xc20, 0xc24, 0xc28, 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, - 0xc40, 0xc44, 0xc48, 0xc4c, 0xc50, 0xc54, 0xc58, 0xc5c, - 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, 0xc74, 0xc78, 0xc7c, - 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, 0xc98, 0xc9c, - 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, 0xcbc, - 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc, - 0xce0, 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, 0xd08, 0xd0c, - 0xd10, 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c, - 0xd40, 0xd44, 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, - 0xd60, 0xd64, 0xd68, 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00, - 0xe04, 0xe08, 0xe10, 0xe14, 0xe18, 0xe1c, 0xe28, 0xe30, - 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, 0xe48, 0xe4c, 0xe50, - 0xe54, 0xe58, 0xe5c, 0xe60, 0xe68, 0xe6c, 0xe70, 0xe74, - 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, 0xed0, 0xed4, - 0xed8, 0xedc, 0xee0, 0xee8, 0xeec, 0xf14, 0xf4c, 0xf00 -}; - -static const uint32_t rtl8188eu_bb_vals[] = { - 0x80040000, 0x00000003, 0x0000fc00, 0x0000000a, 0x10001331, - 0x020c3d10, 0x02200385, 0x00000000, 0x01000100, 0x00390204, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00010000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x569a11a9, 0x01000014, 0x66f60110, - 0x061f0649, 0x00000000, 0x27272700, 0x07000760, 0x25004000, - 0x00000808, 0x00000000, 0xb0000c1c, 0x00000001, 0x00000000, - 0xccc000c0, 0x00000800, 0xfffffffe, 0x40302010, 0x00706050, - 0x00000000, 0x00000023, 0x00000000, 0x81121111, 0x00000002, - 0x00000201, 0x00d047c8, 0x80ff000c, 0x8c838300, 0x2e7f120f, - 0x9500bb78, 0x1114d028, 0x00881117, 0x89140f00, 0x1a1b0000, - 0x090e1317, 0x00000204, 0x00d30000, 0x101fbf00, 0x00000007, - 0x00000900, 0x225b0606, 0x218075b1, 0x80000000, 0x48071d40, - 0x03a05611, 0x000000e4, 0x6c6c6c6c, 0x08800000, 0x40000100, - 0x08800000, 0x40000100, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x69e9ac47, 0x469652af, 0x49795994, 0x0a97971c, - 0x1f7c403f, 0x000100b7, 0xec020107, 0x007f037f, 0x69553420, - 0x43bc0094, 0x00013169, 0x00250492, 0x00000000, 0x7112848b, - 0x47c00bff, 0x00000036, 0x2c7f000d, 0x020610db, 0x0000001f, - 0x00b91612, 0x390000e4, 0x20f60000, 0x40000100, 0x20200000, - 0x00091521, 0x00000000, 0x00121820, 0x00007f7f, 0x00000000, - 0x000300a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x28000000, 0x00000000, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x64b22427, 0x00766932, - 0x00222222, 0x00000000, 0x37644302, 0x2f97d40c, 0x00000740, - 0x00020401, 0x0000907f, 0x20010201, 0xa0633333, 0x3333bc43, - 0x7a8f5b6f, 0xcc979975, 0x00000000, 0x80608000, 0x00000000, - 0x00127353, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x6437140a, 0x00000000, 0x00000282, 0x30032064, 0x4653de68, - 0x04518a3c, 0x00002101, 0x2a201c16, 0x1812362e, 0x322c2220, - 0x000e3c24, 0x2d2d2d2d, 0x2d2d2d2d, 0x0390272d, 0x2d2d2d2d, - 0x2d2d2d2d, 0x2d2d2d2d, 0x2d2d2d2d, 0x00000000, 0x1000dc1f, - 0x10008c1f, 0x02140102, 0x681604c2, 0x01007c00, 0x01004800, - 0xfb000000, 0x000028d1, 0x1000dc1f, 0x10008c1f, 0x02140102, - 0x28160d05, 0x00000008, 0x001b25a4, 0x00c00014, 0x00c00014, - 0x01000014, 0x01000014, 0x01000014, 0x01000014, 0x00c00014, - 0x01000014, 0x00c00014, 0x00c00014, 0x00c00014, 0x00c00014, - 0x00000014, 0x00000014, 0x21555448, 0x01c00014, 0x00000003, - 0x00000000, 0x00000300 -}; - -static const uint32_t rtl8188eu_agc_vals[] = { - 0xfb000001, 0xfb010001, 0xfb020001, 0xfb030001, 0xfb040001, - 0xfb050001, 0xfa060001, 0xf9070001, 0xf8080001, 0xf7090001, - 0xf60a0001, 0xf50b0001, 0xf40c0001, 0xf30d0001, 0xf20e0001, - 0xf10f0001, 0xf0100001, 0xef110001, 0xee120001, 0xed130001, - 0xec140001, 0xeb150001, 0xea160001, 0xe9170001, 0xe8180001, - 0xe7190001, 0xe61a0001, 0xe51b0001, 0xe41c0001, 0xe31d0001, - 0xe21e0001, 0xe11f0001, 0x8a200001, 0x89210001, 0x88220001, - 0x87230001, 0x86240001, 0x85250001, 0x84260001, 0x83270001, - 0x82280001, 0x6b290001, 0x6a2a0001, 0x692b0001, 0x682c0001, - 0x672d0001, 0x662e0001, 0x652f0001, 0x64300001, 0x63310001, - 0x62320001, 0x61330001, 0x46340001, 0x45350001, 0x44360001, - 0x43370001, 0x42380001, 0x41390001, 0x403a0001, 0x403b0001, - 0x403c0001, 0x403d0001, 0x403e0001, 0x403f0001, 0xfb400001, - 0xfb410001, 0xfb420001, 0xfb430001, 0xfb440001, 0xfb450001, - 0xfb460001, 0xfb470001, 0xfb480001, 0xfa490001, 0xf94a0001, - 0xf84B0001, 0xf74c0001, 0xf64d0001, 0xf54e0001, 0xf44f0001, - 0xf3500001, 0xf2510001, 0xf1520001, 0xf0530001, 0xef540001, - 0xee550001, 0xed560001, 0xec570001, 0xeb580001, 0xea590001, - 0xe95a0001, 0xe85b0001, 0xe75c0001, 0xe65d0001, 0xe55e0001, - 0xe45f0001, 0xe3600001, 0xe2610001, 0xc3620001, 0xc2630001, - 0xc1640001, 0x8b650001, 0x8a660001, 0x89670001, 0x88680001, - 0x87690001, 0x866a0001, 0x856b0001, 0x846c0001, 0x676d0001, - 0x666e0001, 0x656f0001, 0x64700001, 0x63710001, 0x62720001, - 0x61730001, 0x60740001, 0x46750001, 0x45760001, 0x44770001, - 0x43780001, 0x42790001, 0x417a0001, 0x407b0001, 0x407c0001, - 0x407d0001, 0x407e0001, 0x407f0001 -}; - -static const struct urtwn_bb_prog rtl8188eu_bb_prog = { - nitems(rtl8188eu_bb_regs), - rtl8188eu_bb_regs, - rtl8188eu_bb_vals, - nitems(rtl8188eu_agc_vals), - rtl8188eu_agc_vals -}; - -/* - * RTL8188RU. - */ -static const uint16_t rtl8188ru_bb_regs[] = { - 0x024, 0x028, 0x040, 0x800, 0x804, 0x808, 0x80c, 0x810, 0x814, - 0x818, 0x81c, 0x820, 0x824, 0x828, 0x82c, 0x830, 0x834, 0x838, - 0x83c, 0x840, 0x844, 0x848, 0x84c, 0x850, 0x854, 0x858, 0x85c, - 0x860, 0x864, 0x868, 0x86c, 0x870, 0x874, 0x878, 0x87c, 0x880, - 0x884, 0x888, 0x88c, 0x890, 0x894, 0x898, 0x89c, 0x900, 0x904, - 0x908, 0x90c, 0xa00, 0xa04, 0xa08, 0xa0c, 0xa10, 0xa14, 0xa18, - 0xa1c, 0xa20, 0xa24, 0xa28, 0xa2c, 0xa70, 0xa74, 0xc00, 0xc04, - 0xc08, 0xc0c, 0xc10, 0xc14, 0xc18, 0xc1c, 0xc20, 0xc24, 0xc28, - 0xc2c, 0xc30, 0xc34, 0xc38, 0xc3c, 0xc40, 0xc44, 0xc48, 0xc4c, - 0xc50, 0xc54, 0xc58, 0xc5c, 0xc60, 0xc64, 0xc68, 0xc6c, 0xc70, - 0xc74, 0xc78, 0xc7c, 0xc80, 0xc84, 0xc88, 0xc8c, 0xc90, 0xc94, - 0xc98, 0xc9c, 0xca0, 0xca4, 0xca8, 0xcac, 0xcb0, 0xcb4, 0xcb8, - 0xcbc, 0xcc0, 0xcc4, 0xcc8, 0xccc, 0xcd0, 0xcd4, 0xcd8, 0xcdc, - 0xce0, 0xce4, 0xce8, 0xcec, 0xd00, 0xd04, 0xd08, 0xd0c, 0xd10, - 0xd14, 0xd18, 0xd2c, 0xd30, 0xd34, 0xd38, 0xd3c, 0xd40, 0xd44, - 0xd48, 0xd4c, 0xd50, 0xd54, 0xd58, 0xd5c, 0xd60, 0xd64, 0xd68, - 0xd6c, 0xd70, 0xd74, 0xd78, 0xe00, 0xe04, 0xe08, 0xe10, 0xe14, - 0xe18, 0xe1c, 0xe28, 0xe30, 0xe34, 0xe38, 0xe3c, 0xe40, 0xe44, - 0xe48, 0xe4c, 0xe50, 0xe54, 0xe58, 0xe5c, 0xe60, 0xe68, 0xe6c, - 0xe70, 0xe74, 0xe78, 0xe7c, 0xe80, 0xe84, 0xe88, 0xe8c, 0xed0, - 0xed4, 0xed8, 0xedc, 0xee0, 0xeec, 0xee8, 0xf14, 0xf4c, 0xf00 -}; - -static const uint32_t rtl8188ru_bb_vals[] = { - 0x0011800d, 0x00ffdb83, 0x000c0004, 0x80040000, 0x00000001, - 0x0000fc00, 0x0000000a, 0x10005388, 0x020c3d10, 0x02200385, - 0x00000000, 0x01000100, 0x00390204, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00010000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x569a569a, 0x001b25a4, 0x66e60230, 0x061f0130, 0x00000000, - 0x32323200, 0x03000300, 0x22004000, 0x00000808, 0x00ffc3f1, - 0xc0083070, 0x000004d5, 0x00000000, 0xccc000c0, 0x00000800, - 0xfffffffe, 0x40302010, 0x00706050, 0x00000000, 0x00000023, - 0x00000000, 0x81121111, 0x00d047c8, 0x80ff000c, 0x8c838300, - 0x2e68120f, 0x9500bb78, 0x11144028, 0x00881117, 0x89140f00, - 0x15160000, 0x070b0f12, 0x00000104, 0x00d30000, 0x101fbf00, - 0x00000007, 0x48071d40, 0x03a05611, 0x000000e4, 0x6c6c6c6c, - 0x08800000, 0x40000100, 0x08800000, 0x40000100, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x69e9ac44, 0x469652cf, - 0x49795994, 0x0a97971c, 0x1f7c403f, 0x000100b7, 0xec020107, - 0x007f037f, 0x6954342e, 0x43bc0094, 0x6954342f, 0x433c0094, - 0x00000000, 0x5116848b, 0x47c00bff, 0x00000036, 0x2c56000d, - 0x018610db, 0x0000001f, 0x00b91612, 0x24000090, 0x20f60000, - 0x24000090, 0x20200000, 0x00121820, 0x00000000, 0x00121820, - 0x00007f7f, 0x00000000, 0x00000080, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x28000000, 0x00000000, - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - 0x64b22427, 0x00766932, 0x00222222, 0x00000000, 0x37644302, - 0x2f97d40c, 0x00080740, 0x00020401, 0x0000907f, 0x20010201, - 0xa0633333, 0x3333bc43, 0x7a8f5b6b, 0xcc979975, 0x00000000, - 0x80608000, 0x00000000, 0x00027293, 0x00000000, 0x00000000, - 0x00000000, 0x00000000, 0x6437140a, 0x00000000, 0x00000000, - 0x30032064, 0x4653de68, 0x04518a3c, 0x00002101, 0x2a201c16, - 0x1812362e, 0x322c2220, 0x000e3c24, 0x2a2a2a2a, 0x2a2a2a2a, - 0x03902a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, 0x2a2a2a2a, - 0x00000000, 0x1000dc1f, 0x10008c1f, 0x02140102, 0x681604c2, - 0x01007c00, 0x01004800, 0xfb000000, 0x000028d1, 0x1000dc1f, - 0x10008c1f, 0x02140102, 0x28160d05, 0x00000010, 0x001b25a4, - 0x631b25a0, 0x631b25a0, 0x081b25a0, 0x081b25a0, 0x081b25a0, - 0x081b25a0, 0x631b25a0, 0x081b25a0, 0x631b25a0, 0x631b25a0, - 0x631b25a0, 0x631b25a0, 0x001b25a0, 0x001b25a0, 0x6b1b25a0, - 0x31555448, 0x00000003, 0x00000000, 0x00000300 -}; - -static const uint32_t rtl8188ru_agc_vals[] = { - 0x7b000001, 0x7b010001, 0x7b020001, 0x7b030001, 0x7b040001, - 0x7b050001, 0x7b060001, 0x7b070001, 0x7b080001, 0x7a090001, - 0x790a0001, 0x780b0001, 0x770c0001, 0x760d0001, 0x750e0001, - 0x740f0001, 0x73100001, 0x72110001, 0x71120001, 0x70130001, - 0x6f140001, 0x6e150001, 0x6d160001, 0x6c170001, 0x6b180001, - 0x6a190001, 0x691a0001, 0x681b0001, 0x671c0001, 0x661d0001, - 0x651e0001, 0x641f0001, 0x63200001, 0x62210001, 0x61220001, - 0x60230001, 0x46240001, 0x45250001, 0x44260001, 0x43270001, - 0x42280001, 0x41290001, 0x402a0001, 0x262b0001, 0x252c0001, - 0x242d0001, 0x232e0001, 0x222f0001, 0x21300001, 0x20310001, - 0x06320001, 0x05330001, 0x04340001, 0x03350001, 0x02360001, - 0x01370001, 0x00380001, 0x00390001, 0x003a0001, 0x003b0001, - 0x003c0001, 0x003d0001, 0x003e0001, 0x003f0001, 0x7b400001, - 0x7b410001, 0x7b420001, 0x7b430001, 0x7b440001, 0x7b450001, - 0x7b460001, 0x7b470001, 0x7b480001, 0x7a490001, 0x794a0001, - 0x784b0001, 0x774c0001, 0x764d0001, 0x754e0001, 0x744f0001, - 0x73500001, 0x72510001, 0x71520001, 0x70530001, 0x6f540001, - 0x6e550001, 0x6d560001, 0x6c570001, 0x6b580001, 0x6a590001, - 0x695a0001, 0x685b0001, 0x675c0001, 0x665d0001, 0x655e0001, - 0x645f0001, 0x63600001, 0x62610001, 0x61620001, 0x60630001, - 0x46640001, 0x45650001, 0x44660001, 0x43670001, 0x42680001, - 0x41690001, 0x406a0001, 0x266b0001, 0x256c0001, 0x246d0001, - 0x236e0001, 0x226f0001, 0x21700001, 0x20710001, 0x06720001, - 0x05730001, 0x04740001, 0x03750001, 0x02760001, 0x01770001, - 0x00780001, 0x00790001, 0x007a0001, 0x007b0001, 0x007c0001, - 0x007d0001, 0x007e0001, 0x007f0001, 0x3800001e, 0x3801001e, - 0x3802001e, 0x3803001e, 0x3804001e, 0x3805001e, 0x3806001e, - 0x3807001e, 0x3808001e, 0x3c09001e, 0x3e0a001e, 0x400b001e, - 0x440c001e, 0x480d001e, 0x4c0e001e, 0x500f001e, 0x5210001e, - 0x5611001e, 0x5a12001e, 0x5e13001e, 0x6014001e, 0x6015001e, - 0x6016001e, 0x6217001e, 0x6218001e, 0x6219001e, 0x621a001e, - 0x621b001e, 0x621c001e, 0x621d001e, 0x621e001e, 0x621f001e -}; - -static const struct urtwn_bb_prog rtl8188ru_bb_prog = { - nitems(rtl8188ru_bb_regs), - rtl8188ru_bb_regs, - rtl8188ru_bb_vals, - nitems(rtl8188ru_agc_vals), - rtl8188ru_agc_vals -}; - -/* - * RF initialization values. - */ -struct urtwn_rf_prog { - int count; - const uint8_t *regs; - const uint32_t *vals; -}; - -/* - * RTL8192CU and RTL8192CE-VAU. - */ -static const uint8_t rtl8192ce_rf1_regs[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, - 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2a, 0x2b, - 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, - 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, - 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, - 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, - 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, 0x2c, 0x2a, 0x2b, 0x2b, - 0x2c, 0x2a, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, - 0x11, 0x10, 0x11, 0x10, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, - 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x00, - 0x18, 0xfe, 0xfe, 0x1f, 0xfe, 0xfe, 0x1e, 0x1f, 0x00 -}; - -static const uint32_t rtl8192ce_rf1_vals[] = { - 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, - 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255, - 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000, - 0x00000, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x577c0, - 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, - 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, - 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, - 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, - 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, - 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, - 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, - 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, - 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, - 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, - 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0x32000, - 0x71000, 0xb0000, 0xfc000, 0x287af, 0x244b7, 0x204ab, 0x1c49f, - 0x18493, 0x14297, 0x10295, 0x0c298, 0x0819c, 0x040a8, 0x0001c, - 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424, - 0xcf424, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, - 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000, - 0x30159 -}; - -static const uint8_t rtl8192ce_rf2_regs[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, - 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, - 0x15, 0x15, 0x16, 0x16, 0x16, 0x16 -}; - -static const uint32_t rtl8192ce_rf2_vals[] = { - 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, - 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x32000, 0x71000, - 0xb0000, 0xfc000, 0x287af, 0x244b7, 0x204ab, 0x1c49f, 0x18493, - 0x14297, 0x10295, 0x0c298, 0x0819c, 0x040a8, 0x0001c, 0x1944c, - 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424, 0xcf424, - 0xe0330, 0xa0330, 0x60330, 0x20330 -}; - -static const struct urtwn_rf_prog rtl8192ce_rf_prog[] = { - { - nitems(rtl8192ce_rf1_regs), - rtl8192ce_rf1_regs, - rtl8192ce_rf1_vals - }, - { - nitems(rtl8192ce_rf2_regs), - rtl8192ce_rf2_regs, - rtl8192ce_rf2_vals - } -}; - -/* - * RTL8188CE-VAU. - */ -static const uint32_t rtl8188ce_rf_vals[] = { - 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, - 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255, - 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000, - 0x00000, 0x01558, 0x00060, 0x00483, 0x4f200, 0xec7d9, 0x577c0, - 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, - 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, - 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, - 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, - 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, - 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, - 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, - 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, - 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, - 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, - 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0x32000, - 0x71000, 0xb0000, 0xfc000, 0x287b3, 0x244b7, 0x204ab, 0x1c49f, - 0x18493, 0x1429b, 0x10299, 0x0c29c, 0x081a0, 0x040ac, 0x00020, - 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f424, 0x4f424, 0x8f424, - 0xcf424, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, - 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000, - 0x30159 -}; - -static const struct urtwn_rf_prog rtl8188ce_rf_prog[] = { - { - nitems(rtl8192ce_rf1_regs), - rtl8192ce_rf1_regs, - rtl8188ce_rf_vals - } -}; - - -/* - * RTL8188CU. - */ -static const uint32_t rtl8188cu_rf_vals[] = { - 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb1, - 0x54867, 0x8992e, 0x0e52c, 0x39ce7, 0x00451, 0x00000, 0x10255, - 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000, - 0x00000, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x577c0, - 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, - 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, - 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, - 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, - 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, - 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, - 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, - 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, - 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, - 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, - 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0x32000, - 0x71000, 0xb0000, 0xfc000, 0x287b3, 0x244b7, 0x204ab, 0x1c49f, - 0x18493, 0x1429b, 0x10299, 0x0c29c, 0x081a0, 0x040ac, 0x00020, - 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f405, 0x4f405, 0x8f405, - 0xcf405, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, - 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000, - 0x30159 -}; - -static const struct urtwn_rf_prog rtl8188cu_rf_prog[] = { - { - nitems(rtl8192ce_rf1_regs), - rtl8192ce_rf1_regs, - rtl8188cu_rf_vals - } -}; - -/* - * RTL8188EU. - */ -static const uint8_t rtl8188eu_rf_regs[] = { - 0x00, 0x08, 0x18, 0x19, 0x1e, 0x1f, 0x2f, 0x3f, 0x42, 0x57, - 0x58, 0x67, 0x83, 0xb0, 0xb1, 0xb2, 0xb4, 0xb6, 0xb7, 0xb8, - 0xb9, 0xba, 0xbb, 0xbf, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xdf, 0xef, 0x51, 0x52, 0x53, 0x56, - 0x35, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0xb6, 0x18, 0x5a, - 0x19, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, - 0x34, 0x34, 0x00, 0x84, 0x86, 0x87, 0x8e, 0x8f, 0xef, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, - 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0xef, 0x00, 0x18, 0xfe, 0xfe, - 0x1f, 0xfe, 0xfe, 0x1e, 0x1f, 0x00 -}; - -static const uint32_t rtl8188eu_rf_vals[] = { - 0x30000, 0x84000, 0x00407, 0x00012, 0x80009, 0x00880, 0x1a060, - 0x00000, 0x060c0, 0xd0000, 0xbe180, 0x01552, 0x00000, 0xff8fc, - 0x54400, 0xccc19, 0x43003, 0x4953e, 0x1c718, 0x060ff, 0x80001, - 0x40000, 0x00400, 0xc0000, 0x02400, 0x00009, 0x40c91, 0x99999, - 0x000a3, 0x88820, 0x76c06, 0x00000, 0x80000, 0x00180, 0x001a0, - 0x6b27d, 0x7e49d, 0x00073, 0x51ff3, 0x00086, 0x00186, - 0x00286, 0x01c25, 0x09c25, 0x11c25, 0x19c25, 0x48538, 0x00c07, - 0x4bd00, 0x739d0, 0x0adf3, 0x09df0, 0x08ded, 0x07dea, 0x06de7, - 0x054ee, 0x044eb, 0x034e8, 0x0246b, 0x01468, 0x0006d, 0x30159, - 0x68200, 0x000ce, 0x48a00, 0x65540, 0x88000, 0x020a0, 0xf02b0, - 0xef7b0, 0xd4fb0, 0xcf060, 0xb0090, 0xa0080, 0x90080, 0x8f780, - 0x722b0, 0x6f7b0, 0x54fb0, 0x4f060, 0x30090, 0x20080, 0x10080, - 0x0f780, 0x000a0, 0x10159, 0x0f407, 0x00000, 0x00000, 0x80003, - 0x00000, 0x00000, 0x00001, 0x80000, 0x33e60 -}; - -static const struct urtwn_rf_prog rtl8188eu_rf_prog[] = { - { - nitems(rtl8188eu_rf_regs), - rtl8188eu_rf_regs, - rtl8188eu_rf_vals - } -}; - -/* - * RTL8188RU. - */ -static const uint32_t rtl8188ru_rf_vals[] = { - 0x30159, 0x31284, 0x98000, 0x18c63, 0x210e7, 0x2044f, 0x1adb0, - 0x54867, 0x8992e, 0x0e529, 0x39ce7, 0x00451, 0x00000, 0x00255, - 0x60a00, 0xfc378, 0xa1250, 0x4445f, 0x80001, 0x0b614, 0x6c000, - 0x0083c, 0x01558, 0x00060, 0x00483, 0x4f000, 0xec7d9, 0x977c0, - 0x04783, 0x00001, 0x21334, 0x00000, 0x00054, 0x00001, 0x00808, - 0x53333, 0x0000c, 0x00002, 0x00808, 0x5b333, 0x0000d, 0x00003, - 0x00808, 0x63333, 0x0000d, 0x00004, 0x00808, 0x6b333, 0x0000d, - 0x00005, 0x00808, 0x73333, 0x0000d, 0x00006, 0x00709, 0x5b333, - 0x0000d, 0x00007, 0x00709, 0x63333, 0x0000d, 0x00008, 0x0060a, - 0x4b333, 0x0000d, 0x00009, 0x0060a, 0x53333, 0x0000d, 0x0000a, - 0x0060a, 0x5b333, 0x0000d, 0x0000b, 0x0060a, 0x63333, 0x0000d, - 0x0000c, 0x0060a, 0x6b333, 0x0000d, 0x0000d, 0x0060a, 0x73333, - 0x0000d, 0x0000e, 0x0050b, 0x66666, 0x0001a, 0xe0000, 0x4000f, - 0xe31fc, 0x6000f, 0xff9f8, 0x2000f, 0x203f9, 0x3000f, 0xff500, - 0x00000, 0x00000, 0x8000f, 0x3f100, 0x9000f, 0x23100, 0xd8000, - 0x90000, 0x51000, 0x12000, 0x28fb4, 0x24fa8, 0x207a4, 0x1c798, - 0x183a4, 0x14398, 0x101a4, 0x0c198, 0x080a4, 0x04098, 0x00014, - 0x1944c, 0x59444, 0x9944c, 0xd9444, 0x0f405, 0x4f405, 0x8f405, - 0xcf405, 0xe0330, 0xa0330, 0x60330, 0x20330, 0x10159, 0x0f401, - 0x00000, 0x00000, 0x80003, 0x00000, 0x00000, 0x44457, 0x80000, - 0x30159 -}; - -static const struct urtwn_rf_prog rtl8188ru_rf_prog[] = { - { - nitems(rtl8192ce_rf1_regs), - rtl8192ce_rf1_regs, - rtl8188ru_rf_vals - } -}; - -struct urtwn_txpwr { - uint8_t pwr[3][28]; -}; - -struct urtwn_r88e_txpwr { - uint8_t pwr[6][28]; -}; - -/* - * Per RF chain/group/rate Tx gain values. - */ -static const struct urtwn_txpwr rtl8192cu_txagc[] = { - { { /* Chain 0. */ - { /* Group 0. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x0c, 0x0c, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* OFDM6~54. */ - 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02, /* MCS0~7. */ - 0x0e, 0x0d, 0x0c, 0x0a, 0x08, 0x06, 0x04, 0x02 /* MCS8~15. */ - }, - { /* Group 1. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - }, - { /* Group 2. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - } - } }, - { { /* Chain 1. */ - { /* Group 0. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - }, - { /* Group 1. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - }, - { /* Group 2. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x04, 0x04, 0x04, 0x04, 0x04, 0x02, 0x02, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - } - } } -}; - -static const struct urtwn_txpwr rtl8188ru_txagc[] = { - { { /* Chain 0. */ - { /* Group 0. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x08, 0x08, 0x08, 0x06, 0x06, 0x04, 0x04, 0x00, /* OFDM6~54. */ - 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00, /* MCS0~7. */ - 0x08, 0x06, 0x06, 0x04, 0x04, 0x02, 0x02, 0x00 /* MCS8~15. */ - }, - { /* Group 1. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - }, - { /* Group 2. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - } - } } -}; - -static const struct urtwn_r88e_txpwr rtl8188eu_txagc[] = { - { { /* Chain 0. */ - { /* Group 0. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - }, - { /* Group 1. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - }, - { /* Group 2. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - }, - { /* Group 3. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - }, - { /* Group 4. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - }, - { /* Group 5. */ - 0x00, 0x00, 0x00, 0x00, /* CCK1~11. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* OFDM6~54. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* MCS0~7. */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* MCS8~15. */ - } - } } -}; diff --git a/sys/dev/urtwn/if_urtwnvar.h b/sys/dev/urtwn/if_urtwnvar.h deleted file mode 100644 index 71c6f4e2b666..000000000000 --- a/sys/dev/urtwn/if_urtwnvar.h +++ /dev/null @@ -1,230 +0,0 @@ -/*- - * Copyright (c) 2010 Damien Bergamini - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - * $OpenBSD: if_urtwnreg.h,v 1.3 2010/11/16 18:02:59 damien Exp $ - * $FreeBSD$ - */ - -#define URTWN_RX_LIST_COUNT 64 -#define URTWN_TX_LIST_COUNT 8 -#define URTWN_HOST_CMD_RING_COUNT 32 - -#define URTWN_RXBUFSZ (8 * 1024) -//#define URTWN_TXBUFSZ (sizeof(struct r92c_tx_desc) + IEEE80211_MAX_LEN) -/* Leave enough space for an A-MSDU frame */ -#define URTWN_TXBUFSZ (16 * 1024) -#define URTWN_RX_DESC_SIZE (sizeof(struct r92c_rx_stat)) -#define URTWN_TX_DESC_SIZE (sizeof(struct r92c_tx_desc)) - -#define URTWN_TX_TIMEOUT 5000 /* ms */ - -#define URTWN_LED_LINK 0 -#define URTWN_LED_DATA 1 - -struct urtwn_rx_radiotap_header { - struct ieee80211_radiotap_header wr_ihdr; - uint64_t wr_tsft; - uint8_t wr_flags; - uint8_t wr_rate; - uint16_t wr_chan_freq; - uint16_t wr_chan_flags; - int8_t wr_dbm_antsignal; - int8_t wr_dbm_antnoise; -} __packed __aligned(8); - -#define URTWN_RX_RADIOTAP_PRESENT \ - (1 << IEEE80211_RADIOTAP_TSFT | \ - 1 << IEEE80211_RADIOTAP_FLAGS | \ - 1 << IEEE80211_RADIOTAP_RATE | \ - 1 << IEEE80211_RADIOTAP_CHANNEL | \ - 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL | \ - 1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) - -struct urtwn_tx_radiotap_header { - struct ieee80211_radiotap_header wt_ihdr; - uint8_t wt_flags; - uint16_t wt_chan_freq; - uint16_t wt_chan_flags; -} __packed __aligned(8); - -#define URTWN_TX_RADIOTAP_PRESENT \ - (1 << IEEE80211_RADIOTAP_FLAGS | \ - 1 << IEEE80211_RADIOTAP_CHANNEL) - -struct urtwn_softc; - -struct urtwn_data { - struct urtwn_softc *sc; - uint8_t *buf; - uint16_t buflen; - struct mbuf *m; - struct ieee80211_node *ni; - STAILQ_ENTRY(urtwn_data) next; -}; -typedef STAILQ_HEAD(, urtwn_data) urtwn_datahead; - -union sec_param { - struct ieee80211_key key; -}; - -#define CMD_FUNC_PROTO void (*func)(struct urtwn_softc *, \ - union sec_param *) - -struct urtwn_cmdq { - union sec_param data; - CMD_FUNC_PROTO; -}; -#define URTWN_CMDQ_SIZE 16 - -struct urtwn_fw_info { - const uint8_t *data; - size_t size; -}; - -struct urtwn_node { - struct ieee80211_node ni; /* must be the first */ - uint8_t id; - int last_rssi; -}; -#define URTWN_NODE(ni) ((struct urtwn_node *)(ni)) - -struct urtwn_vap { - struct ieee80211vap vap; - - struct r92c_tx_desc bcn_desc; - struct mbuf *bcn_mbuf; - struct task tsf_task_adhoc; - - const struct ieee80211_key *keys[IEEE80211_WEP_NKID]; - - int (*newstate)(struct ieee80211vap *, - enum ieee80211_state, int); - void (*recv_mgmt)(struct ieee80211_node *, - struct mbuf *, int, - const struct ieee80211_rx_stats *, - int, int); -}; -#define URTWN_VAP(vap) ((struct urtwn_vap *)(vap)) - -enum { - URTWN_BULK_RX, - URTWN_BULK_TX_BE, /* = WME_AC_BE */ - URTWN_BULK_TX_BK, /* = WME_AC_BK */ - URTWN_BULK_TX_VI, /* = WME_AC_VI */ - URTWN_BULK_TX_VO, /* = WME_AC_VI */ - URTWN_N_TRANSFER = 5, -}; - -#define URTWN_EP_QUEUES URTWN_BULK_RX - -union urtwn_rom { - struct r92c_rom r92c_rom; - struct r88e_rom r88e_rom; -}; - -struct urtwn_softc { - struct ieee80211com sc_ic; - struct ieee80211_ratectl_tx_status sc_txs; - struct mbufq sc_snd; - device_t sc_dev; - struct usb_device *sc_udev; - - uint32_t sc_debug; - uint8_t sc_iface_index; - uint8_t sc_flags; -#define URTWN_FLAG_CCK_HIPWR 0x01 -#define URTWN_DETACHED 0x02 -#define URTWN_RUNNING 0x04 -#define URTWN_FW_LOADED 0x08 -#define URTWN_TEMP_MEASURED 0x10 - - u_int chip; -#define URTWN_CHIP_92C 0x01 -#define URTWN_CHIP_92C_1T2R 0x02 -#define URTWN_CHIP_UMC 0x04 -#define URTWN_CHIP_UMC_A_CUT 0x08 -#define URTWN_CHIP_88E 0x10 - -#define URTWN_CHIP_HAS_RATECTL(_sc) (!!((_sc)->chip & URTWN_CHIP_88E)) - - void (*sc_node_free)(struct ieee80211_node *); - void (*sc_rf_write)(struct urtwn_softc *, - int, uint8_t, uint32_t); - int (*sc_power_on)(struct urtwn_softc *); - void (*sc_power_off)(struct urtwn_softc *); - - struct ieee80211_node *node_list[R88E_MACID_MAX + 1]; - struct mtx nt_mtx; - - uint8_t board_type; - uint8_t regulatory; - uint8_t pa_setting; - int8_t ofdm_tx_pwr_diff; - int8_t bw20_tx_pwr_diff; - int avg_pwdb; - uint8_t thcal_lctemp; - int ntxchains; - int nrxchains; - int ledlink; - int sc_txtimer; - - int last_rssi; - - int fwcur; - struct urtwn_data sc_rx[URTWN_RX_LIST_COUNT]; - urtwn_datahead sc_rx_active; - urtwn_datahead sc_rx_inactive; - struct urtwn_data sc_tx[URTWN_TX_LIST_COUNT]; - urtwn_datahead sc_tx_active; - int sc_tx_n_active; - urtwn_datahead sc_tx_inactive; - urtwn_datahead sc_tx_pending; - - union urtwn_rom rom; - uint16_t last_rom_addr; - - struct callout sc_calib_to; - struct callout sc_watchdog_ch; - struct mtx sc_mtx; - uint32_t keys_bmap; - - struct urtwn_cmdq cmdq[URTWN_CMDQ_SIZE]; - struct mtx cmdq_mtx; - struct task cmdq_task; - uint8_t cmdq_first; - uint8_t cmdq_last; - - uint32_t rf_chnlbw[R92C_MAX_CHAINS]; - struct usb_xfer *sc_xfer[URTWN_N_TRANSFER]; - - struct urtwn_rx_radiotap_header sc_rxtap; - struct urtwn_tx_radiotap_header sc_txtap; -}; - -#define URTWN_LOCK(sc) mtx_lock(&(sc)->sc_mtx) -#define URTWN_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) -#define URTWN_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED) - -#define URTWN_CMDQ_LOCK_INIT(sc) \ - mtx_init(&(sc)->cmdq_mtx, "cmdq lock", NULL, MTX_DEF) -#define URTWN_CMDQ_LOCK(sc) mtx_lock(&(sc)->cmdq_mtx) -#define URTWN_CMDQ_UNLOCK(sc) mtx_unlock(&(sc)->cmdq_mtx) -#define URTWN_CMDQ_LOCK_DESTROY(sc) mtx_destroy(&(sc)->cmdq_mtx) - -#define URTWN_NT_LOCK_INIT(sc) \ - mtx_init(&(sc)->nt_mtx, "node table lock", NULL, MTX_DEF) -#define URTWN_NT_LOCK(sc) mtx_lock(&(sc)->nt_mtx) -#define URTWN_NT_UNLOCK(sc) mtx_unlock(&(sc)->nt_mtx) -#define URTWN_NT_LOCK_DESTROY(sc) mtx_destroy(&(sc)->nt_mtx) diff --git a/sys/dev/usb/controller/at91dci_atmelarm.c b/sys/dev/usb/controller/at91dci_atmelarm.c index e352cc82aa6b..0dc1f9f19294 100644 --- a/sys/dev/usb/controller/at91dci_atmelarm.c +++ b/sys/dev/usb/controller/at91dci_atmelarm.c @@ -243,14 +243,8 @@ static int at91_udp_detach(device_t dev) { struct at91_udp_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_dci.sc_bus.bdev) { - bdev = sc->sc_dci.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/dev/usb/controller/at91dci_fdt.c b/sys/dev/usb/controller/at91dci_fdt.c index ba5ce27e6d1b..431b502bd252 100644 --- a/sys/dev/usb/controller/at91dci_fdt.c +++ b/sys/dev/usb/controller/at91dci_fdt.c @@ -249,14 +249,8 @@ static int at91_udp_detach(device_t dev) { struct at91_udp_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_dci.sc_bus.bdev) { - bdev = sc->sc_dci.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/dev/usb/controller/atmegadci_atmelarm.c b/sys/dev/usb/controller/atmegadci_atmelarm.c index 7c052e6ee9e2..d89ba8b70bcf 100644 --- a/sys/dev/usb/controller/atmegadci_atmelarm.c +++ b/sys/dev/usb/controller/atmegadci_atmelarm.c @@ -155,14 +155,8 @@ static int atmegadci_detach(device_t dev) { struct atmegadci_super_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_otg.sc_bus.bdev) { - bdev = sc->sc_otg.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/dev/usb/controller/dwc_otg_fdt.c b/sys/dev/usb/controller/dwc_otg_fdt.c index 20ab0c5acf06..80d3388050ff 100644 --- a/sys/dev/usb/controller/dwc_otg_fdt.c +++ b/sys/dev/usb/controller/dwc_otg_fdt.c @@ -163,14 +163,8 @@ static int dwc_otg_detach(device_t dev) { struct dwc_otg_fdt_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_otg.sc_bus.bdev) { - bdev = sc->sc_otg.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/dev/usb/controller/ehci_ixp4xx.c b/sys/dev/usb/controller/ehci_ixp4xx.c index 1b2f6409d053..02554ecf1d40 100644 --- a/sys/dev/usb/controller/ehci_ixp4xx.c +++ b/sys/dev/usb/controller/ehci_ixp4xx.c @@ -221,14 +221,8 @@ ehci_ixp_detach(device_t self) { struct ixp_ehci_softc *isc = device_get_softc(self); ehci_softc_t *sc = &isc->base; - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/dev/usb/controller/ehci_mv.c b/sys/dev/usb/controller/ehci_mv.c index cd7d549aaf46..f433b4be9c55 100644 --- a/sys/dev/usb/controller/ehci_mv.c +++ b/sys/dev/usb/controller/ehci_mv.c @@ -264,14 +264,8 @@ static int mv_ehci_detach(device_t self) { ehci_softc_t *sc = device_get_softc(self); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/dev/usb/controller/ehci_pci.c b/sys/dev/usb/controller/ehci_pci.c index cad351cda846..c69d28c45fde 100644 --- a/sys/dev/usb/controller/ehci_pci.c +++ b/sys/dev/usb/controller/ehci_pci.c @@ -477,13 +477,7 @@ static int ehci_pci_detach(device_t self) { ehci_softc_t *sc = device_get_softc(self); - device_t bdev; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/dev/usb/controller/generic_ehci.c b/sys/dev/usb/controller/generic_ehci.c index fcae7dd41a99..53356526fc3d 100644 --- a/sys/dev/usb/controller/generic_ehci.c +++ b/sys/dev/usb/controller/generic_ehci.c @@ -156,14 +156,8 @@ static int generic_ehci_detach(device_t self) { ehci_softc_t *sc = device_get_softc(self); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/dev/usb/controller/generic_ohci.c b/sys/dev/usb/controller/generic_ohci.c index beafd0614b67..44d2419ab86c 100644 --- a/sys/dev/usb/controller/generic_ohci.c +++ b/sys/dev/usb/controller/generic_ohci.c @@ -214,18 +214,11 @@ static int generic_ohci_detach(device_t dev) { struct generic_ohci_softc *sc = device_get_softc(dev); - device_t bdev; int err; #ifdef EXT_RESOURCES struct clk_list *clk, *clk_tmp; #endif - if (sc->ohci_sc.sc_bus.bdev) { - bdev = sc->ohci_sc.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } - /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/dev/usb/controller/musb_otg_atmelarm.c b/sys/dev/usb/controller/musb_otg_atmelarm.c index 3f1b9f834143..b752e630f48f 100644 --- a/sys/dev/usb/controller/musb_otg_atmelarm.c +++ b/sys/dev/usb/controller/musb_otg_atmelarm.c @@ -204,14 +204,8 @@ static int musbotg_detach(device_t dev) { struct musbotg_super_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_otg.sc_bus.bdev) { - bdev = sc->sc_otg.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/dev/usb/controller/ohci_pci.c b/sys/dev/usb/controller/ohci_pci.c index 96950a72c61d..31a1f57b9929 100644 --- a/sys/dev/usb/controller/ohci_pci.c +++ b/sys/dev/usb/controller/ohci_pci.c @@ -335,13 +335,7 @@ static int ohci_pci_detach(device_t self) { ohci_softc_t *sc = device_get_softc(self); - device_t bdev; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/dev/usb/controller/ohci_s3c24x0.c b/sys/dev/usb/controller/ohci_s3c24x0.c index 28c195a0ba57..2e0682766fc3 100644 --- a/sys/dev/usb/controller/ohci_s3c24x0.c +++ b/sys/dev/usb/controller/ohci_s3c24x0.c @@ -148,14 +148,8 @@ static int ohci_s3c24x0_detach(device_t dev) { struct ohci_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/dev/usb/controller/saf1761_otg_boot.c b/sys/dev/usb/controller/saf1761_otg_boot.c index a2acf066950e..cc9e9a16ef95 100644 --- a/sys/dev/usb/controller/saf1761_otg_boot.c +++ b/sys/dev/usb/controller/saf1761_otg_boot.c @@ -124,13 +124,6 @@ static int saf1761_otg_fdt_detach(device_t dev) { struct saf1761_otg_softc *sc = device_get_softc(dev); - device_t bdev; - - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/dev/usb/controller/saf1761_otg_fdt.c b/sys/dev/usb/controller/saf1761_otg_fdt.c index 19c64e7b3443..0d7f2933a84e 100644 --- a/sys/dev/usb/controller/saf1761_otg_fdt.c +++ b/sys/dev/usb/controller/saf1761_otg_fdt.c @@ -238,14 +238,8 @@ static int saf1761_otg_fdt_detach(device_t dev) { struct saf1761_otg_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/dev/usb/controller/uhci_pci.c b/sys/dev/usb/controller/uhci_pci.c index 5916996fff87..2f8b4647cc1d 100644 --- a/sys/dev/usb/controller/uhci_pci.c +++ b/sys/dev/usb/controller/uhci_pci.c @@ -393,13 +393,7 @@ int uhci_pci_detach(device_t self) { uhci_softc_t *sc = device_get_softc(self); - device_t bdev; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/dev/usb/controller/uss820dci_atmelarm.c b/sys/dev/usb/controller/uss820dci_atmelarm.c index dcd4db4bc977..2684d38d49db 100644 --- a/sys/dev/usb/controller/uss820dci_atmelarm.c +++ b/sys/dev/usb/controller/uss820dci_atmelarm.c @@ -164,14 +164,8 @@ static int uss820_atmelarm_detach(device_t dev) { struct uss820dci_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/dev/usb/controller/xhci_mv.c b/sys/dev/usb/controller/xhci_mv.c index 06b35ce337bc..9be09bb436ea 100644 --- a/sys/dev/usb/controller/xhci_mv.c +++ b/sys/dev/usb/controller/xhci_mv.c @@ -171,15 +171,8 @@ static int xhci_detach(device_t dev) { struct xhci_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_bus.bdev != NULL) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } - /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/dev/usb/controller/xhci_pci.c b/sys/dev/usb/controller/xhci_pci.c index 09fab21a8806..35d1ea475c3f 100644 --- a/sys/dev/usb/controller/xhci_pci.c +++ b/sys/dev/usb/controller/xhci_pci.c @@ -340,13 +340,7 @@ static int xhci_pci_detach(device_t self) { struct xhci_softc *sc = device_get_softc(self); - device_t bdev; - if (sc->sc_bus.bdev != NULL) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index 62c3f74e7041..bc0f50e5ead3 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -1103,10 +1103,8 @@ usb_detach_device_sub(struct usb_device *udev, device_t *ppdev, device_printf(dev, "Resume failed\n"); } } - if (device_detach(dev)) { - goto error; - } } + /* detach and delete child */ if (device_delete_child(udev->parent_dev, dev)) { goto error; } diff --git a/sys/dev/usb/video/udl.c b/sys/dev/usb/video/udl.c index 1096ed355095..a15d41b5650b 100644 --- a/sys/dev/usb/video/udl.c +++ b/sys/dev/usb/video/udl.c @@ -443,14 +443,9 @@ udl_detach(device_t dev) { struct udl_softc *sc = device_get_softc(dev); - if (sc->sc_fbdev != NULL) { - device_t bdev; + /* delete all child devices */ + device_delete_children(dev); - bdev = sc->sc_fbdev; - sc->sc_fbdev = NULL; - device_detach(bdev); - device_delete_child(dev, bdev); - } UDL_LOCK(sc); sc->sc_gone = 1; callout_stop(&sc->sc_callout); diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c index 1b90d021d6ca..c60f6436c6ff 100644 --- a/sys/fs/nfsserver/nfs_nfsdstate.c +++ b/sys/fs/nfsserver/nfs_nfsdstate.c @@ -70,6 +70,11 @@ SYSCTL_INT(_vfs_nfsd, OID_AUTO, v4statelimit, CTLFLAG_RWTUN, &nfsrv_v4statelimit, 0, "High water limit for NFSv4 opens+locks+delegations"); +static int nfsrv_writedelegifpos = 0; +SYSCTL_INT(_vfs_nfsd, OID_AUTO, writedelegifpos, CTLFLAG_RW, + &nfsrv_writedelegifpos, 0, + "Issue a write delegation for read opens if possible"); + /* * Hash lists for nfs V4. */ @@ -80,7 +85,6 @@ struct nfssessionhash *nfssessionhash; static u_int32_t nfsrv_openpluslock = 0, nfsrv_delegatecnt = 0; static time_t nfsrvboottime; -static int nfsrv_writedelegifpos = 1; static int nfsrv_returnoldstateid = 0, nfsrv_clients = 0; static int nfsrv_clienthighwater = NFSRV_CLIENTHIGHWATER; static int nfsrv_nogsscallback = 0; diff --git a/sys/geom/mirror/g_mirror.c b/sys/geom/mirror/g_mirror.c index 308e711fcc1d..52c007efd1d9 100644 --- a/sys/geom/mirror/g_mirror.c +++ b/sys/geom/mirror/g_mirror.c @@ -1252,13 +1252,6 @@ g_mirror_regular_release(struct g_mirror_softc *sc) G_MIRROR_LOGREQ(2, bp, "Releasing delayed request (%p).", bp); mtx_lock(&sc->sc_queue_mtx); bioq_insert_head(&sc->sc_queue, bp); -#if 0 - /* - * wakeup() is not needed, because this function is called from - * the worker thread. - */ - wakeup(&sc->sc_queue); -#endif mtx_unlock(&sc->sc_queue_mtx); } } @@ -1282,6 +1275,22 @@ g_mirror_sync_release(struct g_mirror_softc *sc) } } +/* + * Free a synchronization request and clear its slot in the array. + */ +static void +g_mirror_sync_request_free(struct g_mirror_disk *disk, struct bio *bp) +{ + int i; + + if (disk != NULL && disk->d_sync.ds_bios != NULL) { + i = (int)(uintptr_t)bp->bio_caller1; + disk->d_sync.ds_bios[i] = NULL; + } + free(bp->bio_data, M_MIRROR); + g_destroy_bio(bp); +} + /* * Handle synchronization requests. * Every synchronization request is two-steps process: first, READ request is @@ -1294,6 +1303,7 @@ g_mirror_sync_request(struct bio *bp) { struct g_mirror_softc *sc; struct g_mirror_disk *disk; + struct g_mirror_disk_sync *sync; bp->bio_from->index--; sc = bp->bio_from->geom->softc; @@ -1303,8 +1313,7 @@ g_mirror_sync_request(struct bio *bp) g_topology_lock(); g_mirror_kill_consumer(sc, bp->bio_from); g_topology_unlock(); - free(bp->bio_data, M_MIRROR); - g_destroy_bio(bp); + g_mirror_sync_request_free(NULL, bp); sx_xlock(&sc->sc_lock); return; } @@ -1324,7 +1333,7 @@ g_mirror_sync_request(struct bio *bp) G_MIRROR_LOGREQ(0, bp, "Synchronization request failed (error=%d).", bp->bio_error); - g_destroy_bio(bp); + g_mirror_sync_request_free(disk, bp); return; } G_MIRROR_LOGREQ(3, bp, @@ -1341,7 +1350,6 @@ g_mirror_sync_request(struct bio *bp) } case BIO_WRITE: { - struct g_mirror_disk_sync *sync; off_t offset; void *data; int i; @@ -1353,7 +1361,7 @@ g_mirror_sync_request(struct bio *bp) G_MIRROR_LOGREQ(0, bp, "Synchronization request failed (error=%d).", bp->bio_error); - g_destroy_bio(bp); + g_mirror_sync_request_free(disk, bp); sc->sc_bump_id |= G_MIRROR_BUMP_GENID; g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, @@ -1367,12 +1375,7 @@ g_mirror_sync_request(struct bio *bp) (sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) { /* Don't send more synchronization requests. */ sync->ds_inflight--; - if (sync->ds_bios != NULL) { - i = (int)(uintptr_t)bp->bio_caller1; - sync->ds_bios[i] = NULL; - } - free(bp->bio_data, M_MIRROR); - g_destroy_bio(bp); + g_mirror_sync_request_free(disk, bp); if (sync->ds_inflight > 0) return; if (sync->ds_consumer == NULL || @@ -2065,6 +2068,7 @@ g_mirror_sync_stop(struct g_mirror_disk *disk, int type) G_MIRROR_DEBUG(0, "Device %s: rebuilding provider %s stopped.", sc->sc_name, g_mirror_get_diskname(disk)); } + g_mirror_regular_release(sc); free(disk->d_sync.ds_bios, M_MIRROR); disk->d_sync.ds_bios = NULL; cp = disk->d_sync.ds_consumer; diff --git a/sys/i386/i386/bpf_jit_machdep.c b/sys/i386/i386/bpf_jit_machdep.c index e0aaf018cc4e..9f31dde17f0d 100644 --- a/sys/i386/i386/bpf_jit_machdep.c +++ b/sys/i386/i386/bpf_jit_machdep.c @@ -1,6 +1,6 @@ /*- * Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy) - * Copyright (C) 2005-2009 Jung-uk Kim + * Copyright (C) 2005-2016 Jung-uk Kim * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -83,12 +83,13 @@ emit_code(bpf_bin_stream *stream, u_int value, u_int len) break; case 2: - *((u_short *)(stream->ibuf + stream->cur_ip)) = (u_short)value; + *((u_short *)(void *)(stream->ibuf + stream->cur_ip)) = + (u_short)value; stream->cur_ip += 2; break; case 4: - *((u_int *)(stream->ibuf + stream->cur_ip)) = value; + *((u_int *)(void *)(stream->ibuf + stream->cur_ip)) = value; stream->cur_ip += 4; break; } @@ -138,6 +139,7 @@ bpf_jit_optimize(struct bpf_insn *prog, u_int nins) flags |= BPF_JIT_FJMP; break; case BPF_ALU|BPF_DIV|BPF_K: + case BPF_ALU|BPF_MOD|BPF_K: flags |= BPF_JIT_FADK; break; } @@ -445,75 +447,58 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) break; case BPF_JMP|BPF_JGT|BPF_K: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - CMPid(ins->k, EAX); - JCC(JA, JBE); - break; - case BPF_JMP|BPF_JGE|BPF_K: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - CMPid(ins->k, EAX); - JCC(JAE, JB); - break; - case BPF_JMP|BPF_JEQ|BPF_K: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - CMPid(ins->k, EAX); - JCC(JE, JNE); - break; - case BPF_JMP|BPF_JSET|BPF_K: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - TESTid(ins->k, EAX); - JCC(JNE, JE); - break; - case BPF_JMP|BPF_JGT|BPF_X: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - CMPrd(EDX, EAX); - JCC(JA, JBE); - break; - case BPF_JMP|BPF_JGE|BPF_X: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - CMPrd(EDX, EAX); - JCC(JAE, JB); - break; - case BPF_JMP|BPF_JEQ|BPF_X: - if (ins->jt == ins->jf) { - JUMP(ins->jt); - break; - } - CMPrd(EDX, EAX); - JCC(JE, JNE); - break; - case BPF_JMP|BPF_JSET|BPF_X: if (ins->jt == ins->jf) { JUMP(ins->jt); break; } - TESTrd(EDX, EAX); - JCC(JNE, JE); + switch (ins->code) { + case BPF_JMP|BPF_JGT|BPF_K: + CMPid(ins->k, EAX); + JCC(JA, JBE); + break; + + case BPF_JMP|BPF_JGE|BPF_K: + CMPid(ins->k, EAX); + JCC(JAE, JB); + break; + + case BPF_JMP|BPF_JEQ|BPF_K: + CMPid(ins->k, EAX); + JCC(JE, JNE); + break; + + case BPF_JMP|BPF_JSET|BPF_K: + TESTid(ins->k, EAX); + JCC(JNE, JE); + break; + + case BPF_JMP|BPF_JGT|BPF_X: + CMPrd(EDX, EAX); + JCC(JA, JBE); + break; + + case BPF_JMP|BPF_JGE|BPF_X: + CMPrd(EDX, EAX); + JCC(JAE, JB); + break; + + case BPF_JMP|BPF_JEQ|BPF_X: + CMPrd(EDX, EAX); + JCC(JE, JNE); + break; + + case BPF_JMP|BPF_JSET|BPF_X: + TESTrd(EDX, EAX); + JCC(JNE, JE); + break; + } break; case BPF_ALU|BPF_ADD|BPF_X: @@ -531,6 +516,7 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) break; case BPF_ALU|BPF_DIV|BPF_X: + case BPF_ALU|BPF_MOD|BPF_X: TESTrd(EDX, EDX); if (save_esp) { if (fpkt) { @@ -552,6 +538,8 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) MOVrd(EDX, ECX); ZEROrd(EDX); DIVrd(ECX); + if (BPF_OP(ins->code) == BPF_MOD) + MOVrd(EDX, EAX); MOVrd(ECX, EDX); break; @@ -563,6 +551,10 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) ORrd(EDX, EAX); break; + case BPF_ALU|BPF_XOR|BPF_X: + XORrd(EDX, EAX); + break; + case BPF_ALU|BPF_LSH|BPF_X: MOVrd(EDX, ECX); SHL_CLrb(EAX); @@ -589,10 +581,13 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) break; case BPF_ALU|BPF_DIV|BPF_K: + case BPF_ALU|BPF_MOD|BPF_K: MOVrd(EDX, ECX); ZEROrd(EDX); MOVid(ins->k, ESI); DIVrd(ESI); + if (BPF_OP(ins->code) == BPF_MOD) + MOVrd(EDX, EAX); MOVrd(ECX, EDX); break; @@ -604,6 +599,10 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) ORid(ins->k, EAX); break; + case BPF_ALU|BPF_XOR|BPF_K: + XORid(ins->k, EAX); + break; + case BPF_ALU|BPF_LSH|BPF_K: SHLib((ins->k) & 0xff, EAX); break; @@ -679,5 +678,5 @@ bpf_jit_compile(struct bpf_insn *prog, u_int nins, size_t *size) } #endif - return ((bpf_filter_func)stream.ibuf); + return ((bpf_filter_func)(void *)stream.ibuf); } diff --git a/sys/i386/i386/bpf_jit_machdep.h b/sys/i386/i386/bpf_jit_machdep.h index 4ae5494a72aa..22d66321794b 100644 --- a/sys/i386/i386/bpf_jit_machdep.h +++ b/sys/i386/i386/bpf_jit_machdep.h @@ -1,6 +1,6 @@ /*- * Copyright (C) 2002-2003 NetGroup, Politecnico di Torino (Italy) - * Copyright (C) 2005-2009 Jung-uk Kim + * Copyright (C) 2005-2016 Jung-uk Kim * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -302,6 +302,24 @@ typedef void (*emit_func)(bpf_bin_stream *stream, u_int value, u_int n); emitm(&stream, i32, 4); \ } while (0) +/* xorl sr32,dr32 */ +#define XORrd(sr32, dr32) do { \ + emitm(&stream, 0x31, 1); \ + emitm(&stream, \ + (3 << 6) | ((sr32 & 0x7) << 3) | (dr32 & 0x7), 1); \ +} while (0) + +/* xorl i32,r32 */ +#define XORid(i32, r32) do { \ + if (r32 == EAX) { \ + emitm(&stream, 0x35, 1); \ + } else { \ + emitm(&stream, 0x81, 1); \ + emitm(&stream, (25 << 3) | r32, 1); \ + } \ + emitm(&stream, i32, 4); \ +} while (0) + /* shll i8,r32 */ #define SHLib(i8, r32) do { \ emitm(&stream, 0xc1, 1); \ diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 915c84d55f9a..3c42bb72f9d4 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -204,9 +204,9 @@ void mi_startup(void) { - register struct sysinit **sipp; /* system initialization*/ - register struct sysinit **xipp; /* interior loop of sort*/ - register struct sysinit *save; /* bubble*/ + struct sysinit **sipp; /* system initialization*/ + struct sysinit **xipp; /* interior loop of sort*/ + struct sysinit *save; /* bubble*/ #if defined(VERBOSE_SYSINIT) int last; @@ -316,15 +316,6 @@ mi_startup(void) /* NOTREACHED*/ } - -/* - *************************************************************************** - **** - **** The following SYSINIT's belong elsewhere, but have not yet - **** been moved. - **** - *************************************************************************** - */ static void print_caddr_t(void *data) { @@ -418,17 +409,10 @@ struct sysentvec null_sysvec = { }; /* - *************************************************************************** - **** - **** The two following SYSINIT's are proc0 specific glue code. I am not - **** convinced that they can not be safely combined, but their order of - **** operation has been maintained as the same as the original init_main.c - **** for right now. - **** - **** These probably belong in init_proc.c or kern_proc.c, since they - **** deal with proc0 (the fork template process). - **** - *************************************************************************** + * The two following SYSINIT's are proc0 specific glue code. I am not + * convinced that they can not be safely combined, but their order of + * operation has been maintained as the same as the original init_main.c + * for right now. */ /* ARGSUSED*/ static void @@ -662,16 +646,6 @@ SYSINIT(random, SI_SUB_RANDOM, SI_ORDER_FIRST, random_init, NULL); *************************************************************************** */ - -/* - *************************************************************************** - **** - **** The following code probably belongs in another file, like - **** kern/init_init.c. - **** - *************************************************************************** - */ - /* * List of paths to try when searching for "init". */ diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index e573672f9f72..7d9adb050213 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -118,14 +118,14 @@ static int do_execve(struct thread *td, struct image_args *args, struct mac *mac_p); /* XXX This should be vm_size_t. */ -SYSCTL_PROC(_kern, KERN_PS_STRINGS, ps_strings, CTLTYPE_ULONG|CTLFLAG_RD, - NULL, 0, sysctl_kern_ps_strings, "LU", ""); +SYSCTL_PROC(_kern, KERN_PS_STRINGS, ps_strings, CTLTYPE_ULONG|CTLFLAG_RD| + CTLFLAG_MPSAFE, NULL, 0, sysctl_kern_ps_strings, "LU", ""); /* XXX This should be vm_size_t. */ SYSCTL_PROC(_kern, KERN_USRSTACK, usrstack, CTLTYPE_ULONG|CTLFLAG_RD| - CTLFLAG_CAPRD, NULL, 0, sysctl_kern_usrstack, "LU", ""); + CTLFLAG_CAPRD|CTLFLAG_MPSAFE, NULL, 0, sysctl_kern_usrstack, "LU", ""); -SYSCTL_PROC(_kern, OID_AUTO, stackprot, CTLTYPE_INT|CTLFLAG_RD, +SYSCTL_PROC(_kern, OID_AUTO, stackprot, CTLTYPE_INT|CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, 0, sysctl_kern_stackprot, "I", ""); u_long ps_arg_cache_limit = PAGE_SIZE / 16; diff --git a/sys/kern/kern_mib.c b/sys/kern/kern_mib.c index 6840b99ce6c6..5348b2c3fef1 100644 --- a/sys/kern/kern_mib.c +++ b/sys/kern/kern_mib.c @@ -135,7 +135,7 @@ SYSCTL_INT(_kern, KERN_SAVED_IDS, saved_ids, CTLFLAG_RD|CTLFLAG_CAPRD, char kernelname[MAXPATHLEN] = "/kernel"; /* XXX bloat */ -SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, CTLFLAG_RW, +SYSCTL_STRING(_kern, KERN_BOOTFILE, bootfile, CTLFLAG_RW | CTLFLAG_MPSAFE, kernelname, sizeof kernelname, "Name of kernel file booted"); SYSCTL_INT(_kern, KERN_MAXPHYS, maxphys, CTLFLAG_RD | CTLFLAG_CAPRD, @@ -257,8 +257,9 @@ sysctl_hw_machine_arch(SYSCTL_HANDLER_ARGS) return (error); } -SYSCTL_PROC(_hw, HW_MACHINE_ARCH, machine_arch, CTLTYPE_STRING | CTLFLAG_RD, - NULL, 0, sysctl_hw_machine_arch, "A", "System architecture"); +SYSCTL_PROC(_hw, HW_MACHINE_ARCH, machine_arch, CTLTYPE_STRING | CTLFLAG_RD | + CTLFLAG_MPSAFE, NULL, 0, sysctl_hw_machine_arch, "A", + "System architecture"); SYSCTL_STRING(_kern, OID_AUTO, supported_archs, CTLFLAG_RD | CTLFLAG_MPSAFE, #ifdef COMPAT_FREEBSD32 @@ -386,8 +387,8 @@ SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel, /* Actual kernel configuration options. */ extern char kernconfstring[]; -SYSCTL_STRING(_kern, OID_AUTO, conftxt, CTLFLAG_RD, kernconfstring, 0, - "Kernel configuration file"); +SYSCTL_STRING(_kern, OID_AUTO, conftxt, CTLFLAG_RD | CTLFLAG_MPSAFE, + kernconfstring, 0, "Kernel configuration file"); #endif static int diff --git a/sys/kern/makesyscalls.sh b/sys/kern/makesyscalls.sh index 896eb04753ca..3d362d8da986 100644 --- a/sys/kern/makesyscalls.sh +++ b/sys/kern/makesyscalls.sh @@ -65,7 +65,6 @@ if [ -n "$2" ]; then fi sed -e ' -s/\$//g :join /\\$/{a\ @@ -147,7 +146,7 @@ s/\$//g printf " * $%s$\n", "FreeBSD" > systrace } NR == 1 { - gsub("[$]FreeBSD: ", "", $0) + gsub("[$]FreeBSD: ", "FreeBSD: ", $0) gsub(" [$]", "", $0) printf " * created from%s\n */\n\n", $0 > syssw diff --git a/sys/kern/subr_bus.c b/sys/kern/subr_bus.c index 1e188d3cb681..d80c3d91075e 100644 --- a/sys/kern/subr_bus.c +++ b/sys/kern/subr_bus.c @@ -1949,15 +1949,17 @@ device_delete_child(device_t dev, device_t child) PDEBUG(("%s from %s", DEVICENAME(child), DEVICENAME(dev))); - /* remove children first */ + /* detach parent before deleting children, if any */ + if ((error = device_detach(child)) != 0) + return (error); + + /* remove children second */ while ((grandchild = TAILQ_FIRST(&child->children)) != NULL) { error = device_delete_child(child, grandchild); if (error) return (error); } - if ((error = device_detach(child)) != 0) - return (error); if (child->devclass) devclass_delete_device(child->devclass, child); if (child->parent) diff --git a/sys/kern/subr_gtaskqueue.c b/sys/kern/subr_gtaskqueue.c index 9bde3f71735b..6e9ec0711e2a 100644 --- a/sys/kern/subr_gtaskqueue.c +++ b/sys/kern/subr_gtaskqueue.c @@ -52,7 +52,6 @@ static MALLOC_DEFINE(M_GTASKQUEUE, "taskqueue", "Task Queues"); static void gtaskqueue_thread_enqueue(void *); static void gtaskqueue_thread_loop(void *arg); - struct gtaskqueue_busy { struct gtask *tb_running; TAILQ_ENTRY(gtaskqueue_busy) tb_link; @@ -554,7 +553,7 @@ struct taskq_bind_task { }; static void -taskqgroup_cpu_create(struct taskqgroup *qgroup, int idx) +taskqgroup_cpu_create(struct taskqgroup *qgroup, int idx, int cpu) { struct taskqgroup_cpu *qcpu; @@ -564,7 +563,7 @@ taskqgroup_cpu_create(struct taskqgroup *qgroup, int idx) taskqueue_thread_enqueue, &qcpu->tgc_taskq); gtaskqueue_start_threads(&qcpu->tgc_taskq, 1, PI_SOFT, "%s_%d", qgroup->tqg_name, idx); - qcpu->tgc_cpu = idx * qgroup->tqg_stride; + qcpu->tgc_cpu = cpu; } static void @@ -634,6 +633,7 @@ taskqgroup_attach(struct taskqgroup *qgroup, struct grouptask *gtask, LIST_INSERT_HEAD(&qgroup->tqg_queue[qid].tgc_tasks, gtask, gt_list); gtask->gt_taskqueue = qgroup->tqg_queue[qid].tgc_taskq; if (irq != -1 && smp_started) { + gtask->gt_cpu = qgroup->tqg_queue[qid].tgc_cpu; CPU_ZERO(&mask); CPU_SET(qgroup->tqg_queue[qid].tgc_cpu, &mask); mtx_unlock(&qgroup->tqg_lock); @@ -642,6 +642,33 @@ taskqgroup_attach(struct taskqgroup *qgroup, struct grouptask *gtask, mtx_unlock(&qgroup->tqg_lock); } +static void +taskqgroup_attach_deferred(struct taskqgroup *qgroup, struct grouptask *gtask) +{ + cpuset_t mask; + int qid, cpu; + + mtx_lock(&qgroup->tqg_lock); + qid = taskqgroup_find(qgroup, gtask->gt_uniq); + cpu = qgroup->tqg_queue[qid].tgc_cpu; + if (gtask->gt_irq != -1) { + mtx_unlock(&qgroup->tqg_lock); + + CPU_ZERO(&mask); + CPU_SET(cpu, &mask); + intr_setaffinity(gtask->gt_irq, &mask); + + mtx_lock(&qgroup->tqg_lock); + } + qgroup->tqg_queue[qid].tgc_cnt++; + + LIST_INSERT_HEAD(&qgroup->tqg_queue[qid].tgc_tasks, gtask, + gt_list); + MPASS(qgroup->tqg_queue[qid].tgc_taskq != NULL); + gtask->gt_taskqueue = qgroup->tqg_queue[qid].tgc_taskq; + mtx_unlock(&qgroup->tqg_lock); +} + int taskqgroup_attach_cpu(struct taskqgroup *qgroup, struct grouptask *gtask, void *uniq, int cpu, int irq, char *name) @@ -670,13 +697,47 @@ taskqgroup_attach_cpu(struct taskqgroup *qgroup, struct grouptask *gtask, qgroup->tqg_queue[qid].tgc_cnt++; LIST_INSERT_HEAD(&qgroup->tqg_queue[qid].tgc_tasks, gtask, gt_list); gtask->gt_taskqueue = qgroup->tqg_queue[qid].tgc_taskq; - if (irq != -1 && smp_started) { - CPU_ZERO(&mask); - CPU_SET(qgroup->tqg_queue[qid].tgc_cpu, &mask); - mtx_unlock(&qgroup->tqg_lock); + cpu = qgroup->tqg_queue[qid].tgc_cpu; + mtx_unlock(&qgroup->tqg_lock); + + CPU_ZERO(&mask); + CPU_SET(cpu, &mask); + if (irq != -1 && smp_started) intr_setaffinity(irq, &mask); - } else + return (0); +} + +static int +taskqgroup_attach_cpu_deferred(struct taskqgroup *qgroup, struct grouptask *gtask) +{ + cpuset_t mask; + int i, qid, irq, cpu; + + qid = -1; + irq = gtask->gt_irq; + cpu = gtask->gt_cpu; + MPASS(smp_started); + mtx_lock(&qgroup->tqg_lock); + for (i = 0; i < qgroup->tqg_cnt; i++) + if (qgroup->tqg_queue[i].tgc_cpu == cpu) { + qid = i; + break; + } + if (qid == -1) { mtx_unlock(&qgroup->tqg_lock); + return (EINVAL); + } + qgroup->tqg_queue[qid].tgc_cnt++; + LIST_INSERT_HEAD(&qgroup->tqg_queue[qid].tgc_tasks, gtask, gt_list); + MPASS(qgroup->tqg_queue[qid].tgc_taskq != NULL); + gtask->gt_taskqueue = qgroup->tqg_queue[qid].tgc_taskq; + mtx_unlock(&qgroup->tqg_lock); + + CPU_ZERO(&mask); + CPU_SET(cpu, &mask); + + if (irq != -1) + intr_setaffinity(irq, &mask); return (0); } @@ -727,6 +788,9 @@ taskqgroup_bind(struct taskqgroup *qgroup) * Bind taskqueue threads to specific CPUs, if they have been assigned * one. */ + if (qgroup->tqg_cnt == 1) + return; + for (i = 0; i < qgroup->tqg_cnt; i++) { gtask = malloc(sizeof (*gtask), M_DEVBUF, M_WAITOK); GTASK_INIT(>ask->bt_task, 0, 0, taskqgroup_binder, gtask); @@ -740,9 +804,8 @@ static int _taskqgroup_adjust(struct taskqgroup *qgroup, int cnt, int stride) { LIST_HEAD(, grouptask) gtask_head = LIST_HEAD_INITIALIZER(NULL); - cpuset_t mask; struct grouptask *gtask; - int i, k, old_cnt, qid, cpu; + int i, k, old_cnt, old_cpu, cpu; mtx_assert(&qgroup->tqg_lock, MA_OWNED); @@ -757,6 +820,9 @@ _taskqgroup_adjust(struct taskqgroup *qgroup, int cnt, int stride) } qgroup->tqg_adjusting = 1; old_cnt = qgroup->tqg_cnt; + old_cpu = 0; + if (old_cnt < cnt) + old_cpu = qgroup->tqg_queue[old_cnt].tgc_cpu; mtx_unlock(&qgroup->tqg_lock); /* * Set up queue for tasks added before boot. @@ -770,8 +836,13 @@ _taskqgroup_adjust(struct taskqgroup *qgroup, int cnt, int stride) /* * If new taskq threads have been added. */ - for (i = old_cnt; i < cnt; i++) - taskqgroup_cpu_create(qgroup, i); + cpu = old_cpu; + for (i = old_cnt; i < cnt; i++) { + taskqgroup_cpu_create(qgroup, i, cpu); + + for (k = 0; k < stride; k++) + cpu = CPU_NEXT(cpu); + } mtx_lock(&qgroup->tqg_lock); qgroup->tqg_cnt = cnt; qgroup->tqg_stride = stride; @@ -786,41 +857,25 @@ _taskqgroup_adjust(struct taskqgroup *qgroup, int cnt, int stride) LIST_INSERT_HEAD(>ask_head, gtask, gt_list); } } + mtx_unlock(&qgroup->tqg_lock); while ((gtask = LIST_FIRST(>ask_head))) { LIST_REMOVE(gtask, gt_list); if (gtask->gt_cpu == -1) - qid = taskqgroup_find(qgroup, gtask->gt_uniq); - else { - for (i = 0; i < qgroup->tqg_cnt; i++) - if (qgroup->tqg_queue[i].tgc_cpu == gtask->gt_cpu) { - qid = i; - break; - } - } - qgroup->tqg_queue[qid].tgc_cnt++; - LIST_INSERT_HEAD(&qgroup->tqg_queue[qid].tgc_tasks, gtask, - gt_list); - gtask->gt_taskqueue = qgroup->tqg_queue[qid].tgc_taskq; + taskqgroup_attach_deferred(qgroup, gtask); + else if (taskqgroup_attach_cpu_deferred(qgroup, gtask)) + taskqgroup_attach_deferred(qgroup, gtask); } - /* - * Set new CPU and IRQ affinity - */ - cpu = CPU_FIRST(); - for (i = 0; i < cnt; i++) { - qgroup->tqg_queue[i].tgc_cpu = cpu; - for (k = 0; k < qgroup->tqg_stride; k++) - cpu = CPU_NEXT(cpu); - CPU_ZERO(&mask); - CPU_SET(qgroup->tqg_queue[i].tgc_cpu, &mask); - LIST_FOREACH(gtask, &qgroup->tqg_queue[i].tgc_tasks, gt_list) { - if (gtask->gt_irq == -1) - continue; - intr_setaffinity(gtask->gt_irq, &mask); - } + +#ifdef INVARIANTS + mtx_lock(&qgroup->tqg_lock); + for (i = 0; i < qgroup->tqg_cnt; i++) { + MPASS(qgroup->tqg_queue[i].tgc_taskq != NULL); + LIST_FOREACH(gtask, &qgroup->tqg_queue[i].tgc_tasks, gt_list) + MPASS(gtask->gt_taskqueue != NULL); } mtx_unlock(&qgroup->tqg_lock); - +#endif /* * If taskq thread count has been reduced. */ @@ -836,12 +891,12 @@ _taskqgroup_adjust(struct taskqgroup *qgroup, int cnt, int stride) } int -taskqgroup_adjust(struct taskqgroup *qgroup, int cpu, int stride) +taskqgroup_adjust(struct taskqgroup *qgroup, int cnt, int stride) { int error; mtx_lock(&qgroup->tqg_lock); - error = _taskqgroup_adjust(qgroup, cpu, stride); + error = _taskqgroup_adjust(qgroup, cnt, stride); mtx_unlock(&qgroup->tqg_lock); return (error); diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c index 65fc9ab514eb..bf248f9a5dbb 100644 --- a/sys/kern/sys_capability.c +++ b/sys/kern/sys_capability.c @@ -89,6 +89,8 @@ SYSCTL_INT(_kern, OID_AUTO, trap_enotcap, CTLFLAG_RW, &trap_enotcap, 0, #ifdef CAPABILITY_MODE +#define IOCTLS_MAX_COUNT 256 /* XXX: Is 256 sane? */ + FEATURE(security_capability_mode, "Capsicum Capability Mode"); /* @@ -398,6 +400,11 @@ kern_cap_ioctls_limit(struct thread *td, int fd, u_long *cmds, size_t ncmds) AUDIT_ARG_FD(fd); + if (ncmds > IOCTLS_MAX_COUNT) { + error = EINVAL; + goto out_free; + } + fdp = td->td_proc->p_fd; FILEDESC_XLOCK(fdp); @@ -418,6 +425,7 @@ kern_cap_ioctls_limit(struct thread *td, int fd, u_long *cmds, size_t ncmds) error = 0; out: FILEDESC_XUNLOCK(fdp); +out_free: free(cmds, M_FILECAPS); return (error); } @@ -431,7 +439,7 @@ sys_cap_ioctls_limit(struct thread *td, struct cap_ioctls_limit_args *uap) ncmds = uap->ncmds; - if (ncmds > 256) /* XXX: Is 256 sane? */ + if (ncmds > IOCTLS_MAX_COUNT) return (EINVAL); if (ncmds == 0) { @@ -453,45 +461,59 @@ sys_cap_ioctls_get(struct thread *td, struct cap_ioctls_get_args *uap) { struct filedesc *fdp; struct filedescent *fdep; - u_long *cmds; - size_t maxcmds; + u_long *cmdsp, *dstcmds; + size_t maxcmds, ncmds; + int16_t count; int error, fd; fd = uap->fd; - cmds = uap->cmds; + dstcmds = uap->cmds; maxcmds = uap->maxcmds; AUDIT_ARG_FD(fd); fdp = td->td_proc->p_fd; - FILEDESC_SLOCK(fdp); - if (fget_locked(fdp, fd) == NULL) { + cmdsp = NULL; + if (dstcmds != NULL) { + cmdsp = malloc(sizeof(cmdsp[0]) * IOCTLS_MAX_COUNT, M_FILECAPS, + M_WAITOK | M_ZERO); + } + + FILEDESC_SLOCK(fdp); + fdep = fdeget_locked(fdp, fd); + if (fdep == NULL) { error = EBADF; + FILEDESC_SUNLOCK(fdp); goto out; } + count = fdep->fde_nioctls; + if (count != -1 && cmdsp != NULL) { + ncmds = MIN(count, maxcmds); + memcpy(cmdsp, fdep->fde_ioctls, sizeof(cmdsp[0]) * ncmds); + } + FILEDESC_SUNLOCK(fdp); /* * If all ioctls are allowed (fde_nioctls == -1 && fde_ioctls == NULL) * the only sane thing we can do is to not populate the given array and * return CAP_IOCTLS_ALL. */ - - fdep = &fdp->fd_ofiles[fd]; - if (cmds != NULL && fdep->fde_ioctls != NULL) { - error = copyout(fdep->fde_ioctls, cmds, - sizeof(cmds[0]) * MIN(fdep->fde_nioctls, maxcmds)); - if (error != 0) - goto out; - } - if (fdep->fde_nioctls == -1) + if (count != -1) { + if (cmdsp != NULL) { + error = copyout(cmdsp, dstcmds, + sizeof(cmdsp[0]) * ncmds); + if (error != 0) + goto out; + } + td->td_retval[0] = count; + } else { td->td_retval[0] = CAP_IOCTLS_ALL; - else - td->td_retval[0] = fdep->fde_nioctls; + } error = 0; out: - FILEDESC_SUNLOCK(fdp); + free(cmdsp, M_FILECAPS); return (error); } diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index d5037912da91..6101f186f938 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -84,8 +84,10 @@ SDT_PROBE_DEFINE1(vfs, namecache, purge_negative, done, "struct vnode *"); SDT_PROBE_DEFINE1(vfs, namecache, purgevfs, done, "struct mount *"); SDT_PROBE_DEFINE3(vfs, namecache, zap, done, "struct vnode *", "char *", "struct vnode *"); -SDT_PROBE_DEFINE2(vfs, namecache, zap_negative, done, "struct vnode *", - "char *"); +SDT_PROBE_DEFINE3(vfs, namecache, zap_negative, done, "struct vnode *", + "char *", "int"); +SDT_PROBE_DEFINE3(vfs, namecache, shrink_negative, done, "struct vnode *", + "char *", "int"); /* * This structure describes the elements in the cache of recent @@ -97,7 +99,10 @@ struct namecache { LIST_ENTRY(namecache) nc_src; /* source vnode list */ TAILQ_ENTRY(namecache) nc_dst; /* destination vnode list */ struct vnode *nc_dvp; /* vnode of parent of name */ - struct vnode *nc_vp; /* vnode the name refers to */ + union { + struct vnode *nu_vp; /* vnode the name refers to */ + u_int nu_neghits; /* negative entry hits */ + } n_un; u_char nc_flag; /* flag bits */ u_char nc_nlen; /* length of name */ char nc_name[0]; /* segment name + nul */ @@ -116,7 +121,10 @@ struct namecache_ts { LIST_ENTRY(namecache) nc_src; /* source vnode list */ TAILQ_ENTRY(namecache) nc_dst; /* destination vnode list */ struct vnode *nc_dvp; /* vnode of parent of name */ - struct vnode *nc_vp; /* vnode the name refers to */ + union { + struct vnode *nu_vp; /* vnode the name refers to */ + u_int nu_neghits; /* negative entry hits */ + } n_un; u_char nc_flag; /* flag bits */ u_char nc_nlen; /* length of name */ struct timespec nc_time; /* timespec provided by fs */ @@ -125,6 +133,9 @@ struct namecache_ts { char nc_name[0]; /* segment name + nul */ }; +#define nc_vp n_un.nu_vp +#define nc_neghits n_un.nu_neghits + /* * Flags in namecache.nc_flag */ @@ -133,6 +144,8 @@ struct namecache_ts { #define NCF_TS 0x04 #define NCF_DTS 0x08 #define NCF_DVDROP 0x10 +#define NCF_NEGATIVE 0x20 +#define NCF_HOTNEGATIVE 0x40 /* * Name caching works as follows: @@ -154,7 +167,7 @@ struct namecache_ts { * NAME TYPE ROLE * vnodelock mtx vnode lists and v_cache_dd field protection * bucketlock rwlock for access to given set of hash buckets - * ncneg_mtx mtx negative entry LRU management + * neglist mtx negative entry LRU management * * Additionally, ncneg_shrink_lock mtx is used to have at most one thread * shrinking the LRU list. @@ -188,7 +201,6 @@ struct namecache_ts { #define NCHHASH(hash) \ (&nchashtbl[(hash) & nchash]) static LIST_HEAD(nchashhead, namecache) *nchashtbl; /* Hash Table */ -static TAILQ_HEAD(, namecache) ncneg; /* Hash Table */ static u_long nchash; /* size of hash table */ SYSCTL_ULONG(_debug, OID_AUTO, nchash, CTLFLAG_RD, &nchash, 0, "Size of namecache hash table"); @@ -210,6 +222,9 @@ SYSCTL_UINT(_vfs, OID_AUTO, ncsizefactor, CTLFLAG_RW, &ncsizefactor, 0, static u_int ncpurgeminvnodes; SYSCTL_UINT(_vfs, OID_AUTO, ncpurgeminvnodes, CTLFLAG_RW, &ncpurgeminvnodes, 0, "Number of vnodes below which purgevfs ignores the request"); +static u_int ncneghitsrequeue = 8; +SYSCTL_UINT(_vfs, OID_AUTO, ncneghitsrequeue, CTLFLAG_RW, &ncneghitsrequeue, 0, + "Number of hits to requeue a negative entry in the LRU list"); struct nchstats nchstats; /* cache effectiveness statistics */ @@ -217,8 +232,23 @@ static struct mtx ncneg_shrink_lock; MTX_SYSINIT(vfscache_shrink_neg, &ncneg_shrink_lock, "Name Cache shrink neg", MTX_DEF); -static struct mtx_padalign ncneg_mtx; -MTX_SYSINIT(vfscache_neg, &ncneg_mtx, "ncneg", MTX_DEF); +struct neglist { + struct mtx nl_lock; + TAILQ_HEAD(, namecache) nl_list; +} __aligned(CACHE_LINE_SIZE); + +static struct neglist *neglists; +static struct neglist ncneg_hot; + +static int shrink_list_turn; + +static u_int numneglists; +static inline struct neglist * +NCP2NEGLIST(struct namecache *ncp) +{ + + return (&neglists[(((uintptr_t)(ncp) >> 8) % numneglists)]); +} static u_int numbucketlocks; static struct rwlock_padalign *bucketlocks; @@ -623,78 +653,189 @@ SYSCTL_PROC(_debug_hashstat, OID_AUTO, nchash, CTLTYPE_INT|CTLFLAG_RD| /* * Negative entries management + * + * A variation of LRU scheme is used. New entries are hashed into one of + * numneglists cold lists. Entries get promoted to the hot list on first hit. + * Partial LRU for the hot list is maintained by requeueing them every + * ncneghitsrequeue hits. + * + * The shrinker will demote hot list head and evict from the cold list in a + * round-robin manner. */ static void cache_negative_hit(struct namecache *ncp) { + struct neglist *neglist; + u_int hits; - MPASS(ncp->nc_vp == NULL); - mtx_lock(&ncneg_mtx); - TAILQ_REMOVE(&ncneg, ncp, nc_dst); - TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst); - mtx_unlock(&ncneg_mtx); + MPASS(ncp->nc_flag & NCF_NEGATIVE); + hits = atomic_fetchadd_int(&ncp->nc_neghits, 1); + if (ncp->nc_flag & NCF_HOTNEGATIVE) { + if ((hits % ncneghitsrequeue) != 0) + return; + mtx_lock(&ncneg_hot.nl_lock); + if (ncp->nc_flag & NCF_HOTNEGATIVE) { + TAILQ_REMOVE(&ncneg_hot.nl_list, ncp, nc_dst); + TAILQ_INSERT_TAIL(&ncneg_hot.nl_list, ncp, nc_dst); + mtx_unlock(&ncneg_hot.nl_lock); + return; + } + /* + * The shrinker cleared the flag and removed the entry from + * the hot list. Put it back. + */ + } else { + mtx_lock(&ncneg_hot.nl_lock); + } + neglist = NCP2NEGLIST(ncp); + mtx_lock(&neglist->nl_lock); + if (!(ncp->nc_flag & NCF_HOTNEGATIVE)) { + TAILQ_REMOVE(&neglist->nl_list, ncp, nc_dst); + TAILQ_INSERT_TAIL(&ncneg_hot.nl_list, ncp, nc_dst); + ncp->nc_flag |= NCF_HOTNEGATIVE; + } + mtx_unlock(&neglist->nl_lock); + mtx_unlock(&ncneg_hot.nl_lock); } static void -cache_negative_insert(struct namecache *ncp) +cache_negative_insert(struct namecache *ncp, bool neg_locked) { + struct neglist *neglist; - MPASS(ncp->nc_vp == NULL); + MPASS(ncp->nc_flag & NCF_NEGATIVE); cache_assert_bucket_locked(ncp, RA_WLOCKED); - mtx_lock(&ncneg_mtx); - TAILQ_INSERT_TAIL(&ncneg, ncp, nc_dst); - numneg++; - mtx_unlock(&ncneg_mtx); + neglist = NCP2NEGLIST(ncp); + if (!neg_locked) { + mtx_lock(&neglist->nl_lock); + } else { + mtx_assert(&neglist->nl_lock, MA_OWNED); + } + TAILQ_INSERT_TAIL(&neglist->nl_list, ncp, nc_dst); + if (!neg_locked) + mtx_unlock(&neglist->nl_lock); + atomic_add_rel_long(&numneg, 1); } static void cache_negative_remove(struct namecache *ncp, bool neg_locked) { + struct neglist *neglist; + bool hot_locked = false; + bool list_locked = false; - MPASS(ncp->nc_vp == NULL); + MPASS(ncp->nc_flag & NCF_NEGATIVE); cache_assert_bucket_locked(ncp, RA_WLOCKED); - if (!neg_locked) - mtx_lock(&ncneg_mtx); - else - mtx_assert(&ncneg_mtx, MA_OWNED); - TAILQ_REMOVE(&ncneg, ncp, nc_dst); - numneg--; - if (!neg_locked) - mtx_unlock(&ncneg_mtx); + neglist = NCP2NEGLIST(ncp); + if (!neg_locked) { + if (ncp->nc_flag & NCF_HOTNEGATIVE) { + hot_locked = true; + mtx_lock(&ncneg_hot.nl_lock); + if (!(ncp->nc_flag & NCF_HOTNEGATIVE)) { + list_locked = true; + mtx_lock(&neglist->nl_lock); + } + } else { + list_locked = true; + mtx_lock(&neglist->nl_lock); + } + } else { + mtx_assert(&neglist->nl_lock, MA_OWNED); + mtx_assert(&ncneg_hot.nl_lock, MA_OWNED); + } + if (ncp->nc_flag & NCF_HOTNEGATIVE) { + TAILQ_REMOVE(&ncneg_hot.nl_list, ncp, nc_dst); + } else { + TAILQ_REMOVE(&neglist->nl_list, ncp, nc_dst); + } + if (list_locked) + mtx_unlock(&neglist->nl_lock); + if (hot_locked) + mtx_unlock(&ncneg_hot.nl_lock); + atomic_subtract_rel_long(&numneg, 1); +} + +static void +cache_negative_shrink_select(int start, struct namecache **ncpp, + struct neglist **neglistpp) +{ + struct neglist *neglist; + struct namecache *ncp; + int i; + + *ncpp = ncp = NULL; + + for (i = start; i < numneglists; i++) { + neglist = &neglists[i]; + if (TAILQ_FIRST(&neglist->nl_list) == NULL) + continue; + mtx_lock(&neglist->nl_lock); + ncp = TAILQ_FIRST(&neglist->nl_list); + if (ncp != NULL) + break; + mtx_unlock(&neglist->nl_lock); + } + + *neglistpp = neglist; + *ncpp = ncp; } static void cache_negative_zap_one(void) { - struct namecache *ncp, *ncp2; + struct namecache *ncp, *ncp2, *ncpc; + struct neglist *neglist; struct mtx *dvlp; struct rwlock *blp; if (!mtx_trylock(&ncneg_shrink_lock)) return; - mtx_lock(&ncneg_mtx); - ncp = TAILQ_FIRST(&ncneg); + ncpc = NULL; + mtx_lock(&ncneg_hot.nl_lock); + ncp = TAILQ_FIRST(&ncneg_hot.nl_list); + if (ncp != NULL) { + neglist = NCP2NEGLIST(ncp); + mtx_lock(&neglist->nl_lock); + TAILQ_REMOVE(&ncneg_hot.nl_list, ncp, nc_dst); + TAILQ_INSERT_TAIL(&neglist->nl_list, ncp, nc_dst); + ncp->nc_flag &= ~NCF_HOTNEGATIVE; + mtx_unlock(&neglist->nl_lock); + } + + cache_negative_shrink_select(shrink_list_turn, &ncp, &neglist); + shrink_list_turn++; + if (shrink_list_turn == numneglists) + shrink_list_turn = 0; + if (ncp == NULL && shrink_list_turn == 0) + cache_negative_shrink_select(shrink_list_turn, &ncp, &neglist); if (ncp == NULL) { - mtx_unlock(&ncneg_mtx); + mtx_unlock(&ncneg_hot.nl_lock); goto out; } - MPASS(ncp->nc_vp == NULL); + + MPASS(ncp->nc_flag & NCF_NEGATIVE); dvlp = VP2VNODELOCK(ncp->nc_dvp); blp = NCP2BUCKETLOCK(ncp); - mtx_unlock(&ncneg_mtx); + mtx_unlock(&neglist->nl_lock); + mtx_unlock(&ncneg_hot.nl_lock); mtx_lock(dvlp); rw_wlock(blp); - mtx_lock(&ncneg_mtx); - ncp2 = TAILQ_FIRST(&ncneg); + mtx_lock(&ncneg_hot.nl_lock); + mtx_lock(&neglist->nl_lock); + ncp2 = TAILQ_FIRST(&neglist->nl_list); if (ncp != ncp2 || dvlp != VP2VNODELOCK(ncp2->nc_dvp) || - blp != NCP2BUCKETLOCK(ncp2) || ncp2->nc_vp != NULL) { + blp != NCP2BUCKETLOCK(ncp2) || !(ncp2->nc_flag & NCF_NEGATIVE)) { ncp = NULL; goto out_unlock_all; } + SDT_PROBE3(vfs, namecache, shrink_negative, done, ncp->nc_dvp, + nc_get_name(ncp), ncp->nc_neghits); + cache_zap_locked(ncp, true); out_unlock_all: - mtx_unlock(&ncneg_mtx); + mtx_unlock(&neglist->nl_lock); + mtx_unlock(&ncneg_hot.nl_lock); rw_wunlock(blp); mtx_unlock(dvlp); out: @@ -712,17 +853,19 @@ static void cache_zap_locked(struct namecache *ncp, bool neg_locked) { - cache_assert_vnode_locked(ncp->nc_vp); + if (!(ncp->nc_flag & NCF_NEGATIVE)) + cache_assert_vnode_locked(ncp->nc_vp); cache_assert_vnode_locked(ncp->nc_dvp); cache_assert_bucket_locked(ncp, RA_WLOCKED); - CTR2(KTR_VFS, "cache_zap(%p) vp %p", ncp, ncp->nc_vp); - if (ncp->nc_vp != NULL) { + CTR2(KTR_VFS, "cache_zap(%p) vp %p", ncp, + (ncp->nc_flag & NCF_NEGATIVE) ? NULL : ncp->nc_vp); + if (!(ncp->nc_flag & NCF_NEGATIVE)) { SDT_PROBE3(vfs, namecache, zap, done, ncp->nc_dvp, nc_get_name(ncp), ncp->nc_vp); } else { - SDT_PROBE2(vfs, namecache, zap_negative, done, ncp->nc_dvp, - nc_get_name(ncp)); + SDT_PROBE3(vfs, namecache, zap_negative, done, ncp->nc_dvp, + nc_get_name(ncp), ncp->nc_neghits); } LIST_REMOVE(ncp, nc_hash); if (ncp->nc_flag & NCF_ISDOTDOT) { @@ -735,7 +878,7 @@ cache_zap_locked(struct namecache *ncp, bool neg_locked) atomic_subtract_rel_long(&numcachehv, 1); } } - if (ncp->nc_vp) { + if (!(ncp->nc_flag & NCF_NEGATIVE)) { TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst, ncp, nc_dst); if (ncp == ncp->nc_vp->v_cache_dd) ncp->nc_vp->v_cache_dd = NULL; @@ -751,7 +894,7 @@ cache_zap_negative_locked_vnode_kl(struct namecache *ncp, struct vnode *vp) struct rwlock *blp; MPASS(ncp->nc_dvp == vp); - MPASS(ncp->nc_vp == NULL); + MPASS(ncp->nc_flag & NCF_NEGATIVE); cache_assert_vnode_locked(vp); blp = NCP2BUCKETLOCK(ncp); @@ -770,7 +913,7 @@ cache_zap_locked_vnode_kl2(struct namecache *ncp, struct vnode *vp, MPASS(vp == ncp->nc_dvp || vp == ncp->nc_vp); cache_assert_vnode_locked(vp); - if (ncp->nc_vp == NULL) { + if (ncp->nc_flag & NCF_NEGATIVE) { if (*vlpp != NULL) { mtx_unlock(*vlpp); *vlpp = NULL; @@ -829,7 +972,7 @@ cache_zap_locked_vnode(struct namecache *ncp, struct vnode *vp) cache_assert_vnode_locked(vp); pvlp = VP2VNODELOCK(vp); - if (ncp->nc_vp == NULL) { + if (ncp->nc_flag & NCF_NEGATIVE) { cache_zap_negative_locked_vnode_kl(ncp, vp); goto out; } @@ -865,7 +1008,9 @@ cache_zap_rlocked_bucket(struct namecache *ncp, struct rwlock *blp) cache_assert_bucket_locked(ncp, RA_RLOCKED); dvlp = VP2VNODELOCK(ncp->nc_dvp); - vlp = VP2VNODELOCK(ncp->nc_vp); + vlp = NULL; + if (!(ncp->nc_flag & NCF_NEGATIVE)) + vlp = VP2VNODELOCK(ncp->nc_vp); if (cache_trylock_vnodes(dvlp, vlp) == 0) { rw_runlock(blp); rw_wlock(blp); @@ -888,7 +1033,9 @@ cache_zap_wlocked_bucket_kl(struct namecache *ncp, struct rwlock *blp, cache_assert_bucket_locked(ncp, RA_WLOCKED); dvlp = VP2VNODELOCK(ncp->nc_dvp); - vlp = VP2VNODELOCK(ncp->nc_vp); + vlp = NULL; + if (!(ncp->nc_flag & NCF_NEGATIVE)) + vlp = VP2VNODELOCK(ncp->nc_vp); cache_sort(&dvlp, &vlp); if (*vlpp1 == dvlp && *vlpp2 == vlp) { @@ -1034,9 +1181,12 @@ cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, } return (0); } - if ((ncp->nc_flag & NCF_ISDOTDOT) != 0) - *vpp = ncp->nc_vp; - else + if ((ncp->nc_flag & NCF_ISDOTDOT) != 0) { + if (ncp->nc_flag & NCF_NEGATIVE) + *vpp = NULL; + else + *vpp = ncp->nc_vp; + } else *vpp = ncp->nc_dvp; /* Return failure if negative entry was found. */ if (*vpp == NULL) @@ -1084,7 +1234,7 @@ cache_lookup(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp, } /* We found a "positive" match, return the vnode */ - if (ncp->nc_vp) { + if (!(ncp->nc_flag & NCF_NEGATIVE)) { counter_u64_add(numposhits, 1); *vpp = ncp->nc_vp; CTR4(KTR_VFS, "cache_lookup(%p, %s) found %p via ncp %p", @@ -1226,8 +1376,7 @@ cache_lock_vnodes_cel_3(struct celockstate *cel, struct vnode *vp) MPASS(cel->vlp[2] == NULL); vlp = VP2VNODELOCK(vp); - if (vlp == NULL) - return (true); + MPASS(vlp != NULL); ret = true; if (vlp >= cel->vlp[1]) { @@ -1312,6 +1461,8 @@ cache_enter_lock(struct celockstate *cel, struct vnode *dvp, struct vnode *vp, break; MPASS(ncp->nc_dvp == vp); blps[1] = NCP2BUCKETLOCK(ncp); + if (ncp->nc_flag & NCF_NEGATIVE) + break; if (cache_lock_vnodes_cel_3(cel, ncp->nc_vp)) break; /* @@ -1349,6 +1500,8 @@ cache_enter_lock_dd(struct celockstate *cel, struct vnode *dvp, struct vnode *vp break; MPASS(ncp->nc_dvp == dvp); blps[1] = NCP2BUCKETLOCK(ncp); + if (ncp->nc_flag & NCF_NEGATIVE) + break; if (cache_lock_vnodes_cel_3(cel, ncp->nc_vp)) break; if (ncp == dvp->v_cache_dd && @@ -1383,9 +1536,11 @@ cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, struct namecache *ncp, *n2, *ndd; struct namecache_ts *n3; struct nchashhead *ncpp; + struct neglist *neglist; uint32_t hash; int flag; int len; + bool neg_locked; CTR3(KTR_VFS, "cache_enter(%p, %p, %s)", dvp, vp, cnp->cn_nameptr); VNASSERT(vp == NULL || (vp->v_iflag & VI_DOOMED) == 0, vp, @@ -1421,17 +1576,31 @@ cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, ncp->nc_flag & NCF_ISDOTDOT) { KASSERT(ncp->nc_dvp == dvp, ("wrong isdotdot parent")); - if (ncp->nc_vp != NULL) { + neg_locked = false; + if (ncp->nc_flag & NCF_NEGATIVE || vp == NULL) { + neglist = NCP2NEGLIST(ncp); + mtx_lock(&ncneg_hot.nl_lock); + mtx_lock(&neglist->nl_lock); + neg_locked = true; + } + if (!(ncp->nc_flag & NCF_NEGATIVE)) { TAILQ_REMOVE(&ncp->nc_vp->v_cache_dst, ncp, nc_dst); } else { - cache_negative_remove(ncp, false); + cache_negative_remove(ncp, true); } if (vp != NULL) { TAILQ_INSERT_HEAD(&vp->v_cache_dst, ncp, nc_dst); + ncp->nc_flag &= ~(NCF_NEGATIVE|NCF_HOTNEGATIVE); } else { - cache_negative_insert(ncp); + ncp->nc_flag &= ~(NCF_HOTNEGATIVE); + ncp->nc_flag |= NCF_NEGATIVE; + cache_negative_insert(ncp, true); + } + if (neg_locked) { + mtx_unlock(&neglist->nl_lock); + mtx_unlock(&ncneg_hot.nl_lock); } ncp->nc_vp = vp; cache_enter_unlock(&cel); @@ -1450,9 +1619,11 @@ cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, * namecache entry as possible before acquiring the lock. */ ncp = cache_alloc(cnp->cn_namelen, tsp != NULL); - ncp->nc_vp = vp; - ncp->nc_dvp = dvp; ncp->nc_flag = flag; + ncp->nc_vp = vp; + if (vp == NULL) + ncp->nc_flag |= NCF_NEGATIVE; + ncp->nc_dvp = dvp; if (tsp != NULL) { n3 = (struct namecache_ts *)ncp; n3->nc_time = *tsp; @@ -1490,7 +1661,11 @@ cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, n3->nc_dotdottime = ((struct namecache_ts *)ncp)-> nc_dotdottime; + if (ncp->nc_flag & NCF_NEGATIVE) + mtx_lock(&ncneg_hot.nl_lock); n3->nc_flag |= NCF_DTS; + if (ncp->nc_flag & NCF_NEGATIVE) + mtx_unlock(&ncneg_hot.nl_lock); } } goto out_unlock_free; @@ -1557,7 +1732,7 @@ cache_enter_time(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, } else { if (cnp->cn_flags & ISWHITEOUT) ncp->nc_flag |= NCF_WHITE; - cache_negative_insert(ncp); + cache_negative_insert(ncp, false); SDT_PROBE2(vfs, namecache, enter_negative, done, dvp, nc_get_name(ncp)); } @@ -1591,8 +1766,6 @@ nchinit(void *dummy __unused) { u_int i; - TAILQ_INIT(&ncneg); - cache_zone_small = uma_zcreate("S VFS Cache", sizeof(struct namecache) + CACHE_PATH_CUTOFF + 1, NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_ZINIT); @@ -1619,6 +1792,16 @@ nchinit(void *dummy __unused) mtx_init(&vnodelocks[i], "ncvn", NULL, MTX_DUPOK | MTX_RECURSE); ncpurgeminvnodes = numbucketlocks; + numneglists = 4; + neglists = malloc(sizeof(*neglists) * numneglists, M_VFSCACHE, + M_WAITOK | M_ZERO); + for (i = 0; i < numneglists; i++) { + mtx_init(&neglists[i].nl_lock, "ncnegl", NULL, MTX_DEF); + TAILQ_INIT(&neglists[i].nl_list); + } + mtx_init(&ncneg_hot.nl_lock, "ncneglh", NULL, MTX_DEF); + TAILQ_INIT(&ncneg_hot.nl_list); + numcalls = counter_u64_alloc(M_WAITOK); dothits = counter_u64_alloc(M_WAITOK); dotdothits = counter_u64_alloc(M_WAITOK); @@ -1741,7 +1924,7 @@ cache_purge_negative(struct vnode *vp) vlp = VP2VNODELOCK(vp); mtx_lock(vlp); LIST_FOREACH_SAFE(ncp, &vp->v_cache_src, nc_src, nnp) { - if (ncp->nc_vp != NULL) + if (!(ncp->nc_flag & NCF_NEGATIVE)) continue; cache_zap_negative_locked_vnode_kl(ncp, vp); TAILQ_INSERT_TAIL(&ncps, ncp, nc_dst); diff --git a/sys/mips/atheros/ar71xx_ehci.c b/sys/mips/atheros/ar71xx_ehci.c index 07e06b979a0b..19e9a0e20446 100644 --- a/sys/mips/atheros/ar71xx_ehci.c +++ b/sys/mips/atheros/ar71xx_ehci.c @@ -231,14 +231,8 @@ ar71xx_ehci_detach(device_t self) { struct ar71xx_ehci_softc *isc = device_get_softc(self); ehci_softc_t *sc = &isc->base; - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/mips/atheros/ar71xx_ohci.c b/sys/mips/atheros/ar71xx_ohci.c index 30f2c7de64ef..aac32ec58403 100644 --- a/sys/mips/atheros/ar71xx_ohci.c +++ b/sys/mips/atheros/ar71xx_ohci.c @@ -156,13 +156,7 @@ static int ar71xx_ohci_detach(device_t dev) { struct ar71xx_ohci_softc *sc = device_get_softc(dev); - device_t bdev; - if (sc->sc_ohci.sc_bus.bdev) { - bdev = sc->sc_ohci.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/mips/cavium/usb/octusb_octeon.c b/sys/mips/cavium/usb/octusb_octeon.c index a49a36303278..5852e14e146c 100644 --- a/sys/mips/cavium/usb/octusb_octeon.c +++ b/sys/mips/cavium/usb/octusb_octeon.c @@ -160,16 +160,10 @@ static int octusb_octeon_detach(device_t dev) { struct octusb_octeon_softc *sc = device_get_softc(dev); - device_t bdev; int err; int nports; int i; - if (sc->sc_dci.sc_bus.bdev) { - bdev = sc->sc_dci.sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/mips/conf/std.AR933X b/sys/mips/conf/std.AR933X index f9a4d875b571..5b35213d9c30 100644 --- a/sys/mips/conf/std.AR933X +++ b/sys/mips/conf/std.AR933X @@ -20,7 +20,7 @@ files "../atheros/files.ar71xx" hints "AR933X_BASE.hints" makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols -makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_vlan if_gre if_tap if_tun if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr hwpmc ipfw ipfw_nat libalias ipfw_nptv6 urtwn urtwnfw otus otusfw" +makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_vlan if_gre if_tap if_tun if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr hwpmc ipfw ipfw_nat libalias ipfw_nptv6 rtwn rtwn_usb rtwnfw otus otusfw" options DDB options KDB diff --git a/sys/mips/conf/std.AR934X b/sys/mips/conf/std.AR934X index 19399450a493..50b6f01c373f 100644 --- a/sys/mips/conf/std.AR934X +++ b/sys/mips/conf/std.AR934X @@ -20,7 +20,7 @@ files "../atheros/files.ar71xx" hints "AR934X_BASE.hints" makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols -makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_vlan if_gre if_tap if_tun if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr hwpmc ipfw ipfw_nat libalias ipfw_nptv6 urtwn urtwnfw otus otusfw" +makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_vlan if_gre if_tap if_tun if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr hwpmc ipfw ipfw_nat libalias ipfw_nptv6 rtwn rtwn_usb rtwnfw otus otusfw" # makeoptions MODULES_OVERRIDE="" options DDB diff --git a/sys/mips/conf/std.QCA955X b/sys/mips/conf/std.QCA955X index 822a03a0b754..7144d4b386e6 100644 --- a/sys/mips/conf/std.QCA955X +++ b/sys/mips/conf/std.QCA955X @@ -26,7 +26,7 @@ files "../atheros/files.ar71xx" hints "QCA955X_BASE.hints" makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols -makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_vlan if_gre if_tap if_tun if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr hwpmc ipfw ipfw_nat libalias ipfw_nptv6 urtwn urtwnfw otus otusfw" +makeoptions MODULES_OVERRIDE="gpio ar71xx if_gif if_vlan if_gre if_tap if_tun if_bridge bridgestp usb wlan wlan_xauth wlan_acl wlan_wep wlan_tkip wlan_ccmp wlan_rssadapt wlan_amrr hwpmc ipfw ipfw_nat libalias ipfw_nptv6 rtwn rtwn_usb rtwnfw otus otusfw" options DDB options KDB diff --git a/sys/mips/mediatek/mtk_dotg.c b/sys/mips/mediatek/mtk_dotg.c index d7421ad95351..e685eac4f103 100644 --- a/sys/mips/mediatek/mtk_dotg.c +++ b/sys/mips/mediatek/mtk_dotg.c @@ -161,14 +161,8 @@ static int dotg_fdt_detach(device_t dev) { struct dwc_otg_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/mips/mediatek/mtk_ehci.c b/sys/mips/mediatek/mtk_ehci.c index acc30eb028cd..ed1d2fca1fe4 100644 --- a/sys/mips/mediatek/mtk_ehci.c +++ b/sys/mips/mediatek/mtk_ehci.c @@ -162,14 +162,8 @@ static int ehci_fdt_detach(device_t self) { ehci_softc_t *sc = device_get_softc(self); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/mips/mediatek/mtk_ohci.c b/sys/mips/mediatek/mtk_ohci.c index 0b554e7f799e..ad5c68f8069c 100644 --- a/sys/mips/mediatek/mtk_ohci.c +++ b/sys/mips/mediatek/mtk_ohci.c @@ -162,14 +162,8 @@ static int ohci_fdt_detach(device_t self) { ohci_softc_t *sc = device_get_softc(self); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/mips/mediatek/mtk_xhci.c b/sys/mips/mediatek/mtk_xhci.c index 138a4d4df83d..55f39d53daa7 100644 --- a/sys/mips/mediatek/mtk_xhci.c +++ b/sys/mips/mediatek/mtk_xhci.c @@ -161,14 +161,8 @@ static int mtk_xhci_fdt_detach(device_t self) { struct xhci_softc *sc = device_get_softc(self); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/mips/rmi/xls_ehci.c b/sys/mips/rmi/xls_ehci.c index 81758b287f74..4451d13d7f87 100644 --- a/sys/mips/rmi/xls_ehci.c +++ b/sys/mips/rmi/xls_ehci.c @@ -164,14 +164,8 @@ static int ehci_xls_detach(device_t self) { ehci_softc_t *sc = device_get_softc(self); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/mips/rt305x/rt305x_dotg.c b/sys/mips/rt305x/rt305x_dotg.c index 607b2156101e..b39046f89fc8 100644 --- a/sys/mips/rt305x/rt305x_dotg.c +++ b/sys/mips/rt305x/rt305x_dotg.c @@ -173,14 +173,8 @@ static int dotg_obio_detach(device_t dev) { struct dwc_otg_softc *sc = device_get_softc(dev); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(dev, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(dev); diff --git a/sys/mips/rt305x/rt305x_ehci.c b/sys/mips/rt305x/rt305x_ehci.c index 9b2fa22ebaba..0930aff188c6 100644 --- a/sys/mips/rt305x/rt305x_ehci.c +++ b/sys/mips/rt305x/rt305x_ehci.c @@ -175,14 +175,8 @@ static int ehci_obio_detach(device_t self) { ehci_softc_t *sc = device_get_softc(self); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/mips/rt305x/rt305x_ohci.c b/sys/mips/rt305x/rt305x_ohci.c index e726e60d0ff7..b7006033f515 100644 --- a/sys/mips/rt305x/rt305x_ohci.c +++ b/sys/mips/rt305x/rt305x_ohci.c @@ -175,14 +175,8 @@ static int ohci_obio_detach(device_t self) { ohci_softc_t *sc = device_get_softc(self); - device_t bdev; int err; - if (sc->sc_bus.bdev) { - bdev = sc->sc_bus.bdev; - device_detach(bdev); - device_delete_child(self, bdev); - } /* during module unload there are lots of children leftover */ device_delete_children(self); diff --git a/sys/modules/Makefile b/sys/modules/Makefile index 75bbd0f998fe..fbaefc3ebe9a 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -319,6 +319,8 @@ SUBDIR= \ re \ rl \ rtwn \ + rtwn_pci \ + rtwn_usb \ ${_rtwnfw} \ ${_s3} \ ${_safe} \ @@ -374,8 +376,6 @@ SUBDIR= \ ufs \ uinput \ unionfs \ - urtwn \ - ${_urtwnfw} \ usb \ utopia \ ${_vesa} \ @@ -503,7 +503,6 @@ _mwlfw= mwlfw _otusfw= otusfw _ralfw= ralfw _rtwnfw= rtwnfw -_urtwnfw= urtwnfw _sf= sf _ti= ti _txp= txp diff --git a/sys/modules/dtb/omap4/Makefile b/sys/modules/dtb/omap4/Makefile new file mode 100644 index 000000000000..a6eb8e20de7a --- /dev/null +++ b/sys/modules/dtb/omap4/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ +# All the dts files for omap4 systems we support. +DTS= \ + omap4-duovero-parlor.dts \ + pandaboard.dts \ + pandaboard-es.dts + +.include diff --git a/sys/modules/geom/Makefile b/sys/modules/geom/Makefile index 8d7e3c6deb3f..3ea398958aab 100644 --- a/sys/modules/geom/Makefile +++ b/sys/modules/geom/Makefile @@ -6,7 +6,6 @@ SYSDIR?=${.CURDIR}/../.. SUBDIR= geom_bde \ geom_cache \ geom_concat \ - geom_eli \ geom_gate \ geom_journal \ geom_label \ @@ -30,4 +29,9 @@ SUBDIR= geom_bde \ SUBDIR+= geom_ccd .endif +# Alignment issues in g_eli_auth_run() on MIPS64 causes kernel panic +.if ${MACHINE_ARCH} != "mips64" && ${MACHINE_ARCH} != "mips64el" +SUBDIR+= geom_eli +.endif + .include diff --git a/sys/modules/gpio/gpiospi/Makefile b/sys/modules/gpio/gpiospi/Makefile index 922672470265..181ec03b4d78 100644 --- a/sys/modules/gpio/gpiospi/Makefile +++ b/sys/modules/gpio/gpiospi/Makefile @@ -34,7 +34,7 @@ KMOD= gpiospi SRCS= gpiospi.c SRCS+= device_if.h bus_if.h gpio_if.h gpiobus_if.h spibus_if.h -SRCS+= ofw_bus_if.h opt_gpio.h +SRCS+= ofw_bus_if.h opt_gpio.h opt_platform.h CFLAGS+= -I. -I${.CURDIR}/../../../dev/gpio/ diff --git a/sys/modules/netmap/Makefile b/sys/modules/netmap/Makefile index 8e5364bbe7a2..978a4858edb9 100644 --- a/sys/modules/netmap/Makefile +++ b/sys/modules/netmap/Makefile @@ -3,11 +3,14 @@ # Compile netmap as a module, useful if you want a netmap bridge # or loadable drivers. +.include # FreeBSD 10 and earlier +# .include "${SYSDIR}/conf/kern.opts.mk" + .PATH: ${.CURDIR}/../../dev/netmap .PATH.h: ${.CURDIR}/../../net -CFLAGS += -I${.CURDIR}/../../ +CFLAGS += -I${.CURDIR}/../../ -D INET KMOD = netmap -SRCS = device_if.h bus_if.h opt_netmap.h +SRCS = device_if.h bus_if.h pci_if.h opt_netmap.h SRCS += netmap.c netmap.h netmap_kern.h SRCS += netmap_mem2.c netmap_mem2.h SRCS += netmap_generic.c @@ -17,5 +20,8 @@ SRCS += netmap_freebsd.c SRCS += netmap_offloadings.c SRCS += netmap_pipe.c SRCS += netmap_monitor.c +SRCS += netmap_pt.c +SRCS += if_ptnet.c +SRCS += opt_inet.h opt_inet6.h .include diff --git a/sys/modules/rtwn/Makefile b/sys/modules/rtwn/Makefile index f5d230caab5f..d6d9d6d48d9b 100644 --- a/sys/modules/rtwn/Makefile +++ b/sys/modules/rtwn/Makefile @@ -1,8 +1,45 @@ # $FreeBSD$ -.PATH: ${.CURDIR}/../../dev/rtwn +.PATH: ${.CURDIR}/../../dev/rtwn -KMOD = if_rtwn -SRCS = if_rtwn.c device_if.h bus_if.h pci_if.h +SYSDIR?=${.CURDIR}/../.. +.include "${SYSDIR}/conf/kern.opts.mk" + +KMOD = if_rtwn +SRCS = if_rtwn.c if_rtwn_tx.c if_rtwn_rx.c if_rtwn_beacon.c \ + if_rtwn_calib.c if_rtwn_cam.c if_rtwn_task.c if_rtwn_efuse.c \ + if_rtwn_fw.c if_rtwn_nop.h if_rtwnreg.h if_rtwnvar.h if_rtwn_tx.h \ + if_rtwn_rx.h if_rtwn_beacon.h if_rtwn_calib.h if_rtwn_cam.h \ + if_rtwn_task.h if_rtwn_efuse.h if_rtwn_fw.h \ + bus_if.h device_if.h \ + opt_bus.h opt_rtwn.h opt_wlan.h + +.PATH: ${.CURDIR}/../../dev/rtwn/rtl8192c +SRCS += r92c_attach.c r92c_beacon.c r92c_calib.c r92c_chan.c r92c_fw.c \ + r92c_init.c r92c_rf.c r92c_rom.c r92c_rx.c r92c_tx.c \ + r92c.h r92c_priv.h r92c_reg.h r92c_var.h r92c_rom_defs.h \ + r92c_rom_image.h r92c_fw_cmd.h r92c_rx_desc.h r92c_tx_desc.h + +.PATH: ${.CURDIR}/../../dev/rtwn/rtl8188e +SRCS += r88e_beacon.c r88e_calib.c r88e_chan.c r88e_fw.c r88e_init.c \ + r88e_led.c r88e_rf.c r88e_rom.c r88e_rx.c r88e_tx.c r88e.h \ + r88e_priv.h r88e_reg.h r88e_rom_defs.h r88e_rom_image.h \ + r88e_fw_cmd.h r88e_rx_desc.h r88e_tx_desc.h + +.PATH: ${.CURDIR}/../../dev/rtwn/rtl8812a +SRCS += r12a_beacon.c r12a_calib.c r12a_caps.c r12a_chan.c r12a_fw.c \ + r12a_init.c r12a_led.c r12a_rf.c r12a_rom.c r12a_rx.c r12a_tx.c \ + r12a.h r12a_priv.h r12a_reg.h r12a_var.h r12a_rom_defs.h \ + r12a_rom_image.h r12a_fw_cmd.h r12a_rx_desc.h r12a_tx_desc.h + +.PATH: ${.CURDIR}/../../dev/rtwn/rtl8821a +SRCS += r21a_beacon.c r21a_calib.c r21a_chan.c r21a_fw.c r21a_init.c \ + r21a_led.c r21a_rom.c r21a_rx.c r21a.h r21a_priv.h r21a_reg.h + +opt_rtwn.h: + @echo "#define RTWN_DEBUG 1" > ${.TARGET} +.if ${MK_SOURCELESS_UCODE} == "no" + @echo "#define RTWN_WITHOUT_UCODE 1" >> ${.TARGET} +.endif .include diff --git a/sys/modules/rtwn_pci/Makefile b/sys/modules/rtwn_pci/Makefile new file mode 100644 index 000000000000..25cc718b9bee --- /dev/null +++ b/sys/modules/rtwn_pci/Makefile @@ -0,0 +1,26 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/rtwn/pci + +SYSDIR?=${.CURDIR}/../.. +.include "${SYSDIR}/conf/kern.opts.mk" + +KMOD = if_rtwn_pci +SRCS = rtwn_pci_attach.c rtwn_pci_reg.c rtwn_pci_rx.c rtwn_pci_tx.c \ + rtwn_pci_attach.h rtwn_pci_reg.h rtwn_pci_rx.h rtwn_pci_tx.h \ + rtwn_pci_var.h \ + device_if.h bus_if.h pci_if.h \ + opt_bus.h opt_rtwn.h opt_wlan.h + +.PATH: ${.CURDIR}/../../dev/rtwn/rtl8192c/pci +SRCS += r92ce_attach.c r92ce_calib.c r92ce_fw.c r92ce_init.c r92ce_led.c \ + r92ce_rx.c r92ce_tx.c \ + r92ce.h r92ce_priv.h r92ce_reg.h r92ce_rx_desc.h r92ce_tx_desc.h + +opt_rtwn.h: + @echo "#define RTWN_DEBUG 1" > ${.TARGET} +.if ${MK_SOURCELESS_UCODE} == "no" + @echo "#define RTWN_WITHOUT_UCODE 1" >> ${.TARGET} +.endif + +.include diff --git a/sys/modules/rtwn_usb/Makefile b/sys/modules/rtwn_usb/Makefile new file mode 100644 index 000000000000..57cd56721e1a --- /dev/null +++ b/sys/modules/rtwn_usb/Makefile @@ -0,0 +1,37 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/rtwn/usb + +SYSDIR?=${.CURDIR}/../.. +.include "${SYSDIR}/conf/kern.opts.mk" + +KMOD = if_rtwn_usb +SRCS = rtwn_usb_attach.c rtwn_usb_ep.c rtwn_usb_reg.c rtwn_usb_rx.c \ + rtwn_usb_tx.c rtwn_usb_attach.h rtwn_usb_ep.h rtwn_usb_reg.h \ + rtwn_usb_rx.h rtwn_usb_tx.h rtwn_usb_var.h \ + bus_if.h device_if.h \ + opt_bus.h opt_rtwn.h opt_usb.h opt_wlan.h usb_if.h usbdevs.h + +.PATH: ${.CURDIR}/../../dev/rtwn/rtl8188e/usb +SRCS += r88eu_attach.c r88eu_init.c r88eu_rx.c \ + r88eu.h r88eu_reg.h + +.PATH: ${.CURDIR}/../../dev/rtwn/rtl8192c/usb +SRCS += r92cu_attach.c r92cu_init.c r92cu_led.c r92cu_rx.c r92cu_tx.c \ + r92cu.h r92cu_priv.h r92cu_reg.h r92cu_tx_desc.h + +.PATH: ${.CURDIR}/../../dev/rtwn/rtl8812a/usb +SRCS += r12au_attach.c r12au_init.c r12au_rx.c r12au_tx.c \ + r12au.h r12au_reg.h r12au_tx_desc.h + +.PATH: ${.CURDIR}/../../dev/rtwn/rtl8821a/usb +SRCS += r21au_attach.c r21au_init.c \ + r21au.h r21au_reg.h + +opt_rtwn.h: + @echo "#define RTWN_DEBUG 1" > ${.TARGET} +.if ${MK_SOURCELESS_UCODE} == "no" + @echo "#define RTWN_WITHOUT_UCODE 1" >> ${.TARGET} +.endif + +.include diff --git a/sys/modules/rtwnfw/Makefile b/sys/modules/rtwnfw/Makefile index 7a679dfbfebb..ca9ab005e183 100644 --- a/sys/modules/rtwnfw/Makefile +++ b/sys/modules/rtwnfw/Makefile @@ -1,5 +1,6 @@ # $FreeBSD$ -SUBDIR= rtwnrtl8192cU rtwnrtl8192cUB +SUBDIR= rtwnrtl8188eu rtwnrtl8192cT rtwnrtl8192cU rtwnrtl8812au rtwnrtl8821au \ + rtwnrtl8192cE rtwnrtl8192cEB .include diff --git a/sys/modules/rtwnfw/Makefile.inc b/sys/modules/rtwnfw/Makefile.inc index ce5bcee3f531..a101166e7063 100644 --- a/sys/modules/rtwnfw/Makefile.inc +++ b/sys/modules/rtwnfw/Makefile.inc @@ -9,7 +9,7 @@ CLEANFILES+= ${_FIRM} FIRMWS= ${_FIRM}:${KMOD}:111 -FIRMWARE_LICENSE= realtek +# FIRMWARE_LICENSE= realtek ${_FIRM}: ${.CURDIR}/../../../contrib/dev/rtwn/${_FIRM}.uu uudecode -p $? > ${.TARGET} diff --git a/sys/modules/rtwnfw/rtwnrtl8188eu/Makefile b/sys/modules/rtwnfw/rtwnrtl8188eu/Makefile new file mode 100644 index 000000000000..2ec128e651da --- /dev/null +++ b/sys/modules/rtwnfw/rtwnrtl8188eu/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +KMOD= rtwn-rtl8188eufw +IMG= rtwn-rtl8188eufw + +.include diff --git a/sys/modules/rtwnfw/rtwnrtl8192cE/Makefile b/sys/modules/rtwnfw/rtwnrtl8192cE/Makefile new file mode 100644 index 000000000000..095d782b2897 --- /dev/null +++ b/sys/modules/rtwnfw/rtwnrtl8192cE/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +KMOD= rtwn-rtl8192cfwE +IMG= rtwn-rtl8192cfwE + +.include diff --git a/sys/modules/rtwnfw/rtwnrtl8192cEB/Makefile b/sys/modules/rtwnfw/rtwnrtl8192cEB/Makefile new file mode 100644 index 000000000000..c27f48c92db2 --- /dev/null +++ b/sys/modules/rtwnfw/rtwnrtl8192cEB/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +KMOD= rtwn-rtl8192cfwE_B +IMG= rtwn-rtl8192cfwE_B + +.include diff --git a/sys/modules/rtwnfw/rtwnrtl8192cT/Makefile b/sys/modules/rtwnfw/rtwnrtl8192cT/Makefile new file mode 100644 index 000000000000..cca32eaf311e --- /dev/null +++ b/sys/modules/rtwnfw/rtwnrtl8192cT/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +KMOD= rtwn-rtl8192cfwT +IMG= rtwn-rtl8192cfwT + +.include diff --git a/sys/modules/rtwnfw/rtwnrtl8192cUB/Makefile b/sys/modules/rtwnfw/rtwnrtl8192cUB/Makefile deleted file mode 100644 index eb878d48c184..000000000000 --- a/sys/modules/rtwnfw/rtwnrtl8192cUB/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# $FreeBSD$ - -KMOD= rtwn-rtl8192cfwU_B -IMG= rtwn-rtl8192cfwU_B - -.include diff --git a/sys/modules/rtwnfw/rtwnrtl8812au/Makefile b/sys/modules/rtwnfw/rtwnrtl8812au/Makefile new file mode 100644 index 000000000000..66a83277dc55 --- /dev/null +++ b/sys/modules/rtwnfw/rtwnrtl8812au/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +KMOD= rtwn-rtl8812aufw +IMG= rtwn-rtl8812aufw + +.include diff --git a/sys/modules/rtwnfw/rtwnrtl8821au/Makefile b/sys/modules/rtwnfw/rtwnrtl8821au/Makefile new file mode 100644 index 000000000000..c0d8060697f8 --- /dev/null +++ b/sys/modules/rtwnfw/rtwnrtl8821au/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +KMOD= rtwn-rtl8821aufw +IMG= rtwn-rtl8821aufw + +.include diff --git a/sys/modules/urtwn/Makefile b/sys/modules/urtwn/Makefile deleted file mode 100644 index a4fdc254ea24..000000000000 --- a/sys/modules/urtwn/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# $FreeBSD$ - -.PATH: ${.CURDIR}/../../dev/urtwn - -SYSDIR?=${.CURDIR}/../.. -.include "${SYSDIR}/conf/kern.opts.mk" - -KMOD = if_urtwn -SRCS = if_urtwn.c if_urtwnreg.h if_urtwnvar.h \ - bus_if.h device_if.h \ - opt_bus.h opt_urtwn.h opt_usb.h opt_wlan.h usb_if.h usbdevs.h - -.if ${MK_SOURCELESS_UCODE} == "no" -opt_urtwn.h: - @echo "#define URTWN_WITHOUT_UCODE 1" > ${.TARGET} -.endif - -.include diff --git a/sys/modules/urtwnfw/Makefile b/sys/modules/urtwnfw/Makefile deleted file mode 100644 index 611b4115bb5a..000000000000 --- a/sys/modules/urtwnfw/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# $FreeBSD$ - -SUBDIR= urtwnrtl8188eu urtwnrtl8192cT urtwnrtl8192cU - -.include diff --git a/sys/modules/urtwnfw/Makefile.inc b/sys/modules/urtwnfw/Makefile.inc deleted file mode 100644 index 2a97a097209f..000000000000 --- a/sys/modules/urtwnfw/Makefile.inc +++ /dev/null @@ -1,15 +0,0 @@ -# $FreeBSD$ -# -# Common rules for building firmware. Note this gets auto-included -# by the subdir Makefile's as a consequence of included bsd.kmod.mk. - -_FIRM= ${IMG}.fw - -CLEANFILES+= ${_FIRM} - -FIRMWS= ${_FIRM}:${KMOD}:111 - -# FIRMWARE_LICENSE= realtek - -${_FIRM}: ${.CURDIR}/../../../contrib/dev/urtwn/${_FIRM}.uu - uudecode -p $? > ${.TARGET} diff --git a/sys/modules/urtwnfw/urtwnrtl8188eu/Makefile b/sys/modules/urtwnfw/urtwnrtl8188eu/Makefile deleted file mode 100644 index d3c974e9c03a..000000000000 --- a/sys/modules/urtwnfw/urtwnrtl8188eu/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# $FreeBSD$ - -KMOD= urtwn-rtl8188eufw -IMG= urtwn-rtl8188eufw - -.include diff --git a/sys/modules/urtwnfw/urtwnrtl8192cT/Makefile b/sys/modules/urtwnfw/urtwnrtl8192cT/Makefile deleted file mode 100644 index ef4998454e7f..000000000000 --- a/sys/modules/urtwnfw/urtwnrtl8192cT/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# $FreeBSD$ - -KMOD= urtwn-rtl8192cfwT -IMG= urtwn-rtl8192cfwT - -.include diff --git a/sys/modules/urtwnfw/urtwnrtl8192cU/Makefile b/sys/modules/urtwnfw/urtwnrtl8192cU/Makefile deleted file mode 100644 index e9a932c826e8..000000000000 --- a/sys/modules/urtwnfw/urtwnrtl8192cU/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# $FreeBSD$ - -KMOD= urtwn-rtl8192cfwU -IMG= urtwn-rtl8192cfwU - -.include diff --git a/sys/net/bpf_filter.c b/sys/net/bpf_filter.c index ab3198ab3ea0..54bcf9abf933 100644 --- a/sys/net/bpf_filter.c +++ b/sys/net/bpf_filter.c @@ -434,6 +434,12 @@ bpf_filter(const struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen) A /= X; continue; + case BPF_ALU|BPF_MOD|BPF_X: + if (X == 0) + return (0); + A %= X; + continue; + case BPF_ALU|BPF_AND|BPF_X: A &= X; continue; @@ -442,6 +448,10 @@ bpf_filter(const struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen) A |= X; continue; + case BPF_ALU|BPF_XOR|BPF_X: + A ^= X; + continue; + case BPF_ALU|BPF_LSH|BPF_X: A <<= X; continue; @@ -466,6 +476,10 @@ bpf_filter(const struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen) A /= pc->k; continue; + case BPF_ALU|BPF_MOD|BPF_K: + A %= pc->k; + continue; + case BPF_ALU|BPF_AND|BPF_K: A &= pc->k; continue; @@ -474,6 +488,10 @@ bpf_filter(const struct bpf_insn *pc, u_char *p, u_int wirelen, u_int buflen) A |= pc->k; continue; + case BPF_ALU|BPF_XOR|BPF_K: + A ^= pc->k; + continue; + case BPF_ALU|BPF_LSH|BPF_K: A <<= pc->k; continue; @@ -508,8 +526,8 @@ static const u_short bpf_code_map[] = { 0x1013, /* 0x60-0x6f: 1100100000001000 */ 0x1010, /* 0x70-0x7f: 0000100000001000 */ 0x0093, /* 0x80-0x8f: 1100100100000000 */ - 0x0000, /* 0x90-0x9f: 0000000000000000 */ - 0x0000, /* 0xa0-0xaf: 0000000000000000 */ + 0x1010, /* 0x90-0x9f: 0000100000001000 */ + 0x1010, /* 0xa0-0xaf: 0000100000001000 */ 0x0002, /* 0xb0-0xbf: 0100000000000000 */ 0x0000, /* 0xc0-0xcf: 0000000000000000 */ 0x0000, /* 0xd0-0xdf: 0000000000000000 */ @@ -577,7 +595,8 @@ bpf_validate(const struct bpf_insn *f, int len) /* * Check for constant division by 0. */ - if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0) + if ((p->code == (BPF_ALU|BPF_DIV|BPF_K) || + p->code == (BPF_ALU|BPF_MOD|BPF_K)) && p->k == 0) return (0); } return (BPF_CLASS(f[len - 1].code) == BPF_RET); diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c index 4d7de10b3ca6..72b93e213be4 100644 --- a/sys/net/if_loop.c +++ b/sys/net/if_loop.c @@ -36,6 +36,7 @@ #include "opt_inet.h" #include "opt_inet6.h" +#include "opt_rss.h" #include #include @@ -224,6 +225,10 @@ looutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); +#ifdef RSS + M_HASHTYPE_CLEAR(m); +#endif + /* BPF writes need to be handled specially. */ if (dst->sa_family == AF_UNSPEC || dst->sa_family == pseudo_AF_HDRCMPLT) bcopy(dst->sa_data, &af, sizeof(af)); diff --git a/sys/net/if_var.h b/sys/net/if_var.h index 8632ea2f3af3..62c4bfdd33fb 100644 --- a/sys/net/if_var.h +++ b/sys/net/if_var.h @@ -496,7 +496,7 @@ extern struct sx ifnet_sxlock; /* * Look up an ifnet given its index; the _ref variant also acquires a * reference that must be freed using if_rele(). It is almost always a bug - * to call ifnet_byindex() instead if ifnet_byindex_ref(). + * to call ifnet_byindex() instead of ifnet_byindex_ref(). */ struct ifnet *ifnet_byindex(u_short idx); struct ifnet *ifnet_byindex_locked(u_short idx); diff --git a/sys/net/iflib.c b/sys/net/iflib.c index 5938aca90877..42f0d4ce93ec 100644 --- a/sys/net/iflib.c +++ b/sys/net/iflib.c @@ -3162,8 +3162,6 @@ iflib_if_qflush(if_t ifp) IFCAP_TSO4 | IFCAP_TSO6 | IFCAP_VLAN_HWTAGGING | \ IFCAP_VLAN_MTU | IFCAP_VLAN_HWFILTER | IFCAP_VLAN_HWTSO) -#define IFCAP_REINIT IFCAP_FLAGS - static int iflib_if_ioctl(if_t ifp, u_long command, caddr_t data) { @@ -3288,6 +3286,8 @@ iflib_if_ioctl(if_t ifp, u_long command, caddr_t data) #endif setmask |= (mask & IFCAP_FLAGS); + if (setmask & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) + setmask |= (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6); if ((mask & IFCAP_WOL) && (if_getcapabilities(ifp) & IFCAP_WOL) != 0) setmask |= (mask & (IFCAP_WOL_MCAST|IFCAP_WOL_MAGIC)); @@ -3298,10 +3298,10 @@ iflib_if_ioctl(if_t ifp, u_long command, caddr_t data) if (setmask) { CTX_LOCK(ctx); bits = if_getdrvflags(ifp); - if (setmask & IFCAP_REINIT) + if (bits & IFF_DRV_RUNNING) iflib_stop(ctx); if_togglecapenable(ifp, setmask); - if (setmask & IFCAP_REINIT) + if (bits & IFF_DRV_RUNNING) iflib_init_locked(ctx); if_setdrvflags(ifp, bits); CTX_UNLOCK(ctx); @@ -3903,6 +3903,10 @@ _iflib_assert(if_shared_ctx_t sctx) MPASS(sctx->isc_ntxd_default[0]); } +#define DEFAULT_CAPS (IFCAP_TXCSUM_IPV6 | IFCAP_RXCSUM_IPV6 | IFCAP_HWCSUM | IFCAP_LRO | \ + IFCAP_TSO4 | IFCAP_TSO6 | IFCAP_VLAN_HWTAGGING | \ + IFCAP_VLAN_MTU | IFCAP_VLAN_HWFILTER | IFCAP_VLAN_HWTSO | IFCAP_HWSTATS) + static int iflib_register(if_ctx_t ctx) { @@ -3937,8 +3941,9 @@ iflib_register(if_ctx_t ctx) if_setqflushfn(ifp, iflib_if_qflush); if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); - if_setcapabilities(ifp, 0); - if_setcapenable(ifp, 0); + /* XXX - move this in to the driver for non-default settings */ + if_setcapabilities(ifp, DEFAULT_CAPS); + if_setcapenable(ifp, DEFAULT_CAPS); ctx->ifc_vlan_attach_event = EVENTHANDLER_REGISTER(vlan_config, iflib_vlan_register, ctx, @@ -4294,17 +4299,23 @@ iflib_irq_alloc(if_ctx_t ctx, if_irq_t irq, int rid, return (_iflib_irq_alloc(ctx, irq, rid, filter, handler, arg, name)); } -static void +static int find_nth(if_ctx_t ctx, cpuset_t *cpus, int qid) { - int i, cpuid; + int i, cpuid, eqid, count; CPU_COPY(&ctx->ifc_cpus, cpus); + count = CPU_COUNT(&ctx->ifc_cpus); + eqid = qid % count; /* clear up to the qid'th bit */ - for (i = 0; i < qid; i++) { + for (i = 0; i < eqid; i++) { cpuid = CPU_FFS(cpus); - CPU_CLR(cpuid, cpus); + MPASS(cpuid != 0); + CPU_CLR(cpuid-1, cpus); } + cpuid = CPU_FFS(cpus); + MPASS(cpuid != 0); + return (cpuid-1); } int @@ -4317,10 +4328,11 @@ iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid, iflib_filter_info_t info; cpuset_t cpus; gtask_fn_t *fn; - int tqrid, err; + int tqrid, err, cpuid; void *q; info = &ctx->ifc_filter_info; + tqrid = rid; switch (type) { /* XXX merge tx/rx for netmap? */ @@ -4329,7 +4341,6 @@ iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid, info = &ctx->ifc_txqs[qid].ift_filter_info; gtask = &ctx->ifc_txqs[qid].ift_task; tqg = qgroup_if_io_tqg; - tqrid = irq->ii_rid; fn = _task_fn_tx; break; case IFLIB_INTR_RX: @@ -4337,7 +4348,6 @@ iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid, info = &ctx->ifc_rxqs[qid].ifr_filter_info; gtask = &ctx->ifc_rxqs[qid].ifr_task; tqg = qgroup_if_io_tqg; - tqrid = irq->ii_rid; fn = _task_fn_rx; break; case IFLIB_INTR_ADMIN: @@ -4345,7 +4355,6 @@ iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid, info = &ctx->ifc_filter_info; gtask = &ctx->ifc_admin_task; tqg = qgroup_if_config_tqg; - tqrid = -1; fn = _task_fn_admin; break; default: @@ -4363,11 +4372,11 @@ iflib_irq_alloc_generic(if_ctx_t ctx, if_irq_t irq, int rid, if (err != 0) return (err); if (tqrid != -1) { - find_nth(ctx, &cpus, qid); - taskqgroup_attach_cpu(tqg, gtask, q, CPU_FFS(&cpus), irq->ii_rid, name); - } else + cpuid = find_nth(ctx, &cpus, qid); + taskqgroup_attach_cpu(tqg, gtask, q, cpuid, irq->ii_rid, name); + } else { taskqgroup_attach(tqg, gtask, q, tqrid, name); - + } return (0); } diff --git a/sys/net/netmap.h b/sys/net/netmap.h index 88b2957502ab..14b5e2b32128 100644 --- a/sys/net/netmap.h +++ b/sys/net/netmap.h @@ -137,6 +137,26 @@ * netmap:foo-k the k-th NIC ring pair * netmap:foo{k PIPE ring pair k, master side * netmap:foo}k PIPE ring pair k, slave side + * + * Some notes about host rings: + * + * + The RX host ring is used to store those packets that the host network + * stack is trying to transmit through a NIC queue, but only if that queue + * is currently in netmap mode. Netmap will not intercept host stack mbufs + * designated to NIC queues that are not in netmap mode. As a consequence, + * registering a netmap port with netmap:foo^ is not enough to intercept + * mbufs in the RX host ring; the netmap port should be registered with + * netmap:foo*, or another registration should be done to open at least a + * NIC TX queue in netmap mode. + * + * + Netmap is not currently able to deal with intercepted trasmit mbufs which + * require offloadings like TSO, UFO, checksumming offloadings, etc. It is + * responsibility of the user to disable those offloadings (e.g. using + * ifconfig on FreeBSD or ethtool -K on Linux) for an interface that is being + * used in netmap mode. If the offloadings are not disabled, GSO and/or + * unchecksummed packets may be dropped immediately or end up in the host RX + * ring, and will be dropped as soon as the packet reaches another netmap + * adapter. */ /* @@ -277,7 +297,11 @@ struct netmap_ring { struct timeval ts; /* (k) time of last *sync() */ /* opaque room for a mutex or similar object */ - uint8_t sem[128] __attribute__((__aligned__(NM_CACHE_ALIGN))); +#if !defined(_WIN32) || defined(__CYGWIN__) + uint8_t __attribute__((__aligned__(NM_CACHE_ALIGN))) sem[128]; +#else + uint8_t __declspec(align(NM_CACHE_ALIGN)) sem[128]; +#endif /* the slots follow. This struct has variable size */ struct netmap_slot slot[0]; /* array of slots. */ @@ -496,6 +520,11 @@ struct nmreq { #define NETMAP_BDG_OFFSET NETMAP_BDG_VNET_HDR /* deprecated alias */ #define NETMAP_BDG_NEWIF 6 /* create a virtual port */ #define NETMAP_BDG_DELIF 7 /* destroy a virtual port */ +#define NETMAP_PT_HOST_CREATE 8 /* create ptnetmap kthreads */ +#define NETMAP_PT_HOST_DELETE 9 /* delete ptnetmap kthreads */ +#define NETMAP_BDG_POLLING_ON 10 /* delete polling kthread */ +#define NETMAP_BDG_POLLING_OFF 11 /* delete polling kthread */ +#define NETMAP_VNET_HDR_GET 12 /* get the port virtio-net-hdr length */ uint16_t nr_arg1; /* reserve extra rings in NIOCREGIF */ #define NETMAP_BDG_HOST 1 /* attach the host stack on ATTACH */ @@ -521,7 +550,61 @@ enum { NR_REG_DEFAULT = 0, /* backward compat, should not be used. */ #define NR_ZCOPY_MON 0x400 /* request exclusive access to the selected rings */ #define NR_EXCLUSIVE 0x800 +/* request ptnetmap host support */ +#define NR_PASSTHROUGH_HOST NR_PTNETMAP_HOST /* deprecated */ +#define NR_PTNETMAP_HOST 0x1000 +#define NR_RX_RINGS_ONLY 0x2000 +#define NR_TX_RINGS_ONLY 0x4000 +/* Applications set this flag if they are able to deal with virtio-net headers, + * that is send/receive frames that start with a virtio-net header. + * If not set, NIOCREGIF will fail with netmap ports that require applications + * to use those headers. If the flag is set, the application can use the + * NETMAP_VNET_HDR_GET command to figure out the header length. */ +#define NR_ACCEPT_VNET_HDR 0x8000 +#define NM_BDG_NAME "vale" /* prefix for bridge port name */ + +/* + * Windows does not have _IOWR(). _IO(), _IOW() and _IOR() are defined + * in ws2def.h but not sure if they are in the form we need. + * XXX so we redefine them + * in a convenient way to use for DeviceIoControl signatures + */ +#ifdef _WIN32 +#undef _IO // ws2def.h +#define _WIN_NM_IOCTL_TYPE 40000 +#define _IO(_c, _n) CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \ + METHOD_BUFFERED, FILE_ANY_ACCESS ) +#define _IO_direct(_c, _n) CTL_CODE(_WIN_NM_IOCTL_TYPE, ((_n) + 0x800) , \ + METHOD_OUT_DIRECT, FILE_ANY_ACCESS ) + +#define _IOWR(_c, _n, _s) _IO(_c, _n) + +/* We havesome internal sysctl in addition to the externally visible ones */ +#define NETMAP_MMAP _IO_direct('i', 160) // note METHOD_OUT_DIRECT +#define NETMAP_POLL _IO('i', 162) + +/* and also two setsockopt for sysctl emulation */ +#define NETMAP_SETSOCKOPT _IO('i', 140) +#define NETMAP_GETSOCKOPT _IO('i', 141) + + +//These linknames are for the Netmap Core Driver +#define NETMAP_NT_DEVICE_NAME L"\\Device\\NETMAP" +#define NETMAP_DOS_DEVICE_NAME L"\\DosDevices\\netmap" + +//Definition of a structure used to pass a virtual address within an IOCTL +typedef struct _MEMORY_ENTRY { + PVOID pUsermodeVirtualAddress; +} MEMORY_ENTRY, *PMEMORY_ENTRY; + +typedef struct _POLL_REQUEST_DATA { + int events; + int timeout; + int revents; +} POLL_REQUEST_DATA; + +#endif /* _WIN32 */ /* * FreeBSD uses the size value embedded in the _IOWR to determine @@ -561,4 +644,29 @@ struct nm_ifreq { char data[NM_IFRDATA_LEN]; }; +/* + * netmap kernel thread configuration + */ +/* bhyve/vmm.ko MSIX parameters for IOCTL */ +struct ptn_vmm_ioctl_msix { + uint64_t msg; + uint64_t addr; +}; + +/* IOCTL parameters */ +struct nm_kth_ioctl { + uint64_t com; + /* We use union to support more ioctl commands. */ + union { + struct ptn_vmm_ioctl_msix msix; + } data; +}; + +/* Configuration of a ptnetmap ring */ +struct ptnet_ring_cfg { + uint64_t ioeventfd; /* eventfd in linux, tsleep() parameter in FreeBSD */ + uint64_t irqfd; /* eventfd in linux, ioctl fd in FreeBSD */ + struct nm_kth_ioctl ioctl; /* ioctl parameter to send irq (only used in bhyve/FreeBSD) */ + uint64_t reserved[4]; /* reserved to support of more hypervisors */ +}; #endif /* _NET_NETMAP_H_ */ diff --git a/sys/net/netmap_user.h b/sys/net/netmap_user.h index 130117db7a2e..4fbf38731d33 100644 --- a/sys/net/netmap_user.h +++ b/sys/net/netmap_user.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011-2014 Universita` di Pisa. All rights reserved. + * Copyright (C) 2011-2016 Universita` di Pisa + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -65,9 +66,31 @@ #ifndef _NET_NETMAP_USER_H_ #define _NET_NETMAP_USER_H_ +#define NETMAP_DEVICE_NAME "/dev/netmap" + +#ifdef __CYGWIN__ +/* + * we can compile userspace apps with either cygwin or msvc, + * and we use _WIN32 to identify windows specific code + */ +#ifndef _WIN32 +#define _WIN32 +#endif /* _WIN32 */ + +#endif /* __CYGWIN__ */ + +#ifdef _WIN32 +#undef NETMAP_DEVICE_NAME +#define NETMAP_DEVICE_NAME "/proc/sys/DosDevices/Global/netmap" +#include +#include +#include +#endif /* _WIN32 */ + #include #include /* apple needs sockaddr */ #include /* IFNAMSIZ */ +#include #ifndef likely #define likely(x) __builtin_expect(!!(x), 1) @@ -172,17 +195,23 @@ nm_ring_space(struct netmap_ring *ring) } while (0) #endif -struct nm_pkthdr { /* same as pcap_pkthdr */ +struct nm_pkthdr { /* first part is the same as pcap_pkthdr */ struct timeval ts; uint32_t caplen; uint32_t len; + + uint64_t flags; /* NM_MORE_PKTS etc */ +#define NM_MORE_PKTS 1 + struct nm_desc *d; + struct netmap_slot *slot; + uint8_t *buf; }; struct nm_stat { /* same as pcap_stat */ u_int ps_recv; u_int ps_drop; u_int ps_ifdrop; -#ifdef WIN32 +#ifdef WIN32 /* XXX or _WIN32 ? */ u_int bs_capt; #endif /* WIN32 */ }; @@ -284,12 +313,14 @@ typedef void (*nm_cb_t)(u_char *, const struct nm_pkthdr *, const u_char *d); * -NN bind individual NIC ring pair * {NN bind master side of pipe NN * }NN bind slave side of pipe NN - * a suffix starting with + and the following flags, + * a suffix starting with / and the following flags, * in any order: * x exclusive access * z zero copy monitor * t monitor tx side * r monitor rx side + * R bind only RX ring(s) + * T bind only TX ring(s) * * req provides the initial values of nmreq before parsing ifname. * Remember that the ifname parsing will override the ring @@ -328,6 +359,13 @@ enum { static int nm_close(struct nm_desc *); +/* + * nm_mmap() do mmap or inherit from parent if the nr_arg2 + * (memory block) matches. + */ + +static int nm_mmap(struct nm_desc *, const struct nm_desc *); + /* * nm_inject() is the same as pcap_inject() * nm_dispatch() is the same as pcap_dispatch() @@ -338,13 +376,247 @@ static int nm_inject(struct nm_desc *, const void *, size_t); static int nm_dispatch(struct nm_desc *, int, nm_cb_t, u_char *); static u_char *nm_nextpkt(struct nm_desc *, struct nm_pkthdr *); +#ifdef _WIN32 + +intptr_t _get_osfhandle(int); /* defined in io.h in windows */ + +/* + * In windows we do not have yet native poll support, so we keep track + * of file descriptors associated to netmap ports to emulate poll on + * them and fall back on regular poll on other file descriptors. + */ +struct win_netmap_fd_list { + struct win_netmap_fd_list *next; + int win_netmap_fd; + HANDLE win_netmap_handle; +}; + +/* + * list head containing all the netmap opened fd and their + * windows HANDLE counterparts + */ +static struct win_netmap_fd_list *win_netmap_fd_list_head; + +static void +win_insert_fd_record(int fd) +{ + struct win_netmap_fd_list *curr; + + for (curr = win_netmap_fd_list_head; curr; curr = curr->next) { + if (fd == curr->win_netmap_fd) { + return; + } + } + curr = calloc(1, sizeof(*curr)); + curr->next = win_netmap_fd_list_head; + curr->win_netmap_fd = fd; + curr->win_netmap_handle = IntToPtr(_get_osfhandle(fd)); + win_netmap_fd_list_head = curr; +} + +void +win_remove_fd_record(int fd) +{ + struct win_netmap_fd_list *curr = win_netmap_fd_list_head; + struct win_netmap_fd_list *prev = NULL; + for (; curr ; prev = curr, curr = curr->next) { + if (fd != curr->win_netmap_fd) + continue; + /* found the entry */ + if (prev == NULL) { /* we are freeing the first entry */ + win_netmap_fd_list_head = curr->next; + } else { + prev->next = curr->next; + } + free(curr); + break; + } +} + + +HANDLE +win_get_netmap_handle(int fd) +{ + struct win_netmap_fd_list *curr; + + for (curr = win_netmap_fd_list_head; curr; curr = curr->next) { + if (fd == curr->win_netmap_fd) { + return curr->win_netmap_handle; + } + } + return NULL; +} + +/* + * we need to wrap ioctl and mmap, at least for the netmap file descriptors + */ + +/* + * use this function only from netmap_user.h internal functions + * same as ioctl, returns 0 on success and -1 on error + */ +static int +win_nm_ioctl_internal(HANDLE h, int32_t ctlCode, void *arg) +{ + DWORD bReturn = 0, szIn, szOut; + BOOL ioctlReturnStatus; + void *inParam = arg, *outParam = arg; + + switch (ctlCode) { + case NETMAP_POLL: + szIn = sizeof(POLL_REQUEST_DATA); + szOut = sizeof(POLL_REQUEST_DATA); + break; + case NETMAP_MMAP: + szIn = 0; + szOut = sizeof(void*); + inParam = NULL; /* nothing on input */ + break; + case NIOCTXSYNC: + case NIOCRXSYNC: + szIn = 0; + szOut = 0; + break; + case NIOCREGIF: + szIn = sizeof(struct nmreq); + szOut = sizeof(struct nmreq); + break; + case NIOCCONFIG: + D("unsupported NIOCCONFIG!"); + return -1; + + default: /* a regular ioctl */ + D("invalid ioctl %x on netmap fd", ctlCode); + return -1; + } + + ioctlReturnStatus = DeviceIoControl(h, + ctlCode, inParam, szIn, + outParam, szOut, + &bReturn, NULL); + // XXX note windows returns 0 on error or async call, 1 on success + // we could call GetLastError() to figure out what happened + return ioctlReturnStatus ? 0 : -1; +} + +/* + * this function is what must be called from user-space programs + * same as ioctl, returns 0 on success and -1 on error + */ +static int +win_nm_ioctl(int fd, int32_t ctlCode, void *arg) +{ + HANDLE h = win_get_netmap_handle(fd); + + if (h == NULL) { + return ioctl(fd, ctlCode, arg); + } else { + return win_nm_ioctl_internal(h, ctlCode, arg); + } +} + +#define ioctl win_nm_ioctl /* from now on, within this file ... */ + +/* + * We cannot use the native mmap on windows + * The only parameter used is "fd", the other ones are just declared to + * make this signature comparable to the FreeBSD/Linux one + */ +static void * +win32_mmap_emulated(void *addr, size_t length, int prot, int flags, int fd, int32_t offset) +{ + HANDLE h = win_get_netmap_handle(fd); + + if (h == NULL) { + return mmap(addr, length, prot, flags, fd, offset); + } else { + MEMORY_ENTRY ret; + + return win_nm_ioctl_internal(h, NETMAP_MMAP, &ret) ? + NULL : ret.pUsermodeVirtualAddress; + } +} + +#define mmap win32_mmap_emulated + +#include /* XXX needed to use the structure pollfd */ + +static int +win_nm_poll(struct pollfd *fds, int nfds, int timeout) +{ + HANDLE h; + + if (nfds != 1 || fds == NULL || (h = win_get_netmap_handle(fds->fd)) == NULL) {; + return poll(fds, nfds, timeout); + } else { + POLL_REQUEST_DATA prd; + + prd.timeout = timeout; + prd.events = fds->events; + + win_nm_ioctl_internal(h, NETMAP_POLL, &prd); + if ((prd.revents == POLLERR) || (prd.revents == STATUS_TIMEOUT)) { + return -1; + } + return 1; + } +} + +#define poll win_nm_poll + +static int +win_nm_open(char* pathname, int flags) +{ + + if (strcmp(pathname, NETMAP_DEVICE_NAME) == 0) { + int fd = open(NETMAP_DEVICE_NAME, O_RDWR); + if (fd < 0) { + return -1; + } + + win_insert_fd_record(fd); + return fd; + } else { + return open(pathname, flags); + } +} + +#define open win_nm_open + +static int +win_nm_close(int fd) +{ + if (fd != -1) { + close(fd); + if (win_get_netmap_handle(fd) != NULL) { + win_remove_fd_record(fd); + } + } + return 0; +} + +#define close win_nm_close + +#endif /* _WIN32 */ + +static int +nm_is_identifier(const char *s, const char *e) +{ + for (; s != e; s++) { + if (!isalnum(*s) && *s != '_') { + return 0; + } + } + + return 1; +} /* * Try to open, return descriptor if successful, NULL otherwise. * An invalid netmap name will return errno = 0; * You can pass a pointer to a pre-filled nm_desc to add special * parameters. Flags is used as follows - * NM_OPEN_NO_MMAP use the memory from arg, only + * NM_OPEN_NO_MMAP use the memory from arg, only XXX avoid mmap * if the nr_arg2 (memory block) matches. * NM_OPEN_ARG1 use req.nr_arg1 from arg * NM_OPEN_ARG2 use req.nr_arg2 from arg @@ -359,20 +631,48 @@ nm_open(const char *ifname, const struct nmreq *req, u_int namelen; uint32_t nr_ringid = 0, nr_flags, nr_reg; const char *port = NULL; + const char *vpname = NULL; #define MAXERRMSG 80 char errmsg[MAXERRMSG] = ""; enum { P_START, P_RNGSFXOK, P_GETNUM, P_FLAGS, P_FLAGSOK } p_state; + int is_vale; long num; - if (strncmp(ifname, "netmap:", 7) && strncmp(ifname, "vale", 4)) { + if (strncmp(ifname, "netmap:", 7) && + strncmp(ifname, NM_BDG_NAME, strlen(NM_BDG_NAME))) { errno = 0; /* name not recognised, not an error */ return NULL; } - if (ifname[0] == 'n') + + is_vale = (ifname[0] == 'v'); + if (is_vale) { + port = index(ifname, ':'); + if (port == NULL) { + snprintf(errmsg, MAXERRMSG, + "missing ':' in vale name"); + goto fail; + } + + if (!nm_is_identifier(ifname + 4, port)) { + snprintf(errmsg, MAXERRMSG, "invalid bridge name"); + goto fail; + } + + vpname = ++port; + } else { ifname += 7; + port = ifname; + } + /* scan for a separator */ - for (port = ifname; *port && !index("-*^{}/", *port); port++) + for (; *port && !index("-*^{}/", *port); port++) ; + + if (is_vale && !nm_is_identifier(vpname, port)) { + snprintf(errmsg, MAXERRMSG, "invalid bridge port name"); + goto fail; + } + namelen = port - ifname; if (namelen >= sizeof(d->req.nr_name)) { snprintf(errmsg, MAXERRMSG, "name too long"); @@ -449,6 +749,12 @@ nm_open(const char *ifname, const struct nmreq *req, case 'r': nr_flags |= NR_MONITOR_RX; break; + case 'R': + nr_flags |= NR_RX_RINGS_ONLY; + break; + case 'T': + nr_flags |= NR_TX_RINGS_ONLY; + break; default: snprintf(errmsg, MAXERRMSG, "unrecognized flag: '%c'", *port); goto fail; @@ -462,6 +768,11 @@ nm_open(const char *ifname, const struct nmreq *req, snprintf(errmsg, MAXERRMSG, "unexpected end of port name"); goto fail; } + if ((nr_flags & NR_ZCOPY_MON) && + !(nr_flags & (NR_MONITOR_TX|NR_MONITOR_RX))) { + snprintf(errmsg, MAXERRMSG, "'z' used but neither 'r', nor 't' found"); + goto fail; + } ND("flags: %s %s %s %s", (nr_flags & NR_EXCLUSIVE) ? "EXCLUSIVE" : "", (nr_flags & NR_ZCOPY_MON) ? "ZCOPY_MON" : "", @@ -474,7 +785,7 @@ nm_open(const char *ifname, const struct nmreq *req, return NULL; } d->self = d; /* set this early so nm_close() works */ - d->fd = open("/dev/netmap", O_RDWR); + d->fd = open(NETMAP_DEVICE_NAME, O_RDWR); if (d->fd < 0) { snprintf(errmsg, MAXERRMSG, "cannot open /dev/netmap: %s", strerror(errno)); goto fail; @@ -487,7 +798,7 @@ nm_open(const char *ifname, const struct nmreq *req, /* these fields are overridden by ifname and flags processing */ d->req.nr_ringid |= nr_ringid; - d->req.nr_flags = nr_flags; + d->req.nr_flags |= nr_flags; memcpy(d->req.nr_name, ifname, namelen); d->req.nr_name[namelen] = '\0'; /* optionally import info from parent */ @@ -529,31 +840,10 @@ nm_open(const char *ifname, const struct nmreq *req, goto fail; } - if (IS_NETMAP_DESC(parent) && parent->mem && - parent->req.nr_arg2 == d->req.nr_arg2) { - /* do not mmap, inherit from parent */ - d->memsize = parent->memsize; - d->mem = parent->mem; - } else { - /* XXX TODO: check if memsize is too large (or there is overflow) */ - d->memsize = d->req.nr_memsize; - d->mem = mmap(0, d->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, - d->fd, 0); - if (d->mem == MAP_FAILED) { - snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno)); - goto fail; - } - d->done_mmap = 1; - } - { - struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset); - struct netmap_ring *r = NETMAP_RXRING(nifp, ); - - *(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp; - *(struct netmap_ring **)(uintptr_t)&d->some_ring = r; - *(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0); - *(void **)(uintptr_t)&d->buf_end = - (char *)d->mem + d->memsize; + /* if parent is defined, do nm_mmap() even if NM_OPEN_NO_MMAP is set */ + if ((!(new_flags & NM_OPEN_NO_MMAP) || parent) && nm_mmap(d, parent)) { + snprintf(errmsg, MAXERRMSG, "mmap failed: %s", strerror(errno)); + goto fail; } nr_reg = d->req.nr_flags & NR_REG_MASK; @@ -626,14 +916,54 @@ nm_close(struct nm_desc *d) return EINVAL; if (d->done_mmap && d->mem) munmap(d->mem, d->memsize); - if (d->fd != -1) + if (d->fd != -1) { close(d->fd); + } + bzero(d, sizeof(*d)); free(d); return 0; } +static int +nm_mmap(struct nm_desc *d, const struct nm_desc *parent) +{ + //XXX TODO: check if mmap is already done + + if (IS_NETMAP_DESC(parent) && parent->mem && + parent->req.nr_arg2 == d->req.nr_arg2) { + /* do not mmap, inherit from parent */ + D("do not mmap, inherit from parent"); + d->memsize = parent->memsize; + d->mem = parent->mem; + } else { + /* XXX TODO: check if memsize is too large (or there is overflow) */ + d->memsize = d->req.nr_memsize; + d->mem = mmap(0, d->memsize, PROT_WRITE | PROT_READ, MAP_SHARED, + d->fd, 0); + if (d->mem == MAP_FAILED) { + goto fail; + } + d->done_mmap = 1; + } + { + struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset); + struct netmap_ring *r = NETMAP_RXRING(nifp, ); + + *(struct netmap_if **)(uintptr_t)&(d->nifp) = nifp; + *(struct netmap_ring **)(uintptr_t)&d->some_ring = r; + *(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0); + *(void **)(uintptr_t)&d->buf_end = + (char *)d->mem + d->memsize; + } + + return 0; + +fail: + return EINVAL; +} + /* * Same prototype as pcap_inject(), only need to cast. */ @@ -674,6 +1004,9 @@ nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg) { int n = d->last_rx_ring - d->first_rx_ring + 1; int c, got = 0, ri = d->cur_rx_ring; + d->hdr.buf = NULL; + d->hdr.flags = NM_MORE_PKTS; + d->hdr.d = d; if (cnt == 0) cnt = -1; @@ -690,17 +1023,24 @@ nm_dispatch(struct nm_desc *d, int cnt, nm_cb_t cb, u_char *arg) ri = d->first_rx_ring; ring = NETMAP_RXRING(d->nifp, ri); for ( ; !nm_ring_empty(ring) && cnt != got; got++) { - u_int i = ring->cur; - u_int idx = ring->slot[i].buf_idx; - u_char *buf = (u_char *)NETMAP_BUF(ring, idx); - + u_int idx, i; + if (d->hdr.buf) { /* from previous round */ + cb(arg, &d->hdr, d->hdr.buf); + } + i = ring->cur; + idx = ring->slot[i].buf_idx; + d->hdr.slot = &ring->slot[i]; + d->hdr.buf = (u_char *)NETMAP_BUF(ring, idx); // __builtin_prefetch(buf); d->hdr.len = d->hdr.caplen = ring->slot[i].len; d->hdr.ts = ring->ts; - cb(arg, &d->hdr, buf); ring->head = ring->cur = nm_ring_next(ring, i); } } + if (d->hdr.buf) { /* from previous round */ + d->hdr.flags = 0; + cb(arg, &d->hdr, d->hdr.buf); + } d->cur_rx_ring = ri; return got; } diff --git a/sys/net/netmap_virt.h b/sys/net/netmap_virt.h new file mode 100644 index 000000000000..e17dcf854a99 --- /dev/null +++ b/sys/net/netmap_virt.h @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2013-2016 Luigi Rizzo + * Copyright (C) 2013-2016 Giuseppe Lettieri + * Copyright (C) 2013-2016 Vincenzo Maffione + * Copyright (C) 2015 Stefano Garzarella + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#ifndef NETMAP_VIRT_H +#define NETMAP_VIRT_H + +#define NETMAP_VIRT_CSB_SIZE 4096 + +/* ptnetmap features */ +#define PTNETMAP_F_BASE 1 +#define PTNETMAP_F_FULL 2 /* not used */ +#define PTNETMAP_F_VNET_HDR 4 + +/* + * ptnetmap_memdev: device used to expose memory into the guest VM + * + * These macros are used in the hypervisor frontend (QEMU, bhyve) and in the + * guest device driver. + */ + +/* PCI identifiers and PCI BARs for the ptnetmap memdev + * and ptnetmap network interface. */ +#define PTNETMAP_MEMDEV_NAME "ptnetmap-memdev" +#define PTNETMAP_PCI_VENDOR_ID 0x3333 /* TODO change vendor_id */ +#define PTNETMAP_PCI_DEVICE_ID 0x0001 /* memory device */ +#define PTNETMAP_PCI_NETIF_ID 0x0002 /* ptnet network interface */ +#define PTNETMAP_IO_PCI_BAR 0 +#define PTNETMAP_MEM_PCI_BAR 1 +#define PTNETMAP_MSIX_PCI_BAR 2 + +/* Registers for the ptnetmap memdev */ +/* 32 bit r/o */ +#define PTNETMAP_IO_PCI_MEMSIZE 0 /* size of the netmap memory shared + * between guest and host */ +/* 16 bit r/o */ +#define PTNETMAP_IO_PCI_HOSTID 4 /* memory allocator ID in netmap host */ +#define PTNETMAP_IO_SIZE 6 + +/* + * ptnetmap configuration + * + * The hypervisor (QEMU or bhyve) sends this struct to the host netmap + * module through an ioctl() command when it wants to start the ptnetmap + * kthreads. + */ +struct ptnetmap_cfg { +#define PTNETMAP_CFG_FEAT_CSB 0x0001 +#define PTNETMAP_CFG_FEAT_EVENTFD 0x0002 +#define PTNETMAP_CFG_FEAT_IOCTL 0x0004 + uint32_t features; + void *ptrings; /* ptrings inside CSB */ + uint32_t num_rings; /* number of entries */ + struct ptnet_ring_cfg entries[0]; /* per-ptring configuration */ +}; + +/* + * Functions used to write ptnetmap_cfg from/to the nmreq. + * The user-space application writes the pointer of ptnetmap_cfg + * (user-space buffer) starting from nr_arg1 field, so that the kernel + * can read it with copyin (copy_from_user). + */ +static inline void +ptnetmap_write_cfg(struct nmreq *nmr, struct ptnetmap_cfg *cfg) +{ + uintptr_t *nmr_ptncfg = (uintptr_t *)&nmr->nr_arg1; + *nmr_ptncfg = (uintptr_t)cfg; +} + +/* ptnetmap control commands */ +#define PTNETMAP_PTCTL_CONFIG 1 +#define PTNETMAP_PTCTL_FINALIZE 2 +#define PTNETMAP_PTCTL_IFNEW 3 +#define PTNETMAP_PTCTL_IFDELETE 4 +#define PTNETMAP_PTCTL_RINGSCREATE 5 +#define PTNETMAP_PTCTL_RINGSDELETE 6 +#define PTNETMAP_PTCTL_DEREF 7 +#define PTNETMAP_PTCTL_TXSYNC 8 +#define PTNETMAP_PTCTL_RXSYNC 9 +#define PTNETMAP_PTCTL_REGIF 10 +#define PTNETMAP_PTCTL_UNREGIF 11 +#define PTNETMAP_PTCTL_HOSTMEMID 12 + + +/* I/O registers for the ptnet device. */ +#define PTNET_IO_PTFEAT 0 +#define PTNET_IO_PTCTL 4 +#define PTNET_IO_PTSTS 8 +#define PTNET_IO_MAC_LO 12 +#define PTNET_IO_MAC_HI 16 +#define PTNET_IO_CSBBAH 20 +#define PTNET_IO_CSBBAL 24 +#define PTNET_IO_NIFP_OFS 28 +#define PTNET_IO_NUM_TX_RINGS 32 +#define PTNET_IO_NUM_RX_RINGS 36 +#define PTNET_IO_NUM_TX_SLOTS 40 +#define PTNET_IO_NUM_RX_SLOTS 44 +#define PTNET_IO_VNET_HDR_LEN 48 +#define PTNET_IO_END 52 +#define PTNET_IO_KICK_BASE 128 +#define PTNET_IO_MASK 0xff + +/* If defined, CSB is allocated by the guest, not by the host. */ +#define PTNET_CSB_ALLOC + +/* ptnetmap ring fields shared between guest and host */ +struct ptnet_ring { + /* XXX revise the layout to minimize cache bounces. */ + uint32_t head; /* GW+ HR+ the head of the guest netmap_ring */ + uint32_t cur; /* GW+ HR+ the cur of the guest netmap_ring */ + uint32_t guest_need_kick; /* GW+ HR+ host-->guest notification enable */ + uint32_t sync_flags; /* GW+ HR+ the flags of the guest [tx|rx]sync() */ + uint32_t hwcur; /* GR+ HW+ the hwcur of the host netmap_kring */ + uint32_t hwtail; /* GR+ HW+ the hwtail of the host netmap_kring */ + uint32_t host_need_kick; /* GR+ HW+ guest-->host notification enable */ + char pad[4]; +}; + +/* CSB for the ptnet device. */ +struct ptnet_csb { + struct ptnet_ring rings[NETMAP_VIRT_CSB_SIZE/sizeof(struct ptnet_ring)]; +}; + +#if defined (WITH_PTNETMAP_HOST) || defined (WITH_PTNETMAP_GUEST) + +/* return l_elem - r_elem with wraparound */ +static inline uint32_t +ptn_sub(uint32_t l_elem, uint32_t r_elem, uint32_t num_slots) +{ + int64_t res; + + res = (int64_t)(l_elem) - r_elem; + + return (res < 0) ? res + num_slots : res; +} +#endif /* WITH_PTNETMAP_HOST || WITH_PTNETMAP_GUEST */ + +#ifdef WITH_PTNETMAP_GUEST + +/* ptnetmap_memdev routines used to talk with ptnetmap_memdev device driver */ +struct ptnetmap_memdev; +int nm_os_pt_memdev_iomap(struct ptnetmap_memdev *, vm_paddr_t *, void **); +void nm_os_pt_memdev_iounmap(struct ptnetmap_memdev *); + +/* Guest driver: Write kring pointers (cur, head) to the CSB. + * This routine is coupled with ptnetmap_host_read_kring_csb(). */ +static inline void +ptnetmap_guest_write_kring_csb(struct ptnet_ring *ptr, uint32_t cur, + uint32_t head) +{ + /* + * We need to write cur and head to the CSB but we cannot do it atomically. + * There is no way we can prevent the host from reading the updated value + * of one of the two and the old value of the other. However, if we make + * sure that the host never reads a value of head more recent than the + * value of cur we are safe. We can allow the host to read a value of cur + * more recent than the value of head, since in the netmap ring cur can be + * ahead of head and cur cannot wrap around head because it must be behind + * tail. Inverting the order of writes below could instead result into the + * host to think head went ahead of cur, which would cause the sync + * prologue to fail. + * + * The following memory barrier scheme is used to make this happen: + * + * Guest Host + * + * STORE(cur) LOAD(head) + * mb() <-----------> mb() + * STORE(head) LOAD(cur) + */ + ptr->cur = cur; + mb(); + ptr->head = head; +} + +/* Guest driver: Read kring pointers (hwcur, hwtail) from the CSB. + * This routine is coupled with ptnetmap_host_write_kring_csb(). */ +static inline void +ptnetmap_guest_read_kring_csb(struct ptnet_ring *ptr, struct netmap_kring *kring) +{ + /* + * We place a memory barrier to make sure that the update of hwtail never + * overtakes the update of hwcur. + * (see explanation in ptnetmap_host_write_kring_csb). + */ + kring->nr_hwtail = ptr->hwtail; + mb(); + kring->nr_hwcur = ptr->hwcur; +} + +#endif /* WITH_PTNETMAP_GUEST */ + +#ifdef WITH_PTNETMAP_HOST +/* + * ptnetmap kernel thread routines + * */ + +/* Functions to read and write CSB fields in the host */ +#if defined (linux) +#define CSB_READ(csb, field, r) (get_user(r, &csb->field)) +#define CSB_WRITE(csb, field, v) (put_user(v, &csb->field)) +#else /* ! linux */ +#define CSB_READ(csb, field, r) (r = fuword32(&csb->field)) +#define CSB_WRITE(csb, field, v) (suword32(&csb->field, v)) +#endif /* ! linux */ + +/* Host netmap: Write kring pointers (hwcur, hwtail) to the CSB. + * This routine is coupled with ptnetmap_guest_read_kring_csb(). */ +static inline void +ptnetmap_host_write_kring_csb(struct ptnet_ring __user *ptr, uint32_t hwcur, + uint32_t hwtail) +{ + /* + * The same scheme used in ptnetmap_guest_write_kring_csb() applies here. + * We allow the guest to read a value of hwcur more recent than the value + * of hwtail, since this would anyway result in a consistent view of the + * ring state (and hwcur can never wraparound hwtail, since hwcur must be + * behind head). + * + * The following memory barrier scheme is used to make this happen: + * + * Guest Host + * + * STORE(hwcur) LOAD(hwtail) + * mb() <-------------> mb() + * STORE(hwtail) LOAD(hwcur) + */ + CSB_WRITE(ptr, hwcur, hwcur); + mb(); + CSB_WRITE(ptr, hwtail, hwtail); +} + +/* Host netmap: Read kring pointers (head, cur, sync_flags) from the CSB. + * This routine is coupled with ptnetmap_guest_write_kring_csb(). */ +static inline void +ptnetmap_host_read_kring_csb(struct ptnet_ring __user *ptr, + struct netmap_ring *shadow_ring, + uint32_t num_slots) +{ + /* + * We place a memory barrier to make sure that the update of head never + * overtakes the update of cur. + * (see explanation in ptnetmap_guest_write_kring_csb). + */ + CSB_READ(ptr, head, shadow_ring->head); + mb(); + CSB_READ(ptr, cur, shadow_ring->cur); + CSB_READ(ptr, sync_flags, shadow_ring->flags); +} + +#endif /* WITH_PTNETMAP_HOST */ + +#endif /* NETMAP_VIRT_H */ diff --git a/sys/net/rndis.h b/sys/net/rndis.h index 9da76bc08d24..95edb1c5d7e4 100644 --- a/sys/net/rndis.h +++ b/sys/net/rndis.h @@ -320,6 +320,10 @@ struct rndis_status_msg { /* rndis_diag_info */ }; +/* stbuf offset from the beginning of rndis_status_msg. */ +#define RNDIS_STBUFOFFSET_ABS(ofs) \ + ((ofs) + __offsetof(struct rndis_status_msg, rm_status)) + /* * Immediately after rndis_status_msg.rm_stbufoffset, if a control * message is malformatted, or a packet message contains inappropriate diff --git a/sys/net80211/ieee80211_freebsd.h b/sys/net80211/ieee80211_freebsd.h index 82b0ae5b316e..f21423c3e375 100644 --- a/sys/net80211/ieee80211_freebsd.h +++ b/sys/net80211/ieee80211_freebsd.h @@ -652,6 +652,12 @@ int ieee80211_get_xmit_params(struct mbuf *m, #define IEEE80211_RX_F_AMSDU_MORE 0x00000008 /* This is another decap AMSDU frame in the batch */ #define IEEE80211_RX_F_AMPDU 0x00000010 /* This is the start of an decap AMPDU list */ #define IEEE80211_RX_F_AMPDU_MORE 0x00000020 /* This is another decap AMPDU frame in the batch */ +#define IEEE80211_RX_F_FAIL_FCSCRC 0x00000040 /* Failed CRC/FCS */ +#define IEEE80211_RX_F_FAIL_MIC 0x00000080 /* Failed MIC check */ +#define IEEE80211_RX_F_DECRYPTED 0x00000100 /* Hardware decrypted */ +#define IEEE80211_RX_F_IV_STRIP 0x00000200 /* Decrypted; IV stripped */ +#define IEEE80211_RX_F_MMIC_STRIP 0x00000400 /* Decrypted; MMIC stripped */ +#define IEEE80211_RX_F_SHORTGI 0x00000800 /* This is a short-GI frame */ /* Channel width */ #define IEEE80211_RX_FW_20MHZ 1 diff --git a/sys/net80211/ieee80211_scan_sw.c b/sys/net80211/ieee80211_scan_sw.c index 0c1a46553bb0..6313d46177dc 100644 --- a/sys/net80211/ieee80211_scan_sw.c +++ b/sys/net80211/ieee80211_scan_sw.c @@ -412,6 +412,12 @@ ieee80211_swscan_bg_scan(const struct ieee80211_scanner *scan, return (ic->ic_flags & IEEE80211_F_SCAN); } +/* + * Taskqueue work to cancel a scan. + * + * Note: for offload scan devices, we may want to call into the + * driver to try and cancel scanning, however it may not be cancelable. + */ static void cancel_scan(struct ieee80211vap *vap, int any, const char *func) { @@ -511,6 +517,12 @@ ieee80211_swscan_probe_curchan(struct ieee80211vap *vap, int force) struct ifnet *ifp = vap->iv_ifp; int i; + /* + * Full-offload scan devices don't require this. + */ + if (vap->iv_flags_ext & IEEE80211_FEXT_SCAN_OFFLOAD) + return; + /* * Send directed probe requests followed by any * broadcast probe request. @@ -617,7 +629,14 @@ scan_start(void *arg, int pending) return; } - if (vap->iv_opmode == IEEE80211_M_STA && + /* + * Put the station into power save mode. + * + * This is only required if we're not a full-offload devices; + * those devices manage scan/traffic differently. + */ + if (((vap->iv_flags_ext & IEEE80211_FEXT_SCAN_OFFLOAD) == 0) && + vap->iv_opmode == IEEE80211_M_STA && vap->iv_state == IEEE80211_S_RUN) { if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) { /* Enable station power save mode */ @@ -870,7 +889,12 @@ scan_done(struct ieee80211_scan_state *ss, int scandone) * waiting for us. */ if (scandone) { - vap->iv_sta_ps(vap, 0); + /* + * If we're not a scan offload device, come back out of + * station powersave. Offload devices handle this themselves. + */ + if ((vap->iv_flags_ext & IEEE80211_FEXT_SCAN_OFFLOAD) == 0) + vap->iv_sta_ps(vap, 0); if (ss->ss_next >= ss->ss_last) ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN; diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h index 5ca3f43a3335..479a8d62a825 100644 --- a/sys/net80211/ieee80211_var.h +++ b/sys/net80211/ieee80211_var.h @@ -601,11 +601,12 @@ MALLOC_DECLARE(M_80211_VAP); #define IEEE80211_FEXT_WDSLEGACY 0x00010000 /* CONF: legacy WDS operation */ #define IEEE80211_FEXT_PROBECHAN 0x00020000 /* CONF: probe passive channel*/ #define IEEE80211_FEXT_UNIQMAC 0x00040000 /* CONF: user or computed mac */ +#define IEEE80211_FEXT_SCAN_OFFLOAD 0x00080000 /* CONF: scan is fully offloaded */ #define IEEE80211_FEXT_BITS \ "\20\2INACT\3SCANWAIT\4BGSCAN\5WPS\6TSN\7SCANREQ\10RESUME" \ "\0114ADDR\12NONEPR_PR\13SWBMISS\14DFS\15DOTD\16STATEWAIT\17REINIT" \ - "\20BPF\21WDSLEGACY\22PROBECHAN\23UNIQMAC" + "\20BPF\21WDSLEGACY\22PROBECHAN\23UNIQMAC\24SCAN_OFFLOAD" /* ic_flags_ht/iv_flags_ht */ #define IEEE80211_FHT_NONHT_PR 0x00000001 /* STATUS: non-HT sta present */ diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index 867c5e8f76e8..137fecc614f1 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -457,6 +457,8 @@ icmp_input(struct mbuf **mp, int *offp, int proto) * Treat subcodes 2,3 as immediate RST */ case ICMP_UNREACH_PROTOCOL: + code = PRC_UNREACH_PROTOCOL; + break; case ICMP_UNREACH_PORT: code = PRC_UNREACH_PORT; break; diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 258ee00cd275..ed61e64a0ede 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -920,6 +920,16 @@ tcp_input(struct mbuf **mp, int *offp, int proto) goto dropwithreset; } INP_WLOCK_ASSERT(inp); + /* + * While waiting for inp lock during the lookup, another thread + * can have dropped the inpcb, in which case we need to loop back + * and try to find a new inpcb to deliver to. + */ + if (inp->inp_flags & INP_DROPPED) { + INP_WUNLOCK(inp); + inp = NULL; + goto findpcb; + } if ((inp->inp_flowtype == M_HASHTYPE_NONE) && (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) && ((inp->inp_socket == NULL) || @@ -980,6 +990,10 @@ tcp_input(struct mbuf **mp, int *offp, int proto) if (in_pcbrele_wlocked(inp)) { inp = NULL; goto findpcb; + } else if (inp->inp_flags & INP_DROPPED) { + INP_WUNLOCK(inp); + inp = NULL; + goto findpcb; } } else ti_locked = TI_RLOCKED; @@ -1039,6 +1053,10 @@ tcp_input(struct mbuf **mp, int *offp, int proto) if (in_pcbrele_wlocked(inp)) { inp = NULL; goto findpcb; + } else if (inp->inp_flags & INP_DROPPED) { + INP_WUNLOCK(inp); + inp = NULL; + goto findpcb; } goto relocked; } else @@ -3758,7 +3776,15 @@ tcp_mss(struct tcpcb *tp, int offer) (void)sbreserve_locked(&so->so_snd, bufsize, so, NULL); } SOCKBUF_UNLOCK(&so->so_snd); - tp->t_maxseg = mss; + /* + * Sanity check: make sure that maxseg will be large + * enough to allow some data on segments even if the + * all the option space is used (40bytes). Otherwise + * funny things may happen in tcp_output. + * + * XXXGL: shouldn't we reserve space for IP/IPv6 options? + */ + tp->t_maxseg = max(mss, 64); SOCKBUF_LOCK(&so->so_rcv); if ((so->so_rcv.sb_hiwat == V_tcp_recvspace) && metrics.rmx_recvpipe) diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index e69c3d45d0f4..77e2d31d0b18 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -1968,7 +1968,8 @@ tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip) if (cmd == PRC_MSGSIZE) notify = tcp_mtudisc_notify; else if (V_icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB || - cmd == PRC_UNREACH_PORT || cmd == PRC_TIMXCEED_INTRANS) && ip) + cmd == PRC_UNREACH_PORT || cmd == PRC_UNREACH_PROTOCOL || + cmd == PRC_TIMXCEED_INTRANS) && ip) notify = tcp_drop_syn_sent; /* @@ -2100,8 +2101,8 @@ tcp6_ctlinput(int cmd, struct sockaddr *sa, void *d) if (cmd == PRC_MSGSIZE) notify = tcp_mtudisc_notify; else if (V_icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB || - cmd == PRC_UNREACH_PORT || cmd == PRC_TIMXCEED_INTRANS) && - ip6 != NULL) + cmd == PRC_UNREACH_PORT || cmd == PRC_UNREACH_PROTOCOL || + cmd == PRC_TIMXCEED_INTRANS) && ip6 != NULL) notify = tcp_drop_syn_sent; /* diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index a8b78f9379d4..27b965ea2655 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -231,6 +231,10 @@ tcp_twstart(struct tcpcb *tp) INP_INFO_RLOCK_ASSERT(&V_tcbinfo); INP_WLOCK_ASSERT(inp); + /* A dropped inp should never transition to TIME_WAIT state. */ + KASSERT((inp->inp_flags & INP_DROPPED) == 0, ("tcp_twstart: " + "(inp->inp_flags & INP_DROPPED) != 0")); + if (V_nolocaltimewait) { int error = 0; #ifdef INET6 diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 0edd723cc7d3..ede48fa509d9 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #ifdef DDB #include @@ -210,10 +211,26 @@ tcp_detach(struct socket *so, struct inpcb *inp) * In all three cases the tcptw should not be freed here. */ if (inp->inp_flags & INP_DROPPED) { - KASSERT(tp == NULL, ("tcp_detach: INP_TIMEWAIT && " - "INP_DROPPED && tp != NULL")); in_pcbdetach(inp); - in_pcbfree(inp); + if (__predict_true(tp == NULL)) { + in_pcbfree(inp); + } else { + /* + * This case should not happen as in TIMEWAIT + * state the inp should not be destroyed before + * its tcptw. If INVARIANTS is defined, panic. + */ +#ifdef INVARIANTS + panic("%s: Panic before an inp double-free: " + "INP_TIMEWAIT && INP_DROPPED && tp != NULL" + , __func__); +#else + log(LOG_ERR, "%s: Avoid an inp double-free: " + "INP_TIMEWAIT && INP_DROPPED && tp != NULL" + , __func__); +#endif + INP_WUNLOCK(inp); + } } else { in_pcbdetach(inp); INP_WUNLOCK(inp); diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index a7e127139a05..b6342e284d2f 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -490,7 +490,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto) break; case ICMP6_DST_UNREACH_ADMIN: icmp6_ifstat_inc(ifp, ifs6_in_adminprohib); - code = PRC_UNREACH_PROTOCOL; /* is this a good code? */ + code = PRC_UNREACH_ADMIN_PROHIB; break; case ICMP6_DST_UNREACH_BEYONDSCOPE: /* I mean "source address was incorrect." */ diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index ba0fd1f5e6e1..403e419d1789 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1772,6 +1772,6 @@ u_char inet6ctlerrmap[PRC_NCMDS] = { 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, EMSGSIZE, EHOSTUNREACH, 0, 0, - 0, 0, 0, 0, - ENOPROTOOPT + 0, 0, EHOSTUNREACH, 0, + ENOPROTOOPT, ECONNREFUSED }; diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 6045ee1e185b..49b89564b978 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -1393,6 +1393,15 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt) int retval; #endif +/* + * Don't use more than a quarter of mbuf clusters. N.B.: + * nmbclusters is an int, but nmbclusters * MCLBYTES may overflow + * on LP64 architectures, so cast to u_long to avoid undefined + * behavior. ILP32 architectures cannot have nmbclusters + * large enough to overflow for other reasons. + */ +#define IPV6_PKTOPTIONS_MBUF_LIMIT ((u_long)nmbclusters * MCLBYTES / 4) + level = sopt->sopt_level; op = sopt->sopt_dir; optname = sopt->sopt_name; @@ -1448,6 +1457,12 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt) { struct mbuf *m; + if (optlen > IPV6_PKTOPTIONS_MBUF_LIMIT) { + printf("ip6_ctloutput: mbuf limit hit\n"); + error = ENOBUFS; + break; + } + error = soopt_getm(sopt, &m); /* XXX */ if (error != 0) break; diff --git a/sys/netpfil/ipfw/ip_fw_table.c b/sys/netpfil/ipfw/ip_fw_table.c index 84a13fa5dff7..8f55ccf8f15e 100644 --- a/sys/netpfil/ipfw/ip_fw_table.c +++ b/sys/netpfil/ipfw/ip_fw_table.c @@ -1087,6 +1087,7 @@ find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct table_config *tc; struct table_algo *ta; struct table_info *kti; + struct table_value *pval; struct namedobj_instance *ni; int error; size_t sz; @@ -1132,7 +1133,10 @@ find_table_entry(struct ip_fw_chain *ch, ip_fw3_opheader *op3, return (ENOTSUP); error = ta->find_tentry(tc->astate, kti, tent); - + if (error == 0) { + pval = get_table_value(ch, tc, tent->v.kidx); + ipfw_export_table_value_v1(pval, &tent->v.value); + } IPFW_UH_RUNLOCK(ch); return (error); diff --git a/sys/opencrypto/crypto.c b/sys/opencrypto/crypto.c index 44fbdf8fd7a6..9e769c34fea1 100644 --- a/sys/opencrypto/crypto.c +++ b/sys/opencrypto/crypto.c @@ -81,7 +81,7 @@ __FBSDID("$FreeBSD$"); #include #include "cryptodev_if.h" -#if defined(__i386__) || defined(__amd64__) +#if defined(__i386__) || defined(__amd64__) || defined(__aarch64__) #include #endif @@ -1246,7 +1246,7 @@ crypto_proc(void) u_int32_t hid; int result, hint; -#if defined(__i386__) || defined(__amd64__) +#if defined(__i386__) || defined(__amd64__) || defined(__aarch64__) fpu_kern_thread(FPU_KERN_NORMAL); #endif diff --git a/sys/powerpc/conf/dpaa/files.dpaa b/sys/powerpc/conf/dpaa/files.dpaa index 2975838775b1..18c44f9df91a 100644 --- a/sys/powerpc/conf/dpaa/files.dpaa +++ b/sys/powerpc/conf/dpaa/files.dpaa @@ -87,6 +87,8 @@ dev/dpaa/qman_fdt.c optional dpaa fdt \ no-depend compile-with "${DPAA_COMPILE_CMD}" dev/dpaa/fman.c optional dpaa fdt \ no-depend compile-with "${DPAA_COMPILE_CMD}" +dev/dpaa/fman_mdio.c optional dpaa fdt \ + no-depend compile-with "${DPAA_COMPILE_CMD}" dev/dpaa/fman_fdt.c optional dpaa fdt \ no-depend compile-with "${DPAA_COMPILE_CMD}" dev/dpaa/if_dtsec.c optional dpaa \ diff --git a/sys/powerpc/fpu/fpu_emu.c b/sys/powerpc/fpu/fpu_emu.c index 011b9999db99..6d4e20cd7a82 100644 --- a/sys/powerpc/fpu/fpu_emu.c +++ b/sys/powerpc/fpu/fpu_emu.c @@ -185,8 +185,8 @@ fpu_dumpfpn(struct fpn *fp) int fpu_emulate(struct trapframe *frame, struct fpu *fpf) { - static union instr insn; - static struct fpemu fe; + union instr insn; + struct fpemu fe; static int lastill = 0; int sig; diff --git a/sys/powerpc/powerpc/machdep.c b/sys/powerpc/powerpc/machdep.c index cec335d29eaf..01f26d79ae40 100644 --- a/sys/powerpc/powerpc/machdep.c +++ b/sys/powerpc/powerpc/machdep.c @@ -238,6 +238,7 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) vm_offset_t startkernel, endkernel; void *kmdp; char *env; + bool ofw_bootargs = false; #ifdef DDB vm_offset_t ksym_start; vm_offset_t ksym_end; @@ -295,6 +296,7 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) bzero(__bss_start, _end - __bss_start); #endif init_static_kenv(init_kenv, sizeof(init_kenv)); + ofw_bootargs = true; } /* Store boot environment state */ OF_initial_setup((void *)fdt, NULL, (int (*)(void *))ofentry); @@ -337,7 +339,8 @@ powerpc_init(vm_offset_t fdt, vm_offset_t toc, vm_offset_t ofentry, void *mdp) OF_bootstrap(); - ofw_parse_bootargs(); + if (ofw_bootargs) + ofw_parse_bootargs(); /* * Initialize the console before printing anything. diff --git a/sys/riscv/conf/GENERIC b/sys/riscv/conf/GENERIC index aafa3979c186..ad23c6647e73 100644 --- a/sys/riscv/conf/GENERIC +++ b/sys/riscv/conf/GENERIC @@ -25,7 +25,7 @@ makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols # makeoptions WITH_CTF=1 # Run ctfconvert(1) for DTrace support # FIXME: linker error. "--relax and -r may not be used together" -makeoptions WITHOUT_MODULES="usb otusfw mwlfw ispfw mwlfw ralfw rtwnfw urtwnfw" +makeoptions WITHOUT_MODULES="usb otusfw mwlfw ispfw mwlfw ralfw rtwnfw" # makeoptions NO_MODULES options SCHED_ULE # ULE scheduler diff --git a/sys/sys/cdefs.h b/sys/sys/cdefs.h index 89516cf4a835..dd187847e770 100644 --- a/sys/sys/cdefs.h +++ b/sys/sys/cdefs.h @@ -341,6 +341,20 @@ __builtin_types_compatible_p(__typeof(expr), t), yes, no) #endif +/* + * C99 Static array indices in function parameter declarations. Syntax such as: + * void bar(int myArray[static 10]); + * is allowed in C99 but not in C++. Define __min_size appropriately so + * headers using it can be compiled in either language. Use like this: + * void bar(int myArray[__min_size(10)]); + */ +#if !defined(__cplusplus) && \ + (!defined(__STDC_VERSION) || (__STDC_VERSION__ >= 199901)) +#define __min_size(x) static (x) +#else +#define __min_size(x) (x) +#endif + #if __GNUC_PREREQ__(2, 96) #define __malloc_like __attribute__((__malloc__)) #define __pure __attribute__((__pure__)) diff --git a/sys/sys/efi.h b/sys/sys/efi.h index 81c6fd32468f..68fc2816e494 100644 --- a/sys/sys/efi.h +++ b/sys/sys/efi.h @@ -165,9 +165,6 @@ struct efi_systbl { #ifdef _KERNEL extern vm_paddr_t efi_systbl_phys; -struct cdev; -int efidev_init(struct cdev **); -int efidev_uninit(struct cdev *); #endif /* _KERNEL */ #endif /* _SYS_EFI_H_ */ diff --git a/sys/sys/md4.h b/sys/sys/md4.h index 55160ed4d399..bae52a3b02c5 100644 --- a/sys/sys/md4.h +++ b/sys/sys/md4.h @@ -39,7 +39,7 @@ __BEGIN_DECLS void MD4Init(MD4_CTX *); void MD4Update(MD4_CTX *, const unsigned char *, unsigned int); void MD4Pad(MD4_CTX *); -void MD4Final(unsigned char [static 16], MD4_CTX *); +void MD4Final(unsigned char [__min_size(16)], MD4_CTX *); #ifndef _KERNEL char * MD4End(MD4_CTX *, char *); char * MD4File(const char *, char *); diff --git a/sys/sys/md5.h b/sys/sys/md5.h index 8a47795cd0f0..4b59842ca96a 100644 --- a/sys/sys/md5.h +++ b/sys/sys/md5.h @@ -44,9 +44,11 @@ typedef struct MD5Context { __BEGIN_DECLS void MD5Init (MD5_CTX *); void MD5Update (MD5_CTX *, const void *, unsigned int); -void MD5Final (unsigned char[static MD5_DIGEST_LENGTH], MD5_CTX *); +void MD5Final (unsigned char[__min_size(MD5_DIGEST_LENGTH)], MD5_CTX *); #ifndef _KERNEL char * MD5End(MD5_CTX *, char *); +char * MD5Fd(int, char *); +char * MD5FdChunk(int, char *, off_t, off_t); char * MD5File(const char *, char *); char * MD5FileChunk(const char *, char *, off_t, off_t); char * MD5Data(const void *, unsigned int, char *); diff --git a/sys/sys/param.h b/sys/sys/param.h index 02576d6a2a39..7586fa97cf63 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -58,7 +58,7 @@ * in the range 5 to 9. */ #undef __FreeBSD_version -#define __FreeBSD_version 1200013 /* Master, propagated to newvers */ +#define __FreeBSD_version 1200014 /* Master, propagated to newvers */ /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD, diff --git a/sys/ufs/ffs/ffs_vnops.c b/sys/ufs/ffs/ffs_vnops.c index 2af53832d1e9..9e841f072d6a 100644 --- a/sys/ufs/ffs/ffs_vnops.c +++ b/sys/ufs/ffs/ffs_vnops.c @@ -77,6 +77,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -86,6 +87,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -102,8 +104,9 @@ __FBSDID("$FreeBSD$"); #ifdef DIRECTIO extern int ffs_rawread(struct vnode *vp, struct uio *uio, int *workdone); #endif -static vop_fsync_t ffs_fsync; static vop_fdatasync_t ffs_fdatasync; +static vop_fsync_t ffs_fsync; +static vop_getpages_t ffs_getpages; static vop_lock1_t ffs_lock; static vop_read_t ffs_read; static vop_write_t ffs_write; @@ -119,13 +122,12 @@ static vop_openextattr_t ffs_openextattr; static vop_setextattr_t ffs_setextattr; static vop_vptofh_t ffs_vptofh; - /* Global vfs data structures for ufs. */ struct vop_vector ffs_vnodeops1 = { .vop_default = &ufs_vnodeops, .vop_fsync = ffs_fsync, .vop_fdatasync = ffs_fdatasync, - .vop_getpages = vnode_pager_local_getpages, + .vop_getpages = ffs_getpages, .vop_getpages_async = vnode_pager_local_getpages_async, .vop_lock1 = ffs_lock, .vop_read = ffs_read, @@ -147,7 +149,7 @@ struct vop_vector ffs_vnodeops2 = { .vop_default = &ufs_vnodeops, .vop_fsync = ffs_fsync, .vop_fdatasync = ffs_fdatasync, - .vop_getpages = vnode_pager_local_getpages, + .vop_getpages = ffs_getpages, .vop_getpages_async = vnode_pager_local_getpages_async, .vop_lock1 = ffs_lock, .vop_read = ffs_read, @@ -1784,3 +1786,165 @@ vop_vptofh { ufhp->ufid_gen = ip->i_gen; return (0); } + +SYSCTL_DECL(_vfs_ffs); +static int use_buf_pager = 1; +SYSCTL_INT(_vfs_ffs, OID_AUTO, use_buf_pager, CTLFLAG_RWTUN, &use_buf_pager, 0, + "Always use buffer pager instead of bmap"); +static int buf_pager_relbuf; +SYSCTL_INT(_vfs_ffs, OID_AUTO, buf_pager_relbuf, CTLFLAG_RWTUN, + &buf_pager_relbuf, 0, + "Make buffer pager release buffers after reading"); + +/* + * The FFS pager. It uses buffer reads to validate pages. + * + * In contrast to the generic local pager from vm/vnode_pager.c, this + * pager correctly and easily handles volumes where the underlying + * device block size is greater than the machine page size. The + * buffer cache transparently extends the requested page run to be + * aligned at the block boundary, and does the necessary bogus page + * replacements in the addends to avoid obliterating already valid + * pages. + * + * The only non-trivial issue is that the exclusive busy state for + * pages, which is assumed by the vm_pager_getpages() interface, is + * incompatible with the VMIO buffer cache's desire to share-busy the + * pages. This function performs a trivial downgrade of the pages' + * state before reading buffers, and a less trivial upgrade from the + * shared-busy to excl-busy state after the read. + */ +static int +ffs_getpages(struct vop_getpages_args *ap) +{ + struct vnode *vp; + vm_page_t *ma, m; + vm_object_t object; + struct buf *bp; + struct ufsmount *um; + ufs_lbn_t lbn, lbnp; + vm_ooffset_t la, lb; + long bsize; + int bo_bs, count, error, i; + bool redo, lpart; + + vp = ap->a_vp; + ma = ap->a_m; + count = ap->a_count; + + um = VFSTOUFS(ap->a_vp->v_mount); + bo_bs = um->um_devvp->v_bufobj.bo_bsize; + if (!use_buf_pager && bo_bs <= PAGE_SIZE) + return (vnode_pager_generic_getpages(vp, ma, count, + ap->a_rbehind, ap->a_rahead, NULL, NULL)); + + object = vp->v_object; + la = IDX_TO_OFF(ma[count - 1]->pindex); + if (la >= object->un_pager.vnp.vnp_size) + return (VM_PAGER_BAD); + lpart = la + PAGE_SIZE > object->un_pager.vnp.vnp_size; + if (ap->a_rbehind != NULL) { + lb = IDX_TO_OFF(ma[0]->pindex); + *ap->a_rbehind = OFF_TO_IDX(lb - rounddown2(lb, bo_bs)); + } + if (ap->a_rahead != NULL) { + *ap->a_rahead = OFF_TO_IDX(roundup2(la, bo_bs) - la); + if (la + IDX_TO_OFF(*ap->a_rahead) >= + object->un_pager.vnp.vnp_size) { + *ap->a_rahead = OFF_TO_IDX(roundup2(object->un_pager. + vnp.vnp_size, PAGE_SIZE) - la); + } + } + VM_OBJECT_WLOCK(object); +again: + for (i = 0; i < count; i++) + vm_page_busy_downgrade(ma[i]); + VM_OBJECT_WUNLOCK(object); + + lbnp = -1; + for (i = 0; i < count; i++) { + m = ma[i]; + + /* + * Pages are shared busy and the object lock is not + * owned, which together allow for the pages' + * invalidation. The racy test for validity avoids + * useless creation of the buffer for the most typical + * case when invalidation is not used in redo or for + * parallel read. The shared->excl upgrade loop at + * the end of the function catches the race in a + * reliable way (protected by the object lock). + */ + if (m->valid == VM_PAGE_BITS_ALL) + continue; + + lbn = lblkno(um->um_fs, IDX_TO_OFF(m->pindex)); + if (lbn != lbnp) { + bsize = blksize(um->um_fs, VTOI(vp), lbn); + error = bread_gb(vp, lbn, bsize, NOCRED, GB_UNMAPPED, + &bp); + if (error != 0) + break; + KASSERT(1 /* racy, enable for debugging */ || + m->valid == VM_PAGE_BITS_ALL || i == count - 1, + ("buf %d %p invalid", i, m)); + if (i == count - 1 && lpart) { + VM_OBJECT_WLOCK(object); + if (m->valid != 0 && + m->valid != VM_PAGE_BITS_ALL) + vm_page_zero_invalid(m, TRUE); + VM_OBJECT_WUNLOCK(object); + } + if (LIST_EMPTY(&bp->b_dep)) { + /* + * Invalidation clears m->valid, but + * may leave B_CACHE flag if the + * buffer existed at the invalidation + * time. In this case, recycle the + * buffer to do real read on next + * bread() after redo. + * + * Otherwise B_RELBUF is not strictly + * necessary, enable to reduce buf + * cache pressure. + */ + if (buf_pager_relbuf || + m->valid != VM_PAGE_BITS_ALL) + bp->b_flags |= B_RELBUF; + + bp->b_flags &= ~B_NOCACHE; + brelse(bp); + } else { + bqrelse(bp); + } + lbnp = lbn; + } + } + + VM_OBJECT_WLOCK(object); + redo = false; + for (i = 0; i < count; i++) { + vm_page_sunbusy(ma[i]); + ma[i] = vm_page_grab(object, ma[i]->pindex, VM_ALLOC_NORMAL); + + /* + * Since the pages were only sbusy while neither the + * buffer nor the object lock was held by us, or + * reallocated while vm_page_grab() slept for busy + * relinguish, they could have been invalidated. + * Recheck the valid bits and re-read as needed. + * + * Note that the last page is made fully valid in the + * read loop, and partial validity for the page at + * index count - 1 could mean that the page was + * invalidated or removed, so we must restart for + * safety as well. + */ + if (ma[i]->valid != VM_PAGE_BITS_ALL) + redo = true; + } + if (redo && error == 0) + goto again; + VM_OBJECT_WUNLOCK(object); + return (error != 0 ? VM_PAGER_ERROR : VM_PAGER_OK); +} diff --git a/sys/vm/uma_core.c b/sys/vm/uma_core.c index e54db2a29740..90ed29721143 100644 --- a/sys/vm/uma_core.c +++ b/sys/vm/uma_core.c @@ -845,8 +845,7 @@ static void keg_drain(uma_keg_t keg) { struct slabhead freeslabs = { 0 }; - uma_slab_t slab; - uma_slab_t n; + uma_slab_t slab, tmp; /* * We don't want to take pages from statically allocated kegs at this @@ -862,15 +861,10 @@ keg_drain(uma_keg_t keg) if (keg->uk_free == 0) goto finished; - slab = LIST_FIRST(&keg->uk_free_slab); - while (slab) { - n = LIST_NEXT(slab, us_link); - - /* We have no where to free these to */ - if (slab->us_flags & UMA_SLAB_BOOT) { - slab = n; + LIST_FOREACH_SAFE(slab, &keg->uk_free_slab, us_link, tmp) { + /* We have nowhere to free these to. */ + if (slab->us_flags & UMA_SLAB_BOOT) continue; - } LIST_REMOVE(slab, us_link); keg->uk_pages -= keg->uk_ppera; @@ -880,8 +874,6 @@ keg_drain(uma_keg_t keg) UMA_HASH_REMOVE(&keg->uk_hash, slab, slab->us_data); SLIST_INSERT_HEAD(&freeslabs, slab, us_hlink); - - slab = n; } finished: KEG_UNLOCK(keg); diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c index 9257fe83ac5f..03c68dd23cba 100644 --- a/sys/vm/vm_fault.c +++ b/sys/vm/vm_fault.c @@ -722,7 +722,10 @@ RetryFault:; */ if (rv == VM_PAGER_ERROR || rv == VM_PAGER_BAD) { vm_page_lock(fs.m); - vm_page_free(fs.m); + if (fs.m->wire_count == 0) + vm_page_free(fs.m); + else + vm_page_xunbusy_maybelocked(fs.m); vm_page_unlock(fs.m); fs.m = NULL; unlock_and_deallocate(&fs); @@ -742,7 +745,10 @@ RetryFault:; */ if (fs.object != fs.first_object) { vm_page_lock(fs.m); - vm_page_free(fs.m); + if (fs.m->wire_count == 0) + vm_page_free(fs.m); + else + vm_page_xunbusy_maybelocked(fs.m); vm_page_unlock(fs.m); fs.m = NULL; } diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c index bd03a95d754a..407a046f9471 100644 --- a/sys/vm/vm_page.c +++ b/sys/vm/vm_page.c @@ -794,7 +794,7 @@ vm_page_xunbusy_locked(vm_page_t m) wakeup(m); } -static void +void vm_page_xunbusy_maybelocked(vm_page_t m) { bool lockacq; diff --git a/sys/vm/vm_page.h b/sys/vm/vm_page.h index e39c5b1d1ef6..8aca3c1d7125 100644 --- a/sys/vm/vm_page.h +++ b/sys/vm/vm_page.h @@ -495,6 +495,7 @@ boolean_t vm_page_unwire(vm_page_t m, uint8_t queue); void vm_page_updatefake(vm_page_t m, vm_paddr_t paddr, vm_memattr_t memattr); void vm_page_wire (vm_page_t); void vm_page_xunbusy_hard(vm_page_t m); +void vm_page_xunbusy_maybelocked(vm_page_t m); void vm_page_set_validclean (vm_page_t, int, int); void vm_page_clear_dirty (vm_page_t, int, int); void vm_page_set_invalid (vm_page_t, int, int); diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index a80a9c24fd60..92c28f3098ad 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -953,7 +953,7 @@ vnode_pager_generic_getpages(struct vnode *vp, vm_page_t *m, int count, if (a_rahead) *a_rahead = bp->b_pgafter; - KASSERT(bp->b_npages <= sizeof(bp->b_pages), + KASSERT(bp->b_npages <= nitems(bp->b_pages), ("%s: buf %p overflowed", __func__, bp)); /* diff --git a/sys/x86/x86/identcpu.c b/sys/x86/x86/identcpu.c index 11627cec120e..d4cc22363d58 100644 --- a/sys/x86/x86/identcpu.c +++ b/sys/x86/x86/identcpu.c @@ -148,15 +148,15 @@ sysctl_hw_machine(SYSCTL_HANDLER_ARGS) return (error); } -SYSCTL_PROC(_hw, HW_MACHINE, machine, CTLTYPE_STRING | CTLFLAG_RD, - NULL, 0, sysctl_hw_machine, "A", "Machine class"); +SYSCTL_PROC(_hw, HW_MACHINE, machine, CTLTYPE_STRING | CTLFLAG_RD | + CTLFLAG_MPSAFE, NULL, 0, sysctl_hw_machine, "A", "Machine class"); #else SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "Machine class"); #endif static char cpu_model[128]; -SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, +SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD | CTLFLAG_MPSAFE, cpu_model, 0, "Machine model"); static int hw_clockrate; @@ -165,8 +165,8 @@ SYSCTL_INT(_hw, OID_AUTO, clockrate, CTLFLAG_RD, u_int hv_high; char hv_vendor[16]; -SYSCTL_STRING(_hw, OID_AUTO, hv_vendor, CTLFLAG_RD, hv_vendor, 0, - "Hypervisor vendor"); +SYSCTL_STRING(_hw, OID_AUTO, hv_vendor, CTLFLAG_RD | CTLFLAG_MPSAFE, hv_vendor, + 0, "Hypervisor vendor"); static eventhandler_tag tsc_post_tag; diff --git a/tests/sys/Makefile b/tests/sys/Makefile index 682e21c00d37..1bcd76ec2649 100644 --- a/tests/sys/Makefile +++ b/tests/sys/Makefile @@ -6,6 +6,7 @@ TESTS_SUBDIRS+= acl TESTS_SUBDIRS+= aio TESTS_SUBDIRS+= fifo TESTS_SUBDIRS+= file +TESTS_SUBDIRS+= fs TESTS_SUBDIRS+= geom TESTS_SUBDIRS+= kern TESTS_SUBDIRS+= kqueue diff --git a/tests/sys/fs/Makefile b/tests/sys/fs/Makefile new file mode 100644 index 000000000000..c82ee143a785 --- /dev/null +++ b/tests/sys/fs/Makefile @@ -0,0 +1,23 @@ +# $FreeBSD$ + +PACKAGE= tests + +TESTSDIR= ${TESTSBASE}/sys/fs + +TESTSRC= ${SRCTOP}/contrib/netbsd-tests/fs + +#TESTS_SUBDIRS+= nullfs # XXX: needs rump +TESTS_SUBDIRS+= tmpfs + +${PACKAGE}FILES+= h_funcs.subr +${PACKAGE}FILESDIR= ${TESTSDIR} + +CLEANFILES+= h_funcs.subr +CLEANFILES+= h_funcs.subr.tmp + +h_funcs.subr: ${TESTSRC}/h_funcs.subr + cat ${.ALLSRC} | \ + sed -e '/atf_require_prog mount_$${name}/d' >>${.TARGET}.tmp + mv ${.TARGET}.tmp ${.TARGET} + +.include diff --git a/tests/sys/fs/tmpfs/Makefile b/tests/sys/fs/tmpfs/Makefile new file mode 100644 index 000000000000..63facd1d02fb --- /dev/null +++ b/tests/sys/fs/tmpfs/Makefile @@ -0,0 +1,56 @@ +# $FreeBSD$ + +PACKAGE= tests + +FILESYSTEM?= ${.CURDIR:T} + +TESTSDIR= ${TESTSBASE}/sys/fs/${FILESYSTEM} + +TESTSRC= ${SRCTOP}/contrib/netbsd-tests/fs/${FILESYSTEM} + +# XXX: uses /dev/MAKEDEV to create pseudo /dev/{null,zero} character devices +#NETBSD_ATF_TESTS_SH+= devices_test +NETBSD_ATF_TESTS_SH+= create_test +NETBSD_ATF_TESTS_SH+= read_write_test +NETBSD_ATF_TESTS_SH+= dots_test +NETBSD_ATF_TESTS_SH+= exec_test +NETBSD_ATF_TESTS_SH+= link_test +NETBSD_ATF_TESTS_SH+= mkdir_test +NETBSD_ATF_TESTS_SH+= mknod_test +NETBSD_ATF_TESTS_SH+= mount_test +# XXX: need to replace `mknod ... p` with something more sensible +#NETBSD_ATF_TESTS_SH+= pipes_test +NETBSD_ATF_TESTS_SH+= trail_slash_test +NETBSD_ATF_TESTS_SH+= readdir_test +NETBSD_ATF_TESTS_SH+= remove_test +NETBSD_ATF_TESTS_SH+= rename_test +NETBSD_ATF_TESTS_SH+= rmdir_test +NETBSD_ATF_TESTS_SH+= setattr_test +NETBSD_ATF_TESTS_SH+= sizes_test +NETBSD_ATF_TESTS_SH+= sockets_test +NETBSD_ATF_TESTS_SH+= statvfs_test +NETBSD_ATF_TESTS_SH+= symlink_test +NETBSD_ATF_TESTS_SH+= times_test +NETBSD_ATF_TESTS_SH+= truncate_test +NETBSD_ATF_TESTS_SH+= vnd_test +NETBSD_ATF_TESTS_SH+= vnode_leak_test + +${PACKAGE}FILES+= h_funcs.subr +${PACKAGE}FILESDIR= ${TESTSDIR} + +PROGS+= h_tools +BINDIR.h_tools= ${TESTSDIR} + +ATF_TESTS_SH_SED_mount_test= \ + -e 's,-o -g,-o gid=,g' \ + -e 's,-o -m,-o mode=,g' \ + -e 's,-o -s,-o size=,g' \ + -e 's,-o -u,-o uid=,g' \ + -e 's,mount_${FILESYSTEM},mount -t ${FILESYSTEM},g' +ATF_TESTS_SH_SED_sizes_test= -e 's,-o -s,-o size=,g' +ATF_TESTS_SH_SED_statvfs_test= -e 's,-o -s,-o size=,g' +ATF_TESTS_SH_SED_vnode_leak_test= -e 's,-o -s,-o size=,g' + +.include + +.include diff --git a/tests/sys/geom/class/uzip/1_endian_big.img.uzip.uue b/tests/sys/geom/class/uzip/1_endian_big.img.uzip.uue new file mode 100644 index 000000000000..b4903e487dca --- /dev/null +++ b/tests/sys/geom/class/uzip/1_endian_big.img.uzip.uue @@ -0,0 +1,87 @@ +# +# $FreeBSD$ +# + +begin 644 1_endian_big.img.uzip +M(R$O8FEN+W-H"B-6,BXP($9OFEP?'QK +M;&1L;V%D(&=E;VU?=7II<"D^)BTF)FUO=6YT7V-D.38V,"`O9&5V+V!M9&-O +M;F9I9R`M868@)#!@+G5Z:7`@)#$*97AI="`D/PH``````````````$`````` +M0`````````*0`````````I`````````"D`````````*0`````````I`````` +M```#;P````````-O````````!#$````````$,0````````2H````````!*@` +M```````&T@````````B4````````",4````````(Q0````````NZ```````` +M"[H````````,@0````````R!````````#($````````,@0````````R!```` +M````#($````````,@0````````R!````````#($````````,@0````````R! +M````````#($````````,@0````````R!````````#($````````,@0`````` +M``R!````````#($````````,@0````````R!````````#($````````,@0`` +M``````R!````````#($````````,@0````````R!````````#($````````, +M@0````````R!````````#($````````,@0````````R!````````#($````` +M```,@0````````R!````````#($````````,@0````````R!````````#($` +M```````,@0````````R!````````#($````````,@0````````R!```````` +M#($````````,@0````````R!````````#*UXVNW4/0Z",!3`\3:B,FA@A,W1 +MN,C@`3R$":?0R<'!Q.H)3+R0DZOQ(L3%N1:H:``3'=#E_TM>WX.TI7P4(0J! +MB8&)H8E(U)-"*)/\M'9M9+16)JYIZ9GHF7!LOU8>_LLT6:WJ+A`GVU/G,IH\ +M^_EOEI*.EW4K5./Y8BF`!AW3YK!W\JP>Q]5/M+Q]F.SI^L&A3,9LE,````` +M``````````````````````#PC3L712#(>-KMU#T*PD`0AN$)_FTA)*7I+,4J +MA0?P$()7L=+UKTEQMTT]]JD'K,_[P_`T7]SF%4^.$M=GJ1-Z +M`?Z"[[9/P_WD.-UV*:UNK8Y>V2;VZ,.&1ZO59U]@V5Z^3/]ELK$OY]T@A.;V +MSFH>4HO*55;2`P```````````````````````````'C'%6?Y%ZQXVNW.L0W" +M,!"&40A?'7CLTVGM*Z+?5J6>=WXN>K3-3W2+=W3+IUKC?:&UN;G]/T:9DSNFLX` +M``````````````````#@;WP`XC\HZGC:Y=MY*`11'`?PL>[<-AN28\D5Y:I= +M(6W:+<+F_H-"RLZ?8TV;&?F%;IF_Q*5\TJ;\4<,[[E=_91Y!XUZWRJ*L +M<$K35O_P<,OY"]L)!?G+E`S?C/_B1Y%*ICI1/<]L'Z-X7X$MCOE"'NZ_Y%?\ +MZ0[OY[GW0C^\?6)YG(_K:2/%-DO\V4S2"R +MO\/\7!_9?U1<3V6VEVG2#[!;OQ5&1_(N9#^;EXS,)Z+NI'7(_HMID039K[RW,(_L]Y+< +M'R+[&Q.VKI#]Z3-NT.L?NI1>"SW_N7[5R'[.,C\$V<\=K[%#]AM'%A@@^V-3 +M3M.1_;D<6SKT^F\V"WK_V\+1-1S9+^S7O$7VVY.COLC^B#D&]/^/`=D;P\C^ +MX++F*F1_4\8Z]/-KEVETK@V$8 +M!_!E88@LG]"&FQ"]K.>-")D_X+/58OL%Z<.C2#[OYY)`MF_&]+F(ON9L3W0]]^H +M?HE']MN,!CJRGU]^487L3UP[IB'[3Z/9M\A^1_*;'=E?[XUV(OMK.`-"9'^: +M2O&*[%^G;EY"Y_^5&GK^HW]86Y#]#7WN'62_/Y!Q@NR_OF'HD/WV$I*![-_8 +M]YC^_][H\2#[+"[O_DMP5Z_U7ML[F1_33=L`#9S\YI +M2T+V?W8'>,C^>\%D,[*_B`P_(/MMH?PPLM\M<\XC^\<.%,A\"FM+/([L=R0P +MOS7!#@6 +M9+_><`C]_F-4RJ'K'Z&_@_[_W-M^#KW_JSO3SB+[4\3T?F1_ZVK,"K(_(E$Z +MH><_JBL$7?]DI5/(_J/':>C^/Q/A%B/[V:I1_G\Z[R\+%8'F>-KMPS$-`"`0 +M`+%#`#MB$<^K8&J35JLZ\\X=````````````````````\-T#NY8`HWC:[91+ +M;]0P$,=WRR(J"PFNE3C,TDJ`M%T!%Q`E%2"$Q/,P/VGC9.P9C_\SWL%@L#0X/QI.!XFEP:71TK3[ +M.#.X.#H[]14_Z.9&PX_+3`2N;34-AV%`$,0/>?O5]_#X9?F?I#/\QK+2CZ_[ +M\=S/A-G]].[]5P$_]./U/WN`^U\>?YD1_@[[RKU=/GMTU)G?]..%H^\YK[.YM/7S"V+1KE89,[ +M9[5F5PMG# +MB3ML0VLPRO@6&HR=)C+K;!F])VRCCVFL$>!XD!YL'4J'KE/&+L]$PWNG)SS+ +MA&OL8G\"I@5OJS'#=&&/-QX7X$$R%3#WN':AOQ@7/"SDF)T.5&=[=8:K7=Z= +MRWT\+A7#KR1 +MZEC+Y(]ZX"RF[*.Q+@KEY?%NE%TD?O*>$NI% +MRS3/<6-1!?"56NP+MXXB+_;'46$MBA"WR`7O"Y-25\'CZ7@>ER3/DNO:',B8 +M>(:^L4V2+I+[)`?V)^\[\$2'>VPS%B38V#O<&9^:*!/<1!4SVX[9#M:?9WNQ +M_CEOQWB1M+96=B]HN!(S6$CK0I0C5AZ[8<^VT]]R4>[^RD6A?T:"(`B"(`B" +M(`B"(`B"(`B"(`B"(`B"(`B"(`B"(`B"^/_X#/X6=T5XVNW7+0H"01B`X=EQ +M004Q>@3!,B`8A$V#;#$+1@4/(=C4H,VD[@FT>`9ABPB;-GD$,6@0L_B#)L$@ +MIOW>)\Q/?&>FC%(JI7*N8]23=BZN-J\-DL\>[_?_0;\7FZOE5G+_ +M-:^'DOO]TF@FN7]=LT7)_8U@UY'-KMT#$!```,`B"C&]T*>_9!!!(```````````````````!X405W +M`]:``($````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +=```````````````````````````````````````` +` +end diff --git a/tests/sys/geom/class/uzip/1_endian_little.img.uzip.uue b/tests/sys/geom/class/uzip/1_endian_little.img.uzip.uue new file mode 100644 index 000000000000..044dd3107929 --- /dev/null +++ b/tests/sys/geom/class/uzip/1_endian_little.img.uzip.uue @@ -0,0 +1,110 @@ +# +# $FreeBSD$ +# + +begin 644 1_endian_little.img.uzip +M(R$O8FEN+W-H"B-6,BXP($9OFEP?'QK +M;&1L;V%D(&=E;VU?=7II<"D^)BTF)FUO=6YT7V-D.38V,"`O9&5V+V!M9&-O +M;F9I9R`M868@)#!@+G5Z:7`@)#$*97AI="`D/PH``````````````$`````` +M0`````````*0`````````W<````````$G@````````>&````````!ZT````` +M```'U`````````?[````````""(````````(20````````AP````````")<` +M```````(O@````````CE````````"0P````````),P````````E:```````` +M"8$````````)J`````````G/````````"?8````````*'0````````I$```` +M````"FL````````*D@````````JY````````"N`````````+!P````````LN +M````````"U4````````+?`````````NC````````"\H````````+\0`````` +M``P8````````##\````````,9@````````R-````````#+0````````,VP`` +M``````T"````````#2D````````-4`````````UW````````#9X````````- +MQ0````````WL````````#A,````````..@````````YA````````#H@````` +M```.KP````````[6````````#OT````````/)`````````]+````````#W(` +M```````/F0````````_`````````#^<````````0#@```````!`U```````` +M$%P````````0@P```````!"J````````$-9XVNW4L0K",!"`X8LM$@1!!T$G +M.[JZ.W3Q#1Q\`P??H(LZ^T@^B*L/(L1+>L6L#E:0_X-KKTU"C[8Y$0`````` +M````````\"\F&G.-2F-E]X*ZK8=[*47NA8@3FZ#77MJ(-O'P"$&>(8PU'75C +M>M!E[3J?/4SS6D^#[-I9&I]WV%Z/J8;2HEMO\V+4-A[SQFI(4YV<^9KHS?3B +MTJ\]LW.NRO+RQW5:+=T^:_*]^T%YJ1]D"V)?D*QG?%5M^[YGWMY3[%?AY)S7 +M(L+2>F3QGN>R]QOM%H[]`0``````````@%Z]`'B8&[EXVNW9,4H#013&\?>2 +M1=:`J(6@E2G3"I86VW@#A=Q`P1ND,:ESD13!TB9-;F'K$3R`,+ZW^U8'42$$ +M-\W_!]_N;':&?0R9:4:D<60YM0PMH_@MF=7%WE@*D9>^B$ITL.=2FK@KO[RF +M).\I'5AST+ZSBPUKQK6=HUW9K9<]:S3]>W?7\X>ZAB+2CH]^GBK>>WL2-=1= +M5:8"=.5XIO5?^R3NN6'6+G9<9]32KK-)OG8W**_>#[(!OB](MF?\JRK6?-KMFL]/%#$4QQ3'Q3_"UL[`<](07X7V2V7;:OA_]OLY< +M9GN]V\W/T9VN,VV^;]Q[%]M?W[X<76U7KQ-DX=)];^U!=UWP^=-<:A?GN_NO +MBW^.OW;-^/-_B4\0!$$0!$$0!$$0!$$0!$$0!$$0!$'<#.+7YX]X/>_-OA$3 +M!'$[B/]+N=^;GQO.^G>&>',7^S_F%I@(7-MJ&,X#:440-XUEM@PK.TZ(\<'V +M"EMF;'[2_]>8]8WNB41ZVN'-6:_:H<-;`H72V+B4$*6#/VA-5E>NO +M-/<>>)7#D>0!1EI-!.S8&@<.I7!B`!M/GSQ>9>S#8<,]9$YIK%^!&,A4P +M][AVHB\')SQ,9)]==51GQW6&JUW>[7DQEZ)$LT': +MR%6M&BP6B%:@L`44FAN,LH6_@/Z+0JN8]Y5#$FI="JQ5\A6SR6J'-P\\5D_)305+=,\Q\"B"N`K-3D1;AU%GISTH\):%"&& +MR`6?%B:EKH+'W?$\+DF6)=>U.94Q\0QMXS%)NDCNDQQX/OGT!,YT>,&V8D&" +MC6>'.^/3(-KMP3$!```` +MPJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$!````PJ#U3VT, +M'Z````````````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````` +M``````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````````````` +M``````"`MP%````!>-KMP3$!````PJ#U3VT,'Z````````````````````"` +MMP%````!>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%````! +M>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$! +M````PJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$!````PJ#U +M3VT,'Z````````````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`` +M``````````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````````` +M``````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````````````````` +M``"`MP%````!>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%` +M```!>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%````!>-KM +MP3$!````PJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$!```` +MPJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$!````PJ#U3VT, +M'Z````````````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````` +M``````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````````````` +M``````"`MP%````!>-KMP3$!````PJ#U3VT,'Z````````````````````"` +MMP%````!>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%````! +M>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$! +M````PJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$!````PJ#U +M3VT,'Z````````````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`` +M``````````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````````` +M``````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````````````````` +M``"`MP%````!>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%` +M```!>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%````!>-KM +MP3$!````PJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$!```` +MPJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$!````PJ#U3VT, +M'Z````````````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````` +M``````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````````````` +M``````"`MP%````!>-KMP3$!````PJ#U3VT,'Z````````````````````"` +MMP%````!>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%````! +M>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$! +M````PJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$!````PJ#U +M3VT,'Z````````````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`` +M``````````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````````` +M``````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````````````````` +M``"`MP%````!>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%` +M```!>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%````!>-KM +MP3$!````PJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$!```` +MPJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$!````PJ#U3VT, +M'Z````````````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````` +M``````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````````````` +M``````"`MP%````!>-KMP3$!````PJ#U3VT,'Z````````````````````"` +MMP%````!>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%````! +M>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$! +M````PJ#U3VT,'Z````````````````````"`MP%````!>-KMP3$!````PJ#U +M3VT,'Z````````````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`` +M``````````````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````````` +M``````````"`MP%````!>-KMP3$!````PJ#U3VT,'Z`````````````````` +M``"`MP%````!>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%` +M```!>-KMP3$!````PJ#U3VT,'Z````````````````````"`MP%````!>-KM +MP3$!````PJ#U3VT,'Z````````````````````"`MP%````!>-KMT#$!```, +M`B"C&]T*>_9!!!(```````````````````!X405W`]:``($````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +2```````````````````````` +` +end diff --git a/tests/sys/geom/class/uzip/1_test.sh b/tests/sys/geom/class/uzip/1_test.sh index 222b6c9afdec..c73f20e18764 100644 --- a/tests/sys/geom/class/uzip/1_test.sh +++ b/tests/sys/geom/class/uzip/1_test.sh @@ -4,9 +4,21 @@ testsdir=$(dirname $0) . $testsdir/conf.sh +# Check host endianness +ret=$(echo I | tr -d "[:space:]" | od -to2 | head -n1 | awk '{print $2}' | cut -c6) +if [ "$ret" = "1" ]; then + # Little endian + UUE=$testsdir/1_endian_little.img.uzip.uue +elif [ "$ret" = "0" ]; then + # Big endian + UUE=$testsdir/1_endian_big.img.uzip.uue +else + echo "Couldn't detect host endianness" + exit 2 +fi + echo "1..1" -UUE=$testsdir/1.img.uzip.uue uudecode $UUE us0=$(attach_md -f $(basename $UUE .uue)) || exit 1 sleep 1 diff --git a/tests/sys/geom/class/uzip/Makefile b/tests/sys/geom/class/uzip/Makefile index 89b643e07021..1f73edf61e32 100644 --- a/tests/sys/geom/class/uzip/Makefile +++ b/tests/sys/geom/class/uzip/Makefile @@ -8,7 +8,7 @@ PACKAGE= tests TESTSDIR= ${TESTSBASE}/sys/geom/class/${.CURDIR:T} -IMAGE= 1.img +IMAGE= 1_endian_little.img ZIMAGE= ${IMAGE}.uzip UZIMAGE= ${ZIMAGE}.uue @@ -25,7 +25,7 @@ ${UZIMAGE}: ${IMAGE} ${ZIMAGE} printf "FreeBSD$$\n#\n\n" >> ${.TARGET} uuencode ${ZIMAGE} ${ZIMAGE} >>${.TARGET} -${PACKAGE}FILES+= conf.sh \ +${PACKAGE}FILES+= conf.sh 1_endian_big.img.uzip.uue \ ${UZIMAGE} FILESGROUPS+= etalon diff --git a/tests/sys/geom/class/uzip/test-1.img.uzip.uue b/tests/sys/geom/class/uzip/test-1.img.uzip.uue deleted file mode 100644 index ca16f47c794e..000000000000 --- a/tests/sys/geom/class/uzip/test-1.img.uzip.uue +++ /dev/null @@ -1,110 +0,0 @@ -# -# $FreeBSD$ -# - -begin 755 test-1.img.uzip -M(R$O8FEN+W-H"B-6,BXP($9O&ET("0_"@```````$`````` -M0`````````*0`````````W<````````$F@````````AQ````````")@````` -M```(OP````````CF````````"0T````````)-`````````E;````````"8(` -M```````)J0````````G0````````"?<````````*'@````````I%```````` -M"FP````````*DP````````JZ````````"N$````````+"`````````LO```` -M````"U8````````+?0````````ND````````"\L````````+\@````````P9 -M````````#$`````````,9P````````R.````````#+4````````,W``````` -M``T#````````#2H````````-40````````UX````````#9\````````-Q@`` -M``````WM````````#A0````````..P````````YB````````#HD````````. -ML`````````[7````````#OX````````/)0````````],````````#W,````` -M```/F@````````_!````````#^@````````0#P```````!`V````````$%T` -M```````0A````````!"K````````$-(````````0^0```````!$@```````` -M$4<````````1;@```````!&5````````$<%XVNW4/0K",!3`\1>M$`3!42<[ -M>@1!AX)X`^_@X`VZZ.[%''1V]0+>0(@O[0OMZF`5^?_@-6GS2=L\$0`````` -M````````\"_&&A.-7&-NSX)Z7)=KR41N?1$GUD'OO18#Z[>*EWL(\@QAI-6A -MU.WQHL/J<;ZUF-8++7JM>V?5N-YN<]I7>\@LTGCK%Z.P]CA'J;%(*;/SW_H;W97M*9*ZU>^8]YR7'QWX>"< -MUTV$F>7(?M,OY:9D.W6<"0```````````'3J!63?'NAXVNW9,4I#01#&\6^3 -M"*L@6&IE2@]@$=#B@7@#!6^@X`W2F-Z+6(BEM:6%UK9>P!L(ZTS>K"^"B"&8 -M6/Q_,&]W\W8W0\A.LU)KRV+;8FBQ%Y\5\_9\<*2!]-*7DF*"C;,U:S'OT!^O -MI>B]E$WK;JA][P];UJ[+ZEB_L:8W,T[1]>\[/[Z^G.8PB*CK8YY'$^]]C['% -MJ.Z5-!&P"H\YZREW__3A/\HM_FU=I4G>PDS@0```````````"6[K2W_GFOE_R&[;M[ -M=?W^CN_&XM;BSN+>XB))^Q9G%I.%,BU?1ROS0?MFN%A8EF:;+BI(]H"1M04NE -M2FW%BA-X,IX9MYYQ9'LZS=[V`1`OP0-PV$=`W+ARX@&X\`A(_.Q)2:A8@50J -M0??WD:9V//[Y:W]_GLETVE;KU>:WX5I366V*7W]\//;E#]^\/5PN'UQ39SY\ -MZY>UYECHK_ZE_HNY[F79N2'];Y^OA+)<;S[_--?_[HK^^]?47W^)_HNY_CNM -M/^L??MWH7I;=&UK_I?[]O]'OW;!^]XK^U?Q'-Z1/$`1!$`1!$`1!$`1!$`1! -M$`1!$,3MP?]=\!D>.V0%0;R2U_\;K?65WJ*^VL,/:TU];?SY/1P\&@;TE,M8.]B"O?8)F-/AJ/1 -MWM'3P_%G7S!V(&II8@.&\['+'0AP'"7 -M6]"5RPR&]AB[.Q(UGP<]X7$L3*TG9QTH9F!UV68X73CEM<4.N)!8.IR[[SM1 -M?S1.N)OD;;8\4!6?5C'V-DFS)IM791@J-54A=65AA,W"V#+$WF7L4XQ$\R!' -M?\^UF7(%MM8F\2O-L>^`'>@R`R>+1J+@Y85?4(JY\H;Y%#CH=MFQ!DR_$XEO -MCF>A\TE5N*H`AYNE\<.B5@*\SN6EER$>_<"S.&7K&ZLTE3:_/!=4?%@G+&39 -MJQJ3!6(FT-@44L4+5!GC3\#QTU1)/^^E3>(JE0G,51C+SR:N#.8T";+>SD*T -M&3LLO=.U;L.BUJ2R&8DOZF%"<]-BQ1,4%J4#6\K)F3!=-'ERUO8.*Y$Z+Y$( -M/D],F+IT%E?'$]\E1&9<5<4T]Q./,=9OD^!+SFVP`_]?N5`>7^="H?LM0?R76'O)\_]K6'^SM;%^I'5XVG\=C[=:&^Q(3+65 -M3IM9JW4'V[Y?V;BS5SHCA24S">)_QD!_\=.-@"!N)4LO\Z)^KQ_M&PG#*H/E5WGA]5[$=NDV0!"WB]\!34_J -M#GC:[<$Q`0```,*@]4]M#!^@````````````````````@+%$%=P/6@`"! -M```````````````````````````````````````````````````````````` -2```````````````````````` -` -end diff --git a/tests/sys/kern/kern_copyin.c b/tests/sys/kern/kern_copyin.c index 7eea95e8c782..a8cf0422eec5 100644 --- a/tests/sys/kern/kern_copyin.c +++ b/tests/sys/kern/kern_copyin.c @@ -60,7 +60,12 @@ ATF_TC_BODY(kern_copyin, tc) char template[] = "copyin.XXXXXX"; #ifdef __mips__ - /* MIPS has no shared page implemented yet. */ + /* + * MIPS has different VM layout: the UVA map on mips ends the + * highest mapped entry at the VM_MAXUSER_ADDRESS - PAGE_SIZE, + * while all other arches map either stack or shared page up + * to the VM_MAXUSER_ADDRESS. + */ atf_tc_skip("Platform is not supported."); #endif diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc index c2a361084932..b4b94952196d 100644 --- a/tools/build/mk/OptionalObsoleteFiles.inc +++ b/tools/build/mk/OptionalObsoleteFiles.inc @@ -676,6 +676,7 @@ OLD_FILES+=usr/libexec/bsdinstall/distextract OLD_FILES+=usr/libexec/bsdinstall/distfetch OLD_FILES+=usr/libexec/bsdinstall/docsinstall OLD_FILES+=usr/libexec/bsdinstall/entropy +OLD_FILES+=usr/libexec/bsdinstall/hardening OLD_FILES+=usr/libexec/bsdinstall/hostname OLD_FILES+=usr/libexec/bsdinstall/jail OLD_FILES+=usr/libexec/bsdinstall/keymap @@ -2193,6 +2194,39 @@ OLD_FILES+=usr/share/man/man3/gpio_pin_tristate.3.gz OLD_FILES+=usr/share/man/man8/gpioctl.8.gz .endif +.if ${MK_GNU_DIFF} == no +OLD_FILES+=usr/bin/diff +OLD_FILES+=usr/bin/diff3 +OLD_FILES+=usr/share/man/man1/diff.1.gz +OLD_FILES+=usr/share/man/man1/diff3.1.gz +OLD_FILES+=usr/share/man/man7/diff.7.gz +.endif + +.if ${MK_GNU_GREP} == no +OLD_FILES+=usr/bin/gnugrep +OLD_FILES+=usr/share/man/man1/gnugrep.1.gz +.if ${MK_BSD_GREP} == no +OLD_FILES+=usr/bin/bzgrep +OLD_FILES+=usr/bin/bzegrep +OLD_FILES+=usr/bin/bzfgrep +OLD_FILES+=usr/bin/egrep +OLD_FILES+=usr/bin/fgrep +OLD_FILES+=usr/bin/grep +OLD_FILES+=usr/bin/zegrep +OLD_FILES+=usr/bin/zfgrep +OLD_FILES+=usr/bin/zgrep +OLD_FILES+=usr/share/man/man1/bzegrep.1.gz +OLD_FILES+=usr/share/man/man1/bzfgrep.1.gz +OLD_FILES+=usr/share/man/man1/bzgrep.1.gz +OLD_FILES+=usr/share/man/man1/egrep.1.gz +OLD_FILES+=usr/share/man/man1/fgrep.1.gz +OLD_FILES+=usr/share/man/man1/grep.1.gz +OLD_FILES+=usr/share/man/man1/zegrep.1.gz +OLD_FILES+=usr/share/man/man1/zfgrep.1.gz +OLD_FILES+=usr/share/man/man1/zgrep.1.gz +.endif +.endif + # Also includes vgrind(1) .if ${MK_GROFF} == no OLD_FILES+=usr/bin/addftinfo @@ -8624,6 +8658,7 @@ OLD_FILES+=usr/share/man/man4/otus.4.gz OLD_FILES+=usr/share/man/man4/otusfw.4.gz OLD_FILES+=usr/share/man/man4/rsu.4.gz OLD_FILES+=usr/share/man/man4/rsufw.4.gz +OLD_FILES+=usr/share/man/man4/rtwn_usb.4.gz OLD_FILES+=usr/share/man/man4/u3g.4.gz OLD_FILES+=usr/share/man/man4/u3gstub.4.gz OLD_FILES+=usr/share/man/man4/uark.4.gz @@ -8665,8 +8700,6 @@ OLD_FILES+=usr/share/man/man4/ural.4.gz OLD_FILES+=usr/share/man/man4/urio.4.gz OLD_FILES+=usr/share/man/man4/urndis.4.gz OLD_FILES+=usr/share/man/man4/urtw.4.gz -OLD_FILES+=usr/share/man/man4/urtwn.4.gz -OLD_FILES+=usr/share/man/man4/urtwnfw.4.gz OLD_FILES+=usr/share/man/man4/usb.4.gz OLD_FILES+=usr/share/man/man4/usb_quirk.4.gz OLD_FILES+=usr/share/man/man4/usb_template.4.gz diff --git a/tools/build/options/WITHOUT_GNU_DIFF b/tools/build/options/WITHOUT_GNU_DIFF new file mode 100644 index 000000000000..de8667fe4d73 --- /dev/null +++ b/tools/build/options/WITHOUT_GNU_DIFF @@ -0,0 +1,5 @@ +.\" $FreeBSD$ +Set to not build GNU +.Xr diff 1 +and +.Xr diff3 1 . diff --git a/tools/build/options/WITHOUT_GNU_GREP b/tools/build/options/WITHOUT_GNU_GREP new file mode 100644 index 000000000000..1bb7d4a53eba --- /dev/null +++ b/tools/build/options/WITHOUT_GNU_GREP @@ -0,0 +1,3 @@ +.\" $FreeBSD$ +Set to not build GNU +.Xr grep 1 . diff --git a/tools/regression/bpf/bpf_filter/Makefile b/tools/regression/bpf/bpf_filter/Makefile index 79a2e0cb0a46..d0038f915239 100644 --- a/tools/regression/bpf/bpf_filter/Makefile +++ b/tools/regression/bpf/bpf_filter/Makefile @@ -20,9 +20,11 @@ TEST_CASES?= test0001 test0002 test0003 test0004 \ test0069 test0070 test0071 test0072 \ test0073 test0074 test0075 test0076 \ test0077 test0078 test0079 test0080 \ - test0081 test0082 test0083 test0084 + test0081 test0082 test0083 test0084 \ + test0085 test0086 test0087 test0088 \ + test0089 test0090 test0091 -SYSDIR?= ${.CURDIR}/../../../../sys +SYSDIR?= ${SRCTOP}/sys SRCS= ${.CURDIR}/bpf_test.c diff --git a/tools/regression/bpf/bpf_filter/bpf_test.c b/tools/regression/bpf/bpf_filter/bpf_test.c index 6bd67cfe4ca2..9ed4828ea3e2 100644 --- a/tools/regression/bpf/bpf_filter/bpf_test.c +++ b/tools/regression/bpf/bpf_filter/bpf_test.c @@ -105,8 +105,8 @@ static const u_short bpf_code_map[] = { 0x1013, /* 0x60-0x6f: 1100100000001000 */ 0x1010, /* 0x70-0x7f: 0000100000001000 */ 0x0093, /* 0x80-0x8f: 1100100100000000 */ - 0x0000, /* 0x90-0x9f: 0000000000000000 */ - 0x0000, /* 0xa0-0xaf: 0000000000000000 */ + 0x1010, /* 0x90-0x9f: 0000100000001000 */ + 0x1010, /* 0xa0-0xaf: 0000100000001000 */ 0x0002, /* 0xb0-0xbf: 0100000000000000 */ 0x0000, /* 0xc0-0xcf: 0000000000000000 */ 0x0000, /* 0xd0-0xdf: 0000000000000000 */ @@ -176,7 +176,8 @@ bpf_validate(const struct bpf_insn *f, int len) /* * Check for constant division by 0. */ - if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0) + if ((p->code == (BPF_ALU|BPF_DIV|BPF_K) || + p->code == (BPF_ALU|BPF_MOD|BPF_K)) && p->k == 0) return (0); } return (BPF_CLASS(f[len - 1].code) == BPF_RET); diff --git a/tools/regression/bpf/bpf_filter/tests/test0001.h b/tools/regression/bpf/bpf_filter/tests/test0001.h index 76cf71dfa50a..5640f9a1cb22 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0001.h +++ b/tools/regression/bpf/bpf_filter/tests/test0001.h @@ -5,27 +5,27 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(0x55, 0), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 1; +static int invalid = 1; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = SIGABRT; +static int expect_signal = SIGABRT; diff --git a/tools/regression/bpf/bpf_filter/tests/test0002.h b/tools/regression/bpf/bpf_filter/tests/test0002.h index ef92c3170660..15935505d849 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0002.h +++ b/tools/regression/bpf/bpf_filter/tests/test0002.h @@ -5,26 +5,26 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_RET+BPF_K, 0xdeadc0de), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0003.h b/tools/regression/bpf/bpf_filter/tests/test0003.h index 7a547ef763a6..9ab083a48623 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0003.h +++ b/tools/regression/bpf/bpf_filter/tests/test0003.h @@ -5,27 +5,27 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0004.h b/tools/regression/bpf/bpf_filter/tests/test0004.h index ecb4bc216145..7eb42a125ca3 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0004.h +++ b/tools/regression/bpf/bpf_filter/tests/test0004.h @@ -5,27 +5,27 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 1), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0x23456789; +static u_int expect = 0x23456789; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0005.h b/tools/regression/bpf/bpf_filter/tests/test0005.h index 6830add85434..4dae935d1357 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0005.h +++ b/tools/regression/bpf/bpf_filter/tests/test0005.h @@ -5,27 +5,27 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 1), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0x2345; +static u_int expect = 0x2345; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0006.h b/tools/regression/bpf/bpf_filter/tests/test0006.h index f36ec3fa6720..2c7485db6ad7 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0006.h +++ b/tools/regression/bpf/bpf_filter/tests/test0006.h @@ -5,27 +5,27 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 1), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0x23; +static u_int expect = 0x23; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0007.h b/tools/regression/bpf/bpf_filter/tests/test0007.h index 69757223a2b7..026c6f7d9725 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0007.h +++ b/tools/regression/bpf/bpf_filter/tests/test0007.h @@ -5,27 +5,27 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_W+BPF_LEN, 0), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = 0xdeadc0de; +static u_int wirelen = 0xdeadc0de; /* Packet length passed on buffer */ -u_int buflen = 0xdeadc0de; +static u_int buflen = 0xdeadc0de; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0008.h b/tools/regression/bpf/bpf_filter/tests/test0008.h index 93462c76ce12..80e1eb0f812b 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0008.h +++ b/tools/regression/bpf/bpf_filter/tests/test0008.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LDX+BPF_W+BPF_LEN, 0), BPF_STMT(BPF_MISC+BPF_TXA, 0), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = 0xdeadc0de; +static u_int wirelen = 0xdeadc0de; /* Packet length passed on buffer */ -u_int buflen = 0xdeadc0de; +static u_int buflen = 0xdeadc0de; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0009.h b/tools/regression/bpf/bpf_filter/tests/test0009.h index 644e58b8149c..7053450c4893 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0009.h +++ b/tools/regression/bpf/bpf_filter/tests/test0009.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_W+BPF_IND, 1), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0x456789ab; +static u_int expect = 0x456789ab; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0010.h b/tools/regression/bpf/bpf_filter/tests/test0010.h index ce8488e2c806..8377804d4abb 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0010.h +++ b/tools/regression/bpf/bpf_filter/tests/test0010.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_H+BPF_IND, 1), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0x4567; +static u_int expect = 0x4567; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0011.h b/tools/regression/bpf/bpf_filter/tests/test0011.h index c3a94f3c2306..057c224eaec4 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0011.h +++ b/tools/regression/bpf/bpf_filter/tests/test0011.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_B+BPF_IND, 1), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0x45; +static u_int expect = 0x45; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0012.h b/tools/regression/bpf/bpf_filter/tests/test0012.h index 03cd1e9c7988..b1ef2b73da7d 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0012.h +++ b/tools/regression/bpf/bpf_filter/tests/test0012.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LDX+BPF_MSH+BPF_B, 1), BPF_STMT(BPF_MISC+BPF_TXA, 0), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = (0x23 & 0xf) << 2; +static u_int expect = (0x23 & 0xf) << 2; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0013.h b/tools/regression/bpf/bpf_filter/tests/test0013.h index 78313f6c3ed4..004e517b3296 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0013.h +++ b/tools/regression/bpf/bpf_filter/tests/test0013.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_ST, 7), BPF_STMT(BPF_LDX+BPF_MEM, 7), @@ -14,21 +14,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0014.h b/tools/regression/bpf/bpf_filter/tests/test0014.h index bea2b4c9e342..ff1799f29eb1 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0014.h +++ b/tools/regression/bpf/bpf_filter/tests/test0014.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LDX+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_STX, 7), BPF_STMT(BPF_LD+BPF_MEM, 7), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0015.h b/tools/regression/bpf/bpf_filter/tests/test0015.h index 78187027929d..903f7325d772 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0015.h +++ b/tools/regression/bpf/bpf_filter/tests/test0015.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xc0decafe), BPF_STMT(BPF_JMP+BPF_JA, 1), BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xc0decafe; +static u_int expect = 0xc0decafe; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0016.h b/tools/regression/bpf/bpf_filter/tests/test0016.h index b5b0bdd1e3e3..eeb26fa7b33c 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0016.h +++ b/tools/regression/bpf/bpf_filter/tests/test0016.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0x01234567), BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, 0x01234568, 2, 0), BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, 0x01234566, 2, 1), @@ -17,21 +17,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xc0decafe; +static u_int expect = 0xc0decafe; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0017.h b/tools/regression/bpf/bpf_filter/tests/test0017.h index 24f412fc3026..7a38d06940f2 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0017.h +++ b/tools/regression/bpf/bpf_filter/tests/test0017.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0x01234567), BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0x01234568, 2, 0), BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0x01234567, 2, 1), @@ -17,21 +17,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xc0decafe; +static u_int expect = 0xc0decafe; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0018.h b/tools/regression/bpf/bpf_filter/tests/test0018.h index ad80b47e5b60..11f3927c4e72 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0018.h +++ b/tools/regression/bpf/bpf_filter/tests/test0018.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0x01234567), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x01234568, 2, 0), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0x01234567, 2, 1), @@ -17,21 +17,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xc0decafe; +static u_int expect = 0xc0decafe; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0019.h b/tools/regression/bpf/bpf_filter/tests/test0019.h index e7977b11e371..a2c27c08403c 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0019.h +++ b/tools/regression/bpf/bpf_filter/tests/test0019.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0x01234567), BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x80000000, 5, 0), BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x40000000, 4, 0), @@ -22,21 +22,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xc0decafe; +static u_int expect = 0xc0decafe; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0020.h b/tools/regression/bpf/bpf_filter/tests/test0020.h index 662d60b634ce..58384c66a875 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0020.h +++ b/tools/regression/bpf/bpf_filter/tests/test0020.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0x01234567), BPF_STMT(BPF_LDX+BPF_IMM, 0x01234568), BPF_JUMP(BPF_JMP+BPF_JGT+BPF_X, 0, 3, 0), @@ -20,21 +20,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xc0decafe; +static u_int expect = 0xc0decafe; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0021.h b/tools/regression/bpf/bpf_filter/tests/test0021.h index cbc93e5c9d7b..da092b8abb78 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0021.h +++ b/tools/regression/bpf/bpf_filter/tests/test0021.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0x01234567), BPF_STMT(BPF_LDX+BPF_IMM, 0x01234568), BPF_JUMP(BPF_JMP+BPF_JGE+BPF_X, 0, 3, 0), @@ -20,21 +20,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xc0decafe; +static u_int expect = 0xc0decafe; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0022.h b/tools/regression/bpf/bpf_filter/tests/test0022.h index 5a9fcc08aac6..9fa0d94b32d1 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0022.h +++ b/tools/regression/bpf/bpf_filter/tests/test0022.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0x01234567), BPF_STMT(BPF_LDX+BPF_IMM, 0x01234568), BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_X, 0, 3, 0), @@ -20,21 +20,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xc0decafe; +static u_int expect = 0xc0decafe; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0023.h b/tools/regression/bpf/bpf_filter/tests/test0023.h index 24f5c69f091e..ac9bf25e6c85 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0023.h +++ b/tools/regression/bpf/bpf_filter/tests/test0023.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0x01234567), BPF_STMT(BPF_LDX+BPF_IMM, 0x80000000), BPF_JUMP(BPF_JMP+BPF_JSET+BPF_X, 0, 9, 0), @@ -30,21 +30,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xc0decafe; +static u_int expect = 0xc0decafe; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0024.h b/tools/regression/bpf/bpf_filter/tests/test0024.h index d4f80ba811da..511378e7a781 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0024.h +++ b/tools/regression/bpf/bpf_filter/tests/test0024.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xbeadb8dd), BPF_STMT(BPF_LDX+BPF_IMM, 0x20000801), BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0025.h b/tools/regression/bpf/bpf_filter/tests/test0025.h index 2d5f2b4e433d..91acfe47536a 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0025.h +++ b/tools/regression/bpf/bpf_filter/tests/test0025.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 0x20000801), BPF_STMT(BPF_ALU+BPF_SUB+BPF_X, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xbeadb8dd; +static u_int expect = 0xbeadb8dd; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0026.h b/tools/regression/bpf/bpf_filter/tests/test0026.h index 49c9133b818c..f881c0f8eb46 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0026.h +++ b/tools/regression/bpf/bpf_filter/tests/test0026.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdead), BPF_STMT(BPF_LDX+BPF_IMM, 0xc0de), BPF_STMT(BPF_ALU+BPF_MUL+BPF_X, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xa7c2da06; +static u_int expect = 0xa7c2da06; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0027.h b/tools/regression/bpf/bpf_filter/tests/test0027.h index c26248de6a4c..bf41904368eb 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0027.h +++ b/tools/regression/bpf/bpf_filter/tests/test0027.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xa7c2da06), BPF_STMT(BPF_LDX+BPF_IMM, 0xdead), BPF_STMT(BPF_ALU+BPF_DIV+BPF_X, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xc0de; +static u_int expect = 0xc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0028.h b/tools/regression/bpf/bpf_filter/tests/test0028.h index 7a346456e886..f205e143ca13 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0028.h +++ b/tools/regression/bpf/bpf_filter/tests/test0028.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 0xc0decafe), BPF_STMT(BPF_ALU+BPF_AND+BPF_X, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xc08cc0de; +static u_int expect = 0xc08cc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0029.h b/tools/regression/bpf/bpf_filter/tests/test0029.h index 65d842a7b970..f9a26a9d86f8 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0029.h +++ b/tools/regression/bpf/bpf_filter/tests/test0029.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 0xc0decafe), BPF_STMT(BPF_ALU+BPF_OR+BPF_X, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xdeffcafe; +static u_int expect = 0xdeffcafe; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0030.h b/tools/regression/bpf/bpf_filter/tests/test0030.h index f2197ff59a97..5574264d3eee 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0030.h +++ b/tools/regression/bpf/bpf_filter/tests/test0030.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdefc0), BPF_STMT(BPF_LDX+BPF_IMM, 9), BPF_STMT(BPF_ALU+BPF_LSH+BPF_X, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0x1bdf8000; +static u_int expect = 0x1bdf8000; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0031.h b/tools/regression/bpf/bpf_filter/tests/test0031.h index 7f868b053aa5..ff5fc1950a28 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0031.h +++ b/tools/regression/bpf/bpf_filter/tests/test0031.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 13), BPF_STMT(BPF_ALU+BPF_RSH+BPF_X, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0x6f56e; +static u_int expect = 0x6f56e; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0032.h b/tools/regression/bpf/bpf_filter/tests/test0032.h index 779c48b17d29..7bde40237394 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0032.h +++ b/tools/regression/bpf/bpf_filter/tests/test0032.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xbeadb8dd), BPF_STMT(BPF_ALU+BPF_ADD+BPF_K, 0x20000801), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0033.h b/tools/regression/bpf/bpf_filter/tests/test0033.h index 54de1b763183..615021839522 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0033.h +++ b/tools/regression/bpf/bpf_filter/tests/test0033.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_ALU+BPF_SUB+BPF_K, 0x20000801), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xbeadb8dd; +static u_int expect = 0xbeadb8dd; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0034.h b/tools/regression/bpf/bpf_filter/tests/test0034.h index 6bb8b6fbf818..0219eb025478 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0034.h +++ b/tools/regression/bpf/bpf_filter/tests/test0034.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdead), BPF_STMT(BPF_ALU+BPF_MUL+BPF_K, 0xc0de), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xa7c2da06; +static u_int expect = 0xa7c2da06; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0035.h b/tools/regression/bpf/bpf_filter/tests/test0035.h index d7f157fffdcb..0c6b69e3eaeb 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0035.h +++ b/tools/regression/bpf/bpf_filter/tests/test0035.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xa7c2da06), BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 0xdead), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xc0de; +static u_int expect = 0xc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0036.h b/tools/regression/bpf/bpf_filter/tests/test0036.h index 0eddb61fb127..8bee25b78a74 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0036.h +++ b/tools/regression/bpf/bpf_filter/tests/test0036.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_ALU+BPF_AND+BPF_K, 0xc0decafe), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xc08cc0de; +static u_int expect = 0xc08cc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0037.h b/tools/regression/bpf/bpf_filter/tests/test0037.h index dc4c411317d4..66682c4ff8bf 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0037.h +++ b/tools/regression/bpf/bpf_filter/tests/test0037.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_ALU+BPF_OR+BPF_K, 0xc0decafe), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xdeffcafe; +static u_int expect = 0xdeffcafe; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0038.h b/tools/regression/bpf/bpf_filter/tests/test0038.h index a27948cde99d..b9307bb73966 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0038.h +++ b/tools/regression/bpf/bpf_filter/tests/test0038.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdefc0), BPF_STMT(BPF_ALU+BPF_LSH+BPF_K, 9), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0x1bdf8000; +static u_int expect = 0x1bdf8000; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0039.h b/tools/regression/bpf/bpf_filter/tests/test0039.h index 4e7cf7200ad3..51cfed53711c 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0039.h +++ b/tools/regression/bpf/bpf_filter/tests/test0039.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_ALU+BPF_RSH+BPF_K, 13), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0x6f56e; +static u_int expect = 0x6f56e; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0040.h b/tools/regression/bpf/bpf_filter/tests/test0040.h index 9f4e47927a87..11b71cd1c369 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0040.h +++ b/tools/regression/bpf/bpf_filter/tests/test0040.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0x21523f22), BPF_STMT(BPF_ALU+BPF_NEG, 0), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0041.h b/tools/regression/bpf/bpf_filter/tests/test0041.h index 235ad9fc3c1a..28008de347d9 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0041.h +++ b/tools/regression/bpf/bpf_filter/tests/test0041.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_MISC+BPF_TAX, 0), BPF_STMT(BPF_STX, 0), @@ -14,21 +14,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0042.h b/tools/regression/bpf/bpf_filter/tests/test0042.h index a645cb697b29..c5b5928db85a 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0042.h +++ b/tools/regression/bpf/bpf_filter/tests/test0042.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 2), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0043.h b/tools/regression/bpf/bpf_filter/tests/test0043.h index 6971fe09d5e7..be1855d3d892 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0043.h +++ b/tools/regression/bpf/bpf_filter/tests/test0043.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 2), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0044.h b/tools/regression/bpf/bpf_filter/tests/test0044.h index b6ae8e62bfb8..b46632ad802b 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0044.h +++ b/tools/regression/bpf/bpf_filter/tests/test0044.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 2), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0045.h b/tools/regression/bpf/bpf_filter/tests/test0045.h index 5b420e86f973..97ae975ba37d 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0045.h +++ b/tools/regression/bpf/bpf_filter/tests/test0045.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_W+BPF_IND, 2), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0046.h b/tools/regression/bpf/bpf_filter/tests/test0046.h index b31b351682d3..a45204d06b9e 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0046.h +++ b/tools/regression/bpf/bpf_filter/tests/test0046.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_H+BPF_IND, 2), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0047.h b/tools/regression/bpf/bpf_filter/tests/test0047.h index 4ce86dad8780..f0d39d86dac2 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0047.h +++ b/tools/regression/bpf/bpf_filter/tests/test0047.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_B+BPF_IND, 2), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0048.h b/tools/regression/bpf/bpf_filter/tests/test0048.h index 04eea4f5bfb9..6736d5a9fc29 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0048.h +++ b/tools/regression/bpf/bpf_filter/tests/test0048.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_MSH+BPF_B, 2), BPF_STMT(BPF_MISC+BPF_TXA, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0049.h b/tools/regression/bpf/bpf_filter/tests/test0049.h index caa65006b091..d4091998ad84 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0049.h +++ b/tools/regression/bpf/bpf_filter/tests/test0049.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 6), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0050.h b/tools/regression/bpf/bpf_filter/tests/test0050.h index f3c0c727829e..9a5dff68eea6 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0050.h +++ b/tools/regression/bpf/bpf_filter/tests/test0050.h @@ -5,28 +5,28 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 4), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0051.h b/tools/regression/bpf/bpf_filter/tests/test0051.h index b81f30c0ce41..ab48c339e6d1 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0051.h +++ b/tools/regression/bpf/bpf_filter/tests/test0051.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_W+BPF_IND, 6), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0052.h b/tools/regression/bpf/bpf_filter/tests/test0052.h index dc80e9f5c75d..ec7016f67560 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0052.h +++ b/tools/regression/bpf/bpf_filter/tests/test0052.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_H+BPF_IND, 4), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0053.h b/tools/regression/bpf/bpf_filter/tests/test0053.h index d841a14c926c..df81ce0e9209 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0053.h +++ b/tools/regression/bpf/bpf_filter/tests/test0053.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_B+BPF_IND, 3), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0054.h b/tools/regression/bpf/bpf_filter/tests/test0054.h index 9b108aa5f153..45dd64ff36b5 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0054.h +++ b/tools/regression/bpf/bpf_filter/tests/test0054.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 6), BPF_STMT(BPF_LD+BPF_W+BPF_IND, 1), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0055.h b/tools/regression/bpf/bpf_filter/tests/test0055.h index 1951beee2d28..4312102028db 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0055.h +++ b/tools/regression/bpf/bpf_filter/tests/test0055.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 4), BPF_STMT(BPF_LD+BPF_H+BPF_IND, 1), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0056.h b/tools/regression/bpf/bpf_filter/tests/test0056.h index c812933c6dcf..cc3103db2fd4 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0056.h +++ b/tools/regression/bpf/bpf_filter/tests/test0056.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_W+BPF_IND, 0xffffffff), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0057.h b/tools/regression/bpf/bpf_filter/tests/test0057.h index 6c50a6570a25..ba355a3749eb 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0057.h +++ b/tools/regression/bpf/bpf_filter/tests/test0057.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_H+BPF_IND, 0xffffffff), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0058.h b/tools/regression/bpf/bpf_filter/tests/test0058.h index e4e5f06073d3..9ea693ea8f03 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0058.h +++ b/tools/regression/bpf/bpf_filter/tests/test0058.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_B+BPF_IND, 0xffffffff), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0059.h b/tools/regression/bpf/bpf_filter/tests/test0059.h index 4af6adca794e..0292787f6ee5 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0059.h +++ b/tools/regression/bpf/bpf_filter/tests/test0059.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 0xffffffff), BPF_STMT(BPF_LD+BPF_W+BPF_IND, 1), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0060.h b/tools/regression/bpf/bpf_filter/tests/test0060.h index 8afdeb401090..6792fcf9c296 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0060.h +++ b/tools/regression/bpf/bpf_filter/tests/test0060.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 0xffffffff), BPF_STMT(BPF_LD+BPF_H+BPF_IND, 1), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0061.h b/tools/regression/bpf/bpf_filter/tests/test0061.h index 256e6d6f23b7..f1557a16676d 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0061.h +++ b/tools/regression/bpf/bpf_filter/tests/test0061.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 0xffffffff), BPF_STMT(BPF_LD+BPF_B+BPF_IND, 1), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0062.h b/tools/regression/bpf/bpf_filter/tests/test0062.h index 39cd978cc9bd..5689b9c4a19e 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0062.h +++ b/tools/regression/bpf/bpf_filter/tests/test0062.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_W+BPF_IND, 1), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = 0; +static u_int buflen = 0; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0063.h b/tools/regression/bpf/bpf_filter/tests/test0063.h index 886a206f63f4..b9d666130532 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0063.h +++ b/tools/regression/bpf/bpf_filter/tests/test0063.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_H+BPF_IND, 1), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = 0; +static u_int buflen = 0; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0064.h b/tools/regression/bpf/bpf_filter/tests/test0064.h index 3aa7183d1197..0f43c3690fe9 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0064.h +++ b/tools/regression/bpf/bpf_filter/tests/test0064.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_B+BPF_IND, 1), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = 0; +static u_int buflen = 0; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0065.h b/tools/regression/bpf/bpf_filter/tests/test0065.h index f5c9b09124cd..b782a8ef4c49 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0065.h +++ b/tools/regression/bpf/bpf_filter/tests/test0065.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 0), BPF_STMT(BPF_LD+BPF_W+BPF_IND, 1), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = 0; +static u_int buflen = 0; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0066.h b/tools/regression/bpf/bpf_filter/tests/test0066.h index a2a83cbf60f7..1d828e150b07 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0066.h +++ b/tools/regression/bpf/bpf_filter/tests/test0066.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 0), BPF_STMT(BPF_LD+BPF_H+BPF_IND, 1), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = 0; +static u_int buflen = 0; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0067.h b/tools/regression/bpf/bpf_filter/tests/test0067.h index 5bd522c0d7c6..665ce0e21b60 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0067.h +++ b/tools/regression/bpf/bpf_filter/tests/test0067.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 0), BPF_STMT(BPF_LD+BPF_B+BPF_IND, 1), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = 0; +static u_int buflen = 0; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0068.h b/tools/regression/bpf/bpf_filter/tests/test0068.h index 6e8df64f6335..d2f811eda740 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0068.h +++ b/tools/regression/bpf/bpf_filter/tests/test0068.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_W+BPF_IND, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = 0; +static u_int buflen = 0; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0069.h b/tools/regression/bpf/bpf_filter/tests/test0069.h index e25336c56e8b..86fdcad4caa0 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0069.h +++ b/tools/regression/bpf/bpf_filter/tests/test0069.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_H+BPF_IND, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = 0; +static u_int buflen = 0; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0070.h b/tools/regression/bpf/bpf_filter/tests/test0070.h index aff1dbc24e67..3c279c4677d8 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0070.h +++ b/tools/regression/bpf/bpf_filter/tests/test0070.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 1), BPF_STMT(BPF_LD+BPF_B+BPF_IND, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = 0; +static u_int buflen = 0; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0071.h b/tools/regression/bpf/bpf_filter/tests/test0071.h index d476e90271e8..bca754934100 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0071.h +++ b/tools/regression/bpf/bpf_filter/tests/test0071.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 0), BPF_STMT(BPF_LD+BPF_W+BPF_IND, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = 0; +static u_int buflen = 0; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0072.h b/tools/regression/bpf/bpf_filter/tests/test0072.h index bb461fd07594..9bf97ea5158e 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0072.h +++ b/tools/regression/bpf/bpf_filter/tests/test0072.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 0), BPF_STMT(BPF_LD+BPF_H+BPF_IND, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = 0; +static u_int buflen = 0; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0073.h b/tools/regression/bpf/bpf_filter/tests/test0073.h index df8f309a369b..50b3f5693f1f 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0073.h +++ b/tools/regression/bpf/bpf_filter/tests/test0073.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_IMM, 0), BPF_STMT(BPF_LD+BPF_B+BPF_IND, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = 0; +static u_int buflen = 0; /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0074.h b/tools/regression/bpf/bpf_filter/tests/test0074.h index 1447839ce778..febd27525e98 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0074.h +++ b/tools/regression/bpf/bpf_filter/tests/test0074.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xa7c2da06), BPF_STMT(BPF_LDX+BPF_IMM, 0), BPF_STMT(BPF_ALU+BPF_DIV+BPF_X, 0), @@ -13,21 +13,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0075.h b/tools/regression/bpf/bpf_filter/tests/test0075.h index fa85dd0351a6..c20614b7fec9 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0075.h +++ b/tools/regression/bpf/bpf_filter/tests/test0075.h @@ -5,32 +5,32 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LD+BPF_MEM, 0x8fffffff), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 1; +static int invalid = 1; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ #ifdef __amd64__ -int expect_signal = SIGBUS; +static int expect_signal = SIGBUS; #else -int expect_signal = SIGSEGV; +static int expect_signal = SIGSEGV; #endif diff --git a/tools/regression/bpf/bpf_filter/tests/test0076.h b/tools/regression/bpf/bpf_filter/tests/test0076.h index 318cbea0cc15..d2b210e00cc2 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0076.h +++ b/tools/regression/bpf/bpf_filter/tests/test0076.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_LDX+BPF_MEM, 0x8fffffff), BPF_STMT(BPF_MISC+BPF_TXA, 0), @@ -13,25 +13,25 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 1; +static int invalid = 1; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ #ifdef __amd64__ -int expect_signal = SIGBUS; +static int expect_signal = SIGBUS; #else -int expect_signal = SIGSEGV; +static int expect_signal = SIGSEGV; #endif diff --git a/tools/regression/bpf/bpf_filter/tests/test0077.h b/tools/regression/bpf/bpf_filter/tests/test0077.h index 2af70cc9d4a5..5170c003eaaf 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0077.h +++ b/tools/regression/bpf/bpf_filter/tests/test0077.h @@ -5,32 +5,32 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_ST, 0x8fffffff), BPF_STMT(BPF_RET+BPF_A, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 1; +static int invalid = 1; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ #ifdef __amd64__ -int expect_signal = SIGBUS; +static int expect_signal = SIGBUS; #else -int expect_signal = SIGSEGV; +static int expect_signal = SIGSEGV; #endif diff --git a/tools/regression/bpf/bpf_filter/tests/test0078.h b/tools/regression/bpf/bpf_filter/tests/test0078.h index 3146de20acc3..ba830359be49 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0078.h +++ b/tools/regression/bpf/bpf_filter/tests/test0078.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), BPF_STMT(BPF_STX, 0x8fffffff), BPF_STMT(BPF_MISC+BPF_TXA, 0), @@ -13,25 +13,25 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 1; +static int invalid = 1; /* Expected return value */ -u_int expect = 0xdeadc0de; +static u_int expect = 0xdeadc0de; /* Expected signal */ #ifdef __amd64__ -int expect_signal = SIGBUS; +static int expect_signal = SIGBUS; #else -int expect_signal = SIGSEGV; +static int expect_signal = SIGSEGV; #endif diff --git a/tools/regression/bpf/bpf_filter/tests/test0079.h b/tools/regression/bpf/bpf_filter/tests/test0079.h index 753661a34a88..7c65fbe42cc4 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0079.h +++ b/tools/regression/bpf/bpf_filter/tests/test0079.h @@ -5,25 +5,25 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = (u_int)-1; +static u_int expect = (u_int)-1; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0080.h b/tools/regression/bpf/bpf_filter/tests/test0080.h index 65ae6c52dfe7..a4829085d20d 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0080.h +++ b/tools/regression/bpf/bpf_filter/tests/test0080.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { #ifdef BPF_JIT_COMPILER_OBSOLETE BPF_STMT(BPF_LDX+BPF_IMM, 0xffffffff), BPF_STMT(BPF_LD+BPF_MEM, 0), @@ -46,21 +46,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0081.h b/tools/regression/bpf/bpf_filter/tests/test0081.h index 85d1a31cf516..d6ce04ff83be 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0081.h +++ b/tools/regression/bpf/bpf_filter/tests/test0081.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0), BPF_JUMP(BPF_JMP+BPF_JA, 2, 0, 0), BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), @@ -13,25 +13,25 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 1; +static int invalid = 1; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ #ifdef BPF_JIT_COMPILER -int expect_signal = SIGSEGV; +static int expect_signal = SIGSEGV; #else -int expect_signal = SIGABRT; +static int expect_signal = SIGABRT; #endif diff --git a/tools/regression/bpf/bpf_filter/tests/test0082.h b/tools/regression/bpf/bpf_filter/tests/test0082.h index be7d63d5f572..e74171e1f0f2 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0082.h +++ b/tools/regression/bpf/bpf_filter/tests/test0082.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_IMM, 0), BPF_JUMP(BPF_JMP+BPF_JGT+BPF_K, 0, 1, 2), BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), @@ -13,25 +13,25 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 1; +static int invalid = 1; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ #ifdef BPF_JIT_COMPILER -int expect_signal = SIGSEGV; +static int expect_signal = SIGSEGV; #else -int expect_signal = SIGABRT; +static int expect_signal = SIGABRT; #endif diff --git a/tools/regression/bpf/bpf_filter/tests/test0083.h b/tools/regression/bpf/bpf_filter/tests/test0083.h index a55780f9c5e6..3ebf1cc6d39c 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0083.h +++ b/tools/regression/bpf/bpf_filter/tests/test0083.h @@ -5,30 +5,30 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD|BPF_IMM, 0), }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x00, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 1; +static int invalid = 1; /* Expected return value */ -u_int expect = 0; +static u_int expect = 0; /* Expected signal */ #ifdef BPF_JIT_COMPILER -int expect_signal = SIGSEGV; +static int expect_signal = SIGSEGV; #else -int expect_signal = SIGABRT; +static int expect_signal = SIGABRT; #endif diff --git a/tools/regression/bpf/bpf_filter/tests/test0084.h b/tools/regression/bpf/bpf_filter/tests/test0084.h index 043a68e47b0e..f6a777712099 100644 --- a/tools/regression/bpf/bpf_filter/tests/test0084.h +++ b/tools/regression/bpf/bpf_filter/tests/test0084.h @@ -5,7 +5,7 @@ */ /* BPF program */ -struct bpf_insn pc[] = { +static struct bpf_insn pc[] = { BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 1), BPF_STMT(BPF_LD+BPF_W+BPF_ABS, 0), @@ -1010,21 +1010,21 @@ struct bpf_insn pc[] = { }; /* Packet */ -u_char pkt[] = { +static u_char pkt[] = { 0x01, 0x23, 0x45, 0x67, 0x89, }; /* Packet length seen on wire */ -u_int wirelen = sizeof(pkt); +static u_int wirelen = sizeof(pkt); /* Packet length passed on buffer */ -u_int buflen = sizeof(pkt); +static u_int buflen = sizeof(pkt); /* Invalid instruction */ -int invalid = 0; +static int invalid = 0; /* Expected return value */ -u_int expect = 0x23456789; +static u_int expect = 0x23456789; /* Expected signal */ -int expect_signal = 0; +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0085.h b/tools/regression/bpf/bpf_filter/tests/test0085.h new file mode 100644 index 000000000000..3a9f77951d58 --- /dev/null +++ b/tools/regression/bpf/bpf_filter/tests/test0085.h @@ -0,0 +1,33 @@ +/*- + * Test 0085: BPF_ALU+BPF_MOD+BPF_X + * + * $FreeBSD$ + */ + +/* BPF program */ +static struct bpf_insn pc[] = { + BPF_STMT(BPF_LD+BPF_IMM, 0xdfe03de1), + BPF_STMT(BPF_LDX+BPF_IMM, 0xdead), + BPF_STMT(BPF_ALU+BPF_MOD+BPF_X, 0), + BPF_STMT(BPF_RET+BPF_A, 0), +}; + +/* Packet */ +static u_char pkt[] = { + 0x00, +}; + +/* Packet length seen on wire */ +static u_int wirelen = sizeof(pkt); + +/* Packet length passed on buffer */ +static u_int buflen = sizeof(pkt); + +/* Invalid instruction */ +static int invalid = 0; + +/* Expected return value */ +static u_int expect = 0x3154; + +/* Expected signal */ +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0086.h b/tools/regression/bpf/bpf_filter/tests/test0086.h new file mode 100644 index 000000000000..44311bcf2ae6 --- /dev/null +++ b/tools/regression/bpf/bpf_filter/tests/test0086.h @@ -0,0 +1,33 @@ +/*- + * Test 0086: BPF_ALU+BPF_XOR+BPF_X + * + * $FreeBSD$ + */ + +/* BPF program */ +static struct bpf_insn pc[] = { + BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), + BPF_STMT(BPF_LDX+BPF_IMM, 0xc0decafe), + BPF_STMT(BPF_ALU+BPF_XOR+BPF_X, 0), + BPF_STMT(BPF_RET+BPF_A, 0), +}; + +/* Packet */ +static u_char pkt[] = { + 0x00, +}; + +/* Packet length seen on wire */ +static u_int wirelen = sizeof(pkt); + +/* Packet length passed on buffer */ +static u_int buflen = sizeof(pkt); + +/* Invalid instruction */ +static int invalid = 0; + +/* Expected return value */ +static u_int expect = 0x1e730a20; + +/* Expected signal */ +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0087.h b/tools/regression/bpf/bpf_filter/tests/test0087.h new file mode 100644 index 000000000000..5b102278e8aa --- /dev/null +++ b/tools/regression/bpf/bpf_filter/tests/test0087.h @@ -0,0 +1,32 @@ +/*- + * Test 0087: BPF_ALU+BPF_MOD+BPF_K + * + * $FreeBSD$ + */ + +/* BPF program */ +static struct bpf_insn pc[] = { + BPF_STMT(BPF_LD+BPF_IMM, 0xdfe03de1), + BPF_STMT(BPF_ALU+BPF_MOD+BPF_K, 0xdead), + BPF_STMT(BPF_RET+BPF_A, 0), +}; + +/* Packet */ +static u_char pkt[] = { + 0x00, +}; + +/* Packet length seen on wire */ +static u_int wirelen = sizeof(pkt); + +/* Packet length passed on buffer */ +static u_int buflen = sizeof(pkt); + +/* Invalid instruction */ +static int invalid = 0; + +/* Expected return value */ +static u_int expect = 0x3154; + +/* Expected signal */ +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0088.h b/tools/regression/bpf/bpf_filter/tests/test0088.h new file mode 100644 index 000000000000..9126ac020b27 --- /dev/null +++ b/tools/regression/bpf/bpf_filter/tests/test0088.h @@ -0,0 +1,32 @@ +/*- + * Test 0088: BPF_ALU+BPF_XOR+BPF_K + * + * $FreeBSD$ + */ + +/* BPF program */ +static struct bpf_insn pc[] = { + BPF_STMT(BPF_LD+BPF_IMM, 0xdeadc0de), + BPF_STMT(BPF_ALU+BPF_XOR+BPF_K, 0xc0decafe), + BPF_STMT(BPF_RET+BPF_A, 0), +}; + +/* Packet */ +static u_char pkt[] = { + 0x00, +}; + +/* Packet length seen on wire */ +static u_int wirelen = sizeof(pkt); + +/* Packet length passed on buffer */ +static u_int buflen = sizeof(pkt); + +/* Invalid instruction */ +static int invalid = 0; + +/* Expected return value */ +static u_int expect = 0x1e730a20; + +/* Expected signal */ +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0089.h b/tools/regression/bpf/bpf_filter/tests/test0089.h new file mode 100644 index 000000000000..a7b1cfaf2103 --- /dev/null +++ b/tools/regression/bpf/bpf_filter/tests/test0089.h @@ -0,0 +1,33 @@ +/*- + * Test 0089: Divide by 0 (BPF_ALU+BPF_MOD+BPF_X) + * + * $FreeBSD$ + */ + +/* BPF program */ +static struct bpf_insn pc[] = { + BPF_STMT(BPF_LD+BPF_IMM, 0xa7c2da06), + BPF_STMT(BPF_LDX+BPF_IMM, 0), + BPF_STMT(BPF_ALU+BPF_MOD+BPF_X, 0), + BPF_STMT(BPF_RET+BPF_A, 0), +}; + +/* Packet */ +static u_char pkt[] = { + 0x00, +}; + +/* Packet length seen on wire */ +static u_int wirelen = sizeof(pkt); + +/* Packet length passed on buffer */ +static u_int buflen = sizeof(pkt); + +/* Invalid instruction */ +static int invalid = 0; + +/* Expected return value */ +static u_int expect = 0; + +/* Expected signal */ +static int expect_signal = 0; diff --git a/tools/regression/bpf/bpf_filter/tests/test0090.h b/tools/regression/bpf/bpf_filter/tests/test0090.h new file mode 100644 index 000000000000..70ccf1e2b0dc --- /dev/null +++ b/tools/regression/bpf/bpf_filter/tests/test0090.h @@ -0,0 +1,32 @@ +/*- + * Test 0090: Divide by 0 (BPF_ALU+BPF_DIV+BPF_K) + * + * $FreeBSD$ + */ + +/* BPF program */ +static struct bpf_insn pc[] = { + BPF_STMT(BPF_LD+BPF_IMM, 0xa7c2da06), + BPF_STMT(BPF_ALU+BPF_DIV+BPF_K, 0), + BPF_STMT(BPF_RET+BPF_A, 0), +}; + +/* Packet */ +static u_char pkt[] = { + 0x00, +}; + +/* Packet length seen on wire */ +static u_int wirelen = sizeof(pkt); + +/* Packet length passed on buffer */ +static u_int buflen = sizeof(pkt); + +/* Invalid instruction */ +static int invalid = 1; + +/* Expected return value */ +static u_int expect = 0; + +/* Expected signal */ +static int expect_signal = SIGFPE; diff --git a/tools/regression/bpf/bpf_filter/tests/test0091.h b/tools/regression/bpf/bpf_filter/tests/test0091.h new file mode 100644 index 000000000000..1e148e9d783c --- /dev/null +++ b/tools/regression/bpf/bpf_filter/tests/test0091.h @@ -0,0 +1,32 @@ +/*- + * Test 0091: Divide by 0 (BPF_ALU+BPF_MOD+BPF_K) + * + * $FreeBSD$ + */ + +/* BPF program */ +static struct bpf_insn pc[] = { + BPF_STMT(BPF_LD+BPF_IMM, 0xa7c2da06), + BPF_STMT(BPF_ALU+BPF_MOD+BPF_K, 0), + BPF_STMT(BPF_RET+BPF_A, 0), +}; + +/* Packet */ +static u_char pkt[] = { + 0x00, +}; + +/* Packet length seen on wire */ +static u_int wirelen = sizeof(pkt); + +/* Packet length passed on buffer */ +static u_int buflen = sizeof(pkt); + +/* Invalid instruction */ +static int invalid = 1; + +/* Expected return value */ +static u_int expect = 0; + +/* Expected signal */ +static int expect_signal = SIGFPE; diff --git a/tools/tools/README b/tools/tools/README index 307cf16156c7..531c5536fdca 100644 --- a/tools/tools/README +++ b/tools/tools/README @@ -29,6 +29,7 @@ gdb_regofs A simple tool that prints out a register offset table platforms only. genericize Turn a kernel config into something that can more easily be diffed against the appropriate GENERIC. +git Tools to simplify the use of git by committers. hcomp Compress header files by removing comments and whitespace. html-mv Rename HTML generated filenames to human readable filenames. ifinfo Uses the interface MIB to print out all the information diff --git a/tools/tools/git/HOWTO b/tools/tools/git/HOWTO new file mode 100644 index 000000000000..cee1d8cf08ed --- /dev/null +++ b/tools/tools/git/HOWTO @@ -0,0 +1,144 @@ +# $FreeBSD$ + +This directory contains tools intended to help committers use git when +interacting with standard FreeBSD project resources like Differential or svn. + +I. arcgit + +arcgit is a wrapper script around the arc command line tool that simplifies the +automatic creation of a series of Differential reviews from a series of git +commits. The intended workflow is: + +1. Create a series of commits in git. Each commit will be a separate review, so + try to make each commit as self-contained as possible. The series of commits + should demonstrate a logical progression towards your end goal. For example, + one commit might refactor existing code to expose a new API without changing + any current functionality. A subsequent commit could then introduce your new + code that uses the new API. + + It usually will not be helpful to present your code in the order in which it + was actually written and can actually be harmful. For example, if you + introduced a bug early in your development process that you fixed in a + subsequent commit, it is a waste of your reviewer's time to have them review + old code with known bugs. Instead, it would probably be best to squash the + bug fix into the commit that introduced it, so that the bug is never + presented to your reviewers in any review. + + The commit headline and commit message will be imported verbatim into + Differential, so try to give each commit a meaningful commit message that + gives your reviewers the necessary context to understand your change. + +2. Create your reviews bu running this command in your git repo: + $ arcgit -r C1~..C2 -R reviewer -T testplan + + C1 should be the first commit that you want reviewed, and C2 should be the + last commit that you want reviewed. You may add multiple reviewers by + specifying the -R option multiple times. You can CC (AKA subscribe) people + to a review with the -C option. Note that if you subscribe a mailing list + to a review, the mailing list will be emailed for every comment or change + made to each review. Please be judicious when subscibing mailing lists to + reviews. It may be better to instead send a single email to the appropriate + list announcing all of the reviews and giving a short summary of the change + as a whole, along with a link to the individual reviews. + +3. When you need to make a change and upload it to a review, use the following + process. First, check out the branch corresponding to the review (arcgit + automatically creates this branch for every review that it creates): + + $ git checkout review_D1234 + + Next, make your change and perform whatever testing is necessary. Commit it + to your repository with this command: + + $ git commit --fixup HEAD + + You can upload the change to the code review by running this command in your + repository while (ensure that you are still on the review_D1234 branch): + + $ arc diff --update D1234 review_D1234_base + + When you run arc, it will pull up your editor and give you a chance to + change the message that will be shown in Differential for this upload. It's + recommended that you change it from the default "fixup! ...." as that does + not give your reviewers an indication of what changes were made. It's not + recommended that you give the code review fixes meaningful commit messages + directly because we will be using git's autosquash feature in the next step, + which depends on the fixup! tag being present. + + Do not merge in other branches, or rebase your review branches at this point. + Any changes that are made will show up in your reviews, and that will create + extra noise that your reviewers will have to ignore. If a reviewer requests + a change that requires your commit to be based off of a later version of + head, I would suggest deferring the change from the review and creating a + new review with the change once you hit step 5. + +4. Once the reviews have been approved, you need to prepare your patch series + to be committed. This involves squashing the fixes made in code review + back into the original commit that they applied to. This gives you a clean + series of commits that are ready to be commited back to svn. + + First, merge each of your review branches back into your main development + branch. For example: + + $ git checkout myfeature_dev + $ for branch in review_D1234 review_D1235 review_D1236; do \ + git merge $branch || git mergetool -y || break; done + + Next, do an interactive rebase to squash your code review fixes back into the + main commit: + + $ git rebase -i -k review_D1234_base + + review_D1234 should be the name of the *first* review that was created for + you in step 2. For every commit, your editor will be pulled up and you will + be given one last chance to edit your commit message. Make sure that you fill + in the "Reviewed by:" tag indicating who accepted the review. This would + be a good point to add other tags like MFC after:, Sponsored by:, etc. + + The rebase will not introduce any actual changes to your code if done + properly. You can use this command to double-check that no changes were + inadvertently made here: + + $ git diff myfeature_dev@{1} + +5. Finally, you should get up to date with the latest changes from head: + + $ git pull --rebase origin master + + It is not recommended that you combine this step with the rebase done in the + previous step. The reason for this is that if you perform an interactive + rebase that changes the commit that you branch from, it becomes much more + difficult to use the reflog to confirm that the interactive rebase did not + introduce unwanted changes. + + At this point, you are ready to commit your changes to head. The importgit + script can be used to import your commits directly into git. + +II. importgit + +importgit is a script that can take a series of commits from git and commit them +to a svn repository. The script uses the git commit messages for the svn commit +message, which allows importgit to be fully automated. This does mean that once +you start importgit, it will start commit things to svn without giving any +further chance to sanity check what it's doing. + +importgit only supports importing commits that add or modify files. It does not +support importing commits that rename or delete files, to ensure that git's +rename detection heuristics do not introduce an error in the import process. +importgit also does not support importing merge commits. Only linear history +can be imported into svn. + +importgit must be run from a clean subversion checkout. You should ensure that +the working tree is up-to-date with "svn up" before running importgit. +importgit will run svn directly, so make sure that your ssh-agent is running +and has your ssh key loaded already. Run importgit as follows: + + $ importgit -r D1~..D2 -g /path/to/git/repo + +This will import every commit between D1 and D2, including both D1 and D2. The +invocation is very similar to the invocation given to arcgit but there is an +important point to note. When you rebased your commits as you followed steps 4 +and 5, the commit hashes of all of your commits changed, including C1 and C2. +You must go back and find the new commit hashes of your commits to pass to +importgit. Passing -r C1~..C2 would import your commits as they were *before* +your code review fixes were applied. diff --git a/tools/tools/git/arcgit b/tools/tools/git/arcgit new file mode 100755 index 000000000000..4b98042edd42 --- /dev/null +++ b/tools/tools/git/arcgit @@ -0,0 +1,214 @@ +#!/bin/sh +# +# Copyright (c) 2015 Ryan Stone. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +# +# $FreeBSD$ + +# This script is used to submit a series of git commits to Differential. Each +# commit is submitted as a separate review. For each review, this script will +# create a branch called review_DXXXX (e.g. review_D2185 for Differential +# revision D2185). When you need to make a change to a review, checkout the +# review_D2185 branch, commit your change with "git commit --fixup HEAD". To\ +# upload the change to Differential, use the command: +# $ arc diff --update D2185 review_D2185_base +# +# When your reviews are complete, merge all of the review_DXXXX branches +# together, and then do a git rebase -ik to meld the code review fixes into the +# commit that they fixed. Now you have a clean series of patches to commit to +# svn. + +usage() +{ + echo "Usage: arcgit <-c commit | -r commit1~..commit2> [-R reviewer] " >&2 + echo " [-C subscriber] [-T testplan] [-n]" >&2 +} + +error() +{ + echo "$@" >&2 + usage + rm -f $phab_before $phab_after $arc_msg + exit 1 +} + +create_review() +{ + local commit phab_id arc_dir + unset phab_before phab_after arc_msg + commit=$1 + + phab_before=`mktemp -t arcoutput` + phab_after=`mktemp -t arcoutput` + echo "Create review for '`git show $commit -s --oneline`'" + + if [ -n "$dry_run" ] + then + return + fi + + git checkout $commit > /dev/null || error "Could not checkout $commit" + + arc_dir="$(git rev-parse --show-toplevel)/.git/arc" + arc_msg="$arc_dir/create-message" + mkdir -p $arc_dir + git show -s --format='%B' HEAD > $arc_msg + echo >> $arc_msg + echo "Test Plan:" >> $arc_msg + cat $test_plan >> $arc_msg + echo >> $arc_msg + echo "Reviewers:" >> $arc_msg + echo "$reviewers" >> $arc_msg + echo >> $arc_msg + echo "Subscribers:" >> $arc_msg + echo "$cc_list" >> $arc_msg + echo >> $arc_msg + + arc list > $phab_before + yes | env EDITOR=true arc diff --create --allow-untracked HEAD~ + arc list > $phab_after + + headline="$(git show $commit -s --format=%s)" + phab_id=`comm -13 "$phab_before" "$phab_after" | fgrep "$headline" \ + | egrep -o 'D[0-9]+:' | tr -d ':'` + + if [ -z "$phab_id" ] + then + error "Could not get review ID" + fi + + git branch review_${phab_id}_base HEAD~ + + git checkout -b review_$phab_id + cat - < /dev/null 2> /dev/null +then + error "Install devel/git first" +fi + +if ! type arc > /dev/null 2> /dev/null +then + error "Install devel/arcanist first" +fi + +git update-index -q --refresh +if ! git diff-index --quiet --cached HEAD +then + error "index is unclean" +fi + +if ! git diff-files --quiet +then + error "Working directory is unclean" +fi + +if git ls-files --other --error-unmatch . > /dev/null 2> /dev/null +then + error "Working directory contains untracked files" +fi + +# We have to do a git checkout in order to run arc, so save the original branch +# so that we can check it out again once we're done. +if ! orig_branch=$(git symbolic-ref --short -q HEAD) +then + orig_branch=$(git show -s --pretty='%H' HEAD) +fi + +git log --format=%H $range | tail -r | while read -r commit +do + create_review $commit < /dev/null +done + +# Note that due to the use of the pipeline above, the body of the while loop +# above runs in a subshell. If it exits with an error, execution resumes +# here rather than exiting the script, so we have to cache the right exit code +# and return it when we're done cleaning up. +code=$? + +git checkout $orig_branch + +exit $code + diff --git a/tools/tools/git/importgit b/tools/tools/git/importgit new file mode 100755 index 000000000000..786930bc5248 --- /dev/null +++ b/tools/tools/git/importgit @@ -0,0 +1,182 @@ +#!/bin/sh +# +# Copyright (c) 2015 Ryan Stone. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +# +# $FreeBSD$ + +usage() +{ + echo "Usage: importgit <-c commit | -r c1..c2> -g /path/to/git/repo [-n]" >&2 +} + +error() +{ + local print_usage + + if [ "$1" = "-u" ] + then + shift + print_usage=1 + else + print_usage= + fi + + echo "$@" >&2 + if [ -n "$print_usage" ] + then + usage + fi + exit 1 +} + +unset git range commit dry_run + +while getopts ":c:g:nr:" o +do + case "$o" in + c) + range="${OPTARG}~..${OPTARG}" + ;; + g) + git_repo=$OPTARG + ;; + n) + dry_run=1 + ;; + r) + range=$OPTARG + ;; + *) + error -u "Unrecognized argument '-$OPTARG'" + esac +done + +shift $((OPTIND - 1)) +OPTIND=1 + +if [ -n "$1" ] +then + error -u "Unrecognized argument $1" +fi + +if [ -z "$range" ] +then + error -u "-c or -r argument is mandatory" +fi + +if ! echo "$range" | egrep -qs '^[^.]+\.\.[^.]*$' +then + error -u "$range is not a range of commits. Did you mean '-c $range'?" +fi + +if [ -z "$git_repo" ] +then + error -u "-g argument is mandatory" +fi + +git="$git_repo/.git" + +if [ ! -d "$git" ] +then + error "$git_repo does not seem to be a git repo" +fi + +if ! type git > /dev/null 2> /dev/null +then + error "Install devel/git first" +fi + +if ! type svn > /dev/null 2> /dev/null +then + error "Install devel/subversion first" +fi + +if [ -n "$(svn status)" ] +then + error "Working tree is not clean" +fi + +if ! svn --non-interactive ls > /dev/null +then + error "Could not communicate with svn server. Is your ssh key loaded?" +fi + +git --git-dir=$git log --format=%H $range | tail -r | while read -r commit +do + echo "Applying `git --git-dir=$git show -s --oneline $commit`" + + if [ -n "$(git --git-dir=$git show --diff-filter=CDRTUXB $commit)" ] + then + error "Commit performed unsupported change (e.g. delete/rename)" + fi + + if [ "$(git --git-dir=$git show -s --format=%P $commit | wc -w)" -ne 1 ] + then + error "Cannot import merge commits" + fi + + git --git-dir=$git diff --diff-filter=A --name-only \ + ${commit}~..$commit | while read -r newfile + do + if [ -f "$newfile" ] + then + error "New file $newfile already exists in tree" + fi + done + + # The previous while loop ran in a subshell, so we have to check if it + # exited with an error and bail out if so. + ret=$? + if [ "$ret" -ne 0 ] + then + exit $ret + fi + + if [ -n "$dry_run" ] + then + continue + fi + + git --git-dir=$git show $commit | patch -p 1 -s || \ + error "Failed to apply patch" + + git --git-dir=$git diff --diff-filter=A --name-only \ + ${commit}~..$commit | while read -r newfile + do + svn add --parents --depth=infinity $newfile || \ + error "Failed to add new file" + done + + # The previous while loop ran in a subshell, so we have to check if it + # exited with an error and bail out if so. + ret=$? + if [ "$ret" -ne 0 ] + then + exit $ret + fi + + git --git-dir=$git show -s --format='%B' $commit | svn commit -F - || \ + error "Failed to commit" +done + diff --git a/tools/tools/nanobsd/embedded/beaglebone.cfg b/tools/tools/nanobsd/embedded/beaglebone.cfg index 8defe5e0f363..c40d461d9b69 100644 --- a/tools/tools/nanobsd/embedded/beaglebone.cfg +++ b/tools/tools/nanobsd/embedded/beaglebone.cfg @@ -29,7 +29,7 @@ NANO_ARCH=armv6 NANO_KERNEL=BEAGLEBONE NANO_DRIVE=mmcsd0 -NANO_NAME=rpi2 +NANO_NAME=beaglebone NANO_BOOT_PKG=u-boot-beaglebone NANO_CPUTYPE=cortex-a8 diff --git a/tools/tools/nanobsd/embedded/common b/tools/tools/nanobsd/embedded/common index 4050ae579fef..41a52af7520b 100644 --- a/tools/tools/nanobsd/embedded/common +++ b/tools/tools/nanobsd/embedded/common @@ -201,12 +201,19 @@ create_diskimage_gpt ( ) ( create_diskimage_mbr ( ) ( + local fmt + + [ -z ${NANO_DISKIMAGE_FORMAT} ] || fmt=".${NANO_DISKIMAGE_FORMAT}" + pprint 2 "build diskimage ${NANO_NAME}" pprint 3 "log: ${NANO_LOG}/_.di" + pprint 3 "image in: ${NANO_DISKIMGDIR}/_.disk.image.${NANO_NAME}${fmt}" ( local extra i sz fmt fmtarg bootmbr bootbsd skiparg set -o xtrace + # Tell mtools not to be too picky + export MTOOLS_SKIP_CHECK=1 [ -z ${NANO_DISKIMAGE_FORMAT} ] || fmtarg="-f ${NANO_DISKIMAGE_FORMAT}" [ -z ${NANO_DISKIMAGE_FORMAT} ] || fmt=".${NANO_DISKIMAGE_FORMAT}" diff --git a/tools/tools/nanobsd/embedded/pandaboard.cfg b/tools/tools/nanobsd/embedded/pandaboard.cfg new file mode 100644 index 000000000000..b47551b229f8 --- /dev/null +++ b/tools/tools/nanobsd/embedded/pandaboard.cfg @@ -0,0 +1,36 @@ +# $FreeBSD$ + +#- +# Copyright (c) 2016 Warner Losh. All Rights Reserved. +# Copyright (c) 2010-2011 iXsystems, Inc., All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 iXsystems, Inc. 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. +# + +NANO_ARCH=armv6 +NANO_KERNEL=PANDABOARD +NANO_DRIVE=mmcsd0 +NANO_NAME=pandaboard +NANO_BOOT_PKG=u-boot-pandaboard +NANO_CPUTYPE=cortex-a9 + +. common # Pull in common definitions, keep last diff --git a/tools/tools/nanobsd/embedded/rpi3.cfg b/tools/tools/nanobsd/embedded/rpi3.cfg new file mode 100644 index 000000000000..1379aa2d651a --- /dev/null +++ b/tools/tools/nanobsd/embedded/rpi3.cfg @@ -0,0 +1,35 @@ +# $FreeBSD$ + +#- +# Copyright (c) 2015 Warner Losh. All Rights Reserved. +# Copyright (c) 2010-2011 iXsystems, Inc., All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 iXsystems, Inc. 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. +# + +NANO_ARCH=aarch64 +NANO_KERNEL=GENERIC-UP +NANO_DRIVE=mmcsd0 +NANO_NAME=rpi3 +NANO_BOOT_PKG=u-boot-rpi3 + +. common # Pull in common definitions, keep last diff --git a/tools/tools/netmap/Makefile b/tools/tools/netmap/Makefile index 7d7c44b1cce1..8daf59ff8ba8 100644 --- a/tools/tools/netmap/Makefile +++ b/tools/tools/netmap/Makefile @@ -3,11 +3,12 @@ # # For multiple programs using a single source file each, # we can just define 'progs' and create custom targets. -PROGS = pkt-gen bridge vale-ctl +PROGS = pkt-gen nmreplay bridge vale-ctl CLEANFILES = $(PROGS) *.o MAN= -CFLAGS += -Werror -Wall # -nostdinc -I/usr/include -I../../../sys +CFLAGS += -Werror -Wall +CFLAGS += -nostdinc -I ../../../sys -I/usr/include CFLAGS += -Wextra LDFLAGS += -lpthread @@ -16,6 +17,7 @@ CFLAGS += -DNO_PCAP .else LDFLAGS += -lpcap .endif +LDFLAGS += -lm # used by nmreplay .include .include @@ -28,5 +30,8 @@ pkt-gen: pkt-gen.o bridge: bridge.o $(CC) $(CFLAGS) -o bridge bridge.o +nmreplay: nmreplay.o + $(CC) $(CFLAGS) -o nmreplay nmreplay.o $(LDFLAGS) + vale-ctl: vale-ctl.o $(CC) $(CFLAGS) -o vale-ctl vale-ctl.o diff --git a/tools/tools/netmap/bridge.c b/tools/tools/netmap/bridge.c index 0895d4ede676..e99a507a829a 100644 --- a/tools/tools/netmap/bridge.c +++ b/tools/tools/netmap/bridge.c @@ -143,7 +143,7 @@ static void usage(void) { fprintf(stderr, - "usage: bridge [-v] [-i ifa] [-i ifb] [-b burst] [-w wait_time] [iface]\n"); + "usage: bridge [-v] [-i ifa] [-i ifb] [-b burst] [-w wait_time] [ifa [ifb [burst]]]\n"); exit(1); } @@ -201,12 +201,12 @@ main(int argc, char **argv) argc -= optind; argv += optind; + if (argc > 0) + ifa = argv[0]; if (argc > 1) - ifa = argv[1]; + ifb = argv[1]; if (argc > 2) - ifb = argv[2]; - if (argc > 3) - burst = atoi(argv[3]); + burst = atoi(argv[2]); if (!ifb) ifb = ifa; if (!ifa) { @@ -233,7 +233,7 @@ main(int argc, char **argv) D("cannot open %s", ifa); return (1); } - // XXX use a single mmap ? + /* try to reuse the mmap() of the first interface, if possible */ pb = nm_open(ifb, NULL, NM_OPEN_NO_MMAP, pa); if (pb == NULL) { D("cannot open %s", ifb); @@ -262,6 +262,23 @@ main(int argc, char **argv) pollfd[0].revents = pollfd[1].revents = 0; n0 = pkt_queued(pa, 0); n1 = pkt_queued(pb, 0); +#if defined(_WIN32) || defined(BUSYWAIT) + if (n0){ + ioctl(pollfd[1].fd, NIOCTXSYNC, NULL); + pollfd[1].revents = POLLOUT; + } + else { + ioctl(pollfd[0].fd, NIOCRXSYNC, NULL); + } + if (n1){ + ioctl(pollfd[0].fd, NIOCTXSYNC, NULL); + pollfd[0].revents = POLLOUT; + } + else { + ioctl(pollfd[1].fd, NIOCRXSYNC, NULL); + } + ret = 1; +#else if (n0) pollfd[1].events |= POLLOUT; else @@ -271,6 +288,7 @@ main(int argc, char **argv) else pollfd[1].events |= POLLIN; ret = poll(pollfd, 2, 2500); +#endif //defined(_WIN32) || defined(BUSYWAIT) if (ret <= 0 || verbose) D("poll %s [0] ev %x %x rx %d@%d tx %d," " [1] ev %x %x rx %d@%d tx %d", diff --git a/tools/tools/netmap/ctrs.h b/tools/tools/netmap/ctrs.h new file mode 100644 index 000000000000..cee316477144 --- /dev/null +++ b/tools/tools/netmap/ctrs.h @@ -0,0 +1,108 @@ +#ifndef CTRS_H_ +#define CTRS_H_ + +/* $FreeBSD$ */ + +#include + +/* counters to accumulate statistics */ +struct my_ctrs { + uint64_t pkts, bytes, events, drop; + uint64_t min_space; + struct timeval t; +}; + +/* very crude code to print a number in normalized form. + * Caller has to make sure that the buffer is large enough. + */ +static const char * +norm2(char *buf, double val, char *fmt) +{ + char *units[] = { "", "K", "M", "G", "T" }; + u_int i; + + for (i = 0; val >=1000 && i < sizeof(units)/sizeof(char *) - 1; i++) + val /= 1000; + sprintf(buf, fmt, val, units[i]); + return buf; +} + +static __inline const char * +norm(char *buf, double val) +{ + return norm2(buf, val, "%.3f %s"); +} + +static __inline int +timespec_ge(const struct timespec *a, const struct timespec *b) +{ + + if (a->tv_sec > b->tv_sec) + return (1); + if (a->tv_sec < b->tv_sec) + return (0); + if (a->tv_nsec >= b->tv_nsec) + return (1); + return (0); +} + +static __inline struct timespec +timeval2spec(const struct timeval *a) +{ + struct timespec ts = { + .tv_sec = a->tv_sec, + .tv_nsec = a->tv_usec * 1000 + }; + return ts; +} + +static __inline struct timeval +timespec2val(const struct timespec *a) +{ + struct timeval tv = { + .tv_sec = a->tv_sec, + .tv_usec = a->tv_nsec / 1000 + }; + return tv; +} + + +static __inline struct timespec +timespec_add(struct timespec a, struct timespec b) +{ + struct timespec ret = { a.tv_sec + b.tv_sec, a.tv_nsec + b.tv_nsec }; + if (ret.tv_nsec >= 1000000000) { + ret.tv_sec++; + ret.tv_nsec -= 1000000000; + } + return ret; +} + +static __inline struct timespec +timespec_sub(struct timespec a, struct timespec b) +{ + struct timespec ret = { a.tv_sec - b.tv_sec, a.tv_nsec - b.tv_nsec }; + if (ret.tv_nsec < 0) { + ret.tv_sec--; + ret.tv_nsec += 1000000000; + } + return ret; +} + +static uint64_t +wait_for_next_report(struct timeval *prev, struct timeval *cur, + int report_interval) +{ + struct timeval delta; + + delta.tv_sec = report_interval/1000; + delta.tv_usec = (report_interval%1000)*1000; + if (select(0, NULL, NULL, NULL, &delta) < 0 && errno != EINTR) { + perror("select"); + abort(); + } + gettimeofday(cur, NULL); + timersub(cur, prev, &delta); + return delta.tv_sec* 1000000 + delta.tv_usec; +} +#endif /* CTRS_H_ */ diff --git a/tools/tools/netmap/nmreplay.8 b/tools/tools/netmap/nmreplay.8 new file mode 100644 index 000000000000..8e5ddb9698dd --- /dev/null +++ b/tools/tools/netmap/nmreplay.8 @@ -0,0 +1,129 @@ +.\" Copyright (c) 2016 Luigi Rizzo, Universita` di Pisa +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. +.\" +.\" $FreeBSD$ +.\" +.Dd February 16, 2016 +.Dt NMREPLAY 1 +.Os +.Sh NAME +.Nm nmreplay +.Nd playback a pcap file through a netmap interface +.Sh SYNOPSIS +.Bk -words +.Bl -tag -width "nmreplay" +.It Nm +.Op Fl f Ar pcap-file +.Op Fl i Ar netmap-interface +.Op Fl B Ar bandwidth +.Op Fl D Ar delay +.Op Fl L Ar loss +.Op Fl b Ar batch size +.Op Fl w Ar wait-link +.Op Fl v +.Op Fl C Ar cpu-placement +.Sh DESCRIPTION +.Nm +works like +.Nm tcpreplay +to replay a pcap file through a netmap interface, +with programmable rates and possibly delays, losses +and packet alterations. +.Nm +is designed to run at high speed, so the transmit schedule +is computed ahead of time, and the thread in charge of transmission +only has to pump data through the interface. +.Nm +can connect to any type of netmap port. +.Pp +Command line options are as follows +.Bl -tag -width Ds +.It Fl f Ar pcap-file +Name of the pcap file to replay. +.It Fl i Ar interface +Name of the netmap interface to use as output. +.It Fl v +Enable verbose mode +.It Fl b Ar batch-size +Maximum batch size to use during transmissions. +.Nm +normally transmits packets one at a time, but it may use +larger batches, up to the value specified with this option, +when running at high rates. +.It Fl B Ar bps | Cm constant, Ns Ar bps | Cm ether, Ns Ar bps | Cm real Ns Op , Ns Ar speedup +Bandwidth to be used for transmission. +.Ar bps +is a floating point number optionally follow by a character +(k, K, m, M, g, G) that multiplies the value by 10^3, 10^6 and 10^9 +respectively. +.Cm constant +(can be omitted) means that the bandwidth will be computed +with reference to the actual packet size (excluding CRC and framing). +.Cm ether +indicates that the ethernet framing (160 bits) and CRC (32 bits) +will be included in the computation of the packet size. +.Cm real +means transmission will occur according to the timestamps +recorded in the trace. The optional +.Ar speedup +multiplier (defaults to 1) indicates how much faster +or slower than real time the trace should be replayed. +.It Fl D Ar dt | Cm constant, Ns Ar dt | Cm uniform, Ns Ar dmin,dmax | Cm exp, Ar dmin,davg +Adds additional delay to the packet transmission, whose distribution +can be constant, uniform or exponential. +.Ar dt, dmin, dmax, avt +are times expressed as floating point numbers optionally followed +by a character (s, m, u, n) to indicate seconds, milliseconds, +microseconds, nanoseconds. +The delay is added to the transmit time and adjusted so that there is +never packet reordering. +.It Fl L Ar x | Cm plr, Ns Ar x | Cm ber, Ns Ar x +Simulates packet or bit errors, causing offending packets to be dropped. +.Ar x +is a floating point number indicating the packet or bit error rate. +.It Fl w Ar wait-link +indicates the number of seconds to wait before transmitting. +It defaults to 2, and may be useful when talking to physical +ports to let link negotiation complete before starting transmission. +.El +.Sh OPERATION +.Nm +creates an in-memory schedule with all packets to be transmitted, +and then launches a separate thread to take care of transmissions +while the main thread reports statistics every second. +.Sh SEE ALSO +.Pa http://info.iet.unipi.it/~luigi/netmap/ +.Pp +Luigi Rizzo, Revisiting network I/O APIs: the netmap framework, +Communications of the ACM, 55 (3), pp.45-51, March 2012 +.Pp +Luigi Rizzo, Giuseppe Lettieri, +VALE, a switched ethernet for virtual machines, +ACM CoNEXT'12, December 2012, Nice +.Sh AUTHORS +.An -nosplit +.Nm +has been written by +.An Luigi Rizzo, Andrea Beconcini, Francesco Mola and Lorenzo Biagini +at the Universita` di Pisa, Italy. diff --git a/tools/tools/netmap/nmreplay.c b/tools/tools/netmap/nmreplay.c new file mode 100644 index 000000000000..7a46bd57e198 --- /dev/null +++ b/tools/tools/netmap/nmreplay.c @@ -0,0 +1,1820 @@ +/* + * Copyright (C) 2016 Universita` di Pisa. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + + +#if 0 /* COMMENT */ + +This program implements NMREPLAY, a program to replay a pcap file +enforcing the output rate and possibly random losses and delay +distributions. +It is meant to be run from the command line and implemented with a main +control thread for monitoring, plus a thread to push packets out. + +The control thread parses command line arguments, prepares a +schedule for transmission in a memory buffer and then sits +in a loop where it periodically reads traffic statistics from +the other threads and prints them out on the console. + +The transmit buffer contains headers and packets. Each header +includes a timestamp that determines when the packet should be sent out. +A "consumer" thread cons() reads from the queue and transmits packets +on the output netmap port when their time has come. + +The program does CPU pinning and sets the scheduler and priority +for the "cons" threads. Externally one should do the +assignment of other threads (e.g. interrupt handlers) and +make sure that network interfaces are configured properly. + +--- Main functions of the program --- +within each function, q is used as a pointer to the queue holding +packets and parameters. + +pcap_prod() + + reads from the pcap file and prepares packets to transmit. + After reading a packet from the pcap file, the following information + are extracted which can be used to determine the schedule: + + q->cur_pkt points to the buffer containing the packet + q->cur_len packet length, excluding CRC + q->cur_caplen available packet length (may be shorter than cur_len) + q->cur_tt transmission time for the packet, computed from the trace. + + The following functions are then called in sequence: + + q->c_loss (set with the -L command line option) decides + whether the packet should be dropped before even queuing. + This is generally useful to emulate random loss. + The function is supposed to set q->c_drop = 1 if the + packet should be dropped, or leave it to 0 otherwise. + + q->c_bw (set with the -B command line option) is used to + enforce the transmit bandwidth. The function must store + in q->cur_tt the transmission time (in nanoseconds) of + the packet, which is typically proportional to the length + of the packet, i.e. q->cur_tt = q->cur_len / + Variants are possible, eg. to account for constant framing + bits as on the ethernet, or variable channel acquisition times, + etc. + This mechanism can also be used to simulate variable queueing + delay e.g. due to the presence of cross traffic. + + q->c_delay (set with the -D option) implements delay emulation. + The function should set q->cur_delay to the additional + delay the packet is subject to. The framework will take care of + computing the actual exit time of a packet so that there is no + reordering. + + +#endif /* COMMENT */ + +// debugging macros +#define NED(_fmt, ...) do {} while (0) +#define ED(_fmt, ...) \ + do { \ + struct timeval _t0; \ + gettimeofday(&_t0, NULL); \ + fprintf(stderr, "%03d.%03d %-10.10s [%5d] \t" _fmt "\n", \ + (int)(_t0.tv_sec % 1000), (int)_t0.tv_usec/1000, \ + __FUNCTION__, __LINE__, ##__VA_ARGS__); \ + } while (0) + +/* WWW is for warnings, EEE is for errors */ +#define WWW(_fmt, ...) ED("--WWW-- " _fmt, ##__VA_ARGS__) +#define EEE(_fmt, ...) ED("--EEE-- " _fmt, ##__VA_ARGS__) +#define DDD(_fmt, ...) ED("--DDD-- " _fmt, ##__VA_ARGS__) + +#define _GNU_SOURCE // for CPU_SET() etc +#include +#define NETMAP_WITH_LIBS +#include +#include + + +/* + * +A packet in the queue is q_pkt plus the payload. + +For the packet descriptor we need the following: + + - position of next packet in the queue (can go backwards). + We can reduce to 32 bits if we consider alignments, + or we just store the length to be added to the current + value and assume 0 as a special index. + - actual packet length (16 bits may be ok) + - queue output time, in nanoseconds (64 bits) + - delay line output time, in nanoseconds + One of the two can be packed to a 32bit value + +A convenient coding uses 32 bytes per packet. + + */ + +struct q_pkt { + uint64_t next; /* buffer index for next packet */ + uint64_t pktlen; /* actual packet len */ + uint64_t pt_qout; /* time of output from queue */ + uint64_t pt_tx; /* transmit time */ +}; + + +/* + * The header for a pcap file + */ +struct pcap_file_header { + uint32_t magic; + /*used to detect the file format itself and the byte + ordering. The writing application writes 0xa1b2c3d4 with it's native byte + ordering format into this field. The reading application will read either + 0xa1b2c3d4 (identical) or 0xd4c3b2a1 (swapped). If the reading application + reads the swapped 0xd4c3b2a1 value, it knows that all the following fields + will have to be swapped too. For nanosecond-resolution files, the writing + application writes 0xa1b23c4d, with the two nibbles of the two lower-order + bytes swapped, and the reading application will read either 0xa1b23c4d + (identical) or 0x4d3cb2a1 (swapped)*/ + uint16_t version_major; + uint16_t version_minor; /*the version number of this file format */ + int32_t thiszone; + /*the correction time in seconds between GMT (UTC) and the + local timezone of the following packet header timestamps. Examples: If the + timestamps are in GMT (UTC), thiszone is simply 0. If the timestamps are in + Central European time (Amsterdam, Berlin, ...) which is GMT + 1:00, thiszone + must be -3600*/ + uint32_t stampacc; /*the accuracy of time stamps in the capture*/ + uint32_t snaplen; + /*the "snapshot length" for the capture (typically 65535 + or even more, but might be limited by the user)*/ + uint32_t network; + /*link-layer header type, specifying the type of headers + at the beginning of the packet (e.g. 1 for Ethernet); this can be various + types such as 802.11, 802.11 with various radio information, PPP, Token + Ring, FDDI, etc.*/ +}; + +#if 0 /* from pcap.h */ +struct pcap_file_header { + bpf_u_int32 magic; + u_short version_major; + u_short version_minor; + bpf_int32 thiszone; /* gmt to local correction */ + bpf_u_int32 sigfigs; /* accuracy of timestamps */ + bpf_u_int32 snaplen; /* max length saved portion of each pkt */ + bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */ +}; + +struct pcap_pkthdr { + struct timeval ts; /* time stamp */ + bpf_u_int32 caplen; /* length of portion present */ + bpf_u_int32 len; /* length this packet (off wire) */ +}; +#endif /* from pcap.h */ + +struct pcap_pkthdr { + uint32_t ts_sec; /* seconds from epoch */ + uint32_t ts_frac; /* microseconds or nanoseconds depending on sigfigs */ + uint32_t caplen; + /*the number of bytes of packet data actually captured + and saved in the file. This value should never become larger than orig_len + or the snaplen value of the global header*/ + uint32_t len; /* wire length */ +}; + + +#define PKT_PAD (32) /* padding on packets */ + +static inline int pad(int x) +{ + return ((x) + PKT_PAD - 1) & ~(PKT_PAD - 1) ; +} + + + +/* + * wrapper around the pcap file. + * We mmap the file so it is easy to do multiple passes through it. + */ +struct nm_pcap_file { + int fd; + uint64_t filesize; + const char *data; /* mmapped file */ + + uint64_t tot_pkt; + uint64_t tot_bytes; + uint64_t tot_bytes_rounded; /* need hdr + pad(len) */ + uint32_t resolution; /* 1000 for us, 1 for ns */ + int swap; /* need to swap fields ? */ + + uint64_t first_ts; + uint64_t total_tx_time; + /* + * total_tx_time is computed as last_ts - first_ts, plus the + * transmission time for the first packet which in turn is + * computed according to the average bandwidth + */ + + uint64_t file_len; + const char *cur; /* running pointer */ + const char *lim; /* data + file_len */ + int err; +}; + +static struct nm_pcap_file *readpcap(const char *fn); +static void destroy_pcap(struct nm_pcap_file *file); + + +#include +#include +#include +#include +#include +#include /* memcpy */ + +#include + +#define NS_SCALE 1000000000UL /* nanoseconds in 1s */ + +static void destroy_pcap(struct nm_pcap_file *pf) +{ + if (!pf) + return; + + munmap((void *)(uintptr_t)pf->data, pf->filesize); + close(pf->fd); + bzero(pf, sizeof(*pf)); + free(pf); + return; +} + +// convert a field of given size if swap is needed. +static uint32_t +cvt(const void *src, int size, char swap) +{ + uint32_t ret = 0; + if (size != 2 && size != 4) { + EEE("Invalid size %d\n", size); + exit(1); + } + memcpy(&ret, src, size); + if (swap) { + unsigned char tmp, *data = (unsigned char *)&ret; + int i; + for (i = 0; i < size / 2; i++) { + tmp = data[i]; + data[i] = data[size - (1 + i)]; + data[size - (1 + i)] = tmp; + } + } + return ret; +} + +static uint32_t +read_next_info(struct nm_pcap_file *pf, int size) +{ + const char *end = pf->cur + size; + uint32_t ret; + if (end > pf->lim) { + pf->err = 1; + ret = 0; + } else { + ret = cvt(pf->cur, size, pf->swap); + pf->cur = end; + } + return ret; +} + +/* + * mmap the file, make sure timestamps are sorted, and count + * packets and sizes + * Timestamps represent the receive time of the packets. + * We need to compute also the 'first_ts' which refers to a hypotetical + * packet right before the first one, see the code for details. + */ +static struct nm_pcap_file * +readpcap(const char *fn) +{ + struct nm_pcap_file _f, *pf = &_f; + uint64_t prev_ts, first_pkt_time; + uint32_t magic, first_len = 0; + + bzero(pf, sizeof(*pf)); + pf->fd = open(fn, O_RDONLY); + if (pf->fd < 0) { + EEE("cannot open file %s", fn); + return NULL; + } + /* compute length */ + pf->filesize = lseek(pf->fd, 0, SEEK_END); + lseek(pf->fd, 0, SEEK_SET); + ED("filesize is %lu", (u_long)(pf->filesize)); + if (pf->filesize < sizeof(struct pcap_file_header)) { + EEE("file too short %s", fn); + close(pf->fd); + return NULL; + } + pf->data = mmap(NULL, pf->filesize, PROT_READ, MAP_SHARED, pf->fd, 0); + if (pf->data == MAP_FAILED) { + EEE("cannot mmap file %s", fn); + close(pf->fd); + return NULL; + } + pf->cur = pf->data; + pf->lim = pf->data + pf->filesize; + pf->err = 0; + pf->swap = 0; /* default, same endianness when read magic */ + + magic = read_next_info(pf, 4); + ED("magic is 0x%x", magic); + switch (magic) { + case 0xa1b2c3d4: /* native, us resolution */ + pf->swap = 0; + pf->resolution = 1000; + break; + case 0xd4c3b2a1: /* swapped, us resolution */ + pf->swap = 1; + pf->resolution = 1000; + break; + case 0xa1b23c4d: /* native, ns resolution */ + pf->swap = 0; + pf->resolution = 1; /* nanoseconds */ + break; + case 0x4d3cb2a1: /* swapped, ns resolution */ + pf->swap = 1; + pf->resolution = 1; /* nanoseconds */ + break; + default: + EEE("unknown magic 0x%x", magic); + return NULL; + } + + ED("swap %d res %d\n", pf->swap, pf->resolution); + pf->cur = pf->data + sizeof(struct pcap_file_header); + pf->lim = pf->data + pf->filesize; + pf->err = 0; + prev_ts = 0; + while (pf->cur < pf->lim && pf->err == 0) { + uint32_t base = pf->cur - pf->data; + uint64_t cur_ts = read_next_info(pf, 4) * NS_SCALE + + read_next_info(pf, 4) * pf->resolution; + uint32_t caplen = read_next_info(pf, 4); + uint32_t len = read_next_info(pf, 4); + + if (pf->err) { + WWW("end of pcap file after %d packets\n", + (int)pf->tot_pkt); + break; + } + if (cur_ts < prev_ts) { + WWW("reordered packet %d\n", + (int)pf->tot_pkt); + } + prev_ts = cur_ts; + (void)base; + if (pf->tot_pkt == 0) { + pf->first_ts = cur_ts; + first_len = len; + } + pf->tot_pkt++; + pf->tot_bytes += len; + pf->tot_bytes_rounded += pad(len) + sizeof(struct q_pkt); + pf->cur += caplen; + } + pf->total_tx_time = prev_ts - pf->first_ts; /* excluding first packet */ + ED("tot_pkt %lu tot_bytes %lu tx_time %.6f s first_len %lu", + (u_long)pf->tot_pkt, (u_long)pf->tot_bytes, + 1e-9*pf->total_tx_time, (u_long)first_len); + /* + * We determine that based on the + * average bandwidth of the trace, as follows + * first_pkt_ts = p[0].len / avg_bw + * In turn avg_bw = (total_len - p[0].len)/(p[n-1].ts - p[0].ts) + * so + * first_ts = p[0].ts - p[0].len * (p[n-1].ts - p[0].ts) / (total_len - p[0].len) + */ + if (pf->tot_bytes == first_len) { + /* cannot estimate bandwidth, so force 1 Gbit */ + first_pkt_time = first_len * 8; /* * 10^9 / bw */ + } else { + first_pkt_time = pf->total_tx_time * first_len / (pf->tot_bytes - first_len); + } + ED("first_pkt_time %.6f s", 1e-9*first_pkt_time); + pf->total_tx_time += first_pkt_time; + pf->first_ts -= first_pkt_time; + + /* all correct, allocate a record and copy */ + pf = calloc(1, sizeof(*pf)); + *pf = _f; + /* reset pointer to start */ + pf->cur = pf->data + sizeof(struct pcap_file_header); + pf->err = 0; + return pf; +} + +enum my_pcap_mode { PM_NONE, PM_FAST, PM_FIXED, PM_REAL }; + +int verbose = 0; + +static int do_abort = 0; + +#include +#include +#include +#include + +#include // setpriority + +#ifdef __FreeBSD__ +#include /* pthread w/ affinity */ +#include /* cpu_set */ +#endif /* __FreeBSD__ */ + +#ifdef linux +#define cpuset_t cpu_set_t +#endif + +#ifdef __APPLE__ +#define cpuset_t uint64_t // XXX +static inline void CPU_ZERO(cpuset_t *p) +{ + *p = 0; +} + +static inline void CPU_SET(uint32_t i, cpuset_t *p) +{ + *p |= 1<< (i & 0x3f); +} + +#define pthread_setaffinity_np(a, b, c) ((void)a, 0) +#define sched_setscheduler(a, b, c) (1) /* error */ +#define clock_gettime(a,b) \ + do {struct timespec t0 = {0,0}; *(b) = t0; } while (0) + +#define _P64 unsigned long +#endif + +#ifndef _P64 + +/* we use uint64_t widely, but printf gives trouble on different + * platforms so we use _P64 as a cast + */ +#define _P64 uint64_t +#endif /* print stuff */ + + +struct _qs; /* forward */ +/* + * descriptor of a configuration entry. + * Each handler has a parse function which takes ac/av[] and returns + * true if successful. Any allocated space is stored into struct _cfg * + * that is passed as argument. + * arg and arg_len are included for convenience. + */ +struct _cfg { + int (*parse)(struct _qs *, struct _cfg *, int ac, char *av[]); /* 0 ok, 1 on error */ + int (*run)(struct _qs *, struct _cfg *arg); /* 0 Ok, 1 on error */ + // int close(struct _qs *, void *arg); /* 0 Ok, 1 on error */ + + const char *optarg; /* command line argument. Initial value is the error message */ + /* placeholders for common values */ + void *arg; /* allocated memory if any */ + int arg_len; /* size of *arg in case a realloc is needed */ + uint64_t d[16]; /* static storage for simple cases */ + double f[4]; /* static storage for simple cases */ +}; + + +/* + * communication occurs through this data structure, with fields + * cache-aligned according to who are the readers/writers. + * + +The queue is an array of memory (buf) of size buflen (does not change). + +The producer uses 'tail' as an index in the queue to indicate +the first empty location (ie. after the last byte of data), +the consumer uses head to indicate the next byte to consume. + +For best performance we should align buffers and packets +to multiples of cacheline, but this would explode memory too much. +Worst case memory explosion is with 65 byte packets. +Memory usage as shown below: + + qpkt-pad + size 32-16 32-32 32-64 64-64 + + 64 96 96 96 128 + 65 112 128 160 192 + + +An empty queue has head == tail, a full queue will have free space +below a threshold. In our case the queue is large enough and we +are non blocking so we can simply drop traffic when the queue +approaches a full state. + +To simulate bandwidth limitations efficiently, the producer has a second +pointer, prod_tail_1, used to check for expired packets. This is done lazily. + + */ +/* + * When sizing the buffer, we must assume some value for the bandwidth. + * INFINITE_BW is supposed to be faster than what we support + */ +#define INFINITE_BW (200ULL*1000000*1000) +#define MY_CACHELINE (128ULL) +#define MAX_PKT (9200) /* max packet size */ + +#define ALIGN_CACHE __attribute__ ((aligned (MY_CACHELINE))) + +struct _qs { /* shared queue */ + uint64_t t0; /* start of times */ + + uint64_t buflen; /* queue length */ + char *buf; + + /* handlers for various options */ + struct _cfg c_delay; + struct _cfg c_bw; + struct _cfg c_loss; + + /* producer's fields */ + uint64_t tx ALIGN_CACHE; /* tx counter */ + uint64_t prod_tail_1; /* head of queue */ + uint64_t prod_head; /* cached copy */ + uint64_t prod_tail; /* cached copy */ + uint64_t prod_drop; /* drop packet count */ + uint64_t prod_max_gap; /* rx round duration */ + + struct nm_pcap_file *pcap; /* the pcap struct */ + + /* parameters for reading from the netmap port */ + struct nm_desc *src_port; /* netmap descriptor */ + const char * prod_ifname; /* interface name or pcap file */ + struct netmap_ring *rxring; /* current ring being handled */ + uint32_t si; /* ring index */ + int burst; + uint32_t rx_qmax; /* stats on max queued */ + + uint64_t qt_qout; /* queue exit time for last packet */ + /* + * when doing shaping, the software computes and stores here + * the time when the most recently queued packet will exit from + * the queue. + */ + + uint64_t qt_tx; /* delay line exit time for last packet */ + /* + * The software computes the time at which the most recently + * queued packet exits from the queue. + * To avoid reordering, the next packet should exit at least + * at qt_tx + cur_tt + */ + + /* producer's fields controlling the queueing */ + const char * cur_pkt; /* current packet being analysed */ + uint32_t cur_len; /* length of current packet */ + uint32_t cur_caplen; /* captured length of current packet */ + + int cur_drop; /* 1 if current packet should be dropped. */ + /* + * cur_drop can be set as a result of the loss emulation, + * and may need to use the packet size, current time, etc. + */ + + uint64_t cur_tt; /* transmission time (ns) for current packet */ + /* + * The transmission time is how much link time the packet will consume. + * should be set by the function that does the bandwidth emulation, + * but could also be the result of a function that emulates the + * presence of competing traffic, MAC protocols etc. + * cur_tt is 0 for links with infinite bandwidth. + */ + + uint64_t cur_delay; /* delay (ns) for current packet from c_delay.run() */ + /* + * this should be set by the function that computes the extra delay + * applied to the packet. + * The code makes sure that there is no reordering and possibly + * bumps the output time as needed. + */ + + + /* consumer's fields */ + const char * cons_ifname; + uint64_t rx ALIGN_CACHE; /* rx counter */ + uint64_t cons_head; /* cached copy */ + uint64_t cons_tail; /* cached copy */ + uint64_t cons_now; /* most recent producer timestamp */ + uint64_t rx_wait; /* stats */ + + /* shared fields */ + volatile uint64_t _tail ALIGN_CACHE ; /* producer writes here */ + volatile uint64_t _head ALIGN_CACHE ; /* consumer reads from here */ +}; + +struct pipe_args { + int wait_link; + + pthread_t cons_tid; /* main thread */ + pthread_t prod_tid; /* producer thread */ + + /* Affinity: */ + int cons_core; /* core for cons() */ + int prod_core; /* core for prod() */ + + struct nm_desc *pa; /* netmap descriptor */ + struct nm_desc *pb; + + struct _qs q; +}; + +#define NS_IN_S (1000000000ULL) // nanoseconds +#define TIME_UNITS NS_IN_S +/* set the thread affinity. */ +static int +setaffinity(int i) +{ + cpuset_t cpumask; + struct sched_param p; + + if (i == -1) + return 0; + + /* Set thread affinity affinity.*/ + CPU_ZERO(&cpumask); + CPU_SET(i, &cpumask); + + if (pthread_setaffinity_np(pthread_self(), sizeof(cpuset_t), &cpumask) != 0) { + WWW("Unable to set affinity: %s", strerror(errno)); + } + if (setpriority(PRIO_PROCESS, 0, -10)) {; // XXX not meaningful + WWW("Unable to set priority: %s", strerror(errno)); + } + bzero(&p, sizeof(p)); + p.sched_priority = 10; // 99 on linux ? + // use SCHED_RR or SCHED_FIFO + if (sched_setscheduler(0, SCHED_RR, &p)) { + WWW("Unable to set scheduler: %s", strerror(errno)); + } + return 0; +} + + +/* + * set the timestamp from the clock, subtract t0 + */ +static inline void +set_tns_now(uint64_t *now, uint64_t t0) +{ + struct timespec t; + + clock_gettime(CLOCK_REALTIME, &t); // XXX precise on FreeBSD ? + *now = (uint64_t)(t.tv_nsec + NS_IN_S * t.tv_sec); + *now -= t0; +} + + + +/* compare two timestamps */ +static inline int64_t +ts_cmp(uint64_t a, uint64_t b) +{ + return (int64_t)(a - b); +} + +/* create a packet descriptor */ +static inline struct q_pkt * +pkt_at(struct _qs *q, uint64_t ofs) +{ + return (struct q_pkt *)(q->buf + ofs); +} + + +/* + * we have already checked for room and prepared p->next + */ +static inline int +enq(struct _qs *q) +{ + struct q_pkt *p = pkt_at(q, q->prod_tail); + + /* hopefully prefetch has been done ahead */ + nm_pkt_copy(q->cur_pkt, (char *)(p+1), q->cur_caplen); + p->pktlen = q->cur_len; + p->pt_qout = q->qt_qout; + p->pt_tx = q->qt_tx; + p->next = q->prod_tail + pad(q->cur_len) + sizeof(struct q_pkt); + ND("enqueue len %d at %d new tail %ld qout %.6f tx %.6f", + q->cur_len, (int)q->prod_tail, p->next, + 1e-9*p->pt_qout, 1e-9*p->pt_tx); + q->prod_tail = p->next; + q->tx++; + return 0; +} + +/* + * simple handler for parameters not supplied + */ +static int +null_run_fn(struct _qs *q, struct _cfg *cfg) +{ + (void)q; + (void)cfg; + return 0; +} + + + +/* + * put packet data into the buffer. + * We read from the mmapped pcap file, construct header, copy + * the captured length of the packet and pad with zeroes. + */ +static void * +pcap_prod(void *_pa) +{ + struct pipe_args *pa = _pa; + struct _qs *q = &pa->q; + struct nm_pcap_file *pf = q->pcap; /* already opened by readpcap */ + uint32_t loops, i, tot_pkts; + + /* data plus the loop record */ + uint64_t need; + uint64_t t_tx, tt, last_ts; /* last timestamp from trace */ + + /* + * For speed we make sure the trace is at least some 1000 packets, + * so we may need to loop the trace more than once (for short traces) + */ + loops = (1 + 10000 / pf->tot_pkt); + tot_pkts = loops * pf->tot_pkt; + need = loops * pf->tot_bytes_rounded + sizeof(struct q_pkt); + q->buf = calloc(1, need); + if (q->buf == NULL) { + D("alloc %ld bytes for queue failed, exiting",(_P64)need); + goto fail; + } + q->prod_head = q->prod_tail = 0; + q->buflen = need; + + pf->cur = pf->data + sizeof(struct pcap_file_header); + pf->err = 0; + + ED("--- start create %lu packets at tail %d", + (u_long)tot_pkts, (int)q->prod_tail); + last_ts = pf->first_ts; /* beginning of the trace */ + + q->qt_qout = 0; /* first packet out of the queue */ + + for (loops = 0, i = 0; i < tot_pkts && !do_abort; i++) { + const char *next_pkt; /* in the pcap buffer */ + uint64_t cur_ts; + + /* read values from the pcap buffer */ + cur_ts = read_next_info(pf, 4) * NS_SCALE + + read_next_info(pf, 4) * pf->resolution; + q->cur_caplen = read_next_info(pf, 4); + q->cur_len = read_next_info(pf, 4); + next_pkt = pf->cur + q->cur_caplen; + + /* prepare fields in q for the generator */ + q->cur_pkt = pf->cur; + /* initial estimate of tx time */ + q->cur_tt = cur_ts - last_ts; + // -pf->first_ts + loops * pf->total_tx_time - last_ts; + + if ((i % pf->tot_pkt) == 0) + ED("insert %5d len %lu cur_tt %.6f", + i, (u_long)q->cur_len, 1e-9*q->cur_tt); + + /* prepare for next iteration */ + pf->cur = next_pkt; + last_ts = cur_ts; + if (next_pkt == pf->lim) { //last pkt + pf->cur = pf->data + sizeof(struct pcap_file_header); + last_ts = pf->first_ts; /* beginning of the trace */ + loops++; + } + + q->c_loss.run(q, &q->c_loss); + if (q->cur_drop) + continue; + q->c_bw.run(q, &q->c_bw); + tt = q->cur_tt; + q->qt_qout += tt; +#if 0 + if (drop_after(q)) + continue; +#endif + q->c_delay.run(q, &q->c_delay); /* compute delay */ + t_tx = q->qt_qout + q->cur_delay; + ND(5, "tt %ld qout %ld tx %ld qt_tx %ld", tt, q->qt_qout, t_tx, q->qt_tx); + /* insure no reordering and spacing by transmission time */ + q->qt_tx = (t_tx >= q->qt_tx + tt) ? t_tx : q->qt_tx + tt; + enq(q); + + q->tx++; + ND("ins %d q->prod_tail = %lu", (int)insert, (unsigned long)q->prod_tail); + } + /* loop marker ? */ + ED("done q->prod_tail:%d",(int)q->prod_tail); + q->_tail = q->prod_tail; /* publish */ + + return NULL; +fail: + if (q->buf != NULL) { + free(q->buf); + } + nm_close(pa->pb); + return (NULL); +} + + +/* + * the consumer reads from the queue using head, + * advances it every now and then. + */ +static void * +cons(void *_pa) +{ + struct pipe_args *pa = _pa; + struct _qs *q = &pa->q; + int pending = 0; + uint64_t last_ts = 0; + + /* read the start of times in q->t0 */ + set_tns_now(&q->t0, 0); + /* set the time (cons_now) to clock - q->t0 */ + set_tns_now(&q->cons_now, q->t0); + q->cons_head = q->_head; + q->cons_tail = q->_tail; + while (!do_abort) { /* consumer, infinite */ + struct q_pkt *p = pkt_at(q, q->cons_head); + + __builtin_prefetch (q->buf + p->next); + + if (q->cons_head == q->cons_tail) { //reset record + ND("Transmission restarted"); + /* + * add to q->t0 the time for the last packet + */ + q->t0 += last_ts; + q->cons_head = 0; //restart from beginning of the queue + continue; + } + last_ts = p->pt_tx; + if (ts_cmp(p->pt_tx, q->cons_now) > 0) { + // packet not ready + q->rx_wait++; + /* the ioctl should be conditional */ + ioctl(pa->pb->fd, NIOCTXSYNC, 0); // XXX just in case + pending = 0; + usleep(20); + set_tns_now(&q->cons_now, q->t0); + continue; + } + /* XXX copy is inefficient but simple */ + pending++; + if (nm_inject(pa->pb, (char *)(p + 1), p->pktlen) == 0 || + pending > q->burst) { + RD(1, "inject failed len %d now %ld tx %ld h %ld t %ld next %ld", + (int)p->pktlen, (u_long)q->cons_now, (u_long)p->pt_tx, + (u_long)q->_head, (u_long)q->_tail, (u_long)p->next); + ioctl(pa->pb->fd, NIOCTXSYNC, 0); + pending = 0; + continue; + } + q->cons_head = p->next; + /* drain packets from the queue */ + q->rx++; + } + D("exiting on abort"); + return NULL; +} + +/* + * In case of pcap file as input, the program acts in 2 different + * phases. It first fill the queue and then starts the cons() + */ +static void * +nmreplay_main(void *_a) +{ + struct pipe_args *a = _a; + struct _qs *q = &a->q; + const char *cap_fname = q->prod_ifname; + + setaffinity(a->cons_core); + set_tns_now(&q->t0, 0); /* starting reference */ + if (cap_fname == NULL) { + goto fail; + } + q->pcap = readpcap(cap_fname); + if (q->pcap == NULL) { + EEE("unable to read file %s", cap_fname); + goto fail; + } + pcap_prod((void*)a); + destroy_pcap(q->pcap); + q->pcap = NULL; + a->pb = nm_open(q->cons_ifname, NULL, 0, NULL); + if (a->pb == NULL) { + EEE("cannot open netmap on %s", q->cons_ifname); + do_abort = 1; // XXX any better way ? + return NULL; + } + /* continue as cons() */ + WWW("prepare to send packets"); + usleep(1000); + cons((void*)a); + EEE("exiting on abort"); +fail: + if (q->pcap != NULL) { + destroy_pcap(q->pcap); + } + do_abort = 1; + return NULL; +} + + +static void +sigint_h(int sig) +{ + (void)sig; /* UNUSED */ + do_abort = 1; + signal(SIGINT, SIG_DFL); +} + + + +static void +usage(void) +{ + fprintf(stderr, + "usage: nmreplay [-v] [-D delay] [-B {[constant,]bps|ether,bps|real,speedup}] [-L loss]\n" + "\t[-b burst] -i ifa-or-pcap-file -i ifb\n"); + exit(1); +} + + +/*---- configuration handling ---- */ +/* + * support routine: split argument, returns ac and *av. + * av contains two extra entries, a NULL and a pointer + * to the entire string. + */ +static char ** +split_arg(const char *src, int *_ac) +{ + char *my = NULL, **av = NULL, *seps = " \t\r\n,"; + int l, i, ac; /* number of entries */ + + if (!src) + return NULL; + l = strlen(src); + /* in the first pass we count fields, in the second pass + * we allocate the av[] array and a copy of the string + * and fill av[]. av[ac] = NULL, av[ac+1] + */ + for (;;) { + i = ac = 0; + ND("start pass %d: <%s>", av ? 1 : 0, my); + while (i < l) { + /* trim leading separator */ + while (i = l) + break; + ND(" pass %d arg %d: <%s>", av ? 1 : 0, ac, src+i); + if (av) /* in the second pass, set the result */ + av[ac] = my+i; + ac++; + /* skip string */ + while (i ", i, av[i]); + } + av[i++] = NULL; + av[i++] = my; + *_ac = ac; + return av; +} + + +/* + * apply a command against a set of functions, + * install a handler in *dst + */ +static int +cmd_apply(const struct _cfg *a, const char *arg, struct _qs *q, struct _cfg *dst) +{ + int ac = 0; + char **av; + int i; + + if (arg == NULL || *arg == '\0') + return 1; /* no argument may be ok */ + if (a == NULL || dst == NULL) { + ED("program error - invalid arguments"); + exit(1); + } + av = split_arg(arg, &ac); + if (av == NULL) + return 1; /* error */ + for (i = 0; a[i].parse; i++) { + struct _cfg x = a[i]; + const char *errmsg = x.optarg; + int ret; + + x.arg = NULL; + x.arg_len = 0; + bzero(&x.d, sizeof(x.d)); + ND("apply %s to %s", av[0], errmsg); + ret = x.parse(q, &x, ac, av); + if (ret == 2) /* not recognised */ + continue; + if (ret == 1) { + ED("invalid arguments: need '%s' have '%s'", + errmsg, arg); + break; + } + x.optarg = arg; + *dst = x; + return 0; + } + ED("arguments %s not recognised", arg); + free(av); + return 1; +} + +static struct _cfg delay_cfg[]; +static struct _cfg bw_cfg[]; +static struct _cfg loss_cfg[]; + +static uint64_t parse_bw(const char *arg); + +/* + * prodcons [options] + * accept separate sets of arguments for the two directions + * + */ + +static void +add_to(const char ** v, int l, const char *arg, const char *msg) +{ + for (; l > 0 && *v != NULL ; l--, v++); + if (l == 0) { + ED("%s %s", msg, arg); + exit(1); + } + *v = arg; +} + +int +main(int argc, char **argv) +{ + int ch, i, err=0; + +#define N_OPTS 1 + struct pipe_args bp[N_OPTS]; + const char *d[N_OPTS], *b[N_OPTS], *l[N_OPTS], *q[N_OPTS], *ifname[N_OPTS], *m[N_OPTS]; + const char *pcap_file[N_OPTS]; + int cores[4] = { 2, 8, 4, 10 }; /* default values */ + + bzero(&bp, sizeof(bp)); /* all data initially go here */ + bzero(d, sizeof(d)); + bzero(b, sizeof(b)); + bzero(l, sizeof(l)); + bzero(q, sizeof(q)); + bzero(m, sizeof(m)); + bzero(ifname, sizeof(ifname)); + bzero(pcap_file, sizeof(pcap_file)); + + + /* set default values */ + for (i = 0; i < N_OPTS; i++) { + struct _qs *q = &bp[i].q; + + q->burst = 128; + q->c_delay.optarg = "0"; + q->c_delay.run = null_run_fn; + q->c_loss.optarg = "0"; + q->c_loss.run = null_run_fn; + q->c_bw.optarg = "0"; + q->c_bw.run = null_run_fn; + } + + // Options: + // B bandwidth in bps + // D delay in seconds + // L loss probability + // f pcap file + // i interface name + // w wait link + // b batch size + // v verbose + // C cpu placement + + while ( (ch = getopt(argc, argv, "B:C:D:L:b:f:i:vw:")) != -1) { + switch (ch) { + default: + D("bad option %c %s", ch, optarg); + usage(); + break; + + case 'C': /* CPU placement, up to 4 arguments */ + { + int ac = 0; + char **av = split_arg(optarg, &ac); + if (ac == 1) { /* sequential after the first */ + cores[0] = atoi(av[0]); + cores[1] = cores[0] + 1; + cores[2] = cores[1] + 1; + cores[3] = cores[2] + 1; + } else if (ac == 2) { /* two sequential pairs */ + cores[0] = atoi(av[0]); + cores[1] = cores[0] + 1; + cores[2] = atoi(av[1]); + cores[3] = cores[2] + 1; + } else if (ac == 4) { /* four values */ + cores[0] = atoi(av[0]); + cores[1] = atoi(av[1]); + cores[2] = atoi(av[2]); + cores[3] = atoi(av[3]); + } else { + ED(" -C accepts 1, 2 or 4 comma separated arguments"); + usage(); + } + if (av) + free(av); + } + break; + + case 'B': /* bandwidth in bps */ + add_to(b, N_OPTS, optarg, "-B too many times"); + break; + + case 'D': /* delay in seconds (float) */ + add_to(d, N_OPTS, optarg, "-D too many times"); + break; + + case 'L': /* loss probability */ + add_to(l, N_OPTS, optarg, "-L too many times"); + break; + + case 'b': /* burst */ + bp[0].q.burst = atoi(optarg); + break; + + case 'f': /* pcap_file */ + add_to(pcap_file, N_OPTS, optarg, "-f too many times"); + break; + case 'i': /* interface */ + add_to(ifname, N_OPTS, optarg, "-i too many times"); + break; + case 'v': + verbose++; + break; + case 'w': + bp[0].wait_link = atoi(optarg); + break; + } + + } + + argc -= optind; + argv += optind; + + /* + * consistency checks for common arguments + * if pcap file has been provided we need just one interface, two otherwise + */ + if (!pcap_file[0]) { + ED("missing pcap file"); + usage(); + } + if (!ifname[0]) { + ED("missing interface"); + usage(); + } + if (bp[0].q.burst < 1 || bp[0].q.burst > 8192) { + WWW("invalid burst %d, set to 1024", bp[0].q.burst); + bp[0].q.burst = 1024; // XXX 128 is probably better + } + if (bp[0].wait_link > 100) { + ED("invalid wait_link %d, set to 4", bp[0].wait_link); + bp[0].wait_link = 4; + } + + bp[0].q.prod_ifname = pcap_file[0]; + bp[0].q.cons_ifname = ifname[0]; + + /* assign cores. prod and cons work better if on the same HT */ + bp[0].cons_core = cores[0]; + bp[0].prod_core = cores[1]; + ED("running on cores %d %d %d %d", cores[0], cores[1], cores[2], cores[3]); + + /* apply commands */ + for (i = 0; i < N_OPTS; i++) { /* once per queue */ + struct _qs *q = &bp[i].q; + err += cmd_apply(delay_cfg, d[i], q, &q->c_delay); + err += cmd_apply(bw_cfg, b[i], q, &q->c_bw); + err += cmd_apply(loss_cfg, l[i], q, &q->c_loss); + } + + pthread_create(&bp[0].cons_tid, NULL, nmreplay_main, (void*)&bp[0]); + signal(SIGINT, sigint_h); + sleep(1); + while (!do_abort) { + struct _qs olda = bp[0].q; + struct _qs *q0 = &bp[0].q; + + sleep(1); + ED("%ld -> %ld maxq %d round %ld", + (_P64)(q0->rx - olda.rx), (_P64)(q0->tx - olda.tx), + q0->rx_qmax, (_P64)q0->prod_max_gap + ); + ED("plr nominal %le actual %le", + (double)(q0->c_loss.d[0])/(1<<24), + q0->c_loss.d[1] == 0 ? 0 : + (double)(q0->c_loss.d[2])/q0->c_loss.d[1]); + bp[0].q.rx_qmax = (bp[0].q.rx_qmax * 7)/8; // ewma + bp[0].q.prod_max_gap = (bp[0].q.prod_max_gap * 7)/8; // ewma + } + D("exiting on abort"); + sleep(1); + + return (0); +} + +/* conversion factor for numbers. + * Each entry has a set of characters and conversion factor, + * the first entry should have an empty string and default factor, + * the final entry has s = NULL. + */ +struct _sm { /* string and multiplier */ + char *s; + double m; +}; + +/* + * parse a generic value + */ +static double +parse_gen(const char *arg, const struct _sm *conv, int *err) +{ + double d; + char *ep; + int dummy; + + if (err == NULL) + err = &dummy; + *err = 0; + if (arg == NULL) + goto error; + d = strtod(arg, &ep); + if (ep == arg) { /* no value */ + ED("bad argument %s", arg); + goto error; + } + /* special case, no conversion */ + if (conv == NULL && *ep == '\0') + goto done; + ND("checking %s [%s]", arg, ep); + for (;conv->s; conv++) { + if (strchr(conv->s, *ep)) + goto done; + } +error: + *err = 1; /* unrecognised */ + return 0; + +done: + if (conv) { + ND("scale is %s %lf", conv->s, conv->m); + d *= conv->m; /* apply default conversion */ + } + ND("returning %lf", d); + return d; +} + +#define U_PARSE_ERR ~(0ULL) + +/* returns a value in nanoseconds */ +static uint64_t +parse_time(const char *arg) +{ + struct _sm a[] = { + {"", 1000000000 /* seconds */}, + {"n", 1 /* nanoseconds */}, {"u", 1000 /* microseconds */}, + {"m", 1000000 /* milliseconds */}, {"s", 1000000000 /* seconds */}, + {NULL, 0 /* seconds */} + }; + int err; + uint64_t ret = (uint64_t)parse_gen(arg, a, &err); + return err ? U_PARSE_ERR : ret; +} + + +/* + * parse a bandwidth, returns value in bps or U_PARSE_ERR if error. + */ +static uint64_t +parse_bw(const char *arg) +{ + struct _sm a[] = { + {"", 1}, {"kK", 1000}, {"mM", 1000000}, {"gG", 1000000000}, {NULL, 0} + }; + int err; + uint64_t ret = (uint64_t)parse_gen(arg, a, &err); + return err ? U_PARSE_ERR : ret; +} + + +/* + * For some function we need random bits. + * This is a wrapper to whatever function you want that returns + * 24 useful random bits. + */ + +#include /* log, exp etc. */ +static inline uint64_t +my_random24(void) /* 24 useful bits */ +{ + return random() & ((1<<24) - 1); +} + + +/*-------------- user-configuration -----------------*/ + +#if 0 /* start of comment block */ + +Here we place the functions to implement the various features +of the system. For each feature one should define a struct _cfg +(see at the beginning for definition) that refers a *_parse() function +to extract values from the command line, and a *_run() function +that is invoked on each packet to implement the desired function. + +Examples of the two functions are below. In general: + +- the *_parse() function takes argc/argv[], matches the function + name in argv[0], extracts the operating parameters, allocates memory + if needed, and stores them in the struct _cfg. + Return value is 2 if argv[0] is not recosnised, 1 if there is an + error in the arguments, 0 if all ok. + + On the command line, argv[] is a single, comma separated argument + that follow the specific option eg -D constant,20ms + + struct _cfg has some preallocated space (e.g an array of uint64_t) so simple + function can use that without having to allocate memory. + +- the *_run() function takes struct _q *q and struct _cfg *cfg as arguments. + *q contains all the informatio that may be possibly needed, including + those on the packet currently under processing. + The basic values are the following: + + char * cur_pkt points to the current packet (linear buffer) + uint32_t cur_len; length of the current packet + the functions are not supposed to modify these values + + int cur_drop; true if current packet must be dropped. + Must be set to non-zero by the loss emulation function + + uint64_t cur_delay; delay in nanoseconds for the current packet + Must be set by the delay emulation function + + More sophisticated functions may need to access other fields in *q, + see the structure description for that. + +When implementing a new function for a feature (e.g. for delay, +bandwidth, loss...) the struct _cfg should be added to the array +that contains all possible options. + + --- Specific notes --- + +DELAY emulation -D option_arguments + + If the option is not supplied, the system applies 0 extra delay + + The resolution for times is 1ns, the precision is load dependent and + generally in the order of 20-50us. + Times are in nanoseconds, can be followed by a character specifying + a different unit e.g. + + n nanoseconds + u microseconds + m milliseconds + s seconds + + Currently implemented options: + + constant,t constant delay equal to t + + uniform,tmin,tmax uniform delay between tmin and tmax + + exp,tavg,tmin exponential distribution with average tavg + and minimum tmin (corresponds to an exponential + distribution with argument 1/(tavg-tmin) ) + + +LOSS emulation -L option_arguments + + Loss is expressed as packet or bit error rate, which is an absolute + number between 0 and 1 (typically small). + + Currently implemented options + + plr,p uniform packet loss rate p, independent + of packet size + + burst,p,lmin,lmax burst loss with burst probability p and + burst length uniformly distributed between + lmin and lmax + + ber,p uniformly distributed bit error rate p, + so actual loss prob. depends on size. + +BANDWIDTH emulation -B option_arguments + + Bandwidths are expressed in bits per second, can be followed by a + character specifying a different unit e.g. + + b/B bits per second + k/K kbits/s (10^3 bits/s) + m/M mbits/s (10^6 bits/s) + g/G gbits/s (10^9 bits/s) + + Currently implemented options + + const,b constant bw, excluding mac framing + ether,b constant bw, including ethernet framing + (20 bytes framing + 4 bytes crc) + real,[scale] use real time, optionally with a scaling factor + +#endif /* end of comment block */ + +/* + * Configuration options for delay + */ + +/* constant delay, also accepts just a number */ +static int +const_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[]) +{ + uint64_t delay; + + (void)q; + if (strncmp(av[0], "const", 5) != 0 && ac > 1) + return 2; /* unrecognised */ + if (ac > 2) + return 1; /* error */ + delay = parse_time(av[ac - 1]); + if (delay == U_PARSE_ERR) + return 1; /* error */ + dst->d[0] = delay; + return 0; /* success */ +} + +/* runtime function, store the delay into q->cur_delay */ +static int +const_delay_run(struct _qs *q, struct _cfg *arg) +{ + q->cur_delay = arg->d[0]; /* the delay */ + return 0; +} + +static int +uniform_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[]) +{ + uint64_t dmin, dmax; + + (void)q; + if (strcmp(av[0], "uniform") != 0) + return 2; /* not recognised */ + if (ac != 3) + return 1; /* error */ + dmin = parse_time(av[1]); + dmax = parse_time(av[2]); + if (dmin == U_PARSE_ERR || dmax == U_PARSE_ERR || dmin > dmax) + return 1; + D("dmin %ld dmax %ld", (_P64)dmin, (_P64)dmax); + dst->d[0] = dmin; + dst->d[1] = dmax; + dst->d[2] = dmax - dmin; + return 0; +} + +static int +uniform_delay_run(struct _qs *q, struct _cfg *arg) +{ + uint64_t x = my_random24(); + q->cur_delay = arg->d[0] + ((arg->d[2] * x) >> 24); +#if 0 /* COMPUTE_STATS */ +#endif /* COMPUTE_STATS */ + return 0; +} + +/* + * exponential delay: Prob(delay = x) = exp(-x/d_av) + * gives a delay between 0 and infinity with average d_av + * The cumulative function is 1 - d_av exp(-x/d_av) + * + * The inverse function generates a uniform random number p in 0..1 + * and generates delay = (d_av-d_min) * -ln(1-p) + d_min + * + * To speed up behaviour at runtime we tabulate the values + */ + +static int +exp_delay_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[]) +{ +#define PTS_D_EXP 512 + uint64_t i, d_av, d_min, *t; /*table of values */ + + (void)q; + if (strcmp(av[0], "exp") != 0) + return 2; /* not recognised */ + if (ac != 3) + return 1; /* error */ + d_av = parse_time(av[1]); + d_min = parse_time(av[2]); + if (d_av == U_PARSE_ERR || d_min == U_PARSE_ERR || d_av < d_min) + return 1; /* error */ + d_av -= d_min; + dst->arg_len = PTS_D_EXP * sizeof(uint64_t); + dst->arg = calloc(1, dst->arg_len); + if (dst->arg == NULL) + return 1; /* no memory */ + t = (uint64_t *)dst->arg; + /* tabulate -ln(1-n)*delay for n in 0..1 */ + for (i = 0; i < PTS_D_EXP; i++) { + double d = -log2 ((double)(PTS_D_EXP - i) / PTS_D_EXP) * d_av + d_min; + t[i] = (uint64_t)d; + ND(5, "%ld: %le", i, d); + } + return 0; +} + +static int +exp_delay_run(struct _qs *q, struct _cfg *arg) +{ + uint64_t *t = (uint64_t *)arg->arg; + q->cur_delay = t[my_random24() & (PTS_D_EXP - 1)]; + RD(5, "delay %lu", (_P64)q->cur_delay); + return 0; +} + + +/* unused arguments in configuration */ +#define _CFG_END NULL, 0, {0}, {0} + +static struct _cfg delay_cfg[] = { + { const_delay_parse, const_delay_run, + "constant,delay", _CFG_END }, + { uniform_delay_parse, uniform_delay_run, + "uniform,dmin,dmax # dmin <= dmax", _CFG_END }, + { exp_delay_parse, exp_delay_run, + "exp,dmin,davg # dmin <= davg", _CFG_END }, + { NULL, NULL, NULL, _CFG_END } +}; + +/* standard bandwidth, also accepts just a number */ +static int +const_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[]) +{ + uint64_t bw; + + (void)q; + if (strncmp(av[0], "const", 5) != 0 && ac > 1) + return 2; /* unrecognised */ + if (ac > 2) + return 1; /* error */ + bw = parse_bw(av[ac - 1]); + if (bw == U_PARSE_ERR) { + return (ac == 2) ? 1 /* error */ : 2 /* unrecognised */; + } + dst->d[0] = bw; + return 0; /* success */ +} + + +/* runtime function, store the delay into q->cur_delay */ +static int +const_bw_run(struct _qs *q, struct _cfg *arg) +{ + uint64_t bps = arg->d[0]; + q->cur_tt = bps ? 8ULL* TIME_UNITS * q->cur_len / bps : 0 ; + return 0; +} + +/* ethernet bandwidth, add 672 bits per packet */ +static int +ether_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[]) +{ + uint64_t bw; + + (void)q; + if (strcmp(av[0], "ether") != 0) + return 2; /* unrecognised */ + if (ac != 2) + return 1; /* error */ + bw = parse_bw(av[ac - 1]); + if (bw == U_PARSE_ERR) + return 1; /* error */ + dst->d[0] = bw; + return 0; /* success */ +} + + +/* runtime function, add 20 bytes (framing) + 4 bytes (crc) */ +static int +ether_bw_run(struct _qs *q, struct _cfg *arg) +{ + uint64_t bps = arg->d[0]; + q->cur_tt = bps ? 8ULL * TIME_UNITS * (q->cur_len + 24) / bps : 0 ; + return 0; +} + +/* real bandwidth, plus scaling factor */ +static int +real_bw_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[]) +{ + double scale; + + (void)q; + if (strcmp(av[0], "real") != 0) + return 2; /* unrecognised */ + if (ac > 2) { /* second argument is optional */ + return 1; /* error */ + } else if (ac == 1) { + scale = 1; + } else { + int err = 0; + scale = parse_gen(av[ac-1], NULL, &err); + if (err || scale <= 0 || scale > 1000) + return 1; + } + ED("real -> scale is %.6f", scale); + dst->f[0] = scale; + return 0; /* success */ +} + +static int +real_bw_run(struct _qs *q, struct _cfg *arg) +{ + q->cur_tt /= arg->f[0]; + return 0; +} + +static struct _cfg bw_cfg[] = { + { const_bw_parse, const_bw_run, + "constant,bps", _CFG_END }, + { ether_bw_parse, ether_bw_run, + "ether,bps", _CFG_END }, + { real_bw_parse, real_bw_run, + "real,scale", _CFG_END }, + { NULL, NULL, NULL, _CFG_END } +}; + +/* + * loss patterns + */ +static int +const_plr_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[]) +{ + double plr; + int err; + + (void)q; + if (strcmp(av[0], "plr") != 0 && ac > 1) + return 2; /* unrecognised */ + if (ac > 2) + return 1; /* error */ + // XXX to be completed + plr = parse_gen(av[ac-1], NULL, &err); + if (err || plr < 0 || plr > 1) + return 1; + dst->d[0] = plr * (1<<24); /* scale is 16m */ + if (plr != 0 && dst->d[0] == 0) + ED("WWW warning, rounding %le down to 0", plr); + return 0; /* success */ +} + +static int +const_plr_run(struct _qs *q, struct _cfg *arg) +{ + (void)arg; + uint64_t r = my_random24(); + q->cur_drop = r < arg->d[0]; +#if 1 /* keep stats */ + arg->d[1]++; + arg->d[2] += q->cur_drop; +#endif + return 0; +} + + +/* + * For BER the loss is 1- (1-ber)**bit_len + * The linear approximation is only good for small values, so we + * tabulate (1-ber)**len for various sizes in bytes + */ +static int +const_ber_parse(struct _qs *q, struct _cfg *dst, int ac, char *av[]) +{ + double ber, ber8, cur; + int i, err; + uint32_t *plr; + const uint32_t mask = (1<<24) - 1; + + (void)q; + if (strcmp(av[0], "ber") != 0) + return 2; /* unrecognised */ + if (ac != 2) + return 1; /* error */ + ber = parse_gen(av[ac-1], NULL, &err); + if (err || ber < 0 || ber > 1) + return 1; + dst->arg_len = MAX_PKT * sizeof(uint32_t); + plr = calloc(1, dst->arg_len); + if (plr == NULL) + return 1; /* no memory */ + dst->arg = plr; + ber8 = 1 - ber; + ber8 *= ber8; /* **2 */ + ber8 *= ber8; /* **4 */ + ber8 *= ber8; /* **8 */ + cur = 1; + for (i=0; i < MAX_PKT; i++, cur *= ber8) { + plr[i] = (mask + 1)*(1 - cur); + if (plr[i] > mask) + plr[i] = mask; +#if 0 + if (i>= 60) // && plr[i] < mask/2) + RD(50,"%4d: %le %ld", i, 1.0 - cur, (_P64)plr[i]); +#endif + } + dst->d[0] = ber * (mask + 1); + return 0; /* success */ +} + +static int +const_ber_run(struct _qs *q, struct _cfg *arg) +{ + int l = q->cur_len; + uint64_t r = my_random24(); + uint32_t *plr = arg->arg; + + if (l >= MAX_PKT) { + RD(5, "pkt len %d too large, trim to %d", l, MAX_PKT-1); + l = MAX_PKT-1; + } + q->cur_drop = r < plr[l]; +#if 1 /* keep stats */ + arg->d[1] += l * 8; + arg->d[2] += q->cur_drop; +#endif + return 0; +} + +static struct _cfg loss_cfg[] = { + { const_plr_parse, const_plr_run, + "plr,prob # 0 <= prob <= 1", _CFG_END }, + { const_ber_parse, const_ber_run, + "ber,prob # 0 <= prob <= 1", _CFG_END }, + { NULL, NULL, NULL, _CFG_END } +}; diff --git a/tools/tools/netmap/pkt-gen.c b/tools/tools/netmap/pkt-gen.c index 6d9bee6de634..168e022cfba9 100644 --- a/tools/tools/netmap/pkt-gen.c +++ b/tools/tools/netmap/pkt-gen.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2011-2014 Matteo Landi, Luigi Rizzo. All rights reserved. - * Copyright (C) 2013-2014 Universita` di Pisa. All rights reserved. + * Copyright (C) 2013-2015 Universita` di Pisa. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,8 +37,6 @@ * */ -// #define TRASH_VHOST_HDR - #define _GNU_SOURCE /* for CPU_SET() */ #include #define NETMAP_WITH_LIBS @@ -49,12 +47,16 @@ #include // sysconf() #include #include /* ntohs */ +#ifndef _WIN32 #include /* sysctl */ +#endif #include /* getifaddrs */ #include #include #include #include +#include +#include #include @@ -62,6 +64,69 @@ #include #endif +#include "ctrs.h" + +#ifdef _WIN32 +#define cpuset_t DWORD_PTR //uint64_t +static inline void CPU_ZERO(cpuset_t *p) +{ + *p = 0; +} + +static inline void CPU_SET(uint32_t i, cpuset_t *p) +{ + *p |= 1<< (i & 0x3f); +} + +#define pthread_setaffinity_np(a, b, c) !SetThreadAffinityMask(a, *c) //((void)a, 0) +#define TAP_CLONEDEV "/dev/tap" +#define AF_LINK 18 //defined in winsocks.h +#define CLOCK_REALTIME_PRECISE CLOCK_REALTIME +#include + +/* + * Convert an ASCII representation of an ethernet address to + * binary form. + */ +struct ether_addr * +ether_aton(const char *a) +{ + int i; + static struct ether_addr o; + unsigned int o0, o1, o2, o3, o4, o5; + + i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5); + + if (i != 6) + return (NULL); + + o.octet[0]=o0; + o.octet[1]=o1; + o.octet[2]=o2; + o.octet[3]=o3; + o.octet[4]=o4; + o.octet[5]=o5; + + return ((struct ether_addr *)&o); +} + +/* + * Convert a binary representation of an ethernet address to + * an ASCII string. + */ +char * +ether_ntoa(const struct ether_addr *n) +{ + int i; + static char a[18]; + + i = sprintf(a, "%02x:%02x:%02x:%02x:%02x:%02x", + n->octet[0], n->octet[1], n->octet[2], + n->octet[3], n->octet[4], n->octet[5]); + return (i < 17 ? NULL : (char *)&a); +} +#endif /* _WIN32 */ + #ifdef linux #define cpuset_t cpu_set_t @@ -169,10 +234,12 @@ struct glob_arg { int pkt_size; int burst; int forever; - int npackets; /* total packets to send */ + uint64_t npackets; /* total packets to send */ int frags; /* fragments per packet */ int nthreads; - int cpus; + int cpus; /* cpus used for running */ + int system_cpus; /* cpus on the system */ + int options; /* testing */ #define OPT_PREFETCH 1 #define OPT_ACCESS 2 @@ -181,10 +248,10 @@ struct glob_arg { #define OPT_TS 16 /* add a timestamp */ #define OPT_INDIRECT 32 /* use indirect buffers, tx only */ #define OPT_DUMP 64 /* dump rx/tx traffic */ -#define OPT_MONITOR_TX 128 -#define OPT_MONITOR_RX 256 +#define OPT_RUBBISH 256 /* send wathever the buffers contain */ #define OPT_RANDOM_SRC 512 #define OPT_RANDOM_DST 1024 +#define OPT_PPS_STATS 2048 int dev_type; #ifndef NO_PCAP pcap_t *p; @@ -198,13 +265,18 @@ struct glob_arg { struct nm_desc *nmd; int report_interval; /* milliseconds between prints */ void *(*td_body)(void *); + int td_type; void *mmap_addr; char ifname[MAX_IFNAMELEN]; char *nmr_config; int dummy_send; int virt_header; /* send also the virt_header */ int extra_bufs; /* goes in nr_arg3 */ + int extra_pipes; /* goes in nr_arg1 */ char *packet_file; /* -P option */ +#define STATS_WIN 15 + int win_idx; + int64_t win[STATS_WIN]; }; enum dev_type { DEV_NONE, DEV_NETMAP, DEV_PCAP, DEV_TAP }; @@ -220,7 +292,11 @@ struct targ { int cancel; int fd; struct nm_desc *nmd; - volatile uint64_t count; + /* these ought to be volatile, but they are + * only sampled and errors should not accumulate + */ + struct my_ctrs ctr; + struct timespec tic, toc; int me; pthread_t thread; @@ -327,11 +403,10 @@ sigint_h(int sig) int i; (void)sig; /* UNUSED */ - D("received control-C on thread %p", pthread_self()); + D("received control-C on thread %p", (void *)pthread_self()); for (i = 0; i < global_nthreads; i++) { targs[i].cancel = 1; } - signal(SIGINT, SIG_DFL); } /* sysctl wrapper to return the number of active CPUs */ @@ -345,6 +420,12 @@ system_ncpus(void) sysctl(mib, 2, &ncpus, &len, NULL, 0); #elif defined(linux) ncpus = sysconf(_SC_NPROCESSORS_ONLN); +#elif defined(_WIN32) + { + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + ncpus = sysinfo.dwNumberOfProcessors; + } #else /* others */ ncpus = 1; #endif /* others */ @@ -518,10 +599,11 @@ wrapsum(u_int32_t sum) * Look for consecutive ascii representations of the size of the packet. */ static void -dump_payload(char *p, int len, struct netmap_ring *ring, int cur) +dump_payload(const char *_p, int len, struct netmap_ring *ring, int cur) { char buf[128]; int i, j, i0; + const unsigned char *p = (const unsigned char *)_p; /* get the length in ASCII of the length of the packet. */ @@ -629,6 +711,7 @@ initialize_packet(struct targ *targ) indirect_payload : default_payload; int i, l0 = strlen(payload); +#ifndef NO_PCAP char errbuf[PCAP_ERRBUF_SIZE]; pcap_t *file; struct pcap_pkthdr *header; @@ -650,6 +733,7 @@ initialize_packet(struct targ *targ) pcap_close(file); return; } +#endif /* create a nice NUL-terminated string */ for (i = 0; i < paylen; i += l0) { @@ -695,35 +779,49 @@ initialize_packet(struct targ *targ) eh->ether_type = htons(ETHERTYPE_IP); bzero(&pkt->vh, sizeof(pkt->vh)); -#ifdef TRASH_VHOST_HDR - /* set bogus content */ - pkt->vh.fields[0] = 0xff; - pkt->vh.fields[1] = 0xff; - pkt->vh.fields[2] = 0xff; - pkt->vh.fields[3] = 0xff; - pkt->vh.fields[4] = 0xff; - pkt->vh.fields[5] = 0xff; -#endif /* TRASH_VHOST_HDR */ // dump_payload((void *)pkt, targ->g->pkt_size, NULL, 0); } static void -set_vnet_hdr_len(struct targ *t) +get_vnet_hdr_len(struct glob_arg *g) { - int err, l = t->g->virt_header; + struct nmreq req; + int err; + + memset(&req, 0, sizeof(req)); + bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name)); + req.nr_version = NETMAP_API; + req.nr_cmd = NETMAP_VNET_HDR_GET; + err = ioctl(g->main_fd, NIOCREGIF, &req); + if (err) { + D("Unable to get virtio-net header length"); + return; + } + + g->virt_header = req.nr_arg1; + if (g->virt_header) { + D("Port requires virtio-net header, length = %d", + g->virt_header); + } +} + +static void +set_vnet_hdr_len(struct glob_arg *g) +{ + int err, l = g->virt_header; struct nmreq req; if (l == 0) return; memset(&req, 0, sizeof(req)); - bcopy(t->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name)); + bcopy(g->nmd->req.nr_name, req.nr_name, sizeof(req.nr_name)); req.nr_version = NETMAP_API; req.nr_cmd = NETMAP_BDG_VNET_HDR; req.nr_arg1 = l; - err = ioctl(t->fd, NIOCREGIF, &req); + err = ioctl(g->main_fd, NIOCREGIF, &req); if (err) { - D("Unable to set vnet header length %d", l); + D("Unable to set virtio-net header length %d", l); } } @@ -763,12 +861,15 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, for (fcnt = nfrags, sent = 0; sent < count; sent++) { struct netmap_slot *slot = &ring->slot[cur]; char *p = NETMAP_BUF(ring, slot->buf_idx); + int buf_changed = slot->flags & NS_BUF_CHANGED; slot->flags = 0; - if (options & OPT_INDIRECT) { + if (options & OPT_RUBBISH) { + /* do nothing */ + } else if (options & OPT_INDIRECT) { slot->flags |= NS_INDIRECT; - slot->ptr = (uint64_t)frame; - } else if (options & OPT_COPY) { + slot->ptr = (uint64_t)((uintptr_t)frame); + } else if ((options & OPT_COPY) || buf_changed) { nm_pkt_copy(frame, p, size); if (fcnt == nfrags) update_addresses(pkt, g); @@ -797,6 +898,21 @@ send_packets(struct netmap_ring *ring, struct pkt *pkt, void *frame, return (sent); } +/* + * Index of the highest bit set + */ +uint32_t +msb64(uint64_t x) +{ + uint64_t m = 1ULL << 63; + int i; + + for (i = 63; i >= 0; i--, m >>=1) + if (m & x) + return i; + return 0; +} + /* * Send a packet, and wait for a response. * The payload (after UDP header, ofs 42) has a 4-byte sequence @@ -810,25 +926,28 @@ pinger_body(void *data) struct targ *targ = (struct targ *) data; struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; struct netmap_if *nifp = targ->nmd->nifp; - int i, rx = 0, n = targ->g->npackets; + int i, rx = 0; void *frame; int size; - uint32_t sent = 0; struct timespec ts, now, last_print; - uint32_t count = 0, min = 1000000000, av = 0; + uint64_t sent = 0, n = targ->g->npackets; + uint64_t count = 0, t_cur, t_min = ~0, av = 0; + uint64_t buckets[64]; /* bins for delays, ns */ frame = &targ->pkt; frame += sizeof(targ->pkt.vh) - targ->g->virt_header; size = targ->g->pkt_size + targ->g->virt_header; + if (targ->g->nthreads > 1) { D("can only ping with 1 thread"); return NULL; } + bzero(&buckets, sizeof(buckets)); clock_gettime(CLOCK_REALTIME_PRECISE, &last_print); now = last_print; - while (n == 0 || (int)sent < n) { + while (!targ->cancel && (n == 0 || sent < n)) { struct netmap_ring *ring = NETMAP_TXRING(nifp, 0); struct netmap_slot *slot; char *p; @@ -864,6 +983,8 @@ pinger_body(void *data) while (!nm_ring_empty(ring)) { uint32_t seq; struct tstamp *tp; + int pos; + slot = &ring->slot[ring->cur]; p = NETMAP_BUF(ring, slot->buf_idx); @@ -878,12 +999,16 @@ pinger_body(void *data) ts.tv_nsec += 1000000000; ts.tv_sec--; } - if (1) D("seq %d/%d delta %d.%09d", seq, sent, + if (0) D("seq %d/%lu delta %d.%09d", seq, sent, (int)ts.tv_sec, (int)ts.tv_nsec); - if (ts.tv_nsec < (int)min) - min = ts.tv_nsec; + t_cur = ts.tv_sec * 1000000000UL + ts.tv_nsec; + if (t_cur < t_min) + t_min = t_cur; count ++; - av += ts.tv_nsec; + av += t_cur; + pos = msb64(t_cur); + buckets[pos]++; + /* now store it in a bucket */ ring->head = ring->cur = nm_ring_next(ring, ring->cur); rx++; } @@ -897,14 +1022,32 @@ pinger_body(void *data) ts.tv_sec--; } if (ts.tv_sec >= 1) { - D("count %d min %d av %d", - count, min, av/count); + D("count %d RTT: min %d av %d ns", + (int)count, (int)t_min, (int)(av/count)); + int k, j, kmin; + char buf[512]; + + for (kmin = 0; kmin < 64; kmin ++) + if (buckets[kmin]) + break; + for (k = 63; k >= kmin; k--) + if (buckets[k]) + break; + buf[0] = '\0'; + for (j = kmin; j <= k; j++) + sprintf(buf, "%s %5d", buf, (int)buckets[j]); + D("k: %d .. %d\n\t%s", 1<used = 0; + return NULL; } @@ -919,14 +1062,15 @@ ponger_body(void *data) struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; struct netmap_if *nifp = targ->nmd->nifp; struct netmap_ring *txring, *rxring; - int i, rx = 0, sent = 0, n = targ->g->npackets; + int i, rx = 0; + uint64_t sent = 0, n = targ->g->npackets; if (targ->g->nthreads > 1) { D("can only reply ping with 1 thread"); return NULL; } - D("understood ponger %d but don't know how to do it", n); - while (n == 0 || sent < n) { + D("understood ponger %lu but don't know how to do it", n); + while (!targ->cancel && (n == 0 || sent < n)) { uint32_t txcur, txavail; //#define BUSYWAIT #ifdef BUSYWAIT @@ -975,71 +1119,19 @@ ponger_body(void *data) } } txring->head = txring->cur = txcur; - targ->count = sent; + targ->ctr.pkts = sent; #ifdef BUSYWAIT ioctl(pfd.fd, NIOCTXSYNC, NULL); #endif //D("tx %d rx %d", sent, rx); } + + /* reset the ``used`` flag. */ + targ->used = 0; + return NULL; } -static __inline int -timespec_ge(const struct timespec *a, const struct timespec *b) -{ - - if (a->tv_sec > b->tv_sec) - return (1); - if (a->tv_sec < b->tv_sec) - return (0); - if (a->tv_nsec >= b->tv_nsec) - return (1); - return (0); -} - -static __inline struct timespec -timeval2spec(const struct timeval *a) -{ - struct timespec ts = { - .tv_sec = a->tv_sec, - .tv_nsec = a->tv_usec * 1000 - }; - return ts; -} - -static __inline struct timeval -timespec2val(const struct timespec *a) -{ - struct timeval tv = { - .tv_sec = a->tv_sec, - .tv_usec = a->tv_nsec / 1000 - }; - return tv; -} - - -static __inline struct timespec -timespec_add(struct timespec a, struct timespec b) -{ - struct timespec ret = { a.tv_sec + b.tv_sec, a.tv_nsec + b.tv_nsec }; - if (ret.tv_nsec >= 1000000000) { - ret.tv_sec++; - ret.tv_nsec -= 1000000000; - } - return ret; -} - -static __inline struct timespec -timespec_sub(struct timespec a, struct timespec b) -{ - struct timespec ret = { a.tv_sec - b.tv_sec, a.tv_nsec - b.tv_nsec }; - if (ret.tv_nsec < 0) { - ret.tv_sec--; - ret.tv_nsec += 1000000000; - } - return ret; -} - /* * wait until ts, either busy or sleeping if more than 1ms. @@ -1065,9 +1157,11 @@ sender_body(void *data) struct targ *targ = (struct targ *) data; struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT }; struct netmap_if *nifp; - struct netmap_ring *txring; - int i, n = targ->g->npackets / targ->g->nthreads; - int64_t sent = 0; + struct netmap_ring *txring = NULL; + int i; + uint64_t n = targ->g->npackets / targ->g->nthreads; + uint64_t sent = 0; + uint64_t event = 0; int options = targ->g->options | OPT_COPY; struct timespec nexttime = { 0, 0}; // XXX silence compiler int rate_limit = targ->g->tx_rate; @@ -1104,7 +1198,9 @@ sender_body(void *data) sent++; update_addresses(pkt, targ->g); if (i > 10000) { - targ->count = sent; + targ->ctr.pkts = sent; + targ->ctr.bytes = sent*size; + targ->ctr.events = sent; i = 0; } } @@ -1117,7 +1213,9 @@ sender_body(void *data) sent++; update_addresses(pkt, targ->g); if (i > 10000) { - targ->count = sent; + targ->ctr.pkts = sent; + targ->ctr.bytes = sent*size; + targ->ctr.events = sent; i = 0; } } @@ -1126,7 +1224,7 @@ sender_body(void *data) int tosend = 0; int frags = targ->g->frags; - nifp = targ->nmd->nifp; + nifp = targ->nmd->nifp; while (!targ->cancel && (n == 0 || sent < n)) { if (rate_limit && tosend <= 0) { @@ -1138,6 +1236,13 @@ sender_body(void *data) /* * wait for available room in the send queue(s) */ +#ifdef BUSYWAIT + if (ioctl(pfd.fd, NIOCTXSYNC, NULL) < 0) { + D("ioctl error on queue %d: %s", targ->me, + strerror(errno)); + goto quit; + } +#else /* !BUSYWAIT */ if (poll(&pfd, 1, 2000) <= 0) { if (targ->cancel) break; @@ -1146,9 +1251,11 @@ sender_body(void *data) // goto quit; } if (pfd.revents & POLLERR) { - D("poll error"); + D("poll error on %d ring %d-%d", pfd.fd, + targ->nmd->first_tx_ring, targ->nmd->last_tx_ring); goto quit; } +#endif /* !BUSYWAIT */ /* * scan our queues and send on those with room */ @@ -1157,7 +1264,8 @@ sender_body(void *data) options &= ~OPT_COPY; } for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { - int m, limit = rate_limit ? tosend : targ->g->burst; + int m; + uint64_t limit = rate_limit ? tosend : targ->g->burst; if (n > 0 && n - sent < limit) limit = n - sent; txring = NETMAP_TXRING(nifp, i); @@ -1171,7 +1279,11 @@ sender_body(void *data) ND("limit %d tail %d frags %d m %d", limit, txring->tail, frags, m); sent += m; - targ->count = sent; + if (m > 0) //XXX-ste: can m be 0? + event++; + targ->ctr.pkts = sent; + targ->ctr.bytes = sent*size; + targ->ctr.events = event; if (rate_limit) { tosend -= m; if (tosend <= 0) @@ -1182,13 +1294,13 @@ sender_body(void *data) /* flush any remaining packets */ D("flush tail %d head %d on thread %p", txring->tail, txring->head, - pthread_self()); + (void *)pthread_self()); ioctl(pfd.fd, NIOCTXSYNC, NULL); /* final part: wait all the TX queues to be empty. */ for (i = targ->nmd->first_tx_ring; i <= targ->nmd->last_tx_ring; i++) { txring = NETMAP_TXRING(nifp, i); - while (nm_tx_pending(txring)) { + while (!targ->cancel && nm_tx_pending(txring)) { RD(5, "pending tx tail %d head %d on ring %d", txring->tail, txring->head, i); ioctl(pfd.fd, NIOCTXSYNC, NULL); @@ -1199,8 +1311,9 @@ sender_body(void *data) clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); targ->completed = 1; - targ->count = sent; - + targ->ctr.pkts = sent; + targ->ctr.bytes = sent*size; + targ->ctr.events = event; quit: /* reset the ``used`` flag. */ targ->used = 0; @@ -1214,17 +1327,22 @@ static void receive_pcap(u_char *user, const struct pcap_pkthdr * h, const u_char * bytes) { - int *count = (int *)user; - (void)h; /* UNUSED */ + struct my_ctrs *ctr = (struct my_ctrs *)user; (void)bytes; /* UNUSED */ - (*count)++; + ctr->bytes += h->len; + ctr->pkts++; } #endif /* !NO_PCAP */ + static int -receive_packets(struct netmap_ring *ring, u_int limit, int dump) +receive_packets(struct netmap_ring *ring, u_int limit, int dump, uint64_t *bytes) { u_int cur, rx, n; + uint64_t b = 0; + + if (bytes == NULL) + bytes = &b; cur = ring->cur; n = nm_ring_space(ring); @@ -1234,6 +1352,7 @@ receive_packets(struct netmap_ring *ring, u_int limit, int dump) struct netmap_slot *slot = &ring->slot[cur]; char *p = NETMAP_BUF(ring, slot->buf_idx); + *bytes += slot->len; if (dump) dump_payload(p, slot->len, ring, cur); @@ -1252,7 +1371,10 @@ receiver_body(void *data) struct netmap_if *nifp; struct netmap_ring *rxring; int i; - uint64_t received = 0; + struct my_ctrs cur; + + cur.pkts = cur.bytes = cur.events = cur.min_space = 0; + cur.t.tv_usec = cur.t.tv_sec = 0; // unused, just silence the compiler if (setaffinity(targ->thread, targ->affinity)) goto quit; @@ -1273,22 +1395,319 @@ receiver_body(void *data) while (!targ->cancel) { char buf[MAX_BODYSIZE]; /* XXX should we poll ? */ - if (read(targ->g->main_fd, buf, sizeof(buf)) > 0) - targ->count++; + i = read(targ->g->main_fd, buf, sizeof(buf)); + if (i > 0) { + targ->ctr.pkts++; + targ->ctr.bytes += i; + targ->ctr.events++; + } } #ifndef NO_PCAP } else if (targ->g->dev_type == DEV_PCAP) { while (!targ->cancel) { /* XXX should we poll ? */ pcap_dispatch(targ->g->p, targ->g->burst, receive_pcap, - (u_char *)&targ->count); + (u_char *)&targ->ctr); + targ->ctr.events++; } #endif /* !NO_PCAP */ } else { int dump = targ->g->options & OPT_DUMP; - nifp = targ->nmd->nifp; + nifp = targ->nmd->nifp; while (!targ->cancel) { + /* Once we started to receive packets, wait at most 1 seconds + before quitting. */ +#ifdef BUSYWAIT + if (ioctl(pfd.fd, NIOCRXSYNC, NULL) < 0) { + D("ioctl error on queue %d: %s", targ->me, + strerror(errno)); + goto quit; + } +#else /* !BUSYWAIT */ + if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) { + clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); + targ->toc.tv_sec -= 1; /* Subtract timeout time. */ + goto out; + } + + if (pfd.revents & POLLERR) { + D("poll err"); + goto quit; + } +#endif /* !BUSYWAIT */ + uint64_t cur_space = 0; + for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { + int m; + + rxring = NETMAP_RXRING(nifp, i); + /* compute free space in the ring */ + m = rxring->head + rxring->num_slots - rxring->tail; + if (m >= (int) rxring->num_slots) + m -= rxring->num_slots; + cur_space += m; + if (nm_ring_empty(rxring)) + continue; + + m = receive_packets(rxring, targ->g->burst, dump, &cur.bytes); + cur.pkts += m; + if (m > 0) //XXX-ste: can m be 0? + cur.events++; + } + cur.min_space = targ->ctr.min_space; + if (cur_space < cur.min_space) + cur.min_space = cur_space; + targ->ctr = cur; + } + } + + clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); + +#if !defined(BUSYWAIT) +out: +#endif + targ->completed = 1; + targ->ctr = cur; + +quit: + /* reset the ``used`` flag. */ + targ->used = 0; + + return (NULL); +} + +static void * +txseq_body(void *data) +{ + struct targ *targ = (struct targ *) data; + struct pollfd pfd = { .fd = targ->fd, .events = POLLOUT }; + struct netmap_ring *ring; + int64_t sent = 0; + uint64_t event = 0; + int options = targ->g->options | OPT_COPY; + struct timespec nexttime = {0, 0}; + int rate_limit = targ->g->tx_rate; + struct pkt *pkt = &targ->pkt; + int frags = targ->g->frags; + uint32_t sequence = 0; + int budget = 0; + void *frame; + int size; + + if (targ->g->nthreads > 1) { + D("can only txseq ping with 1 thread"); + return NULL; + } + + if (targ->g->npackets > 0) { + D("Ignoring -n argument"); + } + + frame = pkt; + frame += sizeof(pkt->vh) - targ->g->virt_header; + size = targ->g->pkt_size + targ->g->virt_header; + + D("start, fd %d main_fd %d", targ->fd, targ->g->main_fd); + if (setaffinity(targ->thread, targ->affinity)) + goto quit; + + clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); + if (rate_limit) { + targ->tic = timespec_add(targ->tic, (struct timespec){2,0}); + targ->tic.tv_nsec = 0; + wait_time(targ->tic); + nexttime = targ->tic; + } + + /* Only use the first queue. */ + ring = NETMAP_TXRING(targ->nmd->nifp, targ->nmd->first_tx_ring); + + while (!targ->cancel) { + int64_t limit; + unsigned int space; + unsigned int head; + int fcnt; + + if (!rate_limit) { + budget = targ->g->burst; + + } else if (budget <= 0) { + budget = targ->g->burst; + nexttime = timespec_add(nexttime, targ->g->tx_period); + wait_time(nexttime); + } + + /* wait for available room in the send queue */ + if (poll(&pfd, 1, 2000) <= 0) { + if (targ->cancel) + break; + D("poll error/timeout on queue %d: %s", targ->me, + strerror(errno)); + } + if (pfd.revents & POLLERR) { + D("poll error on %d ring %d-%d", pfd.fd, + targ->nmd->first_tx_ring, targ->nmd->last_tx_ring); + goto quit; + } + + /* If no room poll() again. */ + space = nm_ring_space(ring); + if (!space) { + continue; + } + + limit = budget; + + if (space < limit) { + limit = space; + } + + /* Cut off ``limit`` to make sure is multiple of ``frags``. */ + if (frags > 1) { + limit = (limit / frags) * frags; + } + + limit = sent + limit; /* Convert to absolute. */ + + for (fcnt = frags, head = ring->head; + sent < limit; sent++, sequence++) { + struct netmap_slot *slot = &ring->slot[head]; + char *p = NETMAP_BUF(ring, slot->buf_idx); + + slot->flags = 0; + pkt->body[0] = sequence >> 24; + pkt->body[1] = (sequence >> 16) & 0xff; + pkt->body[2] = (sequence >> 8) & 0xff; + pkt->body[3] = sequence & 0xff; + nm_pkt_copy(frame, p, size); + if (fcnt == frags) { + update_addresses(pkt, targ->g); + } + + if (options & OPT_DUMP) { + dump_payload(p, size, ring, head); + } + + slot->len = size; + + if (--fcnt > 0) { + slot->flags |= NS_MOREFRAG; + } else { + fcnt = frags; + } + + if (sent == limit - 1) { + /* Make sure we don't push an incomplete + * packet. */ + assert(!(slot->flags & NS_MOREFRAG)); + slot->flags |= NS_REPORT; + } + + head = nm_ring_next(ring, head); + if (rate_limit) { + budget--; + } + } + + ring->cur = ring->head = head; + + event ++; + targ->ctr.pkts = sent; + targ->ctr.bytes = sent * size; + targ->ctr.events = event; + } + + /* flush any remaining packets */ + D("flush tail %d head %d on thread %p", + ring->tail, ring->head, + (void *)pthread_self()); + ioctl(pfd.fd, NIOCTXSYNC, NULL); + + /* final part: wait the TX queues to become empty. */ + while (!targ->cancel && nm_tx_pending(ring)) { + RD(5, "pending tx tail %d head %d on ring %d", + ring->tail, ring->head, targ->nmd->first_tx_ring); + ioctl(pfd.fd, NIOCTXSYNC, NULL); + usleep(1); /* wait 1 tick */ + } + + clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); + targ->completed = 1; + targ->ctr.pkts = sent; + targ->ctr.bytes = sent * size; + targ->ctr.events = event; +quit: + /* reset the ``used`` flag. */ + targ->used = 0; + + return (NULL); +} + + +static char * +multi_slot_to_string(struct netmap_ring *ring, unsigned int head, + unsigned int nfrags, char *strbuf, size_t strbuflen) +{ + unsigned int f; + char *ret = strbuf; + + for (f = 0; f < nfrags; f++) { + struct netmap_slot *slot = &ring->slot[head]; + int m = snprintf(strbuf, strbuflen, "|%u,%x|", slot->len, + slot->flags); + if (m >= (int)strbuflen) { + break; + } + strbuf += m; + strbuflen -= m; + + head = nm_ring_next(ring, head); + } + + return ret; +} + +static void * +rxseq_body(void *data) +{ + struct targ *targ = (struct targ *) data; + struct pollfd pfd = { .fd = targ->fd, .events = POLLIN }; + int dump = targ->g->options & OPT_DUMP; + struct netmap_ring *ring; + unsigned int frags_exp = 1; + uint32_t seq_exp = 0; + struct my_ctrs cur; + unsigned int frags = 0; + int first_packet = 1; + int first_slot = 1; + int i; + + cur.pkts = cur.bytes = cur.events = cur.min_space = 0; + cur.t.tv_usec = cur.t.tv_sec = 0; // unused, just silence the compiler + + if (setaffinity(targ->thread, targ->affinity)) + goto quit; + + D("reading from %s fd %d main_fd %d", + targ->g->ifname, targ->fd, targ->g->main_fd); + /* unbounded wait for the first packet. */ + for (;!targ->cancel;) { + i = poll(&pfd, 1, 1000); + if (i > 0 && !(pfd.revents & POLLERR)) + break; + RD(1, "waiting for initial packets, poll returns %d %d", + i, pfd.revents); + } + + clock_gettime(CLOCK_REALTIME_PRECISE, &targ->tic); + + ring = NETMAP_RXRING(targ->nmd->nifp, targ->nmd->first_rx_ring); + + while (!targ->cancel) { + unsigned int head; + uint32_t seq; + int limit; + /* Once we started to receive packets, wait at most 1 seconds before quitting. */ if (poll(&pfd, 1, 1 * 1000) <= 0 && !targ->g->forever) { @@ -1302,25 +1721,105 @@ receiver_body(void *data) goto quit; } - for (i = targ->nmd->first_rx_ring; i <= targ->nmd->last_rx_ring; i++) { - int m; + if (nm_ring_empty(ring)) + continue; - rxring = NETMAP_RXRING(nifp, i); - if (nm_ring_empty(rxring)) - continue; + limit = nm_ring_space(ring); + if (limit > targ->g->burst) + limit = targ->g->burst; - m = receive_packets(rxring, targ->g->burst, dump); - received += m; +#if 0 + /* Enable this if + * 1) we remove the early-return optimization from + * the netmap poll implementation, or + * 2) pipes get NS_MOREFRAG support. + * With the current netmap implementation, an experiment like + * pkt-gen -i vale:1{1 -f txseq -F 9 + * pkt-gen -i vale:1}1 -f rxseq + * would get stuck as soon as we find nm_ring_space(ring) < 9, + * since here limit is rounded to 0 and + * pipe rxsync is not called anymore by the poll() of this loop. + */ + if (frags_exp > 1) { + int o = limit; + /* Cut off to the closest smaller multiple. */ + limit = (limit / frags_exp) * frags_exp; + RD(2, "LIMIT %d --> %d", o, limit); } - targ->count = received; +#endif + + for (head = ring->head, i = 0; i < limit; i++) { + struct netmap_slot *slot = &ring->slot[head]; + char *p = NETMAP_BUF(ring, slot->buf_idx); + int len = slot->len; + struct pkt *pkt; + + if (dump) { + dump_payload(p, slot->len, ring, head); + } + + frags++; + if (!(slot->flags & NS_MOREFRAG)) { + if (first_packet) { + first_packet = 0; + } else if (frags != frags_exp) { + char prbuf[512]; + RD(1, "Received packets with %u frags, " + "expected %u, '%s'", frags, frags_exp, + multi_slot_to_string(ring, head-frags+1, frags, + prbuf, sizeof(prbuf))); + } + first_packet = 0; + frags_exp = frags; + frags = 0; + } + + p -= sizeof(pkt->vh) - targ->g->virt_header; + len += sizeof(pkt->vh) - targ->g->virt_header; + pkt = (struct pkt *)p; + + if ((char *)pkt + len < ((char *)pkt->body) + sizeof(seq)) { + RD(1, "%s: packet too small (len=%u)", __func__, + slot->len); + } else { + seq = (pkt->body[0] << 24) | (pkt->body[1] << 16) + | (pkt->body[2] << 8) | pkt->body[3]; + if (first_slot) { + /* Grab the first one, whatever it + is. */ + seq_exp = seq; + first_slot = 0; + } else if (seq != seq_exp) { + uint32_t delta = seq - seq_exp; + + if (delta < (0xFFFFFFFF >> 1)) { + RD(2, "Sequence GAP: exp %u found %u", + seq_exp, seq); + } else { + RD(2, "Sequence OUT OF ORDER: " + "exp %u found %u", seq_exp, seq); + } + seq_exp = seq; + } + seq_exp++; + } + + cur.bytes += slot->len; + head = nm_ring_next(ring, head); + cur.pkts++; + } + + ring->cur = ring->head = head; + + cur.events++; + targ->ctr = cur; } - } clock_gettime(CLOCK_REALTIME_PRECISE, &targ->toc); out: targ->completed = 1; - targ->count = received; + targ->ctr = cur; quit: /* reset the ``used`` flag. */ @@ -1329,56 +1828,38 @@ receiver_body(void *data) return (NULL); } -/* very crude code to print a number in normalized form. - * Caller has to make sure that the buffer is large enough. - */ -static const char * -norm(char *buf, double val) -{ - char *units[] = { "", "K", "M", "G", "T" }; - u_int i; - - for (i = 0; val >=1000 && i < sizeof(units)/sizeof(char *) - 1; i++) - val /= 1000; - sprintf(buf, "%.2f %s", val, units[i]); - return buf; -} static void -tx_output(uint64_t sent, int size, double delta) +tx_output(struct my_ctrs *cur, double delta, const char *msg) { - double bw, raw_bw, pps; + double bw, raw_bw, pps, abs; char b1[40], b2[80], b3[80]; + int size; - printf("Sent %llu packets, %d bytes each, in %.2f seconds.\n", - (unsigned long long)sent, size, delta); + if (cur->pkts == 0) { + printf("%s nothing.\n", msg); + return; + } + + size = (int)(cur->bytes / cur->pkts); + + printf("%s %llu packets %llu bytes %llu events %d bytes each in %.2f seconds.\n", + msg, + (unsigned long long)cur->pkts, + (unsigned long long)cur->bytes, + (unsigned long long)cur->events, size, delta); if (delta == 0) delta = 1e-6; if (size < 60) /* correct for min packet size */ size = 60; - pps = sent / delta; - bw = (8.0 * size * sent) / delta; + pps = cur->pkts / delta; + bw = (8.0 * cur->bytes) / delta; /* raw packets have4 bytes crc + 20 bytes framing */ - raw_bw = (8.0 * (size + 24) * sent) / delta; + raw_bw = (8.0 * (cur->pkts * 24 + cur->bytes)) / delta; + abs = cur->pkts / (double)(cur->events); - printf("Speed: %spps Bandwidth: %sbps (raw %sbps)\n", - norm(b1, pps), norm(b2, bw), norm(b3, raw_bw) ); -} - - -static void -rx_output(uint64_t received, double delta) -{ - double pps; - char b1[40]; - - printf("Received %llu packets, in %.2f seconds.\n", - (unsigned long long) received, delta); - - if (delta == 0) - delta = 1e-6; - pps = received / delta; - printf("Speed: %spps\n", norm(b1, pps)); + printf("Speed: %spps Bandwidth: %sbps (raw %sbps). Average batch: %.2f pkts\n", + norm(b1, pps), norm(b2, bw), norm(b3, raw_bw), abs); } static void @@ -1389,9 +1870,9 @@ usage(void) "Usage:\n" "%s arguments\n" "\t-i interface interface name\n" - "\t-f function tx rx ping pong\n" + "\t-f function tx rx ping pong txseq rxseq\n" "\t-n count number of iterations (can be 0)\n" - "\t-t pkts_to_send also forces tx mode\n" + "\t-t pkts_to_send also forces tx mode\n" "\t-r pkts_to_receive also forces rx mode\n" "\t-l pkt_size in bytes excluding CRC\n" "\t-d dst_ip[:port[-dst_ip:port]] single or range\n" @@ -1403,20 +1884,29 @@ usage(void) "\t-c cores cores to use\n" "\t-p threads processes/threads to use\n" "\t-T report_ms milliseconds between reports\n" - "\t-P use libpcap instead of netmap\n" "\t-w wait_for_link_time in seconds\n" "\t-R rate in packets per second\n" "\t-X dump payload\n" "\t-H len add empty virtio-net-header with size 'len'\n" + "\t-E pipes allocate extra space for a number of pipes\n" + "\t-r do not touch the buffers (send rubbish)\n" "\t-P file load packet from pcap file\n" "\t-z use random IPv4 src address/port\n" "\t-Z use random IPv4 dst address/port\n" + "\t-F num_frags send multi-slot packets\n" + "\t-A activate pps stats on receiver\n" "", cmd); exit(0); } +enum { + TD_TYPE_SENDER = 1, + TD_TYPE_RECEIVER, + TD_TYPE_OTHER, +}; + static void start_threads(struct glob_arg *g) { @@ -1439,33 +1929,32 @@ start_threads(struct glob_arg *g) uint64_t nmd_flags = 0; nmd.self = &nmd; - if (g->nthreads > 1) { - if (nmd.req.nr_flags != NR_REG_ALL_NIC) { - D("invalid nthreads mode %d", nmd.req.nr_flags); + if (i > 0) { + /* the first thread uses the fd opened by the main + * thread, the other threads re-open /dev/netmap + */ + if (g->nthreads > 1) { + nmd.req.nr_flags = + g->nmd->req.nr_flags & ~NR_REG_MASK; + nmd.req.nr_flags |= NR_REG_ONE_NIC; + nmd.req.nr_ringid = i; + } + /* Only touch one of the rings (rx is already ok) */ + if (g->td_type == TD_TYPE_RECEIVER) + nmd_flags |= NETMAP_NO_TX_POLL; + + /* register interface. Override ifname and ringid etc. */ + t->nmd = nm_open(t->g->ifname, NULL, nmd_flags | + NM_OPEN_IFNAME | NM_OPEN_NO_MMAP, &nmd); + if (t->nmd == NULL) { + D("Unable to open %s: %s", + t->g->ifname, strerror(errno)); continue; } - nmd.req.nr_flags = NR_REG_ONE_NIC; - nmd.req.nr_ringid = i; - } - /* Only touch one of the rings (rx is already ok) */ - if (g->td_body == receiver_body) - nmd_flags |= NETMAP_NO_TX_POLL; - - /* register interface. Override ifname and ringid etc. */ - if (g->options & OPT_MONITOR_TX) - nmd.req.nr_flags |= NR_MONITOR_TX; - if (g->options & OPT_MONITOR_RX) - nmd.req.nr_flags |= NR_MONITOR_RX; - - t->nmd = nm_open(t->g->ifname, NULL, nmd_flags | - NM_OPEN_IFNAME | NM_OPEN_NO_MMAP, &nmd); - if (t->nmd == NULL) { - D("Unable to open %s: %s", - t->g->ifname, strerror(errno)); - continue; + } else { + t->nmd = g->nmd; } t->fd = t->nmd->fd; - set_vnet_hdr_len(t); } else { targs[i].fd = g->main_fd; @@ -1473,10 +1962,7 @@ start_threads(struct glob_arg *g) t->used = 1; t->me = i; if (g->affinity >= 0) { - if (g->affinity < g->cpus) - t->affinity = g->affinity; - else - t->affinity = i % g->cpus; + t->affinity = (g->affinity + i) % g->system_cpus; } else { t->affinity = -1; } @@ -1495,45 +1981,89 @@ main_thread(struct glob_arg *g) { int i; - uint64_t prev = 0; - uint64_t count = 0; + struct my_ctrs prev, cur; double delta_t; struct timeval tic, toc; - gettimeofday(&toc, NULL); + prev.pkts = prev.bytes = prev.events = 0; + gettimeofday(&prev.t, NULL); for (;;) { - struct timeval now, delta; - uint64_t pps, usec, my_count, npkts; + char b1[40], b2[40], b3[40], b4[70]; + uint64_t pps, usec; + struct my_ctrs x; + double abs; int done = 0; - delta.tv_sec = g->report_interval/1000; - delta.tv_usec = (g->report_interval%1000)*1000; - select(0, NULL, NULL, NULL, &delta); - gettimeofday(&now, NULL); - timersub(&now, &toc, &toc); - my_count = 0; + usec = wait_for_next_report(&prev.t, &cur.t, + g->report_interval); + + cur.pkts = cur.bytes = cur.events = 0; + cur.min_space = 0; + if (usec < 10000) /* too short to be meaningful */ + continue; + /* accumulate counts for all threads */ for (i = 0; i < g->nthreads; i++) { - my_count += targs[i].count; + cur.pkts += targs[i].ctr.pkts; + cur.bytes += targs[i].ctr.bytes; + cur.events += targs[i].ctr.events; + cur.min_space += targs[i].ctr.min_space; + targs[i].ctr.min_space = 99999; if (targs[i].used == 0) done++; } - usec = toc.tv_sec* 1000000 + toc.tv_usec; - if (usec < 10000) - continue; - npkts = my_count - prev; - pps = (npkts*1000000 + usec/2) / usec; - D("%llu pps (%llu pkts in %llu usec)", - (unsigned long long)pps, - (unsigned long long)npkts, - (unsigned long long)usec); - prev = my_count; - toc = now; + x.pkts = cur.pkts - prev.pkts; + x.bytes = cur.bytes - prev.bytes; + x.events = cur.events - prev.events; + pps = (x.pkts*1000000 + usec/2) / usec; + abs = (x.events > 0) ? (x.pkts / (double) x.events) : 0; + + if (!(g->options & OPT_PPS_STATS)) { + strcpy(b4, ""); + } else { + /* Compute some pps stats using a sliding window. */ + double ppsavg = 0.0, ppsdev = 0.0; + int nsamples = 0; + + g->win[g->win_idx] = pps; + g->win_idx = (g->win_idx + 1) % STATS_WIN; + + for (i = 0; i < STATS_WIN; i++) { + ppsavg += g->win[i]; + if (g->win[i]) { + nsamples ++; + } + } + ppsavg /= nsamples; + + for (i = 0; i < STATS_WIN; i++) { + if (g->win[i] == 0) { + continue; + } + ppsdev += (g->win[i] - ppsavg) * (g->win[i] - ppsavg); + } + ppsdev /= nsamples; + ppsdev = sqrt(ppsdev); + + snprintf(b4, sizeof(b4), "[avg/std %s/%s pps]", + norm(b1, ppsavg), norm(b2, ppsdev)); + } + + D("%spps %s(%spkts %sbps in %llu usec) %.2f avg_batch %d min_space", + norm(b1, pps), b4, + norm(b2, (double)x.pkts), + norm(b3, (double)x.bytes*8), + (unsigned long long)usec, + abs, (int)cur.min_space); + prev = cur; + if (done == g->nthreads) break; } timerclear(&tic); timerclear(&toc); + cur.pkts = cur.bytes = cur.events = 0; + /* final round */ for (i = 0; i < g->nthreads; i++) { struct timespec t_tic, t_toc; /* @@ -1541,8 +2071,13 @@ main_thread(struct glob_arg *g) * file descriptors. */ if (targs[i].used) - pthread_join(targs[i].thread, NULL); - close(targs[i].fd); + pthread_join(targs[i].thread, NULL); /* blocking */ + if (g->dev_type == DEV_NETMAP) { + nm_close(targs[i].nmd); + targs[i].nmd = NULL; + } else { + close(targs[i].fd); + } if (targs[i].completed == 0) D("ouch, thread %d exited with error", i); @@ -1551,7 +2086,13 @@ main_thread(struct glob_arg *g) * Collect threads output and extract information about * how long it took to send all the packets. */ - count += targs[i].count; + cur.pkts += targs[i].ctr.pkts; + cur.bytes += targs[i].ctr.bytes; + cur.events += targs[i].ctr.events; + /* collect the largest start (tic) and end (toc) times, + * XXX maybe we should do the earliest tic, or do a weighted + * average ? + */ t_tic = timeval2spec(&tic); t_toc = timeval2spec(&toc); if (!timerisset(&tic) || timespec_ge(&targs[i].tic, &t_tic)) @@ -1563,29 +2104,26 @@ main_thread(struct glob_arg *g) /* print output. */ timersub(&toc, &tic, &toc); delta_t = toc.tv_sec + 1e-6* toc.tv_usec; - if (g->td_body == sender_body) - tx_output(count, g->pkt_size, delta_t); + if (g->td_type == TD_TYPE_SENDER) + tx_output(&cur, delta_t, "Sent"); else - rx_output(count, delta_t); - - if (g->dev_type == DEV_NETMAP) { - munmap(g->nmd->mem, g->nmd->req.nr_memsize); - close(g->main_fd); - } + tx_output(&cur, delta_t, "Received"); } - -struct sf { +struct td_desc { + int ty; char *key; void *f; }; -static struct sf func[] = { - { "tx", sender_body }, - { "rx", receiver_body }, - { "ping", pinger_body }, - { "pong", ponger_body }, - { NULL, NULL } +static struct td_desc func[] = { + { TD_TYPE_SENDER, "tx", sender_body }, + { TD_TYPE_RECEIVER, "rx", receiver_body }, + { TD_TYPE_OTHER, "ping", pinger_body }, + { TD_TYPE_OTHER, "pong", ponger_body }, + { TD_TYPE_SENDER, "txseq", txseq_body }, + { TD_TYPE_RECEIVER, "rxseq", rxseq_body }, + { 0, NULL, NULL } }; static int @@ -1654,6 +2192,8 @@ int main(int arc, char **argv) { int i; + struct sigaction sa; + sigset_t ss; struct glob_arg g; @@ -1665,6 +2205,7 @@ main(int arc, char **argv) g.main_fd = -1; g.td_body = receiver_body; + g.td_type = TD_TYPE_RECEIVER; g.report_interval = 1000; /* report interval */ g.affinity = -1; /* ip addresses can also be a range x.x.x.x-x.x.x.y */ @@ -1675,7 +2216,7 @@ main(int arc, char **argv) g.pkt_size = 60; g.burst = 512; // default g.nthreads = 1; - g.cpus = 1; + g.cpus = 1; // default g.forever = 1; g.tx_rate = 0; g.frags = 1; @@ -1683,8 +2224,8 @@ main(int arc, char **argv) g.virt_header = 0; while ( (ch = getopt(arc, argv, - "a:f:F:n:i:Il:d:s:D:S:b:c:o:p:T:w:WvR:XC:H:e:m:P:zZ")) != -1) { - struct sf *fn; + "a:f:F:n:i:Il:d:s:D:S:b:c:o:p:T:w:WvR:XC:H:e:E:m:rP:zZA")) != -1) { + struct td_desc *fn; switch(ch) { default: @@ -1693,7 +2234,7 @@ main(int arc, char **argv) break; case 'n': - g.npackets = atoi(optarg); + g.npackets = strtoull(optarg, NULL, 10); break; case 'F': @@ -1710,10 +2251,12 @@ main(int arc, char **argv) if (!strcmp(fn->key, optarg)) break; } - if (fn->key) + if (fn->key) { g.td_body = fn->f; - else + g.td_type = fn->ty; + } else { D("unrecognised function %s", optarg); + } break; case 'o': /* data generation options */ @@ -1817,24 +2360,27 @@ main(int arc, char **argv) case 'e': /* extra bufs */ g.extra_bufs = atoi(optarg); break; - case 'm': - if (strcmp(optarg, "tx") == 0) { - g.options |= OPT_MONITOR_TX; - } else if (strcmp(optarg, "rx") == 0) { - g.options |= OPT_MONITOR_RX; - } else { - D("unrecognized monitor mode %s", optarg); - } + case 'E': + g.extra_pipes = atoi(optarg); break; case 'P': g.packet_file = strdup(optarg); break; + case 'm': + /* ignored */ + break; + case 'r': + g.options |= OPT_RUBBISH; + break; case 'z': g.options |= OPT_RANDOM_SRC; break; case 'Z': g.options |= OPT_RANDOM_DST; break; + case 'A': + g.options |= OPT_PPS_STATS; + break; } } @@ -1843,11 +2389,12 @@ main(int arc, char **argv) usage(); } - i = system_ncpus(); + g.system_cpus = i = system_ncpus(); if (g.cpus < 0 || g.cpus > i) { D("%d cpus is too high, have only %d cpus", g.cpus, i); usage(); } +D("running on %d cpus (have %d)", g.cpus, i); if (g.cpus == 0) g.cpus = i; @@ -1914,6 +2461,11 @@ main(int arc, char **argv) if (g.extra_bufs) { base_nmd.nr_arg3 = g.extra_bufs; } + if (g.extra_pipes) { + base_nmd.nr_arg1 = g.extra_pipes; + } + + base_nmd.nr_flags |= NR_ACCEPT_VNET_HDR; /* * Open the netmap device using nm_open(). @@ -1927,13 +2479,38 @@ main(int arc, char **argv) D("Unable to open %s: %s", g.ifname, strerror(errno)); goto out; } + + if (g.nthreads > 1) { + struct nm_desc saved_desc = *g.nmd; + saved_desc.self = &saved_desc; + saved_desc.mem = NULL; + nm_close(g.nmd); + saved_desc.req.nr_flags &= ~NR_REG_MASK; + saved_desc.req.nr_flags |= NR_REG_ONE_NIC; + saved_desc.req.nr_ringid = 0; + g.nmd = nm_open(g.ifname, &base_nmd, NM_OPEN_IFNAME, &saved_desc); + if (g.nmd == NULL) { + D("Unable to open %s: %s", g.ifname, strerror(errno)); + goto out; + } + } g.main_fd = g.nmd->fd; D("mapped %dKB at %p", g.nmd->req.nr_memsize>>10, g.nmd->mem); - /* get num of queues in tx or rx */ - if (g.td_body == sender_body) + if (g.virt_header) { + /* Set the virtio-net header length, since the user asked + * for it explicitely. */ + set_vnet_hdr_len(&g); + } else { + /* Check whether the netmap port we opened requires us to send + * and receive frames with virtio-net header. */ + get_vnet_hdr_len(&g); + } + + /* get num of queues in tx or rx */ + if (g.td_type == TD_TYPE_SENDER) devqueues = g.nmd->req.nr_tx_rings; - else + else devqueues = g.nmd->req.nr_rx_rings; /* validate provided nthreads. */ @@ -1951,25 +2528,27 @@ main(int arc, char **argv) req->nr_arg2); for (i = 0; i <= req->nr_tx_rings; i++) { struct netmap_ring *ring = NETMAP_TXRING(nifp, i); - D(" TX%d at 0x%lx slots %d", i, - (char *)ring - (char *)nifp, ring->num_slots); + D(" TX%d at 0x%p slots %d", i, + (void *)((char *)ring - (char *)nifp), ring->num_slots); } for (i = 0; i <= req->nr_rx_rings; i++) { struct netmap_ring *ring = NETMAP_RXRING(nifp, i); - D(" RX%d at 0x%lx slots %d", i, - (char *)ring - (char *)nifp, ring->num_slots); + D(" RX%d at 0x%p slots %d", i, + (void *)((char *)ring - (char *)nifp), ring->num_slots); } } /* Print some debug information. */ fprintf(stdout, "%s %s: %d queues, %d threads and %d cpus.\n", - (g.td_body == sender_body) ? "Sending on" : "Receiving from", + (g.td_type == TD_TYPE_SENDER) ? "Sending on" : + ((g.td_type == TD_TYPE_RECEIVER) ? "Receiving from" : + "Working on"), g.ifname, devqueues, g.nthreads, g.cpus); - if (g.td_body == sender_body) { + if (g.td_type == TD_TYPE_SENDER) { fprintf(stdout, "%s -> %s (%s -> %s)\n", g.src_ip.name, g.dst_ip.name, g.src_mac.name, g.dst_mac.name); @@ -1985,12 +2564,13 @@ main(int arc, char **argv) if (g.options) { - D("--- SPECIAL OPTIONS:%s%s%s%s%s\n", + D("--- SPECIAL OPTIONS:%s%s%s%s%s%s\n", g.options & OPT_PREFETCH ? " prefetch" : "", g.options & OPT_ACCESS ? " access" : "", g.options & OPT_MEMCPY ? " memcpy" : "", g.options & OPT_INDIRECT ? " indirect" : "", - g.options & OPT_COPY ? " copy" : ""); + g.options & OPT_COPY ? " copy" : "", + g.options & OPT_RUBBISH ? " rubbish " : ""); } g.tx_period.tv_sec = g.tx_period.tv_nsec = 0; @@ -2010,7 +2590,7 @@ main(int arc, char **argv) g.tx_period.tv_sec = g.tx_period.tv_nsec / 1000000000; g.tx_period.tv_nsec = g.tx_period.tv_nsec % 1000000000; } - if (g.td_body == sender_body) + if (g.td_type == TD_TYPE_SENDER) D("Sending %d packets every %ld.%09ld s", g.burst, g.tx_period.tv_sec, g.tx_period.tv_nsec); /* Wait for PHY reset. */ @@ -2020,10 +2600,24 @@ main(int arc, char **argv) /* Install ^C handler. */ global_nthreads = g.nthreads; - signal(SIGINT, sigint_h); - + sigemptyset(&ss); + sigaddset(&ss, SIGINT); + /* block SIGINT now, so that all created threads will inherit the mask */ + if (pthread_sigmask(SIG_BLOCK, &ss, NULL) < 0) { + D("failed to block SIGINT: %s", strerror(errno)); + } start_threads(&g); + /* Install the handler and re-enable SIGINT for the main thread */ + sa.sa_handler = sigint_h; + if (sigaction(SIGINT, &sa, NULL) < 0) { + D("failed to install ^C handler: %s", strerror(errno)); + } + + if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL) < 0) { + D("failed to re-enable SIGINT: %s", strerror(errno)); + } main_thread(&g); + free(targs); return 0; } diff --git a/tools/tools/netmap/vale-ctl.c b/tools/tools/netmap/vale-ctl.c index c9e5f31b9206..bf6e51fbde97 100644 --- a/tools/tools/netmap/vale-ctl.c +++ b/tools/tools/netmap/vale-ctl.c @@ -25,6 +25,10 @@ /* $FreeBSD$ */ +#define NETMAP_WITH_LIBS +#include +#include + #include #include #include /* PRI* macros */ @@ -35,17 +39,9 @@ #include #include /* apple needs sockaddr */ #include /* ifreq */ -#include -#include #include /* basename */ #include /* atoi, free */ -/* debug support */ -#define ND(format, ...) do {} while(0) -#define D(format, ...) \ - fprintf(stderr, "%s [%d] " format "\n", \ - __FUNCTION__, __LINE__, ##__VA_ARGS__) - /* XXX cut and paste from pkt-gen.c because I'm not sure whether this * program may include nm_util.h */ @@ -117,8 +113,11 @@ bdg_ctl(const char *name, int nr_cmd, int nr_arg, char *nmr_config) break; case NETMAP_BDG_ATTACH: case NETMAP_BDG_DETACH: - if (nr_arg && nr_arg != NETMAP_BDG_HOST) + nmr.nr_flags = NR_REG_ALL_NIC; + if (nr_arg && nr_arg != NETMAP_BDG_HOST) { + nmr.nr_flags = NR_REG_NIC_SW; nr_arg = 0; + } nmr.nr_arg1 = nr_arg; error = ioctl(fd, NIOCREGIF, &nmr); if (error == -1) { @@ -152,6 +151,36 @@ bdg_ctl(const char *name, int nr_cmd, int nr_arg, char *nmr_config) break; + case NETMAP_BDG_POLLING_ON: + case NETMAP_BDG_POLLING_OFF: + /* We reuse nmreq fields as follows: + * nr_tx_slots: 0 and non-zero indicate REG_ALL_NIC + * REG_ONE_NIC, respectively. + * nr_rx_slots: CPU core index. This also indicates the + * first queue in the case of REG_ONE_NIC + * nr_tx_rings: (REG_ONE_NIC only) indicates the + * number of CPU cores or the last queue + */ + nmr.nr_flags |= nmr.nr_tx_slots ? + NR_REG_ONE_NIC : NR_REG_ALL_NIC; + nmr.nr_ringid = nmr.nr_rx_slots; + /* number of cores/rings */ + if (nmr.nr_flags == NR_REG_ALL_NIC) + nmr.nr_arg1 = 1; + else + nmr.nr_arg1 = nmr.nr_tx_rings; + + error = ioctl(fd, NIOCREGIF, &nmr); + if (!error) + D("polling on %s %s", nmr.nr_name, + nr_cmd == NETMAP_BDG_POLLING_ON ? + "started" : "stopped"); + else + D("polling on %s %s (err %d)", nmr.nr_name, + nr_cmd == NETMAP_BDG_POLLING_ON ? + "couldn't start" : "couldn't stop", error); + break; + default: /* GINFO */ nmr.nr_cmd = nmr.nr_arg1 = nmr.nr_arg2 = 0; error = ioctl(fd, NIOCGINFO, &nmr); @@ -173,7 +202,7 @@ main(int argc, char *argv[]) const char *command = basename(argv[0]); char *name = NULL, *nmr_config = NULL; - if (argc > 3) { + if (argc > 5) { usage: fprintf(stderr, "Usage:\n" @@ -186,12 +215,18 @@ main(int argc, char *argv[]) "\t-r interface interface name to be deleted\n" "\t-l list all or specified bridge's interfaces (default)\n" "\t-C string ring/slot setting of an interface creating by -n\n" + "\t-p interface start polling. Additional -C x,y,z configures\n" + "\t\t x: 0 (REG_ALL_NIC) or 1 (REG_ONE_NIC),\n" + "\t\t y: CPU core id for ALL_NIC and core/ring for ONE_NIC\n" + "\t\t z: (ONE_NIC only) num of total cores/rings\n" + "\t-P interface stop polling\n" "", command); return 0; } - while ((ch = getopt(argc, argv, "d:a:h:g:l:n:r:C:")) != -1) { - name = optarg; /* default */ + while ((ch = getopt(argc, argv, "d:a:h:g:l:n:r:C:p:P:")) != -1) { + if (ch != 'C') + name = optarg; /* default */ switch (ch) { default: fprintf(stderr, "bad option %c %s", ch, optarg); @@ -223,11 +258,17 @@ main(int argc, char *argv[]) case 'C': nmr_config = strdup(optarg); break; + case 'p': + nr_cmd = NETMAP_BDG_POLLING_ON; + break; + case 'P': + nr_cmd = NETMAP_BDG_POLLING_OFF; + break; } - if (optind != argc) { - // fprintf(stderr, "optind %d argc %d\n", optind, argc); - goto usage; - } + } + if (optind != argc) { + // fprintf(stderr, "optind %d argc %d\n", optind, argc); + goto usage; } if (argc == 1) nr_cmd = NETMAP_BDG_LIST; diff --git a/usr.bin/elfdump/elfdump.c b/usr.bin/elfdump/elfdump.c index 3cffc9138743..32839254d7b8 100644 --- a/usr.bin/elfdump/elfdump.c +++ b/usr.bin/elfdump/elfdump.c @@ -241,9 +241,9 @@ d_tags(u_int64_t tag) case 0x6ffffff0: return "DT_GNU_VERSYM"; /* 0x70000000 - 0x7fffffff processor-specific semantics */ case 0x70000000: return "DT_IA_64_PLT_RESERVE"; - case 0x7ffffffd: return "DT_SUNW_AUXILIARY"; - case 0x7ffffffe: return "DT_SUNW_USED"; - case 0x7fffffff: return "DT_SUNW_FILTER"; + case DT_AUXILIARY: return "DT_AUXILIARY"; + case DT_USED: return "DT_USED"; + case DT_FILTER: return "DT_FILTER"; } snprintf(unknown_tag, sizeof(unknown_tag), "ERROR: TAG NOT DEFINED -- tag 0x%jx", (uintmax_t)tag); diff --git a/usr.bin/jot/jot.c b/usr.bin/jot/jot.c index 779a4b968dee..881be16d69c5 100644 --- a/usr.bin/jot/jot.c +++ b/usr.bin/jot/jot.c @@ -47,8 +47,11 @@ __FBSDID("$FreeBSD$"); * Author: John Kunze, Office of Comp. Affairs, UCB */ +#include +#include #include #include +#include #include #include #include @@ -89,6 +92,7 @@ static void usage(void); int main(int argc, char **argv) { + cap_rights_t rights; bool have_format = false; bool infinity = false; bool nofinalnl = false; @@ -105,6 +109,21 @@ main(int argc, char **argv) long i; long reps = REPS_DEF; + if (caph_limit_stdio() < 0) + err(1, "unable to limit rights for stdio"); + cap_rights_init(&rights); + if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) + err(1, "unable to limit rights for stdin"); + + /* + * Cache NLS data, for strerror, for err(3), before entering capability + * mode. + */ + caph_cache_catpages(); + + if (cap_enter() < 0 && errno != ENOSYS) + err(1, "unable to enter capability mode"); + while ((ch = getopt(argc, argv, "b:cnp:rs:w:")) != -1) switch (ch) { case 'b': diff --git a/usr.bin/kdump/Makefile b/usr.bin/kdump/Makefile index f80f6684a9e5..e77e241bb4c8 100644 --- a/usr.bin/kdump/Makefile +++ b/usr.bin/kdump/Makefile @@ -6,8 +6,8 @@ .PATH: ${.CURDIR}/../ktrace PROG= kdump -SRCS= kdump_subr.c kdump_subr.h kdump.c subr.c -CFLAGS+= -I${.CURDIR}/../ktrace -I${.CURDIR} -I${.CURDIR}/../.. -I. +SRCS= kdump.c subr.c +CFLAGS+= -I${.CURDIR}/../ktrace #-I${.CURDIR}/../... LIBADD= sysdecode .if ${MK_CASPER} != "no" @@ -17,15 +17,6 @@ LIBADD+= cap_pwd CFLAGS+=-DHAVE_LIBCASPER .endif -NO_WERROR?= YES - -CLEANFILES= kdump_subr.c kdump_subr.h - -kdump_subr.h: mksubr - sh ${.CURDIR}/mksubr ${DESTDIR}${INCLUDEDIR} | \ - sed -n 's/^\([a-z].*)\)$$/void \1;/p' >${.TARGET} - -kdump_subr.c: mksubr kdump_subr.h - sh ${.CURDIR}/mksubr ${DESTDIR}${INCLUDEDIR} >${.TARGET} +#NO_WERROR?= YES .include diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c index 9b5aad75db25..f39cad41c63c 100644 --- a/usr.bin/kdump/kdump.c +++ b/usr.bin/kdump/kdump.c @@ -79,7 +79,6 @@ __FBSDID("$FreeBSD$"); #include #include #include "ktrace.h" -#include "kdump_subr.h" #ifdef HAVE_LIBCASPER #include @@ -117,8 +116,6 @@ void usage(void); #define TIMESTAMP_ELAPSED 0x2 #define TIMESTAMP_RELATIVE 0x4 -extern const char *signames[]; - static int timestamp, decimal, fancy = 1, suppressdata, tail, threads, maxdata, resolv = 0, abiflag = 0, syscallno = 0; static const char *tracefile = DEF_TRACEFILE; @@ -240,6 +237,133 @@ cappwdgrp_setup(cap_channel_t **cappwdp, cap_channel_t **capgrpp) } #endif /* HAVE_LIBCASPER */ +static void +print_integer_arg(const char *(*decoder)(int), int value) +{ + const char *str; + + str = decoder(value); + if (str != NULL) + printf("%s", str); + else { + if (decimal) + printf("", value); + else + printf("", value); + } +} + +/* Like print_integer_arg but unknown values are treated as valid. */ +static void +print_integer_arg_valid(const char *(*decoder)(int), int value) +{ + const char *str; + + str = decoder(value); + if (str != NULL) + printf("%s", str); + else { + if (decimal) + printf("%d", value); + else + printf("%#x", value); + } +} + +static void +print_mask_arg(bool (*decoder)(FILE *, int, int *), int value) +{ + bool invalid; + int rem; + + printf("%#x<", value); + invalid = !decoder(stdout, value, &rem); + printf(">"); + if (invalid) + printf("%u", rem); +} + +static void +print_mask_arg0(bool (*decoder)(FILE *, int, int *), int value) +{ + bool invalid; + int rem; + + if (value == 0) { + printf("0"); + return; + } + printf("%#x<", value); + invalid = !decoder(stdout, value, &rem); + printf(">"); + if (invalid) + printf("%u", rem); +} + +static void +decode_fileflags(fflags_t value) +{ + bool invalid; + fflags_t rem; + + if (value == 0) { + printf("0"); + return; + } + printf("%#x<", value); + invalid = !sysdecode_fileflags(stdout, value, &rem); + printf(">"); + if (invalid) + printf("%u", rem); +} + +static void +decode_filemode(int value) +{ + bool invalid; + int rem; + + if (value == 0) { + printf("0"); + return; + } + printf("%#o<", value); + invalid = !sysdecode_filemode(stdout, value, &rem); + printf(">"); + if (invalid) + printf("%u", rem); +} + +static void +print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), uint32_t value) +{ + bool invalid; + uint32_t rem; + + printf("%#x<", value); + invalid = !decoder(stdout, value, &rem); + printf(">"); + if (invalid) + printf("%u", rem); +} + +static void +print_mask_argul(bool (*decoder)(FILE *, u_long, u_long *), u_long value) +{ + bool invalid; + u_long rem; + + if (value == 0) { + printf("0"); + return; + } + printf("%#lx<", value); + invalid = !decoder(stdout, value, &rem); + printf(">"); + if (invalid) + printf("%lu", rem); +} + int main(int argc, char *argv[]) { @@ -679,6 +803,18 @@ syscallname(u_int code, u_int sv_flags) } } +static void +print_signal(int signo) +{ + const char *signame; + + signame = sysdecode_signal(signo); + if (signame != NULL) + printf("%s", signame); + else + printf("SIG %d", signo); +} + void ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) { @@ -720,7 +856,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) case SYS_unlinkat: case SYS_utimensat: putchar('('); - atfdname(*ip, decimal); + print_integer_arg_valid(sysdecode_atfd, *ip); c = ','; ip++; narg--; @@ -738,7 +874,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) } case SYS_ptrace: putchar('('); - ptraceopname(*ip); + print_integer_arg(sysdecode_ptrace_request, *ip); c = ','; ip++; narg--; @@ -748,7 +884,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) case SYS_faccessat: print_number(ip, narg, c); putchar(','); - accessmodename(*ip); + print_mask_arg(sysdecode_access_mode, *ip); ip++; narg--; break; @@ -756,37 +892,32 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) case SYS_openat: print_number(ip, narg, c); putchar(','); - flagsandmodename(ip[0], ip[1], decimal); + print_mask_arg(sysdecode_open_flags, ip[0]); + if ((ip[0] & O_CREAT) == O_CREAT) { + putchar(','); + decode_filemode(ip[1]); + } ip += 2; narg -= 2; break; case SYS_wait4: print_number(ip, narg, c); print_number(ip, narg, c); - /* - * A flags value of zero is valid for - * wait4() but not for wait6(), so - * handle zero special here. - */ - if (*ip == 0) { - print_number(ip, narg, c); - } else { - putchar(','); - wait6optname(*ip); - ip++; - narg--; - } + putchar(','); + print_mask_arg0(sysdecode_wait4_options, *ip); + ip++; + narg--; break; case SYS_wait6: putchar('('); - idtypename(*ip, decimal); + print_integer_arg(sysdecode_idtype, *ip); c = ','; ip++; narg--; print_number64(first, ip, narg, c); print_number(ip, narg, c); putchar(','); - wait6optname(*ip); + print_mask_arg(sysdecode_wait6_options, *ip); ip++; narg--; break; @@ -796,7 +927,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) case SYS_fchmodat: print_number(ip, narg, c); putchar(','); - modename(*ip); + decode_filemode(*ip); ip++; narg--; break; @@ -804,7 +935,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) case SYS_mknodat: print_number(ip, narg, c); putchar(','); - modename(*ip); + decode_filemode(*ip); ip++; narg--; break; @@ -812,7 +943,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - getfsstatflagsname(*ip); + print_mask_arg(sysdecode_getfsstat_flags, *ip); ip++; narg--; break; @@ -820,14 +951,14 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - mountflagsname(*ip); + print_mask_arg(sysdecode_mount_flags, *ip); ip++; narg--; break; case SYS_unmount: print_number(ip, narg, c); putchar(','); - mountflagsname(*ip); + print_mask_arg(sysdecode_mount_flags, *ip); ip++; narg--; break; @@ -836,7 +967,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - sendrecvflagsname(*ip); + print_mask_arg0(sysdecode_msg_flags, *ip); ip++; narg--; break; @@ -846,7 +977,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - sendrecvflagsname(*ip); + print_mask_arg0(sysdecode_msg_flags, *ip); ip++; narg--; break; @@ -855,26 +986,26 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) case SYS_lchflags: print_number(ip, narg, c); putchar(','); - modename(*ip); + decode_fileflags(*ip); ip++; narg--; break; case SYS_kill: print_number(ip, narg, c); putchar(','); - signame(*ip); + print_signal(*ip); ip++; narg--; break; case SYS_reboot: putchar('('); - rebootoptname(*ip); + print_mask_arg(sysdecode_reboot_howto, *ip); ip++; narg--; break; case SYS_umask: putchar('('); - modename(*ip); + decode_filemode(*ip); ip++; narg--; break; @@ -882,7 +1013,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - msyncflagsname(*ip); + print_mask_arg(sysdecode_msync_flags, *ip); ip++; narg--; break; @@ -891,11 +1022,11 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - mmapprotname(*ip); + print_mask_arg(sysdecode_mmap_prot, *ip); putchar(','); ip++; narg--; - mmapflagsname(*ip); + print_mask_arg(sysdecode_mmap_flags, *ip); ip++; narg--; break; @@ -904,11 +1035,11 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - mmapprotname(*ip); + print_mask_arg(sysdecode_mmap_prot, *ip); putchar(','); ip++; narg--; - mmapflagsname(*ip); + print_mask_arg(sysdecode_mmap_flags, *ip); ip++; narg--; break; @@ -916,7 +1047,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - mmapprotname(*ip); + print_mask_arg(sysdecode_mmap_prot, *ip); ip++; narg--; break; @@ -924,7 +1055,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - madvisebehavname(*ip); + print_integer_arg(sysdecode_madvice, *ip); ip++; narg--; break; @@ -932,14 +1063,25 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - prioname(*ip); + print_integer_arg(sysdecode_prio_which, *ip); ip++; narg--; break; case SYS_fcntl: print_number(ip, narg, c); putchar(','); - fcntlcmdname(ip[0], ip[1], decimal); + print_integer_arg(sysdecode_fcntl_cmd, ip[0]); + if (sysdecode_fcntl_arg_p(ip[0])) { + putchar(','); + if (ip[0] == F_SETFL) + print_mask_arg( + sysdecode_fcntl_fileflags, + ip[1]); + else + sysdecode_fcntl_arg(stdout, + ip[0], ip[1], + decimal ? 10 : 16); + } ip += 2; narg -= 2; break; @@ -947,17 +1089,19 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) int sockdomain; putchar('('); sockdomain = *ip; - sockdomainname(sockdomain); + print_integer_arg(sysdecode_socketdomain, + sockdomain); ip++; narg--; putchar(','); - socktypenamewithflags(*ip); + print_mask_arg(sysdecode_socket_type, *ip); ip++; narg--; if (sockdomain == PF_INET || sockdomain == PF_INET6) { putchar(','); - sockipprotoname(*ip); + print_integer_arg(sysdecode_ipproto, + *ip); ip++; narg--; } @@ -965,19 +1109,23 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) break; } case SYS_setsockopt: - case SYS_getsockopt: + case SYS_getsockopt: { + const char *str; + print_number(ip, narg, c); putchar(','); - sockoptlevelname(*ip, decimal); - if (*ip == SOL_SOCKET) { + print_integer_arg_valid(sysdecode_sockopt_level, + *ip); + str = sysdecode_sockopt_name(ip[0], ip[1]); + if (str != NULL) { + printf(",%s", str); ip++; narg--; - putchar(','); - sockoptname(*ip); } ip++; narg--; break; + } #ifdef SYS_freebsd6_lseek case SYS_freebsd6_lseek: print_number(ip, narg, c); @@ -985,7 +1133,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number64(first, ip, narg, c); putchar(','); - whencename(*ip); + print_integer_arg(sysdecode_whence, *ip); ip++; narg--; break; @@ -994,14 +1142,14 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number64(first, ip, narg, c); putchar(','); - whencename(*ip); + print_integer_arg(sysdecode_whence, *ip); ip++; narg--; break; case SYS_flock: print_number(ip, narg, c); putchar(','); - flockname(*ip); + print_mask_arg(sysdecode_flock_operation, *ip); ip++; narg--; break; @@ -1011,24 +1159,24 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) case SYS_mkdirat: print_number(ip, narg, c); putchar(','); - modename(*ip); + decode_filemode(*ip); ip++; narg--; break; case SYS_shutdown: print_number(ip, narg, c); putchar(','); - shutdownhowname(*ip); + print_integer_arg(sysdecode_shutdown_how, *ip); ip++; narg--; break; case SYS_socketpair: putchar('('); - sockdomainname(*ip); + print_integer_arg(sysdecode_socketdomain, *ip); ip++; narg--; putchar(','); - socktypenamewithflags(*ip); + print_mask_arg(sysdecode_socket_type, *ip); ip++; narg--; c = ','; @@ -1036,7 +1184,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) case SYS_getrlimit: case SYS_setrlimit: putchar('('); - rlimitname(*ip); + print_integer_arg(sysdecode_rlimit, *ip); ip++; narg--; c = ','; @@ -1044,21 +1192,28 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) case SYS_quotactl: print_number(ip, narg, c); putchar(','); - quotactlname(*ip); + if (!sysdecode_quotactl_cmd(stdout, *ip)) { + if (decimal) + printf("", (int)*ip); + else + printf("", + (int)*ip); + } ip++; narg--; c = ','; break; case SYS_nfssvc: putchar('('); - nfssvcname(*ip); + print_integer_arg(sysdecode_nfssvc_flags, *ip); ip++; narg--; c = ','; break; case SYS_rtprio: putchar('('); - rtprioname(*ip); + print_integer_arg(sysdecode_rtprio_function, + *ip); ip++; narg--; c = ','; @@ -1067,7 +1222,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - semctlname(*ip); + print_integer_arg(sysdecode_semctl_cmd, *ip); ip++; narg--; break; @@ -1075,14 +1230,14 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - semgetname(*ip); + print_mask_arg(sysdecode_semget_flags, *ip); ip++; narg--; break; case SYS_msgctl: print_number(ip, narg, c); putchar(','); - shmctlname(*ip); + print_integer_arg(sysdecode_msgctl_cmd, *ip); ip++; narg--; break; @@ -1090,64 +1245,69 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - shmatname(*ip); + print_mask_arg(sysdecode_shmat_flags, *ip); ip++; narg--; break; case SYS_shmctl: print_number(ip, narg, c); putchar(','); - shmctlname(*ip); + print_integer_arg(sysdecode_shmctl_cmd, *ip); ip++; narg--; break; case SYS_shm_open: print_number(ip, narg, c); putchar(','); - flagsname(ip[0]); - printf(",0%o", (unsigned int)ip[1]); - ip += 3; - narg -= 3; + print_mask_arg(sysdecode_open_flags, ip[0]); + putchar(','); + decode_filemode(ip[1]); + ip += 2; + narg -= 2; break; case SYS_minherit: print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - minheritname(*ip); + print_integer_arg(sysdecode_minherit_inherit, + *ip); ip++; narg--; break; case SYS_rfork: putchar('('); - rforkname(*ip); + print_mask_arg(sysdecode_rfork_flags, *ip); ip++; narg--; c = ','; break; case SYS_lio_listio: putchar('('); - lio_listioname(*ip); + print_integer_arg(sysdecode_lio_listio_mode, + *ip); ip++; narg--; c = ','; break; case SYS_mlockall: putchar('('); - mlockallname(*ip); + print_mask_arg(sysdecode_mlockall_flags, *ip); ip++; narg--; break; case SYS_sched_setscheduler: print_number(ip, narg, c); putchar(','); - schedpolicyname(*ip); + print_integer_arg(sysdecode_scheduler_policy, + *ip); ip++; narg--; break; case SYS_sched_get_priority_max: case SYS_sched_get_priority_min: putchar('('); - schedpolicyname(*ip); + print_integer_arg(sysdecode_scheduler_policy, + *ip); ip++; narg--; break; @@ -1159,20 +1319,21 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - sendfileflagsname(*(int *)ip); + print_mask_arg(sysdecode_sendfile_flags, *ip); ip++; narg--; break; case SYS_kldsym: print_number(ip, narg, c); putchar(','); - kldsymcmdname(*ip); + print_integer_arg(sysdecode_kldsym_cmd, *ip); ip++; narg--; break; case SYS_sigprocmask: putchar('('); - sigprocmaskhowname(*ip); + print_integer_arg(sysdecode_sigprocmask_how, + *ip); ip++; narg--; c = ','; @@ -1191,13 +1352,13 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) case SYS___acl_aclcheck_link: print_number(ip, narg, c); putchar(','); - acltypename(*ip); + print_integer_arg(sysdecode_acltype, *ip); ip++; narg--; break; case SYS_sigaction: putchar('('); - signame(*ip); + print_signal(*ip); ip++; narg--; c = ','; @@ -1205,7 +1366,8 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) case SYS_extattrctl: print_number(ip, narg, c); putchar(','); - extattrctlname(*ip); + print_integer_arg(sysdecode_extattrnamespace, + *ip); ip++; narg--; break; @@ -1213,7 +1375,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - mountflagsname(*ip); + print_mask_arg(sysdecode_mount_flags, *ip); ip++; narg--; break; @@ -1221,21 +1383,22 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) print_number(ip, narg, c); print_number(ip, narg, c); putchar(','); - thrcreateflagsname(*ip); + print_mask_arg(sysdecode_thr_create_flags, *ip); ip++; narg--; break; case SYS_thr_kill: print_number(ip, narg, c); putchar(','); - signame(*ip); + print_signal(*ip); ip++; narg--; break; case SYS_kldunloadf: print_number(ip, narg, c); putchar(','); - kldunloadfflagsname(*ip); + print_integer_arg(sysdecode_kldunload_flags, + *ip); ip++; narg--; break; @@ -1244,7 +1407,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) case SYS_symlinkat: print_number(ip, narg, c); putchar(','); - atfdname(*ip, decimal); + print_integer_arg_valid(sysdecode_atfd, *ip); ip++; narg--; break; @@ -1254,45 +1417,47 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags) arg = *ip; ip++; narg--; - capfcntlname(arg); + print_mask_arg32(sysdecode_cap_fcntlrights, arg); break; case SYS_posix_fadvise: print_number(ip, narg, c); print_number(ip, narg, c); print_number(ip, narg, c); (void)putchar(','); - fadvisebehavname((int)*ip); + print_integer_arg(sysdecode_fadvice, *ip); ip++; narg--; break; case SYS_procctl: putchar('('); - idtypename(*ip, decimal); + print_integer_arg(sysdecode_idtype, *ip); c = ','; ip++; narg--; print_number64(first, ip, narg, c); putchar(','); - procctlcmdname(*ip); + print_integer_arg(sysdecode_procctl_cmd, *ip); ip++; narg--; break; case SYS__umtx_op: print_number(ip, narg, c); putchar(','); - umtxopname(*ip); + print_integer_arg(sysdecode_umtx_op, *ip); switch (*ip) { case UMTX_OP_CV_WAIT: ip++; narg--; putchar(','); - umtxcvwaitflags(*ip); + print_mask_argul( + sysdecode_umtx_cvwait_flags, *ip); break; case UMTX_OP_RW_RDLOCK: ip++; narg--; putchar(','); - umtxrwlockflags(*ip); + print_mask_argul( + sysdecode_umtx_rwlock_flags, *ip); break; } ip++; @@ -1482,32 +1647,25 @@ ktrgenio(struct ktr_genio *ktr, int len) visdump(dp, datalen, screenwidth); } -const char *signames[] = { - "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", /* 1 - 6 */ - "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", /* 7 - 12 */ - "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", /* 13 - 18 */ - "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 19 - 24 */ - "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1", /* 25 - 30 */ - "USR2", NULL, /* 31 - 32 */ -}; - void ktrpsig(struct ktr_psig *psig) { - if (psig->signo > 0 && psig->signo < NSIG) - printf("SIG%s ", signames[psig->signo]); - else - printf("SIG %d ", psig->signo); + const char *str; + + print_signal(psig->signo); if (psig->action == SIG_DFL) { - printf("SIG_DFL code="); - sigcodename(psig->signo, psig->code); - putchar('\n'); + printf(" SIG_DFL"); } else { - printf("caught handler=0x%lx mask=0x%x code=", + printf(" caught handler=0x%lx mask=0x%x", (u_long)psig->action, psig->mask.__bits[0]); - sigcodename(psig->signo, psig->code); - putchar('\n'); } + printf(" code="); + str = sysdecode_sigcode(psig->signo, psig->code); + if (str != NULL) + printf("%s", str); + else + printf("", psig->code); + putchar('\n'); } void @@ -1549,7 +1707,7 @@ ktrcaprights(cap_rights_t *rightsp) { printf("cap_rights_t "); - capname(rightsp); + sysdecode_cap_rights(stdout, rightsp); printf("\n"); } @@ -1581,6 +1739,7 @@ ktrsockaddr(struct sockaddr *sa) #include struct sockaddr_nb *nb; */ + const char *str; char addr[64]; /* @@ -1589,7 +1748,11 @@ ktrsockaddr(struct sockaddr *sa) * sa->sa_len bytes long. */ printf("struct sockaddr { "); - sockfamilyname(sa->sa_family); + str = sysdecode_sockaddr_family(sa->sa_family); + if (str != NULL) + printf("%s", str); + else + printf("", sa->sa_family); printf(", "); #define check_sockaddr_len(n) \ @@ -1803,16 +1966,16 @@ ktrcapfail(struct ktr_cap_fail *ktr) case CAPFAIL_NOTCAPABLE: /* operation on fd with insufficient capabilities */ printf("operation requires "); - capname(&ktr->cap_needed); + sysdecode_cap_rights(stdout, &ktr->cap_needed); printf(", descriptor holds "); - capname(&ktr->cap_held); + sysdecode_cap_rights(stdout, &ktr->cap_held); break; case CAPFAIL_INCREASE: /* requested more capabilities than fd already has */ printf("attempt to increase capabilities from "); - capname(&ktr->cap_held); + sysdecode_cap_rights(stdout, &ktr->cap_held); printf(" to "); - capname(&ktr->cap_needed); + sysdecode_cap_rights(stdout, &ktr->cap_needed); break; case CAPFAIL_SYSCALL: /* called restricted syscall */ @@ -1824,9 +1987,9 @@ ktrcapfail(struct ktr_cap_fail *ktr) break; default: printf("unknown capability failure: "); - capname(&ktr->cap_needed); + sysdecode_cap_rights(stdout, &ktr->cap_needed); printf(" "); - capname(&ktr->cap_held); + sysdecode_cap_rights(stdout, &ktr->cap_held); break; } printf("\n"); @@ -1837,15 +2000,20 @@ ktrfault(struct ktr_fault *ktr) { printf("0x%jx ", (uintmax_t)ktr->vaddr); - vmprotname(ktr->type); + print_mask_arg(sysdecode_vmprot, ktr->type); printf("\n"); } void ktrfaultend(struct ktr_faultend *ktr) { + const char *str; - vmresultname(ktr->result); + str = sysdecode_vmresult(ktr->result); + if (str != NULL) + printf("%s", str); + else + printf("", ktr->result); printf("\n"); } diff --git a/usr.bin/kdump/mksubr b/usr.bin/kdump/mksubr deleted file mode 100644 index aa001f8a1b77..000000000000 --- a/usr.bin/kdump/mksubr +++ /dev/null @@ -1,759 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006 "David Kirchner" . All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. -# -# $FreeBSD$ -# -# Generates kdump_subr.c -# mkioctls is a special-purpose script, and works fine as it is -# now, so it remains independent. The idea behind how it generates -# its list was heavily borrowed here. -# -# Some functions here are automatically generated. This can mean -# the user will see unusual kdump output or errors while building -# if the underlying .h files are changed significantly. -# -# Key: -# AUTO: Completely auto-generated with either the "or" or the "switch" -# method. -# AUTO - Special: Generated automatically, but with some extra commands -# that the auto_*_type() functions are inappropriate for. -# MANUAL: Manually entered and must therefore be manually updated. - -set -e - -LC_ALL=C; export LC_ALL - -if [ -z "$1" ] -then - echo "usage: sh $0 include-dir" - exit 1 -fi -include_dir=$1 - -# -# Automatically generates a C function that will print out the -# numeric input as a pipe-delimited string of the appropriate -# #define keys. ex: -# S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH -# The XOR is necessary to prevent including the "0"-value in every -# line. -# -auto_or_type () { - local name grep file - name=$1 - grep=$2 - file=$3 - - cat <<_EOF_ -/* AUTO */ -void -$name(intmax_t arg) -{ - int or = 0; - printf("%#jx<", (uintmax_t)arg); -_EOF_ - egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \ - $include_dir/$file | \ - awk '{ for (i = 1; i <= NF; i++) \ - if ($i ~ /define/) \ - break; \ - ++i; \ - printf "\tif (!((arg > 0) ^ ((%s) > 0)))\n\t\tif_print_or(arg, %s, or);\n", $i, $i }' -cat <<_EOF_ - printf(">"); - if (or == 0) - printf("%jd", arg); -} - -_EOF_ -} - -# -# Automatically generates a C function used when the argument -# maps to a single, specific #definition -# -auto_switch_type () { - local name grep file - name=$1 - grep=$2 - file=$3 - - cat <<_EOF_ -/* AUTO */ -void -$name(intmax_t arg) -{ - switch (arg) { -_EOF_ - egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \ - $include_dir/$file | \ - awk '{ for (i = 1; i <= NF; i++) \ - if ($i ~ /define/) \ - break; \ - ++i; \ - printf "\tcase %s:\n\t\tprintf(\"%s\");\n\t\tbreak;\n", $i, $i }' -cat <<_EOF_ - default: /* Should not reach */ - printf("", arg); - } -} - -_EOF_ -} - -# -# Automatically generates a C function used when the argument -# maps to a #definition -# -auto_if_type () { - local name grep file - name=$1 - grep=$2 - file=$3 - - cat <<_EOF_ -/* AUTO */ -void -$name(intmax_t arg) -{ -_EOF_ - egrep "^#[[:space:]]*define[[:space:]]+"${grep}"[[:space:]]*" \ - $include_dir/$file | \ - awk '{ printf "\t"; \ - if (NR > 1) \ - printf "else " ; \ - printf "if (arg == %s) \n\t\tprintf(\"%s\");\n", $2, $2 }' -cat <<_EOF_ - else /* Should not reach */ - printf("", arg); -} - -_EOF_ -} - -# C start - -cat <<_EOF_ -#include -#include -#include -#include -#include -#include -#include -#define _KERNEL -#include -#undef _KERNEL -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define _KERNEL -#include -#undef _KERNEL -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "kdump_subr.h" - -/* - * These are simple support macros. print_or utilizes a variable - * defined in the calling function to track whether or not it should - * print a logical-OR character ('|') before a string. if_print_or - * simply handles the necessary "if" statement used in many lines - * of this file. - */ -#define print_or(str,orflag) do { \\ - if (orflag) putchar('|'); else orflag = 1; \\ - printf (str); } \\ - while (0) -#define if_print_or(i,flag,orflag) do { \\ - if ((i & flag) == flag) \\ - print_or(#flag,orflag); } \\ - while (0) - -/* MANUAL */ -void -atfdname(int fd, int decimal) -{ - if (fd == AT_FDCWD) - printf("AT_FDCWD"); - else if (decimal) - printf("%d", fd); - else - printf("%#x", fd); -} - -/* MANUAL */ -extern char *signames[]; /* from kdump.c */ -void -signame(int sig) -{ - if (sig > 0 && sig < NSIG) - printf("SIG%s",signames[sig]); - else - printf("SIG %d", sig); -} - -/* MANUAL */ -void -semctlname(int cmd) -{ - switch (cmd) { - case GETNCNT: - printf("GETNCNT"); - break; - case GETPID: - printf("GETPID"); - break; - case GETVAL: - printf("GETVAL"); - break; - case GETALL: - printf("GETALL"); - break; - case GETZCNT: - printf("GETZCNT"); - break; - case SETVAL: - printf("SETVAL"); - break; - case SETALL: - printf("SETALL"); - break; - case IPC_RMID: - printf("IPC_RMID"); - break; - case IPC_SET: - printf("IPC_SET"); - break; - case IPC_STAT: - printf("IPC_STAT"); - break; - default: /* Should not reach */ - printf("", cmd); - } -} - -/* MANUAL */ -void -shmctlname(int cmd) -{ - switch (cmd) { - case IPC_RMID: - printf("IPC_RMID"); - break; - case IPC_SET: - printf("IPC_SET"); - break; - case IPC_STAT: - printf("IPC_STAT"); - break; - default: /* Should not reach */ - printf("", cmd); - } -} - -/* MANUAL */ -void -semgetname(int flag) -{ - int or = 0; - if_print_or(flag, IPC_CREAT, or); - if_print_or(flag, IPC_EXCL, or); - if_print_or(flag, SEM_R, or); - if_print_or(flag, SEM_A, or); - if_print_or(flag, (SEM_R>>3), or); - if_print_or(flag, (SEM_A>>3), or); - if_print_or(flag, (SEM_R>>6), or); - if_print_or(flag, (SEM_A>>6), or); -} - -/* - * MANUAL - * - * Only used by SYS_open. Unless O_CREAT is set in flags, the - * mode argument is unused (and often bogus and misleading). - */ -void -flagsandmodename(int flags, int mode, int decimal) -{ - flagsname(flags); - putchar(','); - if ((flags & O_CREAT) == O_CREAT) { - modename (mode); - } else { - if (decimal) { - printf("%d", mode); - } else { - printf("%#x", (unsigned int)mode); - } - } -} - -/* MANUAL */ -void -idtypename(idtype_t idtype, int decimal) -{ - switch(idtype) { - case P_PID: - printf("P_PID"); - break; - case P_PPID: - printf("P_PPID"); - break; - case P_PGID: - printf("P_PGID"); - break; - case P_SID: - printf("P_SID"); - break; - case P_CID: - printf("P_CID"); - break; - case P_UID: - printf("P_UID"); - break; - case P_GID: - printf("P_GID"); - break; - case P_ALL: - printf("P_ALL"); - break; - case P_LWPID: - printf("P_LWPID"); - break; - case P_TASKID: - printf("P_TASKID"); - break; - case P_PROJID: - printf("P_PROJID"); - break; - case P_POOLID: - printf("P_POOLID"); - break; - case P_JAILID: - printf("P_JAILID"); - break; - case P_CTID: - printf("P_CTID"); - break; - case P_CPUID: - printf("P_CPUID"); - break; - case P_PSETID: - printf("P_PSETID"); - break; - default: - if (decimal) { - printf("%d", idtype); - } else { - printf("%#x", idtype); - } - } -} - -/* - * MANUAL - * - * [g|s]etsockopt's level argument can either be SOL_SOCKET or a value - * referring to a line in /etc/protocols . It might be appropriate - * to use getprotoent(3) here. - */ -void -sockoptlevelname(int level, int decimal) -{ - if (level == SOL_SOCKET) { - printf("SOL_SOCKET"); - } else { - if (decimal) { - printf("%d", level); - } else { - printf("%#x", (unsigned int)level); - } - } -} - -/* - * MANUAL - * - * Used for page fault type. Cannot use auto_or_type since the macro - * values contain a cast. Also, VM_PROT_NONE has to be handled specially. - */ -void -vmprotname (int type) -{ - int or = 0; - - if (type == VM_PROT_NONE) { - (void)printf("VM_PROT_NONE"); - return; - } - if_print_or(type, VM_PROT_READ, or); - if_print_or(type, VM_PROT_WRITE, or); - if_print_or(type, VM_PROT_EXECUTE, or); - if_print_or(type, VM_PROT_COPY, or); -} - -/* - * MANUAL - */ -void -socktypenamewithflags(int type) -{ - if (type & SOCK_CLOEXEC) - printf("SOCK_CLOEXEC|"), type &= ~SOCK_CLOEXEC; - if (type & SOCK_NONBLOCK) - printf("SOCK_NONBLOCK|"), type &= ~SOCK_NONBLOCK; - socktypename(type); -} -_EOF_ - -auto_or_type "accessmodename" "[A-Z]_OK[[:space:]]+0?x?[0-9A-Fa-f]+" "sys/unistd.h" -auto_switch_type "acltypename" "ACL_TYPE_[A-Z4_]+[[:space:]]+0x[0-9]+" "sys/acl.h" -auto_or_type "capfcntlname" "CAP_FCNTL_[A-Z]+[[:space:]]+\(1" "sys/capsicum.h" -auto_switch_type "extattrctlname" "EXTATTR_NAMESPACE_[A-Z]+[[:space:]]+0x[0-9]+" "sys/extattr.h" -auto_switch_type "fadvisebehavname" "POSIX_FADV_[A-Z]+[[:space:]]+[0-9]+" "sys/fcntl.h" -auto_or_type "flagsname" "O_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/fcntl.h" -auto_or_type "flockname" "LOCK_[A-Z]+[[:space:]]+0x[0-9]+" "sys/fcntl.h" -auto_or_type "getfsstatflagsname" "MNT_[A-Z]+[[:space:]]+[1-9][0-9]*" "sys/mount.h" -auto_switch_type "kldsymcmdname" "KLDSYM_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h" -auto_switch_type "kldunloadfflagsname" "LINKER_UNLOAD_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h" -auto_switch_type "lio_listioname" "LIO_(NO)?WAIT[[:space:]]+[0-9]+" "aio.h" -auto_switch_type "madvisebehavname" "_?MADV_[A-Z]+[[:space:]]+[0-9]+" "sys/mman.h" -auto_switch_type "minheritname" "INHERIT_[A-Z]+[[:space:]]+[0-9]+" "sys/mman.h" -auto_or_type "mlockallname" "MCL_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mman.h" -auto_or_type "mmapprotname" "PROT_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/mman.h" -auto_or_type "modename" "S_[A-Z]+[[:space:]]+[0-6]{7}" "sys/stat.h" -auto_or_type "mountflagsname" "MNT_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mount.h" -auto_switch_type "msyncflagsname" "MS_[A-Z]+[[:space:]]+0x[0-9]+" "sys/mman.h" -auto_or_type "nfssvcname" "NFSSVC_[A-Z0-9]+[[:space:]]+0x[0-9]+" "nfs/nfssvc.h" -auto_switch_type "prioname" "PRIO_[A-Z]+[[:space:]]+[0-9]" "sys/resource.h" -auto_switch_type "procctlcmdname" "PROC_[A-Z]+[[:space:]]+[0-9]" "sys/procctl.h" -auto_switch_type "ptraceopname" "PT_[[:alnum:]_]+[[:space:]]+[0-9]+" "sys/ptrace.h" -auto_switch_type "quotactlname" "Q_[A-Z]+[[:space:]]+0x[0-9]+" "ufs/ufs/quota.h" -auto_or_type "rebootoptname" "RB_[A-Z]+[[:space:]]+0x[0-9]+" "sys/reboot.h" -auto_or_type "rforkname" "RF[A-Z]+[[:space:]]+\([0-9]+<<[0-9]+\)" "sys/unistd.h" -auto_switch_type "rlimitname" "RLIMIT_[A-Z]+[[:space:]]+[0-9]+" "sys/resource.h" -auto_switch_type "schedpolicyname" "SCHED_[A-Z]+[[:space:]]+[0-9]+" "sched.h" -auto_switch_type "sendfileflagsname" "SF_[A-Z]+[[:space:]]+[0-9]+" "sys/socket.h" -auto_or_type "shmatname" "SHM_[A-Z]+[[:space:]]+[0-9]{6}+" "sys/shm.h" -auto_switch_type "shutdownhowname" "SHUT_[A-Z]+[[:space:]]+[0-9]+" "sys/socket.h" -auto_switch_type "sigbuscodename" "BUS_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" -auto_switch_type "sigchldcodename" "CLD_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" -auto_switch_type "sigfpecodename" "FPE_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" -auto_switch_type "sigprocmaskhowname" "SIG_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" -auto_switch_type "sigillcodename" "ILL_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" -auto_switch_type "sigsegvcodename" "SEGV_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" -auto_switch_type "sigtrapcodename" "TRAP_[A-Z]+[[:space:]]+[0-9]+" "sys/signal.h" -auto_if_type "sockdomainname" "PF_[[:alnum:]]+[[:space:]]+" "sys/socket.h" -auto_if_type "sockfamilyname" "AF_[[:alnum:]]+[[:space:]]+" "sys/socket.h" -auto_if_type "sockipprotoname" "IPPROTO_[[:alnum:]]+[[:space:]]+" "netinet/in.h" -auto_switch_type "sockoptname" "SO_[A-Z]+[[:space:]]+0x[0-9]+" "sys/socket.h" -auto_switch_type "socktypename" "SOCK_[A-Z]+[[:space:]]+[1-9]+[0-9]*" "sys/socket.h" -auto_or_type "thrcreateflagsname" "THR_[A-Z]+[[:space:]]+0x[0-9]+" "sys/thr.h" -auto_switch_type "umtxopname" "UMTX_OP_[[:alnum:]_]+[[:space:]]+[0-9]+" "sys/umtx.h" -auto_switch_type "vmresultname" "KERN_[A-Z]+[[:space:]]+[0-9]+" "vm/vm_param.h" -auto_or_type "wait6optname" "W[A-Z]+[[:space:]]+[0-9]+" "sys/wait.h" -auto_switch_type "whencename" "SEEK_[A-Z]+[[:space:]]+[0-9]+" "sys/unistd.h" - -cat <<_EOF_ -/* - * AUTO - Special - * F_ is used to specify fcntl commands as well as arguments. Both sets are - * grouped in fcntl.h, and this awk script grabs the first group. - */ -void -fcntlcmdname(int cmd, int arg, int decimal) -{ - switch (cmd) { -_EOF_ -egrep "^#[[:space:]]*define[[:space:]]+F_[A-Z0-9_]+[[:space:]]+[0-9]+[[:space:]]*" \ - $include_dir/sys/fcntl.h | \ - awk 'BEGIN { o=0 } { for (i = 1; i <= NF; i++) \ - if ($i ~ /define/) \ - break; \ - ++i; \ - if (o <= $(i+1)) \ - printf "\tcase %s:\n\t\tprintf(\"%s\");\n\t\tbreak;\n", $i, $i; \ - else \ - exit; \ - o = $(i+1) }' -cat <<_EOF_ - default: /* Should not reach */ - printf("", cmd); - } - putchar(','); - if (cmd == F_GETFD || cmd == F_SETFD) { - if (arg == FD_CLOEXEC) - printf("FD_CLOEXEC"); - else if (arg == 0) - printf("0"); - else { - if (decimal) - printf("%d", arg); - else - printf("%#x", (unsigned int)arg); - } - } else if (cmd == F_SETFL) { - flagsname(arg); - } else { - if (decimal) - printf("%d", arg); - else - printf("%#x", (unsigned int)arg); - } -} - -/* - * AUTO - Special - * - * The MAP_ALIGNED flag requires special handling. - */ -void -mmapflagsname(int flags) -{ - int align; - int or = 0; - printf("%#x<", flags); -_EOF_ -egrep "^#[[:space:]]*define[[:space:]]+MAP_[A-Z_]+[[:space:]]+0x[0-9A-Fa-f]+[[:space:]]*" \ - $include_dir/sys/mman.h | grep -v MAP_ALIGNED | \ - awk '{ for (i = 1; i <= NF; i++) \ - if ($i ~ /define/) \ - break; \ - ++i; \ - printf "\tif (!((flags > 0) ^ ((%s) > 0)))\n\t\tif_print_or(flags, %s, or);\n", $i, $i }' -cat <<_EOF_ -#ifdef MAP_32BIT - if (!((flags > 0) ^ ((MAP_32BIT) > 0))) - if_print_or(flags, MAP_32BIT, or); -#endif - align = flags & MAP_ALIGNMENT_MASK; - if (align != 0) { - if (align == MAP_ALIGNED_SUPER) - print_or("MAP_ALIGNED_SUPER", or); - else { - print_or("MAP_ALIGNED", or); - printf("(%d)", align >> MAP_ALIGNMENT_SHIFT); - } - } - printf(">"); - if (or == 0) - printf("%d", flags); -} - -/* - * AUTO - Special - * - * The only reason this is not fully automated is due to the - * grep -v RTP_PRIO statement. A better egrep line should - * make this capable of being a auto_switch_type() function. - */ -void -rtprioname(int func) -{ - switch (func) { -_EOF_ -egrep "^#[[:space:]]*define[[:space:]]+RTP_[A-Z]+[[:space:]]+0x[0-9]+[[:space:]]*" \ - $include_dir/sys/rtprio.h | grep -v RTP_PRIO | \ - awk '{ for (i = 1; i <= NF; i++) \ - if ($i ~ /define/) \ - break; \ - ++i; \ - printf "\tcase %s:\n\t\tprintf(\"%s\");\n\t\tbreak;\n", $i, $i }' -cat <<_EOF_ - default: /* Should not reach */ - printf("", func); - } -} - -/* - * AUTO - Special - * - * The send and recv functions have a flags argument which can be - * set to 0. There is no corresponding #define. The auto_ functions - * detect this as "invalid", which is incorrect here. - */ -void -sendrecvflagsname(int flags) -{ - int or = 0; - - if (flags == 0) { - printf("0"); - return; - } - - printf("%#x<", flags); -_EOF_ -egrep "^#[[:space:]]*define[[:space:]]+MSG_[A-Z]+[[:space:]]+0x[0-9]+[[:space:]]*" $include_dir/sys/socket.h | \ - awk '{ for (i = 1; i <= NF; i++) \ - if ($i ~ /define/) \ - break; \ - ++i; \ - printf "\tif(!((flags>0)^((%s)>0)))\n\t\tif_print_or(flags, %s, or);\n", $i, $i }' -cat <<_EOF_ - printf(">"); -} - -/* - * AUTO - Special - * - * Check general codes first, then defer to signal-specific codes. - */ -void -sigcodename(int sig, int code) -{ - switch (code) { -_EOF_ -egrep "^#[[:space:]]*define[[:space:]]+SI_[A-Z]+[[:space:]]+0(x[0-9abcdef]+)?[[:space:]]*" \ - $include_dir/sys/signal.h | grep -v SI_UNDEFINED | \ - awk '{ for (i = 1; i <= NF; i++) \ - if ($i ~ /define/) \ - break; \ - ++i; \ - printf "\tcase %s:\n\t\tprintf(\"%s\");\n\t\tbreak;\n", $i, $i }' -cat <<_EOF_ - default: - switch (sig) { - case SIGILL: - sigillcodename(code); - break; - case SIGBUS: - sigbuscodename(code); - break; - case SIGSEGV: - sigsegvcodename(code); - break; - case SIGFPE: - sigfpecodename(code); - break; - case SIGTRAP: - sigtrapcodename(code); - break; - case SIGCHLD: - sigchldcodename(code); - break; - default: - printf("", code); - } - } -} - -/* - * AUTO - Special - * - * Just print 0 as 0. - */ -void -umtxcvwaitflags(intmax_t arg) -{ - int or = 0; - if (arg == 0) { - printf("0"); - return; - } - printf("%#jx<", (uintmax_t)arg); -_EOF_ - egrep "^#[[:space:]]*define[[:space:]]+CVWAIT_[A-Z_]+[[:space:]]+0x[0-9]+[[:space:]]*" \ - $include_dir/sys/umtx.h | \ - awk '{ for (i = 1; i <= NF; i++) \ - if ($i ~ /define/) \ - break; \ - ++i; \ - printf "\tif (!((arg > 0) ^ ((%s) > 0)))\n\t\tif_print_or(arg, %s, or);\n", $i, $i }' -cat <<_EOF_ - printf(">"); - if (or == 0) - printf("%jd", arg); -} - - -/* - * AUTO - Special - * - * Just print 0 as 0. - */ -void -umtxrwlockflags(intmax_t arg) -{ - int or = 0; - if (arg == 0) { - printf("0"); - return; - } - printf("%#jx<", (uintmax_t)arg); -_EOF_ - egrep "^#[[:space:]]*define[[:space:]]+URWLOCK_PREFER_READER[[:space:]]+0x[0-9]+[[:space:]]*" \ - $include_dir/sys/umtx.h | \ - awk '{ for (i = 1; i <= NF; i++) \ - if ($i ~ /define/) \ - break; \ - ++i; \ - printf "\tif (!((arg > 0) ^ ((%s) > 0)))\n\t\tif_print_or(arg, %s, or);\n", $i, $i }' -cat <<_EOF_ - printf(">"); - if (or == 0) - printf("%jd", arg); -} -_EOF_ -egrep '#define[[:space:]]+CAP_[A-Z_]+[[:space:]]+CAPRIGHT\([0-9],[[:space:]]+0x[0-9]{16}ULL\)' \ - $include_dir/sys/capsicum.h | \ - sed -E 's/[ ]+/ /g' | \ - awk -F '[ \(,\)]' ' - BEGIN { - printf "void\n" - printf "capname(const cap_rights_t *rightsp)\n" - printf "{\n" - printf "\tint comma = 0;\n\n" - printf "\tprintf(\"<\");\n" - } - { - printf "\tif ((rightsp->cr_rights[%s] & %s) == %s) {\n", $4, $2, $2 - printf "\t\tif (comma) printf(\",\"); else comma = 1;\n" - printf "\t\tprintf(\"%s\");\n", $2 - printf "\t}\n" - } - END { - printf "\tprintf(\">\");\n" - printf "}\n" - }' diff --git a/usr.bin/mkimg/Makefile b/usr.bin/mkimg/Makefile index 6622fe449829..836bed850dca 100644 --- a/usr.bin/mkimg/Makefile +++ b/usr.bin/mkimg/Makefile @@ -3,14 +3,15 @@ .include PROG= mkimg -SRCS= format.c image.c mkimg.c scheme.c +SRCS= format.c image.c mkimg.c scheme.c uuid.c MAN= mkimg.1 -MKIMG_VERSION=20151211 +MKIMG_VERSION=20161016 mkimg.o: Makefile CFLAGS+=-DMKIMG_VERSION=${MKIMG_VERSION} CFLAGS+=-DSPARSE_WRITE +CFLAGS+=-I${SRCTOP}/sys/sys/disk # List of formats to support SRCS+= \ diff --git a/usr.bin/mkimg/apm.c b/usr.bin/mkimg/apm.c index 8e5e43ffb4c9..8cea13039ef2 100644 --- a/usr.bin/mkimg/apm.c +++ b/usr.bin/mkimg/apm.c @@ -33,20 +33,13 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" -#ifndef APM_ENT_TYPE_APPLE_BOOT -#define APM_ENT_TYPE_APPLE_BOOT "Apple_Bootstrap" -#endif -#ifndef APM_ENT_TYPE_FREEBSD_NANDFS -#define APM_ENT_TYPE_FREEBSD_NANDFS "FreeBSD-nandfs" -#endif - static struct mkimg_alias apm_aliases[] = { { ALIAS_FREEBSD, ALIAS_PTR2TYPE(APM_ENT_TYPE_FREEBSD) }, { ALIAS_FREEBSD_BOOT, ALIAS_PTR2TYPE(APM_ENT_TYPE_APPLE_BOOT) }, diff --git a/usr.bin/mkimg/bsd.c b/usr.bin/mkimg/bsd.c index 1377b20d26f1..dfaa852440c0 100644 --- a/usr.bin/mkimg/bsd.c +++ b/usr.bin/mkimg/bsd.c @@ -33,17 +33,13 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" -#ifndef FS_NANDFS -#define FS_NANDFS 30 -#endif - static struct mkimg_alias bsd_aliases[] = { { ALIAS_FREEBSD_NANDFS, ALIAS_INT2TYPE(FS_NANDFS) }, { ALIAS_FREEBSD_SWAP, ALIAS_INT2TYPE(FS_SWAP) }, @@ -58,7 +54,7 @@ bsd_metadata(u_int where, lba_t blk) { if (where == SCHEME_META_IMG_START) - blk += BBSIZE / secsz; + blk += BSD_BOOTBLOCK_SIZE / secsz; else if (where == SCHEME_META_IMG_END) blk = round_cylinder(blk); else @@ -76,21 +72,21 @@ bsd_write(lba_t imgsz, void *bootcode) int bsdparts, error, n; uint16_t checksum; - buf = malloc(BBSIZE); + buf = malloc(BSD_BOOTBLOCK_SIZE); if (buf == NULL) return (ENOMEM); if (bootcode != NULL) { - memcpy(buf, bootcode, BBSIZE); + memcpy(buf, bootcode, BSD_BOOTBLOCK_SIZE); memset(buf + secsz, 0, sizeof(struct disklabel)); } else - memset(buf, 0, BBSIZE); + memset(buf, 0, BSD_BOOTBLOCK_SIZE); bsdparts = nparts + 1; /* Account for c partition */ - if (bsdparts < MAXPARTITIONS) - bsdparts = MAXPARTITIONS; + if (bsdparts < BSD_NPARTS_MIN) + bsdparts = BSD_NPARTS_MIN; d = (void *)(buf + secsz); - le32enc(&d->d_magic, DISKMAGIC); + le32enc(&d->d_magic, BSD_MAGIC); le32enc(&d->d_secsize, secsz); le32enc(&d->d_nsectors, nsecs); le32enc(&d->d_ntracks, nheads); @@ -98,14 +94,14 @@ bsd_write(lba_t imgsz, void *bootcode) le32enc(&d->d_secpercyl, nsecs * nheads); le32enc(&d->d_secperunit, imgsz); le16enc(&d->d_rpm, 3600); - le32enc(&d->d_magic2, DISKMAGIC); + le32enc(&d->d_magic2, BSD_MAGIC); le16enc(&d->d_npartitions, bsdparts); - le32enc(&d->d_bbsize, BBSIZE); + le32enc(&d->d_bbsize, BSD_BOOTBLOCK_SIZE); - dp = &d->d_partitions[RAW_PART]; + dp = &d->d_partitions[BSD_PART_RAW]; le32enc(&dp->p_size, imgsz); TAILQ_FOREACH(part, &partlist, link) { - n = part->index + ((part->index >= RAW_PART) ? 1 : 0); + n = part->index + ((part->index >= BSD_PART_RAW) ? 1 : 0); dp = &d->d_partitions[n]; le32enc(&dp->p_size, part->size); le32enc(&dp->p_offset, part->block); @@ -121,7 +117,7 @@ bsd_write(lba_t imgsz, void *bootcode) checksum ^= le16dec(p); le16enc(&d->d_checksum, checksum); - error = image_write(0, buf, BBSIZE / secsz); + error = image_write(0, buf, BSD_BOOTBLOCK_SIZE / secsz); free(buf); return (error); } @@ -132,8 +128,8 @@ static struct mkimg_scheme bsd_scheme = { .aliases = bsd_aliases, .metadata = bsd_metadata, .write = bsd_write, - .nparts = 19, - .bootcode = BBSIZE, + .nparts = BSD_NPARTS_MAX - 1, + .bootcode = BSD_BOOTBLOCK_SIZE, .maxsecsz = 512 }; diff --git a/usr.bin/mkimg/ebr.c b/usr.bin/mkimg/ebr.c index be2f3bc4171d..7c26a6cf1343 100644 --- a/usr.bin/mkimg/ebr.c +++ b/usr.bin/mkimg/ebr.c @@ -33,22 +33,15 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" -#ifndef DOSPTYP_FAT16B -#define DOSPTYP_FAT16B 0x06 -#endif -#ifndef DOSPTYP_FAT32 -#define DOSPTYP_FAT32 0x0b -#endif - static struct mkimg_alias ebr_aliases[] = { - { ALIAS_FAT16B, ALIAS_INT2TYPE(DOSPTYP_FAT16B) }, + { ALIAS_FAT16B, ALIAS_INT2TYPE(DOSPTYP_FAT16) }, { ALIAS_FAT32, ALIAS_INT2TYPE(DOSPTYP_FAT32) }, { ALIAS_FREEBSD, ALIAS_INT2TYPE(DOSPTYP_386BSD) }, { ALIAS_NONE, 0 } diff --git a/usr.bin/mkimg/gpt.c b/usr.bin/mkimg/gpt.c index 58fc337962c4..cb92a02c74af 100644 --- a/usr.bin/mkimg/gpt.c +++ b/usr.bin/mkimg/gpt.c @@ -33,31 +33,25 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include -#include +#include +#include #include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" -#ifndef GPT_ENT_TYPE_FREEBSD_NANDFS -#define GPT_ENT_TYPE_FREEBSD_NANDFS \ - {0x74ba7dd9,0xa689,0x11e1,0xbd,0x04,{0x00,0xe0,0x81,0x28,0x6a,0xcf}} -#endif - -static uuid_t gpt_uuid_efi = GPT_ENT_TYPE_EFI; -static uuid_t gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD; -static uuid_t gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; -static uuid_t gpt_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS; -static uuid_t gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; -static uuid_t gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; -static uuid_t gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; -static uuid_t gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; -static uuid_t gpt_uuid_mbr = GPT_ENT_TYPE_MBR; -static uuid_t gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA; +static mkimg_uuid_t gpt_uuid_efi = GPT_ENT_TYPE_EFI; +static mkimg_uuid_t gpt_uuid_freebsd = GPT_ENT_TYPE_FREEBSD; +static mkimg_uuid_t gpt_uuid_freebsd_boot = GPT_ENT_TYPE_FREEBSD_BOOT; +static mkimg_uuid_t gpt_uuid_freebsd_nandfs = GPT_ENT_TYPE_FREEBSD_NANDFS; +static mkimg_uuid_t gpt_uuid_freebsd_swap = GPT_ENT_TYPE_FREEBSD_SWAP; +static mkimg_uuid_t gpt_uuid_freebsd_ufs = GPT_ENT_TYPE_FREEBSD_UFS; +static mkimg_uuid_t gpt_uuid_freebsd_vinum = GPT_ENT_TYPE_FREEBSD_VINUM; +static mkimg_uuid_t gpt_uuid_freebsd_zfs = GPT_ENT_TYPE_FREEBSD_ZFS; +static mkimg_uuid_t gpt_uuid_mbr = GPT_ENT_TYPE_MBR; +static mkimg_uuid_t gpt_uuid_ms_basic_data = GPT_ENT_TYPE_MS_BASIC_DATA; static struct mkimg_alias gpt_aliases[] = { { ALIAS_EFI, ALIAS_PTR2TYPE(&gpt_uuid_efi) }, @@ -131,21 +125,6 @@ crc32(const void *buf, size_t sz) return (crc ^ ~0U); } -static void -gpt_uuid_enc(void *buf, const uuid_t *uuid) -{ - uint8_t *p = buf; - int i; - - le32enc(p, uuid->time_low); - le16enc(p + 4, uuid->time_mid); - le16enc(p + 6, uuid->time_hi_and_version); - p[8] = uuid->clock_seq_hi_and_reserved; - p[9] = uuid->clock_seq_low; - for (i = 0; i < _UUID_NODE_LEN; i++) - p[10 + i] = uuid->node[i]; -} - static u_int gpt_tblsz(void) { @@ -199,7 +178,7 @@ gpt_write_pmbr(lba_t blks, void *bootcode) static struct gpt_ent * gpt_mktbl(u_int tblsz) { - uuid_t uuid; + mkimg_uuid_t uuid; struct gpt_ent *tbl, *ent; struct part *part; int c, idx; @@ -210,9 +189,9 @@ gpt_mktbl(u_int tblsz) TAILQ_FOREACH(part, &partlist, link) { ent = tbl + part->index; - gpt_uuid_enc(&ent->ent_type, ALIAS_TYPE2PTR(part->type)); + mkimg_uuid_enc(&ent->ent_type, ALIAS_TYPE2PTR(part->type)); mkimg_uuid(&uuid); - gpt_uuid_enc(&ent->ent_uuid, &uuid); + mkimg_uuid_enc(&ent->ent_uuid, &uuid); le64enc(&ent->ent_lba_start, part->block); le64enc(&ent->ent_lba_end, part->block + part->size - 1); if (part->label != NULL) { @@ -243,7 +222,7 @@ gpt_write_hdr(struct gpt_hdr *hdr, uint64_t self, uint64_t alt, uint64_t tbl) static int gpt_write(lba_t imgsz, void *bootcode) { - uuid_t uuid; + mkimg_uuid_t uuid; struct gpt_ent *tbl; struct gpt_hdr *hdr; uint32_t crc; @@ -280,7 +259,7 @@ gpt_write(lba_t imgsz, void *bootcode) le64enc(&hdr->hdr_lba_start, 2 + tblsz); le64enc(&hdr->hdr_lba_end, imgsz - tblsz - 2); mkimg_uuid(&uuid); - gpt_uuid_enc(&hdr->hdr_uuid, &uuid); + mkimg_uuid_enc(&hdr->hdr_uuid, &uuid); le32enc(&hdr->hdr_entries, nparts); le32enc(&hdr->hdr_entsz, sizeof(struct gpt_ent)); crc = crc32(tbl, nparts * sizeof(struct gpt_ent)); diff --git a/usr.bin/mkimg/mbr.c b/usr.bin/mkimg/mbr.c index 548437d6c406..16a24eb7b1ba 100644 --- a/usr.bin/mkimg/mbr.c +++ b/usr.bin/mkimg/mbr.c @@ -33,30 +33,17 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" -#ifndef DOSPTYP_FAT16B -#define DOSPTYP_FAT16B 0x06 -#endif -#ifndef DOSPTYP_FAT32 -#define DOSPTYP_FAT32 0x0b -#endif -#ifndef DOSPTYP_PPCBOOT -#define DOSPTYP_PPCBOOT 0x41 -#endif -#ifndef DOSPTYP_EFI -#define DOSPTYP_EFI 0xef -#endif - static struct mkimg_alias mbr_aliases[] = { { ALIAS_EBR, ALIAS_INT2TYPE(DOSPTYP_EXT) }, { ALIAS_EFI, ALIAS_INT2TYPE(DOSPTYP_EFI) }, - { ALIAS_FAT16B, ALIAS_INT2TYPE(DOSPTYP_FAT16B) }, + { ALIAS_FAT16B, ALIAS_INT2TYPE(DOSPTYP_FAT16) }, { ALIAS_FAT32, ALIAS_INT2TYPE(DOSPTYP_FAT32) }, { ALIAS_FREEBSD, ALIAS_INT2TYPE(DOSPTYP_386BSD) }, { ALIAS_NTFS, ALIAS_INT2TYPE(DOSPTYP_NTFS) }, @@ -105,7 +92,12 @@ mbr_write(lba_t imgsz __unused, void *bootcode) TAILQ_FOREACH(part, &partlist, link) { size = round_track(part->size); dp = dpbase + part->index; - dp->dp_flag = (part->index == 0 && bootcode != NULL) ? 0x80 : 0; + if (active_partition != 0) + dp->dp_flag = + (part->index + 1 == active_partition) ? 0x80 : 0; + else + dp->dp_flag = + (part->index == 0 && bootcode != NULL) ? 0x80 : 0; mbr_chs(&dp->dp_scyl, &dp->dp_shd, &dp->dp_ssect, part->block); dp->dp_typ = ALIAS_TYPE2INT(part->type); diff --git a/usr.bin/mkimg/mkimg.1 b/usr.bin/mkimg/mkimg.1 index 856818a71e3b..c1db2016fa2e 100644 --- a/usr.bin/mkimg/mkimg.1 +++ b/usr.bin/mkimg/mkimg.1 @@ -40,6 +40,7 @@ .Op Fl c Ar capacity .Op Fl f Ar format .Op Fl o Ar outfile +.Op Fl a Ar active .Op Fl v .Op Fl y .Op Fl s Ar scheme Op Fl p Ar partition ... @@ -119,7 +120,7 @@ An empty partition table can be written to the disk when specifying a partitioning scheme with the .Fl s option, but without specifying any partitions. -When the size required to for all the partitions is larger than the +When the size required for all the partitions is larger than the given capacity, then the disk image will be larger than the capacity given. .Pp @@ -139,6 +140,26 @@ utility will generate predictable values for Universally Unique Identifiers .Nm utility will create images that are identical. .Pp +The +.Ar active +option marks a partition as active, if the partitioning +scheme supports it. +Currently, only the +.Ar mbr +scheme supports this concept. +By default, +.Nm +will only mark the first partition as active when boot code is +specified. +Use the +.Ar active +option to override the active partition. +The number specified corresponds to the number after the 's' in the +partition's +.Xr geom 8 +name. +No partitions are marked active when the value is 0. +.Pp A set of long options exist to query about the .Nm utility itself. diff --git a/usr.bin/mkimg/mkimg.c b/usr.bin/mkimg/mkimg.c index 0ab0302d9180..92c5a574c5de 100644 --- a/usr.bin/mkimg/mkimg.c +++ b/usr.bin/mkimg/mkimg.c @@ -28,7 +28,6 @@ __FBSDID("$FreeBSD$"); #include -#include #include #include #include @@ -71,6 +70,7 @@ u_int nheads = 1; u_int nsecs = 1; u_int secsz = 512; u_int blksz = 0; +uint32_t active_partition = 0; static void print_formats(int usage) @@ -146,6 +146,7 @@ usage(const char *why) fprintf(stderr, "\t--schemes\t- list partition schemes\n"); fprintf(stderr, "\t--version\t- show version information\n"); fputc('\n', stderr); + fprintf(stderr, "\t-a \t- mark num'th partion as active\n"); fprintf(stderr, "\t-b \t- file containing boot code\n"); fprintf(stderr, "\t-c \t- capacity (in bytes) of the disk\n"); fprintf(stderr, "\t-f \n"); @@ -374,22 +375,6 @@ mkimg_chs(lba_t lba, u_int maxcyl, u_int *cylp, u_int *hdp, u_int *secp) *secp = sec; } -void -mkimg_uuid(struct uuid *uuid) -{ - static uint8_t gen[sizeof(struct uuid)]; - u_int i; - - if (!unit_testing) { - uuidgen(uuid, 1); - return; - } - - for (i = 0; i < sizeof(gen); i++) - gen[i]++; - memcpy(uuid, gen, sizeof(uuid_t)); -} - static int capacity_resize(lba_t end) { @@ -485,9 +470,14 @@ main(int argc, char *argv[]) bcfd = -1; outfd = 1; /* Write to stdout by default */ - while ((c = getopt_long(argc, argv, "b:c:f:o:p:s:vyH:P:S:T:", + while ((c = getopt_long(argc, argv, "a:b:c:f:o:p:s:vyH:P:S:T:", longopts, NULL)) != -1) { switch (c) { + case 'a': /* ACTIVE PARTITION, if supported */ + error = parse_uint32(&active_partition, 1, 100, optarg); + if (error) + errc(EX_DATAERR, error, "Partition ordinal"); + break; case 'b': /* BOOT CODE */ if (bcfd != -1) usage("multiple bootcode given"); diff --git a/usr.bin/mkimg/mkimg.h b/usr.bin/mkimg/mkimg.h index 5a0b4dfefc51..70b14e3a113d 100644 --- a/usr.bin/mkimg/mkimg.h +++ b/usr.bin/mkimg/mkimg.h @@ -30,6 +30,7 @@ #define _MKIMG_MKIMG_H_ #include +#include struct part { TAILQ_ENTRY(part) link; @@ -58,6 +59,7 @@ extern u_int nheads; extern u_int nsecs; extern u_int secsz; /* Logical block size. */ extern u_int blksz; /* Physical block size. */ +extern uint32_t active_partition; static inline lba_t round_block(lba_t n) @@ -89,7 +91,17 @@ ssize_t sparse_write(int, const void *, size_t); void mkimg_chs(lba_t, u_int, u_int *, u_int *, u_int *); -struct uuid; -void mkimg_uuid(struct uuid *); +struct mkimg_uuid { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi_and_reserved; + uint8_t clock_seq_low; + uint8_t node[6]; +}; +typedef struct mkimg_uuid mkimg_uuid_t; + +void mkimg_uuid(mkimg_uuid_t *); +void mkimg_uuid_enc(void *, const mkimg_uuid_t *); #endif /* _MKIMG_MKIMG_H_ */ diff --git a/usr.bin/mkimg/pc98.c b/usr.bin/mkimg/pc98.c index 867c8b1ebcbf..000b26d5bfe6 100644 --- a/usr.bin/mkimg/pc98.c +++ b/usr.bin/mkimg/pc98.c @@ -33,26 +33,13 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" -#ifndef PC98_MAGIC -#define PC98_MAGIC 0xaa55 -#endif -#ifndef PC98_MAGICOFS -#define PC98_MAGICOFS 510 -#endif -#ifndef PC98_NPARTS -#define PC98_NPARTS 16 -#endif -#ifndef PC98_PTYP_386BSD -#define PC98_PTYP_386BSD 0xc494 -#endif - #define PC98_BOOTCODESZ 8192 static struct mkimg_alias pc98_aliases[] = { diff --git a/usr.bin/mkimg/uuid.c b/usr.bin/mkimg/uuid.c new file mode 100644 index 000000000000..437675dbefef --- /dev/null +++ b/usr.bin/mkimg/uuid.c @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 2016 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include "endian.h" +#include "image.h" +#include "mkimg.h" + +static void osdep_uuidgen(mkimg_uuid_t *); + +#ifdef __APPLE__ +#include + +static void +osdep_uuidgen(mkimg_uuid_t *uuid) +{ + + uuid_generate_time((void *)uuid); +} +#endif /* __APPLE__ */ + +#ifdef __FreeBSD__ +#include + +static void +osdep_uuidgen(mkimg_uuid_t *uuid) +{ + + uuidgen((void *)uuid, 1); +} +#endif /* __FreeBSD__ */ + +#ifdef __linux__ +#include +#include + +static void +osdep_uuidgen(mkimg_uuid_t *uuid) +{ + struct timespec tp; + uint64_t time = 0x01B21DD213814000LL; + u_int i; + uint16_t seq; + + if (clock_gettime(CLOCK_REALTIME, &tp) == -1) + abort(); + + time += (uint64_t)tp.tv_sec * 10000000LL; + time += tp.tv_nsec / 100; + + uuid->time_low = (uint32_t)time; + uuid->time_mid = (uint16_t)(time >> 32); + uuid->time_hi_and_version = (uint16_t)(time >> 48) & 0xfff; + uuid->time_hi_and_version |= 1 << 12; + + seq = random(); + + uuid->clock_seq_hi_and_reserved = (uint8_t)(seq >> 8) & 0x3f; + uuid->clock_seq_low = (uint8_t)seq; + + for (i = 0; i < 6; i++) + uuid->node[i] = (uint8_t)random(); + uuid->node[0] |= 0x01; +} +#endif /* __linux__ */ + +void +mkimg_uuid(mkimg_uuid_t *uuid) +{ + static uint8_t gen[sizeof(mkimg_uuid_t)]; + u_int i; + + if (!unit_testing) { + osdep_uuidgen(uuid); + return; + } + + for (i = 0; i < sizeof(gen); i++) + gen[i]++; + memcpy(uuid, gen, sizeof(*uuid)); +} + +void +mkimg_uuid_enc(void *buf, const mkimg_uuid_t *uuid) +{ + uint8_t *p = buf; + u_int i; + + le32enc(p, uuid->time_low); + le16enc(p + 4, uuid->time_mid); + le16enc(p + 6, uuid->time_hi_and_version); + p[8] = uuid->clock_seq_hi_and_reserved; + p[9] = uuid->clock_seq_low; + for (i = 0; i < 6; i++) + p[10 + i] = uuid->node[i]; +} diff --git a/usr.bin/mkimg/vhd.c b/usr.bin/mkimg/vhd.c index bc8d02b47fd0..31a527a96deb 100644 --- a/usr.bin/mkimg/vhd.c +++ b/usr.bin/mkimg/vhd.c @@ -33,7 +33,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include "endian.h" #include "image.h" @@ -92,7 +91,7 @@ struct vhd_footer { #define VHD_DISK_TYPE_DYNAMIC 3 #define VHD_DISK_TYPE_DIFF 4 uint32_t checksum; - uuid_t id; + mkimg_uuid_t id; uint8_t saved_state; uint8_t _reserved[427]; }; @@ -200,26 +199,11 @@ vhd_timestamp(void) return (0x01234567); } -static void -vhd_uuid_enc(void *buf, const uuid_t *uuid) -{ - uint8_t *p = buf; - int i; - - be32enc(p, uuid->time_low); - be16enc(p + 4, uuid->time_mid); - be16enc(p + 6, uuid->time_hi_and_version); - p[8] = uuid->clock_seq_hi_and_reserved; - p[9] = uuid->clock_seq_low; - for (i = 0; i < _UUID_NODE_LEN; i++) - p[10 + i] = uuid->node[i]; -} - static void vhd_make_footer(struct vhd_footer *footer, uint64_t image_size, uint32_t disk_type, uint64_t data_offset) { - uuid_t id; + mkimg_uuid_t id; memset(footer, 0, sizeof(*footer)); be64enc(&footer->cookie, VHD_FOOTER_COOKIE); @@ -236,7 +220,7 @@ vhd_make_footer(struct vhd_footer *footer, uint64_t image_size, be16enc(&footer->geometry.cylinders, footer->geometry.cylinders); be32enc(&footer->disk_type, disk_type); mkimg_uuid(&id); - vhd_uuid_enc(&footer->id, &id); + mkimg_uuid_enc(&footer->id, &id); be32enc(&footer->checksum, vhd_checksum(footer, sizeof(*footer))); } @@ -261,7 +245,7 @@ struct vhd_dyn_header { uint32_t max_entries; uint32_t block_size; uint32_t checksum; - uuid_t parent_id; + mkimg_uuid_t parent_id; uint32_t parent_timestamp; char _reserved1[4]; uint16_t parent_name[256]; /* UTF-16 */ diff --git a/usr.bin/mkimg/vtoc8.c b/usr.bin/mkimg/vtoc8.c index a7409b8551d2..cf9c4bafb255 100644 --- a/usr.bin/mkimg/vtoc8.c +++ b/usr.bin/mkimg/vtoc8.c @@ -34,17 +34,13 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include "endian.h" #include "image.h" #include "mkimg.h" #include "scheme.h" -#ifndef VTOC_TAG_FREEBSD_NANDFS -#define VTOC_TAG_FREEBSD_NANDFS 0x0905 -#endif - static struct mkimg_alias vtoc8_aliases[] = { { ALIAS_FREEBSD_NANDFS, ALIAS_INT2TYPE(VTOC_TAG_FREEBSD_NANDFS) }, { ALIAS_FREEBSD_SWAP, ALIAS_INT2TYPE(VTOC_TAG_FREEBSD_SWAP) }, diff --git a/usr.bin/printenv/printenv.c b/usr.bin/printenv/printenv.c index 315833e85a75..27882ab91ce3 100644 --- a/usr.bin/printenv/printenv.c +++ b/usr.bin/printenv/printenv.c @@ -83,8 +83,8 @@ main(int argc, char *argv[]) for (ep = environ; *ep; ep++) if (!memcmp(*ep, *argv, len)) { cp = *ep + len; - if (!*cp || *cp == '=') { - (void)printf("%s\n", *cp ? cp + 1 : cp); + if (*cp == '=') { + (void)printf("%s\n", cp + 1); exit(0); } } diff --git a/usr.bin/truss/Makefile b/usr.bin/truss/Makefile index 480dab0782d9..d077eda07cf3 100644 --- a/usr.bin/truss/Makefile +++ b/usr.bin/truss/Makefile @@ -1,12 +1,13 @@ # $FreeBSD$ -NO_WERROR= +#NO_WERROR= PROG= truss SRCS= main.c setup.c syscalls.c LIBADD= sysdecode -CFLAGS+= -I${.CURDIR} -I. -I${.CURDIR}/../../sys +#CFLAGS+= -I${.CURDIR} -I. -I${.CURDIR}/../../sys +CFLAGS+= -I${.CURDIR}/../../sys ABIS+= freebsd # Each ABI is expected to have an ABI.c, MACHINE_ARCH-ABI.c or diff --git a/usr.bin/truss/aarch64-cloudabi64.c b/usr.bin/truss/aarch64-cloudabi64.c index 27906ea9204f..6a1694a965df 100644 --- a/usr.bin/truss/aarch64-cloudabi64.c +++ b/usr.bin/truss/aarch64-cloudabi64.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include diff --git a/usr.bin/truss/aarch64-freebsd.c b/usr.bin/truss/aarch64-freebsd.c index 534441c60b8c..a9944f52f4fd 100644 --- a/usr.bin/truss/aarch64-freebsd.c +++ b/usr.bin/truss/aarch64-freebsd.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include diff --git a/usr.bin/truss/amd64-cloudabi64.c b/usr.bin/truss/amd64-cloudabi64.c index f7d7c1aa1442..06de94474c1e 100644 --- a/usr.bin/truss/amd64-cloudabi64.c +++ b/usr.bin/truss/amd64-cloudabi64.c @@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include diff --git a/usr.bin/truss/amd64-freebsd.c b/usr.bin/truss/amd64-freebsd.c index a2f378ca8ea5..fa844fa09340 100644 --- a/usr.bin/truss/amd64-freebsd.c +++ b/usr.bin/truss/amd64-freebsd.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include diff --git a/usr.bin/truss/amd64-freebsd32.c b/usr.bin/truss/amd64-freebsd32.c index cfcead2a6014..adbc3e74c0c5 100644 --- a/usr.bin/truss/amd64-freebsd32.c +++ b/usr.bin/truss/amd64-freebsd32.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include diff --git a/usr.bin/truss/amd64-linux.c b/usr.bin/truss/amd64-linux.c index 439780402bb7..94a3d6abce94 100644 --- a/usr.bin/truss/amd64-linux.c +++ b/usr.bin/truss/amd64-linux.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include diff --git a/usr.bin/truss/amd64-linux32.c b/usr.bin/truss/amd64-linux32.c index 279d2285b3b3..3f32c8473f37 100644 --- a/usr.bin/truss/amd64-linux32.c +++ b/usr.bin/truss/amd64-linux32.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include diff --git a/usr.bin/truss/arm-freebsd.c b/usr.bin/truss/arm-freebsd.c index a1b2b21313ba..826a8d838294 100644 --- a/usr.bin/truss/arm-freebsd.c +++ b/usr.bin/truss/arm-freebsd.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include diff --git a/usr.bin/truss/extern.h b/usr.bin/truss/extern.h index 5ce3d3be8ec6..2cdd9c5f964c 100644 --- a/usr.bin/truss/extern.h +++ b/usr.bin/truss/extern.h @@ -37,4 +37,3 @@ extern void start_tracing(struct trussinfo *, pid_t); extern void restore_proc(int); extern void eventloop(struct trussinfo *); extern const char *ioctlname(unsigned long val); -extern char *strsig(int sig); diff --git a/usr.bin/truss/i386-freebsd.c b/usr.bin/truss/i386-freebsd.c index bf35af2f015b..469ab7de9b7a 100644 --- a/usr.bin/truss/i386-freebsd.c +++ b/usr.bin/truss/i386-freebsd.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include diff --git a/usr.bin/truss/i386-linux.c b/usr.bin/truss/i386-linux.c index 52232b41d450..56fab65cefb7 100644 --- a/usr.bin/truss/i386-linux.c +++ b/usr.bin/truss/i386-linux.c @@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include diff --git a/usr.bin/truss/main.c b/usr.bin/truss/main.c index 38626fd3acc3..84fd37e2a4d8 100644 --- a/usr.bin/truss/main.c +++ b/usr.bin/truss/main.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -61,18 +62,6 @@ usage(void) exit(1); } -char * -strsig(int sig) -{ - static char tmp[64]; - - if (sig > 0 && sig < NSIG) { - snprintf(tmp, sizeof(tmp), "SIG%s", sys_signame[sig]); - return (tmp); - } - return (NULL); -} - int main(int ac, char **av) { diff --git a/usr.bin/truss/mips-freebsd.c b/usr.bin/truss/mips-freebsd.c index 3a42a59d7323..ac803b942f27 100644 --- a/usr.bin/truss/mips-freebsd.c +++ b/usr.bin/truss/mips-freebsd.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include diff --git a/usr.bin/truss/powerpc-freebsd.c b/usr.bin/truss/powerpc-freebsd.c index ee78d038297a..dbeba2b36baf 100644 --- a/usr.bin/truss/powerpc-freebsd.c +++ b/usr.bin/truss/powerpc-freebsd.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include diff --git a/usr.bin/truss/powerpc64-freebsd.c b/usr.bin/truss/powerpc64-freebsd.c index cc64cd685e7e..a8927bb5cc7c 100644 --- a/usr.bin/truss/powerpc64-freebsd.c +++ b/usr.bin/truss/powerpc64-freebsd.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include diff --git a/usr.bin/truss/powerpc64-freebsd32.c b/usr.bin/truss/powerpc64-freebsd32.c index c6f3b10a7092..bc8d2fc97a7f 100644 --- a/usr.bin/truss/powerpc64-freebsd32.c +++ b/usr.bin/truss/powerpc64-freebsd32.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include diff --git a/usr.bin/truss/setup.c b/usr.bin/truss/setup.c index a14c01664ef5..036cb8f40ccc 100644 --- a/usr.bin/truss/setup.c +++ b/usr.bin/truss/setup.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -591,14 +592,15 @@ static void report_signal(struct trussinfo *info, siginfo_t *si) { struct threadinfo *t; - char *signame; + const char *signame; t = info->curthread; clock_gettime(CLOCK_REALTIME, &t->after); print_line_prefix(info); - signame = strsig(si->si_status); - fprintf(info->outfile, "SIGNAL %u (%s)\n", si->si_status, - signame == NULL ? "?" : signame); + signame = sysdecode_signal(si->si_status); + if (signame == NULL) + signame = "?"; + fprintf(info->outfile, "SIGNAL %u (%s)\n", si->si_status, signame); } /* diff --git a/usr.bin/truss/sparc64-freebsd.c b/usr.bin/truss/sparc64-freebsd.c index a8569c010e06..3cbad50df70b 100644 --- a/usr.bin/truss/sparc64-freebsd.c +++ b/usr.bin/truss/sparc64-freebsd.c @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include diff --git a/usr.bin/truss/syscall.h b/usr.bin/truss/syscall.h index 906f799b64b3..0cd752d77a03 100644 --- a/usr.bin/truss/syscall.h +++ b/usr.bin/truss/syscall.h @@ -44,7 +44,7 @@ enum Argtype { None = 1, Hex, Octal, Int, UInt, LongHex, Name, Ptr, Stat, Ioctl, Fcntlflag, Rusage, BinString, Shutdown, Resource, Rlimit, Timeval2, Pathconf, Rforkflags, ExitStatus, Waitoptions, Idtype, Procctl, LinuxSockArgs, Umtxop, Atfd, Atflags, Timespec2, Accessmode, Long, - Sysarch, ExecArgs, ExecEnv, PipeFds, QuadHex, Utrace, IntArray, + Sysarch, ExecArgs, ExecEnv, PipeFds, QuadHex, Utrace, IntArray, Pipe2, CloudABIAdvice, CloudABIClockID, ClouduABIFDSFlags, CloudABIFDStat, CloudABIFileStat, CloudABIFileType, diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c index 855f5d35f45d..46bc87f9575b 100644 --- a/usr.bin/truss/syscalls.c +++ b/usr.bin/truss/syscalls.c @@ -40,14 +40,11 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include -#include #include #include #include #include -#include #include #include #include @@ -60,13 +57,10 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include #include #include #include #include -#include #include #include @@ -256,7 +250,7 @@ static struct syscall decoded_syscalls[] = { { .name = "pipe", .ret_type = 1, .nargs = 1, .args = { { PipeFds | OUT, 0 } } }, { .name = "pipe2", .ret_type = 1, .nargs = 2, - .args = { { Ptr, 0 }, { Open, 1 } } }, + .args = { { Ptr, 0 }, { Pipe2, 1 } } }, { .name = "poll", .ret_type = 1, .nargs = 3, .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } }, { .name = "posix_openpt", .ret_type = 1, .nargs = 1, @@ -553,83 +547,11 @@ static struct xlat poll_flags[] = { X(POLLWRBAND) X(POLLINIGNEOF) XEND }; -static struct xlat mmap_flags[] = { - X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RESERVED0020) - X(MAP_RESERVED0040) X(MAP_RESERVED0080) X(MAP_RESERVED0100) - X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON) - X(MAP_EXCL) X(MAP_NOCORE) X(MAP_PREFAULT_READ) -#ifdef MAP_32BIT - X(MAP_32BIT) -#endif - XEND -}; - -static struct xlat mprot_flags[] = { - X(PROT_NONE) X(PROT_READ) X(PROT_WRITE) X(PROT_EXEC) XEND -}; - -static struct xlat whence_arg[] = { - X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) X(SEEK_DATA) X(SEEK_HOLE) XEND -}; - static struct xlat sigaction_flags[] = { X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP) X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND }; -static struct xlat fcntl_arg[] = { - X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL) - X(F_GETOWN) X(F_SETOWN) X(F_OGETLK) X(F_OSETLK) X(F_OSETLKW) - X(F_DUP2FD) X(F_GETLK) X(F_SETLK) X(F_SETLKW) X(F_SETLK_REMOTE) - X(F_READAHEAD) X(F_RDAHEAD) X(F_DUPFD_CLOEXEC) X(F_DUP2FD_CLOEXEC) - XEND -}; - -static struct xlat fcntlfd_arg[] = { - X(FD_CLOEXEC) XEND -}; - -static struct xlat fcntlfl_arg[] = { - X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW) - X(FRDAHEAD) X(O_DIRECT) XEND -}; - -static struct xlat sockdomain_arg[] = { - X(PF_UNSPEC) X(PF_LOCAL) X(PF_UNIX) X(PF_INET) X(PF_IMPLINK) - X(PF_PUP) X(PF_CHAOS) X(PF_NETBIOS) X(PF_ISO) X(PF_OSI) - X(PF_ECMA) X(PF_DATAKIT) X(PF_CCITT) X(PF_SNA) X(PF_DECnet) - X(PF_DLI) X(PF_LAT) X(PF_HYLINK) X(PF_APPLETALK) X(PF_ROUTE) - X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX) - X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6) - X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER) - X(PF_ARP) X(PF_BLUETOOTH) X(PF_IEEE80211) X(PF_INET_SDP) - X(PF_INET6_SDP) XEND -}; - -static struct xlat socktype_arg[] = { - X(SOCK_STREAM) X(SOCK_DGRAM) X(SOCK_RAW) X(SOCK_RDM) - X(SOCK_SEQPACKET) XEND -}; - -static struct xlat open_flags[] = { - X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK) - X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC) - X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY) - X(O_DIRECT) X(O_DIRECTORY) X(O_EXEC) X(O_TTY_INIT) X(O_CLOEXEC) - X(O_VERIFY) XEND -}; - -static struct xlat shutdown_arg[] = { - X(SHUT_RD) X(SHUT_WR) X(SHUT_RDWR) XEND -}; - -static struct xlat resource_arg[] = { - X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK) - X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC) - X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) X(RLIMIT_NPTS) - X(RLIMIT_SWAP) X(RLIMIT_KQUEUES) XEND -}; - static struct xlat pathconf_arg[] = { X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT) X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF) @@ -643,50 +565,11 @@ static struct xlat pathconf_arg[] = { X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND }; -static struct xlat rfork_flags[] = { - X(RFFDG) X(RFPROC) X(RFMEM) X(RFNOWAIT) X(RFCFDG) X(RFTHREAD) - X(RFSIGSHARE) X(RFLINUXTHPN) X(RFTSIGZMB) X(RFPPWAIT) XEND -}; - -static struct xlat wait_options[] = { - X(WNOHANG) X(WUNTRACED) X(WCONTINUED) X(WNOWAIT) X(WEXITED) - X(WTRAPPED) XEND -}; - -static struct xlat idtype_arg[] = { - X(P_PID) X(P_PPID) X(P_PGID) X(P_SID) X(P_CID) X(P_UID) X(P_GID) - X(P_ALL) X(P_LWPID) X(P_TASKID) X(P_PROJID) X(P_POOLID) X(P_JAILID) - X(P_CTID) X(P_CPUID) X(P_PSETID) XEND -}; - -static struct xlat procctl_arg[] = { - X(PROC_SPROTECT) X(PROC_REAP_ACQUIRE) X(PROC_REAP_RELEASE) - X(PROC_REAP_STATUS) X(PROC_REAP_GETPIDS) X(PROC_REAP_KILL) - X(PROC_TRACE_CTL) X(PROC_TRACE_STATUS) XEND -}; - -static struct xlat umtx_ops[] = { - X(UMTX_OP_RESERVED0) X(UMTX_OP_RESERVED1) X(UMTX_OP_WAIT) - X(UMTX_OP_WAKE) X(UMTX_OP_MUTEX_TRYLOCK) X(UMTX_OP_MUTEX_LOCK) - X(UMTX_OP_MUTEX_UNLOCK) X(UMTX_OP_SET_CEILING) X(UMTX_OP_CV_WAIT) - X(UMTX_OP_CV_SIGNAL) X(UMTX_OP_CV_BROADCAST) X(UMTX_OP_WAIT_UINT) - X(UMTX_OP_RW_RDLOCK) X(UMTX_OP_RW_WRLOCK) X(UMTX_OP_RW_UNLOCK) - X(UMTX_OP_WAIT_UINT_PRIVATE) X(UMTX_OP_WAKE_PRIVATE) - X(UMTX_OP_MUTEX_WAIT) X(UMTX_OP_MUTEX_WAKE) X(UMTX_OP_SEM_WAIT) - X(UMTX_OP_SEM_WAKE) X(UMTX_OP_NWAKE_PRIVATE) X(UMTX_OP_MUTEX_WAKE2) - X(UMTX_OP_SEM2_WAIT) X(UMTX_OP_SEM2_WAKE) - XEND -}; - static struct xlat at_flags[] = { X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW) X(AT_REMOVEDIR) XEND }; -static struct xlat access_modes[] = { - X(R_OK) X(W_OK) X(X_OK) XEND -}; - static struct xlat sysarch_ops[] = { #if defined(__i386__) || defined(__amd64__) X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM) @@ -707,11 +590,6 @@ static struct xlat linux_socketcall_ops[] = { XEND }; -static struct xlat sigprocmask_ops[] = { - X(SIG_BLOCK) X(SIG_UNBLOCK) X(SIG_SETMASK) - XEND -}; - #undef X #define X(a) { CLOUDABI_##a, #a }, @@ -909,6 +787,29 @@ xlookup_bits(struct xlat *xlat, int val) return (str); } +static void +print_integer_arg(const char *(*decoder)(int), FILE *fp, int value) +{ + const char *str; + + str = decoder(value); + if (str != NULL) + fputs(str, fp); + else + fprintf(fp, "%d", value); +} + +static void +print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value) +{ + int rem; + + if (!decoder(fp, value, &rem)) + fprintf(fp, "0x%x", rem); + else if (rem != 0) + fprintf(fp, "|0x%x", rem); +} + void init_syscalls(void) { @@ -1028,18 +929,18 @@ get_string(pid_t pid, void *addr, int max) } } -static char * +static const char * strsig2(int sig) { - static char tmp[sizeof(int) * 3 + 1]; - char *ret; + static char tmp[32]; + const char *signame; - ret = strsig(sig); - if (ret == NULL) { + signame = sysdecode_signal(sig); + if (signame == NULL) { snprintf(tmp, sizeof(tmp), "%d", sig); - ret = tmp; + signame = tmp; } - return (ret); + return (signame); } static void @@ -1493,7 +1394,7 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval, for (i = 1; i < sys_nsig; i++) { if (sigismember(&ss, i)) { fprintf(fp, "%s%s", !first ? "|" : "", - strsig(i)); + strsig2(i)); first = 0; } } @@ -1502,92 +1403,48 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval, fputc('}', fp); break; } - case Sigprocmask: { - fputs(xlookup(sigprocmask_ops, args[sc->offset]), fp); + case Sigprocmask: + print_integer_arg(sysdecode_sigprocmask_how, fp, + args[sc->offset]); break; - } - case Fcntlflag: { + case Fcntlflag: /* XXX: Output depends on the value of the previous argument. */ - switch (args[sc->offset - 1]) { - case F_SETFD: - fputs(xlookup_bits(fcntlfd_arg, args[sc->offset]), fp); - break; - case F_SETFL: - fputs(xlookup_bits(fcntlfl_arg, args[sc->offset]), fp); - break; - case F_GETFD: - case F_GETFL: - case F_GETOWN: - break; - default: - fprintf(fp, "0x%lx", args[sc->offset]); - break; - } + if (sysdecode_fcntl_arg_p(args[sc->offset - 1])) + sysdecode_fcntl_arg(fp, args[sc->offset - 1], + args[sc->offset], 16); break; - } case Open: - fputs(xlookup_bits(open_flags, args[sc->offset]), fp); + print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]); break; case Fcntl: - fputs(xlookup(fcntl_arg, args[sc->offset]), fp); + print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]); break; case Mprot: - fputs(xlookup_bits(mprot_flags, args[sc->offset]), fp); + print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]); break; - case Mmapflags: { - int align, flags; - - /* - * MAP_ALIGNED can't be handled by xlookup_bits(), so - * generate that string manually and prepend it to the - * string from xlookup_bits(). Have to be careful to - * avoid outputting MAP_ALIGNED|0 if MAP_ALIGNED is - * the only flag. - */ - flags = args[sc->offset] & ~MAP_ALIGNMENT_MASK; - align = args[sc->offset] & MAP_ALIGNMENT_MASK; - if (align != 0) { - if (align == MAP_ALIGNED_SUPER) - fputs("MAP_ALIGNED_SUPER", fp); - else - fprintf(fp, "MAP_ALIGNED(%d)", - align >> MAP_ALIGNMENT_SHIFT); - if (flags == 0) - break; - fputc('|', fp); - } - fputs(xlookup_bits(mmap_flags, flags), fp); + case Mmapflags: + print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]); break; - } case Whence: - fputs(xlookup(whence_arg, args[sc->offset]), fp); + print_integer_arg(sysdecode_whence, fp, args[sc->offset]); break; case Sockdomain: - fputs(xlookup(sockdomain_arg, args[sc->offset]), fp); + print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]); break; - case Socktype: { - int type, flags; - - flags = args[sc->offset] & (SOCK_CLOEXEC | SOCK_NONBLOCK); - type = args[sc->offset] & ~flags; - fputs(xlookup(socktype_arg, type), fp); - if (flags & SOCK_CLOEXEC) - fprintf(fp, "|SOCK_CLOEXEC"); - if (flags & SOCK_NONBLOCK) - fprintf(fp, "|SOCK_NONBLOCK"); + case Socktype: + print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]); break; - } case Shutdown: - fputs(xlookup(shutdown_arg, args[sc->offset]), fp); + print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]); break; case Resource: - fputs(xlookup(resource_arg, args[sc->offset]), fp); + print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]); break; case Pathconf: fputs(xlookup(pathconf_arg, args[sc->offset]), fp); break; case Rforkflags: - fputs(xlookup_bits(rfork_flags, args[sc->offset]), fp); + print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]); break; case Sockaddr: { char addr[64]; @@ -1818,31 +1675,25 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval, break; } case Waitoptions: - fputs(xlookup_bits(wait_options, args[sc->offset]), fp); + print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]); break; case Idtype: - fputs(xlookup(idtype_arg, args[sc->offset]), fp); + print_integer_arg(sysdecode_idtype, fp, args[sc->offset]); break; case Procctl: - fputs(xlookup(procctl_arg, args[sc->offset]), fp); + print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]); break; case Umtxop: - fputs(xlookup(umtx_ops, args[sc->offset]), fp); + print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]); break; case Atfd: - if ((int)args[sc->offset] == AT_FDCWD) - fputs("AT_FDCWD", fp); - else - fprintf(fp, "%d", (int)args[sc->offset]); + print_integer_arg(sysdecode_atfd, fp, args[sc->offset]); break; case Atflags: fputs(xlookup_bits(at_flags, args[sc->offset]), fp); break; case Accessmode: - if (args[sc->offset] == F_OK) - fputs("F_OK", fp); - else - fputs(xlookup_bits(access_modes, args[sc->offset]), fp); + print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]); break; case Sysarch: fputs(xlookup(sysarch_ops, args[sc->offset]), fp); @@ -1898,6 +1749,9 @@ print_arg(struct syscall_args *sc, unsigned long *args, long *retval, fprintf(fp, "0x%lx", args[sc->offset]); break; } + case Pipe2: + print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]); + break; case CloudABIAdvice: fputs(xlookup(cloudabi_advice, args[sc->offset]), fp); diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8 index f1e713ea76e2..6453d2508888 100644 --- a/usr.sbin/bhyve/bhyve.8 +++ b/usr.sbin/bhyve/bhyve.8 @@ -172,7 +172,7 @@ Virtio block storage interface. .It Li virtio-rnd Virtio RNG interface. .It Li ahci -AHCI controller attached to arbitraty devices. +AHCI controller attached to arbitrary devices. .It Li ahci-cd AHCI controller attached to an ATAPI CD/DVD. .It Li ahci-hd diff --git a/usr.sbin/bsdconfig/share/sysrc.subr b/usr.sbin/bsdconfig/share/sysrc.subr index 346bf10b3f4a..950089ab3eb1 100644 --- a/usr.sbin/bsdconfig/share/sysrc.subr +++ b/usr.sbin/bsdconfig/share/sysrc.subr @@ -256,7 +256,9 @@ f_sysrc_service_configs() last_name= print_name() { local name="$1" - [ "$name" = "$last_name" ] && return + case "$name" in + ""|.|..|*/*|"$last_name") return ;; + esac echo "$name" >&9 last_name="$name" } diff --git a/usr.sbin/efivar/efivar.c b/usr.sbin/efivar/efivar.c index a4dac498d680..994cc8dfb19e 100644 --- a/usr.sbin/efivar/efivar.c +++ b/usr.sbin/efivar/efivar.c @@ -62,7 +62,7 @@ static struct option longopts[] = { static int aflag, Aflag, bflag, dflag, Dflag, Hflag, Nflag, lflag, Lflag, Rflag, wflag, pflag; static char *varname; -static u_long attrib = EFI_VARIABLE_NON_VOLATILE |EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; +static u_long attrib = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; static void usage(void) diff --git a/usr.sbin/fstyp/Makefile b/usr.sbin/fstyp/Makefile index 5eba12bcabf7..2397b806c8b9 100644 --- a/usr.sbin/fstyp/Makefile +++ b/usr.sbin/fstyp/Makefile @@ -14,8 +14,9 @@ MAN= fstyp.8 WARNS?= 2 .include +.include -.if ${MK_TESTS} != "no" +.if ${MK_TESTS} != "no" && ${TARGET_ENDIANNESS} == 1234 SUBDIR+= tests .endif diff --git a/usr.sbin/pciconf/pciconf.c b/usr.sbin/pciconf/pciconf.c index d62ce77f6ccf..1bc5526a61aa 100644 --- a/usr.sbin/pciconf/pciconf.c +++ b/usr.sbin/pciconf/pciconf.c @@ -697,6 +697,9 @@ static struct {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "entertainment crypto"}, {PCIC_DASP, -1, "dasp"}, {PCIC_DASP, PCIS_DASP_DPIO, "DPIO module"}, + {PCIC_DASP, PCIS_DASP_PERFCNTRS, "performance counters"}, + {PCIC_DASP, PCIS_DASP_COMM_SYNC, "communication synchronizer"}, + {PCIC_DASP, PCIS_DASP_MGMT_CARD, "signal processing management"}, {0, 0, NULL} }; diff --git a/usr.sbin/pmcstat/pmcstat_log.h b/usr.sbin/pmcstat/pmcstat_log.h index b4ced4d9397b..32a22f45063f 100644 --- a/usr.sbin/pmcstat/pmcstat_log.h +++ b/usr.sbin/pmcstat/pmcstat_log.h @@ -76,7 +76,6 @@ enum pmcstat_image_type { struct pmcstat_image { LIST_ENTRY(pmcstat_image) pi_next; /* hash link */ - TAILQ_ENTRY(pmcstat_image) pi_lru; /* LRU list */ pmcstat_interned_string pi_execpath; /* cookie */ pmcstat_interned_string pi_samplename; /* sample path name */ pmcstat_interned_string pi_fullpath; /* path to FS object */