amd8111e.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,175 行 · 第 1/4 页
C
2,175 行
/* Clear CMD2 */ writel(CMD2_CLEAR, mmio +CMD2); /* Clear CMD7 */ writel(CMD7_CLEAR , mmio + CMD7); /* Clear DLY_INT_A and DLY_INT_B */ writel(0x0, mmio + DLY_INT_A); writel(0x0, mmio + DLY_INT_B); /* Clear FLOW_CONTROL */ writel(0x0, mmio + FLOW_CONTROL); /* Clear INT0 write 1 to clear register */ reg_val = readl(mmio + INT0); writel(reg_val, mmio + INT0); /* Clear STVAL */ writel(0x0, mmio + STVAL); /* Clear INTEN0 */ writel( INTEN0_CLEAR, mmio + INTEN0); /* Clear LADRF */ writel(0x0 , mmio + LADRF); /* Set SRAM_SIZE & SRAM_BOUNDARY registers */ writel( 0x80010,mmio + SRAM_SIZE); /* Clear RCV_RING0_LEN */ writel(0x0, mmio + RCV_RING_LEN0); /* Clear XMT_RING0/1/2/3_LEN */ writel(0x0, mmio + XMT_RING_LEN0); writel(0x0, mmio + XMT_RING_LEN1); writel(0x0, mmio + XMT_RING_LEN2); writel(0x0, mmio + XMT_RING_LEN3); /* Clear XMT_RING_LIMIT */ writel(0x0, mmio + XMT_RING_LIMIT); /* Clear MIB */ writew(MIB_CLEAR, mmio + MIB_ADDR); /* Clear LARF */ amd8111e_writeq(*(u64*)logic_filter,mmio+LADRF); /* SRAM_SIZE register */ reg_val = readl(mmio + SRAM_SIZE); if(lp->options & OPTION_JUMBO_ENABLE) writel( VAL2|JUMBO, mmio + CMD3);#if AMD8111E_VLAN_TAG_USED writel(VAL2|VSIZE|VL_TAG_DEL, mmio + CMD3 );#endif /* Set default value to CTRL1 Register */ writel(CTRL1_DEFAULT, mmio + CTRL1); /* To avoid PCI posting bug */ readl(mmio + CMD2);}/* This function disables the interrupt and clears all the pending interrupts in INT0 */static void amd8111e_disable_interrupt(struct amd8111e_priv* lp){ u32 intr0; /* Disable interrupt */ writel(INTREN, lp->mmio + CMD0); /* Clear INT0 */ intr0 = readl(lp->mmio + INT0); writel(intr0, lp->mmio + INT0); /* To avoid PCI posting bug */ readl(lp->mmio + INT0);}/*This function stops the chip. */static void amd8111e_stop_chip(struct amd8111e_priv* lp){ writel(RUN, lp->mmio + CMD0); /* To avoid PCI posting bug */ readl(lp->mmio + CMD0);}/* This function frees the transmiter and receiver descriptor rings.*/static void amd8111e_free_ring(struct amd8111e_priv* lp){ /* Free transmit and receive skbs */ amd8111e_free_skbs(lp->amd8111e_net_dev); /* Free transmit and receive descriptor rings */ if(lp->rx_ring){ pci_free_consistent(lp->pci_dev, sizeof(struct amd8111e_rx_dr)*NUM_RX_RING_DR, lp->rx_ring, lp->rx_ring_dma_addr); lp->rx_ring = NULL; } if(lp->tx_ring){ pci_free_consistent(lp->pci_dev, sizeof(struct amd8111e_tx_dr)*NUM_TX_RING_DR, lp->tx_ring, lp->tx_ring_dma_addr); lp->tx_ring = NULL; }}#if AMD8111E_VLAN_TAG_USED /* This is the receive indication function for packets with vlan tag.*/ static int amd8111e_vlan_rx(struct amd8111e_priv *lp, struct sk_buff *skb, u16 vlan_tag){#ifdef CONFIG_AMD8111E_NAPI return vlan_hwaccel_receive_skb(skb, lp->vlgrp,vlan_tag);#else return vlan_hwaccel_rx(skb, lp->vlgrp, vlan_tag);#endif /* CONFIG_AMD8111E_NAPI */}#endif/*This function will free all the transmit skbs that are actually transmitted by the device. It will check the ownership of the skb before freeing the skb. */static int amd8111e_tx(struct net_device *dev){ struct amd8111e_priv* lp = netdev_priv(dev); int tx_index = lp->tx_complete_idx & TX_RING_DR_MOD_MASK; int status; /* Complete all the transmit packet */ while (lp->tx_complete_idx != lp->tx_idx){ tx_index = lp->tx_complete_idx & TX_RING_DR_MOD_MASK; status = le16_to_cpu(lp->tx_ring[tx_index].tx_flags); if(status & OWN_BIT) break; /* It still hasn't been Txed */ lp->tx_ring[tx_index].buff_phy_addr = 0; /* We must free the original skb */ if (lp->tx_skbuff[tx_index]) { pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[tx_index], lp->tx_skbuff[tx_index]->len, PCI_DMA_TODEVICE); dev_kfree_skb_irq (lp->tx_skbuff[tx_index]); lp->tx_skbuff[tx_index] = NULL; lp->tx_dma_addr[tx_index] = 0; } lp->tx_complete_idx++; /*COAL update tx coalescing parameters */ lp->coal_conf.tx_packets++; lp->coal_conf.tx_bytes += lp->tx_ring[tx_index].buff_count; if (netif_queue_stopped(dev) && lp->tx_complete_idx > lp->tx_idx - NUM_TX_BUFFERS +2){ /* The ring is no longer full, clear tbusy. */ /* lp->tx_full = 0; */ netif_wake_queue (dev); } } return 0;}#ifdef CONFIG_AMD8111E_NAPI/* This function handles the driver receive operation in polling mode */static int amd8111e_rx_poll(struct net_device *dev, int * budget){ struct amd8111e_priv *lp = dev->priv; int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK; void * mmio = lp->mmio; struct sk_buff *skb,*new_skb; int min_pkt_len, status; unsigned int intr0; int num_rx_pkt = 0; /*int max_rx_pkt = NUM_RX_BUFFERS;*/ short pkt_len;#if AMD8111E_VLAN_TAG_USED short vtag;#endif int rx_pkt_limit = dev->quota; do{ /* process receive packets until we use the quota*/ /* If we own the next entry, it's a new packet. Send it up. */ while(!(lp->rx_ring[rx_index].rx_flags & OWN_BIT)){ /* check if err summary bit is set */ if(le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & ERR_BIT){ /* * There is a tricky error noted by John Murphy, * <murf@perftech.com> to Russ Nelson: Even with * full-sized * buffers it's possible for a * jabber packet to use two buffers, with only * the last correctly noting the error. */ /* reseting flags */ lp->rx_ring[rx_index].rx_flags &=RESET_RX_FLAGS; goto err_next_pkt; } /* check for STP and ENP */ status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags); if(!((status & STP_BIT) && (status & ENP_BIT))){ /* reseting flags */ lp->rx_ring[rx_index].rx_flags &=RESET_RX_FLAGS; goto err_next_pkt; } pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;#if AMD8111E_VLAN_TAG_USED vtag = le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & TT_MASK; /*MAC will strip vlan tag*/ if(lp->vlgrp != NULL && vtag !=0) min_pkt_len =MIN_PKT_LEN - 4; else#endif min_pkt_len =MIN_PKT_LEN; if (pkt_len < min_pkt_len) { lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; lp->drv_rx_errors++; goto err_next_pkt; } if(--rx_pkt_limit < 0) goto rx_not_empty; if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){ /* if allocation fail, ignore that pkt and go to next one */ lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; lp->drv_rx_errors++; goto err_next_pkt; } skb_reserve(new_skb, 2); skb = lp->rx_skbuff[rx_index]; pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index], lp->rx_buff_len-2, PCI_DMA_FROMDEVICE); skb_put(skb, pkt_len); skb->dev = dev; lp->rx_skbuff[rx_index] = new_skb; new_skb->dev = dev; lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev, new_skb->data, lp->rx_buff_len-2,PCI_DMA_FROMDEVICE); skb->protocol = eth_type_trans(skb, dev);#if AMD8111E_VLAN_TAG_USED vtag = lp->rx_ring[rx_index].rx_flags & TT_MASK; if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){ amd8111e_vlan_rx(lp, skb, lp->rx_ring[rx_index].tag_ctrl_info); } else#endif netif_receive_skb(skb); /*COAL update rx coalescing parameters*/ lp->coal_conf.rx_packets++; lp->coal_conf.rx_bytes += pkt_len; num_rx_pkt++; dev->last_rx = jiffies; err_next_pkt: lp->rx_ring[rx_index].buff_phy_addr = cpu_to_le32(lp->rx_dma_addr[rx_index]); lp->rx_ring[rx_index].buff_count = cpu_to_le16(lp->rx_buff_len-2); lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT); rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK; } /* Check the interrupt status register for more packets in the mean time. Process them since we have not used up our quota.*/ intr0 = readl(mmio + INT0); /*Ack receive packets */ writel(intr0 & RINT0,mmio + INT0); }while(intr0 & RINT0); /* Receive descriptor is empty now */ dev->quota -= num_rx_pkt; *budget -= num_rx_pkt; netif_rx_complete(dev); /* enable receive interrupt */ writel(VAL0|RINTEN0, mmio + INTEN0); writel(VAL2 | RDMD0, mmio + CMD0); return 0;rx_not_empty: /* Do not call a netif_rx_complete */ dev->quota -= num_rx_pkt; *budget -= num_rx_pkt; return 1; }#else/* This function will check the ownership of receive buffers and descriptors. It will indicate to kernel up to half the number of maximum receive buffers in the descriptor ring, in a single receive interrupt. It will also replenish the descriptors with new skbs.*/static int amd8111e_rx(struct net_device *dev){ struct amd8111e_priv *lp = netdev_priv(dev); struct sk_buff *skb,*new_skb; int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK; int min_pkt_len, status; int num_rx_pkt = 0; int max_rx_pkt = NUM_RX_BUFFERS; short pkt_len;#if AMD8111E_VLAN_TAG_USED short vtag;#endif /* If we own the next entry, it's a new packet. Send it up. */ while(++num_rx_pkt <= max_rx_pkt){ if(lp->rx_ring[rx_index].rx_flags & OWN_BIT) return 0; /* check if err summary bit is set */ if(le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & ERR_BIT){ /* * There is a tricky error noted by John Murphy, * <murf@perftech.com> to Russ Nelson: Even with full-sized * buffers it's possible for a jabber packet to use two * buffers, with only the last correctly noting the error. */ /* reseting flags */ lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; goto err_next_pkt; } /* check for STP and ENP */ status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags); if(!((status & STP_BIT) && (status & ENP_BIT))){ /* reseting flags */ lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; goto err_next_pkt; } pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;#if AMD8111E_VLAN_TAG_USED vtag = le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & TT_MASK; /*MAC will strip vlan tag*/ if(lp->vlgrp != NULL && vtag !=0) min_pkt_len =MIN_PKT_LEN - 4; else#endif min_pkt_len =MIN_PKT_LEN; if (pkt_len < min_pkt_len) { lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; lp->drv_rx_errors++; goto err_next_pkt; } if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){ /* if allocation fail, ignore that pkt and go to next one */ lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; lp->drv_rx_errors++; goto err_next_pkt; } skb_reserve(new_skb, 2); skb = lp->rx_skbuff[rx_index]; pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index], lp->rx_buff_len-2, PCI_DMA_FROMDEVICE); skb_put(skb, pkt_len); skb->dev = dev; lp->rx_skbuff[rx_index] = new_skb; new_skb->dev = dev; lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev, new_skb->data, lp->rx_buff_len-2,PCI_DMA_FROMDEVICE); skb->protocol = eth_type_trans(skb, dev);#if AMD8111E_VLAN_TAG_USED vtag = lp->rx_ring[rx_index].rx_flags & TT_MASK; if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){ amd8111e_vlan_rx(lp, skb, lp->rx_ring[rx_index].tag_ctrl_info); } else#endif netif_rx (skb); /*COAL update rx coalescing parameters*/ lp->coal_conf.rx_packets++; lp->coal_conf.rx_bytes += pkt_len; dev->last_rx = jiffies; err_next_pkt: lp->rx_ring[rx_index].buff_phy_addr = cpu_to_le32(lp->rx_dma_addr[rx_index]); lp->rx_ring[rx_index].buff_count = cpu_to_le16(lp->rx_buff_len-2); lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT); rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK; } return 0;}#endif /* CONFIG_AMD8111E_NAPI *//* This function will indicate the link status to the kernel.*/static int amd8111e_link_change(struct net_device* dev){ struct amd8111e_priv *lp = netdev_priv(dev); int status0,speed; /* read the link change */ status0 = readl(lp->mmio + STAT0); if(status0 & LINK_STATS){ if(status0 & AUTONEG_COMPLETE) lp->link_config.autoneg = AUTONEG_ENABLE; else lp->link_config.autoneg = AUTONEG_DISABLE; if(status0 & FULL_DPLX) lp->link_config.duplex = DUPLEX_FULL; else lp->link_config.duplex = DUPLEX_HALF; speed = (status0 & SPEED_MASK) >> 7; if(speed == PHY_SPEED_10) lp->link_config.speed = SPEED_10; else if(speed == PHY_SPEED_100) lp->link_config.speed = SPEED_100; printk(KERN_INFO "%s: Link is Up. Speed is %s Mbps %s Duplex\n", dev->name, (lp->link_config.speed == SPEED_100) ? "100": "10", (lp->link_config.duplex == DUPLEX_FULL)? "Full": "Half"); netif_carrier_on(dev); } else{ lp->link_config.speed = SPEED_INVALID; lp->link_config.duplex = DUPLEX_INVALID; lp->link_config.autoneg = AUTONEG_INVALID; printk(KERN_INFO "%s: Link is Down.\n",dev->name); netif_carrier_off(dev); } return 0;}/*This function reads the mib counters. */static int amd8111e_read_mib(void* mmio, u8 MIB_COUNTER){ unsigned int status; unsigned int data; unsigned int repeat = REPEAT_CNT; writew( MIB_RD_CMD | MIB_COUNTER, mmio + MIB_ADDR); do { status = readw(mmio + MIB_ADDR); udelay(2); /* controller takes MAX 2 us to get mib data */ } while (--repeat && (status & MIB_CMD_ACTIVE)); data = readl(mmio + MIB_DATA); return data;}/*This function reads the mib registers and returns the hardware statistics. It updates previous internal driver statistics with new values.*/ static struct net_device_stats *amd8111e_get_stats(struct net_device * dev){ struct amd8111e_priv *lp = netdev_priv(dev); void * mmio = lp->mmio; unsigned long flags; /* struct net_device_stats *prev_stats = &lp->prev_stats; */ struct net_device_stats* new_stats = &lp->stats; if(!lp->opened) return &lp->stats; spin_lock_irqsave (&lp->lock, flags); /* stats.rx_packets */ new_stats->rx_packets = amd8111e_read_mib(mmio, rcv_broadcast_pkts)+ amd8111e_read_mib(mmio, rcv_multicast_pkts)+ amd8111e_read_mib(mmio, rcv_unicast_pkts); /* stats.tx_packets */ new_stats->tx_packets = amd8111e_read_mib(mmio, xmt_packets); /*stats.rx_bytes */ new_stats->rx_bytes = amd8111e_read_mib(mmio, rcv_octets); /* stats.tx_bytes */ new_stats->tx_bytes = amd8111e_read_mib(mmio, xmt_octets); /* stats.rx_errors */ /* hw errors + errors driver reported */ new_stats->rx_errors = amd8111e_read_mib(mmio, rcv_undersize_pkts)+ amd8111e_read_mib(mmio, rcv_fragments)+ amd8111e_read_mib(mmio, rcv_jabbers)+ amd8111e_read_mib(mmio, rcv_alignment_errors)+ amd8111e_read_mib(mmio, rcv_fcs_errors)+ amd8111e_read_mib(mmio, rcv_miss_pkts)+ lp->drv_rx_errors; /* stats.tx_errors */ new_stats->tx_errors = amd8111e_read_mib(mmio, xmt_underrun_pkts); /* stats.rx_dropped*/ new_stats->rx_dropped = amd8111e_read_mib(mmio, rcv_miss_pkts); /* stats.tx_dropped*/ new_stats->tx_dropped = amd8111e_read_mib(mmio, xmt_underrun_pkts); /* stats.multicast*/ new_stats->multicast = amd8111e_read_mib(mmio, rcv_multicast_pkts); /* stats.collisions*/ new_stats->collisions = amd8111e_read_mib(mmio, xmt_collisions); /* stats.rx_length_errors*/ new_stats->rx_length_errors = amd8111e_read_mib(mmio, rcv_undersize_pkts)+ amd8111e_read_mib(mmio, rcv_oversize_pkts); /* stats.rx_over_errors*/ new_stats->rx_over_errors = amd8111e_read_mib(mmio, rcv_miss_pkts); /* stats.rx_crc_errors*/ new_stats->rx_crc_errors = amd8111e_read_mib(mmio, rcv_fcs_errors);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?