diff options
Diffstat (limited to 'drivers/net/ethernet/ibm/ibmveth.c')
| -rw-r--r-- | drivers/net/ethernet/ibm/ibmveth.c | 79 | 
1 files changed, 74 insertions, 5 deletions
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index ebe60719e489..a831f947ca8c 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -58,7 +58,7 @@ static struct kobj_type ktype_veth_pool;  static const char ibmveth_driver_name[] = "ibmveth";  static const char ibmveth_driver_string[] = "IBM Power Virtual Ethernet Driver"; -#define ibmveth_driver_version "1.05" +#define ibmveth_driver_version "1.06"  MODULE_AUTHOR("Santiago Leon <[email protected]>");  MODULE_DESCRIPTION("IBM Power Virtual Ethernet Driver"); @@ -137,6 +137,11 @@ static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter)  	return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK;  } +static inline int ibmveth_rxq_large_packet(struct ibmveth_adapter *adapter) +{ +	return ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_LRG_PKT; +} +  static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)  {  	return be32_to_cpu(adapter->rx_queue.queue_addr[adapter->rx_queue.index].length); @@ -1174,6 +1179,53 @@ map_failed:  	goto retry_bounce;  } +static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt) +{ +	struct tcphdr *tcph; +	int offset = 0; +	int hdr_len; + +	/* only TCP packets will be aggregated */ +	if (skb->protocol == htons(ETH_P_IP)) { +		struct iphdr *iph = (struct iphdr *)skb->data; + +		if (iph->protocol == IPPROTO_TCP) { +			offset = iph->ihl * 4; +			skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; +		} else { +			return; +		} +	} else if (skb->protocol == htons(ETH_P_IPV6)) { +		struct ipv6hdr *iph6 = (struct ipv6hdr *)skb->data; + +		if (iph6->nexthdr == IPPROTO_TCP) { +			offset = sizeof(struct ipv6hdr); +			skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; +		} else { +			return; +		} +	} else { +		return; +	} +	/* if mss is not set through Large Packet bit/mss in rx buffer, +	 * expect that the mss will be written to the tcp header checksum. +	 */ +	tcph = (struct tcphdr *)(skb->data + offset); +	if (lrg_pkt) { +		skb_shinfo(skb)->gso_size = mss; +	} else if (offset) { +		skb_shinfo(skb)->gso_size = ntohs(tcph->check); +		tcph->check = 0; +	} + +	if (skb_shinfo(skb)->gso_size) { +		hdr_len = offset + tcph->doff * 4; +		skb_shinfo(skb)->gso_segs = +				DIV_ROUND_UP(skb->len - hdr_len, +					     skb_shinfo(skb)->gso_size); +	} +} +  static int ibmveth_poll(struct napi_struct *napi, int budget)  {  	struct ibmveth_adapter *adapter = @@ -1182,6 +1234,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget)  	int frames_processed = 0;  	unsigned long lpar_rc;  	struct iphdr *iph; +	u16 mss = 0;  restart_poll:  	while (frames_processed < budget) { @@ -1199,9 +1252,21 @@ restart_poll:  			int length = ibmveth_rxq_frame_length(adapter);  			int offset = ibmveth_rxq_frame_offset(adapter);  			int csum_good = ibmveth_rxq_csum_good(adapter); +			int lrg_pkt = ibmveth_rxq_large_packet(adapter);  			skb = ibmveth_rxq_get_buffer(adapter); +			/* if the large packet bit is set in the rx queue +			 * descriptor, the mss will be written by PHYP eight +			 * bytes from the start of the rx buffer, which is +			 * skb->data at this stage +			 */ +			if (lrg_pkt) { +				__be64 *rxmss = (__be64 *)(skb->data + 8); + +				mss = (u16)be64_to_cpu(*rxmss); +			} +  			new_skb = NULL;  			if (length < rx_copybreak)  				new_skb = netdev_alloc_skb(netdev, length); @@ -1235,11 +1300,15 @@ restart_poll:  					if (iph->check == 0xffff) {  						iph->check = 0;  						iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); -						adapter->rx_large_packets++;  					}  				}  			} +			if (length > netdev->mtu + ETH_HLEN) { +				ibmveth_rx_mss_helper(skb, mss, lrg_pkt); +				adapter->rx_large_packets++; +			} +  			napi_gro_receive(napi, skb);	/* send it up */  			netdev->stats.rx_packets++; @@ -1349,9 +1418,6 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu)  	int i, rc;  	int need_restart = 0; -	if (new_mtu < IBMVETH_MIN_MTU) -		return -EINVAL; -  	for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++)  		if (new_mtu_oh <= adapter->rx_buff_pool[i].buff_size)  			break; @@ -1551,6 +1617,9 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)  		netdev->hw_features |= NETIF_F_TSO;  	} +	netdev->min_mtu = IBMVETH_MIN_MTU; +	netdev->max_mtu = ETH_MAX_MTU; +  	memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN);  	if (firmware_has_feature(FW_FEATURE_CMO))  |