if_cnw.c revision 1.4 1 /* $NetBSD: if_cnw.c,v 1.4 2000/01/25 16:48:47 itojun Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Michael Eriksson.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1996, 1997 Berkeley Software Design, Inc.
41 * All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that this notice is retained,
45 * the conditions in the following notices are met, and terms applying
46 * to contributors in the following notices also apply to Berkeley
47 * Software Design, Inc.
48 *
49 * 1. Redistributions of source code must retain the above copyright
50 * notice, this list of conditions and the following disclaimer.
51 * 2. Redistributions in binary form must reproduce the above copyright
52 * notice, this list of conditions and the following disclaimer in the
53 * documentation and/or other materials provided with the distribution.
54 * 3. All advertising materials mentioning features or use of this software
55 * must display the following acknowledgement:
56 * This product includes software developed by
57 * Berkeley Software Design, Inc.
58 * 4. Neither the name of the Berkeley Software Design, Inc. nor the names
59 * of its contributors may be used to endorse or promote products derived
60 * from this software without specific prior written permission.
61 *
62 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65 * ARE DISCLAIMED. IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72 * SUCH DAMAGE.
73 *
74 * Paul Borman, December 1996
75 *
76 * This driver is derived from a generic frame work which is
77 * Copyright(c) 1994,1995,1996
78 * Yoichi Shinoda, Yoshitaka Tokugawa, WIDE Project, Wildboar Project
79 * and Foretune. All rights reserved.
80 *
81 * A linux driver was used as the "hardware reference manual" (i.e.,
82 * to determine registers and a general outline of how the card works)
83 * That driver is publically available and copyright
84 *
85 * John Markus Bj,Ax(Brndalen
86 * Department of Computer Science
87 * University of Troms,Ax(B
88 * Norway
89 * johnm (at) staff.cs.uit.no, http://www.cs.uit.no/~johnm/
90 */
91
92 /*
93 * This is a driver for the Xircom CreditCard Netwave (also known as
94 * the Netwave Airsurfer) wireless LAN PCMCIA adapter.
95 *
96 * When this driver was developed, the Linux Netwave driver was used
97 * as a hardware manual. That driver is Copyright (c) 1997 University
98 * of Troms, Norway. It is part of the Linix pcmcia-cs package that
99 * can be found at
100 * http://hyper.stanford.edu/HyperNews/get/pcmcia/home.html. The most
101 * recent version of the pcmcia-cs package when this driver was
102 * written was 3.0.6.
103 *
104 * Unfortunately, a lot of explicit numeric constants were used in the
105 * Linux driver. I have tried to use symbolic names whenever possible,
106 * but since I don't have any real hardware documentation, there's
107 * still one or two "magic numbers" :-(.
108 *
109 * Driver limitations: This driver doesn't do multicasting or receiver
110 * promiscuity, because of missing hardware documentation. I couldn't
111 * get receiver promiscuity to work, and I haven't even tried
112 * multicast. Volunteers are welcome, of course :-).
113 */
114
115 #include "opt_inet.h"
116 #include "bpfilter.h"
117
118 #include <sys/param.h>
119 #include <sys/systm.h>
120 #include <sys/device.h>
121 #include <sys/socket.h>
122 #include <sys/mbuf.h>
123 #include <sys/ioctl.h>
124 #include <sys/proc.h>
125
126 #include <net/if.h>
127
128 #include <dev/pcmcia/if_cnwreg.h>
129 #include <dev/pcmcia/if_cnwioctl.h>
130
131 #include <dev/pcmcia/pcmciareg.h>
132 #include <dev/pcmcia/pcmciavar.h>
133 #include <dev/pcmcia/pcmciadevs.h>
134
135 #include <net/if_dl.h>
136 #include <net/if_ether.h>
137
138 #ifdef INET
139 #include <netinet/in.h>
140 #include <netinet/in_systm.h>
141 #include <netinet/in_var.h>
142 #include <netinet/ip.h>
143 #include <netinet/if_inarp.h>
144 #endif
145
146 #if NBPFILTER > 0
147 #include <net/bpf.h>
148 #include <net/bpfdesc.h>
149 #endif
150
151 /*
152 * Let these be patchable variables, initialized from macros that can
153 * be set in the kernel config file. Someone with lots of spare time
154 * could probably write a nice Netwave configuration program to do
155 * this a little bit more elegantly :-).
156 */
157 #ifndef CNW_DOMAIN
158 #define CNW_DOMAIN 0x100
159 #endif
160 int cnw_domain = CNW_DOMAIN; /* Domain */
161 #ifndef CNW_SCRAMBLEKEY
162 #define CNW_SCRAMBLEKEY 0
163 #endif
164 int cnw_skey = CNW_SCRAMBLEKEY; /* Scramble key */
165
166 /*
167 * The card appears to work much better when we only allow one packet
168 * "in the air" at a time. This is done by not allowing another packet
169 * on the card, even if there is room. Turning this off will allow the
170 * driver to stuff packets on the card as soon as a transmit buffer is
171 * available. This does increase the number of collisions, though.
172 * We can que a second packet if there are transmit buffers available,
173 * but we do not actually send the packet until the last packet has
174 * been written.
175 #define ONE_AT_A_TIME
176 */
177
178 int cnw_match __P((struct device *, struct cfdata *, void *));
179 void cnw_attach __P((struct device *, struct device *, void *));
180
181 struct cnw_softc {
182 struct device sc_dev; /* Device glue (must be first) */
183 struct ethercom sc_ethercom; /* Ethernet common part */
184 int sc_domain; /* Netwave domain */
185 int sc_skey; /* Netwave scramble key */
186 struct cnwstats sc_stats;
187
188 /* PCMCIA-specific stuff */
189 struct pcmcia_function *sc_pf; /* PCMCIA function */
190 struct pcmcia_io_handle sc_pcioh; /* PCMCIA I/O space handle */
191 int sc_iowin; /* ...window */
192 bus_space_tag_t sc_iot; /* ...bus_space tag */
193 bus_space_handle_t sc_ioh; /* ...bus_space handle */
194 struct pcmcia_mem_handle sc_pcmemh; /* PCMCIA memory handle */
195 bus_addr_t sc_memoff; /* ...offset */
196 int sc_memwin; /* ...window */
197 bus_space_tag_t sc_memt; /* ...bus_space tag */
198 bus_space_handle_t sc_memh; /* ...bus_space handle */
199 void *sc_ih; /* Interrupt cookie */
200 struct timeval sc_txlast; /* When the last xmit was made */
201 int sc_active; /* Currently xmitting a packet */
202 };
203
204 struct cfattach cnw_ca = {
205 sizeof(struct cnw_softc), cnw_match, cnw_attach
206 };
207
208
209 void cnw_reset __P((struct cnw_softc *));
210 void cnw_init __P((struct cnw_softc *));
211 int cnw_enable __P((struct cnw_softc *sc));
212 void cnw_disable __P((struct cnw_softc *sc));
213 void cnw_config __P((struct cnw_softc *sc, u_int8_t *));
214 void cnw_start __P((struct ifnet *));
215 void cnw_transmit __P((struct cnw_softc *, struct mbuf *));
216 struct mbuf *cnw_read __P((struct cnw_softc *));
217 void cnw_recv __P((struct cnw_softc *));
218 int cnw_intr __P((void *arg));
219 int cnw_ioctl __P((struct ifnet *, u_long, caddr_t));
220 void cnw_watchdog __P((struct ifnet *));
221 static int cnw_setdomain __P((struct cnw_softc *, int));
222 static int cnw_setkey __P((struct cnw_softc *, int));
223
224 /* ---------------------------------------------------------------- */
225
226 /* Help routines */
227 static int wait_WOC __P((struct cnw_softc *, int));
228 static int read16 __P((struct cnw_softc *, int));
229 static int cnw_cmd __P((struct cnw_softc *, int, int, int, int));
230
231 /*
232 * Wait until the WOC (Write Operation Complete) bit in the
233 * ASR (Adapter Status Register) is asserted.
234 */
235 static int
236 wait_WOC(sc, line)
237 struct cnw_softc *sc;
238 int line;
239 {
240 int i, asr;
241
242 for (i = 0; i < 5000; i++) {
243 asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
244 if (asr & CNW_ASR_WOC)
245 return (0);
246 DELAY(100);
247 }
248 if (line > 0)
249 printf("%s: wedged at line %d\n", sc->sc_dev.dv_xname, line);
250 return (1);
251 }
252 #define WAIT_WOC(sc) wait_WOC(sc, __LINE__)
253
254
255 /*
256 * Read a 16 bit value from the card.
257 */
258 static int
259 read16(sc, offset)
260 struct cnw_softc *sc;
261 int offset;
262 {
263 int hi, lo;
264 int offs = sc->sc_memoff + offset;
265
266 /* This could presumably be done more efficient with
267 * bus_space_read_2(), but I don't know anything about the
268 * byte sex guarantees... Besides, this is pretty cheap as
269 * well :-)
270 */
271 lo = bus_space_read_1(sc->sc_memt, sc->sc_memh, offs);
272 hi = bus_space_read_1(sc->sc_memt, sc->sc_memh, offs + 1);
273 return ((hi << 8) | lo);
274 }
275
276
277 /*
278 * Send a command to the card by writing it to the command buffer.
279 */
280 int
281 cnw_cmd(sc, cmd, count, arg1, arg2)
282 struct cnw_softc *sc;
283 int cmd, count, arg1, arg2;
284 {
285 int ptr = sc->sc_memoff + CNW_EREG_CB;
286
287 if (wait_WOC(sc, 0)) {
288 printf("%s: wedged when issuing cmd 0x%x\n",
289 sc->sc_dev.dv_xname, cmd);
290 /*
291 * We'll continue anyway, as that's probably the best
292 * thing we can do; at least the user knows there's a
293 * problem, and can reset the interface with ifconfig
294 * down/up.
295 */
296 }
297
298 bus_space_write_1(sc->sc_memt, sc->sc_memh, ptr, cmd);
299 if (count > 0) {
300 bus_space_write_1(sc->sc_memt, sc->sc_memh, ptr + 1, arg1);
301 if (count > 1)
302 bus_space_write_1(sc->sc_memt, sc->sc_memh,
303 ptr + 2, arg2);
304 }
305 bus_space_write_1(sc->sc_memt, sc->sc_memh,
306 ptr + count + 1, CNW_CMD_EOC);
307 return (0);
308 }
309 #define CNW_CMD0(sc, cmd) \
310 do { cnw_cmd(sc, cmd, 0, 0, 0); } while (0)
311 #define CNW_CMD1(sc, cmd, arg1) \
312 do { cnw_cmd(sc, cmd, 1, arg1 , 0); } while (0)
313 #define CNW_CMD2(sc, cmd, arg1, arg2) \
314 do { cnw_cmd(sc, cmd, 2, arg1, arg2); } while (0)
315
316 /* ---------------------------------------------------------------- */
317
318 /*
319 * Reset the hardware.
320 */
321 void
322 cnw_reset(sc)
323 struct cnw_softc *sc;
324 {
325 #ifdef CNW_DEBUG
326 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
327 printf("%s: resetting\n", sc->sc_dev.dv_xname);
328 #endif
329 wait_WOC(sc, 0);
330 bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_PMR, CNW_PMR_RESET);
331 bus_space_write_1(sc->sc_memt, sc->sc_memh,
332 sc->sc_memoff + CNW_EREG_ASCC, CNW_ASR_WOC);
333 bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_PMR, 0);
334 }
335
336
337 /*
338 * Initialize the card.
339 */
340 void
341 cnw_init(sc)
342 struct cnw_softc *sc;
343 {
344 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
345 const u_int8_t rxmode =
346 CNW_RXCONF_RXENA | CNW_RXCONF_BCAST | CNW_RXCONF_AMP;
347
348 /* Reset the card */
349 cnw_reset(sc);
350
351 /* Issue a NOP to check the card */
352 CNW_CMD0(sc, CNW_CMD_NOP);
353
354 /* Set up receive configuration */
355 CNW_CMD1(sc, CNW_CMD_SRC,
356 rxmode | ((ifp->if_flags & IFF_PROMISC) ? CNW_RXCONF_PRO : 0));
357
358 /* Set up transmit configuration */
359 CNW_CMD1(sc, CNW_CMD_STC, CNW_TXCONF_TXENA);
360
361 /* Set domain */
362 CNW_CMD2(sc, CNW_CMD_SMD, sc->sc_domain, sc->sc_domain >> 8);
363
364 /* Set scramble key */
365 CNW_CMD2(sc, CNW_CMD_SSK, sc->sc_skey, sc->sc_skey >> 8);
366
367 /* Enable interrupts */
368 WAIT_WOC(sc);
369 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
370 CNW_REG_IMR, CNW_IMR_IENA | CNW_IMR_RFU1);
371
372 /* Enable receiver */
373 CNW_CMD0(sc, CNW_CMD_ER);
374
375 /* "Set the IENA bit in COR" */
376 WAIT_WOC(sc);
377 bus_space_write_1(sc->sc_iot, sc->sc_ioh, CNW_REG_COR,
378 CNW_COR_IENA | CNW_COR_LVLREQ);
379 }
380
381
382 /*
383 * Enable and initialize the card.
384 */
385 int
386 cnw_enable(sc)
387 struct cnw_softc *sc;
388 {
389 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
390
391 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, cnw_intr, sc);
392 if (sc->sc_ih == NULL) {
393 printf("%s: couldn't establish interrupt handler\n",
394 sc->sc_dev.dv_xname);
395 return (EIO);
396 }
397 if (pcmcia_function_enable(sc->sc_pf) != 0) {
398 printf("%s: couldn't enable card\n", sc->sc_dev.dv_xname);
399 return (EIO);
400 }
401 cnw_init(sc);
402 ifp->if_flags &= ~IFF_OACTIVE;
403 ifp->if_flags |= IFF_RUNNING;
404 return (0);
405 }
406
407
408 /*
409 * Stop and disable the card.
410 */
411 void
412 cnw_disable(sc)
413 struct cnw_softc *sc;
414 {
415 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
416
417 pcmcia_function_disable(sc->sc_pf);
418 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
419 ifp->if_flags &= ~IFF_RUNNING;
420 ifp->if_timer = 0;
421 }
422
423
424 /*
425 * Match the hardware we handle.
426 */
427 int
428 cnw_match(parent, match, aux)
429 struct device *parent;
430 struct cfdata *match;
431 void *aux;
432 {
433 struct pcmcia_attach_args *pa = aux;
434
435 if (pa->manufacturer == PCMCIA_VENDOR_TDK &&
436 pa->product == PCMCIA_PRODUCT_TDK_XIR_CNW_801)
437 return 1;
438 if (pa->manufacturer == PCMCIA_VENDOR_TDK &&
439 pa->product == PCMCIA_PRODUCT_TDK_XIR_CNW_802)
440 return 1;
441 return 0;
442 }
443
444
445 /*
446 * Attach the card.
447 */
448 void
449 cnw_attach(parent, self, aux)
450 struct device *parent, *self;
451 void *aux;
452 {
453 struct cnw_softc *sc = (void *) self;
454 struct pcmcia_attach_args *pa = aux;
455 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
456 u_int8_t macaddr[ETHER_ADDR_LEN];
457 int i;
458
459 /* Enable the card */
460 sc->sc_pf = pa->pf;
461 pcmcia_function_init(sc->sc_pf, sc->sc_pf->cfe_head.sqh_first);
462 if (pcmcia_function_enable(sc->sc_pf)) {
463 printf(": function enable failed\n");
464 return;
465 }
466
467 /* Map I/O register and "memory" */
468 if (pcmcia_io_alloc(sc->sc_pf, 0, CNW_IO_SIZE, CNW_IO_SIZE,
469 &sc->sc_pcioh) != 0) {
470 printf(": can't allocate i/o space\n");
471 return;
472 }
473 if (pcmcia_io_map(sc->sc_pf, PCMCIA_WIDTH_IO16, 0,
474 CNW_IO_SIZE, &sc->sc_pcioh, &sc->sc_iowin) != 0) {
475 printf(": can't map i/o space\n");
476 return;
477 }
478 sc->sc_iot = sc->sc_pcioh.iot;
479 sc->sc_ioh = sc->sc_pcioh.ioh;
480 if (pcmcia_mem_alloc(sc->sc_pf, CNW_MEM_SIZE, &sc->sc_pcmemh) != 0) {
481 printf(": can't allocate memory\n");
482 return;
483 }
484 if (pcmcia_mem_map(sc->sc_pf, PCMCIA_MEM_COMMON, CNW_MEM_ADDR,
485 CNW_MEM_SIZE, &sc->sc_pcmemh, &sc->sc_memoff,
486 &sc->sc_memwin) != 0) {
487 printf(": can't map memory\n");
488 return;
489 }
490 sc->sc_memt = sc->sc_pcmemh.memt;
491 sc->sc_memh = sc->sc_pcmemh.memh;
492 switch (pa->product) {
493 case PCMCIA_PRODUCT_TDK_XIR_CNW_801:
494 printf(": %s\n", PCMCIA_STR_TDK_XIR_CNW_801);
495 break;
496 case PCMCIA_PRODUCT_TDK_XIR_CNW_802:
497 printf(": %s\n", PCMCIA_STR_TDK_XIR_CNW_802);
498 break;
499 }
500
501 /* Finish setup of softc */
502 sc->sc_domain = cnw_domain;
503 sc->sc_skey = cnw_skey;
504
505 /* Get MAC address */
506 cnw_reset(sc);
507 for (i = 0; i < ETHER_ADDR_LEN; i++)
508 macaddr[i] = bus_space_read_1(sc->sc_memt, sc->sc_memh,
509 sc->sc_memoff + CNW_EREG_PA + i);
510 printf("%s: address %s\n", sc->sc_dev.dv_xname,
511 ether_sprintf(macaddr));
512
513 /* Set up ifnet structure */
514 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
515 ifp->if_softc = sc;
516 ifp->if_start = cnw_start;
517 ifp->if_ioctl = cnw_ioctl;
518 ifp->if_watchdog = cnw_watchdog;
519 ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX |
520 IFF_NOTRAILERS;
521
522 /* Attach the interface */
523 if_attach(ifp);
524 ether_ifattach(ifp, macaddr);
525 #if NBPFILTER > 0
526 bpfattach(&sc->sc_ethercom.ec_if.if_bpf, ifp, DLT_EN10MB,
527 sizeof(struct ether_header));
528 #endif
529
530 ifp->if_baudrate = 1 * 1024 * 1024;
531
532 /* Disable the card now, and turn it on when the interface goes up */
533 pcmcia_function_disable(sc->sc_pf);
534 }
535
536 /*
537 * Start outputting on the interface.
538 */
539 void
540 cnw_start(ifp)
541 struct ifnet *ifp;
542 {
543 struct cnw_softc *sc = ifp->if_softc;
544 struct mbuf *m0;
545 int lif;
546 int asr;
547 #ifdef ONE_AT_A_TIME
548 struct timeval now;
549 #endif
550
551 #ifdef CNW_DEBUG
552 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
553 printf("%s: cnw_start\n", ifp->if_xname);
554 if (ifp->if_flags & IFF_OACTIVE)
555 printf("%s: cnw_start reentered\n", ifp->if_xname);
556 #endif
557
558 ifp->if_flags |= IFF_OACTIVE;
559
560 for (;;) {
561 #ifdef ONE_AT_A_TIME
562 microtime(&now);
563 now.tv_sec -= sc->sc_txlast.tv_sec;
564 now.tv_usec -= sc->sc_txlast.tv_usec;
565 if (now.tv_usec < 0) {
566 now.tv_usec += 1000000;
567 now.tv_sec--;
568 }
569
570 /*
571 * Don't ship this packet out until the last
572 * packet has left the building.
573 * If we have not tried to send a packet for 1/5
574 * a second then we assume we lost an interrupt,
575 * lets go on and send the next packet anyhow.
576 *
577 * I suppose we could check to see if it is okay
578 * to put additional packets on the card (beyond
579 * the one already waiting to be sent) but I don't
580 * think we would get any improvement in speed as
581 * we should have ample time to put the next packet
582 * on while this one is going out.
583 */
584 if (sc->sc_active && now.tv_sec == 0 && now.tv_usec < 200000)
585 break;
586 #endif
587
588 /* Make sure the link integrity field is on */
589 WAIT_WOC(sc);
590 lif = bus_space_read_1(sc->sc_memt, sc->sc_memh,
591 sc->sc_memoff + CNW_EREG_LIF);
592 if (lif == 0) {
593 #ifdef CNW_DEBUG
594 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
595 printf("%s: link integrity %d\n", lif);
596 #endif
597 break;
598 }
599
600 /* Is there any buffer space available on the card? */
601 WAIT_WOC(sc);
602 asr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
603 if (!(asr & CNW_ASR_TXBA)) {
604 #ifdef CNW_DEBUG
605 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
606 printf("%s: no buffer space\n", ifp->if_xname);
607 #endif
608 break;
609 }
610
611 sc->sc_stats.nws_tx++;
612
613 IF_DEQUEUE(&ifp->if_snd, m0);
614 if (m0 == 0)
615 break;
616
617 #if NBPFILTER > 0
618 if (ifp->if_bpf)
619 bpf_mtap(ifp->if_bpf, m0);
620 #endif
621
622 cnw_transmit(sc, m0);
623 ++ifp->if_opackets;
624 ifp->if_timer = 3; /* start watchdog timer */
625
626 microtime(&sc->sc_txlast);
627 sc->sc_active = 1;
628 }
629
630 ifp->if_flags &= ~IFF_OACTIVE;
631 }
632
633 /*
634 * Transmit a packet.
635 */
636 void
637 cnw_transmit(sc, m0)
638 struct cnw_softc *sc;
639 struct mbuf *m0;
640 {
641 int buffer, bufsize, bufoffset, bufptr, bufspace, len, mbytes, n;
642 struct mbuf *m;
643 u_int8_t *mptr;
644
645 /* Get buffer info from card */
646 buffer = read16(sc, CNW_EREG_TDP);
647 bufsize = read16(sc, CNW_EREG_TDP + 2);
648 bufoffset = read16(sc, CNW_EREG_TDP + 4);
649 #ifdef CNW_DEBUG
650 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
651 printf("%s: cnw_transmit b=0x%x s=%d o=0x%x\n",
652 sc->sc_dev.dv_xname, buffer, bufsize, bufoffset);
653 #endif
654
655 /* Copy data from mbuf chain to card buffers */
656 bufptr = sc->sc_memoff + buffer + bufoffset;
657 bufspace = bufsize;
658 len = 0;
659 for (m = m0; m; ) {
660 mptr = mtod(m, u_int8_t *);
661 mbytes = m->m_len;
662 len += mbytes;
663 while (mbytes > 0) {
664 if (bufspace == 0) {
665 buffer = read16(sc, buffer);
666 bufptr = sc->sc_memoff + buffer + bufoffset;
667 bufspace = bufsize;
668 #ifdef CNW_DEBUG
669 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
670 printf("%s: next buffer @0x%x\n",
671 sc->sc_dev.dv_xname, buffer);
672 #endif
673 }
674 n = mbytes <= bufspace ? mbytes : bufspace;
675 bus_space_write_region_1(sc->sc_memt, sc->sc_memh,
676 bufptr, mptr, n);
677 bufptr += n;
678 bufspace -= n;
679 mptr += n;
680 mbytes -= n;
681 }
682 MFREE(m, m0);
683 m = m0;
684 }
685
686 /* Issue transmit command */
687 CNW_CMD2(sc, CNW_CMD_TL, len, len >> 8);
688 }
689
690
691 /*
692 * Pull a packet from the card into an mbuf chain.
693 */
694 struct mbuf *
695 cnw_read(sc)
696 struct cnw_softc *sc;
697 {
698 struct mbuf *m, *top, **mp;
699 int totbytes, buffer, bufbytes, bufptr, mbytes, n;
700 u_int8_t *mptr;
701
702 WAIT_WOC(sc);
703 totbytes = read16(sc, CNW_EREG_RDP);
704 #ifdef CNW_DEBUG
705 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
706 printf("%s: recv %d bytes\n", sc->sc_dev.dv_xname, totbytes);
707 #endif
708 buffer = CNW_EREG_RDP + 2;
709 bufbytes = 0;
710 bufptr = 0; /* XXX make gcc happy */
711
712 MGETHDR(m, M_DONTWAIT, MT_DATA);
713 if (m == 0)
714 return (0);
715 m->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if;
716 m->m_pkthdr.len = totbytes;
717 mbytes = MHLEN;
718 top = 0;
719 mp = ⊤
720
721 while (totbytes > 0) {
722 if (top) {
723 MGET(m, M_DONTWAIT, MT_DATA);
724 if (m == 0) {
725 m_freem(top);
726 return (0);
727 }
728 mbytes = MLEN;
729 }
730 if (totbytes >= MINCLSIZE) {
731 MCLGET(m, M_DONTWAIT);
732 if ((m->m_flags & M_EXT) == 0) {
733 m_free(m);
734 m_freem(top);
735 return (0);
736 }
737 mbytes = MCLBYTES;
738 }
739 if (!top) {
740 int pad = ALIGN(sizeof(struct ether_header)) -
741 sizeof(struct ether_header);
742 m->m_data += pad;
743 mbytes -= pad;
744 }
745 mptr = mtod(m, u_int8_t *);
746 mbytes = m->m_len = min(totbytes, mbytes);
747 totbytes -= mbytes;
748 while (mbytes > 0) {
749 if (bufbytes == 0) {
750 buffer = read16(sc, buffer);
751 bufbytes = read16(sc, buffer + 2);
752 bufptr = sc->sc_memoff + buffer +
753 read16(sc, buffer + 4);
754 #ifdef CNW_DEBUG
755 if (sc->sc_ethercom.ec_if.if_flags & IFF_DEBUG)
756 printf("%s: %d bytes @0x%x+0x%x\n",
757 sc->sc_dev.dv_xname, bufbytes,
758 buffer, bufptr - buffer -
759 sc->sc_memoff);
760 #endif
761 }
762 n = mbytes <= bufbytes ? mbytes : bufbytes;
763 bus_space_read_region_1(sc->sc_memt, sc->sc_memh,
764 bufptr, mptr, n);
765 bufbytes -= n;
766 bufptr += n;
767 mbytes -= n;
768 mptr += n;
769 }
770 *mp = m;
771 mp = &m->m_next;
772 }
773
774 return (top);
775 }
776
777
778 /*
779 * Handle received packets.
780 */
781 void
782 cnw_recv(sc)
783 struct cnw_softc *sc;
784 {
785 int rser;
786 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
787 struct mbuf *m;
788 struct ether_header *eh;
789
790 for (;;) {
791 WAIT_WOC(sc);
792 rser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
793 sc->sc_memoff + CNW_EREG_RSER);
794 if (!(rser & CNW_RSER_RXAVAIL))
795 return;
796
797 /* Pull packet off card */
798 m = cnw_read(sc);
799
800 /* Acknowledge packet */
801 CNW_CMD0(sc, CNW_CMD_SRP);
802
803 /* Did we manage to get the packet from the interface? */
804 if (m == 0) {
805 ++ifp->if_ierrors;
806 return;
807 }
808 ++ifp->if_ipackets;
809
810 #if NBPFILTER > 0
811 if (ifp->if_bpf)
812 bpf_mtap(ifp->if_bpf, m);
813 #endif
814
815 /*
816 * Check that the packet is for us or {multi,broad}cast. Maybe
817 * there's a fool-poof hardware check for this, but I don't
818 * really know...
819 */
820 eh = mtod(m, struct ether_header *);
821 if ((eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
822 bcmp(LLADDR(sc->sc_ethercom.ec_if.if_sadl),
823 eh->ether_dhost, sizeof(eh->ether_dhost)) != 0) {
824 m_freem(m);
825 continue;
826 }
827
828 /* Pass the packet up. */
829 (*ifp->if_input)(ifp, m);
830 }
831 }
832
833
834 /*
835 * Interrupt handler.
836 */
837 int
838 cnw_intr(arg)
839 void *arg;
840 {
841 struct cnw_softc *sc = arg;
842 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
843 int ret, status, rser, tser;
844
845 if (!(sc->sc_ethercom.ec_if.if_flags & IFF_RUNNING))
846 return (0);
847 ifp->if_timer = 0; /* stop watchdog timer */
848
849 ret = 0;
850 for (;;) {
851 WAIT_WOC(sc);
852 if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh,
853 CNW_REG_CCSR) & 0x02)) {
854 if (ret == 0)
855 printf("%s: spurious interrupt\n",
856 sc->sc_dev.dv_xname);
857 return (ret);
858 }
859 ret = 1;
860 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, CNW_REG_ASR);
861
862 /* Anything to receive? */
863 if (status & CNW_ASR_RXRDY) {
864 sc->sc_stats.nws_rx++;
865 cnw_recv(sc);
866 }
867
868 /* Receive error */
869 if (status & CNW_ASR_RXERR) {
870 /*
871 * I get a *lot* of spurious receive errors
872 * (many per second), even when the interface
873 * is quiescent, so we don't increment
874 * if_ierrors here.
875 */
876 rser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
877 sc->sc_memoff + CNW_EREG_RSER);
878
879 /* RX statistics */
880 sc->sc_stats.nws_rxerr++;
881 if (rser & CNW_RSER_RXBIG)
882 sc->sc_stats.nws_rxframe++;
883 if (rser & CNW_RSER_RXCRC)
884 sc->sc_stats.nws_rxcrcerror++;
885 if (rser & CNW_RSER_RXOVERRUN)
886 sc->sc_stats.nws_rxoverrun++;
887 if (rser & CNW_RSER_RXOVERFLOW)
888 sc->sc_stats.nws_rxoverflow++;
889 if (rser & CNW_RSER_RXERR)
890 sc->sc_stats.nws_rxerrors++;
891 if (rser & CNW_RSER_RXAVAIL)
892 sc->sc_stats.nws_rxavail++;
893
894 /* Clear error bits in RSER */
895 WAIT_WOC(sc);
896 bus_space_write_1(sc->sc_memt, sc->sc_memh,
897 sc->sc_memoff + CNW_EREG_RSERW,
898 CNW_RSER_RXERR |
899 (rser & (CNW_RSER_RXCRC | CNW_RSER_RXBIG)));
900 /* Clear RXERR in ASR */
901 WAIT_WOC(sc);
902 bus_space_write_1(sc->sc_memt, sc->sc_memh,
903 sc->sc_memoff + CNW_EREG_ASCC, CNW_ASR_RXERR);
904 }
905
906 /* Transmit done */
907 if (status & CNW_ASR_TXDN) {
908 tser = bus_space_read_1(sc->sc_memt, sc->sc_memh,
909 CNW_EREG_TSER);
910
911 /* TX statistics */
912 if (tser & CNW_TSER_TXERR)
913 sc->sc_stats.nws_txerrors++;
914 if (tser & CNW_TSER_TXNOAP)
915 sc->sc_stats.nws_txlostcd++;
916 if (tser & CNW_TSER_TXGU)
917 sc->sc_stats.nws_txabort++;
918
919 if (tser & CNW_TSER_TXOK) {
920 sc->sc_stats.nws_txokay++;
921 sc->sc_stats.nws_txretries[status & 0xf]++;
922 WAIT_WOC(sc);
923 bus_space_write_1(sc->sc_memt, sc->sc_memh,
924 sc->sc_memoff + CNW_EREG_TSERW,
925 CNW_TSER_TXOK | CNW_TSER_RTRY);
926 }
927
928 if (tser & CNW_TSER_ERROR) {
929 ++ifp->if_oerrors;
930 WAIT_WOC(sc);
931 bus_space_write_1(sc->sc_memt, sc->sc_memh,
932 sc->sc_memoff + CNW_EREG_TSERW,
933 (tser & CNW_TSER_ERROR) |
934 CNW_TSER_RTRY);
935 }
936
937 sc->sc_active = 0;
938 ifp->if_flags &= ~IFF_OACTIVE;
939
940 /* Continue to send packets from the queue */
941 cnw_start(&sc->sc_ethercom.ec_if);
942 }
943
944 }
945 }
946
947
948 /*
949 * Handle device ioctls.
950 */
951 int
952 cnw_ioctl(ifp, cmd, data)
953 register struct ifnet *ifp;
954 u_long cmd;
955 caddr_t data;
956 {
957 struct cnw_softc *sc = ifp->if_softc;
958 struct ifaddr *ifa = (struct ifaddr *)data;
959 struct ifreq *ifr = (struct ifreq *)data;
960 int s, error = 0;
961 struct proc *p = curproc; /*XXX*/
962
963 s = splnet();
964
965 switch (cmd) {
966
967 case SIOCSIFADDR:
968 if (!(ifp->if_flags & IFF_RUNNING) &&
969 (error = cnw_enable(sc)) != 0)
970 break;
971 ifp->if_flags |= IFF_UP;
972 switch (ifa->ifa_addr->sa_family) {
973 #ifdef INET
974 case AF_INET:
975 cnw_init(sc);
976 arp_ifinit(&sc->sc_ethercom.ec_if, ifa);
977 break;
978 #endif
979 default:
980 cnw_init(sc);
981 break;
982 }
983 break;
984
985 case SIOCSIFFLAGS:
986 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_RUNNING) {
987 /*
988 * The interface is marked down and it is running, so
989 * stop it.
990 */
991 cnw_disable(sc);
992 } else if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP){
993 /*
994 * The interface is marked up and it is stopped, so
995 * start it.
996 */
997 error = cnw_enable(sc);
998 } else {
999 /* IFF_PROMISC may be changed */
1000 cnw_init(sc);
1001 }
1002 break;
1003
1004 case SIOCADDMULTI:
1005 case SIOCDELMULTI:
1006 /* Update our multicast list. */
1007 error = (cmd == SIOCADDMULTI) ?
1008 ether_addmulti(ifr, &sc->sc_ethercom) :
1009 ether_delmulti(ifr, &sc->sc_ethercom);
1010 if (error == ENETRESET || error == 0) {
1011 cnw_init(sc);
1012 error = 0;
1013 }
1014 break;
1015
1016 case SIOCGCNWDOMAIN:
1017 ((struct ifreq *)data)->ifr_domain = sc->sc_domain;
1018 break;
1019
1020 case SIOCSCNWDOMAIN:
1021 error = suser(p->p_ucred, &p->p_acflag);
1022 if (error)
1023 break;
1024 error = cnw_setdomain(sc, ifr->ifr_domain);
1025 break;
1026
1027 case SIOCSCNWKEY:
1028 error = suser(p->p_ucred, &p->p_acflag);
1029 if (error)
1030 break;
1031 error = cnw_setkey(sc, ifr->ifr_key);
1032 break;
1033
1034 case SIOCGCNWSTATUS:
1035 error = suser(p->p_ucred, &p->p_acflag);
1036 if (error)
1037 break;
1038 if ((ifp->if_flags & IFF_RUNNING) == 0)
1039 break;
1040 bus_space_read_region_1(sc->sc_memt, sc->sc_memh,
1041 sc->sc_memoff + CNW_EREG_CB,
1042 ((struct cnwstatus *)data)->data,
1043 sizeof(((struct cnwstatus *)data)->data));
1044 break;
1045
1046 case SIOCGCNWSTATS:
1047 bcopy((void *)&sc->sc_stats,
1048 (void *)&(((struct cnwistats *)data)->stats),
1049 sizeof(struct cnwstats));
1050 break;
1051
1052 default:
1053 error = EINVAL;
1054 break;
1055 }
1056
1057 splx(s);
1058 return (error);
1059 }
1060
1061
1062 /*
1063 * Device timeout/watchdog routine. Entered if the device neglects to
1064 * generate an interrupt after a transmit has been started on it.
1065 */
1066 void
1067 cnw_watchdog(ifp)
1068 struct ifnet *ifp;
1069 {
1070 struct cnw_softc *sc = ifp->if_softc;
1071
1072 printf("%s: device timeout; card reset\n", sc->sc_dev.dv_xname);
1073 ++ifp->if_oerrors;
1074 cnw_init(sc);
1075 }
1076
1077 int
1078 cnw_setdomain(sc, domain)
1079 struct cnw_softc *sc;
1080 int domain;
1081 {
1082 int s;
1083
1084 if (domain & ~0x1ff)
1085 return EINVAL;
1086
1087 s = splnet();
1088 CNW_CMD2(sc, CNW_CMD_SMD, domain, domain >> 8);
1089 splx(s);
1090
1091 sc->sc_domain = domain;
1092 return 0;
1093 }
1094
1095 int
1096 cnw_setkey(sc, key)
1097 struct cnw_softc *sc;
1098 int key;
1099 {
1100 int s;
1101
1102 if (key & ~0xffff)
1103 return EINVAL;
1104
1105 s = splnet();
1106 CNW_CMD2(sc, CNW_CMD_SSK, key, key >> 8);
1107 splx(s);
1108
1109 sc->sc_skey = key;
1110 return 0;
1111 }
1112