source: rtems/c/src/libchip/network/i82586.c @ 9c6a99f

4.104.114.84.95
Last change on this file since 9c6a99f was 9c6a99f, checked in by Joel Sherrill <joel.sherrill@…>, on 04/04/02 at 18:22:15

2002-04-04 Ralf Corsepius <corsepiu@…>

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