📄 uli526x.c
字号:
{ struct uli526x_board_info *db = dev->priv; unsigned long flags; ULI526X_DBUG(0, "uli526x_set_filter_mode()", 0); spin_lock_irqsave(&db->lock, flags); if (dev->flags & IFF_PROMISC) { ULI526X_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 > ULI5261_MAX_MULTICAST) { ULI526X_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; } ULI526X_DBUG(0, "Set multicast address", dev->mc_count); send_filter_frame(dev, dev->mc_count); /* M5261/M5263 */ spin_unlock_irqrestore(&db->lock, flags);}static voidULi_ethtool_gset(struct uli526x_board_info *db, struct ethtool_cmd *ecmd){ ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII); ecmd->advertising = (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | ADVERTISED_Autoneg | ADVERTISED_MII); ecmd->port = PORT_MII; ecmd->phy_address = db->phy_addr; ecmd->transceiver = XCVR_EXTERNAL; ecmd->speed = 10; ecmd->duplex = DUPLEX_HALF; if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD) { ecmd->speed = 100; } if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD) { ecmd->duplex = DUPLEX_FULL; } if(db->link_failed) { ecmd->speed = -1; ecmd->duplex = -1; } if (db->media_mode & ULI526X_AUTO) { ecmd->autoneg = AUTONEG_ENABLE; }}static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ struct uli526x_board_info *np = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); if (np->pdev) strcpy(info->bus_info, pci_name(np->pdev)); else sprintf(info->bus_info, "EISA 0x%lx %d", dev->base_addr, dev->irq);}static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct uli526x_board_info *np = netdev_priv(dev); ULi_ethtool_gset(np, cmd); return 0;}static u32 netdev_get_link(struct net_device *dev) { struct uli526x_board_info *np = netdev_priv(dev); if(np->link_failed) return 0; else return 1;}static void uli526x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol){ wol->supported = WAKE_PHY | WAKE_MAGIC; wol->wolopts = 0;}static struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .get_link = netdev_get_link, .get_wol = uli526x_get_wol,};/* * A periodic timer routine * Dynamic media sense, allocate Rx buffer... */static void uli526x_timer(unsigned long data){ u32 tmp_cr8; unsigned char tmp_cr12=0; struct net_device *dev = (struct net_device *) data; struct uli526x_board_info *db = netdev_priv(dev); unsigned long flags; u8 TmpSpeed=10; //ULI526X_DBUG(0, "uli526x_timer()", 0); spin_lock_irqsave(&db->lock, flags); /* Dynamic reset ULI526X : 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 && time_after(jiffies, dev->trans_start + ULI526X_TX_KICK) ) { outl(0x1, dev->base_addr + DCR1); // Tx polling again // TX Timeout if ( time_after(jiffies, dev->trans_start + ULI526X_TX_TIMEOUT) ) { db->reset_TXtimeout++; db->wait_reset = 1; printk( "%s: Tx timeout - resetting\n", dev->name); } } if (db->wait_reset) { ULI526X_DBUG(0, "Dynamic Reset device", db->tx_packet_cnt); db->reset_count++; uli526x_dynamic_reset(dev); db->timer.expires = ULI526X_TIMER_WUT; add_timer(&db->timer); spin_unlock_irqrestore(&db->lock, flags); return; } /* Link status check, Dynamic media type change */ if((phy_read(db->ioaddr, db->phy_addr, 5, db->chip_id) & 0x01e0)!=0) tmp_cr12 = 3; if ( !(tmp_cr12 & 0x3) && !db->link_failed ) { /* Link Failed */ ULI526X_DBUG(0, "Link Failed", tmp_cr12); netif_carrier_off(dev); printk(KERN_INFO "uli526x: %s NIC Link is Down\n",dev->name); db->link_failed = 1; /* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */ /* AUTO don't need */ if ( !(db->media_mode & 0x8) ) phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id); /* AUTO mode, if INT phyxcer link failed, select EXT device */ if (db->media_mode & ULI526X_AUTO) { db->cr6_data&=~0x00000200; /* bit9=0, HD mode */ update_cr6(db->cr6_data, db->ioaddr); } } else if ((tmp_cr12 & 0x3) && db->link_failed) { ULI526X_DBUG(0, "Link link OK", tmp_cr12); db->link_failed = 0; /* Auto Sense Speed */ if ( (db->media_mode & ULI526X_AUTO) && uli526x_sense_speed(db) ) db->link_failed = 1; uli526x_process_mode(db); if(db->link_failed==0) { if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD) { TmpSpeed = 100; } if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD) { printk(KERN_INFO "uli526x: %s NIC Link is Up %d Mbps Full duplex\n",dev->name,TmpSpeed); } else { printk(KERN_INFO "uli526x: %s NIC Link is Up %d Mbps Half duplex\n",dev->name,TmpSpeed); } netif_carrier_on(dev); } /* SHOW_MEDIA_TYPE(db->op_mode); */ } else if(!(tmp_cr12 & 0x3) && db->link_failed) { if(db->init==1) { printk(KERN_INFO "uli526x: %s NIC Link is Down\n",dev->name); netif_carrier_off(dev); } } db->init=0; /* Timer active again */ db->timer.expires = ULI526X_TIMER_WUT; add_timer(&db->timer); spin_unlock_irqrestore(&db->lock, flags);}/* * Dynamic reset the ULI526X board * Stop ULI526X board * Free Tx/Rx allocated memory * Reset ULI526X board * Re-initialize ULI526X board */static void uli526x_dynamic_reset(struct net_device *dev){ struct uli526x_board_info *db = netdev_priv(dev); ULI526X_DBUG(0, "uli526x_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 */ netif_stop_queue(dev); /* Free Rx Allocate buffer */ uli526x_free_rxbuffer(db); /* system variable init */ db->tx_packet_cnt = 0; db->rx_avail_cnt = 0; db->link_failed = 1; db->init=1; db->wait_reset = 0; /* Re-initialize ULI526X board */ uli526x_init(dev); /* Restart upper layer interface */ netif_wake_queue(dev);}/* * free all allocated rx buffer */static void uli526x_free_rxbuffer(struct uli526x_board_info * db){ ULI526X_DBUG(0, "uli526x_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 uli526x_reuse_skb(struct uli526x_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, skb->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 ULI526X_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 uli526x_descriptor_init(struct uli526x_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; int i; ULI526X_DBUG(0, "uli526x_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; 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(0x81000000); /* 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; /* pre-allocate Rx buffer */ allocate_rx_buffer(db);}/* * Update CR6 value * Firstly stop ULI526X, then written value and start */static void update_cr6(u32 cr6_data, unsigned long ioaddr){ outl(cr6_data, ioaddr + DCR6); udelay(5);}/* * Send a setup frame for M5261/M5263 * This setup frame initialize ULI526X address filter mode */static void send_filter_frame(struct net_device *dev, int mc_cnt){ struct uli526x_board_info *db = netdev_priv(dev); struct dev_mc_list *mcptr; struct tx_desc *txptr; u16 * addrptr; u32 * suptr; int i; ULI526X_DBUG(0, "send_filter_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 = txptr->next_tx_desc; txptr->tdes1 = cpu_to_le32(0x890000c0); /* Resource Check and Send the setup packet */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -