Make all network interrupt service routines MPSAFE part 1/3.
[dragonfly.git] / sys / dev / netif / cue / if_cue.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1997, 1998, 1999, 2000
3 * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 *
1550dfd9 32 * $FreeBSD: src/sys/dev/usb/if_cue.c,v 1.45 2003/12/08 07:54:14 obrien Exp $
78195a76 33 * $DragonFly: src/sys/dev/netif/cue/if_cue.c,v 1.24 2005/11/28 17:13:41 dillon Exp $
984263bc
MD
34 */
35
36/*
37 * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate
38 * adapters and others.
39 *
40 * Written by Bill Paul <wpaul@ee.columbia.edu>
41 * Electrical Engineering Department
42 * Columbia University, New York City
43 */
44
45/*
46 * The CATC USB-EL1210A provides USB ethernet support at 10Mbps. The
47 * RX filter uses a 512-bit multicast hash table, single perfect entry
48 * for the station address, and promiscuous mode. Unlike the ADMtek
49 * and KLSI chips, the CATC ASIC supports read and write combining
50 * mode where multiple packets can be transfered using a single bulk
51 * transaction, which helps performance a great deal.
52 */
53
54#include <sys/param.h>
55#include <sys/systm.h>
56#include <sys/sockio.h>
57#include <sys/mbuf.h>
58#include <sys/malloc.h>
59#include <sys/kernel.h>
60#include <sys/socket.h>
61
62#include <net/if.h>
f33fa91c 63#include <net/ifq_var.h>
984263bc
MD
64#include <net/if_arp.h>
65#include <net/ethernet.h>
66#include <net/if_dl.h>
67
68#include <net/bpf.h>
69
984263bc 70#include <sys/bus.h>
1550dfd9 71#include <machine/bus.h>
984263bc 72
1f2de5d4
MD
73#include <bus/usb/usb.h>
74#include <bus/usb/usbdi.h>
75#include <bus/usb/usbdi_util.h>
76#include <bus/usb/usbdivar.h>
77#include <bus/usb/usbdevs.h>
78#include <bus/usb/usb_ethersubr.h>
984263bc 79
1f2de5d4 80#include "if_cuereg.h"
984263bc 81
984263bc
MD
82/*
83 * Various supported device vendors/products.
84 */
85Static struct cue_type cue_devs[] = {
86 { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE },
87 { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE2 },
88 { USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTLINK },
89 { 0, 0 }
90};
91
1550dfd9
MD
92Static int cue_match(device_ptr_t);
93Static int cue_attach(device_ptr_t);
94Static int cue_detach(device_ptr_t);
984263bc
MD
95
96Static int cue_tx_list_init(struct cue_softc *);
97Static int cue_rx_list_init(struct cue_softc *);
98Static int cue_newbuf(struct cue_softc *, struct cue_chain *, struct mbuf *);
99Static int cue_encap(struct cue_softc *, struct mbuf *, int);
100Static void cue_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
101Static void cue_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
102Static void cue_tick(void *);
103Static void cue_rxstart(struct ifnet *);
104Static void cue_start(struct ifnet *);
bd4539cc 105Static int cue_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
984263bc
MD
106Static void cue_init(void *);
107Static void cue_stop(struct cue_softc *);
108Static void cue_watchdog(struct ifnet *);
1550dfd9 109Static void cue_shutdown(device_ptr_t);
984263bc
MD
110
111Static void cue_setmulti(struct cue_softc *);
984263bc
MD
112Static void cue_reset(struct cue_softc *);
113
1550dfd9
MD
114Static int cue_csr_read_1(struct cue_softc *, int);
115Static int cue_csr_write_1(struct cue_softc *, int, int);
116Static int cue_csr_read_2(struct cue_softc *, int);
984263bc 117#ifdef notdef
1550dfd9 118Static int cue_csr_write_2(struct cue_softc *, int, int);
984263bc
MD
119#endif
120Static int cue_mem(struct cue_softc *, int, int, void *, int);
121Static int cue_getmac(struct cue_softc *, void *);
122
123Static device_method_t cue_methods[] = {
124 /* Device interface */
125 DEVMETHOD(device_probe, cue_match),
126 DEVMETHOD(device_attach, cue_attach),
127 DEVMETHOD(device_detach, cue_detach),
128 DEVMETHOD(device_shutdown, cue_shutdown),
129
130 { 0, 0 }
131};
132
133Static driver_t cue_driver = {
134 "cue",
135 cue_methods,
136 sizeof(struct cue_softc)
137};
138
139Static devclass_t cue_devclass;
140
32832096 141DECLARE_DUMMY_MODULE(if_cue);
1550dfd9
MD
142DRIVER_MODULE(cue, uhub, cue_driver, cue_devclass, usbd_driver_load, 0);
143MODULE_DEPEND(cue, usb, 1, 1, 1);
984263bc
MD
144
145#define CUE_SETBIT(sc, reg, x) \
1550dfd9 146 cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x))
984263bc
MD
147
148#define CUE_CLRBIT(sc, reg, x) \
1550dfd9 149 cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x))
984263bc
MD
150
151Static int
1550dfd9 152cue_csr_read_1(struct cue_softc *sc, int reg)
984263bc
MD
153{
154 usb_device_request_t req;
155 usbd_status err;
156 u_int8_t val = 0;
984263bc 157
1550dfd9 158 if (sc->cue_dying)
984263bc
MD
159 return(0);
160
1550dfd9 161 CUE_LOCK(sc);
984263bc
MD
162
163 req.bmRequestType = UT_READ_VENDOR_DEVICE;
164 req.bRequest = CUE_CMD_READREG;
165 USETW(req.wValue, 0);
166 USETW(req.wIndex, reg);
167 USETW(req.wLength, 1);
168
1550dfd9 169 err = usbd_do_request(sc->cue_udev, &req, &val);
984263bc 170
1550dfd9 171 CUE_UNLOCK(sc);
984263bc
MD
172
173 if (err)
174 return(0);
175
176 return(val);
177}
178
179Static int
1550dfd9 180cue_csr_read_2(struct cue_softc *sc, int reg)
984263bc
MD
181{
182 usb_device_request_t req;
183 usbd_status err;
184 u_int16_t val = 0;
984263bc 185
1550dfd9 186 if (sc->cue_dying)
984263bc
MD
187 return(0);
188
1550dfd9 189 CUE_LOCK(sc);
984263bc
MD
190
191 req.bmRequestType = UT_READ_VENDOR_DEVICE;
192 req.bRequest = CUE_CMD_READREG;
193 USETW(req.wValue, 0);
194 USETW(req.wIndex, reg);
195 USETW(req.wLength, 2);
196
1550dfd9 197 err = usbd_do_request(sc->cue_udev, &req, &val);
984263bc 198
1550dfd9 199 CUE_UNLOCK(sc);
984263bc
MD
200
201 if (err)
202 return(0);
203
204 return(val);
205}
206
207Static int
1550dfd9 208cue_csr_write_1(struct cue_softc *sc, int reg, int val)
984263bc
MD
209{
210 usb_device_request_t req;
211 usbd_status err;
984263bc 212
1550dfd9 213 if (sc->cue_dying)
984263bc
MD
214 return(0);
215
1550dfd9 216 CUE_LOCK(sc);
984263bc
MD
217
218 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
219 req.bRequest = CUE_CMD_WRITEREG;
220 USETW(req.wValue, val);
221 USETW(req.wIndex, reg);
222 USETW(req.wLength, 0);
223
1550dfd9 224 err = usbd_do_request(sc->cue_udev, &req, NULL);
984263bc 225
1550dfd9 226 CUE_UNLOCK(sc);
984263bc
MD
227
228 if (err)
229 return(-1);
230
231 return(0);
232}
233
234#ifdef notdef
235Static int
1550dfd9 236cue_csr_write_2(struct cue_softc *sc, int reg, int val)
984263bc
MD
237{
238 usb_device_request_t req;
239 usbd_status err;
984263bc 240
1550dfd9 241 if (sc->cue_dying)
984263bc
MD
242 return(0);
243
1550dfd9 244 CUE_LOCK(sc);
984263bc
MD
245
246 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
247 req.bRequest = CUE_CMD_WRITEREG;
248 USETW(req.wValue, val);
249 USETW(req.wIndex, reg);
250 USETW(req.wLength, 0);
251
1550dfd9 252 err = usbd_do_request(sc->cue_udev, &req, NULL);
984263bc 253
1550dfd9 254 CUE_UNLOCK(sc);
984263bc
MD
255
256 if (err)
257 return(-1);
258
259 return(0);
260}
261#endif
262
263Static int
264cue_mem(struct cue_softc *sc, int cmd, int addr, void *buf, int len)
265{
266 usb_device_request_t req;
267 usbd_status err;
984263bc 268
1550dfd9 269 if (sc->cue_dying)
984263bc
MD
270 return(0);
271
1550dfd9 272 CUE_LOCK(sc);
984263bc
MD
273
274 if (cmd == CUE_CMD_READSRAM)
275 req.bmRequestType = UT_READ_VENDOR_DEVICE;
276 else
277 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
278 req.bRequest = cmd;
279 USETW(req.wValue, 0);
280 USETW(req.wIndex, addr);
281 USETW(req.wLength, len);
282
1550dfd9 283 err = usbd_do_request(sc->cue_udev, &req, buf);
984263bc 284
1550dfd9 285 CUE_UNLOCK(sc);
984263bc
MD
286
287 if (err)
288 return(-1);
289
290 return(0);
291}
292
293Static int
294cue_getmac(struct cue_softc *sc, void *buf)
295{
296 usb_device_request_t req;
297 usbd_status err;
984263bc 298
1550dfd9 299 if (sc->cue_dying)
984263bc
MD
300 return(0);
301
1550dfd9 302 CUE_LOCK(sc);
984263bc
MD
303
304 req.bmRequestType = UT_READ_VENDOR_DEVICE;
305 req.bRequest = CUE_CMD_GET_MACADDR;
306 USETW(req.wValue, 0);
307 USETW(req.wIndex, 0);
308 USETW(req.wLength, ETHER_ADDR_LEN);
309
1550dfd9 310 err = usbd_do_request(sc->cue_udev, &req, buf);
984263bc 311
1550dfd9 312 CUE_UNLOCK(sc);
984263bc
MD
313
314 if (err) {
abf66171 315 if_printf(&sc->arpcom.ac_if, "read MAC address failed\n");
984263bc
MD
316 return(-1);
317 }
318
319 return(0);
320}
321
93d4a46b 322#define CUE_BITS 9
984263bc
MD
323
324Static void
325cue_setmulti(struct cue_softc *sc)
326{
327 struct ifnet *ifp;
328 struct ifmultiaddr *ifma;
329 u_int32_t h = 0, i;
330
331 ifp = &sc->arpcom.ac_if;
332
333 if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
334 for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
335 sc->cue_mctab[i] = 0xFF;
1550dfd9
MD
336 cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
337 &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
984263bc
MD
338 return;
339 }
340
341 /* first, zot all the existing hash bits */
342 for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
343 sc->cue_mctab[i] = 0;
344
345 /* now program new ones */
1550dfd9 346 LIST_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
1550dfd9 347 {
984263bc
MD
348 if (ifma->ifma_addr->sa_family != AF_LINK)
349 continue;
93d4a46b
JS
350 h = ether_crc32_le(
351 LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
352 ETHER_ADDR_LEN) & ((1 << CUE_BITS) - 1);
1550dfd9 353 sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
984263bc
MD
354 }
355
356 /*
357 * Also include the broadcast address in the filter
358 * so we can receive broadcast frames.
359 */
360 if (ifp->if_flags & IFF_BROADCAST) {
93d4a46b
JS
361 h = ether_crc32_le(ifp->if_broadcastaddr, ETHER_ADDR_LEN) &
362 ((1 << CUE_BITS) - 1);
1550dfd9 363 sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
984263bc
MD
364 }
365
366 cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
367 &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
368
369 return;
370}
371
372Static void
373cue_reset(struct cue_softc *sc)
374{
375 usb_device_request_t req;
376 usbd_status err;
984263bc 377
1550dfd9 378 if (sc->cue_dying)
984263bc
MD
379 return;
380
984263bc
MD
381 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
382 req.bRequest = CUE_CMD_RESET;
383 USETW(req.wValue, 0);
384 USETW(req.wIndex, 0);
385 USETW(req.wLength, 0);
1550dfd9 386 err = usbd_do_request(sc->cue_udev, &req, NULL);
984263bc 387 if (err)
abf66171 388 if_printf(&sc->arpcom.ac_if, "reset failed\n");
984263bc
MD
389
390 /* Wait a little while for the chip to get its brains in order. */
391 DELAY(1000);
392 return;
393}
394
395/*
396 * Probe for a Pegasus chip.
397 */
398USB_MATCH(cue)
399{
400 USB_MATCH_START(cue, uaa);
401 struct cue_type *t;
402
403 if (!uaa->iface)
404 return(UMATCH_NONE);
405
406 t = cue_devs;
407 while(t->cue_vid) {
408 if (uaa->vendor == t->cue_vid &&
409 uaa->product == t->cue_did) {
410 return(UMATCH_VENDOR_PRODUCT);
411 }
412 t++;
413 }
414
415 return(UMATCH_NONE);
416}
417
418/*
419 * Attach the interface. Allocate softc structures, do ifmedia
420 * setup and ethernet/BPF attach.
421 */
422USB_ATTACH(cue)
423{
424 USB_ATTACH_START(cue, sc, uaa);
425 char devinfo[1024];
984263bc
MD
426 u_char eaddr[ETHER_ADDR_LEN];
427 struct ifnet *ifp;
428 usb_interface_descriptor_t *id;
429 usb_endpoint_descriptor_t *ed;
430 int i;
431
984263bc
MD
432 sc->cue_iface = uaa->iface;
433 sc->cue_udev = uaa->device;
3211e37c 434 callout_init(&sc->cue_stat_timer);
984263bc
MD
435
436 if (usbd_set_config_no(sc->cue_udev, CUE_CONFIG_NO, 0)) {
abf66171
JS
437 device_printf(self, "setting config no %d failed\n",
438 CUE_CONFIG_NO);
984263bc
MD
439 USB_ATTACH_ERROR_RETURN;
440 }
441
442 id = usbd_get_interface_descriptor(uaa->iface);
443
444 usbd_devinfo(uaa->device, 0, devinfo);
445 device_set_desc_copy(self, devinfo);
abf66171 446 device_printf(self, "%s\n", devinfo);
984263bc
MD
447
448 /* Find endpoints. */
449 for (i = 0; i < id->bNumEndpoints; i++) {
450 ed = usbd_interface2endpoint_descriptor(uaa->iface, i);
451 if (!ed) {
abf66171 452 device_printf(self, "couldn't get ep %d\n", i);
984263bc
MD
453 USB_ATTACH_ERROR_RETURN;
454 }
455 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
1550dfd9 456 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
984263bc
MD
457 sc->cue_ed[CUE_ENDPT_RX] = ed->bEndpointAddress;
458 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
1550dfd9 459 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
984263bc
MD
460 sc->cue_ed[CUE_ENDPT_TX] = ed->bEndpointAddress;
461 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
1550dfd9 462 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
984263bc
MD
463 sc->cue_ed[CUE_ENDPT_INTR] = ed->bEndpointAddress;
464 }
465 }
466
1550dfd9
MD
467 CUE_LOCK(sc);
468
abf66171
JS
469 ifp = &sc->arpcom.ac_if;
470 if_initname(ifp, device_get_name(self), device_get_unit(self));
471
984263bc
MD
472#ifdef notdef
473 /* Reset the adapter. */
474 cue_reset(sc);
475#endif
476 /*
477 * Get station address.
478 */
479 cue_getmac(sc, &eaddr);
480
984263bc 481 ifp->if_softc = sc;
984263bc
MD
482 ifp->if_mtu = ETHERMTU;
483 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
484 ifp->if_ioctl = cue_ioctl;
984263bc
MD
485 ifp->if_start = cue_start;
486 ifp->if_watchdog = cue_watchdog;
487 ifp->if_init = cue_init;
488 ifp->if_baudrate = 10000000;
f33fa91c
JS
489 ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN);
490 ifq_set_ready(&ifp->if_snd);
984263bc 491
984263bc
MD
492 /*
493 * Call MI attach routine.
494 */
78195a76 495 ether_ifattach(ifp, eaddr, NULL);
984263bc 496 usb_register_netisr();
1550dfd9 497 sc->cue_dying = 0;
984263bc 498
1550dfd9 499 CUE_UNLOCK(sc);
984263bc
MD
500 USB_ATTACH_SUCCESS_RETURN;
501}
502
503Static int
504cue_detach(device_ptr_t dev)
505{
506 struct cue_softc *sc;
507 struct ifnet *ifp;
984263bc
MD
508
509 sc = device_get_softc(dev);
1550dfd9 510 CUE_LOCK(sc);
984263bc
MD
511 ifp = &sc->arpcom.ac_if;
512
1550dfd9 513 sc->cue_dying = 1;
3211e37c 514 callout_stop(&sc->cue_stat_timer);
1550dfd9 515 ether_ifdetach(ifp);
984263bc
MD
516
517 if (sc->cue_ep[CUE_ENDPT_TX] != NULL)
518 usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_TX]);
519 if (sc->cue_ep[CUE_ENDPT_RX] != NULL)
520 usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_RX]);
521 if (sc->cue_ep[CUE_ENDPT_INTR] != NULL)
522 usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_INTR]);
523
1550dfd9 524 CUE_UNLOCK(sc);
984263bc
MD
525
526 return(0);
527}
528
529/*
530 * Initialize an RX descriptor and attach an MBUF cluster.
531 */
532Static int
533cue_newbuf(struct cue_softc *sc, struct cue_chain *c, struct mbuf *m)
534{
535 struct mbuf *m_new = NULL;
536
537 if (m == NULL) {
74f1caca 538 MGETHDR(m_new, MB_DONTWAIT, MT_DATA);
984263bc 539 if (m_new == NULL) {
abf66171
JS
540 if_printf(&sc->arpcom.ac_if, "no memory for rx list "
541 "-- packet dropped!\n");
984263bc
MD
542 return(ENOBUFS);
543 }
544
74f1caca 545 MCLGET(m_new, MB_DONTWAIT);
984263bc 546 if (!(m_new->m_flags & M_EXT)) {
abf66171
JS
547 if_printf(&sc->arpcom.ac_if, "no memory for rx list "
548 "-- packet dropped!\n");
984263bc
MD
549 m_freem(m_new);
550 return(ENOBUFS);
551 }
552 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
553 } else {
554 m_new = m;
555 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
556 m_new->m_data = m_new->m_ext.ext_buf;
557 }
558
559 m_adj(m_new, ETHER_ALIGN);
560 c->cue_mbuf = m_new;
561
562 return(0);
563}
564
565Static int
566cue_rx_list_init(struct cue_softc *sc)
567{
568 struct cue_cdata *cd;
569 struct cue_chain *c;
570 int i;
571
572 cd = &sc->cue_cdata;
573 for (i = 0; i < CUE_RX_LIST_CNT; i++) {
574 c = &cd->cue_rx_chain[i];
575 c->cue_sc = sc;
576 c->cue_idx = i;
577 if (cue_newbuf(sc, c, NULL) == ENOBUFS)
578 return(ENOBUFS);
579 if (c->cue_xfer == NULL) {
580 c->cue_xfer = usbd_alloc_xfer(sc->cue_udev);
581 if (c->cue_xfer == NULL)
582 return(ENOBUFS);
583 }
584 }
585
586 return(0);
587}
588
589Static int
590cue_tx_list_init(struct cue_softc *sc)
591{
592 struct cue_cdata *cd;
593 struct cue_chain *c;
594 int i;
595
596 cd = &sc->cue_cdata;
597 for (i = 0; i < CUE_TX_LIST_CNT; i++) {
598 c = &cd->cue_tx_chain[i];
599 c->cue_sc = sc;
600 c->cue_idx = i;
601 c->cue_mbuf = NULL;
602 if (c->cue_xfer == NULL) {
603 c->cue_xfer = usbd_alloc_xfer(sc->cue_udev);
604 if (c->cue_xfer == NULL)
605 return(ENOBUFS);
606 }
c5541aee 607 c->cue_buf = malloc(CUE_BUFSZ, M_USBDEV, M_WAITOK);
984263bc
MD
608 }
609
610 return(0);
611}
612
613Static void
614cue_rxstart(struct ifnet *ifp)
615{
616 struct cue_softc *sc;
617 struct cue_chain *c;
618
619 sc = ifp->if_softc;
1550dfd9 620 CUE_LOCK(sc);
984263bc
MD
621 c = &sc->cue_cdata.cue_rx_chain[sc->cue_cdata.cue_rx_prod];
622
623 if (cue_newbuf(sc, c, NULL) == ENOBUFS) {
624 ifp->if_ierrors++;
1550dfd9 625 CUE_UNLOCK(sc);
984263bc
MD
626 return;
627 }
628
629 /* Setup new transfer. */
630 usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX],
631 c, mtod(c->cue_mbuf, char *), CUE_BUFSZ, USBD_SHORT_XFER_OK,
632 USBD_NO_TIMEOUT, cue_rxeof);
633 usbd_transfer(c->cue_xfer);
1550dfd9 634 CUE_UNLOCK(sc);
984263bc
MD
635
636 return;
637}
638
639/*
640 * A frame has been uploaded: pass the resulting mbuf chain up to
641 * the higher level protocols.
642 */
643Static void
644cue_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
645{
646 struct cue_softc *sc;
647 struct cue_chain *c;
648 struct mbuf *m;
649 struct ifnet *ifp;
650 int total_len = 0;
651 u_int16_t len;
652
653 c = priv;
654 sc = c->cue_sc;
1550dfd9 655 CUE_LOCK(sc);
984263bc
MD
656 ifp = &sc->arpcom.ac_if;
657
1550dfd9
MD
658 if (!(ifp->if_flags & IFF_RUNNING)) {
659 CUE_UNLOCK(sc);
984263bc 660 return;
1550dfd9 661 }
984263bc
MD
662
663 if (status != USBD_NORMAL_COMPLETION) {
1550dfd9
MD
664 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
665 CUE_UNLOCK(sc);
984263bc 666 return;
1550dfd9 667 }
abf66171
JS
668 if (usbd_ratecheck(&sc->cue_rx_notice)) {
669 if_printf(ifp, "usb error on rx: %s\n",
670 usbd_errstr(status));
671 }
984263bc
MD
672 if (status == USBD_STALLED)
673 usbd_clear_endpoint_stall(sc->cue_ep[CUE_ENDPT_RX]);
674 goto done;
675 }
676
677 usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
678
679 m = c->cue_mbuf;
680 len = *mtod(m, u_int16_t *);
681
682 /* No errors; receive the packet. */
683 total_len = len;
684
685 if (len < sizeof(struct ether_header)) {
686 ifp->if_ierrors++;
687 goto done;
688 }
689
690 ifp->if_ipackets++;
691 m_adj(m, sizeof(u_int16_t));
ca3f7aba 692 m->m_pkthdr.rcvif = ifp;
984263bc
MD
693 m->m_pkthdr.len = m->m_len = total_len;
694
695 /* Put the packet on the special USB input queue. */
696 usb_ether_input(m);
ca3f7aba
JS
697 cue_rxstart(ifp);
698
1550dfd9 699 CUE_UNLOCK(sc);
984263bc
MD
700
701 return;
702done:
703 /* Setup new transfer. */
704 usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX],
705 c, mtod(c->cue_mbuf, char *), CUE_BUFSZ, USBD_SHORT_XFER_OK,
706 USBD_NO_TIMEOUT, cue_rxeof);
707 usbd_transfer(c->cue_xfer);
1550dfd9 708 CUE_UNLOCK(sc);
984263bc
MD
709
710 return;
711}
712
713/*
714 * A frame was downloaded to the chip. It's safe for us to clean up
715 * the list buffers.
716 */
717
718Static void
719cue_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
720{
721 struct cue_softc *sc;
722 struct cue_chain *c;
723 struct ifnet *ifp;
724 usbd_status err;
984263bc
MD
725
726 c = priv;
727 sc = c->cue_sc;
1550dfd9 728 CUE_LOCK(sc);
984263bc
MD
729 ifp = &sc->arpcom.ac_if;
730
731 if (status != USBD_NORMAL_COMPLETION) {
732 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1550dfd9 733 CUE_UNLOCK(sc);
984263bc
MD
734 return;
735 }
abf66171 736 if_printf(ifp, "usb error on tx: %s\n", usbd_errstr(status));
984263bc
MD
737 if (status == USBD_STALLED)
738 usbd_clear_endpoint_stall(sc->cue_ep[CUE_ENDPT_TX]);
1550dfd9 739 CUE_UNLOCK(sc);
984263bc
MD
740 return;
741 }
742
743 ifp->if_timer = 0;
744 ifp->if_flags &= ~IFF_OACTIVE;
745 usbd_get_xfer_status(c->cue_xfer, NULL, NULL, NULL, &err);
746
747 if (c->cue_mbuf != NULL) {
ca3f7aba 748 m_freem(c->cue_mbuf);
984263bc
MD
749 c->cue_mbuf = NULL;
750 }
751
752 if (err)
753 ifp->if_oerrors++;
754 else
755 ifp->if_opackets++;
756
ca3f7aba
JS
757 if (!ifq_is_empty(&ifp->if_snd))
758 (*ifp->if_start)(ifp);
759
1550dfd9 760 CUE_UNLOCK(sc);
984263bc
MD
761
762 return;
763}
764
765Static void
766cue_tick(void *xsc)
767{
768 struct cue_softc *sc;
769 struct ifnet *ifp;
984263bc
MD
770
771 sc = xsc;
772
1550dfd9 773 if (sc == NULL)
984263bc 774 return;
1550dfd9
MD
775
776 CUE_LOCK(sc);
984263bc
MD
777
778 ifp = &sc->arpcom.ac_if;
779
1550dfd9
MD
780 ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_SINGLECOLL);
781 ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_MULTICOLL);
782 ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_EXCESSCOLL);
984263bc 783
1550dfd9 784 if (cue_csr_read_2(sc, CUE_RX_FRAMEERR))
984263bc
MD
785 ifp->if_ierrors++;
786
3211e37c 787 callout_reset(&sc->cue_stat_timer, hz, cue_tick, sc);
984263bc 788
1550dfd9 789 CUE_UNLOCK(sc);
984263bc
MD
790
791 return;
792}
793
794Static int
795cue_encap(struct cue_softc *sc, struct mbuf *m, int idx)
796{
797 int total_len;
798 struct cue_chain *c;
799 usbd_status err;
800
801 c = &sc->cue_cdata.cue_tx_chain[idx];
802
803 /*
804 * Copy the mbuf data into a contiguous buffer, leaving two
805 * bytes at the beginning to hold the frame length.
806 */
807 m_copydata(m, 0, m->m_pkthdr.len, c->cue_buf + 2);
808 c->cue_mbuf = m;
809
810 total_len = m->m_pkthdr.len + 2;
811
812 /* The first two bytes are the frame length */
813 c->cue_buf[0] = (u_int8_t)m->m_pkthdr.len;
814 c->cue_buf[1] = (u_int8_t)(m->m_pkthdr.len >> 8);
815
816 usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_TX],
817 c, c->cue_buf, total_len, 0, 10000, cue_txeof);
818
819 /* Transmit */
820 err = usbd_transfer(c->cue_xfer);
821 if (err != USBD_IN_PROGRESS) {
822 cue_stop(sc);
823 return(EIO);
824 }
825
826 sc->cue_cdata.cue_tx_cnt++;
827
828 return(0);
829}
830
831Static void
832cue_start(struct ifnet *ifp)
833{
834 struct cue_softc *sc;
835 struct mbuf *m_head = NULL;
836
837 sc = ifp->if_softc;
1550dfd9 838 CUE_LOCK(sc);
984263bc 839
1550dfd9
MD
840 if (ifp->if_flags & IFF_OACTIVE) {
841 CUE_UNLOCK(sc);
984263bc 842 return;
1550dfd9 843 }
984263bc 844
f33fa91c 845 m_head = ifq_poll(&ifp->if_snd);
1550dfd9
MD
846 if (m_head == NULL) {
847 CUE_UNLOCK(sc);
984263bc 848 return;
1550dfd9 849 }
984263bc
MD
850
851 if (cue_encap(sc, m_head, 0)) {
984263bc 852 ifp->if_flags |= IFF_OACTIVE;
1550dfd9 853 CUE_UNLOCK(sc);
984263bc
MD
854 return;
855 }
d2c71fa0 856 ifq_dequeue(&ifp->if_snd, m_head);
984263bc
MD
857
858 /*
859 * If there's a BPF listener, bounce a copy of this frame
860 * to him.
861 */
1550dfd9 862 BPF_MTAP(ifp, m_head);
984263bc
MD
863
864 ifp->if_flags |= IFF_OACTIVE;
865
866 /*
867 * Set a timeout in case the chip goes out to lunch.
868 */
869 ifp->if_timer = 5;
1550dfd9 870 CUE_UNLOCK(sc);
984263bc
MD
871
872 return;
873}
874
875Static void
876cue_init(void *xsc)
877{
878 struct cue_softc *sc = xsc;
879 struct ifnet *ifp = &sc->arpcom.ac_if;
880 struct cue_chain *c;
881 usbd_status err;
1550dfd9 882 int i;
984263bc
MD
883
884 if (ifp->if_flags & IFF_RUNNING)
885 return;
886
1550dfd9 887 CUE_LOCK(sc);
984263bc
MD
888
889 /*
890 * Cancel pending I/O and free all RX/TX buffers.
891 */
892#ifdef foo
893 cue_reset(sc);
894#endif
895
896 /* Set MAC address */
897 for (i = 0; i < ETHER_ADDR_LEN; i++)
1550dfd9 898 cue_csr_write_1(sc, CUE_PAR0 - i, sc->arpcom.ac_enaddr[i]);
984263bc
MD
899
900 /* Enable RX logic. */
1550dfd9 901 cue_csr_write_1(sc, CUE_ETHCTL, CUE_ETHCTL_RX_ON|CUE_ETHCTL_MCAST_ON);
984263bc
MD
902
903 /* If we want promiscuous mode, set the allframes bit. */
904 if (ifp->if_flags & IFF_PROMISC) {
905 CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
906 } else {
907 CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
908 }
909
910 /* Init TX ring. */
911 if (cue_tx_list_init(sc) == ENOBUFS) {
abf66171 912 if_printf(ifp, "tx list init failed\n");
1550dfd9 913 CUE_UNLOCK(sc);
984263bc
MD
914 return;
915 }
916
917 /* Init RX ring. */
918 if (cue_rx_list_init(sc) == ENOBUFS) {
abf66171 919 if_printf(ifp, "rx list init failed\n");
1550dfd9 920 CUE_UNLOCK(sc);
984263bc
MD
921 return;
922 }
923
924 /* Load the multicast filter. */
925 cue_setmulti(sc);
926
927 /*
928 * Set the number of RX and TX buffers that we want
929 * to reserve inside the ASIC.
930 */
1550dfd9
MD
931 cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES);
932 cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES);
984263bc
MD
933
934 /* Set advanced operation modes. */
1550dfd9 935 cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
984263bc
MD
936 CUE_AOP_EMBED_RXLEN|0x01); /* 1 wait state */
937
938 /* Program the LED operation. */
1550dfd9 939 cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK);
984263bc
MD
940
941 /* Open RX and TX pipes. */
942 err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_RX],
943 USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_RX]);
944 if (err) {
abf66171 945 if_printf(ifp, "open rx pipe failed: %s\n", usbd_errstr(err));
1550dfd9 946 CUE_UNLOCK(sc);
984263bc
MD
947 return;
948 }
949 err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_TX],
950 USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_TX]);
951 if (err) {
abf66171 952 if_printf(ifp, "open tx pipe failed: %s\n", usbd_errstr(err));
1550dfd9 953 CUE_UNLOCK(sc);
984263bc
MD
954 return;
955 }
956
957 /* Start up the receive pipe. */
958 for (i = 0; i < CUE_RX_LIST_CNT; i++) {
959 c = &sc->cue_cdata.cue_rx_chain[i];
960 usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX],
961 c, mtod(c->cue_mbuf, char *), CUE_BUFSZ,
962 USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, cue_rxeof);
963 usbd_transfer(c->cue_xfer);
964 }
965
966 ifp->if_flags |= IFF_RUNNING;
967 ifp->if_flags &= ~IFF_OACTIVE;
968
1550dfd9 969 CUE_UNLOCK(sc);
984263bc 970
3211e37c 971 callout_reset(&sc->cue_stat_timer, hz, cue_tick, sc);
984263bc
MD
972}
973
974Static int
bd4539cc 975cue_ioctl(struct ifnet *ifp, u_long command, caddr_t data, struct ucred *cr)
984263bc
MD
976{
977 struct cue_softc *sc = ifp->if_softc;
1550dfd9 978 int error = 0;
984263bc 979
1550dfd9 980 CUE_LOCK(sc);
984263bc
MD
981
982 switch(command) {
984263bc
MD
983 case SIOCSIFFLAGS:
984 if (ifp->if_flags & IFF_UP) {
985 if (ifp->if_flags & IFF_RUNNING &&
986 ifp->if_flags & IFF_PROMISC &&
987 !(sc->cue_if_flags & IFF_PROMISC)) {
988 CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
989 cue_setmulti(sc);
990 } else if (ifp->if_flags & IFF_RUNNING &&
991 !(ifp->if_flags & IFF_PROMISC) &&
992 sc->cue_if_flags & IFF_PROMISC) {
993 CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
994 cue_setmulti(sc);
995 } else if (!(ifp->if_flags & IFF_RUNNING))
996 cue_init(sc);
997 } else {
998 if (ifp->if_flags & IFF_RUNNING)
999 cue_stop(sc);
1000 }
1001 sc->cue_if_flags = ifp->if_flags;
1002 error = 0;
1003 break;
1004 case SIOCADDMULTI:
1005 case SIOCDELMULTI:
1006 cue_setmulti(sc);
1007 error = 0;
1008 break;
1009 default:
1550dfd9 1010 error = ether_ioctl(ifp, command, data);
984263bc
MD
1011 break;
1012 }
1013
1550dfd9 1014 CUE_UNLOCK(sc);
984263bc
MD
1015
1016 return(error);
1017}
1018
1019Static void
1020cue_watchdog(struct ifnet *ifp)
1021{
1022 struct cue_softc *sc;
1023 struct cue_chain *c;
984263bc 1024 usbd_status stat;
1550dfd9 1025
984263bc 1026 sc = ifp->if_softc;
1550dfd9 1027 CUE_LOCK(sc);
984263bc
MD
1028
1029 ifp->if_oerrors++;
abf66171 1030 if_printf(ifp, "watchdog timeout\n");
984263bc
MD
1031
1032 c = &sc->cue_cdata.cue_tx_chain[0];
1033 usbd_get_xfer_status(c->cue_xfer, NULL, NULL, NULL, &stat);
1034 cue_txeof(c->cue_xfer, c, stat);
1035
f33fa91c 1036 if (!ifq_is_empty(&ifp->if_snd))
984263bc 1037 cue_start(ifp);
1550dfd9 1038 CUE_UNLOCK(sc);
984263bc
MD
1039
1040 return;
1041}
1042
1043/*
1044 * Stop the adapter and free any mbufs allocated to the
1045 * RX and TX lists.
1046 */
1047Static void
1048cue_stop(struct cue_softc *sc)
1049{
1050 usbd_status err;
1051 struct ifnet *ifp;
1052 int i;
1053
1550dfd9
MD
1054 CUE_LOCK(sc);
1055
984263bc
MD
1056 ifp = &sc->arpcom.ac_if;
1057 ifp->if_timer = 0;
1058
1550dfd9 1059 cue_csr_write_1(sc, CUE_ETHCTL, 0);
984263bc 1060 cue_reset(sc);
3211e37c 1061 callout_stop(&sc->cue_stat_timer);
984263bc
MD
1062
1063 /* Stop transfers. */
1064 if (sc->cue_ep[CUE_ENDPT_RX] != NULL) {
1065 err = usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_RX]);
1066 if (err) {
abf66171
JS
1067 if_printf(ifp, "abort rx pipe failed: %s\n",
1068 usbd_errstr(err));
984263bc
MD
1069 }
1070 err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_RX]);
1071 if (err) {
abf66171
JS
1072 if_printf(ifp, "close rx pipe failed: %s\n",
1073 usbd_errstr(err));
984263bc
MD
1074 }
1075 sc->cue_ep[CUE_ENDPT_RX] = NULL;
1076 }
1077
1078 if (sc->cue_ep[CUE_ENDPT_TX] != NULL) {
1079 err = usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_TX]);
1080 if (err) {
abf66171
JS
1081 if_printf(ifp, "abort tx pipe failed: %s\n",
1082 usbd_errstr(err));
984263bc
MD
1083 }
1084 err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_TX]);
1085 if (err) {
abf66171
JS
1086 if_printf(ifp, "close tx pipe failed: %s\n",
1087 usbd_errstr(err));
984263bc
MD
1088 }
1089 sc->cue_ep[CUE_ENDPT_TX] = NULL;
1090 }
1091
1092 if (sc->cue_ep[CUE_ENDPT_INTR] != NULL) {
1093 err = usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_INTR]);
1094 if (err) {
abf66171
JS
1095 if_printf(ifp, "abort intr pipe failed: %s\n",
1096 usbd_errstr(err));
984263bc
MD
1097 }
1098 err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_INTR]);
1099 if (err) {
abf66171
JS
1100 if_printf(ifp, "close intr pipe failed: %s\n",
1101 usbd_errstr(err));
984263bc
MD
1102 }
1103 sc->cue_ep[CUE_ENDPT_INTR] = NULL;
1104 }
1105
1106 /* Free RX resources. */
1107 for (i = 0; i < CUE_RX_LIST_CNT; i++) {
1108 if (sc->cue_cdata.cue_rx_chain[i].cue_buf != NULL) {
1109 free(sc->cue_cdata.cue_rx_chain[i].cue_buf, M_USBDEV);
1110 sc->cue_cdata.cue_rx_chain[i].cue_buf = NULL;
1111 }
1112 if (sc->cue_cdata.cue_rx_chain[i].cue_mbuf != NULL) {
1113 m_freem(sc->cue_cdata.cue_rx_chain[i].cue_mbuf);
1114 sc->cue_cdata.cue_rx_chain[i].cue_mbuf = NULL;
1115 }
1116 if (sc->cue_cdata.cue_rx_chain[i].cue_xfer != NULL) {
1117 usbd_free_xfer(sc->cue_cdata.cue_rx_chain[i].cue_xfer);
1118 sc->cue_cdata.cue_rx_chain[i].cue_xfer = NULL;
1119 }
1120 }
1121
1122 /* Free TX resources. */
1123 for (i = 0; i < CUE_TX_LIST_CNT; i++) {
1124 if (sc->cue_cdata.cue_tx_chain[i].cue_buf != NULL) {
1125 free(sc->cue_cdata.cue_tx_chain[i].cue_buf, M_USBDEV);
1126 sc->cue_cdata.cue_tx_chain[i].cue_buf = NULL;
1127 }
1128 if (sc->cue_cdata.cue_tx_chain[i].cue_mbuf != NULL) {
1129 m_freem(sc->cue_cdata.cue_tx_chain[i].cue_mbuf);
1130 sc->cue_cdata.cue_tx_chain[i].cue_mbuf = NULL;
1131 }
1132 if (sc->cue_cdata.cue_tx_chain[i].cue_xfer != NULL) {
1133 usbd_free_xfer(sc->cue_cdata.cue_tx_chain[i].cue_xfer);
1134 sc->cue_cdata.cue_tx_chain[i].cue_xfer = NULL;
1135 }
1136 }
1137
1138 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1550dfd9 1139 CUE_UNLOCK(sc);
984263bc
MD
1140
1141 return;
1142}
1143
1144/*
1145 * Stop all chip I/O so that the kernel's probe routines don't
1146 * get confused by errant DMAs when rebooting.
1147 */
1148Static void
1149cue_shutdown(device_ptr_t dev)
1150{
1151 struct cue_softc *sc;
1152
1153 sc = device_get_softc(dev);
1154
1550dfd9 1155 CUE_LOCK(sc);
984263bc
MD
1156 cue_reset(sc);
1157 cue_stop(sc);
1550dfd9 1158 CUE_UNLOCK(sc);
984263bc
MD
1159
1160 return;
1161}