Hi

I have written a driver to the new hardware. It is serial, synchronous,
ISA
based, communication card but it doesn't meter now. It is mmio driven with
IRQ's without DMA on the ISA.

I send pure TCP/IP packets without any hardware headers etc... It's like
point-to-point through completely transparent hardware.

When I send a packet which is smaller or equal to the actually set MTU
value then everything work perfectly.

The problem starts when I try to send a packet which is grater then
actually set MTU.

As expected, the larger packet is fragmented into smaller parts and it
goes
to the second machine. It is received by the second machine but it is
lost.
It looks like the second computer does not react on it when receives
fragments.

But if I send fragments with delay (udelay(100)) or more then the second
computer recognizes it sometimes and responds properly.
Normal packets below MTU size don't need any delay.


When I set larger value of MTU I can ping with the packet size up to the
new MTU.

Again, when I send packets of a size less then MTU then it works great.

I attached source files here. Please look at it, maybe I miss something or
I don't know about some additional issues.

Please help.

Regards,
Benedykt Kroplewski
/* v35.c  
 * Copyright (C) 1999-2000 by Benedykt Kroplewski
 * e-mail: [EMAIL PROTECTED] ,tel. 0-501-853172
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/errno.h>
#include <linux/init.h>  
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/if_slip.h>
#include <linux/delay.h>
#define MTU 1500
#define DOFF 0x10               /*  Data offset */
#define ROFF 0x8                /* Registers offset 0x8 */
static long base = 0x00000;
#include "bin.h"
#include "db.c"

int v35_init(struct device *dev);
static void v35_interrupt(int irq, void *dev_id, struct pt_regs * regs);
static int v35_open(struct device *dev);
static int v35_stop(struct device *dev);
static int v35_send(struct sk_buff *skb, struct device *dev);
static struct net_device_stats *v35_stat(struct device *dev); 


static const char *version =
        "v35.c:v1.0 1999 Benedykt Kroplewski ([EMAIL PROTECTED])\n";
static const char* irqname = "v35card";
static char v35name[10] = {"wan0\0"};
static struct device v35dev = { v35name,0,0,0,0,0,0,0,0,0,NULL,v35_init };
static struct net_device_stats stats;
static int irq = 0;

MODULE_PARM(irq,"i");
MODULE_PARM(base,"i");
int v35_init(struct device *dev)
{
int irqval,i;

  printk("v35_init(%s);\n",dev->name);
  printk(KERN_DEBUG "%s", version);

  irqval = request_irq(dev->irq, &v35_interrupt, 0, irqname, dev);
  if (irqval) { printk("%s: unable to get IRQ %d (irqval=%d).\n",dev->name, dev->irq, 
irqval); return -EAGAIN; }


  initcard(dev->base_addr);

  for(i=0;i<20000;i++) readb(dev->base_addr+DOFF);
  printk("read 20 000 bytes\n");

  dev->open             = v35_open;
  dev->stop             = v35_stop;
  dev->hard_start_xmit  = v35_send;
  dev->get_stats        = v35_stat;
  dev->mtu              = 1500;
  dev->hard_header_len  = 0;
  dev->addr_len         = 0;
  dev->type             = ARPHRD_SLIP;
  dev->tx_queue_len     = 10;
  dev_init_buffers(dev);
  dev->flags            = IFF_NOARP|IFF_POINTOPOINT; 

  return 0;
}


static void v35_got(struct device *dev,int wielkosc)
{
struct sk_buff *skb;
int i;

        stats.rx_bytes+=wielkosc-3;
        skb = dev_alloc_skb(wielkosc-1);
        skb_put(skb,wielkosc-1);
        skb->dev = dev;


        for(i=0;i<=wielkosc-3;i++)
                *(skb->data+i) = readb(dev->base_addr+DOFF);

        skb->pkt_type = PACKET_HOST;
        skb->mac.raw=skb->data;
        skb->protocol=htons(ETH_P_IP);
        netif_rx(skb);
        stats.rx_packets++;


}

/* numer = numer & BIN00111111; --->  zerowanie pierwszych 2 bitow */
/* numer = numer ^ BIN11000000; --->  zapalanie pierwszych 2 bitow */


static void v35_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct device *dev = dev_id;
unsigned char reg1,reg3,reg7,reg6,znak,tmp;
int what_irq=0;
int wielkosc=0;
int error=0;
/* long flags; */

  dev->interrupt = 1;

/*
  save_flags(flags);
  cli();
*/

  reg3 = readregister(3,dev->base_addr);
/******************************* IRQ RX 
********************************************************/
  if((reg3 & 0x20) == 0x20)     
  {     what_irq++;
 readregister(2,dev->base_addr); 


do {
         reg7 = readregister(7,dev->base_addr);
         reg6 = readregister(6,dev->base_addr); 
         reg1 = readregister(1,dev->base_addr);

         if((reg1 & 0x10) == 0x10) /* bit 4 */
          { writeb(0x30,base+ROFF); error = 4; } /* E4 */
         if((reg1 & 0x20) == 0x20)  /* bit 5 */
          { writeb(0x30,base+ROFF); error = 5; } /* E5 */
         if((reg1 & 0x40) == 0x40)  /* bit 6 */
          { writeb(0x30,base+ROFF); error = 6; } /* E6 */
         if((reg1 & 0x80) == 0x80) ; /* bit 7 */

        tmp = reg7 & BIN00111111;
        wielkosc = tmp << 8;
        wielkosc = wielkosc + reg6;

        v35_got(dev,wielkosc);

        znak = readb(dev->base_addr+DOFF);
        znak = readb(dev->base_addr+DOFF);
        znak = readb(dev->base_addr+DOFF);
         reg7 = readregister(7,dev->base_addr); 
         reg7 = readregister(7,dev->base_addr);
 
}

while( (reg7 & BIN01000000) == BIN01000000 );
if(error != 0) printk("RX error nr. %d\n",error);


         writeb(0x38,base+ROFF);


    
printk("v35_interrupt(%s,Rx,%s,SIZE=%d,ERROR=%d);\n",dev->name,char2bin(reg3),wielkosc-3,error);
 
  } 

/************************************ IRQ TX 
*******************************************************/
        if((reg3 & 0x8) == 0x8)
        {   what_irq++;
            

        stats.tx_packets++;

        udelay(1000);

        dev->tbusy = 0;
        mark_bh(NET_BH); 

readregister(2,dev->base_addr);
         printk("v35_interrupt(%s,Tx,%s);\n",dev->name,char2bin(reg3)); 
        writeb(0x10,base+ROFF); 
        writeb(0x10,base+ROFF);
        writeb(0x38,base+ROFF);
       }


/***************************** IRQ unknown 
*********************************************************/
        if(what_irq == 0)
        { 
            readregister(2,dev->base_addr);
         
           printk("v35_interrupt(%s,UNKNOWN,%s);\n",dev->name,char2bin(reg3));
           writeb(0x10,base+ROFF);
           writeb(0x10,base+ROFF); 
           writeb(0x38,base+ROFF);
        }

/*
  restore_flags(flags);
*/

  dev->interrupt = 0;
  return;
}


static int v35_open(struct device *dev)
{
  printk("v35_open(%s);\n",dev->name);
  MOD_INC_USE_COUNT;
  dev->start = 1;
  dev->tbusy = 0;
  return 0;
}

static int v35_stop(struct device *dev)
{
  printk("v35_stop(%s);\n",dev->name);
  dev->start = 0;
  dev->tbusy = 1;
  free_irq(dev->irq, dev); 
  MOD_DEC_USE_COUNT;
  return 0;
}

long flags;

static int v35_send(struct sk_buff *skb, struct device *dev)
{
int len,i;
unsigned char *data;

  dev->trans_start = jiffies;

  len = skb->len;
  data = skb->data;
  
if(!dev->interrupt)
{

  save_flags(flags);
  cli();
     for(i=0;i<=len;i++) 
writeb(*(data+i),dev->base_addr+DOFF);
  dev->tbusy=1; 
  restore_flags(flags);
/*  printk("%s: transmit %d bytes\n",dev->name,len); */
  stats.tx_bytes+=skb->len;
  dev->trans_start = jiffies;

  dev_kfree_skb(skb);
}
  return 0;
}

static struct net_device_stats *v35_stat(struct device *dev)
{

return &stats;
}


int init_module(void)
{
int result;

  if(irq == 0) { printk("insmod v35.o irq=NUMER base=ADDRESS\n"); return 1; }
  if(base == 0) { printk("insmod v35.o irq=NUMER base=ADDRESS\n"); return 1; }

  v35dev.base_addr      = base;
  v35dev.irq            = irq;
  if((result = register_netdev(&v35dev)) != 0) return result; 

  return 0;
}




void cleanup_module(void)
{
  printk("cleanup_module();\n");
  
  unregister_netdev(&v35dev); 
}

/* end. */

Reply via email to