source: rtems/bsps/shared/net/i82586.c @ a2dad96

5
Last change on this file since a2dad96 was 27de4e1f, checked in by Sebastian Huber <sebastian.huber@…>, on 04/03/18 at 05:20:11

bsps: Move libchip to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

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