From 9a34695ace03c6cf7bf16f38837d5c90c310d5db Mon Sep 17 00:00:00 2001 From: gallatin Date: Sun, 19 Feb 2006 22:39:19 +0000 Subject: [PATCH] 10GbE mode driver and binary firmware for Myricom's PCI-express NICs. More info regarding these nics can be found at http://www.myri.com. Please note that the files sys/dev/myri10ge/{mcp_gen_header.h,myri10ge_mcp.h} are internally shared between all our drivers (solaris, macosx, windows, linux, etc). I'd like to keep these files unchanged, so I can just import newer versions of them when the firmware API/ABI changes. This means I'm stuck with some of the crazy-long #define names, and possibly non-style(9) characteristics of these files. Many thanks to mlaier for doing firmware(9) just as I needed it, and to scottl for his helpful review. Reviewed by: scottl, glebius Sponsored by: Myricom Inc. --- share/man/man4/mxge.4 | 146 + share/man/man4/myri10ge.4 | 146 + sys/dev/mxge/eth_z8e.dat.gz.uu | 633 +++++ sys/dev/mxge/ethp_z8e.dat.gz.uu | 639 +++++ sys/dev/mxge/if_mxge.c | 2489 +++++++++++++++++ sys/dev/mxge/if_mxge_var.h | 203 ++ sys/dev/mxge/mcp_gen_header.h | 107 + sys/dev/mxge/mxge_mcp.h | 265 ++ sys/dev/myri10ge/eth_z8e.dat.gz.uu | 633 +++++ sys/dev/myri10ge/ethp_z8e.dat.gz.uu | 639 +++++ sys/dev/myri10ge/if_myri10ge.c | 2489 +++++++++++++++++ sys/dev/myri10ge/if_myri10ge_var.h | 203 ++ sys/dev/myri10ge/mcp_gen_header.h | 107 + sys/dev/myri10ge/myri10ge_mcp.h | 265 ++ sys/modules/mxge/Makefile | 7 + sys/modules/mxge/mxge/Makefile | 8 + sys/modules/mxge/mxge_eth_z8e/Makefile | 13 + sys/modules/mxge/mxge_ethp_z8e/Makefile | 13 + sys/modules/myri10ge/Makefile | 7 + sys/modules/myri10ge/myri10ge/Makefile | 8 + .../myri10ge/myri10ge_eth_z8e/Makefile | 13 + .../myri10ge/myri10ge_ethp_z8e/Makefile | 13 + 22 files changed, 9046 insertions(+) create mode 100644 share/man/man4/mxge.4 create mode 100644 share/man/man4/myri10ge.4 create mode 100644 sys/dev/mxge/eth_z8e.dat.gz.uu create mode 100644 sys/dev/mxge/ethp_z8e.dat.gz.uu create mode 100644 sys/dev/mxge/if_mxge.c create mode 100644 sys/dev/mxge/if_mxge_var.h create mode 100644 sys/dev/mxge/mcp_gen_header.h create mode 100644 sys/dev/mxge/mxge_mcp.h create mode 100644 sys/dev/myri10ge/eth_z8e.dat.gz.uu create mode 100644 sys/dev/myri10ge/ethp_z8e.dat.gz.uu create mode 100644 sys/dev/myri10ge/if_myri10ge.c create mode 100644 sys/dev/myri10ge/if_myri10ge_var.h create mode 100644 sys/dev/myri10ge/mcp_gen_header.h create mode 100644 sys/dev/myri10ge/myri10ge_mcp.h create mode 100644 sys/modules/mxge/Makefile create mode 100644 sys/modules/mxge/mxge/Makefile create mode 100644 sys/modules/mxge/mxge_eth_z8e/Makefile create mode 100644 sys/modules/mxge/mxge_ethp_z8e/Makefile create mode 100644 sys/modules/myri10ge/Makefile create mode 100644 sys/modules/myri10ge/myri10ge/Makefile create mode 100644 sys/modules/myri10ge/myri10ge_eth_z8e/Makefile create mode 100644 sys/modules/myri10ge/myri10ge_ethp_z8e/Makefile diff --git a/share/man/man4/mxge.4 b/share/man/man4/mxge.4 new file mode 100644 index 000000000000..c78c6b12a477 --- /dev/null +++ b/share/man/man4/mxge.4 @@ -0,0 +1,146 @@ +.\" Copyright (c) 2006, Myricom 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. +.\" +.\" 3. Neither the name of the Myricom Inc nor the names of its +.\" contributors may be used to endorse or promote products derived from +.\" this software without specific prior written permission. +.\" +.\" 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. +.\" +.\" * Other names and brands may be claimed as the property of others. +.\" +.\" $FreeBSD$ +.\" +.Dd February 9, 2006 +.Dt MYRI10GE 4 +.Os +.Sh NAME +.Nm myri10ge +.Nd "Myricom Myri10GE 10 Gigabit Ethernet adapter driver" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device firmware" +.Cd "device myri10ge" +.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_myri10ge_load="YES" +myri10ge_ethp_z8e_load="YES" +myri10ge_eth_z8e_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for PCI Express 10 Gigabit Ethernet adapters based on +the Myricom LANai Z8E chip. +The driver supports Transmit/Receive checksum offload +and Jumbo Frames. +For further hardware information, see http://www.myri.com +.Pp +For questions related to hardware requirements, +refer to the documentation supplied with your Myri10GE adapter. +All hardware requirements listed apply to use with +.Fx . +.Pp +Support for Jumbo Frames is provided via the interface MTU setting. +Selecting an MTU larger than 1500 bytes with the +.Xr ifconfig 8 +utility configures the adapter to receive and transmit Jumbo Frames. +The maximum MTU size for Jumbo Frames is 9000. +.Pp +For more information on configuring this device, see +.Xr ifconfig 8 . +.Sh HARDWARE +The +.Nm +driver supports 10 Gigabit Ethernet adapters based on the +Myricom LANai Z8E chips: +.Pp +.Bl -bullet -compact +.It +Myricom 10GBase-CX4 (10G-PCIE-8A-C, 10G-PCIE-8AL-C) +.It +Myricom 10GBase-R (10G-PCIE-8A-R, 10G-PCIE-8AL-R) +.It +Myricom 10G XAUI over ribbon fiber (10G-PCIE-8A-Q, 10G-PCIE-8AL-Q) +.El +.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 hw.myri10ge.flow_control_enabled +Whether or not hardware flow control is enabled on the adapter. +The default value is 1. +.It Va hw.myri10ge.intr_coal_delay +This value delays the generation of all interrupts in units of +1 microsecond. The default value is 30. +.It Va hw.myri10ge.skip_pio_read +This value determines whether or not the driver may omit doing a +pio read in the interrupt handler which ensures that the interrupt +line has been deasserted when using xPIC interrupts. A non-zero value +may result in lower CPU overhead, however it may also result in +spurious interrupts. The default value is 0. +.El +.Sh DIAGNOSTICS +.Bl -diag +.It "myri10ge%d: Unable to allocate bus resource: memory" +A fatal initialization error has occurred. +.It "myri10ge%d: Unable to allocate bus resource: interrupt" +A fatal initialization error has occurred. +.It "myri10ge%d: Could not find firmware image %s" +The appropriate firmware kld module was not installed. This is a +fatal initialization error. +.El +.Sh SUPPORT +For general information and support, +go to the Myricom support website at: +.Pa http://www.myri.com/scs . +.Pp +If an issue is identified with the released source code on the supported kernel +with a supported adapter, email the specific information related to the +issue to +.Aq help@myri.com . +.Sh SEE ALSO +.Xr arp 4 , +.Xr netintro 4 , +.Xr ng_ether 4 , +.Xr ifconfig 8 +.Sh HISTORY +The +.Nm +device driver first appeared in +.Fx 7.0 . +.Sh AUTHORS +The +.Nm +driver was written by +.An Andrew Gallatin Aq gallatin@freebsd.org . + diff --git a/share/man/man4/myri10ge.4 b/share/man/man4/myri10ge.4 new file mode 100644 index 000000000000..c78c6b12a477 --- /dev/null +++ b/share/man/man4/myri10ge.4 @@ -0,0 +1,146 @@ +.\" Copyright (c) 2006, Myricom 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. +.\" +.\" 3. Neither the name of the Myricom Inc nor the names of its +.\" contributors may be used to endorse or promote products derived from +.\" this software without specific prior written permission. +.\" +.\" 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. +.\" +.\" * Other names and brands may be claimed as the property of others. +.\" +.\" $FreeBSD$ +.\" +.Dd February 9, 2006 +.Dt MYRI10GE 4 +.Os +.Sh NAME +.Nm myri10ge +.Nd "Myricom Myri10GE 10 Gigabit Ethernet adapter driver" +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following lines in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device firmware" +.Cd "device myri10ge" +.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_myri10ge_load="YES" +myri10ge_ethp_z8e_load="YES" +myri10ge_eth_z8e_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides support for PCI Express 10 Gigabit Ethernet adapters based on +the Myricom LANai Z8E chip. +The driver supports Transmit/Receive checksum offload +and Jumbo Frames. +For further hardware information, see http://www.myri.com +.Pp +For questions related to hardware requirements, +refer to the documentation supplied with your Myri10GE adapter. +All hardware requirements listed apply to use with +.Fx . +.Pp +Support for Jumbo Frames is provided via the interface MTU setting. +Selecting an MTU larger than 1500 bytes with the +.Xr ifconfig 8 +utility configures the adapter to receive and transmit Jumbo Frames. +The maximum MTU size for Jumbo Frames is 9000. +.Pp +For more information on configuring this device, see +.Xr ifconfig 8 . +.Sh HARDWARE +The +.Nm +driver supports 10 Gigabit Ethernet adapters based on the +Myricom LANai Z8E chips: +.Pp +.Bl -bullet -compact +.It +Myricom 10GBase-CX4 (10G-PCIE-8A-C, 10G-PCIE-8AL-C) +.It +Myricom 10GBase-R (10G-PCIE-8A-R, 10G-PCIE-8AL-R) +.It +Myricom 10G XAUI over ribbon fiber (10G-PCIE-8A-Q, 10G-PCIE-8AL-Q) +.El +.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 hw.myri10ge.flow_control_enabled +Whether or not hardware flow control is enabled on the adapter. +The default value is 1. +.It Va hw.myri10ge.intr_coal_delay +This value delays the generation of all interrupts in units of +1 microsecond. The default value is 30. +.It Va hw.myri10ge.skip_pio_read +This value determines whether or not the driver may omit doing a +pio read in the interrupt handler which ensures that the interrupt +line has been deasserted when using xPIC interrupts. A non-zero value +may result in lower CPU overhead, however it may also result in +spurious interrupts. The default value is 0. +.El +.Sh DIAGNOSTICS +.Bl -diag +.It "myri10ge%d: Unable to allocate bus resource: memory" +A fatal initialization error has occurred. +.It "myri10ge%d: Unable to allocate bus resource: interrupt" +A fatal initialization error has occurred. +.It "myri10ge%d: Could not find firmware image %s" +The appropriate firmware kld module was not installed. This is a +fatal initialization error. +.El +.Sh SUPPORT +For general information and support, +go to the Myricom support website at: +.Pa http://www.myri.com/scs . +.Pp +If an issue is identified with the released source code on the supported kernel +with a supported adapter, email the specific information related to the +issue to +.Aq help@myri.com . +.Sh SEE ALSO +.Xr arp 4 , +.Xr netintro 4 , +.Xr ng_ether 4 , +.Xr ifconfig 8 +.Sh HISTORY +The +.Nm +device driver first appeared in +.Fx 7.0 . +.Sh AUTHORS +The +.Nm +driver was written by +.An Andrew Gallatin Aq gallatin@freebsd.org . + diff --git a/sys/dev/mxge/eth_z8e.dat.gz.uu b/sys/dev/mxge/eth_z8e.dat.gz.uu new file mode 100644 index 000000000000..6f9f3104b659 --- /dev/null +++ b/sys/dev/mxge/eth_z8e.dat.gz.uu @@ -0,0 +1,633 @@ +/******************************************************************************* + +Copyright (c) 2006, Myricom 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. + + 3. Neither the name of the Myricom Inc, nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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. + +$FreeBSD$ +***************************************************************************/ + +begin 644 eth_z8e.dat.gz +M'XL("*B.]$,``V5T:%]Z.&4N9&%T`.Q:?6P39YI_/'$20]/8+8$8FH!)`B3A +M*Z709D]I-ZN"-M5""4FX"X6#=I7;"UUT2MO`F6Z(G2%!J*($+=DVW=*&U=*[ +MW*K=5CKVCC_HX1Y40B?`G,1J\P>GNEP:>:O0NL1@-QG/>[]GQI/8DW%*MY7N +M'RR-9M[W^7B?K_=YGG<\1-_A9_M[]W[][OWN_>[][OWN_?[__G=DNST +MG\>(8K+#':(WO*\?%PJF;2%R<&VW)2_Z)>:E8^1XR2U4WWRRBT-;_*HL*.B- +MDVTP73DQ3+X3Z;2^8G)?QEC(Y&SO%^H%CT)*SA9_ +MQSMD]RTFZ7)+@#Q+6999M2Q+]_/D^.W/`I(XM,W_^_&X=/!SLI]WKZ?S[NL4 +M['^<@E&%CCY/>>>C-13L5HGY!??4X'X;.*/D>9%HA&95]8%/2.=IB\FS:CYJ +M(V([\=A*CQ(7N8[/$Z,",AS$?6">")?V40'P7:#O"-E^XF?Z7LRO[B/7ZKTDLWS,F4[%;)!A^<&,%=:H-%\$*(G^IA&%&[_2BW<'E%?WWY+O+Y] +M+/'Z]JAO/SD2A=MO7VG3;.6ZT@9;)LNLTL\_J^L^>U!\Q-!CUM68Q +M'\SWA6P;6PWZ"]Y: +M7645`^-2P4?0[Y5Q7SE-R.3`\^$)44ZB>TO_XK]4NVH+*12LF.>PW5]8A84%D+O"/TXVSQ +MR:X$N9[J$;Z@THZY$[0YH8K-B:]QQ7!]*39EG\/]$[&QQR>"RC7@7"+1LZ5? +M08RR'Q3X`;(-WI%)B)PM9X+*'MJ5D!AG4/D%8(>V_+N&D[/EW[1Q]Y:+PK[E +MS$H_Y;(>*FP;5+"OE,]H\_Z(8%V"WFN4W\4YXA+F/Z3\*#E%-O,>9;X7P>OC +M)*\P\"(,9UX&'^81?T((Q@\JW4P35K*W#.&**]D-Y>)0PU^Q?45.0_7$!-NV +MH4Y(N6(<^U+G$P4-YG(:FF,RK8]-L!X-7DV/0PW_.*[IT[!/UZ]A+\\K,F7C +MN5\1&NQUT#5I=-T-_<+>,(@8R-J<$'ZV,6SN!__^H'<]B>R&0@R +M#8WK?/\$'CMBS,_>,`0^X83L@8U$?-=^DC8K-B7H/:+MT:"W'?/T(/B?`[\A +M7@/\P^#U&7BTL!RJ3"[PC*NZ?+%E?O+J\C6Z57MC^6IJLZ7&E>8'+9YNDMK= +M6(TY%\<1Q]#34:%B +M+<"+="6Z&^*@/0&T +M*5E.KS_[\NAIS'U(>5U"X=B]W-J""[2W%>?ET0]I9UL;Y0W[$*OB2XYED>^G +M33=5<:7M$G`FA.AI='.>V[1[3#Q].R8VW0S8$CT-\41VHT/-;BQ7>QJKQ:'& +M0=AKEF;SG,9_UOW;^$^8*]+]T'@&]D(<-5X,>O?`=XU:O(/W$/"'DOAA/4ZV +MO@(\Q%N30XLU^];#HGMK..@]K>W1H/=#VJ60)^CMIEW[%_AYKP:5]\`3>#U; +MX;OFRN@O.#:;RQ7D7$7+P:>U_:#'='-Y:OX@LB,=93N(`Z$Z)D=6@Y%/FGKI+F?DS.TN>*GF]S3DN.BS\GEVOK_EKD/)?K +M8RW_N?#\XQ,&/6P="Y'S.N<#JUP&_"IC[0SP>D.>#/70SO&9V"//^12(X*@)![TT:`+RS0ZBB9]NEL7U">0NY6,W>=A5K0/^B +ML[K,C>Y7,3]FWW8)O!Y@7I=!G^C9=@UXUT/TT[699`%MM7I'A'OW3;] +MJN#GH#=!`YCG=6/R`V7&>IEUVA;2:\,#W0*]4&"APL\];'NL'I#5-BFU3BN,]$K"5VN@KUC$A6BMD8"+X_32`=E<7\1DQ_,"U&Y +M%@MC,OUN3-JZ%7.>$%4$M#F)YF)<-8D#'AC7IM!L'9,J?X>Y)A--BXFFW1A# +MOE'//DVO=:`_B%N!#O@-:#)[1:]IM>JE#Q!$#9X#?9_`W +M8D?#U^,GK,?/G#.3."C-%SQ1@BW#\.EH,+J!T#O"IG,4CBEC36>''C?<(QIK +MAA`KG.M2XG.8U]+7*"@RU@#O88X?K2\&_R3=1=WN!>O3[5'0E&Z/@I94&QY$ +M;(9H3CG'L?6^;`A#ECD^50PC+MY#W-OYCEKW&=8]$^%<;-]=Q6.!9\OS`_)R +MXHX8[?T'V.TV%:(G6729;M#ECC_Y?7^F.:BY,=[CZ)'G!_TWH)/P#P`7N698 +MW_-SW3/M>='=Y(!"4^G +MC>7X;RT_@->`I/KY686L;\MJZP`N]5"K6WM.PE@.%>M;\I_,%_/^)9ESPJJ] +MR9',E6'H.NL&S1O$6!+2O(V_5R/21^W:41+GQ'F#%A>@\]!CSSN6')_0=!AK +M01\_;U!%7>4QGCO$6)ED/`]\Q3W]/.S_N8,9_3$I:^'?3A7%Y,)RK%^F^X3GL`;;XBO$VD2SUE/Q/-N3Y]4) +M-X]K`'=QK/2J>BQDJA_'.;=HN:+PF"G?H$87GC+V5_MBQ-DTHI^)W`4IM8ES2O3TRW$[ +MT_-Y5*>,?LM]3T"8MC9*ZM#034*_[D[]+C< +M%A#RN6K$[)!UG^%&_G.WZ3ER6P#^'1^A^5MPG\!]G<$ST*GQO(K]\`CS,LV' +MG5TT[E3\U=-A\^U"SEIC,5\$&XZ':'X]RY@ROU;(^6L9/\3K@<9ZSVX+O#2? +MW)#S:]#\&7DVK,N\X''3.MW6,L\_`9F_SB#S&ZO-;NFSX_Z +MWD",2J31-'9,^4.'+\AS]E/5]+46E`DY]Y$0+=BAQ='4?(TN`VPAL2V@!^@R +M^=&(?;9#3%YP!/@[C#J)>AAA6R5A@R98/`5V(0UV8'+^NC'_#;Z`_1_J8IIT +M'1]R6/O@(0]\,&'M@X=JK./FH2;Q2[+BM0=^F6"_L!^FV_^A(X;]OT&'Q`@5 +MK9N*IZ(N$Y]K&709A2X):UV*'-:Z%'D@RRG>W"56M1'73A?Z,(>.-\IX>YQQ +MW;^>%\GQ!17O`!^;>'.[R(]0+N,'O5\&@J@ZYSLB9%ICT'IO%B-W9C58S`_I +M[\P6YJ7OV>+(E+UA&]"DO.^=\9K9!PL_U>V_\.-T.18^:VW_A=[,]E_89VW_ +MA>^R_:%3*#T?+[PPI1/6`XV0<^;P^&YU,R[PMPW\&O5;MBW^2^@S7<<6D.6[ +M;\]"]&P2]^^+WD'L#&&,/G/QKU19ZDC:]I,1\BS6;;MX;[H]%IVUMNVB:[#M +M)]:V713)7#<\>=#_DV1\/\SP;V&W-#RGKM`._;FH? +M>-H8)[]-JTVI\IQP1JQBWG-:XQGE_PZH[FW(R>?*+VCQ+,;C^5)W:LQ[A@T\ +MSD$ZKN>Z>+.5&"^=]V*7;I_<)P>2^(QWUW9(Y[5#WX.+3Z;OP<7MZ743?@2= +M*MO0^RTZ!5GOVNXS[$G$3/6Y*MIGDBEK'34E>YK@I*;?>DR6U'#,A*FE/ +MWY,ES5-[$NMI>Y(>^#9["CU'QCUL[-.[M0GV%60JU?#1KU:SC:ZXB?_7\&&^ +MB_MGW59EIMZLU&-MJ])JV,IG;:O2)FM;E7+]]TVO'Z7=O'\@HX-IOJ#2/VIU +M9&R70'Q:U)'2TY-U9`'OG])3FDW&4$?Z*9=KRE0MJ;*H):51ZUI2EF==2\K* +M]#@N:TZ/X[*:*1_#3M]/+>D=H24/H)[[=7\L^<@DRP?6_BB["'_T6ONC;-C: +M'V4*[-X[W1]+"NZNGB^I2:_G2U;^!E?E^Q;`_#((<(QA6.A[IVG'LL +M\/I2\?B=+^->\"3(`C=@YID!+YR.E_ND]@X0<,9/UZ&\0(^U\M;T6"M?,15K +M2R^9:.K2:QKBY/O)!^=&J*)8SP45+YC6S-#_E'/_<\[:U^41:U]7\'NELZLK/.]I?5OVMYK5)!+9`/.N;*RE=_;.8NH*MBO +M\/MM%^/MZM#>YSF[.4Y+.$XKC^GU79#3.XGK,'!-/,]R/!MX^CL-OREW5(:L +M_589M_;;WQ7?ZNS4[A$12_\=W#[4UDD+/Z?EGVG\,<[O +MLO%_BY(X^/,A)YX'9!'OE<357EE<#2JWN$^936)<8[PCQW,=8)$9_B-S&.\F@=N>RN>@ +M/G?8>.>-Y[YOX&7(<]8DSR74NR-)'D,S\6`_Z?'%?EP1^:9W+/SN8816)L^S +M*TW]Q\HJ_1V:7F-V*N9X6UGOC%K%V\I6(][0LS'?WYC@A_6X6QD:RT[MHU=J +M9P?QH+ZO`#]LH@NDQ^7*JIG>1^JZK=JOZ[;:="Y8E3>S;JM66.NV:GVZ;JM_ +M8()K]7]L6@U=U3%Y;BSA_FG59:W?&M@ERCQ6_=:J=R?[+1W_A*;[`/JMD^:^ +MMY;.*^:>:]6H\X25_*OMR7S7,#W?K?;H?EGM3<\'JZO3_;*JQ437G.Z757E_ +M::[G0TM65I:499-L60!#3'R$%5=G>%=\L7$H=W'$.O\OZ[TKR\/2?Q? +M22>>C\KB(C_#UX*_H_F/6T/2"#W<@7IY,40/MT_S;?'-D_8L(0DA;$+_D3WY +MD(5+$C9-VRQ(GYMC)V=^GF/1PB+W#Y^HJ?9U=GB%JL2=(N7_E>ZC_5LK_'K] +MZ#EJ^5W'J[)HPSXC->?X5=]>DMX?#TGY4;*AIY;X>Y\;M&;6.CRO>4H]=/SJ%'\[,7_863JU("SIY^LUS[%^'V"`-P8\"7AA`\_RC+-/ +MA'M?)$K<$"KS?!:TWP&@,^MD_LB,EK5QCU-=W63WN&:6V5II\M<+_3 +M>\#0X7Y=QP.&#O?K.J;!5Z3`BW4=#Q@R%.LZ'J`4>+T)OM$$KS/!UYO@M29X +MC0'7=5SGLM8Q]^HPK2M(ZH@^M-;0@70=:PT=2-[2=:PU9'#I.M92 +M"KS>!-]H@M>9X.M-\%H3O,:`)W6,&CIFZJ]B\J/N$/U&ZY]4_HYB'Q%R7)S? +M2V]&U>-OH[2S=ZR=J;UZ[GET0^%[,;^?O1DB!ZIUGC)Y'];UFI?2H_[ +M:!_CB8.5#=I:G*^Q'J^%=7)X#5X3M/J:/4?K[[;>BIQGZIQ=+CY#-#L5FQ_Y +MJ?F8\4W%(\P9_FQ63']MCZ,+RLSZZ +M#H^]RG2W9#N%Z%%'28&6%V$+&^FV>.RY_*Y:ZM6^[QJE2%;ELYA[F&5(VC9/ +MP`>&/\2A9^OR66[(EA^U^=].D1MRA8[*D$V";-Z;Q.L$O9_Q>6J>]LV;UD=7 +M%Z3*.>63ZG4SRUD]2UL#5A.?.[_)Q'GV0YX<=C+*N5W77? +M:OQPUO$_"WE.99#G8RMY5)GE8;M6O\'T+`MH'$X%!1AV0HX^;+5N?M=)ELL2 +M)G@/=.K?`^[RDL`>$+R_8O(/:HU8=]H\6=IW%)(X9L7#V76,]\R36-\2CGCP +MP$YA]>#R$J>-?AC)6C[;Z56T;\[_C[CO#XKZRO(]W72WQ*#-.,1TC#.2B3/; +M,\],2)XSZR0FDF@2DZA@H@X:(\0U+E'$%A$;!!I:1++AAQ%UB2(RM=DJILI, +MF'INE5/E[G2>SBMF']+DK5N/ER(S'8<80DC2D188[>[[/N?>[Y?^@@T3Q[QZ +M?WSK^[WGWGONN>>>>^ZYO\X7.-U7Z)$#L$?,0_+NP<_.!FBQ[,-!Z_I^P)@6 +MS'_2<[5S5QSN#=`A.>:)A'N/B^JM/5&O7:26V`5PO1453K.P;>V)R3BE&&5\ +MQ/O(W/CR^LAC4\O!(]_B>.;[S3KT$64#[[_W>&HYT_&SD/`^=D>`'FG6RCRD +MURM`/_-Q/3@>/&MC&;)'R)01EN>TI.P,/^B@(=3MJ#G:QO0,[Y_3=O#'9/D? +MZX7WTDD^V/F-UA%Y?ID4A[-+[=H6R:1U^VF\RR +M[S2:H[F-7CQX:?.:CXJ]WK0=G'/_0S-?I^&AJ-TOOEAM-6CF/\^.E>V +M79&@H7_@>?NCS3HL7OY#L)=&O&0;V;^M!&EA2SX<4G/?1R^AW=9HWX$Q_3DL +M>AN&E0SCNX=U>D9DBJ\W2PM2LF.].$,:>"Y_NPK6$W/_Z3EMDBR-^7Z;%"O$U7Z+%7 +M$TP?48+#:]4W0OB>SU\QC5`C\G]$LBP/$,%.KHAPX-,!VS=A"NTV,=U +M$'P_!&,4TH50;U/4NKZ']PJ0-B2&/V^%#F);-3BS$C#K^MZ&JVR;SA.>8IJ1 +M'4XF_5SGJ:OZV>7'`F-C<1'R7Z4DR&8%Z/^SE$WP@,^`*3[PN:[%[_/]%%'T +M>7M],5FX_BWEQGH_G@SZDYE^K3Y!;=P)CG@?7Q&@.S,UV0B"+SU!II%M!=!K +M#]N%WQTVG*M^O%2G3,\OHSC(9TS"8WF& +MLA*81J1/&4L[E&7A^RM)6NF/CO:V.8KWP"92K=$P/>( +M94/:@_V8*X9%U%?T`>!+3OI#T$E1`?VXY-",08P=@SQWV[!0SI5L#:W^T7[J +MK/B`.L/^BG-7@Q:ENRR8IRWY-<=Y^D4T.])*DXTU/&?+"(L_*CV5;N%Y&]MN +M?X'>C:)Z_1^$<&"^MH/WE6#L.>G!$C(-4/I"R$JZAO=+#>_&J?"RG=F)/J7J +MM*,U`MP1VXX`^H,'^MAVA9YX!^6T=H6[B?M`2Y061+]TD#8_]'Q!Z748PY+% +M_CD\OGM2MY*\YU,>(9N_D/M'8QMP_.)W&"FX[T2$P_ROPP'BLYBPA1-Y#)I9 +M24N$V2[GY=$#=>WB0&,@:&T\J^:DZ\.&^:CU"WKB+IZ/"LOZSF:V<:P-%4%K +MO5M8-Z2->)]8'J`E.=SFM8AC6E#VOP2MKU4P+K2S*5H4:6_X2K]#]L31KL$1 +MGZAZK8+/CFIEV%'&J^+`:[")GSBCVDE^5W!\^(83XVUZL/DZWT%,;Q;>>;XA +MRVL5+SHJ('-/=`1,B=*.A@YQHMW;)]T?..&8[@<25SFE#-`RZW7;UHX;L"MN +M@,;K7NC;$UE)KB*:,T!/?B?LI10\R<%[<^\`WO2NX;!F?SYY5G@3A+C7859G +MS9\\8&]2LC+35$$L(RVP*32[`F.V78C_<)K9UCBN8,EL:\!65O;T_A_E<'Z& +M9;^J[)$6+6[_'%HPGN8G$]7ZVS*Y1E*WA2ZI$(;`'.$ZWB +M/H/V15ZF0]YC*OW2YW&AK^5?17]9.B.C/RQU9G8.!4\=IZ13P%5_G-(B4B>> +M`AECZ.U_1::J?0_/]@R1Y"IB4C>S/ +ME8VOI^=TB/L8N/^6XM0:$OIF>KM38GZQ[87NV:K(2TO(O5^+OL#/(OCEO?!.@3+]0OZL/C%6P! +MFX`>\KO_UN>E;B&XG1%Z"GFI0-^Q3T_P^295^T@'>PN?G>1(9; +M1-EVSQZE"K8E0M;&=M5WGJK"O$3J2::9ZP$X">KOFK<;[KF#X$ +MO+'^_G3[^05\-W5'JY*O9V;<;9H.O"O +MH2&`,H=L=3EJC?&9^7I;@(\VM2?Y]%.2)O!R2#BFW]_,[?[,"B,]&>&H1_7A +MISN%["=/=TXV%H)W"U'6?."`'&UHGM1.CJ4[.U6ZAE_1(F%;S_:+N;T\:#[P +M*UIPNW+$\QW&@S:9-4#+%]DQ9^"Y].WB_29HJYTMU_D]];,Q;J-->+V?]?Z% +MMT.T^R0E>CZB&?[P2LRUT@@VRZS&84II*:(D\.@/4G]@++L81)Z]SN2&8_H8 +M_>R.TL_)O"Q5A%,WRW#>`WGRG%DI[RWS.L1Y]W5*W4;S+M.SJS.0OZQ)1'F] +M'/.?I".8$W+^9LP/A:VN&[HNMUG7[;`3K[C)7%<$FV:O8SILXC1[2(T)2B<\ +MB_&=DC4=+O6C\"Y/!5Z+%G\Q`OM&XBVB^I8S"EPWGN>$K=W9DYXGT^ +M)T`;T_4YI[I?\WQAP#1]JCNRR=I](#-P0*\\_[:N?Q@'[-TG=Q?3W!?O2<3\ +MG0AI^>XGYE_/=^IS?7MENI0#GG^R7#28!=\#Y+L^@^C''6H])N&3R_3\I[%R +M5B2-Z3F4P?=]&+^Z7_:\C\M@&U#IO^=]D]F7H-_)O(UJ=J]_\!/%6STEV%MG`_A6?\V +M,&II**$%OA*95LYM@G=O'[D?\?`X\0!F=%V'G9IPDVAT6UU._2],N`R;,JQ9X +M3I)Y_)VY52OPY."!+;JJ#[E2\2S"TXFG8L2[*@O\K%%S^PQY!J^![3GKCD.J +M+HT^A!,Q1^O7ZM**<'*JAU*%M8[C4H3UR'+8O0ZF(6IMJ#'N8S).KAOF7ZW, +M)S'[_3%><3KDLW"Z*'"HL1?I@4-//\;7.7QW&^V%=)A').I[I"/>#,=[N6H- +MA_.&D!=\1=_-&+O_K-=K/^K#<2UR[3PC<^S.+,*K3A5=13 +MRE[&165KK&I5:Q^*-AX;QM%G-;3[',;QFENU>UV'5M<45==Z-W`R+YMN5S^6 +MWT=F?W.`Q[C%T>KZ=M:[_KDA\C='Z>)H/ZV*"M\5RMPAKE?0K=E7J^6957_I +MP_*.\A>T^BU_4.[7\K>\+\]KJ3Q6GL2XJ<\!HR5R[B/OL/H'@ZS;QN)$=5V; +MXN?JU7P&G&GVAY_Q,;W1JKHVIMWCYG%YQ,=],;6(UU56/P`Y%YCSM_TU]'O" +MXHN@M4[>?6THMR8N;1:^(5M]^XAW=>9[;B4W?PU>KGN+5O<`94K[]<$F.7]$ +M>'7-I'-ZR`&/CQB/_JSQHDLC25;O#5/8LN-0YRCF;D7_COGZ +M"](G1F=(VN_]S%NVT4XHWDN9Z@K]._DW=I`_W(%^V-@//>7#7+?5TRP +MW=@F%-Z'3O/8Q;ZOKA22.3M$9LC$C!$O98X,Y2:*(6>2J%K?%]F7E5K6)Z(K +M!Q-XW=)>?DV=J_"[^@EI9D9V.VN4,C/$?ETP;[]*:757:8'8[9AN +M#RK;4.XW7L+W5>CO`XUM)PI@^UTEYPF#[<>V2X8;\^R=3EZ/C-E^NYUF@PZU +MW*J>T'D=MM3Y;E0=6=XY2(3VJ@G0B_.O>U>?B=>^^OX(V\+Z&L1[\]48`GRN +M*6R(Q-AZPIK_O/5YW#JGFHNO"01,=YQ6<[*&B@O?BS"^UB-25Z^!#L]:H>9U +M'CE'%T6?MQXID?X\>I2LK[M#KLM7K>^]B'X='?Z\7:X=>JD"[Z0JX.DJA1S8 +M5M\RG;I&ECY:F\Y[!/)>RD#R1E%5YPMI-A'"F0(\Y#5!?*\! +M;35X9W&=A<&?*5^CVV&M6^V?,6^N$2?6EOW\1PA +M0:Y5%(DPKZ^/>-?VQ/9LUO;I=N&0I?[04%5]3SVV +MAKKNJ=CZR[8OTFQA/)/[8:G7 +M?.#\/,(V-+[GX5NN&^';@>_WM.][\?U+[7L.OM_4OK^+[V+M>S:^7]&^[\'W +ML]JZ7.(5RDI1\O5SV']KJA3_QF!K`O1!_H4&^%PM?56` +M7L@SP),U>+.^IJS!+1K\3(#2DV/P=>I,!/O!P9SW?.E"M/_/T?Y/=1O2#&IY +MT8Y/D0$>4/`L])DW4PWP2]_$_NK\),J)!SX*GHL%Z]4^ +MUR#;*_JZ%W!96689#\^+_(772CM?H2Y^->-?GZGT) +M%J/U?P#=6Z5/F.]&JE;WP+[I9_]%X2(1]!23!?`[5X6"M,HU(NHP3G6%KE&7 +M*T*>0?9%:!=\/J;LZ3F_4]N@VI,5]+JYNX +M/$]4?'2%-LB^P.?+Q8%+F?9*0KH-F;!)6]5S*7.R>J@^MJ%6Z8$7EJL^NJ%6 +M>-DOU89#T`59L(6SXN4OQ3SD1O7Z\#M;SYI3MW%;O.3VW(.Y(<98V`!-/!;S +M^-KICD`G;^`[6Y7O;@V:>?ZY"=]PDC9NR+$8X[T999NXW+CK69A3 +M1.[E=:EIHOQCFNW:2N:9UX1O((_,Y2$Q4/ZJM'.M%W/#Y'=_0.4%W"8O7>3] +M6K^[GY`^>8!>^M`^2F8\)M\V'D=?^HK'GP!M7,C^*GT%3P*V<8;G8[F/V\U] +MZ3*]U,]AR-(GPK9U^:^NCUJ57?72IYK>SD1[S07N_LED%?/&E"MYE(!WTA7: +M=-_8>A=MW`/8//;9E1WA^KM`2 +MZ0N,SYT(Z]H.X$N+6E]TN`I89C:E#9DI39WOW-BACQ,!P-4^PMJS_O`2G[KK +MM.FNB)FD;SR\+2C?PN6CC"9Y-LV]Q(?T:AY1R&<]/X:.Z.-\:>+`VB;%@Y?+ +MN!Y(UP^:Y_F;Y9I^@/=]H\.'R%?`9V->+@:=_;QW@;PSI%Z6\]VUHVH.MRY1 +MS7?7.3!G3!ZRKG,JWKS\GY!GZ1M-\??E?_9\BKFHZB]WCK/ +M]Q/%TKS"^GQSMK +MR/::@^.!*Y@=4;3P7A;"&R?S#\?^B]1:TJ8L_3X'[)0V/B>"?CE+\\4#VK,= +M\FS/L#C-YZI<)92`.IX;2^L6?T+Z>SF]]"LKSTADR[6:R[2IA]?F\)C`X]]K +M]5@4H.RTC`@Z&_LVQ)O#[`L3:?Z,M)CS;3JGIS7$5TP(IT\(IZ(^J2/>;*>^ +MC@?Y]M7*&=7)T;Y.I['6];WS:PD%_B<@'I]S+ZBNOH' +M"?K:+KQIY.\/*SV-.>KE^4CS*L#*<]ORMV@NG]^#7N@3YK1VY!G\I^O]5G_X`W)M(_,`Y=182LG2<(62,8<+ +MGP\O(K:OFV>1Y<1AHF:,7\T8]Y3/KYSD`#T[*O>Q`:\%'/,<"\I_U8P\^`;/ +M.3Z_A?VM4@KB-L9XIN*4#"5*&=7P.ADGYT$:]AMD +M!YU)X'T_T\KU9%^M"`^>?WN2<]>6%Y:'O7*]+BO#[2,_K"'>3[W8R;V`^[OBL(7'TD<5R,]M-%-]L> +MES*[6CZ@+L=_R')8;_H*AKXAW'6MMX*;QRJ_@XC/`Y7?0S,BP^P[=9Y0^WJ; +M[^$Q7.K7`^M[Y'FA+XABYX0^)E[O'/%NML3&^+'Y(>1@L]Q#CF"` +MYPZ0[8]X3((M=ZGEF.@\<4QT7Z$#5MAM/8!UU`,';+^@KX!IJ/JH9;:XL!\P +MU"T0H)>D?:[L24^'U,E7#;'-5 +M/`$9/,OR5W>5DNNO4E+9H(AV06;X3!V?V?#CN[-HE/YG\"O>-_!UY:"_]Q*A +MK`M).90"?.>$]Z%F87ZH%C1<>C?:87VWI-N:NHG'NE??46>)/+]7]JY'CG?( +M>TGIXHH'(+,8VR"Q:G["W[_19/RL\#[8SC@AQ];ST#?G\^3>Q2$>)]XMZ;"B +M?F:>#Z&_U*(?G49=VD>\6U.@BT/:&.##W.9T'?*@CK4K7Z%YF)^]K?I2^7N= +M_?T\[^I6\Z+RM3R^H1]U*GU1OIC'`8PM32=GBR-Z^XVM,0VR.IVS*&W8WZ]':/R=MB)VY?AR<*#5MD..=B. +MN=MVS-NV'\*#$7Q[*YXV/&?P0(:VH^6VHR9YP).7BF-^:CO +M3K!@)_+MA.;=Z<0#>G=FXL'HLA/T[FS&@S)W@L:=R+<3>7A9S@4:71A97*BC +M"_EA/KN09A?HVH4Z[0)M +MNV![[0)MNY"^`+@+%N!!^@+@*T"Z`O"K`/@*0'P!;_:@3?8`SQ[@V0,<>Y!_#^JP +M!WF+D+<(=!4MQX.V+T([%"%=$>2D"'4M0CE%2%N$LHK0?E``M!=UVHL\>]'N +M>U'67M"Y%WGV@O][._$@G1MRY4["`[K<2.M&O=R@SXURW&AO-_*X09,;]+C1 +M9ICL43%H*89<%"-=\1H\D*EB\*$8:8M1CV+4HQAYBL&+8O"A&/4H!GW%R(N. +M2R7@7PGDL03Y2U;@`8X2E%6">I4`3PGPE`!'"?*7@-82Y"U!WGTH=Q]HW`?: +M]J',?4BW#_.,?9"I?2AG']+N0UG[0.<^\&(?^%:*/*6H6RG**@4/2I&G%#PH +M17N6(ETI+*)2]%6^HUF&M&7@V3;TN3+06(:RRI"O#.65(6\9:"L#766@JPSY +MRU!6&?I9&:<'?64H;UM/XP!TW@!9JF`G!.B`7%OC_TD$H!?$9[G\;XF@]FV* +M?3L9/JK!S9R>_T?!Z25LNX0%-9CI9IAS+!V_AS[+36`<>GXM'-3S +M''9ROD'M/:J]`UP7S^`8[1:4U<]A_M;*X_]F!"?`3#?#G/+_&A/2J7KFP49% +MW1&V1#]3].M\FB3.-'F'^;']C/;NT-YM +M&G_T]K1J93&?K1/X8X29;H:-\<>83N=/4*NG-0Y_XL69)H^3_!DKP\`?"8O# +M'QUNX$]>6../`0_S(^^2]N[7WAWC^>.TQ,IR3I0?(\QT,\S('^=$^='JZ8PG +M/_'B3)/'Z?QQ3I0?"8O/'^<$^'&FR>,D?\;*,/!'PN+P1X<;^+-SL<8? +M`Q[FQ\X4[>W4WHFZ_F%:#'K#-J8W!E7_U_5<]#,9%YP09YH\SFG,-SHAGUF/ +M*]=T"/.X7-'-;6Z.;H^56Z[IDSAI3'\YC8$.0WUU_3Q9G:/&=HA3;V-\`+:4 +MKM=B^)6>9_R(7ZS"KBSM[=3[KY;>.H&6H%:6-0[_C7$3^6^(NXG_QGP3^1\T +M\,TZ"?_CI9G(_SAIQO%_K+YQ^#^NSG'X/Z[>X_F_*Z3KA1A^(_]WG5/A73W: +MNVT\_YT3Y5\KRQE/_HUQD_#?&4_^C?FFX+]S,OF/EV8*_COCR?]8?2?GOW,R +M^1]7[_'\WUTXGO_."?*_6Y/_W9K\[Y;RS_&1SW*GI)#:;S=DR_WPPWQ8<[2<>IVWA:_#@[3X,9=&YA-[]C>;E^A>W:VZ>]=7D; +MLWMDO>/83QK\)OOI9KC3F'[4D-YLY.M$6TZOCQ9_DZVGUVWR>$.Y6IFZ+,6K +MTX2X>)KW_ZKK34/8X>\M0[CA[ZV;X3?S4 +MTT_DYSC;+PX_)\9/Y.>$^''\#!IU8[PZQ>'G6+W&\W.OTVA+CN=GD38/V9NL +MWD7],7XZ)\KG./ML?+G.>/*IP>/QTQE//L?9BI/STSF9?$Z(G\A/9SSY'*M3 +M?'XZX\BGVVVT/[=J[YJ;]9O3%E^_ +M27@<_381[C2FCZ/?G+:I]9O3-K5^FRS>4.Y-^NWF.DV(FT2_,>]*SL;7;S*N +M1H5+-'Z6N&_6;V-E3]!O8^5.T&\3X3?QK]4(L?UP\UF*$?EBWB=RPOUZO,H;WEO*YAMCC7<$R[?;Y!DQWD]#FD[$+0Q0=OK$.,!7Q/9[%?R-8])O +M1U]7[R#O4-AY;UN8T\B_,42>#VDV[W?S'G?M;'&&[T]P/-/!^].;KCU'NW/$ +M:,MAHI999#G?1Q229PO*S^A[U+PGS6MZ?*XEMK]0?BE`.>V&/;^CPKM$U!\3 +M/M3U--_C8=_+J'.WL!W)5'L5GN]W-@5)J^/;O`\QXO7,G5A/O3Z\S_&7ZL1P +M/L_&]=#KQW6I.B;:^7P+ZI2(L&5W0(Q>V,)T>VKU^U0!*C]KEO>Q1#?3Q/1L +M<7/=/>UQ:)+[):C#QWI;(/TLI.V-M8?B$>_GN#;S>0^UCQ2@5^5]Z7K&4<3[ +M2:_^CGV^C>V3@F?J?(CG][RWA/02KNU%=?#>$V#R7`7O@8'>"Q=#1.QG@L^^ +M\A[^*!!NE)Y5K::V!]2!^^W-?P!\IJ==>?>,-WA>ES\Z0I57!->&F5_ +MQ,"=>H6\[Z/<%.WMP/LW>-^#]R_POA?OUY$^JJ5/0W@7X/]5>X/&BD&\,U'O +MGM3-#)?UR$3\>JW>G>HL3>5][%,`-+&/9#>?&0<^%](]P/@Y#FD^U/*PSVG@ +MJI2T:/O&"Q%^'>$G&`?:HQ#A8BZ+S[GPF1AU9Z[2-;']KM"VCX;DN:Q*OF\J +MP\BW5'NG:^^GM/#5,!G>"\SC5Z6E\HT6<4EIC\0DSGFYT\`/\>\U^$QOE>< +MX;8?@RO\C.\HS5!RJ>"UO-(;,]?-X1HOW#E!S:FW7G +MB'?_E@`E5FEGF'OE645O&O\?F\]IVNTF)S9%VN06)_7-G%TTFC?QG* +MNH@^U,JXD;^5=>/^(DK4_K%EX7,[?"^S\3#K^/*V"\V2Y[U#NQU)*#L0H%=. +MJ_;8WRK;+ASBMMMRA:J*T0^;4?]FA/,0?E6#XVU*YK>F3YI'O%5.U,')>)@W +M(6M=-]>C?A-9F'ZNAUX'KAO7PU[YG*R+NF^__Q#'`0_D?]-B14^5_*\X8%7& +M,_K`ERK]CU>]Z"B\C^[B?QMF1,0?^1^9G(?/[:GS1S/,R.N+G3]2\@:^H-Y5 +M/3'=]W=R'YC'A_M3*!5I4A`_JH]O/S["9UH_?]N?)]KGBTF^Q?G0CYG +MPGO[?&Z%S[P@WZ4K5+/V(FI3Q[YCO-,$VS/23WN$V`^HO=PMKF7P?T8*V$]S +MS2(^M^+YBO>J#U2-WZL^<"G^4YVJO=^>^CD(BJLWXHWT!Q=H?%HTXCW0;SC+ +MW\M]B<\K9X0]PA0F]I^"=E)^]'PE?-^S9@_3<\HL:@)4(WV4-@S(\S+)`\#O +M^9RL&.,^X_KYP]W44"Y&E;ZM?EF=_UG;K\XD5M>=SY7_/H=]4)T'WLIS[D=F +MBTO:F(,\!^394O:]AC;LU_KHMY&^.=:&U1O':"B@[_!Y-WM$^'B)"U],M<7Z:()HY2RM(SF`6](;_L&V=[5+CY7A+1)W,=XS`*L +M+R%$R1'0T&FO3"!?/I\W/=C+]=;. +M0E@0?M\PWD!G'Y3W$,1G#E+_>2'I*U#=M3WX:\A43P/K$H^#6)>,>`^V!4S3 +MDS0Y[U<\5O>K.+"0S]=Q&-\=[)_B).19V00'@SI/Z^1^Z,$U +MLF^`5DYS\IBXH/I/C4-/QW@X;1WBU#V(@\NR(R8N9QF7H\G8_T:>%;&^6"WO +M]O#YU%B?J\F+V90'ECT`^.W>+W#-I.3/$NG%A@;1>L@*A!^]L+)PE%*W':)/\BAA:01T +M)A%TTQOS^7[[^20>C]Z8SSA+FRFQM$_TUVZU)MY`.YV`G-Z9='?K#>!X+T?F +M:[]UVERS0=N_W!IMM5MBM-5N^89I2X[1E@O:_F'UK=%6]W:,MKJWOR9MIV^= +M-O?=H.WS6Z.MOB]&6WW?[="&.>K'77/E>:.DB_)\[QM?E]_QASL +M3_P?6'R_IL:V-W(@ZW.5S-=*WZ/1A#EMPHMQ)\3W+\+\#UJSJ-X:>G=XU"QL +M?V\Y==5"[PX',;:]T:S[D=/SVIO8IIY,9[_Q_M) +M^[00-?Q>ZO"(_6^1A>_0\EU8=0_6ECCBK1V[__H7^#=3\:_NH1C_:C^.\:_V +MEXI_M:TQ_M4=NC7^U?;&^*?R3LV_NF]-SK\Z9XQ_"MBG^W.U[?]GUQ +MS5=KU'MH2TO4QCXX3?B>#]MSR1=TZ)_IQ +M[RG).SIOWI%P#WV7_0/NAYW&WR/>-U-@IVR9RC^V/J='VO0QGRGF9%+_$VGD +M.XSL7S2DUD[>5/\TWG_O<4ZC?*IPNL.C[#-+2S=]@`Y_S+Y8^#ZAJX3N1/A] +MA!.T^"2$?\/E:O$S$/Z%'A;U%:3N.1VND3"5YUM(L\N09Q;"ZPWQ*0@_88B_ +M"^$?RGLY\G[N#>U^;J-3W<]M=$K_-E[ZFQ'OX44QV_QPDF:S6P#/C,'?#,=L +M^<.Y!OB@!H<]>KC"`._5X,F`-QG@G1H<=NGA=@/\K`;_%N`=!GB;ZKN'>_5_ +M-@"F^68['#3`:A2L$?/F9;'[L#>J$--G@H6E7?AGXPSS/(/BTP +MYZ;KY"\'$D,F)X[H^Z+'X'\KQBS_94,'^UE&M3=S:.RG<*6A@JU%J+" +MD!FWDI>CI:FQC +MGX%VZ"[IQRHR*GT9R'5&%YDQ5YXAOG2ROZXK[!-P9H@25X7LH^4AZ#Y>>PBC +MCE\Z9Y;OPGQT,$`G\WF^0?:1+W-G!;_,_79SE%+X7Z+-^916_P4M$#L=T^V# +MRJ?"IEW)TJ^B\#[7?.H+DKY4HP<:VZ0/A;U.]E?+>L?)O@3#.YUFI,ML-@O8 +MDD=[1.6T93%_V4=7Z/\D+XWY:XK[3Z<4Y*O1 +M>6DWZ?ZUC[JT\L[I_W5"WPQKL.[8^HJ"Z;+S#!I3$0K6H\ +MZS]]G==#@KX2]I5\K/24O(O.]Y=DN`Q]:<&(]UB>WI>4?_)CI7J_8WTD#C2> +MY?O7[(/5Z,/T=FD.T#'YO]#_%^,1VKX=SUD\/CP=/#YECU(ZY$K:.+K_V*CW +M&-]93+],__AL2]1"TG^$-\H^=-D'YED\/CP=>)2-]M_E_?)V8YS\MX'WI_S? +MLVY1:9'K&]'#*MT$&B"CC;E:.NDS8&8EI<9)ER"\;SJU=(F<3J\/^^I'>CV= +M17B/S=?225T?]9KCE6L5WG4^+5VR$9\AC2WJK3G#::*5%NDO`;A#2!_7)]V( +MMPGV_S\N4'JIZ31LGV;57P+T.V2.O2Z@UJ:;!!$?R;Y%_4%^? +MX'$5X;#N:U[YU'\KR>`_G\-S=?_YD_N"?VL'^\H+>K:8[F_A=1V$E6\C\06] +M)?WDZSY0C+X!XO_3)M*M3 +M_"_IJRR8$?&(5$\Z8"=>CP+&\$/ED$WH8JLIG7'UZ?])PS?&OX??EN-.D>AM +M&"#B?]]$^/\&!430C;!/?$MX?>?4@/3A;N9_X&RZ9J*6+W2?`,<7QGR+'$^/ +MM<_Q%7K[X#LK0(\,:M];`J;GT[1OS,<=Z;%Z)=C5^'(B5U@QKE6Q3Z_U_=J] +M09ORQ77\[0`U29]:W+9UYSG41\?LH/*[XX8<29)WSLCN7PWLD^8 +M'SH=N9&5RF.$]`L[HHT1H0!%1IRS3A91BCXV2)\[PY16-XSQ82_&!\T?HQH; +M5I]CWXOL3OMX5=>5?YJ28+QB%\U;T(Z^] +MC_]'V?C_<>%9;OC?4@_[KK>;T)?="8?=F+ +M(G&)_>L@7S?[@L\.FWHPC^K)B(AP=@1SQHCXA.]Z9T0^$=(?+]+67Y7_<^I@ +MF=V$MFQ!N&$;^WK_\H_9Q0'I8X?OPX(&:4=!/LJ!Y_?9D6FIZE[LR;E3^G&W +MW=\C3#82U7^S7-B2L=W&'E&@_^7 +MO6L/BJO,\J>;;G*!?MR0AA!"DC8RM6U,&;8J:Z5FK;&GUMF-6QIV73/+CC%! +MQXVMZ[A,C!$)`<2$:C`D5)FD$'FT;L;%1V)KP2PSI1-FQ1UVAT=KX2[C8*9E +M"%(,ZC7!T.G'_?:<>V]#0V@0N4`>_4<7??N[_?4]Y_>=PL-(Z0;YC2YBKZ".)+?3;DY'EOW:%CWJ`^J1(QI%H_= +MC7DZ.^:Q=^%G_5#_017:&(OOJY*^7VH'%LC4RKT:DU@_-*10+U86/QIM_"^D +M\53>*H_S$>/_2./;S<3]4ELQIV@H%*5[OG4>5JHIZ4:O+)^WC,X[0-^+QK]$ +MSIQ7B1R1>GB8T>]9BS);^L$E4,[`.+./[B'@\?)@V<-M\GXFKJ^*?;1W$/7[ +MH,\=2E\FZ9P1^?Z$]+Y7[FWD$NB[=(^K6-D#(U3:;&6)/-5-;L?Y4MX5!:U) +M`+UUWQF:7[HW$SZ7:9NMHG2N-/;],T5>;:W4G]0UOO\1Y.$^7E/TI/0_MZ.M!1]*]])H?CROF<4_[*;_CZ>]G8Z* +M.!_^'NV=@&.59\Y3[<75&[%WC8?R)O)/U!-A5RA$N84SREZH%&OC%7^`?)WV +MJ'HI$_&JG7B>Y*4[I?XD$>?2>5YXZ8TV^N_(#92;O_1J%_I4=HSGM]\$NF.8 +MO^,+\$7O.6;A.5IWQ4]3KQ$!<[CS\OX8-%>Y2>I)@G9J8)RI^E@!GN\T54MK +MJ]SDH-^8[=KI>H2X#?]-.,N!UN$2\7OS]$I9@JA++34[T$U:6XG&)QWGTE2]O1?E;PMRL&[G9 +M]OP@"`EF:5]!FJ/X27D_$>I'33(C/S'@2R?_[^[+]Q-G"?MY:9^EH`:_;\K% +M.:K(GPL)AFI\[\#?:AKO5X!Y)?I$_-SDQO$JO+Y6?-^&KW9\=>#+@Z\>?/7B +MJR]:_VF:>]ZU*NZZK<%U&/NWS/\N$:"3I,C1%A;/-6W#`#?7?(A=.P- +MPIE]0?)';N0:W&\'_A,:^I'?/8*\1'<1BG:P8+?7(^UE(?Y8XC,:Y#.FSI%& +MJ!.!JQ'!T+J[!\+K8?`AT/[@)C9&\\GY]\D7BLZ!-N0T.ZF7?H@SYTL]9B+Z +M$[*`PI,",D^B&F97_A`H/"D!QTVT-W.='RSX/KENC]R7,)1H:F6OX-KT(T_R +MPT9Q/_(DWT1O0E:Z-1_'PCPI$]_;Z@H@D_A1G=SK7^)+77F-(/6G1HY4']&C +M,+#?IJU1^GH&$%.2@YWP;#E%_CO1_'>G]@E:21;D?"3;..^;(D]A'Q.W#1-EJJ5;QB=QWL6NT%[:-HDQ_LL$F\H,!&TCUG(`MHWYXLHSLX#U45S$/ +MPROY:'>82]_33GR6]JI%?R=T%XY27QC:[S9-VL_G(FQ^4>%OH8/WM%#?R5!Q +MCE7N1_1\HZB[IW$V?+?E2?O9R#P8]1':;TNF9P!(#_5%,K[&?-@L\>"H^+[L +MB\!7-PV^NDG]QZ?!5ZI/E9NKO&@C&,^IKUDUYLDI!Z2^8J\\1N.DBUV7J%_2 +MWZ,OW$Q]V0U2[RWB]4H-B&0A/L]HWS3B\A<1SXN05J>L'WR?=63?9"ZO\'1+ +M0UB6BTJ]1Z_4>YY`SKXGDK._XL`\@6PUKSM(-2G6HIJ?\).?>$VJA9+M!BR> +MJN#!GI(@9\Z5[;CQGZ]T.XZ*W$M8QP*3;;GU[9<9L^EU)]2L>6QB9KN@MJS +M)6NT*Z2K?4*UF@/!.@T^&#`'(`Y-^"B'RLV^># +MD+[2770`^+N^!J@\RZB&+=">AK3'5?9>7">X5K;I_\`Z@IW2FMN%\G0YSN%Z +MA+CZLV"H.XNR[P2H/0NZ[L8!2.H#?L`3S:F>.I/DC-^QX;'H0W$5 +M>G9#LIA@+GG?-CJG^D6TWV2(J?CL:A?F727TF_3;U)-N&^*7?>@/K"L/#\_[M\76%OQU$N3$N2'M@9.>!=`^1UE7'@``=N3XHSL4U]"E`\!#I +M9T-R1Z$`=S\YL;Z*'@`^VPO043AYC77F?@1=#YT;7V=3UUC=SLEK;&/?U#5V +MNHW6&/)[+H0*ZTQC[#-38B]WZL1XY+7)?6&/G"[$^1W](:2\$U=JBG))2`:^R` +M^FML"72NG;O.W5MB.I^7SN/FKO.WWKB6=/Y7JT0FY>6)!A?EVW+OOK?OI/R< +M^N*%CZ5ZL1^X*<>&\#'5";Z`MRYAS+5[X>U[E7$+/8>*?,(R+=ZE(M4SVAAG +M:C^`F&U[4HY]\K/`;[_0G=\+HM-0M?TFX$3DC9CCMJ%.IGT>FSD-;4+3Y.K?GND.?CU9KOH#R?5:WY%/W959K/I.BO1)7Y+FCM +M8$UG`O<"K#OX7V`Y^->@N['Z=G]<&JPUM;*]#YT]]3;#IQX?8T6$9S?F]B/IK'"\W6S&B]-LMZJIY(0WX;EYY\NL:G +MN;$6XHGC48VMM>"[N':;/Q69#3"WR]FT5ZJYK45=:/,V@&D8FO?J<%[43Y_\ +M_Q#-`J[K/NMZ^,M^:*Y2M5X+87:@'MRSU?K`*<6?`[S5[1XG'? +M]4\`&[VWA\;WRR#?-@!QQ4]B?DI<2=MT(H"<7WIV#O.?4T5#>NL/Y?S';_%D +M#3Z&^<](E'QPX/)\\,#GH*U!?T/[<%(N9,JS`^5!Z&?YF_OL$`HX$OSH[S`_ +M$3?FHAXP1SQ=U*XGOB[EB#5@.HPY$N5*NSZ0]^NDVHY_O\T:W&];C[G.VG#N +M=/_G\[A)QY/NF4[-+W]*=?8L.1^+R+7#>7:]0_2_TDUR7W]X^78]F_I@H;B&3U7<:'8!IC3NZJ^`)V$5;U/JN/0WD>[?(A% +MBL>-N:Z`'-4[W;,7R+VU!A_P$74=1L];4&VG>Z\`M05@:3O9#J-CC@3D>AKZ +M9VX6+V-VN@`QPUR`]LPHQ&T/,E'K0CG,\U$J^ +M^0T7U8*Z\[U`-3[)-S]ERY!J0O^"F/D4WSQFH^<`N,X1],V'(C#['#%[BC#[ +M!#'[I2-P7,7U?UF$OMTZ@V^W7A>^_?KV1^_=$?-'5YL_:NM96']D7D)_Q,_@C_CKPA_% +M;&@Q;.@WJMK0),P>FL"L\!QB]IB,V8YS,F8=`XA9WI?L.<2@@C#;&8%964_5 +MWYZC72U8Z/5TG\9P+]I>+MIB@6R+A&,`,8H3GN$V*:)/W +MR/L/2\]4^*;_OX?"7+3'7+3'IZ5QLS&?^HN<`\*5_N^A!G$E3&F_X;:3'@G3 +MFW/L$*![0I(=MDIX$H[LEVB'B&LDGC6E,I[^,<3SJ0D\[W]$?G:$E;Z^)8QG +M<"J>/YZ"YX/3X[EQ`+2U%R$3UXN$JUANS@FHQ0MBM>HKRB]>W[7JCI%8K5HM +M7785QNH9:N4/W>WJYP\\S,)]XKX]]^$AQGT^L,1JU;$X>6WZ]AY+S+>KY=L_ +M.AGS[5>;;_]?(5:KOG9]^_7MCWXGQ/S1U>:/?E\2JU5?N_XH9D.+84-G5;6A +M29A%KU7'J5^KYB%6JU[06O4`^;7YU*K1KS;-UR\N?)WZ3=V5[!.O[SKU'ZMC +M=6JU='DN,U;+4"MW&,Q34Y/?,F(_QQ^%'3//4Z]$+\! +M#QH&P+@*W=YFR"N:@0OMCN!"PZ`CWA,L-WO#O.BU*;PH4&X>0%F;B!M%XT44 +M/R-Y$<:E*;S(,R,O.GQQ=E[D'YLNCD[PHG'?'8ZC#T^)H[MGXT6?O>-7/[<8 +M4B&&MESY,=2=?R7'4,57#4SQ54W7AZ\:[EN`&#H0&4.E7C'$]6;191?J+5*7 +MXSUB]ET-\7,D]MRZ:FOR\R95U^2QB/@Y(,=/(^:>=SLPU]PMY9HZBJ?EPY-C +M:7?OS\`T%"6>[I;C:<4P_:]XW'S](K@`M;L!RC&7_C[Q3+4[M>X37Q5Y +MZG48%\[?%HL+:L6%"QVQO.I:RZN^MBQ`7A51F_QV]Y`7MC:IUOWC*]OG7]^^ +MRK=Z0"O%^`>NH:L7[*[N. +M>MWF>&6@ZKVSF>I5Y8-RO"?_5/'HE'I51W/4>E7%(`#Z*GA.JE?];.;X_\/) +M]2KR6<$$.<:/UZG67L8!AOPI0D4.4*9QJYK/7Y:O +M?#L.L+#YBEKQ_\K.5Z)Q[.>(8W_Q#3DVQOK#Q+%[W_WF->%AV<:FX]9!XM;' +MY\BM%Z#^N^#K^Q/8_I"P[6'ST/[-?5K +MN$,TQU@9U^/5<)NC[MN%<'XU&+ +MR[CW"@$::"^GLL0M7GAK@'3\+.UUG,J$"Z@C_'S&_=]I/IJ+YJ2]K1OP>RP^ +MH:-XP3L6(TRVXMFE?JT%-8K,Y?]G?L/TY@-\=%_]._F:DW0S7;/Y51'7G\']?B'UHY:OA]:E +MM4##+A0[H%^3U+8I7T-[*+E$SM`N.@U-(9:S@O;\V?DU#T?/`U^Y!ZS4UYCV +M_A;*#6[C,R4:]-%9]?AB*9YJNN;?#`'F0AKXTVT0UX#?F0MV7DV2O-=K69*= +ME1M:68)AWOU<%;F%Z'(;)+E#G&$49?>*G)$CN3ZHFV8^B[,3[ +M%-D%DMTXHA=(?O1K6>)Q17[??.0W*/(;MK!R(\8I@Z"._,:LZ/(;%?F-FUF% +MT8KR;Y7E3_)&E]^8)07['_^^SJRL\K +M\O,HOPGMWZB*_9/LZ`-;T*>[(W5`\G?G;P'K/@U#7]/2KTF^ZY91#?@3#:Z` +MT_"."66D?5?-?;`,^8]#K#`)=(SQH27H-+07YS$A^RN`KD(!@IRAJ4B0C\T[ +M,/&=P`<1"\*F,_]C^)^11I#Q6/$+RK=HSHX!%QP]"]:[*^PR'BOL,A[)'107 +M$0\5[<*X170:LZ+C8=S2KTEY;`(/HS7`&6]+[$GR3H^'<0O%4L1CZ_1X)'EG +MQR/ESJ7#(^5D=#PL'AD/BT?&P[*#XK18KDZ<5O#(1SSR9L`COU^3&HS`(Q?Q +M*$SL6>Z)@D<^Q7;$PSD]'LL]L^.1^KNEPV/EYNAXI.;*>*3FRGBDC!!O0#Q4 +MX0T*'A@WC#/$#2/&C;3#$7BX$(]W$GMN=4;!HX6X!N+1/CT>MSIGQR/MD:7# +M(ZTM.AXK!1F/E8*,Q\I"XC&(AXKQPXCQPSA#_#!B_$C/B,`#XX<1X\=]]BAX +M^(C[!)RF*/'C/OOL>*RZM'1XI-\;'8]5)3(>JTID/%89B%I#2\>M5GNC,2<;&Q>!7EV-"'&NM9W$YUMI32X?).BXZ)FLWRYBLW2QC +MLJ9U,3C6-)@@S[(^M+@\R_K]I!:TV""\>3&PXO+MVY<0OY[XPS\ +M=[W"?]PLAX'TS_? +MR@X]/R3HC[CP,Y[I*UOQ'`OM`B<-XP6!WRVQ)IIEQL_Z#:=E9 +M)3$=6L!2.]Z99,?N*!2(EBJ[6BPCQW[2[3GW/7U+),CL9_S@^KUW[GGWGG-_ +MYYY[I7?N%28;IIV8[)A:,'5A.H)I0$U#F$YC&L>$9:RYJI2W)@C"(WA^Q(II +M*R8OIJ"QXR$O?R\FK+Z&\BSS(B]39`]XX1\")#O1.`Z=H`GD339RGD.OC41T +M1AM=SZ_T;,;K.O5Z"_W>'K:'Z&J[`E>$K^@P;TYJ,K(K])P(8K0..D?R)NUL +MP&1".K:?6C:V+>LQC'B%-?6XUHUX8D4E^Z6%ZM_45'?O.: +MEZ,>^0<8Y^BWF.?@L@+`([&&!S%ZH$% +M+@4F0=]@9*T!YG-B_YT(CD/K)Z!ON09%;38VYY8G8<*.*3B-/N,RIG&*6=)4 +M!P,4$Z"G=ZUNQS6X;)N$@U-,G@C^&&H<`6/K;M"T*;2:F066FQ_:_LRMO.0%["]MT2.>6RE])ZX.`CNH0AZ^@GR5>BOVH\I?J9 +M"/*>(CK2W/X`Q1K$\M@QCT5Y1VKIX[_ECC*[Y3]WD;R1`8^%9'"RYR(_CP2\"*ST6\A%'V_*T7QMBKIE5'ENHVW(D^AXV +MEW))]U.J[FBC?J*5#O+8"KRWC&>+0<`^V8YZET?;CK>3'(`:'%OL;7#?#6'M +MMR?DFT!^&WUR^YW)MG:,ZJV1?\GX[]L*:SNJL=SH&$#UT6=7DCN7\F^CCRF[ +M/H^6Y*[/HUW)^CQ:^QO21[J-/N'<]7FL+EF?Q[[\&]+'FEV?QR[GKL^ZU2GZ +M_.K7K4^2OSML',GL[]9]_\[]7)9^79']H,ZI-]-\%&^_YC#IZ[O(XZ\IL=Z4K[MSNK)7)=F=].FYWUK4Y +MV=UA@VIWI;-I=M=CR&)WI?_%[:[7<(=VI\C/[4YG<*2,LZY0=VDP-[M3RDVV +MN]*Z9+NSKLMJ=UVU@P&=L9]BZ=#/Z6\(ZZ&FE84H_I+EU0ZRS@T0ZH1R'FL9 +MLNA9_G/7V8(9$F(M5U.&015RTS:-^";I-_4'IUF-H4.RW +M[)O#[\'P%=`X7T+_X+T`;LTM:,7/!VXY".'_Y?&\0FBF +MT7"Y\0R<;`/M\0CH7XP]?&V%UNB@ +M=184*[XCF&5]Q2R($PX?QQ8_8^C2UE@T01'I$"XPN-@/<4R>!VO?/*R+'$2, +MU1CN4U%LYT$3/H0VA/:!UY:3K\)JPI_B@5'>U<0[83\#U78CB_R=!4[];1SW +MA8,6\;AJ1PLZPRCI@?/]S6_?FA-9@='V=G-`Y+K8D8ZZ95LOTC*5'LL>72-* +M:TFBZT2Q+?G:$8I=?SMR(:_O5=2)8M=_"'FD8TPW,4$WM-DAU.D$ZD;QSSNF +M33P6FN*%>)SZ_REQZA2C'ETS4WH +M`P/NEB`X#X"6XG/=\BS9TH83HM(NX:YGSU)L?]A9+T77ST0TSY[Y+'RK[4Q6 +M\279#!3/[\8QA^\_UZ;@6^B`#:S[=OC^8"X!7TT&?#7$2W'>V?#E8TDO]J-> +M_2#U.;3?!J:I'71^"BM;(^RCZ\*39_EG?-I_\U-\]A#Z(G$#L/U<)\4?I?LB +M*3=?A/ID\T4BRBRR4:_PY-C=\$>HZS]G&V<66_8V2Y@MVE\.>*1M%MG+G&;# +M>O@>8D9[NE8Z0#\_ +M8S:\>WP@'OJ`[+](O2K)ED$D%^V&"(K/5+?+O25'S'&7JY?OD-> +M]M`W&MF3SEGL0S,XYG6CG3G-<-GOH;Y\3Y7?.-?J +M9Q$G_TYHFJ^S<0=\@#9C.'X3BA;V-MX;F&F\[[C:GX::L!_=1/O;B_874->7 +MS9J`]Z5NW9[AFXKM47_BMH?]93BAO\A[+>(0^H>#SX'X_9_=LV@[B2`FE8@# +M81(IT(\X(XA+`^C?:@J(A,L"JP<]REUY]9=L_F.S(1PR:\/[S7JF-9S9WB`( +MUUM`E,5WQJC?D0\\]2I8W!_,P?(6`0@?5F"0(CK#F06=?I3I]!?".OTY6:<_ +M&^[5C\G[+0;Y#<2N&30L5+]\FV7.NQUQN]SX#CAW(UYAVD-W%@@SCI<\#4=N +MJ7A]&_'"/*/0SG':$=9RG^O:E3M>0X37C(+7B<7BI?J*&%[3(![_Z\7CQ?L. +M8D2X52%N'"/L,XB=MZ91P2V*%V$3Q4Q6,:MJ%`0^!OKF("S^2$.^NA"Q,OKS +M`NA_@X0?WY/XL$%"G&3"CO46:A&WP$*O?FXAE(#9?L(LZ*WDF+T7ZV/4CV*8 +M.>*8&3K:(=K/#,$\BCN(][-=_[HXW-1^-J3B=N)F=MS"^;H].'^Y;3];F+&( +M)SJ5?G;\KWZ=N!5*.>!6%\=MN1?QV9",6^$6%;>*L*[0NM!;N#D=-W^.N"WW +M+N'&<6O(`;?3<=Q6>!"??2FXM:BX]2!N=L3-D8[;5(ZXK?`LX<9Q&\D!MV`< +MMXT]B,]8"F[G5-QP?"L<1=S.IN-V+D?<-O8LX<9QRV%\&]L:Q^WY>)YR[7?__GC_]R]^7X5XB,?QC$,<7MKETP%KF7,"MT$%;\P_Q,O&?&K&OF968$I'R4NO6 +M*GS_6(Y\Q3P62)5/+3O*IU/X>L:03TKD8^\ER-B]D7@+.&^'9G427[XBHU&0 +MP.@0Z9IXEW/>_+)B+-?"Y11!$VTC5J#JE1_CUT?;()$/RZ1Z7`GE%BKRCOFP +M7&LJ/_$R,<9K4'D'D'=#DLSWJO6+_#TE\5(?V1R3(=L>`R)]Y[BI4FV'+4GM +M*@C>X6C[=V\BFUBA\I4KI[S(:TOGE98E\/Z1PKME$'GKTGG+$WG-"N^?VI#WA73>]D3>^Q7> +M!/+7:7P?LV!O!7IO!Q3E]HGB?\!A7^;A/SU +MB9@E])<'%9Y-0\C3R,OLT.S)U-=#W=^XX(5W&O@>`)U85R>;.XJ)]I7`N8W+ +M+5^'"?DJN)II#X'M:Q1[TO\ +M0I4OVWX$2MQ7Y3#%<`>K`>IB><_S74:KH#(<#VXFN9) +MGS#Z9SSC*?5ZBLF[#/PS(S"-&RE@U]_K*\PG8_E4=TO/81C9[# +MIX@]>!-`63RB[T?!F_WWW8A/T=Z[@T"+3G +MB?7U8RQ(N`VL8@')J8,K0M4`[>O@_!2Q;&6^$@=8CQYC`=??S(-?J&K17P6! +M]IH8.L;\)U0UH>T\,?U\/Z(A_;\,)?ZP5JZ!UZD.MI^ +MQ;B.:CVOE.P#J_,3O#]X/SSNAV>H/FH/GN>`O^1Y^^^G>#@GTO:TD3QVV!27 +MI_(3DH?B*!6]JSY<=Y7B0*L^&(IP_7B]DO-^JN\LWC\3U0O;>(K7$G&4CMCX5&Q:E3AE6\LX?!42,"4YW;,H9^H;B=:)OLDWT!VH>P)9'MSKYFQ<6DS[#U) +MM*>)-D1Y&7WD`X!]J[90^A*=;;/N]J?03FTH@ZU'>3]=R^=5[\L4VUJK2:23 +M7N]#&3TW-X'/89[W_6!V/X9U2=>%VN^0O'BMIVL\%ZCG0O6L4\_+\B.4N"W8D\%Y4Q#?YLBMQEX]BT$4OX^JO +ML&9BC;?/BOXH*7/^*FW*_=C=$G?IN+/C@0ZU0SP46)&6F4JC^WQ)I:UX-XT_ +MC88?=@%&T/['%R_ITO&%/`18]ML6X0_X8(J+1C_,3_2/Q1PS4S.82F#JQ1V. +MX[<9<-,."1-]MT3C"WT.>`+3@[=[H!W*S?@'_]N@G-\W+-&7Z$OT)?H2_0M! +M=ZETCTKW+M&7Z$OT)?H2_0M`%P0!DW(%&8Y4JJ`>L7OXC.?3RDM^/O4@V38H +METX`Y;M*IAPR0,\80*\?DPW@<`_`]XH!^H8`CKP`\-J46L3@MKH*:?WCZQ^W +M2F56Z\92:QG^EZP;GWIBXU-E5NF5`TV[UUM??DG:M;OIE?TO-KV4393%'Q*F +M/XZ`T@H7S0#_L1/@WY'Z;C_`OZ$N'XT#>$T`4Y<`/M@"\-\-Z;2?:Q5:Q`ZP +:H`>XA3R!"DX3\NT@B'.)5?X_S^VI\1AH`0`` +` +end diff --git a/sys/dev/mxge/ethp_z8e.dat.gz.uu b/sys/dev/mxge/ethp_z8e.dat.gz.uu new file mode 100644 index 000000000000..ad582bafac86 --- /dev/null +++ b/sys/dev/mxge/ethp_z8e.dat.gz.uu @@ -0,0 +1,639 @@ +/******************************************************************************* + +Copyright (c) 2006, Myricom 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. + + 3. Neither the name of the Myricom Inc, nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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. + +$FreeBSD$ +***************************************************************************/ + +begin 644 ethp_z8e.dat.gz +M'XL("*N.]$,``V5T:'!?>CAE+F1A=`#L6F]L4U>6/WZQ$T/3V)1`#"1@D@!) +M^)=2:#.KM)-109-JH;`MS#!QE@";7:4=M./2E#5,B)U'DD$KVJ!IIM!M2M@= +M*F4K.D5:1LL'NJ0+2'R`F-4RFGQ@59=-HTP5P"6&N,FS[_[.>WZ)_?*]"_NCWZ/?H]^CWZ/?H]^CW__.[)UGI +M/X\2C]1U[6RB8MH3([N)[XJ)?8UXZ2O;772+NGT=6T5ZS,RX+"OJB +MY)Y/_EMD]T4DHK<.D-WO%=&@;YCZPL/D#XNAH'*?FN^3/:CB71OGOG[\:BTJ$OR7K1M9XNNFY2 +M\/BS%(PH]-:KE'TQ4DG!UC@QO^">2MSO`V>8W'N)!FE&>2?XA#2>EE%Y1N6G +M7B*V$X_-]"ATDO/MN6)80(9#N'?/%4-%G90+?"?HFT*6K3N9O@/SJSO)>;8Y +M;.UX1PP[?&1Q'R";0R$+=-C5C;FB7)7F3(B>ZV0:D>?Y*I[G"<>/>>Z)8YZ1 +MV#%/Q+^?[+$\S_T^KVHK9Y\7MHJ1_>!M"X +M@&Z1$7FF'7I91^696Z%7(*%7)'B2Z"*N#!]9-9J9YS7]9T[HCQ@Z'/$W9#`? +MS'>&+-NJ=?I+OBIRG"1+-Z_[VVI+@D>E%IN/K4]:__'$^C?T]0\EU@?L"8=+ +M7_\Q5*`Q8*[OR@@68+*1BHB*^Z55-TF1H/*6N`=H1_;Q&=U +M,7*^T";\0:41PY#I.&@_5#29SHUI?/\= +M/&I'F9_5C`BE+\+PM?2B5Z$QF0)UBIWZO!]0S.H98OOU13HQ_DB5KR]2#[QP2ZS5 +MTP_:"Y`SOL-KI;^TB7"?-\+\_)B+;6H0H?%VHFL-UT`#66)BW&%1,AR^@.W: +M\%G,?4+9+4+AV+W64(\+M/<5Q[7A3VB'UTO9`W[$JKC+L2QR`K3I=EST>:\" +M9US`'E'.&1$OWA\5FV[W6F)MGOZ8S3,4M]7:XVVU+M%>>QCVFJ':/+/V +M5YI_:]LQEZ_YH?:X:*U%'-7V!'U[X+M:-=Y%6^TYX)]+X%_1XF3'J\!#O-4. +MJ;%FW=$@6G=<"?K.JGLTZ/N$ZA1R!WVM5+=_?H#W:E#Y"#R!U[8#OMLU,_)+ +MCLU==@4Y5U%S\%EU/V@QOG#^(K$A'-CM1)JXLNYY/1F7'V1#]3*T!>.X- +M44VMFD.13[S--.=+,[&\WW.:8EQP9?D=&[;7X65O.?$\\_ +M[M+I8>O1$#EN4UF3_1- +MS(]8=Y\&KUG,ZQKH8VV[SP+O9HAVKTTG"_SNBC\00QW[)N3X?//^N.#GH"]& +MW9CG=4?E6<7Z>NEUVMVKU899K0*]4.]"A9_;V/98IV<$<<9UF&L8^J8H>/I" +ME.=5:QS7&&4#QUQ/&OZYD_QS&Q,\SPGKWO7-FMS1YH@88MZ]S?=H`#BHT6'1 +MNK>"ZU?OOC&>>P.]DM#DRGUC1*(\U-9P[X$Q&FRB#.XO1N4GLD-4HL;"B$P? +MCDC;MF'.':+27G5.HCD8ET_@@`?&54DTVT:DL@\QM]5`4V^@:=3'D&_8O4_5 +M:QWH3^(*)-8];N#18^!QSD36JP::FP::X:FRSJ94FMG.5)K9;GVL]1A4CKFU +M!IKU!IJM2>/9&$_HS[Y&WA;@0_Z#:@P>UVK:?7J]2401`\>!WZGSUV-'Q=?B +M9TB+G]GG)G!0FB^Y(P1;#L&GP\'(!D+O")O.5CBF]#4=35K<<(^HKQE"K'"N +M2XK/`5Y+6R,W7U\#O`^H=9>Q[KDPYV+K7JY]EP6>3<\/R,NQ!V*X +MX^]AM_N4AYYDT36Z1=>:_ACP_XEFH^:.\AY'CSPO&+@%G42@&[C(-9>T/3_' +M-=V>AQV'()S%>[H_1'.Z:\/_BP):7SEG)_-*(T,_GRMXSX-7S-UL83G^2\T/ +MX-4MQ0/\C%H_=$*.-W3CBK=[H^IS`L9RH$X.F?*?R!=S_S61YMRBYHJ\HX9\@QJ==TK?7XV+R=7H%J;^2IPU(V]C?W4B#US, +M5VE#$W6&SZ&R%B\#Y%K'.G`-X)S"YTV<3SZ,: +M?5XDW?X=R=Q;SG*C/W:#%^(][YS1;\GO$1##C@XYWA^,1^`_5Y,6E[M/"OE" +M!6+6U&;@B_SG\FHY[CN*_3>?8VJSRO8S\\Q;P,\T..%AIS +M*(&*J;!Y5B%GK#&9SX<-QT(T;PO+F#2_5L@Y:QD_Q.N!QGS/[C[Y^CQR0;YSQK6:367>5X79/XZC +MLM^A@EKPL8CW/"(G3%F,'_3=[0VBZEQL"I-AC1[SO5G0"UE?,IGOU]Z9+OLO[#2W_\+3;'_H +M%$K-QPLO3>J$]4`CY,S9/'Y8W?0+_"W=_X3Z+5L6_SGTZ:ZC\\GTW;=[(7HV +MB?OW11\@=OHQ1I^Y^#=Q66I*V/:S07(OUFR[^(U4>RPZ;V[;13=@V\_,;;LH +MG+YNN+.A_V>)^'Z2X=_";FL2<?57E&^+\#JCX!.?E<>8<6SV`\GB]R)<>\>T#'XQRDX;IO +MBO<:B/%2>2]V:O;)>KX[@<]X#VV'5%ZUVAYT^S9Y$W!2^H<5-X<\,Q+KJ7N29GV;/86>(^T>UO?IP]H$^PHR%:GXZ%HZ`]J'1FI$XA/ +MDSI2=':BCLSG_5-T2K7)".K(<;UY+B8BV.B[>G +MQG%QY:2/8:?OIY9T#-*26:CG`[#U?,EE:GU?,F*AZ_G2WSF/EARU-P'2WHT'RRYF>J#);V3/H!MOJ,/ +MXNR#?=0]2$O?Q1WV+WDA58ZEY>;V7UH-^W>;VW]I??J:LS3`,-BY.Z[UQ4^\ +MW!0R],5+3^FV@DP?#]*R=0G95AKPKFKK0+ZIZ_#Y[V-S^9:E.?\MRT_D](^% +MS1@CR[C_-;'#LBT)FFI5!L1/!^Z]!_A]Q;(]#(,<(AA5.!ZJ&W'N,<'K3,;C +M=[Z,>\D=(Q/<7B//-'A#J7A9SZOO``%G_%0=2G*U6"MI2(VUDA63L;;TJH&F +M.K6F(4Z^GWQP89!*"[1<4/J:8B35AJ7>21N6G/^>;!07S3]#< +M1F6YZ?=K&?8_!:?FS+)J__MJ_Z;NO9<5Y!)9AW.N+&O@]W:.?"H/'E?X_;:3 +M\>J:U/=YCE:.TT*.T[*C6GT7Y/!-X-IU7`//\QS/.I[V3B-@R!UE(7._E47- +M_;;76JWY:7I,9WZ;?.;^"ERW/>(,]5U+LC"1[]T_%@/VGQQ7Y<$?ZF=RS\[F&05B;.LRL-_%NYQ1$QB[>5#7J\H6=COO]L@!_6XFYE:,26W$>O5,\.X@EM +M7P%^V$#7FQJ7*\NG>Q^IZ;9JOZ;;:L.Y8%7V]+JM6F&NVZKUJ;JM_H$!KM;_ +MD2DU=%73Q+FQD/NG5=?4?JN[3A2[S?JM5:6 +MC(P,*<,B63(`AIJ4E6'-L.'*3-RSI`S)BLN6N&<:QEE,B\N:N-L,X\QO@&IHR-O]>`O'TPXLNA5Z?Q_]%EH<_=1U4SWR?VT&6IH9R +M7AVQ';L^PKU[V_ON4?G)DA"57Y_F77)/K'VO%['._^M*_W:@7^+_2IKQ_)8L +MKO`S?"WX.YK_N-]>92?Y68OZPLW1J_I"DG:_7[&+]SF"V(68#_;@8?_7)"6^?93NT)JV +M,\WF=".9O[BA_3>VIC=$A4/JN__4>B@-T)I+P/MOX$G`&]+Q3,\X^\10QUZB +MV`,QD-/2R]]D9=7MIZINS'7<(?Y>+8/_,^?O>[KOF+^W$_^XNP9UN=<,YK#T +MOBD>B`J'[Z^E[F9",L9XGUCK4#`>PUB#EQO@*Y+@[P.^'7!*P-\'?"O@E`3? +M8H!O-,"K#?#U!GB5`5ZIPT?VB=I1>>T*O;ZFVOI%]P"M+5?UL_0^[O`=U'5X +M7-/QH*[#XYJ.*?`52?`"3<>#N@P%FHX'*0F^Q0#?:(!7&^#K#?`J`[Q2AVLZ +MKG.:ZYAU?8#6Y29T1!]:I>M`FHY5N@ZDZ9@"7Y$$=VHZ5NDR.#4=JR@)OL4` +MWVB`5QO@ZPWP*@.\4H/O)C:4^@5HM^I]8?R09XCIN`[W12(41/W=$4$Z8[I# +M/Q\";B!$:_:H]I;5,VU`RRU/?R)D%_;WTR=#]%2%RDNFP`E9K7U)/>[3G8PG +M#I6]I*[%^1KK\5I8)Y/7X#5!JZW9=JS\8>NMR/R;$D>+D\\0VQV*)8#\M/VH +M_DU%.V`6)YW`G,,'F#0)0[T/X8P=1=YW +M9+I[LI5"]+2],%?-B["%A31;/+,KIZ6*.M3ONX8IG%&V$W-/L@P)VV8+^$#W +MAVA_I22'Y89L.1%+X$22W)`K])8,V23(YKM-O$[0]P6?I^:JW[RI?71%;K*< +MDSZI6#>]G!4SU#4@)\O(WZL-TS-761Z6,Z983?CS*LIK97?.MR@]G +MG2)RRP/V[7B7:9G64!C=R@HP+`3L,Y'`GM`\/X:E7]0I<>ZP^+.4+^CD,11,QZ.EJ.\9Y['^J9PQ(,;=KH2 +M/[2\T&&A'X8SEL]T^!3UFW/P]`W27[2A'Y'^C[BO#X[JN/(],YH1,A;,A,AX +MC$DLQR1OLH5CV4L28F,C&_P5`P('.S)@21;83P^$&(00(Z'/00AYK0_,AY!A +M)$@M6T6J<*S48ZM(%9N,'V1+V2/?C)Z0`MDF,X:,WO0ASC`OLGLT`[ +M=\7AO@#ME7.>2+K[L*C?&YB +M?GWXT:GYX.%O<#K3_489^K#2@7?=?3B]BO'X24AX'KTM0`][M3KWZNT*T$]\ +MW`Y.!\U.,`_9HF3*BLAS6I)W1AYPT##:=M`<.\'XC.R:/P/Y]9*[LNU)!P__` +M=OLC7CTN4?F]T)=&/90\NFMC.?)V08Z&E.W[R`7TVVKM.S`F/T=$7\N(XF%\ +M7V29GA5=+'*C&)>UZ<2RE?,<11[PN`T\?U'Q^*)Y<3M_409P*I@,7F[41Y/` +M*)CJ/!UT[;S)SC1ASJEA>Q^Z-?3FQW[8,5L$^?L2/5J"M^DR/?IJDNE#2G)8 +MSJ*>7NC4%@U7\/]TAZ1I\L(:A(?`6R7ZO1+(J2#KO.I\[&.[A37?)Y+7Y+5< +MHU3FNY*K)'5@91\_NNAL&U$SGYDMO83\CZ:`7Z`K/-:`\>>K*Z>4CE9UOV?4 +M\^CJ=RO4O2"^U\-G7`/TJ-PO`0]WL_P#'KW@X6[&`[INTF5:Y.,V"+X?@CD* +M^2Z@W::8-?\T[Q4@[P4Q\MDQR"#658,S:Q%GS3_3?2*?G;YT<#87%R*\EQY8%Z/:5&F\$09?30<:1=07@:XO8A-\= +M,9RK?JQ"QTV'Q[1,Q`?14M$MCF13\R#Q?8%@:K^-SVFG]H2ZJ2<4I0[$(]VT +M(A2T08?O19K%$&_F\3]T1 +M?\V9*T&+DET6V&F+?\UIU0,BEAL]1I/--6RS947$GY2VB,/':BPF'^EY$`\5E,Z,(I/`?-K*7%PFR3 +M=GEL=RMT$J\O:/6V*9LTO\]@CUH_I\?O8'M46/)/>EG'L;;E!:V'LH5UO7W4 +M\_@S`5HL[X(U(HUQ0=W_'+06,VZ$?C;%2J.=+5_J=\@>/]@S-.H3=<5Y?'94 +MJ\.&.EX5NXOS`O3X*=5/\KN&TR/7G9AO,X/>:WP',=,K//?XABW%>3]SU(#G +M'N\*F&9*.0\9XD2_=TZZ/W#$,=T/(*XJ2ANDI=9KR5M.7(=><1TX7O-`WA[) +M3G65TIQ!>N);$0^EX;$'[RZX#7`S>T8BFO[YQ&GA21+B;H=9G35_8K>M3?'* +M3%,-,8]T0*?0]`K,V38A_MUI9EWCL(JSLZX!75GIT[O^+H_+-Q?B)%K;\ME6MT37,HM7$.V<\/\E[!$U*.1*$+<)E8'8\9]"_*,A[R +M'E/%%[YJ%\9:T16,ER4SL@8B4F;FYE'PZ&%*/0I8S8:$%8O`TQMA_F@.;7'=`I[%*.`:[:#ZE;[U!SSGK'L'7]/+$3]I^V!H6QF)ZK +MUMJ<+'N@>W5JO!+2RLY5\^_24R@_-V%[DR!//!"_:`_/5]`%D@7DD-_]8Y\_ +M=(WDG1EZ\ED);S2.7X">;%,Z[).0_]^SR[%H`>V@<_.]B2RWB+'NGANF&M8E +M0E;O7C5VGJR#72+E)./,[0",-N@Q4I^[51UWK#VR#1'B?H*^D.R/#&IM>>J' +M-ZM+!^CI`D5/[U[?'(;Q]!URK13]@#%ZYR`]U?`WPWS',7T8<./C_:G.L_/Y +M;FIIC>*OIV?<-Y\R1SU/G8%L#*@SX/H:I$FN04*?<79H,O!OP2&`.H>36S/5 +M&N/3\_2^`!V3U9[D4T]*G$#+8>&8?I^7^_WI949\LB*Q:C6&G^H6',]W>JI\+;^BA2(9\U>4S)U50?/N7]'\6^4CMG<8 +M#OIDUB`]L]`&FX%MZ5N%^W7@UCA;KO-7-\_&O(T^X?5^EOOGCH=H6SNE5']( +M,_R1Y;"U,@@ZRZS](Y3644JIH-%OI?S`7'8^B#([G/:65GV.?G9SQ6=D7IHN +M(NGY,EQX?Z$\9U;!>\N\#G'6?8W2-](]E^C955DH7]DF8KQ>#OLG]0!L0B[O +MA7THDEL[(>L*O+ILAYYXV4WFIE+H-#L@YX%]9.&S<.>.R3@Z"_O[G(/'Q4\7!>B9 +M4Y/KN6UY#T@YW99WRS(,L)A/OBYXTI=!G=+-8LG0&X.C/E\IC^OGTMG_0UP? +M>\[$:1S'/B(R)5\\]PSK:)JN^[OTL3@EP]EV/*KN[LP<]3P'_6U=IFYSJOLU +MSY4$3';G%.NO=NT^D!DP(%>>.Z[+'X8!??>);64T]V=WIOOL91+YN +MW=:WU69*/F#[D_FBQ2RZV-[E>YX8QUUJ/2;IXTOTW"?Q>I:ECLDYU,'W?1B^ +MNE_VG(_K8!U0R;_G?)/IE\#?R;2-:7JO?^AC15LW)=V?1H[?;0Q8F#_3B\EV +MB9:]S.DQ"^L.EP!WV6_\\V6Y>\3U[-2>6!_'G>!R",_Z[6#8TE).\WWE,J^T +M;8)W;AJ]#^GW'2`GVM`+/?BDM$&Y_GIO[P-(>^=:P*KZ:?EFP'*^,S@6ODU; +M<^P-T/)"WMOA;[878W6'\IA.OJI!Z$G+-RN=9_GFLRZB]E9QH6.V@,V[/#-` +MSRE?$0A+GN(YOYYUS8]]3PSA%-AH75I;:A"V +MIU=3NK"V8M:W`N(_),+EML+]JF$YB]B=!G5:<#^4LG"\& +M&&KN17[`T/./T74.W]U&?R$?[(@4?8]TU)/E>+=`K>%PV1#*@JX8NUEC]Y_U +M=NU">SBM0ZZ=9ZT9T>?7@%[92\EW5>Z1HKCJFU#X4; +MSPWC\+,:^GT.PRC.5OW>>D)K:YIJZR'8!EE,2_>MRL>J>\GL]P9XCEL4JS^T +ME^6N?VZ(_-X8G0\/T(J8\%VFE9O%M1JZ.?UJE3RSZJ]X2-Y1_IQ6O>4/ROU: +M_I;WY7DME>?*=LR;N@T8*Y>VC[S#ZA\*LFP;2Q/UK0V*GJM6\1EPQMD?>=K' +M^,;J6AL8]VHWS\NC/AZ+Z:6\KK+J?O"Y@,U_4_J+CG]U1'P>M+8VL'[54F5- +M6>(5ON'D0WM'/:M6ONM6?/.WP.6V=VAM#]!*J;\^T";M1X17-4QJTX,/>'[$ +M?/07C187]?GHUN?>,=C7%>SG%WR=L"&'+#U5+.>?_Y?KR8<"-T>WU9F2/^H. +MU2CYO/K[USS/VZ_7>8_)<_70T?Q]$8I82EW=8=ANI?\&>_UYZ1.C.R3U]RZF +M+>MH1Q3M)4_UA/Z-_.NZR!_IPCCT=D%.'8.M6U/=+Z*2!M#=6"<4G@=/\MS% +MOJ\NEY`Y-T1F\,2,40^M'!TN2!'#SE11EW\NNC,[O;)?Q)8/)?&ZI:WJJCI7 +MX7<-$/+,C&YSSO(64]J1:Y0V,\1^76"W7Z&,IBLT7VQS3+<%E6XH]QLOX/L* +MY/=N;\.18NA^5\AYQ*#[L>Z2Y8:=O<7)ZY%QW6^;TVR0H9:;E1,ZK2.6UF/7 +MZ]J=W4-$UY/;P)<_FW?-L^I4HO[5]T=8%];7(-Z=I^80P'--H4.DQ-<35O_' +MS=MQ+SJ5+;XZ$##9W,HF:\L[]YTHPSMV0,KJU9#AVLOWB;7Y>ORSYS'N(Z-?-8IUPX]5(-W:AW@]%2`#Y+7%+1<(RCG9/)] +MYQ(=O4J6?GHAD_<(Y+V40?LZ4==Z+*3I1`BO%*`AKPGB>S5P*\`[F]LLJAW2 +M]XFP%.?YAY[V29A\7AO\E?X=UAE>>+/C2_;%)?K5VKJ/;80DN591*B*\OC[J +M>>%B?,_FA7Y=+QRV''(-UQTJ"%G:[:&ZUK91SXN$?M#\7RF:\3WP)$=*-M+F +MZGLIO$<0H!?F3M%?%M:EJ_Z">0AVYSLC`?/9,)'RD?#BZ_$UU!>?C*\_1X5& +MXY-JCG[QI%P#J3^4^8^E8;/:BW[QF&[GLNZ+/!L8SN1^6`YI/G!^'F4=&M_W +MX%NN&^';@>]WM>^[\?U+[7L.OM_4OK^-[S+M>S:^7]&^[\+WL]JZ7,IERDY3 +M_/5SZ'^KZQ3]QN)6!^BG_?HZ0(!^/I_+(+X0^"\PQ,_5\M<%Z/E"0[Q=B_?J +M:\I:O$6+/Q6@3'L\_D5U)H+]X,#F/5NQ`/W_<_3_D[V&/$-:6?3CDV2(#ZCX +M;(R9-],-\1>^COW5>:F4<%_/U)8XGFU/]ET@]_N^P[SQTNM\9MC6+BZE5PEQ +MB5YR:>/Q).^KJ;V[EU[B..91<:U:\)K6)QGPRF*8?'UF3+%4XQC'7-CT8!\R7GYWT78]X` +MO23G:XRE3T<]+Q7H8PE\XM/B!Q%?8X@_.?G\OL8M+&M.7!\1H$*3S!5'J`.SV?'V/;DUZW-?2&C?75QT3'UZF +M-7(L\/ERL?N##%LM(=^:E=!):]3S0<9D[5!C;$VCD@-KG6J,KFD4'O9+M68O +M9,%"Z,(+$Y6O@!URO3Z_[^W73IO3-W)?K'57WP7;$',L=``WS\4\OW:[HY#) +M^2'(WMIW7@N:V?[,@?!%?NL,S*6\;LUR)N8A\_]\+6S^[>739IX7O:RC0]:+ +M+YPIT6T%L\26@MO;BR@UNL69MO\*L>^X3)[7VXLI`_K\?#'LF,YG;=KE61M* +MX_DYYGFZNP/SLURCMGH;Y)KW=2=I\X:M-N)X%FR)Z-Z]+31-5 +M']%LUVMDGGE5^`8+R5P5$H-5KTH]UWJ^($)^]_M453Q](E6CO`8?#2 +MQR)YB_-7U\)6I5>M_423VQGHK[F`/3`9K\)N3+M<2$EXIUZFG'O'UKMHW7;$ +MW<,^NW*C;,^L#5^B=>])G1UQPI)SXCXOI>=4RK,PB,LYW1-:+'V!\;D38O:L*N8>28G8]A,&>I\Y[HN?9X((%[M(^2T^2.+?>JN4\X=43-)WWAX +M6U"_A>M''6YY-LV]V(?\RHXHX;.>'T%&]'.Y#+$[QZUH\'(EMP/YNH#S/7ZO +M7-,/\+YO;&0O^8KY;,S+9<"SB_E[MSHYG2 +MER/Z^`S3!GFN`FX2W@>T\<;POQV@EQL-X6_I]2&^C_/CG3V'.8?6$BSU^0%S9?SAD]KR&]9D(XU)'_7D.O5U//"7F_$6N]=- +MMHYJY[F+][8O4][6;LSR36S'6_+/S:PE%^B@:&"/+:)CP9Y!^( +M*#D-&_72/.3YA&8CWV#Z]R2<@VNO3J?8?\^^79@?Z`3OI+Q]+6!EV[;J+9K+ +MY_<@%_J%.:,398;^\=J`U1]YGUP;R3Q(>0V6"K*T7"8[;+C(V3%_>3'O*9]?>?8`/1N6^]B(;T0\[!P+ZG_5C#+X!LWSGE7G;::_@_R9 +M\?DK3]XY/KN!_:U2&M+6Q6FFTA0/I4@>U>`Z&2:709Z5PWR7ZS+O4>8.,*[< +M3O;5BO#0V>.3G+NVK'5&/'*];F&6VT=^:$.\GWJ^XQJ==PQ3#[Y]19CS-_Z9 +M^M,IH;R-86X%;J<93I5+#+!O8C_T^IX@8/63A'$^-D#GW:Q[?)#1T_$^]3C^ +M7=;#KL&*WV*=4@W=+T^EI'5E>!A]N$8A5Y1)GP[H6=`#@RR[0#>_I#G).AR +M%SI:1?>15M%[F79;H;==1%Q7,V!`]POZBAF'N@\[9HMSNQ"'M@4"M%;JYTJ? +MK.Z2,IGKO$86R+YO#%+='WA='KK>1;1SQR7D47["UJ>/7_-DUV*>`?4P'$]8 +M/?QM?.I.JF=B_*T^>OU_:_F:@JF?KU*_;/?_Q_;?2OD:UU3/&ZVB#S*O[XT_ +M4@KXZU0CY%/U!^2HK!#]U2_3W*H/R3EB8JPZ*\:89VKYG'PX&GFOZ8K +M9&^^0JF50R+6`Y[A,W5\9L./[^[2,/WOX)>\;^#KR<-X[R-"7>=2\R@-\,X( +MSX->87ZP$3A<>"?697VGO->:GL-SW:MOJ[-$U7]0^FZUG.]0]H*2Q37W@V/RT\#S0R3#!Q]:SD#=G"^7>Q5Z>)]XI[[*B?6:VAS!>&C&. +M3J(MG:.>U](@BT/:'."#;7.R"670QL;EK]`]L,^.J[%4]6[WP`#;7;W*+JIZ +M@>Y'?POBB[>9+ +M5!EF>PXXG/'ELV[ZVMOS\VIXOCK3S`_H#II;=ETA@CX$VW!CH/HJC]O7+HX? +MMQMAXVY$3VP$KVZ"#;T)]O4FS,J;H"=N6HHG&P]Z91/X8!-LMTVPVS;MQ8,9 +M?-,Q/"?PG,(#'MJ$GMN$EA0"3F$ZGD5X4+X0XZ<090M1IA!E"COQG,8#6Z\0 +MY0IA3Q=BW!1&B#:C_LWS\&3B68<'TF(!W$?`N`MY%P+D(,TD1ZBP"CD4H5X0R12A3!!R+T-XM(,$6E-L"R;O% +MB0?X;EF)![/+%N"[Q8L'=6X!CEM0CO_CP\MR+N#HPLSB0AM=*.=".1?:Z0)5 +M7:"-"^/;!1QA0-)6Y-L*G+8"[E84WHKV;$6>KZU%;AM1?YB +MP"Z>CP?YBP&O&/F*0:]BP"L&WL7`89N=O9#B0?W;4/\VU+\-]6]#_FV`O0WU +M;T/^;8!7@GPEJ+\$\$I0?PGJ+T&>$L`M0?TEJ+\$\$M`GQ*4`?M1">K9#KIL +M!_SM"_&`GML!?SLX=#OJV`[:;$>?;`><[8"S'3"VH_QVM&$[RI:B;"GP*GT& +M#_J^%/U0BGREX)-2M+44]90B;RGJ*D7_00#0#K1I!\KL0+_O0%T[@.<.E-D! +M^N_HQH-\;O"5.Q4/\'(CKQOM<@,_-^IQH[_=*.,&3F[@XT:?P=BC,N!2!KXH +M0[ZRU7C`4V6@0QGREJ$=96A'&<JJ``TJ4*8"-*A`?U8@7P4TH@J, +M5;ZC68F\E:#91HRY2N!8B;HJ4:X2]56B;"5PJP1>E<"K$N4K453XL!9OYOS\ +M/PK.+^,VR;B@%F>Z,E>F@,=POJ&N`P?VOU\7\S@A/B3#?&.>7_-2;D4^TLA(Z*MB-LB7VJ\-?I +M-$F::?(T)QGKD.TVX,SX&N*#AG@C7?ID^C@X3(]-I[1WE_8^H=%'[T^K5A?3 +MV3J!/L8XTXUQ8_0QYM/I$]3::4U`GT1IILG3)'W&ZC#01\8EH(\>;Z!/842C +MCP$.TZ/P@O8>T-Y=X^GCM,3K$(YLYY6I`QZ&]NKR>;(VQXS]D*#=QO0`="E=KL7A*SG/ +M\)&^2(5=V=K;J8]?+;]U`BY!K2YK`OH;TR;2WY!V`_V-Y2;2/VB@FW42^B?* +M,Y'^"?*,H_]8>Q/0?UR;$]!_7+O'TW]K2)<+W47X:PJ;Q8:7/&=+-4DYJ<3IM +MQ^3[C?&FQ/%.TF'J.IZ6/D[/T^(,,K>DE]_QLMR^DD[M[=/>.K^-Z3VRW0GT +M)RW^!OWIQGBG,7_8D-]LI.M$74YOCY9^@ZZGMVWR=$.]6ITZ+R5JTX2T<>TR +MI@5@CQEU0YU_M+03*KQ=H^?V-GW\ZK+34//H&33*QD1M2D#/L7:-I^<.IU&7'$_/4LT.V6%7[]*!.#V= +M$_ESG'XVOEYG(O[4XA/1TYF(/\?IBI/3TSD9?TY(GTA/9R+^'&M38GHZ$_"G +MVVW4/+]_&PJ;Q85V^C:4;Y)LS.;%\&Q=O +M2AS/\LUIE.D#6OH$^2;C#/*MK%/)-Z=!GRS;J[V/:>^&&^6;,SFQ?)/Q">3; +MQ'BG,7\"^>9,GEJ^.9.GEF^3I1OJO4&^W=BF"6F3R#>F7?GIQ/)-IC6H<+E& +MSW+WC?)MK.X)\FVLW@GR;6+\#?2<(-^SJ#V5O8RVL?K1\9Q:`B;QH?5.#2DCXU#CDLT#B?$ +MFQ+'.TF'J8]#+7W<.-3B#..PMC!GD']=B*H_H-F\W\U[W(VSQ2F^/\'IC`?O3^=<_2EMRQ/ACGU$ +M';/(H>4^:U_3X7$M\?Z'J0H#R.@U[?@>%9[%H;A4^M/4D +MW^-AW\MHQ75W^UN"Y+6QN.\#S'JJ9X[L9UZ>WB?XZ^UB>/Y/!NW +M0V\?MZ6N573R^1:T*05AR[:`")_;P'A7-^KWJ0)4==HL[V.)7L:)\=G@YK97 +M=R;`2>Z7H`T?Z7V!_+.0MR_>'XI&O)_CRN?S'FH?*4"OROO2S0RCE/>37OT] +M^WP;VR<%S=3YD.H_\-X2\LMX;2^JB_>>$"?/5?`>&/`]=SY$Q'XF^.PK[^$? +M!7\=!1SDJY!G9>N)_2%U\7Y;RQ_!K[G9M^^(T&VNQ\2?+U/-5>&A,/LC!NST +MR^1Y#_6F:6\'WK_!^RZ\?X'WW7B_COPQ+7\&PEL1__?:&SC6#.&]$NV^F)[/ +M\;(=*Y'^DM;N;G66IO9>]BD`G-A'LIO/C`.>"_GN9_B>%7519&6^?XCD--NA1$U(\IWA+HQ/ZK.8"XQ^(\QS3\X>(/\.TU^/C=*\YQ7T_ +M%J_@,YR3W!]ZO-YFQ!]GWM'C=7P#Y%EZ;J[:]^$ +M:8;B2Q7?R'N=\B[HKD^$Q\9W?+K5_RU4.G#L&S;;(F<=(=HU0O;0CNS;1SV[ +M-@0HI4X[P]PGSRIZ,OC_V'Q.TV8SD``GUW-[^U0^_^]^#[CG2VZ)CFOLH#/F?#> +M/I];X3,O*'?A,C6\S^#\CQ>RGN6$A +MGUNI_I+WJG?7C=^KWGTA\5.?KKV/3_WL`<;UZ_!&_CWS-3HM'/7L'C"_C +ML<3GE;,BU<(4(7D/UA91?O1\Y7S?LV$[XW/4+!H"U"!]E+8,RO,R]D'`K_Z, +MK)CC/N7V^2.]U%(EPDK>UK^LSO_D=*DSB?5-9PODO\^A']07@K;RG/N!V>*" +M-N>@S&YYMI1]KZ$/![0Q^DWD]\;[L'[=&`[%]"T^[V:+"A_/L]+'!>9RU/5R +M2269U=G0/:3EMW-[D2^6%*:T)95T#^"&]+YOD?U=[^)S1% +MR,[T`TY]H&&#X?L]&^9__Y#TPS_D*J(4U!<%#MVVVB3R%?%YTSU]W&[M+(0% +MX?<,\PUD]AYY#T%\ZB#UGQ>2O@+57=L]OP9/76QA65+M()8EHYX])S!&+FI\ +M/J!HK.Y7G`<4\)GZ_C,+Z[V#]%._A9Z01[@CI-F^1^Z)[5V)7,Z6:&D%&^4^?O#LN +MT^MWV5+O7+FD9)JH"FEHE\,-+YF3;F.?CH"/KT]]/F_M. +MX/;9S>'6W!_'K;G_5G"#C?I1SUQYWBCUO#S?^\:7E7/E_Z-FX?N?8(/]F?\# +MB^__H>:V-_+`ZW,5SS?*_X#$DN:<$![,.R&^?Q'A?]":1?V6"^^,A-D?8__1 +M*Q9Z9R2(N>T-K^Y'3B]K:V.=>C*9_<9[2PK(QC*;W]5O\=W4:2E+OF2][(T! +M_5ZJ#BMK8!K_$SB)[\;RG1&_(TCS*LB:Y0;\,.79W(`->B@;JO'^I$+V:2$: +M^+W$42UVO446OD/+=V'5/=CDE%%/X]C]U[]"OYF*?DT/QNG7^%&FZ-?8U^*?DV!./V:>V^.?LUSX_139:>F7_.JR>G77!"GGX)U +M<_1K?AMTLVOTLT].O^;>KT@_FZ)?RZ_C]&MY-4Z_EN\K^K6DQ^FWUWYS]&M9 +M%Z>?*CLU_5K>G)Q^+2?B]%.P)J'?M,3T:_GLJ]%OKWTJ^MWJ?'W+]\4U7ZTQ +MS]X-';%D]L%IPO<\Z)Z+/Z>]O^R(65.$9_E0S+,R5=0F6V*UTRQ\3S_A/25Y +M1^?-VY+NHF^S?\!=T-/X>]3S9AKTE`U3^1-]4_C77''#>EW(/Q] +M>2]'WL^]KMW/W:_YT-COE/YM//3?1CW[%L9U\WVIFLYN0?S*>/R;D;@NOZ_` +M$#^DQ4,?W5=CB._3XNV(;S/$=VOQT$OW=1KB3VOQWT!\ER'^A!J[^_KT?S8@ +M3O/-MB]HB&M0RHW7K4Z]: +MBU=>W=WF8E^?T=WK4]NEO_#]WK'[Z>9';X-<.`$=/!2K.\3_>[FG>HA]6L#F +MIFOD+QFMB26MO=C#OBZ5#XR9/:$(\?W.'M=G'&<+6=L=L:1-%\]_SGQR\/?I +M17R/^>!/%`T.I`1,/VM3]\4/@/^7C>G^BHL)ME.6A428_2M47Z4944MQ-OOKB]9Y&]AG +MH`VR2_JQBH:E+P.YSN@B,VSE&>(+)_OK^E?V"3@S1"DK0K9P50BRC]<>(FCC +M%\Z955MACPX%J+V([0VRC7Y1,"OX1<$WO3%*XW^)>HLHH_ESFB^V.*;;AI1/ +MA9RM=NE747A^ZCWZ.4E?JK'=W@;I0V&'D_W5LMQQLB_!R!:G&?E6>LT"NN3! +MBZ)VVM*XO^R#R_1_#DWX%X6SGPZJ?\#M6GM1_X\3\E?$_34E_*=3&LHUZ+2T +MF73_V@==6GUG]/\Z86Q&M+C>^/J*BM-YYVOBW13V9RC]J[&O`HO7%ZOSMOE/ +M7N/UD*"OG'TEMU8O +MV0>KT8?IK>(+YZ?<,&6"KZ2.H_N/C7E:^D6M +M1:YOQ/:I?!-P`(_N+]#R29\!,VLI/4&^).%YTZGE2^%\>GO85S_RZ_DLPM,Z +M3\LG97W,8TY4KU5X7O1I^>Q&>(8\R3%/PRG.$ZNU2'\)@!U"_H1W*4<];=#_ +M#\U7*[N/W]R7_!O;69?><'J#:;[.GA=!V'EVTA\3F])/_FZ +M#Q2C;X#$_[1QA8=;/QE5_N#?POSWEE/Y8I/_M>"U8@??/SHG9+_2%]E +MP:QHM4BOSD3:=4]+4,$O&_ +M;Z+\?X-B(LA&Z">^Q;R^23SGT=]?L@-*K\[8M29*GWOC!;PWCU +M['2>(Z1?V%%MC@@%*#KJG-5>2FGZW"!][HQ01M,(YH<=F!\T?XQJ;EAUAGTO +MLL\=C%T+OIUB)!K&>Y[!UZXEH?\=;>X(D#>-_2^.>HZ4!.B1$XH>1Z#__$C3 +MZ[UR/"B?+H5;;)%77E7W.%5?[V+?CXKGSOOG#I`8B6E^+#1>P#QU@'WPM]<0 +MWO+_`."'U`Z-]P[$_T_2P/X,-=A=9TN4;\=1CS)Y/"L:2F=%/Q;2'R_R-E^1_W/J8I[-05]V +M(-RRD7V]?_&GW+*`]+'#]V&!@]2CP!]5@/.'W.BT='4OMGWNE'[7:2=79G3(PC5 +M8=GJ8=R(6".4-E3H21$D>[;E8&UI<:I;%93Q@*?K48D[,-O=Z2]=9J=U"Q.Z +MI1:L&J%`2%[>=^]][Z5-2E+`IHU`_LAI7KXOW[Q[/]][[^=^W^N])PO=R89" +MJ;[A#IU-W*%S&C=`$G*DI`%HJ*&8TEDZB+KLIAY`)JHU2-W$Z)P^J/\,/].R +M/6?=Z<)HRL4MO/DF;VLBJ=C27KG*PRHYQR@6/L:3<01Q/Q?%E +MK/(NU)U)B\3JK +M[C%VX&=]L.]S!]H82SICD;Y?80;FRU7+M1JGLSYHT%$M5I;DCS1^OS2NGPWR +M.!6QQ)H[#DZESX7]_0X<'76=5IHO[*^BU6H;.4> +MYL%S-517RKA!B]?:4)]N3;)%XF@BQQ?L0AY)=3[2T3<:RW);^F!_)N45C..[ +MZ3Y#'S3>+U1:FN2>)_MU^!L7G654$T3ZW"77;I+>*_Y(=%8D+Z7X;S8_G];`DBX/^AY[Z/^T6<3[\/>JO@&._/7J>]F<:A:#^-EV4 +M6Y$/H[H):_Q^RC_"[ALH\3A)\1G(Z:F/U?X\Q,PY^LS)_E]+-4R"SJ7S7+"_ +MZQC]!^4BRM_WMW>@WV75O'O%0M!48XZ/+\`7O>=8)C](:[/\):I'XL8\[[S< +M0X/FJC)(=4O0EE,99[!6;\+S[0:KM/ZJ#'GT&]>Z=KH>=\*B#%9Q^%.FQK5< +M;J+:_J:P-0P09[9#YR`_0OU+6++!(E89 +MBM&7`-/UV,0:WG6YX@WD__M[`_RM$_G;"JL`[F2^0)H?YRA_0>XY0C6K26;D +M,*GXTLC_W_O&5N(U@5@@]6(25/A]@QGGL)+/=R?KK/@^#W]KI/X9Y9[H-_%S +M@P/'+7A]C?B^"5_-^#J`KT/X.HRO%GQ]C-^W1*I33?-/>`^+TUEQ;5O_L(EJ +MT?WK3[VX3@2[(<]/>&?V6._M!VVG[0MHVRC`T1*!_)8#.0GWA_Y_AX8^Y(%/ +M(W_17(*R54SH='5)/2_$7TF\1X6\)ZU]J!GJ1>!J14AUKCL!@34QL!;4/UO( +M+M-\]%G9&5#[[7PQU=SWC;;%+7*O4_?8@KR<'V]/`'R<^G +M\$L/EKC5DBS(#4FV$7XX1I[27B8N[Y=K,DI["(H\)(O$$SWH@5&V^K(`1]QK +M.RBV)N[:A#+Y^!24,9%D')%-'21;8IV]#F5Z'66KHSV-DW)]QH[A;E@^C#)] +M;8(EY`M])I#V?7RF['WG0F5DVU;2_DOZ.7BK$6V/GHEH)MY+/6W1Y[D[2X>I +M?@SUQ>6EOC^7X+[7%9[GW[9R+]6G])<7&N6Z175V4;/2?BU\EUNDOC;,NA9`=+#OC(9WQE6N$_BRQ'Q_8TQ"%]-&'PU(77*P^`K[6-5\587V@C& +M?:I_9L5\6K=%JC_V5C6-DR[67*&Z2H^C/[R/ZK>G2C6ZB/\K>T4D"_%^1OW5 +MB/-?0CPO`5^OK!]\O_35DE#.K_#YS(:`+)>4?:%$95_H>>3V&X*Y_5L.S"?( +M5@LZ!=J[8BU1\Q->\A/ORKDRVJXOL\N98Q# +M_E![?J?H*GNNH#J6BBU?'MW[G51[5J[9!>^LBK8]O_H>Y+YZ+V2SA#F-?LT> +MAU13V4WY*$![L0=\R`&0@[M%Y&2='@_X$_(6'?*4BM/X6RKP:H.P6:SN9^F-X+ +MVE5;@+MG%6C1SO)>[`6]Y6%V;@`.V(\78=XA\TWKKL>!:[?U04=W+QS]LA?] +MBL%1CO;3UGL.4+<:VCMQKNX'XB!;^I&#(/_P7U;XQ_\6I\TH1KVJI;YQJ6AK +M7'HIRO`DNRS9;[(A3ZSIL8B)Z+^J>/.*)T$];:L9G(M*B0O]W>]!]GB +MMCT.$?4LZ7B(ZEMZ(!]UM?PYJL=S4>KUY7]Y48:8S!<=-PW?T#Y'I-]DB*GX +M\IQ&S+V*Z#?IMZEVW7+$+W_[GUF'!7-RCQ]88O!O"Q/^[9%UA;\MH-P8%Z1> +M&?D6D.XUTKIJZW=#6Y$'RHMP#9T&$+:3?A9EM)6ZX=$71M=7V9.@S7(W(<< +ME[@NK3'RA?FGD=_2&M/A&MM^LLB?C&ML2_376`QTKKYQG1\JBNM\0CI/N'&= +M__;$K:3SOYHM,BDW3]'9*.>6:_Q]\!SEZ%0_+W`L[2M[@1MSG!HXIKV";^&# +M>1ASS2[XH%09SZ3G59%/9(;%NT*D/8TFQAF:MR!FRU^08Y_\S/`'GW5:NT&T +MZRPK%@(G(F_$'+<)==(,K?]-6@6['W$ +MF\"#X?(.WF4U@OIWO!GV/VQ3#\#A[W/QF-Z;CCF!S@]_[_'PIQ<>X6$:S?GP +MZ'PTCPN.Y.5&JLE9>=+R/(_\-B$KX[U:CVI!'201QZ-]-N>FG^#:_3!99";` +MW.[!)1NE?;<Z5;&#P>-'Z9]5&77VD_$_/7 +M!O+!B]3W+6W+-Z"NQ7RA$_,V_XNFC#2+$2@/0C^K75QD1AY;G.Q%?X?YB7A/ +M+]H.YHCOE;4F$E^G?(+50MK.2["8[A.N^5SNZXDY6J'W19-1>-&4X[MLFA_( +M.9[X1JX+SBH.ME"^T8F9CZ`\5T*YDOBB*9O](^:-'NF^)&".JFU8A]R[N`]& +MZH0C5[RG$-2OET"NE_(1CK<\^K01CIO^")W6CZ#\"CLM]2:S"B!6\0]Z7UZ$ +M')NWK#"I)\PK!=2O'W%B>V;#NT]YI!K>8O791LH]0^ZYCLD[A0HUR:*6]=X> +MDH<'7C'Z*N,1^EO'3-Z5%="YM-1LPI +MY_LVFW(">>KH,SP''Z)E9ZI&R +M.53'2ZQ7P"K2X5B30#JK3(V':X1F$.HP1 +MQYJZ8-A7G(S\4B6H.246M"3Z,?<@>R$\"5<)SWH%3\3L`N&Y.13/)YZ6]\I8 +MQ8%6&4_7B-U(L6!SJ-U0+)#L9DB.!?[M8_#\AO`\&0;/CUS!>!XW?3)QN[DJ +M7AMB&*_Y<>(U'X_7\3@RQAX^Y>-Q9"KBR%%G/([<2G'D,]/DQY'T&,81[3AQ +M1'M;QY&X?POGWXX5Q?W;K>3??L]-OG^;%D/_QHWCW[C;VK_%[2Z6=O>?YFC; +M70B>:T?Q+#V#>*Z7\5QU1L:SK1_QM'S'7D%\=A">JX/PK#QI^9LSU'6$^=_- +M\JA2'T-[+4+[W23;+V'L0WSSBR"!,!)U/3:J]498C]BSB/;\=W)_:.E9%D\$ +M&RYBXO(BM.&79*QG6*G^RQG)ENG_4FI+T)8WNH'Z04LXH_W>4V@&']V+DW!V +M2CA+MOL1VFZ)8KL*SK7XNG`9\RZT76^P[8[@_&[1B.TFCK'=7XVQW:=&<99L +M%[%>W`]J7(.YOLNA>'=:W[G*=GW1Y";Q>PP>W9QR)^[=P_JVW+N[?;B7_=NJG\7L'MZ=_B]M= +M+.WN=.GDW#M0\(Q\[R`A^O<.>%?\WD%,[AT<(Q\YD7L'Z*.;)NIC)_^^P?N+ +M;T;_&K]O$(X_#KCB]PVF0L^#V^+[/5.1#YT=BK:>_9F\BV(YQ?$9@\`].O0= +M(WZV\QG0O/(LU2^]#IYV#@!C.W2ZCH"E;!RNMBZ(JYT#C:`[VRA4\7RQXV]>/>6LF)5]JC4(L +M;_[QQ_)#C3=C+%=\W[$QOJ_I]O9]WQZ8I%A^+#B62W6@B*>.HVND +MO%M#<;WJ7&A,[^Q^$](&(\3U=7)]&,OXL_A +M]F=B$NSP&C=C"I>IX#)J*&.1Y +M*)Y+WDZYY)7&2T8^T@U'8FXW[=C`&`G8O6*M-_WYO@A^WWD`X5DF6>, +M[//E7,5#6KVZ'[;/5QO$0UZ+Z`]O8)\O)OYP6O1K\UV5@_TP'C*Y.5BT.,C- +MF8-%R@U>H=S@V^O,#9!O[*3^XQR0DJ +M4TJ]4=YS9W:#,]"W%?4VNR'0![8"UZ/2US;<]]S)!B?5"J?>#YWN[YS.+`$& +M5&D;E9K#SG1A6I[(BH%Q^-Z*G^'Y2A^QM&]5:=6!\]#FT_I4:;^@.2Y7IC6Z +M5&D1^]'37/EOY\`6@7WE?/8\]*O2SJ8/3E\UDMC;33F +MQVLL^S6H7ST_C7L_JSNQ?)@-_I.`UXSZ/)K3K7F_%C_S`]\Q[)?FP+A/U_/- +M/CP_4E^PQ(7,-5&]IV_-`>+T[C?E0(T4,^] +M2JW&!1^DDHY?IK[U>N:^@#K"S[,_LT)$W=-\-!?-N;ML&M>`WV-)Z8T-^![G +MH7E7!>8-X%2..-V+_HWZ#PZHM%O3K=-^SC87`GYW6*PR(-Y:1P!OIM1V9U3; +M75X7])V6"VIX!,]K"?1Q'W/-7>-=<_K;(JX_G>-X*?4,D*^'UJ5QDXI=*"^& +M/M5,QQ*KBGK=V41.URS:==5^5CB+^K*MOJB%W>=!NVL#&*GV?+Y0SMQ5.L>, +MK385^O6E^_#%=#U6NN;_&`0PEJG@ZX<@H0&_FLBI=(TO6 +M3;CFMB)W5V2Y,R2Y_9SN!,KN1-D'2>XEQ8GN)U[2@EC=8R79=Z/LQ"\5V;M( +M]AE#B6Z2'_W=4K%&D=\S$?DS%/DS-"B_"^7OBH[\>FUD^6 +M),L_W159?KU6EG^Z*[KRSU+DGX7RZXTL67]#WQ]'_H+(\F<&Y'\,Y3>C_,6R +M_#.[QI&_0)9_9E=TY<]4Y,\D^8M0_H(HR3^.W>L"\E>C_&C[^F99_@?LX\CO +MD.5_P!Y=^76*_#J2'^U?'R7[UX]C__J`_&C_>K1_O6+_*\WCR*_8_TIS=.77 +M*_+K27ZT?WU4[)]D1Q^X%WVZ(U@')'^G]4$PEJ@8^IJ]?2J>OW=8!=X4G@;KTX7_O0(=@]`,9' +MB\N9HT*T.;Y`/H@Z17ZYU(\Z_71U,RB_N[0!/Y-T+*".GY%U7+_N1G7,%Y". +M'4K/-+H&]J="`\;8F7A=4M\'%_X5U8RQ2H.6XI!8%9TXI.#0C3ATC8-#=Y]J +M=C/AD(+ZOX(QRE-.)+IK"8MN&0N68NA"?1`6W12[$*_!8#QF=(.:\*`X +M1I]Y\PMG[5P-6@&Q(&S:K5_"?PTU@XS'[.V4H]&<;?V-L/L4&)<5*7AT@+96 +M6>,"X?&X&Y3?7DIK?P2/IV0\ZE;?*!ZS7<%XT-S,%\!C=JJ,Q^Q4&0]^+\5% +MQ".*=J'G1;M>&QD//=^GFO/@*!YZ\''Z[)03TUWA\=#S%$M]=KTI/![37=?& +M8XXN=GC,L43&(ZM.QB.K3L8CRT1Q6JR*3IQ6\"A$/`K&P:.P3Y7=&H2'&?%8 +ME7)B9E<$/`HIMB,>Q>'QF-EU;3RRWXP='G=`9#RR%\MX9"^6\9C30KP!\8@* +M;U#PP+BA'R=NZ#%NY!0&X6%#/.I23CQ@CX#'7N(:B$=S>#P>L%\;CYS[8X=' +MCB,R'G=\+.-QQ\]7P]<%=S +MJWD;IX9;S?M%[+C5O`.1N96Q6\;"V"UC85P_%=PJ#!9H'PNXJ>57\\_$SCX6 +MF"/;Q_SU,B;SU\N8S/-,!;^Z&A/B6+EU4\NQ"9X7!!./(W<>F +MEFO=O3]VF-PM1,;D;I.,R=TF&9.[#D\%UPJ#"<:3A853R[<6QI#_+AR'_YH4 +M_FM2^*\I+UI\:[X64G=G@72_Y-4LT.S(`FYW+6C9]A++_[=W-5RE9-SY(HXI(I4D;JU#7><+;2Z*ZA"*>ENCPBRX=9H8R^L +MD&:W[[V>&6E_L25QI"K6V,W,O'[3_5Z_K]]T;[]I(3V/-0^4LFQ/)]OON1#* +M_F$CTBPL^T@G\N29%?9_\/&F%&RT?5(?I^$ +MU\NTZT+ZFZC8'J*WX2I<%199'9"<=#;OA9!V#G/Z/@OP,O.E0*1Y?KT??B23 +M_/(3M+:UX#+*K]:]7ZT;<6HQAT"4&^:>T>2L\*MV$7TA/W3L8V=X><:""GQ6 +MP'S[B%'BS^(8QL%JV27ZN\T?US*E7(FQCA%:(YL?]D/AV81VB^-#.0=?5'", +M?IOU'EX/$!6!U878\`?]EV"TEG4?^@V`:P`*RW>#V>>,@DE@H>[0)3!M-K,] +M(19P8?_M"9^C."-3_37(:ZA@PS[E$O0X,(5IGY>+F,X!XBJK+!RBM6\3K;7Z +MG-?@8L4EJ.MG2D_XUU#N#)GWO`19)[`^G_,R=*`L*%N`9$1Y>Q/E!4,RK5QA +MD:GVMX;/8SM[_(#MO2IVI,^VB-:)"\/@\\3@XG``RF+,>UU8^"H;:9S0NKM? +M*#Y%[>ZK7P*T1]!-H?A'OM!'0&N<>'V0\KZ/?I)\)?JKFA.:GXDA[PFB(\T7 +M#%$,PE@>.])G4-=(BZL("R2S3_FJE^2-M?492':7D\5\2L1+[2W7D@\M7E[> +M#BSV@[X)K2_K\N/[X&8HO\]`/N)P0[;ARQ[F_=C:9XLT%]OU==C)E$NZG]!T +M]PL+^=\]7G24QUS@?7%KIA@$[).;4>\2O>UX.RDA*,=WBZ,!'KHA+'JR1_D( +MR&^SEH+-$Y-M$6_GNS6$[2Y\/[I(\MLSZ+WYR"/J%$?1;_^O];GP1_ +M=T!J3._OEFR=N+];VIGH[Y;^W;B_6[IG4OZN><"N^KNE7TOQ=TT#]O3^;ND7 +MN+_;/V"?C/SE*]'=+&^_B[QST+/F\ +M!/PA9C1,..X!QFL^H8Z:>_N>_?VI]+A;-C!QW*V0$G&WPCB.N^6W)H6[`P4: +M[I:_DX([=T$&W"UOY[AK*9@@[E3Y.>Z,!8FXL_[^5*1YN7=RN%/+3<3=;B^<'VVY"'26K7VA:O;8=J80'%UNIQL^:]%L"Q>EX' +MCYTM=5+L+,4/QK2]!]DK1="Q`V728V0C1>*4,8_ZC>OV5->?E&[N@A(5ORL_ +MS_%LD)S,G>_TOA9%VJJ51(LTKY3&YU8JC34=:95=\"7B&8M5U/.T,C[0RABA +MN8B[H!3[1L[AVVRXHQ9,JY]D$9_2!:@CQ?T'**8N-PP6[!.EQ3O!XFM\'[H= +M"OS+#D5$&5L/HMX?A-^%CJN0Y=J*_L%_`7Q9MV$/S@]\2ABBO^6QOD+DXYK< +MBS5=T-X`AF,Q,'EKNZE-+>B72J]O`5Z6JN\7?]YP#<2H6ZKAWW$8)#M]TZ'' +M$J>+'Z;8X1YG@-L6YQA&_5N.=BV.OWT'[7<'ENC,@D[V$WPGCX#MX`@LB-6A +MC;58X!.Z;4<@*[H?,83XP.NB]M=@+MF?XH11WKG$V^/H@C*'F<6V%\&)E\?M +M/EI7)![3<#1J+&@E/7"\+_WL]K#(9DJVG]6&1*Z+`^FH6Z9O4^K[6:QL4(]_ +M3_PVA;Y92?X^1=^W[^!KJ!/%0/\$LDG',=W$.-T0LQ[4Z3CJ1G'1+PY8>(PT +MQ0M1W'/L?\?CG?7O4D[<2-21-6UR8I\SWQ">:6,B`[SOHGZ'\EK0!X9\]6%P +M[0::;T@4OX]86G9<5-LEVK3I*'T7$'799?U;G5C6)O^&/4%=GIO?,5,M>711E4_:7;7VPNDCQ,Y>4>[[HUM2_ +MH\#RT#>Z]7CH\B:,N.XP.20;::WC-,)C>JKT@*J](N0=K +MT4?VGH%RIR"@;?+HNQ2?LQ?0MUI>Q?'K=9:$0'(`&.@?@W[8@!G'.@ +MO7.V=V%_$`D7'2J&*?[??EA?UWQ]WN:U#C;@4>JS +M55!(]]_XCT:@/O)BU,#]@5RF^EQ\9C8;&G]_]E3[`?O'`]@_AAL<+*;ZJ&N` +M/+G43WW!`+QY$]MG>\V#H:&:A]JUOGGL)F+Y9<3R=L1R4/LF[I:%U\F:S2L[ +M;MX=Q\H0^58&KCX0WVQXP,"L?:W_]%\A^LYKRF-G;N,8^QV^ZV#-6ZJ=1Y@= +M8C/S&\L&T;8?!<39PV#AW]+4@ZALEW)'1R5#M$XR$4;6#`H";X?!85#VO=U/ +M^R:;%`%.U$(1CD,!?457U)COB1D+W$I+?FO(F']TM"6_+52'?NP'?3!JD!SE +M7E;'@?R^X<`[<1S\8@'A@#!`6,CMSPYI6`@@%OHU+/3& +M6O(O(1ZN)&(AG`$+SZ^^WU@P.[-#TWA(QH,5)H&'^D0\S/*K>+`618W60A4/ +M5AQG6_-"1JN4B(=@!CR\L.[^XV&6?QH/*7@HF00>NA/Q,*=7PT,-XJ%:PT,% +MXJ$2\6!/Q$-_!CQ\9>O]Q\.%CAUO"`8P>K-G:PMB(> +MVA`/1Q/Q<#8#'DI?O?]X6.&>QD,*'B8Q?CB]+1$/FTHT/.#XP:J-'ZPX?K#B +M^,&:-'ZHSX"'/]]___&PJ>2SC(<8SB,)$X2'LBU@(DQ$*:X6YX\__8Y?G!U6 +M\1!#++"(9%)V20;ZVS(<"[1VOR5$8T:/:9B^=T7[BV_WJ_,)=2[!A*P\FD\H +M1IQ/[%(Q$(V@[6\#C+K5><6AVQH&OD$86--ROOY:RISR^`3FE`D8^#`>`^?' +M,5"583ZQ/H/]_9_"_LGSRGMA_R'-_CBO/*;-*T]^*R0JQJG;GVQ/=E^+?9^P +M$,5QPELWKHB$A]R=8"$LC**]R4?0[PCT^T$4,9!L?_,5'!O@.&`<`[_HYN.$ +M%FMU5!LGJ#C`<0)B@'Y;B.U"#-3J&.A/PD#90=T/W!,,)/B!7TYMG'#EC^0' +MAM+X@8WH!^X!#B@.J$/;JP&3ND^#"-E(X_LTF/=""TV>1=UF"S`]J]8M\_9YXS:C7RC$9,NV](=)O\<]*6CNL2FA7 +M0:!YD]Y>%+\V1^,K4>7D_4RM7\QZJ&/<5@]I?"^D\AGB^?+4-OU2)>JS)I77 +M$L^;K_(^5XV\%:F\\HPXW@*5]\O;D+4V]6I]DO@?4?G7$K\] +MWF9Q_>51E>=9ZB\\]AKML2U=7X\T_]5)/[SMYGMC[,.Z]K'APYAHOQ5F*.CT +M*=>A1QD$;RWMK5%I5/&4[U#7OK3[US<%:.W$I;"`MV%PC!YK*>C$<5\KQ<6F +M]3/[$*=\?XY*FU\H/TDRX/4J/WBV:->E?F@OTJXK];7#]'I4[O0+ZR]DRE=C +M(=U@S/IR_++U1V4WE$Q^L+1*/GL%SNV\XY`.)U +MH.#8L38[_H(0%@&\#<]3':_R.I"FVF/=%O1Z:=<\GK!@7\*Z@W;H_JH/7B>$S;PO%T/4XRH"VEK&D@>!SPU+L^Z +MBR0/Q1:K>J__U8)!BHU>?\83X_KQ>F77PU3?4;Q_3M<+V_@LKV,L?]U9JBQ!AMS%=3I7;>%D>CU*2=/4ET/9W.0/^T +MJ9OVYGD=VQW[@1AIMF]#FS7J>_9H]"RD-Z6AHY^P>]+09R+]=!JZ!>G=:>@R +MT@>3Z6CG(-(5G8ZV"6BV^6O@L?M5U>?@>8BS*=F!KU/B/=G52?=H8Y'OBX5V +M01PX.]2]B,)X'_`YA]%/;-A,M'3X)-]`N%#WR:IJ>45B[)R\$EYI)]JS1*NG +MO+0^\A'`OE7UH?PY?K[L:WP:<5J%^E?5J#$;&SD&WE,HWKMJ,)Y.>KT'2^BY +M*SWX'.9YWPMG]F-8EWQ=V/@7)"]>F^@:SS.U\VSM;-3.L_#,W^7(+R27R0]# +MWCMTNL-OLK\"%CJ;._5L$1(.EN;&!&`IY/=XJ"3M/L1OLL;XQ_*G<&CRJN5Y +M!:V^57$<+]SE:49=,>/Q/4R-E=GCY3,EX>$4^=/H(U;'5?#XC"T@XSFO<8PD +MN"U)3ZCUF>D?)Y97A/F6ZK'<&>&]<;P?J.);`IF5N,='(1CURW'UY]C2L8ZW +MSYQ6G90^WVI(NC]]K\2=/B9V/+)7ZQ"/A^:D9";3Z#Y'UFASWDGA3Z'A1!>@ +M$_%_;NJ23A^?R4.`&7]L$?Z$#Z:Z:/3#_$3_L3''S+0,IA&8=C'!]_A=7K@I +MAXR)?E>B]\MB3$LQ/7JW!QJA1,)_\/\**.'WFZ?IT_1I^C1]FOZ9H'LU>J]& +M]T_3I^G3]&GZ-/TS0!<$`9-Z!6F.9*J@'6/W\`G/IY27^'SR0;(M4R]=`.IO +ME4P]%`#W:8"6(*8*@`-N@+\M!#CH`7BC&N!0OU;$T=65I?+BXL7%-GF)S;9B +MD6T)_B_;5CR]=,732VSR=W?O>&FQ[6^VRM]^:<=W=WUSQ]9,HDS]D#$]%@.U +M%;K/`+P?`/@W!\"[K0!G2P$&PP"_G0OPWR +__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 /* for DELAY */ +#include +#include +#include +#include + +#include +#include + +#include /* for pmap_mapdev() */ +#include + +#include +#include +#include + +/* tunable params */ +static int myri10ge_nvidia_ecrc_enable = 1; +static int myri10ge_max_intr_slots = 128; +static int myri10ge_intr_coal_delay = 30; +static int myri10ge_skip_pio_read = 0; +static int myri10ge_flow_control = 1; +static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e"; +static char *myri10ge_fw_aligned = "myri10ge_eth_z8e"; + +static int myri10ge_probe(device_t dev); +static int myri10ge_attach(device_t dev); +static int myri10ge_detach(device_t dev); +static int myri10ge_shutdown(device_t dev); +static void myri10ge_intr(void *arg); + +static device_method_t myri10ge_methods[] = +{ + /* Device interface */ + DEVMETHOD(device_probe, myri10ge_probe), + DEVMETHOD(device_attach, myri10ge_attach), + DEVMETHOD(device_detach, myri10ge_detach), + DEVMETHOD(device_shutdown, myri10ge_shutdown), + {0, 0} +}; + +static driver_t myri10ge_driver = +{ + "myri10ge", + myri10ge_methods, + sizeof(myri10ge_softc_t), +}; + +static devclass_t myri10ge_devclass; + +/* Declare ourselves to be a child of the PCI bus.*/ +DRIVER_MODULE(myri10ge, pci, myri10ge_driver, myri10ge_devclass, 0, 0); +MODULE_DEPEND(myri10ge, firmware, 1, 1, 1); + +static int +myri10ge_probe(device_t dev) +{ + if ((pci_get_vendor(dev) == MYRI10GE_PCI_VENDOR_MYRICOM) && + (pci_get_device(dev) == MYRI10GE_PCI_DEVICE_Z8E)) { + device_set_desc(dev, "Myri10G-PCIE-8A"); + return 0; + } + return ENXIO; +} + +static void +myri10ge_enable_wc(myri10ge_softc_t *sc) +{ + struct mem_range_desc mrdesc; + vm_paddr_t pa; + vm_offset_t len; + int err, action; + + pa = rman_get_start(sc->mem_res); + len = rman_get_size(sc->mem_res); + mrdesc.mr_base = pa; + mrdesc.mr_len = len; + mrdesc.mr_flags = MDF_WRITECOMBINE; + action = MEMRANGE_SET_UPDATE; + strcpy((char *)&mrdesc.mr_owner, "myri10ge"); + err = mem_range_attr_set(&mrdesc, &action); + if (err != 0) { + device_printf(sc->dev, + "w/c failed for pa 0x%lx, len 0x%lx, err = %d\n", + (unsigned long)pa, (unsigned long)len, err); + } else { + sc->wc = 1; + } +} + + +/* callback to get our DMA address */ +static void +myri10ge_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, + int error) +{ + if (error == 0) { + *(bus_addr_t *) arg = segs->ds_addr; + } +} + +static int +myri10ge_dma_alloc(myri10ge_softc_t *sc, myri10ge_dma_t *dma, size_t bytes, + bus_size_t alignment) +{ + int err; + device_t dev = sc->dev; + + /* allocate DMAable memory tags */ + err = bus_dma_tag_create(sc->parent_dmat, /* parent */ + alignment, /* alignment */ + 4096, /* boundary */ + BUS_SPACE_MAXADDR, /* low */ + BUS_SPACE_MAXADDR, /* high */ + NULL, NULL, /* filter */ + bytes, /* maxsize */ + 1, /* num segs */ + 4096, /* maxsegsize */ + BUS_DMA_COHERENT, /* flags */ + NULL, NULL, /* lock */ + &dma->dmat); /* tag */ + if (err != 0) { + device_printf(dev, "couldn't alloc tag (err = %d)\n", err); + return err; + } + + /* allocate DMAable memory & map */ + err = bus_dmamem_alloc(dma->dmat, &dma->addr, + (BUS_DMA_WAITOK | BUS_DMA_COHERENT + | BUS_DMA_ZERO), &dma->map); + if (err != 0) { + device_printf(dev, "couldn't alloc mem (err = %d)\n", err); + goto abort_with_dmat; + } + + /* load the memory */ + err = bus_dmamap_load(dma->dmat, dma->map, dma->addr, bytes, + myri10ge_dmamap_callback, + (void *)&dma->bus_addr, 0); + if (err != 0) { + device_printf(dev, "couldn't load map (err = %d)\n", err); + goto abort_with_mem; + } + return 0; + +abort_with_mem: + bus_dmamem_free(dma->dmat, dma->addr, dma->map); +abort_with_dmat: + (void)bus_dma_tag_destroy(dma->dmat); + return err; +} + + +static void +myri10ge_dma_free(myri10ge_dma_t *dma) +{ + bus_dmamap_unload(dma->dmat, dma->map); + bus_dmamem_free(dma->dmat, dma->addr, dma->map); + (void)bus_dma_tag_destroy(dma->dmat); +} + +/* + * The eeprom strings on the lanaiX have the format + * SN=x\0 + * MAC=x:x:x:x:x:x\0 + * PC=text\0 + */ + +static int +myri10ge_parse_strings(myri10ge_softc_t *sc) +{ +#define MYRI10GE_NEXT_STRING(p) while(ptr < limit && *ptr++) + + char *ptr, *limit; + int i, found_mac; + + ptr = sc->eeprom_strings; + limit = sc->eeprom_strings + MYRI10GE_EEPROM_STRINGS_SIZE; + found_mac = 0; + while (ptr < limit && *ptr != '\0') { + if (memcmp(ptr, "MAC=", 4) == 0) { + ptr+=4; + sc->mac_addr_string = ptr; + for (i = 0; i < 6; i++) { + if ((ptr + 2) > limit) + goto abort; + sc->mac_addr[i] = strtoul(ptr, NULL, 16); + found_mac = 1; + ptr += 3; + } + } else if (memcmp(ptr, "PC=", 4) == 0) { + sc->product_code_string = ptr; + } + MYRI10GE_NEXT_STRING(ptr); + } + + if (found_mac) + return 0; + + abort: + device_printf(sc->dev, "failed to parse eeprom_strings\n"); + + return ENXIO; +} + +#if #cpu(i386) || defined __i386 || defined i386 || defined __i386__ || #cpu(x86_64) || defined __x86_64__ +static int +myri10ge_enable_nvidia_ecrc(myri10ge_softc_t *sc, device_t pdev) +{ + uint32_t val; + unsigned long off; + char *va, *cfgptr; + uint16_t vendor_id, device_id; + uintptr_t bus, slot, func, ivend, idev; + uint32_t *ptr32; + + /* XXXX + Test below is commented because it is believed that doing + config read/write beyond 0xff will access the config space + for the next larger function. Uncomment this and remove + the hacky pmap_mapdev() way of accessing config space when + FreeBSD grows support for extended pcie config space access + */ +#if 0 + /* See if we can, by some miracle, access the extended + config space */ + val = pci_read_config(pdev, 0x178, 4); + if (val != 0xffffffff) { + val |= 0x40; + pci_write_config(pdev, 0x178, val, 4); + return 0; + } +#endif + /* Rather than using normal pci config space writes, we must + * map the Nvidia config space ourselves. This is because on + * opteron/nvidia class machine the 0xe000000 mapping is + * handled by the nvidia chipset, that means the internal PCI + * device (the on-chip northbridge), or the amd-8131 bridge + * and things behind them are not visible by this method. + */ + + BUS_READ_IVAR(device_get_parent(pdev), pdev, + PCI_IVAR_BUS, &bus); + BUS_READ_IVAR(device_get_parent(pdev), pdev, + PCI_IVAR_SLOT, &slot); + BUS_READ_IVAR(device_get_parent(pdev), pdev, + PCI_IVAR_FUNCTION, &func); + BUS_READ_IVAR(device_get_parent(pdev), pdev, + PCI_IVAR_VENDOR, &ivend); + BUS_READ_IVAR(device_get_parent(pdev), pdev, + PCI_IVAR_DEVICE, &idev); + + off = 0xe0000000UL + + 0x00100000UL * (unsigned long)bus + + 0x00001000UL * (unsigned long)(func + + 8 * slot); + + /* map it into the kernel */ + va = pmap_mapdev(trunc_page((vm_paddr_t)off), PAGE_SIZE); + + + if (va == NULL) { + device_printf(sc->dev, "pmap_kenter_temporary didn't\n"); + return EIO; + } + /* get a pointer to the config space mapped into the kernel */ + cfgptr = va + (off & PAGE_MASK); + + /* make sure that we can really access it */ + vendor_id = *(uint16_t *)(cfgptr + PCIR_VENDOR); + device_id = *(uint16_t *)(cfgptr + PCIR_DEVICE); + if (! (vendor_id == ivend && device_id == idev)) { + device_printf(sc->dev, "mapping failed: 0x%x:0x%x\n", + vendor_id, device_id); + pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); + return EIO; + } + + ptr32 = (uint32_t*)(cfgptr + 0x178); + val = *ptr32; + + if (val == 0xffffffff) { + device_printf(sc->dev, "extended mapping failed\n"); + pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); + return EIO; + } + *ptr32 = val | 0x40; + pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); + device_printf(sc->dev, + "Enabled ECRC on upstream Nvidia bridge at %d:%d:%d\n", + (int)bus, (int)slot, (int)func); + return 0; +} +#else +static int +myri10ge_enable_nvidia_ecrc(myri10ge_softc_t *sc, device_t pdev) +{ + device_printf(sc->dev, + "Nforce 4 chipset on non-x86/amd64!?!?!\n"); + return ENXIO; +} +#endif +/* + * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput + * when the PCI-E Completion packets are aligned on an 8-byte + * boundary. Some PCI-E chip sets always align Completion packets; on + * the ones that do not, the alignment can be enforced by enabling + * ECRC generation (if supported). + * + * When PCI-E Completion packets are not aligned, it is actually more + * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. + * + * If the driver can neither enable ECRC nor verify that it has + * already been enabled, then it must use a firmware image which works + * around unaligned completion packets (ethp_z8e.dat), and it should + * also ensure that it never gives the device a Read-DMA which is + * larger than 2KB by setting the tx.boundary to 2KB. If ECRC is + * enabled, then the driver should use the aligned (eth_z8e.dat) + * firmware image, and set tx.boundary to 4KB. + */ + +static void +myri10ge_select_firmware(myri10ge_softc_t *sc) +{ + int err, aligned = 0; + device_t pdev; + uint16_t pvend, pdid; + + pdev = device_get_parent(device_get_parent(sc->dev)); + if (pdev == NULL) { + device_printf(sc->dev, "could not find parent?\n"); + goto abort; + } + pvend = pci_read_config(pdev, PCIR_VENDOR, 2); + pdid = pci_read_config(pdev, PCIR_DEVICE, 2); + + /* see if we can enable ECRC's on an upstream + Nvidia bridge */ + if (myri10ge_nvidia_ecrc_enable && + (pvend == 0x10de && pdid == 0x005d)) { + err = myri10ge_enable_nvidia_ecrc(sc, pdev); + if (err == 0) { + aligned = 1; + device_printf(sc->dev, + "Assuming aligned completions (ECRC)\n"); + } + } + /* see if the upstream bridge is known to + provided aligned completions */ + if (/* HT2000 */ (pvend == 0x1166 && pdid == 0x0132) || + /* Ontario */ (pvend == 0x10b5 && pdid == 0x8532)) { + device_printf(sc->dev, + "Assuming aligned completions (0x%x:0x%x)\n", + pvend, pdid); + } + +abort: + if (aligned) { + sc->fw_name = myri10ge_fw_aligned; + sc->tx.boundary = 4096; + } else { + sc->fw_name = myri10ge_fw_unaligned; + sc->tx.boundary = 2048; + } +} + +union qualhack +{ + const char *ro_char; + char *rw_char; +}; + + +static int +myri10ge_load_firmware_helper(myri10ge_softc_t *sc, uint32_t *limit) +{ + struct firmware *fw; + const mcp_gen_header_t *hdr; + unsigned hdr_offset; + const char *fw_data; + union qualhack hack; + int status; + + + fw = firmware_get(sc->fw_name); + + if (fw == NULL) { + device_printf(sc->dev, "Could not find firmware image %s\n", + sc->fw_name); + return ENOENT; + } + if (fw->datasize > *limit || + fw->datasize < MCP_HEADER_PTR_OFFSET + 4) { + device_printf(sc->dev, "Firmware image %s too large (%d/%d)\n", + sc->fw_name, (int)fw->datasize, (int) *limit); + status = ENOSPC; + goto abort_with_fw; + } + *limit = fw->datasize; + + /* check id */ + fw_data = (const char *)fw->data; + hdr_offset = htobe32(*(const uint32_t *) + (fw_data + MCP_HEADER_PTR_OFFSET)); + if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw->datasize) { + device_printf(sc->dev, "Bad firmware file"); + status = EIO; + goto abort_with_fw; + } + hdr = (const void*)(fw_data + hdr_offset); + if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) { + device_printf(sc->dev, "Bad firmware type: 0x%x\n", + be32toh(hdr->mcp_type)); + status = EIO; + goto abort_with_fw; + } + + /* save firmware version for sysctl */ + strncpy(sc->fw_version, hdr->version, sizeof (sc->fw_version)); + device_printf(sc->dev, "firmware id: %s\n", hdr->version); + + hack.ro_char = fw_data; + /* Copy the inflated firmware to NIC SRAM. */ + myri10ge_pio_copy(&sc->sram[MYRI10GE_FW_OFFSET], + hack.rw_char, *limit); + + status = 0; +abort_with_fw: + firmware_put(fw, FIRMWARE_UNLOAD); + return status; +} + +/* + * Enable or disable periodic RDMAs from the host to make certain + * chipsets resend dropped PCIe messages + */ + +static void +myri10ge_dummy_rdma(myri10ge_softc_t *sc, int enable) +{ + char buf_bytes[72]; + volatile uint32_t *confirm; + volatile char *submit; + uint32_t *buf, dma_low, dma_high; + int i; + + buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); + + /* clear confirmation addr */ + confirm = (volatile uint32_t *)sc->cmd; + *confirm = 0; + mb(); + + /* send an rdma command to the PCIe engine, and wait for the + response in the confirmation address. The firmware should + write a -1 there to indicate it is alive and well + */ + + dma_low = MYRI10GE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); + dma_high = MYRI10GE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); + buf[0] = htobe32(dma_high); /* confirm addr MSW */ + buf[1] = htobe32(dma_low); /* confirm addr LSW */ + buf[2] = htobe32(0xffffffff); /* confirm data */ + dma_low = MYRI10GE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr); + dma_high = MYRI10GE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr); + buf[3] = htobe32(dma_high); /* dummy addr MSW */ + buf[4] = htobe32(dma_low); /* dummy addr LSW */ + buf[5] = htobe32(enable); /* enable? */ + + + submit = (volatile char *)(sc->sram + 0xfc01c0); + + myri10ge_pio_copy(submit, buf, 64); + mb(); + DELAY(1000); + mb(); + i = 0; + while (*confirm != 0xffffffff && i < 20) { + DELAY(1000); + i++; + } + if (*confirm != 0xffffffff) { + device_printf(sc->dev, "dummy rdma %s failed (%p = 0x%x)", + (enable ? "enable" : "disable"), confirm, + *confirm); + } + return; +} + +static int +myri10ge_send_cmd(myri10ge_softc_t *sc, uint32_t cmd, + myri10ge_cmd_t *data) +{ + mcp_cmd_t *buf; + char buf_bytes[sizeof(*buf) + 8]; + volatile mcp_cmd_response_t *response = sc->cmd; + volatile char *cmd_addr = sc->sram + MYRI10GE_MCP_CMD_OFFSET; + uint32_t dma_low, dma_high; + int sleep_total = 0; + + /* ensure buf is aligned to 8 bytes */ + buf = (mcp_cmd_t *)((unsigned long)(buf_bytes + 7) & ~7UL); + + buf->data0 = htobe32(data->data0); + buf->data1 = htobe32(data->data1); + buf->data2 = htobe32(data->data2); + buf->cmd = htobe32(cmd); + dma_low = MYRI10GE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); + dma_high = MYRI10GE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); + + buf->response_addr.low = htobe32(dma_low); + buf->response_addr.high = htobe32(dma_high); + mtx_lock(&sc->cmd_lock); + response->result = 0xffffffff; + mb(); + myri10ge_pio_copy((volatile void *)cmd_addr, buf, sizeof (*buf)); + + /* wait up to 2 seconds */ + for (sleep_total = 0; sleep_total < (2 * 1000); sleep_total += 10) { + bus_dmamap_sync(sc->cmd_dma.dmat, + sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); + mb(); + if (response->result != 0xffffffff) { + if (response->result == 0) { + data->data0 = be32toh(response->data); + mtx_unlock(&sc->cmd_lock); + return 0; + } else { + device_printf(sc->dev, + "myri10ge: command %d " + "failed, result = %d\n", + cmd, be32toh(response->result)); + mtx_unlock(&sc->cmd_lock); + return ENXIO; + } + } + DELAY(1000 * 10); + } + mtx_unlock(&sc->cmd_lock); + device_printf(sc->dev, "myri10ge: command %d timed out" + "result = %d\n", + cmd, be32toh(response->result)); + return EAGAIN; +} + + +static int +myri10ge_load_firmware(myri10ge_softc_t *sc) +{ + volatile uint32_t *confirm; + volatile char *submit; + char buf_bytes[72]; + uint32_t *buf, size, dma_low, dma_high; + int status, i; + + buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); + + size = sc->sram_size; + status = myri10ge_load_firmware_helper(sc, &size); + if (status) { + device_printf(sc->dev, "firmware loading failed\n"); + return status; + } + /* clear confirmation addr */ + confirm = (volatile uint32_t *)sc->cmd; + *confirm = 0; + mb(); + /* send a reload command to the bootstrap MCP, and wait for the + response in the confirmation address. The firmware should + write a -1 there to indicate it is alive and well + */ + + dma_low = MYRI10GE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); + dma_high = MYRI10GE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); + + buf[0] = htobe32(dma_high); /* confirm addr MSW */ + buf[1] = htobe32(dma_low); /* confirm addr LSW */ + buf[2] = htobe32(0xffffffff); /* confirm data */ + + /* FIX: All newest firmware should un-protect the bottom of + the sram before handoff. However, the very first interfaces + do not. Therefore the handoff copy must skip the first 8 bytes + */ + /* where the code starts*/ + buf[3] = htobe32(MYRI10GE_FW_OFFSET + 8); + buf[4] = htobe32(size - 8); /* length of code */ + buf[5] = htobe32(8); /* where to copy to */ + buf[6] = htobe32(0); /* where to jump to */ + + submit = (volatile char *)(sc->sram + 0xfc0000); + myri10ge_pio_copy(submit, buf, 64); + mb(); + DELAY(1000); + mb(); + i = 0; + while (*confirm != 0xffffffff && i < 20) { + DELAY(1000*10); + i++; + bus_dmamap_sync(sc->cmd_dma.dmat, + sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); + } + if (*confirm != 0xffffffff) { + device_printf(sc->dev,"handoff failed (%p = 0x%x)", + confirm, *confirm); + + return ENXIO; + } + myri10ge_dummy_rdma(sc, 1); + return 0; +} + +static int +myri10ge_update_mac_address(myri10ge_softc_t *sc) +{ + myri10ge_cmd_t cmd; + uint8_t *addr = sc->mac_addr; + int status; + + + cmd.data0 = ((addr[0] << 24) | (addr[1] << 16) + | (addr[2] << 8) | addr[3]); + + cmd.data1 = ((addr[4] << 8) | (addr[5])); + + status = myri10ge_send_cmd(sc, MYRI10GE_MCP_SET_MAC_ADDRESS, &cmd); + return status; +} + +static int +myri10ge_change_pause(myri10ge_softc_t *sc, int pause) +{ + myri10ge_cmd_t cmd; + int status; + + if (pause) + status = myri10ge_send_cmd(sc, + MYRI10GE_MCP_ENABLE_FLOW_CONTROL, + &cmd); + else + status = myri10ge_send_cmd(sc, + MYRI10GE_MCP_DISABLE_FLOW_CONTROL, + &cmd); + + if (status) { + device_printf(sc->dev, "Failed to set flow control mode\n"); + return ENXIO; + } + sc->pause = pause; + return 0; +} + +static void +myri10ge_change_promisc(myri10ge_softc_t *sc, int promisc) +{ + myri10ge_cmd_t cmd; + int status; + + if (promisc) + status = myri10ge_send_cmd(sc, + MYRI10GE_MCP_ENABLE_PROMISC, + &cmd); + else + status = myri10ge_send_cmd(sc, + MYRI10GE_MCP_DISABLE_PROMISC, + &cmd); + + if (status) { + device_printf(sc->dev, "Failed to set promisc mode\n"); + } +} + +static int +myri10ge_reset(myri10ge_softc_t *sc) +{ + + myri10ge_cmd_t cmd; + int status, i; + + /* try to send a reset command to the card to see if it + is alive */ + memset(&cmd, 0, sizeof (cmd)); + status = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_RESET, &cmd); + if (status != 0) { + device_printf(sc->dev, "failed reset\n"); + return ENXIO; + } + + /* Now exchange information about interrupts */ + + cmd.data0 = (uint32_t) + (myri10ge_max_intr_slots * sizeof (*sc->intr.q[0])); + status = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_SET_INTRQ_SIZE, &cmd); + for (i = 0; (status == 0) && (i < MYRI10GE_NUM_INTRQS); i++) { + cmd.data0 = MYRI10GE_LOWPART_TO_U32(sc->intr.dma[i].bus_addr); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(sc->intr.dma[i].bus_addr); + status |= + myri10ge_send_cmd(sc, (i + + MYRI10GE_MCP_CMD_SET_INTRQ0_DMA), + &cmd); + } + + cmd.data0 = sc->intr_coal_delay = myri10ge_intr_coal_delay; + status |= myri10ge_send_cmd(sc, + MYRI10GE_MCP_CMD_SET_INTR_COAL_DELAY, &cmd); + + if (sc->msi_enabled) { + status |= myri10ge_send_cmd + (sc, MYRI10GE_MCP_CMD_GET_IRQ_ACK_OFFSET, &cmd); + } else { + status |= myri10ge_send_cmd + (sc, MYRI10GE_MCP_CMD_GET_IRQ_ACK_DEASSERT_OFFSET, + &cmd); + } + if (status != 0) { + device_printf(sc->dev, "failed set interrupt parameters\n"); + return status; + } + sc->irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0); + + /* reset mcp/driver shared state back to 0 */ + sc->intr.seqnum = 0; + sc->intr.intrq = 0; + sc->intr.slot = 0; + sc->tx.req = 0; + sc->tx.done = 0; + sc->rx_big.cnt = 0; + sc->rx_small.cnt = 0; + sc->rdma_tags_available = 15; + status = myri10ge_update_mac_address(sc); + myri10ge_change_promisc(sc, 0); + myri10ge_change_pause(sc, sc->pause); + return status; +} + +static int +myri10ge_change_intr_coal(SYSCTL_HANDLER_ARGS) +{ + myri10ge_cmd_t cmd; + myri10ge_softc_t *sc; + unsigned int intr_coal_delay; + int err; + + sc = arg1; + intr_coal_delay = sc->intr_coal_delay; + err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req); + if (err != 0) { + return err; + } + if (intr_coal_delay == sc->intr_coal_delay) + return 0; + + if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000) + return EINVAL; + + sx_xlock(&sc->driver_lock); + cmd.data0 = intr_coal_delay; + err = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_SET_INTR_COAL_DELAY, + &cmd); + if (err == 0) { + sc->intr_coal_delay = intr_coal_delay; + } + sx_xunlock(&sc->driver_lock); + return err; +} + +static int +myri10ge_change_flow_control(SYSCTL_HANDLER_ARGS) +{ + myri10ge_softc_t *sc; + unsigned int enabled; + int err; + + sc = arg1; + enabled = sc->pause; + err = sysctl_handle_int(oidp, &enabled, arg2, req); + if (err != 0) { + return err; + } + if (enabled == sc->pause) + return 0; + + sx_xlock(&sc->driver_lock); + err = myri10ge_change_pause(sc, enabled); + sx_xunlock(&sc->driver_lock); + return err; +} + +static int +myri10ge_handle_be32(SYSCTL_HANDLER_ARGS) +{ + int err; + + if (arg1 == NULL) + return EFAULT; + arg2 = be32toh(*(int *)arg1); + arg1 = NULL; + err = sysctl_handle_int(oidp, arg1, arg2, req); + + return err; +} + +static void +myri10ge_add_sysctls(myri10ge_softc_t *sc) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *children; + mcp_stats_t *fw; + + ctx = device_get_sysctl_ctx(sc->dev); + children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); + fw = sc->fw_stats; + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "intr_coal_delay", + CTLTYPE_INT|CTLFLAG_RW, sc, + 0, myri10ge_change_intr_coal, + "I", "interrupt coalescing delay in usecs"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "flow_control_enabled", + CTLTYPE_INT|CTLFLAG_RW, sc, + 0, myri10ge_change_flow_control, + "I", "interrupt coalescing delay in usecs"); + + SYSCTL_ADD_INT(ctx, children, OID_AUTO, + "skip_pio_read", + CTLFLAG_RW, &myri10ge_skip_pio_read, + 0, "Skip pio read in interrupt handler"); + + /* stats block from firmware is in network byte order. + Need to swap it */ + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "link_up", + CTLTYPE_INT|CTLFLAG_RD, &fw->link_up, + 0, myri10ge_handle_be32, + "I", "link up"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "rdma_tags_available", + CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available, + 0, myri10ge_handle_be32, + "I", "rdma_tags_available"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_link_overflow", + CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow, + 0, myri10ge_handle_be32, + "I", "dropped_link_overflow"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_link_error_or_filtered", + CTLTYPE_INT|CTLFLAG_RD, + &fw->dropped_link_error_or_filtered, + 0, myri10ge_handle_be32, + "I", "dropped_link_error_or_filtered"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_runt", + CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt, + 0, myri10ge_handle_be32, + "I", "dropped_runt"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_overrun", + CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun, + 0, myri10ge_handle_be32, + "I", "dropped_overrun"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_no_small_buffer", + CTLTYPE_INT|CTLFLAG_RD, + &fw->dropped_no_small_buffer, + 0, myri10ge_handle_be32, + "I", "dropped_no_small_buffer"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_no_big_buffer", + CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer, + 0, myri10ge_handle_be32, + "I", "dropped_no_big_buffer"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_interrupt_busy", + CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_interrupt_busy, + 0, myri10ge_handle_be32, + "I", "dropped_interrupt_busy"); + + /* host counters exported for debugging */ + SYSCTL_ADD_INT(ctx, children, OID_AUTO, + "tx_req", + CTLFLAG_RD, &sc->tx.req, + 0, "tx_req"); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, + "tx_done", + CTLFLAG_RD, &sc->tx.done, + 0, "tx_done"); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, + "rx_small_cnt", + CTLFLAG_RD, &sc->rx_small.cnt, + 0, "rx_small_cnt"); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, + "rx_big_cnt", + CTLFLAG_RD, &sc->rx_big.cnt, + 0, "rx_small_cnt"); + +} + +/* copy an array of mcp_kreq_ether_send_t's to the mcp. Copy + backwards one at a time and handle ring wraps */ + +static inline void +myri10ge_submit_req_backwards(myri10ge_tx_buf_t *tx, + mcp_kreq_ether_send_t *src, int cnt) +{ + int idx, starting_slot; + starting_slot = tx->req; + while (cnt > 1) { + cnt--; + idx = (starting_slot + cnt) & tx->mask; + myri10ge_pio_copy(&tx->lanai[idx], + &src[cnt], sizeof(*src)); + mb(); + } +} + +/* + * copy an array of mcp_kreq_ether_send_t's to the mcp. Copy + * at most 32 bytes at a time, so as to avoid involving the software + * pio handler in the nic. We re-write the first segment's flags + * to mark them valid only after writing the entire chain + */ + +static inline void +myri10ge_submit_req(myri10ge_tx_buf_t *tx, mcp_kreq_ether_send_t *src, + int cnt) +{ + int idx, i; + uint32_t *src_ints; + volatile uint32_t *dst_ints; + mcp_kreq_ether_send_t *srcp; + volatile mcp_kreq_ether_send_t *dstp, *dst; + + + idx = tx->req & tx->mask; + + src->flags &= ~(htobe16(MYRI10GE_MCP_ETHER_FLAGS_VALID)); + mb(); + dst = dstp = &tx->lanai[idx]; + srcp = src; + + if ((idx + cnt) < tx->mask) { + for (i = 0; i < (cnt - 1); i += 2) { + myri10ge_pio_copy(dstp, srcp, 2 * sizeof(*src)); + mb(); /* force write every 32 bytes */ + srcp += 2; + dstp += 2; + } + } else { + /* submit all but the first request, and ensure + that it is submitted below */ + myri10ge_submit_req_backwards(tx, src, cnt); + i = 0; + } + if (i < cnt) { + /* submit the first request */ + myri10ge_pio_copy(dstp, srcp, sizeof(*src)); + mb(); /* barrier before setting valid flag */ + } + + /* re-write the last 32-bits with the valid flags */ + src->flags |= htobe16(MYRI10GE_MCP_ETHER_FLAGS_VALID); + src_ints = (uint32_t *)src; + src_ints+=3; + dst_ints = (volatile uint32_t *)dst; + dst_ints+=3; + *dst_ints = *src_ints; + tx->req += cnt; + mb(); +} + +static inline void +myri10ge_submit_req_wc(myri10ge_tx_buf_t *tx, + mcp_kreq_ether_send_t *src, int cnt) +{ + tx->req += cnt; + mb(); + while (cnt >= 4) { + myri10ge_pio_copy((volatile char *)tx->wc_fifo, src, 64); + mb(); + src += 4; + cnt -= 4; + } + if (cnt > 0) { + /* pad it to 64 bytes. The src is 64 bytes bigger than it + needs to be so that we don't overrun it */ + myri10ge_pio_copy(tx->wc_fifo + (cnt<<18), src, 64); + mb(); + } +} + +static void +myri10ge_encap(myri10ge_softc_t *sc, struct mbuf *m) +{ + mcp_kreq_ether_send_t *req; + bus_dma_segment_t seg_list[MYRI10GE_MCP_ETHER_MAX_SEND_DESC]; + bus_dma_segment_t *seg; + struct mbuf *m_tmp; + struct ifnet *ifp; + myri10ge_tx_buf_t *tx; + struct ether_header *eh; + struct ip *ip; + int cnt, cum_len, err, i, idx; + uint16_t flags, pseudo_hdr_offset; + uint8_t cksum_offset; + + + + ifp = sc->ifp; + tx = &sc->tx; + + /* (try to) map the frame for DMA */ + idx = tx->req & tx->mask; + err = bus_dmamap_load_mbuf_sg(tx->dmat, tx->info[idx].map, + m, seg_list, &cnt, + BUS_DMA_NOWAIT); + if (err == EFBIG) { + /* Too many segments in the chain. Try + to defrag */ + m_tmp = m_defrag(m, M_NOWAIT); + if (m_tmp == NULL) { + goto drop; + } + m = m_tmp; + err = bus_dmamap_load_mbuf_sg(tx->dmat, + tx->info[idx].map, + m, seg_list, &cnt, + BUS_DMA_NOWAIT); + } + if (err != 0) { + device_printf(sc->dev, "bus_dmamap_load_mbuf_sg returned %d\n", + err); + goto drop; + } + bus_dmamap_sync(tx->dmat, tx->info[idx].map, + BUS_DMASYNC_PREWRITE); + + req = tx->req_list; + cksum_offset = 0; + flags = htobe16(MYRI10GE_MCP_ETHER_FLAGS_VALID | + MYRI10GE_MCP_ETHER_FLAGS_NOT_LAST); + + /* checksum offloading? */ + if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) { + eh = mtod(m, struct ether_header *); + ip = (struct ip *) (eh + 1); + cksum_offset = sizeof(*eh) + (ip->ip_hl << 2); + pseudo_hdr_offset = cksum_offset + m->m_pkthdr.csum_data; + req->pseudo_hdr_offset = htobe16(pseudo_hdr_offset); + req->cksum_offset = cksum_offset; + flags |= htobe16(MYRI10GE_MCP_ETHER_FLAGS_CKSUM); + } + if (m->m_pkthdr.len < 512) + req->flags = htobe16(MYRI10GE_MCP_ETHER_FLAGS_FIRST | + MYRI10GE_MCP_ETHER_FLAGS_SMALL); + else + req->flags = htobe16(MYRI10GE_MCP_ETHER_FLAGS_FIRST); + + /* convert segments into a request list */ + cum_len = 0; + seg = seg_list; + for (i = 0; i < cnt; i++) { + req->addr_low = + htobe32(MYRI10GE_LOWPART_TO_U32(seg->ds_addr)); + req->addr_high = + htobe32(MYRI10GE_HIGHPART_TO_U32(seg->ds_addr)); + req->length = htobe16(seg->ds_len); + req->cksum_offset = cksum_offset; + if (cksum_offset > seg->ds_len) + cksum_offset -= seg->ds_len; + else + cksum_offset = 0; + req->flags |= flags | ((cum_len & 1) * + htobe16(MYRI10GE_MCP_ETHER_FLAGS_ALIGN_ODD)); + cum_len += seg->ds_len; + seg++; + req++; + req->flags = 0; + } + req--; + /* pad runts to 60 bytes */ + if (cum_len < 60) { + req++; + req->addr_low = + htobe32(MYRI10GE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr)); + req->addr_high = + htobe32(MYRI10GE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr)); + req->length = htobe16(60 - cum_len); + req->cksum_offset = cksum_offset; + req->flags |= flags | ((cum_len & 1) * + htobe16(MYRI10GE_MCP_ETHER_FLAGS_ALIGN_ODD)); + cnt++; + } + req->flags &= ~(htobe16(MYRI10GE_MCP_ETHER_FLAGS_NOT_LAST)); + tx->info[idx].m = m; + if (tx->wc_fifo == NULL) + myri10ge_submit_req(tx, tx->req_list, cnt); + else + myri10ge_submit_req_wc(tx, tx->req_list, cnt); + return; + +drop: + m_freem(m); + ifp->if_oerrors++; + return; +} + + +static void +myri10ge_start_locked(myri10ge_softc_t *sc) +{ + int avail; + struct mbuf *m; + struct ifnet *ifp; + + + ifp = sc->ifp; + while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { + /* dequeue the packet */ + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + + /* let BPF see it */ + BPF_MTAP(ifp, m); + + /* give it to the nic */ + myri10ge_encap(sc, m); + + /* leave an extra slot keep the ring from wrapping */ + avail = sc->tx.mask - (sc->tx.req - sc->tx.done); + if (avail < MYRI10GE_MCP_ETHER_MAX_SEND_DESC) { + sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE; + return; + } + } +} + +static void +myri10ge_start(struct ifnet *ifp) +{ + myri10ge_softc_t *sc = ifp->if_softc; + + + mtx_lock(&sc->tx_lock); + myri10ge_start_locked(sc); + mtx_unlock(&sc->tx_lock); +} + +static int +myri10ge_get_buf_small(myri10ge_softc_t *sc, bus_dmamap_t map, int idx) +{ + bus_dma_segment_t seg; + struct mbuf *m; + myri10ge_rx_buf_t *rx = &sc->rx_small; + int cnt, err; + + m = m_gethdr(M_DONTWAIT, MT_DATA); + if (m == NULL) { + rx->alloc_fail++; + err = ENOBUFS; + goto done; + } + m->m_len = MHLEN; + err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, + &seg, &cnt, BUS_DMA_NOWAIT); + if (err != 0) { + m_free(m); + goto done; + } + rx->info[idx].m = m; + rx->shadow[idx].addr_low = + htobe32(MYRI10GE_LOWPART_TO_U32(seg.ds_addr)); + rx->shadow[idx].addr_high = + htobe32(MYRI10GE_HIGHPART_TO_U32(seg.ds_addr)); + +done: + if ((idx & 7) == 7) { + myri10ge_pio_copy(&rx->lanai[idx - 7], + &rx->shadow[idx - 7], + 8 * sizeof (*rx->lanai)); + mb(); + } + return err; +} + +static int +myri10ge_get_buf_big(myri10ge_softc_t *sc, bus_dmamap_t map, int idx) +{ + bus_dma_segment_t seg; + struct mbuf *m; + myri10ge_rx_buf_t *rx = &sc->rx_big; + int cnt, err; + + m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, sc->big_bytes); + if (m == NULL) { + rx->alloc_fail++; + err = ENOBUFS; + goto done; + } + m->m_len = sc->big_bytes; + err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, + &seg, &cnt, BUS_DMA_NOWAIT); + if (err != 0) { + m_free(m); + goto done; + } + rx->info[idx].m = m; + rx->shadow[idx].addr_low = + htobe32(MYRI10GE_LOWPART_TO_U32(seg.ds_addr)); + rx->shadow[idx].addr_high = + htobe32(MYRI10GE_HIGHPART_TO_U32(seg.ds_addr)); + +done: + if ((idx & 7) == 7) { + myri10ge_pio_copy(&rx->lanai[idx - 7], + &rx->shadow[idx - 7], + 8 * sizeof (*rx->lanai)); + mb(); + } + return err; +} + +static inline void +myri10ge_rx_done_big(myri10ge_softc_t *sc, int len, int csum, int flags) +{ + struct ifnet *ifp; + struct mbuf *m = 0; /* -Wunitialized */ + struct mbuf *m_prev = 0; /* -Wunitialized */ + struct mbuf *m_head = 0; + bus_dmamap_t old_map; + myri10ge_rx_buf_t *rx; + int idx; + + + rx = &sc->rx_big; + ifp = sc->ifp; + while (len > 0) { + idx = rx->cnt & rx->mask; + rx->cnt++; + /* save a pointer to the received mbuf */ + m = rx->info[idx].m; + /* try to replace the received mbuf */ + if (myri10ge_get_buf_big(sc, rx->extra_map, idx)) { + goto drop; + } + /* unmap the received buffer */ + old_map = rx->info[idx].map; + bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rx->dmat, old_map); + + /* swap the bus_dmamap_t's */ + rx->info[idx].map = rx->extra_map; + rx->extra_map = old_map; + + /* chain multiple segments together */ + if (!m_head) { + m_head = m; + /* mcp implicitly skips 1st bytes so that + * packet is properly aligned */ + m->m_data += MYRI10GE_MCP_ETHER_PAD; + m->m_pkthdr.len = len; + m->m_len = sc->big_bytes - MYRI10GE_MCP_ETHER_PAD; + } else { + m->m_len = sc->big_bytes; + m->m_flags &= ~M_PKTHDR; + m_prev->m_next = m; + } + len -= m->m_len; + m_prev = m; + } + + /* trim trailing garbage from the last mbuf in the chain. If + * there is any garbage, len will be negative */ + m->m_len += len; + + /* if the checksum is valid, mark it in the mbuf header */ + if (sc->csum_flag & flags) { + m_head->m_pkthdr.csum_data = csum; + m_head->m_pkthdr.csum_flags = CSUM_DATA_VALID; + } + + /* pass the frame up the stack */ + m_head->m_pkthdr.rcvif = ifp; + ifp->if_ipackets++; + (*ifp->if_input)(ifp, m_head); + return; + +drop: + /* drop the frame -- the old mbuf(s) are re-cycled by running + every slot through the allocator */ + if (m_head) { + len -= sc->big_bytes; + m_freem(m_head); + } else { + len -= (sc->big_bytes + MYRI10GE_MCP_ETHER_PAD); + } + while ((int)len > 0) { + idx = rx->cnt & rx->mask; + rx->cnt++; + m = rx->info[idx].m; + if (0 == (myri10ge_get_buf_big(sc, rx->extra_map, idx))) { + m_freem(m); + /* unmap the received buffer */ + old_map = rx->info[idx].map; + bus_dmamap_sync(rx->dmat, old_map, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rx->dmat, old_map); + + /* swap the bus_dmamap_t's */ + rx->info[idx].map = rx->extra_map; + rx->extra_map = old_map; + } + len -= sc->big_bytes; + } + + ifp->if_ierrors++; + +} + + +static inline void +myri10ge_rx_done_small(myri10ge_softc_t *sc, uint32_t len, + uint32_t csum, uint32_t flags) +{ + struct ifnet *ifp; + struct mbuf *m; + myri10ge_rx_buf_t *rx; + bus_dmamap_t old_map; + int idx; + + ifp = sc->ifp; + rx = &sc->rx_small; + idx = rx->cnt & rx->mask; + rx->cnt++; + /* save a pointer to the received mbuf */ + m = rx->info[idx].m; + /* try to replace the received mbuf */ + if (myri10ge_get_buf_small(sc, rx->extra_map, idx)) { + /* drop the frame -- the old mbuf is re-cycled */ + ifp->if_ierrors++; + return; + } + + /* unmap the received buffer */ + old_map = rx->info[idx].map; + bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rx->dmat, old_map); + + /* swap the bus_dmamap_t's */ + rx->info[idx].map = rx->extra_map; + rx->extra_map = old_map; + + /* mcp implicitly skips 1st 2 bytes so that packet is properly + * aligned */ + m->m_data += MYRI10GE_MCP_ETHER_PAD; + + /* if the checksum is valid, mark it in the mbuf header */ + if (sc->csum_flag & flags) { + m->m_pkthdr.csum_data = csum; + m->m_pkthdr.csum_flags = CSUM_DATA_VALID; + } + + /* pass the frame up the stack */ + m->m_pkthdr.rcvif = ifp; + m->m_len = m->m_pkthdr.len = len; + ifp->if_ipackets++; + (*ifp->if_input)(ifp, m); +} + +static inline void +myri10ge_tx_done(myri10ge_softc_t *sc, uint32_t mcp_idx) +{ + struct ifnet *ifp; + myri10ge_tx_buf_t *tx; + struct mbuf *m; + bus_dmamap_t map; + int idx; + + tx = &sc->tx; + ifp = sc->ifp; + while (tx->done != mcp_idx) { + idx = tx->done & tx->mask; + tx->done++; + m = tx->info[idx].m; + /* mbuf and DMA map only attached to the first + segment per-mbuf */ + if (m != NULL) { + ifp->if_opackets++; + tx->info[idx].m = NULL; + map = tx->info[idx].map; + bus_dmamap_unload(tx->dmat, map); + m_freem(m); + } + } + + /* If we have space, clear IFF_OACTIVE to tell the stack that + its OK to send packets */ + + if (ifp->if_drv_flags & IFF_DRV_OACTIVE && + tx->req - tx->done < (tx->mask + 1)/4) { + mtx_lock(&sc->tx_lock); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + myri10ge_start_locked(sc); + mtx_unlock(&sc->tx_lock); + } +} + +static void +myri10ge_dump_interrupt_queues(myri10ge_softc_t *sc, int maxslot) +{ + int intrq, slot, type; + static int call_cnt = 0; + + /* only do it a few times to avoid filling the message buffer */ + if (call_cnt > 10) + return; + + call_cnt++; + + device_printf(sc->dev, "--------- Dumping interrupt queue state ----- \n"); + device_printf(sc->dev, "currently expecting interrupts on queue %d\n", + sc->intr.intrq); + device_printf(sc->dev, " q slot status \n"); + device_printf(sc->dev, "--- ---- -------- \n"); + for (intrq = 0; intrq < 2; intrq++) { + for (slot = 0; slot <= maxslot; slot++) { + type = sc->intr.q[intrq][slot].type; +#if 0 + if (type == 0 && slot != 0) + continue; +#endif + device_printf(sc->dev, "[%d]:[%d]: type = 0x%x\n", intrq, slot, + type); + device_printf(sc->dev, "[%d]:[%d]: flag = 0x%x\n", intrq, slot, + sc->intr.q[intrq][slot].flag); + device_printf(sc->dev, "[%d]:[%d]: index = 0x%x\n", intrq, slot, + be16toh(sc->intr.q[intrq][slot].index)); + device_printf(sc->dev, "[%d]:[%d]: seqnum = 0x%x\n", intrq, slot, + (unsigned int)be32toh(sc->intr.q[intrq][slot].seqnum)); + device_printf(sc->dev, "[%d]:[%d]: data0 = 0x%x\n", intrq, slot, + (unsigned int)be32toh(sc->intr.q[intrq][slot].data0)); + device_printf(sc->dev, "[%d]:[%d]: data1 = 0x%x\n", intrq, slot, + (unsigned int)be32toh(sc->intr.q[intrq][slot].data1)); + + } + } + +} + +static inline void +myri10ge_claim_irq(myri10ge_softc_t *sc) +{ + volatile uint32_t dontcare; + + + *sc->irq_claim = 0; + mb(); + + /* do a PIO read to ensure that PIO write to claim the irq has + hit the nic before we exit the interrupt handler */ + if (!myri10ge_skip_pio_read) { + dontcare = *(volatile uint32_t *)sc->sram; + mb(); + } +} + +static void +myri10ge_intr(void *arg) +{ + myri10ge_softc_t *sc = arg; + int intrq, claimed, flags, count, length, ip_csum; + uint32_t raw, slot; + uint8_t type; + + + intrq = sc->intr.intrq; + claimed = 0; + bus_dmamap_sync(sc->intr.dma[intrq].dmat, + sc->intr.dma[intrq].map, BUS_DMASYNC_POSTREAD); + if (sc->msi_enabled) { + /* We know we can immediately claim the interrupt */ + myri10ge_claim_irq(sc); + claimed = 1; + } else { + /* Check to see if we have the last event in the queue + ready. If so, ack it as early as possible. This + allows more time to get the interrupt line + de-asserted prior to the EOI and reduces the chance + of seeing a spurious irq caused by the interrupt + line remaining high after EOI */ + + slot = be16toh(sc->intr.q[intrq][0].index) - 1; + if (slot < myri10ge_max_intr_slots && + sc->intr.q[intrq][slot].type != 0 && + sc->intr.q[intrq][slot].flag != 0) { + myri10ge_claim_irq(sc); + claimed = 1; + } + } + + /* walk each slot in the current queue, processing events until + we reach an event with a zero type */ + for (slot = sc->intr.slot; slot < myri10ge_max_intr_slots; slot++) { + type = sc->intr.q[intrq][slot].type; + + /* check for partially completed DMA of events when + using non-MSI interrupts */ + if (__predict_false(!claimed)) { + mb(); + /* look if there is somscing in the queue */ + if (type == 0) { + /* save the current slot for the next + * time we (re-)enter this routine */ + if (sc->intr.slot == slot) { + sc->intr.spurious++; + } + sc->intr.slot = slot; + return; + } + } + if (__predict_false(htobe32(sc->intr.q[intrq][slot].seqnum) != + sc->intr.seqnum++)) { + device_printf(sc->dev, "Bad interrupt!\n"); + device_printf(sc->dev, + "bad irq seqno" + "(got 0x%x, expected 0x%x) \n", + (unsigned int)htobe32(sc->intr.q[intrq][slot].seqnum), + sc->intr.seqnum); + device_printf(sc->dev, "intrq = %d, slot = %d\n", + intrq, slot); + myri10ge_dump_interrupt_queues(sc, slot); + device_printf(sc->dev, + "Disabling futher interrupt handling\n"); + bus_teardown_intr(sc->dev, sc->irq_res, + sc->ih); + sc->ih = NULL; + return; + } + + switch (type) { + case MYRI10GE_MCP_INTR_ETHER_SEND_DONE: + myri10ge_tx_done(sc, be32toh(sc->intr.q[intrq][slot].data0)); + + if (__predict_true(sc->intr.q[intrq][slot].data1 == 0)) + break; + + /* check the link state. Don't bother to + * byteswap, since it can just be 0 or 1 */ + if (sc->link_state != sc->fw_stats->link_up) { + sc->link_state = sc->fw_stats->link_up; + if (sc->link_state) { + if_link_state_change(sc->ifp, + LINK_STATE_UP); + device_printf(sc->dev, + "link up\n"); + } else { + if_link_state_change(sc->ifp, + LINK_STATE_DOWN); + device_printf(sc->dev, + "link down\n"); + } + } + if (sc->rdma_tags_available != + be32toh(sc->fw_stats->rdma_tags_available)) { + sc->rdma_tags_available = + be32toh(sc->fw_stats->rdma_tags_available); + device_printf(sc->dev, "RDMA timed out!" + " %d tags left\n", + sc->rdma_tags_available); + } + + break; + + + case MYRI10GE_MCP_INTR_ETHER_RECV_SMALL: + raw = be32toh(sc->intr.q[intrq][slot].data0); + count = 0xff & raw; + flags = raw >> 8; + raw = be32toh(sc->intr.q[intrq][slot].data1); + ip_csum = raw >> 16; + length = 0xffff & raw; + myri10ge_rx_done_small(sc, length, ip_csum, + flags); + break; + + case MYRI10GE_MCP_INTR_ETHER_RECV_BIG: + raw = be32toh(sc->intr.q[intrq][slot].data0); + count = 0xff & raw; + flags = raw >> 8; + raw = be32toh(sc->intr.q[intrq][slot].data1); + ip_csum = raw >> 16; + length = 0xffff & raw; + myri10ge_rx_done_big(sc, length, ip_csum, + flags); + + break; + + case MYRI10GE_MCP_INTR_LINK_CHANGE: + /* not yet implemented in firmware */ + break; + + case MYRI10GE_MCP_INTR_ETHER_DOWN: + sc->down_cnt++; + wakeup(&sc->down_cnt); + break; + + default: + device_printf(sc->dev, "Unknown interrupt type %d\n", + type); + } + sc->intr.q[intrq][slot].type = 0; + if (sc->intr.q[intrq][slot].flag != 0) { + if (!claimed) { + myri10ge_claim_irq(sc); + } + sc->intr.slot = 0; + sc->intr.q[intrq][slot].flag = 0; + sc->intr.intrq = ((intrq + 1) & 1); + return; + } + } + + /* we should never be here unless we're on a shared irq and we have + not finished setting up the device */ + return; +} + +static void +myri10ge_watchdog(struct ifnet *ifp) +{ + printf("%s called\n", __FUNCTION__); +} + +static void +myri10ge_init(void *arg) +{ +} + + + +static void +myri10ge_free_mbufs(myri10ge_softc_t *sc) +{ + int i; + + for (i = 0; i <= sc->rx_big.mask; i++) { + if (sc->rx_big.info[i].m == NULL) + continue; + bus_dmamap_unload(sc->rx_big.dmat, + sc->rx_big.info[i].map); + m_freem(sc->rx_big.info[i].m); + sc->rx_big.info[i].m = NULL; + } + + for (i = 0; i <= sc->rx_big.mask; i++) { + if (sc->rx_big.info[i].m == NULL) + continue; + bus_dmamap_unload(sc->rx_big.dmat, + sc->rx_big.info[i].map); + m_freem(sc->rx_big.info[i].m); + sc->rx_big.info[i].m = NULL; + } + + for (i = 0; i <= sc->tx.mask; i++) { + if (sc->tx.info[i].m == NULL) + continue; + bus_dmamap_unload(sc->tx.dmat, + sc->tx.info[i].map); + m_freem(sc->tx.info[i].m); + sc->tx.info[i].m = NULL; + } +} + +static void +myri10ge_free_rings(myri10ge_softc_t *sc) +{ + int i; + + if (sc->tx.req_bytes != NULL) { + free(sc->tx.req_bytes, M_DEVBUF); + } + if (sc->rx_small.shadow != NULL) + free(sc->rx_small.shadow, M_DEVBUF); + if (sc->rx_big.shadow != NULL) + free(sc->rx_big.shadow, M_DEVBUF); + if (sc->tx.info != NULL) { + for (i = 0; i <= sc->tx.mask; i++) { + if (sc->tx.info[i].map != NULL) + bus_dmamap_destroy(sc->tx.dmat, + sc->tx.info[i].map); + } + free(sc->tx.info, M_DEVBUF); + } + if (sc->rx_small.info != NULL) { + for (i = 0; i <= sc->rx_small.mask; i++) { + if (sc->rx_small.info[i].map != NULL) + bus_dmamap_destroy(sc->rx_small.dmat, + sc->rx_small.info[i].map); + } + free(sc->rx_small.info, M_DEVBUF); + } + if (sc->rx_big.info != NULL) { + for (i = 0; i <= sc->rx_big.mask; i++) { + if (sc->rx_big.info[i].map != NULL) + bus_dmamap_destroy(sc->rx_big.dmat, + sc->rx_big.info[i].map); + } + free(sc->rx_big.info, M_DEVBUF); + } + if (sc->rx_big.extra_map != NULL) + bus_dmamap_destroy(sc->rx_big.dmat, + sc->rx_big.extra_map); + if (sc->rx_small.extra_map != NULL) + bus_dmamap_destroy(sc->rx_small.dmat, + sc->rx_small.extra_map); + if (sc->tx.dmat != NULL) + bus_dma_tag_destroy(sc->tx.dmat); + if (sc->rx_small.dmat != NULL) + bus_dma_tag_destroy(sc->rx_small.dmat); + if (sc->rx_big.dmat != NULL) + bus_dma_tag_destroy(sc->rx_big.dmat); +} + +static int +myri10ge_alloc_rings(myri10ge_softc_t *sc) +{ + myri10ge_cmd_t cmd; + int tx_ring_size, rx_ring_size; + int tx_ring_entries, rx_ring_entries; + int i, err; + unsigned long bytes; + + /* get ring sizes */ + err = myri10ge_send_cmd(sc, + MYRI10GE_MCP_CMD_GET_SEND_RING_SIZE, + &cmd); + tx_ring_size = cmd.data0; + err |= myri10ge_send_cmd(sc, + MYRI10GE_MCP_CMD_GET_RX_RING_SIZE, + &cmd); + if (err != 0) { + device_printf(sc->dev, "Cannot determine ring sizes\n"); + goto abort_with_nothing; + } + + rx_ring_size = cmd.data0; + + tx_ring_entries = tx_ring_size / sizeof (mcp_kreq_ether_send_t); + rx_ring_entries = rx_ring_size / sizeof (mcp_dma_addr_t); + sc->ifp->if_snd.ifq_maxlen = tx_ring_entries - 1; + sc->ifp->if_snd.ifq_drv_maxlen = sc->ifp->if_snd.ifq_maxlen; + + sc->tx.mask = tx_ring_entries - 1; + sc->rx_small.mask = sc->rx_big.mask = rx_ring_entries - 1; + + err = ENOMEM; + + /* allocate the tx request copy block */ + bytes = 8 + + sizeof (*sc->tx.req_list) * (MYRI10GE_MCP_ETHER_MAX_SEND_DESC + 4); + sc->tx.req_bytes = malloc(bytes, M_DEVBUF, M_WAITOK); + if (sc->tx.req_bytes == NULL) + goto abort_with_nothing; + /* ensure req_list entries are aligned to 8 bytes */ + sc->tx.req_list = (mcp_kreq_ether_send_t *) + ((unsigned long)(sc->tx.req_bytes + 7) & ~7UL); + + /* allocate the rx shadow rings */ + bytes = rx_ring_entries * sizeof (*sc->rx_small.shadow); + sc->rx_small.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); + if (sc->rx_small.shadow == NULL) + goto abort_with_alloc; + + bytes = rx_ring_entries * sizeof (*sc->rx_big.shadow); + sc->rx_big.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); + if (sc->rx_big.shadow == NULL) + goto abort_with_alloc; + + /* allocate the host info rings */ + bytes = tx_ring_entries * sizeof (*sc->tx.info); + sc->tx.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); + if (sc->tx.info == NULL) + goto abort_with_alloc; + + bytes = rx_ring_entries * sizeof (*sc->rx_small.info); + sc->rx_small.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); + if (sc->rx_small.info == NULL) + goto abort_with_alloc; + + bytes = rx_ring_entries * sizeof (*sc->rx_big.info); + sc->rx_big.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); + if (sc->rx_big.info == NULL) + goto abort_with_alloc; + + /* allocate the busdma resources */ + err = bus_dma_tag_create(sc->parent_dmat, /* parent */ + 1, /* alignment */ + sc->tx.boundary, /* boundary */ + BUS_SPACE_MAXADDR, /* low */ + BUS_SPACE_MAXADDR, /* high */ + NULL, NULL, /* filter */ + MYRI10GE_MAX_ETHER_MTU,/* maxsize */ + MYRI10GE_MCP_ETHER_MAX_SEND_DESC,/* num segs */ + sc->tx.boundary, /* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + NULL, NULL, /* lock */ + &sc->tx.dmat); /* tag */ + + if (err != 0) { + device_printf(sc->dev, "Err %d allocating tx dmat\n", + err); + goto abort_with_alloc; + } + + err = bus_dma_tag_create(sc->parent_dmat, /* parent */ + 1, /* alignment */ + 4096, /* boundary */ + BUS_SPACE_MAXADDR, /* low */ + BUS_SPACE_MAXADDR, /* high */ + NULL, NULL, /* filter */ + MHLEN, /* maxsize */ + 1, /* num segs */ + MHLEN, /* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + NULL, NULL, /* lock */ + &sc->rx_small.dmat); /* tag */ + if (err != 0) { + device_printf(sc->dev, "Err %d allocating rx_small dmat\n", + err); + goto abort_with_alloc; + } + + err = bus_dma_tag_create(sc->parent_dmat, /* parent */ + 1, /* alignment */ + 4096, /* boundary */ + BUS_SPACE_MAXADDR, /* low */ + BUS_SPACE_MAXADDR, /* high */ + NULL, NULL, /* filter */ + 4096, /* maxsize */ + 1, /* num segs */ + 4096, /* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + NULL, NULL, /* lock */ + &sc->rx_big.dmat); /* tag */ + if (err != 0) { + device_printf(sc->dev, "Err %d allocating rx_big dmat\n", + err); + goto abort_with_alloc; + } + + /* now use these tags to setup dmamaps for each slot + in each ring */ + for (i = 0; i <= sc->tx.mask; i++) { + err = bus_dmamap_create(sc->tx.dmat, 0, + &sc->tx.info[i].map); + if (err != 0) { + device_printf(sc->dev, "Err %d tx dmamap\n", + err); + goto abort_with_alloc; + } + } + for (i = 0; i <= sc->rx_small.mask; i++) { + err = bus_dmamap_create(sc->rx_small.dmat, 0, + &sc->rx_small.info[i].map); + if (err != 0) { + device_printf(sc->dev, "Err %d rx_small dmamap\n", + err); + goto abort_with_alloc; + } + } + err = bus_dmamap_create(sc->rx_small.dmat, 0, + &sc->rx_small.extra_map); + if (err != 0) { + device_printf(sc->dev, "Err %d extra rx_small dmamap\n", + err); + goto abort_with_alloc; + } + + for (i = 0; i <= sc->rx_big.mask; i++) { + err = bus_dmamap_create(sc->rx_big.dmat, 0, + &sc->rx_big.info[i].map); + if (err != 0) { + device_printf(sc->dev, "Err %d rx_big dmamap\n", + err); + goto abort_with_alloc; + } + } + err = bus_dmamap_create(sc->rx_big.dmat, 0, + &sc->rx_big.extra_map); + if (err != 0) { + device_printf(sc->dev, "Err %d extra rx_big dmamap\n", + err); + goto abort_with_alloc; + } + return 0; + +abort_with_alloc: + myri10ge_free_rings(sc); + +abort_with_nothing: + return err; +} + +static int +myri10ge_open(myri10ge_softc_t *sc) +{ + myri10ge_cmd_t cmd; + int i, err; + bus_dmamap_t map; + + + err = myri10ge_reset(sc); + if (err != 0) { + device_printf(sc->dev, "failed to reset\n"); + return EIO; + } + + if (MCLBYTES >= + sc->ifp->if_mtu + ETHER_HDR_LEN + MYRI10GE_MCP_ETHER_PAD) + sc->big_bytes = MCLBYTES; + else + sc->big_bytes = MJUMPAGESIZE; + + err = myri10ge_alloc_rings(sc); + if (err != 0) { + device_printf(sc->dev, "failed to allocate rings\n"); + return err; + } + + err = bus_setup_intr(sc->dev, sc->irq_res, + INTR_TYPE_NET | INTR_MPSAFE, + myri10ge_intr, sc, &sc->ih); + if (err != 0) { + goto abort_with_rings; + } + + /* get the lanai pointers to the send and receive rings */ + + err = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_GET_SEND_OFFSET, &cmd); + sc->tx.lanai = + (volatile mcp_kreq_ether_send_t *)(sc->sram + cmd.data0); + err |= myri10ge_send_cmd(sc, + MYRI10GE_MCP_CMD_GET_SMALL_RX_OFFSET, &cmd); + sc->rx_small.lanai = + (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); + err |= myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_GET_BIG_RX_OFFSET, &cmd); + sc->rx_big.lanai = + (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); + + if (err != 0) { + device_printf(sc->dev, + "failed to get ring sizes or locations\n"); + err = EIO; + goto abort_with_irq; + } + + if (sc->wc) { + sc->tx.wc_fifo = sc->sram + 0x200000; + sc->rx_small.wc_fifo = sc->sram + 0x300000; + sc->rx_big.wc_fifo = sc->sram + 0x340000; + } else { + sc->tx.wc_fifo = 0; + sc->rx_small.wc_fifo = 0; + sc->rx_big.wc_fifo = 0; + } + + + /* stock receive rings */ + for (i = 0; i <= sc->rx_small.mask; i++) { + map = sc->rx_small.info[i].map; + err = myri10ge_get_buf_small(sc, map, i); + if (err) { + device_printf(sc->dev, "alloced %d/%d smalls\n", + i, sc->rx_small.mask + 1); + goto abort; + } + } + for (i = 0; i <= sc->rx_big.mask; i++) { + map = sc->rx_big.info[i].map; + err = myri10ge_get_buf_big(sc, map, i); + if (err) { + device_printf(sc->dev, "alloced %d/%d bigs\n", + i, sc->rx_big.mask + 1); + goto abort; + } + } + + /* Give the firmware the mtu and the big and small buffer + sizes. The firmware wants the big buf size to be a power + of two. Luckily, FreeBSD's clusters are powers of two */ + cmd.data0 = sc->ifp->if_mtu + ETHER_HDR_LEN; + err = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_SET_MTU, &cmd); + cmd.data0 = MHLEN; + err |= myri10ge_send_cmd(sc, + MYRI10GE_MCP_CMD_SET_SMALL_BUFFER_SIZE, + &cmd); + cmd.data0 = sc->big_bytes; + err |= myri10ge_send_cmd(sc, + MYRI10GE_MCP_CMD_SET_BIG_BUFFER_SIZE, + &cmd); + /* Now give him the pointer to the stats block */ + cmd.data0 = MYRI10GE_LOWPART_TO_U32(sc->fw_stats_dma.bus_addr); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(sc->fw_stats_dma.bus_addr); + err = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_SET_STATS_DMA, &cmd); + + if (err != 0) { + device_printf(sc->dev, "failed to setup params\n"); + goto abort; + } + + /* Finally, start the firmware running */ + err = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_ETHERNET_UP, &cmd); + if (err) { + device_printf(sc->dev, "Couldn't bring up link\n"); + goto abort; + } + sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; + sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + + return 0; + + +abort: + myri10ge_free_mbufs(sc); +abort_with_irq: + bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); +abort_with_rings: + myri10ge_free_rings(sc); + return err; +} + +static int +myri10ge_close(myri10ge_softc_t *sc) +{ + myri10ge_cmd_t cmd; + int err, old_down_cnt; + + sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + old_down_cnt = sc->down_cnt; + mb(); + err = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_ETHERNET_DOWN, &cmd); + if (err) { + device_printf(sc->dev, "Couldn't bring down link\n"); + } + if (old_down_cnt == sc->down_cnt) { + /* wait for down irq */ + (void)tsleep(&sc->down_cnt, PWAIT, "down myri10ge", hz); + } + if (old_down_cnt == sc->down_cnt) { + device_printf(sc->dev, "never got down irq\n"); + } + if (sc->ih != NULL) + bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); + myri10ge_free_mbufs(sc); + myri10ge_free_rings(sc); + return 0; +} + + +static int +myri10ge_media_change(struct ifnet *ifp) +{ + return EINVAL; +} + +static int +myri10ge_change_mtu(myri10ge_softc_t *sc, int mtu) +{ + struct ifnet *ifp = sc->ifp; + int real_mtu, old_mtu; + int err = 0; + + + real_mtu = mtu + ETHER_HDR_LEN; + if ((real_mtu > MYRI10GE_MAX_ETHER_MTU) || + real_mtu < 60) + return EINVAL; + sx_xlock(&sc->driver_lock); + old_mtu = ifp->if_mtu; + ifp->if_mtu = mtu; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + myri10ge_close(sc); + err = myri10ge_open(sc); + if (err != 0) { + ifp->if_mtu = old_mtu; + myri10ge_close(sc); + (void) myri10ge_open(sc); + } + } + sx_xunlock(&sc->driver_lock); + return err; +} + +static void +myri10ge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + myri10ge_softc_t *sc = ifp->if_softc; + + + if (sc == NULL) + return; + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_status |= sc->fw_stats->link_up ? IFM_ACTIVE : 0; + ifmr->ifm_active = IFM_AUTO | IFM_ETHER; + ifmr->ifm_active |= sc->fw_stats->link_up ? IFM_FDX : 0; +} + +static int +myri10ge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) +{ + myri10ge_softc_t *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + int err, mask; + + err = 0; + switch (command) { + case SIOCSIFADDR: + case SIOCGIFADDR: + err = ether_ioctl(ifp, command, data); + break; + + case SIOCSIFMTU: + err = myri10ge_change_mtu(sc, ifr->ifr_mtu); + break; + + case SIOCSIFFLAGS: + sx_xlock(&sc->driver_lock); + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) + err = myri10ge_open(sc); + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + myri10ge_close(sc); + } + sx_xunlock(&sc->driver_lock); + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + err = 0; + break; + + case SIOCSIFCAP: + sx_xlock(&sc->driver_lock); + mask = ifr->ifr_reqcap ^ ifp->if_capenable; + if (mask & IFCAP_TXCSUM) { + if (IFCAP_TXCSUM & ifp->if_capenable) { + ifp->if_capenable &= ~IFCAP_TXCSUM; + ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP); + } else { + ifp->if_capenable |= IFCAP_TXCSUM; + ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); + } + } else if (mask & IFCAP_RXCSUM) { + if (IFCAP_RXCSUM & ifp->if_capenable) { + ifp->if_capenable &= ~IFCAP_RXCSUM; + sc->csum_flag &= ~MYRI10GE_MCP_ETHER_FLAGS_CKSUM; + } else { + ifp->if_capenable |= IFCAP_RXCSUM; + sc->csum_flag |= MYRI10GE_MCP_ETHER_FLAGS_CKSUM; + } + } + sx_xunlock(&sc->driver_lock); + break; + + case SIOCGIFMEDIA: + err = ifmedia_ioctl(ifp, (struct ifreq *)data, + &sc->media, command); + break; + + default: + err = ENOTTY; + } + return err; +} + +static void +myri10ge_fetch_tunables(myri10ge_softc_t *sc) +{ + + TUNABLE_INT_FETCH("hw.myri10ge.flow_control_enabled", + &myri10ge_flow_control); + TUNABLE_INT_FETCH("hw.myri10ge.intr_coal_delay", + &myri10ge_intr_coal_delay); + TUNABLE_INT_FETCH("hw.myri10ge.nvidia_ecrc_enable", + &myri10ge_nvidia_ecrc_enable); + TUNABLE_INT_FETCH("hw.myri10ge.skip_pio_read", + &myri10ge_skip_pio_read); + + if (myri10ge_intr_coal_delay < 0 || + myri10ge_intr_coal_delay > 10*1000) + myri10ge_intr_coal_delay = 30; + sc->pause = myri10ge_flow_control; +} + +static int +myri10ge_attach(device_t dev) +{ + myri10ge_softc_t *sc = device_get_softc(dev); + struct ifnet *ifp; + size_t bytes; + int rid, err, i; + uint16_t cmd; + + sc->dev = dev; + myri10ge_fetch_tunables(sc); + + err = bus_dma_tag_create(NULL, /* parent */ + 1, /* alignment */ + 4096, /* boundary */ + BUS_SPACE_MAXADDR, /* low */ + BUS_SPACE_MAXADDR, /* high */ + NULL, NULL, /* filter */ + MYRI10GE_MAX_ETHER_MTU,/* maxsize */ + MYRI10GE_MCP_ETHER_MAX_SEND_DESC, /* num segs */ + 4096, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lock */ + &sc->parent_dmat); /* tag */ + + if (err != 0) { + device_printf(sc->dev, "Err %d allocating parent dmat\n", + err); + goto abort_with_nothing; + } + + ifp = sc->ifp = if_alloc(IFT_ETHER); + if (ifp == NULL) { + device_printf(dev, "can not if_alloc()\n"); + err = ENOSPC; + goto abort_with_parent_dmat; + } + mtx_init(&sc->cmd_lock, NULL, + MTX_NETWORK_LOCK, MTX_DEF); + mtx_init(&sc->tx_lock, device_get_nameunit(dev), + MTX_NETWORK_LOCK, MTX_DEF); + sx_init(&sc->driver_lock, device_get_nameunit(dev)); + + /* Enable DMA and Memory space access */ + pci_enable_busmaster(dev); + cmd = pci_read_config(dev, PCIR_COMMAND, 2); + cmd |= PCIM_CMD_MEMEN; + pci_write_config(dev, PCIR_COMMAND, cmd, 2); + + /* Map the board into the kernel */ + rid = PCIR_BARS; + sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, + ~0, 1, RF_ACTIVE); + if (sc->mem_res == NULL) { + device_printf(dev, "could not map memory\n"); + err = ENXIO; + goto abort_with_lock; + } + sc->sram = rman_get_virtual(sc->mem_res); + sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100; + if (sc->sram_size > rman_get_size(sc->mem_res)) { + device_printf(dev, "impossible memory region size %ld\n", + rman_get_size(sc->mem_res)); + err = ENXIO; + goto abort_with_mem_res; + } + + /* make NULL terminated copy of the EEPROM strings section of + lanai SRAM */ + bzero(sc->eeprom_strings, MYRI10GE_EEPROM_STRINGS_SIZE); + bus_space_read_region_1(rman_get_bustag(sc->mem_res), + rman_get_bushandle(sc->mem_res), + sc->sram_size - MYRI10GE_EEPROM_STRINGS_SIZE, + sc->eeprom_strings, + MYRI10GE_EEPROM_STRINGS_SIZE - 2); + err = myri10ge_parse_strings(sc); + if (err != 0) + goto abort_with_mem_res; + + /* Enable write combining for efficient use of PCIe bus */ + myri10ge_enable_wc(sc); + + /* Allocate the out of band dma memory */ + err = myri10ge_dma_alloc(sc, &sc->cmd_dma, + sizeof (myri10ge_cmd_t), 64); + if (err != 0) + goto abort_with_mem_res; + sc->cmd = (mcp_cmd_response_t *) sc->cmd_dma.addr; + err = myri10ge_dma_alloc(sc, &sc->zeropad_dma, 64, 64); + if (err != 0) + goto abort_with_cmd_dma; + + err = myri10ge_dma_alloc(sc, &sc->fw_stats_dma, + sizeof (*sc->fw_stats), 64); + if (err != 0) + goto abort_with_zeropad_dma; + sc->fw_stats = (mcp_stats_t *)sc->fw_stats_dma.addr; + + + /* allocate interrupt queues */ + bytes = myri10ge_max_intr_slots * sizeof (*sc->intr.q[0]); + for (i = 0; i < MYRI10GE_NUM_INTRQS; i++) { + err = myri10ge_dma_alloc(sc, &sc->intr.dma[i], + bytes, 4096); + if (err != 0) + goto abort_with_intrq; + sc->intr.q[i] = (mcp_slot_t *)sc->intr.dma[i].addr; + } + + /* Add our ithread */ + rid = 0; + sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, + 1, RF_SHAREABLE | RF_ACTIVE); + if (sc->irq_res == NULL) { + device_printf(dev, "could not alloc interrupt\n"); + goto abort_with_intrq; + } + + /* load the firmware */ + myri10ge_select_firmware(sc); + + err = myri10ge_load_firmware(sc); + if (err != 0) + goto abort_with_irq_res; + err = myri10ge_reset(sc); + if (err != 0) + goto abort_with_irq_res; + + /* hook into the network stack */ + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_baudrate = 100000000; + ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM; + ifp->if_hwassist = CSUM_TCP | CSUM_UDP; + ifp->if_capenable = ifp->if_capabilities; + sc->csum_flag |= MYRI10GE_MCP_ETHER_FLAGS_CKSUM; + ifp->if_init = myri10ge_init; + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = myri10ge_ioctl; + ifp->if_start = myri10ge_start; + ifp->if_watchdog = myri10ge_watchdog; + ether_ifattach(ifp, sc->mac_addr); + /* ether_ifattach sets mtu to 1500 */ + ifp->if_mtu = MYRI10GE_MAX_ETHER_MTU - ETHER_HDR_LEN; + + /* Initialise the ifmedia structure */ + ifmedia_init(&sc->media, 0, myri10ge_media_change, + myri10ge_media_status); + ifmedia_add(&sc->media, IFM_ETHER|IFM_AUTO, 0, NULL); + myri10ge_add_sysctls(sc); + return 0; + +abort_with_irq_res: + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); +abort_with_intrq: + for (i = 0; i < MYRI10GE_NUM_INTRQS; i++) { + if (sc->intr.q[i] == NULL) + continue; + sc->intr.q[i] = NULL; + myri10ge_dma_free(&sc->intr.dma[i]); + } + myri10ge_dma_free(&sc->fw_stats_dma); +abort_with_zeropad_dma: + myri10ge_dma_free(&sc->zeropad_dma); +abort_with_cmd_dma: + myri10ge_dma_free(&sc->cmd_dma); +abort_with_mem_res: + bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); +abort_with_lock: + pci_disable_busmaster(dev); + mtx_destroy(&sc->cmd_lock); + mtx_destroy(&sc->tx_lock); + sx_destroy(&sc->driver_lock); + if_free(ifp); +abort_with_parent_dmat: + bus_dma_tag_destroy(sc->parent_dmat); + +abort_with_nothing: + return err; +} + +static int +myri10ge_detach(device_t dev) +{ + myri10ge_softc_t *sc = device_get_softc(dev); + int i; + + sx_xlock(&sc->driver_lock); + if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) + myri10ge_close(sc); + sx_xunlock(&sc->driver_lock); + ether_ifdetach(sc->ifp); + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); + for (i = 0; i < MYRI10GE_NUM_INTRQS; i++) { + if (sc->intr.q[i] == NULL) + continue; + sc->intr.q[i] = NULL; + myri10ge_dma_free(&sc->intr.dma[i]); + } + myri10ge_dma_free(&sc->fw_stats_dma); + myri10ge_dma_free(&sc->zeropad_dma); + myri10ge_dma_free(&sc->cmd_dma); + bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); + pci_disable_busmaster(dev); + mtx_destroy(&sc->cmd_lock); + mtx_destroy(&sc->tx_lock); + sx_destroy(&sc->driver_lock); + if_free(sc->ifp); + bus_dma_tag_destroy(sc->parent_dmat); + return 0; +} + +static int +myri10ge_shutdown(device_t dev) +{ + return 0; +} + +/* + This file uses Myri10GE driver indentation. + + Local Variables: + c-file-style:"linux" + tab-width:8 + End: +*/ diff --git a/sys/dev/mxge/if_mxge_var.h b/sys/dev/mxge/if_mxge_var.h new file mode 100644 index 000000000000..e4ce9551fc06 --- /dev/null +++ b/sys/dev/mxge/if_mxge_var.h @@ -0,0 +1,203 @@ +/******************************************************************************* + +Copyright (c) 2006, Myricom 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. + + 3. Neither the name of the Myricom Inc, nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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. + +$FreeBSD$ + +***************************************************************************/ + +#define MYRI10GE_MAX_ETHER_MTU 9014 + +#define MYRI10GE_ETH_STOPPED 0 +#define MYRI10GE_ETH_STOPPING 1 +#define MYRI10GE_ETH_STARTING 2 +#define MYRI10GE_ETH_RUNNING 3 +#define MYRI10GE_ETH_OPEN_FAILED 4 + +#define MYRI10GE_FW_OFFSET 1024*1024 +#define MYRI10GE_EEPROM_STRINGS_SIZE 256 +#define MYRI10GE_NUM_INTRQS 2 + +typedef struct { + void *addr; + bus_addr_t bus_addr; + bus_dma_tag_t dmat; + bus_dmamap_t map; +} myri10ge_dma_t; + +typedef struct myri10ge_intrq +{ + mcp_slot_t *q[MYRI10GE_NUM_INTRQS]; + int intrq; + int slot; + int maxslots; + uint32_t seqnum; + uint32_t spurious; + uint32_t cnt; + myri10ge_dma_t dma[MYRI10GE_NUM_INTRQS]; +} myri10ge_intrq_t; + + +typedef struct +{ + uint32_t data0; + uint32_t data1; + uint32_t data2; +} myri10ge_cmd_t; + +struct myri10ge_buffer_state { + struct mbuf *m; + bus_dmamap_t map; +}; + +typedef struct +{ + volatile mcp_kreq_ether_recv_t *lanai; /* lanai ptr for recv ring */ + volatile uint8_t *wc_fifo; /* w/c rx dma addr fifo address */ + mcp_kreq_ether_recv_t *shadow; /* host shadow of recv ring */ + struct myri10ge_buffer_state *info; + bus_dma_tag_t dmat; + bus_dmamap_t extra_map; + int cnt; + int alloc_fail; + int mask; /* number of rx slots -1 */ +} myri10ge_rx_buf_t; + +typedef struct +{ + volatile mcp_kreq_ether_send_t *lanai; /* lanai ptr for sendq */ + volatile uint8_t *wc_fifo; /* w/c send fifo address */ + mcp_kreq_ether_send_t *req_list; /* host shadow of sendq */ + char *req_bytes; + struct myri10ge_buffer_state *info; + bus_dma_tag_t dmat; + int req; /* transmits submitted */ + int mask; /* number of transmit slots -1 */ + int done; /* transmits completed */ + int boundary; /* boundary transmits cannot cross*/ +} myri10ge_tx_buf_t; + +typedef struct { + struct ifnet* ifp; + int big_bytes; + struct mtx tx_lock; + int csum_flag; /* rx_csums? */ + uint8_t mac_addr[6]; /* eeprom mac address */ + myri10ge_tx_buf_t tx; /* transmit ring */ + myri10ge_rx_buf_t rx_small; + myri10ge_rx_buf_t rx_big; + bus_dma_tag_t parent_dmat; + volatile uint8_t *sram; + int sram_size; + volatile uint32_t *irq_claim; + char *mac_addr_string; + char *product_code_string; + mcp_cmd_response_t *cmd; + myri10ge_dma_t cmd_dma; + myri10ge_dma_t zeropad_dma; + mcp_stats_t *fw_stats; + myri10ge_dma_t fw_stats_dma; + struct pci_dev *pdev; + int msi_enabled; + myri10ge_intrq_t intr; + int link_state; + unsigned int rdma_tags_available; + int intr_coal_delay; + int wc; + struct mtx cmd_lock; + struct sx driver_lock; + int wake_queue; + int stop_queue; + int down_cnt; + int watchdog_resets; + int tx_defragged; + int pause; + struct resource *mem_res; + struct resource *irq_res; + void *ih; + char *fw_name; + char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE]; + char fw_version[128]; + device_t dev; + struct ifmedia media; + +} myri10ge_softc_t; + +#define MYRI10GE_PCI_VENDOR_MYRICOM 0x14c1 +#define MYRI10GE_PCI_DEVICE_Z8E 0x0008 + +#define MYRI10GE_HIGHPART_TO_U32(X) \ +(sizeof (X) == 8) ? ((uint32_t)((uint64_t)(X) >> 32)) : (0) +#define MYRI10GE_LOWPART_TO_U32(X) ((uint32_t)(X)) + + +/* implement our own memory barriers, since bus_space_barrier + cannot handle write-combining regions */ + +#if defined (__GNUC__) + #if #cpu(i386) || defined __i386 || defined i386 || defined __i386__ || #cpu(x86_64) || defined __x86_64__ + #define mb() __asm__ __volatile__ ("sfence;": : :"memory") + #elif #cpu(sparc64) || defined sparc64 || defined __sparcv9 + #define mb() __asm__ __volatile__ ("membar #MemIssue": : :"memory") + #elif #cpu(sparc) || defined sparc || defined __sparc__ + #define mb() __asm__ __volatile__ ("stbar;": : :"memory") + #else + #define mb() /* XXX just to make this compile */ + #endif +#else + #error "unknown compiler" +#endif + +static inline void +myri10ge_pio_copy(volatile void *to_v, void *from_v, size_t size) +{ + register volatile uintptr_t *to; + volatile uintptr_t *from; + size_t i; + + to = (volatile uintptr_t *) to_v; + from = from_v; + for (i = (size / sizeof (uintptr_t)); i; i--) { + *to = *from; + to++; + from++; + } + +} + + +/* + This file uses Myri10GE driver indentation. + + Local Variables: + c-file-style:"linux" + tab-width:8 + End: +*/ diff --git a/sys/dev/mxge/mcp_gen_header.h b/sys/dev/mxge/mcp_gen_header.h new file mode 100644 index 000000000000..7cb449105954 --- /dev/null +++ b/sys/dev/mxge/mcp_gen_header.h @@ -0,0 +1,107 @@ +/******************************************************************************* + +Copyright (c) 2006, Myricom 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. + + 3. Neither the name of the Myricom Inc, nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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. + +$FreeBSD$ +***************************************************************************/ + +#ifndef _mcp_gen_header_h +#define _mcp_gen_header_h + +/* this file define a standard header used as a first entry point to + exchange information between firmware/driver and driver. The + header structure can be anywhere in the mcp. It will usually be in + the .data section, because some fields needs to be initialized at + compile time. + The 32bit word at offset MX_HEADER_PTR_OFFSET in the mcp must + contains the location of the header. + + Typically a MCP will start with the following: + .text + .space 52 ! to help catch MEMORY_INT errors + bt start ! jump to real code + nop + .long _gen_mcp_header + + The source will have a definition like: + + mcp_gen_header_t gen_mcp_header = { + .header_length = sizeof(mcp_gen_header_t), + .mcp_type = MCP_TYPE_XXX, + .version = "something $Id: mcp_gen_header.h,v 1.1 2005/12/23 02:10:44 gallatin Exp $", + .mcp_globals = (unsigned)&Globals + }; +*/ + + +#define MCP_HEADER_PTR_OFFSET 0x3c + +#define MCP_TYPE_MX 0x4d582020 /* "MX " */ +#define MCP_TYPE_PCIE 0x70636965 /* "PCIE" pcie-only MCP */ +#define MCP_TYPE_ETH 0x45544820 /* "ETH " */ +#define MCP_TYPE_MCP0 0x4d435030 /* "MCP0" */ + + +typedef struct mcp_gen_header { + /* the first 4 fields are filled at compile time */ + unsigned header_length; + unsigned mcp_type; + char version[128]; + unsigned mcp_globals; /* pointer to mcp-type specific structure */ + + /* filled by the MCP at run-time */ + unsigned sram_size; + unsigned string_specs; /* either the original STRING_SPECS or a superset */ + unsigned string_specs_len; + + /* Fields above this comment are guaranteed to be present. + + Fields below this comment are extensions added in later versions + of this struct, drivers should compare the header_length against + offsetof(field) to check wether a given MCP implements them. + + Never remove any field. Keep everything naturally align. + */ +} mcp_gen_header_t; + +/* Macro to create a simple mcp header */ +#define MCP_GEN_HEADER_DECL(type, version_str, global_ptr) \ + struct mcp_gen_header mcp_gen_header = { \ + sizeof (struct mcp_gen_header), \ + (type), \ + version_str, \ + (global_ptr), \ + SRAM_SIZE, \ + (unsigned int) STRING_SPECS, \ + 256 \ + } + + +#endif /* _mcp_gen_header_h */ diff --git a/sys/dev/mxge/mxge_mcp.h b/sys/dev/mxge/mxge_mcp.h new file mode 100644 index 000000000000..de85fde72cb5 --- /dev/null +++ b/sys/dev/mxge/mxge_mcp.h @@ -0,0 +1,265 @@ +/******************************************************************************* + +Copyright (c) 2006, Myricom 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. + + 3. Neither the name of the Myricom Inc, nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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. + +$FreeBSD$ +***************************************************************************/ + +#ifndef _myri10ge_mcp_h +#define _myri10ge_mcp_h + +#ifdef MYRI10GE_MCP +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +#endif + +/* 8 Bytes */ +typedef struct +{ + uint32_t high; + uint32_t low; +} mcp_dma_addr_t; + +/* 16 Bytes */ +typedef struct +{ + uint32_t data0; + uint32_t data1; + uint32_t seqnum; + uint16_t index; + uint8_t flag; + uint8_t type; +} mcp_slot_t; + +/* 64 Bytes */ +typedef struct +{ + uint32_t cmd; + uint32_t data0; /* will be low portion if data > 32 bits */ + /* 8 */ + uint32_t data1; /* will be high portion if data > 32 bits */ + uint32_t data2; /* currently unused.. */ + /* 16 */ + mcp_dma_addr_t response_addr; + /* 24 */ + uint8_t pad[40]; +} mcp_cmd_t; + +/* 8 Bytes */ +typedef struct +{ + uint32_t data; + uint32_t result; +} mcp_cmd_response_t; + + + +/* + flags used in mcp_kreq_ether_send_t: + + The SMALL flag is only needed in the first segment. It is raised + for packets that are total less or equal 512 bytes. + + The CKSUM flag must be set in all segments. + + The PADDED flags is set if the packet needs to be padded, and it + must be set for all segments. + + The MYRI10GE_MCP_ETHER_FLAGS_ALIGN_ODD must be set if the cumulative + length of all previous segments was odd. +*/ + + +#define MYRI10GE_MCP_ETHER_FLAGS_VALID 0x1 +#define MYRI10GE_MCP_ETHER_FLAGS_FIRST 0x2 +#define MYRI10GE_MCP_ETHER_FLAGS_ALIGN_ODD 0x4 +#define MYRI10GE_MCP_ETHER_FLAGS_CKSUM 0x8 +#define MYRI10GE_MCP_ETHER_FLAGS_SMALL 0x10 +#define MYRI10GE_MCP_ETHER_FLAGS_NOT_LAST 0x100 +#define MYRI10GE_MCP_ETHER_FLAGS_TSO_HDR 0x200 +#define MYRI10GE_MCP_ETHER_FLAGS_TSO 0x400 + +#define MYRI10GE_MCP_ETHER_SEND_SMALL_SIZE 1520 +#define MYRI10GE_MCP_ETHER_MAX_MTU 9400 + +typedef union mcp_pso_or_cumlen +{ + uint16_t pseudo_hdr_offset; + uint16_t cum_len; +} mcp_pso_or_cumlen_t; + +#define MYRI10GE_MCP_ETHER_MAX_SEND_DESC 12 +#define MYRI10GE_MCP_ETHER_PAD 2 + +/* 16 Bytes */ +typedef struct +{ + uint32_t addr_high; + uint32_t addr_low; + uint16_t length; + uint8_t pad; + uint8_t cksum_offset; /* where to start computing cksum */ + uint16_t pseudo_hdr_offset; + uint16_t flags; /* as defined above */ +} mcp_kreq_ether_send_t; + +/* 8 Bytes */ +typedef struct +{ + uint32_t addr_high; + uint32_t addr_low; +} mcp_kreq_ether_recv_t; + + +/* Commands */ + +#define MYRI10GE_MCP_CMD_OFFSET 0xf80000 + +typedef enum { + MYRI10GE_MCP_CMD_NONE = 0, + /* Reset the mcp, it is left in a safe state, waiting + for the driver to set all its parameters */ + MYRI10GE_MCP_CMD_RESET, + + /* get the version number of the current firmware.. + (may be available in the eeprom strings..? */ + MYRI10GE_MCP_GET_MCP_VERSION, + + + /* Parameters which must be set by the driver before it can + issue MYRI10GE_MCP_CMD_ETHERNET_UP. They persist until the next + MYRI10GE_MCP_CMD_RESET is issued */ + + MYRI10GE_MCP_CMD_SET_INTRQ0_DMA, + MYRI10GE_MCP_CMD_SET_INTRQ1_DMA, + MYRI10GE_MCP_CMD_SET_BIG_BUFFER_SIZE, /* in bytes, power of 2 */ + MYRI10GE_MCP_CMD_SET_SMALL_BUFFER_SIZE, /* in bytes */ + + + /* Parameters which refer to lanai SRAM addresses where the + driver must issue PIO writes for various things */ + + MYRI10GE_MCP_CMD_GET_SEND_OFFSET, + MYRI10GE_MCP_CMD_GET_SMALL_RX_OFFSET, + MYRI10GE_MCP_CMD_GET_BIG_RX_OFFSET, + MYRI10GE_MCP_CMD_GET_IRQ_ACK_OFFSET, + MYRI10GE_MCP_CMD_GET_IRQ_DEASSERT_OFFSET, + MYRI10GE_MCP_CMD_GET_IRQ_ACK_DEASSERT_OFFSET, + + /* Parameters which refer to rings stored on the MCP, + and whose size is controlled by the mcp */ + + MYRI10GE_MCP_CMD_GET_SEND_RING_SIZE, /* in bytes */ + MYRI10GE_MCP_CMD_GET_RX_RING_SIZE, /* in bytes */ + + /* Parameters which refer to rings stored in the host, + and whose size is controlled by the host. Note that + all must be physically contiguous and must contain + a power of 2 number of entries. */ + + MYRI10GE_MCP_CMD_SET_INTRQ_SIZE, /* in bytes */ + + /* command to bring ethernet interface up. Above parameters + (plus mtu & mac address) must have been exchanged prior + to issuing this command */ + MYRI10GE_MCP_CMD_ETHERNET_UP, + + /* command to bring ethernet interface down. No further sends + or receives may be processed until an MYRI10GE_MCP_CMD_ETHERNET_UP + is issued, and all interrupt queues must be flushed prior + to ack'ing this command */ + + MYRI10GE_MCP_CMD_ETHERNET_DOWN, + + /* commands the driver may issue live, without resetting + the nic. Note that increasing the mtu "live" should + only be done if the driver has already supplied buffers + sufficiently large to handle the new mtu. Decreasing + the mtu live is safe */ + + MYRI10GE_MCP_CMD_SET_MTU, + MYRI10GE_MCP_CMD_SET_INTR_COAL_DELAY, /* in microseconds */ + MYRI10GE_MCP_CMD_SET_STATS_INTERVAL, /* in microseconds */ + MYRI10GE_MCP_CMD_SET_STATS_DMA, + + MYRI10GE_MCP_ENABLE_PROMISC, + MYRI10GE_MCP_DISABLE_PROMISC, + MYRI10GE_MCP_SET_MAC_ADDRESS, + + MYRI10GE_MCP_ENABLE_FLOW_CONTROL, + MYRI10GE_MCP_DISABLE_FLOW_CONTROL +} myri10ge_mcp_cmd_type_t; + + +typedef enum { + MYRI10GE_MCP_CMD_OK = 0, + MYRI10GE_MCP_CMD_UNKNOWN, + MYRI10GE_MCP_CMD_ERROR_RANGE, + MYRI10GE_MCP_CMD_ERROR_BUSY, + MYRI10GE_MCP_CMD_ERROR_EMPTY, + MYRI10GE_MCP_CMD_ERROR_CLOSED, + MYRI10GE_MCP_CMD_ERROR_HASH_ERROR, + MYRI10GE_MCP_CMD_ERROR_BAD_PORT, + MYRI10GE_MCP_CMD_ERROR_RESOURCES +} myri10ge_mcp_cmd_status_t; + +typedef enum { + MYRI10GE_MCP_INTR_NONE = 0, + MYRI10GE_MCP_INTR_ETHER_SEND_DONE, + MYRI10GE_MCP_INTR_ETHER_RECV_SMALL, + MYRI10GE_MCP_INTR_ETHER_RECV_BIG, + MYRI10GE_MCP_INTR_LINK_CHANGE, + MYRI10GE_MCP_INTR_STATS_UPDATE, + MYRI10GE_MCP_INTR_ETHER_DOWN +} myri10ge_mcp_intr_type_t; + + +/* 32 Bytes */ +typedef struct +{ + uint32_t link_up; + uint32_t dropped_link_overflow; + uint32_t dropped_link_error_or_filtered; + uint32_t dropped_runt; + uint32_t dropped_overrun; + uint32_t dropped_no_small_buffer; + uint32_t dropped_no_big_buffer; + uint32_t dropped_interrupt_busy; + uint32_t rdma_tags_available; +} mcp_stats_t; + + +#endif /* _myri10ge_mcp_h */ diff --git a/sys/dev/myri10ge/eth_z8e.dat.gz.uu b/sys/dev/myri10ge/eth_z8e.dat.gz.uu new file mode 100644 index 000000000000..6f9f3104b659 --- /dev/null +++ b/sys/dev/myri10ge/eth_z8e.dat.gz.uu @@ -0,0 +1,633 @@ +/******************************************************************************* + +Copyright (c) 2006, Myricom 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. + + 3. Neither the name of the Myricom Inc, nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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. + +$FreeBSD$ +***************************************************************************/ + +begin 644 eth_z8e.dat.gz +M'XL("*B.]$,``V5T:%]Z.&4N9&%T`.Q:?6P39YI_/'$20]/8+8$8FH!)`B3A +M*Z709D]I-ZN"-M5""4FX"X6#=I7;"UUT2MO`F6Z(G2%!J*($+=DVW=*&U=*[ +MW*K=5CKVCC_HX1Y40B?`G,1J\P>GNEP:>:O0NL1@-QG/>[]GQI/8DW%*MY7N +M'RR-9M[W^7B?K_=YGG<\1-_A9_M[]W[][OWN_>[][OWN_?[__G=DNST +MG\>(8K+#':(WO*\?%PJF;2%R<&VW)2_Z)>:E8^1XR2U4WWRRBT-;_*HL*.B- +MDVTP73DQ3+X3Z;2^8G)?QEC(Y&SO%^H%CT)*SA9_ +MQSMD]RTFZ7)+@#Q+6999M2Q+]_/D^.W/`I(XM,W_^_&X=/!SLI]WKZ?S[NL4 +M['^<@E&%CCY/>>>C-13L5HGY!??4X'X;.*/D>9%HA&95]8%/2.=IB\FS:CYJ +M(V([\=A*CQ(7N8[/$Z,",AS$?6">")?V40'P7:#O"-E^XF?Z7LRO[B/7ZKTDLWS,F4[%;)!A^<&,%=:H-%\$*(G^IA&%&[_2BW<'E%?WWY+O+Y] +M+/'Z]JAO/SD2A=MO7VG3;.6ZT@9;)LNLTL\_J^L^>U!\Q-!CUM68Q +M'\SWA6P;6PWZ"]Y: +M7645`^-2P4?0[Y5Q7SE-R.3`\^$)44ZB>TO_XK]4NVH+*12LF.>PW5]8A84%D+O"/TXVSQ +MR:X$N9[J$;Z@THZY$[0YH8K-B:]QQ7!]*39EG\/]$[&QQR>"RC7@7"+1LZ5? +M08RR'Q3X`;(-WI%)B)PM9X+*'MJ5D!AG4/D%8(>V_+N&D[/EW[1Q]Y:+PK[E +MS$H_Y;(>*FP;5+"OE,]H\_Z(8%V"WFN4W\4YXA+F/Z3\*#E%-O,>9;X7P>OC +M)*\P\"(,9UX&'^81?T((Q@\JW4P35K*W#.&**]D-Y>)0PU^Q?45.0_7$!-NV +MH4Y(N6(<^U+G$P4-YG(:FF,RK8]-L!X-7DV/0PW_.*[IT[!/UZ]A+\\K,F7C +MN5\1&NQUT#5I=-T-_<+>,(@8R-J<$'ZV,6SN!__^H'<]B>R&0@R +M#8WK?/\$'CMBS,_>,`0^X83L@8U$?-=^DC8K-B7H/:+MT:"W'?/T(/B?`[\A +M7@/\P^#U&7BTL!RJ3"[PC*NZ?+%E?O+J\C6Z57MC^6IJLZ7&E>8'+9YNDMK= +M6(TY%\<1Q]#34:%B +M+<"+="6Z&^*@/0&T +M*5E.KS_[\NAIS'U(>5U"X=B]W-J""[2W%>?ET0]I9UL;Y0W[$*OB2XYED>^G +M33=5<:7M$G`FA.AI='.>V[1[3#Q].R8VW0S8$CT-\41VHT/-;BQ7>QJKQ:'& +M0=AKEF;SG,9_UOW;^$^8*]+]T'@&]D(<-5X,>O?`=XU:O(/W$/"'DOAA/4ZV +MO@(\Q%N30XLU^];#HGMK..@]K>W1H/=#VJ60)^CMIEW[%_AYKP:5]\`3>#U; +MX;OFRN@O.#:;RQ7D7$7+P:>U_:#'='-Y:OX@LB,=93N(`Z$Z)D=6@Y%/FGKI+F?DS.TN>*GF]S3DN.BS\GEVOK_EKD/)?K +M8RW_N?#\XQ,&/6P="Y'S.N<#JUP&_"IC[0SP>D.>#/70SO&9V"//^12(X*@)![TT:`+RS0ZBB9]NEL7U">0NY6,W>=A5K0/^B +ML[K,C>Y7,3]FWW8)O!Y@7I=!G^C9=@UXUT/TT[699`%MM7I'A'OW3;] +MJN#GH#=!`YCG=6/R`V7&>IEUVA;2:\,#W0*]4&"APL\];'NL'I#5-BFU3BN,]$K"5VN@KUC$A6BMD8"+X_32`=E<7\1DQ_,"U&Y +M%@MC,OUN3-JZ%7.>$%4$M#F)YF)<-8D#'AC7IM!L'9,J?X>Y)A--BXFFW1A# +MOE'//DVO=:`_B%N!#O@-:#)[1:]IM>JE#Q!$#9X#?9_`W +M8D?#U^,GK,?/G#.3."C-%SQ1@BW#\.EH,+J!T#O"IG,4CBEC36>''C?<(QIK +MAA`KG.M2XG.8U]+7*"@RU@#O88X?K2\&_R3=1=WN!>O3[5'0E&Z/@I94&QY$ +M;(9H3CG'L?6^;`A#ECD^50PC+MY#W-OYCEKW&=8]$^%<;-]=Q6.!9\OS`_)R +MXHX8[?T'V.TV%:(G6729;M#ECC_Y?7^F.:BY,=[CZ)'G!_TWH)/P#P`7N698 +MW_-SW3/M>='=Y(!"4^G +MC>7X;RT_@->`I/KY686L;\MJZP`N]5"K6WM.PE@.%>M;\I_,%_/^)9ESPJJ] +MR9',E6'H.NL&S1O$6!+2O(V_5R/21^W:41+GQ'F#%A>@\]!CSSN6')_0=!AK +M01\_;U!%7>4QGCO$6)ED/`]\Q3W]/.S_N8,9_3$I:^'?3A7%Y,)RK%^F^X3GL`;;XBO$VD2SUE/Q/-N3Y]4) +M-X]K`'=QK/2J>BQDJA_'.;=HN:+PF"G?H$87GC+V5_MBQ-DTHI^)W`4IM8ES2O3TRW$[ +MT_-Y5*>,?LM]3T"8MC9*ZM#034*_[D[]+C< +M%A#RN6K$[)!UG^%&_G.WZ3ER6P#^'1^A^5MPG\!]G<$ST*GQO(K]\`CS,LV' +MG5TT[E3\U=-A\^U"SEIC,5\$&XZ':'X]RY@ROU;(^6L9/\3K@<9ZSVX+O#2? +MW)#S:]#\&7DVK,N\X''3.MW6,L\_`9F_SB#S&ZO-;NFSX_Z +MWD",2J31-'9,^4.'+\AS]E/5]+46E`DY]Y$0+=BAQ='4?(TN`VPAL2V@!^@R +M^=&(?;9#3%YP!/@[C#J)>AAA6R5A@R98/`5V(0UV8'+^NC'_#;Z`_1_J8IIT +M'1]R6/O@(0]\,&'M@X=JK./FH2;Q2[+BM0=^F6"_L!^FV_^A(X;]OT&'Q`@5 +MK9N*IZ(N$Y]K&709A2X):UV*'-:Z%'D@RRG>W"56M1'73A?Z,(>.-\IX>YQQ +MW;^>%\GQ!17O`!^;>'.[R(]0+N,'O5\&@J@ZYSLB9%ICT'IO%B-W9C58S`_I +M[\P6YJ7OV>+(E+UA&]"DO.^=\9K9!PL_U>V_\.-T.18^:VW_A=[,]E_89VW_ +MA>^R_:%3*#T?+[PPI1/6`XV0<^;P^&YU,R[PMPW\&O5;MBW^2^@S7<<6D.6[ +M;\]"]&P2]^^+WD'L#&&,/G/QKU19ZDC:]I,1\BS6;;MX;[H]%IVUMNVB:[#M +M)]:V713)7#<\>=#_DV1\/\SP;V&W-#RGKM`._;FH? +M>-H8)[]-JTVI\IQP1JQBWG-:XQGE_PZH[FW(R>?*+VCQ+,;C^5)W:LQ[A@T\ +MSD$ZKN>Z>+.5&"^=]V*7;I_<)P>2^(QWUW9(Y[5#WX.+3Z;OP<7MZ743?@2= +M*MO0^RTZ!5GOVNXS[$G$3/6Y*MIGDBEK'34E>YK@I*;?>DR6U'#,A*FE/ +MWY,ES5-[$NMI>Y(>^#9["CU'QCUL[-.[M0GV%60JU?#1KU:SC:ZXB?_7\&&^ +MB_MGW59EIMZLU&-MJ])JV,IG;:O2)FM;E7+]]TVO'Z7=O'\@HX-IOJ#2/VIU +M9&R70'Q:U)'2TY-U9`'OG])3FDW&4$?Z*9=KRE0MJ;*H):51ZUI2EF==2\K* +M]#@N:TZ/X[*:*1_#3M]/+>D=H24/H)[[=7\L^<@DRP?6_BB["'_T6ONC;-C: +M'V4*[-X[W1]+"NZNGB^I2:_G2U;^!E?E^Q;`_#((<(QA6.A[IVG'LL +M\/I2\?B=+^->\"3(`C=@YID!+YR.E_ND]@X0<,9/UZ&\0(^U\M;T6"M?,15K +M2R^9:.K2:QKBY/O)!^=&J*)8SP45+YC6S-#_E'/_<\[:U^41:U]7\'NELZLK/.]I?5OVMYK5)!+9`/.N;*RE=_;.8NH*MBO +M\/MM%^/MZM#>YSF[.4Y+.$XKC^GU79#3.XGK,'!-/,]R/!MX^CL-OREW5(:L +M_589M_;;WQ7?ZNS4[A$12_\=W#[4UDD+/Z?EGVG\,<[O +MLO%_BY(X^/,A)YX'9!'OE<357EE<#2JWN$^936)<8[PCQW,=8)$9_B-S&.\F@=N>RN>@ +M/G?8>.>-Y[YOX&7(<]8DSR74NR-)'D,S\6`_Z?'%?EP1^:9W+/SN8816)L^S +M*TW]Q\HJ_1V:7F-V*N9X6UGOC%K%V\I6(][0LS'?WYC@A_6X6QD:RT[MHU=J +M9P?QH+ZO`#]LH@NDQ^7*JIG>1^JZK=JOZ[;:="Y8E3>S;JM66.NV:GVZ;JM_ +M8()K]7]L6@U=U3%Y;BSA_FG59:W?&M@ERCQ6_=:J=R?[+1W_A*;[`/JMD^:^ +MMY;.*^:>:]6H\X25_*OMR7S7,#W?K?;H?EGM3<\'JZO3_;*JQ437G.Z757E_ +M::[G0TM65I:499-L60!#3'R$%5=G>%=\L7$H=W'$.O\OZ[TKR\/2?Q? +M22>>C\KB(C_#UX*_H_F/6T/2"#W<@7IY,40/MT_S;?'-D_8L(0DA;$+_D3WY +MD(5+$C9-VRQ(GYMC)V=^GF/1PB+W#Y^HJ?9U=GB%JL2=(N7_E>ZC_5LK_'K] +MZ#EJ^5W'J[)HPSXC->?X5=]>DMX?#TGY4;*AIY;X>Y\;M&;6.CRO>4H]=/SJ%'\[,7_863JU("SIY^LUS[%^'V"`-P8\"7AA`\_RC+-/ +MA'M?)$K<$"KS?!:TWP&@,^MD_LB,EK5QCU-=W63WN&:6V5II\M<+_3 +M>\#0X7Y=QP.&#O?K.J;!5Z3`BW4=#Q@R%.LZ'J`4>+T)OM$$KS/!UYO@M29X +MC0'7=5SGLM8Q]^HPK2M(ZH@^M-;0@70=:PT=2-[2=:PU9'#I.M92 +M"KS>!-]H@M>9X.M-\%H3O,:`)W6,&CIFZJ]B\J/N$/U&ZY]4_HYB'Q%R7)S? +M2V]&U>-OH[2S=ZR=J;UZ[GET0^%[,;^?O1DB!ZIUGC)Y'];UFI?2H_[ +M:!_CB8.5#=I:G*^Q'J^%=7)X#5X3M/J:/4?K[[;>BIQGZIQ=+CY#-#L5FQ_Y +MJ?F8\4W%(\P9_FQ63']MCZ,+RLSZZ +M#H^]RG2W9#N%Z%%'28&6%V$+&^FV>.RY_*Y:ZM6^[QJE2%;ELYA[F&5(VC9/ +MP`>&/\2A9^OR66[(EA^U^=].D1MRA8[*D$V";-Z;Q.L$O9_Q>6J>]LV;UD=7 +M%Z3*.>63ZG4SRUD]2UL#5A.?.[_)Q'GV0YX<=C+*N5W77? +M:OQPUO$_"WE.99#G8RMY5)GE8;M6O\'T+`MH'$X%!1AV0HX^;+5N?M=)ELL2 +M)G@/=.K?`^[RDL`>$+R_8O(/:HU8=]H\6=IW%)(X9L7#V76,]\R36-\2CGCP +MP$YA]>#R$J>-?AC)6C[;Z56T;\[_C[CO#XKZRO(]W72WQ*#-.,1TC#.2B3/; +M,\],2)XSZR0FDF@2DZA@H@X:(\0U+E'$%A$;!!I:1++AAQ%UB2(RM=DJILI, +MF'INE5/E[G2>SBMF']+DK5N/ER(S'8<80DC2D188[>[[/N?>[Y?^@@T3Q[QZ +M?WSK^[WGWGONN>>>>^ZYO\X7.-U7Z)$#L$?,0_+NP<_.!FBQ[,-!Z_I^P)@6 +MS'_2<[5S5QSN#=`A.>:)A'N/B^JM/5&O7:26V`5PO1453K.P;>V)R3BE&&5\ +MQ/O(W/CR^LAC4\O!(]_B>.;[S3KT$64#[[_W>&HYT_&SD/`^=D>`'FG6RCRD +MURM`/_-Q/3@>/&MC&;)'R)01EN>TI.P,/^B@(=3MJ#G:QO0,[Y_3=O#'9/D? +MZX7WTDD^V/F-UA%Y?ID4A[-+[=H6R:1U^VF\RR +M[S2:H[F-7CQX:?.:CXJ]WK0=G'/_0S-?I^&AJ-TOOEAM-6CF/\^.E>V +M79&@H7_@>?NCS3HL7OY#L)=&O&0;V;^M!&EA2SX<4G/?1R^AW=9HWX$Q_3DL +M>AN&E0SCNX=U>D9DBJ\W2PM2LF.].$,:>"Y_NPK6$W/_Z3EMDBR-^7Z;%"O$U7Z+%7 +M$TP?48+#:]4W0OB>SU\QC5`C\G]$LBP/$,%.KHAPX-,!VS=A"NTV,=U +M$'P_!&,4TH50;U/4NKZ']PJ0-B2&/V^%#F);-3BS$C#K^MZ&JVR;SA.>8IJ1 +M'4XF_5SGJ:OZV>7'`F-C<1'R7Z4DR&8%Z/^SE$WP@,^`*3[PN:[%[_/]%%'T +M>7M],5FX_BWEQGH_G@SZDYE^K3Y!;=P)CG@?7Q&@.S,UV0B"+SU!II%M!=!K +M#]N%WQTVG*M^O%2G3,\OHSC(9TS"8WF& +MLA*81J1/&4L[E&7A^RM)6NF/CO:V.8KWP"92K=$P/>( +M94/:@_V8*X9%U%?T`>!+3OI#T$E1`?VXY-",08P=@SQWV[!0SI5L#:W^T7[J +MK/B`.L/^BG-7@Q:ENRR8IRWY-<=Y^D4T.])*DXTU/&?+"(L_*CV5;N%Y&]MN +M?X'>C:)Z_1^$<&"^MH/WE6#L.>G!$C(-4/I"R$JZAO=+#>_&J?"RG=F)/J7J +MM*,U`MP1VXX`^H,'^MAVA9YX!^6T=H6[B?M`2Y061+]TD#8_]'Q!Z748PY+% +M_CD\OGM2MY*\YU,>(9N_D/M'8QMP_.)W&"FX[T2$P_ROPP'BLYBPA1-Y#)I9 +M24N$V2[GY=$#=>WB0&,@:&T\J^:DZ\.&^:CU"WKB+IZ/"LOZSF:V<:P-%4%K +MO5M8-Z2->)]8'J`E.=SFM8AC6E#VOP2MKU4P+K2S*5H4:6_X2K]#]L31KL$1 +MGZAZK8+/CFIEV%'&J^+`:[")GSBCVDE^5W!\^(83XVUZL/DZWT%,;Q;>>;XA +MRVL5+SHJ('-/=`1,B=*.A@YQHMW;)]T?..&8[@<25SFE#-`RZW7;UHX;L"MN +M@,;K7NC;$UE)KB*:,T!/?B?LI10\R<%[<^\`WO2NX;!F?SYY5G@3A+C7859G +MS9\\8&]2LC+35$$L(RVP*32[`F.V78C_<)K9UCBN8,EL:\!65O;T_A_E<'Z& +M9;^J[)$6+6[_'%HPGN8G$]7ZVS*Y1E*WA2ZI$(;`'.$ZWB +M/H/V15ZF0]YC*OW2YW&AK^5?17]9.B.C/RQU9G8.!4\=IZ13P%5_G-(B4B>> +M`AECZ.U_1::J?0_/]@R1Y"IB4C>S/ +ME8VOI^=TB/L8N/^6XM0:$OIF>KM38GZQ[87NV:K(2TO(O5^+OL#/(OCEO?!.@3+]0OZL/C%6P! +MFX`>\KO_UN>E;B&XG1%Z"GFI0-^Q3T_P^295^T@'>PN?G>1(9; +M1-EVSQZE"K8E0M;&=M5WGJK"O$3J2::9ZP$X">KOFK<;[KF#X$ +MO+'^_G3[^05\-W5'JY*O9V;<;9H.O"O +MH2&`,H=L=3EJC?&9^7I;@(\VM2?Y]%.2)O!R2#BFW]_,[?[,"B,]&>&H1_7A +MISN%["=/=TXV%H)W"U'6?."`'&UHGM1.CJ4[.U6ZAE_1(F%;S_:+N;T\:#[P +M*UIPNW+$\QW&@S:9-4#+%]DQ9^"Y].WB_29HJYTMU_D]];,Q;J-->+V?]?Z% +MMT.T^R0E>CZB&?[P2LRUT@@VRZS&84II*:(D\.@/4G]@++L81)Z]SN2&8_H8 +M_>R.TL_)O"Q5A%,WRW#>`WGRG%DI[RWS.L1Y]W5*W4;S+M.SJS.0OZQ)1'F] +M'/.?I".8$W+^9LP/A:VN&[HNMUG7[;`3K[C)7%<$FV:O8SILXC1[2(T)2B<\ +MB_&=DC4=+O6C\"Y/!5Z+%G\Q`OM&XBVB^I8S"EPWGN>$K=W9DYXGT^ +M)T`;T_4YI[I?\WQAP#1]JCNRR=I](#-P0*\\_[:N?Q@'[-TG=Q?3W!?O2<3\ +MG0AI^>XGYE_/=^IS?7MENI0#GG^R7#28!=\#Y+L^@^C''6H])N&3R_3\I[%R +M5B2-Z3F4P?=]&+^Z7_:\C\M@&U#IO^=]D]F7H-_)O(UJ=J]_\!/%6STEV%MG`_A6?\V +M,&II**$%OA*95LYM@G=O'[D?\?`X\0!F=%V'G9IPDVAT6UU._2],N`R;,JQ9X +M3I)Y_)VY52OPY."!+;JJ#[E2\2S"TXFG8L2[*@O\K%%S^PQY!J^![3GKCD.J +M+HT^A!,Q1^O7ZM**<'*JAU*%M8[C4H3UR'+8O0ZF(6IMJ#'N8S).KAOF7ZW, +M)S'[_3%><3KDLW"Z*'"HL1?I@4-//\;7.7QW&^V%=)A').I[I"/>#,=[N6H- +MA_.&D!=\1=_-&+O_K-=K/^K#<2UR[3PC<^S.+,*K3A5=13 +MRE[&165KK&I5:Q^*-AX;QM%G-;3[',;QFENU>UV'5M<45==Z-W`R+YMN5S^6 +MWT=F?W.`Q[C%T>KZ=M:[_KDA\C='Z>)H/ZV*"M\5RMPAKE?0K=E7J^6957_I +MP_*.\A>T^BU_4.[7\K>\+\]KJ3Q6GL2XJ<\!HR5R[B/OL/H'@ZS;QN)$=5V; +MXN?JU7P&G&GVAY_Q,;W1JKHVIMWCYG%YQ,=],;6(UU56/P`Y%YCSM_TU]'O" +MXHN@M4[>?6THMR8N;1:^(5M]^XAW=>9[;B4W?PU>KGN+5O<`94K[]<$F.7]$ +M>'7-I'-ZR`&/CQB/_JSQHDLC25;O#5/8LN-0YRCF;D7_COGZ +M"](G1F=(VN_]S%NVT4XHWDN9Z@K]._DW=I`_W(%^V-@//>7#7+?5TRP +MW=@F%-Z'3O/8Q;ZOKA22.3M$9LC$C!$O98X,Y2:*(6>2J%K?%]F7E5K6)Z(K +M!Q-XW=)>?DV=J_"[^@EI9D9V.VN4,C/$?ETP;[]*:757:8'8[9AN +M#RK;4.XW7L+W5>CO`XUM)PI@^UTEYPF#[<>V2X8;\^R=3EZ/C-E^NYUF@PZU +MW*J>T'D=MM3Y;E0=6=XY2(3VJ@G0B_.O>U>?B=>^^OX(V\+Z&L1[\]48`GRN +M*6R(Q-AZPIK_O/5YW#JGFHNO"01,=YQ6<[*&B@O?BS"^UB-25Z^!#L]:H>9U +M'CE'%T6?MQXID?X\>I2LK[M#KLM7K>^]B'X='?Z\7:X=>JD"[Z0JX.DJA1S8 +M5M\RG;I&ECY:F\Y[!/)>RD#R1E%5YPMI-A'"F0(\Y#5!?*\! +M;35X9W&=A<&?*5^CVV&M6^V?,6^N$2?6EOW\1PA +M0:Y5%(DPKZ^/>-?VQ/9LUO;I=N&0I?[04%5]3SVV +MAKKNJ=CZR[8OTFQA/)/[8:G7 +M?.#\/,(V-+[GX5NN&^';@>_WM.][\?U+[7L.OM_4OK^+[V+M>S:^7]&^[\'W +ML]JZ7.(5RDI1\O5SV']KJA3_QF!K`O1!_H4&^%PM?56` +M7L@SP),U>+.^IJS!+1K\3(#2DV/P=>I,!/O!P9SW?.E"M/_/T?Y/=1O2#&IY +MT8Y/D0$>4/`L])DW4PWP2]_$_NK\),J)!SX*GHL%Z]4^ +MUR#;*_JZ%W!96689#\^+_(772CM?H2Y^->-?GZGT) +M%J/U?P#=6Z5/F.]&JE;WP+[I9_]%X2(1]!23!?`[5X6"M,HU(NHP3G6%KE&7 +M*T*>0?9%:!=\/J;LZ3F_4]N@VI,5]+JYNX +M/$]4?'2%-LB^P.?+Q8%+F?9*0KH-F;!)6]5S*7.R>J@^MJ%6Z8$7EJL^NJ%6 +M>-DOU89#T`59L(6SXN4OQ3SD1O7Z\#M;SYI3MW%;O.3VW(.Y(<98V`!-/!;S +M^-KICD`G;^`[6Y7O;@V:>?ZY"=]PDC9NR+$8X[T999NXW+CK69A3 +M1.[E=:EIHOQCFNW:2N:9UX1O((_,Y2$Q4/ZJM'.M%W/#Y'=_0.4%W"8O7>3] +M6K^[GY`^>8!>^M`^2F8\)M\V'D=?^HK'GP!M7,C^*GT%3P*V<8;G8[F/V\U] +MZ3*]U,]AR-(GPK9U^:^NCUJ57?72IYK>SD1[S07N_LED%?/&E"MYE(!WTA7: +M=-_8>A=MW`/8//;9E1WA^KM`2 +MZ0N,SYT(Z]H.X$N+6E]TN`I89C:E#9DI39WOW-BACQ,!P-4^PMJS_O`2G[KK +MM.FNB)FD;SR\+2C?PN6CC"9Y-LV]Q(?T:AY1R&<]/X:.Z.-\:>+`VB;%@Y?+ +MN!Y(UP^:Y_F;Y9I^@/=]H\.'R%?`9V->+@:=_;QW@;PSI%Z6\]VUHVH.MRY1 +MS7?7.3!G3!ZRKG,JWKS\GY!GZ1M-\??E?_9\BKFHZB]WCK/ +M]Q/%TKS"^GQSMK +MR/::@^.!*Y@=4;3P7A;"&R?S#\?^B]1:TJ8L_3X'[)0V/B>"?CE+\\4#VK,= +M\FS/L#C-YZI<)92`.IX;2^L6?T+Z>SF]]"LKSTADR[6:R[2IA]?F\)C`X]]K +M]5@4H.RTC`@Z&_LVQ)O#[`L3:?Z,M)CS;3JGIS7$5TP(IT\(IZ(^J2/>;*>^ +MC@?Y]M7*&=7)T;Y.I['6];WS:PD%_B<@'I]S+ZBNOH' +M"?K:+KQIY.\/*SV-.>KE^4CS*L#*<]ORMV@NG]^#7N@3YK1VY!G\I^O]5G_X`W)M(_,`Y=182LG2<(62,8<+ +MGP\O(K:OFV>1Y<1AHF:,7\T8]Y3/KYSD`#T[*O>Q`:\%'/,<"\I_U8P\^`;/ +M.3Z_A?VM4@KB-L9XIN*4#"5*&=7P.ADGYT$:]AMD +M!YU)X'T_T\KU9%^M"`^>?WN2<]>6%Y:'O7*]+BO#[2,_K"'>3[W8R;V`^[OBL(7'TD<5R,]M-%-]L> +MES*[6CZ@+L=_R')8;_H*AKXAW'6MMX*;QRJ_@XC/`Y7?0S,BP^P[=9Y0^WJ; +M[^$Q7.K7`^M[Y'FA+XABYX0^)E[O'/%NML3&^+'Y(>1@L]Q#CF"` +MYPZ0[8]X3((M=ZGEF.@\<4QT7Z$#5MAM/8!UU`,';+^@KX!IJ/JH9;:XL!\P +MU"T0H)>D?:[L24^'U,E7#;'-5 +M/`$9/,OR5W>5DNNO4E+9H(AV06;X3!V?V?#CN[-HE/YG\"O>-_!UY:"_]Q*A +MK`M).90"?.>$]Z%F87ZH%C1<>C?:87VWI-N:NHG'NE??46>)/+]7]JY'CG?( +M>TGIXHH'(+,8VR"Q:G["W[_19/RL\#[8SC@AQ];ST#?G\^3>Q2$>)]XMZ;"B +M?F:>#Z&_U*(?G49=VD>\6U.@BT/:&.##W.9T'?*@CK4K7Z%YF)^]K?I2^7N= +M_?T\[^I6\Z+RM3R^H1]U*GU1OIC'`8PM32=GBR-Z^XVM,0VR.IVS*&W8WZ]':/R=MB)VY?AR<*#5MD..=B. +MN=MVS-NV'\*#$7Q[*YXV/&?P0(:VH^6VHR9YP).7BF-^:CO +M3K!@)_+MA.;=Z<0#>G=FXL'HLA/T[FS&@S)W@L:=R+<3>7A9S@4:71A97*BC +M"_EA/KN09A?HVH4Z[0)M +MNV![[0)MNY"^`+@+%N!!^@+@*T"Z`O"K`/@*0'P!;_:@3?8`SQ[@V0,<>Y!_#^JP +M!WF+D+<(=!4MQX.V+T([%"%=$>2D"'4M0CE%2%N$LHK0?E``M!=UVHL\>]'N +M>U'67M"Y%WGV@O][._$@G1MRY4["`[K<2.M&O=R@SXURW&AO-_*X09,;]+C1 +M9ICL43%H*89<%"-=\1H\D*EB\*$8:8M1CV+4HQAYBL&+8O"A&/4H!GW%R(N. +M2R7@7PGDL03Y2U;@`8X2E%6">I4`3PGPE`!'"?*7@-82Y"U!WGTH=Q]HW`?: +M]J',?4BW#_.,?9"I?2AG']+N0UG[0.<^\&(?^%:*/*6H6RG**@4/2I&G%#PH +M17N6(ETI+*)2]%6^HUF&M&7@V3;TN3+06(:RRI"O#.65(6\9:"L#766@JPSY +MRU!6&?I9&:<'?64H;UM/XP!TW@!9JF`G!.B`7%OC_TD$H!?$9[G\;XF@]FV* +M?3L9/JK!S9R>_T?!Z25LNX0%-9CI9IAS+!V_AS[+36`<>GXM'-3S +M''9ROD'M/:J]`UP7S^`8[1:4U<]A_M;*X_]F!"?`3#?#G/+_&A/2J7KFP49% +MW1&V1#]3].M\FB3.-'F'^;']C/;NT-YM +M&G_T]K1J93&?K1/X8X29;H:-\<>83N=/4*NG-0Y_XL69)H^3_!DKP\`?"8O# +M'QUNX$]>6../`0_S(^^2]N[7WAWC^>.TQ,IR3I0?(\QT,\S('^=$^='JZ8PG +M/_'B3)/'Z?QQ3I0?"8O/'^<$^'&FR>,D?\;*,/!'PN+P1X<;^+-SL<8? +M`Q[FQ\X4[>W4WHFZ_F%:#'K#-J8W!E7_U_5<]#,9%YP09YH\SFG,-SHAGUF/ +M*]=T"/.X7-'-;6Z.;H^56Z[IDSAI3'\YC8$.0WUU_3Q9G:/&=HA3;V-\`+:4 +MKM=B^)6>9_R(7ZS"KBSM[=3[KY;>.H&6H%:6-0[_C7$3^6^(NXG_QGP3^1\T +M\,TZ"?_CI9G(_SAIQO%_K+YQ^#^NSG'X/Z[>X_F_*Z3KA1A^(_]WG5/A73W: +MNVT\_YT3Y5\KRQE/_HUQD_#?&4_^C?FFX+]S,OF/EV8*_COCR?]8?2?GOW,R +M^1]7[_'\WUTXGO_."?*_6Y/_W9K\[Y;RS_&1SW*GI)#:;S=DR_WPPWQ8<[2<>IVWA:_#@[3X,9=&YA-[]C>;E^A>W:VZ>]=7D; +MLWMDO>/83QK\)OOI9KC3F'[4D-YLY.M$6TZOCQ9_DZVGUVWR>$.Y6IFZ+,6K +MTX2X>)KW_ZKK34/8X>\M0[CA[ZV;X3?S4 +MTT_DYSC;+PX_)\9/Y.>$^''\#!IU8[PZQ>'G6+W&\W.OTVA+CN=GD38/V9NL +MWD7],7XZ)\KG./ML?+G.>/*IP>/QTQE//L?9BI/STSF9?$Z(G\A/9SSY'*M3 +M?'XZX\BGVVVT/[=J[YJ;]9O3%E^_ +M27@<_381[C2FCZ/?G+:I]9O3-K5^FRS>4.Y-^NWF.DV(FT2_,>]*SL;7;S*N +M1H5+-'Z6N&_6;V-E3]!O8^5.T&\3X3?QK]4(L?UP\UF*$?EBWB=RPOUZO,H;WEO*YAMCC7<$R[?;Y!DQWD]#FD[$+0Q0=OK$.,!7Q/9[%?R-8])O +M1U]7[R#O4-AY;UN8T\B_,42>#VDV[W?S'G?M;'&&[T]P/-/!^].;KCU'NW/$ +M:,MAHI999#G?1Q229PO*S^A[U+PGS6MZ?*XEMK]0?BE`.>V&/;^CPKM$U!\3 +M/M3U--_C8=_+J'.WL!W)5'L5GN]W-@5)J^/;O`\QXO7,G5A/O3Z\S_&7ZL1P +M/L_&]=#KQW6I.B;:^7P+ZI2(L&5W0(Q>V,)T>VKU^U0!*C]KEO>Q1#?3Q/1L +M<7/=/>UQ:)+[):C#QWI;(/TLI.V-M8?B$>_GN#;S>0^UCQ2@5^5]Z7K&4<3[ +M2:_^CGV^C>V3@F?J?(CG][RWA/02KNU%=?#>$V#R7`7O@8'>"Q=#1.QG@L^^ +M\A[^*!!NE)Y5K::V!]2!^^W-?P!\IJ==>?>,-WA>ES\Z0I57!->&F5_ +MQ,"=>H6\[Z/<%.WMP/LW>-^#]R_POA?OUY$^JJ5/0W@7X/]5>X/&BD&\,U'O +MGM3-#)?UR$3\>JW>G>HL3>5][%,`-+&/9#>?&0<^%](]P/@Y#FD^U/*PSVG@ +MJI2T:/O&"Q%^'>$G&`?:HQ#A8BZ+S[GPF1AU9Z[2-;']KM"VCX;DN:Q*OF\J +MP\BW5'NG:^^GM/#5,!G>"\SC5Z6E\HT6<4EIC\0DSGFYT\`/\>\U^$QOE>< +MX;8?@RO\C.\HS5!RJ>"UO-(;,]?-X1HOW#E!S:FW7G +MB'?_E@`E5FEGF'OE645O&O\?F\]IVNTF)S9%VN06)_7-G%TTFC?QG* +MNH@^U,JXD;^5=>/^(DK4_K%EX7,[?"^S\3#K^/*V"\V2Y[U#NQU)*#L0H%=. +MJ_;8WRK;+ASBMMMRA:J*T0^;4?]FA/,0?E6#XVU*YK>F3YI'O%5.U,')>)@W +M(6M=-]>C?A-9F'ZNAUX'KAO7PU[YG*R+NF^__Q#'`0_D?]-B14^5_*\X8%7& +M,_K`ERK]CU>]Z"B\C^[B?QMF1,0?^1^9G(?/[:GS1S/,R.N+G3]2\@:^H-Y5 +M/3'=]W=R'YC'A_M3*!5I4A`_JH]O/S["9UH_?]N?)]KGBTF^Q?G0CYG +MPGO[?&Z%S[P@WZ4K5+/V(FI3Q[YCO-,$VS/23WN$V`^HO=PMKF7P?T8*V$]S +MS2(^M^+YBO>J#U2-WZL^<"G^4YVJO=^>^CD(BJLWXHWT!Q=H?%HTXCW0;SC+ +MW\M]B<\K9X0]PA0F]I^"=E)^]'PE?-^S9@_3<\HL:@)4(WV4-@S(\S+)`\#O +M^9RL&.,^X_KYP]W44"Y&E;ZM?EF=_UG;K\XD5M>=SY7_/H=]4)T'WLIS[D=F +MBTO:F(,\!^394O:]AC;LU_KHMY&^.=:&U1O':"B@[_!Y-WM$^'B)"U],M<7Z:()HY2RM(SF`6](;_L&V=[5+CY7A+1)W,=XS`*L +M+R%$R1'0T&FO3"!?/I\W/=C+]=;. +M0E@0?M\PWD!G'Y3W$,1G#E+_>2'I*U#=M3WX:\A43P/K$H^#6)>,>`^V!4S3 +MDS0Y[U<\5O>K.+"0S]=Q&-\=[)_B).19V00'@SI/Z^1^Z,$U +MLF^`5DYS\IBXH/I/C4-/QW@X;1WBU#V(@\NR(R8N9QF7H\G8_T:>%;&^6"WO +M]O#YU%B?J\F+V90'ECT`^.W>+W#-I.3/$NG%A@;1>L@*A!^]L+)PE%*W':)/\BAA:01T +M)A%TTQOS^7[[^20>C]Z8SSA+FRFQM$_TUVZU)MY`.YV`G-Z9='?K#>!X+T?F +M:[]UVERS0=N_W!IMM5MBM-5N^89I2X[1E@O:_F'UK=%6]W:,MKJWOR9MIV^= +M-O?=H.WS6Z.MOB]&6WW?[="&.>K'77/E>:.DB_)\[QM?E]_QASL +M3_P?6'R_IL:V-W(@ZW.5S-=*WZ/1A#EMPHMQ)\3W+\+\#UJSJ-X:>G=XU"QL +M?V\Y==5"[PX',;:]T:S[D=/SVIO8IIY,9[_Q_M) +M^[00-?Q>ZO"(_6^1A>_0\EU8=0_6ECCBK1V[__H7^#=3\:_NH1C_:C^.\:_V +MEXI_M:TQ_M4=NC7^U?;&^*?R3LV_NF]-SK\Z9XQ_"MBG^W.U[?]GUQ +MS5=KU'MH2TO4QCXX3?B>#]MSR1=TZ)_IQ +M[RG).SIOWI%P#WV7_0/NAYW&WR/>-U-@IVR9RC^V/J='VO0QGRGF9%+_$VGD +M.XSL7S2DUD[>5/\TWG_O<4ZC?*IPNL.C[#-+2S=]@`Y_S+Y8^#ZAJX3N1/A] +MA!.T^"2$?\/E:O$S$/Z%'A;U%:3N.1VND3"5YUM(L\N09Q;"ZPWQ*0@_88B_ +M"^$?RGLY\G[N#>U^;J-3W<]M=$K_-E[ZFQ'OX44QV_QPDF:S6P#/C,'?#,=L +M^<.Y!OB@!H<]>KC"`._5X,F`-QG@G1H<=NGA=@/\K`;_%N`=!GB;ZKN'>_5_ +M-@"F^68['#3`:A2L$?/F9;'[L#>J$--G@H6E7?AGXPSS/(/BTP +MYZ;KY"\'$D,F)X[H^Z+'X'\KQBS_94,'^UE&M3=S:.RG<*6A@JU%J+" +MD!FWDI>CI:FQC +MGX%VZ"[IQRHR*GT9R'5&%YDQ5YXAOG2ROZXK[!-P9H@25X7LH^4AZ#Y>>PBC +MCE\Z9Y;OPGQT,$`G\WF^0?:1+W-G!;_,_79SE%+X7Z+-^916_P4M$#L=T^V# +MRJ?"IEW)TJ^B\#[7?.H+DKY4HP<:VZ0/A;U.]E?+>L?)O@3#.YUFI,ML-@O8 +MDD=[1.6T93%_V4=7Z/\D+XWY:XK[3Z<4Y*O1 +M>6DWZ?ZUC[JT\L[I_W5"WPQKL.[8^HJ"Z;+S#!I3$0K6H\ +MZS]]G==#@KX2]I5\K/24O(O.]Y=DN`Q]:<&(]UB>WI>4?_)CI7J_8WTD#C2> +MY?O7[(/5Z,/T=FD.T#'YO]#_%^,1VKX=SUD\/CP=/#YECU(ZY$K:.+K_V*CW +M&-]93+],__AL2]1"TG^$-\H^=-D'YED\/CP=>)2-]M_E_?)V8YS\MX'WI_S? +MLVY1:9'K&]'#*MT$&B"CC;E:.NDS8&8EI<9)ER"\;SJU=(F<3J\/^^I'>CV= +M17B/S=?225T?]9KCE6L5WG4^+5VR$9\AC2WJK3G#::*5%NDO`;A#2!_7)]V( +MMPGV_S\N4'JIZ31LGV;57P+T.V2.O2Z@UJ:;!!$?R;Y%_4%^? +MX'$5X;#N:U[YU'\KR>`_G\-S=?_YD_N"?VL'^\H+>K:8[F_A=1V$E6\C\06] +M)?WDZSY0C+X!XO_3)M*M3 +M_"_IJRR8$?&(5$\Z8"=>CP+&\$/ED$WH8JLIG7'UZ?])PS?&OX??EN-.D>AM +M&"#B?]]$^/\&!430C;!/?$MX?>?4@/3A;N9_X&RZ9J*6+W2?`,<7QGR+'$^/ +MM<_Q%7K[X#LK0(\,:M];`J;GT[1OS,<=Z;%Z)=C5^'(B5U@QKE6Q3Z_U_=J] +M09ORQ77\[0`U29]:W+9UYSG41\?LH/*[XX8<29)WSLCN7PWLD^8 +M'SH=N9&5RF.$]`L[HHT1H0!%1IRS3A91BCXV2)\[PY16-XSQ82_&!\T?HQH; +M5I]CWXOL3OMX5=>5?YJ28+QB%\U;T(Z^] +MC_]'V?C_<>%9;OC?4@_[KK>;T)?="8?=F+ +M(G&)_>L@7S?[@L\.FWHPC^K)B(AP=@1SQHCXA.]Z9T0^$=(?+]+67Y7_<^I@ +MF=V$MFQ!N&$;^WK_\H_9Q0'I8X?OPX(&:4=!/LJ!Y_?9D6FIZE[LR;E3^G&W +MW=\C3#82U7^S7-B2L=W&'E&@_^7 +MO6L/BJO,\J>;;G*!?MR0AA!"DC8RM6U,&;8J:Z5FK;&GUMF-6QIV73/+CC%! +MQXVMZ[A,C!$)`<2$:C`D5)FD$'FT;L;%1V)KP2PSI1-FQ1UVAT=KX2[C8*9E +M"%(,ZC7!T.G'_?:<>V]#0V@0N4`>_4<7??N[_?4]Y_>=PL-(Z0;YC2YBKZ".)+?3;DY'EOW:%CWJ`^J1(QI%H_= +MC7DZ.^:Q=^%G_5#_017:&(OOJY*^7VH'%LC4RKT:DU@_-*10+U86/QIM_"^D +M\53>*H_S$>/_2./;S<3]4ELQIV@H%*5[OG4>5JHIZ4:O+)^WC,X[0-^+QK]$ +MSIQ7B1R1>GB8T>]9BS);^L$E4,[`.+./[B'@\?)@V<-M\GXFKJ^*?;1W$/7[ +MH,\=2E\FZ9P1^?Z$]+Y7[FWD$NB[=(^K6-D#(U3:;&6)/-5-;L?Y4MX5!:U) +M`+UUWQF:7[HW$SZ7:9NMHG2N-/;],T5>;:W4G]0UOO\1Y.$^7E/TI/0_MZ.M!1]*]])H?CROF<4_[*;_CZ>]G8Z* +M.!_^'NV=@&.59\Y3[<75&[%WC8?R)O)/U!-A5RA$N84SREZH%&OC%7^`?)WV +MJ'HI$_&JG7B>Y*4[I?XD$>?2>5YXZ8TV^N_(#92;O_1J%_I4=HSGM]\$NF.8 +MO^,+\$7O.6;A.5IWQ4]3KQ$!<[CS\OX8-%>Y2>I)@G9J8)RI^E@!GN\T54MK +MJ]SDH-^8[=KI>H2X#?]-.,N!UN$2\7OS]$I9@JA++34[T$U:6XG&)QWGTE2]O1?E;PMRL&[G9 +M]OP@"`EF:5]!FJ/X27D_$>I'33(C/S'@2R?_[^[+]Q-G"?MY:9^EH`:_;\K% +M.:K(GPL)AFI\[\#?:AKO5X!Y)?I$_-SDQO$JO+Y6?-^&KW9\=>#+@Z\>?/7B +MJR]:_VF:>]ZU*NZZK<%U&/NWS/\N$:"3I,C1%A;/-6W#`#?7?(A=.P- +MPIE]0?)';N0:W&\'_A,:^I'?/8*\1'<1BG:P8+?7(^UE(?Y8XC,:Y#.FSI%& +MJ!.!JQ'!T+J[!\+K8?`AT/[@)C9&\\GY]\D7BLZ!-N0T.ZF7?H@SYTL]9B+Z +M$[*`PI,",D^B&F97_A`H/"D!QTVT-W.='RSX/KENC]R7,)1H:F6OX-KT(T_R +MPT9Q/_(DWT1O0E:Z-1_'PCPI$]_;Z@H@D_A1G=SK7^)+77F-(/6G1HY4']&C +M,+#?IJU1^GH&$%.2@YWP;#E%_CO1_'>G]@E:21;D?"3;..^;(D]A'Q.W#1-EJJ5;QB=QWL6NT%[:-HDQ_LL$F\H,!&TCUG(`MHWYXLHSLX#U45S$/ +MPROY:'>82]_33GR6]JI%?R=T%XY27QC:[S9-VL_G(FQ^4>%OH8/WM%#?R5!Q +MCE7N1_1\HZB[IW$V?+?E2?O9R#P8]1':;TNF9P!(#_5%,K[&?-@L\>"H^+[L +MB\!7-PV^NDG]QZ?!5ZI/E9NKO&@C&,^IKUDUYLDI!Z2^8J\\1N.DBUV7J%_2 +MWZ,OW$Q]V0U2[RWB]4H-B&0A/L]HWS3B\A<1SXN05J>L'WR?=63?9"ZO\'1+ +M0UB6BTJ]1Z_4>YY`SKXGDK._XL`\@6PUKSM(-2G6HIJ?\).?>$VJA9+M!BR> +MJN#!GI(@9\Z5[;CQGZ]T.XZ*W$M8QP*3;;GU[9<9L^EU)]2L>6QB9KN@MJS +M)6NT*Z2K?4*UF@/!.@T^&#`'(`Y-^"B'RLV^># +MD+[2770`^+N^!J@\RZB&+=">AK3'5?9>7">X5K;I_\`Z@IW2FMN%\G0YSN%Z +MA+CZLV"H.XNR[P2H/0NZ[L8!2.H#?L`3S:F>.I/DC-^QX;'H0W$5 +M>G9#LIA@+GG?-CJG^D6TWV2(J?CL:A?F727TF_3;U)-N&^*7?>@/K"L/#\_[M\76%OQU$N3$N2'M@9.>!=`^1UE7'@``=N3XHSL4U]"E`\!#I +M9T-R1Z$`=S\YL;Z*'@`^VPO043AYC77F?@1=#YT;7V=3UUC=SLEK;&/?U#5V +MNHW6&/)[+H0*ZTQC[#-38B]WZL1XY+7)?6&/G"[$^1W](:2\$U=JBG))2`:^R` +M^FML"72NG;O.W5MB.I^7SN/FKO.WWKB6=/Y7JT0FY>6)!A?EVW+OOK?OI/R< +M^N*%CZ5ZL1^X*<>&\#'5";Z`MRYAS+5[X>U[E7$+/8>*?,(R+=ZE(M4SVAAG +M:C^`F&U[4HY]\K/`;[_0G=\+HM-0M?TFX$3DC9CCMJ%.IGT>FSD-;4+3Y.K?GND.?CU9KOH#R?5:WY%/W959K/I.BO1)7Y+FCM +M8$UG`O<"K#OX7V`Y^->@N['Z=G]<&JPUM;*]#YT]]3;#IQX?8T6$9S?F]B/IK'"\W6S&B]-LMZJIY(0WX;EYY\NL:G +MN;$6XHGC48VMM>"[N':;/Q69#3"WR]FT5ZJYK45=:/,V@&D8FO?J<%[43Y_\ +M_Q#-`J[K/NMZ^,M^:*Y2M5X+87:@'MRSU?K`*<6?`[S5[1XG'? +M]4\`&[VWA\;WRR#?-@!QQ4]B?DI<2=MT(H"<7WIV#O.?4T5#>NL/Y?S';_%D +M#3Z&^<](E'QPX/)\\,#GH*U!?T/[<%(N9,JS`^5!Z&?YF_OL$`HX$OSH[S`_ +M$3?FHAXP1SQ=U*XGOB[EB#5@.HPY$N5*NSZ0]^NDVHY_O\T:W&];C[G.VG#N +M=/_G\[A)QY/NF4[-+W]*=?8L.1^+R+7#>7:]0_2_TDUR7W]X^78]F_I@H;B&3U7<:'8!IC3NZJ^`)V$5;U/JN/0WD>[?(A% +MBL>-N:Z`'-4[W;,7R+VU!A_P$74=1L];4&VG>Z\`M05@:3O9#J-CC@3D>AKZ +M9VX6+V-VN@`QPUR`]LPHQ&T/,E'K0CG,\U$J^ +M^0T7U8*Z\[U`-3[)-S]ERY!J0O^"F/D4WSQFH^<`N,X1],V'(C#['#%[BC#[ +M!#'[I2-P7,7U?UF$OMTZ@V^W7A>^_?KV1^_=$?-'5YL_:NM96']D7D)_Q,_@C_CKPA_% +M;&@Q;.@WJMK0),P>FL"L\!QB]IB,V8YS,F8=`XA9WI?L.<2@@C#;&8%964_5 +MWYZC72U8Z/5TG\9P+]I>+MIB@6R+A&,`,8H3GN$V*:)/W +MR/L/2\]4^*;_OX?"7+3'7+3'IZ5QLS&?^HN<`\*5_N^A!G$E3&F_X;:3'@G3 +MFW/L$*![0I(=MDIX$H[LEVB'B&LDGC6E,I[^,<3SJ0D\[W]$?G:$E;Z^)8QG +M<"J>/YZ"YX/3X[EQ`+2U%R$3UXN$JUANS@FHQ0MBM>HKRB]>W[7JCI%8K5HM +M7785QNH9:N4/W>WJYP\\S,)]XKX]]^$AQGT^L,1JU;$X>6WZ]AY+S+>KY=L_ +M.AGS[5>;;_]?(5:KOG9]^_7MCWXGQ/S1U>:/?E\2JU5?N_XH9D.+84-G5;6A +M29A%KU7'J5^KYB%6JU[06O4`^;7YU*K1KS;-UR\N?)WZ3=V5[!.O[SKU'ZMC +M=6JU='DN,U;+4"MW&,Q34Y/?,F(_QQ^%'3//4Z]$+\! +M#QH&P+@*W=YFR"N:@0OMCN!"PZ`CWA,L-WO#O.BU*;PH4&X>0%F;B!M%XT44 +M/R-Y$<:E*;S(,R,O.GQQ=E[D'YLNCD[PHG'?'8ZC#T^)H[MGXT6?O>-7/[<8 +M4B&&MESY,=2=?R7'4,57#4SQ54W7AZ\:[EN`&#H0&4.E7C'$]6;191?J+5*7 +MXSUB]ET-\7,D]MRZ:FOR\R95U^2QB/@Y(,=/(^:>=SLPU]PMY9HZBJ?EPY-C +M:7?OS\`T%"6>[I;C:<4P_:]XW'S](K@`M;L!RC&7_C[Q3+4[M>X37Q5Y +MZG48%\[?%HL+:L6%"QVQO.I:RZN^MBQ`7A51F_QV]Y`7MC:IUOWC*]OG7]^^ +MRK=Z0"O%^`>NH:L7[*[N. +M>MWF>&6@ZKVSF>I5Y8-RO"?_5/'HE'I51W/4>E7%(`#Z*GA.JE?];.;X_\/) +M]2KR6<$$.<:/UZG67L8!AOPI0D4.4*9QJYK/7Y:O +M?#L.L+#YBEKQ_\K.5Z)Q[.>(8W_Q#3DVQOK#Q+%[W_WF->%AV<:FX]9!XM;' +MY\BM%Z#^N^#K^Q/8_I"P[6'ST/[-?5K +MN$,TQU@9U^/5<)NC[MN%<'XU&+ +MR[CW"@$::"^GLL0M7GAK@'3\+.UUG,J$"Z@C_'S&_=]I/IJ+YJ2]K1OP>RP^ +MH:-XP3L6(TRVXMFE?JT%-8K,Y?]G?L/TY@-\=%_]._F:DW0S7;/Y51'7G\']?B'UHY:OA]:E +MM4##+A0[H%^3U+8I7T-[*+E$SM`N.@U-(9:S@O;\V?DU#T?/`U^Y!ZS4UYCV +M_A;*#6[C,R4:]-%9]?AB*9YJNN;?#`'F0AKXTVT0UX#?F0MV7DV2O-=K69*= +ME1M:68)AWOU<%;F%Z'(;)+E#G&$49?>*G)$CN3ZHFV8^B[,3[ +M%-D%DMTXHA=(?O1K6>)Q17[??.0W*/(;MK!R(\8I@Z"._,:LZ/(;%?F-FUF% +MT8KR;Y7E3_)&E]^8)07['_^^SJRL\K +M\O,HOPGMWZB*_9/LZ`-;T*>[(W5`\G?G;P'K/@U#7]/2KTF^ZY91#?@3#:Z` +MT_"."66D?5?-?;`,^8]#K#`)=(SQH27H-+07YS$A^RN`KD(!@IRAJ4B0C\T[ +M,/&=P`<1"\*F,_]C^)^11I#Q6/$+RK=HSHX!%QP]"]:[*^PR'BOL,A[)'107 +M$0\5[<*X170:LZ+C8=S2KTEY;`(/HS7`&6]+[$GR3H^'<0O%4L1CZ_1X)'EG +MQR/ESJ7#(^5D=#PL'AD/BT?&P[*#XK18KDZ<5O#(1SSR9L`COU^3&HS`(Q?Q +M*$SL6>Z)@D<^Q7;$PSD]'LL]L^.1^KNEPV/EYNAXI.;*>*3FRGBDC!!O0#Q4 +MX0T*'A@WC#/$#2/&C;3#$7BX$(]W$GMN=4;!HX6X!N+1/CT>MSIGQR/MD:7# +M(ZTM.AXK!1F/E8*,Q\I"XC&(AXKQPXCQPSA#_#!B_$C/B,`#XX<1X\=]]BAX +M^(C[!)RF*/'C/OOL>*RZM'1XI-\;'8]5)3(>JTID/%89B%I#2\>M5GNC,2<;&Q>!7EV-"'&NM9W$YUMI32X?).BXZ)FLWRYBLW2QC +MLJ9U,3C6-)@@S[(^M+@\R_K]I!:TV""\>3&PXO+MVY<0OY[XPS\ +M=[W"?]PLAX'TS_? +MR@X]/R3HC[CP,Y[I*UOQ'`OM`B<-XP6!WRVQ)IIEQL_Z#:=E9 +M)3$=6L!2.]Z99,?N*!2(EBJ[6BPCQW[2[3GW/7U+),CL9_S@^KUW[GGWGG-_ +MYYY[I7?N%28;IIV8[)A:,'5A.H)I0$U#F$YC&L>$9:RYJI2W)@C"(WA^Q(II +M*R8OIJ"QXR$O?R\FK+Z&\BSS(B]39`]XX1\")#O1.`Z=H`GD339RGD.OC41T +M1AM=SZ_T;,;K.O5Z"_W>'K:'Z&J[`E>$K^@P;TYJ,K(K])P(8K0..D?R)NUL +MP&1".K:?6C:V+>LQC'B%-?6XUHUX8D4E^Z6%ZM_45'?O.: +MEZ,>^0<8Y^BWF.?@L@+`([&&!S%ZH$% +M+@4F0=]@9*T!YG-B_YT(CD/K)Z!ON09%;38VYY8G8<*.*3B-/N,RIG&*6=)4 +M!P,4$Z"G=ZUNQS6X;)N$@U-,G@C^&&H<`6/K;M"T*;2:F066FQ_:_LRMO.0%["]MT2.>6RE])ZX.`CNH0AZ^@GR5>BOVH\I?J9 +M"/*>(CK2W/X`Q1K$\M@QCT5Y1VKIX[_ECC*[Y3]WD;R1`8^%9'"RYR(_CP2\"*ST6\A%'V_*T7QMBKIE5'ENHVW(D^AXV +MEW))]U.J[FBC?J*5#O+8"KRWC&>+0<`^V8YZET?;CK>3'(`:'%OL;7#?#6'M +MMR?DFT!^&WUR^YW)MG:,ZJV1?\GX[]L*:SNJL=SH&$#UT6=7DCN7\F^CCRF[ +M/H^6Y*[/HUW)^CQ:^QO21[J-/N'<]7FL+EF?Q[[\&]+'FEV?QR[GKL^ZU2GZ +M_.K7K4^2OSML',GL[]9]_\[]7)9^79']H,ZI-]-\%&^_YC#IZ[O(XZ\IL=Z4K[MSNK)7)=F=].FYWUK4Y +MV=UA@VIWI;-I=M=CR&)WI?_%[:[7<(=VI\C/[4YG<*2,LZY0=VDP-[M3RDVV +MN]*Z9+NSKLMJ=UVU@P&=L9]BZ=#/Z6\(ZZ&FE84H_I+EU0ZRS@T0ZH1R'FL9 +MLNA9_G/7V8(9$F(M5U.&015RTS:-^";I-_4'IUF-H4.RW +M[)O#[\'P%=`X7T+_X+T`;LTM:,7/!VXY".'_Y?&\0FBF +MT7"Y\0R<;`/M\0CH7XP]?&V%UNB@ +M=184*[XCF&5]Q2R($PX?QQ8_8^C2UE@T01'I$"XPN-@/<4R>!VO?/*R+'$2, +MU1CN4U%LYT$3/H0VA/:!UY:3K\)JPI_B@5'>U<0[83\#U78CB_R=!4[];1SW +MA8,6\;AJ1PLZPRCI@?/]S6_?FA-9@='V=G-`Y+K8D8ZZ95LOTC*5'LL>72-* +M:TFBZT2Q+?G:$8I=?SMR(:_O5=2)8M=_"'FD8TPW,4$WM-DAU.D$ZD;QSSNF +M33P6FN*%>)SZ_REQZA2C'ETS4WH +M`P/NEB`X#X"6XG/=\BS9TH83HM(NX:YGSU)L?]A9+T77ST0TSY[Y+'RK[4Q6 +M\279#!3/[\8QA^\_UZ;@6^B`#:S[=OC^8"X!7TT&?#7$2W'>V?#E8TDO]J-> +M_2#U.;3?!J:I'71^"BM;(^RCZ\*39_EG?-I_\U-\]A#Z(G$#L/U<)\4?I?LB +M*3=?A/ID\T4BRBRR4:_PY-C=\$>HZS]G&V<66_8V2Y@MVE\.>*1M%MG+G&;# +M>O@>8D9[NE8Z0#\_ +M8S:\>WP@'OJ`[+](O2K)ED$D%^V&"(K/5+?+O25'S'&7JY?OD-> +M]M`W&MF3SEGL0S,XYG6CG3G-<-GOH;Y\3Y7?.-?J +M9Q$G_TYHFJ^S<0=\@#9C.'X3BA;V-MX;F&F\[[C:GX::L!_=1/O;B_874->7 +MS9J`]Z5NW9[AFXKM47_BMH?]93BAO\A[+>(0^H>#SX'X_9_=LV@[B2`FE8@# +M81(IT(\X(XA+`^C?:@J(A,L"JP<]REUY]9=L_F.S(1PR:\/[S7JF-9S9WB`( +MUUM`E,5WQJC?D0\\]2I8W!_,P?(6`0@?5F"0(CK#F06=?I3I]!?".OTY6:<_ +M&^[5C\G[+0;Y#<2N&30L5+]\FV7.NQUQN]SX#CAW(UYAVD-W%@@SCI<\#4=N +MJ7A]&_'"/*/0SG':$=9RG^O:E3M>0X37C(+7B<7BI?J*&%[3(![_Z\7CQ?L. +M8D2X52%N'"/L,XB=MZ91P2V*%V$3Q4Q6,:MJ%`0^!OKF("S^2$.^NA"Q,OKS +M`NA_@X0?WY/XL$%"G&3"CO46:A&WP$*O?FXAE(#9?L(LZ*WDF+T7ZV/4CV*8 +M.>*8&3K:(=K/#,$\BCN(][-=_[HXW-1^-J3B=N)F=MS"^;H].'^Y;3];F+&( +M)SJ5?G;\KWZ=N!5*.>!6%\=MN1?QV9",6^$6%;>*L*[0NM!;N#D=-W^.N"WW +M+N'&<6O(`;?3<=Q6>!"??2FXM:BX]2!N=L3-D8[;5(ZXK?`LX<9Q&\D!MV`< +MMXT]B,]8"F[G5-QP?"L<1=S.IN-V+D?<-O8LX<9QRV%\&]L:Q^WY>)YR[7?__GC_]R]^7X5XB,?QC$,<7MKETP%KF7,"MT$%;\P_Q,O&?&K&OF968$I'R4NO6 +M*GS_6(Y\Q3P62)5/+3O*IU/X>L:03TKD8^\ER-B]D7@+.&^'9G427[XBHU&0 +MP.@0Z9IXEW/>_+)B+-?"Y11!$VTC5J#JE1_CUT?;()$/RZ1Z7`GE%BKRCOFP +M7&LJ/_$R,<9K4'D'D'=#DLSWJO6+_#TE\5(?V1R3(=L>`R)]Y[BI4FV'+4GM +M*@C>X6C[=V\BFUBA\I4KI[S(:TOGE98E\/Z1PKME$'GKTGG+$WG-"N^?VI#WA73>]D3>^Q7> +M!/+7:7P?LV!O!7IO!Q3E]HGB?\!A7^;A/SU +MB9@E])<'%9Y-0\C3R,OLT.S)U-=#W=^XX(5W&O@>`)U85R>;.XJ)]I7`N8W+ +M+5^'"?DJN)II#X'M:Q1[TO\ +M0I4OVWX$2MQ7Y3#%<`>K`>IB><_S74:KH#(<#VXFN9) +MGS#Z9SSC*?5ZBLF[#/PS(S"-&RE@U]_K*\PG8_E4=TO/81C9[# +MIX@]>!-`63RB[T?!F_WWW8A/T=Z[@T"+3G +MB?7U8RQ(N`VL8@')J8,K0M4`[>O@_!2Q;&6^$@=8CQYC`=??S(-?J&K17P6! +M]IH8.L;\)U0UH>T\,?U\/Z(A_;\,)?ZP5JZ!UZD.MI^ +MQ;B.:CVOE.P#J_,3O#]X/SSNAV>H/FH/GN>`O^1Y^^^G>#@GTO:TD3QVV!27 +MI_(3DH?B*!6]JSY<=Y7B0*L^&(IP_7B]DO-^JN\LWC\3U0O;>(K7$G&4CMCX5&Q:E3AE6\LX?!42,"4YW;,H9^H;B=:)OLDWT!VH>P)9'MSKYFQ<6DS[#U) +MM*>)-D1Y&7WD`X!]J[90^A*=;;/N]J?03FTH@ZU'>3]=R^=5[\L4VUJK2:23 +M7N]#&3TW-X'/89[W_6!V/X9U2=>%VN^0O'BMIVL\%ZCG0O6L4\_+\B.4N"W8D\%Y4Q#?YLBMQEX]BT$4OX^JO +ML&9BC;?/BOXH*7/^*FW*_=C=$G?IN+/C@0ZU0SP46)&6F4JC^WQ)I:UX-XT_ +MC88?=@%&T/['%R_ITO&%/`18]ML6X0_X8(J+1C_,3_2/Q1PS4S.82F#JQ1V. +MX[<9<-,."1-]MT3C"WT.>`+3@[=[H!W*S?@'_]N@G-\W+-&7Z$OT)?H2_0M! +M=ZETCTKW+M&7Z$OT)?H2_0M`%P0!DW(%&8Y4JJ`>L7OXC.?3RDM^/O4@V38H +METX`Y;M*IAPR0,\80*\?DPW@<`_`]XH!^H8`CKP`\-J46L3@MKH*:?WCZQ^W +M2F56Z\92:QG^EZP;GWIBXU-E5NF5`TV[UUM??DG:M;OIE?TO-KV4393%'Q*F +M/XZ`T@H7S0#_L1/@WY'Z;C_`OZ$N'XT#>$T`4Y<`/M@"\-\-Z;2?:Q5:Q`ZP +:H`>XA3R!"DX3\NT@B'.)5?X_S^VI\1AH`0`` +` +end diff --git a/sys/dev/myri10ge/ethp_z8e.dat.gz.uu b/sys/dev/myri10ge/ethp_z8e.dat.gz.uu new file mode 100644 index 000000000000..ad582bafac86 --- /dev/null +++ b/sys/dev/myri10ge/ethp_z8e.dat.gz.uu @@ -0,0 +1,639 @@ +/******************************************************************************* + +Copyright (c) 2006, Myricom 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. + + 3. Neither the name of the Myricom Inc, nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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. + +$FreeBSD$ +***************************************************************************/ + +begin 644 ethp_z8e.dat.gz +M'XL("*N.]$,``V5T:'!?>CAE+F1A=`#L6F]L4U>6/WZQ$T/3V)1`#"1@D@!) +M^)=2:#.KM)-109-JH;`MS#!QE@";7:4=M./2E#5,B)U'DD$KVJ!IIM!M2M@= +M*F4K.D5:1LL'NJ0+2'R`F-4RFGQ@59=-HTP5P"6&N,FS[_[.>WZ)_?*]"_NCWZ/?H]^CWZ/?H]^CW__.[)UGI +M/X\2C]1U[6RB8MH3([N)[XJ)?8UXZ2O;772+NGT=6T5ZS,RX+"OJB +MY)Y/_EMD]T4DHK<.D-WO%=&@;YCZPL/D#XNAH'*?FN^3/:CB71OGOG[\:BTJ$OR7K1M9XNNFY2 +M\/BS%(PH]-:KE'TQ4DG!UC@QO^">2MSO`V>8W'N)!FE&>2?XA#2>EE%Y1N6G +M7B*V$X_-]"ATDO/MN6)80(9#N'?/%4-%G90+?"?HFT*6K3N9O@/SJSO)>;8Y +M;.UX1PP[?&1Q'R";0R$+=-C5C;FB7)7F3(B>ZV0:D>?Y*I[G"<>/>>Z)8YZ1 +MV#%/Q+^?[+$\S_T^KVHK9Y\7MHJ1_>!M"X +M@&Z1$7FF'7I91^696Z%7(*%7)'B2Z"*N#!]9-9J9YS7]9T[HCQ@Z'/$W9#`? +MS'>&+-NJ=?I+OBIRG"1+-Z_[VVI+@D>E%IN/K4]:__'$^C?T]0\EU@?L"8=+ +M7_\Q5*`Q8*[OR@@68+*1BHB*^Z55-TF1H/*6N`=H1_;Q&=U +M,7*^T";\0:41PY#I.&@_5#29SHUI?/\= +M/&I'F9_5C`BE+\+PM?2B5Z$QF0)UBIWZO!]0S.H98OOU13HQ_DB5KR]2#[QP2ZS5 +MTP_:"Y`SOL-KI;^TB7"?-\+\_)B+;6H0H?%VHFL-UT`#66)BW&%1,AR^@.W: +M\%G,?4+9+4+AV+W64(\+M/<5Q[7A3VB'UTO9`W[$JKC+L2QR`K3I=EST>:\" +M9US`'E'.&1$OWA\5FV[W6F)MGOZ8S3,4M]7:XVVU+M%>>QCVFJ':/+/V +M5YI_:]LQEZ_YH?:X:*U%'-7V!'U[X+M:-=Y%6^TYX)]+X%_1XF3'J\!#O-4. +MJ;%FW=$@6G=<"?K.JGLTZ/N$ZA1R!WVM5+=_?H#W:E#Y"#R!U[8#OMLU,_)+ +MCLU==@4Y5U%S\%EU/V@QOG#^(K$A'-CM1)JXLNYY/1F7'V1#]3*T!>.X- +M44VMFD.13[S--.=+,[&\WW.:8EQP9?D=&[;7X65O.?$\\_ +M[M+I8>O1$#EN4UF3_1- +MS(]8=Y\&KUG,ZQKH8VV[SP+O9HAVKTTG"_SNBC\00QW[)N3X?//^N.#GH"]& +MW9CG=4?E6<7Z>NEUVMVKU899K0*]4.]"A9_;V/98IV<$<<9UF&L8^J8H>/I" +ME.=5:QS7&&4#QUQ/&OZYD_QS&Q,\SPGKWO7-FMS1YH@88MZ]S?=H`#BHT6'1 +MNK>"ZU?OOC&>>P.]DM#DRGUC1*(\U-9P[X$Q&FRB#.XO1N4GLD-4HL;"B$P? +MCDC;MF'.':+27G5.HCD8ET_@@`?&54DTVT:DL@\QM]5`4V^@:=3'D&_8O4_5 +M:QWH3^(*)-8];N#18^!QSD36JP::FP::X:FRSJ94FMG.5)K9;GVL]1A4CKFU +M!IKU!IJM2>/9&$_HS[Y&WA;@0_Z#:@P>UVK:?7J]2401`\>!WZGSUV-'Q=?B +M9TB+G]GG)G!0FB^Y(P1;#L&GP\'(!D+O")O.5CBF]#4=35K<<(^HKQE"K'"N +M2XK/`5Y+6R,W7U\#O`^H=9>Q[KDPYV+K7JY]EP6>3<\/R,NQ!V*X +MX^]AM_N4AYYDT36Z1=>:_ACP_XEFH^:.\AY'CSPO&+@%G42@&[C(-9>T/3_' +M-=V>AQV'()S%>[H_1'.Z:\/_BP):7SEG)_-*(T,_GRMXSX-7S-UL83G^2\T/ +MX-4MQ0/\C%H_=$*.-W3CBK=[H^IS`L9RH$X.F?*?R!=S_S61YMRBYHJ\HX9\@QJ==TK?7XV+R=7H%J;^2IPU(V]C?W4B#US, +M5VE#$W6&SZ&R%B\#Y%K'.G`-X)S"YTV<3SZ,: +M?5XDW?X=R=Q;SG*C/W:#%^(][YS1;\GO$1##C@XYWA^,1^`_5Y,6E[M/"OE" +M!6+6U&;@B_SG\FHY[CN*_3>?8VJSRO8S\\Q;P,\T..%AIS +M*(&*J;!Y5B%GK#&9SX<-QT(T;PO+F#2_5L@Y:QD_Q.N!QGS/[C[Y^CQR0;YSQK6:367>5X79/XZC +MLM^A@EKPL8CW/"(G3%F,'_3=[0VBZEQL"I-AC1[SO5G0"UE?,IGOU]Z9+OLO[#2W_\+3;'_H +M%$K-QPLO3>J$]4`CY,S9/'Y8W?0+_"W=_X3Z+5L6_SGTZ:ZC\\GTW;=[(7HV +MB?OW11\@=OHQ1I^Y^#=Q66I*V/:S07(OUFR[^(U4>RPZ;V[;13=@V\_,;;LH +MG+YNN+.A_V>)^'Z2X=_";FL2<?57E&^+\#JCX!.?E<>8<6SV`\GB]R)<>\>T#'XQRDX;IO +MBO<:B/%2>2]V:O;)>KX[@<]X#VV'5%ZUVAYT^S9Y$W!2^H<5-X<\,Q+KJ7N29GV;/86>(^T>UO?IP]H$^PHR%:GXZ%HZ`]J'1FI$XA/ +MDSI2=':BCLSG_5-T2K7)".K(<;UY+B8BV.B[>G +MQG%QY:2/8:?OIY9T#-*26:CG`[#U?,EE:GU?,F*AZ_G2WSF/EARU-P'2WHT'RRYF>J#);V3/H!MOJ,/ +MXNR#?=0]2$O?Q1WV+WDA58ZEY>;V7UH-^W>;VW]I??J:LS3`,-BY.Z[UQ4^\ +MW!0R],5+3^FV@DP?#]*R=0G95AKPKFKK0+ZIZ_#Y[V-S^9:E.?\MRT_D](^% +MS1@CR[C_-;'#LBT)FFI5!L1/!^Z]!_A]Q;(]#(,<(AA5.!ZJ&W'N,<'K3,;C +M=[Z,>\D=(Q/<7B//-'A#J7A9SZOO``%G_%0=2G*U6"MI2(VUDA63L;;TJH&F +M.K6F(4Z^GWQP89!*"[1<4/J:8B35AJ7>21N6G/^>;!07S3]#< +M1F6YZ?=K&?8_!:?FS+)J__MJ_Z;NO9<5Y!)9AW.N+&O@]W:.?"H/'E?X_;:3 +M\>J:U/=YCE:.TT*.T[*C6GT7Y/!-X-IU7`//\QS/.I[V3B-@R!UE(7._E47- +M_;;76JWY:7I,9WZ;?.;^"ERW/>(,]5U+LC"1[]T_%@/VGQQ7Y<$?ZF=RS\[F&05B;.LRL-_%NYQ1$QB[>5#7J\H6=COO]L@!_6XFYE:,26W$>O5,\.X@EM +M7P%^V$#7FQJ7*\NG>Q^IZ;9JOZ;;:L.Y8%7V]+JM6F&NVZKUJ;JM_H$!KM;_ +MD2DU=%73Q+FQD/NG5=?4?JN[3A2[S?JM5:6 +MC(P,*<,B63(`AIJ4E6'-L.'*3-RSI`S)BLN6N&<:QEE,B\N:N-L,X\QO@&IHR-O]>`O'TPXLNA5Z?Q_]%EH<_=1U4SWR?VT&6IH9R +M7AVQ';L^PKU[V_ON4?G)DA"57Y_F77)/K'VO%['._^M*_W:@7^+_2IKQ_)8L +MKO`S?"WX.YK_N-]>92?Y68OZPLW1J_I"DG:_7[&+]SF"V(68#_;@8?_7)"6^?93NT)JV +M,\WF=".9O[BA_3>VIC=$A4/JN__4>B@-T)I+P/MOX$G`&]+Q3,\X^\10QUZB +MV`,QD-/2R]]D9=7MIZINS'7<(?Y>+8/_,^?O>[KOF+^W$_^XNP9UN=<,YK#T +MOBD>B`J'[Z^E[F9",L9XGUCK4#`>PUB#EQO@*Y+@[P.^'7!*P-\'?"O@E`3? +M8H!O-,"K#?#U!GB5`5ZIPT?VB=I1>>T*O;ZFVOI%]P"M+5?UL_0^[O`=U'5X +M7-/QH*[#XYJ.*?`52?`"3<>#N@P%FHX'*0F^Q0#?:(!7&^#K#?`J`[Q2AVLZ +MKG.:ZYAU?8#6Y29T1!]:I>M`FHY5N@ZDZ9@"7Y$$=VHZ5NDR.#4=JR@)OL4` +MWVB`5QO@ZPWP*@.\4H/O)C:4^@5HM^I]8?R09XCIN`[W12(41/W=$4$Z8[I# +M/Q\";B!$:_:H]I;5,VU`RRU/?R)D%_;WTR=#]%2%RDNFP`E9K7U)/>[3G8PG +M#I6]I*[%^1KK\5I8)Y/7X#5!JZW9=JS\8>NMR/R;$D>+D\\0VQV*)8#\M/VH +M_DU%.V`6)YW`G,,'F#0)0[T/X8P=1=YW +M9+I[LI5"]+2],%?-B["%A31;/+,KIZ6*.M3ONX8IG%&V$W-/L@P)VV8+^$#W +MAVA_I22'Y89L.1%+X$22W)`K])8,V23(YKM-O$[0]P6?I^:JW[RI?71%;K*< +MDSZI6#>]G!4SU#4@)\O(WZL-TS-761Z6,Z983?CS*LIK97?.MR@]G +MG2)RRP/V[7B7:9G64!C=R@HP+`3L,Y'`GM`\/X:E7]0I<>ZP^+.4+^CD,11,QZ.EJ.\9Y['^J9PQ(,;=KH2 +M/[2\T&&A'X8SEL]T^!3UFW/P]`W27[2A'Y'^C[BO#X[JN/(],YH1,A;,A,AX +MC$DLQR1OLH5CV4L28F,C&_P5`P('.S)@21;83P^$&(00(Z'/00AYK0_,AY!A +M)$@M6T6J<*S48ZM(%9N,'V1+V2/?C)Z0`MDF,X:,WO0ASC`OLGLT`[ +M=\7AO@#ME7.>2+K[L*C?&YB +M?GWXT:GYX.%O<#K3_489^K#2@7?=?3B]BO'X24AX'KTM0`][M3KWZNT*T$]\ +MW`Y.!\U.,`_9HF3*BLAS6I)W1AYPT##:=M`<.\'XC.R:/P/Y]9*[LNU)!P__` +M=OLC7CTN4?F]T)=&/90\NFMC.?)V08Z&E.W[R`7TVVKM.S`F/T=$7\N(XF%\ +M7V29GA5=+'*C&)>UZ<2RE?,<11[PN`T\?U'Q^*)Y<3M_409P*I@,7F[41Y/` +M*)CJ/!UT[;S)SC1ASJEA>Q^Z-?3FQW[8,5L$^?L2/5J"M^DR/?IJDNE#2G)8 +MSJ*>7NC4%@U7\/]TAZ1I\L(:A(?`6R7ZO1+(J2#KO.I\[&.[A37?)Y+7Y+5< +MHU3FNY*K)'5@91\_NNAL&U$SGYDMO83\CZ:`7Z`K/-:`\>>K*Z>4CE9UOV?4 +M\^CJ=RO4O2"^U\-G7`/TJ-PO`0]WL_P#'KW@X6[&`[INTF5:Y.,V"+X?@CD* +M^2Z@W::8-?\T[Q4@[P4Q\MDQR"#658,S:Q%GS3_3?2*?G;YT<#87%R*\EQY8%Z/:5&F\$09?30<:1=07@:XO8A-\= +M,9RK?JQ"QTV'Q[1,Q`?14M$MCF13\R#Q?8%@:K^-SVFG]H2ZJ2<4I0[$(]VT +M(A2T08?O19K%$&_F\3]T1 +M?\V9*T&+DET6V&F+?\UIU0,BEAL]1I/--6RS947$GY2VB,/':BPF'^EY$`\5E,Z,(I/`?-K*7%PFR3 +M=GEL=RMT$J\O:/6V*9LTO\]@CUH_I\?O8'M46/)/>EG'L;;E!:V'LH5UO7W4 +M\_@S`5HL[X(U(HUQ0=W_'+06,VZ$?C;%2J.=+5_J=\@>/]@S-.H3=<5Y?'94 +MJ\.&.EX5NXOS`O3X*=5/\KN&TR/7G9AO,X/>:WP',=,K//?XABW%>3]SU(#G +M'N\*F&9*.0\9XD2_=TZZ/W#$,=T/(*XJ2ANDI=9KR5M.7(=><1TX7O-`WA[) +M3G65TIQ!>N);$0^EX;$'[RZX#7`S>T8BFO[YQ&GA21+B;H=9G35_8K>M3?'* +M3%,-,8]T0*?0]`K,V38A_MUI9EWCL(JSLZX!75GIT[O^+H_+-Q?B)%K;\ME6MT37,HM7$.V<\/\E[!$U*.1*$+<)E8'8\9]"_*,A[R +M'E/%%[YJ%\9:T16,ER4SL@8B4F;FYE'PZ&%*/0I8S8:$%8O`TQMA_F@.;7'=`I[%*.`:[:#ZE;[U!SSGK'L'7]/+$3]I^V!H6QF)ZK +MUMJ<+'N@>W5JO!+2RLY5\^_24R@_-V%[DR!//!"_:`_/5]`%D@7DD-_]8Y\_ +M=(WDG1EZ\ED);S2.7X">;%,Z[).0_]^SR[%H`>V@<_.]B2RWB+'NGANF&M8E +M0E;O7C5VGJR#72+E)./,[0",-N@Q4I^[51UWK#VR#1'B?H*^D.R/#&IM>>J' +M-ZM+!^CI`D5/[U[?'(;Q]!URK13]@#%ZYR`]U?`WPWS',7T8<./C_:G.L_/Y +M;FIIC>*OIV?<-Y\R1SU/G8%L#*@SX/H:I$FN04*?<79H,O!OP2&`.H>36S/5 +M&N/3\_2^`!V3U9[D4T]*G$#+8>&8?I^7^_WI949\LB*Q:C6&G^H6',]W>JI\+;^BA2(9\U>4S)U50?/N7]'\6^4CMG<8 +M#OIDUB`]L]`&FX%MZ5N%^W7@UCA;KO-7-\_&O(T^X?5^EOOGCH=H6SNE5']( +M,_R1Y;"U,@@ZRZS](Y3644JIH-%OI?S`7'8^B#([G/:65GV.?G9SQ6=D7IHN +M(NGY,EQX?Z$\9U;!>\N\#G'6?8W2-](]E^C955DH7]DF8KQ>#OLG]0!L0B[O +MA7THDEL[(>L*O+ILAYYXV4WFIE+H-#L@YX%]9.&S<.>.R3@Z"_O[G(/'Q4\7!>B9 +M4Y/KN6UY#T@YW99WRS(,L)A/OBYXTI=!G=+-8LG0&X.C/E\IC^OGTMG_0UP? +M>\[$:1S'/B(R)5\\]PSK:)JN^[OTL3@EP]EV/*KN[LP<]3P'_6U=IFYSJOLU +MSY4$3';G%.NO=NT^D!DP(%>>.Z[+'X8!??>);64T]V=WIOOL91+YN +MW=:WU69*/F#[D_FBQ2RZV-[E>YX8QUUJ/2;IXTOTW"?Q>I:ECLDYU,'W?1B^ +MNE_VG(_K8!U0R;_G?)/IE\#?R;2-:7JO?^AC15LW)=V?1H[?;0Q8F#_3B\EV +MB9:]S.DQ"^L.EP!WV6_\\V6Y>\3U[-2>6!_'G>!R",_Z[6#8TE).\WWE,J^T +M;8)W;AJ]#^GW'2`GVM`+/?BDM$&Y_GIO[P-(>^=:P*KZ:?EFP'*^,S@6ODU; +M<^P-T/)"WMOA;[878W6'\IA.OJI!Z$G+-RN=9_GFLRZB]E9QH6.V@,V[/#-` +MSRE?$0A+GN(YOYYUS8]]3PSA%-AH75I;:A"V +MIU=3NK"V8M:W`N(_),+EML+]JF$YB]B=!G5:<#^4LG"\& +M&&KN17[`T/./T74.W]U&?R$?[(@4?8]TU)/E>+=`K>%PV1#*@JX8NUEC]Y_U +M=NU">SBM0ZZ=9ZT9T>?7@%[92\EW5>Z1HKCJFU#X4; +MSPWC\+,:^GT.PRC.5OW>>D)K:YIJZR'8!EE,2_>MRL>J>\GL]P9XCEL4JS^T +ME^6N?VZ(_-X8G0\/T(J8\%VFE9O%M1JZ.?UJE3RSZJ]X2-Y1_IQ6O>4/ROU: +M_I;WY7DME>?*=LR;N@T8*Y>VC[S#ZA\*LFP;2Q/UK0V*GJM6\1EPQMD?>=K' +M^,;J6AL8]VHWS\NC/AZ+Z:6\KK+J?O"Y@,U_4_J+CG]U1'P>M+8VL'[54F5- +M6>(5ON'D0WM'/:M6ONM6?/.WP.6V=VAM#]!*J;\^T";M1X17-4QJTX,/>'[$ +M?/07C187]?GHUN?>,=C7%>SG%WR=L"&'+#U5+.>?_Y?KR8<"-T>WU9F2/^H. +MU2CYO/K[USS/VZ_7>8_)<_70T?Q]$8I82EW=8=ANI?\&>_UYZ1.C.R3U]RZF +M+>MH1Q3M)4_UA/Z-_.NZR!_IPCCT=D%.'8.M6U/=+Z*2!M#=6"<4G@=/\MS% +MOJ\NEY`Y-T1F\,2,40^M'!TN2!'#SE11EW\NNC,[O;)?Q)8/)?&ZI:WJJCI7 +MX7<-$/+,C&YSSO(64]J1:Y0V,\1^76"W7Z&,IBLT7VQS3+<%E6XH]QLOX/L* +MY/=N;\.18NA^5\AYQ*#[L>Z2Y8:=O<7)ZY%QW6^;TVR0H9:;E1,ZK2.6UF/7 +MZ]J=W4-$UY/;P)<_FW?-L^I4HO[5]T=8%];7(-Z=I^80P'--H4.DQ-<35O_' +MS=MQ+SJ5+;XZ$##9W,HF:\L[]YTHPSMV0,KJU9#AVLOWB;7Y>ORSYS'N(Z-?-8IUPX]5(-W:AW@]%2`#Y+7%+1<(RCG9/)] +MYQ(=O4J6?GHAD_<(Y+V40?LZ4==Z+*3I1`BO%*`AKPGB>S5P*\`[F]LLJAW2 +M]XFP%.?YAY[V29A\7AO\E?X=UAE>>+/C2_;%)?K5VKJ/;80DN591*B*\OC[J +M>>%B?,_FA7Y=+QRV''(-UQTJ"%G:[:&ZUK91SXN$?M#\7RF:\3WP)$=*-M+F +MZGLIO$<0H!?F3M%?%M:EJ_Z">0AVYSLC`?/9,)'RD?#BZ_$UU!>?C*\_1X5& +MXY-JCG[QI%P#J3^4^8^E8;/:BW[QF&[GLNZ+/!L8SN1^6`YI/G!^'F4=&M_W +MX%NN&^';@>]WM>^[\?U+[7L.OM_4OK^-[S+M>S:^7]&^[\+WL]JZ7,IERDY3 +M_/5SZ'^KZQ3]QN)6!^BG_?HZ0(!^/I_+(+X0^"\PQ,_5\M<%Z/E"0[Q=B_?J +M:\I:O$6+/Q6@3'L\_D5U)H+]X,#F/5NQ`/W_<_3_D[V&/$-:6?3CDV2(#ZCX +M;(R9-],-\1>^COW5>:F4<%_/U)8XGFU/]ET@]_N^P[SQTNM\9MC6+BZE5PEQ +MB5YR:>/Q).^KJ;V[EU[B..91<:U:\)K6)QGPRF*8?'UF3+%4XQC'7-CT8!\R7GYWT78]X` +MO23G:XRE3T<]+Q7H8PE\XM/B!Q%?8X@_.?G\OL8M+&M.7!\1H$*3S!5'J`.SV?'V/;DUZW-?2&C?75QT3'UZF +M-7(L\/ERL?N##%LM(=^:E=!):]3S0<9D[5!C;$VCD@-KG6J,KFD4'O9+M68O +M9,%"Z,(+$Y6O@!URO3Z_[^W73IO3-W)?K'57WP7;$',L=``WS\4\OW:[HY#) +M^2'(WMIW7@N:V?[,@?!%?NL,S*6\;LUR)N8A\_]\+6S^[>739IX7O:RC0]:+ +M+YPIT6T%L\26@MO;BR@UNL69MO\*L>^X3)[7VXLI`_K\?#'LF,YG;=KE61M* +MX_DYYGFZNP/SLURCMGH;Y)KW=2=I\X:M-N)X%FR)Z-Z]+31-5 +M']%LUVMDGGE5^`8+R5P5$H-5KTH]UWJ^($)^]_M453Q](E6CO`8?#2 +MQR)YB_-7U\)6I5>M_423VQGHK[F`/3`9K\)N3+M<2$EXIUZFG'O'UKMHW7;$ +MW<,^NW*C;,^L#5^B=>])G1UQPI)SXCXOI>=4RK,PB,LYW1-:+'V!\;D38O:L*N8>28G8]A,&>I\Y[HN?9X((%[M(^2T^2.+?>JN4\X=43-)WWAX +M6U"_A>M''6YY-LV]V(?\RHXHX;.>'T%&]'.Y#+$[QZUH\'(EMP/YNH#S/7ZO +M7-,/\+YO;&0O^8KY;,S+9<"SB_E[MSHYG2 +MER/Z^`S3!GFN`FX2W@>T\<;POQV@EQL-X6_I]2&^C_/CG3V'.8?6$BSU^0%S9?SAD]KR&]9D(XU)'_7D.O5U//"7F_$6N]=- +MMHYJY[F+][8O4][6;LSR36S'6_+/S:PE%^B@:&"/+:)CP9Y!^( +M*#D-&_72/.3YA&8CWV#Z]R2<@VNO3J?8?\^^79@?Z`3OI+Q]+6!EV[;J+9K+ +MY_<@%_J%.:,398;^\=J`U1]YGUP;R3Q(>0V6"K*T7"8[;+C(V3%_>3'O*9]?>?8`/1N6^]B(;T0\[!P+ZG_5C#+X!LWSGE7G;::_@_R9 +M\?DK3]XY/KN!_:U2&M+6Q6FFTA0/I4@>U>`Z&2:709Z5PWR7ZS+O4>8.,*[< +M3O;5BO#0V>.3G+NVK'5&/'*];F&6VT=^:$.\GWJ^XQJ==PQ3#[Y]19CS-_Z9 +M^M,IH;R-86X%;J<93I5+#+!O8C_T^IX@8/63A'$^-D#GW:Q[?)#1T_$^]3C^ +M7=;#KL&*WV*=4@W=+T^EI'5E>!A]N$8A5Y1)GP[H6=`#@RR[0#>_I#G).AR +M%SI:1?>15M%[F79;H;==1%Q7,V!`]POZBAF'N@\[9HMSNQ"'M@4"M%;JYTJ? +MK.Z2,IGKO$86R+YO#%+='WA='KK>1;1SQR7D47["UJ>/7_-DUV*>`?4P'$]8 +M/?QM?.I.JF=B_*T^>OU_:_F:@JF?KU*_;/?_Q_;?2OD:UU3/&ZVB#S*O[XT_ +M4@KXZU0CY%/U!^2HK!#]U2_3W*H/R3EB8JPZ*\:89VKYG'PX&GFOZ8K +M9&^^0JF50R+6`Y[A,W5\9L./[^[2,/WOX)>\;^#KR<-X[R-"7>=2\R@-\,X( +MSX->87ZP$3A<>"?697VGO->:GL-SW:MOJ[-$U7]0^FZUG.]0]H*2Q37W@V/RT\#S0R3#!Q]:SD#=G"^7>Q5Z>)]XI[[*B?6:VAS!>&C&. +M3J(MG:.>U](@BT/:'."#;7.R"670QL;EK]`]L,^.J[%4]6[WP`#;7;W*+JIZ +M@>Y'?POBB[>9+ +M5!EF>PXXG/'ELV[ZVMOS\VIXOCK3S`_H#II;=ETA@CX$VW!CH/HJC]O7+HX? +MMQMAXVY$3VP$KVZ"#;T)]O4FS,J;H"=N6HHG&P]Z91/X8!-LMTVPVS;MQ8,9 +M?-,Q/"?PG,(#'MJ$GMN$EA0"3F$ZGD5X4+X0XZ<090M1IA!E"COQG,8#6Z\0 +MY0IA3Q=BW!1&B#:C_LWS\&3B68<'TF(!W$?`N`MY%P+D(,TD1ZBP"CD4H5X0R12A3!!R+T-XM(,$6E-L"R;O% +MB0?X;EF)![/+%N"[Q8L'=6X!CEM0CO_CP\MR+N#HPLSB0AM=*.=".1?:Z0)5 +M7:"-"^/;!1QA0-)6Y-L*G+8"[E84WHKV;$6>KZU%;AM1?YB +MP"Z>CP?YBP&O&/F*0:]BP"L&WL7`89N=O9#B0?W;4/\VU+\-]6]#_FV`O0WU +M;T/^;8!7@GPEJ+\$\$I0?PGJ+T&>$L`M0?TEJ+\$\$M`GQ*4`?M1">K9#KIL +M!_SM"_&`GML!?SLX=#OJV`[:;$>?;`><[8"S'3"VH_QVM&$[RI:B;"GP*GT& +M#_J^%/U0BGREX)-2M+44]90B;RGJ*D7_00#0#K1I!\KL0+_O0%T[@.<.E-D! +M^N_HQH-\;O"5.Q4/\'(CKQOM<@,_-^IQH[_=*.,&3F[@XT:?P=BC,N!2!KXH +M0[ZRU7C`4V6@0QGREJ$=96A'&<JJ``TJ4*8"-*A`?U8@7P4TH@J, +M5;ZC68F\E:#91HRY2N!8B;HJ4:X2]56B;"5PJP1>E<"K$N4K453XL!9OYOS\ +M/PK.+^,VR;B@%F>Z,E>F@,=POJ&N`P?VOU\7\S@A/B3#?&.>7_-2;D4^TLA(Z*MB-LB7VJ\-?I +M-$F::?(T)QGKD.TVX,SX&N*#AG@C7?ID^C@X3(]-I[1WE_8^H=%'[T^K5A?3 +MV3J!/L8XTXUQ8_0QYM/I$]3::4U`GT1IILG3)'W&ZC#01\8EH(\>;Z!/842C +MCP$.TZ/P@O8>T-Y=X^GCM,3K$(YLYY6I`QZ&]NKR>;(VQXS]D*#=QO0`="E=KL7A*SG/ +M\)&^2(5=V=K;J8]?+;]U`BY!K2YK`OH;TR;2WY!V`_V-Y2;2/VB@FW42^B?* +M,Y'^"?*,H_]8>Q/0?UR;$]!_7+O'TW]K2)<+W47X:PJ;Q8:7/&=+-4DYJ<3IM +MQ^3[C?&FQ/%.TF'J.IZ6/D[/T^(,,K>DE]_QLMR^DD[M[=/>.K^-Z3VRW0GT +M)RW^!OWIQGBG,7_8D-]LI.M$74YOCY9^@ZZGMVWR=$.]6ITZ+R5JTX2T<>TR +MI@5@CQEU0YU_M+03*KQ=H^?V-GW\ZK+34//H&33*QD1M2D#/L7:-I^<.IU&7'$_/4LT.V6%7[]*!.#V= +M$_ESG'XVOEYG(O[4XA/1TYF(/\?IBI/3TSD9?TY(GTA/9R+^'&M38GHZ$_"G +MVVW4/+]_&PJ;Q85V^C:4;Y)LS.;%\&Q=O +M2AS/\LUIE.D#6OH$^2;C#/*MK%/)-Z=!GRS;J[V/:>^&&^6;,SFQ?)/Q">3; +MQ'BG,7\"^>9,GEJ^.9.GEF^3I1OJO4&^W=BF"6F3R#>F7?GIQ/)-IC6H<+E& +MSW+WC?)MK.X)\FVLW@GR;6+\#?2<(-^SJ#V5O8RVL?K1\9Q:`B;QH?5.#2DCXU#CDLT#B?$ +MFQ+'.TF'J8]#+7W<.-3B#..PMC!GD']=B*H_H-F\W\U[W(VSQ2F^/\'IC`?O3^=<_2EMRQ/ACGU$ +M';/(H>4^:U_3X7$M\?Z'J0H#R.@U[?@>%9[%H;A4^M/4D +MW^-AW\MHQ75W^UN"Y+6QN.\#S'JJ9X[L9UZ>WB?XZ^UB>/Y/!NW +M0V\?MZ6N573R^1:T*05AR[:`")_;P'A7-^KWJ0)4==HL[V.)7L:)\=G@YK97 +M=R;`2>Z7H`T?Z7V!_+.0MR_>'XI&O)_CRN?S'FH?*4"OROO2S0RCE/>37OT] +M^WP;VR<%S=3YD.H_\-X2\LMX;2^JB_>>$"?/5?`>&/`]=SY$Q'XF^.PK[^$? +M!7\=!1SDJY!G9>N)_2%U\7Y;RQ_!K[G9M^^(T&VNQ\2?+U/-5>&A,/LC!NST +MR^1Y#_6F:6\'WK_!^RZ\?X'WW7B_COPQ+7\&PEL1__?:&SC6#.&]$NV^F)[/ +M\;(=*Y'^DM;N;G66IO9>]BD`G-A'LIO/C`.>"_GN9_B>%7519&6^?XCD--NA1$U(\IWA+HQ/ZK.8"XQ^(\QS3\X>(/\.TU^/C=*\YQ7T_ +M%J_@,YR3W!]ZO-YFQ!]GWM'C=7P#Y%EZ;J[:]^$ +M:8;B2Q7?R'N=\B[HKD^$Q\9W?+K5_RU4.G#L&S;;(F<=(=HU0O;0CNS;1SV[ +M-@0HI4X[P]PGSRIZ,OC_V'Q.TV8SD``GUW-[^U0^_^]^#[CG2VZ)CFOLH#/F?#> +M/I];X3,O*'?A,C6\S^#\CQ>RGN6$A +MGUNI_I+WJG?7C=^KWGTA\5.?KKV/3_WL`<;UZ_!&_CWS-3HM'/7L'C"_C +ML<3GE;,BU<(4(7D/UA91?O1\Y7S?LV$[XW/4+!H"U"!]E+8,RO,R]D'`K_Z, +MK)CC/N7V^2.]U%(EPDK>UK^LSO_D=*DSB?5-9PODO\^A']07@K;RG/N!V>*" +M-N>@S&YYMI1]KZ$/![0Q^DWD]\;[L'[=&`[%]"T^[V:+"A_/L]+'!>9RU/5R +M2269U=G0/:3EMW-[D2^6%*:T)95T#^"&]+YOD?U=[^)S1% +MR,[T`TY]H&&#X?L]&^9__Y#TPS_D*J(4U!<%#MVVVB3R%?%YTSU]W&[M+(0% +MX?<,\PUD]AYY#T%\ZB#UGQ>2O@+57=L]OP9/76QA65+M()8EHYX])S!&+FI\ +M/J!HK.Y7G`<4\)GZ_C,+Z[V#]%._A9Z01[@CI-F^1^Z)[5V)7,Z6:&D%&^4^?O#LN +MT^MWV5+O7+FD9)JH"FEHE\,-+YF3;F.?CH"/KT]]/F_M. +MX/;9S>'6W!_'K;G_5G"#C?I1SUQYWBCUO#S?^\:7E7/E_Z-FX?N?8(/]F?\# +MB^__H>:V-_+`ZW,5SS?*_X#$DN:<$![,.R&^?Q'A?]":1?V6"^^,A-D?8__1 +M*Q9Z9R2(N>T-K^Y'3B]K:V.=>C*9_<9[2PK(QC*;W]5O\=W4:2E+OF2][(T! +M_5ZJ#BMK8!K_$SB)[\;RG1&_(TCS*LB:Y0;\,.79W(`->B@;JO'^I$+V:2$: +M^+W$42UVO446OD/+=V'5/=CDE%%/X]C]U[]"OYF*?DT/QNG7^%&FZ-?8U^*?DV!./V:>V^.?LUSX_139:>F7_.JR>G77!"GGX)U +M<_1K?AMTLVOTLT].O^;>KT@_FZ)?RZ_C]&MY-4Z_EN\K^K6DQ^FWUWYS]&M9 +M%Z>?*CLU_5K>G)Q^+2?B]%.P)J'?M,3T:_GLJ]%OKWTJ^MWJ?'W+]\4U7ZTQ +MS]X-';%D]L%IPO<\Z)Z+/Z>]O^R(65.$9_E0S+,R5=0F6V*UTRQ\3S_A/25Y +M1^?-VY+NHF^S?\!=T-/X>]3S9AKTE`U3^1-]4_C77''#>EW(/Q] +M>2]'WL^]KMW/W:_YT-COE/YM//3?1CW[%L9U\WVIFLYN0?S*>/R;D;@NOZ_` +M$#^DQ4,?W5=CB._3XNV(;S/$=VOQT$OW=1KB3VOQWT!\ER'^A!J[^_KT?S8@ +M3O/-MB]HB&M0RHW7K4Z]: +MBU=>W=WF8E^?T=WK4]NEO_#]WK'[Z>9';X-<.`$=/!2K.\3_>[FG>HA]6L#F +MIFOD+QFMB26MO=C#OBZ5#XR9/:$(\?W.'M=G'&<+6=L=L:1-%\]_SGQR\/?I +M17R/^>!/%`T.I`1,/VM3]\4/@/^7C>G^BHL)ME.6A428_2M47Z4944MQ-OOKB]9Y&]AG +MH`VR2_JQBH:E+P.YSN@B,VSE&>(+)_OK^E?V"3@S1"DK0K9P50BRC]<>(FCC +M%\Z955MACPX%J+V([0VRC7Y1,"OX1<$WO3%*XW^)>HLHH_ESFB^V.*;;AI1/ +MA9RM=NE747A^ZCWZ.4E?JK'=W@;I0V&'D_W5LMQQLB_!R!:G&?E6>LT"NN3! +MBZ)VVM*XO^R#R_1_#DWX%X6SGPZJ?\#M6GM1_X\3\E?$_34E_*=3&LHUZ+2T +MF73_V@==6GUG]/\Z86Q&M+C>^/J*BM-YYVOBW13V9RC]J[&O`HO7%ZOSMOE/ +M7N/UD*"OG'TEMU8O +MV0>KT8?IK>(+YZ?<,&6"KZ2.H_N/C7E:^D6M +M1:YOQ/:I?!-P`(_N+]#R29\!,VLI/4&^).%YTZGE2^%\>GO85S_RZ_DLPM,Z +M3\LG97W,8TY4KU5X7O1I^>Q&>(8\R3%/PRG.$ZNU2'\)@!U"_H1W*4<];=#_ +M#\U7*[N/W]R7_!O;69?><'J#:;[.GA=!V'EVTA\3F])/_FZ +M#Q2C;X#$_[1QA8=;/QE5_N#?POSWEE/Y8I/_M>"U8@??/SHG9+_2%]E +MP:QHM4BOSD3:=4]+4,$O&_ +M;Z+\?X-B(LA&Z">^Q;R^23SGT=]?L@-*K\[8M29*GWOC!;PWCU +M['2>(Z1?V%%MC@@%*#KJG-5>2FGZW"!][HQ01M,(YH<=F!\T?XQJ;EAUAGTO +MLL\=C%T+OIUB)!K&>Y[!UZXEH?\=;>X(D#>-_2^.>HZ4!.B1$XH>1Z#__$C3 +MZ[UR/"B?+H5;;)%77E7W.%5?[V+?CXKGSOOG#I`8B6E^+#1>P#QU@'WPM]<0 +MWO+_`."'U`Z-]P[$_T_2P/X,-=A=9TN4;\=1CS)Y/"L:2F=%/Q;2'R_R-E^1_W/J8I[-05]V +M(-RRD7V]?_&GW+*`]+'#]V&!@]2CP!]5@/.'W.BT='4OMGWNE'[7:2=79G3(PC5 +M8=GJ8=R(6".4-E3H21$D>[;E8&UI<:I;%93Q@*?K48D[,-O=Z2]=9J=U"Q.Z +MI1:L&J%`2%[>=^]][Z5-2E+`IHU`_LAI7KXOW[Q[/]][[^=^W^N])PO=R89" +MJ;[A#IU-W*%S&C=`$G*DI`%HJ*&8TEDZB+KLIAY`)JHU2-W$Z)P^J/\,/].R +M/6?=Z<)HRL4MO/DF;VLBJ=C27KG*PRHYQR@6/L:3<01Q/Q?%E +MK/(NU)U)B\3JK +M[C%VX&=]L.]S!]H82SICD;Y?80;FRU7+M1JGLSYHT%$M5I;DCS1^OS2NGPWR +M.!6QQ)H[#DZESX7]_0X<'76=5IHO[*^BU6H;.4> +MYL%S-517RKA!B]?:4)]N3;)%XF@BQQ?L0AY)=3[2T3<:RW);^F!_)N45C..[ +MZ3Y#'S3>+U1:FN2>)_MU^!L7G654$T3ZW"77;I+>*_Y(=%8D+Z7X;S8_G];`DBX/^AY[Z/^T6<3[\/>JO@&._/7J>]F<:A:#^-EV4 +M6Y$/H[H):_Q^RC_"[ALH\3A)\1G(Z:F/U?X\Q,PY^LS)_E]+-4R"SJ7S7+"_ +MZQC]!^4BRM_WMW>@WV75O'O%0M!48XZ/+\`7O>=8)C](:[/\):I'XL8\[[S< +M0X/FJC)(=4O0EE,99[!6;\+S[0:KM/ZJ#'GT&]>Z=KH>=\*B#%9Q^%.FQK5< +M;J+:_J:P-0P09[9#YR`_0OU+6++!(E89 +MBM&7`-/UV,0:WG6YX@WD__M[`_RM$_G;"JL`[F2^0)H?YRA_0>XY0C6K26;D +M,*GXTLC_W_O&5N(U@5@@]6(25/A]@QGGL)+/=R?KK/@^#W]KI/X9Y9[H-_%S +M@P/'+7A]C?B^"5_-^#J`KT/X.HRO%GQ]C-^W1*I33?-/>`^+TUEQ;5O_L(EJ +MT?WK3[VX3@2[(<]/>&?V6._M!VVG[0MHVRC`T1*!_)8#.0GWA_Y_AX8^Y(%/ +M(W_17(*R54SH='5)/2_$7TF\1X6\)ZU]J!GJ1>!J14AUKCL!@34QL!;4/UO( +M+M-\]%G9&5#[[7PQU=SWC;;%+7*O4_?8@KR<'V]/`'R<^G +M\$L/EKC5DBS(#4FV$7XX1I[27B8N[Y=K,DI["(H\)(O$$SWH@5&V^K(`1]QK +M.RBV)N[:A#+Y^!24,9%D')%-'21;8IV]#F5Z'66KHSV-DW)]QH[A;E@^C#)] +M;8(EY`M])I#V?7RF['WG0F5DVU;2_DOZ.7BK$6V/GHEH)MY+/6W1Y[D[2X>I +M?@SUQ>6EOC^7X+[7%9[GW[9R+]6G])<7&N6Z175V4;/2?BU\EUNDOC;,NA9`=+#OC(9WQE6N$_BRQ'Q_8TQ"%]-&'PU(77*P^`K[6-5\587V@C& +M?:I_9L5\6K=%JC_V5C6-DR[67*&Z2H^C/[R/ZK>G2C6ZB/\K>T4D"_%^1OW5 +MB/-?0CPO`5^OK!]\O_35DE#.K_#YS(:`+)>4?:%$95_H>>3V&X*Y_5L.S"?( +M5@LZ!=J[8BU1\Q->\A/ORKDRVJXOL\N98Q# +M_E![?J?H*GNNH#J6BBU?'MW[G51[5J[9!>^LBK8]O_H>Y+YZ+V2SA#F-?LT> +MAU13V4WY*$![L0=\R`&0@[M%Y&2='@_X$_(6'?*4BM/X6RKP:H.P6:SN9^F-X+ +MVE5;@+MG%6C1SO)>[`6]Y6%V;@`.V(\78=XA\TWKKL>!:[?U04=W+QS]LA?] +MBL%1CO;3UGL.4+<:VCMQKNX'XB!;^I&#(/_P7U;XQ_\6I\TH1KVJI;YQJ6AK +M7'HIRO`DNRS9;[(A3ZSIL8B)Z+^J>/.*)T$];:L9G(M*B0O]W>]!]GB +MMCT.$?4LZ7B(ZEMZ(!]UM?PYJL=S4>KUY7]Y48:8S!<=-PW?T#Y'I-]DB*GX +M\IQ&S+V*Z#?IMZEVW7+$+W_[GUF'!7-RCQ]88O!O"Q/^[9%UA;\MH-P8%Z1> +M&?D6D.XUTKIJZW=#6Y$'RHMP#9T&$+:3?A9EM)6ZX=$71M=7V9.@S7(W(<< +ME[@NK3'RA?FGD=_2&M/A&MM^LLB?C&ML2_376`QTKKYQG1\JBNM\0CI/N'&= +M__;$K:3SOYHM,BDW3]'9*.>6:_Q]\!SEZ%0_+W`L[2M[@1MSG!HXIKV";^&# +M>1ASS2[XH%09SZ3G59%/9(;%NT*D/8TFQAF:MR!FRU^08Y_\S/`'GW5:NT&T +MZRPK%@(G(F_$'+<)==(,K?]-6@6['W$ +MF\"#X?(.WF4U@OIWO!GV/VQ3#\#A[W/QF-Z;CCF!S@]_[_'PIQ<>X6$:S?GP +MZ'PTCPN.Y.5&JLE9>=+R/(_\-B$KX[U:CVI!'201QZ-]-N>FG^#:_3!99";` +MW.[!)1NE?;<Z5;&#P>-'Z9]5&77VD_$_/7 +M!O+!B]3W+6W+-Z"NQ7RA$_,V_XNFC#2+$2@/0C^K75QD1AY;G.Q%?X?YB7A/ +M+]H.YHCOE;4F$E^G?(+50MK.2["8[A.N^5SNZXDY6J'W19-1>-&4X[MLFA_( +M.9[X1JX+SBH.ME"^T8F9CZ`\5T*YDOBB*9O](^:-'NF^)&".JFU8A]R[N`]& +MZH0C5[RG$-2OET"NE_(1CK<\^K01CIO^")W6CZ#\"CLM]2:S"B!6\0]Z7UZ$ +M')NWK#"I)\PK!=2O'W%B>V;#NT]YI!K>8O791LH]0^ZYCLD[A0HUR:*6]=X> +MDH<'7C'Z*N,1^EO'3-Z5%="YM-1LPI +MY_LVFW(">>KH,SP''Z)E9ZI&R +M.53'2ZQ7P"K2X5B30#JK3(V':X1F$.HP1 +MQYJZ8-A7G(S\4B6H.246M"3Z,?<@>R$\"5<)SWH%3\3L`N&Y.13/)YZ6]\I8 +MQ8%6&4_7B-U(L6!SJ-U0+)#L9DB.!?[M8_#\AO`\&0;/CUS!>!XW?3)QN[DJ +M7AMB&*_Y<>(U'X_7\3@RQAX^Y>-Q9"KBR%%G/([<2G'D,]/DQY'T&,81[3AQ +M1'M;QY&X?POGWXX5Q?W;K>3??L]-OG^;%D/_QHWCW[C;VK_%[2Z6=O>?YFC; +M70B>:T?Q+#V#>*Z7\5QU1L:SK1_QM'S'7D%\=A">JX/PK#QI^9LSU'6$^=_- +M\JA2'T-[+4+[W23;+V'L0WSSBR"!,!)U/3:J]498C]BSB/;\=W)_:.E9%D\$ +M&RYBXO(BM.&79*QG6*G^RQG)ENG_4FI+T)8WNH'Z04LXH_W>4V@&']V+DW!V +M2CA+MOL1VFZ)8KL*SK7XNG`9\RZT76^P[8[@_&[1B.TFCK'=7XVQW:=&<99L +M%[%>W`]J7(.YOLNA>'=:W[G*=GW1Y";Q>PP>W9QR)^[=P_JVW+N[?;B7_=NJG\7L'MZ=_B]M= +M+.WN=.GDW#M0\(Q\[R`A^O<.>%?\WD%,[AT<(Q\YD7L'Z*.;)NIC)_^^P?N+ +M;T;_&K]O$(X_#KCB]PVF0L^#V^+[/5.1#YT=BK:>_9F\BV(YQ?$9@\`].O0= +M(WZV\QG0O/(LU2^]#IYV#@!C.W2ZCH"E;!RNMBZ(JYT#C:`[VRA4\7RQXV]>/>6LF)5]JC4(L +M;_[QQ_)#C3=C+%=\W[$QOJ_I]O9]WQZ8I%A^+#B62W6@B*>.HVND +MO%M#<;WJ7&A,[^Q^$](&(\3U=7)]&,OXL_A +M]F=B$NSP&C=C"I>IX#)J*&.1Y +M*)Y+WDZYY)7&2T8^T@U'8FXW[=C`&`G8O6*M-_WYO@A^WWD`X5DF6>, +M[//E7,5#6KVZ'[;/5QO$0UZ+Z`]O8)\O)OYP6O1K\UV5@_TP'C*Y.5BT.,C- +MF8-%R@U>H=S@V^O,#9!O[*3^XQR0DJ +M4TJ]4=YS9W:#,]"W%?4VNR'0![8"UZ/2US;<]]S)!B?5"J?>#YWN[YS.+`$& +M5&D;E9K#SG1A6I[(BH%Q^-Z*G^'Y2A^QM&]5:=6!\]#FT_I4:;^@.2Y7IC6Z +M5&D1^]'37/EOY\`6@7WE?/8\]*O2SJ8/3E\UDMC;33F +MQVLL^S6H7ST_C7L_JSNQ?)@-_I.`UXSZ/)K3K7F_%C_S`]\Q[)?FP+A/U_/- +M/CP_4E^PQ(7,-5&]IV_-`>+T[C?E0(T4,^] +M2JW&!1^DDHY?IK[U>N:^@#K"S[,_LT)$W=-\-!?-N;ML&M>`WV-)Z8T-^![G +MH7E7!>8-X%2..-V+_HWZ#PZHM%O3K=-^SC87`GYW6*PR(-Y:1P!OIM1V9U3; +M75X7])V6"VIX!,]K"?1Q'W/-7>-=<_K;(JX_G>-X*?4,D*^'UJ5QDXI=*"^& +M/M5,QQ*KBGK=V41.URS:==5^5CB+^K*MOJB%W>=!NVL#&*GV?+Y0SMQ5.L>, +MK385^O6E^_#%=#U6NN;_&`0PEJG@ZX<@H0&_FLBI=(TO6 +M3;CFMB)W5V2Y,R2Y_9SN!,KN1-D'2>XEQ8GN)U[2@EC=8R79=Z/LQ"\5V;M( +M]AE#B6Z2'_W=4K%&D=\S$?DS%/DS-"B_"^7OBH[\>FUD^6 +M),L_W159?KU6EG^Z*[KRSU+DGX7RZXTL67]#WQ]'_H+(\F<&Y'\,Y3>C_,6R +M_#.[QI&_0)9_9E=TY<]4Y,\D^8M0_H(HR3^.W>L"\E>C_&C[^F99_@?LX\CO +MD.5_P!Y=^76*_#J2'^U?'R7[UX]C__J`_&C_>K1_O6+_*\WCR*_8_TIS=.77 +M*_+K27ZT?WU4[)]D1Q^X%WVZ(U@')'^G]4$PEJ@8^IJ]?2J>OW=8!=X4G@;KTX7_O0(=@]`,9' +MB\N9HT*T.;Y`/H@Z17ZYU(\Z_71U,RB_N[0!/Y-T+*".GY%U7+_N1G7,%Y". +M'4K/-+H&]J="`\;8F7A=4M\'%_X5U8RQ2H.6XI!8%9TXI.#0C3ATC8-#=Y]J +M=C/AD(+ZOX(QRE-.)+IK"8MN&0N68NA"?1`6W12[$*_!8#QF=(.:\*`X +M1I]Y\PMG[5P-6@&Q(&S:K5_"?PTU@XS'[.V4H]&<;?V-L/L4&)<5*7AT@+96 +M6>,"X?&X&Y3?7DIK?P2/IV0\ZE;?*!ZS7<%XT-S,%\!C=JJ,Q^Q4&0]^+\5% +MQ".*=J'G1;M>&QD//=^GFO/@*!YZ\''Z[)03TUWA\=#S%$M]=KTI/![37=?& +M8XXN=GC,L43&(ZM.QB.K3L8CRT1Q6JR*3IQ6\"A$/`K&P:.P3Y7=&H2'&?%8 +ME7)B9E<$/`HIMB,>Q>'QF-EU;3RRWXP='G=`9#RR%\MX9"^6\9C30KP!\8@* +M;U#PP+BA'R=NZ#%NY!0&X6%#/.I23CQ@CX#'7N(:B$=S>#P>L%\;CYS[8X=' +MCB,R'G=\+.-QQ\]7P]<%=S +MJWD;IX9;S?M%[+C5O`.1N96Q6\;"V"UC85P_%=PJ#!9H'PNXJ>57\\_$SCX6 +MF"/;Q_SU,B;SU\N8S/-,!;^Z&A/B6+EU4\NQ"9X7!!./(W<>F +MEFO=O3]VF-PM1,;D;I.,R=TF&9.[#D\%UPJ#"<:3A853R[<6QI#_+AR'_YH4 +M_FM2^*\I+UI\:[X64G=G@72_Y-4LT.S(`FYW+6C9]A++_[=W-5RE9-SY(HXI(I4D;JU#7><+;2Z*ZA"*>ENCPBRX=9H8R^L +MD&:W[[V>&6E_L25QI"K6V,W,O'[3_5Z_K]]T;[]I(3V/-0^4LFQ/)]OON1#* +M_F$CTBPL^T@G\N29%?9_\/&F%&RT?5(?I^$ +MU\NTZT+ZFZC8'J*WX2I<%199'9"<=#;OA9!V#G/Z/@OP,O.E0*1Y?KT??B23 +M_/(3M+:UX#+*K]:]7ZT;<6HQAT"4&^:>T>2L\*MV$7TA/W3L8V=X><:""GQ6 +MP'S[B%'BS^(8QL%JV27ZN\T?US*E7(FQCA%:(YL?]D/AV81VB^-#.0=?5'", +M?IOU'EX/$!6!U878\`?]EV"TEG4?^@V`:P`*RW>#V>>,@DE@H>[0)3!M-K,] +M(19P8?_M"9^C."-3_37(:ZA@PS[E$O0X,(5IGY>+F,X!XBJK+!RBM6\3K;7Z +MG-?@8L4EJ.MG2D_XUU#N#)GWO`19)[`^G_,R=*`L*%N`9$1Y>Q/E!4,RK5QA +MD:GVMX;/8SM[_(#MO2IVI,^VB-:)"\/@\\3@XG``RF+,>UU8^"H;:9S0NKM? +M*#Y%[>ZK7P*T1]!-H?A'OM!'0&N<>'V0\KZ/?I)\)?JKFA.:GXDA[PFB(\T7 +M#%$,PE@>.])G4-=(BZL("R2S3_FJE^2-M?492':7D\5\2L1+[2W7D@\M7E[> +M#BSV@[X)K2_K\N/[X&8HO\]`/N)P0[;ARQ[F_=C:9XLT%]OU==C)E$NZG]!T +M]PL+^=\]7G24QUS@?7%KIA@$[).;4>\2O>UX.RDA*,=WBZ,!'KHA+'JR1_D( +MR&^SEH+-$Y-M$6_GNS6$[2Y\/[I(\MLSZ+WYR"/J%$?1;_^O];GP1_ +M=T!J3._OEFR=N+];VIGH[Y;^W;B_6[IG4OZN><"N^KNE7TOQ=TT#]O3^;ND7 +MN+_;/V"?C/SE*]'=+&^_B[QST+/F\ +M!/PA9C1,..X!QFL^H8Z:>_N>_?VI]+A;-C!QW*V0$G&WPCB.N^6W)H6[`P4: +M[I:_DX([=T$&W"UOY[AK*9@@[E3Y.>Z,!8FXL_[^5*1YN7=RN%/+3<3=;B^<'VVY"'26K7VA:O;8=J80'%UNIQL^:]%L"Q>EX' +MCYTM=5+L+,4/QK2]!]DK1="Q`V728V0C1>*4,8_ZC>OV5->?E&[N@A(5ORL_ +MS_%LD)S,G>_TOA9%VJJ51(LTKY3&YU8JC34=:95=\"7B&8M5U/.T,C[0RABA +MN8B[H!3[1L[AVVRXHQ9,JY]D$9_2!:@CQ?T'**8N-PP6[!.EQ3O!XFM\'[H= +M"OS+#D5$&5L/HMX?A-^%CJN0Y=J*_L%_`7Q9MV$/S@]\2ABBO^6QOD+DXYK< +MBS5=T-X`AF,Q,'EKNZE-+>B72J]O`5Z6JN\7?]YP#<2H6ZKAWW$8)#M]TZ'' +M$J>+'Z;8X1YG@-L6YQA&_5N.=BV.OWT'[7<'ENC,@D[V$WPGCX#MX`@LB-6A +MC;58X!.Z;4<@*[H?,83XP.NB]M=@+MF?XH11WKG$V^/H@C*'F<6V%\&)E\?M +M/EI7)![3<#1J+&@E/7"\+_WL]K#(9DJVG]6&1*Z+`^FH6Z9O4^K[6:QL4(]_ +M3_PVA;Y92?X^1=^W[^!KJ!/%0/\$LDG',=W$.-T0LQ[4Z3CJ1G'1+PY8>(PT +MQ0M1W'/L?\?CG?7O4D[<2-21-6UR8I\SWQ">:6,B`[SOHGZ'\EK0!X9\]6%P +M[0::;T@4OX]86G9<5-LEVK3I*'T7$'799?U;G5C6)O^&/4%=GIO?,5,M>711E4_:7;7VPNDCQ,Y>4>[[HUM2_ +MH\#RT#>Z]7CH\B:,N.XP.20;::WC-,)C>JKT@*J](N0=K +MT4?VGH%RIR"@;?+HNQ2?LQ?0MUI>Q?'K=9:$0'(`&.@?@W[8@!G'.@ +MO7.V=V%_$`D7'2J&*?[??EA?UWQ]WN:U#C;@4>JS +M55!(]]_XCT:@/O)BU,#]@5RF^EQ\9C8;&G]_]E3[`?O'`]@_AAL<+*;ZJ&N` +M/+G43WW!`+QY$]MG>\V#H:&:A]JUOGGL)F+Y9<3R=L1R4/LF[I:%U\F:S2L[ +M;MX=Q\H0^58&KCX0WVQXP,"L?:W_]%\A^LYKRF-G;N,8^QV^ZV#-6ZJ=1Y@= +M8C/S&\L&T;8?!<39PV#AW]+4@ZALEW)'1R5#M$XR$4;6#`H";X?!85#VO=U/ +M^R:;%`%.U$(1CD,!?457U)COB1D+W$I+?FO(F']TM"6_+52'?NP'?3!JD!SE +M7E;'@?R^X<`[<1S\8@'A@#!`6,CMSPYI6`@@%OHU+/3& +M6O(O(1ZN)&(AG`$+SZ^^WU@P.[-#TWA(QH,5)H&'^D0\S/*K>+`618W60A4/ +M5AQG6_-"1JN4B(=@!CR\L.[^XV&6?QH/*7@HF00>NA/Q,*=7PT,-XJ%:PT,% +MXJ$2\6!/Q$-_!CQ\9>O]Q\.%CAUO"`8P>K-G:PMB(> +MVA`/1Q/Q<#8#'DI?O?]X6.&>QD,*'B8Q?CB]+1$/FTHT/.#XP:J-'ZPX?K#B +M^,&:-'ZHSX"'/]]___&PJ>2SC(<8SB,)$X2'LBU@(DQ$*:X6YX\__8Y?G!U6 +M\1!#++"(9%)V20;ZVS(<"[1VOR5$8T:/:9B^=T7[BV_WJ_,)=2[!A*P\FD\H +M1IQ/[%(Q$(V@[6\#C+K5><6AVQH&OD$86--ROOY:RISR^`3FE`D8^#`>`^?' +M,5"583ZQ/H/]_9_"_LGSRGMA_R'-_CBO/*;-*T]^*R0JQJG;GVQ/=E^+?9^P +M$,5QPELWKHB$A]R=8"$LC**]R4?0[PCT^T$4,9!L?_,5'!O@.&`<`[_HYN.$ +M%FMU5!LGJ#C`<0)B@'Y;B.U"#-3J&.A/PD#90=T/W!,,)/B!7TYMG'#EC^0' +MAM+X@8WH!^X!#B@.J$/;JP&3ND^#"-E(X_LTF/=""TV>1=UF"S`]J]8M\_9YXS:C7RC$9,NV](=)O\<]*6CNL2FA7 +M0:!YD]Y>%+\V1^,K4>7D_4RM7\QZJ&/<5@]I?"^D\AGB^?+4-OU2)>JS)I77 +M$L^;K_(^5XV\%:F\\HPXW@*5]\O;D+4V]6I]DO@?4?G7$K\] +MWF9Q_>51E>=9ZB\\]AKML2U=7X\T_]5)/[SMYGMC[,.Z]K'APYAHOQ5F*.CT +M*=>A1QD$;RWMK5%I5/&4[U#7OK3[US<%:.W$I;"`MV%PC!YK*>C$<5\KQ<6F +M]3/[$*=\?XY*FU\H/TDRX/4J/WBV:->E?F@OTJXK];7#]'I4[O0+ZR]DRE=C +M(=U@S/IR_++U1V4WE$Q^L+1*/GL%SNV\XY`.)U +MH.#8L38[_H(0%@&\#<]3':_R.I"FVF/=%O1Z:=<\GK!@7\*Z@W;H_JH/7B>$S;PO%T/4XRH"VEK&D@>!SPU+L^Z +MBR0/Q1:K>J__U8)!BHU>?\83X_KQ>F77PU3?4;Q_3M<+V_@LKV,L?]U9JBQ!AMS%=3I7;>%D>CU*2=/4ET/9W.0/^T +MJ9OVYGD=VQW[@1AIMF]#FS7J>_9H]"RD-Z6AHY^P>]+09R+]=!JZ!>G=:>@R +MT@>3Z6CG(-(5G8ZV"6BV^6O@L?M5U>?@>8BS*=F!KU/B/=G52?=H8Y'OBX5V +M01PX.]2]B,)X'_`YA]%/;-A,M'3X)-]`N%#WR:IJ>45B[)R\$EYI)]JS1*NG +MO+0^\A'`OE7UH?PY?K[L:WP:<5J%^E?5J#$;&SD&WE,HWKMJ,)Y.>KT'2^BY +M*SWX'.9YWPMG]F-8EWQ=V/@7)"]>F^@:SS.U\VSM;-3.L_#,W^7(+R27R0]# +MWCMTNL-OLK\"%CJ;._5L$1(.EN;&!&`IY/=XJ"3M/L1OLL;XQ_*G<&CRJN5Y +M!:V^57$<+]SE:49=,>/Q/4R-E=GCY3,EX>$4^=/H(U;'5?#XC"T@XSFO<8PD +MN"U)3ZCUF>D?)Y97A/F6ZK'<&>&]<;P?J.);`IF5N,='(1CURW'UY]C2L8ZW +MSYQ6G90^WVI(NC]]K\2=/B9V/+)7ZQ"/A^:D9";3Z#Y'UFASWDGA3Z'A1!>@ +M$_%_;NJ23A^?R4.`&7]L$?Z$#Z:Z:/3#_$3_L3''S+0,IA&8=C'!]_A=7K@I +MAXR)?E>B]\MB3$LQ/7JW!QJA1,)_\/\**.'WFZ?IT_1I^C1]FOZ9H'LU>J]& +M]T_3I^G3]&GZ-/TS0!<$`9-Z!6F.9*J@'6/W\`G/IY27^'SR0;(M4R]=`.IO +ME4P]%`#W:8"6(*8*@`-N@+\M!#CH`7BC&N!0OU;$T=65I?+BXL7%-GF)S;9B +MD6T)_B_;5CR]=,732VSR=W?O>&FQ[6^VRM]^:<=W=WUSQ]9,HDS]D#$]%@.U +M%;K/`+P?`/@W!\"[K0!G2P$&PP"_G0OPWR +__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 /* for DELAY */ +#include +#include +#include +#include + +#include +#include + +#include /* for pmap_mapdev() */ +#include + +#include +#include +#include + +/* tunable params */ +static int myri10ge_nvidia_ecrc_enable = 1; +static int myri10ge_max_intr_slots = 128; +static int myri10ge_intr_coal_delay = 30; +static int myri10ge_skip_pio_read = 0; +static int myri10ge_flow_control = 1; +static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e"; +static char *myri10ge_fw_aligned = "myri10ge_eth_z8e"; + +static int myri10ge_probe(device_t dev); +static int myri10ge_attach(device_t dev); +static int myri10ge_detach(device_t dev); +static int myri10ge_shutdown(device_t dev); +static void myri10ge_intr(void *arg); + +static device_method_t myri10ge_methods[] = +{ + /* Device interface */ + DEVMETHOD(device_probe, myri10ge_probe), + DEVMETHOD(device_attach, myri10ge_attach), + DEVMETHOD(device_detach, myri10ge_detach), + DEVMETHOD(device_shutdown, myri10ge_shutdown), + {0, 0} +}; + +static driver_t myri10ge_driver = +{ + "myri10ge", + myri10ge_methods, + sizeof(myri10ge_softc_t), +}; + +static devclass_t myri10ge_devclass; + +/* Declare ourselves to be a child of the PCI bus.*/ +DRIVER_MODULE(myri10ge, pci, myri10ge_driver, myri10ge_devclass, 0, 0); +MODULE_DEPEND(myri10ge, firmware, 1, 1, 1); + +static int +myri10ge_probe(device_t dev) +{ + if ((pci_get_vendor(dev) == MYRI10GE_PCI_VENDOR_MYRICOM) && + (pci_get_device(dev) == MYRI10GE_PCI_DEVICE_Z8E)) { + device_set_desc(dev, "Myri10G-PCIE-8A"); + return 0; + } + return ENXIO; +} + +static void +myri10ge_enable_wc(myri10ge_softc_t *sc) +{ + struct mem_range_desc mrdesc; + vm_paddr_t pa; + vm_offset_t len; + int err, action; + + pa = rman_get_start(sc->mem_res); + len = rman_get_size(sc->mem_res); + mrdesc.mr_base = pa; + mrdesc.mr_len = len; + mrdesc.mr_flags = MDF_WRITECOMBINE; + action = MEMRANGE_SET_UPDATE; + strcpy((char *)&mrdesc.mr_owner, "myri10ge"); + err = mem_range_attr_set(&mrdesc, &action); + if (err != 0) { + device_printf(sc->dev, + "w/c failed for pa 0x%lx, len 0x%lx, err = %d\n", + (unsigned long)pa, (unsigned long)len, err); + } else { + sc->wc = 1; + } +} + + +/* callback to get our DMA address */ +static void +myri10ge_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, + int error) +{ + if (error == 0) { + *(bus_addr_t *) arg = segs->ds_addr; + } +} + +static int +myri10ge_dma_alloc(myri10ge_softc_t *sc, myri10ge_dma_t *dma, size_t bytes, + bus_size_t alignment) +{ + int err; + device_t dev = sc->dev; + + /* allocate DMAable memory tags */ + err = bus_dma_tag_create(sc->parent_dmat, /* parent */ + alignment, /* alignment */ + 4096, /* boundary */ + BUS_SPACE_MAXADDR, /* low */ + BUS_SPACE_MAXADDR, /* high */ + NULL, NULL, /* filter */ + bytes, /* maxsize */ + 1, /* num segs */ + 4096, /* maxsegsize */ + BUS_DMA_COHERENT, /* flags */ + NULL, NULL, /* lock */ + &dma->dmat); /* tag */ + if (err != 0) { + device_printf(dev, "couldn't alloc tag (err = %d)\n", err); + return err; + } + + /* allocate DMAable memory & map */ + err = bus_dmamem_alloc(dma->dmat, &dma->addr, + (BUS_DMA_WAITOK | BUS_DMA_COHERENT + | BUS_DMA_ZERO), &dma->map); + if (err != 0) { + device_printf(dev, "couldn't alloc mem (err = %d)\n", err); + goto abort_with_dmat; + } + + /* load the memory */ + err = bus_dmamap_load(dma->dmat, dma->map, dma->addr, bytes, + myri10ge_dmamap_callback, + (void *)&dma->bus_addr, 0); + if (err != 0) { + device_printf(dev, "couldn't load map (err = %d)\n", err); + goto abort_with_mem; + } + return 0; + +abort_with_mem: + bus_dmamem_free(dma->dmat, dma->addr, dma->map); +abort_with_dmat: + (void)bus_dma_tag_destroy(dma->dmat); + return err; +} + + +static void +myri10ge_dma_free(myri10ge_dma_t *dma) +{ + bus_dmamap_unload(dma->dmat, dma->map); + bus_dmamem_free(dma->dmat, dma->addr, dma->map); + (void)bus_dma_tag_destroy(dma->dmat); +} + +/* + * The eeprom strings on the lanaiX have the format + * SN=x\0 + * MAC=x:x:x:x:x:x\0 + * PC=text\0 + */ + +static int +myri10ge_parse_strings(myri10ge_softc_t *sc) +{ +#define MYRI10GE_NEXT_STRING(p) while(ptr < limit && *ptr++) + + char *ptr, *limit; + int i, found_mac; + + ptr = sc->eeprom_strings; + limit = sc->eeprom_strings + MYRI10GE_EEPROM_STRINGS_SIZE; + found_mac = 0; + while (ptr < limit && *ptr != '\0') { + if (memcmp(ptr, "MAC=", 4) == 0) { + ptr+=4; + sc->mac_addr_string = ptr; + for (i = 0; i < 6; i++) { + if ((ptr + 2) > limit) + goto abort; + sc->mac_addr[i] = strtoul(ptr, NULL, 16); + found_mac = 1; + ptr += 3; + } + } else if (memcmp(ptr, "PC=", 4) == 0) { + sc->product_code_string = ptr; + } + MYRI10GE_NEXT_STRING(ptr); + } + + if (found_mac) + return 0; + + abort: + device_printf(sc->dev, "failed to parse eeprom_strings\n"); + + return ENXIO; +} + +#if #cpu(i386) || defined __i386 || defined i386 || defined __i386__ || #cpu(x86_64) || defined __x86_64__ +static int +myri10ge_enable_nvidia_ecrc(myri10ge_softc_t *sc, device_t pdev) +{ + uint32_t val; + unsigned long off; + char *va, *cfgptr; + uint16_t vendor_id, device_id; + uintptr_t bus, slot, func, ivend, idev; + uint32_t *ptr32; + + /* XXXX + Test below is commented because it is believed that doing + config read/write beyond 0xff will access the config space + for the next larger function. Uncomment this and remove + the hacky pmap_mapdev() way of accessing config space when + FreeBSD grows support for extended pcie config space access + */ +#if 0 + /* See if we can, by some miracle, access the extended + config space */ + val = pci_read_config(pdev, 0x178, 4); + if (val != 0xffffffff) { + val |= 0x40; + pci_write_config(pdev, 0x178, val, 4); + return 0; + } +#endif + /* Rather than using normal pci config space writes, we must + * map the Nvidia config space ourselves. This is because on + * opteron/nvidia class machine the 0xe000000 mapping is + * handled by the nvidia chipset, that means the internal PCI + * device (the on-chip northbridge), or the amd-8131 bridge + * and things behind them are not visible by this method. + */ + + BUS_READ_IVAR(device_get_parent(pdev), pdev, + PCI_IVAR_BUS, &bus); + BUS_READ_IVAR(device_get_parent(pdev), pdev, + PCI_IVAR_SLOT, &slot); + BUS_READ_IVAR(device_get_parent(pdev), pdev, + PCI_IVAR_FUNCTION, &func); + BUS_READ_IVAR(device_get_parent(pdev), pdev, + PCI_IVAR_VENDOR, &ivend); + BUS_READ_IVAR(device_get_parent(pdev), pdev, + PCI_IVAR_DEVICE, &idev); + + off = 0xe0000000UL + + 0x00100000UL * (unsigned long)bus + + 0x00001000UL * (unsigned long)(func + + 8 * slot); + + /* map it into the kernel */ + va = pmap_mapdev(trunc_page((vm_paddr_t)off), PAGE_SIZE); + + + if (va == NULL) { + device_printf(sc->dev, "pmap_kenter_temporary didn't\n"); + return EIO; + } + /* get a pointer to the config space mapped into the kernel */ + cfgptr = va + (off & PAGE_MASK); + + /* make sure that we can really access it */ + vendor_id = *(uint16_t *)(cfgptr + PCIR_VENDOR); + device_id = *(uint16_t *)(cfgptr + PCIR_DEVICE); + if (! (vendor_id == ivend && device_id == idev)) { + device_printf(sc->dev, "mapping failed: 0x%x:0x%x\n", + vendor_id, device_id); + pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); + return EIO; + } + + ptr32 = (uint32_t*)(cfgptr + 0x178); + val = *ptr32; + + if (val == 0xffffffff) { + device_printf(sc->dev, "extended mapping failed\n"); + pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); + return EIO; + } + *ptr32 = val | 0x40; + pmap_unmapdev((vm_offset_t)va, PAGE_SIZE); + device_printf(sc->dev, + "Enabled ECRC on upstream Nvidia bridge at %d:%d:%d\n", + (int)bus, (int)slot, (int)func); + return 0; +} +#else +static int +myri10ge_enable_nvidia_ecrc(myri10ge_softc_t *sc, device_t pdev) +{ + device_printf(sc->dev, + "Nforce 4 chipset on non-x86/amd64!?!?!\n"); + return ENXIO; +} +#endif +/* + * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput + * when the PCI-E Completion packets are aligned on an 8-byte + * boundary. Some PCI-E chip sets always align Completion packets; on + * the ones that do not, the alignment can be enforced by enabling + * ECRC generation (if supported). + * + * When PCI-E Completion packets are not aligned, it is actually more + * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. + * + * If the driver can neither enable ECRC nor verify that it has + * already been enabled, then it must use a firmware image which works + * around unaligned completion packets (ethp_z8e.dat), and it should + * also ensure that it never gives the device a Read-DMA which is + * larger than 2KB by setting the tx.boundary to 2KB. If ECRC is + * enabled, then the driver should use the aligned (eth_z8e.dat) + * firmware image, and set tx.boundary to 4KB. + */ + +static void +myri10ge_select_firmware(myri10ge_softc_t *sc) +{ + int err, aligned = 0; + device_t pdev; + uint16_t pvend, pdid; + + pdev = device_get_parent(device_get_parent(sc->dev)); + if (pdev == NULL) { + device_printf(sc->dev, "could not find parent?\n"); + goto abort; + } + pvend = pci_read_config(pdev, PCIR_VENDOR, 2); + pdid = pci_read_config(pdev, PCIR_DEVICE, 2); + + /* see if we can enable ECRC's on an upstream + Nvidia bridge */ + if (myri10ge_nvidia_ecrc_enable && + (pvend == 0x10de && pdid == 0x005d)) { + err = myri10ge_enable_nvidia_ecrc(sc, pdev); + if (err == 0) { + aligned = 1; + device_printf(sc->dev, + "Assuming aligned completions (ECRC)\n"); + } + } + /* see if the upstream bridge is known to + provided aligned completions */ + if (/* HT2000 */ (pvend == 0x1166 && pdid == 0x0132) || + /* Ontario */ (pvend == 0x10b5 && pdid == 0x8532)) { + device_printf(sc->dev, + "Assuming aligned completions (0x%x:0x%x)\n", + pvend, pdid); + } + +abort: + if (aligned) { + sc->fw_name = myri10ge_fw_aligned; + sc->tx.boundary = 4096; + } else { + sc->fw_name = myri10ge_fw_unaligned; + sc->tx.boundary = 2048; + } +} + +union qualhack +{ + const char *ro_char; + char *rw_char; +}; + + +static int +myri10ge_load_firmware_helper(myri10ge_softc_t *sc, uint32_t *limit) +{ + struct firmware *fw; + const mcp_gen_header_t *hdr; + unsigned hdr_offset; + const char *fw_data; + union qualhack hack; + int status; + + + fw = firmware_get(sc->fw_name); + + if (fw == NULL) { + device_printf(sc->dev, "Could not find firmware image %s\n", + sc->fw_name); + return ENOENT; + } + if (fw->datasize > *limit || + fw->datasize < MCP_HEADER_PTR_OFFSET + 4) { + device_printf(sc->dev, "Firmware image %s too large (%d/%d)\n", + sc->fw_name, (int)fw->datasize, (int) *limit); + status = ENOSPC; + goto abort_with_fw; + } + *limit = fw->datasize; + + /* check id */ + fw_data = (const char *)fw->data; + hdr_offset = htobe32(*(const uint32_t *) + (fw_data + MCP_HEADER_PTR_OFFSET)); + if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw->datasize) { + device_printf(sc->dev, "Bad firmware file"); + status = EIO; + goto abort_with_fw; + } + hdr = (const void*)(fw_data + hdr_offset); + if (be32toh(hdr->mcp_type) != MCP_TYPE_ETH) { + device_printf(sc->dev, "Bad firmware type: 0x%x\n", + be32toh(hdr->mcp_type)); + status = EIO; + goto abort_with_fw; + } + + /* save firmware version for sysctl */ + strncpy(sc->fw_version, hdr->version, sizeof (sc->fw_version)); + device_printf(sc->dev, "firmware id: %s\n", hdr->version); + + hack.ro_char = fw_data; + /* Copy the inflated firmware to NIC SRAM. */ + myri10ge_pio_copy(&sc->sram[MYRI10GE_FW_OFFSET], + hack.rw_char, *limit); + + status = 0; +abort_with_fw: + firmware_put(fw, FIRMWARE_UNLOAD); + return status; +} + +/* + * Enable or disable periodic RDMAs from the host to make certain + * chipsets resend dropped PCIe messages + */ + +static void +myri10ge_dummy_rdma(myri10ge_softc_t *sc, int enable) +{ + char buf_bytes[72]; + volatile uint32_t *confirm; + volatile char *submit; + uint32_t *buf, dma_low, dma_high; + int i; + + buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); + + /* clear confirmation addr */ + confirm = (volatile uint32_t *)sc->cmd; + *confirm = 0; + mb(); + + /* send an rdma command to the PCIe engine, and wait for the + response in the confirmation address. The firmware should + write a -1 there to indicate it is alive and well + */ + + dma_low = MYRI10GE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); + dma_high = MYRI10GE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); + buf[0] = htobe32(dma_high); /* confirm addr MSW */ + buf[1] = htobe32(dma_low); /* confirm addr LSW */ + buf[2] = htobe32(0xffffffff); /* confirm data */ + dma_low = MYRI10GE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr); + dma_high = MYRI10GE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr); + buf[3] = htobe32(dma_high); /* dummy addr MSW */ + buf[4] = htobe32(dma_low); /* dummy addr LSW */ + buf[5] = htobe32(enable); /* enable? */ + + + submit = (volatile char *)(sc->sram + 0xfc01c0); + + myri10ge_pio_copy(submit, buf, 64); + mb(); + DELAY(1000); + mb(); + i = 0; + while (*confirm != 0xffffffff && i < 20) { + DELAY(1000); + i++; + } + if (*confirm != 0xffffffff) { + device_printf(sc->dev, "dummy rdma %s failed (%p = 0x%x)", + (enable ? "enable" : "disable"), confirm, + *confirm); + } + return; +} + +static int +myri10ge_send_cmd(myri10ge_softc_t *sc, uint32_t cmd, + myri10ge_cmd_t *data) +{ + mcp_cmd_t *buf; + char buf_bytes[sizeof(*buf) + 8]; + volatile mcp_cmd_response_t *response = sc->cmd; + volatile char *cmd_addr = sc->sram + MYRI10GE_MCP_CMD_OFFSET; + uint32_t dma_low, dma_high; + int sleep_total = 0; + + /* ensure buf is aligned to 8 bytes */ + buf = (mcp_cmd_t *)((unsigned long)(buf_bytes + 7) & ~7UL); + + buf->data0 = htobe32(data->data0); + buf->data1 = htobe32(data->data1); + buf->data2 = htobe32(data->data2); + buf->cmd = htobe32(cmd); + dma_low = MYRI10GE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); + dma_high = MYRI10GE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); + + buf->response_addr.low = htobe32(dma_low); + buf->response_addr.high = htobe32(dma_high); + mtx_lock(&sc->cmd_lock); + response->result = 0xffffffff; + mb(); + myri10ge_pio_copy((volatile void *)cmd_addr, buf, sizeof (*buf)); + + /* wait up to 2 seconds */ + for (sleep_total = 0; sleep_total < (2 * 1000); sleep_total += 10) { + bus_dmamap_sync(sc->cmd_dma.dmat, + sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); + mb(); + if (response->result != 0xffffffff) { + if (response->result == 0) { + data->data0 = be32toh(response->data); + mtx_unlock(&sc->cmd_lock); + return 0; + } else { + device_printf(sc->dev, + "myri10ge: command %d " + "failed, result = %d\n", + cmd, be32toh(response->result)); + mtx_unlock(&sc->cmd_lock); + return ENXIO; + } + } + DELAY(1000 * 10); + } + mtx_unlock(&sc->cmd_lock); + device_printf(sc->dev, "myri10ge: command %d timed out" + "result = %d\n", + cmd, be32toh(response->result)); + return EAGAIN; +} + + +static int +myri10ge_load_firmware(myri10ge_softc_t *sc) +{ + volatile uint32_t *confirm; + volatile char *submit; + char buf_bytes[72]; + uint32_t *buf, size, dma_low, dma_high; + int status, i; + + buf = (uint32_t *)((unsigned long)(buf_bytes + 7) & ~7UL); + + size = sc->sram_size; + status = myri10ge_load_firmware_helper(sc, &size); + if (status) { + device_printf(sc->dev, "firmware loading failed\n"); + return status; + } + /* clear confirmation addr */ + confirm = (volatile uint32_t *)sc->cmd; + *confirm = 0; + mb(); + /* send a reload command to the bootstrap MCP, and wait for the + response in the confirmation address. The firmware should + write a -1 there to indicate it is alive and well + */ + + dma_low = MYRI10GE_LOWPART_TO_U32(sc->cmd_dma.bus_addr); + dma_high = MYRI10GE_HIGHPART_TO_U32(sc->cmd_dma.bus_addr); + + buf[0] = htobe32(dma_high); /* confirm addr MSW */ + buf[1] = htobe32(dma_low); /* confirm addr LSW */ + buf[2] = htobe32(0xffffffff); /* confirm data */ + + /* FIX: All newest firmware should un-protect the bottom of + the sram before handoff. However, the very first interfaces + do not. Therefore the handoff copy must skip the first 8 bytes + */ + /* where the code starts*/ + buf[3] = htobe32(MYRI10GE_FW_OFFSET + 8); + buf[4] = htobe32(size - 8); /* length of code */ + buf[5] = htobe32(8); /* where to copy to */ + buf[6] = htobe32(0); /* where to jump to */ + + submit = (volatile char *)(sc->sram + 0xfc0000); + myri10ge_pio_copy(submit, buf, 64); + mb(); + DELAY(1000); + mb(); + i = 0; + while (*confirm != 0xffffffff && i < 20) { + DELAY(1000*10); + i++; + bus_dmamap_sync(sc->cmd_dma.dmat, + sc->cmd_dma.map, BUS_DMASYNC_POSTREAD); + } + if (*confirm != 0xffffffff) { + device_printf(sc->dev,"handoff failed (%p = 0x%x)", + confirm, *confirm); + + return ENXIO; + } + myri10ge_dummy_rdma(sc, 1); + return 0; +} + +static int +myri10ge_update_mac_address(myri10ge_softc_t *sc) +{ + myri10ge_cmd_t cmd; + uint8_t *addr = sc->mac_addr; + int status; + + + cmd.data0 = ((addr[0] << 24) | (addr[1] << 16) + | (addr[2] << 8) | addr[3]); + + cmd.data1 = ((addr[4] << 8) | (addr[5])); + + status = myri10ge_send_cmd(sc, MYRI10GE_MCP_SET_MAC_ADDRESS, &cmd); + return status; +} + +static int +myri10ge_change_pause(myri10ge_softc_t *sc, int pause) +{ + myri10ge_cmd_t cmd; + int status; + + if (pause) + status = myri10ge_send_cmd(sc, + MYRI10GE_MCP_ENABLE_FLOW_CONTROL, + &cmd); + else + status = myri10ge_send_cmd(sc, + MYRI10GE_MCP_DISABLE_FLOW_CONTROL, + &cmd); + + if (status) { + device_printf(sc->dev, "Failed to set flow control mode\n"); + return ENXIO; + } + sc->pause = pause; + return 0; +} + +static void +myri10ge_change_promisc(myri10ge_softc_t *sc, int promisc) +{ + myri10ge_cmd_t cmd; + int status; + + if (promisc) + status = myri10ge_send_cmd(sc, + MYRI10GE_MCP_ENABLE_PROMISC, + &cmd); + else + status = myri10ge_send_cmd(sc, + MYRI10GE_MCP_DISABLE_PROMISC, + &cmd); + + if (status) { + device_printf(sc->dev, "Failed to set promisc mode\n"); + } +} + +static int +myri10ge_reset(myri10ge_softc_t *sc) +{ + + myri10ge_cmd_t cmd; + int status, i; + + /* try to send a reset command to the card to see if it + is alive */ + memset(&cmd, 0, sizeof (cmd)); + status = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_RESET, &cmd); + if (status != 0) { + device_printf(sc->dev, "failed reset\n"); + return ENXIO; + } + + /* Now exchange information about interrupts */ + + cmd.data0 = (uint32_t) + (myri10ge_max_intr_slots * sizeof (*sc->intr.q[0])); + status = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_SET_INTRQ_SIZE, &cmd); + for (i = 0; (status == 0) && (i < MYRI10GE_NUM_INTRQS); i++) { + cmd.data0 = MYRI10GE_LOWPART_TO_U32(sc->intr.dma[i].bus_addr); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(sc->intr.dma[i].bus_addr); + status |= + myri10ge_send_cmd(sc, (i + + MYRI10GE_MCP_CMD_SET_INTRQ0_DMA), + &cmd); + } + + cmd.data0 = sc->intr_coal_delay = myri10ge_intr_coal_delay; + status |= myri10ge_send_cmd(sc, + MYRI10GE_MCP_CMD_SET_INTR_COAL_DELAY, &cmd); + + if (sc->msi_enabled) { + status |= myri10ge_send_cmd + (sc, MYRI10GE_MCP_CMD_GET_IRQ_ACK_OFFSET, &cmd); + } else { + status |= myri10ge_send_cmd + (sc, MYRI10GE_MCP_CMD_GET_IRQ_ACK_DEASSERT_OFFSET, + &cmd); + } + if (status != 0) { + device_printf(sc->dev, "failed set interrupt parameters\n"); + return status; + } + sc->irq_claim = (volatile uint32_t *)(sc->sram + cmd.data0); + + /* reset mcp/driver shared state back to 0 */ + sc->intr.seqnum = 0; + sc->intr.intrq = 0; + sc->intr.slot = 0; + sc->tx.req = 0; + sc->tx.done = 0; + sc->rx_big.cnt = 0; + sc->rx_small.cnt = 0; + sc->rdma_tags_available = 15; + status = myri10ge_update_mac_address(sc); + myri10ge_change_promisc(sc, 0); + myri10ge_change_pause(sc, sc->pause); + return status; +} + +static int +myri10ge_change_intr_coal(SYSCTL_HANDLER_ARGS) +{ + myri10ge_cmd_t cmd; + myri10ge_softc_t *sc; + unsigned int intr_coal_delay; + int err; + + sc = arg1; + intr_coal_delay = sc->intr_coal_delay; + err = sysctl_handle_int(oidp, &intr_coal_delay, arg2, req); + if (err != 0) { + return err; + } + if (intr_coal_delay == sc->intr_coal_delay) + return 0; + + if (intr_coal_delay == 0 || intr_coal_delay > 1000*1000) + return EINVAL; + + sx_xlock(&sc->driver_lock); + cmd.data0 = intr_coal_delay; + err = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_SET_INTR_COAL_DELAY, + &cmd); + if (err == 0) { + sc->intr_coal_delay = intr_coal_delay; + } + sx_xunlock(&sc->driver_lock); + return err; +} + +static int +myri10ge_change_flow_control(SYSCTL_HANDLER_ARGS) +{ + myri10ge_softc_t *sc; + unsigned int enabled; + int err; + + sc = arg1; + enabled = sc->pause; + err = sysctl_handle_int(oidp, &enabled, arg2, req); + if (err != 0) { + return err; + } + if (enabled == sc->pause) + return 0; + + sx_xlock(&sc->driver_lock); + err = myri10ge_change_pause(sc, enabled); + sx_xunlock(&sc->driver_lock); + return err; +} + +static int +myri10ge_handle_be32(SYSCTL_HANDLER_ARGS) +{ + int err; + + if (arg1 == NULL) + return EFAULT; + arg2 = be32toh(*(int *)arg1); + arg1 = NULL; + err = sysctl_handle_int(oidp, arg1, arg2, req); + + return err; +} + +static void +myri10ge_add_sysctls(myri10ge_softc_t *sc) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *children; + mcp_stats_t *fw; + + ctx = device_get_sysctl_ctx(sc->dev); + children = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)); + fw = sc->fw_stats; + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "intr_coal_delay", + CTLTYPE_INT|CTLFLAG_RW, sc, + 0, myri10ge_change_intr_coal, + "I", "interrupt coalescing delay in usecs"); + + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "flow_control_enabled", + CTLTYPE_INT|CTLFLAG_RW, sc, + 0, myri10ge_change_flow_control, + "I", "interrupt coalescing delay in usecs"); + + SYSCTL_ADD_INT(ctx, children, OID_AUTO, + "skip_pio_read", + CTLFLAG_RW, &myri10ge_skip_pio_read, + 0, "Skip pio read in interrupt handler"); + + /* stats block from firmware is in network byte order. + Need to swap it */ + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "link_up", + CTLTYPE_INT|CTLFLAG_RD, &fw->link_up, + 0, myri10ge_handle_be32, + "I", "link up"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "rdma_tags_available", + CTLTYPE_INT|CTLFLAG_RD, &fw->rdma_tags_available, + 0, myri10ge_handle_be32, + "I", "rdma_tags_available"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_link_overflow", + CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_link_overflow, + 0, myri10ge_handle_be32, + "I", "dropped_link_overflow"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_link_error_or_filtered", + CTLTYPE_INT|CTLFLAG_RD, + &fw->dropped_link_error_or_filtered, + 0, myri10ge_handle_be32, + "I", "dropped_link_error_or_filtered"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_runt", + CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_runt, + 0, myri10ge_handle_be32, + "I", "dropped_runt"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_overrun", + CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_overrun, + 0, myri10ge_handle_be32, + "I", "dropped_overrun"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_no_small_buffer", + CTLTYPE_INT|CTLFLAG_RD, + &fw->dropped_no_small_buffer, + 0, myri10ge_handle_be32, + "I", "dropped_no_small_buffer"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_no_big_buffer", + CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_no_big_buffer, + 0, myri10ge_handle_be32, + "I", "dropped_no_big_buffer"); + SYSCTL_ADD_PROC(ctx, children, OID_AUTO, + "dropped_interrupt_busy", + CTLTYPE_INT|CTLFLAG_RD, &fw->dropped_interrupt_busy, + 0, myri10ge_handle_be32, + "I", "dropped_interrupt_busy"); + + /* host counters exported for debugging */ + SYSCTL_ADD_INT(ctx, children, OID_AUTO, + "tx_req", + CTLFLAG_RD, &sc->tx.req, + 0, "tx_req"); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, + "tx_done", + CTLFLAG_RD, &sc->tx.done, + 0, "tx_done"); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, + "rx_small_cnt", + CTLFLAG_RD, &sc->rx_small.cnt, + 0, "rx_small_cnt"); + SYSCTL_ADD_INT(ctx, children, OID_AUTO, + "rx_big_cnt", + CTLFLAG_RD, &sc->rx_big.cnt, + 0, "rx_small_cnt"); + +} + +/* copy an array of mcp_kreq_ether_send_t's to the mcp. Copy + backwards one at a time and handle ring wraps */ + +static inline void +myri10ge_submit_req_backwards(myri10ge_tx_buf_t *tx, + mcp_kreq_ether_send_t *src, int cnt) +{ + int idx, starting_slot; + starting_slot = tx->req; + while (cnt > 1) { + cnt--; + idx = (starting_slot + cnt) & tx->mask; + myri10ge_pio_copy(&tx->lanai[idx], + &src[cnt], sizeof(*src)); + mb(); + } +} + +/* + * copy an array of mcp_kreq_ether_send_t's to the mcp. Copy + * at most 32 bytes at a time, so as to avoid involving the software + * pio handler in the nic. We re-write the first segment's flags + * to mark them valid only after writing the entire chain + */ + +static inline void +myri10ge_submit_req(myri10ge_tx_buf_t *tx, mcp_kreq_ether_send_t *src, + int cnt) +{ + int idx, i; + uint32_t *src_ints; + volatile uint32_t *dst_ints; + mcp_kreq_ether_send_t *srcp; + volatile mcp_kreq_ether_send_t *dstp, *dst; + + + idx = tx->req & tx->mask; + + src->flags &= ~(htobe16(MYRI10GE_MCP_ETHER_FLAGS_VALID)); + mb(); + dst = dstp = &tx->lanai[idx]; + srcp = src; + + if ((idx + cnt) < tx->mask) { + for (i = 0; i < (cnt - 1); i += 2) { + myri10ge_pio_copy(dstp, srcp, 2 * sizeof(*src)); + mb(); /* force write every 32 bytes */ + srcp += 2; + dstp += 2; + } + } else { + /* submit all but the first request, and ensure + that it is submitted below */ + myri10ge_submit_req_backwards(tx, src, cnt); + i = 0; + } + if (i < cnt) { + /* submit the first request */ + myri10ge_pio_copy(dstp, srcp, sizeof(*src)); + mb(); /* barrier before setting valid flag */ + } + + /* re-write the last 32-bits with the valid flags */ + src->flags |= htobe16(MYRI10GE_MCP_ETHER_FLAGS_VALID); + src_ints = (uint32_t *)src; + src_ints+=3; + dst_ints = (volatile uint32_t *)dst; + dst_ints+=3; + *dst_ints = *src_ints; + tx->req += cnt; + mb(); +} + +static inline void +myri10ge_submit_req_wc(myri10ge_tx_buf_t *tx, + mcp_kreq_ether_send_t *src, int cnt) +{ + tx->req += cnt; + mb(); + while (cnt >= 4) { + myri10ge_pio_copy((volatile char *)tx->wc_fifo, src, 64); + mb(); + src += 4; + cnt -= 4; + } + if (cnt > 0) { + /* pad it to 64 bytes. The src is 64 bytes bigger than it + needs to be so that we don't overrun it */ + myri10ge_pio_copy(tx->wc_fifo + (cnt<<18), src, 64); + mb(); + } +} + +static void +myri10ge_encap(myri10ge_softc_t *sc, struct mbuf *m) +{ + mcp_kreq_ether_send_t *req; + bus_dma_segment_t seg_list[MYRI10GE_MCP_ETHER_MAX_SEND_DESC]; + bus_dma_segment_t *seg; + struct mbuf *m_tmp; + struct ifnet *ifp; + myri10ge_tx_buf_t *tx; + struct ether_header *eh; + struct ip *ip; + int cnt, cum_len, err, i, idx; + uint16_t flags, pseudo_hdr_offset; + uint8_t cksum_offset; + + + + ifp = sc->ifp; + tx = &sc->tx; + + /* (try to) map the frame for DMA */ + idx = tx->req & tx->mask; + err = bus_dmamap_load_mbuf_sg(tx->dmat, tx->info[idx].map, + m, seg_list, &cnt, + BUS_DMA_NOWAIT); + if (err == EFBIG) { + /* Too many segments in the chain. Try + to defrag */ + m_tmp = m_defrag(m, M_NOWAIT); + if (m_tmp == NULL) { + goto drop; + } + m = m_tmp; + err = bus_dmamap_load_mbuf_sg(tx->dmat, + tx->info[idx].map, + m, seg_list, &cnt, + BUS_DMA_NOWAIT); + } + if (err != 0) { + device_printf(sc->dev, "bus_dmamap_load_mbuf_sg returned %d\n", + err); + goto drop; + } + bus_dmamap_sync(tx->dmat, tx->info[idx].map, + BUS_DMASYNC_PREWRITE); + + req = tx->req_list; + cksum_offset = 0; + flags = htobe16(MYRI10GE_MCP_ETHER_FLAGS_VALID | + MYRI10GE_MCP_ETHER_FLAGS_NOT_LAST); + + /* checksum offloading? */ + if (m->m_pkthdr.csum_flags & (CSUM_DELAY_DATA)) { + eh = mtod(m, struct ether_header *); + ip = (struct ip *) (eh + 1); + cksum_offset = sizeof(*eh) + (ip->ip_hl << 2); + pseudo_hdr_offset = cksum_offset + m->m_pkthdr.csum_data; + req->pseudo_hdr_offset = htobe16(pseudo_hdr_offset); + req->cksum_offset = cksum_offset; + flags |= htobe16(MYRI10GE_MCP_ETHER_FLAGS_CKSUM); + } + if (m->m_pkthdr.len < 512) + req->flags = htobe16(MYRI10GE_MCP_ETHER_FLAGS_FIRST | + MYRI10GE_MCP_ETHER_FLAGS_SMALL); + else + req->flags = htobe16(MYRI10GE_MCP_ETHER_FLAGS_FIRST); + + /* convert segments into a request list */ + cum_len = 0; + seg = seg_list; + for (i = 0; i < cnt; i++) { + req->addr_low = + htobe32(MYRI10GE_LOWPART_TO_U32(seg->ds_addr)); + req->addr_high = + htobe32(MYRI10GE_HIGHPART_TO_U32(seg->ds_addr)); + req->length = htobe16(seg->ds_len); + req->cksum_offset = cksum_offset; + if (cksum_offset > seg->ds_len) + cksum_offset -= seg->ds_len; + else + cksum_offset = 0; + req->flags |= flags | ((cum_len & 1) * + htobe16(MYRI10GE_MCP_ETHER_FLAGS_ALIGN_ODD)); + cum_len += seg->ds_len; + seg++; + req++; + req->flags = 0; + } + req--; + /* pad runts to 60 bytes */ + if (cum_len < 60) { + req++; + req->addr_low = + htobe32(MYRI10GE_LOWPART_TO_U32(sc->zeropad_dma.bus_addr)); + req->addr_high = + htobe32(MYRI10GE_HIGHPART_TO_U32(sc->zeropad_dma.bus_addr)); + req->length = htobe16(60 - cum_len); + req->cksum_offset = cksum_offset; + req->flags |= flags | ((cum_len & 1) * + htobe16(MYRI10GE_MCP_ETHER_FLAGS_ALIGN_ODD)); + cnt++; + } + req->flags &= ~(htobe16(MYRI10GE_MCP_ETHER_FLAGS_NOT_LAST)); + tx->info[idx].m = m; + if (tx->wc_fifo == NULL) + myri10ge_submit_req(tx, tx->req_list, cnt); + else + myri10ge_submit_req_wc(tx, tx->req_list, cnt); + return; + +drop: + m_freem(m); + ifp->if_oerrors++; + return; +} + + +static void +myri10ge_start_locked(myri10ge_softc_t *sc) +{ + int avail; + struct mbuf *m; + struct ifnet *ifp; + + + ifp = sc->ifp; + while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { + /* dequeue the packet */ + IFQ_DRV_DEQUEUE(&ifp->if_snd, m); + + /* let BPF see it */ + BPF_MTAP(ifp, m); + + /* give it to the nic */ + myri10ge_encap(sc, m); + + /* leave an extra slot keep the ring from wrapping */ + avail = sc->tx.mask - (sc->tx.req - sc->tx.done); + if (avail < MYRI10GE_MCP_ETHER_MAX_SEND_DESC) { + sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE; + return; + } + } +} + +static void +myri10ge_start(struct ifnet *ifp) +{ + myri10ge_softc_t *sc = ifp->if_softc; + + + mtx_lock(&sc->tx_lock); + myri10ge_start_locked(sc); + mtx_unlock(&sc->tx_lock); +} + +static int +myri10ge_get_buf_small(myri10ge_softc_t *sc, bus_dmamap_t map, int idx) +{ + bus_dma_segment_t seg; + struct mbuf *m; + myri10ge_rx_buf_t *rx = &sc->rx_small; + int cnt, err; + + m = m_gethdr(M_DONTWAIT, MT_DATA); + if (m == NULL) { + rx->alloc_fail++; + err = ENOBUFS; + goto done; + } + m->m_len = MHLEN; + err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, + &seg, &cnt, BUS_DMA_NOWAIT); + if (err != 0) { + m_free(m); + goto done; + } + rx->info[idx].m = m; + rx->shadow[idx].addr_low = + htobe32(MYRI10GE_LOWPART_TO_U32(seg.ds_addr)); + rx->shadow[idx].addr_high = + htobe32(MYRI10GE_HIGHPART_TO_U32(seg.ds_addr)); + +done: + if ((idx & 7) == 7) { + myri10ge_pio_copy(&rx->lanai[idx - 7], + &rx->shadow[idx - 7], + 8 * sizeof (*rx->lanai)); + mb(); + } + return err; +} + +static int +myri10ge_get_buf_big(myri10ge_softc_t *sc, bus_dmamap_t map, int idx) +{ + bus_dma_segment_t seg; + struct mbuf *m; + myri10ge_rx_buf_t *rx = &sc->rx_big; + int cnt, err; + + m = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, sc->big_bytes); + if (m == NULL) { + rx->alloc_fail++; + err = ENOBUFS; + goto done; + } + m->m_len = sc->big_bytes; + err = bus_dmamap_load_mbuf_sg(rx->dmat, map, m, + &seg, &cnt, BUS_DMA_NOWAIT); + if (err != 0) { + m_free(m); + goto done; + } + rx->info[idx].m = m; + rx->shadow[idx].addr_low = + htobe32(MYRI10GE_LOWPART_TO_U32(seg.ds_addr)); + rx->shadow[idx].addr_high = + htobe32(MYRI10GE_HIGHPART_TO_U32(seg.ds_addr)); + +done: + if ((idx & 7) == 7) { + myri10ge_pio_copy(&rx->lanai[idx - 7], + &rx->shadow[idx - 7], + 8 * sizeof (*rx->lanai)); + mb(); + } + return err; +} + +static inline void +myri10ge_rx_done_big(myri10ge_softc_t *sc, int len, int csum, int flags) +{ + struct ifnet *ifp; + struct mbuf *m = 0; /* -Wunitialized */ + struct mbuf *m_prev = 0; /* -Wunitialized */ + struct mbuf *m_head = 0; + bus_dmamap_t old_map; + myri10ge_rx_buf_t *rx; + int idx; + + + rx = &sc->rx_big; + ifp = sc->ifp; + while (len > 0) { + idx = rx->cnt & rx->mask; + rx->cnt++; + /* save a pointer to the received mbuf */ + m = rx->info[idx].m; + /* try to replace the received mbuf */ + if (myri10ge_get_buf_big(sc, rx->extra_map, idx)) { + goto drop; + } + /* unmap the received buffer */ + old_map = rx->info[idx].map; + bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rx->dmat, old_map); + + /* swap the bus_dmamap_t's */ + rx->info[idx].map = rx->extra_map; + rx->extra_map = old_map; + + /* chain multiple segments together */ + if (!m_head) { + m_head = m; + /* mcp implicitly skips 1st bytes so that + * packet is properly aligned */ + m->m_data += MYRI10GE_MCP_ETHER_PAD; + m->m_pkthdr.len = len; + m->m_len = sc->big_bytes - MYRI10GE_MCP_ETHER_PAD; + } else { + m->m_len = sc->big_bytes; + m->m_flags &= ~M_PKTHDR; + m_prev->m_next = m; + } + len -= m->m_len; + m_prev = m; + } + + /* trim trailing garbage from the last mbuf in the chain. If + * there is any garbage, len will be negative */ + m->m_len += len; + + /* if the checksum is valid, mark it in the mbuf header */ + if (sc->csum_flag & flags) { + m_head->m_pkthdr.csum_data = csum; + m_head->m_pkthdr.csum_flags = CSUM_DATA_VALID; + } + + /* pass the frame up the stack */ + m_head->m_pkthdr.rcvif = ifp; + ifp->if_ipackets++; + (*ifp->if_input)(ifp, m_head); + return; + +drop: + /* drop the frame -- the old mbuf(s) are re-cycled by running + every slot through the allocator */ + if (m_head) { + len -= sc->big_bytes; + m_freem(m_head); + } else { + len -= (sc->big_bytes + MYRI10GE_MCP_ETHER_PAD); + } + while ((int)len > 0) { + idx = rx->cnt & rx->mask; + rx->cnt++; + m = rx->info[idx].m; + if (0 == (myri10ge_get_buf_big(sc, rx->extra_map, idx))) { + m_freem(m); + /* unmap the received buffer */ + old_map = rx->info[idx].map; + bus_dmamap_sync(rx->dmat, old_map, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rx->dmat, old_map); + + /* swap the bus_dmamap_t's */ + rx->info[idx].map = rx->extra_map; + rx->extra_map = old_map; + } + len -= sc->big_bytes; + } + + ifp->if_ierrors++; + +} + + +static inline void +myri10ge_rx_done_small(myri10ge_softc_t *sc, uint32_t len, + uint32_t csum, uint32_t flags) +{ + struct ifnet *ifp; + struct mbuf *m; + myri10ge_rx_buf_t *rx; + bus_dmamap_t old_map; + int idx; + + ifp = sc->ifp; + rx = &sc->rx_small; + idx = rx->cnt & rx->mask; + rx->cnt++; + /* save a pointer to the received mbuf */ + m = rx->info[idx].m; + /* try to replace the received mbuf */ + if (myri10ge_get_buf_small(sc, rx->extra_map, idx)) { + /* drop the frame -- the old mbuf is re-cycled */ + ifp->if_ierrors++; + return; + } + + /* unmap the received buffer */ + old_map = rx->info[idx].map; + bus_dmamap_sync(rx->dmat, old_map, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(rx->dmat, old_map); + + /* swap the bus_dmamap_t's */ + rx->info[idx].map = rx->extra_map; + rx->extra_map = old_map; + + /* mcp implicitly skips 1st 2 bytes so that packet is properly + * aligned */ + m->m_data += MYRI10GE_MCP_ETHER_PAD; + + /* if the checksum is valid, mark it in the mbuf header */ + if (sc->csum_flag & flags) { + m->m_pkthdr.csum_data = csum; + m->m_pkthdr.csum_flags = CSUM_DATA_VALID; + } + + /* pass the frame up the stack */ + m->m_pkthdr.rcvif = ifp; + m->m_len = m->m_pkthdr.len = len; + ifp->if_ipackets++; + (*ifp->if_input)(ifp, m); +} + +static inline void +myri10ge_tx_done(myri10ge_softc_t *sc, uint32_t mcp_idx) +{ + struct ifnet *ifp; + myri10ge_tx_buf_t *tx; + struct mbuf *m; + bus_dmamap_t map; + int idx; + + tx = &sc->tx; + ifp = sc->ifp; + while (tx->done != mcp_idx) { + idx = tx->done & tx->mask; + tx->done++; + m = tx->info[idx].m; + /* mbuf and DMA map only attached to the first + segment per-mbuf */ + if (m != NULL) { + ifp->if_opackets++; + tx->info[idx].m = NULL; + map = tx->info[idx].map; + bus_dmamap_unload(tx->dmat, map); + m_freem(m); + } + } + + /* If we have space, clear IFF_OACTIVE to tell the stack that + its OK to send packets */ + + if (ifp->if_drv_flags & IFF_DRV_OACTIVE && + tx->req - tx->done < (tx->mask + 1)/4) { + mtx_lock(&sc->tx_lock); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + myri10ge_start_locked(sc); + mtx_unlock(&sc->tx_lock); + } +} + +static void +myri10ge_dump_interrupt_queues(myri10ge_softc_t *sc, int maxslot) +{ + int intrq, slot, type; + static int call_cnt = 0; + + /* only do it a few times to avoid filling the message buffer */ + if (call_cnt > 10) + return; + + call_cnt++; + + device_printf(sc->dev, "--------- Dumping interrupt queue state ----- \n"); + device_printf(sc->dev, "currently expecting interrupts on queue %d\n", + sc->intr.intrq); + device_printf(sc->dev, " q slot status \n"); + device_printf(sc->dev, "--- ---- -------- \n"); + for (intrq = 0; intrq < 2; intrq++) { + for (slot = 0; slot <= maxslot; slot++) { + type = sc->intr.q[intrq][slot].type; +#if 0 + if (type == 0 && slot != 0) + continue; +#endif + device_printf(sc->dev, "[%d]:[%d]: type = 0x%x\n", intrq, slot, + type); + device_printf(sc->dev, "[%d]:[%d]: flag = 0x%x\n", intrq, slot, + sc->intr.q[intrq][slot].flag); + device_printf(sc->dev, "[%d]:[%d]: index = 0x%x\n", intrq, slot, + be16toh(sc->intr.q[intrq][slot].index)); + device_printf(sc->dev, "[%d]:[%d]: seqnum = 0x%x\n", intrq, slot, + (unsigned int)be32toh(sc->intr.q[intrq][slot].seqnum)); + device_printf(sc->dev, "[%d]:[%d]: data0 = 0x%x\n", intrq, slot, + (unsigned int)be32toh(sc->intr.q[intrq][slot].data0)); + device_printf(sc->dev, "[%d]:[%d]: data1 = 0x%x\n", intrq, slot, + (unsigned int)be32toh(sc->intr.q[intrq][slot].data1)); + + } + } + +} + +static inline void +myri10ge_claim_irq(myri10ge_softc_t *sc) +{ + volatile uint32_t dontcare; + + + *sc->irq_claim = 0; + mb(); + + /* do a PIO read to ensure that PIO write to claim the irq has + hit the nic before we exit the interrupt handler */ + if (!myri10ge_skip_pio_read) { + dontcare = *(volatile uint32_t *)sc->sram; + mb(); + } +} + +static void +myri10ge_intr(void *arg) +{ + myri10ge_softc_t *sc = arg; + int intrq, claimed, flags, count, length, ip_csum; + uint32_t raw, slot; + uint8_t type; + + + intrq = sc->intr.intrq; + claimed = 0; + bus_dmamap_sync(sc->intr.dma[intrq].dmat, + sc->intr.dma[intrq].map, BUS_DMASYNC_POSTREAD); + if (sc->msi_enabled) { + /* We know we can immediately claim the interrupt */ + myri10ge_claim_irq(sc); + claimed = 1; + } else { + /* Check to see if we have the last event in the queue + ready. If so, ack it as early as possible. This + allows more time to get the interrupt line + de-asserted prior to the EOI and reduces the chance + of seeing a spurious irq caused by the interrupt + line remaining high after EOI */ + + slot = be16toh(sc->intr.q[intrq][0].index) - 1; + if (slot < myri10ge_max_intr_slots && + sc->intr.q[intrq][slot].type != 0 && + sc->intr.q[intrq][slot].flag != 0) { + myri10ge_claim_irq(sc); + claimed = 1; + } + } + + /* walk each slot in the current queue, processing events until + we reach an event with a zero type */ + for (slot = sc->intr.slot; slot < myri10ge_max_intr_slots; slot++) { + type = sc->intr.q[intrq][slot].type; + + /* check for partially completed DMA of events when + using non-MSI interrupts */ + if (__predict_false(!claimed)) { + mb(); + /* look if there is somscing in the queue */ + if (type == 0) { + /* save the current slot for the next + * time we (re-)enter this routine */ + if (sc->intr.slot == slot) { + sc->intr.spurious++; + } + sc->intr.slot = slot; + return; + } + } + if (__predict_false(htobe32(sc->intr.q[intrq][slot].seqnum) != + sc->intr.seqnum++)) { + device_printf(sc->dev, "Bad interrupt!\n"); + device_printf(sc->dev, + "bad irq seqno" + "(got 0x%x, expected 0x%x) \n", + (unsigned int)htobe32(sc->intr.q[intrq][slot].seqnum), + sc->intr.seqnum); + device_printf(sc->dev, "intrq = %d, slot = %d\n", + intrq, slot); + myri10ge_dump_interrupt_queues(sc, slot); + device_printf(sc->dev, + "Disabling futher interrupt handling\n"); + bus_teardown_intr(sc->dev, sc->irq_res, + sc->ih); + sc->ih = NULL; + return; + } + + switch (type) { + case MYRI10GE_MCP_INTR_ETHER_SEND_DONE: + myri10ge_tx_done(sc, be32toh(sc->intr.q[intrq][slot].data0)); + + if (__predict_true(sc->intr.q[intrq][slot].data1 == 0)) + break; + + /* check the link state. Don't bother to + * byteswap, since it can just be 0 or 1 */ + if (sc->link_state != sc->fw_stats->link_up) { + sc->link_state = sc->fw_stats->link_up; + if (sc->link_state) { + if_link_state_change(sc->ifp, + LINK_STATE_UP); + device_printf(sc->dev, + "link up\n"); + } else { + if_link_state_change(sc->ifp, + LINK_STATE_DOWN); + device_printf(sc->dev, + "link down\n"); + } + } + if (sc->rdma_tags_available != + be32toh(sc->fw_stats->rdma_tags_available)) { + sc->rdma_tags_available = + be32toh(sc->fw_stats->rdma_tags_available); + device_printf(sc->dev, "RDMA timed out!" + " %d tags left\n", + sc->rdma_tags_available); + } + + break; + + + case MYRI10GE_MCP_INTR_ETHER_RECV_SMALL: + raw = be32toh(sc->intr.q[intrq][slot].data0); + count = 0xff & raw; + flags = raw >> 8; + raw = be32toh(sc->intr.q[intrq][slot].data1); + ip_csum = raw >> 16; + length = 0xffff & raw; + myri10ge_rx_done_small(sc, length, ip_csum, + flags); + break; + + case MYRI10GE_MCP_INTR_ETHER_RECV_BIG: + raw = be32toh(sc->intr.q[intrq][slot].data0); + count = 0xff & raw; + flags = raw >> 8; + raw = be32toh(sc->intr.q[intrq][slot].data1); + ip_csum = raw >> 16; + length = 0xffff & raw; + myri10ge_rx_done_big(sc, length, ip_csum, + flags); + + break; + + case MYRI10GE_MCP_INTR_LINK_CHANGE: + /* not yet implemented in firmware */ + break; + + case MYRI10GE_MCP_INTR_ETHER_DOWN: + sc->down_cnt++; + wakeup(&sc->down_cnt); + break; + + default: + device_printf(sc->dev, "Unknown interrupt type %d\n", + type); + } + sc->intr.q[intrq][slot].type = 0; + if (sc->intr.q[intrq][slot].flag != 0) { + if (!claimed) { + myri10ge_claim_irq(sc); + } + sc->intr.slot = 0; + sc->intr.q[intrq][slot].flag = 0; + sc->intr.intrq = ((intrq + 1) & 1); + return; + } + } + + /* we should never be here unless we're on a shared irq and we have + not finished setting up the device */ + return; +} + +static void +myri10ge_watchdog(struct ifnet *ifp) +{ + printf("%s called\n", __FUNCTION__); +} + +static void +myri10ge_init(void *arg) +{ +} + + + +static void +myri10ge_free_mbufs(myri10ge_softc_t *sc) +{ + int i; + + for (i = 0; i <= sc->rx_big.mask; i++) { + if (sc->rx_big.info[i].m == NULL) + continue; + bus_dmamap_unload(sc->rx_big.dmat, + sc->rx_big.info[i].map); + m_freem(sc->rx_big.info[i].m); + sc->rx_big.info[i].m = NULL; + } + + for (i = 0; i <= sc->rx_big.mask; i++) { + if (sc->rx_big.info[i].m == NULL) + continue; + bus_dmamap_unload(sc->rx_big.dmat, + sc->rx_big.info[i].map); + m_freem(sc->rx_big.info[i].m); + sc->rx_big.info[i].m = NULL; + } + + for (i = 0; i <= sc->tx.mask; i++) { + if (sc->tx.info[i].m == NULL) + continue; + bus_dmamap_unload(sc->tx.dmat, + sc->tx.info[i].map); + m_freem(sc->tx.info[i].m); + sc->tx.info[i].m = NULL; + } +} + +static void +myri10ge_free_rings(myri10ge_softc_t *sc) +{ + int i; + + if (sc->tx.req_bytes != NULL) { + free(sc->tx.req_bytes, M_DEVBUF); + } + if (sc->rx_small.shadow != NULL) + free(sc->rx_small.shadow, M_DEVBUF); + if (sc->rx_big.shadow != NULL) + free(sc->rx_big.shadow, M_DEVBUF); + if (sc->tx.info != NULL) { + for (i = 0; i <= sc->tx.mask; i++) { + if (sc->tx.info[i].map != NULL) + bus_dmamap_destroy(sc->tx.dmat, + sc->tx.info[i].map); + } + free(sc->tx.info, M_DEVBUF); + } + if (sc->rx_small.info != NULL) { + for (i = 0; i <= sc->rx_small.mask; i++) { + if (sc->rx_small.info[i].map != NULL) + bus_dmamap_destroy(sc->rx_small.dmat, + sc->rx_small.info[i].map); + } + free(sc->rx_small.info, M_DEVBUF); + } + if (sc->rx_big.info != NULL) { + for (i = 0; i <= sc->rx_big.mask; i++) { + if (sc->rx_big.info[i].map != NULL) + bus_dmamap_destroy(sc->rx_big.dmat, + sc->rx_big.info[i].map); + } + free(sc->rx_big.info, M_DEVBUF); + } + if (sc->rx_big.extra_map != NULL) + bus_dmamap_destroy(sc->rx_big.dmat, + sc->rx_big.extra_map); + if (sc->rx_small.extra_map != NULL) + bus_dmamap_destroy(sc->rx_small.dmat, + sc->rx_small.extra_map); + if (sc->tx.dmat != NULL) + bus_dma_tag_destroy(sc->tx.dmat); + if (sc->rx_small.dmat != NULL) + bus_dma_tag_destroy(sc->rx_small.dmat); + if (sc->rx_big.dmat != NULL) + bus_dma_tag_destroy(sc->rx_big.dmat); +} + +static int +myri10ge_alloc_rings(myri10ge_softc_t *sc) +{ + myri10ge_cmd_t cmd; + int tx_ring_size, rx_ring_size; + int tx_ring_entries, rx_ring_entries; + int i, err; + unsigned long bytes; + + /* get ring sizes */ + err = myri10ge_send_cmd(sc, + MYRI10GE_MCP_CMD_GET_SEND_RING_SIZE, + &cmd); + tx_ring_size = cmd.data0; + err |= myri10ge_send_cmd(sc, + MYRI10GE_MCP_CMD_GET_RX_RING_SIZE, + &cmd); + if (err != 0) { + device_printf(sc->dev, "Cannot determine ring sizes\n"); + goto abort_with_nothing; + } + + rx_ring_size = cmd.data0; + + tx_ring_entries = tx_ring_size / sizeof (mcp_kreq_ether_send_t); + rx_ring_entries = rx_ring_size / sizeof (mcp_dma_addr_t); + sc->ifp->if_snd.ifq_maxlen = tx_ring_entries - 1; + sc->ifp->if_snd.ifq_drv_maxlen = sc->ifp->if_snd.ifq_maxlen; + + sc->tx.mask = tx_ring_entries - 1; + sc->rx_small.mask = sc->rx_big.mask = rx_ring_entries - 1; + + err = ENOMEM; + + /* allocate the tx request copy block */ + bytes = 8 + + sizeof (*sc->tx.req_list) * (MYRI10GE_MCP_ETHER_MAX_SEND_DESC + 4); + sc->tx.req_bytes = malloc(bytes, M_DEVBUF, M_WAITOK); + if (sc->tx.req_bytes == NULL) + goto abort_with_nothing; + /* ensure req_list entries are aligned to 8 bytes */ + sc->tx.req_list = (mcp_kreq_ether_send_t *) + ((unsigned long)(sc->tx.req_bytes + 7) & ~7UL); + + /* allocate the rx shadow rings */ + bytes = rx_ring_entries * sizeof (*sc->rx_small.shadow); + sc->rx_small.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); + if (sc->rx_small.shadow == NULL) + goto abort_with_alloc; + + bytes = rx_ring_entries * sizeof (*sc->rx_big.shadow); + sc->rx_big.shadow = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); + if (sc->rx_big.shadow == NULL) + goto abort_with_alloc; + + /* allocate the host info rings */ + bytes = tx_ring_entries * sizeof (*sc->tx.info); + sc->tx.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); + if (sc->tx.info == NULL) + goto abort_with_alloc; + + bytes = rx_ring_entries * sizeof (*sc->rx_small.info); + sc->rx_small.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); + if (sc->rx_small.info == NULL) + goto abort_with_alloc; + + bytes = rx_ring_entries * sizeof (*sc->rx_big.info); + sc->rx_big.info = malloc(bytes, M_DEVBUF, M_ZERO|M_WAITOK); + if (sc->rx_big.info == NULL) + goto abort_with_alloc; + + /* allocate the busdma resources */ + err = bus_dma_tag_create(sc->parent_dmat, /* parent */ + 1, /* alignment */ + sc->tx.boundary, /* boundary */ + BUS_SPACE_MAXADDR, /* low */ + BUS_SPACE_MAXADDR, /* high */ + NULL, NULL, /* filter */ + MYRI10GE_MAX_ETHER_MTU,/* maxsize */ + MYRI10GE_MCP_ETHER_MAX_SEND_DESC,/* num segs */ + sc->tx.boundary, /* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + NULL, NULL, /* lock */ + &sc->tx.dmat); /* tag */ + + if (err != 0) { + device_printf(sc->dev, "Err %d allocating tx dmat\n", + err); + goto abort_with_alloc; + } + + err = bus_dma_tag_create(sc->parent_dmat, /* parent */ + 1, /* alignment */ + 4096, /* boundary */ + BUS_SPACE_MAXADDR, /* low */ + BUS_SPACE_MAXADDR, /* high */ + NULL, NULL, /* filter */ + MHLEN, /* maxsize */ + 1, /* num segs */ + MHLEN, /* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + NULL, NULL, /* lock */ + &sc->rx_small.dmat); /* tag */ + if (err != 0) { + device_printf(sc->dev, "Err %d allocating rx_small dmat\n", + err); + goto abort_with_alloc; + } + + err = bus_dma_tag_create(sc->parent_dmat, /* parent */ + 1, /* alignment */ + 4096, /* boundary */ + BUS_SPACE_MAXADDR, /* low */ + BUS_SPACE_MAXADDR, /* high */ + NULL, NULL, /* filter */ + 4096, /* maxsize */ + 1, /* num segs */ + 4096, /* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ + NULL, NULL, /* lock */ + &sc->rx_big.dmat); /* tag */ + if (err != 0) { + device_printf(sc->dev, "Err %d allocating rx_big dmat\n", + err); + goto abort_with_alloc; + } + + /* now use these tags to setup dmamaps for each slot + in each ring */ + for (i = 0; i <= sc->tx.mask; i++) { + err = bus_dmamap_create(sc->tx.dmat, 0, + &sc->tx.info[i].map); + if (err != 0) { + device_printf(sc->dev, "Err %d tx dmamap\n", + err); + goto abort_with_alloc; + } + } + for (i = 0; i <= sc->rx_small.mask; i++) { + err = bus_dmamap_create(sc->rx_small.dmat, 0, + &sc->rx_small.info[i].map); + if (err != 0) { + device_printf(sc->dev, "Err %d rx_small dmamap\n", + err); + goto abort_with_alloc; + } + } + err = bus_dmamap_create(sc->rx_small.dmat, 0, + &sc->rx_small.extra_map); + if (err != 0) { + device_printf(sc->dev, "Err %d extra rx_small dmamap\n", + err); + goto abort_with_alloc; + } + + for (i = 0; i <= sc->rx_big.mask; i++) { + err = bus_dmamap_create(sc->rx_big.dmat, 0, + &sc->rx_big.info[i].map); + if (err != 0) { + device_printf(sc->dev, "Err %d rx_big dmamap\n", + err); + goto abort_with_alloc; + } + } + err = bus_dmamap_create(sc->rx_big.dmat, 0, + &sc->rx_big.extra_map); + if (err != 0) { + device_printf(sc->dev, "Err %d extra rx_big dmamap\n", + err); + goto abort_with_alloc; + } + return 0; + +abort_with_alloc: + myri10ge_free_rings(sc); + +abort_with_nothing: + return err; +} + +static int +myri10ge_open(myri10ge_softc_t *sc) +{ + myri10ge_cmd_t cmd; + int i, err; + bus_dmamap_t map; + + + err = myri10ge_reset(sc); + if (err != 0) { + device_printf(sc->dev, "failed to reset\n"); + return EIO; + } + + if (MCLBYTES >= + sc->ifp->if_mtu + ETHER_HDR_LEN + MYRI10GE_MCP_ETHER_PAD) + sc->big_bytes = MCLBYTES; + else + sc->big_bytes = MJUMPAGESIZE; + + err = myri10ge_alloc_rings(sc); + if (err != 0) { + device_printf(sc->dev, "failed to allocate rings\n"); + return err; + } + + err = bus_setup_intr(sc->dev, sc->irq_res, + INTR_TYPE_NET | INTR_MPSAFE, + myri10ge_intr, sc, &sc->ih); + if (err != 0) { + goto abort_with_rings; + } + + /* get the lanai pointers to the send and receive rings */ + + err = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_GET_SEND_OFFSET, &cmd); + sc->tx.lanai = + (volatile mcp_kreq_ether_send_t *)(sc->sram + cmd.data0); + err |= myri10ge_send_cmd(sc, + MYRI10GE_MCP_CMD_GET_SMALL_RX_OFFSET, &cmd); + sc->rx_small.lanai = + (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); + err |= myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_GET_BIG_RX_OFFSET, &cmd); + sc->rx_big.lanai = + (volatile mcp_kreq_ether_recv_t *)(sc->sram + cmd.data0); + + if (err != 0) { + device_printf(sc->dev, + "failed to get ring sizes or locations\n"); + err = EIO; + goto abort_with_irq; + } + + if (sc->wc) { + sc->tx.wc_fifo = sc->sram + 0x200000; + sc->rx_small.wc_fifo = sc->sram + 0x300000; + sc->rx_big.wc_fifo = sc->sram + 0x340000; + } else { + sc->tx.wc_fifo = 0; + sc->rx_small.wc_fifo = 0; + sc->rx_big.wc_fifo = 0; + } + + + /* stock receive rings */ + for (i = 0; i <= sc->rx_small.mask; i++) { + map = sc->rx_small.info[i].map; + err = myri10ge_get_buf_small(sc, map, i); + if (err) { + device_printf(sc->dev, "alloced %d/%d smalls\n", + i, sc->rx_small.mask + 1); + goto abort; + } + } + for (i = 0; i <= sc->rx_big.mask; i++) { + map = sc->rx_big.info[i].map; + err = myri10ge_get_buf_big(sc, map, i); + if (err) { + device_printf(sc->dev, "alloced %d/%d bigs\n", + i, sc->rx_big.mask + 1); + goto abort; + } + } + + /* Give the firmware the mtu and the big and small buffer + sizes. The firmware wants the big buf size to be a power + of two. Luckily, FreeBSD's clusters are powers of two */ + cmd.data0 = sc->ifp->if_mtu + ETHER_HDR_LEN; + err = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_SET_MTU, &cmd); + cmd.data0 = MHLEN; + err |= myri10ge_send_cmd(sc, + MYRI10GE_MCP_CMD_SET_SMALL_BUFFER_SIZE, + &cmd); + cmd.data0 = sc->big_bytes; + err |= myri10ge_send_cmd(sc, + MYRI10GE_MCP_CMD_SET_BIG_BUFFER_SIZE, + &cmd); + /* Now give him the pointer to the stats block */ + cmd.data0 = MYRI10GE_LOWPART_TO_U32(sc->fw_stats_dma.bus_addr); + cmd.data1 = MYRI10GE_HIGHPART_TO_U32(sc->fw_stats_dma.bus_addr); + err = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_SET_STATS_DMA, &cmd); + + if (err != 0) { + device_printf(sc->dev, "failed to setup params\n"); + goto abort; + } + + /* Finally, start the firmware running */ + err = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_ETHERNET_UP, &cmd); + if (err) { + device_printf(sc->dev, "Couldn't bring up link\n"); + goto abort; + } + sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; + sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + + return 0; + + +abort: + myri10ge_free_mbufs(sc); +abort_with_irq: + bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); +abort_with_rings: + myri10ge_free_rings(sc); + return err; +} + +static int +myri10ge_close(myri10ge_softc_t *sc) +{ + myri10ge_cmd_t cmd; + int err, old_down_cnt; + + sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + old_down_cnt = sc->down_cnt; + mb(); + err = myri10ge_send_cmd(sc, MYRI10GE_MCP_CMD_ETHERNET_DOWN, &cmd); + if (err) { + device_printf(sc->dev, "Couldn't bring down link\n"); + } + if (old_down_cnt == sc->down_cnt) { + /* wait for down irq */ + (void)tsleep(&sc->down_cnt, PWAIT, "down myri10ge", hz); + } + if (old_down_cnt == sc->down_cnt) { + device_printf(sc->dev, "never got down irq\n"); + } + if (sc->ih != NULL) + bus_teardown_intr(sc->dev, sc->irq_res, sc->ih); + myri10ge_free_mbufs(sc); + myri10ge_free_rings(sc); + return 0; +} + + +static int +myri10ge_media_change(struct ifnet *ifp) +{ + return EINVAL; +} + +static int +myri10ge_change_mtu(myri10ge_softc_t *sc, int mtu) +{ + struct ifnet *ifp = sc->ifp; + int real_mtu, old_mtu; + int err = 0; + + + real_mtu = mtu + ETHER_HDR_LEN; + if ((real_mtu > MYRI10GE_MAX_ETHER_MTU) || + real_mtu < 60) + return EINVAL; + sx_xlock(&sc->driver_lock); + old_mtu = ifp->if_mtu; + ifp->if_mtu = mtu; + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + myri10ge_close(sc); + err = myri10ge_open(sc); + if (err != 0) { + ifp->if_mtu = old_mtu; + myri10ge_close(sc); + (void) myri10ge_open(sc); + } + } + sx_xunlock(&sc->driver_lock); + return err; +} + +static void +myri10ge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + myri10ge_softc_t *sc = ifp->if_softc; + + + if (sc == NULL) + return; + ifmr->ifm_status = IFM_AVALID; + ifmr->ifm_status |= sc->fw_stats->link_up ? IFM_ACTIVE : 0; + ifmr->ifm_active = IFM_AUTO | IFM_ETHER; + ifmr->ifm_active |= sc->fw_stats->link_up ? IFM_FDX : 0; +} + +static int +myri10ge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) +{ + myri10ge_softc_t *sc = ifp->if_softc; + struct ifreq *ifr = (struct ifreq *)data; + int err, mask; + + err = 0; + switch (command) { + case SIOCSIFADDR: + case SIOCGIFADDR: + err = ether_ioctl(ifp, command, data); + break; + + case SIOCSIFMTU: + err = myri10ge_change_mtu(sc, ifr->ifr_mtu); + break; + + case SIOCSIFFLAGS: + sx_xlock(&sc->driver_lock); + if (ifp->if_flags & IFF_UP) { + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) + err = myri10ge_open(sc); + } else { + if (ifp->if_drv_flags & IFF_DRV_RUNNING) + myri10ge_close(sc); + } + sx_xunlock(&sc->driver_lock); + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + err = 0; + break; + + case SIOCSIFCAP: + sx_xlock(&sc->driver_lock); + mask = ifr->ifr_reqcap ^ ifp->if_capenable; + if (mask & IFCAP_TXCSUM) { + if (IFCAP_TXCSUM & ifp->if_capenable) { + ifp->if_capenable &= ~IFCAP_TXCSUM; + ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP); + } else { + ifp->if_capenable |= IFCAP_TXCSUM; + ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); + } + } else if (mask & IFCAP_RXCSUM) { + if (IFCAP_RXCSUM & ifp->if_capenable) { + ifp->if_capenable &= ~IFCAP_RXCSUM; + sc->csum_flag &= ~MYRI10GE_MCP_ETHER_FLAGS_CKSUM; + } else { + ifp->if_capenable |= IFCAP_RXCSUM; + sc->csum_flag |= MYRI10GE_MCP_ETHER_FLAGS_CKSUM; + } + } + sx_xunlock(&sc->driver_lock); + break; + + case SIOCGIFMEDIA: + err = ifmedia_ioctl(ifp, (struct ifreq *)data, + &sc->media, command); + break; + + default: + err = ENOTTY; + } + return err; +} + +static void +myri10ge_fetch_tunables(myri10ge_softc_t *sc) +{ + + TUNABLE_INT_FETCH("hw.myri10ge.flow_control_enabled", + &myri10ge_flow_control); + TUNABLE_INT_FETCH("hw.myri10ge.intr_coal_delay", + &myri10ge_intr_coal_delay); + TUNABLE_INT_FETCH("hw.myri10ge.nvidia_ecrc_enable", + &myri10ge_nvidia_ecrc_enable); + TUNABLE_INT_FETCH("hw.myri10ge.skip_pio_read", + &myri10ge_skip_pio_read); + + if (myri10ge_intr_coal_delay < 0 || + myri10ge_intr_coal_delay > 10*1000) + myri10ge_intr_coal_delay = 30; + sc->pause = myri10ge_flow_control; +} + +static int +myri10ge_attach(device_t dev) +{ + myri10ge_softc_t *sc = device_get_softc(dev); + struct ifnet *ifp; + size_t bytes; + int rid, err, i; + uint16_t cmd; + + sc->dev = dev; + myri10ge_fetch_tunables(sc); + + err = bus_dma_tag_create(NULL, /* parent */ + 1, /* alignment */ + 4096, /* boundary */ + BUS_SPACE_MAXADDR, /* low */ + BUS_SPACE_MAXADDR, /* high */ + NULL, NULL, /* filter */ + MYRI10GE_MAX_ETHER_MTU,/* maxsize */ + MYRI10GE_MCP_ETHER_MAX_SEND_DESC, /* num segs */ + 4096, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lock */ + &sc->parent_dmat); /* tag */ + + if (err != 0) { + device_printf(sc->dev, "Err %d allocating parent dmat\n", + err); + goto abort_with_nothing; + } + + ifp = sc->ifp = if_alloc(IFT_ETHER); + if (ifp == NULL) { + device_printf(dev, "can not if_alloc()\n"); + err = ENOSPC; + goto abort_with_parent_dmat; + } + mtx_init(&sc->cmd_lock, NULL, + MTX_NETWORK_LOCK, MTX_DEF); + mtx_init(&sc->tx_lock, device_get_nameunit(dev), + MTX_NETWORK_LOCK, MTX_DEF); + sx_init(&sc->driver_lock, device_get_nameunit(dev)); + + /* Enable DMA and Memory space access */ + pci_enable_busmaster(dev); + cmd = pci_read_config(dev, PCIR_COMMAND, 2); + cmd |= PCIM_CMD_MEMEN; + pci_write_config(dev, PCIR_COMMAND, cmd, 2); + + /* Map the board into the kernel */ + rid = PCIR_BARS; + sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, + ~0, 1, RF_ACTIVE); + if (sc->mem_res == NULL) { + device_printf(dev, "could not map memory\n"); + err = ENXIO; + goto abort_with_lock; + } + sc->sram = rman_get_virtual(sc->mem_res); + sc->sram_size = 2*1024*1024 - (2*(48*1024)+(32*1024)) - 0x100; + if (sc->sram_size > rman_get_size(sc->mem_res)) { + device_printf(dev, "impossible memory region size %ld\n", + rman_get_size(sc->mem_res)); + err = ENXIO; + goto abort_with_mem_res; + } + + /* make NULL terminated copy of the EEPROM strings section of + lanai SRAM */ + bzero(sc->eeprom_strings, MYRI10GE_EEPROM_STRINGS_SIZE); + bus_space_read_region_1(rman_get_bustag(sc->mem_res), + rman_get_bushandle(sc->mem_res), + sc->sram_size - MYRI10GE_EEPROM_STRINGS_SIZE, + sc->eeprom_strings, + MYRI10GE_EEPROM_STRINGS_SIZE - 2); + err = myri10ge_parse_strings(sc); + if (err != 0) + goto abort_with_mem_res; + + /* Enable write combining for efficient use of PCIe bus */ + myri10ge_enable_wc(sc); + + /* Allocate the out of band dma memory */ + err = myri10ge_dma_alloc(sc, &sc->cmd_dma, + sizeof (myri10ge_cmd_t), 64); + if (err != 0) + goto abort_with_mem_res; + sc->cmd = (mcp_cmd_response_t *) sc->cmd_dma.addr; + err = myri10ge_dma_alloc(sc, &sc->zeropad_dma, 64, 64); + if (err != 0) + goto abort_with_cmd_dma; + + err = myri10ge_dma_alloc(sc, &sc->fw_stats_dma, + sizeof (*sc->fw_stats), 64); + if (err != 0) + goto abort_with_zeropad_dma; + sc->fw_stats = (mcp_stats_t *)sc->fw_stats_dma.addr; + + + /* allocate interrupt queues */ + bytes = myri10ge_max_intr_slots * sizeof (*sc->intr.q[0]); + for (i = 0; i < MYRI10GE_NUM_INTRQS; i++) { + err = myri10ge_dma_alloc(sc, &sc->intr.dma[i], + bytes, 4096); + if (err != 0) + goto abort_with_intrq; + sc->intr.q[i] = (mcp_slot_t *)sc->intr.dma[i].addr; + } + + /* Add our ithread */ + rid = 0; + sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, + 1, RF_SHAREABLE | RF_ACTIVE); + if (sc->irq_res == NULL) { + device_printf(dev, "could not alloc interrupt\n"); + goto abort_with_intrq; + } + + /* load the firmware */ + myri10ge_select_firmware(sc); + + err = myri10ge_load_firmware(sc); + if (err != 0) + goto abort_with_irq_res; + err = myri10ge_reset(sc); + if (err != 0) + goto abort_with_irq_res; + + /* hook into the network stack */ + if_initname(ifp, device_get_name(dev), device_get_unit(dev)); + ifp->if_baudrate = 100000000; + ifp->if_capabilities = IFCAP_RXCSUM | IFCAP_TXCSUM; + ifp->if_hwassist = CSUM_TCP | CSUM_UDP; + ifp->if_capenable = ifp->if_capabilities; + sc->csum_flag |= MYRI10GE_MCP_ETHER_FLAGS_CKSUM; + ifp->if_init = myri10ge_init; + ifp->if_softc = sc; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_ioctl = myri10ge_ioctl; + ifp->if_start = myri10ge_start; + ifp->if_watchdog = myri10ge_watchdog; + ether_ifattach(ifp, sc->mac_addr); + /* ether_ifattach sets mtu to 1500 */ + ifp->if_mtu = MYRI10GE_MAX_ETHER_MTU - ETHER_HDR_LEN; + + /* Initialise the ifmedia structure */ + ifmedia_init(&sc->media, 0, myri10ge_media_change, + myri10ge_media_status); + ifmedia_add(&sc->media, IFM_ETHER|IFM_AUTO, 0, NULL); + myri10ge_add_sysctls(sc); + return 0; + +abort_with_irq_res: + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); +abort_with_intrq: + for (i = 0; i < MYRI10GE_NUM_INTRQS; i++) { + if (sc->intr.q[i] == NULL) + continue; + sc->intr.q[i] = NULL; + myri10ge_dma_free(&sc->intr.dma[i]); + } + myri10ge_dma_free(&sc->fw_stats_dma); +abort_with_zeropad_dma: + myri10ge_dma_free(&sc->zeropad_dma); +abort_with_cmd_dma: + myri10ge_dma_free(&sc->cmd_dma); +abort_with_mem_res: + bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); +abort_with_lock: + pci_disable_busmaster(dev); + mtx_destroy(&sc->cmd_lock); + mtx_destroy(&sc->tx_lock); + sx_destroy(&sc->driver_lock); + if_free(ifp); +abort_with_parent_dmat: + bus_dma_tag_destroy(sc->parent_dmat); + +abort_with_nothing: + return err; +} + +static int +myri10ge_detach(device_t dev) +{ + myri10ge_softc_t *sc = device_get_softc(dev); + int i; + + sx_xlock(&sc->driver_lock); + if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING) + myri10ge_close(sc); + sx_xunlock(&sc->driver_lock); + ether_ifdetach(sc->ifp); + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); + for (i = 0; i < MYRI10GE_NUM_INTRQS; i++) { + if (sc->intr.q[i] == NULL) + continue; + sc->intr.q[i] = NULL; + myri10ge_dma_free(&sc->intr.dma[i]); + } + myri10ge_dma_free(&sc->fw_stats_dma); + myri10ge_dma_free(&sc->zeropad_dma); + myri10ge_dma_free(&sc->cmd_dma); + bus_release_resource(dev, SYS_RES_MEMORY, PCIR_BARS, sc->mem_res); + pci_disable_busmaster(dev); + mtx_destroy(&sc->cmd_lock); + mtx_destroy(&sc->tx_lock); + sx_destroy(&sc->driver_lock); + if_free(sc->ifp); + bus_dma_tag_destroy(sc->parent_dmat); + return 0; +} + +static int +myri10ge_shutdown(device_t dev) +{ + return 0; +} + +/* + This file uses Myri10GE driver indentation. + + Local Variables: + c-file-style:"linux" + tab-width:8 + End: +*/ diff --git a/sys/dev/myri10ge/if_myri10ge_var.h b/sys/dev/myri10ge/if_myri10ge_var.h new file mode 100644 index 000000000000..e4ce9551fc06 --- /dev/null +++ b/sys/dev/myri10ge/if_myri10ge_var.h @@ -0,0 +1,203 @@ +/******************************************************************************* + +Copyright (c) 2006, Myricom 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. + + 3. Neither the name of the Myricom Inc, nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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. + +$FreeBSD$ + +***************************************************************************/ + +#define MYRI10GE_MAX_ETHER_MTU 9014 + +#define MYRI10GE_ETH_STOPPED 0 +#define MYRI10GE_ETH_STOPPING 1 +#define MYRI10GE_ETH_STARTING 2 +#define MYRI10GE_ETH_RUNNING 3 +#define MYRI10GE_ETH_OPEN_FAILED 4 + +#define MYRI10GE_FW_OFFSET 1024*1024 +#define MYRI10GE_EEPROM_STRINGS_SIZE 256 +#define MYRI10GE_NUM_INTRQS 2 + +typedef struct { + void *addr; + bus_addr_t bus_addr; + bus_dma_tag_t dmat; + bus_dmamap_t map; +} myri10ge_dma_t; + +typedef struct myri10ge_intrq +{ + mcp_slot_t *q[MYRI10GE_NUM_INTRQS]; + int intrq; + int slot; + int maxslots; + uint32_t seqnum; + uint32_t spurious; + uint32_t cnt; + myri10ge_dma_t dma[MYRI10GE_NUM_INTRQS]; +} myri10ge_intrq_t; + + +typedef struct +{ + uint32_t data0; + uint32_t data1; + uint32_t data2; +} myri10ge_cmd_t; + +struct myri10ge_buffer_state { + struct mbuf *m; + bus_dmamap_t map; +}; + +typedef struct +{ + volatile mcp_kreq_ether_recv_t *lanai; /* lanai ptr for recv ring */ + volatile uint8_t *wc_fifo; /* w/c rx dma addr fifo address */ + mcp_kreq_ether_recv_t *shadow; /* host shadow of recv ring */ + struct myri10ge_buffer_state *info; + bus_dma_tag_t dmat; + bus_dmamap_t extra_map; + int cnt; + int alloc_fail; + int mask; /* number of rx slots -1 */ +} myri10ge_rx_buf_t; + +typedef struct +{ + volatile mcp_kreq_ether_send_t *lanai; /* lanai ptr for sendq */ + volatile uint8_t *wc_fifo; /* w/c send fifo address */ + mcp_kreq_ether_send_t *req_list; /* host shadow of sendq */ + char *req_bytes; + struct myri10ge_buffer_state *info; + bus_dma_tag_t dmat; + int req; /* transmits submitted */ + int mask; /* number of transmit slots -1 */ + int done; /* transmits completed */ + int boundary; /* boundary transmits cannot cross*/ +} myri10ge_tx_buf_t; + +typedef struct { + struct ifnet* ifp; + int big_bytes; + struct mtx tx_lock; + int csum_flag; /* rx_csums? */ + uint8_t mac_addr[6]; /* eeprom mac address */ + myri10ge_tx_buf_t tx; /* transmit ring */ + myri10ge_rx_buf_t rx_small; + myri10ge_rx_buf_t rx_big; + bus_dma_tag_t parent_dmat; + volatile uint8_t *sram; + int sram_size; + volatile uint32_t *irq_claim; + char *mac_addr_string; + char *product_code_string; + mcp_cmd_response_t *cmd; + myri10ge_dma_t cmd_dma; + myri10ge_dma_t zeropad_dma; + mcp_stats_t *fw_stats; + myri10ge_dma_t fw_stats_dma; + struct pci_dev *pdev; + int msi_enabled; + myri10ge_intrq_t intr; + int link_state; + unsigned int rdma_tags_available; + int intr_coal_delay; + int wc; + struct mtx cmd_lock; + struct sx driver_lock; + int wake_queue; + int stop_queue; + int down_cnt; + int watchdog_resets; + int tx_defragged; + int pause; + struct resource *mem_res; + struct resource *irq_res; + void *ih; + char *fw_name; + char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE]; + char fw_version[128]; + device_t dev; + struct ifmedia media; + +} myri10ge_softc_t; + +#define MYRI10GE_PCI_VENDOR_MYRICOM 0x14c1 +#define MYRI10GE_PCI_DEVICE_Z8E 0x0008 + +#define MYRI10GE_HIGHPART_TO_U32(X) \ +(sizeof (X) == 8) ? ((uint32_t)((uint64_t)(X) >> 32)) : (0) +#define MYRI10GE_LOWPART_TO_U32(X) ((uint32_t)(X)) + + +/* implement our own memory barriers, since bus_space_barrier + cannot handle write-combining regions */ + +#if defined (__GNUC__) + #if #cpu(i386) || defined __i386 || defined i386 || defined __i386__ || #cpu(x86_64) || defined __x86_64__ + #define mb() __asm__ __volatile__ ("sfence;": : :"memory") + #elif #cpu(sparc64) || defined sparc64 || defined __sparcv9 + #define mb() __asm__ __volatile__ ("membar #MemIssue": : :"memory") + #elif #cpu(sparc) || defined sparc || defined __sparc__ + #define mb() __asm__ __volatile__ ("stbar;": : :"memory") + #else + #define mb() /* XXX just to make this compile */ + #endif +#else + #error "unknown compiler" +#endif + +static inline void +myri10ge_pio_copy(volatile void *to_v, void *from_v, size_t size) +{ + register volatile uintptr_t *to; + volatile uintptr_t *from; + size_t i; + + to = (volatile uintptr_t *) to_v; + from = from_v; + for (i = (size / sizeof (uintptr_t)); i; i--) { + *to = *from; + to++; + from++; + } + +} + + +/* + This file uses Myri10GE driver indentation. + + Local Variables: + c-file-style:"linux" + tab-width:8 + End: +*/ diff --git a/sys/dev/myri10ge/mcp_gen_header.h b/sys/dev/myri10ge/mcp_gen_header.h new file mode 100644 index 000000000000..7cb449105954 --- /dev/null +++ b/sys/dev/myri10ge/mcp_gen_header.h @@ -0,0 +1,107 @@ +/******************************************************************************* + +Copyright (c) 2006, Myricom 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. + + 3. Neither the name of the Myricom Inc, nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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. + +$FreeBSD$ +***************************************************************************/ + +#ifndef _mcp_gen_header_h +#define _mcp_gen_header_h + +/* this file define a standard header used as a first entry point to + exchange information between firmware/driver and driver. The + header structure can be anywhere in the mcp. It will usually be in + the .data section, because some fields needs to be initialized at + compile time. + The 32bit word at offset MX_HEADER_PTR_OFFSET in the mcp must + contains the location of the header. + + Typically a MCP will start with the following: + .text + .space 52 ! to help catch MEMORY_INT errors + bt start ! jump to real code + nop + .long _gen_mcp_header + + The source will have a definition like: + + mcp_gen_header_t gen_mcp_header = { + .header_length = sizeof(mcp_gen_header_t), + .mcp_type = MCP_TYPE_XXX, + .version = "something $Id: mcp_gen_header.h,v 1.1 2005/12/23 02:10:44 gallatin Exp $", + .mcp_globals = (unsigned)&Globals + }; +*/ + + +#define MCP_HEADER_PTR_OFFSET 0x3c + +#define MCP_TYPE_MX 0x4d582020 /* "MX " */ +#define MCP_TYPE_PCIE 0x70636965 /* "PCIE" pcie-only MCP */ +#define MCP_TYPE_ETH 0x45544820 /* "ETH " */ +#define MCP_TYPE_MCP0 0x4d435030 /* "MCP0" */ + + +typedef struct mcp_gen_header { + /* the first 4 fields are filled at compile time */ + unsigned header_length; + unsigned mcp_type; + char version[128]; + unsigned mcp_globals; /* pointer to mcp-type specific structure */ + + /* filled by the MCP at run-time */ + unsigned sram_size; + unsigned string_specs; /* either the original STRING_SPECS or a superset */ + unsigned string_specs_len; + + /* Fields above this comment are guaranteed to be present. + + Fields below this comment are extensions added in later versions + of this struct, drivers should compare the header_length against + offsetof(field) to check wether a given MCP implements them. + + Never remove any field. Keep everything naturally align. + */ +} mcp_gen_header_t; + +/* Macro to create a simple mcp header */ +#define MCP_GEN_HEADER_DECL(type, version_str, global_ptr) \ + struct mcp_gen_header mcp_gen_header = { \ + sizeof (struct mcp_gen_header), \ + (type), \ + version_str, \ + (global_ptr), \ + SRAM_SIZE, \ + (unsigned int) STRING_SPECS, \ + 256 \ + } + + +#endif /* _mcp_gen_header_h */ diff --git a/sys/dev/myri10ge/myri10ge_mcp.h b/sys/dev/myri10ge/myri10ge_mcp.h new file mode 100644 index 000000000000..de85fde72cb5 --- /dev/null +++ b/sys/dev/myri10ge/myri10ge_mcp.h @@ -0,0 +1,265 @@ +/******************************************************************************* + +Copyright (c) 2006, Myricom 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. + + 3. Neither the name of the Myricom Inc, nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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. + +$FreeBSD$ +***************************************************************************/ + +#ifndef _myri10ge_mcp_h +#define _myri10ge_mcp_h + +#ifdef MYRI10GE_MCP +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +#endif + +/* 8 Bytes */ +typedef struct +{ + uint32_t high; + uint32_t low; +} mcp_dma_addr_t; + +/* 16 Bytes */ +typedef struct +{ + uint32_t data0; + uint32_t data1; + uint32_t seqnum; + uint16_t index; + uint8_t flag; + uint8_t type; +} mcp_slot_t; + +/* 64 Bytes */ +typedef struct +{ + uint32_t cmd; + uint32_t data0; /* will be low portion if data > 32 bits */ + /* 8 */ + uint32_t data1; /* will be high portion if data > 32 bits */ + uint32_t data2; /* currently unused.. */ + /* 16 */ + mcp_dma_addr_t response_addr; + /* 24 */ + uint8_t pad[40]; +} mcp_cmd_t; + +/* 8 Bytes */ +typedef struct +{ + uint32_t data; + uint32_t result; +} mcp_cmd_response_t; + + + +/* + flags used in mcp_kreq_ether_send_t: + + The SMALL flag is only needed in the first segment. It is raised + for packets that are total less or equal 512 bytes. + + The CKSUM flag must be set in all segments. + + The PADDED flags is set if the packet needs to be padded, and it + must be set for all segments. + + The MYRI10GE_MCP_ETHER_FLAGS_ALIGN_ODD must be set if the cumulative + length of all previous segments was odd. +*/ + + +#define MYRI10GE_MCP_ETHER_FLAGS_VALID 0x1 +#define MYRI10GE_MCP_ETHER_FLAGS_FIRST 0x2 +#define MYRI10GE_MCP_ETHER_FLAGS_ALIGN_ODD 0x4 +#define MYRI10GE_MCP_ETHER_FLAGS_CKSUM 0x8 +#define MYRI10GE_MCP_ETHER_FLAGS_SMALL 0x10 +#define MYRI10GE_MCP_ETHER_FLAGS_NOT_LAST 0x100 +#define MYRI10GE_MCP_ETHER_FLAGS_TSO_HDR 0x200 +#define MYRI10GE_MCP_ETHER_FLAGS_TSO 0x400 + +#define MYRI10GE_MCP_ETHER_SEND_SMALL_SIZE 1520 +#define MYRI10GE_MCP_ETHER_MAX_MTU 9400 + +typedef union mcp_pso_or_cumlen +{ + uint16_t pseudo_hdr_offset; + uint16_t cum_len; +} mcp_pso_or_cumlen_t; + +#define MYRI10GE_MCP_ETHER_MAX_SEND_DESC 12 +#define MYRI10GE_MCP_ETHER_PAD 2 + +/* 16 Bytes */ +typedef struct +{ + uint32_t addr_high; + uint32_t addr_low; + uint16_t length; + uint8_t pad; + uint8_t cksum_offset; /* where to start computing cksum */ + uint16_t pseudo_hdr_offset; + uint16_t flags; /* as defined above */ +} mcp_kreq_ether_send_t; + +/* 8 Bytes */ +typedef struct +{ + uint32_t addr_high; + uint32_t addr_low; +} mcp_kreq_ether_recv_t; + + +/* Commands */ + +#define MYRI10GE_MCP_CMD_OFFSET 0xf80000 + +typedef enum { + MYRI10GE_MCP_CMD_NONE = 0, + /* Reset the mcp, it is left in a safe state, waiting + for the driver to set all its parameters */ + MYRI10GE_MCP_CMD_RESET, + + /* get the version number of the current firmware.. + (may be available in the eeprom strings..? */ + MYRI10GE_MCP_GET_MCP_VERSION, + + + /* Parameters which must be set by the driver before it can + issue MYRI10GE_MCP_CMD_ETHERNET_UP. They persist until the next + MYRI10GE_MCP_CMD_RESET is issued */ + + MYRI10GE_MCP_CMD_SET_INTRQ0_DMA, + MYRI10GE_MCP_CMD_SET_INTRQ1_DMA, + MYRI10GE_MCP_CMD_SET_BIG_BUFFER_SIZE, /* in bytes, power of 2 */ + MYRI10GE_MCP_CMD_SET_SMALL_BUFFER_SIZE, /* in bytes */ + + + /* Parameters which refer to lanai SRAM addresses where the + driver must issue PIO writes for various things */ + + MYRI10GE_MCP_CMD_GET_SEND_OFFSET, + MYRI10GE_MCP_CMD_GET_SMALL_RX_OFFSET, + MYRI10GE_MCP_CMD_GET_BIG_RX_OFFSET, + MYRI10GE_MCP_CMD_GET_IRQ_ACK_OFFSET, + MYRI10GE_MCP_CMD_GET_IRQ_DEASSERT_OFFSET, + MYRI10GE_MCP_CMD_GET_IRQ_ACK_DEASSERT_OFFSET, + + /* Parameters which refer to rings stored on the MCP, + and whose size is controlled by the mcp */ + + MYRI10GE_MCP_CMD_GET_SEND_RING_SIZE, /* in bytes */ + MYRI10GE_MCP_CMD_GET_RX_RING_SIZE, /* in bytes */ + + /* Parameters which refer to rings stored in the host, + and whose size is controlled by the host. Note that + all must be physically contiguous and must contain + a power of 2 number of entries. */ + + MYRI10GE_MCP_CMD_SET_INTRQ_SIZE, /* in bytes */ + + /* command to bring ethernet interface up. Above parameters + (plus mtu & mac address) must have been exchanged prior + to issuing this command */ + MYRI10GE_MCP_CMD_ETHERNET_UP, + + /* command to bring ethernet interface down. No further sends + or receives may be processed until an MYRI10GE_MCP_CMD_ETHERNET_UP + is issued, and all interrupt queues must be flushed prior + to ack'ing this command */ + + MYRI10GE_MCP_CMD_ETHERNET_DOWN, + + /* commands the driver may issue live, without resetting + the nic. Note that increasing the mtu "live" should + only be done if the driver has already supplied buffers + sufficiently large to handle the new mtu. Decreasing + the mtu live is safe */ + + MYRI10GE_MCP_CMD_SET_MTU, + MYRI10GE_MCP_CMD_SET_INTR_COAL_DELAY, /* in microseconds */ + MYRI10GE_MCP_CMD_SET_STATS_INTERVAL, /* in microseconds */ + MYRI10GE_MCP_CMD_SET_STATS_DMA, + + MYRI10GE_MCP_ENABLE_PROMISC, + MYRI10GE_MCP_DISABLE_PROMISC, + MYRI10GE_MCP_SET_MAC_ADDRESS, + + MYRI10GE_MCP_ENABLE_FLOW_CONTROL, + MYRI10GE_MCP_DISABLE_FLOW_CONTROL +} myri10ge_mcp_cmd_type_t; + + +typedef enum { + MYRI10GE_MCP_CMD_OK = 0, + MYRI10GE_MCP_CMD_UNKNOWN, + MYRI10GE_MCP_CMD_ERROR_RANGE, + MYRI10GE_MCP_CMD_ERROR_BUSY, + MYRI10GE_MCP_CMD_ERROR_EMPTY, + MYRI10GE_MCP_CMD_ERROR_CLOSED, + MYRI10GE_MCP_CMD_ERROR_HASH_ERROR, + MYRI10GE_MCP_CMD_ERROR_BAD_PORT, + MYRI10GE_MCP_CMD_ERROR_RESOURCES +} myri10ge_mcp_cmd_status_t; + +typedef enum { + MYRI10GE_MCP_INTR_NONE = 0, + MYRI10GE_MCP_INTR_ETHER_SEND_DONE, + MYRI10GE_MCP_INTR_ETHER_RECV_SMALL, + MYRI10GE_MCP_INTR_ETHER_RECV_BIG, + MYRI10GE_MCP_INTR_LINK_CHANGE, + MYRI10GE_MCP_INTR_STATS_UPDATE, + MYRI10GE_MCP_INTR_ETHER_DOWN +} myri10ge_mcp_intr_type_t; + + +/* 32 Bytes */ +typedef struct +{ + uint32_t link_up; + uint32_t dropped_link_overflow; + uint32_t dropped_link_error_or_filtered; + uint32_t dropped_runt; + uint32_t dropped_overrun; + uint32_t dropped_no_small_buffer; + uint32_t dropped_no_big_buffer; + uint32_t dropped_interrupt_busy; + uint32_t rdma_tags_available; +} mcp_stats_t; + + +#endif /* _myri10ge_mcp_h */ diff --git a/sys/modules/mxge/Makefile b/sys/modules/mxge/Makefile new file mode 100644 index 000000000000..7cb1e9dc645f --- /dev/null +++ b/sys/modules/mxge/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +SUBDIR= myri10ge +SUBDIR+=myri10ge_eth_z8e +SUBDIR+=myri10ge_ethp_z8e + +.include diff --git a/sys/modules/mxge/mxge/Makefile b/sys/modules/mxge/mxge/Makefile new file mode 100644 index 000000000000..0d9ed993d067 --- /dev/null +++ b/sys/modules/mxge/mxge/Makefile @@ -0,0 +1,8 @@ +#$FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/myri10ge + +KMOD= if_myri10ge +SRCS= if_myri10ge.c device_if.h bus_if.h pci_if.h + +.include diff --git a/sys/modules/mxge/mxge_eth_z8e/Makefile b/sys/modules/mxge/mxge_eth_z8e/Makefile new file mode 100644 index 000000000000..f43c81a21a78 --- /dev/null +++ b/sys/modules/mxge/mxge_eth_z8e/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ + +MYRI10GE= ${.CURDIR}/../../../dev/myri10ge +.PATH= ${MYRI10GE} +KMOD= myri10ge_eth_z8e +FIRMWS= eth_z8e.dat:myri10ge_eth_z8e +CLEANFILES+= eth_z8e.dat + +eth_z8e.dat: ${MYRI10GE}/eth_z8e.dat.gz.uu + uudecode -p < ${MYRI10GE}/eth_z8e.dat.gz.uu \ + | gzip -dc > ${.TARGET} + +.include diff --git a/sys/modules/mxge/mxge_ethp_z8e/Makefile b/sys/modules/mxge/mxge_ethp_z8e/Makefile new file mode 100644 index 000000000000..35b169b1b036 --- /dev/null +++ b/sys/modules/mxge/mxge_ethp_z8e/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ + +MYRI10GE= ${.CURDIR}/../../../dev/myri10ge +.PATH= ${MYRI10GE} +KMOD= myri10ge_ethp_z8e +FIRMWS= ethp_z8e.dat:myri10ge_ethp_z8e +CLEANFILES+= ethp_z8e.dat + +ethp_z8e.dat: ${MYRI10GE}/ethp_z8e.dat.gz.uu + uudecode -p < ${MYRI10GE}/ethp_z8e.dat.gz.uu \ + | gzip -dc > ${.TARGET} + +.include diff --git a/sys/modules/myri10ge/Makefile b/sys/modules/myri10ge/Makefile new file mode 100644 index 000000000000..7cb1e9dc645f --- /dev/null +++ b/sys/modules/myri10ge/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +SUBDIR= myri10ge +SUBDIR+=myri10ge_eth_z8e +SUBDIR+=myri10ge_ethp_z8e + +.include diff --git a/sys/modules/myri10ge/myri10ge/Makefile b/sys/modules/myri10ge/myri10ge/Makefile new file mode 100644 index 000000000000..0d9ed993d067 --- /dev/null +++ b/sys/modules/myri10ge/myri10ge/Makefile @@ -0,0 +1,8 @@ +#$FreeBSD$ + +.PATH: ${.CURDIR}/../../../dev/myri10ge + +KMOD= if_myri10ge +SRCS= if_myri10ge.c device_if.h bus_if.h pci_if.h + +.include diff --git a/sys/modules/myri10ge/myri10ge_eth_z8e/Makefile b/sys/modules/myri10ge/myri10ge_eth_z8e/Makefile new file mode 100644 index 000000000000..f43c81a21a78 --- /dev/null +++ b/sys/modules/myri10ge/myri10ge_eth_z8e/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ + +MYRI10GE= ${.CURDIR}/../../../dev/myri10ge +.PATH= ${MYRI10GE} +KMOD= myri10ge_eth_z8e +FIRMWS= eth_z8e.dat:myri10ge_eth_z8e +CLEANFILES+= eth_z8e.dat + +eth_z8e.dat: ${MYRI10GE}/eth_z8e.dat.gz.uu + uudecode -p < ${MYRI10GE}/eth_z8e.dat.gz.uu \ + | gzip -dc > ${.TARGET} + +.include diff --git a/sys/modules/myri10ge/myri10ge_ethp_z8e/Makefile b/sys/modules/myri10ge/myri10ge_ethp_z8e/Makefile new file mode 100644 index 000000000000..35b169b1b036 --- /dev/null +++ b/sys/modules/myri10ge/myri10ge_ethp_z8e/Makefile @@ -0,0 +1,13 @@ +# $FreeBSD$ + +MYRI10GE= ${.CURDIR}/../../../dev/myri10ge +.PATH= ${MYRI10GE} +KMOD= myri10ge_ethp_z8e +FIRMWS= ethp_z8e.dat:myri10ge_ethp_z8e +CLEANFILES+= ethp_z8e.dat + +ethp_z8e.dat: ${MYRI10GE}/ethp_z8e.dat.gz.uu + uudecode -p < ${MYRI10GE}/ethp_z8e.dat.gz.uu \ + | gzip -dc > ${.TARGET} + +.include