usbnet drivers: Stop timeout loops early if device is detaching.diff -r1.172 -r1.173 src/sys/dev/usb/if_aue.c
(riastradh)
--- src/sys/dev/usb/if_aue.c 2022/03/03 05:50:22 1.172
+++ src/sys/dev/usb/if_aue.c 2022/03/03 05:50:57 1.173
@@ -1,1052 +1,1058 @@ | @@ -1,1052 +1,1058 @@ | |||
1 | /* $NetBSD: if_aue.c,v 1.172 2022/03/03 05:50:22 riastradh Exp $ */ | 1 | /* $NetBSD: if_aue.c,v 1.173 2022/03/03 05:50:57 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_aue.c,v 1.11 2000/01/14 01:36:14 wpaul Exp $ | 34 | * $FreeBSD: src/sys/dev/usb/if_aue.c,v 1.11 2000/01/14 01:36:14 wpaul Exp $ | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | /* | 37 | /* | |
38 | * ADMtek AN986 Pegasus and AN8511 Pegasus II USB to ethernet driver. | 38 | * ADMtek AN986 Pegasus and AN8511 Pegasus II USB to ethernet driver. | |
39 | * Datasheet is available from http://www.admtek.com.tw. | 39 | * Datasheet is available from http://www.admtek.com.tw. | |
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 Pegasus chip uses four USB "endpoints" to provide 10/100 ethernet | 47 | * The Pegasus chip uses four USB "endpoints" to provide 10/100 ethernet | |
48 | * support: the control endpoint for reading/writing registers, burst | 48 | * support: the control endpoint for reading/writing registers, burst | |
49 | * read endpoint for packet reception, burst write for packet transmission | 49 | * read endpoint for packet reception, burst write for packet transmission | |
50 | * and one for "interrupts." The chip uses the same RX filter scheme | 50 | * and one for "interrupts." The chip uses the same RX filter scheme | |
51 | * as the other ADMtek ethernet parts: one perfect filter entry for the | 51 | * as the other ADMtek ethernet parts: one perfect filter entry for the | |
52 | * the station address and a 64-bit multicast hash table. The chip supports | 52 | * the station address and a 64-bit multicast hash table. The chip supports | |
53 | * both MII and HomePNA attachments. | 53 | * both MII and HomePNA attachments. | |
54 | * | 54 | * | |
55 | * Since the maximum data transfer speed of USB is supposed to be 12Mbps, | 55 | * Since the maximum data transfer speed of USB is supposed to be 12Mbps, | |
56 | * you're never really going to get 100Mbps speeds from this device. I | 56 | * you're never really going to get 100Mbps speeds from this device. I | |
57 | * think the idea is to allow the device to connect to 10 or 100Mbps | 57 | * think the idea is to allow the device to connect to 10 or 100Mbps | |
58 | * networks, not necessarily to provide 100Mbps performance. Also, since | 58 | * networks, not necessarily to provide 100Mbps performance. Also, since | |
59 | * the controller uses an external PHY chip, it's possible that board | 59 | * the controller uses an external PHY chip, it's possible that board | |
60 | * designers might simply choose a 10Mbps PHY. | 60 | * designers might simply choose a 10Mbps PHY. | |
61 | * | 61 | * | |
62 | * Registers are accessed using usbd_do_request(). Packet transfers are | 62 | * Registers are accessed using usbd_do_request(). Packet transfers are | |
63 | * done using usbd_transfer() and friends. | 63 | * done using usbd_transfer() and friends. | |
64 | */ | 64 | */ | |
65 | 65 | |||
66 | /* | 66 | /* | |
67 | * Ported to NetBSD and somewhat rewritten by Lennart Augustsson. | 67 | * Ported to NetBSD and somewhat rewritten by Lennart Augustsson. | |
68 | */ | 68 | */ | |
69 | 69 | |||
70 | /* | 70 | /* | |
71 | * TODO: | 71 | * TODO: | |
72 | * better error messages from rxstat | 72 | * better error messages from rxstat | |
73 | * more error checks | 73 | * more error checks | |
74 | * investigate short rx problem | 74 | * investigate short rx problem | |
75 | * proper cleanup on errors | 75 | * proper cleanup on errors | |
76 | */ | 76 | */ | |
77 | 77 | |||
78 | #include <sys/cdefs.h> | 78 | #include <sys/cdefs.h> | |
79 | __KERNEL_RCSID(0, "$NetBSD: if_aue.c,v 1.172 2022/03/03 05:50:22 riastradh Exp $"); | 79 | __KERNEL_RCSID(0, "$NetBSD: if_aue.c,v 1.173 2022/03/03 05:50:57 riastradh Exp $"); | |
80 | 80 | |||
81 | #ifdef _KERNEL_OPT | 81 | #ifdef _KERNEL_OPT | |
82 | #include "opt_usb.h" | 82 | #include "opt_usb.h" | |
83 | #include "opt_inet.h" | 83 | #include "opt_inet.h" | |
84 | #endif | 84 | #endif | |
85 | 85 | |||
86 | #include <sys/param.h> | 86 | #include <sys/param.h> | |
87 | 87 | |||
88 | #include <dev/usb/usbnet.h> | 88 | #include <dev/usb/usbnet.h> | |
89 | #include <dev/usb/usbhist.h> | 89 | #include <dev/usb/usbhist.h> | |
90 | #include <dev/usb/if_auereg.h> | 90 | #include <dev/usb/if_auereg.h> | |
91 | 91 | |||
92 | #ifdef INET | 92 | #ifdef INET | |
93 | #include <netinet/in.h> | 93 | #include <netinet/in.h> | |
94 | #include <netinet/if_inarp.h> | 94 | #include <netinet/if_inarp.h> | |
95 | #endif | 95 | #endif | |
96 | 96 | |||
97 | #ifdef USB_DEBUG | 97 | #ifdef USB_DEBUG | |
98 | #ifndef AUE_DEBUG | 98 | #ifndef AUE_DEBUG | |
99 | #define auedebug 0 | 99 | #define auedebug 0 | |
100 | #else | 100 | #else | |
101 | static int auedebug = 10; | 101 | static int auedebug = 10; | |
102 | 102 | |||
103 | SYSCTL_SETUP(sysctl_hw_aue_setup, "sysctl hw.aue setup") | 103 | SYSCTL_SETUP(sysctl_hw_aue_setup, "sysctl hw.aue setup") | |
104 | { | 104 | { | |
105 | int err; | 105 | int err; | |
106 | const struct sysctlnode *rnode; | 106 | const struct sysctlnode *rnode; | |
107 | const struct sysctlnode *cnode; | 107 | const struct sysctlnode *cnode; | |
108 | 108 | |||
109 | err = sysctl_createv(clog, 0, NULL, &rnode, | 109 | err = sysctl_createv(clog, 0, NULL, &rnode, | |
110 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "aue", | 110 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "aue", | |
111 | SYSCTL_DESCR("aue global controls"), | 111 | SYSCTL_DESCR("aue global controls"), | |
112 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | 112 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | |
113 | 113 | |||
114 | if (err) | 114 | if (err) | |
115 | goto fail; | 115 | goto fail; | |
116 | 116 | |||
117 | /* control debugging printfs */ | 117 | /* control debugging printfs */ | |
118 | err = sysctl_createv(clog, 0, &rnode, &cnode, | 118 | err = sysctl_createv(clog, 0, &rnode, &cnode, | |
119 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | 119 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | |
120 | "debug", SYSCTL_DESCR("Enable debugging output"), | 120 | "debug", SYSCTL_DESCR("Enable debugging output"), | |
121 | NULL, 0, &auedebug, sizeof(auedebug), CTL_CREATE, CTL_EOL); | 121 | NULL, 0, &auedebug, sizeof(auedebug), CTL_CREATE, CTL_EOL); | |
122 | if (err) | 122 | if (err) | |
123 | goto fail; | 123 | goto fail; | |
124 | 124 | |||
125 | return; | 125 | return; | |
126 | fail: | 126 | fail: | |
127 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | 127 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | |
128 | } | 128 | } | |
129 | 129 | |||
130 | #endif /* AUE_DEBUG */ | 130 | #endif /* AUE_DEBUG */ | |
131 | #endif /* USB_DEBUG */ | 131 | #endif /* USB_DEBUG */ | |
132 | 132 | |||
133 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(auedebug,1,FMT,A,B,C,D) | 133 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(auedebug,1,FMT,A,B,C,D) | |
134 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(auedebug,N,FMT,A,B,C,D) | 134 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(auedebug,N,FMT,A,B,C,D) | |
135 | #define AUEHIST_FUNC() USBHIST_FUNC() | 135 | #define AUEHIST_FUNC() USBHIST_FUNC() | |
136 | #define AUEHIST_CALLED(name) USBHIST_CALLED(auedebug) | 136 | #define AUEHIST_CALLED(name) USBHIST_CALLED(auedebug) | |
137 | #define AUEHIST_CALLARGS(FMT,A,B,C,D) \ | 137 | #define AUEHIST_CALLARGS(FMT,A,B,C,D) \ | |
138 | USBHIST_CALLARGS(auedebug,FMT,A,B,C,D) | 138 | USBHIST_CALLARGS(auedebug,FMT,A,B,C,D) | |
139 | #define AUEHIST_CALLARGSN(N,FMT,A,B,C,D) \ | 139 | #define AUEHIST_CALLARGSN(N,FMT,A,B,C,D) \ | |
140 | USBHIST_CALLARGSN(auedebug,N,FMT,A,B,C,D) | 140 | USBHIST_CALLARGSN(auedebug,N,FMT,A,B,C,D) | |
141 | 141 | |||
142 | #define AUE_TX_LIST_CNT 1 | 142 | #define AUE_TX_LIST_CNT 1 | |
143 | #define AUE_RX_LIST_CNT 1 | 143 | #define AUE_RX_LIST_CNT 1 | |
144 | 144 | |||
145 | struct aue_softc { | 145 | struct aue_softc { | |
146 | struct usbnet aue_un; | 146 | struct usbnet aue_un; | |
147 | struct usbnet_intr aue_intr; | 147 | struct usbnet_intr aue_intr; | |
148 | struct aue_intrpkt aue_ibuf; | 148 | struct aue_intrpkt aue_ibuf; | |
149 | }; | 149 | }; | |
150 | 150 | |||
151 | #define AUE_TIMEOUT 1000 | 151 | #define AUE_TIMEOUT 1000 | |
152 | #define AUE_BUFSZ 1536 | 152 | #define AUE_BUFSZ 1536 | |
153 | #define AUE_MIN_FRAMELEN 60 | 153 | #define AUE_MIN_FRAMELEN 60 | |
154 | #define AUE_TX_TIMEOUT 10000 /* ms */ | 154 | #define AUE_TX_TIMEOUT 10000 /* ms */ | |
155 | #define AUE_INTR_INTERVAL 100 /* ms */ | 155 | #define AUE_INTR_INTERVAL 100 /* ms */ | |
156 | 156 | |||
157 | /* | 157 | /* | |
158 | * Various supported device vendors/products. | 158 | * Various supported device vendors/products. | |
159 | */ | 159 | */ | |
160 | struct aue_type { | 160 | struct aue_type { | |
161 | struct usb_devno aue_dev; | 161 | struct usb_devno aue_dev; | |
162 | uint16_t aue_flags; | 162 | uint16_t aue_flags; | |
163 | #define LSYS 0x0001 /* use Linksys reset */ | 163 | #define LSYS 0x0001 /* use Linksys reset */ | |
164 | #define PNA 0x0002 /* has Home PNA */ | 164 | #define PNA 0x0002 /* has Home PNA */ | |
165 | #define PII 0x0004 /* Pegasus II chip */ | 165 | #define PII 0x0004 /* Pegasus II chip */ | |
166 | }; | 166 | }; | |
167 | 167 | |||
168 | static const struct aue_type aue_devs[] = { | 168 | static const struct aue_type aue_devs[] = { | |
169 | {{ USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460B}, PII }, | 169 | {{ USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460B}, PII }, | |
170 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX1}, PNA | PII }, | 170 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX1}, PNA | PII }, | |
171 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX2}, PII }, | 171 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX2}, PII }, | |
172 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE1000}, LSYS }, | 172 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE1000}, LSYS }, | |
173 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX4}, PNA }, | 173 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX4}, PNA }, | |
174 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX5}, PNA }, | 174 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX5}, PNA }, | |
175 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX6}, PII }, | 175 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX6}, PII }, | |
176 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX7}, PII }, | 176 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX7}, PII }, | |
177 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX8}, PII }, | 177 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX8}, PII }, | |
178 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX9}, PNA }, | 178 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX9}, PNA }, | |
179 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX10}, 0 }, | 179 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_XX10}, 0 }, | |
180 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_DSB650TX_PNA}, 0 }, | 180 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_DSB650TX_PNA}, 0 }, | |
181 | {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_USB320_EC}, 0 }, | 181 | {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_USB320_EC}, 0 }, | |
182 | {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_SS1001}, PII }, | 182 | {{ USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_SS1001}, PII }, | |
183 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUS}, PNA }, | 183 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUS}, PNA }, | |
184 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII}, PII }, | 184 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII}, PII }, | |
185 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_2}, PII }, | 185 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_2}, PII }, | |
186 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_3}, PII }, | 186 | {{ USB_VENDOR_ADMTEK, USB_PRODUCT_ADMTEK_PEGASUSII_3}, PII }, | |
187 | {{ USB_VENDOR_AEI, USB_PRODUCT_AEI_USBTOLAN}, PII }, | 187 | {{ USB_VENDOR_AEI, USB_PRODUCT_AEI_USBTOLAN}, PII }, | |
188 | {{ USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_USB2LAN}, PII }, | 188 | {{ USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_USB2LAN}, PII }, | |
189 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB100}, 0 }, | 189 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB100}, 0 }, | |
190 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBLP100}, PNA }, | 190 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBLP100}, PNA }, | |
191 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBEL100}, 0 }, | 191 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBEL100}, 0 }, | |
192 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBE100}, PII }, | 192 | {{ USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USBE100}, PII }, | |
193 | {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_HNE200}, PII }, | 193 | {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_HNE200}, PII }, | |
194 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TX}, 0 }, | 194 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TX}, 0 }, | |
195 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXS},PII }, | 195 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXS},PII }, | |
196 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX4}, LSYS | PII }, | 196 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX4}, LSYS | PII }, | |
197 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX1}, LSYS }, | 197 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX1}, LSYS }, | |
198 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX}, LSYS }, | 198 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX}, LSYS }, | |
199 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX_PNA}, PNA }, | 199 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX_PNA}, PNA }, | |
200 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX3}, LSYS | PII }, | 200 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX3}, LSYS | PII }, | |
201 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX2}, LSYS | PII }, | 201 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650TX2}, LSYS | PII }, | |
202 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650}, 0 }, | 202 | {{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650}, 0 }, | |
203 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX0}, 0 }, | 203 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX0}, 0 }, | |
204 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX1}, LSYS }, | 204 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX1}, LSYS }, | |
205 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX2}, 0 }, | 205 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX2}, 0 }, | |
206 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX3}, LSYS }, | 206 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBTX3}, LSYS }, | |
207 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBLTX}, PII }, | 207 | {{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_LDUSBLTX}, PII }, | |
208 | {{ USB_VENDOR_ELSA, USB_PRODUCT_ELSA_USB2ETHERNET}, 0 }, | 208 | {{ USB_VENDOR_ELSA, USB_PRODUCT_ELSA_USB2ETHERNET}, 0 }, | |
209 | {{ USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_UF100}, PII }, | 209 | {{ USB_VENDOR_HAWKING, USB_PRODUCT_HAWKING_UF100}, PII }, | |
210 | {{ USB_VENDOR_HP, USB_PRODUCT_HP_HN210E}, PII }, | 210 | {{ USB_VENDOR_HP, USB_PRODUCT_HP_HN210E}, PII }, | |
211 | {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTX}, 0 }, | 211 | {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTX}, 0 }, | |
212 | {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTXS}, PII }, | 212 | {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETTXS}, PII }, | |
213 | {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETXUS2}, PII }, | 213 | {{ USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETXUS2}, PII }, | |
214 | {{ USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_KNU101TX}, 0 }, | 214 | {{ USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_KNU101TX}, 0 }, | |
215 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX1}, LSYS | PII }, | 215 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX1}, LSYS | PII }, | |
216 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T}, LSYS }, | 216 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T}, LSYS }, | |
217 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100TX}, LSYS }, | 217 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100TX}, LSYS }, | |
218 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100H1}, LSYS | PNA }, | 218 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB100H1}, LSYS | PNA }, | |
219 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TA}, LSYS }, | 219 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TA}, LSYS }, | |
220 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX2}, LSYS | PII }, | 220 | {{ USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10TX2}, LSYS | PII }, | |
221 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX1}, 0 }, | 221 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX1}, 0 }, | |
222 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX5}, 0 }, | 222 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUATX5}, 0 }, | |
223 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUA2TX5}, PII }, | 223 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUA2TX5}, PII }, | |
224 | {{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN110}, PII }, | 224 | {{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_MN110}, PII }, | |
225 | {{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA101}, PII }, | 225 | {{ USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA101}, PII }, | |
226 | {{ USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM}, PII }, | 226 | {{ USB_VENDOR_SIEMENS, USB_PRODUCT_SIEMENS_SPEEDSTREAM}, PII }, | |
227 | {{ USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTNIC},PII }, | 227 | {{ USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTNIC},PII }, | |
228 | {{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2202USB}, 0 }, | 228 | {{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2202USB}, 0 }, | |
229 | {{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2206USB}, PII }, | 229 | {{ USB_VENDOR_SMC, USB_PRODUCT_SMC_2206USB}, PII }, | |
230 | {{ USB_VENDOR_SOHOWARE, USB_PRODUCT_SOHOWARE_NUB100}, 0 }, | 230 | {{ USB_VENDOR_SOHOWARE, USB_PRODUCT_SOHOWARE_NUB100}, 0 }, | |
231 | }; | 231 | }; | |
232 | #define aue_lookup(v, p) ((const struct aue_type *)usb_lookup(aue_devs, v, p)) | 232 | #define aue_lookup(v, p) ((const struct aue_type *)usb_lookup(aue_devs, v, p)) | |
233 | 233 | |||
234 | static int aue_match(device_t, cfdata_t, void *); | 234 | static int aue_match(device_t, cfdata_t, void *); | |
235 | static void aue_attach(device_t, device_t, void *); | 235 | static void aue_attach(device_t, device_t, void *); | |
236 | 236 | |||
237 | CFATTACH_DECL_NEW(aue, sizeof(struct aue_softc), aue_match, aue_attach, | 237 | CFATTACH_DECL_NEW(aue, sizeof(struct aue_softc), aue_match, aue_attach, | |
238 | usbnet_detach, usbnet_activate); | 238 | usbnet_detach, usbnet_activate); | |
239 | 239 | |||
240 | static void aue_reset_pegasus_II(struct aue_softc *); | 240 | static void aue_reset_pegasus_II(struct aue_softc *); | |
241 | 241 | |||
242 | static void aue_uno_stop(struct ifnet *, int); | 242 | static void aue_uno_stop(struct ifnet *, int); | |
243 | static int aue_uno_ioctl(struct ifnet *, u_long, void *); | 243 | static int aue_uno_ioctl(struct ifnet *, u_long, void *); | |
244 | static int aue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 244 | static int aue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
245 | static int aue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 245 | static int aue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
246 | static void aue_uno_mii_statchg(struct ifnet *); | 246 | static void aue_uno_mii_statchg(struct ifnet *); | |
247 | static unsigned aue_uno_tx_prepare(struct usbnet *, struct mbuf *, | 247 | static unsigned aue_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
248 | struct usbnet_chain *); | 248 | struct usbnet_chain *); | |
249 | static void aue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 249 | static void aue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
250 | static int aue_uno_init(struct ifnet *); | 250 | static int aue_uno_init(struct ifnet *); | |
251 | static void aue_uno_intr(struct usbnet *, usbd_status); | 251 | static void aue_uno_intr(struct usbnet *, usbd_status); | |
252 | 252 | |||
253 | static const struct usbnet_ops aue_ops = { | 253 | static const struct usbnet_ops aue_ops = { | |
254 | .uno_stop = aue_uno_stop, | 254 | .uno_stop = aue_uno_stop, | |
255 | .uno_ioctl = aue_uno_ioctl, | 255 | .uno_ioctl = aue_uno_ioctl, | |
256 | .uno_read_reg = aue_uno_mii_read_reg, | 256 | .uno_read_reg = aue_uno_mii_read_reg, | |
257 | .uno_write_reg = aue_uno_mii_write_reg, | 257 | .uno_write_reg = aue_uno_mii_write_reg, | |
258 | .uno_statchg = aue_uno_mii_statchg, | 258 | .uno_statchg = aue_uno_mii_statchg, | |
259 | .uno_tx_prepare = aue_uno_tx_prepare, | 259 | .uno_tx_prepare = aue_uno_tx_prepare, | |
260 | .uno_rx_loop = aue_uno_rx_loop, | 260 | .uno_rx_loop = aue_uno_rx_loop, | |
261 | .uno_init = aue_uno_init, | 261 | .uno_init = aue_uno_init, | |
262 | .uno_intr = aue_uno_intr, | 262 | .uno_intr = aue_uno_intr, | |
263 | }; | 263 | }; | |
264 | 264 | |||
265 | static uint32_t aue_crc(void *); | 265 | static uint32_t aue_crc(void *); | |
266 | static void aue_reset(struct aue_softc *); | 266 | static void aue_reset(struct aue_softc *); | |
267 | 267 | |||
268 | static int aue_csr_read_1(struct aue_softc *, int); | 268 | static int aue_csr_read_1(struct aue_softc *, int); | |
269 | static int aue_csr_write_1(struct aue_softc *, int, int); | 269 | static int aue_csr_write_1(struct aue_softc *, int, int); | |
270 | static int aue_csr_read_2(struct aue_softc *, int); | 270 | static int aue_csr_read_2(struct aue_softc *, int); | |
271 | static int aue_csr_write_2(struct aue_softc *, int, int); | 271 | static int aue_csr_write_2(struct aue_softc *, int, int); | |
272 | 272 | |||
273 | #define AUE_SETBIT(sc, reg, x) \ | 273 | #define AUE_SETBIT(sc, reg, x) \ | |
274 | aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) | (x)) | 274 | aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) | (x)) | |
275 | 275 | |||
276 | #define AUE_CLRBIT(sc, reg, x) \ | 276 | #define AUE_CLRBIT(sc, reg, x) \ | |
277 | aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) & ~(x)) | 277 | aue_csr_write_1(sc, reg, aue_csr_read_1(sc, reg) & ~(x)) | |
278 | 278 | |||
279 | static int | 279 | static int | |
280 | aue_csr_read_1(struct aue_softc *sc, int reg) | 280 | aue_csr_read_1(struct aue_softc *sc, int reg) | |
281 | { | 281 | { | |
282 | struct usbnet * const un = &sc->aue_un; | 282 | struct usbnet * const un = &sc->aue_un; | |
283 | usb_device_request_t req; | 283 | usb_device_request_t req; | |
284 | usbd_status err; | 284 | usbd_status err; | |
285 | uByte val = 0; | 285 | uByte val = 0; | |
286 | 286 | |||
287 | usbnet_isowned_core(un); | 287 | usbnet_isowned_core(un); | |
288 | 288 | |||
289 | if (usbnet_isdying(un)) | 289 | if (usbnet_isdying(un)) | |
290 | return 0; | 290 | return 0; | |
291 | 291 | |||
292 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 292 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
293 | req.bRequest = AUE_UR_READREG; | 293 | req.bRequest = AUE_UR_READREG; | |
294 | USETW(req.wValue, 0); | 294 | USETW(req.wValue, 0); | |
295 | USETW(req.wIndex, reg); | 295 | USETW(req.wIndex, reg); | |
296 | USETW(req.wLength, 1); | 296 | USETW(req.wLength, 1); | |
297 | 297 | |||
298 | err = usbd_do_request(un->un_udev, &req, &val); | 298 | err = usbd_do_request(un->un_udev, &req, &val); | |
299 | 299 | |||
300 | if (err) { | 300 | if (err) { | |
301 | AUEHIST_FUNC(); | 301 | AUEHIST_FUNC(); | |
302 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | 302 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | |
303 | device_unit(un->un_dev), reg, err, 0); | 303 | device_unit(un->un_dev), reg, err, 0); | |
304 | return 0; | 304 | return 0; | |
305 | } | 305 | } | |
306 | 306 | |||
307 | return val; | 307 | return val; | |
308 | } | 308 | } | |
309 | 309 | |||
310 | static int | 310 | static int | |
311 | aue_csr_read_2(struct aue_softc *sc, int reg) | 311 | aue_csr_read_2(struct aue_softc *sc, int reg) | |
312 | { | 312 | { | |
313 | struct usbnet * const un = &sc->aue_un; | 313 | struct usbnet * const un = &sc->aue_un; | |
314 | usb_device_request_t req; | 314 | usb_device_request_t req; | |
315 | usbd_status err; | 315 | usbd_status err; | |
316 | uWord val; | 316 | uWord val; | |
317 | 317 | |||
318 | usbnet_isowned_core(un); | 318 | usbnet_isowned_core(un); | |
319 | 319 | |||
320 | if (usbnet_isdying(un)) | 320 | if (usbnet_isdying(un)) | |
321 | return 0; | 321 | return 0; | |
322 | 322 | |||
323 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 323 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
324 | req.bRequest = AUE_UR_READREG; | 324 | req.bRequest = AUE_UR_READREG; | |
325 | USETW(req.wValue, 0); | 325 | USETW(req.wValue, 0); | |
326 | USETW(req.wIndex, reg); | 326 | USETW(req.wIndex, reg); | |
327 | USETW(req.wLength, 2); | 327 | USETW(req.wLength, 2); | |
328 | 328 | |||
329 | err = usbd_do_request(un->un_udev, &req, &val); | 329 | err = usbd_do_request(un->un_udev, &req, &val); | |
330 | 330 | |||
331 | if (err) { | 331 | if (err) { | |
332 | AUEHIST_FUNC(); | 332 | AUEHIST_FUNC(); | |
333 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | 333 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | |
334 | device_unit(un->un_dev), reg, err, 0); | 334 | device_unit(un->un_dev), reg, err, 0); | |
335 | return 0; | 335 | return 0; | |
336 | } | 336 | } | |
337 | 337 | |||
338 | return UGETW(val); | 338 | return UGETW(val); | |
339 | } | 339 | } | |
340 | 340 | |||
341 | static int | 341 | static int | |
342 | aue_csr_write_1(struct aue_softc *sc, int reg, int aval) | 342 | aue_csr_write_1(struct aue_softc *sc, int reg, int aval) | |
343 | { | 343 | { | |
344 | struct usbnet * const un = &sc->aue_un; | 344 | struct usbnet * const un = &sc->aue_un; | |
345 | usb_device_request_t req; | 345 | usb_device_request_t req; | |
346 | usbd_status err; | 346 | usbd_status err; | |
347 | uByte val; | 347 | uByte val; | |
348 | 348 | |||
349 | usbnet_isowned_core(un); | 349 | usbnet_isowned_core(un); | |
350 | 350 | |||
351 | if (usbnet_isdying(un)) | 351 | if (usbnet_isdying(un)) | |
352 | return 0; | 352 | return 0; | |
353 | 353 | |||
354 | val = aval; | 354 | val = aval; | |
355 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 355 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
356 | req.bRequest = AUE_UR_WRITEREG; | 356 | req.bRequest = AUE_UR_WRITEREG; | |
357 | USETW(req.wValue, val); | 357 | USETW(req.wValue, val); | |
358 | USETW(req.wIndex, reg); | 358 | USETW(req.wIndex, reg); | |
359 | USETW(req.wLength, 1); | 359 | USETW(req.wLength, 1); | |
360 | 360 | |||
361 | err = usbd_do_request(un->un_udev, &req, &val); | 361 | err = usbd_do_request(un->un_udev, &req, &val); | |
362 | 362 | |||
363 | if (err) { | 363 | if (err) { | |
364 | AUEHIST_FUNC(); | 364 | AUEHIST_FUNC(); | |
365 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | 365 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | |
366 | device_unit(un->un_dev), reg, err, 0); | 366 | device_unit(un->un_dev), reg, err, 0); | |
367 | return -1; | 367 | return -1; | |
368 | } | 368 | } | |
369 | 369 | |||
370 | return 0; | 370 | return 0; | |
371 | } | 371 | } | |
372 | 372 | |||
373 | static int | 373 | static int | |
374 | aue_csr_write_2(struct aue_softc *sc, int reg, int aval) | 374 | aue_csr_write_2(struct aue_softc *sc, int reg, int aval) | |
375 | { | 375 | { | |
376 | struct usbnet * const un = &sc->aue_un; | 376 | struct usbnet * const un = &sc->aue_un; | |
377 | usb_device_request_t req; | 377 | usb_device_request_t req; | |
378 | usbd_status err; | 378 | usbd_status err; | |
379 | uWord val; | 379 | uWord val; | |
380 | 380 | |||
381 | usbnet_isowned_core(un); | 381 | usbnet_isowned_core(un); | |
382 | 382 | |||
383 | if (usbnet_isdying(un)) | 383 | if (usbnet_isdying(un)) | |
384 | return 0; | 384 | return 0; | |
385 | 385 | |||
386 | USETW(val, aval); | 386 | USETW(val, aval); | |
387 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 387 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
388 | req.bRequest = AUE_UR_WRITEREG; | 388 | req.bRequest = AUE_UR_WRITEREG; | |
389 | USETW(req.wValue, aval); | 389 | USETW(req.wValue, aval); | |
390 | USETW(req.wIndex, reg); | 390 | USETW(req.wIndex, reg); | |
391 | USETW(req.wLength, 2); | 391 | USETW(req.wLength, 2); | |
392 | 392 | |||
393 | err = usbd_do_request(un->un_udev, &req, &val); | 393 | err = usbd_do_request(un->un_udev, &req, &val); | |
394 | 394 | |||
395 | if (err) { | 395 | if (err) { | |
396 | AUEHIST_FUNC(); | 396 | AUEHIST_FUNC(); | |
397 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | 397 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | |
398 | device_unit(un->un_dev), reg, err, 0); | 398 | device_unit(un->un_dev), reg, err, 0); | |
399 | return -1; | 399 | return -1; | |
400 | } | 400 | } | |
401 | 401 | |||
402 | return 0; | 402 | return 0; | |
403 | } | 403 | } | |
404 | 404 | |||
405 | /* | 405 | /* | |
406 | * Read a word of data stored in the EEPROM at address 'addr.' | 406 | * Read a word of data stored in the EEPROM at address 'addr.' | |
407 | */ | 407 | */ | |
408 | static int | 408 | static int | |
409 | aue_eeprom_getword(struct aue_softc *sc, int addr) | 409 | aue_eeprom_getword(struct aue_softc *sc, int addr) | |
410 | { | 410 | { | |
411 | struct usbnet * const un = &sc->aue_un; | 411 | struct usbnet * const un = &sc->aue_un; | |
412 | int i; | 412 | int i; | |
413 | 413 | |||
414 | AUEHIST_FUNC(); AUEHIST_CALLED(); | 414 | AUEHIST_FUNC(); AUEHIST_CALLED(); | |
415 | 415 | |||
416 | aue_csr_write_1(sc, AUE_EE_REG, addr); | 416 | aue_csr_write_1(sc, AUE_EE_REG, addr); | |
417 | aue_csr_write_1(sc, AUE_EE_CTL, AUE_EECTL_READ); | 417 | aue_csr_write_1(sc, AUE_EE_CTL, AUE_EECTL_READ); | |
418 | 418 | |||
419 | for (i = 0; i < AUE_TIMEOUT; i++) { | 419 | for (i = 0; i < AUE_TIMEOUT; i++) { | |
420 | if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE) | 420 | if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE) | |
421 | break; | 421 | break; | |
422 | } | 422 | } | |
423 | 423 | |||
424 | if (i == AUE_TIMEOUT) { | 424 | if (i == AUE_TIMEOUT) { | |
425 | printf("%s: EEPROM read timed out\n", | 425 | printf("%s: EEPROM read timed out\n", | |
426 | device_xname(un->un_dev)); | 426 | device_xname(un->un_dev)); | |
427 | } | 427 | } | |
428 | 428 | |||
429 | return aue_csr_read_2(sc, AUE_EE_DATA); | 429 | return aue_csr_read_2(sc, AUE_EE_DATA); | |
430 | } | 430 | } | |
431 | 431 | |||
432 | /* | 432 | /* | |
433 | * Read the MAC from the EEPROM. It's at offset 0. | 433 | * Read the MAC from the EEPROM. It's at offset 0. | |
434 | */ | 434 | */ | |
435 | static void | 435 | static void | |
436 | aue_read_mac(struct usbnet *un) | 436 | aue_read_mac(struct usbnet *un) | |
437 | { | 437 | { | |
438 | struct aue_softc *sc = usbnet_softc(un); | 438 | struct aue_softc *sc = usbnet_softc(un); | |
439 | int i; | 439 | int i; | |
440 | int off = 0; | 440 | int off = 0; | |
441 | int word; | 441 | int word; | |
442 | 442 | |||
443 | usbnet_isowned_core(un); | 443 | usbnet_isowned_core(un); | |
444 | 444 | |||
445 | AUEHIST_FUNC(); | 445 | AUEHIST_FUNC(); | |
446 | AUEHIST_CALLARGS("aue%jd: enter", | 446 | AUEHIST_CALLARGS("aue%jd: enter", | |
447 | device_unit(un->un_dev), 0, 0, 0); | 447 | device_unit(un->un_dev), 0, 0, 0); | |
448 | 448 | |||
449 | for (i = 0; i < 3; i++) { | 449 | for (i = 0; i < 3; i++) { | |
450 | word = aue_eeprom_getword(sc, off + i); | 450 | word = aue_eeprom_getword(sc, off + i); | |
451 | un->un_eaddr[2 * i] = (u_char)word; | 451 | un->un_eaddr[2 * i] = (u_char)word; | |
452 | un->un_eaddr[2 * i + 1] = (u_char)(word >> 8); | 452 | un->un_eaddr[2 * i + 1] = (u_char)(word >> 8); | |
453 | } | 453 | } | |
454 | } | 454 | } | |
455 | 455 | |||
456 | static int | 456 | static int | |
457 | aue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 457 | aue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
458 | { | 458 | { | |
459 | struct aue_softc *sc = usbnet_softc(un); | 459 | struct aue_softc *sc = usbnet_softc(un); | |
460 | int i; | 460 | int i; | |
461 | 461 | |||
462 | AUEHIST_FUNC(); | 462 | AUEHIST_FUNC(); | |
463 | 463 | |||
464 | #if 0 | 464 | #if 0 | |
465 | /* | 465 | /* | |
466 | * The Am79C901 HomePNA PHY actually contains | 466 | * The Am79C901 HomePNA PHY actually contains | |
467 | * two transceivers: a 1Mbps HomePNA PHY and a | 467 | * two transceivers: a 1Mbps HomePNA PHY and a | |
468 | * 10Mbps full/half duplex ethernet PHY with | 468 | * 10Mbps full/half duplex ethernet PHY with | |
469 | * NWAY autoneg. However in the ADMtek adapter, | 469 | * NWAY autoneg. However in the ADMtek adapter, | |
470 | * only the 1Mbps PHY is actually connected to | 470 | * only the 1Mbps PHY is actually connected to | |
471 | * anything, so we ignore the 10Mbps one. It | 471 | * anything, so we ignore the 10Mbps one. It | |
472 | * happens to be configured for MII address 3, | 472 | * happens to be configured for MII address 3, | |
473 | * so we filter that out. | 473 | * so we filter that out. | |
474 | */ | 474 | */ | |
475 | if (sc->aue_vendor == USB_VENDOR_ADMTEK && | 475 | if (sc->aue_vendor == USB_VENDOR_ADMTEK && | |
476 | sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { | 476 | sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { | |
477 | if (phy == 3) | 477 | if (phy == 3) | |
478 | return EINVAL; | 478 | return EINVAL; | |
479 | } | 479 | } | |
480 | #endif | 480 | #endif | |
481 | 481 | |||
482 | aue_csr_write_1(sc, AUE_PHY_ADDR, phy); | 482 | aue_csr_write_1(sc, AUE_PHY_ADDR, phy); | |
483 | aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ); | 483 | aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ); | |
484 | 484 | |||
485 | for (i = 0; i < AUE_TIMEOUT; i++) { | 485 | for (i = 0; i < AUE_TIMEOUT; i++) { | |
486 | if (usbnet_isdying(un)) | |||
487 | return ENXIO; | |||
486 | if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) | 488 | if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) | |
487 | break; | 489 | break; | |
488 | } | 490 | } | |
489 | 491 | |||
490 | if (i == AUE_TIMEOUT) { | 492 | if (i == AUE_TIMEOUT) { | |
491 | AUEHIST_CALLARGS("aue%jd: phy=%#jx reg=%#jx read timed out", | 493 | AUEHIST_CALLARGS("aue%jd: phy=%#jx reg=%#jx read timed out", | |
492 | device_unit(un->un_dev), phy, reg, 0); | 494 | device_unit(un->un_dev), phy, reg, 0); | |
493 | return ETIMEDOUT; | 495 | return ETIMEDOUT; | |
494 | } | 496 | } | |
495 | 497 | |||
496 | *val = aue_csr_read_2(sc, AUE_PHY_DATA); | 498 | *val = aue_csr_read_2(sc, AUE_PHY_DATA); | |
497 | 499 | |||
498 | AUEHIST_CALLARGSN(11, "aue%jd: phy=%#jx reg=%#jx => 0x%04jx", | 500 | AUEHIST_CALLARGSN(11, "aue%jd: phy=%#jx reg=%#jx => 0x%04jx", | |
499 | device_unit(un->un_dev), phy, reg, *val); | 501 | device_unit(un->un_dev), phy, reg, *val); | |
500 | 502 | |||
501 | return 0; | 503 | return 0; | |
502 | } | 504 | } | |
503 | 505 | |||
504 | static int | 506 | static int | |
505 | aue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 507 | aue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
506 | { | 508 | { | |
507 | struct aue_softc *sc = usbnet_softc(un); | 509 | struct aue_softc *sc = usbnet_softc(un); | |
508 | int i; | 510 | int i; | |
509 | 511 | |||
510 | AUEHIST_FUNC(); | 512 | AUEHIST_FUNC(); | |
511 | AUEHIST_CALLARGSN(11, "aue%jd: phy=%jd reg=%jd data=0x%04jx", | 513 | AUEHIST_CALLARGSN(11, "aue%jd: phy=%jd reg=%jd data=0x%04jx", | |
512 | device_unit(un->un_dev), phy, reg, val); | 514 | device_unit(un->un_dev), phy, reg, val); | |
513 | 515 | |||
514 | #if 0 | 516 | #if 0 | |
515 | if (sc->aue_vendor == USB_VENDOR_ADMTEK && | 517 | if (sc->aue_vendor == USB_VENDOR_ADMTEK && | |
516 | sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { | 518 | sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { | |
517 | if (phy == 3) | 519 | if (phy == 3) | |
518 | return EINVAL; | 520 | return EINVAL; | |
519 | } | 521 | } | |
520 | #endif | 522 | #endif | |
521 | 523 | |||
522 | aue_csr_write_2(sc, AUE_PHY_DATA, val); | 524 | aue_csr_write_2(sc, AUE_PHY_DATA, val); | |
523 | aue_csr_write_1(sc, AUE_PHY_ADDR, phy); | 525 | aue_csr_write_1(sc, AUE_PHY_ADDR, phy); | |
524 | aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE); | 526 | aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE); | |
525 | 527 | |||
526 | for (i = 0; i < AUE_TIMEOUT; i++) { | 528 | for (i = 0; i < AUE_TIMEOUT; i++) { | |
529 | if (usbnet_isdying(un)) | |||
530 | return ENXIO; | |||
527 | if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) | 531 | if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) | |
528 | break; | 532 | break; | |
529 | } | 533 | } | |
530 | 534 | |||
531 | if (i == AUE_TIMEOUT) { | 535 | if (i == AUE_TIMEOUT) { | |
532 | DPRINTF("aue%jd: phy=%#jx reg=%#jx val=%#jx write timed out", | 536 | DPRINTF("aue%jd: phy=%#jx reg=%#jx val=%#jx write timed out", | |
533 | device_unit(un->un_dev), phy, reg, val); | 537 | device_unit(un->un_dev), phy, reg, val); | |
534 | return ETIMEDOUT; | 538 | return ETIMEDOUT; | |
535 | } | 539 | } | |
536 | 540 | |||
537 | return 0; | 541 | return 0; | |
538 | } | 542 | } | |
539 | 543 | |||
540 | static void | 544 | static void | |
541 | aue_uno_mii_statchg(struct ifnet *ifp) | 545 | aue_uno_mii_statchg(struct ifnet *ifp) | |
542 | { | 546 | { | |
543 | struct usbnet *un = ifp->if_softc; | 547 | struct usbnet *un = ifp->if_softc; | |
544 | struct aue_softc *sc = usbnet_softc(un); | 548 | struct aue_softc *sc = usbnet_softc(un); | |
545 | struct mii_data *mii = usbnet_mii(un); | 549 | struct mii_data *mii = usbnet_mii(un); | |
546 | const bool hadlink __diagused = usbnet_havelink(un); | 550 | const bool hadlink __diagused = usbnet_havelink(un); | |
547 | 551 | |||
548 | AUEHIST_FUNC(); AUEHIST_CALLED(); | 552 | AUEHIST_FUNC(); AUEHIST_CALLED(); | |
549 | AUEHIST_CALLARGSN(5, "aue%jd: ifp=%#jx link=%jd", | 553 | AUEHIST_CALLARGSN(5, "aue%jd: ifp=%#jx link=%jd", | |
550 | device_unit(un->un_dev), (uintptr_t)ifp, hadlink, 0); | 554 | device_unit(un->un_dev), (uintptr_t)ifp, hadlink, 0); | |
551 | 555 | |||
552 | AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); | 556 | AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); | |
553 | 557 | |||
554 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { | 558 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { | |
555 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); | 559 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); | |
556 | } else { | 560 | } else { | |
557 | AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); | 561 | AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); | |
558 | } | 562 | } | |
559 | 563 | |||
560 | if ((mii->mii_media_active & IFM_FDX) != 0) | 564 | if ((mii->mii_media_active & IFM_FDX) != 0) | |
561 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); | 565 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); | |
562 | else | 566 | else | |
563 | AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); | 567 | AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); | |
564 | 568 | |||
565 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); | 569 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); | |
566 | 570 | |||
567 | if (mii->mii_media_status & IFM_ACTIVE && | 571 | if (mii->mii_media_status & IFM_ACTIVE && | |
568 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | 572 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | |
569 | usbnet_set_link(un, true); | 573 | usbnet_set_link(un, true); | |
570 | } | 574 | } | |
571 | 575 | |||
572 | /* | 576 | /* | |
573 | * Set the LED modes on the LinkSys adapter. | 577 | * Set the LED modes on the LinkSys adapter. | |
574 | * This turns on the 'dual link LED' bin in the auxmode | 578 | * This turns on the 'dual link LED' bin in the auxmode | |
575 | * register of the Broadcom PHY. | 579 | * register of the Broadcom PHY. | |
576 | */ | 580 | */ | |
577 | if (!usbnet_isdying(un) && (un->un_flags & LSYS)) { | 581 | if (!usbnet_isdying(un) && (un->un_flags & LSYS)) { | |
578 | uint16_t auxmode; | 582 | uint16_t auxmode; | |
579 | aue_uno_mii_read_reg(un, 0, 0x1b, &auxmode); | 583 | aue_uno_mii_read_reg(un, 0, 0x1b, &auxmode); | |
580 | aue_uno_mii_write_reg(un, 0, 0x1b, auxmode | 0x04); | 584 | aue_uno_mii_write_reg(un, 0, 0x1b, auxmode | 0x04); | |
581 | } | 585 | } | |
582 | 586 | |||
583 | if (usbnet_havelink(un) != hadlink) { | 587 | if (usbnet_havelink(un) != hadlink) { | |
584 | DPRINTFN(5, "aue%jd: exit link %jd", | 588 | DPRINTFN(5, "aue%jd: exit link %jd", | |
585 | device_unit(un->un_dev), usbnet_havelink(un), 0, 0); | 589 | device_unit(un->un_dev), usbnet_havelink(un), 0, 0); | |
586 | } | 590 | } | |
587 | } | 591 | } | |
588 | 592 | |||
589 | #define AUE_POLY 0xEDB88320 | 593 | #define AUE_POLY 0xEDB88320 | |
590 | #define AUE_BITS 6 | 594 | #define AUE_BITS 6 | |
591 | 595 | |||
592 | static uint32_t | 596 | static uint32_t | |
593 | aue_crc(void *addrv) | 597 | aue_crc(void *addrv) | |
594 | { | 598 | { | |
595 | uint32_t idx, bit, data, crc; | 599 | uint32_t idx, bit, data, crc; | |
596 | char *addr = addrv; | 600 | char *addr = addrv; | |
597 | 601 | |||
598 | /* Compute CRC for the address value. */ | 602 | /* Compute CRC for the address value. */ | |
599 | crc = 0xFFFFFFFF; /* initial value */ | 603 | crc = 0xFFFFFFFF; /* initial value */ | |
600 | 604 | |||
601 | for (idx = 0; idx < 6; idx++) { | 605 | for (idx = 0; idx < 6; idx++) { | |
602 | for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) | 606 | for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) | |
603 | crc = (crc >> 1) ^ (((crc ^ data) & 1) ? AUE_POLY : 0); | 607 | crc = (crc >> 1) ^ (((crc ^ data) & 1) ? AUE_POLY : 0); | |
604 | } | 608 | } | |
605 | 609 | |||
606 | return crc & ((1 << AUE_BITS) - 1); | 610 | return crc & ((1 << AUE_BITS) - 1); | |
607 | } | 611 | } | |
608 | 612 | |||
609 | static void | 613 | static void | |
610 | aue_setiff_locked(struct usbnet *un) | 614 | aue_setiff_locked(struct usbnet *un) | |
611 | { | 615 | { | |
612 | struct aue_softc * const sc = usbnet_softc(un); | 616 | struct aue_softc * const sc = usbnet_softc(un); | |
613 | struct ifnet * const ifp = usbnet_ifp(un); | 617 | struct ifnet * const ifp = usbnet_ifp(un); | |
614 | struct ethercom * ec = usbnet_ec(un); | 618 | struct ethercom * ec = usbnet_ec(un); | |
615 | struct ether_multi *enm; | 619 | struct ether_multi *enm; | |
616 | struct ether_multistep step; | 620 | struct ether_multistep step; | |
617 | uint32_t h = 0, i; | 621 | uint32_t h = 0, i; | |
618 | uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 622 | uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
619 | 623 | |||
620 | AUEHIST_FUNC(); | 624 | AUEHIST_FUNC(); | |
621 | AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | 625 | AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | |
622 | 626 | |||
623 | usbnet_isowned_core(un); | 627 | usbnet_isowned_core(un); | |
624 | 628 | |||
625 | if (ifp->if_flags & IFF_PROMISC) { | 629 | if (ifp->if_flags & IFF_PROMISC) { | |
626 | allmulti: | 630 | allmulti: | |
627 | ifp->if_flags |= IFF_ALLMULTI; | 631 | ifp->if_flags |= IFF_ALLMULTI; | |
628 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); | 632 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); | |
629 | return; | 633 | return; | |
630 | } | 634 | } | |
631 | 635 | |||
632 | AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); | 636 | AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); | |
633 | 637 | |||
634 | /* now program new ones */ | 638 | /* now program new ones */ | |
635 | ETHER_LOCK(ec); | 639 | ETHER_LOCK(ec); | |
636 | ETHER_FIRST_MULTI(step, ec, enm); | 640 | ETHER_FIRST_MULTI(step, ec, enm); | |
637 | while (enm != NULL) { | 641 | while (enm != NULL) { | |
638 | if (memcmp(enm->enm_addrlo, | 642 | if (memcmp(enm->enm_addrlo, | |
639 | enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { | 643 | enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { | |
640 | ETHER_UNLOCK(ec); | 644 | ETHER_UNLOCK(ec); | |
641 | goto allmulti; | 645 | goto allmulti; | |
642 | } | 646 | } | |
643 | 647 | |||
644 | h = aue_crc(enm->enm_addrlo); | 648 | h = aue_crc(enm->enm_addrlo); | |
645 | hashtbl[h >> 3] |= 1 << (h & 0x7); | 649 | hashtbl[h >> 3] |= 1 << (h & 0x7); | |
646 | ETHER_NEXT_MULTI(step, enm); | 650 | ETHER_NEXT_MULTI(step, enm); | |
647 | } | 651 | } | |
648 | ETHER_UNLOCK(ec); | 652 | ETHER_UNLOCK(ec); | |
649 | 653 | |||
650 | /* write the hashtable */ | 654 | /* write the hashtable */ | |
651 | for (i = 0; i < 8; i++) | 655 | for (i = 0; i < 8; i++) | |
652 | aue_csr_write_1(sc, AUE_MAR0 + i, hashtbl[i]); | 656 | aue_csr_write_1(sc, AUE_MAR0 + i, hashtbl[i]); | |
653 | 657 | |||
654 | ifp->if_flags &= ~IFF_ALLMULTI; | 658 | ifp->if_flags &= ~IFF_ALLMULTI; | |
655 | } | 659 | } | |
656 | 660 | |||
657 | static void | 661 | static void | |
658 | aue_reset_pegasus_II(struct aue_softc *sc) | 662 | aue_reset_pegasus_II(struct aue_softc *sc) | |
659 | { | 663 | { | |
660 | /* Magic constants taken from Linux driver. */ | 664 | /* Magic constants taken from Linux driver. */ | |
661 | aue_csr_write_1(sc, AUE_REG_1D, 0); | 665 | aue_csr_write_1(sc, AUE_REG_1D, 0); | |
662 | aue_csr_write_1(sc, AUE_REG_7B, 2); | 666 | aue_csr_write_1(sc, AUE_REG_7B, 2); | |
663 | #if 0 | 667 | #if 0 | |
664 | if ((un->un_flags & PNA) && mii_mode) | 668 | if ((un->un_flags & PNA) && mii_mode) | |
665 | aue_csr_write_1(sc, AUE_REG_81, 6); | 669 | aue_csr_write_1(sc, AUE_REG_81, 6); | |
666 | else | 670 | else | |
667 | #endif | 671 | #endif | |
668 | aue_csr_write_1(sc, AUE_REG_81, 2); | 672 | aue_csr_write_1(sc, AUE_REG_81, 2); | |
669 | } | 673 | } | |
670 | 674 | |||
671 | static void | 675 | static void | |
672 | aue_reset(struct aue_softc *sc) | 676 | aue_reset(struct aue_softc *sc) | |
673 | { | 677 | { | |
674 | struct usbnet * const un = &sc->aue_un; | 678 | struct usbnet * const un = &sc->aue_un; | |
675 | int i; | 679 | int i; | |
676 | 680 | |||
677 | AUEHIST_FUNC(); | 681 | AUEHIST_FUNC(); | |
678 | AUEHIST_CALLARGSN(2, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | 682 | AUEHIST_CALLARGSN(2, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | |
679 | 683 | |||
680 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC); | 684 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC); | |
681 | 685 | |||
682 | for (i = 0; i < AUE_TIMEOUT; i++) { | 686 | for (i = 0; i < AUE_TIMEOUT; i++) { | |
687 | if (usbnet_isdying(un)) | |||
688 | return; | |||
683 | if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC)) | 689 | if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC)) | |
684 | break; | 690 | break; | |
685 | } | 691 | } | |
686 | 692 | |||
687 | if (i == AUE_TIMEOUT) | 693 | if (i == AUE_TIMEOUT) | |
688 | printf("%s: reset failed\n", device_xname(un->un_dev)); | 694 | printf("%s: reset failed\n", device_xname(un->un_dev)); | |
689 | 695 | |||
690 | #if 0 | 696 | #if 0 | |
691 | /* XXX what is mii_mode supposed to be */ | 697 | /* XXX what is mii_mode supposed to be */ | |
692 | if (sc->sc_mii_mode && (un->un_flags & PNA)) | 698 | if (sc->sc_mii_mode && (un->un_flags & PNA)) | |
693 | aue_csr_write_1(sc, AUE_GPIO1, 0x34); | 699 | aue_csr_write_1(sc, AUE_GPIO1, 0x34); | |
694 | else | 700 | else | |
695 | aue_csr_write_1(sc, AUE_GPIO1, 0x26); | 701 | aue_csr_write_1(sc, AUE_GPIO1, 0x26); | |
696 | #endif | 702 | #endif | |
697 | 703 | |||
698 | /* | 704 | /* | |
699 | * The PHY(s) attached to the Pegasus chip may be held | 705 | * The PHY(s) attached to the Pegasus chip may be held | |
700 | * in reset until we flip on the GPIO outputs. Make sure | 706 | * in reset until we flip on the GPIO outputs. Make sure | |
701 | * to set the GPIO pins high so that the PHY(s) will | 707 | * to set the GPIO pins high so that the PHY(s) will | |
702 | * be enabled. | 708 | * be enabled. | |
703 | * | 709 | * | |
704 | * Note: We force all of the GPIO pins low first, *then* | 710 | * Note: We force all of the GPIO pins low first, *then* | |
705 | * enable the ones we want. | 711 | * enable the ones we want. | |
706 | */ | 712 | */ | |
707 | if (un->un_flags & LSYS) { | 713 | if (un->un_flags & LSYS) { | |
708 | /* Grrr. LinkSys has to be different from everyone else. */ | 714 | /* Grrr. LinkSys has to be different from everyone else. */ | |
709 | aue_csr_write_1(sc, AUE_GPIO0, | 715 | aue_csr_write_1(sc, AUE_GPIO0, | |
710 | AUE_GPIO_SEL0 | AUE_GPIO_SEL1); | 716 | AUE_GPIO_SEL0 | AUE_GPIO_SEL1); | |
711 | } else { | 717 | } else { | |
712 | aue_csr_write_1(sc, AUE_GPIO0, | 718 | aue_csr_write_1(sc, AUE_GPIO0, | |
713 | AUE_GPIO_OUT0 | AUE_GPIO_SEL0); | 719 | AUE_GPIO_OUT0 | AUE_GPIO_SEL0); | |
714 | } | 720 | } | |
715 | aue_csr_write_1(sc, AUE_GPIO0, | 721 | aue_csr_write_1(sc, AUE_GPIO0, | |
716 | AUE_GPIO_OUT0 | AUE_GPIO_SEL0 | AUE_GPIO_SEL1); | 722 | AUE_GPIO_OUT0 | AUE_GPIO_SEL0 | AUE_GPIO_SEL1); | |
717 | 723 | |||
718 | if (un->un_flags & PII) | 724 | if (un->un_flags & PII) | |
719 | aue_reset_pegasus_II(sc); | 725 | aue_reset_pegasus_II(sc); | |
720 | 726 | |||
721 | /* Wait a little while for the chip to get its brains in order. */ | 727 | /* Wait a little while for the chip to get its brains in order. */ | |
722 | delay(10000); /* XXX */ | 728 | delay(10000); /* XXX */ | |
723 | //usbd_delay_ms(un->un_udev, 10); /* XXX */ | 729 | //usbd_delay_ms(un->un_udev, 10); /* XXX */ | |
724 | 730 | |||
725 | DPRINTFN(2, "aue%jd: exit", device_unit(un->un_dev), 0, 0, 0); | 731 | DPRINTFN(2, "aue%jd: exit", device_unit(un->un_dev), 0, 0, 0); | |
726 | } | 732 | } | |
727 | 733 | |||
728 | /* | 734 | /* | |
729 | * Probe for a Pegasus chip. | 735 | * Probe for a Pegasus chip. | |
730 | */ | 736 | */ | |
731 | static int | 737 | static int | |
732 | aue_match(device_t parent, cfdata_t match, void *aux) | 738 | aue_match(device_t parent, cfdata_t match, void *aux) | |
733 | { | 739 | { | |
734 | struct usb_attach_arg *uaa = aux; | 740 | struct usb_attach_arg *uaa = aux; | |
735 | 741 | |||
736 | /* | 742 | /* | |
737 | * Some manufacturers use the same vendor and product id for | 743 | * Some manufacturers use the same vendor and product id for | |
738 | * different devices. We need to sanity check the DeviceClass | 744 | * different devices. We need to sanity check the DeviceClass | |
739 | * in this case | 745 | * in this case | |
740 | * Currently known guilty products: | 746 | * Currently known guilty products: | |
741 | * 0x050d/0x0121 Belkin Bluetooth and USB2LAN | 747 | * 0x050d/0x0121 Belkin Bluetooth and USB2LAN | |
742 | * | 748 | * | |
743 | * If this turns out to be more common, we could use a quirk | 749 | * If this turns out to be more common, we could use a quirk | |
744 | * table. | 750 | * table. | |
745 | */ | 751 | */ | |
746 | if (uaa->uaa_vendor == USB_VENDOR_BELKIN && | 752 | if (uaa->uaa_vendor == USB_VENDOR_BELKIN && | |
747 | uaa->uaa_product == USB_PRODUCT_BELKIN_USB2LAN) { | 753 | uaa->uaa_product == USB_PRODUCT_BELKIN_USB2LAN) { | |
748 | usb_device_descriptor_t *dd; | 754 | usb_device_descriptor_t *dd; | |
749 | 755 | |||
750 | dd = usbd_get_device_descriptor(uaa->uaa_device); | 756 | dd = usbd_get_device_descriptor(uaa->uaa_device); | |
751 | if (dd != NULL && | 757 | if (dd != NULL && | |
752 | dd->bDeviceClass != UDCLASS_IN_INTERFACE) | 758 | dd->bDeviceClass != UDCLASS_IN_INTERFACE) | |
753 | return UMATCH_NONE; | 759 | return UMATCH_NONE; | |
754 | } | 760 | } | |
755 | 761 | |||
756 | return aue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 762 | return aue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
757 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 763 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
758 | } | 764 | } | |
759 | 765 | |||
760 | /* | 766 | /* | |
761 | * Attach the interface. Allocate softc structures, do ifmedia | 767 | * Attach the interface. Allocate softc structures, do ifmedia | |
762 | * setup and ethernet/BPF attach. | 768 | * setup and ethernet/BPF attach. | |
763 | */ | 769 | */ | |
764 | static void | 770 | static void | |
765 | aue_attach(device_t parent, device_t self, void *aux) | 771 | aue_attach(device_t parent, device_t self, void *aux) | |
766 | { | 772 | { | |
767 | USBNET_MII_DECL_DEFAULT(unm); | 773 | USBNET_MII_DECL_DEFAULT(unm); | |
768 | struct aue_softc * const sc = device_private(self); | 774 | struct aue_softc * const sc = device_private(self); | |
769 | struct usbnet * const un = &sc->aue_un; | 775 | struct usbnet * const un = &sc->aue_un; | |
770 | struct usb_attach_arg *uaa = aux; | 776 | struct usb_attach_arg *uaa = aux; | |
771 | char *devinfop; | 777 | char *devinfop; | |
772 | struct usbd_device *dev = uaa->uaa_device; | 778 | struct usbd_device *dev = uaa->uaa_device; | |
773 | usbd_status err; | 779 | usbd_status err; | |
774 | usb_interface_descriptor_t *id; | 780 | usb_interface_descriptor_t *id; | |
775 | usb_endpoint_descriptor_t *ed; | 781 | usb_endpoint_descriptor_t *ed; | |
776 | int i; | 782 | int i; | |
777 | 783 | |||
778 | AUEHIST_FUNC(); | 784 | AUEHIST_FUNC(); | |
779 | AUEHIST_CALLARGSN(2, "aue%jd: enter sc=%#jx", | 785 | AUEHIST_CALLARGSN(2, "aue%jd: enter sc=%#jx", | |
780 | device_unit(self), (uintptr_t)sc, 0, 0); | 786 | device_unit(self), (uintptr_t)sc, 0, 0); | |
781 | 787 | |||
782 | KASSERT((void *)sc == un); | 788 | KASSERT((void *)sc == un); | |
783 | 789 | |||
784 | aprint_naive("\n"); | 790 | aprint_naive("\n"); | |
785 | aprint_normal("\n"); | 791 | aprint_normal("\n"); | |
786 | devinfop = usbd_devinfo_alloc(uaa->uaa_device, 0); | 792 | devinfop = usbd_devinfo_alloc(uaa->uaa_device, 0); | |
787 | aprint_normal_dev(self, "%s\n", devinfop); | 793 | aprint_normal_dev(self, "%s\n", devinfop); | |
788 | usbd_devinfo_free(devinfop); | 794 | usbd_devinfo_free(devinfop); | |
789 | 795 | |||
790 | un->un_dev = self; | 796 | un->un_dev = self; | |
791 | un->un_udev = dev; | 797 | un->un_udev = dev; | |
792 | un->un_sc = sc; | 798 | un->un_sc = sc; | |
793 | un->un_ops = &aue_ops; | 799 | un->un_ops = &aue_ops; | |
794 | un->un_intr = &sc->aue_intr; | 800 | un->un_intr = &sc->aue_intr; | |
795 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 801 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
796 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 802 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
797 | un->un_rx_list_cnt = AUE_RX_LIST_CNT; | 803 | un->un_rx_list_cnt = AUE_RX_LIST_CNT; | |
798 | un->un_tx_list_cnt = AUE_RX_LIST_CNT; | 804 | un->un_tx_list_cnt = AUE_RX_LIST_CNT; | |
799 | un->un_rx_bufsz = AUE_BUFSZ; | 805 | un->un_rx_bufsz = AUE_BUFSZ; | |
800 | un->un_tx_bufsz = AUE_BUFSZ; | 806 | un->un_tx_bufsz = AUE_BUFSZ; | |
801 | 807 | |||
802 | sc->aue_intr.uni_buf = &sc->aue_ibuf; | 808 | sc->aue_intr.uni_buf = &sc->aue_ibuf; | |
803 | sc->aue_intr.uni_bufsz = sizeof(sc->aue_ibuf); | 809 | sc->aue_intr.uni_bufsz = sizeof(sc->aue_ibuf); | |
804 | sc->aue_intr.uni_interval = AUE_INTR_INTERVAL; | 810 | sc->aue_intr.uni_interval = AUE_INTR_INTERVAL; | |
805 | 811 | |||
806 | err = usbd_set_config_no(dev, AUE_CONFIG_NO, 1); | 812 | err = usbd_set_config_no(dev, AUE_CONFIG_NO, 1); | |
807 | if (err) { | 813 | if (err) { | |
808 | aprint_error_dev(self, "failed to set configuration" | 814 | aprint_error_dev(self, "failed to set configuration" | |
809 | ", err=%s\n", usbd_errstr(err)); | 815 | ", err=%s\n", usbd_errstr(err)); | |
810 | return; | 816 | return; | |
811 | } | 817 | } | |
812 | 818 | |||
813 | err = usbd_device2interface_handle(dev, AUE_IFACE_IDX, &un->un_iface); | 819 | err = usbd_device2interface_handle(dev, AUE_IFACE_IDX, &un->un_iface); | |
814 | if (err) { | 820 | if (err) { | |
815 | aprint_error_dev(self, "getting interface handle failed\n"); | 821 | aprint_error_dev(self, "getting interface handle failed\n"); | |
816 | return; | 822 | return; | |
817 | } | 823 | } | |
818 | 824 | |||
819 | un->un_flags = aue_lookup(uaa->uaa_vendor, uaa->uaa_product)->aue_flags; | 825 | un->un_flags = aue_lookup(uaa->uaa_vendor, uaa->uaa_product)->aue_flags; | |
820 | 826 | |||
821 | id = usbd_get_interface_descriptor(un->un_iface); | 827 | id = usbd_get_interface_descriptor(un->un_iface); | |
822 | 828 | |||
823 | /* Find endpoints. */ | 829 | /* Find endpoints. */ | |
824 | for (i = 0; i < id->bNumEndpoints; i++) { | 830 | for (i = 0; i < id->bNumEndpoints; i++) { | |
825 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 831 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
826 | if (ed == NULL) { | 832 | if (ed == NULL) { | |
827 | aprint_error_dev(self, | 833 | aprint_error_dev(self, | |
828 | "couldn't get endpoint descriptor %d\n", i); | 834 | "couldn't get endpoint descriptor %d\n", i); | |
829 | return; | 835 | return; | |
830 | } | 836 | } | |
831 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 837 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
832 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 838 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
833 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 839 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
834 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 840 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
835 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 841 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
836 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 842 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
837 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 843 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
838 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 844 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
839 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 845 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
840 | } | 846 | } | |
841 | } | 847 | } | |
842 | 848 | |||
843 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 849 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
844 | un->un_ed[USBNET_ENDPT_TX] == 0 || | 850 | un->un_ed[USBNET_ENDPT_TX] == 0 || | |
845 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | 851 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | |
846 | aprint_error_dev(self, "missing endpoint\n"); | 852 | aprint_error_dev(self, "missing endpoint\n"); | |
847 | return; | 853 | return; | |
848 | } | 854 | } | |
849 | 855 | |||
850 | /* First level attach. */ | 856 | /* First level attach. */ | |
851 | usbnet_attach(un, "auedet"); | 857 | usbnet_attach(un, "auedet"); | |
852 | 858 | |||
853 | usbnet_lock_core(un); | 859 | usbnet_lock_core(un); | |
854 | 860 | |||
855 | /* Reset the adapter and get station address from the EEPROM. */ | 861 | /* Reset the adapter and get station address from the EEPROM. */ | |
856 | aue_reset(sc); | 862 | aue_reset(sc); | |
857 | aue_read_mac(un); | 863 | aue_read_mac(un); | |
858 | 864 | |||
859 | usbnet_unlock_core(un); | 865 | usbnet_unlock_core(un); | |
860 | 866 | |||
861 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 867 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
862 | 0, &unm); | 868 | 0, &unm); | |
863 | } | 869 | } | |
864 | 870 | |||
865 | static void | 871 | static void | |
866 | aue_uno_intr(struct usbnet *un, usbd_status status) | 872 | aue_uno_intr(struct usbnet *un, usbd_status status) | |
867 | { | 873 | { | |
868 | struct ifnet *ifp = usbnet_ifp(un); | 874 | struct ifnet *ifp = usbnet_ifp(un); | |
869 | struct aue_softc *sc = usbnet_softc(un); | 875 | struct aue_softc *sc = usbnet_softc(un); | |
870 | struct aue_intrpkt *p = &sc->aue_ibuf; | 876 | struct aue_intrpkt *p = &sc->aue_ibuf; | |
871 | 877 | |||
872 | AUEHIST_FUNC(); | 878 | AUEHIST_FUNC(); | |
873 | AUEHIST_CALLARGSN(20, "aue%jd: enter txstat0 %#jx\n", | 879 | AUEHIST_CALLARGSN(20, "aue%jd: enter txstat0 %#jx\n", | |
874 | device_unit(un->un_dev), p->aue_txstat0, 0, 0); | 880 | device_unit(un->un_dev), p->aue_txstat0, 0, 0); | |
875 | 881 | |||
876 | if (p->aue_txstat0) | 882 | if (p->aue_txstat0) | |
877 | if_statinc(ifp, if_oerrors); | 883 | if_statinc(ifp, if_oerrors); | |
878 | 884 | |||
879 | if (p->aue_txstat0 & (AUE_TXSTAT0_LATECOLL | AUE_TXSTAT0_EXCESSCOLL)) | 885 | if (p->aue_txstat0 & (AUE_TXSTAT0_LATECOLL | AUE_TXSTAT0_EXCESSCOLL)) | |
880 | if_statinc(ifp, if_collisions); | 886 | if_statinc(ifp, if_collisions); | |
881 | } | 887 | } | |
882 | 888 | |||
883 | static void | 889 | static void | |
884 | aue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 890 | aue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
885 | { | 891 | { | |
886 | struct ifnet *ifp = usbnet_ifp(un); | 892 | struct ifnet *ifp = usbnet_ifp(un); | |
887 | uint8_t *buf = c->unc_buf; | 893 | uint8_t *buf = c->unc_buf; | |
888 | struct aue_rxpkt r; | 894 | struct aue_rxpkt r; | |
889 | uint32_t pktlen; | 895 | uint32_t pktlen; | |
890 | 896 | |||
891 | AUEHIST_FUNC(); | 897 | AUEHIST_FUNC(); | |
892 | AUEHIST_CALLARGSN(10, "aue%jd: enter len %ju", | 898 | AUEHIST_CALLARGSN(10, "aue%jd: enter len %ju", | |
893 | device_unit(un->un_dev), total_len, 0, 0); | 899 | device_unit(un->un_dev), total_len, 0, 0); | |
894 | 900 | |||
895 | if (total_len <= 4 + ETHER_CRC_LEN) { | 901 | if (total_len <= 4 + ETHER_CRC_LEN) { | |
896 | if_statinc(ifp, if_ierrors); | 902 | if_statinc(ifp, if_ierrors); | |
897 | return; | 903 | return; | |
898 | } | 904 | } | |
899 | 905 | |||
900 | memcpy(&r, buf + total_len - 4, sizeof(r)); | 906 | memcpy(&r, buf + total_len - 4, sizeof(r)); | |
901 | 907 | |||
902 | /* Turn off all the non-error bits in the rx status word. */ | 908 | /* Turn off all the non-error bits in the rx status word. */ | |
903 | r.aue_rxstat &= AUE_RXSTAT_MASK; | 909 | r.aue_rxstat &= AUE_RXSTAT_MASK; | |
904 | if (r.aue_rxstat) { | 910 | if (r.aue_rxstat) { | |
905 | if_statinc(ifp, if_ierrors); | 911 | if_statinc(ifp, if_ierrors); | |
906 | return; | 912 | return; | |
907 | } | 913 | } | |
908 | 914 | |||
909 | /* No errors; receive the packet. */ | 915 | /* No errors; receive the packet. */ | |
910 | pktlen = total_len - ETHER_CRC_LEN - 4; | 916 | pktlen = total_len - ETHER_CRC_LEN - 4; | |
911 | 917 | |||
912 | usbnet_enqueue(un, buf, pktlen, 0, 0, 0); | 918 | usbnet_enqueue(un, buf, pktlen, 0, 0, 0); | |
913 | } | 919 | } | |
914 | 920 | |||
915 | static unsigned | 921 | static unsigned | |
916 | aue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 922 | aue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
917 | { | 923 | { | |
918 | uint8_t *buf = c->unc_buf; | 924 | uint8_t *buf = c->unc_buf; | |
919 | int total_len; | 925 | int total_len; | |
920 | 926 | |||
921 | AUEHIST_FUNC(); | 927 | AUEHIST_FUNC(); | |
922 | AUEHIST_CALLARGSN(10, "aue%jd: enter pktlen=%jd", | 928 | AUEHIST_CALLARGSN(10, "aue%jd: enter pktlen=%jd", | |
923 | device_unit(un->un_dev), m->m_pkthdr.len, 0, 0); | 929 | device_unit(un->un_dev), m->m_pkthdr.len, 0, 0); | |
924 | 930 | |||
925 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | 931 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | |
926 | return 0; | 932 | return 0; | |
927 | 933 | |||
928 | /* | 934 | /* | |
929 | * Copy the mbuf data into a contiguous buffer, leaving two | 935 | * Copy the mbuf data into a contiguous buffer, leaving two | |
930 | * bytes at the beginning to hold the frame length. | 936 | * bytes at the beginning to hold the frame length. | |
931 | */ | 937 | */ | |
932 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | 938 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | |
933 | 939 | |||
934 | /* | 940 | /* | |
935 | * The ADMtek documentation says that the packet length is | 941 | * The ADMtek documentation says that the packet length is | |
936 | * supposed to be specified in the first two bytes of the | 942 | * supposed to be specified in the first two bytes of the | |
937 | * transfer, however it actually seems to ignore this info | 943 | * transfer, however it actually seems to ignore this info | |
938 | * and base the frame size on the bulk transfer length. | 944 | * and base the frame size on the bulk transfer length. | |
939 | */ | 945 | */ | |
940 | buf[0] = (uint8_t)m->m_pkthdr.len; | 946 | buf[0] = (uint8_t)m->m_pkthdr.len; | |
941 | buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); | 947 | buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); | |
942 | total_len = m->m_pkthdr.len + 2; | 948 | total_len = m->m_pkthdr.len + 2; | |
943 | 949 | |||
944 | DPRINTFN(5, "aue%jd: send %jd bytes", | 950 | DPRINTFN(5, "aue%jd: send %jd bytes", | |
945 | device_unit(un->un_dev), total_len, 0, 0); | 951 | device_unit(un->un_dev), total_len, 0, 0); | |
946 | 952 | |||
947 | return total_len; | 953 | return total_len; | |
948 | } | 954 | } | |
949 | 955 | |||
950 | static int | 956 | static int | |
951 | aue_init_locked(struct ifnet *ifp) | 957 | aue_init_locked(struct ifnet *ifp) | |
952 | { | 958 | { | |
953 | struct usbnet * const un = ifp->if_softc; | 959 | struct usbnet * const un = ifp->if_softc; | |
954 | struct aue_softc *sc = usbnet_softc(un); | 960 | struct aue_softc *sc = usbnet_softc(un); | |
955 | int i, rv; | 961 | int i, rv; | |
956 | const u_char *eaddr; | 962 | const u_char *eaddr; | |
957 | 963 | |||
958 | AUEHIST_FUNC(); | 964 | AUEHIST_FUNC(); | |
959 | AUEHIST_CALLARGSN(5, "aue%jd: enter link=%jd", | 965 | AUEHIST_CALLARGSN(5, "aue%jd: enter link=%jd", | |
960 | device_unit(un->un_dev), usbnet_havelink(un), 0, 0); | 966 | device_unit(un->un_dev), usbnet_havelink(un), 0, 0); | |
961 | 967 | |||
962 | if (usbnet_isdying(un)) | 968 | if (usbnet_isdying(un)) | |
963 | return EIO; | 969 | return EIO; | |
964 | 970 | |||
965 | /* Cancel pending I/O */ | 971 | /* Cancel pending I/O */ | |
966 | if (ifp->if_flags & IFF_RUNNING) | 972 | if (ifp->if_flags & IFF_RUNNING) | |
967 | return 0; | 973 | return 0; | |
968 | 974 | |||
969 | /* Reset the interface. */ | 975 | /* Reset the interface. */ | |
970 | aue_reset(sc); | 976 | aue_reset(sc); | |
971 | 977 | |||
972 | eaddr = CLLADDR(ifp->if_sadl); | 978 | eaddr = CLLADDR(ifp->if_sadl); | |
973 | for (i = 0; i < ETHER_ADDR_LEN; i++) | 979 | for (i = 0; i < ETHER_ADDR_LEN; i++) | |
974 | aue_csr_write_1(sc, AUE_PAR0 + i, eaddr[i]); | 980 | aue_csr_write_1(sc, AUE_PAR0 + i, eaddr[i]); | |
975 | 981 | |||
976 | /* If we want promiscuous mode, set the allframes bit. */ | 982 | /* If we want promiscuous mode, set the allframes bit. */ | |
977 | if (ifp->if_flags & IFF_PROMISC) | 983 | if (ifp->if_flags & IFF_PROMISC) | |
978 | AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); | 984 | AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); | |
979 | else | 985 | else | |
980 | AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); | 986 | AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); | |
981 | 987 | |||
982 | rv = usbnet_init_rx_tx(un); | 988 | rv = usbnet_init_rx_tx(un); | |
983 | 989 | |||
984 | /* Load the multicast filter. */ | 990 | /* Load the multicast filter. */ | |
985 | aue_setiff_locked(un); | 991 | aue_setiff_locked(un); | |
986 | 992 | |||
987 | /* Enable RX and TX */ | 993 | /* Enable RX and TX */ | |
988 | aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB); | 994 | aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB); | |
989 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_TX_ENB); | 995 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_TX_ENB); | |
990 | AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_EP3_CLR); | 996 | AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_EP3_CLR); | |
991 | 997 | |||
992 | //mii_mediachg(mii); | 998 | //mii_mediachg(mii); | |
993 | 999 | |||
994 | return rv; | 1000 | return rv; | |
995 | } | 1001 | } | |
996 | 1002 | |||
997 | static int | 1003 | static int | |
998 | aue_uno_init(struct ifnet *ifp) | 1004 | aue_uno_init(struct ifnet *ifp) | |
999 | { | 1005 | { | |
1000 | struct usbnet * const un = ifp->if_softc; | 1006 | struct usbnet * const un = ifp->if_softc; | |
1001 | int rv; | 1007 | int rv; | |
1002 | 1008 | |||
1003 | usbnet_busy(un); | 1009 | usbnet_busy(un); | |
1004 | rv = aue_init_locked(ifp); | 1010 | rv = aue_init_locked(ifp); | |
1005 | usbnet_unbusy(un); | 1011 | usbnet_unbusy(un); | |
1006 | 1012 | |||
1007 | return rv; | 1013 | return rv; | |
1008 | } | 1014 | } | |
1009 | 1015 | |||
1010 | static int | 1016 | static int | |
1011 | aue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 1017 | aue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
1012 | { | 1018 | { | |
1013 | struct usbnet * const un = ifp->if_softc; | 1019 | struct usbnet * const un = ifp->if_softc; | |
1014 | 1020 | |||
1015 | AUEHIST_FUNC(); | 1021 | AUEHIST_FUNC(); | |
1016 | AUEHIST_CALLARGSN(5, "aue%jd: enter cmd %#jx data %#jx", | 1022 | AUEHIST_CALLARGSN(5, "aue%jd: enter cmd %#jx data %#jx", | |
1017 | device_unit(((struct usbnet *)(ifp->if_softc))->un_dev), | 1023 | device_unit(((struct usbnet *)(ifp->if_softc))->un_dev), | |
1018 | cmd, (uintptr_t)data, 0); | 1024 | cmd, (uintptr_t)data, 0); | |
1019 | 1025 | |||
1020 | switch (cmd) { | 1026 | switch (cmd) { | |
1021 | case SIOCADDMULTI: | 1027 | case SIOCADDMULTI: | |
1022 | case SIOCDELMULTI: | 1028 | case SIOCDELMULTI: | |
1023 | usbnet_lock_core(un); | 1029 | usbnet_lock_core(un); | |
1024 | aue_uno_init(ifp); | 1030 | aue_uno_init(ifp); | |
1025 | usbnet_unlock_core(un); | 1031 | usbnet_unlock_core(un); | |
1026 | break; | 1032 | break; | |
1027 | default: | 1033 | default: | |
1028 | break; | 1034 | break; | |
1029 | } | 1035 | } | |
1030 | 1036 | |||
1031 | return 0; | 1037 | return 0; | |
1032 | } | 1038 | } | |
1033 | 1039 | |||
1034 | static void | 1040 | static void | |
1035 | aue_uno_stop(struct ifnet *ifp, int disable) | 1041 | aue_uno_stop(struct ifnet *ifp, int disable) | |
1036 | { | 1042 | { | |
1037 | struct usbnet * const un = ifp->if_softc; | 1043 | struct usbnet * const un = ifp->if_softc; | |
1038 | struct aue_softc * const sc = usbnet_softc(un); | 1044 | struct aue_softc * const sc = usbnet_softc(un); | |
1039 | 1045 | |||
1040 | AUEHIST_FUNC(); | 1046 | AUEHIST_FUNC(); | |
1041 | AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | 1047 | AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | |
1042 | 1048 | |||
1043 | aue_csr_write_1(sc, AUE_CTL0, 0); | 1049 | aue_csr_write_1(sc, AUE_CTL0, 0); | |
1044 | aue_csr_write_1(sc, AUE_CTL1, 0); | 1050 | aue_csr_write_1(sc, AUE_CTL1, 0); | |
1045 | aue_reset(sc); | 1051 | aue_reset(sc); | |
1046 | } | 1052 | } | |
1047 | 1053 | |||
1048 | #ifdef _MODULE | 1054 | #ifdef _MODULE | |
1049 | #include "ioconf.c" | 1055 | #include "ioconf.c" | |
1050 | #endif | 1056 | #endif | |
1051 | 1057 | |||
1052 | USBNET_MODULE(aue) | 1058 | USBNET_MODULE(aue) |
--- src/sys/dev/usb/if_mos.c 2022/03/03 05:50:22 1.8
+++ src/sys/dev/usb/if_mos.c 2022/03/03 05:50:57 1.9
@@ -1,799 +1,803 @@ | @@ -1,799 +1,803 @@ | |||
1 | /* $NetBSD: if_mos.c,v 1.8 2022/03/03 05:50:22 riastradh Exp $ */ | 1 | /* $NetBSD: if_mos.c,v 1.9 2022/03/03 05:50:57 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.8 2022/03/03 05:50:22 riastradh Exp $"); | 75 | __KERNEL_RCSID(0, "$NetBSD: if_mos.c,v 1.9 2022/03/03 05:50:57 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 int mos_uno_ioctl(struct ifnet *, u_long, void *); | 148 | static int mos_uno_ioctl(struct ifnet *, u_long, void *); | |
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_ioctl = mos_uno_ioctl, | 167 | .uno_ioctl = mos_uno_ioctl, | |
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)) | |||
368 | return ENXIO; | |||
367 | 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) | |
368 | break; | 370 | break; | |
369 | } | 371 | } | |
370 | if (i == MOS_TIMEOUT) { | 372 | if (i == MOS_TIMEOUT) { | |
371 | aprint_error_dev(un->un_dev, "read PHY failed\n"); | 373 | aprint_error_dev(un->un_dev, "read PHY failed\n"); | |
372 | return EIO; | 374 | return EIO; | |
373 | } | 375 | } | |
374 | 376 | |||
375 | res = mos_reg_read_2(un, MOS_PHY_DATA); | 377 | res = mos_reg_read_2(un, MOS_PHY_DATA); | |
376 | *val = res; | 378 | *val = res; | |
377 | 379 | |||
378 | DPRINTFN(10,("%s: %s: phy %d reg %d val %u\n", | 380 | DPRINTFN(10,("%s: %s: phy %d reg %d val %u\n", | |
379 | device_xname(un->un_dev), __func__, phy, reg, res)); | 381 | device_xname(un->un_dev), __func__, phy, reg, res)); | |
380 | 382 | |||
381 | return 0; | 383 | return 0; | |
382 | } | 384 | } | |
383 | 385 | |||
384 | static int | 386 | static int | |
385 | 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) | |
386 | { | 388 | { | |
387 | int i; | 389 | int i; | |
388 | 390 | |||
389 | DPRINTFN(10,("%s: %s: phy %d reg %d val %u\n", | 391 | DPRINTFN(10,("%s: %s: phy %d reg %d val %u\n", | |
390 | device_xname(un->un_dev), __func__, phy, reg, val)); | 392 | device_xname(un->un_dev), __func__, phy, reg, val)); | |
391 | 393 | |||
392 | mos_reg_write_2(un, MOS_PHY_DATA, val); | 394 | mos_reg_write_2(un, MOS_PHY_DATA, val); | |
393 | 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) | | |
394 | MOS_PHYCTL_WRITE); | 396 | MOS_PHYCTL_WRITE); | |
395 | 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) | | |
396 | MOS_PHYSTS_PENDING); | 398 | MOS_PHYSTS_PENDING); | |
397 | 399 | |||
398 | for (i = 0; i < MOS_TIMEOUT; i++) { | 400 | for (i = 0; i < MOS_TIMEOUT; i++) { | |
401 | if (usbnet_isdying(un)) | |||
402 | return ENXIO; | |||
399 | 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) | |
400 | break; | 404 | break; | |
401 | } | 405 | } | |
402 | if (i == MOS_TIMEOUT) { | 406 | if (i == MOS_TIMEOUT) { | |
403 | aprint_error_dev(un->un_dev, "write PHY failed\n"); | 407 | aprint_error_dev(un->un_dev, "write PHY failed\n"); | |
404 | return EIO; | 408 | return EIO; | |
405 | } | 409 | } | |
406 | 410 | |||
407 | return 0; | 411 | return 0; | |
408 | } | 412 | } | |
409 | 413 | |||
410 | void | 414 | void | |
411 | mos_uno_mii_statchg(struct ifnet *ifp) | 415 | mos_uno_mii_statchg(struct ifnet *ifp) | |
412 | { | 416 | { | |
413 | struct usbnet * const un = ifp->if_softc; | 417 | struct usbnet * const un = ifp->if_softc; | |
414 | struct mii_data * const mii = usbnet_mii(un); | 418 | struct mii_data * const mii = usbnet_mii(un); | |
415 | int val, err; | 419 | int val, err; | |
416 | 420 | |||
417 | if (usbnet_isdying(un)) | 421 | if (usbnet_isdying(un)) | |
418 | return; | 422 | return; | |
419 | 423 | |||
420 | 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__)); | |
421 | 425 | |||
422 | /* disable RX, TX prior to changing FDX, SPEEDSEL */ | 426 | /* disable RX, TX prior to changing FDX, SPEEDSEL */ | |
423 | val = mos_reg_read_1(un, MOS_CTL); | 427 | val = mos_reg_read_1(un, MOS_CTL); | |
424 | val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); | 428 | val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); | |
425 | mos_reg_write_1(un, MOS_CTL, val); | 429 | mos_reg_write_1(un, MOS_CTL, val); | |
426 | 430 | |||
427 | /* reset register which counts dropped frames */ | 431 | /* reset register which counts dropped frames */ | |
428 | mos_reg_write_1(un, MOS_FRAME_DROP_CNT, 0); | 432 | mos_reg_write_1(un, MOS_FRAME_DROP_CNT, 0); | |
429 | 433 | |||
430 | if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) | 434 | if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) | |
431 | val |= MOS_CTL_FDX_ENB; | 435 | val |= MOS_CTL_FDX_ENB; | |
432 | else | 436 | else | |
433 | val &= ~(MOS_CTL_FDX_ENB); | 437 | val &= ~(MOS_CTL_FDX_ENB); | |
434 | 438 | |||
435 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 439 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
436 | (IFM_ACTIVE | IFM_AVALID)) { | 440 | (IFM_ACTIVE | IFM_AVALID)) { | |
437 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 441 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
438 | case IFM_100_TX: | 442 | case IFM_100_TX: | |
439 | val |= MOS_CTL_SPEEDSEL; | 443 | val |= MOS_CTL_SPEEDSEL; | |
440 | break; | 444 | break; | |
441 | case IFM_10_T: | 445 | case IFM_10_T: | |
442 | val &= ~(MOS_CTL_SPEEDSEL); | 446 | val &= ~(MOS_CTL_SPEEDSEL); | |
443 | break; | 447 | break; | |
444 | } | 448 | } | |
445 | usbnet_set_link(un, true); | 449 | usbnet_set_link(un, true); | |
446 | } | 450 | } | |
447 | 451 | |||
448 | /* re-enable TX, RX */ | 452 | /* re-enable TX, RX */ | |
449 | val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); | 453 | val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); | |
450 | err = mos_reg_write_1(un, MOS_CTL, val); | 454 | err = mos_reg_write_1(un, MOS_CTL, val); | |
451 | 455 | |||
452 | if (err) | 456 | if (err) | |
453 | aprint_error_dev(un->un_dev, "media change failed\n"); | 457 | aprint_error_dev(un->un_dev, "media change failed\n"); | |
454 | } | 458 | } | |
455 | 459 | |||
456 | static void | 460 | static void | |
457 | mos_rcvfilt_locked(struct usbnet *un) | 461 | mos_rcvfilt_locked(struct usbnet *un) | |
458 | { | 462 | { | |
459 | struct ifnet *ifp = usbnet_ifp(un); | 463 | struct ifnet *ifp = usbnet_ifp(un); | |
460 | struct ethercom *ec = usbnet_ec(un); | 464 | struct ethercom *ec = usbnet_ec(un); | |
461 | struct ether_multi *enm; | 465 | struct ether_multi *enm; | |
462 | struct ether_multistep step; | 466 | struct ether_multistep step; | |
463 | u_int32_t h = 0; | 467 | u_int32_t h = 0; | |
464 | 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 }; | |
465 | 469 | |||
466 | if (usbnet_isdying(un)) | 470 | if (usbnet_isdying(un)) | |
467 | return; | 471 | return; | |
468 | 472 | |||
469 | rxmode = mos_reg_read_1(un, MOS_CTL); | 473 | rxmode = mos_reg_read_1(un, MOS_CTL); | |
470 | rxmode &= ~(MOS_CTL_ALLMULTI | MOS_CTL_RX_PROMISC); | 474 | rxmode &= ~(MOS_CTL_ALLMULTI | MOS_CTL_RX_PROMISC); | |
471 | 475 | |||
472 | ETHER_LOCK(ec); | 476 | ETHER_LOCK(ec); | |
473 | if (ifp->if_flags & IFF_PROMISC) { | 477 | if (ifp->if_flags & IFF_PROMISC) { | |
474 | ec->ec_flags |= ETHER_F_ALLMULTI; | 478 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
475 | ETHER_UNLOCK(ec); | 479 | ETHER_UNLOCK(ec); | |
476 | /* run promisc. mode */ | 480 | /* run promisc. mode */ | |
477 | rxmode |= MOS_CTL_ALLMULTI; /* ??? */ | 481 | rxmode |= MOS_CTL_ALLMULTI; /* ??? */ | |
478 | rxmode |= MOS_CTL_RX_PROMISC; | 482 | rxmode |= MOS_CTL_RX_PROMISC; | |
479 | goto update; | 483 | goto update; | |
480 | } | 484 | } | |
481 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 485 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
482 | ETHER_FIRST_MULTI(step, ec, enm); | 486 | ETHER_FIRST_MULTI(step, ec, enm); | |
483 | while (enm != NULL) { | 487 | while (enm != NULL) { | |
484 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 488 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
485 | ec->ec_flags |= ETHER_F_ALLMULTI; | 489 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
486 | ETHER_UNLOCK(ec); | 490 | ETHER_UNLOCK(ec); | |
487 | memset(mchash, 0, sizeof(mchash)); /* correct ??? */ | 491 | memset(mchash, 0, sizeof(mchash)); /* correct ??? */ | |
488 | /* accept all multicast frame */ | 492 | /* accept all multicast frame */ | |
489 | rxmode |= MOS_CTL_ALLMULTI; | 493 | rxmode |= MOS_CTL_ALLMULTI; | |
490 | goto update; | 494 | goto update; | |
491 | } | 495 | } | |
492 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | 496 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | |
493 | /* 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] */ | |
494 | mchash[h >> 29] |= 1 << ((h >> 26) % 8); | 498 | mchash[h >> 29] |= 1 << ((h >> 26) % 8); | |
495 | ETHER_NEXT_MULTI(step, enm); | 499 | ETHER_NEXT_MULTI(step, enm); | |
496 | } | 500 | } | |
497 | ETHER_UNLOCK(ec); | 501 | ETHER_UNLOCK(ec); | |
498 | /* MOS receive filter is always on */ | 502 | /* MOS receive filter is always on */ | |
499 | update: | 503 | update: | |
500 | /* | 504 | /* | |
501 | * The datasheet claims broadcast frames were always accepted | 505 | * The datasheet claims broadcast frames were always accepted | |
502 | * regardless of filter settings. But the hardware seems to | 506 | * regardless of filter settings. But the hardware seems to | |
503 | * filter broadcast frames, so pass them explicitly. | 507 | * filter broadcast frames, so pass them explicitly. | |
504 | */ | 508 | */ | |
505 | mchash[7] |= 0x80; | 509 | mchash[7] |= 0x80; | |
506 | mos_write_mcast(un, mchash); | 510 | mos_write_mcast(un, mchash); | |
507 | mos_reg_write_1(un, MOS_CTL, rxmode); | 511 | mos_reg_write_1(un, MOS_CTL, rxmode); | |
508 | } | 512 | } | |
509 | 513 | |||
510 | static void | 514 | static void | |
511 | mos_reset(struct usbnet *un) | 515 | mos_reset(struct usbnet *un) | |
512 | { | 516 | { | |
513 | u_int8_t ctl; | 517 | u_int8_t ctl; | |
514 | 518 | |||
515 | if (usbnet_isdying(un)) | 519 | if (usbnet_isdying(un)) | |
516 | return; | 520 | return; | |
517 | 521 | |||
518 | ctl = mos_reg_read_1(un, MOS_CTL); | 522 | ctl = mos_reg_read_1(un, MOS_CTL); | |
519 | 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 | | |
520 | MOS_CTL_RX_ENB); | 524 | MOS_CTL_RX_ENB); | |
521 | /* Disable RX, TX, promiscuous and allmulticast mode */ | 525 | /* Disable RX, TX, promiscuous and allmulticast mode */ | |
522 | mos_reg_write_1(un, MOS_CTL, ctl); | 526 | mos_reg_write_1(un, MOS_CTL, ctl); | |
523 | 527 | |||
524 | /* Reset frame drop counter register to zero */ | 528 | /* Reset frame drop counter register to zero */ | |
525 | mos_reg_write_1(un, MOS_FRAME_DROP_CNT, 0); | 529 | mos_reg_write_1(un, MOS_FRAME_DROP_CNT, 0); | |
526 | 530 | |||
527 | /* 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. */ | |
528 | DELAY(1000); | 532 | DELAY(1000); | |
529 | } | 533 | } | |
530 | 534 | |||
531 | void | 535 | void | |
532 | mos_chip_init(struct usbnet *un) | 536 | mos_chip_init(struct usbnet *un) | |
533 | { | 537 | { | |
534 | int i; | 538 | int i; | |
535 | 539 | |||
536 | /* | 540 | /* | |
537 | * 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 | |
538 | * at startup. | 542 | * at startup. | |
539 | */ | 543 | */ | |
540 | if (mos_reg_read_1(un, MOS_PAUSE_TRHD) != -1) { | 544 | if (mos_reg_read_1(un, MOS_PAUSE_TRHD) != -1) { | |
541 | for (i = 0; i < MOS_PAUSE_REWRITES; i++) | 545 | for (i = 0; i < MOS_PAUSE_REWRITES; i++) | |
542 | mos_reg_write_1(un, MOS_PAUSE_TRHD, 0); | 546 | mos_reg_write_1(un, MOS_PAUSE_TRHD, 0); | |
543 | } | 547 | } | |
544 | } | 548 | } | |
545 | 549 | |||
546 | /* | 550 | /* | |
547 | * Probe for a MCS7x30 chip. | 551 | * Probe for a MCS7x30 chip. | |
548 | */ | 552 | */ | |
549 | static int | 553 | static int | |
550 | mos_match(device_t parent, cfdata_t match, void *aux) | 554 | mos_match(device_t parent, cfdata_t match, void *aux) | |
551 | { | 555 | { | |
552 | struct usb_attach_arg *uaa = aux; | 556 | struct usb_attach_arg *uaa = aux; | |
553 | 557 | |||
554 | return (mos_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 558 | return (mos_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
555 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE); | 559 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE); | |
556 | } | 560 | } | |
557 | 561 | |||
558 | /* | 562 | /* | |
559 | * Attach the interface. | 563 | * Attach the interface. | |
560 | */ | 564 | */ | |
561 | static void | 565 | static void | |
562 | mos_attach(device_t parent, device_t self, void *aux) | 566 | mos_attach(device_t parent, device_t self, void *aux) | |
563 | { | 567 | { | |
564 | USBNET_MII_DECL_DEFAULT(unm); | 568 | USBNET_MII_DECL_DEFAULT(unm); | |
565 | struct usbnet * un = device_private(self); | 569 | struct usbnet * un = device_private(self); | |
566 | struct usb_attach_arg *uaa = aux; | 570 | struct usb_attach_arg *uaa = aux; | |
567 | struct usbd_device *dev = uaa->uaa_device; | 571 | struct usbd_device *dev = uaa->uaa_device; | |
568 | usbd_status err; | 572 | usbd_status err; | |
569 | usb_interface_descriptor_t *id; | 573 | usb_interface_descriptor_t *id; | |
570 | usb_endpoint_descriptor_t *ed; | 574 | usb_endpoint_descriptor_t *ed; | |
571 | char *devinfop; | 575 | char *devinfop; | |
572 | int i; | 576 | int i; | |
573 | 577 | |||
574 | aprint_naive("\n"); | 578 | aprint_naive("\n"); | |
575 | aprint_normal("\n"); | 579 | aprint_normal("\n"); | |
576 | devinfop = usbd_devinfo_alloc(dev, 0); | 580 | devinfop = usbd_devinfo_alloc(dev, 0); | |
577 | aprint_normal_dev(self, "%s\n", devinfop); | 581 | aprint_normal_dev(self, "%s\n", devinfop); | |
578 | usbd_devinfo_free(devinfop); | 582 | usbd_devinfo_free(devinfop); | |
579 | 583 | |||
580 | un->un_dev = self; | 584 | un->un_dev = self; | |
581 | un->un_udev = dev; | 585 | un->un_udev = dev; | |
582 | un->un_sc = un; | 586 | un->un_sc = un; | |
583 | un->un_ops = &mos_ops; | 587 | un->un_ops = &mos_ops; | |
584 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 588 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
585 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 589 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
586 | un->un_rx_list_cnt = MOS_RX_LIST_CNT; | 590 | un->un_rx_list_cnt = MOS_RX_LIST_CNT; | |
587 | un->un_tx_list_cnt = MOS_TX_LIST_CNT; | 591 | un->un_tx_list_cnt = MOS_TX_LIST_CNT; | |
588 | un->un_rx_bufsz = un->un_tx_bufsz = MOS_BUFSZ; | 592 | un->un_rx_bufsz = un->un_tx_bufsz = MOS_BUFSZ; | |
589 | 593 | |||
590 | err = usbd_set_config_no(dev, MOS_CONFIG_NO, 1); | 594 | err = usbd_set_config_no(dev, MOS_CONFIG_NO, 1); | |
591 | if (err) { | 595 | if (err) { | |
592 | aprint_error_dev(self, "failed to set configuration" | 596 | aprint_error_dev(self, "failed to set configuration" | |
593 | ", err=%s\n", usbd_errstr(err)); | 597 | ", err=%s\n", usbd_errstr(err)); | |
594 | return; | 598 | return; | |
595 | } | 599 | } | |
596 | 600 | |||
597 | err = usbd_device2interface_handle(dev, MOS_IFACE_IDX, &un->un_iface); | 601 | err = usbd_device2interface_handle(dev, MOS_IFACE_IDX, &un->un_iface); | |
598 | if (err) { | 602 | if (err) { | |
599 | aprint_error_dev(self, "failed getting interface handle" | 603 | aprint_error_dev(self, "failed getting interface handle" | |
600 | ", err=%s\n", usbd_errstr(err)); | 604 | ", err=%s\n", usbd_errstr(err)); | |
601 | return; | 605 | return; | |
602 | } | 606 | } | |
603 | 607 | |||
604 | 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; | |
605 | 609 | |||
606 | id = usbd_get_interface_descriptor(un->un_iface); | 610 | id = usbd_get_interface_descriptor(un->un_iface); | |
607 | 611 | |||
608 | /* Find endpoints. */ | 612 | /* Find endpoints. */ | |
609 | for (i = 0; i < id->bNumEndpoints; i++) { | 613 | for (i = 0; i < id->bNumEndpoints; i++) { | |
610 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 614 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
611 | if (!ed) { | 615 | if (!ed) { | |
612 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 616 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
613 | return; | 617 | return; | |
614 | } | 618 | } | |
615 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 619 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
616 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 620 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
617 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 621 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
618 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 622 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
619 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 623 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
620 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 624 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
621 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 625 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
622 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 626 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
623 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 627 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
624 | } | 628 | } | |
625 | } | 629 | } | |
626 | 630 | |||
627 | if (un->un_flags & MCS7730) | 631 | if (un->un_flags & MCS7730) | |
628 | aprint_normal_dev(self, "MCS7730\n"); | 632 | aprint_normal_dev(self, "MCS7730\n"); | |
629 | else if (un->un_flags & MCS7830) | 633 | else if (un->un_flags & MCS7830) | |
630 | aprint_normal_dev(self, "MCS7830\n"); | 634 | aprint_normal_dev(self, "MCS7830\n"); | |
631 | else if (un->un_flags & MCS7832) | 635 | else if (un->un_flags & MCS7832) | |
632 | aprint_normal_dev(self, "MCS7832\n"); | 636 | aprint_normal_dev(self, "MCS7832\n"); | |
633 | 637 | |||
634 | /* Set these up now for register access. */ | 638 | /* Set these up now for register access. */ | |
635 | usbnet_attach(un, "mosdet"); | 639 | usbnet_attach(un, "mosdet"); | |
636 | 640 | |||
637 | mos_chip_init(un); | 641 | mos_chip_init(un); | |
638 | 642 | |||
639 | /* | 643 | /* | |
640 | * Read MAC address, inform the world. | 644 | * Read MAC address, inform the world. | |
641 | */ | 645 | */ | |
642 | err = mos_readmac(un); | 646 | err = mos_readmac(un); | |
643 | if (err) { | 647 | if (err) { | |
644 | aprint_error_dev(self, "couldn't read MAC address\n"); | 648 | aprint_error_dev(self, "couldn't read MAC address\n"); | |
645 | return; | 649 | return; | |
646 | } | 650 | } | |
647 | 651 | |||
648 | struct ifnet *ifp = usbnet_ifp(un); | 652 | struct ifnet *ifp = usbnet_ifp(un); | |
649 | ifp->if_capabilities = ETHERCAP_VLAN_MTU; | 653 | ifp->if_capabilities = ETHERCAP_VLAN_MTU; | |
650 | 654 | |||
651 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 655 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
652 | 0, &unm); | 656 | 0, &unm); | |
653 | } | 657 | } | |
654 | 658 | |||
655 | /* | 659 | /* | |
656 | * 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 | |
657 | * the higher level protocols. | 661 | * the higher level protocols. | |
658 | */ | 662 | */ | |
659 | void | 663 | void | |
660 | 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) | |
661 | { | 665 | { | |
662 | struct ifnet *ifp = usbnet_ifp(un); | 666 | struct ifnet *ifp = usbnet_ifp(un); | |
663 | uint8_t *buf = c->unc_buf; | 667 | uint8_t *buf = c->unc_buf; | |
664 | u_int8_t rxstat; | 668 | u_int8_t rxstat; | |
665 | u_int16_t pktlen = 0; | 669 | u_int16_t pktlen = 0; | |
666 | 670 | |||
667 | DPRINTFN(5,("%s: %s: enter len %u\n", | 671 | DPRINTFN(5,("%s: %s: enter len %u\n", | |
668 | device_xname(un->un_dev), __func__, total_len)); | 672 | device_xname(un->un_dev), __func__, total_len)); | |
669 | 673 | |||
670 | if (total_len <= 1) | 674 | if (total_len <= 1) | |
671 | return; | 675 | return; | |
672 | 676 | |||
673 | /* evaluate status byte at the end */ | 677 | /* evaluate status byte at the end */ | |
674 | pktlen = total_len - 1; | 678 | pktlen = total_len - 1; | |
675 | if (pktlen > un->un_rx_bufsz) { | 679 | if (pktlen > un->un_rx_bufsz) { | |
676 | if_statinc(ifp, if_ierrors); | 680 | if_statinc(ifp, if_ierrors); | |
677 | return; | 681 | return; | |
678 | } | 682 | } | |
679 | rxstat = buf[pktlen] & MOS_RXSTS_MASK; | 683 | rxstat = buf[pktlen] & MOS_RXSTS_MASK; | |
680 | 684 | |||
681 | if (rxstat != MOS_RXSTS_VALID) { | 685 | if (rxstat != MOS_RXSTS_VALID) { | |
682 | DPRINTF(("%s: erroneous frame received: ", | 686 | DPRINTF(("%s: erroneous frame received: ", | |
683 | device_xname(un->un_dev))); | 687 | device_xname(un->un_dev))); | |
684 | if (rxstat & MOS_RXSTS_SHORT_FRAME) | 688 | if (rxstat & MOS_RXSTS_SHORT_FRAME) | |
685 | DPRINTF(("frame size less than 64 bytes\n")); | 689 | DPRINTF(("frame size less than 64 bytes\n")); | |
686 | if (rxstat & MOS_RXSTS_LARGE_FRAME) | 690 | if (rxstat & MOS_RXSTS_LARGE_FRAME) | |
687 | DPRINTF(("frame size larger than 1532 bytes\n")); | 691 | DPRINTF(("frame size larger than 1532 bytes\n")); | |
688 | if (rxstat & MOS_RXSTS_CRC_ERROR) | 692 | if (rxstat & MOS_RXSTS_CRC_ERROR) | |
689 | DPRINTF(("CRC error\n")); | 693 | DPRINTF(("CRC error\n")); | |
690 | if (rxstat & MOS_RXSTS_ALIGN_ERROR) | 694 | if (rxstat & MOS_RXSTS_ALIGN_ERROR) | |
691 | DPRINTF(("alignment error\n")); | 695 | DPRINTF(("alignment error\n")); | |
692 | if_statinc(ifp, if_ierrors); | 696 | if_statinc(ifp, if_ierrors); | |
693 | return; | 697 | return; | |
694 | } | 698 | } | |
695 | 699 | |||
696 | if (pktlen < sizeof(struct ether_header) ) { | 700 | if (pktlen < sizeof(struct ether_header) ) { | |
697 | if_statinc(ifp, if_ierrors); | 701 | if_statinc(ifp, if_ierrors); | |
698 | return; | 702 | return; | |
699 | } | 703 | } | |
700 | 704 | |||
701 | usbnet_enqueue(un, c->unc_buf, pktlen, 0, 0, 0); | 705 | usbnet_enqueue(un, c->unc_buf, pktlen, 0, 0, 0); | |
702 | } | 706 | } | |
703 | 707 | |||
704 | static unsigned | 708 | static unsigned | |
705 | 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) | |
706 | { | 710 | { | |
707 | int length; | 711 | int length; | |
708 | 712 | |||
709 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | 713 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | |
710 | return 0; | 714 | return 0; | |
711 | 715 | |||
712 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | 716 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | |
713 | length = m->m_pkthdr.len; | 717 | length = m->m_pkthdr.len; | |
714 | 718 | |||
715 | DPRINTFN(5,("%s: %s: len %u\n", | 719 | DPRINTFN(5,("%s: %s: len %u\n", | |
716 | device_xname(un->un_dev), __func__, length)); | 720 | device_xname(un->un_dev), __func__, length)); | |
717 | 721 | |||
718 | return length; | 722 | return length; | |
719 | } | 723 | } | |
720 | 724 | |||
721 | static int | 725 | static int | |
722 | mos_init_locked(struct ifnet *ifp) | 726 | mos_init_locked(struct ifnet *ifp) | |
723 | { | 727 | { | |
724 | struct usbnet * const un = ifp->if_softc; | 728 | struct usbnet * const un = ifp->if_softc; | |
725 | u_int8_t rxmode; | 729 | u_int8_t rxmode; | |
726 | unsigned char ipgs[2]; | 730 | unsigned char ipgs[2]; | |
727 | 731 | |||
728 | if (usbnet_isdying(un)) | 732 | if (usbnet_isdying(un)) | |
729 | return EIO; | 733 | return EIO; | |
730 | 734 | |||
731 | /* Cancel pending I/O */ | 735 | /* Cancel pending I/O */ | |
732 | usbnet_stop(un, ifp, 1); | 736 | usbnet_stop(un, ifp, 1); | |
733 | 737 | |||
734 | /* Reset the ethernet interface. */ | 738 | /* Reset the ethernet interface. */ | |
735 | mos_reset(un); | 739 | mos_reset(un); | |
736 | 740 | |||
737 | /* Write MAC address. */ | 741 | /* Write MAC address. */ | |
738 | mos_writemac(un); | 742 | mos_writemac(un); | |
739 | 743 | |||
740 | /* Read and set transmitter IPG values */ | 744 | /* Read and set transmitter IPG values */ | |
741 | ipgs[0] = mos_reg_read_1(un, MOS_IPG0); | 745 | ipgs[0] = mos_reg_read_1(un, MOS_IPG0); | |
742 | ipgs[1] = mos_reg_read_1(un, MOS_IPG1); | 746 | ipgs[1] = mos_reg_read_1(un, MOS_IPG1); | |
743 | mos_reg_write_1(un, MOS_IPG0, ipgs[0]); | 747 | mos_reg_write_1(un, MOS_IPG0, ipgs[0]); | |
744 | mos_reg_write_1(un, MOS_IPG1, ipgs[1]); | 748 | mos_reg_write_1(un, MOS_IPG1, ipgs[1]); | |
745 | 749 | |||
746 | /* Accept multicast frame or run promisc. mode */ | 750 | /* Accept multicast frame or run promisc. mode */ | |
747 | mos_rcvfilt_locked(un); | 751 | mos_rcvfilt_locked(un); | |
748 | 752 | |||
749 | /* Enable receiver and transmitter, bridge controls speed/duplex mode */ | 753 | /* Enable receiver and transmitter, bridge controls speed/duplex mode */ | |
750 | rxmode = mos_reg_read_1(un, MOS_CTL); | 754 | rxmode = mos_reg_read_1(un, MOS_CTL); | |
751 | 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; | |
752 | rxmode &= ~(MOS_CTL_SLEEP); | 756 | rxmode &= ~(MOS_CTL_SLEEP); | |
753 | mos_reg_write_1(un, MOS_CTL, rxmode); | 757 | mos_reg_write_1(un, MOS_CTL, rxmode); | |
754 | 758 | |||
755 | return usbnet_init_rx_tx(un); | 759 | return usbnet_init_rx_tx(un); | |
756 | } | 760 | } | |
757 | 761 | |||
758 | static int | 762 | static int | |
759 | mos_uno_init(struct ifnet *ifp) | 763 | mos_uno_init(struct ifnet *ifp) | |
760 | { | 764 | { | |
761 | struct usbnet * const un = ifp->if_softc; | 765 | struct usbnet * const un = ifp->if_softc; | |
762 | 766 | |||
763 | usbnet_busy(un); | 767 | usbnet_busy(un); | |
764 | int ret = mos_init_locked(ifp); | 768 | int ret = mos_init_locked(ifp); | |
765 | usbnet_unbusy(un); | 769 | usbnet_unbusy(un); | |
766 | 770 | |||
767 | return ret; | 771 | return ret; | |
768 | } | 772 | } | |
769 | 773 | |||
770 | static int | 774 | static int | |
771 | mos_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 775 | mos_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
772 | { | 776 | { | |
773 | struct usbnet * const un = ifp->if_softc; | 777 | struct usbnet * const un = ifp->if_softc; | |
774 | 778 | |||
775 | usbnet_lock_core(un); | 779 | usbnet_lock_core(un); | |
776 | usbnet_busy(un); | 780 | usbnet_busy(un); | |
777 | 781 | |||
778 | switch (cmd) { | 782 | switch (cmd) { | |
779 | case SIOCADDMULTI: | 783 | case SIOCADDMULTI: | |
780 | case SIOCDELMULTI: | 784 | case SIOCDELMULTI: | |
781 | mos_rcvfilt_locked(un); | 785 | mos_rcvfilt_locked(un); | |
782 | break; | 786 | break; | |
783 | default: | 787 | default: | |
784 | break; | 788 | break; | |
785 | } | 789 | } | |
786 | 790 | |||
787 | usbnet_unbusy(un); | 791 | usbnet_unbusy(un); | |
788 | usbnet_unlock_core(un); | 792 | usbnet_unlock_core(un); | |
789 | 793 | |||
790 | return 0; | 794 | return 0; | |
791 | } | 795 | } | |
792 | 796 | |||
793 | void | 797 | void | |
794 | mos_uno_stop(struct ifnet *ifp, int disable) | 798 | mos_uno_stop(struct ifnet *ifp, int disable) | |
795 | { | 799 | { | |
796 | struct usbnet * const un = ifp->if_softc; | 800 | struct usbnet * const un = ifp->if_softc; | |
797 | 801 | |||
798 | mos_reset(un); | 802 | mos_reset(un); | |
799 | } | 803 | } |
--- src/sys/dev/usb/if_mue.c 2022/03/03 05:50:22 1.64
+++ src/sys/dev/usb/if_mue.c 2022/03/03 05:50:57 1.65
@@ -1,1201 +1,1203 @@ | @@ -1,1201 +1,1203 @@ | |||
1 | /* $NetBSD: if_mue.c,v 1.64 2022/03/03 05:50:22 riastradh Exp $ */ | 1 | /* $NetBSD: if_mue.c,v 1.65 2022/03/03 05:50:57 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.64 2022/03/03 05:50:22 riastradh Exp $"); | 23 | __KERNEL_RCSID(0, "$NetBSD: if_mue.c,v 1.65 2022/03/03 05:50:57 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 int mue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 102 | static int mue_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
103 | static int mue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 103 | static int mue_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
104 | static void mue_uno_mii_statchg(struct ifnet *); | 104 | static void mue_uno_mii_statchg(struct ifnet *); | |
105 | static void mue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 105 | static void mue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
106 | uint32_t); | 106 | uint32_t); | |
107 | static unsigned mue_uno_tx_prepare(struct usbnet *, struct mbuf *, | 107 | static unsigned mue_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
108 | struct usbnet_chain *); | 108 | struct usbnet_chain *); | |
109 | static int mue_uno_init(struct ifnet *); | 109 | static int mue_uno_init(struct ifnet *); | |
110 | 110 | |||
111 | static const struct usbnet_ops mue_ops = { | 111 | static const struct usbnet_ops mue_ops = { | |
112 | .uno_stop = mue_uno_stop, | 112 | .uno_stop = mue_uno_stop, | |
113 | .uno_ioctl = mue_uno_ioctl, | 113 | .uno_ioctl = mue_uno_ioctl, | |
114 | .uno_read_reg = mue_uno_mii_read_reg, | 114 | .uno_read_reg = mue_uno_mii_read_reg, | |
115 | .uno_write_reg = mue_uno_mii_write_reg, | 115 | .uno_write_reg = mue_uno_mii_write_reg, | |
116 | .uno_statchg = mue_uno_mii_statchg, | 116 | .uno_statchg = mue_uno_mii_statchg, | |
117 | .uno_tx_prepare = mue_uno_tx_prepare, | 117 | .uno_tx_prepare = mue_uno_tx_prepare, | |
118 | .uno_rx_loop = mue_uno_rx_loop, | 118 | .uno_rx_loop = mue_uno_rx_loop, | |
119 | .uno_init = mue_uno_init, | 119 | .uno_init = mue_uno_init, | |
120 | }; | 120 | }; | |
121 | 121 | |||
122 | #define MUE_SETBIT(un, reg, x) \ | 122 | #define MUE_SETBIT(un, reg, x) \ | |
123 | mue_csr_write(un, reg, mue_csr_read(un, reg) | (x)) | 123 | mue_csr_write(un, reg, mue_csr_read(un, reg) | (x)) | |
124 | 124 | |||
125 | #define MUE_CLRBIT(un, reg, x) \ | 125 | #define MUE_CLRBIT(un, reg, x) \ | |
126 | mue_csr_write(un, reg, mue_csr_read(un, reg) & ~(x)) | 126 | mue_csr_write(un, reg, mue_csr_read(un, reg) & ~(x)) | |
127 | 127 | |||
128 | #define MUE_WAIT_SET(un, reg, set, fail) \ | 128 | #define MUE_WAIT_SET(un, reg, set, fail) \ | |
129 | mue_wait_for_bits(un, reg, set, ~0, fail) | 129 | mue_wait_for_bits(un, reg, set, ~0, fail) | |
130 | 130 | |||
131 | #define MUE_WAIT_CLR(un, reg, clear, fail) \ | 131 | #define MUE_WAIT_CLR(un, reg, clear, fail) \ | |
132 | mue_wait_for_bits(un, reg, 0, clear, fail) | 132 | mue_wait_for_bits(un, reg, 0, clear, fail) | |
133 | 133 | |||
134 | #define ETHER_IS_VALID(addr) \ | 134 | #define ETHER_IS_VALID(addr) \ | |
135 | (!ETHER_IS_MULTICAST(addr) && !ETHER_IS_ZERO(addr)) | 135 | (!ETHER_IS_MULTICAST(addr) && !ETHER_IS_ZERO(addr)) | |
136 | 136 | |||
137 | #define ETHER_IS_ZERO(addr) \ | 137 | #define ETHER_IS_ZERO(addr) \ | |
138 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | 138 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | |
139 | 139 | |||
140 | CFATTACH_DECL_NEW(mue, sizeof(struct usbnet), mue_match, mue_attach, | 140 | CFATTACH_DECL_NEW(mue, sizeof(struct usbnet), mue_match, mue_attach, | |
141 | usbnet_detach, usbnet_activate); | 141 | usbnet_detach, usbnet_activate); | |
142 | 142 | |||
143 | static uint32_t | 143 | static uint32_t | |
144 | mue_csr_read(struct usbnet *un, uint32_t reg) | 144 | mue_csr_read(struct usbnet *un, uint32_t reg) | |
145 | { | 145 | { | |
146 | usb_device_request_t req; | 146 | usb_device_request_t req; | |
147 | usbd_status err; | 147 | usbd_status err; | |
148 | uDWord val; | 148 | uDWord val; | |
149 | 149 | |||
150 | if (usbnet_isdying(un)) | 150 | if (usbnet_isdying(un)) | |
151 | return 0; | 151 | return 0; | |
152 | 152 | |||
153 | USETDW(val, 0); | 153 | USETDW(val, 0); | |
154 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 154 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
155 | req.bRequest = MUE_UR_READREG; | 155 | req.bRequest = MUE_UR_READREG; | |
156 | USETW(req.wValue, 0); | 156 | USETW(req.wValue, 0); | |
157 | USETW(req.wIndex, reg); | 157 | USETW(req.wIndex, reg); | |
158 | USETW(req.wLength, 4); | 158 | USETW(req.wLength, 4); | |
159 | 159 | |||
160 | err = usbd_do_request(un->un_udev, &req, &val); | 160 | err = usbd_do_request(un->un_udev, &req, &val); | |
161 | if (err) { | 161 | if (err) { | |
162 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | 162 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | |
163 | return 0; | 163 | return 0; | |
164 | } | 164 | } | |
165 | 165 | |||
166 | return UGETDW(val); | 166 | return UGETDW(val); | |
167 | } | 167 | } | |
168 | 168 | |||
169 | static int | 169 | static int | |
170 | mue_csr_write(struct usbnet *un, uint32_t reg, uint32_t aval) | 170 | mue_csr_write(struct usbnet *un, uint32_t reg, uint32_t aval) | |
171 | { | 171 | { | |
172 | usb_device_request_t req; | 172 | usb_device_request_t req; | |
173 | usbd_status err; | 173 | usbd_status err; | |
174 | uDWord val; | 174 | uDWord val; | |
175 | 175 | |||
176 | if (usbnet_isdying(un)) | 176 | if (usbnet_isdying(un)) | |
177 | return 0; | 177 | return 0; | |
178 | 178 | |||
179 | USETDW(val, aval); | 179 | USETDW(val, aval); | |
180 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 180 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
181 | req.bRequest = MUE_UR_WRITEREG; | 181 | req.bRequest = MUE_UR_WRITEREG; | |
182 | USETW(req.wValue, 0); | 182 | USETW(req.wValue, 0); | |
183 | USETW(req.wIndex, reg); | 183 | USETW(req.wIndex, reg); | |
184 | USETW(req.wLength, 4); | 184 | USETW(req.wLength, 4); | |
185 | 185 | |||
186 | err = usbd_do_request(un->un_udev, &req, &val); | 186 | err = usbd_do_request(un->un_udev, &req, &val); | |
187 | if (err) { | 187 | if (err) { | |
188 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | 188 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | |
189 | return -1; | 189 | return -1; | |
190 | } | 190 | } | |
191 | 191 | |||
192 | return 0; | 192 | return 0; | |
193 | } | 193 | } | |
194 | 194 | |||
195 | static int | 195 | static int | |
196 | mue_wait_for_bits(struct usbnet *un, uint32_t reg, | 196 | mue_wait_for_bits(struct usbnet *un, uint32_t reg, | |
197 | uint32_t set, uint32_t clear, uint32_t fail) | 197 | uint32_t set, uint32_t clear, uint32_t fail) | |
198 | { | 198 | { | |
199 | uint32_t val; | 199 | uint32_t val; | |
200 | int ntries; | 200 | int ntries; | |
201 | 201 | |||
202 | for (ntries = 0; ntries < 1000; ntries++) { | 202 | for (ntries = 0; ntries < 1000; ntries++) { | |
203 | if (usbnet_isdying(un)) | |||
204 | return 1; | |||
203 | val = mue_csr_read(un, reg); | 205 | val = mue_csr_read(un, reg); | |
204 | if ((val & set) || !(val & clear)) | 206 | if ((val & set) || !(val & clear)) | |
205 | return 0; | 207 | return 0; | |
206 | if (val & fail) | 208 | if (val & fail) | |
207 | return 1; | 209 | return 1; | |
208 | usbd_delay_ms(un->un_udev, 1); | 210 | usbd_delay_ms(un->un_udev, 1); | |
209 | } | 211 | } | |
210 | 212 | |||
211 | return 1; | 213 | return 1; | |
212 | } | 214 | } | |
213 | 215 | |||
214 | static int | 216 | static int | |
215 | mue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 217 | mue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
216 | { | 218 | { | |
217 | uint32_t data; | 219 | uint32_t data; | |
218 | 220 | |||
219 | if (un->un_phyno != phy) | 221 | if (un->un_phyno != phy) | |
220 | return EINVAL; | 222 | return EINVAL; | |
221 | 223 | |||
222 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 224 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
223 | MUE_PRINTF(un, "not ready\n"); | 225 | MUE_PRINTF(un, "not ready\n"); | |
224 | return EBUSY; | 226 | return EBUSY; | |
225 | } | 227 | } | |
226 | 228 | |||
227 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_READ | | 229 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_READ | | |
228 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | 230 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | |
229 | MUE_MII_ACCESS_PHYADDR(phy)); | 231 | MUE_MII_ACCESS_PHYADDR(phy)); | |
230 | 232 | |||
231 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 233 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
232 | MUE_PRINTF(un, "timed out\n"); | 234 | MUE_PRINTF(un, "timed out\n"); | |
233 | return ETIMEDOUT; | 235 | return ETIMEDOUT; | |
234 | } | 236 | } | |
235 | 237 | |||
236 | data = mue_csr_read(un, MUE_MII_DATA); | 238 | data = mue_csr_read(un, MUE_MII_DATA); | |
237 | *val = data & 0xffff; | 239 | *val = data & 0xffff; | |
238 | 240 | |||
239 | return 0; | 241 | return 0; | |
240 | } | 242 | } | |
241 | 243 | |||
242 | static int | 244 | static int | |
243 | mue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 245 | mue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
244 | { | 246 | { | |
245 | 247 | |||
246 | if (un->un_phyno != phy) | 248 | if (un->un_phyno != phy) | |
247 | return EINVAL; | 249 | return EINVAL; | |
248 | 250 | |||
249 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 251 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
250 | MUE_PRINTF(un, "not ready\n"); | 252 | MUE_PRINTF(un, "not ready\n"); | |
251 | return EBUSY; | 253 | return EBUSY; | |
252 | } | 254 | } | |
253 | 255 | |||
254 | mue_csr_write(un, MUE_MII_DATA, val); | 256 | mue_csr_write(un, MUE_MII_DATA, val); | |
255 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_WRITE | | 257 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_WRITE | | |
256 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | 258 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | |
257 | MUE_MII_ACCESS_PHYADDR(phy)); | 259 | MUE_MII_ACCESS_PHYADDR(phy)); | |
258 | 260 | |||
259 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 261 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
260 | MUE_PRINTF(un, "timed out\n"); | 262 | MUE_PRINTF(un, "timed out\n"); | |
261 | return ETIMEDOUT; | 263 | return ETIMEDOUT; | |
262 | } | 264 | } | |
263 | 265 | |||
264 | return 0; | 266 | return 0; | |
265 | } | 267 | } | |
266 | 268 | |||
267 | static void | 269 | static void | |
268 | mue_uno_mii_statchg(struct ifnet *ifp) | 270 | mue_uno_mii_statchg(struct ifnet *ifp) | |
269 | { | 271 | { | |
270 | struct usbnet * const un = ifp->if_softc; | 272 | struct usbnet * const un = ifp->if_softc; | |
271 | struct mii_data * const mii = usbnet_mii(un); | 273 | struct mii_data * const mii = usbnet_mii(un); | |
272 | uint32_t flow, threshold; | 274 | uint32_t flow, threshold; | |
273 | 275 | |||
274 | if (usbnet_isdying(un)) | 276 | if (usbnet_isdying(un)) | |
275 | return; | 277 | return; | |
276 | 278 | |||
277 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 279 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
278 | (IFM_ACTIVE | IFM_AVALID)) { | 280 | (IFM_ACTIVE | IFM_AVALID)) { | |
279 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 281 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
280 | case IFM_10_T: | 282 | case IFM_10_T: | |
281 | case IFM_100_TX: | 283 | case IFM_100_TX: | |
282 | case IFM_1000_T: | 284 | case IFM_1000_T: | |
283 | usbnet_set_link(un, true); | 285 | usbnet_set_link(un, true); | |
284 | break; | 286 | break; | |
285 | default: | 287 | default: | |
286 | break; | 288 | break; | |
287 | } | 289 | } | |
288 | } | 290 | } | |
289 | 291 | |||
290 | /* Lost link, do nothing. */ | 292 | /* Lost link, do nothing. */ | |
291 | if (!usbnet_havelink(un)) { | 293 | if (!usbnet_havelink(un)) { | |
292 | DPRINTF(un, "mii_media_status = %#x\n", mii->mii_media_status); | 294 | DPRINTF(un, "mii_media_status = %#x\n", mii->mii_media_status); | |
293 | return; | 295 | return; | |
294 | } | 296 | } | |
295 | 297 | |||
296 | if (!(un->un_flags & LAN7500)) { | 298 | if (!(un->un_flags & LAN7500)) { | |
297 | if (un->un_udev->ud_speed == USB_SPEED_SUPER) { | 299 | if (un->un_udev->ud_speed == USB_SPEED_SUPER) { | |
298 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { | 300 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { | |
299 | /* Disable U2 and enable U1. */ | 301 | /* Disable U2 and enable U1. */ | |
300 | MUE_CLRBIT(un, MUE_USB_CFG1, | 302 | MUE_CLRBIT(un, MUE_USB_CFG1, | |
301 | MUE_USB_CFG1_DEV_U2_INIT_EN); | 303 | MUE_USB_CFG1_DEV_U2_INIT_EN); | |
302 | MUE_SETBIT(un, MUE_USB_CFG1, | 304 | MUE_SETBIT(un, MUE_USB_CFG1, | |
303 | MUE_USB_CFG1_DEV_U1_INIT_EN); | 305 | MUE_USB_CFG1_DEV_U1_INIT_EN); | |
304 | } else { | 306 | } else { | |
305 | /* Enable U1 and U2. */ | 307 | /* Enable U1 and U2. */ | |
306 | MUE_SETBIT(un, MUE_USB_CFG1, | 308 | MUE_SETBIT(un, MUE_USB_CFG1, | |
307 | MUE_USB_CFG1_DEV_U1_INIT_EN | | 309 | MUE_USB_CFG1_DEV_U1_INIT_EN | | |
308 | MUE_USB_CFG1_DEV_U2_INIT_EN); | 310 | MUE_USB_CFG1_DEV_U2_INIT_EN); | |
309 | } | 311 | } | |
310 | } | 312 | } | |
311 | } | 313 | } | |
312 | 314 | |||
313 | flow = 0; | 315 | flow = 0; | |
314 | /* XXX Linux does not check IFM_FDX flag for 7800. */ | 316 | /* XXX Linux does not check IFM_FDX flag for 7800. */ | |
315 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { | 317 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { | |
316 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) | 318 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) | |
317 | flow |= MUE_FLOW_TX_FCEN | MUE_FLOW_PAUSE_TIME; | 319 | flow |= MUE_FLOW_TX_FCEN | MUE_FLOW_PAUSE_TIME; | |
318 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) | 320 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) | |
319 | flow |= MUE_FLOW_RX_FCEN; | 321 | flow |= MUE_FLOW_RX_FCEN; | |
320 | } | 322 | } | |
321 | 323 | |||
322 | /* XXX Magic numbers taken from Linux driver. */ | 324 | /* XXX Magic numbers taken from Linux driver. */ | |
323 | if (un->un_flags & LAN7500) | 325 | if (un->un_flags & LAN7500) | |
324 | threshold = 0x820; | 326 | threshold = 0x820; | |
325 | else | 327 | else | |
326 | switch (un->un_udev->ud_speed) { | 328 | switch (un->un_udev->ud_speed) { | |
327 | case USB_SPEED_SUPER: | 329 | case USB_SPEED_SUPER: | |
328 | threshold = 0x817; | 330 | threshold = 0x817; | |
329 | break; | 331 | break; | |
330 | case USB_SPEED_HIGH: | 332 | case USB_SPEED_HIGH: | |
331 | threshold = 0x211; | 333 | threshold = 0x211; | |
332 | break; | 334 | break; | |
333 | default: | 335 | default: | |
334 | threshold = 0; | 336 | threshold = 0; | |
335 | break; | 337 | break; | |
336 | } | 338 | } | |
337 | 339 | |||
338 | /* Threshold value should be set before enabling flow. */ | 340 | /* Threshold value should be set before enabling flow. */ | |
339 | mue_csr_write(un, (un->un_flags & LAN7500) ? | 341 | mue_csr_write(un, (un->un_flags & LAN7500) ? | |
340 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, threshold); | 342 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, threshold); | |
341 | mue_csr_write(un, MUE_FLOW, flow); | 343 | mue_csr_write(un, MUE_FLOW, flow); | |
342 | 344 | |||
343 | DPRINTF(un, "done\n"); | 345 | DPRINTF(un, "done\n"); | |
344 | } | 346 | } | |
345 | 347 | |||
346 | static uint8_t | 348 | static uint8_t | |
347 | mue_eeprom_getbyte(struct usbnet *un, int off, uint8_t *dest) | 349 | mue_eeprom_getbyte(struct usbnet *un, int off, uint8_t *dest) | |
348 | { | 350 | { | |
349 | uint32_t val; | 351 | uint32_t val; | |
350 | 352 | |||
351 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, 0)) { | 353 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, 0)) { | |
352 | MUE_PRINTF(un, "not ready\n"); | 354 | MUE_PRINTF(un, "not ready\n"); | |
353 | return ETIMEDOUT; | 355 | return ETIMEDOUT; | |
354 | } | 356 | } | |
355 | 357 | |||
356 | KASSERT((off & ~MUE_E2P_CMD_ADDR_MASK) == 0); | 358 | KASSERT((off & ~MUE_E2P_CMD_ADDR_MASK) == 0); | |
357 | mue_csr_write(un, MUE_E2P_CMD, MUE_E2P_CMD_READ | MUE_E2P_CMD_BUSY | | 359 | mue_csr_write(un, MUE_E2P_CMD, MUE_E2P_CMD_READ | MUE_E2P_CMD_BUSY | | |
358 | off); | 360 | off); | |
359 | 361 | |||
360 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, | 362 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, | |
361 | MUE_E2P_CMD_TIMEOUT)) { | 363 | MUE_E2P_CMD_TIMEOUT)) { | |
362 | MUE_PRINTF(un, "timed out\n"); | 364 | MUE_PRINTF(un, "timed out\n"); | |
363 | return ETIMEDOUT; | 365 | return ETIMEDOUT; | |
364 | } | 366 | } | |
365 | 367 | |||
366 | val = mue_csr_read(un, MUE_E2P_DATA); | 368 | val = mue_csr_read(un, MUE_E2P_DATA); | |
367 | *dest = val & 0xff; | 369 | *dest = val & 0xff; | |
368 | 370 | |||
369 | return 0; | 371 | return 0; | |
370 | } | 372 | } | |
371 | 373 | |||
372 | static int | 374 | static int | |
373 | mue_read_eeprom(struct usbnet *un, uint8_t *dest, int off, int cnt) | 375 | mue_read_eeprom(struct usbnet *un, uint8_t *dest, int off, int cnt) | |
374 | { | 376 | { | |
375 | uint32_t val = 0; /* XXX gcc */ | 377 | uint32_t val = 0; /* XXX gcc */ | |
376 | uint8_t byte; | 378 | uint8_t byte; | |
377 | int i, err = 0; | 379 | int i, err = 0; | |
378 | 380 | |||
379 | /* | 381 | /* | |
380 | * EEPROM pins are muxed with the LED function on LAN7800 device. | 382 | * EEPROM pins are muxed with the LED function on LAN7800 device. | |
381 | */ | 383 | */ | |
382 | if (un->un_flags & LAN7800) { | 384 | if (un->un_flags & LAN7800) { | |
383 | val = mue_csr_read(un, MUE_HW_CFG); | 385 | val = mue_csr_read(un, MUE_HW_CFG); | |
384 | mue_csr_write(un, MUE_HW_CFG, | 386 | mue_csr_write(un, MUE_HW_CFG, | |
385 | val & ~(MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN)); | 387 | val & ~(MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN)); | |
386 | } | 388 | } | |
387 | 389 | |||
388 | for (i = 0; i < cnt; i++) { | 390 | for (i = 0; i < cnt; i++) { | |
389 | err = mue_eeprom_getbyte(un, off + i, &byte); | 391 | err = mue_eeprom_getbyte(un, off + i, &byte); | |
390 | if (err) | 392 | if (err) | |
391 | break; | 393 | break; | |
392 | *(dest + i) = byte; | 394 | *(dest + i) = byte; | |
393 | } | 395 | } | |
394 | 396 | |||
395 | if (un->un_flags & LAN7800) | 397 | if (un->un_flags & LAN7800) | |
396 | mue_csr_write(un, MUE_HW_CFG, val); | 398 | mue_csr_write(un, MUE_HW_CFG, val); | |
397 | 399 | |||
398 | return err ? 1 : 0; | 400 | return err ? 1 : 0; | |
399 | } | 401 | } | |
400 | 402 | |||
401 | static bool | 403 | static bool | |
402 | mue_eeprom_present(struct usbnet *un) | 404 | mue_eeprom_present(struct usbnet *un) | |
403 | { | 405 | { | |
404 | uint32_t val; | 406 | uint32_t val; | |
405 | uint8_t sig; | 407 | uint8_t sig; | |
406 | int ret; | 408 | int ret; | |
407 | 409 | |||
408 | if (un->un_flags & LAN7500) { | 410 | if (un->un_flags & LAN7500) { | |
409 | val = mue_csr_read(un, MUE_E2P_CMD); | 411 | val = mue_csr_read(un, MUE_E2P_CMD); | |
410 | return val & MUE_E2P_CMD_LOADED; | 412 | return val & MUE_E2P_CMD_LOADED; | |
411 | } else { | 413 | } else { | |
412 | ret = mue_read_eeprom(un, &sig, MUE_E2P_IND_OFFSET, 1); | 414 | ret = mue_read_eeprom(un, &sig, MUE_E2P_IND_OFFSET, 1); | |
413 | return (ret == 0) && (sig == MUE_E2P_IND); | 415 | return (ret == 0) && (sig == MUE_E2P_IND); | |
414 | } | 416 | } | |
415 | } | 417 | } | |
416 | 418 | |||
417 | static int | 419 | static int | |
418 | mue_read_otp_raw(struct usbnet *un, uint8_t *dest, int off, int cnt) | 420 | mue_read_otp_raw(struct usbnet *un, uint8_t *dest, int off, int cnt) | |
419 | { | 421 | { | |
420 | uint32_t val; | 422 | uint32_t val; | |
421 | int i, err; | 423 | int i, err; | |
422 | 424 | |||
423 | val = mue_csr_read(un, MUE_OTP_PWR_DN); | 425 | val = mue_csr_read(un, MUE_OTP_PWR_DN); | |
424 | 426 | |||
425 | /* Checking if bit is set. */ | 427 | /* Checking if bit is set. */ | |
426 | if (val & MUE_OTP_PWR_DN_PWRDN_N) { | 428 | if (val & MUE_OTP_PWR_DN_PWRDN_N) { | |
427 | /* Clear it, then wait for it to be cleared. */ | 429 | /* Clear it, then wait for it to be cleared. */ | |
428 | mue_csr_write(un, MUE_OTP_PWR_DN, 0); | 430 | mue_csr_write(un, MUE_OTP_PWR_DN, 0); | |
429 | err = MUE_WAIT_CLR(un, MUE_OTP_PWR_DN, MUE_OTP_PWR_DN_PWRDN_N, | 431 | err = MUE_WAIT_CLR(un, MUE_OTP_PWR_DN, MUE_OTP_PWR_DN_PWRDN_N, | |
430 | 0); | 432 | 0); | |
431 | if (err) { | 433 | if (err) { | |
432 | MUE_PRINTF(un, "not ready\n"); | 434 | MUE_PRINTF(un, "not ready\n"); | |
433 | return 1; | 435 | return 1; | |
434 | } | 436 | } | |
435 | } | 437 | } | |
436 | 438 | |||
437 | /* Start reading the bytes, one at a time. */ | 439 | /* Start reading the bytes, one at a time. */ | |
438 | for (i = 0; i < cnt; i++) { | 440 | for (i = 0; i < cnt; i++) { | |
439 | mue_csr_write(un, MUE_OTP_ADDR1, | 441 | mue_csr_write(un, MUE_OTP_ADDR1, | |
440 | ((off + i) >> 8) & MUE_OTP_ADDR1_MASK); | 442 | ((off + i) >> 8) & MUE_OTP_ADDR1_MASK); | |
441 | mue_csr_write(un, MUE_OTP_ADDR2, | 443 | mue_csr_write(un, MUE_OTP_ADDR2, | |
442 | ((off + i) & MUE_OTP_ADDR2_MASK)); | 444 | ((off + i) & MUE_OTP_ADDR2_MASK)); | |
443 | mue_csr_write(un, MUE_OTP_FUNC_CMD, MUE_OTP_FUNC_CMD_READ); | 445 | mue_csr_write(un, MUE_OTP_FUNC_CMD, MUE_OTP_FUNC_CMD_READ); | |
444 | mue_csr_write(un, MUE_OTP_CMD_GO, MUE_OTP_CMD_GO_GO); | 446 | mue_csr_write(un, MUE_OTP_CMD_GO, MUE_OTP_CMD_GO_GO); | |
445 | 447 | |||
446 | err = MUE_WAIT_CLR(un, MUE_OTP_STATUS, MUE_OTP_STATUS_BUSY, 0); | 448 | err = MUE_WAIT_CLR(un, MUE_OTP_STATUS, MUE_OTP_STATUS_BUSY, 0); | |
447 | if (err) { | 449 | if (err) { | |
448 | MUE_PRINTF(un, "timed out\n"); | 450 | MUE_PRINTF(un, "timed out\n"); | |
449 | return 1; | 451 | return 1; | |
450 | } | 452 | } | |
451 | val = mue_csr_read(un, MUE_OTP_RD_DATA); | 453 | val = mue_csr_read(un, MUE_OTP_RD_DATA); | |
452 | *(dest + i) = (uint8_t)(val & 0xff); | 454 | *(dest + i) = (uint8_t)(val & 0xff); | |
453 | } | 455 | } | |
454 | 456 | |||
455 | return 0; | 457 | return 0; | |
456 | } | 458 | } | |
457 | 459 | |||
458 | static int | 460 | static int | |
459 | mue_read_otp(struct usbnet *un, uint8_t *dest, int off, int cnt) | 461 | mue_read_otp(struct usbnet *un, uint8_t *dest, int off, int cnt) | |
460 | { | 462 | { | |
461 | uint8_t sig; | 463 | uint8_t sig; | |
462 | int err; | 464 | int err; | |
463 | 465 | |||
464 | if (un->un_flags & LAN7500) | 466 | if (un->un_flags & LAN7500) | |
465 | return 1; | 467 | return 1; | |
466 | 468 | |||
467 | err = mue_read_otp_raw(un, &sig, MUE_OTP_IND_OFFSET, 1); | 469 | err = mue_read_otp_raw(un, &sig, MUE_OTP_IND_OFFSET, 1); | |
468 | if (err) | 470 | if (err) | |
469 | return 1; | 471 | return 1; | |
470 | switch (sig) { | 472 | switch (sig) { | |
471 | case MUE_OTP_IND_1: | 473 | case MUE_OTP_IND_1: | |
472 | break; | 474 | break; | |
473 | case MUE_OTP_IND_2: | 475 | case MUE_OTP_IND_2: | |
474 | off += 0x100; | 476 | off += 0x100; | |
475 | break; | 477 | break; | |
476 | default: | 478 | default: | |
477 | DPRINTF(un, "OTP not found\n"); | 479 | DPRINTF(un, "OTP not found\n"); | |
478 | return 1; | 480 | return 1; | |
479 | } | 481 | } | |
480 | err = mue_read_otp_raw(un, dest, off, cnt); | 482 | err = mue_read_otp_raw(un, dest, off, cnt); | |
481 | return err; | 483 | return err; | |
482 | } | 484 | } | |
483 | 485 | |||
484 | static void | 486 | static void | |
485 | mue_dataport_write(struct usbnet *un, uint32_t sel, uint32_t addr, | 487 | mue_dataport_write(struct usbnet *un, uint32_t sel, uint32_t addr, | |
486 | uint32_t cnt, uint32_t *data) | 488 | uint32_t cnt, uint32_t *data) | |
487 | { | 489 | { | |
488 | uint32_t i; | 490 | uint32_t i; | |
489 | 491 | |||
490 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | 492 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | |
491 | MUE_PRINTF(un, "not ready\n"); | 493 | MUE_PRINTF(un, "not ready\n"); | |
492 | return; | 494 | return; | |
493 | } | 495 | } | |
494 | 496 | |||
495 | mue_csr_write(un, MUE_DP_SEL, | 497 | mue_csr_write(un, MUE_DP_SEL, | |
496 | (mue_csr_read(un, MUE_DP_SEL) & ~MUE_DP_SEL_RSEL_MASK) | sel); | 498 | (mue_csr_read(un, MUE_DP_SEL) & ~MUE_DP_SEL_RSEL_MASK) | sel); | |
497 | 499 | |||
498 | for (i = 0; i < cnt; i++) { | 500 | for (i = 0; i < cnt; i++) { | |
499 | mue_csr_write(un, MUE_DP_ADDR, addr + i); | 501 | mue_csr_write(un, MUE_DP_ADDR, addr + i); | |
500 | mue_csr_write(un, MUE_DP_DATA, data[i]); | 502 | mue_csr_write(un, MUE_DP_DATA, data[i]); | |
501 | mue_csr_write(un, MUE_DP_CMD, MUE_DP_CMD_WRITE); | 503 | mue_csr_write(un, MUE_DP_CMD, MUE_DP_CMD_WRITE); | |
502 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | 504 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | |
503 | MUE_PRINTF(un, "timed out\n"); | 505 | MUE_PRINTF(un, "timed out\n"); | |
504 | return; | 506 | return; | |
505 | } | 507 | } | |
506 | } | 508 | } | |
507 | } | 509 | } | |
508 | 510 | |||
509 | static void | 511 | static void | |
510 | mue_init_ltm(struct usbnet *un) | 512 | mue_init_ltm(struct usbnet *un) | |
511 | { | 513 | { | |
512 | uint32_t idx[MUE_NUM_LTM_INDEX] = { 0, 0, 0, 0, 0, 0 }; | 514 | uint32_t idx[MUE_NUM_LTM_INDEX] = { 0, 0, 0, 0, 0, 0 }; | |
513 | uint8_t temp[2]; | 515 | uint8_t temp[2]; | |
514 | size_t i; | 516 | size_t i; | |
515 | 517 | |||
516 | if (mue_csr_read(un, MUE_USB_CFG1) & MUE_USB_CFG1_LTM_ENABLE) { | 518 | if (mue_csr_read(un, MUE_USB_CFG1) & MUE_USB_CFG1_LTM_ENABLE) { | |
517 | if (mue_eeprom_present(un) && | 519 | if (mue_eeprom_present(un) && | |
518 | (mue_read_eeprom(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0)) { | 520 | (mue_read_eeprom(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0)) { | |
519 | if (temp[0] != sizeof(idx)) { | 521 | if (temp[0] != sizeof(idx)) { | |
520 | DPRINTF(un, "EEPROM: unexpected size\n"); | 522 | DPRINTF(un, "EEPROM: unexpected size\n"); | |
521 | goto done; | 523 | goto done; | |
522 | } | 524 | } | |
523 | if (mue_read_eeprom(un, (uint8_t *)idx, temp[1] << 1, | 525 | if (mue_read_eeprom(un, (uint8_t *)idx, temp[1] << 1, | |
524 | sizeof(idx))) { | 526 | sizeof(idx))) { | |
525 | DPRINTF(un, "EEPROM: failed to read\n"); | 527 | DPRINTF(un, "EEPROM: failed to read\n"); | |
526 | goto done; | 528 | goto done; | |
527 | } | 529 | } | |
528 | DPRINTF(un, "success\n"); | 530 | DPRINTF(un, "success\n"); | |
529 | } else if (mue_read_otp(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0) { | 531 | } else if (mue_read_otp(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0) { | |
530 | if (temp[0] != sizeof(idx)) { | 532 | if (temp[0] != sizeof(idx)) { | |
531 | DPRINTF(un, "OTP: unexpected size\n"); | 533 | DPRINTF(un, "OTP: unexpected size\n"); | |
532 | goto done; | 534 | goto done; | |
533 | } | 535 | } | |
534 | if (mue_read_otp(un, (uint8_t *)idx, temp[1] << 1, | 536 | if (mue_read_otp(un, (uint8_t *)idx, temp[1] << 1, | |
535 | sizeof(idx))) { | 537 | sizeof(idx))) { | |
536 | DPRINTF(un, "OTP: failed to read\n"); | 538 | DPRINTF(un, "OTP: failed to read\n"); | |
537 | goto done; | 539 | goto done; | |
538 | } | 540 | } | |
539 | DPRINTF(un, "success\n"); | 541 | DPRINTF(un, "success\n"); | |
540 | } else | 542 | } else | |
541 | DPRINTF(un, "nothing to do\n"); | 543 | DPRINTF(un, "nothing to do\n"); | |
542 | } else | 544 | } else | |
543 | DPRINTF(un, "nothing to do\n"); | 545 | DPRINTF(un, "nothing to do\n"); | |
544 | done: | 546 | done: | |
545 | for (i = 0; i < __arraycount(idx); i++) | 547 | for (i = 0; i < __arraycount(idx); i++) | |
546 | mue_csr_write(un, MUE_LTM_INDEX(i), idx[i]); | 548 | mue_csr_write(un, MUE_LTM_INDEX(i), idx[i]); | |
547 | } | 549 | } | |
548 | 550 | |||
549 | static int | 551 | static int | |
550 | mue_chip_init(struct usbnet *un) | 552 | mue_chip_init(struct usbnet *un) | |
551 | { | 553 | { | |
552 | uint32_t val; | 554 | uint32_t val; | |
553 | 555 | |||
554 | if ((un->un_flags & LAN7500) && | 556 | if ((un->un_flags & LAN7500) && | |
555 | MUE_WAIT_SET(un, MUE_PMT_CTL, MUE_PMT_CTL_READY, 0)) { | 557 | MUE_WAIT_SET(un, MUE_PMT_CTL, MUE_PMT_CTL_READY, 0)) { | |
556 | MUE_PRINTF(un, "not ready\n"); | 558 | MUE_PRINTF(un, "not ready\n"); | |
557 | return ETIMEDOUT; | 559 | return ETIMEDOUT; | |
558 | } | 560 | } | |
559 | 561 | |||
560 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_LRST); | 562 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_LRST); | |
561 | if (MUE_WAIT_CLR(un, MUE_HW_CFG, MUE_HW_CFG_LRST, 0)) { | 563 | if (MUE_WAIT_CLR(un, MUE_HW_CFG, MUE_HW_CFG_LRST, 0)) { | |
562 | MUE_PRINTF(un, "timed out\n"); | 564 | MUE_PRINTF(un, "timed out\n"); | |
563 | return ETIMEDOUT; | 565 | return ETIMEDOUT; | |
564 | } | 566 | } | |
565 | 567 | |||
566 | /* Respond to the IN token with a NAK. */ | 568 | /* Respond to the IN token with a NAK. */ | |
567 | if (un->un_flags & LAN7500) | 569 | if (un->un_flags & LAN7500) | |
568 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BIR); | 570 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BIR); | |
569 | else | 571 | else | |
570 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BIR); | 572 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BIR); | |
571 | 573 | |||
572 | if (un->un_flags & LAN7500) { | 574 | if (un->un_flags & LAN7500) { | |
573 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | 575 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | |
574 | val = MUE_7500_HS_RX_BUFSIZE / | 576 | val = MUE_7500_HS_RX_BUFSIZE / | |
575 | MUE_HS_USB_PKT_SIZE; | 577 | MUE_HS_USB_PKT_SIZE; | |
576 | else | 578 | else | |
577 | val = MUE_7500_FS_RX_BUFSIZE / | 579 | val = MUE_7500_FS_RX_BUFSIZE / | |
578 | MUE_FS_USB_PKT_SIZE; | 580 | MUE_FS_USB_PKT_SIZE; | |
579 | mue_csr_write(un, MUE_7500_BURST_CAP, val); | 581 | mue_csr_write(un, MUE_7500_BURST_CAP, val); | |
580 | mue_csr_write(un, MUE_7500_BULKIN_DELAY, | 582 | mue_csr_write(un, MUE_7500_BULKIN_DELAY, | |
581 | MUE_7500_DEFAULT_BULKIN_DELAY); | 583 | MUE_7500_DEFAULT_BULKIN_DELAY); | |
582 | 584 | |||
583 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BCE | MUE_HW_CFG_MEF); | 585 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BCE | MUE_HW_CFG_MEF); | |
584 | 586 | |||
585 | /* Set FIFO sizes. */ | 587 | /* Set FIFO sizes. */ | |
586 | val = (MUE_7500_MAX_RX_FIFO_SIZE - 512) / 512; | 588 | val = (MUE_7500_MAX_RX_FIFO_SIZE - 512) / 512; | |
587 | mue_csr_write(un, MUE_7500_FCT_RX_FIFO_END, val); | 589 | mue_csr_write(un, MUE_7500_FCT_RX_FIFO_END, val); | |
588 | val = (MUE_7500_MAX_TX_FIFO_SIZE - 512) / 512; | 590 | val = (MUE_7500_MAX_TX_FIFO_SIZE - 512) / 512; | |
589 | mue_csr_write(un, MUE_7500_FCT_TX_FIFO_END, val); | 591 | mue_csr_write(un, MUE_7500_FCT_TX_FIFO_END, val); | |
590 | } else { | 592 | } else { | |
591 | /* Init LTM. */ | 593 | /* Init LTM. */ | |
592 | mue_init_ltm(un); | 594 | mue_init_ltm(un); | |
593 | 595 | |||
594 | val = MUE_7800_RX_BUFSIZE; | 596 | val = MUE_7800_RX_BUFSIZE; | |
595 | switch (un->un_udev->ud_speed) { | 597 | switch (un->un_udev->ud_speed) { | |
596 | case USB_SPEED_SUPER: | 598 | case USB_SPEED_SUPER: | |
597 | val /= MUE_SS_USB_PKT_SIZE; | 599 | val /= MUE_SS_USB_PKT_SIZE; | |
598 | break; | 600 | break; | |
599 | case USB_SPEED_HIGH: | 601 | case USB_SPEED_HIGH: | |
600 | val /= MUE_HS_USB_PKT_SIZE; | 602 | val /= MUE_HS_USB_PKT_SIZE; | |
601 | break; | 603 | break; | |
602 | default: | 604 | default: | |
603 | val /= MUE_FS_USB_PKT_SIZE; | 605 | val /= MUE_FS_USB_PKT_SIZE; | |
604 | break; | 606 | break; | |
605 | } | 607 | } | |
606 | mue_csr_write(un, MUE_7800_BURST_CAP, val); | 608 | mue_csr_write(un, MUE_7800_BURST_CAP, val); | |
607 | mue_csr_write(un, MUE_7800_BULKIN_DELAY, | 609 | mue_csr_write(un, MUE_7800_BULKIN_DELAY, | |
608 | MUE_7800_DEFAULT_BULKIN_DELAY); | 610 | MUE_7800_DEFAULT_BULKIN_DELAY); | |
609 | 611 | |||
610 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_MEF); | 612 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_MEF); | |
611 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BCE); | 613 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BCE); | |
612 | 614 | |||
613 | /* | 615 | /* | |
614 | * Set FCL's RX and TX FIFO sizes: according to data sheet this | 616 | * Set FCL's RX and TX FIFO sizes: according to data sheet this | |
615 | * is already the default value. But we initialize it to the | 617 | * is already the default value. But we initialize it to the | |
616 | * same value anyways, as that's what the Linux driver does. | 618 | * same value anyways, as that's what the Linux driver does. | |
617 | */ | 619 | */ | |
618 | val = (MUE_7800_MAX_RX_FIFO_SIZE - 512) / 512; | 620 | val = (MUE_7800_MAX_RX_FIFO_SIZE - 512) / 512; | |
619 | mue_csr_write(un, MUE_7800_FCT_RX_FIFO_END, val); | 621 | mue_csr_write(un, MUE_7800_FCT_RX_FIFO_END, val); | |
620 | val = (MUE_7800_MAX_TX_FIFO_SIZE - 512) / 512; | 622 | val = (MUE_7800_MAX_TX_FIFO_SIZE - 512) / 512; | |
621 | mue_csr_write(un, MUE_7800_FCT_TX_FIFO_END, val); | 623 | mue_csr_write(un, MUE_7800_FCT_TX_FIFO_END, val); | |
622 | } | 624 | } | |
623 | 625 | |||
624 | /* Enabling interrupts. */ | 626 | /* Enabling interrupts. */ | |
625 | mue_csr_write(un, MUE_INT_STATUS, ~0); | 627 | mue_csr_write(un, MUE_INT_STATUS, ~0); | |
626 | 628 | |||
627 | mue_csr_write(un, (un->un_flags & LAN7500) ? | 629 | mue_csr_write(un, (un->un_flags & LAN7500) ? | |
628 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, 0); | 630 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, 0); | |
629 | mue_csr_write(un, MUE_FLOW, 0); | 631 | mue_csr_write(un, MUE_FLOW, 0); | |
630 | 632 | |||
631 | /* Reset PHY. */ | 633 | /* Reset PHY. */ | |
632 | MUE_SETBIT(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST); | 634 | MUE_SETBIT(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST); | |
633 | if (MUE_WAIT_CLR(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST, 0)) { | 635 | if (MUE_WAIT_CLR(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST, 0)) { | |
634 | MUE_PRINTF(un, "PHY not ready\n"); | 636 | MUE_PRINTF(un, "PHY not ready\n"); | |
635 | return ETIMEDOUT; | 637 | return ETIMEDOUT; | |
636 | } | 638 | } | |
637 | 639 | |||
638 | /* LAN7801 only has RGMII mode. */ | 640 | /* LAN7801 only has RGMII mode. */ | |
639 | if (un->un_flags & LAN7801) | 641 | if (un->un_flags & LAN7801) | |
640 | MUE_CLRBIT(un, MUE_MAC_CR, MUE_MAC_CR_GMII_EN); | 642 | MUE_CLRBIT(un, MUE_MAC_CR, MUE_MAC_CR_GMII_EN); | |
641 | 643 | |||
642 | if ((un->un_flags & (LAN7500 | LAN7800)) || | 644 | if ((un->un_flags & (LAN7500 | LAN7800)) || | |
643 | !mue_eeprom_present(un)) { | 645 | !mue_eeprom_present(un)) { | |
644 | /* Allow MAC to detect speed and duplex from PHY. */ | 646 | /* Allow MAC to detect speed and duplex from PHY. */ | |
645 | MUE_SETBIT(un, MUE_MAC_CR, MUE_MAC_CR_AUTO_SPEED | | 647 | MUE_SETBIT(un, MUE_MAC_CR, MUE_MAC_CR_AUTO_SPEED | | |
646 | MUE_MAC_CR_AUTO_DUPLEX); | 648 | MUE_MAC_CR_AUTO_DUPLEX); | |
647 | } | 649 | } | |
648 | 650 | |||
649 | MUE_SETBIT(un, MUE_MAC_TX, MUE_MAC_TX_TXEN); | 651 | MUE_SETBIT(un, MUE_MAC_TX, MUE_MAC_TX_TXEN); | |
650 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | 652 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | |
651 | MUE_7500_FCT_TX_CTL : MUE_7800_FCT_TX_CTL, MUE_FCT_TX_CTL_EN); | 653 | MUE_7500_FCT_TX_CTL : MUE_7800_FCT_TX_CTL, MUE_FCT_TX_CTL_EN); | |
652 | 654 | |||
653 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | 655 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | |
654 | MUE_7500_FCT_RX_CTL : MUE_7800_FCT_RX_CTL, MUE_FCT_RX_CTL_EN); | 656 | MUE_7500_FCT_RX_CTL : MUE_7800_FCT_RX_CTL, MUE_FCT_RX_CTL_EN); | |
655 | 657 | |||
656 | /* Set default GPIO/LED settings only if no EEPROM is detected. */ | 658 | /* Set default GPIO/LED settings only if no EEPROM is detected. */ | |
657 | if ((un->un_flags & LAN7500) && !mue_eeprom_present(un)) { | 659 | if ((un->un_flags & LAN7500) && !mue_eeprom_present(un)) { | |
658 | MUE_CLRBIT(un, MUE_LED_CFG, MUE_LED_CFG_LED10_FUN_SEL); | 660 | MUE_CLRBIT(un, MUE_LED_CFG, MUE_LED_CFG_LED10_FUN_SEL); | |
659 | MUE_SETBIT(un, MUE_LED_CFG, | 661 | MUE_SETBIT(un, MUE_LED_CFG, | |
660 | MUE_LED_CFG_LEDGPIO_EN | MUE_LED_CFG_LED2_FUN_SEL); | 662 | MUE_LED_CFG_LEDGPIO_EN | MUE_LED_CFG_LED2_FUN_SEL); | |
661 | } | 663 | } | |
662 | 664 | |||
663 | /* XXX We assume two LEDs at least when EEPROM is missing. */ | 665 | /* XXX We assume two LEDs at least when EEPROM is missing. */ | |
664 | if (un->un_flags & LAN7800 && | 666 | if (un->un_flags & LAN7800 && | |
665 | !mue_eeprom_present(un)) | 667 | !mue_eeprom_present(un)) | |
666 | MUE_SETBIT(un, MUE_HW_CFG, | 668 | MUE_SETBIT(un, MUE_HW_CFG, | |
667 | MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN); | 669 | MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN); | |
668 | 670 | |||
669 | return 0; | 671 | return 0; | |
670 | } | 672 | } | |
671 | 673 | |||
672 | static void | 674 | static void | |
673 | mue_set_macaddr(struct usbnet *un) | 675 | mue_set_macaddr(struct usbnet *un) | |
674 | { | 676 | { | |
675 | struct ifnet * const ifp = usbnet_ifp(un); | 677 | struct ifnet * const ifp = usbnet_ifp(un); | |
676 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | 678 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | |
677 | uint32_t lo, hi; | 679 | uint32_t lo, hi; | |
678 | 680 | |||
679 | lo = MUE_ENADDR_LO(enaddr); | 681 | lo = MUE_ENADDR_LO(enaddr); | |
680 | hi = MUE_ENADDR_HI(enaddr); | 682 | hi = MUE_ENADDR_HI(enaddr); | |
681 | 683 | |||
682 | mue_csr_write(un, MUE_RX_ADDRL, lo); | 684 | mue_csr_write(un, MUE_RX_ADDRL, lo); | |
683 | mue_csr_write(un, MUE_RX_ADDRH, hi); | 685 | mue_csr_write(un, MUE_RX_ADDRH, hi); | |
684 | } | 686 | } | |
685 | 687 | |||
686 | static int | 688 | static int | |
687 | mue_get_macaddr(struct usbnet *un, prop_dictionary_t dict) | 689 | mue_get_macaddr(struct usbnet *un, prop_dictionary_t dict) | |
688 | { | 690 | { | |
689 | prop_data_t eaprop; | 691 | prop_data_t eaprop; | |
690 | uint32_t low, high; | 692 | uint32_t low, high; | |
691 | 693 | |||
692 | if (!(un->un_flags & LAN7500)) { | 694 | if (!(un->un_flags & LAN7500)) { | |
693 | low = mue_csr_read(un, MUE_RX_ADDRL); | 695 | low = mue_csr_read(un, MUE_RX_ADDRL); | |
694 | high = mue_csr_read(un, MUE_RX_ADDRH); | 696 | high = mue_csr_read(un, MUE_RX_ADDRH); | |
695 | un->un_eaddr[5] = (uint8_t)((high >> 8) & 0xff); | 697 | un->un_eaddr[5] = (uint8_t)((high >> 8) & 0xff); | |
696 | un->un_eaddr[4] = (uint8_t)((high) & 0xff); | 698 | un->un_eaddr[4] = (uint8_t)((high) & 0xff); | |
697 | un->un_eaddr[3] = (uint8_t)((low >> 24) & 0xff); | 699 | un->un_eaddr[3] = (uint8_t)((low >> 24) & 0xff); | |
698 | un->un_eaddr[2] = (uint8_t)((low >> 16) & 0xff); | 700 | un->un_eaddr[2] = (uint8_t)((low >> 16) & 0xff); | |
699 | un->un_eaddr[1] = (uint8_t)((low >> 8) & 0xff); | 701 | un->un_eaddr[1] = (uint8_t)((low >> 8) & 0xff); | |
700 | un->un_eaddr[0] = (uint8_t)((low) & 0xff); | 702 | un->un_eaddr[0] = (uint8_t)((low) & 0xff); | |
701 | if (ETHER_IS_VALID(un->un_eaddr)) | 703 | if (ETHER_IS_VALID(un->un_eaddr)) | |
702 | return 0; | 704 | return 0; | |
703 | else | 705 | else | |
704 | DPRINTF(un, "registers: %s\n", | 706 | DPRINTF(un, "registers: %s\n", | |
705 | ether_sprintf(un->un_eaddr)); | 707 | ether_sprintf(un->un_eaddr)); | |
706 | } | 708 | } | |
707 | 709 | |||
708 | if (mue_eeprom_present(un) && !mue_read_eeprom(un, un->un_eaddr, | 710 | if (mue_eeprom_present(un) && !mue_read_eeprom(un, un->un_eaddr, | |
709 | MUE_E2P_MAC_OFFSET, ETHER_ADDR_LEN)) { | 711 | MUE_E2P_MAC_OFFSET, ETHER_ADDR_LEN)) { | |
710 | if (ETHER_IS_VALID(un->un_eaddr)) | 712 | if (ETHER_IS_VALID(un->un_eaddr)) | |
711 | return 0; | 713 | return 0; | |
712 | else | 714 | else | |
713 | DPRINTF(un, "EEPROM: %s\n", | 715 | DPRINTF(un, "EEPROM: %s\n", | |
714 | ether_sprintf(un->un_eaddr)); | 716 | ether_sprintf(un->un_eaddr)); | |
715 | } | 717 | } | |
716 | 718 | |||
717 | if (mue_read_otp(un, un->un_eaddr, MUE_OTP_MAC_OFFSET, | 719 | if (mue_read_otp(un, un->un_eaddr, MUE_OTP_MAC_OFFSET, | |
718 | ETHER_ADDR_LEN) == 0) { | 720 | ETHER_ADDR_LEN) == 0) { | |
719 | if (ETHER_IS_VALID(un->un_eaddr)) | 721 | if (ETHER_IS_VALID(un->un_eaddr)) | |
720 | return 0; | 722 | return 0; | |
721 | else | 723 | else | |
722 | DPRINTF(un, "OTP: %s\n", | 724 | DPRINTF(un, "OTP: %s\n", | |
723 | ether_sprintf(un->un_eaddr)); | 725 | ether_sprintf(un->un_eaddr)); | |
724 | } | 726 | } | |
725 | 727 | |||
726 | /* | 728 | /* | |
727 | * Other MD methods. This should be tried only if other methods fail. | 729 | * Other MD methods. This should be tried only if other methods fail. | |
728 | * Otherwise, MAC address for internal device can be assinged to | 730 | * Otherwise, MAC address for internal device can be assinged to | |
729 | * external devices on Raspberry Pi, for example. | 731 | * external devices on Raspberry Pi, for example. | |
730 | */ | 732 | */ | |
731 | eaprop = prop_dictionary_get(dict, "mac-address"); | 733 | eaprop = prop_dictionary_get(dict, "mac-address"); | |
732 | if (eaprop != NULL) { | 734 | if (eaprop != NULL) { | |
733 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | 735 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | |
734 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | 736 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | |
735 | memcpy(un->un_eaddr, prop_data_value(eaprop), | 737 | memcpy(un->un_eaddr, prop_data_value(eaprop), | |
736 | ETHER_ADDR_LEN); | 738 | ETHER_ADDR_LEN); | |
737 | if (ETHER_IS_VALID(un->un_eaddr)) | 739 | if (ETHER_IS_VALID(un->un_eaddr)) | |
738 | return 0; | 740 | return 0; | |
739 | else | 741 | else | |
740 | DPRINTF(un, "prop_dictionary_get: %s\n", | 742 | DPRINTF(un, "prop_dictionary_get: %s\n", | |
741 | ether_sprintf(un->un_eaddr)); | 743 | ether_sprintf(un->un_eaddr)); | |
742 | } | 744 | } | |
743 | 745 | |||
744 | return 1; | 746 | return 1; | |
745 | } | 747 | } | |
746 | 748 | |||
747 | 749 | |||
748 | /* | 750 | /* | |
749 | * Probe for a Microchip chip. | 751 | * Probe for a Microchip chip. | |
750 | */ | 752 | */ | |
751 | static int | 753 | static int | |
752 | mue_match(device_t parent, cfdata_t match, void *aux) | 754 | mue_match(device_t parent, cfdata_t match, void *aux) | |
753 | { | 755 | { | |
754 | struct usb_attach_arg *uaa = aux; | 756 | struct usb_attach_arg *uaa = aux; | |
755 | 757 | |||
756 | return (MUE_LOOKUP(uaa) != NULL) ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 758 | return (MUE_LOOKUP(uaa) != NULL) ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
757 | } | 759 | } | |
758 | 760 | |||
759 | static void | 761 | static void | |
760 | mue_attach(device_t parent, device_t self, void *aux) | 762 | mue_attach(device_t parent, device_t self, void *aux) | |
761 | { | 763 | { | |
762 | USBNET_MII_DECL_DEFAULT(unm); | 764 | USBNET_MII_DECL_DEFAULT(unm); | |
763 | struct usbnet * const un = device_private(self); | 765 | struct usbnet * const un = device_private(self); | |
764 | prop_dictionary_t dict = device_properties(self); | 766 | prop_dictionary_t dict = device_properties(self); | |
765 | struct usb_attach_arg *uaa = aux; | 767 | struct usb_attach_arg *uaa = aux; | |
766 | struct usbd_device *dev = uaa->uaa_device; | 768 | struct usbd_device *dev = uaa->uaa_device; | |
767 | usb_interface_descriptor_t *id; | 769 | usb_interface_descriptor_t *id; | |
768 | usb_endpoint_descriptor_t *ed; | 770 | usb_endpoint_descriptor_t *ed; | |
769 | char *devinfop; | 771 | char *devinfop; | |
770 | usbd_status err; | 772 | usbd_status err; | |
771 | const char *descr; | 773 | const char *descr; | |
772 | uint32_t id_rev; | 774 | uint32_t id_rev; | |
773 | uint8_t i; | 775 | uint8_t i; | |
774 | unsigned rx_list_cnt, tx_list_cnt; | 776 | unsigned rx_list_cnt, tx_list_cnt; | |
775 | unsigned rx_bufsz; | 777 | unsigned rx_bufsz; | |
776 | 778 | |||
777 | aprint_naive("\n"); | 779 | aprint_naive("\n"); | |
778 | aprint_normal("\n"); | 780 | aprint_normal("\n"); | |
779 | devinfop = usbd_devinfo_alloc(dev, 0); | 781 | devinfop = usbd_devinfo_alloc(dev, 0); | |
780 | aprint_normal_dev(self, "%s\n", devinfop); | 782 | aprint_normal_dev(self, "%s\n", devinfop); | |
781 | usbd_devinfo_free(devinfop); | 783 | usbd_devinfo_free(devinfop); | |
782 | 784 | |||
783 | un->un_dev = self; | 785 | un->un_dev = self; | |
784 | un->un_udev = dev; | 786 | un->un_udev = dev; | |
785 | un->un_sc = un; | 787 | un->un_sc = un; | |
786 | un->un_ops = &mue_ops; | 788 | un->un_ops = &mue_ops; | |
787 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 789 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
788 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 790 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
789 | 791 | |||
790 | #define MUE_CONFIG_NO 1 | 792 | #define MUE_CONFIG_NO 1 | |
791 | err = usbd_set_config_no(dev, MUE_CONFIG_NO, 1); | 793 | err = usbd_set_config_no(dev, MUE_CONFIG_NO, 1); | |
792 | if (err) { | 794 | if (err) { | |
793 | aprint_error_dev(self, "failed to set configuration: %s\n", | 795 | aprint_error_dev(self, "failed to set configuration: %s\n", | |
794 | usbd_errstr(err)); | 796 | usbd_errstr(err)); | |
795 | return; | 797 | return; | |
796 | } | 798 | } | |
797 | 799 | |||
798 | #define MUE_IFACE_IDX 0 | 800 | #define MUE_IFACE_IDX 0 | |
799 | err = usbd_device2interface_handle(dev, MUE_IFACE_IDX, &un->un_iface); | 801 | err = usbd_device2interface_handle(dev, MUE_IFACE_IDX, &un->un_iface); | |
800 | if (err) { | 802 | if (err) { | |
801 | aprint_error_dev(self, "failed to get interface handle: %s\n", | 803 | aprint_error_dev(self, "failed to get interface handle: %s\n", | |
802 | usbd_errstr(err)); | 804 | usbd_errstr(err)); | |
803 | return; | 805 | return; | |
804 | } | 806 | } | |
805 | 807 | |||
806 | un->un_flags = MUE_LOOKUP(uaa)->mue_flags; | 808 | un->un_flags = MUE_LOOKUP(uaa)->mue_flags; | |
807 | 809 | |||
808 | /* Decide on what our bufsize will be. */ | 810 | /* Decide on what our bufsize will be. */ | |
809 | if (un->un_flags & LAN7500) { | 811 | if (un->un_flags & LAN7500) { | |
810 | rx_bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? | 812 | rx_bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? | |
811 | MUE_7500_HS_RX_BUFSIZE : MUE_7500_FS_RX_BUFSIZE; | 813 | MUE_7500_HS_RX_BUFSIZE : MUE_7500_FS_RX_BUFSIZE; | |
812 | rx_list_cnt = 1; | 814 | rx_list_cnt = 1; | |
813 | tx_list_cnt = 1; | 815 | tx_list_cnt = 1; | |
814 | } else { | 816 | } else { | |
815 | rx_bufsz = MUE_7800_RX_BUFSIZE; | 817 | rx_bufsz = MUE_7800_RX_BUFSIZE; | |
816 | rx_list_cnt = MUE_RX_LIST_CNT; | 818 | rx_list_cnt = MUE_RX_LIST_CNT; | |
817 | tx_list_cnt = MUE_TX_LIST_CNT; | 819 | tx_list_cnt = MUE_TX_LIST_CNT; | |
818 | } | 820 | } | |
819 | 821 | |||
820 | un->un_rx_list_cnt = rx_list_cnt; | 822 | un->un_rx_list_cnt = rx_list_cnt; | |
821 | un->un_tx_list_cnt = tx_list_cnt; | 823 | un->un_tx_list_cnt = tx_list_cnt; | |
822 | un->un_rx_bufsz = rx_bufsz; | 824 | un->un_rx_bufsz = rx_bufsz; | |
823 | un->un_tx_bufsz = MUE_TX_BUFSIZE; | 825 | un->un_tx_bufsz = MUE_TX_BUFSIZE; | |
824 | 826 | |||
825 | /* Find endpoints. */ | 827 | /* Find endpoints. */ | |
826 | id = usbd_get_interface_descriptor(un->un_iface); | 828 | id = usbd_get_interface_descriptor(un->un_iface); | |
827 | for (i = 0; i < id->bNumEndpoints; i++) { | 829 | for (i = 0; i < id->bNumEndpoints; i++) { | |
828 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 830 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
829 | if (ed == NULL) { | 831 | if (ed == NULL) { | |
830 | aprint_error_dev(self, "failed to get ep %hhd\n", i); | 832 | aprint_error_dev(self, "failed to get ep %hhd\n", i); | |
831 | return; | 833 | return; | |
832 | } | 834 | } | |
833 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 835 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
834 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 836 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
835 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 837 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
836 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 838 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
837 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 839 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
838 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 840 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
839 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 841 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
840 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 842 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
841 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 843 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
842 | } | 844 | } | |
843 | } | 845 | } | |
844 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 846 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
845 | un->un_ed[USBNET_ENDPT_TX] == 0 || | 847 | un->un_ed[USBNET_ENDPT_TX] == 0 || | |
846 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | 848 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | |
847 | aprint_error_dev(self, "failed to find endpoints\n"); | 849 | aprint_error_dev(self, "failed to find endpoints\n"); | |
848 | return; | 850 | return; | |
849 | } | 851 | } | |
850 | 852 | |||
851 | /* Set these up now for mue_cmd(). */ | 853 | /* Set these up now for mue_cmd(). */ | |
852 | usbnet_attach(un, "muedet"); | 854 | usbnet_attach(un, "muedet"); | |
853 | 855 | |||
854 | un->un_phyno = 1; | 856 | un->un_phyno = 1; | |
855 | 857 | |||
856 | if (mue_chip_init(un)) { | 858 | if (mue_chip_init(un)) { | |
857 | aprint_error_dev(self, "failed to initialize chip\n"); | 859 | aprint_error_dev(self, "failed to initialize chip\n"); | |
858 | return; | 860 | return; | |
859 | } | 861 | } | |
860 | 862 | |||
861 | /* A Microchip chip was detected. Inform the world. */ | 863 | /* A Microchip chip was detected. Inform the world. */ | |
862 | id_rev = mue_csr_read(un, MUE_ID_REV); | 864 | id_rev = mue_csr_read(un, MUE_ID_REV); | |
863 | descr = (un->un_flags & LAN7500) ? "LAN7500" : "LAN7800"; | 865 | descr = (un->un_flags & LAN7500) ? "LAN7500" : "LAN7800"; | |
864 | aprint_normal_dev(self, "%s id %#x rev %#x\n", descr, | 866 | aprint_normal_dev(self, "%s id %#x rev %#x\n", descr, | |
865 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_ID), | 867 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_ID), | |
866 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_REV)); | 868 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_REV)); | |
867 | 869 | |||
868 | if (mue_get_macaddr(un, dict)) { | 870 | if (mue_get_macaddr(un, dict)) { | |
869 | aprint_error_dev(self, "failed to read MAC address\n"); | 871 | aprint_error_dev(self, "failed to read MAC address\n"); | |
870 | return; | 872 | return; | |
871 | } | 873 | } | |
872 | 874 | |||
873 | struct ifnet *ifp = usbnet_ifp(un); | 875 | struct ifnet *ifp = usbnet_ifp(un); | |
874 | ifp->if_capabilities = IFCAP_TSOv4 | IFCAP_TSOv6 | | 876 | ifp->if_capabilities = IFCAP_TSOv4 | IFCAP_TSOv6 | | |
875 | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | | 877 | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | | |
876 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | | 878 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | | |
877 | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | | 879 | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | | |
878 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | | 880 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | | |
879 | IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; | 881 | IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; | |
880 | 882 | |||
881 | struct ethercom *ec = usbnet_ec(un); | 883 | struct ethercom *ec = usbnet_ec(un); | |
882 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | 884 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | |
883 | #if 0 /* XXX not yet */ | 885 | #if 0 /* XXX not yet */ | |
884 | ec->ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU; | 886 | ec->ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU; | |
885 | #endif | 887 | #endif | |
886 | 888 | |||
887 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 889 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
888 | 0, &unm); | 890 | 0, &unm); | |
889 | } | 891 | } | |
890 | 892 | |||
891 | static unsigned | 893 | static unsigned | |
892 | mue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 894 | mue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
893 | { | 895 | { | |
894 | struct ifnet * const ifp = usbnet_ifp(un); | 896 | struct ifnet * const ifp = usbnet_ifp(un); | |
895 | struct mue_txbuf_hdr hdr; | 897 | struct mue_txbuf_hdr hdr; | |
896 | uint32_t tx_cmd_a, tx_cmd_b; | 898 | uint32_t tx_cmd_a, tx_cmd_b; | |
897 | int csum, len, rv; | 899 | int csum, len, rv; | |
898 | bool tso, ipe, tpe; | 900 | bool tso, ipe, tpe; | |
899 | 901 | |||
900 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) | 902 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) | |
901 | return 0; | 903 | return 0; | |
902 | 904 | |||
903 | csum = m->m_pkthdr.csum_flags; | 905 | csum = m->m_pkthdr.csum_flags; | |
904 | tso = csum & (M_CSUM_TSOv4 | M_CSUM_TSOv6); | 906 | tso = csum & (M_CSUM_TSOv4 | M_CSUM_TSOv6); | |
905 | ipe = csum & M_CSUM_IPv4; | 907 | ipe = csum & M_CSUM_IPv4; | |
906 | tpe = csum & (M_CSUM_TCPv4 | M_CSUM_UDPv4 | | 908 | tpe = csum & (M_CSUM_TCPv4 | M_CSUM_UDPv4 | | |
907 | M_CSUM_TCPv6 | M_CSUM_UDPv6); | 909 | M_CSUM_TCPv6 | M_CSUM_UDPv6); | |
908 | 910 | |||
909 | len = m->m_pkthdr.len; | 911 | len = m->m_pkthdr.len; | |
910 | if (__predict_false((!tso && len > (int)MUE_FRAME_LEN(ifp->if_mtu)) || | 912 | if (__predict_false((!tso && len > (int)MUE_FRAME_LEN(ifp->if_mtu)) || | |
911 | ( tso && len > MUE_TSO_FRAME_LEN))) { | 913 | ( tso && len > MUE_TSO_FRAME_LEN))) { | |
912 | MUE_PRINTF(un, "packet length %d\n too long", len); | 914 | MUE_PRINTF(un, "packet length %d\n too long", len); | |
913 | return 0; | 915 | return 0; | |
914 | } | 916 | } | |
915 | 917 | |||
916 | KASSERT((len & ~MUE_TX_CMD_A_LEN_MASK) == 0); | 918 | KASSERT((len & ~MUE_TX_CMD_A_LEN_MASK) == 0); | |
917 | tx_cmd_a = len | MUE_TX_CMD_A_FCS; | 919 | tx_cmd_a = len | MUE_TX_CMD_A_FCS; | |
918 | 920 | |||
919 | if (tso) { | 921 | if (tso) { | |
920 | tx_cmd_a |= MUE_TX_CMD_A_LSO; | 922 | tx_cmd_a |= MUE_TX_CMD_A_LSO; | |
921 | if (__predict_true(m->m_pkthdr.segsz > MUE_TX_MSS_MIN)) | 923 | if (__predict_true(m->m_pkthdr.segsz > MUE_TX_MSS_MIN)) | |
922 | tx_cmd_b = m->m_pkthdr.segsz; | 924 | tx_cmd_b = m->m_pkthdr.segsz; | |
923 | else | 925 | else | |
924 | tx_cmd_b = MUE_TX_MSS_MIN; | 926 | tx_cmd_b = MUE_TX_MSS_MIN; | |
925 | tx_cmd_b <<= MUE_TX_CMD_B_MSS_SHIFT; | 927 | tx_cmd_b <<= MUE_TX_CMD_B_MSS_SHIFT; | |
926 | KASSERT((tx_cmd_b & ~MUE_TX_CMD_B_MSS_MASK) == 0); | 928 | KASSERT((tx_cmd_b & ~MUE_TX_CMD_B_MSS_MASK) == 0); | |
927 | rv = mue_prepare_tso(un, m); | 929 | rv = mue_prepare_tso(un, m); | |
928 | if (__predict_false(rv)) | 930 | if (__predict_false(rv)) | |
929 | return 0; | 931 | return 0; | |
930 | } else { | 932 | } else { | |
931 | if (ipe) | 933 | if (ipe) | |
932 | tx_cmd_a |= MUE_TX_CMD_A_IPE; | 934 | tx_cmd_a |= MUE_TX_CMD_A_IPE; | |
933 | if (tpe) | 935 | if (tpe) | |
934 | tx_cmd_a |= MUE_TX_CMD_A_TPE; | 936 | tx_cmd_a |= MUE_TX_CMD_A_TPE; | |
935 | tx_cmd_b = 0; | 937 | tx_cmd_b = 0; | |
936 | } | 938 | } | |
937 | 939 | |||
938 | hdr.tx_cmd_a = htole32(tx_cmd_a); | 940 | hdr.tx_cmd_a = htole32(tx_cmd_a); | |
939 | hdr.tx_cmd_b = htole32(tx_cmd_b); | 941 | hdr.tx_cmd_b = htole32(tx_cmd_b); | |
940 | 942 | |||
941 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); | 943 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); | |
942 | m_copydata(m, 0, len, c->unc_buf + sizeof(hdr)); | 944 | m_copydata(m, 0, len, c->unc_buf + sizeof(hdr)); | |
943 | 945 | |||
944 | return len + sizeof(hdr); | 946 | return len + sizeof(hdr); | |
945 | } | 947 | } | |
946 | 948 | |||
947 | /* | 949 | /* | |
948 | * L3 length field should be cleared. | 950 | * L3 length field should be cleared. | |
949 | */ | 951 | */ | |
950 | static int | 952 | static int | |
951 | mue_prepare_tso(struct usbnet *un, struct mbuf *m) | 953 | mue_prepare_tso(struct usbnet *un, struct mbuf *m) | |
952 | { | 954 | { | |
953 | struct ether_header *eh; | 955 | struct ether_header *eh; | |
954 | struct ip *ip; | 956 | struct ip *ip; | |
955 | struct ip6_hdr *ip6; | 957 | struct ip6_hdr *ip6; | |
956 | uint16_t type, len = 0; | 958 | uint16_t type, len = 0; | |
957 | int off; | 959 | int off; | |
958 | 960 | |||
959 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | 961 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | |
960 | eh = mtod(m, struct ether_header *); | 962 | eh = mtod(m, struct ether_header *); | |
961 | type = eh->ether_type; | 963 | type = eh->ether_type; | |
962 | } else | 964 | } else | |
963 | m_copydata(m, offsetof(struct ether_header, ether_type), | 965 | m_copydata(m, offsetof(struct ether_header, ether_type), | |
964 | sizeof(type), &type); | 966 | sizeof(type), &type); | |
965 | switch (type = htons(type)) { | 967 | switch (type = htons(type)) { | |
966 | case ETHERTYPE_IP: | 968 | case ETHERTYPE_IP: | |
967 | case ETHERTYPE_IPV6: | 969 | case ETHERTYPE_IPV6: | |
968 | off = ETHER_HDR_LEN; | 970 | off = ETHER_HDR_LEN; | |
969 | break; | 971 | break; | |
970 | case ETHERTYPE_VLAN: | 972 | case ETHERTYPE_VLAN: | |
971 | off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | 973 | off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | |
972 | break; | 974 | break; | |
973 | default: | 975 | default: | |
974 | return EINVAL; | 976 | return EINVAL; | |
975 | } | 977 | } | |
976 | 978 | |||
977 | if (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) { | 979 | if (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) { | |
978 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip))) { | 980 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip))) { | |
979 | ip = (void *)(mtod(m, char *) + off); | 981 | ip = (void *)(mtod(m, char *) + off); | |
980 | ip->ip_len = 0; | 982 | ip->ip_len = 0; | |
981 | } else | 983 | } else | |
982 | m_copyback(m, off + offsetof(struct ip, ip_len), | 984 | m_copyback(m, off + offsetof(struct ip, ip_len), | |
983 | sizeof(len), &len); | 985 | sizeof(len), &len); | |
984 | } else { | 986 | } else { | |
985 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip6))) { | 987 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip6))) { | |
986 | ip6 = (void *)(mtod(m, char *) + off); | 988 | ip6 = (void *)(mtod(m, char *) + off); | |
987 | ip6->ip6_plen = 0; | 989 | ip6->ip6_plen = 0; | |
988 | } else | 990 | } else | |
989 | m_copyback(m, off + offsetof(struct ip6_hdr, ip6_plen), | 991 | m_copyback(m, off + offsetof(struct ip6_hdr, ip6_plen), | |
990 | sizeof(len), &len); | 992 | sizeof(len), &len); | |
991 | } | 993 | } | |
992 | return 0; | 994 | return 0; | |
993 | } | 995 | } | |
994 | 996 | |||
995 | static void | 997 | static void | |
996 | mue_setiff_locked(struct usbnet *un) | 998 | mue_setiff_locked(struct usbnet *un) | |
997 | { | 999 | { | |
998 | struct ethercom *ec = usbnet_ec(un); | 1000 | struct ethercom *ec = usbnet_ec(un); | |
999 | struct ifnet * const ifp = usbnet_ifp(un); | 1001 | struct ifnet * const ifp = usbnet_ifp(un); | |
1000 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | 1002 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | |
1001 | struct ether_multi *enm; | 1003 | struct ether_multi *enm; | |
1002 | struct ether_multistep step; | 1004 | struct ether_multistep step; | |
1003 | uint32_t pfiltbl[MUE_NUM_ADDR_FILTX][2]; | 1005 | uint32_t pfiltbl[MUE_NUM_ADDR_FILTX][2]; | |
1004 | uint32_t hashtbl[MUE_DP_SEL_VHF_HASH_LEN]; | 1006 | uint32_t hashtbl[MUE_DP_SEL_VHF_HASH_LEN]; | |
1005 | uint32_t reg, rxfilt, h, hireg, loreg; | 1007 | uint32_t reg, rxfilt, h, hireg, loreg; | |
1006 | size_t i; | 1008 | size_t i; | |
1007 | 1009 | |||
1008 | if (usbnet_isdying(un)) | 1010 | if (usbnet_isdying(un)) | |
1009 | return; | 1011 | return; | |
1010 | 1012 | |||
1011 | /* Clear perfect filter and hash tables. */ | 1013 | /* Clear perfect filter and hash tables. */ | |
1012 | memset(pfiltbl, 0, sizeof(pfiltbl)); | 1014 | memset(pfiltbl, 0, sizeof(pfiltbl)); | |
1013 | memset(hashtbl, 0, sizeof(hashtbl)); | 1015 | memset(hashtbl, 0, sizeof(hashtbl)); | |
1014 | 1016 | |||
1015 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | 1017 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | |
1016 | rxfilt = mue_csr_read(un, reg); | 1018 | rxfilt = mue_csr_read(un, reg); | |
1017 | rxfilt &= ~(MUE_RFE_CTL_PERFECT | MUE_RFE_CTL_MULTICAST_HASH | | 1019 | rxfilt &= ~(MUE_RFE_CTL_PERFECT | MUE_RFE_CTL_MULTICAST_HASH | | |
1018 | MUE_RFE_CTL_UNICAST | MUE_RFE_CTL_MULTICAST); | 1020 | MUE_RFE_CTL_UNICAST | MUE_RFE_CTL_MULTICAST); | |
1019 | 1021 | |||
1020 | /* Always accept broadcast frames. */ | 1022 | /* Always accept broadcast frames. */ | |
1021 | rxfilt |= MUE_RFE_CTL_BROADCAST; | 1023 | rxfilt |= MUE_RFE_CTL_BROADCAST; | |
1022 | 1024 | |||
1023 | if (ifp->if_flags & IFF_PROMISC) { | 1025 | if (ifp->if_flags & IFF_PROMISC) { | |
1024 | rxfilt |= MUE_RFE_CTL_UNICAST; | 1026 | rxfilt |= MUE_RFE_CTL_UNICAST; | |
1025 | allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; | 1027 | allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; | |
1026 | ifp->if_flags |= IFF_ALLMULTI; | 1028 | ifp->if_flags |= IFF_ALLMULTI; | |
1027 | if (ifp->if_flags & IFF_PROMISC) | 1029 | if (ifp->if_flags & IFF_PROMISC) | |
1028 | DPRINTF(un, "promisc\n"); | 1030 | DPRINTF(un, "promisc\n"); | |
1029 | else | 1031 | else | |
1030 | DPRINTF(un, "allmulti\n"); | 1032 | DPRINTF(un, "allmulti\n"); | |
1031 | } else { | 1033 | } else { | |
1032 | /* Now program new ones. */ | 1034 | /* Now program new ones. */ | |
1033 | pfiltbl[0][0] = MUE_ENADDR_HI(enaddr) | MUE_ADDR_FILTX_VALID; | 1035 | pfiltbl[0][0] = MUE_ENADDR_HI(enaddr) | MUE_ADDR_FILTX_VALID; | |
1034 | pfiltbl[0][1] = MUE_ENADDR_LO(enaddr); | 1036 | pfiltbl[0][1] = MUE_ENADDR_LO(enaddr); | |
1035 | i = 1; | 1037 | i = 1; | |
1036 | ETHER_LOCK(ec); | 1038 | ETHER_LOCK(ec); | |
1037 | ETHER_FIRST_MULTI(step, ec, enm); | 1039 | ETHER_FIRST_MULTI(step, ec, enm); | |
1038 | while (enm != NULL) { | 1040 | while (enm != NULL) { | |
1039 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | 1041 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
1040 | ETHER_ADDR_LEN)) { | 1042 | ETHER_ADDR_LEN)) { | |
1041 | memset(pfiltbl, 0, sizeof(pfiltbl)); | 1043 | memset(pfiltbl, 0, sizeof(pfiltbl)); | |
1042 | memset(hashtbl, 0, sizeof(hashtbl)); | 1044 | memset(hashtbl, 0, sizeof(hashtbl)); | |
1043 | rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH; | 1045 | rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH; | |
1044 | ETHER_UNLOCK(ec); | 1046 | ETHER_UNLOCK(ec); | |
1045 | goto allmulti; | 1047 | goto allmulti; | |
1046 | } | 1048 | } | |
1047 | if (i < MUE_NUM_ADDR_FILTX) { | 1049 | if (i < MUE_NUM_ADDR_FILTX) { | |
1048 | /* Use perfect address table if possible. */ | 1050 | /* Use perfect address table if possible. */ | |
1049 | pfiltbl[i][0] = MUE_ENADDR_HI(enm->enm_addrlo) | | 1051 | pfiltbl[i][0] = MUE_ENADDR_HI(enm->enm_addrlo) | | |
1050 | MUE_ADDR_FILTX_VALID; | 1052 | MUE_ADDR_FILTX_VALID; | |
1051 | pfiltbl[i][1] = MUE_ENADDR_LO(enm->enm_addrlo); | 1053 | pfiltbl[i][1] = MUE_ENADDR_LO(enm->enm_addrlo); | |
1052 | } else { | 1054 | } else { | |
1053 | /* Otherwise, use hash table. */ | 1055 | /* Otherwise, use hash table. */ | |
1054 | rxfilt |= MUE_RFE_CTL_MULTICAST_HASH; | 1056 | rxfilt |= MUE_RFE_CTL_MULTICAST_HASH; | |
1055 | h = (ether_crc32_be(enm->enm_addrlo, | 1057 | h = (ether_crc32_be(enm->enm_addrlo, | |
1056 | ETHER_ADDR_LEN) >> 23) & 0x1ff; | 1058 | ETHER_ADDR_LEN) >> 23) & 0x1ff; | |
1057 | hashtbl[h / 32] |= 1 << (h % 32); | 1059 | hashtbl[h / 32] |= 1 << (h % 32); | |
1058 | } | 1060 | } | |
1059 | i++; | 1061 | i++; | |
1060 | ETHER_NEXT_MULTI(step, enm); | 1062 | ETHER_NEXT_MULTI(step, enm); | |
1061 | } | 1063 | } | |
1062 | ETHER_UNLOCK(ec); | 1064 | ETHER_UNLOCK(ec); | |
1063 | rxfilt |= MUE_RFE_CTL_PERFECT; | 1065 | rxfilt |= MUE_RFE_CTL_PERFECT; | |
1064 | ifp->if_flags &= ~IFF_ALLMULTI; | 1066 | ifp->if_flags &= ~IFF_ALLMULTI; | |
1065 | if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH) | 1067 | if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH) | |
1066 | DPRINTF(un, "perfect filter and hash tables\n"); | 1068 | DPRINTF(un, "perfect filter and hash tables\n"); | |
1067 | else | 1069 | else | |
1068 | DPRINTF(un, "perfect filter\n"); | 1070 | DPRINTF(un, "perfect filter\n"); | |
1069 | } | 1071 | } | |
1070 | 1072 | |||
1071 | for (i = 0; i < MUE_NUM_ADDR_FILTX; i++) { | 1073 | for (i = 0; i < MUE_NUM_ADDR_FILTX; i++) { | |
1072 | hireg = (un->un_flags & LAN7500) ? | 1074 | hireg = (un->un_flags & LAN7500) ? | |
1073 | MUE_7500_ADDR_FILTX(i) : MUE_7800_ADDR_FILTX(i); | 1075 | MUE_7500_ADDR_FILTX(i) : MUE_7800_ADDR_FILTX(i); | |
1074 | loreg = hireg + 4; | 1076 | loreg = hireg + 4; | |
1075 | mue_csr_write(un, hireg, 0); | 1077 | mue_csr_write(un, hireg, 0); | |
1076 | mue_csr_write(un, loreg, pfiltbl[i][1]); | 1078 | mue_csr_write(un, loreg, pfiltbl[i][1]); | |
1077 | mue_csr_write(un, hireg, pfiltbl[i][0]); | 1079 | mue_csr_write(un, hireg, pfiltbl[i][0]); | |
1078 | } | 1080 | } | |
1079 | 1081 | |||
1080 | mue_dataport_write(un, MUE_DP_SEL_VHF, MUE_DP_SEL_VHF_VLAN_LEN, | 1082 | mue_dataport_write(un, MUE_DP_SEL_VHF, MUE_DP_SEL_VHF_VLAN_LEN, | |
1081 | MUE_DP_SEL_VHF_HASH_LEN, hashtbl); | 1083 | MUE_DP_SEL_VHF_HASH_LEN, hashtbl); | |
1082 | 1084 | |||
1083 | mue_csr_write(un, reg, rxfilt); | 1085 | mue_csr_write(un, reg, rxfilt); | |
1084 | } | 1086 | } | |
1085 | 1087 | |||
1086 | static void | 1088 | static void | |
1087 | mue_sethwcsum_locked(struct usbnet *un) | 1089 | mue_sethwcsum_locked(struct usbnet *un) | |
1088 | { | 1090 | { | |
1089 | struct ifnet * const ifp = usbnet_ifp(un); | 1091 | struct ifnet * const ifp = usbnet_ifp(un); | |
1090 | uint32_t reg, val; | 1092 | uint32_t reg, val; | |
1091 | 1093 | |||
1092 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | 1094 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | |
1093 | val = mue_csr_read(un, reg); | 1095 | val = mue_csr_read(un, reg); | |
1094 | 1096 | |||
1095 | if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) { | 1097 | if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) { | |
1096 | DPRINTF(un, "RX IPv4 hwcsum enabled\n"); | 1098 | DPRINTF(un, "RX IPv4 hwcsum enabled\n"); | |
1097 | val |= MUE_RFE_CTL_IP_COE; | 1099 | val |= MUE_RFE_CTL_IP_COE; | |
1098 | } else { | 1100 | } else { | |
1099 | DPRINTF(un, "RX IPv4 hwcsum disabled\n"); | 1101 | DPRINTF(un, "RX IPv4 hwcsum disabled\n"); | |
1100 | val &= ~MUE_RFE_CTL_IP_COE; | 1102 | val &= ~MUE_RFE_CTL_IP_COE; | |
1101 | } | 1103 | } | |
1102 | 1104 | |||
1103 | if (ifp->if_capenable & | 1105 | if (ifp->if_capenable & | |
1104 | (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | 1106 | (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | |
1105 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { | 1107 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { | |
1106 | DPRINTF(un, "RX L4 hwcsum enabled\n"); | 1108 | DPRINTF(un, "RX L4 hwcsum enabled\n"); | |
1107 | val |= MUE_RFE_CTL_TCPUDP_COE; | 1109 | val |= MUE_RFE_CTL_TCPUDP_COE; | |
1108 | } else { | 1110 | } else { | |
1109 | DPRINTF(un, "RX L4 hwcsum disabled\n"); | 1111 | DPRINTF(un, "RX L4 hwcsum disabled\n"); | |
1110 | val &= ~MUE_RFE_CTL_TCPUDP_COE; | 1112 | val &= ~MUE_RFE_CTL_TCPUDP_COE; | |
1111 | } | 1113 | } | |
1112 | 1114 | |||
1113 | val &= ~MUE_RFE_CTL_VLAN_FILTER; | 1115 | val &= ~MUE_RFE_CTL_VLAN_FILTER; | |
1114 | 1116 | |||
1115 | mue_csr_write(un, reg, val); | 1117 | mue_csr_write(un, reg, val); | |
1116 | } | 1118 | } | |
1117 | 1119 | |||
1118 | static void | 1120 | static void | |
1119 | mue_setmtu_locked(struct usbnet *un) | 1121 | mue_setmtu_locked(struct usbnet *un) | |
1120 | { | 1122 | { | |
1121 | struct ifnet * const ifp = usbnet_ifp(un); | 1123 | struct ifnet * const ifp = usbnet_ifp(un); | |
1122 | uint32_t val; | 1124 | uint32_t val; | |
1123 | 1125 | |||
1124 | /* Set the maximum frame size. */ | 1126 | /* Set the maximum frame size. */ | |
1125 | MUE_CLRBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | 1127 | MUE_CLRBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | |
1126 | val = mue_csr_read(un, MUE_MAC_RX); | 1128 | val = mue_csr_read(un, MUE_MAC_RX); | |
1127 | val &= ~MUE_MAC_RX_MAX_SIZE_MASK; | 1129 | val &= ~MUE_MAC_RX_MAX_SIZE_MASK; | |
1128 | val |= MUE_MAC_RX_MAX_LEN(MUE_FRAME_LEN(ifp->if_mtu)); | 1130 | val |= MUE_MAC_RX_MAX_LEN(MUE_FRAME_LEN(ifp->if_mtu)); | |
1129 | mue_csr_write(un, MUE_MAC_RX, val); | 1131 | mue_csr_write(un, MUE_MAC_RX, val); | |
1130 | MUE_SETBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | 1132 | MUE_SETBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | |
1131 | } | 1133 | } | |
1132 | 1134 | |||
1133 | static void | 1135 | static void | |
1134 | mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 1136 | mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
1135 | { | 1137 | { | |
1136 | struct ifnet * const ifp = usbnet_ifp(un); | 1138 | struct ifnet * const ifp = usbnet_ifp(un); | |
1137 | struct mue_rxbuf_hdr *hdrp; | 1139 | struct mue_rxbuf_hdr *hdrp; | |
1138 | uint32_t rx_cmd_a; | 1140 | uint32_t rx_cmd_a; | |
1139 | uint16_t pktlen; | 1141 | uint16_t pktlen; | |
1140 | int csum; | 1142 | int csum; | |
1141 | uint8_t *buf = c->unc_buf; | 1143 | uint8_t *buf = c->unc_buf; | |
1142 | bool v6; | 1144 | bool v6; | |
1143 | 1145 | |||
1144 | KASSERTMSG(total_len <= un->un_rx_bufsz, "%u vs %u", | 1146 | KASSERTMSG(total_len <= un->un_rx_bufsz, "%u vs %u", | |
1145 | total_len, un->un_rx_bufsz); | 1147 | total_len, un->un_rx_bufsz); | |
1146 | 1148 | |||
1147 | do { | 1149 | do { | |
1148 | if (__predict_false(total_len < sizeof(*hdrp))) { | 1150 | if (__predict_false(total_len < sizeof(*hdrp))) { | |
1149 | MUE_PRINTF(un, "packet length %u too short\n", total_len); | 1151 | MUE_PRINTF(un, "packet length %u too short\n", total_len); | |
1150 | if_statinc(ifp, if_ierrors); | 1152 | if_statinc(ifp, if_ierrors); | |
1151 | return; | 1153 | return; | |
1152 | } | 1154 | } | |
1153 | 1155 | |||
1154 | hdrp = (struct mue_rxbuf_hdr *)buf; | 1156 | hdrp = (struct mue_rxbuf_hdr *)buf; | |
1155 | rx_cmd_a = le32toh(hdrp->rx_cmd_a); | 1157 | rx_cmd_a = le32toh(hdrp->rx_cmd_a); | |
1156 | 1158 | |||
1157 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ERRORS)) { | 1159 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ERRORS)) { | |
1158 | /* | 1160 | /* | |
1159 | * We cannot use MUE_RX_CMD_A_RED bit here; | 1161 | * We cannot use MUE_RX_CMD_A_RED bit here; | |
1160 | * it is turned on in the cases of L3/L4 | 1162 | * it is turned on in the cases of L3/L4 | |
1161 | * checksum errors which we handle below. | 1163 | * checksum errors which we handle below. | |
1162 | */ | 1164 | */ | |
1163 | MUE_PRINTF(un, "rx_cmd_a: %#x\n", rx_cmd_a); | 1165 | MUE_PRINTF(un, "rx_cmd_a: %#x\n", rx_cmd_a); | |
1164 | if_statinc(ifp, if_ierrors); | 1166 | if_statinc(ifp, if_ierrors); | |
1165 | return; | 1167 | return; | |
1166 | } | 1168 | } | |
1167 | 1169 | |||
1168 | pktlen = (uint16_t)(rx_cmd_a & MUE_RX_CMD_A_LEN_MASK); | 1170 | pktlen = (uint16_t)(rx_cmd_a & MUE_RX_CMD_A_LEN_MASK); | |
1169 | if (un->un_flags & LAN7500) | 1171 | if (un->un_flags & LAN7500) | |
1170 | pktlen -= 2; | 1172 | pktlen -= 2; | |
1171 | 1173 | |||
1172 | if (__predict_false(pktlen < ETHER_HDR_LEN + ETHER_CRC_LEN || | 1174 | if (__predict_false(pktlen < ETHER_HDR_LEN + ETHER_CRC_LEN || | |
1173 | pktlen > MCLBYTES - ETHER_ALIGN || /* XXX */ | 1175 | pktlen > MCLBYTES - ETHER_ALIGN || /* XXX */ | |
1174 | pktlen + sizeof(*hdrp) > total_len)) { | 1176 | pktlen + sizeof(*hdrp) > total_len)) { | |
1175 | MUE_PRINTF(un, "invalid packet length %d\n", pktlen); | 1177 | MUE_PRINTF(un, "invalid packet length %d\n", pktlen); | |
1176 | if_statinc(ifp, if_ierrors); | 1178 | if_statinc(ifp, if_ierrors); | |
1177 | return; | 1179 | return; | |
1178 | } | 1180 | } | |
1179 | 1181 | |||
1180 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ICSM)) { | 1182 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ICSM)) { | |
1181 | csum = 0; | 1183 | csum = 0; | |
1182 | } else { | 1184 | } else { | |
1183 | v6 = rx_cmd_a & MUE_RX_CMD_A_IPV; | 1185 | v6 = rx_cmd_a & MUE_RX_CMD_A_IPV; | |
1184 | switch (rx_cmd_a & MUE_RX_CMD_A_PID) { | 1186 | switch (rx_cmd_a & MUE_RX_CMD_A_PID) { | |
1185 | case MUE_RX_CMD_A_PID_TCP: | 1187 | case MUE_RX_CMD_A_PID_TCP: | |
1186 | csum = v6 ? | 1188 | csum = v6 ? | |
1187 | M_CSUM_TCPv6 : M_CSUM_IPv4 | M_CSUM_TCPv4; | 1189 | M_CSUM_TCPv6 : M_CSUM_IPv4 | M_CSUM_TCPv4; | |
1188 | break; | 1190 | break; | |
1189 | case MUE_RX_CMD_A_PID_UDP: | 1191 | case MUE_RX_CMD_A_PID_UDP: | |
1190 | csum = v6 ? | 1192 | csum = v6 ? | |
1191 | M_CSUM_UDPv6 : M_CSUM_IPv4 | M_CSUM_UDPv4; | 1193 | M_CSUM_UDPv6 : M_CSUM_IPv4 | M_CSUM_UDPv4; | |
1192 | break; | 1194 | break; | |
1193 | case MUE_RX_CMD_A_PID_IP: | 1195 | case MUE_RX_CMD_A_PID_IP: | |
1194 | csum = v6 ? 0 : M_CSUM_IPv4; | 1196 | csum = v6 ? 0 : M_CSUM_IPv4; | |
1195 | break; | 1197 | break; | |
1196 | default: | 1198 | default: | |
1197 | csum = 0; | 1199 | csum = 0; | |
1198 | break; | 1200 | break; | |
1199 | } | 1201 | } | |
1200 | csum &= ifp->if_csum_flags_rx; | 1202 | csum &= ifp->if_csum_flags_rx; | |
1201 | if (__predict_false((csum & M_CSUM_IPv4) && | 1203 | if (__predict_false((csum & M_CSUM_IPv4) && |
--- src/sys/dev/usb/if_smsc.c 2022/03/03 05:50:22 1.72
+++ src/sys/dev/usb/if_smsc.c 2022/03/03 05:50:57 1.73
@@ -1,1091 +1,1093 @@ | @@ -1,1091 +1,1093 @@ | |||
1 | /* $NetBSD: if_smsc.c,v 1.72 2022/03/03 05:50:22 riastradh Exp $ */ | 1 | /* $NetBSD: if_smsc.c,v 1.73 2022/03/03 05:50:57 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.72 2022/03/03 05:50:22 riastradh Exp $"); | 64 | __KERNEL_RCSID(0, "$NetBSD: if_smsc.c,v 1.73 2022/03/03 05:50:57 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 unsigned smsc_uno_tx_prepare(struct usbnet *, struct mbuf *, | 190 | static unsigned smsc_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
191 | struct usbnet_chain *); | 191 | struct usbnet_chain *); | |
192 | static void smsc_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 192 | static void smsc_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
193 | uint32_t); | 193 | uint32_t); | |
194 | 194 | |||
195 | static const struct usbnet_ops smsc_ops = { | 195 | static const struct usbnet_ops smsc_ops = { | |
196 | .uno_stop = smsc_uno_stop, | 196 | .uno_stop = smsc_uno_stop, | |
197 | .uno_ioctl = smsc_uno_ioctl, | 197 | .uno_ioctl = smsc_uno_ioctl, | |
198 | .uno_read_reg = smsc_uno_miibus_readreg, | 198 | .uno_read_reg = smsc_uno_miibus_readreg, | |
199 | .uno_write_reg = smsc_uno_miibus_writereg, | 199 | .uno_write_reg = smsc_uno_miibus_writereg, | |
200 | .uno_statchg = smsc_uno_miibus_statchg, | 200 | .uno_statchg = smsc_uno_miibus_statchg, | |
201 | .uno_tx_prepare = smsc_uno_tx_prepare, | 201 | .uno_tx_prepare = smsc_uno_tx_prepare, | |
202 | .uno_rx_loop = smsc_uno_rx_loop, | 202 | .uno_rx_loop = smsc_uno_rx_loop, | |
203 | .uno_init = smsc_uno_init, | 203 | .uno_init = smsc_uno_init, | |
204 | }; | 204 | }; | |
205 | 205 | |||
206 | static int | 206 | static int | |
207 | smsc_readreg(struct usbnet *un, uint32_t off, uint32_t *data) | 207 | smsc_readreg(struct usbnet *un, uint32_t off, uint32_t *data) | |
208 | { | 208 | { | |
209 | usb_device_request_t req; | 209 | usb_device_request_t req; | |
210 | uint32_t buf; | 210 | uint32_t buf; | |
211 | usbd_status err; | 211 | usbd_status err; | |
212 | 212 | |||
213 | usbnet_isowned_core(un); | 213 | usbnet_isowned_core(un); | |
214 | 214 | |||
215 | if (usbnet_isdying(un)) | 215 | if (usbnet_isdying(un)) | |
216 | return 0; | 216 | return 0; | |
217 | 217 | |||
218 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 218 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
219 | req.bRequest = SMSC_UR_READ_REG; | 219 | req.bRequest = SMSC_UR_READ_REG; | |
220 | USETW(req.wValue, 0); | 220 | USETW(req.wValue, 0); | |
221 | USETW(req.wIndex, off); | 221 | USETW(req.wIndex, off); | |
222 | USETW(req.wLength, 4); | 222 | USETW(req.wLength, 4); | |
223 | 223 | |||
224 | err = usbd_do_request(un->un_udev, &req, &buf); | 224 | err = usbd_do_request(un->un_udev, &req, &buf); | |
225 | if (err != 0) | 225 | if (err != 0) | |
226 | smsc_warn_printf(un, "Failed to read register 0x%0x\n", off); | 226 | smsc_warn_printf(un, "Failed to read register 0x%0x\n", off); | |
227 | 227 | |||
228 | *data = le32toh(buf); | 228 | *data = le32toh(buf); | |
229 | 229 | |||
230 | return err; | 230 | return err; | |
231 | } | 231 | } | |
232 | 232 | |||
233 | static int | 233 | static int | |
234 | smsc_writereg(struct usbnet *un, uint32_t off, uint32_t data) | 234 | smsc_writereg(struct usbnet *un, uint32_t off, uint32_t data) | |
235 | { | 235 | { | |
236 | usb_device_request_t req; | 236 | usb_device_request_t req; | |
237 | uint32_t buf; | 237 | uint32_t buf; | |
238 | usbd_status err; | 238 | usbd_status err; | |
239 | 239 | |||
240 | usbnet_isowned_core(un); | 240 | usbnet_isowned_core(un); | |
241 | 241 | |||
242 | if (usbnet_isdying(un)) | 242 | if (usbnet_isdying(un)) | |
243 | return 0; | 243 | return 0; | |
244 | 244 | |||
245 | buf = htole32(data); | 245 | buf = htole32(data); | |
246 | 246 | |||
247 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 247 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
248 | req.bRequest = SMSC_UR_WRITE_REG; | 248 | req.bRequest = SMSC_UR_WRITE_REG; | |
249 | USETW(req.wValue, 0); | 249 | USETW(req.wValue, 0); | |
250 | USETW(req.wIndex, off); | 250 | USETW(req.wIndex, off); | |
251 | USETW(req.wLength, 4); | 251 | USETW(req.wLength, 4); | |
252 | 252 | |||
253 | err = usbd_do_request(un->un_udev, &req, &buf); | 253 | err = usbd_do_request(un->un_udev, &req, &buf); | |
254 | if (err != 0) | 254 | if (err != 0) | |
255 | smsc_warn_printf(un, "Failed to write register 0x%0x\n", off); | 255 | smsc_warn_printf(un, "Failed to write register 0x%0x\n", off); | |
256 | 256 | |||
257 | return err; | 257 | return err; | |
258 | } | 258 | } | |
259 | 259 | |||
260 | static int | 260 | static int | |
261 | smsc_wait_for_bits(struct usbnet *un, uint32_t reg, uint32_t bits) | 261 | smsc_wait_for_bits(struct usbnet *un, uint32_t reg, uint32_t bits) | |
262 | { | 262 | { | |
263 | uint32_t val; | 263 | uint32_t val; | |
264 | int err, i; | 264 | int err, i; | |
265 | 265 | |||
266 | for (i = 0; i < 100; i++) { | 266 | for (i = 0; i < 100; i++) { | |
267 | if (usbnet_isdying(un)) | |||
268 | return ENXIO; | |||
267 | if ((err = smsc_readreg(un, reg, &val)) != 0) | 269 | if ((err = smsc_readreg(un, reg, &val)) != 0) | |
268 | return err; | 270 | return err; | |
269 | if (!(val & bits)) | 271 | if (!(val & bits)) | |
270 | return 0; | 272 | return 0; | |
271 | DELAY(5); | 273 | DELAY(5); | |
272 | } | 274 | } | |
273 | 275 | |||
274 | return 1; | 276 | return 1; | |
275 | } | 277 | } | |
276 | 278 | |||
277 | static int | 279 | static int | |
278 | smsc_uno_miibus_readreg(struct usbnet *un, int phy, int reg, uint16_t *val) | 280 | smsc_uno_miibus_readreg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
279 | { | 281 | { | |
280 | uint32_t addr; | 282 | uint32_t addr; | |
281 | uint32_t data = 0; | 283 | uint32_t data = 0; | |
282 | 284 | |||
283 | if (un->un_phyno != phy) | 285 | if (un->un_phyno != phy) | |
284 | return EINVAL; | 286 | return EINVAL; | |
285 | 287 | |||
286 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | 288 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | |
287 | smsc_warn_printf(un, "MII is busy\n"); | 289 | smsc_warn_printf(un, "MII is busy\n"); | |
288 | return ETIMEDOUT; | 290 | return ETIMEDOUT; | |
289 | } | 291 | } | |
290 | 292 | |||
291 | addr = (phy << 11) | (reg << 6) | SMSC_MII_READ; | 293 | addr = (phy << 11) | (reg << 6) | SMSC_MII_READ; | |
292 | smsc_writereg(un, SMSC_MII_ADDR, addr); | 294 | smsc_writereg(un, SMSC_MII_ADDR, addr); | |
293 | 295 | |||
294 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | 296 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | |
295 | smsc_warn_printf(un, "MII read timeout\n"); | 297 | smsc_warn_printf(un, "MII read timeout\n"); | |
296 | return ETIMEDOUT; | 298 | return ETIMEDOUT; | |
297 | } | 299 | } | |
298 | 300 | |||
299 | smsc_readreg(un, SMSC_MII_DATA, &data); | 301 | smsc_readreg(un, SMSC_MII_DATA, &data); | |
300 | 302 | |||
301 | *val = data & 0xffff; | 303 | *val = data & 0xffff; | |
302 | return 0; | 304 | return 0; | |
303 | } | 305 | } | |
304 | 306 | |||
305 | static int | 307 | static int | |
306 | smsc_uno_miibus_writereg(struct usbnet *un, int phy, int reg, uint16_t val) | 308 | smsc_uno_miibus_writereg(struct usbnet *un, int phy, int reg, uint16_t val) | |
307 | { | 309 | { | |
308 | uint32_t addr; | 310 | uint32_t addr; | |
309 | 311 | |||
310 | if (un->un_phyno != phy) | 312 | if (un->un_phyno != phy) | |
311 | return EINVAL; | 313 | return EINVAL; | |
312 | 314 | |||
313 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | 315 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | |
314 | smsc_warn_printf(un, "MII is busy\n"); | 316 | smsc_warn_printf(un, "MII is busy\n"); | |
315 | return ETIMEDOUT; | 317 | return ETIMEDOUT; | |
316 | } | 318 | } | |
317 | 319 | |||
318 | smsc_writereg(un, SMSC_MII_DATA, val); | 320 | smsc_writereg(un, SMSC_MII_DATA, val); | |
319 | 321 | |||
320 | addr = (phy << 11) | (reg << 6) | SMSC_MII_WRITE; | 322 | addr = (phy << 11) | (reg << 6) | SMSC_MII_WRITE; | |
321 | smsc_writereg(un, SMSC_MII_ADDR, addr); | 323 | smsc_writereg(un, SMSC_MII_ADDR, addr); | |
322 | 324 | |||
323 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | 325 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | |
324 | smsc_warn_printf(un, "MII write timeout\n"); | 326 | smsc_warn_printf(un, "MII write timeout\n"); | |
325 | return ETIMEDOUT; | 327 | return ETIMEDOUT; | |
326 | } | 328 | } | |
327 | 329 | |||
328 | return 0; | 330 | return 0; | |
329 | } | 331 | } | |
330 | 332 | |||
331 | static void | 333 | static void | |
332 | smsc_uno_miibus_statchg(struct ifnet *ifp) | 334 | smsc_uno_miibus_statchg(struct ifnet *ifp) | |
333 | { | 335 | { | |
334 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | 336 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | |
335 | struct usbnet * const un = ifp->if_softc; | 337 | struct usbnet * const un = ifp->if_softc; | |
336 | 338 | |||
337 | if (usbnet_isdying(un)) | 339 | if (usbnet_isdying(un)) | |
338 | return; | 340 | return; | |
339 | 341 | |||
340 | struct smsc_softc * const sc = usbnet_softc(un); | 342 | struct smsc_softc * const sc = usbnet_softc(un); | |
341 | struct mii_data * const mii = usbnet_mii(un); | 343 | struct mii_data * const mii = usbnet_mii(un); | |
342 | uint32_t flow; | 344 | uint32_t flow; | |
343 | uint32_t afc_cfg; | 345 | uint32_t afc_cfg; | |
344 | 346 | |||
345 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 347 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
346 | (IFM_ACTIVE | IFM_AVALID)) { | 348 | (IFM_ACTIVE | IFM_AVALID)) { | |
347 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 349 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
348 | case IFM_10_T: | 350 | case IFM_10_T: | |
349 | case IFM_100_TX: | 351 | case IFM_100_TX: | |
350 | usbnet_set_link(un, true); | 352 | usbnet_set_link(un, true); | |
351 | break; | 353 | break; | |
352 | case IFM_1000_T: | 354 | case IFM_1000_T: | |
353 | /* Gigabit ethernet not supported by chipset */ | 355 | /* Gigabit ethernet not supported by chipset */ | |
354 | break; | 356 | break; | |
355 | default: | 357 | default: | |
356 | break; | 358 | break; | |
357 | } | 359 | } | |
358 | } | 360 | } | |
359 | 361 | |||
360 | /* Lost link, do nothing. */ | 362 | /* Lost link, do nothing. */ | |
361 | if (!usbnet_havelink(un)) | 363 | if (!usbnet_havelink(un)) | |
362 | return; | 364 | return; | |
363 | 365 | |||
364 | int err = smsc_readreg(un, SMSC_AFC_CFG, &afc_cfg); | 366 | int err = smsc_readreg(un, SMSC_AFC_CFG, &afc_cfg); | |
365 | if (err) { | 367 | if (err) { | |
366 | smsc_warn_printf(un, "failed to read initial AFC_CFG, " | 368 | smsc_warn_printf(un, "failed to read initial AFC_CFG, " | |
367 | "error %d\n", err); | 369 | "error %d\n", err); | |
368 | return; | 370 | return; | |
369 | } | 371 | } | |
370 | 372 | |||
371 | /* Enable/disable full duplex operation and TX/RX pause */ | 373 | /* Enable/disable full duplex operation and TX/RX pause */ | |
372 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { | 374 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { | |
373 | DPRINTF("full duplex operation", 0, 0, 0, 0); | 375 | DPRINTF("full duplex operation", 0, 0, 0, 0); | |
374 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_RCVOWN; | 376 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_RCVOWN; | |
375 | sc->sc_mac_csr |= SMSC_MAC_CSR_FDPX; | 377 | sc->sc_mac_csr |= SMSC_MAC_CSR_FDPX; | |
376 | 378 | |||
377 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) | 379 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) | |
378 | flow = 0xffff0002; | 380 | flow = 0xffff0002; | |
379 | else | 381 | else | |
380 | flow = 0; | 382 | flow = 0; | |
381 | 383 | |||
382 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) | 384 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) | |
383 | afc_cfg |= 0xf; | 385 | afc_cfg |= 0xf; | |
384 | else | 386 | else | |
385 | afc_cfg &= ~0xf; | 387 | afc_cfg &= ~0xf; | |
386 | } else { | 388 | } else { | |
387 | DPRINTF("half duplex operation", 0, 0, 0, 0); | 389 | DPRINTF("half duplex operation", 0, 0, 0, 0); | |
388 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_FDPX; | 390 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_FDPX; | |
389 | sc->sc_mac_csr |= SMSC_MAC_CSR_RCVOWN; | 391 | sc->sc_mac_csr |= SMSC_MAC_CSR_RCVOWN; | |
390 | 392 | |||
391 | flow = 0; | 393 | flow = 0; | |
392 | afc_cfg |= 0xf; | 394 | afc_cfg |= 0xf; | |
393 | } | 395 | } | |
394 | 396 | |||
395 | err = smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 397 | err = smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
396 | err += smsc_writereg(un, SMSC_FLOW, flow); | 398 | err += smsc_writereg(un, SMSC_FLOW, flow); | |
397 | err += smsc_writereg(un, SMSC_AFC_CFG, afc_cfg); | 399 | err += smsc_writereg(un, SMSC_AFC_CFG, afc_cfg); | |
398 | 400 | |||
399 | if (err) | 401 | if (err) | |
400 | smsc_warn_printf(un, "media change failed, error %d\n", err); | 402 | smsc_warn_printf(un, "media change failed, error %d\n", err); | |
401 | } | 403 | } | |
402 | 404 | |||
403 | static inline uint32_t | 405 | static inline uint32_t | |
404 | smsc_hash(uint8_t addr[ETHER_ADDR_LEN]) | 406 | smsc_hash(uint8_t addr[ETHER_ADDR_LEN]) | |
405 | { | 407 | { | |
406 | 408 | |||
407 | return (ether_crc32_be(addr, ETHER_ADDR_LEN) >> 26) & 0x3f; | 409 | return (ether_crc32_be(addr, ETHER_ADDR_LEN) >> 26) & 0x3f; | |
408 | } | 410 | } | |
409 | 411 | |||
410 | static void | 412 | static void | |
411 | smsc_setiff_locked(struct usbnet *un) | 413 | smsc_setiff_locked(struct usbnet *un) | |
412 | { | 414 | { | |
413 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | 415 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | |
414 | struct smsc_softc * const sc = usbnet_softc(un); | 416 | struct smsc_softc * const sc = usbnet_softc(un); | |
415 | struct ifnet * const ifp = usbnet_ifp(un); | 417 | struct ifnet * const ifp = usbnet_ifp(un); | |
416 | struct ethercom *ec = usbnet_ec(un); | 418 | struct ethercom *ec = usbnet_ec(un); | |
417 | struct ether_multi *enm; | 419 | struct ether_multi *enm; | |
418 | struct ether_multistep step; | 420 | struct ether_multistep step; | |
419 | uint32_t hashtbl[2] = { 0, 0 }; | 421 | uint32_t hashtbl[2] = { 0, 0 }; | |
420 | uint32_t hash; | 422 | uint32_t hash; | |
421 | 423 | |||
422 | usbnet_isowned_core(un); | 424 | usbnet_isowned_core(un); | |
423 | 425 | |||
424 | if (usbnet_isdying(un)) | 426 | if (usbnet_isdying(un)) | |
425 | return; | 427 | return; | |
426 | 428 | |||
427 | if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { | 429 | if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) { | |
428 | allmulti: | 430 | allmulti: | |
429 | DPRINTF("receive all multicast enabled", 0, 0, 0, 0); | 431 | DPRINTF("receive all multicast enabled", 0, 0, 0, 0); | |
430 | sc->sc_mac_csr |= SMSC_MAC_CSR_MCPAS; | 432 | sc->sc_mac_csr |= SMSC_MAC_CSR_MCPAS; | |
431 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_HPFILT; | 433 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_HPFILT; | |
432 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 434 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
433 | return; | 435 | return; | |
434 | } else { | 436 | } else { | |
435 | sc->sc_mac_csr |= SMSC_MAC_CSR_HPFILT; | 437 | sc->sc_mac_csr |= SMSC_MAC_CSR_HPFILT; | |
436 | sc->sc_mac_csr &= ~(SMSC_MAC_CSR_PRMS | SMSC_MAC_CSR_MCPAS); | 438 | sc->sc_mac_csr &= ~(SMSC_MAC_CSR_PRMS | SMSC_MAC_CSR_MCPAS); | |
437 | } | 439 | } | |
438 | 440 | |||
439 | ETHER_LOCK(ec); | 441 | ETHER_LOCK(ec); | |
440 | ETHER_FIRST_MULTI(step, ec, enm); | 442 | ETHER_FIRST_MULTI(step, ec, enm); | |
441 | while (enm != NULL) { | 443 | while (enm != NULL) { | |
442 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 444 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
443 | ETHER_UNLOCK(ec); | 445 | ETHER_UNLOCK(ec); | |
444 | goto allmulti; | 446 | goto allmulti; | |
445 | } | 447 | } | |
446 | 448 | |||
447 | hash = smsc_hash(enm->enm_addrlo); | 449 | hash = smsc_hash(enm->enm_addrlo); | |
448 | hashtbl[hash >> 5] |= 1 << (hash & 0x1F); | 450 | hashtbl[hash >> 5] |= 1 << (hash & 0x1F); | |
449 | ETHER_NEXT_MULTI(step, enm); | 451 | ETHER_NEXT_MULTI(step, enm); | |
450 | } | 452 | } | |
451 | ETHER_UNLOCK(ec); | 453 | ETHER_UNLOCK(ec); | |
452 | 454 | |||
453 | /* Debug */ | 455 | /* Debug */ | |
454 | if (sc->sc_mac_csr & SMSC_MAC_CSR_HPFILT) { | 456 | if (sc->sc_mac_csr & SMSC_MAC_CSR_HPFILT) { | |
455 | DPRINTF("receive select group of macs", 0, 0, 0, 0); | 457 | DPRINTF("receive select group of macs", 0, 0, 0, 0); | |
456 | } else { | 458 | } else { | |
457 | DPRINTF("receive own packets only", 0, 0, 0, 0); | 459 | DPRINTF("receive own packets only", 0, 0, 0, 0); | |
458 | } | 460 | } | |
459 | 461 | |||
460 | /* Write the hash table and mac control registers */ | 462 | /* Write the hash table and mac control registers */ | |
461 | 463 | |||
462 | //XXX should we be doing this? | 464 | //XXX should we be doing this? | |
463 | ifp->if_flags &= ~IFF_ALLMULTI; | 465 | ifp->if_flags &= ~IFF_ALLMULTI; | |
464 | smsc_writereg(un, SMSC_HASHH, hashtbl[1]); | 466 | smsc_writereg(un, SMSC_HASHH, hashtbl[1]); | |
465 | smsc_writereg(un, SMSC_HASHL, hashtbl[0]); | 467 | smsc_writereg(un, SMSC_HASHL, hashtbl[0]); | |
466 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 468 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
467 | } | 469 | } | |
468 | 470 | |||
469 | static int | 471 | static int | |
470 | smsc_setoe_locked(struct usbnet *un) | 472 | smsc_setoe_locked(struct usbnet *un) | |
471 | { | 473 | { | |
472 | struct smsc_softc * const sc = usbnet_softc(un); | 474 | struct smsc_softc * const sc = usbnet_softc(un); | |
473 | struct ifnet * const ifp = usbnet_ifp(un); | 475 | struct ifnet * const ifp = usbnet_ifp(un); | |
474 | uint32_t val; | 476 | uint32_t val; | |
475 | int err; | 477 | int err; | |
476 | 478 | |||
477 | usbnet_isowned_core(un); | 479 | usbnet_isowned_core(un); | |
478 | 480 | |||
479 | err = smsc_readreg(un, SMSC_COE_CTRL, &val); | 481 | err = smsc_readreg(un, SMSC_COE_CTRL, &val); | |
480 | if (err != 0) { | 482 | if (err != 0) { | |
481 | smsc_warn_printf(un, "failed to read SMSC_COE_CTRL (err=%d)\n", | 483 | smsc_warn_printf(un, "failed to read SMSC_COE_CTRL (err=%d)\n", | |
482 | err); | 484 | err); | |
483 | return err; | 485 | return err; | |
484 | } | 486 | } | |
485 | 487 | |||
486 | /* Enable/disable the Rx checksum */ | 488 | /* Enable/disable the Rx checksum */ | |
487 | if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx)) | 489 | if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx)) | |
488 | val |= (SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE); | 490 | val |= (SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE); | |
489 | else | 491 | else | |
490 | val &= ~(SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE); | 492 | val &= ~(SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE); | |
491 | 493 | |||
492 | /* Enable/disable the Tx checksum (currently not supported) */ | 494 | /* Enable/disable the Tx checksum (currently not supported) */ | |
493 | if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx)) | 495 | if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx)) | |
494 | val |= SMSC_COE_CTRL_TX_EN; | 496 | val |= SMSC_COE_CTRL_TX_EN; | |
495 | else | 497 | else | |
496 | val &= ~SMSC_COE_CTRL_TX_EN; | 498 | val &= ~SMSC_COE_CTRL_TX_EN; | |
497 | 499 | |||
498 | sc->sc_coe_ctrl = val; | 500 | sc->sc_coe_ctrl = val; | |
499 | 501 | |||
500 | err = smsc_writereg(un, SMSC_COE_CTRL, val); | 502 | err = smsc_writereg(un, SMSC_COE_CTRL, val); | |
501 | if (err != 0) { | 503 | if (err != 0) { | |
502 | smsc_warn_printf(un, "failed to write SMSC_COE_CTRL (err=%d)\n", | 504 | smsc_warn_printf(un, "failed to write SMSC_COE_CTRL (err=%d)\n", | |
503 | err); | 505 | err); | |
504 | return err; | 506 | return err; | |
505 | } | 507 | } | |
506 | 508 | |||
507 | return 0; | 509 | return 0; | |
508 | } | 510 | } | |
509 | 511 | |||
510 | static int | 512 | static int | |
511 | smsc_setmacaddress(struct usbnet *un, const uint8_t *addr) | 513 | smsc_setmacaddress(struct usbnet *un, const uint8_t *addr) | |
512 | { | 514 | { | |
513 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | 515 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | |
514 | int err; | 516 | int err; | |
515 | uint32_t val; | 517 | uint32_t val; | |
516 | 518 | |||
517 | DPRINTF("setting mac address to %02jx:%02jx:%02jx:...", addr[0], | 519 | DPRINTF("setting mac address to %02jx:%02jx:%02jx:...", addr[0], | |
518 | addr[1], addr[2], 0); | 520 | addr[1], addr[2], 0); | |
519 | 521 | |||
520 | DPRINTF("... %02jx:%02jx:%02jx", addr[3], addr[4], addr[5], 0); | 522 | DPRINTF("... %02jx:%02jx:%02jx", addr[3], addr[4], addr[5], 0); | |
521 | 523 | |||
522 | val = ((uint32_t)addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | 524 | val = ((uint32_t)addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | |
523 | | addr[0]; | 525 | | addr[0]; | |
524 | if ((err = smsc_writereg(un, SMSC_MAC_ADDRL, val)) != 0) | 526 | if ((err = smsc_writereg(un, SMSC_MAC_ADDRL, val)) != 0) | |
525 | goto done; | 527 | goto done; | |
526 | 528 | |||
527 | val = (addr[5] << 8) | addr[4]; | 529 | val = (addr[5] << 8) | addr[4]; | |
528 | err = smsc_writereg(un, SMSC_MAC_ADDRH, val); | 530 | err = smsc_writereg(un, SMSC_MAC_ADDRH, val); | |
529 | 531 | |||
530 | done: | 532 | done: | |
531 | return err; | 533 | return err; | |
532 | } | 534 | } | |
533 | 535 | |||
534 | static void | 536 | static void | |
535 | smsc_reset(struct smsc_softc *sc) | 537 | smsc_reset(struct smsc_softc *sc) | |
536 | { | 538 | { | |
537 | struct usbnet * const un = &sc->smsc_un; | 539 | struct usbnet * const un = &sc->smsc_un; | |
538 | 540 | |||
539 | usbnet_isowned_core(un); | 541 | usbnet_isowned_core(un); | |
540 | if (usbnet_isdying(un)) | 542 | if (usbnet_isdying(un)) | |
541 | return; | 543 | return; | |
542 | 544 | |||
543 | /* Wait a little while for the chip to get its brains in order. */ | 545 | /* Wait a little while for the chip to get its brains in order. */ | |
544 | DELAY(1000); | 546 | DELAY(1000); | |
545 | 547 | |||
546 | /* Reinitialize controller to achieve full reset. */ | 548 | /* Reinitialize controller to achieve full reset. */ | |
547 | smsc_chip_init(un); | 549 | smsc_chip_init(un); | |
548 | } | 550 | } | |
549 | 551 | |||
550 | static int | 552 | static int | |
551 | smsc_uno_init(struct ifnet *ifp) | 553 | smsc_uno_init(struct ifnet *ifp) | |
552 | { | 554 | { | |
553 | struct usbnet * const un = ifp->if_softc; | 555 | struct usbnet * const un = ifp->if_softc; | |
554 | 556 | |||
555 | usbnet_busy(un); | 557 | usbnet_busy(un); | |
556 | int ret = smsc_init_locked(ifp); | 558 | int ret = smsc_init_locked(ifp); | |
557 | usbnet_unbusy(un); | 559 | usbnet_unbusy(un); | |
558 | 560 | |||
559 | return ret; | 561 | return ret; | |
560 | } | 562 | } | |
561 | 563 | |||
562 | static int | 564 | static int | |
563 | smsc_init_locked(struct ifnet *ifp) | 565 | smsc_init_locked(struct ifnet *ifp) | |
564 | { | 566 | { | |
565 | struct usbnet * const un = ifp->if_softc; | 567 | struct usbnet * const un = ifp->if_softc; | |
566 | struct smsc_softc * const sc = usbnet_softc(un); | 568 | struct smsc_softc * const sc = usbnet_softc(un); | |
567 | 569 | |||
568 | usbnet_isowned_core(un); | 570 | usbnet_isowned_core(un); | |
569 | 571 | |||
570 | if (usbnet_isdying(un)) | 572 | if (usbnet_isdying(un)) | |
571 | return EIO; | 573 | return EIO; | |
572 | 574 | |||
573 | /* Cancel pending I/O */ | 575 | /* Cancel pending I/O */ | |
574 | usbnet_stop(un, ifp, 1); | 576 | usbnet_stop(un, ifp, 1); | |
575 | 577 | |||
576 | /* Reset the ethernet interface. */ | 578 | /* Reset the ethernet interface. */ | |
577 | smsc_reset(sc); | 579 | smsc_reset(sc); | |
578 | 580 | |||
579 | /* Load the multicast filter. */ | 581 | /* Load the multicast filter. */ | |
580 | smsc_setiff_locked(un); | 582 | smsc_setiff_locked(un); | |
581 | 583 | |||
582 | /* TCP/UDP checksum offload engines. */ | 584 | /* TCP/UDP checksum offload engines. */ | |
583 | smsc_setoe_locked(un); | 585 | smsc_setoe_locked(un); | |
584 | 586 | |||
585 | return usbnet_init_rx_tx(un); | 587 | return usbnet_init_rx_tx(un); | |
586 | } | 588 | } | |
587 | 589 | |||
588 | static void | 590 | static void | |
589 | smsc_uno_stop(struct ifnet *ifp, int disable) | 591 | smsc_uno_stop(struct ifnet *ifp, int disable) | |
590 | { | 592 | { | |
591 | struct usbnet * const un = ifp->if_softc; | 593 | struct usbnet * const un = ifp->if_softc; | |
592 | struct smsc_softc * const sc = usbnet_softc(un); | 594 | struct smsc_softc * const sc = usbnet_softc(un); | |
593 | 595 | |||
594 | // XXXNH didn't do this before | 596 | // XXXNH didn't do this before | |
595 | smsc_reset(sc); | 597 | smsc_reset(sc); | |
596 | } | 598 | } | |
597 | 599 | |||
598 | static int | 600 | static int | |
599 | smsc_chip_init(struct usbnet *un) | 601 | smsc_chip_init(struct usbnet *un) | |
600 | { | 602 | { | |
601 | struct smsc_softc * const sc = usbnet_softc(un); | 603 | struct smsc_softc * const sc = usbnet_softc(un); | |
602 | uint32_t reg_val; | 604 | uint32_t reg_val; | |
603 | int burst_cap; | 605 | int burst_cap; | |
604 | int err; | 606 | int err; | |
605 | 607 | |||
606 | usbnet_isowned_core(un); | 608 | usbnet_isowned_core(un); | |
607 | 609 | |||
608 | /* Enter H/W config mode */ | 610 | /* Enter H/W config mode */ | |
609 | smsc_writereg(un, SMSC_HW_CFG, SMSC_HW_CFG_LRST); | 611 | smsc_writereg(un, SMSC_HW_CFG, SMSC_HW_CFG_LRST); | |
610 | 612 | |||
611 | if ((err = smsc_wait_for_bits(un, SMSC_HW_CFG, | 613 | if ((err = smsc_wait_for_bits(un, SMSC_HW_CFG, | |
612 | SMSC_HW_CFG_LRST)) != 0) { | 614 | SMSC_HW_CFG_LRST)) != 0) { | |
613 | smsc_warn_printf(un, "timed-out waiting for reset to " | 615 | smsc_warn_printf(un, "timed-out waiting for reset to " | |
614 | "complete\n"); | 616 | "complete\n"); | |
615 | goto init_failed; | 617 | goto init_failed; | |
616 | } | 618 | } | |
617 | 619 | |||
618 | /* Reset the PHY */ | 620 | /* Reset the PHY */ | |
619 | smsc_writereg(un, SMSC_PM_CTRL, SMSC_PM_CTRL_PHY_RST); | 621 | smsc_writereg(un, SMSC_PM_CTRL, SMSC_PM_CTRL_PHY_RST); | |
620 | 622 | |||
621 | if ((err = smsc_wait_for_bits(un, SMSC_PM_CTRL, | 623 | if ((err = smsc_wait_for_bits(un, SMSC_PM_CTRL, | |
622 | SMSC_PM_CTRL_PHY_RST)) != 0) { | 624 | SMSC_PM_CTRL_PHY_RST)) != 0) { | |
623 | smsc_warn_printf(un, "timed-out waiting for phy reset to " | 625 | smsc_warn_printf(un, "timed-out waiting for phy reset to " | |
624 | "complete\n"); | 626 | "complete\n"); | |
625 | goto init_failed; | 627 | goto init_failed; | |
626 | } | 628 | } | |
627 | usbd_delay_ms(un->un_udev, 40); | 629 | usbd_delay_ms(un->un_udev, 40); | |
628 | 630 | |||
629 | /* Set the mac address */ | 631 | /* Set the mac address */ | |
630 | struct ifnet * const ifp = usbnet_ifp(un); | 632 | struct ifnet * const ifp = usbnet_ifp(un); | |
631 | const char *eaddr = CLLADDR(ifp->if_sadl); | 633 | const char *eaddr = CLLADDR(ifp->if_sadl); | |
632 | if ((err = smsc_setmacaddress(un, eaddr)) != 0) { | 634 | if ((err = smsc_setmacaddress(un, eaddr)) != 0) { | |
633 | smsc_warn_printf(un, "failed to set the MAC address\n"); | 635 | smsc_warn_printf(un, "failed to set the MAC address\n"); | |
634 | goto init_failed; | 636 | goto init_failed; | |
635 | } | 637 | } | |
636 | 638 | |||
637 | /* | 639 | /* | |
638 | * Don't know what the HW_CFG_BIR bit is, but following the reset | 640 | * Don't know what the HW_CFG_BIR bit is, but following the reset | |
639 | * sequence as used in the Linux driver. | 641 | * sequence as used in the Linux driver. | |
640 | */ | 642 | */ | |
641 | if ((err = smsc_readreg(un, SMSC_HW_CFG, ®_val)) != 0) { | 643 | if ((err = smsc_readreg(un, SMSC_HW_CFG, ®_val)) != 0) { | |
642 | smsc_warn_printf(un, "failed to read HW_CFG: %d\n", err); | 644 | smsc_warn_printf(un, "failed to read HW_CFG: %d\n", err); | |
643 | goto init_failed; | 645 | goto init_failed; | |
644 | } | 646 | } | |
645 | reg_val |= SMSC_HW_CFG_BIR; | 647 | reg_val |= SMSC_HW_CFG_BIR; | |
646 | smsc_writereg(un, SMSC_HW_CFG, reg_val); | 648 | smsc_writereg(un, SMSC_HW_CFG, reg_val); | |
647 | 649 | |||
648 | /* | 650 | /* | |
649 | * There is a so called 'turbo mode' that the linux driver supports, it | 651 | * 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. | 652 | * seems to allow you to jam multiple frames per Rx transaction. | |
651 | * By default this driver supports that and therefore allows multiple | 653 | * By default this driver supports that and therefore allows multiple | |
652 | * frames per USB transfer. | 654 | * frames per USB transfer. | |
653 | * | 655 | * | |
654 | * The xfer buffer size needs to reflect this as well, therefore based | 656 | * 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 | 657 | * on the calculations in the Linux driver the RX bufsize is set to | |
656 | * 18944, | 658 | * 18944, | |
657 | * bufsz = (16 * 1024 + 5 * 512) | 659 | * bufsz = (16 * 1024 + 5 * 512) | |
658 | * | 660 | * | |
659 | * Burst capability is the number of URBs that can be in a burst of | 661 | * Burst capability is the number of URBs that can be in a burst of | |
660 | * data/ethernet frames. | 662 | * data/ethernet frames. | |
661 | */ | 663 | */ | |
662 | 664 | |||
663 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | 665 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | |
664 | burst_cap = 37; | 666 | burst_cap = 37; | |
665 | else | 667 | else | |
666 | burst_cap = 128; | 668 | burst_cap = 128; | |
667 | 669 | |||
668 | smsc_writereg(un, SMSC_BURST_CAP, burst_cap); | 670 | smsc_writereg(un, SMSC_BURST_CAP, burst_cap); | |
669 | 671 | |||
670 | /* Set the default bulk in delay (magic value from Linux driver) */ | 672 | /* Set the default bulk in delay (magic value from Linux driver) */ | |
671 | smsc_writereg(un, SMSC_BULK_IN_DLY, 0x00002000); | 673 | smsc_writereg(un, SMSC_BULK_IN_DLY, 0x00002000); | |
672 | 674 | |||
673 | /* | 675 | /* | |
674 | * Initialise the RX interface | 676 | * Initialise the RX interface | |
675 | */ | 677 | */ | |
676 | if ((err = smsc_readreg(un, SMSC_HW_CFG, ®_val)) < 0) { | 678 | if ((err = smsc_readreg(un, SMSC_HW_CFG, ®_val)) < 0) { | |
677 | smsc_warn_printf(un, "failed to read HW_CFG: (err = %d)\n", | 679 | smsc_warn_printf(un, "failed to read HW_CFG: (err = %d)\n", | |
678 | err); | 680 | err); | |
679 | goto init_failed; | 681 | goto init_failed; | |
680 | } | 682 | } | |
681 | 683 | |||
682 | /* | 684 | /* | |
683 | * The following settings are used for 'turbo mode', a.k.a multiple | 685 | * The following settings are used for 'turbo mode', a.k.a multiple | |
684 | * frames per Rx transaction (again info taken form Linux driver). | 686 | * frames per Rx transaction (again info taken form Linux driver). | |
685 | */ | 687 | */ | |
686 | reg_val |= (SMSC_HW_CFG_MEF | SMSC_HW_CFG_BCE); | 688 | reg_val |= (SMSC_HW_CFG_MEF | SMSC_HW_CFG_BCE); | |
687 | 689 | |||
688 | /* | 690 | /* | |
689 | * set Rx data offset to ETHER_ALIGN which will make the IP header | 691 | * set Rx data offset to ETHER_ALIGN which will make the IP header | |
690 | * align on a word boundary. | 692 | * align on a word boundary. | |
691 | */ | 693 | */ | |
692 | reg_val |= ETHER_ALIGN << SMSC_HW_CFG_RXDOFF_SHIFT; | 694 | reg_val |= ETHER_ALIGN << SMSC_HW_CFG_RXDOFF_SHIFT; | |
693 | 695 | |||
694 | smsc_writereg(un, SMSC_HW_CFG, reg_val); | 696 | smsc_writereg(un, SMSC_HW_CFG, reg_val); | |
695 | 697 | |||
696 | /* Clear the status register ? */ | 698 | /* Clear the status register ? */ | |
697 | smsc_writereg(un, SMSC_INTR_STATUS, 0xffffffff); | 699 | smsc_writereg(un, SMSC_INTR_STATUS, 0xffffffff); | |
698 | 700 | |||
699 | /* Read and display the revision register */ | 701 | /* Read and display the revision register */ | |
700 | if ((err = smsc_readreg(un, SMSC_ID_REV, &sc->sc_rev_id)) < 0) { | 702 | 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); | 703 | smsc_warn_printf(un, "failed to read ID_REV (err = %d)\n", err); | |
702 | goto init_failed; | 704 | goto init_failed; | |
703 | } | 705 | } | |
704 | 706 | |||
705 | /* GPIO/LED setup */ | 707 | /* GPIO/LED setup */ | |
706 | reg_val = SMSC_LED_GPIO_CFG_SPD_LED | SMSC_LED_GPIO_CFG_LNK_LED | | 708 | reg_val = SMSC_LED_GPIO_CFG_SPD_LED | SMSC_LED_GPIO_CFG_LNK_LED | | |
707 | SMSC_LED_GPIO_CFG_FDX_LED; | 709 | SMSC_LED_GPIO_CFG_FDX_LED; | |
708 | smsc_writereg(un, SMSC_LED_GPIO_CFG, reg_val); | 710 | smsc_writereg(un, SMSC_LED_GPIO_CFG, reg_val); | |
709 | 711 | |||
710 | /* | 712 | /* | |
711 | * Initialise the TX interface | 713 | * Initialise the TX interface | |
712 | */ | 714 | */ | |
713 | smsc_writereg(un, SMSC_FLOW, 0); | 715 | smsc_writereg(un, SMSC_FLOW, 0); | |
714 | 716 | |||
715 | smsc_writereg(un, SMSC_AFC_CFG, AFC_CFG_DEFAULT); | 717 | smsc_writereg(un, SMSC_AFC_CFG, AFC_CFG_DEFAULT); | |
716 | 718 | |||
717 | /* Read the current MAC configuration */ | 719 | /* Read the current MAC configuration */ | |
718 | if ((err = smsc_readreg(un, SMSC_MAC_CSR, &sc->sc_mac_csr)) < 0) { | 720 | 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); | 721 | smsc_warn_printf(un, "failed to read MAC_CSR (err=%d)\n", err); | |
720 | goto init_failed; | 722 | goto init_failed; | |
721 | } | 723 | } | |
722 | 724 | |||
723 | /* disable pad stripping, collides with checksum offload */ | 725 | /* disable pad stripping, collides with checksum offload */ | |
724 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_PADSTR; | 726 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_PADSTR; | |
725 | 727 | |||
726 | /* Vlan */ | 728 | /* Vlan */ | |
727 | smsc_writereg(un, SMSC_VLAN1, (uint32_t)ETHERTYPE_VLAN); | 729 | smsc_writereg(un, SMSC_VLAN1, (uint32_t)ETHERTYPE_VLAN); | |
728 | 730 | |||
729 | /* | 731 | /* | |
730 | * Start TX | 732 | * Start TX | |
731 | */ | 733 | */ | |
732 | sc->sc_mac_csr |= SMSC_MAC_CSR_TXEN; | 734 | sc->sc_mac_csr |= SMSC_MAC_CSR_TXEN; | |
733 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 735 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
734 | smsc_writereg(un, SMSC_TX_CFG, SMSC_TX_CFG_ON); | 736 | smsc_writereg(un, SMSC_TX_CFG, SMSC_TX_CFG_ON); | |
735 | 737 | |||
736 | /* | 738 | /* | |
737 | * Start RX | 739 | * Start RX | |
738 | */ | 740 | */ | |
739 | sc->sc_mac_csr |= SMSC_MAC_CSR_RXEN; | 741 | sc->sc_mac_csr |= SMSC_MAC_CSR_RXEN; | |
740 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 742 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
741 | 743 | |||
742 | return 0; | 744 | return 0; | |
743 | 745 | |||
744 | init_failed: | 746 | init_failed: | |
745 | smsc_err_printf(un, "smsc_chip_init failed (err=%d)\n", err); | 747 | smsc_err_printf(un, "smsc_chip_init failed (err=%d)\n", err); | |
746 | return err; | 748 | return err; | |
747 | } | 749 | } | |
748 | 750 | |||
749 | static int | 751 | static int | |
750 | smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 752 | smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
751 | { | 753 | { | |
752 | struct usbnet * const un = ifp->if_softc; | 754 | struct usbnet * const un = ifp->if_softc; | |
753 | 755 | |||
754 | usbnet_lock_core(un); | 756 | usbnet_lock_core(un); | |
755 | usbnet_busy(un); | 757 | usbnet_busy(un); | |
756 | 758 | |||
757 | switch (cmd) { | 759 | switch (cmd) { | |
758 | case SIOCADDMULTI: | 760 | case SIOCADDMULTI: | |
759 | case SIOCDELMULTI: | 761 | case SIOCDELMULTI: | |
760 | smsc_setiff_locked(un); | 762 | smsc_setiff_locked(un); | |
761 | break; | 763 | break; | |
762 | case SIOCSIFCAP: | 764 | case SIOCSIFCAP: | |
763 | smsc_setoe_locked(un); | 765 | smsc_setoe_locked(un); | |
764 | break; | 766 | break; | |
765 | default: | 767 | default: | |
766 | break; | 768 | break; | |
767 | } | 769 | } | |
768 | 770 | |||
769 | usbnet_unbusy(un); | 771 | usbnet_unbusy(un); | |
770 | usbnet_unlock_core(un); | 772 | usbnet_unlock_core(un); | |
771 | 773 | |||
772 | return 0; | 774 | return 0; | |
773 | } | 775 | } | |
774 | 776 | |||
775 | static int | 777 | static int | |
776 | smsc_match(device_t parent, cfdata_t match, void *aux) | 778 | smsc_match(device_t parent, cfdata_t match, void *aux) | |
777 | { | 779 | { | |
778 | struct usb_attach_arg *uaa = aux; | 780 | struct usb_attach_arg *uaa = aux; | |
779 | 781 | |||
780 | return (usb_lookup(smsc_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL) ? | 782 | return (usb_lookup(smsc_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL) ? | |
781 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 783 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
782 | } | 784 | } | |
783 | 785 | |||
784 | static void | 786 | static void | |
785 | smsc_attach(device_t parent, device_t self, void *aux) | 787 | smsc_attach(device_t parent, device_t self, void *aux) | |
786 | { | 788 | { | |
787 | USBNET_MII_DECL_DEFAULT(unm); | 789 | USBNET_MII_DECL_DEFAULT(unm); | |
788 | struct smsc_softc * const sc = device_private(self); | 790 | struct smsc_softc * const sc = device_private(self); | |
789 | struct usbnet * const un = &sc->smsc_un; | 791 | struct usbnet * const un = &sc->smsc_un; | |
790 | struct usb_attach_arg *uaa = aux; | 792 | struct usb_attach_arg *uaa = aux; | |
791 | struct usbd_device *dev = uaa->uaa_device; | 793 | struct usbd_device *dev = uaa->uaa_device; | |
792 | usb_interface_descriptor_t *id; | 794 | usb_interface_descriptor_t *id; | |
793 | usb_endpoint_descriptor_t *ed; | 795 | usb_endpoint_descriptor_t *ed; | |
794 | char *devinfop; | 796 | char *devinfop; | |
795 | unsigned bufsz; | 797 | unsigned bufsz; | |
796 | int err, i; | 798 | int err, i; | |
797 | uint32_t mac_h, mac_l; | 799 | uint32_t mac_h, mac_l; | |
798 | 800 | |||
799 | KASSERT((void *)sc == un); | 801 | KASSERT((void *)sc == un); | |
800 | 802 | |||
801 | aprint_naive("\n"); | 803 | aprint_naive("\n"); | |
802 | aprint_normal("\n"); | 804 | aprint_normal("\n"); | |
803 | 805 | |||
804 | un->un_dev = self; | 806 | un->un_dev = self; | |
805 | un->un_udev = dev; | 807 | un->un_udev = dev; | |
806 | un->un_sc = sc; | 808 | un->un_sc = sc; | |
807 | un->un_ops = &smsc_ops; | 809 | un->un_ops = &smsc_ops; | |
808 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 810 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
809 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 811 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
810 | un->un_rx_list_cnt = SMSC_RX_LIST_CNT; | 812 | un->un_rx_list_cnt = SMSC_RX_LIST_CNT; | |
811 | un->un_tx_list_cnt = SMSC_TX_LIST_CNT; | 813 | un->un_tx_list_cnt = SMSC_TX_LIST_CNT; | |
812 | 814 | |||
813 | devinfop = usbd_devinfo_alloc(un->un_udev, 0); | 815 | devinfop = usbd_devinfo_alloc(un->un_udev, 0); | |
814 | aprint_normal_dev(self, "%s\n", devinfop); | 816 | aprint_normal_dev(self, "%s\n", devinfop); | |
815 | usbd_devinfo_free(devinfop); | 817 | usbd_devinfo_free(devinfop); | |
816 | 818 | |||
817 | err = usbd_set_config_no(dev, SMSC_CONFIG_INDEX, 1); | 819 | err = usbd_set_config_no(dev, SMSC_CONFIG_INDEX, 1); | |
818 | if (err) { | 820 | if (err) { | |
819 | aprint_error_dev(self, "failed to set configuration" | 821 | aprint_error_dev(self, "failed to set configuration" | |
820 | ", err=%s\n", usbd_errstr(err)); | 822 | ", err=%s\n", usbd_errstr(err)); | |
821 | return; | 823 | return; | |
822 | } | 824 | } | |
823 | 825 | |||
824 | /* Setup the endpoints for the SMSC LAN95xx device(s) */ | 826 | /* Setup the endpoints for the SMSC LAN95xx device(s) */ | |
825 | err = usbd_device2interface_handle(dev, SMSC_IFACE_IDX, &un->un_iface); | 827 | err = usbd_device2interface_handle(dev, SMSC_IFACE_IDX, &un->un_iface); | |
826 | if (err) { | 828 | if (err) { | |
827 | aprint_error_dev(self, "getting interface handle failed\n"); | 829 | aprint_error_dev(self, "getting interface handle failed\n"); | |
828 | return; | 830 | return; | |
829 | } | 831 | } | |
830 | 832 | |||
831 | id = usbd_get_interface_descriptor(un->un_iface); | 833 | id = usbd_get_interface_descriptor(un->un_iface); | |
832 | 834 | |||
833 | if (dev->ud_speed >= USB_SPEED_HIGH) { | 835 | if (dev->ud_speed >= USB_SPEED_HIGH) { | |
834 | bufsz = SMSC_MAX_BUFSZ; | 836 | bufsz = SMSC_MAX_BUFSZ; | |
835 | } else { | 837 | } else { | |
836 | bufsz = SMSC_MIN_BUFSZ; | 838 | bufsz = SMSC_MIN_BUFSZ; | |
837 | } | 839 | } | |
838 | un->un_rx_bufsz = bufsz; | 840 | un->un_rx_bufsz = bufsz; | |
839 | un->un_tx_bufsz = bufsz; | 841 | un->un_tx_bufsz = bufsz; | |
840 | 842 | |||
841 | /* Find endpoints. */ | 843 | /* Find endpoints. */ | |
842 | for (i = 0; i < id->bNumEndpoints; i++) { | 844 | for (i = 0; i < id->bNumEndpoints; i++) { | |
843 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 845 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
844 | if (!ed) { | 846 | if (!ed) { | |
845 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 847 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
846 | return; | 848 | return; | |
847 | } | 849 | } | |
848 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 850 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
849 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 851 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
850 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 852 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
851 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 853 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
852 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 854 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
853 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 855 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
854 | #if 0 /* not used yet */ | 856 | #if 0 /* not used yet */ | |
855 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 857 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
856 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 858 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
857 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 859 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
858 | #endif | 860 | #endif | |
859 | } | 861 | } | |
860 | } | 862 | } | |
861 | 863 | |||
862 | usbnet_attach(un, "smscdet"); | 864 | usbnet_attach(un, "smscdet"); | |
863 | 865 | |||
864 | #ifdef notyet | 866 | #ifdef notyet | |
865 | /* | 867 | /* | |
866 | * We can do TCPv4, and UDPv4 checksums in hardware. | 868 | * We can do TCPv4, and UDPv4 checksums in hardware. | |
867 | */ | 869 | */ | |
868 | struct ifnet *ifp = usbnet_ifp(un); | 870 | struct ifnet *ifp = usbnet_ifp(un); | |
869 | 871 | |||
870 | ifp->if_capabilities |= | 872 | ifp->if_capabilities |= | |
871 | /*IFCAP_CSUM_TCPv4_Tx |*/ IFCAP_CSUM_TCPv4_Rx | | 873 | /*IFCAP_CSUM_TCPv4_Tx |*/ IFCAP_CSUM_TCPv4_Rx | | |
872 | /*IFCAP_CSUM_UDPv4_Tx |*/ IFCAP_CSUM_UDPv4_Rx; | 874 | /*IFCAP_CSUM_UDPv4_Tx |*/ IFCAP_CSUM_UDPv4_Rx; | |
873 | #endif | 875 | #endif | |
874 | struct ethercom *ec = usbnet_ec(un); | 876 | struct ethercom *ec = usbnet_ec(un); | |
875 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | 877 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | |
876 | 878 | |||
877 | /* Setup some of the basics */ | 879 | /* Setup some of the basics */ | |
878 | un->un_phyno = 1; | 880 | un->un_phyno = 1; | |
879 | 881 | |||
880 | usbnet_lock_core(un); | 882 | usbnet_lock_core(un); | |
881 | usbnet_busy(un); | 883 | usbnet_busy(un); | |
882 | /* | 884 | /* | |
883 | * Attempt to get the mac address, if an EEPROM is not attached this | 885 | * Attempt to get the mac address, if an EEPROM is not attached this | |
884 | * will just return FF:FF:FF:FF:FF:FF, so in such cases we invent a MAC | 886 | * will just return FF:FF:FF:FF:FF:FF, so in such cases we invent a MAC | |
885 | * address based on urandom. | 887 | * address based on urandom. | |
886 | */ | 888 | */ | |
887 | memset(un->un_eaddr, 0xff, ETHER_ADDR_LEN); | 889 | memset(un->un_eaddr, 0xff, ETHER_ADDR_LEN); | |
888 | 890 | |||
889 | prop_dictionary_t dict = device_properties(self); | 891 | prop_dictionary_t dict = device_properties(self); | |
890 | prop_data_t eaprop = prop_dictionary_get(dict, "mac-address"); | 892 | prop_data_t eaprop = prop_dictionary_get(dict, "mac-address"); | |
891 | 893 | |||
892 | if (eaprop != NULL) { | 894 | if (eaprop != NULL) { | |
893 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | 895 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | |
894 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | 896 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | |
895 | memcpy(un->un_eaddr, prop_data_value(eaprop), | 897 | memcpy(un->un_eaddr, prop_data_value(eaprop), | |
896 | ETHER_ADDR_LEN); | 898 | ETHER_ADDR_LEN); | |
897 | } else { | 899 | } else { | |
898 | /* Check if there is already a MAC address in the register */ | 900 | /* Check if there is already a MAC address in the register */ | |
899 | if ((smsc_readreg(un, SMSC_MAC_ADDRL, &mac_l) == 0) && | 901 | if ((smsc_readreg(un, SMSC_MAC_ADDRL, &mac_l) == 0) && | |
900 | (smsc_readreg(un, SMSC_MAC_ADDRH, &mac_h) == 0)) { | 902 | (smsc_readreg(un, SMSC_MAC_ADDRH, &mac_h) == 0)) { | |
901 | un->un_eaddr[5] = (uint8_t)((mac_h >> 8) & 0xff); | 903 | un->un_eaddr[5] = (uint8_t)((mac_h >> 8) & 0xff); | |
902 | un->un_eaddr[4] = (uint8_t)((mac_h) & 0xff); | 904 | un->un_eaddr[4] = (uint8_t)((mac_h) & 0xff); | |
903 | un->un_eaddr[3] = (uint8_t)((mac_l >> 24) & 0xff); | 905 | un->un_eaddr[3] = (uint8_t)((mac_l >> 24) & 0xff); | |
904 | un->un_eaddr[2] = (uint8_t)((mac_l >> 16) & 0xff); | 906 | un->un_eaddr[2] = (uint8_t)((mac_l >> 16) & 0xff); | |
905 | un->un_eaddr[1] = (uint8_t)((mac_l >> 8) & 0xff); | 907 | un->un_eaddr[1] = (uint8_t)((mac_l >> 8) & 0xff); | |
906 | un->un_eaddr[0] = (uint8_t)((mac_l) & 0xff); | 908 | un->un_eaddr[0] = (uint8_t)((mac_l) & 0xff); | |
907 | } | 909 | } | |
908 | } | 910 | } | |
909 | usbnet_unbusy(un); | 911 | usbnet_unbusy(un); | |
910 | usbnet_unlock_core(un); | 912 | usbnet_unlock_core(un); | |
911 | 913 | |||
912 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 914 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
913 | 0, &unm); | 915 | 0, &unm); | |
914 | } | 916 | } | |
915 | 917 | |||
916 | static void | 918 | static void | |
917 | smsc_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 919 | smsc_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
918 | { | 920 | { | |
919 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | 921 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | |
920 | struct smsc_softc * const sc = usbnet_softc(un); | 922 | struct smsc_softc * const sc = usbnet_softc(un); | |
921 | struct ifnet *ifp = usbnet_ifp(un); | 923 | struct ifnet *ifp = usbnet_ifp(un); | |
922 | uint8_t *buf = c->unc_buf; | 924 | uint8_t *buf = c->unc_buf; | |
923 | int count; | 925 | int count; | |
924 | 926 | |||
925 | count = 0; | 927 | count = 0; | |
926 | DPRINTF("total_len %jd/%#jx", total_len, total_len, 0, 0); | 928 | DPRINTF("total_len %jd/%#jx", total_len, total_len, 0, 0); | |
927 | while (total_len != 0) { | 929 | while (total_len != 0) { | |
928 | uint32_t rxhdr; | 930 | uint32_t rxhdr; | |
929 | if (total_len < sizeof(rxhdr)) { | 931 | if (total_len < sizeof(rxhdr)) { | |
930 | DPRINTF("total_len %jd < sizeof(rxhdr) %jd", | 932 | DPRINTF("total_len %jd < sizeof(rxhdr) %jd", | |
931 | total_len, sizeof(rxhdr), 0, 0); | 933 | total_len, sizeof(rxhdr), 0, 0); | |
932 | if_statinc(ifp, if_ierrors); | 934 | if_statinc(ifp, if_ierrors); | |
933 | return; | 935 | return; | |
934 | } | 936 | } | |
935 | 937 | |||
936 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | 938 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | |
937 | rxhdr = le32toh(rxhdr); | 939 | rxhdr = le32toh(rxhdr); | |
938 | buf += sizeof(rxhdr); | 940 | buf += sizeof(rxhdr); | |
939 | total_len -= sizeof(rxhdr); | 941 | total_len -= sizeof(rxhdr); | |
940 | 942 | |||
941 | if (rxhdr & SMSC_RX_STAT_COLLISION) | 943 | if (rxhdr & SMSC_RX_STAT_COLLISION) | |
942 | if_statinc(ifp, if_collisions); | 944 | if_statinc(ifp, if_collisions); | |
943 | 945 | |||
944 | if (rxhdr & (SMSC_RX_STAT_ERROR | 946 | if (rxhdr & (SMSC_RX_STAT_ERROR | |
945 | | SMSC_RX_STAT_LENGTH_ERROR | 947 | | SMSC_RX_STAT_LENGTH_ERROR | |
946 | | SMSC_RX_STAT_MII_ERROR)) { | 948 | | SMSC_RX_STAT_MII_ERROR)) { | |
947 | DPRINTF("rx error (hdr 0x%08jx)", rxhdr, 0, 0, 0); | 949 | DPRINTF("rx error (hdr 0x%08jx)", rxhdr, 0, 0, 0); | |
948 | if_statinc(ifp, if_ierrors); | 950 | if_statinc(ifp, if_ierrors); | |
949 | return; | 951 | return; | |
950 | } | 952 | } | |
951 | 953 | |||
952 | uint16_t pktlen = (uint16_t)SMSC_RX_STAT_FRM_LENGTH(rxhdr); | 954 | uint16_t pktlen = (uint16_t)SMSC_RX_STAT_FRM_LENGTH(rxhdr); | |
953 | DPRINTF("total_len %jd pktlen %jd rxhdr 0x%08jx", total_len, | 955 | DPRINTF("total_len %jd pktlen %jd rxhdr 0x%08jx", total_len, | |
954 | pktlen, rxhdr, 0); | 956 | pktlen, rxhdr, 0); | |
955 | 957 | |||
956 | if (pktlen < ETHER_HDR_LEN) { | 958 | if (pktlen < ETHER_HDR_LEN) { | |
957 | DPRINTF("pktlen %jd < ETHER_HDR_LEN %jd", pktlen, | 959 | DPRINTF("pktlen %jd < ETHER_HDR_LEN %jd", pktlen, | |
958 | ETHER_HDR_LEN, 0, 0); | 960 | ETHER_HDR_LEN, 0, 0); | |
959 | if_statinc(ifp, if_ierrors); | 961 | if_statinc(ifp, if_ierrors); | |
960 | return; | 962 | return; | |
961 | } | 963 | } | |
962 | 964 | |||
963 | pktlen += ETHER_ALIGN; | 965 | pktlen += ETHER_ALIGN; | |
964 | 966 | |||
965 | if (pktlen > MCLBYTES) { | 967 | if (pktlen > MCLBYTES) { | |
966 | DPRINTF("pktlen %jd > MCLBYTES %jd", pktlen, MCLBYTES, 0, | 968 | DPRINTF("pktlen %jd > MCLBYTES %jd", pktlen, MCLBYTES, 0, | |
967 | 0); | 969 | 0); | |
968 | if_statinc(ifp, if_ierrors); | 970 | if_statinc(ifp, if_ierrors); | |
969 | return; | 971 | return; | |
970 | } | 972 | } | |
971 | 973 | |||
972 | if (pktlen > total_len) { | 974 | if (pktlen > total_len) { | |
973 | DPRINTF("pktlen %jd > total_len %jd", pktlen, total_len, | 975 | DPRINTF("pktlen %jd > total_len %jd", pktlen, total_len, | |
974 | 0, 0); | 976 | 0, 0); | |
975 | if_statinc(ifp, if_ierrors); | 977 | if_statinc(ifp, if_ierrors); | |
976 | return; | 978 | return; | |
977 | } | 979 | } | |
978 | 980 | |||
979 | uint8_t *pktbuf = buf + ETHER_ALIGN; | 981 | uint8_t *pktbuf = buf + ETHER_ALIGN; | |
980 | size_t buflen = pktlen - ETHER_ALIGN; | 982 | size_t buflen = pktlen - ETHER_ALIGN; | |
981 | int mbuf_flags = M_HASFCS; | 983 | int mbuf_flags = M_HASFCS; | |
982 | int csum_flags = 0; | 984 | int csum_flags = 0; | |
983 | uint16_t csum_data = 0; | 985 | uint16_t csum_data = 0; | |
984 | 986 | |||
985 | KASSERT(pktlen < MCLBYTES); | 987 | KASSERT(pktlen < MCLBYTES); | |
986 | 988 | |||
987 | /* Check if RX TCP/UDP checksumming is being offloaded */ | 989 | /* Check if RX TCP/UDP checksumming is being offloaded */ | |
988 | if (sc->sc_coe_ctrl & SMSC_COE_CTRL_RX_EN) { | 990 | if (sc->sc_coe_ctrl & SMSC_COE_CTRL_RX_EN) { | |
989 | DPRINTF("RX checksum offload checking", 0, 0, 0, 0); | 991 | DPRINTF("RX checksum offload checking", 0, 0, 0, 0); | |
990 | struct ether_header *eh = (struct ether_header *)pktbuf; | 992 | struct ether_header *eh = (struct ether_header *)pktbuf; | |
991 | const size_t cssz = sizeof(csum_data); | 993 | const size_t cssz = sizeof(csum_data); | |
992 | 994 | |||
993 | /* Remove the extra 2 bytes of the csum */ | 995 | /* Remove the extra 2 bytes of the csum */ | |
994 | buflen -= cssz; | 996 | buflen -= cssz; | |
995 | 997 | |||
996 | /* | 998 | /* | |
997 | * The checksum appears to be simplistically calculated | 999 | * The checksum appears to be simplistically calculated | |
998 | * over the udp/tcp header and data up to the end of the | 1000 | * over the udp/tcp header and data up to the end of the | |
999 | * eth frame. Which means if the eth frame is padded | 1001 | * eth frame. Which means if the eth frame is padded | |
1000 | * the csum calculation is incorrectly performed over | 1002 | * the csum calculation is incorrectly performed over | |
1001 | * the padding bytes as well. Therefore to be safe we | 1003 | * the padding bytes as well. Therefore to be safe we | |
1002 | * ignore the H/W csum on frames less than or equal to | 1004 | * ignore the H/W csum on frames less than or equal to | |
1003 | * 64 bytes. | 1005 | * 64 bytes. | |
1004 | * | 1006 | * | |
1005 | * Ignore H/W csum for non-IPv4 packets. | 1007 | * Ignore H/W csum for non-IPv4 packets. | |
1006 | */ | 1008 | */ | |
1007 | DPRINTF("Ethertype %02jx pktlen %02jx", | 1009 | DPRINTF("Ethertype %02jx pktlen %02jx", | |
1008 | be16toh(eh->ether_type), pktlen, 0, 0); | 1010 | be16toh(eh->ether_type), pktlen, 0, 0); | |
1009 | if (be16toh(eh->ether_type) == ETHERTYPE_IP && | 1011 | if (be16toh(eh->ether_type) == ETHERTYPE_IP && | |
1010 | pktlen > ETHER_MIN_LEN) { | 1012 | pktlen > ETHER_MIN_LEN) { | |
1011 | 1013 | |||
1012 | csum_flags |= | 1014 | csum_flags |= | |
1013 | (M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_DATA); | 1015 | (M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_DATA); | |
1014 | 1016 | |||
1015 | /* | 1017 | /* | |
1016 | * Copy the TCP/UDP checksum from the last 2 | 1018 | * Copy the TCP/UDP checksum from the last 2 | |
1017 | * bytes of the transfer and put in the | 1019 | * bytes of the transfer and put in the | |
1018 | * csum_data field. | 1020 | * csum_data field. | |
1019 | */ | 1021 | */ | |
1020 | memcpy(&csum_data, buf + pktlen - cssz, cssz); | 1022 | memcpy(&csum_data, buf + pktlen - cssz, cssz); | |
1021 | 1023 | |||
1022 | /* | 1024 | /* | |
1023 | * The data is copied in network order, but the | 1025 | * The data is copied in network order, but the | |
1024 | * csum algorithm in the kernel expects it to be | 1026 | * csum algorithm in the kernel expects it to be | |
1025 | * in host network order. | 1027 | * in host network order. | |
1026 | */ | 1028 | */ | |
1027 | csum_data = ntohs(csum_data); | 1029 | csum_data = ntohs(csum_data); | |
1028 | DPRINTF("RX checksum offloaded (0x%04jx)", | 1030 | DPRINTF("RX checksum offloaded (0x%04jx)", | |
1029 | csum_data, 0, 0, 0); | 1031 | csum_data, 0, 0, 0); | |
1030 | } | 1032 | } | |
1031 | } | 1033 | } | |
1032 | 1034 | |||
1033 | /* round up to next longword */ | 1035 | /* round up to next longword */ | |
1034 | pktlen = (pktlen + 3) & ~0x3; | 1036 | pktlen = (pktlen + 3) & ~0x3; | |
1035 | 1037 | |||
1036 | /* total_len does not include the padding */ | 1038 | /* total_len does not include the padding */ | |
1037 | if (pktlen > total_len) | 1039 | if (pktlen > total_len) | |
1038 | pktlen = total_len; | 1040 | pktlen = total_len; | |
1039 | 1041 | |||
1040 | buf += pktlen; | 1042 | buf += pktlen; | |
1041 | total_len -= pktlen; | 1043 | total_len -= pktlen; | |
1042 | 1044 | |||
1043 | /* push the packet up */ | 1045 | /* push the packet up */ | |
1044 | usbnet_enqueue(un, pktbuf, buflen, csum_flags, csum_data, | 1046 | usbnet_enqueue(un, pktbuf, buflen, csum_flags, csum_data, | |
1045 | mbuf_flags); | 1047 | mbuf_flags); | |
1046 | 1048 | |||
1047 | count++; | 1049 | count++; | |
1048 | } | 1050 | } | |
1049 | 1051 | |||
1050 | if (count != 0) | 1052 | if (count != 0) | |
1051 | rnd_add_uint32(usbnet_rndsrc(un), count); | 1053 | rnd_add_uint32(usbnet_rndsrc(un), count); | |
1052 | } | 1054 | } | |
1053 | 1055 | |||
1054 | static unsigned | 1056 | static unsigned | |
1055 | smsc_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 1057 | smsc_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
1056 | { | 1058 | { | |
1057 | uint32_t txhdr; | 1059 | uint32_t txhdr; | |
1058 | uint32_t frm_len = 0; | 1060 | uint32_t frm_len = 0; | |
1059 | 1061 | |||
1060 | const size_t hdrsz = sizeof(txhdr) * 2; | 1062 | const size_t hdrsz = sizeof(txhdr) * 2; | |
1061 | 1063 | |||
1062 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - hdrsz) | 1064 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - hdrsz) | |
1063 | return 0; | 1065 | return 0; | |
1064 | 1066 | |||
1065 | /* | 1067 | /* | |
1066 | * Each frame is prefixed with two 32-bit values describing the | 1068 | * Each frame is prefixed with two 32-bit values describing the | |
1067 | * length of the packet and buffer. | 1069 | * length of the packet and buffer. | |
1068 | */ | 1070 | */ | |
1069 | txhdr = SMSC_TX_CTRL_0_BUF_SIZE(m->m_pkthdr.len) | | 1071 | txhdr = SMSC_TX_CTRL_0_BUF_SIZE(m->m_pkthdr.len) | | |
1070 | SMSC_TX_CTRL_0_FIRST_SEG | SMSC_TX_CTRL_0_LAST_SEG; | 1072 | SMSC_TX_CTRL_0_FIRST_SEG | SMSC_TX_CTRL_0_LAST_SEG; | |
1071 | txhdr = htole32(txhdr); | 1073 | txhdr = htole32(txhdr); | |
1072 | memcpy(c->unc_buf, &txhdr, sizeof(txhdr)); | 1074 | memcpy(c->unc_buf, &txhdr, sizeof(txhdr)); | |
1073 | 1075 | |||
1074 | txhdr = SMSC_TX_CTRL_1_PKT_LENGTH(m->m_pkthdr.len); | 1076 | txhdr = SMSC_TX_CTRL_1_PKT_LENGTH(m->m_pkthdr.len); | |
1075 | txhdr = htole32(txhdr); | 1077 | txhdr = htole32(txhdr); | |
1076 | memcpy(c->unc_buf + sizeof(txhdr), &txhdr, sizeof(txhdr)); | 1078 | memcpy(c->unc_buf + sizeof(txhdr), &txhdr, sizeof(txhdr)); | |
1077 | 1079 | |||
1078 | frm_len += hdrsz; | 1080 | frm_len += hdrsz; | |
1079 | 1081 | |||
1080 | /* Next copy in the actual packet */ | 1082 | /* Next copy in the actual packet */ | |
1081 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + frm_len); | 1083 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + frm_len); | |
1082 | frm_len += m->m_pkthdr.len; | 1084 | frm_len += m->m_pkthdr.len; | |
1083 | 1085 | |||
1084 | return frm_len; | 1086 | return frm_len; | |
1085 | } | 1087 | } | |
1086 | 1088 | |||
1087 | #ifdef _MODULE | 1089 | #ifdef _MODULE | |
1088 | #include "ioconf.c" | 1090 | #include "ioconf.c" | |
1089 | #endif | 1091 | #endif | |
1090 | 1092 | |||
1091 | USBNET_MODULE(smsc) | 1093 | USBNET_MODULE(smsc) |
--- src/sys/dev/usb/if_udav.c 2022/03/03 05:50:22 1.79
+++ src/sys/dev/usb/if_udav.c 2022/03/03 05:50:57 1.80
@@ -1,865 +1,867 @@ | @@ -1,865 +1,867 @@ | |||
1 | /* $NetBSD: if_udav.c,v 1.79 2022/03/03 05:50:22 riastradh Exp $ */ | 1 | /* $NetBSD: if_udav.c,v 1.80 2022/03/03 05:50:57 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.79 2022/03/03 05:50:22 riastradh Exp $"); | 48 | __KERNEL_RCSID(0, "$NetBSD: if_udav.c,v 1.80 2022/03/03 05:50:57 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 int udav_uno_ioctl(struct ifnet *, u_long, void *); | 72 | static int udav_uno_ioctl(struct ifnet *, u_long, void *); | |
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_ioctl = udav_uno_ioctl, | 135 | .uno_ioctl = udav_uno_ioctl, | |
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 | usbnet_busy(un); | 489 | usbnet_busy(un); | |
490 | 490 | |||
491 | memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); | 491 | memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); | |
492 | udav_csr_write(un, UDAV_PAR, eaddr, ETHER_ADDR_LEN); | 492 | udav_csr_write(un, UDAV_PAR, eaddr, ETHER_ADDR_LEN); | |
493 | 493 | |||
494 | /* Initialize network control register */ | 494 | /* Initialize network control register */ | |
495 | /* Disable loopback */ | 495 | /* Disable loopback */ | |
496 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1); | 496 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1); | |
497 | 497 | |||
498 | /* Initialize RX control register */ | 498 | /* Initialize RX control register */ | |
499 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC); | 499 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC); | |
500 | 500 | |||
501 | /* If we want promiscuous mode, accept all physical frames. */ | 501 | /* If we want promiscuous mode, accept all physical frames. */ | |
502 | if (ifp->if_flags & IFF_PROMISC) | 502 | if (ifp->if_flags & IFF_PROMISC) | |
503 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | 503 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | |
504 | else | 504 | else | |
505 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | 505 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | |
506 | 506 | |||
507 | /* Load the multicast filter */ | 507 | /* Load the multicast filter */ | |
508 | udav_setiff_locked(un); | 508 | udav_setiff_locked(un); | |
509 | 509 | |||
510 | /* Enable RX */ | 510 | /* Enable RX */ | |
511 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_RXEN); | 511 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_RXEN); | |
512 | 512 | |||
513 | /* clear POWER_DOWN state of internal PHY */ | 513 | /* clear POWER_DOWN state of internal PHY */ | |
514 | UDAV_SETBIT(un, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0); | 514 | UDAV_SETBIT(un, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0); | |
515 | UDAV_CLRBIT(un, UDAV_GPR, UDAV_GPR_GEPIO0); | 515 | UDAV_CLRBIT(un, UDAV_GPR, UDAV_GPR_GEPIO0); | |
516 | 516 | |||
517 | if (mii && (rc = mii_mediachg(mii)) == ENXIO) | 517 | if (mii && (rc = mii_mediachg(mii)) == ENXIO) | |
518 | rc = 0; | 518 | rc = 0; | |
519 | 519 | |||
520 | if (rc != 0) { | 520 | if (rc != 0) { | |
521 | usbnet_unbusy(un); | 521 | usbnet_unbusy(un); | |
522 | return rc; | 522 | return rc; | |
523 | } | 523 | } | |
524 | 524 | |||
525 | if (usbnet_isdying(un)) | 525 | if (usbnet_isdying(un)) | |
526 | rc = EIO; | 526 | rc = EIO; | |
527 | else | 527 | else | |
528 | rc = usbnet_init_rx_tx(un); | 528 | rc = usbnet_init_rx_tx(un); | |
529 | 529 | |||
530 | usbnet_unbusy(un); | 530 | usbnet_unbusy(un); | |
531 | 531 | |||
532 | return rc; | 532 | return rc; | |
533 | } | 533 | } | |
534 | 534 | |||
535 | static void | 535 | static void | |
536 | udav_reset(struct usbnet *un) | 536 | udav_reset(struct usbnet *un) | |
537 | { | 537 | { | |
538 | usbnet_isowned_core(un); | 538 | usbnet_isowned_core(un); | |
539 | 539 | |||
540 | if (usbnet_isdying(un)) | 540 | if (usbnet_isdying(un)) | |
541 | return; | 541 | return; | |
542 | 542 | |||
543 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 543 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
544 | 544 | |||
545 | udav_chip_init(un); | 545 | udav_chip_init(un); | |
546 | } | 546 | } | |
547 | 547 | |||
548 | static void | 548 | static void | |
549 | udav_chip_init(struct usbnet *un) | 549 | udav_chip_init(struct usbnet *un) | |
550 | { | 550 | { | |
551 | usbnet_isowned_core(un); | 551 | usbnet_isowned_core(un); | |
552 | 552 | |||
553 | /* Select PHY */ | 553 | /* Select PHY */ | |
554 | #if 1 | 554 | #if 1 | |
555 | /* | 555 | /* | |
556 | * XXX: force select internal phy. | 556 | * XXX: force select internal phy. | |
557 | * external phy routines are not tested. | 557 | * external phy routines are not tested. | |
558 | */ | 558 | */ | |
559 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | 559 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | |
560 | #else | 560 | #else | |
561 | if (un->un_flags & UDAV_EXT_PHY) { | 561 | if (un->un_flags & UDAV_EXT_PHY) { | |
562 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | 562 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | |
563 | } else { | 563 | } else { | |
564 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | 564 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | |
565 | } | 565 | } | |
566 | #endif | 566 | #endif | |
567 | 567 | |||
568 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_RST); | 568 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_RST); | |
569 | 569 | |||
570 | for (int i = 0; i < UDAV_TX_TIMEOUT; i++) { | 570 | for (int i = 0; i < UDAV_TX_TIMEOUT; i++) { | |
571 | if (usbnet_isdying(un)) | |||
572 | return; | |||
571 | if (!(udav_csr_read1(un, UDAV_NCR) & UDAV_NCR_RST)) | 573 | if (!(udav_csr_read1(un, UDAV_NCR) & UDAV_NCR_RST)) | |
572 | break; | 574 | break; | |
573 | delay(10); /* XXX */ | 575 | delay(10); /* XXX */ | |
574 | } | 576 | } | |
575 | delay(10000); /* XXX */ | 577 | delay(10000); /* XXX */ | |
576 | } | 578 | } | |
577 | 579 | |||
578 | #define UDAV_BITS 6 | 580 | #define UDAV_BITS 6 | |
579 | 581 | |||
580 | #define UDAV_CALCHASH(addr) \ | 582 | #define UDAV_CALCHASH(addr) \ | |
581 | (ether_crc32_le((addr), ETHER_ADDR_LEN) & ((1 << UDAV_BITS) - 1)) | 583 | (ether_crc32_le((addr), ETHER_ADDR_LEN) & ((1 << UDAV_BITS) - 1)) | |
582 | 584 | |||
583 | static void | 585 | static void | |
584 | udav_setiff_locked(struct usbnet *un) | 586 | udav_setiff_locked(struct usbnet *un) | |
585 | { | 587 | { | |
586 | struct ethercom *ec = usbnet_ec(un); | 588 | struct ethercom *ec = usbnet_ec(un); | |
587 | struct ifnet * const ifp = usbnet_ifp(un); | 589 | struct ifnet * const ifp = usbnet_ifp(un); | |
588 | struct ether_multi *enm; | 590 | struct ether_multi *enm; | |
589 | struct ether_multistep step; | 591 | struct ether_multistep step; | |
590 | uint8_t hashes[8]; | 592 | uint8_t hashes[8]; | |
591 | int h = 0; | 593 | int h = 0; | |
592 | 594 | |||
593 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 595 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
594 | 596 | |||
595 | usbnet_isowned_core(un); | 597 | usbnet_isowned_core(un); | |
596 | 598 | |||
597 | if (usbnet_isdying(un)) | 599 | if (usbnet_isdying(un)) | |
598 | return; | 600 | return; | |
599 | 601 | |||
600 | if (ISSET(un->un_flags, UDAV_NO_PHY)) { | 602 | if (ISSET(un->un_flags, UDAV_NO_PHY)) { | |
601 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | 603 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | |
602 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | 604 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | |
603 | return; | 605 | return; | |
604 | } | 606 | } | |
605 | 607 | |||
606 | if (ifp->if_flags & IFF_PROMISC) { | 608 | if (ifp->if_flags & IFF_PROMISC) { | |
607 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | 609 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | |
608 | return; | 610 | return; | |
609 | } else if (ifp->if_flags & IFF_ALLMULTI) { | 611 | } else if (ifp->if_flags & IFF_ALLMULTI) { | |
610 | allmulti: | 612 | allmulti: | |
611 | ifp->if_flags |= IFF_ALLMULTI; | 613 | ifp->if_flags |= IFF_ALLMULTI; | |
612 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | 614 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | |
613 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | 615 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | |
614 | return; | 616 | return; | |
615 | } | 617 | } | |
616 | 618 | |||
617 | /* first, zot all the existing hash bits */ | 619 | /* first, zot all the existing hash bits */ | |
618 | memset(hashes, 0x00, sizeof(hashes)); | 620 | memset(hashes, 0x00, sizeof(hashes)); | |
619 | hashes[7] |= 0x80; /* broadcast address */ | 621 | hashes[7] |= 0x80; /* broadcast address */ | |
620 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | 622 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | |
621 | 623 | |||
622 | /* now program new ones */ | 624 | /* now program new ones */ | |
623 | ETHER_LOCK(ec); | 625 | ETHER_LOCK(ec); | |
624 | ETHER_FIRST_MULTI(step, ec, enm); | 626 | ETHER_FIRST_MULTI(step, ec, enm); | |
625 | while (enm != NULL) { | 627 | while (enm != NULL) { | |
626 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | 628 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
627 | ETHER_ADDR_LEN) != 0) { | 629 | ETHER_ADDR_LEN) != 0) { | |
628 | ETHER_UNLOCK(ec); | 630 | ETHER_UNLOCK(ec); | |
629 | goto allmulti; | 631 | goto allmulti; | |
630 | } | 632 | } | |
631 | 633 | |||
632 | h = UDAV_CALCHASH(enm->enm_addrlo); | 634 | h = UDAV_CALCHASH(enm->enm_addrlo); | |
633 | hashes[h>>3] |= 1 << (h & 0x7); | 635 | hashes[h>>3] |= 1 << (h & 0x7); | |
634 | ETHER_NEXT_MULTI(step, enm); | 636 | ETHER_NEXT_MULTI(step, enm); | |
635 | } | 637 | } | |
636 | ETHER_UNLOCK(ec); | 638 | ETHER_UNLOCK(ec); | |
637 | 639 | |||
638 | /* disable all multicast */ | 640 | /* disable all multicast */ | |
639 | ifp->if_flags &= ~IFF_ALLMULTI; | 641 | ifp->if_flags &= ~IFF_ALLMULTI; | |
640 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL); | 642 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL); | |
641 | 643 | |||
642 | /* write hash value to the register */ | 644 | /* write hash value to the register */ | |
643 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | 645 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | |
644 | } | 646 | } | |
645 | 647 | |||
646 | static unsigned | 648 | static unsigned | |
647 | udav_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 649 | udav_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
648 | { | 650 | { | |
649 | int total_len; | 651 | int total_len; | |
650 | uint8_t *buf = c->unc_buf; | 652 | uint8_t *buf = c->unc_buf; | |
651 | 653 | |||
652 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 654 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
653 | 655 | |||
654 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | 656 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | |
655 | return 0; | 657 | return 0; | |
656 | 658 | |||
657 | /* Copy the mbuf data into a contiguous buffer */ | 659 | /* Copy the mbuf data into a contiguous buffer */ | |
658 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | 660 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | |
659 | total_len = m->m_pkthdr.len; | 661 | total_len = m->m_pkthdr.len; | |
660 | if (total_len < UDAV_MIN_FRAME_LEN) { | 662 | if (total_len < UDAV_MIN_FRAME_LEN) { | |
661 | memset(buf + 2 + total_len, 0, | 663 | memset(buf + 2 + total_len, 0, | |
662 | UDAV_MIN_FRAME_LEN - total_len); | 664 | UDAV_MIN_FRAME_LEN - total_len); | |
663 | total_len = UDAV_MIN_FRAME_LEN; | 665 | total_len = UDAV_MIN_FRAME_LEN; | |
664 | } | 666 | } | |
665 | 667 | |||
666 | /* Frame length is specified in the first 2bytes of the buffer */ | 668 | /* Frame length is specified in the first 2bytes of the buffer */ | |
667 | buf[0] = (uint8_t)total_len; | 669 | buf[0] = (uint8_t)total_len; | |
668 | buf[1] = (uint8_t)(total_len >> 8); | 670 | buf[1] = (uint8_t)(total_len >> 8); | |
669 | total_len += 2; | 671 | total_len += 2; | |
670 | 672 | |||
671 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | 673 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | |
672 | __func__, total_len)); | 674 | __func__, total_len)); | |
673 | 675 | |||
674 | return total_len; | 676 | return total_len; | |
675 | } | 677 | } | |
676 | 678 | |||
677 | static void | 679 | static void | |
678 | udav_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 680 | udav_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
679 | { | 681 | { | |
680 | struct ifnet *ifp = usbnet_ifp(un); | 682 | struct ifnet *ifp = usbnet_ifp(un); | |
681 | uint8_t *buf = c->unc_buf; | 683 | uint8_t *buf = c->unc_buf; | |
682 | uint16_t pkt_len; | 684 | uint16_t pkt_len; | |
683 | uint8_t pktstat; | 685 | uint8_t pktstat; | |
684 | 686 | |||
685 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 687 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
686 | 688 | |||
687 | /* first byte in received data */ | 689 | /* first byte in received data */ | |
688 | pktstat = *buf; | 690 | pktstat = *buf; | |
689 | total_len -= sizeof(pktstat); | 691 | total_len -= sizeof(pktstat); | |
690 | buf += sizeof(pktstat); | 692 | buf += sizeof(pktstat); | |
691 | 693 | |||
692 | DPRINTF(("%s: RX Status: 0x%02x\n", device_xname(un->un_dev), pktstat)); | 694 | DPRINTF(("%s: RX Status: 0x%02x\n", device_xname(un->un_dev), pktstat)); | |
693 | 695 | |||
694 | pkt_len = UGETW(buf); | 696 | pkt_len = UGETW(buf); | |
695 | total_len -= sizeof(pkt_len); | 697 | total_len -= sizeof(pkt_len); | |
696 | buf += sizeof(pkt_len); | 698 | buf += sizeof(pkt_len); | |
697 | 699 | |||
698 | DPRINTF(("%s: RX Length: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | 700 | DPRINTF(("%s: RX Length: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | |
699 | 701 | |||
700 | if (pktstat & UDAV_RSR_LCS) { | 702 | if (pktstat & UDAV_RSR_LCS) { | |
701 | if_statinc(ifp, if_collisions); | 703 | if_statinc(ifp, if_collisions); | |
702 | return; | 704 | return; | |
703 | } | 705 | } | |
704 | 706 | |||
705 | if (pkt_len < sizeof(struct ether_header) || | 707 | if (pkt_len < sizeof(struct ether_header) || | |
706 | pkt_len > total_len || | 708 | pkt_len > total_len || | |
707 | (pktstat & UDAV_RSR_ERR)) { | 709 | (pktstat & UDAV_RSR_ERR)) { | |
708 | if_statinc(ifp, if_ierrors); | 710 | if_statinc(ifp, if_ierrors); | |
709 | return; | 711 | return; | |
710 | } | 712 | } | |
711 | 713 | |||
712 | pkt_len -= ETHER_CRC_LEN; | 714 | pkt_len -= ETHER_CRC_LEN; | |
713 | 715 | |||
714 | DPRINTF(("%s: Rx deliver: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | 716 | DPRINTF(("%s: Rx deliver: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | |
715 | 717 | |||
716 | usbnet_enqueue(un, buf, pkt_len, 0, 0, 0); | 718 | usbnet_enqueue(un, buf, pkt_len, 0, 0, 0); | |
717 | } | 719 | } | |
718 | 720 | |||
719 | static int | 721 | static int | |
720 | udav_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 722 | udav_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
721 | { | 723 | { | |
722 | struct usbnet * const un = ifp->if_softc; | 724 | struct usbnet * const un = ifp->if_softc; | |
723 | 725 | |||
724 | usbnet_lock_core(un); | 726 | usbnet_lock_core(un); | |
725 | usbnet_busy(un); | 727 | usbnet_busy(un); | |
726 | 728 | |||
727 | switch (cmd) { | 729 | switch (cmd) { | |
728 | case SIOCADDMULTI: | 730 | case SIOCADDMULTI: | |
729 | case SIOCDELMULTI: | 731 | case SIOCDELMULTI: | |
730 | udav_setiff_locked(un); | 732 | udav_setiff_locked(un); | |
731 | break; | 733 | break; | |
732 | default: | 734 | default: | |
733 | break; | 735 | break; | |
734 | } | 736 | } | |
735 | 737 | |||
736 | usbnet_unbusy(un); | 738 | usbnet_unbusy(un); | |
737 | usbnet_unlock_core(un); | 739 | usbnet_unlock_core(un); | |
738 | 740 | |||
739 | return 0; | 741 | return 0; | |
740 | } | 742 | } | |
741 | 743 | |||
742 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | 744 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | |
743 | static void | 745 | static void | |
744 | udav_uno_stop(struct ifnet *ifp, int disable) | 746 | udav_uno_stop(struct ifnet *ifp, int disable) | |
745 | { | 747 | { | |
746 | struct usbnet * const un = ifp->if_softc; | 748 | struct usbnet * const un = ifp->if_softc; | |
747 | 749 | |||
748 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 750 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
749 | 751 | |||
750 | udav_reset(un); | 752 | udav_reset(un); | |
751 | } | 753 | } | |
752 | 754 | |||
753 | static int | 755 | static int | |
754 | udav_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 756 | udav_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
755 | { | 757 | { | |
756 | uint8_t data[2]; | 758 | uint8_t data[2]; | |
757 | 759 | |||
758 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | 760 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | |
759 | device_xname(un->un_dev), __func__, phy, reg)); | 761 | device_xname(un->un_dev), __func__, phy, reg)); | |
760 | 762 | |||
761 | if (usbnet_isdying(un)) { | 763 | if (usbnet_isdying(un)) { | |
762 | #ifdef DIAGNOSTIC | 764 | #ifdef DIAGNOSTIC | |
763 | printf("%s: %s: dying\n", device_xname(un->un_dev), | 765 | printf("%s: %s: dying\n", device_xname(un->un_dev), | |
764 | __func__); | 766 | __func__); | |
765 | #endif | 767 | #endif | |
766 | return EINVAL; | 768 | return EINVAL; | |
767 | } | 769 | } | |
768 | 770 | |||
769 | /* XXX: one PHY only for the internal PHY */ | 771 | /* XXX: one PHY only for the internal PHY */ | |
770 | if (phy != 0) { | 772 | if (phy != 0) { | |
771 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 773 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
772 | device_xname(un->un_dev), __func__, phy)); | 774 | device_xname(un->un_dev), __func__, phy)); | |
773 | return EINVAL; | 775 | return EINVAL; | |
774 | } | 776 | } | |
775 | 777 | |||
776 | /* select internal PHY and set PHY register address */ | 778 | /* select internal PHY and set PHY register address */ | |
777 | udav_csr_write1(un, UDAV_EPAR, | 779 | udav_csr_write1(un, UDAV_EPAR, | |
778 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | 780 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | |
779 | 781 | |||
780 | /* select PHY operation and start read command */ | 782 | /* select PHY operation and start read command */ | |
781 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR); | 783 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR); | |
782 | 784 | |||
783 | /* XXX: should be wait? */ | 785 | /* XXX: should be wait? */ | |
784 | 786 | |||
785 | /* end read command */ | 787 | /* end read command */ | |
786 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRR); | 788 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRR); | |
787 | 789 | |||
788 | /* retrieve the result from data registers */ | 790 | /* retrieve the result from data registers */ | |
789 | udav_csr_read(un, UDAV_EPDRL, data, 2); | 791 | udav_csr_read(un, UDAV_EPDRL, data, 2); | |
790 | 792 | |||
791 | *val = data[0] | (data[1] << 8); | 793 | *val = data[0] | (data[1] << 8); | |
792 | 794 | |||
793 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | 795 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | |
794 | device_xname(un->un_dev), __func__, phy, reg, *val)); | 796 | device_xname(un->un_dev), __func__, phy, reg, *val)); | |
795 | 797 | |||
796 | return 0; | 798 | return 0; | |
797 | } | 799 | } | |
798 | 800 | |||
799 | static int | 801 | static int | |
800 | udav_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 802 | udav_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
801 | { | 803 | { | |
802 | uint8_t data[2]; | 804 | uint8_t data[2]; | |
803 | 805 | |||
804 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | 806 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | |
805 | device_xname(un->un_dev), __func__, phy, reg, val)); | 807 | device_xname(un->un_dev), __func__, phy, reg, val)); | |
806 | 808 | |||
807 | if (usbnet_isdying(un)) { | 809 | if (usbnet_isdying(un)) { | |
808 | #ifdef DIAGNOSTIC | 810 | #ifdef DIAGNOSTIC | |
809 | printf("%s: %s: dying\n", device_xname(un->un_dev), | 811 | printf("%s: %s: dying\n", device_xname(un->un_dev), | |
810 | __func__); | 812 | __func__); | |
811 | #endif | 813 | #endif | |
812 | return EIO; | 814 | return EIO; | |
813 | } | 815 | } | |
814 | 816 | |||
815 | /* XXX: one PHY only for the internal PHY */ | 817 | /* XXX: one PHY only for the internal PHY */ | |
816 | if (phy != 0) { | 818 | if (phy != 0) { | |
817 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 819 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
818 | device_xname(un->un_dev), __func__, phy)); | 820 | device_xname(un->un_dev), __func__, phy)); | |
819 | return EIO; | 821 | return EIO; | |
820 | } | 822 | } | |
821 | 823 | |||
822 | /* select internal PHY and set PHY register address */ | 824 | /* select internal PHY and set PHY register address */ | |
823 | udav_csr_write1(un, UDAV_EPAR, | 825 | udav_csr_write1(un, UDAV_EPAR, | |
824 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | 826 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | |
825 | 827 | |||
826 | /* put the value to the data registers */ | 828 | /* put the value to the data registers */ | |
827 | data[0] = val & 0xff; | 829 | data[0] = val & 0xff; | |
828 | data[1] = (val >> 8) & 0xff; | 830 | data[1] = (val >> 8) & 0xff; | |
829 | udav_csr_write(un, UDAV_EPDRL, data, 2); | 831 | udav_csr_write(un, UDAV_EPDRL, data, 2); | |
830 | 832 | |||
831 | /* select PHY operation and start write command */ | 833 | /* select PHY operation and start write command */ | |
832 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW); | 834 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW); | |
833 | 835 | |||
834 | /* XXX: should be wait? */ | 836 | /* XXX: should be wait? */ | |
835 | 837 | |||
836 | /* end write command */ | 838 | /* end write command */ | |
837 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRW); | 839 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRW); | |
838 | 840 | |||
839 | return 0; | 841 | return 0; | |
840 | } | 842 | } | |
841 | 843 | |||
842 | static void | 844 | static void | |
843 | udav_uno_mii_statchg(struct ifnet *ifp) | 845 | udav_uno_mii_statchg(struct ifnet *ifp) | |
844 | { | 846 | { | |
845 | struct usbnet * const un = ifp->if_softc; | 847 | struct usbnet * const un = ifp->if_softc; | |
846 | struct mii_data * const mii = usbnet_mii(un); | 848 | struct mii_data * const mii = usbnet_mii(un); | |
847 | 849 | |||
848 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | 850 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | |
849 | 851 | |||
850 | if (usbnet_isdying(un)) | 852 | if (usbnet_isdying(un)) | |
851 | return; | 853 | return; | |
852 | 854 | |||
853 | if ((mii->mii_media_status & IFM_ACTIVE) && | 855 | if ((mii->mii_media_status & IFM_ACTIVE) && | |
854 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | 856 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | |
855 | DPRINTF(("%s: %s: got link\n", | 857 | DPRINTF(("%s: %s: got link\n", | |
856 | device_xname(un->un_dev), __func__)); | 858 | device_xname(un->un_dev), __func__)); | |
857 | usbnet_set_link(un, true); | 859 | usbnet_set_link(un, true); | |
858 | } | 860 | } | |
859 | } | 861 | } | |
860 | 862 | |||
861 | #ifdef _MODULE | 863 | #ifdef _MODULE | |
862 | #include "ioconf.c" | 864 | #include "ioconf.c" | |
863 | #endif | 865 | #endif | |
864 | 866 | |||
865 | USBNET_MODULE(udav) | 867 | USBNET_MODULE(udav) |
--- src/sys/dev/usb/if_url.c 2022/03/03 05:50:22 1.79
+++ src/sys/dev/usb/if_url.c 2022/03/03 05:50:57 1.80
@@ -1,774 +1,776 @@ | @@ -1,774 +1,776 @@ | |||
1 | /* $NetBSD: if_url.c,v 1.79 2022/03/03 05:50:22 riastradh Exp $ */ | 1 | /* $NetBSD: if_url.c,v 1.80 2022/03/03 05:50:57 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.79 2022/03/03 05:50:22 riastradh Exp $"); | 47 | __KERNEL_RCSID(0, "$NetBSD: if_url.c,v 1.80 2022/03/03 05:50:57 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 int url_uno_ioctl(struct ifnet *, u_long, void *); | 80 | static int url_uno_ioctl(struct ifnet *, u_long, void *); | |
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_ioctl = url_uno_ioctl, | 96 | .uno_ioctl = url_uno_ioctl, | |
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 | struct usbnet * const un = ifp->if_softc; | 409 | struct usbnet * const un = ifp->if_softc; | |
410 | 410 | |||
411 | usbnet_busy(un); | 411 | usbnet_busy(un); | |
412 | int ret = url_init_locked(ifp); | 412 | int ret = url_init_locked(ifp); | |
413 | usbnet_unbusy(un); | 413 | usbnet_unbusy(un); | |
414 | 414 | |||
415 | return ret; | 415 | return ret; | |
416 | } | 416 | } | |
417 | 417 | |||
418 | static void | 418 | static void | |
419 | url_reset(struct usbnet *un) | 419 | url_reset(struct usbnet *un) | |
420 | { | 420 | { | |
421 | int i; | 421 | int i; | |
422 | 422 | |||
423 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 423 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
424 | 424 | |||
425 | if (usbnet_isdying(un)) | 425 | if (usbnet_isdying(un)) | |
426 | return; | 426 | return; | |
427 | 427 | |||
428 | URL_SETBIT(un, URL_CR, URL_CR_SOFT_RST); | 428 | URL_SETBIT(un, URL_CR, URL_CR_SOFT_RST); | |
429 | 429 | |||
430 | for (i = 0; i < URL_TX_TIMEOUT; i++) { | 430 | for (i = 0; i < URL_TX_TIMEOUT; i++) { | |
431 | if (usbnet_isdying(un)) | |||
432 | return; | |||
431 | if (!(url_csr_read_1(un, URL_CR) & URL_CR_SOFT_RST)) | 433 | if (!(url_csr_read_1(un, URL_CR) & URL_CR_SOFT_RST)) | |
432 | break; | 434 | break; | |
433 | delay(10); /* XXX */ | 435 | delay(10); /* XXX */ | |
434 | } | 436 | } | |
435 | 437 | |||
436 | delay(10000); /* XXX */ | 438 | delay(10000); /* XXX */ | |
437 | } | 439 | } | |
438 | 440 | |||
439 | static void | 441 | static void | |
440 | url_rcvfilt_locked(struct usbnet *un) | 442 | url_rcvfilt_locked(struct usbnet *un) | |
441 | { | 443 | { | |
442 | struct ifnet * const ifp = usbnet_ifp(un); | 444 | struct ifnet * const ifp = usbnet_ifp(un); | |
443 | struct ethercom *ec = usbnet_ec(un); | 445 | struct ethercom *ec = usbnet_ec(un); | |
444 | struct ether_multi *enm; | 446 | struct ether_multi *enm; | |
445 | struct ether_multistep step; | 447 | struct ether_multistep step; | |
446 | uint32_t mchash[2] = { 0, 0 }; | 448 | uint32_t mchash[2] = { 0, 0 }; | |
447 | int h = 0, rcr; | 449 | int h = 0, rcr; | |
448 | 450 | |||
449 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 451 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
450 | 452 | |||
451 | usbnet_isowned_core(un); | 453 | usbnet_isowned_core(un); | |
452 | 454 | |||
453 | if (usbnet_isdying(un)) | 455 | if (usbnet_isdying(un)) | |
454 | return; | 456 | return; | |
455 | 457 | |||
456 | rcr = url_csr_read_2(un, URL_RCR); | 458 | rcr = url_csr_read_2(un, URL_RCR); | |
457 | rcr &= ~(URL_RCR_AAP | URL_RCR_AAM | URL_RCR_AM); | 459 | rcr &= ~(URL_RCR_AAP | URL_RCR_AAM | URL_RCR_AM); | |
458 | 460 | |||
459 | ETHER_LOCK(ec); | 461 | ETHER_LOCK(ec); | |
460 | if (ifp->if_flags & IFF_PROMISC) { | 462 | if (ifp->if_flags & IFF_PROMISC) { | |
461 | ec->ec_flags |= ETHER_F_ALLMULTI; | 463 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
462 | ETHER_UNLOCK(ec); | 464 | ETHER_UNLOCK(ec); | |
463 | /* run promisc. mode */ | 465 | /* run promisc. mode */ | |
464 | rcr |= URL_RCR_AAM; /* ??? */ | 466 | rcr |= URL_RCR_AAM; /* ??? */ | |
465 | rcr |= URL_RCR_AAP; | 467 | rcr |= URL_RCR_AAP; | |
466 | goto update; | 468 | goto update; | |
467 | } | 469 | } | |
468 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 470 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
469 | ETHER_FIRST_MULTI(step, ec, enm); | 471 | ETHER_FIRST_MULTI(step, ec, enm); | |
470 | while (enm != NULL) { | 472 | while (enm != NULL) { | |
471 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 473 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
472 | ec->ec_flags |= ETHER_F_ALLMULTI; | 474 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
473 | ETHER_UNLOCK(ec); | 475 | ETHER_UNLOCK(ec); | |
474 | /* accept all multicast frames */ | 476 | /* accept all multicast frames */ | |
475 | rcr |= URL_RCR_AAM; | 477 | rcr |= URL_RCR_AAM; | |
476 | goto update; | 478 | goto update; | |
477 | } | 479 | } | |
478 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | 480 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | |
479 | /* 1(31) and 5(30:26) bit sampling */ | 481 | /* 1(31) and 5(30:26) bit sampling */ | |
480 | mchash[h >> 31] |= 1 << ((h >> 26) & 0x1f); | 482 | mchash[h >> 31] |= 1 << ((h >> 26) & 0x1f); | |
481 | ETHER_NEXT_MULTI(step, enm); | 483 | ETHER_NEXT_MULTI(step, enm); | |
482 | } | 484 | } | |
483 | ETHER_UNLOCK(ec); | 485 | ETHER_UNLOCK(ec); | |
484 | if (h != 0) | 486 | if (h != 0) | |
485 | rcr |= URL_RCR_AM; /* activate mcast hash filter */ | 487 | rcr |= URL_RCR_AM; /* activate mcast hash filter */ | |
486 | url_csr_write_4(un, URL_MAR0, mchash[0]); | 488 | url_csr_write_4(un, URL_MAR0, mchash[0]); | |
487 | url_csr_write_4(un, URL_MAR4, mchash[1]); | 489 | url_csr_write_4(un, URL_MAR4, mchash[1]); | |
488 | update: | 490 | update: | |
489 | url_csr_write_2(un, URL_RCR, rcr); | 491 | url_csr_write_2(un, URL_RCR, rcr); | |
490 | } | 492 | } | |
491 | 493 | |||
492 | static unsigned | 494 | static unsigned | |
493 | url_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 495 | url_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
494 | { | 496 | { | |
495 | int total_len; | 497 | int total_len; | |
496 | 498 | |||
497 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | 499 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | |
498 | 500 | |||
499 | KASSERT(un->un_tx_bufsz >= URL_MIN_FRAME_LEN); | 501 | KASSERT(un->un_tx_bufsz >= URL_MIN_FRAME_LEN); | |
500 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | 502 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | |
501 | return 0; | 503 | return 0; | |
502 | 504 | |||
503 | /* Copy the mbuf data into a contiguous buffer */ | 505 | /* Copy the mbuf data into a contiguous buffer */ | |
504 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | 506 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | |
505 | total_len = m->m_pkthdr.len; | 507 | total_len = m->m_pkthdr.len; | |
506 | 508 | |||
507 | if (total_len < URL_MIN_FRAME_LEN) { | 509 | if (total_len < URL_MIN_FRAME_LEN) { | |
508 | memset(c->unc_buf + total_len, 0, | 510 | memset(c->unc_buf + total_len, 0, | |
509 | URL_MIN_FRAME_LEN - total_len); | 511 | URL_MIN_FRAME_LEN - total_len); | |
510 | total_len = URL_MIN_FRAME_LEN; | 512 | total_len = URL_MIN_FRAME_LEN; | |
511 | } | 513 | } | |
512 | 514 | |||
513 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | 515 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | |
514 | __func__, total_len)); | 516 | __func__, total_len)); | |
515 | 517 | |||
516 | return total_len; | 518 | return total_len; | |
517 | } | 519 | } | |
518 | 520 | |||
519 | static void | 521 | static void | |
520 | url_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 522 | url_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
521 | { | 523 | { | |
522 | struct ifnet *ifp = usbnet_ifp(un); | 524 | struct ifnet *ifp = usbnet_ifp(un); | |
523 | url_rxhdr_t rxhdr; | 525 | url_rxhdr_t rxhdr; | |
524 | 526 | |||
525 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | 527 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | |
526 | 528 | |||
527 | if (total_len <= ETHER_CRC_LEN || total_len <= sizeof(rxhdr)) { | 529 | if (total_len <= ETHER_CRC_LEN || total_len <= sizeof(rxhdr)) { | |
528 | if_statinc(ifp, if_ierrors); | 530 | if_statinc(ifp, if_ierrors); | |
529 | return; | 531 | return; | |
530 | } | 532 | } | |
531 | 533 | |||
532 | memcpy(&rxhdr, c->unc_buf + total_len - ETHER_CRC_LEN, sizeof(rxhdr)); | 534 | memcpy(&rxhdr, c->unc_buf + total_len - ETHER_CRC_LEN, sizeof(rxhdr)); | |
533 | 535 | |||
534 | DPRINTF(("%s: RX Status: %dbytes%s%s%s%s packets\n", | 536 | DPRINTF(("%s: RX Status: %dbytes%s%s%s%s packets\n", | |
535 | device_xname(un->un_dev), | 537 | device_xname(un->un_dev), | |
536 | UGETW(rxhdr) & URL_RXHDR_BYTEC_MASK, | 538 | UGETW(rxhdr) & URL_RXHDR_BYTEC_MASK, | |
537 | UGETW(rxhdr) & URL_RXHDR_VALID_MASK ? ", Valid" : "", | 539 | UGETW(rxhdr) & URL_RXHDR_VALID_MASK ? ", Valid" : "", | |
538 | UGETW(rxhdr) & URL_RXHDR_RUNTPKT_MASK ? ", Runt" : "", | 540 | UGETW(rxhdr) & URL_RXHDR_RUNTPKT_MASK ? ", Runt" : "", | |
539 | UGETW(rxhdr) & URL_RXHDR_PHYPKT_MASK ? ", Physical match" : "", | 541 | UGETW(rxhdr) & URL_RXHDR_PHYPKT_MASK ? ", Physical match" : "", | |
540 | UGETW(rxhdr) & URL_RXHDR_MCASTPKT_MASK ? ", Multicast" : "")); | 542 | UGETW(rxhdr) & URL_RXHDR_MCASTPKT_MASK ? ", Multicast" : "")); | |
541 | 543 | |||
542 | if ((UGETW(rxhdr) & URL_RXHDR_VALID_MASK) == 0) { | 544 | if ((UGETW(rxhdr) & URL_RXHDR_VALID_MASK) == 0) { | |
543 | if_statinc(ifp, if_ierrors); | 545 | if_statinc(ifp, if_ierrors); | |
544 | return; | 546 | return; | |
545 | } | 547 | } | |
546 | 548 | |||
547 | total_len -= ETHER_CRC_LEN; | 549 | total_len -= ETHER_CRC_LEN; | |
548 | 550 | |||
549 | DPRINTF(("%s: %s: deliver %d\n", device_xname(un->un_dev), | 551 | DPRINTF(("%s: %s: deliver %d\n", device_xname(un->un_dev), | |
550 | __func__, total_len)); | 552 | __func__, total_len)); | |
551 | usbnet_enqueue(un, c->unc_buf, total_len, 0, 0, 0); | 553 | usbnet_enqueue(un, c->unc_buf, total_len, 0, 0, 0); | |
552 | } | 554 | } | |
553 | 555 | |||
554 | #if 0 | 556 | #if 0 | |
555 | static void url_intr(void) | 557 | static void url_intr(void) | |
556 | { | 558 | { | |
557 | } | 559 | } | |
558 | #endif | 560 | #endif | |
559 | 561 | |||
560 | static int | 562 | static int | |
561 | url_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 563 | url_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
562 | { | 564 | { | |
563 | struct usbnet * const un = ifp->if_softc; | 565 | struct usbnet * const un = ifp->if_softc; | |
564 | 566 | |||
565 | usbnet_lock_core(un); | 567 | usbnet_lock_core(un); | |
566 | usbnet_busy(un); | 568 | usbnet_busy(un); | |
567 | 569 | |||
568 | switch (cmd) { | 570 | switch (cmd) { | |
569 | case SIOCADDMULTI: | 571 | case SIOCADDMULTI: | |
570 | case SIOCDELMULTI: | 572 | case SIOCDELMULTI: | |
571 | url_rcvfilt_locked(un); | 573 | url_rcvfilt_locked(un); | |
572 | break; | 574 | break; | |
573 | default: | 575 | default: | |
574 | break; | 576 | break; | |
575 | } | 577 | } | |
576 | 578 | |||
577 | usbnet_unbusy(un); | 579 | usbnet_unbusy(un); | |
578 | usbnet_unlock_core(un); | 580 | usbnet_unlock_core(un); | |
579 | 581 | |||
580 | return 0; | 582 | return 0; | |
581 | } | 583 | } | |
582 | 584 | |||
583 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | 585 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | |
584 | static void | 586 | static void | |
585 | url_uno_stop(struct ifnet *ifp, int disable) | 587 | url_uno_stop(struct ifnet *ifp, int disable) | |
586 | { | 588 | { | |
587 | struct usbnet * const un = ifp->if_softc; | 589 | struct usbnet * const un = ifp->if_softc; | |
588 | 590 | |||
589 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 591 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
590 | 592 | |||
591 | url_reset(un); | 593 | url_reset(un); | |
592 | } | 594 | } | |
593 | 595 | |||
594 | static int | 596 | static int | |
595 | url_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 597 | url_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
596 | { | 598 | { | |
597 | uint16_t data; | 599 | uint16_t data; | |
598 | usbd_status err = USBD_NORMAL_COMPLETION; | 600 | usbd_status err = USBD_NORMAL_COMPLETION; | |
599 | 601 | |||
600 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | 602 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | |
601 | device_xname(un->un_dev), __func__, phy, reg)); | 603 | device_xname(un->un_dev), __func__, phy, reg)); | |
602 | 604 | |||
603 | /* XXX: one PHY only for the RTL8150 internal PHY */ | 605 | /* XXX: one PHY only for the RTL8150 internal PHY */ | |
604 | if (phy != 0) { | 606 | if (phy != 0) { | |
605 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 607 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
606 | device_xname(un->un_dev), __func__, phy)); | 608 | device_xname(un->un_dev), __func__, phy)); | |
607 | return EINVAL; | 609 | return EINVAL; | |
608 | } | 610 | } | |
609 | 611 | |||
610 | switch (reg) { | 612 | switch (reg) { | |
611 | case MII_BMCR: /* Control Register */ | 613 | case MII_BMCR: /* Control Register */ | |
612 | reg = URL_BMCR; | 614 | reg = URL_BMCR; | |
613 | break; | 615 | break; | |
614 | case MII_BMSR: /* Status Register */ | 616 | case MII_BMSR: /* Status Register */ | |
615 | reg = URL_BMSR; | 617 | reg = URL_BMSR; | |
616 | break; | 618 | break; | |
617 | case MII_PHYIDR1: | 619 | case MII_PHYIDR1: | |
618 | case MII_PHYIDR2: | 620 | case MII_PHYIDR2: | |
619 | *val = 0; | 621 | *val = 0; | |
620 | goto R_DONE; | 622 | goto R_DONE; | |
621 | break; | 623 | break; | |
622 | case MII_ANAR: /* Autonegotiation advertisement */ | 624 | case MII_ANAR: /* Autonegotiation advertisement */ | |
623 | reg = URL_ANAR; | 625 | reg = URL_ANAR; | |
624 | break; | 626 | break; | |
625 | case MII_ANLPAR: /* Autonegotiation link partner abilities */ | 627 | case MII_ANLPAR: /* Autonegotiation link partner abilities */ | |
626 | reg = URL_ANLP; | 628 | reg = URL_ANLP; | |
627 | break; | 629 | break; | |
628 | case URLPHY_MSR: /* Media Status Register */ | 630 | case URLPHY_MSR: /* Media Status Register */ | |
629 | reg = URL_MSR; | 631 | reg = URL_MSR; | |
630 | break; | 632 | break; | |
631 | default: | 633 | default: | |
632 | printf("%s: %s: bad register %04x\n", | 634 | printf("%s: %s: bad register %04x\n", | |
633 | device_xname(un->un_dev), __func__, reg); | 635 | device_xname(un->un_dev), __func__, reg); | |
634 | return EINVAL; | 636 | return EINVAL; | |
635 | } | 637 | } | |
636 | 638 | |||
637 | if (reg == URL_MSR) | 639 | if (reg == URL_MSR) | |
638 | data = url_csr_read_1(un, reg); | 640 | data = url_csr_read_1(un, reg); | |
639 | else | 641 | else | |
640 | data = url_csr_read_2(un, reg); | 642 | data = url_csr_read_2(un, reg); | |
641 | *val = data; | 643 | *val = data; | |
642 | 644 | |||
643 | R_DONE: | 645 | R_DONE: | |
644 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | 646 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | |
645 | device_xname(un->un_dev), __func__, phy, reg, *val)); | 647 | device_xname(un->un_dev), __func__, phy, reg, *val)); | |
646 | 648 | |||
647 | return err; | 649 | return err; | |
648 | } | 650 | } | |
649 | 651 | |||
650 | static int | 652 | static int | |
651 | url_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 653 | url_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
652 | { | 654 | { | |
653 | 655 | |||
654 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | 656 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | |
655 | device_xname(un->un_dev), __func__, phy, reg, val)); | 657 | device_xname(un->un_dev), __func__, phy, reg, val)); | |
656 | 658 | |||
657 | /* XXX: one PHY only for the RTL8150 internal PHY */ | 659 | /* XXX: one PHY only for the RTL8150 internal PHY */ | |
658 | if (phy != 0) { | 660 | if (phy != 0) { | |
659 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 661 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
660 | device_xname(un->un_dev), __func__, phy)); | 662 | device_xname(un->un_dev), __func__, phy)); | |
661 | return EINVAL; | 663 | return EINVAL; | |
662 | } | 664 | } | |
663 | 665 | |||
664 | switch (reg) { | 666 | switch (reg) { | |
665 | case MII_BMCR: /* Control Register */ | 667 | case MII_BMCR: /* Control Register */ | |
666 | reg = URL_BMCR; | 668 | reg = URL_BMCR; | |
667 | break; | 669 | break; | |
668 | case MII_BMSR: /* Status Register */ | 670 | case MII_BMSR: /* Status Register */ | |
669 | reg = URL_BMSR; | 671 | reg = URL_BMSR; | |
670 | break; | 672 | break; | |
671 | case MII_PHYIDR1: | 673 | case MII_PHYIDR1: | |
672 | case MII_PHYIDR2: | 674 | case MII_PHYIDR2: | |
673 | return 0; | 675 | return 0; | |
674 | case MII_ANAR: /* Autonegotiation advertisement */ | 676 | case MII_ANAR: /* Autonegotiation advertisement */ | |
675 | reg = URL_ANAR; | 677 | reg = URL_ANAR; | |
676 | break; | 678 | break; | |
677 | case MII_ANLPAR: /* Autonegotiation link partner abilities */ | 679 | case MII_ANLPAR: /* Autonegotiation link partner abilities */ | |
678 | reg = URL_ANLP; | 680 | reg = URL_ANLP; | |
679 | break; | 681 | break; | |
680 | case URLPHY_MSR: /* Media Status Register */ | 682 | case URLPHY_MSR: /* Media Status Register */ | |
681 | reg = URL_MSR; | 683 | reg = URL_MSR; | |
682 | break; | 684 | break; | |
683 | default: | 685 | default: | |
684 | printf("%s: %s: bad register %04x\n", | 686 | printf("%s: %s: bad register %04x\n", | |
685 | device_xname(un->un_dev), __func__, reg); | 687 | device_xname(un->un_dev), __func__, reg); | |
686 | return EINVAL; | 688 | return EINVAL; | |
687 | } | 689 | } | |
688 | 690 | |||
689 | if (reg == URL_MSR) | 691 | if (reg == URL_MSR) | |
690 | url_csr_write_1(un, reg, val); | 692 | url_csr_write_1(un, reg, val); | |
691 | else | 693 | else | |
692 | url_csr_write_2(un, reg, val); | 694 | url_csr_write_2(un, reg, val); | |
693 | 695 | |||
694 | return 0; | 696 | return 0; | |
695 | } | 697 | } | |
696 | 698 | |||
697 | static void | 699 | static void | |
698 | url_uno_mii_statchg(struct ifnet *ifp) | 700 | url_uno_mii_statchg(struct ifnet *ifp) | |
699 | { | 701 | { | |
700 | struct usbnet * const un = ifp->if_softc; | 702 | struct usbnet * const un = ifp->if_softc; | |
701 | 703 | |||
702 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | 704 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | |
703 | 705 | |||
704 | /* XXX */ | 706 | /* XXX */ | |
705 | usbnet_set_link(un, true); | 707 | usbnet_set_link(un, true); | |
706 | } | 708 | } | |
707 | 709 | |||
708 | #if 0 | 710 | #if 0 | |
709 | /* | 711 | /* | |
710 | * external PHYs support, but not test. | 712 | * external PHYs support, but not test. | |
711 | */ | 713 | */ | |
712 | static usbd_status | 714 | static usbd_status | |
713 | url_ext_mii_read_reg(struct usbnet *un, int phy, int reg) | 715 | url_ext_mii_read_reg(struct usbnet *un, int phy, int reg) | |
714 | { | 716 | { | |
715 | uint16_t val; | 717 | uint16_t val; | |
716 | 718 | |||
717 | DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x\n", | 719 | DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x\n", | |
718 | device_xname(un->un_dev), __func__, phy, reg)); | 720 | device_xname(un->un_dev), __func__, phy, reg)); | |
719 | 721 | |||
720 | url_csr_write_1(un, URL_PHYADD, phy & URL_PHYADD_MASK); | 722 | url_csr_write_1(un, URL_PHYADD, phy & URL_PHYADD_MASK); | |
721 | /* | 723 | /* | |
722 | * RTL8150L will initiate a MII management data transaction | 724 | * RTL8150L will initiate a MII management data transaction | |
723 | * if PHYCNT_OWN bit is set 1 by software. After transaction, | 725 | * if PHYCNT_OWN bit is set 1 by software. After transaction, | |
724 | * this bit is auto cleared by TRL8150L. | 726 | * this bit is auto cleared by TRL8150L. | |
725 | */ | 727 | */ | |
726 | url_csr_write_1(un, URL_PHYCNT, | 728 | url_csr_write_1(un, URL_PHYCNT, | |
727 | (reg | URL_PHYCNT_PHYOWN) & ~URL_PHYCNT_RWCR); | 729 | (reg | URL_PHYCNT_PHYOWN) & ~URL_PHYCNT_RWCR); | |
728 | for (i = 0; i < URL_TIMEOUT; i++) { | 730 | for (i = 0; i < URL_TIMEOUT; i++) { | |
729 | if ((url_csr_read_1(un, URL_PHYCNT) & URL_PHYCNT_PHYOWN) == 0) | 731 | if ((url_csr_read_1(un, URL_PHYCNT) & URL_PHYCNT_PHYOWN) == 0) | |
730 | break; | 732 | break; | |
731 | } | 733 | } | |
732 | if (i == URL_TIMEOUT) { | 734 | if (i == URL_TIMEOUT) { | |
733 | printf("%s: MII read timed out\n", device_xname(un->un_dev)); | 735 | printf("%s: MII read timed out\n", device_xname(un->un_dev)); | |
734 | } | 736 | } | |
735 | 737 | |||
736 | val = url_csr_read_2(un, URL_PHYDAT); | 738 | val = url_csr_read_2(un, URL_PHYDAT); | |
737 | 739 | |||
738 | DPRINTF(("%s: %s: phy=%d reg=0x%04x => 0x%04x\n", | 740 | DPRINTF(("%s: %s: phy=%d reg=0x%04x => 0x%04x\n", | |
739 | device_xname(un->un_dev), __func__, phy, reg, val)); | 741 | device_xname(un->un_dev), __func__, phy, reg, val)); | |
740 | 742 | |||
741 | return USBD_NORMAL_COMPLETION; | 743 | return USBD_NORMAL_COMPLETION; | |
742 | } | 744 | } | |
743 | 745 | |||
744 | static usbd_status | 746 | static usbd_status | |
745 | url_ext_mii_write_reg(struct usbnet *un, int phy, int reg, int data) | 747 | url_ext_mii_write_reg(struct usbnet *un, int phy, int reg, int data) | |
746 | { | 748 | { | |
747 | 749 | |||
748 | DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n", | 750 | DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n", | |
749 | device_xname(un->un_dev), __func__, phy, reg, data)); | 751 | device_xname(un->un_dev), __func__, phy, reg, data)); | |
750 | 752 | |||
751 | url_csr_write_2(un, URL_PHYDAT, data); | 753 | url_csr_write_2(un, URL_PHYDAT, data); | |
752 | url_csr_write_1(un, URL_PHYADD, phy); | 754 | url_csr_write_1(un, URL_PHYADD, phy); | |
753 | url_csr_write_1(un, URL_PHYCNT, reg | URL_PHYCNT_RWCR); /* Write */ | 755 | url_csr_write_1(un, URL_PHYCNT, reg | URL_PHYCNT_RWCR); /* Write */ | |
754 | 756 | |||
755 | for (i=0; i < URL_TIMEOUT; i++) { | 757 | for (i=0; i < URL_TIMEOUT; i++) { | |
756 | if (url_csr_read_1(un, URL_PHYCNT) & URL_PHYCNT_PHYOWN) | 758 | if (url_csr_read_1(un, URL_PHYCNT) & URL_PHYCNT_PHYOWN) | |
757 | break; | 759 | break; | |
758 | } | 760 | } | |
759 | 761 | |||
760 | if (i == URL_TIMEOUT) { | 762 | if (i == URL_TIMEOUT) { | |
761 | printf("%s: MII write timed out\n", | 763 | printf("%s: MII write timed out\n", | |
762 | device_xname(un->un_dev)); | 764 | device_xname(un->un_dev)); | |
763 | return USBD_TIMEOUT; | 765 | return USBD_TIMEOUT; | |
764 | } | 766 | } | |
765 | 767 | |||
766 | return USBD_NORMAL_COMPLETION; | 768 | return USBD_NORMAL_COMPLETION; | |
767 | } | 769 | } | |
768 | #endif | 770 | #endif | |
769 | 771 | |||
770 | #ifdef _MODULE | 772 | #ifdef _MODULE | |
771 | #include "ioconf.c" | 773 | #include "ioconf.c" | |
772 | #endif | 774 | #endif | |
773 | 775 | |||
774 | USBNET_MODULE(url) | 776 | USBNET_MODULE(url) |
--- src/sys/dev/usb/if_ure.c 2022/03/03 05:50:22 1.41
+++ src/sys/dev/usb/if_ure.c 2022/03/03 05:50:57 1.42
@@ -1,1163 +1,1173 @@ | @@ -1,1163 +1,1173 @@ | |||
1 | /* $NetBSD: if_ure.c,v 1.41 2022/03/03 05:50:22 riastradh Exp $ */ | 1 | /* $NetBSD: if_ure.c,v 1.42 2022/03/03 05:50:57 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.41 2022/03/03 05:50:22 riastradh Exp $"); | 33 | __KERNEL_RCSID(0, "$NetBSD: if_ure.c,v 1.42 2022/03/03 05:50:57 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 int ure_uno_ioctl(struct ifnet *, u_long, void *); | 89 | static int ure_uno_ioctl(struct ifnet *, u_long, void *); | |
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_ioctl = ure_uno_ioctl, | 107 | .uno_ioctl = ure_uno_ioctl, | |
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)) | |||
400 | return; | |||
399 | 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) & | |
400 | URE_CR_RST)) | 402 | URE_CR_RST)) | |
401 | break; | 403 | break; | |
402 | usbd_delay_ms(un->un_udev, 10); | 404 | usbd_delay_ms(un->un_udev, 10); | |
403 | } | 405 | } | |
404 | if (i == URE_TIMEOUT) | 406 | if (i == URE_TIMEOUT) | |
405 | URE_PRINTF(un, "reset never completed\n"); | 407 | URE_PRINTF(un, "reset never completed\n"); | |
406 | } | 408 | } | |
407 | 409 | |||
408 | static int | 410 | static int | |
409 | ure_init_locked(struct ifnet *ifp) | 411 | ure_init_locked(struct ifnet *ifp) | |
410 | { | 412 | { | |
411 | struct usbnet * const un = ifp->if_softc; | 413 | struct usbnet * const un = ifp->if_softc; | |
412 | uint8_t eaddr[8]; | 414 | uint8_t eaddr[8]; | |
413 | 415 | |||
414 | usbnet_isowned_core(un); | 416 | usbnet_isowned_core(un); | |
415 | 417 | |||
416 | if (usbnet_isdying(un)) | 418 | if (usbnet_isdying(un)) | |
417 | return EIO; | 419 | return EIO; | |
418 | 420 | |||
419 | /* Cancel pending I/O. */ | 421 | /* Cancel pending I/O. */ | |
420 | if (ifp->if_flags & IFF_RUNNING) | 422 | if (ifp->if_flags & IFF_RUNNING) | |
421 | usbnet_stop(un, ifp, 1); | 423 | usbnet_stop(un, ifp, 1); | |
422 | 424 | |||
423 | /* Set MAC address. */ | 425 | /* Set MAC address. */ | |
424 | memset(eaddr, 0, sizeof(eaddr)); | 426 | memset(eaddr, 0, sizeof(eaddr)); | |
425 | memcpy(eaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); | 427 | memcpy(eaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); | |
426 | 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); | |
427 | 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, | |
428 | eaddr, 8); | 430 | eaddr, 8); | |
429 | 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); | |
430 | 432 | |||
431 | /* Reset the packet filter. */ | 433 | /* Reset the packet filter. */ | |
432 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | 434 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | |
433 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) & | 435 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) & | |
434 | ~URE_FMC_FCR_MCU_EN); | 436 | ~URE_FMC_FCR_MCU_EN); | |
435 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | 437 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | |
436 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) | | 438 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) | | |
437 | URE_FMC_FCR_MCU_EN); | 439 | URE_FMC_FCR_MCU_EN); | |
438 | 440 | |||
439 | /* Enable transmit and receive. */ | 441 | /* Enable transmit and receive. */ | |
440 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, | 442 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, | |
441 | 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 | | |
442 | URE_CR_TE); | 444 | URE_CR_TE); | |
443 | 445 | |||
444 | 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, | |
445 | 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) & | |
446 | ~URE_RXDY_GATED_EN); | 448 | ~URE_RXDY_GATED_EN); | |
447 | 449 | |||
448 | /* Accept multicast frame or run promisc. mode. */ | 450 | /* Accept multicast frame or run promisc. mode. */ | |
449 | ure_rcvfilt_locked(un); | 451 | ure_rcvfilt_locked(un); | |
450 | 452 | |||
451 | return usbnet_init_rx_tx(un); | 453 | return usbnet_init_rx_tx(un); | |
452 | } | 454 | } | |
453 | 455 | |||
454 | static int | 456 | static int | |
455 | ure_uno_init(struct ifnet *ifp) | 457 | ure_uno_init(struct ifnet *ifp) | |
456 | { | 458 | { | |
457 | struct usbnet * const un = ifp->if_softc; | 459 | struct usbnet * const un = ifp->if_softc; | |
458 | 460 | |||
459 | usbnet_busy(un); | 461 | usbnet_busy(un); | |
460 | int ret = ure_init_locked(ifp); | 462 | int ret = ure_init_locked(ifp); | |
461 | usbnet_unbusy(un); | 463 | usbnet_unbusy(un); | |
462 | 464 | |||
463 | return ret; | 465 | return ret; | |
464 | } | 466 | } | |
465 | 467 | |||
466 | static void | 468 | static void | |
467 | ure_uno_stop(struct ifnet *ifp, int disable __unused) | 469 | ure_uno_stop(struct ifnet *ifp, int disable __unused) | |
468 | { | 470 | { | |
469 | struct usbnet * const un = ifp->if_softc; | 471 | struct usbnet * const un = ifp->if_softc; | |
470 | 472 | |||
471 | ure_reset(un); | 473 | ure_reset(un); | |
472 | } | 474 | } | |
473 | 475 | |||
474 | static void | 476 | static void | |
475 | ure_rtl8152_init(struct usbnet *un) | 477 | ure_rtl8152_init(struct usbnet *un) | |
476 | { | 478 | { | |
477 | uint32_t pwrctrl; | 479 | uint32_t pwrctrl; | |
478 | 480 | |||
479 | /* Disable ALDPS. */ | 481 | /* Disable ALDPS. */ | |
480 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | 482 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | |
481 | URE_DIS_SDSAVE); | 483 | URE_DIS_SDSAVE); | |
482 | usbd_delay_ms(un->un_udev, 20); | 484 | usbd_delay_ms(un->un_udev, 20); | |
483 | 485 | |||
484 | if (un->un_flags & URE_FLAG_VER_4C00) { | 486 | if (un->un_flags & URE_FLAG_VER_4C00) { | |
485 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | 487 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | |
486 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | 488 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | |
487 | ~URE_LED_MODE_MASK); | 489 | ~URE_LED_MODE_MASK); | |
488 | } | 490 | } | |
489 | 491 | |||
490 | ure_write_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB, | 492 | ure_write_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB, | |
491 | ure_read_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) & | 493 | ure_read_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) & | |
492 | ~URE_POWER_CUT); | 494 | ~URE_POWER_CUT); | |
493 | ure_write_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB, | 495 | ure_write_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB, | |
494 | ure_read_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) & | 496 | ure_read_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) & | |
495 | ~URE_RESUME_INDICATE); | 497 | ~URE_RESUME_INDICATE); | |
496 | 498 | |||
497 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | 499 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | |
498 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | 500 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | |
499 | URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH); | 501 | URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH); | |
500 | pwrctrl = ure_read_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA); | 502 | pwrctrl = ure_read_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA); | |
501 | pwrctrl &= ~URE_MCU_CLK_RATIO_MASK; | 503 | pwrctrl &= ~URE_MCU_CLK_RATIO_MASK; | |
502 | pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN; | 504 | pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN; | |
503 | ure_write_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl); | 505 | ure_write_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl); | |
504 | ure_write_2(un, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA, | 506 | ure_write_2(un, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA, | |
505 | URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK | | 507 | URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK | | |
506 | URE_SPDWN_LINKCHG_MSK); | 508 | URE_SPDWN_LINKCHG_MSK); | |
507 | 509 | |||
508 | /* Enable Rx aggregation. */ | 510 | /* Enable Rx aggregation. */ | |
509 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | 511 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | |
510 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | 512 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | |
511 | ~URE_RX_AGG_DISABLE); | 513 | ~URE_RX_AGG_DISABLE); | |
512 | 514 | |||
513 | /* Disable ALDPS. */ | 515 | /* Disable ALDPS. */ | |
514 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | 516 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | |
515 | URE_DIS_SDSAVE); | 517 | URE_DIS_SDSAVE); | |
516 | usbd_delay_ms(un->un_udev, 20); | 518 | usbd_delay_ms(un->un_udev, 20); | |
517 | 519 | |||
518 | ure_init_fifo(un); | 520 | ure_init_fifo(un); | |
519 | 521 | |||
520 | ure_write_1(un, URE_USB_TX_AGG, URE_MCU_TYPE_USB, | 522 | ure_write_1(un, URE_USB_TX_AGG, URE_MCU_TYPE_USB, | |
521 | URE_TX_AGG_MAX_THRESHOLD); | 523 | URE_TX_AGG_MAX_THRESHOLD); | |
522 | ure_write_4(un, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH); | 524 | ure_write_4(un, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH); | |
523 | ure_write_4(un, URE_USB_TX_DMA, URE_MCU_TYPE_USB, | 525 | ure_write_4(un, URE_USB_TX_DMA, URE_MCU_TYPE_USB, | |
524 | URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1); | 526 | URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1); | |
525 | } | 527 | } | |
526 | 528 | |||
527 | static void | 529 | static void | |
528 | ure_rtl8153_init(struct usbnet *un) | 530 | ure_rtl8153_init(struct usbnet *un) | |
529 | { | 531 | { | |
530 | uint16_t val; | 532 | uint16_t val; | |
531 | uint8_t u1u2[8]; | 533 | uint8_t u1u2[8]; | |
532 | int i; | 534 | int i; | |
533 | 535 | |||
534 | /* Disable ALDPS. */ | 536 | /* Disable ALDPS. */ | |
535 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 537 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
536 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | 538 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | |
537 | usbd_delay_ms(un->un_udev, 20); | 539 | usbd_delay_ms(un->un_udev, 20); | |
538 | 540 | |||
539 | memset(u1u2, 0x00, sizeof(u1u2)); | 541 | memset(u1u2, 0x00, sizeof(u1u2)); | |
540 | ure_write_mem(un, URE_USB_TOLERANCE, | 542 | ure_write_mem(un, URE_USB_TOLERANCE, | |
541 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 543 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
542 | 544 | |||
543 | for (i = 0; i < URE_TIMEOUT; i++) { | 545 | for (i = 0; i < URE_TIMEOUT; i++) { | |
546 | if (usbnet_isdying(un)) | |||
547 | return; | |||
544 | if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & | 548 | if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & | |
545 | URE_AUTOLOAD_DONE) | 549 | URE_AUTOLOAD_DONE) | |
546 | break; | 550 | break; | |
547 | usbd_delay_ms(un->un_udev, 10); | 551 | usbd_delay_ms(un->un_udev, 10); | |
548 | } | 552 | } | |
549 | if (i == URE_TIMEOUT) | 553 | if (i == URE_TIMEOUT) | |
550 | URE_PRINTF(un, "timeout waiting for chip autoload\n"); | 554 | URE_PRINTF(un, "timeout waiting for chip autoload\n"); | |
551 | 555 | |||
552 | for (i = 0; i < URE_TIMEOUT; i++) { | 556 | for (i = 0; i < URE_TIMEOUT; i++) { | |
557 | if (usbnet_isdying(un)) | |||
558 | return; | |||
553 | val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) & | 559 | val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) & | |
554 | URE_PHY_STAT_MASK; | 560 | URE_PHY_STAT_MASK; | |
555 | if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN) | 561 | if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN) | |
556 | break; | 562 | break; | |
557 | usbd_delay_ms(un->un_udev, 10); | 563 | usbd_delay_ms(un->un_udev, 10); | |
558 | } | 564 | } | |
559 | if (i == URE_TIMEOUT) | 565 | if (i == URE_TIMEOUT) | |
560 | URE_PRINTF(un, "timeout waiting for phy to stabilize\n"); | 566 | URE_PRINTF(un, "timeout waiting for phy to stabilize\n"); | |
561 | 567 | |||
562 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, | 568 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, | |
563 | ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB) & | 569 | ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB) & | |
564 | ~URE_U2P3_ENABLE); | 570 | ~URE_U2P3_ENABLE); | |
565 | 571 | |||
566 | if (un->un_flags & URE_FLAG_VER_5C10) { | 572 | if (un->un_flags & URE_FLAG_VER_5C10) { | |
567 | val = ure_read_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB); | 573 | val = ure_read_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB); | |
568 | val &= ~URE_PWD_DN_SCALE_MASK; | 574 | val &= ~URE_PWD_DN_SCALE_MASK; | |
569 | val |= URE_PWD_DN_SCALE(96); | 575 | val |= URE_PWD_DN_SCALE(96); | |
570 | ure_write_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, val); | 576 | ure_write_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, val); | |
571 | 577 | |||
572 | ure_write_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB, | 578 | ure_write_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB, | |
573 | ure_read_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB) | | 579 | ure_read_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB) | | |
574 | URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND); | 580 | URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND); | |
575 | } else if (un->un_flags & URE_FLAG_VER_5C20) { | 581 | } else if (un->un_flags & URE_FLAG_VER_5C20) { | |
576 | ure_write_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA, | 582 | ure_write_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA, | |
577 | ure_read_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA) & | 583 | ure_read_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA) & | |
578 | ~URE_ECM_ALDPS); | 584 | ~URE_ECM_ALDPS); | |
579 | } | 585 | } | |
580 | if (un->un_flags & (URE_FLAG_VER_5C20 | URE_FLAG_VER_5C30)) { | 586 | if (un->un_flags & (URE_FLAG_VER_5C20 | URE_FLAG_VER_5C30)) { | |
581 | val = ure_read_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB); | 587 | val = ure_read_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB); | |
582 | if (ure_read_2(un, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB) == | 588 | if (ure_read_2(un, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB) == | |
583 | 0) | 589 | 0) | |
584 | val &= ~URE_DYNAMIC_BURST; | 590 | val &= ~URE_DYNAMIC_BURST; | |
585 | else | 591 | else | |
586 | val |= URE_DYNAMIC_BURST; | 592 | val |= URE_DYNAMIC_BURST; | |
587 | ure_write_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB, val); | 593 | ure_write_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB, val); | |
588 | } | 594 | } | |
589 | 595 | |||
590 | ure_write_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB, | 596 | ure_write_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB, | |
591 | ure_read_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB) | | 597 | ure_read_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB) | | |
592 | URE_EP4_FULL_FC); | 598 | URE_EP4_FULL_FC); | |
593 | 599 | |||
594 | ure_write_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB, | 600 | ure_write_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB, | |
595 | ure_read_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB) & | 601 | ure_read_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB) & | |
596 | ~URE_TIMER11_EN); | 602 | ~URE_TIMER11_EN); | |
597 | 603 | |||
598 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | 604 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | |
599 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | 605 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | |
600 | ~URE_LED_MODE_MASK); | 606 | ~URE_LED_MODE_MASK); | |
601 | 607 | |||
602 | if ((un->un_flags & URE_FLAG_VER_5C10) && | 608 | if ((un->un_flags & URE_FLAG_VER_5C10) && | |
603 | un->un_udev->ud_speed != USB_SPEED_SUPER) | 609 | un->un_udev->ud_speed != USB_SPEED_SUPER) | |
604 | val = URE_LPM_TIMER_500MS; | 610 | val = URE_LPM_TIMER_500MS; | |
605 | else | 611 | else | |
606 | val = URE_LPM_TIMER_500US; | 612 | val = URE_LPM_TIMER_500US; | |
607 | ure_write_1(un, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB, | 613 | ure_write_1(un, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB, | |
608 | val | URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM); | 614 | val | URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM); | |
609 | 615 | |||
610 | val = ure_read_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB); | 616 | val = ure_read_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB); | |
611 | val &= ~URE_SEN_VAL_MASK; | 617 | val &= ~URE_SEN_VAL_MASK; | |
612 | val |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE; | 618 | val |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE; | |
613 | ure_write_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, val); | 619 | ure_write_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, val); | |
614 | 620 | |||
615 | ure_write_2(un, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001); | 621 | ure_write_2(un, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001); | |
616 | 622 | |||
617 | ure_write_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, | 623 | ure_write_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, | |
618 | ure_read_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB) & | 624 | ure_read_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB) & | |
619 | ~(URE_PWR_EN | URE_PHASE2_EN)); | 625 | ~(URE_PWR_EN | URE_PHASE2_EN)); | |
620 | ure_write_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB, | 626 | ure_write_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB, | |
621 | ure_read_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB) & | 627 | ure_read_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB) & | |
622 | ~URE_PCUT_STATUS); | 628 | ~URE_PCUT_STATUS); | |
623 | 629 | |||
624 | memset(u1u2, 0xff, sizeof(u1u2)); | 630 | memset(u1u2, 0xff, sizeof(u1u2)); | |
625 | ure_write_mem(un, URE_USB_TOLERANCE, | 631 | ure_write_mem(un, URE_USB_TOLERANCE, | |
626 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 632 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
627 | 633 | |||
628 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, | 634 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, | |
629 | URE_ALDPS_SPDWN_RATIO); | 635 | URE_ALDPS_SPDWN_RATIO); | |
630 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, | 636 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, | |
631 | URE_EEE_SPDWN_RATIO); | 637 | URE_EEE_SPDWN_RATIO); | |
632 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, | 638 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, | |
633 | URE_PKT_AVAIL_SPDWN_EN | URE_SUSPEND_SPDWN_EN | | 639 | URE_PKT_AVAIL_SPDWN_EN | URE_SUSPEND_SPDWN_EN | | |
634 | URE_U1U2_SPDWN_EN | URE_L1_SPDWN_EN); | 640 | URE_U1U2_SPDWN_EN | URE_L1_SPDWN_EN); | |
635 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, | 641 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, | |
636 | URE_PWRSAVE_SPDWN_EN | URE_RXDV_SPDWN_EN | URE_TX10MIDLE_EN | | 642 | URE_PWRSAVE_SPDWN_EN | URE_RXDV_SPDWN_EN | URE_TX10MIDLE_EN | | |
637 | URE_TP100_SPDWN_EN | URE_TP500_SPDWN_EN | URE_TP1000_SPDWN_EN | | 643 | URE_TP100_SPDWN_EN | URE_TP500_SPDWN_EN | URE_TP1000_SPDWN_EN | | |
638 | URE_EEE_SPDWN_EN); | 644 | URE_EEE_SPDWN_EN); | |
639 | 645 | |||
640 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | 646 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | |
641 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | 647 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | |
642 | val |= URE_U2P3_ENABLE; | 648 | val |= URE_U2P3_ENABLE; | |
643 | else | 649 | else | |
644 | val &= ~URE_U2P3_ENABLE; | 650 | val &= ~URE_U2P3_ENABLE; | |
645 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | 651 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | |
646 | 652 | |||
647 | memset(u1u2, 0x00, sizeof(u1u2)); | 653 | memset(u1u2, 0x00, sizeof(u1u2)); | |
648 | ure_write_mem(un, URE_USB_TOLERANCE, | 654 | ure_write_mem(un, URE_USB_TOLERANCE, | |
649 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 655 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
650 | 656 | |||
651 | /* Disable ALDPS. */ | 657 | /* Disable ALDPS. */ | |
652 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 658 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
653 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | 659 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | |
654 | usbd_delay_ms(un->un_udev, 20); | 660 | usbd_delay_ms(un->un_udev, 20); | |
655 | 661 | |||
656 | ure_init_fifo(un); | 662 | ure_init_fifo(un); | |
657 | 663 | |||
658 | /* Enable Rx aggregation. */ | 664 | /* Enable Rx aggregation. */ | |
659 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | 665 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | |
660 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | 666 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | |
661 | ~URE_RX_AGG_DISABLE); | 667 | ~URE_RX_AGG_DISABLE); | |
662 | 668 | |||
663 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | 669 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | |
664 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | 670 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | |
665 | val |= URE_U2P3_ENABLE; | 671 | val |= URE_U2P3_ENABLE; | |
666 | else | 672 | else | |
667 | val &= ~URE_U2P3_ENABLE; | 673 | val &= ~URE_U2P3_ENABLE; | |
668 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | 674 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | |
669 | 675 | |||
670 | memset(u1u2, 0xff, sizeof(u1u2)); | 676 | memset(u1u2, 0xff, sizeof(u1u2)); | |
671 | ure_write_mem(un, URE_USB_TOLERANCE, | 677 | ure_write_mem(un, URE_USB_TOLERANCE, | |
672 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 678 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
673 | } | 679 | } | |
674 | 680 | |||
675 | static void | 681 | static void | |
676 | ure_disable_teredo(struct usbnet *un) | 682 | ure_disable_teredo(struct usbnet *un) | |
677 | { | 683 | { | |
678 | ure_write_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, | 684 | ure_write_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, | |
679 | ure_read_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) & | 685 | ure_read_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) & | |
680 | ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN)); | 686 | ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN)); | |
681 | ure_write_2(un, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, | 687 | ure_write_2(un, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, | |
682 | URE_WDT6_SET_MODE); | 688 | URE_WDT6_SET_MODE); | |
683 | ure_write_2(un, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0); | 689 | ure_write_2(un, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0); | |
684 | ure_write_4(un, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0); | 690 | ure_write_4(un, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0); | |
685 | } | 691 | } | |
686 | 692 | |||
687 | static void | 693 | static void | |
688 | ure_init_fifo(struct usbnet *un) | 694 | ure_init_fifo(struct usbnet *un) | |
689 | { | 695 | { | |
690 | uint32_t rxmode, rx_fifo1, rx_fifo2; | 696 | uint32_t rxmode, rx_fifo1, rx_fifo2; | |
691 | int i; | 697 | int i; | |
692 | 698 | |||
693 | ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, | 699 | ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, | |
694 | ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) | | 700 | ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) | | |
695 | URE_RXDY_GATED_EN); | 701 | URE_RXDY_GATED_EN); | |
696 | 702 | |||
697 | ure_disable_teredo(un); | 703 | ure_disable_teredo(un); | |
698 | 704 | |||
699 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | 705 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | |
700 | rxmode &= ~URE_RCR_ACPT_ALL; | 706 | rxmode &= ~URE_RCR_ACPT_ALL; | |
701 | rxmode |= URE_RCR_APM | URE_RCR_AB; /* accept my own DA and bcast */ | 707 | rxmode |= URE_RCR_APM | URE_RCR_AB; /* accept my own DA and bcast */ | |
702 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | 708 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | |
703 | 709 | |||
704 | if (!(un->un_flags & URE_FLAG_8152)) { | 710 | if (!(un->un_flags & URE_FLAG_8152)) { | |
705 | if (un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10 | | 711 | if (un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10 | | |
706 | URE_FLAG_VER_5C20)) | 712 | URE_FLAG_VER_5C20)) | |
707 | ure_ocp_reg_write(un, URE_OCP_ADC_CFG, | 713 | ure_ocp_reg_write(un, URE_OCP_ADC_CFG, | |
708 | URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L); | 714 | URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L); | |
709 | if (un->un_flags & URE_FLAG_VER_5C00) | 715 | if (un->un_flags & URE_FLAG_VER_5C00) | |
710 | ure_ocp_reg_write(un, URE_OCP_EEE_CFG, | 716 | ure_ocp_reg_write(un, URE_OCP_EEE_CFG, | |
711 | ure_ocp_reg_read(un, URE_OCP_EEE_CFG) & | 717 | ure_ocp_reg_read(un, URE_OCP_EEE_CFG) & | |
712 | ~URE_CTAP_SHORT_EN); | 718 | ~URE_CTAP_SHORT_EN); | |
713 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 719 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
714 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | 720 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | |
715 | URE_EEE_CLKDIV_EN); | 721 | URE_EEE_CLKDIV_EN); | |
716 | ure_ocp_reg_write(un, URE_OCP_DOWN_SPEED, | 722 | ure_ocp_reg_write(un, URE_OCP_DOWN_SPEED, | |
717 | ure_ocp_reg_read(un, URE_OCP_DOWN_SPEED) | | 723 | ure_ocp_reg_read(un, URE_OCP_DOWN_SPEED) | | |
718 | URE_EN_10M_BGOFF); | 724 | URE_EN_10M_BGOFF); | |
719 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 725 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
720 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | 726 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | |
721 | URE_EN_10M_PLLOFF); | 727 | URE_EN_10M_PLLOFF); | |
722 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_IMPEDANCE); | 728 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_IMPEDANCE); | |
723 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0b13); | 729 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0b13); | |
724 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | 730 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | |
725 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | 731 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | |
726 | URE_PFM_PWM_SWITCH); | 732 | URE_PFM_PWM_SWITCH); | |
727 | 733 | |||
728 | /* Enable LPF corner auto tune. */ | 734 | /* Enable LPF corner auto tune. */ | |
729 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_LPF_CFG); | 735 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_LPF_CFG); | |
730 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0xf70f); | 736 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0xf70f); | |
731 | 737 | |||
732 | /* Adjust 10M amplitude. */ | 738 | /* Adjust 10M amplitude. */ | |
733 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP1); | 739 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP1); | |
734 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x00af); | 740 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x00af); | |
735 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP2); | 741 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP2); | |
736 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0208); | 742 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0208); | |
737 | } | 743 | } | |
738 | 744 | |||
739 | ure_reset(un); | 745 | ure_reset(un); | |
740 | 746 | |||
741 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, 0); | 747 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, 0); | |
742 | 748 | |||
743 | ure_write_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, | 749 | ure_write_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, | |
744 | ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | 750 | ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | |
745 | ~URE_NOW_IS_OOB); | 751 | ~URE_NOW_IS_OOB); | |
746 | 752 | |||
747 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | 753 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | |
748 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) & | 754 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) & | |
749 | ~URE_MCU_BORW_EN); | 755 | ~URE_MCU_BORW_EN); | |
750 | for (i = 0; i < URE_TIMEOUT; i++) { | 756 | for (i = 0; i < URE_TIMEOUT; i++) { | |
757 | if (usbnet_isdying(un)) | |||
758 | return; | |||
751 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | 759 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | |
752 | URE_LINK_LIST_READY) | 760 | URE_LINK_LIST_READY) | |
753 | break; | 761 | break; | |
754 | usbd_delay_ms(un->un_udev, 10); | 762 | usbd_delay_ms(un->un_udev, 10); | |
755 | } | 763 | } | |
756 | if (i == URE_TIMEOUT) | 764 | if (i == URE_TIMEOUT) | |
757 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | 765 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | |
758 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | 766 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | |
759 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) | | 767 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) | | |
760 | URE_RE_INIT_LL); | 768 | URE_RE_INIT_LL); | |
761 | for (i = 0; i < URE_TIMEOUT; i++) { | 769 | for (i = 0; i < URE_TIMEOUT; i++) { | |
770 | if (usbnet_isdying(un)) | |||
771 | return; | |||
762 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | 772 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | |
763 | URE_LINK_LIST_READY) | 773 | URE_LINK_LIST_READY) | |
764 | break; | 774 | break; | |
765 | usbd_delay_ms(un->un_udev, 10); | 775 | usbd_delay_ms(un->un_udev, 10); | |
766 | } | 776 | } | |
767 | if (i == URE_TIMEOUT) | 777 | if (i == URE_TIMEOUT) | |
768 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | 778 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | |
769 | 779 | |||
770 | ure_write_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA, | 780 | ure_write_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA, | |
771 | ure_read_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA) & | 781 | ure_read_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA) & | |
772 | ~URE_CPCR_RX_VLAN); | 782 | ~URE_CPCR_RX_VLAN); | |
773 | ure_write_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA, | 783 | ure_write_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA, | |
774 | ure_read_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA) | | 784 | ure_read_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA) | | |
775 | URE_TCR0_AUTO_FIFO); | 785 | URE_TCR0_AUTO_FIFO); | |
776 | 786 | |||
777 | /* Configure Rx FIFO threshold and coalescing. */ | 787 | /* Configure Rx FIFO threshold and coalescing. */ | |
778 | ure_write_4(un, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA, | 788 | ure_write_4(un, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA, | |
779 | URE_RXFIFO_THR1_NORMAL); | 789 | URE_RXFIFO_THR1_NORMAL); | |
780 | if (un->un_udev->ud_speed == USB_SPEED_FULL) { | 790 | if (un->un_udev->ud_speed == USB_SPEED_FULL) { | |
781 | rx_fifo1 = URE_RXFIFO_THR2_FULL; | 791 | rx_fifo1 = URE_RXFIFO_THR2_FULL; | |
782 | rx_fifo2 = URE_RXFIFO_THR3_FULL; | 792 | rx_fifo2 = URE_RXFIFO_THR3_FULL; | |
783 | } else { | 793 | } else { | |
784 | rx_fifo1 = URE_RXFIFO_THR2_HIGH; | 794 | rx_fifo1 = URE_RXFIFO_THR2_HIGH; | |
785 | rx_fifo2 = URE_RXFIFO_THR3_HIGH; | 795 | rx_fifo2 = URE_RXFIFO_THR3_HIGH; | |
786 | } | 796 | } | |
787 | ure_write_4(un, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1); | 797 | ure_write_4(un, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1); | |
788 | ure_write_4(un, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2); | 798 | ure_write_4(un, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2); | |
789 | 799 | |||
790 | /* Configure Tx FIFO threshold. */ | 800 | /* Configure Tx FIFO threshold. */ | |
791 | ure_write_4(un, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, | 801 | ure_write_4(un, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, | |
792 | URE_TXFIFO_THR_NORMAL); | 802 | URE_TXFIFO_THR_NORMAL); | |
793 | } | 803 | } | |
794 | 804 | |||
795 | static int | 805 | static int | |
796 | ure_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 806 | ure_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
797 | { | 807 | { | |
798 | struct usbnet * const un = ifp->if_softc; | 808 | struct usbnet * const un = ifp->if_softc; | |
799 | 809 | |||
800 | usbnet_lock_core(un); | 810 | usbnet_lock_core(un); | |
801 | usbnet_busy(un); | 811 | usbnet_busy(un); | |
802 | 812 | |||
803 | switch (cmd) { | 813 | switch (cmd) { | |
804 | case SIOCADDMULTI: | 814 | case SIOCADDMULTI: | |
805 | case SIOCDELMULTI: | 815 | case SIOCDELMULTI: | |
806 | ure_rcvfilt_locked(un); | 816 | ure_rcvfilt_locked(un); | |
807 | break; | 817 | break; | |
808 | default: | 818 | default: | |
809 | break; | 819 | break; | |
810 | } | 820 | } | |
811 | 821 | |||
812 | usbnet_unbusy(un); | 822 | usbnet_unbusy(un); | |
813 | usbnet_unlock_core(un); | 823 | usbnet_unlock_core(un); | |
814 | 824 | |||
815 | return 0; | 825 | return 0; | |
816 | } | 826 | } | |
817 | 827 | |||
818 | static int | 828 | static int | |
819 | ure_match(device_t parent, cfdata_t match, void *aux) | 829 | ure_match(device_t parent, cfdata_t match, void *aux) | |
820 | { | 830 | { | |
821 | struct usb_attach_arg *uaa = aux; | 831 | struct usb_attach_arg *uaa = aux; | |
822 | 832 | |||
823 | return usb_lookup(ure_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 833 | return usb_lookup(ure_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
824 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 834 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
825 | } | 835 | } | |
826 | 836 | |||
827 | static void | 837 | static void | |
828 | ure_attach(device_t parent, device_t self, void *aux) | 838 | ure_attach(device_t parent, device_t self, void *aux) | |
829 | { | 839 | { | |
830 | USBNET_MII_DECL_DEFAULT(unm); | 840 | USBNET_MII_DECL_DEFAULT(unm); | |
831 | struct usbnet * const un = device_private(self); | 841 | struct usbnet * const un = device_private(self); | |
832 | struct usb_attach_arg *uaa = aux; | 842 | struct usb_attach_arg *uaa = aux; | |
833 | struct usbd_device *dev = uaa->uaa_device; | 843 | struct usbd_device *dev = uaa->uaa_device; | |
834 | usb_interface_descriptor_t *id; | 844 | usb_interface_descriptor_t *id; | |
835 | usb_endpoint_descriptor_t *ed; | 845 | usb_endpoint_descriptor_t *ed; | |
836 | int error, i; | 846 | int error, i; | |
837 | uint16_t ver; | 847 | uint16_t ver; | |
838 | uint8_t eaddr[8]; /* 2byte padded */ | 848 | uint8_t eaddr[8]; /* 2byte padded */ | |
839 | char *devinfop; | 849 | char *devinfop; | |
840 | uint32_t maclo, machi; | 850 | uint32_t maclo, machi; | |
841 | 851 | |||
842 | aprint_naive("\n"); | 852 | aprint_naive("\n"); | |
843 | aprint_normal("\n"); | 853 | aprint_normal("\n"); | |
844 | devinfop = usbd_devinfo_alloc(dev, 0); | 854 | devinfop = usbd_devinfo_alloc(dev, 0); | |
845 | aprint_normal_dev(self, "%s\n", devinfop); | 855 | aprint_normal_dev(self, "%s\n", devinfop); | |
846 | usbd_devinfo_free(devinfop); | 856 | usbd_devinfo_free(devinfop); | |
847 | 857 | |||
848 | un->un_dev = self; | 858 | un->un_dev = self; | |
849 | un->un_udev = dev; | 859 | un->un_udev = dev; | |
850 | un->un_sc = un; | 860 | un->un_sc = un; | |
851 | un->un_ops = &ure_ops; | 861 | un->un_ops = &ure_ops; | |
852 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 862 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
853 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 863 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
854 | un->un_rx_list_cnt = URE_RX_LIST_CNT; | 864 | un->un_rx_list_cnt = URE_RX_LIST_CNT; | |
855 | un->un_tx_list_cnt = URE_TX_LIST_CNT; | 865 | un->un_tx_list_cnt = URE_TX_LIST_CNT; | |
856 | un->un_rx_bufsz = URE_BUFSZ; | 866 | un->un_rx_bufsz = URE_BUFSZ; | |
857 | un->un_tx_bufsz = URE_BUFSZ; | 867 | un->un_tx_bufsz = URE_BUFSZ; | |
858 | 868 | |||
859 | #define URE_CONFIG_NO 1 /* XXX */ | 869 | #define URE_CONFIG_NO 1 /* XXX */ | |
860 | error = usbd_set_config_no(dev, URE_CONFIG_NO, 1); | 870 | error = usbd_set_config_no(dev, URE_CONFIG_NO, 1); | |
861 | if (error) { | 871 | if (error) { | |
862 | aprint_error_dev(self, "failed to set configuration: %s\n", | 872 | aprint_error_dev(self, "failed to set configuration: %s\n", | |
863 | usbd_errstr(error)); | 873 | usbd_errstr(error)); | |
864 | return; /* XXX */ | 874 | return; /* XXX */ | |
865 | } | 875 | } | |
866 | 876 | |||
867 | if (uaa->uaa_product == USB_PRODUCT_REALTEK_RTL8152) | 877 | if (uaa->uaa_product == USB_PRODUCT_REALTEK_RTL8152) | |
868 | un->un_flags |= URE_FLAG_8152; | 878 | un->un_flags |= URE_FLAG_8152; | |
869 | 879 | |||
870 | #define URE_IFACE_IDX 0 /* XXX */ | 880 | #define URE_IFACE_IDX 0 /* XXX */ | |
871 | error = usbd_device2interface_handle(dev, URE_IFACE_IDX, &un->un_iface); | 881 | error = usbd_device2interface_handle(dev, URE_IFACE_IDX, &un->un_iface); | |
872 | if (error) { | 882 | if (error) { | |
873 | aprint_error_dev(self, "failed to get interface handle: %s\n", | 883 | aprint_error_dev(self, "failed to get interface handle: %s\n", | |
874 | usbd_errstr(error)); | 884 | usbd_errstr(error)); | |
875 | return; /* XXX */ | 885 | return; /* XXX */ | |
876 | } | 886 | } | |
877 | 887 | |||
878 | id = usbd_get_interface_descriptor(un->un_iface); | 888 | id = usbd_get_interface_descriptor(un->un_iface); | |
879 | for (i = 0; i < id->bNumEndpoints; i++) { | 889 | for (i = 0; i < id->bNumEndpoints; i++) { | |
880 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 890 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
881 | if (ed == NULL) { | 891 | if (ed == NULL) { | |
882 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 892 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
883 | return; /* XXX */ | 893 | return; /* XXX */ | |
884 | } | 894 | } | |
885 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 895 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
886 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 896 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
887 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 897 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
888 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 898 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
889 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 899 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
890 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 900 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
891 | } | 901 | } | |
892 | } | 902 | } | |
893 | 903 | |||
894 | /* Set these up now for ure_ctl(). */ | 904 | /* Set these up now for ure_ctl(). */ | |
895 | usbnet_attach(un, "uredet"); | 905 | usbnet_attach(un, "uredet"); | |
896 | 906 | |||
897 | un->un_phyno = 0; | 907 | un->un_phyno = 0; | |
898 | 908 | |||
899 | ver = ure_read_2(un, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK; | 909 | ver = ure_read_2(un, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK; | |
900 | switch (ver) { | 910 | switch (ver) { | |
901 | case 0x4c00: | 911 | case 0x4c00: | |
902 | un->un_flags |= URE_FLAG_VER_4C00; | 912 | un->un_flags |= URE_FLAG_VER_4C00; | |
903 | break; | 913 | break; | |
904 | case 0x4c10: | 914 | case 0x4c10: | |
905 | un->un_flags |= URE_FLAG_VER_4C10; | 915 | un->un_flags |= URE_FLAG_VER_4C10; | |
906 | break; | 916 | break; | |
907 | case 0x5c00: | 917 | case 0x5c00: | |
908 | un->un_flags |= URE_FLAG_VER_5C00; | 918 | un->un_flags |= URE_FLAG_VER_5C00; | |
909 | break; | 919 | break; | |
910 | case 0x5c10: | 920 | case 0x5c10: | |
911 | un->un_flags |= URE_FLAG_VER_5C10; | 921 | un->un_flags |= URE_FLAG_VER_5C10; | |
912 | break; | 922 | break; | |
913 | case 0x5c20: | 923 | case 0x5c20: | |
914 | un->un_flags |= URE_FLAG_VER_5C20; | 924 | un->un_flags |= URE_FLAG_VER_5C20; | |
915 | break; | 925 | break; | |
916 | case 0x5c30: | 926 | case 0x5c30: | |
917 | un->un_flags |= URE_FLAG_VER_5C30; | 927 | un->un_flags |= URE_FLAG_VER_5C30; | |
918 | break; | 928 | break; | |
919 | default: | 929 | default: | |
920 | /* fake addr? or just fail? */ | 930 | /* fake addr? or just fail? */ | |
921 | break; | 931 | break; | |
922 | } | 932 | } | |
923 | aprint_normal_dev(self, "RTL%d %sver %04x\n", | 933 | aprint_normal_dev(self, "RTL%d %sver %04x\n", | |
924 | (un->un_flags & URE_FLAG_8152) ? 8152 : 8153, | 934 | (un->un_flags & URE_FLAG_8152) ? 8152 : 8153, | |
925 | (un->un_flags != 0) ? "" : "unknown ", | 935 | (un->un_flags != 0) ? "" : "unknown ", | |
926 | ver); | 936 | ver); | |
927 | 937 | |||
928 | usbnet_lock_core(un); | 938 | usbnet_lock_core(un); | |
929 | if (un->un_flags & URE_FLAG_8152) | 939 | if (un->un_flags & URE_FLAG_8152) | |
930 | ure_rtl8152_init(un); | 940 | ure_rtl8152_init(un); | |
931 | else | 941 | else | |
932 | ure_rtl8153_init(un); | 942 | ure_rtl8153_init(un); | |
933 | 943 | |||
934 | if ((un->un_flags & URE_FLAG_VER_4C00) || | 944 | if ((un->un_flags & URE_FLAG_VER_4C00) || | |
935 | (un->un_flags & URE_FLAG_VER_4C10)) | 945 | (un->un_flags & URE_FLAG_VER_4C10)) | |
936 | ure_read_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA, eaddr, | 946 | ure_read_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA, eaddr, | |
937 | sizeof(eaddr)); | 947 | sizeof(eaddr)); | |
938 | else | 948 | else | |
939 | ure_read_mem(un, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, eaddr, | 949 | ure_read_mem(un, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, eaddr, | |
940 | sizeof(eaddr)); | 950 | sizeof(eaddr)); | |
941 | usbnet_unlock_core(un); | 951 | usbnet_unlock_core(un); | |
942 | if (ETHER_IS_ZERO(eaddr)) { | 952 | if (ETHER_IS_ZERO(eaddr)) { | |
943 | maclo = 0x00f2 | (cprng_strong32() & 0xffff0000); | 953 | maclo = 0x00f2 | (cprng_strong32() & 0xffff0000); | |
944 | machi = cprng_strong32() & 0xffff; | 954 | machi = cprng_strong32() & 0xffff; | |
945 | eaddr[0] = maclo & 0xff; | 955 | eaddr[0] = maclo & 0xff; | |
946 | eaddr[1] = (maclo >> 8) & 0xff; | 956 | eaddr[1] = (maclo >> 8) & 0xff; | |
947 | eaddr[2] = (maclo >> 16) & 0xff; | 957 | eaddr[2] = (maclo >> 16) & 0xff; | |
948 | eaddr[3] = (maclo >> 24) & 0xff; | 958 | eaddr[3] = (maclo >> 24) & 0xff; | |
949 | eaddr[4] = machi & 0xff; | 959 | eaddr[4] = machi & 0xff; | |
950 | eaddr[5] = (machi >> 8) & 0xff; | 960 | eaddr[5] = (machi >> 8) & 0xff; | |
951 | } | 961 | } | |
952 | memcpy(un->un_eaddr, eaddr, sizeof(un->un_eaddr)); | 962 | memcpy(un->un_eaddr, eaddr, sizeof(un->un_eaddr)); | |
953 | 963 | |||
954 | struct ifnet *ifp = usbnet_ifp(un); | 964 | struct ifnet *ifp = usbnet_ifp(un); | |
955 | 965 | |||
956 | /* | 966 | /* | |
957 | * We don't support TSOv4 and v6 for now, that are required to | 967 | * We don't support TSOv4 and v6 for now, that are required to | |
958 | * be handled in software for some cases. | 968 | * be handled in software for some cases. | |
959 | */ | 969 | */ | |
960 | ifp->if_capabilities = IFCAP_CSUM_IPv4_Tx | | 970 | ifp->if_capabilities = IFCAP_CSUM_IPv4_Tx | | |
961 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx; | 971 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx; | |
962 | #ifdef INET6 | 972 | #ifdef INET6 | |
963 | ifp->if_capabilities |= IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx; | 973 | ifp->if_capabilities |= IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx; | |
964 | #endif | 974 | #endif | |
965 | if (un->un_flags & ~URE_FLAG_VER_4C00) { | 975 | if (un->un_flags & ~URE_FLAG_VER_4C00) { | |
966 | ifp->if_capabilities |= IFCAP_CSUM_IPv4_Rx | | 976 | ifp->if_capabilities |= IFCAP_CSUM_IPv4_Rx | | |
967 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | 977 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | |
968 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; | 978 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; | |
969 | } | 979 | } | |
970 | struct ethercom *ec = usbnet_ec(un); | 980 | struct ethercom *ec = usbnet_ec(un); | |
971 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | 981 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | |
972 | #ifdef notyet | 982 | #ifdef notyet | |
973 | ec->ec_capabilities |= ETHERCAP_JUMBO_MTU; | 983 | ec->ec_capabilities |= ETHERCAP_JUMBO_MTU; | |
974 | #endif | 984 | #endif | |
975 | 985 | |||
976 | unm.un_mii_phyloc = un->un_phyno; | 986 | unm.un_mii_phyloc = un->un_phyno; | |
977 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 987 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
978 | 0, &unm); | 988 | 0, &unm); | |
979 | } | 989 | } | |
980 | 990 | |||
981 | static void | 991 | static void | |
982 | ure_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 992 | ure_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
983 | { | 993 | { | |
984 | struct ifnet *ifp = usbnet_ifp(un); | 994 | struct ifnet *ifp = usbnet_ifp(un); | |
985 | uint8_t *buf = c->unc_buf; | 995 | uint8_t *buf = c->unc_buf; | |
986 | uint16_t pkt_len = 0; | 996 | uint16_t pkt_len = 0; | |
987 | uint16_t pkt_count = 0; | 997 | uint16_t pkt_count = 0; | |
988 | struct ure_rxpkt rxhdr; | 998 | struct ure_rxpkt rxhdr; | |
989 | 999 | |||
990 | do { | 1000 | do { | |
991 | if (total_len < sizeof(rxhdr)) { | 1001 | if (total_len < sizeof(rxhdr)) { | |
992 | DPRINTF(("too few bytes left for a packet header\n")); | 1002 | DPRINTF(("too few bytes left for a packet header\n")); | |
993 | if_statinc(ifp, if_ierrors); | 1003 | if_statinc(ifp, if_ierrors); | |
994 | return; | 1004 | return; | |
995 | } | 1005 | } | |
996 | 1006 | |||
997 | buf += roundup(pkt_len, 8); | 1007 | buf += roundup(pkt_len, 8); | |
998 | 1008 | |||
999 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | 1009 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | |
1000 | total_len -= sizeof(rxhdr); | 1010 | total_len -= sizeof(rxhdr); | |
1001 | 1011 | |||
1002 | pkt_len = le32toh(rxhdr.ure_pktlen) & URE_RXPKT_LEN_MASK; | 1012 | pkt_len = le32toh(rxhdr.ure_pktlen) & URE_RXPKT_LEN_MASK; | |
1003 | DPRINTFN(4, ("next packet is %d bytes\n", pkt_len)); | 1013 | DPRINTFN(4, ("next packet is %d bytes\n", pkt_len)); | |
1004 | if (pkt_len > total_len) { | 1014 | if (pkt_len > total_len) { | |
1005 | DPRINTF(("not enough bytes left for next packet\n")); | 1015 | DPRINTF(("not enough bytes left for next packet\n")); | |
1006 | if_statinc(ifp, if_ierrors); | 1016 | if_statinc(ifp, if_ierrors); | |
1007 | return; | 1017 | return; | |
1008 | } | 1018 | } | |
1009 | 1019 | |||
1010 | total_len -= roundup(pkt_len, 8); | 1020 | total_len -= roundup(pkt_len, 8); | |
1011 | buf += sizeof(rxhdr); | 1021 | buf += sizeof(rxhdr); | |
1012 | 1022 | |||
1013 | usbnet_enqueue(un, buf, pkt_len - ETHER_CRC_LEN, | 1023 | usbnet_enqueue(un, buf, pkt_len - ETHER_CRC_LEN, | |
1014 | ure_rxcsum(ifp, &rxhdr), 0, 0); | 1024 | ure_rxcsum(ifp, &rxhdr), 0, 0); | |
1015 | 1025 | |||
1016 | pkt_count++; | 1026 | pkt_count++; | |
1017 | 1027 | |||
1018 | } while (total_len > 0); | 1028 | } while (total_len > 0); | |
1019 | 1029 | |||
1020 | if (pkt_count) | 1030 | if (pkt_count) | |
1021 | rnd_add_uint32(usbnet_rndsrc(un), pkt_count); | 1031 | rnd_add_uint32(usbnet_rndsrc(un), pkt_count); | |
1022 | } | 1032 | } | |
1023 | 1033 | |||
1024 | static int | 1034 | static int | |
1025 | ure_rxcsum(struct ifnet *ifp, struct ure_rxpkt *rp) | 1035 | ure_rxcsum(struct ifnet *ifp, struct ure_rxpkt *rp) | |
1026 | { | 1036 | { | |
1027 | int enabled = ifp->if_csum_flags_rx, flags = 0; | 1037 | int enabled = ifp->if_csum_flags_rx, flags = 0; | |
1028 | uint32_t csum, misc; | 1038 | uint32_t csum, misc; | |
1029 | 1039 | |||
1030 | if (enabled == 0) | 1040 | if (enabled == 0) | |
1031 | return 0; | 1041 | return 0; | |
1032 | 1042 | |||
1033 | csum = le32toh(rp->ure_csum); | 1043 | csum = le32toh(rp->ure_csum); | |
1034 | misc = le32toh(rp->ure_misc); | 1044 | misc = le32toh(rp->ure_misc); | |
1035 | 1045 | |||
1036 | if (csum & URE_RXPKT_IPV4_CS) { | 1046 | if (csum & URE_RXPKT_IPV4_CS) { | |
1037 | flags |= M_CSUM_IPv4; | 1047 | flags |= M_CSUM_IPv4; | |
1038 | if (csum & URE_RXPKT_TCP_CS) | 1048 | if (csum & URE_RXPKT_TCP_CS) | |
1039 | flags |= M_CSUM_TCPv4; | 1049 | flags |= M_CSUM_TCPv4; | |
1040 | if (csum & URE_RXPKT_UDP_CS) | 1050 | if (csum & URE_RXPKT_UDP_CS) | |
1041 | flags |= M_CSUM_UDPv4; | 1051 | flags |= M_CSUM_UDPv4; | |
1042 | } else if (csum & URE_RXPKT_IPV6_CS) { | 1052 | } else if (csum & URE_RXPKT_IPV6_CS) { | |
1043 | flags = 0; | 1053 | flags = 0; | |
1044 | if (csum & URE_RXPKT_TCP_CS) | 1054 | if (csum & URE_RXPKT_TCP_CS) | |
1045 | flags |= M_CSUM_TCPv6; | 1055 | flags |= M_CSUM_TCPv6; | |
1046 | if (csum & URE_RXPKT_UDP_CS) | 1056 | if (csum & URE_RXPKT_UDP_CS) | |
1047 | flags |= M_CSUM_UDPv6; | 1057 | flags |= M_CSUM_UDPv6; | |
1048 | } | 1058 | } | |
1049 | 1059 | |||
1050 | flags &= enabled; | 1060 | flags &= enabled; | |
1051 | if (__predict_false((flags & M_CSUM_IPv4) && | 1061 | if (__predict_false((flags & M_CSUM_IPv4) && | |
1052 | (misc & URE_RXPKT_IP_F))) | 1062 | (misc & URE_RXPKT_IP_F))) | |
1053 | flags |= M_CSUM_IPv4_BAD; | 1063 | flags |= M_CSUM_IPv4_BAD; | |
1054 | if (__predict_false( | 1064 | if (__predict_false( | |
1055 | ((flags & (M_CSUM_TCPv4 | M_CSUM_TCPv6)) && (misc & URE_RXPKT_TCP_F)) | 1065 | ((flags & (M_CSUM_TCPv4 | M_CSUM_TCPv6)) && (misc & URE_RXPKT_TCP_F)) | |
1056 | || ((flags & (M_CSUM_UDPv4 | M_CSUM_UDPv6)) && (misc & URE_RXPKT_UDP_F)) | 1066 | || ((flags & (M_CSUM_UDPv4 | M_CSUM_UDPv6)) && (misc & URE_RXPKT_UDP_F)) | |
1057 | )) | 1067 | )) | |
1058 | flags |= M_CSUM_TCP_UDP_BAD; | 1068 | flags |= M_CSUM_TCP_UDP_BAD; | |
1059 | 1069 | |||
1060 | return flags; | 1070 | return flags; | |
1061 | } | 1071 | } | |
1062 | 1072 | |||
1063 | static unsigned | 1073 | static unsigned | |
1064 | ure_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 1074 | ure_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
1065 | { | 1075 | { | |
1066 | struct ure_txpkt txhdr; | 1076 | struct ure_txpkt txhdr; | |
1067 | uint32_t frm_len = 0; | 1077 | uint32_t frm_len = 0; | |
1068 | uint8_t *buf = c->unc_buf; | 1078 | uint8_t *buf = c->unc_buf; | |
1069 | 1079 | |||
1070 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(txhdr)) | 1080 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(txhdr)) | |
1071 | return 0; | 1081 | return 0; | |
1072 | 1082 | |||
1073 | /* header */ | 1083 | /* header */ | |
1074 | txhdr.ure_pktlen = htole32(m->m_pkthdr.len | URE_TXPKT_TX_FS | | 1084 | txhdr.ure_pktlen = htole32(m->m_pkthdr.len | URE_TXPKT_TX_FS | | |
1075 | URE_TXPKT_TX_LS); | 1085 | URE_TXPKT_TX_LS); | |
1076 | txhdr.ure_csum = htole32(ure_txcsum(m)); | 1086 | txhdr.ure_csum = htole32(ure_txcsum(m)); | |
1077 | memcpy(buf, &txhdr, sizeof(txhdr)); | 1087 | memcpy(buf, &txhdr, sizeof(txhdr)); | |
1078 | buf += sizeof(txhdr); | 1088 | buf += sizeof(txhdr); | |
1079 | frm_len = sizeof(txhdr); | 1089 | frm_len = sizeof(txhdr); | |
1080 | 1090 | |||
1081 | /* packet */ | 1091 | /* packet */ | |
1082 | m_copydata(m, 0, m->m_pkthdr.len, buf); | 1092 | m_copydata(m, 0, m->m_pkthdr.len, buf); | |
1083 | frm_len += m->m_pkthdr.len; | 1093 | frm_len += m->m_pkthdr.len; | |
1084 | 1094 | |||
1085 | DPRINTFN(2, ("tx %d bytes\n", frm_len)); | 1095 | DPRINTFN(2, ("tx %d bytes\n", frm_len)); | |
1086 | 1096 | |||
1087 | return frm_len; | 1097 | return frm_len; | |
1088 | } | 1098 | } | |
1089 | 1099 | |||
1090 | /* | 1100 | /* | |
1091 | * We need to calculate L4 checksum in software, if the offset of | 1101 | * We need to calculate L4 checksum in software, if the offset of | |
1092 | * L4 header is larger than 0x7ff = 2047. | 1102 | * L4 header is larger than 0x7ff = 2047. | |
1093 | */ | 1103 | */ | |
1094 | static uint32_t | 1104 | static uint32_t | |
1095 | ure_txcsum(struct mbuf *m) | 1105 | ure_txcsum(struct mbuf *m) | |
1096 | { | 1106 | { | |
1097 | struct ether_header *eh; | 1107 | struct ether_header *eh; | |
1098 | int flags = m->m_pkthdr.csum_flags; | 1108 | int flags = m->m_pkthdr.csum_flags; | |
1099 | uint32_t data = m->m_pkthdr.csum_data; | 1109 | uint32_t data = m->m_pkthdr.csum_data; | |
1100 | uint32_t reg = 0; | 1110 | uint32_t reg = 0; | |
1101 | int l3off, l4off; | 1111 | int l3off, l4off; | |
1102 | uint16_t type; | 1112 | uint16_t type; | |
1103 | 1113 | |||
1104 | if (flags == 0) | 1114 | if (flags == 0) | |
1105 | return 0; | 1115 | return 0; | |
1106 | 1116 | |||
1107 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | 1117 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | |
1108 | eh = mtod(m, struct ether_header *); | 1118 | eh = mtod(m, struct ether_header *); | |
1109 | type = eh->ether_type; | 1119 | type = eh->ether_type; | |
1110 | } else | 1120 | } else | |
1111 | m_copydata(m, offsetof(struct ether_header, ether_type), | 1121 | m_copydata(m, offsetof(struct ether_header, ether_type), | |
1112 | sizeof(type), &type); | 1122 | sizeof(type), &type); | |
1113 | switch (type = htons(type)) { | 1123 | switch (type = htons(type)) { | |
1114 | case ETHERTYPE_IP: | 1124 | case ETHERTYPE_IP: | |
1115 | case ETHERTYPE_IPV6: | 1125 | case ETHERTYPE_IPV6: | |
1116 | l3off = ETHER_HDR_LEN; | 1126 | l3off = ETHER_HDR_LEN; | |
1117 | break; | 1127 | break; | |
1118 | case ETHERTYPE_VLAN: | 1128 | case ETHERTYPE_VLAN: | |
1119 | l3off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | 1129 | l3off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | |
1120 | break; | 1130 | break; | |
1121 | default: | 1131 | default: | |
1122 | return 0; | 1132 | return 0; | |
1123 | } | 1133 | } | |
1124 | 1134 | |||
1125 | if (flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) { | 1135 | if (flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) { | |
1126 | l4off = l3off + M_CSUM_DATA_IPv4_IPHL(data); | 1136 | l4off = l3off + M_CSUM_DATA_IPv4_IPHL(data); | |
1127 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | 1137 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | |
1128 | in_undefer_cksum(m, l3off, flags); | 1138 | in_undefer_cksum(m, l3off, flags); | |
1129 | return 0; | 1139 | return 0; | |
1130 | } | 1140 | } | |
1131 | reg |= URE_TXPKT_IPV4_CS; | 1141 | reg |= URE_TXPKT_IPV4_CS; | |
1132 | if (flags & M_CSUM_TCPv4) | 1142 | if (flags & M_CSUM_TCPv4) | |
1133 | reg |= URE_TXPKT_TCP_CS; | 1143 | reg |= URE_TXPKT_TCP_CS; | |
1134 | else | 1144 | else | |
1135 | reg |= URE_TXPKT_UDP_CS; | 1145 | reg |= URE_TXPKT_UDP_CS; | |
1136 | reg |= l4off << URE_L4_OFFSET_SHIFT; | 1146 | reg |= l4off << URE_L4_OFFSET_SHIFT; | |
1137 | } | 1147 | } | |
1138 | #ifdef INET6 | 1148 | #ifdef INET6 | |
1139 | else if (flags & (M_CSUM_TCPv6 | M_CSUM_UDPv6)) { | 1149 | else if (flags & (M_CSUM_TCPv6 | M_CSUM_UDPv6)) { | |
1140 | l4off = l3off + M_CSUM_DATA_IPv6_IPHL(data); | 1150 | l4off = l3off + M_CSUM_DATA_IPv6_IPHL(data); | |
1141 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | 1151 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | |
1142 | in6_undefer_cksum(m, l3off, flags); | 1152 | in6_undefer_cksum(m, l3off, flags); | |
1143 | return 0; | 1153 | return 0; | |
1144 | } | 1154 | } | |
1145 | reg |= URE_TXPKT_IPV6_CS; | 1155 | reg |= URE_TXPKT_IPV6_CS; | |
1146 | if (flags & M_CSUM_TCPv6) | 1156 | if (flags & M_CSUM_TCPv6) | |
1147 | reg |= URE_TXPKT_TCP_CS; | 1157 | reg |= URE_TXPKT_TCP_CS; | |
1148 | else | 1158 | else | |
1149 | reg |= URE_TXPKT_UDP_CS; | 1159 | reg |= URE_TXPKT_UDP_CS; | |
1150 | reg |= l4off << URE_L4_OFFSET_SHIFT; | 1160 | reg |= l4off << URE_L4_OFFSET_SHIFT; | |
1151 | } | 1161 | } | |
1152 | #endif | 1162 | #endif | |
1153 | else if (flags & M_CSUM_IPv4) | 1163 | else if (flags & M_CSUM_IPv4) | |
1154 | reg |= URE_TXPKT_IPV4_CS; | 1164 | reg |= URE_TXPKT_IPV4_CS; | |
1155 | 1165 | |||
1156 | return reg; | 1166 | return reg; | |
1157 | } | 1167 | } | |
1158 | 1168 | |||
1159 | #ifdef _MODULE | 1169 | #ifdef _MODULE | |
1160 | #include "ioconf.c" | 1170 | #include "ioconf.c" | |
1161 | #endif | 1171 | #endif | |
1162 | 1172 | |||
1163 | USBNET_MODULE(ure) | 1173 | USBNET_MODULE(ure) |