📄 dmfe.c
字号:
/* Reset DM910x board : need 32 PCI clock to complete */ outl(DM910X_RESET, ioaddr + DCR0); /* RESET MAC */ DELAY_5US; outl(db->cr0_data, ioaddr + DCR0); outl(0x180, ioaddr + DCR12); /* Let bit 7 output port */ outl(0x80, ioaddr + DCR12); /* RESET DM9102 phyxcer */ outl(0x0, ioaddr + DCR12); /* Clear RESET signal */ /* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */ db->phy_addr = 1; /* Media Mode Check */ db->media_mode = dmfe_media_mode; if (db->media_mode & DMFE_AUTO) dmfe_sense_speed(db); else db->op_mode = db->media_mode; dmfe_process_mode(db); /* 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 */ outl(0xffffffff, ioaddr + DCR5); /* clear all CR5 status */ db->cr7_data = CR7_DEFAULT; outl(db->cr7_data, ioaddr + DCR7); /* Init CR15, Tx jabber and Rx watchdog timer */ db->cr15_data = CR15_DEFAULT; outl(db->cr15_data, ioaddr + DCR15); /* Enable DM910X Tx/Rx function */ db->cr6_data |= CR6_RXSC | CR6_TXSC; 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 net_device *dev){ struct dmfe_board_info *db = dev->priv; struct tx_desc *txptr; DMFE_DBUG(0, "dmfe_start_xmit", 0); netif_stop_queue(dev); /* Too large packet check */ if (skb->len > MAX_PACKET_SIZE) { printk(KERN_ERR "%s: oversized frame (%d bytes) for transmit.\n", dev->name, (u16) skb->len); dev_kfree_skb(skb); return 0; } /* No Tx resource check, it never happen nromally */ if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) { return 1; } /* 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_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 */ } 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_packet_cnt < TX_FREE_DESC_CNT) netif_wake_queue(dev); /* 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 net_device *dev){ struct dmfe_board_info *db = dev->priv; u32 ioaddr = dev->base_addr; DMFE_DBUG(0, "dmfe_stop", 0); netif_stop_queue(dev); /* Reset & stop DM910X board */ outl(DM910X_RESET, ioaddr + DCR0); DELAY_5US; /* deleted timer */ del_timer_sync(&db->timer); /* free interrupt */ free_irq(dev->irq, dev); /* 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); return 0;}/* DM9102 insterrupt handler receive the packet to upper layer, free the transmitted packet */static void dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = dev_id; struct tx_desc *txptr; struct dmfe_board_info *db; u32 ioaddr; if (!dev) { DMFE_DBUG(1, "dmfe_interrupt() without device arg", 0); return; } /* A real interrupt coming */ db = (struct dmfe_board_info *) dev->priv; ioaddr = dev->base_addr; DMFE_DBUG(0, "dmfe_interrupt()", 0); /* Disable all interrupt in CR7 to solve the interrupt edge problem */ outl(0, ioaddr + DCR7); /* Got DM910X status */ db->cr5_data = inl(ioaddr + DCR5); outl(db->cr5_data, ioaddr + DCR5); /* printk("CR5=%x\n", db->cr5_data); */ /* Check system status */ if (db->cr5_data & 0x2000) { /* A system bus error occurred */ DMFE_DBUG(1, "A system bus error occurred. CR5=", db->cr5_data); netif_stop_queue(dev); db->wait_reset = 1; /* Need to RESET */ outl(0, ioaddr + DCR7); /* disable all interrupt */ return; } /* Free the transmitted descriptor */ txptr = db->tx_remove_ptr; while (db->tx_packet_cnt) { /* printk("tdes0=%x\n", txptr->tdes0); */ if (txptr->tdes0 & 0x80000000) break; db->stats.tx_packets++; if ((txptr->tdes0 & TDES0_ERR_MASK) && (txptr->tdes0 != 0x7fffffff)) { /* printk("tdes0=%x\n", txptr->tdes0); */ db->stats.tx_errors++; } /* Transmit statistic counter */ if (txptr->tdes0 != 0x7fffffff) { /* printk("tdes0=%x\n", txptr->tdes0); */ db->stats.collisions += (txptr->tdes0 >> 3) & 0xf; db->stats.tx_bytes += txptr->tdes1 & 0x7ff; if (txptr->tdes0 & TDES0_ERR_MASK) db->stats.tx_errors++; } txptr = (struct tx_desc *) txptr->next_tx_desc; db->tx_packet_cnt--; } /* Update TX remove pointer to next */ db->tx_remove_ptr = (struct tx_desc *) txptr; /* Send the Tx packet in queue */ if ((db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt) { txptr->tdes0 = 0x80000000; /* set owner bit to DM910X */ db->tx_packet_cnt++; /* Ready to send count */ outl(0x1, ioaddr + DCR1); /* Issue Tx polling command */ dev->trans_start = jiffies; /* saved the time stamp */ db->tx_queue_cnt--; } /* Resource available check */ if (db->tx_packet_cnt < TX_FREE_DESC_CNT) netif_wake_queue(dev); /* Received the coming packet */ if (db->rx_avail_cnt) dmfe_rx_packet(dev, db); /* reallocated rx descriptor buffer */ if (db->rx_avail_cnt < RX_DESC_CNT) allocated_rx_buffer(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 */ if (db->interval_rx_cnt > RX_MAX_TRAFFIC) db->cr7_data = 0x1a28d; else db->cr7_data = 0x1a2cd; outl(db->cr7_data, ioaddr + DCR7);}/* Receive the come packet and pass to upper layer */static void dmfe_rx_packet(struct net_device *dev, struct dmfe_board_info *db){ struct rx_desc *rxptr; struct sk_buff *skb; int rxlen; rxptr = db->rx_ready_ptr; while (db->rx_avail_cnt) { if (rxptr->rdes0 & 0x80000000) /* packet owner check */ break; db->rx_avail_cnt--; db->interval_rx_cnt++; if ((rxptr->rdes0 & 0x300) != 0x300) { /* A packet without First/Last flag */ /* reused this SKB */ DMFE_DBUG(0, "Reused SK buffer, rdes0", rxptr->rdes0); dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); /* db->rx_error_cnt++; */ } else { /* A packet with First/Last flag */ rxlen = ((rxptr->rdes0 >> 16) & 0x3fff) - 4; /* skip CRC */ if (rxptr->rdes0 & 0x8000) { /* error summary bit check */ /* This is a error packet */ /* printk("rdes0 error : %x \n", rxptr->rdes0); */ db->stats.rx_errors++; if (rxptr->rdes0 & 1) db->stats.rx_fifo_errors++; if (rxptr->rdes0 & 2) db->stats.rx_crc_errors++; if (rxptr->rdes0 & 0x80) db->stats.rx_length_errors++; } if (!(rxptr->rdes0 & 0x8000) || ((db->cr6_data & CR6_PM) && (rxlen > 6))) { skb = (struct sk_buff *) rxptr->rx_skb_ptr; /* Received Packet CRC check need or not */ if ((db->dm910x_chk_mode & 1) && (cal_CRC(skb->tail, rxlen, 1) != (*(unsigned long *) (skb->tail + rxlen)))) { /* Found a error received packet */ dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); db->dm910x_chk_mode = 3; } else { /* A good packet coming, send to upper layer */ skb->dev = dev; skb_put(skb, rxlen); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); /* Send to upper layer */ 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, "Reused SK buffer, rdes0", rxptr->rdes0); dmfe_reused_skb(db, (struct sk_buff *) rxptr->rx_skb_ptr); } } rxptr = (struct rx_desc *) rxptr->next_rx_desc; } db->rx_ready_ptr = rxptr;}/* Get statistics from driver. */static struct net_device_stats *dmfe_get_stats(struct net_device *dev){ struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv; DMFE_DBUG(0, "dmfe_get_stats", 0); return &db->stats;}/* Set DM910X multicast address */static void dmfe_set_filter_mode(struct net_device *dev){ struct dmfe_board_info *db = dev->priv; DMFE_DBUG(0, "dmfe_set_filter_mode()", 0); 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); 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; 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 send_filter_frame(dev, dev->mc_count); /* DM9102/DM9102A */}/* Process the upper socket ioctl command */static int dmfe_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ DMFE_DBUG(0, "dmfe_do_ioctl()", 0); return 0;}/* A periodic timer routine Dynamic media sense, allocated Rx buffer... */static void dmfe_timer(unsigned long data){ u32 tmp_cr8; unsigned char tmp_cr12; struct net_device *dev = (struct net_device *) data; struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv; DMFE_DBUG(0, "dmfe_timer()", 0); /* Do reset now */ if (db->in_reset_state) 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 */ tmp_cr8 = inl(db->ioaddr + DCR8); if ((db->interval_rx_cnt == 0) && (tmp_cr8)) { db->wait_reset = 1; /* printk("CR8 %x, Interval Rx %x\n", tmp_cr8, db->interval_rx_cnt); */ } /* Receiving Traffic check */ if (db->interval_rx_cnt > RX_MAX_TRAFFIC) db->cr7_data = 0x1a28d; else db->cr7_data = 0x1a2cd; outl(db->cr7_data, db->ioaddr + DCR7); db->interval_rx_cnt = 0; if (db->wait_reset | (db->tx_packet_cnt && ((jiffies - dev->trans_start) > DMFE_TX_TIMEOUT)) | (db->rx_error_cnt > 3)) { /* printk("wait_reset %x, tx cnt %x, rx err %x, time %x\n", db->wait_reset, db->tx_packet_cnt, db->rx_error_cnt, jiffies-dev->trans_start); */ DMFE_DBUG(0, "Warn!! Warn!! Tx/Rx moniotr step1", db->tx_packet_cnt); dmfe_dynamic_reset(dev); db->timer.expires = DMFE_TIMER_WUT; add_timer(&db->timer); return; } db->rx_error_cnt = 0; /* Clear previos counter */ /* Link status check, Dynamic media type change */ if (db->chip_id == PCI_DM9132_ID) tmp_cr12 = inb(db->ioaddr + DCR9 + 3); /* DM9132 */ else tmp_cr12 = inb(db->ioaddr + DCR12); /* DM9102/DM9102A */ if (((db->chip_id == PCI_DM9102_ID) && (db->chip_revision == 0x02000030)) || ((db->chip_id == PCI_DM9132_ID) && (db->chip_revision == 0x02000010))) { /* DM9102A Chip */ if (tmp_cr12 & 2) tmp_cr12 = 0x0; /* Link failed */ else tmp_cr12 = 0x3; /* Link OK */ } if (!(tmp_cr12 & 0x3) && !db->link_failed) { /* Link Failed */ DMFE_DBUG(0, "Link Failed", tmp_cr12); db->link_failed = 1; phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id); /* reset Phy */ /* 10/100M link failed, used 1M Home-Net */ db->cr6_data |= 0x00040000; /* CR6 bit18 = 1, select Home-Net */ db->cr6_data &= ~0x00000200; /* CR6 bit9 =0, half duplex mode */ update_cr6(db->cr6_data, db->ioaddr); /* For DM9801 : PHY ID1 0181h, PHY ID2 B900h */ db->phy_id2 = phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id); if (db->phy_id2 == 0xb900) phy_write(db->ioaddr, db->phy_addr, 25, 0x7e08, db->chip_id); } else if ((tmp_cr12 & 0x3) && db->link_failed) { DMFE_DBUG(0, "Link link OK", tmp_cr12); db->link_failed = 0; /* CR6 bit18=0, select 10/100M */ db->cr6_data &= ~0x00040000; update_cr6(db->cr6_data, db->ioaddr); /* Auto Sense Speed */ if (db->media_mode & DMFE_AUTO) dmfe_sense_speed(db); dmfe_process_mode(db); update_cr6(db->cr6_data, db->ioaddr); /* SHOW_MEDIA_TYPE(db->op_mode); */ } /* reallocated rx descriptor buffer */ if (db->rx_avail_cnt < RX_DESC_CNT) allocated_rx_buffer(db); /* Timer active again */ db->timer.expires = DMFE_TIMER_WUT; add_timer(&db->timer);}/* 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 net_device *dev){ struct dmfe_board_info *db = dev->priv; DMFE_DBUG(0, "dmfe_dynamic_reset()", 0); /* Enter dynamic reset route */ db->in_reset_state = 1; /* Disable upper layer interface */ netif_stop_queue(dev); db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */ update_cr6(db->cr6_data, dev->base_addr); /* 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 = 0; db->wait_reset = 0; db->rx_error_cnt = 0; /* Re-initilize DM910X board */ dmfe_init_dm910x(dev); /* Leave dynamic reser route */ db->in_reset_state = 0; /* Restart upper layer interface */ 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((void *) (db->rx_ready_ptr->rx_skb_ptr)); db->rx_ready_ptr = (struct rx_desc *) db->rx_ready_ptr->next_rx_desc; db->rx_avail_cnt--; }}/* Reused the SK buffer */static void dmfe_reused_skb(struct dmfe_board_info *db, struct sk_buff *skb){ struct rx_desc *rxptr = db->rx_insert_ptr; if (!(rxptr->rdes0 & 0x80000000)) { rxptr->rx_skb_ptr = (u32) skb; rxptr->rdes2 = virt_to_bus(skb->tail); rxptr->rdes0 = 0x80000000; db->rx_avail_cnt++; db->rx_insert_ptr = (struct rx_desc *) rxptr->next_rx_desc; } else DMFE_DBUG(0, "SK Buffer reused method error", db->rx_avail_cnt);}/* Initialize transmit/Receive descriptor Using Chain structure, and allocated Tx/Rx buffer */static void dmfe_descriptor_init(struct dmfe_board_info *db, u32 ioaddr){ struct tx_desc *tmp_tx; struct rx_desc *tmp_rx; unsigned char *tmp_buf; int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -