All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ben Hutchings <bhutchings@solarflare.com>
To: netdev@vger.kernel.org
Cc: linux-net-drivers@solarflare.com,
	"Michał Mirosław" <mirq-linux@rere.qmqm.pl>,
	netdev@vger.kernel.org, "David Miller" <davem@davemloft.net>
Subject: [RFC PATCH ethtool 3/3] ethtool: Use ETHTOOL_{G,S}FEATURES where available
Date: Mon, 16 May 2011 16:58:03 +0100	[thread overview]
Message-ID: <1305561483.2885.17.camel@bwh-desktop> (raw)
In-Reply-To: <BANLkTi=Q_RrGgw0H=OeNeJ4JkkCgyYckFA@mail.gmail.com>

Also use the new structures in any case.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
 ethtool.c |  294 +++++++++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 199 insertions(+), 95 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index 5eeca64..db1873c 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -297,8 +297,7 @@ static void show_usage(void)
 static char *devname = NULL;
 
 static int goffload_changed = 0;
-static u32 off_features_wanted = 0;
-static u32 off_features_mask = 0;
+struct ethtool_set_features_block off_features;
 
 static struct ethtool_pauseparam epause;
 static int gpause_changed = 0;
@@ -439,30 +438,30 @@ static struct cmdline_info cmdline_seeprom[] = {
 };
 
 static struct cmdline_info cmdline_offload[] = {
-	{ "rx", CMDL_FLAG, &off_features_wanted, NULL,
-	  NETIF_F_RXCSUM, &off_features_mask },
-	{ "tx", CMDL_FLAG, &off_features_wanted, NULL,
-	  NETIF_F_ALL_CSUM, &off_features_mask },
-	{ "sg", CMDL_FLAG, &off_features_wanted, NULL,
-	  NETIF_F_SG, &off_features_mask },
-	{ "tso", CMDL_FLAG, &off_features_wanted, NULL,
-	  NETIF_F_ALL_TSO, &off_features_mask },
-	{ "ufo", CMDL_FLAG, &off_features_wanted, NULL,
-	  NETIF_F_UFO, &off_features_mask },
-	{ "gso", CMDL_FLAG, &off_features_wanted, NULL,
-	  NETIF_F_GSO, &off_features_mask },
-	{ "lro", CMDL_FLAG, &off_features_wanted, NULL,
-	  NETIF_F_LRO, &off_features_mask },
-	{ "gro", CMDL_FLAG, &off_features_wanted, NULL,
-	  NETIF_F_GRO, &off_features_mask },
-	{ "rxvlan", CMDL_FLAG, &off_features_wanted, NULL,
-	  NETIF_F_HW_VLAN_TX, &off_features_mask },
-	{ "txvlan", CMDL_FLAG, &off_features_wanted, NULL,
-	  NETIF_F_HW_VLAN_TX, &off_features_mask },
-	{ "ntuple", CMDL_FLAG, &off_features_wanted, NULL,
-	  NETIF_F_NTUPLE, &off_features_mask },
-	{ "rxhash", CMDL_FLAG, &off_features_wanted, NULL,
-	  NETIF_F_RXHASH, &off_features_mask },
+	{ "rx", CMDL_FLAG, &off_features.requested, NULL,
+	  NETIF_F_RXCSUM, &off_features.valid },
+	{ "tx", CMDL_FLAG, &off_features.requested, NULL,
+	  NETIF_F_ALL_CSUM, &off_features.valid },
+	{ "sg", CMDL_FLAG, &off_features.requested, NULL,
+	  NETIF_F_SG, &off_features.valid },
+	{ "tso", CMDL_FLAG, &off_features.requested, NULL,
+	  NETIF_F_ALL_TSO, &off_features.valid },
+	{ "ufo", CMDL_FLAG, &off_features.requested, NULL,
+	  NETIF_F_UFO, &off_features.valid },
+	{ "gso", CMDL_FLAG, &off_features.requested, NULL,
+	  NETIF_F_GSO, &off_features.valid },
+	{ "lro", CMDL_FLAG, &off_features.requested, NULL,
+	  NETIF_F_LRO, &off_features.valid },
+	{ "gro", CMDL_FLAG, &off_features.requested, NULL,
+	  NETIF_F_GRO, &off_features.valid },
+	{ "rxvlan", CMDL_FLAG, &off_features.requested, NULL,
+	  NETIF_F_HW_VLAN_TX, &off_features.valid },
+	{ "txvlan", CMDL_FLAG, &off_features.requested, NULL,
+	  NETIF_F_HW_VLAN_TX, &off_features.valid },
+	{ "ntuple", CMDL_FLAG, &off_features.requested, NULL,
+	  NETIF_F_NTUPLE, &off_features.valid },
+	{ "rxhash", CMDL_FLAG, &off_features.requested, NULL,
+	  NETIF_F_RXHASH, &off_features.valid },
 };
 
 static struct cmdline_info cmdline_pause[] = {
@@ -1807,7 +1806,8 @@ static const struct {
 	{ "receive-hashing",		  0,		   NETIF_F_RXHASH },
 };
 
-static int dump_offload(u32 active, u32 mask)
+static int
+dump_offload(const struct ethtool_get_features_block *features, u32 mask)
 {
 	u32 value;
 	int i;
@@ -1816,9 +1816,12 @@ static int dump_offload(u32 active, u32 mask)
 		value = off_feature_def[i].value;
 		if (!(mask & value))
 			continue;
-		printf("%s: %s\n",
+		printf("%s: %s%s%s\n",
 		       off_feature_def[i].long_name,
-		       (active & value) ? "on" : "off");
+		       (features->active & value) ? "on" : "off",
+		       (features->requested & ~features->active & value) ?
+		       " [requested on]" : "",
+		       !(features->available & value) ? " [unchangeable]" : "");
 	}
 
 	return 0;
@@ -2149,41 +2152,65 @@ static const u32 flags_dup_features =
 	(ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | ETH_FLAG_NTUPLE |
 	 ETH_FLAG_RXHASH);
 
-static int get_offload(int fd, struct ifreq *ifr, u32 *features)
+static int get_offload(int fd, struct ifreq *ifr,
+		       struct ethtool_get_features_block *pfeatures)
 {
+	struct {
+		struct ethtool_gfeatures cmd;
+		struct ethtool_get_features_block data[1];
+	} features;
 	struct ethtool_value eval;
 	int err, allfail = 1;
 	u32 value;
 	int i;
 
-	*features = 0; 
+	features.cmd.cmd = ETHTOOL_GFEATURES;
+	features.cmd.size = ARRAY_SIZE(features.data);
+	ifr->ifr_data = (caddr_t)&features;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err == 0) {
+		allfail = 0;
+		pfeatures[0] = features.data[0];
+	} else if (errno != EOPNOTSUPP && errno != EPERM) {
+		perror("Cannot get device offload settings");
+	} else {
+		memset(pfeatures, 0, sizeof(*pfeatures));
 
-	for (i = 0; i < ARRAY_SIZE(off_feature_def); i++) {
-		value = off_feature_def[i].value;
-		if (!off_feature_def[i].cmd)
-			continue;
-		eval.cmd = off_feature_def[i].cmd;
+		for (i = 0; i < ARRAY_SIZE(off_feature_def); i++) {
+			value = off_feature_def[i].value;
+
+			/* Assume that anything we can get is changeable */
+			pfeatures[0].available |= value;
+
+			if (!off_feature_def[i].cmd)
+				continue;
+
+			eval.cmd = off_feature_def[i].cmd;
+			ifr->ifr_data = (caddr_t)&eval;
+			err = send_ioctl(fd, ifr);
+			if (err) {
+				fprintf(stderr,
+					"Cannot get device %s settings: %m\n",
+					off_feature_def[i].long_name);
+			} else {
+				if (eval.data)
+					pfeatures[0].active |= value;
+				allfail = 0;
+			}
+		}
+
+		eval.cmd = ETHTOOL_GFLAGS;
 		ifr->ifr_data = (caddr_t)&eval;
-		err = send_ioctl(fd, ifr);
+		err = ioctl(fd, SIOCETHTOOL, ifr);
 		if (err) {
-			fprintf(stderr,
-				"Cannot get device %s settings: %m\n",
-				off_feature_def[i].long_name);
+			perror("Cannot get device flags");
 		} else {
-			if (eval.data)
-				*features |= value;
+			pfeatures[0].active |=
+				eval.data & flags_dup_features;
 			allfail = 0;
 		}
-	}
 
-	eval.cmd = ETHTOOL_GFLAGS;
-	ifr->ifr_data = (caddr_t)&eval;
-	err = ioctl(fd, SIOCETHTOOL, ifr);
-	if (err) {
-		perror("Cannot get device flags");
-	} else {
-		*features |= eval.data & flags_dup_features;
-		allfail = 0;
+		pfeatures[0].requested = pfeatures[0].active;
 	}
 
 	return allfail;
@@ -2191,7 +2218,7 @@ static int get_offload(int fd, struct ifreq *ifr, u32 *features)
 
 static int do_goffload(int fd, struct ifreq *ifr)
 {
-	u32 features;
+	struct ethtool_get_features_block features;
 
 	fprintf(stdout, "Offload parameters for %s:\n", devname);
 
@@ -2200,79 +2227,156 @@ static int do_goffload(int fd, struct ifreq *ifr)
 		return 83;
 	}
 
-	return dump_offload(features, ~(u32)0);
+	return dump_offload(&features, ~(u32)0);
 }
 
 static int do_soffload(int fd, struct ifreq *ifr)
 {
-	u32 old_features, new_features, diff;
-	struct ethtool_value eval;
+	struct ethtool_get_features_block old_features, new_features;
+	struct {
+		struct ethtool_sfeatures cmd;
+		struct ethtool_set_features_block data[1];
+	} set_features;
+	int failed;
+	u32 diff;
 	int err;
 	int i;
 
+	if (off_features.valid == 0) {
+		fprintf(stdout, "no offload settings changed\n");
+		return 0;
+	}
+
 	if (get_offload(fd, ifr, &old_features)) {
 		fprintf(stderr, "no offload info available\n");
 		return 1;
 	}
 
+	set_features.cmd.cmd = ETHTOOL_SFEATURES;
+	set_features.cmd.size = ARRAY_SIZE(set_features.data);
+	set_features.data[0] = off_features;
+
 	for (i = 0; i < ARRAY_SIZE(off_feature_def); i++) {
-		if (!off_feature_def[i].cmd)
+		u32 value = off_feature_def[i].value;
+
+		if (!(off_features.valid & value))
 			continue;
-		if (off_features_mask & off_feature_def[i].value) {
-			eval.cmd = off_feature_def[i].cmd + 1;
-			eval.data = !!(off_features_wanted &
-				       off_feature_def[i].value);
-			ifr->ifr_data = (caddr_t)&eval;
-			err = send_ioctl(fd, ifr);
-			if (err) {
-				fprintf(stderr,
-					"Cannot set device %s settings: %m\n",
-					off_feature_def[i].long_name);
-				return 1;
-			}
+		if (!(old_features.available & value)) {
+			/* None of these features can be changed */
+			fprintf(stderr,
+				"Cannot set device %s settings: "
+				"Operation not supported\n",
+				off_feature_def[i].long_name);
+			return 1;
 		}
+		/* At least some of these features can be
+		 * enabled; mask out any that cannot
+		 */
+		set_features.data[0].valid &=
+			~(value & ~old_features.available);
 	}
-	if (off_features_mask & flags_dup_features) {
-		eval.cmd = ETHTOOL_GFLAGS;
-		eval.data = 0;
-		ifr->ifr_data = (caddr_t)&eval;
-		err = ioctl(fd, SIOCETHTOOL, ifr);
-		if (err) {
-			perror("Cannot get device flag settings");
-			return 91;
+
+	ifr->ifr_data = (caddr_t)&set_features;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err >= 0) {
+		/* We'll break down the warnings/errors below */
+	} else if (errno != EOPNOTSUPP && errno != EPERM) {
+		perror("Cannot set device offload settings");
+		return 1;
+	} else {
+		struct ethtool_value eval;
+
+		for (i = 0; i < ARRAY_SIZE(off_feature_def); i++) {
+			if (!off_feature_def[i].cmd)
+				continue;
+			if (off_features.valid & off_feature_def[i].value) {
+				eval.cmd = off_feature_def[i].cmd + 1;
+				eval.data = !!(off_features.requested &
+					       off_feature_def[i].value);
+				ifr->ifr_data = (caddr_t)&eval;
+				err = send_ioctl(fd, ifr);
+				if (err) {
+					fprintf(stderr,
+						"Cannot set device %s settings: %m\n",
+						off_feature_def[i].long_name);
+					return 1;
+				}
+			}
 		}
+		if (off_features.valid & flags_dup_features) {
+			eval.cmd = ETHTOOL_GFLAGS;
+			eval.data = 0;
+			ifr->ifr_data = (caddr_t)&eval;
+			err = ioctl(fd, SIOCETHTOOL, ifr);
+			if (err) {
+				perror("Cannot get device flag settings");
+				return 91;
+			}
 
-		eval.cmd = ETHTOOL_SFLAGS;
-		eval.data &= ~(off_features_mask & flags_dup_features);
-		eval.data |= (off_features_wanted &
-			      flags_dup_features);
+			eval.cmd = ETHTOOL_SFLAGS;
+			eval.data &= ~(off_features.valid & flags_dup_features);
+			eval.data |= (off_features.requested &
+				      flags_dup_features);
 
-		err = ioctl(fd, SIOCETHTOOL, ifr);
-		if (err) {
-			perror("Cannot set device flag settings");
-			return 92;
+			err = ioctl(fd, SIOCETHTOOL, ifr);
+			if (err) {
+				perror("Cannot set device flag settings");
+				return 92;
+			}
 		}
 	}
 
-	if (off_features_mask == 0) {
-		fprintf(stdout, "no offload settings changed\n");
-		return 0;
-	}
-
-	/* Were any additional changes made automatically? */
 	if (get_offload(fd, ifr, &new_features)) {
 		fprintf(stderr, "no offload info available\n");
 		return 1;
 	}
-	diff = ((old_features & ~off_features_mask) |
-		(off_features_wanted & off_features_mask)) ^
-		new_features;
+
+	failed = 0;
+
+	/* Report specific failures */
+	for (i = 0; i < ARRAY_SIZE(off_feature_def); i++) {
+		if (!(off_feature_def[i].value & off_features.valid))
+			continue;
+
+		/* For offloads where we have one name for multiple
+		 * feature flags, squash them into a boolean.
+		 */
+		if (!(off_features.requested & off_feature_def[i].value) != 
+		    !(new_features.active & off_feature_def[i].value)) {
+			int did1 = 0;
+
+			fprintf(stderr,
+				"Cannot set device %s settings",
+				off_feature_def[i].long_name);
+			if (err & ETHTOOL_F_WISH) {
+				fprintf(stderr,
+					": Feature depends on other settings");
+				did1++;
+			}
+			/* Report any remaining warning flags (including
+			 * ETHTOOL_F_UNSUPPORTED, which should not be set
+			 * since we checked for unsupported flags above).
+			 */
+			if (err & ~ETHTOOL_F_WISH) {
+				fprintf(stderr, "%s Warning flags %#x",
+					did1 ? ";" : ":",
+					err & ~ETHTOOL_F_WISH);
+			}
+			fprintf(stderr, "\n");
+
+			failed = 1;
+		}
+	}
+
+	/* Were any additional changes made automatically? */
+	diff = (new_features.active ^ old_features.active) &
+		    ~off_features.valid;
 	if (diff) {
 		printf("Additional changes:\n");
-		dump_offload(new_features, diff);
+		dump_offload(&new_features, diff);
 	}
 
-	return 0;
+	return failed;
 }
 
 static int do_gset(int fd, struct ifreq *ifr)
-- 
1.7.4


-- 
Ben Hutchings, Senior Software Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.


  parent reply	other threads:[~2011-05-16 15:58 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-05-14  1:05 [PATCH net-2.6] ethtool: Remove fallback to old ethtool operations for ETHTOOL_SFEATURES Ben Hutchings
2011-05-14  9:54 ` Michał Mirosław
2011-05-14 20:08   ` Ben Hutchings
2011-05-14 10:31 ` [PATCH] net: fix ETHTOOL_SFEATURES compatibility with old ethtool_ops.set_flags Michał Mirosław
2011-05-14 10:35 ` [PATCH net-2.6] ethtool: Remove fallback to old ethtool operations for ETHTOOL_SFEATURES Michał Mirosław
2011-05-16  2:45   ` Ben Hutchings
2011-05-16 12:13     ` Michał Mirosław
2011-05-16 13:28     ` [PATCH] ethtool: ETHTOOL_SFEATURES: remove NETIF_F_COMPAT return Michał Mirosław
2011-05-16 13:37       ` Ben Hutchings
2011-05-16 14:23         ` Michał Mirosław
2011-05-16 14:53           ` Ben Hutchings
2011-05-16 15:01             ` Michał Mirosław
2011-05-16 15:57               ` [RFC PATCH ethtool 1/3] ethtool: Regularise offload feature settings Ben Hutchings
2011-05-16 15:57               ` [RFC PATCH ethtool 2/3] ethtool: Report any consequential offload feature changes Ben Hutchings
2011-05-16 15:58               ` Ben Hutchings [this message]
2011-05-16 20:51             ` [PATCH] ethtool: ETHTOOL_SFEATURES: remove NETIF_F_COMPAT return Michał Mirosław
2011-05-16 21:08               ` Ben Hutchings
2011-05-16 21:50                 ` Michał Mirosław
2011-05-16 22:09                   ` Ben Hutchings
2011-05-17  8:45                     ` Michał Mirosław
2011-05-17 20:33                     ` [RFC PATCH ethtool] ethtool: merge ETHTOOL_[GS]FEATURES support to -k/-K modes Michał Mirosław
2011-05-18 19:02                     ` [PATCH] ethtool: ETHTOOL_SFEATURES: remove NETIF_F_COMPAT return Ben Hutchings
2011-05-19  9:18                       ` Michał Mirosław
2011-05-19 13:25                         ` [RFC PATCH v3 ethtool] ethtool: implement [GS]FEATURES calls Michał Mirosław
2011-05-16 20:54             ` [RFC PATCH ethtool] ethtool: implement G/SFEATURES calls Michał Mirosław
2011-05-16 18:09           ` [PATCH] ethtool: ETHTOOL_SFEATURES: remove NETIF_F_COMPAT return David Miller
2011-05-19 10:03             ` Michał Mirosław
2011-05-24  9:14               ` Michał Mirosław
2011-05-24 19:39                 ` David Miller
2011-05-24 21:59                   ` Michał Mirosław
2011-05-27 14:13                     ` Ben Hutchings
2011-05-27 15:28                       ` Michał Mirosław
2011-05-27 15:45                         ` Ben Hutchings
2011-05-27 16:34                           ` Michał Mirosław
2011-05-27 23:25                             ` Ben Hutchings
2011-05-28  7:35                               ` Michał Mirosław
     [not found]                                 ` <20110528073525.GA19033-CoA6ZxLDdyEEUmgCuDUIdw@public.gmane.org>
2011-05-28 10:07                                   ` [Xen-devel] " Ian Campbell
     [not found]                                     ` <1306577228.23577.17.camel-ztPmHsLffjjnO4AKDKe2m+kiAK3p4hvP@public.gmane.org>
2011-05-28 17:31                                       ` Jesse Gross
     [not found]                                         ` <BANLkTime8PHYe+BFELt92gg7SZ91xKvAwA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-05-29  9:38                                           ` Michał Mirosław
     [not found]                                             ` <20110529093849.GA5245-CoA6ZxLDdyEEUmgCuDUIdw@public.gmane.org>
2011-05-31 18:43                                               ` Jesse Gross
2011-05-26 10:42                   ` [RESEND PATCH net] net: fix ETHTOOL_SFEATURES compatibility with old ethtool_ops.set_flags Michał Mirosław
2011-05-26 18:14                     ` David Miller
2011-05-14 10:41 ` [PATCH v2] " Michał Mirosław

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1305561483.2885.17.camel@bwh-desktop \
    --to=bhutchings@solarflare.com \
    --cc=davem@davemloft.net \
    --cc=linux-net-drivers@solarflare.com \
    --cc=mirq-linux@rere.qmqm.pl \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.