source: rtems/c/src/libchip/network/i82586.c @ 6f0d0527

4.104.114.84.95
Last change on this file since 6f0d0527 was 6f0d0527, checked in by Joel Sherrill <joel.sherrill@…>, on 05/14/02 at 15:16:39

2002-05-07 Chris Johns <ccj@…>

  • c/src/libchip/network/i82586.c: Per PR210, adjust the mbuf lengths to remove the ethernet header as the FreeBSD (RTEMS) stack requires it to be stripped.
  • Property mode set to 100644
File size: 59.1 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  = config->drv_ctrl;
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);
1052/*    sc->sc_debug = IED_ALL; */
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  /*
1266   * Remove the mac header. This is different from the NetBSD
1267   * stack.
1268   */
1269  eh = mtod(m, struct ether_header *);
1270  m->m_data += sizeof (struct ether_header);
1271  m->m_len -= sizeof (struct ether_header);
1272  m->m_pkthdr.len -= sizeof (struct ether_header);
1273
1274#if I82586_DEBUG
1275  if (sc->sc_debug & IED_READFRAME) {
1276
1277    printf("%s: frame from ether %s type 0x%x len %d\n",
1278           sc->arpcom.ac_if.if_name,
1279           ether_sprintf(eh->ether_shost),
1280           (u_int)ntohs(eh->ether_type),
1281           pktlen);
1282  }
1283#endif
1284
1285#if NBPFILTER > 0
1286  /* Check for a BPF filter; if so, hand it up. */
1287  if (sc->arpcom.ac_if.if_bpf != 0)
1288    /* Pass it up. */
1289    bpf_mtap(sc->arpcom.ac_if.if_bpf, m);
1290#endif /* NBPFILTER > 0 */
1291
1292  /*
1293   * Finally pass this packet up to higher layers.
1294   */
1295  ether_input (&sc->arpcom.ac_if, eh, m);
1296  sc->arpcom.ac_if.if_ipackets++;
1297 
1298#if I82586_DEBUG
1299  I82586_TRACE(sc, I82586_RX_OK, sc->arpcom.ac_if.if_ipackets);
1300#endif
1301
1302  return (0);
1303}
1304
1305/*
1306 * Start transmission on an interface.
1307 */
1308void
1309i82586_start(struct ifnet *ifp)
1310{
1311  struct ie_softc *sc = ifp->if_softc;
1312 
1313  if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
1314    return;
1315 
1316#if I82586_DEBUG
1317  I82586_TRACE(sc, I82586_TX_REQ, sc->xmit_busy);
1318#endif
1319 
1320  rtems_event_send (sc->tx_task, i82586_TX_EVENT);
1321}
1322
1323static void
1324i82586_tx_task(void *arg)
1325{
1326  struct ie_softc *sc = arg;
1327  rtems_event_set events;
1328
1329  for (;;) {
1330    rtems_bsdnet_event_receive (i82586_TX_EVENT,
1331                                RTEMS_WAIT | RTEMS_EVENT_ANY,
1332                                0, &events);
1333   
1334#if I82586_DEBUG
1335    I82586_TRACE(sc, I82586_TX_EVT, sc->xmit_busy);
1336   
1337    if (sc->sc_debug)
1338      printf ("%s: =======\n", sc->arpcom.ac_if.if_name);
1339#endif
1340
1341    i82586_start_tx(sc);
1342  }
1343}
1344
1345static void
1346i82586_start_tx(struct ie_softc *sc)
1347{
1348  struct ifnet *ifp = &sc->arpcom.ac_if;
1349  struct mbuf *m0, *m;
1350  int  buffer, head, xbase;
1351  u_short  len;
1352  int  s;
1353 
1354#if I82586_DEBUG
1355  I82586_TRACE(sc, I82586_START_TX, sc->xmit_busy);
1356#endif
1357 
1358  if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
1359  {
1360#if I82586_DEBUG
1361    I82586_TRACE(sc, I82586_TX_ACTIVE, ifp->if_snd.ifq_len);
1362#endif
1363    return;
1364  }
1365 
1366  for (;;) {
1367    if (sc->xmit_busy == NTXBUF) {
1368      ifp->if_flags |= IFF_OACTIVE;
1369      break;
1370    }
1371
1372    head = sc->xchead;
1373    xbase = sc->xbds;
1374
1375    IF_DEQUEUE(&ifp->if_snd, m0);
1376    if (m0 == 0)
1377      break;
1378
1379    /* We need to use m->m_pkthdr.len, so require the header */
1380    if ((m0->m_flags & M_PKTHDR) == 0)
1381      panic("i82586_start: no header mbuf");
1382
1383#if NBPFILTER > 0
1384    /* Tap off here if there is a BPF listener. */
1385    if (ifp->if_bpf)
1386      bpf_mtap(ifp->if_bpf, m0);
1387#endif
1388
1389#if I82586_DEBUG
1390    if (sc->sc_debug & IED_ENQ)
1391      printf("%s: fill buffer %d\n", sc->arpcom.ac_if.if_name,
1392             sc->xchead);
1393#endif
1394
1395    if (m0->m_pkthdr.len > IE_TBUF_SIZE)
1396      printf("%s: tbuf overflow\n", sc->arpcom.ac_if.if_name);
1397
1398    buffer = IE_XBUF_ADDR(sc, head);
1399    for (m = m0; m != 0; m = m->m_next) {
1400      (sc->memcopyout)(sc, mtod(m,caddr_t), buffer, m->m_len);
1401      buffer += m->m_len;
1402    }
1403
1404    len = max(m0->m_pkthdr.len, ETHER_MIN_LEN);
1405    m_freem(m0);
1406
1407    /*
1408     * Setup the transmit buffer descriptor here, while we
1409     * know the packet's length.
1410     */
1411    sc->ie_bus_write16(sc, IE_XBD_FLAGS(xbase, head),
1412                       len | IE_TBD_EOL);
1413    sc->ie_bus_write16(sc, IE_XBD_NEXT(xbase, head), 0xffff);
1414    sc->ie_bus_write24(sc, IE_XBD_BUF(xbase, head),
1415                       IE_XBUF_ADDR(sc, head));
1416
1417    if (++head == NTXBUF)
1418      head = 0;
1419    sc->xchead = head;
1420
1421#if I82586_DEBUG
1422    I82586_TRACE(sc, I82586_TX_START, sc->xmit_busy);
1423#endif
1424     
1425    s = splnet();
1426    /* Start the first packet transmitting. */
1427    if (sc->xmit_busy == 0)
1428      iexmit(sc);
1429
1430    sc->xmit_busy++;
1431     
1432    splx(s);
1433  }
1434}
1435
1436/*
1437 * Probe IE's ram setup   [ Move all this into MD front-end!? ]
1438 * Use only if SCP and ISCP represent offsets into shared ram space.
1439 */
1440int
1441i82586_proberam(struct ie_softc *sc)
1442{
1443  int result, off;
1444
1445  /* Put in 16-bit mode */
1446  off = IE_SCP_BUS_USE(sc->scp);
1447  sc->ie_bus_write16(sc, off, 0);
1448  IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_WRITE);
1449
1450  /* Set the ISCP `busy' bit */
1451  off = IE_ISCP_BUSY(sc->iscp);
1452  sc->ie_bus_write16(sc, off, 1);
1453  IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_WRITE);
1454
1455  if (sc->hwreset)
1456    (sc->hwreset)(sc, CHIP_PROBE);
1457
1458  (sc->chan_attn) (sc, CHIP_PROBE);
1459
1460  delay(100);    /* wait a while... */
1461
1462  /* Read back the ISCP `busy' bit; it should be clear by now */
1463  off = IE_ISCP_BUSY(sc->iscp);
1464  IE_BUS_BARRIER(sc, off, 2, BUS_SPACE_BARRIER_READ);
1465  result = sc->ie_bus_read16(sc, off) == 0;
1466
1467  /* Acknowledge any interrupts we may have caused. */
1468  ie_ack(sc, IE_ST_WHENCE);
1469
1470  return (result);
1471}
1472
1473void
1474i82586_reset(struct ie_softc *sc, int hard)
1475{
1476  int s = splnet();
1477
1478  if (hard)
1479    printf("%s: reset\n", sc->arpcom.ac_if.if_name);
1480
1481  /* Clear OACTIVE in case we're called from watchdog (frozen xmit). */
1482  sc->arpcom.ac_if.if_timer = 0;
1483  sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
1484
1485  /*
1486   * Stop i82586 dead in its tracks.
1487   */
1488  if (i82586_start_cmd(sc, IE_RUC_ABORT | IE_CUC_ABORT, 0, 0, 0))
1489    printf("%s: abort commands timed out\n", sc->arpcom.ac_if.if_name);
1490
1491  /*
1492   * This can really slow down the i82586_reset() on some cards, but it's
1493   * necessary to unwedge other ones (eg, the Sun VME ones) from certain
1494   * lockups.
1495   */
1496  if (hard && sc->hwreset)
1497    (sc->hwreset)(sc, CARD_RESET);
1498
1499  delay(100);
1500  ie_ack(sc, IE_ST_WHENCE);
1501
1502  if ((sc->arpcom.ac_if.if_flags & IFF_UP) != 0) {
1503    i82586_init(&sc->arpcom.ac_if);
1504  }
1505
1506  splx(s);
1507}
1508
1509static void
1510setup_simple_command(struct ie_softc *sc, int cmd, int cmdbuf)
1511{
1512  /* Setup a simple command */
1513  sc->ie_bus_write16(sc, IE_CMD_COMMON_STATUS(cmdbuf), 0);
1514  sc->ie_bus_write16(sc, IE_CMD_COMMON_CMD(cmdbuf), cmd | IE_CMD_LAST);
1515  sc->ie_bus_write16(sc, IE_CMD_COMMON_LINK(cmdbuf), 0xffff);
1516
1517  /* Assign the command buffer to the SCB command list */
1518  sc->ie_bus_write16(sc, IE_SCB_CMDLST(sc->scb), cmdbuf);
1519}
1520
1521/*
1522 * Run the time-domain reflectometer.
1523 */
1524static void
1525ie_run_tdr(struct ie_softc *sc, int cmd)
1526{
1527  int result;
1528
1529  setup_simple_command(sc, IE_CMD_TDR, cmd);
1530  sc->ie_bus_write16(sc, IE_CMD_TDR_TIME(cmd), 0);
1531
1532  if (i82586_start_cmd(sc, IE_CUC_START, cmd, IE_STAT_COMPL, 0) ||
1533      (sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmd)) & IE_STAT_OK) == 0)
1534    result = 0x10000; /* XXX */
1535  else
1536    result = sc->ie_bus_read16(sc, IE_CMD_TDR_TIME(cmd));
1537
1538  /* Squash any pending interrupts */
1539  ie_ack(sc, IE_ST_WHENCE);
1540
1541  if (result & IE_TDR_SUCCESS)
1542    return;
1543
1544  if (result & 0x10000)
1545    printf("%s: TDR command failed\n", sc->arpcom.ac_if.if_name);
1546  else if (result & IE_TDR_XCVR)
1547    printf("%s: transceiver problem\n", sc->arpcom.ac_if.if_name);
1548  else if (result & IE_TDR_OPEN)
1549    printf("%s: TDR detected incorrect termination %d clocks away\n",
1550           sc->arpcom.ac_if.if_name, result & IE_TDR_TIME);
1551  else if (result & IE_TDR_SHORT)
1552    printf("%s: TDR detected a short circuit %d clocks away\n",
1553           sc->arpcom.ac_if.if_name, result & IE_TDR_TIME);
1554  else
1555    printf("%s: TDR returned unknown status 0x%x\n",
1556           sc->arpcom.ac_if.if_name, result);
1557}
1558
1559
1560/*
1561 * i82586_setup_bufs: set up the buffers
1562 *
1563 * We have a block of KVA at sc->buf_area which is of size sc->buf_area_sz.
1564 * this is to be used for the buffers.  The chip indexs its control data
1565 * structures with 16 bit offsets, and it indexes actual buffers with
1566 * 24 bit addresses.   So we should allocate control buffers first so that
1567 * we don't overflow the 16 bit offset field.   The number of transmit
1568 * buffers is fixed at compile time.
1569 *
1570 */
1571static void
1572i82586_setup_bufs(struct ie_softc *sc)
1573{
1574  int  ptr = sc->buf_area;  /* memory pool */
1575  int     n, r;
1576
1577  /*
1578   * step 0: zero memory and figure out how many recv buffers and
1579   * frames we can have.
1580   */
1581  ptr = (ptr + 3) & ~3;  /* set alignment and stick with it */
1582
1583
1584  /*
1585   *  step 1: lay out data structures in the shared-memory area
1586   */
1587
1588  /* The no-op commands; used if "nop-chaining" is in effect */
1589  sc->nop_cmds = ptr;
1590  ptr += NTXBUF * IE_CMD_NOP_SZ;
1591
1592  /* The transmit commands */
1593  sc->xmit_cmds = ptr;
1594  ptr += NTXBUF * IE_CMD_XMIT_SZ;
1595
1596  /* The transmit buffers descriptors */
1597  sc->xbds = ptr;
1598  ptr += NTXBUF * IE_XBD_SZ;
1599
1600  /* The transmit buffers */
1601  sc->xbufs = ptr;
1602  ptr += NTXBUF * IE_TBUF_SIZE;
1603
1604  ptr = (ptr + 3) & ~3;    /* re-align.. just in case */
1605
1606  /* Compute free space for RECV stuff */
1607  n = sc->buf_area_sz - (ptr - sc->buf_area);
1608
1609  /* Compute size of one RECV frame */
1610  r = IE_RFRAME_SZ + ((IE_RBD_SZ + IE_RBUF_SIZE) * B_PER_F);
1611
1612  sc->nframes = n / r;
1613
1614  if (sc->nframes <= 0)
1615    panic("ie: bogus buffer calc\n");
1616
1617  sc->nrxbuf = sc->nframes * B_PER_F;
1618
1619  /* The receice frame descriptors */
1620  sc->rframes = ptr;
1621  ptr += sc->nframes * IE_RFRAME_SZ;
1622
1623  /* The receive buffer descriptors */
1624  sc->rbds = ptr;
1625  ptr += sc->nrxbuf * IE_RBD_SZ;
1626
1627  /* The receive buffers */
1628  sc->rbufs = ptr;
1629  ptr += sc->nrxbuf * IE_RBUF_SIZE;
1630
1631#if I82586_DEBUG
1632  printf("%s: %d frames %d bufs\n", sc->arpcom.ac_if.if_name, sc->nframes,
1633         sc->nrxbuf);
1634#endif
1635
1636  /*
1637   * step 2: link together the recv frames and set EOL on last one
1638   */
1639  for (n = 0; n < sc->nframes; n++) {
1640    int m = (n == sc->nframes - 1) ? 0 : n + 1;
1641
1642    /* Clear status */
1643    sc->ie_bus_write16(sc, IE_RFRAME_STATUS(sc->rframes,n), 0);
1644
1645    /* RBD link = NULL */
1646    sc->ie_bus_write16(sc, IE_RFRAME_BUFDESC(sc->rframes,n),
1647                       0xffff);
1648
1649    /* Make a circular list */
1650    sc->ie_bus_write16(sc, IE_RFRAME_NEXT(sc->rframes,n),
1651                       IE_RFRAME_ADDR(sc->rframes,m));
1652
1653    /* Mark last as EOL */
1654    sc->ie_bus_write16(sc, IE_RFRAME_LAST(sc->rframes,n),
1655                       ((m==0)? (IE_FD_EOL|IE_FD_SUSP) : 0));
1656  }
1657
1658  /*
1659   * step 3: link the RBDs and set EOL on last one
1660   */
1661  for (n = 0; n < sc->nrxbuf; n++) {
1662    int m = (n == sc->nrxbuf - 1) ? 0 : n + 1;
1663
1664    /* Clear status */
1665    sc->ie_bus_write16(sc, IE_RBD_STATUS(sc->rbds,n), 0);
1666
1667    /* Make a circular list */
1668    sc->ie_bus_write16(sc, IE_RBD_NEXT(sc->rbds,n),
1669                       IE_RBD_ADDR(sc->rbds,m));
1670
1671    /* Link to data buffers */
1672    sc->ie_bus_write24(sc, IE_RBD_BUFADDR(sc->rbds, n),
1673                       IE_RBUF_ADDR(sc, n));
1674    sc->ie_bus_write16(sc, IE_RBD_BUFLEN(sc->rbds,n),
1675                       IE_RBUF_SIZE | ((m==0)?IE_RBD_EOL:0));
1676  }
1677
1678  /*
1679   * step 4: all xmit no-op commands loopback onto themselves
1680   */
1681  for (n = 0; n < NTXBUF; n++) {
1682    sc->ie_bus_write16(sc, IE_CMD_NOP_STATUS(sc->nop_cmds, n), 0);
1683
1684    sc->ie_bus_write16(sc, IE_CMD_NOP_CMD(sc->nop_cmds, n),
1685                       IE_CMD_NOP);
1686
1687    sc->ie_bus_write16(sc, IE_CMD_NOP_LINK(sc->nop_cmds, n),
1688                       IE_CMD_NOP_ADDR(sc->nop_cmds, n));
1689  }
1690
1691
1692  /*
1693   * step 6: set the head and tail pointers on receive to keep track of
1694   * the order in which RFDs and RBDs are used.
1695   */
1696
1697  /* Pointers to last packet sent and next available transmit buffer. */
1698  sc->xchead = sc->xctail = 0;
1699
1700  /* Clear transmit-busy flag and set number of free transmit buffers. */
1701  sc->xmit_busy = 0;
1702
1703  /*
1704   * Pointers to first and last receive frame.
1705   * The RFD pointed to by rftail is the only one that has EOL set.
1706   */
1707  sc->rfhead = 0;
1708  sc->rftail = sc->nframes - 1;
1709
1710  /*
1711   * Pointers to first and last receive descriptor buffer.
1712   * The RBD pointed to by rbtail is the only one that has EOL set.
1713   */
1714  sc->rbhead = 0;
1715  sc->rbtail = sc->nrxbuf - 1;
1716
1717/* link in recv frames * and buffer into the scb. */
1718#if I82586_DEBUG
1719  printf("%s: reserved %d bytes\n",
1720         sc->arpcom.ac_if.if_name, ptr - sc->buf_area);
1721#endif
1722}
1723
1724static int
1725ie_cfg_setup(struct ie_softc *sc, int cmd, int promiscuous, int manchester)
1726{
1727  int cmdresult, status;
1728  u_int8_t buf[IE_CMD_CFG_SZ]; /* XXX malloc? */
1729
1730  *IE_CMD_CFG_CNT(buf)       = 0x0c;
1731  *IE_CMD_CFG_FIFO(buf)      = 8;
1732  *IE_CMD_CFG_SAVEBAD(buf)   = 0x40;
1733  *IE_CMD_CFG_ADDRLEN(buf)   = 0x2e;
1734  *IE_CMD_CFG_PRIORITY(buf)  = 0;
1735  *IE_CMD_CFG_IFS(buf)       = 0x60;
1736  *IE_CMD_CFG_SLOT_LOW(buf)  = 0;
1737  *IE_CMD_CFG_SLOT_HIGH(buf) = 0xf2;
1738  *IE_CMD_CFG_PROMISC(buf)   = !!promiscuous | manchester << 2;
1739  *IE_CMD_CFG_CRSCDT(buf)    = 0;
1740  *IE_CMD_CFG_MINLEN(buf)    = 64;
1741  *IE_CMD_CFG_JUNK(buf)      = 0xff;
1742  sc->memcopyout(sc, buf, cmd, IE_CMD_CFG_SZ);
1743  setup_simple_command(sc, IE_CMD_CONFIG, cmd);
1744  IE_BUS_BARRIER(sc, cmd, IE_CMD_CFG_SZ, BUS_SPACE_BARRIER_WRITE);
1745
1746  cmdresult = i82586_start_cmd(sc, IE_CUC_START, cmd, IE_STAT_COMPL, 0);
1747  status = sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmd));
1748  if (cmdresult != 0) {
1749    printf("%s: configure command timed out; status %x\n",
1750           sc->arpcom.ac_if.if_name, status);
1751    return (0);
1752  }
1753  if ((status & IE_STAT_OK) == 0) {
1754    printf("%s: configure command failed; status %x\n",
1755           sc->arpcom.ac_if.if_name, status);
1756    return (0);
1757  }
1758
1759  /* Squash any pending interrupts */
1760  ie_ack(sc, IE_ST_WHENCE);
1761  return (1);
1762}
1763
1764static int
1765ie_ia_setup(struct ie_softc *sc, int cmdbuf)
1766{
1767  int cmdresult, status;
1768
1769  setup_simple_command(sc, IE_CMD_IASETUP, cmdbuf);
1770
1771  (sc->memcopyout)(sc, sc->arpcom.ac_enaddr,
1772                   IE_CMD_IAS_EADDR(cmdbuf), ETHER_ADDR_LEN);
1773 
1774  cmdresult = i82586_start_cmd(sc, IE_CUC_START, cmdbuf, IE_STAT_COMPL, 0);
1775  status = sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmdbuf));
1776  if (cmdresult != 0) {
1777    printf("%s: individual address command timed out; status %x\n",
1778           sc->arpcom.ac_if.if_name, status);
1779    return (0);
1780  }
1781  if ((status & IE_STAT_OK) == 0) {
1782    printf("%s: individual address command failed; status %x\n",
1783           sc->arpcom.ac_if.if_name, status);
1784    return (0);
1785  }
1786
1787  /* Squash any pending interrupts */
1788  ie_ack(sc, IE_ST_WHENCE);
1789  return (1);
1790}
1791
1792/*
1793 * Run the multicast setup command.
1794 * Called at splnet().
1795 */
1796static int
1797ie_mc_setup(struct ie_softc *sc, int cmdbuf)
1798{
1799  int cmdresult, status;
1800
1801  if (sc->mcast_count == 0)
1802    return (1);
1803
1804  setup_simple_command(sc, IE_CMD_MCAST, cmdbuf);
1805
1806  (sc->memcopyout)(sc, (caddr_t)sc->mcast_addrs,
1807                   IE_CMD_MCAST_MADDR(cmdbuf),
1808                   sc->mcast_count * ETHER_ADDR_LEN);
1809
1810  sc->ie_bus_write16(sc, IE_CMD_MCAST_BYTES(cmdbuf),
1811                     sc->mcast_count * ETHER_ADDR_LEN);
1812
1813  /* Start the command */
1814  cmdresult = i82586_start_cmd(sc, IE_CUC_START, cmdbuf, IE_STAT_COMPL, 0);
1815  status = sc->ie_bus_read16(sc, IE_CMD_COMMON_STATUS(cmdbuf));
1816  if (cmdresult != 0) {
1817    printf("%s: multicast setup command timed out; status %x\n",
1818           sc->arpcom.ac_if.if_name, status);
1819    return (0);
1820  }
1821  if ((status & IE_STAT_OK) == 0) {
1822    printf("%s: multicast setup command failed; status %x\n",
1823           sc->arpcom.ac_if.if_name, status);
1824    return (0);
1825  }
1826
1827  /* Squash any pending interrupts */
1828  ie_ack(sc, IE_ST_WHENCE);
1829  return (1);
1830}
1831
1832/*
1833 * This routine takes the environment generated by check_ie_present() and adds
1834 * to it all the other structures we need to operate the adapter.  This
1835 * includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands, starting
1836 * the receiver unit, and clearing interrupts.
1837 *
1838 * THIS ROUTINE MUST BE CALLED AT splnet() OR HIGHER.
1839 */
1840void
1841i82586_init(void *arg)
1842{
1843  struct ie_softc *sc  = arg;
1844  struct ifnet    *ifp = &sc->arpcom.ac_if;
1845  int             cmd;
1846
1847  sc->async_cmd_inprogress = 0;
1848  sc->xmit_busy = 0;
1849
1850#if I82586_DEBUG
1851  memset(sc->trace_flow, 0, sizeof(sc->trace_flow));
1852  sc->trace_flow_wrap = 0;
1853#endif
1854  sc->trace_flow_in = 0;
1855 
1856  cmd = sc->buf_area;
1857 
1858#if I82586_DEBUG
1859  printf ("%s: sc_debug at 0x%08x\n", sc->arpcom.ac_if.if_name, (unsigned int) &sc->sc_debug);
1860#endif
1861 
1862  /*
1863   * Send the configure command first.
1864   */
1865  if (ie_cfg_setup(sc, cmd, sc->promisc, 0) == 0)
1866    return;
1867
1868  /*
1869   * Send the Individual Address Setup command.
1870   */
1871  if (ie_ia_setup(sc, cmd) == 0)
1872    return;
1873
1874  /*
1875   * Run the time-domain reflectometer.
1876   */
1877  ie_run_tdr(sc, cmd);
1878
1879  /*
1880   * Set the multi-cast filter, if any
1881   */
1882  if (ie_mc_setup(sc, cmd) == 0)
1883    return;
1884
1885  /*
1886   * If no tasks exist, create them. Need to add something to allow
1887   * different names for the different devices.
1888   */
1889  if (sc->intr_task == 0)
1890    sc->intr_task = rtems_bsdnet_newproc ("IEi0", 2048, i82586_intr_task, sc);
1891  if (sc->tx_task == 0)
1892    sc->tx_task = rtems_bsdnet_newproc ("IEt0", 2048, i82586_tx_task, sc);
1893
1894
1895  /*
1896   * Acknowledge any interrupts we have generated thus far.
1897   */
1898  ie_ack(sc, IE_ST_WHENCE);
1899
1900  /*
1901   * Set up the transmit and recv buffers.
1902   */
1903  i82586_setup_bufs(sc);
1904
1905  if (sc->hwinit)
1906    (sc->hwinit)(sc);
1907
1908  ifp->if_flags |= IFF_RUNNING;
1909  ifp->if_flags &= ~IFF_OACTIVE;
1910
1911  if (NTXBUF < 2)
1912    sc->do_xmitnopchain = 0;
1913
1914  i82586_start_transceiver(sc);
1915}
1916
1917/*
1918 * Start the RU and possibly the CU unit
1919 */
1920static void
1921i82586_start_transceiver(struct ie_softc *sc)
1922{
1923#if I82586_DEBUG
1924      I82586_TRACE(sc, I82586_RX_START, 0);
1925#endif
1926     
1927  /*
1928   * Start RU at current position in frame & RBD lists.
1929   */
1930  sc->ie_bus_write16(sc, IE_RFRAME_BUFDESC(sc->rframes,sc->rfhead),
1931                     IE_RBD_ADDR(sc->rbds, sc->rbhead));
1932
1933  sc->ie_bus_write16(sc, IE_SCB_RCVLST(sc->scb),
1934                     IE_RFRAME_ADDR(sc->rframes,sc->rfhead));
1935
1936  if (sc->do_xmitnopchain) {
1937    /* Stop transmit command chain */
1938    if (i82586_start_cmd(sc, IE_CUC_SUSPEND|IE_RUC_SUSPEND, 0, 0, 0))
1939      printf("%s: CU/RU stop command timed out\n",
1940             sc->arpcom.ac_if.if_name);
1941
1942    /* Start the receiver & transmitter chain */
1943    /* sc->scb->ie_command_list =
1944       IEADDR(sc->nop_cmds[(sc->xctail+NTXBUF-1) % NTXBUF]);*/
1945    sc->ie_bus_write16(sc, IE_SCB_CMDLST(sc->scb),
1946                       IE_CMD_NOP_ADDR(
1947                         sc->nop_cmds,
1948                         (sc->xctail + NTXBUF - 1) % NTXBUF));
1949
1950    if (i82586_start_cmd(sc, IE_CUC_START|IE_RUC_START, 0, 0, 0))
1951      printf("%s: CU/RU command timed out\n",
1952             sc->arpcom.ac_if.if_name);
1953  } else {
1954    if (i82586_start_cmd(sc, IE_RUC_START, 0, 0, 0))
1955      printf("%s: RU command timed out\n",
1956             sc->arpcom.ac_if.if_name);
1957  }
1958}
1959
1960void
1961i82586_stop(struct ifnet *ifp, int disable)
1962{
1963  struct ie_softc *sc = ifp->if_softc;
1964
1965  if (i82586_start_cmd(sc, IE_RUC_SUSPEND | IE_CUC_SUSPEND, 0, 0, 0))
1966    printf("%s: iestop: disable commands timed out\n",
1967           sc->arpcom.ac_if.if_name);
1968}
1969
1970int
1971i82586_ioctl(struct ifnet *ifp, int cmd, caddr_t data)
1972{
1973  struct ie_softc *sc  = ifp->if_softc;
1974/*  struct ifreq    *ifr = (struct ifreq *)data; */
1975  int             s;
1976  int             error = 0;
1977
1978  s = splnet();
1979  switch(cmd) {
1980    case SIOCGIFMEDIA:
1981    case SIOCSIFMEDIA:
1982      break;
1983    case SIO_RTEMS_SHOW_STATS:
1984#if I82586_DEBUG
1985      print_softie(sc);
1986#endif
1987      break;
1988    default:
1989      error = ether_ioctl(ifp, cmd, data);
1990      if (error == ENETRESET) {
1991        /*
1992         * Multicast list has changed; set the hardware filter
1993         * accordingly.
1994         */
1995        ie_mc_reset(sc);
1996        error = 0;
1997      }
1998      break;
1999  }
2000#if I82586_DEBUG
2001  if (cmd == SIOCSIFFLAGS)
2002    sc->sc_debug = (ifp->if_flags & IFF_DEBUG) ? IED_ALL : 0;
2003#endif
2004  splx(s);
2005  return (error);
2006}
2007
2008static void
2009ie_mc_reset(struct ie_softc *sc)
2010{
2011  struct ether_multi *enm;
2012  struct ether_multistep step;
2013  int size;
2014
2015  /*
2016   * Step through the list of addresses.
2017   */
2018  again:
2019  size = 0;
2020  sc->mcast_count = 0;
2021  ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
2022  while (enm) {
2023    size += 6;
2024    if (sc->mcast_count >= IE_MAXMCAST ||
2025        memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) {
2026      sc->arpcom.ac_if.if_flags |= IFF_ALLMULTI;
2027      i82586_ioctl(&sc->arpcom.ac_if,
2028                   SIOCSIFFLAGS, (void *)0);
2029      return;
2030    }
2031    ETHER_NEXT_MULTI(step, enm);
2032  }
2033
2034  if (size > sc->mcast_addrs_size) {
2035    /* Need to allocate more space */
2036    if (sc->mcast_addrs_size)
2037      free(sc->mcast_addrs, M_IPMADDR);
2038    sc->mcast_addrs = (char *)
2039      malloc(size, M_IPMADDR, M_WAITOK);
2040    sc->mcast_addrs_size = size;
2041  }
2042
2043  /*
2044   * We've got the space; now copy the addresses
2045   */
2046  ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
2047  while (enm) {
2048    if (sc->mcast_count >= IE_MAXMCAST)
2049      goto again; /* Just in case */
2050
2051    memcpy(&sc->mcast_addrs[sc->mcast_count], enm->enm_addrlo, 6);
2052    sc->mcast_count++;
2053    ETHER_NEXT_MULTI(step, enm);
2054  }
2055  sc->want_mcsetup = 1;
2056}
2057
2058/*
2059 * Media change callback.
2060 */
2061int
2062i82586_mediachange(struct ifnet *ifp)
2063{
2064  struct ie_softc *sc = ifp->if_softc;
2065
2066  if (sc->sc_mediachange)
2067    return ((*sc->sc_mediachange)(sc));
2068  return (0);
2069}
2070
2071/*
2072 * Media status callback.
2073 */
2074void
2075i82586_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
2076{
2077  struct ie_softc *sc = ifp->if_softc;
2078 
2079  if (sc->sc_mediastatus)
2080    (*sc->sc_mediastatus)(sc, ifmr);
2081}
2082
2083#if I82586_DEBUG
2084static void
2085print_softie(struct ie_softc *sc)
2086{
2087  static char *trace_labels[] = {
2088    "INTS_REQ",
2089    "INTS_IN",
2090    "INTS_LOOPS",
2091    "INTS_OUT",
2092    "RX_INT",
2093    "RX_DROP",
2094    "RX_ERR",
2095    "RX_OK",
2096    "RX_START",
2097    "START_TX",
2098    "TX_START",
2099    "TX_INT",
2100    "TX_REQ",
2101    "TX_EVT",
2102    "TX_EMIT",
2103    "TX_BAD",
2104    "TX_ACTIVE",
2105    "TRACE_CNT"
2106  };
2107 
2108  int i;
2109 
2110  printf("i82586 %s:\n", sc->arpcom.ac_if.if_name);
2111
2112  printf(" iobase=%p\n", sc->sc_iobase);
2113 
2114  printf(" scp=0x%08x\t\tiscp=0x%08x\t\tscb=0x%08x\n",
2115         sc->scp, sc->iscp, sc->scb);
2116  printf(" buf_area=0x%08x\tbuf_area_sz=0x%08x\n",
2117         sc->buf_area, sc->buf_area_sz);
2118  printf(" rframes=0x%08x\trbds=0x%08x\t\trbufs=0x%08x\n",
2119         sc->rframes, sc->rbds, sc->rbufs);
2120  printf(" nop_cmds=0x%08x\txmit_cmds=0x%08x\n",
2121         sc->nop_cmds, sc->xmit_cmds);
2122  printf(" xbds=0x%08x\txbufs=0x%08x\n\n",
2123         sc->xbds, sc->xbufs);
2124  printf(" rfhead=%d\trftail=%d\n",
2125         sc->rfhead, sc->rftail);
2126  printf(" rbhead=%d\trbtail=%d\n",
2127         sc->rbhead, sc->rbtail);
2128  printf(" nframes=%d\tnrxbuf=%d\trnr_expect=%d\n",
2129         sc->nframes, sc->nrxbuf, sc->rnr_expect);
2130  printf(" xchead=%d\txctail=%d\n",
2131         sc->xchead, sc->xctail);
2132  printf(" xmit_busy=%d\txmit_req=%d\tdo_xmitnopchain=%d\n",
2133         sc->xmit_busy, sc->xmit_req, sc->do_xmitnopchain);
2134  printf(" promisc=%d\tasync_cmd_inprogress=%d\n\n",
2135         sc->promisc, sc->async_cmd_inprogress);
2136
2137  {
2138    int cnt;
2139    int in;
2140    int lfdone = 0;
2141    char *tabs;
2142   
2143    if (!sc->trace_flow_wrap) {
2144      cnt = sc->trace_flow_in;
2145      in = 0;
2146    }
2147    else {
2148      cnt = I82586_TRACE_FLOW;
2149      in = sc->trace_flow_in;
2150    }
2151
2152    sc->trace_flow_in = sc->trace_flow_wrap = 0;
2153
2154    cnt /= 2;
2155   
2156    for (i = 0; i < cnt; i++) {
2157      if (!lfdone) {
2158        switch (sc->trace_flow[in]) {
2159          case I82586_INTS_REQ:
2160          case I82586_INTS_IN:
2161            printf("\n");
2162        }
2163      }
2164
2165      lfdone = 0;
2166
2167      if (strlen(trace_labels[sc->trace_flow[in]]) < 8)
2168        tabs = "\t\t";
2169      else
2170        tabs = "\t";
2171     
2172      printf(" %d\t%s%s0x%08x (%d)\n",
2173             i, trace_labels[sc->trace_flow[in]], tabs,
2174             sc->trace_flow[in + 1], sc->trace_flow[in + 1]);
2175
2176      switch (sc->trace_flow[in]) {
2177        case I82586_INTS_REQ:
2178        case I82586_INTS_OUT:
2179          lfdone = 1;
2180          printf("\n");
2181      }
2182     
2183      in += 2;
2184     
2185      if (in >= I82586_TRACE_FLOW)
2186        in = 0;
2187    }
2188  }
2189}
2190
2191static void
2192print_rbd(struct ie_softc *sc, int n)
2193{
2194  printf("RBD at %08x:\n  status %04x, next %04x, buffer %lx\n"
2195         "length/EOL %04x\n", IE_RBD_ADDR(sc->rbds,n),
2196         sc->ie_bus_read16(sc, IE_RBD_STATUS(sc->rbds,n)),
2197         sc->ie_bus_read16(sc, IE_RBD_NEXT(sc->rbds,n)),
2198         (u_long)0,/*bus_space_read_4(sc->bt, sc->bh, IE_RBD_BUFADDR(sc->rbds,n)),-* XXX */
2199         sc->ie_bus_read16(sc, IE_RBD_BUFLEN(sc->rbds,n)));
2200}
2201
2202#endif
Note: See TracBrowser for help on using the repository browser.