usbnet drivers: No need for usbnet_busy in uno_mcast. This callback always runs with IFNET_LOCK held, and during a task that usbnet_detach prevents scheduling anew and waits for finishing before completing the detach, so there is no need to hang onto a reference count here.diff -r1.135 -r1.136 src/sys/dev/usb/if_axe.c
(riastradh)
--- src/sys/dev/usb/if_axe.c 2022/03/03 05:51:17 1.135
+++ src/sys/dev/usb/if_axe.c 2022/03/03 05:51:27 1.136
@@ -1,1349 +1,1347 @@ | @@ -1,1349 +1,1347 @@ | |||
1 | /* $NetBSD: if_axe.c,v 1.135 2022/03/03 05:51:17 riastradh Exp $ */ | 1 | /* $NetBSD: if_axe.c,v 1.136 2022/03/03 05:51:27 riastradh Exp $ */ | |
2 | /* $OpenBSD: if_axe.c,v 1.137 2016/04/13 11:03:37 mpi Exp $ */ | 2 | /* $OpenBSD: if_axe.c,v 1.137 2016/04/13 11:03:37 mpi Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org> | 5 | * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org> | |
6 | * | 6 | * | |
7 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any | |
8 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above | |
9 | * copyright notice and this permission notice appear in all copies. | 9 | * copyright notice and this permission notice appear in all copies. | |
10 | * | 10 | * | |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
18 | */ | 18 | */ | |
19 | 19 | |||
20 | /* | 20 | /* | |
21 | * Copyright (c) 1997, 1998, 1999, 2000-2003 | 21 | * Copyright (c) 1997, 1998, 1999, 2000-2003 | |
22 | * Bill Paul <wpaul@windriver.com>. All rights reserved. | 22 | * Bill Paul <wpaul@windriver.com>. All rights reserved. | |
23 | * | 23 | * | |
24 | * Redistribution and use in source and binary forms, with or without | 24 | * Redistribution and use in source and binary forms, with or without | |
25 | * modification, are permitted provided that the following conditions | 25 | * modification, are permitted provided that the following conditions | |
26 | * are met: | 26 | * are met: | |
27 | * 1. Redistributions of source code must retain the above copyright | 27 | * 1. Redistributions of source code must retain the above copyright | |
28 | * notice, this list of conditions and the following disclaimer. | 28 | * notice, this list of conditions and the following disclaimer. | |
29 | * 2. Redistributions in binary form must reproduce the above copyright | 29 | * 2. Redistributions in binary form must reproduce the above copyright | |
30 | * notice, this list of conditions and the following disclaimer in the | 30 | * notice, this list of conditions and the following disclaimer in the | |
31 | * documentation and/or other materials provided with the distribution. | 31 | * documentation and/or other materials provided with the distribution. | |
32 | * 3. All advertising materials mentioning features or use of this software | 32 | * 3. All advertising materials mentioning features or use of this software | |
33 | * must display the following acknowledgement: | 33 | * must display the following acknowledgement: | |
34 | * This product includes software developed by Bill Paul. | 34 | * This product includes software developed by Bill Paul. | |
35 | * 4. Neither the name of the author nor the names of any co-contributors | 35 | * 4. Neither the name of the author nor the names of any co-contributors | |
36 | * may be used to endorse or promote products derived from this software | 36 | * may be used to endorse or promote products derived from this software | |
37 | * without specific prior written permission. | 37 | * without specific prior written permission. | |
38 | * | 38 | * | |
39 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | 39 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | |
40 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 40 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
42 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | 42 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | |
43 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 43 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
44 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 44 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
45 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 45 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
46 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 46 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
47 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 47 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
48 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 48 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
49 | * THE POSSIBILITY OF SUCH DAMAGE. | 49 | * THE POSSIBILITY OF SUCH DAMAGE. | |
50 | */ | 50 | */ | |
51 | 51 | |||
52 | /* | 52 | /* | |
53 | * ASIX Electronics AX88172/AX88178/AX88778 USB 2.0 ethernet driver. | 53 | * ASIX Electronics AX88172/AX88178/AX88778 USB 2.0 ethernet driver. | |
54 | * Used in the LinkSys USB200M and various other adapters. | 54 | * Used in the LinkSys USB200M and various other adapters. | |
55 | * | 55 | * | |
56 | * Written by Bill Paul <wpaul@windriver.com> | 56 | * Written by Bill Paul <wpaul@windriver.com> | |
57 | * Senior Engineer | 57 | * Senior Engineer | |
58 | * Wind River Systems | 58 | * Wind River Systems | |
59 | */ | 59 | */ | |
60 | 60 | |||
61 | /* | 61 | /* | |
62 | * The AX88172 provides USB ethernet supports at 10 and 100Mbps. | 62 | * The AX88172 provides USB ethernet supports at 10 and 100Mbps. | |
63 | * It uses an external PHY (reference designs use a RealTek chip), | 63 | * It uses an external PHY (reference designs use a RealTek chip), | |
64 | * and has a 64-bit multicast hash filter. There is some information | 64 | * and has a 64-bit multicast hash filter. There is some information | |
65 | * missing from the manual which one needs to know in order to make | 65 | * missing from the manual which one needs to know in order to make | |
66 | * the chip function: | 66 | * the chip function: | |
67 | * | 67 | * | |
68 | * - You must set bit 7 in the RX control register, otherwise the | 68 | * - You must set bit 7 in the RX control register, otherwise the | |
69 | * chip won't receive any packets. | 69 | * chip won't receive any packets. | |
70 | * - You must initialize all 3 IPG registers, or you won't be able | 70 | * - You must initialize all 3 IPG registers, or you won't be able | |
71 | * to send any packets. | 71 | * to send any packets. | |
72 | * | 72 | * | |
73 | * Note that this device appears to only support loading the station | 73 | * Note that this device appears to only support loading the station | |
74 | * address via autoload from the EEPROM (i.e. there's no way to manually | 74 | * address via autoload from the EEPROM (i.e. there's no way to manually | |
75 | * set it). | 75 | * set it). | |
76 | * | 76 | * | |
77 | * (Adam Weinberger wanted me to name this driver if_gir.c.) | 77 | * (Adam Weinberger wanted me to name this driver if_gir.c.) | |
78 | */ | 78 | */ | |
79 | 79 | |||
80 | /* | 80 | /* | |
81 | * Ax88178 and Ax88772 support backported from the OpenBSD driver. | 81 | * Ax88178 and Ax88772 support backported from the OpenBSD driver. | |
82 | * 2007/02/12, J.R. Oldroyd, fbsd@opal.com | 82 | * 2007/02/12, J.R. Oldroyd, fbsd@opal.com | |
83 | * | 83 | * | |
84 | * Manual here: | 84 | * Manual here: | |
85 | * http://www.asix.com.tw/FrootAttach/datasheet/AX88178_datasheet_Rev10.pdf | 85 | * http://www.asix.com.tw/FrootAttach/datasheet/AX88178_datasheet_Rev10.pdf | |
86 | * http://www.asix.com.tw/FrootAttach/datasheet/AX88772_datasheet_Rev10.pdf | 86 | * http://www.asix.com.tw/FrootAttach/datasheet/AX88772_datasheet_Rev10.pdf | |
87 | */ | 87 | */ | |
88 | 88 | |||
89 | #include <sys/cdefs.h> | 89 | #include <sys/cdefs.h> | |
90 | __KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1.135 2022/03/03 05:51:17 riastradh Exp $"); | 90 | __KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1.136 2022/03/03 05:51:27 riastradh Exp $"); | |
91 | 91 | |||
92 | #ifdef _KERNEL_OPT | 92 | #ifdef _KERNEL_OPT | |
93 | #include "opt_usb.h" | 93 | #include "opt_usb.h" | |
94 | #include "opt_net_mpsafe.h" | 94 | #include "opt_net_mpsafe.h" | |
95 | #endif | 95 | #endif | |
96 | 96 | |||
97 | #include <sys/param.h> | 97 | #include <sys/param.h> | |
98 | 98 | |||
99 | #include <dev/usb/usbnet.h> | 99 | #include <dev/usb/usbnet.h> | |
100 | #include <dev/usb/usbhist.h> | 100 | #include <dev/usb/usbhist.h> | |
101 | #include <dev/usb/if_axereg.h> | 101 | #include <dev/usb/if_axereg.h> | |
102 | 102 | |||
103 | struct axe_type { | 103 | struct axe_type { | |
104 | struct usb_devno axe_dev; | 104 | struct usb_devno axe_dev; | |
105 | uint16_t axe_flags; | 105 | uint16_t axe_flags; | |
106 | }; | 106 | }; | |
107 | 107 | |||
108 | struct axe_softc { | 108 | struct axe_softc { | |
109 | struct usbnet axe_un; | 109 | struct usbnet axe_un; | |
110 | 110 | |||
111 | /* usbnet:un_flags values */ | 111 | /* usbnet:un_flags values */ | |
112 | #define AX178 __BIT(0) /* AX88178 */ | 112 | #define AX178 __BIT(0) /* AX88178 */ | |
113 | #define AX772 __BIT(1) /* AX88772 */ | 113 | #define AX772 __BIT(1) /* AX88772 */ | |
114 | #define AX772A __BIT(2) /* AX88772A */ | 114 | #define AX772A __BIT(2) /* AX88772A */ | |
115 | #define AX772B __BIT(3) /* AX88772B */ | 115 | #define AX772B __BIT(3) /* AX88772B */ | |
116 | #define AXSTD_FRAME __BIT(12) | 116 | #define AXSTD_FRAME __BIT(12) | |
117 | #define AXCSUM_FRAME __BIT(13) | 117 | #define AXCSUM_FRAME __BIT(13) | |
118 | 118 | |||
119 | uint8_t axe_ipgs[3]; | 119 | uint8_t axe_ipgs[3]; | |
120 | uint8_t axe_phyaddrs[2]; | 120 | uint8_t axe_phyaddrs[2]; | |
121 | uint16_t sc_pwrcfg; | 121 | uint16_t sc_pwrcfg; | |
122 | uint16_t sc_lenmask; | 122 | uint16_t sc_lenmask; | |
123 | 123 | |||
124 | }; | 124 | }; | |
125 | 125 | |||
126 | #define AXE_IS_178_FAMILY(un) \ | 126 | #define AXE_IS_178_FAMILY(un) \ | |
127 | ((un)->un_flags & (AX178 | AX772 | AX772A | AX772B)) | 127 | ((un)->un_flags & (AX178 | AX772 | AX772A | AX772B)) | |
128 | 128 | |||
129 | #define AXE_IS_772(un) \ | 129 | #define AXE_IS_772(un) \ | |
130 | ((un)->un_flags & (AX772 | AX772A | AX772B)) | 130 | ((un)->un_flags & (AX772 | AX772A | AX772B)) | |
131 | 131 | |||
132 | #define AXE_IS_172(un) (AXE_IS_178_FAMILY(un) == 0) | 132 | #define AXE_IS_172(un) (AXE_IS_178_FAMILY(un) == 0) | |
133 | 133 | |||
134 | #define AX_RXCSUM \ | 134 | #define AX_RXCSUM \ | |
135 | (IFCAP_CSUM_IPv4_Rx | \ | 135 | (IFCAP_CSUM_IPv4_Rx | \ | |
136 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | \ | 136 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | \ | |
137 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx) | 137 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx) | |
138 | 138 | |||
139 | #define AX_TXCSUM \ | 139 | #define AX_TXCSUM \ | |
140 | (IFCAP_CSUM_IPv4_Tx | \ | 140 | (IFCAP_CSUM_IPv4_Tx | \ | |
141 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx | \ | 141 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx | \ | |
142 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx) | 142 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx) | |
143 | 143 | |||
144 | /* | 144 | /* | |
145 | * AXE_178_MAX_FRAME_BURST | 145 | * AXE_178_MAX_FRAME_BURST | |
146 | * max frame burst size for Ax88178 and Ax88772 | 146 | * max frame burst size for Ax88178 and Ax88772 | |
147 | * 0 2048 bytes | 147 | * 0 2048 bytes | |
148 | * 1 4096 bytes | 148 | * 1 4096 bytes | |
149 | * 2 8192 bytes | 149 | * 2 8192 bytes | |
150 | * 3 16384 bytes | 150 | * 3 16384 bytes | |
151 | * use the largest your system can handle without USB stalling. | 151 | * use the largest your system can handle without USB stalling. | |
152 | * | 152 | * | |
153 | * NB: 88772 parts appear to generate lots of input errors with | 153 | * NB: 88772 parts appear to generate lots of input errors with | |
154 | * a 2K rx buffer and 8K is only slightly faster than 4K on an | 154 | * a 2K rx buffer and 8K is only slightly faster than 4K on an | |
155 | * EHCI port on a T42 so change at your own risk. | 155 | * EHCI port on a T42 so change at your own risk. | |
156 | */ | 156 | */ | |
157 | #define AXE_178_MAX_FRAME_BURST 1 | 157 | #define AXE_178_MAX_FRAME_BURST 1 | |
158 | 158 | |||
159 | 159 | |||
160 | #ifdef USB_DEBUG | 160 | #ifdef USB_DEBUG | |
161 | #ifndef AXE_DEBUG | 161 | #ifndef AXE_DEBUG | |
162 | #define axedebug 0 | 162 | #define axedebug 0 | |
163 | #else | 163 | #else | |
164 | static int axedebug = 0; | 164 | static int axedebug = 0; | |
165 | 165 | |||
166 | SYSCTL_SETUP(sysctl_hw_axe_setup, "sysctl hw.axe setup") | 166 | SYSCTL_SETUP(sysctl_hw_axe_setup, "sysctl hw.axe setup") | |
167 | { | 167 | { | |
168 | int err; | 168 | int err; | |
169 | const struct sysctlnode *rnode; | 169 | const struct sysctlnode *rnode; | |
170 | const struct sysctlnode *cnode; | 170 | const struct sysctlnode *cnode; | |
171 | 171 | |||
172 | err = sysctl_createv(clog, 0, NULL, &rnode, | 172 | err = sysctl_createv(clog, 0, NULL, &rnode, | |
173 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "axe", | 173 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "axe", | |
174 | SYSCTL_DESCR("axe global controls"), | 174 | SYSCTL_DESCR("axe global controls"), | |
175 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | 175 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | |
176 | 176 | |||
177 | if (err) | 177 | if (err) | |
178 | goto fail; | 178 | goto fail; | |
179 | 179 | |||
180 | /* control debugging printfs */ | 180 | /* control debugging printfs */ | |
181 | err = sysctl_createv(clog, 0, &rnode, &cnode, | 181 | err = sysctl_createv(clog, 0, &rnode, &cnode, | |
182 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | 182 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | |
183 | "debug", SYSCTL_DESCR("Enable debugging output"), | 183 | "debug", SYSCTL_DESCR("Enable debugging output"), | |
184 | NULL, 0, &axedebug, sizeof(axedebug), CTL_CREATE, CTL_EOL); | 184 | NULL, 0, &axedebug, sizeof(axedebug), CTL_CREATE, CTL_EOL); | |
185 | if (err) | 185 | if (err) | |
186 | goto fail; | 186 | goto fail; | |
187 | 187 | |||
188 | return; | 188 | return; | |
189 | fail: | 189 | fail: | |
190 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | 190 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | |
191 | } | 191 | } | |
192 | 192 | |||
193 | #endif /* AXE_DEBUG */ | 193 | #endif /* AXE_DEBUG */ | |
194 | #endif /* USB_DEBUG */ | 194 | #endif /* USB_DEBUG */ | |
195 | 195 | |||
196 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(axedebug,1,FMT,A,B,C,D) | 196 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(axedebug,1,FMT,A,B,C,D) | |
197 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(axedebug,N,FMT,A,B,C,D) | 197 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(axedebug,N,FMT,A,B,C,D) | |
198 | #define AXEHIST_FUNC() USBHIST_FUNC() | 198 | #define AXEHIST_FUNC() USBHIST_FUNC() | |
199 | #define AXEHIST_CALLED(name) USBHIST_CALLED(axedebug) | 199 | #define AXEHIST_CALLED(name) USBHIST_CALLED(axedebug) | |
200 | 200 | |||
201 | /* | 201 | /* | |
202 | * Various supported device vendors/products. | 202 | * Various supported device vendors/products. | |
203 | */ | 203 | */ | |
204 | static const struct axe_type axe_devs[] = { | 204 | static const struct axe_type axe_devs[] = { | |
205 | { { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE2000 }, 0 }, | 205 | { { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE2000 }, 0 }, | |
206 | { { USB_VENDOR_ACERCM, USB_PRODUCT_ACERCM_EP1427X2 }, 0 }, | 206 | { { USB_VENDOR_ACERCM, USB_PRODUCT_ACERCM_EP1427X2 }, 0 }, | |
207 | { { USB_VENDOR_APPLE, USB_PRODUCT_APPLE_ETHERNET }, AX772 }, | 207 | { { USB_VENDOR_APPLE, USB_PRODUCT_APPLE_ETHERNET }, AX772 }, | |
208 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88172 }, 0 }, | 208 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88172 }, 0 }, | |
209 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772 }, AX772 }, | 209 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772 }, AX772 }, | |
210 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772A }, AX772 }, | 210 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772A }, AX772 }, | |
211 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B }, AX772B }, | 211 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B }, AX772B }, | |
212 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B_1 }, AX772B }, | 212 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B_1 }, AX772B }, | |
213 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178 }, AX178 }, | 213 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178 }, AX178 }, | |
214 | { { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC210T }, 0 }, | 214 | { { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC210T }, 0 }, | |
215 | { { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D5055 }, AX178 }, | 215 | { { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D5055 }, AX178 }, | |
216 | { { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB2AR }, 0}, | 216 | { { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB2AR }, 0}, | |
217 | { { USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_USB200MV2 }, AX772A }, | 217 | { { USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_USB200MV2 }, AX772A }, | |
218 | { { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB2_TX }, 0 }, | 218 | { { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB2_TX }, 0 }, | |
219 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100 }, 0 }, | 219 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100 }, 0 }, | |
220 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100B1 }, AX772 }, | 220 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100B1 }, AX772 }, | |
221 | { { USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DUBE100B1 }, AX772 }, | 221 | { { USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DUBE100B1 }, AX772 }, | |
222 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100C1 }, AX772B }, | 222 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100C1 }, AX772B }, | |
223 | { { USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_GWUSB2E }, 0 }, | 223 | { { USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_GWUSB2E }, 0 }, | |
224 | { { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETGUS2 }, AX178 }, | 224 | { { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETGUS2 }, AX178 }, | |
225 | { { USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_PRX1 }, 0 }, | 225 | { { USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_PRX1 }, 0 }, | |
226 | { { USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_ETHERNET }, AX772B }, | 226 | { { USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_ETHERNET }, AX772B }, | |
227 | { { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_HG20F9 }, AX772B }, | 227 | { { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_HG20F9 }, AX772B }, | |
228 | { { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_USB200M }, 0 }, | 228 | { { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_USB200M }, 0 }, | |
229 | { { USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_USB1000 }, AX178 }, | 229 | { { USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_USB1000 }, AX178 }, | |
230 | { { USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LAN_GTJU2 }, AX178 }, | 230 | { { USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LAN_GTJU2 }, AX178 }, | |
231 | { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2GT }, AX178 }, | 231 | { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2GT }, AX178 }, | |
232 | { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2KTX }, 0 }, | 232 | { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2KTX }, 0 }, | |
233 | { { USB_VENDOR_MSI, USB_PRODUCT_MSI_AX88772A }, AX772 }, | 233 | { { USB_VENDOR_MSI, USB_PRODUCT_MSI_AX88772A }, AX772 }, | |
234 | { { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA120 }, 0 }, | 234 | { { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA120 }, 0 }, | |
235 | { { USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01PLUS }, AX772 }, | 235 | { { USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01PLUS }, AX772 }, | |
236 | { { USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GU1000T }, AX178 }, | 236 | { { USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GU1000T }, AX178 }, | |
237 | { { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_LN029 }, 0 }, | 237 | { { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_LN029 }, 0 }, | |
238 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN028 }, AX178 }, | 238 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN028 }, AX178 }, | |
239 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN031 }, AX178 }, | 239 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN031 }, AX178 }, | |
240 | { { USB_VENDOR_SYSTEMTALKS, USB_PRODUCT_SYSTEMTALKS_SGCX2UL }, 0 }, | 240 | { { USB_VENDOR_SYSTEMTALKS, USB_PRODUCT_SYSTEMTALKS_SGCX2UL }, 0 }, | |
241 | }; | 241 | }; | |
242 | #define axe_lookup(v, p) ((const struct axe_type *)usb_lookup(axe_devs, v, p)) | 242 | #define axe_lookup(v, p) ((const struct axe_type *)usb_lookup(axe_devs, v, p)) | |
243 | 243 | |||
244 | static const struct ax88772b_mfb ax88772b_mfb_table[] = { | 244 | static const struct ax88772b_mfb ax88772b_mfb_table[] = { | |
245 | { 0x8000, 0x8001, 2048 }, | 245 | { 0x8000, 0x8001, 2048 }, | |
246 | { 0x8100, 0x8147, 4096 }, | 246 | { 0x8100, 0x8147, 4096 }, | |
247 | { 0x8200, 0x81EB, 6144 }, | 247 | { 0x8200, 0x81EB, 6144 }, | |
248 | { 0x8300, 0x83D7, 8192 }, | 248 | { 0x8300, 0x83D7, 8192 }, | |
249 | { 0x8400, 0x851E, 16384 }, | 249 | { 0x8400, 0x851E, 16384 }, | |
250 | { 0x8500, 0x8666, 20480 }, | 250 | { 0x8500, 0x8666, 20480 }, | |
251 | { 0x8600, 0x87AE, 24576 }, | 251 | { 0x8600, 0x87AE, 24576 }, | |
252 | { 0x8700, 0x8A3D, 32768 } | 252 | { 0x8700, 0x8A3D, 32768 } | |
253 | }; | 253 | }; | |
254 | 254 | |||
255 | static int axe_match(device_t, cfdata_t, void *); | 255 | static int axe_match(device_t, cfdata_t, void *); | |
256 | static void axe_attach(device_t, device_t, void *); | 256 | static void axe_attach(device_t, device_t, void *); | |
257 | 257 | |||
258 | CFATTACH_DECL_NEW(axe, sizeof(struct axe_softc), | 258 | CFATTACH_DECL_NEW(axe, sizeof(struct axe_softc), | |
259 | axe_match, axe_attach, usbnet_detach, usbnet_activate); | 259 | axe_match, axe_attach, usbnet_detach, usbnet_activate); | |
260 | 260 | |||
261 | static void axe_uno_stop(struct ifnet *, int); | 261 | static void axe_uno_stop(struct ifnet *, int); | |
262 | static void axe_uno_mcast(struct ifnet *); | 262 | static void axe_uno_mcast(struct ifnet *); | |
263 | static int axe_uno_init(struct ifnet *); | 263 | static int axe_uno_init(struct ifnet *); | |
264 | static int axe_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 264 | static int axe_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
265 | static int axe_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 265 | static int axe_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
266 | static void axe_uno_mii_statchg(struct ifnet *); | 266 | static void axe_uno_mii_statchg(struct ifnet *); | |
267 | static void axe_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 267 | static void axe_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
268 | uint32_t); | 268 | uint32_t); | |
269 | static unsigned axe_uno_tx_prepare(struct usbnet *, struct mbuf *, | 269 | static unsigned axe_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
270 | struct usbnet_chain *); | 270 | struct usbnet_chain *); | |
271 | 271 | |||
272 | static void axe_ax88178_init(struct axe_softc *); | 272 | static void axe_ax88178_init(struct axe_softc *); | |
273 | static void axe_ax88772_init(struct axe_softc *); | 273 | static void axe_ax88772_init(struct axe_softc *); | |
274 | static void axe_ax88772a_init(struct axe_softc *); | 274 | static void axe_ax88772a_init(struct axe_softc *); | |
275 | static void axe_ax88772b_init(struct axe_softc *); | 275 | static void axe_ax88772b_init(struct axe_softc *); | |
276 | 276 | |||
277 | static const struct usbnet_ops axe_ops = { | 277 | static const struct usbnet_ops axe_ops = { | |
278 | .uno_stop = axe_uno_stop, | 278 | .uno_stop = axe_uno_stop, | |
279 | .uno_mcast = axe_uno_mcast, | 279 | .uno_mcast = axe_uno_mcast, | |
280 | .uno_read_reg = axe_uno_mii_read_reg, | 280 | .uno_read_reg = axe_uno_mii_read_reg, | |
281 | .uno_write_reg = axe_uno_mii_write_reg, | 281 | .uno_write_reg = axe_uno_mii_write_reg, | |
282 | .uno_statchg = axe_uno_mii_statchg, | 282 | .uno_statchg = axe_uno_mii_statchg, | |
283 | .uno_tx_prepare = axe_uno_tx_prepare, | 283 | .uno_tx_prepare = axe_uno_tx_prepare, | |
284 | .uno_rx_loop = axe_uno_rx_loop, | 284 | .uno_rx_loop = axe_uno_rx_loop, | |
285 | .uno_init = axe_uno_init, | 285 | .uno_init = axe_uno_init, | |
286 | }; | 286 | }; | |
287 | 287 | |||
288 | static usbd_status | 288 | static usbd_status | |
289 | axe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf) | 289 | axe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf) | |
290 | { | 290 | { | |
291 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 291 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
292 | struct usbnet * const un = &sc->axe_un; | 292 | struct usbnet * const un = &sc->axe_un; | |
293 | usb_device_request_t req; | 293 | usb_device_request_t req; | |
294 | usbd_status err; | 294 | usbd_status err; | |
295 | 295 | |||
296 | usbnet_isowned_core(un); | 296 | usbnet_isowned_core(un); | |
297 | 297 | |||
298 | if (usbnet_isdying(un)) | 298 | if (usbnet_isdying(un)) | |
299 | return -1; | 299 | return -1; | |
300 | 300 | |||
301 | DPRINTFN(20, "cmd %#jx index %#jx val %#jx", cmd, index, val, 0); | 301 | DPRINTFN(20, "cmd %#jx index %#jx val %#jx", cmd, index, val, 0); | |
302 | 302 | |||
303 | if (AXE_CMD_DIR(cmd)) | 303 | if (AXE_CMD_DIR(cmd)) | |
304 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 304 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
305 | else | 305 | else | |
306 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 306 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
307 | req.bRequest = AXE_CMD_CMD(cmd); | 307 | req.bRequest = AXE_CMD_CMD(cmd); | |
308 | USETW(req.wValue, val); | 308 | USETW(req.wValue, val); | |
309 | USETW(req.wIndex, index); | 309 | USETW(req.wIndex, index); | |
310 | USETW(req.wLength, AXE_CMD_LEN(cmd)); | 310 | USETW(req.wLength, AXE_CMD_LEN(cmd)); | |
311 | 311 | |||
312 | err = usbd_do_request(un->un_udev, &req, buf); | 312 | err = usbd_do_request(un->un_udev, &req, buf); | |
313 | if (err) | 313 | if (err) | |
314 | DPRINTF("cmd %jd err %jd", cmd, err, 0, 0); | 314 | DPRINTF("cmd %jd err %jd", cmd, err, 0, 0); | |
315 | 315 | |||
316 | return err; | 316 | return err; | |
317 | } | 317 | } | |
318 | 318 | |||
319 | static int | 319 | static int | |
320 | axe_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 320 | axe_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
321 | { | 321 | { | |
322 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 322 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
323 | struct axe_softc * const sc = usbnet_softc(un); | 323 | struct axe_softc * const sc = usbnet_softc(un); | |
324 | usbd_status err; | 324 | usbd_status err; | |
325 | uint16_t data; | 325 | uint16_t data; | |
326 | 326 | |||
327 | DPRINTFN(30, "phy %#jx reg %#jx\n", phy, reg, 0, 0); | 327 | DPRINTFN(30, "phy %#jx reg %#jx\n", phy, reg, 0, 0); | |
328 | 328 | |||
329 | if (un->un_phyno != phy) | 329 | if (un->un_phyno != phy) | |
330 | return EINVAL; | 330 | return EINVAL; | |
331 | 331 | |||
332 | axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); | 332 | axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); | |
333 | 333 | |||
334 | err = axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, &data); | 334 | err = axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, &data); | |
335 | axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); | 335 | axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); | |
336 | 336 | |||
337 | if (err) { | 337 | if (err) { | |
338 | device_printf(un->un_dev, "read PHY failed\n"); | 338 | device_printf(un->un_dev, "read PHY failed\n"); | |
339 | return EIO; | 339 | return EIO; | |
340 | } | 340 | } | |
341 | 341 | |||
342 | *val = le16toh(data); | 342 | *val = le16toh(data); | |
343 | if (AXE_IS_772(un) && reg == MII_BMSR) { | 343 | if (AXE_IS_772(un) && reg == MII_BMSR) { | |
344 | /* | 344 | /* | |
345 | * BMSR of AX88772 indicates that it supports extended | 345 | * BMSR of AX88772 indicates that it supports extended | |
346 | * capability but the extended status register is | 346 | * capability but the extended status register is | |
347 | * reserved for embedded ethernet PHY. So clear the | 347 | * reserved for embedded ethernet PHY. So clear the | |
348 | * extended capability bit of BMSR. | 348 | * extended capability bit of BMSR. | |
349 | */ | 349 | */ | |
350 | *val &= ~BMSR_EXTCAP; | 350 | *val &= ~BMSR_EXTCAP; | |
351 | } | 351 | } | |
352 | 352 | |||
353 | DPRINTFN(30, "phy %#jx reg %#jx val %#jx", phy, reg, *val, 0); | 353 | DPRINTFN(30, "phy %#jx reg %#jx val %#jx", phy, reg, *val, 0); | |
354 | 354 | |||
355 | return 0; | 355 | return 0; | |
356 | } | 356 | } | |
357 | 357 | |||
358 | static int | 358 | static int | |
359 | axe_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 359 | axe_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
360 | { | 360 | { | |
361 | struct axe_softc * const sc = usbnet_softc(un); | 361 | struct axe_softc * const sc = usbnet_softc(un); | |
362 | usbd_status err; | 362 | usbd_status err; | |
363 | uint16_t aval; | 363 | uint16_t aval; | |
364 | 364 | |||
365 | if (un->un_phyno != phy) | 365 | if (un->un_phyno != phy) | |
366 | return EINVAL; | 366 | return EINVAL; | |
367 | 367 | |||
368 | aval = htole16(val); | 368 | aval = htole16(val); | |
369 | 369 | |||
370 | axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); | 370 | axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); | |
371 | err = axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, &aval); | 371 | err = axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, &aval); | |
372 | axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); | 372 | axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); | |
373 | 373 | |||
374 | if (err) | 374 | if (err) | |
375 | return EIO; | 375 | return EIO; | |
376 | return 0; | 376 | return 0; | |
377 | } | 377 | } | |
378 | 378 | |||
379 | static void | 379 | static void | |
380 | axe_uno_mii_statchg(struct ifnet *ifp) | 380 | axe_uno_mii_statchg(struct ifnet *ifp) | |
381 | { | 381 | { | |
382 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 382 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
383 | 383 | |||
384 | struct usbnet * const un = ifp->if_softc; | 384 | struct usbnet * const un = ifp->if_softc; | |
385 | struct axe_softc * const sc = usbnet_softc(un); | 385 | struct axe_softc * const sc = usbnet_softc(un); | |
386 | struct mii_data *mii = usbnet_mii(un); | 386 | struct mii_data *mii = usbnet_mii(un); | |
387 | int val, err; | 387 | int val, err; | |
388 | 388 | |||
389 | if (usbnet_isdying(un)) | 389 | if (usbnet_isdying(un)) | |
390 | return; | 390 | return; | |
391 | 391 | |||
392 | val = 0; | 392 | val = 0; | |
393 | if (AXE_IS_172(un)) { | 393 | if (AXE_IS_172(un)) { | |
394 | if (mii->mii_media_active & IFM_FDX) | 394 | if (mii->mii_media_active & IFM_FDX) | |
395 | val |= AXE_MEDIA_FULL_DUPLEX; | 395 | val |= AXE_MEDIA_FULL_DUPLEX; | |
396 | } else { | 396 | } else { | |
397 | if (mii->mii_media_active & IFM_FDX) { | 397 | if (mii->mii_media_active & IFM_FDX) { | |
398 | val |= AXE_MEDIA_FULL_DUPLEX; | 398 | val |= AXE_MEDIA_FULL_DUPLEX; | |
399 | if (mii->mii_media_active & IFM_ETH_TXPAUSE) | 399 | if (mii->mii_media_active & IFM_ETH_TXPAUSE) | |
400 | val |= AXE_178_MEDIA_TXFLOW_CONTROL_EN; | 400 | val |= AXE_178_MEDIA_TXFLOW_CONTROL_EN; | |
401 | if (mii->mii_media_active & IFM_ETH_RXPAUSE) | 401 | if (mii->mii_media_active & IFM_ETH_RXPAUSE) | |
402 | val |= AXE_178_MEDIA_RXFLOW_CONTROL_EN; | 402 | val |= AXE_178_MEDIA_RXFLOW_CONTROL_EN; | |
403 | } | 403 | } | |
404 | val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC; | 404 | val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC; | |
405 | if (un->un_flags & AX178) | 405 | if (un->un_flags & AX178) | |
406 | val |= AXE_178_MEDIA_ENCK; | 406 | val |= AXE_178_MEDIA_ENCK; | |
407 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 407 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
408 | case IFM_1000_T: | 408 | case IFM_1000_T: | |
409 | val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK; | 409 | val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK; | |
410 | usbnet_set_link(un, true); | 410 | usbnet_set_link(un, true); | |
411 | break; | 411 | break; | |
412 | case IFM_100_TX: | 412 | case IFM_100_TX: | |
413 | val |= AXE_178_MEDIA_100TX; | 413 | val |= AXE_178_MEDIA_100TX; | |
414 | usbnet_set_link(un, true); | 414 | usbnet_set_link(un, true); | |
415 | break; | 415 | break; | |
416 | case IFM_10_T: | 416 | case IFM_10_T: | |
417 | usbnet_set_link(un, true); | 417 | usbnet_set_link(un, true); | |
418 | break; | 418 | break; | |
419 | } | 419 | } | |
420 | } | 420 | } | |
421 | 421 | |||
422 | DPRINTF("val=%#jx", val, 0, 0, 0); | 422 | DPRINTF("val=%#jx", val, 0, 0, 0); | |
423 | err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL); | 423 | err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL); | |
424 | if (err) | 424 | if (err) | |
425 | device_printf(un->un_dev, "media change failed\n"); | 425 | device_printf(un->un_dev, "media change failed\n"); | |
426 | } | 426 | } | |
427 | 427 | |||
428 | static void | 428 | static void | |
429 | axe_rcvfilt_locked(struct usbnet *un) | 429 | axe_rcvfilt_locked(struct usbnet *un) | |
430 | { | 430 | { | |
431 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 431 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
432 | struct axe_softc * const sc = usbnet_softc(un); | 432 | struct axe_softc * const sc = usbnet_softc(un); | |
433 | struct ifnet * const ifp = usbnet_ifp(un); | 433 | struct ifnet * const ifp = usbnet_ifp(un); | |
434 | struct ethercom *ec = usbnet_ec(un); | 434 | struct ethercom *ec = usbnet_ec(un); | |
435 | struct ether_multi *enm; | 435 | struct ether_multi *enm; | |
436 | struct ether_multistep step; | 436 | struct ether_multistep step; | |
437 | uint16_t rxmode; | 437 | uint16_t rxmode; | |
438 | uint32_t h = 0; | 438 | uint32_t h = 0; | |
439 | uint8_t mchash[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 439 | uint8_t mchash[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
440 | 440 | |||
441 | if (usbnet_isdying(un)) | 441 | if (usbnet_isdying(un)) | |
442 | return; | 442 | return; | |
443 | 443 | |||
444 | if (axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode)) { | 444 | if (axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode)) { | |
445 | device_printf(un->un_dev, "can't read rxmode"); | 445 | device_printf(un->un_dev, "can't read rxmode"); | |
446 | return; | 446 | return; | |
447 | } | 447 | } | |
448 | rxmode = le16toh(rxmode); | 448 | rxmode = le16toh(rxmode); | |
449 | 449 | |||
450 | rxmode &= | 450 | rxmode &= | |
451 | ~(AXE_RXCMD_ALLMULTI | AXE_RXCMD_PROMISC | AXE_RXCMD_MULTICAST); | 451 | ~(AXE_RXCMD_ALLMULTI | AXE_RXCMD_PROMISC | AXE_RXCMD_MULTICAST); | |
452 | 452 | |||
453 | ETHER_LOCK(ec); | 453 | ETHER_LOCK(ec); | |
454 | if (ifp->if_flags & IFF_PROMISC) { | 454 | if (ifp->if_flags & IFF_PROMISC) { | |
455 | ec->ec_flags |= ETHER_F_ALLMULTI; | 455 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
456 | ETHER_UNLOCK(ec); | 456 | ETHER_UNLOCK(ec); | |
457 | /* run promisc. mode */ | 457 | /* run promisc. mode */ | |
458 | rxmode |= AXE_RXCMD_ALLMULTI; /* ??? */ | 458 | rxmode |= AXE_RXCMD_ALLMULTI; /* ??? */ | |
459 | rxmode |= AXE_RXCMD_PROMISC; | 459 | rxmode |= AXE_RXCMD_PROMISC; | |
460 | goto update; | 460 | goto update; | |
461 | } | 461 | } | |
462 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 462 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
463 | ETHER_FIRST_MULTI(step, ec, enm); | 463 | ETHER_FIRST_MULTI(step, ec, enm); | |
464 | while (enm != NULL) { | 464 | while (enm != NULL) { | |
465 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 465 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
466 | ec->ec_flags |= ETHER_F_ALLMULTI; | 466 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
467 | ETHER_UNLOCK(ec); | 467 | ETHER_UNLOCK(ec); | |
468 | /* accept all mcast frames */ | 468 | /* accept all mcast frames */ | |
469 | rxmode |= AXE_RXCMD_ALLMULTI; | 469 | rxmode |= AXE_RXCMD_ALLMULTI; | |
470 | goto update; | 470 | goto update; | |
471 | } | 471 | } | |
472 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | 472 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | |
473 | mchash[h >> 29] |= 1U << ((h >> 26) & 7); | 473 | mchash[h >> 29] |= 1U << ((h >> 26) & 7); | |
474 | ETHER_NEXT_MULTI(step, enm); | 474 | ETHER_NEXT_MULTI(step, enm); | |
475 | } | 475 | } | |
476 | ETHER_UNLOCK(ec); | 476 | ETHER_UNLOCK(ec); | |
477 | if (h != 0) | 477 | if (h != 0) | |
478 | rxmode |= AXE_RXCMD_MULTICAST; /* activate mcast hash filter */ | 478 | rxmode |= AXE_RXCMD_MULTICAST; /* activate mcast hash filter */ | |
479 | axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, mchash); | 479 | axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, mchash); | |
480 | update: | 480 | update: | |
481 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); | 481 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); | |
482 | } | 482 | } | |
483 | 483 | |||
484 | static void | 484 | static void | |
485 | axe_ax_init(struct usbnet *un) | 485 | axe_ax_init(struct usbnet *un) | |
486 | { | 486 | { | |
487 | struct axe_softc * const sc = usbnet_softc(un); | 487 | struct axe_softc * const sc = usbnet_softc(un); | |
488 | 488 | |||
489 | int cmd = AXE_178_CMD_READ_NODEID; | 489 | int cmd = AXE_178_CMD_READ_NODEID; | |
490 | 490 | |||
491 | if (un->un_flags & AX178) { | 491 | if (un->un_flags & AX178) { | |
492 | axe_ax88178_init(sc); | 492 | axe_ax88178_init(sc); | |
493 | } else if (un->un_flags & AX772) { | 493 | } else if (un->un_flags & AX772) { | |
494 | axe_ax88772_init(sc); | 494 | axe_ax88772_init(sc); | |
495 | } else if (un->un_flags & AX772A) { | 495 | } else if (un->un_flags & AX772A) { | |
496 | axe_ax88772a_init(sc); | 496 | axe_ax88772a_init(sc); | |
497 | } else if (un->un_flags & AX772B) { | 497 | } else if (un->un_flags & AX772B) { | |
498 | axe_ax88772b_init(sc); | 498 | axe_ax88772b_init(sc); | |
499 | return; | 499 | return; | |
500 | } else { | 500 | } else { | |
501 | cmd = AXE_172_CMD_READ_NODEID; | 501 | cmd = AXE_172_CMD_READ_NODEID; | |
502 | } | 502 | } | |
503 | 503 | |||
504 | if (axe_cmd(sc, cmd, 0, 0, un->un_eaddr)) { | 504 | if (axe_cmd(sc, cmd, 0, 0, un->un_eaddr)) { | |
505 | aprint_error_dev(un->un_dev, | 505 | aprint_error_dev(un->un_dev, | |
506 | "failed to read ethernet address\n"); | 506 | "failed to read ethernet address\n"); | |
507 | } | 507 | } | |
508 | } | 508 | } | |
509 | 509 | |||
510 | 510 | |||
511 | static void | 511 | static void | |
512 | axe_reset(struct usbnet *un) | 512 | axe_reset(struct usbnet *un) | |
513 | { | 513 | { | |
514 | 514 | |||
515 | usbnet_isowned_core(un); | 515 | usbnet_isowned_core(un); | |
516 | 516 | |||
517 | if (usbnet_isdying(un)) | 517 | if (usbnet_isdying(un)) | |
518 | return; | 518 | return; | |
519 | 519 | |||
520 | /* | 520 | /* | |
521 | * softnet_lock can be taken when NET_MPAFE is not defined when calling | 521 | * softnet_lock can be taken when NET_MPAFE is not defined when calling | |
522 | * if_addr_init -> if_init. This doesn't mix well with the | 522 | * if_addr_init -> if_init. This doesn't mix well with the | |
523 | * usbd_delay_ms calls in the init routines as things like nd6_slowtimo | 523 | * usbd_delay_ms calls in the init routines as things like nd6_slowtimo | |
524 | * can fire during the wait and attempt to take softnet_lock and then | 524 | * can fire during the wait and attempt to take softnet_lock and then | |
525 | * block the softclk thread meaning the wait never ends. | 525 | * block the softclk thread meaning the wait never ends. | |
526 | */ | 526 | */ | |
527 | #ifndef NET_MPSAFE | 527 | #ifndef NET_MPSAFE | |
528 | /* XXX What to reset? */ | 528 | /* XXX What to reset? */ | |
529 | 529 | |||
530 | /* Wait a little while for the chip to get its brains in order. */ | 530 | /* Wait a little while for the chip to get its brains in order. */ | |
531 | DELAY(1000); | 531 | DELAY(1000); | |
532 | #else | 532 | #else | |
533 | axe_ax_init(un); | 533 | axe_ax_init(un); | |
534 | #endif | 534 | #endif | |
535 | } | 535 | } | |
536 | 536 | |||
537 | static int | 537 | static int | |
538 | axe_get_phyno(struct axe_softc *sc, int sel) | 538 | axe_get_phyno(struct axe_softc *sc, int sel) | |
539 | { | 539 | { | |
540 | int phyno; | 540 | int phyno; | |
541 | 541 | |||
542 | switch (AXE_PHY_TYPE(sc->axe_phyaddrs[sel])) { | 542 | switch (AXE_PHY_TYPE(sc->axe_phyaddrs[sel])) { | |
543 | case PHY_TYPE_100_HOME: | 543 | case PHY_TYPE_100_HOME: | |
544 | /* FALLTHROUGH */ | 544 | /* FALLTHROUGH */ | |
545 | case PHY_TYPE_GIG: | 545 | case PHY_TYPE_GIG: | |
546 | phyno = AXE_PHY_NO(sc->axe_phyaddrs[sel]); | 546 | phyno = AXE_PHY_NO(sc->axe_phyaddrs[sel]); | |
547 | break; | 547 | break; | |
548 | case PHY_TYPE_SPECIAL: | 548 | case PHY_TYPE_SPECIAL: | |
549 | /* FALLTHROUGH */ | 549 | /* FALLTHROUGH */ | |
550 | case PHY_TYPE_RSVD: | 550 | case PHY_TYPE_RSVD: | |
551 | /* FALLTHROUGH */ | 551 | /* FALLTHROUGH */ | |
552 | case PHY_TYPE_NON_SUP: | 552 | case PHY_TYPE_NON_SUP: | |
553 | /* FALLTHROUGH */ | 553 | /* FALLTHROUGH */ | |
554 | default: | 554 | default: | |
555 | phyno = -1; | 555 | phyno = -1; | |
556 | break; | 556 | break; | |
557 | } | 557 | } | |
558 | 558 | |||
559 | return phyno; | 559 | return phyno; | |
560 | } | 560 | } | |
561 | 561 | |||
562 | #define AXE_GPIO_WRITE(x, y) do { \ | 562 | #define AXE_GPIO_WRITE(x, y) do { \ | |
563 | axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, (x), NULL); \ | 563 | axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, (x), NULL); \ | |
564 | usbd_delay_ms(sc->axe_un.un_udev, hztoms(y)); \ | 564 | usbd_delay_ms(sc->axe_un.un_udev, hztoms(y)); \ | |
565 | } while (0) | 565 | } while (0) | |
566 | 566 | |||
567 | static void | 567 | static void | |
568 | axe_ax88178_init(struct axe_softc *sc) | 568 | axe_ax88178_init(struct axe_softc *sc) | |
569 | { | 569 | { | |
570 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 570 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
571 | struct usbnet * const un = &sc->axe_un; | 571 | struct usbnet * const un = &sc->axe_un; | |
572 | int gpio0, ledmode, phymode; | 572 | int gpio0, ledmode, phymode; | |
573 | uint16_t eeprom, val; | 573 | uint16_t eeprom, val; | |
574 | 574 | |||
575 | axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL); | 575 | axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL); | |
576 | /* XXX magic */ | 576 | /* XXX magic */ | |
577 | if (axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom) != 0) | 577 | if (axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom) != 0) | |
578 | eeprom = 0xffff; | 578 | eeprom = 0xffff; | |
579 | axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL); | 579 | axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL); | |
580 | 580 | |||
581 | eeprom = le16toh(eeprom); | 581 | eeprom = le16toh(eeprom); | |
582 | 582 | |||
583 | DPRINTF("EEPROM is %#jx", eeprom, 0, 0, 0); | 583 | DPRINTF("EEPROM is %#jx", eeprom, 0, 0, 0); | |
584 | 584 | |||
585 | /* if EEPROM is invalid we have to use to GPIO0 */ | 585 | /* if EEPROM is invalid we have to use to GPIO0 */ | |
586 | if (eeprom == 0xffff) { | 586 | if (eeprom == 0xffff) { | |
587 | phymode = AXE_PHY_MODE_MARVELL; | 587 | phymode = AXE_PHY_MODE_MARVELL; | |
588 | gpio0 = 1; | 588 | gpio0 = 1; | |
589 | ledmode = 0; | 589 | ledmode = 0; | |
590 | } else { | 590 | } else { | |
591 | phymode = eeprom & 0x7f; | 591 | phymode = eeprom & 0x7f; | |
592 | gpio0 = (eeprom & 0x80) ? 0 : 1; | 592 | gpio0 = (eeprom & 0x80) ? 0 : 1; | |
593 | ledmode = eeprom >> 8; | 593 | ledmode = eeprom >> 8; | |
594 | } | 594 | } | |
595 | 595 | |||
596 | DPRINTF("use gpio0: %jd, phymode %jd", gpio0, phymode, 0, 0); | 596 | DPRINTF("use gpio0: %jd, phymode %jd", gpio0, phymode, 0, 0); | |
597 | 597 | |||
598 | /* Program GPIOs depending on PHY hardware. */ | 598 | /* Program GPIOs depending on PHY hardware. */ | |
599 | switch (phymode) { | 599 | switch (phymode) { | |
600 | case AXE_PHY_MODE_MARVELL: | 600 | case AXE_PHY_MODE_MARVELL: | |
601 | if (gpio0 == 1) { | 601 | if (gpio0 == 1) { | |
602 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0_EN, | 602 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0_EN, | |
603 | hz / 32); | 603 | hz / 32); | |
604 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, | 604 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, | |
605 | hz / 32); | 605 | hz / 32); | |
606 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2_EN, hz / 4); | 606 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2_EN, hz / 4); | |
607 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, | 607 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, | |
608 | hz / 32); | 608 | hz / 32); | |
609 | } else { | 609 | } else { | |
610 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | 610 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | |
611 | AXE_GPIO1_EN, hz / 3); | 611 | AXE_GPIO1_EN, hz / 3); | |
612 | if (ledmode == 1) { | 612 | if (ledmode == 1) { | |
613 | AXE_GPIO_WRITE(AXE_GPIO1_EN, hz / 3); | 613 | AXE_GPIO_WRITE(AXE_GPIO1_EN, hz / 3); | |
614 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN, | 614 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN, | |
615 | hz / 3); | 615 | hz / 3); | |
616 | } else { | 616 | } else { | |
617 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | 617 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | |
618 | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | 618 | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | |
619 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | 619 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | |
620 | AXE_GPIO2_EN, hz / 4); | 620 | AXE_GPIO2_EN, hz / 4); | |
621 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | 621 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | |
622 | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | 622 | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | |
623 | } | 623 | } | |
624 | } | 624 | } | |
625 | break; | 625 | break; | |
626 | case AXE_PHY_MODE_CICADA: | 626 | case AXE_PHY_MODE_CICADA: | |
627 | case AXE_PHY_MODE_CICADA_V2: | 627 | case AXE_PHY_MODE_CICADA_V2: | |
628 | case AXE_PHY_MODE_CICADA_V2_ASIX: | 628 | case AXE_PHY_MODE_CICADA_V2_ASIX: | |
629 | if (gpio0 == 1) | 629 | if (gpio0 == 1) | |
630 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0 | | 630 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0 | | |
631 | AXE_GPIO0_EN, hz / 32); | 631 | AXE_GPIO0_EN, hz / 32); | |
632 | else | 632 | else | |
633 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | 633 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | |
634 | AXE_GPIO1_EN, hz / 32); | 634 | AXE_GPIO1_EN, hz / 32); | |
635 | break; | 635 | break; | |
636 | case AXE_PHY_MODE_AGERE: | 636 | case AXE_PHY_MODE_AGERE: | |
637 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | 637 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | |
638 | AXE_GPIO1_EN, hz / 32); | 638 | AXE_GPIO1_EN, hz / 32); | |
639 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | | 639 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | | |
640 | AXE_GPIO2_EN, hz / 32); | 640 | AXE_GPIO2_EN, hz / 32); | |
641 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2_EN, hz / 4); | 641 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2_EN, hz / 4); | |
642 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | | 642 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | | |
643 | AXE_GPIO2_EN, hz / 32); | 643 | AXE_GPIO2_EN, hz / 32); | |
644 | break; | 644 | break; | |
645 | case AXE_PHY_MODE_REALTEK_8211CL: | 645 | case AXE_PHY_MODE_REALTEK_8211CL: | |
646 | case AXE_PHY_MODE_REALTEK_8211BN: | 646 | case AXE_PHY_MODE_REALTEK_8211BN: | |
647 | case AXE_PHY_MODE_REALTEK_8251CL: | 647 | case AXE_PHY_MODE_REALTEK_8251CL: | |
648 | val = gpio0 == 1 ? AXE_GPIO0 | AXE_GPIO0_EN : | 648 | val = gpio0 == 1 ? AXE_GPIO0 | AXE_GPIO0_EN : | |
649 | AXE_GPIO1 | AXE_GPIO1_EN; | 649 | AXE_GPIO1 | AXE_GPIO1_EN; | |
650 | AXE_GPIO_WRITE(val, hz / 32); | 650 | AXE_GPIO_WRITE(val, hz / 32); | |
651 | AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | 651 | AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | |
652 | AXE_GPIO_WRITE(val | AXE_GPIO2_EN, hz / 4); | 652 | AXE_GPIO_WRITE(val | AXE_GPIO2_EN, hz / 4); | |
653 | AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | 653 | AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | |
654 | if (phymode == AXE_PHY_MODE_REALTEK_8211CL) { | 654 | if (phymode == AXE_PHY_MODE_REALTEK_8211CL) { | |
655 | axe_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0005); | 655 | axe_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0005); | |
656 | axe_uno_mii_write_reg(un, un->un_phyno, 0x0C, 0x0000); | 656 | axe_uno_mii_write_reg(un, un->un_phyno, 0x0C, 0x0000); | |
657 | axe_uno_mii_read_reg(un, un->un_phyno, 0x0001, &val); | 657 | axe_uno_mii_read_reg(un, un->un_phyno, 0x0001, &val); | |
658 | axe_uno_mii_write_reg(un, un->un_phyno, 0x01, val | 0x0080); | 658 | axe_uno_mii_write_reg(un, un->un_phyno, 0x01, val | 0x0080); | |
659 | axe_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0000); | 659 | axe_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0000); | |
660 | } | 660 | } | |
661 | break; | 661 | break; | |
662 | default: | 662 | default: | |
663 | /* Unknown PHY model or no need to program GPIOs. */ | 663 | /* Unknown PHY model or no need to program GPIOs. */ | |
664 | break; | 664 | break; | |
665 | } | 665 | } | |
666 | 666 | |||
667 | /* soft reset */ | 667 | /* soft reset */ | |
668 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | 668 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | |
669 | usbd_delay_ms(un->un_udev, 150); | 669 | usbd_delay_ms(un->un_udev, 150); | |
670 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | 670 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | |
671 | AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL); | 671 | AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL); | |
672 | usbd_delay_ms(un->un_udev, 150); | 672 | usbd_delay_ms(un->un_udev, 150); | |
673 | /* Enable MII/GMII/RGMII interface to work with external PHY. */ | 673 | /* Enable MII/GMII/RGMII interface to work with external PHY. */ | |
674 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL); | 674 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL); | |
675 | usbd_delay_ms(un->un_udev, 10); | 675 | usbd_delay_ms(un->un_udev, 10); | |
676 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | 676 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | |
677 | } | 677 | } | |
678 | 678 | |||
679 | static void | 679 | static void | |
680 | axe_ax88772_init(struct axe_softc *sc) | 680 | axe_ax88772_init(struct axe_softc *sc) | |
681 | { | 681 | { | |
682 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 682 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
683 | struct usbnet * const un = &sc->axe_un; | 683 | struct usbnet * const un = &sc->axe_un; | |
684 | 684 | |||
685 | axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL); | 685 | axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL); | |
686 | usbd_delay_ms(un->un_udev, 40); | 686 | usbd_delay_ms(un->un_udev, 40); | |
687 | 687 | |||
688 | if (un->un_phyno == AXE_772_PHY_NO_EPHY) { | 688 | if (un->un_phyno == AXE_772_PHY_NO_EPHY) { | |
689 | /* ask for the embedded PHY */ | 689 | /* ask for the embedded PHY */ | |
690 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, | 690 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, | |
691 | AXE_SW_PHY_SELECT_EMBEDDED, NULL); | 691 | AXE_SW_PHY_SELECT_EMBEDDED, NULL); | |
692 | usbd_delay_ms(un->un_udev, 10); | 692 | usbd_delay_ms(un->un_udev, 10); | |
693 | 693 | |||
694 | /* power down and reset state, pin reset state */ | 694 | /* power down and reset state, pin reset state */ | |
695 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | 695 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | |
696 | usbd_delay_ms(un->un_udev, 60); | 696 | usbd_delay_ms(un->un_udev, 60); | |
697 | 697 | |||
698 | /* power down/reset state, pin operating state */ | 698 | /* power down/reset state, pin operating state */ | |
699 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | 699 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | |
700 | AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); | 700 | AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); | |
701 | usbd_delay_ms(un->un_udev, 150); | 701 | usbd_delay_ms(un->un_udev, 150); | |
702 | 702 | |||
703 | /* power up, reset */ | 703 | /* power up, reset */ | |
704 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL); | 704 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL); | |
705 | 705 | |||
706 | /* power up, operating */ | 706 | /* power up, operating */ | |
707 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | 707 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | |
708 | AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL); | 708 | AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL); | |
709 | } else { | 709 | } else { | |
710 | /* ask for external PHY */ | 710 | /* ask for external PHY */ | |
711 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_EXT, | 711 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_EXT, | |
712 | NULL); | 712 | NULL); | |
713 | usbd_delay_ms(un->un_udev, 10); | 713 | usbd_delay_ms(un->un_udev, 10); | |
714 | 714 | |||
715 | /* power down internal PHY */ | 715 | /* power down internal PHY */ | |
716 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | 716 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | |
717 | AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); | 717 | AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); | |
718 | } | 718 | } | |
719 | 719 | |||
720 | usbd_delay_ms(un->un_udev, 150); | 720 | usbd_delay_ms(un->un_udev, 150); | |
721 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | 721 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | |
722 | } | 722 | } | |
723 | 723 | |||
724 | static void | 724 | static void | |
725 | axe_ax88772_phywake(struct axe_softc *sc) | 725 | axe_ax88772_phywake(struct axe_softc *sc) | |
726 | { | 726 | { | |
727 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 727 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
728 | struct usbnet * const un = &sc->axe_un; | 728 | struct usbnet * const un = &sc->axe_un; | |
729 | 729 | |||
730 | if (un->un_phyno == AXE_772_PHY_NO_EPHY) { | 730 | if (un->un_phyno == AXE_772_PHY_NO_EPHY) { | |
731 | /* Manually select internal(embedded) PHY - MAC mode. */ | 731 | /* Manually select internal(embedded) PHY - MAC mode. */ | |
732 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, | 732 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, | |
733 | AXE_SW_PHY_SELECT_EMBEDDED, NULL); | 733 | AXE_SW_PHY_SELECT_EMBEDDED, NULL); | |
734 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | 734 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | |
735 | } else { | 735 | } else { | |
736 | /* | 736 | /* | |
737 | * Manually select external PHY - MAC mode. | 737 | * Manually select external PHY - MAC mode. | |
738 | * Reverse MII/RMII is for AX88772A PHY mode. | 738 | * Reverse MII/RMII is for AX88772A PHY mode. | |
739 | */ | 739 | */ | |
740 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_SS_ENB | | 740 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_SS_ENB | | |
741 | AXE_SW_PHY_SELECT_EXT | AXE_SW_PHY_SELECT_SS_MII, NULL); | 741 | AXE_SW_PHY_SELECT_EXT | AXE_SW_PHY_SELECT_SS_MII, NULL); | |
742 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | 742 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | |
743 | } | 743 | } | |
744 | 744 | |||
745 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPPD | | 745 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPPD | | |
746 | AXE_SW_RESET_IPRL, NULL); | 746 | AXE_SW_RESET_IPRL, NULL); | |
747 | 747 | |||
748 | /* T1 = min 500ns everywhere */ | 748 | /* T1 = min 500ns everywhere */ | |
749 | usbd_delay_ms(un->un_udev, 150); | 749 | usbd_delay_ms(un->un_udev, 150); | |
750 | 750 | |||
751 | /* Take PHY out of power down. */ | 751 | /* Take PHY out of power down. */ | |
752 | if (un->un_phyno == AXE_772_PHY_NO_EPHY) { | 752 | if (un->un_phyno == AXE_772_PHY_NO_EPHY) { | |
753 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL); | 753 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL); | |
754 | } else { | 754 | } else { | |
755 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRTE, NULL); | 755 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRTE, NULL); | |
756 | } | 756 | } | |
757 | 757 | |||
758 | /* 772 T2 is 60ms. 772A T2 is 160ms, 772B T2 is 600ms */ | 758 | /* 772 T2 is 60ms. 772A T2 is 160ms, 772B T2 is 600ms */ | |
759 | usbd_delay_ms(un->un_udev, 600); | 759 | usbd_delay_ms(un->un_udev, 600); | |
760 | 760 | |||
761 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | 761 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | |
762 | 762 | |||
763 | /* T3 = 500ns everywhere */ | 763 | /* T3 = 500ns everywhere */ | |
764 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | 764 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | |
765 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL); | 765 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL); | |
766 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | 766 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | |
767 | } | 767 | } | |
768 | 768 | |||
769 | static void | 769 | static void | |
770 | axe_ax88772a_init(struct axe_softc *sc) | 770 | axe_ax88772a_init(struct axe_softc *sc) | |
771 | { | 771 | { | |
772 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 772 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
773 | 773 | |||
774 | /* Reload EEPROM. */ | 774 | /* Reload EEPROM. */ | |
775 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM, hz / 32); | 775 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM, hz / 32); | |
776 | axe_ax88772_phywake(sc); | 776 | axe_ax88772_phywake(sc); | |
777 | /* Stop MAC. */ | 777 | /* Stop MAC. */ | |
778 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | 778 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | |
779 | } | 779 | } | |
780 | 780 | |||
781 | static void | 781 | static void | |
782 | axe_ax88772b_init(struct axe_softc *sc) | 782 | axe_ax88772b_init(struct axe_softc *sc) | |
783 | { | 783 | { | |
784 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 784 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
785 | struct usbnet * const un = &sc->axe_un; | 785 | struct usbnet * const un = &sc->axe_un; | |
786 | uint16_t eeprom; | 786 | uint16_t eeprom; | |
787 | int i; | 787 | int i; | |
788 | 788 | |||
789 | /* Reload EEPROM. */ | 789 | /* Reload EEPROM. */ | |
790 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM , hz / 32); | 790 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM , hz / 32); | |
791 | 791 | |||
792 | /* | 792 | /* | |
793 | * Save PHY power saving configuration(high byte) and | 793 | * Save PHY power saving configuration(high byte) and | |
794 | * clear EEPROM checksum value(low byte). | 794 | * clear EEPROM checksum value(low byte). | |
795 | */ | 795 | */ | |
796 | if (axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_PHY_PWRCFG, | 796 | if (axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_PHY_PWRCFG, | |
797 | &eeprom)) { | 797 | &eeprom)) { | |
798 | aprint_error_dev(un->un_dev, "failed to read eeprom\n"); | 798 | aprint_error_dev(un->un_dev, "failed to read eeprom\n"); | |
799 | return; | 799 | return; | |
800 | } | 800 | } | |
801 | 801 | |||
802 | sc->sc_pwrcfg = le16toh(eeprom) & 0xFF00; | 802 | sc->sc_pwrcfg = le16toh(eeprom) & 0xFF00; | |
803 | 803 | |||
804 | /* | 804 | /* | |
805 | * Auto-loaded default station address from internal ROM is | 805 | * Auto-loaded default station address from internal ROM is | |
806 | * 00:00:00:00:00:00 such that an explicit access to EEPROM | 806 | * 00:00:00:00:00:00 such that an explicit access to EEPROM | |
807 | * is required to get real station address. | 807 | * is required to get real station address. | |
808 | */ | 808 | */ | |
809 | uint8_t *eaddr = un->un_eaddr; | 809 | uint8_t *eaddr = un->un_eaddr; | |
810 | for (i = 0; i < ETHER_ADDR_LEN / 2; i++) { | 810 | for (i = 0; i < ETHER_ADDR_LEN / 2; i++) { | |
811 | if (axe_cmd(sc, AXE_CMD_SROM_READ, 0, | 811 | if (axe_cmd(sc, AXE_CMD_SROM_READ, 0, | |
812 | AXE_EEPROM_772B_NODE_ID + i, &eeprom)) { | 812 | AXE_EEPROM_772B_NODE_ID + i, &eeprom)) { | |
813 | aprint_error_dev(un->un_dev, | 813 | aprint_error_dev(un->un_dev, | |
814 | "failed to read eeprom\n"); | 814 | "failed to read eeprom\n"); | |
815 | eeprom = 0; | 815 | eeprom = 0; | |
816 | } | 816 | } | |
817 | eeprom = le16toh(eeprom); | 817 | eeprom = le16toh(eeprom); | |
818 | *eaddr++ = (uint8_t)(eeprom & 0xFF); | 818 | *eaddr++ = (uint8_t)(eeprom & 0xFF); | |
819 | *eaddr++ = (uint8_t)((eeprom >> 8) & 0xFF); | 819 | *eaddr++ = (uint8_t)((eeprom >> 8) & 0xFF); | |
820 | } | 820 | } | |
821 | /* Wakeup PHY. */ | 821 | /* Wakeup PHY. */ | |
822 | axe_ax88772_phywake(sc); | 822 | axe_ax88772_phywake(sc); | |
823 | /* Stop MAC. */ | 823 | /* Stop MAC. */ | |
824 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | 824 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | |
825 | } | 825 | } | |
826 | 826 | |||
827 | #undef AXE_GPIO_WRITE | 827 | #undef AXE_GPIO_WRITE | |
828 | 828 | |||
829 | /* | 829 | /* | |
830 | * Probe for a AX88172 chip. | 830 | * Probe for a AX88172 chip. | |
831 | */ | 831 | */ | |
832 | static int | 832 | static int | |
833 | axe_match(device_t parent, cfdata_t match, void *aux) | 833 | axe_match(device_t parent, cfdata_t match, void *aux) | |
834 | { | 834 | { | |
835 | struct usb_attach_arg *uaa = aux; | 835 | struct usb_attach_arg *uaa = aux; | |
836 | 836 | |||
837 | return axe_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 837 | return axe_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
838 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 838 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
839 | } | 839 | } | |
840 | 840 | |||
841 | /* | 841 | /* | |
842 | * Attach the interface. Allocate softc structures, do ifmedia | 842 | * Attach the interface. Allocate softc structures, do ifmedia | |
843 | * setup and ethernet/BPF attach. | 843 | * setup and ethernet/BPF attach. | |
844 | */ | 844 | */ | |
845 | static void | 845 | static void | |
846 | axe_attach(device_t parent, device_t self, void *aux) | 846 | axe_attach(device_t parent, device_t self, void *aux) | |
847 | { | 847 | { | |
848 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 848 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
849 | USBNET_MII_DECL_DEFAULT(unm); | 849 | USBNET_MII_DECL_DEFAULT(unm); | |
850 | struct axe_softc *sc = device_private(self); | 850 | struct axe_softc *sc = device_private(self); | |
851 | struct usbnet * const un = &sc->axe_un; | 851 | struct usbnet * const un = &sc->axe_un; | |
852 | struct usb_attach_arg *uaa = aux; | 852 | struct usb_attach_arg *uaa = aux; | |
853 | struct usbd_device *dev = uaa->uaa_device; | 853 | struct usbd_device *dev = uaa->uaa_device; | |
854 | usbd_status err; | 854 | usbd_status err; | |
855 | usb_interface_descriptor_t *id; | 855 | usb_interface_descriptor_t *id; | |
856 | usb_endpoint_descriptor_t *ed; | 856 | usb_endpoint_descriptor_t *ed; | |
857 | char *devinfop; | 857 | char *devinfop; | |
858 | unsigned bufsz; | 858 | unsigned bufsz; | |
859 | int i; | 859 | int i; | |
860 | 860 | |||
861 | KASSERT((void *)sc == un); | 861 | KASSERT((void *)sc == un); | |
862 | 862 | |||
863 | aprint_naive("\n"); | 863 | aprint_naive("\n"); | |
864 | aprint_normal("\n"); | 864 | aprint_normal("\n"); | |
865 | devinfop = usbd_devinfo_alloc(dev, 0); | 865 | devinfop = usbd_devinfo_alloc(dev, 0); | |
866 | aprint_normal_dev(self, "%s\n", devinfop); | 866 | aprint_normal_dev(self, "%s\n", devinfop); | |
867 | usbd_devinfo_free(devinfop); | 867 | usbd_devinfo_free(devinfop); | |
868 | 868 | |||
869 | un->un_dev = self; | 869 | un->un_dev = self; | |
870 | un->un_udev = dev; | 870 | un->un_udev = dev; | |
871 | un->un_sc = sc; | 871 | un->un_sc = sc; | |
872 | un->un_ops = &axe_ops; | 872 | un->un_ops = &axe_ops; | |
873 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 873 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
874 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 874 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
875 | un->un_rx_list_cnt = AXE_RX_LIST_CNT; | 875 | un->un_rx_list_cnt = AXE_RX_LIST_CNT; | |
876 | un->un_tx_list_cnt = AXE_TX_LIST_CNT; | 876 | un->un_tx_list_cnt = AXE_TX_LIST_CNT; | |
877 | 877 | |||
878 | err = usbd_set_config_no(dev, AXE_CONFIG_NO, 1); | 878 | err = usbd_set_config_no(dev, AXE_CONFIG_NO, 1); | |
879 | if (err) { | 879 | if (err) { | |
880 | aprint_error_dev(self, "failed to set configuration" | 880 | aprint_error_dev(self, "failed to set configuration" | |
881 | ", err=%s\n", usbd_errstr(err)); | 881 | ", err=%s\n", usbd_errstr(err)); | |
882 | return; | 882 | return; | |
883 | } | 883 | } | |
884 | 884 | |||
885 | un->un_flags = axe_lookup(uaa->uaa_vendor, uaa->uaa_product)->axe_flags; | 885 | un->un_flags = axe_lookup(uaa->uaa_vendor, uaa->uaa_product)->axe_flags; | |
886 | 886 | |||
887 | err = usbd_device2interface_handle(dev, AXE_IFACE_IDX, &un->un_iface); | 887 | err = usbd_device2interface_handle(dev, AXE_IFACE_IDX, &un->un_iface); | |
888 | if (err) { | 888 | if (err) { | |
889 | aprint_error_dev(self, "getting interface handle failed\n"); | 889 | aprint_error_dev(self, "getting interface handle failed\n"); | |
890 | return; | 890 | return; | |
891 | } | 891 | } | |
892 | 892 | |||
893 | id = usbd_get_interface_descriptor(un->un_iface); | 893 | id = usbd_get_interface_descriptor(un->un_iface); | |
894 | 894 | |||
895 | /* decide on what our bufsize will be */ | 895 | /* decide on what our bufsize will be */ | |
896 | if (AXE_IS_172(un)) | 896 | if (AXE_IS_172(un)) | |
897 | bufsz = AXE_172_BUFSZ; | 897 | bufsz = AXE_172_BUFSZ; | |
898 | else | 898 | else | |
899 | bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? | 899 | bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? | |
900 | AXE_178_MAX_BUFSZ : AXE_178_MIN_BUFSZ; | 900 | AXE_178_MAX_BUFSZ : AXE_178_MIN_BUFSZ; | |
901 | un->un_rx_bufsz = un->un_tx_bufsz = bufsz; | 901 | un->un_rx_bufsz = un->un_tx_bufsz = bufsz; | |
902 | 902 | |||
903 | un->un_ed[USBNET_ENDPT_RX] = 0; | 903 | un->un_ed[USBNET_ENDPT_RX] = 0; | |
904 | un->un_ed[USBNET_ENDPT_TX] = 0; | 904 | un->un_ed[USBNET_ENDPT_TX] = 0; | |
905 | un->un_ed[USBNET_ENDPT_INTR] = 0; | 905 | un->un_ed[USBNET_ENDPT_INTR] = 0; | |
906 | 906 | |||
907 | /* Find endpoints. */ | 907 | /* Find endpoints. */ | |
908 | for (i = 0; i < id->bNumEndpoints; i++) { | 908 | for (i = 0; i < id->bNumEndpoints; i++) { | |
909 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 909 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
910 | if (ed == NULL) { | 910 | if (ed == NULL) { | |
911 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 911 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
912 | return; | 912 | return; | |
913 | } | 913 | } | |
914 | const uint8_t xt = UE_GET_XFERTYPE(ed->bmAttributes); | 914 | const uint8_t xt = UE_GET_XFERTYPE(ed->bmAttributes); | |
915 | const uint8_t dir = UE_GET_DIR(ed->bEndpointAddress); | 915 | const uint8_t dir = UE_GET_DIR(ed->bEndpointAddress); | |
916 | 916 | |||
917 | if (dir == UE_DIR_IN && xt == UE_BULK && | 917 | if (dir == UE_DIR_IN && xt == UE_BULK && | |
918 | un->un_ed[USBNET_ENDPT_RX] == 0) { | 918 | un->un_ed[USBNET_ENDPT_RX] == 0) { | |
919 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 919 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
920 | } else if (dir == UE_DIR_OUT && xt == UE_BULK && | 920 | } else if (dir == UE_DIR_OUT && xt == UE_BULK && | |
921 | un->un_ed[USBNET_ENDPT_TX] == 0) { | 921 | un->un_ed[USBNET_ENDPT_TX] == 0) { | |
922 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 922 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
923 | } else if (dir == UE_DIR_IN && xt == UE_INTERRUPT) { | 923 | } else if (dir == UE_DIR_IN && xt == UE_INTERRUPT) { | |
924 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 924 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
925 | } | 925 | } | |
926 | } | 926 | } | |
927 | 927 | |||
928 | /* Set these up now for axe_cmd(). */ | 928 | /* Set these up now for axe_cmd(). */ | |
929 | usbnet_attach(un, "axedet"); | 929 | usbnet_attach(un, "axedet"); | |
930 | 930 | |||
931 | /* We need the PHYID for init dance in some cases */ | 931 | /* We need the PHYID for init dance in some cases */ | |
932 | usbnet_lock_core(un); | 932 | usbnet_lock_core(un); | |
933 | usbnet_busy(un); | 933 | usbnet_busy(un); | |
934 | if (axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, &sc->axe_phyaddrs)) { | 934 | if (axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, &sc->axe_phyaddrs)) { | |
935 | aprint_error_dev(self, "failed to read phyaddrs\n"); | 935 | aprint_error_dev(self, "failed to read phyaddrs\n"); | |
936 | usbnet_unbusy(un); | 936 | usbnet_unbusy(un); | |
937 | usbnet_unlock_core(un); | 937 | usbnet_unlock_core(un); | |
938 | return; | 938 | return; | |
939 | } | 939 | } | |
940 | 940 | |||
941 | DPRINTF(" phyaddrs[0]: %jx phyaddrs[1]: %jx", | 941 | DPRINTF(" phyaddrs[0]: %jx phyaddrs[1]: %jx", | |
942 | sc->axe_phyaddrs[0], sc->axe_phyaddrs[1], 0, 0); | 942 | sc->axe_phyaddrs[0], sc->axe_phyaddrs[1], 0, 0); | |
943 | un->un_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI); | 943 | un->un_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI); | |
944 | if (un->un_phyno == -1) | 944 | if (un->un_phyno == -1) | |
945 | un->un_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC); | 945 | un->un_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC); | |
946 | if (un->un_phyno == -1) { | 946 | if (un->un_phyno == -1) { | |
947 | DPRINTF(" no valid PHY address found, assuming PHY address 0", | 947 | DPRINTF(" no valid PHY address found, assuming PHY address 0", | |
948 | 0, 0, 0, 0); | 948 | 0, 0, 0, 0); | |
949 | un->un_phyno = 0; | 949 | un->un_phyno = 0; | |
950 | } | 950 | } | |
951 | 951 | |||
952 | /* Initialize controller and get station address. */ | 952 | /* Initialize controller and get station address. */ | |
953 | 953 | |||
954 | axe_ax_init(un); | 954 | axe_ax_init(un); | |
955 | 955 | |||
956 | /* | 956 | /* | |
957 | * Fetch IPG values. | 957 | * Fetch IPG values. | |
958 | */ | 958 | */ | |
959 | if (un->un_flags & (AX772A | AX772B)) { | 959 | if (un->un_flags & (AX772A | AX772B)) { | |
960 | /* Set IPG values. */ | 960 | /* Set IPG values. */ | |
961 | sc->axe_ipgs[0] = AXE_IPG0_DEFAULT; | 961 | sc->axe_ipgs[0] = AXE_IPG0_DEFAULT; | |
962 | sc->axe_ipgs[1] = AXE_IPG1_DEFAULT; | 962 | sc->axe_ipgs[1] = AXE_IPG1_DEFAULT; | |
963 | sc->axe_ipgs[2] = AXE_IPG2_DEFAULT; | 963 | sc->axe_ipgs[2] = AXE_IPG2_DEFAULT; | |
964 | } else { | 964 | } else { | |
965 | if (axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->axe_ipgs)) { | 965 | if (axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->axe_ipgs)) { | |
966 | aprint_error_dev(self, "failed to read ipg\n"); | 966 | aprint_error_dev(self, "failed to read ipg\n"); | |
967 | usbnet_unbusy(un); | 967 | usbnet_unbusy(un); | |
968 | usbnet_unlock_core(un); | 968 | usbnet_unlock_core(un); | |
969 | return; | 969 | return; | |
970 | } | 970 | } | |
971 | } | 971 | } | |
972 | 972 | |||
973 | usbnet_unbusy(un); | 973 | usbnet_unbusy(un); | |
974 | usbnet_unlock_core(un); | 974 | usbnet_unlock_core(un); | |
975 | 975 | |||
976 | if (!AXE_IS_172(un)) | 976 | if (!AXE_IS_172(un)) | |
977 | usbnet_ec(un)->ec_capabilities = ETHERCAP_VLAN_MTU; | 977 | usbnet_ec(un)->ec_capabilities = ETHERCAP_VLAN_MTU; | |
978 | if (un->un_flags & AX772B) { | 978 | if (un->un_flags & AX772B) { | |
979 | struct ifnet *ifp = usbnet_ifp(un); | 979 | struct ifnet *ifp = usbnet_ifp(un); | |
980 | 980 | |||
981 | ifp->if_capabilities = | 981 | ifp->if_capabilities = | |
982 | IFCAP_CSUM_IPv4_Rx | | 982 | IFCAP_CSUM_IPv4_Rx | | |
983 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | 983 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | |
984 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; | 984 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; | |
985 | /* | 985 | /* | |
986 | * Checksum offloading of AX88772B also works with VLAN | 986 | * Checksum offloading of AX88772B also works with VLAN | |
987 | * tagged frames but there is no way to take advantage | 987 | * tagged frames but there is no way to take advantage | |
988 | * of the feature because vlan(4) assumes | 988 | * of the feature because vlan(4) assumes | |
989 | * IFCAP_VLAN_HWTAGGING is prerequisite condition to | 989 | * IFCAP_VLAN_HWTAGGING is prerequisite condition to | |
990 | * support checksum offloading with VLAN. VLAN hardware | 990 | * support checksum offloading with VLAN. VLAN hardware | |
991 | * tagging support of AX88772B is very limited so it's | 991 | * tagging support of AX88772B is very limited so it's | |
992 | * not possible to announce IFCAP_VLAN_HWTAGGING. | 992 | * not possible to announce IFCAP_VLAN_HWTAGGING. | |
993 | */ | 993 | */ | |
994 | } | 994 | } | |
995 | if (un->un_flags & (AX772A | AX772B | AX178)) | 995 | if (un->un_flags & (AX772A | AX772B | AX178)) | |
996 | unm.un_mii_flags = MIIF_DOPAUSE; | 996 | unm.un_mii_flags = MIIF_DOPAUSE; | |
997 | 997 | |||
998 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 998 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
999 | 0, &unm); | 999 | 0, &unm); | |
1000 | } | 1000 | } | |
1001 | 1001 | |||
1002 | static void | 1002 | static void | |
1003 | axe_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) | 1003 | axe_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) | |
1004 | { | 1004 | { | |
1005 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 1005 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
1006 | struct axe_softc * const sc = usbnet_softc(un); | 1006 | struct axe_softc * const sc = usbnet_softc(un); | |
1007 | struct ifnet *ifp = usbnet_ifp(un); | 1007 | struct ifnet *ifp = usbnet_ifp(un); | |
1008 | uint8_t *buf = c->unc_buf; | 1008 | uint8_t *buf = c->unc_buf; | |
1009 | 1009 | |||
1010 | do { | 1010 | do { | |
1011 | u_int pktlen = 0; | 1011 | u_int pktlen = 0; | |
1012 | u_int rxlen = 0; | 1012 | u_int rxlen = 0; | |
1013 | int flags = 0; | 1013 | int flags = 0; | |
1014 | 1014 | |||
1015 | if ((un->un_flags & AXSTD_FRAME) != 0) { | 1015 | if ((un->un_flags & AXSTD_FRAME) != 0) { | |
1016 | struct axe_sframe_hdr hdr; | 1016 | struct axe_sframe_hdr hdr; | |
1017 | 1017 | |||
1018 | if (total_len < sizeof(hdr)) { | 1018 | if (total_len < sizeof(hdr)) { | |
1019 | if_statinc(ifp, if_ierrors); | 1019 | if_statinc(ifp, if_ierrors); | |
1020 | break; | 1020 | break; | |
1021 | } | 1021 | } | |
1022 | 1022 | |||
1023 | memcpy(&hdr, buf, sizeof(hdr)); | 1023 | memcpy(&hdr, buf, sizeof(hdr)); | |
1024 | 1024 | |||
1025 | DPRINTFN(20, "total_len %#jx len %#jx ilen %#jx", | 1025 | DPRINTFN(20, "total_len %#jx len %#jx ilen %#jx", | |
1026 | total_len, | 1026 | total_len, | |
1027 | (le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK), | 1027 | (le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK), | |
1028 | (le16toh(hdr.ilen) & AXE_RH1M_RXLEN_MASK), 0); | 1028 | (le16toh(hdr.ilen) & AXE_RH1M_RXLEN_MASK), 0); | |
1029 | 1029 | |||
1030 | total_len -= sizeof(hdr); | 1030 | total_len -= sizeof(hdr); | |
1031 | buf += sizeof(hdr); | 1031 | buf += sizeof(hdr); | |
1032 | 1032 | |||
1033 | if (((le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK) ^ | 1033 | if (((le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK) ^ | |
1034 | (le16toh(hdr.ilen) & AXE_RH1M_RXLEN_MASK)) != | 1034 | (le16toh(hdr.ilen) & AXE_RH1M_RXLEN_MASK)) != | |
1035 | AXE_RH1M_RXLEN_MASK) { | 1035 | AXE_RH1M_RXLEN_MASK) { | |
1036 | if_statinc(ifp, if_ierrors); | 1036 | if_statinc(ifp, if_ierrors); | |
1037 | break; | 1037 | break; | |
1038 | } | 1038 | } | |
1039 | 1039 | |||
1040 | rxlen = le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK; | 1040 | rxlen = le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK; | |
1041 | if (total_len < rxlen) { | 1041 | if (total_len < rxlen) { | |
1042 | pktlen = total_len; | 1042 | pktlen = total_len; | |
1043 | total_len = 0; | 1043 | total_len = 0; | |
1044 | } else { | 1044 | } else { | |
1045 | pktlen = rxlen; | 1045 | pktlen = rxlen; | |
1046 | rxlen = roundup2(rxlen, 2); | 1046 | rxlen = roundup2(rxlen, 2); | |
1047 | total_len -= rxlen; | 1047 | total_len -= rxlen; | |
1048 | } | 1048 | } | |
1049 | 1049 | |||
1050 | } else if ((un->un_flags & AXCSUM_FRAME) != 0) { | 1050 | } else if ((un->un_flags & AXCSUM_FRAME) != 0) { | |
1051 | struct axe_csum_hdr csum_hdr; | 1051 | struct axe_csum_hdr csum_hdr; | |
1052 | 1052 | |||
1053 | if (total_len < sizeof(csum_hdr)) { | 1053 | if (total_len < sizeof(csum_hdr)) { | |
1054 | if_statinc(ifp, if_ierrors); | 1054 | if_statinc(ifp, if_ierrors); | |
1055 | break; | 1055 | break; | |
1056 | } | 1056 | } | |
1057 | 1057 | |||
1058 | memcpy(&csum_hdr, buf, sizeof(csum_hdr)); | 1058 | memcpy(&csum_hdr, buf, sizeof(csum_hdr)); | |
1059 | 1059 | |||
1060 | csum_hdr.len = le16toh(csum_hdr.len); | 1060 | csum_hdr.len = le16toh(csum_hdr.len); | |
1061 | csum_hdr.ilen = le16toh(csum_hdr.ilen); | 1061 | csum_hdr.ilen = le16toh(csum_hdr.ilen); | |
1062 | csum_hdr.cstatus = le16toh(csum_hdr.cstatus); | 1062 | csum_hdr.cstatus = le16toh(csum_hdr.cstatus); | |
1063 | 1063 | |||
1064 | DPRINTFN(20, "total_len %#jx len %#jx ilen %#jx" | 1064 | DPRINTFN(20, "total_len %#jx len %#jx ilen %#jx" | |
1065 | " cstatus %#jx", total_len, | 1065 | " cstatus %#jx", total_len, | |
1066 | csum_hdr.len, csum_hdr.ilen, csum_hdr.cstatus); | 1066 | csum_hdr.len, csum_hdr.ilen, csum_hdr.cstatus); | |
1067 | 1067 | |||
1068 | if ((AXE_CSUM_RXBYTES(csum_hdr.len) ^ | 1068 | if ((AXE_CSUM_RXBYTES(csum_hdr.len) ^ | |
1069 | AXE_CSUM_RXBYTES(csum_hdr.ilen)) != | 1069 | AXE_CSUM_RXBYTES(csum_hdr.ilen)) != | |
1070 | sc->sc_lenmask) { | 1070 | sc->sc_lenmask) { | |
1071 | /* we lost sync */ | 1071 | /* we lost sync */ | |
1072 | if_statinc(ifp, if_ierrors); | 1072 | if_statinc(ifp, if_ierrors); | |
1073 | DPRINTFN(20, "len %#jx ilen %#jx lenmask %#jx " | 1073 | DPRINTFN(20, "len %#jx ilen %#jx lenmask %#jx " | |
1074 | "err", | 1074 | "err", | |
1075 | AXE_CSUM_RXBYTES(csum_hdr.len), | 1075 | AXE_CSUM_RXBYTES(csum_hdr.len), | |
1076 | AXE_CSUM_RXBYTES(csum_hdr.ilen), | 1076 | AXE_CSUM_RXBYTES(csum_hdr.ilen), | |
1077 | sc->sc_lenmask, 0); | 1077 | sc->sc_lenmask, 0); | |
1078 | break; | 1078 | break; | |
1079 | } | 1079 | } | |
1080 | /* | 1080 | /* | |
1081 | * Get total transferred frame length including | 1081 | * Get total transferred frame length including | |
1082 | * checksum header. The length should be multiple | 1082 | * checksum header. The length should be multiple | |
1083 | * of 4. | 1083 | * of 4. | |
1084 | */ | 1084 | */ | |
1085 | pktlen = AXE_CSUM_RXBYTES(csum_hdr.len); | 1085 | pktlen = AXE_CSUM_RXBYTES(csum_hdr.len); | |
1086 | u_int len = sizeof(csum_hdr) + pktlen; | 1086 | u_int len = sizeof(csum_hdr) + pktlen; | |
1087 | len = (len + 3) & ~3; | 1087 | len = (len + 3) & ~3; | |
1088 | if (total_len < len) { | 1088 | if (total_len < len) { | |
1089 | DPRINTFN(20, "total_len %#jx < len %#jx", | 1089 | DPRINTFN(20, "total_len %#jx < len %#jx", | |
1090 | total_len, len, 0, 0); | 1090 | total_len, len, 0, 0); | |
1091 | /* invalid length */ | 1091 | /* invalid length */ | |
1092 | if_statinc(ifp, if_ierrors); | 1092 | if_statinc(ifp, if_ierrors); | |
1093 | break; | 1093 | break; | |
1094 | } | 1094 | } | |
1095 | buf += sizeof(csum_hdr); | 1095 | buf += sizeof(csum_hdr); | |
1096 | 1096 | |||
1097 | const uint16_t cstatus = csum_hdr.cstatus; | 1097 | const uint16_t cstatus = csum_hdr.cstatus; | |
1098 | 1098 | |||
1099 | if (cstatus & AXE_CSUM_HDR_L3_TYPE_IPV4) { | 1099 | if (cstatus & AXE_CSUM_HDR_L3_TYPE_IPV4) { | |
1100 | if (cstatus & AXE_CSUM_HDR_L4_CSUM_ERR) | 1100 | if (cstatus & AXE_CSUM_HDR_L4_CSUM_ERR) | |
1101 | flags |= M_CSUM_TCP_UDP_BAD; | 1101 | flags |= M_CSUM_TCP_UDP_BAD; | |
1102 | if (cstatus & AXE_CSUM_HDR_L3_CSUM_ERR) | 1102 | if (cstatus & AXE_CSUM_HDR_L3_CSUM_ERR) | |
1103 | flags |= M_CSUM_IPv4_BAD; | 1103 | flags |= M_CSUM_IPv4_BAD; | |
1104 | 1104 | |||
1105 | const uint16_t l4type = | 1105 | const uint16_t l4type = | |
1106 | cstatus & AXE_CSUM_HDR_L4_TYPE_MASK; | 1106 | cstatus & AXE_CSUM_HDR_L4_TYPE_MASK; | |
1107 | 1107 | |||
1108 | if (l4type == AXE_CSUM_HDR_L4_TYPE_TCP) | 1108 | if (l4type == AXE_CSUM_HDR_L4_TYPE_TCP) | |
1109 | flags |= M_CSUM_TCPv4; | 1109 | flags |= M_CSUM_TCPv4; | |
1110 | if (l4type == AXE_CSUM_HDR_L4_TYPE_UDP) | 1110 | if (l4type == AXE_CSUM_HDR_L4_TYPE_UDP) | |
1111 | flags |= M_CSUM_UDPv4; | 1111 | flags |= M_CSUM_UDPv4; | |
1112 | } | 1112 | } | |
1113 | if (total_len < len) { | 1113 | if (total_len < len) { | |
1114 | pktlen = total_len; | 1114 | pktlen = total_len; | |
1115 | total_len = 0; | 1115 | total_len = 0; | |
1116 | } else { | 1116 | } else { | |
1117 | total_len -= len; | 1117 | total_len -= len; | |
1118 | rxlen = len - sizeof(csum_hdr); | 1118 | rxlen = len - sizeof(csum_hdr); | |
1119 | } | 1119 | } | |
1120 | DPRINTFN(20, "total_len %#jx len %#jx pktlen %#jx" | 1120 | DPRINTFN(20, "total_len %#jx len %#jx pktlen %#jx" | |
1121 | " rxlen %#jx", total_len, len, pktlen, rxlen); | 1121 | " rxlen %#jx", total_len, len, pktlen, rxlen); | |
1122 | } else { /* AX172 */ | 1122 | } else { /* AX172 */ | |
1123 | pktlen = rxlen = total_len; | 1123 | pktlen = rxlen = total_len; | |
1124 | total_len = 0; | 1124 | total_len = 0; | |
1125 | } | 1125 | } | |
1126 | 1126 | |||
1127 | usbnet_enqueue(un, buf, pktlen, flags, 0, 0); | 1127 | usbnet_enqueue(un, buf, pktlen, flags, 0, 0); | |
1128 | buf += rxlen; | 1128 | buf += rxlen; | |
1129 | 1129 | |||
1130 | } while (total_len > 0); | 1130 | } while (total_len > 0); | |
1131 | 1131 | |||
1132 | DPRINTFN(10, "start rx", 0, 0, 0, 0); | 1132 | DPRINTFN(10, "start rx", 0, 0, 0, 0); | |
1133 | } | 1133 | } | |
1134 | 1134 | |||
1135 | static unsigned | 1135 | static unsigned | |
1136 | axe_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 1136 | axe_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
1137 | { | 1137 | { | |
1138 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 1138 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
1139 | struct axe_sframe_hdr hdr, tlr; | 1139 | struct axe_sframe_hdr hdr, tlr; | |
1140 | size_t hdr_len = 0, tlr_len = 0; | 1140 | size_t hdr_len = 0, tlr_len = 0; | |
1141 | int length, boundary; | 1141 | int length, boundary; | |
1142 | 1142 | |||
1143 | usbnet_isowned_tx(un); | 1143 | usbnet_isowned_tx(un); | |
1144 | 1144 | |||
1145 | if (!AXE_IS_172(un)) { | 1145 | if (!AXE_IS_172(un)) { | |
1146 | /* | 1146 | /* | |
1147 | * Copy the mbuf data into a contiguous buffer, leaving two | 1147 | * Copy the mbuf data into a contiguous buffer, leaving two | |
1148 | * bytes at the beginning to hold the frame length. | 1148 | * bytes at the beginning to hold the frame length. | |
1149 | */ | 1149 | */ | |
1150 | boundary = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? 512 : 64; | 1150 | boundary = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? 512 : 64; | |
1151 | 1151 | |||
1152 | hdr.len = htole16(m->m_pkthdr.len); | 1152 | hdr.len = htole16(m->m_pkthdr.len); | |
1153 | hdr.ilen = ~hdr.len; | 1153 | hdr.ilen = ~hdr.len; | |
1154 | hdr_len = sizeof(hdr); | 1154 | hdr_len = sizeof(hdr); | |
1155 | 1155 | |||
1156 | length = hdr_len + m->m_pkthdr.len; | 1156 | length = hdr_len + m->m_pkthdr.len; | |
1157 | 1157 | |||
1158 | if ((length % boundary) == 0) { | 1158 | if ((length % boundary) == 0) { | |
1159 | tlr.len = 0x0000; | 1159 | tlr.len = 0x0000; | |
1160 | tlr.ilen = 0xffff; | 1160 | tlr.ilen = 0xffff; | |
1161 | tlr_len = sizeof(tlr); | 1161 | tlr_len = sizeof(tlr); | |
1162 | } | 1162 | } | |
1163 | DPRINTFN(20, "length %jx m_pkthdr.len %jx hdrsize %#jx", | 1163 | DPRINTFN(20, "length %jx m_pkthdr.len %jx hdrsize %#jx", | |
1164 | length, m->m_pkthdr.len, sizeof(hdr), 0); | 1164 | length, m->m_pkthdr.len, sizeof(hdr), 0); | |
1165 | } | 1165 | } | |
1166 | 1166 | |||
1167 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - hdr_len - tlr_len) | 1167 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - hdr_len - tlr_len) | |
1168 | return 0; | 1168 | return 0; | |
1169 | length = hdr_len + m->m_pkthdr.len + tlr_len; | 1169 | length = hdr_len + m->m_pkthdr.len + tlr_len; | |
1170 | 1170 | |||
1171 | if (hdr_len) | 1171 | if (hdr_len) | |
1172 | memcpy(c->unc_buf, &hdr, hdr_len); | 1172 | memcpy(c->unc_buf, &hdr, hdr_len); | |
1173 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + hdr_len); | 1173 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + hdr_len); | |
1174 | if (tlr_len) | 1174 | if (tlr_len) | |
1175 | memcpy(c->unc_buf + length - tlr_len, &tlr, tlr_len); | 1175 | memcpy(c->unc_buf + length - tlr_len, &tlr, tlr_len); | |
1176 | 1176 | |||
1177 | return length; | 1177 | return length; | |
1178 | } | 1178 | } | |
1179 | 1179 | |||
1180 | static void | 1180 | static void | |
1181 | axe_csum_cfg(struct axe_softc *sc) | 1181 | axe_csum_cfg(struct axe_softc *sc) | |
1182 | { | 1182 | { | |
1183 | struct usbnet * const un = &sc->axe_un; | 1183 | struct usbnet * const un = &sc->axe_un; | |
1184 | struct ifnet * const ifp = usbnet_ifp(un); | 1184 | struct ifnet * const ifp = usbnet_ifp(un); | |
1185 | uint16_t csum1, csum2; | 1185 | uint16_t csum1, csum2; | |
1186 | 1186 | |||
1187 | if ((un->un_flags & AX772B) != 0) { | 1187 | if ((un->un_flags & AX772B) != 0) { | |
1188 | csum1 = 0; | 1188 | csum1 = 0; | |
1189 | csum2 = 0; | 1189 | csum2 = 0; | |
1190 | if ((ifp->if_capenable & IFCAP_CSUM_IPv4_Tx) != 0) | 1190 | if ((ifp->if_capenable & IFCAP_CSUM_IPv4_Tx) != 0) | |
1191 | csum1 |= AXE_TXCSUM_IP; | 1191 | csum1 |= AXE_TXCSUM_IP; | |
1192 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv4_Tx) != 0) | 1192 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv4_Tx) != 0) | |
1193 | csum1 |= AXE_TXCSUM_TCP; | 1193 | csum1 |= AXE_TXCSUM_TCP; | |
1194 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv4_Tx) != 0) | 1194 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv4_Tx) != 0) | |
1195 | csum1 |= AXE_TXCSUM_UDP; | 1195 | csum1 |= AXE_TXCSUM_UDP; | |
1196 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv6_Tx) != 0) | 1196 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv6_Tx) != 0) | |
1197 | csum1 |= AXE_TXCSUM_TCPV6; | 1197 | csum1 |= AXE_TXCSUM_TCPV6; | |
1198 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv6_Tx) != 0) | 1198 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv6_Tx) != 0) | |
1199 | csum1 |= AXE_TXCSUM_UDPV6; | 1199 | csum1 |= AXE_TXCSUM_UDPV6; | |
1200 | axe_cmd(sc, AXE_772B_CMD_WRITE_TXCSUM, csum2, csum1, NULL); | 1200 | axe_cmd(sc, AXE_772B_CMD_WRITE_TXCSUM, csum2, csum1, NULL); | |
1201 | csum1 = 0; | 1201 | csum1 = 0; | |
1202 | csum2 = 0; | 1202 | csum2 = 0; | |
1203 | 1203 | |||
1204 | if ((ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) != 0) | 1204 | if ((ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) != 0) | |
1205 | csum1 |= AXE_RXCSUM_IP; | 1205 | csum1 |= AXE_RXCSUM_IP; | |
1206 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv4_Rx) != 0) | 1206 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv4_Rx) != 0) | |
1207 | csum1 |= AXE_RXCSUM_TCP; | 1207 | csum1 |= AXE_RXCSUM_TCP; | |
1208 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv4_Rx) != 0) | 1208 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv4_Rx) != 0) | |
1209 | csum1 |= AXE_RXCSUM_UDP; | 1209 | csum1 |= AXE_RXCSUM_UDP; | |
1210 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv6_Rx) != 0) | 1210 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv6_Rx) != 0) | |
1211 | csum1 |= AXE_RXCSUM_TCPV6; | 1211 | csum1 |= AXE_RXCSUM_TCPV6; | |
1212 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv6_Rx) != 0) | 1212 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv6_Rx) != 0) | |
1213 | csum1 |= AXE_RXCSUM_UDPV6; | 1213 | csum1 |= AXE_RXCSUM_UDPV6; | |
1214 | axe_cmd(sc, AXE_772B_CMD_WRITE_RXCSUM, csum2, csum1, NULL); | 1214 | axe_cmd(sc, AXE_772B_CMD_WRITE_RXCSUM, csum2, csum1, NULL); | |
1215 | } | 1215 | } | |
1216 | } | 1216 | } | |
1217 | 1217 | |||
1218 | static int | 1218 | static int | |
1219 | axe_init_locked(struct ifnet *ifp) | 1219 | axe_init_locked(struct ifnet *ifp) | |
1220 | { | 1220 | { | |
1221 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 1221 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
1222 | struct usbnet * const un = ifp->if_softc; | 1222 | struct usbnet * const un = ifp->if_softc; | |
1223 | struct axe_softc * const sc = usbnet_softc(un); | 1223 | struct axe_softc * const sc = usbnet_softc(un); | |
1224 | int rxmode; | 1224 | int rxmode; | |
1225 | 1225 | |||
1226 | usbnet_isowned_core(un); | 1226 | usbnet_isowned_core(un); | |
1227 | 1227 | |||
1228 | if (usbnet_isdying(un)) | 1228 | if (usbnet_isdying(un)) | |
1229 | return EIO; | 1229 | return EIO; | |
1230 | 1230 | |||
1231 | /* Cancel pending I/O */ | 1231 | /* Cancel pending I/O */ | |
1232 | usbnet_stop(un, ifp, 1); | 1232 | usbnet_stop(un, ifp, 1); | |
1233 | 1233 | |||
1234 | /* Reset the ethernet interface. */ | 1234 | /* Reset the ethernet interface. */ | |
1235 | axe_reset(un); | 1235 | axe_reset(un); | |
1236 | 1236 | |||
1237 | #if 0 | 1237 | #if 0 | |
1238 | ret = asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_2 | | 1238 | ret = asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_2 | | |
1239 | AX_GPIO_GPO2EN, 5, in_pm); | 1239 | AX_GPIO_GPO2EN, 5, in_pm); | |
1240 | #endif | 1240 | #endif | |
1241 | /* Set MAC address and transmitter IPG values. */ | 1241 | /* Set MAC address and transmitter IPG values. */ | |
1242 | if (AXE_IS_172(un)) { | 1242 | if (AXE_IS_172(un)) { | |
1243 | axe_cmd(sc, AXE_172_CMD_WRITE_NODEID, 0, 0, un->un_eaddr); | 1243 | axe_cmd(sc, AXE_172_CMD_WRITE_NODEID, 0, 0, un->un_eaddr); | |
1244 | axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->axe_ipgs[0], NULL); | 1244 | axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->axe_ipgs[0], NULL); | |
1245 | axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->axe_ipgs[1], NULL); | 1245 | axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->axe_ipgs[1], NULL); | |
1246 | axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->axe_ipgs[2], NULL); | 1246 | axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->axe_ipgs[2], NULL); | |
1247 | } else { | 1247 | } else { | |
1248 | axe_cmd(sc, AXE_178_CMD_WRITE_NODEID, 0, 0, un->un_eaddr); | 1248 | axe_cmd(sc, AXE_178_CMD_WRITE_NODEID, 0, 0, un->un_eaddr); | |
1249 | axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->axe_ipgs[2], | 1249 | axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->axe_ipgs[2], | |
1250 | (sc->axe_ipgs[1] << 8) | (sc->axe_ipgs[0]), NULL); | 1250 | (sc->axe_ipgs[1] << 8) | (sc->axe_ipgs[0]), NULL); | |
1251 | 1251 | |||
1252 | un->un_flags &= ~(AXSTD_FRAME | AXCSUM_FRAME); | 1252 | un->un_flags &= ~(AXSTD_FRAME | AXCSUM_FRAME); | |
1253 | if ((un->un_flags & AX772B) != 0 && | 1253 | if ((un->un_flags & AX772B) != 0 && | |
1254 | (ifp->if_capenable & AX_RXCSUM) != 0) { | 1254 | (ifp->if_capenable & AX_RXCSUM) != 0) { | |
1255 | sc->sc_lenmask = AXE_CSUM_HDR_LEN_MASK; | 1255 | sc->sc_lenmask = AXE_CSUM_HDR_LEN_MASK; | |
1256 | un->un_flags |= AXCSUM_FRAME; | 1256 | un->un_flags |= AXCSUM_FRAME; | |
1257 | } else { | 1257 | } else { | |
1258 | sc->sc_lenmask = AXE_HDR_LEN_MASK; | 1258 | sc->sc_lenmask = AXE_HDR_LEN_MASK; | |
1259 | un->un_flags |= AXSTD_FRAME; | 1259 | un->un_flags |= AXSTD_FRAME; | |
1260 | } | 1260 | } | |
1261 | } | 1261 | } | |
1262 | 1262 | |||
1263 | /* Configure TX/RX checksum offloading. */ | 1263 | /* Configure TX/RX checksum offloading. */ | |
1264 | axe_csum_cfg(sc); | 1264 | axe_csum_cfg(sc); | |
1265 | 1265 | |||
1266 | if (un->un_flags & AX772B) { | 1266 | if (un->un_flags & AX772B) { | |
1267 | /* AX88772B uses different maximum frame burst configuration. */ | 1267 | /* AX88772B uses different maximum frame burst configuration. */ | |
1268 | axe_cmd(sc, AXE_772B_CMD_RXCTL_WRITE_CFG, | 1268 | axe_cmd(sc, AXE_772B_CMD_RXCTL_WRITE_CFG, | |
1269 | ax88772b_mfb_table[AX88772B_MFB_16K].threshold, | 1269 | ax88772b_mfb_table[AX88772B_MFB_16K].threshold, | |
1270 | ax88772b_mfb_table[AX88772B_MFB_16K].byte_cnt, NULL); | 1270 | ax88772b_mfb_table[AX88772B_MFB_16K].byte_cnt, NULL); | |
1271 | } | 1271 | } | |
1272 | /* Enable receiver, set RX mode */ | 1272 | /* Enable receiver, set RX mode */ | |
1273 | rxmode = (AXE_RXCMD_BROADCAST | AXE_RXCMD_MULTICAST | AXE_RXCMD_ENABLE); | 1273 | rxmode = (AXE_RXCMD_BROADCAST | AXE_RXCMD_MULTICAST | AXE_RXCMD_ENABLE); | |
1274 | if (AXE_IS_172(un)) | 1274 | if (AXE_IS_172(un)) | |
1275 | rxmode |= AXE_172_RXCMD_UNICAST; | 1275 | rxmode |= AXE_172_RXCMD_UNICAST; | |
1276 | else { | 1276 | else { | |
1277 | if (un->un_flags & AX772B) { | 1277 | if (un->un_flags & AX772B) { | |
1278 | /* | 1278 | /* | |
1279 | * Select RX header format type 1. Aligning IP | 1279 | * Select RX header format type 1. Aligning IP | |
1280 | * header on 4 byte boundary is not needed when | 1280 | * header on 4 byte boundary is not needed when | |
1281 | * checksum offloading feature is not used | 1281 | * checksum offloading feature is not used | |
1282 | * because we always copy the received frame in | 1282 | * because we always copy the received frame in | |
1283 | * RX handler. When RX checksum offloading is | 1283 | * RX handler. When RX checksum offloading is | |
1284 | * active, aligning IP header is required to | 1284 | * active, aligning IP header is required to | |
1285 | * reflect actual frame length including RX | 1285 | * reflect actual frame length including RX | |
1286 | * header size. | 1286 | * header size. | |
1287 | */ | 1287 | */ | |
1288 | rxmode |= AXE_772B_RXCMD_HDR_TYPE_1; | 1288 | rxmode |= AXE_772B_RXCMD_HDR_TYPE_1; | |
1289 | if (un->un_flags & AXCSUM_FRAME) | 1289 | if (un->un_flags & AXCSUM_FRAME) | |
1290 | rxmode |= AXE_772B_RXCMD_IPHDR_ALIGN; | 1290 | rxmode |= AXE_772B_RXCMD_IPHDR_ALIGN; | |
1291 | } else { | 1291 | } else { | |
1292 | /* | 1292 | /* | |
1293 | * Default Rx buffer size is too small to get | 1293 | * Default Rx buffer size is too small to get | |
1294 | * maximum performance. | 1294 | * maximum performance. | |
1295 | */ | 1295 | */ | |
1296 | #if 0 | 1296 | #if 0 | |
1297 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) { | 1297 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) { | |
1298 | /* Largest possible USB buffer size for AX88178 */ | 1298 | /* Largest possible USB buffer size for AX88178 */ | |
1299 | } | 1299 | } | |
1300 | #endif | 1300 | #endif | |
1301 | rxmode |= AXE_178_RXCMD_MFB_16384; | 1301 | rxmode |= AXE_178_RXCMD_MFB_16384; | |
1302 | } | 1302 | } | |
1303 | } | 1303 | } | |
1304 | 1304 | |||
1305 | DPRINTF("rxmode %#jx", rxmode, 0, 0, 0); | 1305 | DPRINTF("rxmode %#jx", rxmode, 0, 0, 0); | |
1306 | 1306 | |||
1307 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); | 1307 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); | |
1308 | 1308 | |||
1309 | /* Accept multicast frame or run promisc. mode */ | 1309 | /* Accept multicast frame or run promisc. mode */ | |
1310 | axe_rcvfilt_locked(un); | 1310 | axe_rcvfilt_locked(un); | |
1311 | 1311 | |||
1312 | return usbnet_init_rx_tx(un); | 1312 | return usbnet_init_rx_tx(un); | |
1313 | } | 1313 | } | |
1314 | 1314 | |||
1315 | static int | 1315 | static int | |
1316 | axe_uno_init(struct ifnet *ifp) | 1316 | axe_uno_init(struct ifnet *ifp) | |
1317 | { | 1317 | { | |
1318 | int ret = axe_init_locked(ifp); | 1318 | int ret = axe_init_locked(ifp); | |
1319 | 1319 | |||
1320 | return ret; | 1320 | return ret; | |
1321 | } | 1321 | } | |
1322 | 1322 | |||
1323 | static void | 1323 | static void | |
1324 | axe_uno_mcast(struct ifnet *ifp) | 1324 | axe_uno_mcast(struct ifnet *ifp) | |
1325 | { | 1325 | { | |
1326 | struct usbnet * const un = ifp->if_softc; | 1326 | struct usbnet * const un = ifp->if_softc; | |
1327 | 1327 | |||
1328 | usbnet_lock_core(un); | 1328 | usbnet_lock_core(un); | |
1329 | usbnet_busy(un); | |||
1330 | 1329 | |||
1331 | axe_rcvfilt_locked(un); | 1330 | axe_rcvfilt_locked(un); | |
1332 | 1331 | |||
1333 | usbnet_unbusy(un); | |||
1334 | usbnet_unlock_core(un); | 1332 | usbnet_unlock_core(un); | |
1335 | } | 1333 | } | |
1336 | 1334 | |||
1337 | static void | 1335 | static void | |
1338 | axe_uno_stop(struct ifnet *ifp, int disable) | 1336 | axe_uno_stop(struct ifnet *ifp, int disable) | |
1339 | { | 1337 | { | |
1340 | struct usbnet * const un = ifp->if_softc; | 1338 | struct usbnet * const un = ifp->if_softc; | |
1341 | 1339 | |||
1342 | axe_reset(un); | 1340 | axe_reset(un); | |
1343 | } | 1341 | } | |
1344 | 1342 | |||
1345 | #ifdef _MODULE | 1343 | #ifdef _MODULE | |
1346 | #include "ioconf.c" | 1344 | #include "ioconf.c" | |
1347 | #endif | 1345 | #endif | |
1348 | 1346 | |||
1349 | USBNET_MODULE(axe) | 1347 | USBNET_MODULE(axe) |
--- src/sys/dev/usb/if_axen.c 2022/03/03 05:51:17 1.77
+++ src/sys/dev/usb/if_axen.c 2022/03/03 05:51:27 1.78
@@ -1,973 +1,971 @@ | @@ -1,973 +1,971 @@ | |||
1 | /* $NetBSD: if_axen.c,v 1.77 2022/03/03 05:51:17 riastradh Exp $ */ | 1 | /* $NetBSD: if_axen.c,v 1.78 2022/03/03 05:51:27 riastradh Exp $ */ | |
2 | /* $OpenBSD: if_axen.c,v 1.3 2013/10/21 10:10:22 yuo Exp $ */ | 2 | /* $OpenBSD: if_axen.c,v 1.3 2013/10/21 10:10:22 yuo Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2013 Yojiro UO <yuo@openbsd.org> | 5 | * Copyright (c) 2013 Yojiro UO <yuo@openbsd.org> | |
6 | * | 6 | * | |
7 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any | |
8 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above | |
9 | * copyright notice and this permission notice appear in all copies. | 9 | * copyright notice and this permission notice appear in all copies. | |
10 | * | 10 | * | |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
18 | */ | 18 | */ | |
19 | 19 | |||
20 | /* | 20 | /* | |
21 | * ASIX Electronics AX88178a USB 2.0 ethernet and AX88179 USB 3.0 Ethernet | 21 | * ASIX Electronics AX88178a USB 2.0 ethernet and AX88179 USB 3.0 Ethernet | |
22 | * driver. | 22 | * driver. | |
23 | */ | 23 | */ | |
24 | 24 | |||
25 | #include <sys/cdefs.h> | 25 | #include <sys/cdefs.h> | |
26 | __KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.77 2022/03/03 05:51:17 riastradh Exp $"); | 26 | __KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.78 2022/03/03 05:51:27 riastradh Exp $"); | |
27 | 27 | |||
28 | #ifdef _KERNEL_OPT | 28 | #ifdef _KERNEL_OPT | |
29 | #include "opt_usb.h" | 29 | #include "opt_usb.h" | |
30 | #endif | 30 | #endif | |
31 | 31 | |||
32 | #include <sys/param.h> | 32 | #include <sys/param.h> | |
33 | 33 | |||
34 | #include <netinet/in.h> /* XXX for netinet/ip.h */ | 34 | #include <netinet/in.h> /* XXX for netinet/ip.h */ | |
35 | #include <netinet/ip.h> /* XXX for IP_MAXPACKET */ | 35 | #include <netinet/ip.h> /* XXX for IP_MAXPACKET */ | |
36 | 36 | |||
37 | #include <dev/usb/usbnet.h> | 37 | #include <dev/usb/usbnet.h> | |
38 | 38 | |||
39 | #include <dev/usb/if_axenreg.h> | 39 | #include <dev/usb/if_axenreg.h> | |
40 | 40 | |||
41 | #ifdef AXEN_DEBUG | 41 | #ifdef AXEN_DEBUG | |
42 | #define DPRINTF(x) do { if (axendebug) printf x; } while (/*CONSTCOND*/0) | 42 | #define DPRINTF(x) do { if (axendebug) printf x; } while (/*CONSTCOND*/0) | |
43 | #define DPRINTFN(n, x) do { if (axendebug >= (n)) printf x; } while (/*CONSTCOND*/0) | 43 | #define DPRINTFN(n, x) do { if (axendebug >= (n)) printf x; } while (/*CONSTCOND*/0) | |
44 | int axendebug = 0; | 44 | int axendebug = 0; | |
45 | #else | 45 | #else | |
46 | #define DPRINTF(x) | 46 | #define DPRINTF(x) | |
47 | #define DPRINTFN(n, x) | 47 | #define DPRINTFN(n, x) | |
48 | #endif | 48 | #endif | |
49 | 49 | |||
50 | struct axen_type { | 50 | struct axen_type { | |
51 | struct usb_devno axen_devno; | 51 | struct usb_devno axen_devno; | |
52 | uint16_t axen_flags; | 52 | uint16_t axen_flags; | |
53 | #define AX178A 0x0001 /* AX88178a */ | 53 | #define AX178A 0x0001 /* AX88178a */ | |
54 | #define AX179 0x0002 /* AX88179 */ | 54 | #define AX179 0x0002 /* AX88179 */ | |
55 | }; | 55 | }; | |
56 | 56 | |||
57 | /* | 57 | /* | |
58 | * Various supported device vendors/products. | 58 | * Various supported device vendors/products. | |
59 | */ | 59 | */ | |
60 | static const struct axen_type axen_devs[] = { | 60 | static const struct axen_type axen_devs[] = { | |
61 | #if 0 /* not tested */ | 61 | #if 0 /* not tested */ | |
62 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178A}, AX178A }, | 62 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178A}, AX178A }, | |
63 | #endif | 63 | #endif | |
64 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88179}, AX179 }, | 64 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88179}, AX179 }, | |
65 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUB1312}, AX179 } | 65 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUB1312}, AX179 } | |
66 | }; | 66 | }; | |
67 | 67 | |||
68 | #define axen_lookup(v, p) ((const struct axen_type *)usb_lookup(axen_devs, v, p)) | 68 | #define axen_lookup(v, p) ((const struct axen_type *)usb_lookup(axen_devs, v, p)) | |
69 | 69 | |||
70 | static int axen_match(device_t, cfdata_t, void *); | 70 | static int axen_match(device_t, cfdata_t, void *); | |
71 | static void axen_attach(device_t, device_t, void *); | 71 | static void axen_attach(device_t, device_t, void *); | |
72 | 72 | |||
73 | CFATTACH_DECL_NEW(axen, sizeof(struct usbnet), | 73 | CFATTACH_DECL_NEW(axen, sizeof(struct usbnet), | |
74 | axen_match, axen_attach, usbnet_detach, usbnet_activate); | 74 | axen_match, axen_attach, usbnet_detach, usbnet_activate); | |
75 | 75 | |||
76 | static int axen_cmd(struct usbnet *, int, int, int, void *); | 76 | static int axen_cmd(struct usbnet *, int, int, int, void *); | |
77 | static void axen_reset(struct usbnet *); | 77 | static void axen_reset(struct usbnet *); | |
78 | static int axen_get_eaddr(struct usbnet *, void *); | 78 | static int axen_get_eaddr(struct usbnet *, void *); | |
79 | static void axen_ax88179_init(struct usbnet *); | 79 | static void axen_ax88179_init(struct usbnet *); | |
80 | 80 | |||
81 | static void axen_uno_stop(struct ifnet *, int); | 81 | static void axen_uno_stop(struct ifnet *, int); | |
82 | static int axen_uno_ioctl(struct ifnet *, u_long, void *); | 82 | static int axen_uno_ioctl(struct ifnet *, u_long, void *); | |
83 | static void axen_uno_mcast(struct ifnet *); | 83 | static void axen_uno_mcast(struct ifnet *); | |
84 | static int axen_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 84 | static int axen_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
85 | static int axen_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 85 | static int axen_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
86 | static void axen_uno_mii_statchg(struct ifnet *); | 86 | static void axen_uno_mii_statchg(struct ifnet *); | |
87 | static void axen_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 87 | static void axen_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
88 | uint32_t); | 88 | uint32_t); | |
89 | static unsigned axen_uno_tx_prepare(struct usbnet *, struct mbuf *, | 89 | static unsigned axen_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
90 | struct usbnet_chain *); | 90 | struct usbnet_chain *); | |
91 | static int axen_uno_init(struct ifnet *); | 91 | static int axen_uno_init(struct ifnet *); | |
92 | 92 | |||
93 | static const struct usbnet_ops axen_ops = { | 93 | static const struct usbnet_ops axen_ops = { | |
94 | .uno_stop = axen_uno_stop, | 94 | .uno_stop = axen_uno_stop, | |
95 | .uno_ioctl = axen_uno_ioctl, | 95 | .uno_ioctl = axen_uno_ioctl, | |
96 | .uno_mcast = axen_uno_mcast, | 96 | .uno_mcast = axen_uno_mcast, | |
97 | .uno_read_reg = axen_uno_mii_read_reg, | 97 | .uno_read_reg = axen_uno_mii_read_reg, | |
98 | .uno_write_reg = axen_uno_mii_write_reg, | 98 | .uno_write_reg = axen_uno_mii_write_reg, | |
99 | .uno_statchg = axen_uno_mii_statchg, | 99 | .uno_statchg = axen_uno_mii_statchg, | |
100 | .uno_tx_prepare = axen_uno_tx_prepare, | 100 | .uno_tx_prepare = axen_uno_tx_prepare, | |
101 | .uno_rx_loop = axen_uno_rx_loop, | 101 | .uno_rx_loop = axen_uno_rx_loop, | |
102 | .uno_init = axen_uno_init, | 102 | .uno_init = axen_uno_init, | |
103 | }; | 103 | }; | |
104 | 104 | |||
105 | static int | 105 | static int | |
106 | axen_cmd(struct usbnet *un, int cmd, int index, int val, void *buf) | 106 | axen_cmd(struct usbnet *un, int cmd, int index, int val, void *buf) | |
107 | { | 107 | { | |
108 | usb_device_request_t req; | 108 | usb_device_request_t req; | |
109 | usbd_status err; | 109 | usbd_status err; | |
110 | 110 | |||
111 | usbnet_isowned_core(un); | 111 | usbnet_isowned_core(un); | |
112 | 112 | |||
113 | if (usbnet_isdying(un)) | 113 | if (usbnet_isdying(un)) | |
114 | return 0; | 114 | return 0; | |
115 | 115 | |||
116 | if (AXEN_CMD_DIR(cmd)) | 116 | if (AXEN_CMD_DIR(cmd)) | |
117 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 117 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
118 | else | 118 | else | |
119 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 119 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
120 | req.bRequest = AXEN_CMD_CMD(cmd); | 120 | req.bRequest = AXEN_CMD_CMD(cmd); | |
121 | USETW(req.wValue, val); | 121 | USETW(req.wValue, val); | |
122 | USETW(req.wIndex, index); | 122 | USETW(req.wIndex, index); | |
123 | USETW(req.wLength, AXEN_CMD_LEN(cmd)); | 123 | USETW(req.wLength, AXEN_CMD_LEN(cmd)); | |
124 | 124 | |||
125 | err = usbd_do_request(un->un_udev, &req, buf); | 125 | err = usbd_do_request(un->un_udev, &req, buf); | |
126 | DPRINTFN(5, ("axen_cmd: cmd 0x%04x val 0x%04x len %d\n", | 126 | DPRINTFN(5, ("axen_cmd: cmd 0x%04x val 0x%04x len %d\n", | |
127 | cmd, val, AXEN_CMD_LEN(cmd))); | 127 | cmd, val, AXEN_CMD_LEN(cmd))); | |
128 | 128 | |||
129 | if (err) { | 129 | if (err) { | |
130 | DPRINTF(("%s: cmd: %d, error: %d\n", __func__, cmd, err)); | 130 | DPRINTF(("%s: cmd: %d, error: %d\n", __func__, cmd, err)); | |
131 | return -1; | 131 | return -1; | |
132 | } | 132 | } | |
133 | 133 | |||
134 | return 0; | 134 | return 0; | |
135 | } | 135 | } | |
136 | 136 | |||
137 | static int | 137 | static int | |
138 | axen_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 138 | axen_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
139 | { | 139 | { | |
140 | uint16_t data; | 140 | uint16_t data; | |
141 | 141 | |||
142 | if (un->un_phyno != phy) | 142 | if (un->un_phyno != phy) | |
143 | return EINVAL; | 143 | return EINVAL; | |
144 | 144 | |||
145 | usbd_status err = axen_cmd(un, AXEN_CMD_MII_READ_REG, reg, phy, &data); | 145 | usbd_status err = axen_cmd(un, AXEN_CMD_MII_READ_REG, reg, phy, &data); | |
146 | if (err) | 146 | if (err) | |
147 | return EIO; | 147 | return EIO; | |
148 | 148 | |||
149 | *val = le16toh(data); | 149 | *val = le16toh(data); | |
150 | if (reg == MII_BMSR) | 150 | if (reg == MII_BMSR) | |
151 | *val &= ~BMSR_EXTCAP; | 151 | *val &= ~BMSR_EXTCAP; | |
152 | 152 | |||
153 | return 0; | 153 | return 0; | |
154 | } | 154 | } | |
155 | 155 | |||
156 | static int | 156 | static int | |
157 | axen_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 157 | axen_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
158 | { | 158 | { | |
159 | uint16_t uval = htole16(val); | 159 | uint16_t uval = htole16(val); | |
160 | 160 | |||
161 | if (un->un_phyno != phy) | 161 | if (un->un_phyno != phy) | |
162 | return EINVAL; | 162 | return EINVAL; | |
163 | 163 | |||
164 | usbd_status err = axen_cmd(un, AXEN_CMD_MII_WRITE_REG, reg, phy, &uval); | 164 | usbd_status err = axen_cmd(un, AXEN_CMD_MII_WRITE_REG, reg, phy, &uval); | |
165 | if (err) | 165 | if (err) | |
166 | return EIO; | 166 | return EIO; | |
167 | 167 | |||
168 | return 0; | 168 | return 0; | |
169 | } | 169 | } | |
170 | 170 | |||
171 | static void | 171 | static void | |
172 | axen_uno_mii_statchg(struct ifnet *ifp) | 172 | axen_uno_mii_statchg(struct ifnet *ifp) | |
173 | { | 173 | { | |
174 | struct usbnet * const un = ifp->if_softc; | 174 | struct usbnet * const un = ifp->if_softc; | |
175 | struct mii_data * const mii = usbnet_mii(un); | 175 | struct mii_data * const mii = usbnet_mii(un); | |
176 | int err; | 176 | int err; | |
177 | uint16_t val; | 177 | uint16_t val; | |
178 | uint16_t wval; | 178 | uint16_t wval; | |
179 | 179 | |||
180 | if (usbnet_isdying(un)) | 180 | if (usbnet_isdying(un)) | |
181 | return; | 181 | return; | |
182 | 182 | |||
183 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 183 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
184 | (IFM_ACTIVE | IFM_AVALID)) { | 184 | (IFM_ACTIVE | IFM_AVALID)) { | |
185 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 185 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
186 | case IFM_10_T: | 186 | case IFM_10_T: | |
187 | case IFM_100_TX: | 187 | case IFM_100_TX: | |
188 | usbnet_set_link(un, true); | 188 | usbnet_set_link(un, true); | |
189 | break; | 189 | break; | |
190 | case IFM_1000_T: | 190 | case IFM_1000_T: | |
191 | usbnet_set_link(un, true); | 191 | usbnet_set_link(un, true); | |
192 | break; | 192 | break; | |
193 | default: | 193 | default: | |
194 | break; | 194 | break; | |
195 | } | 195 | } | |
196 | } | 196 | } | |
197 | 197 | |||
198 | /* Lost link, do nothing. */ | 198 | /* Lost link, do nothing. */ | |
199 | if (!usbnet_havelink(un)) | 199 | if (!usbnet_havelink(un)) | |
200 | return; | 200 | return; | |
201 | 201 | |||
202 | val = 0; | 202 | val = 0; | |
203 | if ((mii->mii_media_active & IFM_FDX) != 0) | 203 | if ((mii->mii_media_active & IFM_FDX) != 0) | |
204 | val |= AXEN_MEDIUM_FDX; | 204 | val |= AXEN_MEDIUM_FDX; | |
205 | 205 | |||
206 | val |= AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN | | 206 | val |= AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN | | |
207 | AXEN_MEDIUM_RECV_EN; | 207 | AXEN_MEDIUM_RECV_EN; | |
208 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 208 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
209 | case IFM_1000_T: | 209 | case IFM_1000_T: | |
210 | val |= AXEN_MEDIUM_GIGA | AXEN_MEDIUM_EN_125MHZ; | 210 | val |= AXEN_MEDIUM_GIGA | AXEN_MEDIUM_EN_125MHZ; | |
211 | break; | 211 | break; | |
212 | case IFM_100_TX: | 212 | case IFM_100_TX: | |
213 | val |= AXEN_MEDIUM_PS; | 213 | val |= AXEN_MEDIUM_PS; | |
214 | break; | 214 | break; | |
215 | case IFM_10_T: | 215 | case IFM_10_T: | |
216 | /* doesn't need to be handled */ | 216 | /* doesn't need to be handled */ | |
217 | break; | 217 | break; | |
218 | } | 218 | } | |
219 | 219 | |||
220 | DPRINTF(("%s: val=%#x\n", __func__, val)); | 220 | DPRINTF(("%s: val=%#x\n", __func__, val)); | |
221 | wval = htole16(val); | 221 | wval = htole16(val); | |
222 | err = axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval); | 222 | err = axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval); | |
223 | if (err) | 223 | if (err) | |
224 | aprint_error_dev(un->un_dev, "media change failed\n"); | 224 | aprint_error_dev(un->un_dev, "media change failed\n"); | |
225 | } | 225 | } | |
226 | 226 | |||
227 | static void | 227 | static void | |
228 | axen_setiff_locked(struct usbnet *un) | 228 | axen_setiff_locked(struct usbnet *un) | |
229 | { | 229 | { | |
230 | struct ifnet * const ifp = usbnet_ifp(un); | 230 | struct ifnet * const ifp = usbnet_ifp(un); | |
231 | struct ethercom *ec = usbnet_ec(un); | 231 | struct ethercom *ec = usbnet_ec(un); | |
232 | struct ether_multi *enm; | 232 | struct ether_multi *enm; | |
233 | struct ether_multistep step; | 233 | struct ether_multistep step; | |
234 | uint32_t h = 0; | 234 | uint32_t h = 0; | |
235 | uint16_t rxmode; | 235 | uint16_t rxmode; | |
236 | uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 236 | uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
237 | uint16_t wval; | 237 | uint16_t wval; | |
238 | 238 | |||
239 | if (usbnet_isdying(un)) | 239 | if (usbnet_isdying(un)) | |
240 | return; | 240 | return; | |
241 | 241 | |||
242 | usbnet_isowned_core(un); | 242 | usbnet_isowned_core(un); | |
243 | 243 | |||
244 | rxmode = 0; | 244 | rxmode = 0; | |
245 | 245 | |||
246 | /* Enable receiver, set RX mode */ | 246 | /* Enable receiver, set RX mode */ | |
247 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); | 247 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); | |
248 | rxmode = le16toh(wval); | 248 | rxmode = le16toh(wval); | |
249 | rxmode &= ~(AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_PROMISC | | 249 | rxmode &= ~(AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_PROMISC | | |
250 | AXEN_RXCTL_ACPT_MCAST); | 250 | AXEN_RXCTL_ACPT_MCAST); | |
251 | 251 | |||
252 | if (ifp->if_flags & IFF_PROMISC) { | 252 | if (ifp->if_flags & IFF_PROMISC) { | |
253 | DPRINTF(("%s: promisc\n", device_xname(un->un_dev))); | 253 | DPRINTF(("%s: promisc\n", device_xname(un->un_dev))); | |
254 | rxmode |= AXEN_RXCTL_PROMISC; | 254 | rxmode |= AXEN_RXCTL_PROMISC; | |
255 | allmulti: | 255 | allmulti: | |
256 | ETHER_LOCK(ec); | 256 | ETHER_LOCK(ec); | |
257 | ec->ec_flags |= ETHER_F_ALLMULTI; | 257 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
258 | ETHER_UNLOCK(ec); | 258 | ETHER_UNLOCK(ec); | |
259 | rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST | 259 | rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST | |
260 | /* | AXEN_RXCTL_ACPT_PHY_MCAST */; | 260 | /* | AXEN_RXCTL_ACPT_PHY_MCAST */; | |
261 | } else { | 261 | } else { | |
262 | /* now program new ones */ | 262 | /* now program new ones */ | |
263 | DPRINTF(("%s: initializing hash table\n", | 263 | DPRINTF(("%s: initializing hash table\n", | |
264 | device_xname(un->un_dev))); | 264 | device_xname(un->un_dev))); | |
265 | ETHER_LOCK(ec); | 265 | ETHER_LOCK(ec); | |
266 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 266 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
267 | 267 | |||
268 | ETHER_FIRST_MULTI(step, ec, enm); | 268 | ETHER_FIRST_MULTI(step, ec, enm); | |
269 | while (enm != NULL) { | 269 | while (enm != NULL) { | |
270 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | 270 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
271 | ETHER_ADDR_LEN)) { | 271 | ETHER_ADDR_LEN)) { | |
272 | DPRINTF(("%s: allmulti\n", | 272 | DPRINTF(("%s: allmulti\n", | |
273 | device_xname(un->un_dev))); | 273 | device_xname(un->un_dev))); | |
274 | memset(hashtbl, 0, sizeof(hashtbl)); | 274 | memset(hashtbl, 0, sizeof(hashtbl)); | |
275 | ETHER_UNLOCK(ec); | 275 | ETHER_UNLOCK(ec); | |
276 | goto allmulti; | 276 | goto allmulti; | |
277 | } | 277 | } | |
278 | h = ether_crc32_be(enm->enm_addrlo, | 278 | h = ether_crc32_be(enm->enm_addrlo, | |
279 | ETHER_ADDR_LEN) >> 26; | 279 | ETHER_ADDR_LEN) >> 26; | |
280 | hashtbl[h / 8] |= 1 << (h % 8); | 280 | hashtbl[h / 8] |= 1 << (h % 8); | |
281 | DPRINTF(("%s: %s added\n", | 281 | DPRINTF(("%s: %s added\n", | |
282 | device_xname(un->un_dev), | 282 | device_xname(un->un_dev), | |
283 | ether_sprintf(enm->enm_addrlo))); | 283 | ether_sprintf(enm->enm_addrlo))); | |
284 | ETHER_NEXT_MULTI(step, enm); | 284 | ETHER_NEXT_MULTI(step, enm); | |
285 | } | 285 | } | |
286 | ETHER_UNLOCK(ec); | 286 | ETHER_UNLOCK(ec); | |
287 | rxmode |= AXEN_RXCTL_ACPT_MCAST; | 287 | rxmode |= AXEN_RXCTL_ACPT_MCAST; | |
288 | } | 288 | } | |
289 | 289 | |||
290 | axen_cmd(un, AXEN_CMD_MAC_WRITE_FILTER, 8, AXEN_FILTER_MULTI, hashtbl); | 290 | axen_cmd(un, AXEN_CMD_MAC_WRITE_FILTER, 8, AXEN_FILTER_MULTI, hashtbl); | |
291 | wval = htole16(rxmode); | 291 | wval = htole16(rxmode); | |
292 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | 292 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | |
293 | } | 293 | } | |
294 | 294 | |||
295 | static void | 295 | static void | |
296 | axen_reset(struct usbnet *un) | 296 | axen_reset(struct usbnet *un) | |
297 | { | 297 | { | |
298 | usbnet_isowned_core(un); | 298 | usbnet_isowned_core(un); | |
299 | if (usbnet_isdying(un)) | 299 | if (usbnet_isdying(un)) | |
300 | return; | 300 | return; | |
301 | /* XXX What to reset? */ | 301 | /* XXX What to reset? */ | |
302 | 302 | |||
303 | /* Wait a little while for the chip to get its brains in order. */ | 303 | /* Wait a little while for the chip to get its brains in order. */ | |
304 | DELAY(1000); | 304 | DELAY(1000); | |
305 | } | 305 | } | |
306 | 306 | |||
307 | static int | 307 | static int | |
308 | axen_get_eaddr(struct usbnet *un, void *addr) | 308 | axen_get_eaddr(struct usbnet *un, void *addr) | |
309 | { | 309 | { | |
310 | #if 1 | 310 | #if 1 | |
311 | return axen_cmd(un, AXEN_CMD_MAC_READ_ETHER, 6, AXEN_CMD_MAC_NODE_ID, | 311 | return axen_cmd(un, AXEN_CMD_MAC_READ_ETHER, 6, AXEN_CMD_MAC_NODE_ID, | |
312 | addr); | 312 | addr); | |
313 | #else | 313 | #else | |
314 | int i, retry; | 314 | int i, retry; | |
315 | uint8_t eeprom[20]; | 315 | uint8_t eeprom[20]; | |
316 | uint16_t csum; | 316 | uint16_t csum; | |
317 | uint16_t buf; | 317 | uint16_t buf; | |
318 | 318 | |||
319 | for (i = 0; i < 6; i++) { | 319 | for (i = 0; i < 6; i++) { | |
320 | /* set eeprom address */ | 320 | /* set eeprom address */ | |
321 | buf = htole16(i); | 321 | buf = htole16(i); | |
322 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MAC_EEPROM_ADDR, &buf); | 322 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MAC_EEPROM_ADDR, &buf); | |
323 | 323 | |||
324 | /* set eeprom command */ | 324 | /* set eeprom command */ | |
325 | buf = htole16(AXEN_EEPROM_READ); | 325 | buf = htole16(AXEN_EEPROM_READ); | |
326 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MAC_EEPROM_CMD, &buf); | 326 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MAC_EEPROM_CMD, &buf); | |
327 | 327 | |||
328 | /* check the value is ready */ | 328 | /* check the value is ready */ | |
329 | retry = 3; | 329 | retry = 3; | |
330 | do { | 330 | do { | |
331 | buf = htole16(AXEN_EEPROM_READ); | 331 | buf = htole16(AXEN_EEPROM_READ); | |
332 | usbd_delay_ms(un->un_udev, 10); | 332 | usbd_delay_ms(un->un_udev, 10); | |
333 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_MAC_EEPROM_CMD, | 333 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_MAC_EEPROM_CMD, | |
334 | &buf); | 334 | &buf); | |
335 | retry--; | 335 | retry--; | |
336 | if (retry < 0) | 336 | if (retry < 0) | |
337 | return EINVAL; | 337 | return EINVAL; | |
338 | } while ((le16toh(buf) & 0xff) & AXEN_EEPROM_BUSY); | 338 | } while ((le16toh(buf) & 0xff) & AXEN_EEPROM_BUSY); | |
339 | 339 | |||
340 | /* read data */ | 340 | /* read data */ | |
341 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_EEPROM_READ, | 341 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_EEPROM_READ, | |
342 | &eeprom[i * 2]); | 342 | &eeprom[i * 2]); | |
343 | 343 | |||
344 | /* sanity check */ | 344 | /* sanity check */ | |
345 | if ((i == 0) && (eeprom[0] == 0xff)) | 345 | if ((i == 0) && (eeprom[0] == 0xff)) | |
346 | return EINVAL; | 346 | return EINVAL; | |
347 | } | 347 | } | |
348 | 348 | |||
349 | /* check checksum */ | 349 | /* check checksum */ | |
350 | csum = eeprom[6] + eeprom[7] + eeprom[8] + eeprom[9]; | 350 | csum = eeprom[6] + eeprom[7] + eeprom[8] + eeprom[9]; | |
351 | csum = (csum >> 8) + (csum & 0xff) + eeprom[10]; | 351 | csum = (csum >> 8) + (csum & 0xff) + eeprom[10]; | |
352 | if (csum != 0xff) { | 352 | if (csum != 0xff) { | |
353 | printf("eeprom checksum mismatch(0x%02x)\n", csum); | 353 | printf("eeprom checksum mismatch(0x%02x)\n", csum); | |
354 | return EINVAL; | 354 | return EINVAL; | |
355 | } | 355 | } | |
356 | 356 | |||
357 | memcpy(addr, eeprom, ETHER_ADDR_LEN); | 357 | memcpy(addr, eeprom, ETHER_ADDR_LEN); | |
358 | return 0; | 358 | return 0; | |
359 | #endif | 359 | #endif | |
360 | } | 360 | } | |
361 | 361 | |||
362 | static void | 362 | static void | |
363 | axen_ax88179_init(struct usbnet *un) | 363 | axen_ax88179_init(struct usbnet *un) | |
364 | { | 364 | { | |
365 | struct axen_qctrl qctrl; | 365 | struct axen_qctrl qctrl; | |
366 | uint16_t ctl, temp; | 366 | uint16_t ctl, temp; | |
367 | uint16_t wval; | 367 | uint16_t wval; | |
368 | uint8_t val; | 368 | uint8_t val; | |
369 | 369 | |||
370 | usbnet_lock_core(un); | 370 | usbnet_lock_core(un); | |
371 | usbnet_busy(un); | 371 | usbnet_busy(un); | |
372 | 372 | |||
373 | /* XXX: ? */ | 373 | /* XXX: ? */ | |
374 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_UNK_05, &val); | 374 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_UNK_05, &val); | |
375 | DPRINTFN(5, ("AXEN_CMD_MAC_READ(0x05): 0x%02x\n", val)); | 375 | DPRINTFN(5, ("AXEN_CMD_MAC_READ(0x05): 0x%02x\n", val)); | |
376 | 376 | |||
377 | /* check AX88179 version, UA1 / UA2 */ | 377 | /* check AX88179 version, UA1 / UA2 */ | |
378 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_GENERAL_STATUS, &val); | 378 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_GENERAL_STATUS, &val); | |
379 | /* UA1 */ | 379 | /* UA1 */ | |
380 | if (!(val & AXEN_GENERAL_STATUS_MASK)) { | 380 | if (!(val & AXEN_GENERAL_STATUS_MASK)) { | |
381 | DPRINTF(("AX88179 ver. UA1\n")); | 381 | DPRINTF(("AX88179 ver. UA1\n")); | |
382 | } else { | 382 | } else { | |
383 | DPRINTF(("AX88179 ver. UA2\n")); | 383 | DPRINTF(("AX88179 ver. UA2\n")); | |
384 | } | 384 | } | |
385 | 385 | |||
386 | /* power up ethernet PHY */ | 386 | /* power up ethernet PHY */ | |
387 | wval = htole16(0); | 387 | wval = htole16(0); | |
388 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval); | 388 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval); | |
389 | 389 | |||
390 | wval = htole16(AXEN_PHYPWR_RSTCTL_IPRL); | 390 | wval = htole16(AXEN_PHYPWR_RSTCTL_IPRL); | |
391 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval); | 391 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval); | |
392 | usbd_delay_ms(un->un_udev, 200); | 392 | usbd_delay_ms(un->un_udev, 200); | |
393 | 393 | |||
394 | /* set clock mode */ | 394 | /* set clock mode */ | |
395 | val = AXEN_PHYCLK_ACS | AXEN_PHYCLK_BCS; | 395 | val = AXEN_PHYCLK_ACS | AXEN_PHYCLK_BCS; | |
396 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val); | 396 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val); | |
397 | usbd_delay_ms(un->un_udev, 100); | 397 | usbd_delay_ms(un->un_udev, 100); | |
398 | 398 | |||
399 | /* set monitor mode (disable) */ | 399 | /* set monitor mode (disable) */ | |
400 | val = AXEN_MONITOR_NONE; | 400 | val = AXEN_MONITOR_NONE; | |
401 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val); | 401 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val); | |
402 | 402 | |||
403 | /* enable auto detach */ | 403 | /* enable auto detach */ | |
404 | axen_cmd(un, AXEN_CMD_EEPROM_READ, 2, AXEN_EEPROM_STAT, &wval); | 404 | axen_cmd(un, AXEN_CMD_EEPROM_READ, 2, AXEN_EEPROM_STAT, &wval); | |
405 | temp = le16toh(wval); | 405 | temp = le16toh(wval); | |
406 | DPRINTFN(2,("EEPROM0x43 = 0x%04x\n", temp)); | 406 | DPRINTFN(2,("EEPROM0x43 = 0x%04x\n", temp)); | |
407 | if (!(temp == 0xffff) && !(temp & 0x0100)) { | 407 | if (!(temp == 0xffff) && !(temp & 0x0100)) { | |
408 | /* Enable auto detach bit */ | 408 | /* Enable auto detach bit */ | |
409 | val = 0; | 409 | val = 0; | |
410 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val); | 410 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val); | |
411 | val = AXEN_PHYCLK_ULR; | 411 | val = AXEN_PHYCLK_ULR; | |
412 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val); | 412 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val); | |
413 | usbd_delay_ms(un->un_udev, 100); | 413 | usbd_delay_ms(un->un_udev, 100); | |
414 | 414 | |||
415 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_PHYPWR_RSTCTL, &wval); | 415 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_PHYPWR_RSTCTL, &wval); | |
416 | ctl = le16toh(wval); | 416 | ctl = le16toh(wval); | |
417 | ctl |= AXEN_PHYPWR_RSTCTL_AUTODETACH; | 417 | ctl |= AXEN_PHYPWR_RSTCTL_AUTODETACH; | |
418 | wval = htole16(ctl); | 418 | wval = htole16(ctl); | |
419 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval); | 419 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval); | |
420 | usbd_delay_ms(un->un_udev, 200); | 420 | usbd_delay_ms(un->un_udev, 200); | |
421 | aprint_error_dev(un->un_dev, "enable auto detach (0x%04x)\n", | 421 | aprint_error_dev(un->un_dev, "enable auto detach (0x%04x)\n", | |
422 | ctl); | 422 | ctl); | |
423 | } | 423 | } | |
424 | 424 | |||
425 | /* bulkin queue setting */ | 425 | /* bulkin queue setting */ | |
426 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_USB_UPLINK, &val); | 426 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_USB_UPLINK, &val); | |
427 | switch (val) { | 427 | switch (val) { | |
428 | case AXEN_USB_FS: | 428 | case AXEN_USB_FS: | |
429 | DPRINTF(("uplink: USB1.1\n")); | 429 | DPRINTF(("uplink: USB1.1\n")); | |
430 | qctrl.ctrl = 0x07; | 430 | qctrl.ctrl = 0x07; | |
431 | qctrl.timer_low = 0xcc; | 431 | qctrl.timer_low = 0xcc; | |
432 | qctrl.timer_high = 0x4c; | 432 | qctrl.timer_high = 0x4c; | |
433 | qctrl.bufsize = AXEN_BUFSZ_LS - 1; | 433 | qctrl.bufsize = AXEN_BUFSZ_LS - 1; | |
434 | qctrl.ifg = 0x08; | 434 | qctrl.ifg = 0x08; | |
435 | break; | 435 | break; | |
436 | case AXEN_USB_HS: | 436 | case AXEN_USB_HS: | |
437 | DPRINTF(("uplink: USB2.0\n")); | 437 | DPRINTF(("uplink: USB2.0\n")); | |
438 | qctrl.ctrl = 0x07; | 438 | qctrl.ctrl = 0x07; | |
439 | qctrl.timer_low = 0x02; | 439 | qctrl.timer_low = 0x02; | |
440 | qctrl.timer_high = 0xa0; | 440 | qctrl.timer_high = 0xa0; | |
441 | qctrl.bufsize = AXEN_BUFSZ_HS - 1; | 441 | qctrl.bufsize = AXEN_BUFSZ_HS - 1; | |
442 | qctrl.ifg = 0xff; | 442 | qctrl.ifg = 0xff; | |
443 | break; | 443 | break; | |
444 | case AXEN_USB_SS: | 444 | case AXEN_USB_SS: | |
445 | DPRINTF(("uplink: USB3.0\n")); | 445 | DPRINTF(("uplink: USB3.0\n")); | |
446 | qctrl.ctrl = 0x07; | 446 | qctrl.ctrl = 0x07; | |
447 | qctrl.timer_low = 0x4f; | 447 | qctrl.timer_low = 0x4f; | |
448 | qctrl.timer_high = 0x00; | 448 | qctrl.timer_high = 0x00; | |
449 | qctrl.bufsize = AXEN_BUFSZ_SS - 1; | 449 | qctrl.bufsize = AXEN_BUFSZ_SS - 1; | |
450 | qctrl.ifg = 0xff; | 450 | qctrl.ifg = 0xff; | |
451 | break; | 451 | break; | |
452 | default: | 452 | default: | |
453 | aprint_error_dev(un->un_dev, "unknown uplink bus:0x%02x\n", | 453 | aprint_error_dev(un->un_dev, "unknown uplink bus:0x%02x\n", | |
454 | val); | 454 | val); | |
455 | usbnet_unbusy(un); | 455 | usbnet_unbusy(un); | |
456 | usbnet_unlock_core(un); | 456 | usbnet_unlock_core(un); | |
457 | return; | 457 | return; | |
458 | } | 458 | } | |
459 | axen_cmd(un, AXEN_CMD_MAC_SET_RXSR, 5, AXEN_RX_BULKIN_QCTRL, &qctrl); | 459 | axen_cmd(un, AXEN_CMD_MAC_SET_RXSR, 5, AXEN_RX_BULKIN_QCTRL, &qctrl); | |
460 | 460 | |||
461 | /* | 461 | /* | |
462 | * set buffer high/low watermark to pause/resume. | 462 | * set buffer high/low watermark to pause/resume. | |
463 | * write 2byte will set high/log simultaneous with AXEN_PAUSE_HIGH. | 463 | * write 2byte will set high/log simultaneous with AXEN_PAUSE_HIGH. | |
464 | * XXX: what is the best value? OSX driver uses 0x3c-0x4c as LOW-HIGH | 464 | * XXX: what is the best value? OSX driver uses 0x3c-0x4c as LOW-HIGH | |
465 | * watermark parameters. | 465 | * watermark parameters. | |
466 | */ | 466 | */ | |
467 | val = 0x34; | 467 | val = 0x34; | |
468 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_LOW_WATERMARK, &val); | 468 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_LOW_WATERMARK, &val); | |
469 | val = 0x52; | 469 | val = 0x52; | |
470 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_HIGH_WATERMARK, &val); | 470 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_HIGH_WATERMARK, &val); | |
471 | 471 | |||
472 | /* Set RX/TX configuration. */ | 472 | /* Set RX/TX configuration. */ | |
473 | /* Set RX control register */ | 473 | /* Set RX control register */ | |
474 | ctl = AXEN_RXCTL_IPE | AXEN_RXCTL_DROPCRCERR | AXEN_RXCTL_AUTOB; | 474 | ctl = AXEN_RXCTL_IPE | AXEN_RXCTL_DROPCRCERR | AXEN_RXCTL_AUTOB; | |
475 | wval = htole16(ctl); | 475 | wval = htole16(ctl); | |
476 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | 476 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | |
477 | 477 | |||
478 | /* set monitor mode (enable) */ | 478 | /* set monitor mode (enable) */ | |
479 | val = AXEN_MONITOR_PMETYPE | AXEN_MONITOR_PMEPOL | AXEN_MONITOR_RWMP; | 479 | val = AXEN_MONITOR_PMETYPE | AXEN_MONITOR_PMEPOL | AXEN_MONITOR_RWMP; | |
480 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val); | 480 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val); | |
481 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_MONITOR_MODE, &val); | 481 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_MONITOR_MODE, &val); | |
482 | DPRINTF(("axen: Monitor mode = 0x%02x\n", val)); | 482 | DPRINTF(("axen: Monitor mode = 0x%02x\n", val)); | |
483 | 483 | |||
484 | /* set medium type */ | 484 | /* set medium type */ | |
485 | ctl = AXEN_MEDIUM_GIGA | AXEN_MEDIUM_FDX | AXEN_MEDIUM_EN_125MHZ | | 485 | ctl = AXEN_MEDIUM_GIGA | AXEN_MEDIUM_FDX | AXEN_MEDIUM_EN_125MHZ | | |
486 | AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN | | 486 | AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN | | |
487 | AXEN_MEDIUM_RECV_EN; | 487 | AXEN_MEDIUM_RECV_EN; | |
488 | wval = htole16(ctl); | 488 | wval = htole16(ctl); | |
489 | DPRINTF(("axen: set to medium mode: 0x%04x\n", ctl)); | 489 | DPRINTF(("axen: set to medium mode: 0x%04x\n", ctl)); | |
490 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval); | 490 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval); | |
491 | usbd_delay_ms(un->un_udev, 100); | 491 | usbd_delay_ms(un->un_udev, 100); | |
492 | 492 | |||
493 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MEDIUM_STATUS, &wval); | 493 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MEDIUM_STATUS, &wval); | |
494 | DPRINTF(("axen: current medium mode: 0x%04x\n", le16toh(wval))); | 494 | DPRINTF(("axen: current medium mode: 0x%04x\n", le16toh(wval))); | |
495 | 495 | |||
496 | #if 0 /* XXX: TBD.... */ | 496 | #if 0 /* XXX: TBD.... */ | |
497 | #define GMII_LED_ACTIVE 0x1a | 497 | #define GMII_LED_ACTIVE 0x1a | |
498 | #define GMII_PHY_PAGE_SEL 0x1e | 498 | #define GMII_PHY_PAGE_SEL 0x1e | |
499 | #define GMII_PHY_PAGE_SEL 0x1f | 499 | #define GMII_PHY_PAGE_SEL 0x1f | |
500 | #define GMII_PAGE_EXT 0x0007 | 500 | #define GMII_PAGE_EXT 0x0007 | |
501 | usbnet_mii_writereg(un->un_dev, un->un_phyno, GMII_PHY_PAGE_SEL, | 501 | usbnet_mii_writereg(un->un_dev, un->un_phyno, GMII_PHY_PAGE_SEL, | |
502 | GMII_PAGE_EXT); | 502 | GMII_PAGE_EXT); | |
503 | usbnet_mii_writereg(un->un_dev, un->un_phyno, GMII_PHY_PAGE, | 503 | usbnet_mii_writereg(un->un_dev, un->un_phyno, GMII_PHY_PAGE, | |
504 | 0x002c); | 504 | 0x002c); | |
505 | #endif | 505 | #endif | |
506 | 506 | |||
507 | #if 1 /* XXX: phy hack ? */ | 507 | #if 1 /* XXX: phy hack ? */ | |
508 | usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x1F, 0x0005); | 508 | usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x1F, 0x0005); | |
509 | usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x0C, 0x0000); | 509 | usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x0C, 0x0000); | |
510 | usbnet_mii_readreg(un->un_dev, un->un_phyno, 0x0001, &wval); | 510 | usbnet_mii_readreg(un->un_dev, un->un_phyno, 0x0001, &wval); | |
511 | usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x01, wval | 0x0080); | 511 | usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x01, wval | 0x0080); | |
512 | usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x1F, 0x0000); | 512 | usbnet_mii_writereg(un->un_dev, un->un_phyno, 0x1F, 0x0000); | |
513 | #endif | 513 | #endif | |
514 | 514 | |||
515 | usbnet_unbusy(un); | 515 | usbnet_unbusy(un); | |
516 | usbnet_unlock_core(un); | 516 | usbnet_unlock_core(un); | |
517 | } | 517 | } | |
518 | 518 | |||
519 | static void | 519 | static void | |
520 | axen_setoe_locked(struct usbnet *un) | 520 | axen_setoe_locked(struct usbnet *un) | |
521 | { | 521 | { | |
522 | struct ifnet * const ifp = usbnet_ifp(un); | 522 | struct ifnet * const ifp = usbnet_ifp(un); | |
523 | uint64_t enabled = ifp->if_capenable; | 523 | uint64_t enabled = ifp->if_capenable; | |
524 | uint8_t val; | 524 | uint8_t val; | |
525 | 525 | |||
526 | usbnet_isowned_core(un); | 526 | usbnet_isowned_core(un); | |
527 | 527 | |||
528 | val = AXEN_RXCOE_OFF; | 528 | val = AXEN_RXCOE_OFF; | |
529 | if (enabled & IFCAP_CSUM_IPv4_Rx) | 529 | if (enabled & IFCAP_CSUM_IPv4_Rx) | |
530 | val |= AXEN_RXCOE_IPv4; | 530 | val |= AXEN_RXCOE_IPv4; | |
531 | if (enabled & IFCAP_CSUM_TCPv4_Rx) | 531 | if (enabled & IFCAP_CSUM_TCPv4_Rx) | |
532 | val |= AXEN_RXCOE_TCPv4; | 532 | val |= AXEN_RXCOE_TCPv4; | |
533 | if (enabled & IFCAP_CSUM_UDPv4_Rx) | 533 | if (enabled & IFCAP_CSUM_UDPv4_Rx) | |
534 | val |= AXEN_RXCOE_UDPv4; | 534 | val |= AXEN_RXCOE_UDPv4; | |
535 | if (enabled & IFCAP_CSUM_TCPv6_Rx) | 535 | if (enabled & IFCAP_CSUM_TCPv6_Rx) | |
536 | val |= AXEN_RXCOE_TCPv6; | 536 | val |= AXEN_RXCOE_TCPv6; | |
537 | if (enabled & IFCAP_CSUM_UDPv6_Rx) | 537 | if (enabled & IFCAP_CSUM_UDPv6_Rx) | |
538 | val |= AXEN_RXCOE_UDPv6; | 538 | val |= AXEN_RXCOE_UDPv6; | |
539 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_RX_COE, &val); | 539 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_RX_COE, &val); | |
540 | 540 | |||
541 | val = AXEN_TXCOE_OFF; | 541 | val = AXEN_TXCOE_OFF; | |
542 | if (enabled & IFCAP_CSUM_IPv4_Tx) | 542 | if (enabled & IFCAP_CSUM_IPv4_Tx) | |
543 | val |= AXEN_TXCOE_IPv4; | 543 | val |= AXEN_TXCOE_IPv4; | |
544 | if (enabled & IFCAP_CSUM_TCPv4_Tx) | 544 | if (enabled & IFCAP_CSUM_TCPv4_Tx) | |
545 | val |= AXEN_TXCOE_TCPv4; | 545 | val |= AXEN_TXCOE_TCPv4; | |
546 | if (enabled & IFCAP_CSUM_UDPv4_Tx) | 546 | if (enabled & IFCAP_CSUM_UDPv4_Tx) | |
547 | val |= AXEN_TXCOE_UDPv4; | 547 | val |= AXEN_TXCOE_UDPv4; | |
548 | if (enabled & IFCAP_CSUM_TCPv6_Tx) | 548 | if (enabled & IFCAP_CSUM_TCPv6_Tx) | |
549 | val |= AXEN_TXCOE_TCPv6; | 549 | val |= AXEN_TXCOE_TCPv6; | |
550 | if (enabled & IFCAP_CSUM_UDPv6_Tx) | 550 | if (enabled & IFCAP_CSUM_UDPv6_Tx) | |
551 | val |= AXEN_TXCOE_UDPv6; | 551 | val |= AXEN_TXCOE_UDPv6; | |
552 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_TX_COE, &val); | 552 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_TX_COE, &val); | |
553 | } | 553 | } | |
554 | 554 | |||
555 | static int | 555 | static int | |
556 | axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 556 | axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
557 | { | 557 | { | |
558 | struct usbnet * const un = ifp->if_softc; | 558 | struct usbnet * const un = ifp->if_softc; | |
559 | 559 | |||
560 | usbnet_lock_core(un); | 560 | usbnet_lock_core(un); | |
561 | usbnet_busy(un); | 561 | usbnet_busy(un); | |
562 | 562 | |||
563 | switch (cmd) { | 563 | switch (cmd) { | |
564 | case SIOCSIFCAP: | 564 | case SIOCSIFCAP: | |
565 | axen_setoe_locked(un); | 565 | axen_setoe_locked(un); | |
566 | break; | 566 | break; | |
567 | default: | 567 | default: | |
568 | break; | 568 | break; | |
569 | } | 569 | } | |
570 | 570 | |||
571 | usbnet_unbusy(un); | 571 | usbnet_unbusy(un); | |
572 | usbnet_unlock_core(un); | 572 | usbnet_unlock_core(un); | |
573 | 573 | |||
574 | return 0; | 574 | return 0; | |
575 | } | 575 | } | |
576 | 576 | |||
577 | static void | 577 | static void | |
578 | axen_uno_mcast(struct ifnet *ifp) | 578 | axen_uno_mcast(struct ifnet *ifp) | |
579 | { | 579 | { | |
580 | struct usbnet * const un = ifp->if_softc; | 580 | struct usbnet * const un = ifp->if_softc; | |
581 | 581 | |||
582 | usbnet_lock_core(un); | 582 | usbnet_lock_core(un); | |
583 | usbnet_busy(un); | |||
584 | 583 | |||
585 | axen_setiff_locked(un); | 584 | axen_setiff_locked(un); | |
586 | 585 | |||
587 | usbnet_unbusy(un); | |||
588 | usbnet_unlock_core(un); | 586 | usbnet_unlock_core(un); | |
589 | } | 587 | } | |
590 | 588 | |||
591 | static int | 589 | static int | |
592 | axen_match(device_t parent, cfdata_t match, void *aux) | 590 | axen_match(device_t parent, cfdata_t match, void *aux) | |
593 | { | 591 | { | |
594 | struct usb_attach_arg *uaa = aux; | 592 | struct usb_attach_arg *uaa = aux; | |
595 | 593 | |||
596 | return axen_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 594 | return axen_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
597 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 595 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
598 | } | 596 | } | |
599 | 597 | |||
600 | static void | 598 | static void | |
601 | axen_attach(device_t parent, device_t self, void *aux) | 599 | axen_attach(device_t parent, device_t self, void *aux) | |
602 | { | 600 | { | |
603 | USBNET_MII_DECL_DEFAULT(unm); | 601 | USBNET_MII_DECL_DEFAULT(unm); | |
604 | struct usbnet * const un = device_private(self); | 602 | struct usbnet * const un = device_private(self); | |
605 | struct usb_attach_arg *uaa = aux; | 603 | struct usb_attach_arg *uaa = aux; | |
606 | struct usbd_device *dev = uaa->uaa_device; | 604 | struct usbd_device *dev = uaa->uaa_device; | |
607 | usbd_status err; | 605 | usbd_status err; | |
608 | usb_interface_descriptor_t *id; | 606 | usb_interface_descriptor_t *id; | |
609 | usb_endpoint_descriptor_t *ed; | 607 | usb_endpoint_descriptor_t *ed; | |
610 | char *devinfop; | 608 | char *devinfop; | |
611 | uint16_t axen_flags; | 609 | uint16_t axen_flags; | |
612 | int i; | 610 | int i; | |
613 | 611 | |||
614 | aprint_naive("\n"); | 612 | aprint_naive("\n"); | |
615 | aprint_normal("\n"); | 613 | aprint_normal("\n"); | |
616 | devinfop = usbd_devinfo_alloc(dev, 0); | 614 | devinfop = usbd_devinfo_alloc(dev, 0); | |
617 | aprint_normal_dev(self, "%s\n", devinfop); | 615 | aprint_normal_dev(self, "%s\n", devinfop); | |
618 | usbd_devinfo_free(devinfop); | 616 | usbd_devinfo_free(devinfop); | |
619 | 617 | |||
620 | un->un_dev = self; | 618 | un->un_dev = self; | |
621 | un->un_udev = dev; | 619 | un->un_udev = dev; | |
622 | un->un_sc = un; | 620 | un->un_sc = un; | |
623 | un->un_ops = &axen_ops; | 621 | un->un_ops = &axen_ops; | |
624 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 622 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
625 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 623 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
626 | un->un_rx_list_cnt = AXEN_RX_LIST_CNT; | 624 | un->un_rx_list_cnt = AXEN_RX_LIST_CNT; | |
627 | un->un_tx_list_cnt = AXEN_TX_LIST_CNT; | 625 | un->un_tx_list_cnt = AXEN_TX_LIST_CNT; | |
628 | 626 | |||
629 | err = usbd_set_config_no(dev, AXEN_CONFIG_NO, 1); | 627 | err = usbd_set_config_no(dev, AXEN_CONFIG_NO, 1); | |
630 | if (err) { | 628 | if (err) { | |
631 | aprint_error_dev(self, "failed to set configuration" | 629 | aprint_error_dev(self, "failed to set configuration" | |
632 | ", err=%s\n", usbd_errstr(err)); | 630 | ", err=%s\n", usbd_errstr(err)); | |
633 | return; | 631 | return; | |
634 | } | 632 | } | |
635 | 633 | |||
636 | axen_flags = axen_lookup(uaa->uaa_vendor, uaa->uaa_product)->axen_flags; | 634 | axen_flags = axen_lookup(uaa->uaa_vendor, uaa->uaa_product)->axen_flags; | |
637 | 635 | |||
638 | err = usbd_device2interface_handle(dev, AXEN_IFACE_IDX, &un->un_iface); | 636 | err = usbd_device2interface_handle(dev, AXEN_IFACE_IDX, &un->un_iface); | |
639 | if (err) { | 637 | if (err) { | |
640 | aprint_error_dev(self, "getting interface handle failed\n"); | 638 | aprint_error_dev(self, "getting interface handle failed\n"); | |
641 | return; | 639 | return; | |
642 | } | 640 | } | |
643 | 641 | |||
644 | /* decide on what our bufsize will be */ | 642 | /* decide on what our bufsize will be */ | |
645 | switch (dev->ud_speed) { | 643 | switch (dev->ud_speed) { | |
646 | case USB_SPEED_SUPER: | 644 | case USB_SPEED_SUPER: | |
647 | un->un_rx_bufsz = AXEN_BUFSZ_SS * 1024; | 645 | un->un_rx_bufsz = AXEN_BUFSZ_SS * 1024; | |
648 | break; | 646 | break; | |
649 | case USB_SPEED_HIGH: | 647 | case USB_SPEED_HIGH: | |
650 | un->un_rx_bufsz = AXEN_BUFSZ_HS * 1024; | 648 | un->un_rx_bufsz = AXEN_BUFSZ_HS * 1024; | |
651 | break; | 649 | break; | |
652 | default: | 650 | default: | |
653 | un->un_rx_bufsz = AXEN_BUFSZ_LS * 1024; | 651 | un->un_rx_bufsz = AXEN_BUFSZ_LS * 1024; | |
654 | break; | 652 | break; | |
655 | } | 653 | } | |
656 | un->un_tx_bufsz = IP_MAXPACKET + ETHER_HDR_LEN + ETHER_CRC_LEN + | 654 | un->un_tx_bufsz = IP_MAXPACKET + ETHER_HDR_LEN + ETHER_CRC_LEN + | |
657 | ETHER_VLAN_ENCAP_LEN + sizeof(struct axen_sframe_hdr); | 655 | ETHER_VLAN_ENCAP_LEN + sizeof(struct axen_sframe_hdr); | |
658 | 656 | |||
659 | /* Find endpoints. */ | 657 | /* Find endpoints. */ | |
660 | id = usbd_get_interface_descriptor(un->un_iface); | 658 | id = usbd_get_interface_descriptor(un->un_iface); | |
661 | for (i = 0; i < id->bNumEndpoints; i++) { | 659 | for (i = 0; i < id->bNumEndpoints; i++) { | |
662 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 660 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
663 | if (!ed) { | 661 | if (!ed) { | |
664 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 662 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
665 | return; | 663 | return; | |
666 | } | 664 | } | |
667 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 665 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
668 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 666 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
669 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 667 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
670 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 668 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
671 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 669 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
672 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 670 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
673 | #if 0 /* not used yet */ | 671 | #if 0 /* not used yet */ | |
674 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 672 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
675 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 673 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
676 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 674 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
677 | #endif | 675 | #endif | |
678 | } | 676 | } | |
679 | } | 677 | } | |
680 | 678 | |||
681 | /* Set these up now for axen_cmd(). */ | 679 | /* Set these up now for axen_cmd(). */ | |
682 | usbnet_attach(un, "axendet"); | 680 | usbnet_attach(un, "axendet"); | |
683 | 681 | |||
684 | un->un_phyno = AXEN_PHY_ID; | 682 | un->un_phyno = AXEN_PHY_ID; | |
685 | DPRINTF(("%s: phyno %d\n", device_xname(self), un->un_phyno)); | 683 | DPRINTF(("%s: phyno %d\n", device_xname(self), un->un_phyno)); | |
686 | 684 | |||
687 | /* Get station address. */ | 685 | /* Get station address. */ | |
688 | usbnet_lock_core(un); | 686 | usbnet_lock_core(un); | |
689 | usbnet_busy(un); | 687 | usbnet_busy(un); | |
690 | if (axen_get_eaddr(un, &un->un_eaddr)) { | 688 | if (axen_get_eaddr(un, &un->un_eaddr)) { | |
691 | usbnet_unbusy(un); | 689 | usbnet_unbusy(un); | |
692 | usbnet_unlock_core(un); | 690 | usbnet_unlock_core(un); | |
693 | printf("EEPROM checksum error\n"); | 691 | printf("EEPROM checksum error\n"); | |
694 | return; | 692 | return; | |
695 | } | 693 | } | |
696 | usbnet_unbusy(un); | 694 | usbnet_unbusy(un); | |
697 | usbnet_unlock_core(un); | 695 | usbnet_unlock_core(un); | |
698 | 696 | |||
699 | axen_ax88179_init(un); | 697 | axen_ax88179_init(un); | |
700 | 698 | |||
701 | /* An ASIX chip was detected. Inform the world. */ | 699 | /* An ASIX chip was detected. Inform the world. */ | |
702 | if (axen_flags & AX178A) | 700 | if (axen_flags & AX178A) | |
703 | aprint_normal_dev(self, "AX88178a\n"); | 701 | aprint_normal_dev(self, "AX88178a\n"); | |
704 | else if (axen_flags & AX179) | 702 | else if (axen_flags & AX179) | |
705 | aprint_normal_dev(self, "AX88179\n"); | 703 | aprint_normal_dev(self, "AX88179\n"); | |
706 | else | 704 | else | |
707 | aprint_normal_dev(self, "(unknown)\n"); | 705 | aprint_normal_dev(self, "(unknown)\n"); | |
708 | 706 | |||
709 | struct ethercom *ec = usbnet_ec(un); | 707 | struct ethercom *ec = usbnet_ec(un); | |
710 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | 708 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | |
711 | 709 | |||
712 | /* Adapter does not support TSOv6 (They call it LSOv2). */ | 710 | /* Adapter does not support TSOv6 (They call it LSOv2). */ | |
713 | struct ifnet *ifp = usbnet_ifp(un); | 711 | struct ifnet *ifp = usbnet_ifp(un); | |
714 | ifp->if_capabilities |= IFCAP_TSOv4 | | 712 | ifp->if_capabilities |= IFCAP_TSOv4 | | |
715 | IFCAP_CSUM_IPv4_Rx | IFCAP_CSUM_IPv4_Tx | | 713 | IFCAP_CSUM_IPv4_Rx | IFCAP_CSUM_IPv4_Tx | | |
716 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_TCPv4_Tx | | 714 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_TCPv4_Tx | | |
717 | IFCAP_CSUM_UDPv4_Rx | IFCAP_CSUM_UDPv4_Tx | | 715 | IFCAP_CSUM_UDPv4_Rx | IFCAP_CSUM_UDPv4_Tx | | |
718 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_TCPv6_Tx | | 716 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_TCPv6_Tx | | |
719 | IFCAP_CSUM_UDPv6_Rx | IFCAP_CSUM_UDPv6_Tx; | 717 | IFCAP_CSUM_UDPv6_Rx | IFCAP_CSUM_UDPv6_Tx; | |
720 | 718 | |||
721 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 719 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
722 | 0, &unm); | 720 | 0, &unm); | |
723 | } | 721 | } | |
724 | 722 | |||
725 | static int | 723 | static int | |
726 | axen_csum_flags_rx(struct ifnet *ifp, uint32_t pkt_hdr) | 724 | axen_csum_flags_rx(struct ifnet *ifp, uint32_t pkt_hdr) | |
727 | { | 725 | { | |
728 | int enabled_flags = ifp->if_csum_flags_rx; | 726 | int enabled_flags = ifp->if_csum_flags_rx; | |
729 | int csum_flags = 0; | 727 | int csum_flags = 0; | |
730 | int l3_type, l4_type; | 728 | int l3_type, l4_type; | |
731 | 729 | |||
732 | if (enabled_flags == 0) | 730 | if (enabled_flags == 0) | |
733 | return 0; | 731 | return 0; | |
734 | 732 | |||
735 | l3_type = (pkt_hdr & AXEN_RXHDR_L3_TYPE_MASK) >> | 733 | l3_type = (pkt_hdr & AXEN_RXHDR_L3_TYPE_MASK) >> | |
736 | AXEN_RXHDR_L3_TYPE_OFFSET; | 734 | AXEN_RXHDR_L3_TYPE_OFFSET; | |
737 | 735 | |||
738 | if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) | 736 | if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) | |
739 | csum_flags |= M_CSUM_IPv4; | 737 | csum_flags |= M_CSUM_IPv4; | |
740 | 738 | |||
741 | l4_type = (pkt_hdr & AXEN_RXHDR_L4_TYPE_MASK) >> | 739 | l4_type = (pkt_hdr & AXEN_RXHDR_L4_TYPE_MASK) >> | |
742 | AXEN_RXHDR_L4_TYPE_OFFSET; | 740 | AXEN_RXHDR_L4_TYPE_OFFSET; | |
743 | 741 | |||
744 | switch (l4_type) { | 742 | switch (l4_type) { | |
745 | case AXEN_RXHDR_L4_TYPE_TCP: | 743 | case AXEN_RXHDR_L4_TYPE_TCP: | |
746 | if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) | 744 | if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) | |
747 | csum_flags |= M_CSUM_TCPv4; | 745 | csum_flags |= M_CSUM_TCPv4; | |
748 | else | 746 | else | |
749 | csum_flags |= M_CSUM_TCPv6; | 747 | csum_flags |= M_CSUM_TCPv6; | |
750 | break; | 748 | break; | |
751 | case AXEN_RXHDR_L4_TYPE_UDP: | 749 | case AXEN_RXHDR_L4_TYPE_UDP: | |
752 | if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) | 750 | if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) | |
753 | csum_flags |= M_CSUM_UDPv4; | 751 | csum_flags |= M_CSUM_UDPv4; | |
754 | else | 752 | else | |
755 | csum_flags |= M_CSUM_UDPv6; | 753 | csum_flags |= M_CSUM_UDPv6; | |
756 | break; | 754 | break; | |
757 | default: | 755 | default: | |
758 | break; | 756 | break; | |
759 | } | 757 | } | |
760 | 758 | |||
761 | csum_flags &= enabled_flags; | 759 | csum_flags &= enabled_flags; | |
762 | if ((csum_flags & M_CSUM_IPv4) && (pkt_hdr & AXEN_RXHDR_L3CSUM_ERR)) | 760 | if ((csum_flags & M_CSUM_IPv4) && (pkt_hdr & AXEN_RXHDR_L3CSUM_ERR)) | |
763 | csum_flags |= M_CSUM_IPv4_BAD; | 761 | csum_flags |= M_CSUM_IPv4_BAD; | |
764 | if ((csum_flags & ~M_CSUM_IPv4) && (pkt_hdr & AXEN_RXHDR_L4CSUM_ERR)) | 762 | if ((csum_flags & ~M_CSUM_IPv4) && (pkt_hdr & AXEN_RXHDR_L4CSUM_ERR)) | |
765 | csum_flags |= M_CSUM_TCP_UDP_BAD; | 763 | csum_flags |= M_CSUM_TCP_UDP_BAD; | |
766 | 764 | |||
767 | return csum_flags; | 765 | return csum_flags; | |
768 | } | 766 | } | |
769 | 767 | |||
770 | static void | 768 | static void | |
771 | axen_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 769 | axen_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
772 | { | 770 | { | |
773 | struct ifnet *ifp = usbnet_ifp(un); | 771 | struct ifnet *ifp = usbnet_ifp(un); | |
774 | uint8_t *buf = c->unc_buf; | 772 | uint8_t *buf = c->unc_buf; | |
775 | uint32_t rx_hdr, pkt_hdr; | 773 | uint32_t rx_hdr, pkt_hdr; | |
776 | uint32_t *hdr_p; | 774 | uint32_t *hdr_p; | |
777 | uint16_t hdr_offset, pkt_count; | 775 | uint16_t hdr_offset, pkt_count; | |
778 | size_t pkt_len; | 776 | size_t pkt_len; | |
779 | size_t temp; | 777 | size_t temp; | |
780 | 778 | |||
781 | if (total_len < sizeof(pkt_hdr)) { | 779 | if (total_len < sizeof(pkt_hdr)) { | |
782 | aprint_error_dev(un->un_dev, "rxeof: too short transfer\n"); | 780 | aprint_error_dev(un->un_dev, "rxeof: too short transfer\n"); | |
783 | if_statinc(ifp, if_ierrors); | 781 | if_statinc(ifp, if_ierrors); | |
784 | return; | 782 | return; | |
785 | } | 783 | } | |
786 | 784 | |||
787 | /* | 785 | /* | |
788 | * buffer map | 786 | * buffer map | |
789 | * [packet #0]...[packet #n][pkt hdr#0]..[pkt hdr#n][recv_hdr] | 787 | * [packet #0]...[packet #n][pkt hdr#0]..[pkt hdr#n][recv_hdr] | |
790 | * each packet has 0xeeee as psuedo header.. | 788 | * each packet has 0xeeee as psuedo header.. | |
791 | */ | 789 | */ | |
792 | hdr_p = (uint32_t *)(buf + total_len - sizeof(uint32_t)); | 790 | hdr_p = (uint32_t *)(buf + total_len - sizeof(uint32_t)); | |
793 | rx_hdr = le32toh(*hdr_p); | 791 | rx_hdr = le32toh(*hdr_p); | |
794 | hdr_offset = (uint16_t)(rx_hdr >> 16); | 792 | hdr_offset = (uint16_t)(rx_hdr >> 16); | |
795 | pkt_count = (uint16_t)(rx_hdr & 0xffff); | 793 | pkt_count = (uint16_t)(rx_hdr & 0xffff); | |
796 | 794 | |||
797 | /* sanity check */ | 795 | /* sanity check */ | |
798 | if (hdr_offset > total_len) { | 796 | if (hdr_offset > total_len) { | |
799 | aprint_error_dev(un->un_dev, | 797 | aprint_error_dev(un->un_dev, | |
800 | "rxeof: invalid hdr offset (%u > %u)\n", | 798 | "rxeof: invalid hdr offset (%u > %u)\n", | |
801 | hdr_offset, total_len); | 799 | hdr_offset, total_len); | |
802 | if_statinc(ifp, if_ierrors); | 800 | if_statinc(ifp, if_ierrors); | |
803 | usbd_delay_ms(un->un_udev, 100); | 801 | usbd_delay_ms(un->un_udev, 100); | |
804 | return; | 802 | return; | |
805 | } | 803 | } | |
806 | 804 | |||
807 | /* point first packet header */ | 805 | /* point first packet header */ | |
808 | hdr_p = (uint32_t *)(buf + hdr_offset); | 806 | hdr_p = (uint32_t *)(buf + hdr_offset); | |
809 | 807 | |||
810 | /* | 808 | /* | |
811 | * ax88179 will pack multiple ip packet to a USB transaction. | 809 | * ax88179 will pack multiple ip packet to a USB transaction. | |
812 | * process all of packets in the buffer | 810 | * process all of packets in the buffer | |
813 | */ | 811 | */ | |
814 | 812 | |||
815 | #if 1 /* XXX: paranoiac check. need to remove later */ | 813 | #if 1 /* XXX: paranoiac check. need to remove later */ | |
816 | #define AXEN_MAX_PACKED_PACKET 200 | 814 | #define AXEN_MAX_PACKED_PACKET 200 | |
817 | if (pkt_count > AXEN_MAX_PACKED_PACKET) { | 815 | if (pkt_count > AXEN_MAX_PACKED_PACKET) { | |
818 | DPRINTF(("%s: Too many packets (%d) in a transaction, discard.\n", | 816 | DPRINTF(("%s: Too many packets (%d) in a transaction, discard.\n", | |
819 | device_xname(un->un_dev), pkt_count)); | 817 | device_xname(un->un_dev), pkt_count)); | |
820 | return; | 818 | return; | |
821 | } | 819 | } | |
822 | #endif | 820 | #endif | |
823 | 821 | |||
824 | if (pkt_count) | 822 | if (pkt_count) | |
825 | rnd_add_uint32(usbnet_rndsrc(un), pkt_count); | 823 | rnd_add_uint32(usbnet_rndsrc(un), pkt_count); | |
826 | 824 | |||
827 | do { | 825 | do { | |
828 | if ((buf[0] != 0xee) || (buf[1] != 0xee)) { | 826 | if ((buf[0] != 0xee) || (buf[1] != 0xee)) { | |
829 | aprint_error_dev(un->un_dev, | 827 | aprint_error_dev(un->un_dev, | |
830 | "invalid buffer(pkt#%d), continue\n", pkt_count); | 828 | "invalid buffer(pkt#%d), continue\n", pkt_count); | |
831 | if_statadd(ifp, if_ierrors, pkt_count); | 829 | if_statadd(ifp, if_ierrors, pkt_count); | |
832 | return; | 830 | return; | |
833 | } | 831 | } | |
834 | 832 | |||
835 | pkt_hdr = le32toh(*hdr_p); | 833 | pkt_hdr = le32toh(*hdr_p); | |
836 | pkt_len = (pkt_hdr >> 16) & 0x1fff; | 834 | pkt_len = (pkt_hdr >> 16) & 0x1fff; | |
837 | DPRINTFN(10, | 835 | DPRINTFN(10, | |
838 | ("%s: rxeof: packet#%d, pkt_hdr 0x%08x, pkt_len %zu\n", | 836 | ("%s: rxeof: packet#%d, pkt_hdr 0x%08x, pkt_len %zu\n", | |
839 | device_xname(un->un_dev), pkt_count, pkt_hdr, pkt_len)); | 837 | device_xname(un->un_dev), pkt_count, pkt_hdr, pkt_len)); | |
840 | 838 | |||
841 | if (pkt_hdr & (AXEN_RXHDR_CRC_ERR | AXEN_RXHDR_DROP_ERR)) { | 839 | if (pkt_hdr & (AXEN_RXHDR_CRC_ERR | AXEN_RXHDR_DROP_ERR)) { | |
842 | if_statinc(ifp, if_ierrors); | 840 | if_statinc(ifp, if_ierrors); | |
843 | /* move to next pkt header */ | 841 | /* move to next pkt header */ | |
844 | DPRINTF(("%s: %s err (pkt#%d)\n", | 842 | DPRINTF(("%s: %s err (pkt#%d)\n", | |
845 | device_xname(un->un_dev), | 843 | device_xname(un->un_dev), | |
846 | (pkt_hdr & AXEN_RXHDR_CRC_ERR) ? "crc" : "drop", | 844 | (pkt_hdr & AXEN_RXHDR_CRC_ERR) ? "crc" : "drop", | |
847 | pkt_count)); | 845 | pkt_count)); | |
848 | goto nextpkt; | 846 | goto nextpkt; | |
849 | } | 847 | } | |
850 | 848 | |||
851 | usbnet_enqueue(un, buf + ETHER_ALIGN, pkt_len - 6, | 849 | usbnet_enqueue(un, buf + ETHER_ALIGN, pkt_len - 6, | |
852 | axen_csum_flags_rx(ifp, pkt_hdr), 0, 0); | 850 | axen_csum_flags_rx(ifp, pkt_hdr), 0, 0); | |
853 | 851 | |||
854 | nextpkt: | 852 | nextpkt: | |
855 | /* | 853 | /* | |
856 | * prepare next packet | 854 | * prepare next packet | |
857 | * as each packet will be aligned 8byte boundary, | 855 | * as each packet will be aligned 8byte boundary, | |
858 | * need to fix up the start point of the buffer. | 856 | * need to fix up the start point of the buffer. | |
859 | */ | 857 | */ | |
860 | temp = ((pkt_len + 7) & 0xfff8); | 858 | temp = ((pkt_len + 7) & 0xfff8); | |
861 | buf = buf + temp; | 859 | buf = buf + temp; | |
862 | hdr_p++; | 860 | hdr_p++; | |
863 | pkt_count--; | 861 | pkt_count--; | |
864 | } while (pkt_count > 0); | 862 | } while (pkt_count > 0); | |
865 | } | 863 | } | |
866 | 864 | |||
867 | static unsigned | 865 | static unsigned | |
868 | axen_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 866 | axen_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
869 | { | 867 | { | |
870 | struct axen_sframe_hdr hdr; | 868 | struct axen_sframe_hdr hdr; | |
871 | u_int length, boundary; | 869 | u_int length, boundary; | |
872 | 870 | |||
873 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) | 871 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) | |
874 | return 0; | 872 | return 0; | |
875 | length = m->m_pkthdr.len + sizeof(hdr); | 873 | length = m->m_pkthdr.len + sizeof(hdr); | |
876 | 874 | |||
877 | /* XXX Is this needed? wMaxPacketSize? */ | 875 | /* XXX Is this needed? wMaxPacketSize? */ | |
878 | switch (un->un_udev->ud_speed) { | 876 | switch (un->un_udev->ud_speed) { | |
879 | case USB_SPEED_SUPER: | 877 | case USB_SPEED_SUPER: | |
880 | boundary = 4096; | 878 | boundary = 4096; | |
881 | break; | 879 | break; | |
882 | case USB_SPEED_HIGH: | 880 | case USB_SPEED_HIGH: | |
883 | boundary = 512; | 881 | boundary = 512; | |
884 | break; | 882 | break; | |
885 | default: | 883 | default: | |
886 | boundary = 64; | 884 | boundary = 64; | |
887 | break; | 885 | break; | |
888 | } | 886 | } | |
889 | 887 | |||
890 | hdr.plen = htole32(m->m_pkthdr.len); | 888 | hdr.plen = htole32(m->m_pkthdr.len); | |
891 | 889 | |||
892 | hdr.gso = (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) ? | 890 | hdr.gso = (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) ? | |
893 | m->m_pkthdr.segsz : 0; | 891 | m->m_pkthdr.segsz : 0; | |
894 | if ((length % boundary) == 0) { | 892 | if ((length % boundary) == 0) { | |
895 | DPRINTF(("%s: boundary hit\n", device_xname(un->un_dev))); | 893 | DPRINTF(("%s: boundary hit\n", device_xname(un->un_dev))); | |
896 | hdr.gso |= 0x80008000; /* XXX enable padding */ | 894 | hdr.gso |= 0x80008000; /* XXX enable padding */ | |
897 | } | 895 | } | |
898 | hdr.gso = htole32(hdr.gso); | 896 | hdr.gso = htole32(hdr.gso); | |
899 | 897 | |||
900 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); | 898 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); | |
901 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + sizeof(hdr)); | 899 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + sizeof(hdr)); | |
902 | 900 | |||
903 | return length; | 901 | return length; | |
904 | } | 902 | } | |
905 | 903 | |||
906 | static int | 904 | static int | |
907 | axen_init_locked(struct ifnet *ifp) | 905 | axen_init_locked(struct ifnet *ifp) | |
908 | { | 906 | { | |
909 | struct usbnet * const un = ifp->if_softc; | 907 | struct usbnet * const un = ifp->if_softc; | |
910 | uint16_t rxmode; | 908 | uint16_t rxmode; | |
911 | uint16_t wval; | 909 | uint16_t wval; | |
912 | uint8_t bval; | 910 | uint8_t bval; | |
913 | 911 | |||
914 | usbnet_isowned_core(un); | 912 | usbnet_isowned_core(un); | |
915 | 913 | |||
916 | if (usbnet_isdying(un)) | 914 | if (usbnet_isdying(un)) | |
917 | return EIO; | 915 | return EIO; | |
918 | 916 | |||
919 | /* Cancel pending I/O */ | 917 | /* Cancel pending I/O */ | |
920 | usbnet_stop(un, ifp, 1); | 918 | usbnet_stop(un, ifp, 1); | |
921 | 919 | |||
922 | /* Reset the ethernet interface. */ | 920 | /* Reset the ethernet interface. */ | |
923 | axen_reset(un); | 921 | axen_reset(un); | |
924 | 922 | |||
925 | /* XXX: ? */ | 923 | /* XXX: ? */ | |
926 | bval = 0x01; | 924 | bval = 0x01; | |
927 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_UNK_28, &bval); | 925 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_UNK_28, &bval); | |
928 | 926 | |||
929 | /* Configure offloading engine. */ | 927 | /* Configure offloading engine. */ | |
930 | axen_setoe_locked(un); | 928 | axen_setoe_locked(un); | |
931 | 929 | |||
932 | /* Program promiscuous mode and multicast filters. */ | 930 | /* Program promiscuous mode and multicast filters. */ | |
933 | axen_setiff_locked(un); | 931 | axen_setiff_locked(un); | |
934 | 932 | |||
935 | /* Enable receiver, set RX mode */ | 933 | /* Enable receiver, set RX mode */ | |
936 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); | 934 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); | |
937 | rxmode = le16toh(wval); | 935 | rxmode = le16toh(wval); | |
938 | rxmode |= AXEN_RXCTL_START; | 936 | rxmode |= AXEN_RXCTL_START; | |
939 | wval = htole16(rxmode); | 937 | wval = htole16(rxmode); | |
940 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | 938 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | |
941 | 939 | |||
942 | return usbnet_init_rx_tx(un); | 940 | return usbnet_init_rx_tx(un); | |
943 | } | 941 | } | |
944 | 942 | |||
945 | static int | 943 | static int | |
946 | axen_uno_init(struct ifnet *ifp) | 944 | axen_uno_init(struct ifnet *ifp) | |
947 | { | 945 | { | |
948 | int ret = axen_init_locked(ifp); | 946 | int ret = axen_init_locked(ifp); | |
949 | 947 | |||
950 | return ret; | 948 | return ret; | |
951 | } | 949 | } | |
952 | 950 | |||
953 | static void | 951 | static void | |
954 | axen_uno_stop(struct ifnet *ifp, int disable) | 952 | axen_uno_stop(struct ifnet *ifp, int disable) | |
955 | { | 953 | { | |
956 | struct usbnet * const un = ifp->if_softc; | 954 | struct usbnet * const un = ifp->if_softc; | |
957 | uint16_t rxmode, wval; | 955 | uint16_t rxmode, wval; | |
958 | 956 | |||
959 | axen_reset(un); | 957 | axen_reset(un); | |
960 | 958 | |||
961 | /* Disable receiver, set RX mode */ | 959 | /* Disable receiver, set RX mode */ | |
962 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); | 960 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); | |
963 | rxmode = le16toh(wval); | 961 | rxmode = le16toh(wval); | |
964 | rxmode &= ~AXEN_RXCTL_START; | 962 | rxmode &= ~AXEN_RXCTL_START; | |
965 | wval = htole16(rxmode); | 963 | wval = htole16(rxmode); | |
966 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | 964 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | |
967 | } | 965 | } | |
968 | 966 | |||
969 | #ifdef _MODULE | 967 | #ifdef _MODULE | |
970 | #include "ioconf.c" | 968 | #include "ioconf.c" | |
971 | #endif | 969 | #endif | |
972 | 970 | |||
973 | USBNET_MODULE(axen) | 971 | USBNET_MODULE(axen) |
--- src/sys/dev/usb/if_cue.c 2022/03/03 05:51:17 1.95
+++ src/sys/dev/usb/if_cue.c 2022/03/03 05:51:27 1.96
@@ -1,710 +1,708 @@ | @@ -1,710 +1,708 @@ | |||
1 | /* $NetBSD: if_cue.c,v 1.95 2022/03/03 05:51:17 riastradh Exp $ */ | 1 | /* $NetBSD: if_cue.c,v 1.96 2022/03/03 05:51:27 riastradh Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1997, 1998, 1999, 2000 | 4 | * Copyright (c) 1997, 1998, 1999, 2000 | |
5 | * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. | 5 | * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. All advertising materials mentioning features or use of this software | 15 | * 3. All advertising materials mentioning features or use of this software | |
16 | * must display the following acknowledgement: | 16 | * must display the following acknowledgement: | |
17 | * This product includes software developed by Bill Paul. | 17 | * This product includes software developed by Bill Paul. | |
18 | * 4. Neither the name of the author nor the names of any co-contributors | 18 | * 4. Neither the name of the author nor the names of any co-contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | |
26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
32 | * THE POSSIBILITY OF SUCH DAMAGE. | 32 | * THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | 33 | * | |
34 | * $FreeBSD: src/sys/dev/usb/if_cue.c,v 1.4 2000/01/16 22:45:06 wpaul Exp $ | 34 | * $FreeBSD: src/sys/dev/usb/if_cue.c,v 1.4 2000/01/16 22:45:06 wpaul Exp $ | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | /* | 37 | /* | |
38 | * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate | 38 | * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate | |
39 | * adapters and others. | 39 | * adapters and others. | |
40 | * | 40 | * | |
41 | * Written by Bill Paul <wpaul@ee.columbia.edu> | 41 | * Written by Bill Paul <wpaul@ee.columbia.edu> | |
42 | * Electrical Engineering Department | 42 | * Electrical Engineering Department | |
43 | * Columbia University, New York City | 43 | * Columbia University, New York City | |
44 | */ | 44 | */ | |
45 | 45 | |||
46 | /* | 46 | /* | |
47 | * The CATC USB-EL1210A provides USB ethernet support at 10Mbps. The | 47 | * The CATC USB-EL1210A provides USB ethernet support at 10Mbps. The | |
48 | * RX filter uses a 512-bit multicast hash table, single perfect entry | 48 | * RX filter uses a 512-bit multicast hash table, single perfect entry | |
49 | * for the station address, and promiscuous mode. Unlike the ADMtek | 49 | * for the station address, and promiscuous mode. Unlike the ADMtek | |
50 | * and KLSI chips, the CATC ASIC supports read and write combining | 50 | * and KLSI chips, the CATC ASIC supports read and write combining | |
51 | * mode where multiple packets can be transferred using a single bulk | 51 | * mode where multiple packets can be transferred using a single bulk | |
52 | * transaction, which helps performance a great deal. | 52 | * transaction, which helps performance a great deal. | |
53 | */ | 53 | */ | |
54 | 54 | |||
55 | /* | 55 | /* | |
56 | * Ported to NetBSD and somewhat rewritten by Lennart Augustsson. | 56 | * Ported to NetBSD and somewhat rewritten by Lennart Augustsson. | |
57 | */ | 57 | */ | |
58 | 58 | |||
59 | #include <sys/cdefs.h> | 59 | #include <sys/cdefs.h> | |
60 | __KERNEL_RCSID(0, "$NetBSD: if_cue.c,v 1.95 2022/03/03 05:51:17 riastradh Exp $"); | 60 | __KERNEL_RCSID(0, "$NetBSD: if_cue.c,v 1.96 2022/03/03 05:51:27 riastradh Exp $"); | |
61 | 61 | |||
62 | #ifdef _KERNEL_OPT | 62 | #ifdef _KERNEL_OPT | |
63 | #include "opt_inet.h" | 63 | #include "opt_inet.h" | |
64 | #include "opt_usb.h" | 64 | #include "opt_usb.h" | |
65 | #endif | 65 | #endif | |
66 | 66 | |||
67 | #include <sys/param.h> | 67 | #include <sys/param.h> | |
68 | 68 | |||
69 | #include <dev/usb/usbnet.h> | 69 | #include <dev/usb/usbnet.h> | |
70 | #include <dev/usb/if_cuereg.h> | 70 | #include <dev/usb/if_cuereg.h> | |
71 | 71 | |||
72 | #ifdef INET | 72 | #ifdef INET | |
73 | #include <netinet/in.h> | 73 | #include <netinet/in.h> | |
74 | #include <netinet/if_inarp.h> | 74 | #include <netinet/if_inarp.h> | |
75 | #endif | 75 | #endif | |
76 | 76 | |||
77 | #ifdef CUE_DEBUG | 77 | #ifdef CUE_DEBUG | |
78 | #define DPRINTF(x) if (cuedebug) printf x | 78 | #define DPRINTF(x) if (cuedebug) printf x | |
79 | #define DPRINTFN(n, x) if (cuedebug >= (n)) printf x | 79 | #define DPRINTFN(n, x) if (cuedebug >= (n)) printf x | |
80 | int cuedebug = 0; | 80 | int cuedebug = 0; | |
81 | #else | 81 | #else | |
82 | #define DPRINTF(x) | 82 | #define DPRINTF(x) | |
83 | #define DPRINTFN(n, x) | 83 | #define DPRINTFN(n, x) | |
84 | #endif | 84 | #endif | |
85 | 85 | |||
86 | #define CUE_BUFSZ 1536 | 86 | #define CUE_BUFSZ 1536 | |
87 | #define CUE_MIN_FRAMELEN 60 | 87 | #define CUE_MIN_FRAMELEN 60 | |
88 | #define CUE_RX_FRAMES 1 | 88 | #define CUE_RX_FRAMES 1 | |
89 | #define CUE_TX_FRAMES 1 | 89 | #define CUE_TX_FRAMES 1 | |
90 | 90 | |||
91 | #define CUE_CONFIG_NO 1 | 91 | #define CUE_CONFIG_NO 1 | |
92 | #define CUE_IFACE_IDX 0 | 92 | #define CUE_IFACE_IDX 0 | |
93 | 93 | |||
94 | #define CUE_RX_LIST_CNT 1 | 94 | #define CUE_RX_LIST_CNT 1 | |
95 | #define CUE_TX_LIST_CNT 1 | 95 | #define CUE_TX_LIST_CNT 1 | |
96 | 96 | |||
97 | struct cue_type { | 97 | struct cue_type { | |
98 | uint16_t cue_vid; | 98 | uint16_t cue_vid; | |
99 | uint16_t cue_did; | 99 | uint16_t cue_did; | |
100 | }; | 100 | }; | |
101 | 101 | |||
102 | struct cue_softc; | 102 | struct cue_softc; | |
103 | 103 | |||
104 | struct cue_chain { | 104 | struct cue_chain { | |
105 | struct cue_softc *cue_sc; | 105 | struct cue_softc *cue_sc; | |
106 | struct usbd_xfer *cue_xfer; | 106 | struct usbd_xfer *cue_xfer; | |
107 | char *cue_buf; | 107 | char *cue_buf; | |
108 | struct mbuf *cue_mbuf; | 108 | struct mbuf *cue_mbuf; | |
109 | int cue_idx; | 109 | int cue_idx; | |
110 | }; | 110 | }; | |
111 | 111 | |||
112 | struct cue_cdata { | 112 | struct cue_cdata { | |
113 | struct cue_chain cue_tx_chain[CUE_TX_LIST_CNT]; | 113 | struct cue_chain cue_tx_chain[CUE_TX_LIST_CNT]; | |
114 | struct cue_chain cue_rx_chain[CUE_RX_LIST_CNT]; | 114 | struct cue_chain cue_rx_chain[CUE_RX_LIST_CNT]; | |
115 | int cue_tx_prod; | 115 | int cue_tx_prod; | |
116 | int cue_tx_cnt; | 116 | int cue_tx_cnt; | |
117 | }; | 117 | }; | |
118 | 118 | |||
119 | struct cue_softc { | 119 | struct cue_softc { | |
120 | struct usbnet cue_un; | 120 | struct usbnet cue_un; | |
121 | uint8_t cue_mctab[CUE_MCAST_TABLE_LEN]; | 121 | uint8_t cue_mctab[CUE_MCAST_TABLE_LEN]; | |
122 | }; | 122 | }; | |
123 | 123 | |||
124 | /* | 124 | /* | |
125 | * Various supported device vendors/products. | 125 | * Various supported device vendors/products. | |
126 | */ | 126 | */ | |
127 | static const struct usb_devno cue_devs[] = { | 127 | static const struct usb_devno cue_devs[] = { | |
128 | { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE }, | 128 | { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE }, | |
129 | { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE2 }, | 129 | { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE2 }, | |
130 | { USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTLINK }, | 130 | { USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTLINK }, | |
131 | /* Belkin F5U111 adapter covered by NETMATE entry */ | 131 | /* Belkin F5U111 adapter covered by NETMATE entry */ | |
132 | }; | 132 | }; | |
133 | #define cue_lookup(v, p) (usb_lookup(cue_devs, v, p)) | 133 | #define cue_lookup(v, p) (usb_lookup(cue_devs, v, p)) | |
134 | 134 | |||
135 | static int cue_match(device_t, cfdata_t, void *); | 135 | static int cue_match(device_t, cfdata_t, void *); | |
136 | static void cue_attach(device_t, device_t, void *); | 136 | static void cue_attach(device_t, device_t, void *); | |
137 | 137 | |||
138 | CFATTACH_DECL_NEW(cue, sizeof(struct cue_softc), cue_match, cue_attach, | 138 | CFATTACH_DECL_NEW(cue, sizeof(struct cue_softc), cue_match, cue_attach, | |
139 | usbnet_detach, usbnet_activate); | 139 | usbnet_detach, usbnet_activate); | |
140 | 140 | |||
141 | static unsigned cue_uno_tx_prepare(struct usbnet *, struct mbuf *, | 141 | static unsigned cue_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
142 | struct usbnet_chain *); | 142 | struct usbnet_chain *); | |
143 | static void cue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 143 | static void cue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
144 | static void cue_uno_mcast(struct ifnet *); | 144 | static void cue_uno_mcast(struct ifnet *); | |
145 | static void cue_uno_stop(struct ifnet *, int); | 145 | static void cue_uno_stop(struct ifnet *, int); | |
146 | static int cue_uno_init(struct ifnet *); | 146 | static int cue_uno_init(struct ifnet *); | |
147 | static void cue_uno_tick(struct usbnet *); | 147 | static void cue_uno_tick(struct usbnet *); | |
148 | 148 | |||
149 | static const struct usbnet_ops cue_ops = { | 149 | static const struct usbnet_ops cue_ops = { | |
150 | .uno_stop = cue_uno_stop, | 150 | .uno_stop = cue_uno_stop, | |
151 | .uno_mcast = cue_uno_mcast, | 151 | .uno_mcast = cue_uno_mcast, | |
152 | .uno_tx_prepare = cue_uno_tx_prepare, | 152 | .uno_tx_prepare = cue_uno_tx_prepare, | |
153 | .uno_rx_loop = cue_uno_rx_loop, | 153 | .uno_rx_loop = cue_uno_rx_loop, | |
154 | .uno_init = cue_uno_init, | 154 | .uno_init = cue_uno_init, | |
155 | .uno_tick = cue_uno_tick, | 155 | .uno_tick = cue_uno_tick, | |
156 | }; | 156 | }; | |
157 | 157 | |||
158 | #ifdef CUE_DEBUG | 158 | #ifdef CUE_DEBUG | |
159 | static int | 159 | static int | |
160 | cue_csr_read_1(struct usbnet *un, int reg) | 160 | cue_csr_read_1(struct usbnet *un, int reg) | |
161 | { | 161 | { | |
162 | usb_device_request_t req; | 162 | usb_device_request_t req; | |
163 | usbd_status err; | 163 | usbd_status err; | |
164 | uint8_t val = 0; | 164 | uint8_t val = 0; | |
165 | 165 | |||
166 | if (usbnet_isdying(un)) | 166 | if (usbnet_isdying(un)) | |
167 | return 0; | 167 | return 0; | |
168 | 168 | |||
169 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 169 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
170 | req.bRequest = CUE_CMD_READREG; | 170 | req.bRequest = CUE_CMD_READREG; | |
171 | USETW(req.wValue, 0); | 171 | USETW(req.wValue, 0); | |
172 | USETW(req.wIndex, reg); | 172 | USETW(req.wIndex, reg); | |
173 | USETW(req.wLength, 1); | 173 | USETW(req.wLength, 1); | |
174 | 174 | |||
175 | err = usbd_do_request(un->un_udev, &req, &val); | 175 | err = usbd_do_request(un->un_udev, &req, &val); | |
176 | 176 | |||
177 | if (err) { | 177 | if (err) { | |
178 | DPRINTF(("%s: cue_csr_read_1: reg=%#x err=%s\n", | 178 | DPRINTF(("%s: cue_csr_read_1: reg=%#x err=%s\n", | |
179 | device_xname(un->un_dev), reg, usbd_errstr(err))); | 179 | device_xname(un->un_dev), reg, usbd_errstr(err))); | |
180 | return 0; | 180 | return 0; | |
181 | } | 181 | } | |
182 | 182 | |||
183 | DPRINTFN(10,("%s: cue_csr_read_1 reg=%#x val=%#x\n", | 183 | DPRINTFN(10,("%s: cue_csr_read_1 reg=%#x val=%#x\n", | |
184 | device_xname(un->un_dev), reg, val)); | 184 | device_xname(un->un_dev), reg, val)); | |
185 | 185 | |||
186 | return val; | 186 | return val; | |
187 | } | 187 | } | |
188 | #endif | 188 | #endif | |
189 | 189 | |||
190 | static int | 190 | static int | |
191 | cue_csr_read_2(struct usbnet *un, int reg) | 191 | cue_csr_read_2(struct usbnet *un, int reg) | |
192 | { | 192 | { | |
193 | usb_device_request_t req; | 193 | usb_device_request_t req; | |
194 | usbd_status err; | 194 | usbd_status err; | |
195 | uWord val; | 195 | uWord val; | |
196 | 196 | |||
197 | if (usbnet_isdying(un)) | 197 | if (usbnet_isdying(un)) | |
198 | return 0; | 198 | return 0; | |
199 | 199 | |||
200 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 200 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
201 | req.bRequest = CUE_CMD_READREG; | 201 | req.bRequest = CUE_CMD_READREG; | |
202 | USETW(req.wValue, 0); | 202 | USETW(req.wValue, 0); | |
203 | USETW(req.wIndex, reg); | 203 | USETW(req.wIndex, reg); | |
204 | USETW(req.wLength, 2); | 204 | USETW(req.wLength, 2); | |
205 | 205 | |||
206 | err = usbd_do_request(un->un_udev, &req, &val); | 206 | err = usbd_do_request(un->un_udev, &req, &val); | |
207 | 207 | |||
208 | DPRINTFN(10,("%s: cue_csr_read_2 reg=%#x val=%#x\n", | 208 | DPRINTFN(10,("%s: cue_csr_read_2 reg=%#x val=%#x\n", | |
209 | device_xname(un->un_dev), reg, UGETW(val))); | 209 | device_xname(un->un_dev), reg, UGETW(val))); | |
210 | 210 | |||
211 | if (err) { | 211 | if (err) { | |
212 | DPRINTF(("%s: cue_csr_read_2: reg=%#x err=%s\n", | 212 | DPRINTF(("%s: cue_csr_read_2: reg=%#x err=%s\n", | |
213 | device_xname(un->un_dev), reg, usbd_errstr(err))); | 213 | device_xname(un->un_dev), reg, usbd_errstr(err))); | |
214 | return 0; | 214 | return 0; | |
215 | } | 215 | } | |
216 | 216 | |||
217 | return UGETW(val); | 217 | return UGETW(val); | |
218 | } | 218 | } | |
219 | 219 | |||
220 | static int | 220 | static int | |
221 | cue_csr_write_1(struct usbnet *un, int reg, int val) | 221 | cue_csr_write_1(struct usbnet *un, int reg, int val) | |
222 | { | 222 | { | |
223 | usb_device_request_t req; | 223 | usb_device_request_t req; | |
224 | usbd_status err; | 224 | usbd_status err; | |
225 | 225 | |||
226 | if (usbnet_isdying(un)) | 226 | if (usbnet_isdying(un)) | |
227 | return 0; | 227 | return 0; | |
228 | 228 | |||
229 | DPRINTFN(10,("%s: cue_csr_write_1 reg=%#x val=%#x\n", | 229 | DPRINTFN(10,("%s: cue_csr_write_1 reg=%#x val=%#x\n", | |
230 | device_xname(un->un_dev), reg, val)); | 230 | device_xname(un->un_dev), reg, val)); | |
231 | 231 | |||
232 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 232 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
233 | req.bRequest = CUE_CMD_WRITEREG; | 233 | req.bRequest = CUE_CMD_WRITEREG; | |
234 | USETW(req.wValue, val); | 234 | USETW(req.wValue, val); | |
235 | USETW(req.wIndex, reg); | 235 | USETW(req.wIndex, reg); | |
236 | USETW(req.wLength, 0); | 236 | USETW(req.wLength, 0); | |
237 | 237 | |||
238 | err = usbd_do_request(un->un_udev, &req, NULL); | 238 | err = usbd_do_request(un->un_udev, &req, NULL); | |
239 | 239 | |||
240 | if (err) { | 240 | if (err) { | |
241 | DPRINTF(("%s: cue_csr_write_1: reg=%#x err=%s\n", | 241 | DPRINTF(("%s: cue_csr_write_1: reg=%#x err=%s\n", | |
242 | device_xname(un->un_dev), reg, usbd_errstr(err))); | 242 | device_xname(un->un_dev), reg, usbd_errstr(err))); | |
243 | return -1; | 243 | return -1; | |
244 | } | 244 | } | |
245 | 245 | |||
246 | DPRINTFN(20,("%s: cue_csr_write_1, after reg=%#x val=%#x\n", | 246 | DPRINTFN(20,("%s: cue_csr_write_1, after reg=%#x val=%#x\n", | |
247 | device_xname(un->un_dev), reg, cue_csr_read_1(un, reg))); | 247 | device_xname(un->un_dev), reg, cue_csr_read_1(un, reg))); | |
248 | 248 | |||
249 | return 0; | 249 | return 0; | |
250 | } | 250 | } | |
251 | 251 | |||
252 | #if 0 | 252 | #if 0 | |
253 | static int | 253 | static int | |
254 | cue_csr_write_2(struct usbnet *un, int reg, int aval) | 254 | cue_csr_write_2(struct usbnet *un, int reg, int aval) | |
255 | { | 255 | { | |
256 | usb_device_request_t req; | 256 | usb_device_request_t req; | |
257 | usbd_status err; | 257 | usbd_status err; | |
258 | uWord val; | 258 | uWord val; | |
259 | int s; | 259 | int s; | |
260 | 260 | |||
261 | if (usbnet_isdying(un)) | 261 | if (usbnet_isdying(un)) | |
262 | return 0; | 262 | return 0; | |
263 | 263 | |||
264 | DPRINTFN(10,("%s: cue_csr_write_2 reg=%#x val=%#x\n", | 264 | DPRINTFN(10,("%s: cue_csr_write_2 reg=%#x val=%#x\n", | |
265 | device_xname(un->un_dev), reg, aval)); | 265 | device_xname(un->un_dev), reg, aval)); | |
266 | 266 | |||
267 | USETW(val, aval); | 267 | USETW(val, aval); | |
268 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 268 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
269 | req.bRequest = CUE_CMD_WRITEREG; | 269 | req.bRequest = CUE_CMD_WRITEREG; | |
270 | USETW(req.wValue, val); | 270 | USETW(req.wValue, val); | |
271 | USETW(req.wIndex, reg); | 271 | USETW(req.wIndex, reg); | |
272 | USETW(req.wLength, 0); | 272 | USETW(req.wLength, 0); | |
273 | 273 | |||
274 | err = usbd_do_request(un->un_udev, &req, NULL); | 274 | err = usbd_do_request(un->un_udev, &req, NULL); | |
275 | 275 | |||
276 | if (err) { | 276 | if (err) { | |
277 | DPRINTF(("%s: cue_csr_write_2: reg=%#x err=%s\n", | 277 | DPRINTF(("%s: cue_csr_write_2: reg=%#x err=%s\n", | |
278 | device_xname(un->un_dev), reg, usbd_errstr(err))); | 278 | device_xname(un->un_dev), reg, usbd_errstr(err))); | |
279 | return -1; | 279 | return -1; | |
280 | } | 280 | } | |
281 | 281 | |||
282 | return 0; | 282 | return 0; | |
283 | } | 283 | } | |
284 | #endif | 284 | #endif | |
285 | 285 | |||
286 | static int | 286 | static int | |
287 | cue_mem(struct usbnet *un, int cmd, int addr, void *buf, int len) | 287 | cue_mem(struct usbnet *un, int cmd, int addr, void *buf, int len) | |
288 | { | 288 | { | |
289 | usb_device_request_t req; | 289 | usb_device_request_t req; | |
290 | usbd_status err; | 290 | usbd_status err; | |
291 | 291 | |||
292 | DPRINTFN(10,("%s: cue_mem cmd=%#x addr=%#x len=%d\n", | 292 | DPRINTFN(10,("%s: cue_mem cmd=%#x addr=%#x len=%d\n", | |
293 | device_xname(un->un_dev), cmd, addr, len)); | 293 | device_xname(un->un_dev), cmd, addr, len)); | |
294 | 294 | |||
295 | if (cmd == CUE_CMD_READSRAM) | 295 | if (cmd == CUE_CMD_READSRAM) | |
296 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 296 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
297 | else | 297 | else | |
298 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 298 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
299 | req.bRequest = cmd; | 299 | req.bRequest = cmd; | |
300 | USETW(req.wValue, 0); | 300 | USETW(req.wValue, 0); | |
301 | USETW(req.wIndex, addr); | 301 | USETW(req.wIndex, addr); | |
302 | USETW(req.wLength, len); | 302 | USETW(req.wLength, len); | |
303 | 303 | |||
304 | err = usbd_do_request(un->un_udev, &req, buf); | 304 | err = usbd_do_request(un->un_udev, &req, buf); | |
305 | 305 | |||
306 | if (err) { | 306 | if (err) { | |
307 | DPRINTF(("%s: cue_csr_mem: addr=%#x err=%s\n", | 307 | DPRINTF(("%s: cue_csr_mem: addr=%#x err=%s\n", | |
308 | device_xname(un->un_dev), addr, usbd_errstr(err))); | 308 | device_xname(un->un_dev), addr, usbd_errstr(err))); | |
309 | return -1; | 309 | return -1; | |
310 | } | 310 | } | |
311 | 311 | |||
312 | return 0; | 312 | return 0; | |
313 | } | 313 | } | |
314 | 314 | |||
315 | static int | 315 | static int | |
316 | cue_getmac(struct usbnet *un) | 316 | cue_getmac(struct usbnet *un) | |
317 | { | 317 | { | |
318 | usb_device_request_t req; | 318 | usb_device_request_t req; | |
319 | usbd_status err; | 319 | usbd_status err; | |
320 | 320 | |||
321 | DPRINTFN(10,("%s: cue_getmac\n", device_xname(un->un_dev))); | 321 | DPRINTFN(10,("%s: cue_getmac\n", device_xname(un->un_dev))); | |
322 | 322 | |||
323 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 323 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
324 | req.bRequest = CUE_CMD_GET_MACADDR; | 324 | req.bRequest = CUE_CMD_GET_MACADDR; | |
325 | USETW(req.wValue, 0); | 325 | USETW(req.wValue, 0); | |
326 | USETW(req.wIndex, 0); | 326 | USETW(req.wIndex, 0); | |
327 | USETW(req.wLength, ETHER_ADDR_LEN); | 327 | USETW(req.wLength, ETHER_ADDR_LEN); | |
328 | 328 | |||
329 | err = usbd_do_request(un->un_udev, &req, un->un_eaddr); | 329 | err = usbd_do_request(un->un_udev, &req, un->un_eaddr); | |
330 | 330 | |||
331 | if (err) { | 331 | if (err) { | |
332 | printf("%s: read MAC address failed\n", | 332 | printf("%s: read MAC address failed\n", | |
333 | device_xname(un->un_dev)); | 333 | device_xname(un->un_dev)); | |
334 | return -1; | 334 | return -1; | |
335 | } | 335 | } | |
336 | 336 | |||
337 | return 0; | 337 | return 0; | |
338 | } | 338 | } | |
339 | 339 | |||
340 | #define CUE_POLY 0xEDB88320 | 340 | #define CUE_POLY 0xEDB88320 | |
341 | #define CUE_BITS 9 | 341 | #define CUE_BITS 9 | |
342 | 342 | |||
343 | static uint32_t | 343 | static uint32_t | |
344 | cue_crc(const char *addr) | 344 | cue_crc(const char *addr) | |
345 | { | 345 | { | |
346 | uint32_t idx, bit, data, crc; | 346 | uint32_t idx, bit, data, crc; | |
347 | 347 | |||
348 | /* Compute CRC for the address value. */ | 348 | /* Compute CRC for the address value. */ | |
349 | crc = 0xFFFFFFFF; /* initial value */ | 349 | crc = 0xFFFFFFFF; /* initial value */ | |
350 | 350 | |||
351 | for (idx = 0; idx < 6; idx++) { | 351 | for (idx = 0; idx < 6; idx++) { | |
352 | for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) | 352 | for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) | |
353 | crc = (crc >> 1) ^ (((crc ^ data) & 1) ? CUE_POLY : 0); | 353 | crc = (crc >> 1) ^ (((crc ^ data) & 1) ? CUE_POLY : 0); | |
354 | } | 354 | } | |
355 | 355 | |||
356 | return crc & ((1 << CUE_BITS) - 1); | 356 | return crc & ((1 << CUE_BITS) - 1); | |
357 | } | 357 | } | |
358 | 358 | |||
359 | static void | 359 | static void | |
360 | cue_setiff_locked(struct usbnet *un) | 360 | cue_setiff_locked(struct usbnet *un) | |
361 | { | 361 | { | |
362 | struct cue_softc *sc = usbnet_softc(un); | 362 | struct cue_softc *sc = usbnet_softc(un); | |
363 | struct ethercom *ec = usbnet_ec(un); | 363 | struct ethercom *ec = usbnet_ec(un); | |
364 | struct ifnet *ifp = usbnet_ifp(un); | 364 | struct ifnet *ifp = usbnet_ifp(un); | |
365 | struct ether_multi *enm; | 365 | struct ether_multi *enm; | |
366 | struct ether_multistep step; | 366 | struct ether_multistep step; | |
367 | uint32_t h, i; | 367 | uint32_t h, i; | |
368 | 368 | |||
369 | DPRINTFN(2,("%s: cue_setiff if_flags=%#x\n", | 369 | DPRINTFN(2,("%s: cue_setiff if_flags=%#x\n", | |
370 | device_xname(un->un_dev), ifp->if_flags)); | 370 | device_xname(un->un_dev), ifp->if_flags)); | |
371 | 371 | |||
372 | if (ifp->if_flags & IFF_PROMISC) { | 372 | if (ifp->if_flags & IFF_PROMISC) { | |
373 | allmulti: | 373 | allmulti: | |
374 | ifp->if_flags |= IFF_ALLMULTI; | 374 | ifp->if_flags |= IFF_ALLMULTI; | |
375 | for (i = 0; i < CUE_MCAST_TABLE_LEN; i++) | 375 | for (i = 0; i < CUE_MCAST_TABLE_LEN; i++) | |
376 | sc->cue_mctab[i] = 0xFF; | 376 | sc->cue_mctab[i] = 0xFF; | |
377 | cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, | 377 | cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, | |
378 | &sc->cue_mctab, CUE_MCAST_TABLE_LEN); | 378 | &sc->cue_mctab, CUE_MCAST_TABLE_LEN); | |
379 | return; | 379 | return; | |
380 | } | 380 | } | |
381 | 381 | |||
382 | /* first, zot all the existing hash bits */ | 382 | /* first, zot all the existing hash bits */ | |
383 | for (i = 0; i < CUE_MCAST_TABLE_LEN; i++) | 383 | for (i = 0; i < CUE_MCAST_TABLE_LEN; i++) | |
384 | sc->cue_mctab[i] = 0; | 384 | sc->cue_mctab[i] = 0; | |
385 | 385 | |||
386 | /* now program new ones */ | 386 | /* now program new ones */ | |
387 | ETHER_LOCK(ec); | 387 | ETHER_LOCK(ec); | |
388 | ETHER_FIRST_MULTI(step, ec, enm); | 388 | ETHER_FIRST_MULTI(step, ec, enm); | |
389 | while (enm != NULL) { | 389 | while (enm != NULL) { | |
390 | if (memcmp(enm->enm_addrlo, | 390 | if (memcmp(enm->enm_addrlo, | |
391 | enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { | 391 | enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { | |
392 | ETHER_UNLOCK(ec); | 392 | ETHER_UNLOCK(ec); | |
393 | goto allmulti; | 393 | goto allmulti; | |
394 | } | 394 | } | |
395 | 395 | |||
396 | h = cue_crc(enm->enm_addrlo); | 396 | h = cue_crc(enm->enm_addrlo); | |
397 | sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); | 397 | sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); | |
398 | ETHER_NEXT_MULTI(step, enm); | 398 | ETHER_NEXT_MULTI(step, enm); | |
399 | } | 399 | } | |
400 | ETHER_UNLOCK(ec); | 400 | ETHER_UNLOCK(ec); | |
401 | 401 | |||
402 | ifp->if_flags &= ~IFF_ALLMULTI; | 402 | ifp->if_flags &= ~IFF_ALLMULTI; | |
403 | 403 | |||
404 | /* | 404 | /* | |
405 | * Also include the broadcast address in the filter | 405 | * Also include the broadcast address in the filter | |
406 | * so we can receive broadcast frames. | 406 | * so we can receive broadcast frames. | |
407 | */ | 407 | */ | |
408 | if (ifp->if_flags & IFF_BROADCAST) { | 408 | if (ifp->if_flags & IFF_BROADCAST) { | |
409 | h = cue_crc(etherbroadcastaddr); | 409 | h = cue_crc(etherbroadcastaddr); | |
410 | sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); | 410 | sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); | |
411 | } | 411 | } | |
412 | 412 | |||
413 | cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, | 413 | cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, | |
414 | &sc->cue_mctab, CUE_MCAST_TABLE_LEN); | 414 | &sc->cue_mctab, CUE_MCAST_TABLE_LEN); | |
415 | } | 415 | } | |
416 | 416 | |||
417 | static void | 417 | static void | |
418 | cue_reset(struct usbnet *un) | 418 | cue_reset(struct usbnet *un) | |
419 | { | 419 | { | |
420 | usb_device_request_t req; | 420 | usb_device_request_t req; | |
421 | usbd_status err; | 421 | usbd_status err; | |
422 | 422 | |||
423 | DPRINTFN(2,("%s: cue_reset\n", device_xname(un->un_dev))); | 423 | DPRINTFN(2,("%s: cue_reset\n", device_xname(un->un_dev))); | |
424 | 424 | |||
425 | if (usbnet_isdying(un)) | 425 | if (usbnet_isdying(un)) | |
426 | return; | 426 | return; | |
427 | 427 | |||
428 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 428 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
429 | req.bRequest = CUE_CMD_RESET; | 429 | req.bRequest = CUE_CMD_RESET; | |
430 | USETW(req.wValue, 0); | 430 | USETW(req.wValue, 0); | |
431 | USETW(req.wIndex, 0); | 431 | USETW(req.wIndex, 0); | |
432 | USETW(req.wLength, 0); | 432 | USETW(req.wLength, 0); | |
433 | 433 | |||
434 | err = usbd_do_request(un->un_udev, &req, NULL); | 434 | err = usbd_do_request(un->un_udev, &req, NULL); | |
435 | 435 | |||
436 | if (err) | 436 | if (err) | |
437 | printf("%s: reset failed\n", device_xname(un->un_dev)); | 437 | printf("%s: reset failed\n", device_xname(un->un_dev)); | |
438 | 438 | |||
439 | /* Wait a little while for the chip to get its brains in order. */ | 439 | /* Wait a little while for the chip to get its brains in order. */ | |
440 | usbd_delay_ms(un->un_udev, 1); | 440 | usbd_delay_ms(un->un_udev, 1); | |
441 | } | 441 | } | |
442 | 442 | |||
443 | /* | 443 | /* | |
444 | * Probe for a CATC chip. | 444 | * Probe for a CATC chip. | |
445 | */ | 445 | */ | |
446 | static int | 446 | static int | |
447 | cue_match(device_t parent, cfdata_t match, void *aux) | 447 | cue_match(device_t parent, cfdata_t match, void *aux) | |
448 | { | 448 | { | |
449 | struct usb_attach_arg *uaa = aux; | 449 | struct usb_attach_arg *uaa = aux; | |
450 | 450 | |||
451 | return cue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 451 | return cue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
452 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 452 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
453 | } | 453 | } | |
454 | 454 | |||
455 | /* | 455 | /* | |
456 | * Attach the interface. Allocate softc structures, do ifmedia | 456 | * Attach the interface. Allocate softc structures, do ifmedia | |
457 | * setup and ethernet/BPF attach. | 457 | * setup and ethernet/BPF attach. | |
458 | */ | 458 | */ | |
459 | static void | 459 | static void | |
460 | cue_attach(device_t parent, device_t self, void *aux) | 460 | cue_attach(device_t parent, device_t self, void *aux) | |
461 | { | 461 | { | |
462 | struct cue_softc *sc = device_private(self); | 462 | struct cue_softc *sc = device_private(self); | |
463 | struct usbnet * const un = &sc->cue_un; | 463 | struct usbnet * const un = &sc->cue_un; | |
464 | struct usb_attach_arg *uaa = aux; | 464 | struct usb_attach_arg *uaa = aux; | |
465 | char *devinfop; | 465 | char *devinfop; | |
466 | struct usbd_device * dev = uaa->uaa_device; | 466 | struct usbd_device * dev = uaa->uaa_device; | |
467 | usbd_status err; | 467 | usbd_status err; | |
468 | usb_interface_descriptor_t *id; | 468 | usb_interface_descriptor_t *id; | |
469 | usb_endpoint_descriptor_t *ed; | 469 | usb_endpoint_descriptor_t *ed; | |
470 | int i; | 470 | int i; | |
471 | 471 | |||
472 | KASSERT((void *)sc == un); | 472 | KASSERT((void *)sc == un); | |
473 | 473 | |||
474 | DPRINTFN(5,(" : cue_attach: sc=%p, dev=%p", sc, dev)); | 474 | DPRINTFN(5,(" : cue_attach: sc=%p, dev=%p", sc, dev)); | |
475 | 475 | |||
476 | aprint_naive("\n"); | 476 | aprint_naive("\n"); | |
477 | aprint_normal("\n"); | 477 | aprint_normal("\n"); | |
478 | devinfop = usbd_devinfo_alloc(dev, 0); | 478 | devinfop = usbd_devinfo_alloc(dev, 0); | |
479 | aprint_normal_dev(self, "%s\n", devinfop); | 479 | aprint_normal_dev(self, "%s\n", devinfop); | |
480 | usbd_devinfo_free(devinfop); | 480 | usbd_devinfo_free(devinfop); | |
481 | 481 | |||
482 | err = usbd_set_config_no(dev, CUE_CONFIG_NO, 1); | 482 | err = usbd_set_config_no(dev, CUE_CONFIG_NO, 1); | |
483 | if (err) { | 483 | if (err) { | |
484 | aprint_error_dev(self, "failed to set configuration" | 484 | aprint_error_dev(self, "failed to set configuration" | |
485 | ", err=%s\n", usbd_errstr(err)); | 485 | ", err=%s\n", usbd_errstr(err)); | |
486 | return; | 486 | return; | |
487 | } | 487 | } | |
488 | 488 | |||
489 | un->un_dev = self; | 489 | un->un_dev = self; | |
490 | un->un_udev = dev; | 490 | un->un_udev = dev; | |
491 | un->un_sc = sc; | 491 | un->un_sc = sc; | |
492 | un->un_ops = &cue_ops; | 492 | un->un_ops = &cue_ops; | |
493 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 493 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
494 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 494 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
495 | un->un_rx_list_cnt = CUE_RX_LIST_CNT; | 495 | un->un_rx_list_cnt = CUE_RX_LIST_CNT; | |
496 | un->un_tx_list_cnt = CUE_TX_LIST_CNT; | 496 | un->un_tx_list_cnt = CUE_TX_LIST_CNT; | |
497 | un->un_rx_bufsz = CUE_BUFSZ; | 497 | un->un_rx_bufsz = CUE_BUFSZ; | |
498 | un->un_tx_bufsz = CUE_BUFSZ; | 498 | un->un_tx_bufsz = CUE_BUFSZ; | |
499 | 499 | |||
500 | err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &un->un_iface); | 500 | err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &un->un_iface); | |
501 | if (err) { | 501 | if (err) { | |
502 | aprint_error_dev(self, "getting interface handle failed\n"); | 502 | aprint_error_dev(self, "getting interface handle failed\n"); | |
503 | return; | 503 | return; | |
504 | } | 504 | } | |
505 | 505 | |||
506 | id = usbd_get_interface_descriptor(un->un_iface); | 506 | id = usbd_get_interface_descriptor(un->un_iface); | |
507 | 507 | |||
508 | /* Find endpoints. */ | 508 | /* Find endpoints. */ | |
509 | for (i = 0; i < id->bNumEndpoints; i++) { | 509 | for (i = 0; i < id->bNumEndpoints; i++) { | |
510 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 510 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
511 | if (ed == NULL) { | 511 | if (ed == NULL) { | |
512 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 512 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
513 | return; | 513 | return; | |
514 | } | 514 | } | |
515 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 515 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
516 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 516 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
517 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 517 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
518 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 518 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
519 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 519 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
520 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 520 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
521 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 521 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
522 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 522 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
523 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 523 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
524 | } | 524 | } | |
525 | } | 525 | } | |
526 | 526 | |||
527 | /* First level attach. */ | 527 | /* First level attach. */ | |
528 | usbnet_attach(un, "cuedet"); | 528 | usbnet_attach(un, "cuedet"); | |
529 | 529 | |||
530 | #if 0 | 530 | #if 0 | |
531 | /* Reset the adapter. */ | 531 | /* Reset the adapter. */ | |
532 | cue_reset(un); | 532 | cue_reset(un); | |
533 | #endif | 533 | #endif | |
534 | /* | 534 | /* | |
535 | * Get station address. | 535 | * Get station address. | |
536 | */ | 536 | */ | |
537 | cue_getmac(un); | 537 | cue_getmac(un); | |
538 | 538 | |||
539 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 539 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
540 | 0, NULL); | 540 | 0, NULL); | |
541 | } | 541 | } | |
542 | 542 | |||
543 | static void | 543 | static void | |
544 | cue_uno_tick(struct usbnet *un) | 544 | cue_uno_tick(struct usbnet *un) | |
545 | { | 545 | { | |
546 | struct ifnet *ifp = usbnet_ifp(un); | 546 | struct ifnet *ifp = usbnet_ifp(un); | |
547 | 547 | |||
548 | usbnet_lock_core(un); | 548 | usbnet_lock_core(un); | |
549 | 549 | |||
550 | net_stat_ref_t nsr = IF_STAT_GETREF(ifp); | 550 | net_stat_ref_t nsr = IF_STAT_GETREF(ifp); | |
551 | if (cue_csr_read_2(un, CUE_RX_FRAMEERR)) | 551 | if (cue_csr_read_2(un, CUE_RX_FRAMEERR)) | |
552 | if_statinc_ref(nsr, if_ierrors); | 552 | if_statinc_ref(nsr, if_ierrors); | |
553 | 553 | |||
554 | if_statadd_ref(nsr, if_collisions, | 554 | if_statadd_ref(nsr, if_collisions, | |
555 | cue_csr_read_2(un, CUE_TX_SINGLECOLL)); | 555 | cue_csr_read_2(un, CUE_TX_SINGLECOLL)); | |
556 | if_statadd_ref(nsr, if_collisions, | 556 | if_statadd_ref(nsr, if_collisions, | |
557 | cue_csr_read_2(un, CUE_TX_MULTICOLL)); | 557 | cue_csr_read_2(un, CUE_TX_MULTICOLL)); | |
558 | if_statadd_ref(nsr, if_collisions, | 558 | if_statadd_ref(nsr, if_collisions, | |
559 | cue_csr_read_2(un, CUE_TX_EXCESSCOLL)); | 559 | cue_csr_read_2(un, CUE_TX_EXCESSCOLL)); | |
560 | IF_STAT_PUTREF(ifp); | 560 | IF_STAT_PUTREF(ifp); | |
561 | 561 | |||
562 | usbnet_unlock_core(un); | 562 | usbnet_unlock_core(un); | |
563 | } | 563 | } | |
564 | 564 | |||
565 | static void | 565 | static void | |
566 | cue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 566 | cue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
567 | { | 567 | { | |
568 | struct ifnet *ifp = usbnet_ifp(un); | 568 | struct ifnet *ifp = usbnet_ifp(un); | |
569 | uint8_t *buf = c->unc_buf; | 569 | uint8_t *buf = c->unc_buf; | |
570 | uint16_t len; | 570 | uint16_t len; | |
571 | 571 | |||
572 | DPRINTFN(5,("%s: %s: total_len=%d len=%d\n", | 572 | DPRINTFN(5,("%s: %s: total_len=%d len=%d\n", | |
573 | device_xname(un->un_dev), __func__, | 573 | device_xname(un->un_dev), __func__, | |
574 | total_len, le16dec(buf))); | 574 | total_len, le16dec(buf))); | |
575 | 575 | |||
576 | len = UGETW(buf); | 576 | len = UGETW(buf); | |
577 | if (total_len < 2 || | 577 | if (total_len < 2 || | |
578 | len > total_len - 2 || | 578 | len > total_len - 2 || | |
579 | len < sizeof(struct ether_header)) { | 579 | len < sizeof(struct ether_header)) { | |
580 | if_statinc(ifp, if_ierrors); | 580 | if_statinc(ifp, if_ierrors); | |
581 | return; | 581 | return; | |
582 | } | 582 | } | |
583 | 583 | |||
584 | /* No errors; receive the packet. */ | 584 | /* No errors; receive the packet. */ | |
585 | usbnet_enqueue(un, buf + 2, len, 0, 0, 0); | 585 | usbnet_enqueue(un, buf + 2, len, 0, 0, 0); | |
586 | } | 586 | } | |
587 | 587 | |||
588 | static unsigned | 588 | static unsigned | |
589 | cue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 589 | cue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
590 | { | 590 | { | |
591 | unsigned total_len; | 591 | unsigned total_len; | |
592 | 592 | |||
593 | DPRINTFN(5,("%s: %s: mbuf len=%d\n", | 593 | DPRINTFN(5,("%s: %s: mbuf len=%d\n", | |
594 | device_xname(un->un_dev), __func__, | 594 | device_xname(un->un_dev), __func__, | |
595 | m->m_pkthdr.len)); | 595 | m->m_pkthdr.len)); | |
596 | 596 | |||
597 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | 597 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | |
598 | return 0; | 598 | return 0; | |
599 | 599 | |||
600 | /* | 600 | /* | |
601 | * Copy the mbuf data into a contiguous buffer, leaving two | 601 | * Copy the mbuf data into a contiguous buffer, leaving two | |
602 | * bytes at the beginning to hold the frame length. | 602 | * bytes at the beginning to hold the frame length. | |
603 | */ | 603 | */ | |
604 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + 2); | 604 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + 2); | |
605 | 605 | |||
606 | total_len = m->m_pkthdr.len + 2; | 606 | total_len = m->m_pkthdr.len + 2; | |
607 | 607 | |||
608 | /* The first two bytes are the frame length */ | 608 | /* The first two bytes are the frame length */ | |
609 | c->unc_buf[0] = (uint8_t)m->m_pkthdr.len; | 609 | c->unc_buf[0] = (uint8_t)m->m_pkthdr.len; | |
610 | c->unc_buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); | 610 | c->unc_buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); | |
611 | 611 | |||
612 | return total_len; | 612 | return total_len; | |
613 | } | 613 | } | |
614 | 614 | |||
615 | static int | 615 | static int | |
616 | cue_init_locked(struct ifnet *ifp) | 616 | cue_init_locked(struct ifnet *ifp) | |
617 | { | 617 | { | |
618 | struct usbnet * const un = ifp->if_softc; | 618 | struct usbnet * const un = ifp->if_softc; | |
619 | int i, ctl; | 619 | int i, ctl; | |
620 | const u_char *eaddr; | 620 | const u_char *eaddr; | |
621 | 621 | |||
622 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | 622 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | |
623 | 623 | |||
624 | if (usbnet_isdying(un)) | 624 | if (usbnet_isdying(un)) | |
625 | return ENXIO; | 625 | return ENXIO; | |
626 | 626 | |||
627 | /* Cancel pending I/O */ | 627 | /* Cancel pending I/O */ | |
628 | usbnet_stop(un, ifp, 1); | 628 | usbnet_stop(un, ifp, 1); | |
629 | 629 | |||
630 | /* Reset the interface. */ | 630 | /* Reset the interface. */ | |
631 | #if 1 | 631 | #if 1 | |
632 | cue_reset(un); | 632 | cue_reset(un); | |
633 | #endif | 633 | #endif | |
634 | 634 | |||
635 | /* Set advanced operation modes. */ | 635 | /* Set advanced operation modes. */ | |
636 | cue_csr_write_1(un, CUE_ADVANCED_OPMODES, | 636 | cue_csr_write_1(un, CUE_ADVANCED_OPMODES, | |
637 | CUE_AOP_EMBED_RXLEN | 0x03); /* 1 wait state */ | 637 | CUE_AOP_EMBED_RXLEN | 0x03); /* 1 wait state */ | |
638 | 638 | |||
639 | eaddr = CLLADDR(ifp->if_sadl); | 639 | eaddr = CLLADDR(ifp->if_sadl); | |
640 | /* Set MAC address */ | 640 | /* Set MAC address */ | |
641 | for (i = 0; i < ETHER_ADDR_LEN; i++) | 641 | for (i = 0; i < ETHER_ADDR_LEN; i++) | |
642 | cue_csr_write_1(un, CUE_PAR0 - i, eaddr[i]); | 642 | cue_csr_write_1(un, CUE_PAR0 - i, eaddr[i]); | |
643 | 643 | |||
644 | /* Enable RX logic. */ | 644 | /* Enable RX logic. */ | |
645 | ctl = CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON; | 645 | ctl = CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON; | |
646 | if (ifp->if_flags & IFF_PROMISC) | 646 | if (ifp->if_flags & IFF_PROMISC) | |
647 | ctl |= CUE_ETHCTL_PROMISC; | 647 | ctl |= CUE_ETHCTL_PROMISC; | |
648 | cue_csr_write_1(un, CUE_ETHCTL, ctl); | 648 | cue_csr_write_1(un, CUE_ETHCTL, ctl); | |
649 | 649 | |||
650 | /* Load the multicast filter. */ | 650 | /* Load the multicast filter. */ | |
651 | cue_setiff_locked(un); | 651 | cue_setiff_locked(un); | |
652 | 652 | |||
653 | /* | 653 | /* | |
654 | * Set the number of RX and TX buffers that we want | 654 | * Set the number of RX and TX buffers that we want | |
655 | * to reserve inside the ASIC. | 655 | * to reserve inside the ASIC. | |
656 | */ | 656 | */ | |
657 | cue_csr_write_1(un, CUE_RX_BUFPKTS, CUE_RX_FRAMES); | 657 | cue_csr_write_1(un, CUE_RX_BUFPKTS, CUE_RX_FRAMES); | |
658 | cue_csr_write_1(un, CUE_TX_BUFPKTS, CUE_TX_FRAMES); | 658 | cue_csr_write_1(un, CUE_TX_BUFPKTS, CUE_TX_FRAMES); | |
659 | 659 | |||
660 | /* Set advanced operation modes. */ | 660 | /* Set advanced operation modes. */ | |
661 | cue_csr_write_1(un, CUE_ADVANCED_OPMODES, | 661 | cue_csr_write_1(un, CUE_ADVANCED_OPMODES, | |
662 | CUE_AOP_EMBED_RXLEN | 0x01); /* 1 wait state */ | 662 | CUE_AOP_EMBED_RXLEN | 0x01); /* 1 wait state */ | |
663 | 663 | |||
664 | /* Program the LED operation. */ | 664 | /* Program the LED operation. */ | |
665 | cue_csr_write_1(un, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK); | 665 | cue_csr_write_1(un, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK); | |
666 | 666 | |||
667 | return usbnet_init_rx_tx(un); | 667 | return usbnet_init_rx_tx(un); | |
668 | } | 668 | } | |
669 | 669 | |||
670 | static int | 670 | static int | |
671 | cue_uno_init(struct ifnet *ifp) | 671 | cue_uno_init(struct ifnet *ifp) | |
672 | { | 672 | { | |
673 | int rv; | 673 | int rv; | |
674 | 674 | |||
675 | rv = cue_init_locked(ifp); | 675 | rv = cue_init_locked(ifp); | |
676 | 676 | |||
677 | return rv; | 677 | return rv; | |
678 | } | 678 | } | |
679 | 679 | |||
680 | static void | 680 | static void | |
681 | cue_uno_mcast(struct ifnet *ifp) | 681 | cue_uno_mcast(struct ifnet *ifp) | |
682 | { | 682 | { | |
683 | struct usbnet * const un = ifp->if_softc; | 683 | struct usbnet * const un = ifp->if_softc; | |
684 | 684 | |||
685 | usbnet_lock_core(un); | 685 | usbnet_lock_core(un); | |
686 | usbnet_busy(un); | |||
687 | 686 | |||
688 | cue_setiff_locked(un); | 687 | cue_setiff_locked(un); | |
689 | 688 | |||
690 | usbnet_unbusy(un); | |||
691 | usbnet_unlock_core(un); | 689 | usbnet_unlock_core(un); | |
692 | } | 690 | } | |
693 | 691 | |||
694 | /* Stop and reset the adapter. */ | 692 | /* Stop and reset the adapter. */ | |
695 | static void | 693 | static void | |
696 | cue_uno_stop(struct ifnet *ifp, int disable) | 694 | cue_uno_stop(struct ifnet *ifp, int disable) | |
697 | { | 695 | { | |
698 | struct usbnet * const un = ifp->if_softc; | 696 | struct usbnet * const un = ifp->if_softc; | |
699 | 697 | |||
700 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 698 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
701 | 699 | |||
702 | cue_csr_write_1(un, CUE_ETHCTL, 0); | 700 | cue_csr_write_1(un, CUE_ETHCTL, 0); | |
703 | cue_reset(un); | 701 | cue_reset(un); | |
704 | } | 702 | } | |
705 | 703 | |||
706 | #ifdef _MODULE | 704 | #ifdef _MODULE | |
707 | #include "ioconf.c" | 705 | #include "ioconf.c" | |
708 | #endif | 706 | #endif | |
709 | 707 | |||
710 | USBNET_MODULE(cue) | 708 | USBNET_MODULE(cue) |
--- src/sys/dev/usb/if_kue.c 2022/03/03 05:51:17 1.108
+++ src/sys/dev/usb/if_kue.c 2022/03/03 05:51:27 1.109
@@ -1,658 +1,656 @@ | @@ -1,658 +1,656 @@ | |||
1 | /* $NetBSD: if_kue.c,v 1.108 2022/03/03 05:51:17 riastradh Exp $ */ | 1 | /* $NetBSD: if_kue.c,v 1.109 2022/03/03 05:51:27 riastradh Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1997, 1998, 1999, 2000 | 4 | * Copyright (c) 1997, 1998, 1999, 2000 | |
5 | * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. | 5 | * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. All advertising materials mentioning features or use of this software | 15 | * 3. All advertising materials mentioning features or use of this software | |
16 | * must display the following acknowledgement: | 16 | * must display the following acknowledgement: | |
17 | * This product includes software developed by Bill Paul. | 17 | * This product includes software developed by Bill Paul. | |
18 | * 4. Neither the name of the author nor the names of any co-contributors | 18 | * 4. Neither the name of the author nor the names of any co-contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | |
26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
32 | * THE POSSIBILITY OF SUCH DAMAGE. | 32 | * THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | 33 | * | |
34 | * $FreeBSD: src/sys/dev/usb/if_kue.c,v 1.14 2000/01/14 01:36:15 wpaul Exp $ | 34 | * $FreeBSD: src/sys/dev/usb/if_kue.c,v 1.14 2000/01/14 01:36:15 wpaul Exp $ | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | /* | 37 | /* | |
38 | * Kawasaki LSI KL5KUSB101B USB to ethernet adapter driver. | 38 | * Kawasaki LSI KL5KUSB101B USB to ethernet adapter driver. | |
39 | * | 39 | * | |
40 | * Written by Bill Paul <wpaul@ee.columbia.edu> | 40 | * Written by Bill Paul <wpaul@ee.columbia.edu> | |
41 | * Electrical Engineering Department | 41 | * Electrical Engineering Department | |
42 | * Columbia University, New York City | 42 | * Columbia University, New York City | |
43 | */ | 43 | */ | |
44 | 44 | |||
45 | /* | 45 | /* | |
46 | * The KLSI USB to ethernet adapter chip contains an USB serial interface, | 46 | * The KLSI USB to ethernet adapter chip contains an USB serial interface, | |
47 | * ethernet MAC and embedded microcontroller (called the QT Engine). | 47 | * ethernet MAC and embedded microcontroller (called the QT Engine). | |
48 | * The chip must have firmware loaded into it before it will operate. | 48 | * The chip must have firmware loaded into it before it will operate. | |
49 | * Packets are passed between the chip and host via bulk transfers. | 49 | * Packets are passed between the chip and host via bulk transfers. | |
50 | * There is an interrupt endpoint mentioned in the software spec, however | 50 | * There is an interrupt endpoint mentioned in the software spec, however | |
51 | * it's currently unused. This device is 10Mbps half-duplex only, hence | 51 | * it's currently unused. This device is 10Mbps half-duplex only, hence | |
52 | * there is no media selection logic. The MAC supports a 128 entry | 52 | * there is no media selection logic. The MAC supports a 128 entry | |
53 | * multicast filter, though the exact size of the filter can depend | 53 | * multicast filter, though the exact size of the filter can depend | |
54 | * on the firmware. Curiously, while the software spec describes various | 54 | * on the firmware. Curiously, while the software spec describes various | |
55 | * ethernet statistics counters, my sample adapter and firmware combination | 55 | * ethernet statistics counters, my sample adapter and firmware combination | |
56 | * claims not to support any statistics counters at all. | 56 | * claims not to support any statistics counters at all. | |
57 | * | 57 | * | |
58 | * Note that once we load the firmware in the device, we have to be | 58 | * Note that once we load the firmware in the device, we have to be | |
59 | * careful not to load it again: if you restart your computer but | 59 | * careful not to load it again: if you restart your computer but | |
60 | * leave the adapter attached to the USB controller, it may remain | 60 | * leave the adapter attached to the USB controller, it may remain | |
61 | * powered on and retain its firmware. In this case, we don't need | 61 | * powered on and retain its firmware. In this case, we don't need | |
62 | * to load the firmware a second time. | 62 | * to load the firmware a second time. | |
63 | * | 63 | * | |
64 | * Special thanks to Rob Furr for providing an ADS Technologies | 64 | * Special thanks to Rob Furr for providing an ADS Technologies | |
65 | * adapter for development and testing. No monkeys were harmed during | 65 | * adapter for development and testing. No monkeys were harmed during | |
66 | * the development of this driver. | 66 | * the development of this driver. | |
67 | */ | 67 | */ | |
68 | 68 | |||
69 | /* | 69 | /* | |
70 | * Ported to NetBSD and somewhat rewritten by Lennart Augustsson. | 70 | * Ported to NetBSD and somewhat rewritten by Lennart Augustsson. | |
71 | */ | 71 | */ | |
72 | 72 | |||
73 | #include <sys/cdefs.h> | 73 | #include <sys/cdefs.h> | |
74 | __KERNEL_RCSID(0, "$NetBSD: if_kue.c,v 1.108 2022/03/03 05:51:17 riastradh Exp $"); | 74 | __KERNEL_RCSID(0, "$NetBSD: if_kue.c,v 1.109 2022/03/03 05:51:27 riastradh Exp $"); | |
75 | 75 | |||
76 | #ifdef _KERNEL_OPT | 76 | #ifdef _KERNEL_OPT | |
77 | #include "opt_inet.h" | 77 | #include "opt_inet.h" | |
78 | #include "opt_usb.h" | 78 | #include "opt_usb.h" | |
79 | #endif | 79 | #endif | |
80 | 80 | |||
81 | #include <sys/param.h> | 81 | #include <sys/param.h> | |
82 | #include <sys/kmem.h> | 82 | #include <sys/kmem.h> | |
83 | 83 | |||
84 | #include <dev/usb/usbnet.h> | 84 | #include <dev/usb/usbnet.h> | |
85 | 85 | |||
86 | #ifdef INET | 86 | #ifdef INET | |
87 | #include <netinet/in.h> | 87 | #include <netinet/in.h> | |
88 | #include <netinet/if_inarp.h> | 88 | #include <netinet/if_inarp.h> | |
89 | #endif | 89 | #endif | |
90 | 90 | |||
91 | #include <dev/usb/if_kuereg.h> | 91 | #include <dev/usb/if_kuereg.h> | |
92 | #include <dev/usb/kue_fw.h> | 92 | #include <dev/usb/kue_fw.h> | |
93 | 93 | |||
94 | #ifdef KUE_DEBUG | 94 | #ifdef KUE_DEBUG | |
95 | #define DPRINTF(x) if (kuedebug) printf x | 95 | #define DPRINTF(x) if (kuedebug) printf x | |
96 | #define DPRINTFN(n, x) if (kuedebug >= (n)) printf x | 96 | #define DPRINTFN(n, x) if (kuedebug >= (n)) printf x | |
97 | int kuedebug = 0; | 97 | int kuedebug = 0; | |
98 | #else | 98 | #else | |
99 | #define DPRINTF(x) | 99 | #define DPRINTF(x) | |
100 | #define DPRINTFN(n, x) | 100 | #define DPRINTFN(n, x) | |
101 | #endif | 101 | #endif | |
102 | 102 | |||
103 | struct kue_type { | 103 | struct kue_type { | |
104 | uint16_t kue_vid; | 104 | uint16_t kue_vid; | |
105 | uint16_t kue_did; | 105 | uint16_t kue_did; | |
106 | }; | 106 | }; | |
107 | 107 | |||
108 | struct kue_softc { | 108 | struct kue_softc { | |
109 | struct usbnet kue_un; | 109 | struct usbnet kue_un; | |
110 | 110 | |||
111 | struct kue_ether_desc kue_desc; | 111 | struct kue_ether_desc kue_desc; | |
112 | uint16_t kue_rxfilt; | 112 | uint16_t kue_rxfilt; | |
113 | uint8_t *kue_mcfilters; | 113 | uint8_t *kue_mcfilters; | |
114 | }; | 114 | }; | |
115 | 115 | |||
116 | #define KUE_MCFILT(x, y) \ | 116 | #define KUE_MCFILT(x, y) \ | |
117 | (uint8_t *)&(sc->kue_mcfilters[y * ETHER_ADDR_LEN]) | 117 | (uint8_t *)&(sc->kue_mcfilters[y * ETHER_ADDR_LEN]) | |
118 | 118 | |||
119 | #define KUE_BUFSZ 1536 | 119 | #define KUE_BUFSZ 1536 | |
120 | #define KUE_MIN_FRAMELEN 60 | 120 | #define KUE_MIN_FRAMELEN 60 | |
121 | 121 | |||
122 | #define KUE_RX_LIST_CNT 1 | 122 | #define KUE_RX_LIST_CNT 1 | |
123 | #define KUE_TX_LIST_CNT 1 | 123 | #define KUE_TX_LIST_CNT 1 | |
124 | 124 | |||
125 | /* | 125 | /* | |
126 | * Various supported device vendors/products. | 126 | * Various supported device vendors/products. | |
127 | */ | 127 | */ | |
128 | static const struct usb_devno kue_devs[] = { | 128 | static const struct usb_devno kue_devs[] = { | |
129 | { USB_VENDOR_3COM, USB_PRODUCT_3COM_3C19250 }, | 129 | { USB_VENDOR_3COM, USB_PRODUCT_3COM_3C19250 }, | |
130 | { USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460 }, | 130 | { USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460 }, | |
131 | { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_URE450 }, | 131 | { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_URE450 }, | |
132 | { USB_VENDOR_ADS, USB_PRODUCT_ADS_UBS10BT }, | 132 | { USB_VENDOR_ADS, USB_PRODUCT_ADS_UBS10BT }, | |
133 | { USB_VENDOR_ADS, USB_PRODUCT_ADS_UBS10BTX }, | 133 | { USB_VENDOR_ADS, USB_PRODUCT_ADS_UBS10BTX }, | |
134 | { USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_AR9287 }, | 134 | { USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_AR9287 }, | |
135 | { USB_VENDOR_ALLIEDTELESYN, USB_PRODUCT_ALLIEDTELESYN_AT_USB10 }, | 135 | { USB_VENDOR_ALLIEDTELESYN, USB_PRODUCT_ALLIEDTELESYN_AT_USB10 }, | |
136 | { USB_VENDOR_AOX, USB_PRODUCT_AOX_USB101 }, | 136 | { USB_VENDOR_AOX, USB_PRODUCT_AOX_USB101 }, | |
137 | { USB_VENDOR_ASANTE, USB_PRODUCT_ASANTE_EA }, | 137 | { USB_VENDOR_ASANTE, USB_PRODUCT_ASANTE_EA }, | |
138 | { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC10T }, | 138 | { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC10T }, | |
139 | { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_DSB650C }, | 139 | { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_DSB650C }, | |
140 | { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_ETHER_USB_T }, | 140 | { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_ETHER_USB_T }, | |
141 | { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650C }, | 141 | { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650C }, | |
142 | { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_E45 }, | 142 | { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_E45 }, | |
143 | { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_XX1 }, | 143 | { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_XX1 }, | |
144 | { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_XX2 }, | 144 | { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_XX2 }, | |
145 | { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETT }, | 145 | { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETT }, | |
146 | { USB_VENDOR_JATON, USB_PRODUCT_JATON_EDA }, | 146 | { USB_VENDOR_JATON, USB_PRODUCT_JATON_EDA }, | |
147 | { USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_XX1 }, | 147 | { USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_XX1 }, | |
148 | { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BT }, | 148 | { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BT }, | |
149 | { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BTN }, | 149 | { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BTN }, | |
150 | { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T }, | 150 | { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T }, | |
151 | { USB_VENDOR_MOBILITY, USB_PRODUCT_MOBILITY_EA }, | 151 | { USB_VENDOR_MOBILITY, USB_PRODUCT_MOBILITY_EA }, | |
152 | { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_EA101 }, | 152 | { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_EA101 }, | |
153 | { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_EA101X }, | 153 | { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_EA101X }, | |
154 | { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET }, | 154 | { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET }, | |
155 | { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET2 }, | 155 | { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET2 }, | |
156 | { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET3 }, | 156 | { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET3 }, | |
157 | { USB_VENDOR_PORTGEAR, USB_PRODUCT_PORTGEAR_EA8 }, | 157 | { USB_VENDOR_PORTGEAR, USB_PRODUCT_PORTGEAR_EA8 }, | |
158 | { USB_VENDOR_PORTGEAR, USB_PRODUCT_PORTGEAR_EA9 }, | 158 | { USB_VENDOR_PORTGEAR, USB_PRODUCT_PORTGEAR_EA9 }, | |
159 | { USB_VENDOR_PORTSMITH, USB_PRODUCT_PORTSMITH_EEA }, | 159 | { USB_VENDOR_PORTSMITH, USB_PRODUCT_PORTSMITH_EEA }, | |
160 | { USB_VENDOR_SHARK, USB_PRODUCT_SHARK_PA }, | 160 | { USB_VENDOR_SHARK, USB_PRODUCT_SHARK_PA }, | |
161 | { USB_VENDOR_SILICOM, USB_PRODUCT_SILICOM_U2E }, | 161 | { USB_VENDOR_SILICOM, USB_PRODUCT_SILICOM_U2E }, | |
162 | { USB_VENDOR_SILICOM, USB_PRODUCT_SILICOM_GPE }, | 162 | { USB_VENDOR_SILICOM, USB_PRODUCT_SILICOM_GPE }, | |
163 | { USB_VENDOR_SMC, USB_PRODUCT_SMC_2102USB }, | 163 | { USB_VENDOR_SMC, USB_PRODUCT_SMC_2102USB }, | |
164 | }; | 164 | }; | |
165 | #define kue_lookup(v, p) (usb_lookup(kue_devs, v, p)) | 165 | #define kue_lookup(v, p) (usb_lookup(kue_devs, v, p)) | |
166 | 166 | |||
167 | static int kue_match(device_t, cfdata_t, void *); | 167 | static int kue_match(device_t, cfdata_t, void *); | |
168 | static void kue_attach(device_t, device_t, void *); | 168 | static void kue_attach(device_t, device_t, void *); | |
169 | static int kue_detach(device_t, int); | 169 | static int kue_detach(device_t, int); | |
170 | 170 | |||
171 | CFATTACH_DECL_NEW(kue, sizeof(struct kue_softc), kue_match, kue_attach, | 171 | CFATTACH_DECL_NEW(kue, sizeof(struct kue_softc), kue_match, kue_attach, | |
172 | kue_detach, usbnet_activate); | 172 | kue_detach, usbnet_activate); | |
173 | 173 | |||
174 | static void kue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 174 | static void kue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
175 | static unsigned kue_uno_tx_prepare(struct usbnet *, struct mbuf *, | 175 | static unsigned kue_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
176 | struct usbnet_chain *); | 176 | struct usbnet_chain *); | |
177 | static void kue_uno_mcast(struct ifnet *); | 177 | static void kue_uno_mcast(struct ifnet *); | |
178 | static int kue_uno_init(struct ifnet *); | 178 | static int kue_uno_init(struct ifnet *); | |
179 | 179 | |||
180 | static const struct usbnet_ops kue_ops = { | 180 | static const struct usbnet_ops kue_ops = { | |
181 | .uno_mcast = kue_uno_mcast, | 181 | .uno_mcast = kue_uno_mcast, | |
182 | .uno_tx_prepare = kue_uno_tx_prepare, | 182 | .uno_tx_prepare = kue_uno_tx_prepare, | |
183 | .uno_rx_loop = kue_uno_rx_loop, | 183 | .uno_rx_loop = kue_uno_rx_loop, | |
184 | .uno_init = kue_uno_init, | 184 | .uno_init = kue_uno_init, | |
185 | }; | 185 | }; | |
186 | 186 | |||
187 | static void kue_reset(struct usbnet *); | 187 | static void kue_reset(struct usbnet *); | |
188 | 188 | |||
189 | static usbd_status kue_ctl(struct usbnet *, int, uint8_t, | 189 | static usbd_status kue_ctl(struct usbnet *, int, uint8_t, | |
190 | uint16_t, void *, uint32_t); | 190 | uint16_t, void *, uint32_t); | |
191 | static int kue_load_fw(struct usbnet *); | 191 | static int kue_load_fw(struct usbnet *); | |
192 | 192 | |||
193 | static usbd_status | 193 | static usbd_status | |
194 | kue_setword(struct usbnet *un, uint8_t breq, uint16_t word) | 194 | kue_setword(struct usbnet *un, uint8_t breq, uint16_t word) | |
195 | { | 195 | { | |
196 | usb_device_request_t req; | 196 | usb_device_request_t req; | |
197 | 197 | |||
198 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | 198 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | |
199 | 199 | |||
200 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 200 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
201 | req.bRequest = breq; | 201 | req.bRequest = breq; | |
202 | USETW(req.wValue, word); | 202 | USETW(req.wValue, word); | |
203 | USETW(req.wIndex, 0); | 203 | USETW(req.wIndex, 0); | |
204 | USETW(req.wLength, 0); | 204 | USETW(req.wLength, 0); | |
205 | 205 | |||
206 | return usbd_do_request(un->un_udev, &req, NULL); | 206 | return usbd_do_request(un->un_udev, &req, NULL); | |
207 | } | 207 | } | |
208 | 208 | |||
209 | static usbd_status | 209 | static usbd_status | |
210 | kue_ctl(struct usbnet *un, int rw, uint8_t breq, uint16_t val, | 210 | kue_ctl(struct usbnet *un, int rw, uint8_t breq, uint16_t val, | |
211 | void *data, uint32_t len) | 211 | void *data, uint32_t len) | |
212 | { | 212 | { | |
213 | usb_device_request_t req; | 213 | usb_device_request_t req; | |
214 | 214 | |||
215 | DPRINTFN(10,("%s: %s: enter, len=%d\n", device_xname(un->un_dev), | 215 | DPRINTFN(10,("%s: %s: enter, len=%d\n", device_xname(un->un_dev), | |
216 | __func__, len)); | 216 | __func__, len)); | |
217 | 217 | |||
218 | if (rw == KUE_CTL_WRITE) | 218 | if (rw == KUE_CTL_WRITE) | |
219 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 219 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
220 | else | 220 | else | |
221 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 221 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
222 | 222 | |||
223 | req.bRequest = breq; | 223 | req.bRequest = breq; | |
224 | USETW(req.wValue, val); | 224 | USETW(req.wValue, val); | |
225 | USETW(req.wIndex, 0); | 225 | USETW(req.wIndex, 0); | |
226 | USETW(req.wLength, len); | 226 | USETW(req.wLength, len); | |
227 | 227 | |||
228 | return usbd_do_request(un->un_udev, &req, data); | 228 | return usbd_do_request(un->un_udev, &req, data); | |
229 | } | 229 | } | |
230 | 230 | |||
231 | static int | 231 | static int | |
232 | kue_load_fw(struct usbnet *un) | 232 | kue_load_fw(struct usbnet *un) | |
233 | { | 233 | { | |
234 | usb_device_descriptor_t dd; | 234 | usb_device_descriptor_t dd; | |
235 | usbd_status err; | 235 | usbd_status err; | |
236 | 236 | |||
237 | DPRINTFN(1,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 237 | DPRINTFN(1,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
238 | 238 | |||
239 | /* | 239 | /* | |
240 | * First, check if we even need to load the firmware. | 240 | * First, check if we even need to load the firmware. | |
241 | * If the device was still attached when the system was | 241 | * If the device was still attached when the system was | |
242 | * rebooted, it may already have firmware loaded in it. | 242 | * rebooted, it may already have firmware loaded in it. | |
243 | * If this is the case, we don't need to do it again. | 243 | * If this is the case, we don't need to do it again. | |
244 | * And in fact, if we try to load it again, we'll hang, | 244 | * And in fact, if we try to load it again, we'll hang, | |
245 | * so we have to avoid this condition if we don't want | 245 | * so we have to avoid this condition if we don't want | |
246 | * to look stupid. | 246 | * to look stupid. | |
247 | * | 247 | * | |
248 | * We can test this quickly by checking the bcdRevision | 248 | * We can test this quickly by checking the bcdRevision | |
249 | * code. The NIC will return a different revision code if | 249 | * code. The NIC will return a different revision code if | |
250 | * it's probed while the firmware is still loaded and | 250 | * it's probed while the firmware is still loaded and | |
251 | * running. | 251 | * running. | |
252 | */ | 252 | */ | |
253 | if (usbd_get_device_desc(un->un_udev, &dd)) | 253 | if (usbd_get_device_desc(un->un_udev, &dd)) | |
254 | return EIO; | 254 | return EIO; | |
255 | if (UGETW(dd.bcdDevice) == KUE_WARM_REV) { | 255 | if (UGETW(dd.bcdDevice) == KUE_WARM_REV) { | |
256 | printf("%s: warm boot, no firmware download\n", | 256 | printf("%s: warm boot, no firmware download\n", | |
257 | device_xname(un->un_dev)); | 257 | device_xname(un->un_dev)); | |
258 | return 0; | 258 | return 0; | |
259 | } | 259 | } | |
260 | 260 | |||
261 | printf("%s: cold boot, downloading firmware\n", | 261 | printf("%s: cold boot, downloading firmware\n", | |
262 | device_xname(un->un_dev)); | 262 | device_xname(un->un_dev)); | |
263 | 263 | |||
264 | /* Load code segment */ | 264 | /* Load code segment */ | |
265 | DPRINTFN(1,("%s: kue_load_fw: download code_seg\n", | 265 | DPRINTFN(1,("%s: kue_load_fw: download code_seg\n", | |
266 | device_xname(un->un_dev))); | 266 | device_xname(un->un_dev))); | |
267 | /*XXXUNCONST*/ | 267 | /*XXXUNCONST*/ | |
268 | err = kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, | 268 | err = kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, | |
269 | 0, __UNCONST(kue_code_seg), sizeof(kue_code_seg)); | 269 | 0, __UNCONST(kue_code_seg), sizeof(kue_code_seg)); | |
270 | if (err) { | 270 | if (err) { | |
271 | printf("%s: failed to load code segment: %s\n", | 271 | printf("%s: failed to load code segment: %s\n", | |
272 | device_xname(un->un_dev), usbd_errstr(err)); | 272 | device_xname(un->un_dev), usbd_errstr(err)); | |
273 | return EIO; | 273 | return EIO; | |
274 | } | 274 | } | |
275 | 275 | |||
276 | /* Load fixup segment */ | 276 | /* Load fixup segment */ | |
277 | DPRINTFN(1,("%s: kue_load_fw: download fix_seg\n", | 277 | DPRINTFN(1,("%s: kue_load_fw: download fix_seg\n", | |
278 | device_xname(un->un_dev))); | 278 | device_xname(un->un_dev))); | |
279 | /*XXXUNCONST*/ | 279 | /*XXXUNCONST*/ | |
280 | err = kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, | 280 | err = kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, | |
281 | 0, __UNCONST(kue_fix_seg), sizeof(kue_fix_seg)); | 281 | 0, __UNCONST(kue_fix_seg), sizeof(kue_fix_seg)); | |
282 | if (err) { | 282 | if (err) { | |
283 | printf("%s: failed to load fixup segment: %s\n", | 283 | printf("%s: failed to load fixup segment: %s\n", | |
284 | device_xname(un->un_dev), usbd_errstr(err)); | 284 | device_xname(un->un_dev), usbd_errstr(err)); | |
285 | return EIO; | 285 | return EIO; | |
286 | } | 286 | } | |
287 | 287 | |||
288 | /* Send trigger command. */ | 288 | /* Send trigger command. */ | |
289 | DPRINTFN(1,("%s: kue_load_fw: download trig_seg\n", | 289 | DPRINTFN(1,("%s: kue_load_fw: download trig_seg\n", | |
290 | device_xname(un->un_dev))); | 290 | device_xname(un->un_dev))); | |
291 | /*XXXUNCONST*/ | 291 | /*XXXUNCONST*/ | |
292 | err = kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, | 292 | err = kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, | |
293 | 0, __UNCONST(kue_trig_seg), sizeof(kue_trig_seg)); | 293 | 0, __UNCONST(kue_trig_seg), sizeof(kue_trig_seg)); | |
294 | if (err) { | 294 | if (err) { | |
295 | printf("%s: failed to load trigger segment: %s\n", | 295 | printf("%s: failed to load trigger segment: %s\n", | |
296 | device_xname(un->un_dev), usbd_errstr(err)); | 296 | device_xname(un->un_dev), usbd_errstr(err)); | |
297 | return EIO; | 297 | return EIO; | |
298 | } | 298 | } | |
299 | 299 | |||
300 | usbd_delay_ms(un->un_udev, 10); | 300 | usbd_delay_ms(un->un_udev, 10); | |
301 | 301 | |||
302 | /* | 302 | /* | |
303 | * Reload device descriptor. | 303 | * Reload device descriptor. | |
304 | * Why? The chip without the firmware loaded returns | 304 | * Why? The chip without the firmware loaded returns | |
305 | * one revision code. The chip with the firmware | 305 | * one revision code. The chip with the firmware | |
306 | * loaded and running returns a *different* revision | 306 | * loaded and running returns a *different* revision | |
307 | * code. This confuses the quirk mechanism, which is | 307 | * code. This confuses the quirk mechanism, which is | |
308 | * dependent on the revision data. | 308 | * dependent on the revision data. | |
309 | */ | 309 | */ | |
310 | (void)usbd_reload_device_desc(un->un_udev); | 310 | (void)usbd_reload_device_desc(un->un_udev); | |
311 | 311 | |||
312 | DPRINTFN(1,("%s: %s: done\n", device_xname(un->un_dev), __func__)); | 312 | DPRINTFN(1,("%s: %s: done\n", device_xname(un->un_dev), __func__)); | |
313 | 313 | |||
314 | /* Reset the adapter. */ | 314 | /* Reset the adapter. */ | |
315 | kue_reset(un); | 315 | kue_reset(un); | |
316 | 316 | |||
317 | return 0; | 317 | return 0; | |
318 | } | 318 | } | |
319 | 319 | |||
320 | static void | 320 | static void | |
321 | kue_setiff_locked(struct usbnet *un) | 321 | kue_setiff_locked(struct usbnet *un) | |
322 | { | 322 | { | |
323 | struct ethercom * ec = usbnet_ec(un); | 323 | struct ethercom * ec = usbnet_ec(un); | |
324 | struct kue_softc * sc = usbnet_softc(un); | 324 | struct kue_softc * sc = usbnet_softc(un); | |
325 | struct ifnet * const ifp = usbnet_ifp(un); | 325 | struct ifnet * const ifp = usbnet_ifp(un); | |
326 | struct ether_multi *enm; | 326 | struct ether_multi *enm; | |
327 | struct ether_multistep step; | 327 | struct ether_multistep step; | |
328 | int i; | 328 | int i; | |
329 | 329 | |||
330 | DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 330 | DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
331 | 331 | |||
332 | /* If we want promiscuous mode, set the allframes bit. */ | 332 | /* If we want promiscuous mode, set the allframes bit. */ | |
333 | if (ifp->if_flags & IFF_PROMISC) | 333 | if (ifp->if_flags & IFF_PROMISC) | |
334 | sc->kue_rxfilt |= KUE_RXFILT_PROMISC; | 334 | sc->kue_rxfilt |= KUE_RXFILT_PROMISC; | |
335 | else | 335 | else | |
336 | sc->kue_rxfilt &= ~KUE_RXFILT_PROMISC; | 336 | sc->kue_rxfilt &= ~KUE_RXFILT_PROMISC; | |
337 | 337 | |||
338 | if (ifp->if_flags & IFF_PROMISC) { | 338 | if (ifp->if_flags & IFF_PROMISC) { | |
339 | allmulti: | 339 | allmulti: | |
340 | ifp->if_flags |= IFF_ALLMULTI; | 340 | ifp->if_flags |= IFF_ALLMULTI; | |
341 | sc->kue_rxfilt |= KUE_RXFILT_ALLMULTI|KUE_RXFILT_PROMISC; | 341 | sc->kue_rxfilt |= KUE_RXFILT_ALLMULTI|KUE_RXFILT_PROMISC; | |
342 | sc->kue_rxfilt &= ~KUE_RXFILT_MULTICAST; | 342 | sc->kue_rxfilt &= ~KUE_RXFILT_MULTICAST; | |
343 | kue_setword(un, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt); | 343 | kue_setword(un, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt); | |
344 | return; | 344 | return; | |
345 | } | 345 | } | |
346 | 346 | |||
347 | sc->kue_rxfilt &= ~(KUE_RXFILT_ALLMULTI|KUE_RXFILT_PROMISC); | 347 | sc->kue_rxfilt &= ~(KUE_RXFILT_ALLMULTI|KUE_RXFILT_PROMISC); | |
348 | 348 | |||
349 | i = 0; | 349 | i = 0; | |
350 | ETHER_LOCK(ec); | 350 | ETHER_LOCK(ec); | |
351 | ETHER_FIRST_MULTI(step, ec, enm); | 351 | ETHER_FIRST_MULTI(step, ec, enm); | |
352 | while (enm != NULL) { | 352 | while (enm != NULL) { | |
353 | if (i == KUE_MCFILTCNT(sc) || | 353 | if (i == KUE_MCFILTCNT(sc) || | |
354 | memcmp(enm->enm_addrlo, enm->enm_addrhi, | 354 | memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
355 | ETHER_ADDR_LEN) != 0) { | 355 | ETHER_ADDR_LEN) != 0) { | |
356 | ETHER_UNLOCK(ec); | 356 | ETHER_UNLOCK(ec); | |
357 | goto allmulti; | 357 | goto allmulti; | |
358 | } | 358 | } | |
359 | 359 | |||
360 | memcpy(KUE_MCFILT(sc, i), enm->enm_addrlo, ETHER_ADDR_LEN); | 360 | memcpy(KUE_MCFILT(sc, i), enm->enm_addrlo, ETHER_ADDR_LEN); | |
361 | ETHER_NEXT_MULTI(step, enm); | 361 | ETHER_NEXT_MULTI(step, enm); | |
362 | i++; | 362 | i++; | |
363 | } | 363 | } | |
364 | ETHER_UNLOCK(ec); | 364 | ETHER_UNLOCK(ec); | |
365 | 365 | |||
366 | ifp->if_flags &= ~IFF_ALLMULTI; | 366 | ifp->if_flags &= ~IFF_ALLMULTI; | |
367 | 367 | |||
368 | sc->kue_rxfilt |= KUE_RXFILT_MULTICAST; | 368 | sc->kue_rxfilt |= KUE_RXFILT_MULTICAST; | |
369 | kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SET_MCAST_FILTERS, | 369 | kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SET_MCAST_FILTERS, | |
370 | i, sc->kue_mcfilters, i * ETHER_ADDR_LEN); | 370 | i, sc->kue_mcfilters, i * ETHER_ADDR_LEN); | |
371 | 371 | |||
372 | kue_setword(un, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt); | 372 | kue_setword(un, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt); | |
373 | } | 373 | } | |
374 | 374 | |||
375 | /* | 375 | /* | |
376 | * Issue a SET_CONFIGURATION command to reset the MAC. This should be | 376 | * Issue a SET_CONFIGURATION command to reset the MAC. This should be | |
377 | * done after the firmware is loaded into the adapter in order to | 377 | * done after the firmware is loaded into the adapter in order to | |
378 | * bring it into proper operation. | 378 | * bring it into proper operation. | |
379 | */ | 379 | */ | |
380 | static void | 380 | static void | |
381 | kue_reset(struct usbnet *un) | 381 | kue_reset(struct usbnet *un) | |
382 | { | 382 | { | |
383 | DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 383 | DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
384 | 384 | |||
385 | if (usbd_set_config_no(un->un_udev, KUE_CONFIG_NO, 1) || | 385 | if (usbd_set_config_no(un->un_udev, KUE_CONFIG_NO, 1) || | |
386 | usbd_device2interface_handle(un->un_udev, KUE_IFACE_IDX, | 386 | usbd_device2interface_handle(un->un_udev, KUE_IFACE_IDX, | |
387 | &un->un_iface)) | 387 | &un->un_iface)) | |
388 | printf("%s: reset failed\n", device_xname(un->un_dev)); | 388 | printf("%s: reset failed\n", device_xname(un->un_dev)); | |
389 | 389 | |||
390 | /* Wait a little while for the chip to get its brains in order. */ | 390 | /* Wait a little while for the chip to get its brains in order. */ | |
391 | usbd_delay_ms(un->un_udev, 10); | 391 | usbd_delay_ms(un->un_udev, 10); | |
392 | } | 392 | } | |
393 | 393 | |||
394 | /* | 394 | /* | |
395 | * Probe for a KLSI chip. | 395 | * Probe for a KLSI chip. | |
396 | */ | 396 | */ | |
397 | static int | 397 | static int | |
398 | kue_match(device_t parent, cfdata_t match, void *aux) | 398 | kue_match(device_t parent, cfdata_t match, void *aux) | |
399 | { | 399 | { | |
400 | struct usb_attach_arg *uaa = aux; | 400 | struct usb_attach_arg *uaa = aux; | |
401 | 401 | |||
402 | DPRINTFN(25,("kue_match: enter\n")); | 402 | DPRINTFN(25,("kue_match: enter\n")); | |
403 | 403 | |||
404 | return kue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 404 | return kue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
405 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 405 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
406 | } | 406 | } | |
407 | 407 | |||
408 | /* | 408 | /* | |
409 | * Attach the interface. Allocate softc structures, do | 409 | * Attach the interface. Allocate softc structures, do | |
410 | * setup and ethernet/BPF attach. | 410 | * setup and ethernet/BPF attach. | |
411 | */ | 411 | */ | |
412 | static void | 412 | static void | |
413 | kue_attach(device_t parent, device_t self, void *aux) | 413 | kue_attach(device_t parent, device_t self, void *aux) | |
414 | { | 414 | { | |
415 | struct kue_softc *sc = device_private(self); | 415 | struct kue_softc *sc = device_private(self); | |
416 | struct usbnet * const un = &sc->kue_un; | 416 | struct usbnet * const un = &sc->kue_un; | |
417 | struct usb_attach_arg *uaa = aux; | 417 | struct usb_attach_arg *uaa = aux; | |
418 | char *devinfop; | 418 | char *devinfop; | |
419 | struct usbd_device * dev = uaa->uaa_device; | 419 | struct usbd_device * dev = uaa->uaa_device; | |
420 | usbd_status err; | 420 | usbd_status err; | |
421 | usb_interface_descriptor_t *id; | 421 | usb_interface_descriptor_t *id; | |
422 | usb_endpoint_descriptor_t *ed; | 422 | usb_endpoint_descriptor_t *ed; | |
423 | int i; | 423 | int i; | |
424 | 424 | |||
425 | KASSERT((void *)sc == un); | 425 | KASSERT((void *)sc == un); | |
426 | 426 | |||
427 | DPRINTFN(5,(" : kue_attach: sc=%p, dev=%p", sc, dev)); | 427 | DPRINTFN(5,(" : kue_attach: sc=%p, dev=%p", sc, dev)); | |
428 | 428 | |||
429 | aprint_naive("\n"); | 429 | aprint_naive("\n"); | |
430 | aprint_normal("\n"); | 430 | aprint_normal("\n"); | |
431 | devinfop = usbd_devinfo_alloc(dev, 0); | 431 | devinfop = usbd_devinfo_alloc(dev, 0); | |
432 | aprint_normal_dev(self, "%s\n", devinfop); | 432 | aprint_normal_dev(self, "%s\n", devinfop); | |
433 | usbd_devinfo_free(devinfop); | 433 | usbd_devinfo_free(devinfop); | |
434 | 434 | |||
435 | un->un_dev = self; | 435 | un->un_dev = self; | |
436 | un->un_udev = dev; | 436 | un->un_udev = dev; | |
437 | un->un_sc = sc; | 437 | un->un_sc = sc; | |
438 | un->un_ops = &kue_ops; | 438 | un->un_ops = &kue_ops; | |
439 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 439 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
440 | un->un_tx_xfer_flags = 0; | 440 | un->un_tx_xfer_flags = 0; | |
441 | un->un_rx_list_cnt = KUE_RX_LIST_CNT; | 441 | un->un_rx_list_cnt = KUE_RX_LIST_CNT; | |
442 | un->un_tx_list_cnt = KUE_TX_LIST_CNT; | 442 | un->un_tx_list_cnt = KUE_TX_LIST_CNT; | |
443 | un->un_rx_bufsz = KUE_BUFSZ; | 443 | un->un_rx_bufsz = KUE_BUFSZ; | |
444 | un->un_tx_bufsz = KUE_BUFSZ; | 444 | un->un_tx_bufsz = KUE_BUFSZ; | |
445 | 445 | |||
446 | err = usbd_set_config_no(dev, KUE_CONFIG_NO, 1); | 446 | err = usbd_set_config_no(dev, KUE_CONFIG_NO, 1); | |
447 | if (err) { | 447 | if (err) { | |
448 | aprint_error_dev(self, "failed to set configuration" | 448 | aprint_error_dev(self, "failed to set configuration" | |
449 | ", err=%s\n", usbd_errstr(err)); | 449 | ", err=%s\n", usbd_errstr(err)); | |
450 | return; | 450 | return; | |
451 | } | 451 | } | |
452 | 452 | |||
453 | /* Load the firmware into the NIC. */ | 453 | /* Load the firmware into the NIC. */ | |
454 | if (kue_load_fw(un)) { | 454 | if (kue_load_fw(un)) { | |
455 | aprint_error_dev(self, "loading firmware failed\n"); | 455 | aprint_error_dev(self, "loading firmware failed\n"); | |
456 | return; | 456 | return; | |
457 | } | 457 | } | |
458 | 458 | |||
459 | err = usbd_device2interface_handle(dev, KUE_IFACE_IDX, &un->un_iface); | 459 | err = usbd_device2interface_handle(dev, KUE_IFACE_IDX, &un->un_iface); | |
460 | if (err) { | 460 | if (err) { | |
461 | aprint_error_dev(self, "getting interface handle failed\n"); | 461 | aprint_error_dev(self, "getting interface handle failed\n"); | |
462 | return; | 462 | return; | |
463 | } | 463 | } | |
464 | 464 | |||
465 | id = usbd_get_interface_descriptor(un->un_iface); | 465 | id = usbd_get_interface_descriptor(un->un_iface); | |
466 | 466 | |||
467 | /* Find endpoints. */ | 467 | /* Find endpoints. */ | |
468 | for (i = 0; i < id->bNumEndpoints; i++) { | 468 | for (i = 0; i < id->bNumEndpoints; i++) { | |
469 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 469 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
470 | if (ed == NULL) { | 470 | if (ed == NULL) { | |
471 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 471 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
472 | return; | 472 | return; | |
473 | } | 473 | } | |
474 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 474 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
475 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 475 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
476 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 476 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
477 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 477 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
478 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 478 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
479 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 479 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
480 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 480 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
481 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 481 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
482 | /* | 482 | /* | |
483 | * The interrupt endpoint is currently unused by the | 483 | * The interrupt endpoint is currently unused by the | |
484 | * KLSI part. | 484 | * KLSI part. | |
485 | */ | 485 | */ | |
486 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 486 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
487 | } | 487 | } | |
488 | } | 488 | } | |
489 | 489 | |||
490 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 490 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
491 | un->un_ed[USBNET_ENDPT_TX] == 0) { | 491 | un->un_ed[USBNET_ENDPT_TX] == 0) { | |
492 | aprint_error_dev(self, "missing endpoint\n"); | 492 | aprint_error_dev(self, "missing endpoint\n"); | |
493 | return; | 493 | return; | |
494 | } | 494 | } | |
495 | 495 | |||
496 | /* First level attach, so kue_ctl() works. */ | 496 | /* First level attach, so kue_ctl() works. */ | |
497 | usbnet_attach(un, "kuedet"); | 497 | usbnet_attach(un, "kuedet"); | |
498 | 498 | |||
499 | /* Read ethernet descriptor */ | 499 | /* Read ethernet descriptor */ | |
500 | err = kue_ctl(un, KUE_CTL_READ, KUE_CMD_GET_ETHER_DESCRIPTOR, | 500 | err = kue_ctl(un, KUE_CTL_READ, KUE_CMD_GET_ETHER_DESCRIPTOR, | |
501 | 0, &sc->kue_desc, sizeof(sc->kue_desc)); | 501 | 0, &sc->kue_desc, sizeof(sc->kue_desc)); | |
502 | if (err) { | 502 | if (err) { | |
503 | aprint_error_dev(self, "could not read Ethernet descriptor\n"); | 503 | aprint_error_dev(self, "could not read Ethernet descriptor\n"); | |
504 | return; | 504 | return; | |
505 | } | 505 | } | |
506 | memcpy(un->un_eaddr, sc->kue_desc.kue_macaddr, sizeof(un->un_eaddr)); | 506 | memcpy(un->un_eaddr, sc->kue_desc.kue_macaddr, sizeof(un->un_eaddr)); | |
507 | 507 | |||
508 | sc->kue_mcfilters = kmem_alloc(KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN, | 508 | sc->kue_mcfilters = kmem_alloc(KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN, | |
509 | KM_SLEEP); | 509 | KM_SLEEP); | |
510 | 510 | |||
511 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 511 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
512 | 0, NULL); | 512 | 0, NULL); | |
513 | } | 513 | } | |
514 | 514 | |||
515 | static int | 515 | static int | |
516 | kue_detach(device_t self, int flags) | 516 | kue_detach(device_t self, int flags) | |
517 | { | 517 | { | |
518 | struct kue_softc *sc = device_private(self); | 518 | struct kue_softc *sc = device_private(self); | |
519 | 519 | |||
520 | if (sc->kue_mcfilters != NULL) { | 520 | if (sc->kue_mcfilters != NULL) { | |
521 | kmem_free(sc->kue_mcfilters, | 521 | kmem_free(sc->kue_mcfilters, | |
522 | KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN); | 522 | KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN); | |
523 | sc->kue_mcfilters = NULL; | 523 | sc->kue_mcfilters = NULL; | |
524 | } | 524 | } | |
525 | 525 | |||
526 | return usbnet_detach(self, flags); | 526 | return usbnet_detach(self, flags); | |
527 | } | 527 | } | |
528 | 528 | |||
529 | /* | 529 | /* | |
530 | * A frame has been uploaded: pass the resulting mbuf chain up to | 530 | * A frame has been uploaded: pass the resulting mbuf chain up to | |
531 | * the higher level protocols. | 531 | * the higher level protocols. | |
532 | */ | 532 | */ | |
533 | static void | 533 | static void | |
534 | kue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 534 | kue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
535 | { | 535 | { | |
536 | struct ifnet *ifp = usbnet_ifp(un); | 536 | struct ifnet *ifp = usbnet_ifp(un); | |
537 | uint8_t *buf = c->unc_buf; | 537 | uint8_t *buf = c->unc_buf; | |
538 | unsigned pktlen; | 538 | unsigned pktlen; | |
539 | 539 | |||
540 | if (total_len <= 1) | 540 | if (total_len <= 1) | |
541 | return; | 541 | return; | |
542 | 542 | |||
543 | DPRINTFN(10,("%s: %s: total_len=%d len=%d\n", | 543 | DPRINTFN(10,("%s: %s: total_len=%d len=%d\n", | |
544 | device_xname(un->un_dev), __func__, | 544 | device_xname(un->un_dev), __func__, | |
545 | total_len, le16dec(buf))); | 545 | total_len, le16dec(buf))); | |
546 | 546 | |||
547 | pktlen = le16dec(buf); | 547 | pktlen = le16dec(buf); | |
548 | if (pktlen > total_len - ETHER_ALIGN) | 548 | if (pktlen > total_len - ETHER_ALIGN) | |
549 | pktlen = total_len - ETHER_ALIGN; | 549 | pktlen = total_len - ETHER_ALIGN; | |
550 | 550 | |||
551 | if (pktlen < ETHER_MIN_LEN - ETHER_CRC_LEN || | 551 | if (pktlen < ETHER_MIN_LEN - ETHER_CRC_LEN || | |
552 | pktlen > MCLBYTES - ETHER_ALIGN) { | 552 | pktlen > MCLBYTES - ETHER_ALIGN) { | |
553 | if_statinc(ifp, if_ierrors); | 553 | if_statinc(ifp, if_ierrors); | |
554 | return; | 554 | return; | |
555 | } | 555 | } | |
556 | 556 | |||
557 | DPRINTFN(10,("%s: %s: deliver %d\n", device_xname(un->un_dev), | 557 | DPRINTFN(10,("%s: %s: deliver %d\n", device_xname(un->un_dev), | |
558 | __func__, pktlen)); | 558 | __func__, pktlen)); | |
559 | usbnet_enqueue(un, buf + 2, pktlen, 0, 0, 0); | 559 | usbnet_enqueue(un, buf + 2, pktlen, 0, 0, 0); | |
560 | } | 560 | } | |
561 | 561 | |||
562 | static unsigned | 562 | static unsigned | |
563 | kue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 563 | kue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
564 | { | 564 | { | |
565 | unsigned total_len, pkt_len; | 565 | unsigned total_len, pkt_len; | |
566 | 566 | |||
567 | pkt_len = m->m_pkthdr.len + 2; | 567 | pkt_len = m->m_pkthdr.len + 2; | |
568 | total_len = roundup2(pkt_len, 64); | 568 | total_len = roundup2(pkt_len, 64); | |
569 | 569 | |||
570 | if ((unsigned)total_len > un->un_tx_bufsz) { | 570 | if ((unsigned)total_len > un->un_tx_bufsz) { | |
571 | DPRINTFN(10,("%s: %s: too big pktlen %u total %u\n", | 571 | DPRINTFN(10,("%s: %s: too big pktlen %u total %u\n", | |
572 | device_xname(un->un_dev), __func__, pkt_len, total_len)); | 572 | device_xname(un->un_dev), __func__, pkt_len, total_len)); | |
573 | return 0; | 573 | return 0; | |
574 | } | 574 | } | |
575 | 575 | |||
576 | /* Frame length is specified in the first 2 bytes of the buffer. */ | 576 | /* Frame length is specified in the first 2 bytes of the buffer. */ | |
577 | le16enc(c->unc_buf, (uint16_t)m->m_pkthdr.len); | 577 | le16enc(c->unc_buf, (uint16_t)m->m_pkthdr.len); | |
578 | 578 | |||
579 | /* | 579 | /* | |
580 | * Copy the mbuf data into a contiguous buffer after the frame length, | 580 | * Copy the mbuf data into a contiguous buffer after the frame length, | |
581 | * possibly zeroing the rest of the buffer. | 581 | * possibly zeroing the rest of the buffer. | |
582 | */ | 582 | */ | |
583 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + 2); | 583 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + 2); | |
584 | if (total_len - pkt_len > 0) | 584 | if (total_len - pkt_len > 0) | |
585 | memset(c->unc_buf + pkt_len, 0, total_len - pkt_len); | 585 | memset(c->unc_buf + pkt_len, 0, total_len - pkt_len); | |
586 | 586 | |||
587 | DPRINTFN(10,("%s: %s: enter pktlen %u total %u\n", | 587 | DPRINTFN(10,("%s: %s: enter pktlen %u total %u\n", | |
588 | device_xname(un->un_dev), __func__, pkt_len, total_len)); | 588 | device_xname(un->un_dev), __func__, pkt_len, total_len)); | |
589 | 589 | |||
590 | return total_len; | 590 | return total_len; | |
591 | } | 591 | } | |
592 | 592 | |||
593 | static int | 593 | static int | |
594 | kue_init_locked(struct ifnet *ifp) | 594 | kue_init_locked(struct ifnet *ifp) | |
595 | { | 595 | { | |
596 | struct usbnet * const un = ifp->if_softc; | 596 | struct usbnet * const un = ifp->if_softc; | |
597 | struct kue_softc *sc = usbnet_softc(un); | 597 | struct kue_softc *sc = usbnet_softc(un); | |
598 | uint8_t eaddr[ETHER_ADDR_LEN]; | 598 | uint8_t eaddr[ETHER_ADDR_LEN]; | |
599 | 599 | |||
600 | DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | 600 | DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | |
601 | 601 | |||
602 | if (usbnet_isdying(un)) | 602 | if (usbnet_isdying(un)) | |
603 | return EIO; | 603 | return EIO; | |
604 | 604 | |||
605 | /* Cancel pending I/O */ | 605 | /* Cancel pending I/O */ | |
606 | usbnet_stop(un, ifp, 1); | 606 | usbnet_stop(un, ifp, 1); | |
607 | 607 | |||
608 | memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); | 608 | memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); | |
609 | /* Set MAC address */ | 609 | /* Set MAC address */ | |
610 | kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SET_MAC, 0, eaddr, ETHER_ADDR_LEN); | 610 | kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SET_MAC, 0, eaddr, ETHER_ADDR_LEN); | |
611 | 611 | |||
612 | sc->kue_rxfilt = KUE_RXFILT_UNICAST | KUE_RXFILT_BROADCAST; | 612 | sc->kue_rxfilt = KUE_RXFILT_UNICAST | KUE_RXFILT_BROADCAST; | |
613 | 613 | |||
614 | /* I'm not sure how to tune these. */ | 614 | /* I'm not sure how to tune these. */ | |
615 | #if 0 | 615 | #if 0 | |
616 | /* | 616 | /* | |
617 | * Leave this one alone for now; setting it | 617 | * Leave this one alone for now; setting it | |
618 | * wrong causes lockups on some machines/controllers. | 618 | * wrong causes lockups on some machines/controllers. | |
619 | */ | 619 | */ | |
620 | kue_setword(un, KUE_CMD_SET_SOFS, 1); | 620 | kue_setword(un, KUE_CMD_SET_SOFS, 1); | |
621 | #endif | 621 | #endif | |
622 | kue_setword(un, KUE_CMD_SET_URB_SIZE, 64); | 622 | kue_setword(un, KUE_CMD_SET_URB_SIZE, 64); | |
623 | 623 | |||
624 | /* Load the multicast filter. */ | 624 | /* Load the multicast filter. */ | |
625 | kue_setiff_locked(un); | 625 | kue_setiff_locked(un); | |
626 | 626 | |||
627 | return usbnet_init_rx_tx(un); | 627 | return usbnet_init_rx_tx(un); | |
628 | } | 628 | } | |
629 | 629 | |||
630 | static int | 630 | static int | |
631 | kue_uno_init(struct ifnet *ifp) | 631 | kue_uno_init(struct ifnet *ifp) | |
632 | { | 632 | { | |
633 | int rv; | 633 | int rv; | |
634 | 634 | |||
635 | rv = kue_init_locked(ifp); | 635 | rv = kue_init_locked(ifp); | |
636 | 636 | |||
637 | return rv; | 637 | return rv; | |
638 | } | 638 | } | |
639 | 639 | |||
640 | static void | 640 | static void | |
641 | kue_uno_mcast(struct ifnet *ifp) | 641 | kue_uno_mcast(struct ifnet *ifp) | |
642 | { | 642 | { | |
643 | struct usbnet * const un = ifp->if_softc; | 643 | struct usbnet * const un = ifp->if_softc; | |
644 | 644 | |||
645 | usbnet_lock_core(un); | 645 | usbnet_lock_core(un); | |
646 | usbnet_busy(un); | |||
647 | 646 | |||
648 | kue_setiff_locked(un); | 647 | kue_setiff_locked(un); | |
649 | 648 | |||
650 | usbnet_unbusy(un); | |||
651 | usbnet_unlock_core(un); | 649 | usbnet_unlock_core(un); | |
652 | } | 650 | } | |
653 | 651 | |||
654 | #ifdef _MODULE | 652 | #ifdef _MODULE | |
655 | #include "ioconf.c" | 653 | #include "ioconf.c" | |
656 | #endif | 654 | #endif | |
657 | 655 | |||
658 | USBNET_MODULE(kue) | 656 | USBNET_MODULE(kue) |
--- src/sys/dev/usb/if_mos.c 2022/03/03 05:51:17 1.11
+++ src/sys/dev/usb/if_mos.c 2022/03/03 05:51:27 1.12
@@ -1,790 +1,788 @@ | @@ -1,790 +1,788 @@ | |||
1 | /* $NetBSD: if_mos.c,v 1.11 2022/03/03 05:51:17 riastradh Exp $ */ | 1 | /* $NetBSD: if_mos.c,v 1.12 2022/03/03 05:51:27 riastradh Exp $ */ | |
2 | /* $OpenBSD: if_mos.c,v 1.40 2019/07/07 06:40:10 kevlo Exp $ */ | 2 | /* $OpenBSD: if_mos.c,v 1.40 2019/07/07 06:40:10 kevlo Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2008 Johann Christian Rode <jcrode@gmx.net> | 5 | * Copyright (c) 2008 Johann Christian Rode <jcrode@gmx.net> | |
6 | * | 6 | * | |
7 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any | |
8 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above | |
9 | * copyright notice and this permission notice appear in all copies. | 9 | * copyright notice and this permission notice appear in all copies. | |
10 | * | 10 | * | |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
18 | */ | 18 | */ | |
19 | 19 | |||
20 | /* | 20 | /* | |
21 | * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org> | 21 | * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org> | |
22 | * | 22 | * | |
23 | * Permission to use, copy, modify, and distribute this software for any | 23 | * Permission to use, copy, modify, and distribute this software for any | |
24 | * purpose with or without fee is hereby granted, provided that the above | 24 | * purpose with or without fee is hereby granted, provided that the above | |
25 | * copyright notice and this permission notice appear in all copies. | 25 | * copyright notice and this permission notice appear in all copies. | |
26 | * | 26 | * | |
27 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 27 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
28 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 28 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
29 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 29 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
30 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 30 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
31 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 31 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
32 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 32 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
33 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 33 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
34 | */ | 34 | */ | |
35 | 35 | |||
36 | /* | 36 | /* | |
37 | * Copyright (c) 1997, 1998, 1999, 2000-2003 | 37 | * Copyright (c) 1997, 1998, 1999, 2000-2003 | |
38 | * Bill Paul <wpaul@windriver.com>. All rights reserved. | 38 | * Bill Paul <wpaul@windriver.com>. All rights reserved. | |
39 | * | 39 | * | |
40 | * Redistribution and use in source and binary forms, with or without | 40 | * Redistribution and use in source and binary forms, with or without | |
41 | * modification, are permitted provided that the following conditions | 41 | * modification, are permitted provided that the following conditions | |
42 | * are met: | 42 | * are met: | |
43 | * 1. Redistributions of source code must retain the above copyright | 43 | * 1. Redistributions of source code must retain the above copyright | |
44 | * notice, this list of conditions and the following disclaimer. | 44 | * notice, this list of conditions and the following disclaimer. | |
45 | * 2. Redistributions in binary form must reproduce the above copyright | 45 | * 2. Redistributions in binary form must reproduce the above copyright | |
46 | * notice, this list of conditions and the following disclaimer in the | 46 | * notice, this list of conditions and the following disclaimer in the | |
47 | * documentation and/or other materials provided with the distribution. | 47 | * documentation and/or other materials provided with the distribution. | |
48 | * 3. All advertising materials mentioning features or use of this software | 48 | * 3. All advertising materials mentioning features or use of this software | |
49 | * must display the following acknowledgement: | 49 | * must display the following acknowledgement: | |
50 | * This product includes software developed by Bill Paul. | 50 | * This product includes software developed by Bill Paul. | |
51 | * 4. Neither the name of the author nor the names of any co-contributors | 51 | * 4. Neither the name of the author nor the names of any co-contributors | |
52 | * may be used to endorse or promote products derived from this software | 52 | * may be used to endorse or promote products derived from this software | |
53 | * without specific prior written permission. | 53 | * without specific prior written permission. | |
54 | * | 54 | * | |
55 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | 55 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | |
56 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 56 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
57 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 57 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
58 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | 58 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | |
59 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 59 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
60 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 60 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
61 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 61 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
62 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 62 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
63 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 63 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
64 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 64 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
65 | * THE POSSIBILITY OF SUCH DAMAGE. | 65 | * THE POSSIBILITY OF SUCH DAMAGE. | |
66 | */ | 66 | */ | |
67 | 67 | |||
68 | /* | 68 | /* | |
69 | * Moschip MCS7730/MCS7830/MCS7832 USB to Ethernet controller | 69 | * Moschip MCS7730/MCS7830/MCS7832 USB to Ethernet controller | |
70 | * The datasheet is available at the following URL: | 70 | * The datasheet is available at the following URL: | |
71 | * http://www.moschip.com/data/products/MCS7830/Data%20Sheet_7830.pdf | 71 | * http://www.moschip.com/data/products/MCS7830/Data%20Sheet_7830.pdf | |
72 | */ | 72 | */ | |
73 | 73 | |||
74 | #include <sys/cdefs.h> | 74 | #include <sys/cdefs.h> | |
75 | __KERNEL_RCSID(0, "$NetBSD: if_mos.c,v 1.11 2022/03/03 05:51:17 riastradh Exp $"); | 75 | __KERNEL_RCSID(0, "$NetBSD: if_mos.c,v 1.12 2022/03/03 05:51:27 riastradh Exp $"); | |
76 | 76 | |||
77 | #include <sys/param.h> | 77 | #include <sys/param.h> | |
78 | 78 | |||
79 | #include <dev/usb/usbnet.h> | 79 | #include <dev/usb/usbnet.h> | |
80 | #include <dev/usb/if_mosreg.h> | 80 | #include <dev/usb/if_mosreg.h> | |
81 | 81 | |||
82 | #define MOS_PAUSE_REWRITES 3 | 82 | #define MOS_PAUSE_REWRITES 3 | |
83 | 83 | |||
84 | #define MOS_TIMEOUT 1000 | 84 | #define MOS_TIMEOUT 1000 | |
85 | 85 | |||
86 | #define MOS_RX_LIST_CNT 1 | 86 | #define MOS_RX_LIST_CNT 1 | |
87 | #define MOS_TX_LIST_CNT 1 | 87 | #define MOS_TX_LIST_CNT 1 | |
88 | 88 | |||
89 | /* Maximum size of a fast ethernet frame plus one byte for the status */ | 89 | /* Maximum size of a fast ethernet frame plus one byte for the status */ | |
90 | #define MOS_BUFSZ (ETHER_MAX_LEN+1) | 90 | #define MOS_BUFSZ (ETHER_MAX_LEN+1) | |
91 | 91 | |||
92 | /* | 92 | /* | |
93 | * USB endpoints. | 93 | * USB endpoints. | |
94 | */ | 94 | */ | |
95 | #define MOS_ENDPT_RX 0 | 95 | #define MOS_ENDPT_RX 0 | |
96 | #define MOS_ENDPT_TX 1 | 96 | #define MOS_ENDPT_TX 1 | |
97 | #define MOS_ENDPT_INTR 2 | 97 | #define MOS_ENDPT_INTR 2 | |
98 | #define MOS_ENDPT_MAX 3 | 98 | #define MOS_ENDPT_MAX 3 | |
99 | 99 | |||
100 | /* | 100 | /* | |
101 | * USB vendor requests. | 101 | * USB vendor requests. | |
102 | */ | 102 | */ | |
103 | #define MOS_UR_READREG 0x0e | 103 | #define MOS_UR_READREG 0x0e | |
104 | #define MOS_UR_WRITEREG 0x0d | 104 | #define MOS_UR_WRITEREG 0x0d | |
105 | 105 | |||
106 | #define MOS_CONFIG_NO 1 | 106 | #define MOS_CONFIG_NO 1 | |
107 | #define MOS_IFACE_IDX 0 | 107 | #define MOS_IFACE_IDX 0 | |
108 | 108 | |||
109 | struct mos_type { | 109 | struct mos_type { | |
110 | struct usb_devno mos_dev; | 110 | struct usb_devno mos_dev; | |
111 | u_int16_t mos_flags; | 111 | u_int16_t mos_flags; | |
112 | #define MCS7730 0x0001 /* MCS7730 */ | 112 | #define MCS7730 0x0001 /* MCS7730 */ | |
113 | #define MCS7830 0x0002 /* MCS7830 */ | 113 | #define MCS7830 0x0002 /* MCS7830 */ | |
114 | #define MCS7832 0x0004 /* MCS7832 */ | 114 | #define MCS7832 0x0004 /* MCS7832 */ | |
115 | }; | 115 | }; | |
116 | 116 | |||
117 | #define MOS_INC(x, y) (x) = (x + 1) % y | 117 | #define MOS_INC(x, y) (x) = (x + 1) % y | |
118 | 118 | |||
119 | #ifdef MOS_DEBUG | 119 | #ifdef MOS_DEBUG | |
120 | #define DPRINTF(x) do { if (mosdebug) printf x; } while (0) | 120 | #define DPRINTF(x) do { if (mosdebug) printf x; } while (0) | |
121 | #define DPRINTFN(n,x) do { if (mosdebug >= (n)) printf x; } while (0) | 121 | #define DPRINTFN(n,x) do { if (mosdebug >= (n)) printf x; } while (0) | |
122 | int mosdebug = 0; | 122 | int mosdebug = 0; | |
123 | #else | 123 | #else | |
124 | #define DPRINTF(x) __nothing | 124 | #define DPRINTF(x) __nothing | |
125 | #define DPRINTFN(n,x) __nothing | 125 | #define DPRINTFN(n,x) __nothing | |
126 | #endif | 126 | #endif | |
127 | 127 | |||
128 | /* | 128 | /* | |
129 | * Various supported device vendors/products. | 129 | * Various supported device vendors/products. | |
130 | */ | 130 | */ | |
131 | static const struct mos_type mos_devs[] = { | 131 | static const struct mos_type mos_devs[] = { | |
132 | { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730 }, MCS7730 }, | 132 | { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730 }, MCS7730 }, | |
133 | { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830 }, MCS7830 }, | 133 | { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830 }, MCS7830 }, | |
134 | { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7832 }, MCS7832 }, | 134 | { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7832 }, MCS7832 }, | |
135 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030 }, MCS7830 }, | 135 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030 }, MCS7830 }, | |
136 | }; | 136 | }; | |
137 | #define mos_lookup(v, p) ((const struct mos_type *)usb_lookup(mos_devs, v, p)) | 137 | #define mos_lookup(v, p) ((const struct mos_type *)usb_lookup(mos_devs, v, p)) | |
138 | 138 | |||
139 | static int mos_match(device_t, cfdata_t, void *); | 139 | static int mos_match(device_t, cfdata_t, void *); | |
140 | static void mos_attach(device_t, device_t, void *); | 140 | static void mos_attach(device_t, device_t, void *); | |
141 | 141 | |||
142 | CFATTACH_DECL_NEW(mos, sizeof(struct usbnet), | 142 | CFATTACH_DECL_NEW(mos, sizeof(struct usbnet), | |
143 | mos_match, mos_attach, usbnet_detach, usbnet_activate); | 143 | mos_match, mos_attach, usbnet_detach, usbnet_activate); | |
144 | 144 | |||
145 | static void mos_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 145 | static void mos_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
146 | static unsigned mos_uno_tx_prepare(struct usbnet *, struct mbuf *, | 146 | static unsigned mos_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
147 | struct usbnet_chain *); | 147 | struct usbnet_chain *); | |
148 | static void mos_uno_mcast(struct ifnet *); | 148 | static void mos_uno_mcast(struct ifnet *); | |
149 | static int mos_uno_init(struct ifnet *); | 149 | static int mos_uno_init(struct ifnet *); | |
150 | static void mos_chip_init(struct usbnet *); | 150 | static void mos_chip_init(struct usbnet *); | |
151 | static void mos_uno_stop(struct ifnet *ifp, int disable); | 151 | static void mos_uno_stop(struct ifnet *ifp, int disable); | |
152 | static int mos_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 152 | static int mos_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
153 | static int mos_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 153 | static int mos_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
154 | static void mos_uno_mii_statchg(struct ifnet *); | 154 | static void mos_uno_mii_statchg(struct ifnet *); | |
155 | static void mos_reset(struct usbnet *); | 155 | static void mos_reset(struct usbnet *); | |
156 | 156 | |||
157 | static int mos_reg_read_1(struct usbnet *, int); | 157 | static int mos_reg_read_1(struct usbnet *, int); | |
158 | static int mos_reg_read_2(struct usbnet *, int); | 158 | static int mos_reg_read_2(struct usbnet *, int); | |
159 | static int mos_reg_write_1(struct usbnet *, int, int); | 159 | static int mos_reg_write_1(struct usbnet *, int, int); | |
160 | static int mos_reg_write_2(struct usbnet *, int, int); | 160 | static int mos_reg_write_2(struct usbnet *, int, int); | |
161 | static int mos_readmac(struct usbnet *); | 161 | static int mos_readmac(struct usbnet *); | |
162 | static int mos_writemac(struct usbnet *); | 162 | static int mos_writemac(struct usbnet *); | |
163 | static int mos_write_mcast(struct usbnet *, uint8_t *); | 163 | static int mos_write_mcast(struct usbnet *, uint8_t *); | |
164 | 164 | |||
165 | static const struct usbnet_ops mos_ops = { | 165 | static const struct usbnet_ops mos_ops = { | |
166 | .uno_stop = mos_uno_stop, | 166 | .uno_stop = mos_uno_stop, | |
167 | .uno_mcast = mos_uno_mcast, | 167 | .uno_mcast = mos_uno_mcast, | |
168 | .uno_read_reg = mos_uno_mii_read_reg, | 168 | .uno_read_reg = mos_uno_mii_read_reg, | |
169 | .uno_write_reg = mos_uno_mii_write_reg, | 169 | .uno_write_reg = mos_uno_mii_write_reg, | |
170 | .uno_statchg = mos_uno_mii_statchg, | 170 | .uno_statchg = mos_uno_mii_statchg, | |
171 | .uno_tx_prepare = mos_uno_tx_prepare, | 171 | .uno_tx_prepare = mos_uno_tx_prepare, | |
172 | .uno_rx_loop = mos_uno_rx_loop, | 172 | .uno_rx_loop = mos_uno_rx_loop, | |
173 | .uno_init = mos_uno_init, | 173 | .uno_init = mos_uno_init, | |
174 | }; | 174 | }; | |
175 | 175 | |||
176 | static int | 176 | static int | |
177 | mos_reg_read_1(struct usbnet *un, int reg) | 177 | mos_reg_read_1(struct usbnet *un, int reg) | |
178 | { | 178 | { | |
179 | usb_device_request_t req; | 179 | usb_device_request_t req; | |
180 | usbd_status err; | 180 | usbd_status err; | |
181 | uByte val = 0; | 181 | uByte val = 0; | |
182 | 182 | |||
183 | if (usbnet_isdying(un)) | 183 | if (usbnet_isdying(un)) | |
184 | return 0; | 184 | return 0; | |
185 | 185 | |||
186 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 186 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
187 | req.bRequest = MOS_UR_READREG; | 187 | req.bRequest = MOS_UR_READREG; | |
188 | USETW(req.wValue, 0); | 188 | USETW(req.wValue, 0); | |
189 | USETW(req.wIndex, reg); | 189 | USETW(req.wIndex, reg); | |
190 | USETW(req.wLength, 1); | 190 | USETW(req.wLength, 1); | |
191 | 191 | |||
192 | err = usbd_do_request(un->un_udev, &req, &val); | 192 | err = usbd_do_request(un->un_udev, &req, &val); | |
193 | 193 | |||
194 | if (err) { | 194 | if (err) { | |
195 | aprint_error_dev(un->un_dev, "read reg %x\n", reg); | 195 | aprint_error_dev(un->un_dev, "read reg %x\n", reg); | |
196 | return 0; | 196 | return 0; | |
197 | } | 197 | } | |
198 | 198 | |||
199 | return val; | 199 | return val; | |
200 | } | 200 | } | |
201 | 201 | |||
202 | static int | 202 | static int | |
203 | mos_reg_read_2(struct usbnet *un, int reg) | 203 | mos_reg_read_2(struct usbnet *un, int reg) | |
204 | { | 204 | { | |
205 | usb_device_request_t req; | 205 | usb_device_request_t req; | |
206 | usbd_status err; | 206 | usbd_status err; | |
207 | uWord val; | 207 | uWord val; | |
208 | 208 | |||
209 | if (usbnet_isdying(un)) | 209 | if (usbnet_isdying(un)) | |
210 | return 0; | 210 | return 0; | |
211 | 211 | |||
212 | USETW(val,0); | 212 | USETW(val,0); | |
213 | 213 | |||
214 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 214 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
215 | req.bRequest = MOS_UR_READREG; | 215 | req.bRequest = MOS_UR_READREG; | |
216 | USETW(req.wValue, 0); | 216 | USETW(req.wValue, 0); | |
217 | USETW(req.wIndex, reg); | 217 | USETW(req.wIndex, reg); | |
218 | USETW(req.wLength, 2); | 218 | USETW(req.wLength, 2); | |
219 | 219 | |||
220 | err = usbd_do_request(un->un_udev, &req, &val); | 220 | err = usbd_do_request(un->un_udev, &req, &val); | |
221 | 221 | |||
222 | if (err) { | 222 | if (err) { | |
223 | aprint_error_dev(un->un_dev, "read reg2 %x\n", reg); | 223 | aprint_error_dev(un->un_dev, "read reg2 %x\n", reg); | |
224 | return 0; | 224 | return 0; | |
225 | } | 225 | } | |
226 | 226 | |||
227 | return UGETW(val); | 227 | return UGETW(val); | |
228 | } | 228 | } | |
229 | 229 | |||
230 | static int | 230 | static int | |
231 | mos_reg_write_1(struct usbnet *un, int reg, int aval) | 231 | mos_reg_write_1(struct usbnet *un, int reg, int aval) | |
232 | { | 232 | { | |
233 | usb_device_request_t req; | 233 | usb_device_request_t req; | |
234 | usbd_status err; | 234 | usbd_status err; | |
235 | uByte val; | 235 | uByte val; | |
236 | 236 | |||
237 | if (usbnet_isdying(un)) | 237 | if (usbnet_isdying(un)) | |
238 | return 0; | 238 | return 0; | |
239 | 239 | |||
240 | val = aval; | 240 | val = aval; | |
241 | 241 | |||
242 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 242 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
243 | req.bRequest = MOS_UR_WRITEREG; | 243 | req.bRequest = MOS_UR_WRITEREG; | |
244 | USETW(req.wValue, 0); | 244 | USETW(req.wValue, 0); | |
245 | USETW(req.wIndex, reg); | 245 | USETW(req.wIndex, reg); | |
246 | USETW(req.wLength, 1); | 246 | USETW(req.wLength, 1); | |
247 | 247 | |||
248 | err = usbd_do_request(un->un_udev, &req, &val); | 248 | err = usbd_do_request(un->un_udev, &req, &val); | |
249 | 249 | |||
250 | if (err) | 250 | if (err) | |
251 | aprint_error_dev(un->un_dev, "write reg %x <- %x\n", | 251 | aprint_error_dev(un->un_dev, "write reg %x <- %x\n", | |
252 | reg, aval); | 252 | reg, aval); | |
253 | 253 | |||
254 | return 0; | 254 | return 0; | |
255 | } | 255 | } | |
256 | 256 | |||
257 | static int | 257 | static int | |
258 | mos_reg_write_2(struct usbnet *un, int reg, int aval) | 258 | mos_reg_write_2(struct usbnet *un, int reg, int aval) | |
259 | { | 259 | { | |
260 | usb_device_request_t req; | 260 | usb_device_request_t req; | |
261 | usbd_status err; | 261 | usbd_status err; | |
262 | uWord val; | 262 | uWord val; | |
263 | 263 | |||
264 | USETW(val, aval); | 264 | USETW(val, aval); | |
265 | 265 | |||
266 | if (usbnet_isdying(un)) | 266 | if (usbnet_isdying(un)) | |
267 | return EIO; | 267 | return EIO; | |
268 | 268 | |||
269 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 269 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
270 | req.bRequest = MOS_UR_WRITEREG; | 270 | req.bRequest = MOS_UR_WRITEREG; | |
271 | USETW(req.wValue, 0); | 271 | USETW(req.wValue, 0); | |
272 | USETW(req.wIndex, reg); | 272 | USETW(req.wIndex, reg); | |
273 | USETW(req.wLength, 2); | 273 | USETW(req.wLength, 2); | |
274 | 274 | |||
275 | err = usbd_do_request(un->un_udev, &req, &val); | 275 | err = usbd_do_request(un->un_udev, &req, &val); | |
276 | 276 | |||
277 | if (err) | 277 | if (err) | |
278 | aprint_error_dev(un->un_dev, "write reg2 %x <- %x\n", | 278 | aprint_error_dev(un->un_dev, "write reg2 %x <- %x\n", | |
279 | reg, aval); | 279 | reg, aval); | |
280 | 280 | |||
281 | return 0; | 281 | return 0; | |
282 | } | 282 | } | |
283 | 283 | |||
284 | static int | 284 | static int | |
285 | mos_readmac(struct usbnet *un) | 285 | mos_readmac(struct usbnet *un) | |
286 | { | 286 | { | |
287 | usb_device_request_t req; | 287 | usb_device_request_t req; | |
288 | usbd_status err; | 288 | usbd_status err; | |
289 | 289 | |||
290 | if (usbnet_isdying(un)) | 290 | if (usbnet_isdying(un)) | |
291 | return 0; | 291 | return 0; | |
292 | 292 | |||
293 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 293 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
294 | req.bRequest = MOS_UR_READREG; | 294 | req.bRequest = MOS_UR_READREG; | |
295 | USETW(req.wValue, 0); | 295 | USETW(req.wValue, 0); | |
296 | USETW(req.wIndex, MOS_MAC); | 296 | USETW(req.wIndex, MOS_MAC); | |
297 | USETW(req.wLength, ETHER_ADDR_LEN); | 297 | USETW(req.wLength, ETHER_ADDR_LEN); | |
298 | 298 | |||
299 | err = usbd_do_request(un->un_udev, &req, un->un_eaddr); | 299 | err = usbd_do_request(un->un_udev, &req, un->un_eaddr); | |
300 | 300 | |||
301 | if (err) | 301 | if (err) | |
302 | aprint_error_dev(un->un_dev, "%s: failed", __func__); | 302 | aprint_error_dev(un->un_dev, "%s: failed", __func__); | |
303 | 303 | |||
304 | return err; | 304 | return err; | |
305 | } | 305 | } | |
306 | 306 | |||
307 | static int | 307 | static int | |
308 | mos_writemac(struct usbnet *un) | 308 | mos_writemac(struct usbnet *un) | |
309 | { | 309 | { | |
310 | usb_device_request_t req; | 310 | usb_device_request_t req; | |
311 | usbd_status err; | 311 | usbd_status err; | |
312 | 312 | |||
313 | if (usbnet_isdying(un)) | 313 | if (usbnet_isdying(un)) | |
314 | return 0; | 314 | return 0; | |
315 | 315 | |||
316 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 316 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
317 | req.bRequest = MOS_UR_WRITEREG; | 317 | req.bRequest = MOS_UR_WRITEREG; | |
318 | USETW(req.wValue, 0); | 318 | USETW(req.wValue, 0); | |
319 | USETW(req.wIndex, MOS_MAC); | 319 | USETW(req.wIndex, MOS_MAC); | |
320 | USETW(req.wLength, ETHER_ADDR_LEN); | 320 | USETW(req.wLength, ETHER_ADDR_LEN); | |
321 | 321 | |||
322 | err = usbd_do_request(un->un_udev, &req, un->un_eaddr); | 322 | err = usbd_do_request(un->un_udev, &req, un->un_eaddr); | |
323 | 323 | |||
324 | if (err) | 324 | if (err) | |
325 | aprint_error_dev(un->un_dev, "%s: failed", __func__); | 325 | aprint_error_dev(un->un_dev, "%s: failed", __func__); | |
326 | 326 | |||
327 | return 0; | 327 | return 0; | |
328 | } | 328 | } | |
329 | 329 | |||
330 | static int | 330 | static int | |
331 | mos_write_mcast(struct usbnet *un, uint8_t *hashtbl) | 331 | mos_write_mcast(struct usbnet *un, uint8_t *hashtbl) | |
332 | { | 332 | { | |
333 | usb_device_request_t req; | 333 | usb_device_request_t req; | |
334 | usbd_status err; | 334 | usbd_status err; | |
335 | 335 | |||
336 | if (usbnet_isdying(un)) | 336 | if (usbnet_isdying(un)) | |
337 | return EIO; | 337 | return EIO; | |
338 | 338 | |||
339 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 339 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
340 | req.bRequest = MOS_UR_WRITEREG; | 340 | req.bRequest = MOS_UR_WRITEREG; | |
341 | USETW(req.wValue, 0); | 341 | USETW(req.wValue, 0); | |
342 | USETW(req.wIndex, MOS_MCAST_TABLE); | 342 | USETW(req.wIndex, MOS_MCAST_TABLE); | |
343 | USETW(req.wLength, 8); | 343 | USETW(req.wLength, 8); | |
344 | 344 | |||
345 | err = usbd_do_request(un->un_udev, &req, hashtbl); | 345 | err = usbd_do_request(un->un_udev, &req, hashtbl); | |
346 | 346 | |||
347 | if (err) { | 347 | if (err) { | |
348 | aprint_error_dev(un->un_dev, "%s: failed", __func__); | 348 | aprint_error_dev(un->un_dev, "%s: failed", __func__); | |
349 | return(-1); | 349 | return(-1); | |
350 | } | 350 | } | |
351 | 351 | |||
352 | return 0; | 352 | return 0; | |
353 | } | 353 | } | |
354 | 354 | |||
355 | static int | 355 | static int | |
356 | mos_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 356 | mos_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
357 | { | 357 | { | |
358 | int i, res; | 358 | int i, res; | |
359 | 359 | |||
360 | mos_reg_write_2(un, MOS_PHY_DATA, 0); | 360 | mos_reg_write_2(un, MOS_PHY_DATA, 0); | |
361 | mos_reg_write_1(un, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | | 361 | mos_reg_write_1(un, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | | |
362 | MOS_PHYCTL_READ); | 362 | MOS_PHYCTL_READ); | |
363 | mos_reg_write_1(un, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | | 363 | mos_reg_write_1(un, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | | |
364 | MOS_PHYSTS_PENDING); | 364 | MOS_PHYSTS_PENDING); | |
365 | 365 | |||
366 | for (i = 0; i < MOS_TIMEOUT; i++) { | 366 | for (i = 0; i < MOS_TIMEOUT; i++) { | |
367 | if (usbnet_isdying(un)) | 367 | if (usbnet_isdying(un)) | |
368 | return ENXIO; | 368 | return ENXIO; | |
369 | if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY) | 369 | if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY) | |
370 | break; | 370 | break; | |
371 | } | 371 | } | |
372 | if (i == MOS_TIMEOUT) { | 372 | if (i == MOS_TIMEOUT) { | |
373 | aprint_error_dev(un->un_dev, "read PHY failed\n"); | 373 | aprint_error_dev(un->un_dev, "read PHY failed\n"); | |
374 | return EIO; | 374 | return EIO; | |
375 | } | 375 | } | |
376 | 376 | |||
377 | res = mos_reg_read_2(un, MOS_PHY_DATA); | 377 | res = mos_reg_read_2(un, MOS_PHY_DATA); | |
378 | *val = res; | 378 | *val = res; | |
379 | 379 | |||
380 | DPRINTFN(10,("%s: %s: phy %d reg %d val %u\n", | 380 | DPRINTFN(10,("%s: %s: phy %d reg %d val %u\n", | |
381 | device_xname(un->un_dev), __func__, phy, reg, res)); | 381 | device_xname(un->un_dev), __func__, phy, reg, res)); | |
382 | 382 | |||
383 | return 0; | 383 | return 0; | |
384 | } | 384 | } | |
385 | 385 | |||
386 | static int | 386 | static int | |
387 | mos_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 387 | mos_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
388 | { | 388 | { | |
389 | int i; | 389 | int i; | |
390 | 390 | |||
391 | DPRINTFN(10,("%s: %s: phy %d reg %d val %u\n", | 391 | DPRINTFN(10,("%s: %s: phy %d reg %d val %u\n", | |
392 | device_xname(un->un_dev), __func__, phy, reg, val)); | 392 | device_xname(un->un_dev), __func__, phy, reg, val)); | |
393 | 393 | |||
394 | mos_reg_write_2(un, MOS_PHY_DATA, val); | 394 | mos_reg_write_2(un, MOS_PHY_DATA, val); | |
395 | mos_reg_write_1(un, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | | 395 | mos_reg_write_1(un, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | | |
396 | MOS_PHYCTL_WRITE); | 396 | MOS_PHYCTL_WRITE); | |
397 | mos_reg_write_1(un, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | | 397 | mos_reg_write_1(un, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | | |
398 | MOS_PHYSTS_PENDING); | 398 | MOS_PHYSTS_PENDING); | |
399 | 399 | |||
400 | for (i = 0; i < MOS_TIMEOUT; i++) { | 400 | for (i = 0; i < MOS_TIMEOUT; i++) { | |
401 | if (usbnet_isdying(un)) | 401 | if (usbnet_isdying(un)) | |
402 | return ENXIO; | 402 | return ENXIO; | |
403 | if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY) | 403 | if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY) | |
404 | break; | 404 | break; | |
405 | } | 405 | } | |
406 | if (i == MOS_TIMEOUT) { | 406 | if (i == MOS_TIMEOUT) { | |
407 | aprint_error_dev(un->un_dev, "write PHY failed\n"); | 407 | aprint_error_dev(un->un_dev, "write PHY failed\n"); | |
408 | return EIO; | 408 | return EIO; | |
409 | } | 409 | } | |
410 | 410 | |||
411 | return 0; | 411 | return 0; | |
412 | } | 412 | } | |
413 | 413 | |||
414 | void | 414 | void | |
415 | mos_uno_mii_statchg(struct ifnet *ifp) | 415 | mos_uno_mii_statchg(struct ifnet *ifp) | |
416 | { | 416 | { | |
417 | struct usbnet * const un = ifp->if_softc; | 417 | struct usbnet * const un = ifp->if_softc; | |
418 | struct mii_data * const mii = usbnet_mii(un); | 418 | struct mii_data * const mii = usbnet_mii(un); | |
419 | int val, err; | 419 | int val, err; | |
420 | 420 | |||
421 | if (usbnet_isdying(un)) | 421 | if (usbnet_isdying(un)) | |
422 | return; | 422 | return; | |
423 | 423 | |||
424 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 424 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
425 | 425 | |||
426 | /* disable RX, TX prior to changing FDX, SPEEDSEL */ | 426 | /* disable RX, TX prior to changing FDX, SPEEDSEL */ | |
427 | val = mos_reg_read_1(un, MOS_CTL); | 427 | val = mos_reg_read_1(un, MOS_CTL); | |
428 | val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); | 428 | val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); | |
429 | mos_reg_write_1(un, MOS_CTL, val); | 429 | mos_reg_write_1(un, MOS_CTL, val); | |
430 | 430 | |||
431 | /* reset register which counts dropped frames */ | 431 | /* reset register which counts dropped frames */ | |
432 | mos_reg_write_1(un, MOS_FRAME_DROP_CNT, 0); | 432 | mos_reg_write_1(un, MOS_FRAME_DROP_CNT, 0); | |
433 | 433 | |||
434 | if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) | 434 | if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) | |
435 | val |= MOS_CTL_FDX_ENB; | 435 | val |= MOS_CTL_FDX_ENB; | |
436 | else | 436 | else | |
437 | val &= ~(MOS_CTL_FDX_ENB); | 437 | val &= ~(MOS_CTL_FDX_ENB); | |
438 | 438 | |||
439 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 439 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
440 | (IFM_ACTIVE | IFM_AVALID)) { | 440 | (IFM_ACTIVE | IFM_AVALID)) { | |
441 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 441 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
442 | case IFM_100_TX: | 442 | case IFM_100_TX: | |
443 | val |= MOS_CTL_SPEEDSEL; | 443 | val |= MOS_CTL_SPEEDSEL; | |
444 | break; | 444 | break; | |
445 | case IFM_10_T: | 445 | case IFM_10_T: | |
446 | val &= ~(MOS_CTL_SPEEDSEL); | 446 | val &= ~(MOS_CTL_SPEEDSEL); | |
447 | break; | 447 | break; | |
448 | } | 448 | } | |
449 | usbnet_set_link(un, true); | 449 | usbnet_set_link(un, true); | |
450 | } | 450 | } | |
451 | 451 | |||
452 | /* re-enable TX, RX */ | 452 | /* re-enable TX, RX */ | |
453 | val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); | 453 | val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); | |
454 | err = mos_reg_write_1(un, MOS_CTL, val); | 454 | err = mos_reg_write_1(un, MOS_CTL, val); | |
455 | 455 | |||
456 | if (err) | 456 | if (err) | |
457 | aprint_error_dev(un->un_dev, "media change failed\n"); | 457 | aprint_error_dev(un->un_dev, "media change failed\n"); | |
458 | } | 458 | } | |
459 | 459 | |||
460 | static void | 460 | static void | |
461 | mos_rcvfilt_locked(struct usbnet *un) | 461 | mos_rcvfilt_locked(struct usbnet *un) | |
462 | { | 462 | { | |
463 | struct ifnet *ifp = usbnet_ifp(un); | 463 | struct ifnet *ifp = usbnet_ifp(un); | |
464 | struct ethercom *ec = usbnet_ec(un); | 464 | struct ethercom *ec = usbnet_ec(un); | |
465 | struct ether_multi *enm; | 465 | struct ether_multi *enm; | |
466 | struct ether_multistep step; | 466 | struct ether_multistep step; | |
467 | u_int32_t h = 0; | 467 | u_int32_t h = 0; | |
468 | u_int8_t rxmode, mchash[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 468 | u_int8_t rxmode, mchash[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
469 | 469 | |||
470 | if (usbnet_isdying(un)) | 470 | if (usbnet_isdying(un)) | |
471 | return; | 471 | return; | |
472 | 472 | |||
473 | rxmode = mos_reg_read_1(un, MOS_CTL); | 473 | rxmode = mos_reg_read_1(un, MOS_CTL); | |
474 | rxmode &= ~(MOS_CTL_ALLMULTI | MOS_CTL_RX_PROMISC); | 474 | rxmode &= ~(MOS_CTL_ALLMULTI | MOS_CTL_RX_PROMISC); | |
475 | 475 | |||
476 | ETHER_LOCK(ec); | 476 | ETHER_LOCK(ec); | |
477 | if (ifp->if_flags & IFF_PROMISC) { | 477 | if (ifp->if_flags & IFF_PROMISC) { | |
478 | ec->ec_flags |= ETHER_F_ALLMULTI; | 478 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
479 | ETHER_UNLOCK(ec); | 479 | ETHER_UNLOCK(ec); | |
480 | /* run promisc. mode */ | 480 | /* run promisc. mode */ | |
481 | rxmode |= MOS_CTL_ALLMULTI; /* ??? */ | 481 | rxmode |= MOS_CTL_ALLMULTI; /* ??? */ | |
482 | rxmode |= MOS_CTL_RX_PROMISC; | 482 | rxmode |= MOS_CTL_RX_PROMISC; | |
483 | goto update; | 483 | goto update; | |
484 | } | 484 | } | |
485 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 485 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
486 | ETHER_FIRST_MULTI(step, ec, enm); | 486 | ETHER_FIRST_MULTI(step, ec, enm); | |
487 | while (enm != NULL) { | 487 | while (enm != NULL) { | |
488 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 488 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
489 | ec->ec_flags |= ETHER_F_ALLMULTI; | 489 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
490 | ETHER_UNLOCK(ec); | 490 | ETHER_UNLOCK(ec); | |
491 | memset(mchash, 0, sizeof(mchash)); /* correct ??? */ | 491 | memset(mchash, 0, sizeof(mchash)); /* correct ??? */ | |
492 | /* accept all multicast frame */ | 492 | /* accept all multicast frame */ | |
493 | rxmode |= MOS_CTL_ALLMULTI; | 493 | rxmode |= MOS_CTL_ALLMULTI; | |
494 | goto update; | 494 | goto update; | |
495 | } | 495 | } | |
496 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | 496 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | |
497 | /* 3(31:29) and 3(28:26) sampling to have uint8_t[8] */ | 497 | /* 3(31:29) and 3(28:26) sampling to have uint8_t[8] */ | |
498 | mchash[h >> 29] |= 1 << ((h >> 26) % 8); | 498 | mchash[h >> 29] |= 1 << ((h >> 26) % 8); | |
499 | ETHER_NEXT_MULTI(step, enm); | 499 | ETHER_NEXT_MULTI(step, enm); | |
500 | } | 500 | } | |
501 | ETHER_UNLOCK(ec); | 501 | ETHER_UNLOCK(ec); | |
502 | /* MOS receive filter is always on */ | 502 | /* MOS receive filter is always on */ | |
503 | update: | 503 | update: | |
504 | /* | 504 | /* | |
505 | * The datasheet claims broadcast frames were always accepted | 505 | * The datasheet claims broadcast frames were always accepted | |
506 | * regardless of filter settings. But the hardware seems to | 506 | * regardless of filter settings. But the hardware seems to | |
507 | * filter broadcast frames, so pass them explicitly. | 507 | * filter broadcast frames, so pass them explicitly. | |
508 | */ | 508 | */ | |
509 | mchash[7] |= 0x80; | 509 | mchash[7] |= 0x80; | |
510 | mos_write_mcast(un, mchash); | 510 | mos_write_mcast(un, mchash); | |
511 | mos_reg_write_1(un, MOS_CTL, rxmode); | 511 | mos_reg_write_1(un, MOS_CTL, rxmode); | |
512 | } | 512 | } | |
513 | 513 | |||
514 | static void | 514 | static void | |
515 | mos_reset(struct usbnet *un) | 515 | mos_reset(struct usbnet *un) | |
516 | { | 516 | { | |
517 | u_int8_t ctl; | 517 | u_int8_t ctl; | |
518 | 518 | |||
519 | if (usbnet_isdying(un)) | 519 | if (usbnet_isdying(un)) | |
520 | return; | 520 | return; | |
521 | 521 | |||
522 | ctl = mos_reg_read_1(un, MOS_CTL); | 522 | ctl = mos_reg_read_1(un, MOS_CTL); | |
523 | ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB | | 523 | ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB | | |
524 | MOS_CTL_RX_ENB); | 524 | MOS_CTL_RX_ENB); | |
525 | /* Disable RX, TX, promiscuous and allmulticast mode */ | 525 | /* Disable RX, TX, promiscuous and allmulticast mode */ | |
526 | mos_reg_write_1(un, MOS_CTL, ctl); | 526 | mos_reg_write_1(un, MOS_CTL, ctl); | |
527 | 527 | |||
528 | /* Reset frame drop counter register to zero */ | 528 | /* Reset frame drop counter register to zero */ | |
529 | mos_reg_write_1(un, MOS_FRAME_DROP_CNT, 0); | 529 | mos_reg_write_1(un, MOS_FRAME_DROP_CNT, 0); | |
530 | 530 | |||
531 | /* Wait a little while for the chip to get its brains in order. */ | 531 | /* Wait a little while for the chip to get its brains in order. */ | |
532 | DELAY(1000); | 532 | DELAY(1000); | |
533 | } | 533 | } | |
534 | 534 | |||
535 | void | 535 | void | |
536 | mos_chip_init(struct usbnet *un) | 536 | mos_chip_init(struct usbnet *un) | |
537 | { | 537 | { | |
538 | int i; | 538 | int i; | |
539 | 539 | |||
540 | /* | 540 | /* | |
541 | * Rev.C devices have a pause threshold register which needs to be set | 541 | * Rev.C devices have a pause threshold register which needs to be set | |
542 | * at startup. | 542 | * at startup. | |
543 | */ | 543 | */ | |
544 | if (mos_reg_read_1(un, MOS_PAUSE_TRHD) != -1) { | 544 | if (mos_reg_read_1(un, MOS_PAUSE_TRHD) != -1) { | |
545 | for (i = 0; i < MOS_PAUSE_REWRITES; i++) | 545 | for (i = 0; i < MOS_PAUSE_REWRITES; i++) | |
546 | mos_reg_write_1(un, MOS_PAUSE_TRHD, 0); | 546 | mos_reg_write_1(un, MOS_PAUSE_TRHD, 0); | |
547 | } | 547 | } | |
548 | } | 548 | } | |
549 | 549 | |||
550 | /* | 550 | /* | |
551 | * Probe for a MCS7x30 chip. | 551 | * Probe for a MCS7x30 chip. | |
552 | */ | 552 | */ | |
553 | static int | 553 | static int | |
554 | mos_match(device_t parent, cfdata_t match, void *aux) | 554 | mos_match(device_t parent, cfdata_t match, void *aux) | |
555 | { | 555 | { | |
556 | struct usb_attach_arg *uaa = aux; | 556 | struct usb_attach_arg *uaa = aux; | |
557 | 557 | |||
558 | return (mos_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 558 | return (mos_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
559 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE); | 559 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE); | |
560 | } | 560 | } | |
561 | 561 | |||
562 | /* | 562 | /* | |
563 | * Attach the interface. | 563 | * Attach the interface. | |
564 | */ | 564 | */ | |
565 | static void | 565 | static void | |
566 | mos_attach(device_t parent, device_t self, void *aux) | 566 | mos_attach(device_t parent, device_t self, void *aux) | |
567 | { | 567 | { | |
568 | USBNET_MII_DECL_DEFAULT(unm); | 568 | USBNET_MII_DECL_DEFAULT(unm); | |
569 | struct usbnet * un = device_private(self); | 569 | struct usbnet * un = device_private(self); | |
570 | struct usb_attach_arg *uaa = aux; | 570 | struct usb_attach_arg *uaa = aux; | |
571 | struct usbd_device *dev = uaa->uaa_device; | 571 | struct usbd_device *dev = uaa->uaa_device; | |
572 | usbd_status err; | 572 | usbd_status err; | |
573 | usb_interface_descriptor_t *id; | 573 | usb_interface_descriptor_t *id; | |
574 | usb_endpoint_descriptor_t *ed; | 574 | usb_endpoint_descriptor_t *ed; | |
575 | char *devinfop; | 575 | char *devinfop; | |
576 | int i; | 576 | int i; | |
577 | 577 | |||
578 | aprint_naive("\n"); | 578 | aprint_naive("\n"); | |
579 | aprint_normal("\n"); | 579 | aprint_normal("\n"); | |
580 | devinfop = usbd_devinfo_alloc(dev, 0); | 580 | devinfop = usbd_devinfo_alloc(dev, 0); | |
581 | aprint_normal_dev(self, "%s\n", devinfop); | 581 | aprint_normal_dev(self, "%s\n", devinfop); | |
582 | usbd_devinfo_free(devinfop); | 582 | usbd_devinfo_free(devinfop); | |
583 | 583 | |||
584 | un->un_dev = self; | 584 | un->un_dev = self; | |
585 | un->un_udev = dev; | 585 | un->un_udev = dev; | |
586 | un->un_sc = un; | 586 | un->un_sc = un; | |
587 | un->un_ops = &mos_ops; | 587 | un->un_ops = &mos_ops; | |
588 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 588 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
589 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 589 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
590 | un->un_rx_list_cnt = MOS_RX_LIST_CNT; | 590 | un->un_rx_list_cnt = MOS_RX_LIST_CNT; | |
591 | un->un_tx_list_cnt = MOS_TX_LIST_CNT; | 591 | un->un_tx_list_cnt = MOS_TX_LIST_CNT; | |
592 | un->un_rx_bufsz = un->un_tx_bufsz = MOS_BUFSZ; | 592 | un->un_rx_bufsz = un->un_tx_bufsz = MOS_BUFSZ; | |
593 | 593 | |||
594 | err = usbd_set_config_no(dev, MOS_CONFIG_NO, 1); | 594 | err = usbd_set_config_no(dev, MOS_CONFIG_NO, 1); | |
595 | if (err) { | 595 | if (err) { | |
596 | aprint_error_dev(self, "failed to set configuration" | 596 | aprint_error_dev(self, "failed to set configuration" | |
597 | ", err=%s\n", usbd_errstr(err)); | 597 | ", err=%s\n", usbd_errstr(err)); | |
598 | return; | 598 | return; | |
599 | } | 599 | } | |
600 | 600 | |||
601 | err = usbd_device2interface_handle(dev, MOS_IFACE_IDX, &un->un_iface); | 601 | err = usbd_device2interface_handle(dev, MOS_IFACE_IDX, &un->un_iface); | |
602 | if (err) { | 602 | if (err) { | |
603 | aprint_error_dev(self, "failed getting interface handle" | 603 | aprint_error_dev(self, "failed getting interface handle" | |
604 | ", err=%s\n", usbd_errstr(err)); | 604 | ", err=%s\n", usbd_errstr(err)); | |
605 | return; | 605 | return; | |
606 | } | 606 | } | |
607 | 607 | |||
608 | un->un_flags = mos_lookup(uaa->uaa_vendor, uaa->uaa_product)->mos_flags; | 608 | un->un_flags = mos_lookup(uaa->uaa_vendor, uaa->uaa_product)->mos_flags; | |
609 | 609 | |||
610 | id = usbd_get_interface_descriptor(un->un_iface); | 610 | id = usbd_get_interface_descriptor(un->un_iface); | |
611 | 611 | |||
612 | /* Find endpoints. */ | 612 | /* Find endpoints. */ | |
613 | for (i = 0; i < id->bNumEndpoints; i++) { | 613 | for (i = 0; i < id->bNumEndpoints; i++) { | |
614 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 614 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
615 | if (!ed) { | 615 | if (!ed) { | |
616 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 616 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
617 | return; | 617 | return; | |
618 | } | 618 | } | |
619 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 619 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
620 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 620 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
621 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 621 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
622 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 622 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
623 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 623 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
624 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 624 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
625 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 625 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
626 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 626 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
627 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 627 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
628 | } | 628 | } | |
629 | } | 629 | } | |
630 | 630 | |||
631 | if (un->un_flags & MCS7730) | 631 | if (un->un_flags & MCS7730) | |
632 | aprint_normal_dev(self, "MCS7730\n"); | 632 | aprint_normal_dev(self, "MCS7730\n"); | |
633 | else if (un->un_flags & MCS7830) | 633 | else if (un->un_flags & MCS7830) | |
634 | aprint_normal_dev(self, "MCS7830\n"); | 634 | aprint_normal_dev(self, "MCS7830\n"); | |
635 | else if (un->un_flags & MCS7832) | 635 | else if (un->un_flags & MCS7832) | |
636 | aprint_normal_dev(self, "MCS7832\n"); | 636 | aprint_normal_dev(self, "MCS7832\n"); | |
637 | 637 | |||
638 | /* Set these up now for register access. */ | 638 | /* Set these up now for register access. */ | |
639 | usbnet_attach(un, "mosdet"); | 639 | usbnet_attach(un, "mosdet"); | |
640 | 640 | |||
641 | mos_chip_init(un); | 641 | mos_chip_init(un); | |
642 | 642 | |||
643 | /* | 643 | /* | |
644 | * Read MAC address, inform the world. | 644 | * Read MAC address, inform the world. | |
645 | */ | 645 | */ | |
646 | err = mos_readmac(un); | 646 | err = mos_readmac(un); | |
647 | if (err) { | 647 | if (err) { | |
648 | aprint_error_dev(self, "couldn't read MAC address\n"); | 648 | aprint_error_dev(self, "couldn't read MAC address\n"); | |
649 | return; | 649 | return; | |
650 | } | 650 | } | |
651 | 651 | |||
652 | struct ifnet *ifp = usbnet_ifp(un); | 652 | struct ifnet *ifp = usbnet_ifp(un); | |
653 | ifp->if_capabilities = ETHERCAP_VLAN_MTU; | 653 | ifp->if_capabilities = ETHERCAP_VLAN_MTU; | |
654 | 654 | |||
655 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 655 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
656 | 0, &unm); | 656 | 0, &unm); | |
657 | } | 657 | } | |
658 | 658 | |||
659 | /* | 659 | /* | |
660 | * A frame has been uploaded: pass the resulting mbuf chain up to | 660 | * A frame has been uploaded: pass the resulting mbuf chain up to | |
661 | * the higher level protocols. | 661 | * the higher level protocols. | |
662 | */ | 662 | */ | |
663 | void | 663 | void | |
664 | mos_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) | 664 | mos_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) | |
665 | { | 665 | { | |
666 | struct ifnet *ifp = usbnet_ifp(un); | 666 | struct ifnet *ifp = usbnet_ifp(un); | |
667 | uint8_t *buf = c->unc_buf; | 667 | uint8_t *buf = c->unc_buf; | |
668 | u_int8_t rxstat; | 668 | u_int8_t rxstat; | |
669 | u_int16_t pktlen = 0; | 669 | u_int16_t pktlen = 0; | |
670 | 670 | |||
671 | DPRINTFN(5,("%s: %s: enter len %u\n", | 671 | DPRINTFN(5,("%s: %s: enter len %u\n", | |
672 | device_xname(un->un_dev), __func__, total_len)); | 672 | device_xname(un->un_dev), __func__, total_len)); | |
673 | 673 | |||
674 | if (total_len <= 1) | 674 | if (total_len <= 1) | |
675 | return; | 675 | return; | |
676 | 676 | |||
677 | /* evaluate status byte at the end */ | 677 | /* evaluate status byte at the end */ | |
678 | pktlen = total_len - 1; | 678 | pktlen = total_len - 1; | |
679 | if (pktlen > un->un_rx_bufsz) { | 679 | if (pktlen > un->un_rx_bufsz) { | |
680 | if_statinc(ifp, if_ierrors); | 680 | if_statinc(ifp, if_ierrors); | |
681 | return; | 681 | return; | |
682 | } | 682 | } | |
683 | rxstat = buf[pktlen] & MOS_RXSTS_MASK; | 683 | rxstat = buf[pktlen] & MOS_RXSTS_MASK; | |
684 | 684 | |||
685 | if (rxstat != MOS_RXSTS_VALID) { | 685 | if (rxstat != MOS_RXSTS_VALID) { | |
686 | DPRINTF(("%s: erroneous frame received: ", | 686 | DPRINTF(("%s: erroneous frame received: ", | |
687 | device_xname(un->un_dev))); | 687 | device_xname(un->un_dev))); | |
688 | if (rxstat & MOS_RXSTS_SHORT_FRAME) | 688 | if (rxstat & MOS_RXSTS_SHORT_FRAME) | |
689 | DPRINTF(("frame size less than 64 bytes\n")); | 689 | DPRINTF(("frame size less than 64 bytes\n")); | |
690 | if (rxstat & MOS_RXSTS_LARGE_FRAME) | 690 | if (rxstat & MOS_RXSTS_LARGE_FRAME) | |
691 | DPRINTF(("frame size larger than 1532 bytes\n")); | 691 | DPRINTF(("frame size larger than 1532 bytes\n")); | |
692 | if (rxstat & MOS_RXSTS_CRC_ERROR) | 692 | if (rxstat & MOS_RXSTS_CRC_ERROR) | |
693 | DPRINTF(("CRC error\n")); | 693 | DPRINTF(("CRC error\n")); | |
694 | if (rxstat & MOS_RXSTS_ALIGN_ERROR) | 694 | if (rxstat & MOS_RXSTS_ALIGN_ERROR) | |
695 | DPRINTF(("alignment error\n")); | 695 | DPRINTF(("alignment error\n")); | |
696 | if_statinc(ifp, if_ierrors); | 696 | if_statinc(ifp, if_ierrors); | |
697 | return; | 697 | return; | |
698 | } | 698 | } | |
699 | 699 | |||
700 | if (pktlen < sizeof(struct ether_header) ) { | 700 | if (pktlen < sizeof(struct ether_header) ) { | |
701 | if_statinc(ifp, if_ierrors); | 701 | if_statinc(ifp, if_ierrors); | |
702 | return; | 702 | return; | |
703 | } | 703 | } | |
704 | 704 | |||
705 | usbnet_enqueue(un, c->unc_buf, pktlen, 0, 0, 0); | 705 | usbnet_enqueue(un, c->unc_buf, pktlen, 0, 0, 0); | |
706 | } | 706 | } | |
707 | 707 | |||
708 | static unsigned | 708 | static unsigned | |
709 | mos_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 709 | mos_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
710 | { | 710 | { | |
711 | int length; | 711 | int length; | |
712 | 712 | |||
713 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | 713 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | |
714 | return 0; | 714 | return 0; | |
715 | 715 | |||
716 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | 716 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | |
717 | length = m->m_pkthdr.len; | 717 | length = m->m_pkthdr.len; | |
718 | 718 | |||
719 | DPRINTFN(5,("%s: %s: len %u\n", | 719 | DPRINTFN(5,("%s: %s: len %u\n", | |
720 | device_xname(un->un_dev), __func__, length)); | 720 | device_xname(un->un_dev), __func__, length)); | |
721 | 721 | |||
722 | return length; | 722 | return length; | |
723 | } | 723 | } | |
724 | 724 | |||
725 | static int | 725 | static int | |
726 | mos_init_locked(struct ifnet *ifp) | 726 | mos_init_locked(struct ifnet *ifp) | |
727 | { | 727 | { | |
728 | struct usbnet * const un = ifp->if_softc; | 728 | struct usbnet * const un = ifp->if_softc; | |
729 | u_int8_t rxmode; | 729 | u_int8_t rxmode; | |
730 | unsigned char ipgs[2]; | 730 | unsigned char ipgs[2]; | |
731 | 731 | |||
732 | if (usbnet_isdying(un)) | 732 | if (usbnet_isdying(un)) | |
733 | return EIO; | 733 | return EIO; | |
734 | 734 | |||
735 | /* Cancel pending I/O */ | 735 | /* Cancel pending I/O */ | |
736 | usbnet_stop(un, ifp, 1); | 736 | usbnet_stop(un, ifp, 1); | |
737 | 737 | |||
738 | /* Reset the ethernet interface. */ | 738 | /* Reset the ethernet interface. */ | |
739 | mos_reset(un); | 739 | mos_reset(un); | |
740 | 740 | |||
741 | /* Write MAC address. */ | 741 | /* Write MAC address. */ | |
742 | mos_writemac(un); | 742 | mos_writemac(un); | |
743 | 743 | |||
744 | /* Read and set transmitter IPG values */ | 744 | /* Read and set transmitter IPG values */ | |
745 | ipgs[0] = mos_reg_read_1(un, MOS_IPG0); | 745 | ipgs[0] = mos_reg_read_1(un, MOS_IPG0); | |
746 | ipgs[1] = mos_reg_read_1(un, MOS_IPG1); | 746 | ipgs[1] = mos_reg_read_1(un, MOS_IPG1); | |
747 | mos_reg_write_1(un, MOS_IPG0, ipgs[0]); | 747 | mos_reg_write_1(un, MOS_IPG0, ipgs[0]); | |
748 | mos_reg_write_1(un, MOS_IPG1, ipgs[1]); | 748 | mos_reg_write_1(un, MOS_IPG1, ipgs[1]); | |
749 | 749 | |||
750 | /* Accept multicast frame or run promisc. mode */ | 750 | /* Accept multicast frame or run promisc. mode */ | |
751 | mos_rcvfilt_locked(un); | 751 | mos_rcvfilt_locked(un); | |
752 | 752 | |||
753 | /* Enable receiver and transmitter, bridge controls speed/duplex mode */ | 753 | /* Enable receiver and transmitter, bridge controls speed/duplex mode */ | |
754 | rxmode = mos_reg_read_1(un, MOS_CTL); | 754 | rxmode = mos_reg_read_1(un, MOS_CTL); | |
755 | rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB; | 755 | rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB; | |
756 | rxmode &= ~(MOS_CTL_SLEEP); | 756 | rxmode &= ~(MOS_CTL_SLEEP); | |
757 | mos_reg_write_1(un, MOS_CTL, rxmode); | 757 | mos_reg_write_1(un, MOS_CTL, rxmode); | |
758 | 758 | |||
759 | return usbnet_init_rx_tx(un); | 759 | return usbnet_init_rx_tx(un); | |
760 | } | 760 | } | |
761 | 761 | |||
762 | static int | 762 | static int | |
763 | mos_uno_init(struct ifnet *ifp) | 763 | mos_uno_init(struct ifnet *ifp) | |
764 | { | 764 | { | |
765 | int ret = mos_init_locked(ifp); | 765 | int ret = mos_init_locked(ifp); | |
766 | 766 | |||
767 | return ret; | 767 | return ret; | |
768 | } | 768 | } | |
769 | 769 | |||
770 | static void | 770 | static void | |
771 | mos_uno_mcast(struct ifnet *ifp) | 771 | mos_uno_mcast(struct ifnet *ifp) | |
772 | { | 772 | { | |
773 | struct usbnet * const un = ifp->if_softc; | 773 | struct usbnet * const un = ifp->if_softc; | |
774 | 774 | |||
775 | usbnet_lock_core(un); | 775 | usbnet_lock_core(un); | |
776 | usbnet_busy(un); | |||
777 | 776 | |||
778 | mos_rcvfilt_locked(un); | 777 | mos_rcvfilt_locked(un); | |
779 | 778 | |||
780 | usbnet_unbusy(un); | |||
781 | usbnet_unlock_core(un); | 779 | usbnet_unlock_core(un); | |
782 | } | 780 | } | |
783 | 781 | |||
784 | void | 782 | void | |
785 | mos_uno_stop(struct ifnet *ifp, int disable) | 783 | mos_uno_stop(struct ifnet *ifp, int disable) | |
786 | { | 784 | { | |
787 | struct usbnet * const un = ifp->if_softc; | 785 | struct usbnet * const un = ifp->if_softc; | |
788 | 786 | |||
789 | mos_reset(un); | 787 | mos_reset(un); | |
790 | } | 788 | } |
--- src/sys/dev/usb/if_mue.c 2022/03/03 05:51:17 1.67
+++ src/sys/dev/usb/if_mue.c 2022/03/03 05:51:27 1.68
@@ -1,1329 +1,1327 @@ | @@ -1,1329 +1,1327 @@ | |||
1 | /* $NetBSD: if_mue.c,v 1.67 2022/03/03 05:51:17 riastradh Exp $ */ | 1 | /* $NetBSD: if_mue.c,v 1.68 2022/03/03 05:51:27 riastradh Exp $ */ | |
2 | /* $OpenBSD: if_mue.c,v 1.3 2018/08/04 16:42:46 jsg Exp $ */ | 2 | /* $OpenBSD: if_mue.c,v 1.3 2018/08/04 16:42:46 jsg Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2018 Kevin Lo <kevlo@openbsd.org> | 5 | * Copyright (c) 2018 Kevin Lo <kevlo@openbsd.org> | |
6 | * | 6 | * | |
7 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any | |
8 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above | |
9 | * copyright notice and this permission notice appear in all copies. | 9 | * copyright notice and this permission notice appear in all copies. | |
10 | * | 10 | * | |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
18 | */ | 18 | */ | |
19 | 19 | |||
20 | /* Driver for Microchip LAN7500/LAN7800 chipsets. */ | 20 | /* Driver for Microchip LAN7500/LAN7800 chipsets. */ | |
21 | 21 | |||
22 | #include <sys/cdefs.h> | 22 | #include <sys/cdefs.h> | |
23 | __KERNEL_RCSID(0, "$NetBSD: if_mue.c,v 1.67 2022/03/03 05:51:17 riastradh Exp $"); | 23 | __KERNEL_RCSID(0, "$NetBSD: if_mue.c,v 1.68 2022/03/03 05:51:27 riastradh Exp $"); | |
24 | 24 | |||
25 | #ifdef _KERNEL_OPT | 25 | #ifdef _KERNEL_OPT | |
26 | #include "opt_usb.h" | 26 | #include "opt_usb.h" | |
27 | #include "opt_inet.h" | 27 | #include "opt_inet.h" | |
28 | #endif | 28 | #endif | |
29 | 29 | |||
30 | #include <sys/param.h> | 30 | #include <sys/param.h> | |
31 | 31 | |||
32 | #include <dev/usb/usbnet.h> | 32 | #include <dev/usb/usbnet.h> | |
33 | 33 | |||
34 | #include <dev/usb/if_muereg.h> | 34 | #include <dev/usb/if_muereg.h> | |
35 | #include <dev/usb/if_muevar.h> | 35 | #include <dev/usb/if_muevar.h> | |
36 | 36 | |||
37 | #define MUE_PRINTF(un, fmt, args...) \ | 37 | #define MUE_PRINTF(un, fmt, args...) \ | |
38 | device_printf((un)->un_dev, "%s: " fmt, __func__, ##args); | 38 | device_printf((un)->un_dev, "%s: " fmt, __func__, ##args); | |
39 | 39 | |||
40 | #ifdef USB_DEBUG | 40 | #ifdef USB_DEBUG | |
41 | int muedebug = 0; | 41 | int muedebug = 0; | |
42 | #define DPRINTF(un, fmt, args...) \ | 42 | #define DPRINTF(un, fmt, args...) \ | |
43 | do { \ | 43 | do { \ | |
44 | if (muedebug) \ | 44 | if (muedebug) \ | |
45 | MUE_PRINTF(un, fmt, ##args); \ | 45 | MUE_PRINTF(un, fmt, ##args); \ | |
46 | } while (0 /* CONSTCOND */) | 46 | } while (0 /* CONSTCOND */) | |
47 | #else | 47 | #else | |
48 | #define DPRINTF(un, fmt, args...) __nothing | 48 | #define DPRINTF(un, fmt, args...) __nothing | |
49 | #endif | 49 | #endif | |
50 | 50 | |||
51 | /* | 51 | /* | |
52 | * Various supported device vendors/products. | 52 | * Various supported device vendors/products. | |
53 | */ | 53 | */ | |
54 | struct mue_type { | 54 | struct mue_type { | |
55 | struct usb_devno mue_dev; | 55 | struct usb_devno mue_dev; | |
56 | uint16_t mue_flags; | 56 | uint16_t mue_flags; | |
57 | #define LAN7500 0x0001 /* LAN7500 */ | 57 | #define LAN7500 0x0001 /* LAN7500 */ | |
58 | #define LAN7800 0x0002 /* LAN7800 */ | 58 | #define LAN7800 0x0002 /* LAN7800 */ | |
59 | #define LAN7801 0x0004 /* LAN7801 */ | 59 | #define LAN7801 0x0004 /* LAN7801 */ | |
60 | #define LAN7850 0x0008 /* LAN7850 */ | 60 | #define LAN7850 0x0008 /* LAN7850 */ | |
61 | }; | 61 | }; | |
62 | 62 | |||
63 | static const struct mue_type mue_devs[] = { | 63 | static const struct mue_type mue_devs[] = { | |
64 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7500 }, LAN7500 }, | 64 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7500 }, LAN7500 }, | |
65 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7505 }, LAN7500 }, | 65 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7505 }, LAN7500 }, | |
66 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7800 }, LAN7800 }, | 66 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7800 }, LAN7800 }, | |
67 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7801 }, LAN7801 }, | 67 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7801 }, LAN7801 }, | |
68 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7850 }, LAN7850 } | 68 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7850 }, LAN7850 } | |
69 | }; | 69 | }; | |
70 | 70 | |||
71 | #define MUE_LOOKUP(uaa) ((const struct mue_type *)usb_lookup(mue_devs, \ | 71 | #define MUE_LOOKUP(uaa) ((const struct mue_type *)usb_lookup(mue_devs, \ | |
72 | uaa->uaa_vendor, uaa->uaa_product)) | 72 | uaa->uaa_vendor, uaa->uaa_product)) | |
73 | 73 | |||
74 | #define MUE_ENADDR_LO(enaddr) \ | 74 | #define MUE_ENADDR_LO(enaddr) \ | |
75 | ((enaddr[3] << 24) | (enaddr[2] << 16) | (enaddr[1] << 8) | enaddr[0]) | 75 | ((enaddr[3] << 24) | (enaddr[2] << 16) | (enaddr[1] << 8) | enaddr[0]) | |
76 | #define MUE_ENADDR_HI(enaddr) \ | 76 | #define MUE_ENADDR_HI(enaddr) \ | |
77 | ((enaddr[5] << 8) | enaddr[4]) | 77 | ((enaddr[5] << 8) | enaddr[4]) | |
78 | 78 | |||
79 | static int mue_match(device_t, cfdata_t, void *); | 79 | static int mue_match(device_t, cfdata_t, void *); | |
80 | static void mue_attach(device_t, device_t, void *); | 80 | static void mue_attach(device_t, device_t, void *); | |
81 | 81 | |||
82 | static uint32_t mue_csr_read(struct usbnet *, uint32_t); | 82 | static uint32_t mue_csr_read(struct usbnet *, uint32_t); | |
83 | static int mue_csr_write(struct usbnet *, uint32_t, uint32_t); | 83 | static int mue_csr_write(struct usbnet *, uint32_t, uint32_t); | |
84 | static int mue_wait_for_bits(struct usbnet *, uint32_t, uint32_t, | 84 | static int mue_wait_for_bits(struct usbnet *, uint32_t, uint32_t, | |
85 | uint32_t, uint32_t); | 85 | uint32_t, uint32_t); | |
86 | static uint8_t mue_eeprom_getbyte(struct usbnet *, int, uint8_t *); | 86 | static uint8_t mue_eeprom_getbyte(struct usbnet *, int, uint8_t *); | |
87 | static bool mue_eeprom_present(struct usbnet *); | 87 | static bool mue_eeprom_present(struct usbnet *); | |
88 | static void mue_dataport_write(struct usbnet *, uint32_t, uint32_t, | 88 | static void mue_dataport_write(struct usbnet *, uint32_t, uint32_t, | |
89 | uint32_t, uint32_t *); | 89 | uint32_t, uint32_t *); | |
90 | static void mue_init_ltm(struct usbnet *); | 90 | static void mue_init_ltm(struct usbnet *); | |
91 | static int mue_chip_init(struct usbnet *); | 91 | static int mue_chip_init(struct usbnet *); | |
92 | static void mue_set_macaddr(struct usbnet *); | 92 | static void mue_set_macaddr(struct usbnet *); | |
93 | static int mue_get_macaddr(struct usbnet *, prop_dictionary_t); | 93 | static int mue_get_macaddr(struct usbnet *, prop_dictionary_t); | |
94 | static int mue_prepare_tso(struct usbnet *, struct mbuf *); | 94 | static int mue_prepare_tso(struct usbnet *, struct mbuf *); | |
95 | static void mue_setiff_locked(struct usbnet *); | 95 | static void mue_setiff_locked(struct usbnet *); | |
96 | static void mue_sethwcsum_locked(struct usbnet *); | 96 | static void mue_sethwcsum_locked(struct usbnet *); | |
97 | static void mue_setmtu_locked(struct usbnet *); | 97 | static void mue_setmtu_locked(struct usbnet *); | |
98 | static void mue_reset(struct usbnet *); | 98 | static void mue_reset(struct usbnet *); | |
99 | 99 | |||
100 | static void mue_uno_stop(struct ifnet *, int); | 100 | static void mue_uno_stop(struct ifnet *, int); | |
101 | static int mue_uno_ioctl(struct ifnet *, u_long, void *); | 101 | static int mue_uno_ioctl(struct ifnet *, u_long, void *); | |
102 | static void mue_uno_mcast(struct ifnet *); | 102 | static void mue_uno_mcast(struct ifnet *); | |
103 | static int mue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 103 | static int mue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
104 | static int mue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 104 | static int mue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
105 | static void mue_uno_mii_statchg(struct ifnet *); | 105 | static void mue_uno_mii_statchg(struct ifnet *); | |
106 | static void mue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 106 | static void mue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
107 | uint32_t); | 107 | uint32_t); | |
108 | static unsigned mue_uno_tx_prepare(struct usbnet *, struct mbuf *, | 108 | static unsigned mue_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
109 | struct usbnet_chain *); | 109 | struct usbnet_chain *); | |
110 | static int mue_uno_init(struct ifnet *); | 110 | static int mue_uno_init(struct ifnet *); | |
111 | 111 | |||
112 | static const struct usbnet_ops mue_ops = { | 112 | static const struct usbnet_ops mue_ops = { | |
113 | .uno_stop = mue_uno_stop, | 113 | .uno_stop = mue_uno_stop, | |
114 | .uno_ioctl = mue_uno_ioctl, | 114 | .uno_ioctl = mue_uno_ioctl, | |
115 | .uno_mcast = mue_uno_mcast, | 115 | .uno_mcast = mue_uno_mcast, | |
116 | .uno_read_reg = mue_uno_mii_read_reg, | 116 | .uno_read_reg = mue_uno_mii_read_reg, | |
117 | .uno_write_reg = mue_uno_mii_write_reg, | 117 | .uno_write_reg = mue_uno_mii_write_reg, | |
118 | .uno_statchg = mue_uno_mii_statchg, | 118 | .uno_statchg = mue_uno_mii_statchg, | |
119 | .uno_tx_prepare = mue_uno_tx_prepare, | 119 | .uno_tx_prepare = mue_uno_tx_prepare, | |
120 | .uno_rx_loop = mue_uno_rx_loop, | 120 | .uno_rx_loop = mue_uno_rx_loop, | |
121 | .uno_init = mue_uno_init, | 121 | .uno_init = mue_uno_init, | |
122 | }; | 122 | }; | |
123 | 123 | |||
124 | #define MUE_SETBIT(un, reg, x) \ | 124 | #define MUE_SETBIT(un, reg, x) \ | |
125 | mue_csr_write(un, reg, mue_csr_read(un, reg) | (x)) | 125 | mue_csr_write(un, reg, mue_csr_read(un, reg) | (x)) | |
126 | 126 | |||
127 | #define MUE_CLRBIT(un, reg, x) \ | 127 | #define MUE_CLRBIT(un, reg, x) \ | |
128 | mue_csr_write(un, reg, mue_csr_read(un, reg) & ~(x)) | 128 | mue_csr_write(un, reg, mue_csr_read(un, reg) & ~(x)) | |
129 | 129 | |||
130 | #define MUE_WAIT_SET(un, reg, set, fail) \ | 130 | #define MUE_WAIT_SET(un, reg, set, fail) \ | |
131 | mue_wait_for_bits(un, reg, set, ~0, fail) | 131 | mue_wait_for_bits(un, reg, set, ~0, fail) | |
132 | 132 | |||
133 | #define MUE_WAIT_CLR(un, reg, clear, fail) \ | 133 | #define MUE_WAIT_CLR(un, reg, clear, fail) \ | |
134 | mue_wait_for_bits(un, reg, 0, clear, fail) | 134 | mue_wait_for_bits(un, reg, 0, clear, fail) | |
135 | 135 | |||
136 | #define ETHER_IS_VALID(addr) \ | 136 | #define ETHER_IS_VALID(addr) \ | |
137 | (!ETHER_IS_MULTICAST(addr) && !ETHER_IS_ZERO(addr)) | 137 | (!ETHER_IS_MULTICAST(addr) && !ETHER_IS_ZERO(addr)) | |
138 | 138 | |||
139 | #define ETHER_IS_ZERO(addr) \ | 139 | #define ETHER_IS_ZERO(addr) \ | |
140 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | 140 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | |
141 | 141 | |||
142 | CFATTACH_DECL_NEW(mue, sizeof(struct usbnet), mue_match, mue_attach, | 142 | CFATTACH_DECL_NEW(mue, sizeof(struct usbnet), mue_match, mue_attach, | |
143 | usbnet_detach, usbnet_activate); | 143 | usbnet_detach, usbnet_activate); | |
144 | 144 | |||
145 | static uint32_t | 145 | static uint32_t | |
146 | mue_csr_read(struct usbnet *un, uint32_t reg) | 146 | mue_csr_read(struct usbnet *un, uint32_t reg) | |
147 | { | 147 | { | |
148 | usb_device_request_t req; | 148 | usb_device_request_t req; | |
149 | usbd_status err; | 149 | usbd_status err; | |
150 | uDWord val; | 150 | uDWord val; | |
151 | 151 | |||
152 | if (usbnet_isdying(un)) | 152 | if (usbnet_isdying(un)) | |
153 | return 0; | 153 | return 0; | |
154 | 154 | |||
155 | USETDW(val, 0); | 155 | USETDW(val, 0); | |
156 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 156 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
157 | req.bRequest = MUE_UR_READREG; | 157 | req.bRequest = MUE_UR_READREG; | |
158 | USETW(req.wValue, 0); | 158 | USETW(req.wValue, 0); | |
159 | USETW(req.wIndex, reg); | 159 | USETW(req.wIndex, reg); | |
160 | USETW(req.wLength, 4); | 160 | USETW(req.wLength, 4); | |
161 | 161 | |||
162 | err = usbd_do_request(un->un_udev, &req, &val); | 162 | err = usbd_do_request(un->un_udev, &req, &val); | |
163 | if (err) { | 163 | if (err) { | |
164 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | 164 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | |
165 | return 0; | 165 | return 0; | |
166 | } | 166 | } | |
167 | 167 | |||
168 | return UGETDW(val); | 168 | return UGETDW(val); | |
169 | } | 169 | } | |
170 | 170 | |||
171 | static int | 171 | static int | |
172 | mue_csr_write(struct usbnet *un, uint32_t reg, uint32_t aval) | 172 | mue_csr_write(struct usbnet *un, uint32_t reg, uint32_t aval) | |
173 | { | 173 | { | |
174 | usb_device_request_t req; | 174 | usb_device_request_t req; | |
175 | usbd_status err; | 175 | usbd_status err; | |
176 | uDWord val; | 176 | uDWord val; | |
177 | 177 | |||
178 | if (usbnet_isdying(un)) | 178 | if (usbnet_isdying(un)) | |
179 | return 0; | 179 | return 0; | |
180 | 180 | |||
181 | USETDW(val, aval); | 181 | USETDW(val, aval); | |
182 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 182 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
183 | req.bRequest = MUE_UR_WRITEREG; | 183 | req.bRequest = MUE_UR_WRITEREG; | |
184 | USETW(req.wValue, 0); | 184 | USETW(req.wValue, 0); | |
185 | USETW(req.wIndex, reg); | 185 | USETW(req.wIndex, reg); | |
186 | USETW(req.wLength, 4); | 186 | USETW(req.wLength, 4); | |
187 | 187 | |||
188 | err = usbd_do_request(un->un_udev, &req, &val); | 188 | err = usbd_do_request(un->un_udev, &req, &val); | |
189 | if (err) { | 189 | if (err) { | |
190 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | 190 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | |
191 | return -1; | 191 | return -1; | |
192 | } | 192 | } | |
193 | 193 | |||
194 | return 0; | 194 | return 0; | |
195 | } | 195 | } | |
196 | 196 | |||
197 | static int | 197 | static int | |
198 | mue_wait_for_bits(struct usbnet *un, uint32_t reg, | 198 | mue_wait_for_bits(struct usbnet *un, uint32_t reg, | |
199 | uint32_t set, uint32_t clear, uint32_t fail) | 199 | uint32_t set, uint32_t clear, uint32_t fail) | |
200 | { | 200 | { | |
201 | uint32_t val; | 201 | uint32_t val; | |
202 | int ntries; | 202 | int ntries; | |
203 | 203 | |||
204 | for (ntries = 0; ntries < 1000; ntries++) { | 204 | for (ntries = 0; ntries < 1000; ntries++) { | |
205 | if (usbnet_isdying(un)) | 205 | if (usbnet_isdying(un)) | |
206 | return 1; | 206 | return 1; | |
207 | val = mue_csr_read(un, reg); | 207 | val = mue_csr_read(un, reg); | |
208 | if ((val & set) || !(val & clear)) | 208 | if ((val & set) || !(val & clear)) | |
209 | return 0; | 209 | return 0; | |
210 | if (val & fail) | 210 | if (val & fail) | |
211 | return 1; | 211 | return 1; | |
212 | usbd_delay_ms(un->un_udev, 1); | 212 | usbd_delay_ms(un->un_udev, 1); | |
213 | } | 213 | } | |
214 | 214 | |||
215 | return 1; | 215 | return 1; | |
216 | } | 216 | } | |
217 | 217 | |||
218 | static int | 218 | static int | |
219 | mue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 219 | mue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
220 | { | 220 | { | |
221 | uint32_t data; | 221 | uint32_t data; | |
222 | 222 | |||
223 | if (un->un_phyno != phy) | 223 | if (un->un_phyno != phy) | |
224 | return EINVAL; | 224 | return EINVAL; | |
225 | 225 | |||
226 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 226 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
227 | MUE_PRINTF(un, "not ready\n"); | 227 | MUE_PRINTF(un, "not ready\n"); | |
228 | return EBUSY; | 228 | return EBUSY; | |
229 | } | 229 | } | |
230 | 230 | |||
231 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_READ | | 231 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_READ | | |
232 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | 232 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | |
233 | MUE_MII_ACCESS_PHYADDR(phy)); | 233 | MUE_MII_ACCESS_PHYADDR(phy)); | |
234 | 234 | |||
235 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 235 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
236 | MUE_PRINTF(un, "timed out\n"); | 236 | MUE_PRINTF(un, "timed out\n"); | |
237 | return ETIMEDOUT; | 237 | return ETIMEDOUT; | |
238 | } | 238 | } | |
239 | 239 | |||
240 | data = mue_csr_read(un, MUE_MII_DATA); | 240 | data = mue_csr_read(un, MUE_MII_DATA); | |
241 | *val = data & 0xffff; | 241 | *val = data & 0xffff; | |
242 | 242 | |||
243 | return 0; | 243 | return 0; | |
244 | } | 244 | } | |
245 | 245 | |||
246 | static int | 246 | static int | |
247 | mue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 247 | mue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
248 | { | 248 | { | |
249 | 249 | |||
250 | if (un->un_phyno != phy) | 250 | if (un->un_phyno != phy) | |
251 | return EINVAL; | 251 | return EINVAL; | |
252 | 252 | |||
253 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 253 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
254 | MUE_PRINTF(un, "not ready\n"); | 254 | MUE_PRINTF(un, "not ready\n"); | |
255 | return EBUSY; | 255 | return EBUSY; | |
256 | } | 256 | } | |
257 | 257 | |||
258 | mue_csr_write(un, MUE_MII_DATA, val); | 258 | mue_csr_write(un, MUE_MII_DATA, val); | |
259 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_WRITE | | 259 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_WRITE | | |
260 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | 260 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | |
261 | MUE_MII_ACCESS_PHYADDR(phy)); | 261 | MUE_MII_ACCESS_PHYADDR(phy)); | |
262 | 262 | |||
263 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 263 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
264 | MUE_PRINTF(un, "timed out\n"); | 264 | MUE_PRINTF(un, "timed out\n"); | |
265 | return ETIMEDOUT; | 265 | return ETIMEDOUT; | |
266 | } | 266 | } | |
267 | 267 | |||
268 | return 0; | 268 | return 0; | |
269 | } | 269 | } | |
270 | 270 | |||
271 | static void | 271 | static void | |
272 | mue_uno_mii_statchg(struct ifnet *ifp) | 272 | mue_uno_mii_statchg(struct ifnet *ifp) | |
273 | { | 273 | { | |
274 | struct usbnet * const un = ifp->if_softc; | 274 | struct usbnet * const un = ifp->if_softc; | |
275 | struct mii_data * const mii = usbnet_mii(un); | 275 | struct mii_data * const mii = usbnet_mii(un); | |
276 | uint32_t flow, threshold; | 276 | uint32_t flow, threshold; | |
277 | 277 | |||
278 | if (usbnet_isdying(un)) | 278 | if (usbnet_isdying(un)) | |
279 | return; | 279 | return; | |
280 | 280 | |||
281 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 281 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
282 | (IFM_ACTIVE | IFM_AVALID)) { | 282 | (IFM_ACTIVE | IFM_AVALID)) { | |
283 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 283 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
284 | case IFM_10_T: | 284 | case IFM_10_T: | |
285 | case IFM_100_TX: | 285 | case IFM_100_TX: | |
286 | case IFM_1000_T: | 286 | case IFM_1000_T: | |
287 | usbnet_set_link(un, true); | 287 | usbnet_set_link(un, true); | |
288 | break; | 288 | break; | |
289 | default: | 289 | default: | |
290 | break; | 290 | break; | |
291 | } | 291 | } | |
292 | } | 292 | } | |
293 | 293 | |||
294 | /* Lost link, do nothing. */ | 294 | /* Lost link, do nothing. */ | |
295 | if (!usbnet_havelink(un)) { | 295 | if (!usbnet_havelink(un)) { | |
296 | DPRINTF(un, "mii_media_status = %#x\n", mii->mii_media_status); | 296 | DPRINTF(un, "mii_media_status = %#x\n", mii->mii_media_status); | |
297 | return; | 297 | return; | |
298 | } | 298 | } | |
299 | 299 | |||
300 | if (!(un->un_flags & LAN7500)) { | 300 | if (!(un->un_flags & LAN7500)) { | |
301 | if (un->un_udev->ud_speed == USB_SPEED_SUPER) { | 301 | if (un->un_udev->ud_speed == USB_SPEED_SUPER) { | |
302 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { | 302 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { | |
303 | /* Disable U2 and enable U1. */ | 303 | /* Disable U2 and enable U1. */ | |
304 | MUE_CLRBIT(un, MUE_USB_CFG1, | 304 | MUE_CLRBIT(un, MUE_USB_CFG1, | |
305 | MUE_USB_CFG1_DEV_U2_INIT_EN); | 305 | MUE_USB_CFG1_DEV_U2_INIT_EN); | |
306 | MUE_SETBIT(un, MUE_USB_CFG1, | 306 | MUE_SETBIT(un, MUE_USB_CFG1, | |
307 | MUE_USB_CFG1_DEV_U1_INIT_EN); | 307 | MUE_USB_CFG1_DEV_U1_INIT_EN); | |
308 | } else { | 308 | } else { | |
309 | /* Enable U1 and U2. */ | 309 | /* Enable U1 and U2. */ | |
310 | MUE_SETBIT(un, MUE_USB_CFG1, | 310 | MUE_SETBIT(un, MUE_USB_CFG1, | |
311 | MUE_USB_CFG1_DEV_U1_INIT_EN | | 311 | MUE_USB_CFG1_DEV_U1_INIT_EN | | |
312 | MUE_USB_CFG1_DEV_U2_INIT_EN); | 312 | MUE_USB_CFG1_DEV_U2_INIT_EN); | |
313 | } | 313 | } | |
314 | } | 314 | } | |
315 | } | 315 | } | |
316 | 316 | |||
317 | flow = 0; | 317 | flow = 0; | |
318 | /* XXX Linux does not check IFM_FDX flag for 7800. */ | 318 | /* XXX Linux does not check IFM_FDX flag for 7800. */ | |
319 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { | 319 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { | |
320 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) | 320 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) | |
321 | flow |= MUE_FLOW_TX_FCEN | MUE_FLOW_PAUSE_TIME; | 321 | flow |= MUE_FLOW_TX_FCEN | MUE_FLOW_PAUSE_TIME; | |
322 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) | 322 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) | |
323 | flow |= MUE_FLOW_RX_FCEN; | 323 | flow |= MUE_FLOW_RX_FCEN; | |
324 | } | 324 | } | |
325 | 325 | |||
326 | /* XXX Magic numbers taken from Linux driver. */ | 326 | /* XXX Magic numbers taken from Linux driver. */ | |
327 | if (un->un_flags & LAN7500) | 327 | if (un->un_flags & LAN7500) | |
328 | threshold = 0x820; | 328 | threshold = 0x820; | |
329 | else | 329 | else | |
330 | switch (un->un_udev->ud_speed) { | 330 | switch (un->un_udev->ud_speed) { | |
331 | case USB_SPEED_SUPER: | 331 | case USB_SPEED_SUPER: | |
332 | threshold = 0x817; | 332 | threshold = 0x817; | |
333 | break; | 333 | break; | |
334 | case USB_SPEED_HIGH: | 334 | case USB_SPEED_HIGH: | |
335 | threshold = 0x211; | 335 | threshold = 0x211; | |
336 | break; | 336 | break; | |
337 | default: | 337 | default: | |
338 | threshold = 0; | 338 | threshold = 0; | |
339 | break; | 339 | break; | |
340 | } | 340 | } | |
341 | 341 | |||
342 | /* Threshold value should be set before enabling flow. */ | 342 | /* Threshold value should be set before enabling flow. */ | |
343 | mue_csr_write(un, (un->un_flags & LAN7500) ? | 343 | mue_csr_write(un, (un->un_flags & LAN7500) ? | |
344 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, threshold); | 344 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, threshold); | |
345 | mue_csr_write(un, MUE_FLOW, flow); | 345 | mue_csr_write(un, MUE_FLOW, flow); | |
346 | 346 | |||
347 | DPRINTF(un, "done\n"); | 347 | DPRINTF(un, "done\n"); | |
348 | } | 348 | } | |
349 | 349 | |||
350 | static uint8_t | 350 | static uint8_t | |
351 | mue_eeprom_getbyte(struct usbnet *un, int off, uint8_t *dest) | 351 | mue_eeprom_getbyte(struct usbnet *un, int off, uint8_t *dest) | |
352 | { | 352 | { | |
353 | uint32_t val; | 353 | uint32_t val; | |
354 | 354 | |||
355 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, 0)) { | 355 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, 0)) { | |
356 | MUE_PRINTF(un, "not ready\n"); | 356 | MUE_PRINTF(un, "not ready\n"); | |
357 | return ETIMEDOUT; | 357 | return ETIMEDOUT; | |
358 | } | 358 | } | |
359 | 359 | |||
360 | KASSERT((off & ~MUE_E2P_CMD_ADDR_MASK) == 0); | 360 | KASSERT((off & ~MUE_E2P_CMD_ADDR_MASK) == 0); | |
361 | mue_csr_write(un, MUE_E2P_CMD, MUE_E2P_CMD_READ | MUE_E2P_CMD_BUSY | | 361 | mue_csr_write(un, MUE_E2P_CMD, MUE_E2P_CMD_READ | MUE_E2P_CMD_BUSY | | |
362 | off); | 362 | off); | |
363 | 363 | |||
364 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, | 364 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, | |
365 | MUE_E2P_CMD_TIMEOUT)) { | 365 | MUE_E2P_CMD_TIMEOUT)) { | |
366 | MUE_PRINTF(un, "timed out\n"); | 366 | MUE_PRINTF(un, "timed out\n"); | |
367 | return ETIMEDOUT; | 367 | return ETIMEDOUT; | |
368 | } | 368 | } | |
369 | 369 | |||
370 | val = mue_csr_read(un, MUE_E2P_DATA); | 370 | val = mue_csr_read(un, MUE_E2P_DATA); | |
371 | *dest = val & 0xff; | 371 | *dest = val & 0xff; | |
372 | 372 | |||
373 | return 0; | 373 | return 0; | |
374 | } | 374 | } | |
375 | 375 | |||
376 | static int | 376 | static int | |
377 | mue_read_eeprom(struct usbnet *un, uint8_t *dest, int off, int cnt) | 377 | mue_read_eeprom(struct usbnet *un, uint8_t *dest, int off, int cnt) | |
378 | { | 378 | { | |
379 | uint32_t val = 0; /* XXX gcc */ | 379 | uint32_t val = 0; /* XXX gcc */ | |
380 | uint8_t byte; | 380 | uint8_t byte; | |
381 | int i, err = 0; | 381 | int i, err = 0; | |
382 | 382 | |||
383 | /* | 383 | /* | |
384 | * EEPROM pins are muxed with the LED function on LAN7800 device. | 384 | * EEPROM pins are muxed with the LED function on LAN7800 device. | |
385 | */ | 385 | */ | |
386 | if (un->un_flags & LAN7800) { | 386 | if (un->un_flags & LAN7800) { | |
387 | val = mue_csr_read(un, MUE_HW_CFG); | 387 | val = mue_csr_read(un, MUE_HW_CFG); | |
388 | mue_csr_write(un, MUE_HW_CFG, | 388 | mue_csr_write(un, MUE_HW_CFG, | |
389 | val & ~(MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN)); | 389 | val & ~(MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN)); | |
390 | } | 390 | } | |
391 | 391 | |||
392 | for (i = 0; i < cnt; i++) { | 392 | for (i = 0; i < cnt; i++) { | |
393 | err = mue_eeprom_getbyte(un, off + i, &byte); | 393 | err = mue_eeprom_getbyte(un, off + i, &byte); | |
394 | if (err) | 394 | if (err) | |
395 | break; | 395 | break; | |
396 | *(dest + i) = byte; | 396 | *(dest + i) = byte; | |
397 | } | 397 | } | |
398 | 398 | |||
399 | if (un->un_flags & LAN7800) | 399 | if (un->un_flags & LAN7800) | |
400 | mue_csr_write(un, MUE_HW_CFG, val); | 400 | mue_csr_write(un, MUE_HW_CFG, val); | |
401 | 401 | |||
402 | return err ? 1 : 0; | 402 | return err ? 1 : 0; | |
403 | } | 403 | } | |
404 | 404 | |||
405 | static bool | 405 | static bool | |
406 | mue_eeprom_present(struct usbnet *un) | 406 | mue_eeprom_present(struct usbnet *un) | |
407 | { | 407 | { | |
408 | uint32_t val; | 408 | uint32_t val; | |
409 | uint8_t sig; | 409 | uint8_t sig; | |
410 | int ret; | 410 | int ret; | |
411 | 411 | |||
412 | if (un->un_flags & LAN7500) { | 412 | if (un->un_flags & LAN7500) { | |
413 | val = mue_csr_read(un, MUE_E2P_CMD); | 413 | val = mue_csr_read(un, MUE_E2P_CMD); | |
414 | return val & MUE_E2P_CMD_LOADED; | 414 | return val & MUE_E2P_CMD_LOADED; | |
415 | } else { | 415 | } else { | |
416 | ret = mue_read_eeprom(un, &sig, MUE_E2P_IND_OFFSET, 1); | 416 | ret = mue_read_eeprom(un, &sig, MUE_E2P_IND_OFFSET, 1); | |
417 | return (ret == 0) && (sig == MUE_E2P_IND); | 417 | return (ret == 0) && (sig == MUE_E2P_IND); | |
418 | } | 418 | } | |
419 | } | 419 | } | |
420 | 420 | |||
421 | static int | 421 | static int | |
422 | mue_read_otp_raw(struct usbnet *un, uint8_t *dest, int off, int cnt) | 422 | mue_read_otp_raw(struct usbnet *un, uint8_t *dest, int off, int cnt) | |
423 | { | 423 | { | |
424 | uint32_t val; | 424 | uint32_t val; | |
425 | int i, err; | 425 | int i, err; | |
426 | 426 | |||
427 | val = mue_csr_read(un, MUE_OTP_PWR_DN); | 427 | val = mue_csr_read(un, MUE_OTP_PWR_DN); | |
428 | 428 | |||
429 | /* Checking if bit is set. */ | 429 | /* Checking if bit is set. */ | |
430 | if (val & MUE_OTP_PWR_DN_PWRDN_N) { | 430 | if (val & MUE_OTP_PWR_DN_PWRDN_N) { | |
431 | /* Clear it, then wait for it to be cleared. */ | 431 | /* Clear it, then wait for it to be cleared. */ | |
432 | mue_csr_write(un, MUE_OTP_PWR_DN, 0); | 432 | mue_csr_write(un, MUE_OTP_PWR_DN, 0); | |
433 | err = MUE_WAIT_CLR(un, MUE_OTP_PWR_DN, MUE_OTP_PWR_DN_PWRDN_N, | 433 | err = MUE_WAIT_CLR(un, MUE_OTP_PWR_DN, MUE_OTP_PWR_DN_PWRDN_N, | |
434 | 0); | 434 | 0); | |
435 | if (err) { | 435 | if (err) { | |
436 | MUE_PRINTF(un, "not ready\n"); | 436 | MUE_PRINTF(un, "not ready\n"); | |
437 | return 1; | 437 | return 1; | |
438 | } | 438 | } | |
439 | } | 439 | } | |
440 | 440 | |||
441 | /* Start reading the bytes, one at a time. */ | 441 | /* Start reading the bytes, one at a time. */ | |
442 | for (i = 0; i < cnt; i++) { | 442 | for (i = 0; i < cnt; i++) { | |
443 | mue_csr_write(un, MUE_OTP_ADDR1, | 443 | mue_csr_write(un, MUE_OTP_ADDR1, | |
444 | ((off + i) >> 8) & MUE_OTP_ADDR1_MASK); | 444 | ((off + i) >> 8) & MUE_OTP_ADDR1_MASK); | |
445 | mue_csr_write(un, MUE_OTP_ADDR2, | 445 | mue_csr_write(un, MUE_OTP_ADDR2, | |
446 | ((off + i) & MUE_OTP_ADDR2_MASK)); | 446 | ((off + i) & MUE_OTP_ADDR2_MASK)); | |
447 | mue_csr_write(un, MUE_OTP_FUNC_CMD, MUE_OTP_FUNC_CMD_READ); | 447 | mue_csr_write(un, MUE_OTP_FUNC_CMD, MUE_OTP_FUNC_CMD_READ); | |
448 | mue_csr_write(un, MUE_OTP_CMD_GO, MUE_OTP_CMD_GO_GO); | 448 | mue_csr_write(un, MUE_OTP_CMD_GO, MUE_OTP_CMD_GO_GO); | |
449 | 449 | |||
450 | err = MUE_WAIT_CLR(un, MUE_OTP_STATUS, MUE_OTP_STATUS_BUSY, 0); | 450 | err = MUE_WAIT_CLR(un, MUE_OTP_STATUS, MUE_OTP_STATUS_BUSY, 0); | |
451 | if (err) { | 451 | if (err) { | |
452 | MUE_PRINTF(un, "timed out\n"); | 452 | MUE_PRINTF(un, "timed out\n"); | |
453 | return 1; | 453 | return 1; | |
454 | } | 454 | } | |
455 | val = mue_csr_read(un, MUE_OTP_RD_DATA); | 455 | val = mue_csr_read(un, MUE_OTP_RD_DATA); | |
456 | *(dest + i) = (uint8_t)(val & 0xff); | 456 | *(dest + i) = (uint8_t)(val & 0xff); | |
457 | } | 457 | } | |
458 | 458 | |||
459 | return 0; | 459 | return 0; | |
460 | } | 460 | } | |
461 | 461 | |||
462 | static int | 462 | static int | |
463 | mue_read_otp(struct usbnet *un, uint8_t *dest, int off, int cnt) | 463 | mue_read_otp(struct usbnet *un, uint8_t *dest, int off, int cnt) | |
464 | { | 464 | { | |
465 | uint8_t sig; | 465 | uint8_t sig; | |
466 | int err; | 466 | int err; | |
467 | 467 | |||
468 | if (un->un_flags & LAN7500) | 468 | if (un->un_flags & LAN7500) | |
469 | return 1; | 469 | return 1; | |
470 | 470 | |||
471 | err = mue_read_otp_raw(un, &sig, MUE_OTP_IND_OFFSET, 1); | 471 | err = mue_read_otp_raw(un, &sig, MUE_OTP_IND_OFFSET, 1); | |
472 | if (err) | 472 | if (err) | |
473 | return 1; | 473 | return 1; | |
474 | switch (sig) { | 474 | switch (sig) { | |
475 | case MUE_OTP_IND_1: | 475 | case MUE_OTP_IND_1: | |
476 | break; | 476 | break; | |
477 | case MUE_OTP_IND_2: | 477 | case MUE_OTP_IND_2: | |
478 | off += 0x100; | 478 | off += 0x100; | |
479 | break; | 479 | break; | |
480 | default: | 480 | default: | |
481 | DPRINTF(un, "OTP not found\n"); | 481 | DPRINTF(un, "OTP not found\n"); | |
482 | return 1; | 482 | return 1; | |
483 | } | 483 | } | |
484 | err = mue_read_otp_raw(un, dest, off, cnt); | 484 | err = mue_read_otp_raw(un, dest, off, cnt); | |
485 | return err; | 485 | return err; | |
486 | } | 486 | } | |
487 | 487 | |||
488 | static void | 488 | static void | |
489 | mue_dataport_write(struct usbnet *un, uint32_t sel, uint32_t addr, | 489 | mue_dataport_write(struct usbnet *un, uint32_t sel, uint32_t addr, | |
490 | uint32_t cnt, uint32_t *data) | 490 | uint32_t cnt, uint32_t *data) | |
491 | { | 491 | { | |
492 | uint32_t i; | 492 | uint32_t i; | |
493 | 493 | |||
494 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | 494 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | |
495 | MUE_PRINTF(un, "not ready\n"); | 495 | MUE_PRINTF(un, "not ready\n"); | |
496 | return; | 496 | return; | |
497 | } | 497 | } | |
498 | 498 | |||
499 | mue_csr_write(un, MUE_DP_SEL, | 499 | mue_csr_write(un, MUE_DP_SEL, | |
500 | (mue_csr_read(un, MUE_DP_SEL) & ~MUE_DP_SEL_RSEL_MASK) | sel); | 500 | (mue_csr_read(un, MUE_DP_SEL) & ~MUE_DP_SEL_RSEL_MASK) | sel); | |
501 | 501 | |||
502 | for (i = 0; i < cnt; i++) { | 502 | for (i = 0; i < cnt; i++) { | |
503 | mue_csr_write(un, MUE_DP_ADDR, addr + i); | 503 | mue_csr_write(un, MUE_DP_ADDR, addr + i); | |
504 | mue_csr_write(un, MUE_DP_DATA, data[i]); | 504 | mue_csr_write(un, MUE_DP_DATA, data[i]); | |
505 | mue_csr_write(un, MUE_DP_CMD, MUE_DP_CMD_WRITE); | 505 | mue_csr_write(un, MUE_DP_CMD, MUE_DP_CMD_WRITE); | |
506 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | 506 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | |
507 | MUE_PRINTF(un, "timed out\n"); | 507 | MUE_PRINTF(un, "timed out\n"); | |
508 | return; | 508 | return; | |
509 | } | 509 | } | |
510 | } | 510 | } | |
511 | } | 511 | } | |
512 | 512 | |||
513 | static void | 513 | static void | |
514 | mue_init_ltm(struct usbnet *un) | 514 | mue_init_ltm(struct usbnet *un) | |
515 | { | 515 | { | |
516 | uint32_t idx[MUE_NUM_LTM_INDEX] = { 0, 0, 0, 0, 0, 0 }; | 516 | uint32_t idx[MUE_NUM_LTM_INDEX] = { 0, 0, 0, 0, 0, 0 }; | |
517 | uint8_t temp[2]; | 517 | uint8_t temp[2]; | |
518 | size_t i; | 518 | size_t i; | |
519 | 519 | |||
520 | if (mue_csr_read(un, MUE_USB_CFG1) & MUE_USB_CFG1_LTM_ENABLE) { | 520 | if (mue_csr_read(un, MUE_USB_CFG1) & MUE_USB_CFG1_LTM_ENABLE) { | |
521 | if (mue_eeprom_present(un) && | 521 | if (mue_eeprom_present(un) && | |
522 | (mue_read_eeprom(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0)) { | 522 | (mue_read_eeprom(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0)) { | |
523 | if (temp[0] != sizeof(idx)) { | 523 | if (temp[0] != sizeof(idx)) { | |
524 | DPRINTF(un, "EEPROM: unexpected size\n"); | 524 | DPRINTF(un, "EEPROM: unexpected size\n"); | |
525 | goto done; | 525 | goto done; | |
526 | } | 526 | } | |
527 | if (mue_read_eeprom(un, (uint8_t *)idx, temp[1] << 1, | 527 | if (mue_read_eeprom(un, (uint8_t *)idx, temp[1] << 1, | |
528 | sizeof(idx))) { | 528 | sizeof(idx))) { | |
529 | DPRINTF(un, "EEPROM: failed to read\n"); | 529 | DPRINTF(un, "EEPROM: failed to read\n"); | |
530 | goto done; | 530 | goto done; | |
531 | } | 531 | } | |
532 | DPRINTF(un, "success\n"); | 532 | DPRINTF(un, "success\n"); | |
533 | } else if (mue_read_otp(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0) { | 533 | } else if (mue_read_otp(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0) { | |
534 | if (temp[0] != sizeof(idx)) { | 534 | if (temp[0] != sizeof(idx)) { | |
535 | DPRINTF(un, "OTP: unexpected size\n"); | 535 | DPRINTF(un, "OTP: unexpected size\n"); | |
536 | goto done; | 536 | goto done; | |
537 | } | 537 | } | |
538 | if (mue_read_otp(un, (uint8_t *)idx, temp[1] << 1, | 538 | if (mue_read_otp(un, (uint8_t *)idx, temp[1] << 1, | |
539 | sizeof(idx))) { | 539 | sizeof(idx))) { | |
540 | DPRINTF(un, "OTP: failed to read\n"); | 540 | DPRINTF(un, "OTP: failed to read\n"); | |
541 | goto done; | 541 | goto done; | |
542 | } | 542 | } | |
543 | DPRINTF(un, "success\n"); | 543 | DPRINTF(un, "success\n"); | |
544 | } else | 544 | } else | |
545 | DPRINTF(un, "nothing to do\n"); | 545 | DPRINTF(un, "nothing to do\n"); | |
546 | } else | 546 | } else | |
547 | DPRINTF(un, "nothing to do\n"); | 547 | DPRINTF(un, "nothing to do\n"); | |
548 | done: | 548 | done: | |
549 | for (i = 0; i < __arraycount(idx); i++) | 549 | for (i = 0; i < __arraycount(idx); i++) | |
550 | mue_csr_write(un, MUE_LTM_INDEX(i), idx[i]); | 550 | mue_csr_write(un, MUE_LTM_INDEX(i), idx[i]); | |
551 | } | 551 | } | |
552 | 552 | |||
553 | static int | 553 | static int | |
554 | mue_chip_init(struct usbnet *un) | 554 | mue_chip_init(struct usbnet *un) | |
555 | { | 555 | { | |
556 | uint32_t val; | 556 | uint32_t val; | |
557 | 557 | |||
558 | if ((un->un_flags & LAN7500) && | 558 | if ((un->un_flags & LAN7500) && | |
559 | MUE_WAIT_SET(un, MUE_PMT_CTL, MUE_PMT_CTL_READY, 0)) { | 559 | MUE_WAIT_SET(un, MUE_PMT_CTL, MUE_PMT_CTL_READY, 0)) { | |
560 | MUE_PRINTF(un, "not ready\n"); | 560 | MUE_PRINTF(un, "not ready\n"); | |
561 | return ETIMEDOUT; | 561 | return ETIMEDOUT; | |
562 | } | 562 | } | |
563 | 563 | |||
564 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_LRST); | 564 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_LRST); | |
565 | if (MUE_WAIT_CLR(un, MUE_HW_CFG, MUE_HW_CFG_LRST, 0)) { | 565 | if (MUE_WAIT_CLR(un, MUE_HW_CFG, MUE_HW_CFG_LRST, 0)) { | |
566 | MUE_PRINTF(un, "timed out\n"); | 566 | MUE_PRINTF(un, "timed out\n"); | |
567 | return ETIMEDOUT; | 567 | return ETIMEDOUT; | |
568 | } | 568 | } | |
569 | 569 | |||
570 | /* Respond to the IN token with a NAK. */ | 570 | /* Respond to the IN token with a NAK. */ | |
571 | if (un->un_flags & LAN7500) | 571 | if (un->un_flags & LAN7500) | |
572 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BIR); | 572 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BIR); | |
573 | else | 573 | else | |
574 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BIR); | 574 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BIR); | |
575 | 575 | |||
576 | if (un->un_flags & LAN7500) { | 576 | if (un->un_flags & LAN7500) { | |
577 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | 577 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | |
578 | val = MUE_7500_HS_RX_BUFSIZE / | 578 | val = MUE_7500_HS_RX_BUFSIZE / | |
579 | MUE_HS_USB_PKT_SIZE; | 579 | MUE_HS_USB_PKT_SIZE; | |
580 | else | 580 | else | |
581 | val = MUE_7500_FS_RX_BUFSIZE / | 581 | val = MUE_7500_FS_RX_BUFSIZE / | |
582 | MUE_FS_USB_PKT_SIZE; | 582 | MUE_FS_USB_PKT_SIZE; | |
583 | mue_csr_write(un, MUE_7500_BURST_CAP, val); | 583 | mue_csr_write(un, MUE_7500_BURST_CAP, val); | |
584 | mue_csr_write(un, MUE_7500_BULKIN_DELAY, | 584 | mue_csr_write(un, MUE_7500_BULKIN_DELAY, | |
585 | MUE_7500_DEFAULT_BULKIN_DELAY); | 585 | MUE_7500_DEFAULT_BULKIN_DELAY); | |
586 | 586 | |||
587 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BCE | MUE_HW_CFG_MEF); | 587 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BCE | MUE_HW_CFG_MEF); | |
588 | 588 | |||
589 | /* Set FIFO sizes. */ | 589 | /* Set FIFO sizes. */ | |
590 | val = (MUE_7500_MAX_RX_FIFO_SIZE - 512) / 512; | 590 | val = (MUE_7500_MAX_RX_FIFO_SIZE - 512) / 512; | |
591 | mue_csr_write(un, MUE_7500_FCT_RX_FIFO_END, val); | 591 | mue_csr_write(un, MUE_7500_FCT_RX_FIFO_END, val); | |
592 | val = (MUE_7500_MAX_TX_FIFO_SIZE - 512) / 512; | 592 | val = (MUE_7500_MAX_TX_FIFO_SIZE - 512) / 512; | |
593 | mue_csr_write(un, MUE_7500_FCT_TX_FIFO_END, val); | 593 | mue_csr_write(un, MUE_7500_FCT_TX_FIFO_END, val); | |
594 | } else { | 594 | } else { | |
595 | /* Init LTM. */ | 595 | /* Init LTM. */ | |
596 | mue_init_ltm(un); | 596 | mue_init_ltm(un); | |
597 | 597 | |||
598 | val = MUE_7800_RX_BUFSIZE; | 598 | val = MUE_7800_RX_BUFSIZE; | |
599 | switch (un->un_udev->ud_speed) { | 599 | switch (un->un_udev->ud_speed) { | |
600 | case USB_SPEED_SUPER: | 600 | case USB_SPEED_SUPER: | |
601 | val /= MUE_SS_USB_PKT_SIZE; | 601 | val /= MUE_SS_USB_PKT_SIZE; | |
602 | break; | 602 | break; | |
603 | case USB_SPEED_HIGH: | 603 | case USB_SPEED_HIGH: | |
604 | val /= MUE_HS_USB_PKT_SIZE; | 604 | val /= MUE_HS_USB_PKT_SIZE; | |
605 | break; | 605 | break; | |
606 | default: | 606 | default: | |
607 | val /= MUE_FS_USB_PKT_SIZE; | 607 | val /= MUE_FS_USB_PKT_SIZE; | |
608 | break; | 608 | break; | |
609 | } | 609 | } | |
610 | mue_csr_write(un, MUE_7800_BURST_CAP, val); | 610 | mue_csr_write(un, MUE_7800_BURST_CAP, val); | |
611 | mue_csr_write(un, MUE_7800_BULKIN_DELAY, | 611 | mue_csr_write(un, MUE_7800_BULKIN_DELAY, | |
612 | MUE_7800_DEFAULT_BULKIN_DELAY); | 612 | MUE_7800_DEFAULT_BULKIN_DELAY); | |
613 | 613 | |||
614 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_MEF); | 614 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_MEF); | |
615 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BCE); | 615 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BCE); | |
616 | 616 | |||
617 | /* | 617 | /* | |
618 | * Set FCL's RX and TX FIFO sizes: according to data sheet this | 618 | * Set FCL's RX and TX FIFO sizes: according to data sheet this | |
619 | * is already the default value. But we initialize it to the | 619 | * is already the default value. But we initialize it to the | |
620 | * same value anyways, as that's what the Linux driver does. | 620 | * same value anyways, as that's what the Linux driver does. | |
621 | */ | 621 | */ | |
622 | val = (MUE_7800_MAX_RX_FIFO_SIZE - 512) / 512; | 622 | val = (MUE_7800_MAX_RX_FIFO_SIZE - 512) / 512; | |
623 | mue_csr_write(un, MUE_7800_FCT_RX_FIFO_END, val); | 623 | mue_csr_write(un, MUE_7800_FCT_RX_FIFO_END, val); | |
624 | val = (MUE_7800_MAX_TX_FIFO_SIZE - 512) / 512; | 624 | val = (MUE_7800_MAX_TX_FIFO_SIZE - 512) / 512; | |
625 | mue_csr_write(un, MUE_7800_FCT_TX_FIFO_END, val); | 625 | mue_csr_write(un, MUE_7800_FCT_TX_FIFO_END, val); | |
626 | } | 626 | } | |
627 | 627 | |||
628 | /* Enabling interrupts. */ | 628 | /* Enabling interrupts. */ | |
629 | mue_csr_write(un, MUE_INT_STATUS, ~0); | 629 | mue_csr_write(un, MUE_INT_STATUS, ~0); | |
630 | 630 | |||
631 | mue_csr_write(un, (un->un_flags & LAN7500) ? | 631 | mue_csr_write(un, (un->un_flags & LAN7500) ? | |
632 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, 0); | 632 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, 0); | |
633 | mue_csr_write(un, MUE_FLOW, 0); | 633 | mue_csr_write(un, MUE_FLOW, 0); | |
634 | 634 | |||
635 | /* Reset PHY. */ | 635 | /* Reset PHY. */ | |
636 | MUE_SETBIT(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST); | 636 | MUE_SETBIT(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST); | |
637 | if (MUE_WAIT_CLR(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST, 0)) { | 637 | if (MUE_WAIT_CLR(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST, 0)) { | |
638 | MUE_PRINTF(un, "PHY not ready\n"); | 638 | MUE_PRINTF(un, "PHY not ready\n"); | |
639 | return ETIMEDOUT; | 639 | return ETIMEDOUT; | |
640 | } | 640 | } | |
641 | 641 | |||
642 | /* LAN7801 only has RGMII mode. */ | 642 | /* LAN7801 only has RGMII mode. */ | |
643 | if (un->un_flags & LAN7801) | 643 | if (un->un_flags & LAN7801) | |
644 | MUE_CLRBIT(un, MUE_MAC_CR, MUE_MAC_CR_GMII_EN); | 644 | MUE_CLRBIT(un, MUE_MAC_CR, MUE_MAC_CR_GMII_EN); | |
645 | 645 | |||
646 | if ((un->un_flags & (LAN7500 | LAN7800)) || | 646 | if ((un->un_flags & (LAN7500 | LAN7800)) || | |
647 | !mue_eeprom_present(un)) { | 647 | !mue_eeprom_present(un)) { | |
648 | /* Allow MAC to detect speed and duplex from PHY. */ | 648 | /* Allow MAC to detect speed and duplex from PHY. */ | |
649 | MUE_SETBIT(un, MUE_MAC_CR, MUE_MAC_CR_AUTO_SPEED | | 649 | MUE_SETBIT(un, MUE_MAC_CR, MUE_MAC_CR_AUTO_SPEED | | |
650 | MUE_MAC_CR_AUTO_DUPLEX); | 650 | MUE_MAC_CR_AUTO_DUPLEX); | |
651 | } | 651 | } | |
652 | 652 | |||
653 | MUE_SETBIT(un, MUE_MAC_TX, MUE_MAC_TX_TXEN); | 653 | MUE_SETBIT(un, MUE_MAC_TX, MUE_MAC_TX_TXEN); | |
654 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | 654 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | |
655 | MUE_7500_FCT_TX_CTL : MUE_7800_FCT_TX_CTL, MUE_FCT_TX_CTL_EN); | 655 | MUE_7500_FCT_TX_CTL : MUE_7800_FCT_TX_CTL, MUE_FCT_TX_CTL_EN); | |
656 | 656 | |||
657 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | 657 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | |
658 | MUE_7500_FCT_RX_CTL : MUE_7800_FCT_RX_CTL, MUE_FCT_RX_CTL_EN); | 658 | MUE_7500_FCT_RX_CTL : MUE_7800_FCT_RX_CTL, MUE_FCT_RX_CTL_EN); | |
659 | 659 | |||
660 | /* Set default GPIO/LED settings only if no EEPROM is detected. */ | 660 | /* Set default GPIO/LED settings only if no EEPROM is detected. */ | |
661 | if ((un->un_flags & LAN7500) && !mue_eeprom_present(un)) { | 661 | if ((un->un_flags & LAN7500) && !mue_eeprom_present(un)) { | |
662 | MUE_CLRBIT(un, MUE_LED_CFG, MUE_LED_CFG_LED10_FUN_SEL); | 662 | MUE_CLRBIT(un, MUE_LED_CFG, MUE_LED_CFG_LED10_FUN_SEL); | |
663 | MUE_SETBIT(un, MUE_LED_CFG, | 663 | MUE_SETBIT(un, MUE_LED_CFG, | |
664 | MUE_LED_CFG_LEDGPIO_EN | MUE_LED_CFG_LED2_FUN_SEL); | 664 | MUE_LED_CFG_LEDGPIO_EN | MUE_LED_CFG_LED2_FUN_SEL); | |
665 | } | 665 | } | |
666 | 666 | |||
667 | /* XXX We assume two LEDs at least when EEPROM is missing. */ | 667 | /* XXX We assume two LEDs at least when EEPROM is missing. */ | |
668 | if (un->un_flags & LAN7800 && | 668 | if (un->un_flags & LAN7800 && | |
669 | !mue_eeprom_present(un)) | 669 | !mue_eeprom_present(un)) | |
670 | MUE_SETBIT(un, MUE_HW_CFG, | 670 | MUE_SETBIT(un, MUE_HW_CFG, | |
671 | MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN); | 671 | MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN); | |
672 | 672 | |||
673 | return 0; | 673 | return 0; | |
674 | } | 674 | } | |
675 | 675 | |||
676 | static void | 676 | static void | |
677 | mue_set_macaddr(struct usbnet *un) | 677 | mue_set_macaddr(struct usbnet *un) | |
678 | { | 678 | { | |
679 | struct ifnet * const ifp = usbnet_ifp(un); | 679 | struct ifnet * const ifp = usbnet_ifp(un); | |
680 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | 680 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | |
681 | uint32_t lo, hi; | 681 | uint32_t lo, hi; | |
682 | 682 | |||
683 | lo = MUE_ENADDR_LO(enaddr); | 683 | lo = MUE_ENADDR_LO(enaddr); | |
684 | hi = MUE_ENADDR_HI(enaddr); | 684 | hi = MUE_ENADDR_HI(enaddr); | |
685 | 685 | |||
686 | mue_csr_write(un, MUE_RX_ADDRL, lo); | 686 | mue_csr_write(un, MUE_RX_ADDRL, lo); | |
687 | mue_csr_write(un, MUE_RX_ADDRH, hi); | 687 | mue_csr_write(un, MUE_RX_ADDRH, hi); | |
688 | } | 688 | } | |
689 | 689 | |||
690 | static int | 690 | static int | |
691 | mue_get_macaddr(struct usbnet *un, prop_dictionary_t dict) | 691 | mue_get_macaddr(struct usbnet *un, prop_dictionary_t dict) | |
692 | { | 692 | { | |
693 | prop_data_t eaprop; | 693 | prop_data_t eaprop; | |
694 | uint32_t low, high; | 694 | uint32_t low, high; | |
695 | 695 | |||
696 | if (!(un->un_flags & LAN7500)) { | 696 | if (!(un->un_flags & LAN7500)) { | |
697 | low = mue_csr_read(un, MUE_RX_ADDRL); | 697 | low = mue_csr_read(un, MUE_RX_ADDRL); | |
698 | high = mue_csr_read(un, MUE_RX_ADDRH); | 698 | high = mue_csr_read(un, MUE_RX_ADDRH); | |
699 | un->un_eaddr[5] = (uint8_t)((high >> 8) & 0xff); | 699 | un->un_eaddr[5] = (uint8_t)((high >> 8) & 0xff); | |
700 | un->un_eaddr[4] = (uint8_t)((high) & 0xff); | 700 | un->un_eaddr[4] = (uint8_t)((high) & 0xff); | |
701 | un->un_eaddr[3] = (uint8_t)((low >> 24) & 0xff); | 701 | un->un_eaddr[3] = (uint8_t)((low >> 24) & 0xff); | |
702 | un->un_eaddr[2] = (uint8_t)((low >> 16) & 0xff); | 702 | un->un_eaddr[2] = (uint8_t)((low >> 16) & 0xff); | |
703 | un->un_eaddr[1] = (uint8_t)((low >> 8) & 0xff); | 703 | un->un_eaddr[1] = (uint8_t)((low >> 8) & 0xff); | |
704 | un->un_eaddr[0] = (uint8_t)((low) & 0xff); | 704 | un->un_eaddr[0] = (uint8_t)((low) & 0xff); | |
705 | if (ETHER_IS_VALID(un->un_eaddr)) | 705 | if (ETHER_IS_VALID(un->un_eaddr)) | |
706 | return 0; | 706 | return 0; | |
707 | else | 707 | else | |
708 | DPRINTF(un, "registers: %s\n", | 708 | DPRINTF(un, "registers: %s\n", | |
709 | ether_sprintf(un->un_eaddr)); | 709 | ether_sprintf(un->un_eaddr)); | |
710 | } | 710 | } | |
711 | 711 | |||
712 | if (mue_eeprom_present(un) && !mue_read_eeprom(un, un->un_eaddr, | 712 | if (mue_eeprom_present(un) && !mue_read_eeprom(un, un->un_eaddr, | |
713 | MUE_E2P_MAC_OFFSET, ETHER_ADDR_LEN)) { | 713 | MUE_E2P_MAC_OFFSET, ETHER_ADDR_LEN)) { | |
714 | if (ETHER_IS_VALID(un->un_eaddr)) | 714 | if (ETHER_IS_VALID(un->un_eaddr)) | |
715 | return 0; | 715 | return 0; | |
716 | else | 716 | else | |
717 | DPRINTF(un, "EEPROM: %s\n", | 717 | DPRINTF(un, "EEPROM: %s\n", | |
718 | ether_sprintf(un->un_eaddr)); | 718 | ether_sprintf(un->un_eaddr)); | |
719 | } | 719 | } | |
720 | 720 | |||
721 | if (mue_read_otp(un, un->un_eaddr, MUE_OTP_MAC_OFFSET, | 721 | if (mue_read_otp(un, un->un_eaddr, MUE_OTP_MAC_OFFSET, | |
722 | ETHER_ADDR_LEN) == 0) { | 722 | ETHER_ADDR_LEN) == 0) { | |
723 | if (ETHER_IS_VALID(un->un_eaddr)) | 723 | if (ETHER_IS_VALID(un->un_eaddr)) | |
724 | return 0; | 724 | return 0; | |
725 | else | 725 | else | |
726 | DPRINTF(un, "OTP: %s\n", | 726 | DPRINTF(un, "OTP: %s\n", | |
727 | ether_sprintf(un->un_eaddr)); | 727 | ether_sprintf(un->un_eaddr)); | |
728 | } | 728 | } | |
729 | 729 | |||
730 | /* | 730 | /* | |
731 | * Other MD methods. This should be tried only if other methods fail. | 731 | * Other MD methods. This should be tried only if other methods fail. | |
732 | * Otherwise, MAC address for internal device can be assinged to | 732 | * Otherwise, MAC address for internal device can be assinged to | |
733 | * external devices on Raspberry Pi, for example. | 733 | * external devices on Raspberry Pi, for example. | |
734 | */ | 734 | */ | |
735 | eaprop = prop_dictionary_get(dict, "mac-address"); | 735 | eaprop = prop_dictionary_get(dict, "mac-address"); | |
736 | if (eaprop != NULL) { | 736 | if (eaprop != NULL) { | |
737 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | 737 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | |
738 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | 738 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | |
739 | memcpy(un->un_eaddr, prop_data_value(eaprop), | 739 | memcpy(un->un_eaddr, prop_data_value(eaprop), | |
740 | ETHER_ADDR_LEN); | 740 | ETHER_ADDR_LEN); | |
741 | if (ETHER_IS_VALID(un->un_eaddr)) | 741 | if (ETHER_IS_VALID(un->un_eaddr)) | |
742 | return 0; | 742 | return 0; | |
743 | else | 743 | else | |
744 | DPRINTF(un, "prop_dictionary_get: %s\n", | 744 | DPRINTF(un, "prop_dictionary_get: %s\n", | |
745 | ether_sprintf(un->un_eaddr)); | 745 | ether_sprintf(un->un_eaddr)); | |
746 | } | 746 | } | |
747 | 747 | |||
748 | return 1; | 748 | return 1; | |
749 | } | 749 | } | |
750 | 750 | |||
751 | 751 | |||
752 | /* | 752 | /* | |
753 | * Probe for a Microchip chip. | 753 | * Probe for a Microchip chip. | |
754 | */ | 754 | */ | |
755 | static int | 755 | static int | |
756 | mue_match(device_t parent, cfdata_t match, void *aux) | 756 | mue_match(device_t parent, cfdata_t match, void *aux) | |
757 | { | 757 | { | |
758 | struct usb_attach_arg *uaa = aux; | 758 | struct usb_attach_arg *uaa = aux; | |
759 | 759 | |||
760 | return (MUE_LOOKUP(uaa) != NULL) ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 760 | return (MUE_LOOKUP(uaa) != NULL) ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
761 | } | 761 | } | |
762 | 762 | |||
763 | static void | 763 | static void | |
764 | mue_attach(device_t parent, device_t self, void *aux) | 764 | mue_attach(device_t parent, device_t self, void *aux) | |
765 | { | 765 | { | |
766 | USBNET_MII_DECL_DEFAULT(unm); | 766 | USBNET_MII_DECL_DEFAULT(unm); | |
767 | struct usbnet * const un = device_private(self); | 767 | struct usbnet * const un = device_private(self); | |
768 | prop_dictionary_t dict = device_properties(self); | 768 | prop_dictionary_t dict = device_properties(self); | |
769 | struct usb_attach_arg *uaa = aux; | 769 | struct usb_attach_arg *uaa = aux; | |
770 | struct usbd_device *dev = uaa->uaa_device; | 770 | struct usbd_device *dev = uaa->uaa_device; | |
771 | usb_interface_descriptor_t *id; | 771 | usb_interface_descriptor_t *id; | |
772 | usb_endpoint_descriptor_t *ed; | 772 | usb_endpoint_descriptor_t *ed; | |
773 | char *devinfop; | 773 | char *devinfop; | |
774 | usbd_status err; | 774 | usbd_status err; | |
775 | const char *descr; | 775 | const char *descr; | |
776 | uint32_t id_rev; | 776 | uint32_t id_rev; | |
777 | uint8_t i; | 777 | uint8_t i; | |
778 | unsigned rx_list_cnt, tx_list_cnt; | 778 | unsigned rx_list_cnt, tx_list_cnt; | |
779 | unsigned rx_bufsz; | 779 | unsigned rx_bufsz; | |
780 | 780 | |||
781 | aprint_naive("\n"); | 781 | aprint_naive("\n"); | |
782 | aprint_normal("\n"); | 782 | aprint_normal("\n"); | |
783 | devinfop = usbd_devinfo_alloc(dev, 0); | 783 | devinfop = usbd_devinfo_alloc(dev, 0); | |
784 | aprint_normal_dev(self, "%s\n", devinfop); | 784 | aprint_normal_dev(self, "%s\n", devinfop); | |
785 | usbd_devinfo_free(devinfop); | 785 | usbd_devinfo_free(devinfop); | |
786 | 786 | |||
787 | un->un_dev = self; | 787 | un->un_dev = self; | |
788 | un->un_udev = dev; | 788 | un->un_udev = dev; | |
789 | un->un_sc = un; | 789 | un->un_sc = un; | |
790 | un->un_ops = &mue_ops; | 790 | un->un_ops = &mue_ops; | |
791 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 791 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
792 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 792 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
793 | 793 | |||
794 | #define MUE_CONFIG_NO 1 | 794 | #define MUE_CONFIG_NO 1 | |
795 | err = usbd_set_config_no(dev, MUE_CONFIG_NO, 1); | 795 | err = usbd_set_config_no(dev, MUE_CONFIG_NO, 1); | |
796 | if (err) { | 796 | if (err) { | |
797 | aprint_error_dev(self, "failed to set configuration: %s\n", | 797 | aprint_error_dev(self, "failed to set configuration: %s\n", | |
798 | usbd_errstr(err)); | 798 | usbd_errstr(err)); | |
799 | return; | 799 | return; | |
800 | } | 800 | } | |
801 | 801 | |||
802 | #define MUE_IFACE_IDX 0 | 802 | #define MUE_IFACE_IDX 0 | |
803 | err = usbd_device2interface_handle(dev, MUE_IFACE_IDX, &un->un_iface); | 803 | err = usbd_device2interface_handle(dev, MUE_IFACE_IDX, &un->un_iface); | |
804 | if (err) { | 804 | if (err) { | |
805 | aprint_error_dev(self, "failed to get interface handle: %s\n", | 805 | aprint_error_dev(self, "failed to get interface handle: %s\n", | |
806 | usbd_errstr(err)); | 806 | usbd_errstr(err)); | |
807 | return; | 807 | return; | |
808 | } | 808 | } | |
809 | 809 | |||
810 | un->un_flags = MUE_LOOKUP(uaa)->mue_flags; | 810 | un->un_flags = MUE_LOOKUP(uaa)->mue_flags; | |
811 | 811 | |||
812 | /* Decide on what our bufsize will be. */ | 812 | /* Decide on what our bufsize will be. */ | |
813 | if (un->un_flags & LAN7500) { | 813 | if (un->un_flags & LAN7500) { | |
814 | rx_bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? | 814 | rx_bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? | |
815 | MUE_7500_HS_RX_BUFSIZE : MUE_7500_FS_RX_BUFSIZE; | 815 | MUE_7500_HS_RX_BUFSIZE : MUE_7500_FS_RX_BUFSIZE; | |
816 | rx_list_cnt = 1; | 816 | rx_list_cnt = 1; | |
817 | tx_list_cnt = 1; | 817 | tx_list_cnt = 1; | |
818 | } else { | 818 | } else { | |
819 | rx_bufsz = MUE_7800_RX_BUFSIZE; | 819 | rx_bufsz = MUE_7800_RX_BUFSIZE; | |
820 | rx_list_cnt = MUE_RX_LIST_CNT; | 820 | rx_list_cnt = MUE_RX_LIST_CNT; | |
821 | tx_list_cnt = MUE_TX_LIST_CNT; | 821 | tx_list_cnt = MUE_TX_LIST_CNT; | |
822 | } | 822 | } | |
823 | 823 | |||
824 | un->un_rx_list_cnt = rx_list_cnt; | 824 | un->un_rx_list_cnt = rx_list_cnt; | |
825 | un->un_tx_list_cnt = tx_list_cnt; | 825 | un->un_tx_list_cnt = tx_list_cnt; | |
826 | un->un_rx_bufsz = rx_bufsz; | 826 | un->un_rx_bufsz = rx_bufsz; | |
827 | un->un_tx_bufsz = MUE_TX_BUFSIZE; | 827 | un->un_tx_bufsz = MUE_TX_BUFSIZE; | |
828 | 828 | |||
829 | /* Find endpoints. */ | 829 | /* Find endpoints. */ | |
830 | id = usbd_get_interface_descriptor(un->un_iface); | 830 | id = usbd_get_interface_descriptor(un->un_iface); | |
831 | for (i = 0; i < id->bNumEndpoints; i++) { | 831 | for (i = 0; i < id->bNumEndpoints; i++) { | |
832 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 832 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
833 | if (ed == NULL) { | 833 | if (ed == NULL) { | |
834 | aprint_error_dev(self, "failed to get ep %hhd\n", i); | 834 | aprint_error_dev(self, "failed to get ep %hhd\n", i); | |
835 | return; | 835 | return; | |
836 | } | 836 | } | |
837 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 837 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
838 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 838 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
839 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 839 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
840 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 840 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
841 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 841 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
842 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 842 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
843 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 843 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
844 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 844 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
845 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 845 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
846 | } | 846 | } | |
847 | } | 847 | } | |
848 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 848 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
849 | un->un_ed[USBNET_ENDPT_TX] == 0 || | 849 | un->un_ed[USBNET_ENDPT_TX] == 0 || | |
850 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | 850 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | |
851 | aprint_error_dev(self, "failed to find endpoints\n"); | 851 | aprint_error_dev(self, "failed to find endpoints\n"); | |
852 | return; | 852 | return; | |
853 | } | 853 | } | |
854 | 854 | |||
855 | /* Set these up now for mue_cmd(). */ | 855 | /* Set these up now for mue_cmd(). */ | |
856 | usbnet_attach(un, "muedet"); | 856 | usbnet_attach(un, "muedet"); | |
857 | 857 | |||
858 | un->un_phyno = 1; | 858 | un->un_phyno = 1; | |
859 | 859 | |||
860 | if (mue_chip_init(un)) { | 860 | if (mue_chip_init(un)) { | |
861 | aprint_error_dev(self, "failed to initialize chip\n"); | 861 | aprint_error_dev(self, "failed to initialize chip\n"); | |
862 | return; | 862 | return; | |
863 | } | 863 | } | |
864 | 864 | |||
865 | /* A Microchip chip was detected. Inform the world. */ | 865 | /* A Microchip chip was detected. Inform the world. */ | |
866 | id_rev = mue_csr_read(un, MUE_ID_REV); | 866 | id_rev = mue_csr_read(un, MUE_ID_REV); | |
867 | descr = (un->un_flags & LAN7500) ? "LAN7500" : "LAN7800"; | 867 | descr = (un->un_flags & LAN7500) ? "LAN7500" : "LAN7800"; | |
868 | aprint_normal_dev(self, "%s id %#x rev %#x\n", descr, | 868 | aprint_normal_dev(self, "%s id %#x rev %#x\n", descr, | |
869 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_ID), | 869 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_ID), | |
870 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_REV)); | 870 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_REV)); | |
871 | 871 | |||
872 | if (mue_get_macaddr(un, dict)) { | 872 | if (mue_get_macaddr(un, dict)) { | |
873 | aprint_error_dev(self, "failed to read MAC address\n"); | 873 | aprint_error_dev(self, "failed to read MAC address\n"); | |
874 | return; | 874 | return; | |
875 | } | 875 | } | |
876 | 876 | |||
877 | struct ifnet *ifp = usbnet_ifp(un); | 877 | struct ifnet *ifp = usbnet_ifp(un); | |
878 | ifp->if_capabilities = IFCAP_TSOv4 | IFCAP_TSOv6 | | 878 | ifp->if_capabilities = IFCAP_TSOv4 | IFCAP_TSOv6 | | |
879 | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | | 879 | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | | |
880 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | | 880 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | | |
881 | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | | 881 | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | | |
882 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | | 882 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | | |
883 | IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; | 883 | IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; | |
884 | 884 | |||
885 | struct ethercom *ec = usbnet_ec(un); | 885 | struct ethercom *ec = usbnet_ec(un); | |
886 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | 886 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | |
887 | #if 0 /* XXX not yet */ | 887 | #if 0 /* XXX not yet */ | |
888 | ec->ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU; | 888 | ec->ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU; | |
889 | #endif | 889 | #endif | |
890 | 890 | |||
891 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 891 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
892 | 0, &unm); | 892 | 0, &unm); | |
893 | } | 893 | } | |
894 | 894 | |||
895 | static unsigned | 895 | static unsigned | |
896 | mue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 896 | mue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
897 | { | 897 | { | |
898 | struct ifnet * const ifp = usbnet_ifp(un); | 898 | struct ifnet * const ifp = usbnet_ifp(un); | |
899 | struct mue_txbuf_hdr hdr; | 899 | struct mue_txbuf_hdr hdr; | |
900 | uint32_t tx_cmd_a, tx_cmd_b; | 900 | uint32_t tx_cmd_a, tx_cmd_b; | |
901 | int csum, len, rv; | 901 | int csum, len, rv; | |
902 | bool tso, ipe, tpe; | 902 | bool tso, ipe, tpe; | |
903 | 903 | |||
904 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) | 904 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) | |
905 | return 0; | 905 | return 0; | |
906 | 906 | |||
907 | csum = m->m_pkthdr.csum_flags; | 907 | csum = m->m_pkthdr.csum_flags; | |
908 | tso = csum & (M_CSUM_TSOv4 | M_CSUM_TSOv6); | 908 | tso = csum & (M_CSUM_TSOv4 | M_CSUM_TSOv6); | |
909 | ipe = csum & M_CSUM_IPv4; | 909 | ipe = csum & M_CSUM_IPv4; | |
910 | tpe = csum & (M_CSUM_TCPv4 | M_CSUM_UDPv4 | | 910 | tpe = csum & (M_CSUM_TCPv4 | M_CSUM_UDPv4 | | |
911 | M_CSUM_TCPv6 | M_CSUM_UDPv6); | 911 | M_CSUM_TCPv6 | M_CSUM_UDPv6); | |
912 | 912 | |||
913 | len = m->m_pkthdr.len; | 913 | len = m->m_pkthdr.len; | |
914 | if (__predict_false((!tso && len > (int)MUE_FRAME_LEN(ifp->if_mtu)) || | 914 | if (__predict_false((!tso && len > (int)MUE_FRAME_LEN(ifp->if_mtu)) || | |
915 | ( tso && len > MUE_TSO_FRAME_LEN))) { | 915 | ( tso && len > MUE_TSO_FRAME_LEN))) { | |
916 | MUE_PRINTF(un, "packet length %d\n too long", len); | 916 | MUE_PRINTF(un, "packet length %d\n too long", len); | |
917 | return 0; | 917 | return 0; | |
918 | } | 918 | } | |
919 | 919 | |||
920 | KASSERT((len & ~MUE_TX_CMD_A_LEN_MASK) == 0); | 920 | KASSERT((len & ~MUE_TX_CMD_A_LEN_MASK) == 0); | |
921 | tx_cmd_a = len | MUE_TX_CMD_A_FCS; | 921 | tx_cmd_a = len | MUE_TX_CMD_A_FCS; | |
922 | 922 | |||
923 | if (tso) { | 923 | if (tso) { | |
924 | tx_cmd_a |= MUE_TX_CMD_A_LSO; | 924 | tx_cmd_a |= MUE_TX_CMD_A_LSO; | |
925 | if (__predict_true(m->m_pkthdr.segsz > MUE_TX_MSS_MIN)) | 925 | if (__predict_true(m->m_pkthdr.segsz > MUE_TX_MSS_MIN)) | |
926 | tx_cmd_b = m->m_pkthdr.segsz; | 926 | tx_cmd_b = m->m_pkthdr.segsz; | |
927 | else | 927 | else | |
928 | tx_cmd_b = MUE_TX_MSS_MIN; | 928 | tx_cmd_b = MUE_TX_MSS_MIN; | |
929 | tx_cmd_b <<= MUE_TX_CMD_B_MSS_SHIFT; | 929 | tx_cmd_b <<= MUE_TX_CMD_B_MSS_SHIFT; | |
930 | KASSERT((tx_cmd_b & ~MUE_TX_CMD_B_MSS_MASK) == 0); | 930 | KASSERT((tx_cmd_b & ~MUE_TX_CMD_B_MSS_MASK) == 0); | |
931 | rv = mue_prepare_tso(un, m); | 931 | rv = mue_prepare_tso(un, m); | |
932 | if (__predict_false(rv)) | 932 | if (__predict_false(rv)) | |
933 | return 0; | 933 | return 0; | |
934 | } else { | 934 | } else { | |
935 | if (ipe) | 935 | if (ipe) | |
936 | tx_cmd_a |= MUE_TX_CMD_A_IPE; | 936 | tx_cmd_a |= MUE_TX_CMD_A_IPE; | |
937 | if (tpe) | 937 | if (tpe) | |
938 | tx_cmd_a |= MUE_TX_CMD_A_TPE; | 938 | tx_cmd_a |= MUE_TX_CMD_A_TPE; | |
939 | tx_cmd_b = 0; | 939 | tx_cmd_b = 0; | |
940 | } | 940 | } | |
941 | 941 | |||
942 | hdr.tx_cmd_a = htole32(tx_cmd_a); | 942 | hdr.tx_cmd_a = htole32(tx_cmd_a); | |
943 | hdr.tx_cmd_b = htole32(tx_cmd_b); | 943 | hdr.tx_cmd_b = htole32(tx_cmd_b); | |
944 | 944 | |||
945 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); | 945 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); | |
946 | m_copydata(m, 0, len, c->unc_buf + sizeof(hdr)); | 946 | m_copydata(m, 0, len, c->unc_buf + sizeof(hdr)); | |
947 | 947 | |||
948 | return len + sizeof(hdr); | 948 | return len + sizeof(hdr); | |
949 | } | 949 | } | |
950 | 950 | |||
951 | /* | 951 | /* | |
952 | * L3 length field should be cleared. | 952 | * L3 length field should be cleared. | |
953 | */ | 953 | */ | |
954 | static int | 954 | static int | |
955 | mue_prepare_tso(struct usbnet *un, struct mbuf *m) | 955 | mue_prepare_tso(struct usbnet *un, struct mbuf *m) | |
956 | { | 956 | { | |
957 | struct ether_header *eh; | 957 | struct ether_header *eh; | |
958 | struct ip *ip; | 958 | struct ip *ip; | |
959 | struct ip6_hdr *ip6; | 959 | struct ip6_hdr *ip6; | |
960 | uint16_t type, len = 0; | 960 | uint16_t type, len = 0; | |
961 | int off; | 961 | int off; | |
962 | 962 | |||
963 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | 963 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | |
964 | eh = mtod(m, struct ether_header *); | 964 | eh = mtod(m, struct ether_header *); | |
965 | type = eh->ether_type; | 965 | type = eh->ether_type; | |
966 | } else | 966 | } else | |
967 | m_copydata(m, offsetof(struct ether_header, ether_type), | 967 | m_copydata(m, offsetof(struct ether_header, ether_type), | |
968 | sizeof(type), &type); | 968 | sizeof(type), &type); | |
969 | switch (type = htons(type)) { | 969 | switch (type = htons(type)) { | |
970 | case ETHERTYPE_IP: | 970 | case ETHERTYPE_IP: | |
971 | case ETHERTYPE_IPV6: | 971 | case ETHERTYPE_IPV6: | |
972 | off = ETHER_HDR_LEN; | 972 | off = ETHER_HDR_LEN; | |
973 | break; | 973 | break; | |
974 | case ETHERTYPE_VLAN: | 974 | case ETHERTYPE_VLAN: | |
975 | off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | 975 | off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | |
976 | break; | 976 | break; | |
977 | default: | 977 | default: | |
978 | return EINVAL; | 978 | return EINVAL; | |
979 | } | 979 | } | |
980 | 980 | |||
981 | if (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) { | 981 | if (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) { | |
982 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip))) { | 982 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip))) { | |
983 | ip = (void *)(mtod(m, char *) + off); | 983 | ip = (void *)(mtod(m, char *) + off); | |
984 | ip->ip_len = 0; | 984 | ip->ip_len = 0; | |
985 | } else | 985 | } else | |
986 | m_copyback(m, off + offsetof(struct ip, ip_len), | 986 | m_copyback(m, off + offsetof(struct ip, ip_len), | |
987 | sizeof(len), &len); | 987 | sizeof(len), &len); | |
988 | } else { | 988 | } else { | |
989 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip6))) { | 989 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip6))) { | |
990 | ip6 = (void *)(mtod(m, char *) + off); | 990 | ip6 = (void *)(mtod(m, char *) + off); | |
991 | ip6->ip6_plen = 0; | 991 | ip6->ip6_plen = 0; | |
992 | } else | 992 | } else | |
993 | m_copyback(m, off + offsetof(struct ip6_hdr, ip6_plen), | 993 | m_copyback(m, off + offsetof(struct ip6_hdr, ip6_plen), | |
994 | sizeof(len), &len); | 994 | sizeof(len), &len); | |
995 | } | 995 | } | |
996 | return 0; | 996 | return 0; | |
997 | } | 997 | } | |
998 | 998 | |||
999 | static void | 999 | static void | |
1000 | mue_setiff_locked(struct usbnet *un) | 1000 | mue_setiff_locked(struct usbnet *un) | |
1001 | { | 1001 | { | |
1002 | struct ethercom *ec = usbnet_ec(un); | 1002 | struct ethercom *ec = usbnet_ec(un); | |
1003 | struct ifnet * const ifp = usbnet_ifp(un); | 1003 | struct ifnet * const ifp = usbnet_ifp(un); | |
1004 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | 1004 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | |
1005 | struct ether_multi *enm; | 1005 | struct ether_multi *enm; | |
1006 | struct ether_multistep step; | 1006 | struct ether_multistep step; | |
1007 | uint32_t pfiltbl[MUE_NUM_ADDR_FILTX][2]; | 1007 | uint32_t pfiltbl[MUE_NUM_ADDR_FILTX][2]; | |
1008 | uint32_t hashtbl[MUE_DP_SEL_VHF_HASH_LEN]; | 1008 | uint32_t hashtbl[MUE_DP_SEL_VHF_HASH_LEN]; | |
1009 | uint32_t reg, rxfilt, h, hireg, loreg; | 1009 | uint32_t reg, rxfilt, h, hireg, loreg; | |
1010 | size_t i; | 1010 | size_t i; | |
1011 | 1011 | |||
1012 | if (usbnet_isdying(un)) | 1012 | if (usbnet_isdying(un)) | |
1013 | return; | 1013 | return; | |
1014 | 1014 | |||
1015 | /* Clear perfect filter and hash tables. */ | 1015 | /* Clear perfect filter and hash tables. */ | |
1016 | memset(pfiltbl, 0, sizeof(pfiltbl)); | 1016 | memset(pfiltbl, 0, sizeof(pfiltbl)); | |
1017 | memset(hashtbl, 0, sizeof(hashtbl)); | 1017 | memset(hashtbl, 0, sizeof(hashtbl)); | |
1018 | 1018 | |||
1019 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | 1019 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | |
1020 | rxfilt = mue_csr_read(un, reg); | 1020 | rxfilt = mue_csr_read(un, reg); | |
1021 | rxfilt &= ~(MUE_RFE_CTL_PERFECT | MUE_RFE_CTL_MULTICAST_HASH | | 1021 | rxfilt &= ~(MUE_RFE_CTL_PERFECT | MUE_RFE_CTL_MULTICAST_HASH | | |
1022 | MUE_RFE_CTL_UNICAST | MUE_RFE_CTL_MULTICAST); | 1022 | MUE_RFE_CTL_UNICAST | MUE_RFE_CTL_MULTICAST); | |
1023 | 1023 | |||
1024 | /* Always accept broadcast frames. */ | 1024 | /* Always accept broadcast frames. */ | |
1025 | rxfilt |= MUE_RFE_CTL_BROADCAST; | 1025 | rxfilt |= MUE_RFE_CTL_BROADCAST; | |
1026 | 1026 | |||
1027 | if (ifp->if_flags & IFF_PROMISC) { | 1027 | if (ifp->if_flags & IFF_PROMISC) { | |
1028 | rxfilt |= MUE_RFE_CTL_UNICAST; | 1028 | rxfilt |= MUE_RFE_CTL_UNICAST; | |
1029 | allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; | 1029 | allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; | |
1030 | ifp->if_flags |= IFF_ALLMULTI; | 1030 | ifp->if_flags |= IFF_ALLMULTI; | |
1031 | if (ifp->if_flags & IFF_PROMISC) | 1031 | if (ifp->if_flags & IFF_PROMISC) | |
1032 | DPRINTF(un, "promisc\n"); | 1032 | DPRINTF(un, "promisc\n"); | |
1033 | else | 1033 | else | |
1034 | DPRINTF(un, "allmulti\n"); | 1034 | DPRINTF(un, "allmulti\n"); | |
1035 | } else { | 1035 | } else { | |
1036 | /* Now program new ones. */ | 1036 | /* Now program new ones. */ | |
1037 | pfiltbl[0][0] = MUE_ENADDR_HI(enaddr) | MUE_ADDR_FILTX_VALID; | 1037 | pfiltbl[0][0] = MUE_ENADDR_HI(enaddr) | MUE_ADDR_FILTX_VALID; | |
1038 | pfiltbl[0][1] = MUE_ENADDR_LO(enaddr); | 1038 | pfiltbl[0][1] = MUE_ENADDR_LO(enaddr); | |
1039 | i = 1; | 1039 | i = 1; | |
1040 | ETHER_LOCK(ec); | 1040 | ETHER_LOCK(ec); | |
1041 | ETHER_FIRST_MULTI(step, ec, enm); | 1041 | ETHER_FIRST_MULTI(step, ec, enm); | |
1042 | while (enm != NULL) { | 1042 | while (enm != NULL) { | |
1043 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | 1043 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
1044 | ETHER_ADDR_LEN)) { | 1044 | ETHER_ADDR_LEN)) { | |
1045 | memset(pfiltbl, 0, sizeof(pfiltbl)); | 1045 | memset(pfiltbl, 0, sizeof(pfiltbl)); | |
1046 | memset(hashtbl, 0, sizeof(hashtbl)); | 1046 | memset(hashtbl, 0, sizeof(hashtbl)); | |
1047 | rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH; | 1047 | rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH; | |
1048 | ETHER_UNLOCK(ec); | 1048 | ETHER_UNLOCK(ec); | |
1049 | goto allmulti; | 1049 | goto allmulti; | |
1050 | } | 1050 | } | |
1051 | if (i < MUE_NUM_ADDR_FILTX) { | 1051 | if (i < MUE_NUM_ADDR_FILTX) { | |
1052 | /* Use perfect address table if possible. */ | 1052 | /* Use perfect address table if possible. */ | |
1053 | pfiltbl[i][0] = MUE_ENADDR_HI(enm->enm_addrlo) | | 1053 | pfiltbl[i][0] = MUE_ENADDR_HI(enm->enm_addrlo) | | |
1054 | MUE_ADDR_FILTX_VALID; | 1054 | MUE_ADDR_FILTX_VALID; | |
1055 | pfiltbl[i][1] = MUE_ENADDR_LO(enm->enm_addrlo); | 1055 | pfiltbl[i][1] = MUE_ENADDR_LO(enm->enm_addrlo); | |
1056 | } else { | 1056 | } else { | |
1057 | /* Otherwise, use hash table. */ | 1057 | /* Otherwise, use hash table. */ | |
1058 | rxfilt |= MUE_RFE_CTL_MULTICAST_HASH; | 1058 | rxfilt |= MUE_RFE_CTL_MULTICAST_HASH; | |
1059 | h = (ether_crc32_be(enm->enm_addrlo, | 1059 | h = (ether_crc32_be(enm->enm_addrlo, | |
1060 | ETHER_ADDR_LEN) >> 23) & 0x1ff; | 1060 | ETHER_ADDR_LEN) >> 23) & 0x1ff; | |
1061 | hashtbl[h / 32] |= 1 << (h % 32); | 1061 | hashtbl[h / 32] |= 1 << (h % 32); | |
1062 | } | 1062 | } | |
1063 | i++; | 1063 | i++; | |
1064 | ETHER_NEXT_MULTI(step, enm); | 1064 | ETHER_NEXT_MULTI(step, enm); | |
1065 | } | 1065 | } | |
1066 | ETHER_UNLOCK(ec); | 1066 | ETHER_UNLOCK(ec); | |
1067 | rxfilt |= MUE_RFE_CTL_PERFECT; | 1067 | rxfilt |= MUE_RFE_CTL_PERFECT; | |
1068 | ifp->if_flags &= ~IFF_ALLMULTI; | 1068 | ifp->if_flags &= ~IFF_ALLMULTI; | |
1069 | if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH) | 1069 | if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH) | |
1070 | DPRINTF(un, "perfect filter and hash tables\n"); | 1070 | DPRINTF(un, "perfect filter and hash tables\n"); | |
1071 | else | 1071 | else | |
1072 | DPRINTF(un, "perfect filter\n"); | 1072 | DPRINTF(un, "perfect filter\n"); | |
1073 | } | 1073 | } | |
1074 | 1074 | |||
1075 | for (i = 0; i < MUE_NUM_ADDR_FILTX; i++) { | 1075 | for (i = 0; i < MUE_NUM_ADDR_FILTX; i++) { | |
1076 | hireg = (un->un_flags & LAN7500) ? | 1076 | hireg = (un->un_flags & LAN7500) ? | |
1077 | MUE_7500_ADDR_FILTX(i) : MUE_7800_ADDR_FILTX(i); | 1077 | MUE_7500_ADDR_FILTX(i) : MUE_7800_ADDR_FILTX(i); | |
1078 | loreg = hireg + 4; | 1078 | loreg = hireg + 4; | |
1079 | mue_csr_write(un, hireg, 0); | 1079 | mue_csr_write(un, hireg, 0); | |
1080 | mue_csr_write(un, loreg, pfiltbl[i][1]); | 1080 | mue_csr_write(un, loreg, pfiltbl[i][1]); | |
1081 | mue_csr_write(un, hireg, pfiltbl[i][0]); | 1081 | mue_csr_write(un, hireg, pfiltbl[i][0]); | |
1082 | } | 1082 | } | |
1083 | 1083 | |||
1084 | mue_dataport_write(un, MUE_DP_SEL_VHF, MUE_DP_SEL_VHF_VLAN_LEN, | 1084 | mue_dataport_write(un, MUE_DP_SEL_VHF, MUE_DP_SEL_VHF_VLAN_LEN, | |
1085 | MUE_DP_SEL_VHF_HASH_LEN, hashtbl); | 1085 | MUE_DP_SEL_VHF_HASH_LEN, hashtbl); | |
1086 | 1086 | |||
1087 | mue_csr_write(un, reg, rxfilt); | 1087 | mue_csr_write(un, reg, rxfilt); | |
1088 | } | 1088 | } | |
1089 | 1089 | |||
1090 | static void | 1090 | static void | |
1091 | mue_sethwcsum_locked(struct usbnet *un) | 1091 | mue_sethwcsum_locked(struct usbnet *un) | |
1092 | { | 1092 | { | |
1093 | struct ifnet * const ifp = usbnet_ifp(un); | 1093 | struct ifnet * const ifp = usbnet_ifp(un); | |
1094 | uint32_t reg, val; | 1094 | uint32_t reg, val; | |
1095 | 1095 | |||
1096 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | 1096 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | |
1097 | val = mue_csr_read(un, reg); | 1097 | val = mue_csr_read(un, reg); | |
1098 | 1098 | |||
1099 | if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) { | 1099 | if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) { | |
1100 | DPRINTF(un, "RX IPv4 hwcsum enabled\n"); | 1100 | DPRINTF(un, "RX IPv4 hwcsum enabled\n"); | |
1101 | val |= MUE_RFE_CTL_IP_COE; | 1101 | val |= MUE_RFE_CTL_IP_COE; | |
1102 | } else { | 1102 | } else { | |
1103 | DPRINTF(un, "RX IPv4 hwcsum disabled\n"); | 1103 | DPRINTF(un, "RX IPv4 hwcsum disabled\n"); | |
1104 | val &= ~MUE_RFE_CTL_IP_COE; | 1104 | val &= ~MUE_RFE_CTL_IP_COE; | |
1105 | } | 1105 | } | |
1106 | 1106 | |||
1107 | if (ifp->if_capenable & | 1107 | if (ifp->if_capenable & | |
1108 | (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | 1108 | (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | |
1109 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { | 1109 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { | |
1110 | DPRINTF(un, "RX L4 hwcsum enabled\n"); | 1110 | DPRINTF(un, "RX L4 hwcsum enabled\n"); | |
1111 | val |= MUE_RFE_CTL_TCPUDP_COE; | 1111 | val |= MUE_RFE_CTL_TCPUDP_COE; | |
1112 | } else { | 1112 | } else { | |
1113 | DPRINTF(un, "RX L4 hwcsum disabled\n"); | 1113 | DPRINTF(un, "RX L4 hwcsum disabled\n"); | |
1114 | val &= ~MUE_RFE_CTL_TCPUDP_COE; | 1114 | val &= ~MUE_RFE_CTL_TCPUDP_COE; | |
1115 | } | 1115 | } | |
1116 | 1116 | |||
1117 | val &= ~MUE_RFE_CTL_VLAN_FILTER; | 1117 | val &= ~MUE_RFE_CTL_VLAN_FILTER; | |
1118 | 1118 | |||
1119 | mue_csr_write(un, reg, val); | 1119 | mue_csr_write(un, reg, val); | |
1120 | } | 1120 | } | |
1121 | 1121 | |||
1122 | static void | 1122 | static void | |
1123 | mue_setmtu_locked(struct usbnet *un) | 1123 | mue_setmtu_locked(struct usbnet *un) | |
1124 | { | 1124 | { | |
1125 | struct ifnet * const ifp = usbnet_ifp(un); | 1125 | struct ifnet * const ifp = usbnet_ifp(un); | |
1126 | uint32_t val; | 1126 | uint32_t val; | |
1127 | 1127 | |||
1128 | /* Set the maximum frame size. */ | 1128 | /* Set the maximum frame size. */ | |
1129 | MUE_CLRBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | 1129 | MUE_CLRBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | |
1130 | val = mue_csr_read(un, MUE_MAC_RX); | 1130 | val = mue_csr_read(un, MUE_MAC_RX); | |
1131 | val &= ~MUE_MAC_RX_MAX_SIZE_MASK; | 1131 | val &= ~MUE_MAC_RX_MAX_SIZE_MASK; | |
1132 | val |= MUE_MAC_RX_MAX_LEN(MUE_FRAME_LEN(ifp->if_mtu)); | 1132 | val |= MUE_MAC_RX_MAX_LEN(MUE_FRAME_LEN(ifp->if_mtu)); | |
1133 | mue_csr_write(un, MUE_MAC_RX, val); | 1133 | mue_csr_write(un, MUE_MAC_RX, val); | |
1134 | MUE_SETBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | 1134 | MUE_SETBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | |
1135 | } | 1135 | } | |
1136 | 1136 | |||
1137 | static void | 1137 | static void | |
1138 | mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 1138 | mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
1139 | { | 1139 | { | |
1140 | struct ifnet * const ifp = usbnet_ifp(un); | 1140 | struct ifnet * const ifp = usbnet_ifp(un); | |
1141 | struct mue_rxbuf_hdr *hdrp; | 1141 | struct mue_rxbuf_hdr *hdrp; | |
1142 | uint32_t rx_cmd_a; | 1142 | uint32_t rx_cmd_a; | |
1143 | uint16_t pktlen; | 1143 | uint16_t pktlen; | |
1144 | int csum; | 1144 | int csum; | |
1145 | uint8_t *buf = c->unc_buf; | 1145 | uint8_t *buf = c->unc_buf; | |
1146 | bool v6; | 1146 | bool v6; | |
1147 | 1147 | |||
1148 | KASSERTMSG(total_len <= un->un_rx_bufsz, "%u vs %u", | 1148 | KASSERTMSG(total_len <= un->un_rx_bufsz, "%u vs %u", | |
1149 | total_len, un->un_rx_bufsz); | 1149 | total_len, un->un_rx_bufsz); | |
1150 | 1150 | |||
1151 | do { | 1151 | do { | |
1152 | if (__predict_false(total_len < sizeof(*hdrp))) { | 1152 | if (__predict_false(total_len < sizeof(*hdrp))) { | |
1153 | MUE_PRINTF(un, "packet length %u too short\n", total_len); | 1153 | MUE_PRINTF(un, "packet length %u too short\n", total_len); | |
1154 | if_statinc(ifp, if_ierrors); | 1154 | if_statinc(ifp, if_ierrors); | |
1155 | return; | 1155 | return; | |
1156 | } | 1156 | } | |
1157 | 1157 | |||
1158 | hdrp = (struct mue_rxbuf_hdr *)buf; | 1158 | hdrp = (struct mue_rxbuf_hdr *)buf; | |
1159 | rx_cmd_a = le32toh(hdrp->rx_cmd_a); | 1159 | rx_cmd_a = le32toh(hdrp->rx_cmd_a); | |
1160 | 1160 | |||
1161 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ERRORS)) { | 1161 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ERRORS)) { | |
1162 | /* | 1162 | /* | |
1163 | * We cannot use MUE_RX_CMD_A_RED bit here; | 1163 | * We cannot use MUE_RX_CMD_A_RED bit here; | |
1164 | * it is turned on in the cases of L3/L4 | 1164 | * it is turned on in the cases of L3/L4 | |
1165 | * checksum errors which we handle below. | 1165 | * checksum errors which we handle below. | |
1166 | */ | 1166 | */ | |
1167 | MUE_PRINTF(un, "rx_cmd_a: %#x\n", rx_cmd_a); | 1167 | MUE_PRINTF(un, "rx_cmd_a: %#x\n", rx_cmd_a); | |
1168 | if_statinc(ifp, if_ierrors); | 1168 | if_statinc(ifp, if_ierrors); | |
1169 | return; | 1169 | return; | |
1170 | } | 1170 | } | |
1171 | 1171 | |||
1172 | pktlen = (uint16_t)(rx_cmd_a & MUE_RX_CMD_A_LEN_MASK); | 1172 | pktlen = (uint16_t)(rx_cmd_a & MUE_RX_CMD_A_LEN_MASK); | |
1173 | if (un->un_flags & LAN7500) | 1173 | if (un->un_flags & LAN7500) | |
1174 | pktlen -= 2; | 1174 | pktlen -= 2; | |
1175 | 1175 | |||
1176 | if (__predict_false(pktlen < ETHER_HDR_LEN + ETHER_CRC_LEN || | 1176 | if (__predict_false(pktlen < ETHER_HDR_LEN + ETHER_CRC_LEN || | |
1177 | pktlen > MCLBYTES - ETHER_ALIGN || /* XXX */ | 1177 | pktlen > MCLBYTES - ETHER_ALIGN || /* XXX */ | |
1178 | pktlen + sizeof(*hdrp) > total_len)) { | 1178 | pktlen + sizeof(*hdrp) > total_len)) { | |
1179 | MUE_PRINTF(un, "invalid packet length %d\n", pktlen); | 1179 | MUE_PRINTF(un, "invalid packet length %d\n", pktlen); | |
1180 | if_statinc(ifp, if_ierrors); | 1180 | if_statinc(ifp, if_ierrors); | |
1181 | return; | 1181 | return; | |
1182 | } | 1182 | } | |
1183 | 1183 | |||
1184 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ICSM)) { | 1184 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ICSM)) { | |
1185 | csum = 0; | 1185 | csum = 0; | |
1186 | } else { | 1186 | } else { | |
1187 | v6 = rx_cmd_a & MUE_RX_CMD_A_IPV; | 1187 | v6 = rx_cmd_a & MUE_RX_CMD_A_IPV; | |
1188 | switch (rx_cmd_a & MUE_RX_CMD_A_PID) { | 1188 | switch (rx_cmd_a & MUE_RX_CMD_A_PID) { | |
1189 | case MUE_RX_CMD_A_PID_TCP: | 1189 | case MUE_RX_CMD_A_PID_TCP: | |
1190 | csum = v6 ? | 1190 | csum = v6 ? | |
1191 | M_CSUM_TCPv6 : M_CSUM_IPv4 | M_CSUM_TCPv4; | 1191 | M_CSUM_TCPv6 : M_CSUM_IPv4 | M_CSUM_TCPv4; | |
1192 | break; | 1192 | break; | |
1193 | case MUE_RX_CMD_A_PID_UDP: | 1193 | case MUE_RX_CMD_A_PID_UDP: | |
1194 | csum = v6 ? | 1194 | csum = v6 ? | |
1195 | M_CSUM_UDPv6 : M_CSUM_IPv4 | M_CSUM_UDPv4; | 1195 | M_CSUM_UDPv6 : M_CSUM_IPv4 | M_CSUM_UDPv4; | |
1196 | break; | 1196 | break; | |
1197 | case MUE_RX_CMD_A_PID_IP: | 1197 | case MUE_RX_CMD_A_PID_IP: | |
1198 | csum = v6 ? 0 : M_CSUM_IPv4; | 1198 | csum = v6 ? 0 : M_CSUM_IPv4; | |
1199 | break; | 1199 | break; | |
1200 | default: | 1200 | default: | |
1201 | csum = 0; | 1201 | csum = 0; | |
1202 | break; | 1202 | break; | |
1203 | } | 1203 | } | |
1204 | csum &= ifp->if_csum_flags_rx; | 1204 | csum &= ifp->if_csum_flags_rx; | |
1205 | if (__predict_false((csum & M_CSUM_IPv4) && | 1205 | if (__predict_false((csum & M_CSUM_IPv4) && | |
1206 | (rx_cmd_a & MUE_RX_CMD_A_ICE))) | 1206 | (rx_cmd_a & MUE_RX_CMD_A_ICE))) | |
1207 | csum |= M_CSUM_IPv4_BAD; | 1207 | csum |= M_CSUM_IPv4_BAD; | |
1208 | if (__predict_false((csum & ~M_CSUM_IPv4) && | 1208 | if (__predict_false((csum & ~M_CSUM_IPv4) && | |
1209 | (rx_cmd_a & MUE_RX_CMD_A_TCE))) | 1209 | (rx_cmd_a & MUE_RX_CMD_A_TCE))) | |
1210 | csum |= M_CSUM_TCP_UDP_BAD; | 1210 | csum |= M_CSUM_TCP_UDP_BAD; | |
1211 | } | 1211 | } | |
1212 | 1212 | |||
1213 | usbnet_enqueue(un, buf + sizeof(*hdrp), pktlen, csum, | 1213 | usbnet_enqueue(un, buf + sizeof(*hdrp), pktlen, csum, | |
1214 | 0, M_HASFCS); | 1214 | 0, M_HASFCS); | |
1215 | 1215 | |||
1216 | /* Attention: sizeof(hdr) = 10 */ | 1216 | /* Attention: sizeof(hdr) = 10 */ | |
1217 | pktlen = roundup(pktlen + sizeof(*hdrp), 4); | 1217 | pktlen = roundup(pktlen + sizeof(*hdrp), 4); | |
1218 | if (pktlen > total_len) | 1218 | if (pktlen > total_len) | |
1219 | pktlen = total_len; | 1219 | pktlen = total_len; | |
1220 | total_len -= pktlen; | 1220 | total_len -= pktlen; | |
1221 | buf += pktlen; | 1221 | buf += pktlen; | |
1222 | } while (total_len > 0); | 1222 | } while (total_len > 0); | |
1223 | } | 1223 | } | |
1224 | 1224 | |||
1225 | static int | 1225 | static int | |
1226 | mue_init_locked(struct ifnet *ifp) | 1226 | mue_init_locked(struct ifnet *ifp) | |
1227 | { | 1227 | { | |
1228 | struct usbnet * const un = ifp->if_softc; | 1228 | struct usbnet * const un = ifp->if_softc; | |
1229 | 1229 | |||
1230 | if (usbnet_isdying(un)) { | 1230 | if (usbnet_isdying(un)) { | |
1231 | DPRINTF(un, "dying\n"); | 1231 | DPRINTF(un, "dying\n"); | |
1232 | return EIO; | 1232 | return EIO; | |
1233 | } | 1233 | } | |
1234 | 1234 | |||
1235 | /* Cancel pending I/O and free all TX/RX buffers. */ | 1235 | /* Cancel pending I/O and free all TX/RX buffers. */ | |
1236 | if (ifp->if_flags & IFF_RUNNING) | 1236 | if (ifp->if_flags & IFF_RUNNING) | |
1237 | usbnet_stop(un, ifp, 1); | 1237 | usbnet_stop(un, ifp, 1); | |
1238 | 1238 | |||
1239 | mue_reset(un); | 1239 | mue_reset(un); | |
1240 | 1240 | |||
1241 | /* Set MAC address. */ | 1241 | /* Set MAC address. */ | |
1242 | mue_set_macaddr(un); | 1242 | mue_set_macaddr(un); | |
1243 | 1243 | |||
1244 | /* Load the multicast filter. */ | 1244 | /* Load the multicast filter. */ | |
1245 | mue_setiff_locked(un); | 1245 | mue_setiff_locked(un); | |
1246 | 1246 | |||
1247 | /* TCP/UDP checksum offload engines. */ | 1247 | /* TCP/UDP checksum offload engines. */ | |
1248 | mue_sethwcsum_locked(un); | 1248 | mue_sethwcsum_locked(un); | |
1249 | 1249 | |||
1250 | /* Set MTU. */ | 1250 | /* Set MTU. */ | |
1251 | mue_setmtu_locked(un); | 1251 | mue_setmtu_locked(un); | |
1252 | 1252 | |||
1253 | return usbnet_init_rx_tx(un); | 1253 | return usbnet_init_rx_tx(un); | |
1254 | } | 1254 | } | |
1255 | 1255 | |||
1256 | static int | 1256 | static int | |
1257 | mue_uno_init(struct ifnet *ifp) | 1257 | mue_uno_init(struct ifnet *ifp) | |
1258 | { | 1258 | { | |
1259 | int rv; | 1259 | int rv; | |
1260 | 1260 | |||
1261 | rv = mue_init_locked(ifp); | 1261 | rv = mue_init_locked(ifp); | |
1262 | 1262 | |||
1263 | return rv; | 1263 | return rv; | |
1264 | } | 1264 | } | |
1265 | 1265 | |||
1266 | static int | 1266 | static int | |
1267 | mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 1267 | mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
1268 | { | 1268 | { | |
1269 | struct usbnet * const un = ifp->if_softc; | 1269 | struct usbnet * const un = ifp->if_softc; | |
1270 | 1270 | |||
1271 | usbnet_lock_core(un); | 1271 | usbnet_lock_core(un); | |
1272 | usbnet_busy(un); | 1272 | usbnet_busy(un); | |
1273 | 1273 | |||
1274 | switch (cmd) { | 1274 | switch (cmd) { | |
1275 | case SIOCSIFCAP: | 1275 | case SIOCSIFCAP: | |
1276 | mue_sethwcsum_locked(un); | 1276 | mue_sethwcsum_locked(un); | |
1277 | break; | 1277 | break; | |
1278 | case SIOCSIFMTU: | 1278 | case SIOCSIFMTU: | |
1279 | mue_setmtu_locked(un); | 1279 | mue_setmtu_locked(un); | |
1280 | break; | 1280 | break; | |
1281 | default: | 1281 | default: | |
1282 | break; | 1282 | break; | |
1283 | } | 1283 | } | |
1284 | 1284 | |||
1285 | usbnet_unbusy(un); | 1285 | usbnet_unbusy(un); | |
1286 | usbnet_unlock_core(un); | 1286 | usbnet_unlock_core(un); | |
1287 | 1287 | |||
1288 | return 0; | 1288 | return 0; | |
1289 | } | 1289 | } | |
1290 | 1290 | |||
1291 | static void | 1291 | static void | |
1292 | mue_uno_mcast(struct ifnet *ifp) | 1292 | mue_uno_mcast(struct ifnet *ifp) | |
1293 | { | 1293 | { | |
1294 | struct usbnet * const un = ifp->if_softc; | 1294 | struct usbnet * const un = ifp->if_softc; | |
1295 | 1295 | |||
1296 | usbnet_lock_core(un); | 1296 | usbnet_lock_core(un); | |
1297 | usbnet_busy(un); | |||
1298 | 1297 | |||
1299 | mue_setiff_locked(un); | 1298 | mue_setiff_locked(un); | |
1300 | 1299 | |||
1301 | usbnet_unbusy(un); | |||
1302 | usbnet_unlock_core(un); | 1300 | usbnet_unlock_core(un); | |
1303 | } | 1301 | } | |
1304 | 1302 | |||
1305 | static void | 1303 | static void | |
1306 | mue_reset(struct usbnet *un) | 1304 | mue_reset(struct usbnet *un) | |
1307 | { | 1305 | { | |
1308 | if (usbnet_isdying(un)) | 1306 | if (usbnet_isdying(un)) | |
1309 | return; | 1307 | return; | |
1310 | 1308 | |||
1311 | /* Wait a little while for the chip to get its brains in order. */ | 1309 | /* Wait a little while for the chip to get its brains in order. */ | |
1312 | usbd_delay_ms(un->un_udev, 1); | 1310 | usbd_delay_ms(un->un_udev, 1); | |
1313 | 1311 | |||
1314 | // mue_chip_init(un); /* XXX */ | 1312 | // mue_chip_init(un); /* XXX */ | |
1315 | } | 1313 | } | |
1316 | 1314 | |||
1317 | static void | 1315 | static void | |
1318 | mue_uno_stop(struct ifnet *ifp, int disable) | 1316 | mue_uno_stop(struct ifnet *ifp, int disable) | |
1319 | { | 1317 | { | |
1320 | struct usbnet * const un = ifp->if_softc; | 1318 | struct usbnet * const un = ifp->if_softc; | |
1321 | 1319 | |||
1322 | mue_reset(un); | 1320 | mue_reset(un); | |
1323 | } | 1321 | } | |
1324 | 1322 | |||
1325 | #ifdef _MODULE | 1323 | #ifdef _MODULE | |
1326 | #include "ioconf.c" | 1324 | #include "ioconf.c" | |
1327 | #endif | 1325 | #endif | |
1328 | 1326 | |||
1329 | USBNET_MODULE(mue) | 1327 | USBNET_MODULE(mue) |
--- src/sys/dev/usb/if_smsc.c 2022/03/03 05:51:17 1.75
+++ src/sys/dev/usb/if_smsc.c 2022/03/03 05:51:27 1.76
@@ -1,1101 +1,1099 @@ | @@ -1,1101 +1,1099 @@ | |||
1 | /* $NetBSD: if_smsc.c,v 1.75 2022/03/03 05:51:17 riastradh Exp $ */ | 1 | /* $NetBSD: if_smsc.c,v 1.76 2022/03/03 05:51:27 riastradh Exp $ */ | |
2 | 2 | |||
3 | /* $OpenBSD: if_smsc.c,v 1.4 2012/09/27 12:38:11 jsg Exp $ */ | 3 | /* $OpenBSD: if_smsc.c,v 1.4 2012/09/27 12:38:11 jsg Exp $ */ | |
4 | /* $FreeBSD: src/sys/dev/usb/net/if_smsc.c,v 1.1 2012/08/15 04:03:55 gonzo Exp $ */ | 4 | /* $FreeBSD: src/sys/dev/usb/net/if_smsc.c,v 1.1 2012/08/15 04:03:55 gonzo Exp $ */ | |
5 | /*- | 5 | /*- | |
6 | * Copyright (c) 2012 | 6 | * Copyright (c) 2012 | |
7 | * Ben Gray <bgray@freebsd.org>. | 7 | * Ben Gray <bgray@freebsd.org>. | |
8 | * All rights reserved. | 8 | * All rights reserved. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | 20 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | 21 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | 22 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 23 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | */ | 29 | */ | |
30 | 30 | |||
31 | /* | 31 | /* | |
32 | * SMSC LAN9xxx devices (http://www.smsc.com/) | 32 | * SMSC LAN9xxx devices (http://www.smsc.com/) | |
33 | * | 33 | * | |
34 | * The LAN9500 & LAN9500A devices are stand-alone USB to Ethernet chips that | 34 | * The LAN9500 & LAN9500A devices are stand-alone USB to Ethernet chips that | |
35 | * support USB 2.0 and 10/100 Mbps Ethernet. | 35 | * support USB 2.0 and 10/100 Mbps Ethernet. | |
36 | * | 36 | * | |
37 | * The LAN951x devices are an integrated USB hub and USB to Ethernet adapter. | 37 | * The LAN951x devices are an integrated USB hub and USB to Ethernet adapter. | |
38 | * The driver only covers the Ethernet part, the standard USB hub driver | 38 | * The driver only covers the Ethernet part, the standard USB hub driver | |
39 | * supports the hub part. | 39 | * supports the hub part. | |
40 | * | 40 | * | |
41 | * This driver is closely modelled on the Linux driver written and copyrighted | 41 | * This driver is closely modelled on the Linux driver written and copyrighted | |
42 | * by SMSC. | 42 | * by SMSC. | |
43 | * | 43 | * | |
44 | * H/W TCP & UDP Checksum Offloading | 44 | * H/W TCP & UDP Checksum Offloading | |
45 | * --------------------------------- | 45 | * --------------------------------- | |
46 | * The chip supports both tx and rx offloading of UDP & TCP checksums, this | 46 | * The chip supports both tx and rx offloading of UDP & TCP checksums, this | |
47 | * feature can be dynamically enabled/disabled. | 47 | * feature can be dynamically enabled/disabled. | |
48 | * | 48 | * | |
49 | * RX checksuming is performed across bytes after the IPv4 header to the end of | 49 | * RX checksuming is performed across bytes after the IPv4 header to the end of | |
50 | * the Ethernet frame, this means if the frame is padded with non-zero values | 50 | * the Ethernet frame, this means if the frame is padded with non-zero values | |
51 | * the H/W checksum will be incorrect, however the rx code compensates for this. | 51 | * the H/W checksum will be incorrect, however the rx code compensates for this. | |
52 | * | 52 | * | |
53 | * TX checksuming is more complicated, the device requires a special header to | 53 | * TX checksuming is more complicated, the device requires a special header to | |
54 | * be prefixed onto the start of the frame which indicates the start and end | 54 | * be prefixed onto the start of the frame which indicates the start and end | |
55 | * positions of the UDP or TCP frame. This requires the driver to manually | 55 | * positions of the UDP or TCP frame. This requires the driver to manually | |
56 | * go through the packet data and decode the headers prior to sending. | 56 | * go through the packet data and decode the headers prior to sending. | |
57 | * On Linux they generally provide cues to the location of the csum and the | 57 | * On Linux they generally provide cues to the location of the csum and the | |
58 | * area to calculate it over, on FreeBSD we seem to have to do it all ourselves, | 58 | * area to calculate it over, on FreeBSD we seem to have to do it all ourselves, | |
59 | * hence this is not as optimal and therefore h/w TX checksum is currently not | 59 | * hence this is not as optimal and therefore h/w TX checksum is currently not | |
60 | * implemented. | 60 | * implemented. | |
61 | */ | 61 | */ | |
62 | 62 | |||
63 | #include <sys/cdefs.h> | 63 | #include <sys/cdefs.h> | |
64 | __KERNEL_RCSID(0, "$NetBSD: if_smsc.c,v 1.75 2022/03/03 05:51:17 riastradh Exp $"); | 64 | __KERNEL_RCSID(0, "$NetBSD: if_smsc.c,v 1.76 2022/03/03 05:51:27 riastradh Exp $"); | |
65 | 65 | |||
66 | #ifdef _KERNEL_OPT | 66 | #ifdef _KERNEL_OPT | |
67 | #include "opt_usb.h" | 67 | #include "opt_usb.h" | |
68 | #endif | 68 | #endif | |
69 | 69 | |||
70 | #include <sys/param.h> | 70 | #include <sys/param.h> | |
71 | 71 | |||
72 | #include <dev/usb/usbnet.h> | 72 | #include <dev/usb/usbnet.h> | |
73 | #include <dev/usb/usbhist.h> | 73 | #include <dev/usb/usbhist.h> | |
74 | 74 | |||
75 | #include <dev/usb/if_smscreg.h> | 75 | #include <dev/usb/if_smscreg.h> | |
76 | 76 | |||
77 | #include "ioconf.h" | 77 | #include "ioconf.h" | |
78 | 78 | |||
79 | struct smsc_softc { | 79 | struct smsc_softc { | |
80 | struct usbnet smsc_un; | 80 | struct usbnet smsc_un; | |
81 | 81 | |||
82 | /* | 82 | /* | |
83 | * The following stores the settings in the mac control (MAC_CSR) | 83 | * The following stores the settings in the mac control (MAC_CSR) | |
84 | * register | 84 | * register | |
85 | */ | 85 | */ | |
86 | uint32_t sc_mac_csr; | 86 | uint32_t sc_mac_csr; | |
87 | uint32_t sc_rev_id; | 87 | uint32_t sc_rev_id; | |
88 | 88 | |||
89 | uint32_t sc_coe_ctrl; | 89 | uint32_t sc_coe_ctrl; | |
90 | }; | 90 | }; | |
91 | 91 | |||
92 | #define SMSC_MIN_BUFSZ 2048 | 92 | #define SMSC_MIN_BUFSZ 2048 | |
93 | #define SMSC_MAX_BUFSZ 18944 | 93 | #define SMSC_MAX_BUFSZ 18944 | |
94 | 94 | |||
95 | /* | 95 | /* | |
96 | * Various supported device vendors/products. | 96 | * Various supported device vendors/products. | |
97 | */ | 97 | */ | |
98 | static const struct usb_devno smsc_devs[] = { | 98 | static const struct usb_devno smsc_devs[] = { | |
99 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN89530 }, | 99 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN89530 }, | |
100 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN9530 }, | 100 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN9530 }, | |
101 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN9730 }, | 101 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN9730 }, | |
102 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500 }, | 102 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500 }, | |
103 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500A }, | 103 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500A }, | |
104 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500A_ALT }, | 104 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500A_ALT }, | |
105 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500A_HAL }, | 105 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500A_HAL }, | |
106 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500A_SAL10 }, | 106 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500A_SAL10 }, | |
107 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500_ALT }, | 107 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500_ALT }, | |
108 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500_SAL10 }, | 108 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9500_SAL10 }, | |
109 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9505 }, | 109 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9505 }, | |
110 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9505A }, | 110 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9505A }, | |
111 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9505A_HAL }, | 111 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9505A_HAL }, | |
112 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9505A_SAL10 }, | 112 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9505A_SAL10 }, | |
113 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9505_SAL10 }, | 113 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9505_SAL10 }, | |
114 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9512_14 }, | 114 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9512_14 }, | |
115 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9512_14_ALT }, | 115 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9512_14_ALT }, | |
116 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9512_14_SAL10 } | 116 | { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_SMSC9512_14_SAL10 } | |
117 | }; | 117 | }; | |
118 | 118 | |||
119 | #ifdef USB_DEBUG | 119 | #ifdef USB_DEBUG | |
120 | #ifndef USMSC_DEBUG | 120 | #ifndef USMSC_DEBUG | |
121 | #define usmscdebug 0 | 121 | #define usmscdebug 0 | |
122 | #else | 122 | #else | |
123 | static int usmscdebug = 1; | 123 | static int usmscdebug = 1; | |
124 | 124 | |||
125 | SYSCTL_SETUP(sysctl_hw_smsc_setup, "sysctl hw.usmsc setup") | 125 | SYSCTL_SETUP(sysctl_hw_smsc_setup, "sysctl hw.usmsc setup") | |
126 | { | 126 | { | |
127 | int err; | 127 | int err; | |
128 | const struct sysctlnode *rnode; | 128 | const struct sysctlnode *rnode; | |
129 | const struct sysctlnode *cnode; | 129 | const struct sysctlnode *cnode; | |
130 | 130 | |||
131 | err = sysctl_createv(clog, 0, NULL, &rnode, | 131 | err = sysctl_createv(clog, 0, NULL, &rnode, | |
132 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "usmsc", | 132 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "usmsc", | |
133 | SYSCTL_DESCR("usmsc global controls"), | 133 | SYSCTL_DESCR("usmsc global controls"), | |
134 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | 134 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | |
135 | 135 | |||
136 | if (err) | 136 | if (err) | |
137 | goto fail; | 137 | goto fail; | |
138 | 138 | |||
139 | /* control debugging printfs */ | 139 | /* control debugging printfs */ | |
140 | err = sysctl_createv(clog, 0, &rnode, &cnode, | 140 | err = sysctl_createv(clog, 0, &rnode, &cnode, | |
141 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | 141 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | |
142 | "debug", SYSCTL_DESCR("Enable debugging output"), | 142 | "debug", SYSCTL_DESCR("Enable debugging output"), | |
143 | NULL, 0, &usmscdebug, sizeof(usmscdebug), CTL_CREATE, CTL_EOL); | 143 | NULL, 0, &usmscdebug, sizeof(usmscdebug), CTL_CREATE, CTL_EOL); | |
144 | if (err) | 144 | if (err) | |
145 | goto fail; | 145 | goto fail; | |
146 | 146 | |||
147 | return; | 147 | return; | |
148 | fail: | 148 | fail: | |
149 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | 149 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | |
150 | } | 150 | } | |
151 | 151 | |||
152 | #endif /* SMSC_DEBUG */ | 152 | #endif /* SMSC_DEBUG */ | |
153 | #endif /* USB_DEBUG */ | 153 | #endif /* USB_DEBUG */ | |
154 | 154 | |||
155 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOG(usmscdebug,FMT,A,B,C,D) | 155 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOG(usmscdebug,FMT,A,B,C,D) | |
156 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(usmscdebug,N,FMT,A,B,C,D) | 156 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(usmscdebug,N,FMT,A,B,C,D) | |
157 | #define USMSCHIST_FUNC() USBHIST_FUNC() | 157 | #define USMSCHIST_FUNC() USBHIST_FUNC() | |
158 | #define USMSCHIST_CALLED() USBHIST_CALLED(usmscdebug) | 158 | #define USMSCHIST_CALLED() USBHIST_CALLED(usmscdebug) | |
159 | 159 | |||
160 | #define smsc_warn_printf(un, fmt, args...) \ | 160 | #define smsc_warn_printf(un, fmt, args...) \ | |
161 | printf("%s: warning: " fmt, device_xname((un)->un_dev), ##args) | 161 | printf("%s: warning: " fmt, device_xname((un)->un_dev), ##args) | |
162 | 162 | |||
163 | #define smsc_err_printf(un, fmt, args...) \ | 163 | #define smsc_err_printf(un, fmt, args...) \ | |
164 | printf("%s: error: " fmt, device_xname((un)->un_dev), ##args) | 164 | printf("%s: error: " fmt, device_xname((un)->un_dev), ##args) | |
165 | 165 | |||
166 | /* Function declarations */ | 166 | /* Function declarations */ | |
167 | static int smsc_match(device_t, cfdata_t, void *); | 167 | static int smsc_match(device_t, cfdata_t, void *); | |
168 | static void smsc_attach(device_t, device_t, void *); | 168 | static void smsc_attach(device_t, device_t, void *); | |
169 | 169 | |||
170 | CFATTACH_DECL_NEW(usmsc, sizeof(struct smsc_softc), | 170 | CFATTACH_DECL_NEW(usmsc, sizeof(struct smsc_softc), | |
171 | smsc_match, smsc_attach, usbnet_detach, usbnet_activate); | 171 | smsc_match, smsc_attach, usbnet_detach, usbnet_activate); | |
172 | 172 | |||
173 | static int smsc_chip_init(struct usbnet *); | 173 | static int smsc_chip_init(struct usbnet *); | |
174 | static int smsc_setmacaddress(struct usbnet *, const uint8_t *); | 174 | static int smsc_setmacaddress(struct usbnet *, const uint8_t *); | |
175 | 175 | |||
176 | static int smsc_uno_init(struct ifnet *); | 176 | static int smsc_uno_init(struct ifnet *); | |
177 | static int smsc_init_locked(struct ifnet *); | 177 | static int smsc_init_locked(struct ifnet *); | |
178 | static void smsc_uno_stop(struct ifnet *, int); | 178 | static void smsc_uno_stop(struct ifnet *, int); | |
179 | 179 | |||
180 | static void smsc_reset(struct smsc_softc *); | 180 | static void smsc_reset(struct smsc_softc *); | |
181 | 181 | |||
182 | static void smsc_uno_miibus_statchg(struct ifnet *); | 182 | static void smsc_uno_miibus_statchg(struct ifnet *); | |
183 | static int smsc_readreg(struct usbnet *, uint32_t, uint32_t *); | 183 | static int smsc_readreg(struct usbnet *, uint32_t, uint32_t *); | |
184 | static int smsc_writereg(struct usbnet *, uint32_t, uint32_t); | 184 | static int smsc_writereg(struct usbnet *, uint32_t, uint32_t); | |
185 | static int smsc_wait_for_bits(struct usbnet *, uint32_t, uint32_t); | 185 | static int smsc_wait_for_bits(struct usbnet *, uint32_t, uint32_t); | |
186 | static int smsc_uno_miibus_readreg(struct usbnet *, int, int, uint16_t *); | 186 | static int smsc_uno_miibus_readreg(struct usbnet *, int, int, uint16_t *); | |
187 | static int smsc_uno_miibus_writereg(struct usbnet *, int, int, uint16_t); | 187 | static int smsc_uno_miibus_writereg(struct usbnet *, int, int, uint16_t); | |
188 | 188 | |||
189 | static int smsc_uno_ioctl(struct ifnet *, u_long, void *); | 189 | static int smsc_uno_ioctl(struct ifnet *, u_long, void *); | |
190 | static void smsc_uno_mcast(struct ifnet *); | 190 | static void smsc_uno_mcast(struct ifnet *); | |
191 | static unsigned smsc_uno_tx_prepare(struct usbnet *, struct mbuf *, | 191 | static unsigned smsc_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
192 | struct usbnet_chain *); | 192 | struct usbnet_chain *); | |
193 | static void smsc_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 193 | static void smsc_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
194 | uint32_t); | 194 | uint32_t); | |
195 | 195 | |||
196 | static const struct usbnet_ops smsc_ops = { | 196 | static const struct usbnet_ops smsc_ops = { | |
197 | .uno_stop = smsc_uno_stop, | 197 | .uno_stop = smsc_uno_stop, | |
198 | .uno_ioctl = smsc_uno_ioctl, | 198 | .uno_ioctl = smsc_uno_ioctl, | |
199 | .uno_mcast = smsc_uno_mcast, | 199 | .uno_mcast = smsc_uno_mcast, | |
200 | .uno_read_reg = smsc_uno_miibus_readreg, | 200 | .uno_read_reg = smsc_uno_miibus_readreg, | |
201 | .uno_write_reg = smsc_uno_miibus_writereg, | 201 | .uno_write_reg = smsc_uno_miibus_writereg, | |
202 | .uno_statchg = smsc_uno_miibus_statchg, | 202 | .uno_statchg = smsc_uno_miibus_statchg, | |
203 | .uno_tx_prepare = smsc_uno_tx_prepare, | 203 | .uno_tx_prepare = smsc_uno_tx_prepare, | |
204 | .uno_rx_loop = smsc_uno_rx_loop, | 204 | .uno_rx_loop = smsc_uno_rx_loop, | |
205 | .uno_init = smsc_uno_init, | 205 | .uno_init = smsc_uno_init, | |
206 | }; | 206 | }; | |
207 | 207 | |||
208 | static int | 208 | static int | |
209 | smsc_readreg(struct usbnet *un, uint32_t off, uint32_t *data) | 209 | smsc_readreg(struct usbnet *un, uint32_t off, uint32_t *data) | |
210 | { | 210 | { | |
211 | usb_device_request_t req; | 211 | usb_device_request_t req; | |
212 | uint32_t buf; | 212 | uint32_t buf; | |
213 | usbd_status err; | 213 | usbd_status err; | |
214 | 214 | |||
215 | usbnet_isowned_core(un); | 215 | usbnet_isowned_core(un); | |
216 | 216 | |||
217 | if (usbnet_isdying(un)) | 217 | if (usbnet_isdying(un)) | |
218 | return 0; | 218 | return 0; | |
219 | 219 | |||
220 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 220 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
221 | req.bRequest = SMSC_UR_READ_REG; | 221 | req.bRequest = SMSC_UR_READ_REG; | |
222 | USETW(req.wValue, 0); | 222 | USETW(req.wValue, 0); | |
223 | USETW(req.wIndex, off); | 223 | USETW(req.wIndex, off); | |
224 | USETW(req.wLength, 4); | 224 | USETW(req.wLength, 4); | |
225 | 225 | |||
226 | err = usbd_do_request(un->un_udev, &req, &buf); | 226 | err = usbd_do_request(un->un_udev, &req, &buf); | |
227 | if (err != 0) | 227 | if (err != 0) | |
228 | smsc_warn_printf(un, "Failed to read register 0x%0x\n", off); | 228 | smsc_warn_printf(un, "Failed to read register 0x%0x\n", off); | |
229 | 229 | |||
230 | *data = le32toh(buf); | 230 | *data = le32toh(buf); | |
231 | 231 | |||
232 | return err; | 232 | return err; | |
233 | } | 233 | } | |
234 | 234 | |||
235 | static int | 235 | static int | |
236 | smsc_writereg(struct usbnet *un, uint32_t off, uint32_t data) | 236 | smsc_writereg(struct usbnet *un, uint32_t off, uint32_t data) | |
237 | { | 237 | { | |
238 | usb_device_request_t req; | 238 | usb_device_request_t req; | |
239 | uint32_t buf; | 239 | uint32_t buf; | |
240 | usbd_status err; | 240 | usbd_status err; | |
241 | 241 | |||
242 | usbnet_isowned_core(un); | 242 | usbnet_isowned_core(un); | |
243 | 243 | |||
244 | if (usbnet_isdying(un)) | 244 | if (usbnet_isdying(un)) | |
245 | return 0; | 245 | return 0; | |
246 | 246 | |||
247 | buf = htole32(data); | 247 | buf = htole32(data); | |
248 | 248 | |||
249 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 249 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
250 | req.bRequest = SMSC_UR_WRITE_REG; | 250 | req.bRequest = SMSC_UR_WRITE_REG; | |
251 | USETW(req.wValue, 0); | 251 | USETW(req.wValue, 0); | |
252 | USETW(req.wIndex, off); | 252 | USETW(req.wIndex, off); | |
253 | USETW(req.wLength, 4); | 253 | USETW(req.wLength, 4); | |
254 | 254 | |||
255 | err = usbd_do_request(un->un_udev, &req, &buf); | 255 | err = usbd_do_request(un->un_udev, &req, &buf); | |
256 | if (err != 0) | 256 | if (err != 0) | |
257 | smsc_warn_printf(un, "Failed to write register 0x%0x\n", off); | 257 | smsc_warn_printf(un, "Failed to write register 0x%0x\n", off); | |
258 | 258 | |||
259 | return err; | 259 | return err; | |
260 | } | 260 | } | |
261 | 261 | |||
262 | static int | 262 | static int | |
263 | smsc_wait_for_bits(struct usbnet *un, uint32_t reg, uint32_t bits) | 263 | smsc_wait_for_bits(struct usbnet *un, uint32_t reg, uint32_t bits) | |
264 | { | 264 | { | |
265 | uint32_t val; | 265 | uint32_t val; | |
266 | int err, i; | 266 | int err, i; | |
267 | 267 | |||
268 | for (i = 0; i < 100; i++) { | 268 | for (i = 0; i < 100; i++) { | |
269 | if (usbnet_isdying(un)) | 269 | if (usbnet_isdying(un)) | |
270 | return ENXIO; | 270 | return ENXIO; | |
271 | if ((err = smsc_readreg(un, reg, &val)) != 0) | 271 | if ((err = smsc_readreg(un, reg, &val)) != 0) | |
272 | return err; | 272 | return err; | |
273 | if (!(val & bits)) | 273 | if (!(val & bits)) | |
274 | return 0; | 274 | return 0; | |
275 | DELAY(5); | 275 | DELAY(5); | |
276 | } | 276 | } | |
277 | 277 | |||
278 | return 1; | 278 | return 1; | |
279 | } | 279 | } | |
280 | 280 | |||
281 | static int | 281 | static int | |
282 | smsc_uno_miibus_readreg(struct usbnet *un, int phy, int reg, uint16_t *val) | 282 | smsc_uno_miibus_readreg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
283 | { | 283 | { | |
284 | uint32_t addr; | 284 | uint32_t addr; | |
285 | uint32_t data = 0; | 285 | uint32_t data = 0; | |
286 | 286 | |||
287 | if (un->un_phyno != phy) | 287 | if (un->un_phyno != phy) | |
288 | return EINVAL; | 288 | return EINVAL; | |
289 | 289 | |||
290 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | 290 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | |
291 | smsc_warn_printf(un, "MII is busy\n"); | 291 | smsc_warn_printf(un, "MII is busy\n"); | |
292 | return ETIMEDOUT; | 292 | return ETIMEDOUT; | |
293 | } | 293 | } | |
294 | 294 | |||
295 | addr = (phy << 11) | (reg << 6) | SMSC_MII_READ; | 295 | addr = (phy << 11) | (reg << 6) | SMSC_MII_READ; | |
296 | smsc_writereg(un, SMSC_MII_ADDR, addr); | 296 | smsc_writereg(un, SMSC_MII_ADDR, addr); | |
297 | 297 | |||
298 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | 298 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | |
299 | smsc_warn_printf(un, "MII read timeout\n"); | 299 | smsc_warn_printf(un, "MII read timeout\n"); | |
300 | return ETIMEDOUT; | 300 | return ETIMEDOUT; | |
301 | } | 301 | } | |
302 | 302 | |||
303 | smsc_readreg(un, SMSC_MII_DATA, &data); | 303 | smsc_readreg(un, SMSC_MII_DATA, &data); | |
304 | 304 | |||
305 | *val = data & 0xffff; | 305 | *val = data & 0xffff; | |
306 | return 0; | 306 | return 0; | |
307 | } | 307 | } | |
308 | 308 | |||
309 | static int | 309 | static int | |
310 | smsc_uno_miibus_writereg(struct usbnet *un, int phy, int reg, uint16_t val) | 310 | smsc_uno_miibus_writereg(struct usbnet *un, int phy, int reg, uint16_t val) | |
311 | { | 311 | { | |
312 | uint32_t addr; | 312 | uint32_t addr; | |
313 | 313 | |||
314 | if (un->un_phyno != phy) | 314 | if (un->un_phyno != phy) | |
315 | return EINVAL; | 315 | return EINVAL; | |
316 | 316 | |||
317 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | 317 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | |
318 | smsc_warn_printf(un, "MII is busy\n"); | 318 | smsc_warn_printf(un, "MII is busy\n"); | |
319 | return ETIMEDOUT; | 319 | return ETIMEDOUT; | |
320 | } | 320 | } | |
321 | 321 | |||
322 | smsc_writereg(un, SMSC_MII_DATA, val); | 322 | smsc_writereg(un, SMSC_MII_DATA, val); | |
323 | 323 | |||
324 | addr = (phy << 11) | (reg << 6) | SMSC_MII_WRITE; | 324 | addr = (phy << 11) | (reg << 6) | SMSC_MII_WRITE; | |
325 | smsc_writereg(un, SMSC_MII_ADDR, addr); | 325 | smsc_writereg(un, SMSC_MII_ADDR, addr); | |
326 | 326 | |||
327 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | 327 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | |
328 | smsc_warn_printf(un, "MII write timeout\n"); | 328 | smsc_warn_printf(un, "MII write timeout\n"); | |
329 | return ETIMEDOUT; | 329 | return ETIMEDOUT; | |
330 | } | 330 | } | |
331 | 331 | |||
332 | return 0; | 332 | return 0; | |
333 | } | 333 | } | |
334 | 334 | |||
335 | static void | 335 | static void | |
336 | smsc_uno_miibus_statchg(struct ifnet *ifp) | 336 | smsc_uno_miibus_statchg(struct ifnet *ifp) | |
337 | { | 337 | { | |
338 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | 338 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | |
339 | struct usbnet * const un = ifp->if_softc; | 339 | struct usbnet * const un = ifp->if_softc; | |
340 | 340 | |||
341 | if (usbnet_isdying(un)) | 341 | if (usbnet_isdying(un)) | |
342 | return; | 342 | return; | |
343 | 343 | |||
344 | struct smsc_softc * const sc = usbnet_softc(un); | 344 | struct smsc_softc * const sc = usbnet_softc(un); | |
345 | struct mii_data * const mii = usbnet_mii(un); | 345 | struct mii_data * const mii = usbnet_mii(un); | |
346 | uint32_t flow; | 346 | uint32_t flow; | |
347 | uint32_t afc_cfg; | 347 | uint32_t afc_cfg; | |
348 | 348 | |||
349 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 349 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
350 | (IFM_ACTIVE | IFM_AVALID)) { | 350 | (IFM_ACTIVE | IFM_AVALID)) { | |
351 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 351 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
352 | case IFM_10_T: | 352 | case IFM_10_T: | |
353 | case IFM_100_TX: | 353 | case IFM_100_TX: | |
354 | usbnet_set_link(un, true); | 354 | usbnet_set_link(un, true); | |
355 | break; | 355 | break; | |
356 | case IFM_1000_T: | 356 | case IFM_1000_T: | |
357 | /* Gigabit ethernet not supported by chipset */ | 357 | /* Gigabit ethernet not supported by chipset */ | |
358 | break; | 358 | break; | |
359 | default: | 359 | default: | |
360 | break; | 360 | break; | |
361 | } | 361 | } | |
362 | } | 362 | } | |
363 | 363 | |||
364 | /* Lost link, do nothing. */ | 364 | /* Lost link, do nothing. */ | |
365 | if (!usbnet_havelink(un)) | 365 | if (!usbnet_havelink(un)) | |
366 | return; | 366 | return; | |
367 | 367 | |||
368 | int err = smsc_readreg(un, SMSC_AFC_CFG, &afc_cfg); | 368 | int err = smsc_readreg(un, SMSC_AFC_CFG, &afc_cfg); | |
369 | if (err) { | 369 | if (err) { | |
370 | smsc_warn_printf(un, "failed to read initial AFC_CFG, " | 370 | smsc_warn_printf(un, "failed to read initial AFC_CFG, " | |
371 | "error %d\n", err); | 371 | "error %d\n", err); | |
372 | return; | 372 | return; | |
373 | } | 373 | } | |
374 | 374 | |||
375 | /* Enable/disable full duplex operation and TX/RX pause */ | 375 | /* Enable/disable full duplex operation and TX/RX pause */ | |
376 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { | 376 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { | |
377 | DPRINTF("full duplex operation", 0, 0, 0, 0); | 377 | DPRINTF("full duplex operation", 0, 0, 0, 0); | |
378 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_RCVOWN; | 378 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_RCVOWN; | |
379 | sc->sc_mac_csr |= SMSC_MAC_CSR_FDPX; | 379 | sc->sc_mac_csr |= SMSC_MAC_CSR_FDPX; | |
380 | 380 | |||
381 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) | 381 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) | |
382 | flow = 0xffff0002; | 382 | flow = 0xffff0002; | |
383 | else | 383 | else | |
384 | flow = 0; | 384 | flow = 0; | |
385 | 385 | |||
386 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) | 386 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) | |
387 | afc_cfg |= 0xf; | 387 | afc_cfg |= 0xf; | |
388 | else | 388 | else | |
389 | afc_cfg &= ~0xf; | 389 | afc_cfg &= ~0xf; | |
390 | } else { | 390 | } else { | |
391 | DPRINTF("half duplex operation", 0, 0, 0, 0); | 391 | DPRINTF("half duplex operation", 0, 0, 0, 0); | |
392 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_FDPX; | 392 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_FDPX; | |
393 | sc->sc_mac_csr |= SMSC_MAC_CSR_RCVOWN; | 393 | sc->sc_mac_csr |= SMSC_MAC_CSR_RCVOWN; | |
394 | 394 | |||
395 | flow = 0; | 395 | flow = 0; | |
396 | afc_cfg |= 0xf; | 396 | afc_cfg |= 0xf; | |
397 | } | 397 | } | |
398 | 398 | |||
399 | err = smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 399 | err = smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
400 | err += smsc_writereg(un, SMSC_FLOW, flow); | 400 | err += smsc_writereg(un, SMSC_FLOW, flow); | |
401 | err += smsc_writereg(un, SMSC_AFC_CFG, afc_cfg); | 401 | err += smsc_writereg(un, SMSC_AFC_CFG, afc_cfg); | |
402 | 402 | |||
403 | if (err) | 403 | if (err) | |
404 | smsc_warn_printf(un, "media change failed, error %d\n", err); | 404 | smsc_warn_printf(un, "media change failed, error %d\n", err); | |
405 | } | 405 | } | |
406 | 406 | |||
407 | static inline uint32_t | 407 | static inline uint32_t | |
408 | smsc_hash(uint8_t addr[ETHER_ADDR_LEN]) | 408 | smsc_hash(uint8_t addr[ETHER_ADDR_LEN]) | |
409 | { | 409 | { | |
410 | 410 | |||
411 | return (ether_crc32_be(addr, ETHER_ADDR_LEN) >> 26) & 0x3f; | 411 | return (ether_crc32_be(addr, ETHER_ADDR_LEN) >> 26) & 0x3f; | |
412 | } | 412 | } | |
413 | 413 | |||
414 | static void | 414 | static void | |
415 | smsc_setiff_locked(struct usbnet *un) | 415 | smsc_setiff_locked(struct usbnet *un) | |
416 | { | 416 | { | |
417 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | 417 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | |
418 | struct smsc_softc * const sc = usbnet_softc(un); | 418 | struct smsc_softc * const sc = usbnet_softc(un); | |
419 | struct ifnet * const ifp = usbnet_ifp(un); | 419 | struct ifnet * const ifp = usbnet_ifp(un); | |
420 | struct ethercom *ec = usbnet_ec(un); | 420 | struct ethercom *ec = usbnet_ec(un); | |
421 | struct ether_multi *enm; | 421 | struct ether_multi *enm; | |
422 | struct ether_multistep step; | 422 | struct ether_multistep step; | |
423 | uint32_t hashtbl[2] = { 0, 0 }; | 423 | uint32_t hashtbl[2] = { 0, 0 }; | |
424 | uint32_t hash; | 424 | uint32_t hash; | |
425 | 425 | |||
426 | usbnet_isowned_core(un); | 426 | usbnet_isowned_core(un); | |
427 | 427 | |||
428 | if (usbnet_isdying(un)) | 428 | if (usbnet_isdying(un)) | |
429 | return; | 429 | return; | |
430 | 430 | |||
431 | if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { | 431 | if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { | |
432 | allmulti: | 432 | allmulti: | |
433 | DPRINTF("receive all multicast enabled", 0, 0, 0, 0); | 433 | DPRINTF("receive all multicast enabled", 0, 0, 0, 0); | |
434 | sc->sc_mac_csr |= SMSC_MAC_CSR_MCPAS; | 434 | sc->sc_mac_csr |= SMSC_MAC_CSR_MCPAS; | |
435 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_HPFILT; | 435 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_HPFILT; | |
436 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 436 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
437 | return; | 437 | return; | |
438 | } else { | 438 | } else { | |
439 | sc->sc_mac_csr |= SMSC_MAC_CSR_HPFILT; | 439 | sc->sc_mac_csr |= SMSC_MAC_CSR_HPFILT; | |
440 | sc->sc_mac_csr &= ~(SMSC_MAC_CSR_PRMS | SMSC_MAC_CSR_MCPAS); | 440 | sc->sc_mac_csr &= ~(SMSC_MAC_CSR_PRMS | SMSC_MAC_CSR_MCPAS); | |
441 | } | 441 | } | |
442 | 442 | |||
443 | ETHER_LOCK(ec); | 443 | ETHER_LOCK(ec); | |
444 | ETHER_FIRST_MULTI(step, ec, enm); | 444 | ETHER_FIRST_MULTI(step, ec, enm); | |
445 | while (enm != NULL) { | 445 | while (enm != NULL) { | |
446 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 446 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
447 | ETHER_UNLOCK(ec); | 447 | ETHER_UNLOCK(ec); | |
448 | goto allmulti; | 448 | goto allmulti; | |
449 | } | 449 | } | |
450 | 450 | |||
451 | hash = smsc_hash(enm->enm_addrlo); | 451 | hash = smsc_hash(enm->enm_addrlo); | |
452 | hashtbl[hash >> 5] |= 1 << (hash & 0x1F); | 452 | hashtbl[hash >> 5] |= 1 << (hash & 0x1F); | |
453 | ETHER_NEXT_MULTI(step, enm); | 453 | ETHER_NEXT_MULTI(step, enm); | |
454 | } | 454 | } | |
455 | ETHER_UNLOCK(ec); | 455 | ETHER_UNLOCK(ec); | |
456 | 456 | |||
457 | /* Debug */ | 457 | /* Debug */ | |
458 | if (sc->sc_mac_csr & SMSC_MAC_CSR_HPFILT) { | 458 | if (sc->sc_mac_csr & SMSC_MAC_CSR_HPFILT) { | |
459 | DPRINTF("receive select group of macs", 0, 0, 0, 0); | 459 | DPRINTF("receive select group of macs", 0, 0, 0, 0); | |
460 | } else { | 460 | } else { | |
461 | DPRINTF("receive own packets only", 0, 0, 0, 0); | 461 | DPRINTF("receive own packets only", 0, 0, 0, 0); | |
462 | } | 462 | } | |
463 | 463 | |||
464 | /* Write the hash table and mac control registers */ | 464 | /* Write the hash table and mac control registers */ | |
465 | 465 | |||
466 | //XXX should we be doing this? | 466 | //XXX should we be doing this? | |
467 | ifp->if_flags &= ~IFF_ALLMULTI; | 467 | ifp->if_flags &= ~IFF_ALLMULTI; | |
468 | smsc_writereg(un, SMSC_HASHH, hashtbl[1]); | 468 | smsc_writereg(un, SMSC_HASHH, hashtbl[1]); | |
469 | smsc_writereg(un, SMSC_HASHL, hashtbl[0]); | 469 | smsc_writereg(un, SMSC_HASHL, hashtbl[0]); | |
470 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 470 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
471 | } | 471 | } | |
472 | 472 | |||
473 | static int | 473 | static int | |
474 | smsc_setoe_locked(struct usbnet *un) | 474 | smsc_setoe_locked(struct usbnet *un) | |
475 | { | 475 | { | |
476 | struct smsc_softc * const sc = usbnet_softc(un); | 476 | struct smsc_softc * const sc = usbnet_softc(un); | |
477 | struct ifnet * const ifp = usbnet_ifp(un); | 477 | struct ifnet * const ifp = usbnet_ifp(un); | |
478 | uint32_t val; | 478 | uint32_t val; | |
479 | int err; | 479 | int err; | |
480 | 480 | |||
481 | usbnet_isowned_core(un); | 481 | usbnet_isowned_core(un); | |
482 | 482 | |||
483 | err = smsc_readreg(un, SMSC_COE_CTRL, &val); | 483 | err = smsc_readreg(un, SMSC_COE_CTRL, &val); | |
484 | if (err != 0) { | 484 | if (err != 0) { | |
485 | smsc_warn_printf(un, "failed to read SMSC_COE_CTRL (err=%d)\n", | 485 | smsc_warn_printf(un, "failed to read SMSC_COE_CTRL (err=%d)\n", | |
486 | err); | 486 | err); | |
487 | return err; | 487 | return err; | |
488 | } | 488 | } | |
489 | 489 | |||
490 | /* Enable/disable the Rx checksum */ | 490 | /* Enable/disable the Rx checksum */ | |
491 | if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx)) | 491 | if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx)) | |
492 | val |= (SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE); | 492 | val |= (SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE); | |
493 | else | 493 | else | |
494 | val &= ~(SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE); | 494 | val &= ~(SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE); | |
495 | 495 | |||
496 | /* Enable/disable the Tx checksum (currently not supported) */ | 496 | /* Enable/disable the Tx checksum (currently not supported) */ | |
497 | if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx)) | 497 | if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx)) | |
498 | val |= SMSC_COE_CTRL_TX_EN; | 498 | val |= SMSC_COE_CTRL_TX_EN; | |
499 | else | 499 | else | |
500 | val &= ~SMSC_COE_CTRL_TX_EN; | 500 | val &= ~SMSC_COE_CTRL_TX_EN; | |
501 | 501 | |||
502 | sc->sc_coe_ctrl = val; | 502 | sc->sc_coe_ctrl = val; | |
503 | 503 | |||
504 | err = smsc_writereg(un, SMSC_COE_CTRL, val); | 504 | err = smsc_writereg(un, SMSC_COE_CTRL, val); | |
505 | if (err != 0) { | 505 | if (err != 0) { | |
506 | smsc_warn_printf(un, "failed to write SMSC_COE_CTRL (err=%d)\n", | 506 | smsc_warn_printf(un, "failed to write SMSC_COE_CTRL (err=%d)\n", | |
507 | err); | 507 | err); | |
508 | return err; | 508 | return err; | |
509 | } | 509 | } | |
510 | 510 | |||
511 | return 0; | 511 | return 0; | |
512 | } | 512 | } | |
513 | 513 | |||
514 | static int | 514 | static int | |
515 | smsc_setmacaddress(struct usbnet *un, const uint8_t *addr) | 515 | smsc_setmacaddress(struct usbnet *un, const uint8_t *addr) | |
516 | { | 516 | { | |
517 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | 517 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | |
518 | int err; | 518 | int err; | |
519 | uint32_t val; | 519 | uint32_t val; | |
520 | 520 | |||
521 | DPRINTF("setting mac address to %02jx:%02jx:%02jx:...", addr[0], | 521 | DPRINTF("setting mac address to %02jx:%02jx:%02jx:...", addr[0], | |
522 | addr[1], addr[2], 0); | 522 | addr[1], addr[2], 0); | |
523 | 523 | |||
524 | DPRINTF("... %02jx:%02jx:%02jx", addr[3], addr[4], addr[5], 0); | 524 | DPRINTF("... %02jx:%02jx:%02jx", addr[3], addr[4], addr[5], 0); | |
525 | 525 | |||
526 | val = ((uint32_t)addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | 526 | val = ((uint32_t)addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | |
527 | | addr[0]; | 527 | | addr[0]; | |
528 | if ((err = smsc_writereg(un, SMSC_MAC_ADDRL, val)) != 0) | 528 | if ((err = smsc_writereg(un, SMSC_MAC_ADDRL, val)) != 0) | |
529 | goto done; | 529 | goto done; | |
530 | 530 | |||
531 | val = (addr[5] << 8) | addr[4]; | 531 | val = (addr[5] << 8) | addr[4]; | |
532 | err = smsc_writereg(un, SMSC_MAC_ADDRH, val); | 532 | err = smsc_writereg(un, SMSC_MAC_ADDRH, val); | |
533 | 533 | |||
534 | done: | 534 | done: | |
535 | return err; | 535 | return err; | |
536 | } | 536 | } | |
537 | 537 | |||
538 | static void | 538 | static void | |
539 | smsc_reset(struct smsc_softc *sc) | 539 | smsc_reset(struct smsc_softc *sc) | |
540 | { | 540 | { | |
541 | struct usbnet * const un = &sc->smsc_un; | 541 | struct usbnet * const un = &sc->smsc_un; | |
542 | 542 | |||
543 | usbnet_isowned_core(un); | 543 | usbnet_isowned_core(un); | |
544 | if (usbnet_isdying(un)) | 544 | if (usbnet_isdying(un)) | |
545 | return; | 545 | return; | |
546 | 546 | |||
547 | /* Wait a little while for the chip to get its brains in order. */ | 547 | /* Wait a little while for the chip to get its brains in order. */ | |
548 | DELAY(1000); | 548 | DELAY(1000); | |
549 | 549 | |||
550 | /* Reinitialize controller to achieve full reset. */ | 550 | /* Reinitialize controller to achieve full reset. */ | |
551 | smsc_chip_init(un); | 551 | smsc_chip_init(un); | |
552 | } | 552 | } | |
553 | 553 | |||
554 | static int | 554 | static int | |
555 | smsc_uno_init(struct ifnet *ifp) | 555 | smsc_uno_init(struct ifnet *ifp) | |
556 | { | 556 | { | |
557 | int ret = smsc_init_locked(ifp); | 557 | int ret = smsc_init_locked(ifp); | |
558 | 558 | |||
559 | return ret; | 559 | return ret; | |
560 | } | 560 | } | |
561 | 561 | |||
562 | static int | 562 | static int | |
563 | smsc_init_locked(struct ifnet *ifp) | 563 | smsc_init_locked(struct ifnet *ifp) | |
564 | { | 564 | { | |
565 | struct usbnet * const un = ifp->if_softc; | 565 | struct usbnet * const un = ifp->if_softc; | |
566 | struct smsc_softc * const sc = usbnet_softc(un); | 566 | struct smsc_softc * const sc = usbnet_softc(un); | |
567 | 567 | |||
568 | usbnet_isowned_core(un); | 568 | usbnet_isowned_core(un); | |
569 | 569 | |||
570 | if (usbnet_isdying(un)) | 570 | if (usbnet_isdying(un)) | |
571 | return EIO; | 571 | return EIO; | |
572 | 572 | |||
573 | /* Cancel pending I/O */ | 573 | /* Cancel pending I/O */ | |
574 | usbnet_stop(un, ifp, 1); | 574 | usbnet_stop(un, ifp, 1); | |
575 | 575 | |||
576 | /* Reset the ethernet interface. */ | 576 | /* Reset the ethernet interface. */ | |
577 | smsc_reset(sc); | 577 | smsc_reset(sc); | |
578 | 578 | |||
579 | /* Load the multicast filter. */ | 579 | /* Load the multicast filter. */ | |
580 | smsc_setiff_locked(un); | 580 | smsc_setiff_locked(un); | |
581 | 581 | |||
582 | /* TCP/UDP checksum offload engines. */ | 582 | /* TCP/UDP checksum offload engines. */ | |
583 | smsc_setoe_locked(un); | 583 | smsc_setoe_locked(un); | |
584 | 584 | |||
585 | return usbnet_init_rx_tx(un); | 585 | return usbnet_init_rx_tx(un); | |
586 | } | 586 | } | |
587 | 587 | |||
588 | static void | 588 | static void | |
589 | smsc_uno_stop(struct ifnet *ifp, int disable) | 589 | smsc_uno_stop(struct ifnet *ifp, int disable) | |
590 | { | 590 | { | |
591 | struct usbnet * const un = ifp->if_softc; | 591 | struct usbnet * const un = ifp->if_softc; | |
592 | struct smsc_softc * const sc = usbnet_softc(un); | 592 | struct smsc_softc * const sc = usbnet_softc(un); | |
593 | 593 | |||
594 | // XXXNH didn't do this before | 594 | // XXXNH didn't do this before | |
595 | smsc_reset(sc); | 595 | smsc_reset(sc); | |
596 | } | 596 | } | |
597 | 597 | |||
598 | static int | 598 | static int | |
599 | smsc_chip_init(struct usbnet *un) | 599 | smsc_chip_init(struct usbnet *un) | |
600 | { | 600 | { | |
601 | struct smsc_softc * const sc = usbnet_softc(un); | 601 | struct smsc_softc * const sc = usbnet_softc(un); | |
602 | uint32_t reg_val; | 602 | uint32_t reg_val; | |
603 | int burst_cap; | 603 | int burst_cap; | |
604 | int err; | 604 | int err; | |
605 | 605 | |||
606 | usbnet_isowned_core(un); | 606 | usbnet_isowned_core(un); | |
607 | 607 | |||
608 | /* Enter H/W config mode */ | 608 | /* Enter H/W config mode */ | |
609 | smsc_writereg(un, SMSC_HW_CFG, SMSC_HW_CFG_LRST); | 609 | smsc_writereg(un, SMSC_HW_CFG, SMSC_HW_CFG_LRST); | |
610 | 610 | |||
611 | if ((err = smsc_wait_for_bits(un, SMSC_HW_CFG, | 611 | if ((err = smsc_wait_for_bits(un, SMSC_HW_CFG, | |
612 | SMSC_HW_CFG_LRST)) != 0) { | 612 | SMSC_HW_CFG_LRST)) != 0) { | |
613 | smsc_warn_printf(un, "timed-out waiting for reset to " | 613 | smsc_warn_printf(un, "timed-out waiting for reset to " | |
614 | "complete\n"); | 614 | "complete\n"); | |
615 | goto init_failed; | 615 | goto init_failed; | |
616 | } | 616 | } | |
617 | 617 | |||
618 | /* Reset the PHY */ | 618 | /* Reset the PHY */ | |
619 | smsc_writereg(un, SMSC_PM_CTRL, SMSC_PM_CTRL_PHY_RST); | 619 | smsc_writereg(un, SMSC_PM_CTRL, SMSC_PM_CTRL_PHY_RST); | |
620 | 620 | |||
621 | if ((err = smsc_wait_for_bits(un, SMSC_PM_CTRL, | 621 | if ((err = smsc_wait_for_bits(un, SMSC_PM_CTRL, | |
622 | SMSC_PM_CTRL_PHY_RST)) != 0) { | 622 | SMSC_PM_CTRL_PHY_RST)) != 0) { | |
623 | smsc_warn_printf(un, "timed-out waiting for phy reset to " | 623 | smsc_warn_printf(un, "timed-out waiting for phy reset to " | |
624 | "complete\n"); | 624 | "complete\n"); | |
625 | goto init_failed; | 625 | goto init_failed; | |
626 | } | 626 | } | |
627 | usbd_delay_ms(un->un_udev, 40); | 627 | usbd_delay_ms(un->un_udev, 40); | |
628 | 628 | |||
629 | /* Set the mac address */ | 629 | /* Set the mac address */ | |
630 | struct ifnet * const ifp = usbnet_ifp(un); | 630 | struct ifnet * const ifp = usbnet_ifp(un); | |
631 | const char *eaddr = CLLADDR(ifp->if_sadl); | 631 | const char *eaddr = CLLADDR(ifp->if_sadl); | |
632 | if ((err = smsc_setmacaddress(un, eaddr)) != 0) { | 632 | if ((err = smsc_setmacaddress(un, eaddr)) != 0) { | |
633 | smsc_warn_printf(un, "failed to set the MAC address\n"); | 633 | smsc_warn_printf(un, "failed to set the MAC address\n"); | |
634 | goto init_failed; | 634 | goto init_failed; | |
635 | } | 635 | } | |
636 | 636 | |||
637 | /* | 637 | /* | |
638 | * Don't know what the HW_CFG_BIR bit is, but following the reset | 638 | * Don't know what the HW_CFG_BIR bit is, but following the reset | |
639 | * sequence as used in the Linux driver. | 639 | * sequence as used in the Linux driver. | |
640 | */ | 640 | */ | |
641 | if ((err = smsc_readreg(un, SMSC_HW_CFG, ®_val)) != 0) { | 641 | if ((err = smsc_readreg(un, SMSC_HW_CFG, ®_val)) != 0) { | |
642 | smsc_warn_printf(un, "failed to read HW_CFG: %d\n", err); | 642 | smsc_warn_printf(un, "failed to read HW_CFG: %d\n", err); | |
643 | goto init_failed; | 643 | goto init_failed; | |
644 | } | 644 | } | |
645 | reg_val |= SMSC_HW_CFG_BIR; | 645 | reg_val |= SMSC_HW_CFG_BIR; | |
646 | smsc_writereg(un, SMSC_HW_CFG, reg_val); | 646 | smsc_writereg(un, SMSC_HW_CFG, reg_val); | |
647 | 647 | |||
648 | /* | 648 | /* | |
649 | * There is a so called 'turbo mode' that the linux driver supports, it | 649 | * There is a so called 'turbo mode' that the linux driver supports, it | |
650 | * seems to allow you to jam multiple frames per Rx transaction. | 650 | * seems to allow you to jam multiple frames per Rx transaction. | |
651 | * By default this driver supports that and therefore allows multiple | 651 | * By default this driver supports that and therefore allows multiple | |
652 | * frames per USB transfer. | 652 | * frames per USB transfer. | |
653 | * | 653 | * | |
654 | * The xfer buffer size needs to reflect this as well, therefore based | 654 | * The xfer buffer size needs to reflect this as well, therefore based | |
655 | * on the calculations in the Linux driver the RX bufsize is set to | 655 | * on the calculations in the Linux driver the RX bufsize is set to | |
656 | * 18944, | 656 | * 18944, | |
657 | * bufsz = (16 * 1024 + 5 * 512) | 657 | * bufsz = (16 * 1024 + 5 * 512) | |
658 | * | 658 | * | |
659 | * Burst capability is the number of URBs that can be in a burst of | 659 | * Burst capability is the number of URBs that can be in a burst of | |
660 | * data/ethernet frames. | 660 | * data/ethernet frames. | |
661 | */ | 661 | */ | |
662 | 662 | |||
663 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | 663 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | |
664 | burst_cap = 37; | 664 | burst_cap = 37; | |
665 | else | 665 | else | |
666 | burst_cap = 128; | 666 | burst_cap = 128; | |
667 | 667 | |||
668 | smsc_writereg(un, SMSC_BURST_CAP, burst_cap); | 668 | smsc_writereg(un, SMSC_BURST_CAP, burst_cap); | |
669 | 669 | |||
670 | /* Set the default bulk in delay (magic value from Linux driver) */ | 670 | /* Set the default bulk in delay (magic value from Linux driver) */ | |
671 | smsc_writereg(un, SMSC_BULK_IN_DLY, 0x00002000); | 671 | smsc_writereg(un, SMSC_BULK_IN_DLY, 0x00002000); | |
672 | 672 | |||
673 | /* | 673 | /* | |
674 | * Initialise the RX interface | 674 | * Initialise the RX interface | |
675 | */ | 675 | */ | |
676 | if ((err = smsc_readreg(un, SMSC_HW_CFG, ®_val)) < 0) { | 676 | if ((err = smsc_readreg(un, SMSC_HW_CFG, ®_val)) < 0) { | |
677 | smsc_warn_printf(un, "failed to read HW_CFG: (err = %d)\n", | 677 | smsc_warn_printf(un, "failed to read HW_CFG: (err = %d)\n", | |
678 | err); | 678 | err); | |
679 | goto init_failed; | 679 | goto init_failed; | |
680 | } | 680 | } | |
681 | 681 | |||
682 | /* | 682 | /* | |
683 | * The following settings are used for 'turbo mode', a.k.a multiple | 683 | * The following settings are used for 'turbo mode', a.k.a multiple | |
684 | * frames per Rx transaction (again info taken form Linux driver). | 684 | * frames per Rx transaction (again info taken form Linux driver). | |
685 | */ | 685 | */ | |
686 | reg_val |= (SMSC_HW_CFG_MEF | SMSC_HW_CFG_BCE); | 686 | reg_val |= (SMSC_HW_CFG_MEF | SMSC_HW_CFG_BCE); | |
687 | 687 | |||
688 | /* | 688 | /* | |
689 | * set Rx data offset to ETHER_ALIGN which will make the IP header | 689 | * set Rx data offset to ETHER_ALIGN which will make the IP header | |
690 | * align on a word boundary. | 690 | * align on a word boundary. | |
691 | */ | 691 | */ | |
692 | reg_val |= ETHER_ALIGN << SMSC_HW_CFG_RXDOFF_SHIFT; | 692 | reg_val |= ETHER_ALIGN << SMSC_HW_CFG_RXDOFF_SHIFT; | |
693 | 693 | |||
694 | smsc_writereg(un, SMSC_HW_CFG, reg_val); | 694 | smsc_writereg(un, SMSC_HW_CFG, reg_val); | |
695 | 695 | |||
696 | /* Clear the status register ? */ | 696 | /* Clear the status register ? */ | |
697 | smsc_writereg(un, SMSC_INTR_STATUS, 0xffffffff); | 697 | smsc_writereg(un, SMSC_INTR_STATUS, 0xffffffff); | |
698 | 698 | |||
699 | /* Read and display the revision register */ | 699 | /* Read and display the revision register */ | |
700 | if ((err = smsc_readreg(un, SMSC_ID_REV, &sc->sc_rev_id)) < 0) { | 700 | if ((err = smsc_readreg(un, SMSC_ID_REV, &sc->sc_rev_id)) < 0) { | |
701 | smsc_warn_printf(un, "failed to read ID_REV (err = %d)\n", err); | 701 | smsc_warn_printf(un, "failed to read ID_REV (err = %d)\n", err); | |
702 | goto init_failed; | 702 | goto init_failed; | |
703 | } | 703 | } | |
704 | 704 | |||
705 | /* GPIO/LED setup */ | 705 | /* GPIO/LED setup */ | |
706 | reg_val = SMSC_LED_GPIO_CFG_SPD_LED | SMSC_LED_GPIO_CFG_LNK_LED | | 706 | reg_val = SMSC_LED_GPIO_CFG_SPD_LED | SMSC_LED_GPIO_CFG_LNK_LED | | |
707 | SMSC_LED_GPIO_CFG_FDX_LED; | 707 | SMSC_LED_GPIO_CFG_FDX_LED; | |
708 | smsc_writereg(un, SMSC_LED_GPIO_CFG, reg_val); | 708 | smsc_writereg(un, SMSC_LED_GPIO_CFG, reg_val); | |
709 | 709 | |||
710 | /* | 710 | /* | |
711 | * Initialise the TX interface | 711 | * Initialise the TX interface | |
712 | */ | 712 | */ | |
713 | smsc_writereg(un, SMSC_FLOW, 0); | 713 | smsc_writereg(un, SMSC_FLOW, 0); | |
714 | 714 | |||
715 | smsc_writereg(un, SMSC_AFC_CFG, AFC_CFG_DEFAULT); | 715 | smsc_writereg(un, SMSC_AFC_CFG, AFC_CFG_DEFAULT); | |
716 | 716 | |||
717 | /* Read the current MAC configuration */ | 717 | /* Read the current MAC configuration */ | |
718 | if ((err = smsc_readreg(un, SMSC_MAC_CSR, &sc->sc_mac_csr)) < 0) { | 718 | if ((err = smsc_readreg(un, SMSC_MAC_CSR, &sc->sc_mac_csr)) < 0) { | |
719 | smsc_warn_printf(un, "failed to read MAC_CSR (err=%d)\n", err); | 719 | smsc_warn_printf(un, "failed to read MAC_CSR (err=%d)\n", err); | |
720 | goto init_failed; | 720 | goto init_failed; | |
721 | } | 721 | } | |
722 | 722 | |||
723 | /* disable pad stripping, collides with checksum offload */ | 723 | /* disable pad stripping, collides with checksum offload */ | |
724 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_PADSTR; | 724 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_PADSTR; | |
725 | 725 | |||
726 | /* Vlan */ | 726 | /* Vlan */ | |
727 | smsc_writereg(un, SMSC_VLAN1, (uint32_t)ETHERTYPE_VLAN); | 727 | smsc_writereg(un, SMSC_VLAN1, (uint32_t)ETHERTYPE_VLAN); | |
728 | 728 | |||
729 | /* | 729 | /* | |
730 | * Start TX | 730 | * Start TX | |
731 | */ | 731 | */ | |
732 | sc->sc_mac_csr |= SMSC_MAC_CSR_TXEN; | 732 | sc->sc_mac_csr |= SMSC_MAC_CSR_TXEN; | |
733 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 733 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
734 | smsc_writereg(un, SMSC_TX_CFG, SMSC_TX_CFG_ON); | 734 | smsc_writereg(un, SMSC_TX_CFG, SMSC_TX_CFG_ON); | |
735 | 735 | |||
736 | /* | 736 | /* | |
737 | * Start RX | 737 | * Start RX | |
738 | */ | 738 | */ | |
739 | sc->sc_mac_csr |= SMSC_MAC_CSR_RXEN; | 739 | sc->sc_mac_csr |= SMSC_MAC_CSR_RXEN; | |
740 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 740 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
741 | 741 | |||
742 | return 0; | 742 | return 0; | |
743 | 743 | |||
744 | init_failed: | 744 | init_failed: | |
745 | smsc_err_printf(un, "smsc_chip_init failed (err=%d)\n", err); | 745 | smsc_err_printf(un, "smsc_chip_init failed (err=%d)\n", err); | |
746 | return err; | 746 | return err; | |
747 | } | 747 | } | |
748 | 748 | |||
749 | static int | 749 | static int | |
750 | smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 750 | smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
751 | { | 751 | { | |
752 | struct usbnet * const un = ifp->if_softc; | 752 | struct usbnet * const un = ifp->if_softc; | |
753 | 753 | |||
754 | usbnet_lock_core(un); | 754 | usbnet_lock_core(un); | |
755 | usbnet_busy(un); | 755 | usbnet_busy(un); | |
756 | 756 | |||
757 | switch (cmd) { | 757 | switch (cmd) { | |
758 | case SIOCSIFCAP: | 758 | case SIOCSIFCAP: | |
759 | smsc_setoe_locked(un); | 759 | smsc_setoe_locked(un); | |
760 | break; | 760 | break; | |
761 | default: | 761 | default: | |
762 | break; | 762 | break; | |
763 | } | 763 | } | |
764 | 764 | |||
765 | usbnet_unbusy(un); | 765 | usbnet_unbusy(un); | |
766 | usbnet_unlock_core(un); | 766 | usbnet_unlock_core(un); | |
767 | 767 | |||
768 | return 0; | 768 | return 0; | |
769 | } | 769 | } | |
770 | 770 | |||
771 | static void | 771 | static void | |
772 | smsc_uno_mcast(struct ifnet *ifp) | 772 | smsc_uno_mcast(struct ifnet *ifp) | |
773 | { | 773 | { | |
774 | struct usbnet * const un = ifp->if_softc; | 774 | struct usbnet * const un = ifp->if_softc; | |
775 | 775 | |||
776 | usbnet_lock_core(un); | 776 | usbnet_lock_core(un); | |
777 | usbnet_busy(un); | |||
778 | 777 | |||
779 | smsc_setiff_locked(un); | 778 | smsc_setiff_locked(un); | |
780 | 779 | |||
781 | usbnet_unbusy(un); | |||
782 | usbnet_unlock_core(un); | 780 | usbnet_unlock_core(un); | |
783 | } | 781 | } | |
784 | 782 | |||
785 | static int | 783 | static int | |
786 | smsc_match(device_t parent, cfdata_t match, void *aux) | 784 | smsc_match(device_t parent, cfdata_t match, void *aux) | |
787 | { | 785 | { | |
788 | struct usb_attach_arg *uaa = aux; | 786 | struct usb_attach_arg *uaa = aux; | |
789 | 787 | |||
790 | return (usb_lookup(smsc_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL) ? | 788 | return (usb_lookup(smsc_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL) ? | |
791 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 789 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
792 | } | 790 | } | |
793 | 791 | |||
794 | static void | 792 | static void | |
795 | smsc_attach(device_t parent, device_t self, void *aux) | 793 | smsc_attach(device_t parent, device_t self, void *aux) | |
796 | { | 794 | { | |
797 | USBNET_MII_DECL_DEFAULT(unm); | 795 | USBNET_MII_DECL_DEFAULT(unm); | |
798 | struct smsc_softc * const sc = device_private(self); | 796 | struct smsc_softc * const sc = device_private(self); | |
799 | struct usbnet * const un = &sc->smsc_un; | 797 | struct usbnet * const un = &sc->smsc_un; | |
800 | struct usb_attach_arg *uaa = aux; | 798 | struct usb_attach_arg *uaa = aux; | |
801 | struct usbd_device *dev = uaa->uaa_device; | 799 | struct usbd_device *dev = uaa->uaa_device; | |
802 | usb_interface_descriptor_t *id; | 800 | usb_interface_descriptor_t *id; | |
803 | usb_endpoint_descriptor_t *ed; | 801 | usb_endpoint_descriptor_t *ed; | |
804 | char *devinfop; | 802 | char *devinfop; | |
805 | unsigned bufsz; | 803 | unsigned bufsz; | |
806 | int err, i; | 804 | int err, i; | |
807 | uint32_t mac_h, mac_l; | 805 | uint32_t mac_h, mac_l; | |
808 | 806 | |||
809 | KASSERT((void *)sc == un); | 807 | KASSERT((void *)sc == un); | |
810 | 808 | |||
811 | aprint_naive("\n"); | 809 | aprint_naive("\n"); | |
812 | aprint_normal("\n"); | 810 | aprint_normal("\n"); | |
813 | 811 | |||
814 | un->un_dev = self; | 812 | un->un_dev = self; | |
815 | un->un_udev = dev; | 813 | un->un_udev = dev; | |
816 | un->un_sc = sc; | 814 | un->un_sc = sc; | |
817 | un->un_ops = &smsc_ops; | 815 | un->un_ops = &smsc_ops; | |
818 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 816 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
819 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 817 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
820 | un->un_rx_list_cnt = SMSC_RX_LIST_CNT; | 818 | un->un_rx_list_cnt = SMSC_RX_LIST_CNT; | |
821 | un->un_tx_list_cnt = SMSC_TX_LIST_CNT; | 819 | un->un_tx_list_cnt = SMSC_TX_LIST_CNT; | |
822 | 820 | |||
823 | devinfop = usbd_devinfo_alloc(un->un_udev, 0); | 821 | devinfop = usbd_devinfo_alloc(un->un_udev, 0); | |
824 | aprint_normal_dev(self, "%s\n", devinfop); | 822 | aprint_normal_dev(self, "%s\n", devinfop); | |
825 | usbd_devinfo_free(devinfop); | 823 | usbd_devinfo_free(devinfop); | |
826 | 824 | |||
827 | err = usbd_set_config_no(dev, SMSC_CONFIG_INDEX, 1); | 825 | err = usbd_set_config_no(dev, SMSC_CONFIG_INDEX, 1); | |
828 | if (err) { | 826 | if (err) { | |
829 | aprint_error_dev(self, "failed to set configuration" | 827 | aprint_error_dev(self, "failed to set configuration" | |
830 | ", err=%s\n", usbd_errstr(err)); | 828 | ", err=%s\n", usbd_errstr(err)); | |
831 | return; | 829 | return; | |
832 | } | 830 | } | |
833 | 831 | |||
834 | /* Setup the endpoints for the SMSC LAN95xx device(s) */ | 832 | /* Setup the endpoints for the SMSC LAN95xx device(s) */ | |
835 | err = usbd_device2interface_handle(dev, SMSC_IFACE_IDX, &un->un_iface); | 833 | err = usbd_device2interface_handle(dev, SMSC_IFACE_IDX, &un->un_iface); | |
836 | if (err) { | 834 | if (err) { | |
837 | aprint_error_dev(self, "getting interface handle failed\n"); | 835 | aprint_error_dev(self, "getting interface handle failed\n"); | |
838 | return; | 836 | return; | |
839 | } | 837 | } | |
840 | 838 | |||
841 | id = usbd_get_interface_descriptor(un->un_iface); | 839 | id = usbd_get_interface_descriptor(un->un_iface); | |
842 | 840 | |||
843 | if (dev->ud_speed >= USB_SPEED_HIGH) { | 841 | if (dev->ud_speed >= USB_SPEED_HIGH) { | |
844 | bufsz = SMSC_MAX_BUFSZ; | 842 | bufsz = SMSC_MAX_BUFSZ; | |
845 | } else { | 843 | } else { | |
846 | bufsz = SMSC_MIN_BUFSZ; | 844 | bufsz = SMSC_MIN_BUFSZ; | |
847 | } | 845 | } | |
848 | un->un_rx_bufsz = bufsz; | 846 | un->un_rx_bufsz = bufsz; | |
849 | un->un_tx_bufsz = bufsz; | 847 | un->un_tx_bufsz = bufsz; | |
850 | 848 | |||
851 | /* Find endpoints. */ | 849 | /* Find endpoints. */ | |
852 | for (i = 0; i < id->bNumEndpoints; i++) { | 850 | for (i = 0; i < id->bNumEndpoints; i++) { | |
853 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 851 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
854 | if (!ed) { | 852 | if (!ed) { | |
855 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 853 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
856 | return; | 854 | return; | |
857 | } | 855 | } | |
858 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 856 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
859 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 857 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
860 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 858 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
861 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 859 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
862 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 860 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
863 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 861 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
864 | #if 0 /* not used yet */ | 862 | #if 0 /* not used yet */ | |
865 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 863 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
866 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 864 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
867 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 865 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
868 | #endif | 866 | #endif | |
869 | } | 867 | } | |
870 | } | 868 | } | |
871 | 869 | |||
872 | usbnet_attach(un, "smscdet"); | 870 | usbnet_attach(un, "smscdet"); | |
873 | 871 | |||
874 | #ifdef notyet | 872 | #ifdef notyet | |
875 | /* | 873 | /* | |
876 | * We can do TCPv4, and UDPv4 checksums in hardware. | 874 | * We can do TCPv4, and UDPv4 checksums in hardware. | |
877 | */ | 875 | */ | |
878 | struct ifnet *ifp = usbnet_ifp(un); | 876 | struct ifnet *ifp = usbnet_ifp(un); | |
879 | 877 | |||
880 | ifp->if_capabilities |= | 878 | ifp->if_capabilities |= | |
881 | /*IFCAP_CSUM_TCPv4_Tx |*/ IFCAP_CSUM_TCPv4_Rx | | 879 | /*IFCAP_CSUM_TCPv4_Tx |*/ IFCAP_CSUM_TCPv4_Rx | | |
882 | /*IFCAP_CSUM_UDPv4_Tx |*/ IFCAP_CSUM_UDPv4_Rx; | 880 | /*IFCAP_CSUM_UDPv4_Tx |*/ IFCAP_CSUM_UDPv4_Rx; | |
883 | #endif | 881 | #endif | |
884 | struct ethercom *ec = usbnet_ec(un); | 882 | struct ethercom *ec = usbnet_ec(un); | |
885 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | 883 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | |
886 | 884 | |||
887 | /* Setup some of the basics */ | 885 | /* Setup some of the basics */ | |
888 | un->un_phyno = 1; | 886 | un->un_phyno = 1; | |
889 | 887 | |||
890 | usbnet_lock_core(un); | 888 | usbnet_lock_core(un); | |
891 | usbnet_busy(un); | 889 | usbnet_busy(un); | |
892 | /* | 890 | /* | |
893 | * Attempt to get the mac address, if an EEPROM is not attached this | 891 | * Attempt to get the mac address, if an EEPROM is not attached this | |
894 | * will just return FF:FF:FF:FF:FF:FF, so in such cases we invent a MAC | 892 | * will just return FF:FF:FF:FF:FF:FF, so in such cases we invent a MAC | |
895 | * address based on urandom. | 893 | * address based on urandom. | |
896 | */ | 894 | */ | |
897 | memset(un->un_eaddr, 0xff, ETHER_ADDR_LEN); | 895 | memset(un->un_eaddr, 0xff, ETHER_ADDR_LEN); | |
898 | 896 | |||
899 | prop_dictionary_t dict = device_properties(self); | 897 | prop_dictionary_t dict = device_properties(self); | |
900 | prop_data_t eaprop = prop_dictionary_get(dict, "mac-address"); | 898 | prop_data_t eaprop = prop_dictionary_get(dict, "mac-address"); | |
901 | 899 | |||
902 | if (eaprop != NULL) { | 900 | if (eaprop != NULL) { | |
903 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | 901 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | |
904 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | 902 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | |
905 | memcpy(un->un_eaddr, prop_data_value(eaprop), | 903 | memcpy(un->un_eaddr, prop_data_value(eaprop), | |
906 | ETHER_ADDR_LEN); | 904 | ETHER_ADDR_LEN); | |
907 | } else { | 905 | } else { | |
908 | /* Check if there is already a MAC address in the register */ | 906 | /* Check if there is already a MAC address in the register */ | |
909 | if ((smsc_readreg(un, SMSC_MAC_ADDRL, &mac_l) == 0) && | 907 | if ((smsc_readreg(un, SMSC_MAC_ADDRL, &mac_l) == 0) && | |
910 | (smsc_readreg(un, SMSC_MAC_ADDRH, &mac_h) == 0)) { | 908 | (smsc_readreg(un, SMSC_MAC_ADDRH, &mac_h) == 0)) { | |
911 | un->un_eaddr[5] = (uint8_t)((mac_h >> 8) & 0xff); | 909 | un->un_eaddr[5] = (uint8_t)((mac_h >> 8) & 0xff); | |
912 | un->un_eaddr[4] = (uint8_t)((mac_h) & 0xff); | 910 | un->un_eaddr[4] = (uint8_t)((mac_h) & 0xff); | |
913 | un->un_eaddr[3] = (uint8_t)((mac_l >> 24) & 0xff); | 911 | un->un_eaddr[3] = (uint8_t)((mac_l >> 24) & 0xff); | |
914 | un->un_eaddr[2] = (uint8_t)((mac_l >> 16) & 0xff); | 912 | un->un_eaddr[2] = (uint8_t)((mac_l >> 16) & 0xff); | |
915 | un->un_eaddr[1] = (uint8_t)((mac_l >> 8) & 0xff); | 913 | un->un_eaddr[1] = (uint8_t)((mac_l >> 8) & 0xff); | |
916 | un->un_eaddr[0] = (uint8_t)((mac_l) & 0xff); | 914 | un->un_eaddr[0] = (uint8_t)((mac_l) & 0xff); | |
917 | } | 915 | } | |
918 | } | 916 | } | |
919 | usbnet_unbusy(un); | 917 | usbnet_unbusy(un); | |
920 | usbnet_unlock_core(un); | 918 | usbnet_unlock_core(un); | |
921 | 919 | |||
922 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 920 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
923 | 0, &unm); | 921 | 0, &unm); | |
924 | } | 922 | } | |
925 | 923 | |||
926 | static void | 924 | static void | |
927 | smsc_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 925 | smsc_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
928 | { | 926 | { | |
929 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | 927 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | |
930 | struct smsc_softc * const sc = usbnet_softc(un); | 928 | struct smsc_softc * const sc = usbnet_softc(un); | |
931 | struct ifnet *ifp = usbnet_ifp(un); | 929 | struct ifnet *ifp = usbnet_ifp(un); | |
932 | uint8_t *buf = c->unc_buf; | 930 | uint8_t *buf = c->unc_buf; | |
933 | int count; | 931 | int count; | |
934 | 932 | |||
935 | count = 0; | 933 | count = 0; | |
936 | DPRINTF("total_len %jd/%#jx", total_len, total_len, 0, 0); | 934 | DPRINTF("total_len %jd/%#jx", total_len, total_len, 0, 0); | |
937 | while (total_len != 0) { | 935 | while (total_len != 0) { | |
938 | uint32_t rxhdr; | 936 | uint32_t rxhdr; | |
939 | if (total_len < sizeof(rxhdr)) { | 937 | if (total_len < sizeof(rxhdr)) { | |
940 | DPRINTF("total_len %jd < sizeof(rxhdr) %jd", | 938 | DPRINTF("total_len %jd < sizeof(rxhdr) %jd", | |
941 | total_len, sizeof(rxhdr), 0, 0); | 939 | total_len, sizeof(rxhdr), 0, 0); | |
942 | if_statinc(ifp, if_ierrors); | 940 | if_statinc(ifp, if_ierrors); | |
943 | return; | 941 | return; | |
944 | } | 942 | } | |
945 | 943 | |||
946 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | 944 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | |
947 | rxhdr = le32toh(rxhdr); | 945 | rxhdr = le32toh(rxhdr); | |
948 | buf += sizeof(rxhdr); | 946 | buf += sizeof(rxhdr); | |
949 | total_len -= sizeof(rxhdr); | 947 | total_len -= sizeof(rxhdr); | |
950 | 948 | |||
951 | if (rxhdr & SMSC_RX_STAT_COLLISION) | 949 | if (rxhdr & SMSC_RX_STAT_COLLISION) | |
952 | if_statinc(ifp, if_collisions); | 950 | if_statinc(ifp, if_collisions); | |
953 | 951 | |||
954 | if (rxhdr & (SMSC_RX_STAT_ERROR | 952 | if (rxhdr & (SMSC_RX_STAT_ERROR | |
955 | | SMSC_RX_STAT_LENGTH_ERROR | 953 | | SMSC_RX_STAT_LENGTH_ERROR | |
956 | | SMSC_RX_STAT_MII_ERROR)) { | 954 | | SMSC_RX_STAT_MII_ERROR)) { | |
957 | DPRINTF("rx error (hdr 0x%08jx)", rxhdr, 0, 0, 0); | 955 | DPRINTF("rx error (hdr 0x%08jx)", rxhdr, 0, 0, 0); | |
958 | if_statinc(ifp, if_ierrors); | 956 | if_statinc(ifp, if_ierrors); | |
959 | return; | 957 | return; | |
960 | } | 958 | } | |
961 | 959 | |||
962 | uint16_t pktlen = (uint16_t)SMSC_RX_STAT_FRM_LENGTH(rxhdr); | 960 | uint16_t pktlen = (uint16_t)SMSC_RX_STAT_FRM_LENGTH(rxhdr); | |
963 | DPRINTF("total_len %jd pktlen %jd rxhdr 0x%08jx", total_len, | 961 | DPRINTF("total_len %jd pktlen %jd rxhdr 0x%08jx", total_len, | |
964 | pktlen, rxhdr, 0); | 962 | pktlen, rxhdr, 0); | |
965 | 963 | |||
966 | if (pktlen < ETHER_HDR_LEN) { | 964 | if (pktlen < ETHER_HDR_LEN) { | |
967 | DPRINTF("pktlen %jd < ETHER_HDR_LEN %jd", pktlen, | 965 | DPRINTF("pktlen %jd < ETHER_HDR_LEN %jd", pktlen, | |
968 | ETHER_HDR_LEN, 0, 0); | 966 | ETHER_HDR_LEN, 0, 0); | |
969 | if_statinc(ifp, if_ierrors); | 967 | if_statinc(ifp, if_ierrors); | |
970 | return; | 968 | return; | |
971 | } | 969 | } | |
972 | 970 | |||
973 | pktlen += ETHER_ALIGN; | 971 | pktlen += ETHER_ALIGN; | |
974 | 972 | |||
975 | if (pktlen > MCLBYTES) { | 973 | if (pktlen > MCLBYTES) { | |
976 | DPRINTF("pktlen %jd > MCLBYTES %jd", pktlen, MCLBYTES, 0, | 974 | DPRINTF("pktlen %jd > MCLBYTES %jd", pktlen, MCLBYTES, 0, | |
977 | 0); | 975 | 0); | |
978 | if_statinc(ifp, if_ierrors); | 976 | if_statinc(ifp, if_ierrors); | |
979 | return; | 977 | return; | |
980 | } | 978 | } | |
981 | 979 | |||
982 | if (pktlen > total_len) { | 980 | if (pktlen > total_len) { | |
983 | DPRINTF("pktlen %jd > total_len %jd", pktlen, total_len, | 981 | DPRINTF("pktlen %jd > total_len %jd", pktlen, total_len, | |
984 | 0, 0); | 982 | 0, 0); | |
985 | if_statinc(ifp, if_ierrors); | 983 | if_statinc(ifp, if_ierrors); | |
986 | return; | 984 | return; | |
987 | } | 985 | } | |
988 | 986 | |||
989 | uint8_t *pktbuf = buf + ETHER_ALIGN; | 987 | uint8_t *pktbuf = buf + ETHER_ALIGN; | |
990 | size_t buflen = pktlen - ETHER_ALIGN; | 988 | size_t buflen = pktlen - ETHER_ALIGN; | |
991 | int mbuf_flags = M_HASFCS; | 989 | int mbuf_flags = M_HASFCS; | |
992 | int csum_flags = 0; | 990 | int csum_flags = 0; | |
993 | uint16_t csum_data = 0; | 991 | uint16_t csum_data = 0; | |
994 | 992 | |||
995 | KASSERT(pktlen < MCLBYTES); | 993 | KASSERT(pktlen < MCLBYTES); | |
996 | 994 | |||
997 | /* Check if RX TCP/UDP checksumming is being offloaded */ | 995 | /* Check if RX TCP/UDP checksumming is being offloaded */ | |
998 | if (sc->sc_coe_ctrl & SMSC_COE_CTRL_RX_EN) { | 996 | if (sc->sc_coe_ctrl & SMSC_COE_CTRL_RX_EN) { | |
999 | DPRINTF("RX checksum offload checking", 0, 0, 0, 0); | 997 | DPRINTF("RX checksum offload checking", 0, 0, 0, 0); | |
1000 | struct ether_header *eh = (struct ether_header *)pktbuf; | 998 | struct ether_header *eh = (struct ether_header *)pktbuf; | |
1001 | const size_t cssz = sizeof(csum_data); | 999 | const size_t cssz = sizeof(csum_data); | |
1002 | 1000 | |||
1003 | /* Remove the extra 2 bytes of the csum */ | 1001 | /* Remove the extra 2 bytes of the csum */ | |
1004 | buflen -= cssz; | 1002 | buflen -= cssz; | |
1005 | 1003 | |||
1006 | /* | 1004 | /* | |
1007 | * The checksum appears to be simplistically calculated | 1005 | * The checksum appears to be simplistically calculated | |
1008 | * over the udp/tcp header and data up to the end of the | 1006 | * over the udp/tcp header and data up to the end of the | |
1009 | * eth frame. Which means if the eth frame is padded | 1007 | * eth frame. Which means if the eth frame is padded | |
1010 | * the csum calculation is incorrectly performed over | 1008 | * the csum calculation is incorrectly performed over | |
1011 | * the padding bytes as well. Therefore to be safe we | 1009 | * the padding bytes as well. Therefore to be safe we | |
1012 | * ignore the H/W csum on frames less than or equal to | 1010 | * ignore the H/W csum on frames less than or equal to | |
1013 | * 64 bytes. | 1011 | * 64 bytes. | |
1014 | * | 1012 | * | |
1015 | * Ignore H/W csum for non-IPv4 packets. | 1013 | * Ignore H/W csum for non-IPv4 packets. | |
1016 | */ | 1014 | */ | |
1017 | DPRINTF("Ethertype %02jx pktlen %02jx", | 1015 | DPRINTF("Ethertype %02jx pktlen %02jx", | |
1018 | be16toh(eh->ether_type), pktlen, 0, 0); | 1016 | be16toh(eh->ether_type), pktlen, 0, 0); | |
1019 | if (be16toh(eh->ether_type) == ETHERTYPE_IP && | 1017 | if (be16toh(eh->ether_type) == ETHERTYPE_IP && | |
1020 | pktlen > ETHER_MIN_LEN) { | 1018 | pktlen > ETHER_MIN_LEN) { | |
1021 | 1019 | |||
1022 | csum_flags |= | 1020 | csum_flags |= | |
1023 | (M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_DATA); | 1021 | (M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_DATA); | |
1024 | 1022 | |||
1025 | /* | 1023 | /* | |
1026 | * Copy the TCP/UDP checksum from the last 2 | 1024 | * Copy the TCP/UDP checksum from the last 2 | |
1027 | * bytes of the transfer and put in the | 1025 | * bytes of the transfer and put in the | |
1028 | * csum_data field. | 1026 | * csum_data field. | |
1029 | */ | 1027 | */ | |
1030 | memcpy(&csum_data, buf + pktlen - cssz, cssz); | 1028 | memcpy(&csum_data, buf + pktlen - cssz, cssz); | |
1031 | 1029 | |||
1032 | /* | 1030 | /* | |
1033 | * The data is copied in network order, but the | 1031 | * The data is copied in network order, but the | |
1034 | * csum algorithm in the kernel expects it to be | 1032 | * csum algorithm in the kernel expects it to be | |
1035 | * in host network order. | 1033 | * in host network order. | |
1036 | */ | 1034 | */ | |
1037 | csum_data = ntohs(csum_data); | 1035 | csum_data = ntohs(csum_data); | |
1038 | DPRINTF("RX checksum offloaded (0x%04jx)", | 1036 | DPRINTF("RX checksum offloaded (0x%04jx)", | |
1039 | csum_data, 0, 0, 0); | 1037 | csum_data, 0, 0, 0); | |
1040 | } | 1038 | } | |
1041 | } | 1039 | } | |
1042 | 1040 | |||
1043 | /* round up to next longword */ | 1041 | /* round up to next longword */ | |
1044 | pktlen = (pktlen + 3) & ~0x3; | 1042 | pktlen = (pktlen + 3) & ~0x3; | |
1045 | 1043 | |||
1046 | /* total_len does not include the padding */ | 1044 | /* total_len does not include the padding */ | |
1047 | if (pktlen > total_len) | 1045 | if (pktlen > total_len) | |
1048 | pktlen = total_len; | 1046 | pktlen = total_len; | |
1049 | 1047 | |||
1050 | buf += pktlen; | 1048 | buf += pktlen; | |
1051 | total_len -= pktlen; | 1049 | total_len -= pktlen; | |
1052 | 1050 | |||
1053 | /* push the packet up */ | 1051 | /* push the packet up */ | |
1054 | usbnet_enqueue(un, pktbuf, buflen, csum_flags, csum_data, | 1052 | usbnet_enqueue(un, pktbuf, buflen, csum_flags, csum_data, | |
1055 | mbuf_flags); | 1053 | mbuf_flags); | |
1056 | 1054 | |||
1057 | count++; | 1055 | count++; | |
1058 | } | 1056 | } | |
1059 | 1057 | |||
1060 | if (count != 0) | 1058 | if (count != 0) | |
1061 | rnd_add_uint32(usbnet_rndsrc(un), count); | 1059 | rnd_add_uint32(usbnet_rndsrc(un), count); | |
1062 | } | 1060 | } | |
1063 | 1061 | |||
1064 | static unsigned | 1062 | static unsigned | |
1065 | smsc_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 1063 | smsc_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
1066 | { | 1064 | { | |
1067 | uint32_t txhdr; | 1065 | uint32_t txhdr; | |
1068 | uint32_t frm_len = 0; | 1066 | uint32_t frm_len = 0; | |
1069 | 1067 | |||
1070 | const size_t hdrsz = sizeof(txhdr) * 2; | 1068 | const size_t hdrsz = sizeof(txhdr) * 2; | |
1071 | 1069 | |||
1072 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - hdrsz) | 1070 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - hdrsz) | |
1073 | return 0; | 1071 | return 0; | |
1074 | 1072 | |||
1075 | /* | 1073 | /* | |
1076 | * Each frame is prefixed with two 32-bit values describing the | 1074 | * Each frame is prefixed with two 32-bit values describing the | |
1077 | * length of the packet and buffer. | 1075 | * length of the packet and buffer. | |
1078 | */ | 1076 | */ | |
1079 | txhdr = SMSC_TX_CTRL_0_BUF_SIZE(m->m_pkthdr.len) | | 1077 | txhdr = SMSC_TX_CTRL_0_BUF_SIZE(m->m_pkthdr.len) | | |
1080 | SMSC_TX_CTRL_0_FIRST_SEG | SMSC_TX_CTRL_0_LAST_SEG; | 1078 | SMSC_TX_CTRL_0_FIRST_SEG | SMSC_TX_CTRL_0_LAST_SEG; | |
1081 | txhdr = htole32(txhdr); | 1079 | txhdr = htole32(txhdr); | |
1082 | memcpy(c->unc_buf, &txhdr, sizeof(txhdr)); | 1080 | memcpy(c->unc_buf, &txhdr, sizeof(txhdr)); | |
1083 | 1081 | |||
1084 | txhdr = SMSC_TX_CTRL_1_PKT_LENGTH(m->m_pkthdr.len); | 1082 | txhdr = SMSC_TX_CTRL_1_PKT_LENGTH(m->m_pkthdr.len); | |
1085 | txhdr = htole32(txhdr); | 1083 | txhdr = htole32(txhdr); | |
1086 | memcpy(c->unc_buf + sizeof(txhdr), &txhdr, sizeof(txhdr)); | 1084 | memcpy(c->unc_buf + sizeof(txhdr), &txhdr, sizeof(txhdr)); | |
1087 | 1085 | |||
1088 | frm_len += hdrsz; | 1086 | frm_len += hdrsz; | |
1089 | 1087 | |||
1090 | /* Next copy in the actual packet */ | 1088 | /* Next copy in the actual packet */ | |
1091 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + frm_len); | 1089 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + frm_len); | |
1092 | frm_len += m->m_pkthdr.len; | 1090 | frm_len += m->m_pkthdr.len; | |
1093 | 1091 | |||
1094 | return frm_len; | 1092 | return frm_len; | |
1095 | } | 1093 | } | |
1096 | 1094 | |||
1097 | #ifdef _MODULE | 1095 | #ifdef _MODULE | |
1098 | #include "ioconf.c" | 1096 | #include "ioconf.c" | |
1099 | #endif | 1097 | #endif | |
1100 | 1098 | |||
1101 | USBNET_MODULE(smsc) | 1099 | USBNET_MODULE(smsc) |
--- src/sys/dev/usb/if_udav.c 2022/03/03 05:51:17 1.82
+++ src/sys/dev/usb/if_udav.c 2022/03/03 05:51:27 1.83
@@ -1,853 +1,851 @@ | @@ -1,853 +1,851 @@ | |||
1 | /* $NetBSD: if_udav.c,v 1.82 2022/03/03 05:51:17 riastradh Exp $ */ | 1 | /* $NetBSD: if_udav.c,v 1.83 2022/03/03 05:51:27 riastradh Exp $ */ | |
2 | /* $nabe: if_udav.c,v 1.3 2003/08/21 16:57:19 nabe Exp $ */ | 2 | /* $nabe: if_udav.c,v 1.3 2003/08/21 16:57:19 nabe Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2003 | 5 | * Copyright (c) 2003 | |
6 | * Shingo WATANABE <nabe@nabechan.org>. All rights reserved. | 6 | * Shingo WATANABE <nabe@nabechan.org>. All rights reserved. | |
7 | * | 7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | 9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | 10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | 11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | 12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | 14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | 15 | * documentation and/or other materials provided with the distribution. | |
16 | * 3. Neither the name of the author nor the names of any co-contributors | 16 | * 3. Neither the name of the author nor the names of any co-contributors | |
17 | * may be used to endorse or promote products derived from this software | 17 | * may be used to endorse or promote products derived from this software | |
18 | * without specific prior written permission. | 18 | * without specific prior written permission. | |
19 | * | 19 | * | |
20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
30 | * SUCH DAMAGE. | 30 | * SUCH DAMAGE. | |
31 | * | 31 | * | |
32 | */ | 32 | */ | |
33 | 33 | |||
34 | /* | 34 | /* | |
35 | * DM9601(DAVICOM USB to Ethernet MAC Controller with Integrated 10/100 PHY) | 35 | * DM9601(DAVICOM USB to Ethernet MAC Controller with Integrated 10/100 PHY) | |
36 | * The spec can be found at the following url. | 36 | * The spec can be found at the following url. | |
37 | * http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-F01-062202s.pdf | 37 | * http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-F01-062202s.pdf | |
38 | */ | 38 | */ | |
39 | 39 | |||
40 | /* | 40 | /* | |
41 | * TODO: | 41 | * TODO: | |
42 | * Interrupt Endpoint support | 42 | * Interrupt Endpoint support | |
43 | * External PHYs | 43 | * External PHYs | |
44 | * powerhook() support? | 44 | * powerhook() support? | |
45 | */ | 45 | */ | |
46 | 46 | |||
47 | #include <sys/cdefs.h> | 47 | #include <sys/cdefs.h> | |
48 | __KERNEL_RCSID(0, "$NetBSD: if_udav.c,v 1.82 2022/03/03 05:51:17 riastradh Exp $"); | 48 | __KERNEL_RCSID(0, "$NetBSD: if_udav.c,v 1.83 2022/03/03 05:51:27 riastradh Exp $"); | |
49 | 49 | |||
50 | #ifdef _KERNEL_OPT | 50 | #ifdef _KERNEL_OPT | |
51 | #include "opt_usb.h" | 51 | #include "opt_usb.h" | |
52 | #endif | 52 | #endif | |
53 | 53 | |||
54 | #include <sys/param.h> | 54 | #include <sys/param.h> | |
55 | 55 | |||
56 | #include <dev/usb/usbnet.h> | 56 | #include <dev/usb/usbnet.h> | |
57 | #include <dev/usb/if_udavreg.h> | 57 | #include <dev/usb/if_udavreg.h> | |
58 | 58 | |||
59 | /* Function declarations */ | 59 | /* Function declarations */ | |
60 | static int udav_match(device_t, cfdata_t, void *); | 60 | static int udav_match(device_t, cfdata_t, void *); | |
61 | static void udav_attach(device_t, device_t, void *); | 61 | static void udav_attach(device_t, device_t, void *); | |
62 | 62 | |||
63 | CFATTACH_DECL_NEW(udav, sizeof(struct usbnet), udav_match, udav_attach, | 63 | CFATTACH_DECL_NEW(udav, sizeof(struct usbnet), udav_match, udav_attach, | |
64 | usbnet_detach, usbnet_activate); | 64 | usbnet_detach, usbnet_activate); | |
65 | 65 | |||
66 | static void udav_chip_init(struct usbnet *); | 66 | static void udav_chip_init(struct usbnet *); | |
67 | 67 | |||
68 | static unsigned udav_uno_tx_prepare(struct usbnet *, struct mbuf *, | 68 | static unsigned udav_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
69 | struct usbnet_chain *); | 69 | struct usbnet_chain *); | |
70 | static void udav_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 70 | static void udav_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
71 | static void udav_uno_stop(struct ifnet *, int); | 71 | static void udav_uno_stop(struct ifnet *, int); | |
72 | static void udav_uno_mcast(struct ifnet *); | 72 | static void udav_uno_mcast(struct ifnet *); | |
73 | static int udav_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 73 | static int udav_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
74 | static int udav_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 74 | static int udav_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
75 | static void udav_uno_mii_statchg(struct ifnet *); | 75 | static void udav_uno_mii_statchg(struct ifnet *); | |
76 | static int udav_uno_init(struct ifnet *); | 76 | static int udav_uno_init(struct ifnet *); | |
77 | static void udav_setiff_locked(struct usbnet *); | 77 | static void udav_setiff_locked(struct usbnet *); | |
78 | static void udav_reset(struct usbnet *); | 78 | static void udav_reset(struct usbnet *); | |
79 | 79 | |||
80 | static int udav_csr_read(struct usbnet *, int, void *, int); | 80 | static int udav_csr_read(struct usbnet *, int, void *, int); | |
81 | static int udav_csr_write(struct usbnet *, int, void *, int); | 81 | static int udav_csr_write(struct usbnet *, int, void *, int); | |
82 | static int udav_csr_read1(struct usbnet *, int); | 82 | static int udav_csr_read1(struct usbnet *, int); | |
83 | static int udav_csr_write1(struct usbnet *, int, unsigned char); | 83 | static int udav_csr_write1(struct usbnet *, int, unsigned char); | |
84 | 84 | |||
85 | #if 0 | 85 | #if 0 | |
86 | static int udav_mem_read(struct usbnet *, int, void *, int); | 86 | static int udav_mem_read(struct usbnet *, int, void *, int); | |
87 | static int udav_mem_write(struct usbnet *, int, void *, int); | 87 | static int udav_mem_write(struct usbnet *, int, void *, int); | |
88 | static int udav_mem_write1(struct usbnet *, int, unsigned char); | 88 | static int udav_mem_write1(struct usbnet *, int, unsigned char); | |
89 | #endif | 89 | #endif | |
90 | 90 | |||
91 | /* Macros */ | 91 | /* Macros */ | |
92 | #ifdef UDAV_DEBUG | 92 | #ifdef UDAV_DEBUG | |
93 | #define DPRINTF(x) if (udavdebug) printf x | 93 | #define DPRINTF(x) if (udavdebug) printf x | |
94 | #define DPRINTFN(n, x) if (udavdebug >= (n)) printf x | 94 | #define DPRINTFN(n, x) if (udavdebug >= (n)) printf x | |
95 | int udavdebug = 0; | 95 | int udavdebug = 0; | |
96 | #else | 96 | #else | |
97 | #define DPRINTF(x) | 97 | #define DPRINTF(x) | |
98 | #define DPRINTFN(n, x) | 98 | #define DPRINTFN(n, x) | |
99 | #endif | 99 | #endif | |
100 | 100 | |||
101 | #define UDAV_SETBIT(un, reg, x) \ | 101 | #define UDAV_SETBIT(un, reg, x) \ | |
102 | udav_csr_write1(un, reg, udav_csr_read1(un, reg) | (x)) | 102 | udav_csr_write1(un, reg, udav_csr_read1(un, reg) | (x)) | |
103 | 103 | |||
104 | #define UDAV_CLRBIT(un, reg, x) \ | 104 | #define UDAV_CLRBIT(un, reg, x) \ | |
105 | udav_csr_write1(un, reg, udav_csr_read1(un, reg) & ~(x)) | 105 | udav_csr_write1(un, reg, udav_csr_read1(un, reg) & ~(x)) | |
106 | 106 | |||
107 | static const struct udav_type { | 107 | static const struct udav_type { | |
108 | struct usb_devno udav_dev; | 108 | struct usb_devno udav_dev; | |
109 | uint16_t udav_flags; | 109 | uint16_t udav_flags; | |
110 | #define UDAV_EXT_PHY 0x0001 | 110 | #define UDAV_EXT_PHY 0x0001 | |
111 | #define UDAV_NO_PHY 0x0002 | 111 | #define UDAV_NO_PHY 0x0002 | |
112 | } udav_devs [] = { | 112 | } udav_devs [] = { | |
113 | /* Corega USB-TXC */ | 113 | /* Corega USB-TXC */ | |
114 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC }, 0}, | 114 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC }, 0}, | |
115 | /* ShanTou ST268 USB NIC */ | 115 | /* ShanTou ST268 USB NIC */ | |
116 | {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268_USB_NIC }, 0}, | 116 | {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268_USB_NIC }, 0}, | |
117 | /* ShanTou ADM8515 */ | 117 | /* ShanTou ADM8515 */ | |
118 | {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ADM8515 }, 0}, | 118 | {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ADM8515 }, 0}, | |
119 | /* SUNRISING SR9600 */ | 119 | /* SUNRISING SR9600 */ | |
120 | {{ USB_VENDOR_SUNRISING, USB_PRODUCT_SUNRISING_SR9600 }, 0 }, | 120 | {{ USB_VENDOR_SUNRISING, USB_PRODUCT_SUNRISING_SR9600 }, 0 }, | |
121 | /* SUNRISING QF9700 */ | 121 | /* SUNRISING QF9700 */ | |
122 | {{ USB_VENDOR_SUNRISING, USB_PRODUCT_SUNRISING_QF9700 }, UDAV_NO_PHY }, | 122 | {{ USB_VENDOR_SUNRISING, USB_PRODUCT_SUNRISING_QF9700 }, UDAV_NO_PHY }, | |
123 | /* QUAN DM9601 */ | 123 | /* QUAN DM9601 */ | |
124 | {{USB_VENDOR_QUAN, USB_PRODUCT_QUAN_DM9601 }, 0}, | 124 | {{USB_VENDOR_QUAN, USB_PRODUCT_QUAN_DM9601 }, 0}, | |
125 | #if 0 | 125 | #if 0 | |
126 | /* DAVICOM DM9601 Generic? */ | 126 | /* DAVICOM DM9601 Generic? */ | |
127 | /* XXX: The following ids was obtained from the data sheet. */ | 127 | /* XXX: The following ids was obtained from the data sheet. */ | |
128 | {{ 0x0a46, 0x9601 }, 0}, | 128 | {{ 0x0a46, 0x9601 }, 0}, | |
129 | #endif | 129 | #endif | |
130 | }; | 130 | }; | |
131 | #define udav_lookup(v, p) ((const struct udav_type *)usb_lookup(udav_devs, v, p)) | 131 | #define udav_lookup(v, p) ((const struct udav_type *)usb_lookup(udav_devs, v, p)) | |
132 | 132 | |||
133 | static const struct usbnet_ops udav_ops = { | 133 | static const struct usbnet_ops udav_ops = { | |
134 | .uno_stop = udav_uno_stop, | 134 | .uno_stop = udav_uno_stop, | |
135 | .uno_mcast = udav_uno_mcast, | 135 | .uno_mcast = udav_uno_mcast, | |
136 | .uno_read_reg = udav_uno_mii_read_reg, | 136 | .uno_read_reg = udav_uno_mii_read_reg, | |
137 | .uno_write_reg = udav_uno_mii_write_reg, | 137 | .uno_write_reg = udav_uno_mii_write_reg, | |
138 | .uno_statchg = udav_uno_mii_statchg, | 138 | .uno_statchg = udav_uno_mii_statchg, | |
139 | .uno_tx_prepare = udav_uno_tx_prepare, | 139 | .uno_tx_prepare = udav_uno_tx_prepare, | |
140 | .uno_rx_loop = udav_uno_rx_loop, | 140 | .uno_rx_loop = udav_uno_rx_loop, | |
141 | .uno_init = udav_uno_init, | 141 | .uno_init = udav_uno_init, | |
142 | }; | 142 | }; | |
143 | 143 | |||
144 | /* Probe */ | 144 | /* Probe */ | |
145 | static int | 145 | static int | |
146 | udav_match(device_t parent, cfdata_t match, void *aux) | 146 | udav_match(device_t parent, cfdata_t match, void *aux) | |
147 | { | 147 | { | |
148 | struct usb_attach_arg *uaa = aux; | 148 | struct usb_attach_arg *uaa = aux; | |
149 | 149 | |||
150 | return udav_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 150 | return udav_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
151 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 151 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
152 | } | 152 | } | |
153 | 153 | |||
154 | /* Attach */ | 154 | /* Attach */ | |
155 | static void | 155 | static void | |
156 | udav_attach(device_t parent, device_t self, void *aux) | 156 | udav_attach(device_t parent, device_t self, void *aux) | |
157 | { | 157 | { | |
158 | USBNET_MII_DECL_DEFAULT(unm); | 158 | USBNET_MII_DECL_DEFAULT(unm); | |
159 | struct usbnet_mii *unmp; | 159 | struct usbnet_mii *unmp; | |
160 | struct usbnet * const un = device_private(self); | 160 | struct usbnet * const un = device_private(self); | |
161 | struct usb_attach_arg *uaa = aux; | 161 | struct usb_attach_arg *uaa = aux; | |
162 | struct usbd_device *dev = uaa->uaa_device; | 162 | struct usbd_device *dev = uaa->uaa_device; | |
163 | struct usbd_interface *iface; | 163 | struct usbd_interface *iface; | |
164 | usbd_status err; | 164 | usbd_status err; | |
165 | usb_interface_descriptor_t *id; | 165 | usb_interface_descriptor_t *id; | |
166 | usb_endpoint_descriptor_t *ed; | 166 | usb_endpoint_descriptor_t *ed; | |
167 | char *devinfop; | 167 | char *devinfop; | |
168 | int i; | 168 | int i; | |
169 | 169 | |||
170 | aprint_naive("\n"); | 170 | aprint_naive("\n"); | |
171 | aprint_normal("\n"); | 171 | aprint_normal("\n"); | |
172 | devinfop = usbd_devinfo_alloc(dev, 0); | 172 | devinfop = usbd_devinfo_alloc(dev, 0); | |
173 | aprint_normal_dev(self, "%s\n", devinfop); | 173 | aprint_normal_dev(self, "%s\n", devinfop); | |
174 | usbd_devinfo_free(devinfop); | 174 | usbd_devinfo_free(devinfop); | |
175 | 175 | |||
176 | un->un_dev = self; | 176 | un->un_dev = self; | |
177 | un->un_udev = dev; | 177 | un->un_udev = dev; | |
178 | un->un_sc = un; | 178 | un->un_sc = un; | |
179 | un->un_ops = &udav_ops; | 179 | un->un_ops = &udav_ops; | |
180 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 180 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
181 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 181 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
182 | un->un_rx_list_cnt = UDAV_RX_LIST_CNT; | 182 | un->un_rx_list_cnt = UDAV_RX_LIST_CNT; | |
183 | un->un_tx_list_cnt = UDAV_TX_LIST_CNT; | 183 | un->un_tx_list_cnt = UDAV_TX_LIST_CNT; | |
184 | un->un_rx_bufsz = UDAV_BUFSZ; | 184 | un->un_rx_bufsz = UDAV_BUFSZ; | |
185 | un->un_tx_bufsz = UDAV_BUFSZ; | 185 | un->un_tx_bufsz = UDAV_BUFSZ; | |
186 | 186 | |||
187 | /* Move the device into the configured state. */ | 187 | /* Move the device into the configured state. */ | |
188 | err = usbd_set_config_no(dev, UDAV_CONFIG_NO, 1); /* idx 0 */ | 188 | err = usbd_set_config_no(dev, UDAV_CONFIG_NO, 1); /* idx 0 */ | |
189 | if (err) { | 189 | if (err) { | |
190 | aprint_error_dev(self, "failed to set configuration" | 190 | aprint_error_dev(self, "failed to set configuration" | |
191 | ", err=%s\n", usbd_errstr(err)); | 191 | ", err=%s\n", usbd_errstr(err)); | |
192 | return; | 192 | return; | |
193 | } | 193 | } | |
194 | 194 | |||
195 | /* get control interface */ | 195 | /* get control interface */ | |
196 | err = usbd_device2interface_handle(dev, UDAV_IFACE_INDEX, &iface); | 196 | err = usbd_device2interface_handle(dev, UDAV_IFACE_INDEX, &iface); | |
197 | if (err) { | 197 | if (err) { | |
198 | aprint_error_dev(self, "failed to get interface, err=%s\n", | 198 | aprint_error_dev(self, "failed to get interface, err=%s\n", | |
199 | usbd_errstr(err)); | 199 | usbd_errstr(err)); | |
200 | return; | 200 | return; | |
201 | } | 201 | } | |
202 | 202 | |||
203 | un->un_iface = iface; | 203 | un->un_iface = iface; | |
204 | un->un_flags = udav_lookup(uaa->uaa_vendor, | 204 | un->un_flags = udav_lookup(uaa->uaa_vendor, | |
205 | uaa->uaa_product)->udav_flags; | 205 | uaa->uaa_product)->udav_flags; | |
206 | 206 | |||
207 | /* get interface descriptor */ | 207 | /* get interface descriptor */ | |
208 | id = usbd_get_interface_descriptor(un->un_iface); | 208 | id = usbd_get_interface_descriptor(un->un_iface); | |
209 | 209 | |||
210 | /* find endpoints */ | 210 | /* find endpoints */ | |
211 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = | 211 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = | |
212 | un->un_ed[USBNET_ENDPT_INTR] = -1; | 212 | un->un_ed[USBNET_ENDPT_INTR] = -1; | |
213 | for (i = 0; i < id->bNumEndpoints; i++) { | 213 | for (i = 0; i < id->bNumEndpoints; i++) { | |
214 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 214 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
215 | if (ed == NULL) { | 215 | if (ed == NULL) { | |
216 | aprint_error_dev(self, "couldn't get endpoint %d\n", i); | 216 | aprint_error_dev(self, "couldn't get endpoint %d\n", i); | |
217 | return; | 217 | return; | |
218 | } | 218 | } | |
219 | if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | 219 | if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | |
220 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | 220 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | |
221 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 221 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
222 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | 222 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | |
223 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) | 223 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) | |
224 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 224 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
225 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT && | 225 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT && | |
226 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | 226 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | |
227 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 227 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
228 | } | 228 | } | |
229 | 229 | |||
230 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 230 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
231 | un->un_ed[USBNET_ENDPT_TX] == 0 || | 231 | un->un_ed[USBNET_ENDPT_TX] == 0 || | |
232 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | 232 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | |
233 | aprint_error_dev(self, "missing endpoint\n"); | 233 | aprint_error_dev(self, "missing endpoint\n"); | |
234 | return; | 234 | return; | |
235 | } | 235 | } | |
236 | 236 | |||
237 | /* Not supported yet. */ | 237 | /* Not supported yet. */ | |
238 | un->un_ed[USBNET_ENDPT_INTR] = 0; | 238 | un->un_ed[USBNET_ENDPT_INTR] = 0; | |
239 | 239 | |||
240 | usbnet_attach(un, "udavdet"); | 240 | usbnet_attach(un, "udavdet"); | |
241 | 241 | |||
242 | usbnet_lock_core(un); | 242 | usbnet_lock_core(un); | |
243 | usbnet_busy(un); | 243 | usbnet_busy(un); | |
244 | 244 | |||
245 | // /* reset the adapter */ | 245 | // /* reset the adapter */ | |
246 | // udav_reset(un); | 246 | // udav_reset(un); | |
247 | 247 | |||
248 | /* Get Ethernet Address */ | 248 | /* Get Ethernet Address */ | |
249 | err = udav_csr_read(un, UDAV_PAR, un->un_eaddr, ETHER_ADDR_LEN); | 249 | err = udav_csr_read(un, UDAV_PAR, un->un_eaddr, ETHER_ADDR_LEN); | |
250 | usbnet_unbusy(un); | 250 | usbnet_unbusy(un); | |
251 | usbnet_unlock_core(un); | 251 | usbnet_unlock_core(un); | |
252 | if (err) { | 252 | if (err) { | |
253 | aprint_error_dev(self, "read MAC address failed\n"); | 253 | aprint_error_dev(self, "read MAC address failed\n"); | |
254 | return; | 254 | return; | |
255 | } | 255 | } | |
256 | 256 | |||
257 | if (ISSET(un->un_flags, UDAV_NO_PHY)) | 257 | if (ISSET(un->un_flags, UDAV_NO_PHY)) | |
258 | unmp = NULL; | 258 | unmp = NULL; | |
259 | else | 259 | else | |
260 | unmp = &unm; | 260 | unmp = &unm; | |
261 | 261 | |||
262 | /* initialize interface information */ | 262 | /* initialize interface information */ | |
263 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 263 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
264 | 0, unmp); | 264 | 0, unmp); | |
265 | 265 | |||
266 | return; | 266 | return; | |
267 | } | 267 | } | |
268 | 268 | |||
269 | #if 0 | 269 | #if 0 | |
270 | /* read memory */ | 270 | /* read memory */ | |
271 | static int | 271 | static int | |
272 | udav_mem_read(struct usbnet *un, int offset, void *buf, int len) | 272 | udav_mem_read(struct usbnet *un, int offset, void *buf, int len) | |
273 | { | 273 | { | |
274 | usb_device_request_t req; | 274 | usb_device_request_t req; | |
275 | usbd_status err; | 275 | usbd_status err; | |
276 | 276 | |||
277 | DPRINTFN(0x200, | 277 | DPRINTFN(0x200, | |
278 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 278 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
279 | 279 | |||
280 | if (usbnet_isdying(un)) | 280 | if (usbnet_isdying(un)) | |
281 | return 0; | 281 | return 0; | |
282 | 282 | |||
283 | offset &= 0xffff; | 283 | offset &= 0xffff; | |
284 | len &= 0xff; | 284 | len &= 0xff; | |
285 | 285 | |||
286 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 286 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
287 | req.bRequest = UDAV_REQ_MEM_READ; | 287 | req.bRequest = UDAV_REQ_MEM_READ; | |
288 | USETW(req.wValue, 0x0000); | 288 | USETW(req.wValue, 0x0000); | |
289 | USETW(req.wIndex, offset); | 289 | USETW(req.wIndex, offset); | |
290 | USETW(req.wLength, len); | 290 | USETW(req.wLength, len); | |
291 | 291 | |||
292 | err = usbd_do_request(un->un_udev, &req, buf); | 292 | err = usbd_do_request(un->un_udev, &req, buf); | |
293 | if (err) { | 293 | if (err) { | |
294 | DPRINTF(("%s: %s: read failed. off=%04x, err=%d\n", | 294 | DPRINTF(("%s: %s: read failed. off=%04x, err=%d\n", | |
295 | device_xname(un->un_dev), __func__, offset, err)); | 295 | device_xname(un->un_dev), __func__, offset, err)); | |
296 | } | 296 | } | |
297 | 297 | |||
298 | return err; | 298 | return err; | |
299 | } | 299 | } | |
300 | 300 | |||
301 | /* write memory */ | 301 | /* write memory */ | |
302 | static int | 302 | static int | |
303 | udav_mem_write(struct usbnet *un, int offset, void *buf, int len) | 303 | udav_mem_write(struct usbnet *un, int offset, void *buf, int len) | |
304 | { | 304 | { | |
305 | usb_device_request_t req; | 305 | usb_device_request_t req; | |
306 | usbd_status err; | 306 | usbd_status err; | |
307 | 307 | |||
308 | DPRINTFN(0x200, | 308 | DPRINTFN(0x200, | |
309 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 309 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
310 | 310 | |||
311 | if (usbnet_isdying(un)) | 311 | if (usbnet_isdying(un)) | |
312 | return 0; | 312 | return 0; | |
313 | 313 | |||
314 | offset &= 0xffff; | 314 | offset &= 0xffff; | |
315 | len &= 0xff; | 315 | len &= 0xff; | |
316 | 316 | |||
317 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 317 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
318 | req.bRequest = UDAV_REQ_MEM_WRITE; | 318 | req.bRequest = UDAV_REQ_MEM_WRITE; | |
319 | USETW(req.wValue, 0x0000); | 319 | USETW(req.wValue, 0x0000); | |
320 | USETW(req.wIndex, offset); | 320 | USETW(req.wIndex, offset); | |
321 | USETW(req.wLength, len); | 321 | USETW(req.wLength, len); | |
322 | 322 | |||
323 | err = usbd_do_request(un->un_udev, &req, buf); | 323 | err = usbd_do_request(un->un_udev, &req, buf); | |
324 | if (err) { | 324 | if (err) { | |
325 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | 325 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | |
326 | device_xname(un->un_dev), __func__, offset, err)); | 326 | device_xname(un->un_dev), __func__, offset, err)); | |
327 | } | 327 | } | |
328 | 328 | |||
329 | return err; | 329 | return err; | |
330 | } | 330 | } | |
331 | 331 | |||
332 | /* write memory */ | 332 | /* write memory */ | |
333 | static int | 333 | static int | |
334 | udav_mem_write1(struct usbnet *un, int offset, unsigned char ch) | 334 | udav_mem_write1(struct usbnet *un, int offset, unsigned char ch) | |
335 | { | 335 | { | |
336 | usb_device_request_t req; | 336 | usb_device_request_t req; | |
337 | usbd_status err; | 337 | usbd_status err; | |
338 | 338 | |||
339 | DPRINTFN(0x200, | 339 | DPRINTFN(0x200, | |
340 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 340 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
341 | 341 | |||
342 | if (usbnet_isdying(un)) | 342 | if (usbnet_isdying(un)) | |
343 | return 0; | 343 | return 0; | |
344 | 344 | |||
345 | offset &= 0xffff; | 345 | offset &= 0xffff; | |
346 | 346 | |||
347 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 347 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
348 | req.bRequest = UDAV_REQ_MEM_WRITE1; | 348 | req.bRequest = UDAV_REQ_MEM_WRITE1; | |
349 | USETW(req.wValue, ch); | 349 | USETW(req.wValue, ch); | |
350 | USETW(req.wIndex, offset); | 350 | USETW(req.wIndex, offset); | |
351 | USETW(req.wLength, 0x0000); | 351 | USETW(req.wLength, 0x0000); | |
352 | 352 | |||
353 | err = usbd_do_request(un->un_udev, &req, NULL); | 353 | err = usbd_do_request(un->un_udev, &req, NULL); | |
354 | if (err) { | 354 | if (err) { | |
355 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | 355 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | |
356 | device_xname(un->un_dev), __func__, offset, err)); | 356 | device_xname(un->un_dev), __func__, offset, err)); | |
357 | } | 357 | } | |
358 | 358 | |||
359 | return err; | 359 | return err; | |
360 | } | 360 | } | |
361 | #endif | 361 | #endif | |
362 | 362 | |||
363 | /* read register(s) */ | 363 | /* read register(s) */ | |
364 | static int | 364 | static int | |
365 | udav_csr_read(struct usbnet *un, int offset, void *buf, int len) | 365 | udav_csr_read(struct usbnet *un, int offset, void *buf, int len) | |
366 | { | 366 | { | |
367 | usb_device_request_t req; | 367 | usb_device_request_t req; | |
368 | usbd_status err; | 368 | usbd_status err; | |
369 | 369 | |||
370 | usbnet_isowned_core(un); | 370 | usbnet_isowned_core(un); | |
371 | KASSERT(!usbnet_isdying(un)); | 371 | KASSERT(!usbnet_isdying(un)); | |
372 | 372 | |||
373 | DPRINTFN(0x200, | 373 | DPRINTFN(0x200, | |
374 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 374 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
375 | 375 | |||
376 | offset &= 0xff; | 376 | offset &= 0xff; | |
377 | len &= 0xff; | 377 | len &= 0xff; | |
378 | 378 | |||
379 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 379 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
380 | req.bRequest = UDAV_REQ_REG_READ; | 380 | req.bRequest = UDAV_REQ_REG_READ; | |
381 | USETW(req.wValue, 0x0000); | 381 | USETW(req.wValue, 0x0000); | |
382 | USETW(req.wIndex, offset); | 382 | USETW(req.wIndex, offset); | |
383 | USETW(req.wLength, len); | 383 | USETW(req.wLength, len); | |
384 | 384 | |||
385 | err = usbd_do_request(un->un_udev, &req, buf); | 385 | err = usbd_do_request(un->un_udev, &req, buf); | |
386 | if (err) { | 386 | if (err) { | |
387 | DPRINTF(("%s: %s: read failed. off=%04x, err=%d\n", | 387 | DPRINTF(("%s: %s: read failed. off=%04x, err=%d\n", | |
388 | device_xname(un->un_dev), __func__, offset, err)); | 388 | device_xname(un->un_dev), __func__, offset, err)); | |
389 | } | 389 | } | |
390 | 390 | |||
391 | return err; | 391 | return err; | |
392 | } | 392 | } | |
393 | 393 | |||
394 | /* write register(s) */ | 394 | /* write register(s) */ | |
395 | static int | 395 | static int | |
396 | udav_csr_write(struct usbnet *un, int offset, void *buf, int len) | 396 | udav_csr_write(struct usbnet *un, int offset, void *buf, int len) | |
397 | { | 397 | { | |
398 | usb_device_request_t req; | 398 | usb_device_request_t req; | |
399 | usbd_status err; | 399 | usbd_status err; | |
400 | 400 | |||
401 | usbnet_isowned_core(un); | 401 | usbnet_isowned_core(un); | |
402 | KASSERT(!usbnet_isdying(un)); | 402 | KASSERT(!usbnet_isdying(un)); | |
403 | 403 | |||
404 | DPRINTFN(0x200, | 404 | DPRINTFN(0x200, | |
405 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 405 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
406 | 406 | |||
407 | offset &= 0xff; | 407 | offset &= 0xff; | |
408 | len &= 0xff; | 408 | len &= 0xff; | |
409 | 409 | |||
410 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 410 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
411 | req.bRequest = UDAV_REQ_REG_WRITE; | 411 | req.bRequest = UDAV_REQ_REG_WRITE; | |
412 | USETW(req.wValue, 0x0000); | 412 | USETW(req.wValue, 0x0000); | |
413 | USETW(req.wIndex, offset); | 413 | USETW(req.wIndex, offset); | |
414 | USETW(req.wLength, len); | 414 | USETW(req.wLength, len); | |
415 | 415 | |||
416 | err = usbd_do_request(un->un_udev, &req, buf); | 416 | err = usbd_do_request(un->un_udev, &req, buf); | |
417 | if (err) { | 417 | if (err) { | |
418 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | 418 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | |
419 | device_xname(un->un_dev), __func__, offset, err)); | 419 | device_xname(un->un_dev), __func__, offset, err)); | |
420 | } | 420 | } | |
421 | 421 | |||
422 | return err; | 422 | return err; | |
423 | } | 423 | } | |
424 | 424 | |||
425 | static int | 425 | static int | |
426 | udav_csr_read1(struct usbnet *un, int offset) | 426 | udav_csr_read1(struct usbnet *un, int offset) | |
427 | { | 427 | { | |
428 | uint8_t val = 0; | 428 | uint8_t val = 0; | |
429 | 429 | |||
430 | usbnet_isowned_core(un); | 430 | usbnet_isowned_core(un); | |
431 | 431 | |||
432 | DPRINTFN(0x200, | 432 | DPRINTFN(0x200, | |
433 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 433 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
434 | 434 | |||
435 | if (usbnet_isdying(un)) | 435 | if (usbnet_isdying(un)) | |
436 | return 0; | 436 | return 0; | |
437 | 437 | |||
438 | return udav_csr_read(un, offset, &val, 1) ? 0 : val; | 438 | return udav_csr_read(un, offset, &val, 1) ? 0 : val; | |
439 | } | 439 | } | |
440 | 440 | |||
441 | /* write a register */ | 441 | /* write a register */ | |
442 | static int | 442 | static int | |
443 | udav_csr_write1(struct usbnet *un, int offset, unsigned char ch) | 443 | udav_csr_write1(struct usbnet *un, int offset, unsigned char ch) | |
444 | { | 444 | { | |
445 | usb_device_request_t req; | 445 | usb_device_request_t req; | |
446 | usbd_status err; | 446 | usbd_status err; | |
447 | 447 | |||
448 | usbnet_isowned_core(un); | 448 | usbnet_isowned_core(un); | |
449 | KASSERT(!usbnet_isdying(un)); | 449 | KASSERT(!usbnet_isdying(un)); | |
450 | 450 | |||
451 | DPRINTFN(0x200, | 451 | DPRINTFN(0x200, | |
452 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 452 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
453 | 453 | |||
454 | offset &= 0xff; | 454 | offset &= 0xff; | |
455 | 455 | |||
456 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 456 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
457 | req.bRequest = UDAV_REQ_REG_WRITE1; | 457 | req.bRequest = UDAV_REQ_REG_WRITE1; | |
458 | USETW(req.wValue, ch); | 458 | USETW(req.wValue, ch); | |
459 | USETW(req.wIndex, offset); | 459 | USETW(req.wIndex, offset); | |
460 | USETW(req.wLength, 0x0000); | 460 | USETW(req.wLength, 0x0000); | |
461 | 461 | |||
462 | err = usbd_do_request(un->un_udev, &req, NULL); | 462 | err = usbd_do_request(un->un_udev, &req, NULL); | |
463 | if (err) { | 463 | if (err) { | |
464 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | 464 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | |
465 | device_xname(un->un_dev), __func__, offset, err)); | 465 | device_xname(un->un_dev), __func__, offset, err)); | |
466 | } | 466 | } | |
467 | 467 | |||
468 | return err; | 468 | return err; | |
469 | } | 469 | } | |
470 | 470 | |||
471 | static int | 471 | static int | |
472 | udav_uno_init(struct ifnet *ifp) | 472 | udav_uno_init(struct ifnet *ifp) | |
473 | { | 473 | { | |
474 | struct usbnet * const un = ifp->if_softc; | 474 | struct usbnet * const un = ifp->if_softc; | |
475 | struct mii_data * const mii = usbnet_mii(un); | 475 | struct mii_data * const mii = usbnet_mii(un); | |
476 | uint8_t eaddr[ETHER_ADDR_LEN]; | 476 | uint8_t eaddr[ETHER_ADDR_LEN]; | |
477 | int rc = 0; | 477 | int rc = 0; | |
478 | 478 | |||
479 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 479 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
480 | 480 | |||
481 | if (usbnet_isdying(un)) { | 481 | if (usbnet_isdying(un)) { | |
482 | return EIO; | 482 | return EIO; | |
483 | } | 483 | } | |
484 | 484 | |||
485 | /* Cancel pending I/O and free all TX/RX buffers */ | 485 | /* Cancel pending I/O and free all TX/RX buffers */ | |
486 | if (ifp->if_flags & IFF_RUNNING) | 486 | if (ifp->if_flags & IFF_RUNNING) | |
487 | usbnet_stop(un, ifp, 1); | 487 | usbnet_stop(un, ifp, 1); | |
488 | 488 | |||
489 | memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); | 489 | memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); | |
490 | udav_csr_write(un, UDAV_PAR, eaddr, ETHER_ADDR_LEN); | 490 | udav_csr_write(un, UDAV_PAR, eaddr, ETHER_ADDR_LEN); | |
491 | 491 | |||
492 | /* Initialize network control register */ | 492 | /* Initialize network control register */ | |
493 | /* Disable loopback */ | 493 | /* Disable loopback */ | |
494 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1); | 494 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1); | |
495 | 495 | |||
496 | /* Initialize RX control register */ | 496 | /* Initialize RX control register */ | |
497 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC); | 497 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC); | |
498 | 498 | |||
499 | /* If we want promiscuous mode, accept all physical frames. */ | 499 | /* If we want promiscuous mode, accept all physical frames. */ | |
500 | if (ifp->if_flags & IFF_PROMISC) | 500 | if (ifp->if_flags & IFF_PROMISC) | |
501 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | 501 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | |
502 | else | 502 | else | |
503 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | 503 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | |
504 | 504 | |||
505 | /* Load the multicast filter */ | 505 | /* Load the multicast filter */ | |
506 | udav_setiff_locked(un); | 506 | udav_setiff_locked(un); | |
507 | 507 | |||
508 | /* Enable RX */ | 508 | /* Enable RX */ | |
509 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_RXEN); | 509 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_RXEN); | |
510 | 510 | |||
511 | /* clear POWER_DOWN state of internal PHY */ | 511 | /* clear POWER_DOWN state of internal PHY */ | |
512 | UDAV_SETBIT(un, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0); | 512 | UDAV_SETBIT(un, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0); | |
513 | UDAV_CLRBIT(un, UDAV_GPR, UDAV_GPR_GEPIO0); | 513 | UDAV_CLRBIT(un, UDAV_GPR, UDAV_GPR_GEPIO0); | |
514 | 514 | |||
515 | if (mii && (rc = mii_mediachg(mii)) == ENXIO) | 515 | if (mii && (rc = mii_mediachg(mii)) == ENXIO) | |
516 | rc = 0; | 516 | rc = 0; | |
517 | 517 | |||
518 | if (rc != 0) { | 518 | if (rc != 0) { | |
519 | return rc; | 519 | return rc; | |
520 | } | 520 | } | |
521 | 521 | |||
522 | if (usbnet_isdying(un)) | 522 | if (usbnet_isdying(un)) | |
523 | rc = EIO; | 523 | rc = EIO; | |
524 | else | 524 | else | |
525 | rc = usbnet_init_rx_tx(un); | 525 | rc = usbnet_init_rx_tx(un); | |
526 | 526 | |||
527 | return rc; | 527 | return rc; | |
528 | } | 528 | } | |
529 | 529 | |||
530 | static void | 530 | static void | |
531 | udav_reset(struct usbnet *un) | 531 | udav_reset(struct usbnet *un) | |
532 | { | 532 | { | |
533 | usbnet_isowned_core(un); | 533 | usbnet_isowned_core(un); | |
534 | 534 | |||
535 | if (usbnet_isdying(un)) | 535 | if (usbnet_isdying(un)) | |
536 | return; | 536 | return; | |
537 | 537 | |||
538 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 538 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
539 | 539 | |||
540 | udav_chip_init(un); | 540 | udav_chip_init(un); | |
541 | } | 541 | } | |
542 | 542 | |||
543 | static void | 543 | static void | |
544 | udav_chip_init(struct usbnet *un) | 544 | udav_chip_init(struct usbnet *un) | |
545 | { | 545 | { | |
546 | usbnet_isowned_core(un); | 546 | usbnet_isowned_core(un); | |
547 | 547 | |||
548 | /* Select PHY */ | 548 | /* Select PHY */ | |
549 | #if 1 | 549 | #if 1 | |
550 | /* | 550 | /* | |
551 | * XXX: force select internal phy. | 551 | * XXX: force select internal phy. | |
552 | * external phy routines are not tested. | 552 | * external phy routines are not tested. | |
553 | */ | 553 | */ | |
554 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | 554 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | |
555 | #else | 555 | #else | |
556 | if (un->un_flags & UDAV_EXT_PHY) { | 556 | if (un->un_flags & UDAV_EXT_PHY) { | |
557 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | 557 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | |
558 | } else { | 558 | } else { | |
559 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | 559 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | |
560 | } | 560 | } | |
561 | #endif | 561 | #endif | |
562 | 562 | |||
563 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_RST); | 563 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_RST); | |
564 | 564 | |||
565 | for (int i = 0; i < UDAV_TX_TIMEOUT; i++) { | 565 | for (int i = 0; i < UDAV_TX_TIMEOUT; i++) { | |
566 | if (usbnet_isdying(un)) | 566 | if (usbnet_isdying(un)) | |
567 | return; | 567 | return; | |
568 | if (!(udav_csr_read1(un, UDAV_NCR) & UDAV_NCR_RST)) | 568 | if (!(udav_csr_read1(un, UDAV_NCR) & UDAV_NCR_RST)) | |
569 | break; | 569 | break; | |
570 | delay(10); /* XXX */ | 570 | delay(10); /* XXX */ | |
571 | } | 571 | } | |
572 | delay(10000); /* XXX */ | 572 | delay(10000); /* XXX */ | |
573 | } | 573 | } | |
574 | 574 | |||
575 | #define UDAV_BITS 6 | 575 | #define UDAV_BITS 6 | |
576 | 576 | |||
577 | #define UDAV_CALCHASH(addr) \ | 577 | #define UDAV_CALCHASH(addr) \ | |
578 | (ether_crc32_le((addr), ETHER_ADDR_LEN) & ((1 << UDAV_BITS) - 1)) | 578 | (ether_crc32_le((addr), ETHER_ADDR_LEN) & ((1 << UDAV_BITS) - 1)) | |
579 | 579 | |||
580 | static void | 580 | static void | |
581 | udav_setiff_locked(struct usbnet *un) | 581 | udav_setiff_locked(struct usbnet *un) | |
582 | { | 582 | { | |
583 | struct ethercom *ec = usbnet_ec(un); | 583 | struct ethercom *ec = usbnet_ec(un); | |
584 | struct ifnet * const ifp = usbnet_ifp(un); | 584 | struct ifnet * const ifp = usbnet_ifp(un); | |
585 | struct ether_multi *enm; | 585 | struct ether_multi *enm; | |
586 | struct ether_multistep step; | 586 | struct ether_multistep step; | |
587 | uint8_t hashes[8]; | 587 | uint8_t hashes[8]; | |
588 | int h = 0; | 588 | int h = 0; | |
589 | 589 | |||
590 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 590 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
591 | 591 | |||
592 | usbnet_isowned_core(un); | 592 | usbnet_isowned_core(un); | |
593 | 593 | |||
594 | if (usbnet_isdying(un)) | 594 | if (usbnet_isdying(un)) | |
595 | return; | 595 | return; | |
596 | 596 | |||
597 | if (ISSET(un->un_flags, UDAV_NO_PHY)) { | 597 | if (ISSET(un->un_flags, UDAV_NO_PHY)) { | |
598 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | 598 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | |
599 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | 599 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | |
600 | return; | 600 | return; | |
601 | } | 601 | } | |
602 | 602 | |||
603 | if (ifp->if_flags & IFF_PROMISC) { | 603 | if (ifp->if_flags & IFF_PROMISC) { | |
604 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | 604 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | |
605 | return; | 605 | return; | |
606 | } else if (ifp->if_flags & IFF_ALLMULTI) { | 606 | } else if (ifp->if_flags & IFF_ALLMULTI) { | |
607 | allmulti: | 607 | allmulti: | |
608 | ifp->if_flags |= IFF_ALLMULTI; | 608 | ifp->if_flags |= IFF_ALLMULTI; | |
609 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | 609 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | |
610 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | 610 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | |
611 | return; | 611 | return; | |
612 | } | 612 | } | |
613 | 613 | |||
614 | /* first, zot all the existing hash bits */ | 614 | /* first, zot all the existing hash bits */ | |
615 | memset(hashes, 0x00, sizeof(hashes)); | 615 | memset(hashes, 0x00, sizeof(hashes)); | |
616 | hashes[7] |= 0x80; /* broadcast address */ | 616 | hashes[7] |= 0x80; /* broadcast address */ | |
617 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | 617 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | |
618 | 618 | |||
619 | /* now program new ones */ | 619 | /* now program new ones */ | |
620 | ETHER_LOCK(ec); | 620 | ETHER_LOCK(ec); | |
621 | ETHER_FIRST_MULTI(step, ec, enm); | 621 | ETHER_FIRST_MULTI(step, ec, enm); | |
622 | while (enm != NULL) { | 622 | while (enm != NULL) { | |
623 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | 623 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
624 | ETHER_ADDR_LEN) != 0) { | 624 | ETHER_ADDR_LEN) != 0) { | |
625 | ETHER_UNLOCK(ec); | 625 | ETHER_UNLOCK(ec); | |
626 | goto allmulti; | 626 | goto allmulti; | |
627 | } | 627 | } | |
628 | 628 | |||
629 | h = UDAV_CALCHASH(enm->enm_addrlo); | 629 | h = UDAV_CALCHASH(enm->enm_addrlo); | |
630 | hashes[h>>3] |= 1 << (h & 0x7); | 630 | hashes[h>>3] |= 1 << (h & 0x7); | |
631 | ETHER_NEXT_MULTI(step, enm); | 631 | ETHER_NEXT_MULTI(step, enm); | |
632 | } | 632 | } | |
633 | ETHER_UNLOCK(ec); | 633 | ETHER_UNLOCK(ec); | |
634 | 634 | |||
635 | /* disable all multicast */ | 635 | /* disable all multicast */ | |
636 | ifp->if_flags &= ~IFF_ALLMULTI; | 636 | ifp->if_flags &= ~IFF_ALLMULTI; | |
637 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL); | 637 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL); | |
638 | 638 | |||
639 | /* write hash value to the register */ | 639 | /* write hash value to the register */ | |
640 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | 640 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | |
641 | } | 641 | } | |
642 | 642 | |||
643 | static unsigned | 643 | static unsigned | |
644 | udav_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 644 | udav_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
645 | { | 645 | { | |
646 | int total_len; | 646 | int total_len; | |
647 | uint8_t *buf = c->unc_buf; | 647 | uint8_t *buf = c->unc_buf; | |
648 | 648 | |||
649 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 649 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
650 | 650 | |||
651 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | 651 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | |
652 | return 0; | 652 | return 0; | |
653 | 653 | |||
654 | /* Copy the mbuf data into a contiguous buffer */ | 654 | /* Copy the mbuf data into a contiguous buffer */ | |
655 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | 655 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | |
656 | total_len = m->m_pkthdr.len; | 656 | total_len = m->m_pkthdr.len; | |
657 | if (total_len < UDAV_MIN_FRAME_LEN) { | 657 | if (total_len < UDAV_MIN_FRAME_LEN) { | |
658 | memset(buf + 2 + total_len, 0, | 658 | memset(buf + 2 + total_len, 0, | |
659 | UDAV_MIN_FRAME_LEN - total_len); | 659 | UDAV_MIN_FRAME_LEN - total_len); | |
660 | total_len = UDAV_MIN_FRAME_LEN; | 660 | total_len = UDAV_MIN_FRAME_LEN; | |
661 | } | 661 | } | |
662 | 662 | |||
663 | /* Frame length is specified in the first 2bytes of the buffer */ | 663 | /* Frame length is specified in the first 2bytes of the buffer */ | |
664 | buf[0] = (uint8_t)total_len; | 664 | buf[0] = (uint8_t)total_len; | |
665 | buf[1] = (uint8_t)(total_len >> 8); | 665 | buf[1] = (uint8_t)(total_len >> 8); | |
666 | total_len += 2; | 666 | total_len += 2; | |
667 | 667 | |||
668 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | 668 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | |
669 | __func__, total_len)); | 669 | __func__, total_len)); | |
670 | 670 | |||
671 | return total_len; | 671 | return total_len; | |
672 | } | 672 | } | |
673 | 673 | |||
674 | static void | 674 | static void | |
675 | udav_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 675 | udav_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
676 | { | 676 | { | |
677 | struct ifnet *ifp = usbnet_ifp(un); | 677 | struct ifnet *ifp = usbnet_ifp(un); | |
678 | uint8_t *buf = c->unc_buf; | 678 | uint8_t *buf = c->unc_buf; | |
679 | uint16_t pkt_len; | 679 | uint16_t pkt_len; | |
680 | uint8_t pktstat; | 680 | uint8_t pktstat; | |
681 | 681 | |||
682 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 682 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
683 | 683 | |||
684 | /* first byte in received data */ | 684 | /* first byte in received data */ | |
685 | pktstat = *buf; | 685 | pktstat = *buf; | |
686 | total_len -= sizeof(pktstat); | 686 | total_len -= sizeof(pktstat); | |
687 | buf += sizeof(pktstat); | 687 | buf += sizeof(pktstat); | |
688 | 688 | |||
689 | DPRINTF(("%s: RX Status: 0x%02x\n", device_xname(un->un_dev), pktstat)); | 689 | DPRINTF(("%s: RX Status: 0x%02x\n", device_xname(un->un_dev), pktstat)); | |
690 | 690 | |||
691 | pkt_len = UGETW(buf); | 691 | pkt_len = UGETW(buf); | |
692 | total_len -= sizeof(pkt_len); | 692 | total_len -= sizeof(pkt_len); | |
693 | buf += sizeof(pkt_len); | 693 | buf += sizeof(pkt_len); | |
694 | 694 | |||
695 | DPRINTF(("%s: RX Length: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | 695 | DPRINTF(("%s: RX Length: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | |
696 | 696 | |||
697 | if (pktstat & UDAV_RSR_LCS) { | 697 | if (pktstat & UDAV_RSR_LCS) { | |
698 | if_statinc(ifp, if_collisions); | 698 | if_statinc(ifp, if_collisions); | |
699 | return; | 699 | return; | |
700 | } | 700 | } | |
701 | 701 | |||
702 | if (pkt_len < sizeof(struct ether_header) || | 702 | if (pkt_len < sizeof(struct ether_header) || | |
703 | pkt_len > total_len || | 703 | pkt_len > total_len || | |
704 | (pktstat & UDAV_RSR_ERR)) { | 704 | (pktstat & UDAV_RSR_ERR)) { | |
705 | if_statinc(ifp, if_ierrors); | 705 | if_statinc(ifp, if_ierrors); | |
706 | return; | 706 | return; | |
707 | } | 707 | } | |
708 | 708 | |||
709 | pkt_len -= ETHER_CRC_LEN; | 709 | pkt_len -= ETHER_CRC_LEN; | |
710 | 710 | |||
711 | DPRINTF(("%s: Rx deliver: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | 711 | DPRINTF(("%s: Rx deliver: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | |
712 | 712 | |||
713 | usbnet_enqueue(un, buf, pkt_len, 0, 0, 0); | 713 | usbnet_enqueue(un, buf, pkt_len, 0, 0, 0); | |
714 | } | 714 | } | |
715 | 715 | |||
716 | static void | 716 | static void | |
717 | udav_uno_mcast(struct ifnet *ifp) | 717 | udav_uno_mcast(struct ifnet *ifp) | |
718 | { | 718 | { | |
719 | struct usbnet * const un = ifp->if_softc; | 719 | struct usbnet * const un = ifp->if_softc; | |
720 | 720 | |||
721 | usbnet_lock_core(un); | 721 | usbnet_lock_core(un); | |
722 | usbnet_busy(un); | |||
723 | 722 | |||
724 | udav_setiff_locked(un); | 723 | udav_setiff_locked(un); | |
725 | 724 | |||
726 | usbnet_unbusy(un); | |||
727 | usbnet_unlock_core(un); | 725 | usbnet_unlock_core(un); | |
728 | } | 726 | } | |
729 | 727 | |||
730 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | 728 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | |
731 | static void | 729 | static void | |
732 | udav_uno_stop(struct ifnet *ifp, int disable) | 730 | udav_uno_stop(struct ifnet *ifp, int disable) | |
733 | { | 731 | { | |
734 | struct usbnet * const un = ifp->if_softc; | 732 | struct usbnet * const un = ifp->if_softc; | |
735 | 733 | |||
736 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 734 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
737 | 735 | |||
738 | udav_reset(un); | 736 | udav_reset(un); | |
739 | } | 737 | } | |
740 | 738 | |||
741 | static int | 739 | static int | |
742 | udav_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 740 | udav_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
743 | { | 741 | { | |
744 | uint8_t data[2]; | 742 | uint8_t data[2]; | |
745 | 743 | |||
746 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | 744 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | |
747 | device_xname(un->un_dev), __func__, phy, reg)); | 745 | device_xname(un->un_dev), __func__, phy, reg)); | |
748 | 746 | |||
749 | if (usbnet_isdying(un)) { | 747 | if (usbnet_isdying(un)) { | |
750 | #ifdef DIAGNOSTIC | 748 | #ifdef DIAGNOSTIC | |
751 | printf("%s: %s: dying\n", device_xname(un->un_dev), | 749 | printf("%s: %s: dying\n", device_xname(un->un_dev), | |
752 | __func__); | 750 | __func__); | |
753 | #endif | 751 | #endif | |
754 | return EINVAL; | 752 | return EINVAL; | |
755 | } | 753 | } | |
756 | 754 | |||
757 | /* XXX: one PHY only for the internal PHY */ | 755 | /* XXX: one PHY only for the internal PHY */ | |
758 | if (phy != 0) { | 756 | if (phy != 0) { | |
759 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 757 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
760 | device_xname(un->un_dev), __func__, phy)); | 758 | device_xname(un->un_dev), __func__, phy)); | |
761 | return EINVAL; | 759 | return EINVAL; | |
762 | } | 760 | } | |
763 | 761 | |||
764 | /* select internal PHY and set PHY register address */ | 762 | /* select internal PHY and set PHY register address */ | |
765 | udav_csr_write1(un, UDAV_EPAR, | 763 | udav_csr_write1(un, UDAV_EPAR, | |
766 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | 764 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | |
767 | 765 | |||
768 | /* select PHY operation and start read command */ | 766 | /* select PHY operation and start read command */ | |
769 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR); | 767 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR); | |
770 | 768 | |||
771 | /* XXX: should be wait? */ | 769 | /* XXX: should be wait? */ | |
772 | 770 | |||
773 | /* end read command */ | 771 | /* end read command */ | |
774 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRR); | 772 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRR); | |
775 | 773 | |||
776 | /* retrieve the result from data registers */ | 774 | /* retrieve the result from data registers */ | |
777 | udav_csr_read(un, UDAV_EPDRL, data, 2); | 775 | udav_csr_read(un, UDAV_EPDRL, data, 2); | |
778 | 776 | |||
779 | *val = data[0] | (data[1] << 8); | 777 | *val = data[0] | (data[1] << 8); | |
780 | 778 | |||
781 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | 779 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | |
782 | device_xname(un->un_dev), __func__, phy, reg, *val)); | 780 | device_xname(un->un_dev), __func__, phy, reg, *val)); | |
783 | 781 | |||
784 | return 0; | 782 | return 0; | |
785 | } | 783 | } | |
786 | 784 | |||
787 | static int | 785 | static int | |
788 | udav_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 786 | udav_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
789 | { | 787 | { | |
790 | uint8_t data[2]; | 788 | uint8_t data[2]; | |
791 | 789 | |||
792 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | 790 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | |
793 | device_xname(un->un_dev), __func__, phy, reg, val)); | 791 | device_xname(un->un_dev), __func__, phy, reg, val)); | |
794 | 792 | |||
795 | if (usbnet_isdying(un)) { | 793 | if (usbnet_isdying(un)) { | |
796 | #ifdef DIAGNOSTIC | 794 | #ifdef DIAGNOSTIC | |
797 | printf("%s: %s: dying\n", device_xname(un->un_dev), | 795 | printf("%s: %s: dying\n", device_xname(un->un_dev), | |
798 | __func__); | 796 | __func__); | |
799 | #endif | 797 | #endif | |
800 | return EIO; | 798 | return EIO; | |
801 | } | 799 | } | |
802 | 800 | |||
803 | /* XXX: one PHY only for the internal PHY */ | 801 | /* XXX: one PHY only for the internal PHY */ | |
804 | if (phy != 0) { | 802 | if (phy != 0) { | |
805 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 803 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
806 | device_xname(un->un_dev), __func__, phy)); | 804 | device_xname(un->un_dev), __func__, phy)); | |
807 | return EIO; | 805 | return EIO; | |
808 | } | 806 | } | |
809 | 807 | |||
810 | /* select internal PHY and set PHY register address */ | 808 | /* select internal PHY and set PHY register address */ | |
811 | udav_csr_write1(un, UDAV_EPAR, | 809 | udav_csr_write1(un, UDAV_EPAR, | |
812 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | 810 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | |
813 | 811 | |||
814 | /* put the value to the data registers */ | 812 | /* put the value to the data registers */ | |
815 | data[0] = val & 0xff; | 813 | data[0] = val & 0xff; | |
816 | data[1] = (val >> 8) & 0xff; | 814 | data[1] = (val >> 8) & 0xff; | |
817 | udav_csr_write(un, UDAV_EPDRL, data, 2); | 815 | udav_csr_write(un, UDAV_EPDRL, data, 2); | |
818 | 816 | |||
819 | /* select PHY operation and start write command */ | 817 | /* select PHY operation and start write command */ | |
820 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW); | 818 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW); | |
821 | 819 | |||
822 | /* XXX: should be wait? */ | 820 | /* XXX: should be wait? */ | |
823 | 821 | |||
824 | /* end write command */ | 822 | /* end write command */ | |
825 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRW); | 823 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRW); | |
826 | 824 | |||
827 | return 0; | 825 | return 0; | |
828 | } | 826 | } | |
829 | 827 | |||
830 | static void | 828 | static void | |
831 | udav_uno_mii_statchg(struct ifnet *ifp) | 829 | udav_uno_mii_statchg(struct ifnet *ifp) | |
832 | { | 830 | { | |
833 | struct usbnet * const un = ifp->if_softc; | 831 | struct usbnet * const un = ifp->if_softc; | |
834 | struct mii_data * const mii = usbnet_mii(un); | 832 | struct mii_data * const mii = usbnet_mii(un); | |
835 | 833 | |||
836 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | 834 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | |
837 | 835 | |||
838 | if (usbnet_isdying(un)) | 836 | if (usbnet_isdying(un)) | |
839 | return; | 837 | return; | |
840 | 838 | |||
841 | if ((mii->mii_media_status & IFM_ACTIVE) && | 839 | if ((mii->mii_media_status & IFM_ACTIVE) && | |
842 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | 840 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | |
843 | DPRINTF(("%s: %s: got link\n", | 841 | DPRINTF(("%s: %s: got link\n", | |
844 | device_xname(un->un_dev), __func__)); | 842 | device_xname(un->un_dev), __func__)); | |
845 | usbnet_set_link(un, true); | 843 | usbnet_set_link(un, true); | |
846 | } | 844 | } | |
847 | } | 845 | } | |
848 | 846 | |||
849 | #ifdef _MODULE | 847 | #ifdef _MODULE | |
850 | #include "ioconf.c" | 848 | #include "ioconf.c" | |
851 | #endif | 849 | #endif | |
852 | 850 | |||
853 | USBNET_MODULE(udav) | 851 | USBNET_MODULE(udav) |
--- src/sys/dev/usb/if_url.c 2022/03/03 05:51:17 1.82
+++ src/sys/dev/usb/if_url.c 2022/03/03 05:51:27 1.83
@@ -1,763 +1,761 @@ | @@ -1,763 +1,761 @@ | |||
1 | /* $NetBSD: if_url.c,v 1.82 2022/03/03 05:51:17 riastradh Exp $ */ | 1 | /* $NetBSD: if_url.c,v 1.83 2022/03/03 05:51:27 riastradh Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2001, 2002 | 4 | * Copyright (c) 2001, 2002 | |
5 | * Shingo WATANABE <nabe@nabechan.org>. All rights reserved. | 5 | * Shingo WATANABE <nabe@nabechan.org>. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of the author nor the names of any co-contributors | 15 | * 3. Neither the name of the author nor the names of any co-contributors | |
16 | * may be used to endorse or promote products derived from this software | 16 | * may be used to endorse or promote products derived from this software | |
17 | * without specific prior written permission. | 17 | * without specific prior written permission. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | * | 30 | * | |
31 | */ | 31 | */ | |
32 | 32 | |||
33 | /* | 33 | /* | |
34 | * The RTL8150L(Realtek USB to fast ethernet controller) spec can be found at | 34 | * The RTL8150L(Realtek USB to fast ethernet controller) spec can be found at | |
35 | * ftp://ftp.realtek.com.tw/lancard/data_sheet/8150/8150v14.pdf | 35 | * ftp://ftp.realtek.com.tw/lancard/data_sheet/8150/8150v14.pdf | |
36 | * ftp://152.104.125.40/lancard/data_sheet/8150/8150v14.pdf | 36 | * ftp://152.104.125.40/lancard/data_sheet/8150/8150v14.pdf | |
37 | */ | 37 | */ | |
38 | 38 | |||
39 | /* | 39 | /* | |
40 | * TODO: | 40 | * TODO: | |
41 | * Interrupt Endpoint support | 41 | * Interrupt Endpoint support | |
42 | * External PHYs | 42 | * External PHYs | |
43 | * powerhook() support? | 43 | * powerhook() support? | |
44 | */ | 44 | */ | |
45 | 45 | |||
46 | #include <sys/cdefs.h> | 46 | #include <sys/cdefs.h> | |
47 | __KERNEL_RCSID(0, "$NetBSD: if_url.c,v 1.82 2022/03/03 05:51:17 riastradh Exp $"); | 47 | __KERNEL_RCSID(0, "$NetBSD: if_url.c,v 1.83 2022/03/03 05:51:27 riastradh Exp $"); | |
48 | 48 | |||
49 | #ifdef _KERNEL_OPT | 49 | #ifdef _KERNEL_OPT | |
50 | #include "opt_inet.h" | 50 | #include "opt_inet.h" | |
51 | #include "opt_usb.h" | 51 | #include "opt_usb.h" | |
52 | #endif | 52 | #endif | |
53 | 53 | |||
54 | #include <sys/param.h> | 54 | #include <sys/param.h> | |
55 | 55 | |||
56 | #include <net/if_ether.h> | 56 | #include <net/if_ether.h> | |
57 | #ifdef INET | 57 | #ifdef INET | |
58 | #include <netinet/in.h> | 58 | #include <netinet/in.h> | |
59 | #include <netinet/if_inarp.h> | 59 | #include <netinet/if_inarp.h> | |
60 | #endif | 60 | #endif | |
61 | 61 | |||
62 | #include <dev/mii/urlphyreg.h> | 62 | #include <dev/mii/urlphyreg.h> | |
63 | 63 | |||
64 | #include <dev/usb/usbnet.h> | 64 | #include <dev/usb/usbnet.h> | |
65 | 65 | |||
66 | #include <dev/usb/if_urlreg.h> | 66 | #include <dev/usb/if_urlreg.h> | |
67 | 67 | |||
68 | /* Function declarations */ | 68 | /* Function declarations */ | |
69 | static int url_match(device_t, cfdata_t, void *); | 69 | static int url_match(device_t, cfdata_t, void *); | |
70 | static void url_attach(device_t, device_t, void *); | 70 | static void url_attach(device_t, device_t, void *); | |
71 | 71 | |||
72 | CFATTACH_DECL_NEW(url, sizeof(struct usbnet), url_match, url_attach, | 72 | CFATTACH_DECL_NEW(url, sizeof(struct usbnet), url_match, url_attach, | |
73 | usbnet_detach, usbnet_activate); | 73 | usbnet_detach, usbnet_activate); | |
74 | 74 | |||
75 | static unsigned url_uno_tx_prepare(struct usbnet *, struct mbuf *, | 75 | static unsigned url_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
76 | struct usbnet_chain *); | 76 | struct usbnet_chain *); | |
77 | static void url_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 77 | static void url_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
78 | static int url_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 78 | static int url_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
79 | static int url_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 79 | static int url_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
80 | static void url_uno_mcast(struct ifnet *); | 80 | static void url_uno_mcast(struct ifnet *); | |
81 | static void url_uno_stop(struct ifnet *, int); | 81 | static void url_uno_stop(struct ifnet *, int); | |
82 | static void url_uno_mii_statchg(struct ifnet *); | 82 | static void url_uno_mii_statchg(struct ifnet *); | |
83 | static int url_uno_init(struct ifnet *); | 83 | static int url_uno_init(struct ifnet *); | |
84 | static void url_rcvfilt_locked(struct usbnet *); | 84 | static void url_rcvfilt_locked(struct usbnet *); | |
85 | static void url_reset(struct usbnet *); | 85 | static void url_reset(struct usbnet *); | |
86 | 86 | |||
87 | static int url_csr_read_1(struct usbnet *, int); | 87 | static int url_csr_read_1(struct usbnet *, int); | |
88 | static int url_csr_read_2(struct usbnet *, int); | 88 | static int url_csr_read_2(struct usbnet *, int); | |
89 | static int url_csr_write_1(struct usbnet *, int, int); | 89 | static int url_csr_write_1(struct usbnet *, int, int); | |
90 | static int url_csr_write_2(struct usbnet *, int, int); | 90 | static int url_csr_write_2(struct usbnet *, int, int); | |
91 | static int url_csr_write_4(struct usbnet *, int, int); | 91 | static int url_csr_write_4(struct usbnet *, int, int); | |
92 | static int url_mem(struct usbnet *, int, int, void *, int); | 92 | static int url_mem(struct usbnet *, int, int, void *, int); | |
93 | 93 | |||
94 | static const struct usbnet_ops url_ops = { | 94 | static const struct usbnet_ops url_ops = { | |
95 | .uno_stop = url_uno_stop, | 95 | .uno_stop = url_uno_stop, | |
96 | .uno_mcast = url_uno_mcast, | 96 | .uno_mcast = url_uno_mcast, | |
97 | .uno_read_reg = url_uno_mii_read_reg, | 97 | .uno_read_reg = url_uno_mii_read_reg, | |
98 | .uno_write_reg = url_uno_mii_write_reg, | 98 | .uno_write_reg = url_uno_mii_write_reg, | |
99 | .uno_statchg = url_uno_mii_statchg, | 99 | .uno_statchg = url_uno_mii_statchg, | |
100 | .uno_tx_prepare = url_uno_tx_prepare, | 100 | .uno_tx_prepare = url_uno_tx_prepare, | |
101 | .uno_rx_loop = url_uno_rx_loop, | 101 | .uno_rx_loop = url_uno_rx_loop, | |
102 | .uno_init = url_uno_init, | 102 | .uno_init = url_uno_init, | |
103 | }; | 103 | }; | |
104 | 104 | |||
105 | /* Macros */ | 105 | /* Macros */ | |
106 | #ifdef URL_DEBUG | 106 | #ifdef URL_DEBUG | |
107 | #define DPRINTF(x) if (urldebug) printf x | 107 | #define DPRINTF(x) if (urldebug) printf x | |
108 | #define DPRINTFN(n, x) if (urldebug >= (n)) printf x | 108 | #define DPRINTFN(n, x) if (urldebug >= (n)) printf x | |
109 | int urldebug = 0; | 109 | int urldebug = 0; | |
110 | #else | 110 | #else | |
111 | #define DPRINTF(x) | 111 | #define DPRINTF(x) | |
112 | #define DPRINTFN(n, x) | 112 | #define DPRINTFN(n, x) | |
113 | #endif | 113 | #endif | |
114 | 114 | |||
115 | #define URL_SETBIT(un, reg, x) \ | 115 | #define URL_SETBIT(un, reg, x) \ | |
116 | url_csr_write_1(un, reg, url_csr_read_1(un, reg) | (x)) | 116 | url_csr_write_1(un, reg, url_csr_read_1(un, reg) | (x)) | |
117 | 117 | |||
118 | #define URL_SETBIT2(un, reg, x) \ | 118 | #define URL_SETBIT2(un, reg, x) \ | |
119 | url_csr_write_2(un, reg, url_csr_read_2(un, reg) | (x)) | 119 | url_csr_write_2(un, reg, url_csr_read_2(un, reg) | (x)) | |
120 | 120 | |||
121 | #define URL_CLRBIT(un, reg, x) \ | 121 | #define URL_CLRBIT(un, reg, x) \ | |
122 | url_csr_write_1(un, reg, url_csr_read_1(un, reg) & ~(x)) | 122 | url_csr_write_1(un, reg, url_csr_read_1(un, reg) & ~(x)) | |
123 | 123 | |||
124 | #define URL_CLRBIT2(un, reg, x) \ | 124 | #define URL_CLRBIT2(un, reg, x) \ | |
125 | url_csr_write_2(un, reg, url_csr_read_2(un, reg) & ~(x)) | 125 | url_csr_write_2(un, reg, url_csr_read_2(un, reg) & ~(x)) | |
126 | 126 | |||
127 | static const struct url_type { | 127 | static const struct url_type { | |
128 | struct usb_devno url_dev; | 128 | struct usb_devno url_dev; | |
129 | uint16_t url_flags; | 129 | uint16_t url_flags; | |
130 | #define URL_EXT_PHY 0x0001 | 130 | #define URL_EXT_PHY 0x0001 | |
131 | } url_devs [] = { | 131 | } url_devs [] = { | |
132 | /* MELCO LUA-KTX */ | 132 | /* MELCO LUA-KTX */ | |
133 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX }, 0}, | 133 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX }, 0}, | |
134 | /* Realtek RTL8150L Generic (GREEN HOUSE USBKR100) */ | 134 | /* Realtek RTL8150L Generic (GREEN HOUSE USBKR100) */ | |
135 | {{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8150L}, 0}, | 135 | {{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8150L}, 0}, | |
136 | /* Longshine LCS-8138TX */ | 136 | /* Longshine LCS-8138TX */ | |
137 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_LCS8138TX}, 0}, | 137 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_LCS8138TX}, 0}, | |
138 | /* Micronet SP128AR */ | 138 | /* Micronet SP128AR */ | |
139 | {{ USB_VENDOR_MICRONET, USB_PRODUCT_MICRONET_SP128AR}, 0}, | 139 | {{ USB_VENDOR_MICRONET, USB_PRODUCT_MICRONET_SP128AR}, 0}, | |
140 | /* OQO model 01 */ | 140 | /* OQO model 01 */ | |
141 | {{ USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01}, 0}, | 141 | {{ USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01}, 0}, | |
142 | }; | 142 | }; | |
143 | #define url_lookup(v, p) ((const struct url_type *)usb_lookup(url_devs, v, p)) | 143 | #define url_lookup(v, p) ((const struct url_type *)usb_lookup(url_devs, v, p)) | |
144 | 144 | |||
145 | 145 | |||
146 | /* Probe */ | 146 | /* Probe */ | |
147 | static int | 147 | static int | |
148 | url_match(device_t parent, cfdata_t match, void *aux) | 148 | url_match(device_t parent, cfdata_t match, void *aux) | |
149 | { | 149 | { | |
150 | struct usb_attach_arg *uaa = aux; | 150 | struct usb_attach_arg *uaa = aux; | |
151 | 151 | |||
152 | return url_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 152 | return url_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
153 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 153 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
154 | } | 154 | } | |
155 | /* Attach */ | 155 | /* Attach */ | |
156 | static void | 156 | static void | |
157 | url_attach(device_t parent, device_t self, void *aux) | 157 | url_attach(device_t parent, device_t self, void *aux) | |
158 | { | 158 | { | |
159 | USBNET_MII_DECL_DEFAULT(unm); | 159 | USBNET_MII_DECL_DEFAULT(unm); | |
160 | struct usbnet * const un = device_private(self); | 160 | struct usbnet * const un = device_private(self); | |
161 | struct usb_attach_arg *uaa = aux; | 161 | struct usb_attach_arg *uaa = aux; | |
162 | struct usbd_device *dev = uaa->uaa_device; | 162 | struct usbd_device *dev = uaa->uaa_device; | |
163 | struct usbd_interface *iface; | 163 | struct usbd_interface *iface; | |
164 | usbd_status err; | 164 | usbd_status err; | |
165 | usb_interface_descriptor_t *id; | 165 | usb_interface_descriptor_t *id; | |
166 | usb_endpoint_descriptor_t *ed; | 166 | usb_endpoint_descriptor_t *ed; | |
167 | char *devinfop; | 167 | char *devinfop; | |
168 | int i; | 168 | int i; | |
169 | 169 | |||
170 | aprint_naive("\n"); | 170 | aprint_naive("\n"); | |
171 | aprint_normal("\n"); | 171 | aprint_normal("\n"); | |
172 | devinfop = usbd_devinfo_alloc(dev, 0); | 172 | devinfop = usbd_devinfo_alloc(dev, 0); | |
173 | aprint_normal_dev(self, "%s\n", devinfop); | 173 | aprint_normal_dev(self, "%s\n", devinfop); | |
174 | usbd_devinfo_free(devinfop); | 174 | usbd_devinfo_free(devinfop); | |
175 | 175 | |||
176 | un->un_dev = self; | 176 | un->un_dev = self; | |
177 | un->un_udev = dev; | 177 | un->un_udev = dev; | |
178 | un->un_sc = un; | 178 | un->un_sc = un; | |
179 | un->un_ops = &url_ops; | 179 | un->un_ops = &url_ops; | |
180 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 180 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
181 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 181 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
182 | un->un_rx_list_cnt = URL_RX_LIST_CNT; | 182 | un->un_rx_list_cnt = URL_RX_LIST_CNT; | |
183 | un->un_tx_list_cnt = URL_TX_LIST_CNT; | 183 | un->un_tx_list_cnt = URL_TX_LIST_CNT; | |
184 | un->un_rx_bufsz = URL_BUFSZ; | 184 | un->un_rx_bufsz = URL_BUFSZ; | |
185 | un->un_tx_bufsz = URL_BUFSZ; | 185 | un->un_tx_bufsz = URL_BUFSZ; | |
186 | 186 | |||
187 | /* Move the device into the configured state. */ | 187 | /* Move the device into the configured state. */ | |
188 | err = usbd_set_config_no(dev, URL_CONFIG_NO, 1); | 188 | err = usbd_set_config_no(dev, URL_CONFIG_NO, 1); | |
189 | if (err) { | 189 | if (err) { | |
190 | aprint_error_dev(self, "failed to set configuration" | 190 | aprint_error_dev(self, "failed to set configuration" | |
191 | ", err=%s\n", usbd_errstr(err)); | 191 | ", err=%s\n", usbd_errstr(err)); | |
192 | return; | 192 | return; | |
193 | } | 193 | } | |
194 | 194 | |||
195 | /* get control interface */ | 195 | /* get control interface */ | |
196 | err = usbd_device2interface_handle(dev, URL_IFACE_INDEX, &iface); | 196 | err = usbd_device2interface_handle(dev, URL_IFACE_INDEX, &iface); | |
197 | if (err) { | 197 | if (err) { | |
198 | aprint_error_dev(self, "failed to get interface, err=%s\n", | 198 | aprint_error_dev(self, "failed to get interface, err=%s\n", | |
199 | usbd_errstr(err)); | 199 | usbd_errstr(err)); | |
200 | return; | 200 | return; | |
201 | } | 201 | } | |
202 | 202 | |||
203 | un->un_iface = iface; | 203 | un->un_iface = iface; | |
204 | un->un_flags = url_lookup(uaa->uaa_vendor, uaa->uaa_product)->url_flags; | 204 | un->un_flags = url_lookup(uaa->uaa_vendor, uaa->uaa_product)->url_flags; | |
205 | #if 0 | 205 | #if 0 | |
206 | if (un->un_flags & URL_EXT_PHY) { | 206 | if (un->un_flags & URL_EXT_PHY) { | |
207 | un->un_read_reg_cb = url_ext_mii_read_reg; | 207 | un->un_read_reg_cb = url_ext_mii_read_reg; | |
208 | un->un_write_reg_cb = url_ext_mii_write_reg; | 208 | un->un_write_reg_cb = url_ext_mii_write_reg; | |
209 | } | 209 | } | |
210 | #endif | 210 | #endif | |
211 | 211 | |||
212 | /* get interface descriptor */ | 212 | /* get interface descriptor */ | |
213 | id = usbd_get_interface_descriptor(un->un_iface); | 213 | id = usbd_get_interface_descriptor(un->un_iface); | |
214 | 214 | |||
215 | /* find endpoints */ | 215 | /* find endpoints */ | |
216 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = | 216 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = | |
217 | un->un_ed[USBNET_ENDPT_INTR] = 0; | 217 | un->un_ed[USBNET_ENDPT_INTR] = 0; | |
218 | for (i = 0; i < id->bNumEndpoints; i++) { | 218 | for (i = 0; i < id->bNumEndpoints; i++) { | |
219 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 219 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
220 | if (ed == NULL) { | 220 | if (ed == NULL) { | |
221 | aprint_error_dev(self, | 221 | aprint_error_dev(self, | |
222 | "couldn't get endpoint %d\n", i); | 222 | "couldn't get endpoint %d\n", i); | |
223 | return; | 223 | return; | |
224 | } | 224 | } | |
225 | if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | 225 | if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | |
226 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | 226 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | |
227 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 227 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
228 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | 228 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | |
229 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) | 229 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) | |
230 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 230 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
231 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT && | 231 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT && | |
232 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | 232 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | |
233 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 233 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
234 | } | 234 | } | |
235 | 235 | |||
236 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 236 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
237 | un->un_ed[USBNET_ENDPT_TX] == 0 || | 237 | un->un_ed[USBNET_ENDPT_TX] == 0 || | |
238 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | 238 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | |
239 | aprint_error_dev(self, "missing endpoint\n"); | 239 | aprint_error_dev(self, "missing endpoint\n"); | |
240 | return; | 240 | return; | |
241 | } | 241 | } | |
242 | 242 | |||
243 | /* Set these up now for url_mem(). */ | 243 | /* Set these up now for url_mem(). */ | |
244 | usbnet_attach(un, "urldet"); | 244 | usbnet_attach(un, "urldet"); | |
245 | 245 | |||
246 | usbnet_lock_core(un); | 246 | usbnet_lock_core(un); | |
247 | usbnet_busy(un); | 247 | usbnet_busy(un); | |
248 | 248 | |||
249 | /* reset the adapter */ | 249 | /* reset the adapter */ | |
250 | url_reset(un); | 250 | url_reset(un); | |
251 | 251 | |||
252 | /* Get Ethernet Address */ | 252 | /* Get Ethernet Address */ | |
253 | err = url_mem(un, URL_CMD_READMEM, URL_IDR0, (void *)un->un_eaddr, | 253 | err = url_mem(un, URL_CMD_READMEM, URL_IDR0, (void *)un->un_eaddr, | |
254 | ETHER_ADDR_LEN); | 254 | ETHER_ADDR_LEN); | |
255 | usbnet_unbusy(un); | 255 | usbnet_unbusy(un); | |
256 | usbnet_unlock_core(un); | 256 | usbnet_unlock_core(un); | |
257 | if (err) { | 257 | if (err) { | |
258 | aprint_error_dev(self, "read MAC address failed\n"); | 258 | aprint_error_dev(self, "read MAC address failed\n"); | |
259 | return; | 259 | return; | |
260 | } | 260 | } | |
261 | 261 | |||
262 | /* initialize interface information */ | 262 | /* initialize interface information */ | |
263 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 263 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
264 | 0, &unm); | 264 | 0, &unm); | |
265 | } | 265 | } | |
266 | 266 | |||
267 | /* read/write memory */ | 267 | /* read/write memory */ | |
268 | static int | 268 | static int | |
269 | url_mem(struct usbnet *un, int cmd, int offset, void *buf, int len) | 269 | url_mem(struct usbnet *un, int cmd, int offset, void *buf, int len) | |
270 | { | 270 | { | |
271 | usb_device_request_t req; | 271 | usb_device_request_t req; | |
272 | usbd_status err; | 272 | usbd_status err; | |
273 | 273 | |||
274 | usbnet_isowned_core(un); | 274 | usbnet_isowned_core(un); | |
275 | 275 | |||
276 | DPRINTFN(0x200, | 276 | DPRINTFN(0x200, | |
277 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 277 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
278 | 278 | |||
279 | if (usbnet_isdying(un)) | 279 | if (usbnet_isdying(un)) | |
280 | return 0; | 280 | return 0; | |
281 | 281 | |||
282 | if (cmd == URL_CMD_READMEM) | 282 | if (cmd == URL_CMD_READMEM) | |
283 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 283 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
284 | else | 284 | else | |
285 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 285 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
286 | req.bRequest = URL_REQ_MEM; | 286 | req.bRequest = URL_REQ_MEM; | |
287 | USETW(req.wValue, offset); | 287 | USETW(req.wValue, offset); | |
288 | USETW(req.wIndex, 0x0000); | 288 | USETW(req.wIndex, 0x0000); | |
289 | USETW(req.wLength, len); | 289 | USETW(req.wLength, len); | |
290 | 290 | |||
291 | err = usbd_do_request(un->un_udev, &req, buf); | 291 | err = usbd_do_request(un->un_udev, &req, buf); | |
292 | if (err) { | 292 | if (err) { | |
293 | DPRINTF(("%s: url_mem(): %s failed. off=%04x, err=%d\n", | 293 | DPRINTF(("%s: url_mem(): %s failed. off=%04x, err=%d\n", | |
294 | device_xname(un->un_dev), | 294 | device_xname(un->un_dev), | |
295 | cmd == URL_CMD_READMEM ? "read" : "write", | 295 | cmd == URL_CMD_READMEM ? "read" : "write", | |
296 | offset, err)); | 296 | offset, err)); | |
297 | } | 297 | } | |
298 | 298 | |||
299 | return err; | 299 | return err; | |
300 | } | 300 | } | |
301 | 301 | |||
302 | /* read 1byte from register */ | 302 | /* read 1byte from register */ | |
303 | static int | 303 | static int | |
304 | url_csr_read_1(struct usbnet *un, int reg) | 304 | url_csr_read_1(struct usbnet *un, int reg) | |
305 | { | 305 | { | |
306 | uint8_t val = 0; | 306 | uint8_t val = 0; | |
307 | 307 | |||
308 | DPRINTFN(0x100, | 308 | DPRINTFN(0x100, | |
309 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 309 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
310 | 310 | |||
311 | return url_mem(un, URL_CMD_READMEM, reg, &val, 1) ? 0 : val; | 311 | return url_mem(un, URL_CMD_READMEM, reg, &val, 1) ? 0 : val; | |
312 | } | 312 | } | |
313 | 313 | |||
314 | /* read 2bytes from register */ | 314 | /* read 2bytes from register */ | |
315 | static int | 315 | static int | |
316 | url_csr_read_2(struct usbnet *un, int reg) | 316 | url_csr_read_2(struct usbnet *un, int reg) | |
317 | { | 317 | { | |
318 | uWord val; | 318 | uWord val; | |
319 | 319 | |||
320 | DPRINTFN(0x100, | 320 | DPRINTFN(0x100, | |
321 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 321 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
322 | 322 | |||
323 | USETW(val, 0); | 323 | USETW(val, 0); | |
324 | return url_mem(un, URL_CMD_READMEM, reg, &val, 2) ? 0 : UGETW(val); | 324 | return url_mem(un, URL_CMD_READMEM, reg, &val, 2) ? 0 : UGETW(val); | |
325 | } | 325 | } | |
326 | 326 | |||
327 | /* write 1byte to register */ | 327 | /* write 1byte to register */ | |
328 | static int | 328 | static int | |
329 | url_csr_write_1(struct usbnet *un, int reg, int aval) | 329 | url_csr_write_1(struct usbnet *un, int reg, int aval) | |
330 | { | 330 | { | |
331 | uint8_t val = aval; | 331 | uint8_t val = aval; | |
332 | 332 | |||
333 | DPRINTFN(0x100, | 333 | DPRINTFN(0x100, | |
334 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 334 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
335 | 335 | |||
336 | return url_mem(un, URL_CMD_WRITEMEM, reg, &val, 1) ? -1 : 0; | 336 | return url_mem(un, URL_CMD_WRITEMEM, reg, &val, 1) ? -1 : 0; | |
337 | } | 337 | } | |
338 | 338 | |||
339 | /* write 2bytes to register */ | 339 | /* write 2bytes to register */ | |
340 | static int | 340 | static int | |
341 | url_csr_write_2(struct usbnet *un, int reg, int aval) | 341 | url_csr_write_2(struct usbnet *un, int reg, int aval) | |
342 | { | 342 | { | |
343 | uWord val; | 343 | uWord val; | |
344 | 344 | |||
345 | DPRINTFN(0x100, | 345 | DPRINTFN(0x100, | |
346 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 346 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
347 | 347 | |||
348 | USETW(val, aval); | 348 | USETW(val, aval); | |
349 | 349 | |||
350 | return url_mem(un, URL_CMD_WRITEMEM, reg, &val, 2) ? -1 : 0; | 350 | return url_mem(un, URL_CMD_WRITEMEM, reg, &val, 2) ? -1 : 0; | |
351 | } | 351 | } | |
352 | 352 | |||
353 | /* write 4bytes to register */ | 353 | /* write 4bytes to register */ | |
354 | static int | 354 | static int | |
355 | url_csr_write_4(struct usbnet *un, int reg, int aval) | 355 | url_csr_write_4(struct usbnet *un, int reg, int aval) | |
356 | { | 356 | { | |
357 | uDWord val; | 357 | uDWord val; | |
358 | 358 | |||
359 | DPRINTFN(0x100, | 359 | DPRINTFN(0x100, | |
360 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 360 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
361 | 361 | |||
362 | USETDW(val, aval); | 362 | USETDW(val, aval); | |
363 | 363 | |||
364 | return url_mem(un, URL_CMD_WRITEMEM, reg, &val, 4) ? -1 : 0; | 364 | return url_mem(un, URL_CMD_WRITEMEM, reg, &val, 4) ? -1 : 0; | |
365 | } | 365 | } | |
366 | 366 | |||
367 | static int | 367 | static int | |
368 | url_init_locked(struct ifnet *ifp) | 368 | url_init_locked(struct ifnet *ifp) | |
369 | { | 369 | { | |
370 | struct usbnet * const un = ifp->if_softc; | 370 | struct usbnet * const un = ifp->if_softc; | |
371 | const u_char *eaddr; | 371 | const u_char *eaddr; | |
372 | int i; | 372 | int i; | |
373 | 373 | |||
374 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 374 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
375 | 375 | |||
376 | usbnet_isowned_core(un); | 376 | usbnet_isowned_core(un); | |
377 | 377 | |||
378 | if (usbnet_isdying(un)) | 378 | if (usbnet_isdying(un)) | |
379 | return EIO; | 379 | return EIO; | |
380 | 380 | |||
381 | /* Cancel pending I/O and free all TX/RX buffers */ | 381 | /* Cancel pending I/O and free all TX/RX buffers */ | |
382 | usbnet_stop(un, ifp, 1); | 382 | usbnet_stop(un, ifp, 1); | |
383 | 383 | |||
384 | eaddr = CLLADDR(ifp->if_sadl); | 384 | eaddr = CLLADDR(ifp->if_sadl); | |
385 | for (i = 0; i < ETHER_ADDR_LEN; i++) | 385 | for (i = 0; i < ETHER_ADDR_LEN; i++) | |
386 | url_csr_write_1(un, URL_IDR0 + i, eaddr[i]); | 386 | url_csr_write_1(un, URL_IDR0 + i, eaddr[i]); | |
387 | 387 | |||
388 | /* Init transmission control register */ | 388 | /* Init transmission control register */ | |
389 | URL_CLRBIT(un, URL_TCR, | 389 | URL_CLRBIT(un, URL_TCR, | |
390 | URL_TCR_TXRR1 | URL_TCR_TXRR0 | | 390 | URL_TCR_TXRR1 | URL_TCR_TXRR0 | | |
391 | URL_TCR_IFG1 | URL_TCR_IFG0 | | 391 | URL_TCR_IFG1 | URL_TCR_IFG0 | | |
392 | URL_TCR_NOCRC); | 392 | URL_TCR_NOCRC); | |
393 | 393 | |||
394 | /* Init receive control register */ | 394 | /* Init receive control register */ | |
395 | URL_SETBIT2(un, URL_RCR, URL_RCR_TAIL | URL_RCR_AD | URL_RCR_AB); | 395 | URL_SETBIT2(un, URL_RCR, URL_RCR_TAIL | URL_RCR_AD | URL_RCR_AB); | |
396 | 396 | |||
397 | /* Accept multicast frame or run promisc. mode */ | 397 | /* Accept multicast frame or run promisc. mode */ | |
398 | url_rcvfilt_locked(un); | 398 | url_rcvfilt_locked(un); | |
399 | 399 | |||
400 | /* Enable RX and TX */ | 400 | /* Enable RX and TX */ | |
401 | URL_SETBIT(un, URL_CR, URL_CR_TE | URL_CR_RE); | 401 | URL_SETBIT(un, URL_CR, URL_CR_TE | URL_CR_RE); | |
402 | 402 | |||
403 | return usbnet_init_rx_tx(un); | 403 | return usbnet_init_rx_tx(un); | |
404 | } | 404 | } | |
405 | 405 | |||
406 | static int | 406 | static int | |
407 | url_uno_init(struct ifnet *ifp) | 407 | url_uno_init(struct ifnet *ifp) | |
408 | { | 408 | { | |
409 | int ret = url_init_locked(ifp); | 409 | int ret = url_init_locked(ifp); | |
410 | 410 | |||
411 | return ret; | 411 | return ret; | |
412 | } | 412 | } | |
413 | 413 | |||
414 | static void | 414 | static void | |
415 | url_reset(struct usbnet *un) | 415 | url_reset(struct usbnet *un) | |
416 | { | 416 | { | |
417 | int i; | 417 | int i; | |
418 | 418 | |||
419 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 419 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
420 | 420 | |||
421 | if (usbnet_isdying(un)) | 421 | if (usbnet_isdying(un)) | |
422 | return; | 422 | return; | |
423 | 423 | |||
424 | URL_SETBIT(un, URL_CR, URL_CR_SOFT_RST); | 424 | URL_SETBIT(un, URL_CR, URL_CR_SOFT_RST); | |
425 | 425 | |||
426 | for (i = 0; i < URL_TX_TIMEOUT; i++) { | 426 | for (i = 0; i < URL_TX_TIMEOUT; i++) { | |
427 | if (usbnet_isdying(un)) | 427 | if (usbnet_isdying(un)) | |
428 | return; | 428 | return; | |
429 | if (!(url_csr_read_1(un, URL_CR) & URL_CR_SOFT_RST)) | 429 | if (!(url_csr_read_1(un, URL_CR) & URL_CR_SOFT_RST)) | |
430 | break; | 430 | break; | |
431 | delay(10); /* XXX */ | 431 | delay(10); /* XXX */ | |
432 | } | 432 | } | |
433 | 433 | |||
434 | delay(10000); /* XXX */ | 434 | delay(10000); /* XXX */ | |
435 | } | 435 | } | |
436 | 436 | |||
437 | static void | 437 | static void | |
438 | url_rcvfilt_locked(struct usbnet *un) | 438 | url_rcvfilt_locked(struct usbnet *un) | |
439 | { | 439 | { | |
440 | struct ifnet * const ifp = usbnet_ifp(un); | 440 | struct ifnet * const ifp = usbnet_ifp(un); | |
441 | struct ethercom *ec = usbnet_ec(un); | 441 | struct ethercom *ec = usbnet_ec(un); | |
442 | struct ether_multi *enm; | 442 | struct ether_multi *enm; | |
443 | struct ether_multistep step; | 443 | struct ether_multistep step; | |
444 | uint32_t mchash[2] = { 0, 0 }; | 444 | uint32_t mchash[2] = { 0, 0 }; | |
445 | int h = 0, rcr; | 445 | int h = 0, rcr; | |
446 | 446 | |||
447 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 447 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
448 | 448 | |||
449 | usbnet_isowned_core(un); | 449 | usbnet_isowned_core(un); | |
450 | 450 | |||
451 | if (usbnet_isdying(un)) | 451 | if (usbnet_isdying(un)) | |
452 | return; | 452 | return; | |
453 | 453 | |||
454 | rcr = url_csr_read_2(un, URL_RCR); | 454 | rcr = url_csr_read_2(un, URL_RCR); | |
455 | rcr &= ~(URL_RCR_AAP | URL_RCR_AAM | URL_RCR_AM); | 455 | rcr &= ~(URL_RCR_AAP | URL_RCR_AAM | URL_RCR_AM); | |
456 | 456 | |||
457 | ETHER_LOCK(ec); | 457 | ETHER_LOCK(ec); | |
458 | if (ifp->if_flags & IFF_PROMISC) { | 458 | if (ifp->if_flags & IFF_PROMISC) { | |
459 | ec->ec_flags |= ETHER_F_ALLMULTI; | 459 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
460 | ETHER_UNLOCK(ec); | 460 | ETHER_UNLOCK(ec); | |
461 | /* run promisc. mode */ | 461 | /* run promisc. mode */ | |
462 | rcr |= URL_RCR_AAM; /* ??? */ | 462 | rcr |= URL_RCR_AAM; /* ??? */ | |
463 | rcr |= URL_RCR_AAP; | 463 | rcr |= URL_RCR_AAP; | |
464 | goto update; | 464 | goto update; | |
465 | } | 465 | } | |
466 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 466 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
467 | ETHER_FIRST_MULTI(step, ec, enm); | 467 | ETHER_FIRST_MULTI(step, ec, enm); | |
468 | while (enm != NULL) { | 468 | while (enm != NULL) { | |
469 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 469 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
470 | ec->ec_flags |= ETHER_F_ALLMULTI; | 470 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
471 | ETHER_UNLOCK(ec); | 471 | ETHER_UNLOCK(ec); | |
472 | /* accept all multicast frames */ | 472 | /* accept all multicast frames */ | |
473 | rcr |= URL_RCR_AAM; | 473 | rcr |= URL_RCR_AAM; | |
474 | goto update; | 474 | goto update; | |
475 | } | 475 | } | |
476 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | 476 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | |
477 | /* 1(31) and 5(30:26) bit sampling */ | 477 | /* 1(31) and 5(30:26) bit sampling */ | |
478 | mchash[h >> 31] |= 1 << ((h >> 26) & 0x1f); | 478 | mchash[h >> 31] |= 1 << ((h >> 26) & 0x1f); | |
479 | ETHER_NEXT_MULTI(step, enm); | 479 | ETHER_NEXT_MULTI(step, enm); | |
480 | } | 480 | } | |
481 | ETHER_UNLOCK(ec); | 481 | ETHER_UNLOCK(ec); | |
482 | if (h != 0) | 482 | if (h != 0) | |
483 | rcr |= URL_RCR_AM; /* activate mcast hash filter */ | 483 | rcr |= URL_RCR_AM; /* activate mcast hash filter */ | |
484 | url_csr_write_4(un, URL_MAR0, mchash[0]); | 484 | url_csr_write_4(un, URL_MAR0, mchash[0]); | |
485 | url_csr_write_4(un, URL_MAR4, mchash[1]); | 485 | url_csr_write_4(un, URL_MAR4, mchash[1]); | |
486 | update: | 486 | update: | |
487 | url_csr_write_2(un, URL_RCR, rcr); | 487 | url_csr_write_2(un, URL_RCR, rcr); | |
488 | } | 488 | } | |
489 | 489 | |||
490 | static unsigned | 490 | static unsigned | |
491 | url_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 491 | url_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
492 | { | 492 | { | |
493 | int total_len; | 493 | int total_len; | |
494 | 494 | |||
495 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | 495 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | |
496 | 496 | |||
497 | KASSERT(un->un_tx_bufsz >= URL_MIN_FRAME_LEN); | 497 | KASSERT(un->un_tx_bufsz >= URL_MIN_FRAME_LEN); | |
498 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | 498 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | |
499 | return 0; | 499 | return 0; | |
500 | 500 | |||
501 | /* Copy the mbuf data into a contiguous buffer */ | 501 | /* Copy the mbuf data into a contiguous buffer */ | |
502 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | 502 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | |
503 | total_len = m->m_pkthdr.len; | 503 | total_len = m->m_pkthdr.len; | |
504 | 504 | |||
505 | if (total_len < URL_MIN_FRAME_LEN) { | 505 | if (total_len < URL_MIN_FRAME_LEN) { | |
506 | memset(c->unc_buf + total_len, 0, | 506 | memset(c->unc_buf + total_len, 0, | |
507 | URL_MIN_FRAME_LEN - total_len); | 507 | URL_MIN_FRAME_LEN - total_len); | |
508 | total_len = URL_MIN_FRAME_LEN; | 508 | total_len = URL_MIN_FRAME_LEN; | |
509 | } | 509 | } | |
510 | 510 | |||
511 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | 511 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | |
512 | __func__, total_len)); | 512 | __func__, total_len)); | |
513 | 513 | |||
514 | return total_len; | 514 | return total_len; | |
515 | } | 515 | } | |
516 | 516 | |||
517 | static void | 517 | static void | |
518 | url_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 518 | url_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
519 | { | 519 | { | |
520 | struct ifnet *ifp = usbnet_ifp(un); | 520 | struct ifnet *ifp = usbnet_ifp(un); | |
521 | url_rxhdr_t rxhdr; | 521 | url_rxhdr_t rxhdr; | |
522 | 522 | |||
523 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | 523 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | |
524 | 524 | |||
525 | if (total_len <= ETHER_CRC_LEN || total_len <= sizeof(rxhdr)) { | 525 | if (total_len <= ETHER_CRC_LEN || total_len <= sizeof(rxhdr)) { | |
526 | if_statinc(ifp, if_ierrors); | 526 | if_statinc(ifp, if_ierrors); | |
527 | return; | 527 | return; | |
528 | } | 528 | } | |
529 | 529 | |||
530 | memcpy(&rxhdr, c->unc_buf + total_len - ETHER_CRC_LEN, sizeof(rxhdr)); | 530 | memcpy(&rxhdr, c->unc_buf + total_len - ETHER_CRC_LEN, sizeof(rxhdr)); | |
531 | 531 | |||
532 | DPRINTF(("%s: RX Status: %dbytes%s%s%s%s packets\n", | 532 | DPRINTF(("%s: RX Status: %dbytes%s%s%s%s packets\n", | |
533 | device_xname(un->un_dev), | 533 | device_xname(un->un_dev), | |
534 | UGETW(rxhdr) & URL_RXHDR_BYTEC_MASK, | 534 | UGETW(rxhdr) & URL_RXHDR_BYTEC_MASK, | |
535 | UGETW(rxhdr) & URL_RXHDR_VALID_MASK ? ", Valid" : "", | 535 | UGETW(rxhdr) & URL_RXHDR_VALID_MASK ? ", Valid" : "", | |
536 | UGETW(rxhdr) & URL_RXHDR_RUNTPKT_MASK ? ", Runt" : "", | 536 | UGETW(rxhdr) & URL_RXHDR_RUNTPKT_MASK ? ", Runt" : "", | |
537 | UGETW(rxhdr) & URL_RXHDR_PHYPKT_MASK ? ", Physical match" : "", | 537 | UGETW(rxhdr) & URL_RXHDR_PHYPKT_MASK ? ", Physical match" : "", | |
538 | UGETW(rxhdr) & URL_RXHDR_MCASTPKT_MASK ? ", Multicast" : "")); | 538 | UGETW(rxhdr) & URL_RXHDR_MCASTPKT_MASK ? ", Multicast" : "")); | |
539 | 539 | |||
540 | if ((UGETW(rxhdr) & URL_RXHDR_VALID_MASK) == 0) { | 540 | if ((UGETW(rxhdr) & URL_RXHDR_VALID_MASK) == 0) { | |
541 | if_statinc(ifp, if_ierrors); | 541 | if_statinc(ifp, if_ierrors); | |
542 | return; | 542 | return; | |
543 | } | 543 | } | |
544 | 544 | |||
545 | total_len -= ETHER_CRC_LEN; | 545 | total_len -= ETHER_CRC_LEN; | |
546 | 546 | |||
547 | DPRINTF(("%s: %s: deliver %d\n", device_xname(un->un_dev), | 547 | DPRINTF(("%s: %s: deliver %d\n", device_xname(un->un_dev), | |
548 | __func__, total_len)); | 548 | __func__, total_len)); | |
549 | usbnet_enqueue(un, c->unc_buf, total_len, 0, 0, 0); | 549 | usbnet_enqueue(un, c->unc_buf, total_len, 0, 0, 0); | |
550 | } | 550 | } | |
551 | 551 | |||
552 | #if 0 | 552 | #if 0 | |
553 | static void url_intr(void) | 553 | static void url_intr(void) | |
554 | { | 554 | { | |
555 | } | 555 | } | |
556 | #endif | 556 | #endif | |
557 | 557 | |||
558 | static void | 558 | static void | |
559 | url_uno_mcast(struct ifnet *ifp) | 559 | url_uno_mcast(struct ifnet *ifp) | |
560 | { | 560 | { | |
561 | struct usbnet * const un = ifp->if_softc; | 561 | struct usbnet * const un = ifp->if_softc; | |
562 | 562 | |||
563 | usbnet_lock_core(un); | 563 | usbnet_lock_core(un); | |
564 | usbnet_busy(un); | |||
565 | 564 | |||
566 | url_rcvfilt_locked(un); | 565 | url_rcvfilt_locked(un); | |
567 | 566 | |||
568 | usbnet_unbusy(un); | |||
569 | usbnet_unlock_core(un); | 567 | usbnet_unlock_core(un); | |
570 | } | 568 | } | |
571 | 569 | |||
572 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | 570 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | |
573 | static void | 571 | static void | |
574 | url_uno_stop(struct ifnet *ifp, int disable) | 572 | url_uno_stop(struct ifnet *ifp, int disable) | |
575 | { | 573 | { | |
576 | struct usbnet * const un = ifp->if_softc; | 574 | struct usbnet * const un = ifp->if_softc; | |
577 | 575 | |||
578 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 576 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
579 | 577 | |||
580 | url_reset(un); | 578 | url_reset(un); | |
581 | } | 579 | } | |
582 | 580 | |||
583 | static int | 581 | static int | |
584 | url_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 582 | url_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
585 | { | 583 | { | |
586 | uint16_t data; | 584 | uint16_t data; | |
587 | usbd_status err = USBD_NORMAL_COMPLETION; | 585 | usbd_status err = USBD_NORMAL_COMPLETION; | |
588 | 586 | |||
589 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | 587 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | |
590 | device_xname(un->un_dev), __func__, phy, reg)); | 588 | device_xname(un->un_dev), __func__, phy, reg)); | |
591 | 589 | |||
592 | /* XXX: one PHY only for the RTL8150 internal PHY */ | 590 | /* XXX: one PHY only for the RTL8150 internal PHY */ | |
593 | if (phy != 0) { | 591 | if (phy != 0) { | |
594 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 592 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
595 | device_xname(un->un_dev), __func__, phy)); | 593 | device_xname(un->un_dev), __func__, phy)); | |
596 | return EINVAL; | 594 | return EINVAL; | |
597 | } | 595 | } | |
598 | 596 | |||
599 | switch (reg) { | 597 | switch (reg) { | |
600 | case MII_BMCR: /* Control Register */ | 598 | case MII_BMCR: /* Control Register */ | |
601 | reg = URL_BMCR; | 599 | reg = URL_BMCR; | |
602 | break; | 600 | break; | |
603 | case MII_BMSR: /* Status Register */ | 601 | case MII_BMSR: /* Status Register */ | |
604 | reg = URL_BMSR; | 602 | reg = URL_BMSR; | |
605 | break; | 603 | break; | |
606 | case MII_PHYIDR1: | 604 | case MII_PHYIDR1: | |
607 | case MII_PHYIDR2: | 605 | case MII_PHYIDR2: | |
608 | *val = 0; | 606 | *val = 0; | |
609 | goto R_DONE; | 607 | goto R_DONE; | |
610 | break; | 608 | break; | |
611 | case MII_ANAR: /* Autonegotiation advertisement */ | 609 | case MII_ANAR: /* Autonegotiation advertisement */ | |
612 | reg = URL_ANAR; | 610 | reg = URL_ANAR; | |
613 | break; | 611 | break; | |
614 | case MII_ANLPAR: /* Autonegotiation link partner abilities */ | 612 | case MII_ANLPAR: /* Autonegotiation link partner abilities */ | |
615 | reg = URL_ANLP; | 613 | reg = URL_ANLP; | |
616 | break; | 614 | break; | |
617 | case URLPHY_MSR: /* Media Status Register */ | 615 | case URLPHY_MSR: /* Media Status Register */ | |
618 | reg = URL_MSR; | 616 | reg = URL_MSR; | |
619 | break; | 617 | break; | |
620 | default: | 618 | default: | |
621 | printf("%s: %s: bad register %04x\n", | 619 | printf("%s: %s: bad register %04x\n", | |
622 | device_xname(un->un_dev), __func__, reg); | 620 | device_xname(un->un_dev), __func__, reg); | |
623 | return EINVAL; | 621 | return EINVAL; | |
624 | } | 622 | } | |
625 | 623 | |||
626 | if (reg == URL_MSR) | 624 | if (reg == URL_MSR) | |
627 | data = url_csr_read_1(un, reg); | 625 | data = url_csr_read_1(un, reg); | |
628 | else | 626 | else | |
629 | data = url_csr_read_2(un, reg); | 627 | data = url_csr_read_2(un, reg); | |
630 | *val = data; | 628 | *val = data; | |
631 | 629 | |||
632 | R_DONE: | 630 | R_DONE: | |
633 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | 631 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | |
634 | device_xname(un->un_dev), __func__, phy, reg, *val)); | 632 | device_xname(un->un_dev), __func__, phy, reg, *val)); | |
635 | 633 | |||
636 | return err; | 634 | return err; | |
637 | } | 635 | } | |
638 | 636 | |||
639 | static int | 637 | static int | |
640 | url_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 638 | url_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
641 | { | 639 | { | |
642 | 640 | |||
643 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | 641 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | |
644 | device_xname(un->un_dev), __func__, phy, reg, val)); | 642 | device_xname(un->un_dev), __func__, phy, reg, val)); | |
645 | 643 | |||
646 | /* XXX: one PHY only for the RTL8150 internal PHY */ | 644 | /* XXX: one PHY only for the RTL8150 internal PHY */ | |
647 | if (phy != 0) { | 645 | if (phy != 0) { | |
648 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 646 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
649 | device_xname(un->un_dev), __func__, phy)); | 647 | device_xname(un->un_dev), __func__, phy)); | |
650 | return EINVAL; | 648 | return EINVAL; | |
651 | } | 649 | } | |
652 | 650 | |||
653 | switch (reg) { | 651 | switch (reg) { | |
654 | case MII_BMCR: /* Control Register */ | 652 | case MII_BMCR: /* Control Register */ | |
655 | reg = URL_BMCR; | 653 | reg = URL_BMCR; | |
656 | break; | 654 | break; | |
657 | case MII_BMSR: /* Status Register */ | 655 | case MII_BMSR: /* Status Register */ | |
658 | reg = URL_BMSR; | 656 | reg = URL_BMSR; | |
659 | break; | 657 | break; | |
660 | case MII_PHYIDR1: | 658 | case MII_PHYIDR1: | |
661 | case MII_PHYIDR2: | 659 | case MII_PHYIDR2: | |
662 | return 0; | 660 | return 0; | |
663 | case MII_ANAR: /* Autonegotiation advertisement */ | 661 | case MII_ANAR: /* Autonegotiation advertisement */ | |
664 | reg = URL_ANAR; | 662 | reg = URL_ANAR; | |
665 | break; | 663 | break; | |
666 | case MII_ANLPAR: /* Autonegotiation link partner abilities */ | 664 | case MII_ANLPAR: /* Autonegotiation link partner abilities */ | |
667 | reg = URL_ANLP; | 665 | reg = URL_ANLP; | |
668 | break; | 666 | break; | |
669 | case URLPHY_MSR: /* Media Status Register */ | 667 | case URLPHY_MSR: /* Media Status Register */ | |
670 | reg = URL_MSR; | 668 | reg = URL_MSR; | |
671 | break; | 669 | break; | |
672 | default: | 670 | default: | |
673 | printf("%s: %s: bad register %04x\n", | 671 | printf("%s: %s: bad register %04x\n", | |
674 | device_xname(un->un_dev), __func__, reg); | 672 | device_xname(un->un_dev), __func__, reg); | |
675 | return EINVAL; | 673 | return EINVAL; | |
676 | } | 674 | } | |
677 | 675 | |||
678 | if (reg == URL_MSR) | 676 | if (reg == URL_MSR) | |
679 | url_csr_write_1(un, reg, val); | 677 | url_csr_write_1(un, reg, val); | |
680 | else | 678 | else | |
681 | url_csr_write_2(un, reg, val); | 679 | url_csr_write_2(un, reg, val); | |
682 | 680 | |||
683 | return 0; | 681 | return 0; | |
684 | } | 682 | } | |
685 | 683 | |||
686 | static void | 684 | static void | |
687 | url_uno_mii_statchg(struct ifnet *ifp) | 685 | url_uno_mii_statchg(struct ifnet *ifp) | |
688 | { | 686 | { | |
689 | struct usbnet * const un = ifp->if_softc; | 687 | struct usbnet * const un = ifp->if_softc; | |
690 | 688 | |||
691 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | 689 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | |
692 | 690 | |||
693 | /* XXX */ | 691 | /* XXX */ | |
694 | usbnet_set_link(un, true); | 692 | usbnet_set_link(un, true); | |
695 | } | 693 | } | |
696 | 694 | |||
697 | #if 0 | 695 | #if 0 | |
698 | /* | 696 | /* | |
699 | * external PHYs support, but not test. | 697 | * external PHYs support, but not test. | |
700 | */ | 698 | */ | |
701 | static usbd_status | 699 | static usbd_status | |
702 | url_ext_mii_read_reg(struct usbnet *un, int phy, int reg) | 700 | url_ext_mii_read_reg(struct usbnet *un, int phy, int reg) | |
703 | { | 701 | { | |
704 | uint16_t val; | 702 | uint16_t val; | |
705 | 703 | |||
706 | DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x\n", | 704 | DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x\n", | |
707 | device_xname(un->un_dev), __func__, phy, reg)); | 705 | device_xname(un->un_dev), __func__, phy, reg)); | |
708 | 706 | |||
709 | url_csr_write_1(un, URL_PHYADD, phy & URL_PHYADD_MASK); | 707 | url_csr_write_1(un, URL_PHYADD, phy & URL_PHYADD_MASK); | |
710 | /* | 708 | /* | |
711 | * RTL8150L will initiate a MII management data transaction | 709 | * RTL8150L will initiate a MII management data transaction | |
712 | * if PHYCNT_OWN bit is set 1 by software. After transaction, | 710 | * if PHYCNT_OWN bit is set 1 by software. After transaction, | |
713 | * this bit is auto cleared by TRL8150L. | 711 | * this bit is auto cleared by TRL8150L. | |
714 | */ | 712 | */ | |
715 | url_csr_write_1(un, URL_PHYCNT, | 713 | url_csr_write_1(un, URL_PHYCNT, | |
716 | (reg | URL_PHYCNT_PHYOWN) & ~URL_PHYCNT_RWCR); | 714 | (reg | URL_PHYCNT_PHYOWN) & ~URL_PHYCNT_RWCR); | |
717 | for (i = 0; i < URL_TIMEOUT; i++) { | 715 | for (i = 0; i < URL_TIMEOUT; i++) { | |
718 | if ((url_csr_read_1(un, URL_PHYCNT) & URL_PHYCNT_PHYOWN) == 0) | 716 | if ((url_csr_read_1(un, URL_PHYCNT) & URL_PHYCNT_PHYOWN) == 0) | |
719 | break; | 717 | break; | |
720 | } | 718 | } | |
721 | if (i == URL_TIMEOUT) { | 719 | if (i == URL_TIMEOUT) { | |
722 | printf("%s: MII read timed out\n", device_xname(un->un_dev)); | 720 | printf("%s: MII read timed out\n", device_xname(un->un_dev)); | |
723 | } | 721 | } | |
724 | 722 | |||
725 | val = url_csr_read_2(un, URL_PHYDAT); | 723 | val = url_csr_read_2(un, URL_PHYDAT); | |
726 | 724 | |||
727 | DPRINTF(("%s: %s: phy=%d reg=0x%04x => 0x%04x\n", | 725 | DPRINTF(("%s: %s: phy=%d reg=0x%04x => 0x%04x\n", | |
728 | device_xname(un->un_dev), __func__, phy, reg, val)); | 726 | device_xname(un->un_dev), __func__, phy, reg, val)); | |
729 | 727 | |||
730 | return USBD_NORMAL_COMPLETION; | 728 | return USBD_NORMAL_COMPLETION; | |
731 | } | 729 | } | |
732 | 730 | |||
733 | static usbd_status | 731 | static usbd_status | |
734 | url_ext_mii_write_reg(struct usbnet *un, int phy, int reg, int data) | 732 | url_ext_mii_write_reg(struct usbnet *un, int phy, int reg, int data) | |
735 | { | 733 | { | |
736 | 734 | |||
737 | DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n", | 735 | DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n", | |
738 | device_xname(un->un_dev), __func__, phy, reg, data)); | 736 | device_xname(un->un_dev), __func__, phy, reg, data)); | |
739 | 737 | |||
740 | url_csr_write_2(un, URL_PHYDAT, data); | 738 | url_csr_write_2(un, URL_PHYDAT, data); | |
741 | url_csr_write_1(un, URL_PHYADD, phy); | 739 | url_csr_write_1(un, URL_PHYADD, phy); | |
742 | url_csr_write_1(un, URL_PHYCNT, reg | URL_PHYCNT_RWCR); /* Write */ | 740 | url_csr_write_1(un, URL_PHYCNT, reg | URL_PHYCNT_RWCR); /* Write */ | |
743 | 741 | |||
744 | for (i=0; i < URL_TIMEOUT; i++) { | 742 | for (i=0; i < URL_TIMEOUT; i++) { | |
745 | if (url_csr_read_1(un, URL_PHYCNT) & URL_PHYCNT_PHYOWN) | 743 | if (url_csr_read_1(un, URL_PHYCNT) & URL_PHYCNT_PHYOWN) | |
746 | break; | 744 | break; | |
747 | } | 745 | } | |
748 | 746 | |||
749 | if (i == URL_TIMEOUT) { | 747 | if (i == URL_TIMEOUT) { | |
750 | printf("%s: MII write timed out\n", | 748 | printf("%s: MII write timed out\n", | |
751 | device_xname(un->un_dev)); | 749 | device_xname(un->un_dev)); | |
752 | return USBD_TIMEOUT; | 750 | return USBD_TIMEOUT; | |
753 | } | 751 | } | |
754 | 752 | |||
755 | return USBD_NORMAL_COMPLETION; | 753 | return USBD_NORMAL_COMPLETION; | |
756 | } | 754 | } | |
757 | #endif | 755 | #endif | |
758 | 756 | |||
759 | #ifdef _MODULE | 757 | #ifdef _MODULE | |
760 | #include "ioconf.c" | 758 | #include "ioconf.c" | |
761 | #endif | 759 | #endif | |
762 | 760 | |||
763 | USBNET_MODULE(url) | 761 | USBNET_MODULE(url) |
--- src/sys/dev/usb/if_ure.c 2022/03/03 05:51:17 1.44
+++ src/sys/dev/usb/if_ure.c 2022/03/03 05:51:27 1.45
@@ -1,1160 +1,1158 @@ | @@ -1,1160 +1,1158 @@ | |||
1 | /* $NetBSD: if_ure.c,v 1.44 2022/03/03 05:51:17 riastradh Exp $ */ | 1 | /* $NetBSD: if_ure.c,v 1.45 2022/03/03 05:51:27 riastradh Exp $ */ | |
2 | /* $OpenBSD: if_ure.c,v 1.10 2018/11/02 21:32:30 jcs Exp $ */ | 2 | /* $OpenBSD: if_ure.c,v 1.10 2018/11/02 21:32:30 jcs Exp $ */ | |
3 | 3 | |||
4 | /*- | 4 | /*- | |
5 | * Copyright (c) 2015-2016 Kevin Lo <kevlo@FreeBSD.org> | 5 | * Copyright (c) 2015-2016 Kevin Lo <kevlo@FreeBSD.org> | |
6 | * All rights reserved. | 6 | * All rights reserved. | |
7 | * | 7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | 8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions | 9 | * modification, are permitted provided that the following conditions | |
10 | * are met: | 10 | * are met: | |
11 | * 1. Redistributions of source code must retain the above copyright | 11 | * 1. Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | 12 | * notice, this list of conditions and the following disclaimer. | |
13 | * 2. Redistributions in binary form must reproduce the above copyright | 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in the | 14 | * notice, this list of conditions and the following disclaimer in the | |
15 | * documentation and/or other materials provided with the distribution. | 15 | * documentation and/or other materials provided with the distribution. | |
16 | * | 16 | * | |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
27 | * SUCH DAMAGE. | 27 | * SUCH DAMAGE. | |
28 | */ | 28 | */ | |
29 | 29 | |||
30 | /* RealTek RTL8152/RTL8153 10/100/Gigabit USB Ethernet device */ | 30 | /* RealTek RTL8152/RTL8153 10/100/Gigabit USB Ethernet device */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | __KERNEL_RCSID(0, "$NetBSD: if_ure.c,v 1.44 2022/03/03 05:51:17 riastradh Exp $"); | 33 | __KERNEL_RCSID(0, "$NetBSD: if_ure.c,v 1.45 2022/03/03 05:51:27 riastradh Exp $"); | |
34 | 34 | |||
35 | #ifdef _KERNEL_OPT | 35 | #ifdef _KERNEL_OPT | |
36 | #include "opt_usb.h" | 36 | #include "opt_usb.h" | |
37 | #include "opt_inet.h" | 37 | #include "opt_inet.h" | |
38 | #endif | 38 | #endif | |
39 | 39 | |||
40 | #include <sys/param.h> | 40 | #include <sys/param.h> | |
41 | #include <sys/cprng.h> | 41 | #include <sys/cprng.h> | |
42 | 42 | |||
43 | #include <net/route.h> | 43 | #include <net/route.h> | |
44 | 44 | |||
45 | #include <dev/usb/usbnet.h> | 45 | #include <dev/usb/usbnet.h> | |
46 | 46 | |||
47 | #include <netinet/in_offload.h> /* XXX for in_undefer_cksum() */ | 47 | #include <netinet/in_offload.h> /* XXX for in_undefer_cksum() */ | |
48 | #ifdef INET6 | 48 | #ifdef INET6 | |
49 | #include <netinet/in.h> | 49 | #include <netinet/in.h> | |
50 | #include <netinet6/in6_offload.h> /* XXX for in6_undefer_cksum() */ | 50 | #include <netinet6/in6_offload.h> /* XXX for in6_undefer_cksum() */ | |
51 | #endif | 51 | #endif | |
52 | 52 | |||
53 | #include <dev/ic/rtl81x9reg.h> /* XXX for RTK_GMEDIASTAT */ | 53 | #include <dev/ic/rtl81x9reg.h> /* XXX for RTK_GMEDIASTAT */ | |
54 | #include <dev/usb/if_urereg.h> | 54 | #include <dev/usb/if_urereg.h> | |
55 | #include <dev/usb/if_urevar.h> | 55 | #include <dev/usb/if_urevar.h> | |
56 | 56 | |||
57 | #define URE_PRINTF(un, fmt, args...) \ | 57 | #define URE_PRINTF(un, fmt, args...) \ | |
58 | device_printf((un)->un_dev, "%s: " fmt, __func__, ##args); | 58 | device_printf((un)->un_dev, "%s: " fmt, __func__, ##args); | |
59 | 59 | |||
60 | #define URE_DEBUG | 60 | #define URE_DEBUG | |
61 | #ifdef URE_DEBUG | 61 | #ifdef URE_DEBUG | |
62 | #define DPRINTF(x) do { if (uredebug) printf x; } while (0) | 62 | #define DPRINTF(x) do { if (uredebug) printf x; } while (0) | |
63 | #define DPRINTFN(n, x) do { if (uredebug >= (n)) printf x; } while (0) | 63 | #define DPRINTFN(n, x) do { if (uredebug >= (n)) printf x; } while (0) | |
64 | int uredebug = 0; | 64 | int uredebug = 0; | |
65 | #else | 65 | #else | |
66 | #define DPRINTF(x) | 66 | #define DPRINTF(x) | |
67 | #define DPRINTFN(n, x) | 67 | #define DPRINTFN(n, x) | |
68 | #endif | 68 | #endif | |
69 | 69 | |||
70 | #define ETHER_IS_ZERO(addr) \ | 70 | #define ETHER_IS_ZERO(addr) \ | |
71 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | 71 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | |
72 | 72 | |||
73 | static const struct usb_devno ure_devs[] = { | 73 | static const struct usb_devno ure_devs[] = { | |
74 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8152 }, | 74 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8152 }, | |
75 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8153 } | 75 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8153 } | |
76 | }; | 76 | }; | |
77 | 77 | |||
78 | #define URE_BUFSZ (16 * 1024) | 78 | #define URE_BUFSZ (16 * 1024) | |
79 | 79 | |||
80 | static void ure_reset(struct usbnet *); | 80 | static void ure_reset(struct usbnet *); | |
81 | static uint32_t ure_txcsum(struct mbuf *); | 81 | static uint32_t ure_txcsum(struct mbuf *); | |
82 | static int ure_rxcsum(struct ifnet *, struct ure_rxpkt *); | 82 | static int ure_rxcsum(struct ifnet *, struct ure_rxpkt *); | |
83 | static void ure_rtl8152_init(struct usbnet *); | 83 | static void ure_rtl8152_init(struct usbnet *); | |
84 | static void ure_rtl8153_init(struct usbnet *); | 84 | static void ure_rtl8153_init(struct usbnet *); | |
85 | static void ure_disable_teredo(struct usbnet *); | 85 | static void ure_disable_teredo(struct usbnet *); | |
86 | static void ure_init_fifo(struct usbnet *); | 86 | static void ure_init_fifo(struct usbnet *); | |
87 | 87 | |||
88 | static void ure_uno_stop(struct ifnet *, int); | 88 | static void ure_uno_stop(struct ifnet *, int); | |
89 | static void ure_uno_mcast(struct ifnet *); | 89 | static void ure_uno_mcast(struct ifnet *); | |
90 | static int ure_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 90 | static int ure_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
91 | static int ure_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 91 | static int ure_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
92 | static void ure_uno_miibus_statchg(struct ifnet *); | 92 | static void ure_uno_miibus_statchg(struct ifnet *); | |
93 | static unsigned ure_uno_tx_prepare(struct usbnet *, struct mbuf *, | 93 | static unsigned ure_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
94 | struct usbnet_chain *); | 94 | struct usbnet_chain *); | |
95 | static void ure_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 95 | static void ure_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
96 | uint32_t); | 96 | uint32_t); | |
97 | static int ure_uno_init(struct ifnet *); | 97 | static int ure_uno_init(struct ifnet *); | |
98 | 98 | |||
99 | static int ure_match(device_t, cfdata_t, void *); | 99 | static int ure_match(device_t, cfdata_t, void *); | |
100 | static void ure_attach(device_t, device_t, void *); | 100 | static void ure_attach(device_t, device_t, void *); | |
101 | 101 | |||
102 | CFATTACH_DECL_NEW(ure, sizeof(struct usbnet), ure_match, ure_attach, | 102 | CFATTACH_DECL_NEW(ure, sizeof(struct usbnet), ure_match, ure_attach, | |
103 | usbnet_detach, usbnet_activate); | 103 | usbnet_detach, usbnet_activate); | |
104 | 104 | |||
105 | static const struct usbnet_ops ure_ops = { | 105 | static const struct usbnet_ops ure_ops = { | |
106 | .uno_stop = ure_uno_stop, | 106 | .uno_stop = ure_uno_stop, | |
107 | .uno_mcast = ure_uno_mcast, | 107 | .uno_mcast = ure_uno_mcast, | |
108 | .uno_read_reg = ure_uno_mii_read_reg, | 108 | .uno_read_reg = ure_uno_mii_read_reg, | |
109 | .uno_write_reg = ure_uno_mii_write_reg, | 109 | .uno_write_reg = ure_uno_mii_write_reg, | |
110 | .uno_statchg = ure_uno_miibus_statchg, | 110 | .uno_statchg = ure_uno_miibus_statchg, | |
111 | .uno_tx_prepare = ure_uno_tx_prepare, | 111 | .uno_tx_prepare = ure_uno_tx_prepare, | |
112 | .uno_rx_loop = ure_uno_rx_loop, | 112 | .uno_rx_loop = ure_uno_rx_loop, | |
113 | .uno_init = ure_uno_init, | 113 | .uno_init = ure_uno_init, | |
114 | }; | 114 | }; | |
115 | 115 | |||
116 | static int | 116 | static int | |
117 | ure_ctl(struct usbnet *un, uint8_t rw, uint16_t val, uint16_t index, | 117 | ure_ctl(struct usbnet *un, uint8_t rw, uint16_t val, uint16_t index, | |
118 | void *buf, int len) | 118 | void *buf, int len) | |
119 | { | 119 | { | |
120 | usb_device_request_t req; | 120 | usb_device_request_t req; | |
121 | usbd_status err; | 121 | usbd_status err; | |
122 | 122 | |||
123 | if (usbnet_isdying(un)) | 123 | if (usbnet_isdying(un)) | |
124 | return 0; | 124 | return 0; | |
125 | 125 | |||
126 | if (rw == URE_CTL_WRITE) | 126 | if (rw == URE_CTL_WRITE) | |
127 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 127 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
128 | else | 128 | else | |
129 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 129 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
130 | req.bRequest = UR_SET_ADDRESS; | 130 | req.bRequest = UR_SET_ADDRESS; | |
131 | USETW(req.wValue, val); | 131 | USETW(req.wValue, val); | |
132 | USETW(req.wIndex, index); | 132 | USETW(req.wIndex, index); | |
133 | USETW(req.wLength, len); | 133 | USETW(req.wLength, len); | |
134 | 134 | |||
135 | DPRINTFN(5, ("ure_ctl: rw %d, val %04hu, index %04hu, len %d\n", | 135 | DPRINTFN(5, ("ure_ctl: rw %d, val %04hu, index %04hu, len %d\n", | |
136 | rw, val, index, len)); | 136 | rw, val, index, len)); | |
137 | err = usbd_do_request(un->un_udev, &req, buf); | 137 | err = usbd_do_request(un->un_udev, &req, buf); | |
138 | if (err) { | 138 | if (err) { | |
139 | DPRINTF(("ure_ctl: error %d\n", err)); | 139 | DPRINTF(("ure_ctl: error %d\n", err)); | |
140 | return -1; | 140 | return -1; | |
141 | } | 141 | } | |
142 | 142 | |||
143 | return 0; | 143 | return 0; | |
144 | } | 144 | } | |
145 | 145 | |||
146 | static int | 146 | static int | |
147 | ure_read_mem(struct usbnet *un, uint16_t addr, uint16_t index, | 147 | ure_read_mem(struct usbnet *un, uint16_t addr, uint16_t index, | |
148 | void *buf, int len) | 148 | void *buf, int len) | |
149 | { | 149 | { | |
150 | return ure_ctl(un, URE_CTL_READ, addr, index, buf, len); | 150 | return ure_ctl(un, URE_CTL_READ, addr, index, buf, len); | |
151 | } | 151 | } | |
152 | 152 | |||
153 | static int | 153 | static int | |
154 | ure_write_mem(struct usbnet *un, uint16_t addr, uint16_t index, | 154 | ure_write_mem(struct usbnet *un, uint16_t addr, uint16_t index, | |
155 | void *buf, int len) | 155 | void *buf, int len) | |
156 | { | 156 | { | |
157 | return ure_ctl(un, URE_CTL_WRITE, addr, index, buf, len); | 157 | return ure_ctl(un, URE_CTL_WRITE, addr, index, buf, len); | |
158 | } | 158 | } | |
159 | 159 | |||
160 | static uint8_t | 160 | static uint8_t | |
161 | ure_read_1(struct usbnet *un, uint16_t reg, uint16_t index) | 161 | ure_read_1(struct usbnet *un, uint16_t reg, uint16_t index) | |
162 | { | 162 | { | |
163 | uint32_t val; | 163 | uint32_t val; | |
164 | uint8_t temp[4]; | 164 | uint8_t temp[4]; | |
165 | uint8_t shift; | 165 | uint8_t shift; | |
166 | 166 | |||
167 | shift = (reg & 3) << 3; | 167 | shift = (reg & 3) << 3; | |
168 | reg &= ~3; | 168 | reg &= ~3; | |
169 | 169 | |||
170 | ure_read_mem(un, reg, index, &temp, 4); | 170 | ure_read_mem(un, reg, index, &temp, 4); | |
171 | val = UGETDW(temp); | 171 | val = UGETDW(temp); | |
172 | val >>= shift; | 172 | val >>= shift; | |
173 | 173 | |||
174 | return val & 0xff; | 174 | return val & 0xff; | |
175 | } | 175 | } | |
176 | 176 | |||
177 | static uint16_t | 177 | static uint16_t | |
178 | ure_read_2(struct usbnet *un, uint16_t reg, uint16_t index) | 178 | ure_read_2(struct usbnet *un, uint16_t reg, uint16_t index) | |
179 | { | 179 | { | |
180 | uint32_t val; | 180 | uint32_t val; | |
181 | uint8_t temp[4]; | 181 | uint8_t temp[4]; | |
182 | uint8_t shift; | 182 | uint8_t shift; | |
183 | 183 | |||
184 | shift = (reg & 2) << 3; | 184 | shift = (reg & 2) << 3; | |
185 | reg &= ~3; | 185 | reg &= ~3; | |
186 | 186 | |||
187 | ure_read_mem(un, reg, index, &temp, 4); | 187 | ure_read_mem(un, reg, index, &temp, 4); | |
188 | val = UGETDW(temp); | 188 | val = UGETDW(temp); | |
189 | val >>= shift; | 189 | val >>= shift; | |
190 | 190 | |||
191 | return val & 0xffff; | 191 | return val & 0xffff; | |
192 | } | 192 | } | |
193 | 193 | |||
194 | static uint32_t | 194 | static uint32_t | |
195 | ure_read_4(struct usbnet *un, uint16_t reg, uint16_t index) | 195 | ure_read_4(struct usbnet *un, uint16_t reg, uint16_t index) | |
196 | { | 196 | { | |
197 | uint8_t temp[4]; | 197 | uint8_t temp[4]; | |
198 | 198 | |||
199 | ure_read_mem(un, reg, index, &temp, 4); | 199 | ure_read_mem(un, reg, index, &temp, 4); | |
200 | return UGETDW(temp); | 200 | return UGETDW(temp); | |
201 | } | 201 | } | |
202 | 202 | |||
203 | static int | 203 | static int | |
204 | ure_write_1(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | 204 | ure_write_1(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | |
205 | { | 205 | { | |
206 | uint16_t byen; | 206 | uint16_t byen; | |
207 | uint8_t temp[4]; | 207 | uint8_t temp[4]; | |
208 | uint8_t shift; | 208 | uint8_t shift; | |
209 | 209 | |||
210 | byen = URE_BYTE_EN_BYTE; | 210 | byen = URE_BYTE_EN_BYTE; | |
211 | shift = reg & 3; | 211 | shift = reg & 3; | |
212 | val &= 0xff; | 212 | val &= 0xff; | |
213 | 213 | |||
214 | if (reg & 3) { | 214 | if (reg & 3) { | |
215 | byen <<= shift; | 215 | byen <<= shift; | |
216 | val <<= (shift << 3); | 216 | val <<= (shift << 3); | |
217 | reg &= ~3; | 217 | reg &= ~3; | |
218 | } | 218 | } | |
219 | 219 | |||
220 | USETDW(temp, val); | 220 | USETDW(temp, val); | |
221 | return ure_write_mem(un, reg, index | byen, &temp, 4); | 221 | return ure_write_mem(un, reg, index | byen, &temp, 4); | |
222 | } | 222 | } | |
223 | 223 | |||
224 | static int | 224 | static int | |
225 | ure_write_2(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | 225 | ure_write_2(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | |
226 | { | 226 | { | |
227 | uint16_t byen; | 227 | uint16_t byen; | |
228 | uint8_t temp[4]; | 228 | uint8_t temp[4]; | |
229 | uint8_t shift; | 229 | uint8_t shift; | |
230 | 230 | |||
231 | byen = URE_BYTE_EN_WORD; | 231 | byen = URE_BYTE_EN_WORD; | |
232 | shift = reg & 2; | 232 | shift = reg & 2; | |
233 | val &= 0xffff; | 233 | val &= 0xffff; | |
234 | 234 | |||
235 | if (reg & 2) { | 235 | if (reg & 2) { | |
236 | byen <<= shift; | 236 | byen <<= shift; | |
237 | val <<= (shift << 3); | 237 | val <<= (shift << 3); | |
238 | reg &= ~3; | 238 | reg &= ~3; | |
239 | } | 239 | } | |
240 | 240 | |||
241 | USETDW(temp, val); | 241 | USETDW(temp, val); | |
242 | return ure_write_mem(un, reg, index | byen, &temp, 4); | 242 | return ure_write_mem(un, reg, index | byen, &temp, 4); | |
243 | } | 243 | } | |
244 | 244 | |||
245 | static int | 245 | static int | |
246 | ure_write_4(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | 246 | ure_write_4(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | |
247 | { | 247 | { | |
248 | uint8_t temp[4]; | 248 | uint8_t temp[4]; | |
249 | 249 | |||
250 | USETDW(temp, val); | 250 | USETDW(temp, val); | |
251 | return ure_write_mem(un, reg, index | URE_BYTE_EN_DWORD, &temp, 4); | 251 | return ure_write_mem(un, reg, index | URE_BYTE_EN_DWORD, &temp, 4); | |
252 | } | 252 | } | |
253 | 253 | |||
254 | static uint16_t | 254 | static uint16_t | |
255 | ure_ocp_reg_read(struct usbnet *un, uint16_t addr) | 255 | ure_ocp_reg_read(struct usbnet *un, uint16_t addr) | |
256 | { | 256 | { | |
257 | uint16_t reg; | 257 | uint16_t reg; | |
258 | 258 | |||
259 | ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); | 259 | ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); | |
260 | reg = (addr & 0x0fff) | 0xb000; | 260 | reg = (addr & 0x0fff) | 0xb000; | |
261 | 261 | |||
262 | return ure_read_2(un, reg, URE_MCU_TYPE_PLA); | 262 | return ure_read_2(un, reg, URE_MCU_TYPE_PLA); | |
263 | } | 263 | } | |
264 | 264 | |||
265 | static void | 265 | static void | |
266 | ure_ocp_reg_write(struct usbnet *un, uint16_t addr, uint16_t data) | 266 | ure_ocp_reg_write(struct usbnet *un, uint16_t addr, uint16_t data) | |
267 | { | 267 | { | |
268 | uint16_t reg; | 268 | uint16_t reg; | |
269 | 269 | |||
270 | ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); | 270 | ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); | |
271 | reg = (addr & 0x0fff) | 0xb000; | 271 | reg = (addr & 0x0fff) | 0xb000; | |
272 | 272 | |||
273 | ure_write_2(un, reg, URE_MCU_TYPE_PLA, data); | 273 | ure_write_2(un, reg, URE_MCU_TYPE_PLA, data); | |
274 | } | 274 | } | |
275 | 275 | |||
276 | static int | 276 | static int | |
277 | ure_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 277 | ure_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
278 | { | 278 | { | |
279 | 279 | |||
280 | if (un->un_phyno != phy) | 280 | if (un->un_phyno != phy) | |
281 | return EINVAL; | 281 | return EINVAL; | |
282 | 282 | |||
283 | /* Let the rgephy driver read the URE_PLA_PHYSTATUS register. */ | 283 | /* Let the rgephy driver read the URE_PLA_PHYSTATUS register. */ | |
284 | if (reg == RTK_GMEDIASTAT) { | 284 | if (reg == RTK_GMEDIASTAT) { | |
285 | *val = ure_read_1(un, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA); | 285 | *val = ure_read_1(un, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA); | |
286 | return USBD_NORMAL_COMPLETION; | 286 | return USBD_NORMAL_COMPLETION; | |
287 | } | 287 | } | |
288 | 288 | |||
289 | *val = ure_ocp_reg_read(un, URE_OCP_BASE_MII + reg * 2); | 289 | *val = ure_ocp_reg_read(un, URE_OCP_BASE_MII + reg * 2); | |
290 | 290 | |||
291 | return 0; | 291 | return 0; | |
292 | } | 292 | } | |
293 | 293 | |||
294 | static int | 294 | static int | |
295 | ure_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 295 | ure_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
296 | { | 296 | { | |
297 | 297 | |||
298 | if (un->un_phyno != phy) | 298 | if (un->un_phyno != phy) | |
299 | return EINVAL; | 299 | return EINVAL; | |
300 | 300 | |||
301 | ure_ocp_reg_write(un, URE_OCP_BASE_MII + reg * 2, val); | 301 | ure_ocp_reg_write(un, URE_OCP_BASE_MII + reg * 2, val); | |
302 | 302 | |||
303 | return 0; | 303 | return 0; | |
304 | } | 304 | } | |
305 | 305 | |||
306 | static void | 306 | static void | |
307 | ure_uno_miibus_statchg(struct ifnet *ifp) | 307 | ure_uno_miibus_statchg(struct ifnet *ifp) | |
308 | { | 308 | { | |
309 | struct usbnet * const un = ifp->if_softc; | 309 | struct usbnet * const un = ifp->if_softc; | |
310 | struct mii_data * const mii = usbnet_mii(un); | 310 | struct mii_data * const mii = usbnet_mii(un); | |
311 | 311 | |||
312 | if (usbnet_isdying(un)) | 312 | if (usbnet_isdying(un)) | |
313 | return; | 313 | return; | |
314 | 314 | |||
315 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 315 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
316 | (IFM_ACTIVE | IFM_AVALID)) { | 316 | (IFM_ACTIVE | IFM_AVALID)) { | |
317 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 317 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
318 | case IFM_10_T: | 318 | case IFM_10_T: | |
319 | case IFM_100_TX: | 319 | case IFM_100_TX: | |
320 | usbnet_set_link(un, true); | 320 | usbnet_set_link(un, true); | |
321 | break; | 321 | break; | |
322 | case IFM_1000_T: | 322 | case IFM_1000_T: | |
323 | if ((un->un_flags & URE_FLAG_8152) != 0) | 323 | if ((un->un_flags & URE_FLAG_8152) != 0) | |
324 | break; | 324 | break; | |
325 | usbnet_set_link(un, true); | 325 | usbnet_set_link(un, true); | |
326 | break; | 326 | break; | |
327 | default: | 327 | default: | |
328 | break; | 328 | break; | |
329 | } | 329 | } | |
330 | } | 330 | } | |
331 | } | 331 | } | |
332 | 332 | |||
333 | static void | 333 | static void | |
334 | ure_rcvfilt_locked(struct usbnet *un) | 334 | ure_rcvfilt_locked(struct usbnet *un) | |
335 | { | 335 | { | |
336 | struct ethercom *ec = usbnet_ec(un); | 336 | struct ethercom *ec = usbnet_ec(un); | |
337 | struct ifnet *ifp = usbnet_ifp(un); | 337 | struct ifnet *ifp = usbnet_ifp(un); | |
338 | struct ether_multi *enm; | 338 | struct ether_multi *enm; | |
339 | struct ether_multistep step; | 339 | struct ether_multistep step; | |
340 | uint32_t mchash[2] = { 0, 0 }; | 340 | uint32_t mchash[2] = { 0, 0 }; | |
341 | uint32_t h = 0, rxmode; | 341 | uint32_t h = 0, rxmode; | |
342 | 342 | |||
343 | usbnet_isowned_core(un); | 343 | usbnet_isowned_core(un); | |
344 | 344 | |||
345 | if (usbnet_isdying(un)) | 345 | if (usbnet_isdying(un)) | |
346 | return; | 346 | return; | |
347 | 347 | |||
348 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | 348 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | |
349 | rxmode &= ~(URE_RCR_AAP | URE_RCR_AM); | 349 | rxmode &= ~(URE_RCR_AAP | URE_RCR_AM); | |
350 | /* continue to accept my own DA and bcast frames */ | 350 | /* continue to accept my own DA and bcast frames */ | |
351 | 351 | |||
352 | ETHER_LOCK(ec); | 352 | ETHER_LOCK(ec); | |
353 | if (ifp->if_flags & IFF_PROMISC) { | 353 | if (ifp->if_flags & IFF_PROMISC) { | |
354 | ec->ec_flags |= ETHER_F_ALLMULTI; | 354 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
355 | ETHER_UNLOCK(ec); | 355 | ETHER_UNLOCK(ec); | |
356 | /* run promisc. mode */ | 356 | /* run promisc. mode */ | |
357 | rxmode |= URE_RCR_AM; /* ??? */ | 357 | rxmode |= URE_RCR_AM; /* ??? */ | |
358 | rxmode |= URE_RCR_AAP; | 358 | rxmode |= URE_RCR_AAP; | |
359 | goto update; | 359 | goto update; | |
360 | } | 360 | } | |
361 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 361 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
362 | ETHER_FIRST_MULTI(step, ec, enm); | 362 | ETHER_FIRST_MULTI(step, ec, enm); | |
363 | while (enm != NULL) { | 363 | while (enm != NULL) { | |
364 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 364 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
365 | ec->ec_flags |= ETHER_F_ALLMULTI; | 365 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
366 | ETHER_UNLOCK(ec); | 366 | ETHER_UNLOCK(ec); | |
367 | /* accept all mcast frames */ | 367 | /* accept all mcast frames */ | |
368 | rxmode |= URE_RCR_AM; | 368 | rxmode |= URE_RCR_AM; | |
369 | mchash[0] = mchash[1] = ~0U; /* necessary ?? */ | 369 | mchash[0] = mchash[1] = ~0U; /* necessary ?? */ | |
370 | goto update; | 370 | goto update; | |
371 | } | 371 | } | |
372 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | 372 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | |
373 | mchash[h >> 31] |= 1 << ((h >> 26) & 0x1f); | 373 | mchash[h >> 31] |= 1 << ((h >> 26) & 0x1f); | |
374 | ETHER_NEXT_MULTI(step, enm); | 374 | ETHER_NEXT_MULTI(step, enm); | |
375 | } | 375 | } | |
376 | ETHER_UNLOCK(ec); | 376 | ETHER_UNLOCK(ec); | |
377 | if (h != 0) { | 377 | if (h != 0) { | |
378 | rxmode |= URE_RCR_AM; /* activate mcast hash filter */ | 378 | rxmode |= URE_RCR_AM; /* activate mcast hash filter */ | |
379 | h = bswap32(mchash[0]); | 379 | h = bswap32(mchash[0]); | |
380 | mchash[0] = bswap32(mchash[1]); | 380 | mchash[0] = bswap32(mchash[1]); | |
381 | mchash[1] = h; | 381 | mchash[1] = h; | |
382 | } | 382 | } | |
383 | update: | 383 | update: | |
384 | ure_write_4(un, URE_PLA_MAR0, URE_MCU_TYPE_PLA, mchash[0]); | 384 | ure_write_4(un, URE_PLA_MAR0, URE_MCU_TYPE_PLA, mchash[0]); | |
385 | ure_write_4(un, URE_PLA_MAR4, URE_MCU_TYPE_PLA, mchash[1]); | 385 | ure_write_4(un, URE_PLA_MAR4, URE_MCU_TYPE_PLA, mchash[1]); | |
386 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | 386 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | |
387 | } | 387 | } | |
388 | 388 | |||
389 | static void | 389 | static void | |
390 | ure_reset(struct usbnet *un) | 390 | ure_reset(struct usbnet *un) | |
391 | { | 391 | { | |
392 | int i; | 392 | int i; | |
393 | 393 | |||
394 | usbnet_isowned_core(un); | 394 | usbnet_isowned_core(un); | |
395 | 395 | |||
396 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST); | 396 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST); | |
397 | 397 | |||
398 | for (i = 0; i < URE_TIMEOUT; i++) { | 398 | for (i = 0; i < URE_TIMEOUT; i++) { | |
399 | if (usbnet_isdying(un)) | 399 | if (usbnet_isdying(un)) | |
400 | return; | 400 | return; | |
401 | if (!(ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) & | 401 | if (!(ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) & | |
402 | URE_CR_RST)) | 402 | URE_CR_RST)) | |
403 | break; | 403 | break; | |
404 | usbd_delay_ms(un->un_udev, 10); | 404 | usbd_delay_ms(un->un_udev, 10); | |
405 | } | 405 | } | |
406 | if (i == URE_TIMEOUT) | 406 | if (i == URE_TIMEOUT) | |
407 | URE_PRINTF(un, "reset never completed\n"); | 407 | URE_PRINTF(un, "reset never completed\n"); | |
408 | } | 408 | } | |
409 | 409 | |||
410 | static int | 410 | static int | |
411 | ure_init_locked(struct ifnet *ifp) | 411 | ure_init_locked(struct ifnet *ifp) | |
412 | { | 412 | { | |
413 | struct usbnet * const un = ifp->if_softc; | 413 | struct usbnet * const un = ifp->if_softc; | |
414 | uint8_t eaddr[8]; | 414 | uint8_t eaddr[8]; | |
415 | 415 | |||
416 | usbnet_isowned_core(un); | 416 | usbnet_isowned_core(un); | |
417 | 417 | |||
418 | if (usbnet_isdying(un)) | 418 | if (usbnet_isdying(un)) | |
419 | return EIO; | 419 | return EIO; | |
420 | 420 | |||
421 | /* Cancel pending I/O. */ | 421 | /* Cancel pending I/O. */ | |
422 | if (ifp->if_flags & IFF_RUNNING) | 422 | if (ifp->if_flags & IFF_RUNNING) | |
423 | usbnet_stop(un, ifp, 1); | 423 | usbnet_stop(un, ifp, 1); | |
424 | 424 | |||
425 | /* Set MAC address. */ | 425 | /* Set MAC address. */ | |
426 | memset(eaddr, 0, sizeof(eaddr)); | 426 | memset(eaddr, 0, sizeof(eaddr)); | |
427 | memcpy(eaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); | 427 | memcpy(eaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); | |
428 | ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG); | 428 | ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG); | |
429 | ure_write_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES, | 429 | ure_write_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES, | |
430 | eaddr, 8); | 430 | eaddr, 8); | |
431 | ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML); | 431 | ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML); | |
432 | 432 | |||
433 | /* Reset the packet filter. */ | 433 | /* Reset the packet filter. */ | |
434 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | 434 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | |
435 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) & | 435 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) & | |
436 | ~URE_FMC_FCR_MCU_EN); | 436 | ~URE_FMC_FCR_MCU_EN); | |
437 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | 437 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | |
438 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) | | 438 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) | | |
439 | URE_FMC_FCR_MCU_EN); | 439 | URE_FMC_FCR_MCU_EN); | |
440 | 440 | |||
441 | /* Enable transmit and receive. */ | 441 | /* Enable transmit and receive. */ | |
442 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, | 442 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, | |
443 | ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) | URE_CR_RE | | 443 | ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) | URE_CR_RE | | |
444 | URE_CR_TE); | 444 | URE_CR_TE); | |
445 | 445 | |||
446 | ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, | 446 | ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, | |
447 | ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) & | 447 | ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) & | |
448 | ~URE_RXDY_GATED_EN); | 448 | ~URE_RXDY_GATED_EN); | |
449 | 449 | |||
450 | /* Accept multicast frame or run promisc. mode. */ | 450 | /* Accept multicast frame or run promisc. mode. */ | |
451 | ure_rcvfilt_locked(un); | 451 | ure_rcvfilt_locked(un); | |
452 | 452 | |||
453 | return usbnet_init_rx_tx(un); | 453 | return usbnet_init_rx_tx(un); | |
454 | } | 454 | } | |
455 | 455 | |||
456 | static int | 456 | static int | |
457 | ure_uno_init(struct ifnet *ifp) | 457 | ure_uno_init(struct ifnet *ifp) | |
458 | { | 458 | { | |
459 | int ret = ure_init_locked(ifp); | 459 | int ret = ure_init_locked(ifp); | |
460 | 460 | |||
461 | return ret; | 461 | return ret; | |
462 | } | 462 | } | |
463 | 463 | |||
464 | static void | 464 | static void | |
465 | ure_uno_stop(struct ifnet *ifp, int disable __unused) | 465 | ure_uno_stop(struct ifnet *ifp, int disable __unused) | |
466 | { | 466 | { | |
467 | struct usbnet * const un = ifp->if_softc; | 467 | struct usbnet * const un = ifp->if_softc; | |
468 | 468 | |||
469 | ure_reset(un); | 469 | ure_reset(un); | |
470 | } | 470 | } | |
471 | 471 | |||
472 | static void | 472 | static void | |
473 | ure_rtl8152_init(struct usbnet *un) | 473 | ure_rtl8152_init(struct usbnet *un) | |
474 | { | 474 | { | |
475 | uint32_t pwrctrl; | 475 | uint32_t pwrctrl; | |
476 | 476 | |||
477 | /* Disable ALDPS. */ | 477 | /* Disable ALDPS. */ | |
478 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | 478 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | |
479 | URE_DIS_SDSAVE); | 479 | URE_DIS_SDSAVE); | |
480 | usbd_delay_ms(un->un_udev, 20); | 480 | usbd_delay_ms(un->un_udev, 20); | |
481 | 481 | |||
482 | if (un->un_flags & URE_FLAG_VER_4C00) { | 482 | if (un->un_flags & URE_FLAG_VER_4C00) { | |
483 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | 483 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | |
484 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | 484 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | |
485 | ~URE_LED_MODE_MASK); | 485 | ~URE_LED_MODE_MASK); | |
486 | } | 486 | } | |
487 | 487 | |||
488 | ure_write_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB, | 488 | ure_write_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB, | |
489 | ure_read_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) & | 489 | ure_read_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) & | |
490 | ~URE_POWER_CUT); | 490 | ~URE_POWER_CUT); | |
491 | ure_write_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB, | 491 | ure_write_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB, | |
492 | ure_read_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) & | 492 | ure_read_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) & | |
493 | ~URE_RESUME_INDICATE); | 493 | ~URE_RESUME_INDICATE); | |
494 | 494 | |||
495 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | 495 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | |
496 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | 496 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | |
497 | URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH); | 497 | URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH); | |
498 | pwrctrl = ure_read_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA); | 498 | pwrctrl = ure_read_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA); | |
499 | pwrctrl &= ~URE_MCU_CLK_RATIO_MASK; | 499 | pwrctrl &= ~URE_MCU_CLK_RATIO_MASK; | |
500 | pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN; | 500 | pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN; | |
501 | ure_write_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl); | 501 | ure_write_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl); | |
502 | ure_write_2(un, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA, | 502 | ure_write_2(un, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA, | |
503 | URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK | | 503 | URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK | | |
504 | URE_SPDWN_LINKCHG_MSK); | 504 | URE_SPDWN_LINKCHG_MSK); | |
505 | 505 | |||
506 | /* Enable Rx aggregation. */ | 506 | /* Enable Rx aggregation. */ | |
507 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | 507 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | |
508 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | 508 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | |
509 | ~URE_RX_AGG_DISABLE); | 509 | ~URE_RX_AGG_DISABLE); | |
510 | 510 | |||
511 | /* Disable ALDPS. */ | 511 | /* Disable ALDPS. */ | |
512 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | 512 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | |
513 | URE_DIS_SDSAVE); | 513 | URE_DIS_SDSAVE); | |
514 | usbd_delay_ms(un->un_udev, 20); | 514 | usbd_delay_ms(un->un_udev, 20); | |
515 | 515 | |||
516 | ure_init_fifo(un); | 516 | ure_init_fifo(un); | |
517 | 517 | |||
518 | ure_write_1(un, URE_USB_TX_AGG, URE_MCU_TYPE_USB, | 518 | ure_write_1(un, URE_USB_TX_AGG, URE_MCU_TYPE_USB, | |
519 | URE_TX_AGG_MAX_THRESHOLD); | 519 | URE_TX_AGG_MAX_THRESHOLD); | |
520 | ure_write_4(un, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH); | 520 | ure_write_4(un, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH); | |
521 | ure_write_4(un, URE_USB_TX_DMA, URE_MCU_TYPE_USB, | 521 | ure_write_4(un, URE_USB_TX_DMA, URE_MCU_TYPE_USB, | |
522 | URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1); | 522 | URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1); | |
523 | } | 523 | } | |
524 | 524 | |||
525 | static void | 525 | static void | |
526 | ure_rtl8153_init(struct usbnet *un) | 526 | ure_rtl8153_init(struct usbnet *un) | |
527 | { | 527 | { | |
528 | uint16_t val; | 528 | uint16_t val; | |
529 | uint8_t u1u2[8]; | 529 | uint8_t u1u2[8]; | |
530 | int i; | 530 | int i; | |
531 | 531 | |||
532 | /* Disable ALDPS. */ | 532 | /* Disable ALDPS. */ | |
533 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 533 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
534 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | 534 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | |
535 | usbd_delay_ms(un->un_udev, 20); | 535 | usbd_delay_ms(un->un_udev, 20); | |
536 | 536 | |||
537 | memset(u1u2, 0x00, sizeof(u1u2)); | 537 | memset(u1u2, 0x00, sizeof(u1u2)); | |
538 | ure_write_mem(un, URE_USB_TOLERANCE, | 538 | ure_write_mem(un, URE_USB_TOLERANCE, | |
539 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 539 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
540 | 540 | |||
541 | for (i = 0; i < URE_TIMEOUT; i++) { | 541 | for (i = 0; i < URE_TIMEOUT; i++) { | |
542 | if (usbnet_isdying(un)) | 542 | if (usbnet_isdying(un)) | |
543 | return; | 543 | return; | |
544 | if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & | 544 | if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & | |
545 | URE_AUTOLOAD_DONE) | 545 | URE_AUTOLOAD_DONE) | |
546 | break; | 546 | break; | |
547 | usbd_delay_ms(un->un_udev, 10); | 547 | usbd_delay_ms(un->un_udev, 10); | |
548 | } | 548 | } | |
549 | if (i == URE_TIMEOUT) | 549 | if (i == URE_TIMEOUT) | |
550 | URE_PRINTF(un, "timeout waiting for chip autoload\n"); | 550 | URE_PRINTF(un, "timeout waiting for chip autoload\n"); | |
551 | 551 | |||
552 | for (i = 0; i < URE_TIMEOUT; i++) { | 552 | for (i = 0; i < URE_TIMEOUT; i++) { | |
553 | if (usbnet_isdying(un)) | 553 | if (usbnet_isdying(un)) | |
554 | return; | 554 | return; | |
555 | val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) & | 555 | val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) & | |
556 | URE_PHY_STAT_MASK; | 556 | URE_PHY_STAT_MASK; | |
557 | if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN) | 557 | if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN) | |
558 | break; | 558 | break; | |
559 | usbd_delay_ms(un->un_udev, 10); | 559 | usbd_delay_ms(un->un_udev, 10); | |
560 | } | 560 | } | |
561 | if (i == URE_TIMEOUT) | 561 | if (i == URE_TIMEOUT) | |
562 | URE_PRINTF(un, "timeout waiting for phy to stabilize\n"); | 562 | URE_PRINTF(un, "timeout waiting for phy to stabilize\n"); | |
563 | 563 | |||
564 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, | 564 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, | |
565 | ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB) & | 565 | ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB) & | |
566 | ~URE_U2P3_ENABLE); | 566 | ~URE_U2P3_ENABLE); | |
567 | 567 | |||
568 | if (un->un_flags & URE_FLAG_VER_5C10) { | 568 | if (un->un_flags & URE_FLAG_VER_5C10) { | |
569 | val = ure_read_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB); | 569 | val = ure_read_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB); | |
570 | val &= ~URE_PWD_DN_SCALE_MASK; | 570 | val &= ~URE_PWD_DN_SCALE_MASK; | |
571 | val |= URE_PWD_DN_SCALE(96); | 571 | val |= URE_PWD_DN_SCALE(96); | |
572 | ure_write_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, val); | 572 | ure_write_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, val); | |
573 | 573 | |||
574 | ure_write_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB, | 574 | ure_write_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB, | |
575 | ure_read_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB) | | 575 | ure_read_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB) | | |
576 | URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND); | 576 | URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND); | |
577 | } else if (un->un_flags & URE_FLAG_VER_5C20) { | 577 | } else if (un->un_flags & URE_FLAG_VER_5C20) { | |
578 | ure_write_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA, | 578 | ure_write_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA, | |
579 | ure_read_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA) & | 579 | ure_read_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA) & | |
580 | ~URE_ECM_ALDPS); | 580 | ~URE_ECM_ALDPS); | |
581 | } | 581 | } | |
582 | if (un->un_flags & (URE_FLAG_VER_5C20 | URE_FLAG_VER_5C30)) { | 582 | if (un->un_flags & (URE_FLAG_VER_5C20 | URE_FLAG_VER_5C30)) { | |
583 | val = ure_read_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB); | 583 | val = ure_read_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB); | |
584 | if (ure_read_2(un, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB) == | 584 | if (ure_read_2(un, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB) == | |
585 | 0) | 585 | 0) | |
586 | val &= ~URE_DYNAMIC_BURST; | 586 | val &= ~URE_DYNAMIC_BURST; | |
587 | else | 587 | else | |
588 | val |= URE_DYNAMIC_BURST; | 588 | val |= URE_DYNAMIC_BURST; | |
589 | ure_write_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB, val); | 589 | ure_write_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB, val); | |
590 | } | 590 | } | |
591 | 591 | |||
592 | ure_write_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB, | 592 | ure_write_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB, | |
593 | ure_read_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB) | | 593 | ure_read_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB) | | |
594 | URE_EP4_FULL_FC); | 594 | URE_EP4_FULL_FC); | |
595 | 595 | |||
596 | ure_write_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB, | 596 | ure_write_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB, | |
597 | ure_read_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB) & | 597 | ure_read_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB) & | |
598 | ~URE_TIMER11_EN); | 598 | ~URE_TIMER11_EN); | |
599 | 599 | |||
600 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | 600 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | |
601 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | 601 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | |
602 | ~URE_LED_MODE_MASK); | 602 | ~URE_LED_MODE_MASK); | |
603 | 603 | |||
604 | if ((un->un_flags & URE_FLAG_VER_5C10) && | 604 | if ((un->un_flags & URE_FLAG_VER_5C10) && | |
605 | un->un_udev->ud_speed != USB_SPEED_SUPER) | 605 | un->un_udev->ud_speed != USB_SPEED_SUPER) | |
606 | val = URE_LPM_TIMER_500MS; | 606 | val = URE_LPM_TIMER_500MS; | |
607 | else | 607 | else | |
608 | val = URE_LPM_TIMER_500US; | 608 | val = URE_LPM_TIMER_500US; | |
609 | ure_write_1(un, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB, | 609 | ure_write_1(un, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB, | |
610 | val | URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM); | 610 | val | URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM); | |
611 | 611 | |||
612 | val = ure_read_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB); | 612 | val = ure_read_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB); | |
613 | val &= ~URE_SEN_VAL_MASK; | 613 | val &= ~URE_SEN_VAL_MASK; | |
614 | val |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE; | 614 | val |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE; | |
615 | ure_write_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, val); | 615 | ure_write_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, val); | |
616 | 616 | |||
617 | ure_write_2(un, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001); | 617 | ure_write_2(un, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001); | |
618 | 618 | |||
619 | ure_write_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, | 619 | ure_write_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, | |
620 | ure_read_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB) & | 620 | ure_read_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB) & | |
621 | ~(URE_PWR_EN | URE_PHASE2_EN)); | 621 | ~(URE_PWR_EN | URE_PHASE2_EN)); | |
622 | ure_write_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB, | 622 | ure_write_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB, | |
623 | ure_read_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB) & | 623 | ure_read_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB) & | |
624 | ~URE_PCUT_STATUS); | 624 | ~URE_PCUT_STATUS); | |
625 | 625 | |||
626 | memset(u1u2, 0xff, sizeof(u1u2)); | 626 | memset(u1u2, 0xff, sizeof(u1u2)); | |
627 | ure_write_mem(un, URE_USB_TOLERANCE, | 627 | ure_write_mem(un, URE_USB_TOLERANCE, | |
628 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 628 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
629 | 629 | |||
630 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, | 630 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, | |
631 | URE_ALDPS_SPDWN_RATIO); | 631 | URE_ALDPS_SPDWN_RATIO); | |
632 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, | 632 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, | |
633 | URE_EEE_SPDWN_RATIO); | 633 | URE_EEE_SPDWN_RATIO); | |
634 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, | 634 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, | |
635 | URE_PKT_AVAIL_SPDWN_EN | URE_SUSPEND_SPDWN_EN | | 635 | URE_PKT_AVAIL_SPDWN_EN | URE_SUSPEND_SPDWN_EN | | |
636 | URE_U1U2_SPDWN_EN | URE_L1_SPDWN_EN); | 636 | URE_U1U2_SPDWN_EN | URE_L1_SPDWN_EN); | |
637 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, | 637 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, | |
638 | URE_PWRSAVE_SPDWN_EN | URE_RXDV_SPDWN_EN | URE_TX10MIDLE_EN | | 638 | URE_PWRSAVE_SPDWN_EN | URE_RXDV_SPDWN_EN | URE_TX10MIDLE_EN | | |
639 | URE_TP100_SPDWN_EN | URE_TP500_SPDWN_EN | URE_TP1000_SPDWN_EN | | 639 | URE_TP100_SPDWN_EN | URE_TP500_SPDWN_EN | URE_TP1000_SPDWN_EN | | |
640 | URE_EEE_SPDWN_EN); | 640 | URE_EEE_SPDWN_EN); | |
641 | 641 | |||
642 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | 642 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | |
643 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | 643 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | |
644 | val |= URE_U2P3_ENABLE; | 644 | val |= URE_U2P3_ENABLE; | |
645 | else | 645 | else | |
646 | val &= ~URE_U2P3_ENABLE; | 646 | val &= ~URE_U2P3_ENABLE; | |
647 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | 647 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | |
648 | 648 | |||
649 | memset(u1u2, 0x00, sizeof(u1u2)); | 649 | memset(u1u2, 0x00, sizeof(u1u2)); | |
650 | ure_write_mem(un, URE_USB_TOLERANCE, | 650 | ure_write_mem(un, URE_USB_TOLERANCE, | |
651 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 651 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
652 | 652 | |||
653 | /* Disable ALDPS. */ | 653 | /* Disable ALDPS. */ | |
654 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 654 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
655 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | 655 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | |
656 | usbd_delay_ms(un->un_udev, 20); | 656 | usbd_delay_ms(un->un_udev, 20); | |
657 | 657 | |||
658 | ure_init_fifo(un); | 658 | ure_init_fifo(un); | |
659 | 659 | |||
660 | /* Enable Rx aggregation. */ | 660 | /* Enable Rx aggregation. */ | |
661 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | 661 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | |
662 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | 662 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | |
663 | ~URE_RX_AGG_DISABLE); | 663 | ~URE_RX_AGG_DISABLE); | |
664 | 664 | |||
665 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | 665 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | |
666 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | 666 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | |
667 | val |= URE_U2P3_ENABLE; | 667 | val |= URE_U2P3_ENABLE; | |
668 | else | 668 | else | |
669 | val &= ~URE_U2P3_ENABLE; | 669 | val &= ~URE_U2P3_ENABLE; | |
670 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | 670 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | |
671 | 671 | |||
672 | memset(u1u2, 0xff, sizeof(u1u2)); | 672 | memset(u1u2, 0xff, sizeof(u1u2)); | |
673 | ure_write_mem(un, URE_USB_TOLERANCE, | 673 | ure_write_mem(un, URE_USB_TOLERANCE, | |
674 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 674 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
675 | } | 675 | } | |
676 | 676 | |||
677 | static void | 677 | static void | |
678 | ure_disable_teredo(struct usbnet *un) | 678 | ure_disable_teredo(struct usbnet *un) | |
679 | { | 679 | { | |
680 | ure_write_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, | 680 | ure_write_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, | |
681 | ure_read_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) & | 681 | ure_read_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) & | |
682 | ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN)); | 682 | ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN)); | |
683 | ure_write_2(un, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, | 683 | ure_write_2(un, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, | |
684 | URE_WDT6_SET_MODE); | 684 | URE_WDT6_SET_MODE); | |
685 | ure_write_2(un, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0); | 685 | ure_write_2(un, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0); | |
686 | ure_write_4(un, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0); | 686 | ure_write_4(un, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0); | |
687 | } | 687 | } | |
688 | 688 | |||
689 | static void | 689 | static void | |
690 | ure_init_fifo(struct usbnet *un) | 690 | ure_init_fifo(struct usbnet *un) | |
691 | { | 691 | { | |
692 | uint32_t rxmode, rx_fifo1, rx_fifo2; | 692 | uint32_t rxmode, rx_fifo1, rx_fifo2; | |
693 | int i; | 693 | int i; | |
694 | 694 | |||
695 | ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, | 695 | ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, | |
696 | ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) | | 696 | ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) | | |
697 | URE_RXDY_GATED_EN); | 697 | URE_RXDY_GATED_EN); | |
698 | 698 | |||
699 | ure_disable_teredo(un); | 699 | ure_disable_teredo(un); | |
700 | 700 | |||
701 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | 701 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | |
702 | rxmode &= ~URE_RCR_ACPT_ALL; | 702 | rxmode &= ~URE_RCR_ACPT_ALL; | |
703 | rxmode |= URE_RCR_APM | URE_RCR_AB; /* accept my own DA and bcast */ | 703 | rxmode |= URE_RCR_APM | URE_RCR_AB; /* accept my own DA and bcast */ | |
704 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | 704 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | |
705 | 705 | |||
706 | if (!(un->un_flags & URE_FLAG_8152)) { | 706 | if (!(un->un_flags & URE_FLAG_8152)) { | |
707 | if (un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10 | | 707 | if (un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10 | | |
708 | URE_FLAG_VER_5C20)) | 708 | URE_FLAG_VER_5C20)) | |
709 | ure_ocp_reg_write(un, URE_OCP_ADC_CFG, | 709 | ure_ocp_reg_write(un, URE_OCP_ADC_CFG, | |
710 | URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L); | 710 | URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L); | |
711 | if (un->un_flags & URE_FLAG_VER_5C00) | 711 | if (un->un_flags & URE_FLAG_VER_5C00) | |
712 | ure_ocp_reg_write(un, URE_OCP_EEE_CFG, | 712 | ure_ocp_reg_write(un, URE_OCP_EEE_CFG, | |
713 | ure_ocp_reg_read(un, URE_OCP_EEE_CFG) & | 713 | ure_ocp_reg_read(un, URE_OCP_EEE_CFG) & | |
714 | ~URE_CTAP_SHORT_EN); | 714 | ~URE_CTAP_SHORT_EN); | |
715 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 715 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
716 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | 716 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | |
717 | URE_EEE_CLKDIV_EN); | 717 | URE_EEE_CLKDIV_EN); | |
718 | ure_ocp_reg_write(un, URE_OCP_DOWN_SPEED, | 718 | ure_ocp_reg_write(un, URE_OCP_DOWN_SPEED, | |
719 | ure_ocp_reg_read(un, URE_OCP_DOWN_SPEED) | | 719 | ure_ocp_reg_read(un, URE_OCP_DOWN_SPEED) | | |
720 | URE_EN_10M_BGOFF); | 720 | URE_EN_10M_BGOFF); | |
721 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 721 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
722 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | 722 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | |
723 | URE_EN_10M_PLLOFF); | 723 | URE_EN_10M_PLLOFF); | |
724 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_IMPEDANCE); | 724 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_IMPEDANCE); | |
725 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0b13); | 725 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0b13); | |
726 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | 726 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | |
727 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | 727 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | |
728 | URE_PFM_PWM_SWITCH); | 728 | URE_PFM_PWM_SWITCH); | |
729 | 729 | |||
730 | /* Enable LPF corner auto tune. */ | 730 | /* Enable LPF corner auto tune. */ | |
731 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_LPF_CFG); | 731 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_LPF_CFG); | |
732 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0xf70f); | 732 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0xf70f); | |
733 | 733 | |||
734 | /* Adjust 10M amplitude. */ | 734 | /* Adjust 10M amplitude. */ | |
735 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP1); | 735 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP1); | |
736 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x00af); | 736 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x00af); | |
737 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP2); | 737 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP2); | |
738 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0208); | 738 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0208); | |
739 | } | 739 | } | |
740 | 740 | |||
741 | ure_reset(un); | 741 | ure_reset(un); | |
742 | 742 | |||
743 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, 0); | 743 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, 0); | |
744 | 744 | |||
745 | ure_write_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, | 745 | ure_write_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, | |
746 | ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | 746 | ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | |
747 | ~URE_NOW_IS_OOB); | 747 | ~URE_NOW_IS_OOB); | |
748 | 748 | |||
749 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | 749 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | |
750 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) & | 750 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) & | |
751 | ~URE_MCU_BORW_EN); | 751 | ~URE_MCU_BORW_EN); | |
752 | for (i = 0; i < URE_TIMEOUT; i++) { | 752 | for (i = 0; i < URE_TIMEOUT; i++) { | |
753 | if (usbnet_isdying(un)) | 753 | if (usbnet_isdying(un)) | |
754 | return; | 754 | return; | |
755 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | 755 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | |
756 | URE_LINK_LIST_READY) | 756 | URE_LINK_LIST_READY) | |
757 | break; | 757 | break; | |
758 | usbd_delay_ms(un->un_udev, 10); | 758 | usbd_delay_ms(un->un_udev, 10); | |
759 | } | 759 | } | |
760 | if (i == URE_TIMEOUT) | 760 | if (i == URE_TIMEOUT) | |
761 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | 761 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | |
762 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | 762 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | |
763 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) | | 763 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) | | |
764 | URE_RE_INIT_LL); | 764 | URE_RE_INIT_LL); | |
765 | for (i = 0; i < URE_TIMEOUT; i++) { | 765 | for (i = 0; i < URE_TIMEOUT; i++) { | |
766 | if (usbnet_isdying(un)) | 766 | if (usbnet_isdying(un)) | |
767 | return; | 767 | return; | |
768 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | 768 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | |
769 | URE_LINK_LIST_READY) | 769 | URE_LINK_LIST_READY) | |
770 | break; | 770 | break; | |
771 | usbd_delay_ms(un->un_udev, 10); | 771 | usbd_delay_ms(un->un_udev, 10); | |
772 | } | 772 | } | |
773 | if (i == URE_TIMEOUT) | 773 | if (i == URE_TIMEOUT) | |
774 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | 774 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | |
775 | 775 | |||
776 | ure_write_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA, | 776 | ure_write_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA, | |
777 | ure_read_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA) & | 777 | ure_read_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA) & | |
778 | ~URE_CPCR_RX_VLAN); | 778 | ~URE_CPCR_RX_VLAN); | |
779 | ure_write_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA, | 779 | ure_write_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA, | |
780 | ure_read_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA) | | 780 | ure_read_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA) | | |
781 | URE_TCR0_AUTO_FIFO); | 781 | URE_TCR0_AUTO_FIFO); | |
782 | 782 | |||
783 | /* Configure Rx FIFO threshold and coalescing. */ | 783 | /* Configure Rx FIFO threshold and coalescing. */ | |
784 | ure_write_4(un, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA, | 784 | ure_write_4(un, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA, | |
785 | URE_RXFIFO_THR1_NORMAL); | 785 | URE_RXFIFO_THR1_NORMAL); | |
786 | if (un->un_udev->ud_speed == USB_SPEED_FULL) { | 786 | if (un->un_udev->ud_speed == USB_SPEED_FULL) { | |
787 | rx_fifo1 = URE_RXFIFO_THR2_FULL; | 787 | rx_fifo1 = URE_RXFIFO_THR2_FULL; | |
788 | rx_fifo2 = URE_RXFIFO_THR3_FULL; | 788 | rx_fifo2 = URE_RXFIFO_THR3_FULL; | |
789 | } else { | 789 | } else { | |
790 | rx_fifo1 = URE_RXFIFO_THR2_HIGH; | 790 | rx_fifo1 = URE_RXFIFO_THR2_HIGH; | |
791 | rx_fifo2 = URE_RXFIFO_THR3_HIGH; | 791 | rx_fifo2 = URE_RXFIFO_THR3_HIGH; | |
792 | } | 792 | } | |
793 | ure_write_4(un, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1); | 793 | ure_write_4(un, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1); | |
794 | ure_write_4(un, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2); | 794 | ure_write_4(un, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2); | |
795 | 795 | |||
796 | /* Configure Tx FIFO threshold. */ | 796 | /* Configure Tx FIFO threshold. */ | |
797 | ure_write_4(un, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, | 797 | ure_write_4(un, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, | |
798 | URE_TXFIFO_THR_NORMAL); | 798 | URE_TXFIFO_THR_NORMAL); | |
799 | } | 799 | } | |
800 | 800 | |||
801 | static void | 801 | static void | |
802 | ure_uno_mcast(struct ifnet *ifp) | 802 | ure_uno_mcast(struct ifnet *ifp) | |
803 | { | 803 | { | |
804 | struct usbnet * const un = ifp->if_softc; | 804 | struct usbnet * const un = ifp->if_softc; | |
805 | 805 | |||
806 | usbnet_lock_core(un); | 806 | usbnet_lock_core(un); | |
807 | usbnet_busy(un); | |||
808 | 807 | |||
809 | ure_rcvfilt_locked(un); | 808 | ure_rcvfilt_locked(un); | |
810 | 809 | |||
811 | usbnet_unbusy(un); | |||
812 | usbnet_unlock_core(un); | 810 | usbnet_unlock_core(un); | |
813 | } | 811 | } | |
814 | 812 | |||
815 | static int | 813 | static int | |
816 | ure_match(device_t parent, cfdata_t match, void *aux) | 814 | ure_match(device_t parent, cfdata_t match, void *aux) | |
817 | { | 815 | { | |
818 | struct usb_attach_arg *uaa = aux; | 816 | struct usb_attach_arg *uaa = aux; | |
819 | 817 | |||
820 | return usb_lookup(ure_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 818 | return usb_lookup(ure_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
821 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 819 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
822 | } | 820 | } | |
823 | 821 | |||
824 | static void | 822 | static void | |
825 | ure_attach(device_t parent, device_t self, void *aux) | 823 | ure_attach(device_t parent, device_t self, void *aux) | |
826 | { | 824 | { | |
827 | USBNET_MII_DECL_DEFAULT(unm); | 825 | USBNET_MII_DECL_DEFAULT(unm); | |
828 | struct usbnet * const un = device_private(self); | 826 | struct usbnet * const un = device_private(self); | |
829 | struct usb_attach_arg *uaa = aux; | 827 | struct usb_attach_arg *uaa = aux; | |
830 | struct usbd_device *dev = uaa->uaa_device; | 828 | struct usbd_device *dev = uaa->uaa_device; | |
831 | usb_interface_descriptor_t *id; | 829 | usb_interface_descriptor_t *id; | |
832 | usb_endpoint_descriptor_t *ed; | 830 | usb_endpoint_descriptor_t *ed; | |
833 | int error, i; | 831 | int error, i; | |
834 | uint16_t ver; | 832 | uint16_t ver; | |
835 | uint8_t eaddr[8]; /* 2byte padded */ | 833 | uint8_t eaddr[8]; /* 2byte padded */ | |
836 | char *devinfop; | 834 | char *devinfop; | |
837 | uint32_t maclo, machi; | 835 | uint32_t maclo, machi; | |
838 | 836 | |||
839 | aprint_naive("\n"); | 837 | aprint_naive("\n"); | |
840 | aprint_normal("\n"); | 838 | aprint_normal("\n"); | |
841 | devinfop = usbd_devinfo_alloc(dev, 0); | 839 | devinfop = usbd_devinfo_alloc(dev, 0); | |
842 | aprint_normal_dev(self, "%s\n", devinfop); | 840 | aprint_normal_dev(self, "%s\n", devinfop); | |
843 | usbd_devinfo_free(devinfop); | 841 | usbd_devinfo_free(devinfop); | |
844 | 842 | |||
845 | un->un_dev = self; | 843 | un->un_dev = self; | |
846 | un->un_udev = dev; | 844 | un->un_udev = dev; | |
847 | un->un_sc = un; | 845 | un->un_sc = un; | |
848 | un->un_ops = &ure_ops; | 846 | un->un_ops = &ure_ops; | |
849 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 847 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
850 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 848 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
851 | un->un_rx_list_cnt = URE_RX_LIST_CNT; | 849 | un->un_rx_list_cnt = URE_RX_LIST_CNT; | |
852 | un->un_tx_list_cnt = URE_TX_LIST_CNT; | 850 | un->un_tx_list_cnt = URE_TX_LIST_CNT; | |
853 | un->un_rx_bufsz = URE_BUFSZ; | 851 | un->un_rx_bufsz = URE_BUFSZ; | |
854 | un->un_tx_bufsz = URE_BUFSZ; | 852 | un->un_tx_bufsz = URE_BUFSZ; | |
855 | 853 | |||
856 | #define URE_CONFIG_NO 1 /* XXX */ | 854 | #define URE_CONFIG_NO 1 /* XXX */ | |
857 | error = usbd_set_config_no(dev, URE_CONFIG_NO, 1); | 855 | error = usbd_set_config_no(dev, URE_CONFIG_NO, 1); | |
858 | if (error) { | 856 | if (error) { | |
859 | aprint_error_dev(self, "failed to set configuration: %s\n", | 857 | aprint_error_dev(self, "failed to set configuration: %s\n", | |
860 | usbd_errstr(error)); | 858 | usbd_errstr(error)); | |
861 | return; /* XXX */ | 859 | return; /* XXX */ | |
862 | } | 860 | } | |
863 | 861 | |||
864 | if (uaa->uaa_product == USB_PRODUCT_REALTEK_RTL8152) | 862 | if (uaa->uaa_product == USB_PRODUCT_REALTEK_RTL8152) | |
865 | un->un_flags |= URE_FLAG_8152; | 863 | un->un_flags |= URE_FLAG_8152; | |
866 | 864 | |||
867 | #define URE_IFACE_IDX 0 /* XXX */ | 865 | #define URE_IFACE_IDX 0 /* XXX */ | |
868 | error = usbd_device2interface_handle(dev, URE_IFACE_IDX, &un->un_iface); | 866 | error = usbd_device2interface_handle(dev, URE_IFACE_IDX, &un->un_iface); | |
869 | if (error) { | 867 | if (error) { | |
870 | aprint_error_dev(self, "failed to get interface handle: %s\n", | 868 | aprint_error_dev(self, "failed to get interface handle: %s\n", | |
871 | usbd_errstr(error)); | 869 | usbd_errstr(error)); | |
872 | return; /* XXX */ | 870 | return; /* XXX */ | |
873 | } | 871 | } | |
874 | 872 | |||
875 | id = usbd_get_interface_descriptor(un->un_iface); | 873 | id = usbd_get_interface_descriptor(un->un_iface); | |
876 | for (i = 0; i < id->bNumEndpoints; i++) { | 874 | for (i = 0; i < id->bNumEndpoints; i++) { | |
877 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 875 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
878 | if (ed == NULL) { | 876 | if (ed == NULL) { | |
879 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 877 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
880 | return; /* XXX */ | 878 | return; /* XXX */ | |
881 | } | 879 | } | |
882 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 880 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
883 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 881 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
884 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 882 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
885 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 883 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
886 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 884 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
887 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 885 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
888 | } | 886 | } | |
889 | } | 887 | } | |
890 | 888 | |||
891 | /* Set these up now for ure_ctl(). */ | 889 | /* Set these up now for ure_ctl(). */ | |
892 | usbnet_attach(un, "uredet"); | 890 | usbnet_attach(un, "uredet"); | |
893 | 891 | |||
894 | un->un_phyno = 0; | 892 | un->un_phyno = 0; | |
895 | 893 | |||
896 | ver = ure_read_2(un, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK; | 894 | ver = ure_read_2(un, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK; | |
897 | switch (ver) { | 895 | switch (ver) { | |
898 | case 0x4c00: | 896 | case 0x4c00: | |
899 | un->un_flags |= URE_FLAG_VER_4C00; | 897 | un->un_flags |= URE_FLAG_VER_4C00; | |
900 | break; | 898 | break; | |
901 | case 0x4c10: | 899 | case 0x4c10: | |
902 | un->un_flags |= URE_FLAG_VER_4C10; | 900 | un->un_flags |= URE_FLAG_VER_4C10; | |
903 | break; | 901 | break; | |
904 | case 0x5c00: | 902 | case 0x5c00: | |
905 | un->un_flags |= URE_FLAG_VER_5C00; | 903 | un->un_flags |= URE_FLAG_VER_5C00; | |
906 | break; | 904 | break; | |
907 | case 0x5c10: | 905 | case 0x5c10: | |
908 | un->un_flags |= URE_FLAG_VER_5C10; | 906 | un->un_flags |= URE_FLAG_VER_5C10; | |
909 | break; | 907 | break; | |
910 | case 0x5c20: | 908 | case 0x5c20: | |
911 | un->un_flags |= URE_FLAG_VER_5C20; | 909 | un->un_flags |= URE_FLAG_VER_5C20; | |
912 | break; | 910 | break; | |
913 | case 0x5c30: | 911 | case 0x5c30: | |
914 | un->un_flags |= URE_FLAG_VER_5C30; | 912 | un->un_flags |= URE_FLAG_VER_5C30; | |
915 | break; | 913 | break; | |
916 | default: | 914 | default: | |
917 | /* fake addr? or just fail? */ | 915 | /* fake addr? or just fail? */ | |
918 | break; | 916 | break; | |
919 | } | 917 | } | |
920 | aprint_normal_dev(self, "RTL%d %sver %04x\n", | 918 | aprint_normal_dev(self, "RTL%d %sver %04x\n", | |
921 | (un->un_flags & URE_FLAG_8152) ? 8152 : 8153, | 919 | (un->un_flags & URE_FLAG_8152) ? 8152 : 8153, | |
922 | (un->un_flags != 0) ? "" : "unknown ", | 920 | (un->un_flags != 0) ? "" : "unknown ", | |
923 | ver); | 921 | ver); | |
924 | 922 | |||
925 | usbnet_lock_core(un); | 923 | usbnet_lock_core(un); | |
926 | if (un->un_flags & URE_FLAG_8152) | 924 | if (un->un_flags & URE_FLAG_8152) | |
927 | ure_rtl8152_init(un); | 925 | ure_rtl8152_init(un); | |
928 | else | 926 | else | |
929 | ure_rtl8153_init(un); | 927 | ure_rtl8153_init(un); | |
930 | 928 | |||
931 | if ((un->un_flags & URE_FLAG_VER_4C00) || | 929 | if ((un->un_flags & URE_FLAG_VER_4C00) || | |
932 | (un->un_flags & URE_FLAG_VER_4C10)) | 930 | (un->un_flags & URE_FLAG_VER_4C10)) | |
933 | ure_read_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA, eaddr, | 931 | ure_read_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA, eaddr, | |
934 | sizeof(eaddr)); | 932 | sizeof(eaddr)); | |
935 | else | 933 | else | |
936 | ure_read_mem(un, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, eaddr, | 934 | ure_read_mem(un, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, eaddr, | |
937 | sizeof(eaddr)); | 935 | sizeof(eaddr)); | |
938 | usbnet_unlock_core(un); | 936 | usbnet_unlock_core(un); | |
939 | if (ETHER_IS_ZERO(eaddr)) { | 937 | if (ETHER_IS_ZERO(eaddr)) { | |
940 | maclo = 0x00f2 | (cprng_strong32() & 0xffff0000); | 938 | maclo = 0x00f2 | (cprng_strong32() & 0xffff0000); | |
941 | machi = cprng_strong32() & 0xffff; | 939 | machi = cprng_strong32() & 0xffff; | |
942 | eaddr[0] = maclo & 0xff; | 940 | eaddr[0] = maclo & 0xff; | |
943 | eaddr[1] = (maclo >> 8) & 0xff; | 941 | eaddr[1] = (maclo >> 8) & 0xff; | |
944 | eaddr[2] = (maclo >> 16) & 0xff; | 942 | eaddr[2] = (maclo >> 16) & 0xff; | |
945 | eaddr[3] = (maclo >> 24) & 0xff; | 943 | eaddr[3] = (maclo >> 24) & 0xff; | |
946 | eaddr[4] = machi & 0xff; | 944 | eaddr[4] = machi & 0xff; | |
947 | eaddr[5] = (machi >> 8) & 0xff; | 945 | eaddr[5] = (machi >> 8) & 0xff; | |
948 | } | 946 | } | |
949 | memcpy(un->un_eaddr, eaddr, sizeof(un->un_eaddr)); | 947 | memcpy(un->un_eaddr, eaddr, sizeof(un->un_eaddr)); | |
950 | 948 | |||
951 | struct ifnet *ifp = usbnet_ifp(un); | 949 | struct ifnet *ifp = usbnet_ifp(un); | |
952 | 950 | |||
953 | /* | 951 | /* | |
954 | * We don't support TSOv4 and v6 for now, that are required to | 952 | * We don't support TSOv4 and v6 for now, that are required to | |
955 | * be handled in software for some cases. | 953 | * be handled in software for some cases. | |
956 | */ | 954 | */ | |
957 | ifp->if_capabilities = IFCAP_CSUM_IPv4_Tx | | 955 | ifp->if_capabilities = IFCAP_CSUM_IPv4_Tx | | |
958 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx; | 956 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx; | |
959 | #ifdef INET6 | 957 | #ifdef INET6 | |
960 | ifp->if_capabilities |= IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx; | 958 | ifp->if_capabilities |= IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx; | |
961 | #endif | 959 | #endif | |
962 | if (un->un_flags & ~URE_FLAG_VER_4C00) { | 960 | if (un->un_flags & ~URE_FLAG_VER_4C00) { | |
963 | ifp->if_capabilities |= IFCAP_CSUM_IPv4_Rx | | 961 | ifp->if_capabilities |= IFCAP_CSUM_IPv4_Rx | | |
964 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | 962 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | |
965 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; | 963 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; | |
966 | } | 964 | } | |
967 | struct ethercom *ec = usbnet_ec(un); | 965 | struct ethercom *ec = usbnet_ec(un); | |
968 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | 966 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | |
969 | #ifdef notyet | 967 | #ifdef notyet | |
970 | ec->ec_capabilities |= ETHERCAP_JUMBO_MTU; | 968 | ec->ec_capabilities |= ETHERCAP_JUMBO_MTU; | |
971 | #endif | 969 | #endif | |
972 | 970 | |||
973 | unm.un_mii_phyloc = un->un_phyno; | 971 | unm.un_mii_phyloc = un->un_phyno; | |
974 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 972 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
975 | 0, &unm); | 973 | 0, &unm); | |
976 | } | 974 | } | |
977 | 975 | |||
978 | static void | 976 | static void | |
979 | ure_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 977 | ure_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
980 | { | 978 | { | |
981 | struct ifnet *ifp = usbnet_ifp(un); | 979 | struct ifnet *ifp = usbnet_ifp(un); | |
982 | uint8_t *buf = c->unc_buf; | 980 | uint8_t *buf = c->unc_buf; | |
983 | uint16_t pkt_len = 0; | 981 | uint16_t pkt_len = 0; | |
984 | uint16_t pkt_count = 0; | 982 | uint16_t pkt_count = 0; | |
985 | struct ure_rxpkt rxhdr; | 983 | struct ure_rxpkt rxhdr; | |
986 | 984 | |||
987 | do { | 985 | do { | |
988 | if (total_len < sizeof(rxhdr)) { | 986 | if (total_len < sizeof(rxhdr)) { | |
989 | DPRINTF(("too few bytes left for a packet header\n")); | 987 | DPRINTF(("too few bytes left for a packet header\n")); | |
990 | if_statinc(ifp, if_ierrors); | 988 | if_statinc(ifp, if_ierrors); | |
991 | return; | 989 | return; | |
992 | } | 990 | } | |
993 | 991 | |||
994 | buf += roundup(pkt_len, 8); | 992 | buf += roundup(pkt_len, 8); | |
995 | 993 | |||
996 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | 994 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | |
997 | total_len -= sizeof(rxhdr); | 995 | total_len -= sizeof(rxhdr); | |
998 | 996 | |||
999 | pkt_len = le32toh(rxhdr.ure_pktlen) & URE_RXPKT_LEN_MASK; | 997 | pkt_len = le32toh(rxhdr.ure_pktlen) & URE_RXPKT_LEN_MASK; | |
1000 | DPRINTFN(4, ("next packet is %d bytes\n", pkt_len)); | 998 | DPRINTFN(4, ("next packet is %d bytes\n", pkt_len)); | |
1001 | if (pkt_len > total_len) { | 999 | if (pkt_len > total_len) { | |
1002 | DPRINTF(("not enough bytes left for next packet\n")); | 1000 | DPRINTF(("not enough bytes left for next packet\n")); | |
1003 | if_statinc(ifp, if_ierrors); | 1001 | if_statinc(ifp, if_ierrors); | |
1004 | return; | 1002 | return; | |
1005 | } | 1003 | } | |
1006 | 1004 | |||
1007 | total_len -= roundup(pkt_len, 8); | 1005 | total_len -= roundup(pkt_len, 8); | |
1008 | buf += sizeof(rxhdr); | 1006 | buf += sizeof(rxhdr); | |
1009 | 1007 | |||
1010 | usbnet_enqueue(un, buf, pkt_len - ETHER_CRC_LEN, | 1008 | usbnet_enqueue(un, buf, pkt_len - ETHER_CRC_LEN, | |
1011 | ure_rxcsum(ifp, &rxhdr), 0, 0); | 1009 | ure_rxcsum(ifp, &rxhdr), 0, 0); | |
1012 | 1010 | |||
1013 | pkt_count++; | 1011 | pkt_count++; | |
1014 | 1012 | |||
1015 | } while (total_len > 0); | 1013 | } while (total_len > 0); | |
1016 | 1014 | |||
1017 | if (pkt_count) | 1015 | if (pkt_count) | |
1018 | rnd_add_uint32(usbnet_rndsrc(un), pkt_count); | 1016 | rnd_add_uint32(usbnet_rndsrc(un), pkt_count); | |
1019 | } | 1017 | } | |
1020 | 1018 | |||
1021 | static int | 1019 | static int | |
1022 | ure_rxcsum(struct ifnet *ifp, struct ure_rxpkt *rp) | 1020 | ure_rxcsum(struct ifnet *ifp, struct ure_rxpkt *rp) | |
1023 | { | 1021 | { | |
1024 | int enabled = ifp->if_csum_flags_rx, flags = 0; | 1022 | int enabled = ifp->if_csum_flags_rx, flags = 0; | |
1025 | uint32_t csum, misc; | 1023 | uint32_t csum, misc; | |
1026 | 1024 | |||
1027 | if (enabled == 0) | 1025 | if (enabled == 0) | |
1028 | return 0; | 1026 | return 0; | |
1029 | 1027 | |||
1030 | csum = le32toh(rp->ure_csum); | 1028 | csum = le32toh(rp->ure_csum); | |
1031 | misc = le32toh(rp->ure_misc); | 1029 | misc = le32toh(rp->ure_misc); | |
1032 | 1030 | |||
1033 | if (csum & URE_RXPKT_IPV4_CS) { | 1031 | if (csum & URE_RXPKT_IPV4_CS) { | |
1034 | flags |= M_CSUM_IPv4; | 1032 | flags |= M_CSUM_IPv4; | |
1035 | if (csum & URE_RXPKT_TCP_CS) | 1033 | if (csum & URE_RXPKT_TCP_CS) | |
1036 | flags |= M_CSUM_TCPv4; | 1034 | flags |= M_CSUM_TCPv4; | |
1037 | if (csum & URE_RXPKT_UDP_CS) | 1035 | if (csum & URE_RXPKT_UDP_CS) | |
1038 | flags |= M_CSUM_UDPv4; | 1036 | flags |= M_CSUM_UDPv4; | |
1039 | } else if (csum & URE_RXPKT_IPV6_CS) { | 1037 | } else if (csum & URE_RXPKT_IPV6_CS) { | |
1040 | flags = 0; | 1038 | flags = 0; | |
1041 | if (csum & URE_RXPKT_TCP_CS) | 1039 | if (csum & URE_RXPKT_TCP_CS) | |
1042 | flags |= M_CSUM_TCPv6; | 1040 | flags |= M_CSUM_TCPv6; | |
1043 | if (csum & URE_RXPKT_UDP_CS) | 1041 | if (csum & URE_RXPKT_UDP_CS) | |
1044 | flags |= M_CSUM_UDPv6; | 1042 | flags |= M_CSUM_UDPv6; | |
1045 | } | 1043 | } | |
1046 | 1044 | |||
1047 | flags &= enabled; | 1045 | flags &= enabled; | |
1048 | if (__predict_false((flags & M_CSUM_IPv4) && | 1046 | if (__predict_false((flags & M_CSUM_IPv4) && | |
1049 | (misc & URE_RXPKT_IP_F))) | 1047 | (misc & URE_RXPKT_IP_F))) | |
1050 | flags |= M_CSUM_IPv4_BAD; | 1048 | flags |= M_CSUM_IPv4_BAD; | |
1051 | if (__predict_false( | 1049 | if (__predict_false( | |
1052 | ((flags & (M_CSUM_TCPv4 | M_CSUM_TCPv6)) && (misc & URE_RXPKT_TCP_F)) | 1050 | ((flags & (M_CSUM_TCPv4 | M_CSUM_TCPv6)) && (misc & URE_RXPKT_TCP_F)) | |
1053 | || ((flags & (M_CSUM_UDPv4 | M_CSUM_UDPv6)) && (misc & URE_RXPKT_UDP_F)) | 1051 | || ((flags & (M_CSUM_UDPv4 | M_CSUM_UDPv6)) && (misc & URE_RXPKT_UDP_F)) | |
1054 | )) | 1052 | )) | |
1055 | flags |= M_CSUM_TCP_UDP_BAD; | 1053 | flags |= M_CSUM_TCP_UDP_BAD; | |
1056 | 1054 | |||
1057 | return flags; | 1055 | return flags; | |
1058 | } | 1056 | } | |
1059 | 1057 | |||
1060 | static unsigned | 1058 | static unsigned | |
1061 | ure_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 1059 | ure_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
1062 | { | 1060 | { | |
1063 | struct ure_txpkt txhdr; | 1061 | struct ure_txpkt txhdr; | |
1064 | uint32_t frm_len = 0; | 1062 | uint32_t frm_len = 0; | |
1065 | uint8_t *buf = c->unc_buf; | 1063 | uint8_t *buf = c->unc_buf; | |
1066 | 1064 | |||
1067 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(txhdr)) | 1065 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(txhdr)) | |
1068 | return 0; | 1066 | return 0; | |
1069 | 1067 | |||
1070 | /* header */ | 1068 | /* header */ | |
1071 | txhdr.ure_pktlen = htole32(m->m_pkthdr.len | URE_TXPKT_TX_FS | | 1069 | txhdr.ure_pktlen = htole32(m->m_pkthdr.len | URE_TXPKT_TX_FS | | |
1072 | URE_TXPKT_TX_LS); | 1070 | URE_TXPKT_TX_LS); | |
1073 | txhdr.ure_csum = htole32(ure_txcsum(m)); | 1071 | txhdr.ure_csum = htole32(ure_txcsum(m)); | |
1074 | memcpy(buf, &txhdr, sizeof(txhdr)); | 1072 | memcpy(buf, &txhdr, sizeof(txhdr)); | |
1075 | buf += sizeof(txhdr); | 1073 | buf += sizeof(txhdr); | |
1076 | frm_len = sizeof(txhdr); | 1074 | frm_len = sizeof(txhdr); | |
1077 | 1075 | |||
1078 | /* packet */ | 1076 | /* packet */ | |
1079 | m_copydata(m, 0, m->m_pkthdr.len, buf); | 1077 | m_copydata(m, 0, m->m_pkthdr.len, buf); | |
1080 | frm_len += m->m_pkthdr.len; | 1078 | frm_len += m->m_pkthdr.len; | |
1081 | 1079 | |||
1082 | DPRINTFN(2, ("tx %d bytes\n", frm_len)); | 1080 | DPRINTFN(2, ("tx %d bytes\n", frm_len)); | |
1083 | 1081 | |||
1084 | return frm_len; | 1082 | return frm_len; | |
1085 | } | 1083 | } | |
1086 | 1084 | |||
1087 | /* | 1085 | /* | |
1088 | * We need to calculate L4 checksum in software, if the offset of | 1086 | * We need to calculate L4 checksum in software, if the offset of | |
1089 | * L4 header is larger than 0x7ff = 2047. | 1087 | * L4 header is larger than 0x7ff = 2047. | |
1090 | */ | 1088 | */ | |
1091 | static uint32_t | 1089 | static uint32_t | |
1092 | ure_txcsum(struct mbuf *m) | 1090 | ure_txcsum(struct mbuf *m) | |
1093 | { | 1091 | { | |
1094 | struct ether_header *eh; | 1092 | struct ether_header *eh; | |
1095 | int flags = m->m_pkthdr.csum_flags; | 1093 | int flags = m->m_pkthdr.csum_flags; | |
1096 | uint32_t data = m->m_pkthdr.csum_data; | 1094 | uint32_t data = m->m_pkthdr.csum_data; | |
1097 | uint32_t reg = 0; | 1095 | uint32_t reg = 0; | |
1098 | int l3off, l4off; | 1096 | int l3off, l4off; | |
1099 | uint16_t type; | 1097 | uint16_t type; | |
1100 | 1098 | |||
1101 | if (flags == 0) | 1099 | if (flags == 0) | |
1102 | return 0; | 1100 | return 0; | |
1103 | 1101 | |||
1104 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | 1102 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | |
1105 | eh = mtod(m, struct ether_header *); | 1103 | eh = mtod(m, struct ether_header *); | |
1106 | type = eh->ether_type; | 1104 | type = eh->ether_type; | |
1107 | } else | 1105 | } else | |
1108 | m_copydata(m, offsetof(struct ether_header, ether_type), | 1106 | m_copydata(m, offsetof(struct ether_header, ether_type), | |
1109 | sizeof(type), &type); | 1107 | sizeof(type), &type); | |
1110 | switch (type = htons(type)) { | 1108 | switch (type = htons(type)) { | |
1111 | case ETHERTYPE_IP: | 1109 | case ETHERTYPE_IP: | |
1112 | case ETHERTYPE_IPV6: | 1110 | case ETHERTYPE_IPV6: | |
1113 | l3off = ETHER_HDR_LEN; | 1111 | l3off = ETHER_HDR_LEN; | |
1114 | break; | 1112 | break; | |
1115 | case ETHERTYPE_VLAN: | 1113 | case ETHERTYPE_VLAN: | |
1116 | l3off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | 1114 | l3off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | |
1117 | break; | 1115 | break; | |
1118 | default: | 1116 | default: | |
1119 | return 0; | 1117 | return 0; | |
1120 | } | 1118 | } | |
1121 | 1119 | |||
1122 | if (flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) { | 1120 | if (flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) { | |
1123 | l4off = l3off + M_CSUM_DATA_IPv4_IPHL(data); | 1121 | l4off = l3off + M_CSUM_DATA_IPv4_IPHL(data); | |
1124 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | 1122 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | |
1125 | in_undefer_cksum(m, l3off, flags); | 1123 | in_undefer_cksum(m, l3off, flags); | |
1126 | return 0; | 1124 | return 0; | |
1127 | } | 1125 | } | |
1128 | reg |= URE_TXPKT_IPV4_CS; | 1126 | reg |= URE_TXPKT_IPV4_CS; | |
1129 | if (flags & M_CSUM_TCPv4) | 1127 | if (flags & M_CSUM_TCPv4) | |
1130 | reg |= URE_TXPKT_TCP_CS; | 1128 | reg |= URE_TXPKT_TCP_CS; | |
1131 | else | 1129 | else | |
1132 | reg |= URE_TXPKT_UDP_CS; | 1130 | reg |= URE_TXPKT_UDP_CS; | |
1133 | reg |= l4off << URE_L4_OFFSET_SHIFT; | 1131 | reg |= l4off << URE_L4_OFFSET_SHIFT; | |
1134 | } | 1132 | } | |
1135 | #ifdef INET6 | 1133 | #ifdef INET6 | |
1136 | else if (flags & (M_CSUM_TCPv6 | M_CSUM_UDPv6)) { | 1134 | else if (flags & (M_CSUM_TCPv6 | M_CSUM_UDPv6)) { | |
1137 | l4off = l3off + M_CSUM_DATA_IPv6_IPHL(data); | 1135 | l4off = l3off + M_CSUM_DATA_IPv6_IPHL(data); | |
1138 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | 1136 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | |
1139 | in6_undefer_cksum(m, l3off, flags); | 1137 | in6_undefer_cksum(m, l3off, flags); | |
1140 | return 0; | 1138 | return 0; | |
1141 | } | 1139 | } | |
1142 | reg |= URE_TXPKT_IPV6_CS; | 1140 | reg |= URE_TXPKT_IPV6_CS; | |
1143 | if (flags & M_CSUM_TCPv6) | 1141 | if (flags & M_CSUM_TCPv6) | |
1144 | reg |= URE_TXPKT_TCP_CS; | 1142 | reg |= URE_TXPKT_TCP_CS; | |
1145 | else | 1143 | else | |
1146 | reg |= URE_TXPKT_UDP_CS; | 1144 | reg |= URE_TXPKT_UDP_CS; | |
1147 | reg |= l4off << URE_L4_OFFSET_SHIFT; | 1145 | reg |= l4off << URE_L4_OFFSET_SHIFT; | |
1148 | } | 1146 | } | |
1149 | #endif | 1147 | #endif | |
1150 | else if (flags & M_CSUM_IPv4) | 1148 | else if (flags & M_CSUM_IPv4) | |
1151 | reg |= URE_TXPKT_IPV4_CS; | 1149 | reg |= URE_TXPKT_IPV4_CS; | |
1152 | 1150 | |||
1153 | return reg; | 1151 | return reg; | |
1154 | } | 1152 | } | |
1155 | 1153 | |||
1156 | #ifdef _MODULE | 1154 | #ifdef _MODULE | |
1157 | #include "ioconf.c" | 1155 | #include "ioconf.c" | |
1158 | #endif | 1156 | #endif | |
1159 | 1157 | |||
1160 | USBNET_MODULE(ure) | 1158 | USBNET_MODULE(ure) |