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

Subversion Repositories openrisc

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

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

powered by: WebSVN 2.1.0

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