| @@ -1,1273 +1,1275 @@ | | | @@ -1,1273 +1,1275 @@ |
1 | /* $NetBSD: if_axe.c,v 1.81 2017/03/03 06:27:20 msaitoh Exp $ */ | | 1 | /* $NetBSD: if_axe.c,v 1.82 2017/03/06 01:50:44 ozaki-r 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.81 2017/03/03 06:27:20 msaitoh Exp $"); | | 90 | __KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1.82 2017/03/06 01:50:44 ozaki-r Exp $"); |
91 | | | 91 | |
92 | #ifdef _KERNEL_OPT | | 92 | #ifdef _KERNEL_OPT |
93 | #include "opt_inet.h" | | 93 | #include "opt_inet.h" |
94 | #include "opt_usb.h" | | 94 | #include "opt_usb.h" |
95 | #include "opt_net_mpsafe.h" | | 95 | #include "opt_net_mpsafe.h" |
96 | #endif | | 96 | #endif |
97 | | | 97 | |
98 | #include <sys/param.h> | | 98 | #include <sys/param.h> |
99 | #include <sys/bus.h> | | 99 | #include <sys/bus.h> |
100 | #include <sys/device.h> | | 100 | #include <sys/device.h> |
101 | #include <sys/kernel.h> | | 101 | #include <sys/kernel.h> |
102 | #include <sys/mbuf.h> | | 102 | #include <sys/mbuf.h> |
103 | #include <sys/module.h> | | 103 | #include <sys/module.h> |
104 | #include <sys/mutex.h> | | 104 | #include <sys/mutex.h> |
105 | #include <sys/socket.h> | | 105 | #include <sys/socket.h> |
106 | #include <sys/sockio.h> | | 106 | #include <sys/sockio.h> |
107 | #include <sys/systm.h> | | 107 | #include <sys/systm.h> |
108 | | | 108 | |
109 | #include <sys/rndsource.h> | | 109 | #include <sys/rndsource.h> |
110 | | | 110 | |
111 | #include <net/if.h> | | 111 | #include <net/if.h> |
112 | #include <net/if_dl.h> | | 112 | #include <net/if_dl.h> |
113 | #include <net/if_ether.h> | | 113 | #include <net/if_ether.h> |
114 | #include <net/if_media.h> | | 114 | #include <net/if_media.h> |
115 | | | 115 | |
116 | #include <net/bpf.h> | | 116 | #include <net/bpf.h> |
117 | | | 117 | |
118 | #include <dev/mii/mii.h> | | 118 | #include <dev/mii/mii.h> |
119 | #include <dev/mii/miivar.h> | | 119 | #include <dev/mii/miivar.h> |
120 | | | 120 | |
121 | #include <dev/usb/usb.h> | | 121 | #include <dev/usb/usb.h> |
122 | #include <dev/usb/usbhist.h> | | 122 | #include <dev/usb/usbhist.h> |
123 | #include <dev/usb/usbdi.h> | | 123 | #include <dev/usb/usbdi.h> |
124 | #include <dev/usb/usbdi_util.h> | | 124 | #include <dev/usb/usbdi_util.h> |
125 | #include <dev/usb/usbdivar.h> | | 125 | #include <dev/usb/usbdivar.h> |
126 | #include <dev/usb/usbdevs.h> | | 126 | #include <dev/usb/usbdevs.h> |
127 | | | 127 | |
128 | #include <dev/usb/if_axereg.h> | | 128 | #include <dev/usb/if_axereg.h> |
129 | | | 129 | |
130 | /* | | 130 | /* |
131 | * AXE_178_MAX_FRAME_BURST | | 131 | * AXE_178_MAX_FRAME_BURST |
132 | * max frame burst size for Ax88178 and Ax88772 | | 132 | * max frame burst size for Ax88178 and Ax88772 |
133 | * 0 2048 bytes | | 133 | * 0 2048 bytes |
134 | * 1 4096 bytes | | 134 | * 1 4096 bytes |
135 | * 2 8192 bytes | | 135 | * 2 8192 bytes |
136 | * 3 16384 bytes | | 136 | * 3 16384 bytes |
137 | * use the largest your system can handle without USB stalling. | | 137 | * use the largest your system can handle without USB stalling. |
138 | * | | 138 | * |
139 | * NB: 88772 parts appear to generate lots of input errors with | | 139 | * NB: 88772 parts appear to generate lots of input errors with |
140 | * a 2K rx buffer and 8K is only slightly faster than 4K on an | | 140 | * a 2K rx buffer and 8K is only slightly faster than 4K on an |
141 | * EHCI port on a T42 so change at your own risk. | | 141 | * EHCI port on a T42 so change at your own risk. |
142 | */ | | 142 | */ |
143 | #define AXE_178_MAX_FRAME_BURST 1 | | 143 | #define AXE_178_MAX_FRAME_BURST 1 |
144 | | | 144 | |
145 | | | 145 | |
146 | #ifdef USB_DEBUG | | 146 | #ifdef USB_DEBUG |
147 | #ifndef AXE_DEBUG | | 147 | #ifndef AXE_DEBUG |
148 | #define axedebug 0 | | 148 | #define axedebug 0 |
149 | #else | | 149 | #else |
150 | static int axedebug = 20; | | 150 | static int axedebug = 20; |
151 | | | 151 | |
152 | SYSCTL_SETUP(sysctl_hw_axe_setup, "sysctl hw.axe setup") | | 152 | SYSCTL_SETUP(sysctl_hw_axe_setup, "sysctl hw.axe setup") |
153 | { | | 153 | { |
154 | int err; | | 154 | int err; |
155 | const struct sysctlnode *rnode; | | 155 | const struct sysctlnode *rnode; |
156 | const struct sysctlnode *cnode; | | 156 | const struct sysctlnode *cnode; |
157 | | | 157 | |
158 | err = sysctl_createv(clog, 0, NULL, &rnode, | | 158 | err = sysctl_createv(clog, 0, NULL, &rnode, |
159 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "axe", | | 159 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "axe", |
160 | SYSCTL_DESCR("axe global controls"), | | 160 | SYSCTL_DESCR("axe global controls"), |
161 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | | 161 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); |
162 | | | 162 | |
163 | if (err) | | 163 | if (err) |
164 | goto fail; | | 164 | goto fail; |
165 | | | 165 | |
166 | /* control debugging printfs */ | | 166 | /* control debugging printfs */ |
167 | err = sysctl_createv(clog, 0, &rnode, &cnode, | | 167 | err = sysctl_createv(clog, 0, &rnode, &cnode, |
168 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, | | 168 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, |
169 | "debug", SYSCTL_DESCR("Enable debugging output"), | | 169 | "debug", SYSCTL_DESCR("Enable debugging output"), |
170 | NULL, 0, &axedebug, sizeof(axedebug), CTL_CREATE, CTL_EOL); | | 170 | NULL, 0, &axedebug, sizeof(axedebug), CTL_CREATE, CTL_EOL); |
171 | if (err) | | 171 | if (err) |
172 | goto fail; | | 172 | goto fail; |
173 | | | 173 | |
174 | return; | | 174 | return; |
175 | fail: | | 175 | fail: |
176 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | | 176 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); |
177 | } | | 177 | } |
178 | | | 178 | |
179 | #endif /* AXE_DEBUG */ | | 179 | #endif /* AXE_DEBUG */ |
180 | #endif /* USB_DEBUG */ | | 180 | #endif /* USB_DEBUG */ |
181 | | | 181 | |
182 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(axedebug,1,FMT,A,B,C,D) | | 182 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(axedebug,1,FMT,A,B,C,D) |
183 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(axedebug,N,FMT,A,B,C,D) | | 183 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(axedebug,N,FMT,A,B,C,D) |
184 | #define AXEHIST_FUNC() USBHIST_FUNC() | | 184 | #define AXEHIST_FUNC() USBHIST_FUNC() |
185 | #define AXEHIST_CALLED(name) USBHIST_CALLED(axedebug) | | 185 | #define AXEHIST_CALLED(name) USBHIST_CALLED(axedebug) |
186 | | | 186 | |
187 | /* | | 187 | /* |
188 | * Various supported device vendors/products. | | 188 | * Various supported device vendors/products. |
189 | */ | | 189 | */ |
190 | static const struct axe_type axe_devs[] = { | | 190 | static const struct axe_type axe_devs[] = { |
191 | { { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE2000}, 0 }, | | 191 | { { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE2000}, 0 }, |
192 | { { USB_VENDOR_ACERCM, USB_PRODUCT_ACERCM_EP1427X2}, 0 }, | | 192 | { { USB_VENDOR_ACERCM, USB_PRODUCT_ACERCM_EP1427X2}, 0 }, |
193 | { { USB_VENDOR_APPLE, USB_PRODUCT_APPLE_ETHERNET }, AX772 }, | | 193 | { { USB_VENDOR_APPLE, USB_PRODUCT_APPLE_ETHERNET }, AX772 }, |
194 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88172}, 0 }, | | 194 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88172}, 0 }, |
195 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772}, AX772 }, | | 195 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772}, AX772 }, |
196 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772A}, AX772 }, | | 196 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772A}, AX772 }, |
197 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B}, AX772B }, | | 197 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B}, AX772B }, |
198 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B_1}, AX772B }, | | 198 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B_1}, AX772B }, |
199 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178}, AX178 }, | | 199 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178}, AX178 }, |
200 | { { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC210T}, 0 }, | | 200 | { { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC210T}, 0 }, |
201 | { { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D5055 }, AX178 }, | | 201 | { { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D5055 }, AX178 }, |
202 | { { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB2AR}, 0}, | | 202 | { { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB2AR}, 0}, |
203 | { { USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_USB200MV2}, AX772A }, | | 203 | { { USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_USB200MV2}, AX772A }, |
204 | { { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB2_TX }, 0}, | | 204 | { { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB2_TX }, 0}, |
205 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100}, 0 }, | | 205 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100}, 0 }, |
206 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100B1 }, AX772 }, | | 206 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100B1 }, AX772 }, |
207 | { { USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DUBE100B1 }, AX772 }, | | 207 | { { USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DUBE100B1 }, AX772 }, |
208 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100C1 }, AX772B }, | | 208 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100C1 }, AX772B }, |
209 | { { USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_GWUSB2E}, 0 }, | | 209 | { { USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_GWUSB2E}, 0 }, |
210 | { { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETGUS2 }, AX178 }, | | 210 | { { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETGUS2 }, AX178 }, |
211 | { { USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_PRX1}, 0 }, | | 211 | { { USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_PRX1}, 0 }, |
212 | { { USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_ETHERNET }, AX772B }, | | 212 | { { USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_ETHERNET }, AX772B }, |
213 | { { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_HG20F9}, AX772B }, | | 213 | { { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_HG20F9}, AX772B }, |
214 | { { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_USB200M}, 0 }, | | 214 | { { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_USB200M}, 0 }, |
215 | { { USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_USB1000 }, AX178 }, | | 215 | { { USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_USB1000 }, AX178 }, |
216 | { { USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LAN_GTJU2}, AX178 }, | | 216 | { { USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LAN_GTJU2}, AX178 }, |
217 | { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2GT}, AX178 }, | | 217 | { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2GT}, AX178 }, |
218 | { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2KTX}, 0 }, | | 218 | { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2KTX}, 0 }, |
219 | { { USB_VENDOR_MSI, USB_PRODUCT_MSI_AX88772A}, AX772 }, | | 219 | { { USB_VENDOR_MSI, USB_PRODUCT_MSI_AX88772A}, AX772 }, |
220 | { { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA120}, 0 }, | | 220 | { { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA120}, 0 }, |
221 | { { USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01PLUS }, AX772 }, | | 221 | { { USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01PLUS }, AX772 }, |
222 | { { USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GU1000T }, AX178 }, | | 222 | { { USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GU1000T }, AX178 }, |
223 | { { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_LN029}, 0 }, | | 223 | { { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_LN029}, 0 }, |
224 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN028 }, AX178 }, | | 224 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN028 }, AX178 }, |
225 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN031 }, AX178 }, | | 225 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN031 }, AX178 }, |
226 | { { USB_VENDOR_SYSTEMTALKS, USB_PRODUCT_SYSTEMTALKS_SGCX2UL}, 0 }, | | 226 | { { USB_VENDOR_SYSTEMTALKS, USB_PRODUCT_SYSTEMTALKS_SGCX2UL}, 0 }, |
227 | }; | | 227 | }; |
228 | #define axe_lookup(v, p) ((const struct axe_type *)usb_lookup(axe_devs, v, p)) | | 228 | #define axe_lookup(v, p) ((const struct axe_type *)usb_lookup(axe_devs, v, p)) |
229 | | | 229 | |
230 | static const struct ax88772b_mfb ax88772b_mfb_table[] = { | | 230 | static const struct ax88772b_mfb ax88772b_mfb_table[] = { |
231 | { 0x8000, 0x8001, 2048 }, | | 231 | { 0x8000, 0x8001, 2048 }, |
232 | { 0x8100, 0x8147, 4096 }, | | 232 | { 0x8100, 0x8147, 4096 }, |
233 | { 0x8200, 0x81EB, 6144 }, | | 233 | { 0x8200, 0x81EB, 6144 }, |
234 | { 0x8300, 0x83D7, 8192 }, | | 234 | { 0x8300, 0x83D7, 8192 }, |
235 | { 0x8400, 0x851E, 16384 }, | | 235 | { 0x8400, 0x851E, 16384 }, |
236 | { 0x8500, 0x8666, 20480 }, | | 236 | { 0x8500, 0x8666, 20480 }, |
237 | { 0x8600, 0x87AE, 24576 }, | | 237 | { 0x8600, 0x87AE, 24576 }, |
238 | { 0x8700, 0x8A3D, 32768 } | | 238 | { 0x8700, 0x8A3D, 32768 } |
239 | }; | | 239 | }; |
240 | | | 240 | |
241 | int axe_match(device_t, cfdata_t, void *); | | 241 | int axe_match(device_t, cfdata_t, void *); |
242 | void axe_attach(device_t, device_t, void *); | | 242 | void axe_attach(device_t, device_t, void *); |
243 | int axe_detach(device_t, int); | | 243 | int axe_detach(device_t, int); |
244 | int axe_activate(device_t, devact_t); | | 244 | int axe_activate(device_t, devact_t); |
245 | | | 245 | |
246 | CFATTACH_DECL_NEW(axe, sizeof(struct axe_softc), | | 246 | CFATTACH_DECL_NEW(axe, sizeof(struct axe_softc), |
247 | axe_match, axe_attach, axe_detach, axe_activate); | | 247 | axe_match, axe_attach, axe_detach, axe_activate); |
248 | | | 248 | |
249 | static int axe_tx_list_init(struct axe_softc *); | | 249 | static int axe_tx_list_init(struct axe_softc *); |
250 | static int axe_rx_list_init(struct axe_softc *); | | 250 | static int axe_rx_list_init(struct axe_softc *); |
251 | static int axe_encap(struct axe_softc *, struct mbuf *, int); | | 251 | static int axe_encap(struct axe_softc *, struct mbuf *, int); |
252 | static void axe_rxeof(struct usbd_xfer *, void *, usbd_status); | | 252 | static void axe_rxeof(struct usbd_xfer *, void *, usbd_status); |
253 | static void axe_txeof(struct usbd_xfer *, void *, usbd_status); | | 253 | static void axe_txeof(struct usbd_xfer *, void *, usbd_status); |
254 | static void axe_tick(void *); | | 254 | static void axe_tick(void *); |
255 | static void axe_tick_task(void *); | | 255 | static void axe_tick_task(void *); |
256 | static void axe_start(struct ifnet *); | | 256 | static void axe_start(struct ifnet *); |
257 | static int axe_ioctl(struct ifnet *, u_long, void *); | | 257 | static int axe_ioctl(struct ifnet *, u_long, void *); |
258 | static int axe_init(struct ifnet *); | | 258 | static int axe_init(struct ifnet *); |
259 | static void axe_stop(struct ifnet *, int); | | 259 | static void axe_stop(struct ifnet *, int); |
260 | static void axe_watchdog(struct ifnet *); | | 260 | static void axe_watchdog(struct ifnet *); |
261 | static int axe_miibus_readreg_locked(device_t, int, int); | | 261 | static int axe_miibus_readreg_locked(device_t, int, int); |
262 | static int axe_miibus_readreg(device_t, int, int); | | 262 | static int axe_miibus_readreg(device_t, int, int); |
263 | static void axe_miibus_writereg_locked(device_t, int, int, int); | | 263 | static void axe_miibus_writereg_locked(device_t, int, int, int); |
264 | static void axe_miibus_writereg(device_t, int, int, int); | | 264 | static void axe_miibus_writereg(device_t, int, int, int); |
265 | static void axe_miibus_statchg(struct ifnet *); | | 265 | static void axe_miibus_statchg(struct ifnet *); |
266 | static int axe_cmd(struct axe_softc *, int, int, int, void *); | | 266 | static int axe_cmd(struct axe_softc *, int, int, int, void *); |
267 | static void axe_reset(struct axe_softc *); | | 267 | static void axe_reset(struct axe_softc *); |
268 | | | 268 | |
269 | static void axe_setmulti(struct axe_softc *); | | 269 | static void axe_setmulti(struct axe_softc *); |
270 | static void axe_lock_mii(struct axe_softc *); | | 270 | static void axe_lock_mii(struct axe_softc *); |
271 | static void axe_unlock_mii(struct axe_softc *); | | 271 | static void axe_unlock_mii(struct axe_softc *); |
272 | | | 272 | |
273 | static void axe_ax88178_init(struct axe_softc *); | | 273 | static void axe_ax88178_init(struct axe_softc *); |
274 | static void axe_ax88772_init(struct axe_softc *); | | 274 | static void axe_ax88772_init(struct axe_softc *); |
| | | 275 | static void axe_ax88772a_init(struct axe_softc *); |
| | | 276 | static void axe_ax88772b_init(struct axe_softc *); |
275 | | | 277 | |
276 | /* Get exclusive access to the MII registers */ | | 278 | /* Get exclusive access to the MII registers */ |
277 | static void | | 279 | static void |
278 | axe_lock_mii(struct axe_softc *sc) | | 280 | axe_lock_mii(struct axe_softc *sc) |
279 | { | | 281 | { |
280 | | | 282 | |
281 | sc->axe_refcnt++; | | 283 | sc->axe_refcnt++; |
282 | mutex_enter(&sc->axe_mii_lock); | | 284 | mutex_enter(&sc->axe_mii_lock); |
283 | } | | 285 | } |
284 | | | 286 | |
285 | static void | | 287 | static void |
286 | axe_unlock_mii(struct axe_softc *sc) | | 288 | axe_unlock_mii(struct axe_softc *sc) |
287 | { | | 289 | { |
288 | | | 290 | |
289 | mutex_exit(&sc->axe_mii_lock); | | 291 | mutex_exit(&sc->axe_mii_lock); |
290 | if (--sc->axe_refcnt < 0) | | 292 | if (--sc->axe_refcnt < 0) |
291 | usb_detach_wakeupold((sc->axe_dev)); | | 293 | usb_detach_wakeupold((sc->axe_dev)); |
292 | } | | 294 | } |
293 | | | 295 | |
294 | static int | | 296 | static int |
295 | axe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf) | | 297 | axe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf) |
296 | { | | 298 | { |
297 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 299 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
298 | usb_device_request_t req; | | 300 | usb_device_request_t req; |
299 | usbd_status err; | | 301 | usbd_status err; |
300 | | | 302 | |
301 | KASSERT(mutex_owned(&sc->axe_mii_lock)); | | 303 | KASSERT(mutex_owned(&sc->axe_mii_lock)); |
302 | | | 304 | |
303 | if (sc->axe_dying) | | 305 | if (sc->axe_dying) |
304 | return 0; | | 306 | return 0; |
305 | | | 307 | |
306 | DPRINTFN(20, "cmd %#x index %#x val %#x", cmd, index, val, 0); | | 308 | DPRINTFN(20, "cmd %#x index %#x val %#x", cmd, index, val, 0); |
307 | | | 309 | |
308 | if (AXE_CMD_DIR(cmd)) | | 310 | if (AXE_CMD_DIR(cmd)) |
309 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | | 311 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; |
310 | else | | 312 | else |
311 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | | 313 | req.bmRequestType = UT_READ_VENDOR_DEVICE; |
312 | req.bRequest = AXE_CMD_CMD(cmd); | | 314 | req.bRequest = AXE_CMD_CMD(cmd); |
313 | USETW(req.wValue, val); | | 315 | USETW(req.wValue, val); |
314 | USETW(req.wIndex, index); | | 316 | USETW(req.wIndex, index); |
315 | USETW(req.wLength, AXE_CMD_LEN(cmd)); | | 317 | USETW(req.wLength, AXE_CMD_LEN(cmd)); |
316 | | | 318 | |
317 | err = usbd_do_request(sc->axe_udev, &req, buf); | | 319 | err = usbd_do_request(sc->axe_udev, &req, buf); |
318 | | | 320 | |
319 | if (err) { | | 321 | if (err) { |
320 | DPRINTF("cmd %d err %d", cmd, err, 0, 0); | | 322 | DPRINTF("cmd %d err %d", cmd, err, 0, 0); |
321 | return -1; | | 323 | return -1; |
322 | } | | 324 | } |
323 | return 0; | | 325 | return 0; |
324 | } | | 326 | } |
325 | | | 327 | |
326 | static int | | 328 | static int |
327 | axe_miibus_readreg_locked(device_t dev, int phy, int reg) | | 329 | axe_miibus_readreg_locked(device_t dev, int phy, int reg) |
328 | { | | 330 | { |
329 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 331 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
330 | struct axe_softc *sc = device_private(dev); | | 332 | struct axe_softc *sc = device_private(dev); |
331 | usbd_status err; | | 333 | usbd_status err; |
332 | uint16_t val; | | 334 | uint16_t val; |
333 | | | 335 | |
334 | DPRINTFN(30, "phy 0x%x reg 0x%x\n", phy, reg, 0, 0); | | 336 | DPRINTFN(30, "phy 0x%x reg 0x%x\n", phy, reg, 0, 0); |
335 | | | 337 | |
336 | axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); | | 338 | axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); |
337 | | | 339 | |
338 | err = axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, (void *)&val); | | 340 | err = axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, (void *)&val); |
339 | axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); | | 341 | axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); |
340 | if (err) { | | 342 | if (err) { |
341 | aprint_error_dev(sc->axe_dev, "read PHY failed\n"); | | 343 | aprint_error_dev(sc->axe_dev, "read PHY failed\n"); |
342 | return -1; | | 344 | return -1; |
343 | } | | 345 | } |
344 | | | 346 | |
345 | val = le16toh(val); | | 347 | val = le16toh(val); |
346 | if (AXE_IS_772(sc) && reg == MII_BMSR) { | | 348 | if (AXE_IS_772(sc) && reg == MII_BMSR) { |
347 | /* | | 349 | /* |
348 | * BMSR of AX88772 indicates that it supports extended | | 350 | * BMSR of AX88772 indicates that it supports extended |
349 | * capability but the extended status register is | | 351 | * capability but the extended status register is |
350 | * reserved for embedded ethernet PHY. So clear the | | 352 | * reserved for embedded ethernet PHY. So clear the |
351 | * extended capability bit of BMSR. | | 353 | * extended capability bit of BMSR. |
352 | */ | | 354 | */ |
353 | val &= ~BMSR_EXTCAP; | | 355 | val &= ~BMSR_EXTCAP; |
354 | } | | 356 | } |
355 | | | 357 | |
356 | DPRINTFN(30, "phy 0x%x reg 0x%x val %#x", phy, reg, val, 0); | | 358 | DPRINTFN(30, "phy 0x%x reg 0x%x val %#x", phy, reg, val, 0); |
357 | | | 359 | |
358 | return val; | | 360 | return val; |
359 | } | | 361 | } |
360 | | | 362 | |
361 | static int | | 363 | static int |
362 | axe_miibus_readreg(device_t dev, int phy, int reg) | | 364 | axe_miibus_readreg(device_t dev, int phy, int reg) |
363 | { | | 365 | { |
364 | struct axe_softc *sc = device_private(dev); | | 366 | struct axe_softc *sc = device_private(dev); |
365 | int val; | | 367 | int val; |
366 | | | 368 | |
367 | if (sc->axe_dying) | | 369 | if (sc->axe_dying) |
368 | return 0; | | 370 | return 0; |
369 | | | 371 | |
370 | if (sc->axe_phyno != phy) | | 372 | if (sc->axe_phyno != phy) |
371 | return 0; | | 373 | return 0; |
372 | | | 374 | |
373 | axe_lock_mii(sc); | | 375 | axe_lock_mii(sc); |
374 | val = axe_miibus_readreg_locked(dev, phy, reg); | | 376 | val = axe_miibus_readreg_locked(dev, phy, reg); |
375 | axe_unlock_mii(sc); | | 377 | axe_unlock_mii(sc); |
376 | | | 378 | |
377 | return val; | | 379 | return val; |
378 | } | | 380 | } |
379 | | | 381 | |
380 | static void | | 382 | static void |
381 | axe_miibus_writereg_locked(device_t dev, int phy, int reg, int aval) | | 383 | axe_miibus_writereg_locked(device_t dev, int phy, int reg, int aval) |
382 | { | | 384 | { |
383 | struct axe_softc *sc = device_private(dev); | | 385 | struct axe_softc *sc = device_private(dev); |
384 | usbd_status err; | | 386 | usbd_status err; |
385 | uint16_t val; | | 387 | uint16_t val; |
386 | | | 388 | |
387 | val = htole16(aval); | | 389 | val = htole16(aval); |
388 | | | 390 | |
389 | axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); | | 391 | axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); |
390 | err = axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, (void *)&val); | | 392 | err = axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, (void *)&val); |
391 | axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); | | 393 | axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); |
392 | | | 394 | |
393 | if (err) { | | 395 | if (err) { |
394 | aprint_error_dev(sc->axe_dev, "write PHY failed\n"); | | 396 | aprint_error_dev(sc->axe_dev, "write PHY failed\n"); |
395 | return; | | 397 | return; |
396 | } | | 398 | } |
397 | } | | 399 | } |
398 | | | 400 | |
399 | static void | | 401 | static void |
400 | axe_miibus_writereg(device_t dev, int phy, int reg, int aval) | | 402 | axe_miibus_writereg(device_t dev, int phy, int reg, int aval) |
401 | { | | 403 | { |
402 | struct axe_softc *sc = device_private(dev); | | 404 | struct axe_softc *sc = device_private(dev); |
403 | | | 405 | |
404 | if (sc->axe_dying) | | 406 | if (sc->axe_dying) |
405 | return; | | 407 | return; |
406 | | | 408 | |
407 | if (sc->axe_phyno != phy) | | 409 | if (sc->axe_phyno != phy) |
408 | return; | | 410 | return; |
409 | | | 411 | |
410 | axe_lock_mii(sc); | | 412 | axe_lock_mii(sc); |
411 | axe_miibus_writereg_locked(dev, phy, reg, aval); | | 413 | axe_miibus_writereg_locked(dev, phy, reg, aval); |
412 | axe_unlock_mii(sc); | | 414 | axe_unlock_mii(sc); |
413 | } | | 415 | } |
414 | | | 416 | |
415 | static void | | 417 | static void |
416 | axe_miibus_statchg(struct ifnet *ifp) | | 418 | axe_miibus_statchg(struct ifnet *ifp) |
417 | { | | 419 | { |
418 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 420 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
419 | | | 421 | |
420 | struct axe_softc *sc = ifp->if_softc; | | 422 | struct axe_softc *sc = ifp->if_softc; |
421 | struct mii_data *mii = &sc->axe_mii; | | 423 | struct mii_data *mii = &sc->axe_mii; |
422 | int val, err; | | 424 | int val, err; |
423 | | | 425 | |
424 | val = 0; | | 426 | val = 0; |
425 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { | | 427 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { |
426 | val |= AXE_MEDIA_FULL_DUPLEX; | | 428 | val |= AXE_MEDIA_FULL_DUPLEX; |
427 | if (AXE_IS_178_FAMILY(sc)) { | | 429 | if (AXE_IS_178_FAMILY(sc)) { |
428 | if ((IFM_OPTIONS(mii->mii_media_active) & | | 430 | if ((IFM_OPTIONS(mii->mii_media_active) & |
429 | IFM_ETH_TXPAUSE) != 0) | | 431 | IFM_ETH_TXPAUSE) != 0) |
430 | val |= AXE_178_MEDIA_TXFLOW_CONTROL_EN; | | 432 | val |= AXE_178_MEDIA_TXFLOW_CONTROL_EN; |
431 | if ((IFM_OPTIONS(mii->mii_media_active) & | | 433 | if ((IFM_OPTIONS(mii->mii_media_active) & |
432 | IFM_ETH_RXPAUSE) != 0) | | 434 | IFM_ETH_RXPAUSE) != 0) |
433 | val |= AXE_178_MEDIA_RXFLOW_CONTROL_EN; | | 435 | val |= AXE_178_MEDIA_RXFLOW_CONTROL_EN; |
434 | } | | 436 | } |
435 | } | | 437 | } |
436 | if (AXE_IS_178_FAMILY(sc)) { | | 438 | if (AXE_IS_178_FAMILY(sc)) { |
437 | val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC; | | 439 | val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC; |
438 | if (sc->axe_flags & AX178) | | 440 | if (sc->axe_flags & AX178) |
439 | val |= AXE_178_MEDIA_ENCK; | | 441 | val |= AXE_178_MEDIA_ENCK; |
440 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | | 442 | switch (IFM_SUBTYPE(mii->mii_media_active)) { |
441 | case IFM_1000_T: | | 443 | case IFM_1000_T: |
442 | val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK; | | 444 | val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK; |
443 | break; | | 445 | break; |
444 | case IFM_100_TX: | | 446 | case IFM_100_TX: |
445 | val |= AXE_178_MEDIA_100TX; | | 447 | val |= AXE_178_MEDIA_100TX; |
446 | break; | | 448 | break; |
447 | case IFM_10_T: | | 449 | case IFM_10_T: |
448 | /* doesn't need to be handled */ | | 450 | /* doesn't need to be handled */ |
449 | break; | | 451 | break; |
450 | } | | 452 | } |
451 | } | | 453 | } |
452 | | | 454 | |
453 | DPRINTF("val=0x%x", val, 0, 0, 0); | | 455 | DPRINTF("val=0x%x", val, 0, 0, 0); |
454 | axe_lock_mii(sc); | | 456 | axe_lock_mii(sc); |
455 | err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL); | | 457 | err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL); |
456 | axe_unlock_mii(sc); | | 458 | axe_unlock_mii(sc); |
457 | if (err) { | | 459 | if (err) { |
458 | aprint_error_dev(sc->axe_dev, "media change failed\n"); | | 460 | aprint_error_dev(sc->axe_dev, "media change failed\n"); |
459 | return; | | 461 | return; |
460 | } | | 462 | } |
461 | } | | 463 | } |
462 | | | 464 | |
463 | static void | | 465 | static void |
464 | axe_setmulti(struct axe_softc *sc) | | 466 | axe_setmulti(struct axe_softc *sc) |
465 | { | | 467 | { |
466 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 468 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
467 | struct ifnet *ifp = &sc->sc_if; | | 469 | struct ifnet *ifp = &sc->sc_if; |
468 | struct ether_multi *enm; | | 470 | struct ether_multi *enm; |
469 | struct ether_multistep step; | | 471 | struct ether_multistep step; |
470 | uint32_t h = 0; | | 472 | uint32_t h = 0; |
471 | uint16_t rxmode; | | 473 | uint16_t rxmode; |
472 | uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | | 474 | uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; |
473 | | | 475 | |
474 | if (sc->axe_dying) | | 476 | if (sc->axe_dying) |
475 | return; | | 477 | return; |
476 | | | 478 | |
477 | axe_lock_mii(sc); | | 479 | axe_lock_mii(sc); |
478 | axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, (void *)&rxmode); | | 480 | axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, (void *)&rxmode); |
479 | rxmode = le16toh(rxmode); | | 481 | rxmode = le16toh(rxmode); |
480 | | | 482 | |
481 | rxmode &= | | 483 | rxmode &= |
482 | ~(AXE_RXCMD_ALLMULTI | AXE_RXCMD_PROMISC | | | 484 | ~(AXE_RXCMD_ALLMULTI | AXE_RXCMD_PROMISC | |
483 | AXE_RXCMD_BROADCAST | AXE_RXCMD_MULTICAST); | | 485 | AXE_RXCMD_BROADCAST | AXE_RXCMD_MULTICAST); |
484 | | | 486 | |
485 | rxmode |= | | 487 | rxmode |= |
486 | (ifp->if_flags & IFF_BROADCAST) ? AXE_RXCMD_BROADCAST : 0; | | 488 | (ifp->if_flags & IFF_BROADCAST) ? AXE_RXCMD_BROADCAST : 0; |
487 | | | 489 | |
488 | if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { | | 490 | if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { |
489 | if (ifp->if_flags & IFF_PROMISC) | | 491 | if (ifp->if_flags & IFF_PROMISC) |
490 | rxmode |= AXE_RXCMD_PROMISC; | | 492 | rxmode |= AXE_RXCMD_PROMISC; |
491 | goto allmulti; | | 493 | goto allmulti; |
492 | } | | 494 | } |
493 | | | 495 | |
494 | /* Now program new ones */ | | 496 | /* Now program new ones */ |
495 | ETHER_FIRST_MULTI(step, &sc->axe_ec, enm); | | 497 | ETHER_FIRST_MULTI(step, &sc->axe_ec, enm); |
496 | while (enm != NULL) { | | 498 | while (enm != NULL) { |
497 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | | 499 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, |
498 | ETHER_ADDR_LEN) != 0) | | 500 | ETHER_ADDR_LEN) != 0) |
499 | goto allmulti; | | 501 | goto allmulti; |
500 | | | 502 | |
501 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26; | | 503 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26; |
502 | hashtbl[h >> 3] |= 1U << (h & 7); | | 504 | hashtbl[h >> 3] |= 1U << (h & 7); |
503 | ETHER_NEXT_MULTI(step, enm); | | 505 | ETHER_NEXT_MULTI(step, enm); |
504 | } | | 506 | } |
505 | ifp->if_flags &= ~IFF_ALLMULTI; | | 507 | ifp->if_flags &= ~IFF_ALLMULTI; |
506 | rxmode |= AXE_RXCMD_MULTICAST; | | 508 | rxmode |= AXE_RXCMD_MULTICAST; |
507 | | | 509 | |
508 | axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl); | | 510 | axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl); |
509 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); | | 511 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); |
510 | axe_unlock_mii(sc); | | 512 | axe_unlock_mii(sc); |
511 | return; | | 513 | return; |
512 | | | 514 | |
513 | allmulti: | | 515 | allmulti: |
514 | ifp->if_flags |= IFF_ALLMULTI; | | 516 | ifp->if_flags |= IFF_ALLMULTI; |
515 | rxmode |= AXE_RXCMD_ALLMULTI; | | 517 | rxmode |= AXE_RXCMD_ALLMULTI; |
516 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); | | 518 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); |
517 | axe_unlock_mii(sc); | | 519 | axe_unlock_mii(sc); |
518 | } | | 520 | } |
519 | | | 521 | |
520 | | | 522 | |
521 | static void | | 523 | static void |
522 | axe_reset(struct axe_softc *sc) | | 524 | axe_reset(struct axe_softc *sc) |
523 | { | | 525 | { |
524 | | | 526 | |
525 | if (sc->axe_dying) | | 527 | if (sc->axe_dying) |
526 | return; | | 528 | return; |
527 | | | 529 | |
528 | /* | | 530 | /* |
529 | * softnet_lock can be taken when NET_MPAFE is not defined when calling | | 531 | * softnet_lock can be taken when NET_MPAFE is not defined when calling |
530 | * if_addr_init -> if_init. This doesn't mixe well with the | | 532 | * if_addr_init -> if_init. This doesn't mixe well with the |
531 | * usbd_delay_ms calls in the init routines as things like nd6_slowtimo | | 533 | * usbd_delay_ms calls in the init routines as things like nd6_slowtimo |
532 | * can fire during the wait and attempt to take softnet_lock and then | | 534 | * can fire during the wait and attempt to take softnet_lock and then |
533 | * block the softclk thread meaing the wait never ends. | | 535 | * block the softclk thread meaing the wait never ends. |
534 | */ | | 536 | */ |
535 | #ifndef NET_MPSAFE | | 537 | #ifndef NET_MPSAFE |
536 | /* XXX What to reset? */ | | 538 | /* XXX What to reset? */ |
537 | | | 539 | |
538 | /* Wait a little while for the chip to get its brains in order. */ | | 540 | /* Wait a little while for the chip to get its brains in order. */ |
539 | DELAY(1000); | | 541 | DELAY(1000); |
540 | #else | | 542 | #else |
541 | axe_lock_mii(sc); | | 543 | axe_lock_mii(sc); |
542 | | | 544 | |
543 | if (sc->axe_flags & AX178) { | | 545 | if (sc->axe_flags & AX178) { |
544 | axe_ax88178_init(sc); | | 546 | axe_ax88178_init(sc); |
545 | } else if (sc->axe_flags & AX772) { | | 547 | } else if (sc->axe_flags & AX772) { |
546 | axe_ax88772_init(sc); | | 548 | axe_ax88772_init(sc); |
547 | } else if (sc->axe_flags & AX772A) { | | 549 | } else if (sc->axe_flags & AX772A) { |
548 | axe_ax88772a_init(sc); | | 550 | axe_ax88772a_init(sc); |
549 | } else if (sc->axe_flags & AX772B) { | | 551 | } else if (sc->axe_flags & AX772B) { |
550 | axe_ax88772b_init(sc); | | 552 | axe_ax88772b_init(sc); |
551 | } | | 553 | } |
552 | axe_unlock_mii(sc); | | 554 | axe_unlock_mii(sc); |
553 | #endif | | 555 | #endif |
554 | } | | 556 | } |
555 | | | 557 | |
556 | static int | | 558 | static int |
557 | axe_get_phyno(struct axe_softc *sc, int sel) | | 559 | axe_get_phyno(struct axe_softc *sc, int sel) |
558 | { | | 560 | { |
559 | int phyno; | | 561 | int phyno; |
560 | | | 562 | |
561 | switch (AXE_PHY_TYPE(sc->axe_phyaddrs[sel])) { | | 563 | switch (AXE_PHY_TYPE(sc->axe_phyaddrs[sel])) { |
562 | case PHY_TYPE_100_HOME: | | 564 | case PHY_TYPE_100_HOME: |
563 | /* FALLTHROUGH */ | | 565 | /* FALLTHROUGH */ |
564 | case PHY_TYPE_GIG: | | 566 | case PHY_TYPE_GIG: |
565 | phyno = AXE_PHY_NO(sc->axe_phyaddrs[sel]); | | 567 | phyno = AXE_PHY_NO(sc->axe_phyaddrs[sel]); |
566 | break; | | 568 | break; |
567 | case PHY_TYPE_SPECIAL: | | 569 | case PHY_TYPE_SPECIAL: |
568 | /* FALLTHROUGH */ | | 570 | /* FALLTHROUGH */ |
569 | case PHY_TYPE_RSVD: | | 571 | case PHY_TYPE_RSVD: |
570 | /* FALLTHROUGH */ | | 572 | /* FALLTHROUGH */ |
571 | case PHY_TYPE_NON_SUP: | | 573 | case PHY_TYPE_NON_SUP: |
572 | /* FALLTHROUGH */ | | 574 | /* FALLTHROUGH */ |
573 | default: | | 575 | default: |
574 | phyno = -1; | | 576 | phyno = -1; |
575 | break; | | 577 | break; |
576 | } | | 578 | } |
577 | | | 579 | |
578 | return phyno; | | 580 | return phyno; |
579 | } | | 581 | } |
580 | | | 582 | |
581 | #define AXE_GPIO_WRITE(x, y) do { \ | | 583 | #define AXE_GPIO_WRITE(x, y) do { \ |
582 | axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, (x), NULL); \ | | 584 | axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, (x), NULL); \ |
583 | usbd_delay_ms(sc->axe_udev, hztoms(y)); \ | | 585 | usbd_delay_ms(sc->axe_udev, hztoms(y)); \ |
584 | } while (0) | | 586 | } while (0) |
585 | | | 587 | |
586 | static void | | 588 | static void |
587 | axe_ax88178_init(struct axe_softc *sc) | | 589 | axe_ax88178_init(struct axe_softc *sc) |
588 | { | | 590 | { |
589 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 591 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
590 | int gpio0, ledmode, phymode; | | 592 | int gpio0, ledmode, phymode; |
591 | uint16_t eeprom, val; | | 593 | uint16_t eeprom, val; |
592 | | | 594 | |
593 | axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL); | | 595 | axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL); |
594 | /* XXX magic */ | | 596 | /* XXX magic */ |
595 | axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom); | | 597 | axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom); |
596 | axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL); | | 598 | axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL); |
597 | | | 599 | |
598 | eeprom = le16toh(eeprom); | | 600 | eeprom = le16toh(eeprom); |
599 | | | 601 | |
600 | DPRINTF("EEPROM is 0x%x", eeprom, 0, 0, 0); | | 602 | DPRINTF("EEPROM is 0x%x", eeprom, 0, 0, 0); |
601 | | | 603 | |
602 | /* if EEPROM is invalid we have to use to GPIO0 */ | | 604 | /* if EEPROM is invalid we have to use to GPIO0 */ |
603 | if (eeprom == 0xffff) { | | 605 | if (eeprom == 0xffff) { |
604 | phymode = AXE_PHY_MODE_MARVELL; | | 606 | phymode = AXE_PHY_MODE_MARVELL; |
605 | gpio0 = 1; | | 607 | gpio0 = 1; |
606 | ledmode = 0; | | 608 | ledmode = 0; |
607 | } else { | | 609 | } else { |
608 | phymode = eeprom & 0x7f; | | 610 | phymode = eeprom & 0x7f; |
609 | gpio0 = (eeprom & 0x80) ? 0 : 1; | | 611 | gpio0 = (eeprom & 0x80) ? 0 : 1; |
610 | ledmode = eeprom >> 8; | | 612 | ledmode = eeprom >> 8; |
611 | } | | 613 | } |
612 | | | 614 | |
613 | DPRINTF("use gpio0: %d, phymode %d", gpio0, phymode, 0, 0); | | 615 | DPRINTF("use gpio0: %d, phymode %d", gpio0, phymode, 0, 0); |
614 | | | 616 | |
615 | /* Program GPIOs depending on PHY hardware. */ | | 617 | /* Program GPIOs depending on PHY hardware. */ |
616 | switch (phymode) { | | 618 | switch (phymode) { |
617 | case AXE_PHY_MODE_MARVELL: | | 619 | case AXE_PHY_MODE_MARVELL: |
618 | if (gpio0 == 1) { | | 620 | if (gpio0 == 1) { |
619 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0_EN, | | 621 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0_EN, |
620 | hz / 32); | | 622 | hz / 32); |
621 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, | | 623 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, |
622 | hz / 32); | | 624 | hz / 32); |
623 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2_EN, hz / 4); | | 625 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2_EN, hz / 4); |
624 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, | | 626 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, |
625 | hz / 32); | | 627 | hz / 32); |
626 | } else { | | 628 | } else { |
627 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | | 629 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | |
628 | AXE_GPIO1_EN, hz / 3); | | 630 | AXE_GPIO1_EN, hz / 3); |
629 | if (ledmode == 1) { | | 631 | if (ledmode == 1) { |
630 | AXE_GPIO_WRITE(AXE_GPIO1_EN, hz / 3); | | 632 | AXE_GPIO_WRITE(AXE_GPIO1_EN, hz / 3); |
631 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN, | | 633 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN, |
632 | hz / 3); | | 634 | hz / 3); |
633 | } else { | | 635 | } else { |
634 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | | 636 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | |
635 | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | | 637 | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); |
636 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | | 638 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | |
637 | AXE_GPIO2_EN, hz / 4); | | 639 | AXE_GPIO2_EN, hz / 4); |
638 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | | 640 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | |
639 | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | | 641 | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); |
640 | } | | 642 | } |
641 | } | | 643 | } |
642 | break; | | 644 | break; |
643 | case AXE_PHY_MODE_CICADA: | | 645 | case AXE_PHY_MODE_CICADA: |
644 | case AXE_PHY_MODE_CICADA_V2: | | 646 | case AXE_PHY_MODE_CICADA_V2: |
645 | case AXE_PHY_MODE_CICADA_V2_ASIX: | | 647 | case AXE_PHY_MODE_CICADA_V2_ASIX: |
646 | if (gpio0 == 1) | | 648 | if (gpio0 == 1) |
647 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0 | | | 649 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0 | |
648 | AXE_GPIO0_EN, hz / 32); | | 650 | AXE_GPIO0_EN, hz / 32); |
649 | else | | 651 | else |
650 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | | 652 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | |
651 | AXE_GPIO1_EN, hz / 32); | | 653 | AXE_GPIO1_EN, hz / 32); |
652 | break; | | 654 | break; |
653 | case AXE_PHY_MODE_AGERE: | | 655 | case AXE_PHY_MODE_AGERE: |
654 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | | 656 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | |
655 | AXE_GPIO1_EN, hz / 32); | | 657 | AXE_GPIO1_EN, hz / 32); |
656 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | | | 658 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | |
657 | AXE_GPIO2_EN, hz / 32); | | 659 | AXE_GPIO2_EN, hz / 32); |
658 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2_EN, hz / 4); | | 660 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2_EN, hz / 4); |
659 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | | | 661 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | |
660 | AXE_GPIO2_EN, hz / 32); | | 662 | AXE_GPIO2_EN, hz / 32); |
661 | break; | | 663 | break; |
662 | case AXE_PHY_MODE_REALTEK_8211CL: | | 664 | case AXE_PHY_MODE_REALTEK_8211CL: |
663 | case AXE_PHY_MODE_REALTEK_8211BN: | | 665 | case AXE_PHY_MODE_REALTEK_8211BN: |
664 | case AXE_PHY_MODE_REALTEK_8251CL: | | 666 | case AXE_PHY_MODE_REALTEK_8251CL: |
665 | val = gpio0 == 1 ? AXE_GPIO0 | AXE_GPIO0_EN : | | 667 | val = gpio0 == 1 ? AXE_GPIO0 | AXE_GPIO0_EN : |
666 | AXE_GPIO1 | AXE_GPIO1_EN; | | 668 | AXE_GPIO1 | AXE_GPIO1_EN; |
667 | AXE_GPIO_WRITE(val, hz / 32); | | 669 | AXE_GPIO_WRITE(val, hz / 32); |
668 | AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | | 670 | AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); |
669 | AXE_GPIO_WRITE(val | AXE_GPIO2_EN, hz / 4); | | 671 | AXE_GPIO_WRITE(val | AXE_GPIO2_EN, hz / 4); |
670 | AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | | 672 | AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); |
671 | if (phymode == AXE_PHY_MODE_REALTEK_8211CL) { | | 673 | if (phymode == AXE_PHY_MODE_REALTEK_8211CL) { |
672 | axe_miibus_writereg_locked(sc->axe_dev, | | 674 | axe_miibus_writereg_locked(sc->axe_dev, |
673 | sc->axe_phyno, 0x1F, 0x0005); | | 675 | sc->axe_phyno, 0x1F, 0x0005); |
674 | axe_miibus_writereg_locked(sc->axe_dev, | | 676 | axe_miibus_writereg_locked(sc->axe_dev, |
675 | sc->axe_phyno, 0x0C, 0x0000); | | 677 | sc->axe_phyno, 0x0C, 0x0000); |
676 | val = axe_miibus_readreg_locked(sc->axe_dev, | | 678 | val = axe_miibus_readreg_locked(sc->axe_dev, |
677 | sc->axe_phyno, 0x0001); | | 679 | sc->axe_phyno, 0x0001); |
678 | axe_miibus_writereg_locked(sc->axe_dev, | | 680 | axe_miibus_writereg_locked(sc->axe_dev, |
679 | sc->axe_phyno, 0x01, val | 0x0080); | | 681 | sc->axe_phyno, 0x01, val | 0x0080); |
680 | axe_miibus_writereg_locked(sc->axe_dev, | | 682 | axe_miibus_writereg_locked(sc->axe_dev, |
681 | sc->axe_phyno, 0x1F, 0x0000); | | 683 | sc->axe_phyno, 0x1F, 0x0000); |
682 | } | | 684 | } |
683 | break; | | 685 | break; |
684 | default: | | 686 | default: |
685 | /* Unknown PHY model or no need to program GPIOs. */ | | 687 | /* Unknown PHY model or no need to program GPIOs. */ |
686 | break; | | 688 | break; |
687 | } | | 689 | } |
688 | | | 690 | |
689 | /* soft reset */ | | 691 | /* soft reset */ |
690 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | | 692 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); |
691 | usbd_delay_ms(sc->axe_udev, 150); | | 693 | usbd_delay_ms(sc->axe_udev, 150); |
692 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | | 694 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, |
693 | AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL); | | 695 | AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL); |
694 | usbd_delay_ms(sc->axe_udev, 150); | | 696 | usbd_delay_ms(sc->axe_udev, 150); |
695 | /* Enable MII/GMII/RGMII interface to work with external PHY. */ | | 697 | /* Enable MII/GMII/RGMII interface to work with external PHY. */ |
696 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL); | | 698 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL); |
697 | usbd_delay_ms(sc->axe_udev, 10); | | 699 | usbd_delay_ms(sc->axe_udev, 10); |
698 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | | 700 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); |
699 | } | | 701 | } |
700 | | | 702 | |
701 | static void | | 703 | static void |
702 | axe_ax88772_init(struct axe_softc *sc) | | 704 | axe_ax88772_init(struct axe_softc *sc) |
703 | { | | 705 | { |
704 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 706 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
705 | | | 707 | |
706 | axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL); | | 708 | axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL); |
707 | usbd_delay_ms(sc->axe_udev, 40); | | 709 | usbd_delay_ms(sc->axe_udev, 40); |
708 | | | 710 | |
709 | if (sc->axe_phyno == AXE_772_PHY_NO_EPHY) { | | 711 | if (sc->axe_phyno == AXE_772_PHY_NO_EPHY) { |
710 | /* ask for the embedded PHY */ | | 712 | /* ask for the embedded PHY */ |
711 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, | | 713 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, |
712 | AXE_SW_PHY_SELECT_EMBEDDED, NULL); | | 714 | AXE_SW_PHY_SELECT_EMBEDDED, NULL); |
713 | usbd_delay_ms(sc->axe_udev, 10); | | 715 | usbd_delay_ms(sc->axe_udev, 10); |
714 | | | 716 | |
715 | /* power down and reset state, pin reset state */ | | 717 | /* power down and reset state, pin reset state */ |
716 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | | 718 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); |
717 | usbd_delay_ms(sc->axe_udev, 60); | | 719 | usbd_delay_ms(sc->axe_udev, 60); |
718 | | | 720 | |
719 | /* power down/reset state, pin operating state */ | | 721 | /* power down/reset state, pin operating state */ |
720 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | | 722 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, |
721 | AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); | | 723 | AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); |
722 | usbd_delay_ms(sc->axe_udev, 150); | | 724 | usbd_delay_ms(sc->axe_udev, 150); |
723 | | | 725 | |
724 | /* power up, reset */ | | 726 | /* power up, reset */ |
725 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL); | | 727 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL); |
726 | | | 728 | |
727 | /* power up, operating */ | | 729 | /* power up, operating */ |
728 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | | 730 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, |
729 | AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL); | | 731 | AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL); |
730 | } else { | | 732 | } else { |
731 | /* ask for external PHY */ | | 733 | /* ask for external PHY */ |
732 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_EXT, | | 734 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_EXT, |
733 | NULL); | | 735 | NULL); |
734 | usbd_delay_ms(sc->axe_udev, 10); | | 736 | usbd_delay_ms(sc->axe_udev, 10); |
735 | | | 737 | |
736 | /* power down internal PHY */ | | 738 | /* power down internal PHY */ |
737 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | | 739 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, |
738 | AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); | | 740 | AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); |
739 | } | | 741 | } |
740 | | | 742 | |
741 | usbd_delay_ms(sc->axe_udev, 150); | | 743 | usbd_delay_ms(sc->axe_udev, 150); |
742 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | | 744 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); |
743 | } | | 745 | } |
744 | | | 746 | |
745 | static void | | 747 | static void |
746 | axe_ax88772_phywake(struct axe_softc *sc) | | 748 | axe_ax88772_phywake(struct axe_softc *sc) |
747 | { | | 749 | { |
748 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 750 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
749 | | | 751 | |
750 | if (sc->axe_phyno == AXE_772_PHY_NO_EPHY) { | | 752 | if (sc->axe_phyno == AXE_772_PHY_NO_EPHY) { |
751 | /* Manually select internal(embedded) PHY - MAC mode. */ | | 753 | /* Manually select internal(embedded) PHY - MAC mode. */ |
752 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, | | 754 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, |
753 | AXE_SW_PHY_SELECT_EMBEDDED, | | 755 | AXE_SW_PHY_SELECT_EMBEDDED, |
754 | NULL); | | 756 | NULL); |
755 | usbd_delay_ms(sc->axe_udev, hztoms(hz / 32)); | | 757 | usbd_delay_ms(sc->axe_udev, hztoms(hz / 32)); |
756 | } else { | | 758 | } else { |
757 | /* | | 759 | /* |
758 | * Manually select external PHY - MAC mode. | | 760 | * Manually select external PHY - MAC mode. |
759 | * Reverse MII/RMII is for AX88772A PHY mode. | | 761 | * Reverse MII/RMII is for AX88772A PHY mode. |
760 | */ | | 762 | */ |
761 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_SS_ENB | | | 763 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_SS_ENB | |
762 | AXE_SW_PHY_SELECT_EXT | AXE_SW_PHY_SELECT_SS_MII, NULL); | | 764 | AXE_SW_PHY_SELECT_EXT | AXE_SW_PHY_SELECT_SS_MII, NULL); |
763 | usbd_delay_ms(sc->axe_udev, hztoms(hz / 32)); | | 765 | usbd_delay_ms(sc->axe_udev, hztoms(hz / 32)); |
764 | } | | 766 | } |
765 | | | 767 | |
766 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPPD | | | 768 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPPD | |
767 | AXE_SW_RESET_IPRL, NULL); | | 769 | AXE_SW_RESET_IPRL, NULL); |
768 | | | 770 | |
769 | /* T1 = min 500ns everywhere */ | | 771 | /* T1 = min 500ns everywhere */ |
770 | usbd_delay_ms(sc->axe_udev, 150); | | 772 | usbd_delay_ms(sc->axe_udev, 150); |
771 | | | 773 | |
772 | /* Take PHY out of power down. */ | | 774 | /* Take PHY out of power down. */ |
773 | if (sc->axe_phyno == AXE_772_PHY_NO_EPHY) { | | 775 | if (sc->axe_phyno == AXE_772_PHY_NO_EPHY) { |
774 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL); | | 776 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL); |
775 | } else { | | 777 | } else { |
776 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRTE, NULL); | | 778 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRTE, NULL); |
777 | } | | 779 | } |
778 | | | 780 | |
779 | /* 772 T2 is 60ms. 772A T2 is 160ms, 772B T2 is 600ms */ | | 781 | /* 772 T2 is 60ms. 772A T2 is 160ms, 772B T2 is 600ms */ |
780 | usbd_delay_ms(sc->axe_udev, 600); | | 782 | usbd_delay_ms(sc->axe_udev, 600); |
781 | | | 783 | |
782 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | | 784 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); |
783 | | | 785 | |
784 | /* T3 = 500ns everywhere */ | | 786 | /* T3 = 500ns everywhere */ |
785 | usbd_delay_ms(sc->axe_udev, hztoms(hz / 32)); | | 787 | usbd_delay_ms(sc->axe_udev, hztoms(hz / 32)); |
786 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL); | | 788 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL); |
787 | usbd_delay_ms(sc->axe_udev, hztoms(hz / 32)); | | 789 | usbd_delay_ms(sc->axe_udev, hztoms(hz / 32)); |
788 | } | | 790 | } |
789 | | | 791 | |
790 | static void | | 792 | static void |
791 | axe_ax88772a_init(struct axe_softc *sc) | | 793 | axe_ax88772a_init(struct axe_softc *sc) |
792 | { | | 794 | { |
793 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 795 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
794 | | | 796 | |
795 | /* Reload EEPROM. */ | | 797 | /* Reload EEPROM. */ |
796 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM, hz / 32); | | 798 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM, hz / 32); |
797 | axe_ax88772_phywake(sc); | | 799 | axe_ax88772_phywake(sc); |
798 | /* Stop MAC. */ | | 800 | /* Stop MAC. */ |
799 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | | 801 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); |
800 | } | | 802 | } |
801 | | | 803 | |
802 | static void | | 804 | static void |
803 | axe_ax88772b_init(struct axe_softc *sc) | | 805 | axe_ax88772b_init(struct axe_softc *sc) |
804 | { | | 806 | { |
805 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 807 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
806 | uint16_t eeprom; | | 808 | uint16_t eeprom; |
807 | int i; | | 809 | int i; |
808 | | | 810 | |
809 | /* Reload EEPROM. */ | | 811 | /* Reload EEPROM. */ |
810 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM , hz / 32); | | 812 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM , hz / 32); |
811 | | | 813 | |
812 | /* | | 814 | /* |
813 | * Save PHY power saving configuration(high byte) and | | 815 | * Save PHY power saving configuration(high byte) and |
814 | * clear EEPROM checksum value(low byte). | | 816 | * clear EEPROM checksum value(low byte). |
815 | */ | | 817 | */ |
816 | axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_PHY_PWRCFG, &eeprom); | | 818 | axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_PHY_PWRCFG, &eeprom); |
817 | sc->sc_pwrcfg = le16toh(eeprom) & 0xFF00; | | 819 | sc->sc_pwrcfg = le16toh(eeprom) & 0xFF00; |
818 | | | 820 | |
819 | /* | | 821 | /* |
820 | * Auto-loaded default station address from internal ROM is | | 822 | * Auto-loaded default station address from internal ROM is |
821 | * 00:00:00:00:00:00 such that an explicit access to EEPROM | | 823 | * 00:00:00:00:00:00 such that an explicit access to EEPROM |
822 | * is required to get real station address. | | 824 | * is required to get real station address. |
823 | */ | | 825 | */ |
824 | uint8_t *eaddr = sc->axe_enaddr; | | 826 | uint8_t *eaddr = sc->axe_enaddr; |
825 | for (i = 0; i < ETHER_ADDR_LEN / 2; i++) { | | 827 | for (i = 0; i < ETHER_ADDR_LEN / 2; i++) { |
826 | axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_NODE_ID + i, | | 828 | axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_NODE_ID + i, |
827 | &eeprom); | | 829 | &eeprom); |
828 | eeprom = le16toh(eeprom); | | 830 | eeprom = le16toh(eeprom); |
829 | *eaddr++ = (uint8_t)(eeprom & 0xFF); | | 831 | *eaddr++ = (uint8_t)(eeprom & 0xFF); |
830 | *eaddr++ = (uint8_t)((eeprom >> 8) & 0xFF); | | 832 | *eaddr++ = (uint8_t)((eeprom >> 8) & 0xFF); |
831 | } | | 833 | } |
832 | /* Wakeup PHY. */ | | 834 | /* Wakeup PHY. */ |
833 | axe_ax88772_phywake(sc); | | 835 | axe_ax88772_phywake(sc); |
834 | /* Stop MAC. */ | | 836 | /* Stop MAC. */ |
835 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | | 837 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); |
836 | } | | 838 | } |
837 | | | 839 | |
838 | #undef AXE_GPIO_WRITE | | 840 | #undef AXE_GPIO_WRITE |
839 | | | 841 | |
840 | /* | | 842 | /* |
841 | * Probe for a AX88172 chip. | | 843 | * Probe for a AX88172 chip. |
842 | */ | | 844 | */ |
843 | int | | 845 | int |
844 | axe_match(device_t parent, cfdata_t match, void *aux) | | 846 | axe_match(device_t parent, cfdata_t match, void *aux) |
845 | { | | 847 | { |
846 | struct usb_attach_arg *uaa = aux; | | 848 | struct usb_attach_arg *uaa = aux; |
847 | | | 849 | |
848 | return axe_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | | 850 | return axe_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? |
849 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | | 851 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; |
850 | } | | 852 | } |
851 | | | 853 | |
852 | /* | | 854 | /* |
853 | * Attach the interface. Allocate softc structures, do ifmedia | | 855 | * Attach the interface. Allocate softc structures, do ifmedia |
854 | * setup and ethernet/BPF attach. | | 856 | * setup and ethernet/BPF attach. |
855 | */ | | 857 | */ |
856 | void | | 858 | void |
857 | axe_attach(device_t parent, device_t self, void *aux) | | 859 | axe_attach(device_t parent, device_t self, void *aux) |
858 | { | | 860 | { |
859 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 861 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
860 | struct axe_softc *sc = device_private(self); | | 862 | struct axe_softc *sc = device_private(self); |
861 | struct usb_attach_arg *uaa = aux; | | 863 | struct usb_attach_arg *uaa = aux; |
862 | struct usbd_device *dev = uaa->uaa_device; | | 864 | struct usbd_device *dev = uaa->uaa_device; |
863 | usbd_status err; | | 865 | usbd_status err; |
864 | usb_interface_descriptor_t *id; | | 866 | usb_interface_descriptor_t *id; |
865 | usb_endpoint_descriptor_t *ed; | | 867 | usb_endpoint_descriptor_t *ed; |
866 | struct mii_data *mii; | | 868 | struct mii_data *mii; |
867 | char *devinfop; | | 869 | char *devinfop; |
868 | const char *devname = device_xname(self); | | 870 | const char *devname = device_xname(self); |
869 | struct ifnet *ifp; | | 871 | struct ifnet *ifp; |
870 | int i, s; | | 872 | int i, s; |
871 | | | 873 | |
872 | aprint_naive("\n"); | | 874 | aprint_naive("\n"); |
873 | aprint_normal("\n"); | | 875 | aprint_normal("\n"); |
874 | | | 876 | |
875 | sc->axe_dev = self; | | 877 | sc->axe_dev = self; |
876 | sc->axe_udev = dev; | | 878 | sc->axe_udev = dev; |
877 | | | 879 | |
878 | devinfop = usbd_devinfo_alloc(dev, 0); | | 880 | devinfop = usbd_devinfo_alloc(dev, 0); |
879 | aprint_normal_dev(self, "%s\n", devinfop); | | 881 | aprint_normal_dev(self, "%s\n", devinfop); |
880 | usbd_devinfo_free(devinfop); | | 882 | usbd_devinfo_free(devinfop); |
881 | | | 883 | |
882 | err = usbd_set_config_no(dev, AXE_CONFIG_NO, 1); | | 884 | err = usbd_set_config_no(dev, AXE_CONFIG_NO, 1); |
883 | if (err) { | | 885 | if (err) { |
884 | aprint_error_dev(self, "failed to set configuration" | | 886 | aprint_error_dev(self, "failed to set configuration" |
885 | ", err=%s\n", usbd_errstr(err)); | | 887 | ", err=%s\n", usbd_errstr(err)); |
886 | return; | | 888 | return; |
887 | } | | 889 | } |
888 | | | 890 | |
889 | sc->axe_flags = axe_lookup(uaa->uaa_vendor, uaa->uaa_product)->axe_flags; | | 891 | sc->axe_flags = axe_lookup(uaa->uaa_vendor, uaa->uaa_product)->axe_flags; |
890 | | | 892 | |
891 | mutex_init(&sc->axe_mii_lock, MUTEX_DEFAULT, IPL_NONE); | | 893 | mutex_init(&sc->axe_mii_lock, MUTEX_DEFAULT, IPL_NONE); |
892 | usb_init_task(&sc->axe_tick_task, axe_tick_task, sc, 0); | | 894 | usb_init_task(&sc->axe_tick_task, axe_tick_task, sc, 0); |
893 | | | 895 | |
894 | err = usbd_device2interface_handle(dev, AXE_IFACE_IDX, &sc->axe_iface); | | 896 | err = usbd_device2interface_handle(dev, AXE_IFACE_IDX, &sc->axe_iface); |
895 | if (err) { | | 897 | if (err) { |
896 | aprint_error_dev(self, "getting interface handle failed\n"); | | 898 | aprint_error_dev(self, "getting interface handle failed\n"); |
897 | return; | | 899 | return; |
898 | } | | 900 | } |
899 | | | 901 | |
900 | sc->axe_product = uaa->uaa_product; | | 902 | sc->axe_product = uaa->uaa_product; |
901 | sc->axe_vendor = uaa->uaa_vendor; | | 903 | sc->axe_vendor = uaa->uaa_vendor; |
902 | | | 904 | |
903 | id = usbd_get_interface_descriptor(sc->axe_iface); | | 905 | id = usbd_get_interface_descriptor(sc->axe_iface); |
904 | | | 906 | |
905 | /* decide on what our bufsize will be */ | | 907 | /* decide on what our bufsize will be */ |
906 | if (AXE_IS_178_FAMILY(sc)) | | 908 | if (AXE_IS_178_FAMILY(sc)) |
907 | sc->axe_bufsz = (sc->axe_udev->ud_speed == USB_SPEED_HIGH) ? | | 909 | sc->axe_bufsz = (sc->axe_udev->ud_speed == USB_SPEED_HIGH) ? |
908 | AXE_178_MAX_BUFSZ : AXE_178_MIN_BUFSZ; | | 910 | AXE_178_MAX_BUFSZ : AXE_178_MIN_BUFSZ; |
909 | else | | 911 | else |
910 | sc->axe_bufsz = AXE_172_BUFSZ; | | 912 | sc->axe_bufsz = AXE_172_BUFSZ; |
911 | | | 913 | |
912 | sc->axe_ed[AXE_ENDPT_RX] = -1; | | 914 | sc->axe_ed[AXE_ENDPT_RX] = -1; |
913 | sc->axe_ed[AXE_ENDPT_TX] = -1; | | 915 | sc->axe_ed[AXE_ENDPT_TX] = -1; |
914 | sc->axe_ed[AXE_ENDPT_INTR] = -1; | | 916 | sc->axe_ed[AXE_ENDPT_INTR] = -1; |
915 | | | 917 | |
916 | /* Find endpoints. */ | | 918 | /* Find endpoints. */ |
917 | for (i = 0; i < id->bNumEndpoints; i++) { | | 919 | for (i = 0; i < id->bNumEndpoints; i++) { |
918 | ed = usbd_interface2endpoint_descriptor(sc->axe_iface, i); | | 920 | ed = usbd_interface2endpoint_descriptor(sc->axe_iface, i); |
919 | if (ed == NULL) { | | 921 | if (ed == NULL) { |
920 | aprint_error_dev(self, "couldn't get ep %d\n", i); | | 922 | aprint_error_dev(self, "couldn't get ep %d\n", i); |
921 | return; | | 923 | return; |
922 | } | | 924 | } |
923 | const uint8_t xt = UE_GET_XFERTYPE(ed->bmAttributes); | | 925 | const uint8_t xt = UE_GET_XFERTYPE(ed->bmAttributes); |
924 | const uint8_t dir = UE_GET_DIR(ed->bEndpointAddress); | | 926 | const uint8_t dir = UE_GET_DIR(ed->bEndpointAddress); |
925 | | | 927 | |
926 | if (dir == UE_DIR_IN && xt == UE_BULK && | | 928 | if (dir == UE_DIR_IN && xt == UE_BULK && |
927 | sc->axe_ed[AXE_ENDPT_RX] == -1) { | | 929 | sc->axe_ed[AXE_ENDPT_RX] == -1) { |
928 | sc->axe_ed[AXE_ENDPT_RX] = ed->bEndpointAddress; | | 930 | sc->axe_ed[AXE_ENDPT_RX] = ed->bEndpointAddress; |
929 | } else if (dir == UE_DIR_OUT && xt == UE_BULK && | | 931 | } else if (dir == UE_DIR_OUT && xt == UE_BULK && |
930 | sc->axe_ed[AXE_ENDPT_TX] == -1) { | | 932 | sc->axe_ed[AXE_ENDPT_TX] == -1) { |
931 | sc->axe_ed[AXE_ENDPT_TX] = ed->bEndpointAddress; | | 933 | sc->axe_ed[AXE_ENDPT_TX] = ed->bEndpointAddress; |
932 | } else if (dir == UE_DIR_IN && xt == UE_INTERRUPT) { | | 934 | } else if (dir == UE_DIR_IN && xt == UE_INTERRUPT) { |
933 | sc->axe_ed[AXE_ENDPT_INTR] = ed->bEndpointAddress; | | 935 | sc->axe_ed[AXE_ENDPT_INTR] = ed->bEndpointAddress; |
934 | } | | 936 | } |
935 | } | | 937 | } |
936 | | | 938 | |
937 | s = splnet(); | | 939 | s = splnet(); |
938 | | | 940 | |
939 | /* We need the PHYID for init dance in some cases */ | | 941 | /* We need the PHYID for init dance in some cases */ |
940 | axe_lock_mii(sc); | | 942 | axe_lock_mii(sc); |
941 | axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, (void *)&sc->axe_phyaddrs); | | 943 | axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, (void *)&sc->axe_phyaddrs); |
942 | | | 944 | |
943 | DPRINTF(" phyaddrs[0]: %x phyaddrs[1]: %x", | | 945 | DPRINTF(" phyaddrs[0]: %x phyaddrs[1]: %x", |
944 | sc->axe_phyaddrs[0], sc->axe_phyaddrs[1], 0, 0); | | 946 | sc->axe_phyaddrs[0], sc->axe_phyaddrs[1], 0, 0); |
945 | sc->axe_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI); | | 947 | sc->axe_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI); |
946 | if (sc->axe_phyno == -1) | | 948 | if (sc->axe_phyno == -1) |
947 | sc->axe_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC); | | 949 | sc->axe_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC); |
948 | if (sc->axe_phyno == -1) { | | 950 | if (sc->axe_phyno == -1) { |
949 | DPRINTF(" no valid PHY address found, assuming PHY address 0", | | 951 | DPRINTF(" no valid PHY address found, assuming PHY address 0", |
950 | 0, 0, 0, 0); | | 952 | 0, 0, 0, 0); |
951 | sc->axe_phyno = 0; | | 953 | sc->axe_phyno = 0; |
952 | } | | 954 | } |
953 | | | 955 | |
954 | /* Initialize controller and get station address. */ | | 956 | /* Initialize controller and get station address. */ |
955 | | | 957 | |
956 | if (sc->axe_flags & AX178) { | | 958 | if (sc->axe_flags & AX178) { |
957 | axe_ax88178_init(sc); | | 959 | axe_ax88178_init(sc); |
958 | axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, sc->axe_enaddr); | | 960 | axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, sc->axe_enaddr); |
959 | } else if (sc->axe_flags & AX772) { | | 961 | } else if (sc->axe_flags & AX772) { |
960 | axe_ax88772_init(sc); | | 962 | axe_ax88772_init(sc); |
961 | axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, sc->axe_enaddr); | | 963 | axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, sc->axe_enaddr); |
962 | } else if (sc->axe_flags & AX772A) { | | 964 | } else if (sc->axe_flags & AX772A) { |
963 | axe_ax88772a_init(sc); | | 965 | axe_ax88772a_init(sc); |
964 | axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, sc->axe_enaddr); | | 966 | axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, sc->axe_enaddr); |
965 | } else if (sc->axe_flags & AX772B) { | | 967 | } else if (sc->axe_flags & AX772B) { |
966 | axe_ax88772b_init(sc); | | 968 | axe_ax88772b_init(sc); |
967 | } else | | 969 | } else |
968 | axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, sc->axe_enaddr); | | 970 | axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, sc->axe_enaddr); |
969 | | | 971 | |
970 | /* | | 972 | /* |
971 | * Fetch IPG values. | | 973 | * Fetch IPG values. |
972 | */ | | 974 | */ |
973 | if (sc->axe_flags & (AX772A | AX772B)) { | | 975 | if (sc->axe_flags & (AX772A | AX772B)) { |
974 | /* Set IPG values. */ | | 976 | /* Set IPG values. */ |
975 | sc->axe_ipgs[0] = AXE_IPG0_DEFAULT; | | 977 | sc->axe_ipgs[0] = AXE_IPG0_DEFAULT; |
976 | sc->axe_ipgs[1] = AXE_IPG1_DEFAULT; | | 978 | sc->axe_ipgs[1] = AXE_IPG1_DEFAULT; |
977 | sc->axe_ipgs[2] = AXE_IPG2_DEFAULT; | | 979 | sc->axe_ipgs[2] = AXE_IPG2_DEFAULT; |
978 | } else | | 980 | } else |
979 | axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->axe_ipgs); | | 981 | axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->axe_ipgs); |
980 | | | 982 | |
981 | axe_unlock_mii(sc); | | 983 | axe_unlock_mii(sc); |
982 | | | 984 | |
983 | /* | | 985 | /* |
984 | * An ASIX chip was detected. Inform the world. | | 986 | * An ASIX chip was detected. Inform the world. |
985 | */ | | 987 | */ |
986 | aprint_normal_dev(self, "Ethernet address %s\n", | | 988 | aprint_normal_dev(self, "Ethernet address %s\n", |
987 | ether_sprintf(sc->axe_enaddr)); | | 989 | ether_sprintf(sc->axe_enaddr)); |
988 | | | 990 | |
989 | /* Initialize interface info.*/ | | 991 | /* Initialize interface info.*/ |
990 | ifp = &sc->sc_if; | | 992 | ifp = &sc->sc_if; |
991 | ifp->if_softc = sc; | | 993 | ifp->if_softc = sc; |
992 | strlcpy(ifp->if_xname, devname, IFNAMSIZ); | | 994 | strlcpy(ifp->if_xname, devname, IFNAMSIZ); |
993 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | | 995 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; |
994 | ifp->if_ioctl = axe_ioctl; | | 996 | ifp->if_ioctl = axe_ioctl; |
995 | ifp->if_start = axe_start; | | 997 | ifp->if_start = axe_start; |
996 | ifp->if_init = axe_init; | | 998 | ifp->if_init = axe_init; |
997 | ifp->if_stop = axe_stop; | | 999 | ifp->if_stop = axe_stop; |
998 | ifp->if_watchdog = axe_watchdog; | | 1000 | ifp->if_watchdog = axe_watchdog; |
999 | | | 1001 | |
1000 | IFQ_SET_READY(&ifp->if_snd); | | 1002 | IFQ_SET_READY(&ifp->if_snd); |
1001 | | | 1003 | |
1002 | if (AXE_IS_178_FAMILY(sc)) | | 1004 | if (AXE_IS_178_FAMILY(sc)) |
1003 | sc->axe_ec.ec_capabilities = ETHERCAP_VLAN_MTU; | | 1005 | sc->axe_ec.ec_capabilities = ETHERCAP_VLAN_MTU; |
1004 | if (sc->axe_flags & AX772B) { | | 1006 | if (sc->axe_flags & AX772B) { |
1005 | ifp->if_capabilities = | | 1007 | ifp->if_capabilities = |
1006 | IFCAP_CSUM_IPv4_Rx | | | 1008 | IFCAP_CSUM_IPv4_Rx | |
1007 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | | 1009 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | |
1008 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; | | 1010 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; |
1009 | /* | | 1011 | /* |
1010 | * Checksum offloading of AX88772B also works with VLAN | | 1012 | * Checksum offloading of AX88772B also works with VLAN |
1011 | * tagged frames but there is no way to take advantage | | 1013 | * tagged frames but there is no way to take advantage |
1012 | * of the feature because vlan(4) assumes | | 1014 | * of the feature because vlan(4) assumes |
1013 | * IFCAP_VLAN_HWTAGGING is prerequisite condition to | | 1015 | * IFCAP_VLAN_HWTAGGING is prerequisite condition to |
1014 | * support checksum offloading with VLAN. VLAN hardware | | 1016 | * support checksum offloading with VLAN. VLAN hardware |
1015 | * tagging support of AX88772B is very limited so it's | | 1017 | * tagging support of AX88772B is very limited so it's |
1016 | * not possible to announce IFCAP_VLAN_HWTAGGING. | | 1018 | * not possible to announce IFCAP_VLAN_HWTAGGING. |
1017 | */ | | 1019 | */ |
1018 | } | | 1020 | } |
1019 | u_int adv_pause; | | 1021 | u_int adv_pause; |
1020 | if (sc->axe_flags & (AX772A | AX772B | AX178)) | | 1022 | if (sc->axe_flags & (AX772A | AX772B | AX178)) |
1021 | adv_pause = MIIF_DOPAUSE; | | 1023 | adv_pause = MIIF_DOPAUSE; |
1022 | else | | 1024 | else |
1023 | adv_pause = 0; | | 1025 | adv_pause = 0; |
1024 | adv_pause = 0; | | 1026 | adv_pause = 0; |
1025 | | | 1027 | |
1026 | /* Initialize MII/media info. */ | | 1028 | /* Initialize MII/media info. */ |
1027 | mii = &sc->axe_mii; | | 1029 | mii = &sc->axe_mii; |
1028 | mii->mii_ifp = ifp; | | 1030 | mii->mii_ifp = ifp; |
1029 | mii->mii_readreg = axe_miibus_readreg; | | 1031 | mii->mii_readreg = axe_miibus_readreg; |
1030 | mii->mii_writereg = axe_miibus_writereg; | | 1032 | mii->mii_writereg = axe_miibus_writereg; |
1031 | mii->mii_statchg = axe_miibus_statchg; | | 1033 | mii->mii_statchg = axe_miibus_statchg; |
1032 | mii->mii_flags = MIIF_AUTOTSLEEP; | | 1034 | mii->mii_flags = MIIF_AUTOTSLEEP; |
1033 | | | 1035 | |
1034 | sc->axe_ec.ec_mii = mii; | | 1036 | sc->axe_ec.ec_mii = mii; |
1035 | ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus); | | 1037 | ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus); |
1036 | | | 1038 | |
1037 | mii_attach(sc->axe_dev, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, | | 1039 | mii_attach(sc->axe_dev, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, |
1038 | adv_pause); | | 1040 | adv_pause); |
1039 | | | 1041 | |
1040 | if (LIST_EMPTY(&mii->mii_phys)) { | | 1042 | if (LIST_EMPTY(&mii->mii_phys)) { |
1041 | ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL); | | 1043 | ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL); |
1042 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE); | | 1044 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE); |
1043 | } else | | 1045 | } else |
1044 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); | | 1046 | ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO); |
1045 | | | 1047 | |
1046 | /* Attach the interface. */ | | 1048 | /* Attach the interface. */ |
1047 | if_attach(ifp); | | 1049 | if_attach(ifp); |
1048 | ether_ifattach(ifp, sc->axe_enaddr); | | 1050 | ether_ifattach(ifp, sc->axe_enaddr); |
1049 | rnd_attach_source(&sc->rnd_source, device_xname(sc->axe_dev), | | 1051 | rnd_attach_source(&sc->rnd_source, device_xname(sc->axe_dev), |
1050 | RND_TYPE_NET, RND_FLAG_DEFAULT); | | 1052 | RND_TYPE_NET, RND_FLAG_DEFAULT); |
1051 | | | 1053 | |
1052 | callout_init(&sc->axe_stat_ch, 0); | | 1054 | callout_init(&sc->axe_stat_ch, 0); |
1053 | callout_setfunc(&sc->axe_stat_ch, axe_tick, sc); | | 1055 | callout_setfunc(&sc->axe_stat_ch, axe_tick, sc); |
1054 | | | 1056 | |
1055 | sc->axe_attached = true; | | 1057 | sc->axe_attached = true; |
1056 | splx(s); | | 1058 | splx(s); |
1057 | | | 1059 | |
1058 | usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->axe_udev, sc->axe_dev); | | 1060 | usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->axe_udev, sc->axe_dev); |
1059 | | | 1061 | |
1060 | if (!pmf_device_register(self, NULL, NULL)) | | 1062 | if (!pmf_device_register(self, NULL, NULL)) |
1061 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 1063 | aprint_error_dev(self, "couldn't establish power handler\n"); |
1062 | } | | 1064 | } |
1063 | | | 1065 | |
1064 | int | | 1066 | int |
1065 | axe_detach(device_t self, int flags) | | 1067 | axe_detach(device_t self, int flags) |
1066 | { | | 1068 | { |
1067 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 1069 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
1068 | struct axe_softc *sc = device_private(self); | | 1070 | struct axe_softc *sc = device_private(self); |
1069 | int s; | | 1071 | int s; |
1070 | struct ifnet *ifp = &sc->sc_if; | | 1072 | struct ifnet *ifp = &sc->sc_if; |
1071 | | | 1073 | |
1072 | /* Detached before attached finished, so just bail out. */ | | 1074 | /* Detached before attached finished, so just bail out. */ |
1073 | if (!sc->axe_attached) | | 1075 | if (!sc->axe_attached) |
1074 | return 0; | | 1076 | return 0; |
1075 | | | 1077 | |
1076 | pmf_device_deregister(self); | | 1078 | pmf_device_deregister(self); |
1077 | | | 1079 | |
1078 | sc->axe_dying = true; | | 1080 | sc->axe_dying = true; |
1079 | | | 1081 | |
1080 | if (sc->axe_ep[AXE_ENDPT_TX] != NULL) | | 1082 | if (sc->axe_ep[AXE_ENDPT_TX] != NULL) |
1081 | usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_TX]); | | 1083 | usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_TX]); |
1082 | if (sc->axe_ep[AXE_ENDPT_RX] != NULL) | | 1084 | if (sc->axe_ep[AXE_ENDPT_RX] != NULL) |
1083 | usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_RX]); | | 1085 | usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_RX]); |
1084 | if (sc->axe_ep[AXE_ENDPT_INTR] != NULL) | | 1086 | if (sc->axe_ep[AXE_ENDPT_INTR] != NULL) |
1085 | usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_INTR]); | | 1087 | usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_INTR]); |
1086 | | | 1088 | |
1087 | /* | | 1089 | /* |
1088 | * Remove any pending tasks. They cannot be executing because they run | | 1090 | * Remove any pending tasks. They cannot be executing because they run |
1089 | * in the same thread as detach. | | 1091 | * in the same thread as detach. |
1090 | */ | | 1092 | */ |
1091 | usb_rem_task(sc->axe_udev, &sc->axe_tick_task); | | 1093 | usb_rem_task(sc->axe_udev, &sc->axe_tick_task); |
1092 | | | 1094 | |
1093 | s = splusb(); | | 1095 | s = splusb(); |
1094 | | | 1096 | |
1095 | if (ifp->if_flags & IFF_RUNNING) | | 1097 | if (ifp->if_flags & IFF_RUNNING) |
1096 | axe_stop(ifp, 1); | | 1098 | axe_stop(ifp, 1); |
1097 | | | 1099 | |
1098 | | | 1100 | |
1099 | if (--sc->axe_refcnt >= 0) { | | 1101 | if (--sc->axe_refcnt >= 0) { |
1100 | /* Wait for processes to go away. */ | | 1102 | /* Wait for processes to go away. */ |
1101 | usb_detach_waitold(sc->axe_dev); | | 1103 | usb_detach_waitold(sc->axe_dev); |
1102 | } | | 1104 | } |
1103 | | | 1105 | |
1104 | callout_destroy(&sc->axe_stat_ch); | | 1106 | callout_destroy(&sc->axe_stat_ch); |
1105 | mutex_destroy(&sc->axe_mii_lock); | | 1107 | mutex_destroy(&sc->axe_mii_lock); |
1106 | rnd_detach_source(&sc->rnd_source); | | 1108 | rnd_detach_source(&sc->rnd_source); |
1107 | mii_detach(&sc->axe_mii, MII_PHY_ANY, MII_OFFSET_ANY); | | 1109 | mii_detach(&sc->axe_mii, MII_PHY_ANY, MII_OFFSET_ANY); |
1108 | ifmedia_delete_instance(&sc->axe_mii.mii_media, IFM_INST_ANY); | | 1110 | ifmedia_delete_instance(&sc->axe_mii.mii_media, IFM_INST_ANY); |
1109 | ether_ifdetach(ifp); | | 1111 | ether_ifdetach(ifp); |
1110 | if_detach(ifp); | | 1112 | if_detach(ifp); |
1111 | | | 1113 | |
1112 | #ifdef DIAGNOSTIC | | 1114 | #ifdef DIAGNOSTIC |
1113 | if (sc->axe_ep[AXE_ENDPT_TX] != NULL || | | 1115 | if (sc->axe_ep[AXE_ENDPT_TX] != NULL || |
1114 | sc->axe_ep[AXE_ENDPT_RX] != NULL || | | 1116 | sc->axe_ep[AXE_ENDPT_RX] != NULL || |
1115 | sc->axe_ep[AXE_ENDPT_INTR] != NULL) | | 1117 | sc->axe_ep[AXE_ENDPT_INTR] != NULL) |
1116 | aprint_debug_dev(self, "detach has active endpoints\n"); | | 1118 | aprint_debug_dev(self, "detach has active endpoints\n"); |
1117 | #endif | | 1119 | #endif |
1118 | | | 1120 | |
1119 | sc->axe_attached = false; | | 1121 | sc->axe_attached = false; |
1120 | | | 1122 | |
1121 | splx(s); | | 1123 | splx(s); |
1122 | | | 1124 | |
1123 | usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->axe_udev, sc->axe_dev); | | 1125 | usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->axe_udev, sc->axe_dev); |
1124 | | | 1126 | |
1125 | return 0; | | 1127 | return 0; |
1126 | } | | 1128 | } |
1127 | | | 1129 | |
1128 | int | | 1130 | int |
1129 | axe_activate(device_t self, devact_t act) | | 1131 | axe_activate(device_t self, devact_t act) |
1130 | { | | 1132 | { |
1131 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 1133 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
1132 | struct axe_softc *sc = device_private(self); | | 1134 | struct axe_softc *sc = device_private(self); |
1133 | | | 1135 | |
1134 | switch (act) { | | 1136 | switch (act) { |
1135 | case DVACT_DEACTIVATE: | | 1137 | case DVACT_DEACTIVATE: |
1136 | if_deactivate(&sc->axe_ec.ec_if); | | 1138 | if_deactivate(&sc->axe_ec.ec_if); |
1137 | sc->axe_dying = true; | | 1139 | sc->axe_dying = true; |
1138 | return 0; | | 1140 | return 0; |
1139 | default: | | 1141 | default: |
1140 | return EOPNOTSUPP; | | 1142 | return EOPNOTSUPP; |
1141 | } | | 1143 | } |
1142 | } | | 1144 | } |
1143 | | | 1145 | |
1144 | static int | | 1146 | static int |
1145 | axe_rx_list_init(struct axe_softc *sc) | | 1147 | axe_rx_list_init(struct axe_softc *sc) |
1146 | { | | 1148 | { |
1147 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 1149 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
1148 | | | 1150 | |
1149 | struct axe_cdata *cd; | | 1151 | struct axe_cdata *cd; |
1150 | struct axe_chain *c; | | 1152 | struct axe_chain *c; |
1151 | int i; | | 1153 | int i; |
1152 | | | 1154 | |
1153 | cd = &sc->axe_cdata; | | 1155 | cd = &sc->axe_cdata; |
1154 | for (i = 0; i < AXE_RX_LIST_CNT; i++) { | | 1156 | for (i = 0; i < AXE_RX_LIST_CNT; i++) { |
1155 | c = &cd->axe_rx_chain[i]; | | 1157 | c = &cd->axe_rx_chain[i]; |
1156 | c->axe_sc = sc; | | 1158 | c->axe_sc = sc; |
1157 | c->axe_idx = i; | | 1159 | c->axe_idx = i; |
1158 | if (c->axe_xfer == NULL) { | | 1160 | if (c->axe_xfer == NULL) { |
1159 | int err = usbd_create_xfer(sc->axe_ep[AXE_ENDPT_RX], | | 1161 | int err = usbd_create_xfer(sc->axe_ep[AXE_ENDPT_RX], |
1160 | sc->axe_bufsz, USBD_SHORT_XFER_OK, 0, &c->axe_xfer); | | 1162 | sc->axe_bufsz, USBD_SHORT_XFER_OK, 0, &c->axe_xfer); |
1161 | if (err) | | 1163 | if (err) |
1162 | return err; | | 1164 | return err; |
1163 | c->axe_buf = usbd_get_buffer(c->axe_xfer); | | 1165 | c->axe_buf = usbd_get_buffer(c->axe_xfer); |
1164 | } | | 1166 | } |
1165 | } | | 1167 | } |
1166 | | | 1168 | |
1167 | return 0; | | 1169 | return 0; |
1168 | } | | 1170 | } |
1169 | | | 1171 | |
1170 | static int | | 1172 | static int |
1171 | axe_tx_list_init(struct axe_softc *sc) | | 1173 | axe_tx_list_init(struct axe_softc *sc) |
1172 | { | | 1174 | { |
1173 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 1175 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
1174 | struct axe_cdata *cd; | | 1176 | struct axe_cdata *cd; |
1175 | struct axe_chain *c; | | 1177 | struct axe_chain *c; |
1176 | int i; | | 1178 | int i; |
1177 | | | 1179 | |
1178 | cd = &sc->axe_cdata; | | 1180 | cd = &sc->axe_cdata; |
1179 | for (i = 0; i < AXE_TX_LIST_CNT; i++) { | | 1181 | for (i = 0; i < AXE_TX_LIST_CNT; i++) { |
1180 | c = &cd->axe_tx_chain[i]; | | 1182 | c = &cd->axe_tx_chain[i]; |
1181 | c->axe_sc = sc; | | 1183 | c->axe_sc = sc; |
1182 | c->axe_idx = i; | | 1184 | c->axe_idx = i; |
1183 | if (c->axe_xfer == NULL) { | | 1185 | if (c->axe_xfer == NULL) { |
1184 | int err = usbd_create_xfer(sc->axe_ep[AXE_ENDPT_TX], | | 1186 | int err = usbd_create_xfer(sc->axe_ep[AXE_ENDPT_TX], |
1185 | sc->axe_bufsz, USBD_FORCE_SHORT_XFER, 0, | | 1187 | sc->axe_bufsz, USBD_FORCE_SHORT_XFER, 0, |
1186 | &c->axe_xfer); | | 1188 | &c->axe_xfer); |
1187 | if (err) | | 1189 | if (err) |
1188 | return err; | | 1190 | return err; |
1189 | c->axe_buf = usbd_get_buffer(c->axe_xfer); | | 1191 | c->axe_buf = usbd_get_buffer(c->axe_xfer); |
1190 | } | | 1192 | } |
1191 | } | | 1193 | } |
1192 | | | 1194 | |
1193 | return 0; | | 1195 | return 0; |
1194 | } | | 1196 | } |
1195 | | | 1197 | |
1196 | /* | | 1198 | /* |
1197 | * A frame has been uploaded: pass the resulting mbuf chain up to | | 1199 | * A frame has been uploaded: pass the resulting mbuf chain up to |
1198 | * the higher level protocols. | | 1200 | * the higher level protocols. |
1199 | */ | | 1201 | */ |
1200 | static void | | 1202 | static void |
1201 | axe_rxeof(struct usbd_xfer *xfer, void * priv, usbd_status status) | | 1203 | axe_rxeof(struct usbd_xfer *xfer, void * priv, usbd_status status) |
1202 | { | | 1204 | { |
1203 | AXEHIST_FUNC(); AXEHIST_CALLED(); | | 1205 | AXEHIST_FUNC(); AXEHIST_CALLED(); |
1204 | struct axe_softc *sc; | | 1206 | struct axe_softc *sc; |
1205 | struct axe_chain *c; | | 1207 | struct axe_chain *c; |
1206 | struct ifnet *ifp; | | 1208 | struct ifnet *ifp; |
1207 | uint8_t *buf; | | 1209 | uint8_t *buf; |
1208 | uint32_t total_len; | | 1210 | uint32_t total_len; |
1209 | struct mbuf *m; | | 1211 | struct mbuf *m; |
1210 | int s; | | 1212 | int s; |
1211 | | | 1213 | |
1212 | c = (struct axe_chain *)priv; | | 1214 | c = (struct axe_chain *)priv; |
1213 | sc = c->axe_sc; | | 1215 | sc = c->axe_sc; |
1214 | buf = c->axe_buf; | | 1216 | buf = c->axe_buf; |
1215 | ifp = &sc->sc_if; | | 1217 | ifp = &sc->sc_if; |
1216 | | | 1218 | |
1217 | if (sc->axe_dying) | | 1219 | if (sc->axe_dying) |
1218 | return; | | 1220 | return; |
1219 | | | 1221 | |
1220 | if ((ifp->if_flags & IFF_RUNNING) == 0) | | 1222 | if ((ifp->if_flags & IFF_RUNNING) == 0) |
1221 | return; | | 1223 | return; |
1222 | | | 1224 | |
1223 | if (status != USBD_NORMAL_COMPLETION) { | | 1225 | if (status != USBD_NORMAL_COMPLETION) { |
1224 | if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) | | 1226 | if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) |
1225 | return; | | 1227 | return; |
1226 | if (usbd_ratecheck(&sc->axe_rx_notice)) { | | 1228 | if (usbd_ratecheck(&sc->axe_rx_notice)) { |
1227 | aprint_error_dev(sc->axe_dev, "usb errors on rx: %s\n", | | 1229 | aprint_error_dev(sc->axe_dev, "usb errors on rx: %s\n", |
1228 | usbd_errstr(status)); | | 1230 | usbd_errstr(status)); |
1229 | } | | 1231 | } |
1230 | if (status == USBD_STALLED) | | 1232 | if (status == USBD_STALLED) |
1231 | usbd_clear_endpoint_stall_async(sc->axe_ep[AXE_ENDPT_RX]); | | 1233 | usbd_clear_endpoint_stall_async(sc->axe_ep[AXE_ENDPT_RX]); |
1232 | goto done; | | 1234 | goto done; |
1233 | } | | 1235 | } |
1234 | | | 1236 | |
1235 | usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); | | 1237 | usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); |
1236 | | | 1238 | |
1237 | do { | | 1239 | do { |
1238 | u_int pktlen = 0; | | 1240 | u_int pktlen = 0; |
1239 | u_int rxlen = 0; | | 1241 | u_int rxlen = 0; |
1240 | int flags = 0; | | 1242 | int flags = 0; |
1241 | if ((sc->axe_flags & AXSTD_FRAME) != 0) { | | 1243 | if ((sc->axe_flags & AXSTD_FRAME) != 0) { |
1242 | struct axe_sframe_hdr hdr; | | 1244 | struct axe_sframe_hdr hdr; |
1243 | | | 1245 | |
1244 | if (total_len < sizeof(hdr)) { | | 1246 | if (total_len < sizeof(hdr)) { |
1245 | ifp->if_ierrors++; | | 1247 | ifp->if_ierrors++; |
1246 | goto done; | | 1248 | goto done; |
1247 | } | | 1249 | } |
1248 | | | 1250 | |
1249 | memcpy(&hdr, buf, sizeof(hdr)); | | 1251 | memcpy(&hdr, buf, sizeof(hdr)); |
1250 | | | 1252 | |
1251 | DPRINTFN(20, "total_len %#x len %x ilen %#x", | | 1253 | DPRINTFN(20, "total_len %#x len %x ilen %#x", |
1252 | total_len, | | 1254 | total_len, |
1253 | (le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK), | | 1255 | (le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK), |
1254 | (le16toh(hdr.ilen) & AXE_RH1M_RXLEN_MASK), 0); | | 1256 | (le16toh(hdr.ilen) & AXE_RH1M_RXLEN_MASK), 0); |
1255 | | | 1257 | |
1256 | total_len -= sizeof(hdr); | | 1258 | total_len -= sizeof(hdr); |
1257 | buf += sizeof(hdr); | | 1259 | buf += sizeof(hdr); |
1258 | | | 1260 | |
1259 | if (((le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK) ^ | | 1261 | if (((le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK) ^ |
1260 | (le16toh(hdr.ilen) & AXE_RH1M_RXLEN_MASK)) != | | 1262 | (le16toh(hdr.ilen) & AXE_RH1M_RXLEN_MASK)) != |
1261 | AXE_RH1M_RXLEN_MASK) { | | 1263 | AXE_RH1M_RXLEN_MASK) { |
1262 | ifp->if_ierrors++; | | 1264 | ifp->if_ierrors++; |
1263 | goto done; | | 1265 | goto done; |
1264 | } | | 1266 | } |
1265 | | | 1267 | |
1266 | rxlen = le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK; | | 1268 | rxlen = le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK; |
1267 | if (total_len < rxlen) { | | 1269 | if (total_len < rxlen) { |
1268 | pktlen = total_len; | | 1270 | pktlen = total_len; |
1269 | total_len = 0; | | 1271 | total_len = 0; |
1270 | } else { | | 1272 | } else { |
1271 | pktlen = rxlen; | | 1273 | pktlen = rxlen; |
1272 | rxlen = roundup2(rxlen, 2); | | 1274 | rxlen = roundup2(rxlen, 2); |
1273 | total_len -= rxlen; | | 1275 | total_len -= rxlen; |