diff options
Diffstat (limited to 'drivers/net/usb/smsc75xx.c')
| -rw-r--r-- | drivers/net/usb/smsc75xx.c | 131 | 
1 files changed, 48 insertions, 83 deletions
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 753ee6eb7ed..15b3d6888ae 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -65,7 +65,6 @@ struct smsc75xx_priv {  	struct usbnet *dev;  	u32 rfe_ctl;  	u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN]; -	bool use_rx_csum;  	struct mutex dataport_mutex;  	spinlock_t rfe_ctl_lock;  	struct work_struct set_multicast; @@ -504,7 +503,7 @@ static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex,  static int smsc75xx_link_reset(struct usbnet *dev)  {  	struct mii_if_info *mii = &dev->mii; -	struct ethtool_cmd ecmd; +	struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };  	u16 lcladv, rmtadv;  	int ret; @@ -520,8 +519,9 @@ static int smsc75xx_link_reset(struct usbnet *dev)  	lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);  	rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA); -	netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x" -		" rmtadv: %04x", ecmd.speed, ecmd.duplex, lcladv, rmtadv); +	netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x" +		  " rmtadv: %04x", ethtool_cmd_speed(&ecmd), +		  ecmd.duplex, lcladv, rmtadv);  	return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);  } @@ -548,28 +548,6 @@ static void smsc75xx_status(struct usbnet *dev, struct urb *urb)  			"unexpected interrupt, intdata=0x%08X", intdata);  } -/* Enable or disable Rx checksum offload engine */ -static int smsc75xx_set_rx_csum_offload(struct usbnet *dev) -{ -	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); -	unsigned long flags; -	int ret; - -	spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); - -	if (pdata->use_rx_csum) -		pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; -	else -		pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); - -	spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); - -	ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); -	check_warn_return(ret, "Error writing RFE_CTL"); - -	return 0; -} -  static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net)  {  	return MAX_EEPROM_SIZE; @@ -599,34 +577,6 @@ static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev,  	return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data);  } -static u32 smsc75xx_ethtool_get_rx_csum(struct net_device *netdev) -{ -	struct usbnet *dev = netdev_priv(netdev); -	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - -	return pdata->use_rx_csum; -} - -static int smsc75xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) -{ -	struct usbnet *dev = netdev_priv(netdev); -	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); - -	pdata->use_rx_csum = !!val; - -	return smsc75xx_set_rx_csum_offload(dev); -} - -static int smsc75xx_ethtool_set_tso(struct net_device *netdev, u32 data) -{ -	if (data) -		netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; -	else -		netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); - -	return 0; -} -  static const struct ethtool_ops smsc75xx_ethtool_ops = {  	.get_link	= usbnet_get_link,  	.nway_reset	= usbnet_nway_reset, @@ -638,12 +588,6 @@ static const struct ethtool_ops smsc75xx_ethtool_ops = {  	.get_eeprom_len	= smsc75xx_ethtool_get_eeprom_len,  	.get_eeprom	= smsc75xx_ethtool_get_eeprom,  	.set_eeprom	= smsc75xx_ethtool_set_eeprom, -	.get_tx_csum	= ethtool_op_get_tx_csum, -	.set_tx_csum	= ethtool_op_set_tx_hw_csum, -	.get_rx_csum	= smsc75xx_ethtool_get_rx_csum, -	.set_rx_csum	= smsc75xx_ethtool_set_rx_csum, -	.get_tso	= ethtool_op_get_tso, -	.set_tso	= smsc75xx_ethtool_set_tso,  };  static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) @@ -782,6 +726,30 @@ static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu)  	return usbnet_change_mtu(netdev, new_mtu);  } +/* Enable or disable Rx checksum offload engine */ +static int smsc75xx_set_features(struct net_device *netdev, u32 features) +{ +	struct usbnet *dev = netdev_priv(netdev); +	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); +	unsigned long flags; +	int ret; + +	spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); + +	if (features & NETIF_F_RXCSUM) +		pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; +	else +		pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); + +	spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); +	/* it's racing here! */ + +	ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); +	check_warn_return(ret, "Error writing RFE_CTL"); + +	return 0; +} +  static int smsc75xx_reset(struct usbnet *dev)  {  	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); @@ -960,11 +928,7 @@ static int smsc75xx_reset(struct usbnet *dev)  	netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl);  	/* Enable or disable checksum offload engines */ -	ethtool_op_set_tx_hw_csum(dev->net, DEFAULT_TX_CSUM_ENABLE); -	ret = smsc75xx_set_rx_csum_offload(dev); -	check_warn_return(ret, "Failed to set rx csum offload: %d", ret); - -	smsc75xx_ethtool_set_tso(dev->net, DEFAULT_TSO_ENABLE); +	smsc75xx_set_features(dev->net, dev->net->features);  	smsc75xx_set_multicast(dev->net); @@ -1037,6 +1001,7 @@ static const struct net_device_ops smsc75xx_netdev_ops = {  	.ndo_validate_addr	= eth_validate_addr,  	.ndo_do_ioctl 		= smsc75xx_ioctl,  	.ndo_set_multicast_list = smsc75xx_set_multicast, +	.ndo_set_features	= smsc75xx_set_features,  };  static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) @@ -1065,10 +1030,17 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)  	INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); -	pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; +	if (DEFAULT_TX_CSUM_ENABLE) { +		dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; +		if (DEFAULT_TSO_ENABLE) +			dev->net->features |= NETIF_F_SG | +				NETIF_F_TSO | NETIF_F_TSO6; +	} +	if (DEFAULT_RX_CSUM_ENABLE) +		dev->net->features |= NETIF_F_RXCSUM; -	/* We have to advertise SG otherwise TSO cannot be enabled */ -	dev->net->features |= NETIF_F_SG; +	dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | +		NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM;  	/* Init all registers */  	ret = smsc75xx_reset(dev); @@ -1091,10 +1063,11 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)  	}  } -static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a, -				     u32 rx_cmd_b) +static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb, +				     u32 rx_cmd_a, u32 rx_cmd_b)  { -	if (unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { +	if (!(dev->net->features & NETIF_F_RXCSUM) || +	    unlikely(rx_cmd_a & RX_CMD_A_LCSM)) {  		skb->ip_summed = CHECKSUM_NONE;  	} else {  		skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT)); @@ -1104,8 +1077,6 @@ static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a,  static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)  { -	struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); -  	while (skb->len > 0) {  		u32 rx_cmd_a, rx_cmd_b, align_count, size;  		struct sk_buff *ax_skb; @@ -1145,11 +1116,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)  			/* last frame in this batch */  			if (skb->len == size) { -				if (pdata->use_rx_csum) -					smsc75xx_rx_csum_offload(skb, rx_cmd_a, -						rx_cmd_b); -				else -					skb->ip_summed = CHECKSUM_NONE; +				smsc75xx_rx_csum_offload(dev, skb, rx_cmd_a, +					rx_cmd_b);  				skb_trim(skb, skb->len - 4); /* remove fcs */  				skb->truesize = size + sizeof(struct sk_buff); @@ -1167,11 +1135,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)  			ax_skb->data = packet;  			skb_set_tail_pointer(ax_skb, size); -			if (pdata->use_rx_csum) -				smsc75xx_rx_csum_offload(ax_skb, rx_cmd_a, -					rx_cmd_b); -			else -				ax_skb->ip_summed = CHECKSUM_NONE; +			smsc75xx_rx_csum_offload(dev, ax_skb, rx_cmd_a, +				rx_cmd_b);  			skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */  			ax_skb->truesize = size + sizeof(struct sk_buff);  |