source: rtems/c/src/libchip/network/i82586.c @ 230acc55

5
Last change on this file since 230acc55 was 230acc55, checked in by Chris Johns <chrisj@…>, on 01/04/18 at 07:52:26

libchip: Use public include path

Update #3254.

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