⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dmfe.c

📁 A Davicom DM9102A NIC fast ethernet driver for Linux.
💻 C
📖 第 1 页 / 共 5 页
字号:
#if 0
	/* show statistic counter */
	printk("<DM9XS>: FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
		db->tx_fifo_underrun, db->tx_excessive_collision,
		db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
		db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
		db->reset_fatal, db->reset_TXtimeout);
#endif

 return 0;
}

/*
  DM9102 insterrupt handler
  receive the packet to upper layer, free the transmitted packet
*/
#ifdef SA_SHIRQ
static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#else
static void dmfe_interrupt(int irq, struct pt_regs *regs)
#endif
{
#ifdef SA_SHIRQ
 struct DEVICE *dev=dev_id;
#else
 struct DEVICE *dev = (struct DEVICE *)(irq2dev_map[irq]);
#endif
 struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
 u32 ioaddr = dev->base_addr;

 DMFE_DBUG(0, "dmfe_interrupt()", 0);

 if (!dev) 
   {
    DMFE_DBUG(1, "dmfe_interrupt() without DEVICE arg", 0);
    return;
   }

 /* Got DM910X status */
 db->cr5_data=inl(ioaddr+DCR5);
 outl(db->cr5_data, ioaddr+DCR5);
 if ( !(db->cr5_data & 0xc1) )
	return;

/* Disable MAC interrupt in CR7 to solve the interrupt edge problem */
 outl(0, ioaddr+DCR7);

 /* Check system status */
 if (db->cr5_data & 0x2000)
   {
    /* system bus error happen */
    DMFE_DBUG(1, "System bus error happen. CR5=", db->cr5_data);
#if LINUX_VERSION_CODE < 0x20400
    dev->tbusy=1;
#else
    netif_stop_queue(dev);
#endif
    db->reset_fatal++;
    db->wait_reset=1;           /* Need to RESET */
    return;
   }

 /* Received the coming packet */
 if ( (db->cr5_data & 0x40) && db->rx_avail_cnt )
	dmfe_rx_packet(dev, db);

 /* reallocated rx descriptor buffer */
 if (db->rx_avail_cnt<RX_DESC_CNT)
    allocated_rx_buffer(db);

 /* Free the transmitted descriptor */
 //if ( db->cr5_data & 0x01)
	dmfe_free_tx_pkt(dev, db);
// mark_bh(NET_BH);	/* Active upper layer */

 /* Mode Check */
 if (db->dm910x_chk_mode & 0x2)
   {
    db->dm910x_chk_mode = 0x4;
    db->cr6_data |= 0x100;
    update_cr6(db->cr6_data, db->ioaddr);
   }

/* Restore CR7 to enable MAC interrupt mask */ 
 outl(db->cr7_data, ioaddr+DCR7);
}

/*
 *	Free TX resource after TX complete
 */

static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
{
	struct tx_desc *txptr;
	u32 ioaddr = dev->base_addr; 

	txptr = db->tx_remove_ptr;
	while(db->tx_packet_cnt) {
		/* printk("<DMFE>: tdes0=%x\n", txptr->tdes0); */
		if (txptr->tdes0 & 0x80000000)
			break;

		/* A packet sent completed */
		db->tx_packet_cnt--;
		db->stats.tx_packets++;

		/* Transmit statistic counter */
		if ( txptr->tdes0 != 0x7fffffff ) {
			/* printk("<DMFE>: tdes0=%x\n", txptr->tdes0); */
			db->stats.collisions += (txptr->tdes0 >> 3) & 0xf;
#if LINUX_VERSION_CODE > 0x20127
			db->stats.tx_bytes += txptr->tdes1 & 0x7ff;
#endif
			if (txptr->tdes0 & TDES0_ERR_MASK) {
				db->stats.tx_errors++;
	
				if (txptr->tdes0 & 0x0002) {	/* UnderRun */
					db->tx_fifo_underrun++;
					if ( !(db->cr6_data & CR6_SFT) ) {
						db->cr6_data = db->cr6_data | CR6_SFT;
						update_cr6(db->cr6_data, db->ioaddr);
					}
				}
				if (txptr->tdes0 & 0x0100)
					db->tx_excessive_collision++;
				if (txptr->tdes0 & 0x0200) 
					db->tx_late_collision++;
				if (txptr->tdes0 & 0x0400) 
					db->tx_no_carrier++;
				if (txptr->tdes0 & 0x0800) 
					db->tx_loss_carrier++;
				if (txptr->tdes0 & 0x4000) 
					db->tx_jabber_timeout++;
			}
		}

    		txptr = (struct tx_desc *) txptr->next_tx_desc;
	}/* End of while */
 
	/* Update TX remove pointer to next */
	db->tx_remove_ptr = (struct tx_desc *) txptr;

	/* Send the Tx packet in queue */
	if ( (db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt ) {
		txptr->tdes0 = 0x80000000;		/* Set owner bit */
		db->tx_packet_cnt++;			/* Ready to send */
		db->tx_queue_cnt--;
		outl(0x1, ioaddr + DCR1);		/* Issue Tx polling */
		dev->trans_start = jiffies;		/* saved time stamp */
	}

	/* Resource available check */
 	if ( db->tx_queue_cnt < TX_WAKE_DESC_CNT )
#if LINUX_VERSION_CODE < 0x20400
		{ dev->tbusy=0; mark_bh(NET_BH); }	/* Active upper layer */
#else
		netif_wake_queue(dev);			/* Active upper layer */
#endif
}

/*
  Receive the come packet and pass to upper layer
*/
static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
{
 struct rx_desc *rxptr;
 struct sk_buff *skb;
 int rxlen;

 rxptr=db->rx_ready_ptr;

 while(db->rx_avail_cnt)
   {
    if (rxptr->rdes0 & 0x80000000)              /* packet owner check */
       break;

    db->rx_avail_cnt--;
    db->interval_rx_cnt++;

    if ((rxptr->rdes0 & 0x300)!=0x300)
      {
       /* A packet without First/Last flag */
       /* reused this SKB */
       DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0);
       dmfe_reused_skb(db, (struct sk_buff *)rxptr->rx_skb_ptr);
      }
    else
      {
       /* A packet with First/Last flag */
       rxlen=((rxptr->rdes0 >> 16) & 0x3fff) - 4;               /* skip CRC */

       if (rxptr->rdes0 & 0x8000)       /* error summary bit check */
         {
          /* This is a error packet */
          /* printk("rdes0 error : %x \n", rxptr->rdes0); */
          db->stats.rx_errors++;
          if (rxptr->rdes0 & 1) db->stats.rx_fifo_errors++;
          if (rxptr->rdes0 & 2) db->stats.rx_crc_errors++;
          if (rxptr->rdes0 & 0x80) db->stats.rx_length_errors++;
         }

       if ( !(rxptr->rdes0 & 0x8000) ||
            ((db->cr6_data & CR6_PM) && (rxlen>6)) )
         {
          skb=(struct sk_buff *)rxptr->rx_skb_ptr; 

	  /* Received Packet CRC check need or not */
          if ( (db->dm910x_chk_mode & 1) && (cal_CRC(skb->tail, rxlen, 1)!=(*(unsigned long *)(skb->tail+rxlen))) )
    	    {
	     /* Found a error received packet */
             dmfe_reused_skb(db, (struct sk_buff *)rxptr->rx_skb_ptr);
	     db->dm910x_chk_mode = 3;
	    } 
	  else
	    {
	     /* A good packet coming, send to upper layer */
	     /* Shorst packet used new SKB */
	     if ( (rxlen<RX_COPY_SIZE) && ((skb=dev_alloc_skb(rxlen+2))!=NULL) )
               {
 		/* Rx packet size less than COPY_SIZE, allocated a rxlen SKB */
		skb->dev=dev;
		skb_reserve(skb, 2); /* 16byte align */
		memcpy(skb_put(skb, rxlen), ((struct sk_buff *)rxptr->rx_skb_ptr)->tail, rxlen);
                dmfe_reused_skb(db, (struct sk_buff *)rxptr->rx_skb_ptr);
               }
	     else
               {
		/* Pass this Rx buffer to upper layer */
                skb->dev=dev;
                skb_put(skb, rxlen);
               }
             skb->protocol=eth_type_trans(skb, dev);
             netif_rx(skb);                /* Send to upper layer */
	     dev->last_rx = jiffies;
             db->stats.rx_packets++;
#if LINUX_VERSION_CODE > 0x20127
             db->stats.rx_bytes+=rxlen;
#endif
	    }
         }
       else
         {
	  /* Reuse SKB buffer when the packet is error */
          DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0);
          dmfe_reused_skb(db, (struct sk_buff *)rxptr->rx_skb_ptr);
         }
      }

    rxptr=(struct rx_desc *)rxptr->next_rx_desc;
   }

 db->rx_ready_ptr=rxptr;

}

/*
  Get statistics from driver.
*/
#if LINUX_VERSION_CODE < 0x20400
static struct enet_statistics * dmfe_get_stats(struct DEVICE *dev)
#else
static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev)
#endif
{
 struct dmfe_board_info *db=(struct dmfe_board_info *)dev->priv;

 DMFE_DBUG(0, "dmfe_get_stats", 0);
 return &db->stats;
}

/*
  Set DM910X multicast address
*/
static void dmfe_set_filter_mode(struct DEVICE * dev)
{
 struct dmfe_board_info *db=dev->priv;

 DMFE_DBUG(0, "dmfe_set_filter_mode()", 0);

 if (dev->flags & IFF_PROMISC)
   {
    DMFE_DBUG(0, "Enable PROM Mode", 0);
    db->cr6_data |=CR6_PM | CR6_PBF;
    update_cr6(db->cr6_data, db->ioaddr);
    return;
   }

 if (dev->flags & IFF_ALLMULTI || dev->mc_count > DMFE_MAX_MULTICAST)
   {
    DMFE_DBUG(0, "Pass all multicast address", dev->mc_count);
    db->cr6_data&=~(CR6_PM | CR6_PBF);
    db->cr6_data|=CR6_PAM;
    return;
   }

 DMFE_DBUG(0, "Set multicast address", dev->mc_count);
 if (db->chip_id == PCI_DM9132_ID)
    dm9132_id_table(dev, dev->mc_count);	/* DM9132 */
 else
    send_filter_frame(dev, dev->mc_count); 	/* DM9102/DM9102A */
}

/*
  Process the upper socket ioctl command
*/
static int dmfe_do_ioctl(struct DEVICE *dev, struct ifreq *ifr, int cmd)
{
 DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
 return 0;
}

/*
  A periodic timer routine
  Dynamic media sense, allocated Rx buffer...
*/
static void dmfe_timer(unsigned long data)
{
 u32 tmp_cr8;
 unsigned char tmp_cr12;
 struct DEVICE *dev=(struct DEVICE *)data;
 struct dmfe_board_info *db=(struct dmfe_board_info *)dev->priv;
 
 DMFE_DBUG(0, "dmfe_timer()", 0);

 /* Media mode process when Link OK before enter this route */
 if (db->first_in_callback==0)
   {
    db->first_in_callback=1;
    if (db->chip_type && (db->chip_id==PCI_DM9102_ID))
      {
	db->cr6_data &= ~0x40000;
	update_cr6(db->cr6_data, db->ioaddr);
       phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
	db->cr6_data |= 0x40000;
	update_cr6(db->cr6_data, db->ioaddr);
       db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
       add_timer(&db->timer);
       return;
      }
   }

 /* Operating Mode Check */
 if ((db->dm910x_chk_mode & 0x1) && (db->stats.rx_packets > MAX_CHECK_PACKET) )
   {
    db->dm910x_chk_mode = 0x4;
   }

 /* Dynamic reset DM910X : system error or transmit time-out */
 tmp_cr8=inl(db->ioaddr+DCR8);
 if ((db->interval_rx_cnt==0) && (tmp_cr8))
   {
    db->reset_cr8++;
    db->wait_reset=1;
   }
 db->interval_rx_cnt=0;

 /* TX polling kick monitor */
 if ( db->tx_packet_cnt && 
	((jiffies - dev->trans_start) > DMFE_TX_KICK) )
   {
    outl(0x1, dev->base_addr + DCR1);   /* Tx polling again */

    /* TX Timeout */
    if ( db->tx_packet_cnt && ((jiffies - dev->trans_start) > DMFE_TX_TIMEOUT) )
      {
       db->reset_TXtimeout++;
       db->wait_reset = 1;
      }
   }

 if (db->wait_reset)
   {
    DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx moniotr step1", db->tx_packet_cnt);
    db->reset_count++;
    dmfe_dynamic_reset(dev);
    db->first_in_callback=0;
    db->timer.expires = DMFE_TIMER_WUT;
    add_timer(&db->timer);
    return;
   }

 /* Link status check, Dynamic media type change */
 if (db->chip_id == PCI_DM9132_ID) 
    tmp_cr12=inb(db->ioaddr+DCR9+3);		/* DM9132 */
 else
    tmp_cr12=inb(db->ioaddr+DCR12);		/* DM9102/DM9102A */

 if ( ((db->chip_id == PCI_DM9102_ID) && (db->chip_revision == 0x02000030)) ||
      ((db->chip_id == PCI_DM9132_ID) && (db->chip_revision == 0x02000010)) )
   {
    /* DM9102A Chip */
    if (tmp_cr12 & 2)
       tmp_cr12=0x0;		/* Link failed */
    else tmp_cr12=0x3;		/* Link OK */
   }

 if (!(tmp_cr12 & 0x3) && !db->link_failed)
   {
    /* Link Failed */
    DMFE_DBUG(0, "Link Failed", tmp_cr12);
    db->link_failed=1;

    /* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
    /* AUTO or force 1M Homerun/Longrun don't need */
    if ( !(db->media_mode & 0x38) )
       phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);

    /* In AUTO mode, if INT phyxcer link failed, select EXT device */
    if (db->media_mode & DMFE_AUTO)
      {
       /* 10/100M link failed, used 1M Home-Net */
       db->cr6_data|=0x00040000;	/* CR6 bit18 = 1, select Home-Net */
       db->cr6_data&=~0x00000200;	/* CR6 bit9 =0, half duplex mode */
       update_cr6(db->cr6_data, db->ioaddr);
      } 
   }
 else if ((tmp_cr12 & 0x3) && db->link_failed)
        {
         DMFE_DBUG(0, "Link link OK", tmp_cr12);
         db->link_failed=0;
	 
	 /* Auto Sense Speed */
         if (db->media_mode & DMFE_AUTO)
            if (dmfe_sense_speed(db))
 		db->link_failed=1;
         dmfe_process_mode(db);
         /* SHOW_MEDIA_TYPE(db->op_mode); */
        } 

 /* HPNA remote command check */
 if (db->HPNA_command & 0xf00)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -