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

📄 dmfe.c

📁 A Davicom DM9102A NIC fast ethernet driver for Linux.
💻 C
📖 第 1 页 / 共 5 页
字号:
 u8  pci_irqline;
 static int index=0;            /* For multiple call */
 struct dmfe_board_info *db;    /* Point a board information structure */
 int i;
#if LINUX_VERSION_CODE >= 0x20155
 struct pci_dev * net_dev=NULL;
#else
 unsigned char bus, fun;
#endif

 DMFE_DBUG(0, "dmfe_probe()",0);

#if LINUX_VERSION_CODE >= 0x20155
 if (! pci_present())
   return -ENODEV;
#else
 if (! pcibios_present())
    return -ENODEV;
#endif

  index=0;
#if LINUX_VERSION_CODE >= 0x20155
 while ((net_dev=pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, net_dev)))
#else
 while (pcibios_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, index, &bus, &fun)==PCIBIOS_SUCCESSFUL)
#endif
    {
     u32 pci_id, dev_rev, pci_pmr;
     u8 pci_cmd;

     index++;
#if LINUX_VERSION_CODE >= 0x20155
     if (pci_read_config_dword(net_dev, PCI_VENDOR_ID, &pci_id)!=DMFE_SUCC) 
#else
     if (pcibios_read_config_dword(bus,fun,PCI_VENDOR_ID,&pci_id)!=DMFE_SUCC) 
#endif
        continue;

     if ((pci_id != PCI_DM9102_ID)&&(pci_id != PCI_DM9132_ID)&&(pci_id!=PCI_DM9009_ID) )
        continue;

#if LINUX_VERSION_CODE >= 0x20155
     /* read PCI IO base address and IRQ to check */
     pci_read_config_dword(net_dev, PCI_BASE_ADDRESS_0, &pci_iobase);
     pci_read_config_byte(net_dev, PCI_INTERRUPT_LINE, &pci_irqline);
     pci_read_config_byte(net_dev, PCI_COMMAND, &pci_cmd);
     pci_read_config_dword(net_dev, 8, &dev_rev); /* Read Chip revision */
     pci_read_config_dword(net_dev, 0x50, &pci_pmr); /* Read PMR */
#else
     /* read PCI IO base address and IRQ to check */
     pcibios_read_config_dword(bus,fun,PCI_BASE_ADDRESS_0, &pci_iobase);
     pcibios_read_config_byte(bus, fun, PCI_INTERRUPT_LINE, &pci_irqline);
     pcibios_read_config_byte(bus, fun, PCI_COMMAND, &pci_cmd);
     pcibios_read_config_dword(bus,fun,8,&dev_rev); /* Read Chip revision */
     pcibios_read_config_dword(bus,fun,0x50,&pci_pmr); /* Read PMR */
#endif

     /* Enable Master/IO access, Disable memory access */
     pci_cmd|=PCI_COMMAND_IO+PCI_COMMAND_MASTER;
     pci_cmd&=~PCI_COMMAND_MEMORY;

     /* Write back PCI command & Let latency timer = 0x80 */
#if LINUX_VERSION_CODE >= 0x20155
     pci_write_config_byte(net_dev, PCI_COMMAND, pci_cmd);
     pci_write_config_byte(net_dev, PCI_LATENCY_TIMER, 0x80);
#else
     pcibios_write_config_byte(bus, fun, PCI_COMMAND, pci_cmd);
     pcibios_write_config_byte(bus, fun, PCI_LATENCY_TIMER, 0x80);
#endif

     /* IO range check */
     pci_iobase&=~0x7f;         /* mask off bit0~6 */
     if (check_region(pci_iobase, CHK_IO_SIZE(pci_id, dev_rev)))
       {
	printk(KERN_ERR "dmfe: I/O conflict : IO=%x Range=%x\n", pci_iobase, CHK_IO_SIZE(pci_id, dev_rev));     
        continue;
       }

     /* Interrupt check */
     if ( (pci_irqline==0xff) || (pci_irqline==0) )
       {
	printk(KERN_ERR "dmfe: Interrupt wrong : IRQ=%d\n", pci_irqline);
        continue;
       }

     /* Found DM9102 card and PCI resource allocated OK */
     dm9102_count++;                    /* Found a DM9102 card */

     /* Init network device */
     dev=init_etherdev(dev, 0); 

     /* Allocated board information structure */
     db=(void *)(kmalloc(sizeof(*db), GFP_KERNEL|GFP_DMA));
     memset(db, 0, sizeof(*db));
     dev->priv = db;                    /* link device and board info */
     db->next_dev=dmfe_root_dev;
     dmfe_root_dev=dev;

     db->chip_id=pci_id;                /* keep Chip vandor/Device ID */
     db->ioaddr=pci_iobase;
     db->chip_revision=dev_rev;

#if LINUX_VERSION_CODE >= 0x20155
     db->net_dev=net_dev;
#else
     db->bus=bus;                       /* keep bus/function */
     db->fun=fun;
#endif

     dev->base_addr=pci_iobase;
     dev->irq=pci_irqline;
     dev->open=&dmfe_open;
     dev->hard_start_xmit=&dmfe_start_xmit;
     dev->stop=&dmfe_stop;
     dev->get_stats=&dmfe_get_stats;
     dev->set_multicast_list=&dmfe_set_filter_mode;
     dev->do_ioctl=&dmfe_do_ioctl;

     request_region(pci_iobase, CHK_IO_SIZE(pci_id, dev_rev), dev->name);

     printk("dmfe: INDEX=%d ID=%x NAME=%s IO=%x IRQ=%d\n", index, pci_id, dev->name, pci_iobase, pci_irqline);

     /* Check Chip type decision */
     pci_pmr &= 0x070000;	/* Leave PMR revision */
     if ( (pci_pmr==0x010000) && (dev_rev==0x02000031) )
        db->chip_type=1;	/* DM9102A E3 */
     else
	db->chip_type=0;

     /* read 64 word srom data */
     for (i=0; i<64; i++)
         ((u16 *)db->srom)[i]=read_srom_word(pci_iobase, i);

     /* Set Node address */
     for (i=0; i<6; i++)
         dev->dev_addr[i]=db->srom[20+i];

     dev=0;             /* NULL device */
    }
 
 if (!dm9102_count)
    printk(KERN_ERR "dmfe: Can't find DM910X board or resource error\n");

 return dm9102_count ? 0:-ENODEV;
}

/*
  Open the interface.
  The interface is opened whenever "ifconfig" actives it.
*/
static int dmfe_open(struct DEVICE *dev)
{
 struct dmfe_board_info * db=dev->priv;

 DMFE_DBUG(0, "dmfe_open", 0);

#ifdef SA_SHIRQ
 if (request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev))
    return -EAGAIN;
#else
 if (irq2dev_map[dev->irq] != NULL || (irq2dev_map[dev->irq]=dev)==NULL
    || request_irq(dev->irq, &dmfe_interrupt, 0, "DM910X"))
    return -EAGAIN;
#endif

 /* Allocated Tx/Rx descriptor memory */
 db->desc_pool_ptr=kmalloc(sizeof(struct tx_desc)*DESC_ALL_CNT+0x20,GFP_KERNEL|GFP_DMA);
 if (db->desc_pool_ptr==NULL)
    return -ENOMEM;
 if ((u32)db->desc_pool_ptr & 0x1f)
    db->first_tx_desc=(struct tx_desc *)(((u32)db->desc_pool_ptr&~0x1f)+0x20);
 else
    db->first_tx_desc=(struct tx_desc *)db->desc_pool_ptr;

 /* Allocated Tx buffer memory */
 db->buf_pool_ptr=kmalloc(TX_BUF_ALLOC*TX_DESC_CNT+4,GFP_KERNEL|GFP_DMA);
 if (db->buf_pool_ptr==NULL)
   {
    kfree(db->desc_pool_ptr);
    return -ENOMEM;
   }
 if ((u32)db->buf_pool_ptr & 0x3)
    db->buf_pool_start=(char *)(((u32)db->buf_pool_ptr & ~0x3) + 0x4);
 else
    db->buf_pool_start=db->buf_pool_ptr;

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

 db->first_in_callback=0;
 db->NIC_capability=0xf;	/* All capability*/
 db->PHY_reg4=0x1e0;

 /* CR6 operation mode decision */
 if ( !chkmode || (db->chip_id == PCI_DM9132_ID) || (db->chip_revision >= 0x02000030) )
   {
    db->cr6_data |= DMFE_TXTH_256;
    db->cr0_data = CR0_DEFAULT;		/* TX/RX desc burst mode */
    db->dm910x_chk_mode=4;		/* Enter the normal mode */
   }
 else
   {
    db->cr6_data |= CR6_SFT;		/* Store & Forward mode */
    db->cr0_data=0;
    db->dm910x_chk_mode=1;		/* Enter the check mode */
   } 

 /* Initilize DM910X board */
 dmfe_init_dm910x(dev);
 
 /* Active System Interface */
#if LINUX_VERSION_CODE < 0x20400
 dev->tbusy=0;                          /* Can transmit packet */
 dev->start=1;                          /* interface ready */
#else
 netif_wake_queue(dev);
#endif
 MOD_INC_USE_COUNT;

 /* set and active a timer process */
 init_timer(&db->timer);
 db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
 db->timer.data = (unsigned long)dev;
 db->timer.function = &dmfe_timer;
 add_timer(&db->timer);

 return 0;
}

/* Initilize DM910X board
   Reset DM910X board
   Initilize TX/Rx descriptor chain structure
   Send the set-up frame
   Enable Tx/Rx machine
*/
static void dmfe_init_dm910x(struct DEVICE *dev)
{
 struct dmfe_board_info *db=dev->priv;
 u32 ioaddr=db->ioaddr;

 DMFE_DBUG(0, "dmfe_init_dm910x()", 0);

 /* Reset DM910x MAC controller */
 outl(DM910X_RESET, ioaddr+DCR0);	/* RESET MAC */
 udelay(100);
 outl(db->cr0_data, ioaddr+DCR0);
 DELAY_5US;

 /* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
 db->phy_addr= 1;
 
 /* Parser SROM and media mode */
 dmfe_parse_srom(db);
 db->media_mode=dmfe_media_mode;

 /* RESET Phyxcer Chip by GPR port bit 7 */
 outl(0x180, ioaddr+DCR12);     /* Let bit 7 output port */
 if (db->chip_id==PCI_DM9009_ID) 
   {
    outl(0x80, ioaddr+DCR12);       /* Issue RESET signal */
    mdelay(300);		/* Delay 300 ms */
   }
 outl(0x0, ioaddr+DCR12);       /* Clear RESET signal */

/* Process Phyxcer Media Mode */
if ( !(db->media_mode & 0x10) )	/* Force 1M mode */
	dmfe_set_phyxcer(db);

/* Media Mode Check */
/* Don't need now. We did Restart Auto-Negotiation in dmfe_set_phyxcer()
   and it should not complete now. We check media mode and program in
   dmfe_timer() later */
 if ( !(db->media_mode & DMFE_AUTO) )
    db->op_mode=db->media_mode; 	/* Force Mode */
 
 /* Initiliaze Transmit/Receive decriptor and CR3/4 */
 dmfe_descriptor_init(db, ioaddr);

 /* Init CR6 to program DM910x operation */
 update_cr6(db->cr6_data, ioaddr);

 /* Send setup frame */
 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 */
 
 /* Init CR5/CR7, interrupt active bit */
 db->cr7_data=CR7_DEFAULT;
 outl(db->cr7_data, ioaddr+DCR7);

/* Init CR15, Tx jabber and Rx watchdog timer */
 outl(db->cr15_data, ioaddr+DCR15);

 /* Enable DM910X Tx/Rx function */
 db->cr6_data|=CR6_RXSC | CR6_TXSC | 0x40000;
 update_cr6(db->cr6_data, ioaddr);

}


/*
  Hardware start transmission.
  Send a packet to media from the upper layer.
*/
static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev)
{
 struct dmfe_board_info *db=dev->priv;
 struct tx_desc *txptr;

 DMFE_DBUG(0, "dmfe_start_xmit", 0);

 /* Resource flag check */
#if LINUX_VERSION_CODE < 0x20400
 if ( test_and_set_bit(0, (void *)&dev->tbusy) )
	return 1;
#else
 netif_stop_queue(dev);
#endif

 /* Too large packet check */
 if (skb->len>MAX_PACKET_SIZE)
   {
    printk(KERN_ERR "dmfe: A big packet, size=%d\n", (u16)skb->len);
    #if LINUX_VERSION_CODE > 0x20155
        dev_kfree_skb(skb);
    #else
        dev_kfree_skb(skb, FREE_WRITE);
    #endif
    return 0;
   }

 /* No Tx resource check, it never happen nromally */
 if (db->tx_queue_cnt >= TX_FREE_DESC_CNT)
    return -EBUSY;

 /* Disable all interrupt */ 
 outl(0, dev->base_addr+DCR7);

 /* transmit this packet */
 txptr=db->tx_insert_ptr;
 memcpy((char *)txptr->tx_buf_ptr, (char *)skb->data, skb->len);
 txptr->tdes1=0xe1000000 | skb->len;

 /* Point to next transmit free descriptor */
 db->tx_insert_ptr=(struct tx_desc *)txptr->next_tx_desc;

 /* Transmit Packet Process */
 if ( (!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT) )
   {
    txptr->tdes0=0x80000000;               /* set owner bit to DM910X */
    db->tx_packet_cnt++;		   /* Ready to send count */
    outl(0x1, dev->base_addr+DCR1);	   /* Issue Tx polling comand */
    dev->trans_start=jiffies;              /* saved the time stamp */
   }
 else
   {
    db->tx_queue_cnt++;			   /* queue the tx packet */
    outl(0x1, dev->base_addr+DCR1);	   /* Issue Tx polling comand */
   }

 /* Tx resource check */
 if ( db->tx_queue_cnt < TX_FREE_DESC_CNT )
#if LINUX_VERSION_CODE < 0x20400
    dev->tbusy=0;
#else
    netif_wake_queue(dev);
#endif

 /* free this SKB */
 #if LINUX_VERSION_CODE > 0x20155
     dev_kfree_skb(skb);
 #else
     dev_kfree_skb(skb, FREE_WRITE);
 #endif

/* Restore CR7 to enable interrupt */ 
 outl(db->cr7_data, dev->base_addr+DCR7);

 return 0;
}

/*
  Stop the interface.
  The interface is stopped when it is brought.
*/
static int dmfe_stop(struct DEVICE *dev)
{
 struct dmfe_board_info *db=dev->priv;
 u32 ioaddr=dev->base_addr; 

 DMFE_DBUG(0, "dmfe_stop", 0);

 /* disable system */
#if LINUX_VERSION_CODE < 0x20400
 dev->start=0;                          /* interface disable */
 dev->tbusy=1;                          /* can't transmit */
#else
 netif_stop_queue(dev);
#endif

 /* deleted timer */
 del_timer(&db->timer);

 /* Reset & stop DM910X board */
 outl(DM910X_RESET, ioaddr+DCR0);
 DELAY_5US;
 phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);

 /* free interrupt */
#ifdef SA_SHIRQ
 free_irq(dev->irq, dev);
#else
 free_irq(dev->irq);
 irq2dev_map[dev->irq] = 0;
#endif

 /* free allocated rx buffer */
 dmfe_free_rxbuffer(db);

 /* free all descriptor memory and buffer memory */
 kfree(db->desc_pool_ptr);
 kfree(db->buf_pool_ptr);

 MOD_DEC_USE_COUNT;

⌨️ 快捷键说明

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