diff options
Diffstat (limited to 'drivers/net/sky2.c')
| -rw-r--r-- | drivers/net/sky2.c | 195 | 
1 files changed, 77 insertions, 118 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index ff8d262dc27..3ee41da130c 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1198,12 +1198,12 @@ static void rx_set_checksum(struct sky2_port *sky2)  	sky2_write32(sky2->hw,  		     Q_ADDR(rxqaddr[sky2->port], Q_CSR), -		     (sky2->flags & SKY2_FLAG_RX_CHECKSUM) +		     (sky2->netdev->features & NETIF_F_RXCSUM)  		     ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);  }  /* Enable/disable receive hash calculation (RSS) */ -static void rx_set_rss(struct net_device *dev) +static void rx_set_rss(struct net_device *dev, u32 features)  {  	struct sky2_port *sky2 = netdev_priv(dev);  	struct sky2_hw *hw = sky2->hw; @@ -1216,7 +1216,7 @@ static void rx_set_rss(struct net_device *dev)  	}  	/* Program RSS initial values */ -	if (dev->features & NETIF_F_RXHASH) { +	if (features & NETIF_F_RXHASH) {  		u32 key[nkeys];  		get_random_bytes(key, nkeys * sizeof(u32)); @@ -1322,32 +1322,32 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)  	return err;  } -#define NETIF_F_ALL_VLAN (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX) +#define SKY2_VLAN_OFFLOADS (NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO) -static void sky2_vlan_mode(struct net_device *dev) +static void sky2_vlan_mode(struct net_device *dev, u32 features)  {  	struct sky2_port *sky2 = netdev_priv(dev);  	struct sky2_hw *hw = sky2->hw;  	u16 port = sky2->port; -	if (dev->features & NETIF_F_HW_VLAN_RX) +	if (features & NETIF_F_HW_VLAN_RX)  		sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),  			     RX_VLAN_STRIP_ON);  	else  		sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),  			     RX_VLAN_STRIP_OFF); -	dev->vlan_features = dev->features &~ NETIF_F_ALL_VLAN; -	if (dev->features & NETIF_F_HW_VLAN_TX) +	if (features & NETIF_F_HW_VLAN_TX) {  		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),  			     TX_VLAN_TAG_ON); -	else { + +		dev->vlan_features |= SKY2_VLAN_OFFLOADS; +	} else {  		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),  			     TX_VLAN_TAG_OFF);  		/* Can't do transmit offload of vlan without hw vlan */ -		dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_SG -					| NETIF_F_ALL_CSUM); +		dev->vlan_features &= ~SKY2_VLAN_OFFLOADS;  	}  } @@ -1463,7 +1463,7 @@ static void sky2_rx_start(struct sky2_port *sky2)  		rx_set_checksum(sky2);  	if (!(hw->flags & SKY2_HW_RSS_BROKEN)) -		rx_set_rss(sky2->netdev); +		rx_set_rss(sky2->netdev, sky2->netdev->features);  	/* submit Rx ring */  	for (i = 0; i < sky2->rx_pending; i++) { @@ -1626,7 +1626,8 @@ static void sky2_hw_up(struct sky2_port *sky2)  	sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,  			   sky2->tx_ring_size - 1); -	sky2_vlan_mode(sky2->netdev); +	sky2_vlan_mode(sky2->netdev, sky2->netdev->features); +	netdev_update_features(sky2->netdev);  	sky2_rx_start(sky2);  } @@ -2261,12 +2262,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)  	     hw->chip_id == CHIP_ID_YUKON_FE_P))  		return -EINVAL; -	/* TSO, etc on Yukon Ultra and MTU > 1500 not supported */ -	if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U) -		dev->features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM); -  	if (!netif_running(dev)) {  		dev->mtu = new_mtu; +		netdev_update_features(dev);  		return 0;  	} @@ -2288,6 +2286,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)  	sky2_rx_clean(sky2);  	dev->mtu = new_mtu; +	netdev_update_features(dev);  	mode = DATA_BLIND_VAL(DATA_BLIND_DEF) |  		GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF); @@ -2535,8 +2534,11 @@ static void sky2_rx_checksum(struct sky2_port *sky2, u32 status)  			   "%s: receive checksum problem (status = %#x)\n",  			   sky2->netdev->name, status); -		/* Disable checksum offload */ -		sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; +		/* Disable checksum offload +		 * It will be reenabled on next ndo_set_features, but if it's +		 * really broken, will get disabled again +		 */ +		sky2->netdev->features &= ~NETIF_F_RXCSUM;  		sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),  			     BMU_DIS_RX_CHKSUM);  	} @@ -2591,7 +2593,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)  			/* This chip reports checksum status differently */  			if (hw->flags & SKY2_HW_NEW_LE) { -				if ((sky2->flags & SKY2_FLAG_RX_CHECKSUM) && +				if ((dev->features & NETIF_F_RXCSUM) &&  				    (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) &&  				    (le->css & CSS_TCPUDPCSOK))  					skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -2616,7 +2618,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)  			sky2->rx_tag = length;  			/* fall through */  		case OP_RXCHKS: -			if (likely(sky2->flags & SKY2_FLAG_RX_CHECKSUM)) +			if (likely(dev->features & NETIF_F_RXCSUM))  				sky2_rx_checksum(sky2, status);  			break; @@ -3411,10 +3413,10 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)  	ecmd->phy_address = PHY_ADDR_MARV;  	if (sky2_is_copper(hw)) {  		ecmd->port = PORT_TP; -		ecmd->speed = sky2->speed; +		ethtool_cmd_speed_set(ecmd, sky2->speed);  		ecmd->supported |=  SUPPORTED_Autoneg | SUPPORTED_TP;  	} else { -		ecmd->speed = SPEED_1000; +		ethtool_cmd_speed_set(ecmd, SPEED_1000);  		ecmd->port = PORT_FIBRE;  		ecmd->supported |=  SUPPORTED_Autoneg | SUPPORTED_FIBRE;  	} @@ -3450,8 +3452,9 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)  		sky2->speed = -1;  	} else {  		u32 setting; +		u32 speed = ethtool_cmd_speed(ecmd); -		switch (ecmd->speed) { +		switch (speed) {  		case SPEED_1000:  			if (ecmd->duplex == DUPLEX_FULL)  				setting = SUPPORTED_1000baseT_Full; @@ -3484,7 +3487,7 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)  		if ((setting & supported) == 0)  			return -EINVAL; -		sky2->speed = ecmd->speed; +		sky2->speed = speed;  		sky2->duplex = ecmd->duplex;  		sky2->flags &= ~SKY2_FLAG_AUTO_SPEED;  	} @@ -3552,28 +3555,6 @@ static const struct sky2_stat {  	{ "tx_fifo_underrun", GM_TXE_FIFO_UR },  }; -static u32 sky2_get_rx_csum(struct net_device *dev) -{ -	struct sky2_port *sky2 = netdev_priv(dev); - -	return !!(sky2->flags & SKY2_FLAG_RX_CHECKSUM); -} - -static int sky2_set_rx_csum(struct net_device *dev, u32 data) -{ -	struct sky2_port *sky2 = netdev_priv(dev); - -	if (data) -		sky2->flags |= SKY2_FLAG_RX_CHECKSUM; -	else -		sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM; - -	sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), -		     data ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); - -	return 0; -} -  static u32 sky2_get_msglevel(struct net_device *netdev)  {  	struct sky2_port *sky2 = netdev_priv(netdev); @@ -3826,23 +3807,24 @@ static void sky2_led(struct sky2_port *sky2, enum led_mode mode)  }  /* blink LED's for finding board */ -static int sky2_phys_id(struct net_device *dev, u32 data) +static int sky2_set_phys_id(struct net_device *dev, +			    enum ethtool_phys_id_state state)  {  	struct sky2_port *sky2 = netdev_priv(dev); -	unsigned int i; - -	if (data == 0) -		data = UINT_MAX; -	for (i = 0; i < data; i++) { +	switch (state) { +	case ETHTOOL_ID_ACTIVE: +		return 1;	/* cycle on/off once per second */ +	case ETHTOOL_ID_INACTIVE: +		sky2_led(sky2, MO_LED_NORM); +		break; +	case ETHTOOL_ID_ON:  		sky2_led(sky2, MO_LED_ON); -		if (msleep_interruptible(500)) -			break; +		break; +	case ETHTOOL_ID_OFF:  		sky2_led(sky2, MO_LED_OFF); -		if (msleep_interruptible(500)) -			break; +		break;  	} -	sky2_led(sky2, MO_LED_NORM);  	return 0;  } @@ -4083,34 +4065,6 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,  	}  } -/* In order to do Jumbo packets on these chips, need to turn off the - * transmit store/forward. Therefore checksum offload won't work. - */ -static int no_tx_offload(struct net_device *dev) -{ -	const struct sky2_port *sky2 = netdev_priv(dev); -	const struct sky2_hw *hw = sky2->hw; - -	return dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U; -} - -static int sky2_set_tx_csum(struct net_device *dev, u32 data) -{ -	if (data && no_tx_offload(dev)) -		return -EINVAL; - -	return ethtool_op_set_tx_csum(dev, data); -} - - -static int sky2_set_tso(struct net_device *dev, u32 data) -{ -	if (data && no_tx_offload(dev)) -		return -EINVAL; - -	return ethtool_op_set_tso(dev, data); -} -  static int sky2_get_eeprom_len(struct net_device *dev)  {  	struct sky2_port *sky2 = netdev_priv(dev); @@ -4213,31 +4167,36 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom  	return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len);  } -static int sky2_set_flags(struct net_device *dev, u32 data) +static u32 sky2_fix_features(struct net_device *dev, u32 features)  { -	struct sky2_port *sky2 = netdev_priv(dev); -	unsigned long old_feat = dev->features; -	u32 supported = 0; -	int rc; +	const struct sky2_port *sky2 = netdev_priv(dev); +	const struct sky2_hw *hw = sky2->hw; -	if (!(sky2->hw->flags & SKY2_HW_RSS_BROKEN)) -		supported |= ETH_FLAG_RXHASH; +	/* In order to do Jumbo packets on these chips, need to turn off the +	 * transmit store/forward. Therefore checksum offload won't work. +	 */ +	if (dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U) +		features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM); -	if (!(sky2->hw->flags & SKY2_HW_VLAN_BROKEN)) -		supported |= ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN; +	return features; +} -	printk(KERN_DEBUG "sky2 set_flags: supported %x data %x\n", -	       supported, data); +static int sky2_set_features(struct net_device *dev, u32 features) +{ +	struct sky2_port *sky2 = netdev_priv(dev); +	u32 changed = dev->features ^ features; -	rc = ethtool_op_set_flags(dev, data, supported); -	if (rc) -		return rc; +	if (changed & NETIF_F_RXCSUM) { +		u32 on = features & NETIF_F_RXCSUM; +		sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR), +			     on ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); +	} -	if ((old_feat ^ dev->features) & NETIF_F_RXHASH) -		rx_set_rss(dev); +	if (changed & NETIF_F_RXHASH) +		rx_set_rss(dev, features); -	if ((old_feat ^ dev->features) & NETIF_F_ALL_VLAN) -		sky2_vlan_mode(dev); +	if (changed & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)) +		sky2_vlan_mode(dev, features);  	return 0;  } @@ -4257,11 +4216,6 @@ static const struct ethtool_ops sky2_ethtool_ops = {  	.get_eeprom_len	= sky2_get_eeprom_len,  	.get_eeprom	= sky2_get_eeprom,  	.set_eeprom	= sky2_set_eeprom, -	.set_sg 	= ethtool_op_set_sg, -	.set_tx_csum	= sky2_set_tx_csum, -	.set_tso	= sky2_set_tso, -	.get_rx_csum	= sky2_get_rx_csum, -	.set_rx_csum	= sky2_set_rx_csum,  	.get_strings	= sky2_get_strings,  	.get_coalesce	= sky2_get_coalesce,  	.set_coalesce	= sky2_set_coalesce, @@ -4269,11 +4223,9 @@ static const struct ethtool_ops sky2_ethtool_ops = {  	.set_ringparam	= sky2_set_ringparam,  	.get_pauseparam = sky2_get_pauseparam,  	.set_pauseparam = sky2_set_pauseparam, -	.phys_id	= sky2_phys_id, +	.set_phys_id	= sky2_set_phys_id,  	.get_sset_count = sky2_get_sset_count,  	.get_ethtool_stats = sky2_get_ethtool_stats, -	.set_flags	= sky2_set_flags, -	.get_flags	= ethtool_op_get_flags,  };  #ifdef CONFIG_SKY2_DEBUG @@ -4553,6 +4505,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = {  	.ndo_set_mac_address	= sky2_set_mac_address,  	.ndo_set_multicast_list	= sky2_set_multicast,  	.ndo_change_mtu		= sky2_change_mtu, +	.ndo_fix_features	= sky2_fix_features, +	.ndo_set_features	= sky2_set_features,  	.ndo_tx_timeout		= sky2_tx_timeout,  	.ndo_get_stats64	= sky2_get_stats,  #ifdef CONFIG_NET_POLL_CONTROLLER @@ -4568,6 +4522,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = {  	.ndo_set_mac_address	= sky2_set_mac_address,  	.ndo_set_multicast_list	= sky2_set_multicast,  	.ndo_change_mtu		= sky2_change_mtu, +	.ndo_fix_features	= sky2_fix_features, +	.ndo_set_features	= sky2_set_features,  	.ndo_tx_timeout		= sky2_tx_timeout,  	.ndo_get_stats64	= sky2_get_stats,    }, @@ -4600,7 +4556,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,  	/* Auto speed and flow control */  	sky2->flags = SKY2_FLAG_AUTO_SPEED | SKY2_FLAG_AUTO_PAUSE;  	if (hw->chip_id != CHIP_ID_YUKON_XL) -		sky2->flags |= SKY2_FLAG_RX_CHECKSUM; +		dev->hw_features |= NETIF_F_RXCSUM;  	sky2->flow_mode = FC_BOTH; @@ -4619,18 +4575,21 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,  	sky2->port = port; -	dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG -		| NETIF_F_TSO | NETIF_F_GRO; +	dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO;  	if (highmem)  		dev->features |= NETIF_F_HIGHDMA;  	/* Enable receive hashing unless hardware is known broken */  	if (!(hw->flags & SKY2_HW_RSS_BROKEN)) -		dev->features |= NETIF_F_RXHASH; +		dev->hw_features |= NETIF_F_RXHASH; + +	if (!(hw->flags & SKY2_HW_VLAN_BROKEN)) { +		dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; +		dev->vlan_features |= SKY2_VLAN_OFFLOADS; +	} -	if (!(hw->flags & SKY2_HW_VLAN_BROKEN)) -		dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; +	dev->features |= dev->hw_features;  	/* read the mac address */  	memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);  |