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

4.104.114.84.95
Last change on this file since 6a9db57 was 6a9db57, checked in by Joel Sherrill <joel.sherrill@…>, on 09/19/01 at 17:38:01

2001-09-19 Chris Johns <ccj@…>

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