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

📄 dmfe.c

📁 A Davicom DM9102A NIC fast ethernet driver for Linux.
💻 C
📖 第 1 页 / 共 5 页
字号:
   {
    db->HPNA_timer--;
    if (!db->HPNA_timer)
       dmfe_HPNA_remote_cmd_chk(db);
   }

 /* Timer active again */
 db->timer.expires = DMFE_TIMER_WUT;
 add_timer(&db->timer);
}

/*
  Dynamic reset the DM910X board
  Stop DM910X board
  Free Tx/Rx allocated memory
  Reset DM910X board
  Re-initilize DM910X board
*/
static void dmfe_dynamic_reset(struct DEVICE *dev)
{
 struct dmfe_board_info *db=dev->priv;

 DMFE_DBUG(0, "dmfe_dynamic_reset()", 0);
 
 /* Disable upper layer interface */
#if LINUX_VERSION_CODE < 0x20400
 dev->tbusy=1;                          /* transmit packet disable */
 dev->start=0;                          /* interface not ready */
#else
 netif_stop_queue(dev);
#endif

 /* Stop MAC controller */
 db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);        /* Disable Tx/Rx */
 update_cr6(db->cr6_data, dev->base_addr);
 outl(0, dev->base_addr + DCR7);
 outl(inl(dev->base_addr + DCR5), dev->base_addr + DCR5);

 /* Free Rx Allocate buffer */
 dmfe_free_rxbuffer(db);

 /* system variable init */
 db->tx_packet_cnt=0;
 db->tx_queue_cnt=0;
 db->rx_avail_cnt=0;
 db->link_failed=1;
 db->wait_reset=0;

 /* Re-initilize DM910X board */
 dmfe_init_dm910x(dev);

 /* Restart upper layer interface */
#if LINUX_VERSION_CODE < 0x20400
 dev->tbusy=0;                          /* Can transmit packet */
 dev->start=1;                          /* interface ready */
#else
 netif_wake_queue(dev);
#endif
}

/*
  free all allocated rx buffer 
*/
static void dmfe_free_rxbuffer(struct dmfe_board_info * db)
{
 DMFE_DBUG(0, "dmfe_free_rxbuffer()", 0);

 /* free allocated rx buffer */
 while (db->rx_avail_cnt)
   {
    #if LINUX_VERSION_CODE > 0x20155
        dev_kfree_skb((void *)(db->rx_ready_ptr->rx_skb_ptr));
    #else
        dev_kfree_skb((void *)(db->rx_ready_ptr->rx_skb_ptr), FREE_READ);
    #endif
    db->rx_ready_ptr=(struct rx_desc *)db->rx_ready_ptr->next_rx_desc;
    db->rx_avail_cnt--;
   }
}

/*
  Reused the SK buffer
*/
static void dmfe_reused_skb(struct dmfe_board_info *db, struct sk_buff * skb)
{
 struct rx_desc *rxptr=db->rx_insert_ptr;

 if (!(rxptr->rdes0 & 0x80000000))
   {
    rxptr->rx_skb_ptr=(u32)skb;
    rxptr->rdes2=virt_to_bus(skb->tail);
    rxptr->rdes0=0x80000000;
    db->rx_avail_cnt++;
    db->rx_insert_ptr=(struct rx_desc *)rxptr->next_rx_desc;
   }
 else
   DMFE_DBUG(0, "SK Buffer reused method error", db->rx_avail_cnt); 
}

/*
  Initialize transmit/Receive descriptor 
  Using Chain structure, and allocated Tx/Rx buffer
*/
static void dmfe_descriptor_init(struct dmfe_board_info *db, u32 ioaddr)
{
 struct tx_desc *tmp_tx;
 struct rx_desc *tmp_rx;
 unsigned char *tmp_buf;
 int i;

 DMFE_DBUG(0, "dmfe_descriptor_init()", 0);

 /* tx descriptor start pointer */
 db->tx_insert_ptr=db->first_tx_desc;
 db->tx_remove_ptr=db->first_tx_desc;
 outl(virt_to_bus(db->first_tx_desc), ioaddr+DCR4);     /* Init CR4 */

 /* rx descriptor start pointer */
 db->first_rx_desc=(struct rx_desc *)
                   ((u32)db->first_tx_desc+sizeof(struct rx_desc)*TX_DESC_CNT);
 db->rx_insert_ptr=db->first_rx_desc;
 db->rx_ready_ptr=db->first_rx_desc;
 outl(virt_to_bus(db->first_rx_desc), ioaddr+DCR3);     /* Init CR3 */

 /* Init Transmit chain */
 tmp_buf=db->buf_pool_start;
 for (tmp_tx=db->first_tx_desc, i=0; i<TX_DESC_CNT; i++, tmp_tx++)
    {
     tmp_tx->tx_buf_ptr=(u32)tmp_buf;
     tmp_tx->tdes0=0;
     tmp_tx->tdes1=0x81000000;                  /* IC, chain */
     tmp_tx->tdes2=(u32)virt_to_bus(tmp_buf);
     tmp_tx->tdes3=(u32)virt_to_bus(tmp_tx)+sizeof(struct tx_desc);
     tmp_tx->next_tx_desc=(u32)((u32)tmp_tx+sizeof(struct tx_desc));
     tmp_buf=(unsigned char *)((u32)tmp_buf+TX_BUF_ALLOC);
    }
 (--tmp_tx)->tdes3=(u32)virt_to_bus(db->first_tx_desc);
 tmp_tx->next_tx_desc=(u32)db->first_tx_desc;

 /* Init Receive descriptor chain */
 for (tmp_rx=db->first_rx_desc, i=0; i<RX_DESC_CNT; i++, tmp_rx++)
    {
     tmp_rx->rdes0=0;
     tmp_rx->rdes1=0x01000600;
     tmp_rx->rdes3=(u32)virt_to_bus(tmp_rx)+sizeof(struct rx_desc);
     tmp_rx->next_rx_desc=(u32)((u32)tmp_rx+sizeof(struct rx_desc));
    }
 (--tmp_rx)->rdes3=(u32)virt_to_bus(db->first_rx_desc);
 tmp_rx->next_rx_desc=(u32)db->first_rx_desc;

 /* pre-allocated Rx buffer */
 allocated_rx_buffer(db);
}

/*
  Update CR6 vaule
  Firstly stop DM910X , then written value and start
*/
static void update_cr6(u32 cr6_data, u32 ioaddr)
 {
  u32 cr6_tmp;
  
  cr6_tmp=cr6_data & ~0x2002;           /* stop Tx/Rx */
  outl(cr6_tmp, ioaddr+DCR6);
  DELAY_5US;
  outl(cr6_data, ioaddr+DCR6);
  DELAY_5US;
 }

/* Send a setup frame for DM9132
   This setup frame initilize DM910X addres filter mode
*/
static void dm9132_id_table(struct DEVICE *dev, int mc_cnt)
 {
  struct dev_mc_list *mcptr;
  u16 * addrptr;
  u32 ioaddr=dev->base_addr+0xc0;		/* ID Table */ 
  u32 hash_val;
  u16 i, hash_table[4];

  DMFE_DBUG(0, "dm9132_id_table()", 0);

  /* Node address */
  addrptr=(u16 *)dev->dev_addr;
  outw(addrptr[0], ioaddr);
  ioaddr+=4;
  outw(addrptr[1], ioaddr);
  ioaddr+=4;
  outw(addrptr[2], ioaddr);
  ioaddr+=4;
  
  /* Clear Hash Table */
  for (i=0; i<4; i++)
      hash_table[i]=0x0;

  /* broadcast address */
  hash_table[3]=0x8000;

  /* the multicast address in Hash Table : 64 bits */
  for (mcptr=dev->mc_list, i=0; i<mc_cnt; i++, mcptr=mcptr->next)
     {
      hash_val=cal_CRC((char *)mcptr->dmi_addr, 6, 0) & 0x3f; 
      hash_table[hash_val/16] |= (u16) 1 << (hash_val % 16);
     }

  /* Write the hash table to MAC MD table */
  for (i=0; i<4; i++, ioaddr+=4)
    {
     outw(hash_table[i], ioaddr);
    }
 }

/* Send a setup frame for DM9102/DM9102A
   This setup frame initilize DM910X addres filter mode
*/
static void send_filter_frame(struct DEVICE *dev, int mc_cnt)
 {
  struct dmfe_board_info *db=dev->priv;
  struct dev_mc_list *mcptr;
  struct tx_desc *txptr;
  u16 * addrptr;
  u32 * suptr;
  int i;

  DMFE_DBUG(0, "send_filetr_frame()", 0);

  txptr = db->tx_insert_ptr;
  suptr=(u32 *)txptr->tx_buf_ptr;

  /* Node address */
  addrptr=(u16 *)dev->dev_addr;
  *suptr++=addrptr[0];
  *suptr++=addrptr[1];
  *suptr++=addrptr[2];

  /* broadcast address */
  *suptr++=0xffff;
  *suptr++=0xffff;
  *suptr++=0xffff;

  /* fit the multicast address */
  for (mcptr=dev->mc_list, i=0; i<mc_cnt; i++, mcptr=mcptr->next)
     {
      addrptr=(u16 *)mcptr->dmi_addr;
      *suptr++=addrptr[0];
      *suptr++=addrptr[1];
      *suptr++=addrptr[2];
     }

  for (; i<14; i++)
     {
      *suptr++=0xffff;
      *suptr++=0xffff;
      *suptr++=0xffff;
     }

  /* prepare the setup frame */
  db->tx_insert_ptr=(struct tx_desc *)txptr->next_tx_desc;
  txptr->tdes1=0x890000c0;

  /* Resource Check and Send the setup packet */
  if (!db->tx_packet_cnt)
    {
     /* Resource Empty */
     db->tx_packet_cnt++;
     txptr->tdes0=0x80000000;
     update_cr6(db->cr6_data | 0x2000, dev->base_addr);
     outl(0x1, dev->base_addr+DCR1);		/* Issue Tx polling command */
     update_cr6(db->cr6_data, dev->base_addr);
     dev->trans_start=jiffies;
    }  
  else
    {
     /* Put into TX queue */
     db->tx_queue_cnt++;
    }

 }

/*
  Allocate rx buffer,
  As possible as allocated maxiumn Rx buffer
*/
static void allocated_rx_buffer(struct dmfe_board_info *db)
 {
  struct rx_desc *rxptr;
  struct sk_buff *skb;

  rxptr=db->rx_insert_ptr;

  while(db->rx_avail_cnt<RX_DESC_CNT)
   {
    if ( (skb=dev_alloc_skb(RX_ALLOC_SIZE)) == NULL )
       break;
    rxptr->rx_skb_ptr=(u32)skb;
    rxptr->rdes2=virt_to_bus(skb->tail);
    rxptr->rdes0=0x80000000;
    rxptr=(struct rx_desc *)rxptr->next_rx_desc;
    db->rx_avail_cnt++;
   }

  db->rx_insert_ptr=rxptr;
 }

/*
  Read one word data from the serial ROM
*/
static u16 read_srom_word(long ioaddr, int offset)
{
 int i;
 u16 srom_data = 0;
 long cr9_ioaddr = ioaddr + DCR9;
        
 outl(CR9_SROM_READ, cr9_ioaddr);
 outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
        
 /* Send the Read Command 110b */
 SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
 SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr);
 SROM_CLK_WRITE(SROM_DATA_0, cr9_ioaddr);

 /* Send the offset */
 for (i = 5; i >= 0; i--) 
    {
     srom_data = (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0;
     SROM_CLK_WRITE(srom_data, cr9_ioaddr);
    }

 outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
        
 for (i = 16; i > 0; i--) 
    {
     outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr);
     DELAY_5US;
     srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0);
     outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr);
     DELAY_5US;
    }

 outl(CR9_SROM_READ, cr9_ioaddr);
 return srom_data;
}

/*
  Auto sense the media mode
*/
static u8 dmfe_sense_speed(struct dmfe_board_info * db)
{
 u8 ErrFlag=0;
 u16 phy_mode;

 /* CR6 bit18=0, select 10/100M */
 update_cr6( (db->cr6_data & ~0x40000), db->ioaddr);
	 
 phy_mode=phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
 phy_mode=phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);

 if ( (phy_mode & 0x24) == 0x24 )
   {
    if (db->chip_id == PCI_DM9132_ID)	/* DM9132 */
       phy_mode=phy_read(db->ioaddr, db->phy_addr, 7, db->chip_id) &0xf000;
    else 				/* DM9102/DM9102A */
       phy_mode=phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) &0xf000;
    /* printk("Phy_mode %x ",phy_mode); */
    switch (phy_mode)
      {
       case 0x1000: db->op_mode=DMFE_10MHF; break;
       case 0x2000: db->op_mode=DMFE_10MFD; break;
       case 0x4000: db->op_mode=DMFE_100MHF; break;
       case 0x8000: db->op_mode=DMFE_100MFD; break;
       default: db->op_mode=DMFE_10MHF;
                DMFE_DBUG(0, "Media Type error, phy reg17", phy_mode);
		ErrFlag=1;
                break;
      }
   }
 else
   {
    db->op_mode=DMFE_10MHF; 
    DMFE_DBUG(0, "Link Failed :", phy_mode);
    ErrFlag=1;
   }

 return ErrFlag;
}

/*
  Set 10/100 phyxcer capability
  AUTO mode : phyxcer register4 is NIC capability
  Force mode: phyxcer register4 is the force media
*/
static void dmfe_set_phyxcer(struct dmfe_board_info *db)
{
 u16 phy_reg;

 /* Select 10/100M phyxcer */
 db->cr6_data&=~0x40000;
 update_cr6(db->cr6_data, db->ioaddr);

 /* DM9009 Chip: Phyxcer reg18 bit12=0 */
 if (db->chip_id == PCI_DM9009_ID)
   {
    phy_reg=phy_read(db->ioaddr, db->phy_addr, 18, db->chip_id) & ~0x1000;
    phy_write(db->ioaddr, db->phy_addr, 18, phy_reg, db->chip_id); 
   }

 /* Phyxcer capability setting */
 phy_reg=phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;

 if (!(db->media_mode & DMFE_AUTO))	/* AUTO/Force Mode Check */
   { /* Force Mode */
    switch(db->media_mode)
     {
      case DMFE_10MHF: phy_reg|=0x20; break;
      case DMFE_10MFD: phy_reg|=0x40; break;
      case DMFE_100MHF: phy_reg|=0x80; break;
      case DMFE_100MFD: phy_reg|=0x100; break;
     }
    if (db->chip_id==PCI_DM9009_ID) phy_reg&=0x61;
   }

  /* Write new capability to Phyxcer Reg4 */
  if (!(phy_reg & 0x01e0)) {phy_reg|=db->PHY_reg4; db->media_mode|=DMFE_AUTO;}
  phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id); 

  /* Restart Auto-Negotiation */
  if ( db->chip_type && (db->chip_id==PCI_DM9102_ID) )
     phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);
  if (!db->chip_type)
     phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
}

⌨️ 快捷键说明

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