Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

net: Implement SFEATURES compatibility for not updated drivers



Use discrete setting ops for not updated drivers. This will not make
them conform to full G/SFEATURES semantics, though.

Signed-off-by: default avatarMichał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4e4db200
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -591,6 +591,9 @@ struct ethtool_sfeatures {
 *      Probably there are other device-specific constraints on some features
 *      in the set. When %ETHTOOL_F_UNSUPPORTED is set, .valid is considered
 *      here as though ignored bits were cleared.
 *   %ETHTOOL_F_COMPAT - some or all changes requested were made by calling
 *      compatibility functions. Requested offload state cannot be properly
 *      managed by kernel.
 *
 * Meaning of bits in the masks are obtained by %ETHTOOL_GSSET_INFO (number of
 * bits in the arrays - always multiple of 32) and %ETHTOOL_GSTRINGS commands
@@ -600,10 +603,12 @@ struct ethtool_sfeatures {
enum ethtool_sfeatures_retval_bits {
	ETHTOOL_F_UNSUPPORTED__BIT,
	ETHTOOL_F_WISH__BIT,
	ETHTOOL_F_COMPAT__BIT,
};

#define ETHTOOL_F_UNSUPPORTED   (1 << ETHTOOL_F_UNSUPPORTED__BIT)
#define ETHTOOL_F_WISH          (1 << ETHTOOL_F_WISH__BIT)
#define ETHTOOL_F_COMPAT        (1 << ETHTOOL_F_COMPAT__BIT)

#ifdef __KERNEL__

+61 −0
Original line number Diff line number Diff line
@@ -178,6 +178,64 @@ static void ethtool_get_features_compat(struct net_device *dev,
	if (dev->ethtool_ops->get_rx_csum)
		if (dev->ethtool_ops->get_rx_csum(dev))
			features[0].active |= NETIF_F_RXCSUM;

	/* mark legacy-changeable features */
	if (dev->ethtool_ops->set_sg)
		features[0].available |= NETIF_F_SG;
	if (dev->ethtool_ops->set_tx_csum)
		features[0].available |= NETIF_F_ALL_CSUM;
	if (dev->ethtool_ops->set_tso)
		features[0].available |= NETIF_F_ALL_TSO;
	if (dev->ethtool_ops->set_rx_csum)
		features[0].available |= NETIF_F_RXCSUM;
	if (dev->ethtool_ops->set_flags)
		features[0].available |= flags_dup_features;
}

static int ethtool_set_feature_compat(struct net_device *dev,
	int (*legacy_set)(struct net_device *, u32),
	struct ethtool_set_features_block *features, u32 mask)
{
	u32 do_set;

	if (!legacy_set)
		return 0;

	if (!(features[0].valid & mask))
		return 0;

	features[0].valid &= ~mask;

	do_set = !!(features[0].requested & mask);

	if (legacy_set(dev, do_set) < 0)
		netdev_info(dev,
			"Legacy feature change (%s) failed for 0x%08x\n",
			do_set ? "set" : "clear", mask);

	return 1;
}

static int ethtool_set_features_compat(struct net_device *dev,
	struct ethtool_set_features_block *features)
{
	int compat;

	if (!dev->ethtool_ops)
		return 0;

	compat  = ethtool_set_feature_compat(dev, dev->ethtool_ops->set_sg,
		features, NETIF_F_SG);
	compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tx_csum,
		features, NETIF_F_ALL_CSUM);
	compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tso,
		features, NETIF_F_ALL_TSO);
	compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_rx_csum,
		features, NETIF_F_RXCSUM);
	compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_flags,
		features, flags_dup_features);

	return compat;
}

static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
@@ -234,6 +292,9 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
	if (features[0].valid & ~NETIF_F_ETHTOOL_BITS)
		return -EINVAL;

	if (ethtool_set_features_compat(dev, features))
		ret |= ETHTOOL_F_COMPAT;

	if (features[0].valid & ~dev->hw_features) {
		features[0].valid &= dev->hw_features;
		ret |= ETHTOOL_F_UNSUPPORTED;