📄 e1000_main.c
字号:
e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb){ struct e1000_context_desc *context_desc; int i; uint8_t css, cso; if(skb->ip_summed == CHECKSUM_HW) { css = skb->h.raw - skb->data; cso = (skb->h.raw + skb->csum) - 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 = cso; context_desc->upper_setup.tcp_fields.tucse = 0; context_desc->tcp_seg_setup.data = 0; context_desc->cmd_and_length = cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT); if(++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){ struct e1000_desc_ring *tx_ring = &adapter->tx_ring; int len = skb->len, offset = 0, size, count = 0, i; int f; len -= skb->data_len; i = tx_ring->next_to_use; while(len) { size = min(len, E1000_MAX_DATA_PER_TXD); tx_ring->buffer_info[i].length = size; tx_ring->buffer_info[i].dma = pci_map_single(adapter->pdev, skb->data + offset, size, PCI_DMA_TODEVICE); tx_ring->buffer_info[i].time_stamp = jiffies; len -= size; offset += size; count++; if(++i == tx_ring->count) i = 0; } for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) { struct skb_frag_struct *frag; frag = &skb_shinfo(skb)->frags[f]; len = frag->size; offset = 0; while(len) { size = min(len, E1000_MAX_DATA_PER_TXD); tx_ring->buffer_info[i].length = size; tx_ring->buffer_info[i].dma = pci_map_page(adapter->pdev, frag->page, frag->page_offset + offset, size, PCI_DMA_TODEVICE); tx_ring->buffer_info[i].time_stamp = jiffies; len -= size; offset += size; count++; if(++i == tx_ring->count) i = 0; } } if(--i < 0) i = tx_ring->count - 1; tx_ring->buffer_info[i].skb = skb; 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; uint32_t txd_upper, txd_lower; int i; txd_upper = 0; txd_lower = adapter->txd_cmd; if(tx_flags & E1000_TX_FLAGS_CSUM) { txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D; txd_upper |= E1000_TXD_POPTS_TXSM << 8; } if(tx_flags & E1000_TX_FLAGS_VLAN) { txd_lower |= E1000_TXD_CMD_VLE; txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK); } i = tx_ring->next_to_use; while(count--) { tx_desc = E1000_TX_DESC(*tx_ring, i); tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma); tx_desc->lower.data = cpu_to_le32(txd_lower | tx_ring->buffer_info[i].length); tx_desc->upper.data = cpu_to_le32(txd_upper); if(++i == tx_ring->count) i = 0; } tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP); /* Force memory writes to complete before letting h/w * know there are new descriptors to fetch. (Only * applicable for weak-ordered memory model archs, * such as IA-64). */ wmb(); tx_ring->next_to_use = i; E1000_WRITE_REG(&adapter->hw, TDT, i);}/** * 82547 workaround to avoid controller hang in half-duplex environment. * The workaround is to avoid queuing a large packet that would span * the internal Tx FIFO ring boundary by notifying the stack to resend * the packet at a later time. This gives the Tx FIFO an opportunity to * flush all packets. When that occurs, we reset the Tx FIFO pointers * to the beginning of the Tx FIFO. **/#define E1000_FIFO_HDR 0x10#define E1000_82547_PAD_LEN 0x3E0static inline inte1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb){ uint32_t fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head; uint32_t skb_fifo_len = skb->len + E1000_FIFO_HDR; E1000_ROUNDUP(skb_fifo_len, E1000_FIFO_HDR); if(adapter->link_duplex != HALF_DUPLEX) goto no_fifo_stall_required; if(atomic_read(&adapter->tx_fifo_stall)) return 1; if(skb_fifo_len >= (E1000_82547_PAD_LEN + fifo_space)) { atomic_set(&adapter->tx_fifo_stall, 1); return 1; }no_fifo_stall_required: adapter->tx_fifo_head += skb_fifo_len; if(adapter->tx_fifo_head >= adapter->tx_fifo_size) adapter->tx_fifo_head -= adapter->tx_fifo_size; return 0;}/* Tx Descriptors needed, worst case */#define TXD_USE_COUNT(S) (((S) >> E1000_MAX_TXD_PWR) + \ (((S) & (E1000_MAX_DATA_PER_TXD - 1)) ? 1 : 0))#define DESC_NEEDED TXD_USE_COUNT(MAX_JUMBO_FRAME_SIZE) + \ MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1static inte1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev){ struct e1000_adapter *adapter = netdev->priv; int tx_flags = 0; if(skb->len <= 0) { dev_kfree_skb_any(skb); return 0; } if(E1000_DESC_UNUSED(&adapter->tx_ring) < DESC_NEEDED) { netif_stop_queue(netdev); return 1; } if(adapter->hw.mac_type == e1000_82547) { if(e1000_82547_fifo_workaround(adapter, skb)) { netif_stop_queue(netdev); mod_timer(&adapter->tx_fifo_stall_timer, jiffies); return 1; } } if(adapter->vlgrp && vlan_tx_tag_present(skb)) { tx_flags |= E1000_TX_FLAGS_VLAN; tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT); } if(e1000_tx_csum(adapter, skb)) tx_flags |= E1000_TX_FLAGS_CSUM; e1000_tx_queue(adapter, e1000_tx_map(adapter, skb), tx_flags); netdev->trans_start = jiffies; return 0;}/** * e1000_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure **/static voide1000_tx_timeout(struct net_device *netdev){ struct e1000_adapter *adapter = netdev->priv; /* Do the reset outside of interrupt context */ schedule_task(&adapter->tx_timeout_task);}static voide1000_tx_timeout_task(struct net_device *netdev){ struct e1000_adapter *adapter = netdev->priv; netif_device_detach(netdev); e1000_down(adapter); e1000_up(adapter); netif_device_attach(netdev);}/** * e1000_get_stats - Get System Network Statistics * @netdev: network interface device structure * * Returns the address of the device statistics structure. * The statistics are actually updated from the timer callback. **/static struct net_device_stats *e1000_get_stats(struct net_device *netdev){ struct e1000_adapter *adapter = netdev->priv; return &adapter->net_stats;}/** * e1000_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure * @new_mtu: new value for maximum frame size * * Returns 0 on success, negative on failure **/static inte1000_change_mtu(struct net_device *netdev, int new_mtu){ struct e1000_adapter *adapter = netdev->priv; int old_mtu = adapter->rx_buffer_len; int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) || (max_frame > MAX_JUMBO_FRAME_SIZE)) { E1000_ERR("Invalid MTU setting\n"); return -EINVAL; } if(max_frame <= MAXIMUM_ETHERNET_FRAME_SIZE) { adapter->rx_buffer_len = E1000_RXBUFFER_2048; } else if(adapter->hw.mac_type < e1000_82543) { E1000_ERR("Jumbo Frames not supported on 82542\n"); return -EINVAL; } else if(max_frame <= E1000_RXBUFFER_4096) { adapter->rx_buffer_len = E1000_RXBUFFER_4096; } else if(max_frame <= E1000_RXBUFFER_8192) { adapter->rx_buffer_len = E1000_RXBUFFER_8192; } else { adapter->rx_buffer_len = E1000_RXBUFFER_16384; } if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) { e1000_down(adapter); e1000_up(adapter); } netdev->mtu = new_mtu; adapter->hw.max_frame_size = max_frame; return 0;}/** * e1000_update_stats - Update the board statistics counters * @adapter: board private structure **/static voide1000_update_stats(struct e1000_adapter *adapter){ struct e1000_hw *hw = &adapter->hw; unsigned long flags; uint16_t phy_tmp;#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF spin_lock_irqsave(&adapter->stats_lock, flags); /* these counters are modified from e1000_adjust_tbi_stats, * called from the interrupt context, so they must only * be written while holding adapter->stats_lock */ adapter->stats.crcerrs += E1000_READ_REG(hw, CRCERRS); adapter->stats.gprc += E1000_READ_REG(hw, GPRC); adapter->gorcl = E1000_READ_REG(hw, GORCL); adapter->stats.gorcl += adapter->gorcl; adapter->stats.gorch += E1000_READ_REG(hw, GORCH); adapter->stats.bprc += E1000_READ_REG(hw, BPRC); adapter->stats.mprc += E1000_READ_REG(hw, MPRC); adapter->stats.roc += E1000_READ_REG(hw, ROC); adapter->stats.prc64 += E1000_READ_REG(hw, PRC64); adapter->stats.prc127 += E1000_READ_REG(hw, PRC127); adapter->stats.prc255 += E1000_READ_REG(hw, PRC255); adapter->stats.prc511 += E1000_READ_REG(hw, PRC511); adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023); adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522); spin_unlock_irqrestore(&adapter->stats_lock, flags); /* the rest of the counters are only modified here */ adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS); adapter->stats.mpc += E1000_READ_REG(hw, MPC); adapter->stats.scc += E1000_READ_REG(hw, SCC); adapter->stats.ecol += E1000_READ_REG(hw, ECOL); adapter->stats.mcc += E1000_READ_REG(hw, MCC); adapter->stats.latecol += E1000_READ_REG(hw, LATECOL); adapter->stats.dc += E1000_READ_REG(hw, DC); adapter->stats.sec += E1000_READ_REG(hw, SEC); adapter->stats.rlec += E1000_READ_REG(hw, RLEC); adapter->stats.xonrxc += E1000_READ_REG(hw, XONRXC); adapter->stats.xontxc += E1000_READ_REG(hw, XONTXC); adapter->stats.xoffrxc += E1000_READ_REG(hw, XOFFRXC); adapter->stats.xofftxc += E1000_READ_REG(hw, XOFFTXC); adapter->stats.fcruc += E1000_READ_REG(hw, FCRUC); adapter->stats.gptc += E1000_READ_REG(hw, GPTC); adapter->gotcl = E1000_READ_REG(hw, GOTCL); adapter->stats.gotcl += adapter->gotcl; adapter->stats.gotch += E1000_READ_REG(hw, GOTCH); adapter->stats.rnbc += E1000_READ_REG(hw, RNBC); adapter->stats.ruc += E1000_READ_REG(hw, RUC); adapter->stats.rfc += E1000_READ_REG(hw, RFC); adapter->stats.rjc += E1000_READ_REG(hw, RJC); adapter->stats.torl += E1000_READ_REG(hw, TORL); adapter->stats.torh += E1000_READ_REG(hw, TORH); adapter->stats.totl += E1000_READ_REG(hw, TOTL); adapter->stats.toth += E1000_READ_REG(hw, TOTH); adapter->stats.tpr += E1000_READ_REG(hw, TPR); adapter->stats.ptc64 += E1000_READ_REG(hw, PTC64); adapter->stats.ptc127 += E1000_READ_REG(hw, PTC127); adapter->stats.ptc255 += E1000_READ_REG(hw, PTC255); adapter->stats.ptc511 += E1000_READ_REG(hw, PTC511); adapter->stats.ptc1023 += E1000_READ_REG(hw, PTC1023); adapter->stats.ptc1522 += E1000_READ_REG(hw, PTC1522); adapter->stats.mptc += E1000_READ_REG(hw, MPTC); adapter->stats.bptc += E1000_READ_REG(hw, BPTC); /* used for adaptive IFS */ hw->tx_packet_delta = E1000_READ_REG(hw, TPT); adapter->stats.tpt += hw->tx_packet_delta; hw->collision_delta = E1000_READ_REG(hw, COLC); adapter->stats.colc += hw->collision_delta; if(hw->mac_type >= e1000_82543) { adapter->stats.algnerrc += E1000_READ_REG(hw, ALGNERRC); adapter->stats.rxerrc += E1000_READ_REG(hw, RXERRC); adapter->stats.tncrs += E1000_READ_REG(hw, TNCRS); adapter->stats.cexterr += E1000_READ_REG(hw, CEXTERR); adapter->stats.tsctc += E1000_READ_REG(hw, TSCTC); adapter->stats.tsctfc += E1000_READ_REG(hw, TSCTFC); } /* Fill out the OS statistics structure */ adapter->net_stats.rx_packets = adapter->stats.gprc; adapter->net_stats.tx_packets = adapter->stats.gptc; adapter->net_stats.rx_bytes = adapter->stats.gorcl; adapter->net_stats.tx_bytes = adapter->stats.gotcl; adapter->net_stats.multicast = adapter->stats.mprc; adapter->net_stats.collisions = adapter->stats.colc; /* Rx Errors */ adapter->net_stats.rx_errors = adapter->stats.rxerrc + adapter->stats.crcerrs + adapter->stats.algnerrc + adapter->stats.rlec + adapter->stats.rnbc + adapter->stats.mpc + adapter->stats.cexterr; adapter->net_stats.rx_dropped = adapter->stats.rnbc; adapter->net_stats.rx_length_errors = adapter->stats.rlec; adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; adapter->net_stats.rx_fifo_errors = adapter->stats.mpc; adapter->net_stats.rx_missed_errors = adapter->stats.mpc; /* Tx Errors */ adapter->net_stats.tx_errors = adapter->stats.ecol + adapter->stats.latecol; adapter->net_stats.tx_aborted_errors = adapter->stats.ecol; adapter->net_stats.tx_window_errors = adapter->stats.latecol; adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs; /* Tx Dropped needs to be maintained elsewhere */ /* Phy Stats */ if(hw->media_type == e1000_media_type_copper) { if((adapter->link_speed == SPEED_1000) && (!e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) { phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; adapter->phy_stats.idle_errors += phy_tmp; } if((hw->mac_type <= e1000_82546) && !e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp)) adapter->phy_stats.receive_errors += phy_tmp; }}/** * e1000_irq_disable - Mask off interrupt generation on the NIC * @adapter: board private structure **/static inline voide1000_irq_disable(struct e1000_adapter *adapter){ atomic_inc(&adapter->irq_sem); E1000_WRITE_REG(&adapter->hw, IMC, ~0); E1000_WRITE_FLUSH(&adapter->hw); synchronize_irq();}/** * e1000_irq_enable - Enable default interrupt generation settings * @adapter: board private structure **/static inline voide1000_irq_enable(struct e1000_adapter *adapter){ if(atomic_dec_and_test(&adapter->irq_sem)) { E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK); E1000_WRITE_FLUSH(&adapter->hw); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -