OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [c/] [src/] [libchip/] [network/] [i82586.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.