usbnet drivers: Omit needless isdying tests in *_uno_init. usbnet(9) already checks this immediately before calling *_uno_init.diff -r1.186 -r1.187 src/sys/dev/usb/if_aue.c
(riastradh)
--- src/sys/dev/usb/if_aue.c 2022/03/03 05:54:37 1.186
+++ src/sys/dev/usb/if_aue.c 2022/03/03 05:55:01 1.187
@@ -1,1003 +1,1000 @@ | @@ -1,1003 +1,1000 @@ | |||
1 | /* $NetBSD: if_aue.c,v 1.186 2022/03/03 05:54:37 riastradh Exp $ */ | 1 | /* $NetBSD: if_aue.c,v 1.187 2022/03/03 05:55:01 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.186 2022/03/03 05:54:37 riastradh Exp $"); | 79 | __KERNEL_RCSID(0, "$NetBSD: if_aue.c,v 1.187 2022/03/03 05:55:01 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 void aue_uno_mcast(struct ifnet *); | 243 | static void aue_uno_mcast(struct ifnet *); | |
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_mcast = aue_uno_mcast, | 255 | .uno_mcast = aue_uno_mcast, | |
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 | if (usbnet_isdying(un)) | 287 | if (usbnet_isdying(un)) | |
288 | return 0; | 288 | return 0; | |
289 | 289 | |||
290 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 290 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
291 | req.bRequest = AUE_UR_READREG; | 291 | req.bRequest = AUE_UR_READREG; | |
292 | USETW(req.wValue, 0); | 292 | USETW(req.wValue, 0); | |
293 | USETW(req.wIndex, reg); | 293 | USETW(req.wIndex, reg); | |
294 | USETW(req.wLength, 1); | 294 | USETW(req.wLength, 1); | |
295 | 295 | |||
296 | err = usbd_do_request(un->un_udev, &req, &val); | 296 | err = usbd_do_request(un->un_udev, &req, &val); | |
297 | 297 | |||
298 | if (err) { | 298 | if (err) { | |
299 | AUEHIST_FUNC(); | 299 | AUEHIST_FUNC(); | |
300 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | 300 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | |
301 | device_unit(un->un_dev), reg, err, 0); | 301 | device_unit(un->un_dev), reg, err, 0); | |
302 | return 0; | 302 | return 0; | |
303 | } | 303 | } | |
304 | 304 | |||
305 | return val; | 305 | return val; | |
306 | } | 306 | } | |
307 | 307 | |||
308 | static int | 308 | static int | |
309 | aue_csr_read_2(struct aue_softc *sc, int reg) | 309 | aue_csr_read_2(struct aue_softc *sc, int reg) | |
310 | { | 310 | { | |
311 | struct usbnet * const un = &sc->aue_un; | 311 | struct usbnet * const un = &sc->aue_un; | |
312 | usb_device_request_t req; | 312 | usb_device_request_t req; | |
313 | usbd_status err; | 313 | usbd_status err; | |
314 | uWord val; | 314 | uWord val; | |
315 | 315 | |||
316 | if (usbnet_isdying(un)) | 316 | if (usbnet_isdying(un)) | |
317 | return 0; | 317 | return 0; | |
318 | 318 | |||
319 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 319 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
320 | req.bRequest = AUE_UR_READREG; | 320 | req.bRequest = AUE_UR_READREG; | |
321 | USETW(req.wValue, 0); | 321 | USETW(req.wValue, 0); | |
322 | USETW(req.wIndex, reg); | 322 | USETW(req.wIndex, reg); | |
323 | USETW(req.wLength, 2); | 323 | USETW(req.wLength, 2); | |
324 | 324 | |||
325 | err = usbd_do_request(un->un_udev, &req, &val); | 325 | err = usbd_do_request(un->un_udev, &req, &val); | |
326 | 326 | |||
327 | if (err) { | 327 | if (err) { | |
328 | AUEHIST_FUNC(); | 328 | AUEHIST_FUNC(); | |
329 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | 329 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | |
330 | device_unit(un->un_dev), reg, err, 0); | 330 | device_unit(un->un_dev), reg, err, 0); | |
331 | return 0; | 331 | return 0; | |
332 | } | 332 | } | |
333 | 333 | |||
334 | return UGETW(val); | 334 | return UGETW(val); | |
335 | } | 335 | } | |
336 | 336 | |||
337 | static int | 337 | static int | |
338 | aue_csr_write_1(struct aue_softc *sc, int reg, int aval) | 338 | aue_csr_write_1(struct aue_softc *sc, int reg, int aval) | |
339 | { | 339 | { | |
340 | struct usbnet * const un = &sc->aue_un; | 340 | struct usbnet * const un = &sc->aue_un; | |
341 | usb_device_request_t req; | 341 | usb_device_request_t req; | |
342 | usbd_status err; | 342 | usbd_status err; | |
343 | uByte val; | 343 | uByte val; | |
344 | 344 | |||
345 | if (usbnet_isdying(un)) | 345 | if (usbnet_isdying(un)) | |
346 | return 0; | 346 | return 0; | |
347 | 347 | |||
348 | val = aval; | 348 | val = aval; | |
349 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 349 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
350 | req.bRequest = AUE_UR_WRITEREG; | 350 | req.bRequest = AUE_UR_WRITEREG; | |
351 | USETW(req.wValue, val); | 351 | USETW(req.wValue, val); | |
352 | USETW(req.wIndex, reg); | 352 | USETW(req.wIndex, reg); | |
353 | USETW(req.wLength, 1); | 353 | USETW(req.wLength, 1); | |
354 | 354 | |||
355 | err = usbd_do_request(un->un_udev, &req, &val); | 355 | err = usbd_do_request(un->un_udev, &req, &val); | |
356 | 356 | |||
357 | if (err) { | 357 | if (err) { | |
358 | AUEHIST_FUNC(); | 358 | AUEHIST_FUNC(); | |
359 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | 359 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | |
360 | device_unit(un->un_dev), reg, err, 0); | 360 | device_unit(un->un_dev), reg, err, 0); | |
361 | return -1; | 361 | return -1; | |
362 | } | 362 | } | |
363 | 363 | |||
364 | return 0; | 364 | return 0; | |
365 | } | 365 | } | |
366 | 366 | |||
367 | static int | 367 | static int | |
368 | aue_csr_write_2(struct aue_softc *sc, int reg, int aval) | 368 | aue_csr_write_2(struct aue_softc *sc, int reg, int aval) | |
369 | { | 369 | { | |
370 | struct usbnet * const un = &sc->aue_un; | 370 | struct usbnet * const un = &sc->aue_un; | |
371 | usb_device_request_t req; | 371 | usb_device_request_t req; | |
372 | usbd_status err; | 372 | usbd_status err; | |
373 | uWord val; | 373 | uWord val; | |
374 | 374 | |||
375 | if (usbnet_isdying(un)) | 375 | if (usbnet_isdying(un)) | |
376 | return 0; | 376 | return 0; | |
377 | 377 | |||
378 | USETW(val, aval); | 378 | USETW(val, aval); | |
379 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 379 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
380 | req.bRequest = AUE_UR_WRITEREG; | 380 | req.bRequest = AUE_UR_WRITEREG; | |
381 | USETW(req.wValue, aval); | 381 | USETW(req.wValue, aval); | |
382 | USETW(req.wIndex, reg); | 382 | USETW(req.wIndex, reg); | |
383 | USETW(req.wLength, 2); | 383 | USETW(req.wLength, 2); | |
384 | 384 | |||
385 | err = usbd_do_request(un->un_udev, &req, &val); | 385 | err = usbd_do_request(un->un_udev, &req, &val); | |
386 | 386 | |||
387 | if (err) { | 387 | if (err) { | |
388 | AUEHIST_FUNC(); | 388 | AUEHIST_FUNC(); | |
389 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | 389 | AUEHIST_CALLARGS("aue%jd: reg=%#jx err=%jd", | |
390 | device_unit(un->un_dev), reg, err, 0); | 390 | device_unit(un->un_dev), reg, err, 0); | |
391 | return -1; | 391 | return -1; | |
392 | } | 392 | } | |
393 | 393 | |||
394 | return 0; | 394 | return 0; | |
395 | } | 395 | } | |
396 | 396 | |||
397 | /* | 397 | /* | |
398 | * Read a word of data stored in the EEPROM at address 'addr.' | 398 | * Read a word of data stored in the EEPROM at address 'addr.' | |
399 | */ | 399 | */ | |
400 | static int | 400 | static int | |
401 | aue_eeprom_getword(struct aue_softc *sc, int addr) | 401 | aue_eeprom_getword(struct aue_softc *sc, int addr) | |
402 | { | 402 | { | |
403 | struct usbnet * const un = &sc->aue_un; | 403 | struct usbnet * const un = &sc->aue_un; | |
404 | int i; | 404 | int i; | |
405 | 405 | |||
406 | AUEHIST_FUNC(); AUEHIST_CALLED(); | 406 | AUEHIST_FUNC(); AUEHIST_CALLED(); | |
407 | 407 | |||
408 | aue_csr_write_1(sc, AUE_EE_REG, addr); | 408 | aue_csr_write_1(sc, AUE_EE_REG, addr); | |
409 | aue_csr_write_1(sc, AUE_EE_CTL, AUE_EECTL_READ); | 409 | aue_csr_write_1(sc, AUE_EE_CTL, AUE_EECTL_READ); | |
410 | 410 | |||
411 | for (i = 0; i < AUE_TIMEOUT; i++) { | 411 | for (i = 0; i < AUE_TIMEOUT; i++) { | |
412 | if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE) | 412 | if (aue_csr_read_1(sc, AUE_EE_CTL) & AUE_EECTL_DONE) | |
413 | break; | 413 | break; | |
414 | } | 414 | } | |
415 | 415 | |||
416 | if (i == AUE_TIMEOUT) { | 416 | if (i == AUE_TIMEOUT) { | |
417 | printf("%s: EEPROM read timed out\n", | 417 | printf("%s: EEPROM read timed out\n", | |
418 | device_xname(un->un_dev)); | 418 | device_xname(un->un_dev)); | |
419 | } | 419 | } | |
420 | 420 | |||
421 | return aue_csr_read_2(sc, AUE_EE_DATA); | 421 | return aue_csr_read_2(sc, AUE_EE_DATA); | |
422 | } | 422 | } | |
423 | 423 | |||
424 | /* | 424 | /* | |
425 | * Read the MAC from the EEPROM. It's at offset 0. | 425 | * Read the MAC from the EEPROM. It's at offset 0. | |
426 | */ | 426 | */ | |
427 | static void | 427 | static void | |
428 | aue_read_mac(struct usbnet *un) | 428 | aue_read_mac(struct usbnet *un) | |
429 | { | 429 | { | |
430 | struct aue_softc *sc = usbnet_softc(un); | 430 | struct aue_softc *sc = usbnet_softc(un); | |
431 | int i; | 431 | int i; | |
432 | int off = 0; | 432 | int off = 0; | |
433 | int word; | 433 | int word; | |
434 | 434 | |||
435 | AUEHIST_FUNC(); | 435 | AUEHIST_FUNC(); | |
436 | AUEHIST_CALLARGS("aue%jd: enter", | 436 | AUEHIST_CALLARGS("aue%jd: enter", | |
437 | device_unit(un->un_dev), 0, 0, 0); | 437 | device_unit(un->un_dev), 0, 0, 0); | |
438 | 438 | |||
439 | for (i = 0; i < 3; i++) { | 439 | for (i = 0; i < 3; i++) { | |
440 | word = aue_eeprom_getword(sc, off + i); | 440 | word = aue_eeprom_getword(sc, off + i); | |
441 | un->un_eaddr[2 * i] = (u_char)word; | 441 | un->un_eaddr[2 * i] = (u_char)word; | |
442 | un->un_eaddr[2 * i + 1] = (u_char)(word >> 8); | 442 | un->un_eaddr[2 * i + 1] = (u_char)(word >> 8); | |
443 | } | 443 | } | |
444 | } | 444 | } | |
445 | 445 | |||
446 | static int | 446 | static int | |
447 | aue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 447 | aue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
448 | { | 448 | { | |
449 | struct aue_softc *sc = usbnet_softc(un); | 449 | struct aue_softc *sc = usbnet_softc(un); | |
450 | int i; | 450 | int i; | |
451 | 451 | |||
452 | AUEHIST_FUNC(); | 452 | AUEHIST_FUNC(); | |
453 | 453 | |||
454 | #if 0 | 454 | #if 0 | |
455 | /* | 455 | /* | |
456 | * The Am79C901 HomePNA PHY actually contains | 456 | * The Am79C901 HomePNA PHY actually contains | |
457 | * two transceivers: a 1Mbps HomePNA PHY and a | 457 | * two transceivers: a 1Mbps HomePNA PHY and a | |
458 | * 10Mbps full/half duplex ethernet PHY with | 458 | * 10Mbps full/half duplex ethernet PHY with | |
459 | * NWAY autoneg. However in the ADMtek adapter, | 459 | * NWAY autoneg. However in the ADMtek adapter, | |
460 | * only the 1Mbps PHY is actually connected to | 460 | * only the 1Mbps PHY is actually connected to | |
461 | * anything, so we ignore the 10Mbps one. It | 461 | * anything, so we ignore the 10Mbps one. It | |
462 | * happens to be configured for MII address 3, | 462 | * happens to be configured for MII address 3, | |
463 | * so we filter that out. | 463 | * so we filter that out. | |
464 | */ | 464 | */ | |
465 | if (sc->aue_vendor == USB_VENDOR_ADMTEK && | 465 | if (sc->aue_vendor == USB_VENDOR_ADMTEK && | |
466 | sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { | 466 | sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { | |
467 | if (phy == 3) { | 467 | if (phy == 3) { | |
468 | *val = 0; | 468 | *val = 0; | |
469 | return EINVAL; | 469 | return EINVAL; | |
470 | } | 470 | } | |
471 | } | 471 | } | |
472 | #endif | 472 | #endif | |
473 | 473 | |||
474 | aue_csr_write_1(sc, AUE_PHY_ADDR, phy); | 474 | aue_csr_write_1(sc, AUE_PHY_ADDR, phy); | |
475 | aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ); | 475 | aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_READ); | |
476 | 476 | |||
477 | for (i = 0; i < AUE_TIMEOUT; i++) { | 477 | for (i = 0; i < AUE_TIMEOUT; i++) { | |
478 | if (usbnet_isdying(un)) { | 478 | if (usbnet_isdying(un)) { | |
479 | *val = 0; | 479 | *val = 0; | |
480 | return ENXIO; | 480 | return ENXIO; | |
481 | } | 481 | } | |
482 | if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) | 482 | if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) | |
483 | break; | 483 | break; | |
484 | } | 484 | } | |
485 | 485 | |||
486 | if (i == AUE_TIMEOUT) { | 486 | if (i == AUE_TIMEOUT) { | |
487 | AUEHIST_CALLARGS("aue%jd: phy=%#jx reg=%#jx read timed out", | 487 | AUEHIST_CALLARGS("aue%jd: phy=%#jx reg=%#jx read timed out", | |
488 | device_unit(un->un_dev), phy, reg, 0); | 488 | device_unit(un->un_dev), phy, reg, 0); | |
489 | *val = 0; | 489 | *val = 0; | |
490 | return ETIMEDOUT; | 490 | return ETIMEDOUT; | |
491 | } | 491 | } | |
492 | 492 | |||
493 | *val = aue_csr_read_2(sc, AUE_PHY_DATA); | 493 | *val = aue_csr_read_2(sc, AUE_PHY_DATA); | |
494 | 494 | |||
495 | AUEHIST_CALLARGSN(11, "aue%jd: phy=%#jx reg=%#jx => 0x%04jx", | 495 | AUEHIST_CALLARGSN(11, "aue%jd: phy=%#jx reg=%#jx => 0x%04jx", | |
496 | device_unit(un->un_dev), phy, reg, *val); | 496 | device_unit(un->un_dev), phy, reg, *val); | |
497 | 497 | |||
498 | return 0; | 498 | return 0; | |
499 | } | 499 | } | |
500 | 500 | |||
501 | static int | 501 | static int | |
502 | aue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 502 | aue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
503 | { | 503 | { | |
504 | struct aue_softc *sc = usbnet_softc(un); | 504 | struct aue_softc *sc = usbnet_softc(un); | |
505 | int i; | 505 | int i; | |
506 | 506 | |||
507 | AUEHIST_FUNC(); | 507 | AUEHIST_FUNC(); | |
508 | AUEHIST_CALLARGSN(11, "aue%jd: phy=%jd reg=%jd data=0x%04jx", | 508 | AUEHIST_CALLARGSN(11, "aue%jd: phy=%jd reg=%jd data=0x%04jx", | |
509 | device_unit(un->un_dev), phy, reg, val); | 509 | device_unit(un->un_dev), phy, reg, val); | |
510 | 510 | |||
511 | #if 0 | 511 | #if 0 | |
512 | if (sc->aue_vendor == USB_VENDOR_ADMTEK && | 512 | if (sc->aue_vendor == USB_VENDOR_ADMTEK && | |
513 | sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { | 513 | sc->aue_product == USB_PRODUCT_ADMTEK_PEGASUS) { | |
514 | if (phy == 3) | 514 | if (phy == 3) | |
515 | return EINVAL; | 515 | return EINVAL; | |
516 | } | 516 | } | |
517 | #endif | 517 | #endif | |
518 | 518 | |||
519 | aue_csr_write_2(sc, AUE_PHY_DATA, val); | 519 | aue_csr_write_2(sc, AUE_PHY_DATA, val); | |
520 | aue_csr_write_1(sc, AUE_PHY_ADDR, phy); | 520 | aue_csr_write_1(sc, AUE_PHY_ADDR, phy); | |
521 | aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE); | 521 | aue_csr_write_1(sc, AUE_PHY_CTL, reg | AUE_PHYCTL_WRITE); | |
522 | 522 | |||
523 | for (i = 0; i < AUE_TIMEOUT; i++) { | 523 | for (i = 0; i < AUE_TIMEOUT; i++) { | |
524 | if (usbnet_isdying(un)) | 524 | if (usbnet_isdying(un)) | |
525 | return ENXIO; | 525 | return ENXIO; | |
526 | if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) | 526 | if (aue_csr_read_1(sc, AUE_PHY_CTL) & AUE_PHYCTL_DONE) | |
527 | break; | 527 | break; | |
528 | } | 528 | } | |
529 | 529 | |||
530 | if (i == AUE_TIMEOUT) { | 530 | if (i == AUE_TIMEOUT) { | |
531 | DPRINTF("aue%jd: phy=%#jx reg=%#jx val=%#jx write timed out", | 531 | DPRINTF("aue%jd: phy=%#jx reg=%#jx val=%#jx write timed out", | |
532 | device_unit(un->un_dev), phy, reg, val); | 532 | device_unit(un->un_dev), phy, reg, val); | |
533 | return ETIMEDOUT; | 533 | return ETIMEDOUT; | |
534 | } | 534 | } | |
535 | 535 | |||
536 | return 0; | 536 | return 0; | |
537 | } | 537 | } | |
538 | 538 | |||
539 | static void | 539 | static void | |
540 | aue_uno_mii_statchg(struct ifnet *ifp) | 540 | aue_uno_mii_statchg(struct ifnet *ifp) | |
541 | { | 541 | { | |
542 | struct usbnet *un = ifp->if_softc; | 542 | struct usbnet *un = ifp->if_softc; | |
543 | struct aue_softc *sc = usbnet_softc(un); | 543 | struct aue_softc *sc = usbnet_softc(un); | |
544 | struct mii_data *mii = usbnet_mii(un); | 544 | struct mii_data *mii = usbnet_mii(un); | |
545 | const bool hadlink __diagused = usbnet_havelink(un); | 545 | const bool hadlink __diagused = usbnet_havelink(un); | |
546 | 546 | |||
547 | AUEHIST_FUNC(); AUEHIST_CALLED(); | 547 | AUEHIST_FUNC(); AUEHIST_CALLED(); | |
548 | AUEHIST_CALLARGSN(5, "aue%jd: ifp=%#jx link=%jd", | 548 | AUEHIST_CALLARGSN(5, "aue%jd: ifp=%#jx link=%jd", | |
549 | device_unit(un->un_dev), (uintptr_t)ifp, hadlink, 0); | 549 | device_unit(un->un_dev), (uintptr_t)ifp, hadlink, 0); | |
550 | 550 | |||
551 | AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); | 551 | AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); | |
552 | 552 | |||
553 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { | 553 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { | |
554 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); | 554 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); | |
555 | } else { | 555 | } else { | |
556 | AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); | 556 | AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_SPEEDSEL); | |
557 | } | 557 | } | |
558 | 558 | |||
559 | if ((mii->mii_media_active & IFM_FDX) != 0) | 559 | if ((mii->mii_media_active & IFM_FDX) != 0) | |
560 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); | 560 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); | |
561 | else | 561 | else | |
562 | AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); | 562 | AUE_CLRBIT(sc, AUE_CTL1, AUE_CTL1_DUPLEX); | |
563 | 563 | |||
564 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); | 564 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_RX_ENB | AUE_CTL0_TX_ENB); | |
565 | 565 | |||
566 | if (mii->mii_media_status & IFM_ACTIVE && | 566 | if (mii->mii_media_status & IFM_ACTIVE && | |
567 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | 567 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | |
568 | usbnet_set_link(un, true); | 568 | usbnet_set_link(un, true); | |
569 | } | 569 | } | |
570 | 570 | |||
571 | /* | 571 | /* | |
572 | * Set the LED modes on the LinkSys adapter. | 572 | * Set the LED modes on the LinkSys adapter. | |
573 | * This turns on the 'dual link LED' bin in the auxmode | 573 | * This turns on the 'dual link LED' bin in the auxmode | |
574 | * register of the Broadcom PHY. | 574 | * register of the Broadcom PHY. | |
575 | */ | 575 | */ | |
576 | if (!usbnet_isdying(un) && (un->un_flags & LSYS)) { | 576 | if (!usbnet_isdying(un) && (un->un_flags & LSYS)) { | |
577 | uint16_t auxmode; | 577 | uint16_t auxmode; | |
578 | aue_uno_mii_read_reg(un, 0, 0x1b, &auxmode); | 578 | aue_uno_mii_read_reg(un, 0, 0x1b, &auxmode); | |
579 | aue_uno_mii_write_reg(un, 0, 0x1b, auxmode | 0x04); | 579 | aue_uno_mii_write_reg(un, 0, 0x1b, auxmode | 0x04); | |
580 | } | 580 | } | |
581 | 581 | |||
582 | if (usbnet_havelink(un) != hadlink) { | 582 | if (usbnet_havelink(un) != hadlink) { | |
583 | DPRINTFN(5, "aue%jd: exit link %jd", | 583 | DPRINTFN(5, "aue%jd: exit link %jd", | |
584 | device_unit(un->un_dev), usbnet_havelink(un), 0, 0); | 584 | device_unit(un->un_dev), usbnet_havelink(un), 0, 0); | |
585 | } | 585 | } | |
586 | } | 586 | } | |
587 | 587 | |||
588 | #define AUE_POLY 0xEDB88320 | 588 | #define AUE_POLY 0xEDB88320 | |
589 | #define AUE_BITS 6 | 589 | #define AUE_BITS 6 | |
590 | 590 | |||
591 | static uint32_t | 591 | static uint32_t | |
592 | aue_crc(void *addrv) | 592 | aue_crc(void *addrv) | |
593 | { | 593 | { | |
594 | uint32_t idx, bit, data, crc; | 594 | uint32_t idx, bit, data, crc; | |
595 | char *addr = addrv; | 595 | char *addr = addrv; | |
596 | 596 | |||
597 | /* Compute CRC for the address value. */ | 597 | /* Compute CRC for the address value. */ | |
598 | crc = 0xFFFFFFFF; /* initial value */ | 598 | crc = 0xFFFFFFFF; /* initial value */ | |
599 | 599 | |||
600 | for (idx = 0; idx < 6; idx++) { | 600 | for (idx = 0; idx < 6; idx++) { | |
601 | for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) | 601 | for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) | |
602 | crc = (crc >> 1) ^ (((crc ^ data) & 1) ? AUE_POLY : 0); | 602 | crc = (crc >> 1) ^ (((crc ^ data) & 1) ? AUE_POLY : 0); | |
603 | } | 603 | } | |
604 | 604 | |||
605 | return crc & ((1 << AUE_BITS) - 1); | 605 | return crc & ((1 << AUE_BITS) - 1); | |
606 | } | 606 | } | |
607 | 607 | |||
608 | static void | 608 | static void | |
609 | aue_uno_mcast(struct ifnet *ifp) | 609 | aue_uno_mcast(struct ifnet *ifp) | |
610 | { | 610 | { | |
611 | struct usbnet * const un = ifp->if_softc; | 611 | struct usbnet * const un = ifp->if_softc; | |
612 | struct aue_softc * const sc = usbnet_softc(un); | 612 | struct aue_softc * const sc = usbnet_softc(un); | |
613 | struct ethercom * ec = usbnet_ec(un); | 613 | struct ethercom * ec = usbnet_ec(un); | |
614 | struct ether_multi *enm; | 614 | struct ether_multi *enm; | |
615 | struct ether_multistep step; | 615 | struct ether_multistep step; | |
616 | uint32_t h = 0, i; | 616 | uint32_t h = 0, i; | |
617 | uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 617 | uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
618 | 618 | |||
619 | AUEHIST_FUNC(); | 619 | AUEHIST_FUNC(); | |
620 | AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | 620 | AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | |
621 | 621 | |||
622 | if (ifp->if_flags & IFF_PROMISC) { | 622 | if (ifp->if_flags & IFF_PROMISC) { | |
623 | ETHER_LOCK(ec); | 623 | ETHER_LOCK(ec); | |
624 | allmulti: | 624 | allmulti: | |
625 | ec->ec_flags |= ETHER_F_ALLMULTI; | 625 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
626 | ETHER_UNLOCK(ec); | 626 | ETHER_UNLOCK(ec); | |
627 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); | 627 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); | |
628 | return; | 628 | return; | |
629 | } | 629 | } | |
630 | 630 | |||
631 | /* now program new ones */ | 631 | /* now program new ones */ | |
632 | ETHER_LOCK(ec); | 632 | ETHER_LOCK(ec); | |
633 | ETHER_FIRST_MULTI(step, ec, enm); | 633 | ETHER_FIRST_MULTI(step, ec, enm); | |
634 | while (enm != NULL) { | 634 | while (enm != NULL) { | |
635 | if (memcmp(enm->enm_addrlo, | 635 | if (memcmp(enm->enm_addrlo, | |
636 | enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { | 636 | enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { | |
637 | goto allmulti; | 637 | goto allmulti; | |
638 | } | 638 | } | |
639 | 639 | |||
640 | h = aue_crc(enm->enm_addrlo); | 640 | h = aue_crc(enm->enm_addrlo); | |
641 | hashtbl[h >> 3] |= 1 << (h & 0x7); | 641 | hashtbl[h >> 3] |= 1 << (h & 0x7); | |
642 | ETHER_NEXT_MULTI(step, enm); | 642 | ETHER_NEXT_MULTI(step, enm); | |
643 | } | 643 | } | |
644 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 644 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
645 | ETHER_UNLOCK(ec); | 645 | ETHER_UNLOCK(ec); | |
646 | 646 | |||
647 | AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); | 647 | AUE_CLRBIT(sc, AUE_CTL0, AUE_CTL0_ALLMULTI); | |
648 | 648 | |||
649 | /* write the hashtable */ | 649 | /* write the hashtable */ | |
650 | for (i = 0; i < 8; i++) | 650 | for (i = 0; i < 8; i++) | |
651 | aue_csr_write_1(sc, AUE_MAR0 + i, hashtbl[i]); | 651 | aue_csr_write_1(sc, AUE_MAR0 + i, hashtbl[i]); | |
652 | } | 652 | } | |
653 | 653 | |||
654 | static void | 654 | static void | |
655 | aue_reset_pegasus_II(struct aue_softc *sc) | 655 | aue_reset_pegasus_II(struct aue_softc *sc) | |
656 | { | 656 | { | |
657 | /* Magic constants taken from Linux driver. */ | 657 | /* Magic constants taken from Linux driver. */ | |
658 | aue_csr_write_1(sc, AUE_REG_1D, 0); | 658 | aue_csr_write_1(sc, AUE_REG_1D, 0); | |
659 | aue_csr_write_1(sc, AUE_REG_7B, 2); | 659 | aue_csr_write_1(sc, AUE_REG_7B, 2); | |
660 | #if 0 | 660 | #if 0 | |
661 | if ((un->un_flags & PNA) && mii_mode) | 661 | if ((un->un_flags & PNA) && mii_mode) | |
662 | aue_csr_write_1(sc, AUE_REG_81, 6); | 662 | aue_csr_write_1(sc, AUE_REG_81, 6); | |
663 | else | 663 | else | |
664 | #endif | 664 | #endif | |
665 | aue_csr_write_1(sc, AUE_REG_81, 2); | 665 | aue_csr_write_1(sc, AUE_REG_81, 2); | |
666 | } | 666 | } | |
667 | 667 | |||
668 | static void | 668 | static void | |
669 | aue_reset(struct aue_softc *sc) | 669 | aue_reset(struct aue_softc *sc) | |
670 | { | 670 | { | |
671 | struct usbnet * const un = &sc->aue_un; | 671 | struct usbnet * const un = &sc->aue_un; | |
672 | int i; | 672 | int i; | |
673 | 673 | |||
674 | AUEHIST_FUNC(); | 674 | AUEHIST_FUNC(); | |
675 | AUEHIST_CALLARGSN(2, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | 675 | AUEHIST_CALLARGSN(2, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | |
676 | 676 | |||
677 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC); | 677 | AUE_SETBIT(sc, AUE_CTL1, AUE_CTL1_RESETMAC); | |
678 | 678 | |||
679 | for (i = 0; i < AUE_TIMEOUT; i++) { | 679 | for (i = 0; i < AUE_TIMEOUT; i++) { | |
680 | if (usbnet_isdying(un)) | 680 | if (usbnet_isdying(un)) | |
681 | return; | 681 | return; | |
682 | if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC)) | 682 | if (!(aue_csr_read_1(sc, AUE_CTL1) & AUE_CTL1_RESETMAC)) | |
683 | break; | 683 | break; | |
684 | } | 684 | } | |
685 | 685 | |||
686 | if (i == AUE_TIMEOUT) | 686 | if (i == AUE_TIMEOUT) | |
687 | printf("%s: reset failed\n", device_xname(un->un_dev)); | 687 | printf("%s: reset failed\n", device_xname(un->un_dev)); | |
688 | 688 | |||
689 | #if 0 | 689 | #if 0 | |
690 | /* XXX what is mii_mode supposed to be */ | 690 | /* XXX what is mii_mode supposed to be */ | |
691 | if (sc->sc_mii_mode && (un->un_flags & PNA)) | 691 | if (sc->sc_mii_mode && (un->un_flags & PNA)) | |
692 | aue_csr_write_1(sc, AUE_GPIO1, 0x34); | 692 | aue_csr_write_1(sc, AUE_GPIO1, 0x34); | |
693 | else | 693 | else | |
694 | aue_csr_write_1(sc, AUE_GPIO1, 0x26); | 694 | aue_csr_write_1(sc, AUE_GPIO1, 0x26); | |
695 | #endif | 695 | #endif | |
696 | 696 | |||
697 | /* | 697 | /* | |
698 | * The PHY(s) attached to the Pegasus chip may be held | 698 | * The PHY(s) attached to the Pegasus chip may be held | |
699 | * in reset until we flip on the GPIO outputs. Make sure | 699 | * in reset until we flip on the GPIO outputs. Make sure | |
700 | * to set the GPIO pins high so that the PHY(s) will | 700 | * to set the GPIO pins high so that the PHY(s) will | |
701 | * be enabled. | 701 | * be enabled. | |
702 | * | 702 | * | |
703 | * Note: We force all of the GPIO pins low first, *then* | 703 | * Note: We force all of the GPIO pins low first, *then* | |
704 | * enable the ones we want. | 704 | * enable the ones we want. | |
705 | */ | 705 | */ | |
706 | if (un->un_flags & LSYS) { | 706 | if (un->un_flags & LSYS) { | |
707 | /* Grrr. LinkSys has to be different from everyone else. */ | 707 | /* Grrr. LinkSys has to be different from everyone else. */ | |
708 | aue_csr_write_1(sc, AUE_GPIO0, | 708 | aue_csr_write_1(sc, AUE_GPIO0, | |
709 | AUE_GPIO_SEL0 | AUE_GPIO_SEL1); | 709 | AUE_GPIO_SEL0 | AUE_GPIO_SEL1); | |
710 | } else { | 710 | } else { | |
711 | aue_csr_write_1(sc, AUE_GPIO0, | 711 | aue_csr_write_1(sc, AUE_GPIO0, | |
712 | AUE_GPIO_OUT0 | AUE_GPIO_SEL0); | 712 | AUE_GPIO_OUT0 | AUE_GPIO_SEL0); | |
713 | } | 713 | } | |
714 | aue_csr_write_1(sc, AUE_GPIO0, | 714 | aue_csr_write_1(sc, AUE_GPIO0, | |
715 | AUE_GPIO_OUT0 | AUE_GPIO_SEL0 | AUE_GPIO_SEL1); | 715 | AUE_GPIO_OUT0 | AUE_GPIO_SEL0 | AUE_GPIO_SEL1); | |
716 | 716 | |||
717 | if (un->un_flags & PII) | 717 | if (un->un_flags & PII) | |
718 | aue_reset_pegasus_II(sc); | 718 | aue_reset_pegasus_II(sc); | |
719 | 719 | |||
720 | /* Wait a little while for the chip to get its brains in order. */ | 720 | /* Wait a little while for the chip to get its brains in order. */ | |
721 | delay(10000); /* XXX */ | 721 | delay(10000); /* XXX */ | |
722 | //usbd_delay_ms(un->un_udev, 10); /* XXX */ | 722 | //usbd_delay_ms(un->un_udev, 10); /* XXX */ | |
723 | 723 | |||
724 | DPRINTFN(2, "aue%jd: exit", device_unit(un->un_dev), 0, 0, 0); | 724 | DPRINTFN(2, "aue%jd: exit", device_unit(un->un_dev), 0, 0, 0); | |
725 | } | 725 | } | |
726 | 726 | |||
727 | /* | 727 | /* | |
728 | * Probe for a Pegasus chip. | 728 | * Probe for a Pegasus chip. | |
729 | */ | 729 | */ | |
730 | static int | 730 | static int | |
731 | aue_match(device_t parent, cfdata_t match, void *aux) | 731 | aue_match(device_t parent, cfdata_t match, void *aux) | |
732 | { | 732 | { | |
733 | struct usb_attach_arg *uaa = aux; | 733 | struct usb_attach_arg *uaa = aux; | |
734 | 734 | |||
735 | /* | 735 | /* | |
736 | * Some manufacturers use the same vendor and product id for | 736 | * Some manufacturers use the same vendor and product id for | |
737 | * different devices. We need to sanity check the DeviceClass | 737 | * different devices. We need to sanity check the DeviceClass | |
738 | * in this case | 738 | * in this case | |
739 | * Currently known guilty products: | 739 | * Currently known guilty products: | |
740 | * 0x050d/0x0121 Belkin Bluetooth and USB2LAN | 740 | * 0x050d/0x0121 Belkin Bluetooth and USB2LAN | |
741 | * | 741 | * | |
742 | * If this turns out to be more common, we could use a quirk | 742 | * If this turns out to be more common, we could use a quirk | |
743 | * table. | 743 | * table. | |
744 | */ | 744 | */ | |
745 | if (uaa->uaa_vendor == USB_VENDOR_BELKIN && | 745 | if (uaa->uaa_vendor == USB_VENDOR_BELKIN && | |
746 | uaa->uaa_product == USB_PRODUCT_BELKIN_USB2LAN) { | 746 | uaa->uaa_product == USB_PRODUCT_BELKIN_USB2LAN) { | |
747 | usb_device_descriptor_t *dd; | 747 | usb_device_descriptor_t *dd; | |
748 | 748 | |||
749 | dd = usbd_get_device_descriptor(uaa->uaa_device); | 749 | dd = usbd_get_device_descriptor(uaa->uaa_device); | |
750 | if (dd != NULL && | 750 | if (dd != NULL && | |
751 | dd->bDeviceClass != UDCLASS_IN_INTERFACE) | 751 | dd->bDeviceClass != UDCLASS_IN_INTERFACE) | |
752 | return UMATCH_NONE; | 752 | return UMATCH_NONE; | |
753 | } | 753 | } | |
754 | 754 | |||
755 | return aue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 755 | return aue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
756 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 756 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
757 | } | 757 | } | |
758 | 758 | |||
759 | /* | 759 | /* | |
760 | * Attach the interface. Allocate softc structures, do ifmedia | 760 | * Attach the interface. Allocate softc structures, do ifmedia | |
761 | * setup and ethernet/BPF attach. | 761 | * setup and ethernet/BPF attach. | |
762 | */ | 762 | */ | |
763 | static void | 763 | static void | |
764 | aue_attach(device_t parent, device_t self, void *aux) | 764 | aue_attach(device_t parent, device_t self, void *aux) | |
765 | { | 765 | { | |
766 | USBNET_MII_DECL_DEFAULT(unm); | 766 | USBNET_MII_DECL_DEFAULT(unm); | |
767 | struct aue_softc * const sc = device_private(self); | 767 | struct aue_softc * const sc = device_private(self); | |
768 | struct usbnet * const un = &sc->aue_un; | 768 | struct usbnet * const un = &sc->aue_un; | |
769 | struct usb_attach_arg *uaa = aux; | 769 | struct usb_attach_arg *uaa = aux; | |
770 | char *devinfop; | 770 | char *devinfop; | |
771 | struct usbd_device *dev = uaa->uaa_device; | 771 | struct usbd_device *dev = uaa->uaa_device; | |
772 | usbd_status err; | 772 | usbd_status err; | |
773 | usb_interface_descriptor_t *id; | 773 | usb_interface_descriptor_t *id; | |
774 | usb_endpoint_descriptor_t *ed; | 774 | usb_endpoint_descriptor_t *ed; | |
775 | int i; | 775 | int i; | |
776 | 776 | |||
777 | AUEHIST_FUNC(); | 777 | AUEHIST_FUNC(); | |
778 | AUEHIST_CALLARGSN(2, "aue%jd: enter sc=%#jx", | 778 | AUEHIST_CALLARGSN(2, "aue%jd: enter sc=%#jx", | |
779 | device_unit(self), (uintptr_t)sc, 0, 0); | 779 | device_unit(self), (uintptr_t)sc, 0, 0); | |
780 | 780 | |||
781 | KASSERT((void *)sc == un); | 781 | KASSERT((void *)sc == un); | |
782 | 782 | |||
783 | aprint_naive("\n"); | 783 | aprint_naive("\n"); | |
784 | aprint_normal("\n"); | 784 | aprint_normal("\n"); | |
785 | devinfop = usbd_devinfo_alloc(uaa->uaa_device, 0); | 785 | devinfop = usbd_devinfo_alloc(uaa->uaa_device, 0); | |
786 | aprint_normal_dev(self, "%s\n", devinfop); | 786 | aprint_normal_dev(self, "%s\n", devinfop); | |
787 | usbd_devinfo_free(devinfop); | 787 | usbd_devinfo_free(devinfop); | |
788 | 788 | |||
789 | un->un_dev = self; | 789 | un->un_dev = self; | |
790 | un->un_udev = dev; | 790 | un->un_udev = dev; | |
791 | un->un_sc = sc; | 791 | un->un_sc = sc; | |
792 | un->un_ops = &aue_ops; | 792 | un->un_ops = &aue_ops; | |
793 | un->un_intr = &sc->aue_intr; | 793 | un->un_intr = &sc->aue_intr; | |
794 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 794 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
795 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 795 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
796 | un->un_rx_list_cnt = AUE_RX_LIST_CNT; | 796 | un->un_rx_list_cnt = AUE_RX_LIST_CNT; | |
797 | un->un_tx_list_cnt = AUE_RX_LIST_CNT; | 797 | un->un_tx_list_cnt = AUE_RX_LIST_CNT; | |
798 | un->un_rx_bufsz = AUE_BUFSZ; | 798 | un->un_rx_bufsz = AUE_BUFSZ; | |
799 | un->un_tx_bufsz = AUE_BUFSZ; | 799 | un->un_tx_bufsz = AUE_BUFSZ; | |
800 | 800 | |||
801 | sc->aue_intr.uni_buf = &sc->aue_ibuf; | 801 | sc->aue_intr.uni_buf = &sc->aue_ibuf; | |
802 | sc->aue_intr.uni_bufsz = sizeof(sc->aue_ibuf); | 802 | sc->aue_intr.uni_bufsz = sizeof(sc->aue_ibuf); | |
803 | sc->aue_intr.uni_interval = AUE_INTR_INTERVAL; | 803 | sc->aue_intr.uni_interval = AUE_INTR_INTERVAL; | |
804 | 804 | |||
805 | err = usbd_set_config_no(dev, AUE_CONFIG_NO, 1); | 805 | err = usbd_set_config_no(dev, AUE_CONFIG_NO, 1); | |
806 | if (err) { | 806 | if (err) { | |
807 | aprint_error_dev(self, "failed to set configuration" | 807 | aprint_error_dev(self, "failed to set configuration" | |
808 | ", err=%s\n", usbd_errstr(err)); | 808 | ", err=%s\n", usbd_errstr(err)); | |
809 | return; | 809 | return; | |
810 | } | 810 | } | |
811 | 811 | |||
812 | err = usbd_device2interface_handle(dev, AUE_IFACE_IDX, &un->un_iface); | 812 | err = usbd_device2interface_handle(dev, AUE_IFACE_IDX, &un->un_iface); | |
813 | if (err) { | 813 | if (err) { | |
814 | aprint_error_dev(self, "getting interface handle failed\n"); | 814 | aprint_error_dev(self, "getting interface handle failed\n"); | |
815 | return; | 815 | return; | |
816 | } | 816 | } | |
817 | 817 | |||
818 | un->un_flags = aue_lookup(uaa->uaa_vendor, uaa->uaa_product)->aue_flags; | 818 | un->un_flags = aue_lookup(uaa->uaa_vendor, uaa->uaa_product)->aue_flags; | |
819 | 819 | |||
820 | id = usbd_get_interface_descriptor(un->un_iface); | 820 | id = usbd_get_interface_descriptor(un->un_iface); | |
821 | 821 | |||
822 | /* Find endpoints. */ | 822 | /* Find endpoints. */ | |
823 | for (i = 0; i < id->bNumEndpoints; i++) { | 823 | for (i = 0; i < id->bNumEndpoints; i++) { | |
824 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 824 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
825 | if (ed == NULL) { | 825 | if (ed == NULL) { | |
826 | aprint_error_dev(self, | 826 | aprint_error_dev(self, | |
827 | "couldn't get endpoint descriptor %d\n", i); | 827 | "couldn't get endpoint descriptor %d\n", i); | |
828 | return; | 828 | return; | |
829 | } | 829 | } | |
830 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 830 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
831 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 831 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
832 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 832 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
833 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 833 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
834 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 834 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
835 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 835 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
836 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 836 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
837 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 837 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
838 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 838 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
839 | } | 839 | } | |
840 | } | 840 | } | |
841 | 841 | |||
842 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 842 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
843 | un->un_ed[USBNET_ENDPT_TX] == 0 || | 843 | un->un_ed[USBNET_ENDPT_TX] == 0 || | |
844 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | 844 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | |
845 | aprint_error_dev(self, "missing endpoint\n"); | 845 | aprint_error_dev(self, "missing endpoint\n"); | |
846 | return; | 846 | return; | |
847 | } | 847 | } | |
848 | 848 | |||
849 | /* First level attach. */ | 849 | /* First level attach. */ | |
850 | usbnet_attach(un, "auedet"); | 850 | usbnet_attach(un, "auedet"); | |
851 | 851 | |||
852 | /* Reset the adapter and get station address from the EEPROM. */ | 852 | /* Reset the adapter and get station address from the EEPROM. */ | |
853 | aue_reset(sc); | 853 | aue_reset(sc); | |
854 | aue_read_mac(un); | 854 | aue_read_mac(un); | |
855 | 855 | |||
856 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 856 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
857 | 0, &unm); | 857 | 0, &unm); | |
858 | } | 858 | } | |
859 | 859 | |||
860 | static void | 860 | static void | |
861 | aue_uno_intr(struct usbnet *un, usbd_status status) | 861 | aue_uno_intr(struct usbnet *un, usbd_status status) | |
862 | { | 862 | { | |
863 | struct ifnet *ifp = usbnet_ifp(un); | 863 | struct ifnet *ifp = usbnet_ifp(un); | |
864 | struct aue_softc *sc = usbnet_softc(un); | 864 | struct aue_softc *sc = usbnet_softc(un); | |
865 | struct aue_intrpkt *p = &sc->aue_ibuf; | 865 | struct aue_intrpkt *p = &sc->aue_ibuf; | |
866 | 866 | |||
867 | AUEHIST_FUNC(); | 867 | AUEHIST_FUNC(); | |
868 | AUEHIST_CALLARGSN(20, "aue%jd: enter txstat0 %#jx\n", | 868 | AUEHIST_CALLARGSN(20, "aue%jd: enter txstat0 %#jx\n", | |
869 | device_unit(un->un_dev), p->aue_txstat0, 0, 0); | 869 | device_unit(un->un_dev), p->aue_txstat0, 0, 0); | |
870 | 870 | |||
871 | if (p->aue_txstat0) | 871 | if (p->aue_txstat0) | |
872 | if_statinc(ifp, if_oerrors); | 872 | if_statinc(ifp, if_oerrors); | |
873 | 873 | |||
874 | if (p->aue_txstat0 & (AUE_TXSTAT0_LATECOLL | AUE_TXSTAT0_EXCESSCOLL)) | 874 | if (p->aue_txstat0 & (AUE_TXSTAT0_LATECOLL | AUE_TXSTAT0_EXCESSCOLL)) | |
875 | if_statinc(ifp, if_collisions); | 875 | if_statinc(ifp, if_collisions); | |
876 | } | 876 | } | |
877 | 877 | |||
878 | static void | 878 | static void | |
879 | aue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 879 | aue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
880 | { | 880 | { | |
881 | struct ifnet *ifp = usbnet_ifp(un); | 881 | struct ifnet *ifp = usbnet_ifp(un); | |
882 | uint8_t *buf = c->unc_buf; | 882 | uint8_t *buf = c->unc_buf; | |
883 | struct aue_rxpkt r; | 883 | struct aue_rxpkt r; | |
884 | uint32_t pktlen; | 884 | uint32_t pktlen; | |
885 | 885 | |||
886 | AUEHIST_FUNC(); | 886 | AUEHIST_FUNC(); | |
887 | AUEHIST_CALLARGSN(10, "aue%jd: enter len %ju", | 887 | AUEHIST_CALLARGSN(10, "aue%jd: enter len %ju", | |
888 | device_unit(un->un_dev), total_len, 0, 0); | 888 | device_unit(un->un_dev), total_len, 0, 0); | |
889 | 889 | |||
890 | if (total_len <= 4 + ETHER_CRC_LEN) { | 890 | if (total_len <= 4 + ETHER_CRC_LEN) { | |
891 | if_statinc(ifp, if_ierrors); | 891 | if_statinc(ifp, if_ierrors); | |
892 | return; | 892 | return; | |
893 | } | 893 | } | |
894 | 894 | |||
895 | memcpy(&r, buf + total_len - 4, sizeof(r)); | 895 | memcpy(&r, buf + total_len - 4, sizeof(r)); | |
896 | 896 | |||
897 | /* Turn off all the non-error bits in the rx status word. */ | 897 | /* Turn off all the non-error bits in the rx status word. */ | |
898 | r.aue_rxstat &= AUE_RXSTAT_MASK; | 898 | r.aue_rxstat &= AUE_RXSTAT_MASK; | |
899 | if (r.aue_rxstat) { | 899 | if (r.aue_rxstat) { | |
900 | if_statinc(ifp, if_ierrors); | 900 | if_statinc(ifp, if_ierrors); | |
901 | return; | 901 | return; | |
902 | } | 902 | } | |
903 | 903 | |||
904 | /* No errors; receive the packet. */ | 904 | /* No errors; receive the packet. */ | |
905 | pktlen = total_len - ETHER_CRC_LEN - 4; | 905 | pktlen = total_len - ETHER_CRC_LEN - 4; | |
906 | 906 | |||
907 | usbnet_enqueue(un, buf, pktlen, 0, 0, 0); | 907 | usbnet_enqueue(un, buf, pktlen, 0, 0, 0); | |
908 | } | 908 | } | |
909 | 909 | |||
910 | static unsigned | 910 | static unsigned | |
911 | aue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 911 | aue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
912 | { | 912 | { | |
913 | uint8_t *buf = c->unc_buf; | 913 | uint8_t *buf = c->unc_buf; | |
914 | int total_len; | 914 | int total_len; | |
915 | 915 | |||
916 | AUEHIST_FUNC(); | 916 | AUEHIST_FUNC(); | |
917 | AUEHIST_CALLARGSN(10, "aue%jd: enter pktlen=%jd", | 917 | AUEHIST_CALLARGSN(10, "aue%jd: enter pktlen=%jd", | |
918 | device_unit(un->un_dev), m->m_pkthdr.len, 0, 0); | 918 | device_unit(un->un_dev), m->m_pkthdr.len, 0, 0); | |
919 | 919 | |||
920 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | 920 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | |
921 | return 0; | 921 | return 0; | |
922 | 922 | |||
923 | /* | 923 | /* | |
924 | * Copy the mbuf data into a contiguous buffer, leaving two | 924 | * Copy the mbuf data into a contiguous buffer, leaving two | |
925 | * bytes at the beginning to hold the frame length. | 925 | * bytes at the beginning to hold the frame length. | |
926 | */ | 926 | */ | |
927 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | 927 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | |
928 | 928 | |||
929 | /* | 929 | /* | |
930 | * The ADMtek documentation says that the packet length is | 930 | * The ADMtek documentation says that the packet length is | |
931 | * supposed to be specified in the first two bytes of the | 931 | * supposed to be specified in the first two bytes of the | |
932 | * transfer, however it actually seems to ignore this info | 932 | * transfer, however it actually seems to ignore this info | |
933 | * and base the frame size on the bulk transfer length. | 933 | * and base the frame size on the bulk transfer length. | |
934 | */ | 934 | */ | |
935 | buf[0] = (uint8_t)m->m_pkthdr.len; | 935 | buf[0] = (uint8_t)m->m_pkthdr.len; | |
936 | buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); | 936 | buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); | |
937 | total_len = m->m_pkthdr.len + 2; | 937 | total_len = m->m_pkthdr.len + 2; | |
938 | 938 | |||
939 | DPRINTFN(5, "aue%jd: send %jd bytes", | 939 | DPRINTFN(5, "aue%jd: send %jd bytes", | |
940 | device_unit(un->un_dev), total_len, 0, 0); | 940 | device_unit(un->un_dev), total_len, 0, 0); | |
941 | 941 | |||
942 | return total_len; | 942 | return total_len; | |
943 | } | 943 | } | |
944 | 944 | |||
945 | static int | 945 | static int | |
946 | aue_uno_init(struct ifnet *ifp) | 946 | aue_uno_init(struct ifnet *ifp) | |
947 | { | 947 | { | |
948 | struct usbnet * const un = ifp->if_softc; | 948 | struct usbnet * const un = ifp->if_softc; | |
949 | struct aue_softc *sc = usbnet_softc(un); | 949 | struct aue_softc *sc = usbnet_softc(un); | |
950 | int i; | 950 | int i; | |
951 | const u_char *eaddr; | 951 | const u_char *eaddr; | |
952 | 952 | |||
953 | AUEHIST_FUNC(); | 953 | AUEHIST_FUNC(); | |
954 | AUEHIST_CALLARGSN(5, "aue%jd: enter link=%jd", | 954 | AUEHIST_CALLARGSN(5, "aue%jd: enter link=%jd", | |
955 | device_unit(un->un_dev), usbnet_havelink(un), 0, 0); | 955 | device_unit(un->un_dev), usbnet_havelink(un), 0, 0); | |
956 | 956 | |||
957 | if (usbnet_isdying(un)) | |||
958 | return EIO; | |||
959 | ||||
960 | /* Cancel pending I/O */ | 957 | /* Cancel pending I/O */ | |
961 | if (ifp->if_flags & IFF_RUNNING) | 958 | if (ifp->if_flags & IFF_RUNNING) | |
962 | return 0; | 959 | return 0; | |
963 | 960 | |||
964 | /* Reset the interface. */ | 961 | /* Reset the interface. */ | |
965 | aue_reset(sc); | 962 | aue_reset(sc); | |
966 | 963 | |||
967 | eaddr = CLLADDR(ifp->if_sadl); | 964 | eaddr = CLLADDR(ifp->if_sadl); | |
968 | for (i = 0; i < ETHER_ADDR_LEN; i++) | 965 | for (i = 0; i < ETHER_ADDR_LEN; i++) | |
969 | aue_csr_write_1(sc, AUE_PAR0 + i, eaddr[i]); | 966 | aue_csr_write_1(sc, AUE_PAR0 + i, eaddr[i]); | |
970 | 967 | |||
971 | /* If we want promiscuous mode, set the allframes bit. */ | 968 | /* If we want promiscuous mode, set the allframes bit. */ | |
972 | if (ifp->if_flags & IFF_PROMISC) | 969 | if (ifp->if_flags & IFF_PROMISC) | |
973 | AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); | 970 | AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); | |
974 | else | 971 | else | |
975 | AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); | 972 | AUE_CLRBIT(sc, AUE_CTL2, AUE_CTL2_RX_PROMISC); | |
976 | 973 | |||
977 | /* Enable RX and TX */ | 974 | /* Enable RX and TX */ | |
978 | aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB); | 975 | aue_csr_write_1(sc, AUE_CTL0, AUE_CTL0_RXSTAT_APPEND | AUE_CTL0_RX_ENB); | |
979 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_TX_ENB); | 976 | AUE_SETBIT(sc, AUE_CTL0, AUE_CTL0_TX_ENB); | |
980 | AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_EP3_CLR); | 977 | AUE_SETBIT(sc, AUE_CTL2, AUE_CTL2_EP3_CLR); | |
981 | 978 | |||
982 | return usbnet_init_rx_tx(un); | 979 | return usbnet_init_rx_tx(un); | |
983 | } | 980 | } | |
984 | 981 | |||
985 | static void | 982 | static void | |
986 | aue_uno_stop(struct ifnet *ifp, int disable) | 983 | aue_uno_stop(struct ifnet *ifp, int disable) | |
987 | { | 984 | { | |
988 | struct usbnet * const un = ifp->if_softc; | 985 | struct usbnet * const un = ifp->if_softc; | |
989 | struct aue_softc * const sc = usbnet_softc(un); | 986 | struct aue_softc * const sc = usbnet_softc(un); | |
990 | 987 | |||
991 | AUEHIST_FUNC(); | 988 | AUEHIST_FUNC(); | |
992 | AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | 989 | AUEHIST_CALLARGSN(5, "aue%jd: enter", device_unit(un->un_dev), 0, 0, 0); | |
993 | 990 | |||
994 | aue_csr_write_1(sc, AUE_CTL0, 0); | 991 | aue_csr_write_1(sc, AUE_CTL0, 0); | |
995 | aue_csr_write_1(sc, AUE_CTL1, 0); | 992 | aue_csr_write_1(sc, AUE_CTL1, 0); | |
996 | aue_reset(sc); | 993 | aue_reset(sc); | |
997 | } | 994 | } | |
998 | 995 | |||
999 | #ifdef _MODULE | 996 | #ifdef _MODULE | |
1000 | #include "ioconf.c" | 997 | #include "ioconf.c" | |
1001 | #endif | 998 | #endif | |
1002 | 999 | |||
1003 | USBNET_MODULE(aue) | 1000 | USBNET_MODULE(aue) |
--- src/sys/dev/usb/if_axe.c 2022/03/03 05:54:37 1.145
+++ src/sys/dev/usb/if_axe.c 2022/03/03 05:55:01 1.146
@@ -1,1310 +1,1307 @@ | @@ -1,1310 +1,1307 @@ | |||
1 | /* $NetBSD: if_axe.c,v 1.145 2022/03/03 05:54:37 riastradh Exp $ */ | 1 | /* $NetBSD: if_axe.c,v 1.146 2022/03/03 05:55:01 riastradh Exp $ */ | |
2 | /* $OpenBSD: if_axe.c,v 1.137 2016/04/13 11:03:37 mpi Exp $ */ | 2 | /* $OpenBSD: if_axe.c,v 1.137 2016/04/13 11:03:37 mpi Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org> | 5 | * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg@openbsd.org> | |
6 | * | 6 | * | |
7 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any | |
8 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above | |
9 | * copyright notice and this permission notice appear in all copies. | 9 | * copyright notice and this permission notice appear in all copies. | |
10 | * | 10 | * | |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
18 | */ | 18 | */ | |
19 | 19 | |||
20 | /* | 20 | /* | |
21 | * Copyright (c) 1997, 1998, 1999, 2000-2003 | 21 | * Copyright (c) 1997, 1998, 1999, 2000-2003 | |
22 | * Bill Paul <wpaul@windriver.com>. All rights reserved. | 22 | * Bill Paul <wpaul@windriver.com>. All rights reserved. | |
23 | * | 23 | * | |
24 | * Redistribution and use in source and binary forms, with or without | 24 | * Redistribution and use in source and binary forms, with or without | |
25 | * modification, are permitted provided that the following conditions | 25 | * modification, are permitted provided that the following conditions | |
26 | * are met: | 26 | * are met: | |
27 | * 1. Redistributions of source code must retain the above copyright | 27 | * 1. Redistributions of source code must retain the above copyright | |
28 | * notice, this list of conditions and the following disclaimer. | 28 | * notice, this list of conditions and the following disclaimer. | |
29 | * 2. Redistributions in binary form must reproduce the above copyright | 29 | * 2. Redistributions in binary form must reproduce the above copyright | |
30 | * notice, this list of conditions and the following disclaimer in the | 30 | * notice, this list of conditions and the following disclaimer in the | |
31 | * documentation and/or other materials provided with the distribution. | 31 | * documentation and/or other materials provided with the distribution. | |
32 | * 3. All advertising materials mentioning features or use of this software | 32 | * 3. All advertising materials mentioning features or use of this software | |
33 | * must display the following acknowledgement: | 33 | * must display the following acknowledgement: | |
34 | * This product includes software developed by Bill Paul. | 34 | * This product includes software developed by Bill Paul. | |
35 | * 4. Neither the name of the author nor the names of any co-contributors | 35 | * 4. Neither the name of the author nor the names of any co-contributors | |
36 | * may be used to endorse or promote products derived from this software | 36 | * may be used to endorse or promote products derived from this software | |
37 | * without specific prior written permission. | 37 | * without specific prior written permission. | |
38 | * | 38 | * | |
39 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | 39 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | |
40 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 40 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 41 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
42 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | 42 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | |
43 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 43 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
44 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 44 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
45 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 45 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
46 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 46 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
47 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 47 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
48 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 48 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
49 | * THE POSSIBILITY OF SUCH DAMAGE. | 49 | * THE POSSIBILITY OF SUCH DAMAGE. | |
50 | */ | 50 | */ | |
51 | 51 | |||
52 | /* | 52 | /* | |
53 | * ASIX Electronics AX88172/AX88178/AX88778 USB 2.0 ethernet driver. | 53 | * ASIX Electronics AX88172/AX88178/AX88778 USB 2.0 ethernet driver. | |
54 | * Used in the LinkSys USB200M and various other adapters. | 54 | * Used in the LinkSys USB200M and various other adapters. | |
55 | * | 55 | * | |
56 | * Written by Bill Paul <wpaul@windriver.com> | 56 | * Written by Bill Paul <wpaul@windriver.com> | |
57 | * Senior Engineer | 57 | * Senior Engineer | |
58 | * Wind River Systems | 58 | * Wind River Systems | |
59 | */ | 59 | */ | |
60 | 60 | |||
61 | /* | 61 | /* | |
62 | * The AX88172 provides USB ethernet supports at 10 and 100Mbps. | 62 | * The AX88172 provides USB ethernet supports at 10 and 100Mbps. | |
63 | * It uses an external PHY (reference designs use a RealTek chip), | 63 | * It uses an external PHY (reference designs use a RealTek chip), | |
64 | * and has a 64-bit multicast hash filter. There is some information | 64 | * and has a 64-bit multicast hash filter. There is some information | |
65 | * missing from the manual which one needs to know in order to make | 65 | * missing from the manual which one needs to know in order to make | |
66 | * the chip function: | 66 | * the chip function: | |
67 | * | 67 | * | |
68 | * - You must set bit 7 in the RX control register, otherwise the | 68 | * - You must set bit 7 in the RX control register, otherwise the | |
69 | * chip won't receive any packets. | 69 | * chip won't receive any packets. | |
70 | * - You must initialize all 3 IPG registers, or you won't be able | 70 | * - You must initialize all 3 IPG registers, or you won't be able | |
71 | * to send any packets. | 71 | * to send any packets. | |
72 | * | 72 | * | |
73 | * Note that this device appears to only support loading the station | 73 | * Note that this device appears to only support loading the station | |
74 | * address via autoload from the EEPROM (i.e. there's no way to manually | 74 | * address via autoload from the EEPROM (i.e. there's no way to manually | |
75 | * set it). | 75 | * set it). | |
76 | * | 76 | * | |
77 | * (Adam Weinberger wanted me to name this driver if_gir.c.) | 77 | * (Adam Weinberger wanted me to name this driver if_gir.c.) | |
78 | */ | 78 | */ | |
79 | 79 | |||
80 | /* | 80 | /* | |
81 | * Ax88178 and Ax88772 support backported from the OpenBSD driver. | 81 | * Ax88178 and Ax88772 support backported from the OpenBSD driver. | |
82 | * 2007/02/12, J.R. Oldroyd, fbsd@opal.com | 82 | * 2007/02/12, J.R. Oldroyd, fbsd@opal.com | |
83 | * | 83 | * | |
84 | * Manual here: | 84 | * Manual here: | |
85 | * http://www.asix.com.tw/FrootAttach/datasheet/AX88178_datasheet_Rev10.pdf | 85 | * http://www.asix.com.tw/FrootAttach/datasheet/AX88178_datasheet_Rev10.pdf | |
86 | * http://www.asix.com.tw/FrootAttach/datasheet/AX88772_datasheet_Rev10.pdf | 86 | * http://www.asix.com.tw/FrootAttach/datasheet/AX88772_datasheet_Rev10.pdf | |
87 | */ | 87 | */ | |
88 | 88 | |||
89 | #include <sys/cdefs.h> | 89 | #include <sys/cdefs.h> | |
90 | __KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1.145 2022/03/03 05:54:37 riastradh Exp $"); | 90 | __KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1.146 2022/03/03 05:55:01 riastradh Exp $"); | |
91 | 91 | |||
92 | #ifdef _KERNEL_OPT | 92 | #ifdef _KERNEL_OPT | |
93 | #include "opt_usb.h" | 93 | #include "opt_usb.h" | |
94 | #include "opt_net_mpsafe.h" | 94 | #include "opt_net_mpsafe.h" | |
95 | #endif | 95 | #endif | |
96 | 96 | |||
97 | #include <sys/param.h> | 97 | #include <sys/param.h> | |
98 | 98 | |||
99 | #include <dev/usb/usbnet.h> | 99 | #include <dev/usb/usbnet.h> | |
100 | #include <dev/usb/usbhist.h> | 100 | #include <dev/usb/usbhist.h> | |
101 | #include <dev/usb/if_axereg.h> | 101 | #include <dev/usb/if_axereg.h> | |
102 | 102 | |||
103 | struct axe_type { | 103 | struct axe_type { | |
104 | struct usb_devno axe_dev; | 104 | struct usb_devno axe_dev; | |
105 | uint16_t axe_flags; | 105 | uint16_t axe_flags; | |
106 | }; | 106 | }; | |
107 | 107 | |||
108 | struct axe_softc { | 108 | struct axe_softc { | |
109 | struct usbnet axe_un; | 109 | struct usbnet axe_un; | |
110 | 110 | |||
111 | /* usbnet:un_flags values */ | 111 | /* usbnet:un_flags values */ | |
112 | #define AX178 __BIT(0) /* AX88178 */ | 112 | #define AX178 __BIT(0) /* AX88178 */ | |
113 | #define AX772 __BIT(1) /* AX88772 */ | 113 | #define AX772 __BIT(1) /* AX88772 */ | |
114 | #define AX772A __BIT(2) /* AX88772A */ | 114 | #define AX772A __BIT(2) /* AX88772A */ | |
115 | #define AX772B __BIT(3) /* AX88772B */ | 115 | #define AX772B __BIT(3) /* AX88772B */ | |
116 | #define AXSTD_FRAME __BIT(12) | 116 | #define AXSTD_FRAME __BIT(12) | |
117 | #define AXCSUM_FRAME __BIT(13) | 117 | #define AXCSUM_FRAME __BIT(13) | |
118 | 118 | |||
119 | uint8_t axe_ipgs[3]; | 119 | uint8_t axe_ipgs[3]; | |
120 | uint8_t axe_phyaddrs[2]; | 120 | uint8_t axe_phyaddrs[2]; | |
121 | uint16_t sc_pwrcfg; | 121 | uint16_t sc_pwrcfg; | |
122 | uint16_t sc_lenmask; | 122 | uint16_t sc_lenmask; | |
123 | 123 | |||
124 | }; | 124 | }; | |
125 | 125 | |||
126 | #define AXE_IS_178_FAMILY(un) \ | 126 | #define AXE_IS_178_FAMILY(un) \ | |
127 | ((un)->un_flags & (AX178 | AX772 | AX772A | AX772B)) | 127 | ((un)->un_flags & (AX178 | AX772 | AX772A | AX772B)) | |
128 | 128 | |||
129 | #define AXE_IS_772(un) \ | 129 | #define AXE_IS_772(un) \ | |
130 | ((un)->un_flags & (AX772 | AX772A | AX772B)) | 130 | ((un)->un_flags & (AX772 | AX772A | AX772B)) | |
131 | 131 | |||
132 | #define AXE_IS_172(un) (AXE_IS_178_FAMILY(un) == 0) | 132 | #define AXE_IS_172(un) (AXE_IS_178_FAMILY(un) == 0) | |
133 | 133 | |||
134 | #define AX_RXCSUM \ | 134 | #define AX_RXCSUM \ | |
135 | (IFCAP_CSUM_IPv4_Rx | \ | 135 | (IFCAP_CSUM_IPv4_Rx | \ | |
136 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | \ | 136 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | \ | |
137 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx) | 137 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx) | |
138 | 138 | |||
139 | #define AX_TXCSUM \ | 139 | #define AX_TXCSUM \ | |
140 | (IFCAP_CSUM_IPv4_Tx | \ | 140 | (IFCAP_CSUM_IPv4_Tx | \ | |
141 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx | \ | 141 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx | \ | |
142 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx) | 142 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx) | |
143 | 143 | |||
144 | /* | 144 | /* | |
145 | * AXE_178_MAX_FRAME_BURST | 145 | * AXE_178_MAX_FRAME_BURST | |
146 | * max frame burst size for Ax88178 and Ax88772 | 146 | * max frame burst size for Ax88178 and Ax88772 | |
147 | * 0 2048 bytes | 147 | * 0 2048 bytes | |
148 | * 1 4096 bytes | 148 | * 1 4096 bytes | |
149 | * 2 8192 bytes | 149 | * 2 8192 bytes | |
150 | * 3 16384 bytes | 150 | * 3 16384 bytes | |
151 | * use the largest your system can handle without USB stalling. | 151 | * use the largest your system can handle without USB stalling. | |
152 | * | 152 | * | |
153 | * NB: 88772 parts appear to generate lots of input errors with | 153 | * NB: 88772 parts appear to generate lots of input errors with | |
154 | * a 2K rx buffer and 8K is only slightly faster than 4K on an | 154 | * a 2K rx buffer and 8K is only slightly faster than 4K on an | |
155 | * EHCI port on a T42 so change at your own risk. | 155 | * EHCI port on a T42 so change at your own risk. | |
156 | */ | 156 | */ | |
157 | #define AXE_178_MAX_FRAME_BURST 1 | 157 | #define AXE_178_MAX_FRAME_BURST 1 | |
158 | 158 | |||
159 | 159 | |||
160 | #ifdef USB_DEBUG | 160 | #ifdef USB_DEBUG | |
161 | #ifndef AXE_DEBUG | 161 | #ifndef AXE_DEBUG | |
162 | #define axedebug 0 | 162 | #define axedebug 0 | |
163 | #else | 163 | #else | |
164 | static int axedebug = 0; | 164 | static int axedebug = 0; | |
165 | 165 | |||
166 | SYSCTL_SETUP(sysctl_hw_axe_setup, "sysctl hw.axe setup") | 166 | SYSCTL_SETUP(sysctl_hw_axe_setup, "sysctl hw.axe setup") | |
167 | { | 167 | { | |
168 | int err; | 168 | int err; | |
169 | const struct sysctlnode *rnode; | 169 | const struct sysctlnode *rnode; | |
170 | const struct sysctlnode *cnode; | 170 | const struct sysctlnode *cnode; | |
171 | 171 | |||
172 | err = sysctl_createv(clog, 0, NULL, &rnode, | 172 | err = sysctl_createv(clog, 0, NULL, &rnode, | |
173 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "axe", | 173 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "axe", | |
174 | SYSCTL_DESCR("axe global controls"), | 174 | SYSCTL_DESCR("axe global controls"), | |
175 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | 175 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL); | |
176 | 176 | |||
177 | if (err) | 177 | if (err) | |
178 | goto fail; | 178 | goto fail; | |
179 | 179 | |||
180 | /* control debugging printfs */ | 180 | /* control debugging printfs */ | |
181 | err = sysctl_createv(clog, 0, &rnode, &cnode, | 181 | err = sysctl_createv(clog, 0, &rnode, &cnode, | |
182 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | 182 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | |
183 | "debug", SYSCTL_DESCR("Enable debugging output"), | 183 | "debug", SYSCTL_DESCR("Enable debugging output"), | |
184 | NULL, 0, &axedebug, sizeof(axedebug), CTL_CREATE, CTL_EOL); | 184 | NULL, 0, &axedebug, sizeof(axedebug), CTL_CREATE, CTL_EOL); | |
185 | if (err) | 185 | if (err) | |
186 | goto fail; | 186 | goto fail; | |
187 | 187 | |||
188 | return; | 188 | return; | |
189 | fail: | 189 | fail: | |
190 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | 190 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | |
191 | } | 191 | } | |
192 | 192 | |||
193 | #endif /* AXE_DEBUG */ | 193 | #endif /* AXE_DEBUG */ | |
194 | #endif /* USB_DEBUG */ | 194 | #endif /* USB_DEBUG */ | |
195 | 195 | |||
196 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(axedebug,1,FMT,A,B,C,D) | 196 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(axedebug,1,FMT,A,B,C,D) | |
197 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(axedebug,N,FMT,A,B,C,D) | 197 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(axedebug,N,FMT,A,B,C,D) | |
198 | #define AXEHIST_FUNC() USBHIST_FUNC() | 198 | #define AXEHIST_FUNC() USBHIST_FUNC() | |
199 | #define AXEHIST_CALLED(name) USBHIST_CALLED(axedebug) | 199 | #define AXEHIST_CALLED(name) USBHIST_CALLED(axedebug) | |
200 | 200 | |||
201 | /* | 201 | /* | |
202 | * Various supported device vendors/products. | 202 | * Various supported device vendors/products. | |
203 | */ | 203 | */ | |
204 | static const struct axe_type axe_devs[] = { | 204 | static const struct axe_type axe_devs[] = { | |
205 | { { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE2000 }, 0 }, | 205 | { { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UFE2000 }, 0 }, | |
206 | { { USB_VENDOR_ACERCM, USB_PRODUCT_ACERCM_EP1427X2 }, 0 }, | 206 | { { USB_VENDOR_ACERCM, USB_PRODUCT_ACERCM_EP1427X2 }, 0 }, | |
207 | { { USB_VENDOR_APPLE, USB_PRODUCT_APPLE_ETHERNET }, AX772 }, | 207 | { { USB_VENDOR_APPLE, USB_PRODUCT_APPLE_ETHERNET }, AX772 }, | |
208 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88172 }, 0 }, | 208 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88172 }, 0 }, | |
209 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772 }, AX772 }, | 209 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772 }, AX772 }, | |
210 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772A }, AX772 }, | 210 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772A }, AX772 }, | |
211 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B }, AX772B }, | 211 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B }, AX772B }, | |
212 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B_1 }, AX772B }, | 212 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B_1 }, AX772B }, | |
213 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178 }, AX178 }, | 213 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178 }, AX178 }, | |
214 | { { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC210T }, 0 }, | 214 | { { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC210T }, 0 }, | |
215 | { { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D5055 }, AX178 }, | 215 | { { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D5055 }, AX178 }, | |
216 | { { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB2AR }, 0}, | 216 | { { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB2AR }, 0}, | |
217 | { { USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_USB200MV2 }, AX772A }, | 217 | { { USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_USB200MV2 }, AX772A }, | |
218 | { { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB2_TX }, 0 }, | 218 | { { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB2_TX }, 0 }, | |
219 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100 }, 0 }, | 219 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100 }, 0 }, | |
220 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100B1 }, AX772 }, | 220 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100B1 }, AX772 }, | |
221 | { { USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DUBE100B1 }, AX772 }, | 221 | { { USB_VENDOR_DLINK2, USB_PRODUCT_DLINK2_DUBE100B1 }, AX772 }, | |
222 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100C1 }, AX772B }, | 222 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100C1 }, AX772B }, | |
223 | { { USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_GWUSB2E }, 0 }, | 223 | { { USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_GWUSB2E }, 0 }, | |
224 | { { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETGUS2 }, AX178 }, | 224 | { { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETGUS2 }, AX178 }, | |
225 | { { USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_PRX1 }, 0 }, | 225 | { { USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_PRX1 }, 0 }, | |
226 | { { USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_ETHERNET }, AX772B }, | 226 | { { USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_ETHERNET }, AX772B }, | |
227 | { { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_HG20F9 }, AX772B }, | 227 | { { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_HG20F9 }, AX772B }, | |
228 | { { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_USB200M }, 0 }, | 228 | { { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_USB200M }, 0 }, | |
229 | { { USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_USB1000 }, AX178 }, | 229 | { { USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_USB1000 }, AX178 }, | |
230 | { { USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LAN_GTJU2 }, AX178 }, | 230 | { { USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LAN_GTJU2 }, AX178 }, | |
231 | { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2GT }, AX178 }, | 231 | { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2GT }, AX178 }, | |
232 | { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2KTX }, 0 }, | 232 | { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2KTX }, 0 }, | |
233 | { { USB_VENDOR_MSI, USB_PRODUCT_MSI_AX88772A }, AX772 }, | 233 | { { USB_VENDOR_MSI, USB_PRODUCT_MSI_AX88772A }, AX772 }, | |
234 | { { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA120 }, 0 }, | 234 | { { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA120 }, 0 }, | |
235 | { { USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01PLUS }, AX772 }, | 235 | { { USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01PLUS }, AX772 }, | |
236 | { { USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GU1000T }, AX178 }, | 236 | { { USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GU1000T }, AX178 }, | |
237 | { { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_LN029 }, 0 }, | 237 | { { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_LN029 }, 0 }, | |
238 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN028 }, AX178 }, | 238 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN028 }, AX178 }, | |
239 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN031 }, AX178 }, | 239 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN031 }, AX178 }, | |
240 | { { USB_VENDOR_SYSTEMTALKS, USB_PRODUCT_SYSTEMTALKS_SGCX2UL }, 0 }, | 240 | { { USB_VENDOR_SYSTEMTALKS, USB_PRODUCT_SYSTEMTALKS_SGCX2UL }, 0 }, | |
241 | }; | 241 | }; | |
242 | #define axe_lookup(v, p) ((const struct axe_type *)usb_lookup(axe_devs, v, p)) | 242 | #define axe_lookup(v, p) ((const struct axe_type *)usb_lookup(axe_devs, v, p)) | |
243 | 243 | |||
244 | static const struct ax88772b_mfb ax88772b_mfb_table[] = { | 244 | static const struct ax88772b_mfb ax88772b_mfb_table[] = { | |
245 | { 0x8000, 0x8001, 2048 }, | 245 | { 0x8000, 0x8001, 2048 }, | |
246 | { 0x8100, 0x8147, 4096 }, | 246 | { 0x8100, 0x8147, 4096 }, | |
247 | { 0x8200, 0x81EB, 6144 }, | 247 | { 0x8200, 0x81EB, 6144 }, | |
248 | { 0x8300, 0x83D7, 8192 }, | 248 | { 0x8300, 0x83D7, 8192 }, | |
249 | { 0x8400, 0x851E, 16384 }, | 249 | { 0x8400, 0x851E, 16384 }, | |
250 | { 0x8500, 0x8666, 20480 }, | 250 | { 0x8500, 0x8666, 20480 }, | |
251 | { 0x8600, 0x87AE, 24576 }, | 251 | { 0x8600, 0x87AE, 24576 }, | |
252 | { 0x8700, 0x8A3D, 32768 } | 252 | { 0x8700, 0x8A3D, 32768 } | |
253 | }; | 253 | }; | |
254 | 254 | |||
255 | static int axe_match(device_t, cfdata_t, void *); | 255 | static int axe_match(device_t, cfdata_t, void *); | |
256 | static void axe_attach(device_t, device_t, void *); | 256 | static void axe_attach(device_t, device_t, void *); | |
257 | 257 | |||
258 | CFATTACH_DECL_NEW(axe, sizeof(struct axe_softc), | 258 | CFATTACH_DECL_NEW(axe, sizeof(struct axe_softc), | |
259 | axe_match, axe_attach, usbnet_detach, usbnet_activate); | 259 | axe_match, axe_attach, usbnet_detach, usbnet_activate); | |
260 | 260 | |||
261 | static void axe_uno_stop(struct ifnet *, int); | 261 | static void axe_uno_stop(struct ifnet *, int); | |
262 | static void axe_uno_mcast(struct ifnet *); | 262 | static void axe_uno_mcast(struct ifnet *); | |
263 | static int axe_uno_init(struct ifnet *); | 263 | static int axe_uno_init(struct ifnet *); | |
264 | static int axe_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 264 | static int axe_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
265 | static int axe_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 265 | static int axe_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
266 | static void axe_uno_mii_statchg(struct ifnet *); | 266 | static void axe_uno_mii_statchg(struct ifnet *); | |
267 | static void axe_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 267 | static void axe_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
268 | uint32_t); | 268 | uint32_t); | |
269 | static unsigned axe_uno_tx_prepare(struct usbnet *, struct mbuf *, | 269 | static unsigned axe_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
270 | struct usbnet_chain *); | 270 | struct usbnet_chain *); | |
271 | 271 | |||
272 | static void axe_ax88178_init(struct axe_softc *); | 272 | static void axe_ax88178_init(struct axe_softc *); | |
273 | static void axe_ax88772_init(struct axe_softc *); | 273 | static void axe_ax88772_init(struct axe_softc *); | |
274 | static void axe_ax88772a_init(struct axe_softc *); | 274 | static void axe_ax88772a_init(struct axe_softc *); | |
275 | static void axe_ax88772b_init(struct axe_softc *); | 275 | static void axe_ax88772b_init(struct axe_softc *); | |
276 | 276 | |||
277 | static const struct usbnet_ops axe_ops = { | 277 | static const struct usbnet_ops axe_ops = { | |
278 | .uno_stop = axe_uno_stop, | 278 | .uno_stop = axe_uno_stop, | |
279 | .uno_mcast = axe_uno_mcast, | 279 | .uno_mcast = axe_uno_mcast, | |
280 | .uno_read_reg = axe_uno_mii_read_reg, | 280 | .uno_read_reg = axe_uno_mii_read_reg, | |
281 | .uno_write_reg = axe_uno_mii_write_reg, | 281 | .uno_write_reg = axe_uno_mii_write_reg, | |
282 | .uno_statchg = axe_uno_mii_statchg, | 282 | .uno_statchg = axe_uno_mii_statchg, | |
283 | .uno_tx_prepare = axe_uno_tx_prepare, | 283 | .uno_tx_prepare = axe_uno_tx_prepare, | |
284 | .uno_rx_loop = axe_uno_rx_loop, | 284 | .uno_rx_loop = axe_uno_rx_loop, | |
285 | .uno_init = axe_uno_init, | 285 | .uno_init = axe_uno_init, | |
286 | }; | 286 | }; | |
287 | 287 | |||
288 | static usbd_status | 288 | static usbd_status | |
289 | axe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf) | 289 | axe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf) | |
290 | { | 290 | { | |
291 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 291 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
292 | struct usbnet * const un = &sc->axe_un; | 292 | struct usbnet * const un = &sc->axe_un; | |
293 | usb_device_request_t req; | 293 | usb_device_request_t req; | |
294 | usbd_status err; | 294 | usbd_status err; | |
295 | 295 | |||
296 | if (usbnet_isdying(un)) | 296 | if (usbnet_isdying(un)) | |
297 | return -1; | 297 | return -1; | |
298 | 298 | |||
299 | DPRINTFN(20, "cmd %#jx index %#jx val %#jx", cmd, index, val, 0); | 299 | DPRINTFN(20, "cmd %#jx index %#jx val %#jx", cmd, index, val, 0); | |
300 | 300 | |||
301 | if (AXE_CMD_DIR(cmd)) | 301 | if (AXE_CMD_DIR(cmd)) | |
302 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 302 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
303 | else | 303 | else | |
304 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 304 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
305 | req.bRequest = AXE_CMD_CMD(cmd); | 305 | req.bRequest = AXE_CMD_CMD(cmd); | |
306 | USETW(req.wValue, val); | 306 | USETW(req.wValue, val); | |
307 | USETW(req.wIndex, index); | 307 | USETW(req.wIndex, index); | |
308 | USETW(req.wLength, AXE_CMD_LEN(cmd)); | 308 | USETW(req.wLength, AXE_CMD_LEN(cmd)); | |
309 | 309 | |||
310 | err = usbd_do_request(un->un_udev, &req, buf); | 310 | err = usbd_do_request(un->un_udev, &req, buf); | |
311 | if (err) | 311 | if (err) | |
312 | DPRINTF("cmd %jd err %jd", cmd, err, 0, 0); | 312 | DPRINTF("cmd %jd err %jd", cmd, err, 0, 0); | |
313 | 313 | |||
314 | return err; | 314 | return err; | |
315 | } | 315 | } | |
316 | 316 | |||
317 | static int | 317 | static int | |
318 | axe_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 318 | axe_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
319 | { | 319 | { | |
320 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 320 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
321 | struct axe_softc * const sc = usbnet_softc(un); | 321 | struct axe_softc * const sc = usbnet_softc(un); | |
322 | usbd_status err; | 322 | usbd_status err; | |
323 | uint16_t data; | 323 | uint16_t data; | |
324 | 324 | |||
325 | DPRINTFN(30, "phy %#jx reg %#jx\n", phy, reg, 0, 0); | 325 | DPRINTFN(30, "phy %#jx reg %#jx\n", phy, reg, 0, 0); | |
326 | 326 | |||
327 | if (un->un_phyno != phy) { | 327 | if (un->un_phyno != phy) { | |
328 | *val = 0; | 328 | *val = 0; | |
329 | return EINVAL; | 329 | return EINVAL; | |
330 | } | 330 | } | |
331 | 331 | |||
332 | axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); | 332 | axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); | |
333 | 333 | |||
334 | err = axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, &data); | 334 | err = axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, &data); | |
335 | axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); | 335 | axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); | |
336 | 336 | |||
337 | if (err) { | 337 | if (err) { | |
338 | device_printf(un->un_dev, "read PHY failed\n"); | 338 | device_printf(un->un_dev, "read PHY failed\n"); | |
339 | *val = 0; | 339 | *val = 0; | |
340 | return EIO; | 340 | return EIO; | |
341 | } | 341 | } | |
342 | 342 | |||
343 | *val = le16toh(data); | 343 | *val = le16toh(data); | |
344 | if (AXE_IS_772(un) && reg == MII_BMSR) { | 344 | if (AXE_IS_772(un) && reg == MII_BMSR) { | |
345 | /* | 345 | /* | |
346 | * BMSR of AX88772 indicates that it supports extended | 346 | * BMSR of AX88772 indicates that it supports extended | |
347 | * capability but the extended status register is | 347 | * capability but the extended status register is | |
348 | * reserved for embedded ethernet PHY. So clear the | 348 | * reserved for embedded ethernet PHY. So clear the | |
349 | * extended capability bit of BMSR. | 349 | * extended capability bit of BMSR. | |
350 | */ | 350 | */ | |
351 | *val &= ~BMSR_EXTCAP; | 351 | *val &= ~BMSR_EXTCAP; | |
352 | } | 352 | } | |
353 | 353 | |||
354 | DPRINTFN(30, "phy %#jx reg %#jx val %#jx", phy, reg, *val, 0); | 354 | DPRINTFN(30, "phy %#jx reg %#jx val %#jx", phy, reg, *val, 0); | |
355 | 355 | |||
356 | return 0; | 356 | return 0; | |
357 | } | 357 | } | |
358 | 358 | |||
359 | static int | 359 | static int | |
360 | axe_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 360 | axe_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
361 | { | 361 | { | |
362 | struct axe_softc * const sc = usbnet_softc(un); | 362 | struct axe_softc * const sc = usbnet_softc(un); | |
363 | usbd_status err; | 363 | usbd_status err; | |
364 | uint16_t aval; | 364 | uint16_t aval; | |
365 | 365 | |||
366 | if (un->un_phyno != phy) | 366 | if (un->un_phyno != phy) | |
367 | return EINVAL; | 367 | return EINVAL; | |
368 | 368 | |||
369 | aval = htole16(val); | 369 | aval = htole16(val); | |
370 | 370 | |||
371 | axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); | 371 | axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL); | |
372 | err = axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, &aval); | 372 | err = axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, &aval); | |
373 | axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); | 373 | axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL); | |
374 | 374 | |||
375 | if (err) | 375 | if (err) | |
376 | return EIO; | 376 | return EIO; | |
377 | return 0; | 377 | return 0; | |
378 | } | 378 | } | |
379 | 379 | |||
380 | static void | 380 | static void | |
381 | axe_uno_mii_statchg(struct ifnet *ifp) | 381 | axe_uno_mii_statchg(struct ifnet *ifp) | |
382 | { | 382 | { | |
383 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 383 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
384 | 384 | |||
385 | struct usbnet * const un = ifp->if_softc; | 385 | struct usbnet * const un = ifp->if_softc; | |
386 | struct axe_softc * const sc = usbnet_softc(un); | 386 | struct axe_softc * const sc = usbnet_softc(un); | |
387 | struct mii_data *mii = usbnet_mii(un); | 387 | struct mii_data *mii = usbnet_mii(un); | |
388 | int val, err; | 388 | int val, err; | |
389 | 389 | |||
390 | if (usbnet_isdying(un)) | 390 | if (usbnet_isdying(un)) | |
391 | return; | 391 | return; | |
392 | 392 | |||
393 | val = 0; | 393 | val = 0; | |
394 | if (AXE_IS_172(un)) { | 394 | if (AXE_IS_172(un)) { | |
395 | if (mii->mii_media_active & IFM_FDX) | 395 | if (mii->mii_media_active & IFM_FDX) | |
396 | val |= AXE_MEDIA_FULL_DUPLEX; | 396 | val |= AXE_MEDIA_FULL_DUPLEX; | |
397 | } else { | 397 | } else { | |
398 | if (mii->mii_media_active & IFM_FDX) { | 398 | if (mii->mii_media_active & IFM_FDX) { | |
399 | val |= AXE_MEDIA_FULL_DUPLEX; | 399 | val |= AXE_MEDIA_FULL_DUPLEX; | |
400 | if (mii->mii_media_active & IFM_ETH_TXPAUSE) | 400 | if (mii->mii_media_active & IFM_ETH_TXPAUSE) | |
401 | val |= AXE_178_MEDIA_TXFLOW_CONTROL_EN; | 401 | val |= AXE_178_MEDIA_TXFLOW_CONTROL_EN; | |
402 | if (mii->mii_media_active & IFM_ETH_RXPAUSE) | 402 | if (mii->mii_media_active & IFM_ETH_RXPAUSE) | |
403 | val |= AXE_178_MEDIA_RXFLOW_CONTROL_EN; | 403 | val |= AXE_178_MEDIA_RXFLOW_CONTROL_EN; | |
404 | } | 404 | } | |
405 | val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC; | 405 | val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC; | |
406 | if (un->un_flags & AX178) | 406 | if (un->un_flags & AX178) | |
407 | val |= AXE_178_MEDIA_ENCK; | 407 | val |= AXE_178_MEDIA_ENCK; | |
408 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 408 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
409 | case IFM_1000_T: | 409 | case IFM_1000_T: | |
410 | val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK; | 410 | val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK; | |
411 | usbnet_set_link(un, true); | 411 | usbnet_set_link(un, true); | |
412 | break; | 412 | break; | |
413 | case IFM_100_TX: | 413 | case IFM_100_TX: | |
414 | val |= AXE_178_MEDIA_100TX; | 414 | val |= AXE_178_MEDIA_100TX; | |
415 | usbnet_set_link(un, true); | 415 | usbnet_set_link(un, true); | |
416 | break; | 416 | break; | |
417 | case IFM_10_T: | 417 | case IFM_10_T: | |
418 | usbnet_set_link(un, true); | 418 | usbnet_set_link(un, true); | |
419 | break; | 419 | break; | |
420 | } | 420 | } | |
421 | } | 421 | } | |
422 | 422 | |||
423 | DPRINTF("val=%#jx", val, 0, 0, 0); | 423 | DPRINTF("val=%#jx", val, 0, 0, 0); | |
424 | err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL); | 424 | err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL); | |
425 | if (err) | 425 | if (err) | |
426 | device_printf(un->un_dev, "media change failed\n"); | 426 | device_printf(un->un_dev, "media change failed\n"); | |
427 | } | 427 | } | |
428 | 428 | |||
429 | static void | 429 | static void | |
430 | axe_uno_mcast(struct ifnet *ifp) | 430 | axe_uno_mcast(struct ifnet *ifp) | |
431 | { | 431 | { | |
432 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 432 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
433 | struct usbnet * const un = ifp->if_softc; | 433 | struct usbnet * const un = ifp->if_softc; | |
434 | struct axe_softc * const sc = usbnet_softc(un); | 434 | struct axe_softc * const sc = usbnet_softc(un); | |
435 | struct ethercom *ec = usbnet_ec(un); | 435 | struct ethercom *ec = usbnet_ec(un); | |
436 | struct ether_multi *enm; | 436 | struct ether_multi *enm; | |
437 | struct ether_multistep step; | 437 | struct ether_multistep step; | |
438 | uint16_t rxmode; | 438 | uint16_t rxmode; | |
439 | uint32_t h = 0; | 439 | uint32_t h = 0; | |
440 | uint8_t mchash[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 440 | uint8_t mchash[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
441 | 441 | |||
442 | if (usbnet_isdying(un)) | 442 | if (usbnet_isdying(un)) | |
443 | return; | 443 | return; | |
444 | 444 | |||
445 | if (axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode)) { | 445 | if (axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode)) { | |
446 | device_printf(un->un_dev, "can't read rxmode"); | 446 | device_printf(un->un_dev, "can't read rxmode"); | |
447 | return; | 447 | return; | |
448 | } | 448 | } | |
449 | rxmode = le16toh(rxmode); | 449 | rxmode = le16toh(rxmode); | |
450 | 450 | |||
451 | rxmode &= | 451 | rxmode &= | |
452 | ~(AXE_RXCMD_ALLMULTI | AXE_RXCMD_PROMISC | AXE_RXCMD_MULTICAST); | 452 | ~(AXE_RXCMD_ALLMULTI | AXE_RXCMD_PROMISC | AXE_RXCMD_MULTICAST); | |
453 | 453 | |||
454 | ETHER_LOCK(ec); | 454 | ETHER_LOCK(ec); | |
455 | if (ifp->if_flags & IFF_PROMISC) { | 455 | if (ifp->if_flags & IFF_PROMISC) { | |
456 | ec->ec_flags |= ETHER_F_ALLMULTI; | 456 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
457 | ETHER_UNLOCK(ec); | 457 | ETHER_UNLOCK(ec); | |
458 | /* run promisc. mode */ | 458 | /* run promisc. mode */ | |
459 | rxmode |= AXE_RXCMD_ALLMULTI; /* ??? */ | 459 | rxmode |= AXE_RXCMD_ALLMULTI; /* ??? */ | |
460 | rxmode |= AXE_RXCMD_PROMISC; | 460 | rxmode |= AXE_RXCMD_PROMISC; | |
461 | goto update; | 461 | goto update; | |
462 | } | 462 | } | |
463 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 463 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
464 | ETHER_FIRST_MULTI(step, ec, enm); | 464 | ETHER_FIRST_MULTI(step, ec, enm); | |
465 | while (enm != NULL) { | 465 | while (enm != NULL) { | |
466 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 466 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
467 | ec->ec_flags |= ETHER_F_ALLMULTI; | 467 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
468 | ETHER_UNLOCK(ec); | 468 | ETHER_UNLOCK(ec); | |
469 | /* accept all mcast frames */ | 469 | /* accept all mcast frames */ | |
470 | rxmode |= AXE_RXCMD_ALLMULTI; | 470 | rxmode |= AXE_RXCMD_ALLMULTI; | |
471 | goto update; | 471 | goto update; | |
472 | } | 472 | } | |
473 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | 473 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | |
474 | mchash[h >> 29] |= 1U << ((h >> 26) & 7); | 474 | mchash[h >> 29] |= 1U << ((h >> 26) & 7); | |
475 | ETHER_NEXT_MULTI(step, enm); | 475 | ETHER_NEXT_MULTI(step, enm); | |
476 | } | 476 | } | |
477 | ETHER_UNLOCK(ec); | 477 | ETHER_UNLOCK(ec); | |
478 | if (h != 0) | 478 | if (h != 0) | |
479 | rxmode |= AXE_RXCMD_MULTICAST; /* activate mcast hash filter */ | 479 | rxmode |= AXE_RXCMD_MULTICAST; /* activate mcast hash filter */ | |
480 | axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, mchash); | 480 | axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, mchash); | |
481 | update: | 481 | update: | |
482 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); | 482 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); | |
483 | } | 483 | } | |
484 | 484 | |||
485 | static void | 485 | static void | |
486 | axe_ax_init(struct usbnet *un) | 486 | axe_ax_init(struct usbnet *un) | |
487 | { | 487 | { | |
488 | struct axe_softc * const sc = usbnet_softc(un); | 488 | struct axe_softc * const sc = usbnet_softc(un); | |
489 | 489 | |||
490 | int cmd = AXE_178_CMD_READ_NODEID; | 490 | int cmd = AXE_178_CMD_READ_NODEID; | |
491 | 491 | |||
492 | if (un->un_flags & AX178) { | 492 | if (un->un_flags & AX178) { | |
493 | axe_ax88178_init(sc); | 493 | axe_ax88178_init(sc); | |
494 | } else if (un->un_flags & AX772) { | 494 | } else if (un->un_flags & AX772) { | |
495 | axe_ax88772_init(sc); | 495 | axe_ax88772_init(sc); | |
496 | } else if (un->un_flags & AX772A) { | 496 | } else if (un->un_flags & AX772A) { | |
497 | axe_ax88772a_init(sc); | 497 | axe_ax88772a_init(sc); | |
498 | } else if (un->un_flags & AX772B) { | 498 | } else if (un->un_flags & AX772B) { | |
499 | axe_ax88772b_init(sc); | 499 | axe_ax88772b_init(sc); | |
500 | return; | 500 | return; | |
501 | } else { | 501 | } else { | |
502 | cmd = AXE_172_CMD_READ_NODEID; | 502 | cmd = AXE_172_CMD_READ_NODEID; | |
503 | } | 503 | } | |
504 | 504 | |||
505 | if (axe_cmd(sc, cmd, 0, 0, un->un_eaddr)) { | 505 | if (axe_cmd(sc, cmd, 0, 0, un->un_eaddr)) { | |
506 | aprint_error_dev(un->un_dev, | 506 | aprint_error_dev(un->un_dev, | |
507 | "failed to read ethernet address\n"); | 507 | "failed to read ethernet address\n"); | |
508 | } | 508 | } | |
509 | } | 509 | } | |
510 | 510 | |||
511 | 511 | |||
512 | static void | 512 | static void | |
513 | axe_reset(struct usbnet *un) | 513 | axe_reset(struct usbnet *un) | |
514 | { | 514 | { | |
515 | 515 | |||
516 | if (usbnet_isdying(un)) | 516 | if (usbnet_isdying(un)) | |
517 | return; | 517 | return; | |
518 | 518 | |||
519 | /* | 519 | /* | |
520 | * softnet_lock can be taken when NET_MPAFE is not defined when calling | 520 | * softnet_lock can be taken when NET_MPAFE is not defined when calling | |
521 | * if_addr_init -> if_init. This doesn't mix well with the | 521 | * if_addr_init -> if_init. This doesn't mix well with the | |
522 | * usbd_delay_ms calls in the init routines as things like nd6_slowtimo | 522 | * usbd_delay_ms calls in the init routines as things like nd6_slowtimo | |
523 | * can fire during the wait and attempt to take softnet_lock and then | 523 | * can fire during the wait and attempt to take softnet_lock and then | |
524 | * block the softclk thread meaning the wait never ends. | 524 | * block the softclk thread meaning the wait never ends. | |
525 | */ | 525 | */ | |
526 | #ifndef NET_MPSAFE | 526 | #ifndef NET_MPSAFE | |
527 | /* XXX What to reset? */ | 527 | /* XXX What to reset? */ | |
528 | 528 | |||
529 | /* Wait a little while for the chip to get its brains in order. */ | 529 | /* Wait a little while for the chip to get its brains in order. */ | |
530 | DELAY(1000); | 530 | DELAY(1000); | |
531 | #else | 531 | #else | |
532 | axe_ax_init(un); | 532 | axe_ax_init(un); | |
533 | #endif | 533 | #endif | |
534 | } | 534 | } | |
535 | 535 | |||
536 | static int | 536 | static int | |
537 | axe_get_phyno(struct axe_softc *sc, int sel) | 537 | axe_get_phyno(struct axe_softc *sc, int sel) | |
538 | { | 538 | { | |
539 | int phyno; | 539 | int phyno; | |
540 | 540 | |||
541 | switch (AXE_PHY_TYPE(sc->axe_phyaddrs[sel])) { | 541 | switch (AXE_PHY_TYPE(sc->axe_phyaddrs[sel])) { | |
542 | case PHY_TYPE_100_HOME: | 542 | case PHY_TYPE_100_HOME: | |
543 | /* FALLTHROUGH */ | 543 | /* FALLTHROUGH */ | |
544 | case PHY_TYPE_GIG: | 544 | case PHY_TYPE_GIG: | |
545 | phyno = AXE_PHY_NO(sc->axe_phyaddrs[sel]); | 545 | phyno = AXE_PHY_NO(sc->axe_phyaddrs[sel]); | |
546 | break; | 546 | break; | |
547 | case PHY_TYPE_SPECIAL: | 547 | case PHY_TYPE_SPECIAL: | |
548 | /* FALLTHROUGH */ | 548 | /* FALLTHROUGH */ | |
549 | case PHY_TYPE_RSVD: | 549 | case PHY_TYPE_RSVD: | |
550 | /* FALLTHROUGH */ | 550 | /* FALLTHROUGH */ | |
551 | case PHY_TYPE_NON_SUP: | 551 | case PHY_TYPE_NON_SUP: | |
552 | /* FALLTHROUGH */ | 552 | /* FALLTHROUGH */ | |
553 | default: | 553 | default: | |
554 | phyno = -1; | 554 | phyno = -1; | |
555 | break; | 555 | break; | |
556 | } | 556 | } | |
557 | 557 | |||
558 | return phyno; | 558 | return phyno; | |
559 | } | 559 | } | |
560 | 560 | |||
561 | #define AXE_GPIO_WRITE(x, y) do { \ | 561 | #define AXE_GPIO_WRITE(x, y) do { \ | |
562 | axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, (x), NULL); \ | 562 | axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, (x), NULL); \ | |
563 | usbd_delay_ms(sc->axe_un.un_udev, hztoms(y)); \ | 563 | usbd_delay_ms(sc->axe_un.un_udev, hztoms(y)); \ | |
564 | } while (0) | 564 | } while (0) | |
565 | 565 | |||
566 | static void | 566 | static void | |
567 | axe_ax88178_init(struct axe_softc *sc) | 567 | axe_ax88178_init(struct axe_softc *sc) | |
568 | { | 568 | { | |
569 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 569 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
570 | struct usbnet * const un = &sc->axe_un; | 570 | struct usbnet * const un = &sc->axe_un; | |
571 | int gpio0, ledmode, phymode; | 571 | int gpio0, ledmode, phymode; | |
572 | uint16_t eeprom, val; | 572 | uint16_t eeprom, val; | |
573 | 573 | |||
574 | axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL); | 574 | axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL); | |
575 | /* XXX magic */ | 575 | /* XXX magic */ | |
576 | if (axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom) != 0) | 576 | if (axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom) != 0) | |
577 | eeprom = 0xffff; | 577 | eeprom = 0xffff; | |
578 | axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL); | 578 | axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL); | |
579 | 579 | |||
580 | eeprom = le16toh(eeprom); | 580 | eeprom = le16toh(eeprom); | |
581 | 581 | |||
582 | DPRINTF("EEPROM is %#jx", eeprom, 0, 0, 0); | 582 | DPRINTF("EEPROM is %#jx", eeprom, 0, 0, 0); | |
583 | 583 | |||
584 | /* if EEPROM is invalid we have to use to GPIO0 */ | 584 | /* if EEPROM is invalid we have to use to GPIO0 */ | |
585 | if (eeprom == 0xffff) { | 585 | if (eeprom == 0xffff) { | |
586 | phymode = AXE_PHY_MODE_MARVELL; | 586 | phymode = AXE_PHY_MODE_MARVELL; | |
587 | gpio0 = 1; | 587 | gpio0 = 1; | |
588 | ledmode = 0; | 588 | ledmode = 0; | |
589 | } else { | 589 | } else { | |
590 | phymode = eeprom & 0x7f; | 590 | phymode = eeprom & 0x7f; | |
591 | gpio0 = (eeprom & 0x80) ? 0 : 1; | 591 | gpio0 = (eeprom & 0x80) ? 0 : 1; | |
592 | ledmode = eeprom >> 8; | 592 | ledmode = eeprom >> 8; | |
593 | } | 593 | } | |
594 | 594 | |||
595 | DPRINTF("use gpio0: %jd, phymode %jd", gpio0, phymode, 0, 0); | 595 | DPRINTF("use gpio0: %jd, phymode %jd", gpio0, phymode, 0, 0); | |
596 | 596 | |||
597 | /* Program GPIOs depending on PHY hardware. */ | 597 | /* Program GPIOs depending on PHY hardware. */ | |
598 | switch (phymode) { | 598 | switch (phymode) { | |
599 | case AXE_PHY_MODE_MARVELL: | 599 | case AXE_PHY_MODE_MARVELL: | |
600 | if (gpio0 == 1) { | 600 | if (gpio0 == 1) { | |
601 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0_EN, | 601 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0_EN, | |
602 | hz / 32); | 602 | hz / 32); | |
603 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, | 603 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, | |
604 | hz / 32); | 604 | hz / 32); | |
605 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2_EN, hz / 4); | 605 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2_EN, hz / 4); | |
606 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, | 606 | AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN, | |
607 | hz / 32); | 607 | hz / 32); | |
608 | } else { | 608 | } else { | |
609 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | 609 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | |
610 | AXE_GPIO1_EN, hz / 3); | 610 | AXE_GPIO1_EN, hz / 3); | |
611 | if (ledmode == 1) { | 611 | if (ledmode == 1) { | |
612 | AXE_GPIO_WRITE(AXE_GPIO1_EN, hz / 3); | 612 | AXE_GPIO_WRITE(AXE_GPIO1_EN, hz / 3); | |
613 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN, | 613 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN, | |
614 | hz / 3); | 614 | hz / 3); | |
615 | } else { | 615 | } else { | |
616 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | 616 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | |
617 | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | 617 | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | |
618 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | 618 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | |
619 | AXE_GPIO2_EN, hz / 4); | 619 | AXE_GPIO2_EN, hz / 4); | |
620 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | 620 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | | |
621 | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | 621 | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | |
622 | } | 622 | } | |
623 | } | 623 | } | |
624 | break; | 624 | break; | |
625 | case AXE_PHY_MODE_CICADA: | 625 | case AXE_PHY_MODE_CICADA: | |
626 | case AXE_PHY_MODE_CICADA_V2: | 626 | case AXE_PHY_MODE_CICADA_V2: | |
627 | case AXE_PHY_MODE_CICADA_V2_ASIX: | 627 | case AXE_PHY_MODE_CICADA_V2_ASIX: | |
628 | if (gpio0 == 1) | 628 | if (gpio0 == 1) | |
629 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0 | | 629 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0 | | |
630 | AXE_GPIO0_EN, hz / 32); | 630 | AXE_GPIO0_EN, hz / 32); | |
631 | else | 631 | else | |
632 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | 632 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | |
633 | AXE_GPIO1_EN, hz / 32); | 633 | AXE_GPIO1_EN, hz / 32); | |
634 | break; | 634 | break; | |
635 | case AXE_PHY_MODE_AGERE: | 635 | case AXE_PHY_MODE_AGERE: | |
636 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | 636 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 | | |
637 | AXE_GPIO1_EN, hz / 32); | 637 | AXE_GPIO1_EN, hz / 32); | |
638 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | | 638 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | | |
639 | AXE_GPIO2_EN, hz / 32); | 639 | AXE_GPIO2_EN, hz / 32); | |
640 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2_EN, hz / 4); | 640 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2_EN, hz / 4); | |
641 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | | 641 | AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 | | |
642 | AXE_GPIO2_EN, hz / 32); | 642 | AXE_GPIO2_EN, hz / 32); | |
643 | break; | 643 | break; | |
644 | case AXE_PHY_MODE_REALTEK_8211CL: | 644 | case AXE_PHY_MODE_REALTEK_8211CL: | |
645 | case AXE_PHY_MODE_REALTEK_8211BN: | 645 | case AXE_PHY_MODE_REALTEK_8211BN: | |
646 | case AXE_PHY_MODE_REALTEK_8251CL: | 646 | case AXE_PHY_MODE_REALTEK_8251CL: | |
647 | val = gpio0 == 1 ? AXE_GPIO0 | AXE_GPIO0_EN : | 647 | val = gpio0 == 1 ? AXE_GPIO0 | AXE_GPIO0_EN : | |
648 | AXE_GPIO1 | AXE_GPIO1_EN; | 648 | AXE_GPIO1 | AXE_GPIO1_EN; | |
649 | AXE_GPIO_WRITE(val, hz / 32); | 649 | AXE_GPIO_WRITE(val, hz / 32); | |
650 | AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | 650 | AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | |
651 | AXE_GPIO_WRITE(val | AXE_GPIO2_EN, hz / 4); | 651 | AXE_GPIO_WRITE(val | AXE_GPIO2_EN, hz / 4); | |
652 | AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | 652 | AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32); | |
653 | if (phymode == AXE_PHY_MODE_REALTEK_8211CL) { | 653 | if (phymode == AXE_PHY_MODE_REALTEK_8211CL) { | |
654 | axe_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0005); | 654 | axe_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0005); | |
655 | axe_uno_mii_write_reg(un, un->un_phyno, 0x0C, 0x0000); | 655 | axe_uno_mii_write_reg(un, un->un_phyno, 0x0C, 0x0000); | |
656 | axe_uno_mii_read_reg(un, un->un_phyno, 0x0001, &val); | 656 | axe_uno_mii_read_reg(un, un->un_phyno, 0x0001, &val); | |
657 | axe_uno_mii_write_reg(un, un->un_phyno, 0x01, val | 0x0080); | 657 | axe_uno_mii_write_reg(un, un->un_phyno, 0x01, val | 0x0080); | |
658 | axe_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0000); | 658 | axe_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0000); | |
659 | } | 659 | } | |
660 | break; | 660 | break; | |
661 | default: | 661 | default: | |
662 | /* Unknown PHY model or no need to program GPIOs. */ | 662 | /* Unknown PHY model or no need to program GPIOs. */ | |
663 | break; | 663 | break; | |
664 | } | 664 | } | |
665 | 665 | |||
666 | /* soft reset */ | 666 | /* soft reset */ | |
667 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | 667 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | |
668 | usbd_delay_ms(un->un_udev, 150); | 668 | usbd_delay_ms(un->un_udev, 150); | |
669 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | 669 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | |
670 | AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL); | 670 | AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL); | |
671 | usbd_delay_ms(un->un_udev, 150); | 671 | usbd_delay_ms(un->un_udev, 150); | |
672 | /* Enable MII/GMII/RGMII interface to work with external PHY. */ | 672 | /* Enable MII/GMII/RGMII interface to work with external PHY. */ | |
673 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL); | 673 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL); | |
674 | usbd_delay_ms(un->un_udev, 10); | 674 | usbd_delay_ms(un->un_udev, 10); | |
675 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | 675 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | |
676 | } | 676 | } | |
677 | 677 | |||
678 | static void | 678 | static void | |
679 | axe_ax88772_init(struct axe_softc *sc) | 679 | axe_ax88772_init(struct axe_softc *sc) | |
680 | { | 680 | { | |
681 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 681 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
682 | struct usbnet * const un = &sc->axe_un; | 682 | struct usbnet * const un = &sc->axe_un; | |
683 | 683 | |||
684 | axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL); | 684 | axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL); | |
685 | usbd_delay_ms(un->un_udev, 40); | 685 | usbd_delay_ms(un->un_udev, 40); | |
686 | 686 | |||
687 | if (un->un_phyno == AXE_772_PHY_NO_EPHY) { | 687 | if (un->un_phyno == AXE_772_PHY_NO_EPHY) { | |
688 | /* ask for the embedded PHY */ | 688 | /* ask for the embedded PHY */ | |
689 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, | 689 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, | |
690 | AXE_SW_PHY_SELECT_EMBEDDED, NULL); | 690 | AXE_SW_PHY_SELECT_EMBEDDED, NULL); | |
691 | usbd_delay_ms(un->un_udev, 10); | 691 | usbd_delay_ms(un->un_udev, 10); | |
692 | 692 | |||
693 | /* power down and reset state, pin reset state */ | 693 | /* power down and reset state, pin reset state */ | |
694 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | 694 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | |
695 | usbd_delay_ms(un->un_udev, 60); | 695 | usbd_delay_ms(un->un_udev, 60); | |
696 | 696 | |||
697 | /* power down/reset state, pin operating state */ | 697 | /* power down/reset state, pin operating state */ | |
698 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | 698 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | |
699 | AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); | 699 | AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); | |
700 | usbd_delay_ms(un->un_udev, 150); | 700 | usbd_delay_ms(un->un_udev, 150); | |
701 | 701 | |||
702 | /* power up, reset */ | 702 | /* power up, reset */ | |
703 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL); | 703 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL); | |
704 | 704 | |||
705 | /* power up, operating */ | 705 | /* power up, operating */ | |
706 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | 706 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | |
707 | AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL); | 707 | AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL); | |
708 | } else { | 708 | } else { | |
709 | /* ask for external PHY */ | 709 | /* ask for external PHY */ | |
710 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_EXT, | 710 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_EXT, | |
711 | NULL); | 711 | NULL); | |
712 | usbd_delay_ms(un->un_udev, 10); | 712 | usbd_delay_ms(un->un_udev, 10); | |
713 | 713 | |||
714 | /* power down internal PHY */ | 714 | /* power down internal PHY */ | |
715 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | 715 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, | |
716 | AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); | 716 | AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL); | |
717 | } | 717 | } | |
718 | 718 | |||
719 | usbd_delay_ms(un->un_udev, 150); | 719 | usbd_delay_ms(un->un_udev, 150); | |
720 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | 720 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | |
721 | } | 721 | } | |
722 | 722 | |||
723 | static void | 723 | static void | |
724 | axe_ax88772_phywake(struct axe_softc *sc) | 724 | axe_ax88772_phywake(struct axe_softc *sc) | |
725 | { | 725 | { | |
726 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 726 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
727 | struct usbnet * const un = &sc->axe_un; | 727 | struct usbnet * const un = &sc->axe_un; | |
728 | 728 | |||
729 | if (un->un_phyno == AXE_772_PHY_NO_EPHY) { | 729 | if (un->un_phyno == AXE_772_PHY_NO_EPHY) { | |
730 | /* Manually select internal(embedded) PHY - MAC mode. */ | 730 | /* Manually select internal(embedded) PHY - MAC mode. */ | |
731 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, | 731 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, | |
732 | AXE_SW_PHY_SELECT_EMBEDDED, NULL); | 732 | AXE_SW_PHY_SELECT_EMBEDDED, NULL); | |
733 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | 733 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | |
734 | } else { | 734 | } else { | |
735 | /* | 735 | /* | |
736 | * Manually select external PHY - MAC mode. | 736 | * Manually select external PHY - MAC mode. | |
737 | * Reverse MII/RMII is for AX88772A PHY mode. | 737 | * Reverse MII/RMII is for AX88772A PHY mode. | |
738 | */ | 738 | */ | |
739 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_SS_ENB | | 739 | axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, AXE_SW_PHY_SELECT_SS_ENB | | |
740 | AXE_SW_PHY_SELECT_EXT | AXE_SW_PHY_SELECT_SS_MII, NULL); | 740 | AXE_SW_PHY_SELECT_EXT | AXE_SW_PHY_SELECT_SS_MII, NULL); | |
741 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | 741 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | |
742 | } | 742 | } | |
743 | 743 | |||
744 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPPD | | 744 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPPD | | |
745 | AXE_SW_RESET_IPRL, NULL); | 745 | AXE_SW_RESET_IPRL, NULL); | |
746 | 746 | |||
747 | /* T1 = min 500ns everywhere */ | 747 | /* T1 = min 500ns everywhere */ | |
748 | usbd_delay_ms(un->un_udev, 150); | 748 | usbd_delay_ms(un->un_udev, 150); | |
749 | 749 | |||
750 | /* Take PHY out of power down. */ | 750 | /* Take PHY out of power down. */ | |
751 | if (un->un_phyno == AXE_772_PHY_NO_EPHY) { | 751 | if (un->un_phyno == AXE_772_PHY_NO_EPHY) { | |
752 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL); | 752 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL); | |
753 | } else { | 753 | } else { | |
754 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRTE, NULL); | 754 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRTE, NULL); | |
755 | } | 755 | } | |
756 | 756 | |||
757 | /* 772 T2 is 60ms. 772A T2 is 160ms, 772B T2 is 600ms */ | 757 | /* 772 T2 is 60ms. 772A T2 is 160ms, 772B T2 is 600ms */ | |
758 | usbd_delay_ms(un->un_udev, 600); | 758 | usbd_delay_ms(un->un_udev, 600); | |
759 | 759 | |||
760 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | 760 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL); | |
761 | 761 | |||
762 | /* T3 = 500ns everywhere */ | 762 | /* T3 = 500ns everywhere */ | |
763 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | 763 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | |
764 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL); | 764 | axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_IPRL, NULL); | |
765 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | 765 | usbd_delay_ms(un->un_udev, hztoms(hz / 32)); | |
766 | } | 766 | } | |
767 | 767 | |||
768 | static void | 768 | static void | |
769 | axe_ax88772a_init(struct axe_softc *sc) | 769 | axe_ax88772a_init(struct axe_softc *sc) | |
770 | { | 770 | { | |
771 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 771 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
772 | 772 | |||
773 | /* Reload EEPROM. */ | 773 | /* Reload EEPROM. */ | |
774 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM, hz / 32); | 774 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM, hz / 32); | |
775 | axe_ax88772_phywake(sc); | 775 | axe_ax88772_phywake(sc); | |
776 | /* Stop MAC. */ | 776 | /* Stop MAC. */ | |
777 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | 777 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | |
778 | } | 778 | } | |
779 | 779 | |||
780 | static void | 780 | static void | |
781 | axe_ax88772b_init(struct axe_softc *sc) | 781 | axe_ax88772b_init(struct axe_softc *sc) | |
782 | { | 782 | { | |
783 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 783 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
784 | struct usbnet * const un = &sc->axe_un; | 784 | struct usbnet * const un = &sc->axe_un; | |
785 | uint16_t eeprom; | 785 | uint16_t eeprom; | |
786 | int i; | 786 | int i; | |
787 | 787 | |||
788 | /* Reload EEPROM. */ | 788 | /* Reload EEPROM. */ | |
789 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM , hz / 32); | 789 | AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM , hz / 32); | |
790 | 790 | |||
791 | /* | 791 | /* | |
792 | * Save PHY power saving configuration(high byte) and | 792 | * Save PHY power saving configuration(high byte) and | |
793 | * clear EEPROM checksum value(low byte). | 793 | * clear EEPROM checksum value(low byte). | |
794 | */ | 794 | */ | |
795 | if (axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_PHY_PWRCFG, | 795 | if (axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_PHY_PWRCFG, | |
796 | &eeprom)) { | 796 | &eeprom)) { | |
797 | aprint_error_dev(un->un_dev, "failed to read eeprom\n"); | 797 | aprint_error_dev(un->un_dev, "failed to read eeprom\n"); | |
798 | return; | 798 | return; | |
799 | } | 799 | } | |
800 | 800 | |||
801 | sc->sc_pwrcfg = le16toh(eeprom) & 0xFF00; | 801 | sc->sc_pwrcfg = le16toh(eeprom) & 0xFF00; | |
802 | 802 | |||
803 | /* | 803 | /* | |
804 | * Auto-loaded default station address from internal ROM is | 804 | * Auto-loaded default station address from internal ROM is | |
805 | * 00:00:00:00:00:00 such that an explicit access to EEPROM | 805 | * 00:00:00:00:00:00 such that an explicit access to EEPROM | |
806 | * is required to get real station address. | 806 | * is required to get real station address. | |
807 | */ | 807 | */ | |
808 | uint8_t *eaddr = un->un_eaddr; | 808 | uint8_t *eaddr = un->un_eaddr; | |
809 | for (i = 0; i < ETHER_ADDR_LEN / 2; i++) { | 809 | for (i = 0; i < ETHER_ADDR_LEN / 2; i++) { | |
810 | if (axe_cmd(sc, AXE_CMD_SROM_READ, 0, | 810 | if (axe_cmd(sc, AXE_CMD_SROM_READ, 0, | |
811 | AXE_EEPROM_772B_NODE_ID + i, &eeprom)) { | 811 | AXE_EEPROM_772B_NODE_ID + i, &eeprom)) { | |
812 | aprint_error_dev(un->un_dev, | 812 | aprint_error_dev(un->un_dev, | |
813 | "failed to read eeprom\n"); | 813 | "failed to read eeprom\n"); | |
814 | eeprom = 0; | 814 | eeprom = 0; | |
815 | } | 815 | } | |
816 | eeprom = le16toh(eeprom); | 816 | eeprom = le16toh(eeprom); | |
817 | *eaddr++ = (uint8_t)(eeprom & 0xFF); | 817 | *eaddr++ = (uint8_t)(eeprom & 0xFF); | |
818 | *eaddr++ = (uint8_t)((eeprom >> 8) & 0xFF); | 818 | *eaddr++ = (uint8_t)((eeprom >> 8) & 0xFF); | |
819 | } | 819 | } | |
820 | /* Wakeup PHY. */ | 820 | /* Wakeup PHY. */ | |
821 | axe_ax88772_phywake(sc); | 821 | axe_ax88772_phywake(sc); | |
822 | /* Stop MAC. */ | 822 | /* Stop MAC. */ | |
823 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | 823 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL); | |
824 | } | 824 | } | |
825 | 825 | |||
826 | #undef AXE_GPIO_WRITE | 826 | #undef AXE_GPIO_WRITE | |
827 | 827 | |||
828 | /* | 828 | /* | |
829 | * Probe for a AX88172 chip. | 829 | * Probe for a AX88172 chip. | |
830 | */ | 830 | */ | |
831 | static int | 831 | static int | |
832 | axe_match(device_t parent, cfdata_t match, void *aux) | 832 | axe_match(device_t parent, cfdata_t match, void *aux) | |
833 | { | 833 | { | |
834 | struct usb_attach_arg *uaa = aux; | 834 | struct usb_attach_arg *uaa = aux; | |
835 | 835 | |||
836 | return axe_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 836 | return axe_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
837 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 837 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
838 | } | 838 | } | |
839 | 839 | |||
840 | /* | 840 | /* | |
841 | * Attach the interface. Allocate softc structures, do ifmedia | 841 | * Attach the interface. Allocate softc structures, do ifmedia | |
842 | * setup and ethernet/BPF attach. | 842 | * setup and ethernet/BPF attach. | |
843 | */ | 843 | */ | |
844 | static void | 844 | static void | |
845 | axe_attach(device_t parent, device_t self, void *aux) | 845 | axe_attach(device_t parent, device_t self, void *aux) | |
846 | { | 846 | { | |
847 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 847 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
848 | USBNET_MII_DECL_DEFAULT(unm); | 848 | USBNET_MII_DECL_DEFAULT(unm); | |
849 | struct axe_softc *sc = device_private(self); | 849 | struct axe_softc *sc = device_private(self); | |
850 | struct usbnet * const un = &sc->axe_un; | 850 | struct usbnet * const un = &sc->axe_un; | |
851 | struct usb_attach_arg *uaa = aux; | 851 | struct usb_attach_arg *uaa = aux; | |
852 | struct usbd_device *dev = uaa->uaa_device; | 852 | struct usbd_device *dev = uaa->uaa_device; | |
853 | usbd_status err; | 853 | usbd_status err; | |
854 | usb_interface_descriptor_t *id; | 854 | usb_interface_descriptor_t *id; | |
855 | usb_endpoint_descriptor_t *ed; | 855 | usb_endpoint_descriptor_t *ed; | |
856 | char *devinfop; | 856 | char *devinfop; | |
857 | unsigned bufsz; | 857 | unsigned bufsz; | |
858 | int i; | 858 | int i; | |
859 | 859 | |||
860 | KASSERT((void *)sc == un); | 860 | KASSERT((void *)sc == un); | |
861 | 861 | |||
862 | aprint_naive("\n"); | 862 | aprint_naive("\n"); | |
863 | aprint_normal("\n"); | 863 | aprint_normal("\n"); | |
864 | devinfop = usbd_devinfo_alloc(dev, 0); | 864 | devinfop = usbd_devinfo_alloc(dev, 0); | |
865 | aprint_normal_dev(self, "%s\n", devinfop); | 865 | aprint_normal_dev(self, "%s\n", devinfop); | |
866 | usbd_devinfo_free(devinfop); | 866 | usbd_devinfo_free(devinfop); | |
867 | 867 | |||
868 | un->un_dev = self; | 868 | un->un_dev = self; | |
869 | un->un_udev = dev; | 869 | un->un_udev = dev; | |
870 | un->un_sc = sc; | 870 | un->un_sc = sc; | |
871 | un->un_ops = &axe_ops; | 871 | un->un_ops = &axe_ops; | |
872 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 872 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
873 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 873 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
874 | un->un_rx_list_cnt = AXE_RX_LIST_CNT; | 874 | un->un_rx_list_cnt = AXE_RX_LIST_CNT; | |
875 | un->un_tx_list_cnt = AXE_TX_LIST_CNT; | 875 | un->un_tx_list_cnt = AXE_TX_LIST_CNT; | |
876 | 876 | |||
877 | err = usbd_set_config_no(dev, AXE_CONFIG_NO, 1); | 877 | err = usbd_set_config_no(dev, AXE_CONFIG_NO, 1); | |
878 | if (err) { | 878 | if (err) { | |
879 | aprint_error_dev(self, "failed to set configuration" | 879 | aprint_error_dev(self, "failed to set configuration" | |
880 | ", err=%s\n", usbd_errstr(err)); | 880 | ", err=%s\n", usbd_errstr(err)); | |
881 | return; | 881 | return; | |
882 | } | 882 | } | |
883 | 883 | |||
884 | un->un_flags = axe_lookup(uaa->uaa_vendor, uaa->uaa_product)->axe_flags; | 884 | un->un_flags = axe_lookup(uaa->uaa_vendor, uaa->uaa_product)->axe_flags; | |
885 | 885 | |||
886 | err = usbd_device2interface_handle(dev, AXE_IFACE_IDX, &un->un_iface); | 886 | err = usbd_device2interface_handle(dev, AXE_IFACE_IDX, &un->un_iface); | |
887 | if (err) { | 887 | if (err) { | |
888 | aprint_error_dev(self, "getting interface handle failed\n"); | 888 | aprint_error_dev(self, "getting interface handle failed\n"); | |
889 | return; | 889 | return; | |
890 | } | 890 | } | |
891 | 891 | |||
892 | id = usbd_get_interface_descriptor(un->un_iface); | 892 | id = usbd_get_interface_descriptor(un->un_iface); | |
893 | 893 | |||
894 | /* decide on what our bufsize will be */ | 894 | /* decide on what our bufsize will be */ | |
895 | if (AXE_IS_172(un)) | 895 | if (AXE_IS_172(un)) | |
896 | bufsz = AXE_172_BUFSZ; | 896 | bufsz = AXE_172_BUFSZ; | |
897 | else | 897 | else | |
898 | bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? | 898 | bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? | |
899 | AXE_178_MAX_BUFSZ : AXE_178_MIN_BUFSZ; | 899 | AXE_178_MAX_BUFSZ : AXE_178_MIN_BUFSZ; | |
900 | un->un_rx_bufsz = un->un_tx_bufsz = bufsz; | 900 | un->un_rx_bufsz = un->un_tx_bufsz = bufsz; | |
901 | 901 | |||
902 | un->un_ed[USBNET_ENDPT_RX] = 0; | 902 | un->un_ed[USBNET_ENDPT_RX] = 0; | |
903 | un->un_ed[USBNET_ENDPT_TX] = 0; | 903 | un->un_ed[USBNET_ENDPT_TX] = 0; | |
904 | un->un_ed[USBNET_ENDPT_INTR] = 0; | 904 | un->un_ed[USBNET_ENDPT_INTR] = 0; | |
905 | 905 | |||
906 | /* Find endpoints. */ | 906 | /* Find endpoints. */ | |
907 | for (i = 0; i < id->bNumEndpoints; i++) { | 907 | for (i = 0; i < id->bNumEndpoints; i++) { | |
908 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 908 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
909 | if (ed == NULL) { | 909 | if (ed == NULL) { | |
910 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 910 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
911 | return; | 911 | return; | |
912 | } | 912 | } | |
913 | const uint8_t xt = UE_GET_XFERTYPE(ed->bmAttributes); | 913 | const uint8_t xt = UE_GET_XFERTYPE(ed->bmAttributes); | |
914 | const uint8_t dir = UE_GET_DIR(ed->bEndpointAddress); | 914 | const uint8_t dir = UE_GET_DIR(ed->bEndpointAddress); | |
915 | 915 | |||
916 | if (dir == UE_DIR_IN && xt == UE_BULK && | 916 | if (dir == UE_DIR_IN && xt == UE_BULK && | |
917 | un->un_ed[USBNET_ENDPT_RX] == 0) { | 917 | un->un_ed[USBNET_ENDPT_RX] == 0) { | |
918 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 918 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
919 | } else if (dir == UE_DIR_OUT && xt == UE_BULK && | 919 | } else if (dir == UE_DIR_OUT && xt == UE_BULK && | |
920 | un->un_ed[USBNET_ENDPT_TX] == 0) { | 920 | un->un_ed[USBNET_ENDPT_TX] == 0) { | |
921 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 921 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
922 | } else if (dir == UE_DIR_IN && xt == UE_INTERRUPT) { | 922 | } else if (dir == UE_DIR_IN && xt == UE_INTERRUPT) { | |
923 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 923 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
924 | } | 924 | } | |
925 | } | 925 | } | |
926 | 926 | |||
927 | /* Set these up now for axe_cmd(). */ | 927 | /* Set these up now for axe_cmd(). */ | |
928 | usbnet_attach(un, "axedet"); | 928 | usbnet_attach(un, "axedet"); | |
929 | 929 | |||
930 | /* We need the PHYID for init dance in some cases */ | 930 | /* We need the PHYID for init dance in some cases */ | |
931 | if (axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, &sc->axe_phyaddrs)) { | 931 | if (axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, &sc->axe_phyaddrs)) { | |
932 | aprint_error_dev(self, "failed to read phyaddrs\n"); | 932 | aprint_error_dev(self, "failed to read phyaddrs\n"); | |
933 | return; | 933 | return; | |
934 | } | 934 | } | |
935 | 935 | |||
936 | DPRINTF(" phyaddrs[0]: %jx phyaddrs[1]: %jx", | 936 | DPRINTF(" phyaddrs[0]: %jx phyaddrs[1]: %jx", | |
937 | sc->axe_phyaddrs[0], sc->axe_phyaddrs[1], 0, 0); | 937 | sc->axe_phyaddrs[0], sc->axe_phyaddrs[1], 0, 0); | |
938 | un->un_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI); | 938 | un->un_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI); | |
939 | if (un->un_phyno == -1) | 939 | if (un->un_phyno == -1) | |
940 | un->un_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC); | 940 | un->un_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC); | |
941 | if (un->un_phyno == -1) { | 941 | if (un->un_phyno == -1) { | |
942 | DPRINTF(" no valid PHY address found, assuming PHY address 0", | 942 | DPRINTF(" no valid PHY address found, assuming PHY address 0", | |
943 | 0, 0, 0, 0); | 943 | 0, 0, 0, 0); | |
944 | un->un_phyno = 0; | 944 | un->un_phyno = 0; | |
945 | } | 945 | } | |
946 | 946 | |||
947 | /* Initialize controller and get station address. */ | 947 | /* Initialize controller and get station address. */ | |
948 | 948 | |||
949 | axe_ax_init(un); | 949 | axe_ax_init(un); | |
950 | 950 | |||
951 | /* | 951 | /* | |
952 | * Fetch IPG values. | 952 | * Fetch IPG values. | |
953 | */ | 953 | */ | |
954 | if (un->un_flags & (AX772A | AX772B)) { | 954 | if (un->un_flags & (AX772A | AX772B)) { | |
955 | /* Set IPG values. */ | 955 | /* Set IPG values. */ | |
956 | sc->axe_ipgs[0] = AXE_IPG0_DEFAULT; | 956 | sc->axe_ipgs[0] = AXE_IPG0_DEFAULT; | |
957 | sc->axe_ipgs[1] = AXE_IPG1_DEFAULT; | 957 | sc->axe_ipgs[1] = AXE_IPG1_DEFAULT; | |
958 | sc->axe_ipgs[2] = AXE_IPG2_DEFAULT; | 958 | sc->axe_ipgs[2] = AXE_IPG2_DEFAULT; | |
959 | } else { | 959 | } else { | |
960 | if (axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->axe_ipgs)) { | 960 | if (axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->axe_ipgs)) { | |
961 | aprint_error_dev(self, "failed to read ipg\n"); | 961 | aprint_error_dev(self, "failed to read ipg\n"); | |
962 | return; | 962 | return; | |
963 | } | 963 | } | |
964 | } | 964 | } | |
965 | 965 | |||
966 | if (!AXE_IS_172(un)) | 966 | if (!AXE_IS_172(un)) | |
967 | usbnet_ec(un)->ec_capabilities = ETHERCAP_VLAN_MTU; | 967 | usbnet_ec(un)->ec_capabilities = ETHERCAP_VLAN_MTU; | |
968 | if (un->un_flags & AX772B) { | 968 | if (un->un_flags & AX772B) { | |
969 | struct ifnet *ifp = usbnet_ifp(un); | 969 | struct ifnet *ifp = usbnet_ifp(un); | |
970 | 970 | |||
971 | ifp->if_capabilities = | 971 | ifp->if_capabilities = | |
972 | IFCAP_CSUM_IPv4_Rx | | 972 | IFCAP_CSUM_IPv4_Rx | | |
973 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | 973 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | |
974 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; | 974 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; | |
975 | /* | 975 | /* | |
976 | * Checksum offloading of AX88772B also works with VLAN | 976 | * Checksum offloading of AX88772B also works with VLAN | |
977 | * tagged frames but there is no way to take advantage | 977 | * tagged frames but there is no way to take advantage | |
978 | * of the feature because vlan(4) assumes | 978 | * of the feature because vlan(4) assumes | |
979 | * IFCAP_VLAN_HWTAGGING is prerequisite condition to | 979 | * IFCAP_VLAN_HWTAGGING is prerequisite condition to | |
980 | * support checksum offloading with VLAN. VLAN hardware | 980 | * support checksum offloading with VLAN. VLAN hardware | |
981 | * tagging support of AX88772B is very limited so it's | 981 | * tagging support of AX88772B is very limited so it's | |
982 | * not possible to announce IFCAP_VLAN_HWTAGGING. | 982 | * not possible to announce IFCAP_VLAN_HWTAGGING. | |
983 | */ | 983 | */ | |
984 | } | 984 | } | |
985 | if (un->un_flags & (AX772A | AX772B | AX178)) | 985 | if (un->un_flags & (AX772A | AX772B | AX178)) | |
986 | unm.un_mii_flags = MIIF_DOPAUSE; | 986 | unm.un_mii_flags = MIIF_DOPAUSE; | |
987 | 987 | |||
988 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 988 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
989 | 0, &unm); | 989 | 0, &unm); | |
990 | } | 990 | } | |
991 | 991 | |||
992 | static void | 992 | static void | |
993 | axe_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) | 993 | axe_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) | |
994 | { | 994 | { | |
995 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 995 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
996 | struct axe_softc * const sc = usbnet_softc(un); | 996 | struct axe_softc * const sc = usbnet_softc(un); | |
997 | struct ifnet *ifp = usbnet_ifp(un); | 997 | struct ifnet *ifp = usbnet_ifp(un); | |
998 | uint8_t *buf = c->unc_buf; | 998 | uint8_t *buf = c->unc_buf; | |
999 | 999 | |||
1000 | do { | 1000 | do { | |
1001 | u_int pktlen = 0; | 1001 | u_int pktlen = 0; | |
1002 | u_int rxlen = 0; | 1002 | u_int rxlen = 0; | |
1003 | int flags = 0; | 1003 | int flags = 0; | |
1004 | 1004 | |||
1005 | if ((un->un_flags & AXSTD_FRAME) != 0) { | 1005 | if ((un->un_flags & AXSTD_FRAME) != 0) { | |
1006 | struct axe_sframe_hdr hdr; | 1006 | struct axe_sframe_hdr hdr; | |
1007 | 1007 | |||
1008 | if (total_len < sizeof(hdr)) { | 1008 | if (total_len < sizeof(hdr)) { | |
1009 | if_statinc(ifp, if_ierrors); | 1009 | if_statinc(ifp, if_ierrors); | |
1010 | break; | 1010 | break; | |
1011 | } | 1011 | } | |
1012 | 1012 | |||
1013 | memcpy(&hdr, buf, sizeof(hdr)); | 1013 | memcpy(&hdr, buf, sizeof(hdr)); | |
1014 | 1014 | |||
1015 | DPRINTFN(20, "total_len %#jx len %#jx ilen %#jx", | 1015 | DPRINTFN(20, "total_len %#jx len %#jx ilen %#jx", | |
1016 | total_len, | 1016 | total_len, | |
1017 | (le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK), | 1017 | (le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK), | |
1018 | (le16toh(hdr.ilen) & AXE_RH1M_RXLEN_MASK), 0); | 1018 | (le16toh(hdr.ilen) & AXE_RH1M_RXLEN_MASK), 0); | |
1019 | 1019 | |||
1020 | total_len -= sizeof(hdr); | 1020 | total_len -= sizeof(hdr); | |
1021 | buf += sizeof(hdr); | 1021 | buf += sizeof(hdr); | |
1022 | 1022 | |||
1023 | if (((le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK) ^ | 1023 | if (((le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK) ^ | |
1024 | (le16toh(hdr.ilen) & AXE_RH1M_RXLEN_MASK)) != | 1024 | (le16toh(hdr.ilen) & AXE_RH1M_RXLEN_MASK)) != | |
1025 | AXE_RH1M_RXLEN_MASK) { | 1025 | AXE_RH1M_RXLEN_MASK) { | |
1026 | if_statinc(ifp, if_ierrors); | 1026 | if_statinc(ifp, if_ierrors); | |
1027 | break; | 1027 | break; | |
1028 | } | 1028 | } | |
1029 | 1029 | |||
1030 | rxlen = le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK; | 1030 | rxlen = le16toh(hdr.len) & AXE_RH1M_RXLEN_MASK; | |
1031 | if (total_len < rxlen) { | 1031 | if (total_len < rxlen) { | |
1032 | pktlen = total_len; | 1032 | pktlen = total_len; | |
1033 | total_len = 0; | 1033 | total_len = 0; | |
1034 | } else { | 1034 | } else { | |
1035 | pktlen = rxlen; | 1035 | pktlen = rxlen; | |
1036 | rxlen = roundup2(rxlen, 2); | 1036 | rxlen = roundup2(rxlen, 2); | |
1037 | total_len -= rxlen; | 1037 | total_len -= rxlen; | |
1038 | } | 1038 | } | |
1039 | 1039 | |||
1040 | } else if ((un->un_flags & AXCSUM_FRAME) != 0) { | 1040 | } else if ((un->un_flags & AXCSUM_FRAME) != 0) { | |
1041 | struct axe_csum_hdr csum_hdr; | 1041 | struct axe_csum_hdr csum_hdr; | |
1042 | 1042 | |||
1043 | if (total_len < sizeof(csum_hdr)) { | 1043 | if (total_len < sizeof(csum_hdr)) { | |
1044 | if_statinc(ifp, if_ierrors); | 1044 | if_statinc(ifp, if_ierrors); | |
1045 | break; | 1045 | break; | |
1046 | } | 1046 | } | |
1047 | 1047 | |||
1048 | memcpy(&csum_hdr, buf, sizeof(csum_hdr)); | 1048 | memcpy(&csum_hdr, buf, sizeof(csum_hdr)); | |
1049 | 1049 | |||
1050 | csum_hdr.len = le16toh(csum_hdr.len); | 1050 | csum_hdr.len = le16toh(csum_hdr.len); | |
1051 | csum_hdr.ilen = le16toh(csum_hdr.ilen); | 1051 | csum_hdr.ilen = le16toh(csum_hdr.ilen); | |
1052 | csum_hdr.cstatus = le16toh(csum_hdr.cstatus); | 1052 | csum_hdr.cstatus = le16toh(csum_hdr.cstatus); | |
1053 | 1053 | |||
1054 | DPRINTFN(20, "total_len %#jx len %#jx ilen %#jx" | 1054 | DPRINTFN(20, "total_len %#jx len %#jx ilen %#jx" | |
1055 | " cstatus %#jx", total_len, | 1055 | " cstatus %#jx", total_len, | |
1056 | csum_hdr.len, csum_hdr.ilen, csum_hdr.cstatus); | 1056 | csum_hdr.len, csum_hdr.ilen, csum_hdr.cstatus); | |
1057 | 1057 | |||
1058 | if ((AXE_CSUM_RXBYTES(csum_hdr.len) ^ | 1058 | if ((AXE_CSUM_RXBYTES(csum_hdr.len) ^ | |
1059 | AXE_CSUM_RXBYTES(csum_hdr.ilen)) != | 1059 | AXE_CSUM_RXBYTES(csum_hdr.ilen)) != | |
1060 | sc->sc_lenmask) { | 1060 | sc->sc_lenmask) { | |
1061 | /* we lost sync */ | 1061 | /* we lost sync */ | |
1062 | if_statinc(ifp, if_ierrors); | 1062 | if_statinc(ifp, if_ierrors); | |
1063 | DPRINTFN(20, "len %#jx ilen %#jx lenmask %#jx " | 1063 | DPRINTFN(20, "len %#jx ilen %#jx lenmask %#jx " | |
1064 | "err", | 1064 | "err", | |
1065 | AXE_CSUM_RXBYTES(csum_hdr.len), | 1065 | AXE_CSUM_RXBYTES(csum_hdr.len), | |
1066 | AXE_CSUM_RXBYTES(csum_hdr.ilen), | 1066 | AXE_CSUM_RXBYTES(csum_hdr.ilen), | |
1067 | sc->sc_lenmask, 0); | 1067 | sc->sc_lenmask, 0); | |
1068 | break; | 1068 | break; | |
1069 | } | 1069 | } | |
1070 | /* | 1070 | /* | |
1071 | * Get total transferred frame length including | 1071 | * Get total transferred frame length including | |
1072 | * checksum header. The length should be multiple | 1072 | * checksum header. The length should be multiple | |
1073 | * of 4. | 1073 | * of 4. | |
1074 | */ | 1074 | */ | |
1075 | pktlen = AXE_CSUM_RXBYTES(csum_hdr.len); | 1075 | pktlen = AXE_CSUM_RXBYTES(csum_hdr.len); | |
1076 | u_int len = sizeof(csum_hdr) + pktlen; | 1076 | u_int len = sizeof(csum_hdr) + pktlen; | |
1077 | len = (len + 3) & ~3; | 1077 | len = (len + 3) & ~3; | |
1078 | if (total_len < len) { | 1078 | if (total_len < len) { | |
1079 | DPRINTFN(20, "total_len %#jx < len %#jx", | 1079 | DPRINTFN(20, "total_len %#jx < len %#jx", | |
1080 | total_len, len, 0, 0); | 1080 | total_len, len, 0, 0); | |
1081 | /* invalid length */ | 1081 | /* invalid length */ | |
1082 | if_statinc(ifp, if_ierrors); | 1082 | if_statinc(ifp, if_ierrors); | |
1083 | break; | 1083 | break; | |
1084 | } | 1084 | } | |
1085 | buf += sizeof(csum_hdr); | 1085 | buf += sizeof(csum_hdr); | |
1086 | 1086 | |||
1087 | const uint16_t cstatus = csum_hdr.cstatus; | 1087 | const uint16_t cstatus = csum_hdr.cstatus; | |
1088 | 1088 | |||
1089 | if (cstatus & AXE_CSUM_HDR_L3_TYPE_IPV4) { | 1089 | if (cstatus & AXE_CSUM_HDR_L3_TYPE_IPV4) { | |
1090 | if (cstatus & AXE_CSUM_HDR_L4_CSUM_ERR) | 1090 | if (cstatus & AXE_CSUM_HDR_L4_CSUM_ERR) | |
1091 | flags |= M_CSUM_TCP_UDP_BAD; | 1091 | flags |= M_CSUM_TCP_UDP_BAD; | |
1092 | if (cstatus & AXE_CSUM_HDR_L3_CSUM_ERR) | 1092 | if (cstatus & AXE_CSUM_HDR_L3_CSUM_ERR) | |
1093 | flags |= M_CSUM_IPv4_BAD; | 1093 | flags |= M_CSUM_IPv4_BAD; | |
1094 | 1094 | |||
1095 | const uint16_t l4type = | 1095 | const uint16_t l4type = | |
1096 | cstatus & AXE_CSUM_HDR_L4_TYPE_MASK; | 1096 | cstatus & AXE_CSUM_HDR_L4_TYPE_MASK; | |
1097 | 1097 | |||
1098 | if (l4type == AXE_CSUM_HDR_L4_TYPE_TCP) | 1098 | if (l4type == AXE_CSUM_HDR_L4_TYPE_TCP) | |
1099 | flags |= M_CSUM_TCPv4; | 1099 | flags |= M_CSUM_TCPv4; | |
1100 | if (l4type == AXE_CSUM_HDR_L4_TYPE_UDP) | 1100 | if (l4type == AXE_CSUM_HDR_L4_TYPE_UDP) | |
1101 | flags |= M_CSUM_UDPv4; | 1101 | flags |= M_CSUM_UDPv4; | |
1102 | } | 1102 | } | |
1103 | if (total_len < len) { | 1103 | if (total_len < len) { | |
1104 | pktlen = total_len; | 1104 | pktlen = total_len; | |
1105 | total_len = 0; | 1105 | total_len = 0; | |
1106 | } else { | 1106 | } else { | |
1107 | total_len -= len; | 1107 | total_len -= len; | |
1108 | rxlen = len - sizeof(csum_hdr); | 1108 | rxlen = len - sizeof(csum_hdr); | |
1109 | } | 1109 | } | |
1110 | DPRINTFN(20, "total_len %#jx len %#jx pktlen %#jx" | 1110 | DPRINTFN(20, "total_len %#jx len %#jx pktlen %#jx" | |
1111 | " rxlen %#jx", total_len, len, pktlen, rxlen); | 1111 | " rxlen %#jx", total_len, len, pktlen, rxlen); | |
1112 | } else { /* AX172 */ | 1112 | } else { /* AX172 */ | |
1113 | pktlen = rxlen = total_len; | 1113 | pktlen = rxlen = total_len; | |
1114 | total_len = 0; | 1114 | total_len = 0; | |
1115 | } | 1115 | } | |
1116 | 1116 | |||
1117 | usbnet_enqueue(un, buf, pktlen, flags, 0, 0); | 1117 | usbnet_enqueue(un, buf, pktlen, flags, 0, 0); | |
1118 | buf += rxlen; | 1118 | buf += rxlen; | |
1119 | 1119 | |||
1120 | } while (total_len > 0); | 1120 | } while (total_len > 0); | |
1121 | 1121 | |||
1122 | DPRINTFN(10, "start rx", 0, 0, 0, 0); | 1122 | DPRINTFN(10, "start rx", 0, 0, 0, 0); | |
1123 | } | 1123 | } | |
1124 | 1124 | |||
1125 | static unsigned | 1125 | static unsigned | |
1126 | axe_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 1126 | axe_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
1127 | { | 1127 | { | |
1128 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 1128 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
1129 | struct axe_sframe_hdr hdr, tlr; | 1129 | struct axe_sframe_hdr hdr, tlr; | |
1130 | size_t hdr_len = 0, tlr_len = 0; | 1130 | size_t hdr_len = 0, tlr_len = 0; | |
1131 | int length, boundary; | 1131 | int length, boundary; | |
1132 | 1132 | |||
1133 | if (!AXE_IS_172(un)) { | 1133 | if (!AXE_IS_172(un)) { | |
1134 | /* | 1134 | /* | |
1135 | * Copy the mbuf data into a contiguous buffer, leaving two | 1135 | * Copy the mbuf data into a contiguous buffer, leaving two | |
1136 | * bytes at the beginning to hold the frame length. | 1136 | * bytes at the beginning to hold the frame length. | |
1137 | */ | 1137 | */ | |
1138 | boundary = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? 512 : 64; | 1138 | boundary = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? 512 : 64; | |
1139 | 1139 | |||
1140 | hdr.len = htole16(m->m_pkthdr.len); | 1140 | hdr.len = htole16(m->m_pkthdr.len); | |
1141 | hdr.ilen = ~hdr.len; | 1141 | hdr.ilen = ~hdr.len; | |
1142 | hdr_len = sizeof(hdr); | 1142 | hdr_len = sizeof(hdr); | |
1143 | 1143 | |||
1144 | length = hdr_len + m->m_pkthdr.len; | 1144 | length = hdr_len + m->m_pkthdr.len; | |
1145 | 1145 | |||
1146 | if ((length % boundary) == 0) { | 1146 | if ((length % boundary) == 0) { | |
1147 | tlr.len = 0x0000; | 1147 | tlr.len = 0x0000; | |
1148 | tlr.ilen = 0xffff; | 1148 | tlr.ilen = 0xffff; | |
1149 | tlr_len = sizeof(tlr); | 1149 | tlr_len = sizeof(tlr); | |
1150 | } | 1150 | } | |
1151 | DPRINTFN(20, "length %jx m_pkthdr.len %jx hdrsize %#jx", | 1151 | DPRINTFN(20, "length %jx m_pkthdr.len %jx hdrsize %#jx", | |
1152 | length, m->m_pkthdr.len, sizeof(hdr), 0); | 1152 | length, m->m_pkthdr.len, sizeof(hdr), 0); | |
1153 | } | 1153 | } | |
1154 | 1154 | |||
1155 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - hdr_len - tlr_len) | 1155 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - hdr_len - tlr_len) | |
1156 | return 0; | 1156 | return 0; | |
1157 | length = hdr_len + m->m_pkthdr.len + tlr_len; | 1157 | length = hdr_len + m->m_pkthdr.len + tlr_len; | |
1158 | 1158 | |||
1159 | if (hdr_len) | 1159 | if (hdr_len) | |
1160 | memcpy(c->unc_buf, &hdr, hdr_len); | 1160 | memcpy(c->unc_buf, &hdr, hdr_len); | |
1161 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + hdr_len); | 1161 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + hdr_len); | |
1162 | if (tlr_len) | 1162 | if (tlr_len) | |
1163 | memcpy(c->unc_buf + length - tlr_len, &tlr, tlr_len); | 1163 | memcpy(c->unc_buf + length - tlr_len, &tlr, tlr_len); | |
1164 | 1164 | |||
1165 | return length; | 1165 | return length; | |
1166 | } | 1166 | } | |
1167 | 1167 | |||
1168 | static void | 1168 | static void | |
1169 | axe_csum_cfg(struct axe_softc *sc) | 1169 | axe_csum_cfg(struct axe_softc *sc) | |
1170 | { | 1170 | { | |
1171 | struct usbnet * const un = &sc->axe_un; | 1171 | struct usbnet * const un = &sc->axe_un; | |
1172 | struct ifnet * const ifp = usbnet_ifp(un); | 1172 | struct ifnet * const ifp = usbnet_ifp(un); | |
1173 | uint16_t csum1, csum2; | 1173 | uint16_t csum1, csum2; | |
1174 | 1174 | |||
1175 | if ((un->un_flags & AX772B) != 0) { | 1175 | if ((un->un_flags & AX772B) != 0) { | |
1176 | csum1 = 0; | 1176 | csum1 = 0; | |
1177 | csum2 = 0; | 1177 | csum2 = 0; | |
1178 | if ((ifp->if_capenable & IFCAP_CSUM_IPv4_Tx) != 0) | 1178 | if ((ifp->if_capenable & IFCAP_CSUM_IPv4_Tx) != 0) | |
1179 | csum1 |= AXE_TXCSUM_IP; | 1179 | csum1 |= AXE_TXCSUM_IP; | |
1180 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv4_Tx) != 0) | 1180 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv4_Tx) != 0) | |
1181 | csum1 |= AXE_TXCSUM_TCP; | 1181 | csum1 |= AXE_TXCSUM_TCP; | |
1182 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv4_Tx) != 0) | 1182 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv4_Tx) != 0) | |
1183 | csum1 |= AXE_TXCSUM_UDP; | 1183 | csum1 |= AXE_TXCSUM_UDP; | |
1184 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv6_Tx) != 0) | 1184 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv6_Tx) != 0) | |
1185 | csum1 |= AXE_TXCSUM_TCPV6; | 1185 | csum1 |= AXE_TXCSUM_TCPV6; | |
1186 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv6_Tx) != 0) | 1186 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv6_Tx) != 0) | |
1187 | csum1 |= AXE_TXCSUM_UDPV6; | 1187 | csum1 |= AXE_TXCSUM_UDPV6; | |
1188 | axe_cmd(sc, AXE_772B_CMD_WRITE_TXCSUM, csum2, csum1, NULL); | 1188 | axe_cmd(sc, AXE_772B_CMD_WRITE_TXCSUM, csum2, csum1, NULL); | |
1189 | csum1 = 0; | 1189 | csum1 = 0; | |
1190 | csum2 = 0; | 1190 | csum2 = 0; | |
1191 | 1191 | |||
1192 | if ((ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) != 0) | 1192 | if ((ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) != 0) | |
1193 | csum1 |= AXE_RXCSUM_IP; | 1193 | csum1 |= AXE_RXCSUM_IP; | |
1194 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv4_Rx) != 0) | 1194 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv4_Rx) != 0) | |
1195 | csum1 |= AXE_RXCSUM_TCP; | 1195 | csum1 |= AXE_RXCSUM_TCP; | |
1196 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv4_Rx) != 0) | 1196 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv4_Rx) != 0) | |
1197 | csum1 |= AXE_RXCSUM_UDP; | 1197 | csum1 |= AXE_RXCSUM_UDP; | |
1198 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv6_Rx) != 0) | 1198 | if ((ifp->if_capenable & IFCAP_CSUM_TCPv6_Rx) != 0) | |
1199 | csum1 |= AXE_RXCSUM_TCPV6; | 1199 | csum1 |= AXE_RXCSUM_TCPV6; | |
1200 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv6_Rx) != 0) | 1200 | if ((ifp->if_capenable & IFCAP_CSUM_UDPv6_Rx) != 0) | |
1201 | csum1 |= AXE_RXCSUM_UDPV6; | 1201 | csum1 |= AXE_RXCSUM_UDPV6; | |
1202 | axe_cmd(sc, AXE_772B_CMD_WRITE_RXCSUM, csum2, csum1, NULL); | 1202 | axe_cmd(sc, AXE_772B_CMD_WRITE_RXCSUM, csum2, csum1, NULL); | |
1203 | } | 1203 | } | |
1204 | } | 1204 | } | |
1205 | 1205 | |||
1206 | static int | 1206 | static int | |
1207 | axe_uno_init(struct ifnet *ifp) | 1207 | axe_uno_init(struct ifnet *ifp) | |
1208 | { | 1208 | { | |
1209 | AXEHIST_FUNC(); AXEHIST_CALLED(); | 1209 | AXEHIST_FUNC(); AXEHIST_CALLED(); | |
1210 | struct usbnet * const un = ifp->if_softc; | 1210 | struct usbnet * const un = ifp->if_softc; | |
1211 | struct axe_softc * const sc = usbnet_softc(un); | 1211 | struct axe_softc * const sc = usbnet_softc(un); | |
1212 | int rxmode; | 1212 | int rxmode; | |
1213 | 1213 | |||
1214 | if (usbnet_isdying(un)) | |||
1215 | return EIO; | |||
1216 | ||||
1217 | /* Cancel pending I/O */ | 1214 | /* Cancel pending I/O */ | |
1218 | usbnet_stop(un, ifp, 1); | 1215 | usbnet_stop(un, ifp, 1); | |
1219 | 1216 | |||
1220 | /* Reset the ethernet interface. */ | 1217 | /* Reset the ethernet interface. */ | |
1221 | axe_reset(un); | 1218 | axe_reset(un); | |
1222 | 1219 | |||
1223 | #if 0 | 1220 | #if 0 | |
1224 | ret = asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_2 | | 1221 | ret = asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_2 | | |
1225 | AX_GPIO_GPO2EN, 5, in_pm); | 1222 | AX_GPIO_GPO2EN, 5, in_pm); | |
1226 | #endif | 1223 | #endif | |
1227 | /* Set MAC address and transmitter IPG values. */ | 1224 | /* Set MAC address and transmitter IPG values. */ | |
1228 | if (AXE_IS_172(un)) { | 1225 | if (AXE_IS_172(un)) { | |
1229 | axe_cmd(sc, AXE_172_CMD_WRITE_NODEID, 0, 0, un->un_eaddr); | 1226 | axe_cmd(sc, AXE_172_CMD_WRITE_NODEID, 0, 0, un->un_eaddr); | |
1230 | axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->axe_ipgs[0], NULL); | 1227 | axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->axe_ipgs[0], NULL); | |
1231 | axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->axe_ipgs[1], NULL); | 1228 | axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->axe_ipgs[1], NULL); | |
1232 | axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->axe_ipgs[2], NULL); | 1229 | axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->axe_ipgs[2], NULL); | |
1233 | } else { | 1230 | } else { | |
1234 | axe_cmd(sc, AXE_178_CMD_WRITE_NODEID, 0, 0, un->un_eaddr); | 1231 | axe_cmd(sc, AXE_178_CMD_WRITE_NODEID, 0, 0, un->un_eaddr); | |
1235 | axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->axe_ipgs[2], | 1232 | axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->axe_ipgs[2], | |
1236 | (sc->axe_ipgs[1] << 8) | (sc->axe_ipgs[0]), NULL); | 1233 | (sc->axe_ipgs[1] << 8) | (sc->axe_ipgs[0]), NULL); | |
1237 | 1234 | |||
1238 | un->un_flags &= ~(AXSTD_FRAME | AXCSUM_FRAME); | 1235 | un->un_flags &= ~(AXSTD_FRAME | AXCSUM_FRAME); | |
1239 | if ((un->un_flags & AX772B) != 0 && | 1236 | if ((un->un_flags & AX772B) != 0 && | |
1240 | (ifp->if_capenable & AX_RXCSUM) != 0) { | 1237 | (ifp->if_capenable & AX_RXCSUM) != 0) { | |
1241 | sc->sc_lenmask = AXE_CSUM_HDR_LEN_MASK; | 1238 | sc->sc_lenmask = AXE_CSUM_HDR_LEN_MASK; | |
1242 | un->un_flags |= AXCSUM_FRAME; | 1239 | un->un_flags |= AXCSUM_FRAME; | |
1243 | } else { | 1240 | } else { | |
1244 | sc->sc_lenmask = AXE_HDR_LEN_MASK; | 1241 | sc->sc_lenmask = AXE_HDR_LEN_MASK; | |
1245 | un->un_flags |= AXSTD_FRAME; | 1242 | un->un_flags |= AXSTD_FRAME; | |
1246 | } | 1243 | } | |
1247 | } | 1244 | } | |
1248 | 1245 | |||
1249 | /* Configure TX/RX checksum offloading. */ | 1246 | /* Configure TX/RX checksum offloading. */ | |
1250 | axe_csum_cfg(sc); | 1247 | axe_csum_cfg(sc); | |
1251 | 1248 | |||
1252 | if (un->un_flags & AX772B) { | 1249 | if (un->un_flags & AX772B) { | |
1253 | /* AX88772B uses different maximum frame burst configuration. */ | 1250 | /* AX88772B uses different maximum frame burst configuration. */ | |
1254 | axe_cmd(sc, AXE_772B_CMD_RXCTL_WRITE_CFG, | 1251 | axe_cmd(sc, AXE_772B_CMD_RXCTL_WRITE_CFG, | |
1255 | ax88772b_mfb_table[AX88772B_MFB_16K].threshold, | 1252 | ax88772b_mfb_table[AX88772B_MFB_16K].threshold, | |
1256 | ax88772b_mfb_table[AX88772B_MFB_16K].byte_cnt, NULL); | 1253 | ax88772b_mfb_table[AX88772B_MFB_16K].byte_cnt, NULL); | |
1257 | } | 1254 | } | |
1258 | /* Enable receiver, set RX mode */ | 1255 | /* Enable receiver, set RX mode */ | |
1259 | rxmode = (AXE_RXCMD_BROADCAST | AXE_RXCMD_MULTICAST | AXE_RXCMD_ENABLE); | 1256 | rxmode = (AXE_RXCMD_BROADCAST | AXE_RXCMD_MULTICAST | AXE_RXCMD_ENABLE); | |
1260 | if (AXE_IS_172(un)) | 1257 | if (AXE_IS_172(un)) | |
1261 | rxmode |= AXE_172_RXCMD_UNICAST; | 1258 | rxmode |= AXE_172_RXCMD_UNICAST; | |
1262 | else { | 1259 | else { | |
1263 | if (un->un_flags & AX772B) { | 1260 | if (un->un_flags & AX772B) { | |
1264 | /* | 1261 | /* | |
1265 | * Select RX header format type 1. Aligning IP | 1262 | * Select RX header format type 1. Aligning IP | |
1266 | * header on 4 byte boundary is not needed when | 1263 | * header on 4 byte boundary is not needed when | |
1267 | * checksum offloading feature is not used | 1264 | * checksum offloading feature is not used | |
1268 | * because we always copy the received frame in | 1265 | * because we always copy the received frame in | |
1269 | * RX handler. When RX checksum offloading is | 1266 | * RX handler. When RX checksum offloading is | |
1270 | * active, aligning IP header is required to | 1267 | * active, aligning IP header is required to | |
1271 | * reflect actual frame length including RX | 1268 | * reflect actual frame length including RX | |
1272 | * header size. | 1269 | * header size. | |
1273 | */ | 1270 | */ | |
1274 | rxmode |= AXE_772B_RXCMD_HDR_TYPE_1; | 1271 | rxmode |= AXE_772B_RXCMD_HDR_TYPE_1; | |
1275 | if (un->un_flags & AXCSUM_FRAME) | 1272 | if (un->un_flags & AXCSUM_FRAME) | |
1276 | rxmode |= AXE_772B_RXCMD_IPHDR_ALIGN; | 1273 | rxmode |= AXE_772B_RXCMD_IPHDR_ALIGN; | |
1277 | } else { | 1274 | } else { | |
1278 | /* | 1275 | /* | |
1279 | * Default Rx buffer size is too small to get | 1276 | * Default Rx buffer size is too small to get | |
1280 | * maximum performance. | 1277 | * maximum performance. | |
1281 | */ | 1278 | */ | |
1282 | #if 0 | 1279 | #if 0 | |
1283 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) { | 1280 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) { | |
1284 | /* Largest possible USB buffer size for AX88178 */ | 1281 | /* Largest possible USB buffer size for AX88178 */ | |
1285 | } | 1282 | } | |
1286 | #endif | 1283 | #endif | |
1287 | rxmode |= AXE_178_RXCMD_MFB_16384; | 1284 | rxmode |= AXE_178_RXCMD_MFB_16384; | |
1288 | } | 1285 | } | |
1289 | } | 1286 | } | |
1290 | 1287 | |||
1291 | DPRINTF("rxmode %#jx", rxmode, 0, 0, 0); | 1288 | DPRINTF("rxmode %#jx", rxmode, 0, 0, 0); | |
1292 | 1289 | |||
1293 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); | 1290 | axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL); | |
1294 | 1291 | |||
1295 | return usbnet_init_rx_tx(un); | 1292 | return usbnet_init_rx_tx(un); | |
1296 | } | 1293 | } | |
1297 | 1294 | |||
1298 | static void | 1295 | static void | |
1299 | axe_uno_stop(struct ifnet *ifp, int disable) | 1296 | axe_uno_stop(struct ifnet *ifp, int disable) | |
1300 | { | 1297 | { | |
1301 | struct usbnet * const un = ifp->if_softc; | 1298 | struct usbnet * const un = ifp->if_softc; | |
1302 | 1299 | |||
1303 | axe_reset(un); | 1300 | axe_reset(un); | |
1304 | } | 1301 | } | |
1305 | 1302 | |||
1306 | #ifdef _MODULE | 1303 | #ifdef _MODULE | |
1307 | #include "ioconf.c" | 1304 | #include "ioconf.c" | |
1308 | #endif | 1305 | #endif | |
1309 | 1306 | |||
1310 | USBNET_MODULE(axe) | 1307 | USBNET_MODULE(axe) |
--- src/sys/dev/usb/if_axen.c 2022/03/03 05:54:37 1.89
+++ src/sys/dev/usb/if_axen.c 2022/03/03 05:55:01 1.90
@@ -1,925 +1,922 @@ | @@ -1,925 +1,922 @@ | |||
1 | /* $NetBSD: if_axen.c,v 1.89 2022/03/03 05:54:37 riastradh Exp $ */ | 1 | /* $NetBSD: if_axen.c,v 1.90 2022/03/03 05:55:01 riastradh Exp $ */ | |
2 | /* $OpenBSD: if_axen.c,v 1.3 2013/10/21 10:10:22 yuo Exp $ */ | 2 | /* $OpenBSD: if_axen.c,v 1.3 2013/10/21 10:10:22 yuo Exp $ */ | |
3 | 3 | |||
4 | /* | 4 | /* | |
5 | * Copyright (c) 2013 Yojiro UO <yuo@openbsd.org> | 5 | * Copyright (c) 2013 Yojiro UO <yuo@openbsd.org> | |
6 | * | 6 | * | |
7 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any | |
8 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above | |
9 | * copyright notice and this permission notice appear in all copies. | 9 | * copyright notice and this permission notice appear in all copies. | |
10 | * | 10 | * | |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
18 | */ | 18 | */ | |
19 | 19 | |||
20 | /* | 20 | /* | |
21 | * ASIX Electronics AX88178a USB 2.0 ethernet and AX88179 USB 3.0 Ethernet | 21 | * ASIX Electronics AX88178a USB 2.0 ethernet and AX88179 USB 3.0 Ethernet | |
22 | * driver. | 22 | * driver. | |
23 | */ | 23 | */ | |
24 | 24 | |||
25 | #include <sys/cdefs.h> | 25 | #include <sys/cdefs.h> | |
26 | __KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.89 2022/03/03 05:54:37 riastradh Exp $"); | 26 | __KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.90 2022/03/03 05:55:01 riastradh Exp $"); | |
27 | 27 | |||
28 | #ifdef _KERNEL_OPT | 28 | #ifdef _KERNEL_OPT | |
29 | #include "opt_usb.h" | 29 | #include "opt_usb.h" | |
30 | #endif | 30 | #endif | |
31 | 31 | |||
32 | #include <sys/param.h> | 32 | #include <sys/param.h> | |
33 | 33 | |||
34 | #include <netinet/in.h> /* XXX for netinet/ip.h */ | 34 | #include <netinet/in.h> /* XXX for netinet/ip.h */ | |
35 | #include <netinet/ip.h> /* XXX for IP_MAXPACKET */ | 35 | #include <netinet/ip.h> /* XXX for IP_MAXPACKET */ | |
36 | 36 | |||
37 | #include <dev/usb/usbnet.h> | 37 | #include <dev/usb/usbnet.h> | |
38 | 38 | |||
39 | #include <dev/usb/if_axenreg.h> | 39 | #include <dev/usb/if_axenreg.h> | |
40 | 40 | |||
41 | #ifdef AXEN_DEBUG | 41 | #ifdef AXEN_DEBUG | |
42 | #define DPRINTF(x) do { if (axendebug) printf x; } while (/*CONSTCOND*/0) | 42 | #define DPRINTF(x) do { if (axendebug) printf x; } while (/*CONSTCOND*/0) | |
43 | #define DPRINTFN(n, x) do { if (axendebug >= (n)) printf x; } while (/*CONSTCOND*/0) | 43 | #define DPRINTFN(n, x) do { if (axendebug >= (n)) printf x; } while (/*CONSTCOND*/0) | |
44 | int axendebug = 0; | 44 | int axendebug = 0; | |
45 | #else | 45 | #else | |
46 | #define DPRINTF(x) | 46 | #define DPRINTF(x) | |
47 | #define DPRINTFN(n, x) | 47 | #define DPRINTFN(n, x) | |
48 | #endif | 48 | #endif | |
49 | 49 | |||
50 | struct axen_type { | 50 | struct axen_type { | |
51 | struct usb_devno axen_devno; | 51 | struct usb_devno axen_devno; | |
52 | uint16_t axen_flags; | 52 | uint16_t axen_flags; | |
53 | #define AX178A 0x0001 /* AX88178a */ | 53 | #define AX178A 0x0001 /* AX88178a */ | |
54 | #define AX179 0x0002 /* AX88179 */ | 54 | #define AX179 0x0002 /* AX88179 */ | |
55 | }; | 55 | }; | |
56 | 56 | |||
57 | /* | 57 | /* | |
58 | * Various supported device vendors/products. | 58 | * Various supported device vendors/products. | |
59 | */ | 59 | */ | |
60 | static const struct axen_type axen_devs[] = { | 60 | static const struct axen_type axen_devs[] = { | |
61 | #if 0 /* not tested */ | 61 | #if 0 /* not tested */ | |
62 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178A}, AX178A }, | 62 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178A}, AX178A }, | |
63 | #endif | 63 | #endif | |
64 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88179}, AX179 }, | 64 | { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88179}, AX179 }, | |
65 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUB1312}, AX179 } | 65 | { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUB1312}, AX179 } | |
66 | }; | 66 | }; | |
67 | 67 | |||
68 | #define axen_lookup(v, p) ((const struct axen_type *)usb_lookup(axen_devs, v, p)) | 68 | #define axen_lookup(v, p) ((const struct axen_type *)usb_lookup(axen_devs, v, p)) | |
69 | 69 | |||
70 | static int axen_match(device_t, cfdata_t, void *); | 70 | static int axen_match(device_t, cfdata_t, void *); | |
71 | static void axen_attach(device_t, device_t, void *); | 71 | static void axen_attach(device_t, device_t, void *); | |
72 | 72 | |||
73 | CFATTACH_DECL_NEW(axen, sizeof(struct usbnet), | 73 | CFATTACH_DECL_NEW(axen, sizeof(struct usbnet), | |
74 | axen_match, axen_attach, usbnet_detach, usbnet_activate); | 74 | axen_match, axen_attach, usbnet_detach, usbnet_activate); | |
75 | 75 | |||
76 | static int axen_cmd(struct usbnet *, int, int, int, void *); | 76 | static int axen_cmd(struct usbnet *, int, int, int, void *); | |
77 | static void axen_reset(struct usbnet *); | 77 | static void axen_reset(struct usbnet *); | |
78 | static int axen_get_eaddr(struct usbnet *, void *); | 78 | static int axen_get_eaddr(struct usbnet *, void *); | |
79 | static void axen_ax88179_init(struct usbnet *); | 79 | static void axen_ax88179_init(struct usbnet *); | |
80 | 80 | |||
81 | static void axen_uno_stop(struct ifnet *, int); | 81 | static void axen_uno_stop(struct ifnet *, int); | |
82 | static int axen_uno_ioctl(struct ifnet *, u_long, void *); | 82 | static int axen_uno_ioctl(struct ifnet *, u_long, void *); | |
83 | static void axen_uno_mcast(struct ifnet *); | 83 | static void axen_uno_mcast(struct ifnet *); | |
84 | static int axen_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 84 | static int axen_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
85 | static int axen_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 85 | static int axen_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
86 | static void axen_uno_mii_statchg(struct ifnet *); | 86 | static void axen_uno_mii_statchg(struct ifnet *); | |
87 | static void axen_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 87 | static void axen_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
88 | uint32_t); | 88 | uint32_t); | |
89 | static unsigned axen_uno_tx_prepare(struct usbnet *, struct mbuf *, | 89 | static unsigned axen_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
90 | struct usbnet_chain *); | 90 | struct usbnet_chain *); | |
91 | static int axen_uno_init(struct ifnet *); | 91 | static int axen_uno_init(struct ifnet *); | |
92 | 92 | |||
93 | static const struct usbnet_ops axen_ops = { | 93 | static const struct usbnet_ops axen_ops = { | |
94 | .uno_stop = axen_uno_stop, | 94 | .uno_stop = axen_uno_stop, | |
95 | .uno_ioctl = axen_uno_ioctl, | 95 | .uno_ioctl = axen_uno_ioctl, | |
96 | .uno_mcast = axen_uno_mcast, | 96 | .uno_mcast = axen_uno_mcast, | |
97 | .uno_read_reg = axen_uno_mii_read_reg, | 97 | .uno_read_reg = axen_uno_mii_read_reg, | |
98 | .uno_write_reg = axen_uno_mii_write_reg, | 98 | .uno_write_reg = axen_uno_mii_write_reg, | |
99 | .uno_statchg = axen_uno_mii_statchg, | 99 | .uno_statchg = axen_uno_mii_statchg, | |
100 | .uno_tx_prepare = axen_uno_tx_prepare, | 100 | .uno_tx_prepare = axen_uno_tx_prepare, | |
101 | .uno_rx_loop = axen_uno_rx_loop, | 101 | .uno_rx_loop = axen_uno_rx_loop, | |
102 | .uno_init = axen_uno_init, | 102 | .uno_init = axen_uno_init, | |
103 | }; | 103 | }; | |
104 | 104 | |||
105 | static int | 105 | static int | |
106 | axen_cmd(struct usbnet *un, int cmd, int index, int val, void *buf) | 106 | axen_cmd(struct usbnet *un, int cmd, int index, int val, void *buf) | |
107 | { | 107 | { | |
108 | usb_device_request_t req; | 108 | usb_device_request_t req; | |
109 | usbd_status err; | 109 | usbd_status err; | |
110 | 110 | |||
111 | if (usbnet_isdying(un)) | 111 | if (usbnet_isdying(un)) | |
112 | return 0; | 112 | return 0; | |
113 | 113 | |||
114 | if (AXEN_CMD_DIR(cmd)) | 114 | if (AXEN_CMD_DIR(cmd)) | |
115 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 115 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
116 | else | 116 | else | |
117 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 117 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
118 | req.bRequest = AXEN_CMD_CMD(cmd); | 118 | req.bRequest = AXEN_CMD_CMD(cmd); | |
119 | USETW(req.wValue, val); | 119 | USETW(req.wValue, val); | |
120 | USETW(req.wIndex, index); | 120 | USETW(req.wIndex, index); | |
121 | USETW(req.wLength, AXEN_CMD_LEN(cmd)); | 121 | USETW(req.wLength, AXEN_CMD_LEN(cmd)); | |
122 | 122 | |||
123 | err = usbd_do_request(un->un_udev, &req, buf); | 123 | err = usbd_do_request(un->un_udev, &req, buf); | |
124 | DPRINTFN(5, ("axen_cmd: cmd 0x%04x val 0x%04x len %d\n", | 124 | DPRINTFN(5, ("axen_cmd: cmd 0x%04x val 0x%04x len %d\n", | |
125 | cmd, val, AXEN_CMD_LEN(cmd))); | 125 | cmd, val, AXEN_CMD_LEN(cmd))); | |
126 | 126 | |||
127 | if (err) { | 127 | if (err) { | |
128 | DPRINTF(("%s: cmd: %d, error: %d\n", __func__, cmd, err)); | 128 | DPRINTF(("%s: cmd: %d, error: %d\n", __func__, cmd, err)); | |
129 | return -1; | 129 | return -1; | |
130 | } | 130 | } | |
131 | 131 | |||
132 | return 0; | 132 | return 0; | |
133 | } | 133 | } | |
134 | 134 | |||
135 | static int | 135 | static int | |
136 | axen_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 136 | axen_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
137 | { | 137 | { | |
138 | uint16_t data; | 138 | uint16_t data; | |
139 | 139 | |||
140 | if (un->un_phyno != phy) { | 140 | if (un->un_phyno != phy) { | |
141 | *val = 0; | 141 | *val = 0; | |
142 | return EINVAL; | 142 | return EINVAL; | |
143 | } | 143 | } | |
144 | 144 | |||
145 | usbd_status err = axen_cmd(un, AXEN_CMD_MII_READ_REG, reg, phy, &data); | 145 | usbd_status err = axen_cmd(un, AXEN_CMD_MII_READ_REG, reg, phy, &data); | |
146 | if (err) { | 146 | if (err) { | |
147 | *val = 0; | 147 | *val = 0; | |
148 | return EIO; | 148 | return EIO; | |
149 | } | 149 | } | |
150 | 150 | |||
151 | *val = le16toh(data); | 151 | *val = le16toh(data); | |
152 | if (reg == MII_BMSR) | 152 | if (reg == MII_BMSR) | |
153 | *val &= ~BMSR_EXTCAP; | 153 | *val &= ~BMSR_EXTCAP; | |
154 | 154 | |||
155 | return 0; | 155 | return 0; | |
156 | } | 156 | } | |
157 | 157 | |||
158 | static int | 158 | static int | |
159 | axen_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 159 | axen_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
160 | { | 160 | { | |
161 | uint16_t uval = htole16(val); | 161 | uint16_t uval = htole16(val); | |
162 | 162 | |||
163 | if (un->un_phyno != phy) | 163 | if (un->un_phyno != phy) | |
164 | return EINVAL; | 164 | return EINVAL; | |
165 | 165 | |||
166 | usbd_status err = axen_cmd(un, AXEN_CMD_MII_WRITE_REG, reg, phy, &uval); | 166 | usbd_status err = axen_cmd(un, AXEN_CMD_MII_WRITE_REG, reg, phy, &uval); | |
167 | if (err) | 167 | if (err) | |
168 | return EIO; | 168 | return EIO; | |
169 | 169 | |||
170 | return 0; | 170 | return 0; | |
171 | } | 171 | } | |
172 | 172 | |||
173 | static void | 173 | static void | |
174 | axen_uno_mii_statchg(struct ifnet *ifp) | 174 | axen_uno_mii_statchg(struct ifnet *ifp) | |
175 | { | 175 | { | |
176 | struct usbnet * const un = ifp->if_softc; | 176 | struct usbnet * const un = ifp->if_softc; | |
177 | struct mii_data * const mii = usbnet_mii(un); | 177 | struct mii_data * const mii = usbnet_mii(un); | |
178 | int err; | 178 | int err; | |
179 | uint16_t val; | 179 | uint16_t val; | |
180 | uint16_t wval; | 180 | uint16_t wval; | |
181 | 181 | |||
182 | if (usbnet_isdying(un)) | 182 | if (usbnet_isdying(un)) | |
183 | return; | 183 | return; | |
184 | 184 | |||
185 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 185 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
186 | (IFM_ACTIVE | IFM_AVALID)) { | 186 | (IFM_ACTIVE | IFM_AVALID)) { | |
187 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 187 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
188 | case IFM_10_T: | 188 | case IFM_10_T: | |
189 | case IFM_100_TX: | 189 | case IFM_100_TX: | |
190 | usbnet_set_link(un, true); | 190 | usbnet_set_link(un, true); | |
191 | break; | 191 | break; | |
192 | case IFM_1000_T: | 192 | case IFM_1000_T: | |
193 | usbnet_set_link(un, true); | 193 | usbnet_set_link(un, true); | |
194 | break; | 194 | break; | |
195 | default: | 195 | default: | |
196 | break; | 196 | break; | |
197 | } | 197 | } | |
198 | } | 198 | } | |
199 | 199 | |||
200 | /* Lost link, do nothing. */ | 200 | /* Lost link, do nothing. */ | |
201 | if (!usbnet_havelink(un)) | 201 | if (!usbnet_havelink(un)) | |
202 | return; | 202 | return; | |
203 | 203 | |||
204 | val = 0; | 204 | val = 0; | |
205 | if ((mii->mii_media_active & IFM_FDX) != 0) | 205 | if ((mii->mii_media_active & IFM_FDX) != 0) | |
206 | val |= AXEN_MEDIUM_FDX; | 206 | val |= AXEN_MEDIUM_FDX; | |
207 | 207 | |||
208 | val |= AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN | | 208 | val |= AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN | | |
209 | AXEN_MEDIUM_RECV_EN; | 209 | AXEN_MEDIUM_RECV_EN; | |
210 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 210 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
211 | case IFM_1000_T: | 211 | case IFM_1000_T: | |
212 | val |= AXEN_MEDIUM_GIGA | AXEN_MEDIUM_EN_125MHZ; | 212 | val |= AXEN_MEDIUM_GIGA | AXEN_MEDIUM_EN_125MHZ; | |
213 | break; | 213 | break; | |
214 | case IFM_100_TX: | 214 | case IFM_100_TX: | |
215 | val |= AXEN_MEDIUM_PS; | 215 | val |= AXEN_MEDIUM_PS; | |
216 | break; | 216 | break; | |
217 | case IFM_10_T: | 217 | case IFM_10_T: | |
218 | /* doesn't need to be handled */ | 218 | /* doesn't need to be handled */ | |
219 | break; | 219 | break; | |
220 | } | 220 | } | |
221 | 221 | |||
222 | DPRINTF(("%s: val=%#x\n", __func__, val)); | 222 | DPRINTF(("%s: val=%#x\n", __func__, val)); | |
223 | wval = htole16(val); | 223 | wval = htole16(val); | |
224 | err = axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval); | 224 | err = axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval); | |
225 | if (err) | 225 | if (err) | |
226 | aprint_error_dev(un->un_dev, "media change failed\n"); | 226 | aprint_error_dev(un->un_dev, "media change failed\n"); | |
227 | } | 227 | } | |
228 | 228 | |||
229 | static void | 229 | static void | |
230 | axen_uno_mcast(struct ifnet *ifp) | 230 | axen_uno_mcast(struct ifnet *ifp) | |
231 | { | 231 | { | |
232 | struct usbnet * const un = ifp->if_softc; | 232 | struct usbnet * const un = ifp->if_softc; | |
233 | struct ethercom *ec = usbnet_ec(un); | 233 | struct ethercom *ec = usbnet_ec(un); | |
234 | struct ether_multi *enm; | 234 | struct ether_multi *enm; | |
235 | struct ether_multistep step; | 235 | struct ether_multistep step; | |
236 | uint32_t h = 0; | 236 | uint32_t h = 0; | |
237 | uint16_t rxmode; | 237 | uint16_t rxmode; | |
238 | uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 238 | uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
239 | uint16_t wval; | 239 | uint16_t wval; | |
240 | 240 | |||
241 | if (usbnet_isdying(un)) | 241 | if (usbnet_isdying(un)) | |
242 | return; | 242 | return; | |
243 | 243 | |||
244 | rxmode = 0; | 244 | rxmode = 0; | |
245 | 245 | |||
246 | /* Enable receiver, set RX mode */ | 246 | /* Enable receiver, set RX mode */ | |
247 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); | 247 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); | |
248 | rxmode = le16toh(wval); | 248 | rxmode = le16toh(wval); | |
249 | rxmode &= ~(AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_PROMISC | | 249 | rxmode &= ~(AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_PROMISC | | |
250 | AXEN_RXCTL_ACPT_MCAST); | 250 | AXEN_RXCTL_ACPT_MCAST); | |
251 | 251 | |||
252 | if (ifp->if_flags & IFF_PROMISC) { | 252 | if (ifp->if_flags & IFF_PROMISC) { | |
253 | DPRINTF(("%s: promisc\n", device_xname(un->un_dev))); | 253 | DPRINTF(("%s: promisc\n", device_xname(un->un_dev))); | |
254 | rxmode |= AXEN_RXCTL_PROMISC; | 254 | rxmode |= AXEN_RXCTL_PROMISC; | |
255 | allmulti: | 255 | allmulti: | |
256 | ETHER_LOCK(ec); | 256 | ETHER_LOCK(ec); | |
257 | ec->ec_flags |= ETHER_F_ALLMULTI; | 257 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
258 | ETHER_UNLOCK(ec); | 258 | ETHER_UNLOCK(ec); | |
259 | rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST | 259 | rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST | |
260 | /* | AXEN_RXCTL_ACPT_PHY_MCAST */; | 260 | /* | AXEN_RXCTL_ACPT_PHY_MCAST */; | |
261 | } else { | 261 | } else { | |
262 | /* now program new ones */ | 262 | /* now program new ones */ | |
263 | DPRINTF(("%s: initializing hash table\n", | 263 | DPRINTF(("%s: initializing hash table\n", | |
264 | device_xname(un->un_dev))); | 264 | device_xname(un->un_dev))); | |
265 | ETHER_LOCK(ec); | 265 | ETHER_LOCK(ec); | |
266 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 266 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
267 | 267 | |||
268 | ETHER_FIRST_MULTI(step, ec, enm); | 268 | ETHER_FIRST_MULTI(step, ec, enm); | |
269 | while (enm != NULL) { | 269 | while (enm != NULL) { | |
270 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | 270 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
271 | ETHER_ADDR_LEN)) { | 271 | ETHER_ADDR_LEN)) { | |
272 | DPRINTF(("%s: allmulti\n", | 272 | DPRINTF(("%s: allmulti\n", | |
273 | device_xname(un->un_dev))); | 273 | device_xname(un->un_dev))); | |
274 | memset(hashtbl, 0, sizeof(hashtbl)); | 274 | memset(hashtbl, 0, sizeof(hashtbl)); | |
275 | ETHER_UNLOCK(ec); | 275 | ETHER_UNLOCK(ec); | |
276 | goto allmulti; | 276 | goto allmulti; | |
277 | } | 277 | } | |
278 | h = ether_crc32_be(enm->enm_addrlo, | 278 | h = ether_crc32_be(enm->enm_addrlo, | |
279 | ETHER_ADDR_LEN) >> 26; | 279 | ETHER_ADDR_LEN) >> 26; | |
280 | hashtbl[h / 8] |= 1 << (h % 8); | 280 | hashtbl[h / 8] |= 1 << (h % 8); | |
281 | DPRINTF(("%s: %s added\n", | 281 | DPRINTF(("%s: %s added\n", | |
282 | device_xname(un->un_dev), | 282 | device_xname(un->un_dev), | |
283 | ether_sprintf(enm->enm_addrlo))); | 283 | ether_sprintf(enm->enm_addrlo))); | |
284 | ETHER_NEXT_MULTI(step, enm); | 284 | ETHER_NEXT_MULTI(step, enm); | |
285 | } | 285 | } | |
286 | ETHER_UNLOCK(ec); | 286 | ETHER_UNLOCK(ec); | |
287 | rxmode |= AXEN_RXCTL_ACPT_MCAST; | 287 | rxmode |= AXEN_RXCTL_ACPT_MCAST; | |
288 | } | 288 | } | |
289 | 289 | |||
290 | axen_cmd(un, AXEN_CMD_MAC_WRITE_FILTER, 8, AXEN_FILTER_MULTI, hashtbl); | 290 | axen_cmd(un, AXEN_CMD_MAC_WRITE_FILTER, 8, AXEN_FILTER_MULTI, hashtbl); | |
291 | wval = htole16(rxmode); | 291 | wval = htole16(rxmode); | |
292 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | 292 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | |
293 | } | 293 | } | |
294 | 294 | |||
295 | static void | 295 | static void | |
296 | axen_reset(struct usbnet *un) | 296 | axen_reset(struct usbnet *un) | |
297 | { | 297 | { | |
298 | if (usbnet_isdying(un)) | 298 | if (usbnet_isdying(un)) | |
299 | return; | 299 | return; | |
300 | /* XXX What to reset? */ | 300 | /* XXX What to reset? */ | |
301 | 301 | |||
302 | /* Wait a little while for the chip to get its brains in order. */ | 302 | /* Wait a little while for the chip to get its brains in order. */ | |
303 | DELAY(1000); | 303 | DELAY(1000); | |
304 | } | 304 | } | |
305 | 305 | |||
306 | static int | 306 | static int | |
307 | axen_get_eaddr(struct usbnet *un, void *addr) | 307 | axen_get_eaddr(struct usbnet *un, void *addr) | |
308 | { | 308 | { | |
309 | #if 1 | 309 | #if 1 | |
310 | return axen_cmd(un, AXEN_CMD_MAC_READ_ETHER, 6, AXEN_CMD_MAC_NODE_ID, | 310 | return axen_cmd(un, AXEN_CMD_MAC_READ_ETHER, 6, AXEN_CMD_MAC_NODE_ID, | |
311 | addr); | 311 | addr); | |
312 | #else | 312 | #else | |
313 | int i, retry; | 313 | int i, retry; | |
314 | uint8_t eeprom[20]; | 314 | uint8_t eeprom[20]; | |
315 | uint16_t csum; | 315 | uint16_t csum; | |
316 | uint16_t buf; | 316 | uint16_t buf; | |
317 | 317 | |||
318 | for (i = 0; i < 6; i++) { | 318 | for (i = 0; i < 6; i++) { | |
319 | /* set eeprom address */ | 319 | /* set eeprom address */ | |
320 | buf = htole16(i); | 320 | buf = htole16(i); | |
321 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MAC_EEPROM_ADDR, &buf); | 321 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MAC_EEPROM_ADDR, &buf); | |
322 | 322 | |||
323 | /* set eeprom command */ | 323 | /* set eeprom command */ | |
324 | buf = htole16(AXEN_EEPROM_READ); | 324 | buf = htole16(AXEN_EEPROM_READ); | |
325 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MAC_EEPROM_CMD, &buf); | 325 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MAC_EEPROM_CMD, &buf); | |
326 | 326 | |||
327 | /* check the value is ready */ | 327 | /* check the value is ready */ | |
328 | retry = 3; | 328 | retry = 3; | |
329 | do { | 329 | do { | |
330 | buf = htole16(AXEN_EEPROM_READ); | 330 | buf = htole16(AXEN_EEPROM_READ); | |
331 | usbd_delay_ms(un->un_udev, 10); | 331 | usbd_delay_ms(un->un_udev, 10); | |
332 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_MAC_EEPROM_CMD, | 332 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_MAC_EEPROM_CMD, | |
333 | &buf); | 333 | &buf); | |
334 | retry--; | 334 | retry--; | |
335 | if (retry < 0) | 335 | if (retry < 0) | |
336 | return EINVAL; | 336 | return EINVAL; | |
337 | } while ((le16toh(buf) & 0xff) & AXEN_EEPROM_BUSY); | 337 | } while ((le16toh(buf) & 0xff) & AXEN_EEPROM_BUSY); | |
338 | 338 | |||
339 | /* read data */ | 339 | /* read data */ | |
340 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_EEPROM_READ, | 340 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_EEPROM_READ, | |
341 | &eeprom[i * 2]); | 341 | &eeprom[i * 2]); | |
342 | 342 | |||
343 | /* sanity check */ | 343 | /* sanity check */ | |
344 | if ((i == 0) && (eeprom[0] == 0xff)) | 344 | if ((i == 0) && (eeprom[0] == 0xff)) | |
345 | return EINVAL; | 345 | return EINVAL; | |
346 | } | 346 | } | |
347 | 347 | |||
348 | /* check checksum */ | 348 | /* check checksum */ | |
349 | csum = eeprom[6] + eeprom[7] + eeprom[8] + eeprom[9]; | 349 | csum = eeprom[6] + eeprom[7] + eeprom[8] + eeprom[9]; | |
350 | csum = (csum >> 8) + (csum & 0xff) + eeprom[10]; | 350 | csum = (csum >> 8) + (csum & 0xff) + eeprom[10]; | |
351 | if (csum != 0xff) { | 351 | if (csum != 0xff) { | |
352 | printf("eeprom checksum mismatch(0x%02x)\n", csum); | 352 | printf("eeprom checksum mismatch(0x%02x)\n", csum); | |
353 | return EINVAL; | 353 | return EINVAL; | |
354 | } | 354 | } | |
355 | 355 | |||
356 | memcpy(addr, eeprom, ETHER_ADDR_LEN); | 356 | memcpy(addr, eeprom, ETHER_ADDR_LEN); | |
357 | return 0; | 357 | return 0; | |
358 | #endif | 358 | #endif | |
359 | } | 359 | } | |
360 | 360 | |||
361 | static void | 361 | static void | |
362 | axen_ax88179_init(struct usbnet *un) | 362 | axen_ax88179_init(struct usbnet *un) | |
363 | { | 363 | { | |
364 | struct axen_qctrl qctrl; | 364 | struct axen_qctrl qctrl; | |
365 | uint16_t ctl, temp; | 365 | uint16_t ctl, temp; | |
366 | uint16_t wval; | 366 | uint16_t wval; | |
367 | uint8_t val; | 367 | uint8_t val; | |
368 | 368 | |||
369 | /* XXX: ? */ | 369 | /* XXX: ? */ | |
370 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_UNK_05, &val); | 370 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_UNK_05, &val); | |
371 | DPRINTFN(5, ("AXEN_CMD_MAC_READ(0x05): 0x%02x\n", val)); | 371 | DPRINTFN(5, ("AXEN_CMD_MAC_READ(0x05): 0x%02x\n", val)); | |
372 | 372 | |||
373 | /* check AX88179 version, UA1 / UA2 */ | 373 | /* check AX88179 version, UA1 / UA2 */ | |
374 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_GENERAL_STATUS, &val); | 374 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_GENERAL_STATUS, &val); | |
375 | /* UA1 */ | 375 | /* UA1 */ | |
376 | if (!(val & AXEN_GENERAL_STATUS_MASK)) { | 376 | if (!(val & AXEN_GENERAL_STATUS_MASK)) { | |
377 | DPRINTF(("AX88179 ver. UA1\n")); | 377 | DPRINTF(("AX88179 ver. UA1\n")); | |
378 | } else { | 378 | } else { | |
379 | DPRINTF(("AX88179 ver. UA2\n")); | 379 | DPRINTF(("AX88179 ver. UA2\n")); | |
380 | } | 380 | } | |
381 | 381 | |||
382 | /* power up ethernet PHY */ | 382 | /* power up ethernet PHY */ | |
383 | wval = htole16(0); | 383 | wval = htole16(0); | |
384 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval); | 384 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval); | |
385 | 385 | |||
386 | wval = htole16(AXEN_PHYPWR_RSTCTL_IPRL); | 386 | wval = htole16(AXEN_PHYPWR_RSTCTL_IPRL); | |
387 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval); | 387 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval); | |
388 | usbd_delay_ms(un->un_udev, 200); | 388 | usbd_delay_ms(un->un_udev, 200); | |
389 | 389 | |||
390 | /* set clock mode */ | 390 | /* set clock mode */ | |
391 | val = AXEN_PHYCLK_ACS | AXEN_PHYCLK_BCS; | 391 | val = AXEN_PHYCLK_ACS | AXEN_PHYCLK_BCS; | |
392 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val); | 392 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val); | |
393 | usbd_delay_ms(un->un_udev, 100); | 393 | usbd_delay_ms(un->un_udev, 100); | |
394 | 394 | |||
395 | /* set monitor mode (disable) */ | 395 | /* set monitor mode (disable) */ | |
396 | val = AXEN_MONITOR_NONE; | 396 | val = AXEN_MONITOR_NONE; | |
397 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val); | 397 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val); | |
398 | 398 | |||
399 | /* enable auto detach */ | 399 | /* enable auto detach */ | |
400 | axen_cmd(un, AXEN_CMD_EEPROM_READ, 2, AXEN_EEPROM_STAT, &wval); | 400 | axen_cmd(un, AXEN_CMD_EEPROM_READ, 2, AXEN_EEPROM_STAT, &wval); | |
401 | temp = le16toh(wval); | 401 | temp = le16toh(wval); | |
402 | DPRINTFN(2,("EEPROM0x43 = 0x%04x\n", temp)); | 402 | DPRINTFN(2,("EEPROM0x43 = 0x%04x\n", temp)); | |
403 | if (!(temp == 0xffff) && !(temp & 0x0100)) { | 403 | if (!(temp == 0xffff) && !(temp & 0x0100)) { | |
404 | /* Enable auto detach bit */ | 404 | /* Enable auto detach bit */ | |
405 | val = 0; | 405 | val = 0; | |
406 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val); | 406 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val); | |
407 | val = AXEN_PHYCLK_ULR; | 407 | val = AXEN_PHYCLK_ULR; | |
408 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val); | 408 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val); | |
409 | usbd_delay_ms(un->un_udev, 100); | 409 | usbd_delay_ms(un->un_udev, 100); | |
410 | 410 | |||
411 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_PHYPWR_RSTCTL, &wval); | 411 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_PHYPWR_RSTCTL, &wval); | |
412 | ctl = le16toh(wval); | 412 | ctl = le16toh(wval); | |
413 | ctl |= AXEN_PHYPWR_RSTCTL_AUTODETACH; | 413 | ctl |= AXEN_PHYPWR_RSTCTL_AUTODETACH; | |
414 | wval = htole16(ctl); | 414 | wval = htole16(ctl); | |
415 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval); | 415 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval); | |
416 | usbd_delay_ms(un->un_udev, 200); | 416 | usbd_delay_ms(un->un_udev, 200); | |
417 | aprint_error_dev(un->un_dev, "enable auto detach (0x%04x)\n", | 417 | aprint_error_dev(un->un_dev, "enable auto detach (0x%04x)\n", | |
418 | ctl); | 418 | ctl); | |
419 | } | 419 | } | |
420 | 420 | |||
421 | /* bulkin queue setting */ | 421 | /* bulkin queue setting */ | |
422 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_USB_UPLINK, &val); | 422 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_USB_UPLINK, &val); | |
423 | switch (val) { | 423 | switch (val) { | |
424 | case AXEN_USB_FS: | 424 | case AXEN_USB_FS: | |
425 | DPRINTF(("uplink: USB1.1\n")); | 425 | DPRINTF(("uplink: USB1.1\n")); | |
426 | qctrl.ctrl = 0x07; | 426 | qctrl.ctrl = 0x07; | |
427 | qctrl.timer_low = 0xcc; | 427 | qctrl.timer_low = 0xcc; | |
428 | qctrl.timer_high = 0x4c; | 428 | qctrl.timer_high = 0x4c; | |
429 | qctrl.bufsize = AXEN_BUFSZ_LS - 1; | 429 | qctrl.bufsize = AXEN_BUFSZ_LS - 1; | |
430 | qctrl.ifg = 0x08; | 430 | qctrl.ifg = 0x08; | |
431 | break; | 431 | break; | |
432 | case AXEN_USB_HS: | 432 | case AXEN_USB_HS: | |
433 | DPRINTF(("uplink: USB2.0\n")); | 433 | DPRINTF(("uplink: USB2.0\n")); | |
434 | qctrl.ctrl = 0x07; | 434 | qctrl.ctrl = 0x07; | |
435 | qctrl.timer_low = 0x02; | 435 | qctrl.timer_low = 0x02; | |
436 | qctrl.timer_high = 0xa0; | 436 | qctrl.timer_high = 0xa0; | |
437 | qctrl.bufsize = AXEN_BUFSZ_HS - 1; | 437 | qctrl.bufsize = AXEN_BUFSZ_HS - 1; | |
438 | qctrl.ifg = 0xff; | 438 | qctrl.ifg = 0xff; | |
439 | break; | 439 | break; | |
440 | case AXEN_USB_SS: | 440 | case AXEN_USB_SS: | |
441 | DPRINTF(("uplink: USB3.0\n")); | 441 | DPRINTF(("uplink: USB3.0\n")); | |
442 | qctrl.ctrl = 0x07; | 442 | qctrl.ctrl = 0x07; | |
443 | qctrl.timer_low = 0x4f; | 443 | qctrl.timer_low = 0x4f; | |
444 | qctrl.timer_high = 0x00; | 444 | qctrl.timer_high = 0x00; | |
445 | qctrl.bufsize = AXEN_BUFSZ_SS - 1; | 445 | qctrl.bufsize = AXEN_BUFSZ_SS - 1; | |
446 | qctrl.ifg = 0xff; | 446 | qctrl.ifg = 0xff; | |
447 | break; | 447 | break; | |
448 | default: | 448 | default: | |
449 | aprint_error_dev(un->un_dev, "unknown uplink bus:0x%02x\n", | 449 | aprint_error_dev(un->un_dev, "unknown uplink bus:0x%02x\n", | |
450 | val); | 450 | val); | |
451 | return; | 451 | return; | |
452 | } | 452 | } | |
453 | axen_cmd(un, AXEN_CMD_MAC_SET_RXSR, 5, AXEN_RX_BULKIN_QCTRL, &qctrl); | 453 | axen_cmd(un, AXEN_CMD_MAC_SET_RXSR, 5, AXEN_RX_BULKIN_QCTRL, &qctrl); | |
454 | 454 | |||
455 | /* | 455 | /* | |
456 | * set buffer high/low watermark to pause/resume. | 456 | * set buffer high/low watermark to pause/resume. | |
457 | * write 2byte will set high/log simultaneous with AXEN_PAUSE_HIGH. | 457 | * write 2byte will set high/log simultaneous with AXEN_PAUSE_HIGH. | |
458 | * XXX: what is the best value? OSX driver uses 0x3c-0x4c as LOW-HIGH | 458 | * XXX: what is the best value? OSX driver uses 0x3c-0x4c as LOW-HIGH | |
459 | * watermark parameters. | 459 | * watermark parameters. | |
460 | */ | 460 | */ | |
461 | val = 0x34; | 461 | val = 0x34; | |
462 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_LOW_WATERMARK, &val); | 462 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_LOW_WATERMARK, &val); | |
463 | val = 0x52; | 463 | val = 0x52; | |
464 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_HIGH_WATERMARK, &val); | 464 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_HIGH_WATERMARK, &val); | |
465 | 465 | |||
466 | /* Set RX/TX configuration. */ | 466 | /* Set RX/TX configuration. */ | |
467 | /* Set RX control register */ | 467 | /* Set RX control register */ | |
468 | ctl = AXEN_RXCTL_IPE | AXEN_RXCTL_DROPCRCERR | AXEN_RXCTL_AUTOB; | 468 | ctl = AXEN_RXCTL_IPE | AXEN_RXCTL_DROPCRCERR | AXEN_RXCTL_AUTOB; | |
469 | wval = htole16(ctl); | 469 | wval = htole16(ctl); | |
470 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | 470 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | |
471 | 471 | |||
472 | /* set monitor mode (enable) */ | 472 | /* set monitor mode (enable) */ | |
473 | val = AXEN_MONITOR_PMETYPE | AXEN_MONITOR_PMEPOL | AXEN_MONITOR_RWMP; | 473 | val = AXEN_MONITOR_PMETYPE | AXEN_MONITOR_PMEPOL | AXEN_MONITOR_RWMP; | |
474 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val); | 474 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val); | |
475 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_MONITOR_MODE, &val); | 475 | axen_cmd(un, AXEN_CMD_MAC_READ, 1, AXEN_MONITOR_MODE, &val); | |
476 | DPRINTF(("axen: Monitor mode = 0x%02x\n", val)); | 476 | DPRINTF(("axen: Monitor mode = 0x%02x\n", val)); | |
477 | 477 | |||
478 | /* set medium type */ | 478 | /* set medium type */ | |
479 | ctl = AXEN_MEDIUM_GIGA | AXEN_MEDIUM_FDX | AXEN_MEDIUM_EN_125MHZ | | 479 | ctl = AXEN_MEDIUM_GIGA | AXEN_MEDIUM_FDX | AXEN_MEDIUM_EN_125MHZ | | |
480 | AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN | | 480 | AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN | | |
481 | AXEN_MEDIUM_RECV_EN; | 481 | AXEN_MEDIUM_RECV_EN; | |
482 | wval = htole16(ctl); | 482 | wval = htole16(ctl); | |
483 | DPRINTF(("axen: set to medium mode: 0x%04x\n", ctl)); | 483 | DPRINTF(("axen: set to medium mode: 0x%04x\n", ctl)); | |
484 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval); | 484 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval); | |
485 | usbd_delay_ms(un->un_udev, 100); | 485 | usbd_delay_ms(un->un_udev, 100); | |
486 | 486 | |||
487 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MEDIUM_STATUS, &wval); | 487 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MEDIUM_STATUS, &wval); | |
488 | DPRINTF(("axen: current medium mode: 0x%04x\n", le16toh(wval))); | 488 | DPRINTF(("axen: current medium mode: 0x%04x\n", le16toh(wval))); | |
489 | 489 | |||
490 | #if 0 /* XXX: TBD.... */ | 490 | #if 0 /* XXX: TBD.... */ | |
491 | #define GMII_LED_ACTIVE 0x1a | 491 | #define GMII_LED_ACTIVE 0x1a | |
492 | #define GMII_PHY_PAGE_SEL 0x1e | 492 | #define GMII_PHY_PAGE_SEL 0x1e | |
493 | #define GMII_PHY_PAGE_SEL 0x1f | 493 | #define GMII_PHY_PAGE_SEL 0x1f | |
494 | #define GMII_PAGE_EXT 0x0007 | 494 | #define GMII_PAGE_EXT 0x0007 | |
495 | axen_uno_mii_write_reg(un, un->un_phyno, GMII_PHY_PAGE_SEL, | 495 | axen_uno_mii_write_reg(un, un->un_phyno, GMII_PHY_PAGE_SEL, | |
496 | GMII_PAGE_EXT); | 496 | GMII_PAGE_EXT); | |
497 | axen_uno_mii_write_reg(un, un->un_phyno, GMII_PHY_PAGE, | 497 | axen_uno_mii_write_reg(un, un->un_phyno, GMII_PHY_PAGE, | |
498 | 0x002c); | 498 | 0x002c); | |
499 | #endif | 499 | #endif | |
500 | 500 | |||
501 | #if 1 /* XXX: phy hack ? */ | 501 | #if 1 /* XXX: phy hack ? */ | |
502 | axen_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0005); | 502 | axen_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0005); | |
503 | axen_uno_mii_write_reg(un, un->un_phyno, 0x0C, 0x0000); | 503 | axen_uno_mii_write_reg(un, un->un_phyno, 0x0C, 0x0000); | |
504 | axen_uno_mii_read_reg(un, un->un_phyno, 0x0001, &wval); | 504 | axen_uno_mii_read_reg(un, un->un_phyno, 0x0001, &wval); | |
505 | axen_uno_mii_write_reg(un, un->un_phyno, 0x01, wval | 0x0080); | 505 | axen_uno_mii_write_reg(un, un->un_phyno, 0x01, wval | 0x0080); | |
506 | axen_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0000); | 506 | axen_uno_mii_write_reg(un, un->un_phyno, 0x1F, 0x0000); | |
507 | #endif | 507 | #endif | |
508 | } | 508 | } | |
509 | 509 | |||
510 | static void | 510 | static void | |
511 | axen_setoe_locked(struct usbnet *un) | 511 | axen_setoe_locked(struct usbnet *un) | |
512 | { | 512 | { | |
513 | struct ifnet * const ifp = usbnet_ifp(un); | 513 | struct ifnet * const ifp = usbnet_ifp(un); | |
514 | uint64_t enabled = ifp->if_capenable; | 514 | uint64_t enabled = ifp->if_capenable; | |
515 | uint8_t val; | 515 | uint8_t val; | |
516 | 516 | |||
517 | KASSERT(IFNET_LOCKED(ifp)); | 517 | KASSERT(IFNET_LOCKED(ifp)); | |
518 | 518 | |||
519 | val = AXEN_RXCOE_OFF; | 519 | val = AXEN_RXCOE_OFF; | |
520 | if (enabled & IFCAP_CSUM_IPv4_Rx) | 520 | if (enabled & IFCAP_CSUM_IPv4_Rx) | |
521 | val |= AXEN_RXCOE_IPv4; | 521 | val |= AXEN_RXCOE_IPv4; | |
522 | if (enabled & IFCAP_CSUM_TCPv4_Rx) | 522 | if (enabled & IFCAP_CSUM_TCPv4_Rx) | |
523 | val |= AXEN_RXCOE_TCPv4; | 523 | val |= AXEN_RXCOE_TCPv4; | |
524 | if (enabled & IFCAP_CSUM_UDPv4_Rx) | 524 | if (enabled & IFCAP_CSUM_UDPv4_Rx) | |
525 | val |= AXEN_RXCOE_UDPv4; | 525 | val |= AXEN_RXCOE_UDPv4; | |
526 | if (enabled & IFCAP_CSUM_TCPv6_Rx) | 526 | if (enabled & IFCAP_CSUM_TCPv6_Rx) | |
527 | val |= AXEN_RXCOE_TCPv6; | 527 | val |= AXEN_RXCOE_TCPv6; | |
528 | if (enabled & IFCAP_CSUM_UDPv6_Rx) | 528 | if (enabled & IFCAP_CSUM_UDPv6_Rx) | |
529 | val |= AXEN_RXCOE_UDPv6; | 529 | val |= AXEN_RXCOE_UDPv6; | |
530 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_RX_COE, &val); | 530 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_RX_COE, &val); | |
531 | 531 | |||
532 | val = AXEN_TXCOE_OFF; | 532 | val = AXEN_TXCOE_OFF; | |
533 | if (enabled & IFCAP_CSUM_IPv4_Tx) | 533 | if (enabled & IFCAP_CSUM_IPv4_Tx) | |
534 | val |= AXEN_TXCOE_IPv4; | 534 | val |= AXEN_TXCOE_IPv4; | |
535 | if (enabled & IFCAP_CSUM_TCPv4_Tx) | 535 | if (enabled & IFCAP_CSUM_TCPv4_Tx) | |
536 | val |= AXEN_TXCOE_TCPv4; | 536 | val |= AXEN_TXCOE_TCPv4; | |
537 | if (enabled & IFCAP_CSUM_UDPv4_Tx) | 537 | if (enabled & IFCAP_CSUM_UDPv4_Tx) | |
538 | val |= AXEN_TXCOE_UDPv4; | 538 | val |= AXEN_TXCOE_UDPv4; | |
539 | if (enabled & IFCAP_CSUM_TCPv6_Tx) | 539 | if (enabled & IFCAP_CSUM_TCPv6_Tx) | |
540 | val |= AXEN_TXCOE_TCPv6; | 540 | val |= AXEN_TXCOE_TCPv6; | |
541 | if (enabled & IFCAP_CSUM_UDPv6_Tx) | 541 | if (enabled & IFCAP_CSUM_UDPv6_Tx) | |
542 | val |= AXEN_TXCOE_UDPv6; | 542 | val |= AXEN_TXCOE_UDPv6; | |
543 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_TX_COE, &val); | 543 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_TX_COE, &val); | |
544 | } | 544 | } | |
545 | 545 | |||
546 | static int | 546 | static int | |
547 | axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 547 | axen_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
548 | { | 548 | { | |
549 | struct usbnet * const un = ifp->if_softc; | 549 | struct usbnet * const un = ifp->if_softc; | |
550 | 550 | |||
551 | switch (cmd) { | 551 | switch (cmd) { | |
552 | case SIOCSIFCAP: | 552 | case SIOCSIFCAP: | |
553 | axen_setoe_locked(un); | 553 | axen_setoe_locked(un); | |
554 | break; | 554 | break; | |
555 | default: | 555 | default: | |
556 | break; | 556 | break; | |
557 | } | 557 | } | |
558 | 558 | |||
559 | return 0; | 559 | return 0; | |
560 | } | 560 | } | |
561 | 561 | |||
562 | static int | 562 | static int | |
563 | axen_match(device_t parent, cfdata_t match, void *aux) | 563 | axen_match(device_t parent, cfdata_t match, void *aux) | |
564 | { | 564 | { | |
565 | struct usb_attach_arg *uaa = aux; | 565 | struct usb_attach_arg *uaa = aux; | |
566 | 566 | |||
567 | return axen_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 567 | return axen_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
568 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 568 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
569 | } | 569 | } | |
570 | 570 | |||
571 | static void | 571 | static void | |
572 | axen_attach(device_t parent, device_t self, void *aux) | 572 | axen_attach(device_t parent, device_t self, void *aux) | |
573 | { | 573 | { | |
574 | USBNET_MII_DECL_DEFAULT(unm); | 574 | USBNET_MII_DECL_DEFAULT(unm); | |
575 | struct usbnet * const un = device_private(self); | 575 | struct usbnet * const un = device_private(self); | |
576 | struct usb_attach_arg *uaa = aux; | 576 | struct usb_attach_arg *uaa = aux; | |
577 | struct usbd_device *dev = uaa->uaa_device; | 577 | struct usbd_device *dev = uaa->uaa_device; | |
578 | usbd_status err; | 578 | usbd_status err; | |
579 | usb_interface_descriptor_t *id; | 579 | usb_interface_descriptor_t *id; | |
580 | usb_endpoint_descriptor_t *ed; | 580 | usb_endpoint_descriptor_t *ed; | |
581 | char *devinfop; | 581 | char *devinfop; | |
582 | uint16_t axen_flags; | 582 | uint16_t axen_flags; | |
583 | int i; | 583 | int i; | |
584 | 584 | |||
585 | aprint_naive("\n"); | 585 | aprint_naive("\n"); | |
586 | aprint_normal("\n"); | 586 | aprint_normal("\n"); | |
587 | devinfop = usbd_devinfo_alloc(dev, 0); | 587 | devinfop = usbd_devinfo_alloc(dev, 0); | |
588 | aprint_normal_dev(self, "%s\n", devinfop); | 588 | aprint_normal_dev(self, "%s\n", devinfop); | |
589 | usbd_devinfo_free(devinfop); | 589 | usbd_devinfo_free(devinfop); | |
590 | 590 | |||
591 | un->un_dev = self; | 591 | un->un_dev = self; | |
592 | un->un_udev = dev; | 592 | un->un_udev = dev; | |
593 | un->un_sc = un; | 593 | un->un_sc = un; | |
594 | un->un_ops = &axen_ops; | 594 | un->un_ops = &axen_ops; | |
595 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 595 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
596 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 596 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
597 | un->un_rx_list_cnt = AXEN_RX_LIST_CNT; | 597 | un->un_rx_list_cnt = AXEN_RX_LIST_CNT; | |
598 | un->un_tx_list_cnt = AXEN_TX_LIST_CNT; | 598 | un->un_tx_list_cnt = AXEN_TX_LIST_CNT; | |
599 | 599 | |||
600 | err = usbd_set_config_no(dev, AXEN_CONFIG_NO, 1); | 600 | err = usbd_set_config_no(dev, AXEN_CONFIG_NO, 1); | |
601 | if (err) { | 601 | if (err) { | |
602 | aprint_error_dev(self, "failed to set configuration" | 602 | aprint_error_dev(self, "failed to set configuration" | |
603 | ", err=%s\n", usbd_errstr(err)); | 603 | ", err=%s\n", usbd_errstr(err)); | |
604 | return; | 604 | return; | |
605 | } | 605 | } | |
606 | 606 | |||
607 | axen_flags = axen_lookup(uaa->uaa_vendor, uaa->uaa_product)->axen_flags; | 607 | axen_flags = axen_lookup(uaa->uaa_vendor, uaa->uaa_product)->axen_flags; | |
608 | 608 | |||
609 | err = usbd_device2interface_handle(dev, AXEN_IFACE_IDX, &un->un_iface); | 609 | err = usbd_device2interface_handle(dev, AXEN_IFACE_IDX, &un->un_iface); | |
610 | if (err) { | 610 | if (err) { | |
611 | aprint_error_dev(self, "getting interface handle failed\n"); | 611 | aprint_error_dev(self, "getting interface handle failed\n"); | |
612 | return; | 612 | return; | |
613 | } | 613 | } | |
614 | 614 | |||
615 | /* decide on what our bufsize will be */ | 615 | /* decide on what our bufsize will be */ | |
616 | switch (dev->ud_speed) { | 616 | switch (dev->ud_speed) { | |
617 | case USB_SPEED_SUPER: | 617 | case USB_SPEED_SUPER: | |
618 | un->un_rx_bufsz = AXEN_BUFSZ_SS * 1024; | 618 | un->un_rx_bufsz = AXEN_BUFSZ_SS * 1024; | |
619 | break; | 619 | break; | |
620 | case USB_SPEED_HIGH: | 620 | case USB_SPEED_HIGH: | |
621 | un->un_rx_bufsz = AXEN_BUFSZ_HS * 1024; | 621 | un->un_rx_bufsz = AXEN_BUFSZ_HS * 1024; | |
622 | break; | 622 | break; | |
623 | default: | 623 | default: | |
624 | un->un_rx_bufsz = AXEN_BUFSZ_LS * 1024; | 624 | un->un_rx_bufsz = AXEN_BUFSZ_LS * 1024; | |
625 | break; | 625 | break; | |
626 | } | 626 | } | |
627 | un->un_tx_bufsz = IP_MAXPACKET + ETHER_HDR_LEN + ETHER_CRC_LEN + | 627 | un->un_tx_bufsz = IP_MAXPACKET + ETHER_HDR_LEN + ETHER_CRC_LEN + | |
628 | ETHER_VLAN_ENCAP_LEN + sizeof(struct axen_sframe_hdr); | 628 | ETHER_VLAN_ENCAP_LEN + sizeof(struct axen_sframe_hdr); | |
629 | 629 | |||
630 | /* Find endpoints. */ | 630 | /* Find endpoints. */ | |
631 | id = usbd_get_interface_descriptor(un->un_iface); | 631 | id = usbd_get_interface_descriptor(un->un_iface); | |
632 | for (i = 0; i < id->bNumEndpoints; i++) { | 632 | for (i = 0; i < id->bNumEndpoints; i++) { | |
633 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 633 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
634 | if (!ed) { | 634 | if (!ed) { | |
635 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 635 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
636 | return; | 636 | return; | |
637 | } | 637 | } | |
638 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 638 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
639 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 639 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
640 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 640 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
641 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 641 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
642 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 642 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
643 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 643 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
644 | #if 0 /* not used yet */ | 644 | #if 0 /* not used yet */ | |
645 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 645 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
646 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 646 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
647 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 647 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
648 | #endif | 648 | #endif | |
649 | } | 649 | } | |
650 | } | 650 | } | |
651 | 651 | |||
652 | /* Set these up now for axen_cmd(). */ | 652 | /* Set these up now for axen_cmd(). */ | |
653 | usbnet_attach(un, "axendet"); | 653 | usbnet_attach(un, "axendet"); | |
654 | 654 | |||
655 | un->un_phyno = AXEN_PHY_ID; | 655 | un->un_phyno = AXEN_PHY_ID; | |
656 | DPRINTF(("%s: phyno %d\n", device_xname(self), un->un_phyno)); | 656 | DPRINTF(("%s: phyno %d\n", device_xname(self), un->un_phyno)); | |
657 | 657 | |||
658 | /* Get station address. */ | 658 | /* Get station address. */ | |
659 | if (axen_get_eaddr(un, &un->un_eaddr)) { | 659 | if (axen_get_eaddr(un, &un->un_eaddr)) { | |
660 | printf("EEPROM checksum error\n"); | 660 | printf("EEPROM checksum error\n"); | |
661 | return; | 661 | return; | |
662 | } | 662 | } | |
663 | 663 | |||
664 | axen_ax88179_init(un); | 664 | axen_ax88179_init(un); | |
665 | 665 | |||
666 | /* An ASIX chip was detected. Inform the world. */ | 666 | /* An ASIX chip was detected. Inform the world. */ | |
667 | if (axen_flags & AX178A) | 667 | if (axen_flags & AX178A) | |
668 | aprint_normal_dev(self, "AX88178a\n"); | 668 | aprint_normal_dev(self, "AX88178a\n"); | |
669 | else if (axen_flags & AX179) | 669 | else if (axen_flags & AX179) | |
670 | aprint_normal_dev(self, "AX88179\n"); | 670 | aprint_normal_dev(self, "AX88179\n"); | |
671 | else | 671 | else | |
672 | aprint_normal_dev(self, "(unknown)\n"); | 672 | aprint_normal_dev(self, "(unknown)\n"); | |
673 | 673 | |||
674 | struct ethercom *ec = usbnet_ec(un); | 674 | struct ethercom *ec = usbnet_ec(un); | |
675 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | 675 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | |
676 | 676 | |||
677 | /* Adapter does not support TSOv6 (They call it LSOv2). */ | 677 | /* Adapter does not support TSOv6 (They call it LSOv2). */ | |
678 | struct ifnet *ifp = usbnet_ifp(un); | 678 | struct ifnet *ifp = usbnet_ifp(un); | |
679 | ifp->if_capabilities |= IFCAP_TSOv4 | | 679 | ifp->if_capabilities |= IFCAP_TSOv4 | | |
680 | IFCAP_CSUM_IPv4_Rx | IFCAP_CSUM_IPv4_Tx | | 680 | IFCAP_CSUM_IPv4_Rx | IFCAP_CSUM_IPv4_Tx | | |
681 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_TCPv4_Tx | | 681 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_TCPv4_Tx | | |
682 | IFCAP_CSUM_UDPv4_Rx | IFCAP_CSUM_UDPv4_Tx | | 682 | IFCAP_CSUM_UDPv4_Rx | IFCAP_CSUM_UDPv4_Tx | | |
683 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_TCPv6_Tx | | 683 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_TCPv6_Tx | | |
684 | IFCAP_CSUM_UDPv6_Rx | IFCAP_CSUM_UDPv6_Tx; | 684 | IFCAP_CSUM_UDPv6_Rx | IFCAP_CSUM_UDPv6_Tx; | |
685 | 685 | |||
686 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 686 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
687 | 0, &unm); | 687 | 0, &unm); | |
688 | } | 688 | } | |
689 | 689 | |||
690 | static int | 690 | static int | |
691 | axen_csum_flags_rx(struct ifnet *ifp, uint32_t pkt_hdr) | 691 | axen_csum_flags_rx(struct ifnet *ifp, uint32_t pkt_hdr) | |
692 | { | 692 | { | |
693 | int enabled_flags = ifp->if_csum_flags_rx; | 693 | int enabled_flags = ifp->if_csum_flags_rx; | |
694 | int csum_flags = 0; | 694 | int csum_flags = 0; | |
695 | int l3_type, l4_type; | 695 | int l3_type, l4_type; | |
696 | 696 | |||
697 | if (enabled_flags == 0) | 697 | if (enabled_flags == 0) | |
698 | return 0; | 698 | return 0; | |
699 | 699 | |||
700 | l3_type = (pkt_hdr & AXEN_RXHDR_L3_TYPE_MASK) >> | 700 | l3_type = (pkt_hdr & AXEN_RXHDR_L3_TYPE_MASK) >> | |
701 | AXEN_RXHDR_L3_TYPE_OFFSET; | 701 | AXEN_RXHDR_L3_TYPE_OFFSET; | |
702 | 702 | |||
703 | if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) | 703 | if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) | |
704 | csum_flags |= M_CSUM_IPv4; | 704 | csum_flags |= M_CSUM_IPv4; | |
705 | 705 | |||
706 | l4_type = (pkt_hdr & AXEN_RXHDR_L4_TYPE_MASK) >> | 706 | l4_type = (pkt_hdr & AXEN_RXHDR_L4_TYPE_MASK) >> | |
707 | AXEN_RXHDR_L4_TYPE_OFFSET; | 707 | AXEN_RXHDR_L4_TYPE_OFFSET; | |
708 | 708 | |||
709 | switch (l4_type) { | 709 | switch (l4_type) { | |
710 | case AXEN_RXHDR_L4_TYPE_TCP: | 710 | case AXEN_RXHDR_L4_TYPE_TCP: | |
711 | if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) | 711 | if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) | |
712 | csum_flags |= M_CSUM_TCPv4; | 712 | csum_flags |= M_CSUM_TCPv4; | |
713 | else | 713 | else | |
714 | csum_flags |= M_CSUM_TCPv6; | 714 | csum_flags |= M_CSUM_TCPv6; | |
715 | break; | 715 | break; | |
716 | case AXEN_RXHDR_L4_TYPE_UDP: | 716 | case AXEN_RXHDR_L4_TYPE_UDP: | |
717 | if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) | 717 | if (l3_type == AXEN_RXHDR_L3_TYPE_IPV4) | |
718 | csum_flags |= M_CSUM_UDPv4; | 718 | csum_flags |= M_CSUM_UDPv4; | |
719 | else | 719 | else | |
720 | csum_flags |= M_CSUM_UDPv6; | 720 | csum_flags |= M_CSUM_UDPv6; | |
721 | break; | 721 | break; | |
722 | default: | 722 | default: | |
723 | break; | 723 | break; | |
724 | } | 724 | } | |
725 | 725 | |||
726 | csum_flags &= enabled_flags; | 726 | csum_flags &= enabled_flags; | |
727 | if ((csum_flags & M_CSUM_IPv4) && (pkt_hdr & AXEN_RXHDR_L3CSUM_ERR)) | 727 | if ((csum_flags & M_CSUM_IPv4) && (pkt_hdr & AXEN_RXHDR_L3CSUM_ERR)) | |
728 | csum_flags |= M_CSUM_IPv4_BAD; | 728 | csum_flags |= M_CSUM_IPv4_BAD; | |
729 | if ((csum_flags & ~M_CSUM_IPv4) && (pkt_hdr & AXEN_RXHDR_L4CSUM_ERR)) | 729 | if ((csum_flags & ~M_CSUM_IPv4) && (pkt_hdr & AXEN_RXHDR_L4CSUM_ERR)) | |
730 | csum_flags |= M_CSUM_TCP_UDP_BAD; | 730 | csum_flags |= M_CSUM_TCP_UDP_BAD; | |
731 | 731 | |||
732 | return csum_flags; | 732 | return csum_flags; | |
733 | } | 733 | } | |
734 | 734 | |||
735 | static void | 735 | static void | |
736 | axen_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 736 | axen_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
737 | { | 737 | { | |
738 | struct ifnet *ifp = usbnet_ifp(un); | 738 | struct ifnet *ifp = usbnet_ifp(un); | |
739 | uint8_t *buf = c->unc_buf; | 739 | uint8_t *buf = c->unc_buf; | |
740 | uint32_t rx_hdr, pkt_hdr; | 740 | uint32_t rx_hdr, pkt_hdr; | |
741 | uint32_t *hdr_p; | 741 | uint32_t *hdr_p; | |
742 | uint16_t hdr_offset, pkt_count; | 742 | uint16_t hdr_offset, pkt_count; | |
743 | size_t pkt_len; | 743 | size_t pkt_len; | |
744 | size_t temp; | 744 | size_t temp; | |
745 | 745 | |||
746 | if (total_len < sizeof(pkt_hdr)) { | 746 | if (total_len < sizeof(pkt_hdr)) { | |
747 | aprint_error_dev(un->un_dev, "rxeof: too short transfer\n"); | 747 | aprint_error_dev(un->un_dev, "rxeof: too short transfer\n"); | |
748 | if_statinc(ifp, if_ierrors); | 748 | if_statinc(ifp, if_ierrors); | |
749 | return; | 749 | return; | |
750 | } | 750 | } | |
751 | 751 | |||
752 | /* | 752 | /* | |
753 | * buffer map | 753 | * buffer map | |
754 | * [packet #0]...[packet #n][pkt hdr#0]..[pkt hdr#n][recv_hdr] | 754 | * [packet #0]...[packet #n][pkt hdr#0]..[pkt hdr#n][recv_hdr] | |
755 | * each packet has 0xeeee as psuedo header.. | 755 | * each packet has 0xeeee as psuedo header.. | |
756 | */ | 756 | */ | |
757 | hdr_p = (uint32_t *)(buf + total_len - sizeof(uint32_t)); | 757 | hdr_p = (uint32_t *)(buf + total_len - sizeof(uint32_t)); | |
758 | rx_hdr = le32toh(*hdr_p); | 758 | rx_hdr = le32toh(*hdr_p); | |
759 | hdr_offset = (uint16_t)(rx_hdr >> 16); | 759 | hdr_offset = (uint16_t)(rx_hdr >> 16); | |
760 | pkt_count = (uint16_t)(rx_hdr & 0xffff); | 760 | pkt_count = (uint16_t)(rx_hdr & 0xffff); | |
761 | 761 | |||
762 | /* sanity check */ | 762 | /* sanity check */ | |
763 | if (hdr_offset > total_len) { | 763 | if (hdr_offset > total_len) { | |
764 | aprint_error_dev(un->un_dev, | 764 | aprint_error_dev(un->un_dev, | |
765 | "rxeof: invalid hdr offset (%u > %u)\n", | 765 | "rxeof: invalid hdr offset (%u > %u)\n", | |
766 | hdr_offset, total_len); | 766 | hdr_offset, total_len); | |
767 | if_statinc(ifp, if_ierrors); | 767 | if_statinc(ifp, if_ierrors); | |
768 | usbd_delay_ms(un->un_udev, 100); | 768 | usbd_delay_ms(un->un_udev, 100); | |
769 | return; | 769 | return; | |
770 | } | 770 | } | |
771 | 771 | |||
772 | /* point first packet header */ | 772 | /* point first packet header */ | |
773 | hdr_p = (uint32_t *)(buf + hdr_offset); | 773 | hdr_p = (uint32_t *)(buf + hdr_offset); | |
774 | 774 | |||
775 | /* | 775 | /* | |
776 | * ax88179 will pack multiple ip packet to a USB transaction. | 776 | * ax88179 will pack multiple ip packet to a USB transaction. | |
777 | * process all of packets in the buffer | 777 | * process all of packets in the buffer | |
778 | */ | 778 | */ | |
779 | 779 | |||
780 | #if 1 /* XXX: paranoiac check. need to remove later */ | 780 | #if 1 /* XXX: paranoiac check. need to remove later */ | |
781 | #define AXEN_MAX_PACKED_PACKET 200 | 781 | #define AXEN_MAX_PACKED_PACKET 200 | |
782 | if (pkt_count > AXEN_MAX_PACKED_PACKET) { | 782 | if (pkt_count > AXEN_MAX_PACKED_PACKET) { | |
783 | DPRINTF(("%s: Too many packets (%d) in a transaction, discard.\n", | 783 | DPRINTF(("%s: Too many packets (%d) in a transaction, discard.\n", | |
784 | device_xname(un->un_dev), pkt_count)); | 784 | device_xname(un->un_dev), pkt_count)); | |
785 | return; | 785 | return; | |
786 | } | 786 | } | |
787 | #endif | 787 | #endif | |
788 | 788 | |||
789 | if (pkt_count) | 789 | if (pkt_count) | |
790 | rnd_add_uint32(usbnet_rndsrc(un), pkt_count); | 790 | rnd_add_uint32(usbnet_rndsrc(un), pkt_count); | |
791 | 791 | |||
792 | do { | 792 | do { | |
793 | if ((buf[0] != 0xee) || (buf[1] != 0xee)) { | 793 | if ((buf[0] != 0xee) || (buf[1] != 0xee)) { | |
794 | aprint_error_dev(un->un_dev, | 794 | aprint_error_dev(un->un_dev, | |
795 | "invalid buffer(pkt#%d), continue\n", pkt_count); | 795 | "invalid buffer(pkt#%d), continue\n", pkt_count); | |
796 | if_statadd(ifp, if_ierrors, pkt_count); | 796 | if_statadd(ifp, if_ierrors, pkt_count); | |
797 | return; | 797 | return; | |
798 | } | 798 | } | |
799 | 799 | |||
800 | pkt_hdr = le32toh(*hdr_p); | 800 | pkt_hdr = le32toh(*hdr_p); | |
801 | pkt_len = (pkt_hdr >> 16) & 0x1fff; | 801 | pkt_len = (pkt_hdr >> 16) & 0x1fff; | |
802 | DPRINTFN(10, | 802 | DPRINTFN(10, | |
803 | ("%s: rxeof: packet#%d, pkt_hdr 0x%08x, pkt_len %zu\n", | 803 | ("%s: rxeof: packet#%d, pkt_hdr 0x%08x, pkt_len %zu\n", | |
804 | device_xname(un->un_dev), pkt_count, pkt_hdr, pkt_len)); | 804 | device_xname(un->un_dev), pkt_count, pkt_hdr, pkt_len)); | |
805 | 805 | |||
806 | if (pkt_hdr & (AXEN_RXHDR_CRC_ERR | AXEN_RXHDR_DROP_ERR)) { | 806 | if (pkt_hdr & (AXEN_RXHDR_CRC_ERR | AXEN_RXHDR_DROP_ERR)) { | |
807 | if_statinc(ifp, if_ierrors); | 807 | if_statinc(ifp, if_ierrors); | |
808 | /* move to next pkt header */ | 808 | /* move to next pkt header */ | |
809 | DPRINTF(("%s: %s err (pkt#%d)\n", | 809 | DPRINTF(("%s: %s err (pkt#%d)\n", | |
810 | device_xname(un->un_dev), | 810 | device_xname(un->un_dev), | |
811 | (pkt_hdr & AXEN_RXHDR_CRC_ERR) ? "crc" : "drop", | 811 | (pkt_hdr & AXEN_RXHDR_CRC_ERR) ? "crc" : "drop", | |
812 | pkt_count)); | 812 | pkt_count)); | |
813 | goto nextpkt; | 813 | goto nextpkt; | |
814 | } | 814 | } | |
815 | 815 | |||
816 | usbnet_enqueue(un, buf + ETHER_ALIGN, pkt_len - 6, | 816 | usbnet_enqueue(un, buf + ETHER_ALIGN, pkt_len - 6, | |
817 | axen_csum_flags_rx(ifp, pkt_hdr), 0, 0); | 817 | axen_csum_flags_rx(ifp, pkt_hdr), 0, 0); | |
818 | 818 | |||
819 | nextpkt: | 819 | nextpkt: | |
820 | /* | 820 | /* | |
821 | * prepare next packet | 821 | * prepare next packet | |
822 | * as each packet will be aligned 8byte boundary, | 822 | * as each packet will be aligned 8byte boundary, | |
823 | * need to fix up the start point of the buffer. | 823 | * need to fix up the start point of the buffer. | |
824 | */ | 824 | */ | |
825 | temp = ((pkt_len + 7) & 0xfff8); | 825 | temp = ((pkt_len + 7) & 0xfff8); | |
826 | buf = buf + temp; | 826 | buf = buf + temp; | |
827 | hdr_p++; | 827 | hdr_p++; | |
828 | pkt_count--; | 828 | pkt_count--; | |
829 | } while (pkt_count > 0); | 829 | } while (pkt_count > 0); | |
830 | } | 830 | } | |
831 | 831 | |||
832 | static unsigned | 832 | static unsigned | |
833 | axen_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 833 | axen_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
834 | { | 834 | { | |
835 | struct axen_sframe_hdr hdr; | 835 | struct axen_sframe_hdr hdr; | |
836 | u_int length, boundary; | 836 | u_int length, boundary; | |
837 | 837 | |||
838 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) | 838 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) | |
839 | return 0; | 839 | return 0; | |
840 | length = m->m_pkthdr.len + sizeof(hdr); | 840 | length = m->m_pkthdr.len + sizeof(hdr); | |
841 | 841 | |||
842 | /* XXX Is this needed? wMaxPacketSize? */ | 842 | /* XXX Is this needed? wMaxPacketSize? */ | |
843 | switch (un->un_udev->ud_speed) { | 843 | switch (un->un_udev->ud_speed) { | |
844 | case USB_SPEED_SUPER: | 844 | case USB_SPEED_SUPER: | |
845 | boundary = 4096; | 845 | boundary = 4096; | |
846 | break; | 846 | break; | |
847 | case USB_SPEED_HIGH: | 847 | case USB_SPEED_HIGH: | |
848 | boundary = 512; | 848 | boundary = 512; | |
849 | break; | 849 | break; | |
850 | default: | 850 | default: | |
851 | boundary = 64; | 851 | boundary = 64; | |
852 | break; | 852 | break; | |
853 | } | 853 | } | |
854 | 854 | |||
855 | hdr.plen = htole32(m->m_pkthdr.len); | 855 | hdr.plen = htole32(m->m_pkthdr.len); | |
856 | 856 | |||
857 | hdr.gso = (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) ? | 857 | hdr.gso = (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) ? | |
858 | m->m_pkthdr.segsz : 0; | 858 | m->m_pkthdr.segsz : 0; | |
859 | if ((length % boundary) == 0) { | 859 | if ((length % boundary) == 0) { | |
860 | DPRINTF(("%s: boundary hit\n", device_xname(un->un_dev))); | 860 | DPRINTF(("%s: boundary hit\n", device_xname(un->un_dev))); | |
861 | hdr.gso |= 0x80008000; /* XXX enable padding */ | 861 | hdr.gso |= 0x80008000; /* XXX enable padding */ | |
862 | } | 862 | } | |
863 | hdr.gso = htole32(hdr.gso); | 863 | hdr.gso = htole32(hdr.gso); | |
864 | 864 | |||
865 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); | 865 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); | |
866 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + sizeof(hdr)); | 866 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + sizeof(hdr)); | |
867 | 867 | |||
868 | return length; | 868 | return length; | |
869 | } | 869 | } | |
870 | 870 | |||
871 | static int | 871 | static int | |
872 | axen_uno_init(struct ifnet *ifp) | 872 | axen_uno_init(struct ifnet *ifp) | |
873 | { | 873 | { | |
874 | struct usbnet * const un = ifp->if_softc; | 874 | struct usbnet * const un = ifp->if_softc; | |
875 | uint16_t rxmode; | 875 | uint16_t rxmode; | |
876 | uint16_t wval; | 876 | uint16_t wval; | |
877 | uint8_t bval; | 877 | uint8_t bval; | |
878 | 878 | |||
879 | if (usbnet_isdying(un)) | |||
880 | return EIO; | |||
881 | ||||
882 | /* Cancel pending I/O */ | 879 | /* Cancel pending I/O */ | |
883 | usbnet_stop(un, ifp, 1); | 880 | usbnet_stop(un, ifp, 1); | |
884 | 881 | |||
885 | /* Reset the ethernet interface. */ | 882 | /* Reset the ethernet interface. */ | |
886 | axen_reset(un); | 883 | axen_reset(un); | |
887 | 884 | |||
888 | /* XXX: ? */ | 885 | /* XXX: ? */ | |
889 | bval = 0x01; | 886 | bval = 0x01; | |
890 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_UNK_28, &bval); | 887 | axen_cmd(un, AXEN_CMD_MAC_WRITE, 1, AXEN_UNK_28, &bval); | |
891 | 888 | |||
892 | /* Configure offloading engine. */ | 889 | /* Configure offloading engine. */ | |
893 | axen_setoe_locked(un); | 890 | axen_setoe_locked(un); | |
894 | 891 | |||
895 | /* Enable receiver, set RX mode */ | 892 | /* Enable receiver, set RX mode */ | |
896 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); | 893 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); | |
897 | rxmode = le16toh(wval); | 894 | rxmode = le16toh(wval); | |
898 | rxmode |= AXEN_RXCTL_START; | 895 | rxmode |= AXEN_RXCTL_START; | |
899 | wval = htole16(rxmode); | 896 | wval = htole16(rxmode); | |
900 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | 897 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | |
901 | 898 | |||
902 | return usbnet_init_rx_tx(un); | 899 | return usbnet_init_rx_tx(un); | |
903 | } | 900 | } | |
904 | 901 | |||
905 | static void | 902 | static void | |
906 | axen_uno_stop(struct ifnet *ifp, int disable) | 903 | axen_uno_stop(struct ifnet *ifp, int disable) | |
907 | { | 904 | { | |
908 | struct usbnet * const un = ifp->if_softc; | 905 | struct usbnet * const un = ifp->if_softc; | |
909 | uint16_t rxmode, wval; | 906 | uint16_t rxmode, wval; | |
910 | 907 | |||
911 | axen_reset(un); | 908 | axen_reset(un); | |
912 | 909 | |||
913 | /* Disable receiver, set RX mode */ | 910 | /* Disable receiver, set RX mode */ | |
914 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); | 911 | axen_cmd(un, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval); | |
915 | rxmode = le16toh(wval); | 912 | rxmode = le16toh(wval); | |
916 | rxmode &= ~AXEN_RXCTL_START; | 913 | rxmode &= ~AXEN_RXCTL_START; | |
917 | wval = htole16(rxmode); | 914 | wval = htole16(rxmode); | |
918 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | 915 | axen_cmd(un, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval); | |
919 | } | 916 | } | |
920 | 917 | |||
921 | #ifdef _MODULE | 918 | #ifdef _MODULE | |
922 | #include "ioconf.c" | 919 | #include "ioconf.c" | |
923 | #endif | 920 | #endif | |
924 | 921 | |||
925 | USBNET_MODULE(axen) | 922 | USBNET_MODULE(axen) |
--- src/sys/dev/usb/if_cdce.c 2022/03/03 05:52:20 1.74
+++ src/sys/dev/usb/if_cdce.c 2022/03/03 05:55:01 1.75
@@ -1,320 +1,316 @@ | @@ -1,320 +1,316 @@ | |||
1 | /* $NetBSD: if_cdce.c,v 1.74 2022/03/03 05:52:20 riastradh Exp $ */ | 1 | /* $NetBSD: if_cdce.c,v 1.75 2022/03/03 05:55:01 riastradh Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com> | 4 | * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com> | |
5 | * Copyright (c) 2003 Craig Boston | 5 | * Copyright (c) 2003 Craig Boston | |
6 | * Copyright (c) 2004 Daniel Hartmeier | 6 | * Copyright (c) 2004 Daniel Hartmeier | |
7 | * All rights reserved. | 7 | * All rights reserved. | |
8 | * | 8 | * | |
9 | * Redistribution and use in source and binary forms, with or without | 9 | * Redistribution and use in source and binary forms, with or without | |
10 | * modification, are permitted provided that the following conditions | 10 | * modification, are permitted provided that the following conditions | |
11 | * are met: | 11 | * are met: | |
12 | * 1. Redistributions of source code must retain the above copyright | 12 | * 1. Redistributions of source code must retain the above copyright | |
13 | * notice, this list of conditions and the following disclaimer. | 13 | * notice, this list of conditions and the following disclaimer. | |
14 | * 2. Redistributions in binary form must reproduce the above copyright | 14 | * 2. Redistributions in binary form must reproduce the above copyright | |
15 | * notice, this list of conditions and the following disclaimer in the | 15 | * notice, this list of conditions and the following disclaimer in the | |
16 | * documentation and/or other materials provided with the distribution. | 16 | * documentation and/or other materials provided with the distribution. | |
17 | * 3. All advertising materials mentioning features or use of this software | 17 | * 3. All advertising materials mentioning features or use of this software | |
18 | * must display the following acknowledgement: | 18 | * must display the following acknowledgement: | |
19 | * This product includes software developed by Bill Paul. | 19 | * This product includes software developed by Bill Paul. | |
20 | * 4. Neither the name of the author nor the names of any co-contributors | 20 | * 4. Neither the name of the author nor the names of any co-contributors | |
21 | * may be used to endorse or promote products derived from this software | 21 | * may be used to endorse or promote products derived from this software | |
22 | * without specific prior written permission. | 22 | * without specific prior written permission. | |
23 | * | 23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | 24 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR | 27 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR | |
28 | * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 28 | * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
29 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 29 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
30 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | 30 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
31 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | 31 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
32 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | 32 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
33 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | 33 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
34 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | /* | 37 | /* | |
38 | * USB Communication Device Class (Ethernet Networking Control Model) | 38 | * USB Communication Device Class (Ethernet Networking Control Model) | |
39 | * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf | 39 | * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf | |
40 | */ | 40 | */ | |
41 | 41 | |||
42 | #include <sys/cdefs.h> | 42 | #include <sys/cdefs.h> | |
43 | __KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.74 2022/03/03 05:52:20 riastradh Exp $"); | 43 | __KERNEL_RCSID(0, "$NetBSD: if_cdce.c,v 1.75 2022/03/03 05:55:01 riastradh Exp $"); | |
44 | 44 | |||
45 | #include <sys/param.h> | 45 | #include <sys/param.h> | |
46 | 46 | |||
47 | #include <dev/usb/usbnet.h> | 47 | #include <dev/usb/usbnet.h> | |
48 | #include <dev/usb/usbcdc.h> | 48 | #include <dev/usb/usbcdc.h> | |
49 | 49 | |||
50 | #include <dev/usb/if_cdcereg.h> | 50 | #include <dev/usb/if_cdcereg.h> | |
51 | 51 | |||
52 | struct cdce_type { | 52 | struct cdce_type { | |
53 | struct usb_devno cdce_dev; | 53 | struct usb_devno cdce_dev; | |
54 | uint16_t cdce_flags; | 54 | uint16_t cdce_flags; | |
55 | #define CDCE_ZAURUS 1 | 55 | #define CDCE_ZAURUS 1 | |
56 | #define CDCE_NO_UNION 2 | 56 | #define CDCE_NO_UNION 2 | |
57 | }; | 57 | }; | |
58 | 58 | |||
59 | static const struct cdce_type cdce_devs[] = { | 59 | static const struct cdce_type cdce_devs[] = { | |
60 | {{ USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632 }, CDCE_NO_UNION }, | 60 | {{ USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632 }, CDCE_NO_UNION }, | |
61 | {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX }, CDCE_NO_UNION }, | 61 | {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX }, CDCE_NO_UNION }, | |
62 | {{ USB_VENDOR_GMATE, USB_PRODUCT_GMATE_YP3X00 }, CDCE_NO_UNION }, | 62 | {{ USB_VENDOR_GMATE, USB_PRODUCT_GMATE_YP3X00 }, CDCE_NO_UNION }, | |
63 | {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN }, CDCE_ZAURUS | CDCE_NO_UNION }, | 63 | {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN }, CDCE_ZAURUS | CDCE_NO_UNION }, | |
64 | {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN2 }, CDCE_ZAURUS | CDCE_NO_UNION }, | 64 | {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN2 }, CDCE_ZAURUS | CDCE_NO_UNION }, | |
65 | {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, CDCE_NO_UNION }, | 65 | {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, CDCE_NO_UNION }, | |
66 | {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, CDCE_ZAURUS }, | 66 | {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, CDCE_ZAURUS }, | |
67 | {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, CDCE_ZAURUS | CDCE_NO_UNION }, | 67 | {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, CDCE_ZAURUS | CDCE_NO_UNION }, | |
68 | {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, CDCE_ZAURUS | CDCE_NO_UNION }, | 68 | {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, CDCE_ZAURUS | CDCE_NO_UNION }, | |
69 | {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, CDCE_ZAURUS | CDCE_NO_UNION }, | 69 | {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, CDCE_ZAURUS | CDCE_NO_UNION }, | |
70 | {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, CDCE_ZAURUS | CDCE_NO_UNION }, | 70 | {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, CDCE_ZAURUS | CDCE_NO_UNION }, | |
71 | }; | 71 | }; | |
72 | #define cdce_lookup(v, p) \ | 72 | #define cdce_lookup(v, p) \ | |
73 | ((const struct cdce_type *)usb_lookup(cdce_devs, v, p)) | 73 | ((const struct cdce_type *)usb_lookup(cdce_devs, v, p)) | |
74 | 74 | |||
75 | static int cdce_match(device_t, cfdata_t, void *); | 75 | static int cdce_match(device_t, cfdata_t, void *); | |
76 | static void cdce_attach(device_t, device_t, void *); | 76 | static void cdce_attach(device_t, device_t, void *); | |
77 | 77 | |||
78 | CFATTACH_DECL_NEW(cdce, sizeof(struct usbnet), cdce_match, cdce_attach, | 78 | CFATTACH_DECL_NEW(cdce, sizeof(struct usbnet), cdce_match, cdce_attach, | |
79 | usbnet_detach, usbnet_activate); | 79 | usbnet_detach, usbnet_activate); | |
80 | 80 | |||
81 | static void cdce_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 81 | static void cdce_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
82 | uint32_t); | 82 | uint32_t); | |
83 | static unsigned cdce_uno_tx_prepare(struct usbnet *, struct mbuf *, | 83 | static unsigned cdce_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
84 | struct usbnet_chain *); | 84 | struct usbnet_chain *); | |
85 | static int cdce_uno_init(struct ifnet *); | 85 | static int cdce_uno_init(struct ifnet *); | |
86 | 86 | |||
87 | static const struct usbnet_ops cdce_ops = { | 87 | static const struct usbnet_ops cdce_ops = { | |
88 | .uno_tx_prepare = cdce_uno_tx_prepare, | 88 | .uno_tx_prepare = cdce_uno_tx_prepare, | |
89 | .uno_rx_loop = cdce_uno_rx_loop, | 89 | .uno_rx_loop = cdce_uno_rx_loop, | |
90 | .uno_init = cdce_uno_init, | 90 | .uno_init = cdce_uno_init, | |
91 | }; | 91 | }; | |
92 | 92 | |||
93 | static int | 93 | static int | |
94 | cdce_match(device_t parent, cfdata_t match, void *aux) | 94 | cdce_match(device_t parent, cfdata_t match, void *aux) | |
95 | { | 95 | { | |
96 | struct usbif_attach_arg *uiaa = aux; | 96 | struct usbif_attach_arg *uiaa = aux; | |
97 | 97 | |||
98 | if (cdce_lookup(uiaa->uiaa_vendor, uiaa->uiaa_product) != NULL) | 98 | if (cdce_lookup(uiaa->uiaa_vendor, uiaa->uiaa_product) != NULL) | |
99 | return UMATCH_VENDOR_PRODUCT; | 99 | return UMATCH_VENDOR_PRODUCT; | |
100 | 100 | |||
101 | if (uiaa->uiaa_class == UICLASS_CDC && uiaa->uiaa_subclass == | 101 | if (uiaa->uiaa_class == UICLASS_CDC && uiaa->uiaa_subclass == | |
102 | UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL) | 102 | UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL) | |
103 | return UMATCH_IFACECLASS_GENERIC; | 103 | return UMATCH_IFACECLASS_GENERIC; | |
104 | 104 | |||
105 | return UMATCH_NONE; | 105 | return UMATCH_NONE; | |
106 | } | 106 | } | |
107 | 107 | |||
108 | static void | 108 | static void | |
109 | cdce_attach(device_t parent, device_t self, void *aux) | 109 | cdce_attach(device_t parent, device_t self, void *aux) | |
110 | { | 110 | { | |
111 | struct usbnet * const un = device_private(self); | 111 | struct usbnet * const un = device_private(self); | |
112 | struct usbif_attach_arg *uiaa = aux; | 112 | struct usbif_attach_arg *uiaa = aux; | |
113 | char *devinfop; | 113 | char *devinfop; | |
114 | struct usbd_device *dev = uiaa->uiaa_device; | 114 | struct usbd_device *dev = uiaa->uiaa_device; | |
115 | const struct cdce_type *t; | 115 | const struct cdce_type *t; | |
116 | usb_interface_descriptor_t *id; | 116 | usb_interface_descriptor_t *id; | |
117 | usb_endpoint_descriptor_t *ed; | 117 | usb_endpoint_descriptor_t *ed; | |
118 | const usb_cdc_union_descriptor_t *ud; | 118 | const usb_cdc_union_descriptor_t *ud; | |
119 | usb_config_descriptor_t *cd; | 119 | usb_config_descriptor_t *cd; | |
120 | int data_ifcno; | 120 | int data_ifcno; | |
121 | int i, j, numalts; | 121 | int i, j, numalts; | |
122 | const usb_cdc_ethernet_descriptor_t *ue; | 122 | const usb_cdc_ethernet_descriptor_t *ue; | |
123 | char eaddr_str[USB_MAX_ENCODED_STRING_LEN]; | 123 | char eaddr_str[USB_MAX_ENCODED_STRING_LEN]; | |
124 | 124 | |||
125 | aprint_naive("\n"); | 125 | aprint_naive("\n"); | |
126 | aprint_normal("\n"); | 126 | aprint_normal("\n"); | |
127 | devinfop = usbd_devinfo_alloc(dev, 0); | 127 | devinfop = usbd_devinfo_alloc(dev, 0); | |
128 | aprint_normal_dev(self, "%s\n", devinfop); | 128 | aprint_normal_dev(self, "%s\n", devinfop); | |
129 | usbd_devinfo_free(devinfop); | 129 | usbd_devinfo_free(devinfop); | |
130 | 130 | |||
131 | un->un_dev = self; | 131 | un->un_dev = self; | |
132 | un->un_udev = dev; | 132 | un->un_udev = dev; | |
133 | un->un_sc = un; | 133 | un->un_sc = un; | |
134 | un->un_ops = &cdce_ops; | 134 | un->un_ops = &cdce_ops; | |
135 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 135 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
136 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 136 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
137 | un->un_rx_list_cnt = CDCE_RX_LIST_CNT; | 137 | un->un_rx_list_cnt = CDCE_RX_LIST_CNT; | |
138 | un->un_tx_list_cnt = CDCE_TX_LIST_CNT; | 138 | un->un_tx_list_cnt = CDCE_TX_LIST_CNT; | |
139 | un->un_rx_bufsz = CDCE_BUFSZ; | 139 | un->un_rx_bufsz = CDCE_BUFSZ; | |
140 | un->un_tx_bufsz = CDCE_BUFSZ; | 140 | un->un_tx_bufsz = CDCE_BUFSZ; | |
141 | 141 | |||
142 | t = cdce_lookup(uiaa->uiaa_vendor, uiaa->uiaa_product); | 142 | t = cdce_lookup(uiaa->uiaa_vendor, uiaa->uiaa_product); | |
143 | if (t) | 143 | if (t) | |
144 | un->un_flags = t->cdce_flags; | 144 | un->un_flags = t->cdce_flags; | |
145 | 145 | |||
146 | if (un->un_flags & CDCE_NO_UNION) | 146 | if (un->un_flags & CDCE_NO_UNION) | |
147 | un->un_iface = uiaa->uiaa_iface; | 147 | un->un_iface = uiaa->uiaa_iface; | |
148 | else { | 148 | else { | |
149 | ud = (const usb_cdc_union_descriptor_t *)usb_find_desc_if(un->un_udev, | 149 | ud = (const usb_cdc_union_descriptor_t *)usb_find_desc_if(un->un_udev, | |
150 | UDESC_CS_INTERFACE, UDESCSUB_CDC_UNION, | 150 | UDESC_CS_INTERFACE, UDESCSUB_CDC_UNION, | |
151 | usbd_get_interface_descriptor(uiaa->uiaa_iface)); | 151 | usbd_get_interface_descriptor(uiaa->uiaa_iface)); | |
152 | if (ud == NULL) { | 152 | if (ud == NULL) { | |
153 | aprint_error_dev(self, "no union descriptor\n"); | 153 | aprint_error_dev(self, "no union descriptor\n"); | |
154 | return; | 154 | return; | |
155 | } | 155 | } | |
156 | data_ifcno = ud->bSlaveInterface[0]; | 156 | data_ifcno = ud->bSlaveInterface[0]; | |
157 | 157 | |||
158 | for (i = 0; i < uiaa->uiaa_nifaces; i++) { | 158 | for (i = 0; i < uiaa->uiaa_nifaces; i++) { | |
159 | if (uiaa->uiaa_ifaces[i] != NULL) { | 159 | if (uiaa->uiaa_ifaces[i] != NULL) { | |
160 | id = usbd_get_interface_descriptor( | 160 | id = usbd_get_interface_descriptor( | |
161 | uiaa->uiaa_ifaces[i]); | 161 | uiaa->uiaa_ifaces[i]); | |
162 | if (id != NULL && id->bInterfaceNumber == | 162 | if (id != NULL && id->bInterfaceNumber == | |
163 | data_ifcno) { | 163 | data_ifcno) { | |
164 | un->un_iface = uiaa->uiaa_ifaces[i]; | 164 | un->un_iface = uiaa->uiaa_ifaces[i]; | |
165 | uiaa->uiaa_ifaces[i] = NULL; | 165 | uiaa->uiaa_ifaces[i] = NULL; | |
166 | } | 166 | } | |
167 | } | 167 | } | |
168 | } | 168 | } | |
169 | } | 169 | } | |
170 | if (un->un_iface == NULL) { | 170 | if (un->un_iface == NULL) { | |
171 | aprint_error_dev(self, "no data interface\n"); | 171 | aprint_error_dev(self, "no data interface\n"); | |
172 | return; | 172 | return; | |
173 | } | 173 | } | |
174 | 174 | |||
175 | /* | 175 | /* | |
176 | * <quote> | 176 | * <quote> | |
177 | * The Data Class interface of a networking device shall have a minimum | 177 | * The Data Class interface of a networking device shall have a minimum | |
178 | * of two interface settings. The first setting (the default interface | 178 | * of two interface settings. The first setting (the default interface | |
179 | * setting) includes no endpoints and therefore no networking traffic is | 179 | * setting) includes no endpoints and therefore no networking traffic is | |
180 | * exchanged whenever the default interface setting is selected. One or | 180 | * exchanged whenever the default interface setting is selected. One or | |
181 | * more additional interface settings are used for normal operation, and | 181 | * more additional interface settings are used for normal operation, and | |
182 | * therefore each includes a pair of endpoints (one IN, and one OUT) to | 182 | * therefore each includes a pair of endpoints (one IN, and one OUT) to | |
183 | * exchange network traffic. Select an alternate interface setting to | 183 | * exchange network traffic. Select an alternate interface setting to | |
184 | * initialize the network aspects of the device and to enable the | 184 | * initialize the network aspects of the device and to enable the | |
185 | * exchange of network traffic. | 185 | * exchange of network traffic. | |
186 | * </quote> | 186 | * </quote> | |
187 | * | 187 | * | |
188 | * Some devices, most notably cable modems, include interface settings | 188 | * Some devices, most notably cable modems, include interface settings | |
189 | * that have no IN or OUT endpoint, therefore loop through the list of all | 189 | * that have no IN or OUT endpoint, therefore loop through the list of all | |
190 | * available interface settings looking for one with both IN and OUT | 190 | * available interface settings looking for one with both IN and OUT | |
191 | * endpoints. | 191 | * endpoints. | |
192 | */ | 192 | */ | |
193 | id = usbd_get_interface_descriptor(un->un_iface); | 193 | id = usbd_get_interface_descriptor(un->un_iface); | |
194 | cd = usbd_get_config_descriptor(un->un_udev); | 194 | cd = usbd_get_config_descriptor(un->un_udev); | |
195 | numalts = usbd_get_no_alts(cd, id->bInterfaceNumber); | 195 | numalts = usbd_get_no_alts(cd, id->bInterfaceNumber); | |
196 | 196 | |||
197 | for (j = 0; j < numalts; j++) { | 197 | for (j = 0; j < numalts; j++) { | |
198 | if (usbd_set_interface(un->un_iface, j)) { | 198 | if (usbd_set_interface(un->un_iface, j)) { | |
199 | aprint_error_dev(un->un_dev, | 199 | aprint_error_dev(un->un_dev, | |
200 | "setting alternate interface failed\n"); | 200 | "setting alternate interface failed\n"); | |
201 | return; | 201 | return; | |
202 | } | 202 | } | |
203 | /* Find endpoints. */ | 203 | /* Find endpoints. */ | |
204 | id = usbd_get_interface_descriptor(un->un_iface); | 204 | id = usbd_get_interface_descriptor(un->un_iface); | |
205 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = 0; | 205 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = 0; | |
206 | for (i = 0; i < id->bNumEndpoints; i++) { | 206 | for (i = 0; i < id->bNumEndpoints; i++) { | |
207 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 207 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
208 | if (!ed) { | 208 | if (!ed) { | |
209 | aprint_error_dev(self, | 209 | aprint_error_dev(self, | |
210 | "could not read endpoint descriptor\n"); | 210 | "could not read endpoint descriptor\n"); | |
211 | return; | 211 | return; | |
212 | } | 212 | } | |
213 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 213 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
214 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 214 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
215 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 215 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
216 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 216 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
217 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 217 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
218 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 218 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
219 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 219 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
220 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 220 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
221 | /* XXX: CDC spec defines an interrupt pipe, but it is not | 221 | /* XXX: CDC spec defines an interrupt pipe, but it is not | |
222 | * needed for simple host-to-host applications. */ | 222 | * needed for simple host-to-host applications. */ | |
223 | } else { | 223 | } else { | |
224 | aprint_error_dev(self, "unexpected endpoint\n"); | 224 | aprint_error_dev(self, "unexpected endpoint\n"); | |
225 | } | 225 | } | |
226 | } | 226 | } | |
227 | /* If we found something, try and use it... */ | 227 | /* If we found something, try and use it... */ | |
228 | if (un->un_ed[USBNET_ENDPT_RX] != 0 && un->un_ed[USBNET_ENDPT_TX] != 0) | 228 | if (un->un_ed[USBNET_ENDPT_RX] != 0 && un->un_ed[USBNET_ENDPT_TX] != 0) | |
229 | break; | 229 | break; | |
230 | } | 230 | } | |
231 | 231 | |||
232 | if (un->un_ed[USBNET_ENDPT_RX] == 0) { | 232 | if (un->un_ed[USBNET_ENDPT_RX] == 0) { | |
233 | aprint_error_dev(self, "could not find data bulk in\n"); | 233 | aprint_error_dev(self, "could not find data bulk in\n"); | |
234 | return; | 234 | return; | |
235 | } | 235 | } | |
236 | if (un->un_ed[USBNET_ENDPT_TX] == 0) { | 236 | if (un->un_ed[USBNET_ENDPT_TX] == 0) { | |
237 | aprint_error_dev(self, "could not find data bulk out\n"); | 237 | aprint_error_dev(self, "could not find data bulk out\n"); | |
238 | return; | 238 | return; | |
239 | } | 239 | } | |
240 | 240 | |||
241 | ue = (const usb_cdc_ethernet_descriptor_t *)usb_find_desc_if(dev, | 241 | ue = (const usb_cdc_ethernet_descriptor_t *)usb_find_desc_if(dev, | |
242 | UDESC_CS_INTERFACE, UDESCSUB_CDC_ENF, | 242 | UDESC_CS_INTERFACE, UDESCSUB_CDC_ENF, | |
243 | usbd_get_interface_descriptor(uiaa->uiaa_iface)); | 243 | usbd_get_interface_descriptor(uiaa->uiaa_iface)); | |
244 | if (!ue || usbd_get_string(dev, ue->iMacAddress, eaddr_str) || | 244 | if (!ue || usbd_get_string(dev, ue->iMacAddress, eaddr_str) || | |
245 | ether_aton_r(un->un_eaddr, sizeof(un->un_eaddr), eaddr_str)) { | 245 | ether_aton_r(un->un_eaddr, sizeof(un->un_eaddr), eaddr_str)) { | |
246 | aprint_normal_dev(self, "faking address\n"); | 246 | aprint_normal_dev(self, "faking address\n"); | |
247 | un->un_eaddr[0] = 0x2a; | 247 | un->un_eaddr[0] = 0x2a; | |
248 | uint32_t ticks = getticks(); | 248 | uint32_t ticks = getticks(); | |
249 | memcpy(&un->un_eaddr[1], &ticks, sizeof(ticks)); | 249 | memcpy(&un->un_eaddr[1], &ticks, sizeof(ticks)); | |
250 | un->un_eaddr[5] = (uint8_t)(device_unit(un->un_dev)); | 250 | un->un_eaddr[5] = (uint8_t)(device_unit(un->un_dev)); | |
251 | } | 251 | } | |
252 | 252 | |||
253 | usbnet_attach(un, "cdcedet"); | 253 | usbnet_attach(un, "cdcedet"); | |
254 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 254 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
255 | 0, NULL); | 255 | 0, NULL); | |
256 | } | 256 | } | |
257 | 257 | |||
258 | static int | 258 | static int | |
259 | cdce_uno_init(struct ifnet *ifp) | 259 | cdce_uno_init(struct ifnet *ifp) | |
260 | { | 260 | { | |
261 | struct usbnet *un = ifp->if_softc; | 261 | struct usbnet *un = ifp->if_softc; | |
262 | int rv; | 262 | int rv; | |
263 | 263 | |||
264 | if (usbnet_isdying(un)) | 264 | usbnet_stop(un, ifp, 1); | |
265 | rv = EIO; | 265 | rv = usbnet_init_rx_tx(un); | |
266 | else { | 266 | usbnet_set_link(un, rv == 0); | |
267 | usbnet_stop(un, ifp, 1); | |||
268 | rv = usbnet_init_rx_tx(un); | |||
269 | usbnet_set_link(un, rv == 0); | |||
270 | } | |||
271 | 267 | |||
272 | return rv; | 268 | return rv; | |
273 | } | 269 | } | |
274 | 270 | |||
275 | static void | 271 | static void | |
276 | cdce_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) | 272 | cdce_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) | |
277 | { | 273 | { | |
278 | struct ifnet *ifp = usbnet_ifp(un); | 274 | struct ifnet *ifp = usbnet_ifp(un); | |
279 | 275 | |||
280 | /* Strip off CRC added by Zaurus, if present */ | 276 | /* Strip off CRC added by Zaurus, if present */ | |
281 | if (un->un_flags & CDCE_ZAURUS && total_len > 4) | 277 | if (un->un_flags & CDCE_ZAURUS && total_len > 4) | |
282 | total_len -= 4; | 278 | total_len -= 4; | |
283 | 279 | |||
284 | if (total_len < sizeof(struct ether_header)) { | 280 | if (total_len < sizeof(struct ether_header)) { | |
285 | if_statinc(ifp, if_ierrors); | 281 | if_statinc(ifp, if_ierrors); | |
286 | return; | 282 | return; | |
287 | } | 283 | } | |
288 | 284 | |||
289 | usbnet_enqueue(un, c->unc_buf, total_len, 0, 0, 0); | 285 | usbnet_enqueue(un, c->unc_buf, total_len, 0, 0, 0); | |
290 | } | 286 | } | |
291 | 287 | |||
292 | static unsigned | 288 | static unsigned | |
293 | cdce_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 289 | cdce_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
294 | { | 290 | { | |
295 | /* Zaurus wants a 32-bit CRC appended to every frame */ | 291 | /* Zaurus wants a 32-bit CRC appended to every frame */ | |
296 | uint32_t crc; | 292 | uint32_t crc; | |
297 | unsigned extra = 0; | 293 | unsigned extra = 0; | |
298 | unsigned length; | 294 | unsigned length; | |
299 | 295 | |||
300 | if (un->un_flags & CDCE_ZAURUS) | 296 | if (un->un_flags & CDCE_ZAURUS) | |
301 | extra = sizeof(crc); | 297 | extra = sizeof(crc); | |
302 | 298 | |||
303 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - extra) | 299 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - extra) | |
304 | return 0; | 300 | return 0; | |
305 | length = m->m_pkthdr.len + extra; | 301 | length = m->m_pkthdr.len + extra; | |
306 | 302 | |||
307 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | 303 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | |
308 | if (un->un_flags & CDCE_ZAURUS) { | 304 | if (un->un_flags & CDCE_ZAURUS) { | |
309 | crc = htole32(~ether_crc32_le(c->unc_buf, m->m_pkthdr.len)); | 305 | crc = htole32(~ether_crc32_le(c->unc_buf, m->m_pkthdr.len)); | |
310 | memcpy(c->unc_buf + m->m_pkthdr.len, &crc, sizeof(crc)); | 306 | memcpy(c->unc_buf + m->m_pkthdr.len, &crc, sizeof(crc)); | |
311 | } | 307 | } | |
312 | 308 | |||
313 | return length; | 309 | return length; | |
314 | } | 310 | } | |
315 | 311 | |||
316 | #ifdef _MODULE | 312 | #ifdef _MODULE | |
317 | #include "ioconf.c" | 313 | #include "ioconf.c" | |
318 | #endif | 314 | #endif | |
319 | 315 | |||
320 | USBNET_MODULE(cdce) | 316 | USBNET_MODULE(cdce) |
--- src/sys/dev/usb/if_cue.c 2022/03/03 05:54:37 1.102
+++ src/sys/dev/usb/if_cue.c 2022/03/03 05:55:01 1.103
@@ -1,679 +1,676 @@ | @@ -1,679 +1,676 @@ | |||
1 | /* $NetBSD: if_cue.c,v 1.102 2022/03/03 05:54:37 riastradh Exp $ */ | 1 | /* $NetBSD: if_cue.c,v 1.103 2022/03/03 05:55:01 riastradh Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1997, 1998, 1999, 2000 | 4 | * Copyright (c) 1997, 1998, 1999, 2000 | |
5 | * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. | 5 | * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. All advertising materials mentioning features or use of this software | 15 | * 3. All advertising materials mentioning features or use of this software | |
16 | * must display the following acknowledgement: | 16 | * must display the following acknowledgement: | |
17 | * This product includes software developed by Bill Paul. | 17 | * This product includes software developed by Bill Paul. | |
18 | * 4. Neither the name of the author nor the names of any co-contributors | 18 | * 4. Neither the name of the author nor the names of any co-contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | |
26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
32 | * THE POSSIBILITY OF SUCH DAMAGE. | 32 | * THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | 33 | * | |
34 | * $FreeBSD: src/sys/dev/usb/if_cue.c,v 1.4 2000/01/16 22:45:06 wpaul Exp $ | 34 | * $FreeBSD: src/sys/dev/usb/if_cue.c,v 1.4 2000/01/16 22:45:06 wpaul Exp $ | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | /* | 37 | /* | |
38 | * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate | 38 | * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate | |
39 | * adapters and others. | 39 | * adapters and others. | |
40 | * | 40 | * | |
41 | * Written by Bill Paul <wpaul@ee.columbia.edu> | 41 | * Written by Bill Paul <wpaul@ee.columbia.edu> | |
42 | * Electrical Engineering Department | 42 | * Electrical Engineering Department | |
43 | * Columbia University, New York City | 43 | * Columbia University, New York City | |
44 | */ | 44 | */ | |
45 | 45 | |||
46 | /* | 46 | /* | |
47 | * The CATC USB-EL1210A provides USB ethernet support at 10Mbps. The | 47 | * The CATC USB-EL1210A provides USB ethernet support at 10Mbps. The | |
48 | * RX filter uses a 512-bit multicast hash table, single perfect entry | 48 | * RX filter uses a 512-bit multicast hash table, single perfect entry | |
49 | * for the station address, and promiscuous mode. Unlike the ADMtek | 49 | * for the station address, and promiscuous mode. Unlike the ADMtek | |
50 | * and KLSI chips, the CATC ASIC supports read and write combining | 50 | * and KLSI chips, the CATC ASIC supports read and write combining | |
51 | * mode where multiple packets can be transferred using a single bulk | 51 | * mode where multiple packets can be transferred using a single bulk | |
52 | * transaction, which helps performance a great deal. | 52 | * transaction, which helps performance a great deal. | |
53 | */ | 53 | */ | |
54 | 54 | |||
55 | /* | 55 | /* | |
56 | * Ported to NetBSD and somewhat rewritten by Lennart Augustsson. | 56 | * Ported to NetBSD and somewhat rewritten by Lennart Augustsson. | |
57 | */ | 57 | */ | |
58 | 58 | |||
59 | #include <sys/cdefs.h> | 59 | #include <sys/cdefs.h> | |
60 | __KERNEL_RCSID(0, "$NetBSD: if_cue.c,v 1.102 2022/03/03 05:54:37 riastradh Exp $"); | 60 | __KERNEL_RCSID(0, "$NetBSD: if_cue.c,v 1.103 2022/03/03 05:55:01 riastradh Exp $"); | |
61 | 61 | |||
62 | #ifdef _KERNEL_OPT | 62 | #ifdef _KERNEL_OPT | |
63 | #include "opt_inet.h" | 63 | #include "opt_inet.h" | |
64 | #include "opt_usb.h" | 64 | #include "opt_usb.h" | |
65 | #endif | 65 | #endif | |
66 | 66 | |||
67 | #include <sys/param.h> | 67 | #include <sys/param.h> | |
68 | 68 | |||
69 | #include <dev/usb/usbnet.h> | 69 | #include <dev/usb/usbnet.h> | |
70 | #include <dev/usb/if_cuereg.h> | 70 | #include <dev/usb/if_cuereg.h> | |
71 | 71 | |||
72 | #ifdef INET | 72 | #ifdef INET | |
73 | #include <netinet/in.h> | 73 | #include <netinet/in.h> | |
74 | #include <netinet/if_inarp.h> | 74 | #include <netinet/if_inarp.h> | |
75 | #endif | 75 | #endif | |
76 | 76 | |||
77 | #ifdef CUE_DEBUG | 77 | #ifdef CUE_DEBUG | |
78 | #define DPRINTF(x) if (cuedebug) printf x | 78 | #define DPRINTF(x) if (cuedebug) printf x | |
79 | #define DPRINTFN(n, x) if (cuedebug >= (n)) printf x | 79 | #define DPRINTFN(n, x) if (cuedebug >= (n)) printf x | |
80 | int cuedebug = 0; | 80 | int cuedebug = 0; | |
81 | #else | 81 | #else | |
82 | #define DPRINTF(x) | 82 | #define DPRINTF(x) | |
83 | #define DPRINTFN(n, x) | 83 | #define DPRINTFN(n, x) | |
84 | #endif | 84 | #endif | |
85 | 85 | |||
86 | #define CUE_BUFSZ 1536 | 86 | #define CUE_BUFSZ 1536 | |
87 | #define CUE_MIN_FRAMELEN 60 | 87 | #define CUE_MIN_FRAMELEN 60 | |
88 | #define CUE_RX_FRAMES 1 | 88 | #define CUE_RX_FRAMES 1 | |
89 | #define CUE_TX_FRAMES 1 | 89 | #define CUE_TX_FRAMES 1 | |
90 | 90 | |||
91 | #define CUE_CONFIG_NO 1 | 91 | #define CUE_CONFIG_NO 1 | |
92 | #define CUE_IFACE_IDX 0 | 92 | #define CUE_IFACE_IDX 0 | |
93 | 93 | |||
94 | #define CUE_RX_LIST_CNT 1 | 94 | #define CUE_RX_LIST_CNT 1 | |
95 | #define CUE_TX_LIST_CNT 1 | 95 | #define CUE_TX_LIST_CNT 1 | |
96 | 96 | |||
97 | struct cue_type { | 97 | struct cue_type { | |
98 | uint16_t cue_vid; | 98 | uint16_t cue_vid; | |
99 | uint16_t cue_did; | 99 | uint16_t cue_did; | |
100 | }; | 100 | }; | |
101 | 101 | |||
102 | struct cue_softc; | 102 | struct cue_softc; | |
103 | 103 | |||
104 | struct cue_chain { | 104 | struct cue_chain { | |
105 | struct cue_softc *cue_sc; | 105 | struct cue_softc *cue_sc; | |
106 | struct usbd_xfer *cue_xfer; | 106 | struct usbd_xfer *cue_xfer; | |
107 | char *cue_buf; | 107 | char *cue_buf; | |
108 | struct mbuf *cue_mbuf; | 108 | struct mbuf *cue_mbuf; | |
109 | int cue_idx; | 109 | int cue_idx; | |
110 | }; | 110 | }; | |
111 | 111 | |||
112 | struct cue_cdata { | 112 | struct cue_cdata { | |
113 | struct cue_chain cue_tx_chain[CUE_TX_LIST_CNT]; | 113 | struct cue_chain cue_tx_chain[CUE_TX_LIST_CNT]; | |
114 | struct cue_chain cue_rx_chain[CUE_RX_LIST_CNT]; | 114 | struct cue_chain cue_rx_chain[CUE_RX_LIST_CNT]; | |
115 | int cue_tx_prod; | 115 | int cue_tx_prod; | |
116 | int cue_tx_cnt; | 116 | int cue_tx_cnt; | |
117 | }; | 117 | }; | |
118 | 118 | |||
119 | struct cue_softc { | 119 | struct cue_softc { | |
120 | struct usbnet cue_un; | 120 | struct usbnet cue_un; | |
121 | uint8_t cue_mctab[CUE_MCAST_TABLE_LEN]; | 121 | uint8_t cue_mctab[CUE_MCAST_TABLE_LEN]; | |
122 | }; | 122 | }; | |
123 | 123 | |||
124 | /* | 124 | /* | |
125 | * Various supported device vendors/products. | 125 | * Various supported device vendors/products. | |
126 | */ | 126 | */ | |
127 | static const struct usb_devno cue_devs[] = { | 127 | static const struct usb_devno cue_devs[] = { | |
128 | { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE }, | 128 | { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE }, | |
129 | { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE2 }, | 129 | { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE2 }, | |
130 | { USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTLINK }, | 130 | { USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTLINK }, | |
131 | /* Belkin F5U111 adapter covered by NETMATE entry */ | 131 | /* Belkin F5U111 adapter covered by NETMATE entry */ | |
132 | }; | 132 | }; | |
133 | #define cue_lookup(v, p) (usb_lookup(cue_devs, v, p)) | 133 | #define cue_lookup(v, p) (usb_lookup(cue_devs, v, p)) | |
134 | 134 | |||
135 | static int cue_match(device_t, cfdata_t, void *); | 135 | static int cue_match(device_t, cfdata_t, void *); | |
136 | static void cue_attach(device_t, device_t, void *); | 136 | static void cue_attach(device_t, device_t, void *); | |
137 | 137 | |||
138 | CFATTACH_DECL_NEW(cue, sizeof(struct cue_softc), cue_match, cue_attach, | 138 | CFATTACH_DECL_NEW(cue, sizeof(struct cue_softc), cue_match, cue_attach, | |
139 | usbnet_detach, usbnet_activate); | 139 | usbnet_detach, usbnet_activate); | |
140 | 140 | |||
141 | static unsigned cue_uno_tx_prepare(struct usbnet *, struct mbuf *, | 141 | static unsigned cue_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
142 | struct usbnet_chain *); | 142 | struct usbnet_chain *); | |
143 | static void cue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 143 | static void cue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
144 | static void cue_uno_mcast(struct ifnet *); | 144 | static void cue_uno_mcast(struct ifnet *); | |
145 | static void cue_uno_stop(struct ifnet *, int); | 145 | static void cue_uno_stop(struct ifnet *, int); | |
146 | static int cue_uno_init(struct ifnet *); | 146 | static int cue_uno_init(struct ifnet *); | |
147 | static void cue_uno_tick(struct usbnet *); | 147 | static void cue_uno_tick(struct usbnet *); | |
148 | 148 | |||
149 | static const struct usbnet_ops cue_ops = { | 149 | static const struct usbnet_ops cue_ops = { | |
150 | .uno_stop = cue_uno_stop, | 150 | .uno_stop = cue_uno_stop, | |
151 | .uno_mcast = cue_uno_mcast, | 151 | .uno_mcast = cue_uno_mcast, | |
152 | .uno_tx_prepare = cue_uno_tx_prepare, | 152 | .uno_tx_prepare = cue_uno_tx_prepare, | |
153 | .uno_rx_loop = cue_uno_rx_loop, | 153 | .uno_rx_loop = cue_uno_rx_loop, | |
154 | .uno_init = cue_uno_init, | 154 | .uno_init = cue_uno_init, | |
155 | .uno_tick = cue_uno_tick, | 155 | .uno_tick = cue_uno_tick, | |
156 | }; | 156 | }; | |
157 | 157 | |||
158 | #ifdef CUE_DEBUG | 158 | #ifdef CUE_DEBUG | |
159 | static int | 159 | static int | |
160 | cue_csr_read_1(struct usbnet *un, int reg) | 160 | cue_csr_read_1(struct usbnet *un, int reg) | |
161 | { | 161 | { | |
162 | usb_device_request_t req; | 162 | usb_device_request_t req; | |
163 | usbd_status err; | 163 | usbd_status err; | |
164 | uint8_t val = 0; | 164 | uint8_t val = 0; | |
165 | 165 | |||
166 | if (usbnet_isdying(un)) | 166 | if (usbnet_isdying(un)) | |
167 | return 0; | 167 | return 0; | |
168 | 168 | |||
169 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 169 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
170 | req.bRequest = CUE_CMD_READREG; | 170 | req.bRequest = CUE_CMD_READREG; | |
171 | USETW(req.wValue, 0); | 171 | USETW(req.wValue, 0); | |
172 | USETW(req.wIndex, reg); | 172 | USETW(req.wIndex, reg); | |
173 | USETW(req.wLength, 1); | 173 | USETW(req.wLength, 1); | |
174 | 174 | |||
175 | err = usbd_do_request(un->un_udev, &req, &val); | 175 | err = usbd_do_request(un->un_udev, &req, &val); | |
176 | 176 | |||
177 | if (err) { | 177 | if (err) { | |
178 | DPRINTF(("%s: cue_csr_read_1: reg=%#x err=%s\n", | 178 | DPRINTF(("%s: cue_csr_read_1: reg=%#x err=%s\n", | |
179 | device_xname(un->un_dev), reg, usbd_errstr(err))); | 179 | device_xname(un->un_dev), reg, usbd_errstr(err))); | |
180 | return 0; | 180 | return 0; | |
181 | } | 181 | } | |
182 | 182 | |||
183 | DPRINTFN(10,("%s: cue_csr_read_1 reg=%#x val=%#x\n", | 183 | DPRINTFN(10,("%s: cue_csr_read_1 reg=%#x val=%#x\n", | |
184 | device_xname(un->un_dev), reg, val)); | 184 | device_xname(un->un_dev), reg, val)); | |
185 | 185 | |||
186 | return val; | 186 | return val; | |
187 | } | 187 | } | |
188 | #endif | 188 | #endif | |
189 | 189 | |||
190 | static int | 190 | static int | |
191 | cue_csr_read_2(struct usbnet *un, int reg) | 191 | cue_csr_read_2(struct usbnet *un, int reg) | |
192 | { | 192 | { | |
193 | usb_device_request_t req; | 193 | usb_device_request_t req; | |
194 | usbd_status err; | 194 | usbd_status err; | |
195 | uWord val; | 195 | uWord val; | |
196 | 196 | |||
197 | if (usbnet_isdying(un)) | 197 | if (usbnet_isdying(un)) | |
198 | return 0; | 198 | return 0; | |
199 | 199 | |||
200 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 200 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
201 | req.bRequest = CUE_CMD_READREG; | 201 | req.bRequest = CUE_CMD_READREG; | |
202 | USETW(req.wValue, 0); | 202 | USETW(req.wValue, 0); | |
203 | USETW(req.wIndex, reg); | 203 | USETW(req.wIndex, reg); | |
204 | USETW(req.wLength, 2); | 204 | USETW(req.wLength, 2); | |
205 | 205 | |||
206 | err = usbd_do_request(un->un_udev, &req, &val); | 206 | err = usbd_do_request(un->un_udev, &req, &val); | |
207 | 207 | |||
208 | DPRINTFN(10,("%s: cue_csr_read_2 reg=%#x val=%#x\n", | 208 | DPRINTFN(10,("%s: cue_csr_read_2 reg=%#x val=%#x\n", | |
209 | device_xname(un->un_dev), reg, UGETW(val))); | 209 | device_xname(un->un_dev), reg, UGETW(val))); | |
210 | 210 | |||
211 | if (err) { | 211 | if (err) { | |
212 | DPRINTF(("%s: cue_csr_read_2: reg=%#x err=%s\n", | 212 | DPRINTF(("%s: cue_csr_read_2: reg=%#x err=%s\n", | |
213 | device_xname(un->un_dev), reg, usbd_errstr(err))); | 213 | device_xname(un->un_dev), reg, usbd_errstr(err))); | |
214 | return 0; | 214 | return 0; | |
215 | } | 215 | } | |
216 | 216 | |||
217 | return UGETW(val); | 217 | return UGETW(val); | |
218 | } | 218 | } | |
219 | 219 | |||
220 | static int | 220 | static int | |
221 | cue_csr_write_1(struct usbnet *un, int reg, int val) | 221 | cue_csr_write_1(struct usbnet *un, int reg, int val) | |
222 | { | 222 | { | |
223 | usb_device_request_t req; | 223 | usb_device_request_t req; | |
224 | usbd_status err; | 224 | usbd_status err; | |
225 | 225 | |||
226 | if (usbnet_isdying(un)) | 226 | if (usbnet_isdying(un)) | |
227 | return 0; | 227 | return 0; | |
228 | 228 | |||
229 | DPRINTFN(10,("%s: cue_csr_write_1 reg=%#x val=%#x\n", | 229 | DPRINTFN(10,("%s: cue_csr_write_1 reg=%#x val=%#x\n", | |
230 | device_xname(un->un_dev), reg, val)); | 230 | device_xname(un->un_dev), reg, val)); | |
231 | 231 | |||
232 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 232 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
233 | req.bRequest = CUE_CMD_WRITEREG; | 233 | req.bRequest = CUE_CMD_WRITEREG; | |
234 | USETW(req.wValue, val); | 234 | USETW(req.wValue, val); | |
235 | USETW(req.wIndex, reg); | 235 | USETW(req.wIndex, reg); | |
236 | USETW(req.wLength, 0); | 236 | USETW(req.wLength, 0); | |
237 | 237 | |||
238 | err = usbd_do_request(un->un_udev, &req, NULL); | 238 | err = usbd_do_request(un->un_udev, &req, NULL); | |
239 | 239 | |||
240 | if (err) { | 240 | if (err) { | |
241 | DPRINTF(("%s: cue_csr_write_1: reg=%#x err=%s\n", | 241 | DPRINTF(("%s: cue_csr_write_1: reg=%#x err=%s\n", | |
242 | device_xname(un->un_dev), reg, usbd_errstr(err))); | 242 | device_xname(un->un_dev), reg, usbd_errstr(err))); | |
243 | return -1; | 243 | return -1; | |
244 | } | 244 | } | |
245 | 245 | |||
246 | DPRINTFN(20,("%s: cue_csr_write_1, after reg=%#x val=%#x\n", | 246 | DPRINTFN(20,("%s: cue_csr_write_1, after reg=%#x val=%#x\n", | |
247 | device_xname(un->un_dev), reg, cue_csr_read_1(un, reg))); | 247 | device_xname(un->un_dev), reg, cue_csr_read_1(un, reg))); | |
248 | 248 | |||
249 | return 0; | 249 | return 0; | |
250 | } | 250 | } | |
251 | 251 | |||
252 | #if 0 | 252 | #if 0 | |
253 | static int | 253 | static int | |
254 | cue_csr_write_2(struct usbnet *un, int reg, int aval) | 254 | cue_csr_write_2(struct usbnet *un, int reg, int aval) | |
255 | { | 255 | { | |
256 | usb_device_request_t req; | 256 | usb_device_request_t req; | |
257 | usbd_status err; | 257 | usbd_status err; | |
258 | uWord val; | 258 | uWord val; | |
259 | int s; | 259 | int s; | |
260 | 260 | |||
261 | if (usbnet_isdying(un)) | 261 | if (usbnet_isdying(un)) | |
262 | return 0; | 262 | return 0; | |
263 | 263 | |||
264 | DPRINTFN(10,("%s: cue_csr_write_2 reg=%#x val=%#x\n", | 264 | DPRINTFN(10,("%s: cue_csr_write_2 reg=%#x val=%#x\n", | |
265 | device_xname(un->un_dev), reg, aval)); | 265 | device_xname(un->un_dev), reg, aval)); | |
266 | 266 | |||
267 | USETW(val, aval); | 267 | USETW(val, aval); | |
268 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 268 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
269 | req.bRequest = CUE_CMD_WRITEREG; | 269 | req.bRequest = CUE_CMD_WRITEREG; | |
270 | USETW(req.wValue, val); | 270 | USETW(req.wValue, val); | |
271 | USETW(req.wIndex, reg); | 271 | USETW(req.wIndex, reg); | |
272 | USETW(req.wLength, 0); | 272 | USETW(req.wLength, 0); | |
273 | 273 | |||
274 | err = usbd_do_request(un->un_udev, &req, NULL); | 274 | err = usbd_do_request(un->un_udev, &req, NULL); | |
275 | 275 | |||
276 | if (err) { | 276 | if (err) { | |
277 | DPRINTF(("%s: cue_csr_write_2: reg=%#x err=%s\n", | 277 | DPRINTF(("%s: cue_csr_write_2: reg=%#x err=%s\n", | |
278 | device_xname(un->un_dev), reg, usbd_errstr(err))); | 278 | device_xname(un->un_dev), reg, usbd_errstr(err))); | |
279 | return -1; | 279 | return -1; | |
280 | } | 280 | } | |
281 | 281 | |||
282 | return 0; | 282 | return 0; | |
283 | } | 283 | } | |
284 | #endif | 284 | #endif | |
285 | 285 | |||
286 | static int | 286 | static int | |
287 | cue_mem(struct usbnet *un, int cmd, int addr, void *buf, int len) | 287 | cue_mem(struct usbnet *un, int cmd, int addr, void *buf, int len) | |
288 | { | 288 | { | |
289 | usb_device_request_t req; | 289 | usb_device_request_t req; | |
290 | usbd_status err; | 290 | usbd_status err; | |
291 | 291 | |||
292 | DPRINTFN(10,("%s: cue_mem cmd=%#x addr=%#x len=%d\n", | 292 | DPRINTFN(10,("%s: cue_mem cmd=%#x addr=%#x len=%d\n", | |
293 | device_xname(un->un_dev), cmd, addr, len)); | 293 | device_xname(un->un_dev), cmd, addr, len)); | |
294 | 294 | |||
295 | if (cmd == CUE_CMD_READSRAM) | 295 | if (cmd == CUE_CMD_READSRAM) | |
296 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 296 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
297 | else | 297 | else | |
298 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 298 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
299 | req.bRequest = cmd; | 299 | req.bRequest = cmd; | |
300 | USETW(req.wValue, 0); | 300 | USETW(req.wValue, 0); | |
301 | USETW(req.wIndex, addr); | 301 | USETW(req.wIndex, addr); | |
302 | USETW(req.wLength, len); | 302 | USETW(req.wLength, len); | |
303 | 303 | |||
304 | err = usbd_do_request(un->un_udev, &req, buf); | 304 | err = usbd_do_request(un->un_udev, &req, buf); | |
305 | 305 | |||
306 | if (err) { | 306 | if (err) { | |
307 | DPRINTF(("%s: cue_csr_mem: addr=%#x err=%s\n", | 307 | DPRINTF(("%s: cue_csr_mem: addr=%#x err=%s\n", | |
308 | device_xname(un->un_dev), addr, usbd_errstr(err))); | 308 | device_xname(un->un_dev), addr, usbd_errstr(err))); | |
309 | return -1; | 309 | return -1; | |
310 | } | 310 | } | |
311 | 311 | |||
312 | return 0; | 312 | return 0; | |
313 | } | 313 | } | |
314 | 314 | |||
315 | static int | 315 | static int | |
316 | cue_getmac(struct usbnet *un) | 316 | cue_getmac(struct usbnet *un) | |
317 | { | 317 | { | |
318 | usb_device_request_t req; | 318 | usb_device_request_t req; | |
319 | usbd_status err; | 319 | usbd_status err; | |
320 | 320 | |||
321 | DPRINTFN(10,("%s: cue_getmac\n", device_xname(un->un_dev))); | 321 | DPRINTFN(10,("%s: cue_getmac\n", device_xname(un->un_dev))); | |
322 | 322 | |||
323 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 323 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
324 | req.bRequest = CUE_CMD_GET_MACADDR; | 324 | req.bRequest = CUE_CMD_GET_MACADDR; | |
325 | USETW(req.wValue, 0); | 325 | USETW(req.wValue, 0); | |
326 | USETW(req.wIndex, 0); | 326 | USETW(req.wIndex, 0); | |
327 | USETW(req.wLength, ETHER_ADDR_LEN); | 327 | USETW(req.wLength, ETHER_ADDR_LEN); | |
328 | 328 | |||
329 | err = usbd_do_request(un->un_udev, &req, un->un_eaddr); | 329 | err = usbd_do_request(un->un_udev, &req, un->un_eaddr); | |
330 | 330 | |||
331 | if (err) { | 331 | if (err) { | |
332 | printf("%s: read MAC address failed\n", | 332 | printf("%s: read MAC address failed\n", | |
333 | device_xname(un->un_dev)); | 333 | device_xname(un->un_dev)); | |
334 | return -1; | 334 | return -1; | |
335 | } | 335 | } | |
336 | 336 | |||
337 | return 0; | 337 | return 0; | |
338 | } | 338 | } | |
339 | 339 | |||
340 | #define CUE_POLY 0xEDB88320 | 340 | #define CUE_POLY 0xEDB88320 | |
341 | #define CUE_BITS 9 | 341 | #define CUE_BITS 9 | |
342 | 342 | |||
343 | static uint32_t | 343 | static uint32_t | |
344 | cue_crc(const char *addr) | 344 | cue_crc(const char *addr) | |
345 | { | 345 | { | |
346 | uint32_t idx, bit, data, crc; | 346 | uint32_t idx, bit, data, crc; | |
347 | 347 | |||
348 | /* Compute CRC for the address value. */ | 348 | /* Compute CRC for the address value. */ | |
349 | crc = 0xFFFFFFFF; /* initial value */ | 349 | crc = 0xFFFFFFFF; /* initial value */ | |
350 | 350 | |||
351 | for (idx = 0; idx < 6; idx++) { | 351 | for (idx = 0; idx < 6; idx++) { | |
352 | for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) | 352 | for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) | |
353 | crc = (crc >> 1) ^ (((crc ^ data) & 1) ? CUE_POLY : 0); | 353 | crc = (crc >> 1) ^ (((crc ^ data) & 1) ? CUE_POLY : 0); | |
354 | } | 354 | } | |
355 | 355 | |||
356 | return crc & ((1 << CUE_BITS) - 1); | 356 | return crc & ((1 << CUE_BITS) - 1); | |
357 | } | 357 | } | |
358 | 358 | |||
359 | static void | 359 | static void | |
360 | cue_uno_mcast(struct ifnet *ifp) | 360 | cue_uno_mcast(struct ifnet *ifp) | |
361 | { | 361 | { | |
362 | struct usbnet *un = ifp->if_softc; | 362 | struct usbnet *un = ifp->if_softc; | |
363 | struct cue_softc *sc = usbnet_softc(un); | 363 | struct cue_softc *sc = usbnet_softc(un); | |
364 | struct ethercom *ec = usbnet_ec(un); | 364 | struct ethercom *ec = usbnet_ec(un); | |
365 | struct ether_multi *enm; | 365 | struct ether_multi *enm; | |
366 | struct ether_multistep step; | 366 | struct ether_multistep step; | |
367 | uint32_t h, i; | 367 | uint32_t h, i; | |
368 | 368 | |||
369 | DPRINTFN(2,("%s: cue_setiff if_flags=%#x\n", | 369 | DPRINTFN(2,("%s: cue_setiff if_flags=%#x\n", | |
370 | device_xname(un->un_dev), ifp->if_flags)); | 370 | device_xname(un->un_dev), ifp->if_flags)); | |
371 | 371 | |||
372 | if (ifp->if_flags & IFF_PROMISC) { | 372 | if (ifp->if_flags & IFF_PROMISC) { | |
373 | ETHER_LOCK(ec); | 373 | ETHER_LOCK(ec); | |
374 | allmulti: | 374 | allmulti: | |
375 | ec->ec_flags |= ETHER_F_ALLMULTI; | 375 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
376 | ETHER_UNLOCK(ec); | 376 | ETHER_UNLOCK(ec); | |
377 | for (i = 0; i < CUE_MCAST_TABLE_LEN; i++) | 377 | for (i = 0; i < CUE_MCAST_TABLE_LEN; i++) | |
378 | sc->cue_mctab[i] = 0xFF; | 378 | sc->cue_mctab[i] = 0xFF; | |
379 | cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, | 379 | cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, | |
380 | &sc->cue_mctab, CUE_MCAST_TABLE_LEN); | 380 | &sc->cue_mctab, CUE_MCAST_TABLE_LEN); | |
381 | return; | 381 | return; | |
382 | } | 382 | } | |
383 | 383 | |||
384 | /* first, zot all the existing hash bits */ | 384 | /* first, zot all the existing hash bits */ | |
385 | for (i = 0; i < CUE_MCAST_TABLE_LEN; i++) | 385 | for (i = 0; i < CUE_MCAST_TABLE_LEN; i++) | |
386 | sc->cue_mctab[i] = 0; | 386 | sc->cue_mctab[i] = 0; | |
387 | 387 | |||
388 | /* now program new ones */ | 388 | /* now program new ones */ | |
389 | ETHER_LOCK(ec); | 389 | ETHER_LOCK(ec); | |
390 | ETHER_FIRST_MULTI(step, ec, enm); | 390 | ETHER_FIRST_MULTI(step, ec, enm); | |
391 | while (enm != NULL) { | 391 | while (enm != NULL) { | |
392 | if (memcmp(enm->enm_addrlo, | 392 | if (memcmp(enm->enm_addrlo, | |
393 | enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { | 393 | enm->enm_addrhi, ETHER_ADDR_LEN) != 0) { | |
394 | goto allmulti; | 394 | goto allmulti; | |
395 | } | 395 | } | |
396 | 396 | |||
397 | h = cue_crc(enm->enm_addrlo); | 397 | h = cue_crc(enm->enm_addrlo); | |
398 | sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); | 398 | sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); | |
399 | ETHER_NEXT_MULTI(step, enm); | 399 | ETHER_NEXT_MULTI(step, enm); | |
400 | } | 400 | } | |
401 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 401 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
402 | ETHER_UNLOCK(ec); | 402 | ETHER_UNLOCK(ec); | |
403 | 403 | |||
404 | /* | 404 | /* | |
405 | * Also include the broadcast address in the filter | 405 | * Also include the broadcast address in the filter | |
406 | * so we can receive broadcast frames. | 406 | * so we can receive broadcast frames. | |
407 | */ | 407 | */ | |
408 | if (ifp->if_flags & IFF_BROADCAST) { | 408 | if (ifp->if_flags & IFF_BROADCAST) { | |
409 | h = cue_crc(etherbroadcastaddr); | 409 | h = cue_crc(etherbroadcastaddr); | |
410 | sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); | 410 | sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); | |
411 | } | 411 | } | |
412 | 412 | |||
413 | cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, | 413 | cue_mem(un, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, | |
414 | &sc->cue_mctab, CUE_MCAST_TABLE_LEN); | 414 | &sc->cue_mctab, CUE_MCAST_TABLE_LEN); | |
415 | } | 415 | } | |
416 | 416 | |||
417 | static void | 417 | static void | |
418 | cue_reset(struct usbnet *un) | 418 | cue_reset(struct usbnet *un) | |
419 | { | 419 | { | |
420 | usb_device_request_t req; | 420 | usb_device_request_t req; | |
421 | usbd_status err; | 421 | usbd_status err; | |
422 | 422 | |||
423 | DPRINTFN(2,("%s: cue_reset\n", device_xname(un->un_dev))); | 423 | DPRINTFN(2,("%s: cue_reset\n", device_xname(un->un_dev))); | |
424 | 424 | |||
425 | if (usbnet_isdying(un)) | 425 | if (usbnet_isdying(un)) | |
426 | return; | 426 | return; | |
427 | 427 | |||
428 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 428 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
429 | req.bRequest = CUE_CMD_RESET; | 429 | req.bRequest = CUE_CMD_RESET; | |
430 | USETW(req.wValue, 0); | 430 | USETW(req.wValue, 0); | |
431 | USETW(req.wIndex, 0); | 431 | USETW(req.wIndex, 0); | |
432 | USETW(req.wLength, 0); | 432 | USETW(req.wLength, 0); | |
433 | 433 | |||
434 | err = usbd_do_request(un->un_udev, &req, NULL); | 434 | err = usbd_do_request(un->un_udev, &req, NULL); | |
435 | 435 | |||
436 | if (err) | 436 | if (err) | |
437 | printf("%s: reset failed\n", device_xname(un->un_dev)); | 437 | printf("%s: reset failed\n", device_xname(un->un_dev)); | |
438 | 438 | |||
439 | /* Wait a little while for the chip to get its brains in order. */ | 439 | /* Wait a little while for the chip to get its brains in order. */ | |
440 | usbd_delay_ms(un->un_udev, 1); | 440 | usbd_delay_ms(un->un_udev, 1); | |
441 | } | 441 | } | |
442 | 442 | |||
443 | /* | 443 | /* | |
444 | * Probe for a CATC chip. | 444 | * Probe for a CATC chip. | |
445 | */ | 445 | */ | |
446 | static int | 446 | static int | |
447 | cue_match(device_t parent, cfdata_t match, void *aux) | 447 | cue_match(device_t parent, cfdata_t match, void *aux) | |
448 | { | 448 | { | |
449 | struct usb_attach_arg *uaa = aux; | 449 | struct usb_attach_arg *uaa = aux; | |
450 | 450 | |||
451 | return cue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 451 | return cue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
452 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 452 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
453 | } | 453 | } | |
454 | 454 | |||
455 | /* | 455 | /* | |
456 | * Attach the interface. Allocate softc structures, do ifmedia | 456 | * Attach the interface. Allocate softc structures, do ifmedia | |
457 | * setup and ethernet/BPF attach. | 457 | * setup and ethernet/BPF attach. | |
458 | */ | 458 | */ | |
459 | static void | 459 | static void | |
460 | cue_attach(device_t parent, device_t self, void *aux) | 460 | cue_attach(device_t parent, device_t self, void *aux) | |
461 | { | 461 | { | |
462 | struct cue_softc *sc = device_private(self); | 462 | struct cue_softc *sc = device_private(self); | |
463 | struct usbnet * const un = &sc->cue_un; | 463 | struct usbnet * const un = &sc->cue_un; | |
464 | struct usb_attach_arg *uaa = aux; | 464 | struct usb_attach_arg *uaa = aux; | |
465 | char *devinfop; | 465 | char *devinfop; | |
466 | struct usbd_device * dev = uaa->uaa_device; | 466 | struct usbd_device * dev = uaa->uaa_device; | |
467 | usbd_status err; | 467 | usbd_status err; | |
468 | usb_interface_descriptor_t *id; | 468 | usb_interface_descriptor_t *id; | |
469 | usb_endpoint_descriptor_t *ed; | 469 | usb_endpoint_descriptor_t *ed; | |
470 | int i; | 470 | int i; | |
471 | 471 | |||
472 | KASSERT((void *)sc == un); | 472 | KASSERT((void *)sc == un); | |
473 | 473 | |||
474 | DPRINTFN(5,(" : cue_attach: sc=%p, dev=%p", sc, dev)); | 474 | DPRINTFN(5,(" : cue_attach: sc=%p, dev=%p", sc, dev)); | |
475 | 475 | |||
476 | aprint_naive("\n"); | 476 | aprint_naive("\n"); | |
477 | aprint_normal("\n"); | 477 | aprint_normal("\n"); | |
478 | devinfop = usbd_devinfo_alloc(dev, 0); | 478 | devinfop = usbd_devinfo_alloc(dev, 0); | |
479 | aprint_normal_dev(self, "%s\n", devinfop); | 479 | aprint_normal_dev(self, "%s\n", devinfop); | |
480 | usbd_devinfo_free(devinfop); | 480 | usbd_devinfo_free(devinfop); | |
481 | 481 | |||
482 | err = usbd_set_config_no(dev, CUE_CONFIG_NO, 1); | 482 | err = usbd_set_config_no(dev, CUE_CONFIG_NO, 1); | |
483 | if (err) { | 483 | if (err) { | |
484 | aprint_error_dev(self, "failed to set configuration" | 484 | aprint_error_dev(self, "failed to set configuration" | |
485 | ", err=%s\n", usbd_errstr(err)); | 485 | ", err=%s\n", usbd_errstr(err)); | |
486 | return; | 486 | return; | |
487 | } | 487 | } | |
488 | 488 | |||
489 | un->un_dev = self; | 489 | un->un_dev = self; | |
490 | un->un_udev = dev; | 490 | un->un_udev = dev; | |
491 | un->un_sc = sc; | 491 | un->un_sc = sc; | |
492 | un->un_ops = &cue_ops; | 492 | un->un_ops = &cue_ops; | |
493 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 493 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
494 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 494 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
495 | un->un_rx_list_cnt = CUE_RX_LIST_CNT; | 495 | un->un_rx_list_cnt = CUE_RX_LIST_CNT; | |
496 | un->un_tx_list_cnt = CUE_TX_LIST_CNT; | 496 | un->un_tx_list_cnt = CUE_TX_LIST_CNT; | |
497 | un->un_rx_bufsz = CUE_BUFSZ; | 497 | un->un_rx_bufsz = CUE_BUFSZ; | |
498 | un->un_tx_bufsz = CUE_BUFSZ; | 498 | un->un_tx_bufsz = CUE_BUFSZ; | |
499 | 499 | |||
500 | err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &un->un_iface); | 500 | err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &un->un_iface); | |
501 | if (err) { | 501 | if (err) { | |
502 | aprint_error_dev(self, "getting interface handle failed\n"); | 502 | aprint_error_dev(self, "getting interface handle failed\n"); | |
503 | return; | 503 | return; | |
504 | } | 504 | } | |
505 | 505 | |||
506 | id = usbd_get_interface_descriptor(un->un_iface); | 506 | id = usbd_get_interface_descriptor(un->un_iface); | |
507 | 507 | |||
508 | /* Find endpoints. */ | 508 | /* Find endpoints. */ | |
509 | for (i = 0; i < id->bNumEndpoints; i++) { | 509 | for (i = 0; i < id->bNumEndpoints; i++) { | |
510 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 510 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
511 | if (ed == NULL) { | 511 | if (ed == NULL) { | |
512 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 512 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
513 | return; | 513 | return; | |
514 | } | 514 | } | |
515 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 515 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
516 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 516 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
517 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 517 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
518 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 518 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
519 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 519 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
520 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 520 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
521 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 521 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
522 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 522 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
523 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 523 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
524 | } | 524 | } | |
525 | } | 525 | } | |
526 | 526 | |||
527 | /* First level attach. */ | 527 | /* First level attach. */ | |
528 | usbnet_attach(un, "cuedet"); | 528 | usbnet_attach(un, "cuedet"); | |
529 | 529 | |||
530 | #if 0 | 530 | #if 0 | |
531 | /* Reset the adapter. */ | 531 | /* Reset the adapter. */ | |
532 | cue_reset(un); | 532 | cue_reset(un); | |
533 | #endif | 533 | #endif | |
534 | /* | 534 | /* | |
535 | * Get station address. | 535 | * Get station address. | |
536 | */ | 536 | */ | |
537 | cue_getmac(un); | 537 | cue_getmac(un); | |
538 | 538 | |||
539 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 539 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
540 | 0, NULL); | 540 | 0, NULL); | |
541 | } | 541 | } | |
542 | 542 | |||
543 | static void | 543 | static void | |
544 | cue_uno_tick(struct usbnet *un) | 544 | cue_uno_tick(struct usbnet *un) | |
545 | { | 545 | { | |
546 | struct ifnet *ifp = usbnet_ifp(un); | 546 | struct ifnet *ifp = usbnet_ifp(un); | |
547 | 547 | |||
548 | net_stat_ref_t nsr = IF_STAT_GETREF(ifp); | 548 | net_stat_ref_t nsr = IF_STAT_GETREF(ifp); | |
549 | if (cue_csr_read_2(un, CUE_RX_FRAMEERR)) | 549 | if (cue_csr_read_2(un, CUE_RX_FRAMEERR)) | |
550 | if_statinc_ref(nsr, if_ierrors); | 550 | if_statinc_ref(nsr, if_ierrors); | |
551 | 551 | |||
552 | if_statadd_ref(nsr, if_collisions, | 552 | if_statadd_ref(nsr, if_collisions, | |
553 | cue_csr_read_2(un, CUE_TX_SINGLECOLL)); | 553 | cue_csr_read_2(un, CUE_TX_SINGLECOLL)); | |
554 | if_statadd_ref(nsr, if_collisions, | 554 | if_statadd_ref(nsr, if_collisions, | |
555 | cue_csr_read_2(un, CUE_TX_MULTICOLL)); | 555 | cue_csr_read_2(un, CUE_TX_MULTICOLL)); | |
556 | if_statadd_ref(nsr, if_collisions, | 556 | if_statadd_ref(nsr, if_collisions, | |
557 | cue_csr_read_2(un, CUE_TX_EXCESSCOLL)); | 557 | cue_csr_read_2(un, CUE_TX_EXCESSCOLL)); | |
558 | IF_STAT_PUTREF(ifp); | 558 | IF_STAT_PUTREF(ifp); | |
559 | } | 559 | } | |
560 | 560 | |||
561 | static void | 561 | static void | |
562 | cue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 562 | cue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
563 | { | 563 | { | |
564 | struct ifnet *ifp = usbnet_ifp(un); | 564 | struct ifnet *ifp = usbnet_ifp(un); | |
565 | uint8_t *buf = c->unc_buf; | 565 | uint8_t *buf = c->unc_buf; | |
566 | uint16_t len; | 566 | uint16_t len; | |
567 | 567 | |||
568 | DPRINTFN(5,("%s: %s: total_len=%d len=%d\n", | 568 | DPRINTFN(5,("%s: %s: total_len=%d len=%d\n", | |
569 | device_xname(un->un_dev), __func__, | 569 | device_xname(un->un_dev), __func__, | |
570 | total_len, le16dec(buf))); | 570 | total_len, le16dec(buf))); | |
571 | 571 | |||
572 | len = UGETW(buf); | 572 | len = UGETW(buf); | |
573 | if (total_len < 2 || | 573 | if (total_len < 2 || | |
574 | len > total_len - 2 || | 574 | len > total_len - 2 || | |
575 | len < sizeof(struct ether_header)) { | 575 | len < sizeof(struct ether_header)) { | |
576 | if_statinc(ifp, if_ierrors); | 576 | if_statinc(ifp, if_ierrors); | |
577 | return; | 577 | return; | |
578 | } | 578 | } | |
579 | 579 | |||
580 | /* No errors; receive the packet. */ | 580 | /* No errors; receive the packet. */ | |
581 | usbnet_enqueue(un, buf + 2, len, 0, 0, 0); | 581 | usbnet_enqueue(un, buf + 2, len, 0, 0, 0); | |
582 | } | 582 | } | |
583 | 583 | |||
584 | static unsigned | 584 | static unsigned | |
585 | cue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 585 | cue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
586 | { | 586 | { | |
587 | unsigned total_len; | 587 | unsigned total_len; | |
588 | 588 | |||
589 | DPRINTFN(5,("%s: %s: mbuf len=%d\n", | 589 | DPRINTFN(5,("%s: %s: mbuf len=%d\n", | |
590 | device_xname(un->un_dev), __func__, | 590 | device_xname(un->un_dev), __func__, | |
591 | m->m_pkthdr.len)); | 591 | m->m_pkthdr.len)); | |
592 | 592 | |||
593 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | 593 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | |
594 | return 0; | 594 | return 0; | |
595 | 595 | |||
596 | /* | 596 | /* | |
597 | * Copy the mbuf data into a contiguous buffer, leaving two | 597 | * Copy the mbuf data into a contiguous buffer, leaving two | |
598 | * bytes at the beginning to hold the frame length. | 598 | * bytes at the beginning to hold the frame length. | |
599 | */ | 599 | */ | |
600 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + 2); | 600 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + 2); | |
601 | 601 | |||
602 | total_len = m->m_pkthdr.len + 2; | 602 | total_len = m->m_pkthdr.len + 2; | |
603 | 603 | |||
604 | /* The first two bytes are the frame length */ | 604 | /* The first two bytes are the frame length */ | |
605 | c->unc_buf[0] = (uint8_t)m->m_pkthdr.len; | 605 | c->unc_buf[0] = (uint8_t)m->m_pkthdr.len; | |
606 | c->unc_buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); | 606 | c->unc_buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); | |
607 | 607 | |||
608 | return total_len; | 608 | return total_len; | |
609 | } | 609 | } | |
610 | 610 | |||
611 | static int | 611 | static int | |
612 | cue_uno_init(struct ifnet *ifp) | 612 | cue_uno_init(struct ifnet *ifp) | |
613 | { | 613 | { | |
614 | struct usbnet * const un = ifp->if_softc; | 614 | struct usbnet * const un = ifp->if_softc; | |
615 | int i, ctl; | 615 | int i, ctl; | |
616 | const u_char *eaddr; | 616 | const u_char *eaddr; | |
617 | 617 | |||
618 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | 618 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | |
619 | 619 | |||
620 | if (usbnet_isdying(un)) | |||
621 | return ENXIO; | |||
622 | ||||
623 | /* Cancel pending I/O */ | 620 | /* Cancel pending I/O */ | |
624 | usbnet_stop(un, ifp, 1); | 621 | usbnet_stop(un, ifp, 1); | |
625 | 622 | |||
626 | /* Reset the interface. */ | 623 | /* Reset the interface. */ | |
627 | #if 1 | 624 | #if 1 | |
628 | cue_reset(un); | 625 | cue_reset(un); | |
629 | #endif | 626 | #endif | |
630 | 627 | |||
631 | /* Set advanced operation modes. */ | 628 | /* Set advanced operation modes. */ | |
632 | cue_csr_write_1(un, CUE_ADVANCED_OPMODES, | 629 | cue_csr_write_1(un, CUE_ADVANCED_OPMODES, | |
633 | CUE_AOP_EMBED_RXLEN | 0x03); /* 1 wait state */ | 630 | CUE_AOP_EMBED_RXLEN | 0x03); /* 1 wait state */ | |
634 | 631 | |||
635 | eaddr = CLLADDR(ifp->if_sadl); | 632 | eaddr = CLLADDR(ifp->if_sadl); | |
636 | /* Set MAC address */ | 633 | /* Set MAC address */ | |
637 | for (i = 0; i < ETHER_ADDR_LEN; i++) | 634 | for (i = 0; i < ETHER_ADDR_LEN; i++) | |
638 | cue_csr_write_1(un, CUE_PAR0 - i, eaddr[i]); | 635 | cue_csr_write_1(un, CUE_PAR0 - i, eaddr[i]); | |
639 | 636 | |||
640 | /* Enable RX logic. */ | 637 | /* Enable RX logic. */ | |
641 | ctl = CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON; | 638 | ctl = CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON; | |
642 | if (ifp->if_flags & IFF_PROMISC) | 639 | if (ifp->if_flags & IFF_PROMISC) | |
643 | ctl |= CUE_ETHCTL_PROMISC; | 640 | ctl |= CUE_ETHCTL_PROMISC; | |
644 | cue_csr_write_1(un, CUE_ETHCTL, ctl); | 641 | cue_csr_write_1(un, CUE_ETHCTL, ctl); | |
645 | 642 | |||
646 | /* | 643 | /* | |
647 | * Set the number of RX and TX buffers that we want | 644 | * Set the number of RX and TX buffers that we want | |
648 | * to reserve inside the ASIC. | 645 | * to reserve inside the ASIC. | |
649 | */ | 646 | */ | |
650 | cue_csr_write_1(un, CUE_RX_BUFPKTS, CUE_RX_FRAMES); | 647 | cue_csr_write_1(un, CUE_RX_BUFPKTS, CUE_RX_FRAMES); | |
651 | cue_csr_write_1(un, CUE_TX_BUFPKTS, CUE_TX_FRAMES); | 648 | cue_csr_write_1(un, CUE_TX_BUFPKTS, CUE_TX_FRAMES); | |
652 | 649 | |||
653 | /* Set advanced operation modes. */ | 650 | /* Set advanced operation modes. */ | |
654 | cue_csr_write_1(un, CUE_ADVANCED_OPMODES, | 651 | cue_csr_write_1(un, CUE_ADVANCED_OPMODES, | |
655 | CUE_AOP_EMBED_RXLEN | 0x01); /* 1 wait state */ | 652 | CUE_AOP_EMBED_RXLEN | 0x01); /* 1 wait state */ | |
656 | 653 | |||
657 | /* Program the LED operation. */ | 654 | /* Program the LED operation. */ | |
658 | cue_csr_write_1(un, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK); | 655 | cue_csr_write_1(un, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK); | |
659 | 656 | |||
660 | return usbnet_init_rx_tx(un); | 657 | return usbnet_init_rx_tx(un); | |
661 | } | 658 | } | |
662 | 659 | |||
663 | /* Stop and reset the adapter. */ | 660 | /* Stop and reset the adapter. */ | |
664 | static void | 661 | static void | |
665 | cue_uno_stop(struct ifnet *ifp, int disable) | 662 | cue_uno_stop(struct ifnet *ifp, int disable) | |
666 | { | 663 | { | |
667 | struct usbnet * const un = ifp->if_softc; | 664 | struct usbnet * const un = ifp->if_softc; | |
668 | 665 | |||
669 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 666 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
670 | 667 | |||
671 | cue_csr_write_1(un, CUE_ETHCTL, 0); | 668 | cue_csr_write_1(un, CUE_ETHCTL, 0); | |
672 | cue_reset(un); | 669 | cue_reset(un); | |
673 | } | 670 | } | |
674 | 671 | |||
675 | #ifdef _MODULE | 672 | #ifdef _MODULE | |
676 | #include "ioconf.c" | 673 | #include "ioconf.c" | |
677 | #endif | 674 | #endif | |
678 | 675 | |||
679 | USBNET_MODULE(cue) | 676 | USBNET_MODULE(cue) |
--- src/sys/dev/usb/if_kue.c 2022/03/03 05:53:33 1.114
+++ src/sys/dev/usb/if_kue.c 2022/03/03 05:55:01 1.115
@@ -1,631 +1,628 @@ | @@ -1,631 +1,628 @@ | |||
1 | /* $NetBSD: if_kue.c,v 1.114 2022/03/03 05:53:33 riastradh Exp $ */ | 1 | /* $NetBSD: if_kue.c,v 1.115 2022/03/03 05:55:01 riastradh Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1997, 1998, 1999, 2000 | 4 | * Copyright (c) 1997, 1998, 1999, 2000 | |
5 | * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. | 5 | * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. All advertising materials mentioning features or use of this software | 15 | * 3. All advertising materials mentioning features or use of this software | |
16 | * must display the following acknowledgement: | 16 | * must display the following acknowledgement: | |
17 | * This product includes software developed by Bill Paul. | 17 | * This product includes software developed by Bill Paul. | |
18 | * 4. Neither the name of the author nor the names of any co-contributors | 18 | * 4. Neither the name of the author nor the names of any co-contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | |
26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
32 | * THE POSSIBILITY OF SUCH DAMAGE. | 32 | * THE POSSIBILITY OF SUCH DAMAGE. | |
33 | * | 33 | * | |
34 | * $FreeBSD: src/sys/dev/usb/if_kue.c,v 1.14 2000/01/14 01:36:15 wpaul Exp $ | 34 | * $FreeBSD: src/sys/dev/usb/if_kue.c,v 1.14 2000/01/14 01:36:15 wpaul Exp $ | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | /* | 37 | /* | |
38 | * Kawasaki LSI KL5KUSB101B USB to ethernet adapter driver. | 38 | * Kawasaki LSI KL5KUSB101B USB to ethernet adapter driver. | |
39 | * | 39 | * | |
40 | * Written by Bill Paul <wpaul@ee.columbia.edu> | 40 | * Written by Bill Paul <wpaul@ee.columbia.edu> | |
41 | * Electrical Engineering Department | 41 | * Electrical Engineering Department | |
42 | * Columbia University, New York City | 42 | * Columbia University, New York City | |
43 | */ | 43 | */ | |
44 | 44 | |||
45 | /* | 45 | /* | |
46 | * The KLSI USB to ethernet adapter chip contains an USB serial interface, | 46 | * The KLSI USB to ethernet adapter chip contains an USB serial interface, | |
47 | * ethernet MAC and embedded microcontroller (called the QT Engine). | 47 | * ethernet MAC and embedded microcontroller (called the QT Engine). | |
48 | * The chip must have firmware loaded into it before it will operate. | 48 | * The chip must have firmware loaded into it before it will operate. | |
49 | * Packets are passed between the chip and host via bulk transfers. | 49 | * Packets are passed between the chip and host via bulk transfers. | |
50 | * There is an interrupt endpoint mentioned in the software spec, however | 50 | * There is an interrupt endpoint mentioned in the software spec, however | |
51 | * it's currently unused. This device is 10Mbps half-duplex only, hence | 51 | * it's currently unused. This device is 10Mbps half-duplex only, hence | |
52 | * there is no media selection logic. The MAC supports a 128 entry | 52 | * there is no media selection logic. The MAC supports a 128 entry | |
53 | * multicast filter, though the exact size of the filter can depend | 53 | * multicast filter, though the exact size of the filter can depend | |
54 | * on the firmware. Curiously, while the software spec describes various | 54 | * on the firmware. Curiously, while the software spec describes various | |
55 | * ethernet statistics counters, my sample adapter and firmware combination | 55 | * ethernet statistics counters, my sample adapter and firmware combination | |
56 | * claims not to support any statistics counters at all. | 56 | * claims not to support any statistics counters at all. | |
57 | * | 57 | * | |
58 | * Note that once we load the firmware in the device, we have to be | 58 | * Note that once we load the firmware in the device, we have to be | |
59 | * careful not to load it again: if you restart your computer but | 59 | * careful not to load it again: if you restart your computer but | |
60 | * leave the adapter attached to the USB controller, it may remain | 60 | * leave the adapter attached to the USB controller, it may remain | |
61 | * powered on and retain its firmware. In this case, we don't need | 61 | * powered on and retain its firmware. In this case, we don't need | |
62 | * to load the firmware a second time. | 62 | * to load the firmware a second time. | |
63 | * | 63 | * | |
64 | * Special thanks to Rob Furr for providing an ADS Technologies | 64 | * Special thanks to Rob Furr for providing an ADS Technologies | |
65 | * adapter for development and testing. No monkeys were harmed during | 65 | * adapter for development and testing. No monkeys were harmed during | |
66 | * the development of this driver. | 66 | * the development of this driver. | |
67 | */ | 67 | */ | |
68 | 68 | |||
69 | /* | 69 | /* | |
70 | * Ported to NetBSD and somewhat rewritten by Lennart Augustsson. | 70 | * Ported to NetBSD and somewhat rewritten by Lennart Augustsson. | |
71 | */ | 71 | */ | |
72 | 72 | |||
73 | #include <sys/cdefs.h> | 73 | #include <sys/cdefs.h> | |
74 | __KERNEL_RCSID(0, "$NetBSD: if_kue.c,v 1.114 2022/03/03 05:53:33 riastradh Exp $"); | 74 | __KERNEL_RCSID(0, "$NetBSD: if_kue.c,v 1.115 2022/03/03 05:55:01 riastradh Exp $"); | |
75 | 75 | |||
76 | #ifdef _KERNEL_OPT | 76 | #ifdef _KERNEL_OPT | |
77 | #include "opt_inet.h" | 77 | #include "opt_inet.h" | |
78 | #include "opt_usb.h" | 78 | #include "opt_usb.h" | |
79 | #endif | 79 | #endif | |
80 | 80 | |||
81 | #include <sys/param.h> | 81 | #include <sys/param.h> | |
82 | #include <sys/kmem.h> | 82 | #include <sys/kmem.h> | |
83 | 83 | |||
84 | #include <dev/usb/usbnet.h> | 84 | #include <dev/usb/usbnet.h> | |
85 | 85 | |||
86 | #ifdef INET | 86 | #ifdef INET | |
87 | #include <netinet/in.h> | 87 | #include <netinet/in.h> | |
88 | #include <netinet/if_inarp.h> | 88 | #include <netinet/if_inarp.h> | |
89 | #endif | 89 | #endif | |
90 | 90 | |||
91 | #include <dev/usb/if_kuereg.h> | 91 | #include <dev/usb/if_kuereg.h> | |
92 | #include <dev/usb/kue_fw.h> | 92 | #include <dev/usb/kue_fw.h> | |
93 | 93 | |||
94 | #ifdef KUE_DEBUG | 94 | #ifdef KUE_DEBUG | |
95 | #define DPRINTF(x) if (kuedebug) printf x | 95 | #define DPRINTF(x) if (kuedebug) printf x | |
96 | #define DPRINTFN(n, x) if (kuedebug >= (n)) printf x | 96 | #define DPRINTFN(n, x) if (kuedebug >= (n)) printf x | |
97 | int kuedebug = 0; | 97 | int kuedebug = 0; | |
98 | #else | 98 | #else | |
99 | #define DPRINTF(x) | 99 | #define DPRINTF(x) | |
100 | #define DPRINTFN(n, x) | 100 | #define DPRINTFN(n, x) | |
101 | #endif | 101 | #endif | |
102 | 102 | |||
103 | struct kue_type { | 103 | struct kue_type { | |
104 | uint16_t kue_vid; | 104 | uint16_t kue_vid; | |
105 | uint16_t kue_did; | 105 | uint16_t kue_did; | |
106 | }; | 106 | }; | |
107 | 107 | |||
108 | struct kue_softc { | 108 | struct kue_softc { | |
109 | struct usbnet kue_un; | 109 | struct usbnet kue_un; | |
110 | 110 | |||
111 | struct kue_ether_desc kue_desc; | 111 | struct kue_ether_desc kue_desc; | |
112 | uint16_t kue_rxfilt; | 112 | uint16_t kue_rxfilt; | |
113 | uint8_t *kue_mcfilters; | 113 | uint8_t *kue_mcfilters; | |
114 | }; | 114 | }; | |
115 | 115 | |||
116 | #define KUE_MCFILT(x, y) \ | 116 | #define KUE_MCFILT(x, y) \ | |
117 | (uint8_t *)&(sc->kue_mcfilters[y * ETHER_ADDR_LEN]) | 117 | (uint8_t *)&(sc->kue_mcfilters[y * ETHER_ADDR_LEN]) | |
118 | 118 | |||
119 | #define KUE_BUFSZ 1536 | 119 | #define KUE_BUFSZ 1536 | |
120 | #define KUE_MIN_FRAMELEN 60 | 120 | #define KUE_MIN_FRAMELEN 60 | |
121 | 121 | |||
122 | #define KUE_RX_LIST_CNT 1 | 122 | #define KUE_RX_LIST_CNT 1 | |
123 | #define KUE_TX_LIST_CNT 1 | 123 | #define KUE_TX_LIST_CNT 1 | |
124 | 124 | |||
125 | /* | 125 | /* | |
126 | * Various supported device vendors/products. | 126 | * Various supported device vendors/products. | |
127 | */ | 127 | */ | |
128 | static const struct usb_devno kue_devs[] = { | 128 | static const struct usb_devno kue_devs[] = { | |
129 | { USB_VENDOR_3COM, USB_PRODUCT_3COM_3C19250 }, | 129 | { USB_VENDOR_3COM, USB_PRODUCT_3COM_3C19250 }, | |
130 | { USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460 }, | 130 | { USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460 }, | |
131 | { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_URE450 }, | 131 | { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_URE450 }, | |
132 | { USB_VENDOR_ADS, USB_PRODUCT_ADS_UBS10BT }, | 132 | { USB_VENDOR_ADS, USB_PRODUCT_ADS_UBS10BT }, | |
133 | { USB_VENDOR_ADS, USB_PRODUCT_ADS_UBS10BTX }, | 133 | { USB_VENDOR_ADS, USB_PRODUCT_ADS_UBS10BTX }, | |
134 | { USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_AR9287 }, | 134 | { USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_AR9287 }, | |
135 | { USB_VENDOR_ALLIEDTELESYN, USB_PRODUCT_ALLIEDTELESYN_AT_USB10 }, | 135 | { USB_VENDOR_ALLIEDTELESYN, USB_PRODUCT_ALLIEDTELESYN_AT_USB10 }, | |
136 | { USB_VENDOR_AOX, USB_PRODUCT_AOX_USB101 }, | 136 | { USB_VENDOR_AOX, USB_PRODUCT_AOX_USB101 }, | |
137 | { USB_VENDOR_ASANTE, USB_PRODUCT_ASANTE_EA }, | 137 | { USB_VENDOR_ASANTE, USB_PRODUCT_ASANTE_EA }, | |
138 | { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC10T }, | 138 | { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC10T }, | |
139 | { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_DSB650C }, | 139 | { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_DSB650C }, | |
140 | { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_ETHER_USB_T }, | 140 | { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_ETHER_USB_T }, | |
141 | { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650C }, | 141 | { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650C }, | |
142 | { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_E45 }, | 142 | { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_E45 }, | |
143 | { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_XX1 }, | 143 | { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_XX1 }, | |
144 | { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_XX2 }, | 144 | { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_XX2 }, | |
145 | { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETT }, | 145 | { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETT }, | |
146 | { USB_VENDOR_JATON, USB_PRODUCT_JATON_EDA }, | 146 | { USB_VENDOR_JATON, USB_PRODUCT_JATON_EDA }, | |
147 | { USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_XX1 }, | 147 | { USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_XX1 }, | |
148 | { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BT }, | 148 | { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BT }, | |
149 | { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BTN }, | 149 | { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BTN }, | |
150 | { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T }, | 150 | { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T }, | |
151 | { USB_VENDOR_MOBILITY, USB_PRODUCT_MOBILITY_EA }, | 151 | { USB_VENDOR_MOBILITY, USB_PRODUCT_MOBILITY_EA }, | |
152 | { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_EA101 }, | 152 | { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_EA101 }, | |
153 | { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_EA101X }, | 153 | { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_EA101X }, | |
154 | { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET }, | 154 | { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET }, | |
155 | { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET2 }, | 155 | { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET2 }, | |
156 | { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET3 }, | 156 | { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET3 }, | |
157 | { USB_VENDOR_PORTGEAR, USB_PRODUCT_PORTGEAR_EA8 }, | 157 | { USB_VENDOR_PORTGEAR, USB_PRODUCT_PORTGEAR_EA8 }, | |
158 | { USB_VENDOR_PORTGEAR, USB_PRODUCT_PORTGEAR_EA9 }, | 158 | { USB_VENDOR_PORTGEAR, USB_PRODUCT_PORTGEAR_EA9 }, | |
159 | { USB_VENDOR_PORTSMITH, USB_PRODUCT_PORTSMITH_EEA }, | 159 | { USB_VENDOR_PORTSMITH, USB_PRODUCT_PORTSMITH_EEA }, | |
160 | { USB_VENDOR_SHARK, USB_PRODUCT_SHARK_PA }, | 160 | { USB_VENDOR_SHARK, USB_PRODUCT_SHARK_PA }, | |
161 | { USB_VENDOR_SILICOM, USB_PRODUCT_SILICOM_U2E }, | 161 | { USB_VENDOR_SILICOM, USB_PRODUCT_SILICOM_U2E }, | |
162 | { USB_VENDOR_SILICOM, USB_PRODUCT_SILICOM_GPE }, | 162 | { USB_VENDOR_SILICOM, USB_PRODUCT_SILICOM_GPE }, | |
163 | { USB_VENDOR_SMC, USB_PRODUCT_SMC_2102USB }, | 163 | { USB_VENDOR_SMC, USB_PRODUCT_SMC_2102USB }, | |
164 | }; | 164 | }; | |
165 | #define kue_lookup(v, p) (usb_lookup(kue_devs, v, p)) | 165 | #define kue_lookup(v, p) (usb_lookup(kue_devs, v, p)) | |
166 | 166 | |||
167 | static int kue_match(device_t, cfdata_t, void *); | 167 | static int kue_match(device_t, cfdata_t, void *); | |
168 | static void kue_attach(device_t, device_t, void *); | 168 | static void kue_attach(device_t, device_t, void *); | |
169 | static int kue_detach(device_t, int); | 169 | static int kue_detach(device_t, int); | |
170 | 170 | |||
171 | CFATTACH_DECL_NEW(kue, sizeof(struct kue_softc), kue_match, kue_attach, | 171 | CFATTACH_DECL_NEW(kue, sizeof(struct kue_softc), kue_match, kue_attach, | |
172 | kue_detach, usbnet_activate); | 172 | kue_detach, usbnet_activate); | |
173 | 173 | |||
174 | static void kue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 174 | static void kue_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
175 | static unsigned kue_uno_tx_prepare(struct usbnet *, struct mbuf *, | 175 | static unsigned kue_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
176 | struct usbnet_chain *); | 176 | struct usbnet_chain *); | |
177 | static void kue_uno_mcast(struct ifnet *); | 177 | static void kue_uno_mcast(struct ifnet *); | |
178 | static int kue_uno_init(struct ifnet *); | 178 | static int kue_uno_init(struct ifnet *); | |
179 | 179 | |||
180 | static const struct usbnet_ops kue_ops = { | 180 | static const struct usbnet_ops kue_ops = { | |
181 | .uno_mcast = kue_uno_mcast, | 181 | .uno_mcast = kue_uno_mcast, | |
182 | .uno_tx_prepare = kue_uno_tx_prepare, | 182 | .uno_tx_prepare = kue_uno_tx_prepare, | |
183 | .uno_rx_loop = kue_uno_rx_loop, | 183 | .uno_rx_loop = kue_uno_rx_loop, | |
184 | .uno_init = kue_uno_init, | 184 | .uno_init = kue_uno_init, | |
185 | }; | 185 | }; | |
186 | 186 | |||
187 | static void kue_reset(struct usbnet *); | 187 | static void kue_reset(struct usbnet *); | |
188 | 188 | |||
189 | static usbd_status kue_ctl(struct usbnet *, int, uint8_t, | 189 | static usbd_status kue_ctl(struct usbnet *, int, uint8_t, | |
190 | uint16_t, void *, uint32_t); | 190 | uint16_t, void *, uint32_t); | |
191 | static int kue_load_fw(struct usbnet *); | 191 | static int kue_load_fw(struct usbnet *); | |
192 | 192 | |||
193 | static usbd_status | 193 | static usbd_status | |
194 | kue_setword(struct usbnet *un, uint8_t breq, uint16_t word) | 194 | kue_setword(struct usbnet *un, uint8_t breq, uint16_t word) | |
195 | { | 195 | { | |
196 | usb_device_request_t req; | 196 | usb_device_request_t req; | |
197 | 197 | |||
198 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | 198 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | |
199 | 199 | |||
200 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 200 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
201 | req.bRequest = breq; | 201 | req.bRequest = breq; | |
202 | USETW(req.wValue, word); | 202 | USETW(req.wValue, word); | |
203 | USETW(req.wIndex, 0); | 203 | USETW(req.wIndex, 0); | |
204 | USETW(req.wLength, 0); | 204 | USETW(req.wLength, 0); | |
205 | 205 | |||
206 | return usbd_do_request(un->un_udev, &req, NULL); | 206 | return usbd_do_request(un->un_udev, &req, NULL); | |
207 | } | 207 | } | |
208 | 208 | |||
209 | static usbd_status | 209 | static usbd_status | |
210 | kue_ctl(struct usbnet *un, int rw, uint8_t breq, uint16_t val, | 210 | kue_ctl(struct usbnet *un, int rw, uint8_t breq, uint16_t val, | |
211 | void *data, uint32_t len) | 211 | void *data, uint32_t len) | |
212 | { | 212 | { | |
213 | usb_device_request_t req; | 213 | usb_device_request_t req; | |
214 | 214 | |||
215 | DPRINTFN(10,("%s: %s: enter, len=%d\n", device_xname(un->un_dev), | 215 | DPRINTFN(10,("%s: %s: enter, len=%d\n", device_xname(un->un_dev), | |
216 | __func__, len)); | 216 | __func__, len)); | |
217 | 217 | |||
218 | if (rw == KUE_CTL_WRITE) | 218 | if (rw == KUE_CTL_WRITE) | |
219 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 219 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
220 | else | 220 | else | |
221 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 221 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
222 | 222 | |||
223 | req.bRequest = breq; | 223 | req.bRequest = breq; | |
224 | USETW(req.wValue, val); | 224 | USETW(req.wValue, val); | |
225 | USETW(req.wIndex, 0); | 225 | USETW(req.wIndex, 0); | |
226 | USETW(req.wLength, len); | 226 | USETW(req.wLength, len); | |
227 | 227 | |||
228 | return usbd_do_request(un->un_udev, &req, data); | 228 | return usbd_do_request(un->un_udev, &req, data); | |
229 | } | 229 | } | |
230 | 230 | |||
231 | static int | 231 | static int | |
232 | kue_load_fw(struct usbnet *un) | 232 | kue_load_fw(struct usbnet *un) | |
233 | { | 233 | { | |
234 | usb_device_descriptor_t dd; | 234 | usb_device_descriptor_t dd; | |
235 | usbd_status err; | 235 | usbd_status err; | |
236 | 236 | |||
237 | DPRINTFN(1,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 237 | DPRINTFN(1,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
238 | 238 | |||
239 | /* | 239 | /* | |
240 | * First, check if we even need to load the firmware. | 240 | * First, check if we even need to load the firmware. | |
241 | * If the device was still attached when the system was | 241 | * If the device was still attached when the system was | |
242 | * rebooted, it may already have firmware loaded in it. | 242 | * rebooted, it may already have firmware loaded in it. | |
243 | * If this is the case, we don't need to do it again. | 243 | * If this is the case, we don't need to do it again. | |
244 | * And in fact, if we try to load it again, we'll hang, | 244 | * And in fact, if we try to load it again, we'll hang, | |
245 | * so we have to avoid this condition if we don't want | 245 | * so we have to avoid this condition if we don't want | |
246 | * to look stupid. | 246 | * to look stupid. | |
247 | * | 247 | * | |
248 | * We can test this quickly by checking the bcdRevision | 248 | * We can test this quickly by checking the bcdRevision | |
249 | * code. The NIC will return a different revision code if | 249 | * code. The NIC will return a different revision code if | |
250 | * it's probed while the firmware is still loaded and | 250 | * it's probed while the firmware is still loaded and | |
251 | * running. | 251 | * running. | |
252 | */ | 252 | */ | |
253 | if (usbd_get_device_desc(un->un_udev, &dd)) | 253 | if (usbd_get_device_desc(un->un_udev, &dd)) | |
254 | return EIO; | 254 | return EIO; | |
255 | if (UGETW(dd.bcdDevice) == KUE_WARM_REV) { | 255 | if (UGETW(dd.bcdDevice) == KUE_WARM_REV) { | |
256 | printf("%s: warm boot, no firmware download\n", | 256 | printf("%s: warm boot, no firmware download\n", | |
257 | device_xname(un->un_dev)); | 257 | device_xname(un->un_dev)); | |
258 | return 0; | 258 | return 0; | |
259 | } | 259 | } | |
260 | 260 | |||
261 | printf("%s: cold boot, downloading firmware\n", | 261 | printf("%s: cold boot, downloading firmware\n", | |
262 | device_xname(un->un_dev)); | 262 | device_xname(un->un_dev)); | |
263 | 263 | |||
264 | /* Load code segment */ | 264 | /* Load code segment */ | |
265 | DPRINTFN(1,("%s: kue_load_fw: download code_seg\n", | 265 | DPRINTFN(1,("%s: kue_load_fw: download code_seg\n", | |
266 | device_xname(un->un_dev))); | 266 | device_xname(un->un_dev))); | |
267 | /*XXXUNCONST*/ | 267 | /*XXXUNCONST*/ | |
268 | err = kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, | 268 | err = kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, | |
269 | 0, __UNCONST(kue_code_seg), sizeof(kue_code_seg)); | 269 | 0, __UNCONST(kue_code_seg), sizeof(kue_code_seg)); | |
270 | if (err) { | 270 | if (err) { | |
271 | printf("%s: failed to load code segment: %s\n", | 271 | printf("%s: failed to load code segment: %s\n", | |
272 | device_xname(un->un_dev), usbd_errstr(err)); | 272 | device_xname(un->un_dev), usbd_errstr(err)); | |
273 | return EIO; | 273 | return EIO; | |
274 | } | 274 | } | |
275 | 275 | |||
276 | /* Load fixup segment */ | 276 | /* Load fixup segment */ | |
277 | DPRINTFN(1,("%s: kue_load_fw: download fix_seg\n", | 277 | DPRINTFN(1,("%s: kue_load_fw: download fix_seg\n", | |
278 | device_xname(un->un_dev))); | 278 | device_xname(un->un_dev))); | |
279 | /*XXXUNCONST*/ | 279 | /*XXXUNCONST*/ | |
280 | err = kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, | 280 | err = kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, | |
281 | 0, __UNCONST(kue_fix_seg), sizeof(kue_fix_seg)); | 281 | 0, __UNCONST(kue_fix_seg), sizeof(kue_fix_seg)); | |
282 | if (err) { | 282 | if (err) { | |
283 | printf("%s: failed to load fixup segment: %s\n", | 283 | printf("%s: failed to load fixup segment: %s\n", | |
284 | device_xname(un->un_dev), usbd_errstr(err)); | 284 | device_xname(un->un_dev), usbd_errstr(err)); | |
285 | return EIO; | 285 | return EIO; | |
286 | } | 286 | } | |
287 | 287 | |||
288 | /* Send trigger command. */ | 288 | /* Send trigger command. */ | |
289 | DPRINTFN(1,("%s: kue_load_fw: download trig_seg\n", | 289 | DPRINTFN(1,("%s: kue_load_fw: download trig_seg\n", | |
290 | device_xname(un->un_dev))); | 290 | device_xname(un->un_dev))); | |
291 | /*XXXUNCONST*/ | 291 | /*XXXUNCONST*/ | |
292 | err = kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, | 292 | err = kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, | |
293 | 0, __UNCONST(kue_trig_seg), sizeof(kue_trig_seg)); | 293 | 0, __UNCONST(kue_trig_seg), sizeof(kue_trig_seg)); | |
294 | if (err) { | 294 | if (err) { | |
295 | printf("%s: failed to load trigger segment: %s\n", | 295 | printf("%s: failed to load trigger segment: %s\n", | |
296 | device_xname(un->un_dev), usbd_errstr(err)); | 296 | device_xname(un->un_dev), usbd_errstr(err)); | |
297 | return EIO; | 297 | return EIO; | |
298 | } | 298 | } | |
299 | 299 | |||
300 | usbd_delay_ms(un->un_udev, 10); | 300 | usbd_delay_ms(un->un_udev, 10); | |
301 | 301 | |||
302 | /* | 302 | /* | |
303 | * Reload device descriptor. | 303 | * Reload device descriptor. | |
304 | * Why? The chip without the firmware loaded returns | 304 | * Why? The chip without the firmware loaded returns | |
305 | * one revision code. The chip with the firmware | 305 | * one revision code. The chip with the firmware | |
306 | * loaded and running returns a *different* revision | 306 | * loaded and running returns a *different* revision | |
307 | * code. This confuses the quirk mechanism, which is | 307 | * code. This confuses the quirk mechanism, which is | |
308 | * dependent on the revision data. | 308 | * dependent on the revision data. | |
309 | */ | 309 | */ | |
310 | (void)usbd_reload_device_desc(un->un_udev); | 310 | (void)usbd_reload_device_desc(un->un_udev); | |
311 | 311 | |||
312 | DPRINTFN(1,("%s: %s: done\n", device_xname(un->un_dev), __func__)); | 312 | DPRINTFN(1,("%s: %s: done\n", device_xname(un->un_dev), __func__)); | |
313 | 313 | |||
314 | /* Reset the adapter. */ | 314 | /* Reset the adapter. */ | |
315 | kue_reset(un); | 315 | kue_reset(un); | |
316 | 316 | |||
317 | return 0; | 317 | return 0; | |
318 | } | 318 | } | |
319 | 319 | |||
320 | static void | 320 | static void | |
321 | kue_uno_mcast(struct ifnet *ifp) | 321 | kue_uno_mcast(struct ifnet *ifp) | |
322 | { | 322 | { | |
323 | struct usbnet * un = ifp->if_softc; | 323 | struct usbnet * un = ifp->if_softc; | |
324 | struct ethercom * ec = usbnet_ec(un); | 324 | struct ethercom * ec = usbnet_ec(un); | |
325 | struct kue_softc * sc = usbnet_softc(un); | 325 | struct kue_softc * sc = usbnet_softc(un); | |
326 | struct ether_multi *enm; | 326 | struct ether_multi *enm; | |
327 | struct ether_multistep step; | 327 | struct ether_multistep step; | |
328 | int i; | 328 | int i; | |
329 | 329 | |||
330 | DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 330 | DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
331 | 331 | |||
332 | /* If we want promiscuous mode, set the allframes bit. */ | 332 | /* If we want promiscuous mode, set the allframes bit. */ | |
333 | if (ifp->if_flags & IFF_PROMISC) | 333 | if (ifp->if_flags & IFF_PROMISC) | |
334 | sc->kue_rxfilt |= KUE_RXFILT_PROMISC; | 334 | sc->kue_rxfilt |= KUE_RXFILT_PROMISC; | |
335 | else | 335 | else | |
336 | sc->kue_rxfilt &= ~KUE_RXFILT_PROMISC; | 336 | sc->kue_rxfilt &= ~KUE_RXFILT_PROMISC; | |
337 | 337 | |||
338 | if (ifp->if_flags & IFF_PROMISC) { | 338 | if (ifp->if_flags & IFF_PROMISC) { | |
339 | ETHER_LOCK(ec); | 339 | ETHER_LOCK(ec); | |
340 | allmulti: | 340 | allmulti: | |
341 | ec->ec_flags |= ETHER_F_ALLMULTI; | 341 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
342 | ETHER_UNLOCK(ec); | 342 | ETHER_UNLOCK(ec); | |
343 | sc->kue_rxfilt |= KUE_RXFILT_ALLMULTI|KUE_RXFILT_PROMISC; | 343 | sc->kue_rxfilt |= KUE_RXFILT_ALLMULTI|KUE_RXFILT_PROMISC; | |
344 | sc->kue_rxfilt &= ~KUE_RXFILT_MULTICAST; | 344 | sc->kue_rxfilt &= ~KUE_RXFILT_MULTICAST; | |
345 | kue_setword(un, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt); | 345 | kue_setword(un, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt); | |
346 | return; | 346 | return; | |
347 | } | 347 | } | |
348 | 348 | |||
349 | sc->kue_rxfilt &= ~(KUE_RXFILT_ALLMULTI|KUE_RXFILT_PROMISC); | 349 | sc->kue_rxfilt &= ~(KUE_RXFILT_ALLMULTI|KUE_RXFILT_PROMISC); | |
350 | 350 | |||
351 | i = 0; | 351 | i = 0; | |
352 | ETHER_LOCK(ec); | 352 | ETHER_LOCK(ec); | |
353 | ETHER_FIRST_MULTI(step, ec, enm); | 353 | ETHER_FIRST_MULTI(step, ec, enm); | |
354 | while (enm != NULL) { | 354 | while (enm != NULL) { | |
355 | if (i == KUE_MCFILTCNT(sc) || | 355 | if (i == KUE_MCFILTCNT(sc) || | |
356 | memcmp(enm->enm_addrlo, enm->enm_addrhi, | 356 | memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
357 | ETHER_ADDR_LEN) != 0) { | 357 | ETHER_ADDR_LEN) != 0) { | |
358 | goto allmulti; | 358 | goto allmulti; | |
359 | } | 359 | } | |
360 | 360 | |||
361 | memcpy(KUE_MCFILT(sc, i), enm->enm_addrlo, ETHER_ADDR_LEN); | 361 | memcpy(KUE_MCFILT(sc, i), enm->enm_addrlo, ETHER_ADDR_LEN); | |
362 | ETHER_NEXT_MULTI(step, enm); | 362 | ETHER_NEXT_MULTI(step, enm); | |
363 | i++; | 363 | i++; | |
364 | } | 364 | } | |
365 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 365 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
366 | ETHER_UNLOCK(ec); | 366 | ETHER_UNLOCK(ec); | |
367 | 367 | |||
368 | sc->kue_rxfilt |= KUE_RXFILT_MULTICAST; | 368 | sc->kue_rxfilt |= KUE_RXFILT_MULTICAST; | |
369 | kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SET_MCAST_FILTERS, | 369 | kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SET_MCAST_FILTERS, | |
370 | i, sc->kue_mcfilters, i * ETHER_ADDR_LEN); | 370 | i, sc->kue_mcfilters, i * ETHER_ADDR_LEN); | |
371 | 371 | |||
372 | kue_setword(un, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt); | 372 | kue_setword(un, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt); | |
373 | } | 373 | } | |
374 | 374 | |||
375 | /* | 375 | /* | |
376 | * Issue a SET_CONFIGURATION command to reset the MAC. This should be | 376 | * Issue a SET_CONFIGURATION command to reset the MAC. This should be | |
377 | * done after the firmware is loaded into the adapter in order to | 377 | * done after the firmware is loaded into the adapter in order to | |
378 | * bring it into proper operation. | 378 | * bring it into proper operation. | |
379 | */ | 379 | */ | |
380 | static void | 380 | static void | |
381 | kue_reset(struct usbnet *un) | 381 | kue_reset(struct usbnet *un) | |
382 | { | 382 | { | |
383 | DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 383 | DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
384 | 384 | |||
385 | if (usbd_set_config_no(un->un_udev, KUE_CONFIG_NO, 1) || | 385 | if (usbd_set_config_no(un->un_udev, KUE_CONFIG_NO, 1) || | |
386 | usbd_device2interface_handle(un->un_udev, KUE_IFACE_IDX, | 386 | usbd_device2interface_handle(un->un_udev, KUE_IFACE_IDX, | |
387 | &un->un_iface)) | 387 | &un->un_iface)) | |
388 | printf("%s: reset failed\n", device_xname(un->un_dev)); | 388 | printf("%s: reset failed\n", device_xname(un->un_dev)); | |
389 | 389 | |||
390 | /* Wait a little while for the chip to get its brains in order. */ | 390 | /* Wait a little while for the chip to get its brains in order. */ | |
391 | usbd_delay_ms(un->un_udev, 10); | 391 | usbd_delay_ms(un->un_udev, 10); | |
392 | } | 392 | } | |
393 | 393 | |||
394 | /* | 394 | /* | |
395 | * Probe for a KLSI chip. | 395 | * Probe for a KLSI chip. | |
396 | */ | 396 | */ | |
397 | static int | 397 | static int | |
398 | kue_match(device_t parent, cfdata_t match, void *aux) | 398 | kue_match(device_t parent, cfdata_t match, void *aux) | |
399 | { | 399 | { | |
400 | struct usb_attach_arg *uaa = aux; | 400 | struct usb_attach_arg *uaa = aux; | |
401 | 401 | |||
402 | DPRINTFN(25,("kue_match: enter\n")); | 402 | DPRINTFN(25,("kue_match: enter\n")); | |
403 | 403 | |||
404 | return kue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 404 | return kue_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
405 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 405 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
406 | } | 406 | } | |
407 | 407 | |||
408 | /* | 408 | /* | |
409 | * Attach the interface. Allocate softc structures, do | 409 | * Attach the interface. Allocate softc structures, do | |
410 | * setup and ethernet/BPF attach. | 410 | * setup and ethernet/BPF attach. | |
411 | */ | 411 | */ | |
412 | static void | 412 | static void | |
413 | kue_attach(device_t parent, device_t self, void *aux) | 413 | kue_attach(device_t parent, device_t self, void *aux) | |
414 | { | 414 | { | |
415 | struct kue_softc *sc = device_private(self); | 415 | struct kue_softc *sc = device_private(self); | |
416 | struct usbnet * const un = &sc->kue_un; | 416 | struct usbnet * const un = &sc->kue_un; | |
417 | struct usb_attach_arg *uaa = aux; | 417 | struct usb_attach_arg *uaa = aux; | |
418 | char *devinfop; | 418 | char *devinfop; | |
419 | struct usbd_device * dev = uaa->uaa_device; | 419 | struct usbd_device * dev = uaa->uaa_device; | |
420 | usbd_status err; | 420 | usbd_status err; | |
421 | usb_interface_descriptor_t *id; | 421 | usb_interface_descriptor_t *id; | |
422 | usb_endpoint_descriptor_t *ed; | 422 | usb_endpoint_descriptor_t *ed; | |
423 | int i; | 423 | int i; | |
424 | 424 | |||
425 | KASSERT((void *)sc == un); | 425 | KASSERT((void *)sc == un); | |
426 | 426 | |||
427 | DPRINTFN(5,(" : kue_attach: sc=%p, dev=%p", sc, dev)); | 427 | DPRINTFN(5,(" : kue_attach: sc=%p, dev=%p", sc, dev)); | |
428 | 428 | |||
429 | aprint_naive("\n"); | 429 | aprint_naive("\n"); | |
430 | aprint_normal("\n"); | 430 | aprint_normal("\n"); | |
431 | devinfop = usbd_devinfo_alloc(dev, 0); | 431 | devinfop = usbd_devinfo_alloc(dev, 0); | |
432 | aprint_normal_dev(self, "%s\n", devinfop); | 432 | aprint_normal_dev(self, "%s\n", devinfop); | |
433 | usbd_devinfo_free(devinfop); | 433 | usbd_devinfo_free(devinfop); | |
434 | 434 | |||
435 | un->un_dev = self; | 435 | un->un_dev = self; | |
436 | un->un_udev = dev; | 436 | un->un_udev = dev; | |
437 | un->un_sc = sc; | 437 | un->un_sc = sc; | |
438 | un->un_ops = &kue_ops; | 438 | un->un_ops = &kue_ops; | |
439 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 439 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
440 | un->un_tx_xfer_flags = 0; | 440 | un->un_tx_xfer_flags = 0; | |
441 | un->un_rx_list_cnt = KUE_RX_LIST_CNT; | 441 | un->un_rx_list_cnt = KUE_RX_LIST_CNT; | |
442 | un->un_tx_list_cnt = KUE_TX_LIST_CNT; | 442 | un->un_tx_list_cnt = KUE_TX_LIST_CNT; | |
443 | un->un_rx_bufsz = KUE_BUFSZ; | 443 | un->un_rx_bufsz = KUE_BUFSZ; | |
444 | un->un_tx_bufsz = KUE_BUFSZ; | 444 | un->un_tx_bufsz = KUE_BUFSZ; | |
445 | 445 | |||
446 | err = usbd_set_config_no(dev, KUE_CONFIG_NO, 1); | 446 | err = usbd_set_config_no(dev, KUE_CONFIG_NO, 1); | |
447 | if (err) { | 447 | if (err) { | |
448 | aprint_error_dev(self, "failed to set configuration" | 448 | aprint_error_dev(self, "failed to set configuration" | |
449 | ", err=%s\n", usbd_errstr(err)); | 449 | ", err=%s\n", usbd_errstr(err)); | |
450 | return; | 450 | return; | |
451 | } | 451 | } | |
452 | 452 | |||
453 | /* Load the firmware into the NIC. */ | 453 | /* Load the firmware into the NIC. */ | |
454 | if (kue_load_fw(un)) { | 454 | if (kue_load_fw(un)) { | |
455 | aprint_error_dev(self, "loading firmware failed\n"); | 455 | aprint_error_dev(self, "loading firmware failed\n"); | |
456 | return; | 456 | return; | |
457 | } | 457 | } | |
458 | 458 | |||
459 | err = usbd_device2interface_handle(dev, KUE_IFACE_IDX, &un->un_iface); | 459 | err = usbd_device2interface_handle(dev, KUE_IFACE_IDX, &un->un_iface); | |
460 | if (err) { | 460 | if (err) { | |
461 | aprint_error_dev(self, "getting interface handle failed\n"); | 461 | aprint_error_dev(self, "getting interface handle failed\n"); | |
462 | return; | 462 | return; | |
463 | } | 463 | } | |
464 | 464 | |||
465 | id = usbd_get_interface_descriptor(un->un_iface); | 465 | id = usbd_get_interface_descriptor(un->un_iface); | |
466 | 466 | |||
467 | /* Find endpoints. */ | 467 | /* Find endpoints. */ | |
468 | for (i = 0; i < id->bNumEndpoints; i++) { | 468 | for (i = 0; i < id->bNumEndpoints; i++) { | |
469 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 469 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
470 | if (ed == NULL) { | 470 | if (ed == NULL) { | |
471 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 471 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
472 | return; | 472 | return; | |
473 | } | 473 | } | |
474 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 474 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
475 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 475 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
476 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 476 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
477 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 477 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
478 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 478 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
479 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 479 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
480 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 480 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
481 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 481 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
482 | /* | 482 | /* | |
483 | * The interrupt endpoint is currently unused by the | 483 | * The interrupt endpoint is currently unused by the | |
484 | * KLSI part. | 484 | * KLSI part. | |
485 | */ | 485 | */ | |
486 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 486 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
487 | } | 487 | } | |
488 | } | 488 | } | |
489 | 489 | |||
490 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 490 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
491 | un->un_ed[USBNET_ENDPT_TX] == 0) { | 491 | un->un_ed[USBNET_ENDPT_TX] == 0) { | |
492 | aprint_error_dev(self, "missing endpoint\n"); | 492 | aprint_error_dev(self, "missing endpoint\n"); | |
493 | return; | 493 | return; | |
494 | } | 494 | } | |
495 | 495 | |||
496 | /* First level attach, so kue_ctl() works. */ | 496 | /* First level attach, so kue_ctl() works. */ | |
497 | usbnet_attach(un, "kuedet"); | 497 | usbnet_attach(un, "kuedet"); | |
498 | 498 | |||
499 | /* Read ethernet descriptor */ | 499 | /* Read ethernet descriptor */ | |
500 | err = kue_ctl(un, KUE_CTL_READ, KUE_CMD_GET_ETHER_DESCRIPTOR, | 500 | err = kue_ctl(un, KUE_CTL_READ, KUE_CMD_GET_ETHER_DESCRIPTOR, | |
501 | 0, &sc->kue_desc, sizeof(sc->kue_desc)); | 501 | 0, &sc->kue_desc, sizeof(sc->kue_desc)); | |
502 | if (err) { | 502 | if (err) { | |
503 | aprint_error_dev(self, "could not read Ethernet descriptor\n"); | 503 | aprint_error_dev(self, "could not read Ethernet descriptor\n"); | |
504 | return; | 504 | return; | |
505 | } | 505 | } | |
506 | memcpy(un->un_eaddr, sc->kue_desc.kue_macaddr, sizeof(un->un_eaddr)); | 506 | memcpy(un->un_eaddr, sc->kue_desc.kue_macaddr, sizeof(un->un_eaddr)); | |
507 | 507 | |||
508 | sc->kue_mcfilters = kmem_alloc(KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN, | 508 | sc->kue_mcfilters = kmem_alloc(KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN, | |
509 | KM_SLEEP); | 509 | KM_SLEEP); | |
510 | 510 | |||
511 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 511 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
512 | 0, NULL); | 512 | 0, NULL); | |
513 | } | 513 | } | |
514 | 514 | |||
515 | static int | 515 | static int | |
516 | kue_detach(device_t self, int flags) | 516 | kue_detach(device_t self, int flags) | |
517 | { | 517 | { | |
518 | struct kue_softc *sc = device_private(self); | 518 | struct kue_softc *sc = device_private(self); | |
519 | 519 | |||
520 | if (sc->kue_mcfilters != NULL) { | 520 | if (sc->kue_mcfilters != NULL) { | |
521 | kmem_free(sc->kue_mcfilters, | 521 | kmem_free(sc->kue_mcfilters, | |
522 | KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN); | 522 | KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN); | |
523 | sc->kue_mcfilters = NULL; | 523 | sc->kue_mcfilters = NULL; | |
524 | } | 524 | } | |
525 | 525 | |||
526 | return usbnet_detach(self, flags); | 526 | return usbnet_detach(self, flags); | |
527 | } | 527 | } | |
528 | 528 | |||
529 | /* | 529 | /* | |
530 | * A frame has been uploaded: pass the resulting mbuf chain up to | 530 | * A frame has been uploaded: pass the resulting mbuf chain up to | |
531 | * the higher level protocols. | 531 | * the higher level protocols. | |
532 | */ | 532 | */ | |
533 | static void | 533 | static void | |
534 | kue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 534 | kue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
535 | { | 535 | { | |
536 | struct ifnet *ifp = usbnet_ifp(un); | 536 | struct ifnet *ifp = usbnet_ifp(un); | |
537 | uint8_t *buf = c->unc_buf; | 537 | uint8_t *buf = c->unc_buf; | |
538 | unsigned pktlen; | 538 | unsigned pktlen; | |
539 | 539 | |||
540 | if (total_len <= 1) | 540 | if (total_len <= 1) | |
541 | return; | 541 | return; | |
542 | 542 | |||
543 | DPRINTFN(10,("%s: %s: total_len=%d len=%d\n", | 543 | DPRINTFN(10,("%s: %s: total_len=%d len=%d\n", | |
544 | device_xname(un->un_dev), __func__, | 544 | device_xname(un->un_dev), __func__, | |
545 | total_len, le16dec(buf))); | 545 | total_len, le16dec(buf))); | |
546 | 546 | |||
547 | pktlen = le16dec(buf); | 547 | pktlen = le16dec(buf); | |
548 | if (pktlen > total_len - ETHER_ALIGN) | 548 | if (pktlen > total_len - ETHER_ALIGN) | |
549 | pktlen = total_len - ETHER_ALIGN; | 549 | pktlen = total_len - ETHER_ALIGN; | |
550 | 550 | |||
551 | if (pktlen < ETHER_MIN_LEN - ETHER_CRC_LEN || | 551 | if (pktlen < ETHER_MIN_LEN - ETHER_CRC_LEN || | |
552 | pktlen > MCLBYTES - ETHER_ALIGN) { | 552 | pktlen > MCLBYTES - ETHER_ALIGN) { | |
553 | if_statinc(ifp, if_ierrors); | 553 | if_statinc(ifp, if_ierrors); | |
554 | return; | 554 | return; | |
555 | } | 555 | } | |
556 | 556 | |||
557 | DPRINTFN(10,("%s: %s: deliver %d\n", device_xname(un->un_dev), | 557 | DPRINTFN(10,("%s: %s: deliver %d\n", device_xname(un->un_dev), | |
558 | __func__, pktlen)); | 558 | __func__, pktlen)); | |
559 | usbnet_enqueue(un, buf + 2, pktlen, 0, 0, 0); | 559 | usbnet_enqueue(un, buf + 2, pktlen, 0, 0, 0); | |
560 | } | 560 | } | |
561 | 561 | |||
562 | static unsigned | 562 | static unsigned | |
563 | kue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 563 | kue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
564 | { | 564 | { | |
565 | unsigned total_len, pkt_len; | 565 | unsigned total_len, pkt_len; | |
566 | 566 | |||
567 | pkt_len = m->m_pkthdr.len + 2; | 567 | pkt_len = m->m_pkthdr.len + 2; | |
568 | total_len = roundup2(pkt_len, 64); | 568 | total_len = roundup2(pkt_len, 64); | |
569 | 569 | |||
570 | if ((unsigned)total_len > un->un_tx_bufsz) { | 570 | if ((unsigned)total_len > un->un_tx_bufsz) { | |
571 | DPRINTFN(10,("%s: %s: too big pktlen %u total %u\n", | 571 | DPRINTFN(10,("%s: %s: too big pktlen %u total %u\n", | |
572 | device_xname(un->un_dev), __func__, pkt_len, total_len)); | 572 | device_xname(un->un_dev), __func__, pkt_len, total_len)); | |
573 | return 0; | 573 | return 0; | |
574 | } | 574 | } | |
575 | 575 | |||
576 | /* Frame length is specified in the first 2 bytes of the buffer. */ | 576 | /* Frame length is specified in the first 2 bytes of the buffer. */ | |
577 | le16enc(c->unc_buf, (uint16_t)m->m_pkthdr.len); | 577 | le16enc(c->unc_buf, (uint16_t)m->m_pkthdr.len); | |
578 | 578 | |||
579 | /* | 579 | /* | |
580 | * Copy the mbuf data into a contiguous buffer after the frame length, | 580 | * Copy the mbuf data into a contiguous buffer after the frame length, | |
581 | * possibly zeroing the rest of the buffer. | 581 | * possibly zeroing the rest of the buffer. | |
582 | */ | 582 | */ | |
583 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + 2); | 583 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + 2); | |
584 | if (total_len - pkt_len > 0) | 584 | if (total_len - pkt_len > 0) | |
585 | memset(c->unc_buf + pkt_len, 0, total_len - pkt_len); | 585 | memset(c->unc_buf + pkt_len, 0, total_len - pkt_len); | |
586 | 586 | |||
587 | DPRINTFN(10,("%s: %s: enter pktlen %u total %u\n", | 587 | DPRINTFN(10,("%s: %s: enter pktlen %u total %u\n", | |
588 | device_xname(un->un_dev), __func__, pkt_len, total_len)); | 588 | device_xname(un->un_dev), __func__, pkt_len, total_len)); | |
589 | 589 | |||
590 | return total_len; | 590 | return total_len; | |
591 | } | 591 | } | |
592 | 592 | |||
593 | static int | 593 | static int | |
594 | kue_uno_init(struct ifnet *ifp) | 594 | kue_uno_init(struct ifnet *ifp) | |
595 | { | 595 | { | |
596 | struct usbnet * const un = ifp->if_softc; | 596 | struct usbnet * const un = ifp->if_softc; | |
597 | struct kue_softc *sc = usbnet_softc(un); | 597 | struct kue_softc *sc = usbnet_softc(un); | |
598 | uint8_t eaddr[ETHER_ADDR_LEN]; | 598 | uint8_t eaddr[ETHER_ADDR_LEN]; | |
599 | 599 | |||
600 | DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | 600 | DPRINTFN(5,("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | |
601 | 601 | |||
602 | if (usbnet_isdying(un)) | |||
603 | return EIO; | |||
604 | ||||
605 | /* Cancel pending I/O */ | 602 | /* Cancel pending I/O */ | |
606 | usbnet_stop(un, ifp, 1); | 603 | usbnet_stop(un, ifp, 1); | |
607 | 604 | |||
608 | memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); | 605 | memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); | |
609 | /* Set MAC address */ | 606 | /* Set MAC address */ | |
610 | kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SET_MAC, 0, eaddr, ETHER_ADDR_LEN); | 607 | kue_ctl(un, KUE_CTL_WRITE, KUE_CMD_SET_MAC, 0, eaddr, ETHER_ADDR_LEN); | |
611 | 608 | |||
612 | sc->kue_rxfilt = KUE_RXFILT_UNICAST | KUE_RXFILT_BROADCAST; | 609 | sc->kue_rxfilt = KUE_RXFILT_UNICAST | KUE_RXFILT_BROADCAST; | |
613 | 610 | |||
614 | /* I'm not sure how to tune these. */ | 611 | /* I'm not sure how to tune these. */ | |
615 | #if 0 | 612 | #if 0 | |
616 | /* | 613 | /* | |
617 | * Leave this one alone for now; setting it | 614 | * Leave this one alone for now; setting it | |
618 | * wrong causes lockups on some machines/controllers. | 615 | * wrong causes lockups on some machines/controllers. | |
619 | */ | 616 | */ | |
620 | kue_setword(un, KUE_CMD_SET_SOFS, 1); | 617 | kue_setword(un, KUE_CMD_SET_SOFS, 1); | |
621 | #endif | 618 | #endif | |
622 | kue_setword(un, KUE_CMD_SET_URB_SIZE, 64); | 619 | kue_setword(un, KUE_CMD_SET_URB_SIZE, 64); | |
623 | 620 | |||
624 | return usbnet_init_rx_tx(un); | 621 | return usbnet_init_rx_tx(un); | |
625 | } | 622 | } | |
626 | 623 | |||
627 | #ifdef _MODULE | 624 | #ifdef _MODULE | |
628 | #include "ioconf.c" | 625 | #include "ioconf.c" | |
629 | #endif | 626 | #endif | |
630 | 627 | |||
631 | USBNET_MODULE(kue) | 628 | USBNET_MODULE(kue) |
--- src/sys/dev/usb/if_mos.c 2022/03/03 05:54:21 1.17
+++ src/sys/dev/usb/if_mos.c 2022/03/03 05:55:01 1.18
@@ -1,768 +1,765 @@ | @@ -1,768 +1,765 @@ | |||
1 | /* $NetBSD: if_mos.c,v 1.17 2022/03/03 05:54:21 riastradh Exp $ */ | 1 | /* $NetBSD: if_mos.c,v 1.18 2022/03/03 05:55:01 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.17 2022/03/03 05:54:21 riastradh Exp $"); | 75 | __KERNEL_RCSID(0, "$NetBSD: if_mos.c,v 1.18 2022/03/03 05:55:01 riastradh Exp $"); | |
76 | 76 | |||
77 | #include <sys/param.h> | 77 | #include <sys/param.h> | |
78 | 78 | |||
79 | #include <dev/usb/usbnet.h> | 79 | #include <dev/usb/usbnet.h> | |
80 | #include <dev/usb/if_mosreg.h> | 80 | #include <dev/usb/if_mosreg.h> | |
81 | 81 | |||
82 | #define MOS_PAUSE_REWRITES 3 | 82 | #define MOS_PAUSE_REWRITES 3 | |
83 | 83 | |||
84 | #define MOS_TIMEOUT 1000 | 84 | #define MOS_TIMEOUT 1000 | |
85 | 85 | |||
86 | #define MOS_RX_LIST_CNT 1 | 86 | #define MOS_RX_LIST_CNT 1 | |
87 | #define MOS_TX_LIST_CNT 1 | 87 | #define MOS_TX_LIST_CNT 1 | |
88 | 88 | |||
89 | /* Maximum size of a fast ethernet frame plus one byte for the status */ | 89 | /* Maximum size of a fast ethernet frame plus one byte for the status */ | |
90 | #define MOS_BUFSZ (ETHER_MAX_LEN+1) | 90 | #define MOS_BUFSZ (ETHER_MAX_LEN+1) | |
91 | 91 | |||
92 | /* | 92 | /* | |
93 | * USB endpoints. | 93 | * USB endpoints. | |
94 | */ | 94 | */ | |
95 | #define MOS_ENDPT_RX 0 | 95 | #define MOS_ENDPT_RX 0 | |
96 | #define MOS_ENDPT_TX 1 | 96 | #define MOS_ENDPT_TX 1 | |
97 | #define MOS_ENDPT_INTR 2 | 97 | #define MOS_ENDPT_INTR 2 | |
98 | #define MOS_ENDPT_MAX 3 | 98 | #define MOS_ENDPT_MAX 3 | |
99 | 99 | |||
100 | /* | 100 | /* | |
101 | * USB vendor requests. | 101 | * USB vendor requests. | |
102 | */ | 102 | */ | |
103 | #define MOS_UR_READREG 0x0e | 103 | #define MOS_UR_READREG 0x0e | |
104 | #define MOS_UR_WRITEREG 0x0d | 104 | #define MOS_UR_WRITEREG 0x0d | |
105 | 105 | |||
106 | #define MOS_CONFIG_NO 1 | 106 | #define MOS_CONFIG_NO 1 | |
107 | #define MOS_IFACE_IDX 0 | 107 | #define MOS_IFACE_IDX 0 | |
108 | 108 | |||
109 | struct mos_type { | 109 | struct mos_type { | |
110 | struct usb_devno mos_dev; | 110 | struct usb_devno mos_dev; | |
111 | u_int16_t mos_flags; | 111 | u_int16_t mos_flags; | |
112 | #define MCS7730 0x0001 /* MCS7730 */ | 112 | #define MCS7730 0x0001 /* MCS7730 */ | |
113 | #define MCS7830 0x0002 /* MCS7830 */ | 113 | #define MCS7830 0x0002 /* MCS7830 */ | |
114 | #define MCS7832 0x0004 /* MCS7832 */ | 114 | #define MCS7832 0x0004 /* MCS7832 */ | |
115 | }; | 115 | }; | |
116 | 116 | |||
117 | #define MOS_INC(x, y) (x) = (x + 1) % y | 117 | #define MOS_INC(x, y) (x) = (x + 1) % y | |
118 | 118 | |||
119 | #ifdef MOS_DEBUG | 119 | #ifdef MOS_DEBUG | |
120 | #define DPRINTF(x) do { if (mosdebug) printf x; } while (0) | 120 | #define DPRINTF(x) do { if (mosdebug) printf x; } while (0) | |
121 | #define DPRINTFN(n,x) do { if (mosdebug >= (n)) printf x; } while (0) | 121 | #define DPRINTFN(n,x) do { if (mosdebug >= (n)) printf x; } while (0) | |
122 | int mosdebug = 0; | 122 | int mosdebug = 0; | |
123 | #else | 123 | #else | |
124 | #define DPRINTF(x) __nothing | 124 | #define DPRINTF(x) __nothing | |
125 | #define DPRINTFN(n,x) __nothing | 125 | #define DPRINTFN(n,x) __nothing | |
126 | #endif | 126 | #endif | |
127 | 127 | |||
128 | /* | 128 | /* | |
129 | * Various supported device vendors/products. | 129 | * Various supported device vendors/products. | |
130 | */ | 130 | */ | |
131 | static const struct mos_type mos_devs[] = { | 131 | static const struct mos_type mos_devs[] = { | |
132 | { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730 }, MCS7730 }, | 132 | { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7730 }, MCS7730 }, | |
133 | { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830 }, MCS7830 }, | 133 | { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7830 }, MCS7830 }, | |
134 | { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7832 }, MCS7832 }, | 134 | { { USB_VENDOR_MOSCHIP, USB_PRODUCT_MOSCHIP_MCS7832 }, MCS7832 }, | |
135 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030 }, MCS7830 }, | 135 | { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN030 }, MCS7830 }, | |
136 | }; | 136 | }; | |
137 | #define mos_lookup(v, p) ((const struct mos_type *)usb_lookup(mos_devs, v, p)) | 137 | #define mos_lookup(v, p) ((const struct mos_type *)usb_lookup(mos_devs, v, p)) | |
138 | 138 | |||
139 | static int mos_match(device_t, cfdata_t, void *); | 139 | static int mos_match(device_t, cfdata_t, void *); | |
140 | static void mos_attach(device_t, device_t, void *); | 140 | static void mos_attach(device_t, device_t, void *); | |
141 | 141 | |||
142 | CFATTACH_DECL_NEW(mos, sizeof(struct usbnet), | 142 | CFATTACH_DECL_NEW(mos, sizeof(struct usbnet), | |
143 | mos_match, mos_attach, usbnet_detach, usbnet_activate); | 143 | mos_match, mos_attach, usbnet_detach, usbnet_activate); | |
144 | 144 | |||
145 | static void mos_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 145 | static void mos_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
146 | static unsigned mos_uno_tx_prepare(struct usbnet *, struct mbuf *, | 146 | static unsigned mos_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
147 | struct usbnet_chain *); | 147 | struct usbnet_chain *); | |
148 | static void mos_uno_mcast(struct ifnet *); | 148 | static void mos_uno_mcast(struct ifnet *); | |
149 | static int mos_uno_init(struct ifnet *); | 149 | static int mos_uno_init(struct ifnet *); | |
150 | static void mos_chip_init(struct usbnet *); | 150 | static void mos_chip_init(struct usbnet *); | |
151 | static void mos_uno_stop(struct ifnet *ifp, int disable); | 151 | static void mos_uno_stop(struct ifnet *ifp, int disable); | |
152 | static int mos_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 152 | static int mos_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
153 | static int mos_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 153 | static int mos_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
154 | static void mos_uno_mii_statchg(struct ifnet *); | 154 | static void mos_uno_mii_statchg(struct ifnet *); | |
155 | static void mos_reset(struct usbnet *); | 155 | static void mos_reset(struct usbnet *); | |
156 | 156 | |||
157 | static int mos_reg_read_1(struct usbnet *, int); | 157 | static int mos_reg_read_1(struct usbnet *, int); | |
158 | static int mos_reg_read_2(struct usbnet *, int); | 158 | static int mos_reg_read_2(struct usbnet *, int); | |
159 | static int mos_reg_write_1(struct usbnet *, int, int); | 159 | static int mos_reg_write_1(struct usbnet *, int, int); | |
160 | static int mos_reg_write_2(struct usbnet *, int, int); | 160 | static int mos_reg_write_2(struct usbnet *, int, int); | |
161 | static int mos_readmac(struct usbnet *); | 161 | static int mos_readmac(struct usbnet *); | |
162 | static int mos_writemac(struct usbnet *); | 162 | static int mos_writemac(struct usbnet *); | |
163 | static int mos_write_mcast(struct usbnet *, uint8_t *); | 163 | static int mos_write_mcast(struct usbnet *, uint8_t *); | |
164 | 164 | |||
165 | static const struct usbnet_ops mos_ops = { | 165 | static const struct usbnet_ops mos_ops = { | |
166 | .uno_stop = mos_uno_stop, | 166 | .uno_stop = mos_uno_stop, | |
167 | .uno_mcast = mos_uno_mcast, | 167 | .uno_mcast = mos_uno_mcast, | |
168 | .uno_read_reg = mos_uno_mii_read_reg, | 168 | .uno_read_reg = mos_uno_mii_read_reg, | |
169 | .uno_write_reg = mos_uno_mii_write_reg, | 169 | .uno_write_reg = mos_uno_mii_write_reg, | |
170 | .uno_statchg = mos_uno_mii_statchg, | 170 | .uno_statchg = mos_uno_mii_statchg, | |
171 | .uno_tx_prepare = mos_uno_tx_prepare, | 171 | .uno_tx_prepare = mos_uno_tx_prepare, | |
172 | .uno_rx_loop = mos_uno_rx_loop, | 172 | .uno_rx_loop = mos_uno_rx_loop, | |
173 | .uno_init = mos_uno_init, | 173 | .uno_init = mos_uno_init, | |
174 | }; | 174 | }; | |
175 | 175 | |||
176 | static int | 176 | static int | |
177 | mos_reg_read_1(struct usbnet *un, int reg) | 177 | mos_reg_read_1(struct usbnet *un, int reg) | |
178 | { | 178 | { | |
179 | usb_device_request_t req; | 179 | usb_device_request_t req; | |
180 | usbd_status err; | 180 | usbd_status err; | |
181 | uByte val = 0; | 181 | uByte val = 0; | |
182 | 182 | |||
183 | if (usbnet_isdying(un)) | 183 | if (usbnet_isdying(un)) | |
184 | return 0; | 184 | return 0; | |
185 | 185 | |||
186 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 186 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
187 | req.bRequest = MOS_UR_READREG; | 187 | req.bRequest = MOS_UR_READREG; | |
188 | USETW(req.wValue, 0); | 188 | USETW(req.wValue, 0); | |
189 | USETW(req.wIndex, reg); | 189 | USETW(req.wIndex, reg); | |
190 | USETW(req.wLength, 1); | 190 | USETW(req.wLength, 1); | |
191 | 191 | |||
192 | err = usbd_do_request(un->un_udev, &req, &val); | 192 | err = usbd_do_request(un->un_udev, &req, &val); | |
193 | 193 | |||
194 | if (err) { | 194 | if (err) { | |
195 | aprint_error_dev(un->un_dev, "read reg %x\n", reg); | 195 | aprint_error_dev(un->un_dev, "read reg %x\n", reg); | |
196 | return 0; | 196 | return 0; | |
197 | } | 197 | } | |
198 | 198 | |||
199 | return val; | 199 | return val; | |
200 | } | 200 | } | |
201 | 201 | |||
202 | static int | 202 | static int | |
203 | mos_reg_read_2(struct usbnet *un, int reg) | 203 | mos_reg_read_2(struct usbnet *un, int reg) | |
204 | { | 204 | { | |
205 | usb_device_request_t req; | 205 | usb_device_request_t req; | |
206 | usbd_status err; | 206 | usbd_status err; | |
207 | uWord val; | 207 | uWord val; | |
208 | 208 | |||
209 | if (usbnet_isdying(un)) | 209 | if (usbnet_isdying(un)) | |
210 | return 0; | 210 | return 0; | |
211 | 211 | |||
212 | USETW(val,0); | 212 | USETW(val,0); | |
213 | 213 | |||
214 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 214 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
215 | req.bRequest = MOS_UR_READREG; | 215 | req.bRequest = MOS_UR_READREG; | |
216 | USETW(req.wValue, 0); | 216 | USETW(req.wValue, 0); | |
217 | USETW(req.wIndex, reg); | 217 | USETW(req.wIndex, reg); | |
218 | USETW(req.wLength, 2); | 218 | USETW(req.wLength, 2); | |
219 | 219 | |||
220 | err = usbd_do_request(un->un_udev, &req, &val); | 220 | err = usbd_do_request(un->un_udev, &req, &val); | |
221 | 221 | |||
222 | if (err) { | 222 | if (err) { | |
223 | aprint_error_dev(un->un_dev, "read reg2 %x\n", reg); | 223 | aprint_error_dev(un->un_dev, "read reg2 %x\n", reg); | |
224 | return 0; | 224 | return 0; | |
225 | } | 225 | } | |
226 | 226 | |||
227 | return UGETW(val); | 227 | return UGETW(val); | |
228 | } | 228 | } | |
229 | 229 | |||
230 | static int | 230 | static int | |
231 | mos_reg_write_1(struct usbnet *un, int reg, int aval) | 231 | mos_reg_write_1(struct usbnet *un, int reg, int aval) | |
232 | { | 232 | { | |
233 | usb_device_request_t req; | 233 | usb_device_request_t req; | |
234 | usbd_status err; | 234 | usbd_status err; | |
235 | uByte val; | 235 | uByte val; | |
236 | 236 | |||
237 | if (usbnet_isdying(un)) | 237 | if (usbnet_isdying(un)) | |
238 | return 0; | 238 | return 0; | |
239 | 239 | |||
240 | val = aval; | 240 | val = aval; | |
241 | 241 | |||
242 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 242 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
243 | req.bRequest = MOS_UR_WRITEREG; | 243 | req.bRequest = MOS_UR_WRITEREG; | |
244 | USETW(req.wValue, 0); | 244 | USETW(req.wValue, 0); | |
245 | USETW(req.wIndex, reg); | 245 | USETW(req.wIndex, reg); | |
246 | USETW(req.wLength, 1); | 246 | USETW(req.wLength, 1); | |
247 | 247 | |||
248 | err = usbd_do_request(un->un_udev, &req, &val); | 248 | err = usbd_do_request(un->un_udev, &req, &val); | |
249 | 249 | |||
250 | if (err) | 250 | if (err) | |
251 | aprint_error_dev(un->un_dev, "write reg %x <- %x\n", | 251 | aprint_error_dev(un->un_dev, "write reg %x <- %x\n", | |
252 | reg, aval); | 252 | reg, aval); | |
253 | 253 | |||
254 | return 0; | 254 | return 0; | |
255 | } | 255 | } | |
256 | 256 | |||
257 | static int | 257 | static int | |
258 | mos_reg_write_2(struct usbnet *un, int reg, int aval) | 258 | mos_reg_write_2(struct usbnet *un, int reg, int aval) | |
259 | { | 259 | { | |
260 | usb_device_request_t req; | 260 | usb_device_request_t req; | |
261 | usbd_status err; | 261 | usbd_status err; | |
262 | uWord val; | 262 | uWord val; | |
263 | 263 | |||
264 | USETW(val, aval); | 264 | USETW(val, aval); | |
265 | 265 | |||
266 | if (usbnet_isdying(un)) | 266 | if (usbnet_isdying(un)) | |
267 | return EIO; | 267 | return EIO; | |
268 | 268 | |||
269 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 269 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
270 | req.bRequest = MOS_UR_WRITEREG; | 270 | req.bRequest = MOS_UR_WRITEREG; | |
271 | USETW(req.wValue, 0); | 271 | USETW(req.wValue, 0); | |
272 | USETW(req.wIndex, reg); | 272 | USETW(req.wIndex, reg); | |
273 | USETW(req.wLength, 2); | 273 | USETW(req.wLength, 2); | |
274 | 274 | |||
275 | err = usbd_do_request(un->un_udev, &req, &val); | 275 | err = usbd_do_request(un->un_udev, &req, &val); | |
276 | 276 | |||
277 | if (err) | 277 | if (err) | |
278 | aprint_error_dev(un->un_dev, "write reg2 %x <- %x\n", | 278 | aprint_error_dev(un->un_dev, "write reg2 %x <- %x\n", | |
279 | reg, aval); | 279 | reg, aval); | |
280 | 280 | |||
281 | return 0; | 281 | return 0; | |
282 | } | 282 | } | |
283 | 283 | |||
284 | static int | 284 | static int | |
285 | mos_readmac(struct usbnet *un) | 285 | mos_readmac(struct usbnet *un) | |
286 | { | 286 | { | |
287 | usb_device_request_t req; | 287 | usb_device_request_t req; | |
288 | usbd_status err; | 288 | usbd_status err; | |
289 | 289 | |||
290 | if (usbnet_isdying(un)) | 290 | if (usbnet_isdying(un)) | |
291 | return 0; | 291 | return 0; | |
292 | 292 | |||
293 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 293 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
294 | req.bRequest = MOS_UR_READREG; | 294 | req.bRequest = MOS_UR_READREG; | |
295 | USETW(req.wValue, 0); | 295 | USETW(req.wValue, 0); | |
296 | USETW(req.wIndex, MOS_MAC); | 296 | USETW(req.wIndex, MOS_MAC); | |
297 | USETW(req.wLength, ETHER_ADDR_LEN); | 297 | USETW(req.wLength, ETHER_ADDR_LEN); | |
298 | 298 | |||
299 | err = usbd_do_request(un->un_udev, &req, un->un_eaddr); | 299 | err = usbd_do_request(un->un_udev, &req, un->un_eaddr); | |
300 | 300 | |||
301 | if (err) | 301 | if (err) | |
302 | aprint_error_dev(un->un_dev, "%s: failed", __func__); | 302 | aprint_error_dev(un->un_dev, "%s: failed", __func__); | |
303 | 303 | |||
304 | return err; | 304 | return err; | |
305 | } | 305 | } | |
306 | 306 | |||
307 | static int | 307 | static int | |
308 | mos_writemac(struct usbnet *un) | 308 | mos_writemac(struct usbnet *un) | |
309 | { | 309 | { | |
310 | usb_device_request_t req; | 310 | usb_device_request_t req; | |
311 | usbd_status err; | 311 | usbd_status err; | |
312 | 312 | |||
313 | if (usbnet_isdying(un)) | 313 | if (usbnet_isdying(un)) | |
314 | return 0; | 314 | return 0; | |
315 | 315 | |||
316 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 316 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
317 | req.bRequest = MOS_UR_WRITEREG; | 317 | req.bRequest = MOS_UR_WRITEREG; | |
318 | USETW(req.wValue, 0); | 318 | USETW(req.wValue, 0); | |
319 | USETW(req.wIndex, MOS_MAC); | 319 | USETW(req.wIndex, MOS_MAC); | |
320 | USETW(req.wLength, ETHER_ADDR_LEN); | 320 | USETW(req.wLength, ETHER_ADDR_LEN); | |
321 | 321 | |||
322 | err = usbd_do_request(un->un_udev, &req, un->un_eaddr); | 322 | err = usbd_do_request(un->un_udev, &req, un->un_eaddr); | |
323 | 323 | |||
324 | if (err) | 324 | if (err) | |
325 | aprint_error_dev(un->un_dev, "%s: failed", __func__); | 325 | aprint_error_dev(un->un_dev, "%s: failed", __func__); | |
326 | 326 | |||
327 | return 0; | 327 | return 0; | |
328 | } | 328 | } | |
329 | 329 | |||
330 | static int | 330 | static int | |
331 | mos_write_mcast(struct usbnet *un, uint8_t *hashtbl) | 331 | mos_write_mcast(struct usbnet *un, uint8_t *hashtbl) | |
332 | { | 332 | { | |
333 | usb_device_request_t req; | 333 | usb_device_request_t req; | |
334 | usbd_status err; | 334 | usbd_status err; | |
335 | 335 | |||
336 | if (usbnet_isdying(un)) | 336 | if (usbnet_isdying(un)) | |
337 | return EIO; | 337 | return EIO; | |
338 | 338 | |||
339 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 339 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
340 | req.bRequest = MOS_UR_WRITEREG; | 340 | req.bRequest = MOS_UR_WRITEREG; | |
341 | USETW(req.wValue, 0); | 341 | USETW(req.wValue, 0); | |
342 | USETW(req.wIndex, MOS_MCAST_TABLE); | 342 | USETW(req.wIndex, MOS_MCAST_TABLE); | |
343 | USETW(req.wLength, 8); | 343 | USETW(req.wLength, 8); | |
344 | 344 | |||
345 | err = usbd_do_request(un->un_udev, &req, hashtbl); | 345 | err = usbd_do_request(un->un_udev, &req, hashtbl); | |
346 | 346 | |||
347 | if (err) { | 347 | if (err) { | |
348 | aprint_error_dev(un->un_dev, "%s: failed", __func__); | 348 | aprint_error_dev(un->un_dev, "%s: failed", __func__); | |
349 | return(-1); | 349 | return(-1); | |
350 | } | 350 | } | |
351 | 351 | |||
352 | return 0; | 352 | return 0; | |
353 | } | 353 | } | |
354 | 354 | |||
355 | static int | 355 | static int | |
356 | mos_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 356 | mos_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
357 | { | 357 | { | |
358 | int i, res; | 358 | int i, res; | |
359 | 359 | |||
360 | mos_reg_write_2(un, MOS_PHY_DATA, 0); | 360 | mos_reg_write_2(un, MOS_PHY_DATA, 0); | |
361 | mos_reg_write_1(un, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | | 361 | mos_reg_write_1(un, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | | |
362 | MOS_PHYCTL_READ); | 362 | MOS_PHYCTL_READ); | |
363 | mos_reg_write_1(un, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | | 363 | mos_reg_write_1(un, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | | |
364 | MOS_PHYSTS_PENDING); | 364 | MOS_PHYSTS_PENDING); | |
365 | 365 | |||
366 | for (i = 0; i < MOS_TIMEOUT; i++) { | 366 | for (i = 0; i < MOS_TIMEOUT; i++) { | |
367 | if (usbnet_isdying(un)) { | 367 | if (usbnet_isdying(un)) { | |
368 | *val = 0; | 368 | *val = 0; | |
369 | return ENXIO; | 369 | return ENXIO; | |
370 | } | 370 | } | |
371 | if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY) | 371 | if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY) | |
372 | break; | 372 | break; | |
373 | } | 373 | } | |
374 | if (i == MOS_TIMEOUT) { | 374 | if (i == MOS_TIMEOUT) { | |
375 | aprint_error_dev(un->un_dev, "read PHY failed\n"); | 375 | aprint_error_dev(un->un_dev, "read PHY failed\n"); | |
376 | *val = 0; | 376 | *val = 0; | |
377 | return EIO; | 377 | return EIO; | |
378 | } | 378 | } | |
379 | 379 | |||
380 | res = mos_reg_read_2(un, MOS_PHY_DATA); | 380 | res = mos_reg_read_2(un, MOS_PHY_DATA); | |
381 | *val = res; | 381 | *val = res; | |
382 | 382 | |||
383 | DPRINTFN(10,("%s: %s: phy %d reg %d val %u\n", | 383 | DPRINTFN(10,("%s: %s: phy %d reg %d val %u\n", | |
384 | device_xname(un->un_dev), __func__, phy, reg, res)); | 384 | device_xname(un->un_dev), __func__, phy, reg, res)); | |
385 | 385 | |||
386 | return 0; | 386 | return 0; | |
387 | } | 387 | } | |
388 | 388 | |||
389 | static int | 389 | static int | |
390 | mos_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 390 | mos_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
391 | { | 391 | { | |
392 | int i; | 392 | int i; | |
393 | 393 | |||
394 | DPRINTFN(10,("%s: %s: phy %d reg %d val %u\n", | 394 | DPRINTFN(10,("%s: %s: phy %d reg %d val %u\n", | |
395 | device_xname(un->un_dev), __func__, phy, reg, val)); | 395 | device_xname(un->un_dev), __func__, phy, reg, val)); | |
396 | 396 | |||
397 | mos_reg_write_2(un, MOS_PHY_DATA, val); | 397 | mos_reg_write_2(un, MOS_PHY_DATA, val); | |
398 | mos_reg_write_1(un, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | | 398 | mos_reg_write_1(un, MOS_PHY_CTL, (phy & MOS_PHYCTL_PHYADDR) | | |
399 | MOS_PHYCTL_WRITE); | 399 | MOS_PHYCTL_WRITE); | |
400 | mos_reg_write_1(un, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | | 400 | mos_reg_write_1(un, MOS_PHY_STS, (reg & MOS_PHYSTS_PHYREG) | | |
401 | MOS_PHYSTS_PENDING); | 401 | MOS_PHYSTS_PENDING); | |
402 | 402 | |||
403 | for (i = 0; i < MOS_TIMEOUT; i++) { | 403 | for (i = 0; i < MOS_TIMEOUT; i++) { | |
404 | if (usbnet_isdying(un)) | 404 | if (usbnet_isdying(un)) | |
405 | return ENXIO; | 405 | return ENXIO; | |
406 | if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY) | 406 | if (mos_reg_read_1(un, MOS_PHY_STS) & MOS_PHYSTS_READY) | |
407 | break; | 407 | break; | |
408 | } | 408 | } | |
409 | if (i == MOS_TIMEOUT) { | 409 | if (i == MOS_TIMEOUT) { | |
410 | aprint_error_dev(un->un_dev, "write PHY failed\n"); | 410 | aprint_error_dev(un->un_dev, "write PHY failed\n"); | |
411 | return EIO; | 411 | return EIO; | |
412 | } | 412 | } | |
413 | 413 | |||
414 | return 0; | 414 | return 0; | |
415 | } | 415 | } | |
416 | 416 | |||
417 | void | 417 | void | |
418 | mos_uno_mii_statchg(struct ifnet *ifp) | 418 | mos_uno_mii_statchg(struct ifnet *ifp) | |
419 | { | 419 | { | |
420 | struct usbnet * const un = ifp->if_softc; | 420 | struct usbnet * const un = ifp->if_softc; | |
421 | struct mii_data * const mii = usbnet_mii(un); | 421 | struct mii_data * const mii = usbnet_mii(un); | |
422 | int val, err; | 422 | int val, err; | |
423 | 423 | |||
424 | if (usbnet_isdying(un)) | 424 | if (usbnet_isdying(un)) | |
425 | return; | 425 | return; | |
426 | 426 | |||
427 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 427 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
428 | 428 | |||
429 | /* disable RX, TX prior to changing FDX, SPEEDSEL */ | 429 | /* disable RX, TX prior to changing FDX, SPEEDSEL */ | |
430 | val = mos_reg_read_1(un, MOS_CTL); | 430 | val = mos_reg_read_1(un, MOS_CTL); | |
431 | val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); | 431 | val &= ~(MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); | |
432 | mos_reg_write_1(un, MOS_CTL, val); | 432 | mos_reg_write_1(un, MOS_CTL, val); | |
433 | 433 | |||
434 | /* reset register which counts dropped frames */ | 434 | /* reset register which counts dropped frames */ | |
435 | mos_reg_write_1(un, MOS_FRAME_DROP_CNT, 0); | 435 | mos_reg_write_1(un, MOS_FRAME_DROP_CNT, 0); | |
436 | 436 | |||
437 | if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) | 437 | if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) | |
438 | val |= MOS_CTL_FDX_ENB; | 438 | val |= MOS_CTL_FDX_ENB; | |
439 | else | 439 | else | |
440 | val &= ~(MOS_CTL_FDX_ENB); | 440 | val &= ~(MOS_CTL_FDX_ENB); | |
441 | 441 | |||
442 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 442 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
443 | (IFM_ACTIVE | IFM_AVALID)) { | 443 | (IFM_ACTIVE | IFM_AVALID)) { | |
444 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 444 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
445 | case IFM_100_TX: | 445 | case IFM_100_TX: | |
446 | val |= MOS_CTL_SPEEDSEL; | 446 | val |= MOS_CTL_SPEEDSEL; | |
447 | break; | 447 | break; | |
448 | case IFM_10_T: | 448 | case IFM_10_T: | |
449 | val &= ~(MOS_CTL_SPEEDSEL); | 449 | val &= ~(MOS_CTL_SPEEDSEL); | |
450 | break; | 450 | break; | |
451 | } | 451 | } | |
452 | usbnet_set_link(un, true); | 452 | usbnet_set_link(un, true); | |
453 | } | 453 | } | |
454 | 454 | |||
455 | /* re-enable TX, RX */ | 455 | /* re-enable TX, RX */ | |
456 | val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); | 456 | val |= (MOS_CTL_TX_ENB | MOS_CTL_RX_ENB); | |
457 | err = mos_reg_write_1(un, MOS_CTL, val); | 457 | err = mos_reg_write_1(un, MOS_CTL, val); | |
458 | 458 | |||
459 | if (err) | 459 | if (err) | |
460 | aprint_error_dev(un->un_dev, "media change failed\n"); | 460 | aprint_error_dev(un->un_dev, "media change failed\n"); | |
461 | } | 461 | } | |
462 | 462 | |||
463 | static void | 463 | static void | |
464 | mos_uno_mcast(struct ifnet *ifp) | 464 | mos_uno_mcast(struct ifnet *ifp) | |
465 | { | 465 | { | |
466 | struct usbnet *un = ifp->if_softc; | 466 | struct usbnet *un = ifp->if_softc; | |
467 | struct ethercom *ec = usbnet_ec(un); | 467 | struct ethercom *ec = usbnet_ec(un); | |
468 | struct ether_multi *enm; | 468 | struct ether_multi *enm; | |
469 | struct ether_multistep step; | 469 | struct ether_multistep step; | |
470 | u_int32_t h = 0; | 470 | u_int32_t h = 0; | |
471 | u_int8_t rxmode, mchash[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | 471 | u_int8_t rxmode, mchash[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
472 | 472 | |||
473 | if (usbnet_isdying(un)) | 473 | if (usbnet_isdying(un)) | |
474 | return; | 474 | return; | |
475 | 475 | |||
476 | rxmode = mos_reg_read_1(un, MOS_CTL); | 476 | rxmode = mos_reg_read_1(un, MOS_CTL); | |
477 | rxmode &= ~(MOS_CTL_ALLMULTI | MOS_CTL_RX_PROMISC); | 477 | rxmode &= ~(MOS_CTL_ALLMULTI | MOS_CTL_RX_PROMISC); | |
478 | 478 | |||
479 | ETHER_LOCK(ec); | 479 | ETHER_LOCK(ec); | |
480 | if (ifp->if_flags & IFF_PROMISC) { | 480 | if (ifp->if_flags & IFF_PROMISC) { | |
481 | ec->ec_flags |= ETHER_F_ALLMULTI; | 481 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
482 | ETHER_UNLOCK(ec); | 482 | ETHER_UNLOCK(ec); | |
483 | /* run promisc. mode */ | 483 | /* run promisc. mode */ | |
484 | rxmode |= MOS_CTL_ALLMULTI; /* ??? */ | 484 | rxmode |= MOS_CTL_ALLMULTI; /* ??? */ | |
485 | rxmode |= MOS_CTL_RX_PROMISC; | 485 | rxmode |= MOS_CTL_RX_PROMISC; | |
486 | goto update; | 486 | goto update; | |
487 | } | 487 | } | |
488 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 488 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
489 | ETHER_FIRST_MULTI(step, ec, enm); | 489 | ETHER_FIRST_MULTI(step, ec, enm); | |
490 | while (enm != NULL) { | 490 | while (enm != NULL) { | |
491 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 491 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
492 | ec->ec_flags |= ETHER_F_ALLMULTI; | 492 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
493 | ETHER_UNLOCK(ec); | 493 | ETHER_UNLOCK(ec); | |
494 | memset(mchash, 0, sizeof(mchash)); /* correct ??? */ | 494 | memset(mchash, 0, sizeof(mchash)); /* correct ??? */ | |
495 | /* accept all multicast frame */ | 495 | /* accept all multicast frame */ | |
496 | rxmode |= MOS_CTL_ALLMULTI; | 496 | rxmode |= MOS_CTL_ALLMULTI; | |
497 | goto update; | 497 | goto update; | |
498 | } | 498 | } | |
499 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | 499 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | |
500 | /* 3(31:29) and 3(28:26) sampling to have uint8_t[8] */ | 500 | /* 3(31:29) and 3(28:26) sampling to have uint8_t[8] */ | |
501 | mchash[h >> 29] |= 1 << ((h >> 26) % 8); | 501 | mchash[h >> 29] |= 1 << ((h >> 26) % 8); | |
502 | ETHER_NEXT_MULTI(step, enm); | 502 | ETHER_NEXT_MULTI(step, enm); | |
503 | } | 503 | } | |
504 | ETHER_UNLOCK(ec); | 504 | ETHER_UNLOCK(ec); | |
505 | /* MOS receive filter is always on */ | 505 | /* MOS receive filter is always on */ | |
506 | update: | 506 | update: | |
507 | /* | 507 | /* | |
508 | * The datasheet claims broadcast frames were always accepted | 508 | * The datasheet claims broadcast frames were always accepted | |
509 | * regardless of filter settings. But the hardware seems to | 509 | * regardless of filter settings. But the hardware seems to | |
510 | * filter broadcast frames, so pass them explicitly. | 510 | * filter broadcast frames, so pass them explicitly. | |
511 | */ | 511 | */ | |
512 | mchash[7] |= 0x80; | 512 | mchash[7] |= 0x80; | |
513 | mos_write_mcast(un, mchash); | 513 | mos_write_mcast(un, mchash); | |
514 | mos_reg_write_1(un, MOS_CTL, rxmode); | 514 | mos_reg_write_1(un, MOS_CTL, rxmode); | |
515 | } | 515 | } | |
516 | 516 | |||
517 | static void | 517 | static void | |
518 | mos_reset(struct usbnet *un) | 518 | mos_reset(struct usbnet *un) | |
519 | { | 519 | { | |
520 | u_int8_t ctl; | 520 | u_int8_t ctl; | |
521 | 521 | |||
522 | if (usbnet_isdying(un)) | 522 | if (usbnet_isdying(un)) | |
523 | return; | 523 | return; | |
524 | 524 | |||
525 | ctl = mos_reg_read_1(un, MOS_CTL); | 525 | ctl = mos_reg_read_1(un, MOS_CTL); | |
526 | ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB | | 526 | ctl &= ~(MOS_CTL_RX_PROMISC | MOS_CTL_ALLMULTI | MOS_CTL_TX_ENB | | |
527 | MOS_CTL_RX_ENB); | 527 | MOS_CTL_RX_ENB); | |
528 | /* Disable RX, TX, promiscuous and allmulticast mode */ | 528 | /* Disable RX, TX, promiscuous and allmulticast mode */ | |
529 | mos_reg_write_1(un, MOS_CTL, ctl); | 529 | mos_reg_write_1(un, MOS_CTL, ctl); | |
530 | 530 | |||
531 | /* Reset frame drop counter register to zero */ | 531 | /* Reset frame drop counter register to zero */ | |
532 | mos_reg_write_1(un, MOS_FRAME_DROP_CNT, 0); | 532 | mos_reg_write_1(un, MOS_FRAME_DROP_CNT, 0); | |
533 | 533 | |||
534 | /* Wait a little while for the chip to get its brains in order. */ | 534 | /* Wait a little while for the chip to get its brains in order. */ | |
535 | DELAY(1000); | 535 | DELAY(1000); | |
536 | } | 536 | } | |
537 | 537 | |||
538 | void | 538 | void | |
539 | mos_chip_init(struct usbnet *un) | 539 | mos_chip_init(struct usbnet *un) | |
540 | { | 540 | { | |
541 | int i; | 541 | int i; | |
542 | 542 | |||
543 | /* | 543 | /* | |
544 | * Rev.C devices have a pause threshold register which needs to be set | 544 | * Rev.C devices have a pause threshold register which needs to be set | |
545 | * at startup. | 545 | * at startup. | |
546 | */ | 546 | */ | |
547 | if (mos_reg_read_1(un, MOS_PAUSE_TRHD) != -1) { | 547 | if (mos_reg_read_1(un, MOS_PAUSE_TRHD) != -1) { | |
548 | for (i = 0; i < MOS_PAUSE_REWRITES; i++) | 548 | for (i = 0; i < MOS_PAUSE_REWRITES; i++) | |
549 | mos_reg_write_1(un, MOS_PAUSE_TRHD, 0); | 549 | mos_reg_write_1(un, MOS_PAUSE_TRHD, 0); | |
550 | } | 550 | } | |
551 | } | 551 | } | |
552 | 552 | |||
553 | /* | 553 | /* | |
554 | * Probe for a MCS7x30 chip. | 554 | * Probe for a MCS7x30 chip. | |
555 | */ | 555 | */ | |
556 | static int | 556 | static int | |
557 | mos_match(device_t parent, cfdata_t match, void *aux) | 557 | mos_match(device_t parent, cfdata_t match, void *aux) | |
558 | { | 558 | { | |
559 | struct usb_attach_arg *uaa = aux; | 559 | struct usb_attach_arg *uaa = aux; | |
560 | 560 | |||
561 | return (mos_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 561 | return (mos_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
562 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE); | 562 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE); | |
563 | } | 563 | } | |
564 | 564 | |||
565 | /* | 565 | /* | |
566 | * Attach the interface. | 566 | * Attach the interface. | |
567 | */ | 567 | */ | |
568 | static void | 568 | static void | |
569 | mos_attach(device_t parent, device_t self, void *aux) | 569 | mos_attach(device_t parent, device_t self, void *aux) | |
570 | { | 570 | { | |
571 | USBNET_MII_DECL_DEFAULT(unm); | 571 | USBNET_MII_DECL_DEFAULT(unm); | |
572 | struct usbnet * un = device_private(self); | 572 | struct usbnet * un = device_private(self); | |
573 | struct usb_attach_arg *uaa = aux; | 573 | struct usb_attach_arg *uaa = aux; | |
574 | struct usbd_device *dev = uaa->uaa_device; | 574 | struct usbd_device *dev = uaa->uaa_device; | |
575 | usbd_status err; | 575 | usbd_status err; | |
576 | usb_interface_descriptor_t *id; | 576 | usb_interface_descriptor_t *id; | |
577 | usb_endpoint_descriptor_t *ed; | 577 | usb_endpoint_descriptor_t *ed; | |
578 | char *devinfop; | 578 | char *devinfop; | |
579 | int i; | 579 | int i; | |
580 | 580 | |||
581 | aprint_naive("\n"); | 581 | aprint_naive("\n"); | |
582 | aprint_normal("\n"); | 582 | aprint_normal("\n"); | |
583 | devinfop = usbd_devinfo_alloc(dev, 0); | 583 | devinfop = usbd_devinfo_alloc(dev, 0); | |
584 | aprint_normal_dev(self, "%s\n", devinfop); | 584 | aprint_normal_dev(self, "%s\n", devinfop); | |
585 | usbd_devinfo_free(devinfop); | 585 | usbd_devinfo_free(devinfop); | |
586 | 586 | |||
587 | un->un_dev = self; | 587 | un->un_dev = self; | |
588 | un->un_udev = dev; | 588 | un->un_udev = dev; | |
589 | un->un_sc = un; | 589 | un->un_sc = un; | |
590 | un->un_ops = &mos_ops; | 590 | un->un_ops = &mos_ops; | |
591 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 591 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
592 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 592 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
593 | un->un_rx_list_cnt = MOS_RX_LIST_CNT; | 593 | un->un_rx_list_cnt = MOS_RX_LIST_CNT; | |
594 | un->un_tx_list_cnt = MOS_TX_LIST_CNT; | 594 | un->un_tx_list_cnt = MOS_TX_LIST_CNT; | |
595 | un->un_rx_bufsz = un->un_tx_bufsz = MOS_BUFSZ; | 595 | un->un_rx_bufsz = un->un_tx_bufsz = MOS_BUFSZ; | |
596 | 596 | |||
597 | err = usbd_set_config_no(dev, MOS_CONFIG_NO, 1); | 597 | err = usbd_set_config_no(dev, MOS_CONFIG_NO, 1); | |
598 | if (err) { | 598 | if (err) { | |
599 | aprint_error_dev(self, "failed to set configuration" | 599 | aprint_error_dev(self, "failed to set configuration" | |
600 | ", err=%s\n", usbd_errstr(err)); | 600 | ", err=%s\n", usbd_errstr(err)); | |
601 | return; | 601 | return; | |
602 | } | 602 | } | |
603 | 603 | |||
604 | err = usbd_device2interface_handle(dev, MOS_IFACE_IDX, &un->un_iface); | 604 | err = usbd_device2interface_handle(dev, MOS_IFACE_IDX, &un->un_iface); | |
605 | if (err) { | 605 | if (err) { | |
606 | aprint_error_dev(self, "failed getting interface handle" | 606 | aprint_error_dev(self, "failed getting interface handle" | |
607 | ", err=%s\n", usbd_errstr(err)); | 607 | ", err=%s\n", usbd_errstr(err)); | |
608 | return; | 608 | return; | |
609 | } | 609 | } | |
610 | 610 | |||
611 | un->un_flags = mos_lookup(uaa->uaa_vendor, uaa->uaa_product)->mos_flags; | 611 | un->un_flags = mos_lookup(uaa->uaa_vendor, uaa->uaa_product)->mos_flags; | |
612 | 612 | |||
613 | id = usbd_get_interface_descriptor(un->un_iface); | 613 | id = usbd_get_interface_descriptor(un->un_iface); | |
614 | 614 | |||
615 | /* Find endpoints. */ | 615 | /* Find endpoints. */ | |
616 | for (i = 0; i < id->bNumEndpoints; i++) { | 616 | for (i = 0; i < id->bNumEndpoints; i++) { | |
617 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 617 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
618 | if (!ed) { | 618 | if (!ed) { | |
619 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 619 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
620 | return; | 620 | return; | |
621 | } | 621 | } | |
622 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 622 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
623 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 623 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
624 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 624 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
625 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 625 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
626 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 626 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
627 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 627 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
628 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 628 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
629 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 629 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
630 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 630 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
631 | } | 631 | } | |
632 | } | 632 | } | |
633 | 633 | |||
634 | if (un->un_flags & MCS7730) | 634 | if (un->un_flags & MCS7730) | |
635 | aprint_normal_dev(self, "MCS7730\n"); | 635 | aprint_normal_dev(self, "MCS7730\n"); | |
636 | else if (un->un_flags & MCS7830) | 636 | else if (un->un_flags & MCS7830) | |
637 | aprint_normal_dev(self, "MCS7830\n"); | 637 | aprint_normal_dev(self, "MCS7830\n"); | |
638 | else if (un->un_flags & MCS7832) | 638 | else if (un->un_flags & MCS7832) | |
639 | aprint_normal_dev(self, "MCS7832\n"); | 639 | aprint_normal_dev(self, "MCS7832\n"); | |
640 | 640 | |||
641 | /* Set these up now for register access. */ | 641 | /* Set these up now for register access. */ | |
642 | usbnet_attach(un, "mosdet"); | 642 | usbnet_attach(un, "mosdet"); | |
643 | 643 | |||
644 | mos_chip_init(un); | 644 | mos_chip_init(un); | |
645 | 645 | |||
646 | /* | 646 | /* | |
647 | * Read MAC address, inform the world. | 647 | * Read MAC address, inform the world. | |
648 | */ | 648 | */ | |
649 | err = mos_readmac(un); | 649 | err = mos_readmac(un); | |
650 | if (err) { | 650 | if (err) { | |
651 | aprint_error_dev(self, "couldn't read MAC address\n"); | 651 | aprint_error_dev(self, "couldn't read MAC address\n"); | |
652 | return; | 652 | return; | |
653 | } | 653 | } | |
654 | 654 | |||
655 | struct ifnet *ifp = usbnet_ifp(un); | 655 | struct ifnet *ifp = usbnet_ifp(un); | |
656 | ifp->if_capabilities = ETHERCAP_VLAN_MTU; | 656 | ifp->if_capabilities = ETHERCAP_VLAN_MTU; | |
657 | 657 | |||
658 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 658 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
659 | 0, &unm); | 659 | 0, &unm); | |
660 | } | 660 | } | |
661 | 661 | |||
662 | /* | 662 | /* | |
663 | * A frame has been uploaded: pass the resulting mbuf chain up to | 663 | * A frame has been uploaded: pass the resulting mbuf chain up to | |
664 | * the higher level protocols. | 664 | * the higher level protocols. | |
665 | */ | 665 | */ | |
666 | void | 666 | void | |
667 | mos_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) | 667 | mos_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) | |
668 | { | 668 | { | |
669 | struct ifnet *ifp = usbnet_ifp(un); | 669 | struct ifnet *ifp = usbnet_ifp(un); | |
670 | uint8_t *buf = c->unc_buf; | 670 | uint8_t *buf = c->unc_buf; | |
671 | u_int8_t rxstat; | 671 | u_int8_t rxstat; | |
672 | u_int16_t pktlen = 0; | 672 | u_int16_t pktlen = 0; | |
673 | 673 | |||
674 | DPRINTFN(5,("%s: %s: enter len %u\n", | 674 | DPRINTFN(5,("%s: %s: enter len %u\n", | |
675 | device_xname(un->un_dev), __func__, total_len)); | 675 | device_xname(un->un_dev), __func__, total_len)); | |
676 | 676 | |||
677 | if (total_len <= 1) | 677 | if (total_len <= 1) | |
678 | return; | 678 | return; | |
679 | 679 | |||
680 | /* evaluate status byte at the end */ | 680 | /* evaluate status byte at the end */ | |
681 | pktlen = total_len - 1; | 681 | pktlen = total_len - 1; | |
682 | if (pktlen > un->un_rx_bufsz) { | 682 | if (pktlen > un->un_rx_bufsz) { | |
683 | if_statinc(ifp, if_ierrors); | 683 | if_statinc(ifp, if_ierrors); | |
684 | return; | 684 | return; | |
685 | } | 685 | } | |
686 | rxstat = buf[pktlen] & MOS_RXSTS_MASK; | 686 | rxstat = buf[pktlen] & MOS_RXSTS_MASK; | |
687 | 687 | |||
688 | if (rxstat != MOS_RXSTS_VALID) { | 688 | if (rxstat != MOS_RXSTS_VALID) { | |
689 | DPRINTF(("%s: erroneous frame received: ", | 689 | DPRINTF(("%s: erroneous frame received: ", | |
690 | device_xname(un->un_dev))); | 690 | device_xname(un->un_dev))); | |
691 | if (rxstat & MOS_RXSTS_SHORT_FRAME) | 691 | if (rxstat & MOS_RXSTS_SHORT_FRAME) | |
692 | DPRINTF(("frame size less than 64 bytes\n")); | 692 | DPRINTF(("frame size less than 64 bytes\n")); | |
693 | if (rxstat & MOS_RXSTS_LARGE_FRAME) | 693 | if (rxstat & MOS_RXSTS_LARGE_FRAME) | |
694 | DPRINTF(("frame size larger than 1532 bytes\n")); | 694 | DPRINTF(("frame size larger than 1532 bytes\n")); | |
695 | if (rxstat & MOS_RXSTS_CRC_ERROR) | 695 | if (rxstat & MOS_RXSTS_CRC_ERROR) | |
696 | DPRINTF(("CRC error\n")); | 696 | DPRINTF(("CRC error\n")); | |
697 | if (rxstat & MOS_RXSTS_ALIGN_ERROR) | 697 | if (rxstat & MOS_RXSTS_ALIGN_ERROR) | |
698 | DPRINTF(("alignment error\n")); | 698 | DPRINTF(("alignment error\n")); | |
699 | if_statinc(ifp, if_ierrors); | 699 | if_statinc(ifp, if_ierrors); | |
700 | return; | 700 | return; | |
701 | } | 701 | } | |
702 | 702 | |||
703 | if (pktlen < sizeof(struct ether_header) ) { | 703 | if (pktlen < sizeof(struct ether_header) ) { | |
704 | if_statinc(ifp, if_ierrors); | 704 | if_statinc(ifp, if_ierrors); | |
705 | return; | 705 | return; | |
706 | } | 706 | } | |
707 | 707 | |||
708 | usbnet_enqueue(un, c->unc_buf, pktlen, 0, 0, 0); | 708 | usbnet_enqueue(un, c->unc_buf, pktlen, 0, 0, 0); | |
709 | } | 709 | } | |
710 | 710 | |||
711 | static unsigned | 711 | static unsigned | |
712 | mos_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 712 | mos_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
713 | { | 713 | { | |
714 | int length; | 714 | int length; | |
715 | 715 | |||
716 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | 716 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | |
717 | return 0; | 717 | return 0; | |
718 | 718 | |||
719 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | 719 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | |
720 | length = m->m_pkthdr.len; | 720 | length = m->m_pkthdr.len; | |
721 | 721 | |||
722 | DPRINTFN(5,("%s: %s: len %u\n", | 722 | DPRINTFN(5,("%s: %s: len %u\n", | |
723 | device_xname(un->un_dev), __func__, length)); | 723 | device_xname(un->un_dev), __func__, length)); | |
724 | 724 | |||
725 | return length; | 725 | return length; | |
726 | } | 726 | } | |
727 | 727 | |||
728 | static int | 728 | static int | |
729 | mos_uno_init(struct ifnet *ifp) | 729 | mos_uno_init(struct ifnet *ifp) | |
730 | { | 730 | { | |
731 | struct usbnet * const un = ifp->if_softc; | 731 | struct usbnet * const un = ifp->if_softc; | |
732 | u_int8_t rxmode; | 732 | u_int8_t rxmode; | |
733 | unsigned char ipgs[2]; | 733 | unsigned char ipgs[2]; | |
734 | 734 | |||
735 | if (usbnet_isdying(un)) | |||
736 | return EIO; | |||
737 | ||||
738 | /* Cancel pending I/O */ | 735 | /* Cancel pending I/O */ | |
739 | usbnet_stop(un, ifp, 1); | 736 | usbnet_stop(un, ifp, 1); | |
740 | 737 | |||
741 | /* Reset the ethernet interface. */ | 738 | /* Reset the ethernet interface. */ | |
742 | mos_reset(un); | 739 | mos_reset(un); | |
743 | 740 | |||
744 | /* Write MAC address. */ | 741 | /* Write MAC address. */ | |
745 | mos_writemac(un); | 742 | mos_writemac(un); | |
746 | 743 | |||
747 | /* Read and set transmitter IPG values */ | 744 | /* Read and set transmitter IPG values */ | |
748 | ipgs[0] = mos_reg_read_1(un, MOS_IPG0); | 745 | ipgs[0] = mos_reg_read_1(un, MOS_IPG0); | |
749 | ipgs[1] = mos_reg_read_1(un, MOS_IPG1); | 746 | ipgs[1] = mos_reg_read_1(un, MOS_IPG1); | |
750 | mos_reg_write_1(un, MOS_IPG0, ipgs[0]); | 747 | mos_reg_write_1(un, MOS_IPG0, ipgs[0]); | |
751 | mos_reg_write_1(un, MOS_IPG1, ipgs[1]); | 748 | mos_reg_write_1(un, MOS_IPG1, ipgs[1]); | |
752 | 749 | |||
753 | /* Enable receiver and transmitter, bridge controls speed/duplex mode */ | 750 | /* Enable receiver and transmitter, bridge controls speed/duplex mode */ | |
754 | rxmode = mos_reg_read_1(un, MOS_CTL); | 751 | rxmode = mos_reg_read_1(un, MOS_CTL); | |
755 | rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB; | 752 | rxmode |= MOS_CTL_RX_ENB | MOS_CTL_TX_ENB | MOS_CTL_BS_ENB; | |
756 | rxmode &= ~(MOS_CTL_SLEEP); | 753 | rxmode &= ~(MOS_CTL_SLEEP); | |
757 | mos_reg_write_1(un, MOS_CTL, rxmode); | 754 | mos_reg_write_1(un, MOS_CTL, rxmode); | |
758 | 755 | |||
759 | return usbnet_init_rx_tx(un); | 756 | return usbnet_init_rx_tx(un); | |
760 | } | 757 | } | |
761 | 758 | |||
762 | void | 759 | void | |
763 | mos_uno_stop(struct ifnet *ifp, int disable) | 760 | mos_uno_stop(struct ifnet *ifp, int disable) | |
764 | { | 761 | { | |
765 | struct usbnet * const un = ifp->if_softc; | 762 | struct usbnet * const un = ifp->if_softc; | |
766 | 763 | |||
767 | mos_reset(un); | 764 | mos_reset(un); | |
768 | } | 765 | } |
--- src/sys/dev/usb/if_mue.c 2022/03/03 05:54:37 1.77
+++ src/sys/dev/usb/if_mue.c 2022/03/03 05:55:01 1.78
@@ -1,1302 +1,1297 @@ | @@ -1,1302 +1,1297 @@ | |||
1 | /* $NetBSD: if_mue.c,v 1.77 2022/03/03 05:54:37 riastradh Exp $ */ | 1 | /* $NetBSD: if_mue.c,v 1.78 2022/03/03 05:55:01 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.77 2022/03/03 05:54:37 riastradh Exp $"); | 23 | __KERNEL_RCSID(0, "$NetBSD: if_mue.c,v 1.78 2022/03/03 05:55:01 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_uno_mcast(struct ifnet *); | 95 | static void mue_uno_mcast(struct ifnet *); | |
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_mcast = mue_uno_mcast, | 114 | .uno_mcast = mue_uno_mcast, | |
115 | .uno_read_reg = mue_uno_mii_read_reg, | 115 | .uno_read_reg = mue_uno_mii_read_reg, | |
116 | .uno_write_reg = mue_uno_mii_write_reg, | 116 | .uno_write_reg = mue_uno_mii_write_reg, | |
117 | .uno_statchg = mue_uno_mii_statchg, | 117 | .uno_statchg = mue_uno_mii_statchg, | |
118 | .uno_tx_prepare = mue_uno_tx_prepare, | 118 | .uno_tx_prepare = mue_uno_tx_prepare, | |
119 | .uno_rx_loop = mue_uno_rx_loop, | 119 | .uno_rx_loop = mue_uno_rx_loop, | |
120 | .uno_init = mue_uno_init, | 120 | .uno_init = mue_uno_init, | |
121 | }; | 121 | }; | |
122 | 122 | |||
123 | #define MUE_SETBIT(un, reg, x) \ | 123 | #define MUE_SETBIT(un, reg, x) \ | |
124 | mue_csr_write(un, reg, mue_csr_read(un, reg) | (x)) | 124 | mue_csr_write(un, reg, mue_csr_read(un, reg) | (x)) | |
125 | 125 | |||
126 | #define MUE_CLRBIT(un, reg, x) \ | 126 | #define MUE_CLRBIT(un, reg, x) \ | |
127 | mue_csr_write(un, reg, mue_csr_read(un, reg) & ~(x)) | 127 | mue_csr_write(un, reg, mue_csr_read(un, reg) & ~(x)) | |
128 | 128 | |||
129 | #define MUE_WAIT_SET(un, reg, set, fail) \ | 129 | #define MUE_WAIT_SET(un, reg, set, fail) \ | |
130 | mue_wait_for_bits(un, reg, set, ~0, fail) | 130 | mue_wait_for_bits(un, reg, set, ~0, fail) | |
131 | 131 | |||
132 | #define MUE_WAIT_CLR(un, reg, clear, fail) \ | 132 | #define MUE_WAIT_CLR(un, reg, clear, fail) \ | |
133 | mue_wait_for_bits(un, reg, 0, clear, fail) | 133 | mue_wait_for_bits(un, reg, 0, clear, fail) | |
134 | 134 | |||
135 | #define ETHER_IS_VALID(addr) \ | 135 | #define ETHER_IS_VALID(addr) \ | |
136 | (!ETHER_IS_MULTICAST(addr) && !ETHER_IS_ZERO(addr)) | 136 | (!ETHER_IS_MULTICAST(addr) && !ETHER_IS_ZERO(addr)) | |
137 | 137 | |||
138 | #define ETHER_IS_ZERO(addr) \ | 138 | #define ETHER_IS_ZERO(addr) \ | |
139 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | 139 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | |
140 | 140 | |||
141 | CFATTACH_DECL_NEW(mue, sizeof(struct usbnet), mue_match, mue_attach, | 141 | CFATTACH_DECL_NEW(mue, sizeof(struct usbnet), mue_match, mue_attach, | |
142 | usbnet_detach, usbnet_activate); | 142 | usbnet_detach, usbnet_activate); | |
143 | 143 | |||
144 | static uint32_t | 144 | static uint32_t | |
145 | mue_csr_read(struct usbnet *un, uint32_t reg) | 145 | mue_csr_read(struct usbnet *un, uint32_t reg) | |
146 | { | 146 | { | |
147 | usb_device_request_t req; | 147 | usb_device_request_t req; | |
148 | usbd_status err; | 148 | usbd_status err; | |
149 | uDWord val; | 149 | uDWord val; | |
150 | 150 | |||
151 | if (usbnet_isdying(un)) | 151 | if (usbnet_isdying(un)) | |
152 | return 0; | 152 | return 0; | |
153 | 153 | |||
154 | USETDW(val, 0); | 154 | USETDW(val, 0); | |
155 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 155 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
156 | req.bRequest = MUE_UR_READREG; | 156 | req.bRequest = MUE_UR_READREG; | |
157 | USETW(req.wValue, 0); | 157 | USETW(req.wValue, 0); | |
158 | USETW(req.wIndex, reg); | 158 | USETW(req.wIndex, reg); | |
159 | USETW(req.wLength, 4); | 159 | USETW(req.wLength, 4); | |
160 | 160 | |||
161 | err = usbd_do_request(un->un_udev, &req, &val); | 161 | err = usbd_do_request(un->un_udev, &req, &val); | |
162 | if (err) { | 162 | if (err) { | |
163 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | 163 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | |
164 | return 0; | 164 | return 0; | |
165 | } | 165 | } | |
166 | 166 | |||
167 | return UGETDW(val); | 167 | return UGETDW(val); | |
168 | } | 168 | } | |
169 | 169 | |||
170 | static int | 170 | static int | |
171 | mue_csr_write(struct usbnet *un, uint32_t reg, uint32_t aval) | 171 | mue_csr_write(struct usbnet *un, uint32_t reg, uint32_t aval) | |
172 | { | 172 | { | |
173 | usb_device_request_t req; | 173 | usb_device_request_t req; | |
174 | usbd_status err; | 174 | usbd_status err; | |
175 | uDWord val; | 175 | uDWord val; | |
176 | 176 | |||
177 | if (usbnet_isdying(un)) | 177 | if (usbnet_isdying(un)) | |
178 | return 0; | 178 | return 0; | |
179 | 179 | |||
180 | USETDW(val, aval); | 180 | USETDW(val, aval); | |
181 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 181 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
182 | req.bRequest = MUE_UR_WRITEREG; | 182 | req.bRequest = MUE_UR_WRITEREG; | |
183 | USETW(req.wValue, 0); | 183 | USETW(req.wValue, 0); | |
184 | USETW(req.wIndex, reg); | 184 | USETW(req.wIndex, reg); | |
185 | USETW(req.wLength, 4); | 185 | USETW(req.wLength, 4); | |
186 | 186 | |||
187 | err = usbd_do_request(un->un_udev, &req, &val); | 187 | err = usbd_do_request(un->un_udev, &req, &val); | |
188 | if (err) { | 188 | if (err) { | |
189 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | 189 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | |
190 | return -1; | 190 | return -1; | |
191 | } | 191 | } | |
192 | 192 | |||
193 | return 0; | 193 | return 0; | |
194 | } | 194 | } | |
195 | 195 | |||
196 | static int | 196 | static int | |
197 | mue_wait_for_bits(struct usbnet *un, uint32_t reg, | 197 | mue_wait_for_bits(struct usbnet *un, uint32_t reg, | |
198 | uint32_t set, uint32_t clear, uint32_t fail) | 198 | uint32_t set, uint32_t clear, uint32_t fail) | |
199 | { | 199 | { | |
200 | uint32_t val; | 200 | uint32_t val; | |
201 | int ntries; | 201 | int ntries; | |
202 | 202 | |||
203 | for (ntries = 0; ntries < 1000; ntries++) { | 203 | for (ntries = 0; ntries < 1000; ntries++) { | |
204 | if (usbnet_isdying(un)) | 204 | if (usbnet_isdying(un)) | |
205 | return 1; | 205 | return 1; | |
206 | val = mue_csr_read(un, reg); | 206 | val = mue_csr_read(un, reg); | |
207 | if ((val & set) || !(val & clear)) | 207 | if ((val & set) || !(val & clear)) | |
208 | return 0; | 208 | return 0; | |
209 | if (val & fail) | 209 | if (val & fail) | |
210 | return 1; | 210 | return 1; | |
211 | usbd_delay_ms(un->un_udev, 1); | 211 | usbd_delay_ms(un->un_udev, 1); | |
212 | } | 212 | } | |
213 | 213 | |||
214 | return 1; | 214 | return 1; | |
215 | } | 215 | } | |
216 | 216 | |||
217 | static int | 217 | static int | |
218 | mue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 218 | mue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
219 | { | 219 | { | |
220 | uint32_t data; | 220 | uint32_t data; | |
221 | 221 | |||
222 | if (un->un_phyno != phy) { | 222 | if (un->un_phyno != phy) { | |
223 | *val = 0; | 223 | *val = 0; | |
224 | return EINVAL; | 224 | return EINVAL; | |
225 | } | 225 | } | |
226 | 226 | |||
227 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 227 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
228 | MUE_PRINTF(un, "not ready\n"); | 228 | MUE_PRINTF(un, "not ready\n"); | |
229 | *val = 0; | 229 | *val = 0; | |
230 | return EBUSY; | 230 | return EBUSY; | |
231 | } | 231 | } | |
232 | 232 | |||
233 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_READ | | 233 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_READ | | |
234 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | 234 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | |
235 | MUE_MII_ACCESS_PHYADDR(phy)); | 235 | MUE_MII_ACCESS_PHYADDR(phy)); | |
236 | 236 | |||
237 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 237 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
238 | MUE_PRINTF(un, "timed out\n"); | 238 | MUE_PRINTF(un, "timed out\n"); | |
239 | *val = 0; | 239 | *val = 0; | |
240 | return ETIMEDOUT; | 240 | return ETIMEDOUT; | |
241 | } | 241 | } | |
242 | 242 | |||
243 | data = mue_csr_read(un, MUE_MII_DATA); | 243 | data = mue_csr_read(un, MUE_MII_DATA); | |
244 | *val = data & 0xffff; | 244 | *val = data & 0xffff; | |
245 | 245 | |||
246 | return 0; | 246 | return 0; | |
247 | } | 247 | } | |
248 | 248 | |||
249 | static int | 249 | static int | |
250 | mue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 250 | mue_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
251 | { | 251 | { | |
252 | 252 | |||
253 | if (un->un_phyno != phy) | 253 | if (un->un_phyno != phy) | |
254 | return EINVAL; | 254 | return EINVAL; | |
255 | 255 | |||
256 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 256 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
257 | MUE_PRINTF(un, "not ready\n"); | 257 | MUE_PRINTF(un, "not ready\n"); | |
258 | return EBUSY; | 258 | return EBUSY; | |
259 | } | 259 | } | |
260 | 260 | |||
261 | mue_csr_write(un, MUE_MII_DATA, val); | 261 | mue_csr_write(un, MUE_MII_DATA, val); | |
262 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_WRITE | | 262 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_WRITE | | |
263 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | 263 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | |
264 | MUE_MII_ACCESS_PHYADDR(phy)); | 264 | MUE_MII_ACCESS_PHYADDR(phy)); | |
265 | 265 | |||
266 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | 266 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | |
267 | MUE_PRINTF(un, "timed out\n"); | 267 | MUE_PRINTF(un, "timed out\n"); | |
268 | return ETIMEDOUT; | 268 | return ETIMEDOUT; | |
269 | } | 269 | } | |
270 | 270 | |||
271 | return 0; | 271 | return 0; | |
272 | } | 272 | } | |
273 | 273 | |||
274 | static void | 274 | static void | |
275 | mue_uno_mii_statchg(struct ifnet *ifp) | 275 | mue_uno_mii_statchg(struct ifnet *ifp) | |
276 | { | 276 | { | |
277 | struct usbnet * const un = ifp->if_softc; | 277 | struct usbnet * const un = ifp->if_softc; | |
278 | struct mii_data * const mii = usbnet_mii(un); | 278 | struct mii_data * const mii = usbnet_mii(un); | |
279 | uint32_t flow, threshold; | 279 | uint32_t flow, threshold; | |
280 | 280 | |||
281 | if (usbnet_isdying(un)) | 281 | if (usbnet_isdying(un)) | |
282 | return; | 282 | return; | |
283 | 283 | |||
284 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 284 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
285 | (IFM_ACTIVE | IFM_AVALID)) { | 285 | (IFM_ACTIVE | IFM_AVALID)) { | |
286 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 286 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
287 | case IFM_10_T: | 287 | case IFM_10_T: | |
288 | case IFM_100_TX: | 288 | case IFM_100_TX: | |
289 | case IFM_1000_T: | 289 | case IFM_1000_T: | |
290 | usbnet_set_link(un, true); | 290 | usbnet_set_link(un, true); | |
291 | break; | 291 | break; | |
292 | default: | 292 | default: | |
293 | break; | 293 | break; | |
294 | } | 294 | } | |
295 | } | 295 | } | |
296 | 296 | |||
297 | /* Lost link, do nothing. */ | 297 | /* Lost link, do nothing. */ | |
298 | if (!usbnet_havelink(un)) { | 298 | if (!usbnet_havelink(un)) { | |
299 | DPRINTF(un, "mii_media_status = %#x\n", mii->mii_media_status); | 299 | DPRINTF(un, "mii_media_status = %#x\n", mii->mii_media_status); | |
300 | return; | 300 | return; | |
301 | } | 301 | } | |
302 | 302 | |||
303 | if (!(un->un_flags & LAN7500)) { | 303 | if (!(un->un_flags & LAN7500)) { | |
304 | if (un->un_udev->ud_speed == USB_SPEED_SUPER) { | 304 | if (un->un_udev->ud_speed == USB_SPEED_SUPER) { | |
305 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { | 305 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { | |
306 | /* Disable U2 and enable U1. */ | 306 | /* Disable U2 and enable U1. */ | |
307 | MUE_CLRBIT(un, MUE_USB_CFG1, | 307 | MUE_CLRBIT(un, MUE_USB_CFG1, | |
308 | MUE_USB_CFG1_DEV_U2_INIT_EN); | 308 | MUE_USB_CFG1_DEV_U2_INIT_EN); | |
309 | MUE_SETBIT(un, MUE_USB_CFG1, | 309 | MUE_SETBIT(un, MUE_USB_CFG1, | |
310 | MUE_USB_CFG1_DEV_U1_INIT_EN); | 310 | MUE_USB_CFG1_DEV_U1_INIT_EN); | |
311 | } else { | 311 | } else { | |
312 | /* Enable U1 and U2. */ | 312 | /* Enable U1 and U2. */ | |
313 | MUE_SETBIT(un, MUE_USB_CFG1, | 313 | MUE_SETBIT(un, MUE_USB_CFG1, | |
314 | MUE_USB_CFG1_DEV_U1_INIT_EN | | 314 | MUE_USB_CFG1_DEV_U1_INIT_EN | | |
315 | MUE_USB_CFG1_DEV_U2_INIT_EN); | 315 | MUE_USB_CFG1_DEV_U2_INIT_EN); | |
316 | } | 316 | } | |
317 | } | 317 | } | |
318 | } | 318 | } | |
319 | 319 | |||
320 | flow = 0; | 320 | flow = 0; | |
321 | /* XXX Linux does not check IFM_FDX flag for 7800. */ | 321 | /* XXX Linux does not check IFM_FDX flag for 7800. */ | |
322 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { | 322 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { | |
323 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) | 323 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) | |
324 | flow |= MUE_FLOW_TX_FCEN | MUE_FLOW_PAUSE_TIME; | 324 | flow |= MUE_FLOW_TX_FCEN | MUE_FLOW_PAUSE_TIME; | |
325 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) | 325 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) | |
326 | flow |= MUE_FLOW_RX_FCEN; | 326 | flow |= MUE_FLOW_RX_FCEN; | |
327 | } | 327 | } | |
328 | 328 | |||
329 | /* XXX Magic numbers taken from Linux driver. */ | 329 | /* XXX Magic numbers taken from Linux driver. */ | |
330 | if (un->un_flags & LAN7500) | 330 | if (un->un_flags & LAN7500) | |
331 | threshold = 0x820; | 331 | threshold = 0x820; | |
332 | else | 332 | else | |
333 | switch (un->un_udev->ud_speed) { | 333 | switch (un->un_udev->ud_speed) { | |
334 | case USB_SPEED_SUPER: | 334 | case USB_SPEED_SUPER: | |
335 | threshold = 0x817; | 335 | threshold = 0x817; | |
336 | break; | 336 | break; | |
337 | case USB_SPEED_HIGH: | 337 | case USB_SPEED_HIGH: | |
338 | threshold = 0x211; | 338 | threshold = 0x211; | |
339 | break; | 339 | break; | |
340 | default: | 340 | default: | |
341 | threshold = 0; | 341 | threshold = 0; | |
342 | break; | 342 | break; | |
343 | } | 343 | } | |
344 | 344 | |||
345 | /* Threshold value should be set before enabling flow. */ | 345 | /* Threshold value should be set before enabling flow. */ | |
346 | mue_csr_write(un, (un->un_flags & LAN7500) ? | 346 | mue_csr_write(un, (un->un_flags & LAN7500) ? | |
347 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, threshold); | 347 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, threshold); | |
348 | mue_csr_write(un, MUE_FLOW, flow); | 348 | mue_csr_write(un, MUE_FLOW, flow); | |
349 | 349 | |||
350 | DPRINTF(un, "done\n"); | 350 | DPRINTF(un, "done\n"); | |
351 | } | 351 | } | |
352 | 352 | |||
353 | static uint8_t | 353 | static uint8_t | |
354 | mue_eeprom_getbyte(struct usbnet *un, int off, uint8_t *dest) | 354 | mue_eeprom_getbyte(struct usbnet *un, int off, uint8_t *dest) | |
355 | { | 355 | { | |
356 | uint32_t val; | 356 | uint32_t val; | |
357 | 357 | |||
358 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, 0)) { | 358 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, 0)) { | |
359 | MUE_PRINTF(un, "not ready\n"); | 359 | MUE_PRINTF(un, "not ready\n"); | |
360 | return ETIMEDOUT; | 360 | return ETIMEDOUT; | |
361 | } | 361 | } | |
362 | 362 | |||
363 | KASSERT((off & ~MUE_E2P_CMD_ADDR_MASK) == 0); | 363 | KASSERT((off & ~MUE_E2P_CMD_ADDR_MASK) == 0); | |
364 | mue_csr_write(un, MUE_E2P_CMD, MUE_E2P_CMD_READ | MUE_E2P_CMD_BUSY | | 364 | mue_csr_write(un, MUE_E2P_CMD, MUE_E2P_CMD_READ | MUE_E2P_CMD_BUSY | | |
365 | off); | 365 | off); | |
366 | 366 | |||
367 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, | 367 | if (MUE_WAIT_CLR(un, MUE_E2P_CMD, MUE_E2P_CMD_BUSY, | |
368 | MUE_E2P_CMD_TIMEOUT)) { | 368 | MUE_E2P_CMD_TIMEOUT)) { | |
369 | MUE_PRINTF(un, "timed out\n"); | 369 | MUE_PRINTF(un, "timed out\n"); | |
370 | return ETIMEDOUT; | 370 | return ETIMEDOUT; | |
371 | } | 371 | } | |
372 | 372 | |||
373 | val = mue_csr_read(un, MUE_E2P_DATA); | 373 | val = mue_csr_read(un, MUE_E2P_DATA); | |
374 | *dest = val & 0xff; | 374 | *dest = val & 0xff; | |
375 | 375 | |||
376 | return 0; | 376 | return 0; | |
377 | } | 377 | } | |
378 | 378 | |||
379 | static int | 379 | static int | |
380 | mue_read_eeprom(struct usbnet *un, uint8_t *dest, int off, int cnt) | 380 | mue_read_eeprom(struct usbnet *un, uint8_t *dest, int off, int cnt) | |
381 | { | 381 | { | |
382 | uint32_t val = 0; /* XXX gcc */ | 382 | uint32_t val = 0; /* XXX gcc */ | |
383 | uint8_t byte; | 383 | uint8_t byte; | |
384 | int i, err = 0; | 384 | int i, err = 0; | |
385 | 385 | |||
386 | /* | 386 | /* | |
387 | * EEPROM pins are muxed with the LED function on LAN7800 device. | 387 | * EEPROM pins are muxed with the LED function on LAN7800 device. | |
388 | */ | 388 | */ | |
389 | if (un->un_flags & LAN7800) { | 389 | if (un->un_flags & LAN7800) { | |
390 | val = mue_csr_read(un, MUE_HW_CFG); | 390 | val = mue_csr_read(un, MUE_HW_CFG); | |
391 | mue_csr_write(un, MUE_HW_CFG, | 391 | mue_csr_write(un, MUE_HW_CFG, | |
392 | val & ~(MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN)); | 392 | val & ~(MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN)); | |
393 | } | 393 | } | |
394 | 394 | |||
395 | for (i = 0; i < cnt; i++) { | 395 | for (i = 0; i < cnt; i++) { | |
396 | err = mue_eeprom_getbyte(un, off + i, &byte); | 396 | err = mue_eeprom_getbyte(un, off + i, &byte); | |
397 | if (err) | 397 | if (err) | |
398 | break; | 398 | break; | |
399 | *(dest + i) = byte; | 399 | *(dest + i) = byte; | |
400 | } | 400 | } | |
401 | 401 | |||
402 | if (un->un_flags & LAN7800) | 402 | if (un->un_flags & LAN7800) | |
403 | mue_csr_write(un, MUE_HW_CFG, val); | 403 | mue_csr_write(un, MUE_HW_CFG, val); | |
404 | 404 | |||
405 | return err ? 1 : 0; | 405 | return err ? 1 : 0; | |
406 | } | 406 | } | |
407 | 407 | |||
408 | static bool | 408 | static bool | |
409 | mue_eeprom_present(struct usbnet *un) | 409 | mue_eeprom_present(struct usbnet *un) | |
410 | { | 410 | { | |
411 | uint32_t val; | 411 | uint32_t val; | |
412 | uint8_t sig; | 412 | uint8_t sig; | |
413 | int ret; | 413 | int ret; | |
414 | 414 | |||
415 | if (un->un_flags & LAN7500) { | 415 | if (un->un_flags & LAN7500) { | |
416 | val = mue_csr_read(un, MUE_E2P_CMD); | 416 | val = mue_csr_read(un, MUE_E2P_CMD); | |
417 | return val & MUE_E2P_CMD_LOADED; | 417 | return val & MUE_E2P_CMD_LOADED; | |
418 | } else { | 418 | } else { | |
419 | ret = mue_read_eeprom(un, &sig, MUE_E2P_IND_OFFSET, 1); | 419 | ret = mue_read_eeprom(un, &sig, MUE_E2P_IND_OFFSET, 1); | |
420 | return (ret == 0) && (sig == MUE_E2P_IND); | 420 | return (ret == 0) && (sig == MUE_E2P_IND); | |
421 | } | 421 | } | |
422 | } | 422 | } | |
423 | 423 | |||
424 | static int | 424 | static int | |
425 | mue_read_otp_raw(struct usbnet *un, uint8_t *dest, int off, int cnt) | 425 | mue_read_otp_raw(struct usbnet *un, uint8_t *dest, int off, int cnt) | |
426 | { | 426 | { | |
427 | uint32_t val; | 427 | uint32_t val; | |
428 | int i, err; | 428 | int i, err; | |
429 | 429 | |||
430 | val = mue_csr_read(un, MUE_OTP_PWR_DN); | 430 | val = mue_csr_read(un, MUE_OTP_PWR_DN); | |
431 | 431 | |||
432 | /* Checking if bit is set. */ | 432 | /* Checking if bit is set. */ | |
433 | if (val & MUE_OTP_PWR_DN_PWRDN_N) { | 433 | if (val & MUE_OTP_PWR_DN_PWRDN_N) { | |
434 | /* Clear it, then wait for it to be cleared. */ | 434 | /* Clear it, then wait for it to be cleared. */ | |
435 | mue_csr_write(un, MUE_OTP_PWR_DN, 0); | 435 | mue_csr_write(un, MUE_OTP_PWR_DN, 0); | |
436 | err = MUE_WAIT_CLR(un, MUE_OTP_PWR_DN, MUE_OTP_PWR_DN_PWRDN_N, | 436 | err = MUE_WAIT_CLR(un, MUE_OTP_PWR_DN, MUE_OTP_PWR_DN_PWRDN_N, | |
437 | 0); | 437 | 0); | |
438 | if (err) { | 438 | if (err) { | |
439 | MUE_PRINTF(un, "not ready\n"); | 439 | MUE_PRINTF(un, "not ready\n"); | |
440 | return 1; | 440 | return 1; | |
441 | } | 441 | } | |
442 | } | 442 | } | |
443 | 443 | |||
444 | /* Start reading the bytes, one at a time. */ | 444 | /* Start reading the bytes, one at a time. */ | |
445 | for (i = 0; i < cnt; i++) { | 445 | for (i = 0; i < cnt; i++) { | |
446 | mue_csr_write(un, MUE_OTP_ADDR1, | 446 | mue_csr_write(un, MUE_OTP_ADDR1, | |
447 | ((off + i) >> 8) & MUE_OTP_ADDR1_MASK); | 447 | ((off + i) >> 8) & MUE_OTP_ADDR1_MASK); | |
448 | mue_csr_write(un, MUE_OTP_ADDR2, | 448 | mue_csr_write(un, MUE_OTP_ADDR2, | |
449 | ((off + i) & MUE_OTP_ADDR2_MASK)); | 449 | ((off + i) & MUE_OTP_ADDR2_MASK)); | |
450 | mue_csr_write(un, MUE_OTP_FUNC_CMD, MUE_OTP_FUNC_CMD_READ); | 450 | mue_csr_write(un, MUE_OTP_FUNC_CMD, MUE_OTP_FUNC_CMD_READ); | |
451 | mue_csr_write(un, MUE_OTP_CMD_GO, MUE_OTP_CMD_GO_GO); | 451 | mue_csr_write(un, MUE_OTP_CMD_GO, MUE_OTP_CMD_GO_GO); | |
452 | 452 | |||
453 | err = MUE_WAIT_CLR(un, MUE_OTP_STATUS, MUE_OTP_STATUS_BUSY, 0); | 453 | err = MUE_WAIT_CLR(un, MUE_OTP_STATUS, MUE_OTP_STATUS_BUSY, 0); | |
454 | if (err) { | 454 | if (err) { | |
455 | MUE_PRINTF(un, "timed out\n"); | 455 | MUE_PRINTF(un, "timed out\n"); | |
456 | return 1; | 456 | return 1; | |
457 | } | 457 | } | |
458 | val = mue_csr_read(un, MUE_OTP_RD_DATA); | 458 | val = mue_csr_read(un, MUE_OTP_RD_DATA); | |
459 | *(dest + i) = (uint8_t)(val & 0xff); | 459 | *(dest + i) = (uint8_t)(val & 0xff); | |
460 | } | 460 | } | |
461 | 461 | |||
462 | return 0; | 462 | return 0; | |
463 | } | 463 | } | |
464 | 464 | |||
465 | static int | 465 | static int | |
466 | mue_read_otp(struct usbnet *un, uint8_t *dest, int off, int cnt) | 466 | mue_read_otp(struct usbnet *un, uint8_t *dest, int off, int cnt) | |
467 | { | 467 | { | |
468 | uint8_t sig; | 468 | uint8_t sig; | |
469 | int err; | 469 | int err; | |
470 | 470 | |||
471 | if (un->un_flags & LAN7500) | 471 | if (un->un_flags & LAN7500) | |
472 | return 1; | 472 | return 1; | |
473 | 473 | |||
474 | err = mue_read_otp_raw(un, &sig, MUE_OTP_IND_OFFSET, 1); | 474 | err = mue_read_otp_raw(un, &sig, MUE_OTP_IND_OFFSET, 1); | |
475 | if (err) | 475 | if (err) | |
476 | return 1; | 476 | return 1; | |
477 | switch (sig) { | 477 | switch (sig) { | |
478 | case MUE_OTP_IND_1: | 478 | case MUE_OTP_IND_1: | |
479 | break; | 479 | break; | |
480 | case MUE_OTP_IND_2: | 480 | case MUE_OTP_IND_2: | |
481 | off += 0x100; | 481 | off += 0x100; | |
482 | break; | 482 | break; | |
483 | default: | 483 | default: | |
484 | DPRINTF(un, "OTP not found\n"); | 484 | DPRINTF(un, "OTP not found\n"); | |
485 | return 1; | 485 | return 1; | |
486 | } | 486 | } | |
487 | err = mue_read_otp_raw(un, dest, off, cnt); | 487 | err = mue_read_otp_raw(un, dest, off, cnt); | |
488 | return err; | 488 | return err; | |
489 | } | 489 | } | |
490 | 490 | |||
491 | static void | 491 | static void | |
492 | mue_dataport_write(struct usbnet *un, uint32_t sel, uint32_t addr, | 492 | mue_dataport_write(struct usbnet *un, uint32_t sel, uint32_t addr, | |
493 | uint32_t cnt, uint32_t *data) | 493 | uint32_t cnt, uint32_t *data) | |
494 | { | 494 | { | |
495 | uint32_t i; | 495 | uint32_t i; | |
496 | 496 | |||
497 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | 497 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | |
498 | MUE_PRINTF(un, "not ready\n"); | 498 | MUE_PRINTF(un, "not ready\n"); | |
499 | return; | 499 | return; | |
500 | } | 500 | } | |
501 | 501 | |||
502 | mue_csr_write(un, MUE_DP_SEL, | 502 | mue_csr_write(un, MUE_DP_SEL, | |
503 | (mue_csr_read(un, MUE_DP_SEL) & ~MUE_DP_SEL_RSEL_MASK) | sel); | 503 | (mue_csr_read(un, MUE_DP_SEL) & ~MUE_DP_SEL_RSEL_MASK) | sel); | |
504 | 504 | |||
505 | for (i = 0; i < cnt; i++) { | 505 | for (i = 0; i < cnt; i++) { | |
506 | mue_csr_write(un, MUE_DP_ADDR, addr + i); | 506 | mue_csr_write(un, MUE_DP_ADDR, addr + i); | |
507 | mue_csr_write(un, MUE_DP_DATA, data[i]); | 507 | mue_csr_write(un, MUE_DP_DATA, data[i]); | |
508 | mue_csr_write(un, MUE_DP_CMD, MUE_DP_CMD_WRITE); | 508 | mue_csr_write(un, MUE_DP_CMD, MUE_DP_CMD_WRITE); | |
509 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | 509 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | |
510 | MUE_PRINTF(un, "timed out\n"); | 510 | MUE_PRINTF(un, "timed out\n"); | |
511 | return; | 511 | return; | |
512 | } | 512 | } | |
513 | } | 513 | } | |
514 | } | 514 | } | |
515 | 515 | |||
516 | static void | 516 | static void | |
517 | mue_init_ltm(struct usbnet *un) | 517 | mue_init_ltm(struct usbnet *un) | |
518 | { | 518 | { | |
519 | uint32_t idx[MUE_NUM_LTM_INDEX] = { 0, 0, 0, 0, 0, 0 }; | 519 | uint32_t idx[MUE_NUM_LTM_INDEX] = { 0, 0, 0, 0, 0, 0 }; | |
520 | uint8_t temp[2]; | 520 | uint8_t temp[2]; | |
521 | size_t i; | 521 | size_t i; | |
522 | 522 | |||
523 | if (mue_csr_read(un, MUE_USB_CFG1) & MUE_USB_CFG1_LTM_ENABLE) { | 523 | if (mue_csr_read(un, MUE_USB_CFG1) & MUE_USB_CFG1_LTM_ENABLE) { | |
524 | if (mue_eeprom_present(un) && | 524 | if (mue_eeprom_present(un) && | |
525 | (mue_read_eeprom(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0)) { | 525 | (mue_read_eeprom(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0)) { | |
526 | if (temp[0] != sizeof(idx)) { | 526 | if (temp[0] != sizeof(idx)) { | |
527 | DPRINTF(un, "EEPROM: unexpected size\n"); | 527 | DPRINTF(un, "EEPROM: unexpected size\n"); | |
528 | goto done; | 528 | goto done; | |
529 | } | 529 | } | |
530 | if (mue_read_eeprom(un, (uint8_t *)idx, temp[1] << 1, | 530 | if (mue_read_eeprom(un, (uint8_t *)idx, temp[1] << 1, | |
531 | sizeof(idx))) { | 531 | sizeof(idx))) { | |
532 | DPRINTF(un, "EEPROM: failed to read\n"); | 532 | DPRINTF(un, "EEPROM: failed to read\n"); | |
533 | goto done; | 533 | goto done; | |
534 | } | 534 | } | |
535 | DPRINTF(un, "success\n"); | 535 | DPRINTF(un, "success\n"); | |
536 | } else if (mue_read_otp(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0) { | 536 | } else if (mue_read_otp(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0) { | |
537 | if (temp[0] != sizeof(idx)) { | 537 | if (temp[0] != sizeof(idx)) { | |
538 | DPRINTF(un, "OTP: unexpected size\n"); | 538 | DPRINTF(un, "OTP: unexpected size\n"); | |
539 | goto done; | 539 | goto done; | |
540 | } | 540 | } | |
541 | if (mue_read_otp(un, (uint8_t *)idx, temp[1] << 1, | 541 | if (mue_read_otp(un, (uint8_t *)idx, temp[1] << 1, | |
542 | sizeof(idx))) { | 542 | sizeof(idx))) { | |
543 | DPRINTF(un, "OTP: failed to read\n"); | 543 | DPRINTF(un, "OTP: failed to read\n"); | |
544 | goto done; | 544 | goto done; | |
545 | } | 545 | } | |
546 | DPRINTF(un, "success\n"); | 546 | DPRINTF(un, "success\n"); | |
547 | } else | 547 | } else | |
548 | DPRINTF(un, "nothing to do\n"); | 548 | DPRINTF(un, "nothing to do\n"); | |
549 | } else | 549 | } else | |
550 | DPRINTF(un, "nothing to do\n"); | 550 | DPRINTF(un, "nothing to do\n"); | |
551 | done: | 551 | done: | |
552 | for (i = 0; i < __arraycount(idx); i++) | 552 | for (i = 0; i < __arraycount(idx); i++) | |
553 | mue_csr_write(un, MUE_LTM_INDEX(i), idx[i]); | 553 | mue_csr_write(un, MUE_LTM_INDEX(i), idx[i]); | |
554 | } | 554 | } | |
555 | 555 | |||
556 | static int | 556 | static int | |
557 | mue_chip_init(struct usbnet *un) | 557 | mue_chip_init(struct usbnet *un) | |
558 | { | 558 | { | |
559 | uint32_t val; | 559 | uint32_t val; | |
560 | 560 | |||
561 | if ((un->un_flags & LAN7500) && | 561 | if ((un->un_flags & LAN7500) && | |
562 | MUE_WAIT_SET(un, MUE_PMT_CTL, MUE_PMT_CTL_READY, 0)) { | 562 | MUE_WAIT_SET(un, MUE_PMT_CTL, MUE_PMT_CTL_READY, 0)) { | |
563 | MUE_PRINTF(un, "not ready\n"); | 563 | MUE_PRINTF(un, "not ready\n"); | |
564 | return ETIMEDOUT; | 564 | return ETIMEDOUT; | |
565 | } | 565 | } | |
566 | 566 | |||
567 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_LRST); | 567 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_LRST); | |
568 | if (MUE_WAIT_CLR(un, MUE_HW_CFG, MUE_HW_CFG_LRST, 0)) { | 568 | if (MUE_WAIT_CLR(un, MUE_HW_CFG, MUE_HW_CFG_LRST, 0)) { | |
569 | MUE_PRINTF(un, "timed out\n"); | 569 | MUE_PRINTF(un, "timed out\n"); | |
570 | return ETIMEDOUT; | 570 | return ETIMEDOUT; | |
571 | } | 571 | } | |
572 | 572 | |||
573 | /* Respond to the IN token with a NAK. */ | 573 | /* Respond to the IN token with a NAK. */ | |
574 | if (un->un_flags & LAN7500) | 574 | if (un->un_flags & LAN7500) | |
575 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BIR); | 575 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BIR); | |
576 | else | 576 | else | |
577 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BIR); | 577 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BIR); | |
578 | 578 | |||
579 | if (un->un_flags & LAN7500) { | 579 | if (un->un_flags & LAN7500) { | |
580 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | 580 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | |
581 | val = MUE_7500_HS_RX_BUFSIZE / | 581 | val = MUE_7500_HS_RX_BUFSIZE / | |
582 | MUE_HS_USB_PKT_SIZE; | 582 | MUE_HS_USB_PKT_SIZE; | |
583 | else | 583 | else | |
584 | val = MUE_7500_FS_RX_BUFSIZE / | 584 | val = MUE_7500_FS_RX_BUFSIZE / | |
585 | MUE_FS_USB_PKT_SIZE; | 585 | MUE_FS_USB_PKT_SIZE; | |
586 | mue_csr_write(un, MUE_7500_BURST_CAP, val); | 586 | mue_csr_write(un, MUE_7500_BURST_CAP, val); | |
587 | mue_csr_write(un, MUE_7500_BULKIN_DELAY, | 587 | mue_csr_write(un, MUE_7500_BULKIN_DELAY, | |
588 | MUE_7500_DEFAULT_BULKIN_DELAY); | 588 | MUE_7500_DEFAULT_BULKIN_DELAY); | |
589 | 589 | |||
590 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BCE | MUE_HW_CFG_MEF); | 590 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BCE | MUE_HW_CFG_MEF); | |
591 | 591 | |||
592 | /* Set FIFO sizes. */ | 592 | /* Set FIFO sizes. */ | |
593 | val = (MUE_7500_MAX_RX_FIFO_SIZE - 512) / 512; | 593 | val = (MUE_7500_MAX_RX_FIFO_SIZE - 512) / 512; | |
594 | mue_csr_write(un, MUE_7500_FCT_RX_FIFO_END, val); | 594 | mue_csr_write(un, MUE_7500_FCT_RX_FIFO_END, val); | |
595 | val = (MUE_7500_MAX_TX_FIFO_SIZE - 512) / 512; | 595 | val = (MUE_7500_MAX_TX_FIFO_SIZE - 512) / 512; | |
596 | mue_csr_write(un, MUE_7500_FCT_TX_FIFO_END, val); | 596 | mue_csr_write(un, MUE_7500_FCT_TX_FIFO_END, val); | |
597 | } else { | 597 | } else { | |
598 | /* Init LTM. */ | 598 | /* Init LTM. */ | |
599 | mue_init_ltm(un); | 599 | mue_init_ltm(un); | |
600 | 600 | |||
601 | val = MUE_7800_RX_BUFSIZE; | 601 | val = MUE_7800_RX_BUFSIZE; | |
602 | switch (un->un_udev->ud_speed) { | 602 | switch (un->un_udev->ud_speed) { | |
603 | case USB_SPEED_SUPER: | 603 | case USB_SPEED_SUPER: | |
604 | val /= MUE_SS_USB_PKT_SIZE; | 604 | val /= MUE_SS_USB_PKT_SIZE; | |
605 | break; | 605 | break; | |
606 | case USB_SPEED_HIGH: | 606 | case USB_SPEED_HIGH: | |
607 | val /= MUE_HS_USB_PKT_SIZE; | 607 | val /= MUE_HS_USB_PKT_SIZE; | |
608 | break; | 608 | break; | |
609 | default: | 609 | default: | |
610 | val /= MUE_FS_USB_PKT_SIZE; | 610 | val /= MUE_FS_USB_PKT_SIZE; | |
611 | break; | 611 | break; | |
612 | } | 612 | } | |
613 | mue_csr_write(un, MUE_7800_BURST_CAP, val); | 613 | mue_csr_write(un, MUE_7800_BURST_CAP, val); | |
614 | mue_csr_write(un, MUE_7800_BULKIN_DELAY, | 614 | mue_csr_write(un, MUE_7800_BULKIN_DELAY, | |
615 | MUE_7800_DEFAULT_BULKIN_DELAY); | 615 | MUE_7800_DEFAULT_BULKIN_DELAY); | |
616 | 616 | |||
617 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_MEF); | 617 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_MEF); | |
618 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BCE); | 618 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BCE); | |
619 | 619 | |||
620 | /* | 620 | /* | |
621 | * Set FCL's RX and TX FIFO sizes: according to data sheet this | 621 | * Set FCL's RX and TX FIFO sizes: according to data sheet this | |
622 | * is already the default value. But we initialize it to the | 622 | * is already the default value. But we initialize it to the | |
623 | * same value anyways, as that's what the Linux driver does. | 623 | * same value anyways, as that's what the Linux driver does. | |
624 | */ | 624 | */ | |
625 | val = (MUE_7800_MAX_RX_FIFO_SIZE - 512) / 512; | 625 | val = (MUE_7800_MAX_RX_FIFO_SIZE - 512) / 512; | |
626 | mue_csr_write(un, MUE_7800_FCT_RX_FIFO_END, val); | 626 | mue_csr_write(un, MUE_7800_FCT_RX_FIFO_END, val); | |
627 | val = (MUE_7800_MAX_TX_FIFO_SIZE - 512) / 512; | 627 | val = (MUE_7800_MAX_TX_FIFO_SIZE - 512) / 512; | |
628 | mue_csr_write(un, MUE_7800_FCT_TX_FIFO_END, val); | 628 | mue_csr_write(un, MUE_7800_FCT_TX_FIFO_END, val); | |
629 | } | 629 | } | |
630 | 630 | |||
631 | /* Enabling interrupts. */ | 631 | /* Enabling interrupts. */ | |
632 | mue_csr_write(un, MUE_INT_STATUS, ~0); | 632 | mue_csr_write(un, MUE_INT_STATUS, ~0); | |
633 | 633 | |||
634 | mue_csr_write(un, (un->un_flags & LAN7500) ? | 634 | mue_csr_write(un, (un->un_flags & LAN7500) ? | |
635 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, 0); | 635 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, 0); | |
636 | mue_csr_write(un, MUE_FLOW, 0); | 636 | mue_csr_write(un, MUE_FLOW, 0); | |
637 | 637 | |||
638 | /* Reset PHY. */ | 638 | /* Reset PHY. */ | |
639 | MUE_SETBIT(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST); | 639 | MUE_SETBIT(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST); | |
640 | if (MUE_WAIT_CLR(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST, 0)) { | 640 | if (MUE_WAIT_CLR(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST, 0)) { | |
641 | MUE_PRINTF(un, "PHY not ready\n"); | 641 | MUE_PRINTF(un, "PHY not ready\n"); | |
642 | return ETIMEDOUT; | 642 | return ETIMEDOUT; | |
643 | } | 643 | } | |
644 | 644 | |||
645 | /* LAN7801 only has RGMII mode. */ | 645 | /* LAN7801 only has RGMII mode. */ | |
646 | if (un->un_flags & LAN7801) | 646 | if (un->un_flags & LAN7801) | |
647 | MUE_CLRBIT(un, MUE_MAC_CR, MUE_MAC_CR_GMII_EN); | 647 | MUE_CLRBIT(un, MUE_MAC_CR, MUE_MAC_CR_GMII_EN); | |
648 | 648 | |||
649 | if ((un->un_flags & (LAN7500 | LAN7800)) || | 649 | if ((un->un_flags & (LAN7500 | LAN7800)) || | |
650 | !mue_eeprom_present(un)) { | 650 | !mue_eeprom_present(un)) { | |
651 | /* Allow MAC to detect speed and duplex from PHY. */ | 651 | /* Allow MAC to detect speed and duplex from PHY. */ | |
652 | MUE_SETBIT(un, MUE_MAC_CR, MUE_MAC_CR_AUTO_SPEED | | 652 | MUE_SETBIT(un, MUE_MAC_CR, MUE_MAC_CR_AUTO_SPEED | | |
653 | MUE_MAC_CR_AUTO_DUPLEX); | 653 | MUE_MAC_CR_AUTO_DUPLEX); | |
654 | } | 654 | } | |
655 | 655 | |||
656 | MUE_SETBIT(un, MUE_MAC_TX, MUE_MAC_TX_TXEN); | 656 | MUE_SETBIT(un, MUE_MAC_TX, MUE_MAC_TX_TXEN); | |
657 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | 657 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | |
658 | MUE_7500_FCT_TX_CTL : MUE_7800_FCT_TX_CTL, MUE_FCT_TX_CTL_EN); | 658 | MUE_7500_FCT_TX_CTL : MUE_7800_FCT_TX_CTL, MUE_FCT_TX_CTL_EN); | |
659 | 659 | |||
660 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | 660 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | |
661 | MUE_7500_FCT_RX_CTL : MUE_7800_FCT_RX_CTL, MUE_FCT_RX_CTL_EN); | 661 | MUE_7500_FCT_RX_CTL : MUE_7800_FCT_RX_CTL, MUE_FCT_RX_CTL_EN); | |
662 | 662 | |||
663 | /* Set default GPIO/LED settings only if no EEPROM is detected. */ | 663 | /* Set default GPIO/LED settings only if no EEPROM is detected. */ | |
664 | if ((un->un_flags & LAN7500) && !mue_eeprom_present(un)) { | 664 | if ((un->un_flags & LAN7500) && !mue_eeprom_present(un)) { | |
665 | MUE_CLRBIT(un, MUE_LED_CFG, MUE_LED_CFG_LED10_FUN_SEL); | 665 | MUE_CLRBIT(un, MUE_LED_CFG, MUE_LED_CFG_LED10_FUN_SEL); | |
666 | MUE_SETBIT(un, MUE_LED_CFG, | 666 | MUE_SETBIT(un, MUE_LED_CFG, | |
667 | MUE_LED_CFG_LEDGPIO_EN | MUE_LED_CFG_LED2_FUN_SEL); | 667 | MUE_LED_CFG_LEDGPIO_EN | MUE_LED_CFG_LED2_FUN_SEL); | |
668 | } | 668 | } | |
669 | 669 | |||
670 | /* XXX We assume two LEDs at least when EEPROM is missing. */ | 670 | /* XXX We assume two LEDs at least when EEPROM is missing. */ | |
671 | if (un->un_flags & LAN7800 && | 671 | if (un->un_flags & LAN7800 && | |
672 | !mue_eeprom_present(un)) | 672 | !mue_eeprom_present(un)) | |
673 | MUE_SETBIT(un, MUE_HW_CFG, | 673 | MUE_SETBIT(un, MUE_HW_CFG, | |
674 | MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN); | 674 | MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN); | |
675 | 675 | |||
676 | return 0; | 676 | return 0; | |
677 | } | 677 | } | |
678 | 678 | |||
679 | static void | 679 | static void | |
680 | mue_set_macaddr(struct usbnet *un) | 680 | mue_set_macaddr(struct usbnet *un) | |
681 | { | 681 | { | |
682 | struct ifnet * const ifp = usbnet_ifp(un); | 682 | struct ifnet * const ifp = usbnet_ifp(un); | |
683 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | 683 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | |
684 | uint32_t lo, hi; | 684 | uint32_t lo, hi; | |
685 | 685 | |||
686 | lo = MUE_ENADDR_LO(enaddr); | 686 | lo = MUE_ENADDR_LO(enaddr); | |
687 | hi = MUE_ENADDR_HI(enaddr); | 687 | hi = MUE_ENADDR_HI(enaddr); | |
688 | 688 | |||
689 | mue_csr_write(un, MUE_RX_ADDRL, lo); | 689 | mue_csr_write(un, MUE_RX_ADDRL, lo); | |
690 | mue_csr_write(un, MUE_RX_ADDRH, hi); | 690 | mue_csr_write(un, MUE_RX_ADDRH, hi); | |
691 | } | 691 | } | |
692 | 692 | |||
693 | static int | 693 | static int | |
694 | mue_get_macaddr(struct usbnet *un, prop_dictionary_t dict) | 694 | mue_get_macaddr(struct usbnet *un, prop_dictionary_t dict) | |
695 | { | 695 | { | |
696 | prop_data_t eaprop; | 696 | prop_data_t eaprop; | |
697 | uint32_t low, high; | 697 | uint32_t low, high; | |
698 | 698 | |||
699 | if (!(un->un_flags & LAN7500)) { | 699 | if (!(un->un_flags & LAN7500)) { | |
700 | low = mue_csr_read(un, MUE_RX_ADDRL); | 700 | low = mue_csr_read(un, MUE_RX_ADDRL); | |
701 | high = mue_csr_read(un, MUE_RX_ADDRH); | 701 | high = mue_csr_read(un, MUE_RX_ADDRH); | |
702 | un->un_eaddr[5] = (uint8_t)((high >> 8) & 0xff); | 702 | un->un_eaddr[5] = (uint8_t)((high >> 8) & 0xff); | |
703 | un->un_eaddr[4] = (uint8_t)((high) & 0xff); | 703 | un->un_eaddr[4] = (uint8_t)((high) & 0xff); | |
704 | un->un_eaddr[3] = (uint8_t)((low >> 24) & 0xff); | 704 | un->un_eaddr[3] = (uint8_t)((low >> 24) & 0xff); | |
705 | un->un_eaddr[2] = (uint8_t)((low >> 16) & 0xff); | 705 | un->un_eaddr[2] = (uint8_t)((low >> 16) & 0xff); | |
706 | un->un_eaddr[1] = (uint8_t)((low >> 8) & 0xff); | 706 | un->un_eaddr[1] = (uint8_t)((low >> 8) & 0xff); | |
707 | un->un_eaddr[0] = (uint8_t)((low) & 0xff); | 707 | un->un_eaddr[0] = (uint8_t)((low) & 0xff); | |
708 | if (ETHER_IS_VALID(un->un_eaddr)) | 708 | if (ETHER_IS_VALID(un->un_eaddr)) | |
709 | return 0; | 709 | return 0; | |
710 | else | 710 | else | |
711 | DPRINTF(un, "registers: %s\n", | 711 | DPRINTF(un, "registers: %s\n", | |
712 | ether_sprintf(un->un_eaddr)); | 712 | ether_sprintf(un->un_eaddr)); | |
713 | } | 713 | } | |
714 | 714 | |||
715 | if (mue_eeprom_present(un) && !mue_read_eeprom(un, un->un_eaddr, | 715 | if (mue_eeprom_present(un) && !mue_read_eeprom(un, un->un_eaddr, | |
716 | MUE_E2P_MAC_OFFSET, ETHER_ADDR_LEN)) { | 716 | MUE_E2P_MAC_OFFSET, ETHER_ADDR_LEN)) { | |
717 | if (ETHER_IS_VALID(un->un_eaddr)) | 717 | if (ETHER_IS_VALID(un->un_eaddr)) | |
718 | return 0; | 718 | return 0; | |
719 | else | 719 | else | |
720 | DPRINTF(un, "EEPROM: %s\n", | 720 | DPRINTF(un, "EEPROM: %s\n", | |
721 | ether_sprintf(un->un_eaddr)); | 721 | ether_sprintf(un->un_eaddr)); | |
722 | } | 722 | } | |
723 | 723 | |||
724 | if (mue_read_otp(un, un->un_eaddr, MUE_OTP_MAC_OFFSET, | 724 | if (mue_read_otp(un, un->un_eaddr, MUE_OTP_MAC_OFFSET, | |
725 | ETHER_ADDR_LEN) == 0) { | 725 | ETHER_ADDR_LEN) == 0) { | |
726 | if (ETHER_IS_VALID(un->un_eaddr)) | 726 | if (ETHER_IS_VALID(un->un_eaddr)) | |
727 | return 0; | 727 | return 0; | |
728 | else | 728 | else | |
729 | DPRINTF(un, "OTP: %s\n", | 729 | DPRINTF(un, "OTP: %s\n", | |
730 | ether_sprintf(un->un_eaddr)); | 730 | ether_sprintf(un->un_eaddr)); | |
731 | } | 731 | } | |
732 | 732 | |||
733 | /* | 733 | /* | |
734 | * Other MD methods. This should be tried only if other methods fail. | 734 | * Other MD methods. This should be tried only if other methods fail. | |
735 | * Otherwise, MAC address for internal device can be assinged to | 735 | * Otherwise, MAC address for internal device can be assinged to | |
736 | * external devices on Raspberry Pi, for example. | 736 | * external devices on Raspberry Pi, for example. | |
737 | */ | 737 | */ | |
738 | eaprop = prop_dictionary_get(dict, "mac-address"); | 738 | eaprop = prop_dictionary_get(dict, "mac-address"); | |
739 | if (eaprop != NULL) { | 739 | if (eaprop != NULL) { | |
740 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | 740 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | |
741 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | 741 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | |
742 | memcpy(un->un_eaddr, prop_data_value(eaprop), | 742 | memcpy(un->un_eaddr, prop_data_value(eaprop), | |
743 | ETHER_ADDR_LEN); | 743 | ETHER_ADDR_LEN); | |
744 | if (ETHER_IS_VALID(un->un_eaddr)) | 744 | if (ETHER_IS_VALID(un->un_eaddr)) | |
745 | return 0; | 745 | return 0; | |
746 | else | 746 | else | |
747 | DPRINTF(un, "prop_dictionary_get: %s\n", | 747 | DPRINTF(un, "prop_dictionary_get: %s\n", | |
748 | ether_sprintf(un->un_eaddr)); | 748 | ether_sprintf(un->un_eaddr)); | |
749 | } | 749 | } | |
750 | 750 | |||
751 | return 1; | 751 | return 1; | |
752 | } | 752 | } | |
753 | 753 | |||
754 | 754 | |||
755 | /* | 755 | /* | |
756 | * Probe for a Microchip chip. | 756 | * Probe for a Microchip chip. | |
757 | */ | 757 | */ | |
758 | static int | 758 | static int | |
759 | mue_match(device_t parent, cfdata_t match, void *aux) | 759 | mue_match(device_t parent, cfdata_t match, void *aux) | |
760 | { | 760 | { | |
761 | struct usb_attach_arg *uaa = aux; | 761 | struct usb_attach_arg *uaa = aux; | |
762 | 762 | |||
763 | return (MUE_LOOKUP(uaa) != NULL) ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 763 | return (MUE_LOOKUP(uaa) != NULL) ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
764 | } | 764 | } | |
765 | 765 | |||
766 | static void | 766 | static void | |
767 | mue_attach(device_t parent, device_t self, void *aux) | 767 | mue_attach(device_t parent, device_t self, void *aux) | |
768 | { | 768 | { | |
769 | USBNET_MII_DECL_DEFAULT(unm); | 769 | USBNET_MII_DECL_DEFAULT(unm); | |
770 | struct usbnet * const un = device_private(self); | 770 | struct usbnet * const un = device_private(self); | |
771 | prop_dictionary_t dict = device_properties(self); | 771 | prop_dictionary_t dict = device_properties(self); | |
772 | struct usb_attach_arg *uaa = aux; | 772 | struct usb_attach_arg *uaa = aux; | |
773 | struct usbd_device *dev = uaa->uaa_device; | 773 | struct usbd_device *dev = uaa->uaa_device; | |
774 | usb_interface_descriptor_t *id; | 774 | usb_interface_descriptor_t *id; | |
775 | usb_endpoint_descriptor_t *ed; | 775 | usb_endpoint_descriptor_t *ed; | |
776 | char *devinfop; | 776 | char *devinfop; | |
777 | usbd_status err; | 777 | usbd_status err; | |
778 | const char *descr; | 778 | const char *descr; | |
779 | uint32_t id_rev; | 779 | uint32_t id_rev; | |
780 | uint8_t i; | 780 | uint8_t i; | |
781 | unsigned rx_list_cnt, tx_list_cnt; | 781 | unsigned rx_list_cnt, tx_list_cnt; | |
782 | unsigned rx_bufsz; | 782 | unsigned rx_bufsz; | |
783 | 783 | |||
784 | aprint_naive("\n"); | 784 | aprint_naive("\n"); | |
785 | aprint_normal("\n"); | 785 | aprint_normal("\n"); | |
786 | devinfop = usbd_devinfo_alloc(dev, 0); | 786 | devinfop = usbd_devinfo_alloc(dev, 0); | |
787 | aprint_normal_dev(self, "%s\n", devinfop); | 787 | aprint_normal_dev(self, "%s\n", devinfop); | |
788 | usbd_devinfo_free(devinfop); | 788 | usbd_devinfo_free(devinfop); | |
789 | 789 | |||
790 | un->un_dev = self; | 790 | un->un_dev = self; | |
791 | un->un_udev = dev; | 791 | un->un_udev = dev; | |
792 | un->un_sc = un; | 792 | un->un_sc = un; | |
793 | un->un_ops = &mue_ops; | 793 | un->un_ops = &mue_ops; | |
794 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 794 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
795 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 795 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
796 | 796 | |||
797 | #define MUE_CONFIG_NO 1 | 797 | #define MUE_CONFIG_NO 1 | |
798 | err = usbd_set_config_no(dev, MUE_CONFIG_NO, 1); | 798 | err = usbd_set_config_no(dev, MUE_CONFIG_NO, 1); | |
799 | if (err) { | 799 | if (err) { | |
800 | aprint_error_dev(self, "failed to set configuration: %s\n", | 800 | aprint_error_dev(self, "failed to set configuration: %s\n", | |
801 | usbd_errstr(err)); | 801 | usbd_errstr(err)); | |
802 | return; | 802 | return; | |
803 | } | 803 | } | |
804 | 804 | |||
805 | #define MUE_IFACE_IDX 0 | 805 | #define MUE_IFACE_IDX 0 | |
806 | err = usbd_device2interface_handle(dev, MUE_IFACE_IDX, &un->un_iface); | 806 | err = usbd_device2interface_handle(dev, MUE_IFACE_IDX, &un->un_iface); | |
807 | if (err) { | 807 | if (err) { | |
808 | aprint_error_dev(self, "failed to get interface handle: %s\n", | 808 | aprint_error_dev(self, "failed to get interface handle: %s\n", | |
809 | usbd_errstr(err)); | 809 | usbd_errstr(err)); | |
810 | return; | 810 | return; | |
811 | } | 811 | } | |
812 | 812 | |||
813 | un->un_flags = MUE_LOOKUP(uaa)->mue_flags; | 813 | un->un_flags = MUE_LOOKUP(uaa)->mue_flags; | |
814 | 814 | |||
815 | /* Decide on what our bufsize will be. */ | 815 | /* Decide on what our bufsize will be. */ | |
816 | if (un->un_flags & LAN7500) { | 816 | if (un->un_flags & LAN7500) { | |
817 | rx_bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? | 817 | rx_bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? | |
818 | MUE_7500_HS_RX_BUFSIZE : MUE_7500_FS_RX_BUFSIZE; | 818 | MUE_7500_HS_RX_BUFSIZE : MUE_7500_FS_RX_BUFSIZE; | |
819 | rx_list_cnt = 1; | 819 | rx_list_cnt = 1; | |
820 | tx_list_cnt = 1; | 820 | tx_list_cnt = 1; | |
821 | } else { | 821 | } else { | |
822 | rx_bufsz = MUE_7800_RX_BUFSIZE; | 822 | rx_bufsz = MUE_7800_RX_BUFSIZE; | |
823 | rx_list_cnt = MUE_RX_LIST_CNT; | 823 | rx_list_cnt = MUE_RX_LIST_CNT; | |
824 | tx_list_cnt = MUE_TX_LIST_CNT; | 824 | tx_list_cnt = MUE_TX_LIST_CNT; | |
825 | } | 825 | } | |
826 | 826 | |||
827 | un->un_rx_list_cnt = rx_list_cnt; | 827 | un->un_rx_list_cnt = rx_list_cnt; | |
828 | un->un_tx_list_cnt = tx_list_cnt; | 828 | un->un_tx_list_cnt = tx_list_cnt; | |
829 | un->un_rx_bufsz = rx_bufsz; | 829 | un->un_rx_bufsz = rx_bufsz; | |
830 | un->un_tx_bufsz = MUE_TX_BUFSIZE; | 830 | un->un_tx_bufsz = MUE_TX_BUFSIZE; | |
831 | 831 | |||
832 | /* Find endpoints. */ | 832 | /* Find endpoints. */ | |
833 | id = usbd_get_interface_descriptor(un->un_iface); | 833 | id = usbd_get_interface_descriptor(un->un_iface); | |
834 | for (i = 0; i < id->bNumEndpoints; i++) { | 834 | for (i = 0; i < id->bNumEndpoints; i++) { | |
835 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 835 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
836 | if (ed == NULL) { | 836 | if (ed == NULL) { | |
837 | aprint_error_dev(self, "failed to get ep %hhd\n", i); | 837 | aprint_error_dev(self, "failed to get ep %hhd\n", i); | |
838 | return; | 838 | return; | |
839 | } | 839 | } | |
840 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 840 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
841 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 841 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
842 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 842 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
843 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 843 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
844 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 844 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
845 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 845 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
846 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 846 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
847 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 847 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
848 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 848 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
849 | } | 849 | } | |
850 | } | 850 | } | |
851 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 851 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
852 | un->un_ed[USBNET_ENDPT_TX] == 0 || | 852 | un->un_ed[USBNET_ENDPT_TX] == 0 || | |
853 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | 853 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | |
854 | aprint_error_dev(self, "failed to find endpoints\n"); | 854 | aprint_error_dev(self, "failed to find endpoints\n"); | |
855 | return; | 855 | return; | |
856 | } | 856 | } | |
857 | 857 | |||
858 | /* Set these up now for mue_cmd(). */ | 858 | /* Set these up now for mue_cmd(). */ | |
859 | usbnet_attach(un, "muedet"); | 859 | usbnet_attach(un, "muedet"); | |
860 | 860 | |||
861 | un->un_phyno = 1; | 861 | un->un_phyno = 1; | |
862 | 862 | |||
863 | if (mue_chip_init(un)) { | 863 | if (mue_chip_init(un)) { | |
864 | aprint_error_dev(self, "failed to initialize chip\n"); | 864 | aprint_error_dev(self, "failed to initialize chip\n"); | |
865 | return; | 865 | return; | |
866 | } | 866 | } | |
867 | 867 | |||
868 | /* A Microchip chip was detected. Inform the world. */ | 868 | /* A Microchip chip was detected. Inform the world. */ | |
869 | id_rev = mue_csr_read(un, MUE_ID_REV); | 869 | id_rev = mue_csr_read(un, MUE_ID_REV); | |
870 | descr = (un->un_flags & LAN7500) ? "LAN7500" : "LAN7800"; | 870 | descr = (un->un_flags & LAN7500) ? "LAN7500" : "LAN7800"; | |
871 | aprint_normal_dev(self, "%s id %#x rev %#x\n", descr, | 871 | aprint_normal_dev(self, "%s id %#x rev %#x\n", descr, | |
872 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_ID), | 872 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_ID), | |
873 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_REV)); | 873 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_REV)); | |
874 | 874 | |||
875 | if (mue_get_macaddr(un, dict)) { | 875 | if (mue_get_macaddr(un, dict)) { | |
876 | aprint_error_dev(self, "failed to read MAC address\n"); | 876 | aprint_error_dev(self, "failed to read MAC address\n"); | |
877 | return; | 877 | return; | |
878 | } | 878 | } | |
879 | 879 | |||
880 | struct ifnet *ifp = usbnet_ifp(un); | 880 | struct ifnet *ifp = usbnet_ifp(un); | |
881 | ifp->if_capabilities = IFCAP_TSOv4 | IFCAP_TSOv6 | | 881 | ifp->if_capabilities = IFCAP_TSOv4 | IFCAP_TSOv6 | | |
882 | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | | 882 | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | | |
883 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | | 883 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | | |
884 | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | | 884 | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | | |
885 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | | 885 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | | |
886 | IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; | 886 | IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; | |
887 | 887 | |||
888 | struct ethercom *ec = usbnet_ec(un); | 888 | struct ethercom *ec = usbnet_ec(un); | |
889 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | 889 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | |
890 | #if 0 /* XXX not yet */ | 890 | #if 0 /* XXX not yet */ | |
891 | ec->ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU; | 891 | ec->ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU; | |
892 | #endif | 892 | #endif | |
893 | 893 | |||
894 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 894 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
895 | 0, &unm); | 895 | 0, &unm); | |
896 | } | 896 | } | |
897 | 897 | |||
898 | static unsigned | 898 | static unsigned | |
899 | mue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 899 | mue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
900 | { | 900 | { | |
901 | struct ifnet * const ifp = usbnet_ifp(un); | 901 | struct ifnet * const ifp = usbnet_ifp(un); | |
902 | struct mue_txbuf_hdr hdr; | 902 | struct mue_txbuf_hdr hdr; | |
903 | uint32_t tx_cmd_a, tx_cmd_b; | 903 | uint32_t tx_cmd_a, tx_cmd_b; | |
904 | int csum, len, rv; | 904 | int csum, len, rv; | |
905 | bool tso, ipe, tpe; | 905 | bool tso, ipe, tpe; | |
906 | 906 | |||
907 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) | 907 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) | |
908 | return 0; | 908 | return 0; | |
909 | 909 | |||
910 | csum = m->m_pkthdr.csum_flags; | 910 | csum = m->m_pkthdr.csum_flags; | |
911 | tso = csum & (M_CSUM_TSOv4 | M_CSUM_TSOv6); | 911 | tso = csum & (M_CSUM_TSOv4 | M_CSUM_TSOv6); | |
912 | ipe = csum & M_CSUM_IPv4; | 912 | ipe = csum & M_CSUM_IPv4; | |
913 | tpe = csum & (M_CSUM_TCPv4 | M_CSUM_UDPv4 | | 913 | tpe = csum & (M_CSUM_TCPv4 | M_CSUM_UDPv4 | | |
914 | M_CSUM_TCPv6 | M_CSUM_UDPv6); | 914 | M_CSUM_TCPv6 | M_CSUM_UDPv6); | |
915 | 915 | |||
916 | len = m->m_pkthdr.len; | 916 | len = m->m_pkthdr.len; | |
917 | if (__predict_false((!tso && len > (int)MUE_FRAME_LEN(ifp->if_mtu)) || | 917 | if (__predict_false((!tso && len > (int)MUE_FRAME_LEN(ifp->if_mtu)) || | |
918 | ( tso && len > MUE_TSO_FRAME_LEN))) { | 918 | ( tso && len > MUE_TSO_FRAME_LEN))) { | |
919 | MUE_PRINTF(un, "packet length %d\n too long", len); | 919 | MUE_PRINTF(un, "packet length %d\n too long", len); | |
920 | return 0; | 920 | return 0; | |
921 | } | 921 | } | |
922 | 922 | |||
923 | KASSERT((len & ~MUE_TX_CMD_A_LEN_MASK) == 0); | 923 | KASSERT((len & ~MUE_TX_CMD_A_LEN_MASK) == 0); | |
924 | tx_cmd_a = len | MUE_TX_CMD_A_FCS; | 924 | tx_cmd_a = len | MUE_TX_CMD_A_FCS; | |
925 | 925 | |||
926 | if (tso) { | 926 | if (tso) { | |
927 | tx_cmd_a |= MUE_TX_CMD_A_LSO; | 927 | tx_cmd_a |= MUE_TX_CMD_A_LSO; | |
928 | if (__predict_true(m->m_pkthdr.segsz > MUE_TX_MSS_MIN)) | 928 | if (__predict_true(m->m_pkthdr.segsz > MUE_TX_MSS_MIN)) | |
929 | tx_cmd_b = m->m_pkthdr.segsz; | 929 | tx_cmd_b = m->m_pkthdr.segsz; | |
930 | else | 930 | else | |
931 | tx_cmd_b = MUE_TX_MSS_MIN; | 931 | tx_cmd_b = MUE_TX_MSS_MIN; | |
932 | tx_cmd_b <<= MUE_TX_CMD_B_MSS_SHIFT; | 932 | tx_cmd_b <<= MUE_TX_CMD_B_MSS_SHIFT; | |
933 | KASSERT((tx_cmd_b & ~MUE_TX_CMD_B_MSS_MASK) == 0); | 933 | KASSERT((tx_cmd_b & ~MUE_TX_CMD_B_MSS_MASK) == 0); | |
934 | rv = mue_prepare_tso(un, m); | 934 | rv = mue_prepare_tso(un, m); | |
935 | if (__predict_false(rv)) | 935 | if (__predict_false(rv)) | |
936 | return 0; | 936 | return 0; | |
937 | } else { | 937 | } else { | |
938 | if (ipe) | 938 | if (ipe) | |
939 | tx_cmd_a |= MUE_TX_CMD_A_IPE; | 939 | tx_cmd_a |= MUE_TX_CMD_A_IPE; | |
940 | if (tpe) | 940 | if (tpe) | |
941 | tx_cmd_a |= MUE_TX_CMD_A_TPE; | 941 | tx_cmd_a |= MUE_TX_CMD_A_TPE; | |
942 | tx_cmd_b = 0; | 942 | tx_cmd_b = 0; | |
943 | } | 943 | } | |
944 | 944 | |||
945 | hdr.tx_cmd_a = htole32(tx_cmd_a); | 945 | hdr.tx_cmd_a = htole32(tx_cmd_a); | |
946 | hdr.tx_cmd_b = htole32(tx_cmd_b); | 946 | hdr.tx_cmd_b = htole32(tx_cmd_b); | |
947 | 947 | |||
948 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); | 948 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); | |
949 | m_copydata(m, 0, len, c->unc_buf + sizeof(hdr)); | 949 | m_copydata(m, 0, len, c->unc_buf + sizeof(hdr)); | |
950 | 950 | |||
951 | return len + sizeof(hdr); | 951 | return len + sizeof(hdr); | |
952 | } | 952 | } | |
953 | 953 | |||
954 | /* | 954 | /* | |
955 | * L3 length field should be cleared. | 955 | * L3 length field should be cleared. | |
956 | */ | 956 | */ | |
957 | static int | 957 | static int | |
958 | mue_prepare_tso(struct usbnet *un, struct mbuf *m) | 958 | mue_prepare_tso(struct usbnet *un, struct mbuf *m) | |
959 | { | 959 | { | |
960 | struct ether_header *eh; | 960 | struct ether_header *eh; | |
961 | struct ip *ip; | 961 | struct ip *ip; | |
962 | struct ip6_hdr *ip6; | 962 | struct ip6_hdr *ip6; | |
963 | uint16_t type, len = 0; | 963 | uint16_t type, len = 0; | |
964 | int off; | 964 | int off; | |
965 | 965 | |||
966 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | 966 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | |
967 | eh = mtod(m, struct ether_header *); | 967 | eh = mtod(m, struct ether_header *); | |
968 | type = eh->ether_type; | 968 | type = eh->ether_type; | |
969 | } else | 969 | } else | |
970 | m_copydata(m, offsetof(struct ether_header, ether_type), | 970 | m_copydata(m, offsetof(struct ether_header, ether_type), | |
971 | sizeof(type), &type); | 971 | sizeof(type), &type); | |
972 | switch (type = htons(type)) { | 972 | switch (type = htons(type)) { | |
973 | case ETHERTYPE_IP: | 973 | case ETHERTYPE_IP: | |
974 | case ETHERTYPE_IPV6: | 974 | case ETHERTYPE_IPV6: | |
975 | off = ETHER_HDR_LEN; | 975 | off = ETHER_HDR_LEN; | |
976 | break; | 976 | break; | |
977 | case ETHERTYPE_VLAN: | 977 | case ETHERTYPE_VLAN: | |
978 | off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | 978 | off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | |
979 | break; | 979 | break; | |
980 | default: | 980 | default: | |
981 | return EINVAL; | 981 | return EINVAL; | |
982 | } | 982 | } | |
983 | 983 | |||
984 | if (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) { | 984 | if (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) { | |
985 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip))) { | 985 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip))) { | |
986 | ip = (void *)(mtod(m, char *) + off); | 986 | ip = (void *)(mtod(m, char *) + off); | |
987 | ip->ip_len = 0; | 987 | ip->ip_len = 0; | |
988 | } else | 988 | } else | |
989 | m_copyback(m, off + offsetof(struct ip, ip_len), | 989 | m_copyback(m, off + offsetof(struct ip, ip_len), | |
990 | sizeof(len), &len); | 990 | sizeof(len), &len); | |
991 | } else { | 991 | } else { | |
992 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip6))) { | 992 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip6))) { | |
993 | ip6 = (void *)(mtod(m, char *) + off); | 993 | ip6 = (void *)(mtod(m, char *) + off); | |
994 | ip6->ip6_plen = 0; | 994 | ip6->ip6_plen = 0; | |
995 | } else | 995 | } else | |
996 | m_copyback(m, off + offsetof(struct ip6_hdr, ip6_plen), | 996 | m_copyback(m, off + offsetof(struct ip6_hdr, ip6_plen), | |
997 | sizeof(len), &len); | 997 | sizeof(len), &len); | |
998 | } | 998 | } | |
999 | return 0; | 999 | return 0; | |
1000 | } | 1000 | } | |
1001 | 1001 | |||
1002 | static void | 1002 | static void | |
1003 | mue_uno_mcast(struct ifnet *ifp) | 1003 | mue_uno_mcast(struct ifnet *ifp) | |
1004 | { | 1004 | { | |
1005 | struct usbnet *un = ifp->if_softc; | 1005 | struct usbnet *un = ifp->if_softc; | |
1006 | struct ethercom *ec = usbnet_ec(un); | 1006 | struct ethercom *ec = usbnet_ec(un); | |
1007 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | 1007 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | |
1008 | struct ether_multi *enm; | 1008 | struct ether_multi *enm; | |
1009 | struct ether_multistep step; | 1009 | struct ether_multistep step; | |
1010 | uint32_t pfiltbl[MUE_NUM_ADDR_FILTX][2]; | 1010 | uint32_t pfiltbl[MUE_NUM_ADDR_FILTX][2]; | |
1011 | uint32_t hashtbl[MUE_DP_SEL_VHF_HASH_LEN]; | 1011 | uint32_t hashtbl[MUE_DP_SEL_VHF_HASH_LEN]; | |
1012 | uint32_t reg, rxfilt, h, hireg, loreg; | 1012 | uint32_t reg, rxfilt, h, hireg, loreg; | |
1013 | size_t i; | 1013 | size_t i; | |
1014 | 1014 | |||
1015 | if (usbnet_isdying(un)) | 1015 | if (usbnet_isdying(un)) | |
1016 | return; | 1016 | return; | |
1017 | 1017 | |||
1018 | /* Clear perfect filter and hash tables. */ | 1018 | /* Clear perfect filter and hash tables. */ | |
1019 | memset(pfiltbl, 0, sizeof(pfiltbl)); | 1019 | memset(pfiltbl, 0, sizeof(pfiltbl)); | |
1020 | memset(hashtbl, 0, sizeof(hashtbl)); | 1020 | memset(hashtbl, 0, sizeof(hashtbl)); | |
1021 | 1021 | |||
1022 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | 1022 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | |
1023 | rxfilt = mue_csr_read(un, reg); | 1023 | rxfilt = mue_csr_read(un, reg); | |
1024 | rxfilt &= ~(MUE_RFE_CTL_PERFECT | MUE_RFE_CTL_MULTICAST_HASH | | 1024 | rxfilt &= ~(MUE_RFE_CTL_PERFECT | MUE_RFE_CTL_MULTICAST_HASH | | |
1025 | MUE_RFE_CTL_UNICAST | MUE_RFE_CTL_MULTICAST); | 1025 | MUE_RFE_CTL_UNICAST | MUE_RFE_CTL_MULTICAST); | |
1026 | 1026 | |||
1027 | /* Always accept broadcast frames. */ | 1027 | /* Always accept broadcast frames. */ | |
1028 | rxfilt |= MUE_RFE_CTL_BROADCAST; | 1028 | rxfilt |= MUE_RFE_CTL_BROADCAST; | |
1029 | 1029 | |||
1030 | ETHER_LOCK(ec); | 1030 | ETHER_LOCK(ec); | |
1031 | if (ifp->if_flags & IFF_PROMISC) { | 1031 | if (ifp->if_flags & IFF_PROMISC) { | |
1032 | rxfilt |= MUE_RFE_CTL_UNICAST; | 1032 | rxfilt |= MUE_RFE_CTL_UNICAST; | |
1033 | allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; | 1033 | allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; | |
1034 | ec->ec_flags |= ETHER_F_ALLMULTI; | 1034 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
1035 | if (ifp->if_flags & IFF_PROMISC) | 1035 | if (ifp->if_flags & IFF_PROMISC) | |
1036 | DPRINTF(un, "promisc\n"); | 1036 | DPRINTF(un, "promisc\n"); | |
1037 | else | 1037 | else | |
1038 | DPRINTF(un, "allmulti\n"); | 1038 | DPRINTF(un, "allmulti\n"); | |
1039 | } else { | 1039 | } else { | |
1040 | /* Now program new ones. */ | 1040 | /* Now program new ones. */ | |
1041 | pfiltbl[0][0] = MUE_ENADDR_HI(enaddr) | MUE_ADDR_FILTX_VALID; | 1041 | pfiltbl[0][0] = MUE_ENADDR_HI(enaddr) | MUE_ADDR_FILTX_VALID; | |
1042 | pfiltbl[0][1] = MUE_ENADDR_LO(enaddr); | 1042 | pfiltbl[0][1] = MUE_ENADDR_LO(enaddr); | |
1043 | i = 1; | 1043 | i = 1; | |
1044 | ETHER_FIRST_MULTI(step, ec, enm); | 1044 | ETHER_FIRST_MULTI(step, ec, enm); | |
1045 | while (enm != NULL) { | 1045 | while (enm != NULL) { | |
1046 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | 1046 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
1047 | ETHER_ADDR_LEN)) { | 1047 | ETHER_ADDR_LEN)) { | |
1048 | memset(pfiltbl, 0, sizeof(pfiltbl)); | 1048 | memset(pfiltbl, 0, sizeof(pfiltbl)); | |
1049 | memset(hashtbl, 0, sizeof(hashtbl)); | 1049 | memset(hashtbl, 0, sizeof(hashtbl)); | |
1050 | rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH; | 1050 | rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH; | |
1051 | goto allmulti; | 1051 | goto allmulti; | |
1052 | } | 1052 | } | |
1053 | if (i < MUE_NUM_ADDR_FILTX) { | 1053 | if (i < MUE_NUM_ADDR_FILTX) { | |
1054 | /* Use perfect address table if possible. */ | 1054 | /* Use perfect address table if possible. */ | |
1055 | pfiltbl[i][0] = MUE_ENADDR_HI(enm->enm_addrlo) | | 1055 | pfiltbl[i][0] = MUE_ENADDR_HI(enm->enm_addrlo) | | |
1056 | MUE_ADDR_FILTX_VALID; | 1056 | MUE_ADDR_FILTX_VALID; | |
1057 | pfiltbl[i][1] = MUE_ENADDR_LO(enm->enm_addrlo); | 1057 | pfiltbl[i][1] = MUE_ENADDR_LO(enm->enm_addrlo); | |
1058 | } else { | 1058 | } else { | |
1059 | /* Otherwise, use hash table. */ | 1059 | /* Otherwise, use hash table. */ | |
1060 | rxfilt |= MUE_RFE_CTL_MULTICAST_HASH; | 1060 | rxfilt |= MUE_RFE_CTL_MULTICAST_HASH; | |
1061 | h = (ether_crc32_be(enm->enm_addrlo, | 1061 | h = (ether_crc32_be(enm->enm_addrlo, | |
1062 | ETHER_ADDR_LEN) >> 23) & 0x1ff; | 1062 | ETHER_ADDR_LEN) >> 23) & 0x1ff; | |
1063 | hashtbl[h / 32] |= 1 << (h % 32); | 1063 | hashtbl[h / 32] |= 1 << (h % 32); | |
1064 | } | 1064 | } | |
1065 | i++; | 1065 | i++; | |
1066 | ETHER_NEXT_MULTI(step, enm); | 1066 | ETHER_NEXT_MULTI(step, enm); | |
1067 | } | 1067 | } | |
1068 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 1068 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
1069 | rxfilt |= MUE_RFE_CTL_PERFECT; | 1069 | rxfilt |= MUE_RFE_CTL_PERFECT; | |
1070 | if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH) | 1070 | if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH) | |
1071 | DPRINTF(un, "perfect filter and hash tables\n"); | 1071 | DPRINTF(un, "perfect filter and hash tables\n"); | |
1072 | else | 1072 | else | |
1073 | DPRINTF(un, "perfect filter\n"); | 1073 | DPRINTF(un, "perfect filter\n"); | |
1074 | } | 1074 | } | |
1075 | ETHER_UNLOCK(ec); | 1075 | ETHER_UNLOCK(ec); | |
1076 | 1076 | |||
1077 | for (i = 0; i < MUE_NUM_ADDR_FILTX; i++) { | 1077 | for (i = 0; i < MUE_NUM_ADDR_FILTX; i++) { | |
1078 | hireg = (un->un_flags & LAN7500) ? | 1078 | hireg = (un->un_flags & LAN7500) ? | |
1079 | MUE_7500_ADDR_FILTX(i) : MUE_7800_ADDR_FILTX(i); | 1079 | MUE_7500_ADDR_FILTX(i) : MUE_7800_ADDR_FILTX(i); | |
1080 | loreg = hireg + 4; | 1080 | loreg = hireg + 4; | |
1081 | mue_csr_write(un, hireg, 0); | 1081 | mue_csr_write(un, hireg, 0); | |
1082 | mue_csr_write(un, loreg, pfiltbl[i][1]); | 1082 | mue_csr_write(un, loreg, pfiltbl[i][1]); | |
1083 | mue_csr_write(un, hireg, pfiltbl[i][0]); | 1083 | mue_csr_write(un, hireg, pfiltbl[i][0]); | |
1084 | } | 1084 | } | |
1085 | 1085 | |||
1086 | mue_dataport_write(un, MUE_DP_SEL_VHF, MUE_DP_SEL_VHF_VLAN_LEN, | 1086 | mue_dataport_write(un, MUE_DP_SEL_VHF, MUE_DP_SEL_VHF_VLAN_LEN, | |
1087 | MUE_DP_SEL_VHF_HASH_LEN, hashtbl); | 1087 | MUE_DP_SEL_VHF_HASH_LEN, hashtbl); | |
1088 | 1088 | |||
1089 | mue_csr_write(un, reg, rxfilt); | 1089 | mue_csr_write(un, reg, rxfilt); | |
1090 | } | 1090 | } | |
1091 | 1091 | |||
1092 | static void | 1092 | static void | |
1093 | mue_sethwcsum_locked(struct usbnet *un) | 1093 | mue_sethwcsum_locked(struct usbnet *un) | |
1094 | { | 1094 | { | |
1095 | struct ifnet * const ifp = usbnet_ifp(un); | 1095 | struct ifnet * const ifp = usbnet_ifp(un); | |
1096 | uint32_t reg, val; | 1096 | uint32_t reg, val; | |
1097 | 1097 | |||
1098 | KASSERT(IFNET_LOCKED(ifp)); | 1098 | KASSERT(IFNET_LOCKED(ifp)); | |
1099 | 1099 | |||
1100 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | 1100 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | |
1101 | val = mue_csr_read(un, reg); | 1101 | val = mue_csr_read(un, reg); | |
1102 | 1102 | |||
1103 | if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) { | 1103 | if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) { | |
1104 | DPRINTF(un, "RX IPv4 hwcsum enabled\n"); | 1104 | DPRINTF(un, "RX IPv4 hwcsum enabled\n"); | |
1105 | val |= MUE_RFE_CTL_IP_COE; | 1105 | val |= MUE_RFE_CTL_IP_COE; | |
1106 | } else { | 1106 | } else { | |
1107 | DPRINTF(un, "RX IPv4 hwcsum disabled\n"); | 1107 | DPRINTF(un, "RX IPv4 hwcsum disabled\n"); | |
1108 | val &= ~MUE_RFE_CTL_IP_COE; | 1108 | val &= ~MUE_RFE_CTL_IP_COE; | |
1109 | } | 1109 | } | |
1110 | 1110 | |||
1111 | if (ifp->if_capenable & | 1111 | if (ifp->if_capenable & | |
1112 | (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | 1112 | (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | |
1113 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { | 1113 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { | |
1114 | DPRINTF(un, "RX L4 hwcsum enabled\n"); | 1114 | DPRINTF(un, "RX L4 hwcsum enabled\n"); | |
1115 | val |= MUE_RFE_CTL_TCPUDP_COE; | 1115 | val |= MUE_RFE_CTL_TCPUDP_COE; | |
1116 | } else { | 1116 | } else { | |
1117 | DPRINTF(un, "RX L4 hwcsum disabled\n"); | 1117 | DPRINTF(un, "RX L4 hwcsum disabled\n"); | |
1118 | val &= ~MUE_RFE_CTL_TCPUDP_COE; | 1118 | val &= ~MUE_RFE_CTL_TCPUDP_COE; | |
1119 | } | 1119 | } | |
1120 | 1120 | |||
1121 | val &= ~MUE_RFE_CTL_VLAN_FILTER; | 1121 | val &= ~MUE_RFE_CTL_VLAN_FILTER; | |
1122 | 1122 | |||
1123 | mue_csr_write(un, reg, val); | 1123 | mue_csr_write(un, reg, val); | |
1124 | } | 1124 | } | |
1125 | 1125 | |||
1126 | static void | 1126 | static void | |
1127 | mue_setmtu_locked(struct usbnet *un) | 1127 | mue_setmtu_locked(struct usbnet *un) | |
1128 | { | 1128 | { | |
1129 | struct ifnet * const ifp = usbnet_ifp(un); | 1129 | struct ifnet * const ifp = usbnet_ifp(un); | |
1130 | uint32_t val; | 1130 | uint32_t val; | |
1131 | 1131 | |||
1132 | KASSERT(IFNET_LOCKED(ifp)); | 1132 | KASSERT(IFNET_LOCKED(ifp)); | |
1133 | 1133 | |||
1134 | /* Set the maximum frame size. */ | 1134 | /* Set the maximum frame size. */ | |
1135 | MUE_CLRBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | 1135 | MUE_CLRBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | |
1136 | val = mue_csr_read(un, MUE_MAC_RX); | 1136 | val = mue_csr_read(un, MUE_MAC_RX); | |
1137 | val &= ~MUE_MAC_RX_MAX_SIZE_MASK; | 1137 | val &= ~MUE_MAC_RX_MAX_SIZE_MASK; | |
1138 | val |= MUE_MAC_RX_MAX_LEN(MUE_FRAME_LEN(ifp->if_mtu)); | 1138 | val |= MUE_MAC_RX_MAX_LEN(MUE_FRAME_LEN(ifp->if_mtu)); | |
1139 | mue_csr_write(un, MUE_MAC_RX, val); | 1139 | mue_csr_write(un, MUE_MAC_RX, val); | |
1140 | MUE_SETBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | 1140 | MUE_SETBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | |
1141 | } | 1141 | } | |
1142 | 1142 | |||
1143 | static void | 1143 | static void | |
1144 | mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 1144 | mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
1145 | { | 1145 | { | |
1146 | struct ifnet * const ifp = usbnet_ifp(un); | 1146 | struct ifnet * const ifp = usbnet_ifp(un); | |
1147 | struct mue_rxbuf_hdr *hdrp; | 1147 | struct mue_rxbuf_hdr *hdrp; | |
1148 | uint32_t rx_cmd_a; | 1148 | uint32_t rx_cmd_a; | |
1149 | uint16_t pktlen; | 1149 | uint16_t pktlen; | |
1150 | int csum; | 1150 | int csum; | |
1151 | uint8_t *buf = c->unc_buf; | 1151 | uint8_t *buf = c->unc_buf; | |
1152 | bool v6; | 1152 | bool v6; | |
1153 | 1153 | |||
1154 | KASSERTMSG(total_len <= un->un_rx_bufsz, "%u vs %u", | 1154 | KASSERTMSG(total_len <= un->un_rx_bufsz, "%u vs %u", | |
1155 | total_len, un->un_rx_bufsz); | 1155 | total_len, un->un_rx_bufsz); | |
1156 | 1156 | |||
1157 | do { | 1157 | do { | |
1158 | if (__predict_false(total_len < sizeof(*hdrp))) { | 1158 | if (__predict_false(total_len < sizeof(*hdrp))) { | |
1159 | MUE_PRINTF(un, "packet length %u too short\n", total_len); | 1159 | MUE_PRINTF(un, "packet length %u too short\n", total_len); | |
1160 | if_statinc(ifp, if_ierrors); | 1160 | if_statinc(ifp, if_ierrors); | |
1161 | return; | 1161 | return; | |
1162 | } | 1162 | } | |
1163 | 1163 | |||
1164 | hdrp = (struct mue_rxbuf_hdr *)buf; | 1164 | hdrp = (struct mue_rxbuf_hdr *)buf; | |
1165 | rx_cmd_a = le32toh(hdrp->rx_cmd_a); | 1165 | rx_cmd_a = le32toh(hdrp->rx_cmd_a); | |
1166 | 1166 | |||
1167 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ERRORS)) { | 1167 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ERRORS)) { | |
1168 | /* | 1168 | /* | |
1169 | * We cannot use MUE_RX_CMD_A_RED bit here; | 1169 | * We cannot use MUE_RX_CMD_A_RED bit here; | |
1170 | * it is turned on in the cases of L3/L4 | 1170 | * it is turned on in the cases of L3/L4 | |
1171 | * checksum errors which we handle below. | 1171 | * checksum errors which we handle below. | |
1172 | */ | 1172 | */ | |
1173 | MUE_PRINTF(un, "rx_cmd_a: %#x\n", rx_cmd_a); | 1173 | MUE_PRINTF(un, "rx_cmd_a: %#x\n", rx_cmd_a); | |
1174 | if_statinc(ifp, if_ierrors); | 1174 | if_statinc(ifp, if_ierrors); | |
1175 | return; | 1175 | return; | |
1176 | } | 1176 | } | |
1177 | 1177 | |||
1178 | pktlen = (uint16_t)(rx_cmd_a & MUE_RX_CMD_A_LEN_MASK); | 1178 | pktlen = (uint16_t)(rx_cmd_a & MUE_RX_CMD_A_LEN_MASK); | |
1179 | if (un->un_flags & LAN7500) | 1179 | if (un->un_flags & LAN7500) | |
1180 | pktlen -= 2; | 1180 | pktlen -= 2; | |
1181 | 1181 | |||
1182 | if (__predict_false(pktlen < ETHER_HDR_LEN + ETHER_CRC_LEN || | 1182 | if (__predict_false(pktlen < ETHER_HDR_LEN + ETHER_CRC_LEN || | |
1183 | pktlen > MCLBYTES - ETHER_ALIGN || /* XXX */ | 1183 | pktlen > MCLBYTES - ETHER_ALIGN || /* XXX */ | |
1184 | pktlen + sizeof(*hdrp) > total_len)) { | 1184 | pktlen + sizeof(*hdrp) > total_len)) { | |
1185 | MUE_PRINTF(un, "invalid packet length %d\n", pktlen); | 1185 | MUE_PRINTF(un, "invalid packet length %d\n", pktlen); | |
1186 | if_statinc(ifp, if_ierrors); | 1186 | if_statinc(ifp, if_ierrors); | |
1187 | return; | 1187 | return; | |
1188 | } | 1188 | } | |
1189 | 1189 | |||
1190 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ICSM)) { | 1190 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ICSM)) { | |
1191 | csum = 0; | 1191 | csum = 0; | |
1192 | } else { | 1192 | } else { | |
1193 | v6 = rx_cmd_a & MUE_RX_CMD_A_IPV; | 1193 | v6 = rx_cmd_a & MUE_RX_CMD_A_IPV; | |
1194 | switch (rx_cmd_a & MUE_RX_CMD_A_PID) { | 1194 | switch (rx_cmd_a & MUE_RX_CMD_A_PID) { | |
1195 | case MUE_RX_CMD_A_PID_TCP: | 1195 | case MUE_RX_CMD_A_PID_TCP: | |
1196 | csum = v6 ? | 1196 | csum = v6 ? | |
1197 | M_CSUM_TCPv6 : M_CSUM_IPv4 | M_CSUM_TCPv4; | 1197 | M_CSUM_TCPv6 : M_CSUM_IPv4 | M_CSUM_TCPv4; | |
1198 | break; | 1198 | break; | |
1199 | case MUE_RX_CMD_A_PID_UDP: | 1199 | case MUE_RX_CMD_A_PID_UDP: | |
1200 | csum = v6 ? | 1200 | csum = v6 ? | |
1201 | M_CSUM_UDPv6 : M_CSUM_IPv4 | M_CSUM_UDPv4; | 1201 | M_CSUM_UDPv6 : M_CSUM_IPv4 | M_CSUM_UDPv4; | |
1202 | break; | 1202 | break; | |
1203 | case MUE_RX_CMD_A_PID_IP: | 1203 | case MUE_RX_CMD_A_PID_IP: | |
1204 | csum = v6 ? 0 : M_CSUM_IPv4; | 1204 | csum = v6 ? 0 : M_CSUM_IPv4; | |
1205 | break; | 1205 | break; | |
1206 | default: | 1206 | default: | |
1207 | csum = 0; | 1207 | csum = 0; | |
1208 | break; | 1208 | break; | |
1209 | } | 1209 | } | |
1210 | csum &= ifp->if_csum_flags_rx; | 1210 | csum &= ifp->if_csum_flags_rx; | |
1211 | if (__predict_false((csum & M_CSUM_IPv4) && | 1211 | if (__predict_false((csum & M_CSUM_IPv4) && | |
1212 | (rx_cmd_a & MUE_RX_CMD_A_ICE))) | 1212 | (rx_cmd_a & MUE_RX_CMD_A_ICE))) | |
1213 | csum |= M_CSUM_IPv4_BAD; | 1213 | csum |= M_CSUM_IPv4_BAD; | |
1214 | if (__predict_false((csum & ~M_CSUM_IPv4) && | 1214 | if (__predict_false((csum & ~M_CSUM_IPv4) && | |
1215 | (rx_cmd_a & MUE_RX_CMD_A_TCE))) | 1215 | (rx_cmd_a & MUE_RX_CMD_A_TCE))) | |
1216 | csum |= M_CSUM_TCP_UDP_BAD; | 1216 | csum |= M_CSUM_TCP_UDP_BAD; | |
1217 | } | 1217 | } | |
1218 | 1218 | |||
1219 | usbnet_enqueue(un, buf + sizeof(*hdrp), pktlen, csum, | 1219 | usbnet_enqueue(un, buf + sizeof(*hdrp), pktlen, csum, | |
1220 | 0, M_HASFCS); | 1220 | 0, M_HASFCS); | |
1221 | 1221 | |||
1222 | /* Attention: sizeof(hdr) = 10 */ | 1222 | /* Attention: sizeof(hdr) = 10 */ | |
1223 | pktlen = roundup(pktlen + sizeof(*hdrp), 4); | 1223 | pktlen = roundup(pktlen + sizeof(*hdrp), 4); | |
1224 | if (pktlen > total_len) | 1224 | if (pktlen > total_len) | |
1225 | pktlen = total_len; | 1225 | pktlen = total_len; | |
1226 | total_len -= pktlen; | 1226 | total_len -= pktlen; | |
1227 | buf += pktlen; | 1227 | buf += pktlen; | |
1228 | } while (total_len > 0); | 1228 | } while (total_len > 0); | |
1229 | } | 1229 | } | |
1230 | 1230 | |||
1231 | static int | 1231 | static int | |
1232 | mue_uno_init(struct ifnet *ifp) | 1232 | mue_uno_init(struct ifnet *ifp) | |
1233 | { | 1233 | { | |
1234 | struct usbnet * const un = ifp->if_softc; | 1234 | struct usbnet * const un = ifp->if_softc; | |
1235 | 1235 | |||
1236 | if (usbnet_isdying(un)) { | |||
1237 | DPRINTF(un, "dying\n"); | |||
1238 | return EIO; | |||
1239 | } | |||
1240 | ||||
1241 | /* Cancel pending I/O and free all TX/RX buffers. */ | 1236 | /* Cancel pending I/O and free all TX/RX buffers. */ | |
1242 | if (ifp->if_flags & IFF_RUNNING) | 1237 | if (ifp->if_flags & IFF_RUNNING) | |
1243 | usbnet_stop(un, ifp, 1); | 1238 | usbnet_stop(un, ifp, 1); | |
1244 | 1239 | |||
1245 | mue_reset(un); | 1240 | mue_reset(un); | |
1246 | 1241 | |||
1247 | /* Set MAC address. */ | 1242 | /* Set MAC address. */ | |
1248 | mue_set_macaddr(un); | 1243 | mue_set_macaddr(un); | |
1249 | 1244 | |||
1250 | /* TCP/UDP checksum offload engines. */ | 1245 | /* TCP/UDP checksum offload engines. */ | |
1251 | mue_sethwcsum_locked(un); | 1246 | mue_sethwcsum_locked(un); | |
1252 | 1247 | |||
1253 | /* Set MTU. */ | 1248 | /* Set MTU. */ | |
1254 | mue_setmtu_locked(un); | 1249 | mue_setmtu_locked(un); | |
1255 | 1250 | |||
1256 | return usbnet_init_rx_tx(un); | 1251 | return usbnet_init_rx_tx(un); | |
1257 | } | 1252 | } | |
1258 | 1253 | |||
1259 | static int | 1254 | static int | |
1260 | mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 1255 | mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
1261 | { | 1256 | { | |
1262 | struct usbnet * const un = ifp->if_softc; | 1257 | struct usbnet * const un = ifp->if_softc; | |
1263 | 1258 | |||
1264 | switch (cmd) { | 1259 | switch (cmd) { | |
1265 | case SIOCSIFCAP: | 1260 | case SIOCSIFCAP: | |
1266 | mue_sethwcsum_locked(un); | 1261 | mue_sethwcsum_locked(un); | |
1267 | break; | 1262 | break; | |
1268 | case SIOCSIFMTU: | 1263 | case SIOCSIFMTU: | |
1269 | mue_setmtu_locked(un); | 1264 | mue_setmtu_locked(un); | |
1270 | break; | 1265 | break; | |
1271 | default: | 1266 | default: | |
1272 | break; | 1267 | break; | |
1273 | } | 1268 | } | |
1274 | 1269 | |||
1275 | return 0; | 1270 | return 0; | |
1276 | } | 1271 | } | |
1277 | 1272 | |||
1278 | static void | 1273 | static void | |
1279 | mue_reset(struct usbnet *un) | 1274 | mue_reset(struct usbnet *un) | |
1280 | { | 1275 | { | |
1281 | if (usbnet_isdying(un)) | 1276 | if (usbnet_isdying(un)) | |
1282 | return; | 1277 | return; | |
1283 | 1278 | |||
1284 | /* Wait a little while for the chip to get its brains in order. */ | 1279 | /* Wait a little while for the chip to get its brains in order. */ | |
1285 | usbd_delay_ms(un->un_udev, 1); | 1280 | usbd_delay_ms(un->un_udev, 1); | |
1286 | 1281 | |||
1287 | // mue_chip_init(un); /* XXX */ | 1282 | // mue_chip_init(un); /* XXX */ | |
1288 | } | 1283 | } | |
1289 | 1284 | |||
1290 | static void | 1285 | static void | |
1291 | mue_uno_stop(struct ifnet *ifp, int disable) | 1286 | mue_uno_stop(struct ifnet *ifp, int disable) | |
1292 | { | 1287 | { | |
1293 | struct usbnet * const un = ifp->if_softc; | 1288 | struct usbnet * const un = ifp->if_softc; | |
1294 | 1289 | |||
1295 | mue_reset(un); | 1290 | mue_reset(un); | |
1296 | } | 1291 | } | |
1297 | 1292 | |||
1298 | #ifdef _MODULE | 1293 | #ifdef _MODULE | |
1299 | #include "ioconf.c" | 1294 | #include "ioconf.c" | |
1300 | #endif | 1295 | #endif | |
1301 | 1296 | |||
1302 | USBNET_MODULE(mue) | 1297 | USBNET_MODULE(mue) |
--- src/sys/dev/usb/if_smsc.c 2022/03/03 05:54:37 1.87
+++ src/sys/dev/usb/if_smsc.c 2022/03/03 05:55:01 1.88
@@ -1,1060 +1,1057 @@ | @@ -1,1060 +1,1057 @@ | |||
1 | /* $NetBSD: if_smsc.c,v 1.87 2022/03/03 05:54:37 riastradh Exp $ */ | 1 | /* $NetBSD: if_smsc.c,v 1.88 2022/03/03 05:55:01 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.87 2022/03/03 05:54:37 riastradh Exp $"); | 64 | __KERNEL_RCSID(0, "$NetBSD: if_smsc.c,v 1.88 2022/03/03 05:55:01 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 void smsc_uno_stop(struct ifnet *, int); | 177 | static void smsc_uno_stop(struct ifnet *, int); | |
178 | 178 | |||
179 | static void smsc_reset(struct smsc_softc *); | 179 | static void smsc_reset(struct smsc_softc *); | |
180 | 180 | |||
181 | static void smsc_uno_miibus_statchg(struct ifnet *); | 181 | static void smsc_uno_miibus_statchg(struct ifnet *); | |
182 | static int smsc_readreg(struct usbnet *, uint32_t, uint32_t *); | 182 | static int smsc_readreg(struct usbnet *, uint32_t, uint32_t *); | |
183 | static int smsc_writereg(struct usbnet *, uint32_t, uint32_t); | 183 | static int smsc_writereg(struct usbnet *, uint32_t, uint32_t); | |
184 | static int smsc_wait_for_bits(struct usbnet *, uint32_t, uint32_t); | 184 | static int smsc_wait_for_bits(struct usbnet *, uint32_t, uint32_t); | |
185 | static int smsc_uno_miibus_readreg(struct usbnet *, int, int, uint16_t *); | 185 | static int smsc_uno_miibus_readreg(struct usbnet *, int, int, uint16_t *); | |
186 | static int smsc_uno_miibus_writereg(struct usbnet *, int, int, uint16_t); | 186 | static int smsc_uno_miibus_writereg(struct usbnet *, int, int, uint16_t); | |
187 | 187 | |||
188 | static int smsc_uno_ioctl(struct ifnet *, u_long, void *); | 188 | static int smsc_uno_ioctl(struct ifnet *, u_long, void *); | |
189 | static void smsc_uno_mcast(struct ifnet *); | 189 | static void smsc_uno_mcast(struct ifnet *); | |
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_mcast = smsc_uno_mcast, | 198 | .uno_mcast = smsc_uno_mcast, | |
199 | .uno_read_reg = smsc_uno_miibus_readreg, | 199 | .uno_read_reg = smsc_uno_miibus_readreg, | |
200 | .uno_write_reg = smsc_uno_miibus_writereg, | 200 | .uno_write_reg = smsc_uno_miibus_writereg, | |
201 | .uno_statchg = smsc_uno_miibus_statchg, | 201 | .uno_statchg = smsc_uno_miibus_statchg, | |
202 | .uno_tx_prepare = smsc_uno_tx_prepare, | 202 | .uno_tx_prepare = smsc_uno_tx_prepare, | |
203 | .uno_rx_loop = smsc_uno_rx_loop, | 203 | .uno_rx_loop = smsc_uno_rx_loop, | |
204 | .uno_init = smsc_uno_init, | 204 | .uno_init = smsc_uno_init, | |
205 | }; | 205 | }; | |
206 | 206 | |||
207 | static int | 207 | static int | |
208 | smsc_readreg(struct usbnet *un, uint32_t off, uint32_t *data) | 208 | smsc_readreg(struct usbnet *un, uint32_t off, uint32_t *data) | |
209 | { | 209 | { | |
210 | usb_device_request_t req; | 210 | usb_device_request_t req; | |
211 | uint32_t buf; | 211 | uint32_t buf; | |
212 | usbd_status err; | 212 | usbd_status err; | |
213 | 213 | |||
214 | if (usbnet_isdying(un)) | 214 | if (usbnet_isdying(un)) | |
215 | return 0; | 215 | return 0; | |
216 | 216 | |||
217 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 217 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
218 | req.bRequest = SMSC_UR_READ_REG; | 218 | req.bRequest = SMSC_UR_READ_REG; | |
219 | USETW(req.wValue, 0); | 219 | USETW(req.wValue, 0); | |
220 | USETW(req.wIndex, off); | 220 | USETW(req.wIndex, off); | |
221 | USETW(req.wLength, 4); | 221 | USETW(req.wLength, 4); | |
222 | 222 | |||
223 | err = usbd_do_request(un->un_udev, &req, &buf); | 223 | err = usbd_do_request(un->un_udev, &req, &buf); | |
224 | if (err != 0) | 224 | if (err != 0) | |
225 | smsc_warn_printf(un, "Failed to read register 0x%0x\n", off); | 225 | smsc_warn_printf(un, "Failed to read register 0x%0x\n", off); | |
226 | 226 | |||
227 | *data = le32toh(buf); | 227 | *data = le32toh(buf); | |
228 | 228 | |||
229 | return err; | 229 | return err; | |
230 | } | 230 | } | |
231 | 231 | |||
232 | static int | 232 | static int | |
233 | smsc_writereg(struct usbnet *un, uint32_t off, uint32_t data) | 233 | smsc_writereg(struct usbnet *un, uint32_t off, uint32_t data) | |
234 | { | 234 | { | |
235 | usb_device_request_t req; | 235 | usb_device_request_t req; | |
236 | uint32_t buf; | 236 | uint32_t buf; | |
237 | usbd_status err; | 237 | usbd_status err; | |
238 | 238 | |||
239 | if (usbnet_isdying(un)) | 239 | if (usbnet_isdying(un)) | |
240 | return 0; | 240 | return 0; | |
241 | 241 | |||
242 | buf = htole32(data); | 242 | buf = htole32(data); | |
243 | 243 | |||
244 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 244 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
245 | req.bRequest = SMSC_UR_WRITE_REG; | 245 | req.bRequest = SMSC_UR_WRITE_REG; | |
246 | USETW(req.wValue, 0); | 246 | USETW(req.wValue, 0); | |
247 | USETW(req.wIndex, off); | 247 | USETW(req.wIndex, off); | |
248 | USETW(req.wLength, 4); | 248 | USETW(req.wLength, 4); | |
249 | 249 | |||
250 | err = usbd_do_request(un->un_udev, &req, &buf); | 250 | err = usbd_do_request(un->un_udev, &req, &buf); | |
251 | if (err != 0) | 251 | if (err != 0) | |
252 | smsc_warn_printf(un, "Failed to write register 0x%0x\n", off); | 252 | smsc_warn_printf(un, "Failed to write register 0x%0x\n", off); | |
253 | 253 | |||
254 | return err; | 254 | return err; | |
255 | } | 255 | } | |
256 | 256 | |||
257 | static int | 257 | static int | |
258 | smsc_wait_for_bits(struct usbnet *un, uint32_t reg, uint32_t bits) | 258 | smsc_wait_for_bits(struct usbnet *un, uint32_t reg, uint32_t bits) | |
259 | { | 259 | { | |
260 | uint32_t val; | 260 | uint32_t val; | |
261 | int err, i; | 261 | int err, i; | |
262 | 262 | |||
263 | for (i = 0; i < 100; i++) { | 263 | for (i = 0; i < 100; i++) { | |
264 | if (usbnet_isdying(un)) | 264 | if (usbnet_isdying(un)) | |
265 | return ENXIO; | 265 | return ENXIO; | |
266 | if ((err = smsc_readreg(un, reg, &val)) != 0) | 266 | if ((err = smsc_readreg(un, reg, &val)) != 0) | |
267 | return err; | 267 | return err; | |
268 | if (!(val & bits)) | 268 | if (!(val & bits)) | |
269 | return 0; | 269 | return 0; | |
270 | DELAY(5); | 270 | DELAY(5); | |
271 | } | 271 | } | |
272 | 272 | |||
273 | return 1; | 273 | return 1; | |
274 | } | 274 | } | |
275 | 275 | |||
276 | static int | 276 | static int | |
277 | smsc_uno_miibus_readreg(struct usbnet *un, int phy, int reg, uint16_t *val) | 277 | smsc_uno_miibus_readreg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
278 | { | 278 | { | |
279 | uint32_t addr; | 279 | uint32_t addr; | |
280 | uint32_t data = 0; | 280 | uint32_t data = 0; | |
281 | 281 | |||
282 | if (un->un_phyno != phy) { | 282 | if (un->un_phyno != phy) { | |
283 | *val = 0; | 283 | *val = 0; | |
284 | return EINVAL; | 284 | return EINVAL; | |
285 | } | 285 | } | |
286 | 286 | |||
287 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | 287 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | |
288 | smsc_warn_printf(un, "MII is busy\n"); | 288 | smsc_warn_printf(un, "MII is busy\n"); | |
289 | *val = 0; | 289 | *val = 0; | |
290 | return ETIMEDOUT; | 290 | return ETIMEDOUT; | |
291 | } | 291 | } | |
292 | 292 | |||
293 | addr = (phy << 11) | (reg << 6) | SMSC_MII_READ; | 293 | addr = (phy << 11) | (reg << 6) | SMSC_MII_READ; | |
294 | smsc_writereg(un, SMSC_MII_ADDR, addr); | 294 | smsc_writereg(un, SMSC_MII_ADDR, addr); | |
295 | 295 | |||
296 | 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) { | |
297 | smsc_warn_printf(un, "MII read timeout\n"); | 297 | smsc_warn_printf(un, "MII read timeout\n"); | |
298 | *val = 0; | 298 | *val = 0; | |
299 | return ETIMEDOUT; | 299 | return ETIMEDOUT; | |
300 | } | 300 | } | |
301 | 301 | |||
302 | smsc_readreg(un, SMSC_MII_DATA, &data); | 302 | smsc_readreg(un, SMSC_MII_DATA, &data); | |
303 | 303 | |||
304 | *val = data & 0xffff; | 304 | *val = data & 0xffff; | |
305 | return 0; | 305 | return 0; | |
306 | } | 306 | } | |
307 | 307 | |||
308 | static int | 308 | static int | |
309 | smsc_uno_miibus_writereg(struct usbnet *un, int phy, int reg, uint16_t val) | 309 | smsc_uno_miibus_writereg(struct usbnet *un, int phy, int reg, uint16_t val) | |
310 | { | 310 | { | |
311 | uint32_t addr; | 311 | uint32_t addr; | |
312 | 312 | |||
313 | if (un->un_phyno != phy) | 313 | if (un->un_phyno != phy) | |
314 | return EINVAL; | 314 | return EINVAL; | |
315 | 315 | |||
316 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | 316 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | |
317 | smsc_warn_printf(un, "MII is busy\n"); | 317 | smsc_warn_printf(un, "MII is busy\n"); | |
318 | return ETIMEDOUT; | 318 | return ETIMEDOUT; | |
319 | } | 319 | } | |
320 | 320 | |||
321 | smsc_writereg(un, SMSC_MII_DATA, val); | 321 | smsc_writereg(un, SMSC_MII_DATA, val); | |
322 | 322 | |||
323 | addr = (phy << 11) | (reg << 6) | SMSC_MII_WRITE; | 323 | addr = (phy << 11) | (reg << 6) | SMSC_MII_WRITE; | |
324 | smsc_writereg(un, SMSC_MII_ADDR, addr); | 324 | smsc_writereg(un, SMSC_MII_ADDR, addr); | |
325 | 325 | |||
326 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | 326 | if (smsc_wait_for_bits(un, SMSC_MII_ADDR, SMSC_MII_BUSY) != 0) { | |
327 | smsc_warn_printf(un, "MII write timeout\n"); | 327 | smsc_warn_printf(un, "MII write timeout\n"); | |
328 | return ETIMEDOUT; | 328 | return ETIMEDOUT; | |
329 | } | 329 | } | |
330 | 330 | |||
331 | return 0; | 331 | return 0; | |
332 | } | 332 | } | |
333 | 333 | |||
334 | static void | 334 | static void | |
335 | smsc_uno_miibus_statchg(struct ifnet *ifp) | 335 | smsc_uno_miibus_statchg(struct ifnet *ifp) | |
336 | { | 336 | { | |
337 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | 337 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | |
338 | struct usbnet * const un = ifp->if_softc; | 338 | struct usbnet * const un = ifp->if_softc; | |
339 | 339 | |||
340 | if (usbnet_isdying(un)) | 340 | if (usbnet_isdying(un)) | |
341 | return; | 341 | return; | |
342 | 342 | |||
343 | struct smsc_softc * const sc = usbnet_softc(un); | 343 | struct smsc_softc * const sc = usbnet_softc(un); | |
344 | struct mii_data * const mii = usbnet_mii(un); | 344 | struct mii_data * const mii = usbnet_mii(un); | |
345 | uint32_t flow; | 345 | uint32_t flow; | |
346 | uint32_t afc_cfg; | 346 | uint32_t afc_cfg; | |
347 | 347 | |||
348 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 348 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
349 | (IFM_ACTIVE | IFM_AVALID)) { | 349 | (IFM_ACTIVE | IFM_AVALID)) { | |
350 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 350 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
351 | case IFM_10_T: | 351 | case IFM_10_T: | |
352 | case IFM_100_TX: | 352 | case IFM_100_TX: | |
353 | usbnet_set_link(un, true); | 353 | usbnet_set_link(un, true); | |
354 | break; | 354 | break; | |
355 | case IFM_1000_T: | 355 | case IFM_1000_T: | |
356 | /* Gigabit ethernet not supported by chipset */ | 356 | /* Gigabit ethernet not supported by chipset */ | |
357 | break; | 357 | break; | |
358 | default: | 358 | default: | |
359 | break; | 359 | break; | |
360 | } | 360 | } | |
361 | } | 361 | } | |
362 | 362 | |||
363 | /* Lost link, do nothing. */ | 363 | /* Lost link, do nothing. */ | |
364 | if (!usbnet_havelink(un)) | 364 | if (!usbnet_havelink(un)) | |
365 | return; | 365 | return; | |
366 | 366 | |||
367 | int err = smsc_readreg(un, SMSC_AFC_CFG, &afc_cfg); | 367 | int err = smsc_readreg(un, SMSC_AFC_CFG, &afc_cfg); | |
368 | if (err) { | 368 | if (err) { | |
369 | smsc_warn_printf(un, "failed to read initial AFC_CFG, " | 369 | smsc_warn_printf(un, "failed to read initial AFC_CFG, " | |
370 | "error %d\n", err); | 370 | "error %d\n", err); | |
371 | return; | 371 | return; | |
372 | } | 372 | } | |
373 | 373 | |||
374 | /* Enable/disable full duplex operation and TX/RX pause */ | 374 | /* Enable/disable full duplex operation and TX/RX pause */ | |
375 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { | 375 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) { | |
376 | DPRINTF("full duplex operation", 0, 0, 0, 0); | 376 | DPRINTF("full duplex operation", 0, 0, 0, 0); | |
377 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_RCVOWN; | 377 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_RCVOWN; | |
378 | sc->sc_mac_csr |= SMSC_MAC_CSR_FDPX; | 378 | sc->sc_mac_csr |= SMSC_MAC_CSR_FDPX; | |
379 | 379 | |||
380 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) | 380 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0) | |
381 | flow = 0xffff0002; | 381 | flow = 0xffff0002; | |
382 | else | 382 | else | |
383 | flow = 0; | 383 | flow = 0; | |
384 | 384 | |||
385 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) | 385 | if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0) | |
386 | afc_cfg |= 0xf; | 386 | afc_cfg |= 0xf; | |
387 | else | 387 | else | |
388 | afc_cfg &= ~0xf; | 388 | afc_cfg &= ~0xf; | |
389 | } else { | 389 | } else { | |
390 | DPRINTF("half duplex operation", 0, 0, 0, 0); | 390 | DPRINTF("half duplex operation", 0, 0, 0, 0); | |
391 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_FDPX; | 391 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_FDPX; | |
392 | sc->sc_mac_csr |= SMSC_MAC_CSR_RCVOWN; | 392 | sc->sc_mac_csr |= SMSC_MAC_CSR_RCVOWN; | |
393 | 393 | |||
394 | flow = 0; | 394 | flow = 0; | |
395 | afc_cfg |= 0xf; | 395 | afc_cfg |= 0xf; | |
396 | } | 396 | } | |
397 | 397 | |||
398 | err = smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 398 | err = smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
399 | err += smsc_writereg(un, SMSC_FLOW, flow); | 399 | err += smsc_writereg(un, SMSC_FLOW, flow); | |
400 | err += smsc_writereg(un, SMSC_AFC_CFG, afc_cfg); | 400 | err += smsc_writereg(un, SMSC_AFC_CFG, afc_cfg); | |
401 | 401 | |||
402 | if (err) | 402 | if (err) | |
403 | smsc_warn_printf(un, "media change failed, error %d\n", err); | 403 | smsc_warn_printf(un, "media change failed, error %d\n", err); | |
404 | } | 404 | } | |
405 | 405 | |||
406 | static inline uint32_t | 406 | static inline uint32_t | |
407 | smsc_hash(uint8_t addr[ETHER_ADDR_LEN]) | 407 | smsc_hash(uint8_t addr[ETHER_ADDR_LEN]) | |
408 | { | 408 | { | |
409 | 409 | |||
410 | return (ether_crc32_be(addr, ETHER_ADDR_LEN) >> 26) & 0x3f; | 410 | return (ether_crc32_be(addr, ETHER_ADDR_LEN) >> 26) & 0x3f; | |
411 | } | 411 | } | |
412 | 412 | |||
413 | static void | 413 | static void | |
414 | smsc_uno_mcast(struct ifnet *ifp) | 414 | smsc_uno_mcast(struct ifnet *ifp) | |
415 | { | 415 | { | |
416 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | 416 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | |
417 | struct usbnet * const un = ifp->if_softc; | 417 | struct usbnet * const un = ifp->if_softc; | |
418 | struct smsc_softc * const sc = usbnet_softc(un); | 418 | struct smsc_softc * const sc = usbnet_softc(un); | |
419 | struct ethercom *ec = usbnet_ec(un); | 419 | struct ethercom *ec = usbnet_ec(un); | |
420 | struct ether_multi *enm; | 420 | struct ether_multi *enm; | |
421 | struct ether_multistep step; | 421 | struct ether_multistep step; | |
422 | uint32_t hashtbl[2] = { 0, 0 }; | 422 | uint32_t hashtbl[2] = { 0, 0 }; | |
423 | uint32_t hash; | 423 | uint32_t hash; | |
424 | 424 | |||
425 | if (usbnet_isdying(un)) | 425 | if (usbnet_isdying(un)) | |
426 | return; | 426 | return; | |
427 | 427 | |||
428 | if (ifp->if_flags & IFF_PROMISC) { | 428 | if (ifp->if_flags & IFF_PROMISC) { | |
429 | ETHER_LOCK(ec); | 429 | ETHER_LOCK(ec); | |
430 | allmulti: | 430 | allmulti: | |
431 | ec->ec_flags |= ETHER_F_ALLMULTI; | 431 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
432 | ETHER_UNLOCK(ec); | 432 | ETHER_UNLOCK(ec); | |
433 | DPRINTF("receive all multicast enabled", 0, 0, 0, 0); | 433 | DPRINTF("receive all multicast enabled", 0, 0, 0, 0); | |
434 | sc->sc_mac_csr |= SMSC_MAC_CSR_MCPAS; | 434 | sc->sc_mac_csr |= SMSC_MAC_CSR_MCPAS; | |
435 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_HPFILT; | 435 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_HPFILT; | |
436 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 436 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
437 | return; | 437 | return; | |
438 | } else { | 438 | } else { | |
439 | sc->sc_mac_csr |= SMSC_MAC_CSR_HPFILT; | 439 | sc->sc_mac_csr |= SMSC_MAC_CSR_HPFILT; | |
440 | sc->sc_mac_csr &= ~(SMSC_MAC_CSR_PRMS | SMSC_MAC_CSR_MCPAS); | 440 | sc->sc_mac_csr &= ~(SMSC_MAC_CSR_PRMS | SMSC_MAC_CSR_MCPAS); | |
441 | } | 441 | } | |
442 | 442 | |||
443 | ETHER_LOCK(ec); | 443 | ETHER_LOCK(ec); | |
444 | ETHER_FIRST_MULTI(step, ec, enm); | 444 | ETHER_FIRST_MULTI(step, ec, enm); | |
445 | while (enm != NULL) { | 445 | while (enm != NULL) { | |
446 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 446 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
447 | goto allmulti; | 447 | goto allmulti; | |
448 | } | 448 | } | |
449 | 449 | |||
450 | hash = smsc_hash(enm->enm_addrlo); | 450 | hash = smsc_hash(enm->enm_addrlo); | |
451 | hashtbl[hash >> 5] |= 1 << (hash & 0x1F); | 451 | hashtbl[hash >> 5] |= 1 << (hash & 0x1F); | |
452 | ETHER_NEXT_MULTI(step, enm); | 452 | ETHER_NEXT_MULTI(step, enm); | |
453 | } | 453 | } | |
454 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 454 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
455 | ETHER_UNLOCK(ec); | 455 | ETHER_UNLOCK(ec); | |
456 | 456 | |||
457 | /* Debug */ | 457 | /* Debug */ | |
458 | if (sc->sc_mac_csr & SMSC_MAC_CSR_HPFILT) { | 458 | if (sc->sc_mac_csr & SMSC_MAC_CSR_HPFILT) { | |
459 | DPRINTF("receive select group of macs", 0, 0, 0, 0); | 459 | DPRINTF("receive select group of macs", 0, 0, 0, 0); | |
460 | } else { | 460 | } else { | |
461 | DPRINTF("receive own packets only", 0, 0, 0, 0); | 461 | DPRINTF("receive own packets only", 0, 0, 0, 0); | |
462 | } | 462 | } | |
463 | 463 | |||
464 | /* Write the hash table and mac control registers */ | 464 | /* Write the hash table and mac control registers */ | |
465 | 465 | |||
466 | //XXX should we be doing this? | 466 | //XXX should we be doing this? | |
467 | smsc_writereg(un, SMSC_HASHH, hashtbl[1]); | 467 | smsc_writereg(un, SMSC_HASHH, hashtbl[1]); | |
468 | smsc_writereg(un, SMSC_HASHL, hashtbl[0]); | 468 | smsc_writereg(un, SMSC_HASHL, hashtbl[0]); | |
469 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 469 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
470 | } | 470 | } | |
471 | 471 | |||
472 | static int | 472 | static int | |
473 | smsc_setoe_locked(struct usbnet *un) | 473 | smsc_setoe_locked(struct usbnet *un) | |
474 | { | 474 | { | |
475 | struct smsc_softc * const sc = usbnet_softc(un); | 475 | struct smsc_softc * const sc = usbnet_softc(un); | |
476 | struct ifnet * const ifp = usbnet_ifp(un); | 476 | struct ifnet * const ifp = usbnet_ifp(un); | |
477 | uint32_t val; | 477 | uint32_t val; | |
478 | int err; | 478 | int err; | |
479 | 479 | |||
480 | KASSERT(IFNET_LOCKED(ifp)); | 480 | KASSERT(IFNET_LOCKED(ifp)); | |
481 | 481 | |||
482 | err = smsc_readreg(un, SMSC_COE_CTRL, &val); | 482 | err = smsc_readreg(un, SMSC_COE_CTRL, &val); | |
483 | if (err != 0) { | 483 | if (err != 0) { | |
484 | smsc_warn_printf(un, "failed to read SMSC_COE_CTRL (err=%d)\n", | 484 | smsc_warn_printf(un, "failed to read SMSC_COE_CTRL (err=%d)\n", | |
485 | err); | 485 | err); | |
486 | return err; | 486 | return err; | |
487 | } | 487 | } | |
488 | 488 | |||
489 | /* Enable/disable the Rx checksum */ | 489 | /* Enable/disable the Rx checksum */ | |
490 | if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx)) | 490 | if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx)) | |
491 | val |= (SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE); | 491 | val |= (SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE); | |
492 | else | 492 | else | |
493 | val &= ~(SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE); | 493 | val &= ~(SMSC_COE_CTRL_RX_EN | SMSC_COE_CTRL_RX_MODE); | |
494 | 494 | |||
495 | /* Enable/disable the Tx checksum (currently not supported) */ | 495 | /* Enable/disable the Tx checksum (currently not supported) */ | |
496 | if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx)) | 496 | if (ifp->if_capenable & (IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx)) | |
497 | val |= SMSC_COE_CTRL_TX_EN; | 497 | val |= SMSC_COE_CTRL_TX_EN; | |
498 | else | 498 | else | |
499 | val &= ~SMSC_COE_CTRL_TX_EN; | 499 | val &= ~SMSC_COE_CTRL_TX_EN; | |
500 | 500 | |||
501 | sc->sc_coe_ctrl = val; | 501 | sc->sc_coe_ctrl = val; | |
502 | 502 | |||
503 | err = smsc_writereg(un, SMSC_COE_CTRL, val); | 503 | err = smsc_writereg(un, SMSC_COE_CTRL, val); | |
504 | if (err != 0) { | 504 | if (err != 0) { | |
505 | smsc_warn_printf(un, "failed to write SMSC_COE_CTRL (err=%d)\n", | 505 | smsc_warn_printf(un, "failed to write SMSC_COE_CTRL (err=%d)\n", | |
506 | err); | 506 | err); | |
507 | return err; | 507 | return err; | |
508 | } | 508 | } | |
509 | 509 | |||
510 | return 0; | 510 | return 0; | |
511 | } | 511 | } | |
512 | 512 | |||
513 | static int | 513 | static int | |
514 | smsc_setmacaddress(struct usbnet *un, const uint8_t *addr) | 514 | smsc_setmacaddress(struct usbnet *un, const uint8_t *addr) | |
515 | { | 515 | { | |
516 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | 516 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | |
517 | int err; | 517 | int err; | |
518 | uint32_t val; | 518 | uint32_t val; | |
519 | 519 | |||
520 | DPRINTF("setting mac address to %02jx:%02jx:%02jx:...", addr[0], | 520 | DPRINTF("setting mac address to %02jx:%02jx:%02jx:...", addr[0], | |
521 | addr[1], addr[2], 0); | 521 | addr[1], addr[2], 0); | |
522 | 522 | |||
523 | DPRINTF("... %02jx:%02jx:%02jx", addr[3], addr[4], addr[5], 0); | 523 | DPRINTF("... %02jx:%02jx:%02jx", addr[3], addr[4], addr[5], 0); | |
524 | 524 | |||
525 | val = ((uint32_t)addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | 525 | val = ((uint32_t)addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | |
526 | | addr[0]; | 526 | | addr[0]; | |
527 | if ((err = smsc_writereg(un, SMSC_MAC_ADDRL, val)) != 0) | 527 | if ((err = smsc_writereg(un, SMSC_MAC_ADDRL, val)) != 0) | |
528 | goto done; | 528 | goto done; | |
529 | 529 | |||
530 | val = (addr[5] << 8) | addr[4]; | 530 | val = (addr[5] << 8) | addr[4]; | |
531 | err = smsc_writereg(un, SMSC_MAC_ADDRH, val); | 531 | err = smsc_writereg(un, SMSC_MAC_ADDRH, val); | |
532 | 532 | |||
533 | done: | 533 | done: | |
534 | return err; | 534 | return err; | |
535 | } | 535 | } | |
536 | 536 | |||
537 | static void | 537 | static void | |
538 | smsc_reset(struct smsc_softc *sc) | 538 | smsc_reset(struct smsc_softc *sc) | |
539 | { | 539 | { | |
540 | struct usbnet * const un = &sc->smsc_un; | 540 | struct usbnet * const un = &sc->smsc_un; | |
541 | 541 | |||
542 | if (usbnet_isdying(un)) | 542 | if (usbnet_isdying(un)) | |
543 | return; | 543 | return; | |
544 | 544 | |||
545 | /* 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. */ | |
546 | DELAY(1000); | 546 | DELAY(1000); | |
547 | 547 | |||
548 | /* Reinitialize controller to achieve full reset. */ | 548 | /* Reinitialize controller to achieve full reset. */ | |
549 | smsc_chip_init(un); | 549 | smsc_chip_init(un); | |
550 | } | 550 | } | |
551 | 551 | |||
552 | static int | 552 | static int | |
553 | smsc_uno_init(struct ifnet *ifp) | 553 | smsc_uno_init(struct ifnet *ifp) | |
554 | { | 554 | { | |
555 | struct usbnet * const un = ifp->if_softc; | 555 | struct usbnet * const un = ifp->if_softc; | |
556 | struct smsc_softc * const sc = usbnet_softc(un); | 556 | struct smsc_softc * const sc = usbnet_softc(un); | |
557 | 557 | |||
558 | if (usbnet_isdying(un)) | |||
559 | return EIO; | |||
560 | ||||
561 | /* Cancel pending I/O */ | 558 | /* Cancel pending I/O */ | |
562 | usbnet_stop(un, ifp, 1); | 559 | usbnet_stop(un, ifp, 1); | |
563 | 560 | |||
564 | /* Reset the ethernet interface. */ | 561 | /* Reset the ethernet interface. */ | |
565 | smsc_reset(sc); | 562 | smsc_reset(sc); | |
566 | 563 | |||
567 | /* TCP/UDP checksum offload engines. */ | 564 | /* TCP/UDP checksum offload engines. */ | |
568 | smsc_setoe_locked(un); | 565 | smsc_setoe_locked(un); | |
569 | 566 | |||
570 | return usbnet_init_rx_tx(un); | 567 | return usbnet_init_rx_tx(un); | |
571 | } | 568 | } | |
572 | 569 | |||
573 | static void | 570 | static void | |
574 | smsc_uno_stop(struct ifnet *ifp, int disable) | 571 | smsc_uno_stop(struct ifnet *ifp, int disable) | |
575 | { | 572 | { | |
576 | struct usbnet * const un = ifp->if_softc; | 573 | struct usbnet * const un = ifp->if_softc; | |
577 | struct smsc_softc * const sc = usbnet_softc(un); | 574 | struct smsc_softc * const sc = usbnet_softc(un); | |
578 | 575 | |||
579 | // XXXNH didn't do this before | 576 | // XXXNH didn't do this before | |
580 | smsc_reset(sc); | 577 | smsc_reset(sc); | |
581 | } | 578 | } | |
582 | 579 | |||
583 | static int | 580 | static int | |
584 | smsc_chip_init(struct usbnet *un) | 581 | smsc_chip_init(struct usbnet *un) | |
585 | { | 582 | { | |
586 | struct smsc_softc * const sc = usbnet_softc(un); | 583 | struct smsc_softc * const sc = usbnet_softc(un); | |
587 | uint32_t reg_val; | 584 | uint32_t reg_val; | |
588 | int burst_cap; | 585 | int burst_cap; | |
589 | int err; | 586 | int err; | |
590 | 587 | |||
591 | /* Enter H/W config mode */ | 588 | /* Enter H/W config mode */ | |
592 | smsc_writereg(un, SMSC_HW_CFG, SMSC_HW_CFG_LRST); | 589 | smsc_writereg(un, SMSC_HW_CFG, SMSC_HW_CFG_LRST); | |
593 | 590 | |||
594 | if ((err = smsc_wait_for_bits(un, SMSC_HW_CFG, | 591 | if ((err = smsc_wait_for_bits(un, SMSC_HW_CFG, | |
595 | SMSC_HW_CFG_LRST)) != 0) { | 592 | SMSC_HW_CFG_LRST)) != 0) { | |
596 | smsc_warn_printf(un, "timed-out waiting for reset to " | 593 | smsc_warn_printf(un, "timed-out waiting for reset to " | |
597 | "complete\n"); | 594 | "complete\n"); | |
598 | goto init_failed; | 595 | goto init_failed; | |
599 | } | 596 | } | |
600 | 597 | |||
601 | /* Reset the PHY */ | 598 | /* Reset the PHY */ | |
602 | smsc_writereg(un, SMSC_PM_CTRL, SMSC_PM_CTRL_PHY_RST); | 599 | smsc_writereg(un, SMSC_PM_CTRL, SMSC_PM_CTRL_PHY_RST); | |
603 | 600 | |||
604 | if ((err = smsc_wait_for_bits(un, SMSC_PM_CTRL, | 601 | if ((err = smsc_wait_for_bits(un, SMSC_PM_CTRL, | |
605 | SMSC_PM_CTRL_PHY_RST)) != 0) { | 602 | SMSC_PM_CTRL_PHY_RST)) != 0) { | |
606 | smsc_warn_printf(un, "timed-out waiting for phy reset to " | 603 | smsc_warn_printf(un, "timed-out waiting for phy reset to " | |
607 | "complete\n"); | 604 | "complete\n"); | |
608 | goto init_failed; | 605 | goto init_failed; | |
609 | } | 606 | } | |
610 | usbd_delay_ms(un->un_udev, 40); | 607 | usbd_delay_ms(un->un_udev, 40); | |
611 | 608 | |||
612 | /* Set the mac address */ | 609 | /* Set the mac address */ | |
613 | struct ifnet * const ifp = usbnet_ifp(un); | 610 | struct ifnet * const ifp = usbnet_ifp(un); | |
614 | const char *eaddr = CLLADDR(ifp->if_sadl); | 611 | const char *eaddr = CLLADDR(ifp->if_sadl); | |
615 | if ((err = smsc_setmacaddress(un, eaddr)) != 0) { | 612 | if ((err = smsc_setmacaddress(un, eaddr)) != 0) { | |
616 | smsc_warn_printf(un, "failed to set the MAC address\n"); | 613 | smsc_warn_printf(un, "failed to set the MAC address\n"); | |
617 | goto init_failed; | 614 | goto init_failed; | |
618 | } | 615 | } | |
619 | 616 | |||
620 | /* | 617 | /* | |
621 | * Don't know what the HW_CFG_BIR bit is, but following the reset | 618 | * Don't know what the HW_CFG_BIR bit is, but following the reset | |
622 | * sequence as used in the Linux driver. | 619 | * sequence as used in the Linux driver. | |
623 | */ | 620 | */ | |
624 | if ((err = smsc_readreg(un, SMSC_HW_CFG, ®_val)) != 0) { | 621 | if ((err = smsc_readreg(un, SMSC_HW_CFG, ®_val)) != 0) { | |
625 | smsc_warn_printf(un, "failed to read HW_CFG: %d\n", err); | 622 | smsc_warn_printf(un, "failed to read HW_CFG: %d\n", err); | |
626 | goto init_failed; | 623 | goto init_failed; | |
627 | } | 624 | } | |
628 | reg_val |= SMSC_HW_CFG_BIR; | 625 | reg_val |= SMSC_HW_CFG_BIR; | |
629 | smsc_writereg(un, SMSC_HW_CFG, reg_val); | 626 | smsc_writereg(un, SMSC_HW_CFG, reg_val); | |
630 | 627 | |||
631 | /* | 628 | /* | |
632 | * There is a so called 'turbo mode' that the linux driver supports, it | 629 | * There is a so called 'turbo mode' that the linux driver supports, it | |
633 | * seems to allow you to jam multiple frames per Rx transaction. | 630 | * seems to allow you to jam multiple frames per Rx transaction. | |
634 | * By default this driver supports that and therefore allows multiple | 631 | * By default this driver supports that and therefore allows multiple | |
635 | * frames per USB transfer. | 632 | * frames per USB transfer. | |
636 | * | 633 | * | |
637 | * The xfer buffer size needs to reflect this as well, therefore based | 634 | * The xfer buffer size needs to reflect this as well, therefore based | |
638 | * on the calculations in the Linux driver the RX bufsize is set to | 635 | * on the calculations in the Linux driver the RX bufsize is set to | |
639 | * 18944, | 636 | * 18944, | |
640 | * bufsz = (16 * 1024 + 5 * 512) | 637 | * bufsz = (16 * 1024 + 5 * 512) | |
641 | * | 638 | * | |
642 | * Burst capability is the number of URBs that can be in a burst of | 639 | * Burst capability is the number of URBs that can be in a burst of | |
643 | * data/ethernet frames. | 640 | * data/ethernet frames. | |
644 | */ | 641 | */ | |
645 | 642 | |||
646 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | 643 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | |
647 | burst_cap = 37; | 644 | burst_cap = 37; | |
648 | else | 645 | else | |
649 | burst_cap = 128; | 646 | burst_cap = 128; | |
650 | 647 | |||
651 | smsc_writereg(un, SMSC_BURST_CAP, burst_cap); | 648 | smsc_writereg(un, SMSC_BURST_CAP, burst_cap); | |
652 | 649 | |||
653 | /* Set the default bulk in delay (magic value from Linux driver) */ | 650 | /* Set the default bulk in delay (magic value from Linux driver) */ | |
654 | smsc_writereg(un, SMSC_BULK_IN_DLY, 0x00002000); | 651 | smsc_writereg(un, SMSC_BULK_IN_DLY, 0x00002000); | |
655 | 652 | |||
656 | /* | 653 | /* | |
657 | * Initialise the RX interface | 654 | * Initialise the RX interface | |
658 | */ | 655 | */ | |
659 | if ((err = smsc_readreg(un, SMSC_HW_CFG, ®_val)) < 0) { | 656 | if ((err = smsc_readreg(un, SMSC_HW_CFG, ®_val)) < 0) { | |
660 | smsc_warn_printf(un, "failed to read HW_CFG: (err = %d)\n", | 657 | smsc_warn_printf(un, "failed to read HW_CFG: (err = %d)\n", | |
661 | err); | 658 | err); | |
662 | goto init_failed; | 659 | goto init_failed; | |
663 | } | 660 | } | |
664 | 661 | |||
665 | /* | 662 | /* | |
666 | * The following settings are used for 'turbo mode', a.k.a multiple | 663 | * The following settings are used for 'turbo mode', a.k.a multiple | |
667 | * frames per Rx transaction (again info taken form Linux driver). | 664 | * frames per Rx transaction (again info taken form Linux driver). | |
668 | */ | 665 | */ | |
669 | reg_val |= (SMSC_HW_CFG_MEF | SMSC_HW_CFG_BCE); | 666 | reg_val |= (SMSC_HW_CFG_MEF | SMSC_HW_CFG_BCE); | |
670 | 667 | |||
671 | /* | 668 | /* | |
672 | * set Rx data offset to ETHER_ALIGN which will make the IP header | 669 | * set Rx data offset to ETHER_ALIGN which will make the IP header | |
673 | * align on a word boundary. | 670 | * align on a word boundary. | |
674 | */ | 671 | */ | |
675 | reg_val |= ETHER_ALIGN << SMSC_HW_CFG_RXDOFF_SHIFT; | 672 | reg_val |= ETHER_ALIGN << SMSC_HW_CFG_RXDOFF_SHIFT; | |
676 | 673 | |||
677 | smsc_writereg(un, SMSC_HW_CFG, reg_val); | 674 | smsc_writereg(un, SMSC_HW_CFG, reg_val); | |
678 | 675 | |||
679 | /* Clear the status register ? */ | 676 | /* Clear the status register ? */ | |
680 | smsc_writereg(un, SMSC_INTR_STATUS, 0xffffffff); | 677 | smsc_writereg(un, SMSC_INTR_STATUS, 0xffffffff); | |
681 | 678 | |||
682 | /* Read and display the revision register */ | 679 | /* Read and display the revision register */ | |
683 | if ((err = smsc_readreg(un, SMSC_ID_REV, &sc->sc_rev_id)) < 0) { | 680 | if ((err = smsc_readreg(un, SMSC_ID_REV, &sc->sc_rev_id)) < 0) { | |
684 | smsc_warn_printf(un, "failed to read ID_REV (err = %d)\n", err); | 681 | smsc_warn_printf(un, "failed to read ID_REV (err = %d)\n", err); | |
685 | goto init_failed; | 682 | goto init_failed; | |
686 | } | 683 | } | |
687 | 684 | |||
688 | /* GPIO/LED setup */ | 685 | /* GPIO/LED setup */ | |
689 | reg_val = SMSC_LED_GPIO_CFG_SPD_LED | SMSC_LED_GPIO_CFG_LNK_LED | | 686 | reg_val = SMSC_LED_GPIO_CFG_SPD_LED | SMSC_LED_GPIO_CFG_LNK_LED | | |
690 | SMSC_LED_GPIO_CFG_FDX_LED; | 687 | SMSC_LED_GPIO_CFG_FDX_LED; | |
691 | smsc_writereg(un, SMSC_LED_GPIO_CFG, reg_val); | 688 | smsc_writereg(un, SMSC_LED_GPIO_CFG, reg_val); | |
692 | 689 | |||
693 | /* | 690 | /* | |
694 | * Initialise the TX interface | 691 | * Initialise the TX interface | |
695 | */ | 692 | */ | |
696 | smsc_writereg(un, SMSC_FLOW, 0); | 693 | smsc_writereg(un, SMSC_FLOW, 0); | |
697 | 694 | |||
698 | smsc_writereg(un, SMSC_AFC_CFG, AFC_CFG_DEFAULT); | 695 | smsc_writereg(un, SMSC_AFC_CFG, AFC_CFG_DEFAULT); | |
699 | 696 | |||
700 | /* Read the current MAC configuration */ | 697 | /* Read the current MAC configuration */ | |
701 | if ((err = smsc_readreg(un, SMSC_MAC_CSR, &sc->sc_mac_csr)) < 0) { | 698 | if ((err = smsc_readreg(un, SMSC_MAC_CSR, &sc->sc_mac_csr)) < 0) { | |
702 | smsc_warn_printf(un, "failed to read MAC_CSR (err=%d)\n", err); | 699 | smsc_warn_printf(un, "failed to read MAC_CSR (err=%d)\n", err); | |
703 | goto init_failed; | 700 | goto init_failed; | |
704 | } | 701 | } | |
705 | 702 | |||
706 | /* disable pad stripping, collides with checksum offload */ | 703 | /* disable pad stripping, collides with checksum offload */ | |
707 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_PADSTR; | 704 | sc->sc_mac_csr &= ~SMSC_MAC_CSR_PADSTR; | |
708 | 705 | |||
709 | /* Vlan */ | 706 | /* Vlan */ | |
710 | smsc_writereg(un, SMSC_VLAN1, (uint32_t)ETHERTYPE_VLAN); | 707 | smsc_writereg(un, SMSC_VLAN1, (uint32_t)ETHERTYPE_VLAN); | |
711 | 708 | |||
712 | /* | 709 | /* | |
713 | * Start TX | 710 | * Start TX | |
714 | */ | 711 | */ | |
715 | sc->sc_mac_csr |= SMSC_MAC_CSR_TXEN; | 712 | sc->sc_mac_csr |= SMSC_MAC_CSR_TXEN; | |
716 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 713 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
717 | smsc_writereg(un, SMSC_TX_CFG, SMSC_TX_CFG_ON); | 714 | smsc_writereg(un, SMSC_TX_CFG, SMSC_TX_CFG_ON); | |
718 | 715 | |||
719 | /* | 716 | /* | |
720 | * Start RX | 717 | * Start RX | |
721 | */ | 718 | */ | |
722 | sc->sc_mac_csr |= SMSC_MAC_CSR_RXEN; | 719 | sc->sc_mac_csr |= SMSC_MAC_CSR_RXEN; | |
723 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | 720 | smsc_writereg(un, SMSC_MAC_CSR, sc->sc_mac_csr); | |
724 | 721 | |||
725 | return 0; | 722 | return 0; | |
726 | 723 | |||
727 | init_failed: | 724 | init_failed: | |
728 | smsc_err_printf(un, "smsc_chip_init failed (err=%d)\n", err); | 725 | smsc_err_printf(un, "smsc_chip_init failed (err=%d)\n", err); | |
729 | return err; | 726 | return err; | |
730 | } | 727 | } | |
731 | 728 | |||
732 | static int | 729 | static int | |
733 | smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 730 | smsc_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
734 | { | 731 | { | |
735 | struct usbnet * const un = ifp->if_softc; | 732 | struct usbnet * const un = ifp->if_softc; | |
736 | 733 | |||
737 | switch (cmd) { | 734 | switch (cmd) { | |
738 | case SIOCSIFCAP: | 735 | case SIOCSIFCAP: | |
739 | smsc_setoe_locked(un); | 736 | smsc_setoe_locked(un); | |
740 | break; | 737 | break; | |
741 | default: | 738 | default: | |
742 | break; | 739 | break; | |
743 | } | 740 | } | |
744 | 741 | |||
745 | return 0; | 742 | return 0; | |
746 | } | 743 | } | |
747 | 744 | |||
748 | static int | 745 | static int | |
749 | smsc_match(device_t parent, cfdata_t match, void *aux) | 746 | smsc_match(device_t parent, cfdata_t match, void *aux) | |
750 | { | 747 | { | |
751 | struct usb_attach_arg *uaa = aux; | 748 | struct usb_attach_arg *uaa = aux; | |
752 | 749 | |||
753 | return (usb_lookup(smsc_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL) ? | 750 | return (usb_lookup(smsc_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL) ? | |
754 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 751 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
755 | } | 752 | } | |
756 | 753 | |||
757 | static void | 754 | static void | |
758 | smsc_attach(device_t parent, device_t self, void *aux) | 755 | smsc_attach(device_t parent, device_t self, void *aux) | |
759 | { | 756 | { | |
760 | USBNET_MII_DECL_DEFAULT(unm); | 757 | USBNET_MII_DECL_DEFAULT(unm); | |
761 | struct smsc_softc * const sc = device_private(self); | 758 | struct smsc_softc * const sc = device_private(self); | |
762 | struct usbnet * const un = &sc->smsc_un; | 759 | struct usbnet * const un = &sc->smsc_un; | |
763 | struct usb_attach_arg *uaa = aux; | 760 | struct usb_attach_arg *uaa = aux; | |
764 | struct usbd_device *dev = uaa->uaa_device; | 761 | struct usbd_device *dev = uaa->uaa_device; | |
765 | usb_interface_descriptor_t *id; | 762 | usb_interface_descriptor_t *id; | |
766 | usb_endpoint_descriptor_t *ed; | 763 | usb_endpoint_descriptor_t *ed; | |
767 | char *devinfop; | 764 | char *devinfop; | |
768 | unsigned bufsz; | 765 | unsigned bufsz; | |
769 | int err, i; | 766 | int err, i; | |
770 | uint32_t mac_h, mac_l; | 767 | uint32_t mac_h, mac_l; | |
771 | 768 | |||
772 | KASSERT((void *)sc == un); | 769 | KASSERT((void *)sc == un); | |
773 | 770 | |||
774 | aprint_naive("\n"); | 771 | aprint_naive("\n"); | |
775 | aprint_normal("\n"); | 772 | aprint_normal("\n"); | |
776 | 773 | |||
777 | un->un_dev = self; | 774 | un->un_dev = self; | |
778 | un->un_udev = dev; | 775 | un->un_udev = dev; | |
779 | un->un_sc = sc; | 776 | un->un_sc = sc; | |
780 | un->un_ops = &smsc_ops; | 777 | un->un_ops = &smsc_ops; | |
781 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 778 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
782 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 779 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
783 | un->un_rx_list_cnt = SMSC_RX_LIST_CNT; | 780 | un->un_rx_list_cnt = SMSC_RX_LIST_CNT; | |
784 | un->un_tx_list_cnt = SMSC_TX_LIST_CNT; | 781 | un->un_tx_list_cnt = SMSC_TX_LIST_CNT; | |
785 | 782 | |||
786 | devinfop = usbd_devinfo_alloc(un->un_udev, 0); | 783 | devinfop = usbd_devinfo_alloc(un->un_udev, 0); | |
787 | aprint_normal_dev(self, "%s\n", devinfop); | 784 | aprint_normal_dev(self, "%s\n", devinfop); | |
788 | usbd_devinfo_free(devinfop); | 785 | usbd_devinfo_free(devinfop); | |
789 | 786 | |||
790 | err = usbd_set_config_no(dev, SMSC_CONFIG_INDEX, 1); | 787 | err = usbd_set_config_no(dev, SMSC_CONFIG_INDEX, 1); | |
791 | if (err) { | 788 | if (err) { | |
792 | aprint_error_dev(self, "failed to set configuration" | 789 | aprint_error_dev(self, "failed to set configuration" | |
793 | ", err=%s\n", usbd_errstr(err)); | 790 | ", err=%s\n", usbd_errstr(err)); | |
794 | return; | 791 | return; | |
795 | } | 792 | } | |
796 | 793 | |||
797 | /* Setup the endpoints for the SMSC LAN95xx device(s) */ | 794 | /* Setup the endpoints for the SMSC LAN95xx device(s) */ | |
798 | err = usbd_device2interface_handle(dev, SMSC_IFACE_IDX, &un->un_iface); | 795 | err = usbd_device2interface_handle(dev, SMSC_IFACE_IDX, &un->un_iface); | |
799 | if (err) { | 796 | if (err) { | |
800 | aprint_error_dev(self, "getting interface handle failed\n"); | 797 | aprint_error_dev(self, "getting interface handle failed\n"); | |
801 | return; | 798 | return; | |
802 | } | 799 | } | |
803 | 800 | |||
804 | id = usbd_get_interface_descriptor(un->un_iface); | 801 | id = usbd_get_interface_descriptor(un->un_iface); | |
805 | 802 | |||
806 | if (dev->ud_speed >= USB_SPEED_HIGH) { | 803 | if (dev->ud_speed >= USB_SPEED_HIGH) { | |
807 | bufsz = SMSC_MAX_BUFSZ; | 804 | bufsz = SMSC_MAX_BUFSZ; | |
808 | } else { | 805 | } else { | |
809 | bufsz = SMSC_MIN_BUFSZ; | 806 | bufsz = SMSC_MIN_BUFSZ; | |
810 | } | 807 | } | |
811 | un->un_rx_bufsz = bufsz; | 808 | un->un_rx_bufsz = bufsz; | |
812 | un->un_tx_bufsz = bufsz; | 809 | un->un_tx_bufsz = bufsz; | |
813 | 810 | |||
814 | /* Find endpoints. */ | 811 | /* Find endpoints. */ | |
815 | for (i = 0; i < id->bNumEndpoints; i++) { | 812 | for (i = 0; i < id->bNumEndpoints; i++) { | |
816 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 813 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
817 | if (!ed) { | 814 | if (!ed) { | |
818 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 815 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
819 | return; | 816 | return; | |
820 | } | 817 | } | |
821 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 818 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
822 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 819 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
823 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 820 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
824 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 821 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
825 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 822 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
826 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 823 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
827 | #if 0 /* not used yet */ | 824 | #if 0 /* not used yet */ | |
828 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 825 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
829 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | 826 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | |
830 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 827 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
831 | #endif | 828 | #endif | |
832 | } | 829 | } | |
833 | } | 830 | } | |
834 | 831 | |||
835 | usbnet_attach(un, "smscdet"); | 832 | usbnet_attach(un, "smscdet"); | |
836 | 833 | |||
837 | #ifdef notyet | 834 | #ifdef notyet | |
838 | /* | 835 | /* | |
839 | * We can do TCPv4, and UDPv4 checksums in hardware. | 836 | * We can do TCPv4, and UDPv4 checksums in hardware. | |
840 | */ | 837 | */ | |
841 | struct ifnet *ifp = usbnet_ifp(un); | 838 | struct ifnet *ifp = usbnet_ifp(un); | |
842 | 839 | |||
843 | ifp->if_capabilities |= | 840 | ifp->if_capabilities |= | |
844 | /*IFCAP_CSUM_TCPv4_Tx |*/ IFCAP_CSUM_TCPv4_Rx | | 841 | /*IFCAP_CSUM_TCPv4_Tx |*/ IFCAP_CSUM_TCPv4_Rx | | |
845 | /*IFCAP_CSUM_UDPv4_Tx |*/ IFCAP_CSUM_UDPv4_Rx; | 842 | /*IFCAP_CSUM_UDPv4_Tx |*/ IFCAP_CSUM_UDPv4_Rx; | |
846 | #endif | 843 | #endif | |
847 | struct ethercom *ec = usbnet_ec(un); | 844 | struct ethercom *ec = usbnet_ec(un); | |
848 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | 845 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | |
849 | 846 | |||
850 | /* Setup some of the basics */ | 847 | /* Setup some of the basics */ | |
851 | un->un_phyno = 1; | 848 | un->un_phyno = 1; | |
852 | 849 | |||
853 | /* | 850 | /* | |
854 | * Attempt to get the mac address, if an EEPROM is not attached this | 851 | * Attempt to get the mac address, if an EEPROM is not attached this | |
855 | * will just return FF:FF:FF:FF:FF:FF, so in such cases we invent a MAC | 852 | * will just return FF:FF:FF:FF:FF:FF, so in such cases we invent a MAC | |
856 | * address based on urandom. | 853 | * address based on urandom. | |
857 | */ | 854 | */ | |
858 | memset(un->un_eaddr, 0xff, ETHER_ADDR_LEN); | 855 | memset(un->un_eaddr, 0xff, ETHER_ADDR_LEN); | |
859 | 856 | |||
860 | prop_dictionary_t dict = device_properties(self); | 857 | prop_dictionary_t dict = device_properties(self); | |
861 | prop_data_t eaprop = prop_dictionary_get(dict, "mac-address"); | 858 | prop_data_t eaprop = prop_dictionary_get(dict, "mac-address"); | |
862 | 859 | |||
863 | if (eaprop != NULL) { | 860 | if (eaprop != NULL) { | |
864 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | 861 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | |
865 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | 862 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | |
866 | memcpy(un->un_eaddr, prop_data_value(eaprop), | 863 | memcpy(un->un_eaddr, prop_data_value(eaprop), | |
867 | ETHER_ADDR_LEN); | 864 | ETHER_ADDR_LEN); | |
868 | } else { | 865 | } else { | |
869 | /* Check if there is already a MAC address in the register */ | 866 | /* Check if there is already a MAC address in the register */ | |
870 | if ((smsc_readreg(un, SMSC_MAC_ADDRL, &mac_l) == 0) && | 867 | if ((smsc_readreg(un, SMSC_MAC_ADDRL, &mac_l) == 0) && | |
871 | (smsc_readreg(un, SMSC_MAC_ADDRH, &mac_h) == 0)) { | 868 | (smsc_readreg(un, SMSC_MAC_ADDRH, &mac_h) == 0)) { | |
872 | un->un_eaddr[5] = (uint8_t)((mac_h >> 8) & 0xff); | 869 | un->un_eaddr[5] = (uint8_t)((mac_h >> 8) & 0xff); | |
873 | un->un_eaddr[4] = (uint8_t)((mac_h) & 0xff); | 870 | un->un_eaddr[4] = (uint8_t)((mac_h) & 0xff); | |
874 | un->un_eaddr[3] = (uint8_t)((mac_l >> 24) & 0xff); | 871 | un->un_eaddr[3] = (uint8_t)((mac_l >> 24) & 0xff); | |
875 | un->un_eaddr[2] = (uint8_t)((mac_l >> 16) & 0xff); | 872 | un->un_eaddr[2] = (uint8_t)((mac_l >> 16) & 0xff); | |
876 | un->un_eaddr[1] = (uint8_t)((mac_l >> 8) & 0xff); | 873 | un->un_eaddr[1] = (uint8_t)((mac_l >> 8) & 0xff); | |
877 | un->un_eaddr[0] = (uint8_t)((mac_l) & 0xff); | 874 | un->un_eaddr[0] = (uint8_t)((mac_l) & 0xff); | |
878 | } | 875 | } | |
879 | } | 876 | } | |
880 | 877 | |||
881 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 878 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
882 | 0, &unm); | 879 | 0, &unm); | |
883 | } | 880 | } | |
884 | 881 | |||
885 | static void | 882 | static void | |
886 | smsc_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 883 | smsc_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
887 | { | 884 | { | |
888 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | 885 | USMSCHIST_FUNC(); USMSCHIST_CALLED(); | |
889 | struct smsc_softc * const sc = usbnet_softc(un); | 886 | struct smsc_softc * const sc = usbnet_softc(un); | |
890 | struct ifnet *ifp = usbnet_ifp(un); | 887 | struct ifnet *ifp = usbnet_ifp(un); | |
891 | uint8_t *buf = c->unc_buf; | 888 | uint8_t *buf = c->unc_buf; | |
892 | int count; | 889 | int count; | |
893 | 890 | |||
894 | count = 0; | 891 | count = 0; | |
895 | DPRINTF("total_len %jd/%#jx", total_len, total_len, 0, 0); | 892 | DPRINTF("total_len %jd/%#jx", total_len, total_len, 0, 0); | |
896 | while (total_len != 0) { | 893 | while (total_len != 0) { | |
897 | uint32_t rxhdr; | 894 | uint32_t rxhdr; | |
898 | if (total_len < sizeof(rxhdr)) { | 895 | if (total_len < sizeof(rxhdr)) { | |
899 | DPRINTF("total_len %jd < sizeof(rxhdr) %jd", | 896 | DPRINTF("total_len %jd < sizeof(rxhdr) %jd", | |
900 | total_len, sizeof(rxhdr), 0, 0); | 897 | total_len, sizeof(rxhdr), 0, 0); | |
901 | if_statinc(ifp, if_ierrors); | 898 | if_statinc(ifp, if_ierrors); | |
902 | return; | 899 | return; | |
903 | } | 900 | } | |
904 | 901 | |||
905 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | 902 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | |
906 | rxhdr = le32toh(rxhdr); | 903 | rxhdr = le32toh(rxhdr); | |
907 | buf += sizeof(rxhdr); | 904 | buf += sizeof(rxhdr); | |
908 | total_len -= sizeof(rxhdr); | 905 | total_len -= sizeof(rxhdr); | |
909 | 906 | |||
910 | if (rxhdr & SMSC_RX_STAT_COLLISION) | 907 | if (rxhdr & SMSC_RX_STAT_COLLISION) | |
911 | if_statinc(ifp, if_collisions); | 908 | if_statinc(ifp, if_collisions); | |
912 | 909 | |||
913 | if (rxhdr & (SMSC_RX_STAT_ERROR | 910 | if (rxhdr & (SMSC_RX_STAT_ERROR | |
914 | | SMSC_RX_STAT_LENGTH_ERROR | 911 | | SMSC_RX_STAT_LENGTH_ERROR | |
915 | | SMSC_RX_STAT_MII_ERROR)) { | 912 | | SMSC_RX_STAT_MII_ERROR)) { | |
916 | DPRINTF("rx error (hdr 0x%08jx)", rxhdr, 0, 0, 0); | 913 | DPRINTF("rx error (hdr 0x%08jx)", rxhdr, 0, 0, 0); | |
917 | if_statinc(ifp, if_ierrors); | 914 | if_statinc(ifp, if_ierrors); | |
918 | return; | 915 | return; | |
919 | } | 916 | } | |
920 | 917 | |||
921 | uint16_t pktlen = (uint16_t)SMSC_RX_STAT_FRM_LENGTH(rxhdr); | 918 | uint16_t pktlen = (uint16_t)SMSC_RX_STAT_FRM_LENGTH(rxhdr); | |
922 | DPRINTF("total_len %jd pktlen %jd rxhdr 0x%08jx", total_len, | 919 | DPRINTF("total_len %jd pktlen %jd rxhdr 0x%08jx", total_len, | |
923 | pktlen, rxhdr, 0); | 920 | pktlen, rxhdr, 0); | |
924 | 921 | |||
925 | if (pktlen < ETHER_HDR_LEN) { | 922 | if (pktlen < ETHER_HDR_LEN) { | |
926 | DPRINTF("pktlen %jd < ETHER_HDR_LEN %jd", pktlen, | 923 | DPRINTF("pktlen %jd < ETHER_HDR_LEN %jd", pktlen, | |
927 | ETHER_HDR_LEN, 0, 0); | 924 | ETHER_HDR_LEN, 0, 0); | |
928 | if_statinc(ifp, if_ierrors); | 925 | if_statinc(ifp, if_ierrors); | |
929 | return; | 926 | return; | |
930 | } | 927 | } | |
931 | 928 | |||
932 | pktlen += ETHER_ALIGN; | 929 | pktlen += ETHER_ALIGN; | |
933 | 930 | |||
934 | if (pktlen > MCLBYTES) { | 931 | if (pktlen > MCLBYTES) { | |
935 | DPRINTF("pktlen %jd > MCLBYTES %jd", pktlen, MCLBYTES, 0, | 932 | DPRINTF("pktlen %jd > MCLBYTES %jd", pktlen, MCLBYTES, 0, | |
936 | 0); | 933 | 0); | |
937 | if_statinc(ifp, if_ierrors); | 934 | if_statinc(ifp, if_ierrors); | |
938 | return; | 935 | return; | |
939 | } | 936 | } | |
940 | 937 | |||
941 | if (pktlen > total_len) { | 938 | if (pktlen > total_len) { | |
942 | DPRINTF("pktlen %jd > total_len %jd", pktlen, total_len, | 939 | DPRINTF("pktlen %jd > total_len %jd", pktlen, total_len, | |
943 | 0, 0); | 940 | 0, 0); | |
944 | if_statinc(ifp, if_ierrors); | 941 | if_statinc(ifp, if_ierrors); | |
945 | return; | 942 | return; | |
946 | } | 943 | } | |
947 | 944 | |||
948 | uint8_t *pktbuf = buf + ETHER_ALIGN; | 945 | uint8_t *pktbuf = buf + ETHER_ALIGN; | |
949 | size_t buflen = pktlen - ETHER_ALIGN; | 946 | size_t buflen = pktlen - ETHER_ALIGN; | |
950 | int mbuf_flags = M_HASFCS; | 947 | int mbuf_flags = M_HASFCS; | |
951 | int csum_flags = 0; | 948 | int csum_flags = 0; | |
952 | uint16_t csum_data = 0; | 949 | uint16_t csum_data = 0; | |
953 | 950 | |||
954 | KASSERT(pktlen < MCLBYTES); | 951 | KASSERT(pktlen < MCLBYTES); | |
955 | 952 | |||
956 | /* Check if RX TCP/UDP checksumming is being offloaded */ | 953 | /* Check if RX TCP/UDP checksumming is being offloaded */ | |
957 | if (sc->sc_coe_ctrl & SMSC_COE_CTRL_RX_EN) { | 954 | if (sc->sc_coe_ctrl & SMSC_COE_CTRL_RX_EN) { | |
958 | DPRINTF("RX checksum offload checking", 0, 0, 0, 0); | 955 | DPRINTF("RX checksum offload checking", 0, 0, 0, 0); | |
959 | struct ether_header *eh = (struct ether_header *)pktbuf; | 956 | struct ether_header *eh = (struct ether_header *)pktbuf; | |
960 | const size_t cssz = sizeof(csum_data); | 957 | const size_t cssz = sizeof(csum_data); | |
961 | 958 | |||
962 | /* Remove the extra 2 bytes of the csum */ | 959 | /* Remove the extra 2 bytes of the csum */ | |
963 | buflen -= cssz; | 960 | buflen -= cssz; | |
964 | 961 | |||
965 | /* | 962 | /* | |
966 | * The checksum appears to be simplistically calculated | 963 | * The checksum appears to be simplistically calculated | |
967 | * over the udp/tcp header and data up to the end of the | 964 | * over the udp/tcp header and data up to the end of the | |
968 | * eth frame. Which means if the eth frame is padded | 965 | * eth frame. Which means if the eth frame is padded | |
969 | * the csum calculation is incorrectly performed over | 966 | * the csum calculation is incorrectly performed over | |
970 | * the padding bytes as well. Therefore to be safe we | 967 | * the padding bytes as well. Therefore to be safe we | |
971 | * ignore the H/W csum on frames less than or equal to | 968 | * ignore the H/W csum on frames less than or equal to | |
972 | * 64 bytes. | 969 | * 64 bytes. | |
973 | * | 970 | * | |
974 | * Ignore H/W csum for non-IPv4 packets. | 971 | * Ignore H/W csum for non-IPv4 packets. | |
975 | */ | 972 | */ | |
976 | DPRINTF("Ethertype %02jx pktlen %02jx", | 973 | DPRINTF("Ethertype %02jx pktlen %02jx", | |
977 | be16toh(eh->ether_type), pktlen, 0, 0); | 974 | be16toh(eh->ether_type), pktlen, 0, 0); | |
978 | if (be16toh(eh->ether_type) == ETHERTYPE_IP && | 975 | if (be16toh(eh->ether_type) == ETHERTYPE_IP && | |
979 | pktlen > ETHER_MIN_LEN) { | 976 | pktlen > ETHER_MIN_LEN) { | |
980 | 977 | |||
981 | csum_flags |= | 978 | csum_flags |= | |
982 | (M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_DATA); | 979 | (M_CSUM_TCPv4 | M_CSUM_UDPv4 | M_CSUM_DATA); | |
983 | 980 | |||
984 | /* | 981 | /* | |
985 | * Copy the TCP/UDP checksum from the last 2 | 982 | * Copy the TCP/UDP checksum from the last 2 | |
986 | * bytes of the transfer and put in the | 983 | * bytes of the transfer and put in the | |
987 | * csum_data field. | 984 | * csum_data field. | |
988 | */ | 985 | */ | |
989 | memcpy(&csum_data, buf + pktlen - cssz, cssz); | 986 | memcpy(&csum_data, buf + pktlen - cssz, cssz); | |
990 | 987 | |||
991 | /* | 988 | /* | |
992 | * The data is copied in network order, but the | 989 | * The data is copied in network order, but the | |
993 | * csum algorithm in the kernel expects it to be | 990 | * csum algorithm in the kernel expects it to be | |
994 | * in host network order. | 991 | * in host network order. | |
995 | */ | 992 | */ | |
996 | csum_data = ntohs(csum_data); | 993 | csum_data = ntohs(csum_data); | |
997 | DPRINTF("RX checksum offloaded (0x%04jx)", | 994 | DPRINTF("RX checksum offloaded (0x%04jx)", | |
998 | csum_data, 0, 0, 0); | 995 | csum_data, 0, 0, 0); | |
999 | } | 996 | } | |
1000 | } | 997 | } | |
1001 | 998 | |||
1002 | /* round up to next longword */ | 999 | /* round up to next longword */ | |
1003 | pktlen = (pktlen + 3) & ~0x3; | 1000 | pktlen = (pktlen + 3) & ~0x3; | |
1004 | 1001 | |||
1005 | /* total_len does not include the padding */ | 1002 | /* total_len does not include the padding */ | |
1006 | if (pktlen > total_len) | 1003 | if (pktlen > total_len) | |
1007 | pktlen = total_len; | 1004 | pktlen = total_len; | |
1008 | 1005 | |||
1009 | buf += pktlen; | 1006 | buf += pktlen; | |
1010 | total_len -= pktlen; | 1007 | total_len -= pktlen; | |
1011 | 1008 | |||
1012 | /* push the packet up */ | 1009 | /* push the packet up */ | |
1013 | usbnet_enqueue(un, pktbuf, buflen, csum_flags, csum_data, | 1010 | usbnet_enqueue(un, pktbuf, buflen, csum_flags, csum_data, | |
1014 | mbuf_flags); | 1011 | mbuf_flags); | |
1015 | 1012 | |||
1016 | count++; | 1013 | count++; | |
1017 | } | 1014 | } | |
1018 | 1015 | |||
1019 | if (count != 0) | 1016 | if (count != 0) | |
1020 | rnd_add_uint32(usbnet_rndsrc(un), count); | 1017 | rnd_add_uint32(usbnet_rndsrc(un), count); | |
1021 | } | 1018 | } | |
1022 | 1019 | |||
1023 | static unsigned | 1020 | static unsigned | |
1024 | smsc_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 1021 | smsc_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
1025 | { | 1022 | { | |
1026 | uint32_t txhdr; | 1023 | uint32_t txhdr; | |
1027 | uint32_t frm_len = 0; | 1024 | uint32_t frm_len = 0; | |
1028 | 1025 | |||
1029 | const size_t hdrsz = sizeof(txhdr) * 2; | 1026 | const size_t hdrsz = sizeof(txhdr) * 2; | |
1030 | 1027 | |||
1031 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - hdrsz) | 1028 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - hdrsz) | |
1032 | return 0; | 1029 | return 0; | |
1033 | 1030 | |||
1034 | /* | 1031 | /* | |
1035 | * Each frame is prefixed with two 32-bit values describing the | 1032 | * Each frame is prefixed with two 32-bit values describing the | |
1036 | * length of the packet and buffer. | 1033 | * length of the packet and buffer. | |
1037 | */ | 1034 | */ | |
1038 | txhdr = SMSC_TX_CTRL_0_BUF_SIZE(m->m_pkthdr.len) | | 1035 | txhdr = SMSC_TX_CTRL_0_BUF_SIZE(m->m_pkthdr.len) | | |
1039 | SMSC_TX_CTRL_0_FIRST_SEG | SMSC_TX_CTRL_0_LAST_SEG; | 1036 | SMSC_TX_CTRL_0_FIRST_SEG | SMSC_TX_CTRL_0_LAST_SEG; | |
1040 | txhdr = htole32(txhdr); | 1037 | txhdr = htole32(txhdr); | |
1041 | memcpy(c->unc_buf, &txhdr, sizeof(txhdr)); | 1038 | memcpy(c->unc_buf, &txhdr, sizeof(txhdr)); | |
1042 | 1039 | |||
1043 | txhdr = SMSC_TX_CTRL_1_PKT_LENGTH(m->m_pkthdr.len); | 1040 | txhdr = SMSC_TX_CTRL_1_PKT_LENGTH(m->m_pkthdr.len); | |
1044 | txhdr = htole32(txhdr); | 1041 | txhdr = htole32(txhdr); | |
1045 | memcpy(c->unc_buf + sizeof(txhdr), &txhdr, sizeof(txhdr)); | 1042 | memcpy(c->unc_buf + sizeof(txhdr), &txhdr, sizeof(txhdr)); | |
1046 | 1043 | |||
1047 | frm_len += hdrsz; | 1044 | frm_len += hdrsz; | |
1048 | 1045 | |||
1049 | /* Next copy in the actual packet */ | 1046 | /* Next copy in the actual packet */ | |
1050 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + frm_len); | 1047 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf + frm_len); | |
1051 | frm_len += m->m_pkthdr.len; | 1048 | frm_len += m->m_pkthdr.len; | |
1052 | 1049 | |||
1053 | return frm_len; | 1050 | return frm_len; | |
1054 | } | 1051 | } | |
1055 | 1052 | |||
1056 | #ifdef _MODULE | 1053 | #ifdef _MODULE | |
1057 | #include "ioconf.c" | 1054 | #include "ioconf.c" | |
1058 | #endif | 1055 | #endif | |
1059 | 1056 | |||
1060 | USBNET_MODULE(smsc) | 1057 | USBNET_MODULE(smsc) |
--- src/sys/dev/usb/if_udav.c 2022/03/03 05:54:37 1.92
+++ src/sys/dev/usb/if_udav.c 2022/03/03 05:55:01 1.93
@@ -1,831 +1,827 @@ | @@ -1,831 +1,827 @@ | |||
1 | /* $NetBSD: if_udav.c,v 1.92 2022/03/03 05:54:37 riastradh Exp $ */ | 1 | /* $NetBSD: if_udav.c,v 1.93 2022/03/03 05:55:01 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.92 2022/03/03 05:54:37 riastradh Exp $"); | 48 | __KERNEL_RCSID(0, "$NetBSD: if_udav.c,v 1.93 2022/03/03 05:55:01 riastradh Exp $"); | |
49 | 49 | |||
50 | #ifdef _KERNEL_OPT | 50 | #ifdef _KERNEL_OPT | |
51 | #include "opt_usb.h" | 51 | #include "opt_usb.h" | |
52 | #endif | 52 | #endif | |
53 | 53 | |||
54 | #include <sys/param.h> | 54 | #include <sys/param.h> | |
55 | 55 | |||
56 | #include <dev/usb/usbnet.h> | 56 | #include <dev/usb/usbnet.h> | |
57 | #include <dev/usb/if_udavreg.h> | 57 | #include <dev/usb/if_udavreg.h> | |
58 | 58 | |||
59 | /* Function declarations */ | 59 | /* Function declarations */ | |
60 | static int udav_match(device_t, cfdata_t, void *); | 60 | static int udav_match(device_t, cfdata_t, void *); | |
61 | static void udav_attach(device_t, device_t, void *); | 61 | static void udav_attach(device_t, device_t, void *); | |
62 | 62 | |||
63 | CFATTACH_DECL_NEW(udav, sizeof(struct usbnet), udav_match, udav_attach, | 63 | CFATTACH_DECL_NEW(udav, sizeof(struct usbnet), udav_match, udav_attach, | |
64 | usbnet_detach, usbnet_activate); | 64 | usbnet_detach, usbnet_activate); | |
65 | 65 | |||
66 | static void udav_chip_init(struct usbnet *); | 66 | static void udav_chip_init(struct usbnet *); | |
67 | 67 | |||
68 | static unsigned udav_uno_tx_prepare(struct usbnet *, struct mbuf *, | 68 | static unsigned udav_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
69 | struct usbnet_chain *); | 69 | struct usbnet_chain *); | |
70 | static void udav_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 70 | static void udav_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
71 | static void udav_uno_stop(struct ifnet *, int); | 71 | static void udav_uno_stop(struct ifnet *, int); | |
72 | static void udav_uno_mcast(struct ifnet *); | 72 | static void udav_uno_mcast(struct ifnet *); | |
73 | static int udav_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 73 | static int udav_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
74 | static int udav_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 74 | static int udav_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
75 | static void udav_uno_mii_statchg(struct ifnet *); | 75 | static void udav_uno_mii_statchg(struct ifnet *); | |
76 | static int udav_uno_init(struct ifnet *); | 76 | static int udav_uno_init(struct ifnet *); | |
77 | static void udav_reset(struct usbnet *); | 77 | static void udav_reset(struct usbnet *); | |
78 | 78 | |||
79 | static int udav_csr_read(struct usbnet *, int, void *, int); | 79 | static int udav_csr_read(struct usbnet *, int, void *, int); | |
80 | static int udav_csr_write(struct usbnet *, int, void *, int); | 80 | static int udav_csr_write(struct usbnet *, int, void *, int); | |
81 | static int udav_csr_read1(struct usbnet *, int); | 81 | static int udav_csr_read1(struct usbnet *, int); | |
82 | static int udav_csr_write1(struct usbnet *, int, unsigned char); | 82 | static int udav_csr_write1(struct usbnet *, int, unsigned char); | |
83 | 83 | |||
84 | #if 0 | 84 | #if 0 | |
85 | static int udav_mem_read(struct usbnet *, int, void *, int); | 85 | static int udav_mem_read(struct usbnet *, int, void *, int); | |
86 | static int udav_mem_write(struct usbnet *, int, void *, int); | 86 | static int udav_mem_write(struct usbnet *, int, void *, int); | |
87 | static int udav_mem_write1(struct usbnet *, int, unsigned char); | 87 | static int udav_mem_write1(struct usbnet *, int, unsigned char); | |
88 | #endif | 88 | #endif | |
89 | 89 | |||
90 | /* Macros */ | 90 | /* Macros */ | |
91 | #ifdef UDAV_DEBUG | 91 | #ifdef UDAV_DEBUG | |
92 | #define DPRINTF(x) if (udavdebug) printf x | 92 | #define DPRINTF(x) if (udavdebug) printf x | |
93 | #define DPRINTFN(n, x) if (udavdebug >= (n)) printf x | 93 | #define DPRINTFN(n, x) if (udavdebug >= (n)) printf x | |
94 | int udavdebug = 0; | 94 | int udavdebug = 0; | |
95 | #else | 95 | #else | |
96 | #define DPRINTF(x) | 96 | #define DPRINTF(x) | |
97 | #define DPRINTFN(n, x) | 97 | #define DPRINTFN(n, x) | |
98 | #endif | 98 | #endif | |
99 | 99 | |||
100 | #define UDAV_SETBIT(un, reg, x) \ | 100 | #define UDAV_SETBIT(un, reg, x) \ | |
101 | udav_csr_write1(un, reg, udav_csr_read1(un, reg) | (x)) | 101 | udav_csr_write1(un, reg, udav_csr_read1(un, reg) | (x)) | |
102 | 102 | |||
103 | #define UDAV_CLRBIT(un, reg, x) \ | 103 | #define UDAV_CLRBIT(un, reg, x) \ | |
104 | udav_csr_write1(un, reg, udav_csr_read1(un, reg) & ~(x)) | 104 | udav_csr_write1(un, reg, udav_csr_read1(un, reg) & ~(x)) | |
105 | 105 | |||
106 | static const struct udav_type { | 106 | static const struct udav_type { | |
107 | struct usb_devno udav_dev; | 107 | struct usb_devno udav_dev; | |
108 | uint16_t udav_flags; | 108 | uint16_t udav_flags; | |
109 | #define UDAV_EXT_PHY 0x0001 | 109 | #define UDAV_EXT_PHY 0x0001 | |
110 | #define UDAV_NO_PHY 0x0002 | 110 | #define UDAV_NO_PHY 0x0002 | |
111 | } udav_devs [] = { | 111 | } udav_devs [] = { | |
112 | /* Corega USB-TXC */ | 112 | /* Corega USB-TXC */ | |
113 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC }, 0}, | 113 | {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC }, 0}, | |
114 | /* ShanTou ST268 USB NIC */ | 114 | /* ShanTou ST268 USB NIC */ | |
115 | {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268_USB_NIC }, 0}, | 115 | {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ST268_USB_NIC }, 0}, | |
116 | /* ShanTou ADM8515 */ | 116 | /* ShanTou ADM8515 */ | |
117 | {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ADM8515 }, 0}, | 117 | {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ADM8515 }, 0}, | |
118 | /* SUNRISING SR9600 */ | 118 | /* SUNRISING SR9600 */ | |
119 | {{ USB_VENDOR_SUNRISING, USB_PRODUCT_SUNRISING_SR9600 }, 0 }, | 119 | {{ USB_VENDOR_SUNRISING, USB_PRODUCT_SUNRISING_SR9600 }, 0 }, | |
120 | /* SUNRISING QF9700 */ | 120 | /* SUNRISING QF9700 */ | |
121 | {{ USB_VENDOR_SUNRISING, USB_PRODUCT_SUNRISING_QF9700 }, UDAV_NO_PHY }, | 121 | {{ USB_VENDOR_SUNRISING, USB_PRODUCT_SUNRISING_QF9700 }, UDAV_NO_PHY }, | |
122 | /* QUAN DM9601 */ | 122 | /* QUAN DM9601 */ | |
123 | {{USB_VENDOR_QUAN, USB_PRODUCT_QUAN_DM9601 }, 0}, | 123 | {{USB_VENDOR_QUAN, USB_PRODUCT_QUAN_DM9601 }, 0}, | |
124 | #if 0 | 124 | #if 0 | |
125 | /* DAVICOM DM9601 Generic? */ | 125 | /* DAVICOM DM9601 Generic? */ | |
126 | /* XXX: The following ids was obtained from the data sheet. */ | 126 | /* XXX: The following ids was obtained from the data sheet. */ | |
127 | {{ 0x0a46, 0x9601 }, 0}, | 127 | {{ 0x0a46, 0x9601 }, 0}, | |
128 | #endif | 128 | #endif | |
129 | }; | 129 | }; | |
130 | #define udav_lookup(v, p) ((const struct udav_type *)usb_lookup(udav_devs, v, p)) | 130 | #define udav_lookup(v, p) ((const struct udav_type *)usb_lookup(udav_devs, v, p)) | |
131 | 131 | |||
132 | static const struct usbnet_ops udav_ops = { | 132 | static const struct usbnet_ops udav_ops = { | |
133 | .uno_stop = udav_uno_stop, | 133 | .uno_stop = udav_uno_stop, | |
134 | .uno_mcast = udav_uno_mcast, | 134 | .uno_mcast = udav_uno_mcast, | |
135 | .uno_read_reg = udav_uno_mii_read_reg, | 135 | .uno_read_reg = udav_uno_mii_read_reg, | |
136 | .uno_write_reg = udav_uno_mii_write_reg, | 136 | .uno_write_reg = udav_uno_mii_write_reg, | |
137 | .uno_statchg = udav_uno_mii_statchg, | 137 | .uno_statchg = udav_uno_mii_statchg, | |
138 | .uno_tx_prepare = udav_uno_tx_prepare, | 138 | .uno_tx_prepare = udav_uno_tx_prepare, | |
139 | .uno_rx_loop = udav_uno_rx_loop, | 139 | .uno_rx_loop = udav_uno_rx_loop, | |
140 | .uno_init = udav_uno_init, | 140 | .uno_init = udav_uno_init, | |
141 | }; | 141 | }; | |
142 | 142 | |||
143 | /* Probe */ | 143 | /* Probe */ | |
144 | static int | 144 | static int | |
145 | udav_match(device_t parent, cfdata_t match, void *aux) | 145 | udav_match(device_t parent, cfdata_t match, void *aux) | |
146 | { | 146 | { | |
147 | struct usb_attach_arg *uaa = aux; | 147 | struct usb_attach_arg *uaa = aux; | |
148 | 148 | |||
149 | return udav_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 149 | return udav_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
150 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 150 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
151 | } | 151 | } | |
152 | 152 | |||
153 | /* Attach */ | 153 | /* Attach */ | |
154 | static void | 154 | static void | |
155 | udav_attach(device_t parent, device_t self, void *aux) | 155 | udav_attach(device_t parent, device_t self, void *aux) | |
156 | { | 156 | { | |
157 | USBNET_MII_DECL_DEFAULT(unm); | 157 | USBNET_MII_DECL_DEFAULT(unm); | |
158 | struct usbnet_mii *unmp; | 158 | struct usbnet_mii *unmp; | |
159 | struct usbnet * const un = device_private(self); | 159 | struct usbnet * const un = device_private(self); | |
160 | struct usb_attach_arg *uaa = aux; | 160 | struct usb_attach_arg *uaa = aux; | |
161 | struct usbd_device *dev = uaa->uaa_device; | 161 | struct usbd_device *dev = uaa->uaa_device; | |
162 | struct usbd_interface *iface; | 162 | struct usbd_interface *iface; | |
163 | usbd_status err; | 163 | usbd_status err; | |
164 | usb_interface_descriptor_t *id; | 164 | usb_interface_descriptor_t *id; | |
165 | usb_endpoint_descriptor_t *ed; | 165 | usb_endpoint_descriptor_t *ed; | |
166 | char *devinfop; | 166 | char *devinfop; | |
167 | int i; | 167 | int i; | |
168 | 168 | |||
169 | aprint_naive("\n"); | 169 | aprint_naive("\n"); | |
170 | aprint_normal("\n"); | 170 | aprint_normal("\n"); | |
171 | devinfop = usbd_devinfo_alloc(dev, 0); | 171 | devinfop = usbd_devinfo_alloc(dev, 0); | |
172 | aprint_normal_dev(self, "%s\n", devinfop); | 172 | aprint_normal_dev(self, "%s\n", devinfop); | |
173 | usbd_devinfo_free(devinfop); | 173 | usbd_devinfo_free(devinfop); | |
174 | 174 | |||
175 | un->un_dev = self; | 175 | un->un_dev = self; | |
176 | un->un_udev = dev; | 176 | un->un_udev = dev; | |
177 | un->un_sc = un; | 177 | un->un_sc = un; | |
178 | un->un_ops = &udav_ops; | 178 | un->un_ops = &udav_ops; | |
179 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 179 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
180 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 180 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
181 | un->un_rx_list_cnt = UDAV_RX_LIST_CNT; | 181 | un->un_rx_list_cnt = UDAV_RX_LIST_CNT; | |
182 | un->un_tx_list_cnt = UDAV_TX_LIST_CNT; | 182 | un->un_tx_list_cnt = UDAV_TX_LIST_CNT; | |
183 | un->un_rx_bufsz = UDAV_BUFSZ; | 183 | un->un_rx_bufsz = UDAV_BUFSZ; | |
184 | un->un_tx_bufsz = UDAV_BUFSZ; | 184 | un->un_tx_bufsz = UDAV_BUFSZ; | |
185 | 185 | |||
186 | /* Move the device into the configured state. */ | 186 | /* Move the device into the configured state. */ | |
187 | err = usbd_set_config_no(dev, UDAV_CONFIG_NO, 1); /* idx 0 */ | 187 | err = usbd_set_config_no(dev, UDAV_CONFIG_NO, 1); /* idx 0 */ | |
188 | if (err) { | 188 | if (err) { | |
189 | aprint_error_dev(self, "failed to set configuration" | 189 | aprint_error_dev(self, "failed to set configuration" | |
190 | ", err=%s\n", usbd_errstr(err)); | 190 | ", err=%s\n", usbd_errstr(err)); | |
191 | return; | 191 | return; | |
192 | } | 192 | } | |
193 | 193 | |||
194 | /* get control interface */ | 194 | /* get control interface */ | |
195 | err = usbd_device2interface_handle(dev, UDAV_IFACE_INDEX, &iface); | 195 | err = usbd_device2interface_handle(dev, UDAV_IFACE_INDEX, &iface); | |
196 | if (err) { | 196 | if (err) { | |
197 | aprint_error_dev(self, "failed to get interface, err=%s\n", | 197 | aprint_error_dev(self, "failed to get interface, err=%s\n", | |
198 | usbd_errstr(err)); | 198 | usbd_errstr(err)); | |
199 | return; | 199 | return; | |
200 | } | 200 | } | |
201 | 201 | |||
202 | un->un_iface = iface; | 202 | un->un_iface = iface; | |
203 | un->un_flags = udav_lookup(uaa->uaa_vendor, | 203 | un->un_flags = udav_lookup(uaa->uaa_vendor, | |
204 | uaa->uaa_product)->udav_flags; | 204 | uaa->uaa_product)->udav_flags; | |
205 | 205 | |||
206 | /* get interface descriptor */ | 206 | /* get interface descriptor */ | |
207 | id = usbd_get_interface_descriptor(un->un_iface); | 207 | id = usbd_get_interface_descriptor(un->un_iface); | |
208 | 208 | |||
209 | /* find endpoints */ | 209 | /* find endpoints */ | |
210 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = | 210 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = | |
211 | un->un_ed[USBNET_ENDPT_INTR] = -1; | 211 | un->un_ed[USBNET_ENDPT_INTR] = -1; | |
212 | for (i = 0; i < id->bNumEndpoints; i++) { | 212 | for (i = 0; i < id->bNumEndpoints; i++) { | |
213 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 213 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
214 | if (ed == NULL) { | 214 | if (ed == NULL) { | |
215 | aprint_error_dev(self, "couldn't get endpoint %d\n", i); | 215 | aprint_error_dev(self, "couldn't get endpoint %d\n", i); | |
216 | return; | 216 | return; | |
217 | } | 217 | } | |
218 | if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | 218 | if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | |
219 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | 219 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | |
220 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 220 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
221 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | 221 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | |
222 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) | 222 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) | |
223 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 223 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
224 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT && | 224 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT && | |
225 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | 225 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | |
226 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 226 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
227 | } | 227 | } | |
228 | 228 | |||
229 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 229 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
230 | un->un_ed[USBNET_ENDPT_TX] == 0 || | 230 | un->un_ed[USBNET_ENDPT_TX] == 0 || | |
231 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | 231 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | |
232 | aprint_error_dev(self, "missing endpoint\n"); | 232 | aprint_error_dev(self, "missing endpoint\n"); | |
233 | return; | 233 | return; | |
234 | } | 234 | } | |
235 | 235 | |||
236 | /* Not supported yet. */ | 236 | /* Not supported yet. */ | |
237 | un->un_ed[USBNET_ENDPT_INTR] = 0; | 237 | un->un_ed[USBNET_ENDPT_INTR] = 0; | |
238 | 238 | |||
239 | usbnet_attach(un, "udavdet"); | 239 | usbnet_attach(un, "udavdet"); | |
240 | 240 | |||
241 | // /* reset the adapter */ | 241 | // /* reset the adapter */ | |
242 | // udav_reset(un); | 242 | // udav_reset(un); | |
243 | 243 | |||
244 | /* Get Ethernet Address */ | 244 | /* Get Ethernet Address */ | |
245 | err = udav_csr_read(un, UDAV_PAR, un->un_eaddr, ETHER_ADDR_LEN); | 245 | err = udav_csr_read(un, UDAV_PAR, un->un_eaddr, ETHER_ADDR_LEN); | |
246 | if (err) { | 246 | if (err) { | |
247 | aprint_error_dev(self, "read MAC address failed\n"); | 247 | aprint_error_dev(self, "read MAC address failed\n"); | |
248 | return; | 248 | return; | |
249 | } | 249 | } | |
250 | 250 | |||
251 | if (ISSET(un->un_flags, UDAV_NO_PHY)) | 251 | if (ISSET(un->un_flags, UDAV_NO_PHY)) | |
252 | unmp = NULL; | 252 | unmp = NULL; | |
253 | else | 253 | else | |
254 | unmp = &unm; | 254 | unmp = &unm; | |
255 | 255 | |||
256 | /* initialize interface information */ | 256 | /* initialize interface information */ | |
257 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 257 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
258 | 0, unmp); | 258 | 0, unmp); | |
259 | 259 | |||
260 | return; | 260 | return; | |
261 | } | 261 | } | |
262 | 262 | |||
263 | #if 0 | 263 | #if 0 | |
264 | /* read memory */ | 264 | /* read memory */ | |
265 | static int | 265 | static int | |
266 | udav_mem_read(struct usbnet *un, int offset, void *buf, int len) | 266 | udav_mem_read(struct usbnet *un, int offset, void *buf, int len) | |
267 | { | 267 | { | |
268 | usb_device_request_t req; | 268 | usb_device_request_t req; | |
269 | usbd_status err; | 269 | usbd_status err; | |
270 | 270 | |||
271 | DPRINTFN(0x200, | 271 | DPRINTFN(0x200, | |
272 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 272 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
273 | 273 | |||
274 | if (usbnet_isdying(un)) | 274 | if (usbnet_isdying(un)) | |
275 | return 0; | 275 | return 0; | |
276 | 276 | |||
277 | offset &= 0xffff; | 277 | offset &= 0xffff; | |
278 | len &= 0xff; | 278 | len &= 0xff; | |
279 | 279 | |||
280 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 280 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
281 | req.bRequest = UDAV_REQ_MEM_READ; | 281 | req.bRequest = UDAV_REQ_MEM_READ; | |
282 | USETW(req.wValue, 0x0000); | 282 | USETW(req.wValue, 0x0000); | |
283 | USETW(req.wIndex, offset); | 283 | USETW(req.wIndex, offset); | |
284 | USETW(req.wLength, len); | 284 | USETW(req.wLength, len); | |
285 | 285 | |||
286 | err = usbd_do_request(un->un_udev, &req, buf); | 286 | err = usbd_do_request(un->un_udev, &req, buf); | |
287 | if (err) { | 287 | if (err) { | |
288 | DPRINTF(("%s: %s: read failed. off=%04x, err=%d\n", | 288 | DPRINTF(("%s: %s: read failed. off=%04x, err=%d\n", | |
289 | device_xname(un->un_dev), __func__, offset, err)); | 289 | device_xname(un->un_dev), __func__, offset, err)); | |
290 | } | 290 | } | |
291 | 291 | |||
292 | return err; | 292 | return err; | |
293 | } | 293 | } | |
294 | 294 | |||
295 | /* write memory */ | 295 | /* write memory */ | |
296 | static int | 296 | static int | |
297 | udav_mem_write(struct usbnet *un, int offset, void *buf, int len) | 297 | udav_mem_write(struct usbnet *un, int offset, void *buf, int len) | |
298 | { | 298 | { | |
299 | usb_device_request_t req; | 299 | usb_device_request_t req; | |
300 | usbd_status err; | 300 | usbd_status err; | |
301 | 301 | |||
302 | DPRINTFN(0x200, | 302 | DPRINTFN(0x200, | |
303 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 303 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
304 | 304 | |||
305 | if (usbnet_isdying(un)) | 305 | if (usbnet_isdying(un)) | |
306 | return 0; | 306 | return 0; | |
307 | 307 | |||
308 | offset &= 0xffff; | 308 | offset &= 0xffff; | |
309 | len &= 0xff; | 309 | len &= 0xff; | |
310 | 310 | |||
311 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 311 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
312 | req.bRequest = UDAV_REQ_MEM_WRITE; | 312 | req.bRequest = UDAV_REQ_MEM_WRITE; | |
313 | USETW(req.wValue, 0x0000); | 313 | USETW(req.wValue, 0x0000); | |
314 | USETW(req.wIndex, offset); | 314 | USETW(req.wIndex, offset); | |
315 | USETW(req.wLength, len); | 315 | USETW(req.wLength, len); | |
316 | 316 | |||
317 | err = usbd_do_request(un->un_udev, &req, buf); | 317 | err = usbd_do_request(un->un_udev, &req, buf); | |
318 | if (err) { | 318 | if (err) { | |
319 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | 319 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | |
320 | device_xname(un->un_dev), __func__, offset, err)); | 320 | device_xname(un->un_dev), __func__, offset, err)); | |
321 | } | 321 | } | |
322 | 322 | |||
323 | return err; | 323 | return err; | |
324 | } | 324 | } | |
325 | 325 | |||
326 | /* write memory */ | 326 | /* write memory */ | |
327 | static int | 327 | static int | |
328 | udav_mem_write1(struct usbnet *un, int offset, unsigned char ch) | 328 | udav_mem_write1(struct usbnet *un, int offset, unsigned char ch) | |
329 | { | 329 | { | |
330 | usb_device_request_t req; | 330 | usb_device_request_t req; | |
331 | usbd_status err; | 331 | usbd_status err; | |
332 | 332 | |||
333 | DPRINTFN(0x200, | 333 | DPRINTFN(0x200, | |
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 | if (usbnet_isdying(un)) | 336 | if (usbnet_isdying(un)) | |
337 | return 0; | 337 | return 0; | |
338 | 338 | |||
339 | offset &= 0xffff; | 339 | offset &= 0xffff; | |
340 | 340 | |||
341 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 341 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
342 | req.bRequest = UDAV_REQ_MEM_WRITE1; | 342 | req.bRequest = UDAV_REQ_MEM_WRITE1; | |
343 | USETW(req.wValue, ch); | 343 | USETW(req.wValue, ch); | |
344 | USETW(req.wIndex, offset); | 344 | USETW(req.wIndex, offset); | |
345 | USETW(req.wLength, 0x0000); | 345 | USETW(req.wLength, 0x0000); | |
346 | 346 | |||
347 | err = usbd_do_request(un->un_udev, &req, NULL); | 347 | err = usbd_do_request(un->un_udev, &req, NULL); | |
348 | if (err) { | 348 | if (err) { | |
349 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | 349 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | |
350 | device_xname(un->un_dev), __func__, offset, err)); | 350 | device_xname(un->un_dev), __func__, offset, err)); | |
351 | } | 351 | } | |
352 | 352 | |||
353 | return err; | 353 | return err; | |
354 | } | 354 | } | |
355 | #endif | 355 | #endif | |
356 | 356 | |||
357 | /* read register(s) */ | 357 | /* read register(s) */ | |
358 | static int | 358 | static int | |
359 | udav_csr_read(struct usbnet *un, int offset, void *buf, int len) | 359 | udav_csr_read(struct usbnet *un, int offset, void *buf, int len) | |
360 | { | 360 | { | |
361 | usb_device_request_t req; | 361 | usb_device_request_t req; | |
362 | usbd_status err; | 362 | usbd_status err; | |
363 | 363 | |||
364 | if (usbnet_isdying(un)) | 364 | if (usbnet_isdying(un)) | |
365 | return USBD_IOERROR; | 365 | return USBD_IOERROR; | |
366 | 366 | |||
367 | DPRINTFN(0x200, | 367 | DPRINTFN(0x200, | |
368 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 368 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
369 | 369 | |||
370 | offset &= 0xff; | 370 | offset &= 0xff; | |
371 | len &= 0xff; | 371 | len &= 0xff; | |
372 | 372 | |||
373 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 373 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
374 | req.bRequest = UDAV_REQ_REG_READ; | 374 | req.bRequest = UDAV_REQ_REG_READ; | |
375 | USETW(req.wValue, 0x0000); | 375 | USETW(req.wValue, 0x0000); | |
376 | USETW(req.wIndex, offset); | 376 | USETW(req.wIndex, offset); | |
377 | USETW(req.wLength, len); | 377 | USETW(req.wLength, len); | |
378 | 378 | |||
379 | err = usbd_do_request(un->un_udev, &req, buf); | 379 | err = usbd_do_request(un->un_udev, &req, buf); | |
380 | if (err) { | 380 | if (err) { | |
381 | DPRINTF(("%s: %s: read failed. off=%04x, err=%d\n", | 381 | DPRINTF(("%s: %s: read failed. off=%04x, err=%d\n", | |
382 | device_xname(un->un_dev), __func__, offset, err)); | 382 | device_xname(un->un_dev), __func__, offset, err)); | |
383 | memset(buf, 0, len); | 383 | memset(buf, 0, len); | |
384 | } | 384 | } | |
385 | 385 | |||
386 | return err; | 386 | return err; | |
387 | } | 387 | } | |
388 | 388 | |||
389 | /* write register(s) */ | 389 | /* write register(s) */ | |
390 | static int | 390 | static int | |
391 | udav_csr_write(struct usbnet *un, int offset, void *buf, int len) | 391 | udav_csr_write(struct usbnet *un, int offset, void *buf, int len) | |
392 | { | 392 | { | |
393 | usb_device_request_t req; | 393 | usb_device_request_t req; | |
394 | usbd_status err; | 394 | usbd_status err; | |
395 | 395 | |||
396 | if (usbnet_isdying(un)) | 396 | if (usbnet_isdying(un)) | |
397 | return USBD_IOERROR; | 397 | return USBD_IOERROR; | |
398 | 398 | |||
399 | DPRINTFN(0x200, | 399 | DPRINTFN(0x200, | |
400 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 400 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
401 | 401 | |||
402 | offset &= 0xff; | 402 | offset &= 0xff; | |
403 | len &= 0xff; | 403 | len &= 0xff; | |
404 | 404 | |||
405 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 405 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
406 | req.bRequest = UDAV_REQ_REG_WRITE; | 406 | req.bRequest = UDAV_REQ_REG_WRITE; | |
407 | USETW(req.wValue, 0x0000); | 407 | USETW(req.wValue, 0x0000); | |
408 | USETW(req.wIndex, offset); | 408 | USETW(req.wIndex, offset); | |
409 | USETW(req.wLength, len); | 409 | USETW(req.wLength, len); | |
410 | 410 | |||
411 | err = usbd_do_request(un->un_udev, &req, buf); | 411 | err = usbd_do_request(un->un_udev, &req, buf); | |
412 | if (err) { | 412 | if (err) { | |
413 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | 413 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | |
414 | device_xname(un->un_dev), __func__, offset, err)); | 414 | device_xname(un->un_dev), __func__, offset, err)); | |
415 | } | 415 | } | |
416 | 416 | |||
417 | return err; | 417 | return err; | |
418 | } | 418 | } | |
419 | 419 | |||
420 | static int | 420 | static int | |
421 | udav_csr_read1(struct usbnet *un, int offset) | 421 | udav_csr_read1(struct usbnet *un, int offset) | |
422 | { | 422 | { | |
423 | uint8_t val = 0; | 423 | uint8_t val = 0; | |
424 | 424 | |||
425 | DPRINTFN(0x200, | 425 | DPRINTFN(0x200, | |
426 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 426 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
427 | 427 | |||
428 | if (usbnet_isdying(un)) | 428 | if (usbnet_isdying(un)) | |
429 | return 0; | 429 | return 0; | |
430 | 430 | |||
431 | return udav_csr_read(un, offset, &val, 1) ? 0 : val; | 431 | return udav_csr_read(un, offset, &val, 1) ? 0 : val; | |
432 | } | 432 | } | |
433 | 433 | |||
434 | /* write a register */ | 434 | /* write a register */ | |
435 | static int | 435 | static int | |
436 | udav_csr_write1(struct usbnet *un, int offset, unsigned char ch) | 436 | udav_csr_write1(struct usbnet *un, int offset, unsigned char ch) | |
437 | { | 437 | { | |
438 | usb_device_request_t req; | 438 | usb_device_request_t req; | |
439 | usbd_status err; | 439 | usbd_status err; | |
440 | 440 | |||
441 | if (usbnet_isdying(un)) | 441 | if (usbnet_isdying(un)) | |
442 | return USBD_IOERROR; | 442 | return USBD_IOERROR; | |
443 | 443 | |||
444 | DPRINTFN(0x200, | 444 | DPRINTFN(0x200, | |
445 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 445 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
446 | 446 | |||
447 | offset &= 0xff; | 447 | offset &= 0xff; | |
448 | 448 | |||
449 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 449 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
450 | req.bRequest = UDAV_REQ_REG_WRITE1; | 450 | req.bRequest = UDAV_REQ_REG_WRITE1; | |
451 | USETW(req.wValue, ch); | 451 | USETW(req.wValue, ch); | |
452 | USETW(req.wIndex, offset); | 452 | USETW(req.wIndex, offset); | |
453 | USETW(req.wLength, 0x0000); | 453 | USETW(req.wLength, 0x0000); | |
454 | 454 | |||
455 | err = usbd_do_request(un->un_udev, &req, NULL); | 455 | err = usbd_do_request(un->un_udev, &req, NULL); | |
456 | if (err) { | 456 | if (err) { | |
457 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | 457 | DPRINTF(("%s: %s: write failed. off=%04x, err=%d\n", | |
458 | device_xname(un->un_dev), __func__, offset, err)); | 458 | device_xname(un->un_dev), __func__, offset, err)); | |
459 | } | 459 | } | |
460 | 460 | |||
461 | return err; | 461 | return err; | |
462 | } | 462 | } | |
463 | 463 | |||
464 | static int | 464 | static int | |
465 | udav_uno_init(struct ifnet *ifp) | 465 | udav_uno_init(struct ifnet *ifp) | |
466 | { | 466 | { | |
467 | struct usbnet * const un = ifp->if_softc; | 467 | struct usbnet * const un = ifp->if_softc; | |
468 | struct mii_data * const mii = usbnet_mii(un); | 468 | struct mii_data * const mii = usbnet_mii(un); | |
469 | uint8_t eaddr[ETHER_ADDR_LEN]; | 469 | uint8_t eaddr[ETHER_ADDR_LEN]; | |
470 | int rc = 0; | 470 | int rc = 0; | |
471 | 471 | |||
472 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 472 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
473 | 473 | |||
474 | if (usbnet_isdying(un)) { | |||
475 | return EIO; | |||
476 | } | |||
477 | ||||
478 | /* Cancel pending I/O and free all TX/RX buffers */ | 474 | /* Cancel pending I/O and free all TX/RX buffers */ | |
479 | if (ifp->if_flags & IFF_RUNNING) | 475 | if (ifp->if_flags & IFF_RUNNING) | |
480 | usbnet_stop(un, ifp, 1); | 476 | usbnet_stop(un, ifp, 1); | |
481 | 477 | |||
482 | memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); | 478 | memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr)); | |
483 | udav_csr_write(un, UDAV_PAR, eaddr, ETHER_ADDR_LEN); | 479 | udav_csr_write(un, UDAV_PAR, eaddr, ETHER_ADDR_LEN); | |
484 | 480 | |||
485 | /* Initialize network control register */ | 481 | /* Initialize network control register */ | |
486 | /* Disable loopback */ | 482 | /* Disable loopback */ | |
487 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1); | 483 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_LBK0 | UDAV_NCR_LBK1); | |
488 | 484 | |||
489 | /* Initialize RX control register */ | 485 | /* Initialize RX control register */ | |
490 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC); | 486 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_DIS_LONG | UDAV_RCR_DIS_CRC); | |
491 | 487 | |||
492 | /* If we want promiscuous mode, accept all physical frames. */ | 488 | /* If we want promiscuous mode, accept all physical frames. */ | |
493 | if (ifp->if_flags & IFF_PROMISC) | 489 | if (ifp->if_flags & IFF_PROMISC) | |
494 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | 490 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | |
495 | else | 491 | else | |
496 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | 492 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | |
497 | 493 | |||
498 | /* Enable RX */ | 494 | /* Enable RX */ | |
499 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_RXEN); | 495 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_RXEN); | |
500 | 496 | |||
501 | /* clear POWER_DOWN state of internal PHY */ | 497 | /* clear POWER_DOWN state of internal PHY */ | |
502 | UDAV_SETBIT(un, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0); | 498 | UDAV_SETBIT(un, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0); | |
503 | UDAV_CLRBIT(un, UDAV_GPR, UDAV_GPR_GEPIO0); | 499 | UDAV_CLRBIT(un, UDAV_GPR, UDAV_GPR_GEPIO0); | |
504 | 500 | |||
505 | if (mii && (rc = mii_mediachg(mii)) == ENXIO) | 501 | if (mii && (rc = mii_mediachg(mii)) == ENXIO) | |
506 | rc = 0; | 502 | rc = 0; | |
507 | 503 | |||
508 | if (rc != 0) { | 504 | if (rc != 0) { | |
509 | return rc; | 505 | return rc; | |
510 | } | 506 | } | |
511 | 507 | |||
512 | if (usbnet_isdying(un)) | 508 | if (usbnet_isdying(un)) | |
513 | rc = EIO; | 509 | rc = EIO; | |
514 | else | 510 | else | |
515 | rc = usbnet_init_rx_tx(un); | 511 | rc = usbnet_init_rx_tx(un); | |
516 | 512 | |||
517 | return rc; | 513 | return rc; | |
518 | } | 514 | } | |
519 | 515 | |||
520 | static void | 516 | static void | |
521 | udav_reset(struct usbnet *un) | 517 | udav_reset(struct usbnet *un) | |
522 | { | 518 | { | |
523 | 519 | |||
524 | if (usbnet_isdying(un)) | 520 | if (usbnet_isdying(un)) | |
525 | return; | 521 | return; | |
526 | 522 | |||
527 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 523 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
528 | 524 | |||
529 | udav_chip_init(un); | 525 | udav_chip_init(un); | |
530 | } | 526 | } | |
531 | 527 | |||
532 | static void | 528 | static void | |
533 | udav_chip_init(struct usbnet *un) | 529 | udav_chip_init(struct usbnet *un) | |
534 | { | 530 | { | |
535 | 531 | |||
536 | /* Select PHY */ | 532 | /* Select PHY */ | |
537 | #if 1 | 533 | #if 1 | |
538 | /* | 534 | /* | |
539 | * XXX: force select internal phy. | 535 | * XXX: force select internal phy. | |
540 | * external phy routines are not tested. | 536 | * external phy routines are not tested. | |
541 | */ | 537 | */ | |
542 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | 538 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | |
543 | #else | 539 | #else | |
544 | if (un->un_flags & UDAV_EXT_PHY) { | 540 | if (un->un_flags & UDAV_EXT_PHY) { | |
545 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | 541 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | |
546 | } else { | 542 | } else { | |
547 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | 543 | UDAV_CLRBIT(un, UDAV_NCR, UDAV_NCR_EXT_PHY); | |
548 | } | 544 | } | |
549 | #endif | 545 | #endif | |
550 | 546 | |||
551 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_RST); | 547 | UDAV_SETBIT(un, UDAV_NCR, UDAV_NCR_RST); | |
552 | 548 | |||
553 | for (int i = 0; i < UDAV_TX_TIMEOUT; i++) { | 549 | for (int i = 0; i < UDAV_TX_TIMEOUT; i++) { | |
554 | if (usbnet_isdying(un)) | 550 | if (usbnet_isdying(un)) | |
555 | return; | 551 | return; | |
556 | if (!(udav_csr_read1(un, UDAV_NCR) & UDAV_NCR_RST)) | 552 | if (!(udav_csr_read1(un, UDAV_NCR) & UDAV_NCR_RST)) | |
557 | break; | 553 | break; | |
558 | delay(10); /* XXX */ | 554 | delay(10); /* XXX */ | |
559 | } | 555 | } | |
560 | delay(10000); /* XXX */ | 556 | delay(10000); /* XXX */ | |
561 | } | 557 | } | |
562 | 558 | |||
563 | #define UDAV_BITS 6 | 559 | #define UDAV_BITS 6 | |
564 | 560 | |||
565 | #define UDAV_CALCHASH(addr) \ | 561 | #define UDAV_CALCHASH(addr) \ | |
566 | (ether_crc32_le((addr), ETHER_ADDR_LEN) & ((1 << UDAV_BITS) - 1)) | 562 | (ether_crc32_le((addr), ETHER_ADDR_LEN) & ((1 << UDAV_BITS) - 1)) | |
567 | 563 | |||
568 | static void | 564 | static void | |
569 | udav_uno_mcast(struct ifnet *ifp) | 565 | udav_uno_mcast(struct ifnet *ifp) | |
570 | { | 566 | { | |
571 | struct usbnet * const un = ifp->if_softc; | 567 | struct usbnet * const un = ifp->if_softc; | |
572 | struct ethercom *ec = usbnet_ec(un); | 568 | struct ethercom *ec = usbnet_ec(un); | |
573 | struct ether_multi *enm; | 569 | struct ether_multi *enm; | |
574 | struct ether_multistep step; | 570 | struct ether_multistep step; | |
575 | uint8_t hashes[8]; | 571 | uint8_t hashes[8]; | |
576 | int h = 0; | 572 | int h = 0; | |
577 | 573 | |||
578 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 574 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
579 | 575 | |||
580 | if (usbnet_isdying(un)) | 576 | if (usbnet_isdying(un)) | |
581 | return; | 577 | return; | |
582 | 578 | |||
583 | if (ISSET(un->un_flags, UDAV_NO_PHY)) { | 579 | if (ISSET(un->un_flags, UDAV_NO_PHY)) { | |
584 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | 580 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | |
585 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | 581 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | |
586 | return; | 582 | return; | |
587 | } | 583 | } | |
588 | 584 | |||
589 | if (ifp->if_flags & IFF_PROMISC) { | 585 | if (ifp->if_flags & IFF_PROMISC) { | |
590 | ETHER_LOCK(ec); | 586 | ETHER_LOCK(ec); | |
591 | ec->ec_flags |= ETHER_F_ALLMULTI; | 587 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
592 | ETHER_UNLOCK(ec); | 588 | ETHER_UNLOCK(ec); | |
593 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | 589 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL | UDAV_RCR_PRMSC); | |
594 | return; | 590 | return; | |
595 | } else if (ifp->if_flags & IFF_ALLMULTI) { /* XXX ??? Can't happen? */ | 591 | } else if (ifp->if_flags & IFF_ALLMULTI) { /* XXX ??? Can't happen? */ | |
596 | ETHER_LOCK(ec); | 592 | ETHER_LOCK(ec); | |
597 | allmulti: | 593 | allmulti: | |
598 | ec->ec_flags |= ETHER_F_ALLMULTI; | 594 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
599 | ETHER_UNLOCK(ec); | 595 | ETHER_UNLOCK(ec); | |
600 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | 596 | UDAV_SETBIT(un, UDAV_RCR, UDAV_RCR_ALL); | |
601 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | 597 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_PRMSC); | |
602 | return; | 598 | return; | |
603 | } | 599 | } | |
604 | 600 | |||
605 | /* first, zot all the existing hash bits */ | 601 | /* first, zot all the existing hash bits */ | |
606 | memset(hashes, 0x00, sizeof(hashes)); | 602 | memset(hashes, 0x00, sizeof(hashes)); | |
607 | hashes[7] |= 0x80; /* broadcast address */ | 603 | hashes[7] |= 0x80; /* broadcast address */ | |
608 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | 604 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | |
609 | 605 | |||
610 | /* now program new ones */ | 606 | /* now program new ones */ | |
611 | ETHER_LOCK(ec); | 607 | ETHER_LOCK(ec); | |
612 | ETHER_FIRST_MULTI(step, ec, enm); | 608 | ETHER_FIRST_MULTI(step, ec, enm); | |
613 | while (enm != NULL) { | 609 | while (enm != NULL) { | |
614 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | 610 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | |
615 | ETHER_ADDR_LEN) != 0) { | 611 | ETHER_ADDR_LEN) != 0) { | |
616 | goto allmulti; | 612 | goto allmulti; | |
617 | } | 613 | } | |
618 | 614 | |||
619 | h = UDAV_CALCHASH(enm->enm_addrlo); | 615 | h = UDAV_CALCHASH(enm->enm_addrlo); | |
620 | hashes[h>>3] |= 1 << (h & 0x7); | 616 | hashes[h>>3] |= 1 << (h & 0x7); | |
621 | ETHER_NEXT_MULTI(step, enm); | 617 | ETHER_NEXT_MULTI(step, enm); | |
622 | } | 618 | } | |
623 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 619 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
624 | ETHER_UNLOCK(ec); | 620 | ETHER_UNLOCK(ec); | |
625 | 621 | |||
626 | /* disable all multicast */ | 622 | /* disable all multicast */ | |
627 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL); | 623 | UDAV_CLRBIT(un, UDAV_RCR, UDAV_RCR_ALL); | |
628 | 624 | |||
629 | /* write hash value to the register */ | 625 | /* write hash value to the register */ | |
630 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | 626 | udav_csr_write(un, UDAV_MAR, hashes, sizeof(hashes)); | |
631 | } | 627 | } | |
632 | 628 | |||
633 | static unsigned | 629 | static unsigned | |
634 | udav_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 630 | udav_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
635 | { | 631 | { | |
636 | int total_len; | 632 | int total_len; | |
637 | uint8_t *buf = c->unc_buf; | 633 | uint8_t *buf = c->unc_buf; | |
638 | 634 | |||
639 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 635 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
640 | 636 | |||
641 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | 637 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - 2) | |
642 | return 0; | 638 | return 0; | |
643 | 639 | |||
644 | /* Copy the mbuf data into a contiguous buffer */ | 640 | /* Copy the mbuf data into a contiguous buffer */ | |
645 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | 641 | m_copydata(m, 0, m->m_pkthdr.len, buf + 2); | |
646 | total_len = m->m_pkthdr.len; | 642 | total_len = m->m_pkthdr.len; | |
647 | if (total_len < UDAV_MIN_FRAME_LEN) { | 643 | if (total_len < UDAV_MIN_FRAME_LEN) { | |
648 | memset(buf + 2 + total_len, 0, | 644 | memset(buf + 2 + total_len, 0, | |
649 | UDAV_MIN_FRAME_LEN - total_len); | 645 | UDAV_MIN_FRAME_LEN - total_len); | |
650 | total_len = UDAV_MIN_FRAME_LEN; | 646 | total_len = UDAV_MIN_FRAME_LEN; | |
651 | } | 647 | } | |
652 | 648 | |||
653 | /* Frame length is specified in the first 2bytes of the buffer */ | 649 | /* Frame length is specified in the first 2bytes of the buffer */ | |
654 | buf[0] = (uint8_t)total_len; | 650 | buf[0] = (uint8_t)total_len; | |
655 | buf[1] = (uint8_t)(total_len >> 8); | 651 | buf[1] = (uint8_t)(total_len >> 8); | |
656 | total_len += 2; | 652 | total_len += 2; | |
657 | 653 | |||
658 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | 654 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | |
659 | __func__, total_len)); | 655 | __func__, total_len)); | |
660 | 656 | |||
661 | return total_len; | 657 | return total_len; | |
662 | } | 658 | } | |
663 | 659 | |||
664 | static void | 660 | static void | |
665 | udav_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 661 | udav_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
666 | { | 662 | { | |
667 | struct ifnet *ifp = usbnet_ifp(un); | 663 | struct ifnet *ifp = usbnet_ifp(un); | |
668 | uint8_t *buf = c->unc_buf; | 664 | uint8_t *buf = c->unc_buf; | |
669 | uint16_t pkt_len; | 665 | uint16_t pkt_len; | |
670 | uint8_t pktstat; | 666 | uint8_t pktstat; | |
671 | 667 | |||
672 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 668 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
673 | 669 | |||
674 | /* first byte in received data */ | 670 | /* first byte in received data */ | |
675 | pktstat = *buf; | 671 | pktstat = *buf; | |
676 | total_len -= sizeof(pktstat); | 672 | total_len -= sizeof(pktstat); | |
677 | buf += sizeof(pktstat); | 673 | buf += sizeof(pktstat); | |
678 | 674 | |||
679 | DPRINTF(("%s: RX Status: 0x%02x\n", device_xname(un->un_dev), pktstat)); | 675 | DPRINTF(("%s: RX Status: 0x%02x\n", device_xname(un->un_dev), pktstat)); | |
680 | 676 | |||
681 | pkt_len = UGETW(buf); | 677 | pkt_len = UGETW(buf); | |
682 | total_len -= sizeof(pkt_len); | 678 | total_len -= sizeof(pkt_len); | |
683 | buf += sizeof(pkt_len); | 679 | buf += sizeof(pkt_len); | |
684 | 680 | |||
685 | DPRINTF(("%s: RX Length: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | 681 | DPRINTF(("%s: RX Length: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | |
686 | 682 | |||
687 | if (pktstat & UDAV_RSR_LCS) { | 683 | if (pktstat & UDAV_RSR_LCS) { | |
688 | if_statinc(ifp, if_collisions); | 684 | if_statinc(ifp, if_collisions); | |
689 | return; | 685 | return; | |
690 | } | 686 | } | |
691 | 687 | |||
692 | if (pkt_len < sizeof(struct ether_header) || | 688 | if (pkt_len < sizeof(struct ether_header) || | |
693 | pkt_len > total_len || | 689 | pkt_len > total_len || | |
694 | (pktstat & UDAV_RSR_ERR)) { | 690 | (pktstat & UDAV_RSR_ERR)) { | |
695 | if_statinc(ifp, if_ierrors); | 691 | if_statinc(ifp, if_ierrors); | |
696 | return; | 692 | return; | |
697 | } | 693 | } | |
698 | 694 | |||
699 | pkt_len -= ETHER_CRC_LEN; | 695 | pkt_len -= ETHER_CRC_LEN; | |
700 | 696 | |||
701 | DPRINTF(("%s: Rx deliver: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | 697 | DPRINTF(("%s: Rx deliver: 0x%02x\n", device_xname(un->un_dev), pkt_len)); | |
702 | 698 | |||
703 | usbnet_enqueue(un, buf, pkt_len, 0, 0, 0); | 699 | usbnet_enqueue(un, buf, pkt_len, 0, 0, 0); | |
704 | } | 700 | } | |
705 | 701 | |||
706 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | 702 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | |
707 | static void | 703 | static void | |
708 | udav_uno_stop(struct ifnet *ifp, int disable) | 704 | udav_uno_stop(struct ifnet *ifp, int disable) | |
709 | { | 705 | { | |
710 | struct usbnet * const un = ifp->if_softc; | 706 | struct usbnet * const un = ifp->if_softc; | |
711 | 707 | |||
712 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 708 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
713 | 709 | |||
714 | udav_reset(un); | 710 | udav_reset(un); | |
715 | } | 711 | } | |
716 | 712 | |||
717 | static int | 713 | static int | |
718 | udav_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 714 | udav_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
719 | { | 715 | { | |
720 | uint8_t data[2]; | 716 | uint8_t data[2]; | |
721 | 717 | |||
722 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | 718 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | |
723 | device_xname(un->un_dev), __func__, phy, reg)); | 719 | device_xname(un->un_dev), __func__, phy, reg)); | |
724 | 720 | |||
725 | if (usbnet_isdying(un)) { | 721 | if (usbnet_isdying(un)) { | |
726 | #ifdef DIAGNOSTIC | 722 | #ifdef DIAGNOSTIC | |
727 | printf("%s: %s: dying\n", device_xname(un->un_dev), | 723 | printf("%s: %s: dying\n", device_xname(un->un_dev), | |
728 | __func__); | 724 | __func__); | |
729 | #endif | 725 | #endif | |
730 | *val = 0; | 726 | *val = 0; | |
731 | return EINVAL; | 727 | return EINVAL; | |
732 | } | 728 | } | |
733 | 729 | |||
734 | /* XXX: one PHY only for the internal PHY */ | 730 | /* XXX: one PHY only for the internal PHY */ | |
735 | if (phy != 0) { | 731 | if (phy != 0) { | |
736 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 732 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
737 | device_xname(un->un_dev), __func__, phy)); | 733 | device_xname(un->un_dev), __func__, phy)); | |
738 | *val = 0; | 734 | *val = 0; | |
739 | return EINVAL; | 735 | return EINVAL; | |
740 | } | 736 | } | |
741 | 737 | |||
742 | /* select internal PHY and set PHY register address */ | 738 | /* select internal PHY and set PHY register address */ | |
743 | udav_csr_write1(un, UDAV_EPAR, | 739 | udav_csr_write1(un, UDAV_EPAR, | |
744 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | 740 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | |
745 | 741 | |||
746 | /* select PHY operation and start read command */ | 742 | /* select PHY operation and start read command */ | |
747 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR); | 743 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRR); | |
748 | 744 | |||
749 | /* XXX: should be wait? */ | 745 | /* XXX: should be wait? */ | |
750 | 746 | |||
751 | /* end read command */ | 747 | /* end read command */ | |
752 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRR); | 748 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRR); | |
753 | 749 | |||
754 | /* retrieve the result from data registers */ | 750 | /* retrieve the result from data registers */ | |
755 | udav_csr_read(un, UDAV_EPDRL, data, 2); | 751 | udav_csr_read(un, UDAV_EPDRL, data, 2); | |
756 | 752 | |||
757 | *val = data[0] | (data[1] << 8); | 753 | *val = data[0] | (data[1] << 8); | |
758 | 754 | |||
759 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | 755 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | |
760 | device_xname(un->un_dev), __func__, phy, reg, *val)); | 756 | device_xname(un->un_dev), __func__, phy, reg, *val)); | |
761 | 757 | |||
762 | return 0; | 758 | return 0; | |
763 | } | 759 | } | |
764 | 760 | |||
765 | static int | 761 | static int | |
766 | udav_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 762 | udav_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
767 | { | 763 | { | |
768 | uint8_t data[2]; | 764 | uint8_t data[2]; | |
769 | 765 | |||
770 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | 766 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | |
771 | device_xname(un->un_dev), __func__, phy, reg, val)); | 767 | device_xname(un->un_dev), __func__, phy, reg, val)); | |
772 | 768 | |||
773 | if (usbnet_isdying(un)) { | 769 | if (usbnet_isdying(un)) { | |
774 | #ifdef DIAGNOSTIC | 770 | #ifdef DIAGNOSTIC | |
775 | printf("%s: %s: dying\n", device_xname(un->un_dev), | 771 | printf("%s: %s: dying\n", device_xname(un->un_dev), | |
776 | __func__); | 772 | __func__); | |
777 | #endif | 773 | #endif | |
778 | return EIO; | 774 | return EIO; | |
779 | } | 775 | } | |
780 | 776 | |||
781 | /* XXX: one PHY only for the internal PHY */ | 777 | /* XXX: one PHY only for the internal PHY */ | |
782 | if (phy != 0) { | 778 | if (phy != 0) { | |
783 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 779 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
784 | device_xname(un->un_dev), __func__, phy)); | 780 | device_xname(un->un_dev), __func__, phy)); | |
785 | return EIO; | 781 | return EIO; | |
786 | } | 782 | } | |
787 | 783 | |||
788 | /* select internal PHY and set PHY register address */ | 784 | /* select internal PHY and set PHY register address */ | |
789 | udav_csr_write1(un, UDAV_EPAR, | 785 | udav_csr_write1(un, UDAV_EPAR, | |
790 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | 786 | UDAV_EPAR_PHY_ADR0 | (reg & UDAV_EPAR_EROA_MASK)); | |
791 | 787 | |||
792 | /* put the value to the data registers */ | 788 | /* put the value to the data registers */ | |
793 | data[0] = val & 0xff; | 789 | data[0] = val & 0xff; | |
794 | data[1] = (val >> 8) & 0xff; | 790 | data[1] = (val >> 8) & 0xff; | |
795 | udav_csr_write(un, UDAV_EPDRL, data, 2); | 791 | udav_csr_write(un, UDAV_EPDRL, data, 2); | |
796 | 792 | |||
797 | /* select PHY operation and start write command */ | 793 | /* select PHY operation and start write command */ | |
798 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW); | 794 | udav_csr_write1(un, UDAV_EPCR, UDAV_EPCR_EPOS | UDAV_EPCR_ERPRW); | |
799 | 795 | |||
800 | /* XXX: should be wait? */ | 796 | /* XXX: should be wait? */ | |
801 | 797 | |||
802 | /* end write command */ | 798 | /* end write command */ | |
803 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRW); | 799 | UDAV_CLRBIT(un, UDAV_EPCR, UDAV_EPCR_ERPRW); | |
804 | 800 | |||
805 | return 0; | 801 | return 0; | |
806 | } | 802 | } | |
807 | 803 | |||
808 | static void | 804 | static void | |
809 | udav_uno_mii_statchg(struct ifnet *ifp) | 805 | udav_uno_mii_statchg(struct ifnet *ifp) | |
810 | { | 806 | { | |
811 | struct usbnet * const un = ifp->if_softc; | 807 | struct usbnet * const un = ifp->if_softc; | |
812 | struct mii_data * const mii = usbnet_mii(un); | 808 | struct mii_data * const mii = usbnet_mii(un); | |
813 | 809 | |||
814 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | 810 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | |
815 | 811 | |||
816 | if (usbnet_isdying(un)) | 812 | if (usbnet_isdying(un)) | |
817 | return; | 813 | return; | |
818 | 814 | |||
819 | if ((mii->mii_media_status & IFM_ACTIVE) && | 815 | if ((mii->mii_media_status & IFM_ACTIVE) && | |
820 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | 816 | IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { | |
821 | DPRINTF(("%s: %s: got link\n", | 817 | DPRINTF(("%s: %s: got link\n", | |
822 | device_xname(un->un_dev), __func__)); | 818 | device_xname(un->un_dev), __func__)); | |
823 | usbnet_set_link(un, true); | 819 | usbnet_set_link(un, true); | |
824 | } | 820 | } | |
825 | } | 821 | } | |
826 | 822 | |||
827 | #ifdef _MODULE | 823 | #ifdef _MODULE | |
828 | #include "ioconf.c" | 824 | #include "ioconf.c" | |
829 | #endif | 825 | #endif | |
830 | 826 | |||
831 | USBNET_MODULE(udav) | 827 | USBNET_MODULE(udav) |
--- src/sys/dev/usb/if_upl.c 2022/03/03 05:50:22 1.72
+++ src/sys/dev/usb/if_upl.c 2022/03/03 05:55:01 1.73
@@ -1,320 +1,317 @@ | @@ -1,320 +1,317 @@ | |||
1 | /* $NetBSD: if_upl.c,v 1.72 2022/03/03 05:50:22 riastradh Exp $ */ | 1 | /* $NetBSD: if_upl.c,v 1.73 2022/03/03 05:55:01 riastradh Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 2000 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2000 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Lennart Augustsson (lennart@augustsson.net) at | 8 | * by Lennart Augustsson (lennart@augustsson.net) at | |
9 | * Carlstedt Research & Technology. | 9 | * Carlstedt Research & Technology. | |
10 | * | 10 | * | |
11 | * Redistribution and use in source and binary forms, with or without | 11 | * Redistribution and use in source and binary forms, with or without | |
12 | * modification, are permitted provided that the following conditions | 12 | * modification, are permitted provided that the following conditions | |
13 | * are met: | 13 | * are met: | |
14 | * 1. Redistributions of source code must retain the above copyright | 14 | * 1. Redistributions of source code must retain the above copyright | |
15 | * notice, this list of conditions and the following disclaimer. | 15 | * notice, this list of conditions and the following disclaimer. | |
16 | * 2. Redistributions in binary form must reproduce the above copyright | 16 | * 2. Redistributions in binary form must reproduce the above copyright | |
17 | * notice, this list of conditions and the following disclaimer in the | 17 | * notice, this list of conditions and the following disclaimer in the | |
18 | * documentation and/or other materials provided with the distribution. | 18 | * documentation and/or other materials provided with the distribution. | |
19 | * | 19 | * | |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
30 | * POSSIBILITY OF SUCH DAMAGE. | 30 | * POSSIBILITY OF SUCH DAMAGE. | |
31 | */ | 31 | */ | |
32 | 32 | |||
33 | /* | 33 | /* | |
34 | * Prolific PL2301/PL2302 driver | 34 | * Prolific PL2301/PL2302 driver | |
35 | */ | 35 | */ | |
36 | 36 | |||
37 | #include <sys/cdefs.h> | 37 | #include <sys/cdefs.h> | |
38 | __KERNEL_RCSID(0, "$NetBSD: if_upl.c,v 1.72 2022/03/03 05:50:22 riastradh Exp $"); | 38 | __KERNEL_RCSID(0, "$NetBSD: if_upl.c,v 1.73 2022/03/03 05:55:01 riastradh Exp $"); | |
39 | 39 | |||
40 | #ifdef _KERNEL_OPT | 40 | #ifdef _KERNEL_OPT | |
41 | #include "opt_inet.h" | 41 | #include "opt_inet.h" | |
42 | #include "opt_usb.h" | 42 | #include "opt_usb.h" | |
43 | #endif | 43 | #endif | |
44 | 44 | |||
45 | #include <sys/param.h> | 45 | #include <sys/param.h> | |
46 | 46 | |||
47 | #include <dev/usb/usbnet.h> | 47 | #include <dev/usb/usbnet.h> | |
48 | 48 | |||
49 | #include <net/if_types.h> | 49 | #include <net/if_types.h> | |
50 | 50 | |||
51 | #ifdef INET | 51 | #ifdef INET | |
52 | #include <netinet/in.h> | 52 | #include <netinet/in.h> | |
53 | #include <netinet/in_var.h> | 53 | #include <netinet/in_var.h> | |
54 | #include <netinet/if_inarp.h> | 54 | #include <netinet/if_inarp.h> | |
55 | #endif | 55 | #endif | |
56 | 56 | |||
57 | /* | 57 | /* | |
58 | * 7 6 5 4 3 2 1 0 | 58 | * 7 6 5 4 3 2 1 0 | |
59 | * tx rx 1 0 | 59 | * tx rx 1 0 | |
60 | * 1110 0000 rxdata | 60 | * 1110 0000 rxdata | |
61 | * 1010 0000 idle | 61 | * 1010 0000 idle | |
62 | * 0010 0000 tx over | 62 | * 0010 0000 tx over | |
63 | * 0110 tx over + rxd | 63 | * 0110 tx over + rxd | |
64 | */ | 64 | */ | |
65 | 65 | |||
66 | #define UPL_RXDATA 0x40 | 66 | #define UPL_RXDATA 0x40 | |
67 | #define UPL_TXOK 0x80 | 67 | #define UPL_TXOK 0x80 | |
68 | 68 | |||
69 | #define UPL_CONFIG_NO 1 | 69 | #define UPL_CONFIG_NO 1 | |
70 | #define UPL_IFACE_IDX 0 | 70 | #define UPL_IFACE_IDX 0 | |
71 | 71 | |||
72 | /***/ | 72 | /***/ | |
73 | 73 | |||
74 | #define UPL_INTR_INTERVAL 20 | 74 | #define UPL_INTR_INTERVAL 20 | |
75 | 75 | |||
76 | #define UPL_BUFSZ 1024 | 76 | #define UPL_BUFSZ 1024 | |
77 | 77 | |||
78 | #define UPL_RX_LIST_CNT 1 | 78 | #define UPL_RX_LIST_CNT 1 | |
79 | #define UPL_TX_LIST_CNT 1 | 79 | #define UPL_TX_LIST_CNT 1 | |
80 | 80 | |||
81 | #ifdef UPL_DEBUG | 81 | #ifdef UPL_DEBUG | |
82 | #define DPRINTF(x) if (upldebug) printf x | 82 | #define DPRINTF(x) if (upldebug) printf x | |
83 | #define DPRINTFN(n,x) if (upldebug >= (n)) printf x | 83 | #define DPRINTFN(n,x) if (upldebug >= (n)) printf x | |
84 | int upldebug = 0; | 84 | int upldebug = 0; | |
85 | #else | 85 | #else | |
86 | #define DPRINTF(x) | 86 | #define DPRINTF(x) | |
87 | #define DPRINTFN(n,x) | 87 | #define DPRINTFN(n,x) | |
88 | #endif | 88 | #endif | |
89 | 89 | |||
90 | /* | 90 | /* | |
91 | * Various supported device vendors/products. | 91 | * Various supported device vendors/products. | |
92 | */ | 92 | */ | |
93 | static const struct usb_devno sc_devs[] = { | 93 | static const struct usb_devno sc_devs[] = { | |
94 | { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2301 }, | 94 | { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2301 }, | |
95 | { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2302 }, | 95 | { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2302 }, | |
96 | { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL25A1 }, | 96 | { USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL25A1 }, | |
97 | { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U258 }, | 97 | { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5U258 }, | |
98 | { USB_VENDOR_NI, USB_PRODUCT_NI_HTOH_7825 } | 98 | { USB_VENDOR_NI, USB_PRODUCT_NI_HTOH_7825 } | |
99 | }; | 99 | }; | |
100 | 100 | |||
101 | static int upl_match(device_t, cfdata_t, void *); | 101 | static int upl_match(device_t, cfdata_t, void *); | |
102 | static void upl_attach(device_t, device_t, void *); | 102 | static void upl_attach(device_t, device_t, void *); | |
103 | 103 | |||
104 | CFATTACH_DECL_NEW(upl, sizeof(struct usbnet), upl_match, upl_attach, | 104 | CFATTACH_DECL_NEW(upl, sizeof(struct usbnet), upl_match, upl_attach, | |
105 | usbnet_detach, usbnet_activate); | 105 | usbnet_detach, usbnet_activate); | |
106 | 106 | |||
107 | #if 0 | 107 | #if 0 | |
108 | static void upl_uno_intr(struct usbnet *, usbd_status); | 108 | static void upl_uno_intr(struct usbnet *, usbd_status); | |
109 | #endif | 109 | #endif | |
110 | static void upl_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 110 | static void upl_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
111 | static unsigned upl_uno_tx_prepare(struct usbnet *, struct mbuf *, | 111 | static unsigned upl_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
112 | struct usbnet_chain *); | 112 | struct usbnet_chain *); | |
113 | static int upl_uno_ioctl(struct ifnet *, u_long, void *); | 113 | static int upl_uno_ioctl(struct ifnet *, u_long, void *); | |
114 | static int upl_uno_init(struct ifnet *); | 114 | static int upl_uno_init(struct ifnet *); | |
115 | 115 | |||
116 | static const struct usbnet_ops upl_ops = { | 116 | static const struct usbnet_ops upl_ops = { | |
117 | .uno_init = upl_uno_init, | 117 | .uno_init = upl_uno_init, | |
118 | .uno_tx_prepare = upl_uno_tx_prepare, | 118 | .uno_tx_prepare = upl_uno_tx_prepare, | |
119 | .uno_rx_loop = upl_uno_rx_loop, | 119 | .uno_rx_loop = upl_uno_rx_loop, | |
120 | .uno_ioctl = upl_uno_ioctl, | 120 | .uno_ioctl = upl_uno_ioctl, | |
121 | #if 0 | 121 | #if 0 | |
122 | .uno_intr = upl_uno_intr, | 122 | .uno_intr = upl_uno_intr, | |
123 | #endif | 123 | #endif | |
124 | }; | 124 | }; | |
125 | 125 | |||
126 | static int upl_output(struct ifnet *, struct mbuf *, const struct sockaddr *, | 126 | static int upl_output(struct ifnet *, struct mbuf *, const struct sockaddr *, | |
127 | const struct rtentry *); | 127 | const struct rtentry *); | |
128 | static void upl_input(struct ifnet *, struct mbuf *); | 128 | static void upl_input(struct ifnet *, struct mbuf *); | |
129 | 129 | |||
130 | /* | 130 | /* | |
131 | * Probe for a Prolific chip. | 131 | * Probe for a Prolific chip. | |
132 | */ | 132 | */ | |
133 | static int | 133 | static int | |
134 | upl_match(device_t parent, cfdata_t match, void *aux) | 134 | upl_match(device_t parent, cfdata_t match, void *aux) | |
135 | { | 135 | { | |
136 | struct usb_attach_arg *uaa = aux; | 136 | struct usb_attach_arg *uaa = aux; | |
137 | 137 | |||
138 | return usb_lookup(sc_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 138 | return usb_lookup(sc_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
139 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 139 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
140 | } | 140 | } | |
141 | 141 | |||
142 | static void | 142 | static void | |
143 | upl_attach(device_t parent, device_t self, void *aux) | 143 | upl_attach(device_t parent, device_t self, void *aux) | |
144 | { | 144 | { | |
145 | struct usbnet * const un = device_private(self); | 145 | struct usbnet * const un = device_private(self); | |
146 | struct usb_attach_arg *uaa = aux; | 146 | struct usb_attach_arg *uaa = aux; | |
147 | char *devinfop; | 147 | char *devinfop; | |
148 | struct usbd_device * dev = uaa->uaa_device; | 148 | struct usbd_device * dev = uaa->uaa_device; | |
149 | usbd_status err; | 149 | usbd_status err; | |
150 | usb_interface_descriptor_t *id; | 150 | usb_interface_descriptor_t *id; | |
151 | usb_endpoint_descriptor_t *ed; | 151 | usb_endpoint_descriptor_t *ed; | |
152 | int i; | 152 | int i; | |
153 | 153 | |||
154 | DPRINTFN(5,(" : upl_attach: un=%p, dev=%p", un, dev)); | 154 | DPRINTFN(5,(" : upl_attach: un=%p, dev=%p", un, dev)); | |
155 | 155 | |||
156 | aprint_naive("\n"); | 156 | aprint_naive("\n"); | |
157 | aprint_normal("\n"); | 157 | aprint_normal("\n"); | |
158 | devinfop = usbd_devinfo_alloc(dev, 0); | 158 | devinfop = usbd_devinfo_alloc(dev, 0); | |
159 | aprint_normal_dev(self, "%s\n", devinfop); | 159 | aprint_normal_dev(self, "%s\n", devinfop); | |
160 | usbd_devinfo_free(devinfop); | 160 | usbd_devinfo_free(devinfop); | |
161 | 161 | |||
162 | un->un_dev = self; | 162 | un->un_dev = self; | |
163 | un->un_udev = dev; | 163 | un->un_udev = dev; | |
164 | un->un_sc = un; | 164 | un->un_sc = un; | |
165 | un->un_ops = &upl_ops; | 165 | un->un_ops = &upl_ops; | |
166 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 166 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
167 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 167 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
168 | un->un_rx_list_cnt = UPL_RX_LIST_CNT; | 168 | un->un_rx_list_cnt = UPL_RX_LIST_CNT; | |
169 | un->un_tx_list_cnt = UPL_TX_LIST_CNT; | 169 | un->un_tx_list_cnt = UPL_TX_LIST_CNT; | |
170 | un->un_rx_bufsz = UPL_BUFSZ; | 170 | un->un_rx_bufsz = UPL_BUFSZ; | |
171 | un->un_tx_bufsz = UPL_BUFSZ; | 171 | un->un_tx_bufsz = UPL_BUFSZ; | |
172 | 172 | |||
173 | err = usbd_set_config_no(dev, UPL_CONFIG_NO, 1); | 173 | err = usbd_set_config_no(dev, UPL_CONFIG_NO, 1); | |
174 | if (err) { | 174 | if (err) { | |
175 | aprint_error_dev(self, "failed to set configuration" | 175 | aprint_error_dev(self, "failed to set configuration" | |
176 | ", err=%s\n", usbd_errstr(err)); | 176 | ", err=%s\n", usbd_errstr(err)); | |
177 | return; | 177 | return; | |
178 | } | 178 | } | |
179 | 179 | |||
180 | err = usbd_device2interface_handle(dev, UPL_IFACE_IDX, &un->un_iface); | 180 | err = usbd_device2interface_handle(dev, UPL_IFACE_IDX, &un->un_iface); | |
181 | if (err) { | 181 | if (err) { | |
182 | aprint_error_dev(self, "getting interface handle failed\n"); | 182 | aprint_error_dev(self, "getting interface handle failed\n"); | |
183 | return; | 183 | return; | |
184 | } | 184 | } | |
185 | 185 | |||
186 | id = usbd_get_interface_descriptor(un->un_iface); | 186 | id = usbd_get_interface_descriptor(un->un_iface); | |
187 | 187 | |||
188 | /* Find endpoints. */ | 188 | /* Find endpoints. */ | |
189 | for (i = 0; i < id->bNumEndpoints; i++) { | 189 | for (i = 0; i < id->bNumEndpoints; i++) { | |
190 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 190 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
191 | if (ed == NULL) { | 191 | if (ed == NULL) { | |
192 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 192 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
193 | return; | 193 | return; | |
194 | } | 194 | } | |
195 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 195 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
196 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 196 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
197 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 197 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
198 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 198 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
199 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 199 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
200 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 200 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
201 | } | 201 | } | |
202 | } | 202 | } | |
203 | 203 | |||
204 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || un->un_ed[USBNET_ENDPT_TX] == 0 /*|| | 204 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || un->un_ed[USBNET_ENDPT_TX] == 0 /*|| | |
205 | un->un_ed[USBNET_ENDPT_INTR] == 0*/) { | 205 | un->un_ed[USBNET_ENDPT_INTR] == 0*/) { | |
206 | aprint_error_dev(self, "missing endpoint\n"); | 206 | aprint_error_dev(self, "missing endpoint\n"); | |
207 | return; | 207 | return; | |
208 | } | 208 | } | |
209 | 209 | |||
210 | usbnet_attach(un, "upldet"); | 210 | usbnet_attach(un, "upldet"); | |
211 | 211 | |||
212 | /* Initialize interface info.*/ | 212 | /* Initialize interface info.*/ | |
213 | struct ifnet *ifp = usbnet_ifp(un); | 213 | struct ifnet *ifp = usbnet_ifp(un); | |
214 | ifp->if_mtu = UPL_BUFSZ; | 214 | ifp->if_mtu = UPL_BUFSZ; | |
215 | ifp->if_type = IFT_OTHER; | 215 | ifp->if_type = IFT_OTHER; | |
216 | ifp->if_addrlen = 0; | 216 | ifp->if_addrlen = 0; | |
217 | ifp->if_hdrlen = 0; | 217 | ifp->if_hdrlen = 0; | |
218 | ifp->if_output = upl_output; | 218 | ifp->if_output = upl_output; | |
219 | ifp->_if_input = upl_input; | 219 | ifp->_if_input = upl_input; | |
220 | ifp->if_baudrate = 12000000; | 220 | ifp->if_baudrate = 12000000; | |
221 | ifp->if_dlt = DLT_RAW; | 221 | ifp->if_dlt = DLT_RAW; | |
222 | 222 | |||
223 | usbnet_attach_ifp(un, IFF_POINTOPOINT | IFF_NOARP | IFF_SIMPLEX, | 223 | usbnet_attach_ifp(un, IFF_POINTOPOINT | IFF_NOARP | IFF_SIMPLEX, | |
224 | 0, NULL); | 224 | 0, NULL); | |
225 | } | 225 | } | |
226 | 226 | |||
227 | static void | 227 | static void | |
228 | upl_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) | 228 | upl_uno_rx_loop(struct usbnet * un, struct usbnet_chain *c, uint32_t total_len) | |
229 | { | 229 | { | |
230 | 230 | |||
231 | DPRINTFN(9,("%s: %s: enter length=%d\n", | 231 | DPRINTFN(9,("%s: %s: enter length=%d\n", | |
232 | device_xname(un->un_dev), __func__, total_len)); | 232 | device_xname(un->un_dev), __func__, total_len)); | |
233 | 233 | |||
234 | usbnet_input(un, c->unc_buf, total_len); | 234 | usbnet_input(un, c->unc_buf, total_len); | |
235 | } | 235 | } | |
236 | 236 | |||
237 | static unsigned | 237 | static unsigned | |
238 | upl_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 238 | upl_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
239 | { | 239 | { | |
240 | int total_len; | 240 | int total_len; | |
241 | 241 | |||
242 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | 242 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | |
243 | return 0; | 243 | return 0; | |
244 | 244 | |||
245 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | 245 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | |
246 | total_len = m->m_pkthdr.len; | 246 | total_len = m->m_pkthdr.len; | |
247 | 247 | |||
248 | DPRINTFN(10,("%s: %s: total_len=%d\n", | 248 | DPRINTFN(10,("%s: %s: total_len=%d\n", | |
249 | device_xname(un->un_dev), __func__, total_len)); | 249 | device_xname(un->un_dev), __func__, total_len)); | |
250 | 250 | |||
251 | return total_len; | 251 | return total_len; | |
252 | } | 252 | } | |
253 | 253 | |||
254 | static int | 254 | static int | |
255 | upl_uno_init(struct ifnet *ifp) | 255 | upl_uno_init(struct ifnet *ifp) | |
256 | { | 256 | { | |
257 | struct usbnet * const un = ifp->if_softc; | 257 | struct usbnet * const un = ifp->if_softc; | |
258 | int rv; | 258 | int rv; | |
259 | 259 | |||
260 | if (usbnet_isdying(un)) | 260 | rv = usbnet_init_rx_tx(un); | |
261 | rv = EIO; | |||
262 | else | |||
263 | rv = usbnet_init_rx_tx(un); | |||
264 | 261 | |||
265 | return rv; | 262 | return rv; | |
266 | } | 263 | } | |
267 | 264 | |||
268 | static int | 265 | static int | |
269 | upl_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 266 | upl_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
270 | { | 267 | { | |
271 | if (cmd == SIOCSIFMTU) { | 268 | if (cmd == SIOCSIFMTU) { | |
272 | struct ifreq *ifr = data; | 269 | struct ifreq *ifr = data; | |
273 | 270 | |||
274 | if (ifr->ifr_mtu > UPL_BUFSZ) | 271 | if (ifr->ifr_mtu > UPL_BUFSZ) | |
275 | return EINVAL; | 272 | return EINVAL; | |
276 | } | 273 | } | |
277 | return 0; | 274 | return 0; | |
278 | } | 275 | } | |
279 | 276 | |||
280 | static int | 277 | static int | |
281 | upl_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, | 278 | upl_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, | |
282 | const struct rtentry *rt0) | 279 | const struct rtentry *rt0) | |
283 | { | 280 | { | |
284 | struct usbnet * const un __unused = ifp->if_softc; | 281 | struct usbnet * const un __unused = ifp->if_softc; | |
285 | 282 | |||
286 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 283 | DPRINTFN(10,("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
287 | 284 | |||
288 | /* If the queueing discipline needs packet classification, do it now. */ | 285 | /* If the queueing discipline needs packet classification, do it now. */ | |
289 | IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); | 286 | IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); | |
290 | 287 | |||
291 | /* | 288 | /* | |
292 | * Queue message on interface, and start output if interface | 289 | * Queue message on interface, and start output if interface | |
293 | * not yet active. | 290 | * not yet active. | |
294 | */ | 291 | */ | |
295 | return if_transmit_lock(ifp, m); | 292 | return if_transmit_lock(ifp, m); | |
296 | } | 293 | } | |
297 | 294 | |||
298 | static void | 295 | static void | |
299 | upl_input(struct ifnet *ifp, struct mbuf *m) | 296 | upl_input(struct ifnet *ifp, struct mbuf *m) | |
300 | { | 297 | { | |
301 | #ifdef INET | 298 | #ifdef INET | |
302 | size_t pktlen = m->m_len; | 299 | size_t pktlen = m->m_len; | |
303 | int s; | 300 | int s; | |
304 | 301 | |||
305 | s = splnet(); | 302 | s = splnet(); | |
306 | if (__predict_false(!pktq_enqueue(ip_pktq, m, 0))) { | 303 | if (__predict_false(!pktq_enqueue(ip_pktq, m, 0))) { | |
307 | if_statinc(ifp, if_iqdrops); | 304 | if_statinc(ifp, if_iqdrops); | |
308 | m_freem(m); | 305 | m_freem(m); | |
309 | } else { | 306 | } else { | |
310 | if_statadd2(ifp, if_ipackets, 1, if_ibytes, pktlen); | 307 | if_statadd2(ifp, if_ipackets, 1, if_ibytes, pktlen); | |
311 | } | 308 | } | |
312 | splx(s); | 309 | splx(s); | |
313 | #endif | 310 | #endif | |
314 | } | 311 | } | |
315 | 312 | |||
316 | #ifdef _MODULE | 313 | #ifdef _MODULE | |
317 | #include "ioconf.c" | 314 | #include "ioconf.c" | |
318 | #endif | 315 | #endif | |
319 | 316 | |||
320 | USBNET_MODULE(upl) | 317 | USBNET_MODULE(upl) |
--- src/sys/dev/usb/if_ure.c 2022/03/03 05:54:37 1.52
+++ src/sys/dev/usb/if_ure.c 2022/03/03 05:55:01 1.53
@@ -1,1131 +1,1128 @@ | @@ -1,1131 +1,1128 @@ | |||
1 | /* $NetBSD: if_ure.c,v 1.52 2022/03/03 05:54:37 riastradh Exp $ */ | 1 | /* $NetBSD: if_ure.c,v 1.53 2022/03/03 05:55:01 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.52 2022/03/03 05:54:37 riastradh Exp $"); | 33 | __KERNEL_RCSID(0, "$NetBSD: if_ure.c,v 1.53 2022/03/03 05:55:01 riastradh Exp $"); | |
34 | 34 | |||
35 | #ifdef _KERNEL_OPT | 35 | #ifdef _KERNEL_OPT | |
36 | #include "opt_usb.h" | 36 | #include "opt_usb.h" | |
37 | #include "opt_inet.h" | 37 | #include "opt_inet.h" | |
38 | #endif | 38 | #endif | |
39 | 39 | |||
40 | #include <sys/param.h> | 40 | #include <sys/param.h> | |
41 | #include <sys/cprng.h> | 41 | #include <sys/cprng.h> | |
42 | 42 | |||
43 | #include <net/route.h> | 43 | #include <net/route.h> | |
44 | 44 | |||
45 | #include <dev/usb/usbnet.h> | 45 | #include <dev/usb/usbnet.h> | |
46 | 46 | |||
47 | #include <netinet/in_offload.h> /* XXX for in_undefer_cksum() */ | 47 | #include <netinet/in_offload.h> /* XXX for in_undefer_cksum() */ | |
48 | #ifdef INET6 | 48 | #ifdef INET6 | |
49 | #include <netinet/in.h> | 49 | #include <netinet/in.h> | |
50 | #include <netinet6/in6_offload.h> /* XXX for in6_undefer_cksum() */ | 50 | #include <netinet6/in6_offload.h> /* XXX for in6_undefer_cksum() */ | |
51 | #endif | 51 | #endif | |
52 | 52 | |||
53 | #include <dev/ic/rtl81x9reg.h> /* XXX for RTK_GMEDIASTAT */ | 53 | #include <dev/ic/rtl81x9reg.h> /* XXX for RTK_GMEDIASTAT */ | |
54 | #include <dev/usb/if_urereg.h> | 54 | #include <dev/usb/if_urereg.h> | |
55 | #include <dev/usb/if_urevar.h> | 55 | #include <dev/usb/if_urevar.h> | |
56 | 56 | |||
57 | #define URE_PRINTF(un, fmt, args...) \ | 57 | #define URE_PRINTF(un, fmt, args...) \ | |
58 | device_printf((un)->un_dev, "%s: " fmt, __func__, ##args); | 58 | device_printf((un)->un_dev, "%s: " fmt, __func__, ##args); | |
59 | 59 | |||
60 | #define URE_DEBUG | 60 | #define URE_DEBUG | |
61 | #ifdef URE_DEBUG | 61 | #ifdef URE_DEBUG | |
62 | #define DPRINTF(x) do { if (uredebug) printf x; } while (0) | 62 | #define DPRINTF(x) do { if (uredebug) printf x; } while (0) | |
63 | #define DPRINTFN(n, x) do { if (uredebug >= (n)) printf x; } while (0) | 63 | #define DPRINTFN(n, x) do { if (uredebug >= (n)) printf x; } while (0) | |
64 | int uredebug = 0; | 64 | int uredebug = 0; | |
65 | #else | 65 | #else | |
66 | #define DPRINTF(x) | 66 | #define DPRINTF(x) | |
67 | #define DPRINTFN(n, x) | 67 | #define DPRINTFN(n, x) | |
68 | #endif | 68 | #endif | |
69 | 69 | |||
70 | #define ETHER_IS_ZERO(addr) \ | 70 | #define ETHER_IS_ZERO(addr) \ | |
71 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | 71 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | |
72 | 72 | |||
73 | static const struct usb_devno ure_devs[] = { | 73 | static const struct usb_devno ure_devs[] = { | |
74 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8152 }, | 74 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8152 }, | |
75 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8153 } | 75 | { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8153 } | |
76 | }; | 76 | }; | |
77 | 77 | |||
78 | #define URE_BUFSZ (16 * 1024) | 78 | #define URE_BUFSZ (16 * 1024) | |
79 | 79 | |||
80 | static void ure_reset(struct usbnet *); | 80 | static void ure_reset(struct usbnet *); | |
81 | static uint32_t ure_txcsum(struct mbuf *); | 81 | static uint32_t ure_txcsum(struct mbuf *); | |
82 | static int ure_rxcsum(struct ifnet *, struct ure_rxpkt *); | 82 | static int ure_rxcsum(struct ifnet *, struct ure_rxpkt *); | |
83 | static void ure_rtl8152_init(struct usbnet *); | 83 | static void ure_rtl8152_init(struct usbnet *); | |
84 | static void ure_rtl8153_init(struct usbnet *); | 84 | static void ure_rtl8153_init(struct usbnet *); | |
85 | static void ure_disable_teredo(struct usbnet *); | 85 | static void ure_disable_teredo(struct usbnet *); | |
86 | static void ure_init_fifo(struct usbnet *); | 86 | static void ure_init_fifo(struct usbnet *); | |
87 | 87 | |||
88 | static void ure_uno_stop(struct ifnet *, int); | 88 | static void ure_uno_stop(struct ifnet *, int); | |
89 | static void ure_uno_mcast(struct ifnet *); | 89 | static void ure_uno_mcast(struct ifnet *); | |
90 | static int ure_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 90 | static int ure_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
91 | static int ure_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 91 | static int ure_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
92 | static void ure_uno_miibus_statchg(struct ifnet *); | 92 | static void ure_uno_miibus_statchg(struct ifnet *); | |
93 | static unsigned ure_uno_tx_prepare(struct usbnet *, struct mbuf *, | 93 | static unsigned ure_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
94 | struct usbnet_chain *); | 94 | struct usbnet_chain *); | |
95 | static void ure_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | 95 | static void ure_uno_rx_loop(struct usbnet *, struct usbnet_chain *, | |
96 | uint32_t); | 96 | uint32_t); | |
97 | static int ure_uno_init(struct ifnet *); | 97 | static int ure_uno_init(struct ifnet *); | |
98 | 98 | |||
99 | static int ure_match(device_t, cfdata_t, void *); | 99 | static int ure_match(device_t, cfdata_t, void *); | |
100 | static void ure_attach(device_t, device_t, void *); | 100 | static void ure_attach(device_t, device_t, void *); | |
101 | 101 | |||
102 | CFATTACH_DECL_NEW(ure, sizeof(struct usbnet), ure_match, ure_attach, | 102 | CFATTACH_DECL_NEW(ure, sizeof(struct usbnet), ure_match, ure_attach, | |
103 | usbnet_detach, usbnet_activate); | 103 | usbnet_detach, usbnet_activate); | |
104 | 104 | |||
105 | static const struct usbnet_ops ure_ops = { | 105 | static const struct usbnet_ops ure_ops = { | |
106 | .uno_stop = ure_uno_stop, | 106 | .uno_stop = ure_uno_stop, | |
107 | .uno_mcast = ure_uno_mcast, | 107 | .uno_mcast = ure_uno_mcast, | |
108 | .uno_read_reg = ure_uno_mii_read_reg, | 108 | .uno_read_reg = ure_uno_mii_read_reg, | |
109 | .uno_write_reg = ure_uno_mii_write_reg, | 109 | .uno_write_reg = ure_uno_mii_write_reg, | |
110 | .uno_statchg = ure_uno_miibus_statchg, | 110 | .uno_statchg = ure_uno_miibus_statchg, | |
111 | .uno_tx_prepare = ure_uno_tx_prepare, | 111 | .uno_tx_prepare = ure_uno_tx_prepare, | |
112 | .uno_rx_loop = ure_uno_rx_loop, | 112 | .uno_rx_loop = ure_uno_rx_loop, | |
113 | .uno_init = ure_uno_init, | 113 | .uno_init = ure_uno_init, | |
114 | }; | 114 | }; | |
115 | 115 | |||
116 | static int | 116 | static int | |
117 | ure_ctl(struct usbnet *un, uint8_t rw, uint16_t val, uint16_t index, | 117 | ure_ctl(struct usbnet *un, uint8_t rw, uint16_t val, uint16_t index, | |
118 | void *buf, int len) | 118 | void *buf, int len) | |
119 | { | 119 | { | |
120 | usb_device_request_t req; | 120 | usb_device_request_t req; | |
121 | usbd_status err; | 121 | usbd_status err; | |
122 | 122 | |||
123 | if (usbnet_isdying(un)) | 123 | if (usbnet_isdying(un)) | |
124 | return 0; | 124 | return 0; | |
125 | 125 | |||
126 | if (rw == URE_CTL_WRITE) | 126 | if (rw == URE_CTL_WRITE) | |
127 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 127 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
128 | else | 128 | else | |
129 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 129 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
130 | req.bRequest = UR_SET_ADDRESS; | 130 | req.bRequest = UR_SET_ADDRESS; | |
131 | USETW(req.wValue, val); | 131 | USETW(req.wValue, val); | |
132 | USETW(req.wIndex, index); | 132 | USETW(req.wIndex, index); | |
133 | USETW(req.wLength, len); | 133 | USETW(req.wLength, len); | |
134 | 134 | |||
135 | DPRINTFN(5, ("ure_ctl: rw %d, val %04hu, index %04hu, len %d\n", | 135 | DPRINTFN(5, ("ure_ctl: rw %d, val %04hu, index %04hu, len %d\n", | |
136 | rw, val, index, len)); | 136 | rw, val, index, len)); | |
137 | err = usbd_do_request(un->un_udev, &req, buf); | 137 | err = usbd_do_request(un->un_udev, &req, buf); | |
138 | if (err) { | 138 | if (err) { | |
139 | DPRINTF(("ure_ctl: error %d\n", err)); | 139 | DPRINTF(("ure_ctl: error %d\n", err)); | |
140 | if (rw == URE_CTL_READ) | 140 | if (rw == URE_CTL_READ) | |
141 | memset(buf, 0, len); | 141 | memset(buf, 0, len); | |
142 | return -1; | 142 | return -1; | |
143 | } | 143 | } | |
144 | 144 | |||
145 | return 0; | 145 | return 0; | |
146 | } | 146 | } | |
147 | 147 | |||
148 | static int | 148 | static int | |
149 | ure_read_mem(struct usbnet *un, uint16_t addr, uint16_t index, | 149 | ure_read_mem(struct usbnet *un, uint16_t addr, uint16_t index, | |
150 | void *buf, int len) | 150 | void *buf, int len) | |
151 | { | 151 | { | |
152 | return ure_ctl(un, URE_CTL_READ, addr, index, buf, len); | 152 | return ure_ctl(un, URE_CTL_READ, addr, index, buf, len); | |
153 | } | 153 | } | |
154 | 154 | |||
155 | static int | 155 | static int | |
156 | ure_write_mem(struct usbnet *un, uint16_t addr, uint16_t index, | 156 | ure_write_mem(struct usbnet *un, uint16_t addr, uint16_t index, | |
157 | void *buf, int len) | 157 | void *buf, int len) | |
158 | { | 158 | { | |
159 | return ure_ctl(un, URE_CTL_WRITE, addr, index, buf, len); | 159 | return ure_ctl(un, URE_CTL_WRITE, addr, index, buf, len); | |
160 | } | 160 | } | |
161 | 161 | |||
162 | static uint8_t | 162 | static uint8_t | |
163 | ure_read_1(struct usbnet *un, uint16_t reg, uint16_t index) | 163 | ure_read_1(struct usbnet *un, uint16_t reg, uint16_t index) | |
164 | { | 164 | { | |
165 | uint32_t val; | 165 | uint32_t val; | |
166 | uint8_t temp[4]; | 166 | uint8_t temp[4]; | |
167 | uint8_t shift; | 167 | uint8_t shift; | |
168 | 168 | |||
169 | shift = (reg & 3) << 3; | 169 | shift = (reg & 3) << 3; | |
170 | reg &= ~3; | 170 | reg &= ~3; | |
171 | 171 | |||
172 | ure_read_mem(un, reg, index, &temp, 4); | 172 | ure_read_mem(un, reg, index, &temp, 4); | |
173 | val = UGETDW(temp); | 173 | val = UGETDW(temp); | |
174 | val >>= shift; | 174 | val >>= shift; | |
175 | 175 | |||
176 | return val & 0xff; | 176 | return val & 0xff; | |
177 | } | 177 | } | |
178 | 178 | |||
179 | static uint16_t | 179 | static uint16_t | |
180 | ure_read_2(struct usbnet *un, uint16_t reg, uint16_t index) | 180 | ure_read_2(struct usbnet *un, uint16_t reg, uint16_t index) | |
181 | { | 181 | { | |
182 | uint32_t val; | 182 | uint32_t val; | |
183 | uint8_t temp[4]; | 183 | uint8_t temp[4]; | |
184 | uint8_t shift; | 184 | uint8_t shift; | |
185 | 185 | |||
186 | shift = (reg & 2) << 3; | 186 | shift = (reg & 2) << 3; | |
187 | reg &= ~3; | 187 | reg &= ~3; | |
188 | 188 | |||
189 | ure_read_mem(un, reg, index, &temp, 4); | 189 | ure_read_mem(un, reg, index, &temp, 4); | |
190 | val = UGETDW(temp); | 190 | val = UGETDW(temp); | |
191 | val >>= shift; | 191 | val >>= shift; | |
192 | 192 | |||
193 | return val & 0xffff; | 193 | return val & 0xffff; | |
194 | } | 194 | } | |
195 | 195 | |||
196 | static uint32_t | 196 | static uint32_t | |
197 | ure_read_4(struct usbnet *un, uint16_t reg, uint16_t index) | 197 | ure_read_4(struct usbnet *un, uint16_t reg, uint16_t index) | |
198 | { | 198 | { | |
199 | uint8_t temp[4]; | 199 | uint8_t temp[4]; | |
200 | 200 | |||
201 | ure_read_mem(un, reg, index, &temp, 4); | 201 | ure_read_mem(un, reg, index, &temp, 4); | |
202 | return UGETDW(temp); | 202 | return UGETDW(temp); | |
203 | } | 203 | } | |
204 | 204 | |||
205 | static int | 205 | static int | |
206 | ure_write_1(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | 206 | ure_write_1(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | |
207 | { | 207 | { | |
208 | uint16_t byen; | 208 | uint16_t byen; | |
209 | uint8_t temp[4]; | 209 | uint8_t temp[4]; | |
210 | uint8_t shift; | 210 | uint8_t shift; | |
211 | 211 | |||
212 | byen = URE_BYTE_EN_BYTE; | 212 | byen = URE_BYTE_EN_BYTE; | |
213 | shift = reg & 3; | 213 | shift = reg & 3; | |
214 | val &= 0xff; | 214 | val &= 0xff; | |
215 | 215 | |||
216 | if (reg & 3) { | 216 | if (reg & 3) { | |
217 | byen <<= shift; | 217 | byen <<= shift; | |
218 | val <<= (shift << 3); | 218 | val <<= (shift << 3); | |
219 | reg &= ~3; | 219 | reg &= ~3; | |
220 | } | 220 | } | |
221 | 221 | |||
222 | USETDW(temp, val); | 222 | USETDW(temp, val); | |
223 | return ure_write_mem(un, reg, index | byen, &temp, 4); | 223 | return ure_write_mem(un, reg, index | byen, &temp, 4); | |
224 | } | 224 | } | |
225 | 225 | |||
226 | static int | 226 | static int | |
227 | ure_write_2(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | 227 | ure_write_2(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | |
228 | { | 228 | { | |
229 | uint16_t byen; | 229 | uint16_t byen; | |
230 | uint8_t temp[4]; | 230 | uint8_t temp[4]; | |
231 | uint8_t shift; | 231 | uint8_t shift; | |
232 | 232 | |||
233 | byen = URE_BYTE_EN_WORD; | 233 | byen = URE_BYTE_EN_WORD; | |
234 | shift = reg & 2; | 234 | shift = reg & 2; | |
235 | val &= 0xffff; | 235 | val &= 0xffff; | |
236 | 236 | |||
237 | if (reg & 2) { | 237 | if (reg & 2) { | |
238 | byen <<= shift; | 238 | byen <<= shift; | |
239 | val <<= (shift << 3); | 239 | val <<= (shift << 3); | |
240 | reg &= ~3; | 240 | reg &= ~3; | |
241 | } | 241 | } | |
242 | 242 | |||
243 | USETDW(temp, val); | 243 | USETDW(temp, val); | |
244 | return ure_write_mem(un, reg, index | byen, &temp, 4); | 244 | return ure_write_mem(un, reg, index | byen, &temp, 4); | |
245 | } | 245 | } | |
246 | 246 | |||
247 | static int | 247 | static int | |
248 | ure_write_4(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | 248 | ure_write_4(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val) | |
249 | { | 249 | { | |
250 | uint8_t temp[4]; | 250 | uint8_t temp[4]; | |
251 | 251 | |||
252 | USETDW(temp, val); | 252 | USETDW(temp, val); | |
253 | return ure_write_mem(un, reg, index | URE_BYTE_EN_DWORD, &temp, 4); | 253 | return ure_write_mem(un, reg, index | URE_BYTE_EN_DWORD, &temp, 4); | |
254 | } | 254 | } | |
255 | 255 | |||
256 | static uint16_t | 256 | static uint16_t | |
257 | ure_ocp_reg_read(struct usbnet *un, uint16_t addr) | 257 | ure_ocp_reg_read(struct usbnet *un, uint16_t addr) | |
258 | { | 258 | { | |
259 | uint16_t reg; | 259 | uint16_t reg; | |
260 | 260 | |||
261 | ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); | 261 | ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); | |
262 | reg = (addr & 0x0fff) | 0xb000; | 262 | reg = (addr & 0x0fff) | 0xb000; | |
263 | 263 | |||
264 | return ure_read_2(un, reg, URE_MCU_TYPE_PLA); | 264 | return ure_read_2(un, reg, URE_MCU_TYPE_PLA); | |
265 | } | 265 | } | |
266 | 266 | |||
267 | static void | 267 | static void | |
268 | ure_ocp_reg_write(struct usbnet *un, uint16_t addr, uint16_t data) | 268 | ure_ocp_reg_write(struct usbnet *un, uint16_t addr, uint16_t data) | |
269 | { | 269 | { | |
270 | uint16_t reg; | 270 | uint16_t reg; | |
271 | 271 | |||
272 | ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); | 272 | ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000); | |
273 | reg = (addr & 0x0fff) | 0xb000; | 273 | reg = (addr & 0x0fff) | 0xb000; | |
274 | 274 | |||
275 | ure_write_2(un, reg, URE_MCU_TYPE_PLA, data); | 275 | ure_write_2(un, reg, URE_MCU_TYPE_PLA, data); | |
276 | } | 276 | } | |
277 | 277 | |||
278 | static int | 278 | static int | |
279 | ure_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 279 | ure_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
280 | { | 280 | { | |
281 | 281 | |||
282 | if (un->un_phyno != phy) { | 282 | if (un->un_phyno != phy) { | |
283 | *val = 0; | 283 | *val = 0; | |
284 | return EINVAL; | 284 | return EINVAL; | |
285 | } | 285 | } | |
286 | 286 | |||
287 | /* Let the rgephy driver read the URE_PLA_PHYSTATUS register. */ | 287 | /* Let the rgephy driver read the URE_PLA_PHYSTATUS register. */ | |
288 | if (reg == RTK_GMEDIASTAT) { | 288 | if (reg == RTK_GMEDIASTAT) { | |
289 | *val = ure_read_1(un, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA); | 289 | *val = ure_read_1(un, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA); | |
290 | return USBD_NORMAL_COMPLETION; | 290 | return USBD_NORMAL_COMPLETION; | |
291 | } | 291 | } | |
292 | 292 | |||
293 | *val = ure_ocp_reg_read(un, URE_OCP_BASE_MII + reg * 2); | 293 | *val = ure_ocp_reg_read(un, URE_OCP_BASE_MII + reg * 2); | |
294 | 294 | |||
295 | return 0; | 295 | return 0; | |
296 | } | 296 | } | |
297 | 297 | |||
298 | static int | 298 | static int | |
299 | ure_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 299 | ure_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
300 | { | 300 | { | |
301 | 301 | |||
302 | if (un->un_phyno != phy) | 302 | if (un->un_phyno != phy) | |
303 | return EINVAL; | 303 | return EINVAL; | |
304 | 304 | |||
305 | ure_ocp_reg_write(un, URE_OCP_BASE_MII + reg * 2, val); | 305 | ure_ocp_reg_write(un, URE_OCP_BASE_MII + reg * 2, val); | |
306 | 306 | |||
307 | return 0; | 307 | return 0; | |
308 | } | 308 | } | |
309 | 309 | |||
310 | static void | 310 | static void | |
311 | ure_uno_miibus_statchg(struct ifnet *ifp) | 311 | ure_uno_miibus_statchg(struct ifnet *ifp) | |
312 | { | 312 | { | |
313 | struct usbnet * const un = ifp->if_softc; | 313 | struct usbnet * const un = ifp->if_softc; | |
314 | struct mii_data * const mii = usbnet_mii(un); | 314 | struct mii_data * const mii = usbnet_mii(un); | |
315 | 315 | |||
316 | if (usbnet_isdying(un)) | 316 | if (usbnet_isdying(un)) | |
317 | return; | 317 | return; | |
318 | 318 | |||
319 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | 319 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | |
320 | (IFM_ACTIVE | IFM_AVALID)) { | 320 | (IFM_ACTIVE | IFM_AVALID)) { | |
321 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | 321 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | |
322 | case IFM_10_T: | 322 | case IFM_10_T: | |
323 | case IFM_100_TX: | 323 | case IFM_100_TX: | |
324 | usbnet_set_link(un, true); | 324 | usbnet_set_link(un, true); | |
325 | break; | 325 | break; | |
326 | case IFM_1000_T: | 326 | case IFM_1000_T: | |
327 | if ((un->un_flags & URE_FLAG_8152) != 0) | 327 | if ((un->un_flags & URE_FLAG_8152) != 0) | |
328 | break; | 328 | break; | |
329 | usbnet_set_link(un, true); | 329 | usbnet_set_link(un, true); | |
330 | break; | 330 | break; | |
331 | default: | 331 | default: | |
332 | break; | 332 | break; | |
333 | } | 333 | } | |
334 | } | 334 | } | |
335 | } | 335 | } | |
336 | 336 | |||
337 | static void | 337 | static void | |
338 | ure_uno_mcast(struct ifnet *ifp) | 338 | ure_uno_mcast(struct ifnet *ifp) | |
339 | { | 339 | { | |
340 | struct usbnet *un = ifp->if_softc; | 340 | struct usbnet *un = ifp->if_softc; | |
341 | struct ethercom *ec = usbnet_ec(un); | 341 | struct ethercom *ec = usbnet_ec(un); | |
342 | struct ether_multi *enm; | 342 | struct ether_multi *enm; | |
343 | struct ether_multistep step; | 343 | struct ether_multistep step; | |
344 | uint32_t mchash[2] = { 0, 0 }; | 344 | uint32_t mchash[2] = { 0, 0 }; | |
345 | uint32_t h = 0, rxmode; | 345 | uint32_t h = 0, rxmode; | |
346 | 346 | |||
347 | if (usbnet_isdying(un)) | 347 | if (usbnet_isdying(un)) | |
348 | return; | 348 | return; | |
349 | 349 | |||
350 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | 350 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | |
351 | rxmode &= ~(URE_RCR_AAP | URE_RCR_AM); | 351 | rxmode &= ~(URE_RCR_AAP | URE_RCR_AM); | |
352 | /* continue to accept my own DA and bcast frames */ | 352 | /* continue to accept my own DA and bcast frames */ | |
353 | 353 | |||
354 | ETHER_LOCK(ec); | 354 | ETHER_LOCK(ec); | |
355 | if (ifp->if_flags & IFF_PROMISC) { | 355 | if (ifp->if_flags & IFF_PROMISC) { | |
356 | ec->ec_flags |= ETHER_F_ALLMULTI; | 356 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
357 | ETHER_UNLOCK(ec); | 357 | ETHER_UNLOCK(ec); | |
358 | /* run promisc. mode */ | 358 | /* run promisc. mode */ | |
359 | rxmode |= URE_RCR_AM; /* ??? */ | 359 | rxmode |= URE_RCR_AM; /* ??? */ | |
360 | rxmode |= URE_RCR_AAP; | 360 | rxmode |= URE_RCR_AAP; | |
361 | goto update; | 361 | goto update; | |
362 | } | 362 | } | |
363 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 363 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
364 | ETHER_FIRST_MULTI(step, ec, enm); | 364 | ETHER_FIRST_MULTI(step, ec, enm); | |
365 | while (enm != NULL) { | 365 | while (enm != NULL) { | |
366 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 366 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
367 | ec->ec_flags |= ETHER_F_ALLMULTI; | 367 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
368 | ETHER_UNLOCK(ec); | 368 | ETHER_UNLOCK(ec); | |
369 | /* accept all mcast frames */ | 369 | /* accept all mcast frames */ | |
370 | rxmode |= URE_RCR_AM; | 370 | rxmode |= URE_RCR_AM; | |
371 | mchash[0] = mchash[1] = ~0U; /* necessary ?? */ | 371 | mchash[0] = mchash[1] = ~0U; /* necessary ?? */ | |
372 | goto update; | 372 | goto update; | |
373 | } | 373 | } | |
374 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | 374 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | |
375 | mchash[h >> 31] |= 1 << ((h >> 26) & 0x1f); | 375 | mchash[h >> 31] |= 1 << ((h >> 26) & 0x1f); | |
376 | ETHER_NEXT_MULTI(step, enm); | 376 | ETHER_NEXT_MULTI(step, enm); | |
377 | } | 377 | } | |
378 | ETHER_UNLOCK(ec); | 378 | ETHER_UNLOCK(ec); | |
379 | if (h != 0) { | 379 | if (h != 0) { | |
380 | rxmode |= URE_RCR_AM; /* activate mcast hash filter */ | 380 | rxmode |= URE_RCR_AM; /* activate mcast hash filter */ | |
381 | h = bswap32(mchash[0]); | 381 | h = bswap32(mchash[0]); | |
382 | mchash[0] = bswap32(mchash[1]); | 382 | mchash[0] = bswap32(mchash[1]); | |
383 | mchash[1] = h; | 383 | mchash[1] = h; | |
384 | } | 384 | } | |
385 | update: | 385 | update: | |
386 | ure_write_4(un, URE_PLA_MAR0, URE_MCU_TYPE_PLA, mchash[0]); | 386 | ure_write_4(un, URE_PLA_MAR0, URE_MCU_TYPE_PLA, mchash[0]); | |
387 | ure_write_4(un, URE_PLA_MAR4, URE_MCU_TYPE_PLA, mchash[1]); | 387 | ure_write_4(un, URE_PLA_MAR4, URE_MCU_TYPE_PLA, mchash[1]); | |
388 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | 388 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | |
389 | } | 389 | } | |
390 | 390 | |||
391 | static void | 391 | static void | |
392 | ure_reset(struct usbnet *un) | 392 | ure_reset(struct usbnet *un) | |
393 | { | 393 | { | |
394 | int i; | 394 | int i; | |
395 | 395 | |||
396 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST); | 396 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST); | |
397 | 397 | |||
398 | for (i = 0; i < URE_TIMEOUT; i++) { | 398 | for (i = 0; i < URE_TIMEOUT; i++) { | |
399 | if (usbnet_isdying(un)) | 399 | if (usbnet_isdying(un)) | |
400 | return; | 400 | return; | |
401 | if (!(ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) & | 401 | if (!(ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) & | |
402 | URE_CR_RST)) | 402 | URE_CR_RST)) | |
403 | break; | 403 | break; | |
404 | usbd_delay_ms(un->un_udev, 10); | 404 | usbd_delay_ms(un->un_udev, 10); | |
405 | } | 405 | } | |
406 | if (i == URE_TIMEOUT) | 406 | if (i == URE_TIMEOUT) | |
407 | URE_PRINTF(un, "reset never completed\n"); | 407 | URE_PRINTF(un, "reset never completed\n"); | |
408 | } | 408 | } | |
409 | 409 | |||
410 | static int | 410 | static int | |
411 | ure_uno_init(struct ifnet *ifp) | 411 | ure_uno_init(struct ifnet *ifp) | |
412 | { | 412 | { | |
413 | struct usbnet * const un = ifp->if_softc; | 413 | struct usbnet * const un = ifp->if_softc; | |
414 | uint8_t eaddr[8]; | 414 | uint8_t eaddr[8]; | |
415 | 415 | |||
416 | if (usbnet_isdying(un)) | |||
417 | return EIO; | |||
418 | ||||
419 | /* Cancel pending I/O. */ | 416 | /* Cancel pending I/O. */ | |
420 | if (ifp->if_flags & IFF_RUNNING) | 417 | if (ifp->if_flags & IFF_RUNNING) | |
421 | usbnet_stop(un, ifp, 1); | 418 | usbnet_stop(un, ifp, 1); | |
422 | 419 | |||
423 | /* Set MAC address. */ | 420 | /* Set MAC address. */ | |
424 | memset(eaddr, 0, sizeof(eaddr)); | 421 | memset(eaddr, 0, sizeof(eaddr)); | |
425 | memcpy(eaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); | 422 | memcpy(eaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); | |
426 | ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG); | 423 | 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, | 424 | ure_write_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES, | |
428 | eaddr, 8); | 425 | eaddr, 8); | |
429 | ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML); | 426 | ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML); | |
430 | 427 | |||
431 | /* Reset the packet filter. */ | 428 | /* Reset the packet filter. */ | |
432 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | 429 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | |
433 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) & | 430 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) & | |
434 | ~URE_FMC_FCR_MCU_EN); | 431 | ~URE_FMC_FCR_MCU_EN); | |
435 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | 432 | ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA, | |
436 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) | | 433 | ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) | | |
437 | URE_FMC_FCR_MCU_EN); | 434 | URE_FMC_FCR_MCU_EN); | |
438 | 435 | |||
439 | /* Enable transmit and receive. */ | 436 | /* Enable transmit and receive. */ | |
440 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, | 437 | 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 | | 438 | ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) | URE_CR_RE | | |
442 | URE_CR_TE); | 439 | URE_CR_TE); | |
443 | 440 | |||
444 | ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, | 441 | 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) & | 442 | ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) & | |
446 | ~URE_RXDY_GATED_EN); | 443 | ~URE_RXDY_GATED_EN); | |
447 | 444 | |||
448 | return usbnet_init_rx_tx(un); | 445 | return usbnet_init_rx_tx(un); | |
449 | } | 446 | } | |
450 | 447 | |||
451 | static void | 448 | static void | |
452 | ure_uno_stop(struct ifnet *ifp, int disable __unused) | 449 | ure_uno_stop(struct ifnet *ifp, int disable __unused) | |
453 | { | 450 | { | |
454 | struct usbnet * const un = ifp->if_softc; | 451 | struct usbnet * const un = ifp->if_softc; | |
455 | 452 | |||
456 | ure_reset(un); | 453 | ure_reset(un); | |
457 | } | 454 | } | |
458 | 455 | |||
459 | static void | 456 | static void | |
460 | ure_rtl8152_init(struct usbnet *un) | 457 | ure_rtl8152_init(struct usbnet *un) | |
461 | { | 458 | { | |
462 | uint32_t pwrctrl; | 459 | uint32_t pwrctrl; | |
463 | 460 | |||
464 | /* Disable ALDPS. */ | 461 | /* Disable ALDPS. */ | |
465 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | 462 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | |
466 | URE_DIS_SDSAVE); | 463 | URE_DIS_SDSAVE); | |
467 | usbd_delay_ms(un->un_udev, 20); | 464 | usbd_delay_ms(un->un_udev, 20); | |
468 | 465 | |||
469 | if (un->un_flags & URE_FLAG_VER_4C00) { | 466 | if (un->un_flags & URE_FLAG_VER_4C00) { | |
470 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | 467 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | |
471 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | 468 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | |
472 | ~URE_LED_MODE_MASK); | 469 | ~URE_LED_MODE_MASK); | |
473 | } | 470 | } | |
474 | 471 | |||
475 | ure_write_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB, | 472 | ure_write_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB, | |
476 | ure_read_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) & | 473 | ure_read_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) & | |
477 | ~URE_POWER_CUT); | 474 | ~URE_POWER_CUT); | |
478 | ure_write_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB, | 475 | ure_write_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB, | |
479 | ure_read_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) & | 476 | ure_read_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) & | |
480 | ~URE_RESUME_INDICATE); | 477 | ~URE_RESUME_INDICATE); | |
481 | 478 | |||
482 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | 479 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | |
483 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | 480 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | |
484 | URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH); | 481 | URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH); | |
485 | pwrctrl = ure_read_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA); | 482 | pwrctrl = ure_read_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA); | |
486 | pwrctrl &= ~URE_MCU_CLK_RATIO_MASK; | 483 | pwrctrl &= ~URE_MCU_CLK_RATIO_MASK; | |
487 | pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN; | 484 | pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN; | |
488 | ure_write_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl); | 485 | ure_write_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl); | |
489 | ure_write_2(un, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA, | 486 | ure_write_2(un, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA, | |
490 | URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK | | 487 | URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK | | |
491 | URE_SPDWN_LINKCHG_MSK); | 488 | URE_SPDWN_LINKCHG_MSK); | |
492 | 489 | |||
493 | /* Enable Rx aggregation. */ | 490 | /* Enable Rx aggregation. */ | |
494 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | 491 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | |
495 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | 492 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | |
496 | ~URE_RX_AGG_DISABLE); | 493 | ~URE_RX_AGG_DISABLE); | |
497 | 494 | |||
498 | /* Disable ALDPS. */ | 495 | /* Disable ALDPS. */ | |
499 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | 496 | ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA | | |
500 | URE_DIS_SDSAVE); | 497 | URE_DIS_SDSAVE); | |
501 | usbd_delay_ms(un->un_udev, 20); | 498 | usbd_delay_ms(un->un_udev, 20); | |
502 | 499 | |||
503 | ure_init_fifo(un); | 500 | ure_init_fifo(un); | |
504 | 501 | |||
505 | ure_write_1(un, URE_USB_TX_AGG, URE_MCU_TYPE_USB, | 502 | ure_write_1(un, URE_USB_TX_AGG, URE_MCU_TYPE_USB, | |
506 | URE_TX_AGG_MAX_THRESHOLD); | 503 | URE_TX_AGG_MAX_THRESHOLD); | |
507 | ure_write_4(un, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH); | 504 | ure_write_4(un, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH); | |
508 | ure_write_4(un, URE_USB_TX_DMA, URE_MCU_TYPE_USB, | 505 | ure_write_4(un, URE_USB_TX_DMA, URE_MCU_TYPE_USB, | |
509 | URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1); | 506 | URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1); | |
510 | } | 507 | } | |
511 | 508 | |||
512 | static void | 509 | static void | |
513 | ure_rtl8153_init(struct usbnet *un) | 510 | ure_rtl8153_init(struct usbnet *un) | |
514 | { | 511 | { | |
515 | uint16_t val; | 512 | uint16_t val; | |
516 | uint8_t u1u2[8]; | 513 | uint8_t u1u2[8]; | |
517 | int i; | 514 | int i; | |
518 | 515 | |||
519 | /* Disable ALDPS. */ | 516 | /* Disable ALDPS. */ | |
520 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 517 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
521 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | 518 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | |
522 | usbd_delay_ms(un->un_udev, 20); | 519 | usbd_delay_ms(un->un_udev, 20); | |
523 | 520 | |||
524 | memset(u1u2, 0x00, sizeof(u1u2)); | 521 | memset(u1u2, 0x00, sizeof(u1u2)); | |
525 | ure_write_mem(un, URE_USB_TOLERANCE, | 522 | ure_write_mem(un, URE_USB_TOLERANCE, | |
526 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 523 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
527 | 524 | |||
528 | for (i = 0; i < URE_TIMEOUT; i++) { | 525 | for (i = 0; i < URE_TIMEOUT; i++) { | |
529 | if (usbnet_isdying(un)) | 526 | if (usbnet_isdying(un)) | |
530 | return; | 527 | return; | |
531 | if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & | 528 | if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) & | |
532 | URE_AUTOLOAD_DONE) | 529 | URE_AUTOLOAD_DONE) | |
533 | break; | 530 | break; | |
534 | usbd_delay_ms(un->un_udev, 10); | 531 | usbd_delay_ms(un->un_udev, 10); | |
535 | } | 532 | } | |
536 | if (i == URE_TIMEOUT) | 533 | if (i == URE_TIMEOUT) | |
537 | URE_PRINTF(un, "timeout waiting for chip autoload\n"); | 534 | URE_PRINTF(un, "timeout waiting for chip autoload\n"); | |
538 | 535 | |||
539 | for (i = 0; i < URE_TIMEOUT; i++) { | 536 | for (i = 0; i < URE_TIMEOUT; i++) { | |
540 | if (usbnet_isdying(un)) | 537 | if (usbnet_isdying(un)) | |
541 | return; | 538 | return; | |
542 | val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) & | 539 | val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) & | |
543 | URE_PHY_STAT_MASK; | 540 | URE_PHY_STAT_MASK; | |
544 | if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN) | 541 | if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN) | |
545 | break; | 542 | break; | |
546 | usbd_delay_ms(un->un_udev, 10); | 543 | usbd_delay_ms(un->un_udev, 10); | |
547 | } | 544 | } | |
548 | if (i == URE_TIMEOUT) | 545 | if (i == URE_TIMEOUT) | |
549 | URE_PRINTF(un, "timeout waiting for phy to stabilize\n"); | 546 | URE_PRINTF(un, "timeout waiting for phy to stabilize\n"); | |
550 | 547 | |||
551 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, | 548 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, | |
552 | ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB) & | 549 | ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB) & | |
553 | ~URE_U2P3_ENABLE); | 550 | ~URE_U2P3_ENABLE); | |
554 | 551 | |||
555 | if (un->un_flags & URE_FLAG_VER_5C10) { | 552 | if (un->un_flags & URE_FLAG_VER_5C10) { | |
556 | val = ure_read_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB); | 553 | val = ure_read_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB); | |
557 | val &= ~URE_PWD_DN_SCALE_MASK; | 554 | val &= ~URE_PWD_DN_SCALE_MASK; | |
558 | val |= URE_PWD_DN_SCALE(96); | 555 | val |= URE_PWD_DN_SCALE(96); | |
559 | ure_write_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, val); | 556 | ure_write_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, val); | |
560 | 557 | |||
561 | ure_write_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB, | 558 | ure_write_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB, | |
562 | ure_read_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB) | | 559 | ure_read_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB) | | |
563 | URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND); | 560 | URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND); | |
564 | } else if (un->un_flags & URE_FLAG_VER_5C20) { | 561 | } else if (un->un_flags & URE_FLAG_VER_5C20) { | |
565 | ure_write_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA, | 562 | ure_write_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA, | |
566 | ure_read_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA) & | 563 | ure_read_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA) & | |
567 | ~URE_ECM_ALDPS); | 564 | ~URE_ECM_ALDPS); | |
568 | } | 565 | } | |
569 | if (un->un_flags & (URE_FLAG_VER_5C20 | URE_FLAG_VER_5C30)) { | 566 | if (un->un_flags & (URE_FLAG_VER_5C20 | URE_FLAG_VER_5C30)) { | |
570 | val = ure_read_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB); | 567 | val = ure_read_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB); | |
571 | if (ure_read_2(un, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB) == | 568 | if (ure_read_2(un, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB) == | |
572 | 0) | 569 | 0) | |
573 | val &= ~URE_DYNAMIC_BURST; | 570 | val &= ~URE_DYNAMIC_BURST; | |
574 | else | 571 | else | |
575 | val |= URE_DYNAMIC_BURST; | 572 | val |= URE_DYNAMIC_BURST; | |
576 | ure_write_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB, val); | 573 | ure_write_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB, val); | |
577 | } | 574 | } | |
578 | 575 | |||
579 | ure_write_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB, | 576 | ure_write_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB, | |
580 | ure_read_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB) | | 577 | ure_read_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB) | | |
581 | URE_EP4_FULL_FC); | 578 | URE_EP4_FULL_FC); | |
582 | 579 | |||
583 | ure_write_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB, | 580 | ure_write_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB, | |
584 | ure_read_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB) & | 581 | ure_read_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB) & | |
585 | ~URE_TIMER11_EN); | 582 | ~URE_TIMER11_EN); | |
586 | 583 | |||
587 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | 584 | ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, | |
588 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | 585 | ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) & | |
589 | ~URE_LED_MODE_MASK); | 586 | ~URE_LED_MODE_MASK); | |
590 | 587 | |||
591 | if ((un->un_flags & URE_FLAG_VER_5C10) && | 588 | if ((un->un_flags & URE_FLAG_VER_5C10) && | |
592 | un->un_udev->ud_speed != USB_SPEED_SUPER) | 589 | un->un_udev->ud_speed != USB_SPEED_SUPER) | |
593 | val = URE_LPM_TIMER_500MS; | 590 | val = URE_LPM_TIMER_500MS; | |
594 | else | 591 | else | |
595 | val = URE_LPM_TIMER_500US; | 592 | val = URE_LPM_TIMER_500US; | |
596 | ure_write_1(un, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB, | 593 | ure_write_1(un, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB, | |
597 | val | URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM); | 594 | val | URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM); | |
598 | 595 | |||
599 | val = ure_read_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB); | 596 | val = ure_read_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB); | |
600 | val &= ~URE_SEN_VAL_MASK; | 597 | val &= ~URE_SEN_VAL_MASK; | |
601 | val |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE; | 598 | val |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE; | |
602 | ure_write_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, val); | 599 | ure_write_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, val); | |
603 | 600 | |||
604 | ure_write_2(un, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001); | 601 | ure_write_2(un, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001); | |
605 | 602 | |||
606 | ure_write_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, | 603 | ure_write_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, | |
607 | ure_read_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB) & | 604 | ure_read_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB) & | |
608 | ~(URE_PWR_EN | URE_PHASE2_EN)); | 605 | ~(URE_PWR_EN | URE_PHASE2_EN)); | |
609 | ure_write_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB, | 606 | ure_write_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB, | |
610 | ure_read_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB) & | 607 | ure_read_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB) & | |
611 | ~URE_PCUT_STATUS); | 608 | ~URE_PCUT_STATUS); | |
612 | 609 | |||
613 | memset(u1u2, 0xff, sizeof(u1u2)); | 610 | memset(u1u2, 0xff, sizeof(u1u2)); | |
614 | ure_write_mem(un, URE_USB_TOLERANCE, | 611 | ure_write_mem(un, URE_USB_TOLERANCE, | |
615 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 612 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
616 | 613 | |||
617 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, | 614 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, | |
618 | URE_ALDPS_SPDWN_RATIO); | 615 | URE_ALDPS_SPDWN_RATIO); | |
619 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, | 616 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, | |
620 | URE_EEE_SPDWN_RATIO); | 617 | URE_EEE_SPDWN_RATIO); | |
621 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, | 618 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, | |
622 | URE_PKT_AVAIL_SPDWN_EN | URE_SUSPEND_SPDWN_EN | | 619 | URE_PKT_AVAIL_SPDWN_EN | URE_SUSPEND_SPDWN_EN | | |
623 | URE_U1U2_SPDWN_EN | URE_L1_SPDWN_EN); | 620 | URE_U1U2_SPDWN_EN | URE_L1_SPDWN_EN); | |
624 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, | 621 | ure_write_2(un, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, | |
625 | URE_PWRSAVE_SPDWN_EN | URE_RXDV_SPDWN_EN | URE_TX10MIDLE_EN | | 622 | URE_PWRSAVE_SPDWN_EN | URE_RXDV_SPDWN_EN | URE_TX10MIDLE_EN | | |
626 | URE_TP100_SPDWN_EN | URE_TP500_SPDWN_EN | URE_TP1000_SPDWN_EN | | 623 | URE_TP100_SPDWN_EN | URE_TP500_SPDWN_EN | URE_TP1000_SPDWN_EN | | |
627 | URE_EEE_SPDWN_EN); | 624 | URE_EEE_SPDWN_EN); | |
628 | 625 | |||
629 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | 626 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | |
630 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | 627 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | |
631 | val |= URE_U2P3_ENABLE; | 628 | val |= URE_U2P3_ENABLE; | |
632 | else | 629 | else | |
633 | val &= ~URE_U2P3_ENABLE; | 630 | val &= ~URE_U2P3_ENABLE; | |
634 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | 631 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | |
635 | 632 | |||
636 | memset(u1u2, 0x00, sizeof(u1u2)); | 633 | memset(u1u2, 0x00, sizeof(u1u2)); | |
637 | ure_write_mem(un, URE_USB_TOLERANCE, | 634 | ure_write_mem(un, URE_USB_TOLERANCE, | |
638 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 635 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
639 | 636 | |||
640 | /* Disable ALDPS. */ | 637 | /* Disable ALDPS. */ | |
641 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 638 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
642 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | 639 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS); | |
643 | usbd_delay_ms(un->un_udev, 20); | 640 | usbd_delay_ms(un->un_udev, 20); | |
644 | 641 | |||
645 | ure_init_fifo(un); | 642 | ure_init_fifo(un); | |
646 | 643 | |||
647 | /* Enable Rx aggregation. */ | 644 | /* Enable Rx aggregation. */ | |
648 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | 645 | ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, | |
649 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | 646 | ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) & | |
650 | ~URE_RX_AGG_DISABLE); | 647 | ~URE_RX_AGG_DISABLE); | |
651 | 648 | |||
652 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | 649 | val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB); | |
653 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | 650 | if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10))) | |
654 | val |= URE_U2P3_ENABLE; | 651 | val |= URE_U2P3_ENABLE; | |
655 | else | 652 | else | |
656 | val &= ~URE_U2P3_ENABLE; | 653 | val &= ~URE_U2P3_ENABLE; | |
657 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | 654 | ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val); | |
658 | 655 | |||
659 | memset(u1u2, 0xff, sizeof(u1u2)); | 656 | memset(u1u2, 0xff, sizeof(u1u2)); | |
660 | ure_write_mem(un, URE_USB_TOLERANCE, | 657 | ure_write_mem(un, URE_USB_TOLERANCE, | |
661 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | 658 | URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2)); | |
662 | } | 659 | } | |
663 | 660 | |||
664 | static void | 661 | static void | |
665 | ure_disable_teredo(struct usbnet *un) | 662 | ure_disable_teredo(struct usbnet *un) | |
666 | { | 663 | { | |
667 | ure_write_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, | 664 | ure_write_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, | |
668 | ure_read_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) & | 665 | ure_read_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) & | |
669 | ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN)); | 666 | ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN)); | |
670 | ure_write_2(un, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, | 667 | ure_write_2(un, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, | |
671 | URE_WDT6_SET_MODE); | 668 | URE_WDT6_SET_MODE); | |
672 | ure_write_2(un, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0); | 669 | ure_write_2(un, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0); | |
673 | ure_write_4(un, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0); | 670 | ure_write_4(un, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0); | |
674 | } | 671 | } | |
675 | 672 | |||
676 | static void | 673 | static void | |
677 | ure_init_fifo(struct usbnet *un) | 674 | ure_init_fifo(struct usbnet *un) | |
678 | { | 675 | { | |
679 | uint32_t rxmode, rx_fifo1, rx_fifo2; | 676 | uint32_t rxmode, rx_fifo1, rx_fifo2; | |
680 | int i; | 677 | int i; | |
681 | 678 | |||
682 | ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, | 679 | ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, | |
683 | ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) | | 680 | ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) | | |
684 | URE_RXDY_GATED_EN); | 681 | URE_RXDY_GATED_EN); | |
685 | 682 | |||
686 | ure_disable_teredo(un); | 683 | ure_disable_teredo(un); | |
687 | 684 | |||
688 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | 685 | rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA); | |
689 | rxmode &= ~URE_RCR_ACPT_ALL; | 686 | rxmode &= ~URE_RCR_ACPT_ALL; | |
690 | rxmode |= URE_RCR_APM | URE_RCR_AB; /* accept my own DA and bcast */ | 687 | rxmode |= URE_RCR_APM | URE_RCR_AB; /* accept my own DA and bcast */ | |
691 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | 688 | ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode); | |
692 | 689 | |||
693 | if (!(un->un_flags & URE_FLAG_8152)) { | 690 | if (!(un->un_flags & URE_FLAG_8152)) { | |
694 | if (un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10 | | 691 | if (un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10 | | |
695 | URE_FLAG_VER_5C20)) | 692 | URE_FLAG_VER_5C20)) | |
696 | ure_ocp_reg_write(un, URE_OCP_ADC_CFG, | 693 | ure_ocp_reg_write(un, URE_OCP_ADC_CFG, | |
697 | URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L); | 694 | URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L); | |
698 | if (un->un_flags & URE_FLAG_VER_5C00) | 695 | if (un->un_flags & URE_FLAG_VER_5C00) | |
699 | ure_ocp_reg_write(un, URE_OCP_EEE_CFG, | 696 | ure_ocp_reg_write(un, URE_OCP_EEE_CFG, | |
700 | ure_ocp_reg_read(un, URE_OCP_EEE_CFG) & | 697 | ure_ocp_reg_read(un, URE_OCP_EEE_CFG) & | |
701 | ~URE_CTAP_SHORT_EN); | 698 | ~URE_CTAP_SHORT_EN); | |
702 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 699 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
703 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | 700 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | |
704 | URE_EEE_CLKDIV_EN); | 701 | URE_EEE_CLKDIV_EN); | |
705 | ure_ocp_reg_write(un, URE_OCP_DOWN_SPEED, | 702 | ure_ocp_reg_write(un, URE_OCP_DOWN_SPEED, | |
706 | ure_ocp_reg_read(un, URE_OCP_DOWN_SPEED) | | 703 | ure_ocp_reg_read(un, URE_OCP_DOWN_SPEED) | | |
707 | URE_EN_10M_BGOFF); | 704 | URE_EN_10M_BGOFF); | |
708 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | 705 | ure_ocp_reg_write(un, URE_OCP_POWER_CFG, | |
709 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | 706 | ure_ocp_reg_read(un, URE_OCP_POWER_CFG) | | |
710 | URE_EN_10M_PLLOFF); | 707 | URE_EN_10M_PLLOFF); | |
711 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_IMPEDANCE); | 708 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_IMPEDANCE); | |
712 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0b13); | 709 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0b13); | |
713 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | 710 | ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, | |
714 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | 711 | ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) | | |
715 | URE_PFM_PWM_SWITCH); | 712 | URE_PFM_PWM_SWITCH); | |
716 | 713 | |||
717 | /* Enable LPF corner auto tune. */ | 714 | /* Enable LPF corner auto tune. */ | |
718 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_LPF_CFG); | 715 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_LPF_CFG); | |
719 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0xf70f); | 716 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0xf70f); | |
720 | 717 | |||
721 | /* Adjust 10M amplitude. */ | 718 | /* Adjust 10M amplitude. */ | |
722 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP1); | 719 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP1); | |
723 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x00af); | 720 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x00af); | |
724 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP2); | 721 | ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP2); | |
725 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0208); | 722 | ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0208); | |
726 | } | 723 | } | |
727 | 724 | |||
728 | ure_reset(un); | 725 | ure_reset(un); | |
729 | 726 | |||
730 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, 0); | 727 | ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, 0); | |
731 | 728 | |||
732 | ure_write_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, | 729 | ure_write_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, | |
733 | ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | 730 | ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | |
734 | ~URE_NOW_IS_OOB); | 731 | ~URE_NOW_IS_OOB); | |
735 | 732 | |||
736 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | 733 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | |
737 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) & | 734 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) & | |
738 | ~URE_MCU_BORW_EN); | 735 | ~URE_MCU_BORW_EN); | |
739 | for (i = 0; i < URE_TIMEOUT; i++) { | 736 | for (i = 0; i < URE_TIMEOUT; i++) { | |
740 | if (usbnet_isdying(un)) | 737 | if (usbnet_isdying(un)) | |
741 | return; | 738 | return; | |
742 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | 739 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | |
743 | URE_LINK_LIST_READY) | 740 | URE_LINK_LIST_READY) | |
744 | break; | 741 | break; | |
745 | usbd_delay_ms(un->un_udev, 10); | 742 | usbd_delay_ms(un->un_udev, 10); | |
746 | } | 743 | } | |
747 | if (i == URE_TIMEOUT) | 744 | if (i == URE_TIMEOUT) | |
748 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | 745 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | |
749 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | 746 | ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, | |
750 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) | | 747 | ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) | | |
751 | URE_RE_INIT_LL); | 748 | URE_RE_INIT_LL); | |
752 | for (i = 0; i < URE_TIMEOUT; i++) { | 749 | for (i = 0; i < URE_TIMEOUT; i++) { | |
753 | if (usbnet_isdying(un)) | 750 | if (usbnet_isdying(un)) | |
754 | return; | 751 | return; | |
755 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | 752 | if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) & | |
756 | URE_LINK_LIST_READY) | 753 | URE_LINK_LIST_READY) | |
757 | break; | 754 | break; | |
758 | usbd_delay_ms(un->un_udev, 10); | 755 | usbd_delay_ms(un->un_udev, 10); | |
759 | } | 756 | } | |
760 | if (i == URE_TIMEOUT) | 757 | if (i == URE_TIMEOUT) | |
761 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | 758 | URE_PRINTF(un, "timeout waiting for OOB control\n"); | |
762 | 759 | |||
763 | ure_write_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA, | 760 | ure_write_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA, | |
764 | ure_read_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA) & | 761 | ure_read_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA) & | |
765 | ~URE_CPCR_RX_VLAN); | 762 | ~URE_CPCR_RX_VLAN); | |
766 | ure_write_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA, | 763 | ure_write_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA, | |
767 | ure_read_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA) | | 764 | ure_read_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA) | | |
768 | URE_TCR0_AUTO_FIFO); | 765 | URE_TCR0_AUTO_FIFO); | |
769 | 766 | |||
770 | /* Configure Rx FIFO threshold and coalescing. */ | 767 | /* Configure Rx FIFO threshold and coalescing. */ | |
771 | ure_write_4(un, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA, | 768 | ure_write_4(un, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA, | |
772 | URE_RXFIFO_THR1_NORMAL); | 769 | URE_RXFIFO_THR1_NORMAL); | |
773 | if (un->un_udev->ud_speed == USB_SPEED_FULL) { | 770 | if (un->un_udev->ud_speed == USB_SPEED_FULL) { | |
774 | rx_fifo1 = URE_RXFIFO_THR2_FULL; | 771 | rx_fifo1 = URE_RXFIFO_THR2_FULL; | |
775 | rx_fifo2 = URE_RXFIFO_THR3_FULL; | 772 | rx_fifo2 = URE_RXFIFO_THR3_FULL; | |
776 | } else { | 773 | } else { | |
777 | rx_fifo1 = URE_RXFIFO_THR2_HIGH; | 774 | rx_fifo1 = URE_RXFIFO_THR2_HIGH; | |
778 | rx_fifo2 = URE_RXFIFO_THR3_HIGH; | 775 | rx_fifo2 = URE_RXFIFO_THR3_HIGH; | |
779 | } | 776 | } | |
780 | ure_write_4(un, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1); | 777 | ure_write_4(un, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1); | |
781 | ure_write_4(un, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2); | 778 | ure_write_4(un, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2); | |
782 | 779 | |||
783 | /* Configure Tx FIFO threshold. */ | 780 | /* Configure Tx FIFO threshold. */ | |
784 | ure_write_4(un, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, | 781 | ure_write_4(un, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, | |
785 | URE_TXFIFO_THR_NORMAL); | 782 | URE_TXFIFO_THR_NORMAL); | |
786 | } | 783 | } | |
787 | 784 | |||
788 | static int | 785 | static int | |
789 | ure_match(device_t parent, cfdata_t match, void *aux) | 786 | ure_match(device_t parent, cfdata_t match, void *aux) | |
790 | { | 787 | { | |
791 | struct usb_attach_arg *uaa = aux; | 788 | struct usb_attach_arg *uaa = aux; | |
792 | 789 | |||
793 | return usb_lookup(ure_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 790 | return usb_lookup(ure_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
794 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 791 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
795 | } | 792 | } | |
796 | 793 | |||
797 | static void | 794 | static void | |
798 | ure_attach(device_t parent, device_t self, void *aux) | 795 | ure_attach(device_t parent, device_t self, void *aux) | |
799 | { | 796 | { | |
800 | USBNET_MII_DECL_DEFAULT(unm); | 797 | USBNET_MII_DECL_DEFAULT(unm); | |
801 | struct usbnet * const un = device_private(self); | 798 | struct usbnet * const un = device_private(self); | |
802 | struct usb_attach_arg *uaa = aux; | 799 | struct usb_attach_arg *uaa = aux; | |
803 | struct usbd_device *dev = uaa->uaa_device; | 800 | struct usbd_device *dev = uaa->uaa_device; | |
804 | usb_interface_descriptor_t *id; | 801 | usb_interface_descriptor_t *id; | |
805 | usb_endpoint_descriptor_t *ed; | 802 | usb_endpoint_descriptor_t *ed; | |
806 | int error, i; | 803 | int error, i; | |
807 | uint16_t ver; | 804 | uint16_t ver; | |
808 | uint8_t eaddr[8]; /* 2byte padded */ | 805 | uint8_t eaddr[8]; /* 2byte padded */ | |
809 | char *devinfop; | 806 | char *devinfop; | |
810 | uint32_t maclo, machi; | 807 | uint32_t maclo, machi; | |
811 | 808 | |||
812 | aprint_naive("\n"); | 809 | aprint_naive("\n"); | |
813 | aprint_normal("\n"); | 810 | aprint_normal("\n"); | |
814 | devinfop = usbd_devinfo_alloc(dev, 0); | 811 | devinfop = usbd_devinfo_alloc(dev, 0); | |
815 | aprint_normal_dev(self, "%s\n", devinfop); | 812 | aprint_normal_dev(self, "%s\n", devinfop); | |
816 | usbd_devinfo_free(devinfop); | 813 | usbd_devinfo_free(devinfop); | |
817 | 814 | |||
818 | un->un_dev = self; | 815 | un->un_dev = self; | |
819 | un->un_udev = dev; | 816 | un->un_udev = dev; | |
820 | un->un_sc = un; | 817 | un->un_sc = un; | |
821 | un->un_ops = &ure_ops; | 818 | un->un_ops = &ure_ops; | |
822 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 819 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
823 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 820 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
824 | un->un_rx_list_cnt = URE_RX_LIST_CNT; | 821 | un->un_rx_list_cnt = URE_RX_LIST_CNT; | |
825 | un->un_tx_list_cnt = URE_TX_LIST_CNT; | 822 | un->un_tx_list_cnt = URE_TX_LIST_CNT; | |
826 | un->un_rx_bufsz = URE_BUFSZ; | 823 | un->un_rx_bufsz = URE_BUFSZ; | |
827 | un->un_tx_bufsz = URE_BUFSZ; | 824 | un->un_tx_bufsz = URE_BUFSZ; | |
828 | 825 | |||
829 | #define URE_CONFIG_NO 1 /* XXX */ | 826 | #define URE_CONFIG_NO 1 /* XXX */ | |
830 | error = usbd_set_config_no(dev, URE_CONFIG_NO, 1); | 827 | error = usbd_set_config_no(dev, URE_CONFIG_NO, 1); | |
831 | if (error) { | 828 | if (error) { | |
832 | aprint_error_dev(self, "failed to set configuration: %s\n", | 829 | aprint_error_dev(self, "failed to set configuration: %s\n", | |
833 | usbd_errstr(error)); | 830 | usbd_errstr(error)); | |
834 | return; /* XXX */ | 831 | return; /* XXX */ | |
835 | } | 832 | } | |
836 | 833 | |||
837 | if (uaa->uaa_product == USB_PRODUCT_REALTEK_RTL8152) | 834 | if (uaa->uaa_product == USB_PRODUCT_REALTEK_RTL8152) | |
838 | un->un_flags |= URE_FLAG_8152; | 835 | un->un_flags |= URE_FLAG_8152; | |
839 | 836 | |||
840 | #define URE_IFACE_IDX 0 /* XXX */ | 837 | #define URE_IFACE_IDX 0 /* XXX */ | |
841 | error = usbd_device2interface_handle(dev, URE_IFACE_IDX, &un->un_iface); | 838 | error = usbd_device2interface_handle(dev, URE_IFACE_IDX, &un->un_iface); | |
842 | if (error) { | 839 | if (error) { | |
843 | aprint_error_dev(self, "failed to get interface handle: %s\n", | 840 | aprint_error_dev(self, "failed to get interface handle: %s\n", | |
844 | usbd_errstr(error)); | 841 | usbd_errstr(error)); | |
845 | return; /* XXX */ | 842 | return; /* XXX */ | |
846 | } | 843 | } | |
847 | 844 | |||
848 | id = usbd_get_interface_descriptor(un->un_iface); | 845 | id = usbd_get_interface_descriptor(un->un_iface); | |
849 | for (i = 0; i < id->bNumEndpoints; i++) { | 846 | for (i = 0; i < id->bNumEndpoints; i++) { | |
850 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 847 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
851 | if (ed == NULL) { | 848 | if (ed == NULL) { | |
852 | aprint_error_dev(self, "couldn't get ep %d\n", i); | 849 | aprint_error_dev(self, "couldn't get ep %d\n", i); | |
853 | return; /* XXX */ | 850 | return; /* XXX */ | |
854 | } | 851 | } | |
855 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 852 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
856 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 853 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
857 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 854 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
858 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 855 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
859 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 856 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
860 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 857 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
861 | } | 858 | } | |
862 | } | 859 | } | |
863 | 860 | |||
864 | /* Set these up now for ure_ctl(). */ | 861 | /* Set these up now for ure_ctl(). */ | |
865 | usbnet_attach(un, "uredet"); | 862 | usbnet_attach(un, "uredet"); | |
866 | 863 | |||
867 | un->un_phyno = 0; | 864 | un->un_phyno = 0; | |
868 | 865 | |||
869 | ver = ure_read_2(un, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK; | 866 | ver = ure_read_2(un, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK; | |
870 | switch (ver) { | 867 | switch (ver) { | |
871 | case 0x4c00: | 868 | case 0x4c00: | |
872 | un->un_flags |= URE_FLAG_VER_4C00; | 869 | un->un_flags |= URE_FLAG_VER_4C00; | |
873 | break; | 870 | break; | |
874 | case 0x4c10: | 871 | case 0x4c10: | |
875 | un->un_flags |= URE_FLAG_VER_4C10; | 872 | un->un_flags |= URE_FLAG_VER_4C10; | |
876 | break; | 873 | break; | |
877 | case 0x5c00: | 874 | case 0x5c00: | |
878 | un->un_flags |= URE_FLAG_VER_5C00; | 875 | un->un_flags |= URE_FLAG_VER_5C00; | |
879 | break; | 876 | break; | |
880 | case 0x5c10: | 877 | case 0x5c10: | |
881 | un->un_flags |= URE_FLAG_VER_5C10; | 878 | un->un_flags |= URE_FLAG_VER_5C10; | |
882 | break; | 879 | break; | |
883 | case 0x5c20: | 880 | case 0x5c20: | |
884 | un->un_flags |= URE_FLAG_VER_5C20; | 881 | un->un_flags |= URE_FLAG_VER_5C20; | |
885 | break; | 882 | break; | |
886 | case 0x5c30: | 883 | case 0x5c30: | |
887 | un->un_flags |= URE_FLAG_VER_5C30; | 884 | un->un_flags |= URE_FLAG_VER_5C30; | |
888 | break; | 885 | break; | |
889 | default: | 886 | default: | |
890 | /* fake addr? or just fail? */ | 887 | /* fake addr? or just fail? */ | |
891 | break; | 888 | break; | |
892 | } | 889 | } | |
893 | aprint_normal_dev(self, "RTL%d %sver %04x\n", | 890 | aprint_normal_dev(self, "RTL%d %sver %04x\n", | |
894 | (un->un_flags & URE_FLAG_8152) ? 8152 : 8153, | 891 | (un->un_flags & URE_FLAG_8152) ? 8152 : 8153, | |
895 | (un->un_flags != 0) ? "" : "unknown ", | 892 | (un->un_flags != 0) ? "" : "unknown ", | |
896 | ver); | 893 | ver); | |
897 | 894 | |||
898 | if (un->un_flags & URE_FLAG_8152) | 895 | if (un->un_flags & URE_FLAG_8152) | |
899 | ure_rtl8152_init(un); | 896 | ure_rtl8152_init(un); | |
900 | else | 897 | else | |
901 | ure_rtl8153_init(un); | 898 | ure_rtl8153_init(un); | |
902 | 899 | |||
903 | if ((un->un_flags & URE_FLAG_VER_4C00) || | 900 | if ((un->un_flags & URE_FLAG_VER_4C00) || | |
904 | (un->un_flags & URE_FLAG_VER_4C10)) | 901 | (un->un_flags & URE_FLAG_VER_4C10)) | |
905 | ure_read_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA, eaddr, | 902 | ure_read_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA, eaddr, | |
906 | sizeof(eaddr)); | 903 | sizeof(eaddr)); | |
907 | else | 904 | else | |
908 | ure_read_mem(un, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, eaddr, | 905 | ure_read_mem(un, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, eaddr, | |
909 | sizeof(eaddr)); | 906 | sizeof(eaddr)); | |
910 | if (ETHER_IS_ZERO(eaddr)) { | 907 | if (ETHER_IS_ZERO(eaddr)) { | |
911 | maclo = 0x00f2 | (cprng_strong32() & 0xffff0000); | 908 | maclo = 0x00f2 | (cprng_strong32() & 0xffff0000); | |
912 | machi = cprng_strong32() & 0xffff; | 909 | machi = cprng_strong32() & 0xffff; | |
913 | eaddr[0] = maclo & 0xff; | 910 | eaddr[0] = maclo & 0xff; | |
914 | eaddr[1] = (maclo >> 8) & 0xff; | 911 | eaddr[1] = (maclo >> 8) & 0xff; | |
915 | eaddr[2] = (maclo >> 16) & 0xff; | 912 | eaddr[2] = (maclo >> 16) & 0xff; | |
916 | eaddr[3] = (maclo >> 24) & 0xff; | 913 | eaddr[3] = (maclo >> 24) & 0xff; | |
917 | eaddr[4] = machi & 0xff; | 914 | eaddr[4] = machi & 0xff; | |
918 | eaddr[5] = (machi >> 8) & 0xff; | 915 | eaddr[5] = (machi >> 8) & 0xff; | |
919 | } | 916 | } | |
920 | memcpy(un->un_eaddr, eaddr, sizeof(un->un_eaddr)); | 917 | memcpy(un->un_eaddr, eaddr, sizeof(un->un_eaddr)); | |
921 | 918 | |||
922 | struct ifnet *ifp = usbnet_ifp(un); | 919 | struct ifnet *ifp = usbnet_ifp(un); | |
923 | 920 | |||
924 | /* | 921 | /* | |
925 | * We don't support TSOv4 and v6 for now, that are required to | 922 | * We don't support TSOv4 and v6 for now, that are required to | |
926 | * be handled in software for some cases. | 923 | * be handled in software for some cases. | |
927 | */ | 924 | */ | |
928 | ifp->if_capabilities = IFCAP_CSUM_IPv4_Tx | | 925 | ifp->if_capabilities = IFCAP_CSUM_IPv4_Tx | | |
929 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx; | 926 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx; | |
930 | #ifdef INET6 | 927 | #ifdef INET6 | |
931 | ifp->if_capabilities |= IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx; | 928 | ifp->if_capabilities |= IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx; | |
932 | #endif | 929 | #endif | |
933 | if (un->un_flags & ~URE_FLAG_VER_4C00) { | 930 | if (un->un_flags & ~URE_FLAG_VER_4C00) { | |
934 | ifp->if_capabilities |= IFCAP_CSUM_IPv4_Rx | | 931 | ifp->if_capabilities |= IFCAP_CSUM_IPv4_Rx | | |
935 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | 932 | IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | |
936 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; | 933 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx; | |
937 | } | 934 | } | |
938 | struct ethercom *ec = usbnet_ec(un); | 935 | struct ethercom *ec = usbnet_ec(un); | |
939 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | 936 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | |
940 | #ifdef notyet | 937 | #ifdef notyet | |
941 | ec->ec_capabilities |= ETHERCAP_JUMBO_MTU; | 938 | ec->ec_capabilities |= ETHERCAP_JUMBO_MTU; | |
942 | #endif | 939 | #endif | |
943 | 940 | |||
944 | unm.un_mii_phyloc = un->un_phyno; | 941 | unm.un_mii_phyloc = un->un_phyno; | |
945 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 942 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
946 | 0, &unm); | 943 | 0, &unm); | |
947 | } | 944 | } | |
948 | 945 | |||
949 | static void | 946 | static void | |
950 | ure_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 947 | ure_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
951 | { | 948 | { | |
952 | struct ifnet *ifp = usbnet_ifp(un); | 949 | struct ifnet *ifp = usbnet_ifp(un); | |
953 | uint8_t *buf = c->unc_buf; | 950 | uint8_t *buf = c->unc_buf; | |
954 | uint16_t pkt_len = 0; | 951 | uint16_t pkt_len = 0; | |
955 | uint16_t pkt_count = 0; | 952 | uint16_t pkt_count = 0; | |
956 | struct ure_rxpkt rxhdr; | 953 | struct ure_rxpkt rxhdr; | |
957 | 954 | |||
958 | do { | 955 | do { | |
959 | if (total_len < sizeof(rxhdr)) { | 956 | if (total_len < sizeof(rxhdr)) { | |
960 | DPRINTF(("too few bytes left for a packet header\n")); | 957 | DPRINTF(("too few bytes left for a packet header\n")); | |
961 | if_statinc(ifp, if_ierrors); | 958 | if_statinc(ifp, if_ierrors); | |
962 | return; | 959 | return; | |
963 | } | 960 | } | |
964 | 961 | |||
965 | buf += roundup(pkt_len, 8); | 962 | buf += roundup(pkt_len, 8); | |
966 | 963 | |||
967 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | 964 | memcpy(&rxhdr, buf, sizeof(rxhdr)); | |
968 | total_len -= sizeof(rxhdr); | 965 | total_len -= sizeof(rxhdr); | |
969 | 966 | |||
970 | pkt_len = le32toh(rxhdr.ure_pktlen) & URE_RXPKT_LEN_MASK; | 967 | pkt_len = le32toh(rxhdr.ure_pktlen) & URE_RXPKT_LEN_MASK; | |
971 | DPRINTFN(4, ("next packet is %d bytes\n", pkt_len)); | 968 | DPRINTFN(4, ("next packet is %d bytes\n", pkt_len)); | |
972 | if (pkt_len > total_len) { | 969 | if (pkt_len > total_len) { | |
973 | DPRINTF(("not enough bytes left for next packet\n")); | 970 | DPRINTF(("not enough bytes left for next packet\n")); | |
974 | if_statinc(ifp, if_ierrors); | 971 | if_statinc(ifp, if_ierrors); | |
975 | return; | 972 | return; | |
976 | } | 973 | } | |
977 | 974 | |||
978 | total_len -= roundup(pkt_len, 8); | 975 | total_len -= roundup(pkt_len, 8); | |
979 | buf += sizeof(rxhdr); | 976 | buf += sizeof(rxhdr); | |
980 | 977 | |||
981 | usbnet_enqueue(un, buf, pkt_len - ETHER_CRC_LEN, | 978 | usbnet_enqueue(un, buf, pkt_len - ETHER_CRC_LEN, | |
982 | ure_rxcsum(ifp, &rxhdr), 0, 0); | 979 | ure_rxcsum(ifp, &rxhdr), 0, 0); | |
983 | 980 | |||
984 | pkt_count++; | 981 | pkt_count++; | |
985 | 982 | |||
986 | } while (total_len > 0); | 983 | } while (total_len > 0); | |
987 | 984 | |||
988 | if (pkt_count) | 985 | if (pkt_count) | |
989 | rnd_add_uint32(usbnet_rndsrc(un), pkt_count); | 986 | rnd_add_uint32(usbnet_rndsrc(un), pkt_count); | |
990 | } | 987 | } | |
991 | 988 | |||
992 | static int | 989 | static int | |
993 | ure_rxcsum(struct ifnet *ifp, struct ure_rxpkt *rp) | 990 | ure_rxcsum(struct ifnet *ifp, struct ure_rxpkt *rp) | |
994 | { | 991 | { | |
995 | int enabled = ifp->if_csum_flags_rx, flags = 0; | 992 | int enabled = ifp->if_csum_flags_rx, flags = 0; | |
996 | uint32_t csum, misc; | 993 | uint32_t csum, misc; | |
997 | 994 | |||
998 | if (enabled == 0) | 995 | if (enabled == 0) | |
999 | return 0; | 996 | return 0; | |
1000 | 997 | |||
1001 | csum = le32toh(rp->ure_csum); | 998 | csum = le32toh(rp->ure_csum); | |
1002 | misc = le32toh(rp->ure_misc); | 999 | misc = le32toh(rp->ure_misc); | |
1003 | 1000 | |||
1004 | if (csum & URE_RXPKT_IPV4_CS) { | 1001 | if (csum & URE_RXPKT_IPV4_CS) { | |
1005 | flags |= M_CSUM_IPv4; | 1002 | flags |= M_CSUM_IPv4; | |
1006 | if (csum & URE_RXPKT_TCP_CS) | 1003 | if (csum & URE_RXPKT_TCP_CS) | |
1007 | flags |= M_CSUM_TCPv4; | 1004 | flags |= M_CSUM_TCPv4; | |
1008 | if (csum & URE_RXPKT_UDP_CS) | 1005 | if (csum & URE_RXPKT_UDP_CS) | |
1009 | flags |= M_CSUM_UDPv4; | 1006 | flags |= M_CSUM_UDPv4; | |
1010 | } else if (csum & URE_RXPKT_IPV6_CS) { | 1007 | } else if (csum & URE_RXPKT_IPV6_CS) { | |
1011 | flags = 0; | 1008 | flags = 0; | |
1012 | if (csum & URE_RXPKT_TCP_CS) | 1009 | if (csum & URE_RXPKT_TCP_CS) | |
1013 | flags |= M_CSUM_TCPv6; | 1010 | flags |= M_CSUM_TCPv6; | |
1014 | if (csum & URE_RXPKT_UDP_CS) | 1011 | if (csum & URE_RXPKT_UDP_CS) | |
1015 | flags |= M_CSUM_UDPv6; | 1012 | flags |= M_CSUM_UDPv6; | |
1016 | } | 1013 | } | |
1017 | 1014 | |||
1018 | flags &= enabled; | 1015 | flags &= enabled; | |
1019 | if (__predict_false((flags & M_CSUM_IPv4) && | 1016 | if (__predict_false((flags & M_CSUM_IPv4) && | |
1020 | (misc & URE_RXPKT_IP_F))) | 1017 | (misc & URE_RXPKT_IP_F))) | |
1021 | flags |= M_CSUM_IPv4_BAD; | 1018 | flags |= M_CSUM_IPv4_BAD; | |
1022 | if (__predict_false( | 1019 | if (__predict_false( | |
1023 | ((flags & (M_CSUM_TCPv4 | M_CSUM_TCPv6)) && (misc & URE_RXPKT_TCP_F)) | 1020 | ((flags & (M_CSUM_TCPv4 | M_CSUM_TCPv6)) && (misc & URE_RXPKT_TCP_F)) | |
1024 | || ((flags & (M_CSUM_UDPv4 | M_CSUM_UDPv6)) && (misc & URE_RXPKT_UDP_F)) | 1021 | || ((flags & (M_CSUM_UDPv4 | M_CSUM_UDPv6)) && (misc & URE_RXPKT_UDP_F)) | |
1025 | )) | 1022 | )) | |
1026 | flags |= M_CSUM_TCP_UDP_BAD; | 1023 | flags |= M_CSUM_TCP_UDP_BAD; | |
1027 | 1024 | |||
1028 | return flags; | 1025 | return flags; | |
1029 | } | 1026 | } | |
1030 | 1027 | |||
1031 | static unsigned | 1028 | static unsigned | |
1032 | ure_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 1029 | ure_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
1033 | { | 1030 | { | |
1034 | struct ure_txpkt txhdr; | 1031 | struct ure_txpkt txhdr; | |
1035 | uint32_t frm_len = 0; | 1032 | uint32_t frm_len = 0; | |
1036 | uint8_t *buf = c->unc_buf; | 1033 | uint8_t *buf = c->unc_buf; | |
1037 | 1034 | |||
1038 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(txhdr)) | 1035 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(txhdr)) | |
1039 | return 0; | 1036 | return 0; | |
1040 | 1037 | |||
1041 | /* header */ | 1038 | /* header */ | |
1042 | txhdr.ure_pktlen = htole32(m->m_pkthdr.len | URE_TXPKT_TX_FS | | 1039 | txhdr.ure_pktlen = htole32(m->m_pkthdr.len | URE_TXPKT_TX_FS | | |
1043 | URE_TXPKT_TX_LS); | 1040 | URE_TXPKT_TX_LS); | |
1044 | txhdr.ure_csum = htole32(ure_txcsum(m)); | 1041 | txhdr.ure_csum = htole32(ure_txcsum(m)); | |
1045 | memcpy(buf, &txhdr, sizeof(txhdr)); | 1042 | memcpy(buf, &txhdr, sizeof(txhdr)); | |
1046 | buf += sizeof(txhdr); | 1043 | buf += sizeof(txhdr); | |
1047 | frm_len = sizeof(txhdr); | 1044 | frm_len = sizeof(txhdr); | |
1048 | 1045 | |||
1049 | /* packet */ | 1046 | /* packet */ | |
1050 | m_copydata(m, 0, m->m_pkthdr.len, buf); | 1047 | m_copydata(m, 0, m->m_pkthdr.len, buf); | |
1051 | frm_len += m->m_pkthdr.len; | 1048 | frm_len += m->m_pkthdr.len; | |
1052 | 1049 | |||
1053 | DPRINTFN(2, ("tx %d bytes\n", frm_len)); | 1050 | DPRINTFN(2, ("tx %d bytes\n", frm_len)); | |
1054 | 1051 | |||
1055 | return frm_len; | 1052 | return frm_len; | |
1056 | } | 1053 | } | |
1057 | 1054 | |||
1058 | /* | 1055 | /* | |
1059 | * We need to calculate L4 checksum in software, if the offset of | 1056 | * We need to calculate L4 checksum in software, if the offset of | |
1060 | * L4 header is larger than 0x7ff = 2047. | 1057 | * L4 header is larger than 0x7ff = 2047. | |
1061 | */ | 1058 | */ | |
1062 | static uint32_t | 1059 | static uint32_t | |
1063 | ure_txcsum(struct mbuf *m) | 1060 | ure_txcsum(struct mbuf *m) | |
1064 | { | 1061 | { | |
1065 | struct ether_header *eh; | 1062 | struct ether_header *eh; | |
1066 | int flags = m->m_pkthdr.csum_flags; | 1063 | int flags = m->m_pkthdr.csum_flags; | |
1067 | uint32_t data = m->m_pkthdr.csum_data; | 1064 | uint32_t data = m->m_pkthdr.csum_data; | |
1068 | uint32_t reg = 0; | 1065 | uint32_t reg = 0; | |
1069 | int l3off, l4off; | 1066 | int l3off, l4off; | |
1070 | uint16_t type; | 1067 | uint16_t type; | |
1071 | 1068 | |||
1072 | if (flags == 0) | 1069 | if (flags == 0) | |
1073 | return 0; | 1070 | return 0; | |
1074 | 1071 | |||
1075 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | 1072 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | |
1076 | eh = mtod(m, struct ether_header *); | 1073 | eh = mtod(m, struct ether_header *); | |
1077 | type = eh->ether_type; | 1074 | type = eh->ether_type; | |
1078 | } else | 1075 | } else | |
1079 | m_copydata(m, offsetof(struct ether_header, ether_type), | 1076 | m_copydata(m, offsetof(struct ether_header, ether_type), | |
1080 | sizeof(type), &type); | 1077 | sizeof(type), &type); | |
1081 | switch (type = htons(type)) { | 1078 | switch (type = htons(type)) { | |
1082 | case ETHERTYPE_IP: | 1079 | case ETHERTYPE_IP: | |
1083 | case ETHERTYPE_IPV6: | 1080 | case ETHERTYPE_IPV6: | |
1084 | l3off = ETHER_HDR_LEN; | 1081 | l3off = ETHER_HDR_LEN; | |
1085 | break; | 1082 | break; | |
1086 | case ETHERTYPE_VLAN: | 1083 | case ETHERTYPE_VLAN: | |
1087 | l3off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | 1084 | l3off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | |
1088 | break; | 1085 | break; | |
1089 | default: | 1086 | default: | |
1090 | return 0; | 1087 | return 0; | |
1091 | } | 1088 | } | |
1092 | 1089 | |||
1093 | if (flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) { | 1090 | if (flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) { | |
1094 | l4off = l3off + M_CSUM_DATA_IPv4_IPHL(data); | 1091 | l4off = l3off + M_CSUM_DATA_IPv4_IPHL(data); | |
1095 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | 1092 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | |
1096 | in_undefer_cksum(m, l3off, flags); | 1093 | in_undefer_cksum(m, l3off, flags); | |
1097 | return 0; | 1094 | return 0; | |
1098 | } | 1095 | } | |
1099 | reg |= URE_TXPKT_IPV4_CS; | 1096 | reg |= URE_TXPKT_IPV4_CS; | |
1100 | if (flags & M_CSUM_TCPv4) | 1097 | if (flags & M_CSUM_TCPv4) | |
1101 | reg |= URE_TXPKT_TCP_CS; | 1098 | reg |= URE_TXPKT_TCP_CS; | |
1102 | else | 1099 | else | |
1103 | reg |= URE_TXPKT_UDP_CS; | 1100 | reg |= URE_TXPKT_UDP_CS; | |
1104 | reg |= l4off << URE_L4_OFFSET_SHIFT; | 1101 | reg |= l4off << URE_L4_OFFSET_SHIFT; | |
1105 | } | 1102 | } | |
1106 | #ifdef INET6 | 1103 | #ifdef INET6 | |
1107 | else if (flags & (M_CSUM_TCPv6 | M_CSUM_UDPv6)) { | 1104 | else if (flags & (M_CSUM_TCPv6 | M_CSUM_UDPv6)) { | |
1108 | l4off = l3off + M_CSUM_DATA_IPv6_IPHL(data); | 1105 | l4off = l3off + M_CSUM_DATA_IPv6_IPHL(data); | |
1109 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | 1106 | if (__predict_false(l4off > URE_L4_OFFSET_MAX)) { | |
1110 | in6_undefer_cksum(m, l3off, flags); | 1107 | in6_undefer_cksum(m, l3off, flags); | |
1111 | return 0; | 1108 | return 0; | |
1112 | } | 1109 | } | |
1113 | reg |= URE_TXPKT_IPV6_CS; | 1110 | reg |= URE_TXPKT_IPV6_CS; | |
1114 | if (flags & M_CSUM_TCPv6) | 1111 | if (flags & M_CSUM_TCPv6) | |
1115 | reg |= URE_TXPKT_TCP_CS; | 1112 | reg |= URE_TXPKT_TCP_CS; | |
1116 | else | 1113 | else | |
1117 | reg |= URE_TXPKT_UDP_CS; | 1114 | reg |= URE_TXPKT_UDP_CS; | |
1118 | reg |= l4off << URE_L4_OFFSET_SHIFT; | 1115 | reg |= l4off << URE_L4_OFFSET_SHIFT; | |
1119 | } | 1116 | } | |
1120 | #endif | 1117 | #endif | |
1121 | else if (flags & M_CSUM_IPv4) | 1118 | else if (flags & M_CSUM_IPv4) | |
1122 | reg |= URE_TXPKT_IPV4_CS; | 1119 | reg |= URE_TXPKT_IPV4_CS; | |
1123 | 1120 | |||
1124 | return reg; | 1121 | return reg; | |
1125 | } | 1122 | } | |
1126 | 1123 | |||
1127 | #ifdef _MODULE | 1124 | #ifdef _MODULE | |
1128 | #include "ioconf.c" | 1125 | #include "ioconf.c" | |
1129 | #endif | 1126 | #endif | |
1130 | 1127 | |||
1131 | USBNET_MODULE(ure) | 1128 | USBNET_MODULE(ure) |
--- src/sys/dev/usb/if_url.c 2022/03/03 05:54:37 1.91
+++ src/sys/dev/usb/if_url.c 2022/03/03 05:55:01 1.92
@@ -1,732 +1,729 @@ | @@ -1,732 +1,729 @@ | |||
1 | /* $NetBSD: if_url.c,v 1.91 2022/03/03 05:54:37 riastradh Exp $ */ | 1 | /* $NetBSD: if_url.c,v 1.92 2022/03/03 05:55:01 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.91 2022/03/03 05:54:37 riastradh Exp $"); | 47 | __KERNEL_RCSID(0, "$NetBSD: if_url.c,v 1.92 2022/03/03 05:55:01 riastradh Exp $"); | |
48 | 48 | |||
49 | #ifdef _KERNEL_OPT | 49 | #ifdef _KERNEL_OPT | |
50 | #include "opt_inet.h" | 50 | #include "opt_inet.h" | |
51 | #include "opt_usb.h" | 51 | #include "opt_usb.h" | |
52 | #endif | 52 | #endif | |
53 | 53 | |||
54 | #include <sys/param.h> | 54 | #include <sys/param.h> | |
55 | 55 | |||
56 | #include <net/if_ether.h> | 56 | #include <net/if_ether.h> | |
57 | #ifdef INET | 57 | #ifdef INET | |
58 | #include <netinet/in.h> | 58 | #include <netinet/in.h> | |
59 | #include <netinet/if_inarp.h> | 59 | #include <netinet/if_inarp.h> | |
60 | #endif | 60 | #endif | |
61 | 61 | |||
62 | #include <dev/mii/urlphyreg.h> | 62 | #include <dev/mii/urlphyreg.h> | |
63 | 63 | |||
64 | #include <dev/usb/usbnet.h> | 64 | #include <dev/usb/usbnet.h> | |
65 | 65 | |||
66 | #include <dev/usb/if_urlreg.h> | 66 | #include <dev/usb/if_urlreg.h> | |
67 | 67 | |||
68 | /* Function declarations */ | 68 | /* Function declarations */ | |
69 | static int url_match(device_t, cfdata_t, void *); | 69 | static int url_match(device_t, cfdata_t, void *); | |
70 | static void url_attach(device_t, device_t, void *); | 70 | static void url_attach(device_t, device_t, void *); | |
71 | 71 | |||
72 | CFATTACH_DECL_NEW(url, sizeof(struct usbnet), url_match, url_attach, | 72 | CFATTACH_DECL_NEW(url, sizeof(struct usbnet), url_match, url_attach, | |
73 | usbnet_detach, usbnet_activate); | 73 | usbnet_detach, usbnet_activate); | |
74 | 74 | |||
75 | static unsigned url_uno_tx_prepare(struct usbnet *, struct mbuf *, | 75 | static unsigned url_uno_tx_prepare(struct usbnet *, struct mbuf *, | |
76 | struct usbnet_chain *); | 76 | struct usbnet_chain *); | |
77 | static void url_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | 77 | static void url_uno_rx_loop(struct usbnet *, struct usbnet_chain *, uint32_t); | |
78 | static int url_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | 78 | static int url_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *); | |
79 | static int url_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | 79 | static int url_uno_mii_write_reg(struct usbnet *, int, int, uint16_t); | |
80 | static void url_uno_stop(struct ifnet *, int); | 80 | static void url_uno_stop(struct ifnet *, int); | |
81 | static void url_uno_mii_statchg(struct ifnet *); | 81 | static void url_uno_mii_statchg(struct ifnet *); | |
82 | static int url_uno_init(struct ifnet *); | 82 | static int url_uno_init(struct ifnet *); | |
83 | static void url_uno_mcast(struct ifnet *); | 83 | static void url_uno_mcast(struct ifnet *); | |
84 | static void url_reset(struct usbnet *); | 84 | static void url_reset(struct usbnet *); | |
85 | 85 | |||
86 | static int url_csr_read_1(struct usbnet *, int); | 86 | static int url_csr_read_1(struct usbnet *, int); | |
87 | static int url_csr_read_2(struct usbnet *, int); | 87 | static int url_csr_read_2(struct usbnet *, int); | |
88 | static int url_csr_write_1(struct usbnet *, int, int); | 88 | static int url_csr_write_1(struct usbnet *, int, int); | |
89 | static int url_csr_write_2(struct usbnet *, int, int); | 89 | static int url_csr_write_2(struct usbnet *, int, int); | |
90 | static int url_csr_write_4(struct usbnet *, int, int); | 90 | static int url_csr_write_4(struct usbnet *, int, int); | |
91 | static int url_mem(struct usbnet *, int, int, void *, int); | 91 | static int url_mem(struct usbnet *, int, int, void *, int); | |
92 | 92 | |||
93 | static const struct usbnet_ops url_ops = { | 93 | static const struct usbnet_ops url_ops = { | |
94 | .uno_stop = url_uno_stop, | 94 | .uno_stop = url_uno_stop, | |
95 | .uno_mcast = url_uno_mcast, | 95 | .uno_mcast = url_uno_mcast, | |
96 | .uno_read_reg = url_uno_mii_read_reg, | 96 | .uno_read_reg = url_uno_mii_read_reg, | |
97 | .uno_write_reg = url_uno_mii_write_reg, | 97 | .uno_write_reg = url_uno_mii_write_reg, | |
98 | .uno_statchg = url_uno_mii_statchg, | 98 | .uno_statchg = url_uno_mii_statchg, | |
99 | .uno_tx_prepare = url_uno_tx_prepare, | 99 | .uno_tx_prepare = url_uno_tx_prepare, | |
100 | .uno_rx_loop = url_uno_rx_loop, | 100 | .uno_rx_loop = url_uno_rx_loop, | |
101 | .uno_init = url_uno_init, | 101 | .uno_init = url_uno_init, | |
102 | }; | 102 | }; | |
103 | 103 | |||
104 | /* Macros */ | 104 | /* Macros */ | |
105 | #ifdef URL_DEBUG | 105 | #ifdef URL_DEBUG | |
106 | #define DPRINTF(x) if (urldebug) printf x | 106 | #define DPRINTF(x) if (urldebug) printf x | |
107 | #define DPRINTFN(n, x) if (urldebug >= (n)) printf x | 107 | #define DPRINTFN(n, x) if (urldebug >= (n)) printf x | |
108 | int urldebug = 0; | 108 | int urldebug = 0; | |
109 | #else | 109 | #else | |
110 | #define DPRINTF(x) | 110 | #define DPRINTF(x) | |
111 | #define DPRINTFN(n, x) | 111 | #define DPRINTFN(n, x) | |
112 | #endif | 112 | #endif | |
113 | 113 | |||
114 | #define URL_SETBIT(un, reg, x) \ | 114 | #define URL_SETBIT(un, reg, x) \ | |
115 | url_csr_write_1(un, reg, url_csr_read_1(un, reg) | (x)) | 115 | url_csr_write_1(un, reg, url_csr_read_1(un, reg) | (x)) | |
116 | 116 | |||
117 | #define URL_SETBIT2(un, reg, x) \ | 117 | #define URL_SETBIT2(un, reg, x) \ | |
118 | url_csr_write_2(un, reg, url_csr_read_2(un, reg) | (x)) | 118 | url_csr_write_2(un, reg, url_csr_read_2(un, reg) | (x)) | |
119 | 119 | |||
120 | #define URL_CLRBIT(un, reg, x) \ | 120 | #define URL_CLRBIT(un, reg, x) \ | |
121 | url_csr_write_1(un, reg, url_csr_read_1(un, reg) & ~(x)) | 121 | url_csr_write_1(un, reg, url_csr_read_1(un, reg) & ~(x)) | |
122 | 122 | |||
123 | #define URL_CLRBIT2(un, reg, x) \ | 123 | #define URL_CLRBIT2(un, reg, x) \ | |
124 | url_csr_write_2(un, reg, url_csr_read_2(un, reg) & ~(x)) | 124 | url_csr_write_2(un, reg, url_csr_read_2(un, reg) & ~(x)) | |
125 | 125 | |||
126 | static const struct url_type { | 126 | static const struct url_type { | |
127 | struct usb_devno url_dev; | 127 | struct usb_devno url_dev; | |
128 | uint16_t url_flags; | 128 | uint16_t url_flags; | |
129 | #define URL_EXT_PHY 0x0001 | 129 | #define URL_EXT_PHY 0x0001 | |
130 | } url_devs [] = { | 130 | } url_devs [] = { | |
131 | /* MELCO LUA-KTX */ | 131 | /* MELCO LUA-KTX */ | |
132 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX }, 0}, | 132 | {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX }, 0}, | |
133 | /* Realtek RTL8150L Generic (GREEN HOUSE USBKR100) */ | 133 | /* Realtek RTL8150L Generic (GREEN HOUSE USBKR100) */ | |
134 | {{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8150L}, 0}, | 134 | {{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8150L}, 0}, | |
135 | /* Longshine LCS-8138TX */ | 135 | /* Longshine LCS-8138TX */ | |
136 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_LCS8138TX}, 0}, | 136 | {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_LCS8138TX}, 0}, | |
137 | /* Micronet SP128AR */ | 137 | /* Micronet SP128AR */ | |
138 | {{ USB_VENDOR_MICRONET, USB_PRODUCT_MICRONET_SP128AR}, 0}, | 138 | {{ USB_VENDOR_MICRONET, USB_PRODUCT_MICRONET_SP128AR}, 0}, | |
139 | /* OQO model 01 */ | 139 | /* OQO model 01 */ | |
140 | {{ USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01}, 0}, | 140 | {{ USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01}, 0}, | |
141 | }; | 141 | }; | |
142 | #define url_lookup(v, p) ((const struct url_type *)usb_lookup(url_devs, v, p)) | 142 | #define url_lookup(v, p) ((const struct url_type *)usb_lookup(url_devs, v, p)) | |
143 | 143 | |||
144 | 144 | |||
145 | /* Probe */ | 145 | /* Probe */ | |
146 | static int | 146 | static int | |
147 | url_match(device_t parent, cfdata_t match, void *aux) | 147 | url_match(device_t parent, cfdata_t match, void *aux) | |
148 | { | 148 | { | |
149 | struct usb_attach_arg *uaa = aux; | 149 | struct usb_attach_arg *uaa = aux; | |
150 | 150 | |||
151 | return url_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | 151 | return url_lookup(uaa->uaa_vendor, uaa->uaa_product) != NULL ? | |
152 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | 152 | UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | |
153 | } | 153 | } | |
154 | /* Attach */ | 154 | /* Attach */ | |
155 | static void | 155 | static void | |
156 | url_attach(device_t parent, device_t self, void *aux) | 156 | url_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 * const un = device_private(self); | 159 | struct usbnet * const un = device_private(self); | |
160 | struct usb_attach_arg *uaa = aux; | 160 | struct usb_attach_arg *uaa = aux; | |
161 | struct usbd_device *dev = uaa->uaa_device; | 161 | struct usbd_device *dev = uaa->uaa_device; | |
162 | struct usbd_interface *iface; | 162 | struct usbd_interface *iface; | |
163 | usbd_status err; | 163 | usbd_status err; | |
164 | usb_interface_descriptor_t *id; | 164 | usb_interface_descriptor_t *id; | |
165 | usb_endpoint_descriptor_t *ed; | 165 | usb_endpoint_descriptor_t *ed; | |
166 | char *devinfop; | 166 | char *devinfop; | |
167 | int i; | 167 | int i; | |
168 | 168 | |||
169 | aprint_naive("\n"); | 169 | aprint_naive("\n"); | |
170 | aprint_normal("\n"); | 170 | aprint_normal("\n"); | |
171 | devinfop = usbd_devinfo_alloc(dev, 0); | 171 | devinfop = usbd_devinfo_alloc(dev, 0); | |
172 | aprint_normal_dev(self, "%s\n", devinfop); | 172 | aprint_normal_dev(self, "%s\n", devinfop); | |
173 | usbd_devinfo_free(devinfop); | 173 | usbd_devinfo_free(devinfop); | |
174 | 174 | |||
175 | un->un_dev = self; | 175 | un->un_dev = self; | |
176 | un->un_udev = dev; | 176 | un->un_udev = dev; | |
177 | un->un_sc = un; | 177 | un->un_sc = un; | |
178 | un->un_ops = &url_ops; | 178 | un->un_ops = &url_ops; | |
179 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | 179 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | |
180 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | 180 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | |
181 | un->un_rx_list_cnt = URL_RX_LIST_CNT; | 181 | un->un_rx_list_cnt = URL_RX_LIST_CNT; | |
182 | un->un_tx_list_cnt = URL_TX_LIST_CNT; | 182 | un->un_tx_list_cnt = URL_TX_LIST_CNT; | |
183 | un->un_rx_bufsz = URL_BUFSZ; | 183 | un->un_rx_bufsz = URL_BUFSZ; | |
184 | un->un_tx_bufsz = URL_BUFSZ; | 184 | un->un_tx_bufsz = URL_BUFSZ; | |
185 | 185 | |||
186 | /* Move the device into the configured state. */ | 186 | /* Move the device into the configured state. */ | |
187 | err = usbd_set_config_no(dev, URL_CONFIG_NO, 1); | 187 | err = usbd_set_config_no(dev, URL_CONFIG_NO, 1); | |
188 | if (err) { | 188 | if (err) { | |
189 | aprint_error_dev(self, "failed to set configuration" | 189 | aprint_error_dev(self, "failed to set configuration" | |
190 | ", err=%s\n", usbd_errstr(err)); | 190 | ", err=%s\n", usbd_errstr(err)); | |
191 | return; | 191 | return; | |
192 | } | 192 | } | |
193 | 193 | |||
194 | /* get control interface */ | 194 | /* get control interface */ | |
195 | err = usbd_device2interface_handle(dev, URL_IFACE_INDEX, &iface); | 195 | err = usbd_device2interface_handle(dev, URL_IFACE_INDEX, &iface); | |
196 | if (err) { | 196 | if (err) { | |
197 | aprint_error_dev(self, "failed to get interface, err=%s\n", | 197 | aprint_error_dev(self, "failed to get interface, err=%s\n", | |
198 | usbd_errstr(err)); | 198 | usbd_errstr(err)); | |
199 | return; | 199 | return; | |
200 | } | 200 | } | |
201 | 201 | |||
202 | un->un_iface = iface; | 202 | un->un_iface = iface; | |
203 | un->un_flags = url_lookup(uaa->uaa_vendor, uaa->uaa_product)->url_flags; | 203 | un->un_flags = url_lookup(uaa->uaa_vendor, uaa->uaa_product)->url_flags; | |
204 | #if 0 | 204 | #if 0 | |
205 | if (un->un_flags & URL_EXT_PHY) { | 205 | if (un->un_flags & URL_EXT_PHY) { | |
206 | un->un_read_reg_cb = url_ext_mii_read_reg; | 206 | un->un_read_reg_cb = url_ext_mii_read_reg; | |
207 | un->un_write_reg_cb = url_ext_mii_write_reg; | 207 | un->un_write_reg_cb = url_ext_mii_write_reg; | |
208 | } | 208 | } | |
209 | #endif | 209 | #endif | |
210 | 210 | |||
211 | /* get interface descriptor */ | 211 | /* get interface descriptor */ | |
212 | id = usbd_get_interface_descriptor(un->un_iface); | 212 | id = usbd_get_interface_descriptor(un->un_iface); | |
213 | 213 | |||
214 | /* find endpoints */ | 214 | /* find endpoints */ | |
215 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = | 215 | un->un_ed[USBNET_ENDPT_RX] = un->un_ed[USBNET_ENDPT_TX] = | |
216 | un->un_ed[USBNET_ENDPT_INTR] = 0; | 216 | un->un_ed[USBNET_ENDPT_INTR] = 0; | |
217 | for (i = 0; i < id->bNumEndpoints; i++) { | 217 | for (i = 0; i < id->bNumEndpoints; i++) { | |
218 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | 218 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | |
219 | if (ed == NULL) { | 219 | if (ed == NULL) { | |
220 | aprint_error_dev(self, | 220 | aprint_error_dev(self, | |
221 | "couldn't get endpoint %d\n", i); | 221 | "couldn't get endpoint %d\n", i); | |
222 | return; | 222 | return; | |
223 | } | 223 | } | |
224 | if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | 224 | if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | |
225 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | 225 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | |
226 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | 226 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | |
227 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | 227 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK && | |
228 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) | 228 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT) | |
229 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | 229 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | |
230 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT && | 230 | else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT && | |
231 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | 231 | UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN) | |
232 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | 232 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | |
233 | } | 233 | } | |
234 | 234 | |||
235 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | 235 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | |
236 | un->un_ed[USBNET_ENDPT_TX] == 0 || | 236 | un->un_ed[USBNET_ENDPT_TX] == 0 || | |
237 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | 237 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | |
238 | aprint_error_dev(self, "missing endpoint\n"); | 238 | aprint_error_dev(self, "missing endpoint\n"); | |
239 | return; | 239 | return; | |
240 | } | 240 | } | |
241 | 241 | |||
242 | /* Set these up now for url_mem(). */ | 242 | /* Set these up now for url_mem(). */ | |
243 | usbnet_attach(un, "urldet"); | 243 | usbnet_attach(un, "urldet"); | |
244 | 244 | |||
245 | /* reset the adapter */ | 245 | /* reset the adapter */ | |
246 | url_reset(un); | 246 | url_reset(un); | |
247 | 247 | |||
248 | /* Get Ethernet Address */ | 248 | /* Get Ethernet Address */ | |
249 | err = url_mem(un, URL_CMD_READMEM, URL_IDR0, (void *)un->un_eaddr, | 249 | err = url_mem(un, URL_CMD_READMEM, URL_IDR0, (void *)un->un_eaddr, | |
250 | ETHER_ADDR_LEN); | 250 | ETHER_ADDR_LEN); | |
251 | if (err) { | 251 | if (err) { | |
252 | aprint_error_dev(self, "read MAC address failed\n"); | 252 | aprint_error_dev(self, "read MAC address failed\n"); | |
253 | return; | 253 | return; | |
254 | } | 254 | } | |
255 | 255 | |||
256 | /* initialize interface information */ | 256 | /* initialize interface information */ | |
257 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | 257 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | |
258 | 0, &unm); | 258 | 0, &unm); | |
259 | } | 259 | } | |
260 | 260 | |||
261 | /* read/write memory */ | 261 | /* read/write memory */ | |
262 | static int | 262 | static int | |
263 | url_mem(struct usbnet *un, int cmd, int offset, void *buf, int len) | 263 | url_mem(struct usbnet *un, int cmd, int offset, void *buf, int len) | |
264 | { | 264 | { | |
265 | usb_device_request_t req; | 265 | usb_device_request_t req; | |
266 | usbd_status err; | 266 | usbd_status err; | |
267 | 267 | |||
268 | DPRINTFN(0x200, | 268 | DPRINTFN(0x200, | |
269 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 269 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
270 | 270 | |||
271 | if (usbnet_isdying(un)) { | 271 | if (usbnet_isdying(un)) { | |
272 | if (cmd == URL_CMD_READMEM) | 272 | if (cmd == URL_CMD_READMEM) | |
273 | memset(buf, 0, len); | 273 | memset(buf, 0, len); | |
274 | return 0; | 274 | return 0; | |
275 | } | 275 | } | |
276 | 276 | |||
277 | if (cmd == URL_CMD_READMEM) | 277 | if (cmd == URL_CMD_READMEM) | |
278 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | 278 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | |
279 | else | 279 | else | |
280 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | 280 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | |
281 | req.bRequest = URL_REQ_MEM; | 281 | req.bRequest = URL_REQ_MEM; | |
282 | USETW(req.wValue, offset); | 282 | USETW(req.wValue, offset); | |
283 | USETW(req.wIndex, 0x0000); | 283 | USETW(req.wIndex, 0x0000); | |
284 | USETW(req.wLength, len); | 284 | USETW(req.wLength, len); | |
285 | 285 | |||
286 | err = usbd_do_request(un->un_udev, &req, buf); | 286 | err = usbd_do_request(un->un_udev, &req, buf); | |
287 | if (err) { | 287 | if (err) { | |
288 | DPRINTF(("%s: url_mem(): %s failed. off=%04x, err=%d\n", | 288 | DPRINTF(("%s: url_mem(): %s failed. off=%04x, err=%d\n", | |
289 | device_xname(un->un_dev), | 289 | device_xname(un->un_dev), | |
290 | cmd == URL_CMD_READMEM ? "read" : "write", | 290 | cmd == URL_CMD_READMEM ? "read" : "write", | |
291 | offset, err)); | 291 | offset, err)); | |
292 | if (cmd == URL_CMD_READMEM) | 292 | if (cmd == URL_CMD_READMEM) | |
293 | memset(buf, 0, len); | 293 | memset(buf, 0, len); | |
294 | } | 294 | } | |
295 | 295 | |||
296 | return err; | 296 | return err; | |
297 | } | 297 | } | |
298 | 298 | |||
299 | /* read 1byte from register */ | 299 | /* read 1byte from register */ | |
300 | static int | 300 | static int | |
301 | url_csr_read_1(struct usbnet *un, int reg) | 301 | url_csr_read_1(struct usbnet *un, int reg) | |
302 | { | 302 | { | |
303 | uint8_t val = 0; | 303 | uint8_t val = 0; | |
304 | 304 | |||
305 | DPRINTFN(0x100, | 305 | DPRINTFN(0x100, | |
306 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 306 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
307 | 307 | |||
308 | return url_mem(un, URL_CMD_READMEM, reg, &val, 1) ? 0 : val; | 308 | return url_mem(un, URL_CMD_READMEM, reg, &val, 1) ? 0 : val; | |
309 | } | 309 | } | |
310 | 310 | |||
311 | /* read 2bytes from register */ | 311 | /* read 2bytes from register */ | |
312 | static int | 312 | static int | |
313 | url_csr_read_2(struct usbnet *un, int reg) | 313 | url_csr_read_2(struct usbnet *un, int reg) | |
314 | { | 314 | { | |
315 | uWord val; | 315 | uWord val; | |
316 | 316 | |||
317 | DPRINTFN(0x100, | 317 | DPRINTFN(0x100, | |
318 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 318 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
319 | 319 | |||
320 | USETW(val, 0); | 320 | USETW(val, 0); | |
321 | return url_mem(un, URL_CMD_READMEM, reg, &val, 2) ? 0 : UGETW(val); | 321 | return url_mem(un, URL_CMD_READMEM, reg, &val, 2) ? 0 : UGETW(val); | |
322 | } | 322 | } | |
323 | 323 | |||
324 | /* write 1byte to register */ | 324 | /* write 1byte to register */ | |
325 | static int | 325 | static int | |
326 | url_csr_write_1(struct usbnet *un, int reg, int aval) | 326 | url_csr_write_1(struct usbnet *un, int reg, int aval) | |
327 | { | 327 | { | |
328 | uint8_t val = aval; | 328 | uint8_t val = aval; | |
329 | 329 | |||
330 | DPRINTFN(0x100, | 330 | DPRINTFN(0x100, | |
331 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 331 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
332 | 332 | |||
333 | return url_mem(un, URL_CMD_WRITEMEM, reg, &val, 1) ? -1 : 0; | 333 | return url_mem(un, URL_CMD_WRITEMEM, reg, &val, 1) ? -1 : 0; | |
334 | } | 334 | } | |
335 | 335 | |||
336 | /* write 2bytes to register */ | 336 | /* write 2bytes to register */ | |
337 | static int | 337 | static int | |
338 | url_csr_write_2(struct usbnet *un, int reg, int aval) | 338 | url_csr_write_2(struct usbnet *un, int reg, int aval) | |
339 | { | 339 | { | |
340 | uWord val; | 340 | uWord val; | |
341 | 341 | |||
342 | DPRINTFN(0x100, | 342 | DPRINTFN(0x100, | |
343 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 343 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
344 | 344 | |||
345 | USETW(val, aval); | 345 | USETW(val, aval); | |
346 | 346 | |||
347 | return url_mem(un, URL_CMD_WRITEMEM, reg, &val, 2) ? -1 : 0; | 347 | return url_mem(un, URL_CMD_WRITEMEM, reg, &val, 2) ? -1 : 0; | |
348 | } | 348 | } | |
349 | 349 | |||
350 | /* write 4bytes to register */ | 350 | /* write 4bytes to register */ | |
351 | static int | 351 | static int | |
352 | url_csr_write_4(struct usbnet *un, int reg, int aval) | 352 | url_csr_write_4(struct usbnet *un, int reg, int aval) | |
353 | { | 353 | { | |
354 | uDWord val; | 354 | uDWord val; | |
355 | 355 | |||
356 | DPRINTFN(0x100, | 356 | DPRINTFN(0x100, | |
357 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 357 | ("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
358 | 358 | |||
359 | USETDW(val, aval); | 359 | USETDW(val, aval); | |
360 | 360 | |||
361 | return url_mem(un, URL_CMD_WRITEMEM, reg, &val, 4) ? -1 : 0; | 361 | return url_mem(un, URL_CMD_WRITEMEM, reg, &val, 4) ? -1 : 0; | |
362 | } | 362 | } | |
363 | 363 | |||
364 | static int | 364 | static int | |
365 | url_uno_init(struct ifnet *ifp) | 365 | url_uno_init(struct ifnet *ifp) | |
366 | { | 366 | { | |
367 | struct usbnet * const un = ifp->if_softc; | 367 | struct usbnet * const un = ifp->if_softc; | |
368 | const u_char *eaddr; | 368 | const u_char *eaddr; | |
369 | int i; | 369 | int i; | |
370 | 370 | |||
371 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 371 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
372 | 372 | |||
373 | if (usbnet_isdying(un)) | |||
374 | return EIO; | |||
375 | ||||
376 | /* Cancel pending I/O and free all TX/RX buffers */ | 373 | /* Cancel pending I/O and free all TX/RX buffers */ | |
377 | usbnet_stop(un, ifp, 1); | 374 | usbnet_stop(un, ifp, 1); | |
378 | 375 | |||
379 | eaddr = CLLADDR(ifp->if_sadl); | 376 | eaddr = CLLADDR(ifp->if_sadl); | |
380 | for (i = 0; i < ETHER_ADDR_LEN; i++) | 377 | for (i = 0; i < ETHER_ADDR_LEN; i++) | |
381 | url_csr_write_1(un, URL_IDR0 + i, eaddr[i]); | 378 | url_csr_write_1(un, URL_IDR0 + i, eaddr[i]); | |
382 | 379 | |||
383 | /* Init transmission control register */ | 380 | /* Init transmission control register */ | |
384 | URL_CLRBIT(un, URL_TCR, | 381 | URL_CLRBIT(un, URL_TCR, | |
385 | URL_TCR_TXRR1 | URL_TCR_TXRR0 | | 382 | URL_TCR_TXRR1 | URL_TCR_TXRR0 | | |
386 | URL_TCR_IFG1 | URL_TCR_IFG0 | | 383 | URL_TCR_IFG1 | URL_TCR_IFG0 | | |
387 | URL_TCR_NOCRC); | 384 | URL_TCR_NOCRC); | |
388 | 385 | |||
389 | /* Init receive control register */ | 386 | /* Init receive control register */ | |
390 | URL_SETBIT2(un, URL_RCR, URL_RCR_TAIL | URL_RCR_AD | URL_RCR_AB); | 387 | URL_SETBIT2(un, URL_RCR, URL_RCR_TAIL | URL_RCR_AD | URL_RCR_AB); | |
391 | 388 | |||
392 | /* Enable RX and TX */ | 389 | /* Enable RX and TX */ | |
393 | URL_SETBIT(un, URL_CR, URL_CR_TE | URL_CR_RE); | 390 | URL_SETBIT(un, URL_CR, URL_CR_TE | URL_CR_RE); | |
394 | 391 | |||
395 | return usbnet_init_rx_tx(un); | 392 | return usbnet_init_rx_tx(un); | |
396 | } | 393 | } | |
397 | 394 | |||
398 | static void | 395 | static void | |
399 | url_reset(struct usbnet *un) | 396 | url_reset(struct usbnet *un) | |
400 | { | 397 | { | |
401 | int i; | 398 | int i; | |
402 | 399 | |||
403 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 400 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
404 | 401 | |||
405 | if (usbnet_isdying(un)) | 402 | if (usbnet_isdying(un)) | |
406 | return; | 403 | return; | |
407 | 404 | |||
408 | URL_SETBIT(un, URL_CR, URL_CR_SOFT_RST); | 405 | URL_SETBIT(un, URL_CR, URL_CR_SOFT_RST); | |
409 | 406 | |||
410 | for (i = 0; i < URL_TX_TIMEOUT; i++) { | 407 | for (i = 0; i < URL_TX_TIMEOUT; i++) { | |
411 | if (usbnet_isdying(un)) | 408 | if (usbnet_isdying(un)) | |
412 | return; | 409 | return; | |
413 | if (!(url_csr_read_1(un, URL_CR) & URL_CR_SOFT_RST)) | 410 | if (!(url_csr_read_1(un, URL_CR) & URL_CR_SOFT_RST)) | |
414 | break; | 411 | break; | |
415 | delay(10); /* XXX */ | 412 | delay(10); /* XXX */ | |
416 | } | 413 | } | |
417 | 414 | |||
418 | delay(10000); /* XXX */ | 415 | delay(10000); /* XXX */ | |
419 | } | 416 | } | |
420 | 417 | |||
421 | static void | 418 | static void | |
422 | url_uno_mcast(struct ifnet *ifp) | 419 | url_uno_mcast(struct ifnet *ifp) | |
423 | { | 420 | { | |
424 | struct usbnet * const un = ifp->if_softc; | 421 | struct usbnet * const un = ifp->if_softc; | |
425 | struct ethercom *ec = usbnet_ec(un); | 422 | struct ethercom *ec = usbnet_ec(un); | |
426 | struct ether_multi *enm; | 423 | struct ether_multi *enm; | |
427 | struct ether_multistep step; | 424 | struct ether_multistep step; | |
428 | uint32_t mchash[2] = { 0, 0 }; | 425 | uint32_t mchash[2] = { 0, 0 }; | |
429 | int h = 0, rcr; | 426 | int h = 0, rcr; | |
430 | 427 | |||
431 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 428 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
432 | 429 | |||
433 | if (usbnet_isdying(un)) | 430 | if (usbnet_isdying(un)) | |
434 | return; | 431 | return; | |
435 | 432 | |||
436 | rcr = url_csr_read_2(un, URL_RCR); | 433 | rcr = url_csr_read_2(un, URL_RCR); | |
437 | rcr &= ~(URL_RCR_AAP | URL_RCR_AAM | URL_RCR_AM); | 434 | rcr &= ~(URL_RCR_AAP | URL_RCR_AAM | URL_RCR_AM); | |
438 | 435 | |||
439 | ETHER_LOCK(ec); | 436 | ETHER_LOCK(ec); | |
440 | if (ifp->if_flags & IFF_PROMISC) { | 437 | if (ifp->if_flags & IFF_PROMISC) { | |
441 | ec->ec_flags |= ETHER_F_ALLMULTI; | 438 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
442 | ETHER_UNLOCK(ec); | 439 | ETHER_UNLOCK(ec); | |
443 | /* run promisc. mode */ | 440 | /* run promisc. mode */ | |
444 | rcr |= URL_RCR_AAM; /* ??? */ | 441 | rcr |= URL_RCR_AAM; /* ??? */ | |
445 | rcr |= URL_RCR_AAP; | 442 | rcr |= URL_RCR_AAP; | |
446 | goto update; | 443 | goto update; | |
447 | } | 444 | } | |
448 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | 445 | ec->ec_flags &= ~ETHER_F_ALLMULTI; | |
449 | ETHER_FIRST_MULTI(step, ec, enm); | 446 | ETHER_FIRST_MULTI(step, ec, enm); | |
450 | while (enm != NULL) { | 447 | while (enm != NULL) { | |
451 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | 448 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { | |
452 | ec->ec_flags |= ETHER_F_ALLMULTI; | 449 | ec->ec_flags |= ETHER_F_ALLMULTI; | |
453 | ETHER_UNLOCK(ec); | 450 | ETHER_UNLOCK(ec); | |
454 | /* accept all multicast frames */ | 451 | /* accept all multicast frames */ | |
455 | rcr |= URL_RCR_AAM; | 452 | rcr |= URL_RCR_AAM; | |
456 | goto update; | 453 | goto update; | |
457 | } | 454 | } | |
458 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | 455 | h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN); | |
459 | /* 1(31) and 5(30:26) bit sampling */ | 456 | /* 1(31) and 5(30:26) bit sampling */ | |
460 | mchash[h >> 31] |= 1 << ((h >> 26) & 0x1f); | 457 | mchash[h >> 31] |= 1 << ((h >> 26) & 0x1f); | |
461 | ETHER_NEXT_MULTI(step, enm); | 458 | ETHER_NEXT_MULTI(step, enm); | |
462 | } | 459 | } | |
463 | ETHER_UNLOCK(ec); | 460 | ETHER_UNLOCK(ec); | |
464 | if (h != 0) | 461 | if (h != 0) | |
465 | rcr |= URL_RCR_AM; /* activate mcast hash filter */ | 462 | rcr |= URL_RCR_AM; /* activate mcast hash filter */ | |
466 | url_csr_write_4(un, URL_MAR0, mchash[0]); | 463 | url_csr_write_4(un, URL_MAR0, mchash[0]); | |
467 | url_csr_write_4(un, URL_MAR4, mchash[1]); | 464 | url_csr_write_4(un, URL_MAR4, mchash[1]); | |
468 | update: | 465 | update: | |
469 | url_csr_write_2(un, URL_RCR, rcr); | 466 | url_csr_write_2(un, URL_RCR, rcr); | |
470 | } | 467 | } | |
471 | 468 | |||
472 | static unsigned | 469 | static unsigned | |
473 | url_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | 470 | url_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | |
474 | { | 471 | { | |
475 | int total_len; | 472 | int total_len; | |
476 | 473 | |||
477 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | 474 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | |
478 | 475 | |||
479 | KASSERT(un->un_tx_bufsz >= URL_MIN_FRAME_LEN); | 476 | KASSERT(un->un_tx_bufsz >= URL_MIN_FRAME_LEN); | |
480 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | 477 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz) | |
481 | return 0; | 478 | return 0; | |
482 | 479 | |||
483 | /* Copy the mbuf data into a contiguous buffer */ | 480 | /* Copy the mbuf data into a contiguous buffer */ | |
484 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | 481 | m_copydata(m, 0, m->m_pkthdr.len, c->unc_buf); | |
485 | total_len = m->m_pkthdr.len; | 482 | total_len = m->m_pkthdr.len; | |
486 | 483 | |||
487 | if (total_len < URL_MIN_FRAME_LEN) { | 484 | if (total_len < URL_MIN_FRAME_LEN) { | |
488 | memset(c->unc_buf + total_len, 0, | 485 | memset(c->unc_buf + total_len, 0, | |
489 | URL_MIN_FRAME_LEN - total_len); | 486 | URL_MIN_FRAME_LEN - total_len); | |
490 | total_len = URL_MIN_FRAME_LEN; | 487 | total_len = URL_MIN_FRAME_LEN; | |
491 | } | 488 | } | |
492 | 489 | |||
493 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | 490 | DPRINTF(("%s: %s: send %d bytes\n", device_xname(un->un_dev), | |
494 | __func__, total_len)); | 491 | __func__, total_len)); | |
495 | 492 | |||
496 | return total_len; | 493 | return total_len; | |
497 | } | 494 | } | |
498 | 495 | |||
499 | static void | 496 | static void | |
500 | url_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | 497 | url_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | |
501 | { | 498 | { | |
502 | struct ifnet *ifp = usbnet_ifp(un); | 499 | struct ifnet *ifp = usbnet_ifp(un); | |
503 | url_rxhdr_t rxhdr; | 500 | url_rxhdr_t rxhdr; | |
504 | 501 | |||
505 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | 502 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev),__func__)); | |
506 | 503 | |||
507 | if (total_len <= ETHER_CRC_LEN || total_len <= sizeof(rxhdr)) { | 504 | if (total_len <= ETHER_CRC_LEN || total_len <= sizeof(rxhdr)) { | |
508 | if_statinc(ifp, if_ierrors); | 505 | if_statinc(ifp, if_ierrors); | |
509 | return; | 506 | return; | |
510 | } | 507 | } | |
511 | 508 | |||
512 | memcpy(&rxhdr, c->unc_buf + total_len - ETHER_CRC_LEN, sizeof(rxhdr)); | 509 | memcpy(&rxhdr, c->unc_buf + total_len - ETHER_CRC_LEN, sizeof(rxhdr)); | |
513 | 510 | |||
514 | DPRINTF(("%s: RX Status: %dbytes%s%s%s%s packets\n", | 511 | DPRINTF(("%s: RX Status: %dbytes%s%s%s%s packets\n", | |
515 | device_xname(un->un_dev), | 512 | device_xname(un->un_dev), | |
516 | UGETW(rxhdr) & URL_RXHDR_BYTEC_MASK, | 513 | UGETW(rxhdr) & URL_RXHDR_BYTEC_MASK, | |
517 | UGETW(rxhdr) & URL_RXHDR_VALID_MASK ? ", Valid" : "", | 514 | UGETW(rxhdr) & URL_RXHDR_VALID_MASK ? ", Valid" : "", | |
518 | UGETW(rxhdr) & URL_RXHDR_RUNTPKT_MASK ? ", Runt" : "", | 515 | UGETW(rxhdr) & URL_RXHDR_RUNTPKT_MASK ? ", Runt" : "", | |
519 | UGETW(rxhdr) & URL_RXHDR_PHYPKT_MASK ? ", Physical match" : "", | 516 | UGETW(rxhdr) & URL_RXHDR_PHYPKT_MASK ? ", Physical match" : "", | |
520 | UGETW(rxhdr) & URL_RXHDR_MCASTPKT_MASK ? ", Multicast" : "")); | 517 | UGETW(rxhdr) & URL_RXHDR_MCASTPKT_MASK ? ", Multicast" : "")); | |
521 | 518 | |||
522 | if ((UGETW(rxhdr) & URL_RXHDR_VALID_MASK) == 0) { | 519 | if ((UGETW(rxhdr) & URL_RXHDR_VALID_MASK) == 0) { | |
523 | if_statinc(ifp, if_ierrors); | 520 | if_statinc(ifp, if_ierrors); | |
524 | return; | 521 | return; | |
525 | } | 522 | } | |
526 | 523 | |||
527 | total_len -= ETHER_CRC_LEN; | 524 | total_len -= ETHER_CRC_LEN; | |
528 | 525 | |||
529 | DPRINTF(("%s: %s: deliver %d\n", device_xname(un->un_dev), | 526 | DPRINTF(("%s: %s: deliver %d\n", device_xname(un->un_dev), | |
530 | __func__, total_len)); | 527 | __func__, total_len)); | |
531 | usbnet_enqueue(un, c->unc_buf, total_len, 0, 0, 0); | 528 | usbnet_enqueue(un, c->unc_buf, total_len, 0, 0, 0); | |
532 | } | 529 | } | |
533 | 530 | |||
534 | #if 0 | 531 | #if 0 | |
535 | static void url_intr(void) | 532 | static void url_intr(void) | |
536 | { | 533 | { | |
537 | } | 534 | } | |
538 | #endif | 535 | #endif | |
539 | 536 | |||
540 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | 537 | /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */ | |
541 | static void | 538 | static void | |
542 | url_uno_stop(struct ifnet *ifp, int disable) | 539 | url_uno_stop(struct ifnet *ifp, int disable) | |
543 | { | 540 | { | |
544 | struct usbnet * const un = ifp->if_softc; | 541 | struct usbnet * const un = ifp->if_softc; | |
545 | 542 | |||
546 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | 543 | DPRINTF(("%s: %s: enter\n", device_xname(un->un_dev), __func__)); | |
547 | 544 | |||
548 | url_reset(un); | 545 | url_reset(un); | |
549 | } | 546 | } | |
550 | 547 | |||
551 | static int | 548 | static int | |
552 | url_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | 549 | url_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | |
553 | { | 550 | { | |
554 | uint16_t data; | 551 | uint16_t data; | |
555 | usbd_status err = USBD_NORMAL_COMPLETION; | 552 | usbd_status err = USBD_NORMAL_COMPLETION; | |
556 | 553 | |||
557 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | 554 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n", | |
558 | device_xname(un->un_dev), __func__, phy, reg)); | 555 | device_xname(un->un_dev), __func__, phy, reg)); | |
559 | 556 | |||
560 | /* XXX: one PHY only for the RTL8150 internal PHY */ | 557 | /* XXX: one PHY only for the RTL8150 internal PHY */ | |
561 | if (phy != 0) { | 558 | if (phy != 0) { | |
562 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 559 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
563 | device_xname(un->un_dev), __func__, phy)); | 560 | device_xname(un->un_dev), __func__, phy)); | |
564 | *val = 0; | 561 | *val = 0; | |
565 | return EINVAL; | 562 | return EINVAL; | |
566 | } | 563 | } | |
567 | 564 | |||
568 | switch (reg) { | 565 | switch (reg) { | |
569 | case MII_BMCR: /* Control Register */ | 566 | case MII_BMCR: /* Control Register */ | |
570 | reg = URL_BMCR; | 567 | reg = URL_BMCR; | |
571 | break; | 568 | break; | |
572 | case MII_BMSR: /* Status Register */ | 569 | case MII_BMSR: /* Status Register */ | |
573 | reg = URL_BMSR; | 570 | reg = URL_BMSR; | |
574 | break; | 571 | break; | |
575 | case MII_PHYIDR1: | 572 | case MII_PHYIDR1: | |
576 | case MII_PHYIDR2: | 573 | case MII_PHYIDR2: | |
577 | *val = 0; | 574 | *val = 0; | |
578 | goto R_DONE; | 575 | goto R_DONE; | |
579 | break; | 576 | break; | |
580 | case MII_ANAR: /* Autonegotiation advertisement */ | 577 | case MII_ANAR: /* Autonegotiation advertisement */ | |
581 | reg = URL_ANAR; | 578 | reg = URL_ANAR; | |
582 | break; | 579 | break; | |
583 | case MII_ANLPAR: /* Autonegotiation link partner abilities */ | 580 | case MII_ANLPAR: /* Autonegotiation link partner abilities */ | |
584 | reg = URL_ANLP; | 581 | reg = URL_ANLP; | |
585 | break; | 582 | break; | |
586 | case URLPHY_MSR: /* Media Status Register */ | 583 | case URLPHY_MSR: /* Media Status Register */ | |
587 | reg = URL_MSR; | 584 | reg = URL_MSR; | |
588 | break; | 585 | break; | |
589 | default: | 586 | default: | |
590 | printf("%s: %s: bad register %04x\n", | 587 | printf("%s: %s: bad register %04x\n", | |
591 | device_xname(un->un_dev), __func__, reg); | 588 | device_xname(un->un_dev), __func__, reg); | |
592 | return EINVAL; | 589 | return EINVAL; | |
593 | } | 590 | } | |
594 | 591 | |||
595 | if (reg == URL_MSR) | 592 | if (reg == URL_MSR) | |
596 | data = url_csr_read_1(un, reg); | 593 | data = url_csr_read_1(un, reg); | |
597 | else | 594 | else | |
598 | data = url_csr_read_2(un, reg); | 595 | data = url_csr_read_2(un, reg); | |
599 | *val = data; | 596 | *val = data; | |
600 | 597 | |||
601 | R_DONE: | 598 | R_DONE: | |
602 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | 599 | DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04hx\n", | |
603 | device_xname(un->un_dev), __func__, phy, reg, *val)); | 600 | device_xname(un->un_dev), __func__, phy, reg, *val)); | |
604 | 601 | |||
605 | return err; | 602 | return err; | |
606 | } | 603 | } | |
607 | 604 | |||
608 | static int | 605 | static int | |
609 | url_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | 606 | url_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val) | |
610 | { | 607 | { | |
611 | 608 | |||
612 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | 609 | DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x val=0x%04hx\n", | |
613 | device_xname(un->un_dev), __func__, phy, reg, val)); | 610 | device_xname(un->un_dev), __func__, phy, reg, val)); | |
614 | 611 | |||
615 | /* XXX: one PHY only for the RTL8150 internal PHY */ | 612 | /* XXX: one PHY only for the RTL8150 internal PHY */ | |
616 | if (phy != 0) { | 613 | if (phy != 0) { | |
617 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | 614 | DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n", | |
618 | device_xname(un->un_dev), __func__, phy)); | 615 | device_xname(un->un_dev), __func__, phy)); | |
619 | return EINVAL; | 616 | return EINVAL; | |
620 | } | 617 | } | |
621 | 618 | |||
622 | switch (reg) { | 619 | switch (reg) { | |
623 | case MII_BMCR: /* Control Register */ | 620 | case MII_BMCR: /* Control Register */ | |
624 | reg = URL_BMCR; | 621 | reg = URL_BMCR; | |
625 | break; | 622 | break; | |
626 | case MII_BMSR: /* Status Register */ | 623 | case MII_BMSR: /* Status Register */ | |
627 | reg = URL_BMSR; | 624 | reg = URL_BMSR; | |
628 | break; | 625 | break; | |
629 | case MII_PHYIDR1: | 626 | case MII_PHYIDR1: | |
630 | case MII_PHYIDR2: | 627 | case MII_PHYIDR2: | |
631 | return 0; | 628 | return 0; | |
632 | case MII_ANAR: /* Autonegotiation advertisement */ | 629 | case MII_ANAR: /* Autonegotiation advertisement */ | |
633 | reg = URL_ANAR; | 630 | reg = URL_ANAR; | |
634 | break; | 631 | break; | |
635 | case MII_ANLPAR: /* Autonegotiation link partner abilities */ | 632 | case MII_ANLPAR: /* Autonegotiation link partner abilities */ | |
636 | reg = URL_ANLP; | 633 | reg = URL_ANLP; | |
637 | break; | 634 | break; | |
638 | case URLPHY_MSR: /* Media Status Register */ | 635 | case URLPHY_MSR: /* Media Status Register */ | |
639 | reg = URL_MSR; | 636 | reg = URL_MSR; | |
640 | break; | 637 | break; | |
641 | default: | 638 | default: | |
642 | printf("%s: %s: bad register %04x\n", | 639 | printf("%s: %s: bad register %04x\n", | |
643 | device_xname(un->un_dev), __func__, reg); | 640 | device_xname(un->un_dev), __func__, reg); | |
644 | return EINVAL; | 641 | return EINVAL; | |
645 | } | 642 | } | |
646 | 643 | |||
647 | if (reg == URL_MSR) | 644 | if (reg == URL_MSR) | |
648 | url_csr_write_1(un, reg, val); | 645 | url_csr_write_1(un, reg, val); | |
649 | else | 646 | else | |
650 | url_csr_write_2(un, reg, val); | 647 | url_csr_write_2(un, reg, val); | |
651 | 648 | |||
652 | return 0; | 649 | return 0; | |
653 | } | 650 | } | |
654 | 651 | |||
655 | static void | 652 | static void | |
656 | url_uno_mii_statchg(struct ifnet *ifp) | 653 | url_uno_mii_statchg(struct ifnet *ifp) | |
657 | { | 654 | { | |
658 | struct usbnet * const un = ifp->if_softc; | 655 | struct usbnet * const un = ifp->if_softc; | |
659 | 656 | |||
660 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | 657 | DPRINTF(("%s: %s: enter\n", ifp->if_xname, __func__)); | |
661 | 658 | |||
662 | /* XXX */ | 659 | /* XXX */ | |
663 | usbnet_set_link(un, true); | 660 | usbnet_set_link(un, true); | |
664 | } | 661 | } | |
665 | 662 | |||
666 | #if 0 | 663 | #if 0 | |
667 | /* | 664 | /* | |
668 | * external PHYs support, but not test. | 665 | * external PHYs support, but not test. | |
669 | */ | 666 | */ | |
670 | static usbd_status | 667 | static usbd_status | |
671 | url_ext_mii_read_reg(struct usbnet *un, int phy, int reg) | 668 | url_ext_mii_read_reg(struct usbnet *un, int phy, int reg) | |
672 | { | 669 | { | |
673 | uint16_t val; | 670 | uint16_t val; | |
674 | 671 | |||
675 | DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x\n", | 672 | DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x\n", | |
676 | device_xname(un->un_dev), __func__, phy, reg)); | 673 | device_xname(un->un_dev), __func__, phy, reg)); | |
677 | 674 | |||
678 | url_csr_write_1(un, URL_PHYADD, phy & URL_PHYADD_MASK); | 675 | url_csr_write_1(un, URL_PHYADD, phy & URL_PHYADD_MASK); | |
679 | /* | 676 | /* | |
680 | * RTL8150L will initiate a MII management data transaction | 677 | * RTL8150L will initiate a MII management data transaction | |
681 | * if PHYCNT_OWN bit is set 1 by software. After transaction, | 678 | * if PHYCNT_OWN bit is set 1 by software. After transaction, | |
682 | * this bit is auto cleared by TRL8150L. | 679 | * this bit is auto cleared by TRL8150L. | |
683 | */ | 680 | */ | |
684 | url_csr_write_1(un, URL_PHYCNT, | 681 | url_csr_write_1(un, URL_PHYCNT, | |
685 | (reg | URL_PHYCNT_PHYOWN) & ~URL_PHYCNT_RWCR); | 682 | (reg | URL_PHYCNT_PHYOWN) & ~URL_PHYCNT_RWCR); | |
686 | for (i = 0; i < URL_TIMEOUT; i++) { | 683 | for (i = 0; i < URL_TIMEOUT; i++) { | |
687 | if ((url_csr_read_1(un, URL_PHYCNT) & URL_PHYCNT_PHYOWN) == 0) | 684 | if ((url_csr_read_1(un, URL_PHYCNT) & URL_PHYCNT_PHYOWN) == 0) | |
688 | break; | 685 | break; | |
689 | } | 686 | } | |
690 | if (i == URL_TIMEOUT) { | 687 | if (i == URL_TIMEOUT) { | |
691 | printf("%s: MII read timed out\n", device_xname(un->un_dev)); | 688 | printf("%s: MII read timed out\n", device_xname(un->un_dev)); | |
692 | } | 689 | } | |
693 | 690 | |||
694 | val = url_csr_read_2(un, URL_PHYDAT); | 691 | val = url_csr_read_2(un, URL_PHYDAT); | |
695 | 692 | |||
696 | DPRINTF(("%s: %s: phy=%d reg=0x%04x => 0x%04x\n", | 693 | DPRINTF(("%s: %s: phy=%d reg=0x%04x => 0x%04x\n", | |
697 | device_xname(un->un_dev), __func__, phy, reg, val)); | 694 | device_xname(un->un_dev), __func__, phy, reg, val)); | |
698 | 695 | |||
699 | return USBD_NORMAL_COMPLETION; | 696 | return USBD_NORMAL_COMPLETION; | |
700 | } | 697 | } | |
701 | 698 | |||
702 | static usbd_status | 699 | static usbd_status | |
703 | url_ext_mii_write_reg(struct usbnet *un, int phy, int reg, int data) | 700 | url_ext_mii_write_reg(struct usbnet *un, int phy, int reg, int data) | |
704 | { | 701 | { | |
705 | 702 | |||
706 | DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n", | 703 | DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n", | |
707 | device_xname(un->un_dev), __func__, phy, reg, data)); | 704 | device_xname(un->un_dev), __func__, phy, reg, data)); | |
708 | 705 | |||
709 | url_csr_write_2(un, URL_PHYDAT, data); | 706 | url_csr_write_2(un, URL_PHYDAT, data); | |
710 | url_csr_write_1(un, URL_PHYADD, phy); | 707 | url_csr_write_1(un, URL_PHYADD, phy); | |
711 | url_csr_write_1(un, URL_PHYCNT, reg | URL_PHYCNT_RWCR); /* Write */ | 708 | url_csr_write_1(un, URL_PHYCNT, reg | URL_PHYCNT_RWCR); /* Write */ | |
712 | 709 | |||
713 | for (i=0; i < URL_TIMEOUT; i++) { | 710 | for (i=0; i < URL_TIMEOUT; i++) { | |
714 | if (url_csr_read_1(un, URL_PHYCNT) & URL_PHYCNT_PHYOWN) | 711 | if (url_csr_read_1(un, URL_PHYCNT) & URL_PHYCNT_PHYOWN) | |
715 | break; | 712 | break; | |
716 | } | 713 | } | |
717 | 714 | |||
718 | if (i == URL_TIMEOUT) { | 715 | if (i == URL_TIMEOUT) { | |
719 | printf("%s: MII write timed out\n", | 716 | printf("%s: MII write timed out\n", | |
720 | device_xname(un->un_dev)); | 717 | device_xname(un->un_dev)); | |
721 | return USBD_TIMEOUT; | 718 | return USBD_TIMEOUT; | |
722 | } | 719 | } | |
723 | 720 | |||
724 | return USBD_NORMAL_COMPLETION; | 721 | return USBD_NORMAL_COMPLETION; | |
725 | } | 722 | } | |
726 | #endif | 723 | #endif | |
727 | 724 | |||
728 | #ifdef _MODULE | 725 | #ifdef _MODULE | |
729 | #include "ioconf.c" | 726 | #include "ioconf.c" | |
730 | #endif | 727 | #endif | |
731 | 728 | |||
732 | USBNET_MODULE(url) | 729 | USBNET_MODULE(url) |