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

Subversion Repositories fade_ether_protocol

[/] [fade_ether_protocol/] [trunk/] [stable_jumbo_frames_version/] [linux/] [fpga_l3_fade.c] - Blame information for rev 48

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

Line No. Rev Author Line
1 15 wzab
/*
2
 * fpga_l3_fade - driver for L3 communication protocol with FPGA based system
3
 * Copyright (C) 2012 by Wojciech M. Zabolotny
4
 * Institute of Electronic Systems, Warsaw University of Technology
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, write to the Free Software
18
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20
 
21
#include <linux/module.h>
22
#include <linux/kernel.h>
23 48 wzab
#include <linux/version.h>
24 47 wzab
#include <linux/sched.h>
25 15 wzab
#include <asm/uaccess.h>
26
 
27
MODULE_LICENSE("GPL v2");
28
//#define FADE_DEBUG 1
29
#include <linux/device.h>
30
#include <linux/netdevice.h>
31
#include <linux/fs.h>
32
#include <linux/cdev.h>
33
#include <linux/poll.h>
34
#include <linux/mm.h>
35
#include <asm/io.h>
36
#include <linux/wait.h>
37
#include <linux/sched.h>
38
#include <asm/uaccess.h>  /* for put_user */
39
#include <linux/mutex.h>
40
 
41
#include "fpga_l3_fade.h"
42
 
43
#define SUCCESS 0
44
#define DEVICE_NAME "fpga_l3_fade"
45
 
46
 
47
/* Length of the user header in the packet
48
 * The following fields are BEFORE the user header
49
 * SRC+TGT - 12 bytes : source & destination
50
 * 0xFADE - 2 bytes : protocol ID
51
 *
52
 * Fields which belong to the user header:
53
 * 0x0100 - 2 bytes : protocol version - offset 0
54
 * For DATA - to PC
55
 * 0xA5A5 - 2 bytes : data ID 0 - offset 2
56
 * retry number - 2 bytes - offset 4
57
 * packet number - 4 bytes - offset 6
58
 * transm_delay - 4 bytes - offset 10
59
 * cmd_response - 12 bytes - offset 14
60
 *
61
 * Total: 26 bytes!
62 18 wzab
 * If the packet contains "flushed" buffer,
63
 * then data ID is 0xA5A6, and the last word
64
 * contains number of transmitted words.
65 15 wzab
 
66
 * For command response
67
 * 0xA55A : cmd_resp ID 2 bytes - offset 2
68
 * 0x0000 : filler - 2 bytes - offset 4
69
 * cmd_response - 12 bytes offset 6
70
 */
71
#define USER_HDR_LEN 26
72
 
73
/* Number of bytes of user data in a packet */
74
#define LOG2_USER_LEN 13
75
#define USER_LEN (1<<LOG2_USER_LEN) 
76
#define PAYL_LEN ( USER_HDR_LEN + USER_LEN )
77
 
78
/* Number of packets in window - this number depends on amount of RAM
79
 * in the FPGA - Packets in a widnow must fit in the FPGA RAM
80
 * Should be power of two! */
81 18 wzab
#define PKTS_IN_WINDOW (1<<4)
82 15 wzab
#define PKTS_IN_WINDOW_MASK (PKTS_IN_WINDOW-1)
83
 
84
/* Capacity of kernel buffer (mmapped into user space) measured in
85
 * number of windows - should be equal to power of two, to simplify
86
 * the modulo operation (replacing it by binary AND) */
87
#define WINDOWS_IN_BUFFER (1<<8)
88
 
89
#define MY_BUF_LEN (WINDOWS_IN_BUFFER * PKTS_IN_WINDOW * USER_LEN)
90
#define MY_BUF_LEN_MASK (MY_BUF_LEN-1)
91
 
92
 
93
/* Length of the acknowledment packet and command packets */
94
#define MY_ACK_LEN 64
95
 
96
/* Number of bytes to be copied from data packet to ack packet
97
 * It covers: retry_number, packet_number and transm_delay - 10 bytes
98
 */
99
#define MY_ACK_COPIED 10
100
 
101
/* The Ethernet type of our packet. This is NOT OFFICIALLY REGISTERED type,
102
 * however our protocol is:
103
 * 1. experimental,
104
 * 2. supposed to be used only in private networks
105
 */
106
#define MY_PROTO_ID 0xfade
107
#define MY_PROTO_VER 0x0100
108
 
109
static int max_slaves = 4;
110
module_param(max_slaves,int,0);
111
MODULE_PARM_DESC(max_slaves,"Maximum number of slave FPGA devices serviced by the system.");
112
 
113
static int proto_registered = 0; //Was the protocol registred? Should be deregistered at exit?
114
 
115
DEFINE_RWLOCK(slave_table_lock); //Used to protect table of slaves
116
 
117
/* Structure used to store offset of two currently serviced sets in the data buffer */
118
struct pkt_map {
119
  int num;
120
  int offset;
121
};
122
 
123
typedef struct
124
{
125
  // fields related to the circular buffer
126
  volatile int head;
127
  volatile int tail;
128
  rwlock_t ptrs_lock; //Used to protect the head and tail pointers
129
 
130
  unsigned char * buffer;
131
  struct mutex usercmd_lock;
132
  uint16_t cmd_code;
133
  uint16_t cmd_seq;
134
  uint8_t cmd_ack;
135
  uint8_t cmd_resp[12];
136
  rwlock_t pkts_rwlock; //Protects the pkts table and last_pkt
137
  uint32_t last_nack_pkt; /* Number of the last not acknowledged packet. This is also the number
138
                             of the first packet in the current transmission window */
139
  uint32_t pkts[PKTS_IN_WINDOW]; /* This array stores numbers of the last received packets in the
140
                                  * transmission window. It is used to avoid unnecessary copying of duplicated
141
                                  * packets into the receiver buffer */
142
  rwlock_t flags_lock; //Protects other fields of the slave_data struct
143 18 wzab
  uint32_t last_pkt_num; /* Number of the last "flushed" packet */
144
  uint32_t last_pkt_len; /* Number of words in the last "flushed" packet */
145 15 wzab
  char err_flag;
146 18 wzab
  char stopped_flag; /* Flag informing, that transmission has been already terminated */
147
  char eof_flag; /* Flag informing, that all packets are delivered after transmission is terminated */
148 15 wzab
  char active;
149
  char is_open;
150
  int rx_wakeup_thr;
151
  unsigned char mac[ETH_ALEN];
152
  struct net_device * dev;
153
} slave_data;
154
 
155 16 wzab
/* Auxiliary inline functions */
156
static inline uint16_t get_be_u16(char * buf)
157
{
158
  return be16_to_cpu(*(uint16_t *)buf);
159
}
160
 
161
static inline uint32_t get_be_u32(char * buf)
162
{
163
  return be32_to_cpu(*(uint32_t *)buf);
164
}
165
 
166
static inline uint64_t get_be_u64(char * buf)
167
{
168
  return be64_to_cpu(*(uint64_t *)buf);
169
}
170
 
171
static inline void put_skb_u16(struct sk_buff * skb, uint16_t val)
172
{
173 18 wzab
  void * data = skb_put(skb,sizeof(val));
174 16 wzab
  * (uint16_t *) data = cpu_to_be16(val);
175
}
176
 
177
static inline void put_skb_u32(struct sk_buff * skb, uint32_t val)
178
{
179 18 wzab
  void * data = skb_put(skb,sizeof(val));
180 16 wzab
  * (uint32_t *) data = cpu_to_be32(val);
181
}
182
 
183
static inline void put_skb_u64(struct sk_buff * skb, uint64_t val)
184
{
185 18 wzab
  void * data = skb_put(skb,sizeof(val));
186 16 wzab
  * (uint64_t *) data = cpu_to_be64(val);
187
}
188
 
189 15 wzab
static slave_data * slave_table = NULL;
190
 
191
static int my_proto_rcv(struct sk_buff * skb, struct net_device * dev, struct packet_type * pt,
192
                        struct net_device * orig_dev);
193
 
194
static struct packet_type my_proto_pt __read_mostly = {
195
  .type = cpu_to_be16(MY_PROTO_ID),
196
  .dev = NULL,
197
  .func = my_proto_rcv,
198
};
199
 
200
// Prototypes of functions defined in module
201
void cleanup_my_proto1( void );
202
int init_my_proto1( void );
203
static int my_proto1_open(struct inode *inode, struct file *file);
204
static int my_proto1_release(struct inode *inode, struct file *file);
205
static long my_proto1_ioctl (struct file *filp,  unsigned int cmd, unsigned long arg);
206
int my_proto1_mmap(struct file *filp, struct vm_area_struct *vma);
207
unsigned int my_proto1_poll(struct file *filp,poll_table *wait);
208
 
209
//Wait queue for user application
210
DECLARE_WAIT_QUEUE_HEAD (read_queue);
211
//Wait queue for user commands
212
DECLARE_WAIT_QUEUE_HEAD (usercmd_queue);
213
dev_t my_dev=0;
214
struct cdev * my_cdev = NULL;
215
static struct class *class_my_proto = NULL;
216
 
217
struct file_operations Fops = {
218
  .owner = THIS_MODULE,
219
  .open=my_proto1_open,
220
  .release=my_proto1_release,  /* a.k.a. close */
221
  .poll = my_proto1_poll,
222
  .unlocked_ioctl=my_proto1_ioctl,
223
  .mmap=my_proto1_mmap
224
};
225
 
226 18 wzab
 
227
/* Function used to send the user command and wait for confirmation */
228
static inline
229
long send_cmd(slave_data * sd, uint16_t cmd, uint32_t arg, void * resp, int nof_retries, int timeout)
230
{
231
  long result = -ETIMEDOUT;
232 19 wzab
  //First check, if the Ethernet device is claimed, otherwise return an error
233
  if(sd->dev==NULL) return -ENODEV;
234 18 wzab
  //Each slave may perform only one user command, so first check, if no other thread
235
  //attempts to send the command
236
  if ( mutex_trylock(&sd->usercmd_lock)==0) return -EBUSY;
237
  //Mutex acquired, we can proceed
238
  //First allocate the sequence number for the command
239
  sd->cmd_seq += 1;
240
  sd->cmd_code = cmd;
241
  sd->cmd_ack = 1; //Mark, that we are waiting for response
242
  //Now in the loop we send the packet, requesting execution of the command
243
  //and then we wait for response with timeout
244
  while(nof_retries--) {
245
    //Send the packet 
246
    struct sk_buff *newskb = NULL;
247
    uint8_t * my_data = NULL;
248
    newskb = alloc_skb(LL_RESERVED_SPACE(sd->dev)+MY_ACK_LEN, GFP_KERNEL);
249
    skb_reserve(newskb,LL_RESERVED_SPACE(sd->dev));
250
    skb_reset_network_header(newskb);
251
    newskb->dev = sd->dev;
252
    newskb->protocol = htons(MY_PROTO_ID);
253
    //Build the MAC header for the new packet
254 29 wzab
    // Here http://lxr.free-electrons.com/source/net/ipv4/arp.c?v=3.17#L608 it is shown how to build a packet!
255 18 wzab
    if (dev_hard_header(newskb,sd->dev,MY_PROTO_ID,&sd->mac,sd->dev->dev_addr,MY_ACK_LEN+ETH_HLEN) < 0)
256
      {
257 29 wzab
        mutex_unlock(&sd->usercmd_lock);
258 18 wzab
        kfree_skb(newskb);
259
        return -EINVAL;
260
      }
261
    //Put the protocol version id to the packet
262
    put_skb_u16(newskb,MY_PROTO_VER);
263
    //Put the command code
264
    put_skb_u16(newskb,cmd);
265
    //Put the sequence number
266
    put_skb_u16(newskb,sd->cmd_seq);
267
    //Put the argument
268
    put_skb_u32(newskb,arg);
269
    //Fill the packet
270
    my_data = skb_put(newskb,MY_ACK_LEN-10);
271
    memset(my_data,0xa5,MY_ACK_LEN-10);
272
    dev_queue_xmit(newskb);
273
    //Sleep with short timeout, waiting for response
274 30 wzab
    if(wait_event_interruptible_timeout(usercmd_queue,sd->cmd_ack==2,timeout)) {
275 18 wzab
      //Response received
276
      //If target buffer provided, copy data to the userspace buffer
277
      if(resp) memcpy(resp,sd->cmd_resp,12);
278
      result = SUCCESS;
279
      break; //exit loop
280
    }
281
  }
282
  //We don't wait for response any more
283
  sd->cmd_ack = 0;
284
  mutex_unlock(&sd->usercmd_lock);
285
  return result;
286
}
287 21 wzab
/* Function used to send RESET command (without confirmation, as
288
the core is reinitialized and can't send confirmation) */
289
static inline
290
long send_reset(slave_data * sd)
291
{
292
  struct sk_buff *newskb = NULL;
293
  uint8_t * my_data = NULL;
294
  //First check, if the Ethernet device is claimed, otherwise return an error
295
  if(sd->dev==NULL) return -ENODEV;
296
  //Each slave may perform only one user command, so first check, if no other thread
297
  //attempts to send the command
298
  if ( mutex_trylock(&sd->usercmd_lock)==0) return -EBUSY;
299
  //Mutex acquired, we can proceed
300
  //First allocate the sequence number for the command
301
  sd->cmd_seq = 0;
302
  sd->cmd_code = FCMD_RESET;
303
  sd->cmd_ack = 0; //We don't wait for response
304
  //Send the packet 
305
  newskb = alloc_skb(LL_RESERVED_SPACE(sd->dev)+MY_ACK_LEN, GFP_KERNEL);
306
  skb_reserve(newskb,LL_RESERVED_SPACE(sd->dev));
307
  skb_reset_network_header(newskb);
308
  newskb->dev = sd->dev;
309
  newskb->protocol = htons(MY_PROTO_ID);
310
  //Build the MAC header for the new packet
311 29 wzab
  // Here http://lxr.free-electrons.com/source/net/ipv4/arp.c?v=3.17#L608 it is shown how to build a packet!
312 21 wzab
  if (dev_hard_header(newskb,sd->dev,MY_PROTO_ID,&sd->mac,sd->dev->dev_addr,MY_ACK_LEN+ETH_HLEN) < 0)
313
    {
314 29 wzab
      mutex_unlock(&sd->usercmd_lock);
315 21 wzab
      kfree_skb(newskb);
316
      return -EINVAL;
317
    }
318
  //Put the protocol version id to the packet
319
  put_skb_u16(newskb,MY_PROTO_VER);
320
  //Put the command code
321
  put_skb_u16(newskb,sd->cmd_code);
322
  //Put the sequence number
323
  put_skb_u16(newskb,sd->cmd_seq);
324
  //Put the argument
325
  put_skb_u32(newskb,0);
326
  //Fill the packet
327
  my_data = skb_put(newskb,MY_ACK_LEN-10);
328
  memset(my_data,0xa5,MY_ACK_LEN-10);
329
  dev_queue_xmit(newskb);
330
  mutex_unlock(&sd->usercmd_lock);
331
  return SUCCESS;
332
}
333 18 wzab
 
334
/* Function free_mac may be safely called even if the MAC was not taken
335
   it checks sd->active to detect such situation
336
*/
337
static inline
338
long free_mac(slave_data *sd) {
339
  write_lock_bh(&slave_table_lock);
340
  if(sd->active) {
341
    /* Clear the MAC address */
342
    sd->active = 0;
343
    memset(&sd->mac,0,ETH_ALEN);
344
    write_unlock_bh(&slave_table_lock);
345
    /* Now send the "stop transmission" packet to the slave */
346
    /* Find the net device */
347
    if (!sd->dev) return -ENODEV;
348
    dev_put(sd->dev);
349
    sd->dev=NULL;
350
  } else {
351
    write_unlock_bh(&slave_table_lock);
352
  }
353
  return SUCCESS;
354
}
355
 
356 15 wzab
static long my_proto1_ioctl (struct file *filp,
357
                             unsigned int cmd, unsigned long arg)
358
{
359
  slave_data * sd = filp->private_data;
360
  if (_IOC_TYPE(cmd) != L3_V1_IOC_MAGIC) {
361
    return -EINVAL;
362
  }
363
  switch (cmd) {
364
  case L3_V1_IOC_SETWAKEUP:
365
    if (arg > MY_BUF_LEN/2)
366
      return -EINVAL; //Don't allow to set too high read threshold!
367
    write_lock_bh(&sd->flags_lock);
368
    sd->rx_wakeup_thr = arg;
369
    write_unlock_bh(&sd->flags_lock);
370
    return 0;
371
  case L3_V1_IOC_GETBUFLEN:
372
    /* Inform the user application about the length of the buffer */
373
    return MY_BUF_LEN;
374
  case L3_V1_IOC_READPTRS:
375
    {
376
      void * res = (void *) arg;
377
      long res2;
378
      struct l3_v1_buf_pointers bp;
379 48 wzab
#if LINUX_VERSION_CODE >= 0x50000
380
      if (!access_ok(res,sizeof(bp))) {
381
#else
382 15 wzab
      if (!access_ok(VERIFY_WRITE,res,sizeof(bp))) {
383 48 wzab
#endif
384 15 wzab
        return -EFAULT;
385
      } else {
386
        read_lock_bh(&sd->ptrs_lock);
387
        bp.head=sd->head;
388
        bp.tail=sd->tail;
389 18 wzab
        bp.eof=sd->eof_flag;
390 15 wzab
        read_unlock_bh(&sd->ptrs_lock);
391
        res2 = __copy_to_user(res,&bp,sizeof(bp));
392
        if(res2)
393
          return -EFAULT;
394
        if (sd->err_flag)
395
          return -EIO; /* In this case user must him/herself
396
                          calculate the number of available bytes */
397
        else
398
          return (bp.head-bp.tail) & MY_BUF_LEN_MASK;
399
        /* Return the number of available bytes */
400
      }
401
    }
402
  case L3_V1_IOC_WRITEPTRS:
403
    /* Update the read pointer
404
     * The argument contains information about the number of bytes
405
     * consumed by the application
406
     */
407
    {
408
      int rptr;
409
      int wptr;
410
      int available_data;
411
      //We need to check if the amount of consumed data is correct
412
      write_lock_bh(&sd->ptrs_lock);
413
      wptr = sd->head;
414
      rptr = sd->tail;
415
      available_data = (wptr - rptr) & MY_BUF_LEN_MASK;
416
      if (arg>available_data)
417
        {
418
          write_unlock_bh(&sd->ptrs_lock);
419
          return -EINVAL;
420
        }
421
      //If the number of consumed bytes is correct, update the number of bytes
422
      sd->tail = (rptr + arg) & MY_BUF_LEN_MASK;
423
      write_unlock_bh(&sd->ptrs_lock);
424
      return SUCCESS;
425
    }
426
  case L3_V1_IOC_STARTMAC: //Open the slave
427
    {
428 18 wzab
      sd->stopped_flag = 0;
429
      sd->eof_flag = 0;
430
      //We just send a request to start transmission and wait for confirmation
431
      return send_cmd(sd,FCMD_START,0,NULL,100,2);
432 15 wzab
    }
433 18 wzab
  case L3_V1_IOC_STOPMAC: //Close the slave and reset it to stop transmission immediately
434
    {
435
      return send_cmd(sd,FCMD_STOP,0,NULL,100,2);
436
    }
437
  case L3_V1_IOC_RESETMAC: //Reset MAC so, that it stops transmission immediately
438
    {
439 21 wzab
      return send_reset(sd);
440 18 wzab
    }
441 15 wzab
  case L3_V1_IOC_GETMAC: //Open the slave
442
    {
443
      void * source = (void *) arg;
444
      struct l3_v1_slave sl;
445
      struct net_device *dev = NULL;
446
      long res2;
447 48 wzab
#if LINUX_VERSION_CODE >= 0x50000
448
      if (!access_ok(source,sizeof(sl))) {
449
#else 
450 15 wzab
      if (!access_ok(VERIFY_READ,source,sizeof(sl))) {
451 48 wzab
#endif
452 15 wzab
        return -EFAULT;
453
      }
454
      /* First deactivate the slave to avoid situation where data are modified
455
       * while slave is active */
456
      if (sd->active) sd->active = 0;
457
      //Set the numbers of stored packets to MAX
458
      write_lock_bh(&sd->pkts_rwlock);
459
      memset(&sd->pkts,0xff,sizeof(sd->pkts));
460
      sd->last_nack_pkt=0;
461
      write_unlock_bh(&sd->pkts_rwlock);
462
      //Copy arguments from the user space
463
      res2 = __copy_from_user(&sl,source,sizeof(sl));
464
      if(res2) {
465
        return -EFAULT;
466
      }
467
      write_lock_bh(&slave_table_lock);
468
      /* Copy the MAC address */
469
      memcpy(&sd->mac,sl.mac,ETH_ALEN);
470
      sd->active = 1;
471
      write_unlock_bh(&slave_table_lock);
472
      /* Find the net device */
473
      sl.devname[IFNAMSIZ-1]=0; // Protect against incorrect device name
474
      if (sd->dev) {
475
        //Maybe there was no STOPMAC call after previous STARTMAC?
476
        dev_put(sd->dev);
477
        sd->dev=NULL;
478
      }
479
      dev = dev_get_by_name(&init_net,sl.devname);
480
      if (!dev) return -ENODEV;
481
      sd->dev = dev;
482
      return SUCCESS;
483
    }
484
  case L3_V1_IOC_FREEMAC: //Close the slave and reset it to stop transmission immediately
485
    {
486 18 wzab
      free_mac(sd);
487 15 wzab
      return SUCCESS;
488
    }
489
  case L3_V1_IOC_USERCMD: //Perform the user command
490
    {
491
      void * source = (void *) arg;
492
      long result = -EINVAL;
493
      struct l3_v1_usercmd ucmd;
494
      //First copy command data
495
      result = __copy_from_user(&ucmd,source,sizeof(ucmd));
496
      if(result) {
497
        return -EFAULT;
498
      }
499
      //Now we check if the command is valid user command
500
      if(ucmd.cmd < 0x0100) return -EINVAL;
501 18 wzab
      result = send_cmd(sd,ucmd.cmd, ucmd.arg, ucmd.resp, ucmd.nr_of_retries,ucmd.timeout);
502
      if(result<0) return result;
503
      result = __copy_to_user(source,&ucmd,sizeof(ucmd));
504 15 wzab
      return result;
505
    }
506
  }
507
  return -EINVAL;
508
}
509
/*
510
  Implementation of the poll method
511
*/
512
unsigned int my_proto1_poll(struct file *filp,poll_table *wait)
513
{
514
  unsigned int mask =0;
515
  slave_data * sd = filp->private_data;
516
  unsigned int data_available;
517
  poll_wait(filp,&read_queue,wait);
518
  read_lock_bh(&sd->ptrs_lock);
519
  data_available = (sd->head - sd->tail) & MY_BUF_LEN_MASK;
520 18 wzab
  if (data_available >= sd->rx_wakeup_thr) mask |= POLLIN |POLLRDNORM;
521
  if (sd->eof_flag) {
522
    if(data_available) mask |= POLLIN | POLLRDNORM;
523
    else mask |= POLLHUP;
524
  }
525 15 wzab
#ifdef FADE_DEBUG
526
  printk(KERN_INFO "poll head: %d tail: %d data: %d prog: %d.\n",sd->head,sd->tail,data_available,sd->rx_wakeup_thr);
527
#endif
528
  //Check if the error occured
529
  if (sd->err_flag) mask |= POLLERR;
530
  read_unlock_bh(&sd->ptrs_lock);
531
  return mask;
532
}
533
 
534
/* Module initialization  */
535
int init_my_proto1( void )
536
{
537
  int res;
538
  int i;
539
  /* Create the device class for udev */
540
  class_my_proto = class_create(THIS_MODULE, "my_proto");
541
  if (IS_ERR(class_my_proto)) {
542
    printk(KERN_ERR "Error creating my_proto class.\n");
543
    res=PTR_ERR(class_my_proto);
544
    goto err1;
545
  }
546
  /* Allocate the device number */
547
  res=alloc_chrdev_region(&my_dev, 0, max_slaves, DEVICE_NAME);
548
  if (res) {
549
    printk (KERN_ERR "Alocation of the device number for %s failed\n",
550
            DEVICE_NAME);
551
    goto err1;
552
  };
553
  /* Allocate the character device structure */
554
  my_cdev = cdev_alloc( );
555
  if (my_cdev == NULL) {
556
    printk (KERN_ERR "Allocation of cdev for %s failed\n",
557
            DEVICE_NAME);
558
    goto err1;
559
  }
560
  my_cdev->ops = &Fops;
561
  my_cdev->owner = THIS_MODULE;
562
  /* Add the character device to the system */
563
  res=cdev_add(my_cdev, my_dev, max_slaves);
564
  if (res) {
565
    printk (KERN_ERR "Registration of the device number for %s failed\n",
566
            DEVICE_NAME);
567
    goto err1;
568
  };
569
  /* Create our devices in the system */
570
  for (i=0;i<max_slaves;i++) {
571
    device_create(class_my_proto,NULL,MKDEV(MAJOR(my_dev),MINOR(my_dev)+i),NULL,"l3_fpga%d",i);
572
  }
573
  printk (KERN_ERR "%s The major device number is %d.\n",
574
          "Registration is a success.",
575
          MAJOR(my_dev));
576
  //Prepare the table of slaves
577
  slave_table = kzalloc(sizeof(slave_data)*max_slaves, GFP_KERNEL);
578
  if (!slave_table) return -ENOMEM;
579
  for (i=0;i<max_slaves;i++) {
580
    /* Perform initialization, which should be done only once, when the module
581
     * is loaded. Other actions may be needed, when the transmission from
582
     * particular slave is started. This will be done in IOCTL STARTMAC
583
     */
584
    slave_data * sd = &slave_table[i];
585
    sd->active=0; //Entry not used
586
    sd->dev=NULL;
587
    rwlock_init(&sd->pkts_rwlock);
588
    rwlock_init(&sd->ptrs_lock);
589
    rwlock_init(&sd->flags_lock);
590
    mutex_init(&sd->usercmd_lock);
591
  }
592
  //Install our protocol sniffer
593
  dev_add_pack(&my_proto_pt);
594
  proto_registered = 1;
595
  return SUCCESS;
596
 err1:
597
  /* In case of error free all allocated resources */
598
  cleanup_my_proto1();
599
  return res;
600
}
601
 
602
module_init(init_my_proto1);
603
 
604
/* Clean-up when removing the module */
605
void cleanup_my_proto1( void )
606
{
607
  /* Unregister the protocol sniffer */
608
  if (proto_registered) dev_remove_pack(&my_proto_pt);
609
  /* Free the slave table */
610
  if (slave_table) {
611
    int i;
612
    for (i=0;i<max_slaves;i++) {
613
      if (slave_table[i].buffer) {
614
        vfree(slave_table[i].buffer);
615
        slave_table[i].buffer = NULL;
616
      }
617
      if (slave_table[i].dev) {
618
        dev_put(slave_table[i].dev);
619
        slave_table[i].dev=NULL;
620
      }
621
      if (slave_table[i].active) {
622
        slave_table[i].active = 0;
623
      }
624
    }
625
    kfree(slave_table);
626
    slave_table=NULL;
627
  }
628
  /* Remove device from the class */
629
  if (my_dev && class_my_proto) {
630
    int i;
631
    for (i=0;i<max_slaves;i++) {
632
      device_destroy(class_my_proto,MKDEV(MAJOR(my_dev),MINOR(my_dev)+i));
633
    }
634
  }
635
  /* Deregister device */
636
  if (my_cdev) cdev_del(my_cdev);
637
  my_cdev=NULL;
638
  /* Free the device number */
639
  unregister_chrdev_region(my_dev, max_slaves);
640
  /* Deregister class */
641
  if (class_my_proto) {
642
    class_destroy(class_my_proto);
643
    class_my_proto=NULL;
644
  }
645
 
646
}
647
module_exit(cleanup_my_proto1);
648
/*
649
  Function, which receives my packet, copies the data and acknowledges the packet
650
  as soon as possible...
651
  I've tried to allow this function to handle multiple packets in parallel
652
  in the SMP system, however I've used rwlocks for that.
653
  Probably it should be improved, according to the last tendency to avoid
654
  rwlocks in the kernel...
655
*/
656
 
657
static int my_proto_rcv(struct sk_buff * skb, struct net_device * dev, struct packet_type * pt,
658
                        struct net_device * orig_dev)
659
{
660
  struct sk_buff *newskb = NULL;
661
  struct ethhdr * rcv_hdr = NULL;
662
  //unsigned int head;
663
  //unsigned int tail;
664
  int is_duplicate = 0;
665
  int res;
666
  uint32_t packet_number;
667
  int ns; //Number of slave
668
  slave_data * sd = NULL;
669
  int32_t pkt_dist;
670
  char * my_data = NULL;
671
  unsigned char tmp_buf[USER_HDR_LEN];
672
  char ack_packet = 0; //Should we acknowledge the packet?
673 18 wzab
  uint32_t pkt_pos, needed_space, buf_free;
674 15 wzab
  //Extract the MAC header from the received packet
675
  rcv_hdr=eth_hdr(skb);
676
  //First we try to identify the sender so we search the table of active slaves
677
  //The table is protected during the search, so it should not be changed
678
#ifdef FADE_DEBUG
679
  printk("snd: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",(int)rcv_hdr->h_source[0],
680
         (int)rcv_hdr->h_source[1],(int)rcv_hdr->h_source[2],(int)rcv_hdr->h_source[3],
681
         (int)rcv_hdr->h_source[4],(int)rcv_hdr->h_source[5]);
682
#endif
683
  read_lock_bh(&slave_table_lock);
684
  for (ns=0;ns<max_slaves;ns++) {
685
#ifdef FADE_DEBUG
686
    printk("slv: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x  act: %d\n",
687
           (int)slave_table[ns].mac[0],(int)slave_table[ns].mac[1],(int)slave_table[ns].mac[2],
688
           (int)slave_table[ns].mac[3],(int)slave_table[ns].mac[4],(int)slave_table[ns].mac[5],
689
           (int)slave_table[ns].active);
690
#endif
691
    if (
692
        slave_table[ns].active!=0 &&
693
        memcmp(slave_table[ns].mac,rcv_hdr->h_source, sizeof(slave_table[0].mac))==0
694
        ) break;
695
  }
696
  read_unlock_bh(&slave_table_lock);
697
  //Now we know which slave sent us the packet (ns<max_slaves) or that
698
  //the packet came from an unknown slave (ns==max_slaves)
699
  if (unlikely(ns==max_slaves)) {
700
    printk(KERN_WARNING " Received packet from incorrect slave!\n");
701
    //Sender is not opened, so ignore the packet, and send
702
    //to the sender request to stop the transmission immediately
703
    newskb = alloc_skb(LL_RESERVED_SPACE(dev)+MY_ACK_LEN, GFP_ATOMIC);
704
    skb_reserve(newskb,LL_RESERVED_SPACE(dev));
705
    skb_reset_network_header(newskb);
706
    newskb->dev = dev;
707
    newskb->protocol = htons(MY_PROTO_ID);
708
    //Build the MAC header for the new packet
709 29 wzab
    // Here http://lxr.free-electrons.com/source/net/ipv4/arp.c?v=3.17#L608 it is shown how to build a packet!
710 15 wzab
    if (dev_hard_header(newskb,dev,MY_PROTO_ID,&rcv_hdr->h_source,&rcv_hdr->h_dest,MY_ACK_LEN+ETH_HLEN) < 0)
711
      goto error;
712
    //Put the protocol version id to the packet
713 16 wzab
    put_skb_u16(newskb,MY_PROTO_VER);
714 18 wzab
    //Put the "restart" command to the packet, which should force it to stop transmission
715
    //immediately
716
    put_skb_u16(newskb,FCMD_RESET);
717 15 wzab
    my_data = skb_put(newskb,MY_ACK_LEN - 4);
718
    memset(my_data,0xa5,MY_ACK_LEN - 4);
719
    dev_queue_xmit(newskb);
720
    kfree_skb(skb);
721
    return NET_RX_DROP;
722
  }
723
  sd = &slave_table[ns]; //To speed up access to the data describing state of the slave
724
#ifdef FADE_DEBUG
725
  printk(KERN_INFO " Received packet!\n");
726
#endif
727
  //Now we should analyze the origin and meaning of the packet
728
  //To avoid problems with scattered packets, we copy initial part of data to the buffer
729
  //using the skb_copy_bits
730
  skb_copy_bits(skb,0,tmp_buf,USER_HDR_LEN);
731
  /* We extract the information from the user header
732
   * First we check if this is correct version of the protocol */
733 18 wzab
  if (unlikely(get_be_u16(&tmp_buf[0]) != MY_PROTO_VER)) goto wrong_pkt_type_error;
734 16 wzab
  if (unlikely(get_be_u16(&tmp_buf[2]) == 0xa55a)) {
735 15 wzab
    //This is a command response packet
736
    printk(KERN_INFO " received command response packet");
737
    if(sd->cmd_ack==1) {
738
      //We are waiting for response
739
      printk(KERN_INFO "we were waiting for command response packet");
740 16 wzab
      if ((get_be_u16(&tmp_buf[6]) == sd->cmd_code) &&
741 18 wzab
          (get_be_u16(&tmp_buf[8]) == sd->cmd_seq)){
742 15 wzab
        //This is a response for the right command
743
        //copy the response to the slave data
744
        printk(KERN_INFO "It was response for the right command");
745
        memcpy(&sd->cmd_resp,&tmp_buf[6],12);
746
        sd->cmd_ack=2;
747
        //Wake up the waiting process
748
        wake_up_interruptible(&usercmd_queue);
749
      }
750
    }
751
    kfree_skb(skb);
752
    return NET_RX_SUCCESS;
753
  }
754 18 wzab
  if (unlikely((get_be_u16(&tmp_buf[2]) != 0xa5a5) &&
755
               (get_be_u16(&tmp_buf[2]) != 0xa5a6))
756
      ) {
757 15 wzab
    //This is not a data packet
758
    goto wrong_pkt_type_error;
759
  }
760
  /* Now we handle the data packet
761
     PLEASE NOTE, THAT THIS MUST TIGHTLY CORRESPOND
762
     TO YOUR FPGA IMPLEMENTATION! */
763
  //Check, if we need to read a command response
764
  if(sd->cmd_ack==1) {
765
    //We are waiting for response
766 16 wzab
    if ((get_be_u16(&tmp_buf[14]) == sd->cmd_code) &&
767
        (get_be_u16(&tmp_buf[16]) == sd->cmd_seq)) {
768 15 wzab
      //This is a response for the right command
769
      //copy the response to the slave data
770
      memcpy(&sd->cmd_resp,&tmp_buf[14],12);
771
      sd->cmd_ack=2;
772
      //Wake up the waiting process
773
      wake_up_interruptible(&usercmd_queue);
774
    }
775
  }
776 16 wzab
  packet_number = get_be_u32(&tmp_buf[6]);
777 15 wzab
#ifdef FADE_DEBUG
778
  printk(KERN_INFO "pkt=%d\n",(int)packet_number);
779
#endif
780
  /* To know if this is a new packet, we compare the packet number
781
   * in the received packet with the number of the last unconfirmed packet,
782
   * calculating the difference between those two numbers: */
783
  read_lock_bh(&sd->pkts_rwlock);
784
  pkt_dist=(int32_t) packet_number - (int32_t) sd->last_nack_pkt;
785 18 wzab
  //Check if this packet was received before
786 15 wzab
  is_duplicate=(sd->pkts[packet_number & PKTS_IN_WINDOW_MASK] == packet_number) ? 1 : 0;
787
  read_unlock_bh(&sd->pkts_rwlock);
788 18 wzab
  if (unlikely((pkt_dist<0) || (pkt_dist>=PKTS_IN_WINDOW))) {
789
    //This is a "too old" packet, or packet "from the future", which should not be transimtted
790
    //by the FPGA
791 15 wzab
    if (pkt_dist<0) {
792 18 wzab
      // This is a packet which was already confirmed, but probably ACK was lost
793 15 wzab
#ifdef FADE_DEBUG
794
      printk(KERN_INFO "Packet already confirmed: pkt=%d expect=%d last=%d\n",packet_number, sd->pkts[packet_number], sd->last_nack_pkt);
795
#endif
796 18 wzab
      ack_packet = 1;
797
      goto confirm;
798 15 wzab
    } else {
799
      /* This is a packet with too high set number (packet "from the future"
800
       * it my be a symptom of serious communication problem! */
801
      printk(KERN_ERR "Packet from the future! number: %d last_confirmed: %d\n", packet_number, sd->last_nack_pkt);
802 18 wzab
      goto error2;
803 15 wzab
    }
804
  }
805 18 wzab
  //If we get there, it means, that:
806
  //   pkt_dist >= 0 and pkt_dist < PKTS_IN_WINDOW
807
  // So this is an expected data packet.
808
  if(is_duplicate) {
809
    //Packet already confirmed, probably the ACK was lost, so simply generate the ACK
810
    ack_packet = 1;
811
    goto confirm;
812
  }
813
  //Packet not confirmed yet. Confirm it only after all processing is successfully completed
814
  pkt_pos=(packet_number<<LOG2_USER_LEN) & MY_BUF_LEN_MASK;
815
  //We must be sure, that the pointers do not change during this check
816
  read_lock_bh(&sd->ptrs_lock);
817
  //Calculate free space needed to copy the packet
818
  needed_space = (pkt_pos+USER_LEN-1-(sd->head)) & MY_BUF_LEN_MASK;
819
  //Calculate the amount of free space in the buffer
820
  buf_free = (sd->tail - sd->head -1 ) & MY_BUF_LEN_MASK;
821
#ifdef FADE_DEBUG
822
  printk(KERN_INFO "packet_nr: %d Free buffer: %d needed space: %d head=%d last_nack=%d\n",
823
         packet_number, needed_space, buf_free, sd->head, sd->last_nack_pkt);
824
#endif
825
  read_unlock_bh(&sd->ptrs_lock);
826
  if (unlikely( buf_free <= needed_space )) goto error2; //No place for copying, drop the packet
827
  // Check the length of the package
828
  if (unlikely(skb->len != PAYL_LEN)) {
829
    printk(KERN_ERR "Error! Length of data should be %d but is %d!\n",PAYL_LEN, skb->len);
830
    sd->err_flag |= FADE_ERR_INCORRECT_LENGTH;
831
    goto error2;
832
  }
833
  // We can safely copy all the packet to the buffer:
834
  res = skb_copy_bits(skb,USER_HDR_LEN,&(sd->buffer[pkt_pos]),USER_LEN);
835
#ifdef FADE_DEBUG
836
  printk(KERN_INFO " skb_copy_bits: %d", res);
837
#endif
838
  if (res<0) goto error2; //Unsuccessfull copying
839
  //Packet was copied, so note, that we should confirm it
840
  ack_packet=1;
841
  /* When packet is copied, we can check if this is the last "flushed" packet */
842
  if (get_be_u16(&tmp_buf[2])==0xa5a6) {
843
    //Flushed packet, store its number and length (should it be protected with spinlock?)
844
    sd->last_pkt_num = packet_number;
845
    //Copy the length, truncating it from 64 bits
846 46 wzab
    sd->last_pkt_len = get_be_u64(&(sd->buffer[pkt_pos+USER_LEN-sizeof(uint64_t)]));
847 18 wzab
    //We have received the "flushed" buffer, mark that transmission is stopped
848
    sd->stopped_flag = 1;
849 20 wzab
    //printk(KERN_INFO "set stopped flag");
850 18 wzab
  }
851
  /* We modify the number of the copied packet in the pkts array, to avoid
852
   * unnecessary copying if we receive a duplicate
853
   * To modify the pkts table, we must close pkts_rwlock for writing */
854
  write_lock_bh(&sd->pkts_rwlock);
855
  sd->pkts[packet_number & PKTS_IN_WINDOW_MASK]= packet_number;
856
  if (packet_number == sd->last_nack_pkt) {
857
    /* If our packet was the last, which prevented shifting of the head pointer,
858
     * we can try now to move the head pointer.
859
     * We browse the pkts table, looking for the first packet with incorrect number
860
     * i.e. the packet which was not received and not confimed yet
861
     */
862
    uint32_t chk_packet_num = packet_number+1;
863
    uint32_t count=0;
864
    while (++count < PKTS_IN_WINDOW) {
865
      if (sd->pkts[(sd->last_nack_pkt + count) & PKTS_IN_WINDOW_MASK] != chk_packet_num) break; //Packet not confirmed
866
      chk_packet_num++;
867
    }
868
    sd->last_nack_pkt += count;
869
    write_unlock_bh(&sd->pkts_rwlock);
870
    /* Now we can move the head position */
871
    if(likely((sd->stopped_flag == 0) ||
872
              ((uint32_t)(sd->last_nack_pkt-1) != sd->last_pkt_num))) {
873
      //Normal packet, set head right after the last serviced packet
874
      write_lock_bh(&sd->ptrs_lock);
875
      sd->head = (sd->last_nack_pkt*USER_LEN) & MY_BUF_LEN_MASK;
876
      //Now try to wake up the reading process
877
      if (((sd->head - sd->tail) & MY_BUF_LEN_MASK) >= sd->rx_wakeup_thr)
878
        wake_up_interruptible(&read_queue);
879
    } else {
880
      //Flushed packet, set head right after the end of the packet
881
      write_lock_bh(&sd->ptrs_lock);
882 46 wzab
      sd->head = ((sd->last_nack_pkt-1)*USER_LEN+8*sd->last_pkt_len) & MY_BUF_LEN_MASK;
883 18 wzab
      //We have consumed the last, "flushed" buffer, so now we can set the eof flag
884
      sd-> eof_flag = 1;
885 20 wzab
      //printk(KERN_ALERT "set eof flag!");
886 18 wzab
      //And we wake up the reading process
887
      wake_up_interruptible(&read_queue);
888
    } //if - stopped_flag
889
    write_unlock_bh(&sd->ptrs_lock);
890
  } else { // if - last_nack_pkt 
891
    write_unlock_bh(&sd->pkts_rwlock);
892
  }
893
 confirm:
894
  //Send the confirmation if required
895 15 wzab
  if (likely(ack_packet)) {
896
    newskb = alloc_skb(LL_RESERVED_SPACE(dev)+MY_ACK_LEN, GFP_ATOMIC);
897
    skb_reserve(newskb,LL_RESERVED_SPACE(dev));
898
    skb_reset_network_header(newskb);
899
    newskb->dev = dev;
900
    newskb->protocol = htons(MY_PROTO_ID);
901
    //Build the MAC header for the new packet
902 29 wzab
    // Here http://lxr.free-electrons.com/source/net/ipv4/arp.c?v=3.17#L608 it is shown how to build a packet!
903 15 wzab
    if (dev_hard_header(newskb,dev,MY_PROTO_ID,&rcv_hdr->h_source,&rcv_hdr->h_dest,MY_ACK_LEN+ETH_HLEN) < 0)
904
      goto error;
905
    //Put the protocol version id to the packet
906 18 wzab
    put_skb_u16(newskb,MY_PROTO_VER);
907 15 wzab
    //Put the "ACKNOWLEDGE" type
908 18 wzab
    put_skb_u16(newskb,FCMD_ACK);
909 15 wzab
    //Copy the begining of the received packet to the acknowledge packet
910
    my_data = skb_put(newskb,MY_ACK_COPIED);
911
    res = skb_copy_bits(skb,4,my_data,MY_ACK_COPIED);
912
    my_data = skb_put(newskb,MY_ACK_LEN -MY_ACK_COPIED-4);
913
    memset(my_data,0xa5,MY_ACK_LEN - MY_ACK_COPIED-4);
914
#ifdef FADE_DEBUG
915
    printk(KERN_INFO " skb_nh: %x, skb_dt: %x, skb_nh2: %x, skb_t: %x\n tail: %d head: %d\n",skb_network_header(newskb),newskb->data,
916
           newskb->network_header,newskb->tail, sd->tail, sd->head) ;
917
#endif
918
    dev_queue_xmit(newskb);
919
  }
920
  kfree_skb(skb);
921
  return NET_RX_SUCCESS;
922
 wrong_pkt_type_error:
923
  //This code should be called with sd initialized,
924
  //but to avoid kernel panic, check if sd was set
925
  if(sd) {
926
    write_lock_bh(&sd->flags_lock);
927
    sd->err_flag |= FADE_ERR_INCORRECT_PACKET_TYPE;
928
    write_unlock_bh(&sd->flags_lock);
929
  } else {
930
    printk(KERN_ERR "FADE: wrong_pkt_type_error called with null sd");
931
  }
932
 error:
933
  if (newskb) kfree_skb(newskb);
934 18 wzab
 error2:
935 15 wzab
  if (skb) kfree_skb(skb);
936
  return NET_RX_DROP;
937
}
938
 
939
/*
940
  Implementation of the "device open" function
941
*/
942
static int my_proto1_open(struct inode *inode,
943
                          struct file *file)
944
{
945
  int i;
946
  slave_data * sd = NULL;
947
  unsigned long flags;
948
  i=iminor(inode)-MINOR(my_dev);
949
  if (i >= max_slaves) {
950
    printk(KERN_WARNING "Trying to access %s slave with too high minor number: %d\n",
951
           DEVICE_NAME, i);
952
    return -ENODEV;
953
  }
954
  read_lock_irqsave(&slave_table_lock,flags);
955
  sd = &slave_table[i];
956
  //Each device may be opened only once!
957
  if (sd->is_open) {
958 28 wzab
    read_unlock_irqrestore(&slave_table_lock,flags);
959 15 wzab
    return -EBUSY;
960
  }
961
  //Prepare slave_table for operation
962
  read_unlock_irqrestore(&slave_table_lock,flags);
963
  sd->buffer = vmalloc_user(MY_BUF_LEN);
964
  if (!sd->buffer) return -ENOMEM;
965
  //Set the MAC address to 0
966
  memset(sd->mac,0,sizeof(sd->mac));
967
  sd->head = 0;
968
  sd->tail = 0;
969 18 wzab
  sd->eof_flag = 0;
970
  sd->stopped_flag = 0;
971 15 wzab
  sd->err_flag = 0;
972
  sd->last_nack_pkt = 0;
973
  sd->rx_wakeup_thr = 1;
974
  sd->active = 0;
975
  sd->cmd_seq = 0;
976
  sd->is_open = 1;
977
  file->private_data=sd;
978
  return SUCCESS;
979
}
980
 
981
 
982
static int my_proto1_release(struct inode *inode,
983
                             struct file *file)
984
{
985
  slave_data * sd = file->private_data;
986 18 wzab
  //#ifdef FADE_DEBUG
987 15 wzab
  printk (KERN_INFO "device_release(%p,%p)\n", inode, file);
988 18 wzab
  //#endif
989 15 wzab
  //Release resources associated with servicing of the particular device
990
  if (sd) {
991
    if (sd->is_open) {
992
      sd->is_open = 0; //It can be dangerous! Before freeing the buffer, we must be sure, that
993
      //no our packet is being processed!
994 18 wzab
      printk (KERN_INFO "freed MAC\n");
995
      free_mac(sd); //It also sets sd->active to 0!
996 15 wzab
      if (sd->buffer) {
997 18 wzab
        printk (KERN_INFO "freed buffer\n");
998 15 wzab
        vfree(sd->buffer);
999
        sd->buffer = NULL;
1000
      }
1001
    }
1002
  }
1003
  return SUCCESS;
1004
}
1005
 
1006
/* Memory mapping */
1007
void my_proto1_vma_open (struct vm_area_struct * area)
1008
{  }
1009
 
1010
void my_proto1_vma_close (struct vm_area_struct * area)
1011
{  }
1012
 
1013
static struct vm_operations_struct my_proto1_vm_ops = {
1014
  my_proto1_vma_open,
1015
  my_proto1_vma_close,
1016
};
1017
 
1018
/*
1019
  mmap method implementation
1020
*/
1021
int my_proto1_mmap(struct file *filp,
1022
                   struct vm_area_struct *vma)
1023
{
1024
  slave_data * sd = filp->private_data;
1025
  unsigned long vsize = vma->vm_end - vma->vm_start;
1026
  unsigned long psize = MY_BUF_LEN;
1027
  if (vsize>psize)
1028
    return -EINVAL;
1029
  remap_vmalloc_range(vma,sd->buffer, 0);
1030
  if (vma->vm_ops)
1031
    return -EINVAL; //It should never happen...
1032
  vma->vm_ops = &my_proto1_vm_ops;
1033
  my_proto1_vma_open(vma); //No open(vma) was called, we have called it ourselves
1034
  return 0;
1035
}
1036
 

powered by: WebSVN 2.1.0

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