Line 55... |
Line 55... |
* packet number - 4 bytes - offset 6
|
* packet number - 4 bytes - offset 6
|
* transm_delay - 4 bytes - offset 10
|
* transm_delay - 4 bytes - offset 10
|
* cmd_response - 12 bytes - offset 14
|
* cmd_response - 12 bytes - offset 14
|
*
|
*
|
* Total: 26 bytes!
|
* Total: 26 bytes!
|
|
* If the packet contains "flushed" buffer,
|
|
* then data ID is 0xA5A6, and the last word
|
|
* contains number of transmitted words.
|
|
|
* For command response
|
* For command response
|
* 0xA55A : cmd_resp ID 2 bytes - offset 2
|
* 0xA55A : cmd_resp ID 2 bytes - offset 2
|
* 0x0000 : filler - 2 bytes - offset 4
|
* 0x0000 : filler - 2 bytes - offset 4
|
* cmd_response - 12 bytes offset 6
|
* cmd_response - 12 bytes offset 6
|
Line 71... |
Line 74... |
#define PAYL_LEN ( USER_HDR_LEN + USER_LEN )
|
#define PAYL_LEN ( USER_HDR_LEN + USER_LEN )
|
|
|
/* Number of packets in window - this number depends on amount of RAM
|
/* Number of packets in window - this number depends on amount of RAM
|
* in the FPGA - Packets in a widnow must fit in the FPGA RAM
|
* in the FPGA - Packets in a widnow must fit in the FPGA RAM
|
* Should be power of two! */
|
* Should be power of two! */
|
#define PKTS_IN_WINDOW (1<<5)
|
#define PKTS_IN_WINDOW (1<<4)
|
#define PKTS_IN_WINDOW_MASK (PKTS_IN_WINDOW-1)
|
#define PKTS_IN_WINDOW_MASK (PKTS_IN_WINDOW-1)
|
|
|
/* Capacity of kernel buffer (mmapped into user space) measured in
|
/* Capacity of kernel buffer (mmapped into user space) measured in
|
* number of windows - should be equal to power of two, to simplify
|
* number of windows - should be equal to power of two, to simplify
|
* the modulo operation (replacing it by binary AND) */
|
* the modulo operation (replacing it by binary AND) */
|
Line 133... |
Line 136... |
of the first packet in the current transmission window */
|
of the first packet in the current transmission window */
|
uint32_t pkts[PKTS_IN_WINDOW]; /* This array stores numbers of the last received packets in the
|
uint32_t pkts[PKTS_IN_WINDOW]; /* This array stores numbers of the last received packets in the
|
* transmission window. It is used to avoid unnecessary copying of duplicated
|
* transmission window. It is used to avoid unnecessary copying of duplicated
|
* packets into the receiver buffer */
|
* packets into the receiver buffer */
|
rwlock_t flags_lock; //Protects other fields of the slave_data struct
|
rwlock_t flags_lock; //Protects other fields of the slave_data struct
|
|
uint32_t last_pkt_num; /* Number of the last "flushed" packet */
|
|
uint32_t last_pkt_len; /* Number of words in the last "flushed" packet */
|
char err_flag;
|
char err_flag;
|
|
char stopped_flag; /* Flag informing, that transmission has been already terminated */
|
|
char eof_flag; /* Flag informing, that all packets are delivered after transmission is terminated */
|
char active;
|
char active;
|
char is_open;
|
char is_open;
|
int rx_wakeup_thr;
|
int rx_wakeup_thr;
|
unsigned char mac[ETH_ALEN];
|
unsigned char mac[ETH_ALEN];
|
struct net_device * dev;
|
struct net_device * dev;
|
Line 159... |
Line 166... |
return be64_to_cpu(*(uint64_t *)buf);
|
return be64_to_cpu(*(uint64_t *)buf);
|
}
|
}
|
|
|
static inline void put_skb_u16(struct sk_buff * skb, uint16_t val)
|
static inline void put_skb_u16(struct sk_buff * skb, uint16_t val)
|
{
|
{
|
char * data = skb_put(skb,sizeof(val));
|
void * data = skb_put(skb,sizeof(val));
|
* (uint16_t *) data = cpu_to_be16(val);
|
* (uint16_t *) data = cpu_to_be16(val);
|
}
|
}
|
|
|
static inline void put_skb_u32(struct sk_buff * skb, uint32_t val)
|
static inline void put_skb_u32(struct sk_buff * skb, uint32_t val)
|
{
|
{
|
char * data = skb_put(skb,sizeof(val));
|
void * data = skb_put(skb,sizeof(val));
|
* (uint32_t *) data = cpu_to_be32(val);
|
* (uint32_t *) data = cpu_to_be32(val);
|
}
|
}
|
|
|
static inline void put_skb_u64(struct sk_buff * skb, uint64_t val)
|
static inline void put_skb_u64(struct sk_buff * skb, uint64_t val)
|
{
|
{
|
char * data = skb_put(skb,sizeof(val));
|
void * data = skb_put(skb,sizeof(val));
|
* (uint64_t *) data = cpu_to_be64(val);
|
* (uint64_t *) data = cpu_to_be64(val);
|
}
|
}
|
|
|
static slave_data * slave_table = NULL;
|
static slave_data * slave_table = NULL;
|
|
|
Line 212... |
Line 219... |
.poll = my_proto1_poll,
|
.poll = my_proto1_poll,
|
.unlocked_ioctl=my_proto1_ioctl,
|
.unlocked_ioctl=my_proto1_ioctl,
|
.mmap=my_proto1_mmap
|
.mmap=my_proto1_mmap
|
};
|
};
|
|
|
|
|
|
/* Function used to send the user command and wait for confirmation */
|
|
static inline
|
|
long send_cmd(slave_data * sd, uint16_t cmd, uint32_t arg, void * resp, int nof_retries, int timeout)
|
|
{
|
|
long result = -ETIMEDOUT;
|
|
//Each slave may perform only one user command, so first check, if no other thread
|
|
//attempts to send the command
|
|
if ( mutex_trylock(&sd->usercmd_lock)==0) return -EBUSY;
|
|
//Mutex acquired, we can proceed
|
|
//First allocate the sequence number for the command
|
|
sd->cmd_seq += 1;
|
|
sd->cmd_code = cmd;
|
|
sd->cmd_ack = 1; //Mark, that we are waiting for response
|
|
//Now in the loop we send the packet, requesting execution of the command
|
|
//and then we wait for response with timeout
|
|
while(nof_retries--) {
|
|
//Send the packet
|
|
struct sk_buff *newskb = NULL;
|
|
uint8_t * my_data = NULL;
|
|
newskb = alloc_skb(LL_RESERVED_SPACE(sd->dev)+MY_ACK_LEN, GFP_KERNEL);
|
|
skb_reserve(newskb,LL_RESERVED_SPACE(sd->dev));
|
|
skb_reset_network_header(newskb);
|
|
newskb->dev = sd->dev;
|
|
newskb->protocol = htons(MY_PROTO_ID);
|
|
//Build the MAC header for the new packet
|
|
// Tu http://lxr.linux.no/linux+*/net/ipv4/arp.c#L586 jest pokazane jak zbudować pakiet!
|
|
if (dev_hard_header(newskb,sd->dev,MY_PROTO_ID,&sd->mac,sd->dev->dev_addr,MY_ACK_LEN+ETH_HLEN) < 0)
|
|
{
|
|
kfree_skb(newskb);
|
|
return -EINVAL;
|
|
}
|
|
//Put the protocol version id to the packet
|
|
put_skb_u16(newskb,MY_PROTO_VER);
|
|
//Put the command code
|
|
put_skb_u16(newskb,cmd);
|
|
//Put the sequence number
|
|
put_skb_u16(newskb,sd->cmd_seq);
|
|
//Put the argument
|
|
put_skb_u32(newskb,arg);
|
|
//Fill the packet
|
|
my_data = skb_put(newskb,MY_ACK_LEN-10);
|
|
memset(my_data,0xa5,MY_ACK_LEN-10);
|
|
dev_queue_xmit(newskb);
|
|
//Sleep with short timeout, waiting for response
|
|
if(wait_event_timeout(usercmd_queue,sd->cmd_ack==2,timeout)) {
|
|
//Response received
|
|
//If target buffer provided, copy data to the userspace buffer
|
|
if(resp) memcpy(resp,sd->cmd_resp,12);
|
|
result = SUCCESS;
|
|
break; //exit loop
|
|
}
|
|
}
|
|
//We don't wait for response any more
|
|
sd->cmd_ack = 0;
|
|
mutex_unlock(&sd->usercmd_lock);
|
|
return result;
|
|
}
|
|
|
|
/* Function free_mac may be safely called even if the MAC was not taken
|
|
it checks sd->active to detect such situation
|
|
*/
|
|
static inline
|
|
long free_mac(slave_data *sd) {
|
|
write_lock_bh(&slave_table_lock);
|
|
if(sd->active) {
|
|
/* Clear the MAC address */
|
|
sd->active = 0;
|
|
memset(&sd->mac,0,ETH_ALEN);
|
|
write_unlock_bh(&slave_table_lock);
|
|
/* Now send the "stop transmission" packet to the slave */
|
|
/* Find the net device */
|
|
if (!sd->dev) return -ENODEV;
|
|
dev_put(sd->dev);
|
|
sd->dev=NULL;
|
|
} else {
|
|
write_unlock_bh(&slave_table_lock);
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
static long my_proto1_ioctl (struct file *filp,
|
static long my_proto1_ioctl (struct file *filp,
|
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
{
|
{
|
slave_data * sd = filp->private_data;
|
slave_data * sd = filp->private_data;
|
if (_IOC_TYPE(cmd) != L3_V1_IOC_MAGIC) {
|
if (_IOC_TYPE(cmd) != L3_V1_IOC_MAGIC) {
|
Line 241... |
Line 329... |
return -EFAULT;
|
return -EFAULT;
|
} else {
|
} else {
|
read_lock_bh(&sd->ptrs_lock);
|
read_lock_bh(&sd->ptrs_lock);
|
bp.head=sd->head;
|
bp.head=sd->head;
|
bp.tail=sd->tail;
|
bp.tail=sd->tail;
|
|
bp.eof=sd->eof_flag;
|
read_unlock_bh(&sd->ptrs_lock);
|
read_unlock_bh(&sd->ptrs_lock);
|
res2 = __copy_to_user(res,&bp,sizeof(bp));
|
res2 = __copy_to_user(res,&bp,sizeof(bp));
|
if(res2)
|
if(res2)
|
return -EFAULT;
|
return -EFAULT;
|
if (sd->err_flag)
|
if (sd->err_flag)
|
Line 279... |
Line 368... |
write_unlock_bh(&sd->ptrs_lock);
|
write_unlock_bh(&sd->ptrs_lock);
|
return SUCCESS;
|
return SUCCESS;
|
}
|
}
|
case L3_V1_IOC_STARTMAC: //Open the slave
|
case L3_V1_IOC_STARTMAC: //Open the slave
|
{
|
{
|
struct sk_buff *newskb = NULL;
|
sd->stopped_flag = 0;
|
char * my_data = NULL;
|
sd->eof_flag = 0;
|
newskb = alloc_skb(LL_RESERVED_SPACE(sd->dev)+MY_ACK_LEN, GFP_KERNEL);
|
//We just send a request to start transmission and wait for confirmation
|
skb_reserve(newskb,LL_RESERVED_SPACE(sd->dev));
|
return send_cmd(sd,FCMD_START,0,NULL,100,2);
|
skb_reset_network_header(newskb);
|
|
newskb->dev = sd->dev;
|
|
newskb->protocol = htons(MY_PROTO_ID);
|
|
//Build the MAC header for the new packet
|
|
// Based on http://lxr.linux.no/#linux+v3.3.4/net/ipv4/arp.c#L586 !
|
|
if (dev_hard_header(newskb,sd->dev,MY_PROTO_ID,&sd->mac,sd->dev->dev_addr,MY_ACK_LEN+ETH_HLEN) < 0) {
|
|
kfree_skb(newskb);
|
|
return -EINVAL;
|
|
}
|
}
|
//Put the protocol version id to the packet
|
case L3_V1_IOC_STOPMAC: //Close the slave and reset it to stop transmission immediately
|
put_skb_u16(newskb,MY_PROTO_VER);
|
{
|
//Put the "start" command to the packet
|
return send_cmd(sd,FCMD_STOP,0,NULL,100,2);
|
put_skb_u16(newskb,0x01);
|
}
|
my_data = skb_put(newskb,MY_ACK_LEN - 4);
|
case L3_V1_IOC_RESETMAC: //Reset MAC so, that it stops transmission immediately
|
memset(my_data,0xa5,MY_ACK_LEN - 4);
|
{
|
#ifdef FADE_DEBUG
|
return send_cmd(sd,FCMD_RESET,0,NULL,100,2);
|
printk(KERN_INFO "skb_nh: %x, skb_dt: %x, skb_nh2: %x, skb_t: %x\n tail: %d head: %d\n",(int)skb_network_header(newskb),(int)newskb->data,
|
|
(int)newskb->network_header,(int)newskb->tail, (int)sd->tail, (int)sd->head) ;
|
|
#endif
|
|
dev_queue_xmit(newskb);
|
|
return SUCCESS;
|
|
}
|
}
|
case L3_V1_IOC_GETMAC: //Open the slave
|
case L3_V1_IOC_GETMAC: //Open the slave
|
{
|
{
|
void * source = (void *) arg;
|
void * source = (void *) arg;
|
struct l3_v1_slave sl;
|
struct l3_v1_slave sl;
|
Line 346... |
Line 422... |
sd->dev = dev;
|
sd->dev = dev;
|
return SUCCESS;
|
return SUCCESS;
|
}
|
}
|
case L3_V1_IOC_FREEMAC: //Close the slave and reset it to stop transmission immediately
|
case L3_V1_IOC_FREEMAC: //Close the slave and reset it to stop transmission immediately
|
{
|
{
|
write_lock_bh(&slave_table_lock);
|
free_mac(sd);
|
/* Clear the MAC address */
|
|
sd->active = 0;
|
|
memset(&sd->mac,0,ETH_ALEN);
|
|
write_unlock_bh(&slave_table_lock);
|
|
/* Now send the "stop transmission" packet to the slave */
|
|
/* Find the net device */
|
|
if (!sd->dev) return -ENODEV;
|
|
dev_put(sd->dev);
|
|
sd->dev=NULL;
|
|
return SUCCESS;
|
|
}
|
|
case L3_V1_IOC_STOPMAC: //Close the slave and reset it to stop transmission immediately
|
|
{
|
|
struct sk_buff *newskb = NULL;
|
|
char * my_data = NULL;
|
|
if (!sd->dev) return -ENODEV;
|
|
newskb = alloc_skb(LL_RESERVED_SPACE(sd->dev)+MY_ACK_LEN, GFP_ATOMIC);
|
|
skb_reserve(newskb,LL_RESERVED_SPACE(sd->dev));
|
|
skb_reset_network_header(newskb);
|
|
newskb->dev = sd->dev;
|
|
newskb->protocol = htons(MY_PROTO_ID);
|
|
//Build the MAC header for the new packet
|
|
// Based on http://lxr.linux.no/#linux+v3.3.4/net/ipv4/arp.c#L586 !
|
|
if (dev_hard_header(newskb,sd->dev,MY_PROTO_ID,&sd->mac,sd->dev->dev_addr,MY_ACK_LEN+ETH_HLEN) < 0) {
|
|
kfree_skb(newskb);
|
|
return -EINVAL;
|
|
}
|
|
//Put the protocol version id to the packet
|
|
put_skb_u16(newskb,MY_PROTO_VER);
|
|
//Put the "stop" command to the packet
|
|
put_skb_u16(newskb,0x05);
|
|
my_data = skb_put(newskb,MY_ACK_LEN - 4);
|
|
memset(my_data,0xa5,MY_ACK_LEN - 4);
|
|
#ifdef FADE_DEBUG
|
|
printk(KERN_INFO "skb_nh: %x, skb_dt: %x, skb_nh2: %x, skb_t: %x\n tail: %d head: %d\n",(int)skb_network_header(newskb),(int)newskb->data,
|
|
(int)newskb->network_header,(int)newskb->tail, (int)sd->tail, (int)sd->head) ;
|
|
#endif
|
|
dev_queue_xmit(newskb);
|
|
dev_put(sd->dev);
|
|
sd->dev=NULL;
|
|
return SUCCESS;
|
return SUCCESS;
|
}
|
}
|
case L3_V1_IOC_USERCMD: //Perform the user command
|
case L3_V1_IOC_USERCMD: //Perform the user command
|
{
|
{
|
void * source = (void *) arg;
|
void * source = (void *) arg;
|
Line 401... |
Line 437... |
if(result) {
|
if(result) {
|
return -EFAULT;
|
return -EFAULT;
|
}
|
}
|
//Now we check if the command is valid user command
|
//Now we check if the command is valid user command
|
if(ucmd.cmd < 0x0100) return -EINVAL;
|
if(ucmd.cmd < 0x0100) return -EINVAL;
|
//Each slave may perform only one user command, so first check, if no other thread
|
result = send_cmd(sd,ucmd.cmd, ucmd.arg, ucmd.resp, ucmd.nr_of_retries,ucmd.timeout);
|
//attempts to send the command
|
if(result<0) return result;
|
if ( mutex_trylock(&sd->usercmd_lock)==0) return -EBUSY;
|
|
//Mutex acquired, we can proceed
|
|
//First allocate the sequence number for the command
|
|
sd->cmd_seq += 1;
|
|
sd->cmd_code = ucmd.cmd;
|
|
sd->cmd_ack = 1; //Mark, that we are waiting for response
|
|
//Now in the loop we send the packet, requesting execution of the command
|
|
//and then we wait for response with timeout
|
|
while(ucmd.nr_of_retries--) {
|
|
//Send the packet
|
|
struct sk_buff *newskb = NULL;
|
|
uint8_t * my_data = NULL;
|
|
newskb = alloc_skb(LL_RESERVED_SPACE(sd->dev)+MY_ACK_LEN, GFP_KERNEL);
|
|
skb_reserve(newskb,LL_RESERVED_SPACE(sd->dev));
|
|
skb_reset_network_header(newskb);
|
|
newskb->dev = sd->dev;
|
|
newskb->protocol = htons(MY_PROTO_ID);
|
|
//Build the MAC header for the new packet
|
|
// Tu http://lxr.linux.no/linux+*/net/ipv4/arp.c#L586 jest pokazane jak zbudować pakiet!
|
|
if (dev_hard_header(newskb,sd->dev,MY_PROTO_ID,&sd->mac,sd->dev->dev_addr,MY_ACK_LEN+ETH_HLEN) < 0)
|
|
{
|
|
kfree_skb(newskb);
|
|
mutex_unlock(&sd->usercmd_lock);
|
|
return -EINVAL;
|
|
}
|
|
//Put the protocol version id to the packet
|
|
put_skb_u16(newskb,MY_PROTO_VER);
|
|
//Put the command code
|
|
put_skb_u16(newskb,ucmd.cmd);
|
|
//Put the sequence number
|
|
put_skb_u16(newskb,sd->cmd_seq);
|
|
//Put the argument
|
|
put_skb_u32(newskb,ucmd.arg);
|
|
//Fill the packet
|
|
my_data = skb_put(newskb,MY_ACK_LEN-10);
|
|
memset(my_data,0xa5,MY_ACK_LEN-10);
|
|
dev_queue_xmit(newskb);
|
|
//Sleep with short timeout, waiting for response
|
|
if(wait_event_timeout(usercmd_queue,sd->cmd_ack==2,ucmd.timeout)) {
|
|
//Response received
|
|
//Copy data to the userspace buffer
|
|
memcpy(&ucmd.resp,sd->cmd_resp,12);
|
|
result = __copy_to_user(source,&ucmd,sizeof(ucmd));
|
result = __copy_to_user(source,&ucmd,sizeof(ucmd));
|
if (result==0){
|
|
sd->cmd_ack = 0;
|
|
result = SUCCESS;
|
|
}
|
|
break; //exit loop
|
|
}
|
|
}
|
|
mutex_unlock(&sd->usercmd_lock);
|
|
return result;
|
return result;
|
}
|
}
|
}
|
}
|
return -EINVAL;
|
return -EINVAL;
|
}
|
}
|
Line 471... |
Line 457... |
unsigned int data_available;
|
unsigned int data_available;
|
poll_wait(filp,&read_queue,wait);
|
poll_wait(filp,&read_queue,wait);
|
read_lock_bh(&sd->ptrs_lock);
|
read_lock_bh(&sd->ptrs_lock);
|
data_available = (sd->head - sd->tail) & MY_BUF_LEN_MASK;
|
data_available = (sd->head - sd->tail) & MY_BUF_LEN_MASK;
|
if (data_available>=sd->rx_wakeup_thr) mask |= POLLIN |POLLRDNORM;
|
if (data_available>=sd->rx_wakeup_thr) mask |= POLLIN |POLLRDNORM;
|
|
if (sd->eof_flag) {
|
|
if(data_available) mask |= POLLIN | POLLRDNORM;
|
|
else mask |= POLLHUP;
|
|
}
|
#ifdef FADE_DEBUG
|
#ifdef FADE_DEBUG
|
printk(KERN_INFO "poll head: %d tail: %d data: %d prog: %d.\n",sd->head,sd->tail,data_available,sd->rx_wakeup_thr);
|
printk(KERN_INFO "poll head: %d tail: %d data: %d prog: %d.\n",sd->head,sd->tail,data_available,sd->rx_wakeup_thr);
|
#endif
|
#endif
|
//Check if the error occured
|
//Check if the error occured
|
if (sd->err_flag) mask |= POLLERR;
|
if (sd->err_flag) mask |= POLLERR;
|
Line 619... |
Line 609... |
slave_data * sd = NULL;
|
slave_data * sd = NULL;
|
int32_t pkt_dist;
|
int32_t pkt_dist;
|
char * my_data = NULL;
|
char * my_data = NULL;
|
unsigned char tmp_buf[USER_HDR_LEN];
|
unsigned char tmp_buf[USER_HDR_LEN];
|
char ack_packet = 0; //Should we acknowledge the packet?
|
char ack_packet = 0; //Should we acknowledge the packet?
|
|
uint32_t pkt_pos, needed_space, buf_free;
|
//Extract the MAC header from the received packet
|
//Extract the MAC header from the received packet
|
rcv_hdr=eth_hdr(skb);
|
rcv_hdr=eth_hdr(skb);
|
//First we try to identify the sender so we search the table of active slaves
|
//First we try to identify the sender so we search the table of active slaves
|
//The table is protected during the search, so it should not be changed
|
//The table is protected during the search, so it should not be changed
|
#ifdef FADE_DEBUG
|
#ifdef FADE_DEBUG
|
Line 659... |
Line 650... |
// Here is shown how to build a packet: http://lxr.linux.no/linux+*/net/ipv4/arp.c#L586
|
// Here is shown how to build a packet: http://lxr.linux.no/linux+*/net/ipv4/arp.c#L586
|
if (dev_hard_header(newskb,dev,MY_PROTO_ID,&rcv_hdr->h_source,&rcv_hdr->h_dest,MY_ACK_LEN+ETH_HLEN) < 0)
|
if (dev_hard_header(newskb,dev,MY_PROTO_ID,&rcv_hdr->h_source,&rcv_hdr->h_dest,MY_ACK_LEN+ETH_HLEN) < 0)
|
goto error;
|
goto error;
|
//Put the protocol version id to the packet
|
//Put the protocol version id to the packet
|
put_skb_u16(newskb,MY_PROTO_VER);
|
put_skb_u16(newskb,MY_PROTO_VER);
|
//Put the "restart" command to the packet
|
//Put the "restart" command to the packet, which should force it to stop transmission
|
put_skb_u16(newskb,0x05);
|
//immediately
|
|
put_skb_u16(newskb,FCMD_RESET);
|
my_data = skb_put(newskb,MY_ACK_LEN - 4);
|
my_data = skb_put(newskb,MY_ACK_LEN - 4);
|
memset(my_data,0xa5,MY_ACK_LEN - 4);
|
memset(my_data,0xa5,MY_ACK_LEN - 4);
|
dev_queue_xmit(newskb);
|
dev_queue_xmit(newskb);
|
kfree_skb(skb);
|
kfree_skb(skb);
|
return NET_RX_DROP;
|
return NET_RX_DROP;
|
Line 677... |
Line 669... |
//To avoid problems with scattered packets, we copy initial part of data to the buffer
|
//To avoid problems with scattered packets, we copy initial part of data to the buffer
|
//using the skb_copy_bits
|
//using the skb_copy_bits
|
skb_copy_bits(skb,0,tmp_buf,USER_HDR_LEN);
|
skb_copy_bits(skb,0,tmp_buf,USER_HDR_LEN);
|
/* We extract the information from the user header
|
/* We extract the information from the user header
|
* First we check if this is correct version of the protocol */
|
* First we check if this is correct version of the protocol */
|
if (unlikely(get_be_u16(&tmp_buf[0]) != MY_PROTO_VER))
|
if (unlikely(get_be_u16(&tmp_buf[0]) != MY_PROTO_VER)) goto wrong_pkt_type_error;
|
goto wrong_pkt_type_error;
|
|
if (unlikely(get_be_u16(&tmp_buf[2]) == 0xa55a)) {
|
if (unlikely(get_be_u16(&tmp_buf[2]) == 0xa55a)) {
|
//This is a command response packet
|
//This is a command response packet
|
printk(KERN_INFO " received command response packet");
|
printk(KERN_INFO " received command response packet");
|
if(sd->cmd_ack==1) {
|
if(sd->cmd_ack==1) {
|
//We are waiting for response
|
//We are waiting for response
|
Line 699... |
Line 690... |
}
|
}
|
}
|
}
|
kfree_skb(skb);
|
kfree_skb(skb);
|
return NET_RX_SUCCESS;
|
return NET_RX_SUCCESS;
|
}
|
}
|
if (unlikely(get_be_u16(&tmp_buf[2]) != 0xa5a5)) {
|
if (unlikely((get_be_u16(&tmp_buf[2]) != 0xa5a5) &&
|
|
(get_be_u16(&tmp_buf[2]) != 0xa5a6))
|
|
) {
|
//This is not a data packet
|
//This is not a data packet
|
goto wrong_pkt_type_error;
|
goto wrong_pkt_type_error;
|
}
|
}
|
/* Now we handle the data packet
|
/* Now we handle the data packet
|
PLEASE NOTE, THAT THIS MUST TIGHTLY CORRESPOND
|
PLEASE NOTE, THAT THIS MUST TIGHTLY CORRESPOND
|
Line 728... |
Line 721... |
/* To know if this is a new packet, we compare the packet number
|
/* To know if this is a new packet, we compare the packet number
|
* in the received packet with the number of the last unconfirmed packet,
|
* in the received packet with the number of the last unconfirmed packet,
|
* calculating the difference between those two numbers: */
|
* calculating the difference between those two numbers: */
|
read_lock_bh(&sd->pkts_rwlock);
|
read_lock_bh(&sd->pkts_rwlock);
|
pkt_dist=(int32_t) packet_number - (int32_t) sd->last_nack_pkt;
|
pkt_dist=(int32_t) packet_number - (int32_t) sd->last_nack_pkt;
|
//Check if this packet was already received
|
//Check if this packet was received before
|
is_duplicate=(sd->pkts[packet_number & PKTS_IN_WINDOW_MASK] == packet_number) ? 1 : 0;
|
is_duplicate=(sd->pkts[packet_number & PKTS_IN_WINDOW_MASK] == packet_number) ? 1 : 0;
|
read_unlock_bh(&sd->pkts_rwlock);
|
read_unlock_bh(&sd->pkts_rwlock);
|
if (likely((pkt_dist>=0) && (pkt_dist<PKTS_IN_WINDOW))) {
|
if (unlikely((pkt_dist<0) || (pkt_dist>=PKTS_IN_WINDOW))) {
|
/* This is the expected data packet. */
|
//This is a "too old" packet, or packet "from the future", which should not be transimtted
|
|
//by the FPGA
|
|
if (pkt_dist<0) {
|
|
// This is a packet which was already confirmed, but probably ACK was lost
|
|
#ifdef FADE_DEBUG
|
|
printk(KERN_INFO "Packet already confirmed: pkt=%d expect=%d last=%d\n",packet_number, sd->pkts[packet_number], sd->last_nack_pkt);
|
|
#endif
|
|
ack_packet = 1;
|
|
goto confirm;
|
|
} else {
|
|
/* This is a packet with too high set number (packet "from the future"
|
|
* it my be a symptom of serious communication problem! */
|
|
printk(KERN_ERR "Packet from the future! number: %d last_confirmed: %d\n", packet_number, sd->last_nack_pkt);
|
|
goto error2;
|
|
}
|
|
}
|
|
//If we get there, it means, that:
|
|
// pkt_dist >= 0 and pkt_dist < PKTS_IN_WINDOW
|
|
// So this is an expected data packet.
|
if(is_duplicate) {
|
if(is_duplicate) {
|
//Packet already confirmed, probably the ACK was lost, so simply generate the ACK
|
//Packet already confirmed, probably the ACK was lost, so simply generate the ACK
|
ack_packet = 1;
|
ack_packet = 1;
|
} else {
|
goto confirm;
|
//First check, if there is a free space to copy data
|
}
|
uint32_t pkt_pos, needed_space, buf_free;
|
//Packet not confirmed yet. Confirm it only after all processing is successfully completed
|
pkt_pos=(packet_number<<LOG2_USER_LEN) & MY_BUF_LEN_MASK;
|
pkt_pos=(packet_number<<LOG2_USER_LEN) & MY_BUF_LEN_MASK;
|
//We must be sure, that the pointers do not change during this check
|
//We must be sure, that the pointers do not change during this check
|
read_lock_bh(&sd->ptrs_lock);
|
read_lock_bh(&sd->ptrs_lock);
|
//Calculate free space needed to copy the packet
|
//Calculate free space needed to copy the packet
|
needed_space = (pkt_pos+USER_LEN-1-(sd->head)) & MY_BUF_LEN_MASK;
|
needed_space = (pkt_pos+USER_LEN-1-(sd->head)) & MY_BUF_LEN_MASK;
|
Line 751... |
Line 762... |
#ifdef FADE_DEBUG
|
#ifdef FADE_DEBUG
|
printk(KERN_INFO "packet_nr: %d Free buffer: %d needed space: %d head=%d last_nack=%d\n",
|
printk(KERN_INFO "packet_nr: %d Free buffer: %d needed space: %d head=%d last_nack=%d\n",
|
packet_number, needed_space, buf_free, sd->head, sd->last_nack_pkt);
|
packet_number, needed_space, buf_free, sd->head, sd->last_nack_pkt);
|
#endif
|
#endif
|
read_unlock_bh(&sd->ptrs_lock);
|
read_unlock_bh(&sd->ptrs_lock);
|
if (likely( buf_free > needed_space )) {
|
if (unlikely( buf_free <= needed_space )) goto error2; //No place for copying, drop the packet
|
// Check the length of the package
|
// Check the length of the package
|
if (unlikely(skb->len != PAYL_LEN)) {
|
if (unlikely(skb->len != PAYL_LEN)) {
|
printk(KERN_ERR "Error! Length of data should be %d but is %d!\n",PAYL_LEN, skb->len);
|
printk(KERN_ERR "Error! Length of data should be %d but is %d!\n",PAYL_LEN, skb->len);
|
sd->err_flag |= FADE_ERR_INCORRECT_LENGTH;
|
sd->err_flag |= FADE_ERR_INCORRECT_LENGTH;
|
kfree_skb(skb);
|
goto error2;
|
return NET_RX_DROP;
|
|
}
|
}
|
// We can safely copy all the packet to the buffer:
|
// We can safely copy all the packet to the buffer:
|
res = skb_copy_bits(skb,USER_HDR_LEN,&(sd->buffer[pkt_pos]),USER_LEN);
|
res = skb_copy_bits(skb,USER_HDR_LEN,&(sd->buffer[pkt_pos]),USER_LEN);
|
#ifdef FADE_DEBUG
|
#ifdef FADE_DEBUG
|
printk(KERN_INFO " skb_copy_bits: %d", res);
|
printk(KERN_INFO " skb_copy_bits: %d", res);
|
#endif
|
#endif
|
|
if (res<0) goto error2; //Unsuccessfull copying
|
//Packet was copied, so note, that we should confirm it
|
//Packet was copied, so note, that we should confirm it
|
if (res>=0) {
|
|
ack_packet=1;
|
ack_packet=1;
|
|
/* When packet is copied, we can check if this is the last "flushed" packet */
|
|
if (get_be_u16(&tmp_buf[2])==0xa5a6) {
|
|
//Flushed packet, store its number and length (should it be protected with spinlock?)
|
|
sd->last_pkt_num = packet_number;
|
|
//Copy the length, truncating it from 64 bits
|
|
sd->last_pkt_len = (uint32_t) * (uint64_t *) &(sd->buffer[pkt_pos+USER_LEN-sizeof(uint64_t)]);
|
|
//We have received the "flushed" buffer, mark that transmission is stopped
|
|
sd->stopped_flag = 1;
|
|
}
|
/* We modify the number of the copied packet in the pkts array, to avoid
|
/* We modify the number of the copied packet in the pkts array, to avoid
|
* unnecessary copying if we receive a duplicate
|
* unnecessary copying if we receive a duplicate
|
* To modify the pkts table, we must close pkts_rwlock for writing */
|
* To modify the pkts table, we must close pkts_rwlock for writing */
|
write_lock_bh(&sd->pkts_rwlock);
|
write_lock_bh(&sd->pkts_rwlock);
|
sd->pkts[packet_number & PKTS_IN_WINDOW_MASK]= packet_number;
|
sd->pkts[packet_number & PKTS_IN_WINDOW_MASK]= packet_number;
|
Line 786... |
Line 805... |
if (sd->pkts[(sd->last_nack_pkt + count) & PKTS_IN_WINDOW_MASK] != chk_packet_num) break; //Packet not confirmed
|
if (sd->pkts[(sd->last_nack_pkt + count) & PKTS_IN_WINDOW_MASK] != chk_packet_num) break; //Packet not confirmed
|
chk_packet_num++;
|
chk_packet_num++;
|
}
|
}
|
sd->last_nack_pkt += count;
|
sd->last_nack_pkt += count;
|
write_unlock_bh(&sd->pkts_rwlock);
|
write_unlock_bh(&sd->pkts_rwlock);
|
/* Now we can move the head position right after the last serviced packet */
|
/* Now we can move the head position */
|
|
if(likely((sd->stopped_flag == 0) ||
|
|
((uint32_t)(sd->last_nack_pkt-1) != sd->last_pkt_num))) {
|
|
//Normal packet, set head right after the last serviced packet
|
write_lock_bh(&sd->ptrs_lock);
|
write_lock_bh(&sd->ptrs_lock);
|
sd->head = (sd->last_nack_pkt*USER_LEN) & MY_BUF_LEN_MASK;
|
sd->head = (sd->last_nack_pkt*USER_LEN) & MY_BUF_LEN_MASK;
|
/* When we have moved the head pointer, we can try to wake up the reading processes */
|
//Now try to wake up the reading process
|
|
if (((sd->head - sd->tail) & MY_BUF_LEN_MASK) >= sd->rx_wakeup_thr)
|
wake_up_interruptible(&read_queue);
|
wake_up_interruptible(&read_queue);
|
write_unlock_bh(&sd->ptrs_lock);
|
|
} else {
|
} else {
|
// It was not the last packet, no need to move the head pointer
|
//Flushed packet, set head right after the end of the packet
|
|
write_lock_bh(&sd->ptrs_lock);
|
|
sd->head = ((sd->last_nack_pkt-1)*USER_LEN+sd->last_pkt_len) & MY_BUF_LEN_MASK;
|
|
//We have consumed the last, "flushed" buffer, so now we can set the eof flag
|
|
sd-> eof_flag = 1;
|
|
//And we wake up the reading process
|
|
wake_up_interruptible(&read_queue);
|
|
} //if - stopped_flag
|
|
write_unlock_bh(&sd->ptrs_lock);
|
|
} else { // if - last_nack_pkt
|
write_unlock_bh(&sd->pkts_rwlock);
|
write_unlock_bh(&sd->pkts_rwlock);
|
}
|
}
|
}
|
confirm:
|
}
|
//Send the confirmation if required
|
}
|
|
} else {
|
|
/* This packet has incorrect set number. If the number is too low, we ignore the packet,
|
|
* but send the confirmation (ack was received too late, or was lost?) */
|
|
if (pkt_dist<0) {
|
|
ack_packet = 1;
|
|
#ifdef FADE_DEBUG
|
|
printk(KERN_INFO "Packet already confirmed: pkt=%d expect=%d last=%d\n",packet_number, sd->pkts[packet_number], sd->last_nack_pkt);
|
|
#endif
|
|
} else {
|
|
/* This is a packet with too high set number (packet "from the future"
|
|
* it my be a symptom of serious communication problem! */
|
|
printk(KERN_ERR "Packet from the future! number: %d last_confirmed: %d\n", packet_number, sd->last_nack_pkt);
|
|
}
|
|
}
|
|
//Now send the confirmation
|
|
if (likely(ack_packet)) {
|
if (likely(ack_packet)) {
|
newskb = alloc_skb(LL_RESERVED_SPACE(dev)+MY_ACK_LEN, GFP_ATOMIC);
|
newskb = alloc_skb(LL_RESERVED_SPACE(dev)+MY_ACK_LEN, GFP_ATOMIC);
|
skb_reserve(newskb,LL_RESERVED_SPACE(dev));
|
skb_reserve(newskb,LL_RESERVED_SPACE(dev));
|
skb_reset_network_header(newskb);
|
skb_reset_network_header(newskb);
|
newskb->dev = dev;
|
newskb->dev = dev;
|
Line 827... |
Line 842... |
if (dev_hard_header(newskb,dev,MY_PROTO_ID,&rcv_hdr->h_source,&rcv_hdr->h_dest,MY_ACK_LEN+ETH_HLEN) < 0)
|
if (dev_hard_header(newskb,dev,MY_PROTO_ID,&rcv_hdr->h_source,&rcv_hdr->h_dest,MY_ACK_LEN+ETH_HLEN) < 0)
|
goto error;
|
goto error;
|
//Put the protocol version id to the packet
|
//Put the protocol version id to the packet
|
put_skb_u16(newskb,MY_PROTO_VER);
|
put_skb_u16(newskb,MY_PROTO_VER);
|
//Put the "ACKNOWLEDGE" type
|
//Put the "ACKNOWLEDGE" type
|
put_skb_u16(newskb,0x03); //ACK!
|
put_skb_u16(newskb,FCMD_ACK);
|
//Copy the begining of the received packet to the acknowledge packet
|
//Copy the begining of the received packet to the acknowledge packet
|
my_data = skb_put(newskb,MY_ACK_COPIED);
|
my_data = skb_put(newskb,MY_ACK_COPIED);
|
res = skb_copy_bits(skb,4,my_data,MY_ACK_COPIED);
|
res = skb_copy_bits(skb,4,my_data,MY_ACK_COPIED);
|
my_data = skb_put(newskb,MY_ACK_LEN -MY_ACK_COPIED-4);
|
my_data = skb_put(newskb,MY_ACK_LEN -MY_ACK_COPIED-4);
|
memset(my_data,0xa5,MY_ACK_LEN - MY_ACK_COPIED-4);
|
memset(my_data,0xa5,MY_ACK_LEN - MY_ACK_COPIED-4);
|
Line 853... |
Line 868... |
} else {
|
} else {
|
printk(KERN_ERR "FADE: wrong_pkt_type_error called with null sd");
|
printk(KERN_ERR "FADE: wrong_pkt_type_error called with null sd");
|
}
|
}
|
error:
|
error:
|
if (newskb) kfree_skb(newskb);
|
if (newskb) kfree_skb(newskb);
|
|
error2:
|
if (skb) kfree_skb(skb);
|
if (skb) kfree_skb(skb);
|
return NET_RX_DROP;
|
return NET_RX_DROP;
|
}
|
}
|
|
|
/*
|
/*
|
Line 887... |
Line 903... |
if (!sd->buffer) return -ENOMEM;
|
if (!sd->buffer) return -ENOMEM;
|
//Set the MAC address to 0
|
//Set the MAC address to 0
|
memset(sd->mac,0,sizeof(sd->mac));
|
memset(sd->mac,0,sizeof(sd->mac));
|
sd->head = 0;
|
sd->head = 0;
|
sd->tail = 0;
|
sd->tail = 0;
|
|
sd->eof_flag = 0;
|
|
sd->stopped_flag = 0;
|
sd->err_flag = 0;
|
sd->err_flag = 0;
|
sd->last_nack_pkt = 0;
|
sd->last_nack_pkt = 0;
|
sd->rx_wakeup_thr = 1;
|
sd->rx_wakeup_thr = 1;
|
sd->active = 0;
|
sd->active = 0;
|
sd->cmd_seq = 0;
|
sd->cmd_seq = 0;
|
Line 902... |
Line 920... |
|
|
static int my_proto1_release(struct inode *inode,
|
static int my_proto1_release(struct inode *inode,
|
struct file *file)
|
struct file *file)
|
{
|
{
|
slave_data * sd = file->private_data;
|
slave_data * sd = file->private_data;
|
#ifdef FADE_DEBUG
|
//#ifdef FADE_DEBUG
|
printk (KERN_INFO "device_release(%p,%p)\n", inode, file);
|
printk (KERN_INFO "device_release(%p,%p)\n", inode, file);
|
#endif
|
//#endif
|
//Release resources associated with servicing of the particular device
|
//Release resources associated with servicing of the particular device
|
if (sd) {
|
if (sd) {
|
if (sd->is_open) {
|
if (sd->is_open) {
|
sd->is_open = 0; //It can be dangerous! Before freeing the buffer, we must be sure, that
|
sd->is_open = 0; //It can be dangerous! Before freeing the buffer, we must be sure, that
|
//no our packet is being processed!
|
//no our packet is being processed!
|
if (sd->active) {
|
printk (KERN_INFO "freed MAC\n");
|
sd->active = 0;
|
free_mac(sd); //It also sets sd->active to 0!
|
}
|
|
if (sd->buffer) {
|
if (sd->buffer) {
|
|
printk (KERN_INFO "freed buffer\n");
|
vfree(sd->buffer);
|
vfree(sd->buffer);
|
sd->buffer = NULL;
|
sd->buffer = NULL;
|
}
|
}
|
}
|
}
|
}
|
}
|