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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [peripheral/] [eth.c] - Blame information for rev 450

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 19 jeremybenn
/* ethernet.c -- Simulation of Ethernet MAC
2
 
3
   Copyright (C) 2001 by Erez Volk, erez@opencores.org
4
                         Ivan Guzvinec, ivang@opencores.org
5 443 jeremybenn
   Copyright (C) 2008, 2001 Embecosm Limited
6 437 julius
   Copyright (C) 2010 ORSoC
7 19 jeremybenn
 
8
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
9 437 julius
   Contributor Julius Baxter <julius@orsoc.se>
10 19 jeremybenn
 
11
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
12
 
13
   This program is free software; you can redistribute it and/or modify it
14
   under the terms of the GNU General Public License as published by the Free
15
   Software Foundation; either version 3 of the License, or (at your option)
16
   any later version.
17
 
18
   This program is distributed in the hope that it will be useful, but WITHOUT
19
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
21
   more details.
22
 
23
   You should have received a copy of the GNU General Public License along
24
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
25
 
26
/* This program is commented throughout in a fashion suitable for processing
27
   with Doxygen. */
28
 
29
 
30
/* Autoconf and/or portability configuration */
31
#include "config.h"
32
#include "port.h"
33
 
34
/* System includes */
35
#include <stdlib.h>
36
#include <stdio.h>
37 434 jeremybenn
 
38
#include <sys/socket.h>
39
#include <sys/ioctl.h>
40
#include <sys/stat.h>
41 19 jeremybenn
#include <sys/types.h>
42
#include <fcntl.h>
43 434 jeremybenn
 
44 19 jeremybenn
#include <sys/poll.h>
45
#include <unistd.h>
46
#include <errno.h>
47
 
48 434 jeremybenn
#include <linux/if.h>
49
#include <linux/if_tun.h>
50
 
51 19 jeremybenn
/* Package includes */
52
#include "arch.h"
53
#include "config.h"
54
#include "abstract.h"
55
#include "eth.h"
56
#include "dma.h"
57
#include "sim-config.h"
58
#include "fields.h"
59
#include "crc32.h"
60
#include "vapi.h"
61
#include "pic.h"
62
#include "sched.h"
63
#include "toplevel-support.h"
64
#include "sim-cmd.h"
65
 
66 443 jeremybenn
 
67
/* Control debug messages */
68 450 jeremybenn
#define ETH_DEBUG 0
69 443 jeremybenn
#ifndef ETH_DEBUG
70
# define ETH_DEBUG  1
71
#endif
72
 
73
 
74 450 jeremybenn
/*! MAC address that is always accepted. */
75
static const unsigned char mac_broadcast[ETHER_ADDR_LEN] =
76
  { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
77
 
78 443 jeremybenn
/* -------------------------------------------------------------------------- */
79
/*!Structure describing the Ethernet device                                   */
80
/* -------------------------------------------------------------------------- */
81 19 jeremybenn
struct eth_device
82
{
83 443 jeremybenn
  /* Basic stuff about the device */
84
  int                enabled;           /* Is peripheral enabled */
85
  oraddr_t           baseaddr;          /* Base address in memory */
86
  unsigned long int  base_vapi_id;      /* Start of VAPI ID block */
87 19 jeremybenn
 
88 443 jeremybenn
  /* DMA controller this MAC is connected to, and associated channels */
89 19 jeremybenn
  unsigned dma;
90
  unsigned tx_channel;
91
  unsigned rx_channel;
92
 
93 443 jeremybenn
  /* Details of the hardware */
94
  unsigned char      mac_address[ETHER_ADDR_LEN];  /* Ext HW address */
95
  unsigned long int  phy_addr;          /* Int HW address */
96
  unsigned long int  mac_int;           /* interrupt line number */
97
  int                int_line_stat;     /* interrupt line status */
98 19 jeremybenn
 
99 443 jeremybenn
  /* External interface deatils */
100
  int rtx_type;                         /* Type of external i/f: FILE or TAP */
101 19 jeremybenn
 
102 434 jeremybenn
  /* RX and TX file names and handles for FILE type connection. */
103 443 jeremybenn
  char  *rxfile;                        /* Rx filename */
104
  char  *txfile;                        /* Tx filename */
105
  int    txfd;                          /* Rx file handle */
106
  int    rxfd;                          /* Tx file handle */
107 19 jeremybenn
 
108 434 jeremybenn
  /* Info for TAP type connections */
109 443 jeremybenn
  char *tap_dev;                        /* The TAP device */
110
  int   rtx_fd;                         /* TAP device handle */
111 19 jeremybenn
 
112 450 jeremybenn
  /* Indices into the buffer descriptors. */
113
  unsigned long int  tx_bd_index;
114
  unsigned long int  rx_bd_index;
115 19 jeremybenn
 
116
  /* Visible registers */
117
  struct
118
  {
119 443 jeremybenn
    unsigned long int  moder;
120
    unsigned long int  int_source;
121
    unsigned long int  int_mask;
122
    unsigned long int  ipgt;
123
    unsigned long int  ipgr1;
124
    unsigned long int  ipgr2;
125
    unsigned long int  packetlen;
126
    unsigned long int  collconf;
127
    unsigned long int  tx_bd_num;
128
    unsigned long int  controlmoder;
129
    unsigned long int  miimoder;
130
    unsigned long int  miicommand;
131
    unsigned long int  miiaddress;
132
    unsigned long int  miitx_data;
133
    unsigned long int  miirx_data;
134
    unsigned long int  miistatus;
135
    unsigned long int  hash0;
136
    unsigned long int  hash1;
137 19 jeremybenn
 
138
    /* Buffer descriptors */
139 443 jeremybenn
    unsigned long int  bd_ram[ETH_BD_SPACE / 4];
140 19 jeremybenn
  } regs;
141
};
142
 
143
 
144 434 jeremybenn
 
145 443 jeremybenn
/* -------------------------------------------------------------------------- */
146
/*!Emulate MIIM transaction to ethernet PHY
147
 
148
   @param[in]  eth  Ethernet device datastruture.                           */
149
/* -------------------------------------------------------------------------- */
150
static void
151
eth_miim_trans (struct eth_device *eth)
152
{
153
  switch (eth->regs.miicommand)
154
    {
155
    case ((1 << ETH_MIICOMM_WCDATA_OFFSET)):
156
      /* Perhaps something to emulate here later, but for now do nothing */
157
      break;
158
 
159
    case ((1 << ETH_MIICOMM_RSTAT_OFFSET)):
160
      /*
161
      printf("or1ksim: eth_miim_trans: phy %d\n",(int)
162
             ((eth->regs.miiaddress >> ETH_MIIADDR_FIAD_OFFSET)&
163
              ETH_MIIADDR_FIAD_MASK));
164
      printf("or1ksim: eth_miim_trans: reg %d\n",(int)
165
             ((eth->regs.miiaddress >> ETH_MIIADDR_RGAD_OFFSET)&
166
              ETH_MIIADDR_RGAD_MASK));
167
      */
168
      /*First check if it's the correct PHY to address */
169
      if (((eth->regs.miiaddress >> ETH_MIIADDR_FIAD_OFFSET)&
170
           ETH_MIIADDR_FIAD_MASK) == eth->phy_addr)
171
        {
172
          /* Correct PHY - now switch based on the register address in the PHY*/
173
          switch ((eth->regs.miiaddress >> ETH_MIIADDR_RGAD_OFFSET)&
174
                  ETH_MIIADDR_RGAD_MASK)
175 19 jeremybenn
            {
176 443 jeremybenn
            case MII_BMCR:
177
              eth->regs.miirx_data = BMCR_FULLDPLX;
178
              break;
179
            case MII_BMSR:
180
              eth->regs.miirx_data = BMSR_LSTATUS | BMSR_ANEGCOMPLETE |
181
                BMSR_10HALF | BMSR_10FULL | BMSR_100HALF | BMSR_100FULL;
182
              break;
183
            case MII_PHYSID1:
184
              eth->regs.miirx_data = 0x22; /* Micrel PHYID */
185
              break;
186
            case MII_PHYSID2:
187
              eth->regs.miirx_data = 0x1613; /* Micrel PHYID */
188
              break;
189
            case MII_ADVERTISE:
190
              eth->regs.miirx_data = ADVERTISE_FULL;
191
              break;
192
            case MII_LPA:
193
              eth->regs.miirx_data = LPA_DUPLEX | LPA_100;
194
              break;
195
            case MII_EXPANSION:
196
              eth->regs.miirx_data = 0;
197
              break;
198
            case MII_CTRL1000:
199
              eth->regs.miirx_data = 0;
200
              break;
201
            case MII_STAT1000:
202
              eth->regs.miirx_data = 0;
203
              break;
204
            case MII_ESTATUS:
205
              eth->regs.miirx_data = 0;
206
              break;
207
            case MII_DCOUNTER:
208
              eth->regs.miirx_data = 0;
209
              break;
210
            case MII_FCSCOUNTER:
211
              eth->regs.miirx_data = 0;
212
              break;
213
            case MII_NWAYTEST:
214
              eth->regs.miirx_data = 0;
215
              break;
216
            case MII_RERRCOUNTER:
217
              eth->regs.miirx_data = 0;
218
              break;
219
            case MII_SREVISION:
220
              eth->regs.miirx_data = 0;
221
              break;
222
            case MII_RESV1:
223
              eth->regs.miirx_data = 0;
224
              break;
225
            case MII_LBRERROR:
226
              eth->regs.miirx_data = 0;
227
              break;
228
            case MII_PHYADDR:
229
              eth->regs.miirx_data = eth->phy_addr;
230
              break;
231
            case MII_RESV2:
232
              eth->regs.miirx_data = 0;
233
              break;
234
            case MII_TPISTATUS:
235
              eth->regs.miirx_data = 0;
236
              break;
237
            case MII_NCONFIG:
238
              eth->regs.miirx_data = 0;
239
              break;
240
            default:
241
              eth->regs.miirx_data = 0xffff;
242
              break;
243 19 jeremybenn
            }
244
        }
245 443 jeremybenn
      else
246
        {
247
          eth->regs.miirx_data = 0xffff; /* PHY doesn't exist, read all 1's */
248
        }
249 19 jeremybenn
 
250
      break;
251 443 jeremybenn
 
252
    case ((1 << ETH_MIICOMM_SCANS_OFFSET)):
253
      /* From MAC's datasheet:
254
         A host initiates the Scan Status Operation by asserting the SCANSTAT
255
         signal. The MIIM performs a continuous read operation of the PHY
256
         Status register. The PHY is selected by the FIAD[4:0] signals. The
257
         link status LinkFail signal is asserted/deasserted by the MIIM module
258
         and reflects the link status bit of the PHY Status register. The
259
         signal NVALID is used for qualifying the validity of the LinkFail
260
         signals and the status data PRSD[15:0]. These signals are invalid
261
         until the first scan status operation ends. During the scan status
262
         operation, the BUSY signal is asserted until the last read is
263
         performed (the scan status operation is stopped).
264
 
265
         So for now - do nothing, leave link status indicator as permanently
266
         with link.
267
      */
268
 
269
      break;
270
 
271
    default:
272
      break;
273
    }
274
}       /* eth_miim_trans () */
275
 
276
 
277 450 jeremybenn
 
278 443 jeremybenn
/* -------------------------------------------------------------------------- */
279 450 jeremybenn
/*!Write an Ethernet packet to a FILE interface.
280 443 jeremybenn
 
281 450 jeremybenn
   This writes a single Ethernet packet to a FILE interface. The format is to
282
   write the length, then the data.
283 443 jeremybenn
 
284 450 jeremybenn
   @param[in] eth     Pointer to the relevant Ethernet data structure.
285
   @param[in] buf     Where to get the data.
286
   @param[in] length  Length of data to write.
287 443 jeremybenn
 
288 450 jeremybenn
   @return  The length if successful, a negative value otherwise.             */
289
/* -------------------------------------------------------------------------- */
290
static ssize_t
291
eth_write_file_packet (struct eth_device *eth,
292
                       unsigned char     *buf,
293
                       unsigned long int  length)
294
{
295
  ssize_t  nwritten;
296 443 jeremybenn
 
297 450 jeremybenn
  /* Write length to file. */
298
  nwritten = write (eth->txfd, &(length), sizeof (length));
299
  if (nwritten != sizeof (length))
300
    {
301
      fprintf (stderr, "ERROR: Failed to write Ethernet packet length: %s.\n",
302
               strerror (errno));
303
      return  -1;
304
    }
305 443 jeremybenn
 
306 450 jeremybenn
  /* write data to file */
307
  nwritten = write (eth->txfd, buf, length);
308
  if (nwritten != length)
309
    {
310
      fprintf (stderr, "ERROR: Failed to write Ethernet packet data: %s.\n",
311
               strerror (errno));
312
      return  -1;
313
    }
314 443 jeremybenn
 
315 450 jeremybenn
  return  nwritten;
316
 
317
}       /* eth_write_file_packet () */
318
 
319
 
320 443 jeremybenn
/* -------------------------------------------------------------------------- */
321 450 jeremybenn
/*!Write an Ethernet packet to a TAP interface.
322
 
323
   This writes a single Ethernet packet to a TAP interface.
324
 
325
   @param[in] eth     Pointer to the relevant Ethernet data structure.
326
   @param[in] buf     Where to get the data.
327
   @param[in] length  Length of data to write.
328
 
329
   @return  The length if successful, a negative value otherwise.             */
330
/* -------------------------------------------------------------------------- */
331
static ssize_t
332
eth_write_tap_packet (struct eth_device *eth,
333
                      unsigned char     *buf,
334
                      unsigned long int  length)
335 443 jeremybenn
{
336 450 jeremybenn
  ssize_t  nwritten;
337 443 jeremybenn
 
338 450 jeremybenn
#if ETH_DEBUG
339
  int  j;
340 443 jeremybenn
 
341 450 jeremybenn
  printf ("Writing TAP\n");
342
  printf ("  packet %d bytes:", (int) length);
343
 
344
  for (j = 0; j < length; j++)
345 443 jeremybenn
    {
346 450 jeremybenn
      if (0 == (j % 16))
347
        {
348
          printf ("\n");
349
        }
350
      else if (0 == (j % 8))
351
        {
352
          printf (" ");
353
        }
354
 
355
      printf ("%.2x ", buf[j]);
356
    }
357
 
358
  printf("\nend packet:\n");
359
#endif    
360 443 jeremybenn
 
361 450 jeremybenn
  /* Write the data to the TAP */
362
  nwritten = write (eth->rtx_fd, buf, length);
363
  if (nwritten != length)
364
    {
365
      fprintf (stderr, "ERROR: Failed to write Ethernet packet data: %s.\n",
366
               strerror (errno));
367
      return  -1;
368
    }
369 443 jeremybenn
 
370 450 jeremybenn
  return  nwritten;
371 443 jeremybenn
 
372 450 jeremybenn
}       /* eth_write_tap_packet () */
373 443 jeremybenn
 
374
 
375 450 jeremybenn
/* -------------------------------------------------------------------------- */
376
/*!Write an Ethernet packet.
377 443 jeremybenn
 
378 450 jeremybenn
   This writes a single Ethernet packet to the outside world from the supplied
379
   buffer. It deals with the different types of external interface.
380 443 jeremybenn
 
381 450 jeremybenn
   @param[in] eth     Pointer to the relevant Ethernet data structure.
382
   @param[in] buf     Where to get the data.
383
   @param[in] length  Length of data to write.
384 443 jeremybenn
 
385 450 jeremybenn
   @return  The length if successful, zero if no packet was available,
386
            a negative value otherwise.                                       */
387
/* -------------------------------------------------------------------------- */
388
static ssize_t
389
eth_write_packet (struct eth_device *eth,
390
                  unsigned char     *buf,
391
                  ssize_t            length)
392
{
393
  /* Send packet according to interface type. */
394
  switch (eth->rtx_type)
395
    {
396
    case ETH_RTX_FILE: return  eth_write_file_packet (eth, buf, length);
397
    case ETH_RTX_TAP:  return  eth_write_tap_packet (eth, buf, length);
398 443 jeremybenn
 
399 450 jeremybenn
    default:
400
      fprintf (stderr, "Unknown Ethernet write interface: ignored.\n");
401
      return  (ssize_t) -1;
402
    }
403
}       /* eth_write_packet () */
404 443 jeremybenn
 
405
 
406 450 jeremybenn
/* -------------------------------------------------------------------------- */
407
/*!Flush a Tx buffer descriptor to the outside world.
408 19 jeremybenn
 
409 450 jeremybenn
   We know the buffer descriptor is full, so write it to the appropriate
410
   outside interface.
411
 
412
   @param[in] eth  The Ethernet data structure.                               */
413
/* -------------------------------------------------------------------------- */
414
static void
415
eth_flush_bd (struct eth_device *eth)
416
{
417
  /* First word of BD is flags and length, second is pointer to buffer */
418
  unsigned long int  bd_info = eth->regs.bd_ram[eth->tx_bd_index];
419
  unsigned long int  bd_addr = eth->regs.bd_ram[eth->tx_bd_index + 1];
420
  unsigned char      buf[ETH_MAXPL];
421
  long int           packet_length;
422
  long int           bytes_sent;
423
 
424
  /* Get the packet length */
425
  packet_length = GET_FIELD (bd_info, ETH_TX_BD, LENGTH);
426
 
427
  /* Clear error status bits and retry count. */
428
  CLEAR_FLAG (bd_info, ETH_TX_BD, DEFER);
429
  CLEAR_FLAG (bd_info, ETH_TX_BD, COLLISION);
430
  CLEAR_FLAG (bd_info, ETH_TX_BD, RETRANSMIT);
431
  CLEAR_FLAG (bd_info, ETH_TX_BD, UNDERRUN);
432
  CLEAR_FLAG (bd_info, ETH_TX_BD, NO_CARRIER);
433
 
434
  SET_FIELD (bd_info, ETH_TX_BD, RETRY, 0);
435
 
436
  /* Copy data from buffer descriptor address into our local buf. */
437
  for (bytes_sent = 0; bytes_sent < packet_length; bytes_sent +=4)
438
    {
439
      unsigned long int  read_word =
440
        eval_direct32 (bytes_sent + bd_addr, 0, 0);
441
 
442
      buf[bytes_sent]     = (unsigned char) (read_word >> 24);
443
      buf[bytes_sent + 1] = (unsigned char) (read_word >> 16);
444
      buf[bytes_sent + 2] = (unsigned char) (read_word >> 8);
445
      buf[bytes_sent + 3] = (unsigned char) (read_word);
446
    }
447
 
448
  /* Send packet according to interface type and set BD status. If we didn't
449
     write the whole packet, then we retry. */
450
  if (eth_write_packet (eth, buf, packet_length) == packet_length)
451
    {
452
      CLEAR_FLAG (bd_info, ETH_TX_BD, READY);
453
      SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXB);
454
    }
455
  else
456
    {
457
      /* Does this retry mechanism really work? */
458
      CLEAR_FLAG (bd_info, ETH_TX_BD, READY);
459
      CLEAR_FLAG (bd_info, ETH_TX_BD, COLLISION);
460
      SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, TXE);
461 443 jeremybenn
#if ETH_DEBUG
462 450 jeremybenn
      printf ("Transmit retry request.\n");
463 443 jeremybenn
#endif
464 450 jeremybenn
    }
465 19 jeremybenn
 
466 450 jeremybenn
  /* Update the flags in the buffer descriptor */
467
  eth->regs.bd_ram[eth->tx_bd_index] = bd_info;
468 19 jeremybenn
 
469 450 jeremybenn
  /* Generate interrupt to indicate transfer complete, under the
470
     following criteria all being met:
471
     - either INT_MASK flag for Tx (OK or error) is set
472
     - the bugger descriptor has its IRQ flag set
473
     - there is no interrupt in progress.
474 437 julius
 
475 450 jeremybenn
     @todo We ought to warn if we get here and fail to set an IRQ. */
476
  if ((TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, TXE_M) ||
477
       TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, TXB_M)) &&
478
      TEST_FLAG (bd_info, ETH_TX_BD, IRQ))
479
    {
480
      if (eth->int_line_stat)
481 19 jeremybenn
        {
482 450 jeremybenn
          fprintf (stderr, "Warning: Interrupt active during Tx.\n");
483
        }
484
      else
485
        {
486 437 julius
#if ETH_DEBUG
487 443 jeremybenn
          printf ("TRANSMIT interrupt\n");
488 437 julius
#endif
489 443 jeremybenn
          report_interrupt (eth->mac_int);
490
          eth->int_line_stat = 1;
491 19 jeremybenn
        }
492 450 jeremybenn
    }
493 19 jeremybenn
 
494 450 jeremybenn
  /* Advance to next BD, wrapping around if appropriate. */
495
  if (TEST_FLAG (bd_info, ETH_TX_BD, WRAP) ||
496
      eth->tx_bd_index >= ((eth->regs.tx_bd_num - 1) * 2))
497
    {
498
      eth->tx_bd_index = 0;
499 19 jeremybenn
    }
500 450 jeremybenn
  else
501
    {
502
      eth->tx_bd_index += 2;
503
    }
504
}       /* eth_flush_bd () */
505 19 jeremybenn
 
506
 
507 443 jeremybenn
/* -------------------------------------------------------------------------- */
508 450 jeremybenn
/*!Tx clock function.
509 443 jeremybenn
 
510 450 jeremybenn
   Responsible for starting and completing any TX actions.
511 443 jeremybenn
 
512
   The original version had 4 states, which allowed modeling the transfer of
513 450 jeremybenn
   data one byte per cycle.  For now we use only the one state for
514
   efficiency. When we find something in a buffer descriptor, we transmit
515
   it.
516 443 jeremybenn
 
517 450 jeremybenn
   We reschedule every cycle. There is no point in trying to do anything if
518
   there is an interrupt still being processed by the core.
519 443 jeremybenn
 
520
   @todo We should eventually reinstate the one byte per cycle transfer.
521
 
522
   @param[in] dat  The Ethernet data structure, passed as a void pointer.    */
523
/* -------------------------------------------------------------------------- */
524 19 jeremybenn
static void
525 450 jeremybenn
eth_controller_tx_clock (void *dat)
526 19 jeremybenn
{
527
  struct eth_device *eth = dat;
528
 
529 450 jeremybenn
  /* Only do anything if there is not an interrupt outstanding. */
530
  if (!eth->int_line_stat)
531 19 jeremybenn
    {
532 450 jeremybenn
      /* First word of BD is flags. If we have a buffer ready, get it and
533
         transmit it. */
534
      if (TEST_FLAG (eth->regs.bd_ram[eth->tx_bd_index], ETH_TX_BD, READY))
535
        {
536
          eth_flush_bd (eth);
537
        }
538
    }
539 19 jeremybenn
 
540 450 jeremybenn
  /* Wake up again after 1 ticks (was 10, changed by Julius). */
541
  SCHED_ADD (eth_controller_tx_clock, dat, 1);
542 434 jeremybenn
 
543 450 jeremybenn
}       /* eth_controller_tx_clock () */
544 19 jeremybenn
 
545
 
546 450 jeremybenn
/* -------------------------------------------------------------------------- */
547
/*!Read an Ethernet packet from a FILE interface.
548 437 julius
 
549 450 jeremybenn
   This reads a single Ethernet packet from the outside world via a FILE
550
   interface.
551 434 jeremybenn
 
552 450 jeremybenn
   The format is 4 bytes of packet length, followed by the packet data.
553 434 jeremybenn
 
554 450 jeremybenn
   @param[in]  eth  Pointer to the relevant Ethernet data structure
555
   @param[out] buf  Where to put the data
556 434 jeremybenn
 
557 450 jeremybenn
   @return  The length if successful, zero if no packet was available
558
            (i.e. EOF), a negative value otherwise.                           */
559
/* -------------------------------------------------------------------------- */
560
static ssize_t
561
eth_read_file_packet (struct eth_device *eth,
562
                      unsigned char     *buf)
563
{
564
  ssize_t  packet_length;
565
  ssize_t  nread;
566 434 jeremybenn
 
567 450 jeremybenn
  /* Read packet length. We may be at EOF. */
568
  nread = read (eth->rxfd, &(packet_length), sizeof (packet_length));
569 19 jeremybenn
 
570 450 jeremybenn
  if (0 == nread)
571
    {
572
      return  0;                 /* No more packets */
573
    }
574
  else if (nread < sizeof (packet_length))
575
    {
576
      fprintf (stderr, "ERROR: Failed to read length from file.\n");
577
      return  -1;
578
    }
579 434 jeremybenn
 
580 450 jeremybenn
  /* Packet must be big enough to hold a header */
581
  if (packet_length < ETHER_HDR_LEN)
582
    {
583
      fprintf (stderr, "Warning: Ethernet packet length %zd too small.\n",
584
               packet_length);
585
      return  -1;
586
    }
587 19 jeremybenn
 
588 450 jeremybenn
  /* Read the packet proper. */
589
  nread = read (eth->rxfd, buf, packet_length);
590 19 jeremybenn
 
591 450 jeremybenn
  if (nread != packet_length)
592
    {
593
      fprintf (stderr, "ERROR: Failed to read packet from file.\n");
594
      return  -1;
595
    }
596 19 jeremybenn
 
597 450 jeremybenn
  return  packet_length;
598 19 jeremybenn
 
599 450 jeremybenn
}       /* eth_read_file_packet () */
600 19 jeremybenn
 
601
 
602 450 jeremybenn
/* -------------------------------------------------------------------------- */
603
/*!Read an Ethernet packet from a FILE interface.
604 19 jeremybenn
 
605 450 jeremybenn
   This reads a single Ethernet packet from the outside world via a TAP
606
   interface.
607 19 jeremybenn
 
608 450 jeremybenn
   A complete packet is always read, so its length (minus CRC) is the amount
609
   read.
610
 
611
   @param[in]  eth  Pointer to the relevant Ethernet data structure
612
   @param[out] buf  Where to put the data
613
 
614
   @return  The length if successful, zero if no packet was available,
615
            a negative value otherwise.                                       */
616
/* -------------------------------------------------------------------------- */
617
static ssize_t
618
eth_read_tap_packet (struct eth_device *eth,
619
                     unsigned char     *buf)
620
{
621
  struct pollfd  fds[1];
622
  int            n;
623
  ssize_t        packet_length;
624
 
625
  /* Poll to see if there is data to read */
626
  fds[0].fd     = eth->rtx_fd;
627
  fds[0].events = POLLIN;
628 434 jeremybenn
 
629 450 jeremybenn
  n = poll (fds, 1, 0);
630
  if (n < 0)
631
    {
632
      fprintf (stderr, "Warning: Poll for TAP receive failed %s: ignored.\n",
633
               strerror (errno));
634
      return  -1;
635
    }
636
  else if ((n > 0) && ((fds[0].revents & POLLIN) == POLLIN))
637
    {
638
      /* Data to be read from TAP */
639
      packet_length = read (eth->rtx_fd, buf, ETH_MAXPL);
640 437 julius
#if ETH_DEBUG
641 450 jeremybenn
      printf ("%d bytes read from TAP.\n", (int) packet_length);
642 437 julius
#endif
643 450 jeremybenn
      if (packet_length < 0)
644
        {
645
          fprintf (stderr, "Warning: Read of RXTATE_RECV failed: %s.\n",
646
                   strerror (errno));
647
          SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, RXE);
648
 
649
          /* Signal interrupt if enabled, and no interrupt currently in
650
             progress. */
651
          if (TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, RXE_M) &&
652
              !eth->int_line_stat)
653
            {
654 437 julius
#if ETH_DEBUG
655 450 jeremybenn
              printf ("Ethernet failed receive interrupt\n");
656 437 julius
#endif
657 450 jeremybenn
              report_interrupt (eth->mac_int);
658
              eth->int_line_stat = 1;
659
            }
660
        }
661
 
662
      return  packet_length;
663
    }
664
  else
665
    {
666
      return  0;                 /* No packet */
667
    }
668
}       /* eth_read_tap_packet () */
669 434 jeremybenn
 
670 437 julius
 
671 450 jeremybenn
/* -------------------------------------------------------------------------- */
672
/*!Read an Ethernet packet.
673 434 jeremybenn
 
674 450 jeremybenn
   This reads a single Ethernet packet from the outside world into the
675
   supplied buffer. It deals with the different types of external interface.
676 19 jeremybenn
 
677 450 jeremybenn
   @param[in]  eth  Pointer to the relevant Ethernet data structure
678
   @param[out] buf  Where to put the data
679 436 julius
 
680 450 jeremybenn
   @return  The length if successful, zero if no packet was available,
681
            a negative value otherwise.                                       */
682
/* -------------------------------------------------------------------------- */
683
static ssize_t
684
eth_read_packet (struct eth_device *eth,
685
                 unsigned char     *buf)
686
{
687
  switch (eth->rtx_type)
688
    {
689
    case ETH_RTX_FILE: return  eth_read_file_packet (eth, buf);
690
    case ETH_RTX_TAP:  return  eth_read_tap_packet (eth, buf);
691 19 jeremybenn
 
692 450 jeremybenn
    default:
693
      fprintf (stderr, "Unknown Ethernet read interface: ignored.\n");
694
      return  (ssize_t) -1;
695
    }
696
}       /* eth_read_packet () */
697 19 jeremybenn
 
698
 
699 450 jeremybenn
/* -------------------------------------------------------------------------- */
700
/*!Fill a buffer descriptor
701
 
702
   A buffer descriptor is empty. Attempt to fill it from the outside world.
703
 
704
   @param[in] eth  The Ethernet data structure, passed as a void pointer.    */
705
/* -------------------------------------------------------------------------- */
706
static void
707
eth_fill_bd (struct eth_device *eth)
708
{
709
 
710
  /* First word of BD is flags and length, second is pointer to buffer */
711
  unsigned long int  bd_info = eth->regs.bd_ram[eth->rx_bd_index];
712
  unsigned long int  bd_addr = eth->regs.bd_ram[eth->rx_bd_index + 1];
713
 
714
  long int           packet_length;
715
  long int           bytes_read;
716
  unsigned char      buf[ETH_MAXPL];
717
 
718
  /* Clear various status bits */
719
  CLEAR_FLAG (bd_info, ETH_RX_BD, MISS);
720
  CLEAR_FLAG (bd_info, ETH_RX_BD, INVALID);
721
  CLEAR_FLAG (bd_info, ETH_RX_BD, DRIBBLE);
722
  CLEAR_FLAG (bd_info, ETH_RX_BD, UVERRUN);
723
  CLEAR_FLAG (bd_info, ETH_RX_BD, COLLISION);
724
  CLEAR_FLAG (bd_info, ETH_RX_BD, TOOBIG);
725
  CLEAR_FLAG (bd_info, ETH_RX_BD, TOOSHORT);
726
 
727
  /* Loopback is permitted. We believe that Linux never uses it, so we'll
728
     note the attempt and ignore.
729
 
730
     @todo We should support this. */
731
  if (TEST_FLAG (eth->regs.moder, ETH_MODER, LOOPBCK))
732
    {
733
      PRINTF ("Ethernet loopback requested.\n");
734
      fprintf (stderr, "ERROR: Loopback not supported. Ignored.\n");
735
    }
736
 
737
  packet_length = eth_read_packet (eth, buf);
738
  if (packet_length <= 0)
739
    {
740
      /* Empty packet or error. No more to do here. */
741
      return;
742
    }
743
 
744
/* Got a packet successfully. If not promiscuous mode, check the destination
745
   address is meant for us. */
746
  if (!TEST_FLAG (eth->regs.moder, ETH_MODER, PRO))
747
    {
748
      if (TEST_FLAG (eth->regs.moder, ETH_MODER, IAM))
749
        {
750
          /* There is little documentation of how IAM is supposed to work. It
751
             seems that some mapping function (not defined) maps the address
752
             down to a number in the range 0-63. If that bit is set in
753
             HASH0/HASH1 registers, the packet is accepted. */
754
          fprintf (stderr, "Warning: Individual Address Mode ignored.\n");
755 19 jeremybenn
        }
756 450 jeremybenn
 
757
      /* Check for HW address match. */
758
      if ((0 != bcmp (eth->mac_address, buf, ETHER_ADDR_LEN)) &&
759
          (0 != bcmp (mac_broadcast,    buf, ETHER_ADDR_LEN)))
760
        {
761
#if ETH_DEBUG           
762
          printf ("packet for %.2x:%.2x:%.2x:%.2x:%.2x:%.2x ignored.\n",
763
                  buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
764
#endif
765
          /* Not for us. No more to do here. */
766
          return;
767
        }
768
    }
769 19 jeremybenn
 
770 450 jeremybenn
  /* Transfer the buffer into the BD. */
771 437 julius
#if ETH_DEBUG
772 450 jeremybenn
  printf ("writing to Rx BD%d: %d bytes @ 0x%.8x\n",
773
          (int) eth->rx_bd_index / 2,  (int) packet_length,
774
          (unsigned int)bd_addr);
775 437 julius
#endif
776 450 jeremybenn
 
777
  for (bytes_read = 0; bytes_read < packet_length; bytes_read +=4)
778
    {
779
      unsigned long int  send_word =
780
        ((unsigned long) buf[bytes_read]     << 24) |
781
        ((unsigned long) buf[bytes_read + 1] << 16) |
782
        ((unsigned long) buf[bytes_read + 2] <<  8) |
783
        ((unsigned long) buf[bytes_read + 3]      );
784
      set_direct32 (bd_addr + bytes_read, send_word, 0, 0);
785
    }
786
 
787
#if ETH_DEBUG
788
  printf("BD filled with 0x%08lx bytes.\n", bytes_read);
789
#endif
790
 
791
  /* Write result to BD.
792
 
793
     @todo Why is the length 4 more than the packet length? Is that for
794
     the CRC? */
795
  SET_FIELD (bd_info, ETH_RX_BD, LENGTH, packet_length + 4);
796
  CLEAR_FLAG (bd_info, ETH_RX_BD, READY);
797
  SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, RXB);
798
 
799
  eth->regs.bd_ram[eth->rx_bd_index] = bd_info;
800
 
801
  /* Advance to next BD. The Rx BDs start after the Tx BDs. */
802
  if (TEST_FLAG (bd_info, ETH_RX_BD, WRAP) ||
803
      (eth->rx_bd_index >= ETH_BD_COUNT))
804
    {
805
      eth->rx_bd_index = eth->regs.tx_bd_num * 2;
806
    }
807
  else
808
    {
809
      eth->rx_bd_index += 2;
810
    }
811
 
812
  /* Raise an interrupt if necessary. */
813
  if (TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, RXB_M) &&
814
      TEST_FLAG (bd_info, ETH_RX_BD, IRQ))
815
    {
816
      if (eth->int_line_stat)
817
        {
818
          fprintf (stderr, "Warning: Interrupt active during Rx.\n");
819 436 julius
        }
820 450 jeremybenn
      else
821
        {
822 437 julius
#if ETH_DEBUG
823 450 jeremybenn
          printf ("Rx successful receive interrupt\n");
824 437 julius
#endif
825 450 jeremybenn
          report_interrupt (eth->mac_int);
826
          eth->int_line_stat = 1;
827
        }
828
    }
829
}       /* eth_fill_bd () */
830 19 jeremybenn
 
831
 
832 450 jeremybenn
/* -------------------------------------------------------------------------- */
833
/*!Ignore a packet from the outside world.
834 437 julius
 
835 450 jeremybenn
   We don't have a BD ready, so any packets waiting should be thrown away.
836
 
837
   @param[in] eth  The Ethernet data structure.                               */
838
/* -------------------------------------------------------------------------- */
839
static void
840
eth_ignore_packet (struct eth_device *eth)
841
{
842
  unsigned char  buf[ETH_MAXPL];
843
  ssize_t        nread = eth_read_packet (eth, buf);
844
 
845
  if (nread < 0)
846
    {
847
      fprintf (stderr,
848
               "Warning: Read of when Ethernet busy failed %s.\n",
849
               strerror (errno));
850
    }
851
  else if (nread > 0)
852
    {
853
      /* Record that a packet was thrown away. */
854
      SET_FLAG (eth->regs.int_source, ETH_INT_SOURCE, BUSY);
855
      PRINTF ("Ethernet discarding %d bytes from TAP while BD full.\n",
856
              nread);
857
 
858
      /* Raise an interrupt if necessary. */
859
      if (TEST_FLAG (eth->regs.int_mask, ETH_INT_MASK, BUSY_M))
860
        {
861
          if (eth->int_line_stat)
862 19 jeremybenn
            {
863 450 jeremybenn
              fprintf (stderr, "Warning: Interrupt active during ignore.\n");
864
            }
865
          else
866
            {
867 437 julius
#if ETH_DEBUG
868 450 jeremybenn
              printf ("Ethernet Rx BUSY interrupt\n");
869 437 julius
#endif
870 19 jeremybenn
              report_interrupt (eth->mac_int);
871 437 julius
              eth->int_line_stat = 1;
872 19 jeremybenn
            }
873 450 jeremybenn
        }
874
    }
875
}       /* eth_ignore_packet () */
876 19 jeremybenn
 
877 450 jeremybenn
 
878
/* -------------------------------------------------------------------------- */
879
/*!Rx clock function.
880
 
881
   Responsible for starting and completing any RX actions.
882
 
883
   The original version had 4 states, which allowed modeling the transfer of
884
   data one byte per cycle.  For now we use only the one state for
885
   efficiency. When the buffer is empty, we fill it from the external world.
886
 
887
   We schedule to wake up again each cycle. This means we will get called when
888
   the core is still processing the previous interrupt. To avoid races, we do
889
   nothing until the interrupt is cleared.
890
 
891
   @todo We should eventually reinstate the one byte per cycle transfer.
892
 
893
   @param[in] dat  The Ethernet data structure, passed as a void pointer.    */
894
/* -------------------------------------------------------------------------- */
895
static void
896
eth_controller_rx_clock (void *dat)
897
{
898
  struct eth_device *eth = dat;
899
 
900
  /* Only do anything if there is not an interrupt outstanding. */
901
  if (!eth->int_line_stat)
902
    {
903
      /* First word of the BD is flags, where we can test if it's ready. */
904
      if (TEST_FLAG (eth->regs.bd_ram[eth->rx_bd_index], ETH_RX_BD, READY))
905
        {
906
          /* The BD is empty, so we try to fill it with data from the outside
907
             world. */
908
          eth_fill_bd (eth);    /* BD ready to be filled. */
909 19 jeremybenn
        }
910 450 jeremybenn
      else if ((TEST_FLAG (eth->regs.moder, ETH_MODER, RXEN)) &&
911
               (ETH_RTX_FILE == eth->rtx_type))
912
        {
913
          /* The BD is full, Rx is enabled and we are reading from an external
914
             TAP interface. We can't take any more, so we'll throw oustanding
915
             input packets on the floor.
916
 
917
             @note We don't do this for file I/O, since it would discard
918
             everything immediately! */
919
          eth_ignore_packet (eth);
920
        }
921 19 jeremybenn
    }
922
 
923 450 jeremybenn
  /* Whatever happens, we reschedule a wake up in the future. This used to be
924
     every 10 ticks, but now it is very 1 tick. */
925 442 julius
  SCHED_ADD (eth_controller_rx_clock, dat, 1);
926 19 jeremybenn
 
927 450 jeremybenn
}       /* eth_controller_rx_clock () */
928
 
929
 
930 19 jeremybenn
/* ========================================================================= */
931
 
932 443 jeremybenn
/* ========================================================================= */
933 19 jeremybenn
 
934 443 jeremybenn
 
935 19 jeremybenn
/*
936 443 jeremybenn
 *   VAPI connection to outside
937 19 jeremybenn
 */
938 443 jeremybenn
static void
939
eth_vapi_read (unsigned long id, unsigned long data, void *dat)
940 19 jeremybenn
{
941 443 jeremybenn
  unsigned long which;
942
  struct eth_device *eth = dat;
943 19 jeremybenn
 
944 443 jeremybenn
  which = id - eth->base_vapi_id;
945
 
946
  if (!eth)
947 19 jeremybenn
    {
948 443 jeremybenn
      return;
949 19 jeremybenn
    }
950
 
951 443 jeremybenn
  switch (which)
952
    {
953
    case ETH_VAPI_DATA:
954
      break;
955
    case ETH_VAPI_CTRL:
956
      break;
957
    }
958 19 jeremybenn
}
959
 
960 434 jeremybenn
/* -------------------------------------------------------------------------- */
961
/*!Reset the Ethernet.
962
 
963
   Open the correct type of simulation interface to the outside world.
964
 
965
   Initialize all registers to default and places devices in memory address
966
   space.
967
 
968
   @param[in] dat  The Ethernet interface data structure.                     */
969
/* -------------------------------------------------------------------------- */
970 19 jeremybenn
static void
971
eth_reset (void *dat)
972
{
973
  struct eth_device *eth = dat;
974 434 jeremybenn
  struct ifreq       ifr;
975 19 jeremybenn
 
976 437 julius
#if ETH_DEBUG
977 434 jeremybenn
  printf ("Resetting Ethernet\n");
978 437 julius
#endif
979 434 jeremybenn
  /* Nothing to do if we do not have a base address set.
980
 
981
     TODO: Surely this should test for being enabled? */
982
  if (0 == eth->baseaddr)
983 19 jeremybenn
    {
984 434 jeremybenn
      return;
985
    }
986
 
987
  switch (eth->rtx_type)
988
    {
989
    case ETH_RTX_FILE:
990
 
991
      /* (Re-)open TX/RX files */
992
      if (eth->rxfd >= 0)
993 19 jeremybenn
        {
994 434 jeremybenn
          close (eth->rxfd);
995
        }
996 19 jeremybenn
 
997 434 jeremybenn
      if (eth->txfd >= 0)
998
        {
999
          close (eth->txfd);
1000
        }
1001 19 jeremybenn
 
1002 434 jeremybenn
      eth->rxfd = -1;
1003
      eth->txfd = -1;
1004 19 jeremybenn
 
1005 434 jeremybenn
      eth->rxfd = open (eth->rxfile, O_RDONLY);
1006
      if (eth->rxfd < 0)
1007
        {
1008
          fprintf (stderr, "Warning: Cannot open Ethernet RX file \"%s\": %s\n",
1009
                   eth->rxfile, strerror (errno));
1010
        }
1011 19 jeremybenn
 
1012 434 jeremybenn
      eth->txfd = open (eth->txfile,
1013
#if defined(O_SYNC)             /* BSD/MacOS X doesn't know about O_SYNC */
1014
                        O_SYNC |
1015
#endif
1016
                        O_RDWR | O_CREAT | O_APPEND,
1017
                        S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1018
      if (eth->txfd < 0)
1019
        {
1020
          fprintf (stderr, "Warning: Cannot open Ethernet TX file \"%s\": %s\n",
1021
                   eth->txfile, strerror (errno));
1022
        }
1023 19 jeremybenn
 
1024 434 jeremybenn
      break;
1025 19 jeremybenn
 
1026 434 jeremybenn
    case ETH_RTX_TAP:
1027 19 jeremybenn
 
1028 434 jeremybenn
      /* (Re-)open TAP interface if necessary */
1029
      if (eth->rtx_fd != 0)
1030
        {
1031 19 jeremybenn
          break;
1032
        }
1033
 
1034 434 jeremybenn
      /* Open the TUN/TAP device */
1035
      eth->rtx_fd = open ("/dev/net/tun", O_RDWR);
1036
      if( eth->rtx_fd < 0 )
1037
        {
1038
          fprintf (stderr, "Warning: Failed to open TUN/TAP device: %s\n",
1039
                   strerror (errno));
1040
          eth->rtx_fd = 0;
1041
          return;
1042
        }
1043 19 jeremybenn
 
1044 434 jeremybenn
      /* Turn it into a specific TAP device. If we haven't specified a
1045
         specific (persistent) device, one will be created, but that requires
1046
         superuser, or at least CAP_NET_ADMIN capabilities. */
1047
      memset (&ifr, 0, sizeof(ifr));
1048 436 julius
      ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
1049 434 jeremybenn
      strncpy (ifr.ifr_name, eth->tap_dev, IFNAMSIZ);
1050 19 jeremybenn
 
1051 434 jeremybenn
      if (ioctl (eth->rtx_fd, TUNSETIFF, (void *) &ifr) < 0)
1052 19 jeremybenn
        {
1053 434 jeremybenn
          fprintf (stderr, "Warning: Failed to set TAP device: %s\n",
1054
                   strerror (errno));
1055
          close (eth->rtx_fd);
1056
          eth->rtx_fd = 0;
1057
          return;
1058 19 jeremybenn
        }
1059 437 julius
#if ETH_DEBUG
1060 434 jeremybenn
      PRINTF ("Opened TAP %s\n", ifr.ifr_name);
1061 437 julius
#endif
1062 434 jeremybenn
      /* Do we need to flush any packets? */
1063
      break;
1064 19 jeremybenn
    }
1065
 
1066 434 jeremybenn
  /* Set registers to default values */
1067
  memset (&(eth->regs), 0, sizeof (eth->regs));
1068 19 jeremybenn
 
1069 434 jeremybenn
  eth->regs.moder     = 0x0000A000;
1070
  eth->regs.ipgt      = 0x00000012;
1071
  eth->regs.ipgr1     = 0x0000000C;
1072
  eth->regs.ipgr2     = 0x00000012;
1073
  eth->regs.packetlen = 0x003C0600;
1074
  eth->regs.collconf  = 0x000F003F;
1075
  eth->regs.miimoder  = 0x00000064;
1076
  eth->regs.tx_bd_num = 0x00000040;
1077 19 jeremybenn
 
1078 450 jeremybenn
  /* Reset TX/RX BD indexes. The Rx BD indexes start after the Tx BD indexes. */
1079
  eth->tx_bd_index = 0;
1080
  eth->rx_bd_index = eth->regs.tx_bd_num * 2;
1081 434 jeremybenn
 
1082 437 julius
  /* Reset IRQ line status */
1083
  eth->int_line_stat = 0;
1084
 
1085 434 jeremybenn
  /* Initialize VAPI */
1086
  if (eth->base_vapi_id)
1087
    {
1088
      vapi_install_multi_handler (eth->base_vapi_id, ETH_NUM_VAPI_IDS,
1089
                                  eth_vapi_read, dat);
1090
    }
1091
}       /* eth_reset () */
1092
 
1093
 
1094 19 jeremybenn
/*
1095
  Print register values on stdout
1096
*/
1097
static void
1098
eth_status (void *dat)
1099
{
1100
  struct eth_device *eth = dat;
1101
 
1102
  PRINTF ("\nEthernet MAC at 0x%" PRIxADDR ":\n", eth->baseaddr);
1103
  PRINTF ("MODER        : 0x%08lX\n", eth->regs.moder);
1104
  PRINTF ("INT_SOURCE   : 0x%08lX\n", eth->regs.int_source);
1105
  PRINTF ("INT_MASK     : 0x%08lX\n", eth->regs.int_mask);
1106
  PRINTF ("IPGT         : 0x%08lX\n", eth->regs.ipgt);
1107
  PRINTF ("IPGR1        : 0x%08lX\n", eth->regs.ipgr1);
1108
  PRINTF ("IPGR2        : 0x%08lX\n", eth->regs.ipgr2);
1109
  PRINTF ("PACKETLEN    : 0x%08lX\n", eth->regs.packetlen);
1110
  PRINTF ("COLLCONF     : 0x%08lX\n", eth->regs.collconf);
1111
  PRINTF ("TX_BD_NUM    : 0x%08lX\n", eth->regs.tx_bd_num);
1112
  PRINTF ("CTRLMODER    : 0x%08lX\n", eth->regs.controlmoder);
1113
  PRINTF ("MIIMODER     : 0x%08lX\n", eth->regs.miimoder);
1114
  PRINTF ("MIICOMMAND   : 0x%08lX\n", eth->regs.miicommand);
1115
  PRINTF ("MIIADDRESS   : 0x%08lX\n", eth->regs.miiaddress);
1116
  PRINTF ("MIITX_DATA   : 0x%08lX\n", eth->regs.miitx_data);
1117
  PRINTF ("MIIRX_DATA   : 0x%08lX\n", eth->regs.miirx_data);
1118
  PRINTF ("MIISTATUS    : 0x%08lX\n", eth->regs.miistatus);
1119
  PRINTF ("MAC Address  : %02X:%02X:%02X:%02X:%02X:%02X\n",
1120 450 jeremybenn
          eth->mac_address[5], eth->mac_address[4], eth->mac_address[3],
1121
          eth->mac_address[2], eth->mac_address[1], eth->mac_address[0]);
1122 19 jeremybenn
  PRINTF ("HASH0        : 0x%08lX\n", eth->regs.hash0);
1123
  PRINTF ("HASH1        : 0x%08lX\n", eth->regs.hash1);
1124
}
1125
 
1126
/* ========================================================================= */
1127
 
1128
 
1129
/*
1130
  Read a register
1131
*/
1132
static uint32_t
1133
eth_read32 (oraddr_t addr, void *dat)
1134
{
1135
  struct eth_device *eth = dat;
1136
 
1137
  switch (addr)
1138
    {
1139
    case ETH_MODER:
1140
      return eth->regs.moder;
1141
    case ETH_INT_SOURCE:
1142
      return eth->regs.int_source;
1143
    case ETH_INT_MASK:
1144
      return eth->regs.int_mask;
1145
    case ETH_IPGT:
1146
      return eth->regs.ipgt;
1147
    case ETH_IPGR1:
1148
      return eth->regs.ipgr1;
1149
    case ETH_IPGR2:
1150
      return eth->regs.ipgr2;
1151
    case ETH_PACKETLEN:
1152
      return eth->regs.packetlen;
1153
    case ETH_COLLCONF:
1154
      return eth->regs.collconf;
1155
    case ETH_TX_BD_NUM:
1156
      return eth->regs.tx_bd_num;
1157
    case ETH_CTRLMODER:
1158
      return eth->regs.controlmoder;
1159
    case ETH_MIIMODER:
1160
      return eth->regs.miimoder;
1161
    case ETH_MIICOMMAND:
1162
      return eth->regs.miicommand;
1163
    case ETH_MIIADDRESS:
1164
      return eth->regs.miiaddress;
1165
    case ETH_MIITX_DATA:
1166
      return eth->regs.miitx_data;
1167
    case ETH_MIIRX_DATA:
1168 428 julius
      /*printf("or1ksim: read MIIM RX: 0x%x\n",(int)eth->regs.miirx_data);*/
1169 19 jeremybenn
      return eth->regs.miirx_data;
1170
    case ETH_MIISTATUS:
1171
      return eth->regs.miistatus;
1172
    case ETH_MAC_ADDR0:
1173 450 jeremybenn
      return (((unsigned long) eth->mac_address[2]) << 24) |
1174
        (((unsigned long) eth->mac_address[3]) << 16) |
1175
        (((unsigned long) eth->mac_address[4]) << 8) |
1176
        (unsigned long) eth->mac_address[5];
1177 19 jeremybenn
    case ETH_MAC_ADDR1:
1178 450 jeremybenn
      return (((unsigned long) eth->mac_address[0]) << 8) |
1179
        (unsigned long) eth->mac_address[1];
1180 19 jeremybenn
    case ETH_HASH0:
1181
      return eth->regs.hash0;
1182
    case ETH_HASH1:
1183
      return eth->regs.hash1;
1184
      /*case ETH_DMA_RX_TX: return eth_rx( eth ); */
1185
    }
1186
 
1187
  if ((addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE))
1188
    return eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4];
1189
 
1190
  PRINTF ("eth_read32( 0x%" PRIxADDR " ): Illegal address\n",
1191
          addr + eth->baseaddr);
1192
  return 0;
1193
}
1194
 
1195
/* ========================================================================= */
1196
 
1197
 
1198
/*
1199
  Write a register
1200
*/
1201
static void
1202
eth_write32 (oraddr_t addr, uint32_t value, void *dat)
1203
{
1204
  struct eth_device *eth = dat;
1205 450 jeremybenn
  unsigned char      buf[ETH_MAXPL];
1206 19 jeremybenn
 
1207
  switch (addr)
1208
    {
1209
    case ETH_MODER:
1210 437 julius
#if ETH_DEBUG
1211
      printf("eth_write32: MODER 0x%x\n",value);
1212
#endif
1213 19 jeremybenn
      if (!TEST_FLAG (eth->regs.moder, ETH_MODER, RXEN) &&
1214
          TEST_FLAG (value, ETH_MODER, RXEN))
1215 436 julius
        {
1216
          // Reset RX BD index
1217 450 jeremybenn
          eth->rx_bd_index = eth->regs.tx_bd_num << 1;
1218 437 julius
 
1219
          // Clear TAP
1220
          {
1221
            /* Poll to see if there is data to read */
1222
            struct pollfd  fds[1];
1223
            int    n;
1224
            int nread;
1225
 
1226
            fds[0].fd = eth->rtx_fd;
1227
            fds[0].events = POLLIN;
1228
 
1229
            do {
1230
              n = poll (fds, 1, 0);
1231
              if (n < 0)
1232
                {
1233
                  fprintf (stderr, "Warning: Poll in while emptying TAP: %s: ignored.\n",
1234
                           strerror (errno));
1235
                }
1236
              else if ((n > 0) && ((fds[0].revents & POLLIN) == POLLIN))
1237
                {
1238 450 jeremybenn
                  nread = read (eth->rtx_fd, buf, ETH_MAXPL);
1239 437 julius
 
1240
                  if (nread < 0)
1241
                    {
1242
                      fprintf (stderr,
1243
                               "Warning: Read failed %s: ignored\n",
1244
                               strerror (errno));
1245
                    }
1246
                }
1247
            } while (n > 0);
1248
          }
1249
 
1250 436 julius
          SCHED_ADD (eth_controller_rx_clock, dat, 1);
1251
        }
1252 437 julius
      else if (!TEST_FLAG (value, ETH_MODER, RXEN) &&
1253
               TEST_FLAG (eth->regs.moder, ETH_MODER, RXEN))
1254 19 jeremybenn
        SCHED_FIND_REMOVE (eth_controller_rx_clock, dat);
1255
 
1256
      if (!TEST_FLAG (eth->regs.moder, ETH_MODER, TXEN) &&
1257
          TEST_FLAG (value, ETH_MODER, TXEN))
1258 436 julius
        {
1259 450 jeremybenn
          eth->tx_bd_index = 0;
1260 436 julius
          SCHED_ADD (eth_controller_tx_clock, dat, 1);
1261
        }
1262 437 julius
      else if (!TEST_FLAG (value, ETH_MODER, TXEN) &&
1263
               TEST_FLAG (eth->regs.moder, ETH_MODER, TXEN))
1264 19 jeremybenn
        SCHED_FIND_REMOVE (eth_controller_tx_clock, dat);
1265
 
1266
      eth->regs.moder = value;
1267
 
1268
      if (TEST_FLAG (value, ETH_MODER, RST))
1269
        eth_reset (dat);
1270
      return;
1271
    case ETH_INT_SOURCE:
1272 437 julius
#if ETH_DEBUG
1273
      printf("eth_write32: INT_SOURCE 0x%x\n",value);
1274
#endif
1275
      eth->regs.int_source &= ~value;
1276 436 julius
 
1277 437 julius
      // Clear IRQ line if all interrupt sources have been dealt with
1278
      if (!(eth->regs.int_source & eth->regs.int_mask) && eth->int_line_stat)
1279
        {
1280
          clear_interrupt (eth->mac_int);
1281
          eth->int_line_stat = 0;
1282
        }
1283
 
1284 19 jeremybenn
      return;
1285
    case ETH_INT_MASK:
1286 437 julius
#if ETH_DEBUG
1287
      printf("eth_write32: INT_MASK 0x%x\n",value);
1288
#endif
1289 19 jeremybenn
      eth->regs.int_mask = value;
1290 437 julius
      if ((eth->regs.int_source & eth->regs.int_mask) && !eth->int_line_stat)
1291 436 julius
        report_interrupt (eth->mac_int);
1292
      else
1293 437 julius
        if (eth->int_line_stat)
1294
          {
1295
            clear_interrupt (eth->mac_int);
1296
            eth->int_line_stat = 0;
1297
          }
1298 19 jeremybenn
      return;
1299
    case ETH_IPGT:
1300
      eth->regs.ipgt = value;
1301
      return;
1302
    case ETH_IPGR1:
1303
      eth->regs.ipgr1 = value;
1304
      return;
1305
    case ETH_IPGR2:
1306
      eth->regs.ipgr2 = value;
1307
      return;
1308
    case ETH_PACKETLEN:
1309
      eth->regs.packetlen = value;
1310
      return;
1311
    case ETH_COLLCONF:
1312
      eth->regs.collconf = value;
1313
      return;
1314
    case ETH_TX_BD_NUM:
1315 443 jeremybenn
      /* When TX_BD_NUM is written, also reset current RX BD index */
1316
      eth->regs.tx_bd_num = value & 0xFF;
1317 450 jeremybenn
      eth->rx_bd_index = eth->regs.tx_bd_num << 1;
1318 19 jeremybenn
      return;
1319
    case ETH_CTRLMODER:
1320
      eth->regs.controlmoder = value;
1321
      return;
1322
    case ETH_MIIMODER:
1323
      eth->regs.miimoder = value;
1324
      return;
1325
    case ETH_MIICOMMAND:
1326
      eth->regs.miicommand = value;
1327 428 julius
      /* Perform MIIM transaction, if required */
1328 443 jeremybenn
      eth_miim_trans (eth);
1329 19 jeremybenn
      return;
1330
    case ETH_MIIADDRESS:
1331
      eth->regs.miiaddress = value;
1332
      return;
1333
    case ETH_MIITX_DATA:
1334
      eth->regs.miitx_data = value;
1335
      return;
1336
    case ETH_MIIRX_DATA:
1337 428 julius
      /* Register is R/O
1338 19 jeremybenn
      eth->regs.miirx_data = value;
1339 428 julius
      */
1340 19 jeremybenn
      return;
1341
    case ETH_MIISTATUS:
1342 428 julius
      /* Register is R/O
1343 19 jeremybenn
      eth->regs.miistatus = value;
1344 428 julius
      */
1345 19 jeremybenn
      return;
1346 428 julius
 
1347 19 jeremybenn
    case ETH_MAC_ADDR0:
1348 450 jeremybenn
      eth->mac_address[5] = value & 0xFF;
1349
      eth->mac_address[4] = (value >> 8) & 0xFF;
1350
      eth->mac_address[3] = (value >> 16) & 0xFF;
1351
      eth->mac_address[2] = (value >> 24) & 0xFF;
1352 19 jeremybenn
      return;
1353
    case ETH_MAC_ADDR1:
1354 450 jeremybenn
      eth->mac_address[1] = value & 0xFF;
1355
      eth->mac_address[0] = (value >> 8) & 0xFF;
1356 19 jeremybenn
      return;
1357
    case ETH_HASH0:
1358
      eth->regs.hash0 = value;
1359
      return;
1360
    case ETH_HASH1:
1361
      eth->regs.hash1 = value;
1362
      return;
1363
 
1364
      /*case ETH_DMA_RX_TX: eth_tx( eth, value ); return; */
1365
    }
1366
 
1367
  if ((addr >= ETH_BD_BASE) && (addr < ETH_BD_BASE + ETH_BD_SPACE))
1368
    {
1369
      eth->regs.bd_ram[(addr - ETH_BD_BASE) / 4] = value;
1370
      return;
1371
    }
1372
 
1373
  PRINTF ("eth_write32( 0x%" PRIxADDR " ): Illegal address\n",
1374
          addr + eth->baseaddr);
1375
  return;
1376
}
1377
 
1378
/* ========================================================================= */
1379
 
1380
 
1381
/* ========================================================================= */
1382
 
1383
 
1384
 
1385
/* ========================================================================= */
1386
 
1387
/*-----------------------------------------------[ Ethernet configuration ]---*/
1388
 
1389
 
1390
/*---------------------------------------------------------------------------*/
1391
/*!Enable or disable the Ethernet interface
1392
 
1393
   @param[in] val  The value to use
1394
   @param[in] dat  The config data structure                                 */
1395
/*---------------------------------------------------------------------------*/
1396
static void
1397
eth_enabled (union param_val  val,
1398
             void            *dat)
1399
{
1400
  struct eth_device *eth = dat;
1401
 
1402
  eth->enabled = val.int_val;
1403
 
1404
}       /* eth_enabled() */
1405
 
1406
 
1407
/*---------------------------------------------------------------------------*/
1408
/*!Set the Ethernet interface base address
1409
 
1410
   @param[in] val  The value to use
1411
   @param[in] dat  The config data structure                                 */
1412
/*---------------------------------------------------------------------------*/
1413
static void
1414
eth_baseaddr (union param_val  val,
1415
              void            *dat)
1416
{
1417
  struct eth_device *eth = dat;
1418
 
1419
  eth->baseaddr = val.addr_val;
1420
 
1421
}       /* eth_baseaddr() */
1422
 
1423
 
1424
/*---------------------------------------------------------------------------*/
1425
/*!Set the Ethernet DMA port
1426
 
1427
   This is not currently supported, so a warning message is printed.
1428
 
1429
   @param[in] val  The value to use
1430
   @param[in] dat  The config data structure                                 */
1431
/*---------------------------------------------------------------------------*/
1432
static void
1433
eth_dma (union param_val  val,
1434
         void            *dat)
1435
{
1436
  struct eth_device *eth = dat;
1437
 
1438
  fprintf (stderr, "Warning: External Ethernet DMA not currently supported\n");
1439
  eth->dma = val.addr_val;
1440
 
1441
}       /* eth_dma() */
1442
 
1443
 
1444
/*---------------------------------------------------------------------------*/
1445
/*!Set the Ethernet IRQ
1446
 
1447
   @param[in] val  The value to use
1448
   @param[in] dat  The config data structure                                 */
1449
/*---------------------------------------------------------------------------*/
1450
static void
1451
eth_irq (union param_val  val,
1452
         void            *dat)
1453
{
1454
  struct eth_device *eth = dat;
1455
 
1456
  eth->mac_int = val.int_val;
1457
 
1458
}       /* eth_irq() */
1459
 
1460
 
1461
/*---------------------------------------------------------------------------*/
1462
/*!Set the Ethernet interface type
1463
 
1464 434 jeremybenn
   Currently two types are supported, file and tap.
1465 19 jeremybenn
 
1466 434 jeremybenn
   @param[in] val  The value to use. Currently "file" and "tap" are supported.
1467 19 jeremybenn
   @param[in] dat  The config data structure                                 */
1468
/*---------------------------------------------------------------------------*/
1469
static void
1470
eth_rtx_type (union param_val  val,
1471
              void            *dat)
1472
{
1473
  struct eth_device *eth = dat;
1474
 
1475 434 jeremybenn
  if (0 == strcasecmp ("file", val.str_val))
1476 19 jeremybenn
    {
1477 434 jeremybenn
      printf ("Ethernet FILE type\n");
1478
      eth->rtx_type = ETH_RTX_FILE;
1479 19 jeremybenn
    }
1480 434 jeremybenn
  else if (0 == strcasecmp ("tap", val.str_val))
1481
    {
1482
      printf ("Ethernet TAP type\n");
1483
      eth->rtx_type = ETH_RTX_TAP;
1484
    }
1485
  else
1486
    {
1487
      fprintf (stderr, "Warning: Unknown Ethernet type: file assumed.\n");
1488
      eth->rtx_type = ETH_RTX_FILE;
1489
    }
1490 19 jeremybenn
}       /* eth_rtx_type() */
1491
 
1492
 
1493
/*---------------------------------------------------------------------------*/
1494
/*!Set the Ethernet DMA Rx channel
1495
 
1496
   External DMA is not currently supported, so a warning message is printed.
1497
 
1498
   @param[in] val  The value to use
1499
   @param[in] dat  The config data structure                                 */
1500
/*---------------------------------------------------------------------------*/
1501
static void
1502
eth_rx_channel (union param_val  val,
1503
                void            *dat)
1504
{
1505
  struct eth_device *eth = dat;
1506
 
1507
  fprintf (stderr, "Warning: External Ethernet DMA not currently supported: "
1508
           "Rx channel ignored\n");
1509
  eth->rx_channel = val.int_val;
1510
 
1511
}       /* eth_rx_channel() */
1512
 
1513
 
1514
/*---------------------------------------------------------------------------*/
1515
/*!Set the Ethernet DMA Tx channel
1516
 
1517
   External DMA is not currently supported, so a warning message is printed.
1518
 
1519
   @param[in] val  The value to use
1520
   @param[in] dat  The config data structure                                 */
1521
/*---------------------------------------------------------------------------*/
1522
static void
1523
eth_tx_channel (union param_val  val,
1524
                void            *dat)
1525
{
1526
  struct eth_device *eth = dat;
1527
 
1528
  fprintf (stderr, "Warning: External Ethernet DMA not currently supported: "
1529
           "Tx channel ignored\n");
1530
  eth->tx_channel = val.int_val;
1531
 
1532
}       /* eth_tx_channel() */
1533
 
1534
 
1535
/*---------------------------------------------------------------------------*/
1536
/*!Set the Ethernet DMA Rx file
1537
 
1538
   Free any previously allocated value.
1539
 
1540
   @param[in] val  The value to use
1541
   @param[in] dat  The config data structure                                 */
1542
/*---------------------------------------------------------------------------*/
1543
static void
1544
eth_rxfile (union param_val  val,
1545
            void            *dat)
1546
{
1547
  struct eth_device *eth = dat;
1548
 
1549
  if (NULL != eth->rxfile)
1550
    {
1551
      free (eth->rxfile);
1552
      eth->rxfile = NULL;
1553
    }
1554
 
1555
  if (!(eth->rxfile = strdup (val.str_val)))
1556
    {
1557
      fprintf (stderr, "Peripheral Ethernet: Run out of memory\n");
1558
      exit (-1);
1559
    }
1560
}       /* eth_rxfile() */
1561
 
1562
 
1563
/*---------------------------------------------------------------------------*/
1564
/*!Set the Ethernet DMA Tx file
1565
 
1566
   Free any previously allocated value.
1567
 
1568
   @param[in] val  The value to use
1569
   @param[in] dat  The config data structure                                 */
1570
/*---------------------------------------------------------------------------*/
1571
static void
1572
eth_txfile (union param_val  val,
1573
            void            *dat)
1574
{
1575
  struct eth_device *eth = dat;
1576
 
1577
  if (NULL != eth->txfile)
1578
    {
1579
      free (eth->txfile);
1580
      eth->txfile = NULL;
1581
    }
1582
 
1583
  if (!(eth->txfile = strdup (val.str_val)))
1584
    {
1585
      fprintf (stderr, "Peripheral Ethernet: Run out of memory\n");
1586
      exit (-1);
1587
    }
1588
}       /* eth_txfile() */
1589
 
1590
 
1591
/*---------------------------------------------------------------------------*/
1592 434 jeremybenn
/*!Set the Ethernet TAP device.
1593 19 jeremybenn
 
1594 434 jeremybenn
   If we are not superuser (or do not have CAP_NET_ADMIN priviledges), then we
1595
   must work with a persistent TAP device that is already set up. This option
1596
   specifies the device to user.
1597 19 jeremybenn
 
1598 434 jeremybenn
   @param[in] val  The value to use.
1599 19 jeremybenn
   @param[in] dat  The config data structure                                 */
1600
/*---------------------------------------------------------------------------*/
1601
static void
1602 434 jeremybenn
eth_tap_dev (union param_val  val,
1603
              void            *dat)
1604 19 jeremybenn
{
1605
  struct eth_device *eth = dat;
1606
 
1607 434 jeremybenn
  if (NULL != eth->tap_dev)
1608 19 jeremybenn
    {
1609 434 jeremybenn
      free (eth->tap_dev);
1610
      eth->tap_dev = NULL;
1611 19 jeremybenn
    }
1612
 
1613 434 jeremybenn
  eth->tap_dev = strdup (val.str_val);
1614
 
1615
  if (NULL == eth->tap_dev)
1616 19 jeremybenn
    {
1617 434 jeremybenn
      fprintf (stderr, "ERROR: Peripheral Ethernet: Run out of memory\n");
1618 19 jeremybenn
      exit (-1);
1619
    }
1620 434 jeremybenn
}       /* eth_tap_dev() */
1621 19 jeremybenn
 
1622
 
1623
static void
1624
eth_vapi_id (union param_val  val,
1625
             void            *dat)
1626
{
1627
  struct eth_device *eth = dat;
1628
  eth->base_vapi_id = val.int_val;
1629
}
1630
 
1631 428 julius
 
1632
static void
1633
eth_phy_addr (union param_val  val,
1634
              void            *dat)
1635
{
1636
  struct eth_device *eth = dat;
1637
  eth->phy_addr = val.int_val & ETH_MIIADDR_FIAD_MASK;
1638
}
1639
 
1640
 
1641 19 jeremybenn
/*---------------------------------------------------------------------------*/
1642
/*!Initialize a new Ethernet configuration
1643
 
1644
   ALL parameters are set explicitly to default values.                      */
1645
/*---------------------------------------------------------------------------*/
1646
static void *
1647
eth_sec_start (void)
1648
{
1649
  struct eth_device *new = malloc (sizeof (struct eth_device));
1650
 
1651
  if (!new)
1652
    {
1653
      fprintf (stderr, "Peripheral Eth: Run out of memory\n");
1654
      exit (-1);
1655
    }
1656
 
1657
  memset (new, 0, sizeof (struct eth_device));
1658
 
1659
  new->enabled      = 1;
1660
  new->baseaddr     = 0;
1661
  new->dma          = 0;
1662
  new->mac_int      = 0;
1663 437 julius
  new->int_line_stat= 0;
1664 434 jeremybenn
  new->rtx_type     = ETH_RTX_FILE;
1665 19 jeremybenn
  new->rx_channel   = 0;
1666
  new->tx_channel   = 0;
1667 436 julius
  new->rtx_fd       = 0;
1668 19 jeremybenn
  new->rxfile       = strdup ("eth_rx");
1669
  new->txfile       = strdup ("eth_tx");
1670 434 jeremybenn
  new->tap_dev      = strdup ("");
1671 19 jeremybenn
  new->base_vapi_id = 0;
1672 428 julius
  new->phy_addr     = 0;
1673 19 jeremybenn
 
1674
  return new;
1675
}
1676
 
1677
static void
1678
eth_sec_end (void *dat)
1679
{
1680
  struct eth_device *eth = dat;
1681
  struct mem_ops ops;
1682
 
1683
  if (!eth->enabled)
1684
    {
1685
      free (eth->rxfile);
1686
      free (eth->txfile);
1687 434 jeremybenn
      free (eth->tap_dev);
1688 19 jeremybenn
      free (eth);
1689
      return;
1690
    }
1691
 
1692
  memset (&ops, 0, sizeof (struct mem_ops));
1693
 
1694
  ops.readfunc32 = eth_read32;
1695
  ops.writefunc32 = eth_write32;
1696
  ops.read_dat32 = dat;
1697
  ops.write_dat32 = dat;
1698
 
1699
  /* FIXME: Correct delay? */
1700
  ops.delayr = 2;
1701
  ops.delayw = 2;
1702
  reg_mem_area (eth->baseaddr, ETH_ADDR_SPACE, 0, &ops);
1703
  reg_sim_stat (eth_status, dat);
1704
  reg_sim_reset (eth_reset, dat);
1705
}
1706
 
1707
 
1708
/*---------------------------------------------------------------------------*/
1709
/*!Register a new Ethernet configuration                                     */
1710
/*---------------------------------------------------------------------------*/
1711
void
1712
reg_ethernet_sec ()
1713
{
1714
  struct config_section *sec =
1715
    reg_config_sec ("ethernet", eth_sec_start, eth_sec_end);
1716
 
1717 224 jeremybenn
  reg_config_param (sec, "enabled",    PARAMT_INT,  eth_enabled);
1718
  reg_config_param (sec, "baseaddr",   PARAMT_ADDR, eth_baseaddr);
1719
  reg_config_param (sec, "dma",        PARAMT_INT,  eth_dma);
1720
  reg_config_param (sec, "irq",        PARAMT_INT,  eth_irq);
1721 434 jeremybenn
  reg_config_param (sec, "rtx_type",   PARAMT_STR,  eth_rtx_type);
1722 224 jeremybenn
  reg_config_param (sec, "rx_channel", PARAMT_INT,  eth_rx_channel);
1723
  reg_config_param (sec, "tx_channel", PARAMT_INT,  eth_tx_channel);
1724
  reg_config_param (sec, "rxfile",     PARAMT_STR,  eth_rxfile);
1725
  reg_config_param (sec, "txfile",     PARAMT_STR,  eth_txfile);
1726 434 jeremybenn
  reg_config_param (sec, "tap_dev",    PARAMT_STR,  eth_tap_dev);
1727 224 jeremybenn
  reg_config_param (sec, "vapi_id",    PARAMT_INT,  eth_vapi_id);
1728 428 julius
  reg_config_param (sec, "phy_addr",   PARAMT_INT,  eth_phy_addr);
1729 19 jeremybenn
 
1730
}       /* reg_ethernet_sec() */
1731
 

powered by: WebSVN 2.1.0

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