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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [bootloaders/] [orpmon/] [drivers/] [eth.c] - Blame information for rev 419

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

Line No. Rev Author Line
1 2 marcus.erl
#include "board.h"
2
#if OC_LAN==1
3
 
4
#include "common.h"
5
#include "support.h"
6
#include "uart.h"
7
#include "eth.h"
8
#include "int.h"
9 246 julius
#include "spr-defs.h"
10 2 marcus.erl
 
11 140 julius
//#define PRINT_PACKETS
12
//#define ETHPHY_10MBPS
13 405 julius
//#define ETHPHY_RESET_ON_INIT
14 140 julius
 
15 2 marcus.erl
extern int printf (const char *fmt, ...);
16
extern void lolev_ie(void);
17
extern void lolev_idis(void);
18
 
19
int tx_next;  /* Next buffer to be given to the user */
20
int tx_last;  /* Next buffer to be checked if packet sent */
21
int tx_full;
22
int rx_next;  /* Next buffer to be checked for new packet and given to the user */
23
void (*receive)(volatile unsigned char *add, int len); /* Pointer to function to be called
24
                                        when frame is received */
25 140 julius
int eth_monitor_enabled;
26 2 marcus.erl
 
27 140 julius
//unsigned long eth_data[((ETH_TXBD_NUM + ETH_RXBD_NUM) * ETH_MAXBUF_LEN)/4] = {0};
28
//#undef ETH_DATA_BASE
29
//#define ETH_DATA_BASE ((unsigned long)eth_data)
30 2 marcus.erl
 
31 140 julius
 
32 2 marcus.erl
static void
33
print_packet(unsigned long add, int len)
34
{
35 405 julius
  int truncate = (len > 256);
36
  int length_to_print = truncate ? 256 : len;
37
 
38 2 marcus.erl
  int i;
39 405 julius
  printf("\nipacket: add = %lx len = %d\n", add, len);
40
  for(i = 0; i < length_to_print; i++) {
41
    if(!(i % 8))
42
      printf(" ");
43
    if(!(i % 16))
44
      printf("\n");
45
    printf(" %.2x", *(((unsigned char *)add) + i));
46
 
47
  }
48
  printf("\n");
49
 
50
  if (truncate)
51
    printf("\ttruncated....\n");
52
  /*
53
  int i;
54 2 marcus.erl
  printf("ipacket: add = %lx len = %d\n", add, len);
55
  for(i = 0; i < len; i++) {
56 140 julius
      if(!(i % 16)) printf("\n");
57
      else if(!(i % 8)) printf(" "); // space here, so output is like wireshark
58 2 marcus.erl
      printf(" %.2x", *(((unsigned char *)add) + i));
59
  }
60
  printf("\n");
61 405 julius
  */
62 2 marcus.erl
}
63
 
64
void init_tx_bd_pool(void)
65
{
66
  eth_bd  *bd;
67
  int i;
68
 
69
  bd = (eth_bd *)ETH_BD_BASE;
70
 
71
  for(i = 0; i < ETH_TXBD_NUM; i++) {
72
    /* Set Tx BD status */
73
    bd[i].len_status = 0 << 16 | ETH_TX_BD_PAD | ETH_TX_BD_CRC | ETH_RX_BD_IRQ;
74
 
75
    /* Initialize Tx buffer pointer */
76
    bd[i].addr = ETH_DATA_BASE + (i * ETH_MAXBUF_LEN);
77
  }
78
 
79
  bd[i-1].len_status |= ETH_TX_BD_WRAP; // Last Tx BD - Wrap
80
}
81
 
82
void init_rx_bd_pool(void)
83
{
84
  eth_bd  *bd;
85
  int i;
86
 
87
  bd = (eth_bd *)ETH_BD_BASE + ETH_TXBD_NUM;
88
 
89
  for(i = 0; i < ETH_RXBD_NUM; i++){
90
 
91
    /* Set Rx BD status */
92
    bd[i].len_status = 0 << 16 | ETH_RX_BD_EMPTY | ETH_RX_BD_IRQ;
93
 
94
    /* Initialize Rx buffer pointer */
95
    bd[i].addr = ETH_DATA_BASE + ((ETH_TXBD_NUM + i) * ETH_MAXBUF_LEN);
96
  }
97
 
98
  bd[i-1].len_status |= ETH_RX_BD_WRAP; // Last Rx BD - Wrap
99
}
100
 
101 140 julius
 
102
void eth_traffic_monitor(void)
103
{
104
 volatile oeth_regs *regs;
105
  regs = (oeth_regs *)(ETH_REG_BASE);
106
 
107
  uint  int_events;
108
  int serviced;
109
  int i;
110
 
111
  serviced = 0;
112
 
113
  /* Get the interrupt events that caused us to be here.
114
   */
115
  int_events = regs->int_src;
116
  regs->int_src = int_events;
117
 
118
  printf("\n=tx_ | %x | %x | %x | %x | %x | %x | %x | %x\n",
119
         ((oeth_bd *)(ETH_BD_BASE))->len_status,
120
         ((oeth_bd *)(ETH_BD_BASE+8))->len_status,
121
         ((oeth_bd *)(ETH_BD_BASE+16))->len_status,
122
         ((oeth_bd *)(ETH_BD_BASE+24))->len_status,
123
         ((oeth_bd *)(ETH_BD_BASE+32))->len_status,
124
         ((oeth_bd *)(ETH_BD_BASE+40))->len_status,
125
         ((oeth_bd *)(ETH_BD_BASE+48))->len_status,
126
         ((oeth_bd *)(ETH_BD_BASE+56))->len_status);
127
 
128
  printf("=rx_ | %x | %x | %x | %x | %x | %x | %x | %x\n",
129
         ((oeth_bd *)(ETH_BD_BASE+64))->len_status,
130
         ((oeth_bd *)(ETH_BD_BASE+64+8))->len_status,
131
         ((oeth_bd *)(ETH_BD_BASE+64+16))->len_status,
132
         ((oeth_bd *)(ETH_BD_BASE+64+24))->len_status,
133
         ((oeth_bd *)(ETH_BD_BASE+64+32))->len_status,
134
         ((oeth_bd *)(ETH_BD_BASE+64+40))->len_status,
135
         ((oeth_bd *)(ETH_BD_BASE+64+48))->len_status,
136
         ((oeth_bd *)(ETH_BD_BASE+64+56))->len_status);
137
 
138
  printf("=int | txb %d | txe %d | rxb %d | rxe %d | busy %d\n",
139
         (int_events & ETH_INT_TXB) > 0,
140
         (int_events & ETH_INT_TXE) > 0,
141
         (int_events & ETH_INT_RXF) > 0,
142
         (int_events & ETH_INT_RXE) > 0,
143
         (int_events & ETH_INT_BUSY) > 0);
144
 
145
 
146
  /* Check for receive busy, i.e. packets coming but no place to
147
   * put them.
148
   */
149
  if (int_events & ETH_INT_BUSY ) {
150
    serviced |= 0x4;
151
    printf("eth: busy!");
152
  }
153
 
154
  /* Handle receive event
155
   */
156
  if (int_events & (ETH_INT_RXF | ETH_INT_RXE)) {
157
    serviced |= 0x1;
158
    volatile oeth_bd *rx_bdp;
159
    rx_bdp = ((oeth_bd *)ETH_BD_BASE) + ETH_TXBD_NUM;
160
    /* Find RX buffers marked as having received data */
161
    for(i = 0; i < ETH_RXBD_NUM; i++)
162
      {
163
        if(!(rx_bdp[i].len_status & ETH_RX_BD_EMPTY))
164
          {
165
            print_packet(rx_bdp[i].addr, rx_bdp[i].len_status >> 16);
166
            rx_bdp[i].len_status &= ~ETH_RX_BD_STATS;  /* Clear stats */
167
            rx_bdp[i].len_status |= ETH_RX_BD_EMPTY; /* Mark RX BD as empty */
168
          }
169
      }
170
  }
171
 
172
  /* Handle transmit event
173
   */
174
  if (int_events & (ETH_INT_TXB | ETH_INT_TXE)) {
175
    serviced |= 0x2;
176
    volatile oeth_bd *tx_bd;
177
    tx_bd = (volatile oeth_bd *)ETH_BD_BASE; /* Search from beginning*/
178
    for(i = 0; i < ETH_TXBD_NUM; i++)
179
      {
180
        /* Looking for buffer NOT ready for transmit */
181
        if((!(tx_bd[i].len_status & (ETH_TX_BD_READY))) &&
182
           (tx_bd[i].len_status & (ETH_TX_BD_IRQ)))
183
          {
184
            print_packet(tx_bd[i].addr, (tx_bd[i].len_status >> 16));
185
            tx_bd[i].len_status &= ~ETH_TX_BD_IRQ;
186
          }
187
      }
188
 
189
  }
190
 
191
  if (serviced == 0)
192
    printf("\neth interrupt called but nothing serviced\n");
193
 
194
}
195
 
196
 
197 2 marcus.erl
/* Ethernet interrupt handler */
198
void eth_int (void)
199
{
200 140 julius
  printf("eth-int!\n");
201
  if (eth_monitor_enabled)
202
    eth_traffic_monitor();
203
  //REG32(ETH_REG_BASE + ETH_INT) = 0xffffffff;
204
 
205 2 marcus.erl
}
206
 
207 140 julius
void eth_reset_phy(void)
208
{
209
  /* Reset Eth PHY via MDIO*/
210
  printf("Resetting PHY, waiting for link");
211
  REG32(ETH_REG_BASE + ETH_MIIADDRESS) = (0<<8)|(ETH_MDIOPHYADDR&0xff);
212
  REG32(ETH_REG_BASE + ETH_MIITX_DATA) = 0x8000; // Bit 15 = 1: RESET
213
  REG32(ETH_REG_BASE + ETH_MIICOMMAND) = ETH_MIICOMMAND_WCTRLDATA;
214
  while(REG32(ETH_REG_BASE + ETH_MIISTATUS) & ETH_MIISTATUS_BUSY);
215
 
216
  sleep(100);
217
 
218
  while(1){
219
    printf(".");
220
    REG32(ETH_REG_BASE + ETH_MIIADDRESS) = (0<<8)|(ETH_MDIOPHYADDR&0xff);
221
    REG32(ETH_REG_BASE + ETH_MIICOMMAND) = ETH_MIICOMMAND_RSTAT;
222
    while(REG32(ETH_REG_BASE + ETH_MIISTATUS) & ETH_MIISTATUS_BUSY);
223
    if(!(REG32(ETH_REG_BASE + ETH_MIIRX_DATA) & 0x8000)) // If reset clear
224
      break;
225
  }
226
}
227
 
228
 
229 2 marcus.erl
void eth_init (void (*rec)(volatile unsigned char *, int))
230
{
231
  /* Reset ethernet core */
232
  REG32(ETH_REG_BASE + ETH_MODER) = ETH_MODER_RST;    /* Reset ON */
233
  REG32(ETH_REG_BASE + ETH_MODER) &= ~ETH_MODER_RST;  /* Reset OFF */
234
 
235 405 julius
#ifdef ETHPHY_RESET_ON_INIT
236
  REG32(ETH_REG_BASE + ETH_MIIADDRESS) = 0<<8; // BMCR reg
237
  REG32(ETH_REG_BASE + ETH_MIITX_DATA) = 0x8000; // RESET bit
238
  REG32(ETH_REG_BASE + ETH_MIICOMMAND) = ETH_MIICOMMAND_WCTRLDATA;
239
  while(REG32(ETH_REG_BASE + ETH_MIISTATUS) & ETH_MIISTATUS_BUSY);
240
 
241
  while(1){
242
    REG32(ETH_REG_BASE + ETH_MIIADDRESS) = 1<<8;
243
    REG32(ETH_REG_BASE + ETH_MIICOMMAND) = ETH_MIICOMMAND_RSTAT;
244
    while(REG32(ETH_REG_BASE + ETH_MIISTATUS) & ETH_MIISTATUS_BUSY);
245
    if(REG32(ETH_REG_BASE + ETH_MIIRX_DATA) & 0x04)
246
      break;
247
  }
248
#endif
249 140 julius
 
250
#ifdef ETHPHY_10MBPS
251 2 marcus.erl
  // Set PHY to 10 Mbps full duplex
252
  REG32(ETH_REG_BASE + ETH_MIIADDRESS) = 0<<8;
253
  REG32(ETH_REG_BASE + ETH_MIITX_DATA) = 0x0100;
254
  REG32(ETH_REG_BASE + ETH_MIICOMMAND) = ETH_MIICOMMAND_WCTRLDATA;
255
  while(REG32(ETH_REG_BASE + ETH_MIISTATUS) & ETH_MIISTATUS_BUSY);
256
 
257
  while(1){
258
    REG32(ETH_REG_BASE + ETH_MIIADDRESS) = 1<<8;
259
    REG32(ETH_REG_BASE + ETH_MIICOMMAND) = ETH_MIICOMMAND_RSTAT;
260
    while(REG32(ETH_REG_BASE + ETH_MIISTATUS) & ETH_MIISTATUS_BUSY);
261
    if(REG32(ETH_REG_BASE + ETH_MIIRX_DATA) & 0x04)
262
      break;
263
  }
264 140 julius
 
265
#endif
266 2 marcus.erl
 
267 405 julius
 
268
  /* Setting TX BD number */
269
  REG32(ETH_REG_BASE + ETH_TX_BD_NUM) = ETH_TXBD_NUM;
270
 
271 2 marcus.erl
  /* Set min/max packet length */
272
  REG32(ETH_REG_BASE + ETH_PACKETLEN) = 0x00400600;
273
 
274
  /* Set IPGT register to recomended value */
275
  REG32(ETH_REG_BASE + ETH_IPGT) =  0x00000012;
276
 
277
  /* Set IPGR1 register to recomended value */
278
  REG32(ETH_REG_BASE + ETH_IPGR1) =  0x0000000c;
279
 
280
  /* Set IPGR2 register to recomended value */
281
  REG32(ETH_REG_BASE + ETH_IPGR2) =  0x00000012;
282
 
283
  /* Set COLLCONF register to recomended value */
284
  REG32(ETH_REG_BASE + ETH_COLLCONF) =  0x000f003f;
285
 
286
#if 0
287 140 julius
  REG32(ETH_REG_BASE + ETH_CTRLMODER) = ETH_CTRLMODER_TXFLOW | ETH_CTRLMODER_RXFLOW;
288 2 marcus.erl
#else
289
  REG32(ETH_REG_BASE + ETH_CTRLMODER) = 0;
290
#endif
291
 
292
  /* Initialize RX and TX buffer descriptors */
293
  init_rx_bd_pool();
294
  init_tx_bd_pool();
295
 
296
  /* Initialize tx pointers */
297
  tx_next = 0;
298
  tx_last = 0;
299
  tx_full = 0;
300
 
301
  /* Initialize rx pointers */
302
  rx_next = 0;
303 405 julius
 
304
  /* Assign receive function pointer to what we were passed */
305 2 marcus.erl
  receive = rec;
306
 
307
  /* Set local MAC address */
308
  REG32(ETH_REG_BASE + ETH_MAC_ADDR1) = ETH_MACADDR0 << 8 |
309
            ETH_MACADDR1;
310
  REG32(ETH_REG_BASE + ETH_MAC_ADDR0) = ETH_MACADDR2 << 24 |
311
            ETH_MACADDR3 << 16 |
312
            ETH_MACADDR4 << 8 |
313
            ETH_MACADDR5;
314
 
315
  /* Clear all pending interrupts */
316
  REG32(ETH_REG_BASE + ETH_INT) = 0xffffffff;
317
 
318 405 julius
  /* Register interrupt handler */
319
  int_add (ETH_IRQ, eth_int);
320
 
321 2 marcus.erl
  /* Promisc, IFG, CRCEn */
322
  REG32(ETH_REG_BASE + ETH_MODER) |= ETH_MODER_PAD | ETH_MODER_IFG | ETH_MODER_CRCEN;
323
 
324
  /* Enable interrupt sources */
325
#if 0
326 140 julius
  REG32(ETH_REG_BASE + ETH_INT_MASK)= ETH_INT_MASK_TXB        |
327 2 marcus.erl
                   ETH_INT_MASK_TXE        |
328
                   ETH_INT_MASK_RXF        |
329
                   ETH_INT_MASK_RXE        |
330
                   ETH_INT_MASK_BUSY       |
331
                   ETH_INT_MASK_TXC        |
332
                   ETH_INT_MASK_RXC;
333 140 julius
  eth_monitor_enabled = 1;
334 2 marcus.erl
#else
335
  REG32(ETH_REG_BASE + ETH_INT_MASK) = 0x00000000;
336 140 julius
  printf("eth_init: monitor disabled at startup\n");
337
  eth_monitor_enabled = 0;
338 2 marcus.erl
#endif
339
 
340
  /* Enable receiver and transmiter */
341
  REG32(ETH_REG_BASE + ETH_MODER) |= ETH_MODER_RXEN | ETH_MODER_TXEN;
342
 
343
}
344
 
345
/* Returns pointer to next free buffer; NULL if none available */
346
void *eth_get_tx_buf ()
347
{
348
  eth_bd  *bd;
349
  unsigned long add;
350
 
351
  if(tx_full)
352
    return (void *)0;
353
 
354
  bd = (eth_bd *)ETH_BD_BASE;
355
 
356
  if(bd[tx_next].len_status & ETH_TX_BD_READY)
357
    return (void *)0;
358
 
359
  add = bd[tx_next].addr;
360
 
361 405 julius
  tx_next++;
362 2 marcus.erl
 
363 405 julius
  if (tx_next == ETH_TXBD_NUM)
364
    tx_next = 0;
365 2 marcus.erl
 
366 405 julius
  // Disabled for now - highly unlikely we'll ever run out of TX buffer spots
367
  //if(tx_next == tx_last)
368
  //tx_full = 1;
369
 
370 2 marcus.erl
  return (void *)add;
371
}
372
 
373
/* Send a packet at address */
374
void eth_send (void *buf, unsigned long len)
375
{
376 140 julius
    eth_bd  *bd;
377 246 julius
    int i;
378 2 marcus.erl
 
379 140 julius
#ifdef PRINT_PACKETS  
380 405 julius
    printf("transmitted packet txbd %d:\t", tx_last);
381 140 julius
  print_packet(buf, len);
382
#endif
383
 
384 2 marcus.erl
  bd = (eth_bd *)ETH_BD_BASE;
385
 
386
  bd[tx_last].addr = (unsigned long)buf;
387 246 julius
 
388 140 julius
 retry_eth_send:
389 2 marcus.erl
  bd[tx_last].len_status &= 0x0000ffff & ~ETH_TX_BD_STATS;
390 406 julius
 
391 140 julius
  if (eth_monitor_enabled) // enable IRQ when sending
392
    bd[tx_last].len_status |= ETH_TX_BD_IRQ;
393 406 julius
 
394 2 marcus.erl
  bd[tx_last].len_status |= len << 16 | ETH_TX_BD_READY;
395
 
396 406 julius
  if (!eth_monitor_enabled) // If we're not running the network sniffer...
397 140 julius
    {
398 406 julius
      while (bd[tx_last].len_status & ETH_TX_BD_READY);
399
 
400
      //printf("packet tx\n");
401
      // Check it was sent OK 
402
      /*
403
        BUG with current implementation - constantly getting carrier sense
404
        lost, and deferred indication, so ignore it for now.
405
      if ( bd[tx_last].len_status & 0xf)
406
        {
407
          printf("eth_send: carrier sense lost (txbd: 0x%x), deferred, retrying\n",
408
                 bd[tx_last].len_status);
409
          sleep(1);
410
          goto retry_eth_send;
411
        }
412
      */
413 140 julius
    }
414 406 julius
 
415 405 julius
  tx_last++;
416
 
417
  if (tx_last == ETH_TXBD_NUM)
418
    tx_last = 0;
419
 
420 2 marcus.erl
  tx_full = 0;
421 140 julius
 
422 2 marcus.erl
}
423
 
424
/* Waits for packet and pass it to the upper layers */
425 405 julius
unsigned long
426
eth_rx (void)
427 2 marcus.erl
{
428
  eth_bd  *bd;
429
  unsigned long len = 0;
430 246 julius
  int i;
431 2 marcus.erl
 
432
  bd = (eth_bd *)ETH_BD_BASE + ETH_TXBD_NUM;
433 140 julius
 
434 2 marcus.erl
  while(1) {
435
 
436
    int bad = 0;
437
 
438
    if(bd[rx_next].len_status & ETH_RX_BD_EMPTY)
439
      return len;
440 246 julius
 
441 2 marcus.erl
    if(bd[rx_next].len_status & ETH_RX_BD_OVERRUN) {
442
      printf("eth rx: ETH_RX_BD_OVERRUN\n");
443
      bad = 1;
444
    }
445
    if(bd[rx_next].len_status & ETH_RX_BD_INVSIMB) {
446
      printf("eth rx: ETH_RX_BD_INVSIMB\n");
447
      bad = 1;
448
    }
449
    if(bd[rx_next].len_status & ETH_RX_BD_DRIBBLE) {
450
      printf("eth rx: ETH_RX_BD_DRIBBLE\n");
451
      bad = 1;
452
    }
453
    if(bd[rx_next].len_status & ETH_RX_BD_TOOLONG) {
454
      printf("eth rx: ETH_RX_BD_TOOLONG\n");
455
      bad = 1;
456
    }
457
    if(bd[rx_next].len_status & ETH_RX_BD_SHORT) {
458
      printf("eth rx: ETH_RX_BD_SHORT\n");
459
      bad = 1;
460
    }
461
    if(bd[rx_next].len_status & ETH_RX_BD_CRCERR) {
462
      printf("eth rx: ETH_RX_BD_CRCERR\n");
463
      bad = 1;
464
    }
465
    if(bd[rx_next].len_status & ETH_RX_BD_LATECOL) {
466
      printf("eth rx: ETH_RX_BD_LATECOL\n");
467
      bad = 1;
468
    }
469
 
470
    if(!bad) {
471 140 julius
#ifdef PRINT_PACKETS
472 405 julius
      printf("received packet: rxbd %d\t",rx_next);
473 140 julius
      print_packet(bd[rx_next].addr, bd[rx_next].len_status >> 16);
474
#endif
475 246 julius
 
476 2 marcus.erl
      receive((void *)bd[rx_next].addr, bd[rx_next].len_status >> 16);
477
      len += bd[rx_next].len_status >> 16;
478
    }
479
 
480
    bd[rx_next].len_status &= ~ETH_RX_BD_STATS;
481
    bd[rx_next].len_status |= ETH_RX_BD_EMPTY;
482
 
483 405 julius
    rx_next++;
484
 
485
    if (rx_next == ETH_RXBD_NUM)
486
      rx_next = 0;
487 2 marcus.erl
  }
488
}
489
 
490
void eth_int_enable(void)
491
{
492
  REG32(ETH_REG_BASE + ETH_INT_MASK) =  ETH_INT_MASK_TXB        |
493
                                        ETH_INT_MASK_TXE        |
494
                                        ETH_INT_MASK_RXF        |
495
                                        ETH_INT_MASK_RXE        |
496
                                        ETH_INT_MASK_BUSY       |
497
                                        ETH_INT_MASK_TXC        |
498
                                        ETH_INT_MASK_RXC;
499
}
500
 
501 140 julius
void eth_int_disable(void)
502
{
503
  REG32(ETH_REG_BASE + ETH_INT_MASK) = 0;
504
}
505
 
506 2 marcus.erl
void eth_halt(void)
507
{
508 140 julius
  /* Disable receiver and transmiter */
509 2 marcus.erl
  REG32(ETH_REG_BASE + ETH_MODER) &= ~(ETH_MODER_RXEN | ETH_MODER_TXEN);
510
}
511 140 julius
 
512
 
513
void eth_toggle_traffic_mon(void)
514
{
515
  if (!eth_monitor_enabled)
516
    {
517
      printf("eth_toggle_traffic_mon: traffic monitor ENABLED\n");
518
      printf("eth_toggle_traffic_mon: Warning - do not enable during tftp boot!\n");
519
      eth_monitor_enabled = 1;
520
      eth_int_enable();
521
    }
522
  else
523
    {
524
      eth_int_disable();
525
      eth_monitor_enabled = 0;
526
      printf("eth_toggle_traffic_mon: traffic monitor DISABLED\n");
527
 
528
 
529
    }
530
 
531
}
532 2 marcus.erl
#endif

powered by: WebSVN 2.1.0

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