📄 ethernet driver for linux.txt
字号:
} else {
skb->dev = dev;
skb_put(skb, rxlen);
}
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
db->stats.rx_packets++;
db->stats.rx_bytes += rxlen;
}
} else {
/* Reuse SKB buffer when the packet is error */
DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
}
}
rxptr = rxptr->next_rx_desc;
}
db->rx_ready_ptr = rxptr;
}
/*
* Get statistics from driver.
*/
static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev)
{
// struct dmfe_board_info *db = (struct dmfe_board_info *)dev->priv;
struct dmfe_board_info *db = netdev_priv(dev);
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;
struct dmfe_board_info *db = netdev_priv(dev);
unsigned long flags;
DMFE_DBUG(0, "dmfe_set_filter_mode()", 0);
spin_lock_irqsave(&db->lock, flags);
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);
spin_unlock_irqrestore(&db->lock, flags);
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;
spin_unlock_irqrestore(&db->lock, flags);
return;
}
DMFE_DBUG(0, "Set multicast address", dev->mc_count);
send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */
spin_unlock_irqrestore(&db->lock, flags);
}
/*
* Process the ethtool ioctl command
*/
static int dmfe_ethtool_ioctl(struct net_device *dev, void *useraddr)
{
// struct dmfe_board_info *db = dev->priv;
struct dmfe_board_info *db = netdev_priv(dev);
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
u32 ethcmd;
if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd)))
return -EFAULT;
switch (ethcmd) {
case ETHTOOL_GDRVINFO:
strcpy(info.driver, DRV_NAME);
strcpy(info.version, DRV_VERSION);
if (db->pdev)
// strcpy(info.bus_info, db->pdev->slot_name);
sprintf(info.bus_info, "ITC MAC 10/100M Fast Ethernet Adapter driver 1.0 0x%lx %d", dev->base_addr, dev->irq);
else
sprintf(info.bus_info, "EISA 0x%lx %d",
dev->base_addr, dev->irq);
if (copy_to_user(useraddr, &info, sizeof(info)))
return -EFAULT;
return 0;
}
return -EOPNOTSUPP;
}
/*
* Process the upper socket ioctl command
*/
static int dmfe_do_ioctl(struct DEVICE *dev, struct ifreq *ifr, int cmd)
{
int retval = -EOPNOTSUPP;
DMFE_DBUG(0, "dmfe_do_ioctl()", 0);
switch(cmd) {
case SIOCETHTOOL:
return dmfe_ethtool_ioctl(dev, (void*)ifr->ifr_data);
}
return retval;
}
/*
* A periodic timer routine
* Dynamic media sense, allocate 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;
struct dmfe_board_info *db = netdev_priv(dev);
unsigned long flags;
int link_status;
DMFE_DBUG(0, "dmfe_timer()", 0);
spin_lock_irqsave(&db->lock, flags);
/* 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);
spin_unlock_irqrestore(&db->lock, flags);
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 */
db->interval_rx_cnt = 0;
/* TX polling kick monitor */
if ( db->tx_packet_cnt &&
time_after(jiffies, dev->trans_start + DMFE_TX_KICK) ) {
outl(0x1, dev->base_addr + DCR1); /* Tx polling again */
/* TX Timeout */
if ( time_after(jiffies, dev->trans_start + DMFE_TX_TIMEOUT) ) {
db->reset_TXtimeout++;
db->wait_reset = 1;
printk(KERN_WARNING "%s: Tx timeout - resetting\n",
dev->name);
}
}
if (db->wait_reset) {
DMFE_DBUG(0, "Dynamic Reset device", 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);
spin_unlock_irqrestore(&db->lock, flags);
return;
}
link_status = phy_read(db->ioaddr, db->phy_addr, 0x01, db->chip_id);
#ifdef NO_PHY_PROBE
tmp_cr12 = 3;
#else
tmp_cr12 = link_status & 0x4 ? 0x3: 0;
#endif
if ( (!(tmp_cr12 & 0x3)) && (!db->link_failed) ) {
/* Link Failed */
printk("dev %x:Link Failed %x", db->phy_addr, link_status);
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);
/* AUTO mode */
if (db->media_mode & DMFE_AUTO) {
/* 10/100M link failed */
db->cr6_data&=~0x00000200; /* bit9=0, HD mode */
update_cr6(db->cr6_data, db->ioaddr);
}
} else
if ((tmp_cr12 & 0x3) && db->link_failed) {
// printk("dev %x:Link OK %x", db->phy_addr,link_status);
db->link_failed = 0;
/* Auto Sense Speed */
if ( (db->media_mode & DMFE_AUTO) &&
dmfe_sense_speed(db) )
db->link_failed = 1;
dmfe_process_mode(db);
// SHOW_MEDIA_TYPE(db->op_mode);
}
/* Timer active again */
db->timer.expires = DMFE_TIMER_WUT;
add_timer(&db->timer);
spin_unlock_irqrestore(&db->lock, flags);
}
/*
* 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;
struct dmfe_board_info *db = netdev_priv(dev);
DMFE_DBUG(0, "dmfe_dynamic_reset()", 0);
/* Sopt 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); /* Disable Interrupt */
outl(inl(dev->base_addr + DCR5), dev->base_addr + DCR5);
/* Disable upper layer interface */
// add by tfl
netif_stop_queue(dev);
/* 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 */
// add by tfl
netif_wake_queue(dev);
}
/*
* 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) {
dev_kfree_skb(db->rx_ready_ptr->rx_skb_ptr);
db->rx_ready_ptr = db->rx_ready_ptr->next_rx_desc;
db->rx_avail_cnt--;
}
}
/*
* Reuse the SK buffer
*/
static void dmfe_reuse_skb(struct dmfe_board_info *db, struct sk_buff * skb)
{
struct rx_desc *rxptr = db->rx_insert_ptr;
if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) {
rxptr->rx_skb_ptr = skb;
rxptr->rdes2 = cpu_to_le32(pci_map_single(db->pdev, rxptr->rx_skb_ptr->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
wmb();
rxptr->rdes0 = cpu_to_le32(0x80000000);
db->rx_avail_cnt++;
db->rx_insert_ptr = rxptr->next_rx_desc;
} else
DMFE_DBUG(0, "SK Buffer reuse method error", db->rx_avail_cnt);
}
/*
* Initialize transmit/Receive descriptor
* Using Chain structure, and allocate Tx/Rx buffer
*/
static void dmfe_descriptor_init(struct dmfe_board_info *db, unsigned long ioaddr)
{
struct tx_desc *tmp_tx;
struct rx_desc *tmp_rx;
unsigned char *tmp_buf;
dma_addr_t tmp_tx_dma, tmp_rx_dma;
dma_addr_t tmp_buf_dma;
u32 csr5;
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(db->first_tx_desc_dma, ioaddr + DCR4); /* TX DESC address */
/* rx descriptor start pointer */
db->first_rx_desc = (void *)db->first_tx_desc + sizeof(struct tx_desc) * TX_DESC_CNT;
db->first_rx_desc_dma = db->first_tx_desc_dma + sizeof(struct tx_desc) * TX_DESC_CNT;
db->rx_insert_ptr = db->first_rx_desc;
db->rx_ready_ptr = db->first_rx_desc;
outl(db->first_rx_desc_dma, ioaddr + DCR3); /* RX DESC address */
/* Init Transmit chain */
tmp_buf = db->buf_pool_start;
tmp_buf_dma = db->buf_pool_dma_start;
tmp_tx_dma = db->first_tx_desc_dma;
//printk("first_tx_desc %08x\n", db->first_tx_desc);
//printk("first_rx_desc %08x\n", db->first_rx_desc);
for (tmp_tx = db->first_tx_desc, i = 0; i < TX_DESC_CNT; i++, tmp_tx++) {
tmp_tx->tx_buf_ptr = tmp_buf;
tmp_tx->tdes0 = cpu_to_le32(0);
tmp_tx->tdes1 = cpu_to_le32(0xe1000000); /* IC, chain */
tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma);
tmp_tx_dma += sizeof(struct tx_desc);
tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma);
tmp_tx->next_tx_desc = tmp_tx + 1;
tmp_buf = tmp_buf + TX_BUF_ALLOC;
tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC;
}
(--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma);
tmp_tx->next_tx_desc = db->first_tx_desc;
/* Init Receive descriptor chain */
tmp_rx_dma=db->first_rx_desc_dma;
for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT; i++, tmp_rx++) {
tmp_rx->rdes0 = cpu_to_le32(0);
tmp_rx->rdes1 = cpu_to_le32(0x01000600);
tmp_rx_dma += sizeof(struct rx_desc);
tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma);
tmp_rx->next_rx_desc = tmp_rx + 1;
}
(--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma);
tmp_rx->next_rx_desc = db->first_rx_desc;
#if 1
csr5 = inl(ioaddr+DCR5);
outl(2,DCR5+ioaddr);
csr5 = inl(ioaddr+DCR5);
#endif
/* pre-allocate Rx buffer */
allocate_rx_buffer(db);
}
/*
* Update CR6 value
* Firstly stop DM910X , then written value and start
*/
static void update_cr6(u32 cr6_data, unsigned long ioaddr)
{
u32 cr6_tmp;
cr6_tmp = cr6_data & ~0x2002; /* stop Tx/Rx */
outl(cr6_tmp, ioaddr + DCR6);
udelay(5);
outl(cr6_data|0x2002, ioaddr + DCR6);
udelay(5);
}
/*
* 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 dmfe_board_info *db = netdev_priv(dev);
struct dev_mc_list *mcptr;
struct tx_desc *txptr;
u16 * addrptr;
u32 * suptr;
int i;
//return;
DMFE_DBUG(0, "send_filter_frame()", 0);
txptr = db->tx_insert_ptr;
suptr = (u32 *) txptr->tx_buf_ptr;
printk("send filter use %d\n", txptr- db->first_tx_desc);
/* 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 = txptr->next_tx_desc;
txptr->tdes1 = cpu_to_le32(0x890000c0);
/* Resource Check and Send the setup packet */
//if (!db->tx_packet_cnt) {
/* Resource Empty */
//db->tx_packet_cnt++;
txptr->tdes0 = cpu_to_le32(0x80000000);
//update_cr6(db->cr6_data | 0x2000, dev->base_addr);
outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling */
dev->trans_start = jiffies;
for(i=0; txptr->tdes0 & 0x80000000; i++){
if(i>=800000){
printk("Send setup frame failed %d= %x\n", txptr-db->first_tx_desc, txptr->tdes0);
printk("CSR0 %x\n", inl(db->ioaddr+ DCR0));
printk("CSR1 %x\n", inl(db->ioaddr+ DCR1));
printk("CSR2 %x\n", inl(db->ioaddr+ DCR2));
printk("CSR3 %x\n", inl(db->ioaddr+ DCR3));
printk("CSR4 %x\n", inl(db->ioaddr+ DCR4));
printk("CSR5 %x\n", inl(db->ioaddr+ DCR5));
printk("CSR6 %x\n", inl(db->ioaddr+ DCR6));
printk("CSR7 %x\n", inl(db->ioaddr+ DCR7));
printk("CSR9 %x\n", inl(db->ioaddr+ DCR9));
break;
}
}
//} else
// db->tx_queue_cnt++; /* Put in TX queue */
}
/*
* Allocate rx buffer,
* As possible as allocate maxiumn Rx buffer
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -