📄 ethernet driver for linux.txt
字号:
// kfree(dev); /* free board information */
free_netdev(dev);
}
DMFE_DBUG(0, "dmfe_remove_one() exit", 0);
}
/*
* Open the interface.
* The interface is opened whenever "ifconfig" actives it.
*/
//#define request_irq myrequest_irq
//#define free_irq myfree_irq
static int dmfe_open(struct DEVICE *dev)
{
int ret;
// struct dmfe_board_info *db = dev->priv;
struct dmfe_board_info *db = netdev_priv(dev);
DMFE_DBUG(0, "dmfe_open", 0);
/* 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;
db->dm910x_chk_mode=4; /* Enter the normal mode */
db->cr0_data = 0;
db->cr6_data = 0x32002002;
/* Initilize DM910X board */
dmfe_init_dm910x(dev);
/* Active System Interface */
// add by tfl
netif_wake_queue(dev);
/* 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);
ret = request_irq(dev->irq, dmfe_interrupt, SA_SHIRQ, dev->name, dev);
if (ret)
return ret;
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;
struct dmfe_board_info *db = netdev_priv(dev);
unsigned long ioaddr = db->ioaddr;
int tmp;
DMFE_DBUG(0, "dmfe_init_dm910x()", 0);
/* Reset DM910x MAC controller */
tmp = inl(ioaddr + DCR0);
outl(DM910X_RESET|tmp, ioaddr + DCR0); /* RESET MAC */
udelay(1000);
outl(db->cr0_data, ioaddr + DCR0);
udelay(5);
/* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
db->phy_addr = IRQ2PHYADDR(dev->irq);
if (ioaddr == 0x1F005200) {
// db->phy_addr = 5;
db->phy_addr = 0x13;
} else if (ioaddr == 0x1F005300) {
db->phy_addr = 4;
}
/* Parser media mode */
db->media_mode = dmfe_media_mode;
dmfe_set_phyxcer(db);
/* Media Mode Process */
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);
db->cr5_data = inl(ioaddr + DCR5);
outl(db->cr5_data, ioaddr + DCR5);
/* Init CR6 to program DM910x operation */
update_cr6(db->cr6_data, ioaddr);
send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */
/* Init 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 dmfe_board_info *db = netdev_priv(dev);
struct tx_desc *txptr;
unsigned long flags;
DMFE_DBUG(0, "dmfe_start_xmit", 0);
/* Resource flag check */
// add by tfl
netif_stop_queue(dev);
/* Too large packet check */
if (skb->len > MAX_PACKET_SIZE) {
printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len);
dev_kfree_skb(skb);
return 0;
}
spin_lock_irqsave(&db->lock, flags);
/* No Tx resource check, it never happen nromally */
if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
spin_unlock_irqrestore(&db->lock, flags);
printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_queue_cnt);
return 1;
}
/* Disable NIC interrupt */ //yyyyy
//outl(0, dev->base_addr + DCR7);
outl(db->cr7_data | 0x1, dev->base_addr + DCR7);
/* transmit this packet */
txptr = db->tx_insert_ptr;
memcpy(txptr->tx_buf_ptr, skb->data, skb->len);
txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len);
//txptr->tdes1 = cpu_to_le32(0x61000000 | skb->len);
/* Point to next transmit free descriptor */
db->tx_insert_ptr = txptr->next_tx_desc;
#if 0
printk("xmit use descriptor %d\n", db->tx_insert_ptr -db->first_tx_desc);
#endif
/* Transmit Packet Process */
//if ( (!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT) ) {
txptr->tdes0 = cpu_to_le32(0x80000000); /* Set owner bit */
db->tx_packet_cnt++; /* Ready to send */
outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling */
dev->trans_start = jiffies; /* saved time stamp */
//} else {
// db->tx_queue_cnt++; /* queue TX packet */
// outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling */
//}
/* Tx resource check */
// add by tfl
if ( db->tx_queue_cnt < TX_FREE_DESC_CNT )
netif_wake_queue(dev);
/* free this SKB */
dev_kfree_skb(skb);
/* Restore CR7 to enable interrupt */
spin_unlock_irqrestore(&db->lock, flags);
//outl(db->cr7_data | 0x1, 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;
struct dmfe_board_info *db = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
DMFE_DBUG(0, "dmfe_stop", 0);
/* disable system */
// add by tfl
netif_stop_queue(dev);
/* deleted timer */
del_timer_sync(&db->timer);
/* Reset & stop DM910X board */
outl(DM910X_RESET, ioaddr + DCR0);
udelay(5);
phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
/* free interrupt */
free_irq(dev->irq, dev);
/* free allocated rx buffer */
dmfe_free_rxbuffer(db);
#if 0
/* show statistic counter */
printk(DRV_NAME ": 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
*/
static int count = 0;
static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct DEVICE *dev = dev_id;
// struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv;
struct dmfe_board_info *db = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
unsigned long flags;
DMFE_DBUG(0, "dmfe_interrupt()", 0);
if (!dev) {
DMFE_DBUG(1, "dmfe_interrupt() without DEVICE arg", 0);
return;
}
spin_lock_irqsave(&db->lock, flags);
/* Got DM910X status */
db->cr5_data = inl(ioaddr + DCR5);
// printk("cr5 %x\n", db->cr5_data);
outl(db->cr5_data, ioaddr + DCR5);
if ( !(db->cr5_data & 0xc1) ) {
spin_unlock_irqrestore(&db->lock, flags);
return;
}
/* Disable all 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);
db->reset_fatal++;
db->wait_reset = 1; /* Need to RESET */
spin_unlock_irqrestore(&db->lock, flags);
return;
}
/* Received the coming packet */
if ( (db->cr5_data & 0x40) && db->rx_avail_cnt ) {
count++;
if (count == 8000) {
count = 0;
int j = 0;
int i;
/* do {
if (t->rdes0 & 0x80000000) {
j++;
}
t = t->next_rx_desc;
} while (t != db->first_rx_desc);
printk("io base = 0x%X, rx_avail_cnt = 0x%x, scan_cnt = 0x%x\n", db->ioaddr, db->rx_avail_cnt, j);
*/
}
dmfe_rx_packet(dev, db);
}
/* reallocate rx descriptor buffer */
if (db->rx_avail_cnt<RX_DESC_CNT)
allocate_rx_buffer(db);
/* Free the transmitted descriptor */
if ( db->cr5_data & 0x01)
dmfe_free_tx_pkt(dev, db);
#if 0
/* Mode Check */
if (db->dm910x_chk_mode & 0x2) {
db->dm910x_chk_mode = 0x4;
db->cr6_data |= 0x100;
update_cr6(db->cr6_data, db->ioaddr);
}
#endif
/* Restore CR7 to enable interrupt mask */
// outl(db->cr7_data, ioaddr + DCR7);
spin_unlock_irqrestore(&db->lock, flags);
}
/*
* Free TX resource after TX complete
*/
static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db)
{
struct tx_desc *txptr;
unsigned long ioaddr = dev->base_addr;
u32 tdes0;
// netif_stop_queue(dev);
txptr = db->tx_remove_ptr;
while(db->tx_packet_cnt) {
tdes0 = le32_to_cpu(txptr->tdes0);
/* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
//printk("free tx_ptr %d tdes0 %x\n", txptr - db->first_tx_desc, tdes0);
if (tdes0 & 0x80000000)
break;
/* A packet sent completed */
db->tx_packet_cnt--;
db->stats.tx_packets++;
/* Transmit statistic counter */
if ( tdes0 != 0x7fffffff ) {
/* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
db->stats.collisions += (tdes0 >> 3) & 0xf;
db->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
if (tdes0 & TDES0_ERR_MASK) {
db->stats.tx_errors++;
if (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 (tdes0 & 0x0100)
db->tx_excessive_collision++;
if (tdes0 & 0x0200)
db->tx_late_collision++;
if (tdes0 & 0x0400)
db->tx_no_carrier++;
if (tdes0 & 0x0800)
db->tx_loss_carrier++;
if (tdes0 & 0x4000)
db->tx_jabber_timeout++;
}
}
txptr = txptr->next_tx_desc;
}/* End of while */
/* Update TX remove pointer to next */
db->tx_remove_ptr = txptr;
/* Send the Tx packet in queue */
if ( (db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt ) {
txptr->tdes0 = cpu_to_le32(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 */
// add by tfl
if ( db->tx_queue_cnt < TX_WAKE_DESC_CNT )
netif_wake_queue(dev); /* Active upper layer, send again */
}
/*
* 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 = NULL;
int rxlen;
u32 rdes0;
rxptr = db->rx_ready_ptr;
while(db->rx_avail_cnt) {
rdes0 = le32_to_cpu(rxptr->rdes0);
if (rdes0 & 0x80000000) /* packet owner check */
break;
db->rx_avail_cnt--;
db->interval_rx_cnt++;
pci_unmap_single(db->pdev, le32_to_cpu(rxptr->rdes2), RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE);
if ( (rdes0 & 0x300) != 0x300) {
/* A packet without First/Last flag */
/* reuse this SKB */
DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
} else {
/* A packet with First/Last flag */
rxlen = ( (rdes0 >> 16) & 0x3fff) - 4;
/* error summary bit check */
if (rdes0 & 0x8000) {
/* This is a error packet */
//printk(DRV_NAME ": rdes0: %lx\n", rdes0);
db->stats.rx_errors++;
if (rdes0 & 1)
db->stats.rx_fifo_errors++;
if (rdes0 & 2)
db->stats.rx_crc_errors++;
if (rdes0 & 0x80)
db->stats.rx_length_errors++;
}
if ( !(rdes0 & 0x8000) ||
((db->cr6_data & CR6_PM) && (rxlen>6)) ) {
skb = rxptr->rx_skb_ptr;
/* Received Packet CRC check need or not */
if ( (db->dm910x_chk_mode & 1) &&
(cal_CRC(skb->tail, rxlen, 1) !=
(*(u32 *) (skb->tail+rxlen) ))) { /* FIXME (?) */
/* Found a error received packet */
dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
db->dm910x_chk_mode = 3;
} else {
/* Good packet, send to upper layer */
/* Shorst packet used new SKB */
if ( (rxlen < RX_COPY_SIZE) &&
( (skb = dev_alloc_skb(rxlen + 2) )
!= NULL) ) {
/* size less than COPY_SIZE, allocate a rxlen SKB */
skb->dev = dev;
skb_reserve(skb, 2); /* 16byte align */
memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen);
#if 0
{
int i;
printk("Received :\n");
for(i=0; i<rxlen; i++){
printk("%02x", (u8)rxptr->rx_skb_ptr->tail[i]);
if((i+1)%16==0)
printk("\n");
else
printk(" ");
}
printk("\n");
}
#endif
dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -