| @@ -1,1322 +1,1346 @@ | | | @@ -1,1322 +1,1346 @@ |
1 | /* $NetBSD: if_mue.c,v 1.60 2020/06/27 13:33:26 jmcneill Exp $ */ | | 1 | /* $NetBSD: if_mue.c,v 1.61 2021/07/15 03:25:50 nisimura 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.60 2020/06/27 13:33:26 jmcneill Exp $"); | | 23 | __KERNEL_RCSID(0, "$NetBSD: if_mue.c,v 1.61 2021/07/15 03:25:50 nisimura Exp $"); |
24 | | | 24 | |
25 | #ifdef _KERNEL_OPT | | 25 | #ifdef _KERNEL_OPT |
26 | #include "opt_usb.h" | | 26 | #include "opt_usb.h" |
27 | #include "opt_inet.h" | | 27 | #include "opt_inet.h" |
28 | #endif | | 28 | #endif |
29 | | | 29 | |
30 | #include <sys/param.h> | | 30 | #include <sys/param.h> |
31 | | | 31 | |
32 | #include <dev/usb/usbnet.h> | | 32 | #include <dev/usb/usbnet.h> |
33 | | | 33 | |
34 | #include <dev/usb/if_muereg.h> | | 34 | #include <dev/usb/if_muereg.h> |
35 | #include <dev/usb/if_muevar.h> | | 35 | #include <dev/usb/if_muevar.h> |
36 | | | 36 | |
37 | #define MUE_PRINTF(un, fmt, args...) \ | | 37 | #define MUE_PRINTF(un, fmt, args...) \ |
38 | device_printf((un)->un_dev, "%s: " fmt, __func__, ##args); | | 38 | device_printf((un)->un_dev, "%s: " fmt, __func__, ##args); |
39 | | | 39 | |
40 | #ifdef USB_DEBUG | | 40 | #ifdef USB_DEBUG |
41 | int muedebug = 0; | | 41 | int muedebug = 0; |
42 | #define DPRINTF(un, fmt, args...) \ | | 42 | #define DPRINTF(un, fmt, args...) \ |
43 | do { \ | | 43 | do { \ |
44 | if (muedebug) \ | | 44 | if (muedebug) \ |
45 | MUE_PRINTF(un, fmt, ##args); \ | | 45 | MUE_PRINTF(un, fmt, ##args); \ |
46 | } while (0 /* CONSTCOND */) | | 46 | } while (0 /* CONSTCOND */) |
47 | #else | | 47 | #else |
48 | #define DPRINTF(un, fmt, args...) __nothing | | 48 | #define DPRINTF(un, fmt, args...) __nothing |
49 | #endif | | 49 | #endif |
50 | | | 50 | |
51 | /* | | 51 | /* |
52 | * Various supported device vendors/products. | | 52 | * Various supported device vendors/products. |
53 | */ | | 53 | */ |
54 | struct mue_type { | | 54 | struct mue_type { |
55 | struct usb_devno mue_dev; | | 55 | struct usb_devno mue_dev; |
56 | uint16_t mue_flags; | | 56 | uint16_t mue_flags; |
57 | #define LAN7500 0x0001 /* LAN7500 */ | | 57 | #define LAN7500 0x0001 /* LAN7500 */ |
58 | #define LAN7800 0x0002 /* LAN7800 */ | | 58 | #define LAN7800 0x0002 /* LAN7800 */ |
59 | #define LAN7801 0x0004 /* LAN7801 */ | | 59 | #define LAN7801 0x0004 /* LAN7801 */ |
60 | #define LAN7850 0x0008 /* LAN7850 */ | | 60 | #define LAN7850 0x0008 /* LAN7850 */ |
61 | }; | | 61 | }; |
62 | | | 62 | |
63 | static const struct mue_type mue_devs[] = { | | 63 | static const struct mue_type mue_devs[] = { |
64 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7500 }, LAN7500 }, | | 64 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7500 }, LAN7500 }, |
65 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7505 }, LAN7500 }, | | 65 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7505 }, LAN7500 }, |
66 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7800 }, LAN7800 }, | | 66 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7800 }, LAN7800 }, |
67 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7801 }, LAN7801 }, | | 67 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7801 }, LAN7801 }, |
68 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7850 }, LAN7850 } | | 68 | { { USB_VENDOR_SMSC, USB_PRODUCT_SMSC_LAN7850 }, LAN7850 } |
69 | }; | | 69 | }; |
70 | | | 70 | |
71 | #define MUE_LOOKUP(uaa) ((const struct mue_type *)usb_lookup(mue_devs, \ | | 71 | #define MUE_LOOKUP(uaa) ((const struct mue_type *)usb_lookup(mue_devs, \ |
72 | uaa->uaa_vendor, uaa->uaa_product)) | | 72 | uaa->uaa_vendor, uaa->uaa_product)) |
73 | | | 73 | |
74 | #define MUE_ENADDR_LO(enaddr) \ | | 74 | #define MUE_ENADDR_LO(enaddr) \ |
75 | ((enaddr[3] << 24) | (enaddr[2] << 16) | (enaddr[1] << 8) | enaddr[0]) | | 75 | ((enaddr[3] << 24) | (enaddr[2] << 16) | (enaddr[1] << 8) | enaddr[0]) |
76 | #define MUE_ENADDR_HI(enaddr) \ | | 76 | #define MUE_ENADDR_HI(enaddr) \ |
77 | ((enaddr[5] << 8) | enaddr[4]) | | 77 | ((enaddr[5] << 8) | enaddr[4]) |
78 | | | 78 | |
79 | static int mue_match(device_t, cfdata_t, void *); | | 79 | static int mue_match(device_t, cfdata_t, void *); |
80 | static void mue_attach(device_t, device_t, void *); | | 80 | static void mue_attach(device_t, device_t, void *); |
81 | | | 81 | |
82 | static uint32_t mue_csr_read(struct usbnet *, uint32_t); | | 82 | static uint32_t mue_csr_read(struct usbnet *, uint32_t); |
83 | static int mue_csr_write(struct usbnet *, uint32_t, uint32_t); | | 83 | static int mue_csr_write(struct usbnet *, uint32_t, uint32_t); |
84 | static int mue_wait_for_bits(struct usbnet *, uint32_t, uint32_t, | | 84 | static int mue_wait_for_bits(struct usbnet *, uint32_t, uint32_t, |
85 | uint32_t, uint32_t); | | 85 | uint32_t, uint32_t); |
86 | static uint8_t mue_eeprom_getbyte(struct usbnet *, int, uint8_t *); | | 86 | static uint8_t mue_eeprom_getbyte(struct usbnet *, int, uint8_t *); |
87 | static bool mue_eeprom_present(struct usbnet *); | | 87 | static bool mue_eeprom_present(struct usbnet *); |
88 | static void mue_dataport_write(struct usbnet *, uint32_t, uint32_t, | | 88 | static void mue_dataport_write(struct usbnet *, uint32_t, uint32_t, |
89 | uint32_t, uint32_t *); | | 89 | uint32_t, uint32_t *); |
90 | static void mue_init_ltm(struct usbnet *); | | 90 | static void mue_init_ltm(struct usbnet *); |
91 | static int mue_chip_init(struct usbnet *); | | 91 | static int mue_chip_init(struct usbnet *); |
92 | static void mue_set_macaddr(struct usbnet *); | | 92 | static void mue_set_macaddr(struct usbnet *); |
93 | static int mue_get_macaddr(struct usbnet *, prop_dictionary_t); | | 93 | static int mue_get_macaddr(struct usbnet *, prop_dictionary_t); |
94 | static int mue_prepare_tso(struct usbnet *, struct mbuf *); | | 94 | static int mue_prepare_tso(struct usbnet *, struct mbuf *); |
95 | static void mue_setiff_locked(struct usbnet *); | | 95 | static void mue_setiff_locked(struct usbnet *); |
96 | static void mue_sethwcsum_locked(struct usbnet *); | | 96 | static void mue_sethwcsum_locked(struct usbnet *); |
97 | static void mue_setmtu_locked(struct usbnet *); | | 97 | static void mue_setmtu_locked(struct usbnet *); |
98 | static void mue_reset(struct usbnet *); | | 98 | static void mue_reset(struct usbnet *); |
99 | | | 99 | |
100 | static void mue_uno_stop(struct ifnet *, int); | | 100 | static void mue_uno_stop(struct ifnet *, int); |
101 | static int mue_uno_ioctl(struct ifnet *, u_long, void *); | | 101 | static int mue_uno_override_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_override_ioctl = mue_uno_override_ioctl, |
114 | .uno_read_reg = mue_uno_mii_read_reg, | | 114 | .uno_read_reg = mue_uno_mii_read_reg, |
115 | .uno_write_reg = mue_uno_mii_write_reg, | | 115 | .uno_write_reg = mue_uno_mii_write_reg, |
116 | .uno_statchg = mue_uno_mii_statchg, | | 116 | .uno_statchg = mue_uno_mii_statchg, |
117 | .uno_tx_prepare = mue_uno_tx_prepare, | | 117 | .uno_tx_prepare = mue_uno_tx_prepare, |
118 | .uno_rx_loop = mue_uno_rx_loop, | | 118 | .uno_rx_loop = mue_uno_rx_loop, |
119 | .uno_init = mue_uno_init, | | 119 | .uno_init = mue_uno_init, |
120 | }; | | 120 | }; |
121 | | | 121 | |
122 | #define MUE_SETBIT(un, reg, x) \ | | 122 | #define MUE_SETBIT(un, reg, x) \ |
123 | mue_csr_write(un, reg, mue_csr_read(un, reg) | (x)) | | 123 | mue_csr_write(un, reg, mue_csr_read(un, reg) | (x)) |
124 | | | 124 | |
125 | #define MUE_CLRBIT(un, reg, x) \ | | 125 | #define MUE_CLRBIT(un, reg, x) \ |
126 | mue_csr_write(un, reg, mue_csr_read(un, reg) & ~(x)) | | 126 | mue_csr_write(un, reg, mue_csr_read(un, reg) & ~(x)) |
127 | | | 127 | |
128 | #define MUE_WAIT_SET(un, reg, set, fail) \ | | 128 | #define MUE_WAIT_SET(un, reg, set, fail) \ |
129 | mue_wait_for_bits(un, reg, set, ~0, fail) | | 129 | mue_wait_for_bits(un, reg, set, ~0, fail) |
130 | | | 130 | |
131 | #define MUE_WAIT_CLR(un, reg, clear, fail) \ | | 131 | #define MUE_WAIT_CLR(un, reg, clear, fail) \ |
132 | mue_wait_for_bits(un, reg, 0, clear, fail) | | 132 | mue_wait_for_bits(un, reg, 0, clear, fail) |
133 | | | 133 | |
134 | #define ETHER_IS_VALID(addr) \ | | 134 | #define ETHER_IS_VALID(addr) \ |
135 | (!ETHER_IS_MULTICAST(addr) && !ETHER_IS_ZERO(addr)) | | 135 | (!ETHER_IS_MULTICAST(addr) && !ETHER_IS_ZERO(addr)) |
136 | | | 136 | |
137 | #define ETHER_IS_ZERO(addr) \ | | 137 | #define ETHER_IS_ZERO(addr) \ |
138 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) | | 138 | (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5])) |
139 | | | 139 | |
140 | CFATTACH_DECL_NEW(mue, sizeof(struct usbnet), mue_match, mue_attach, | | 140 | struct mue_softc { |
| | | 141 | struct usbnet sc_un; |
| | | 142 | struct usbnet_intr sc_intr; |
| | | 143 | uint8_t sc_ibuf[8]; |
| | | 144 | unsigned sc_flowflags; /* 802.3x PAUSE flow control */ |
| | | 145 | }; |
| | | 146 | |
| | | 147 | CFATTACH_DECL_NEW(mue, sizeof(struct mue_softc), mue_match, mue_attach, |
141 | usbnet_detach, usbnet_activate); | | 148 | usbnet_detach, usbnet_activate); |
142 | | | 149 | |
143 | static uint32_t | | 150 | static uint32_t |
144 | mue_csr_read(struct usbnet *un, uint32_t reg) | | 151 | mue_csr_read(struct usbnet *un, uint32_t reg) |
145 | { | | 152 | { |
146 | usb_device_request_t req; | | 153 | usb_device_request_t req; |
147 | usbd_status err; | | 154 | usbd_status err; |
148 | uDWord val; | | 155 | uDWord val; |
149 | | | 156 | |
150 | if (usbnet_isdying(un)) | | 157 | if (usbnet_isdying(un)) |
151 | return 0; | | 158 | return 0; |
152 | | | 159 | |
153 | USETDW(val, 0); | | 160 | USETDW(val, 0); |
154 | req.bmRequestType = UT_READ_VENDOR_DEVICE; | | 161 | req.bmRequestType = UT_READ_VENDOR_DEVICE; |
155 | req.bRequest = MUE_UR_READREG; | | 162 | req.bRequest = MUE_UR_READREG; |
156 | USETW(req.wValue, 0); | | 163 | USETW(req.wValue, 0); |
157 | USETW(req.wIndex, reg); | | 164 | USETW(req.wIndex, reg); |
158 | USETW(req.wLength, 4); | | 165 | USETW(req.wLength, 4); |
159 | | | 166 | |
160 | err = usbd_do_request(un->un_udev, &req, &val); | | 167 | err = usbd_do_request(un->un_udev, &req, &val); |
161 | if (err) { | | 168 | if (err) { |
162 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | | 169 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); |
163 | return 0; | | 170 | return 0; |
164 | } | | 171 | } |
165 | | | 172 | |
166 | return UGETDW(val); | | 173 | return UGETDW(val); |
167 | } | | 174 | } |
168 | | | 175 | |
169 | static int | | 176 | static int |
170 | mue_csr_write(struct usbnet *un, uint32_t reg, uint32_t aval) | | 177 | mue_csr_write(struct usbnet *un, uint32_t reg, uint32_t aval) |
171 | { | | 178 | { |
172 | usb_device_request_t req; | | 179 | usb_device_request_t req; |
173 | usbd_status err; | | 180 | usbd_status err; |
174 | uDWord val; | | 181 | uDWord val; |
175 | | | 182 | |
176 | if (usbnet_isdying(un)) | | 183 | if (usbnet_isdying(un)) |
177 | return 0; | | 184 | return 0; |
178 | | | 185 | |
179 | USETDW(val, aval); | | 186 | USETDW(val, aval); |
180 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; | | 187 | req.bmRequestType = UT_WRITE_VENDOR_DEVICE; |
181 | req.bRequest = MUE_UR_WRITEREG; | | 188 | req.bRequest = MUE_UR_WRITEREG; |
182 | USETW(req.wValue, 0); | | 189 | USETW(req.wValue, 0); |
183 | USETW(req.wIndex, reg); | | 190 | USETW(req.wIndex, reg); |
184 | USETW(req.wLength, 4); | | 191 | USETW(req.wLength, 4); |
185 | | | 192 | |
186 | err = usbd_do_request(un->un_udev, &req, &val); | | 193 | err = usbd_do_request(un->un_udev, &req, &val); |
187 | if (err) { | | 194 | if (err) { |
188 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); | | 195 | MUE_PRINTF(un, "reg = %#x: %s\n", reg, usbd_errstr(err)); |
189 | return -1; | | 196 | return -1; |
190 | } | | 197 | } |
191 | | | 198 | |
192 | return 0; | | 199 | return 0; |
193 | } | | 200 | } |
194 | | | 201 | |
195 | static int | | 202 | static int |
196 | mue_wait_for_bits(struct usbnet *un, uint32_t reg, | | 203 | mue_wait_for_bits(struct usbnet *un, uint32_t reg, |
197 | uint32_t set, uint32_t clear, uint32_t fail) | | 204 | uint32_t set, uint32_t clear, uint32_t fail) |
198 | { | | 205 | { |
199 | uint32_t val; | | 206 | uint32_t val; |
200 | int ntries; | | 207 | int ntries; |
201 | | | 208 | |
202 | for (ntries = 0; ntries < 1000; ntries++) { | | 209 | for (ntries = 0; ntries < 1000; ntries++) { |
203 | val = mue_csr_read(un, reg); | | 210 | val = mue_csr_read(un, reg); |
204 | if ((val & set) || !(val & clear)) | | 211 | if ((val & set) || !(val & clear)) |
205 | return 0; | | 212 | return 0; |
206 | if (val & fail) | | 213 | if (val & fail) |
207 | return 1; | | 214 | return 1; |
208 | usbd_delay_ms(un->un_udev, 1); | | 215 | usbd_delay_ms(un->un_udev, 1); |
209 | } | | 216 | } |
210 | | | 217 | |
211 | return 1; | | 218 | return 1; |
212 | } | | 219 | } |
213 | | | 220 | |
214 | static int | | 221 | static int |
215 | mue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) | | 222 | mue_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val) |
216 | { | | 223 | { |
217 | uint32_t data; | | 224 | uint32_t data; |
218 | | | 225 | |
219 | if (un->un_phyno != phy) | | 226 | if (un->un_phyno != phy) |
220 | return EINVAL; | | 227 | return EINVAL; |
221 | | | 228 | |
222 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | | 229 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { |
223 | MUE_PRINTF(un, "not ready\n"); | | 230 | MUE_PRINTF(un, "not ready\n"); |
224 | return EBUSY; | | 231 | return EBUSY; |
225 | } | | 232 | } |
226 | | | 233 | |
227 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_READ | | | 234 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_READ | |
228 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | | 235 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | |
229 | MUE_MII_ACCESS_PHYADDR(phy)); | | 236 | MUE_MII_ACCESS_PHYADDR(phy)); |
230 | | | 237 | |
231 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { | | 238 | if (MUE_WAIT_CLR(un, MUE_MII_ACCESS, MUE_MII_ACCESS_BUSY, 0)) { |
232 | MUE_PRINTF(un, "timed out\n"); | | 239 | MUE_PRINTF(un, "timed out\n"); |
233 | return ETIMEDOUT; | | 240 | return ETIMEDOUT; |
234 | } | | 241 | } |
235 | | | 242 | |
236 | data = mue_csr_read(un, MUE_MII_DATA); | | 243 | data = mue_csr_read(un, MUE_MII_DATA); |
237 | *val = data & 0xffff; | | 244 | *val = data & 0xffff; |
238 | | | 245 | |
239 | return 0; | | 246 | return 0; |
240 | } | | 247 | } |
241 | | | 248 | |
242 | static int | | 249 | static int |
243 | 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) |
244 | { | | 251 | { |
245 | | | 252 | |
246 | if (un->un_phyno != phy) | | 253 | if (un->un_phyno != phy) |
247 | return EINVAL; | | 254 | return EINVAL; |
248 | | | 255 | |
249 | 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)) { |
250 | MUE_PRINTF(un, "not ready\n"); | | 257 | MUE_PRINTF(un, "not ready\n"); |
251 | return EBUSY; | | 258 | return EBUSY; |
252 | } | | 259 | } |
253 | | | 260 | |
254 | mue_csr_write(un, MUE_MII_DATA, val); | | 261 | mue_csr_write(un, MUE_MII_DATA, val); |
255 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_WRITE | | | 262 | mue_csr_write(un, MUE_MII_ACCESS, MUE_MII_ACCESS_WRITE | |
256 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | | | 263 | MUE_MII_ACCESS_BUSY | MUE_MII_ACCESS_REGADDR(reg) | |
257 | MUE_MII_ACCESS_PHYADDR(phy)); | | 264 | MUE_MII_ACCESS_PHYADDR(phy)); |
258 | | | 265 | |
259 | 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)) { |
260 | MUE_PRINTF(un, "timed out\n"); | | 267 | MUE_PRINTF(un, "timed out\n"); |
261 | return ETIMEDOUT; | | 268 | return ETIMEDOUT; |
262 | } | | 269 | } |
263 | | | 270 | |
264 | return 0; | | 271 | return 0; |
265 | } | | 272 | } |
266 | | | 273 | |
267 | static void | | 274 | static void |
268 | mue_uno_mii_statchg(struct ifnet *ifp) | | 275 | mue_uno_mii_statchg(struct ifnet *ifp) |
269 | { | | 276 | { |
270 | struct usbnet * const un = ifp->if_softc; | | 277 | struct usbnet * const un = ifp->if_softc; |
271 | struct mii_data * const mii = usbnet_mii(un); | | 278 | struct mii_data * const mii = usbnet_mii(un); |
272 | uint32_t flow, threshold; | | 279 | uint32_t flow, threshold; |
273 | | | 280 | |
274 | if (usbnet_isdying(un)) | | 281 | if (usbnet_isdying(un)) |
275 | return; | | 282 | return; |
276 | | | 283 | |
277 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == | | 284 | if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == |
278 | (IFM_ACTIVE | IFM_AVALID)) { | | 285 | (IFM_ACTIVE | IFM_AVALID)) { |
279 | switch (IFM_SUBTYPE(mii->mii_media_active)) { | | 286 | switch (IFM_SUBTYPE(mii->mii_media_active)) { |
280 | case IFM_10_T: | | 287 | case IFM_10_T: |
281 | case IFM_100_TX: | | 288 | case IFM_100_TX: |
282 | case IFM_1000_T: | | 289 | case IFM_1000_T: |
283 | usbnet_set_link(un, true); | | 290 | usbnet_set_link(un, true); |
284 | break; | | 291 | break; |
285 | default: | | 292 | default: |
286 | break; | | 293 | break; |
287 | } | | 294 | } |
288 | } | | 295 | } |
289 | | | 296 | |
290 | /* Lost link, do nothing. */ | | 297 | /* Lost link, do nothing. */ |
291 | if (!usbnet_havelink(un)) { | | 298 | if (!usbnet_havelink(un)) { |
292 | DPRINTF(un, "mii_media_status = %#x\n", mii->mii_media_status); | | 299 | DPRINTF(un, "mii_media_status = %#x\n", mii->mii_media_status); |
293 | return; | | 300 | return; |
294 | } | | 301 | } |
295 | | | 302 | |
296 | if (!(un->un_flags & LAN7500)) { | | 303 | if (!(un->un_flags & LAN7500)) { |
297 | if (un->un_udev->ud_speed == USB_SPEED_SUPER) { | | 304 | if (un->un_udev->ud_speed == USB_SPEED_SUPER) { |
298 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { | | 305 | if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) { |
299 | /* Disable U2 and enable U1. */ | | 306 | /* Disable U2 and enable U1. */ |
300 | MUE_CLRBIT(un, MUE_USB_CFG1, | | 307 | MUE_CLRBIT(un, MUE_USB_CFG1, |
301 | MUE_USB_CFG1_DEV_U2_INIT_EN); | | 308 | MUE_USB_CFG1_DEV_U2_INIT_EN); |
302 | MUE_SETBIT(un, MUE_USB_CFG1, | | 309 | MUE_SETBIT(un, MUE_USB_CFG1, |
303 | MUE_USB_CFG1_DEV_U1_INIT_EN); | | 310 | MUE_USB_CFG1_DEV_U1_INIT_EN); |
304 | } else { | | 311 | } else { |
305 | /* Enable U1 and U2. */ | | 312 | /* Enable U1 and U2. */ |
306 | MUE_SETBIT(un, MUE_USB_CFG1, | | 313 | MUE_SETBIT(un, MUE_USB_CFG1, |
307 | MUE_USB_CFG1_DEV_U1_INIT_EN | | | 314 | MUE_USB_CFG1_DEV_U1_INIT_EN | |
308 | MUE_USB_CFG1_DEV_U2_INIT_EN); | | 315 | MUE_USB_CFG1_DEV_U2_INIT_EN); |
309 | } | | 316 | } |
310 | } | | 317 | } |
311 | } | | 318 | } |
312 | | | 319 | |
313 | flow = 0; | | 320 | flow = 0; |
314 | /* XXX Linux does not check IFM_FDX flag for 7800. */ | | 321 | /* XXX Linux does not check IFM_FDX flag for 7800. */ |
315 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { | | 322 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) { |
316 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) | | 323 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) |
317 | flow |= MUE_FLOW_TX_FCEN | MUE_FLOW_PAUSE_TIME; | | 324 | flow |= MUE_FLOW_TX_FCEN | MUE_FLOW_PAUSE_TIME; |
318 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) | | 325 | if (IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) |
319 | flow |= MUE_FLOW_RX_FCEN; | | 326 | flow |= MUE_FLOW_RX_FCEN; |
320 | } | | 327 | } |
321 | | | 328 | |
322 | /* XXX Magic numbers taken from Linux driver. */ | | 329 | /* XXX Magic numbers taken from Linux driver. */ |
323 | if (un->un_flags & LAN7500) | | 330 | if (un->un_flags & LAN7500) |
324 | threshold = 0x820; | | 331 | threshold = 0x820; |
325 | else | | 332 | else |
326 | switch (un->un_udev->ud_speed) { | | 333 | switch (un->un_udev->ud_speed) { |
327 | case USB_SPEED_SUPER: | | 334 | case USB_SPEED_SUPER: |
328 | threshold = 0x817; | | 335 | threshold = 0x817; |
329 | break; | | 336 | break; |
330 | case USB_SPEED_HIGH: | | 337 | case USB_SPEED_HIGH: |
331 | threshold = 0x211; | | 338 | threshold = 0x211; |
332 | break; | | 339 | break; |
333 | default: | | 340 | default: |
334 | threshold = 0; | | 341 | threshold = 0; |
335 | break; | | 342 | break; |
336 | } | | 343 | } |
337 | | | 344 | |
338 | /* Threshold value should be set before enabling flow. */ | | 345 | /* Threshold value should be set before enabling flow. */ |
339 | mue_csr_write(un, (un->un_flags & LAN7500) ? | | 346 | mue_csr_write(un, (un->un_flags & LAN7500) ? |
340 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, threshold); | | 347 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, threshold); |
341 | mue_csr_write(un, MUE_FLOW, flow); | | 348 | mue_csr_write(un, MUE_FLOW, flow); |
342 | | | 349 | |
343 | DPRINTF(un, "done\n"); | | 350 | DPRINTF(un, "done\n"); |
344 | } | | 351 | } |
345 | | | 352 | |
346 | static uint8_t | | 353 | static uint8_t |
347 | mue_eeprom_getbyte(struct usbnet *un, int off, uint8_t *dest) | | 354 | mue_eeprom_getbyte(struct usbnet *un, int off, uint8_t *dest) |
348 | { | | 355 | { |
349 | uint32_t val; | | 356 | uint32_t val; |
350 | | | 357 | |
351 | 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)) { |
352 | MUE_PRINTF(un, "not ready\n"); | | 359 | MUE_PRINTF(un, "not ready\n"); |
353 | return ETIMEDOUT; | | 360 | return ETIMEDOUT; |
354 | } | | 361 | } |
355 | | | 362 | |
356 | KASSERT((off & ~MUE_E2P_CMD_ADDR_MASK) == 0); | | 363 | KASSERT((off & ~MUE_E2P_CMD_ADDR_MASK) == 0); |
357 | 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 | |
358 | off); | | 365 | off); |
359 | | | 366 | |
360 | 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, |
361 | MUE_E2P_CMD_TIMEOUT)) { | | 368 | MUE_E2P_CMD_TIMEOUT)) { |
362 | MUE_PRINTF(un, "timed out\n"); | | 369 | MUE_PRINTF(un, "timed out\n"); |
363 | return ETIMEDOUT; | | 370 | return ETIMEDOUT; |
364 | } | | 371 | } |
365 | | | 372 | |
366 | val = mue_csr_read(un, MUE_E2P_DATA); | | 373 | val = mue_csr_read(un, MUE_E2P_DATA); |
367 | *dest = val & 0xff; | | 374 | *dest = val & 0xff; |
368 | | | 375 | |
369 | return 0; | | 376 | return 0; |
370 | } | | 377 | } |
371 | | | 378 | |
372 | static int | | 379 | static int |
373 | 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) |
374 | { | | 381 | { |
375 | uint32_t val = 0; /* XXX gcc */ | | 382 | uint32_t val = 0; /* XXX gcc */ |
376 | uint8_t byte; | | 383 | uint8_t byte; |
377 | int i, err = 0; | | 384 | int i, err = 0; |
378 | | | 385 | |
379 | /* | | 386 | /* |
380 | * EEPROM pins are muxed with the LED function on LAN7800 device. | | 387 | * EEPROM pins are muxed with the LED function on LAN7800 device. |
381 | */ | | 388 | */ |
382 | if (un->un_flags & LAN7800) { | | 389 | if (un->un_flags & LAN7800) { |
383 | val = mue_csr_read(un, MUE_HW_CFG); | | 390 | val = mue_csr_read(un, MUE_HW_CFG); |
384 | mue_csr_write(un, MUE_HW_CFG, | | 391 | mue_csr_write(un, MUE_HW_CFG, |
385 | val & ~(MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN)); | | 392 | val & ~(MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN)); |
386 | } | | 393 | } |
387 | | | 394 | |
388 | for (i = 0; i < cnt; i++) { | | 395 | for (i = 0; i < cnt; i++) { |
389 | err = mue_eeprom_getbyte(un, off + i, &byte); | | 396 | err = mue_eeprom_getbyte(un, off + i, &byte); |
390 | if (err) | | 397 | if (err) |
391 | break; | | 398 | break; |
392 | *(dest + i) = byte; | | 399 | *(dest + i) = byte; |
393 | } | | 400 | } |
394 | | | 401 | |
395 | if (un->un_flags & LAN7800) | | 402 | if (un->un_flags & LAN7800) |
396 | mue_csr_write(un, MUE_HW_CFG, val); | | 403 | mue_csr_write(un, MUE_HW_CFG, val); |
397 | | | 404 | |
398 | return err ? 1 : 0; | | 405 | return err ? 1 : 0; |
399 | } | | 406 | } |
400 | | | 407 | |
401 | static bool | | 408 | static bool |
402 | mue_eeprom_present(struct usbnet *un) | | 409 | mue_eeprom_present(struct usbnet *un) |
403 | { | | 410 | { |
404 | uint32_t val; | | 411 | uint32_t val; |
405 | uint8_t sig; | | 412 | uint8_t sig; |
406 | int ret; | | 413 | int ret; |
407 | | | 414 | |
408 | if (un->un_flags & LAN7500) { | | 415 | if (un->un_flags & LAN7500) { |
409 | val = mue_csr_read(un, MUE_E2P_CMD); | | 416 | val = mue_csr_read(un, MUE_E2P_CMD); |
410 | return val & MUE_E2P_CMD_LOADED; | | 417 | return val & MUE_E2P_CMD_LOADED; |
411 | } else { | | 418 | } else { |
412 | ret = mue_read_eeprom(un, &sig, MUE_E2P_IND_OFFSET, 1); | | 419 | ret = mue_read_eeprom(un, &sig, MUE_E2P_IND_OFFSET, 1); |
413 | return (ret == 0) && (sig == MUE_E2P_IND); | | 420 | return (ret == 0) && (sig == MUE_E2P_IND); |
414 | } | | 421 | } |
415 | } | | 422 | } |
416 | | | 423 | |
417 | static int | | 424 | static int |
418 | 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) |
419 | { | | 426 | { |
420 | uint32_t val; | | 427 | uint32_t val; |
421 | int i, err; | | 428 | int i, err; |
422 | | | 429 | |
423 | val = mue_csr_read(un, MUE_OTP_PWR_DN); | | 430 | val = mue_csr_read(un, MUE_OTP_PWR_DN); |
424 | | | 431 | |
425 | /* Checking if bit is set. */ | | 432 | /* Checking if bit is set. */ |
426 | if (val & MUE_OTP_PWR_DN_PWRDN_N) { | | 433 | if (val & MUE_OTP_PWR_DN_PWRDN_N) { |
427 | /* Clear it, then wait for it to be cleared. */ | | 434 | /* Clear it, then wait for it to be cleared. */ |
428 | mue_csr_write(un, MUE_OTP_PWR_DN, 0); | | 435 | mue_csr_write(un, MUE_OTP_PWR_DN, 0); |
429 | err = MUE_WAIT_CLR(un, MUE_OTP_PWR_DN, MUE_OTP_PWR_DN_PWRDN_N, | | 436 | err = MUE_WAIT_CLR(un, MUE_OTP_PWR_DN, MUE_OTP_PWR_DN_PWRDN_N, |
430 | 0); | | 437 | 0); |
431 | if (err) { | | 438 | if (err) { |
432 | MUE_PRINTF(un, "not ready\n"); | | 439 | MUE_PRINTF(un, "not ready\n"); |
433 | return 1; | | 440 | return 1; |
434 | } | | 441 | } |
435 | } | | 442 | } |
436 | | | 443 | |
437 | /* Start reading the bytes, one at a time. */ | | 444 | /* Start reading the bytes, one at a time. */ |
438 | for (i = 0; i < cnt; i++) { | | 445 | for (i = 0; i < cnt; i++) { |
439 | mue_csr_write(un, MUE_OTP_ADDR1, | | 446 | mue_csr_write(un, MUE_OTP_ADDR1, |
440 | ((off + i) >> 8) & MUE_OTP_ADDR1_MASK); | | 447 | ((off + i) >> 8) & MUE_OTP_ADDR1_MASK); |
441 | mue_csr_write(un, MUE_OTP_ADDR2, | | 448 | mue_csr_write(un, MUE_OTP_ADDR2, |
442 | ((off + i) & MUE_OTP_ADDR2_MASK)); | | 449 | ((off + i) & MUE_OTP_ADDR2_MASK)); |
443 | 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); |
444 | 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); |
445 | | | 452 | |
446 | 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); |
447 | if (err) { | | 454 | if (err) { |
448 | MUE_PRINTF(un, "timed out\n"); | | 455 | MUE_PRINTF(un, "timed out\n"); |
449 | return 1; | | 456 | return 1; |
450 | } | | 457 | } |
451 | val = mue_csr_read(un, MUE_OTP_RD_DATA); | | 458 | val = mue_csr_read(un, MUE_OTP_RD_DATA); |
452 | *(dest + i) = (uint8_t)(val & 0xff); | | 459 | *(dest + i) = (uint8_t)(val & 0xff); |
453 | } | | 460 | } |
454 | | | 461 | |
455 | return 0; | | 462 | return 0; |
456 | } | | 463 | } |
457 | | | 464 | |
458 | static int | | 465 | static int |
459 | 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) |
460 | { | | 467 | { |
461 | uint8_t sig; | | 468 | uint8_t sig; |
462 | int err; | | 469 | int err; |
463 | | | 470 | |
464 | if (un->un_flags & LAN7500) | | 471 | if (un->un_flags & LAN7500) |
465 | return 1; | | 472 | return 1; |
466 | | | 473 | |
467 | 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); |
468 | if (err) | | 475 | if (err) |
469 | return 1; | | 476 | return 1; |
470 | switch (sig) { | | 477 | switch (sig) { |
471 | case MUE_OTP_IND_1: | | 478 | case MUE_OTP_IND_1: |
472 | break; | | 479 | break; |
473 | case MUE_OTP_IND_2: | | 480 | case MUE_OTP_IND_2: |
474 | off += 0x100; | | 481 | off += 0x100; |
475 | break; | | 482 | break; |
476 | default: | | 483 | default: |
477 | DPRINTF(un, "OTP not found\n"); | | 484 | DPRINTF(un, "OTP not found\n"); |
478 | return 1; | | 485 | return 1; |
479 | } | | 486 | } |
480 | err = mue_read_otp_raw(un, dest, off, cnt); | | 487 | err = mue_read_otp_raw(un, dest, off, cnt); |
481 | return err; | | 488 | return err; |
482 | } | | 489 | } |
483 | | | 490 | |
484 | static void | | 491 | static void |
485 | 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, |
486 | uint32_t cnt, uint32_t *data) | | 493 | uint32_t cnt, uint32_t *data) |
487 | { | | 494 | { |
488 | uint32_t i; | | 495 | uint32_t i; |
489 | | | 496 | |
490 | 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)) { |
491 | MUE_PRINTF(un, "not ready\n"); | | 498 | MUE_PRINTF(un, "not ready\n"); |
492 | return; | | 499 | return; |
493 | } | | 500 | } |
494 | | | 501 | |
495 | mue_csr_write(un, MUE_DP_SEL, | | 502 | mue_csr_write(un, MUE_DP_SEL, |
496 | (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); |
497 | | | 504 | |
498 | for (i = 0; i < cnt; i++) { | | 505 | for (i = 0; i < cnt; i++) { |
499 | mue_csr_write(un, MUE_DP_ADDR, addr + i); | | 506 | mue_csr_write(un, MUE_DP_ADDR, addr + i); |
500 | mue_csr_write(un, MUE_DP_DATA, data[i]); | | 507 | mue_csr_write(un, MUE_DP_DATA, data[i]); |
501 | mue_csr_write(un, MUE_DP_CMD, MUE_DP_CMD_WRITE); | | 508 | mue_csr_write(un, MUE_DP_CMD, MUE_DP_CMD_WRITE); |
502 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { | | 509 | if (MUE_WAIT_SET(un, MUE_DP_SEL, MUE_DP_SEL_DPRDY, 0)) { |
503 | MUE_PRINTF(un, "timed out\n"); | | 510 | MUE_PRINTF(un, "timed out\n"); |
504 | return; | | 511 | return; |
505 | } | | 512 | } |
506 | } | | 513 | } |
507 | } | | 514 | } |
508 | | | 515 | |
509 | static void | | 516 | static void |
510 | mue_init_ltm(struct usbnet *un) | | 517 | mue_init_ltm(struct usbnet *un) |
511 | { | | 518 | { |
512 | 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 }; |
513 | uint8_t temp[2]; | | 520 | uint8_t temp[2]; |
514 | size_t i; | | 521 | size_t i; |
515 | | | 522 | |
516 | 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) { |
517 | if (mue_eeprom_present(un) && | | 524 | if (mue_eeprom_present(un) && |
518 | (mue_read_eeprom(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0)) { | | 525 | (mue_read_eeprom(un, temp, MUE_E2P_LTM_OFFSET, 2) == 0)) { |
519 | if (temp[0] != sizeof(idx)) { | | 526 | if (temp[0] != sizeof(idx)) { |
520 | DPRINTF(un, "EEPROM: unexpected size\n"); | | 527 | DPRINTF(un, "EEPROM: unexpected size\n"); |
521 | goto done; | | 528 | goto done; |
522 | } | | 529 | } |
523 | if (mue_read_eeprom(un, (uint8_t *)idx, temp[1] << 1, | | 530 | if (mue_read_eeprom(un, (uint8_t *)idx, temp[1] << 1, |
524 | sizeof(idx))) { | | 531 | sizeof(idx))) { |
525 | DPRINTF(un, "EEPROM: failed to read\n"); | | 532 | DPRINTF(un, "EEPROM: failed to read\n"); |
526 | goto done; | | 533 | goto done; |
527 | } | | 534 | } |
528 | DPRINTF(un, "success\n"); | | 535 | DPRINTF(un, "success\n"); |
529 | } 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) { |
530 | if (temp[0] != sizeof(idx)) { | | 537 | if (temp[0] != sizeof(idx)) { |
531 | DPRINTF(un, "OTP: unexpected size\n"); | | 538 | DPRINTF(un, "OTP: unexpected size\n"); |
532 | goto done; | | 539 | goto done; |
533 | } | | 540 | } |
534 | if (mue_read_otp(un, (uint8_t *)idx, temp[1] << 1, | | 541 | if (mue_read_otp(un, (uint8_t *)idx, temp[1] << 1, |
535 | sizeof(idx))) { | | 542 | sizeof(idx))) { |
536 | DPRINTF(un, "OTP: failed to read\n"); | | 543 | DPRINTF(un, "OTP: failed to read\n"); |
537 | goto done; | | 544 | goto done; |
538 | } | | 545 | } |
539 | DPRINTF(un, "success\n"); | | 546 | DPRINTF(un, "success\n"); |
540 | } else | | 547 | } else |
541 | DPRINTF(un, "nothing to do\n"); | | 548 | DPRINTF(un, "nothing to do\n"); |
542 | } else | | 549 | } else |
543 | DPRINTF(un, "nothing to do\n"); | | 550 | DPRINTF(un, "nothing to do\n"); |
544 | done: | | 551 | done: |
545 | for (i = 0; i < __arraycount(idx); i++) | | 552 | for (i = 0; i < __arraycount(idx); i++) |
546 | mue_csr_write(un, MUE_LTM_INDEX(i), idx[i]); | | 553 | mue_csr_write(un, MUE_LTM_INDEX(i), idx[i]); |
547 | } | | 554 | } |
548 | | | 555 | |
549 | static int | | 556 | static int |
550 | mue_chip_init(struct usbnet *un) | | 557 | mue_chip_init(struct usbnet *un) |
551 | { | | 558 | { |
552 | uint32_t val; | | 559 | uint32_t val; |
553 | | | 560 | |
554 | if ((un->un_flags & LAN7500) && | | 561 | if ((un->un_flags & LAN7500) && |
555 | 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)) { |
556 | MUE_PRINTF(un, "not ready\n"); | | 563 | MUE_PRINTF(un, "not ready\n"); |
557 | return ETIMEDOUT; | | 564 | return ETIMEDOUT; |
558 | } | | 565 | } |
559 | | | 566 | |
560 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_LRST); | | 567 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_LRST); |
561 | 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)) { |
562 | MUE_PRINTF(un, "timed out\n"); | | 569 | MUE_PRINTF(un, "timed out\n"); |
563 | return ETIMEDOUT; | | 570 | return ETIMEDOUT; |
564 | } | | 571 | } |
565 | | | 572 | |
566 | /* Respond to the IN token with a NAK. */ | | 573 | /* Respond to the IN token with a NAK. */ |
567 | if (un->un_flags & LAN7500) | | 574 | if (un->un_flags & LAN7500) |
568 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BIR); | | 575 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_BIR); |
569 | else | | 576 | else |
570 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BIR); | | 577 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BIR); |
571 | | | 578 | |
572 | if (un->un_flags & LAN7500) { | | 579 | if (un->un_flags & LAN7500) { |
573 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) | | 580 | if (un->un_udev->ud_speed == USB_SPEED_HIGH) |
574 | val = MUE_7500_HS_RX_BUFSIZE / | | 581 | val = MUE_7500_HS_RX_BUFSIZE / |
575 | MUE_HS_USB_PKT_SIZE; | | 582 | MUE_HS_USB_PKT_SIZE; |
576 | else | | 583 | else |
577 | val = MUE_7500_FS_RX_BUFSIZE / | | 584 | val = MUE_7500_FS_RX_BUFSIZE / |
578 | MUE_FS_USB_PKT_SIZE; | | 585 | MUE_FS_USB_PKT_SIZE; |
579 | mue_csr_write(un, MUE_7500_BURST_CAP, val); | | 586 | mue_csr_write(un, MUE_7500_BURST_CAP, val); |
580 | mue_csr_write(un, MUE_7500_BULKIN_DELAY, | | 587 | mue_csr_write(un, MUE_7500_BULKIN_DELAY, |
581 | MUE_7500_DEFAULT_BULKIN_DELAY); | | 588 | MUE_7500_DEFAULT_BULKIN_DELAY); |
582 | | | 589 | |
583 | 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); |
584 | | | 591 | |
585 | /* Set FIFO sizes. */ | | 592 | /* Set FIFO sizes. */ |
586 | val = (MUE_7500_MAX_RX_FIFO_SIZE - 512) / 512; | | 593 | val = (MUE_7500_MAX_RX_FIFO_SIZE - 512) / 512; |
587 | mue_csr_write(un, MUE_7500_FCT_RX_FIFO_END, val); | | 594 | mue_csr_write(un, MUE_7500_FCT_RX_FIFO_END, val); |
588 | val = (MUE_7500_MAX_TX_FIFO_SIZE - 512) / 512; | | 595 | val = (MUE_7500_MAX_TX_FIFO_SIZE - 512) / 512; |
589 | mue_csr_write(un, MUE_7500_FCT_TX_FIFO_END, val); | | 596 | mue_csr_write(un, MUE_7500_FCT_TX_FIFO_END, val); |
590 | } else { | | 597 | } else { |
591 | /* Init LTM. */ | | 598 | /* Init LTM. */ |
592 | mue_init_ltm(un); | | 599 | mue_init_ltm(un); |
593 | | | 600 | |
594 | val = MUE_7800_RX_BUFSIZE; | | 601 | val = MUE_7800_RX_BUFSIZE; |
595 | switch (un->un_udev->ud_speed) { | | 602 | switch (un->un_udev->ud_speed) { |
596 | case USB_SPEED_SUPER: | | 603 | case USB_SPEED_SUPER: |
597 | val /= MUE_SS_USB_PKT_SIZE; | | 604 | val /= MUE_SS_USB_PKT_SIZE; |
598 | break; | | 605 | break; |
599 | case USB_SPEED_HIGH: | | 606 | case USB_SPEED_HIGH: |
600 | val /= MUE_HS_USB_PKT_SIZE; | | 607 | val /= MUE_HS_USB_PKT_SIZE; |
601 | break; | | 608 | break; |
602 | default: | | 609 | default: |
603 | val /= MUE_FS_USB_PKT_SIZE; | | 610 | val /= MUE_FS_USB_PKT_SIZE; |
604 | break; | | 611 | break; |
605 | } | | 612 | } |
606 | mue_csr_write(un, MUE_7800_BURST_CAP, val); | | 613 | mue_csr_write(un, MUE_7800_BURST_CAP, val); |
607 | mue_csr_write(un, MUE_7800_BULKIN_DELAY, | | 614 | mue_csr_write(un, MUE_7800_BULKIN_DELAY, |
608 | MUE_7800_DEFAULT_BULKIN_DELAY); | | 615 | MUE_7800_DEFAULT_BULKIN_DELAY); |
609 | | | 616 | |
610 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_MEF); | | 617 | MUE_SETBIT(un, MUE_HW_CFG, MUE_HW_CFG_MEF); |
611 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BCE); | | 618 | MUE_SETBIT(un, MUE_USB_CFG0, MUE_USB_CFG0_BCE); |
612 | | | 619 | |
613 | /* | | 620 | /* |
614 | * 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 |
615 | * is already the default value. But we initialize it to the | | 622 | * is already the default value. But we initialize it to the |
616 | * same value anyways, as that's what the Linux driver does. | | 623 | * same value anyways, as that's what the Linux driver does. |
617 | */ | | 624 | */ |
618 | val = (MUE_7800_MAX_RX_FIFO_SIZE - 512) / 512; | | 625 | val = (MUE_7800_MAX_RX_FIFO_SIZE - 512) / 512; |
619 | mue_csr_write(un, MUE_7800_FCT_RX_FIFO_END, val); | | 626 | mue_csr_write(un, MUE_7800_FCT_RX_FIFO_END, val); |
620 | val = (MUE_7800_MAX_TX_FIFO_SIZE - 512) / 512; | | 627 | val = (MUE_7800_MAX_TX_FIFO_SIZE - 512) / 512; |
621 | mue_csr_write(un, MUE_7800_FCT_TX_FIFO_END, val); | | 628 | mue_csr_write(un, MUE_7800_FCT_TX_FIFO_END, val); |
622 | } | | 629 | } |
623 | | | 630 | |
624 | /* Enabling interrupts. */ | | 631 | /* Enabling interrupts. */ |
625 | mue_csr_write(un, MUE_INT_STATUS, ~0); | | 632 | mue_csr_write(un, MUE_INT_STATUS, ~0); |
626 | | | 633 | |
627 | mue_csr_write(un, (un->un_flags & LAN7500) ? | | 634 | mue_csr_write(un, (un->un_flags & LAN7500) ? |
628 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, 0); | | 635 | MUE_7500_FCT_FLOW : MUE_7800_FCT_FLOW, 0); |
629 | mue_csr_write(un, MUE_FLOW, 0); | | 636 | mue_csr_write(un, MUE_FLOW, 0); |
630 | | | 637 | |
631 | /* Reset PHY. */ | | 638 | /* Reset PHY. */ |
632 | MUE_SETBIT(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST); | | 639 | MUE_SETBIT(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST); |
633 | if (MUE_WAIT_CLR(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST, 0)) { | | 640 | if (MUE_WAIT_CLR(un, MUE_PMT_CTL, MUE_PMT_CTL_PHY_RST, 0)) { |
634 | MUE_PRINTF(un, "PHY not ready\n"); | | 641 | MUE_PRINTF(un, "PHY not ready\n"); |
635 | return ETIMEDOUT; | | 642 | return ETIMEDOUT; |
636 | } | | 643 | } |
637 | | | 644 | |
638 | /* LAN7801 only has RGMII mode. */ | | 645 | /* LAN7801 only has RGMII mode. */ |
639 | if (un->un_flags & LAN7801) | | 646 | if (un->un_flags & LAN7801) |
640 | MUE_CLRBIT(un, MUE_MAC_CR, MUE_MAC_CR_GMII_EN); | | 647 | MUE_CLRBIT(un, MUE_MAC_CR, MUE_MAC_CR_GMII_EN); |
641 | | | 648 | |
642 | if ((un->un_flags & (LAN7500 | LAN7800)) || | | 649 | if ((un->un_flags & (LAN7500 | LAN7800)) || |
643 | !mue_eeprom_present(un)) { | | 650 | !mue_eeprom_present(un)) { |
644 | /* Allow MAC to detect speed and duplex from PHY. */ | | 651 | /* Allow MAC to detect speed and duplex from PHY. */ |
645 | MUE_SETBIT(un, MUE_MAC_CR, MUE_MAC_CR_AUTO_SPEED | | | 652 | MUE_SETBIT(un, MUE_MAC_CR, MUE_MAC_CR_AUTO_SPEED | |
646 | MUE_MAC_CR_AUTO_DUPLEX); | | 653 | MUE_MAC_CR_AUTO_DUPLEX); |
647 | } | | 654 | } |
648 | | | 655 | |
649 | MUE_SETBIT(un, MUE_MAC_TX, MUE_MAC_TX_TXEN); | | 656 | MUE_SETBIT(un, MUE_MAC_TX, MUE_MAC_TX_TXEN); |
650 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | | 657 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? |
651 | 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); |
652 | | | 659 | |
653 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? | | 660 | MUE_SETBIT(un, (un->un_flags & LAN7500) ? |
654 | 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); |
655 | | | 662 | |
656 | /* Set default GPIO/LED settings only if no EEPROM is detected. */ | | 663 | /* Set default GPIO/LED settings only if no EEPROM is detected. */ |
657 | if ((un->un_flags & LAN7500) && !mue_eeprom_present(un)) { | | 664 | if ((un->un_flags & LAN7500) && !mue_eeprom_present(un)) { |
658 | 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); |
659 | MUE_SETBIT(un, MUE_LED_CFG, | | 666 | MUE_SETBIT(un, MUE_LED_CFG, |
660 | MUE_LED_CFG_LEDGPIO_EN | MUE_LED_CFG_LED2_FUN_SEL); | | 667 | MUE_LED_CFG_LEDGPIO_EN | MUE_LED_CFG_LED2_FUN_SEL); |
661 | } | | 668 | } |
662 | | | 669 | |
663 | /* XXX We assume two LEDs at least when EEPROM is missing. */ | | 670 | /* XXX We assume two LEDs at least when EEPROM is missing. */ |
664 | if (un->un_flags & LAN7800 && | | 671 | if (un->un_flags & LAN7800 && |
665 | !mue_eeprom_present(un)) | | 672 | !mue_eeprom_present(un)) |
666 | MUE_SETBIT(un, MUE_HW_CFG, | | 673 | MUE_SETBIT(un, MUE_HW_CFG, |
667 | MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN); | | 674 | MUE_HW_CFG_LED0_EN | MUE_HW_CFG_LED1_EN); |
668 | | | 675 | |
669 | return 0; | | 676 | return 0; |
670 | } | | 677 | } |
671 | | | 678 | |
672 | static void | | 679 | static void |
673 | mue_set_macaddr(struct usbnet *un) | | 680 | mue_set_macaddr(struct usbnet *un) |
674 | { | | 681 | { |
675 | struct ifnet * const ifp = usbnet_ifp(un); | | 682 | struct ifnet * const ifp = usbnet_ifp(un); |
676 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | | 683 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); |
677 | uint32_t lo, hi; | | 684 | uint32_t lo, hi; |
678 | | | 685 | |
679 | lo = MUE_ENADDR_LO(enaddr); | | 686 | lo = MUE_ENADDR_LO(enaddr); |
680 | hi = MUE_ENADDR_HI(enaddr); | | 687 | hi = MUE_ENADDR_HI(enaddr); |
681 | | | 688 | |
682 | mue_csr_write(un, MUE_RX_ADDRL, lo); | | 689 | mue_csr_write(un, MUE_RX_ADDRL, lo); |
683 | mue_csr_write(un, MUE_RX_ADDRH, hi); | | 690 | mue_csr_write(un, MUE_RX_ADDRH, hi); |
684 | } | | 691 | } |
685 | | | 692 | |
686 | static int | | 693 | static int |
687 | mue_get_macaddr(struct usbnet *un, prop_dictionary_t dict) | | 694 | mue_get_macaddr(struct usbnet *un, prop_dictionary_t dict) |
688 | { | | 695 | { |
689 | prop_data_t eaprop; | | 696 | prop_data_t eaprop; |
690 | uint32_t low, high; | | 697 | uint32_t low, high; |
691 | | | 698 | |
692 | if (!(un->un_flags & LAN7500)) { | | 699 | if (!(un->un_flags & LAN7500)) { |
693 | low = mue_csr_read(un, MUE_RX_ADDRL); | | 700 | low = mue_csr_read(un, MUE_RX_ADDRL); |
694 | high = mue_csr_read(un, MUE_RX_ADDRH); | | 701 | high = mue_csr_read(un, MUE_RX_ADDRH); |
695 | un->un_eaddr[5] = (uint8_t)((high >> 8) & 0xff); | | 702 | un->un_eaddr[5] = (uint8_t)((high >> 8) & 0xff); |
696 | un->un_eaddr[4] = (uint8_t)((high) & 0xff); | | 703 | un->un_eaddr[4] = (uint8_t)((high) & 0xff); |
697 | un->un_eaddr[3] = (uint8_t)((low >> 24) & 0xff); | | 704 | un->un_eaddr[3] = (uint8_t)((low >> 24) & 0xff); |
698 | un->un_eaddr[2] = (uint8_t)((low >> 16) & 0xff); | | 705 | un->un_eaddr[2] = (uint8_t)((low >> 16) & 0xff); |
699 | un->un_eaddr[1] = (uint8_t)((low >> 8) & 0xff); | | 706 | un->un_eaddr[1] = (uint8_t)((low >> 8) & 0xff); |
700 | un->un_eaddr[0] = (uint8_t)((low) & 0xff); | | 707 | un->un_eaddr[0] = (uint8_t)((low) & 0xff); |
701 | if (ETHER_IS_VALID(un->un_eaddr)) | | 708 | if (ETHER_IS_VALID(un->un_eaddr)) |
702 | return 0; | | 709 | return 0; |
703 | else | | 710 | else |
704 | DPRINTF(un, "registers: %s\n", | | 711 | DPRINTF(un, "registers: %s\n", |
705 | ether_sprintf(un->un_eaddr)); | | 712 | ether_sprintf(un->un_eaddr)); |
706 | } | | 713 | } |
707 | | | 714 | |
708 | 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, |
709 | MUE_E2P_MAC_OFFSET, ETHER_ADDR_LEN)) { | | 716 | MUE_E2P_MAC_OFFSET, ETHER_ADDR_LEN)) { |
710 | if (ETHER_IS_VALID(un->un_eaddr)) | | 717 | if (ETHER_IS_VALID(un->un_eaddr)) |
711 | return 0; | | 718 | return 0; |
712 | else | | 719 | else |
713 | DPRINTF(un, "EEPROM: %s\n", | | 720 | DPRINTF(un, "EEPROM: %s\n", |
714 | ether_sprintf(un->un_eaddr)); | | 721 | ether_sprintf(un->un_eaddr)); |
715 | } | | 722 | } |
716 | | | 723 | |
717 | 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, |
718 | ETHER_ADDR_LEN) == 0) { | | 725 | ETHER_ADDR_LEN) == 0) { |
719 | if (ETHER_IS_VALID(un->un_eaddr)) | | 726 | if (ETHER_IS_VALID(un->un_eaddr)) |
720 | return 0; | | 727 | return 0; |
721 | else | | 728 | else |
722 | DPRINTF(un, "OTP: %s\n", | | 729 | DPRINTF(un, "OTP: %s\n", |
723 | ether_sprintf(un->un_eaddr)); | | 730 | ether_sprintf(un->un_eaddr)); |
724 | } | | 731 | } |
725 | | | 732 | |
726 | /* | | 733 | /* |
727 | * 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. |
728 | * Otherwise, MAC address for internal device can be assinged to | | 735 | * Otherwise, MAC address for internal device can be assinged to |
729 | * external devices on Raspberry Pi, for example. | | 736 | * external devices on Raspberry Pi, for example. |
730 | */ | | 737 | */ |
731 | eaprop = prop_dictionary_get(dict, "mac-address"); | | 738 | eaprop = prop_dictionary_get(dict, "mac-address"); |
732 | if (eaprop != NULL) { | | 739 | if (eaprop != NULL) { |
733 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); | | 740 | KASSERT(prop_object_type(eaprop) == PROP_TYPE_DATA); |
734 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); | | 741 | KASSERT(prop_data_size(eaprop) == ETHER_ADDR_LEN); |
735 | memcpy(un->un_eaddr, prop_data_value(eaprop), | | 742 | memcpy(un->un_eaddr, prop_data_value(eaprop), |
736 | ETHER_ADDR_LEN); | | 743 | ETHER_ADDR_LEN); |
737 | if (ETHER_IS_VALID(un->un_eaddr)) | | 744 | if (ETHER_IS_VALID(un->un_eaddr)) |
738 | return 0; | | 745 | return 0; |
739 | else | | 746 | else |
740 | DPRINTF(un, "prop_dictionary_get: %s\n", | | 747 | DPRINTF(un, "prop_dictionary_get: %s\n", |
741 | ether_sprintf(un->un_eaddr)); | | 748 | ether_sprintf(un->un_eaddr)); |
742 | } | | 749 | } |
743 | | | 750 | |
744 | return 1; | | 751 | return 1; |
745 | } | | 752 | } |
746 | | | 753 | |
747 | | | 754 | |
748 | /* | | 755 | /* |
749 | * Probe for a Microchip chip. | | 756 | * Probe for a Microchip chip. |
750 | */ | | 757 | */ |
751 | static int | | 758 | static int |
752 | mue_match(device_t parent, cfdata_t match, void *aux) | | 759 | mue_match(device_t parent, cfdata_t match, void *aux) |
753 | { | | 760 | { |
754 | struct usb_attach_arg *uaa = aux; | | 761 | struct usb_attach_arg *uaa = aux; |
755 | | | 762 | |
756 | return (MUE_LOOKUP(uaa) != NULL) ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; | | 763 | return (MUE_LOOKUP(uaa) != NULL) ? UMATCH_VENDOR_PRODUCT : UMATCH_NONE; |
757 | } | | 764 | } |
758 | | | 765 | |
759 | static void | | 766 | static void |
760 | mue_attach(device_t parent, device_t self, void *aux) | | 767 | mue_attach(device_t parent, device_t self, void *aux) |
761 | { | | 768 | { |
762 | USBNET_MII_DECL_DEFAULT(unm); | | 769 | USBNET_MII_DECL_DEFAULT(unm); |
763 | struct usbnet * const un = device_private(self); | | | |
764 | prop_dictionary_t dict = device_properties(self); | | 770 | prop_dictionary_t dict = device_properties(self); |
| | | 771 | struct mue_softc * const sc = device_private(self); |
765 | struct usb_attach_arg *uaa = aux; | | 772 | struct usb_attach_arg *uaa = aux; |
766 | struct usbd_device *dev = uaa->uaa_device; | | 773 | struct usbd_device *dev = uaa->uaa_device; |
| | | 774 | struct usbnet *un = &sc->sc_un; |
767 | usb_interface_descriptor_t *id; | | 775 | usb_interface_descriptor_t *id; |
768 | usb_endpoint_descriptor_t *ed; | | 776 | usb_endpoint_descriptor_t *ed; |
769 | char *devinfop; | | | |
770 | usbd_status err; | | 777 | usbd_status err; |
| | | 778 | char *devinfop; |
771 | const char *descr; | | 779 | const char *descr; |
772 | uint32_t id_rev; | | 780 | uint32_t id_rev; |
773 | uint8_t i; | | 781 | uint8_t i; |
774 | unsigned rx_list_cnt, tx_list_cnt; | | 782 | unsigned rx_list_cnt, tx_list_cnt; |
775 | unsigned rx_bufsz; | | 783 | unsigned rx_bufsz; |
776 | | | 784 | |
777 | aprint_naive("\n"); | | 785 | aprint_naive("\n"); |
778 | aprint_normal("\n"); | | 786 | aprint_normal("\n"); |
779 | devinfop = usbd_devinfo_alloc(dev, 0); | | 787 | devinfop = usbd_devinfo_alloc(dev, 0); |
780 | aprint_normal_dev(self, "%s\n", devinfop); | | 788 | aprint_normal_dev(self, "%s\n", devinfop); |
781 | usbd_devinfo_free(devinfop); | | 789 | usbd_devinfo_free(devinfop); |
782 | | | 790 | |
783 | un->un_dev = self; | | 791 | un->un_dev = self; |
784 | un->un_udev = dev; | | 792 | un->un_udev = dev; |
785 | un->un_sc = un; | | 793 | un->un_sc = sc; /* @@! */ |
786 | un->un_ops = &mue_ops; | | 794 | un->un_ops = &mue_ops; |
787 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; | | 795 | un->un_rx_xfer_flags = USBD_SHORT_XFER_OK; |
788 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; | | 796 | un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER; |
789 | | | 797 | |
790 | #define MUE_CONFIG_NO 1 | | 798 | #define MUE_CONFIG_NO 1 |
791 | err = usbd_set_config_no(dev, MUE_CONFIG_NO, 1); | | 799 | err = usbd_set_config_no(dev, MUE_CONFIG_NO, 1); |
792 | if (err) { | | 800 | if (err) { |
793 | aprint_error_dev(self, "failed to set configuration: %s\n", | | 801 | aprint_error_dev(self, "failed to set configuration: %s\n", |
794 | usbd_errstr(err)); | | 802 | usbd_errstr(err)); |
795 | return; | | 803 | return; |
796 | } | | 804 | } |
797 | | | 805 | |
798 | #define MUE_IFACE_IDX 0 | | 806 | #define MUE_IFACE_IDX 0 |
799 | err = usbd_device2interface_handle(dev, MUE_IFACE_IDX, &un->un_iface); | | 807 | err = usbd_device2interface_handle(dev, MUE_IFACE_IDX, &un->un_iface); |
800 | if (err) { | | 808 | if (err) { |
801 | aprint_error_dev(self, "failed to get interface handle: %s\n", | | 809 | aprint_error_dev(self, "failed to get interface handle: %s\n", |
802 | usbd_errstr(err)); | | 810 | usbd_errstr(err)); |
803 | return; | | 811 | return; |
804 | } | | 812 | } |
805 | | | 813 | |
806 | un->un_flags = MUE_LOOKUP(uaa)->mue_flags; | | 814 | un->un_flags = MUE_LOOKUP(uaa)->mue_flags; |
807 | | | 815 | |
808 | /* Decide on what our bufsize will be. */ | | 816 | /* Decide on what our bufsize will be. */ |
809 | if (un->un_flags & LAN7500) { | | 817 | if (un->un_flags & LAN7500) { |
810 | rx_bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? | | 818 | rx_bufsz = (un->un_udev->ud_speed == USB_SPEED_HIGH) ? |
811 | MUE_7500_HS_RX_BUFSIZE : MUE_7500_FS_RX_BUFSIZE; | | 819 | MUE_7500_HS_RX_BUFSIZE : MUE_7500_FS_RX_BUFSIZE; |
812 | rx_list_cnt = 1; | | 820 | rx_list_cnt = 1; |
813 | tx_list_cnt = 1; | | 821 | tx_list_cnt = 1; |
814 | } else { | | 822 | } else { |
815 | rx_bufsz = MUE_7800_RX_BUFSIZE; | | 823 | rx_bufsz = MUE_7800_RX_BUFSIZE; |
816 | rx_list_cnt = MUE_RX_LIST_CNT; | | 824 | rx_list_cnt = MUE_RX_LIST_CNT; |
817 | tx_list_cnt = MUE_TX_LIST_CNT; | | 825 | tx_list_cnt = MUE_TX_LIST_CNT; |
818 | } | | 826 | } |
819 | | | 827 | |
820 | un->un_rx_list_cnt = rx_list_cnt; | | 828 | un->un_rx_list_cnt = rx_list_cnt; |
821 | un->un_tx_list_cnt = tx_list_cnt; | | 829 | un->un_tx_list_cnt = tx_list_cnt; |
822 | un->un_rx_bufsz = rx_bufsz; | | 830 | un->un_rx_bufsz = rx_bufsz; |
823 | un->un_tx_bufsz = MUE_TX_BUFSIZE; | | 831 | un->un_tx_bufsz = MUE_TX_BUFSIZE; |
824 | | | 832 | |
825 | /* Find endpoints. */ | | 833 | /* Find endpoints. */ |
826 | id = usbd_get_interface_descriptor(un->un_iface); | | 834 | id = usbd_get_interface_descriptor(un->un_iface); |
827 | for (i = 0; i < id->bNumEndpoints; i++) { | | 835 | for (i = 0; i < id->bNumEndpoints; i++) { |
828 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); | | 836 | ed = usbd_interface2endpoint_descriptor(un->un_iface, i); |
829 | if (ed == NULL) { | | 837 | if (ed == NULL) { |
830 | aprint_error_dev(self, "failed to get ep %hhd\n", i); | | 838 | aprint_error_dev(self, "failed to get ep %hhd\n", i); |
831 | return; | | 839 | return; |
832 | } | | 840 | } |
833 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | | 841 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && |
834 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | | 842 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { |
835 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; | | 843 | un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress; |
836 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | | 844 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && |
837 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | | 845 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { |
838 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; | | 846 | un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress; |
839 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | | 847 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && |
840 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { | | 848 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { |
841 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; | | 849 | un->un_ed[USBNET_ENDPT_INTR] = ed->bEndpointAddress; |
842 | } | | 850 | } |
843 | } | | 851 | } |
844 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || | | 852 | if (un->un_ed[USBNET_ENDPT_RX] == 0 || |
845 | un->un_ed[USBNET_ENDPT_TX] == 0 || | | 853 | un->un_ed[USBNET_ENDPT_TX] == 0 || |
846 | un->un_ed[USBNET_ENDPT_INTR] == 0) { | | 854 | un->un_ed[USBNET_ENDPT_INTR] == 0) { |
847 | aprint_error_dev(self, "failed to find endpoints\n"); | | 855 | aprint_error_dev(self, "failed to find endpoints\n"); |
848 | return; | | 856 | return; |
849 | } | | 857 | } |
850 | | | 858 | |
851 | /* Set these up now for mue_cmd(). */ | | 859 | /* Set these up now for mue_cmd(). */ |
852 | usbnet_attach(un, "muedet"); | | 860 | usbnet_attach(un, "muedet"); |
853 | | | 861 | |
854 | un->un_phyno = 1; | | 862 | un->un_phyno = 1; |
855 | | | 863 | |
856 | if (mue_chip_init(un)) { | | 864 | if (mue_chip_init(un)) { |
857 | aprint_error_dev(self, "failed to initialize chip\n"); | | 865 | aprint_error_dev(self, "failed to initialize chip\n"); |
858 | return; | | 866 | return; |
859 | } | | 867 | } |
860 | | | 868 | |
861 | /* A Microchip chip was detected. Inform the world. */ | | 869 | /* A Microchip chip was detected. Inform the world. */ |
862 | id_rev = mue_csr_read(un, MUE_ID_REV); | | 870 | id_rev = mue_csr_read(un, MUE_ID_REV); |
863 | descr = (un->un_flags & LAN7500) ? "LAN7500" : "LAN7800"; | | 871 | descr = (un->un_flags & LAN7500) ? "LAN7500" : "LAN7800"; |
864 | aprint_normal_dev(self, "%s id %#x rev %#x\n", descr, | | 872 | aprint_normal_dev(self, "%s id %#x rev %#x\n", descr, |
865 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_ID), | | 873 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_ID), |
866 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_REV)); | | 874 | (unsigned)__SHIFTOUT(id_rev, MUE_ID_REV_REV)); |
867 | | | 875 | |
868 | if (mue_get_macaddr(un, dict)) { | | 876 | if (mue_get_macaddr(un, dict)) { |
869 | aprint_error_dev(self, "failed to read MAC address\n"); | | 877 | aprint_error_dev(self, "failed to read MAC address\n"); |
870 | return; | | 878 | return; |
871 | } | | 879 | } |
872 | | | 880 | |
873 | struct ifnet *ifp = usbnet_ifp(un); | | 881 | struct ifnet *ifp = usbnet_ifp(un); |
874 | ifp->if_capabilities = IFCAP_TSOv4 | IFCAP_TSOv6 | | | 882 | ifp->if_capabilities = IFCAP_TSOv4 | IFCAP_TSOv6 | |
875 | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | | | 883 | IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx | |
876 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | | | 884 | IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | |
877 | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | | | 885 | IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx | |
878 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | | | 886 | IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx | |
879 | IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; | | 887 | IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx; |
880 | | | 888 | |
881 | struct ethercom *ec = usbnet_ec(un); | | 889 | struct ethercom *ec = usbnet_ec(un); |
882 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; | | 890 | ec->ec_capabilities = ETHERCAP_VLAN_MTU; |
883 | #if 0 /* XXX not yet */ | | 891 | #if 0 /* XXX not yet */ |
884 | ec->ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU; | | 892 | ec->ec_capabilities = ETHERCAP_VLAN_MTU | ETHERCAP_JUMBO_MTU; |
885 | #endif | | 893 | #endif |
886 | | | 894 | |
| | | 895 | unm.un_mii_phyloc = un->un_phyno; /* use internal PHY 1 */ |
| | | 896 | unm.un_mii_flags |= MIIF_DOPAUSE; /* use PAUSE cap. */ |
887 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, | | 897 | usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST, |
888 | 0, &unm); | | 898 | 0, &unm); |
889 | } | | 899 | } |
890 | | | 900 | |
891 | static unsigned | | 901 | static unsigned |
892 | mue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) | | 902 | mue_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c) |
893 | { | | 903 | { |
894 | struct ifnet * const ifp = usbnet_ifp(un); | | 904 | struct ifnet * const ifp = usbnet_ifp(un); |
895 | struct mue_txbuf_hdr hdr; | | 905 | struct mue_txbuf_hdr hdr; |
896 | uint32_t tx_cmd_a, tx_cmd_b; | | 906 | uint32_t tx_cmd_a, tx_cmd_b; |
897 | int csum, len, rv; | | 907 | int csum, len, rv; |
898 | bool tso, ipe, tpe; | | 908 | bool tso, ipe, tpe; |
899 | | | 909 | |
900 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) | | 910 | if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(hdr)) |
901 | return 0; | | 911 | return 0; |
902 | | | 912 | |
903 | csum = m->m_pkthdr.csum_flags; | | 913 | csum = m->m_pkthdr.csum_flags; |
904 | tso = csum & (M_CSUM_TSOv4 | M_CSUM_TSOv6); | | 914 | tso = csum & (M_CSUM_TSOv4 | M_CSUM_TSOv6); |
905 | ipe = csum & M_CSUM_IPv4; | | 915 | ipe = csum & M_CSUM_IPv4; |
906 | tpe = csum & (M_CSUM_TCPv4 | M_CSUM_UDPv4 | | | 916 | tpe = csum & (M_CSUM_TCPv4 | M_CSUM_UDPv4 | |
907 | M_CSUM_TCPv6 | M_CSUM_UDPv6); | | 917 | M_CSUM_TCPv6 | M_CSUM_UDPv6); |
908 | | | 918 | |
909 | len = m->m_pkthdr.len; | | 919 | len = m->m_pkthdr.len; |
910 | if (__predict_false((!tso && len > (int)MUE_FRAME_LEN(ifp->if_mtu)) || | | 920 | if (__predict_false((!tso && len > (int)MUE_FRAME_LEN(ifp->if_mtu)) || |
911 | ( tso && len > MUE_TSO_FRAME_LEN))) { | | 921 | ( tso && len > MUE_TSO_FRAME_LEN))) { |
912 | MUE_PRINTF(un, "packet length %d\n too long", len); | | 922 | MUE_PRINTF(un, "packet length %d\n too long", len); |
913 | return 0; | | 923 | return 0; |
914 | } | | 924 | } |
915 | | | 925 | |
916 | KASSERT((len & ~MUE_TX_CMD_A_LEN_MASK) == 0); | | 926 | KASSERT((len & ~MUE_TX_CMD_A_LEN_MASK) == 0); |
917 | tx_cmd_a = len | MUE_TX_CMD_A_FCS; | | 927 | tx_cmd_a = len | MUE_TX_CMD_A_FCS; |
918 | | | 928 | |
919 | if (tso) { | | 929 | if (tso) { |
920 | tx_cmd_a |= MUE_TX_CMD_A_LSO; | | 930 | tx_cmd_a |= MUE_TX_CMD_A_LSO; |
921 | if (__predict_true(m->m_pkthdr.segsz > MUE_TX_MSS_MIN)) | | 931 | if (__predict_true(m->m_pkthdr.segsz > MUE_TX_MSS_MIN)) |
922 | tx_cmd_b = m->m_pkthdr.segsz; | | 932 | tx_cmd_b = m->m_pkthdr.segsz; |
923 | else | | 933 | else |
924 | tx_cmd_b = MUE_TX_MSS_MIN; | | 934 | tx_cmd_b = MUE_TX_MSS_MIN; |
925 | tx_cmd_b <<= MUE_TX_CMD_B_MSS_SHIFT; | | 935 | tx_cmd_b <<= MUE_TX_CMD_B_MSS_SHIFT; |
926 | KASSERT((tx_cmd_b & ~MUE_TX_CMD_B_MSS_MASK) == 0); | | 936 | KASSERT((tx_cmd_b & ~MUE_TX_CMD_B_MSS_MASK) == 0); |
927 | rv = mue_prepare_tso(un, m); | | 937 | rv = mue_prepare_tso(un, m); |
928 | if (__predict_false(rv)) | | 938 | if (__predict_false(rv)) |
929 | return 0; | | 939 | return 0; |
930 | } else { | | 940 | } else { |
931 | if (ipe) | | 941 | if (ipe) |
932 | tx_cmd_a |= MUE_TX_CMD_A_IPE; | | 942 | tx_cmd_a |= MUE_TX_CMD_A_IPE; |
933 | if (tpe) | | 943 | if (tpe) |
934 | tx_cmd_a |= MUE_TX_CMD_A_TPE; | | 944 | tx_cmd_a |= MUE_TX_CMD_A_TPE; |
935 | tx_cmd_b = 0; | | 945 | tx_cmd_b = 0; |
936 | } | | 946 | } |
937 | | | 947 | |
938 | hdr.tx_cmd_a = htole32(tx_cmd_a); | | 948 | hdr.tx_cmd_a = htole32(tx_cmd_a); |
939 | hdr.tx_cmd_b = htole32(tx_cmd_b); | | 949 | hdr.tx_cmd_b = htole32(tx_cmd_b); |
940 | | | 950 | |
941 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); | | 951 | memcpy(c->unc_buf, &hdr, sizeof(hdr)); |
942 | m_copydata(m, 0, len, c->unc_buf + sizeof(hdr)); | | 952 | m_copydata(m, 0, len, c->unc_buf + sizeof(hdr)); |
943 | | | 953 | |
944 | return len + sizeof(hdr); | | 954 | return len + sizeof(hdr); |
945 | } | | 955 | } |
946 | | | 956 | |
947 | /* | | 957 | /* |
948 | * L3 length field should be cleared. | | 958 | * L3 length field should be cleared. |
949 | */ | | 959 | */ |
950 | static int | | 960 | static int |
951 | mue_prepare_tso(struct usbnet *un, struct mbuf *m) | | 961 | mue_prepare_tso(struct usbnet *un, struct mbuf *m) |
952 | { | | 962 | { |
953 | struct ether_header *eh; | | 963 | struct ether_header *eh; |
954 | struct ip *ip; | | 964 | struct ip *ip; |
955 | struct ip6_hdr *ip6; | | 965 | struct ip6_hdr *ip6; |
956 | uint16_t type, len = 0; | | 966 | uint16_t type, len = 0; |
957 | int off; | | 967 | int off; |
958 | | | 968 | |
959 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { | | 969 | if (__predict_true(m->m_len >= (int)sizeof(*eh))) { |
960 | eh = mtod(m, struct ether_header *); | | 970 | eh = mtod(m, struct ether_header *); |
961 | type = eh->ether_type; | | 971 | type = eh->ether_type; |
962 | } else | | 972 | } else |
963 | m_copydata(m, offsetof(struct ether_header, ether_type), | | 973 | m_copydata(m, offsetof(struct ether_header, ether_type), |
964 | sizeof(type), &type); | | 974 | sizeof(type), &type); |
965 | switch (type = htons(type)) { | | 975 | switch (type = htons(type)) { |
966 | case ETHERTYPE_IP: | | 976 | case ETHERTYPE_IP: |
967 | case ETHERTYPE_IPV6: | | 977 | case ETHERTYPE_IPV6: |
968 | off = ETHER_HDR_LEN; | | 978 | off = ETHER_HDR_LEN; |
969 | break; | | 979 | break; |
970 | case ETHERTYPE_VLAN: | | 980 | case ETHERTYPE_VLAN: |
971 | off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; | | 981 | off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; |
972 | break; | | 982 | break; |
973 | default: | | 983 | default: |
974 | return EINVAL; | | 984 | return EINVAL; |
975 | } | | 985 | } |
976 | | | 986 | |
977 | if (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) { | | 987 | if (m->m_pkthdr.csum_flags & M_CSUM_TSOv4) { |
978 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip))) { | | 988 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip))) { |
979 | ip = (void *)(mtod(m, char *) + off); | | 989 | ip = (void *)(mtod(m, char *) + off); |
980 | ip->ip_len = 0; | | 990 | ip->ip_len = 0; |
981 | } else | | 991 | } else |
982 | m_copyback(m, off + offsetof(struct ip, ip_len), | | 992 | m_copyback(m, off + offsetof(struct ip, ip_len), |
983 | sizeof(len), &len); | | 993 | sizeof(len), &len); |
984 | } else { | | 994 | } else { |
985 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip6))) { | | 995 | if (__predict_true(m->m_len >= off + (int)sizeof(*ip6))) { |
986 | ip6 = (void *)(mtod(m, char *) + off); | | 996 | ip6 = (void *)(mtod(m, char *) + off); |
987 | ip6->ip6_plen = 0; | | 997 | ip6->ip6_plen = 0; |
988 | } else | | 998 | } else |
989 | m_copyback(m, off + offsetof(struct ip6_hdr, ip6_plen), | | 999 | m_copyback(m, off + offsetof(struct ip6_hdr, ip6_plen), |
990 | sizeof(len), &len); | | 1000 | sizeof(len), &len); |
991 | } | | 1001 | } |
992 | return 0; | | 1002 | return 0; |
993 | } | | 1003 | } |
994 | | | 1004 | |
995 | static void | | 1005 | static void |
996 | mue_setiff_locked(struct usbnet *un) | | 1006 | mue_setiff_locked(struct usbnet *un) |
997 | { | | 1007 | { |
998 | struct ethercom *ec = usbnet_ec(un); | | 1008 | struct ethercom *ec = usbnet_ec(un); |
999 | struct ifnet * const ifp = usbnet_ifp(un); | | 1009 | struct ifnet * const ifp = usbnet_ifp(un); |
1000 | const uint8_t *enaddr = CLLADDR(ifp->if_sadl); | | | |
1001 | struct ether_multi *enm; | | | |
1002 | struct ether_multistep step; | | 1010 | struct ether_multistep step; |
1003 | uint32_t pfiltbl[MUE_NUM_ADDR_FILTX][2]; | | 1011 | struct ether_multi *enm; |
1004 | uint32_t hashtbl[MUE_DP_SEL_VHF_HASH_LEN]; | | 1012 | uint32_t mchash[MUE_DP_SEL_VHF_HASH_LEN]; |
1005 | uint32_t reg, rxfilt, h, hireg, loreg; | | 1013 | uint32_t rfe, rxfilt, crc, hireg, loreg; |
1006 | size_t i; | | 1014 | size_t i; |
1007 | | | 1015 | |
1008 | if (usbnet_isdying(un)) | | 1016 | if (usbnet_isdying(un)) |
1009 | return; | | 1017 | return; |
1010 | | | 1018 | |
1011 | /* Clear perfect filter and hash tables. */ | | 1019 | for (i = 1; i < MUE_NUM_ADDR_FILTX; i++) { |
1012 | memset(pfiltbl, 0, sizeof(pfiltbl)); | | 1020 | hireg = (un->un_flags & LAN7500) |
1013 | memset(hashtbl, 0, sizeof(hashtbl)); | | 1021 | ? MUE_7500_ADDR_FILTX(i) : MUE_7800_ADDR_FILTX(i); |
| | | 1022 | mue_csr_write(un, hireg, 0); |
| | | 1023 | } |
| | | 1024 | memset(mchash, 0, sizeof(mchash)); |
1014 | | | 1025 | |
1015 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | | 1026 | rfe = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; |
1016 | rxfilt = mue_csr_read(un, reg); | | 1027 | rxfilt = mue_csr_read(un, rfe); |
1017 | rxfilt &= ~(MUE_RFE_CTL_PERFECT | MUE_RFE_CTL_MULTICAST_HASH | | | 1028 | rxfilt &= ~(MUE_RFE_CTL_MULTICAST_HASH | |
1018 | MUE_RFE_CTL_UNICAST | MUE_RFE_CTL_MULTICAST); | | 1029 | MUE_RFE_CTL_UNICAST | MUE_RFE_CTL_MULTICAST); |
1019 | | | 1030 | |
1020 | /* Always accept broadcast frames. */ | | 1031 | ETHER_LOCK(ec); |
1021 | rxfilt |= MUE_RFE_CTL_BROADCAST; | | | |
1022 | | | | |
1023 | if (ifp->if_flags & IFF_PROMISC) { | | 1032 | if (ifp->if_flags & IFF_PROMISC) { |
1024 | rxfilt |= MUE_RFE_CTL_UNICAST; | | 1033 | ec->ec_flags |= ETHER_F_ALLMULTI; |
1025 | allmulti: rxfilt |= MUE_RFE_CTL_MULTICAST; | | 1034 | ETHER_UNLOCK(ec); |
1026 | ifp->if_flags |= IFF_ALLMULTI; | | 1035 | /* run promisc. mode */ |
1027 | if (ifp->if_flags & IFF_PROMISC) | | 1036 | rxfilt |= (MUE_RFE_CTL_UNICAST | MUE_RFE_CTL_MULTICAST); |
1028 | DPRINTF(un, "promisc\n"); | | 1037 | DPRINTF(un, "promisc\n"); |
1029 | else | | 1038 | goto update; |
1030 | DPRINTF(un, "allmulti\n"); | | 1039 | } |
1031 | } else { | | 1040 | ec->ec_flags &= ~ETHER_F_ALLMULTI; |
1032 | /* Now program new ones. */ | | 1041 | ETHER_FIRST_MULTI(step, ec, enm); |
1033 | pfiltbl[0][0] = MUE_ENADDR_HI(enaddr) | MUE_ADDR_FILTX_VALID; | | 1042 | i = 1; /* the first slot is occupied by my station address */ |
1034 | pfiltbl[0][1] = MUE_ENADDR_LO(enaddr); | | 1043 | while (enm != NULL) { |
1035 | i = 1; | | 1044 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { |
1036 | ETHER_LOCK(ec); | | 1045 | /* |
1037 | ETHER_FIRST_MULTI(step, ec, enm); | | 1046 | * We must listen to a range of multicast addresses. |
1038 | while (enm != NULL) { | | 1047 | * For now, just accept all multicasts, rather than |
1039 | if (memcmp(enm->enm_addrlo, enm->enm_addrhi, | | 1048 | * trying to set only those filter bits needed to match |
1040 | ETHER_ADDR_LEN)) { | | 1049 | * the range. (At this time, the only use of address |
1041 | memset(pfiltbl, 0, sizeof(pfiltbl)); | | 1050 | * ranges is for IP multicast routing, for which the |
1042 | memset(hashtbl, 0, sizeof(hashtbl)); | | 1051 | * range is big enough to require all bits set.) |
1043 | rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH; | | 1052 | */ |
1044 | ETHER_UNLOCK(ec); | | 1053 | ec->ec_flags |= ETHER_F_ALLMULTI; |
1045 | goto allmulti; | | 1054 | ETHER_UNLOCK(ec); |
1046 | } | | 1055 | /* accept all multicast */ |
1047 | if (i < MUE_NUM_ADDR_FILTX) { | | 1056 | for (i = 1; i < MUE_NUM_ADDR_FILTX; i++) { |
1048 | /* Use perfect address table if possible. */ | | 1057 | hireg = (un->un_flags & LAN7500) |
1049 | pfiltbl[i][0] = MUE_ENADDR_HI(enm->enm_addrlo) | | | 1058 | ? MUE_7500_ADDR_FILTX(i) |
1050 | MUE_ADDR_FILTX_VALID; | | 1059 | : MUE_7800_ADDR_FILTX(i); |
1051 | pfiltbl[i][1] = MUE_ENADDR_LO(enm->enm_addrlo); | | 1060 | mue_csr_write(un, hireg, 0); |
1052 | } else { | | | |
1053 | /* Otherwise, use hash table. */ | | | |
1054 | rxfilt |= MUE_RFE_CTL_MULTICAST_HASH; | | | |
1055 | h = (ether_crc32_be(enm->enm_addrlo, | | | |
1056 | ETHER_ADDR_LEN) >> 23) & 0x1ff; | | | |
1057 | hashtbl[h / 32] |= 1 << (h % 32); | | | |
1058 | } | | 1061 | } |
1059 | i++; | | 1062 | memset(mchash, 0, sizeof(mchash)); |
1060 | ETHER_NEXT_MULTI(step, enm); | | 1063 | rxfilt |= MUE_RFE_CTL_MULTICAST; |
| | | 1064 | rxfilt &= ~MUE_RFE_CTL_MULTICAST_HASH; |
| | | 1065 | DPRINTF(un, "allmulti\n"); |
| | | 1066 | goto update; |
1061 | } | | 1067 | } |
1062 | ETHER_UNLOCK(ec); | | 1068 | if (i < MUE_NUM_ADDR_FILTX) { |
1063 | rxfilt |= MUE_RFE_CTL_PERFECT; | | 1069 | /* Use perfect address table if possible. */ |
1064 | ifp->if_flags &= ~IFF_ALLMULTI; | | 1070 | uint8_t *en = enm->enm_addrlo; |
1065 | if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH) | | 1071 | hireg = (un->un_flags & LAN7500) ? |
1066 | DPRINTF(un, "perfect filter and hash tables\n"); | | 1072 | MUE_7500_ADDR_FILTX(i) : MUE_7800_ADDR_FILTX(i); |
1067 | else | | 1073 | loreg = hireg + 4; |
1068 | DPRINTF(un, "perfect filter\n"); | | 1074 | mue_csr_write(un, hireg, 0); |
1069 | } | | 1075 | mue_csr_write(un, loreg, MUE_ENADDR_LO(en)); |
1070 | | | 1076 | mue_csr_write(un, hireg, MUE_ENADDR_HI(en) |
1071 | for (i = 0; i < MUE_NUM_ADDR_FILTX; i++) { | | 1077 | | MUE_ADDR_FILTX_VALID); |
1072 | hireg = (un->un_flags & LAN7500) ? | | 1078 | } else { |
1073 | MUE_7500_ADDR_FILTX(i) : MUE_7800_ADDR_FILTX(i); | | 1079 | /* Otherwise, use hash table. */ |
1074 | loreg = hireg + 4; | | 1080 | rxfilt |= MUE_RFE_CTL_MULTICAST_HASH; |
1075 | mue_csr_write(un, hireg, 0); | | 1081 | crc = (ether_crc32_be(enm->enm_addrlo, |
1076 | mue_csr_write(un, loreg, pfiltbl[i][1]); | | 1082 | ETHER_ADDR_LEN) >> 23) & 0x1ff; |
1077 | mue_csr_write(un, hireg, pfiltbl[i][0]); | | 1083 | mchash[crc / 32] |= 1 << (crc % 32); |
| | | 1084 | } |
| | | 1085 | i++; |
| | | 1086 | ETHER_NEXT_MULTI(step, enm); |
1078 | } | | 1087 | } |
1079 | | | 1088 | ETHER_UNLOCK(ec); |
| | | 1089 | update: |
| | | 1090 | if (rxfilt & MUE_RFE_CTL_MULTICAST_HASH) |
| | | 1091 | DPRINTF(un, "perfect filter and hash tables\n"); |
| | | 1092 | else |
| | | 1093 | DPRINTF(un, "perfect filter\n"); |
1080 | mue_dataport_write(un, MUE_DP_SEL_VHF, MUE_DP_SEL_VHF_VLAN_LEN, | | 1094 | mue_dataport_write(un, MUE_DP_SEL_VHF, MUE_DP_SEL_VHF_VLAN_LEN, |
1081 | MUE_DP_SEL_VHF_HASH_LEN, hashtbl); | | 1095 | MUE_DP_SEL_VHF_HASH_LEN, mchash); |
1082 | | | 1096 | mue_csr_write(un, rfe, rxfilt); |
1083 | mue_csr_write(un, reg, rxfilt); | | | |
1084 | } | | 1097 | } |
1085 | | | 1098 | |
1086 | static void | | 1099 | static void |
1087 | mue_sethwcsum_locked(struct usbnet *un) | | 1100 | mue_sethwcsum_locked(struct usbnet *un) |
1088 | { | | 1101 | { |
1089 | struct ifnet * const ifp = usbnet_ifp(un); | | 1102 | struct ifnet * const ifp = usbnet_ifp(un); |
1090 | uint32_t reg, val; | | 1103 | uint32_t reg, val; |
1091 | | | 1104 | |
1092 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; | | 1105 | reg = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; |
1093 | val = mue_csr_read(un, reg); | | 1106 | val = mue_csr_read(un, reg); |
1094 | | | 1107 | |
1095 | if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) { | | 1108 | if (ifp->if_capenable & IFCAP_CSUM_IPv4_Rx) { |
1096 | DPRINTF(un, "RX IPv4 hwcsum enabled\n"); | | 1109 | DPRINTF(un, "RX IPv4 hwcsum enabled\n"); |
1097 | val |= MUE_RFE_CTL_IP_COE; | | 1110 | val |= MUE_RFE_CTL_IP_COE; |
1098 | } else { | | 1111 | } else { |
1099 | DPRINTF(un, "RX IPv4 hwcsum disabled\n"); | | 1112 | DPRINTF(un, "RX IPv4 hwcsum disabled\n"); |
1100 | val &= ~MUE_RFE_CTL_IP_COE; | | 1113 | val &= ~MUE_RFE_CTL_IP_COE; |
1101 | } | | 1114 | } |
1102 | | | 1115 | |
1103 | if (ifp->if_capenable & | | 1116 | if (ifp->if_capenable & |
1104 | (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | | | 1117 | (IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx | |
1105 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { | | 1118 | IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx)) { |
1106 | DPRINTF(un, "RX L4 hwcsum enabled\n"); | | 1119 | DPRINTF(un, "RX L4 hwcsum enabled\n"); |
1107 | val |= MUE_RFE_CTL_TCPUDP_COE; | | 1120 | val |= MUE_RFE_CTL_TCPUDP_COE; |
1108 | } else { | | 1121 | } else { |
1109 | DPRINTF(un, "RX L4 hwcsum disabled\n"); | | 1122 | DPRINTF(un, "RX L4 hwcsum disabled\n"); |
1110 | val &= ~MUE_RFE_CTL_TCPUDP_COE; | | 1123 | val &= ~MUE_RFE_CTL_TCPUDP_COE; |
1111 | } | | 1124 | } |
1112 | | | 1125 | |
1113 | val &= ~MUE_RFE_CTL_VLAN_FILTER; | | 1126 | val &= ~MUE_RFE_CTL_VLAN_FILTER; |
1114 | | | 1127 | |
1115 | mue_csr_write(un, reg, val); | | 1128 | mue_csr_write(un, reg, val); |
1116 | } | | 1129 | } |
1117 | | | 1130 | |
1118 | static void | | 1131 | static void |
1119 | mue_setmtu_locked(struct usbnet *un) | | 1132 | mue_setmtu_locked(struct usbnet *un) |
1120 | { | | 1133 | { |
1121 | struct ifnet * const ifp = usbnet_ifp(un); | | 1134 | struct ifnet * const ifp = usbnet_ifp(un); |
1122 | uint32_t val; | | 1135 | uint32_t val; |
1123 | | | 1136 | |
1124 | /* Set the maximum frame size. */ | | 1137 | /* Set the maximum frame size. */ |
1125 | MUE_CLRBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | | 1138 | MUE_CLRBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); |
1126 | val = mue_csr_read(un, MUE_MAC_RX); | | 1139 | val = mue_csr_read(un, MUE_MAC_RX); |
1127 | val &= ~MUE_MAC_RX_MAX_SIZE_MASK; | | 1140 | val &= ~MUE_MAC_RX_MAX_SIZE_MASK; |
1128 | val |= MUE_MAC_RX_MAX_LEN(MUE_FRAME_LEN(ifp->if_mtu)); | | 1141 | val |= MUE_MAC_RX_MAX_LEN(MUE_FRAME_LEN(ifp->if_mtu)); |
1129 | mue_csr_write(un, MUE_MAC_RX, val); | | 1142 | mue_csr_write(un, MUE_MAC_RX, val); |
1130 | MUE_SETBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); | | 1143 | MUE_SETBIT(un, MUE_MAC_RX, MUE_MAC_RX_RXEN); |
1131 | } | | 1144 | } |
1132 | | | 1145 | |
1133 | static void | | 1146 | static void |
1134 | mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) | | 1147 | mue_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len) |
1135 | { | | 1148 | { |
1136 | struct ifnet * const ifp = usbnet_ifp(un); | | 1149 | struct ifnet * const ifp = usbnet_ifp(un); |
1137 | struct mue_rxbuf_hdr *hdrp; | | 1150 | struct mue_rxbuf_hdr *hdrp; |
1138 | uint32_t rx_cmd_a; | | 1151 | uint32_t rx_cmd_a; |
1139 | uint16_t pktlen; | | 1152 | uint16_t pktlen; |
1140 | int csum; | | 1153 | int csum; |
1141 | uint8_t *buf = c->unc_buf; | | 1154 | uint8_t *buf = c->unc_buf; |
1142 | bool v6; | | 1155 | bool v6; |
1143 | | | 1156 | |
1144 | KASSERTMSG(total_len <= un->un_rx_bufsz, "%u vs %u", | | 1157 | KASSERTMSG(total_len <= un->un_rx_bufsz, "%u vs %u", |
1145 | total_len, un->un_rx_bufsz); | | 1158 | total_len, un->un_rx_bufsz); |
1146 | | | 1159 | |
1147 | do { | | 1160 | do { |
1148 | if (__predict_false(total_len < sizeof(*hdrp))) { | | 1161 | if (__predict_false(total_len < sizeof(*hdrp))) { |
1149 | MUE_PRINTF(un, "packet length %u too short\n", total_len); | | 1162 | MUE_PRINTF(un, "packet length %u too short\n", total_len); |
1150 | if_statinc(ifp, if_ierrors); | | 1163 | if_statinc(ifp, if_ierrors); |
1151 | return; | | 1164 | return; |
1152 | } | | 1165 | } |
1153 | | | 1166 | |
1154 | hdrp = (struct mue_rxbuf_hdr *)buf; | | 1167 | hdrp = (struct mue_rxbuf_hdr *)buf; |
1155 | rx_cmd_a = le32toh(hdrp->rx_cmd_a); | | 1168 | rx_cmd_a = le32toh(hdrp->rx_cmd_a); |
1156 | | | 1169 | |
1157 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ERRORS)) { | | 1170 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ERRORS)) { |
1158 | /* | | 1171 | /* |
1159 | * We cannot use MUE_RX_CMD_A_RED bit here; | | 1172 | * We cannot use MUE_RX_CMD_A_RED bit here; |
1160 | * it is turned on in the cases of L3/L4 | | 1173 | * it is turned on in the cases of L3/L4 |
1161 | * checksum errors which we handle below. | | 1174 | * checksum errors which we handle below. |
1162 | */ | | 1175 | */ |
1163 | MUE_PRINTF(un, "rx_cmd_a: %#x\n", rx_cmd_a); | | 1176 | MUE_PRINTF(un, "rx_cmd_a: %#x\n", rx_cmd_a); |
1164 | if_statinc(ifp, if_ierrors); | | 1177 | if_statinc(ifp, if_ierrors); |
1165 | return; | | 1178 | return; |
1166 | } | | 1179 | } |
1167 | | | 1180 | |
1168 | pktlen = (uint16_t)(rx_cmd_a & MUE_RX_CMD_A_LEN_MASK); | | 1181 | pktlen = (uint16_t)(rx_cmd_a & MUE_RX_CMD_A_LEN_MASK); |
1169 | if (un->un_flags & LAN7500) | | 1182 | if (un->un_flags & LAN7500) |
1170 | pktlen -= 2; | | 1183 | pktlen -= 2; |
1171 | | | 1184 | |
1172 | if (__predict_false(pktlen < ETHER_HDR_LEN + ETHER_CRC_LEN || | | 1185 | if (__predict_false(pktlen < ETHER_HDR_LEN + ETHER_CRC_LEN || |
1173 | pktlen > MCLBYTES - ETHER_ALIGN || /* XXX */ | | 1186 | pktlen > MCLBYTES - ETHER_ALIGN || /* XXX */ |
1174 | pktlen + sizeof(*hdrp) > total_len)) { | | 1187 | pktlen + sizeof(*hdrp) > total_len)) { |
1175 | MUE_PRINTF(un, "invalid packet length %d\n", pktlen); | | 1188 | MUE_PRINTF(un, "invalid packet length %d\n", pktlen); |
1176 | if_statinc(ifp, if_ierrors); | | 1189 | if_statinc(ifp, if_ierrors); |
1177 | return; | | 1190 | return; |
1178 | } | | 1191 | } |
1179 | | | 1192 | |
1180 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ICSM)) { | | 1193 | if (__predict_false(rx_cmd_a & MUE_RX_CMD_A_ICSM)) { |
1181 | csum = 0; | | 1194 | csum = 0; |
1182 | } else { | | 1195 | } else { |
1183 | v6 = rx_cmd_a & MUE_RX_CMD_A_IPV; | | 1196 | v6 = rx_cmd_a & MUE_RX_CMD_A_IPV; |
1184 | switch (rx_cmd_a & MUE_RX_CMD_A_PID) { | | 1197 | switch (rx_cmd_a & MUE_RX_CMD_A_PID) { |
1185 | case MUE_RX_CMD_A_PID_TCP: | | 1198 | case MUE_RX_CMD_A_PID_TCP: |
1186 | csum = v6 ? | | 1199 | csum = v6 ? |
1187 | M_CSUM_TCPv6 : M_CSUM_IPv4 | M_CSUM_TCPv4; | | 1200 | M_CSUM_TCPv6 : M_CSUM_IPv4 | M_CSUM_TCPv4; |
1188 | break; | | 1201 | break; |
1189 | case MUE_RX_CMD_A_PID_UDP: | | 1202 | case MUE_RX_CMD_A_PID_UDP: |
1190 | csum = v6 ? | | 1203 | csum = v6 ? |
1191 | M_CSUM_UDPv6 : M_CSUM_IPv4 | M_CSUM_UDPv4; | | 1204 | M_CSUM_UDPv6 : M_CSUM_IPv4 | M_CSUM_UDPv4; |
1192 | break; | | 1205 | break; |
1193 | case MUE_RX_CMD_A_PID_IP: | | 1206 | case MUE_RX_CMD_A_PID_IP: |
1194 | csum = v6 ? 0 : M_CSUM_IPv4; | | 1207 | csum = v6 ? 0 : M_CSUM_IPv4; |
1195 | break; | | 1208 | break; |
1196 | default: | | 1209 | default: |
1197 | csum = 0; | | 1210 | csum = 0; |
1198 | break; | | 1211 | break; |
1199 | } | | 1212 | } |
1200 | csum &= ifp->if_csum_flags_rx; | | 1213 | csum &= ifp->if_csum_flags_rx; |
1201 | if (__predict_false((csum & M_CSUM_IPv4) && | | 1214 | if (__predict_false((csum & M_CSUM_IPv4) && |
1202 | (rx_cmd_a & MUE_RX_CMD_A_ICE))) | | 1215 | (rx_cmd_a & MUE_RX_CMD_A_ICE))) |
1203 | csum |= M_CSUM_IPv4_BAD; | | 1216 | csum |= M_CSUM_IPv4_BAD; |
1204 | if (__predict_false((csum & ~M_CSUM_IPv4) && | | 1217 | if (__predict_false((csum & ~M_CSUM_IPv4) && |
1205 | (rx_cmd_a & MUE_RX_CMD_A_TCE))) | | 1218 | (rx_cmd_a & MUE_RX_CMD_A_TCE))) |
1206 | csum |= M_CSUM_TCP_UDP_BAD; | | 1219 | csum |= M_CSUM_TCP_UDP_BAD; |
1207 | } | | 1220 | } |
1208 | | | 1221 | |
1209 | usbnet_enqueue(un, buf + sizeof(*hdrp), pktlen, csum, | | 1222 | usbnet_enqueue(un, buf + sizeof(*hdrp), pktlen, csum, |
1210 | 0, M_HASFCS); | | 1223 | 0, M_HASFCS); |
1211 | | | 1224 | |
1212 | /* Attention: sizeof(hdr) = 10 */ | | 1225 | /* Attention: sizeof(hdr) = 10 */ |
1213 | pktlen = roundup(pktlen + sizeof(*hdrp), 4); | | 1226 | pktlen = roundup(pktlen + sizeof(*hdrp), 4); |
1214 | if (pktlen > total_len) | | 1227 | if (pktlen > total_len) |
1215 | pktlen = total_len; | | 1228 | pktlen = total_len; |
1216 | total_len -= pktlen; | | 1229 | total_len -= pktlen; |
1217 | buf += pktlen; | | 1230 | buf += pktlen; |
1218 | } while (total_len > 0); | | 1231 | } while (total_len > 0); |
1219 | } | | 1232 | } |
1220 | | | 1233 | |
1221 | static int | | 1234 | static int |
1222 | mue_init_locked(struct ifnet *ifp) | | 1235 | mue_init_locked(struct ifnet *ifp) |
1223 | { | | 1236 | { |
1224 | struct usbnet * const un = ifp->if_softc; | | 1237 | struct usbnet * const un = ifp->if_softc; |
| | | 1238 | const uint8_t *ea = CLLADDR(ifp->if_sadl); |
| | | 1239 | uint32_t rfe, hireg, loreg; |
1225 | | | 1240 | |
1226 | if (usbnet_isdying(un)) { | | 1241 | if (usbnet_isdying(un)) { |
1227 | DPRINTF(un, "dying\n"); | | 1242 | DPRINTF(un, "dying\n"); |
1228 | return EIO; | | 1243 | return EIO; |
1229 | } | | 1244 | } |
1230 | | | 1245 | |
1231 | /* Cancel pending I/O and free all TX/RX buffers. */ | | 1246 | /* Cancel pending I/O and free all TX/RX buffers. */ |
1232 | if (ifp->if_flags & IFF_RUNNING) | | 1247 | if (ifp->if_flags & IFF_RUNNING) |
1233 | usbnet_stop(un, ifp, 1); | | 1248 | usbnet_stop(un, ifp, 1); |
1234 | | | 1249 | |
1235 | mue_reset(un); | | 1250 | mue_reset(un); |
1236 | | | 1251 | |
1237 | /* Set MAC address. */ | | 1252 | /* Set MAC address. */ |
1238 | mue_set_macaddr(un); | | 1253 | mue_set_macaddr(un); |
1239 | | | 1254 | |
| | | 1255 | hireg = (un->un_flags & LAN7500) |
| | | 1256 | ? MUE_7500_ADDR_FILTX(0) : MUE_7800_ADDR_FILTX(0); |
| | | 1257 | loreg = hireg + 4; |
| | | 1258 | mue_csr_write(un, loreg, MUE_ENADDR_LO(ea)); |
| | | 1259 | mue_csr_write(un, hireg, MUE_ENADDR_HI(ea) | MUE_ADDR_FILTX_VALID); |
| | | 1260 | |
| | | 1261 | rfe = (un->un_flags & LAN7500) ? MUE_7500_RFE_CTL : MUE_7800_RFE_CTL; |
| | | 1262 | mue_csr_write(un, rfe, MUE_RFE_CTL_BROADCAST | MUE_RFE_CTL_PERFECT); |
| | | 1263 | |
1240 | /* Load the multicast filter. */ | | 1264 | /* Load the multicast filter. */ |
1241 | mue_setiff_locked(un); | | 1265 | mue_setiff_locked(un); |
1242 | | | 1266 | |
1243 | /* TCP/UDP checksum offload engines. */ | | 1267 | /* TCP/UDP checksum offload engines. */ |
1244 | mue_sethwcsum_locked(un); | | 1268 | mue_sethwcsum_locked(un); |
1245 | | | 1269 | |
1246 | /* Set MTU. */ | | 1270 | /* Set MTU. */ |
1247 | mue_setmtu_locked(un); | | 1271 | mue_setmtu_locked(un); |
1248 | | | 1272 | |
1249 | return usbnet_init_rx_tx(un); | | 1273 | return usbnet_init_rx_tx(un); |
1250 | } | | 1274 | } |
1251 | | | 1275 | |
1252 | static int | | 1276 | static int |
1253 | mue_uno_init(struct ifnet *ifp) | | 1277 | mue_uno_init(struct ifnet *ifp) |
1254 | { | | 1278 | { |
1255 | struct usbnet * const un = ifp->if_softc; | | 1279 | struct usbnet * const un = ifp->if_softc; |
1256 | int rv; | | 1280 | int rv; |
1257 | | | 1281 | |
1258 | usbnet_lock_core(un); | | 1282 | usbnet_lock_core(un); |
1259 | usbnet_busy(un); | | 1283 | usbnet_busy(un); |
1260 | rv = mue_init_locked(ifp); | | 1284 | rv = mue_init_locked(ifp); |
1261 | usbnet_unbusy(un); | | 1285 | usbnet_unbusy(un); |
1262 | usbnet_unlock_core(un); | | 1286 | usbnet_unlock_core(un); |
1263 | | | 1287 | |
1264 | return rv; | | 1288 | return rv; |
1265 | } | | 1289 | } |
1266 | | | 1290 | |
1267 | static int | | 1291 | static int |
1268 | mue_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data) | | 1292 | mue_uno_override_ioctl(struct ifnet *ifp, u_long cmd, void *data) |
1269 | { | | 1293 | { |
1270 | struct usbnet * const un = ifp->if_softc; | | 1294 | struct usbnet * const un = ifp->if_softc; |
1271 | | | 1295 | |
1272 | usbnet_lock_core(un); | | 1296 | usbnet_lock_core(un); |
1273 | usbnet_busy(un); | | 1297 | usbnet_busy(un); |
1274 | | | 1298 | |
1275 | switch (cmd) { | | 1299 | switch (cmd) { |
1276 | case SIOCSIFFLAGS: | | 1300 | case SIOCSIFFLAGS: |
1277 | case SIOCSETHERCAP: | | 1301 | case SIOCSETHERCAP: |
1278 | case SIOCADDMULTI: | | 1302 | case SIOCADDMULTI: |
1279 | case SIOCDELMULTI: | | 1303 | case SIOCDELMULTI: |
1280 | mue_setiff_locked(un); | | 1304 | mue_setiff_locked(un); |
1281 | break; | | 1305 | break; |
1282 | case SIOCSIFCAP: | | 1306 | case SIOCSIFCAP: |
1283 | mue_sethwcsum_locked(un); | | 1307 | mue_sethwcsum_locked(un); |
1284 | break; | | 1308 | break; |
1285 | case SIOCSIFMTU: | | 1309 | case SIOCSIFMTU: |
1286 | mue_setmtu_locked(un); | | 1310 | mue_setmtu_locked(un); |
1287 | break; | | 1311 | break; |
1288 | default: | | 1312 | default: |
1289 | break; | | 1313 | break; |
1290 | } | | 1314 | } |
1291 | | | 1315 | |
1292 | usbnet_unbusy(un); | | 1316 | usbnet_unbusy(un); |
1293 | usbnet_unlock_core(un); | | 1317 | usbnet_unlock_core(un); |
1294 | | | 1318 | |
1295 | return 0; | | 1319 | return 0; |
1296 | } | | 1320 | } |
1297 | | | 1321 | |
1298 | static void | | 1322 | static void |
1299 | mue_reset(struct usbnet *un) | | 1323 | mue_reset(struct usbnet *un) |
1300 | { | | 1324 | { |
1301 | if (usbnet_isdying(un)) | | 1325 | if (usbnet_isdying(un)) |
1302 | return; | | 1326 | return; |
1303 | | | 1327 | |
1304 | /* Wait a little while for the chip to get its brains in order. */ | | 1328 | /* Wait a little while for the chip to get its brains in order. */ |
1305 | usbd_delay_ms(un->un_udev, 1); | | 1329 | usbd_delay_ms(un->un_udev, 1); |
1306 | | | 1330 | |
1307 | // mue_chip_init(un); /* XXX */ | | 1331 | // mue_chip_init(un); /* XXX */ |
1308 | } | | 1332 | } |
1309 | | | 1333 | |
1310 | static void | | 1334 | static void |
1311 | mue_uno_stop(struct ifnet *ifp, int disable) | | 1335 | mue_uno_stop(struct ifnet *ifp, int disable) |
1312 | { | | 1336 | { |
1313 | struct usbnet * const un = ifp->if_softc; | | 1337 | struct usbnet * const un = ifp->if_softc; |
1314 | | | 1338 | |
1315 | mue_reset(un); | | 1339 | mue_reset(un); |
1316 | } | | 1340 | } |
1317 | | | 1341 | |
1318 | #ifdef _MODULE | | 1342 | #ifdef _MODULE |
1319 | #include "ioconf.c" | | 1343 | #include "ioconf.c" |
1320 | #endif | | 1344 | #endif |
1321 | | | 1345 | |
1322 | USBNET_MODULE(mue) | | 1346 | USBNET_MODULE(mue) |