source: rtems/c/src/libchip/network/i82586.c @ 18b6986

4.104.114.84.95
Last change on this file since 18b6986 was 18b6986, checked in by Joel Sherrill <joel.sherrill@…>, on 04/13/02 at 16:42:23

2002-04-11 Chris Johns <ccj@…>

  • network/rtems_bsdnet.h: To address PR59, added the drv_ctrl driver control block field to the ifconfig network driver structure. This field is needed by the i82586 driver which was ported from NetBSD as it had better hardware abstraction.
  • Property mode set to 100644
File size: 58.9 KB
RevLine 
[6a9db57]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>
[9c6a99f]156#include <string.h>
[6a9db57]157
158#include <sys/param.h>
159#include <sys/mbuf.h>
160#include <sys/socket.h>
161#include <sys/sockio.h>
162#include <sys/ioctl.h>
163#include <sys/errno.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 *, int 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 *b  = 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
266char *ether_sprintf(unsigned char *addr)
267{
268  static char buf[32];
269  char *b = buf;
270  int i;
271 
272  for (i = 0; i < ETHER_ADDR_LEN; i++)
273  {
274    sprintf(b, "%02x:", *addr++);
275    b += 3;
276  }
277  b--;
278  b = "\0";
279  return buf;
280}
281
282/*
283 * Front-ends call this function to attach to the MI driver.
284 *
285 * The front-end has responsibility for managing the ICP and ISCP
286 * structures. Both of these are opaque to us.  Also, the front-end
287 * chooses a location for the SCB which is expected to be addressable
288 * (through `sc->scb') as an offset against the shared-memory bus handle.
289 *
290 * The following MD interface function must be setup by the front-end
291 * before calling here:
292 *
293 *  hwreset      - board dependent reset
294 *  hwinit      - board dependent initialization
295 *  chan_attn    - channel attention
296 *  intrhook    - board dependent interrupt processing
297 *  memcopyin    - shared memory copy: board to KVA
298 *  memcopyout    - shared memory copy: KVA to board
299 *  ie_bus_read16    - read a sixteen-bit i82586 pointer
300 *  ie_bus_write16    - write a sixteen-bit i82586 pointer
301 *  ie_bus_write24    - write a twenty-four-bit i82586 pointer
302 *
303 */
304int
305i82586_attach(struct rtems_bsdnet_ifconfig *config, int attaching)
306{
307  struct ie_softc *sc;
308  struct ifnet    *ifp;
309  char            *name;
310  int             unit;
311  int             mtu;
312 
313  /*
314    * Parse driver name
315   */
316 
317  if ((unit = rtems_bsdnet_parse_driver_name (config, &name)) < 0)
318    return 0;
319 
[18b6986]320  sc  = config->drv_ctrl;
[6a9db57]321  ifp = &sc->arpcom.ac_if;
322 
323#if I82586_DEBUG
324  sc->sc_debug = 0; //IED_TINT | IED_XMIT;
325#endif
326
327  if (attaching)
328  {
329    if (ifp->if_softc)
330    {
331      printf ("Driver `%s' already in use.\n", config->name);
332      return 0;
333    }
334   
335    /*
336     * Process options
337     */
338   
339    memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
340 
341    if (config->mtu)
342      mtu = config->mtu;
343    else
344      mtu = ETHERMTU;
345   
346    ifp->if_softc  = sc;
347    ifp->if_unit   = unit;
348    ifp->if_name   = name;
349    ifp->if_mtu    = mtu;
350    ifp->if_init   = i82586_init;
351    ifp->if_ioctl  = i82586_ioctl;
352    ifp->if_start  = i82586_start;
353    ifp->if_output = ether_output;
354    ifp->if_flags  = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
355
356    if (ifp->if_snd.ifq_maxlen == 0)
357      ifp->if_snd.ifq_maxlen = ifqmaxlen;
358
359    /* Attach the interface. */
360    if_attach(ifp);
361    ether_ifattach(ifp);
362    return 1;
363  }
364  return 0;
365}
366
367
368/*
369 * Interrupt Acknowledge. Mask in native byte-order.
370 */
371static __inline__ void
372ie_ack(struct ie_softc *sc, u_int mask)
373{
374  u_int status;
375
376  IE_BUS_BARRIER(sc, 0, 0, BUS_SPACE_BARRIER_READ);
377  status = sc->ie_bus_read16(sc, IE_SCB_STATUS(sc->scb));
378  i82586_start_cmd(sc, status & mask, 0, 0, 0);
379  if (sc->intrhook)
380    sc->intrhook(sc, INTR_ACK);
381}
382
383
384/*
385 * Read data off the interface, and turn it into an mbuf chain.
386 *
387 * This code is DRAMATICALLY different from the previous version; this
388 * version tries to allocate the entire mbuf chain up front, given the
389 * length of the data available.  This enables us to allocate mbuf
390 * clusters in many situations where before we would have had a long
391 * chain of partially-full mbufs.  This should help to speed up the
392 * operation considerably.  (Provided that it works, of course.)
393 */
394static __inline struct mbuf *
395ieget(struct ie_softc *sc, int head, int totlen)
396{
397  struct mbuf *m, *m0, *newm;
398  int len, resid;
399  int thisrboff, thismboff;
400  struct ether_header eh;
401
402  /*
403   * Snarf the Ethernet header.
404   */
405  (sc->memcopyin)(sc, &eh, IE_RBUF_ADDR(sc, head),
406                  sizeof(struct ether_header));
407
408  resid = totlen;
409
410  MGETHDR(m0, M_DONTWAIT, MT_DATA);
411  if (m0 == 0)
412    return (0);
413  m0->m_pkthdr.rcvif = &sc->arpcom.ac_if;
414  m0->m_pkthdr.len = totlen;
415  len = MHLEN;
416  m = m0;
417
418  /*
419   * This loop goes through and allocates mbufs for all the data we will
420   * be copying in.  It does not actually do the copying yet.
421   */
422  while (totlen > 0) {
423    if (totlen >= MINCLSIZE) {
424      MCLGET(m, M_DONTWAIT);
425      if ((m->m_flags & M_EXT) == 0)
426        goto bad;
427      len = MCLBYTES;
428    }
429
430    if (m == m0) {
431      caddr_t newdata = (caddr_t)
432        ALIGN(m->m_data + sizeof(struct ether_header)) -
433        sizeof(struct ether_header);
434      len -= newdata - m->m_data;
435      m->m_data = newdata;
436    }
437
438    m->m_len = len = min(totlen, len);
439
440    totlen -= len;
441    if (totlen > 0) {
442      MGET(newm, M_DONTWAIT, MT_DATA);
443      if (newm == 0)
444        goto bad;
445      len = MLEN;
446      m = m->m_next = newm;
447    }
448  }
449
450  m = m0;
451  thismboff = 0;
452
453  /*
454   * Copy the Ethernet header into the mbuf chain.
455   */
456  memcpy(mtod(m, caddr_t), &eh, sizeof(struct ether_header));
457  thismboff = sizeof(struct ether_header);
458  thisrboff = sizeof(struct ether_header);
459  resid -= sizeof(struct ether_header);
460
461  /*
462   * Now we take the mbuf chain (hopefully only one mbuf most of the
463   * time) and stuff the data into it.  There are no possible failures
464   * at or after this point.
465   */
466  while (resid > 0) {
467    int thisrblen = IE_RBUF_SIZE - thisrboff,
468      thismblen = m->m_len - thismboff;
469    len = min(thisrblen, thismblen);
470
471    (sc->memcopyin)(sc, mtod(m, caddr_t) + thismboff,
472                    IE_RBUF_ADDR(sc,head) + thisrboff,
473                    (u_int)len);
474    resid -= len;
475
476    if (len == thismblen) {
477      m = m->m_next;
478      thismboff = 0;
479    } else
480      thismboff += len;
481
482    if (len == thisrblen) {
483      if (++head == sc->nrxbuf)
484        head = 0;
485      thisrboff = 0;
486    } else
487      thisrboff += len;
488  }
489
490  /*
491   * Unless something changed strangely while we were doing the copy,
492   * we have now copied everything in from the shared memory.
493   * This means that we are done.
494   */
495  return (m0);
496
497  bad:
498  m_freem(m0);
499  return (0);
500}
501
502/*
503 * Setup all necessary artifacts for an XMIT command, and then pass the XMIT
504 * command to the chip to be executed.
505 */
506static __inline__ void
507iexmit(struct ie_softc *sc)
508{
509  int off;
510  int cur, prev;
511
512  cur = sc->xctail;
513
514#if I82586_DEBUG
515    I82586_TRACE(sc, I82586_TX_EMIT, cur);
516#endif
517   
518#if I82586_DEBUG
519  if (sc->sc_debug & IED_XMIT)
520    printf("%s: xmit buffer %d\n", sc->arpcom.ac_if.if_name, cur);
521#endif
522
523  /*
524   * Setup the transmit command.
525   */
526  sc->ie_bus_write16(sc, IE_CMD_XMIT_DESC(sc->xmit_cmds, cur),
527                     IE_XBD_ADDR(sc->xbds, cur));
528
529  sc->ie_bus_write16(sc, IE_CMD_XMIT_STATUS(sc->xmit_cmds, cur), 0);
530
531  if (sc->do_xmitnopchain) {
532    /*
533     * Gate this XMIT command to the following NOP
534     */
535    sc->ie_bus_write16(sc, IE_CMD_XMIT_LINK(sc->xmit_cmds, cur),
536                       IE_CMD_NOP_ADDR(sc->nop_cmds, cur));
537    sc->ie_bus_write16(sc, IE_CMD_XMIT_CMD(sc->xmit_cmds, cur),
538                       IE_CMD_XMIT | IE_CMD_INTR);
539
540    /*
541     * Loopback at following NOP
542     */
543    sc->ie_bus_write16(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, cur), 0);
544    sc->ie_bus_write16(sc, IE_CMD_NOP_LINK(sc->nop_cmds, cur),
545                       IE_CMD_NOP_ADDR(sc->nop_cmds, cur));
546
547    /*
548     * Gate preceding NOP to this XMIT command
549     */
550    prev = (cur + NTXBUF - 1) % NTXBUF;
551    sc->ie_bus_write16(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, prev), 0);
552    sc->ie_bus_write16(sc, IE_CMD_NOP_LINK(sc->nop_cmds, prev),
553                       IE_CMD_XMIT_ADDR(sc->xmit_cmds, cur));
554
555    off = IE_SCB_STATUS(sc->scb);
556    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
557    if ((sc->ie_bus_read16(sc, off) & IE_CUS_ACTIVE) == 0) {
558      printf("iexmit: CU not active\n");
559      i82586_start_transceiver(sc);
560    }
561  } else {
562    sc->ie_bus_write16(sc, IE_CMD_XMIT_LINK(sc->xmit_cmds,cur),
563                       0xffff);
564
565    sc->ie_bus_write16(sc, IE_CMD_XMIT_CMD(sc->xmit_cmds, cur),
566                       IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST);
567
568    off = IE_SCB_CMDLST(sc->scb);
569    sc->ie_bus_write16(sc, off, IE_CMD_XMIT_ADDR(sc->xmit_cmds, cur));
570    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
571
572    if (i82586_start_cmd(sc, IE_CUC_START, 0, 0, ASYNC_OPTION))
573      printf("%s: iexmit: start xmit command timed out\n",
574             sc->arpcom.ac_if.if_name);
575  }
576
577  sc->arpcom.ac_if.if_timer = 5;
578}
579
580
581/*
582 * Device timeout/watchdog routine.
583 * Entered if the device neglects to generate an interrupt after a
584 * transmit has been started on it.
585 */
586void
587i82586_watchdog(struct ifnet *ifp)
588{
589  struct ie_softc *sc = ifp->if_softc;
590  printf("%s: device timeout\n", ifp->if_name);
591  ++ifp->if_oerrors;
592  i82586_reset(sc, 1);
593}
594
595static int
596i82586_cmd_wait(struct ie_softc *sc)
597{
598  /* spin on i82586 command acknowledge; wait at most 0.9 (!) seconds */
599  int i, off;
600  u_int16_t cmd;
601
602  for (i = 0; i < 900000; i++) {
603    /* Read the command word */
604    off = IE_SCB_CMD(sc->scb);
605
606    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
607    if ((cmd = sc->ie_bus_read16(sc, off)) == 0)
608      return (0);
609    delay(1);
610  }
611
612  off = IE_SCB_STATUS(sc->scb);
613  printf("i82586_cmd_wait: timo(%ssync): scb status: 0x%x, cmd: 0x%x\n",
614         sc->async_cmd_inprogress?"a":"",
615         sc->ie_bus_read16(sc, off), cmd);
616
617  return (1);  /* Timeout */
618}
619
620/*
621 * Send a command to the controller and wait for it to either complete
622 * or be accepted, depending on the command.  If the command pointer
623 * is null, then pretend that the command is not an action command.
624 * If the command pointer is not null, and the command is an action
625 * command, wait for one of the MASK bits to turn on in the command's
626 * status field.
627 * If ASYNC is set, we just call the chip's attention and return.
628 * We may have to wait for the command's acceptance later though.
629 */
630static int
631i82586_start_cmd(struct ie_softc *sc, int cmd, int iecmdbuf, int mask, int async)
632{
633  int i;
634  int off;
635
636  if (sc->async_cmd_inprogress != 0) {
637    /*
638     * If previous command was issued asynchronously, wait
639     * for it now.
640     */
641    if (i82586_cmd_wait(sc) != 0)
642      return (1);
643    sc->async_cmd_inprogress = 0;
644  }
645
646  off = IE_SCB_CMD(sc->scb);
647  sc->ie_bus_write16(sc, off, cmd);
648  IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_WRITE);
649  (sc->chan_attn)(sc, CARD_RESET);
650
651  if (async != 0) {
652    sc->async_cmd_inprogress = 1;
653    return (0);
654  }
655
656  if (IE_ACTION_COMMAND(cmd) && iecmdbuf) {
657    int status;
658    /*
659     * Now spin-lock waiting for status.  This is not a very nice
660     * thing to do, and can kill performance pretty well...
661     * According to the packet driver, the minimum timeout
662     * should be .369 seconds.
663     */
664    for (i = 0; i < 369000; i++) {
665      /* Read the command status */
666      off = IE_CMD_COMMON_STATUS(iecmdbuf);
667      IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
668      status = sc->ie_bus_read16(sc, off);
669      if (status & mask)
670        return (0);
671      delay(1);
672    }
673
674  } else {
675    /*
676     * Otherwise, just wait for the command to be accepted.
677     */
678    return (i82586_cmd_wait(sc));
679  }
680
681  /* Timeout */
682  return (1);
683}
684
685
686/*
687 * Transfer accumulated chip error counters to IF.
688 */
689static __inline void
690i82586_count_errors(struct ie_softc *sc)
691{
692  int scb = sc->scb;
693
694  sc->arpcom.ac_if.if_ierrors +=
695    sc->ie_bus_read16(sc, IE_SCB_ERRCRC(scb)) +
696    sc->ie_bus_read16(sc, IE_SCB_ERRALN(scb)) +
697    sc->ie_bus_read16(sc, IE_SCB_ERRRES(scb)) +
698    sc->ie_bus_read16(sc, IE_SCB_ERROVR(scb));
699
700  /* Clear error counters */
701  sc->ie_bus_write16(sc, IE_SCB_ERRCRC(scb), 0);
702  sc->ie_bus_write16(sc, IE_SCB_ERRALN(scb), 0);
703  sc->ie_bus_write16(sc, IE_SCB_ERRRES(scb), 0);
704  sc->ie_bus_write16(sc, IE_SCB_ERROVR(scb), 0);
705}
706
707
708static void
709i82586_rx_errors(struct ie_softc *sc, int fn, int status)
710{
711  char bits[128];
712
713  printf("%s: rx error (frame# %d): %s\n", sc->arpcom.ac_if.if_name, fn,
714         bitmask_snprintf(status, IE_FD_STATUSBITS, bits, sizeof(bits)));
715}
716
717/*
718 * i82586 interrupt entry point.
719 */
720rtems_isr
721i82586_intr(rtems_vector_number vec, void *arg)
722{
723  struct ie_softc *sc = arg;
724
725#if I82586_DEBUG
726  static unsigned long icnt = 0;
727  I82586_TRACE(sc, I82586_INTS_REQ, icnt++);
728#endif
729   
730  /*
731   * Implementation dependent interrupt handling. It must at least
732   * disabled interrupts from the i82586. It is hoped this can
733   * happen somewhere outside the i82586.
734   */
735  if (sc->intrhook)
736    (sc->intrhook)(sc, INTR_ENTER);
737
738  /*
739   * Wake the task to handle the interrupt. It will
740   * enabled the interrupts when it has finished.
741   */
742  rtems_event_send (sc->intr_task, i82586_WAKE_EVENT);
743}
744
745/*
746 * i82586 interrupt task. The task is actually an extension of the interrupt
747 * with a context switch in the middle. The RTEMS TCP/IP stack requires a task
748 * be used to talk to the stack as a network semaphore is claimed. This
749 * cannot happen during an interrupt.
750 */
751static void
752i82586_intr_task(void *arg)
753{
754  struct ie_softc *sc = arg;
755  rtems_event_set events;
756  u_int           status;
757  int             off;
758  int             reset;
759 
760  /*
761   * Not sure this is a good idea but as a out path exists and
762   * roads lead to it, it seems ok.
763   */
764  for (;;) {
765    rtems_bsdnet_event_receive (i82586_WAKE_EVENT,
766                                RTEMS_WAIT | RTEMS_EVENT_ANY,
767                                0, &events);
768
769    off = IE_SCB_STATUS(sc->scb);
770    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
771    status = sc->ie_bus_read16(sc, off) & IE_ST_WHENCE;
772
773#if I82586_DEBUG
774    I82586_TRACE(sc, I82586_INTS_IN, status);
775#endif
776
777    reset = 0;
778   
779    while ((status & IE_ST_WHENCE) != 0) {
780#if I82586_DEBUG
781      if (sc->sc_debug)
782        printf ("%s: -------\n%s: scbstatus=0x%x\n",
783                sc->arpcom.ac_if.if_name, sc->arpcom.ac_if.if_name, status);
784#endif
785   
786#if 1
787      /* Ack interrupts FIRST in case we receive more during the ISR. */
788      ie_ack(sc, status & IE_ST_WHENCE);
789#endif
790
791      i82586_start_cmd(sc, status & IE_ST_WHENCE, 0, 0, ASYNC_OPTION);
792
793      if (status & (IE_ST_FR | IE_ST_RNR))
794        if (i82586_rint(sc, status) != 0) {
795          reset = 1;
796          break;
797        }
798
799      if (status & IE_ST_CX)
800        if (i82586_tint(sc, status) != 0) {
801          reset = 1;
802          break;
803        }
804
805#if I82586_DEBUG
806      if ((status & IE_ST_CNA) && (sc->sc_debug & IED_CNA))
807        printf("%s: cna; status=0x%x\n", sc->arpcom.ac_if.if_name, status);
808#endif
809
810#if 0
811      if (sc->intrhook)
812        (sc->intrhook)(sc, INTR_LOOP);
813#endif
814
815#if 1
816      /*
817       * Interrupt ACK was posted asynchronously; wait for
818       * completion here before reading SCB status again.
819       *
820       * If ACK fails, try to reset the chip, in hopes that
821       * it helps.
822       */
823      if (i82586_cmd_wait(sc) != 0) {
824          reset = 1;
825          break;
826        }
827#endif
828   
829      IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
830      status = sc->ie_bus_read16(sc, off);
831#if I82586_DEBUG
832      I82586_TRACE(sc, I82586_INTS_LOOPS, status);
833#endif
834    }
835   
836    if (reset) {
837#if I82586_DEBUG
838      printf("%s: intr reset; status=0x%x\n", sc->arpcom.ac_if.if_name, status);
839#endif
840      i82586_cmd_wait(sc);
841      i82586_reset(sc, 1);
842    }
843   
844#if I82586_DEBUG
845    I82586_TRACE(sc, I82586_INTS_OUT, status);
846#endif
847   
848    if (sc->intrhook)
849      (sc->intrhook)(sc, INTR_EXIT);
850  }
851}
852
853/*
854 * Process a received-frame interrupt.
855 */
856int
857i82586_rint(struct ie_softc *sc, int scbstatus)
858{
859  static int timesthru = 1024;
860  int i, status, off;
861
862#if I82586_DEBUG
863  I82586_TRACE(sc, I82586_RX_INT, scbstatus);
864 
865  if (sc->sc_debug & IED_RINT)
866    printf("%s: rint: status 0x%x\n",
867           sc->arpcom.ac_if.if_name, scbstatus);
868#endif
869
870  for (;;) {
871    int drop = 0;
872
873    i = sc->rfhead;
874    off = IE_RFRAME_STATUS(sc->rframes, i);
875    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
876    status = sc->ie_bus_read16(sc, off);
877
878#if I82586_DEBUG
879    if (sc->sc_debug & IED_RINT)
880      printf("%s: rint: frame(%d) status 0x%x\n",
881             sc->arpcom.ac_if.if_name, i, status);
882#endif
883    if ((status & IE_FD_COMPLETE) == 0) {
884      if ((status & IE_FD_OK) != 0) {
885        printf("%s: rint: weird: ",
886               sc->arpcom.ac_if.if_name);
887        i82586_rx_errors(sc, i, status);
888#if I82586_DEBUG
889        I82586_TRACE(sc, I82586_RX_ERR, status);
890#endif
891        break;
892      }
893      if (--timesthru == 0) {
894        /* Account the accumulated errors */
895        i82586_count_errors(sc);
896        timesthru = 1024;
897      }
898      break;
899    } else if ((status & IE_FD_OK) == 0) {
900      /*
901       * If the chip is configured to automatically
902       * discard bad frames, the only reason we can
903       * get here is an "out-of-resource" condition.
904       */
905      i82586_rx_errors(sc, i, status);
906      drop = 1;
907     
908#if I82586_DEBUG
909      I82586_TRACE(sc, I82586_RX_DROP, status);
910#endif
911    }
912
913#if I82586_DEBUG
914    if ((status & IE_FD_BUSY) != 0)
915      printf("%s: rint: frame(%d) busy; status=0x%x\n",
916             sc->arpcom.ac_if.if_name, i, status);
917#endif
918
919    /*
920     * Advance the RFD list, since we're done with
921     * this descriptor.
922     */
923
924    /* Clear frame status */
925    sc->ie_bus_write16(sc, off, 0);
926
927    /* Put fence at this frame (the head) */
928    off = IE_RFRAME_LAST(sc->rframes, i);
929    sc->ie_bus_write16(sc, off, IE_FD_EOL|IE_FD_SUSP);
930
931    /* and clear RBD field */
932    off = IE_RFRAME_BUFDESC(sc->rframes, i);
933    sc->ie_bus_write16(sc, off, 0xffff);
934
935    /* Remove fence from current tail */
936    off = IE_RFRAME_LAST(sc->rframes, sc->rftail);
937    sc->ie_bus_write16(sc, off, 0);
938
939    if (++sc->rftail == sc->nframes)
940      sc->rftail = 0;
941    if (++sc->rfhead == sc->nframes)
942      sc->rfhead = 0;
943
944    /* Pull the frame off the board */
945    if (drop) {
946      i82586_drop_frames(sc);
947      if ((status & IE_FD_RNR) != 0)
948        sc->rnr_expect = 1;
949      sc->arpcom.ac_if.if_ierrors++;
950    } else if (ie_readframe(sc, i) != 0)
951      return (1);
952  }
953
954  if ((scbstatus & IE_ST_RNR) != 0) {
955
956    /*
957     * Receiver went "Not Ready". We try to figure out
958     * whether this was an expected event based on past
959     * frame status values.
960     */
961
962    if ((scbstatus & IE_RUS_SUSPEND) != 0) {
963      /*
964       * We use the "suspend on last frame" flag.
965       * Send a RU RESUME command in response, since
966       * we should have dealt with all completed frames
967       * by now.
968       */
969      printf("RINT: SUSPENDED; scbstatus=0x%x\n",
970             scbstatus);
971      if (i82586_start_cmd(sc, IE_RUC_RESUME, 0, 0, 0) == 0)
972        return (0);
973      printf("%s: RU RESUME command timed out\n",
974             sc->arpcom.ac_if.if_name);
975      return (1);  /* Ask for a reset */
976    }
977
978    if (sc->rnr_expect != 0) {
979      /*
980       * The RNR condition was announced in the previously
981       * completed frame.  Assume the receive ring is Ok,
982       * so restart the receiver without further delay.
983       */
984      i82586_start_transceiver(sc);
985      sc->rnr_expect = 0;
986      return (0);
987
988    } else if ((scbstatus & IE_RUS_NOSPACE) != 0) {
989      /*
990       * We saw no previous IF_FD_RNR flag.
991       * We check our ring invariants and, if ok,
992       * just restart the receiver at the current
993       * point in the ring.
994       */
995      if (i82586_chk_rx_ring(sc) != 0)
996        return (1);
997
998      i82586_start_transceiver(sc);
999      sc->arpcom.ac_if.if_ierrors++;
1000      return (0);
1001    } else
1002      printf("%s: receiver not ready; scbstatus=0x%x\n",
1003             sc->arpcom.ac_if.if_name, scbstatus);
1004
1005    sc->arpcom.ac_if.if_ierrors++;
1006    return (1);  /* Ask for a reset */
1007  }
1008
1009  return (0);
1010}
1011
1012/*
1013 * Process a command-complete interrupt.  These are only generated by the
1014 * transmission of frames.  This routine is deceptively simple, since most
1015 * of the real work is done by i82586_start().
1016 */
1017int
1018i82586_tint(struct ie_softc *sc, int scbstatus)
1019{
1020  struct ifnet *ifp = &sc->arpcom.ac_if;
1021  int status;
1022
1023#if I82586_DEBUG
1024  I82586_TRACE(sc, I82586_TX_INT, sc->xmit_busy);
1025#endif
1026
1027#if I82586_DEBUG
1028  if (sc->xmit_busy <= 0) {
1029    printf("i82586_tint: (%d), WEIRD: xmit_busy=%d, xctail=%d, xchead=%d\n",
1030           sc->trace_flow_in / 2, sc->xmit_busy, sc->xctail, sc->xchead);
1031    I82586_TRACE(sc, I82586_TX_BAD, sc->xctail);
1032    return (0);
1033  }
1034#endif
1035
1036  ifp->if_timer = 0;
1037  ifp->if_flags &= ~IFF_OACTIVE;
1038
1039  status = sc->ie_bus_read16(sc, IE_CMD_XMIT_STATUS(sc->xmit_cmds,
1040                                                    sc->xctail));
1041
1042#if I82586_DEBUG
1043  if (sc->sc_debug & IED_TINT)
1044    printf("%s: tint: SCB status 0x%x; xmit status 0x%x\n",
1045           sc->arpcom.ac_if.if_name, scbstatus, status);
1046#endif
1047
1048  if ((status & IE_STAT_COMPL) == 0 || (status & IE_STAT_BUSY)) {
1049    printf("i82586_tint: (%d) command still busy; status=0x%x; tail=%d\n",
1050           sc->trace_flow_in / 2, status, sc->xctail);
1051    printf("iestatus = 0x%x\n", scbstatus);
[ed13346]1052/*    sc->sc_debug = IED_ALL; */
[6a9db57]1053  }
1054
1055  if (status & IE_STAT_OK) {
1056    ifp->if_opackets++;
1057    ifp->if_collisions += (status & IE_XS_MAXCOLL);
1058  } else {
1059    ifp->if_oerrors++;
1060    /*
1061     * Check SQE and DEFERRED?
1062     * What if more than one bit is set?
1063     */
1064    if (status & IE_STAT_ABORT)
1065      printf("%s: send aborted\n", sc->arpcom.ac_if.if_name);
1066    else if (status & IE_XS_NOCARRIER)
1067      printf("%s: no carrier\n", sc->arpcom.ac_if.if_name);
1068    else if (status & IE_XS_LOSTCTS)
1069      printf("%s: lost CTS\n", sc->arpcom.ac_if.if_name);
1070    else if (status & IE_XS_UNDERRUN)
1071      printf("%s: DMA underrun\n", sc->arpcom.ac_if.if_name);
1072    else if (status & IE_XS_EXCMAX) {
1073      printf("%s: too many collisions\n",
1074             sc->arpcom.ac_if.if_name);
1075      sc->arpcom.ac_if.if_collisions += 16;
1076    }
1077  }
1078
1079  /*
1080   * If multicast addresses were added or deleted while transmitting,
1081   * ie_mc_reset() set the want_mcsetup flag indicating that we
1082   * should do it.
1083   */
1084  if (sc->want_mcsetup) {
1085    ie_mc_setup(sc, IE_XBUF_ADDR(sc, sc->xctail));
1086    sc->want_mcsetup = 0;
1087  }
1088
1089  /* Done with the buffer. */
1090  sc->xmit_busy--;
1091  sc->xctail = (sc->xctail + 1) % NTXBUF;
1092
1093  /* Start the next packet, if any, transmitting. */
1094  if (sc->xmit_busy > 0)
1095    iexmit(sc);
1096
1097  i82586_start_tx(sc);
1098  return (0);
1099}
1100
1101/*
1102 * Get a range of receive buffer descriptors that represent one packet.
1103 */
1104static int
1105i82586_get_rbd_list(struct ie_softc *sc, u_int16_t *start, u_int16_t *end, int *pktlen)
1106{
1107  int  off, rbbase = sc->rbds;
1108  int  rbindex, count = 0;
1109  int  plen = 0;
1110  int  rbdstatus;
1111
1112  *start = rbindex = sc->rbhead;
1113
1114  do {
1115    off = IE_RBD_STATUS(rbbase, rbindex);
1116    IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
1117    rbdstatus = sc->ie_bus_read16(sc, off);
1118    if ((rbdstatus & IE_RBD_USED) == 0) {
1119      /*
1120       * This means we are somehow out of sync.  So, we
1121       * reset the adapter.
1122       */
1123#if I82586_DEBUG
1124      print_rbd(sc, rbindex);
1125#endif
1126      printf("%s: receive descriptors out of sync at %d\n",
1127             sc->arpcom.ac_if.if_name, rbindex);
1128      return (0);
1129    }
1130    plen += (rbdstatus & IE_RBD_CNTMASK);
1131
1132    if (++rbindex == sc->nrxbuf)
1133      rbindex = 0;
1134
1135    ++count;
1136  } while ((rbdstatus & IE_RBD_LAST) == 0);
1137  *end = rbindex;
1138  *pktlen = plen;
1139  return (count);
1140}
1141
1142
1143/*
1144 * Release a range of receive buffer descriptors after we've copied the packet.
1145 */
1146static void
1147i82586_release_rbd_list(struct ie_softc *sc, u_int16_t start, u_int16_t end)
1148{
1149  int  off, rbbase = sc->rbds;
1150  int  rbindex = start;
1151
1152  do {
1153    /* Clear buffer status */
1154    off = IE_RBD_STATUS(rbbase, rbindex);
1155    sc->ie_bus_write16(sc, off, 0);
1156    if (++rbindex == sc->nrxbuf)
1157      rbindex = 0;
1158  } while (rbindex != end);
1159
1160  /* Mark EOL at new tail */
1161  rbindex = ((rbindex == 0) ? sc->nrxbuf : rbindex) - 1;
1162  off = IE_RBD_BUFLEN(rbbase, rbindex);
1163  sc->ie_bus_write16(sc, off, IE_RBUF_SIZE|IE_RBD_EOL);
1164
1165  /* Remove EOL from current tail */
1166  off = IE_RBD_BUFLEN(rbbase, sc->rbtail);
1167  sc->ie_bus_write16(sc, off, IE_RBUF_SIZE);
1168
1169  /* New head & tail pointer */
1170/* hmm, why have both? head is always (tail + 1) % NRXBUF */
1171  sc->rbhead = end;
1172  sc->rbtail = rbindex;
1173}
1174
1175/*
1176 * Drop the packet at the head of the RX buffer ring.
1177 * Called if the frame descriptor reports an error on this packet.
1178 * Returns 1 if the buffer descriptor ring appears to be corrupt;
1179 * and 0 otherwise.
1180 */
1181static int
1182i82586_drop_frames(struct ie_softc *sc)
1183{
1184  u_int16_t bstart, bend;
1185  int pktlen;
1186
1187  if (i82586_get_rbd_list(sc, &bstart, &bend, &pktlen) == 0)
1188    return (1);
1189  i82586_release_rbd_list(sc, bstart, bend);
1190  return (0);
1191}
1192
1193/*
1194 * Check the RX frame & buffer descriptor lists for our invariants,
1195 * i.e.: EOL bit set iff. it is pointed at by the r*tail pointer.
1196 *
1197 * Called when the receive unit has stopped unexpectedly.
1198 * Returns 1 if an inconsistency is detected; 0 otherwise.
1199 *
1200 * The Receive Unit is expected to be NOT RUNNING.
1201 */
1202static int
1203i82586_chk_rx_ring(struct ie_softc *sc)
1204{
1205  int n, off, val;
1206
1207  for (n = 0; n < sc->nrxbuf; n++) {
1208    off = IE_RBD_BUFLEN(sc->rbds, n);
1209    val = sc->ie_bus_read16(sc, off);
1210    if ((n == sc->rbtail) ^ ((val & IE_RBD_EOL) != 0)) {
1211      /* `rbtail' and EOL flag out of sync */
1212      printf("%s: rx buffer descriptors out of sync at %d\n",
1213             sc->arpcom.ac_if.if_name, n);
1214      return (1);
1215    }
1216
1217    /* Take the opportunity to clear the status fields here ? */
1218  }
1219
1220  for (n = 0; n < sc->nframes; n++) {
1221    off = IE_RFRAME_LAST(sc->rframes, n);
1222    val = sc->ie_bus_read16(sc, off);
1223    if ((n == sc->rftail) ^ ((val & (IE_FD_EOL|IE_FD_SUSP)) != 0)) {
1224      /* `rftail' and EOL flag out of sync */
1225      printf("%s: rx frame list out of sync at %d\n",
1226             sc->arpcom.ac_if.if_name, n);
1227      return (1);
1228    }
1229  }
1230
1231  return (0);
1232}
1233
1234
1235/*
1236 * Read frame NUM from unit UNIT (pre-cached as IE).
1237 *
1238 * This routine reads the RFD at NUM, and copies in the buffers from the list
1239 * of RBD, then rotates the RBD list so that the receiver doesn't start
1240 * complaining.  Trailers are DROPPED---there's no point in wasting time
1241 * on confusing code to deal with them.  Hopefully, this machine will
1242 * never ARP for trailers anyway.
1243 */
1244static int
1245ie_readframe(struct ie_softc *sc, int num) /* frame number to read */
1246{
1247  struct ether_header *eh;
1248  struct mbuf         *m;
1249  u_int16_t           bstart, bend;
1250  int                 pktlen;
1251
1252  if (i82586_get_rbd_list(sc, &bstart, &bend, &pktlen) == 0) {
1253    sc->arpcom.ac_if.if_ierrors++;
1254    return (1);
1255  }
1256
1257  m = ieget(sc, bstart, pktlen);
1258  i82586_release_rbd_list(sc, bstart, bend);
1259
1260  if (m == 0) {
1261    sc->arpcom.ac_if.if_ierrors++;
1262    return (0);
1263  }
1264
1265  eh = mtod(m, struct ether_header *);
1266  m->m_data += 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_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  int 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 %d 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 %d clocks away\n",
1547           sc->arpcom.ac_if.if_name, result & IE_TDR_TIME);
1548  else
1549    printf("%s: TDR returned unknown status 0x%x\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, int cmd, caddr_t data)
1966{
1967  struct ie_softc *sc  = ifp->if_softc;
[ed13346]1968/*  struct ifreq    *ifr = (struct ifreq *)data; */
[6a9db57]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.