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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [orpsocv2/] [sw/] [tests/] [ethmac/] [sim/] [ethmac-rx.c] - Blame information for rev 409

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

Line No. Rev Author Line
1 349 julius
//////////////////////////////////////////////////////////////////////
2
////                                                              ////
3
////  Interrupt-driven Ethernet MAC test code                     ////
4
////                                                              ////
5
////  Description                                                 ////
6
////  Do ethernet receive path testing                            ////
7
////  Relies on testbench to provide simulus - expects at least   ////
8
////  256 packets to be sent.                                     ////
9
////                                                              ////
10
////  Author(s):                                                  ////
11
////      - jb, jb@orsoc.se, with parts taken from Linux kernel   ////
12
////        open_eth driver.                                      ////
13
////                                                              ////
14
////                                                              ////
15
//////////////////////////////////////////////////////////////////////
16
////                                                              ////
17
//// Copyright (C) 2009 Authors and OPENCORES.ORG                 ////
18
////                                                              ////
19
//// This source file may be used and distributed without         ////
20
//// restriction provided that this copyright statement is not    ////
21
//// removed from the file and that any derivative work contains  ////
22
//// the original copyright notice and the associated disclaimer. ////
23
////                                                              ////
24
//// This source file is free software; you can redistribute it   ////
25
//// and/or modify it under the terms of the GNU Lesser General   ////
26
//// Public License as published by the Free Software Foundation; ////
27
//// either version 2.1 of the License, or (at your option) any   ////
28
//// later version.                                               ////
29
////                                                              ////
30
//// This source is distributed in the hope that it will be       ////
31
//// useful, but WITHOUT ANY WARRANTY; without even the implied   ////
32
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      ////
33
//// PURPOSE.  See the GNU Lesser General Public License for more ////
34
//// details.                                                     ////
35
////                                                              ////
36
//// You should have received a copy of the GNU Lesser General    ////
37
//// Public License along with this source; if not, download it   ////
38
//// from http://www.opencores.org/lgpl.shtml                     ////
39
////                                                              ////
40
//////////////////////////////////////////////////////////////////////
41
 
42 409 julius
#include "cpu-utils.h"
43
//#include "spr-defs.h"
44 349 julius
#include "board.h"
45
#include "int.h"
46
#include "uart.h"
47 409 julius
#include "ethmac.h"
48 349 julius
#include "printf.h"
49
#include "eth-phy-mii.h"
50
 
51
volatile unsigned tx_done;
52
volatile unsigned rx_done;
53
 
54
/* Functions in this file */
55
void ethmac_setup(void);
56
void ethphy_init(void);
57
void oeth_dump_bds();
58
/* Interrupt functions */
59
void oeth_interrupt(void);
60
static void oeth_rx(void);
61
static void oeth_tx(void);
62
 
63
/* Defining RTLSIM turns off use of real printf'ing to save time in simulation */
64
#define RTLSIM
65
 
66
#ifdef RTLSIM
67
#define printk
68
#else
69
#define printk printf
70
#endif
71
/* Let the ethernet packets use a space beginning here for buffering */
72
#define ETH_BUFF_BASE 0x01000000
73
 
74
 
75
#define RXBUFF_PREALLOC 1
76
#define TXBUFF_PREALLOC 1
77
//#undef RXBUFF_PREALLOC
78
//#undef TXBUFF_PREALLOC
79
 
80
/* The transmitter timeout
81
 */
82
#define TX_TIMEOUT      (2*HZ)
83
 
84
/* Buffer number (must be 2^n)
85
 */
86
#define OETH_RXBD_NUM           16
87
#define OETH_TXBD_NUM           16
88
#define OETH_RXBD_NUM_MASK      (OETH_RXBD_NUM-1)
89
#define OETH_TXBD_NUM_MASK      (OETH_TXBD_NUM-1)
90
 
91
/* Buffer size
92
 */
93
#define OETH_RX_BUFF_SIZE       0x600
94
#define OETH_TX_BUFF_SIZE       0x600
95
 
96
/* Buffer size  (if not XXBUF_PREALLOC
97
 */
98
#define MAX_FRAME_SIZE          1518
99
 
100
/* The buffer descriptors track the ring buffers.
101
 */
102
struct oeth_private {
103
  //struct      sk_buff* rx_skbuff[OETH_RXBD_NUM];
104
  //struct      sk_buff* tx_skbuff[OETH_TXBD_NUM];
105
 
106
  unsigned short        tx_next;                        /* Next buffer to be sent */
107
  unsigned short        tx_last;                        /* Next buffer to be checked if packet sent */
108
  unsigned short        tx_full;                        /* Buffer ring fuul indicator */
109
  unsigned short        rx_cur;                         /* Next buffer to be checked if packet received */
110
 
111
  oeth_regs     *regs;                  /* Address of controller registers. */
112
  oeth_bd               *rx_bd_base;            /* Address of Rx BDs. */
113
  oeth_bd               *tx_bd_base;            /* Address of Tx BDs. */
114
 
115
  //    struct net_device_stats stats;
116
};
117
 
118
 
119
#define PHYNUM 7
120
 
121
/* Scan the MIIM bus for PHYs */
122
void scan_ethphys(void)
123
{
124
  unsigned int phynum,regnum, i;
125
 
126
  volatile oeth_regs *regs;
127
  regs = (oeth_regs *)(OETH_REG_BASE);
128
 
129
  regs->miitx_data = 0;
130
 
131
  for(phynum=0;phynum<32;phynum++)
132
    {
133
      for (regnum=0;regnum<8;regnum++)
134
        {
135
          printk("scan_ethphys: phy %d r%d ",phynum, regnum);
136
 
137
          /* Now actually perform the read on the MIIM bus*/
138
          regs->miiaddress = (regnum << 8) | phynum; /* Basic Control Register */
139
          regs->miicommand = OETH_MIICOMMAND_RSTAT;
140
 
141
          while(!(regs->miistatus & OETH_MIISTATUS_BUSY)); /* Wait for command to be registered*/
142
 
143
          regs->miicommand = 0;
144
 
145
          while(regs->miistatus & OETH_MIISTATUS_BUSY);
146
 
147
          printk("%x\n",regs->miirx_data);
148
        }
149
    }
150
}
151
 
152
 
153
 
154
void ethmac_scanstatus(void)
155
{
156
  volatile oeth_regs *regs;
157
  regs = (oeth_regs *)(OETH_REG_BASE);
158
 
159
 
160
  printk("Oeth: regs->miistatus %x regs->miirx_data %x\n",regs->miistatus, regs->miirx_data);
161
  regs->miiaddress = 0;
162
  regs->miitx_data = 0;
163
  regs->miicommand = OETH_MIICOMMAND_SCANSTAT;
164
  printk("Oeth: regs->miiaddress %x regs->miicommand %x\n",regs->miiaddress, regs->miicommand);
165
  //regs->miicommand = 0; 
166
  volatile int i; for(i=0;i<1000;i++);
167
   while(regs->miistatus & OETH_MIISTATUS_BUSY) ;
168
   //spin_cursor(); 
169
   //printk("\r"); 
170
   //or32_exit(0);
171
}
172
 
173
void
174
eth_mii_write(char phynum, short regnum, short data)
175
{
176
  static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE);
177
  regs->miiaddress = (regnum << 8) | phynum;
178
  regs->miitx_data = data;
179
  regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;
180
  regs->miicommand = 0;
181
  while(regs->miistatus & OETH_MIISTATUS_BUSY);
182
}
183
 
184
short
185
eth_mii_read(char phynum, short regnum)
186
{
187
  static volatile oeth_regs *regs = (oeth_regs *)(OETH_REG_BASE);
188
  regs->miiaddress = (regnum << 8) | phynum;
189
  regs->miicommand = OETH_MIICOMMAND_RSTAT;
190
  regs->miicommand = 0;
191
  while(regs->miistatus & OETH_MIISTATUS_BUSY);
192
 
193
  return regs->miirx_data;
194
}
195
 
196
void ethphy_init(void)
197
{
198
 
199
  /* Init the Alaska 88E1111 Phy */
200
  char alaska88e1111_ml501_phynum = 0x7;
201
 
202
  /* Init, reset */
203
  short ctl = eth_mii_read(alaska88e1111_ml501_phynum, MII_BMCR);
204
  ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
205
  ctl |= BMCR_SPEED100; // 100MBit
206
  ctl |= BMCR_FULLDPLX; // Full duplex
207
  eth_mii_write(alaska88e1111_ml501_phynum, MII_BMCR, ctl);
208
 
209
  // Setup Autoneg
210
  short adv = eth_mii_read(alaska88e1111_ml501_phynum, MII_ADVERTISE);
211
  adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_1000XFULL
212
           |ADVERTISE_1000XHALF | ADVERTISE_1000XPAUSE |
213
           ADVERTISE_1000XPSE_ASYM);
214
  adv |= ADVERTISE_10HALF;
215
  adv |= ADVERTISE_10FULL;
216
  adv |= ADVERTISE_100HALF;
217
  adv |= ADVERTISE_100FULL;
218
  eth_mii_write(alaska88e1111_ml501_phynum, MII_ADVERTISE, adv);
219
  // Disable gigabit???
220
  adv = eth_mii_read(alaska88e1111_ml501_phynum, MII_M1011_PHY_SPEC_CONTROL);
221
  adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
222
           MII_1000BASETCONTROL_HALFDUPLEXCAP);
223
  eth_mii_write(alaska88e1111_ml501_phynum, MII_M1011_PHY_SPEC_CONTROL, adv);
224
  // Even more disable gigabit?!
225
  adv = eth_mii_read(alaska88e1111_ml501_phynum, MII_CTRL1000);
226
  adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
227
  eth_mii_write(alaska88e1111_ml501_phynum, MII_CTRL1000, adv);
228
 
229
  // Restart autoneg
230
  printk("Resetting phy...\n");
231
  ctl = eth_mii_read(alaska88e1111_ml501_phynum, MII_BMCR);
232
  ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
233
  eth_mii_write(alaska88e1111_ml501_phynum, MII_BMCR, ctl);
234
 
235
 
236
}
237
 
238
 
239
void ethmac_setup(void)
240
{
241
  // from arch/or32/drivers/open_eth.c
242
  volatile oeth_regs *regs;
243
 
244
  regs = (oeth_regs *)(OETH_REG_BASE);
245
 
246
  /* Reset MII mode module */
247
  regs->miimoder = OETH_MIIMODER_RST; /* MII Reset ON */
248
  regs->miimoder &= ~OETH_MIIMODER_RST; /* MII Reset OFF */
249
  regs->miimoder = 0x64; /* Clock divider for MII Management interface */
250
 
251
  /* Reset the controller.
252
   */
253
  regs->moder = OETH_MODER_RST; /* Reset ON */
254
  regs->moder &= ~OETH_MODER_RST;       /* Reset OFF */
255
 
256
  /* Setting TXBD base to OETH_TXBD_NUM.
257
   */
258
  regs->tx_bd_num = OETH_TXBD_NUM;
259
 
260
 
261
  /* Set min/max packet length
262
   */
263
  regs->packet_len = 0x00400600;
264
 
265
  /* Set IPGT register to recomended value
266
   */
267
  regs->ipgt = 0x12;
268
 
269
  /* Set IPGR1 register to recomended value
270
   */
271
  regs->ipgr1 = 0x0000000c;
272
 
273
  /* Set IPGR2 register to recomended value
274
   */
275
  regs->ipgr2 = 0x00000012;
276
 
277
  /* Set COLLCONF register to recomended value
278
   */
279
  regs->collconf = 0x000f003f;
280
 
281
  /* Set control module mode
282
   */
283
#if 0
284
  regs->ctrlmoder = OETH_CTRLMODER_TXFLOW | OETH_CTRLMODER_RXFLOW;
285
#else
286
  regs->ctrlmoder = 0;
287
#endif
288
 
289
  /* Clear MIIM registers */
290
  regs->miitx_data = 0;
291
  regs->miiaddress = 0;
292
  regs->miicommand = 0;
293
 
294
  regs->mac_addr1 = ETH_MACADDR0 << 8 | ETH_MACADDR1;
295
  regs->mac_addr0 = ETH_MACADDR2 << 24 | ETH_MACADDR3 << 16 | ETH_MACADDR4 << 8 | ETH_MACADDR5;
296
 
297
  /* Clear all pending interrupts
298
   */
299
  regs->int_src = 0xffffffff;
300
 
301
  /* Promisc, IFG, CRCEn
302
   */
303
  regs->moder |= OETH_MODER_PRO | OETH_MODER_PAD | OETH_MODER_IFG | OETH_MODER_CRCEN | OETH_MODER_FULLD;
304
 
305
  /* Enable interrupt sources.
306
   */
307
 
308
  regs->int_mask = OETH_INT_MASK_TXB    |
309
    OETH_INT_MASK_TXE   |
310
    OETH_INT_MASK_RXF   |
311
    OETH_INT_MASK_RXE   |
312
    OETH_INT_MASK_BUSY  |
313
    OETH_INT_MASK_TXC   |
314
    OETH_INT_MASK_RXC;
315
 
316
  // Buffer setup stuff
317
  volatile oeth_bd *tx_bd, *rx_bd;
318
  int i,j,k;
319
 
320
  /* Initialize TXBD pointer
321
   */
322
  tx_bd = (volatile oeth_bd *)OETH_BD_BASE;
323
 
324
  /* Initialize RXBD pointer
325
   */
326
  rx_bd = ((volatile oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM;
327
 
328
  /* Preallocated ethernet buffer setup */
329
  unsigned long mem_addr = ETH_BUFF_BASE; /* Defined at top */
330
 
331
  // Setup TX Buffers
332
  for(i = 0; i < OETH_TXBD_NUM; i++) {
333
      //tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC | OETH_RX_BD_IRQ;
334
      tx_bd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC;
335
      tx_bd[i].addr = mem_addr;
336
      mem_addr += OETH_TX_BUFF_SIZE;
337
  }
338
  tx_bd[OETH_TXBD_NUM - 1].len_status |= OETH_TX_BD_WRAP;
339
 
340
  // Setup RX buffers
341
  for(i = 0; i < OETH_RXBD_NUM; i++) {
342
    rx_bd[i].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ; // Init. with IRQ
343
    rx_bd[i].addr = mem_addr;
344
    mem_addr += OETH_RX_BUFF_SIZE;
345
  }
346
  rx_bd[OETH_RXBD_NUM - 1].len_status |= OETH_RX_BD_WRAP; // Last buffer wraps
347
 
348
  /* Enable just the receiver
349
   */
350
  regs->moder &= ~(OETH_MODER_RXEN | OETH_MODER_TXEN);
351
  regs->moder |= OETH_MODER_RXEN /* | OETH_MODER_TXEN*/;
352
 
353
  return;
354
}
355
 
356
 
357
/* The interrupt handler.
358
 */
359
void
360
oeth_interrupt(void)
361
{
362
 
363
  volatile oeth_regs *regs;
364
  regs = (oeth_regs *)(OETH_REG_BASE);
365
 
366
  uint  int_events;
367
  int serviced;
368
 
369
        serviced = 0;
370
 
371
        /* Get the interrupt events that caused us to be here.
372
         */
373
        int_events = regs->int_src;
374
        regs->int_src = int_events;
375
 
376
 
377
        /* Handle receive event in its own function.
378
         */
379
        if (int_events & (OETH_INT_RXF | OETH_INT_RXE)) {
380
                serviced |= 0x1;
381
                oeth_rx();
382
        }
383
 
384
        /* Handle transmit event in its own function.
385
         */
386
        if (int_events & (OETH_INT_TXB | OETH_INT_TXE)) {
387
                serviced |= 0x2;
388
                oeth_tx();
389
                serviced |= 0x2;
390
 
391
        }
392
 
393
        /* Check for receive busy, i.e. packets coming but no place to
394
         * put them.
395
         */
396
        if (int_events & OETH_INT_BUSY) {
397
                serviced |= 0x4;
398
                if (!(int_events & (OETH_INT_RXF | OETH_INT_RXE)))
399
                  oeth_rx();
400
        }
401
 
402
        return;
403
}
404
 
405
 
406
 
407
static void
408
oeth_rx(void)
409
{
410
  volatile oeth_regs *regs;
411
  regs = (oeth_regs *)(OETH_REG_BASE);
412
 
413
  volatile oeth_bd *rx_bdp;
414
  int   pkt_len, i;
415
  int   bad = 0;
416
 
417
  rx_bdp = ((oeth_bd *)OETH_BD_BASE) + OETH_TXBD_NUM;
418
 
419
  printk("r");
420
 
421
  /* Find RX buffers marked as having received data */
422
  for(i = 0; i < OETH_RXBD_NUM; i++)
423
    {
424
      bad=0;
425
      if(!(rx_bdp[i].len_status & OETH_RX_BD_EMPTY)){ /* Looking for NOT empty buffers desc. */
426
        /* Check status for errors.
427
         */
428
        report(i);
429
        report(rx_bdp[i].len_status);
430
        if (rx_bdp[i].len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) {
431
          bad = 1;
432
          report(0xbaad0001);
433
        }
434
        if (rx_bdp[i].len_status & OETH_RX_BD_DRIBBLE) {
435
          bad = 1;
436
          report(0xbaad0002);
437
        }
438
        if (rx_bdp[i].len_status & OETH_RX_BD_CRCERR) {
439
          bad = 1;
440
          report(0xbaad0003);
441
        }
442
        if (rx_bdp[i].len_status & OETH_RX_BD_OVERRUN) {
443
          bad = 1;
444
          report(0xbaad0004);
445
        }
446
        if (rx_bdp[i].len_status & OETH_RX_BD_MISS) {
447
          report(0xbaad0005);
448
        }
449
        if (rx_bdp[i].len_status & OETH_RX_BD_LATECOL) {
450
          bad = 1;
451
          report(0xbaad0006);
452
        }
453
        if (bad) {
454
          rx_bdp[i].len_status &= ~OETH_RX_BD_STATS;
455
          rx_bdp[i].len_status |= OETH_RX_BD_EMPTY;
456
          //exit(0xbaaaaaad);
457
 
458
          continue;
459
        }
460
        else {
461
          /*
462
          Process the incoming frame.
463
           */
464
          pkt_len = rx_bdp[i].len_status >> 16;
465
 
466
          /* finish up */
467
          rx_bdp[i].len_status &= ~OETH_RX_BD_STATS; /* Clear stats */
468
          rx_bdp[i].len_status |= OETH_RX_BD_EMPTY; /* Mark RX BD as empty */
469
          rx_done++;
470
          report(rx_done);
471
        }
472
      }
473
    }
474
}
475
 
476
 
477
 
478
static void
479
oeth_tx(void)
480
{
481
  volatile oeth_bd *tx_bd;
482
  int i;
483
 
484
  tx_bd = (volatile oeth_bd *)OETH_BD_BASE; /* Search from beginning*/
485
 
486
  /* Go through the TX buffs, search for one that was just sent */
487
  for(i = 0; i < OETH_TXBD_NUM; i++)
488
    {
489
      /* Looking for buffer NOT ready for transmit. and IRQ enabled */
490
      if( (!(tx_bd[i].len_status & (OETH_TX_BD_READY))) && (tx_bd[i].len_status & (OETH_TX_BD_IRQ)) )
491
        {
492
          /* Single threaded so no chance we have detected a buffer that has had its IRQ bit set but not its BD_READ flag. Maybe this won't work in linux */
493
          tx_bd[i].len_status &= ~OETH_TX_BD_IRQ;
494
 
495
          /* Probably good to check for TX errors here */
496
 
497
          /* set our test variable */
498
          tx_done = 1;
499
 
500
          printk("T%d",i);
501
 
502
        }
503
    }
504
  return;
505
}
506
 
507
// Loop to check if a number is prime by doing mod divide of the number
508
// to test by every number less than it
509
int
510
is_prime_number(unsigned long n)
511
{
512
  unsigned long c;
513
  if (n < 2) return 0;
514
  for(c=2;c<n;c++)
515
    if ((n % c) == 0)
516
      return 0;
517
  return 1;
518
}
519
 
520
int main ()
521
{
522
 
523
  /* Initialise handler vector */
524
  int_init();
525
 
526
  /* Install ethernet interrupt handler, it is enabled here too */
527
  int_add(ETH0_IRQ, oeth_interrupt, 0);
528
 
529
  /* Enable interrupts in supervisor register */
530 409 julius
  cpu_enable_user_interrupts();
531 349 julius
 
532
  rx_done = 0;
533
 
534
  ethmac_setup(); /* Configure MAC, TX/RX BDs and enable RX in MODER */
535
 
536
#define NUM_PRIMES_TO_CHECK 1000
537
 
538
  char prime_check_results[NUM_PRIMES_TO_CHECK];
539
  unsigned long num_to_check;
540
 
541
      for(num_to_check=2;num_to_check<NUM_PRIMES_TO_CHECK;num_to_check++)
542
        {
543
          prime_check_results[num_to_check-2]
544
            = (char) is_prime_number(num_to_check);
545
          report(num_to_check | (0x1e<<24));
546
          report(prime_check_results[num_to_check-2] | (0x2e<<24));
547
          if (rx_done >= 255) // Check number of packets received, testbench
548
                             // will hopefully send at least 256 packets
549
            exit(0x8000000d);
550
        }
551
      exit(0xbaaaaaad);
552
}

powered by: WebSVN 2.1.0

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