📄 dmfe.c
字号:
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; 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 */ 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); 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 = netdev_priv(dev); unsigned long 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); udelay(5); /* 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 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); /* 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 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 = netdev_priv(dev); struct tx_desc *txptr; unsigned long flags; DMFE_DBUG(0, "dmfe_start_xmit", 0); /* Resource flag check */ 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 */ outl(0, 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); /* Point to next transmit free descriptor */ db->tx_insert_ptr = txptr->next_tx_desc; /* 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 */ if ( db->tx_queue_cnt < TX_FREE_DESC_CNT ) netif_wake_queue(dev); /* Restore CR7 to enable interrupt */ spin_unlock_irqrestore(&db->lock, flags); outl(db->cr7_data, dev->base_addr + DCR7); /* free this SKB */ dev_kfree_skb(skb); 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 = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; DMFE_DBUG(0, "dmfe_stop", 0); /* disable system */ 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 irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct DEVICE *dev = dev_id; struct dmfe_board_info *db = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; unsigned long flags; DMFE_DBUG(0, "dmfe_interrupt()", 0); spin_lock_irqsave(&db->lock, flags); /* Got DM910X status */ db->cr5_data = inl(ioaddr + DCR5); outl(db->cr5_data, ioaddr + DCR5); if ( !(db->cr5_data & 0xc1) ) { spin_unlock_irqrestore(&db->lock, flags); return IRQ_HANDLED; } /* 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 IRQ_HANDLED; } /* Received the coming packet */ if ( (db->cr5_data & 0x40) && db->rx_avail_cnt ) 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); /* Mode Check */ if (db->dm910x_chk_mode & 0x2) { db->dm910x_chk_mode = 0x4; db->cr6_data |= 0x100; update_cr6(db->cr6_data, db->ioaddr); } /* Restore CR7 to enable interrupt mask */ outl(db->cr7_data, ioaddr + DCR7); spin_unlock_irqrestore(&db->lock, flags); return IRQ_HANDLED;}#ifdef CONFIG_NET_POLL_CONTROLLER/* * Polling 'interrupt' - used by things like netconsole to send skbs * without having to re-enable interrupts. It's not called while * the interrupt routine is executing. */static void poll_dmfe (struct net_device *dev){ /* disable_irq here is not very nice, but with the lockless interrupt handler we have no other choice. */ disable_irq(dev->irq); dmfe_interrupt (dev->irq, dev, NULL); enable_irq(dev->irq);}#endif/* * 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; txptr = db->tx_remove_ptr; while(db->tx_packet_cnt) { tdes0 = le32_to_cpu(txptr->tdes0); /* printk(DRV_NAME ": tdes0=%x\n", 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 */ if ( db->tx_queue_cnt < TX_WAKE_DESC_CNT ) netif_wake_queue(dev); /* Active upper layer, send again */}/* * Calculate the CRC valude of the Rx packet * flag = 1 : return the reverse CRC (for the received packet CRC) * 0 : return the normal CRC (for Hash Table index) */static inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag){ u32 crc = crc32(~0, Data, Len); if (flag) crc = ~crc; return crc;}/* * 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; 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->data, rxlen, 1) != (*(u32 *) (skb->data+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->data, rxlen); dmfe_reuse_skb(db, rxptr->rx_skb_ptr); } 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 = 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 = 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); if (db->chip_id == PCI_DM9132_ID) dm9132_id_table(dev, dev->mc_count); /* DM9132 */ else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -