📄 e1000_main.c
字号:
/** * e1000_intr - Interrupt Handler * @irq: interrupt number * @data: pointer to a network interface device structure * @pt_regs: CPU registers structure **/static voide1000_intr(int irq, void *data, struct pt_regs *regs){ struct net_device *netdev = data; struct e1000_adapter *adapter = netdev->priv; uint32_t icr = E1000_READ_REG(&adapter->hw, ICR); int i; if(!icr) return; /* Not our interrupt */ if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) { adapter->hw.get_link_status = 1; mod_timer(&adapter->watchdog_timer, jiffies); } for(i = 0; i < E1000_MAX_INTR; i++) if(!e1000_clean_rx_irq(adapter) && !e1000_clean_tx_irq(adapter)) break;}/** * e1000_clean_tx_irq - Reclaim resources after transmit completes * @adapter: board private structure **/static boolean_te1000_clean_tx_irq(struct e1000_adapter *adapter){ struct e1000_desc_ring *tx_ring = &adapter->tx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_tx_desc *tx_desc; int i, cleaned = FALSE; i = tx_ring->next_to_clean; tx_desc = E1000_TX_DESC(*tx_ring, i); while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) { cleaned = TRUE; if(tx_ring->buffer_info[i].dma) { pci_unmap_page(pdev, tx_ring->buffer_info[i].dma, tx_ring->buffer_info[i].length, PCI_DMA_TODEVICE); tx_ring->buffer_info[i].dma = 0; } if(tx_ring->buffer_info[i].skb) { dev_kfree_skb_any(tx_ring->buffer_info[i].skb); tx_ring->buffer_info[i].skb = NULL; } tx_desc->buffer_addr = 0; tx_desc->lower.data = 0; tx_desc->upper.data = 0; if(++i == tx_ring->count) i = 0; tx_desc = E1000_TX_DESC(*tx_ring, i); } tx_ring->next_to_clean = i; if(cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) netif_wake_queue(netdev); return cleaned;}/** * e1000_clean_rx_irq - Send received data up the network stack, * @adapter: board private structure **/static boolean_te1000_clean_rx_irq(struct e1000_adapter *adapter){ struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_rx_desc *rx_desc; struct sk_buff *skb; unsigned long flags; uint32_t length; uint8_t last_byte; int i, cleaned = FALSE; i = rx_ring->next_to_clean; rx_desc = E1000_RX_DESC(*rx_ring, i); while(rx_desc->status & E1000_RXD_STAT_DD) { cleaned = TRUE; pci_unmap_single(pdev, rx_ring->buffer_info[i].dma, rx_ring->buffer_info[i].length, PCI_DMA_FROMDEVICE); skb = rx_ring->buffer_info[i].skb; length = le16_to_cpu(rx_desc->length); if(!(rx_desc->status & E1000_RXD_STAT_EOP)) { /* All receives must fit into a single buffer */ E1000_DBG("Receive packet consumed multiple buffers\n"); dev_kfree_skb_irq(skb); rx_desc->status = 0; rx_ring->buffer_info[i].skb = NULL; if(++i == rx_ring->count) i = 0; rx_desc = E1000_RX_DESC(*rx_ring, i); continue; } if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) { last_byte = *(skb->data + length - 1); if(TBI_ACCEPT(&adapter->hw, rx_desc->status, rx_desc->errors, length, last_byte)) { spin_lock_irqsave(&adapter->stats_lock, flags); e1000_tbi_adjust_stats(&adapter->hw, &adapter->stats, length, skb->data); spin_unlock_irqrestore(&adapter->stats_lock, flags); length--; } else { dev_kfree_skb_irq(skb); rx_desc->status = 0; rx_ring->buffer_info[i].skb = NULL; if(++i == rx_ring->count) i = 0; rx_desc = E1000_RX_DESC(*rx_ring, i); continue; } } /* Good Receive */ skb_put(skb, length - ETHERNET_FCS_SIZE); /* Receive Checksum Offload */ e1000_rx_checksum(adapter, rx_desc, skb); skb->protocol = eth_type_trans(skb, netdev); if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) { vlan_hwaccel_rx(skb, adapter->vlgrp, (rx_desc->special & E1000_RXD_SPC_VLAN_MASK)); } else { netif_rx(skb); } netdev->last_rx = jiffies; rx_desc->status = 0; rx_ring->buffer_info[i].skb = NULL; if(++i == rx_ring->count) i = 0; rx_desc = E1000_RX_DESC(*rx_ring, i); } rx_ring->next_to_clean = i; e1000_alloc_rx_buffers(adapter); return cleaned;}/** * e1000_alloc_rx_buffers - Replace used receive buffers * @data: address of board private structure **/static voide1000_alloc_rx_buffers(struct e1000_adapter *adapter){ struct e1000_desc_ring *rx_ring = &adapter->rx_ring; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; struct e1000_rx_desc *rx_desc; struct sk_buff *skb; int reserve_len = 2; int i; i = rx_ring->next_to_use; while(!rx_ring->buffer_info[i].skb) { rx_desc = E1000_RX_DESC(*rx_ring, i); skb = dev_alloc_skb(adapter->rx_buffer_len + reserve_len); if(!skb) { /* Better luck next round */ break; } /* Make buffer alignment 2 beyond a 16 byte boundary * this will result in a 16 byte aligned IP header after * the 14 byte MAC header is removed */ skb_reserve(skb, reserve_len); skb->dev = netdev; rx_ring->buffer_info[i].skb = skb; rx_ring->buffer_info[i].length = adapter->rx_buffer_len; rx_ring->buffer_info[i].dma = pci_map_single(pdev, skb->data, adapter->rx_buffer_len, PCI_DMA_FROMDEVICE); rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma); if((i & ~(E1000_RX_BUFFER_WRITE - 1)) == i) { /* 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(); E1000_WRITE_REG(&adapter->hw, RDT, i); } if(++i == rx_ring->count) i = 0; } rx_ring->next_to_use = i;}/** * e1000_smartspeed - Workaround for SmartSpeed on 82541 and 82547 controllers. * @adapter: **/static voide1000_smartspeed(struct e1000_adapter *adapter){ uint16_t phy_status; uint16_t phy_ctrl; if((adapter->hw.phy_type != e1000_phy_igp) || !adapter->hw.autoneg || !(adapter->hw.autoneg_advertised & ADVERTISE_1000_FULL)) return; if(adapter->smartspeed == 0) { /* If Master/Slave config fault is asserted twice, * we assume back-to-back */ e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status); if(!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return; e1000_read_phy_reg(&adapter->hw, PHY_1000T_STATUS, &phy_status); if(!(phy_status & SR_1000T_MS_CONFIG_FAULT)) return; e1000_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl); if(phy_ctrl & CR_1000T_MS_ENABLE) { phy_ctrl &= ~CR_1000T_MS_ENABLE; e1000_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_ctrl); adapter->smartspeed++; if(!e1000_phy_setup_autoneg(&adapter->hw) && !e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_ctrl)) { phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_ctrl); } } return; } else if(adapter->smartspeed == E1000_SMARTSPEED_DOWNSHIFT) { /* If still no link, perhaps using 2/3 pair cable */ e1000_read_phy_reg(&adapter->hw, PHY_1000T_CTRL, &phy_ctrl); phy_ctrl |= CR_1000T_MS_ENABLE; e1000_write_phy_reg(&adapter->hw, PHY_1000T_CTRL, phy_ctrl); if(!e1000_phy_setup_autoneg(&adapter->hw) && !e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &phy_ctrl)) { phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); e1000_write_phy_reg(&adapter->hw, PHY_CTRL, phy_ctrl); } } /* Restart process after E1000_SMARTSPEED_MAX iterations */ if(adapter->smartspeed++ == E1000_SMARTSPEED_MAX) adapter->smartspeed = 0;}/** * e1000_ioctl - * @netdev: * @ifreq: * @cmd: **/static inte1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd){ switch (cmd) { case SIOCGMIIPHY: case SIOCGMIIREG: case SIOCSMIIREG: return e1000_mii_ioctl(netdev, ifr, cmd); case SIOCETHTOOL: return e1000_ethtool_ioctl(netdev, ifr); default: return -EOPNOTSUPP; }}/** * e1000_mii_ioctl - * @netdev: * @ifreq: * @cmd: **/static inte1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd){ struct e1000_adapter *adapter = netdev->priv; struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; int retval; uint16_t mii_reg; uint16_t spddplx; if(adapter->hw.media_type == e1000_media_type_fiber) return -EOPNOTSUPP; switch (cmd) { case SIOCGMIIPHY: data->phy_id = adapter->hw.phy_addr; break; case SIOCGMIIREG: if (!capable(CAP_NET_ADMIN)) return -EPERM; if (e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, &data->val_out)) return -EIO; break; case SIOCSMIIREG: if (!capable(CAP_NET_ADMIN)) return -EPERM; if (data->reg_num & ~(0x1F)) return -EFAULT; mii_reg = data->val_in; if (e1000_write_phy_reg(&adapter->hw, data->reg_num, data->val_in)) return -EIO; if (adapter->hw.phy_type == e1000_phy_m88) { switch (data->reg_num) { case PHY_CTRL: if(data->val_in & MII_CR_AUTO_NEG_EN) { adapter->hw.autoneg = 1; adapter->hw.autoneg_advertised = 0x2F; } else { if (data->val_in & 0x40) spddplx = SPEED_1000; else if (data->val_in & 0x2000) spddplx = SPEED_100; else spddplx = SPEED_10; spddplx += (data->val_in & 0x100) ? FULL_DUPLEX : HALF_DUPLEX; retval = e1000_set_spd_dplx(adapter, spddplx); if(retval) return retval; } if(netif_running(adapter->netdev)) { e1000_down(adapter); e1000_up(adapter); } else e1000_reset(adapter); break; case M88E1000_PHY_SPEC_CTRL: case M88E1000_EXT_PHY_SPEC_CTRL: if (e1000_phy_reset(&adapter->hw)) return -EIO; break; } } break; default: return -EOPNOTSUPP; } return E1000_SUCCESS;}/** * e1000_rx_checksum - Receive Checksum Offload for 82543 * @adapter: board private structure * @rx_desc: receive descriptor * @sk_buff: socket buffer with received data **/static inline voide1000_rx_checksum(struct e1000_adapter *adapter, struct e1000_rx_desc *rx_desc, struct sk_buff *skb){ /* 82543 or newer only */ if((adapter->hw.mac_type < e1000_82543) || /* Ignore Checksum bit is set */ (rx_desc->status & E1000_RXD_STAT_IXSM) || /* TCP Checksum has not been calculated */ (!(rx_desc->status & E1000_RXD_STAT_TCPCS))) { skb->ip_summed = CHECKSUM_NONE; return; } /* At this point we know the hardware did the TCP checksum */ /* now look at the TCP checksum error bit */ if(rx_desc->errors & E1000_RXD_ERR_TCPE) { /* let the stack verify checksum errors */ skb->ip_summed = CHECKSUM_NONE; adapter->hw_csum_err++; } else { /* TCP checksum is good */ skb->ip_summed = CHECKSUM_UNNECESSARY; adapter->hw_csum_good++; }}voide1000_pci_set_mwi(struct e1000_hw *hw){ struct e1000_adapter *adapter = hw->back; pci_set_mwi(adapter->pdev);}voide1000_pci_clear_mwi(struct e1000_hw *hw){ struct e1000_adapter *adapter = hw->back; pci_clear_mwi(adapter->pdev);}voide1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value){ struct e1000_adapter *adapter = hw->back; pci_read_config_word(adapter->pdev, reg, value);}voide1000_write_pci_cfg(struct
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -