📄 e1000_main.c
字号:
**/static inte1000_set_mac(struct net_device *netdev, void *p){ struct e1000_adapter *adapter = netdev->priv; struct sockaddr *addr = p; if(!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; /* 82542 2.0 needs to be in reset to write receive address registers */ if(adapter->hw.mac_type == e1000_82542_rev2_0) e1000_enter_82542_rst(adapter); memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); if(adapter->hw.mac_type == e1000_82542_rev2_0) e1000_leave_82542_rst(adapter); return 0;}/** * e1000_set_multi - Multicast and Promiscuous mode set * @netdev: network interface device structure * * The set_multi entry point is called whenever the multicast address * list or the network interface flags are updated. This routine is * responsible for configuring the hardware for proper multicast, * promiscuous mode, and all-multi behavior. **/static voide1000_set_multi(struct net_device *netdev){ struct e1000_adapter *adapter = netdev->priv; struct e1000_hw *hw = &adapter->hw; struct dev_mc_list *mc_ptr; uint32_t rctl; uint32_t hash_value; int i; unsigned long flags; /* Check for Promiscuous and All Multicast modes */ spin_lock_irqsave(&adapter->tx_lock, flags); rctl = E1000_READ_REG(hw, RCTL); if(netdev->flags & IFF_PROMISC) { rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); } else if(netdev->flags & IFF_ALLMULTI) { rctl |= E1000_RCTL_MPE; rctl &= ~E1000_RCTL_UPE; } else { rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); } E1000_WRITE_REG(hw, RCTL, rctl); /* 82542 2.0 needs to be in reset to write receive address registers */ if(hw->mac_type == e1000_82542_rev2_0) e1000_enter_82542_rst(adapter); /* load the first 14 multicast address into the exact filters 1-14 * RAR 0 is used for the station MAC adddress * if there are not 14 addresses, go ahead and clear the filters */ mc_ptr = netdev->mc_list; for(i = 1; i < E1000_RAR_ENTRIES; i++) { if(mc_ptr) { e1000_rar_set(hw, mc_ptr->dmi_addr, i); mc_ptr = mc_ptr->next; } else { E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0); E1000_WRITE_REG_ARRAY(hw, RA, (i << 1) + 1, 0); } } /* clear the old settings from the multicast hash table */ for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) E1000_WRITE_REG_ARRAY(hw, MTA, i, 0); /* load any remaining addresses into the hash table */ for(; mc_ptr; mc_ptr = mc_ptr->next) { hash_value = e1000_hash_mc_addr(hw, mc_ptr->dmi_addr); e1000_mta_set(hw, hash_value); } if(hw->mac_type == e1000_82542_rev2_0) e1000_leave_82542_rst(adapter); spin_unlock_irqrestore(&adapter->tx_lock, flags);}/* Need to wait a few seconds after link up to get diagnostic information from * the phy */static voide1000_update_phy_info(unsigned long data){ struct e1000_adapter *adapter = (struct e1000_adapter *) data; e1000_phy_get_info(&adapter->hw, &adapter->phy_info);}/** * e1000_82547_tx_fifo_stall - Timer Call-back * @data: pointer to adapter cast into an unsigned long **/static voide1000_82547_tx_fifo_stall(unsigned long data){ struct e1000_adapter *adapter = (struct e1000_adapter *) data; struct net_device *netdev = adapter->netdev; uint32_t tctl; if(atomic_read(&adapter->tx_fifo_stall)) { if((E1000_READ_REG(&adapter->hw, TDT) == E1000_READ_REG(&adapter->hw, TDH)) && (E1000_READ_REG(&adapter->hw, TDFT) == E1000_READ_REG(&adapter->hw, TDFH)) && (E1000_READ_REG(&adapter->hw, TDFTS) == E1000_READ_REG(&adapter->hw, TDFHS))) { tctl = E1000_READ_REG(&adapter->hw, TCTL); E1000_WRITE_REG(&adapter->hw, TCTL, tctl & ~E1000_TCTL_EN); E1000_WRITE_REG(&adapter->hw, TDFT, adapter->tx_head_addr); E1000_WRITE_REG(&adapter->hw, TDFH, adapter->tx_head_addr); E1000_WRITE_REG(&adapter->hw, TDFTS, adapter->tx_head_addr); E1000_WRITE_REG(&adapter->hw, TDFHS, adapter->tx_head_addr); E1000_WRITE_REG(&adapter->hw, TCTL, tctl); E1000_WRITE_FLUSH(&adapter->hw); adapter->tx_fifo_head = 0; atomic_set(&adapter->tx_fifo_stall, 0); netif_wake_queue(netdev); } else { mod_timer(&adapter->tx_fifo_stall_timer, jiffies + 1); } }}/** * e1000_watchdog - Timer Call-back * @data: pointer to netdev cast into an unsigned long **/static voide1000_watchdog(unsigned long data){ struct e1000_adapter *adapter = (struct e1000_adapter *) data; struct net_device *netdev = adapter->netdev; struct e1000_desc_ring *txdr = &adapter->tx_ring; uint32_t link; e1000_check_for_link(&adapter->hw); if((adapter->hw.media_type == e1000_media_type_internal_serdes) && !(E1000_READ_REG(&adapter->hw, TXCW) & E1000_TXCW_ANE)) link = !adapter->hw.serdes_link_down; else link = E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU; if(link) { if(!netif_carrier_ok(netdev)) { e1000_get_speed_and_duplex(&adapter->hw, &adapter->link_speed, &adapter->link_duplex); DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s\n", adapter->link_speed, adapter->link_duplex == FULL_DUPLEX ? "Full Duplex" : "Half Duplex"); netif_carrier_on(netdev); netif_wake_queue(netdev); mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); adapter->smartspeed = 0; } } else { if(netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; DPRINTK(LINK, INFO, "NIC Link is Down\n"); netif_carrier_off(netdev); netif_stop_queue(netdev); mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); } e1000_smartspeed(adapter); } e1000_update_stats(adapter); adapter->hw.tx_packet_delta = adapter->stats.tpt - adapter->tpt_old; adapter->tpt_old = adapter->stats.tpt; adapter->hw.collision_delta = adapter->stats.colc - adapter->colc_old; adapter->colc_old = adapter->stats.colc; adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old; adapter->gorcl_old = adapter->stats.gorcl; adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old; adapter->gotcl_old = adapter->stats.gotcl; e1000_update_adaptive(&adapter->hw); if(!netif_carrier_ok(netdev)) { if(E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { /* We've lost link, so the controller stops DMA, * but we've got queued Tx work that's never going * to get done, so reset controller to flush Tx. * (Do the reset outside of interrupt context). */ schedule_task(&adapter->tx_timeout_task); } } /* Dynamic mode for Interrupt Throttle Rate (ITR) */ if(adapter->hw.mac_type >= e1000_82540 && adapter->itr == 1) { /* Symmetric Tx/Rx gets a reduced ITR=2000; Total * asymmetrical Tx or Rx gets ITR=8000; everyone * else is between 2000-8000. */ uint32_t goc = (adapter->gotcl + adapter->gorcl) / 10000; uint32_t dif = (adapter->gotcl > adapter->gorcl ? adapter->gotcl - adapter->gorcl : adapter->gorcl - adapter->gotcl) / 10000; uint32_t itr = goc > 0 ? (dif * 6000 / goc + 2000) : 8000; E1000_WRITE_REG(&adapter->hw, ITR, 1000000000 / (itr * 256)); } /* Cause software interrupt to ensure rx ring is cleaned */ E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0); /* Force detection of hung controller every watchdog period*/ adapter->detect_tx_hung = TRUE; /* Reset the timer */ mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);}#define E1000_TX_FLAGS_CSUM 0x00000001#define E1000_TX_FLAGS_VLAN 0x00000002#define E1000_TX_FLAGS_TSO 0x00000004#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000#define E1000_TX_FLAGS_VLAN_SHIFT 16static inline boolean_te1000_tso(struct e1000_adapter *adapter, struct sk_buff *skb){#ifdef NETIF_F_TSO struct e1000_context_desc *context_desc; unsigned int i; uint32_t cmd_length = 0; uint16_t ipcse, tucse, mss; uint8_t ipcss, ipcso, tucss, tucso, hdr_len; if(skb_shinfo(skb)->tso_size) { hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); mss = skb_shinfo(skb)->tso_size; skb->nh.iph->tot_len = 0; skb->nh.iph->check = 0; skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr, skb->nh.iph->daddr, 0, IPPROTO_TCP, 0); ipcss = skb->nh.raw - skb->data; ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data; ipcse = skb->h.raw - skb->data - 1; tucss = skb->h.raw - skb->data; tucso = (void *)&(skb->h.th->check) - (void *)skb->data; tucse = 0; cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE | E1000_TXD_CMD_IP | E1000_TXD_CMD_TCP | (skb->len - (hdr_len))); i = adapter->tx_ring.next_to_use; context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); context_desc->lower_setup.ip_fields.ipcss = ipcss; context_desc->lower_setup.ip_fields.ipcso = ipcso; context_desc->lower_setup.ip_fields.ipcse = cpu_to_le16(ipcse); context_desc->upper_setup.tcp_fields.tucss = tucss; context_desc->upper_setup.tcp_fields.tucso = tucso; context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse); context_desc->tcp_seg_setup.fields.mss = cpu_to_le16(mss); context_desc->tcp_seg_setup.fields.hdr_len = hdr_len; context_desc->cmd_and_length = cpu_to_le32(cmd_length); if(++i == adapter->tx_ring.count) i = 0; adapter->tx_ring.next_to_use = i; return TRUE; }#endif return FALSE;}static inline boolean_te1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb){ struct e1000_context_desc *context_desc; unsigned int i; uint8_t css; if(likely(skb->ip_summed == CHECKSUM_HW)) { css = skb->h.raw - skb->data; i = adapter->tx_ring.next_to_use; context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i); context_desc->upper_setup.tcp_fields.tucss = css; context_desc->upper_setup.tcp_fields.tucso = css + skb->csum; context_desc->upper_setup.tcp_fields.tucse = 0; context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT); if(unlikely(++i == adapter->tx_ring.count)) i = 0; adapter->tx_ring.next_to_use = i; return TRUE; } return FALSE;}#define E1000_MAX_TXD_PWR 12#define E1000_MAX_DATA_PER_TXD (1<<E1000_MAX_TXD_PWR)static inline inte1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb, unsigned int first, unsigned int max_per_txd, unsigned int nr_frags, unsigned int mss){ struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_buffer *buffer_info; unsigned int len = skb->len; unsigned int offset = 0, size, count = 0, i; unsigned int f; len -= skb->data_len; i = tx_ring->next_to_use; while(len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, max_per_txd);#ifdef NETIF_F_TSO /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ if(unlikely(mss && !nr_frags && size == len && size > 8)) size -= 4;#endif /* Workaround for potential 82544 hang in PCI-X. Avoid * terminating buffers within evenly-aligned dwords. */ if(unlikely(adapter->pcix_82544 && !((unsigned long)(skb->data + offset + size - 1) & 4) && size > 4)) size -= 4; buffer_info->length = size; buffer_info->dma = pci_map_single(adapter->pdev, skb->data + offset, size, PCI_DMA_TODEVICE); buffer_info->time_stamp = jiffies; len -= size; offset += size; count++; if(unlikely(++i == tx_ring->count)) i = 0; } for(f = 0; f < nr_frags; f++) { struct skb_frag_struct *frag; frag = &skb_shinfo(skb)->frags[f]; len = frag->size; offset = frag->page_offset; while(len) { buffer_info = &tx_ring->buffer_info[i]; size = min(len, max_per_txd);#ifdef NETIF_F_TSO /* Workaround for premature desc write-backs * in TSO mode. Append 4-byte sentinel desc */ if(unlikely(mss && f == (nr_frags-1) && size == len && size > 8)) size -= 4;#endif /* Workaround for potential 82544 hang in PCI-X. * Avoid terminating buffers within evenly-aligned * dwords. */ if(unlikely(adapter->pcix_82544 && !((unsigned long)(frag->page+offset+size-1) & 4) && size > 4)) size -= 4; buffer_info->length = size; buffer_info->dma = pci_map_page(adapter->pdev, frag->page, offset, size, PCI_DMA_TODEVICE); buffer_info->time_stamp = jiffies; len -= size; offset += size; count++; if(unlikely(++i == tx_ring->count)) i = 0; } } i = (i == 0) ? tx_ring->count - 1 : i - 1; tx_ring->buffer_info[i].skb = skb; tx_ring->buffer_info[first].next_to_watch = i; return count;}static inline voide1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags){ struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct e1000_tx_desc *tx_desc = NULL; struct e1000_buffer *buffer_info; uint32_t txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS; unsigned int i; if(likely(tx_flags & E1000_TX_FLAGS_TSO)) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D | E1000_TXD_CMD_TSE; txd_upper |= (E1000_TXD_POPTS_IXSM | E1000_TXD_POPTS_TXSM) << 8; } if(likely(tx_flags & E1000_TX_FLAGS_CSUM)) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; txd_upper |= E1000_TXD_POPTS_TXSM << 8; } if(unlikely(tx_flags & E1000_TX_FLAGS_VLAN)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -