diff options
Diffstat (limited to 'drivers/net/ethernet/intel/igc/igc_main.c')
| -rw-r--r-- | drivers/net/ethernet/intel/igc/igc_main.c | 231 | 
1 files changed, 227 insertions, 4 deletions
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 24888676f69b..9700527dd797 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -795,6 +795,44 @@ static int igc_set_mac(struct net_device *netdev, void *p)  	return 0;  } +/** + *  igc_write_mc_addr_list - write multicast addresses to MTA + *  @netdev: network interface device structure + * + *  Writes multicast address list to the MTA hash table. + *  Returns: -ENOMEM on failure + *           0 on no addresses written + *           X on writing X addresses to MTA + **/ +static int igc_write_mc_addr_list(struct net_device *netdev) +{ +	struct igc_adapter *adapter = netdev_priv(netdev); +	struct igc_hw *hw = &adapter->hw; +	struct netdev_hw_addr *ha; +	u8  *mta_list; +	int i; + +	if (netdev_mc_empty(netdev)) { +		/* nothing to program, so clear mc list */ +		igc_update_mc_addr_list(hw, NULL, 0); +		return 0; +	} + +	mta_list = kcalloc(netdev_mc_count(netdev), 6, GFP_ATOMIC); +	if (!mta_list) +		return -ENOMEM; + +	/* The shared function expects a packed array of only addresses. */ +	i = 0; +	netdev_for_each_mc_addr(ha, netdev) +		memcpy(mta_list + (i++ * ETH_ALEN), ha->addr, ETH_ALEN); + +	igc_update_mc_addr_list(hw, mta_list, i); +	kfree(mta_list); + +	return netdev_mc_count(netdev); +} +  static void igc_tx_ctxtdesc(struct igc_ring *tx_ring,  			    struct igc_tx_buffer *first,  			    u32 vlan_macip_lens, u32 type_tucmd, @@ -1163,6 +1201,46 @@ static netdev_tx_t igc_xmit_frame(struct sk_buff *skb,  	return igc_xmit_frame_ring(skb, igc_tx_queue_mapping(adapter, skb));  } +static void igc_rx_checksum(struct igc_ring *ring, +			    union igc_adv_rx_desc *rx_desc, +			    struct sk_buff *skb) +{ +	skb_checksum_none_assert(skb); + +	/* Ignore Checksum bit is set */ +	if (igc_test_staterr(rx_desc, IGC_RXD_STAT_IXSM)) +		return; + +	/* Rx checksum disabled via ethtool */ +	if (!(ring->netdev->features & NETIF_F_RXCSUM)) +		return; + +	/* TCP/UDP checksum error bit is set */ +	if (igc_test_staterr(rx_desc, +			     IGC_RXDEXT_STATERR_TCPE | +			     IGC_RXDEXT_STATERR_IPE)) { +		/* work around errata with sctp packets where the TCPE aka +		 * L4E bit is set incorrectly on 64 byte (60 byte w/o crc) +		 * packets (aka let the stack check the crc32c) +		 */ +		if (!(skb->len == 60 && +		      test_bit(IGC_RING_FLAG_RX_SCTP_CSUM, &ring->flags))) { +			u64_stats_update_begin(&ring->rx_syncp); +			ring->rx_stats.csum_err++; +			u64_stats_update_end(&ring->rx_syncp); +		} +		/* let the stack verify checksum errors */ +		return; +	} +	/* It must be a TCP or UDP packet with a valid checksum */ +	if (igc_test_staterr(rx_desc, IGC_RXD_STAT_TCPCS | +				      IGC_RXD_STAT_UDPCS)) +		skb->ip_summed = CHECKSUM_UNNECESSARY; + +	dev_dbg(ring->dev, "cksum success: bits %08X\n", +		le32_to_cpu(rx_desc->wb.upper.status_error)); +} +  static inline void igc_rx_hash(struct igc_ring *ring,  			       union igc_adv_rx_desc *rx_desc,  			       struct sk_buff *skb) @@ -1189,6 +1267,8 @@ static void igc_process_skb_fields(struct igc_ring *rx_ring,  {  	igc_rx_hash(rx_ring, rx_desc, skb); +	igc_rx_checksum(rx_ring, rx_desc, skb); +  	skb_record_rx_queue(skb, rx_ring->queue_index);  	skb->protocol = eth_type_trans(skb, rx_ring->netdev); @@ -2192,7 +2272,6 @@ static int igc_change_mtu(struct net_device *netdev, int new_mtu)  {  	int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;  	struct igc_adapter *adapter = netdev_priv(netdev); -	struct pci_dev *pdev = adapter->pdev;  	/* adjust max frame to be at least the size of a standard frame */  	if (max_frame < (ETH_FRAME_LEN + ETH_FCS_LEN)) @@ -2207,8 +2286,8 @@ static int igc_change_mtu(struct net_device *netdev, int new_mtu)  	if (netif_running(netdev))  		igc_down(adapter); -	dev_info(&pdev->dev, "changing MTU from %d to %d\n", -		 netdev->mtu, new_mtu); +	netdev_dbg(netdev, "changing MTU from %d to %d\n", +		   netdev->mtu, new_mtu);  	netdev->mtu = new_mtu;  	if (netif_running(netdev)) @@ -2518,6 +2597,110 @@ int igc_del_mac_steering_filter(struct igc_adapter *adapter,  					IGC_MAC_STATE_QUEUE_STEERING | flags);  } +/* Add a MAC filter for 'addr' directing matching traffic to 'queue', + * 'flags' is used to indicate what kind of match is made, match is by + * default for the destination address, if matching by source address + * is desired the flag IGC_MAC_STATE_SRC_ADDR can be used. + */ +static int igc_add_mac_filter(struct igc_adapter *adapter, +			      const u8 *addr, const u8 queue) +{ +	struct igc_hw *hw = &adapter->hw; +	int rar_entries = hw->mac.rar_entry_count; +	int i; + +	if (is_zero_ether_addr(addr)) +		return -EINVAL; + +	/* Search for the first empty entry in the MAC table. +	 * Do not touch entries at the end of the table reserved for the VF MAC +	 * addresses. +	 */ +	for (i = 0; i < rar_entries; i++) { +		if (!igc_mac_entry_can_be_used(&adapter->mac_table[i], +					       addr, 0)) +			continue; + +		ether_addr_copy(adapter->mac_table[i].addr, addr); +		adapter->mac_table[i].queue = queue; +		adapter->mac_table[i].state |= IGC_MAC_STATE_IN_USE; + +		igc_rar_set_index(adapter, i); +		return i; +	} + +	return -ENOSPC; +} + +/* Remove a MAC filter for 'addr' directing matching traffic to + * 'queue', 'flags' is used to indicate what kind of match need to be + * removed, match is by default for the destination address, if + * matching by source address is to be removed the flag + * IGC_MAC_STATE_SRC_ADDR can be used. + */ +static int igc_del_mac_filter(struct igc_adapter *adapter, +			      const u8 *addr, const u8 queue) +{ +	struct igc_hw *hw = &adapter->hw; +	int rar_entries = hw->mac.rar_entry_count; +	int i; + +	if (is_zero_ether_addr(addr)) +		return -EINVAL; + +	/* Search for matching entry in the MAC table based on given address +	 * and queue. Do not touch entries at the end of the table reserved +	 * for the VF MAC addresses. +	 */ +	for (i = 0; i < rar_entries; i++) { +		if (!(adapter->mac_table[i].state & IGC_MAC_STATE_IN_USE)) +			continue; +		if (adapter->mac_table[i].state != 0) +			continue; +		if (adapter->mac_table[i].queue != queue) +			continue; +		if (!ether_addr_equal(adapter->mac_table[i].addr, addr)) +			continue; + +		/* When a filter for the default address is "deleted", +		 * we return it to its initial configuration +		 */ +		if (adapter->mac_table[i].state & IGC_MAC_STATE_DEFAULT) { +			adapter->mac_table[i].state = +				IGC_MAC_STATE_DEFAULT | IGC_MAC_STATE_IN_USE; +			adapter->mac_table[i].queue = 0; +		} else { +			adapter->mac_table[i].state = 0; +			adapter->mac_table[i].queue = 0; +			memset(adapter->mac_table[i].addr, 0, ETH_ALEN); +		} + +		igc_rar_set_index(adapter, i); +		return 0; +	} + +	return -ENOENT; +} + +static int igc_uc_sync(struct net_device *netdev, const unsigned char *addr) +{ +	struct igc_adapter *adapter = netdev_priv(netdev); +	int ret; + +	ret = igc_add_mac_filter(adapter, addr, adapter->num_rx_queues); + +	return min_t(int, ret, 0); +} + +static int igc_uc_unsync(struct net_device *netdev, const unsigned char *addr) +{ +	struct igc_adapter *adapter = netdev_priv(netdev); + +	igc_del_mac_filter(adapter, addr, adapter->num_rx_queues); + +	return 0; +} +  /**   * igc_set_rx_mode - Secondary Unicast, Multicast and Promiscuous mode set   * @netdev: network interface device structure @@ -2529,6 +2712,44 @@ int igc_del_mac_steering_filter(struct igc_adapter *adapter,   */  static void igc_set_rx_mode(struct net_device *netdev)  { +	struct igc_adapter *adapter = netdev_priv(netdev); +	struct igc_hw *hw = &adapter->hw; +	u32 rctl = 0, rlpml = MAX_JUMBO_FRAME_SIZE; +	int count; + +	/* Check for Promiscuous and All Multicast modes */ +	if (netdev->flags & IFF_PROMISC) { +		rctl |= IGC_RCTL_UPE | IGC_RCTL_MPE; +	} else { +		if (netdev->flags & IFF_ALLMULTI) { +			rctl |= IGC_RCTL_MPE; +		} else { +			/* Write addresses to the MTA, if the attempt fails +			 * then we should just turn on promiscuous mode so +			 * that we can at least receive multicast traffic +			 */ +			count = igc_write_mc_addr_list(netdev); +			if (count < 0) +				rctl |= IGC_RCTL_MPE; +		} +	} + +	/* Write addresses to available RAR registers, if there is not +	 * sufficient space to store all the addresses then enable +	 * unicast promiscuous mode +	 */ +	if (__dev_uc_sync(netdev, igc_uc_sync, igc_uc_unsync)) +		rctl |= IGC_RCTL_UPE; + +	/* update state of unicast and multicast */ +	rctl |= rd32(IGC_RCTL) & ~(IGC_RCTL_UPE | IGC_RCTL_MPE); +	wr32(IGC_RCTL, rctl); + +#if (PAGE_SIZE < 8192) +	if (adapter->max_frame_size <= IGC_MAX_FRAME_BUILD_SKB) +		rlpml = IGC_MAX_FRAME_BUILD_SKB; +#endif +	wr32(IGC_RLPML, rlpml);  }  /** @@ -3982,6 +4203,7 @@ static const struct net_device_ops igc_netdev_ops = {  	.ndo_open		= igc_open,  	.ndo_stop		= igc_close,  	.ndo_start_xmit		= igc_xmit_frame, +	.ndo_set_rx_mode	= igc_set_rx_mode,  	.ndo_set_mac_address	= igc_set_mac,  	.ndo_change_mtu		= igc_change_mtu,  	.ndo_get_stats		= igc_get_stats, @@ -4211,7 +4433,9 @@ static int igc_probe(struct pci_dev *pdev,  		goto err_sw_init;  	/* Add supported features to the features list*/ +	netdev->features |= NETIF_F_RXCSUM;  	netdev->features |= NETIF_F_HW_CSUM; +	netdev->features |= NETIF_F_SCTP_CRC;  	/* setup the private structure */  	err = igc_sw_init(adapter); @@ -4349,7 +4573,6 @@ static void igc_remove(struct pci_dev *pdev)  	pci_release_mem_regions(pdev);  	kfree(adapter->mac_table); -	kfree(adapter->shadow_vfta);  	free_netdev(netdev);  	pci_disable_pcie_error_reporting(pdev);  |