source: rtems/c/src/libchip/network/i82586.c @ b7acc4ad

4.104.114.84.95
Last change on this file since b7acc4ad was b7acc4ad, checked in by Jennifer Averett <Jennifer.Averett@…>, on May 2, 2005 at 4:24:10 PM

2005-05-02 Jennifer Averett <jennifer.averett@…>

  • libchip/network/cs8900.c, libchip/network/i82586.c, libchip/network/open_eth.c, libchip/network/sonic.c, libchip/serial/mc68681.c: Modified types to remove warnings. Added initialization to remove warnings.
  • Property mode set to 100644
File size: 58.7 KB
Line 
1/*  $NetBSD: i82586.c,v 1.38 2001/07/07 05:35:39 thorpej 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 Paul Kranenburg and Charles M. Hannum.
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) 1997 Paul Kranenburg.
41 * Copyright (c) 1992, 1993, University of Vermont and State
42 *  Agricultural College.
43 * Copyright (c) 1992, 1993, Garrett A. Wollman.
44 *
45 * Portions:
46 * Copyright (c) 1994, 1995, Rafal K. Boni
47 * Copyright (c) 1990, 1991, William F. Jolitz
48 * Copyright (c) 1990, The Regents of the University of California
49 *
50 * RTEMS:
51 * Copyright (c) 2001, Chris Johns, Cybertec Pty Ltd,
52 *       http://www.cybertec.com.au/.
53 *
54 * All rights reserved.
55 *
56 * Redistribution and use in source and binary forms, with or without
57 * modification, are permitted provided that the following conditions
58 * are met:
59 * 1. Redistributions of source code must retain the above copyright
60 *    notice, this list of conditions and the following disclaimer.
61 * 2. Redistributions in binary form must reproduce the above copyright
62 *    notice, this list of conditions and the following disclaimer in the
63 *    documentation and/or other materials provided with the distribution.
64 * 3. All advertising materials mentioning features or use of this software
65 *    must display the following acknowledgement:
66 *  This product includes software developed by the University of Vermont
67 *  and State Agricultural College and Garrett A. Wollman, by William F.
68 *  Jolitz, and by the University of California, Berkeley, Lawrence
69 *  Berkeley Laboratory, and its contributors.
70 * 4. Neither the names of the Universities nor the names of the authors
71 *    may be used to endorse or promote products derived from this software
72 *    without specific prior written permission.
73 *
74 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
75 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
76 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
77 * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR AUTHORS BE LIABLE
78 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
79 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
80 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
81 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
82 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
83 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
84 * SUCH DAMAGE.
85 */
86
87/*
88 * Intel 82586 Ethernet chip
89 * Register, bit, and structure definitions.
90 *
91 * Original StarLAN driver written by Garrett Wollman with reference to the
92 * Clarkson Packet Driver code for this chip written by Russ Nelson and others.
93 *
94 * BPF support code taken from hpdev/if_le.c, supplied with tcpdump.
95 *
96 * 3C507 support is loosely based on code donated to NetBSD by Rafal Boni.
97 *
98 * Majorly cleaned up and 3C507 code merged by Charles Hannum.
99 *
100 * Converted to SUN ie driver by Charles D. Cranor,
101 *    October 1994, January 1995.
102 * This sun version based on i386 version 1.30.
103 */
104
105/*
106 * The i82586 is a very painful chip, found in sun3's, sun-4/100's
107 * sun-4/200's, and VME based suns.  The byte order is all wrong for a
108 * SUN, making life difficult.  Programming this chip is mostly the same,
109 * but certain details differ from system to system.  This driver is
110 * written so that different "ie" interfaces can be controled by the same
111 * driver.
112 */
113
114/*
115Mode of operation:
116
117   We run the 82586 in a standard Ethernet mode.  We keep NFRAMES
118   received frame descriptors around for the receiver to use, and
119   NRXBUF associated receive buffer descriptors, both in a circular
120   list.  Whenever a frame is received, we rotate both lists as
121   necessary.  (The 586 treats both lists as a simple queue.)  We also
122   keep a transmit command around so that packets can be sent off
123   quickly.
124
125   We configure the adapter in AL-LOC = 1 mode, which means that the
126   Ethernet/802.3 MAC header is placed at the beginning of the receive
127   buffer rather than being split off into various fields in the RFD.
128   This also means that we must include this header in the transmit
129   buffer as well.
130
131   By convention, all transmit commands, and only transmit commands,
132   shall have the I (IE_CMD_INTR) bit set in the command.  This way,
133   when an interrupt arrives at i82586_intr(), it is immediately possible
134   to tell what precisely caused it.  ANY OTHER command-sending
135   routines should run at splnet(), and should post an acknowledgement
136   to every interrupt they generate.
137
138   To save the expense of shipping a command to 82586 every time we
139   want to send a frame, we use a linked list of commands consisting
140   of alternate XMIT and NOP commands. The links of these elements
141   are manipulated (in iexmit()) such that the NOP command loops back
142   to itself whenever the following XMIT command is not yet ready to
143   go. Whenever an XMIT is ready, the preceding NOP link is pointed
144   at it, while its own link field points to the following NOP command.
145   Thus, a single transmit command sets off an interlocked traversal
146   of the xmit command chain, with the host processor in control of
147   the synchronization.
148*/
149
150#include <rtems.h>
151#include <rtems/error.h>
152#include <rtems/rtems_bsdnet.h>
153
154#include <ctype.h>
155#include <stdio.h>
156#include <string.h>
157#include <errno.h>
158
159#include <sys/param.h>
160#include <sys/mbuf.h>
161#include <sys/socket.h>
162#include <sys/sockio.h>
163#include <sys/ioctl.h>
164
165#include <net/ethernet.h>
166#include <net/if.h>
167#include <net/if_types.h>
168#include <net/if_dl.h>
169
170#include <netinet/in.h>
171#include <netinet/if_ether.h>
172
173#include "i82586reg.h"
174#include "i82586var.h"
175
176/*
177 * A global way to change all async cmd requests at once. For RTEMS and running
178 * as tasks I wanted to see if the tx race condition is effected by this.
179 */
180#define ASYNC_OPTION (1)
181
182void i82586_reset (struct ie_softc *, int);
183void i82586_watchdog (struct ifnet *);
184void i82586_init (void *);
185int  i82586_ioctl (struct ifnet *, u_long cmd, caddr_t data);
186void i82586_start (struct ifnet *);
187
188void i82586_stop (struct ifnet *, int);
189int  i82586_rint (struct ie_softc *, int);
190int  i82586_tint (struct ie_softc *, int);
191
192int  i82586_mediachange (struct ifnet *);
193void i82586_mediastatus (struct ifnet *, struct ifmediareq *);
194
195static void i82586_tx_task(void *arg);
196static void i82586_start_tx(struct ie_softc *sc);
197
198static int ie_readframe (struct ie_softc *, int);
199static struct mbuf *ieget (struct ie_softc *, int, int);
200static int i82586_get_rbd_list (struct ie_softc *, u_int16_t*,
201                                          u_int16_t*, int *);
202static void i82586_release_rbd_list (struct ie_softc *,
203                                     u_int16_t, u_int16_t);
204static int i82586_drop_frames (struct ie_softc *);
205static int i82586_chk_rx_ring (struct ie_softc *);
206
207static __inline__ void ie_ack (struct ie_softc *, u_int);
208static __inline__ void iexmit (struct ie_softc *);
209static void i82586_start_transceiver (struct ie_softc *);
210
211static void i82586_count_errors (struct ie_softc *);
212static void i82586_rx_errors (struct ie_softc *, int, int);
213static void i82586_setup_bufs (struct ie_softc *);
214static void setup_simple_command (struct ie_softc *, int, int);
215static int  ie_cfg_setup (struct ie_softc *, int, int, int);
216static int  ie_ia_setup (struct ie_softc *, int);
217static void ie_run_tdr (struct ie_softc *, int);
218static int  ie_mc_setup (struct ie_softc *, int);
219static void ie_mc_reset (struct ie_softc *);
220static int  i82586_start_cmd (struct ie_softc *, int, int, int, int);
221static int  i82586_cmd_wait (struct ie_softc *);
222
223#if I82586_DEBUG
224static void print_softie(struct ie_softc *sc);
225static void print_rbd (struct ie_softc *, int);
226#endif
227
228#define min(l,r) ((l) < (r) ? (l) : (r))
229#define max(l,r) ((l) > (r) ? (l) : (r))
230
231#define delay(p) rtems_task_wake_after (TOD_MICROSECONDS_TO_TICKS (p))
232
233#define i82586_WAKE_EVENT RTEMS_EVENT_1
234#define i82586_TX_EVENT   RTEMS_EVENT_2
235
236char *bitmask_snprintf(unsigned long value, const char *format, char *buf, int blen)
237{
238  char *= buf;
239  int  bit = 31;
240
241  while (bit-- > *format)
242    value <<= 1;
243
244  format++;
245
246  while (*format)
247  {
248    if (value & 0x80000000)
249      while (isalnum(*format))
250        *b++ = *format;
251    else
252      *b++ = '0';
253
254    *b++ = ',';
255
256    while (bit-- > *format)
257      value <<= 1;
258
259    format++;
260  }
261
262  *b = '\0';
263  return buf;
264}
265
266/*
267 * Front-ends call this function to attach to the MI driver.
268 *
269 * The front-end has responsibility for managing the ICP and ISCP
270 * structures. Both of these are opaque to us.  Also, the front-end
271 * chooses a location for the SCB which is expected to be addressable
272 * (through `sc->scb') as an offset against the shared-memory bus handle.
273 *
274 * The following MD interface function must be setup by the front-end
275 * before calling here:
276 *
277 *  hwreset      - board dependent reset
278 *  hwinit      - board dependent initialization
279 *  chan_attn    - channel attention
280 *  intrhook    - board dependent interrupt processing
281 *  memcopyin    - shared memory copy: board to KVA
282 *  memcopyout    - shared memory copy: KVA to board
283 *  ie_bus_read16    - read a sixteen-bit i82586 pointer
284 *  ie_bus_write16    - write a sixteen-bit i82586 pointer
285 *  ie_bus_write24    - write a twenty-four-bit i82586 pointer
286 *
287 */
288int
289i82586_attach(struct rtems_bsdnet_ifconfig *config, int attaching)
290{
291  struct ie_softc *sc;
292  struct ifnet    *ifp;
293  char            *name;
294  int             unit;
295  int             mtu;
296
297  /*
298    * Parse driver name
299   */
300
301  if ((unit = rtems_bsdnet_parse_driver_name (config, &name)) < 0)
302    return 0;
303
304  sc  = config->drv_ctrl;
305  ifp = &sc->arpcom.ac_if;
306
307#if I82586_DEBUG
308  sc->sc_debug = 0; //IED_TINT | IED_XMIT;
309#endif
310
311  if (attaching)
312  {
313    if (ifp->if_softc)
314    {
315      printf ("Driver `%s' already in use.\n", config->name);
316      return 0;
317    }
318
319    /*
320     * Process options
321     */
322
323    memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
324
325    if (config->mtu)
326      mtu = config->mtu;
327    else
328      mtu = ETHERMTU;
329
330    ifp->if_softc  = sc;
331    ifp->if_unit   = unit;
332    ifp->if_name   = name;
333    ifp->if_mtu    = mtu;
334    ifp->if_init   = i82586_init;
335    ifp->if_ioctl  = i82586_ioctl;
336    ifp->if_start  = i82586_start;
337    ifp->if_output = ether_output;
338    ifp->if_flags  = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
339
340    if (ifp->if_snd.ifq_maxlen == 0)
341      ifp->if_snd.ifq_maxlen = ifqmaxlen;
342
343    /* Attach the interface. */
344    if_attach(ifp);
345    ether_ifattach(ifp);
346    return 1;
347  }
348  return 0;
349}
350
351
352/*
353 * Interrupt Acknowledge. Mask in native byte-order.
354 */
355static __inline__ void
356ie_ack(struct ie_softc *sc, u_int mask)
357{
358  u_int status;
359
360  IE_BUS_BARRIER(sc, 0, 0, BUS_SPACE_BARRIER_READ);
361  status = sc->ie_bus_read16(sc, IE_SCB_STATUS(sc->scb));
362  i82586_start_cmd(sc, status & mask, 0, 0, 0);
363  if (sc->intrhook)
364    sc->intrhook(sc, INTR_ACK);
365}
366
367
368/*
369 * Read data off the interface, and turn it into an mbuf chain.
370 *
371 * This code is DRAMATICALLY different from the previous version; this
372 * version tries to allocate the entire mbuf chain up front, given the
373 * length of the data available.  This enables us to allocate mbuf
374 * clusters in many situations where before we would have had a long
375 * chain of partially-full mbufs.  This should help to speed up the
376 * operation considerably.  (Provided that it works, of course.)
377 */
378static __inline struct mbuf *
379ieget(struct ie_softc *sc, int head, int totlen)
380{
381  struct mbuf *m, *m0, *newm;
382  int len, resid;
383  int thisrboff, thismboff;
384  struct ether_header eh;
385
386  /*
387   * Snarf the Ethernet header.
388   */
389  (sc->memcopyin)(sc, &eh, IE_RBUF_ADDR(sc, head),
390                  sizeof(struct ether_header));
391
392  resid = totlen;
393
394  MGETHDR(m0, M_DONTWAIT, MT_DATA);
395  if (m0 == 0)
396    return (0);
397  m0->m_pkthdr.rcvif = &sc->arpcom.ac_if;
398  m0->m_pkthdr.len = totlen;
399  len = MHLEN;
400  m = m0;
401
402  /*
403   * This loop goes through and allocates mbufs for all the data we will
404   * be copying in.  It does not actually do the copying yet.
405   */
406  while (totlen > 0) {
407    if (totlen >= MINCLSIZE) {
408      MCLGET(m, M_DONTWAIT);
409      if ((m->m_flags & M_EXT) == 0)
410        goto bad;
411      len = MCLBYTES;
412    }
413
414    if (m == m0) {
415      caddr_t newdata = (caddr_t)
416        ALIGN(m->m_data + sizeof(struct ether_header)) -
417        sizeof(struct ether_header);
418      len -= newdata - m->m_data;
419      m->m_data = newdata;
420    }
421
422    m->m_len = len = min(totlen, len);
423
424    totlen -= len;
425    if (totlen > 0) {
426      MGET(newm, M_DONTWAIT, MT_DATA);
427      if (newm == 0)
428        goto bad;
429      len = MLEN;
430      m = m->m_next = newm;
431    }
432  }
433
434  m = m0;
435  thismboff = 0;
436
437  /*
438   * Copy the Ethernet header into the mbuf chain.
439   */
440  memcpy(mtod(m, caddr_t), &eh, sizeof(struct ether_header));
441  thismboff = sizeof(struct ether_header);
442  thisrboff = sizeof(struct ether_header);
443  resid -= sizeof(struct ether_header);
444
445  /*
446   * Now we take the mbuf chain (hopefully only one mbuf most of the
447   * time) and stuff the data into it.  There are no possible failures
448   * at or after this point.
449   */
450  while (resid > 0) {
451    int thisrblen = IE_RBUF_SIZE - thisrboff,
452      thismblen = m->m_len - thismboff;
453    len = min(thisrblen, thismblen);
454
455    (sc->memcopyin)(sc, mtod(m, caddr_t) + thismboff,
456                    IE_RBUF_ADDR(sc,head) + thisrboff,
457                    (u_int)len);
458    resid -= len;
459
460    if (len == thismblen) {
461      m = m->m_next;
462      thismboff = 0;
463    } else
464      thismboff += len;
465
466    if (len == thisrblen) {
467      if (++head == sc->nrxbuf)
468        head = 0;
469      thisrboff = 0;
470    } else
471      thisrboff += len;
472  }
473
474  /*
475   * Unless something changed strangely while we were doing the copy,
476   * we have now copied everything in from the shared memory.
477   * This means that we are done.
478   */
479  return (m0);
480
481  bad:
482  m_freem(m0);
483  return (0);
484}
485
486/*
487 * Setup all necessary artifacts for an XMIT command, and then pass the XMIT
488 * command to the chip to be executed.
489 */
490static __inline__ void
491iexmit(struct ie_softc *sc)
492{
493  int off;
494  int cur, prev;
495
496  cur = sc->xctail;
497
498#if I82586_DEBUG
499    I82586_TRACE(sc, I82586_TX_EMIT, cur);
500#endif
501
502#if I82586_DEBUG
503  if (sc->sc_debug & IED_XMIT)
504    printf("%s: xmit buffer %d\n", sc->arpcom.ac_if.if_name, cur);
505#endif
506
507  /*
508   * Setup the transmit command.
509   */
510  sc->ie_bus_write16(sc, IE_CMD_XMIT_DESC(sc->xmit_cmds, cur),
511                     IE_XBD_ADDR(sc->xbds, cur));
512
513  sc->ie_bus_write16(sc, IE_CMD_XMIT_STATUS(sc->xmit_cmds, cur), 0);
514
515  if (sc->do_xmitnopchain) {
516    /*
517     * Gate this XMIT command to the following NOP
518     */
519    sc->ie_bus_write16(sc, IE_CMD_XMIT_LINK(sc->xmit_cmds, cur),
520                       IE_CMD_NOP_ADDR(sc->nop_cmds, cur));
521    sc->ie_bus_write16(sc, IE_CMD_XMIT_CMD(sc->xmit_cmds, cur),
522                       IE_CMD_XMIT | IE_CMD_INTR);
523
524    /*
525     * Loopback at following NOP
526     */
527    sc->ie_bus_write16(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, cur), 0);
528    sc->ie_bus_write16(sc, IE_CMD_NOP_LINK(sc->nop_cmds, cur),
529                       IE_CMD_NOP_ADDR(sc->nop_cmds, cur));
530
531    /*
532     * Gate preceding NOP to this XMIT command
533     */
534    prev = (cur + NTXBUF - 1) % NTXBUF;
535    sc->ie_bus_write16(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, prev), 0);
536    sc->ie_bus_write16(sc, IE_CMD_NOP_LINK(sc->nop_cmds, prev),
537                       IE_CMD_XMIT_ADDR(sc->xmit_cmds, cur));
538
539    off = IE_SCB_STATUS(sc->scb);
540    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
541    if ((sc->ie_bus_read16(sc, off) & IE_CUS_ACTIVE) == 0) {
542      printf("iexmit: CU not active\n");
543      i82586_start_transceiver(sc);
544    }
545  } else {
546    sc->ie_bus_write16(sc, IE_CMD_XMIT_LINK(sc->xmit_cmds,cur),
547                       0xffff);
548
549    sc->ie_bus_write16(sc, IE_CMD_XMIT_CMD(sc->xmit_cmds, cur),
550                       IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST);
551
552    off = IE_SCB_CMDLST(sc->scb);
553    sc->ie_bus_write16(sc, off, IE_CMD_XMIT_ADDR(sc->xmit_cmds, cur));
554    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
555
556    if (i82586_start_cmd(sc, IE_CUC_START, 0, 0, ASYNC_OPTION))
557      printf("%s: iexmit: start xmit command timed out\n",
558             sc->arpcom.ac_if.if_name);
559  }
560
561  sc->arpcom.ac_if.if_timer = 5;
562}
563
564
565/*
566 * Device timeout/watchdog routine.
567 * Entered if the device neglects to generate an interrupt after a
568 * transmit has been started on it.
569 */
570void
571i82586_watchdog(struct ifnet *ifp)
572{
573  struct ie_softc *sc = ifp->if_softc;
574  printf("%s: device timeout\n", ifp->if_name);
575  ++ifp->if_oerrors;
576  i82586_reset(sc, 1);
577}
578
579static int
580i82586_cmd_wait(struct ie_softc *sc)
581{
582  /* spin on i82586 command acknowledge; wait at most 0.9 (!) seconds */
583  int i, off;
584  u_int16_t cmd;
585
586  for (i = 0; i < 900000; i++) {
587    /* Read the command word */
588    off = IE_SCB_CMD(sc->scb);
589
590    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
591    if ((cmd = sc->ie_bus_read16(sc, off)) == 0)
592      return (0);
593    delay(1);
594  }
595
596  off = IE_SCB_STATUS(sc->scb);
597  printf("i82586_cmd_wait: timo(%ssync): scb status: 0x%x, cmd: 0x%x\n",
598         sc->async_cmd_inprogress?"a":"",
599         sc->ie_bus_read16(sc, off), cmd);
600
601  return (1);  /* Timeout */
602}
603
604/*
605 * Send a command to the controller and wait for it to either complete
606 * or be accepted, depending on the command.  If the command pointer
607 * is null, then pretend that the command is not an action command.
608 * If the command pointer is not null, and the command is an action
609 * command, wait for one of the MASK bits to turn on in the command's
610 * status field.
611 * If ASYNC is set, we just call the chip's attention and return.
612 * We may have to wait for the command's acceptance later though.
613 */
614static int
615i82586_start_cmd(struct ie_softc *sc, int cmd, int iecmdbuf, int mask, int async)
616{
617  int i;
618  int off;
619
620  if (sc->async_cmd_inprogress != 0) {
621    /*
622     * If previous command was issued asynchronously, wait
623     * for it now.
624     */
625    if (i82586_cmd_wait(sc) != 0)
626      return (1);
627    sc->async_cmd_inprogress = 0;
628  }
629
630  off = IE_SCB_CMD(sc->scb);
631  sc->ie_bus_write16(sc, off, cmd);
632  IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_WRITE);
633  (sc->chan_attn)(sc, CARD_RESET);
634
635  if (async != 0) {
636    sc->async_cmd_inprogress = 1;
637    return (0);
638  }
639
640  if (IE_ACTION_COMMAND(cmd) && iecmdbuf) {
641    int status;
642    /*
643     * Now spin-lock waiting for status.  This is not a very nice
644     * thing to do, and can kill performance pretty well...
645     * According to the packet driver, the minimum timeout
646     * should be .369 seconds.
647     */
648    for (i = 0; i < 369000; i++) {
649      /* Read the command status */
650      off = IE_CMD_COMMON_STATUS(iecmdbuf);
651      IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
652      status = sc->ie_bus_read16(sc, off);
653      if (status & mask)
654        return (0);
655      delay(1);
656    }
657
658  } else {
659    /*
660     * Otherwise, just wait for the command to be accepted.
661     */
662    return (i82586_cmd_wait(sc));
663  }
664
665  /* Timeout */
666  return (1);
667}
668
669
670/*
671 * Transfer accumulated chip error counters to IF.
672 */
673static __inline void
674i82586_count_errors(struct ie_softc *sc)
675{
676  int scb = sc->scb;
677
678  sc->arpcom.ac_if.if_ierrors +=
679    sc->ie_bus_read16(sc, IE_SCB_ERRCRC(scb)) +
680    sc->ie_bus_read16(sc, IE_SCB_ERRALN(scb)) +
681    sc->ie_bus_read16(sc, IE_SCB_ERRRES(scb)) +
682    sc->ie_bus_read16(sc, IE_SCB_ERROVR(scb));
683
684  /* Clear error counters */
685  sc->ie_bus_write16(sc, IE_SCB_ERRCRC(scb), 0);
686  sc->ie_bus_write16(sc, IE_SCB_ERRALN(scb), 0);
687  sc->ie_bus_write16(sc, IE_SCB_ERRRES(scb), 0);
688  sc->ie_bus_write16(sc, IE_SCB_ERROVR(scb), 0);
689}
690
691
692static void
693i82586_rx_errors(struct ie_softc *sc, int fn, int status)
694{
695  char bits[128];
696
697  printf("%s: rx error (frame# %d): %s\n", sc->arpcom.ac_if.if_name, fn,
698         bitmask_snprintf(status, IE_FD_STATUSBITS, bits, sizeof(bits)));
699}
700
701/*
702 * i82586 interrupt entry point.
703 */
704rtems_isr
705i82586_intr(rtems_vector_number vec, void *arg)
706{
707  struct ie_softc *sc = arg;
708
709#if I82586_DEBUG
710  static unsigned long icnt = 0;
711  I82586_TRACE(sc, I82586_INTS_REQ, icnt++);
712#endif
713
714  /*
715   * Implementation dependent interrupt handling. It must at least
716   * disabled interrupts from the i82586. It is hoped this can
717   * happen somewhere outside the i82586.
718   */
719  if (sc->intrhook)
720    (sc->intrhook)(sc, INTR_ENTER);
721
722  /*
723   * Wake the task to handle the interrupt. It will
724   * enabled the interrupts when it has finished.
725   */
726  rtems_event_send (sc->intr_task, i82586_WAKE_EVENT);
727}
728
729/*
730 * i82586 interrupt task. The task is actually an extension of the interrupt
731 * with a context switch in the middle. The RTEMS TCP/IP stack requires a task
732 * be used to talk to the stack as a network semaphore is claimed. This
733 * cannot happen during an interrupt.
734 */
735static void
736i82586_intr_task(void *arg)
737{
738  struct ie_softc *sc = arg;
739  rtems_event_set events;
740  u_int           status;
741  int             off;
742  int             reset;
743
744  /*
745   * Not sure this is a good idea but as a out path exists and
746   * roads lead to it, it seems ok.
747   */
748  for (;;) {
749    rtems_bsdnet_event_receive (i82586_WAKE_EVENT,
750                                RTEMS_WAIT | RTEMS_EVENT_ANY,
751                                0, &events);
752
753    off = IE_SCB_STATUS(sc->scb);
754    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
755    status = sc->ie_bus_read16(sc, off) & IE_ST_WHENCE;
756
757#if I82586_DEBUG
758    I82586_TRACE(sc, I82586_INTS_IN, status);
759#endif
760
761    reset = 0;
762
763    while ((status & IE_ST_WHENCE) != 0) {
764#if I82586_DEBUG
765      if (sc->sc_debug)
766        printf ("%s: -------\n%s: scbstatus=0x%x\n",
767                sc->arpcom.ac_if.if_name, sc->arpcom.ac_if.if_name, status);
768#endif
769
770#if 1
771      /* Ack interrupts FIRST in case we receive more during the ISR. */
772      ie_ack(sc, status & IE_ST_WHENCE);
773#endif
774
775      i82586_start_cmd(sc, status & IE_ST_WHENCE, 0, 0, ASYNC_OPTION);
776
777      if (status & (IE_ST_FR | IE_ST_RNR))
778        if (i82586_rint(sc, status) != 0) {
779          reset = 1;
780          break;
781        }
782
783      if (status & IE_ST_CX)
784        if (i82586_tint(sc, status) != 0) {
785          reset = 1;
786          break;
787        }
788
789#if I82586_DEBUG
790      if ((status & IE_ST_CNA) && (sc->sc_debug & IED_CNA))
791        printf("%s: cna; status=0x%x\n", sc->arpcom.ac_if.if_name, status);
792#endif
793
794#if 0
795      if (sc->intrhook)
796        (sc->intrhook)(sc, INTR_LOOP);
797#endif
798
799#if 1
800      /*
801       * Interrupt ACK was posted asynchronously; wait for
802       * completion here before reading SCB status again.
803       *
804       * If ACK fails, try to reset the chip, in hopes that
805       * it helps.
806       */
807      if (i82586_cmd_wait(sc) != 0) {
808          reset = 1;
809          break;
810        }
811#endif
812
813      IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
814      status = sc->ie_bus_read16(sc, off);
815#if I82586_DEBUG
816      I82586_TRACE(sc, I82586_INTS_LOOPS, status);
817#endif
818    }
819
820    if (reset) {
821#if I82586_DEBUG
822      printf("%s: intr reset; status=0x%x\n", sc->arpcom.ac_if.if_name, status);
823#endif
824      i82586_cmd_wait(sc);
825      i82586_reset(sc, 1);
826    }
827
828#if I82586_DEBUG
829    I82586_TRACE(sc, I82586_INTS_OUT, status);
830#endif
831
832    if (sc->intrhook)
833      (sc->intrhook)(sc, INTR_EXIT);
834  }
835}
836
837/*
838 * Process a received-frame interrupt.
839 */
840int
841i82586_rint(struct ie_softc *sc, int scbstatus)
842{
843  static int timesthru = 1024;
844  int i, status, off;
845
846#if I82586_DEBUG
847  I82586_TRACE(sc, I82586_RX_INT, scbstatus);
848
849  if (sc->sc_debug & IED_RINT)
850    printf("%s: rint: status 0x%x\n",
851           sc->arpcom.ac_if.if_name, scbstatus);
852#endif
853
854  for (;;) {
855    int drop = 0;
856
857    i = sc->rfhead;
858    off = IE_RFRAME_STATUS(sc->rframes, i);
859    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
860    status = sc->ie_bus_read16(sc, off);
861
862#if I82586_DEBUG
863    if (sc->sc_debug & IED_RINT)
864      printf("%s: rint: frame(%d) status 0x%x\n",
865             sc->arpcom.ac_if.if_name, i, status);
866#endif
867    if ((status & IE_FD_COMPLETE) == 0) {
868      if ((status & IE_FD_OK) != 0) {
869        printf("%s: rint: weird: ",
870               sc->arpcom.ac_if.if_name);
871        i82586_rx_errors(sc, i, status);
872#if I82586_DEBUG
873        I82586_TRACE(sc, I82586_RX_ERR, status);
874#endif
875        break;
876      }
877      if (--timesthru == 0) {
878        /* Account the accumulated errors */
879        i82586_count_errors(sc);
880        timesthru = 1024;
881      }
882      break;
883    } else if ((status & IE_FD_OK) == 0) {
884      /*
885       * If the chip is configured to automatically
886       * discard bad frames, the only reason we can
887       * get here is an "out-of-resource" condition.
888       */
889      i82586_rx_errors(sc, i, status);
890      drop = 1;
891
892#if I82586_DEBUG
893      I82586_TRACE(sc, I82586_RX_DROP, status);
894#endif
895    }
896
897#if I82586_DEBUG
898    if ((status & IE_FD_BUSY) != 0)
899      printf("%s: rint: frame(%d) busy; status=0x%x\n",
900             sc->arpcom.ac_if.if_name, i, status);
901#endif
902
903    /*
904     * Advance the RFD list, since we're done with
905     * this descriptor.
906     */
907
908    /* Clear frame status */
909    sc->ie_bus_write16(sc, off, 0);
910
911    /* Put fence at this frame (the head) */
912    off = IE_RFRAME_LAST(sc->rframes, i);
913    sc->ie_bus_write16(sc, off, IE_FD_EOL|IE_FD_SUSP);
914
915    /* and clear RBD field */
916    off = IE_RFRAME_BUFDESC(sc->rframes, i);
917    sc->ie_bus_write16(sc, off, 0xffff);
918
919    /* Remove fence from current tail */
920    off = IE_RFRAME_LAST(sc->rframes, sc->rftail);
921    sc->ie_bus_write16(sc, off, 0);
922
923    if (++sc->rftail == sc->nframes)
924      sc->rftail = 0;
925    if (++sc->rfhead == sc->nframes)
926      sc->rfhead = 0;
927
928    /* Pull the frame off the board */
929    if (drop) {
930      i82586_drop_frames(sc);
931      if ((status & IE_FD_RNR) != 0)
932        sc->rnr_expect = 1;
933      sc->arpcom.ac_if.if_ierrors++;
934    } else if (ie_readframe(sc, i) != 0)
935      return (1);
936  }
937
938  if ((scbstatus & IE_ST_RNR) != 0) {
939
940    /*
941     * Receiver went "Not Ready". We try to figure out
942     * whether this was an expected event based on past
943     * frame status values.
944     */
945
946    if ((scbstatus & IE_RUS_SUSPEND) != 0) {
947      /*
948       * We use the "suspend on last frame" flag.
949       * Send a RU RESUME command in response, since
950       * we should have dealt with all completed frames
951       * by now.
952       */
953      printf("RINT: SUSPENDED; scbstatus=0x%x\n",
954             scbstatus);
955      if (i82586_start_cmd(sc, IE_RUC_RESUME, 0, 0, 0) == 0)
956        return (0);
957      printf("%s: RU RESUME command timed out\n",
958             sc->arpcom.ac_if.if_name);
959      return (1);  /* Ask for a reset */
960    }
961
962    if (sc->rnr_expect != 0) {
963      /*
964       * The RNR condition was announced in the previously
965       * completed frame.  Assume the receive ring is Ok,
966       * so restart the receiver without further delay.
967       */
968      i82586_start_transceiver(sc);
969      sc->rnr_expect = 0;
970      return (0);
971
972    } else if ((scbstatus & IE_RUS_NOSPACE) != 0) {
973      /*
974       * We saw no previous IF_FD_RNR flag.
975       * We check our ring invariants and, if ok,
976       * just restart the receiver at the current
977       * point in the ring.
978       */
979      if (i82586_chk_rx_ring(sc) != 0)
980        return (1);
981
982      i82586_start_transceiver(sc);
983      sc->arpcom.ac_if.if_ierrors++;
984      return (0);
985    } else
986      printf("%s: receiver not ready; scbstatus=0x%x\n",
987             sc->arpcom.ac_if.if_name, scbstatus);
988
989    sc->arpcom.ac_if.if_ierrors++;
990    return (1);  /* Ask for a reset */
991  }
992
993  return (0);
994}
995
996/*
997 * Process a command-complete interrupt.  These are only generated by the
998 * transmission of frames.  This routine is deceptively simple, since most
999 * of the real work is done by i82586_start().
1000 */
1001int
1002i82586_tint(struct ie_softc *sc, int scbstatus)
1003{
1004  struct ifnet *ifp = &sc->arpcom.ac_if;
1005  int status;
1006
1007#if I82586_DEBUG
1008  I82586_TRACE(sc, I82586_TX_INT, sc->xmit_busy);
1009#endif
1010
1011#if I82586_DEBUG
1012  if (sc->xmit_busy <= 0) {
1013    printf("i82586_tint: (%d), WEIRD: xmit_busy=%d, xctail=%d, xchead=%d\n",
1014           sc->trace_flow_in / 2, sc->xmit_busy, sc->xctail, sc->xchead);
1015    I82586_TRACE(sc, I82586_TX_BAD, sc->xctail);
1016    return (0);
1017  }
1018#endif
1019
1020  ifp->if_timer = 0;
1021  ifp->if_flags &= ~IFF_OACTIVE;
1022
1023  status = sc->ie_bus_read16(sc, IE_CMD_XMIT_STATUS(sc->xmit_cmds,
1024                                                    sc->xctail));
1025
1026#if I82586_DEBUG
1027  if (sc->sc_debug & IED_TINT)
1028    printf("%s: tint: SCB status 0x%x; xmit status 0x%x\n",
1029           sc->arpcom.ac_if.if_name, scbstatus, status);
1030#endif
1031
1032  if ((status & IE_STAT_COMPL) == 0 || (status & IE_STAT_BUSY)) {
1033    printf("i82586_tint: (%d) command still busy; status=0x%x; tail=%d\n",
1034           sc->trace_flow_in / 2, status, sc->xctail);
1035    printf("iestatus = 0x%x\n", scbstatus);
1036/*    sc->sc_debug = IED_ALL; */
1037  }
1038
1039  if (status & IE_STAT_OK) {
1040    ifp->if_opackets++;
1041    ifp->if_collisions += (status & IE_XS_MAXCOLL);
1042  } else {
1043    ifp->if_oerrors++;
1044    /*
1045     * Check SQE and DEFERRED?
1046     * What if more than one bit is set?
1047     */
1048    if (status & IE_STAT_ABORT)
1049      printf("%s: send aborted\n", sc->arpcom.ac_if.if_name);
1050    else if (status & IE_XS_NOCARRIER)
1051      printf("%s: no carrier\n", sc->arpcom.ac_if.if_name);
1052    else if (status & IE_XS_LOSTCTS)
1053      printf("%s: lost CTS\n", sc->arpcom.ac_if.if_name);
1054    else if (status & IE_XS_UNDERRUN)
1055      printf("%s: DMA underrun\n", sc->arpcom.ac_if.if_name);
1056    else if (status & IE_XS_EXCMAX) {
1057      printf("%s: too many collisions\n",
1058             sc->arpcom.ac_if.if_name);
1059      sc->arpcom.ac_if.if_collisions += 16;
1060    }
1061  }
1062
1063  /*
1064   * If multicast addresses were added or deleted while transmitting,
1065   * ie_mc_reset() set the want_mcsetup flag indicating that we
1066   * should do it.
1067   */
1068  if (sc->want_mcsetup) {
1069    ie_mc_setup(sc, IE_XBUF_ADDR(sc, sc->xctail));
1070    sc->want_mcsetup = 0;
1071  }
1072
1073  /* Done with the buffer. */
1074  sc->xmit_busy--;
1075  sc->xctail = (sc->xctail + 1) % NTXBUF;
1076
1077  /* Start the next packet, if any, transmitting. */
1078  if (sc->xmit_busy > 0)
1079    iexmit(sc);
1080
1081  i82586_start_tx(sc);
1082  return (0);
1083}
1084
1085/*
1086 * Get a range of receive buffer descriptors that represent one packet.
1087 */
1088static int
1089i82586_get_rbd_list(struct ie_softc *sc, u_int16_t *start, u_int16_t *end, int *pktlen)
1090{
1091  int  off, rbbase = sc->rbds;
1092  int  rbindex, count = 0;
1093  int  plen = 0;
1094  int  rbdstatus;
1095
1096  *start = rbindex = sc->rbhead;
1097
1098  do {
1099    off = IE_RBD_STATUS(rbbase, rbindex);
1100    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
1101    rbdstatus = sc->ie_bus_read16(sc, off);
1102    if ((rbdstatus & IE_RBD_USED) == 0) {
1103      /*
1104       * This means we are somehow out of sync.  So, we
1105       * reset the adapter.
1106       */
1107#if I82586_DEBUG
1108      print_rbd(sc, rbindex);
1109#endif
1110      printf("%s: receive descriptors out of sync at %d\n",
1111             sc->arpcom.ac_if.if_name, rbindex);
1112      return (0);
1113    }
1114    plen += (rbdstatus & IE_RBD_CNTMASK);
1115
1116    if (++rbindex == sc->nrxbuf)
1117      rbindex = 0;
1118
1119    ++count;
1120  } while ((rbdstatus & IE_RBD_LAST) == 0);
1121  *end = rbindex;
1122  *pktlen = plen;
1123  return (count);
1124}
1125
1126
1127/*
1128 * Release a range of receive buffer descriptors after we've copied the packet.
1129 */
1130static void
1131i82586_release_rbd_list(struct ie_softc *sc, u_int16_t start, u_int16_t end)
1132{
1133  int  off, rbbase = sc->rbds;
1134  int  rbindex = start;
1135
1136  do {
1137    /* Clear buffer status */
1138    off = IE_RBD_STATUS(rbbase, rbindex);
1139    sc->ie_bus_write16(sc, off, 0);
1140    if (++rbindex == sc->nrxbuf)
1141      rbindex = 0;
1142  } while (rbindex != end);
1143
1144  /* Mark EOL at new tail */
1145  rbindex = ((rbindex == 0) ? sc->nrxbuf : rbindex) - 1;
1146  off = IE_RBD_BUFLEN(rbbase, rbindex);
1147  sc->ie_bus_write16(sc, off, IE_RBUF_SIZE|IE_RBD_EOL);
1148
1149  /* Remove EOL from current tail */
1150  off = IE_RBD_BUFLEN(rbbase, sc->rbtail);
1151  sc->ie_bus_write16(sc, off, IE_RBUF_SIZE);
1152
1153  /* New head & tail pointer */
1154/* hmm, why have both? head is always (tail + 1) % NRXBUF */
1155  sc->rbhead = end;
1156  sc->rbtail = rbindex;
1157}
1158
1159/*
1160 * Drop the packet at the head of the RX buffer ring.
1161 * Called if the frame descriptor reports an error on this packet.
1162 * Returns 1 if the buffer descriptor ring appears to be corrupt;
1163 * and 0 otherwise.
1164 */
1165static int
1166i82586_drop_frames(struct ie_softc *sc)
1167{
1168  u_int16_t bstart, bend;
1169  int pktlen;
1170
1171  if (i82586_get_rbd_list(sc, &bstart, &bend, &pktlen) == 0)
1172    return (1);
1173  i82586_release_rbd_list(sc, bstart, bend);
1174  return (0);
1175}
1176
1177/*
1178 * Check the RX frame & buffer descriptor lists for our invariants,
1179 * i.e.: EOL bit set iff. it is pointed at by the r*tail pointer.
1180 *
1181 * Called when the receive unit has stopped unexpectedly.
1182 * Returns 1 if an inconsistency is detected; 0 otherwise.
1183 *
1184 * The Receive Unit is expected to be NOT RUNNING.
1185 */
1186static int
1187i82586_chk_rx_ring(struct ie_softc *sc)
1188{
1189  int n, off, val;
1190
1191  for (n = 0; n < sc->nrxbuf; n++) {
1192    off = IE_RBD_BUFLEN(sc->rbds, n);
1193    val = sc->ie_bus_read16(sc, off);
1194    if ((n == sc->rbtail) ^ ((val & IE_RBD_EOL) != 0)) {
1195      /* `rbtail' and EOL flag out of sync */
1196      printf("%s: rx buffer descriptors out of sync at %d\n",
1197             sc->arpcom.ac_if.if_name, n);
1198      return (1);
1199    }
1200
1201    /* Take the opportunity to clear the status fields here ? */
1202  }
1203
1204  for (n = 0; n < sc->nframes; n++) {
1205    off = IE_RFRAME_LAST(sc->rframes, n);
1206    val = sc->ie_bus_read16(sc, off);
1207    if ((n == sc->rftail) ^ ((val & (IE_FD_EOL|IE_FD_SUSP)) != 0)) {
1208      /* `rftail' and EOL flag out of sync */
1209      printf("%s: rx frame list out of sync at %d\n",
1210             sc->arpcom.ac_if.if_name, n);
1211      return (1);
1212    }
1213  }
1214
1215  return (0);
1216}
1217
1218
1219/*
1220 * Read frame NUM from unit UNIT (pre-cached as IE).
1221 *
1222 * This routine reads the RFD at NUM, and copies in the buffers from the list
1223 * of RBD, then rotates the RBD list so that the receiver doesn't start
1224 * complaining.  Trailers are DROPPED---there's no point in wasting time
1225 * on confusing code to deal with them.  Hopefully, this machine will
1226 * never ARP for trailers anyway.
1227 */
1228static int
1229ie_readframe(struct ie_softc *sc, int num) /* frame number to read */
1230{
1231  struct ether_header *eh;
1232  struct mbuf         *m;
1233  u_int16_t           bstart, bend;
1234  int                 pktlen;
1235
1236  if (i82586_get_rbd_list(sc, &bstart, &bend, &pktlen) == 0) {
1237    sc->arpcom.ac_if.if_ierrors++;
1238    return (1);
1239  }
1240
1241  m = ieget(sc, bstart, pktlen);
1242  i82586_release_rbd_list(sc, bstart, bend);
1243
1244  if (m == 0) {
1245    sc->arpcom.ac_if.if_ierrors++;
1246    return (0);
1247  }
1248
1249  /*
1250   * Remove the mac header. This is different from the NetBSD
1251   * stack.
1252   */
1253  eh = mtod(m, struct ether_header *);
1254  m->m_data += sizeof (struct ether_header);
1255  m->m_len -= sizeof (struct ether_header);
1256  m->m_pkthdr.len -= sizeof (struct ether_header);
1257
1258#if I82586_DEBUG
1259  if (sc->sc_debug & IED_READFRAME) {
1260
1261    printf("%s: frame from ether %s type 0x%x len %d\n",
1262           sc->arpcom.ac_if.if_name,
1263           ether_sprintf(eh->ether_shost),
1264           (u_int)ntohs(eh->ether_type),
1265           pktlen);
1266  }
1267#endif
1268
1269#if NBPFILTER > 0
1270  /* Check for a BPF filter; if so, hand it up. */
1271  if (sc->arpcom.ac_if.if_bpf != 0)
1272    /* Pass it up. */
1273    bpf_mtap(sc->arpcom.ac_if.if_bpf, m);
1274#endif /* NBPFILTER > 0 */
1275
1276  /*
1277   * Finally pass this packet up to higher layers.
1278   */
1279  ether_input (&sc->arpcom.ac_if, eh, m);
1280  sc->arpcom.ac_if.if_ipackets++;
1281
1282#if I82586_DEBUG
1283  I82586_TRACE(sc, I82586_RX_OK, sc->arpcom.ac_if.if_ipackets);
1284#endif
1285
1286  return (0);
1287}
1288
1289/*
1290 * Start transmission on an interface.
1291 */
1292void
1293i82586_start(struct ifnet *ifp)
1294{
1295  struct ie_softc *sc = ifp->if_softc;
1296
1297  if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
1298    return;
1299
1300#if I82586_DEBUG
1301  I82586_TRACE(sc, I82586_TX_REQ, sc->xmit_busy);
1302#endif
1303
1304  rtems_event_send (sc->tx_task, i82586_TX_EVENT);
1305}
1306
1307static void
1308i82586_tx_task(void *arg)
1309{
1310  struct ie_softc *sc = arg;
1311  rtems_event_set events;
1312
1313  for (;;) {
1314    rtems_bsdnet_event_receive (i82586_TX_EVENT,
1315                                RTEMS_WAIT | RTEMS_EVENT_ANY,
1316                                0, &events);
1317
1318#if I82586_DEBUG
1319    I82586_TRACE(sc, I82586_TX_EVT, sc->xmit_busy);
1320
1321    if (sc->sc_debug)
1322      printf ("%s: =======\n", sc->arpcom.ac_if.if_name);
1323#endif
1324
1325    i82586_start_tx(sc);
1326  }
1327}
1328
1329static void
1330i82586_start_tx(struct ie_softc *sc)
1331{
1332  struct ifnet *ifp = &sc->arpcom.ac_if;
1333  struct mbuf *m0, *m;
1334  int  buffer, head, xbase;
1335  u_short  len;
1336  int  s;
1337
1338#if I82586_DEBUG
1339  I82586_TRACE(sc, I82586_START_TX, sc->xmit_busy);
1340#endif
1341
1342  if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
1343  {
1344#if I82586_DEBUG
1345    I82586_TRACE(sc, I82586_TX_ACTIVE, ifp->if_snd.ifq_len);
1346#endif
1347    return;
1348  }
1349
1350  for (;;) {
1351    if (sc->xmit_busy == NTXBUF) {
1352      ifp->if_flags |= IFF_OACTIVE;
1353      break;
1354    }
1355
1356    head = sc->xchead;
1357    xbase = sc->xbds;
1358
1359    IF_DEQUEUE(&ifp->if_snd, m0);
1360    if (m0 == 0)
1361      break;
1362
1363    /* We need to use m->m_pkthdr.len, so require the header */
1364    if ((m0->m_flags & M_PKTHDR) == 0)
1365      panic("i82586_start: no header mbuf");
1366
1367#if NBPFILTER > 0
1368    /* Tap off here if there is a BPF listener. */
1369    if (ifp->if_bpf)
1370      bpf_mtap(ifp->if_bpf, m0);
1371#endif
1372
1373#if I82586_DEBUG
1374    if (sc->sc_debug & IED_ENQ)
1375      printf("%s: fill buffer %d\n", sc->arpcom.ac_if.if_name,
1376             sc->xchead);
1377#endif
1378
1379    if (m0->m_pkthdr.len > IE_TBUF_SIZE)
1380      printf("%s: tbuf overflow\n", sc->arpcom.ac_if.if_name);
1381
1382    buffer = IE_XBUF_ADDR(sc, head);
1383    for (m = m0; m != 0; m = m->m_next) {
1384      (sc->memcopyout)(sc, mtod(m,caddr_t), buffer, m->m_len);
1385      buffer += m->m_len;
1386    }
1387
1388    len = max(m0->m_pkthdr.len, ETHER_MIN_LEN);
1389    m_freem(m0);
1390
1391    /*
1392     * Setup the transmit buffer descriptor here, while we
1393     * know the packet's length.
1394     */
1395    sc->ie_bus_write16(sc, IE_XBD_FLAGS(xbase, head),
1396                       len | IE_TBD_EOL);
1397    sc->ie_bus_write16(sc, IE_XBD_NEXT(xbase, head), 0xffff);
1398    sc->ie_bus_write24(sc, IE_XBD_BUF(xbase, head),
1399                       IE_XBUF_ADDR(sc, head));
1400
1401    if (++head == NTXBUF)
1402      head = 0;
1403    sc->xchead = head;
1404
1405#if I82586_DEBUG
1406    I82586_TRACE(sc, I82586_TX_START, sc->xmit_busy);
1407#endif
1408
1409    s = splnet();
1410    /* Start the first packet transmitting. */
1411    if (sc->xmit_busy == 0)
1412      iexmit(sc);
1413
1414    sc->xmit_busy++;
1415
1416    splx(s);
1417  }
1418}
1419
1420/*
1421 * Probe IE's ram setup   [ Move all this into MD front-end!? ]
1422 * Use only if SCP and ISCP represent offsets into shared ram space.
1423 */
1424int
1425i82586_proberam(struct ie_softc *sc)
1426{
1427  int result, off;
1428
1429  /* Put in 16-bit mode */
1430  off = IE_SCP_BUS_USE(sc->scp);
1431  sc->ie_bus_write16(sc, off, 0);
1432  IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_WRITE);
1433
1434  /* Set the ISCP `busy' bit */
1435  off = IE_ISCP_BUSY(sc->iscp);
1436  sc->ie_bus_write16(sc, off, 1);
1437  IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_WRITE);
1438
1439  if (sc->hwreset)
1440    (sc->hwreset)(sc, CHIP_PROBE);
1441
1442  (sc->chan_attn) (sc, CHIP_PROBE);
1443
1444  delay(100);    /* wait a while... */
1445
1446  /* Read back the ISCP `busy' bit; it should be clear by now */
1447  off = IE_ISCP_BUSY(sc->iscp);
1448  IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
1449  result = sc->ie_bus_read16(sc, off) == 0;
1450
1451  /* Acknowledge any interrupts we may have caused. */
1452  ie_ack(sc, IE_ST_WHENCE);
1453
1454  return (result);
1455}
1456
1457void
1458i82586_reset(struct ie_softc *sc, int hard)
1459{
1460  int s = splnet();
1461
1462  if (hard)
1463    printf("%s: reset\n", sc->arpcom.ac_if.if_name);
1464
1465  /* Clear OACTIVE in case we're called from watchdog (frozen xmit). */
1466  sc->arpcom.ac_if.if_timer = 0;
1467  sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
1468
1469  /*
1470   * Stop i82586 dead in its tracks.
1471   */
1472  if (i82586_start_cmd(sc, IE_RUC_ABORT | IE_CUC_ABORT, 0, 0, 0))
1473    printf("%s: abort commands timed out\n", sc->arpcom.ac_if.if_name);
1474
1475  /*
1476   * This can really slow down the i82586_reset() on some cards, but it's
1477   * necessary to unwedge other ones (eg, the Sun VME ones) from certain
1478   * lockups.
1479   */
1480  if (hard && sc->hwreset)
1481    (sc->hwreset)(sc, CARD_RESET);
1482
1483  delay(100);
1484  ie_ack(sc, IE_ST_WHENCE);
1485
1486  if ((sc->arpcom.ac_if.if_flags & IFF_UP) != 0) {
1487    i82586_init(&sc->arpcom.ac_if);
1488  }
1489
1490  splx(s);
1491}
1492
1493static void
1494setup_simple_command(struct ie_softc *sc, int cmd, int cmdbuf)
1495{
1496  /* Setup a simple command */
1497  sc->ie_bus_write16(sc, IE_CMD_COMMON_STATUS(cmdbuf), 0);
1498  sc->ie_bus_write16(sc, IE_CMD_COMMON_CMD(cmdbuf), cmd | IE_CMD_LAST);
1499  sc->ie_bus_write16(sc, IE_CMD_COMMON_LINK(cmdbuf), 0xffff);
1500
1501  /* Assign the command buffer to the SCB command list */
1502  sc->ie_bus_write16(sc, IE_SCB_CMDLST(sc->scb), cmdbuf);
1503}
1504
1505/*
1506 * Run the time-domain reflectometer.
1507 */
1508static void
1509ie_run_tdr(struct ie_softc *sc, int cmd)
1510{
1511  int result;
1512
1513  setup_simple_command(sc, IE_CMD_TDR, cmd);
1514  sc->ie_bus_write16(sc, IE_CMD_TDR_TIME(cmd), 0);
1515
1516  if (i82586_start_cmd(sc, IE_CUC_START, cmd, IE_STAT_COMPL, 0) ||
1517      (sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmd)) & IE_STAT_OK) == 0)
1518    result = 0x10000; /* XXX */
1519  else
1520    result = sc->ie_bus_read16(sc, IE_CMD_TDR_TIME(cmd));
1521
1522  /* Squash any pending interrupts */
1523  ie_ack(sc, IE_ST_WHENCE);
1524
1525  if (result & IE_TDR_SUCCESS)
1526    return;
1527
1528  if (result & 0x10000)
1529    printf("%s: TDR command failed\n", sc->arpcom.ac_if.if_name);
1530  else if (result & IE_TDR_XCVR)
1531    printf("%s: transceiver problem\n", sc->arpcom.ac_if.if_name);
1532  else if (result & IE_TDR_OPEN)
1533    printf("%s: TDR detected incorrect termination %d clocks away\n",
1534           sc->arpcom.ac_if.if_name, result & IE_TDR_TIME);
1535  else if (result & IE_TDR_SHORT)
1536    printf("%s: TDR detected a short circuit %d clocks away\n",
1537           sc->arpcom.ac_if.if_name, result & IE_TDR_TIME);
1538  else
1539    printf("%s: TDR returned unknown status 0x%x\n",
1540           sc->arpcom.ac_if.if_name, result);
1541}
1542
1543
1544/*
1545 * i82586_setup_bufs: set up the buffers
1546 *
1547 * We have a block of KVA at sc->buf_area which is of size sc->buf_area_sz.
1548 * this is to be used for the buffers.  The chip indexs its control data
1549 * structures with 16 bit offsets, and it indexes actual buffers with
1550 * 24 bit addresses.   So we should allocate control buffers first so that
1551 * we don't overflow the 16 bit offset field.   The number of transmit
1552 * buffers is fixed at compile time.
1553 *
1554 */
1555static void
1556i82586_setup_bufs(struct ie_softc *sc)
1557{
1558  int  ptr = sc->buf_area;  /* memory pool */
1559  int     n, r;
1560
1561  /*
1562   * step 0: zero memory and figure out how many recv buffers and
1563   * frames we can have.
1564   */
1565  ptr = (ptr + 3) & ~3;  /* set alignment and stick with it */
1566
1567
1568  /*
1569   *  step 1: lay out data structures in the shared-memory area
1570   */
1571
1572  /* The no-op commands; used if "nop-chaining" is in effect */
1573  sc->nop_cmds = ptr;
1574  ptr += NTXBUF * IE_CMD_NOP_SZ;
1575
1576  /* The transmit commands */
1577  sc->xmit_cmds = ptr;
1578  ptr += NTXBUF * IE_CMD_XMIT_SZ;
1579
1580  /* The transmit buffers descriptors */
1581  sc->xbds = ptr;
1582  ptr += NTXBUF * IE_XBD_SZ;
1583
1584  /* The transmit buffers */
1585  sc->xbufs = ptr;
1586  ptr += NTXBUF * IE_TBUF_SIZE;
1587
1588  ptr = (ptr + 3) & ~3;    /* re-align.. just in case */
1589
1590  /* Compute free space for RECV stuff */
1591  n = sc->buf_area_sz - (ptr - sc->buf_area);
1592
1593  /* Compute size of one RECV frame */
1594  r = IE_RFRAME_SZ + ((IE_RBD_SZ + IE_RBUF_SIZE) * B_PER_F);
1595
1596  sc->nframes = n / r;
1597
1598  if (sc->nframes <= 0)
1599    panic("ie: bogus buffer calc\n");
1600
1601  sc->nrxbuf = sc->nframes * B_PER_F;
1602
1603  /* The receice frame descriptors */
1604  sc->rframes = ptr;
1605  ptr += sc->nframes * IE_RFRAME_SZ;
1606
1607  /* The receive buffer descriptors */
1608  sc->rbds = ptr;
1609  ptr += sc->nrxbuf * IE_RBD_SZ;
1610
1611  /* The receive buffers */
1612  sc->rbufs = ptr;
1613  ptr += sc->nrxbuf * IE_RBUF_SIZE;
1614
1615#if I82586_DEBUG
1616  printf("%s: %d frames %d bufs\n", sc->arpcom.ac_if.if_name, sc->nframes,
1617         sc->nrxbuf);
1618#endif
1619
1620  /*
1621   * step 2: link together the recv frames and set EOL on last one
1622   */
1623  for (n = 0; n < sc->nframes; n++) {
1624    int m = (n == sc->nframes - 1) ? 0 : n + 1;
1625
1626    /* Clear status */
1627    sc->ie_bus_write16(sc, IE_RFRAME_STATUS(sc->rframes,n), 0);
1628
1629    /* RBD link = NULL */
1630    sc->ie_bus_write16(sc, IE_RFRAME_BUFDESC(sc->rframes,n),
1631                       0xffff);
1632
1633    /* Make a circular list */
1634    sc->ie_bus_write16(sc, IE_RFRAME_NEXT(sc->rframes,n),
1635                       IE_RFRAME_ADDR(sc->rframes,m));
1636
1637    /* Mark last as EOL */
1638    sc->ie_bus_write16(sc, IE_RFRAME_LAST(sc->rframes,n),
1639                       ((m==0)? (IE_FD_EOL|IE_FD_SUSP) : 0));
1640  }
1641
1642  /*
1643   * step 3: link the RBDs and set EOL on last one
1644   */
1645  for (n = 0; n < sc->nrxbuf; n++) {
1646    int m = (n == sc->nrxbuf - 1) ? 0 : n + 1;
1647
1648    /* Clear status */
1649    sc->ie_bus_write16(sc, IE_RBD_STATUS(sc->rbds,n), 0);
1650
1651    /* Make a circular list */
1652    sc->ie_bus_write16(sc, IE_RBD_NEXT(sc->rbds,n),
1653                       IE_RBD_ADDR(sc->rbds,m));
1654
1655    /* Link to data buffers */
1656    sc->ie_bus_write24(sc, IE_RBD_BUFADDR(sc->rbds, n),
1657                       IE_RBUF_ADDR(sc, n));
1658    sc->ie_bus_write16(sc, IE_RBD_BUFLEN(sc->rbds,n),
1659                       IE_RBUF_SIZE | ((m==0)?IE_RBD_EOL:0));
1660  }
1661
1662  /*
1663   * step 4: all xmit no-op commands loopback onto themselves
1664   */
1665  for (n = 0; n < NTXBUF; n++) {
1666    sc->ie_bus_write16(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, n), 0);
1667
1668    sc->ie_bus_write16(sc, IE_CMD_NOP_CMD(sc->nop_cmds, n),
1669                       IE_CMD_NOP);
1670
1671    sc->ie_bus_write16(sc, IE_CMD_NOP_LINK(sc->nop_cmds, n),
1672                       IE_CMD_NOP_ADDR(sc->nop_cmds, n));
1673  }
1674
1675
1676  /*
1677   * step 6: set the head and tail pointers on receive to keep track of
1678   * the order in which RFDs and RBDs are used.
1679   */
1680
1681  /* Pointers to last packet sent and next available transmit buffer. */
1682  sc->xchead = sc->xctail = 0;
1683
1684  /* Clear transmit-busy flag and set number of free transmit buffers. */
1685  sc->xmit_busy = 0;
1686
1687  /*
1688   * Pointers to first and last receive frame.
1689   * The RFD pointed to by rftail is the only one that has EOL set.
1690   */
1691  sc->rfhead = 0;
1692  sc->rftail = sc->nframes - 1;
1693
1694  /*
1695   * Pointers to first and last receive descriptor buffer.
1696   * The RBD pointed to by rbtail is the only one that has EOL set.
1697   */
1698  sc->rbhead = 0;
1699  sc->rbtail = sc->nrxbuf - 1;
1700
1701/* link in recv frames * and buffer into the scb. */
1702#if I82586_DEBUG
1703  printf("%s: reserved %d bytes\n",
1704         sc->arpcom.ac_if.if_name, ptr - sc->buf_area);
1705#endif
1706}
1707
1708static int
1709ie_cfg_setup(struct ie_softc *sc, int cmd, int promiscuous, int manchester)
1710{
1711  int cmdresult, status;
1712  u_int8_t buf[IE_CMD_CFG_SZ]; /* XXX malloc? */
1713
1714  *IE_CMD_CFG_CNT(buf)       = 0x0c;
1715  *IE_CMD_CFG_FIFO(buf)      = 8;
1716  *IE_CMD_CFG_SAVEBAD(buf)   = 0x40;
1717  *IE_CMD_CFG_ADDRLEN(buf)   = 0x2e;
1718  *IE_CMD_CFG_PRIORITY(buf)  = 0;
1719  *IE_CMD_CFG_IFS(buf)       = 0x60;
1720  *IE_CMD_CFG_SLOT_LOW(buf)  = 0;
1721  *IE_CMD_CFG_SLOT_HIGH(buf) = 0xf2;
1722  *IE_CMD_CFG_PROMISC(buf)   = !!promiscuous | manchester << 2;
1723  *IE_CMD_CFG_CRSCDT(buf)    = 0;
1724  *IE_CMD_CFG_MINLEN(buf)    = 64;
1725  *IE_CMD_CFG_JUNK(buf)      = 0xff;
1726  sc->memcopyout(sc, buf, cmd, IE_CMD_CFG_SZ);
1727  setup_simple_command(sc, IE_CMD_CONFIG, cmd);
1728  IE_BUS_BARRIER(sc, cmd, IE_CMD_CFG_SZ, BUS_SPACE_BARRIER_WRITE);
1729
1730  cmdresult = i82586_start_cmd(sc, IE_CUC_START, cmd, IE_STAT_COMPL, 0);
1731  status = sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmd));
1732  if (cmdresult != 0) {
1733    printf("%s: configure command timed out; status %x\n",
1734           sc->arpcom.ac_if.if_name, status);
1735    return (0);
1736  }
1737  if ((status & IE_STAT_OK) == 0) {
1738    printf("%s: configure command failed; status %x\n",
1739           sc->arpcom.ac_if.if_name, status);
1740    return (0);
1741  }
1742
1743  /* Squash any pending interrupts */
1744  ie_ack(sc, IE_ST_WHENCE);
1745  return (1);
1746}
1747
1748static int
1749ie_ia_setup(struct ie_softc *sc, int cmdbuf)
1750{
1751  int cmdresult, status;
1752
1753  setup_simple_command(sc, IE_CMD_IASETUP, cmdbuf);
1754
1755  (sc->memcopyout)(sc, sc->arpcom.ac_enaddr,
1756                   IE_CMD_IAS_EADDR(cmdbuf), ETHER_ADDR_LEN);
1757
1758  cmdresult = i82586_start_cmd(sc, IE_CUC_START, cmdbuf, IE_STAT_COMPL, 0);
1759  status = sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmdbuf));
1760  if (cmdresult != 0) {
1761    printf("%s: individual address command timed out; status %x\n",
1762           sc->arpcom.ac_if.if_name, status);
1763    return (0);
1764  }
1765  if ((status & IE_STAT_OK) == 0) {
1766    printf("%s: individual address command failed; status %x\n",
1767           sc->arpcom.ac_if.if_name, status);
1768    return (0);
1769  }
1770
1771  /* Squash any pending interrupts */
1772  ie_ack(sc, IE_ST_WHENCE);
1773  return (1);
1774}
1775
1776/*
1777 * Run the multicast setup command.
1778 * Called at splnet().
1779 */
1780static int
1781ie_mc_setup(struct ie_softc *sc, int cmdbuf)
1782{
1783  int cmdresult, status;
1784
1785  if (sc->mcast_count == 0)
1786    return (1);
1787
1788  setup_simple_command(sc, IE_CMD_MCAST, cmdbuf);
1789
1790  (sc->memcopyout)(sc, (caddr_t)sc->mcast_addrs,
1791                   IE_CMD_MCAST_MADDR(cmdbuf),
1792                   sc->mcast_count * ETHER_ADDR_LEN);
1793
1794  sc->ie_bus_write16(sc, IE_CMD_MCAST_BYTES(cmdbuf),
1795                     sc->mcast_count * ETHER_ADDR_LEN);
1796
1797  /* Start the command */
1798  cmdresult = i82586_start_cmd(sc, IE_CUC_START, cmdbuf, IE_STAT_COMPL, 0);
1799  status = sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmdbuf));
1800  if (cmdresult != 0) {
1801    printf("%s: multicast setup command timed out; status %x\n",
1802           sc->arpcom.ac_if.if_name, status);
1803    return (0);
1804  }
1805  if ((status & IE_STAT_OK) == 0) {
1806    printf("%s: multicast setup command failed; status %x\n",
1807           sc->arpcom.ac_if.if_name, status);
1808    return (0);
1809  }
1810
1811  /* Squash any pending interrupts */
1812  ie_ack(sc, IE_ST_WHENCE);
1813  return (1);
1814}
1815
1816/*
1817 * This routine takes the environment generated by check_ie_present() and adds
1818 * to it all the other structures we need to operate the adapter.  This
1819 * includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands, starting
1820 * the receiver unit, and clearing interrupts.
1821 *
1822 * THIS ROUTINE MUST BE CALLED AT splnet() OR HIGHER.
1823 */
1824void
1825i82586_init(void *arg)
1826{
1827  struct ie_softc *sc  = arg;
1828  struct ifnet    *ifp = &sc->arpcom.ac_if;
1829  int             cmd;
1830
1831  sc->async_cmd_inprogress = 0;
1832  sc->xmit_busy = 0;
1833
1834#if I82586_DEBUG
1835  memset(sc->trace_flow, 0, sizeof(sc->trace_flow));
1836  sc->trace_flow_wrap = 0;
1837#endif
1838  sc->trace_flow_in = 0;
1839
1840  cmd = sc->buf_area;
1841
1842#if I82586_DEBUG
1843  printf ("%s: sc_debug at 0x%08x\n", sc->arpcom.ac_if.if_name, (unsigned int) &sc->sc_debug);
1844#endif
1845
1846  /*
1847   * Send the configure command first.
1848   */
1849  if (ie_cfg_setup(sc, cmd, sc->promisc, 0) == 0)
1850    return;
1851
1852  /*
1853   * Send the Individual Address Setup command.
1854   */
1855  if (ie_ia_setup(sc, cmd) == 0)
1856    return;
1857
1858  /*
1859   * Run the time-domain reflectometer.
1860   */
1861  ie_run_tdr(sc, cmd);
1862
1863  /*
1864   * Set the multi-cast filter, if any
1865   */
1866  if (ie_mc_setup(sc, cmd) == 0)
1867    return;
1868
1869  /*
1870   * If no tasks exist, create them. Need to add something to allow
1871   * different names for the different devices.
1872   */
1873  if (sc->intr_task == 0)
1874    sc->intr_task = rtems_bsdnet_newproc ("IEi0", 2048, i82586_intr_task, sc);
1875  if (sc->tx_task == 0)
1876    sc->tx_task = rtems_bsdnet_newproc ("IEt0", 2048, i82586_tx_task, sc);
1877
1878
1879  /*
1880   * Acknowledge any interrupts we have generated thus far.
1881   */
1882  ie_ack(sc, IE_ST_WHENCE);
1883
1884  /*
1885   * Set up the transmit and recv buffers.
1886   */
1887  i82586_setup_bufs(sc);
1888
1889  if (sc->hwinit)
1890    (sc->hwinit)(sc);
1891
1892  ifp->if_flags |= IFF_RUNNING;
1893  ifp->if_flags &= ~IFF_OACTIVE;
1894
1895  if (NTXBUF < 2)
1896    sc->do_xmitnopchain = 0;
1897
1898  i82586_start_transceiver(sc);
1899}
1900
1901/*
1902 * Start the RU and possibly the CU unit
1903 */
1904static void
1905i82586_start_transceiver(struct ie_softc *sc)
1906{
1907#if I82586_DEBUG
1908      I82586_TRACE(sc, I82586_RX_START, 0);
1909#endif
1910
1911  /*
1912   * Start RU at current position in frame & RBD lists.
1913   */
1914  sc->ie_bus_write16(sc, IE_RFRAME_BUFDESC(sc->rframes,sc->rfhead),
1915                     IE_RBD_ADDR(sc->rbds, sc->rbhead));
1916
1917  sc->ie_bus_write16(sc, IE_SCB_RCVLST(sc->scb),
1918                     IE_RFRAME_ADDR(sc->rframes,sc->rfhead));
1919
1920  if (sc->do_xmitnopchain) {
1921    /* Stop transmit command chain */
1922    if (i82586_start_cmd(sc, IE_CUC_SUSPEND|IE_RUC_SUSPEND, 0, 0, 0))
1923      printf("%s: CU/RU stop command timed out\n",
1924             sc->arpcom.ac_if.if_name);
1925
1926    /* Start the receiver & transmitter chain */
1927    /* sc->scb->ie_command_list =
1928       IEADDR(sc->nop_cmds[(sc->xctail+NTXBUF-1) % NTXBUF]);*/
1929    sc->ie_bus_write16(sc, IE_SCB_CMDLST(sc->scb),
1930                       IE_CMD_NOP_ADDR(
1931                         sc->nop_cmds,
1932                         (sc->xctail + NTXBUF - 1) % NTXBUF));
1933
1934    if (i82586_start_cmd(sc, IE_CUC_START|IE_RUC_START, 0, 0, 0))
1935      printf("%s: CU/RU command timed out\n",
1936             sc->arpcom.ac_if.if_name);
1937  } else {
1938    if (i82586_start_cmd(sc, IE_RUC_START, 0, 0, 0))
1939      printf("%s: RU command timed out\n",
1940             sc->arpcom.ac_if.if_name);
1941  }
1942}
1943
1944void
1945i82586_stop(struct ifnet *ifp, int disable)
1946{
1947  struct ie_softc *sc = ifp->if_softc;
1948
1949  if (i82586_start_cmd(sc, IE_RUC_SUSPEND | IE_CUC_SUSPEND, 0, 0, 0))
1950    printf("%s: iestop: disable commands timed out\n",
1951           sc->arpcom.ac_if.if_name);
1952}
1953
1954int
1955i82586_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1956{
1957  struct ie_softc *sc  = ifp->if_softc;
1958/*  struct ifreq    *ifr = (struct ifreq *)data; */
1959  int             s;
1960  int             error = 0;
1961
1962  s = splnet();
1963  switch(cmd) {
1964    case SIOCGIFMEDIA:
1965    case SIOCSIFMEDIA:
1966      break;
1967    case SIO_RTEMS_SHOW_STATS:
1968#if I82586_DEBUG
1969      print_softie(sc);
1970#endif
1971      break;
1972    default:
1973      error = ether_ioctl(ifp, cmd, data);
1974      if (error == ENETRESET) {
1975        /*
1976         * Multicast list has changed; set the hardware filter
1977         * accordingly.
1978         */
1979        ie_mc_reset(sc);
1980        error = 0;
1981      }
1982      break;
1983  }
1984#if I82586_DEBUG
1985  if (cmd == SIOCSIFFLAGS)
1986    sc->sc_debug = (ifp->if_flags & IFF_DEBUG) ? IED_ALL : 0;
1987#endif
1988  splx(s);
1989  return (error);
1990}
1991
1992static void
1993ie_mc_reset(struct ie_softc *sc)
1994{
1995  struct ether_multi *enm;
1996  struct ether_multistep step;
1997  int size;
1998
1999  /*
2000   * Step through the list of addresses.
2001   */
2002  again:
2003  size = 0;
2004  sc->mcast_count = 0;
2005  ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
2006  while (enm) {
2007    size += 6;
2008    if (sc->mcast_count >= IE_MAXMCAST ||
2009        memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2010      sc->arpcom.ac_if.if_flags |= IFF_ALLMULTI;
2011      i82586_ioctl(&sc->arpcom.ac_if,
2012                   SIOCSIFFLAGS, (void *)0);
2013      return;
2014    }
2015    ETHER_NEXT_MULTI(step, enm);
2016  }
2017
2018  if (size > sc->mcast_addrs_size) {
2019    /* Need to allocate more space */
2020    if (sc->mcast_addrs_size)
2021      free(sc->mcast_addrs, M_IPMADDR);
2022    sc->mcast_addrs = (char *)
2023      malloc(size, M_IPMADDR, M_WAITOK);
2024    sc->mcast_addrs_size = size;
2025  }
2026
2027  /*
2028   * We've got the space; now copy the addresses
2029   */
2030  ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
2031  while (enm) {
2032    if (sc->mcast_count >= IE_MAXMCAST)
2033      goto again; /* Just in case */
2034
2035    memcpy(&sc->mcast_addrs[sc->mcast_count], enm->enm_addrlo, 6);
2036    sc->mcast_count++;
2037    ETHER_NEXT_MULTI(step, enm);
2038  }
2039  sc->want_mcsetup = 1;
2040}
2041
2042/*
2043 * Media change callback.
2044 */
2045int
2046i82586_mediachange(struct ifnet *ifp)
2047{
2048  struct ie_softc *sc = ifp->if_softc;
2049
2050  if (sc->sc_mediachange)
2051    return ((*sc->sc_mediachange)(sc));
2052  return (0);
2053}
2054
2055/*
2056 * Media status callback.
2057 */
2058void
2059i82586_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
2060{
2061  struct ie_softc *sc = ifp->if_softc;
2062
2063  if (sc->sc_mediastatus)
2064    (*sc->sc_mediastatus)(sc, ifmr);
2065}
2066
2067#if I82586_DEBUG
2068static void
2069print_softie(struct ie_softc *sc)
2070{
2071  static char *trace_labels[] = {
2072    "INTS_REQ",
2073    "INTS_IN",
2074    "INTS_LOOPS",
2075    "INTS_OUT",
2076    "RX_INT",
2077    "RX_DROP",
2078    "RX_ERR",
2079    "RX_OK",
2080    "RX_START",
2081    "START_TX",
2082    "TX_START",
2083    "TX_INT",
2084    "TX_REQ",
2085    "TX_EVT",
2086    "TX_EMIT",
2087    "TX_BAD",
2088    "TX_ACTIVE",
2089    "TRACE_CNT"
2090  };
2091
2092  int i;
2093
2094  printf("i82586 %s:\n", sc->arpcom.ac_if.if_name);
2095
2096  printf(" iobase=%p\n", sc->sc_iobase);
2097
2098  printf(" scp=0x%08x\t\tiscp=0x%08x\t\tscb=0x%08x\n",
2099         sc->scp, sc->iscp, sc->scb);
2100  printf(" buf_area=0x%08x\tbuf_area_sz=0x%08x\n",
2101         sc->buf_area, sc->buf_area_sz);
2102  printf(" rframes=0x%08x\trbds=0x%08x\t\trbufs=0x%08x\n",
2103         sc->rframes, sc->rbds, sc->rbufs);
2104  printf(" nop_cmds=0x%08x\txmit_cmds=0x%08x\n",
2105         sc->nop_cmds, sc->xmit_cmds);
2106  printf(" xbds=0x%08x\txbufs=0x%08x\n\n",
2107         sc->xbds, sc->xbufs);
2108  printf(" rfhead=%d\trftail=%d\n",
2109         sc->rfhead, sc->rftail);
2110  printf(" rbhead=%d\trbtail=%d\n",
2111         sc->rbhead, sc->rbtail);
2112  printf(" nframes=%d\tnrxbuf=%d\trnr_expect=%d\n",
2113         sc->nframes, sc->nrxbuf, sc->rnr_expect);
2114  printf(" xchead=%d\txctail=%d\n",
2115         sc->xchead, sc->xctail);
2116  printf(" xmit_busy=%d\txmit_req=%d\tdo_xmitnopchain=%d\n",
2117         sc->xmit_busy, sc->xmit_req, sc->do_xmitnopchain);
2118  printf(" promisc=%d\tasync_cmd_inprogress=%d\n\n",
2119         sc->promisc, sc->async_cmd_inprogress);
2120
2121  {
2122    int cnt;
2123    int in;
2124    int lfdone = 0;
2125    char *tabs;
2126
2127    if (!sc->trace_flow_wrap) {
2128      cnt = sc->trace_flow_in;
2129      in = 0;
2130    }
2131    else {
2132      cnt = I82586_TRACE_FLOW;
2133      in = sc->trace_flow_in;
2134    }
2135
2136    sc->trace_flow_in = sc->trace_flow_wrap = 0;
2137
2138    cnt /= 2;
2139
2140    for (i = 0; i < cnt; i++) {
2141      if (!lfdone) {
2142        switch (sc->trace_flow[in]) {
2143          case I82586_INTS_REQ:
2144          case I82586_INTS_IN:
2145            printf("\n");
2146        }
2147      }
2148
2149      lfdone = 0;
2150
2151      if (strlen(trace_labels[sc->trace_flow[in]]) < 8)
2152        tabs = "\t\t";
2153      else
2154        tabs = "\t";
2155
2156      printf(" %d\t%s%s0x%08x (%d)\n",
2157             i, trace_labels[sc->trace_flow[in]], tabs,
2158             sc->trace_flow[in + 1], sc->trace_flow[in + 1]);
2159
2160      switch (sc->trace_flow[in]) {
2161        case I82586_INTS_REQ:
2162        case I82586_INTS_OUT:
2163          lfdone = 1;
2164          printf("\n");
2165      }
2166
2167      in += 2;
2168
2169      if (in >= I82586_TRACE_FLOW)
2170        in = 0;
2171    }
2172  }
2173}
2174
2175static void
2176print_rbd(struct ie_softc *sc, int n)
2177{
2178  printf("RBD at %08x:\n  status %04x, next %04x, buffer %lx\n"
2179         "length/EOL %04x\n", IE_RBD_ADDR(sc->rbds,n),
2180         sc->ie_bus_read16(sc, IE_RBD_STATUS(sc->rbds,n)),
2181         sc->ie_bus_read16(sc, IE_RBD_NEXT(sc->rbds,n)),
2182         (u_long)0,/*bus_space_read_4(sc->bt, sc->bh, IE_RBD_BUFADDR(sc->rbds,n)),-* XXX */
2183         sc->ie_bus_read16(sc, IE_RBD_BUFLEN(sc->rbds,n)));
2184}
2185
2186#endif
Note: See TracBrowser for help on using the repository browser.