Commit f5d64037 authored by Michał Mirosław's avatar Michał Mirosław Committed by David S. Miller
Browse files

net: sky2: convert to hw_features



Caveats:
 - driver modifies vlan_features on HW VLAN TX changes
 - broken RX checksum will be reenabled on features change

Signed-off-by: default avatarMichał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 87267485
Loading
Loading
Loading
Loading
+59 −102
Original line number Original line Diff line number Diff line
@@ -1198,12 +1198,12 @@ static void rx_set_checksum(struct sky2_port *sky2)


	sky2_write32(sky2->hw,
	sky2_write32(sky2->hw,
		     Q_ADDR(rxqaddr[sky2->port], Q_CSR),
		     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);
		     ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
}
}


/* Enable/disable receive hash calculation (RSS) */
/* 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_port *sky2 = netdev_priv(dev);
	struct sky2_hw *hw = sky2->hw;
	struct sky2_hw *hw = sky2->hw;
@@ -1216,7 +1216,7 @@ static void rx_set_rss(struct net_device *dev)
	}
	}


	/* Program RSS initial values */
	/* Program RSS initial values */
	if (dev->features & NETIF_F_RXHASH) {
	if (features & NETIF_F_RXHASH) {
		u32 key[nkeys];
		u32 key[nkeys];


		get_random_bytes(key, nkeys * sizeof(u32));
		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;
	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_port *sky2 = netdev_priv(dev);
	struct sky2_hw *hw = sky2->hw;
	struct sky2_hw *hw = sky2->hw;
	u16 port = sky2->port;
	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),
		sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
			     RX_VLAN_STRIP_ON);
			     RX_VLAN_STRIP_ON);
	else
	else
		sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
		sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
			     RX_VLAN_STRIP_OFF);
			     RX_VLAN_STRIP_OFF);


	dev->vlan_features = dev->features &~ NETIF_F_ALL_VLAN;
	if (features & NETIF_F_HW_VLAN_TX) {
	if (dev->features & NETIF_F_HW_VLAN_TX)
		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
			     TX_VLAN_TAG_ON);
			     TX_VLAN_TAG_ON);
	else {

		dev->vlan_features |= SKY2_VLAN_OFFLOADS;
	} else {
		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
			     TX_VLAN_TAG_OFF);
			     TX_VLAN_TAG_OFF);


		/* Can't do transmit offload of vlan without hw vlan */
		/* Can't do transmit offload of vlan without hw vlan */
		dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_SG
		dev->vlan_features &= ~SKY2_VLAN_OFFLOADS;
					| NETIF_F_ALL_CSUM);
	}
	}
}
}


@@ -1463,7 +1463,7 @@ static void sky2_rx_start(struct sky2_port *sky2)
		rx_set_checksum(sky2);
		rx_set_checksum(sky2);


	if (!(hw->flags & SKY2_HW_RSS_BROKEN))
	if (!(hw->flags & SKY2_HW_RSS_BROKEN))
		rx_set_rss(sky2->netdev);
		rx_set_rss(sky2->netdev, sky2->netdev->features);


	/* submit Rx ring */
	/* submit Rx ring */
	for (i = 0; i < sky2->rx_pending; i++) {
	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_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
			   sky2->tx_ring_size - 1);
			   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);
	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))
	     hw->chip_id == CHIP_ID_YUKON_FE_P))
		return -EINVAL;
		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)) {
	if (!netif_running(dev)) {
		dev->mtu = new_mtu;
		dev->mtu = new_mtu;
		netdev_update_features(dev);
		return 0;
		return 0;
	}
	}


@@ -2288,6 +2286,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
	sky2_rx_clean(sky2);
	sky2_rx_clean(sky2);


	dev->mtu = new_mtu;
	dev->mtu = new_mtu;
	netdev_update_features(dev);


	mode = DATA_BLIND_VAL(DATA_BLIND_DEF) |
	mode = DATA_BLIND_VAL(DATA_BLIND_DEF) |
		GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_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",
			   "%s: receive checksum problem (status = %#x)\n",
			   sky2->netdev->name, status);
			   sky2->netdev->name, status);


		/* Disable checksum offload */
		/* Disable checksum offload
		sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM;
		 * 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),
		sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
			     BMU_DIS_RX_CHKSUM);
			     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 */
			/* This chip reports checksum status differently */
			if (hw->flags & SKY2_HW_NEW_LE) {
			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_ISIPV4 | CSS_ISIPV6)) &&
				    (le->css & CSS_TCPUDPCSOK))
				    (le->css & CSS_TCPUDPCSOK))
					skb->ip_summed = CHECKSUM_UNNECESSARY;
					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;
			sky2->rx_tag = length;
			/* fall through */
			/* fall through */
		case OP_RXCHKS:
		case OP_RXCHKS:
			if (likely(sky2->flags & SKY2_FLAG_RX_CHECKSUM))
			if (likely(dev->features & NETIF_F_RXCSUM))
				sky2_rx_checksum(sky2, status);
				sky2_rx_checksum(sky2, status);
			break;
			break;


@@ -3552,28 +3554,6 @@ static const struct sky2_stat {
	{ "tx_fifo_underrun", GM_TXE_FIFO_UR },
	{ "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)
static u32 sky2_get_msglevel(struct net_device *netdev)
{
{
	struct sky2_port *sky2 = netdev_priv(netdev);
	struct sky2_port *sky2 = netdev_priv(netdev);
@@ -4084,34 +4064,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)
static int sky2_get_eeprom_len(struct net_device *dev)
{
{
	struct sky2_port *sky2 = netdev_priv(dev);
	struct sky2_port *sky2 = netdev_priv(dev);
@@ -4214,31 +4166,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);
	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);
	const struct sky2_port *sky2 = netdev_priv(dev);
	unsigned long old_feat = dev->features;
	const struct sky2_hw *hw = sky2->hw;
	u32 supported = 0;
	int rc;


	if (!(sky2->hw->flags & SKY2_HW_RSS_BROKEN))
	/* In order to do Jumbo packets on these chips, need to turn off the
		supported |= ETH_FLAG_RXHASH;
	 * 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))
	return features;
		supported |= ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN;
}


	printk(KERN_DEBUG "sky2 set_flags: supported %x data %x\n",
static int sky2_set_features(struct net_device *dev, u32 features)
	       supported, data);
{
	struct sky2_port *sky2 = netdev_priv(dev);
	u32 changed = dev->features ^ features;


	rc = ethtool_op_set_flags(dev, data, supported);
	if (changed & NETIF_F_RXCSUM) {
	if (rc)
		u32 on = features & NETIF_F_RXCSUM;
		return rc;
		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)
	if (changed & NETIF_F_RXHASH)
		rx_set_rss(dev);
		rx_set_rss(dev, features);


	if ((old_feat ^ dev->features) & NETIF_F_ALL_VLAN)
	if (changed & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX))
		sky2_vlan_mode(dev);
		sky2_vlan_mode(dev, features);


	return 0;
	return 0;
}
}
@@ -4258,11 +4215,6 @@ static const struct ethtool_ops sky2_ethtool_ops = {
	.get_eeprom_len	= sky2_get_eeprom_len,
	.get_eeprom_len	= sky2_get_eeprom_len,
	.get_eeprom	= sky2_get_eeprom,
	.get_eeprom	= sky2_get_eeprom,
	.set_eeprom	= sky2_set_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_strings	= sky2_get_strings,
	.get_coalesce	= sky2_get_coalesce,
	.get_coalesce	= sky2_get_coalesce,
	.set_coalesce	= sky2_set_coalesce,
	.set_coalesce	= sky2_set_coalesce,
@@ -4273,8 +4225,6 @@ static const struct ethtool_ops sky2_ethtool_ops = {
	.set_phys_id	= sky2_set_phys_id,
	.set_phys_id	= sky2_set_phys_id,
	.get_sset_count = sky2_get_sset_count,
	.get_sset_count = sky2_get_sset_count,
	.get_ethtool_stats = sky2_get_ethtool_stats,
	.get_ethtool_stats = sky2_get_ethtool_stats,
	.set_flags	= sky2_set_flags,
	.get_flags	= ethtool_op_get_flags,
};
};


#ifdef CONFIG_SKY2_DEBUG
#ifdef CONFIG_SKY2_DEBUG
@@ -4554,6 +4504,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
	.ndo_set_mac_address	= sky2_set_mac_address,
	.ndo_set_mac_address	= sky2_set_mac_address,
	.ndo_set_multicast_list	= sky2_set_multicast,
	.ndo_set_multicast_list	= sky2_set_multicast,
	.ndo_change_mtu		= sky2_change_mtu,
	.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_tx_timeout		= sky2_tx_timeout,
	.ndo_get_stats64	= sky2_get_stats,
	.ndo_get_stats64	= sky2_get_stats,
#ifdef CONFIG_NET_POLL_CONTROLLER
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -4569,6 +4521,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
	.ndo_set_mac_address	= sky2_set_mac_address,
	.ndo_set_mac_address	= sky2_set_mac_address,
	.ndo_set_multicast_list	= sky2_set_multicast,
	.ndo_set_multicast_list	= sky2_set_multicast,
	.ndo_change_mtu		= sky2_change_mtu,
	.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_tx_timeout		= sky2_tx_timeout,
	.ndo_get_stats64	= sky2_get_stats,
	.ndo_get_stats64	= sky2_get_stats,
  },
  },
@@ -4601,7 +4555,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
	/* Auto speed and flow control */
	/* Auto speed and flow control */
	sky2->flags = SKY2_FLAG_AUTO_SPEED | SKY2_FLAG_AUTO_PAUSE;
	sky2->flags = SKY2_FLAG_AUTO_SPEED | SKY2_FLAG_AUTO_PAUSE;
	if (hw->chip_id != CHIP_ID_YUKON_XL)
	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;
	sky2->flow_mode = FC_BOTH;


@@ -4620,18 +4574,21 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,


	sky2->port = port;
	sky2->port = port;


	dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG
	dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO;
		| NETIF_F_TSO | NETIF_F_GRO;


	if (highmem)
	if (highmem)
		dev->features |= NETIF_F_HIGHDMA;
		dev->features |= NETIF_F_HIGHDMA;


	/* Enable receive hashing unless hardware is known broken */
	/* Enable receive hashing unless hardware is known broken */
	if (!(hw->flags & SKY2_HW_RSS_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 |= dev->hw_features;
		dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;


	/* read the mac address */
	/* read the mac address */
	memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
	memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
+0 −1
Original line number Original line Diff line number Diff line
@@ -2254,7 +2254,6 @@ struct sky2_port {
	u8		     wol;		/* WAKE_ bits */
	u8		     wol;		/* WAKE_ bits */
	u8		     duplex;		/* DUPLEX_HALF, DUPLEX_FULL */
	u8		     duplex;		/* DUPLEX_HALF, DUPLEX_FULL */
	u16		     flags;
	u16		     flags;
#define SKY2_FLAG_RX_CHECKSUM		0x0001
#define SKY2_FLAG_AUTO_SPEED		0x0002
#define SKY2_FLAG_AUTO_SPEED		0x0002
#define SKY2_FLAG_AUTO_PAUSE		0x0004
#define SKY2_FLAG_AUTO_PAUSE		0x0004