Line data Source code
1 : /* $OpenBSD: if_url.c,v 1.83 2018/07/03 14:33:43 kevlo Exp $ */
2 : /* $NetBSD: if_url.c,v 1.6 2002/09/29 10:19:21 martin Exp $ */
3 : /*
4 : * Copyright (c) 2001, 2002
5 : * Shingo WATANABE <nabe@nabechan.org>. All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
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
16 : * may be used to endorse or promote products derived from this software
17 : * without specific prior written permission.
18 : *
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
21 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
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
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
29 : * SUCH DAMAGE.
30 : *
31 : */
32 :
33 : /*
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
36 : * ftp://152.104.125.40/lancard/data_sheet/8150/8150v14.pdf
37 : */
38 :
39 : /*
40 : * TODO:
41 : * Interrupt Endpoint support
42 : * External PHYs
43 : */
44 :
45 : #include "bpfilter.h"
46 :
47 : #include <sys/param.h>
48 : #include <sys/systm.h>
49 : #include <sys/rwlock.h>
50 : #include <sys/mbuf.h>
51 : #include <sys/kernel.h>
52 : #include <sys/socket.h>
53 :
54 : #include <sys/device.h>
55 :
56 : #include <net/if.h>
57 : #include <net/if_media.h>
58 :
59 : #if NBPFILTER > 0
60 : #include <net/bpf.h>
61 : #endif
62 :
63 : #include <netinet/in.h>
64 : #include <netinet/if_ether.h>
65 :
66 : #include <dev/mii/mii.h>
67 : #include <dev/mii/miivar.h>
68 : #include <dev/mii/urlphyreg.h>
69 :
70 : #include <dev/usb/usb.h>
71 : #include <dev/usb/usbdi.h>
72 : #include <dev/usb/usbdi_util.h>
73 : #include <dev/usb/usbdevs.h>
74 :
75 : #include <dev/usb/if_urlreg.h>
76 :
77 : int url_match(struct device *, void *, void *);
78 : void url_attach(struct device *, struct device *, void *);
79 : int url_detach(struct device *, int);
80 :
81 : struct cfdriver url_cd = {
82 : NULL, "url", DV_IFNET
83 : };
84 :
85 : const struct cfattach url_ca = {
86 : sizeof(struct url_softc), url_match, url_attach, url_detach
87 : };
88 :
89 : int url_openpipes(struct url_softc *);
90 : int url_rx_list_init(struct url_softc *);
91 : int url_tx_list_init(struct url_softc *);
92 : int url_newbuf(struct url_softc *, struct url_chain *, struct mbuf *);
93 : void url_start(struct ifnet *);
94 : int url_send(struct url_softc *, struct mbuf *, int);
95 : void url_txeof(struct usbd_xfer *, void *, usbd_status);
96 : void url_rxeof(struct usbd_xfer *, void *, usbd_status);
97 : void url_tick(void *);
98 : void url_tick_task(void *);
99 : int url_ioctl(struct ifnet *, u_long, caddr_t);
100 : void url_stop_task(struct url_softc *);
101 : void url_stop(struct ifnet *, int);
102 : void url_watchdog(struct ifnet *);
103 : int url_ifmedia_change(struct ifnet *);
104 : void url_ifmedia_status(struct ifnet *, struct ifmediareq *);
105 : void url_lock_mii(struct url_softc *);
106 : void url_unlock_mii(struct url_softc *);
107 : int url_int_miibus_readreg(struct device *, int, int);
108 : void url_int_miibus_writereg(struct device *, int, int, int);
109 : void url_miibus_statchg(struct device *);
110 : int url_init(struct ifnet *);
111 : void url_iff(struct url_softc *);
112 : void url_reset(struct url_softc *);
113 :
114 : int url_csr_read_1(struct url_softc *, int);
115 : int url_csr_read_2(struct url_softc *, int);
116 : int url_csr_write_1(struct url_softc *, int, int);
117 : int url_csr_write_2(struct url_softc *, int, int);
118 : int url_csr_write_4(struct url_softc *, int, int);
119 : int url_mem(struct url_softc *, int, int, void *, int);
120 :
121 : /* Macros */
122 : #ifdef URL_DEBUG
123 : #define DPRINTF(x) do { if (urldebug) printf x; } while (0)
124 : #define DPRINTFN(n,x) do { if (urldebug >= (n)) printf x; } while (0)
125 : int urldebug = 0;
126 : #else
127 : #define DPRINTF(x)
128 : #define DPRINTFN(n,x)
129 : #endif
130 :
131 : #define URL_SETBIT(sc, reg, x) \
132 : url_csr_write_1(sc, reg, url_csr_read_1(sc, reg) | (x))
133 :
134 : #define URL_SETBIT2(sc, reg, x) \
135 : url_csr_write_2(sc, reg, url_csr_read_2(sc, reg) | (x))
136 :
137 : #define URL_CLRBIT(sc, reg, x) \
138 : url_csr_write_1(sc, reg, url_csr_read_1(sc, reg) & ~(x))
139 :
140 : #define URL_CLRBIT2(sc, reg, x) \
141 : url_csr_write_2(sc, reg, url_csr_read_2(sc, reg) & ~(x))
142 :
143 : static const struct url_type {
144 : struct usb_devno url_dev;
145 : u_int16_t url_flags;
146 : #define URL_EXT_PHY 0x0001
147 : } url_devs [] = {
148 : {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_LCS8138TX}, 0},
149 : {{ USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_RTL8151}, 0},
150 : {{ USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX }, 0},
151 : {{ USB_VENDOR_MICRONET, USB_PRODUCT_MICRONET_SP128AR}, 0},
152 : {{ USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01}, 0},
153 : {{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8150}, 0},
154 : {{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8151}, 0},
155 : {{ USB_VENDOR_ZYXEL, USB_PRODUCT_ZYXEL_PRESTIGE}, 0}
156 : };
157 : #define url_lookup(v, p) ((struct url_type *)usb_lookup(url_devs, v, p))
158 :
159 :
160 : /* Probe */
161 : int
162 0 : url_match(struct device *parent, void *match, void *aux)
163 : {
164 0 : struct usb_attach_arg *uaa = aux;
165 :
166 0 : if (uaa->iface == NULL || uaa->configno != URL_CONFIG_NO)
167 0 : return (UMATCH_NONE);
168 :
169 0 : return (url_lookup(uaa->vendor, uaa->product) != NULL ?
170 : UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
171 0 : }
172 : /* Attach */
173 : void
174 0 : url_attach(struct device *parent, struct device *self, void *aux)
175 : {
176 0 : struct url_softc *sc = (struct url_softc *)self;
177 0 : struct usb_attach_arg *uaa = aux;
178 0 : struct usbd_device *dev = uaa->device;
179 0 : struct usbd_interface *iface;
180 : usbd_status err;
181 : usb_interface_descriptor_t *id;
182 : usb_endpoint_descriptor_t *ed;
183 0 : char *devname = sc->sc_dev.dv_xname;
184 : struct ifnet *ifp;
185 : struct mii_data *mii;
186 0 : u_char eaddr[ETHER_ADDR_LEN];
187 : int i, s;
188 :
189 0 : sc->sc_udev = dev;
190 :
191 0 : usb_init_task(&sc->sc_tick_task, url_tick_task, sc,
192 : USB_TASK_TYPE_GENERIC);
193 0 : rw_init(&sc->sc_mii_lock, "urlmii");
194 0 : usb_init_task(&sc->sc_stop_task, (void (*)(void *)) url_stop_task, sc,
195 : USB_TASK_TYPE_GENERIC);
196 :
197 : /* get control interface */
198 0 : err = usbd_device2interface_handle(dev, URL_IFACE_INDEX, &iface);
199 0 : if (err) {
200 0 : printf("%s: failed to get interface, err=%s\n", devname,
201 0 : usbd_errstr(err));
202 0 : goto bad;
203 : }
204 :
205 0 : sc->sc_ctl_iface = iface;
206 0 : sc->sc_flags = url_lookup(uaa->vendor, uaa->product)->url_flags;
207 :
208 : /* get interface descriptor */
209 0 : id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
210 :
211 : /* find endpoints */
212 0 : sc->sc_bulkin_no = sc->sc_bulkout_no = sc->sc_intrin_no = -1;
213 0 : for (i = 0; i < id->bNumEndpoints; i++) {
214 0 : ed = usbd_interface2endpoint_descriptor(sc->sc_ctl_iface, i);
215 0 : if (ed == NULL) {
216 0 : printf("%s: couldn't get endpoint %d\n", devname, i);
217 0 : goto bad;
218 : }
219 0 : if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK &&
220 0 : UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
221 0 : sc->sc_bulkin_no = ed->bEndpointAddress; /* RX */
222 0 : else if ((ed->bmAttributes & UE_XFERTYPE) == UE_BULK &&
223 0 : UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT)
224 0 : sc->sc_bulkout_no = ed->bEndpointAddress; /* TX */
225 0 : else if ((ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT &&
226 0 : UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN)
227 0 : sc->sc_intrin_no = ed->bEndpointAddress; /* Status */
228 : }
229 :
230 0 : if (sc->sc_bulkin_no == -1 || sc->sc_bulkout_no == -1 ||
231 0 : sc->sc_intrin_no == -1) {
232 0 : printf("%s: missing endpoint\n", devname);
233 0 : goto bad;
234 : }
235 :
236 0 : s = splnet();
237 :
238 : /* reset the adapter */
239 0 : url_reset(sc);
240 :
241 : /* Get Ethernet Address */
242 0 : err = url_mem(sc, URL_CMD_READMEM, URL_IDR0, (void *)eaddr,
243 : ETHER_ADDR_LEN);
244 0 : if (err) {
245 0 : printf("%s: read MAC address failed\n", devname);
246 0 : splx(s);
247 0 : goto bad;
248 : }
249 :
250 : /* Print Ethernet Address */
251 0 : printf("%s: address %s\n", devname, ether_sprintf(eaddr));
252 :
253 0 : bcopy(eaddr, (char *)&sc->sc_ac.ac_enaddr, ETHER_ADDR_LEN);
254 : /* initialize interface information */
255 0 : ifp = GET_IFP(sc);
256 0 : ifp->if_softc = sc;
257 0 : strlcpy(ifp->if_xname, devname, IFNAMSIZ);
258 0 : ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
259 0 : ifp->if_start = url_start;
260 0 : ifp->if_ioctl = url_ioctl;
261 0 : ifp->if_watchdog = url_watchdog;
262 :
263 0 : ifp->if_capabilities = IFCAP_VLAN_MTU;
264 :
265 : /*
266 : * Do ifmedia setup.
267 : */
268 0 : mii = &sc->sc_mii;
269 0 : mii->mii_ifp = ifp;
270 0 : mii->mii_readreg = url_int_miibus_readreg;
271 0 : mii->mii_writereg = url_int_miibus_writereg;
272 : #if 0
273 : if (sc->sc_flags & URL_EXT_PHY) {
274 : mii->mii_readreg = url_ext_miibus_readreg;
275 : mii->mii_writereg = url_ext_miibus_writereg;
276 : }
277 : #endif
278 0 : mii->mii_statchg = url_miibus_statchg;
279 0 : mii->mii_flags = MIIF_AUTOTSLEEP;
280 0 : ifmedia_init(&mii->mii_media, 0,
281 : url_ifmedia_change, url_ifmedia_status);
282 0 : mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
283 0 : if (LIST_FIRST(&mii->mii_phys) == NULL) {
284 0 : ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
285 0 : ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
286 0 : } else
287 0 : ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
288 :
289 : /* attach the interface */
290 0 : if_attach(ifp);
291 0 : ether_ifattach(ifp);
292 :
293 0 : timeout_set(&sc->sc_stat_ch, url_tick, sc);
294 :
295 0 : splx(s);
296 :
297 0 : return;
298 :
299 : bad:
300 0 : usbd_deactivate(sc->sc_udev);
301 0 : }
302 :
303 : /* detach */
304 : int
305 0 : url_detach(struct device *self, int flags)
306 : {
307 0 : struct url_softc *sc = (struct url_softc *)self;
308 0 : struct ifnet *ifp = GET_IFP(sc);
309 : int s;
310 :
311 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
312 :
313 0 : if (timeout_initialized(&sc->sc_stat_ch))
314 0 : timeout_del(&sc->sc_stat_ch);
315 :
316 : /* Remove any pending tasks */
317 0 : usb_rem_task(sc->sc_udev, &sc->sc_tick_task);
318 0 : usb_rem_task(sc->sc_udev, &sc->sc_stop_task);
319 :
320 0 : s = splusb();
321 :
322 0 : if (--sc->sc_refcnt >= 0) {
323 : /* Wait for processes to go away */
324 0 : usb_detach_wait(&sc->sc_dev);
325 0 : }
326 :
327 0 : if (ifp->if_flags & IFF_RUNNING)
328 0 : url_stop(GET_IFP(sc), 1);
329 :
330 0 : mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
331 0 : ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
332 0 : if (ifp->if_softc != NULL) {
333 0 : ether_ifdetach(ifp);
334 0 : if_detach(ifp);
335 0 : }
336 :
337 : #ifdef DIAGNOSTIC
338 0 : if (sc->sc_pipe_tx != NULL)
339 0 : printf("%s: detach has active tx endpoint.\n",
340 0 : sc->sc_dev.dv_xname);
341 0 : if (sc->sc_pipe_rx != NULL)
342 0 : printf("%s: detach has active rx endpoint.\n",
343 0 : sc->sc_dev.dv_xname);
344 0 : if (sc->sc_pipe_intr != NULL)
345 0 : printf("%s: detach has active intr endpoint.\n",
346 0 : sc->sc_dev.dv_xname);
347 : #endif
348 :
349 0 : splx(s);
350 :
351 0 : return (0);
352 : }
353 :
354 : /* read/write memory */
355 : int
356 0 : url_mem(struct url_softc *sc, int cmd, int offset, void *buf, int len)
357 : {
358 0 : usb_device_request_t req;
359 : usbd_status err;
360 :
361 0 : if (sc == NULL)
362 0 : return (0);
363 :
364 : DPRINTFN(0x200,
365 : ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
366 :
367 0 : if (usbd_is_dying(sc->sc_udev))
368 0 : return (0);
369 :
370 0 : if (cmd == URL_CMD_READMEM)
371 0 : req.bmRequestType = UT_READ_VENDOR_DEVICE;
372 : else
373 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
374 0 : req.bRequest = URL_REQ_MEM;
375 0 : USETW(req.wValue, offset);
376 0 : USETW(req.wIndex, 0x0000);
377 0 : USETW(req.wLength, len);
378 :
379 0 : sc->sc_refcnt++;
380 0 : err = usbd_do_request(sc->sc_udev, &req, buf);
381 0 : if (--sc->sc_refcnt < 0)
382 0 : usb_detach_wakeup(&sc->sc_dev);
383 : if (err) {
384 : DPRINTF(("%s: url_mem(): %s failed. off=%04x, err=%d\n",
385 : sc->sc_dev.dv_xname,
386 : cmd == URL_CMD_READMEM ? "read" : "write",
387 : offset, err));
388 : }
389 :
390 0 : return (err);
391 0 : }
392 :
393 : /* read 1byte from register */
394 : int
395 0 : url_csr_read_1(struct url_softc *sc, int reg)
396 : {
397 0 : u_int8_t val = 0;
398 :
399 : DPRINTFN(0x100,
400 : ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
401 :
402 0 : return (url_mem(sc, URL_CMD_READMEM, reg, &val, 1) ? 0 : val);
403 0 : }
404 :
405 : /* read 2bytes from register */
406 : int
407 0 : url_csr_read_2(struct url_softc *sc, int reg)
408 : {
409 0 : uWord val;
410 :
411 : DPRINTFN(0x100,
412 : ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
413 :
414 0 : USETW(val, 0);
415 0 : return (url_mem(sc, URL_CMD_READMEM, reg, &val, 2) ? 0 : UGETW(val));
416 0 : }
417 :
418 : /* write 1byte to register */
419 : int
420 0 : url_csr_write_1(struct url_softc *sc, int reg, int aval)
421 : {
422 0 : u_int8_t val = aval;
423 :
424 : DPRINTFN(0x100,
425 : ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
426 :
427 0 : return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 1) ? -1 : 0);
428 0 : }
429 :
430 : /* write 2bytes to register */
431 : int
432 0 : url_csr_write_2(struct url_softc *sc, int reg, int aval)
433 : {
434 0 : uWord val;
435 :
436 : DPRINTFN(0x100,
437 : ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
438 :
439 0 : USETW(val, aval);
440 :
441 0 : return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 2) ? -1 : 0);
442 0 : }
443 :
444 : /* write 4bytes to register */
445 : int
446 0 : url_csr_write_4(struct url_softc *sc, int reg, int aval)
447 : {
448 0 : uDWord val;
449 :
450 : DPRINTFN(0x100,
451 : ("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
452 :
453 0 : USETDW(val, aval);
454 :
455 0 : return (url_mem(sc, URL_CMD_WRITEMEM, reg, &val, 4) ? -1 : 0);
456 0 : }
457 :
458 : int
459 0 : url_init(struct ifnet *ifp)
460 : {
461 0 : struct url_softc *sc = ifp->if_softc;
462 0 : struct mii_data *mii = GET_MII(sc);
463 : u_char *eaddr;
464 : int i, s;
465 :
466 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
467 :
468 0 : s = splnet();
469 :
470 : /* Cancel pending I/O and free all TX/RX buffers */
471 0 : url_stop(ifp, 1);
472 :
473 0 : eaddr = sc->sc_ac.ac_enaddr;
474 0 : for (i = 0; i < ETHER_ADDR_LEN; i++)
475 0 : url_csr_write_1(sc, URL_IDR0 + i, eaddr[i]);
476 :
477 : /* Init transmission control register */
478 0 : URL_CLRBIT(sc, URL_TCR,
479 : URL_TCR_TXRR1 | URL_TCR_TXRR0 |
480 : URL_TCR_IFG1 | URL_TCR_IFG0 |
481 : URL_TCR_NOCRC);
482 :
483 : /* Init receive control register */
484 0 : URL_SETBIT2(sc, URL_RCR, URL_RCR_TAIL);
485 :
486 : /* Initialize transmit ring */
487 0 : if (url_tx_list_init(sc) == ENOBUFS) {
488 0 : printf("%s: tx list init failed\n", sc->sc_dev.dv_xname);
489 0 : splx(s);
490 0 : return (EIO);
491 : }
492 :
493 : /* Initialize receive ring */
494 0 : if (url_rx_list_init(sc) == ENOBUFS) {
495 0 : printf("%s: rx list init failed\n", sc->sc_dev.dv_xname);
496 0 : splx(s);
497 0 : return (EIO);
498 : }
499 :
500 : /* Program promiscuous mode and multicast filters */
501 0 : url_iff(sc);
502 :
503 : /* Enable RX and TX */
504 0 : URL_SETBIT(sc, URL_CR, URL_CR_TE | URL_CR_RE);
505 :
506 0 : mii_mediachg(mii);
507 :
508 0 : if (sc->sc_pipe_tx == NULL || sc->sc_pipe_rx == NULL) {
509 0 : if (url_openpipes(sc)) {
510 0 : splx(s);
511 0 : return (EIO);
512 : }
513 : }
514 :
515 0 : ifp->if_flags |= IFF_RUNNING;
516 0 : ifq_clr_oactive(&ifp->if_snd);
517 :
518 0 : splx(s);
519 :
520 0 : timeout_add_sec(&sc->sc_stat_ch, 1);
521 :
522 0 : return (0);
523 0 : }
524 :
525 : void
526 0 : url_reset(struct url_softc *sc)
527 : {
528 : int i;
529 :
530 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
531 :
532 0 : if (usbd_is_dying(sc->sc_udev))
533 0 : return;
534 :
535 0 : URL_SETBIT(sc, URL_CR, URL_CR_SOFT_RST);
536 :
537 0 : for (i = 0; i < URL_TX_TIMEOUT; i++) {
538 0 : if (!(url_csr_read_1(sc, URL_CR) & URL_CR_SOFT_RST))
539 : break;
540 0 : delay(10); /* XXX */
541 : }
542 :
543 0 : delay(10000); /* XXX */
544 0 : }
545 :
546 : void
547 0 : url_iff(struct url_softc *sc)
548 : {
549 0 : struct ifnet *ifp = GET_IFP(sc);
550 : struct arpcom *ac = &sc->sc_ac;
551 : struct ether_multi *enm;
552 : struct ether_multistep step;
553 : u_int32_t hashes[2];
554 : u_int16_t rcr;
555 : int h = 0;
556 :
557 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
558 :
559 0 : if (usbd_is_dying(sc->sc_udev))
560 0 : return;
561 :
562 0 : rcr = url_csr_read_2(sc, URL_RCR);
563 0 : rcr &= ~(URL_RCR_AAM | URL_RCR_AAP | URL_RCR_AB | URL_RCR_AD |
564 : URL_RCR_AM);
565 : bzero(hashes, sizeof(hashes));
566 0 : ifp->if_flags &= ~IFF_ALLMULTI;
567 :
568 : /*
569 : * Always accept broadcast frames.
570 : * Always accept frames destined to our station address.
571 : */
572 0 : rcr |= URL_RCR_AB | URL_RCR_AD;
573 :
574 0 : if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
575 0 : ifp->if_flags |= IFF_ALLMULTI;
576 0 : rcr |= URL_RCR_AAM;
577 0 : if (ifp->if_flags & IFF_PROMISC)
578 0 : rcr |= URL_RCR_AAP;
579 : } else {
580 0 : rcr |= URL_RCR_AM;
581 :
582 : /* now program new ones */
583 0 : ETHER_FIRST_MULTI(step, ac, enm);
584 0 : while (enm != NULL) {
585 0 : h = ether_crc32_be(enm->enm_addrlo,
586 0 : ETHER_ADDR_LEN) >> 26;
587 :
588 0 : if (h < 32)
589 0 : hashes[0] |= (1 << h);
590 : else
591 0 : hashes[1] |= (1 << (h - 32));
592 :
593 0 : ETHER_NEXT_MULTI(step, enm);
594 : }
595 : }
596 :
597 0 : url_csr_write_4(sc, URL_MAR0, hashes[0]);
598 0 : url_csr_write_4(sc, URL_MAR4, hashes[1]);
599 0 : url_csr_write_2(sc, URL_RCR, rcr);
600 0 : }
601 :
602 : int
603 0 : url_openpipes(struct url_softc *sc)
604 : {
605 : struct url_chain *c;
606 : usbd_status err;
607 : int i;
608 : int error = 0;
609 :
610 0 : if (usbd_is_dying(sc->sc_udev))
611 0 : return (EIO);
612 :
613 0 : sc->sc_refcnt++;
614 :
615 : /* Open RX pipe */
616 0 : err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_bulkin_no,
617 0 : USBD_EXCLUSIVE_USE, &sc->sc_pipe_rx);
618 0 : if (err) {
619 0 : printf("%s: open rx pipe failed: %s\n",
620 0 : sc->sc_dev.dv_xname, usbd_errstr(err));
621 : error = EIO;
622 0 : goto done;
623 : }
624 :
625 : /* Open TX pipe */
626 0 : err = usbd_open_pipe(sc->sc_ctl_iface, sc->sc_bulkout_no,
627 0 : USBD_EXCLUSIVE_USE, &sc->sc_pipe_tx);
628 0 : if (err) {
629 0 : printf("%s: open tx pipe failed: %s\n",
630 0 : sc->sc_dev.dv_xname, usbd_errstr(err));
631 : error = EIO;
632 0 : goto done;
633 : }
634 :
635 : #if 0
636 : /* XXX: interrupt endpoint is not yet supported */
637 : /* Open Interrupt pipe */
638 : err = usbd_open_pipe_intr(sc->sc_ctl_iface, sc->sc_intrin_no,
639 : USBD_EXCLUSIVE_USE, &sc->sc_pipe_intr, sc,
640 : &sc->sc_cdata.url_ibuf, URL_INTR_PKGLEN,
641 : url_intr, URL_INTR_INTERVAL);
642 : if (err) {
643 : printf("%s: open intr pipe failed: %s\n",
644 : sc->sc_dev.dv_xname, usbd_errstr(err));
645 : error = EIO;
646 : goto done;
647 : }
648 : #endif
649 :
650 :
651 : /* Start up the receive pipe. */
652 0 : for (i = 0; i < URL_RX_LIST_CNT; i++) {
653 0 : c = &sc->sc_cdata.url_rx_chain[i];
654 0 : usbd_setup_xfer(c->url_xfer, sc->sc_pipe_rx,
655 0 : c, c->url_buf, URL_BUFSZ,
656 : USBD_SHORT_XFER_OK | USBD_NO_COPY,
657 : USBD_NO_TIMEOUT, url_rxeof);
658 0 : (void)usbd_transfer(c->url_xfer);
659 : DPRINTF(("%s: %s: start read\n", sc->sc_dev.dv_xname,
660 : __func__));
661 : }
662 :
663 : done:
664 0 : if (--sc->sc_refcnt < 0)
665 0 : usb_detach_wakeup(&sc->sc_dev);
666 :
667 0 : return (error);
668 0 : }
669 :
670 : int
671 0 : url_newbuf(struct url_softc *sc, struct url_chain *c, struct mbuf *m)
672 : {
673 : struct mbuf *m_new = NULL;
674 :
675 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
676 :
677 0 : if (m == NULL) {
678 0 : MGETHDR(m_new, M_DONTWAIT, MT_DATA);
679 0 : if (m_new == NULL) {
680 0 : printf("%s: no memory for rx list "
681 0 : "-- packet dropped!\n", sc->sc_dev.dv_xname);
682 0 : return (ENOBUFS);
683 : }
684 0 : MCLGET(m_new, M_DONTWAIT);
685 0 : if (!(m_new->m_flags & M_EXT)) {
686 0 : printf("%s: no memory for rx list "
687 0 : "-- packet dropped!\n", sc->sc_dev.dv_xname);
688 0 : m_freem(m_new);
689 0 : return (ENOBUFS);
690 : }
691 0 : m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
692 0 : } else {
693 : m_new = m;
694 0 : m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
695 0 : m_new->m_data = m_new->m_ext.ext_buf;
696 : }
697 :
698 0 : m_adj(m_new, ETHER_ALIGN);
699 0 : c->url_mbuf = m_new;
700 :
701 0 : return (0);
702 0 : }
703 :
704 :
705 : int
706 0 : url_rx_list_init(struct url_softc *sc)
707 : {
708 : struct url_cdata *cd;
709 : struct url_chain *c;
710 : int i;
711 :
712 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
713 :
714 0 : cd = &sc->sc_cdata;
715 0 : for (i = 0; i < URL_RX_LIST_CNT; i++) {
716 0 : c = &cd->url_rx_chain[i];
717 0 : c->url_sc = sc;
718 0 : c->url_idx = i;
719 0 : if (url_newbuf(sc, c, NULL) == ENOBUFS)
720 0 : return (ENOBUFS);
721 0 : if (c->url_xfer == NULL) {
722 0 : c->url_xfer = usbd_alloc_xfer(sc->sc_udev);
723 0 : if (c->url_xfer == NULL)
724 0 : return (ENOBUFS);
725 0 : c->url_buf = usbd_alloc_buffer(c->url_xfer, URL_BUFSZ);
726 0 : if (c->url_buf == NULL) {
727 0 : usbd_free_xfer(c->url_xfer);
728 0 : return (ENOBUFS);
729 : }
730 : }
731 : }
732 :
733 0 : return (0);
734 0 : }
735 :
736 : int
737 0 : url_tx_list_init(struct url_softc *sc)
738 : {
739 : struct url_cdata *cd;
740 : struct url_chain *c;
741 : int i;
742 :
743 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
744 :
745 0 : cd = &sc->sc_cdata;
746 0 : for (i = 0; i < URL_TX_LIST_CNT; i++) {
747 0 : c = &cd->url_tx_chain[i];
748 0 : c->url_sc = sc;
749 0 : c->url_idx = i;
750 0 : c->url_mbuf = NULL;
751 0 : if (c->url_xfer == NULL) {
752 0 : c->url_xfer = usbd_alloc_xfer(sc->sc_udev);
753 0 : if (c->url_xfer == NULL)
754 0 : return (ENOBUFS);
755 0 : c->url_buf = usbd_alloc_buffer(c->url_xfer, URL_BUFSZ);
756 0 : if (c->url_buf == NULL) {
757 0 : usbd_free_xfer(c->url_xfer);
758 0 : return (ENOBUFS);
759 : }
760 : }
761 : }
762 :
763 0 : return (0);
764 0 : }
765 :
766 : void
767 0 : url_start(struct ifnet *ifp)
768 : {
769 0 : struct url_softc *sc = ifp->if_softc;
770 : struct mbuf *m_head = NULL;
771 :
772 : DPRINTF(("%s: %s: enter, link=%d\n", sc->sc_dev.dv_xname,
773 : __func__, sc->sc_link));
774 :
775 0 : if (usbd_is_dying(sc->sc_udev))
776 0 : return;
777 :
778 0 : if (!sc->sc_link)
779 0 : return;
780 :
781 0 : if (ifq_is_oactive(&ifp->if_snd))
782 0 : return;
783 :
784 0 : m_head = ifq_deq_begin(&ifp->if_snd);
785 0 : if (m_head == NULL)
786 0 : return;
787 :
788 0 : if (url_send(sc, m_head, 0)) {
789 0 : ifq_deq_rollback(&ifp->if_snd, m_head);
790 0 : ifq_set_oactive(&ifp->if_snd);
791 0 : return;
792 : }
793 :
794 0 : ifq_deq_commit(&ifp->if_snd, m_head);
795 :
796 : #if NBPFILTER > 0
797 0 : if (ifp->if_bpf)
798 0 : bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
799 : #endif
800 :
801 0 : ifq_set_oactive(&ifp->if_snd);
802 :
803 : /* Set a timeout in case the chip goes out to lunch. */
804 0 : ifp->if_timer = 5;
805 0 : }
806 :
807 : int
808 0 : url_send(struct url_softc *sc, struct mbuf *m, int idx)
809 : {
810 : int total_len;
811 : struct url_chain *c;
812 : usbd_status err;
813 :
814 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
815 :
816 0 : c = &sc->sc_cdata.url_tx_chain[idx];
817 :
818 : /* Copy the mbuf data into a contiguous buffer */
819 0 : m_copydata(m, 0, m->m_pkthdr.len, c->url_buf);
820 0 : c->url_mbuf = m;
821 0 : total_len = m->m_pkthdr.len;
822 :
823 0 : if (total_len < URL_MIN_FRAME_LEN) {
824 0 : bzero(c->url_buf + total_len, URL_MIN_FRAME_LEN - total_len);
825 : total_len = URL_MIN_FRAME_LEN;
826 0 : }
827 0 : usbd_setup_xfer(c->url_xfer, sc->sc_pipe_tx, c, c->url_buf, total_len,
828 : USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
829 : URL_TX_TIMEOUT, url_txeof);
830 :
831 : /* Transmit */
832 0 : sc->sc_refcnt++;
833 0 : err = usbd_transfer(c->url_xfer);
834 0 : if (--sc->sc_refcnt < 0)
835 0 : usb_detach_wakeup(&sc->sc_dev);
836 0 : if (err != USBD_IN_PROGRESS) {
837 0 : printf("%s: url_send error=%s\n", sc->sc_dev.dv_xname,
838 0 : usbd_errstr(err));
839 : /* Stop the interface */
840 0 : usb_add_task(sc->sc_udev, &sc->sc_stop_task);
841 0 : return (EIO);
842 : }
843 :
844 : DPRINTF(("%s: %s: send %d bytes\n", sc->sc_dev.dv_xname,
845 : __func__, total_len));
846 :
847 0 : sc->sc_cdata.url_tx_cnt++;
848 :
849 0 : return (0);
850 0 : }
851 :
852 : void
853 0 : url_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
854 : {
855 0 : struct url_chain *c = priv;
856 0 : struct url_softc *sc = c->url_sc;
857 0 : struct ifnet *ifp = GET_IFP(sc);
858 : int s;
859 :
860 0 : if (usbd_is_dying(sc->sc_udev))
861 0 : return;
862 :
863 0 : s = splnet();
864 :
865 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
866 :
867 0 : ifp->if_timer = 0;
868 0 : ifq_clr_oactive(&ifp->if_snd);
869 :
870 0 : if (status != USBD_NORMAL_COMPLETION) {
871 0 : if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
872 0 : splx(s);
873 0 : return;
874 : }
875 0 : ifp->if_oerrors++;
876 0 : printf("%s: usb error on tx: %s\n", sc->sc_dev.dv_xname,
877 0 : usbd_errstr(status));
878 0 : if (status == USBD_STALLED) {
879 0 : sc->sc_refcnt++;
880 0 : usbd_clear_endpoint_stall_async(sc->sc_pipe_tx);
881 0 : if (--sc->sc_refcnt < 0)
882 0 : usb_detach_wakeup(&sc->sc_dev);
883 : }
884 0 : splx(s);
885 0 : return;
886 : }
887 :
888 0 : m_freem(c->url_mbuf);
889 0 : c->url_mbuf = NULL;
890 :
891 0 : if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
892 0 : url_start(ifp);
893 :
894 0 : splx(s);
895 0 : }
896 :
897 : void
898 0 : url_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
899 : {
900 0 : struct url_chain *c = priv;
901 0 : struct url_softc *sc = c->url_sc;
902 0 : struct ifnet *ifp = GET_IFP(sc);
903 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
904 : struct mbuf *m;
905 0 : u_int32_t total_len;
906 : url_rxhdr_t rxhdr;
907 : int s;
908 :
909 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
910 :
911 0 : if (usbd_is_dying(sc->sc_udev))
912 0 : return;
913 :
914 0 : if (status != USBD_NORMAL_COMPLETION) {
915 0 : if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
916 0 : return;
917 0 : sc->sc_rx_errs++;
918 0 : if (usbd_ratecheck(&sc->sc_rx_notice)) {
919 0 : printf("%s: %u usb errors on rx: %s\n",
920 0 : sc->sc_dev.dv_xname, sc->sc_rx_errs,
921 0 : usbd_errstr(status));
922 0 : sc->sc_rx_errs = 0;
923 0 : }
924 0 : if (status == USBD_STALLED) {
925 0 : sc->sc_refcnt++;
926 0 : usbd_clear_endpoint_stall_async(sc->sc_pipe_rx);
927 0 : if (--sc->sc_refcnt < 0)
928 0 : usb_detach_wakeup(&sc->sc_dev);
929 : }
930 : goto done;
931 : }
932 :
933 0 : usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
934 :
935 0 : memcpy(mtod(c->url_mbuf, char *), c->url_buf, total_len);
936 :
937 0 : if (total_len <= ETHER_CRC_LEN) {
938 0 : ifp->if_ierrors++;
939 0 : goto done;
940 : }
941 :
942 0 : memcpy(&rxhdr, c->url_buf + total_len - ETHER_CRC_LEN, sizeof(rxhdr));
943 :
944 : DPRINTF(("%s: RX Status: %dbytes%s%s%s%s packets\n",
945 : sc->sc_dev.dv_xname,
946 : UGETW(rxhdr) & URL_RXHDR_BYTEC_MASK,
947 : UGETW(rxhdr) & URL_RXHDR_VALID_MASK ? ", Valid" : "",
948 : UGETW(rxhdr) & URL_RXHDR_RUNTPKT_MASK ? ", Runt" : "",
949 : UGETW(rxhdr) & URL_RXHDR_PHYPKT_MASK ? ", Physical match" : "",
950 : UGETW(rxhdr) & URL_RXHDR_MCASTPKT_MASK ? ", Multicast" : ""));
951 :
952 0 : if ((UGETW(rxhdr) & URL_RXHDR_VALID_MASK) == 0) {
953 0 : ifp->if_ierrors++;
954 0 : goto done;
955 : }
956 :
957 0 : total_len -= ETHER_CRC_LEN;
958 :
959 0 : m = c->url_mbuf;
960 0 : m->m_pkthdr.len = m->m_len = total_len;
961 0 : ml_enqueue(&ml, m);
962 :
963 0 : if (url_newbuf(sc, c, NULL) == ENOBUFS) {
964 0 : ifp->if_ierrors++;
965 0 : goto done;
966 : }
967 :
968 : DPRINTF(("%s: %s: deliver %d\n", sc->sc_dev.dv_xname,
969 : __func__, m->m_len));
970 :
971 0 : s = splnet();
972 0 : if_input(ifp, &ml);
973 0 : splx(s);
974 :
975 : done:
976 : /* Setup new transfer */
977 0 : usbd_setup_xfer(xfer, sc->sc_pipe_rx, c, c->url_buf, URL_BUFSZ,
978 : USBD_SHORT_XFER_OK | USBD_NO_COPY,
979 : USBD_NO_TIMEOUT, url_rxeof);
980 0 : sc->sc_refcnt++;
981 0 : usbd_transfer(xfer);
982 0 : if (--sc->sc_refcnt < 0)
983 0 : usb_detach_wakeup(&sc->sc_dev);
984 :
985 : DPRINTF(("%s: %s: start rx\n", sc->sc_dev.dv_xname, __func__));
986 0 : }
987 :
988 : int
989 0 : url_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
990 : {
991 0 : struct url_softc *sc = ifp->if_softc;
992 0 : struct ifreq *ifr = (struct ifreq *)data;
993 : int s, error = 0;
994 :
995 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
996 :
997 0 : if (usbd_is_dying(sc->sc_udev))
998 0 : return (EIO);
999 :
1000 0 : s = splnet();
1001 :
1002 0 : switch (cmd) {
1003 : case SIOCSIFADDR:
1004 0 : ifp->if_flags |= IFF_UP;
1005 0 : if (!(ifp->if_flags & IFF_RUNNING))
1006 0 : url_init(ifp);
1007 : break;
1008 :
1009 : case SIOCSIFFLAGS:
1010 0 : if (ifp->if_flags & IFF_UP) {
1011 0 : if (ifp->if_flags & IFF_RUNNING)
1012 0 : error = ENETRESET;
1013 : else
1014 0 : url_init(ifp);
1015 : } else {
1016 0 : if (ifp->if_flags & IFF_RUNNING)
1017 0 : url_stop(ifp, 1);
1018 : }
1019 : break;
1020 :
1021 : case SIOCGIFMEDIA:
1022 : case SIOCSIFMEDIA:
1023 0 : error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
1024 0 : break;
1025 :
1026 : default:
1027 0 : error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
1028 0 : }
1029 :
1030 0 : if (error == ENETRESET) {
1031 0 : if (ifp->if_flags & IFF_RUNNING)
1032 0 : url_iff(sc);
1033 : error = 0;
1034 0 : }
1035 :
1036 0 : splx(s);
1037 0 : return (error);
1038 0 : }
1039 :
1040 : void
1041 0 : url_watchdog(struct ifnet *ifp)
1042 : {
1043 0 : struct url_softc *sc = ifp->if_softc;
1044 : struct url_chain *c;
1045 0 : usbd_status stat;
1046 : int s;
1047 :
1048 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
1049 :
1050 0 : ifp->if_oerrors++;
1051 0 : printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
1052 :
1053 0 : s = splusb();
1054 0 : c = &sc->sc_cdata.url_tx_chain[0];
1055 0 : usbd_get_xfer_status(c->url_xfer, NULL, NULL, NULL, &stat);
1056 0 : url_txeof(c->url_xfer, c, stat);
1057 :
1058 0 : if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
1059 0 : url_start(ifp);
1060 0 : splx(s);
1061 0 : }
1062 :
1063 : void
1064 0 : url_stop_task(struct url_softc *sc)
1065 : {
1066 0 : url_stop(GET_IFP(sc), 1);
1067 0 : }
1068 :
1069 : /* Stop the adapter and free any mbufs allocated to the RX and TX lists. */
1070 : void
1071 0 : url_stop(struct ifnet *ifp, int disable)
1072 : {
1073 0 : struct url_softc *sc = ifp->if_softc;
1074 : usbd_status err;
1075 : int i;
1076 :
1077 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
1078 :
1079 0 : ifp->if_timer = 0;
1080 0 : ifp->if_flags &= ~IFF_RUNNING;
1081 0 : ifq_clr_oactive(&ifp->if_snd);
1082 :
1083 0 : url_reset(sc);
1084 :
1085 0 : timeout_del(&sc->sc_stat_ch);
1086 :
1087 : /* Stop transfers */
1088 : /* RX endpoint */
1089 0 : if (sc->sc_pipe_rx != NULL) {
1090 0 : usbd_abort_pipe(sc->sc_pipe_rx);
1091 0 : err = usbd_close_pipe(sc->sc_pipe_rx);
1092 0 : if (err)
1093 0 : printf("%s: close rx pipe failed: %s\n",
1094 0 : sc->sc_dev.dv_xname, usbd_errstr(err));
1095 0 : sc->sc_pipe_rx = NULL;
1096 0 : }
1097 :
1098 : /* TX endpoint */
1099 0 : if (sc->sc_pipe_tx != NULL) {
1100 0 : usbd_abort_pipe(sc->sc_pipe_tx);
1101 0 : err = usbd_close_pipe(sc->sc_pipe_tx);
1102 0 : if (err)
1103 0 : printf("%s: close tx pipe failed: %s\n",
1104 0 : sc->sc_dev.dv_xname, usbd_errstr(err));
1105 0 : sc->sc_pipe_tx = NULL;
1106 0 : }
1107 :
1108 : #if 0
1109 : /* XXX: Interrupt endpoint is not yet supported!! */
1110 : /* Interrupt endpoint */
1111 : if (sc->sc_pipe_intr != NULL) {
1112 : usbd_abort_pipe(sc->sc_pipe_intr);
1113 : err = usbd_close_pipe(sc->sc_pipe_intr);
1114 : if (err)
1115 : printf("%s: close intr pipe failed: %s\n",
1116 : sc->sc_dev.dv_xname, usbd_errstr(err));
1117 : sc->sc_pipe_intr = NULL;
1118 : }
1119 : #endif
1120 :
1121 : /* Free RX resources. */
1122 0 : for (i = 0; i < URL_RX_LIST_CNT; i++) {
1123 0 : if (sc->sc_cdata.url_rx_chain[i].url_mbuf != NULL) {
1124 0 : m_freem(sc->sc_cdata.url_rx_chain[i].url_mbuf);
1125 0 : sc->sc_cdata.url_rx_chain[i].url_mbuf = NULL;
1126 0 : }
1127 0 : if (sc->sc_cdata.url_rx_chain[i].url_xfer != NULL) {
1128 0 : usbd_free_xfer(sc->sc_cdata.url_rx_chain[i].url_xfer);
1129 0 : sc->sc_cdata.url_rx_chain[i].url_xfer = NULL;
1130 0 : }
1131 : }
1132 :
1133 : /* Free TX resources. */
1134 0 : for (i = 0; i < URL_TX_LIST_CNT; i++) {
1135 0 : if (sc->sc_cdata.url_tx_chain[i].url_mbuf != NULL) {
1136 0 : m_freem(sc->sc_cdata.url_tx_chain[i].url_mbuf);
1137 0 : sc->sc_cdata.url_tx_chain[i].url_mbuf = NULL;
1138 0 : }
1139 0 : if (sc->sc_cdata.url_tx_chain[i].url_xfer != NULL) {
1140 0 : usbd_free_xfer(sc->sc_cdata.url_tx_chain[i].url_xfer);
1141 0 : sc->sc_cdata.url_tx_chain[i].url_xfer = NULL;
1142 0 : }
1143 : }
1144 :
1145 0 : sc->sc_link = 0;
1146 0 : }
1147 :
1148 : /* Set media options */
1149 : int
1150 0 : url_ifmedia_change(struct ifnet *ifp)
1151 : {
1152 0 : struct url_softc *sc = ifp->if_softc;
1153 0 : struct mii_data *mii = GET_MII(sc);
1154 :
1155 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
1156 :
1157 0 : if (usbd_is_dying(sc->sc_udev))
1158 0 : return (0);
1159 :
1160 0 : sc->sc_link = 0;
1161 0 : if (mii->mii_instance) {
1162 : struct mii_softc *miisc;
1163 0 : LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1164 0 : mii_phy_reset(miisc);
1165 0 : }
1166 :
1167 0 : return (mii_mediachg(mii));
1168 0 : }
1169 :
1170 : /* Report current media status. */
1171 : void
1172 0 : url_ifmedia_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1173 : {
1174 0 : struct url_softc *sc = ifp->if_softc;
1175 0 : struct mii_data *mii = GET_MII(sc);
1176 :
1177 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
1178 :
1179 0 : if (usbd_is_dying(sc->sc_udev))
1180 0 : return;
1181 :
1182 0 : if ((ifp->if_flags & IFF_RUNNING) == 0) {
1183 0 : ifmr->ifm_active = IFM_ETHER | IFM_NONE;
1184 0 : ifmr->ifm_status = 0;
1185 0 : return;
1186 : }
1187 :
1188 0 : mii_pollstat(mii);
1189 0 : ifmr->ifm_active = mii->mii_media_active;
1190 0 : ifmr->ifm_status = mii->mii_media_status;
1191 0 : }
1192 :
1193 : void
1194 0 : url_tick(void *xsc)
1195 : {
1196 0 : struct url_softc *sc = xsc;
1197 :
1198 0 : if (sc == NULL)
1199 0 : return;
1200 :
1201 : DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
1202 : __func__));
1203 :
1204 0 : if (usbd_is_dying(sc->sc_udev))
1205 0 : return;
1206 :
1207 : /* Perform periodic stuff in process context */
1208 0 : usb_add_task(sc->sc_udev, &sc->sc_tick_task);
1209 0 : }
1210 :
1211 : void
1212 0 : url_tick_task(void *xsc)
1213 : {
1214 0 : struct url_softc *sc = xsc;
1215 : struct ifnet *ifp;
1216 : struct mii_data *mii;
1217 : int s;
1218 :
1219 0 : if (sc == NULL)
1220 0 : return;
1221 :
1222 : DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
1223 : __func__));
1224 :
1225 0 : if (usbd_is_dying(sc->sc_udev))
1226 0 : return;
1227 :
1228 0 : ifp = GET_IFP(sc);
1229 0 : mii = GET_MII(sc);
1230 :
1231 0 : if (mii == NULL)
1232 0 : return;
1233 :
1234 0 : s = splnet();
1235 :
1236 0 : mii_tick(mii);
1237 0 : if (!sc->sc_link && mii->mii_media_status & IFM_ACTIVE &&
1238 0 : IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
1239 : DPRINTF(("%s: %s: got link\n",
1240 : sc->sc_dev.dv_xname, __func__));
1241 0 : sc->sc_link++;
1242 0 : if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
1243 0 : url_start(ifp);
1244 : }
1245 :
1246 0 : timeout_add_sec(&sc->sc_stat_ch, 1);
1247 :
1248 0 : splx(s);
1249 0 : }
1250 :
1251 : /* Get exclusive access to the MII registers */
1252 : void
1253 0 : url_lock_mii(struct url_softc *sc)
1254 : {
1255 : DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
1256 : __func__));
1257 :
1258 0 : sc->sc_refcnt++;
1259 0 : rw_enter_write(&sc->sc_mii_lock);
1260 0 : }
1261 :
1262 : void
1263 0 : url_unlock_mii(struct url_softc *sc)
1264 : {
1265 : DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
1266 : __func__));
1267 :
1268 0 : rw_exit_write(&sc->sc_mii_lock);
1269 0 : if (--sc->sc_refcnt < 0)
1270 0 : usb_detach_wakeup(&sc->sc_dev);
1271 0 : }
1272 :
1273 : int
1274 0 : url_int_miibus_readreg(struct device *dev, int phy, int reg)
1275 : {
1276 : struct url_softc *sc;
1277 : u_int16_t val;
1278 :
1279 0 : if (dev == NULL)
1280 0 : return (0);
1281 :
1282 0 : sc = (void *)dev;
1283 :
1284 : DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x\n",
1285 : sc->sc_dev.dv_xname, __func__, phy, reg));
1286 :
1287 0 : if (usbd_is_dying(sc->sc_udev)) {
1288 : #ifdef DIAGNOSTIC
1289 0 : printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
1290 : __func__);
1291 : #endif
1292 0 : return (0);
1293 : }
1294 :
1295 : /* XXX: one PHY only for the RTL8150 internal PHY */
1296 0 : if (phy != 0) {
1297 : DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n",
1298 : sc->sc_dev.dv_xname, __func__, phy));
1299 0 : return (0);
1300 : }
1301 :
1302 0 : url_lock_mii(sc);
1303 :
1304 0 : switch (reg) {
1305 : case MII_BMCR: /* Control Register */
1306 : reg = URL_BMCR;
1307 0 : break;
1308 : case MII_BMSR: /* Status Register */
1309 : reg = URL_BMSR;
1310 0 : break;
1311 : case MII_PHYIDR1:
1312 : case MII_PHYIDR2:
1313 : val = 0;
1314 0 : goto R_DONE;
1315 : break;
1316 : case MII_ANAR: /* Autonegotiation advertisement */
1317 : reg = URL_ANAR;
1318 0 : break;
1319 : case MII_ANLPAR: /* Autonegotiation link partner abilities */
1320 : reg = URL_ANLP;
1321 0 : break;
1322 : case URLPHY_MSR: /* Media Status Register */
1323 : reg = URL_MSR;
1324 0 : break;
1325 : default:
1326 0 : printf("%s: %s: bad register %04x\n",
1327 0 : sc->sc_dev.dv_xname, __func__, reg);
1328 : val = 0;
1329 0 : goto R_DONE;
1330 : break;
1331 : }
1332 :
1333 0 : if (reg == URL_MSR)
1334 0 : val = url_csr_read_1(sc, reg);
1335 : else
1336 0 : val = url_csr_read_2(sc, reg);
1337 :
1338 : R_DONE:
1339 : DPRINTFN(0xff, ("%s: %s: phy=%d reg=0x%04x => 0x%04x\n",
1340 : sc->sc_dev.dv_xname, __func__, phy, reg, val));
1341 :
1342 0 : url_unlock_mii(sc);
1343 0 : return (val);
1344 0 : }
1345 :
1346 : void
1347 0 : url_int_miibus_writereg(struct device *dev, int phy, int reg, int data)
1348 : {
1349 : struct url_softc *sc;
1350 :
1351 0 : if (dev == NULL)
1352 0 : return;
1353 :
1354 0 : sc = (void *)dev;
1355 :
1356 : DPRINTFN(0xff, ("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n",
1357 : sc->sc_dev.dv_xname, __func__, phy, reg, data));
1358 :
1359 0 : if (usbd_is_dying(sc->sc_udev)) {
1360 : #ifdef DIAGNOSTIC
1361 0 : printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
1362 : __func__);
1363 : #endif
1364 0 : return;
1365 : }
1366 :
1367 : /* XXX: one PHY only for the RTL8150 internal PHY */
1368 0 : if (phy != 0) {
1369 : DPRINTFN(0xff, ("%s: %s: phy=%d is not supported\n",
1370 : sc->sc_dev.dv_xname, __func__, phy));
1371 0 : return;
1372 : }
1373 :
1374 0 : url_lock_mii(sc);
1375 :
1376 0 : switch (reg) {
1377 : case MII_BMCR: /* Control Register */
1378 : reg = URL_BMCR;
1379 0 : break;
1380 : case MII_BMSR: /* Status Register */
1381 : reg = URL_BMSR;
1382 0 : break;
1383 : case MII_PHYIDR1:
1384 : case MII_PHYIDR2:
1385 : goto W_DONE;
1386 : break;
1387 : case MII_ANAR: /* Autonegotiation advertisement */
1388 : reg = URL_ANAR;
1389 0 : break;
1390 : case MII_ANLPAR: /* Autonegotiation link partner abilities */
1391 : reg = URL_ANLP;
1392 0 : break;
1393 : case URLPHY_MSR: /* Media Status Register */
1394 : reg = URL_MSR;
1395 0 : break;
1396 : default:
1397 0 : printf("%s: %s: bad register %04x\n",
1398 0 : sc->sc_dev.dv_xname, __func__, reg);
1399 0 : goto W_DONE;
1400 : break;
1401 : }
1402 :
1403 0 : if (reg == URL_MSR)
1404 0 : url_csr_write_1(sc, reg, data);
1405 : else
1406 0 : url_csr_write_2(sc, reg, data);
1407 : W_DONE:
1408 :
1409 0 : url_unlock_mii(sc);
1410 0 : return;
1411 0 : }
1412 :
1413 : void
1414 0 : url_miibus_statchg(struct device *dev)
1415 : {
1416 : #ifdef URL_DEBUG
1417 : struct url_softc *sc;
1418 :
1419 : if (dev == NULL)
1420 : return;
1421 :
1422 : sc = (void *)dev;
1423 : DPRINTF(("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
1424 : #endif
1425 : /* Nothing to do */
1426 0 : }
1427 :
1428 : #if 0
1429 : /*
1430 : * external PHYs support, but not test.
1431 : */
1432 : int
1433 : url_ext_miibus_redreg(struct device *dev, int phy, int reg)
1434 : {
1435 : struct url_softc *sc = (void *)dev;
1436 : u_int16_t val;
1437 :
1438 : DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x\n",
1439 : sc->sc_dev.dv_xname, __func__, phy, reg));
1440 :
1441 : if (usbd_is_dying(sc->sc_udev)) {
1442 : #ifdef DIAGNOSTIC
1443 : printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
1444 : __func__);
1445 : #endif
1446 : return (0);
1447 : }
1448 :
1449 : url_lock_mii(sc);
1450 :
1451 : url_csr_write_1(sc, URL_PHYADD, phy & URL_PHYADD_MASK);
1452 : /*
1453 : * RTL8150L will initiate a MII management data transaction
1454 : * if PHYCNT_OWN bit is set 1 by software. After transaction,
1455 : * this bit is auto cleared by TRL8150L.
1456 : */
1457 : url_csr_write_1(sc, URL_PHYCNT,
1458 : (reg | URL_PHYCNT_PHYOWN) & ~URL_PHYCNT_RWCR);
1459 : for (i = 0; i < URL_TIMEOUT; i++) {
1460 : if ((url_csr_read_1(sc, URL_PHYCNT) & URL_PHYCNT_PHYOWN) == 0)
1461 : break;
1462 : }
1463 : if (i == URL_TIMEOUT) {
1464 : printf("%s: MII read timed out\n", sc->sc_dev.dv_xname);
1465 : }
1466 :
1467 : val = url_csr_read_2(sc, URL_PHYDAT);
1468 :
1469 : DPRINTF(("%s: %s: phy=%d reg=0x%04x => 0x%04x\n",
1470 : sc->sc_dev.dv_xname, __func__, phy, reg, val));
1471 :
1472 : url_unlock_mii(sc);
1473 : return (val);
1474 : }
1475 :
1476 : void
1477 : url_ext_miibus_writereg(struct device *dev, int phy, int reg, int data)
1478 : {
1479 : struct url_softc *sc = (void *)dev;
1480 :
1481 : DPRINTF(("%s: %s: enter, phy=%d reg=0x%04x data=0x%04x\n",
1482 : sc->sc_dev.dv_xname, __func__, phy, reg, data));
1483 :
1484 : if (usbd_is_dying(sc->sc_udev)) {
1485 : #ifdef DIAGNOSTIC
1486 : printf("%s: %s: dying\n", sc->sc_dev.dv_xname,
1487 : __func__);
1488 : #endif
1489 : return;
1490 : }
1491 :
1492 : url_lock_mii(sc);
1493 :
1494 : url_csr_write_2(sc, URL_PHYDAT, data);
1495 : url_csr_write_1(sc, URL_PHYADD, phy);
1496 : url_csr_write_1(sc, URL_PHYCNT, reg | URL_PHYCNT_RWCR); /* Write */
1497 :
1498 : for (i=0; i < URL_TIMEOUT; i++) {
1499 : if (url_csr_read_1(sc, URL_PHYCNT) & URL_PHYCNT_PHYOWN)
1500 : break;
1501 : }
1502 :
1503 : if (i == URL_TIMEOUT) {
1504 : printf("%s: MII write timed out\n",
1505 : sc->sc_dev.dv_xname);
1506 : }
1507 :
1508 : url_unlock_mii(sc);
1509 : return;
1510 : }
1511 : #endif
1512 :
|