Netdev List
 help / color / mirror / Atom feed
* [ethtool PATCH 2/4] Cleanup defines and header includes to address several issues
From: Alexander Duyck @ 2011-05-04 18:41 UTC (permalink / raw)
  To: davem, jeffrey.t.kirsher, dm, bhutchings; +Cc: netdev
In-Reply-To: <20110504183752.26394.29231.stgit@gitlad.jf.intel.com>

This change is meant to address several issues.  First it moves the check
for ethtool-config.h into ethtool-util.h the reason for this change is so
that any references to ethtool-util.h outside of ethtool.c will use the
correct defines for the endian types.

In addition I have pulled several headers that will be common to both
ethtool.c and rxclass.c into the ethtool-util.h header file.  I am also
centralizing several macros that will be needed across multiple files when
I implement the network flow classifier rules.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
---

 ethtool-util.h |   17 +++++++++++++++--
 ethtool.c      |   17 +----------------
 2 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/ethtool-util.h b/ethtool-util.h
index f053028..6a4f3f4 100644
--- a/ethtool-util.h
+++ b/ethtool-util.h
@@ -3,8 +3,13 @@
 #ifndef ETHTOOL_UTIL_H__
 #define ETHTOOL_UTIL_H__
 
+#ifdef HAVE_CONFIG_H
+#include "ethtool-config.h"
+#endif
 #include <sys/types.h>
 #include <endian.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
 
 /* ethtool.h expects these to be defined by <linux/types.h> */
 #ifndef HAVE_BE_TYPES
@@ -12,14 +17,14 @@ typedef __uint16_t __be16;
 typedef __uint32_t __be32;
 #endif
 
-#include "ethtool-copy.h"
-
 typedef unsigned long long u64;
 typedef __uint32_t u32;
 typedef __uint16_t u16;
 typedef __uint8_t u8;
 typedef __int32_t s32;
 
+#include "ethtool-copy.h"
+
 #if __BYTE_ORDER == __BIG_ENDIAN
 static inline u16 cpu_to_be16(u16 value)
 {
@@ -40,6 +45,14 @@ static inline u32 cpu_to_be32(u32 value)
 }
 #endif
 
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#ifndef SIOCETHTOOL
+#define SIOCETHTOOL     0x8946
+#endif
+
 /* National Semiconductor DP83815, DP83816 */
 int natsemi_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
 int natsemi_dump_eeprom(struct ethtool_drvinfo *info,
diff --git a/ethtool.c b/ethtool.c
index 9ad7000..24d4e4f 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -21,19 +21,12 @@
  *   * show settings for all devices
  */
 
-#ifdef HAVE_CONFIG_H
-#  include "ethtool-config.h"
-#endif
-
-#include <sys/types.h>
+#include "ethtool-util.h"
 #include <string.h>
 #include <stdlib.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <stdio.h>
 #include <errno.h>
-#include <net/if.h>
 #include <sys/utsname.h>
 #include <limits.h>
 #include <ctype.h>
@@ -43,18 +36,10 @@
 #include <arpa/inet.h>
 
 #include <linux/sockios.h>
-#include "ethtool-util.h"
 
-
-#ifndef SIOCETHTOOL
-#define SIOCETHTOOL     0x8946
-#endif
 #ifndef MAX_ADDR_LEN
 #define MAX_ADDR_LEN	32
 #endif
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-#endif
 
 #ifndef HAVE_NETIF_MSG
 enum {


^ permalink raw reply related

* [ethtool PATCH 4/4] v6 Add RX packet classification interface
From: Alexander Duyck @ 2011-05-04 18:41 UTC (permalink / raw)
  To: davem, jeffrey.t.kirsher, dm, bhutchings; +Cc: netdev
In-Reply-To: <20110504183752.26394.29231.stgit@gitlad.jf.intel.com>

From: Santwona Behera <santwona.behera@sun.com>

This patch was originally introduced as:
  [PATCH 1/3] [ethtool] Add rx pkt classification interface
  Signed-off-by: Santwona Behera <santwona.behera@sun.com>
  http://patchwork.ozlabs.org/patch/23223/

v2:
I have updated it to address a number of issues.  As a result I removed the
local caching of rules due to the fact that there were memory leaks in this
code and the rule manager would consume over 1Mb of space for an 8K table
when all that was needed was 1K in order to store which rules were active
and which were not.

In addition I dropped the use of regions as there were multiple issue found
including the fact that the regions were not properly expanding beyond 2
and the fact that the regions required reading all of the rules in order to
correctly expand beyond 2.  By dropping the regions from the rule manager
it is possible to write a much cleaner interface leaving region management
to be done by either the driver or by external management scripts.

v3:
The latest update to this patch now inverts the masks to match the mask
types used for n-tuple.  As such a network flow classifier is defined using
the exact same syntax as n-tuple, and the tool will correct for the fact
that NFC uses the 1's compliment of the n-tuple mask.

I also updated the ordering of new rules being added.  All new rules will
take the highest numbered open rule when no location is specified.

Since NFC now uses the same syntax as n-tuple I added code such that now
when location is not specified the -U option will first try to add a new
n-tuple rule, and if that fails with a ENOTSUPP it will then try to add the
rule via the NFC interface.

Finally I split out the addition of bitops and the updates to documentation
into separate patches.  This makes the total patch size a bit more
manageable since the addition of NFC and the merging of it with n-tuple were
combined into this patch.

v4:
This change merges the ntuple and network flow classifier rules so that if
we setup a rule and the device has the NTUPLE flag set we will first try to
use set_rx_ntuple.  If that fails with EOPNOTSUPP we then will attempt to
use the network flow classifier rule insertion.  This way we can support
legacy configurations such as niu on kernels prior to 2.6.40 that support
network flow classifier but not ntuple, but for drivers such as ixgbe we
can test for ntuple first, and then network flow classifier.

This patch has also updated the output to make use of the updated network
flow classifier extensions that have been accepted into the kernel.

v5:
This change merged the documentation update into this patch.  In addition the
documentation changes were made such that there is only one listing of the
individual options and they are all listed as optional.

In addition this patch contains several fixes to address things such as the
fact that we were maintaining the table logic even though we only need it for
displaying all of the rules, or when adding a rule with no location specified.
As such all of the logic for deleting or finding rules in the table has been
removed.

v6:
This change further reduced the use of the rule manager so that it is only
initialized and used when a rule is added without a location specified.  For
future expansion it should be possible to add a call to a in kernel ethtool
ioctl that can effectively replace the rule manager entirely.  However this
basic rule manager will be necessary to support legacy kernels.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
---

 Makefile.am    |    3 
 ethtool-util.h |   14 +
 ethtool.8.in   |  194 +++++-----
 ethtool.c      |  400 ++++++++++++---------
 rxclass.c      | 1073 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 1418 insertions(+), 266 deletions(-)
 create mode 100644 rxclass.c

diff --git a/Makefile.am b/Makefile.am
index a0d2116..0262c31 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,7 +8,8 @@ ethtool_SOURCES = ethtool.c ethtool-copy.h ethtool-util.h	\
 		  amd8111e.c de2104x.c e100.c e1000.c igb.c	\
 		  fec_8xx.c ibm_emac.c ixgb.c ixgbe.c natsemi.c	\
 		  pcnet32.c realtek.c tg3.c marvell.c vioc.c	\
-		  smsc911x.c at76c50x-usb.c sfc.c stmmac.c
+		  smsc911x.c at76c50x-usb.c sfc.c stmmac.c	\
+		  rxclass.c
 
 dist-hook:
 	cp $(top_srcdir)/ethtool.spec $(distdir)
diff --git a/ethtool-util.h b/ethtool-util.h
index d8b621c..79be7f2 100644
--- a/ethtool-util.h
+++ b/ethtool-util.h
@@ -65,6 +65,8 @@ static inline u64 cpu_to_be64(u64 value)
 #define SIOCETHTOOL     0x8946
 #endif
 
+#define	RX_CLS_LOC_UNSPEC	0xffffffffUL
+
 /* National Semiconductor DP83815, DP83816 */
 int natsemi_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
 int natsemi_dump_eeprom(struct ethtool_drvinfo *info,
@@ -128,4 +130,14 @@ int sfc_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
 int st_mac100_dump_regs(struct ethtool_drvinfo *info,
 			struct ethtool_regs *regs);
 int st_gmac_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
-#endif
+
+/* Rx flow classification */
+int rxclass_parse_ruleopts(char **optstr, int opt_cnt,
+			   struct ethtool_rx_flow_spec *fsp);
+int rxclass_rule_getall(int fd, struct ifreq *ifr);
+int rxclass_rule_get(int fd, struct ifreq *ifr, __u32 loc);
+int rxclass_rule_ins(int fd, struct ifreq *ifr,
+		     struct ethtool_rx_flow_spec *fsp);
+int rxclass_rule_del(int fd, struct ifreq *ifr, __u32 loc);
+
+#endif /* ETHTOOL_UTIL_H__ */
diff --git a/ethtool.8.in b/ethtool.8.in
index 9f484fb..c923319 100644
--- a/ethtool.8.in
+++ b/ethtool.8.in
@@ -42,10 +42,20 @@
 [\\fB\\$1\\fP\ \\fIN\\fP]
 ..
 .\"
+.\"	.BM - same as above but has a mask field for format "[value N [m N]]"
+.\"
+.de BM
+[\\fB\\$1\\fP\ \\fIN\\fP\ [\\fBm\\fP\ \\fIN\\fP]]
+..
+.\"
 .\"	\(*MA - mac address
 .\"
 .ds MA \fIxx\fP\fB:\fP\fIyy\fP\fB:\fP\fIzz\fP\fB:\fP\fIaa\fP\fB:\fP\fIbb\fP\fB:\fP\fIcc\fP
 .\"
+.\"	\(*PA - IP address
+.\"
+.ds PA \fIx\fP\fB.\fP\fIx\fP\fB.\fP\fIx\fP\fB.\fP\fIx\fP
+.\"
 .\"	\(*WO - wol flags
 .\"
 .ds WO \fBp\fP|\fBu\fP|\fBm\fP|\fBb\fP|\fBa\fP|\fBg\fP|\fBs\fP|\fBd\fP...
@@ -57,6 +67,12 @@
 .\"	\(*HO - hash options
 .\"
 .ds HO \fBm\fP|\fBv\fP|\fBt\fP|\fBs\fP|\fBd\fP|\fBf\fP|\fBn\fP|\fBr\fP...
+.\"
+.\"	\(*NC - Network Classifier type values
+.\"
+.ds NC \fBether\fP|\fBip4\fP|\fBtcp4\fP|\fBudp4\fP|\fBsctp4\fP|\fBah4\fP|\fBesp4\fP
+
+.\"
 .\" Start URL.
 .de UR
 .  ds m1 \\$1\"
@@ -236,8 +252,7 @@ ethtool \- query or control network driver and hardware settings
 .HP
 .B ethtool \-N
 .I ethX
-.RB [ rx\-flow\-hash \ \*(FL
-.RB \ \*(HO]
+.RB [ rx\-flow\-hash \ \*(FL \  \*(HO]
 .HP
 .B ethtool \-x|\-\-show\-rxfh\-indir
 .I ethX
@@ -257,50 +272,28 @@ ethtool \- query or control network driver and hardware settings
 .HP
 .B ethtool \-u|\-\-show\-ntuple
 .I ethX
-.TP
+.BN rule
+.HP
+
 .BI ethtool\ \-U|\-\-config\-ntuple \ ethX
-.RB {
-.A3 flow\-type tcp4 udp4 sctp4
-.RB [ src\-ip
-.IR addr
-.RB [ src\-ip\-mask
-.IR mask ]]
-.RB [ dst\-ip
-.IR addr
-.RB [ dst\-ip\-mask
-.IR mask ]]
-.RB [ src\-port
-.IR port
-.RB [ src\-port\-mask
-.IR mask ]]
-.RB [ dst\-port
-.IR port
-.RB [ dst\-port\-mask
-.IR mask ]]
-.br
-.RB | \ flow\-type\ ether
-.RB [ src
-.IR mac\-addr
-.RB [ src\-mask
-.IR mask ]]
-.RB [ dst
-.IR mac\-addr
-.RB [ dst\-mask
-.IR mask ]]
-.RB [ proto
-.IR N
-.RB [ proto\-mask
-.IR mask ]]\ }
-.br
-.RB [ vlan
-.IR VLAN\-tag
-.RB [ vlan\-mask
-.IR mask ]]
-.RB [ user\-def
-.IR data
-.RB [ user\-def\-mask
-.IR mask ]]
-.RI action \ N
+.BN delete
+.RB [\  flow\-type \ \*(NC
+.RB [ src \ \*(MA\ [ m \ \*(MA]]
+.RB [ dst \ \*(MA\ [ m \ \*(MA]]
+.BM proto
+.RB [ src\-ip \ \*(PA\ [ m \ \*(PA]]
+.RB [ dst\-ip \ \*(PA\ [ m \ \*(PA]]
+.BM tos
+.BM l4proto
+.BM src\-port
+.BM dst\-port
+.BM spi
+.BM vlan\-etype
+.BM vlan
+.BM user\-def
+.BN action
+.BN loc
+.RB ]
 .
 .\" Adjust lines (i.e. full justification) and hyphenate.
 .ad
@@ -630,77 +623,90 @@ Default region is 0 which denotes all regions in the flash.
 .TP
 .B \-u \-\-show\-ntuple
 Get Rx ntuple filters and actions, then display them to the user.
+.TP
+.BI rule \ N
+Retrieves the RX classification rule with the given ID.
 .PD
 .RE
 .TP
 .B \-U \-\-config\-ntuple
 Configure Rx ntuple filters and actions
 .TP
-.B flow\-type tcp4|udp4|sctp4|ether
+.BI delete \ N
+Deletes the RX classification rule with the given ID.
+.TP
+.B flow\-type \*(NC
 .TS
 nokeep;
 lB	l.
+ether	Ethernet
+ip4	Raw IPv4
 tcp4	TCP over IPv4
 udp4	UDP over IPv4
 sctp4	SCTP over IPv4
-ether	Ethernet
+ah4	IPSEC AH over IPv4
+esp4	IPSEC ESP over IPv4
 .TE
+.PP
+All fields below that include a mask option may either use "m" to
+indicate a mask, or may use the full name of the field with a "-mask"
+appended to indicate that this is the mask for a given field.
+.PD
+.RE
 .TP
-.BI src\-ip \ addr
-Includes the source IP address, specified using dotted-quad notation
-or as a single 32-bit number.
-.TP
-.BI src\-ip\-mask \ mask
-Specify a mask for the source IP address.
-.TP
-.BI dst\-ip \ addr
-Includes the destination IP address.
-.TP
-.BI dst\-ip\-mask \ mask
-Specify a mask for the destination IP address.
-.TP
-.BI src\-port \ port
-Includes the source port.
-.TP
-.BI src\-port\-mask \ mask
-Specify a mask for the source port.
+.BR src \ \*(MA\ [ m \ \*(MA]
+Includes the source MAC address, specified as 6 bytes in hexadecimal
+separated by colons, along with an optional mask.  Valid only for
+flow-type ether.
 .TP
-.BI dst\-port \ port
-Includes the destination port.
+.BR dst \ \*(MA\ [ m \ \*(MA]
+Includes the destination MAC address, specified as 6 bytes in hexadecimal
+separated by colons, along with an optional mask.  Valid only for
+flow-type ether.
 .TP
-.BI dst\-port\-mask \ mask
-Specify a mask for the destination port.
+.BI proto \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Includes the Ethernet protocol number (ethertype) and an optional mask.
+Valid only for flow-type ether.
 .TP
-.BI src \ mac\-addr
-Includes the source MAC address, specified as 6 bytes in hexadecimal
-separated by colons.
+.BR src\-ip \ \*(PA\ [ m \ \*(PA]
+Specify the source IP address of the incoming packet to match along with
+an optional mask.  Valid for all IPv4 based flow-types.
 .TP
-.BI src\-mask \ mask
-Specify a mask for the source MAC address.
+.BR dst\-ip \ \*(PA\ [ m \ \*(PA]
+Specify the destination IP address of the incoming packet to match along
+with an optional mask.  Valid for all IPv4 based flow-types.
 .TP
-.BI dst \ mac\-addr
-Includes the destination MAC address.
+.BI tos \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Specify the value of the Type of Service field in the incoming packet to
+match along with an optional mask.  Applies to all IPv4 based flow-types.
 .TP
-.BI dst\-mask \ mask
-Specify a mask for the destination MAC address.
+.BI l4proto \ N \\fR\ [\\fPl4m \ N \\fR]\\fP
+Includes the layer 4 protocol number and optional mask.  Valid only for
+flow-type ip4.
 .TP
-.BI proto \ N
-Includes the Ethernet protocol number (ethertype).
+.BI src\-port \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Specify the value of the source port field (applicable to TCP/UDP packets)
+in the incoming packet to match along with an optional mask.  Valid for
+flow-types ip4, tcp4, udp4, and sctp4.
 .TP
-.BI proto\-mask \ mask
-Specify a mask for the Ethernet protocol number.
+.BI dst\-port \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Specify the value of the destination port field (applicable to TCP/UDP
+packets)in the incoming packet to match along with an optional mask.
+Valid for flow-types ip4, tcp4, udp4, and sctp4.
 .TP
-.BI vlan \ VLAN\-tag
-Includes the VLAN tag.
+.BI spi \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Specify the value of the security parameter index field (applicable to
+AH/ESP packets)in the incoming packet to match along with an optional
+mask.  Valid for flow-types ip4, ah4, and esp4.
 .TP
-.BI vlan\-mask \ mask
-Specify a mask for the VLAN tag.
+.BI vlan\-etype \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Includes the VLAN tag Ethertype and an optional mask.
 .TP
-.BI user\-def \ data
-Includes 64-bits of user-specific data.
+.BI vlan \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Includes the VLAN tag and an optional mask.
 .TP
-.BI user\-def\-mask \ mask
-Specify a mask for the user-specific data.
+.BI user\-def \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Includes 64-bits of user-specific data and an optional mask.
 .TP
 .BI action \ N
 Specifies the Rx queue to send packets to, or some other action.
@@ -711,6 +717,11 @@ lB	l.
 -1	Drop the matched flow
 0 or higher	Rx queue to route the flow
 .TE
+.TP
+.BI loc \ N
+Specify the location/ID to insert the rule. This will overwrite
+any rule present in that location and will not go through any
+of the rule ordering process.
 .SH BUGS
 Not supported (in part or whole) on all network drivers.
 .SH AUTHOR
@@ -724,7 +735,8 @@ Jakub Jelinek,
 Andre Majorel,
 Eli Kupermann,
 Scott Feldman,
-Andi Kleen.
+Andi Kleen,
+Alexander Duyck.
 .SH AVAILABILITY
 .B ethtool
 is available from
diff --git a/ethtool.c b/ethtool.c
index 24d4e4f..2e04d87 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -6,6 +6,7 @@
  * Kernel 2.4 update Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
  * Wake-on-LAN,natsemi,misc support by Tim Hockin <thockin@sun.com>
  * Portions Copyright 2002 Intel
+ * Portions Copyright (C) Sun Microsystems 2008
  * do_test support by Eli Kupermann <eli.kupermann@intel.com>
  * ETHTOOL_PHYS_ID support by Chris Leech <christopher.leech@intel.com>
  * e1000 support by Scott Feldman <scott.feldman@intel.com>
@@ -14,6 +15,7 @@
  * amd8111e support by Reeja John <reeja.john@amd.com>
  * long arguments by Andi Kleen.
  * SMSC LAN911x support by Steve Glendinning <steve.glendinning@smsc.com>
+ * Rx Network Flow Control configuration support <santwona.behera@sun.com>
  * Various features by Ben Hutchings <bhutchings@solarflare.com>;
  *	Copyright 2009, 2010 Solarflare Communications
  *
@@ -85,14 +87,13 @@ static int do_gstats(int fd, struct ifreq *ifr);
 static int rxflow_str_to_type(const char *str);
 static int parse_rxfhashopts(char *optstr, u32 *data);
 static char *unparse_rxfhashopts(u64 opts);
-static void parse_rxntupleopts(int argc, char **argp, int first_arg);
 static int dump_rxfhash(int fhash, u64 val);
 static int do_srxclass(int fd, struct ifreq *ifr);
 static int do_grxclass(int fd, struct ifreq *ifr);
 static int do_grxfhindir(int fd, struct ifreq *ifr);
 static int do_srxfhindir(int fd, struct ifreq *ifr);
-static int do_srxntuple(int fd, struct ifreq *ifr);
-static int do_grxntuple(int fd, struct ifreq *ifr);
+static int do_srxclsrule(int fd, struct ifreq *ifr);
+static int do_grxclsrule(int fd, struct ifreq *ifr);
 static int do_flash(int fd, struct ifreq *ifr);
 static int do_permaddr(int fd, struct ifreq *ifr);
 
@@ -123,8 +124,8 @@ static enum {
 	MODE_SNFC,
 	MODE_GRXFHINDIR,
 	MODE_SRXFHINDIR,
-	MODE_SNTUPLE,
-	MODE_GNTUPLE,
+	MODE_SCLSRULE,
+	MODE_GCLSRULE,
 	MODE_FLASHDEV,
 	MODE_PERMADDR,
 } mode = MODE_GSET;
@@ -230,22 +231,28 @@ static struct option {
 		"indirection" },
     { "-X", "--set-rxfh-indir", MODE_SRXFHINDIR, "Set Rx flow hash indirection",
 		"		equal N | weight W0 W1 ...\n" },
-    { "-U", "--config-ntuple", MODE_SNTUPLE, "Configure Rx ntuple filters "
+    { "-U", "--config-ntuple", MODE_SCLSRULE, "Configure Rx ntuple filters "
 		"and actions",
-		"		{ flow-type tcp4|udp4|sctp4\n"
-		"		  [ src-ip ADDR [src-ip-mask MASK] ]\n"
-		"		  [ dst-ip ADDR [dst-ip-mask MASK] ]\n"
-		"		  [ src-port PORT [src-port-mask MASK] ]\n"
-		"		  [ dst-port PORT [dst-port-mask MASK] ]\n"
-		"		| flow-type ether\n"
-		"		  [ src MAC-ADDR [src-mask MASK] ]\n"
-		"		  [ dst MAC-ADDR [dst-mask MASK] ]\n"
-		"		  [ proto N [proto-mask MASK] ] }\n"
-		"		[ vlan VLAN-TAG [vlan-mask MASK] ]\n"
-		"		[ user-def DATA [user-def-mask MASK] ]\n"
-		"		action N\n" },
-    { "-u", "--show-ntuple", MODE_GNTUPLE,
-		"Get Rx ntuple filters and actions\n" },
+		"		[ delete %d ] |\n"
+		"		[ flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4\n"
+		"			[ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
+		"			[ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
+		"			[ proto %d [m %x] ]\n"
+		"			[ src-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]\n"
+		"			[ dst-ip %d.%d.%d.%d [m %d.%d.%d.%d] ]\n"
+		"			[ tos %d [m %x] ]\n"
+		"			[ l4proto %d [m %x] ]\n"
+		"			[ src-port %d [m %x] ]\n"
+		"			[ dst-port %d [m %x] ]\n"
+		"			[ spi %d [m %x] ]\n"
+		"			[ vlan-etype %x [m %x] ]\n"
+		"			[ vlan %x [m %x] ]\n"
+		"			[ user-def %x [m %x] ]\n"
+		"			[ action %d ]\n"
+		"			[ loc %d]]\n" },
+    { "-u", "--show-ntuple", MODE_GCLSRULE,
+		"Get Rx ntuple filters and actions",
+		"		[ rule %d ]\n"},
     { "-P", "--show-permaddr", MODE_PERMADDR,
 		"Show permanent hardware address" },
     { "-h", "--help", MODE_HELP, "Show this help" },
@@ -371,26 +378,6 @@ static u32 rx_fhash_val = 0;
 static int rx_fhash_changed = 0;
 static int rxfhindir_equal = 0;
 static char **rxfhindir_weight = NULL;
-static int sntuple_changed = 0;
-static struct ethtool_rx_ntuple_flow_spec ntuple_fs;
-static int ntuple_ip4src_seen = 0;
-static int ntuple_ip4src_mask_seen = 0;
-static int ntuple_ip4dst_seen = 0;
-static int ntuple_ip4dst_mask_seen = 0;
-static int ntuple_psrc_seen = 0;
-static int ntuple_psrc_mask_seen = 0;
-static int ntuple_pdst_seen = 0;
-static int ntuple_pdst_mask_seen = 0;
-static int ntuple_ether_dst_seen = 0;
-static int ntuple_ether_dst_mask_seen = 0;
-static int ntuple_ether_src_seen = 0;
-static int ntuple_ether_src_mask_seen = 0;
-static int ntuple_ether_proto_seen = 0;
-static int ntuple_ether_proto_mask_seen = 0;
-static int ntuple_vlan_tag_seen = 0;
-static int ntuple_vlan_tag_mask_seen = 0;
-static int ntuple_user_def_seen = 0;
-static int ntuple_user_def_mask_seen = 0;
 static char *flash_file = NULL;
 static int flash = -1;
 static int flash_region = -1;
@@ -399,6 +386,11 @@ static int msglvl_changed;
 static u32 msglvl_wanted = 0;
 static u32 msglvl_mask = 0;
 
+static int rx_class_rule_get = -1;
+static int rx_class_rule_del = -1;
+static int rx_class_rule_added = 0;
+static struct ethtool_rx_flow_spec rx_rule_fs;
+
 static enum {
 	ONLINE=0,
 	OFFLINE,
@@ -511,58 +503,6 @@ static struct cmdline_info cmdline_coalesce[] = {
 	{ "tx-frames-high", CMDL_S32, &coal_tx_frames_high_wanted, &ecoal.tx_max_coalesced_frames_high },
 };
 
-static struct cmdline_info cmdline_ntuple_tcp_ip4[] = {
-	{ "src-ip", CMDL_IP4, &ntuple_fs.h_u.tcp_ip4_spec.ip4src, NULL,
-	  0, &ntuple_ip4src_seen },
-	{ "src-ip-mask", CMDL_IP4, &ntuple_fs.m_u.tcp_ip4_spec.ip4src, NULL,
-	  0, &ntuple_ip4src_mask_seen },
-	{ "dst-ip", CMDL_IP4, &ntuple_fs.h_u.tcp_ip4_spec.ip4dst, NULL,
-	  0, &ntuple_ip4dst_seen },
-	{ "dst-ip-mask", CMDL_IP4, &ntuple_fs.m_u.tcp_ip4_spec.ip4dst, NULL,
-	  0, &ntuple_ip4dst_mask_seen },
-	{ "src-port", CMDL_BE16, &ntuple_fs.h_u.tcp_ip4_spec.psrc, NULL,
-	  0, &ntuple_psrc_seen },
-	{ "src-port-mask", CMDL_BE16, &ntuple_fs.m_u.tcp_ip4_spec.psrc, NULL,
-	  0, &ntuple_psrc_mask_seen },
-	{ "dst-port", CMDL_BE16, &ntuple_fs.h_u.tcp_ip4_spec.pdst, NULL,
-	  0, &ntuple_pdst_seen },
-	{ "dst-port-mask", CMDL_BE16, &ntuple_fs.m_u.tcp_ip4_spec.pdst, NULL,
-	  0, &ntuple_pdst_mask_seen },
-	{ "vlan", CMDL_U16, &ntuple_fs.vlan_tag, NULL,
-	  0, &ntuple_vlan_tag_seen },
-	{ "vlan-mask", CMDL_U16, &ntuple_fs.vlan_tag_mask, NULL,
-	  0, &ntuple_vlan_tag_mask_seen },
-	{ "user-def", CMDL_U64, &ntuple_fs.data, NULL,
-	  0, &ntuple_user_def_seen },
-	{ "user-def-mask", CMDL_U64, &ntuple_fs.data_mask, NULL,
-	  0, &ntuple_user_def_mask_seen },
-	{ "action", CMDL_S32, &ntuple_fs.action, NULL },
-};
-
-static struct cmdline_info cmdline_ntuple_ether[] = {
-	{ "dst", CMDL_MAC, ntuple_fs.h_u.ether_spec.h_dest, NULL,
-	  0, &ntuple_ether_dst_seen },
-	{ "dst-mask", CMDL_MAC, ntuple_fs.m_u.ether_spec.h_dest, NULL,
-	  0, &ntuple_ether_dst_mask_seen },
-	{ "src", CMDL_MAC, ntuple_fs.h_u.ether_spec.h_source, NULL,
-	  0, &ntuple_ether_src_seen },
-	{ "src-mask", CMDL_MAC, ntuple_fs.m_u.ether_spec.h_source, NULL,
-	  0, &ntuple_ether_src_mask_seen },
-	{ "proto", CMDL_BE16, &ntuple_fs.h_u.ether_spec.h_proto, NULL,
-	  0, &ntuple_ether_proto_seen },
-	{ "proto-mask", CMDL_BE16, &ntuple_fs.m_u.ether_spec.h_proto, NULL,
-	  0, &ntuple_ether_proto_mask_seen },
-	{ "vlan", CMDL_U16, &ntuple_fs.vlan_tag, NULL,
-	  0, &ntuple_vlan_tag_seen },
-	{ "vlan-mask", CMDL_U16, &ntuple_fs.vlan_tag_mask, NULL,
-	  0, &ntuple_vlan_tag_mask_seen },
-	{ "user-def", CMDL_U64, &ntuple_fs.data, NULL,
-	  0, &ntuple_user_def_seen },
-	{ "user-def-mask", CMDL_U64, &ntuple_fs.data_mask, NULL,
-	  0, &ntuple_user_def_mask_seen },
-	{ "action", CMDL_S32, &ntuple_fs.action, NULL },
-};
-
 static struct cmdline_info cmdline_msglvl[] = {
 	{ "drv", CMDL_FLAG, &msglvl_wanted, NULL,
 	  NETIF_MSG_DRV, &msglvl_mask },
@@ -833,8 +773,8 @@ static void parse_cmdline(int argc, char **argp)
 			    (mode == MODE_SNFC) ||
 			    (mode == MODE_GRXFHINDIR) ||
 			    (mode == MODE_SRXFHINDIR) ||
-			    (mode == MODE_SNTUPLE) ||
-			    (mode == MODE_GNTUPLE) ||
+			    (mode == MODE_SCLSRULE) ||
+			    (mode == MODE_GCLSRULE) ||
 			    (mode == MODE_PHYS_ID) ||
 			    (mode == MODE_FLASHDEV) ||
 			    (mode == MODE_PERMADDR)) {
@@ -918,16 +858,45 @@ static void parse_cmdline(int argc, char **argp)
 				i = argc;
 				break;
 			}
-			if (mode == MODE_SNTUPLE) {
+			if (mode == MODE_SCLSRULE) {
 				if (!strcmp(argp[i], "flow-type")) {
 					i += 1;
 					if (i >= argc) {
 						exit_bad_args();
 						break;
 					}
-					parse_rxntupleopts(argc, argp, i);
-					i = argc;
-					break;
+					if (rxclass_parse_ruleopts(&argp[i],
+							argc - i,
+							&rx_rule_fs) < 0) {
+						exit_bad_args();
+					} else {
+						i = argc;
+						rx_class_rule_added = 1;
+					}
+				} else if (!strcmp(argp[i], "delete")) {
+					i += 1;
+					if (i >= argc) {
+						exit_bad_args();
+						break;
+					}
+					rx_class_rule_del =
+						get_uint_range(argp[i], 0,
+							       INT_MAX);
+				} else {
+					exit_bad_args();
+				}
+				break;
+			}
+			if (mode == MODE_GCLSRULE) {
+				if (!strcmp(argp[i], "rule")) {
+					i += 1;
+					if (i >= argc) {
+						exit_bad_args();
+						break;
+					}
+					rx_class_rule_get =
+						get_uint_range(argp[i], 0,
+							       INT_MAX);
 				} else {
 					exit_bad_args();
 				}
@@ -1598,66 +1567,6 @@ static char *unparse_rxfhashopts(u64 opts)
 	return buf;
 }
 
-static void parse_rxntupleopts(int argc, char **argp, int i)
-{
-	ntuple_fs.flow_type = rxflow_str_to_type(argp[i]);
-
-	switch (ntuple_fs.flow_type) {
-	case TCP_V4_FLOW:
-	case UDP_V4_FLOW:
-	case SCTP_V4_FLOW:
-		parse_generic_cmdline(argc, argp, i + 1,
-				      &sntuple_changed,
-				      cmdline_ntuple_tcp_ip4,
-				      ARRAY_SIZE(cmdline_ntuple_tcp_ip4));
-		if (!ntuple_ip4src_seen)
-			ntuple_fs.m_u.tcp_ip4_spec.ip4src = 0xffffffff;
-		if (!ntuple_ip4dst_seen)
-			ntuple_fs.m_u.tcp_ip4_spec.ip4dst = 0xffffffff;
-		if (!ntuple_psrc_seen)
-			ntuple_fs.m_u.tcp_ip4_spec.psrc = 0xffff;
-		if (!ntuple_pdst_seen)
-			ntuple_fs.m_u.tcp_ip4_spec.pdst = 0xffff;
-		ntuple_fs.m_u.tcp_ip4_spec.tos = 0xff;
-		break;
-	case ETHER_FLOW:
-		parse_generic_cmdline(argc, argp, i + 1,
-				      &sntuple_changed,
-				      cmdline_ntuple_ether,
-				      ARRAY_SIZE(cmdline_ntuple_ether));
-		if (!ntuple_ether_dst_seen)
-			memset(ntuple_fs.m_u.ether_spec.h_dest, 0xff, ETH_ALEN);
-		if (!ntuple_ether_src_seen)
-			memset(ntuple_fs.m_u.ether_spec.h_source, 0xff,
-			       ETH_ALEN);
-		if (!ntuple_ether_proto_seen)
-			ntuple_fs.m_u.ether_spec.h_proto = 0xffff;
-		break;
-	default:
-		fprintf(stderr, "Unsupported flow type \"%s\"\n", argp[i]);
-		exit(106);
-		break;
-	}
-
-	if (!ntuple_vlan_tag_seen)
-		ntuple_fs.vlan_tag_mask = 0xffff;
-	if (!ntuple_user_def_seen)
-		ntuple_fs.data_mask = 0xffffffffffffffffULL;
-
-	if ((ntuple_ip4src_mask_seen && !ntuple_ip4src_seen) ||
-	    (ntuple_ip4dst_mask_seen && !ntuple_ip4dst_seen) ||
-	    (ntuple_psrc_mask_seen && !ntuple_psrc_seen) ||
-	    (ntuple_pdst_mask_seen && !ntuple_pdst_seen) ||
-	    (ntuple_ether_dst_mask_seen && !ntuple_ether_dst_seen) ||
-	    (ntuple_ether_src_mask_seen && !ntuple_ether_src_seen) ||
-	    (ntuple_ether_proto_mask_seen && !ntuple_ether_proto_seen) ||
-	    (ntuple_vlan_tag_mask_seen && !ntuple_vlan_tag_seen) ||
-	    (ntuple_user_def_mask_seen && !ntuple_user_def_seen)) {
-		fprintf(stderr, "Cannot specify mask without value\n");
-		exit(107);
-	}
-}
-
 static struct {
 	const char *name;
 	int (*func)(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
@@ -2019,10 +1928,10 @@ static int doit(void)
 		return do_grxfhindir(fd, &ifr);
 	} else if (mode == MODE_SRXFHINDIR) {
 		return do_srxfhindir(fd, &ifr);
-	} else if (mode == MODE_SNTUPLE) {
-		return do_srxntuple(fd, &ifr);
-	} else if (mode == MODE_GNTUPLE) {
-		return do_grxntuple(fd, &ifr);
+	} else if (mode == MODE_SCLSRULE) {
+		return do_srxclsrule(fd, &ifr);
+	} else if (mode == MODE_GCLSRULE) {
+		return do_grxclsrule(fd, &ifr);
 	} else if (mode == MODE_FLASHDEV) {
 		return do_flash(fd, &ifr);
 	} else if (mode == MODE_PERMADDR) {
@@ -3155,21 +3064,143 @@ static int do_permaddr(int fd, struct ifreq *ifr)
 	return err;
 }
 
+static int flow_spec_to_ntuple(struct ethtool_rx_flow_spec *fsp,
+			       struct ethtool_rx_ntuple_flow_spec *ntuple)
+{
+	size_t i;
+
+	/* verify location is not specified */
+	if (fsp->location != RX_CLS_LOC_UNSPEC)
+		return -1;
+
+	/* verify ring cookie can transfer to action */
+	if (fsp->ring_cookie > INT_MAX && fsp->ring_cookie < (u64)(-2))
+		return -1;
+
+	/* verify only one field is setting data field */
+	if ((fsp->flow_type & FLOW_EXT) &&
+	    (fsp->m_ext.data[0] || fsp->m_ext.data[1]) &&
+	    fsp->m_ext.vlan_etype)
+		return -1;
+
+	/* Set entire ntuple to ~0 to guarantee all masks are set */
+	memset(ntuple, ~0, sizeof(*ntuple));
+
+	/* set non-filter values */
+	ntuple->flow_type = fsp->flow_type;
+	ntuple->action = fsp->ring_cookie;
+
+	/*
+	 * Copy over header union, they are identical in layout however
+	 * the ntuple union contains additional padding on the end
+	 */
+	memcpy(&ntuple->h_u, &fsp->h_u, sizeof(fsp->h_u));
+
+	/*
+	 * The same rule mentioned above applies to the mask union.  However,
+	 * in addition we need to invert the mask bits to match the ntuple
+	 * mask which is 1 for masked, versus 0 for masked as seen in nfc.
+	 */
+	memcpy(&ntuple->m_u, &fsp->m_u, sizeof(fsp->m_u));
+	for (i = 0; i < sizeof(fsp->m_u); i++)
+		ntuple->m_u.hdata[i] ^= 0xFF;
+
+	/* copy extended fields */
+	if (fsp->flow_type & FLOW_EXT) {
+		ntuple->vlan_tag =
+			ntohs(fsp->h_ext.vlan_tci);
+		ntuple->vlan_tag_mask =
+			~ntohs(fsp->m_ext.vlan_tci);
+		if (fsp->m_ext.vlan_etype) {
+			/*
+			 * vlan_etype and user data are mutually exclusive
+			 * in ntuple configuration as they occupy the same
+			 * space.
+			 */
+			if (fsp->m_ext.data[0] || fsp->m_ext.data[1])
+				return -1;
+			ntuple->data =
+				ntohl(fsp->h_ext.vlan_etype);
+			ntuple->data_mask =
+				~(u64)ntohl(fsp->m_ext.vlan_etype);
+		} else {
+			ntuple->data =
+				(u64)ntohl(fsp->h_ext.data[0]) << 32;
+			ntuple->data |=
+				(u64)ntohl(fsp->h_ext.data[1]);
+			ntuple->data_mask =
+				(u64)ntohl(~fsp->m_ext.data[0]) << 32;
+			ntuple->data_mask |=
+				(u64)ntohl(~fsp->m_ext.data[1]);
+		}
+	}
+
+	return 0;
+}
+
 static int do_srxntuple(int fd, struct ifreq *ifr)
 {
+	struct ethtool_rx_ntuple ntuplecmd;
+	struct ethtool_value eval;
 	int err;
 
-	if (sntuple_changed) {
-		struct ethtool_rx_ntuple ntuplecmd;
+	/* attempt to convert the flow classifier to an ntuple classifier */
+	err = flow_spec_to_ntuple(&rx_rule_fs, &ntuplecmd.fs);
+	if (err)
+		return -1;
 
-		ntuplecmd.cmd = ETHTOOL_SRXNTUPLE;
-		memcpy(&ntuplecmd.fs, &ntuple_fs,
-		       sizeof(struct ethtool_rx_ntuple_flow_spec));
+	/*
+	 * Check to see if the flag is set for N-tuple, this allows
+	 * us to avoid the possible EINVAL response for the N-tuple
+	 * flag not being set on the device
+	 */
+	eval.cmd = ETHTOOL_GFLAGS;
+	ifr->ifr_data = (caddr_t)&eval;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err || !(eval.data & ETH_FLAG_NTUPLE))
+		return -1;
 
-		ifr->ifr_data = (caddr_t)&ntuplecmd;
-		err = ioctl(fd, SIOCETHTOOL, ifr);
-		if (err < 0)
-			perror("Cannot add new RX n-tuple filter");
+	/* send rule via N-tuple */
+	ntuplecmd.cmd = ETHTOOL_SRXNTUPLE;
+	ifr->ifr_data = (caddr_t)&ntuplecmd;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+
+	/*
+	 * Display error only if reponse is something other than op not
+	 * supported.  It is possible that the interface uses the network
+	 * flow classifier interface instead of N-tuple. 
+	 */ 
+	if (err && errno != EOPNOTSUPP)
+		perror("Cannot add new rule via N-tuple");
+
+	return err;
+}
+
+static int do_srxclsrule(int fd, struct ifreq *ifr)
+{
+	int err;
+
+	if (rx_class_rule_added) {
+		/* attempt to add rule via N-tuple specifier */
+		err = do_srxntuple(fd, ifr);
+		if (!err)
+			return 0;
+
+		/* attempt to add rule via network flow classifier */
+		err = rxclass_rule_ins(fd, ifr, &rx_rule_fs);
+		if (err < 0) {
+			fprintf(stderr, "Cannot insert"
+				" classification rule\n");
+			return 1;
+		}
+	} else if (rx_class_rule_del >= 0) {
+		err = rxclass_rule_del(fd, ifr, rx_class_rule_del);
+
+		if (err < 0) {
+			fprintf(stderr, "Cannot delete"
+				" classification rule\n");
+			return 1;
+		}
 	} else {
 		exit_bad_args();
 	}
@@ -3177,9 +3208,32 @@ static int do_srxntuple(int fd, struct ifreq *ifr)
 	return 0;
 }
 
-static int do_grxntuple(int fd, struct ifreq *ifr)
+static int do_grxclsrule(int fd, struct ifreq *ifr)
 {
-	return 0;
+	struct ethtool_rxnfc nfccmd;
+	int err;
+
+	if (rx_class_rule_get >= 0) {
+		err = rxclass_rule_get(fd, ifr, rx_class_rule_get);
+		if (err < 0)
+			fprintf(stderr, "Cannot get RX classification rule\n");
+		return err ? 1 : 0;
+	}
+
+	nfccmd.cmd = ETHTOOL_GRXRINGS;
+	ifr->ifr_data = (caddr_t)&nfccmd;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0)
+		perror("Cannot get RX rings");
+	else
+		fprintf(stdout, "%d RX rings available\n",
+			(int)nfccmd.data);
+
+	err = rxclass_rule_getall(fd, ifr);
+	if (err < 0)
+		fprintf(stderr, "RX classification rule retrieval failed\n");
+
+	return err ? 1 : 0;
 }
 
 static int send_ioctl(int fd, struct ifreq *ifr)
diff --git a/rxclass.c b/rxclass.c
new file mode 100644
index 0000000..ee486f7
--- /dev/null
+++ b/rxclass.c
@@ -0,0 +1,1073 @@
+/*
+ * Copyright (C) 2008 Sun Microsystems, Inc. All rights reserved.
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <linux/sockios.h>
+#include <arpa/inet.h>
+#include "ethtool-util.h"
+#include "ethtool-bitops.h"
+
+static void invert_flow_mask(struct ethtool_rx_flow_spec *fsp)
+{
+	size_t i;
+
+	for (i = 0; i < sizeof(fsp->m_u); i++)
+		fsp->m_u.hdata[i] ^= 0xFF;
+}
+
+static void rxclass_print_ipv4_rule(__be32 sip, __be32 sipm, __be32 dip,
+				    __be32 dipm, u8 tos, u8 tosm)
+{
+	char sip_str[INET_ADDRSTRLEN];
+	char sipm_str[INET_ADDRSTRLEN];
+	char dip_str[INET_ADDRSTRLEN];
+	char dipm_str[INET_ADDRSTRLEN];
+
+	fprintf(stdout,
+		"\tSrc IP addr: %s mask: %s\n"
+		"\tDest IP addr: %s mask: %s\n"
+		"\tTOS: 0x%x mask: 0x%x\n",
+		inet_ntop(AF_INET, &sip, sip_str, INET_ADDRSTRLEN),
+		inet_ntop(AF_INET, &sipm, sipm_str, INET_ADDRSTRLEN),
+		inet_ntop(AF_INET, &dip, dip_str, INET_ADDRSTRLEN),
+		inet_ntop(AF_INET, &dipm, dipm_str, INET_ADDRSTRLEN),
+		tos, tosm);
+}
+
+static void rxclass_print_nfc_spec_ext(struct ethtool_rx_flow_spec *fsp)
+{
+	u64 data, datam;
+	__u16 etype, etypem, tci, tcim;
+
+	if (!(fsp->flow_type & FLOW_EXT))
+		return;
+
+	etype = ntohs(fsp->h_ext.vlan_etype);
+	etypem = ntohs(~fsp->m_ext.vlan_etype);
+	tci = ntohs(fsp->h_ext.vlan_tci);
+	tcim = ntohs(~fsp->m_ext.vlan_tci);
+	data = (u64)ntohl(fsp->h_ext.data[0]) << 32;
+	data = (u64)ntohl(fsp->h_ext.data[1]);
+	datam = (u64)ntohl(~fsp->m_ext.data[0]) << 32;
+	datam |= (u64)ntohl(~fsp->m_ext.data[1]);
+
+	fprintf(stdout,
+		"\tVLAN EtherType: 0x%x mask: 0x%x\n"
+		"\tVLAN: 0x%x mask: 0x%x\n"
+		"\tUser-defined: 0x%llx mask: 0x%llx\n",
+		etype, etypem, tci, tcim, data, datam);
+}
+
+static void rxclass_print_nfc_rule(struct ethtool_rx_flow_spec *fsp)
+{
+	unsigned char	*smac, *smacm, *dmac, *dmacm;
+	__u32		flow_type;
+
+	if (fsp->location != RX_CLS_LOC_UNSPEC)
+		fprintf(stdout,	"Filter: %d\n", fsp->location);
+	else
+		fprintf(stdout,	"Filter: Unspecified\n");
+
+	flow_type = fsp->flow_type & ~FLOW_EXT;
+
+	invert_flow_mask(fsp);
+
+	switch (flow_type) {
+	case TCP_V4_FLOW:
+	case UDP_V4_FLOW:
+	case SCTP_V4_FLOW:
+		if (flow_type == TCP_V4_FLOW)
+			fprintf(stdout, "\tRule Type: TCP over IPv4\n");
+		else if (flow_type == UDP_V4_FLOW)
+			fprintf(stdout, "\tRule Type: UDP over IPv4\n");
+		else
+			fprintf(stdout, "\tRule Type: SCTP over IPv4\n");
+		rxclass_print_ipv4_rule(fsp->h_u.tcp_ip4_spec.ip4src,
+				     fsp->m_u.tcp_ip4_spec.ip4src,
+				     fsp->h_u.tcp_ip4_spec.ip4dst,
+				     fsp->m_u.tcp_ip4_spec.ip4dst,
+				     fsp->h_u.tcp_ip4_spec.tos,
+				     fsp->m_u.tcp_ip4_spec.tos);
+		fprintf(stdout,
+			"\tSrc port: %d mask: 0x%x\n"
+			"\tDest port: %d mask: 0x%x\n",
+			ntohs(fsp->h_u.tcp_ip4_spec.psrc),
+			ntohs(fsp->m_u.tcp_ip4_spec.psrc),
+			ntohs(fsp->h_u.tcp_ip4_spec.pdst),
+			ntohs(fsp->m_u.tcp_ip4_spec.pdst));
+		break;
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+		if (flow_type == AH_V4_FLOW)
+			fprintf(stdout, "\tRule Type: IPSEC AH over IPv4\n");
+		else
+			fprintf(stdout, "\tRule Type: IPSEC ESP over IPv4\n");
+		rxclass_print_ipv4_rule(fsp->h_u.ah_ip4_spec.ip4src,
+				     fsp->m_u.ah_ip4_spec.ip4src,
+				     fsp->h_u.ah_ip4_spec.ip4dst,
+				     fsp->m_u.ah_ip4_spec.ip4dst,
+				     fsp->h_u.ah_ip4_spec.tos,
+				     fsp->m_u.ah_ip4_spec.tos);
+		fprintf(stdout,
+			"\tSPI: %d mask: 0x%x\n",
+			ntohl(fsp->h_u.esp_ip4_spec.spi),
+			ntohl(fsp->m_u.esp_ip4_spec.spi));
+		break;
+	case IP_USER_FLOW:
+		fprintf(stdout, "\tRule Type: Raw IPv4\n");
+		rxclass_print_ipv4_rule(fsp->h_u.usr_ip4_spec.ip4src,
+				     fsp->m_u.usr_ip4_spec.ip4src,
+				     fsp->h_u.usr_ip4_spec.ip4dst,
+				     fsp->m_u.usr_ip4_spec.ip4dst,
+				     fsp->h_u.usr_ip4_spec.tos,
+				     fsp->m_u.usr_ip4_spec.tos);
+		fprintf(stdout,
+			"\tProtocol: %d mask: 0x%x\n"
+			"\tL4 bytes: 0x%x mask: 0x%x\n",
+			fsp->h_u.usr_ip4_spec.proto,
+			fsp->m_u.usr_ip4_spec.proto,
+			ntohl(fsp->h_u.usr_ip4_spec.l4_4_bytes),
+			ntohl(fsp->m_u.usr_ip4_spec.l4_4_bytes));
+		break;
+	case ETHER_FLOW:
+		dmac = fsp->h_u.ether_spec.h_dest;
+		dmacm = fsp->m_u.ether_spec.h_dest;
+		smac = fsp->h_u.ether_spec.h_source;
+		smacm = fsp->m_u.ether_spec.h_source;
+
+		fprintf(stdout,
+			"\tFlow Type: Raw Ethernet\n"
+			"\tSrc MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
+			" mask: %02X:%02X:%02X:%02X:%02X:%02X\n"
+			"\tDest MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
+			" mask: %02X:%02X:%02X:%02X:%02X:%02X\n"
+			"\tEthertype: 0x%X mask: 0x%X\n",
+			smac[0], smac[1], smac[2], smac[3], smac[4], smac[5],
+			smacm[0], smacm[1], smacm[2], smacm[3], smacm[4],
+			smacm[5], dmac[0], dmac[1], dmac[2], dmac[3], dmac[4],
+			dmac[5], dmacm[0], dmacm[1], dmacm[2], dmacm[3],
+			dmacm[4], dmacm[5],
+			ntohs(fsp->h_u.ether_spec.h_proto),
+			ntohs(fsp->m_u.ether_spec.h_proto));
+		break;
+	default:
+		fprintf(stdout,
+			"\tUnknown Flow type: %d\n", flow_type);
+		break;
+	}
+
+	rxclass_print_nfc_spec_ext(fsp);
+
+	if (fsp->ring_cookie != RX_CLS_FLOW_DISC)
+		fprintf(stdout, "\tAction: Direct to queue %llu\n",
+			fsp->ring_cookie);
+	else
+		fprintf(stdout, "\tAction: Drop\n");
+
+	fprintf(stdout, "\n");
+}
+
+static void rxclass_print_rule(struct ethtool_rx_flow_spec *fsp)
+{
+	/* print the rule in this location */
+	switch (fsp->flow_type & ~FLOW_EXT) {
+	case TCP_V4_FLOW:
+	case UDP_V4_FLOW:
+	case SCTP_V4_FLOW:
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+	case ETHER_FLOW:
+		rxclass_print_nfc_rule(fsp);
+		break;
+	case IP_USER_FLOW:
+		if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4) {
+			rxclass_print_nfc_rule(fsp);
+			break;
+		}
+		/* IPv6 User Flow falls through to the case below */
+	case TCP_V6_FLOW:
+	case UDP_V6_FLOW:
+	case SCTP_V6_FLOW:
+	case AH_V6_FLOW:
+	case ESP_V6_FLOW:
+		fprintf(stderr, "IPv6 flows not implemented\n");
+		break;
+	default:
+		fprintf(stderr, "rxclass: Unknown flow type\n");
+		break;
+	}
+}
+
+static int rxclass_get_count(int fd, struct ifreq *ifr, __u32 *count)
+{
+	struct ethtool_rxnfc nfccmd;
+	int err;
+
+	/* request count and store */
+	nfccmd.cmd = ETHTOOL_GRXCLSRLCNT;
+	nfccmd.rule_cnt = 0;
+	ifr->ifr_data = (caddr_t)&nfccmd;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	*count = nfccmd.rule_cnt;
+	if (err < 0)
+		perror("rxclass: Cannot get RX class rule count");
+
+	return err;
+}
+
+int rxclass_rule_get(int fd, struct ifreq *ifr, __u32 loc)
+{
+	struct ethtool_rxnfc nfccmd;
+	int err;
+
+	/* fetch rule from netdev */
+	nfccmd.cmd = ETHTOOL_GRXCLSRULE;
+	memset(&nfccmd.fs, 0, sizeof(struct ethtool_rx_flow_spec));
+	nfccmd.fs.location = loc;
+	ifr->ifr_data = (caddr_t)&nfccmd;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("rxclass: Cannot get RX class rule");
+		return err;
+	}
+
+	/* display rule */
+	rxclass_print_rule(&nfccmd.fs);
+	return err;
+}
+
+int rxclass_rule_getall(int fd, struct ifreq *ifr)
+{
+	struct ethtool_rxnfc *nfccmd;
+	__u32 *rule_locs;
+	int err, i;
+	__u32 count;
+
+	/* determine rule count */
+	err = rxclass_get_count(fd, ifr, &count);
+	if (err < 0)
+		return err;
+
+	fprintf(stdout, "Total %d rules\n\n", count);
+
+	/* alloc memory for request of location list */
+	nfccmd = calloc(1, sizeof(*nfccmd) + (count * sizeof(__u32)));
+	if (!nfccmd) {
+		perror("rxclass: Cannot allocate memory for"
+		       " RX class rule locations");
+		return -ENOMEM;
+	}
+
+	/* request location list */
+	nfccmd->cmd = ETHTOOL_GRXCLSRLALL;
+	nfccmd->rule_cnt = count;
+	ifr->ifr_data = (caddr_t)nfccmd;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("rxclass: Cannot get RX class rules");
+		free(nfccmd);
+		return err;
+	}
+
+	/* write locations to bitmap */
+	rule_locs = nfccmd->rule_locs;
+	for (i = 0; i < count; i++) {
+		err = rxclass_rule_get(fd, ifr, rule_locs[i]);
+		if (err < 0)
+			break;
+	}
+
+	/* free memory and set flag to avoid reinit */
+	free(nfccmd);
+
+	return err;
+}
+
+/*
+ * This is a simple rule manager implementation for ordering rx flow
+ * classification rules based on newest rules being first in the list.
+ * The assumption is that this rule manager is the only one adding rules to
+ * the device's hardware classifier.
+ */
+
+struct rmgr_ctrl {
+	/* slot contains a bitmap indicating which filters are valid */
+	unsigned long		*slot;
+	__u32			n_rules;
+	__u32			size;
+};
+
+static struct rmgr_ctrl rmgr;
+static int rmgr_init_done = 0;
+
+static int rmgr_ins(__u32 loc)
+{
+	/* verify location is in rule manager range */
+	if (loc >= rmgr.size) {
+		fprintf(stderr, "rmgr: Location out of range\n");
+		return -1;
+	}
+
+	/* set bit for the rule */
+	set_bit(loc, rmgr.slot);
+
+	return 0;
+}
+
+static int rmgr_find_empty_slot(struct ethtool_rx_flow_spec *fsp)
+{
+	__u32 loc;
+	__u32 slot_num;
+
+	/* start at the end of the list since it is lowest priority */
+	loc = rmgr.size - 1;
+
+	/* locate the first slot a rule can be placed in */
+	slot_num = loc / BITS_PER_LONG;
+
+	/*
+	 * Avoid testing individual bits by inverting the word and checking
+	 * to see if any bits are left set, if so there are empty spots.  By
+	 * moving 1 + loc % BITS_PER_LONG we align ourselves to the last bit
+	 * in the previous word.
+	 *
+	 * If loc rolls over it should be greater than or equal to rmgr.size
+	 * and as such we know we have reached the end of the list.
+	 */
+	if (!~(rmgr.slot[slot_num] | (~1UL << rmgr.size % BITS_PER_LONG))) {
+		loc -= 1 + (loc % BITS_PER_LONG);
+		slot_num--;
+	}
+
+	/*
+	 * Now that we are aligned with the last bit in each long we can just
+	 * go though and eliminate all the longs with no free bits
+	 */
+	while (loc < rmgr.size && !~(rmgr.slot[slot_num])) {
+		loc -= BITS_PER_LONG;
+		slot_num--;
+	}
+
+	/*
+	 * If we still are inside the range, test individual bits as one is
+	 * likely available for our use.
+	 */
+	while (loc < rmgr.size && test_bit(loc, rmgr.slot))
+		loc--;
+
+	/* location found, insert rule */
+	if (loc < rmgr.size) {
+		fsp->location = loc;
+		return rmgr_ins(loc);
+	}
+
+	/* No space to add this rule */
+	fprintf(stderr, "rmgr: Cannot find appropriate slot to insert rule\n");
+
+	return -1;
+}
+
+static int rmgr_init(int fd, struct ifreq *ifr)
+{
+	struct ethtool_rxnfc *nfccmd;
+	int err, i;
+	__u32 *rule_locs;
+
+	if (rmgr_init_done)
+		return 0;
+
+	/* clear rule manager settings */
+	memset(&rmgr, 0, sizeof(struct rmgr_ctrl));
+
+	/* request count and store in rmgr.n_rules */
+	err = rxclass_get_count(fd, ifr, &rmgr.n_rules);
+	if (err < 0)
+		return err;
+
+	/* alloc memory for request of location list */
+	nfccmd = calloc(1, sizeof(*nfccmd) + (rmgr.n_rules * sizeof(__u32)));
+	if (!nfccmd) {
+		perror("rmgr: Cannot allocate memory for"
+		       " RX class rule locations");
+		return -1;
+	}
+
+	/* request location list */
+	nfccmd->cmd = ETHTOOL_GRXCLSRLALL;
+	nfccmd->rule_cnt = rmgr.n_rules;
+	ifr->ifr_data = (caddr_t)nfccmd;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("rmgr: Cannot get RX class rules");
+		free(nfccmd);
+		return err;
+	}
+
+	/* make certain the table size is valid */
+	rmgr.size = nfccmd->data;
+	if (rmgr.size == 0 || rmgr.size < rmgr.n_rules) {
+		perror("rmgr: Invalid RX class rules table size");
+		return -1;
+	}
+
+	/* initialize bitmap for storage of valid locations */
+	rmgr.slot = calloc(1, BITS_TO_LONGS(rmgr.size) * sizeof(long));
+	if (!rmgr.slot) {
+		perror("rmgr: Cannot allocate memory for RX class rules");
+		return -1;
+	}
+
+	/* write locations to bitmap */
+	rule_locs = nfccmd->rule_locs;
+	for (i = 0; i < rmgr.n_rules; i++) {
+		err = rmgr_ins(rule_locs[i]);
+		if (err < 0)
+			break;
+	}
+
+	/* free memory and set flag to avoid reinit */
+	free(nfccmd);
+	rmgr_init_done = 1;
+
+	return err;
+}
+
+static void rmgr_cleanup(void)
+{
+	if (!rmgr_init_done)
+		return;
+
+	rmgr_init_done = 0;
+
+	free(rmgr.slot);
+	rmgr.slot = NULL;
+	rmgr.size = 0;
+}
+
+static int rmgr_set_location(int fd, struct ifreq *ifr,
+			     struct ethtool_rx_flow_spec *fsp)
+{
+	int err;
+
+	/* init table of available rules */
+	err = rmgr_init(fd, ifr);
+	if (err < 0)
+		return err;
+
+	/* verify rule location */
+	err = rmgr_find_empty_slot(fsp);
+
+	/* cleanup table and free resources */
+	rmgr_cleanup();
+
+	return err;
+}
+
+int rxclass_rule_ins(int fd, struct ifreq *ifr,
+		     struct ethtool_rx_flow_spec *fsp)
+{
+	struct ethtool_rxnfc nfccmd;
+	__u32 loc = fsp->location;
+	int err;
+
+	/*
+	 * if location is unspecified pull rules from device
+	 * and allocate a free rule for our use
+	 */
+	if (loc == RX_CLS_LOC_UNSPEC) {
+		err = rmgr_set_location(fd, ifr, fsp);
+		if (err < 0)
+			return err;
+	}
+
+	/* notify netdev of new rule */
+	nfccmd.cmd = ETHTOOL_SRXCLSRLINS;
+	nfccmd.fs = *fsp;
+	ifr->ifr_data = (caddr_t)&nfccmd;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0)
+		perror("rmgr: Cannot insert RX class rule");
+	else if (loc == RX_CLS_LOC_UNSPEC)
+		printf("Added rule with ID %d\n", fsp->location);
+
+	return 0;
+}
+
+int rxclass_rule_del(int fd, struct ifreq *ifr, __u32 loc)
+{
+	struct ethtool_rxnfc nfccmd;
+	int err;
+
+	/* notify netdev of rule removal */
+	nfccmd.cmd = ETHTOOL_SRXCLSRLDEL;
+	nfccmd.fs.location = loc;
+	ifr->ifr_data = (caddr_t)&nfccmd;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0)
+		perror("rmgr: Cannot delete RX class rule");
+
+	return err;
+}
+
+typedef enum {
+	OPT_NONE = 0,
+	OPT_S32,
+	OPT_U8,
+	OPT_U16,
+	OPT_U32,
+	OPT_U64,
+	OPT_BE16,
+	OPT_BE32,
+	OPT_BE64,
+	OPT_IP4,
+	OPT_MAC,
+} rule_opt_type_t;
+
+#define NFC_FLAG_RING		0x001
+#define NFC_FLAG_LOC		0x002
+#define NFC_FLAG_SADDR		0x004
+#define NFC_FLAG_DADDR		0x008
+#define NFC_FLAG_SPORT		0x010
+#define NFC_FLAG_DPORT		0x020
+#define NFC_FLAG_SPI		0x030
+#define NFC_FLAG_TOS		0x040
+#define NFC_FLAG_PROTO		0x080
+#define NTUPLE_FLAG_VLAN	0x100
+#define NTUPLE_FLAG_UDEF	0x200
+#define NTUPLE_FLAG_VETH	0x400
+
+struct rule_opts {
+	const char	*name;
+	rule_opt_type_t	type;
+	u32		flag;
+	int		offset;
+	int		moffset;
+};
+
+static struct rule_opts rule_nfc_tcp_ip4[] = {
+	{ "src-ip", OPT_IP4, NFC_FLAG_SADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.ip4src),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.ip4src) },
+	{ "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.ip4dst),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.ip4dst) },
+	{ "tos", OPT_U8, NFC_FLAG_TOS,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.tos),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.tos) },
+	{ "src-port", OPT_BE16, NFC_FLAG_SPORT,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.psrc),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.psrc) },
+	{ "dst-port", OPT_BE16, NFC_FLAG_DPORT,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip4_spec.pdst),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip4_spec.pdst) },
+	{ "action", OPT_U64, NFC_FLAG_RING,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "loc", OPT_U32, NFC_FLAG_LOC,
+	  offsetof(struct ethtool_rx_flow_spec, location), -1 },
+	{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
+	{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
+	{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.data),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
+};
+
+static struct rule_opts rule_nfc_esp_ip4[] = {
+	{ "src-ip", OPT_IP4, NFC_FLAG_SADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.ip4src),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.ip4src) },
+	{ "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.ip4dst),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.ip4dst) },
+	{ "tos", OPT_U8, NFC_FLAG_TOS,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.tos),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.tos) },
+	{ "spi", OPT_BE32, NFC_FLAG_SPI,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip4_spec.spi),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip4_spec.spi) },
+	{ "action", OPT_U64, NFC_FLAG_RING,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "loc", OPT_U32, NFC_FLAG_LOC,
+	  offsetof(struct ethtool_rx_flow_spec, location), -1 },
+	{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
+	{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
+	{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.data),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
+};
+
+static struct rule_opts rule_nfc_usr_ip4[] = {
+	{ "src-ip", OPT_IP4, NFC_FLAG_SADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.ip4src),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.ip4src) },
+	{ "dst-ip", OPT_IP4, NFC_FLAG_DADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.ip4dst),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.ip4dst) },
+	{ "tos", OPT_U8, NFC_FLAG_TOS,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.tos),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.tos) },
+	{ "l4proto", OPT_U8, NFC_FLAG_PROTO,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.proto),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.proto) },
+	{ "spi", OPT_BE32, NFC_FLAG_SPI,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) },
+	{ "src-port", OPT_BE16, NFC_FLAG_SPORT,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) },
+	{ "dst-port", OPT_BE16, NFC_FLAG_DPORT,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip4_spec.l4_4_bytes) + 2,
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip4_spec.l4_4_bytes) + 2 },
+	{ "action", OPT_U64, NFC_FLAG_RING,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "loc", OPT_U32, NFC_FLAG_LOC,
+	  offsetof(struct ethtool_rx_flow_spec, location), -1 },
+	{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
+	{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
+	{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.data),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
+};
+
+static struct rule_opts rule_nfc_ether[] = {
+	{ "src", OPT_MAC, NFC_FLAG_SADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_dest),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_dest) },
+	{ "dst", OPT_MAC, NFC_FLAG_DADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_source),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_source) },
+	{ "proto", OPT_BE16, NFC_FLAG_PROTO,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_proto),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_proto) },
+	{ "action", OPT_U64, NFC_FLAG_RING,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "loc", OPT_U32, NFC_FLAG_LOC,
+	  offsetof(struct ethtool_rx_flow_spec, location), -1 },
+	{ "vlan-etype", OPT_BE16, NTUPLE_FLAG_VETH,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_etype),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_etype) },
+	{ "vlan", OPT_BE16, NTUPLE_FLAG_VLAN,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.vlan_tci),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.vlan_tci) },
+	{ "user-def", OPT_BE64, NTUPLE_FLAG_UDEF,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.data),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.data) },
+};
+
+static int rxclass_get_long(char *str, long long *val, int size)
+{
+	long long max = ~0ULL >> (65 - size);
+	char *endp;
+
+	errno = 0;
+
+	*val = strtoll(str, &endp, 0);
+
+	if (*endp || errno || (*val > max) || (*val < ~max))
+		return -1;
+
+	return 0;
+}
+
+static int rxclass_get_ulong(char *str, unsigned long long *val, int size)
+{
+	long long max = ~0ULL >> (64 - size);
+	char *endp;
+
+	errno = 0;
+
+	*val = strtoull(str, &endp, 0);
+
+	if (*endp || errno || (*val > max))
+		return -1;
+
+	return 0;
+}
+
+static int rxclass_get_ipv4(char *str, __be32 *val)
+{
+	if (!inet_pton(AF_INET, str, val))
+		return -1;
+
+	return 0;
+}
+
+static int rxclass_get_ether(char *str, unsigned char *val)
+{
+	unsigned int buf[ETH_ALEN];
+	int count;
+
+	if (!strchr(str, ':'))
+		return -1;
+
+	count = sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x",
+		       &buf[0], &buf[1], &buf[2],
+		       &buf[3], &buf[4], &buf[5]);
+
+	if (count != ETH_ALEN)
+		return -1;
+
+	do {
+		count--;
+		val[count] = buf[count];
+	} while (count);
+
+	return 0;
+}
+
+static int rxclass_get_val(char *str, unsigned char *p, u32 *flags,
+			   const struct rule_opts *opt)
+{
+	unsigned long long mask = ~0ULL;
+	int err = 0;
+
+	if (*flags & opt->flag)
+		return -1;
+
+	*flags |= opt->flag;
+
+	switch (opt->type) {
+	case OPT_S32: {
+		long long val;
+		err = rxclass_get_long(str, &val, 32);
+		if (err)
+			return -1;
+		*(int *)&p[opt->offset] = (int)val;
+		if (opt->moffset >= 0)
+			*(int *)&p[opt->moffset] = (int)mask;
+		break;
+	}
+	case OPT_U8: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 8);
+		if (err)
+			return -1;
+		*(u8 *)&p[opt->offset] = (u8)val;
+		if (opt->moffset >= 0)
+			*(u8 *)&p[opt->moffset] = (u8)mask;
+		break;
+	}
+	case OPT_U16: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 16);
+		if (err)
+			return -1;
+		*(u16 *)&p[opt->offset] = (u16)val;
+		if (opt->moffset >= 0)
+			*(u16 *)&p[opt->moffset] = (u16)mask;
+		break;
+	}
+	case OPT_U32: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 32);
+		if (err)
+			return -1;
+		*(u32 *)&p[opt->offset] = (u32)val;
+		if (opt->moffset >= 0)
+			*(u32 *)&p[opt->moffset] = (u32)mask;
+		break;
+	}
+	case OPT_U64: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 64);
+		if (err)
+			return -1;
+		*(u64 *)&p[opt->offset] = (u64)val;
+		if (opt->moffset >= 0)
+			*(u64 *)&p[opt->moffset] = (u64)mask;
+		break;
+	}
+	case OPT_BE16: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 16);
+		if (err)
+			return -1;
+		*(__be16 *)&p[opt->offset] = htons((u16)val);
+		if (opt->moffset >= 0)
+			*(__be16 *)&p[opt->moffset] = (__be16)mask;
+		break;
+	}
+	case OPT_BE32: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 32);
+		if (err)
+			return -1;
+		*(__be32 *)&p[opt->offset] = htonl((u32)val);
+		if (opt->moffset >= 0)
+			*(__be32 *)&p[opt->moffset] = (__be32)mask;
+		break;
+	}
+	case OPT_BE64: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 64);
+		if (err)
+			return -1;
+		*(__be64 *)&p[opt->offset] = htonll((u64)val);
+		if (opt->moffset >= 0)
+			*(__be64 *)&p[opt->moffset] = (__be64)mask;
+		break;
+	}
+	case OPT_IP4: {
+		__be32 val;
+		err = rxclass_get_ipv4(str, &val);
+		if (err)
+			return -1;
+		*(__be32 *)&p[opt->offset] = val;
+		if (opt->moffset >= 0)
+			*(__be32 *)&p[opt->moffset] = (__be32)mask;
+		break;
+	}
+	case OPT_MAC: {
+		unsigned char val[ETH_ALEN];
+		err = rxclass_get_ether(str, val);
+		if (err)
+			return -1;
+		memcpy(&p[opt->offset], val, ETH_ALEN);
+		if (opt->moffset >= 0)
+			memcpy(&p[opt->moffset], &mask, ETH_ALEN);
+		break;
+	}
+	case OPT_NONE:
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+static int rxclass_get_mask(char *str, unsigned char *p,
+			    const struct rule_opts *opt)
+{
+	int err = 0;
+
+	if (opt->moffset < 0)
+		return -1;
+
+	switch (opt->type) {
+	case OPT_S32: {
+		long long val;
+		err = rxclass_get_long(str, &val, 32);
+		if (err)
+			return -1;
+		*(int *)&p[opt->moffset] = ~(int)val;
+		break;
+	}
+	case OPT_U8: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 8);
+		if (err)
+			return -1;
+		*(u8 *)&p[opt->moffset] = ~(u8)val;
+		break;
+	}
+	case OPT_U16: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 16);
+		if (err)
+			return -1;
+		*(u16 *)&p[opt->moffset] = ~(u16)val;
+		break;
+	}
+	case OPT_U32: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 32);
+		if (err)
+			return -1;
+		*(u32 *)&p[opt->moffset] = ~(u32)val;
+		break;
+	}
+	case OPT_U64: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 64);
+		if (err)
+			return -1;
+		*(u64 *)&p[opt->moffset] = ~(u64)val;
+		break;
+	}
+	case OPT_BE16: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 16);
+		if (err)
+			return -1;
+		*(__be16 *)&p[opt->moffset] = ~htons((u16)val);
+		break;
+	}
+	case OPT_BE32: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 32);
+		if (err)
+			return -1;
+		*(__be32 *)&p[opt->moffset] = ~htonl((u32)val);
+		break;
+	}
+	case OPT_BE64: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 64);
+		if (err)
+			return -1;
+		*(__be64 *)&p[opt->moffset] = ~htonll((u64)val);
+		break;
+	}
+	case OPT_IP4: {
+		__be32 val;
+		err = rxclass_get_ipv4(str, &val);
+		if (err)
+			return -1;
+		*(__be32 *)&p[opt->moffset] = ~val;
+		break;
+	}
+	case OPT_MAC: {
+		unsigned char val[ETH_ALEN];
+		int i;
+		err = rxclass_get_ether(str, val);
+		if (err)
+			return -1;
+
+		for (i = 0; i < ETH_ALEN; i++)
+			val[i] = ~val[i];
+
+		memcpy(&p[opt->moffset], val, ETH_ALEN);
+		break;
+	}
+	case OPT_NONE:
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+int rxclass_parse_ruleopts(char **argp, int argc,
+			   struct ethtool_rx_flow_spec *fsp)
+{
+	const struct rule_opts *options;
+	unsigned char *p = (unsigned char *)fsp;
+	int i = 0, n_opts, err;
+	u32 flags = 0;
+	int flow_type;
+
+	if (argc < 1)
+		goto syntax_err;
+
+	if (!strcmp(argp[0], "tcp4"))
+		flow_type = TCP_V4_FLOW;
+	else if (!strcmp(argp[0], "udp4"))
+		flow_type = UDP_V4_FLOW;
+	else if (!strcmp(argp[0], "sctp4"))
+		flow_type = SCTP_V4_FLOW;
+	else if (!strcmp(argp[0], "ah4"))
+		flow_type = AH_V4_FLOW;
+	else if (!strcmp(argp[0], "esp4"))
+		flow_type = ESP_V4_FLOW;
+	else if (!strcmp(argp[0], "ip4"))
+		flow_type = IP_USER_FLOW;
+	else if (!strcmp(argp[0], "ether"))
+		flow_type = ETHER_FLOW;
+	else
+		goto syntax_err;
+
+	switch (flow_type) {
+	case TCP_V4_FLOW:
+	case UDP_V4_FLOW:
+	case SCTP_V4_FLOW:
+		options = rule_nfc_tcp_ip4;
+		n_opts = ARRAY_SIZE(rule_nfc_tcp_ip4);
+		break;
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+		options = rule_nfc_esp_ip4;
+		n_opts = ARRAY_SIZE(rule_nfc_esp_ip4);
+		break;
+	case IP_USER_FLOW:
+		options = rule_nfc_usr_ip4;
+		n_opts = ARRAY_SIZE(rule_nfc_usr_ip4);
+		break;
+	case ETHER_FLOW:
+		options = rule_nfc_ether;
+		n_opts = ARRAY_SIZE(rule_nfc_ether);
+		break;
+	default:
+		fprintf(stderr, "Add rule, invalid rule type[%s]\n", argp[0]);
+		return -1;
+	}
+
+	memset(p, 0, sizeof(*fsp));
+	fsp->flow_type = flow_type;
+	fsp->location = RX_CLS_LOC_UNSPEC;
+
+	for (i = 1; i < argc;) {
+		const struct rule_opts *opt;
+		int idx;
+		for (opt = options, idx = 0; idx < n_opts; idx++, opt++) {
+			char mask_name[16];
+
+			if (strcmp(argp[i], opt->name))
+				continue;
+
+			i++;
+			if (i >= argc)
+				break;
+
+			err = rxclass_get_val(argp[i], p, &flags, opt);
+			if (err) {
+				fprintf(stderr, "Invalid %s value[%s]\n",
+					opt->name, argp[i]);
+				return -1;
+			}
+
+			i++;
+			if (i >= argc)
+				break;
+
+			sprintf(mask_name, "%s-mask", opt->name);
+			if (strcmp(argp[i], "m") && strcmp(argp[i], mask_name))
+				break;
+
+			i++;
+			if (i >= argc)
+				goto syntax_err;
+
+			err = rxclass_get_mask(argp[i], p, opt);
+			if (err) {
+				fprintf(stderr, "Invalid %s mask[%s]\n",
+					opt->name, argp[i]);
+				return -1;
+			}
+
+			i++;
+
+			break;
+		}
+		if (idx == n_opts) {
+			fprintf(stdout, "Add rule, unrecognized option[%s]\n",
+				argp[i]);
+			return -1;
+		}
+	}
+
+	if (flags & (NTUPLE_FLAG_VLAN | NTUPLE_FLAG_UDEF | NTUPLE_FLAG_VETH))
+		fsp->flow_type |= FLOW_EXT;
+
+	return 0;
+
+syntax_err:
+	fprintf(stderr, "Add rule, invalid syntax\n");
+	return -1;
+}


^ permalink raw reply related

* [ethtool PATCH 1/4] ethtool: remove strings based approach for displaying n-tuple
From: Alexander Duyck @ 2011-05-04 18:41 UTC (permalink / raw)
  To: davem, jeffrey.t.kirsher, dm, bhutchings; +Cc: netdev
In-Reply-To: <20110504183752.26394.29231.stgit@gitlad.jf.intel.com>

This change is meant to remove the strings based approach for displaying
n-tuple filters.  A follow-on patch will replace that functionality with a
network flow classification based approach that will get the number of
filters, get their locations, and then request and display them
individually.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
---

 ethtool.c |   44 --------------------------------------------
 1 files changed, 0 insertions(+), 44 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index cfdac65..9ad7000 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -3194,50 +3194,6 @@ static int do_srxntuple(int fd, struct ifreq *ifr)
 
 static int do_grxntuple(int fd, struct ifreq *ifr)
 {
-	struct ethtool_sset_info *sset_info;
-	struct ethtool_gstrings *strings;
-	int sz_str, n_strings, err, i;
-
-	sset_info = malloc(sizeof(struct ethtool_sset_info) + sizeof(u32));
-	sset_info->cmd = ETHTOOL_GSSET_INFO;
-	sset_info->sset_mask = (1ULL << ETH_SS_NTUPLE_FILTERS);
-	ifr->ifr_data = (caddr_t)sset_info;
-	err = send_ioctl(fd, ifr);
-
-	if ((err < 0) ||
-	    (!(sset_info->sset_mask & (1ULL << ETH_SS_NTUPLE_FILTERS)))) {
-		perror("Cannot get driver strings info");
-		return 100;
-	}
-
-	n_strings = sset_info->data[0];
-	free(sset_info);
-	sz_str = n_strings * ETH_GSTRING_LEN;
-
-	strings = calloc(1, sz_str + sizeof(struct ethtool_gstrings));
-	if (!strings) {
-		fprintf(stderr, "no memory available\n");
-		return 95;
-	}
-
-	strings->cmd = ETHTOOL_GRXNTUPLE;
-	strings->string_set = ETH_SS_NTUPLE_FILTERS;
-	strings->len = n_strings;
-	ifr->ifr_data = (caddr_t) strings;
-	err = send_ioctl(fd, ifr);
-	if (err < 0) {
-		perror("Cannot get Rx n-tuple information");
-		free(strings);
-		return 101;
-	}
-
-	n_strings = strings->len;
-	fprintf(stdout, "Rx n-tuple filters:\n");
-	for (i = 0; i < n_strings; i++)
-		fprintf(stdout, "%s", &strings->data[i * ETH_GSTRING_LEN]);
-
-	free(strings);
-
 	return 0;
 }
 


^ permalink raw reply related

* [ethtool PATCH 3/4] Add support for __be64 and bitops, centralize several needed macros
From: Alexander Duyck @ 2011-05-04 18:41 UTC (permalink / raw)
  To: davem, jeffrey.t.kirsher, dm, bhutchings; +Cc: netdev
In-Reply-To: <20110504183752.26394.29231.stgit@gitlad.jf.intel.com>

This change is meant to add support for __be64 values and bitops to
ethtool.  In addition the patch pulls the SIOCETHTOOL define and the
ARRAY_SIZE define into ethtool-util.h for later use by the rxclass files.
These changes will be needed in order to support network flow
classifier rule configuration.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
---

 ethtool-bitops.h |   25 +++++++++++++++++++++++++
 ethtool-util.h   |   16 ++++++++++++++--
 2 files changed, 39 insertions(+), 2 deletions(-)
 create mode 100644 ethtool-bitops.h

diff --git a/ethtool-bitops.h b/ethtool-bitops.h
new file mode 100644
index 0000000..b1eb426
--- /dev/null
+++ b/ethtool-bitops.h
@@ -0,0 +1,25 @@
+#ifndef ETHTOOL_BITOPS_H__
+#define ETHTOOL_BITOPS_H__
+
+#define BITS_PER_BYTE		8
+#define BITS_PER_LONG		(BITS_PER_BYTE * sizeof(long))
+#define DIV_ROUND_UP(n, d)	(((n) + (d) - 1) / (d))
+#define BITS_TO_LONGS(nr)	DIV_ROUND_UP(nr, BITS_PER_LONG)
+
+static inline void set_bit(int nr, unsigned long *addr)
+{
+	addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
+}
+
+static inline void clear_bit(int nr, unsigned long *addr)
+{
+	addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG));
+}
+
+static inline int test_bit(unsigned int nr, const unsigned long *addr)
+{
+	return !!((1UL << (nr % BITS_PER_LONG)) &
+		  (((unsigned long *)addr)[nr / BITS_PER_LONG]));
+}
+
+#endif
diff --git a/ethtool-util.h b/ethtool-util.h
index 6a4f3f4..d8b621c 100644
--- a/ethtool-util.h
+++ b/ethtool-util.h
@@ -15,6 +15,7 @@
 #ifndef HAVE_BE_TYPES
 typedef __uint16_t __be16;
 typedef __uint32_t __be32;
+typedef unsigned long long __be64;
 #endif
 
 typedef unsigned long long u64;
@@ -28,11 +29,15 @@ typedef __int32_t s32;
 #if __BYTE_ORDER == __BIG_ENDIAN
 static inline u16 cpu_to_be16(u16 value)
 {
-    return value;
+	return value;
 }
 static inline u32 cpu_to_be32(u32 value)
 {
-    return value;
+	return value;
+}
+static inline u64 cpu_to_be64(u64 value)
+{
+	return value;
 }
 #else
 static inline u16 cpu_to_be16(u16 value)
@@ -43,8 +48,15 @@ static inline u32 cpu_to_be32(u32 value)
 {
 	return cpu_to_be16(value >> 16) | (cpu_to_be16(value) << 16);
 }
+static inline u64 cpu_to_be64(u64 value)
+{
+	return cpu_to_be32(value >> 32) | ((u64)cpu_to_be32(value) << 32);
+}
 #endif
 
+#define ntohll cpu_to_be64
+#define htonll cpu_to_be64
+
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 #endif


^ permalink raw reply related

* Re: [ethtool PATCH 4/4] v5 Add RX packet classification interface
From: Ben Hutchings @ 2011-05-04 18:45 UTC (permalink / raw)
  To: Alexander Duyck
  Cc: Dimitris Michailidis, davem@davemloft.net, Kirsher, Jeffrey T,
	netdev@vger.kernel.org
In-Reply-To: <4DC19912.3000803@intel.com>

On Wed, 2011-05-04 at 11:21 -0700, Alexander Duyck wrote:
[...]
> Honestly what I would prefer to see is a seperate call added such as an 
> ETHTOOL_GRSCLSRLLOC that we could pass the flow specifier to and perhaps 
> include first/last location call in that and then let the driver return 
> where it wants to drop the rule.

This must not be done as a separate operation because it's racy (in fact
that's an inherent problem with the rule manager).  In the sfc driver
(and probably others in future) filters could be inserted for RFS at any
time.

> That way we can avoid having to create 
> an overly complicated rule manager that can handle all the bizarre rule 
> ordering options that I am sure all the different network devices support.

Right, the rule manager can't implement that.

> The only reason I am not implementing this now is because there aren't 
> any drivers in place that would currently use it.  I figure once cxgb 
> has a means in place of supporting flow classifier rules then Dimitris 
> can add the necessary code to ethtool and the kernel to allow the driver 
> to specify rule locations.  I would prefer to avoid adding features 
> based on speculation of what will be needed and would like to be able to 
> actually see how the features will be used.

If you are going to implement the same interface in ixgbe as in niu
(modulo bugs), then I have no objection to going ahead with this and
then adding the option for driver-assigned locations later.

Please can you confirm that the location specified for
ETHTOOL_SRXCLSRLINS will indeed be used as a priority in case of
overlapping filters?

Ben.

-- 
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.


^ permalink raw reply

* Re: [ethtool PATCH 4/4] v5 Add RX packet classification interface
From: Dimitris Michailidis @ 2011-05-04 18:50 UTC (permalink / raw)
  To: Alexander Duyck
  Cc: Ben Hutchings, davem@davemloft.net, Kirsher, Jeffrey T,
	netdev@vger.kernel.org
In-Reply-To: <4DC19C78.9070308@intel.com>

On 05/04/2011 11:35 AM, Alexander Duyck wrote:
> On 5/4/2011 11:18 AM, Dimitris Michailidis wrote:
>> On 05/04/2011 10:41 AM, Alexander Duyck wrote:
>>> This is why I was suggesting that the best approach would be to update
>>> the kernel to add a separate ioctl for letting the driver setup the
>>> location.  We can just attempt to make that call and when we get the
>>> EOPNOTSUPP errno we know the device driver doesn't support it and can
>>> then let the rule manager take over.
>>
>> The problem with this is the location is dependent on the type of 
>> filter being
>> added.  I.e., the ioctl would need to get all the information the 
>> existing
>> ioctl carries making the new ioctl a small superset of the current one.
>> Additionally, if the driver only allocates a location in a separate 
>> ioctl how
>> does it know that the app is actually going to use it?
> 
> It doesn't know that the application is actually going to use it.  What 
> should happen is that the location should be verified by the driver when 
> it is used in the rule insertion call.  After all it is fully possible 
> for the user to specify a location out of range since the insert call 
> does no validation in ethtool if the user specified the location.  That 
> responsibility now lies with the driver.

That's not the problem I was pointing out.  Of course the driver will verify 
the location it is given.  The problem is if you have a separate ioctl call 
that only reserves a location (and it needs to reserve otherwise several of 
these calls can get the same value), if you don't use it you leave the driver 
with orphan reservations.  Imagine you hit ^C between the two ioctls in ethtool.


^ permalink raw reply

* Re: Divide error in bictcp_cong_avoid ?
From: David Miller @ 2011-05-04 18:56 UTC (permalink / raw)
  To: shemminger; +Cc: rdunlap, lkml, netdev, linux-kernel
In-Reply-To: <20110504113351.4643a0c9@nehalam>

From: Stephen Hemminger <shemminger@vyatta.com>
Date: Wed, 4 May 2011 11:33:51 -0700

> On Wed, 4 May 2011 10:49:40 -0700
> Randy Dunlap <rdunlap@xenotime.net> wrote:
> 
>> > [28522.642590] Pid: 0, comm: swapper Not tainted 2.6.38.5 #6
                                                      ^^^^^^^^

>> > 
>> >   Supermicro X8DTH-i/6/iF/6F
>> > /
>> >   X8DTH
>> > 
> 
> What kernel version?

It's right there in the dump Stephen, see above.

^ permalink raw reply

* Re: Divide error in bictcp_cong_avoid ?
From: TB @ 2011-05-04 19:03 UTC (permalink / raw)
  To: Randy Dunlap; +Cc: Stephen Hemminger, netdev, linux-kernel
In-Reply-To: <20110504113521.3c506a54.rdunlap@xenotime.net>

On 11-05-04 02:35 PM, Randy Dunlap wrote:
> On Wed, 4 May 2011 11:33:51 -0700 Stephen Hemminger wrote:
>
>> On Wed, 4 May 2011 10:49:40 -0700
>> Randy Dunlap<rdunlap@xenotime.net>  wrote:
>>
>>> [add cc to netdev]
>>>
>>>
>>> On Wed, 04 May 2011 12:03:31 -0400 TB wrote:
>>>
>>>> We're having this issue sporadically on a few servers and this is the
>>>> backtrace we get from netconsole.
>>>>
>>>>
>>>> [28522.642419] divide error: 0000 [#1] SMP
>>>> [28522.642457] last sysfs file:
>>>> /sys/devices/pci0000:00/0000:00:1f.2/host2/target2:0:0/2:0:0:0/vendor
>>>> [28522.642504] CPU 0
>>>> [28522.642511] Modules linked in:
>>>>    i2c_i801
>>>>    i2c_core
>>>>    evdev
>>>>    button
>>>> [28522.642570]
>>>> [28522.642590] Pid: 0, comm: swapper Not tainted 2.6.38.5 #6<<<<<<<<<<<<<<
>>>>
>>>>    Supermicro X8DTH-i/6/iF/6F
>>>> /
>>>>    X8DTH
>>>>
>>
>> What kernel version? I suspect they are running something really old
>> kernel like RHEL 5 since BIC has not been the default congestion control for
>> several years.
>
> Please see about 6 lines above.... at the "<<<<<<<<<<<".

/proc/sys/net/ipv4/tcp_available_congestion_control
cubic reno

cat /proc/sys/net/ipv4/tcp_congestion_control
cubic

^ permalink raw reply

* Re: [ethtool PATCH 4/4] v5 Add RX packet classification interface
From: Dimitris Michailidis @ 2011-05-04 19:06 UTC (permalink / raw)
  To: Ben Hutchings
  Cc: Alexander Duyck, davem@davemloft.net, Kirsher, Jeffrey T,
	netdev@vger.kernel.org
In-Reply-To: <1304532342.2926.46.camel@bwh-desktop>

On 05/04/2011 11:05 AM, Ben Hutchings wrote:
> How about having ETHTOOL_GRXCLSRLCNT set a flag in the 'data' field to
> indicate that the driver can assign locations?  (We would have to
> specify that for compatibility with older kernels the application must
> initialise this filed to 0.)
> 
> rmgr_init() would then check for this flag.

I think this is a good suggestion if we want to support location selection by 
either the driver or ethtool.  I also think ethtool's assumption that it is the 
only allocator and can allocate race-free is fundamentally flawed (take two 
parallel ethtools).

^ permalink raw reply

* Re: ath5k regression associating with APs in 2.6.38
From: Seth Forshee @ 2011-05-04 19:26 UTC (permalink / raw)
  To: John W. Linville
  Cc: Jiri Slaby, Nick Kossifidis, Luis R. Rodriguez, Bob Copeland,
	linux-wireless, ath5k-devel, netdev, linux-kernel
In-Reply-To: <20110504172716.GC18541@tuxdriver.com>

On Wed, May 04, 2011 at 01:27:17PM -0400, John W. Linville wrote:
> On Wed, May 04, 2011 at 10:38:19AM -0500, Seth Forshee wrote:
> > I've been investigating some reports of a regression in associating with
> > APs with AR2413 in 2.6.38. Association repeatedly fails with some
> > "direct probe to x timed out" messages (see syslog excerpt below),
> > although it will generally associate eventually, after many tries.
> > 
> > Bisection identifies 8aec7af (ath5k: Support synth-only channel change
> > for AR2413/AR5413) as offending commit. Prior to this commit there are
> > no direct probe messages at all in the logs. I've also found that
> > forcing fast to false at the top of ath5k_hw_reset() fixes the issue.
> > I'm not sure what the connection is between this commit and the
> > timeouts. Any suggestions?
> 
> Have you tried reverting that commit on top of 2.6.38?  Can you
> recreate the issue with 2.6.39-rc6 (or later)?

I started to revert that commit, but it wasn't straight-forward due to
later changes. Forcing fast to false in ath5k_hw_reset() acts as a
functional revert of sorts since that should force it back to a full
reset for all channel changes, and it's much simpler than working out
the right way to revert the commit. I think the results suggest strongly
that a revert is likely to fix the problem. I can finish the work to
revert if you'd still like to see the results.

Testing a previous .39-rc kernel still exhibited the failure. I don't
recall which one it was and apparently forgot to make note of it. I'll
request testing against rc6.

Thanks,
Seth

^ permalink raw reply

* Re: [PATCH rfc 1/5] r8169: style cleanups.
From: Francois Romieu @ 2011-05-04 19:17 UTC (permalink / raw)
  To: David Miller; +Cc: joe, netdev, nic_swsd
In-Reply-To: <20110427.140043.183040785.davem@davemloft.net>

David Miller <davem@davemloft.net> :
> From: Joe Perches <joe@perches.com>
[...]
> >> -	if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
> >> -	    tp->mac_version == RTL_GIGA_MAC_VER_33)
> >> +	if ((tp->mac_version == RTL_GIGA_MAC_VER_32) ||
> >> +	    (tp->mac_version == RTL_GIGA_MAC_VER_33))
> > 
> > Shrug.  I don't think this is better.
> 
> Yeah, same here.

Ok. I'll have the driver consistently use the former then.

Thanks.

-- 
Ueimor

^ permalink raw reply

* [net-next-2.6 0/9][pull request] Intel Wired LAN Driver Update
From: Jeff Kirsher @ 2011-05-04 19:30 UTC (permalink / raw)
  To: davem; +Cc: Jeff Kirsher, netdev, gospo, bphilips

The following series contains updates to e100, igb, igbvf, ixgb and ixgbe.

The following are changes since commit e67f88dd12f610da98ca838822f2c9b4e7c6100e:
  net: dont hold rtnl mutex during netlink dump callbacks
and are available in the git repository at:
  master.kernel.org:/pub/scm/linux/kernel/git/jkirsher/net-next-2.6 master

Carolyn Wyborny (1):
  igb: Add check for invalid size to igb_get_invariants_82575()

Don Skidmore (2):
  ixgbe: fix typo error with software defined pins on 82599
  ixgbe: Cleanup PCIe bus speed info

Emil Tantilov (4):
  e100: fix build warning
  ixgbe: Use function pointer for ixgbe_acquire/release_swfw_sync()
  ixgbe: fix sparse warning
  ixgbe: improve EEPROM read/write operations

Jeff Kirsher (1):
  ixgb: convert to set_phys_id

stephen hemminger (1):
  igbvf: remove bogus phys_id

 drivers/net/e100.c                |    2 +-
 drivers/net/igb/e1000_82575.c     |    8 +
 drivers/net/igbvf/ethtool.c       |    6 -
 drivers/net/ixgb/ixgb.h           |    3 -
 drivers/net/ixgb/ixgb_ethtool.c   |   46 +---
 drivers/net/ixgbe/ixgbe_82598.c   |    1 +
 drivers/net/ixgbe/ixgbe_82599.c   |   38 +++-
 drivers/net/ixgbe/ixgbe_common.c  |  440 +++++++++++++++++++++++++++++--------
 drivers/net/ixgbe/ixgbe_common.h  |    8 +
 drivers/net/ixgbe/ixgbe_ethtool.c |  115 ++++++-----
 drivers/net/ixgbe/ixgbe_main.c    |    7 +-
 drivers/net/ixgbe/ixgbe_phy.c     |   10 +-
 drivers/net/ixgbe/ixgbe_type.h    |    7 +
 drivers/net/ixgbe/ixgbe_x540.c    |   69 ++++++-
 14 files changed, 559 insertions(+), 201 deletions(-)

-- 
1.7.4.4


^ permalink raw reply

* [net-next-2.6 1/9] e100: fix build warning
From: Jeff Kirsher @ 2011-05-04 19:30 UTC (permalink / raw)
  To: davem; +Cc: Emil Tantilov, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1304537441-2056-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Emil Tantilov <emil.s.tantilov@intel.com>

In function 'e100_hw_init':
warning: 'err' may be used uninitialized in this function

Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Tested-by:  Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/e100.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index c810cda..29f812d 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1512,7 +1512,7 @@ static int e100_phy_init(struct nic *nic)
 
 static int e100_hw_init(struct nic *nic)
 {
-	int err;
+	int err = 0;
 
 	e100_hw_reset(nic);
 
-- 
1.7.4.4


^ permalink raw reply related

* [net-next-2.6 3/9] igb: Add check for invalid size to igb_get_invariants_82575()
From: Jeff Kirsher @ 2011-05-04 19:30 UTC (permalink / raw)
  To: davem; +Cc: Carolyn Wyborny, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1304537441-2056-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Carolyn Wyborny <carolyn.wyborny@intel.com>

Recent commits have changed how EEPROM size is checked and if the size
word is misconfigured, the driver will fail to load.  This patch adds a
check for invalid size word in the EEPROM and uses default size instead
for 82576 parts.

Reported-by: Stefan Assmann <sassmann@redhat.com>
Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/igb/e1000_82575.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index 0cd41c4..0f563c8 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -244,6 +244,14 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
 	 */
 	size += NVM_WORD_SIZE_BASE_SHIFT;
 
+	/*
+	 * Check for invalid size
+	 */
+	if ((hw->mac.type == e1000_82576) && (size > 15)) {
+		printk("igb: The NVM size is not valid, "
+			"defaulting to 32K.\n");
+		size = 15;
+	}
 	nvm->word_size = 1 << size;
 	if (nvm->word_size == (1 << 15))
 		nvm->page_size = 128;
-- 
1.7.4.4


^ permalink raw reply related

* [net-next-2.6 2/9] ixgb: convert to set_phys_id
From: Jeff Kirsher @ 2011-05-04 19:30 UTC (permalink / raw)
  To: davem; +Cc: Jeff Kirsher, netdev, gospo, bphilips, Stephen Hemminger
In-Reply-To: <1304537441-2056-1-git-send-email-jeffrey.t.kirsher@intel.com>

Based on the original patch sent by Stephen Hemminger.

This version incorporates the ethtool changes that Bruce Allan
submitted.

CC: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Tested-by: Evan Swanson <evan.swanson@intel.com>
---
 drivers/net/ixgb/ixgb.h         |    3 --
 drivers/net/ixgb/ixgb_ethtool.c |   46 ++++++++++----------------------------
 2 files changed, 12 insertions(+), 37 deletions(-)

diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index 8f3df04..49e8408 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -157,9 +157,6 @@ struct ixgb_adapter {
 	u16 link_duplex;
 	struct work_struct tx_timeout_task;
 
-	struct timer_list blink_timer;
-	unsigned long led_status;
-
 	/* TX */
 	struct ixgb_desc_ring tx_ring ____cacheline_aligned_in_smp;
 	unsigned int restart_queue;
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index 5f224c3..6da890b 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -611,45 +611,23 @@ err_setup_rx:
 	return err;
 }
 
-/* toggle LED 4 times per second = 2 "blinks" per second */
-#define IXGB_ID_INTERVAL	(HZ/4)
-
-/* bit defines for adapter->led_status */
-#define IXGB_LED_ON		0
-
-static void
-ixgb_led_blink_callback(unsigned long data)
-{
-	struct ixgb_adapter *adapter = (struct ixgb_adapter *)data;
-
-	if (test_and_change_bit(IXGB_LED_ON, &adapter->led_status))
-		ixgb_led_off(&adapter->hw);
-	else
-		ixgb_led_on(&adapter->hw);
-
-	mod_timer(&adapter->blink_timer, jiffies + IXGB_ID_INTERVAL);
-}
-
 static int
-ixgb_phys_id(struct net_device *netdev, u32 data)
+ixgb_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state)
 {
 	struct ixgb_adapter *adapter = netdev_priv(netdev);
 
-	if (!data)
-		data = INT_MAX;
-
-	if (!adapter->blink_timer.function) {
-		init_timer(&adapter->blink_timer);
-		adapter->blink_timer.function = ixgb_led_blink_callback;
-		adapter->blink_timer.data = (unsigned long)adapter;
-	}
+	switch (state) {
+	case ETHTOOL_ID_ACTIVE:
+		return 2;
 
-	mod_timer(&adapter->blink_timer, jiffies);
+	case ETHTOOL_ID_ON:
+		ixgb_led_on(&adapter->hw);
+		break;
 
-	msleep_interruptible(data * 1000);
-	del_timer_sync(&adapter->blink_timer);
-	ixgb_led_off(&adapter->hw);
-	clear_bit(IXGB_LED_ON, &adapter->led_status);
+	case ETHTOOL_ID_OFF:
+	case ETHTOOL_ID_INACTIVE:
+		ixgb_led_off(&adapter->hw);
+	}
 
 	return 0;
 }
@@ -767,7 +745,7 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
 	.set_msglevel = ixgb_set_msglevel,
 	.set_tso = ixgb_set_tso,
 	.get_strings = ixgb_get_strings,
-	.phys_id = ixgb_phys_id,
+	.set_phys_id = ixgb_set_phys_id,
 	.get_sset_count = ixgb_get_sset_count,
 	.get_ethtool_stats = ixgb_get_ethtool_stats,
 	.get_flags = ethtool_op_get_flags,
-- 
1.7.4.4


^ permalink raw reply related

* [net-next-2.6 4/9] igbvf: remove bogus phys_id
From: Jeff Kirsher @ 2011-05-04 19:30 UTC (permalink / raw)
  To: davem; +Cc: stephen hemminger, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1304537441-2056-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: stephen hemminger <shemminger@vyatta.com>

This device lies about supporting phys_id. Remove it and just
let the upper layer report not supported.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Tested-by: <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/igbvf/ethtool.c |    6 ------
 1 files changed, 0 insertions(+), 6 deletions(-)

diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c
index 112ae15..b0b14d6 100644
--- a/drivers/net/igbvf/ethtool.c
+++ b/drivers/net/igbvf/ethtool.c
@@ -391,11 +391,6 @@ static int igbvf_set_wol(struct net_device *netdev,
 	return -EOPNOTSUPP;
 }
 
-static int igbvf_phys_id(struct net_device *netdev, u32 data)
-{
-	return 0;
-}
-
 static int igbvf_get_coalesce(struct net_device *netdev,
                               struct ethtool_coalesce *ec)
 {
@@ -527,7 +522,6 @@ static const struct ethtool_ops igbvf_ethtool_ops = {
 	.self_test		= igbvf_diag_test,
 	.get_sset_count		= igbvf_get_sset_count,
 	.get_strings		= igbvf_get_strings,
-	.phys_id		= igbvf_phys_id,
 	.get_ethtool_stats	= igbvf_get_ethtool_stats,
 	.get_coalesce		= igbvf_get_coalesce,
 	.set_coalesce		= igbvf_set_coalesce,
-- 
1.7.4.4


^ permalink raw reply related

* [net-next-2.6 5/9] ixgbe: Use function pointer for ixgbe_acquire/release_swfw_sync()
From: Jeff Kirsher @ 2011-05-04 19:30 UTC (permalink / raw)
  To: davem; +Cc: Emil Tantilov, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1304537441-2056-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Emil Tantilov <emil.s.tantilov@intel.com>

Change remaining direct calls to function pointers.

Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Tested-by: Evan Swanson <evan.swanson@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_82599.c |    3 +--
 drivers/net/ixgbe/ixgbe_phy.c   |   10 +++++-----
 drivers/net/ixgbe/ixgbe_x540.c  |    2 +-
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
index d1cda36..5b8e17e 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ixgbe/ixgbe_82599.c
@@ -110,7 +110,6 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
 
 		ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset,
 		                                              &data_offset);
-
 		if (ret_val != 0)
 			goto setup_sfp_out;
 
@@ -130,7 +129,7 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
 		}
 
 		/* Release the semaphore */
-		ixgbe_release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM);
+		hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM);
 		/*
 		 * Delay obtaining semaphore again to allow FW access,
 		 * semaphore_delay is in ms usleep_range needs us.
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c
index edcaaeb..735f686 100644
--- a/drivers/net/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ixgbe/ixgbe_phy.c
@@ -1222,7 +1222,7 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
 		swfw_mask = IXGBE_GSSR_PHY0_SM;
 
 	do {
-		if (ixgbe_acquire_swfw_sync(hw, swfw_mask) != 0) {
+		if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != 0) {
 			status = IXGBE_ERR_SWFW_SYNC;
 			goto read_byte_out;
 		}
@@ -1269,7 +1269,7 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
 		break;
 
 fail:
-		ixgbe_release_swfw_sync(hw, swfw_mask);
+		hw->mac.ops.release_swfw_sync(hw, swfw_mask);
 		msleep(100);
 		ixgbe_i2c_bus_clear(hw);
 		retry++;
@@ -1280,7 +1280,7 @@ fail:
 
 	} while (retry < max_retry);
 
-	ixgbe_release_swfw_sync(hw, swfw_mask);
+	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
 
 read_byte_out:
 	return status;
@@ -1308,7 +1308,7 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
 	else
 		swfw_mask = IXGBE_GSSR_PHY0_SM;
 
-	if (ixgbe_acquire_swfw_sync(hw, swfw_mask) != 0) {
+	if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != 0) {
 		status = IXGBE_ERR_SWFW_SYNC;
 		goto write_byte_out;
 	}
@@ -1352,7 +1352,7 @@ fail:
 			hw_dbg(hw, "I2C byte write error.\n");
 	} while (retry < max_retry);
 
-	ixgbe_release_swfw_sync(hw, swfw_mask);
+	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
 
 write_byte_out:
 	return status;
diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c
index 75c6465..179ee82 100644
--- a/drivers/net/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ixgbe/ixgbe_x540.c
@@ -318,7 +318,7 @@ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data)
 	else
 		status = IXGBE_ERR_SWFW_SYNC;
 
-	ixgbe_release_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM);
+	hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
 	return status;
 }
 
-- 
1.7.4.4


^ permalink raw reply related

* [net-next-2.6 6/9] ixgbe: fix typo error with software defined pins on 82599
From: Jeff Kirsher @ 2011-05-04 19:30 UTC (permalink / raw)
  To: davem; +Cc: Don Skidmore, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1304537441-2056-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Don Skidmore <donald.c.skidmore@intel.com>

Correcting a simple typo with enabling software defined pins.  I don't
believe this was causing any issues but this is how it was meant to be
implemented.

Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com>
Tested-by: Evan Swanson <evan.swanson@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_main.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 9160811..bd3d21d 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -3862,9 +3862,10 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
 	if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
 		gpie |= IXGBE_SDP1_GPIEN;
 
-	if (hw->mac.type == ixgbe_mac_82599EB)
+	if (hw->mac.type == ixgbe_mac_82599EB) {
 		gpie |= IXGBE_SDP1_GPIEN;
 		gpie |= IXGBE_SDP2_GPIEN;
+	}
 
 	IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
 }
-- 
1.7.4.4


^ permalink raw reply related

* [net-next-2.6 7/9] ixgbe: fix sparse warning
From: Jeff Kirsher @ 2011-05-04 19:30 UTC (permalink / raw)
  To: davem; +Cc: Emil Tantilov, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1304537441-2056-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Emil Tantilov <emil.s.tantilov@intel.com>

warning: symbol 'before' shadows an earlier one

Convert large macros to functions similar to e1000e.

Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Acked-by: Don Skidmore <donald.c.skidmore@intel.com>
Tested-by: Evan Swanson <evan.swanson@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_ethtool.c |  108 +++++++++++++++++++++----------------
 1 files changed, 62 insertions(+), 46 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index bcba057..410c298 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -1236,46 +1236,62 @@ static const struct ixgbe_reg_test reg_test_82598[] = {
 	{ 0, 0, 0, 0 }
 };
 
-static const u32 register_test_patterns[] = {
-	0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
-};
-
-#define REG_PATTERN_TEST(R, M, W)                                             \
-{                                                                             \
-	u32 pat, val, before;                                                 \
-	for (pat = 0; pat < ARRAY_SIZE(register_test_patterns); pat++) {      \
-		before = readl(adapter->hw.hw_addr + R);                      \
-		writel((register_test_patterns[pat] & W),                     \
-		       (adapter->hw.hw_addr + R));                            \
-		val = readl(adapter->hw.hw_addr + R);                         \
-		if (val != (register_test_patterns[pat] & W & M)) {           \
-			e_err(drv, "pattern test reg %04X failed: got "       \
-			      "0x%08X expected 0x%08X\n",                     \
-			      R, val, (register_test_patterns[pat] & W & M)); \
-			*data = R;                                            \
-			writel(before, adapter->hw.hw_addr + R);              \
-			return 1;                                             \
-		}                                                             \
-		writel(before, adapter->hw.hw_addr + R);                      \
-	}                                                                     \
+static bool reg_pattern_test(struct ixgbe_adapter *adapter, u64 *data, int reg,
+			     u32 mask, u32 write)
+{
+	u32 pat, val, before;
+	static const u32 test_pattern[] = {
+		0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
+
+	for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
+		before = readl(adapter->hw.hw_addr + reg);
+		writel((test_pattern[pat] & write),
+		       (adapter->hw.hw_addr + reg));
+		val = readl(adapter->hw.hw_addr + reg);
+		if (val != (test_pattern[pat] & write & mask)) {
+			e_err(drv, "pattern test reg %04X failed: got "
+			      "0x%08X expected 0x%08X\n",
+			      reg, val, (test_pattern[pat] & write & mask));
+			*data = reg;
+			writel(before, adapter->hw.hw_addr + reg);
+			return 1;
+		}
+		writel(before, adapter->hw.hw_addr + reg);
+	}
+	return 0;
 }
 
-#define REG_SET_AND_CHECK(R, M, W)                                            \
-{                                                                             \
-	u32 val, before;                                                      \
-	before = readl(adapter->hw.hw_addr + R);                              \
-	writel((W & M), (adapter->hw.hw_addr + R));                           \
-	val = readl(adapter->hw.hw_addr + R);                                 \
-	if ((W & M) != (val & M)) {                                           \
-		e_err(drv, "set/check reg %04X test failed: got 0x%08X "  \
-		      "expected 0x%08X\n", R, (val & M), (W & M));        \
-		*data = R;                                                    \
-		writel(before, (adapter->hw.hw_addr + R));                    \
-		return 1;                                                     \
-	}                                                                     \
-	writel(before, (adapter->hw.hw_addr + R));                            \
+static bool reg_set_and_check(struct ixgbe_adapter *adapter, u64 *data, int reg,
+			      u32 mask, u32 write)
+{
+	u32 val, before;
+	before = readl(adapter->hw.hw_addr + reg);
+	writel((write & mask), (adapter->hw.hw_addr + reg));
+	val = readl(adapter->hw.hw_addr + reg);
+	if ((write & mask) != (val & mask)) {
+		e_err(drv, "set/check reg %04X test failed: got 0x%08X "
+		      "expected 0x%08X\n", reg, (val & mask), (write & mask));
+		*data = reg;
+		writel(before, (adapter->hw.hw_addr + reg));
+		return 1;
+	}
+	writel(before, (adapter->hw.hw_addr + reg));
+	return 0;
 }
 
+#define REG_PATTERN_TEST(reg, mask, write)				      \
+	do {								      \
+		if (reg_pattern_test(adapter, data, reg, mask, write))	      \
+			return 1;					      \
+	} while (0)							      \
+
+
+#define REG_SET_AND_CHECK(reg, mask, write)				      \
+	do {								      \
+		if (reg_set_and_check(adapter, data, reg, mask, write))	      \
+			return 1;					      \
+	} while (0)							      \
+
 static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
 {
 	const struct ixgbe_reg_test *test;
@@ -1326,13 +1342,13 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
 			switch (test->test_type) {
 			case PATTERN_TEST:
 				REG_PATTERN_TEST(test->reg + (i * 0x40),
-						test->mask,
-						test->write);
+						 test->mask,
+						 test->write);
 				break;
 			case SET_READ_TEST:
 				REG_SET_AND_CHECK(test->reg + (i * 0x40),
-						test->mask,
-						test->write);
+						  test->mask,
+						  test->write);
 				break;
 			case WRITE_NO_TEST:
 				writel(test->write,
@@ -1341,18 +1357,18 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
 				break;
 			case TABLE32_TEST:
 				REG_PATTERN_TEST(test->reg + (i * 4),
-						test->mask,
-						test->write);
+						 test->mask,
+						 test->write);
 				break;
 			case TABLE64_TEST_LO:
 				REG_PATTERN_TEST(test->reg + (i * 8),
-						test->mask,
-						test->write);
+						 test->mask,
+						 test->write);
 				break;
 			case TABLE64_TEST_HI:
 				REG_PATTERN_TEST((test->reg + 4) + (i * 8),
-						test->mask,
-						test->write);
+						 test->mask,
+						 test->write);
 				break;
 			}
 		}
-- 
1.7.4.4


^ permalink raw reply related

* [net-next-2.6 9/9] ixgbe: Cleanup PCIe bus speed info
From: Jeff Kirsher @ 2011-05-04 19:30 UTC (permalink / raw)
  To: davem; +Cc: Don Skidmore, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1304537441-2056-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Don Skidmore <donald.c.skidmore@intel.com>

PCIe connections should be expressed as GT/s (GigaTransfers per second)
instead of the current Gb/s (Gigabits per second).  In addition, it is
incorrect because (due to PCIe gen 1 & 2 having a 20% overhead) the
actually data rate, when expressed in Gb/s, is only 80% of the rate of
GT/s.

Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com>
Tested-by: Evan Swanson <evan.swanson@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_main.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index bd3d21d..eebb192 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -7469,8 +7469,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
 
 	/* print bus type/speed/width info */
 	e_dev_info("(PCI Express:%s:%s) %pM\n",
-		   (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0Gb/s" :
-		    hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5Gb/s" :
+		   (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0GT/s" :
+		    hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5GT/s" :
 		    "Unknown"),
 		   (hw->bus.width == ixgbe_bus_width_pcie_x8 ? "Width x8" :
 		    hw->bus.width == ixgbe_bus_width_pcie_x4 ? "Width x4" :
-- 
1.7.4.4


^ permalink raw reply related

* [net-next-2.6 8/9] ixgbe: improve EEPROM read/write operations
From: Jeff Kirsher @ 2011-05-04 19:30 UTC (permalink / raw)
  To: davem; +Cc: Emil Tantilov, netdev, gospo, bphilips, Jeff Kirsher
In-Reply-To: <1304537441-2056-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Emil Tantilov <emil.s.tantilov@intel.com>

Introduce buffered read/writes which greatly improves performance on
parts with large EEPROMs.

Previously reading/writing a word requires taking/releasing of synchronization
semaphores which adds 10ms to each operation. The optimization is to
read/write in buffers, but make sure the semaphore is not held for >500ms
according to the datasheet.

Since we can't read the EEPROM page size ixgbe_detect_eeprom_page_size() is
used to discover the EEPROM size when needed and keeps the result in
word_page_size for the rest of the run time.

Use buffered reads for ethtool -e.

Signed-off-by: Emil Tantilov <emil.s.tantilov@intel.com>
Tested-by: Evan Swanson <evan.swanson@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ixgbe/ixgbe_82598.c   |    1 +
 drivers/net/ixgbe/ixgbe_82599.c   |   35 +++
 drivers/net/ixgbe/ixgbe_common.c  |  440 +++++++++++++++++++++++++++++--------
 drivers/net/ixgbe/ixgbe_common.h  |    8 +
 drivers/net/ixgbe/ixgbe_ethtool.c |    7 +-
 drivers/net/ixgbe/ixgbe_type.h    |    7 +
 drivers/net/ixgbe/ixgbe_x540.c    |   67 +++++-
 7 files changed, 465 insertions(+), 100 deletions(-)

diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
index 7a64f50..8179e50 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -1281,6 +1281,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = {
 static struct ixgbe_eeprom_operations eeprom_ops_82598 = {
 	.init_params		= &ixgbe_init_eeprom_params_generic,
 	.read			= &ixgbe_read_eerd_generic,
+	.read_buffer		= &ixgbe_read_eerd_buffer_generic,
 	.calc_checksum          = &ixgbe_calc_eeprom_checksum_generic,
 	.validate_checksum	= &ixgbe_validate_eeprom_checksum_generic,
 	.update_checksum	= &ixgbe_update_eeprom_checksum_generic,
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
index 5b8e17e..dba5ca6 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ixgbe/ixgbe_82599.c
@@ -2064,6 +2064,39 @@ out:
 }
 
 /**
+ *  ixgbe_read_eeprom_buffer_82599 - Read EEPROM word(s) using
+ *  fastest available method
+ *
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in EEPROM to read
+ *  @words: number of words
+ *  @data: word(s) read from the EEPROM
+ *
+ *  Retrieves 16 bit word(s) read from EEPROM
+ **/
+static s32 ixgbe_read_eeprom_buffer_82599(struct ixgbe_hw *hw, u16 offset,
+					  u16 words, u16 *data)
+{
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	s32 ret_val = IXGBE_ERR_CONFIG;
+
+	/*
+	 * If EEPROM is detected and can be addressed using 14 bits,
+	 * use EERD otherwise use bit bang
+	 */
+	if ((eeprom->type == ixgbe_eeprom_spi) &&
+	    (offset + (words - 1) <= IXGBE_EERD_MAX_ADDR))
+		ret_val = ixgbe_read_eerd_buffer_generic(hw, offset, words,
+							 data);
+	else
+		ret_val = ixgbe_read_eeprom_buffer_bit_bang_generic(hw, offset,
+								    words,
+								    data);
+
+	return ret_val;
+}
+
+/**
  *  ixgbe_read_eeprom_82599 - Read EEPROM word using
  *  fastest available method
  *
@@ -2139,7 +2172,9 @@ static struct ixgbe_mac_operations mac_ops_82599 = {
 static struct ixgbe_eeprom_operations eeprom_ops_82599 = {
 	.init_params		= &ixgbe_init_eeprom_params_generic,
 	.read			= &ixgbe_read_eeprom_82599,
+	.read_buffer		= &ixgbe_read_eeprom_buffer_82599,
 	.write			= &ixgbe_write_eeprom_generic,
+	.write_buffer		= &ixgbe_write_eeprom_buffer_bit_bang_generic,
 	.calc_checksum		= &ixgbe_calc_eeprom_checksum_generic,
 	.validate_checksum	= &ixgbe_validate_eeprom_checksum_generic,
 	.update_checksum	= &ixgbe_update_eeprom_checksum_generic,
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
index cb2e8e1..c4730cd 100644
--- a/drivers/net/ixgbe/ixgbe_common.c
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -55,6 +55,12 @@ static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg,
 			      u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm);
 static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num);
 static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg);
+static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset,
+					     u16 words, u16 *data);
+static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset,
+					     u16 words, u16 *data);
+static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw,
+						 u16 offset);
 
 /**
  *  ixgbe_start_hw_generic - Prepare hardware for Tx/Rx
@@ -585,6 +591,8 @@ s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw)
 		/* Set default semaphore delay to 10ms which is a well
 		 * tested value */
 		eeprom->semaphore_delay = 10;
+		/* Clear EEPROM page size, it will be initialized as needed */
+		eeprom->word_page_size = 0;
 
 		/*
 		 * Check for EEPROM present first.
@@ -617,26 +625,78 @@ s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw)
 }
 
 /**
- *  ixgbe_write_eeprom_generic - Writes 16 bit value to EEPROM
+ *  ixgbe_write_eeprom_buffer_bit_bang_generic - Write EEPROM using bit-bang
  *  @hw: pointer to hardware structure
- *  @offset: offset within the EEPROM to be written to
- *  @data: 16 bit word to be written to the EEPROM
+ *  @offset: offset within the EEPROM to write
+ *  @words: number of words
+ *  @data: 16 bit word(s) to write to EEPROM
  *
- *  If ixgbe_eeprom_update_checksum is not called after this function, the
- *  EEPROM will most likely contain an invalid checksum.
+ *  Reads 16 bit word(s) from EEPROM through bit-bang method
  **/
-s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data)
+s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
+					       u16 words, u16 *data)
 {
-	s32 status;
-	u8 write_opcode = IXGBE_EEPROM_WRITE_OPCODE_SPI;
+	s32 status = 0;
+	u16 i, count;
 
 	hw->eeprom.ops.init_params(hw);
 
-	if (offset >= hw->eeprom.word_size) {
+	if (words == 0) {
+		status = IXGBE_ERR_INVALID_ARGUMENT;
+		goto out;
+	}
+
+	if (offset + words > hw->eeprom.word_size) {
 		status = IXGBE_ERR_EEPROM;
 		goto out;
 	}
 
+	/*
+	 * The EEPROM page size cannot be queried from the chip. We do lazy
+	 * initialization. It is worth to do that when we write large buffer.
+	 */
+	if ((hw->eeprom.word_page_size == 0) &&
+	    (words > IXGBE_EEPROM_PAGE_SIZE_MAX))
+		ixgbe_detect_eeprom_page_size_generic(hw, offset);
+
+	/*
+	 * We cannot hold synchronization semaphores for too long
+	 * to avoid other entity starvation. However it is more efficient
+	 * to read in bursts than synchronizing access for each word.
+	 */
+	for (i = 0; i < words; i += IXGBE_EEPROM_RD_BUFFER_MAX_COUNT) {
+		count = (words - i) / IXGBE_EEPROM_RD_BUFFER_MAX_COUNT > 0 ?
+			 IXGBE_EEPROM_RD_BUFFER_MAX_COUNT : (words - i);
+		status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset + i,
+							    count, &data[i]);
+
+		if (status != 0)
+			break;
+	}
+
+out:
+	return status;
+}
+
+/**
+ *  ixgbe_write_eeprom_buffer_bit_bang - Writes 16 bit word(s) to EEPROM
+ *  @hw: pointer to hardware structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of word(s)
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  If ixgbe_eeprom_update_checksum is not called after this function, the
+ *  EEPROM will most likely contain an invalid checksum.
+ **/
+static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset,
+					      u16 words, u16 *data)
+{
+	s32 status;
+	u16 word;
+	u16 page_size;
+	u16 i;
+	u8 write_opcode = IXGBE_EEPROM_WRITE_OPCODE_SPI;
+
 	/* Prepare the EEPROM for writing  */
 	status = ixgbe_acquire_eeprom(hw);
 
@@ -648,62 +708,147 @@ s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data)
 	}
 
 	if (status == 0) {
-		ixgbe_standby_eeprom(hw);
+		for (i = 0; i < words; i++) {
+			ixgbe_standby_eeprom(hw);
 
-		/*  Send the WRITE ENABLE command (8 bit opcode )  */
-		ixgbe_shift_out_eeprom_bits(hw, IXGBE_EEPROM_WREN_OPCODE_SPI,
-		                            IXGBE_EEPROM_OPCODE_BITS);
+			/*  Send the WRITE ENABLE command (8 bit opcode )  */
+			ixgbe_shift_out_eeprom_bits(hw,
+						  IXGBE_EEPROM_WREN_OPCODE_SPI,
+						  IXGBE_EEPROM_OPCODE_BITS);
 
-		ixgbe_standby_eeprom(hw);
+			ixgbe_standby_eeprom(hw);
 
-		/*
-		 * Some SPI eeproms use the 8th address bit embedded in the
-		 * opcode
-		 */
-		if ((hw->eeprom.address_bits == 8) && (offset >= 128))
-			write_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI;
+			/*
+			 * Some SPI eeproms use the 8th address bit embedded
+			 * in the opcode
+			 */
+			if ((hw->eeprom.address_bits == 8) &&
+			    ((offset + i) >= 128))
+				write_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI;
+
+			/* Send the Write command (8-bit opcode + addr) */
+			ixgbe_shift_out_eeprom_bits(hw, write_opcode,
+						    IXGBE_EEPROM_OPCODE_BITS);
+			ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2),
+						    hw->eeprom.address_bits);
+
+			page_size = hw->eeprom.word_page_size;
+
+			/* Send the data in burst via SPI*/
+			do {
+				word = data[i];
+				word = (word >> 8) | (word << 8);
+				ixgbe_shift_out_eeprom_bits(hw, word, 16);
+
+				if (page_size == 0)
+					break;
+
+				/* do not wrap around page */
+				if (((offset + i) & (page_size - 1)) ==
+				    (page_size - 1))
+					break;
+			} while (++i < words);
+
+			ixgbe_standby_eeprom(hw);
+			usleep_range(10000, 20000);
+		}
+		/* Done with writing - release the EEPROM */
+		ixgbe_release_eeprom(hw);
+	}
 
-		/* Send the Write command (8-bit opcode + addr) */
-		ixgbe_shift_out_eeprom_bits(hw, write_opcode,
-		                            IXGBE_EEPROM_OPCODE_BITS);
-		ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2),
-		                            hw->eeprom.address_bits);
+	return status;
+}
 
-		/* Send the data */
-		data = (data >> 8) | (data << 8);
-		ixgbe_shift_out_eeprom_bits(hw, data, 16);
-		ixgbe_standby_eeprom(hw);
+/**
+ *  ixgbe_write_eeprom_generic - Writes 16 bit value to EEPROM
+ *  @hw: pointer to hardware structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @data: 16 bit word to be written to the EEPROM
+ *
+ *  If ixgbe_eeprom_update_checksum is not called after this function, the
+ *  EEPROM will most likely contain an invalid checksum.
+ **/
+s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data)
+{
+	s32 status;
 
-		/* Done with writing - release the EEPROM */
-		ixgbe_release_eeprom(hw);
+	hw->eeprom.ops.init_params(hw);
+
+	if (offset >= hw->eeprom.word_size) {
+		status = IXGBE_ERR_EEPROM;
+		goto out;
 	}
 
+	status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset, 1, &data);
+
 out:
 	return status;
 }
 
 /**
- *  ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang
+ *  ixgbe_read_eeprom_buffer_bit_bang_generic - Read EEPROM using bit-bang
  *  @hw: pointer to hardware structure
  *  @offset: offset within the EEPROM to be read
- *  @data: read 16 bit value from EEPROM
+ *  @words: number of word(s)
+ *  @data: read 16 bit words(s) from EEPROM
  *
- *  Reads 16 bit value from EEPROM through bit-bang method
+ *  Reads 16 bit word(s) from EEPROM through bit-bang method
  **/
-s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
-                                       u16 *data)
+s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
+					      u16 words, u16 *data)
 {
-	s32 status;
-	u16 word_in;
-	u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI;
+	s32 status = 0;
+	u16 i, count;
 
 	hw->eeprom.ops.init_params(hw);
 
-	if (offset >= hw->eeprom.word_size) {
+	if (words == 0) {
+		status = IXGBE_ERR_INVALID_ARGUMENT;
+		goto out;
+	}
+
+	if (offset + words > hw->eeprom.word_size) {
 		status = IXGBE_ERR_EEPROM;
 		goto out;
 	}
 
+	/*
+	 * We cannot hold synchronization semaphores for too long
+	 * to avoid other entity starvation. However it is more efficient
+	 * to read in bursts than synchronizing access for each word.
+	 */
+	for (i = 0; i < words; i += IXGBE_EEPROM_RD_BUFFER_MAX_COUNT) {
+		count = (words - i) / IXGBE_EEPROM_RD_BUFFER_MAX_COUNT > 0 ?
+			 IXGBE_EEPROM_RD_BUFFER_MAX_COUNT : (words - i);
+
+		status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset + i,
+							   count, &data[i]);
+
+		if (status != 0)
+			break;
+	}
+
+out:
+	return status;
+}
+
+/**
+ *  ixgbe_read_eeprom_buffer_bit_bang - Read EEPROM using bit-bang
+ *  @hw: pointer to hardware structure
+ *  @offset: offset within the EEPROM to be read
+ *  @words: number of word(s)
+ *  @data: read 16 bit word(s) from EEPROM
+ *
+ *  Reads 16 bit word(s) from EEPROM through bit-bang method
+ **/
+static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset,
+					     u16 words, u16 *data)
+{
+	s32 status;
+	u16 word_in;
+	u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI;
+	u16 i;
+
 	/* Prepare the EEPROM for reading  */
 	status = ixgbe_acquire_eeprom(hw);
 
@@ -715,104 +860,208 @@ s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
 	}
 
 	if (status == 0) {
-		ixgbe_standby_eeprom(hw);
+		for (i = 0; i < words; i++) {
+			ixgbe_standby_eeprom(hw);
+			/*
+			 * Some SPI eeproms use the 8th address bit embedded
+			 * in the opcode
+			 */
+			if ((hw->eeprom.address_bits == 8) &&
+			    ((offset + i) >= 128))
+				read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI;
+
+			/* Send the READ command (opcode + addr) */
+			ixgbe_shift_out_eeprom_bits(hw, read_opcode,
+						    IXGBE_EEPROM_OPCODE_BITS);
+			ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2),
+						    hw->eeprom.address_bits);
+
+			/* Read the data. */
+			word_in = ixgbe_shift_in_eeprom_bits(hw, 16);
+			data[i] = (word_in >> 8) | (word_in << 8);
+		}
 
-		/*
-		 * Some SPI eeproms use the 8th address bit embedded in the
-		 * opcode
-		 */
-		if ((hw->eeprom.address_bits == 8) && (offset >= 128))
-			read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI;
+		/* End this read operation */
+		ixgbe_release_eeprom(hw);
+	}
 
-		/* Send the READ command (opcode + addr) */
-		ixgbe_shift_out_eeprom_bits(hw, read_opcode,
-		                            IXGBE_EEPROM_OPCODE_BITS);
-		ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2),
-		                            hw->eeprom.address_bits);
+	return status;
+}
 
-		/* Read the data. */
-		word_in = ixgbe_shift_in_eeprom_bits(hw, 16);
-		*data = (word_in >> 8) | (word_in << 8);
+/**
+ *  ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang
+ *  @hw: pointer to hardware structure
+ *  @offset: offset within the EEPROM to be read
+ *  @data: read 16 bit value from EEPROM
+ *
+ *  Reads 16 bit value from EEPROM through bit-bang method
+ **/
+s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
+				       u16 *data)
+{
+	s32 status;
 
-		/* End this read operation */
-		ixgbe_release_eeprom(hw);
+	hw->eeprom.ops.init_params(hw);
+
+	if (offset >= hw->eeprom.word_size) {
+		status = IXGBE_ERR_EEPROM;
+		goto out;
 	}
 
+	status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data);
+
 out:
 	return status;
 }
 
 /**
- *  ixgbe_read_eerd_generic - Read EEPROM word using EERD
+ *  ixgbe_read_eerd_buffer_generic - Read EEPROM word(s) using EERD
  *  @hw: pointer to hardware structure
- *  @offset: offset of  word in the EEPROM to read
- *  @data: word read from the EEPROM
+ *  @offset: offset of word in the EEPROM to read
+ *  @words: number of word(s)
+ *  @data: 16 bit word(s) from the EEPROM
  *
- *  Reads a 16 bit word from the EEPROM using the EERD register.
+ *  Reads a 16 bit word(s) from the EEPROM using the EERD register.
  **/
-s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data)
+s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset,
+				   u16 words, u16 *data)
 {
 	u32 eerd;
-	s32 status;
+	s32 status = 0;
+	u32 i;
 
 	hw->eeprom.ops.init_params(hw);
 
+	if (words == 0) {
+		status = IXGBE_ERR_INVALID_ARGUMENT;
+		goto out;
+	}
+
 	if (offset >= hw->eeprom.word_size) {
 		status = IXGBE_ERR_EEPROM;
 		goto out;
 	}
 
-	eerd = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) +
-	       IXGBE_EEPROM_RW_REG_START;
+	for (i = 0; i < words; i++) {
+		eerd = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) +
+		       IXGBE_EEPROM_RW_REG_START;
 
-	IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd);
-	status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_READ);
+		IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd);
+		status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_READ);
 
-	if (status == 0)
-		*data = (IXGBE_READ_REG(hw, IXGBE_EERD) >>
-		         IXGBE_EEPROM_RW_REG_DATA);
-	else
-		hw_dbg(hw, "Eeprom read timed out\n");
+		if (status == 0) {
+			data[i] = (IXGBE_READ_REG(hw, IXGBE_EERD) >>
+				   IXGBE_EEPROM_RW_REG_DATA);
+		} else {
+			hw_dbg(hw, "Eeprom read timed out\n");
+			goto out;
+		}
+	}
+out:
+	return status;
+}
 
+/**
+ *  ixgbe_detect_eeprom_page_size_generic - Detect EEPROM page size
+ *  @hw: pointer to hardware structure
+ *  @offset: offset within the EEPROM to be used as a scratch pad
+ *
+ *  Discover EEPROM page size by writing marching data at given offset.
+ *  This function is called only when we are writing a new large buffer
+ *  at given offset so the data would be overwritten anyway.
+ **/
+static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw,
+						 u16 offset)
+{
+	u16 data[IXGBE_EEPROM_PAGE_SIZE_MAX];
+	s32 status = 0;
+	u16 i;
+
+	for (i = 0; i < IXGBE_EEPROM_PAGE_SIZE_MAX; i++)
+		data[i] = i;
+
+	hw->eeprom.word_page_size = IXGBE_EEPROM_PAGE_SIZE_MAX;
+	status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset,
+					     IXGBE_EEPROM_PAGE_SIZE_MAX, data);
+	hw->eeprom.word_page_size = 0;
+	if (status != 0)
+		goto out;
+
+	status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data);
+	if (status != 0)
+		goto out;
+
+	/*
+	 * When writing in burst more than the actual page size
+	 * EEPROM address wraps around current page.
+	 */
+	hw->eeprom.word_page_size = IXGBE_EEPROM_PAGE_SIZE_MAX - data[0];
+
+	hw_dbg(hw, "Detected EEPROM page size = %d words.",
+	       hw->eeprom.word_page_size);
 out:
 	return status;
 }
 
 /**
- *  ixgbe_write_eewr_generic - Write EEPROM word using EEWR
+ *  ixgbe_read_eerd_generic - Read EEPROM word using EERD
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data)
+{
+	return ixgbe_read_eerd_buffer_generic(hw, offset, 1, data);
+}
+
+/**
+ *  ixgbe_write_eewr_buffer_generic - Write EEPROM word(s) using EEWR
  *  @hw: pointer to hardware structure
  *  @offset: offset of  word in the EEPROM to write
- *  @data: word write to the EEPROM
+ *  @words: number of words
+ *  @data: word(s) write to the EEPROM
  *
- *  Write a 16 bit word to the EEPROM using the EEWR register.
+ *  Write a 16 bit word(s) to the EEPROM using the EEWR register.
  **/
-s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data)
+s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset,
+				    u16 words, u16 *data)
 {
 	u32 eewr;
-	s32 status;
+	s32 status = 0;
+	u16 i;
 
 	hw->eeprom.ops.init_params(hw);
 
+	if (words == 0) {
+		status = IXGBE_ERR_INVALID_ARGUMENT;
+		goto out;
+	}
+
 	if (offset >= hw->eeprom.word_size) {
 		status = IXGBE_ERR_EEPROM;
 		goto out;
 	}
 
-	eewr = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) |
-	       (data << IXGBE_EEPROM_RW_REG_DATA) | IXGBE_EEPROM_RW_REG_START;
+	for (i = 0; i < words; i++) {
+		eewr = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) |
+		       (data[i] << IXGBE_EEPROM_RW_REG_DATA) |
+		       IXGBE_EEPROM_RW_REG_START;
 
-	status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
-	if (status != 0) {
-		hw_dbg(hw, "Eeprom write EEWR timed out\n");
-		goto out;
-	}
+		status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
+		if (status != 0) {
+			hw_dbg(hw, "Eeprom write EEWR timed out\n");
+			goto out;
+		}
 
-	IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr);
+		IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr);
 
-	status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
-	if (status != 0) {
-		hw_dbg(hw, "Eeprom write EEWR timed out\n");
-		goto out;
+		status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
+		if (status != 0) {
+			hw_dbg(hw, "Eeprom write EEWR timed out\n");
+			goto out;
+		}
 	}
 
 out:
@@ -820,6 +1069,19 @@ out:
 }
 
 /**
+ *  ixgbe_write_eewr_generic - Write EEPROM word using EEWR
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to write
+ *  @data: word write to the EEPROM
+ *
+ *  Write a 16 bit word to the EEPROM using the EEWR register.
+ **/
+s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data)
+{
+	return ixgbe_write_eewr_buffer_generic(hw, offset, 1, &data);
+}
+
+/**
  *  ixgbe_poll_eerd_eewr_done - Poll EERD read or EEWR write status
  *  @hw: pointer to hardware structure
  *  @ee_reg: EEPROM flag for polling
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
index e850adb..46be83c 100644
--- a/drivers/net/ixgbe/ixgbe_common.h
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -49,10 +49,18 @@ s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index);
 
 s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw);
 s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data);
+s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
+					       u16 words, u16 *data);
 s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data);
+s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset,
+				   u16 words, u16 *data);
 s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data);
+s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset,
+				    u16 words, u16 *data);
 s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
                                        u16 *data);
+s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
+					      u16 words, u16 *data);
 u16 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw);
 s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw,
                                            u16 *checksum_val);
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 410c298..f2efa32 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -847,11 +847,8 @@ static int ixgbe_get_eeprom(struct net_device *netdev,
 	if (!eeprom_buff)
 		return -ENOMEM;
 
-	for (i = 0; i < eeprom_len; i++) {
-		if ((ret_val = hw->eeprom.ops.read(hw, first_word + i,
-		    &eeprom_buff[i])))
-			break;
-	}
+	ret_val = hw->eeprom.ops.read_buffer(hw, first_word, eeprom_len,
+					     eeprom_buff);
 
 	/* Device's eeprom is always little-endian, word addressable */
 	for (i = 0; i < eeprom_len; i++)
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index fab9737..b1d523c 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -1668,6 +1668,10 @@
 
 #define IXGBE_ETH_LENGTH_OF_ADDRESS   6
 
+#define IXGBE_EEPROM_PAGE_SIZE_MAX       128
+#define IXGBE_EEPROM_RD_BUFFER_MAX_COUNT 512 /* EEPROM words # read in burst */
+#define IXGBE_EEPROM_WR_BUFFER_MAX_COUNT 256 /* EEPROM words # wr in burst */
+
 #ifndef IXGBE_EEPROM_GRANT_ATTEMPTS
 #define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
 #endif
@@ -2563,7 +2567,9 @@ typedef u8* (*ixgbe_mc_addr_itr) (struct ixgbe_hw *hw, u8 **mc_addr_ptr,
 struct ixgbe_eeprom_operations {
 	s32 (*init_params)(struct ixgbe_hw *);
 	s32 (*read)(struct ixgbe_hw *, u16, u16 *);
+	s32 (*read_buffer)(struct ixgbe_hw *, u16, u16, u16 *);
 	s32 (*write)(struct ixgbe_hw *, u16, u16);
+	s32 (*write_buffer)(struct ixgbe_hw *, u16, u16, u16 *);
 	s32 (*validate_checksum)(struct ixgbe_hw *, u16 *);
 	s32 (*update_checksum)(struct ixgbe_hw *);
 	u16 (*calc_checksum)(struct ixgbe_hw *);
@@ -2649,6 +2655,7 @@ struct ixgbe_eeprom_info {
 	u32                             semaphore_delay;
 	u16                             word_size;
 	u16                             address_bits;
+	u16                             word_page_size;
 };
 
 #define IXGBE_FLAGS_DOUBLE_RESET_REQUIRED	0x01
diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c
index 179ee82..4ed687b 100644
--- a/drivers/net/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ixgbe/ixgbe_x540.c
@@ -304,16 +304,19 @@ static s32 ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw)
 }
 
 /**
- * ixgbe_read_eerd_X540 - Read EEPROM word using EERD
- * @hw: pointer to hardware structure
- * @offset: offset of word in the EEPROM to read
- * @data: word read from the EERPOM
+ *  ixgbe_read_eerd_X540- Read EEPROM word using EERD
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM using the EERD register.
  **/
 static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data)
 {
-	s32 status;
+	s32 status = 0;
 
-	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0)
+	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) ==
+	    0)
 		status = ixgbe_read_eerd_generic(hw, offset, data);
 	else
 		status = IXGBE_ERR_SWFW_SYNC;
@@ -323,6 +326,31 @@ static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data)
 }
 
 /**
+ *  ixgbe_read_eerd_buffer_X540 - Read EEPROM word(s) using EERD
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to read
+ *  @words: number of words
+ *  @data: word(s) read from the EEPROM
+ *
+ *  Reads a 16 bit word(s) from the EEPROM using the EERD register.
+ **/
+static s32 ixgbe_read_eerd_buffer_X540(struct ixgbe_hw *hw,
+				       u16 offset, u16 words, u16 *data)
+{
+	s32 status = 0;
+
+	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) ==
+	    0)
+		status = ixgbe_read_eerd_buffer_generic(hw, offset,
+							words, data);
+	else
+		status = IXGBE_ERR_SWFW_SYNC;
+
+	hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+	return status;
+}
+
+/**
  *  ixgbe_write_eewr_X540 - Write EEPROM word using EEWR
  *  @hw: pointer to hardware structure
  *  @offset: offset of  word in the EEPROM to write
@@ -344,6 +372,31 @@ static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data)
 }
 
 /**
+ *  ixgbe_write_eewr_buffer_X540 - Write EEPROM word(s) using EEWR
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to write
+ *  @words: number of words
+ *  @data: word(s) write to the EEPROM
+ *
+ *  Write a 16 bit word(s) to the EEPROM using the EEWR register.
+ **/
+static s32 ixgbe_write_eewr_buffer_X540(struct ixgbe_hw *hw,
+					u16 offset, u16 words, u16 *data)
+{
+	s32 status = 0;
+
+	if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) ==
+	    0)
+		status = ixgbe_write_eewr_buffer_generic(hw, offset,
+							 words, data);
+	else
+		status = IXGBE_ERR_SWFW_SYNC;
+
+	hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+	return status;
+}
+
+/**
  *  ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum
  *
  *  This function does not use synchronization for EERD and EEWR. It can
@@ -851,7 +904,9 @@ static struct ixgbe_mac_operations mac_ops_X540 = {
 static struct ixgbe_eeprom_operations eeprom_ops_X540 = {
 	.init_params            = &ixgbe_init_eeprom_params_X540,
 	.read                   = &ixgbe_read_eerd_X540,
+	.read_buffer		= &ixgbe_read_eerd_buffer_X540,
 	.write                  = &ixgbe_write_eewr_X540,
+	.write_buffer		= &ixgbe_write_eewr_buffer_X540,
 	.calc_checksum		= &ixgbe_calc_eeprom_checksum_X540,
 	.validate_checksum      = &ixgbe_validate_eeprom_checksum_X540,
 	.update_checksum        = &ixgbe_update_eeprom_checksum_X540,
-- 
1.7.4.4


^ permalink raw reply related

* Re: Divide error in bictcp_cong_avoid ?
From: Valdis.Kletnieks @ 2011-05-04 19:31 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: Randy Dunlap, TB, netdev, linux-kernel
In-Reply-To: <20110504113351.4643a0c9@nehalam>

[-- Attachment #1: Type: text/plain, Size: 697 bytes --]

On Wed, 04 May 2011 11:33:51 PDT, Stephen Hemminger said:

> What kernel version? I suspect they are running something really old
> kernel like RHEL 5 since BIC has not been the default congestion control for
> several years.

Pretty bleeding edge here, and BIC is *still* the default:

% uname -a
Linux turing-police.cc.vt.edu 2.6.39-rc5-mmotm0429 #1 SMP PREEMPT Sat Apr 30 00:36:49 EDT 2011 x86_64 x86_64 x86_64 GNU/Linux
% zgrep -i BIC /proc/config.gz 
CONFIG_TCP_CONG_BIC=y
CONFIG_TCP_CONG_CUBIC=m
CONFIG_DEFAULT_BIC=y
CONFIG_DEFAULT_TCP_CONG="bic"

Why? Because BIC was working "well enough", so I never changed it by hand, and
"make oldconfig" never changed it automagically either.  Now, 


[-- Attachment #2: Type: application/pgp-signature, Size: 227 bytes --]

^ permalink raw reply

* Re: Divide error in bictcp_cong_avoid ?
From: Stephen Hemminger @ 2011-05-04 19:37 UTC (permalink / raw)
  To: Valdis.Kletnieks; +Cc: Randy Dunlap, TB, netdev, linux-kernel
In-Reply-To: <16668.1304537481@localhost>

On Wed, 04 May 2011 15:31:21 -0400
Valdis.Kletnieks@vt.edu wrote:

> On Wed, 04 May 2011 11:33:51 PDT, Stephen Hemminger said:
> 
> > What kernel version? I suspect they are running something really old
> > kernel like RHEL 5 since BIC has not been the default congestion control for
> > several years.
> 
> Pretty bleeding edge here, and BIC is *still* the default:
> 
> % uname -a
> Linux turing-police.cc.vt.edu 2.6.39-rc5-mmotm0429 #1 SMP PREEMPT Sat Apr 30 00:36:49 EDT 2011 x86_64 x86_64 x86_64 GNU/Linux
> % zgrep -i BIC /proc/config.gz 
> CONFIG_TCP_CONG_BIC=y
> CONFIG_TCP_CONG_CUBIC=m
> CONFIG_DEFAULT_BIC=y
> CONFIG_DEFAULT_TCP_CONG="bic"
> 
> Why? Because BIC was working "well enough", so I never changed it by hand, and
> "make oldconfig" never changed it automagically either.  Now, 
> 

The CUBIC code has the same function names so that is where the
problem is.

Don't use BIC, it is known to be unfair between flows.
The configuration process never changes your values, it only asks
about new ones.

-- 

^ permalink raw reply

* Re: [PATCH 1/2] libertas: Convert lbs_pr_<level> to pr_<level>
From: Dan Williams @ 2011-05-04 19:39 UTC (permalink / raw)
  To: Joe Perches
  Cc: John W. Linville, libertas-dev-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <353dfb1607172b5a3dbaccddbe52c24312d42af4.1304379925.git.joe-6d6DIl74uiNBDgjK7y7TUQ@public.gmane.org>

On Mon, 2011-05-02 at 16:49 -0700, Joe Perches wrote:
> Use the standard pr_<level> functions eases grep a bit.
> 
> Added a few missing terminating newlines to messages.
> Coalesced long formats.

Is there any reason to not put the pr_fmt() definition into 'defs.h'
instead of C&P at the top of every file?  I don't really care either way
but that seems cleaner since almost all the libertas files are going to
use logging.

Dan

> Signed-off-by: Joe Perches <joe-6d6DIl74uiNBDgjK7y7TUQ@public.gmane.org>
> ---
>  drivers/net/wireless/libertas/cfg.c     |   15 +++---
>  drivers/net/wireless/libertas/cmd.c     |   36 +++++++-------
>  drivers/net/wireless/libertas/cmdresp.c |   29 +++++++-----
>  drivers/net/wireless/libertas/debugfs.c |    6 ++-
>  drivers/net/wireless/libertas/defs.h    |    7 ---
>  drivers/net/wireless/libertas/if_cs.c   |   52 +++++++++++----------
>  drivers/net/wireless/libertas/if_sdio.c |   38 ++++++++--------
>  drivers/net/wireless/libertas/if_spi.c  |   74 ++++++++++++++-----------------
>  drivers/net/wireless/libertas/if_usb.c  |   41 +++++++++--------
>  drivers/net/wireless/libertas/main.c    |   33 +++++++-------
>  drivers/net/wireless/libertas/mesh.c    |    8 ++-
>  drivers/net/wireless/libertas/rx.c      |    7 ++-
>  12 files changed, 174 insertions(+), 172 deletions(-)
> 
> diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
> index 5caa2ac..d6e0656 100644
> --- a/drivers/net/wireless/libertas/cfg.c
> +++ b/drivers/net/wireless/libertas/cfg.c
> @@ -6,6 +6,8 @@
>   *
>   */
>  
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
>  #include <linux/sched.h>
>  #include <linux/wait.h>
>  #include <linux/slab.h>
> @@ -1314,8 +1316,7 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
>  		sme->ssid, sme->ssid_len,
>  		WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
>  	if (!bss) {
> -		lbs_pr_err("assoc: bss %pM not in scan results\n",
> -			   sme->bssid);
> +		pr_err("assoc: bss %pM not in scan results\n", sme->bssid);
>  		ret = -ENOENT;
>  		goto done;
>  	}
> @@ -1372,8 +1373,8 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
>  		lbs_enable_rsn(priv, sme->crypto.cipher_group != 0);
>  		break;
>  	default:
> -		lbs_pr_err("unsupported cipher group 0x%x\n",
> -			   sme->crypto.cipher_group);
> +		pr_err("unsupported cipher group 0x%x\n",
> +		       sme->crypto.cipher_group);
>  		ret = -ENOTSUPP;
>  		goto done;
>  	}
> @@ -1491,7 +1492,7 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
>  				     params->key, params->key_len);
>  		break;
>  	default:
> -		lbs_pr_err("unhandled cipher 0x%x\n", params->cipher);
> +		pr_err("unhandled cipher 0x%x\n", params->cipher);
>  		ret = -ENOTSUPP;
>  		break;
>  	}
> @@ -2118,13 +2119,13 @@ int lbs_cfg_register(struct lbs_private *priv)
>  
>  	ret = wiphy_register(wdev->wiphy);
>  	if (ret < 0)
> -		lbs_pr_err("cannot register wiphy device\n");
> +		pr_err("cannot register wiphy device\n");
>  
>  	priv->wiphy_registered = true;
>  
>  	ret = register_netdev(priv->dev);
>  	if (ret)
> -		lbs_pr_err("cannot register network device\n");
> +		pr_err("cannot register network device\n");
>  
>  	INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
>  
> diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
> index 7e8a658..10ca485 100644
> --- a/drivers/net/wireless/libertas/cmd.c
> +++ b/drivers/net/wireless/libertas/cmd.c
> @@ -3,6 +3,8 @@
>    * It prepares command and sends it to firmware when it is ready.
>    */
>  
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
>  #include <linux/kfifo.h>
>  #include <linux/sched.h>
>  #include <linux/slab.h>
> @@ -108,7 +110,7 @@ int lbs_update_hw_spec(struct lbs_private *priv)
>  	 * CF card    firmware 5.0.16p0:   cap 0x00000303
>  	 * USB dongle firmware 5.110.17p2: cap 0x00000303
>  	 */
> -	lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n",
> +	pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n",
>  		cmd.permanentaddr,
>  		priv->fwrelease >> 24 & 0xff,
>  		priv->fwrelease >> 16 & 0xff,
> @@ -139,7 +141,7 @@ int lbs_update_hw_spec(struct lbs_private *priv)
>  	/* if it's unidentified region code, use the default (USA) */
>  	if (i >= MRVDRV_MAX_REGION_CODE) {
>  		priv->regioncode = 0x10;
> -		lbs_pr_info("unidentified region code; using the default (USA)\n");
> +		pr_info("unidentified region code; using the default (USA)\n");
>  	}
>  
>  	if (priv->current_addr[0] == 0xff)
> @@ -209,7 +211,7 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
>  					(uint8_t *)&cmd_config.wol_conf,
>  					sizeof(struct wol_config));
>  	} else {
> -		lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
> +		pr_info("HOST_SLEEP_CFG failed %d\n", ret);
>  	}
>  
>  	return ret;
> @@ -312,7 +314,7 @@ static int lbs_wait_for_ds_awake(struct lbs_private *priv)
>  	if (priv->is_deep_sleep) {
>  		if (!wait_event_interruptible_timeout(priv->ds_awake_q,
>  					!priv->is_deep_sleep, (10 * HZ))) {
> -			lbs_pr_err("ds_awake_q: timer expired\n");
> +			pr_err("ds_awake_q: timer expired\n");
>  			ret = -1;
>  		}
>  	}
> @@ -337,7 +339,7 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
>  				netif_carrier_off(priv->dev);
>  			}
>  		} else {
> -			lbs_pr_err("deep sleep: already enabled\n");
> +			pr_err("deep sleep: already enabled\n");
>  		}
>  	} else {
>  		if (priv->is_deep_sleep) {
> @@ -347,8 +349,7 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
>  			if (!ret) {
>  				ret = lbs_wait_for_ds_awake(priv);
>  				if (ret)
> -					lbs_pr_err("deep sleep: wakeup"
> -							"failed\n");
> +					pr_err("deep sleep: wakeup failed\n");
>  			}
>  		}
>  	}
> @@ -382,8 +383,8 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
>  			ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
>  					(struct wol_config *)NULL);
>  			if (ret) {
> -				lbs_pr_info("Host sleep configuration failed: "
> -						"%d\n", ret);
> +				pr_info("Host sleep configuration failed: %d\n",
> +					ret);
>  				return ret;
>  			}
>  			if (priv->psstate == PS_STATE_FULL_POWER) {
> @@ -393,19 +394,19 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
>  						sizeof(cmd),
>  						lbs_ret_host_sleep_activate, 0);
>  				if (ret)
> -					lbs_pr_info("HOST_SLEEP_ACTIVATE "
> -							"failed: %d\n", ret);
> +					pr_info("HOST_SLEEP_ACTIVATE failed: %d\n",
> +						ret);
>  			}
>  
>  			if (!wait_event_interruptible_timeout(
>  						priv->host_sleep_q,
>  						priv->is_host_sleep_activated,
>  						(10 * HZ))) {
> -				lbs_pr_err("host_sleep_q: timer expired\n");
> +				pr_err("host_sleep_q: timer expired\n");
>  				ret = -1;
>  			}
>  		} else {
> -			lbs_pr_err("host sleep: already enabled\n");
> +			pr_err("host sleep: already enabled\n");
>  		}
>  	} else {
>  		if (priv->is_host_sleep_activated)
> @@ -1002,7 +1003,7 @@ static void lbs_submit_command(struct lbs_private *priv,
>  	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
>  
>  	if (ret) {
> -		lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
> +		pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
>  		/* Let the timer kick in and retry, and potentially reset
>  		   the whole thing if the condition persists */
>  		timeo = HZ/4;
> @@ -1267,7 +1268,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
>  	spin_lock_irqsave(&priv->driver_lock, flags);
>  
>  	if (priv->cur_cmd) {
> -		lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
> +		pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
>  		spin_unlock_irqrestore(&priv->driver_lock, flags);
>  		ret = -1;
>  		goto done;
> @@ -1429,7 +1430,7 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)
>  	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
>  		sizeof(confirm_sleep));
>  	if (ret) {
> -		lbs_pr_alert("confirm_sleep failed\n");
> +		pr_alert("confirm_sleep failed\n");
>  		goto out;
>  	}
>  
> @@ -1655,8 +1656,7 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command,
>  	spin_lock_irqsave(&priv->driver_lock, flags);
>  	ret = cmdnode->result;
>  	if (ret)
> -		lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
> -			    command, ret);
> +		pr_info("PREP_CMD: command 0x%04x failed: %d\n", command, ret);
>  
>  	__lbs_cleanup_and_insert_cmd(priv, cmdnode);
>  	spin_unlock_irqrestore(&priv->driver_lock, flags);
> diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
> index 5e95da9..2cb6f5f 100644
> --- a/drivers/net/wireless/libertas/cmdresp.c
> +++ b/drivers/net/wireless/libertas/cmdresp.c
> @@ -2,6 +2,9 @@
>    * This file contains the handling of command
>    * responses as well as events generated by firmware.
>    */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
>  #include <linux/slab.h>
>  #include <linux/delay.h>
>  #include <linux/sched.h>
> @@ -84,15 +87,17 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
>  	lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
>  
>  	if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
> -		lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
> -			    le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
> +		pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
> +			le16_to_cpu(resp->seqnum),
> +			le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
>  		spin_unlock_irqrestore(&priv->driver_lock, flags);
>  		ret = -1;
>  		goto done;
>  	}
>  	if (respcmd != CMD_RET(curcmd) &&
>  	    respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
> -		lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
> +		pr_info("Invalid CMD_RESP %x to command %x!\n",
> +			respcmd, curcmd);
>  		spin_unlock_irqrestore(&priv->driver_lock, flags);
>  		ret = -1;
>  		goto done;
> @@ -101,8 +106,8 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
>  	if (resp->result == cpu_to_le16(0x0004)) {
>  		/* 0x0004 means -EAGAIN. Drop the response, let it time out
>  		   and be resubmitted */
> -		lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
> -			    le16_to_cpu(resp->command));
> +		pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
> +			le16_to_cpu(resp->command));
>  		spin_unlock_irqrestore(&priv->driver_lock, flags);
>  		ret = -1;
>  		goto done;
> @@ -313,28 +318,28 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
>  		lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
>  		break;
>  	case MACREG_INT_CODE_RSSI_LOW:
> -		lbs_pr_alert("EVENT: rssi low\n");
> +		pr_alert("EVENT: rssi low\n");
>  		break;
>  	case MACREG_INT_CODE_SNR_LOW:
> -		lbs_pr_alert("EVENT: snr low\n");
> +		pr_alert("EVENT: snr low\n");
>  		break;
>  	case MACREG_INT_CODE_MAX_FAIL:
> -		lbs_pr_alert("EVENT: max fail\n");
> +		pr_alert("EVENT: max fail\n");
>  		break;
>  	case MACREG_INT_CODE_RSSI_HIGH:
> -		lbs_pr_alert("EVENT: rssi high\n");
> +		pr_alert("EVENT: rssi high\n");
>  		break;
>  	case MACREG_INT_CODE_SNR_HIGH:
> -		lbs_pr_alert("EVENT: snr high\n");
> +		pr_alert("EVENT: snr high\n");
>  		break;
>  
>  	case MACREG_INT_CODE_MESH_AUTO_STARTED:
>  		/* Ignore spurious autostart events */
> -		lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
> +		pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
>  		break;
>  
>  	default:
> -		lbs_pr_alert("EVENT: unknown event id %d\n", event);
> +		pr_alert("EVENT: unknown event id %d\n", event);
>  		break;
>  	}
>  
> diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
> index fbf3b033..c179094 100644
> --- a/drivers/net/wireless/libertas/debugfs.c
> +++ b/drivers/net/wireless/libertas/debugfs.c
> @@ -1,3 +1,5 @@
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
>  #include <linux/dcache.h>
>  #include <linux/debugfs.h>
>  #include <linux/delay.h>
> @@ -151,13 +153,13 @@ static ssize_t lbs_host_sleep_write(struct file *file,
>  		ret = lbs_set_host_sleep(priv, 0);
>  	else if (host_sleep == 1) {
>  		if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
> -			lbs_pr_info("wake parameters not configured");
> +			pr_info("wake parameters not configured\n");
>  			ret = -EINVAL;
>  			goto out_unlock;
>  		}
>  		ret = lbs_set_host_sleep(priv, 1);
>  	} else {
> -		lbs_pr_err("invalid option\n");
> +		pr_err("invalid option\n");
>  		ret = -EINVAL;
>  	}
>  
> diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
> index d00c728..c9b89b0 100644
> --- a/drivers/net/wireless/libertas/defs.h
> +++ b/drivers/net/wireless/libertas/defs.h
> @@ -89,13 +89,6 @@ do { if ((lbs_debug & (grp)) == (grp)) \
>  #define lbs_deb_spi(fmt, args...)       LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args)
>  #define lbs_deb_cfg80211(fmt, args...)  LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args)
>  
> -#define lbs_pr_info(format, args...) \
> -	printk(KERN_INFO DRV_NAME": " format, ## args)
> -#define lbs_pr_err(format, args...) \
> -	printk(KERN_ERR DRV_NAME": " format, ## args)
> -#define lbs_pr_alert(format, args...) \
> -	printk(KERN_ALERT DRV_NAME": " format, ## args)
> -
>  #ifdef DEBUG
>  static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
>  {
> diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
> index 8712cb2..eb88d9a 100644
> --- a/drivers/net/wireless/libertas/if_cs.c
> +++ b/drivers/net/wireless/libertas/if_cs.c
> @@ -21,6 +21,8 @@
>  
>  */
>  
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
>  #include <linux/module.h>
>  #include <linux/slab.h>
>  #include <linux/delay.h>
> @@ -361,7 +363,7 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
>  		if (status & IF_CS_BIT_COMMAND)
>  			break;
>  		if (++loops > 100) {
> -			lbs_pr_err("card not ready for commands\n");
> +			pr_err("card not ready for commands\n");
>  			goto done;
>  		}
>  		mdelay(1);
> @@ -431,14 +433,14 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
>  	/* is hardware ready? */
>  	status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
>  	if ((status & IF_CS_BIT_RESP) == 0) {
> -		lbs_pr_err("no cmd response in card\n");
> +		pr_err("no cmd response in card\n");
>  		*len = 0;
>  		goto out;
>  	}
>  
>  	*len = if_cs_read16(priv->card, IF_CS_RESP_LEN);
>  	if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
> -		lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
> +		pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
>  		goto out;
>  	}
>  
> @@ -472,7 +474,7 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
>  
>  	len = if_cs_read16(priv->card, IF_CS_READ_LEN);
>  	if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
> -		lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
> +		pr_err("card data buffer has invalid # of bytes (%d)\n", len);
>  		priv->dev->stats.rx_dropped++;
>  		goto dat_err;
>  	}
> @@ -644,8 +646,8 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
>  		ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
>  			IF_CS_BIT_COMMAND);
>  		if (ret < 0) {
> -			lbs_pr_err("can't download helper at 0x%x, ret %d\n",
> -				sent, ret);
> +			pr_err("can't download helper at 0x%x, ret %d\n",
> +			       sent, ret);
>  			goto done;
>  		}
>  
> @@ -675,7 +677,7 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
>  	ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
>  		IF_CS_SQ_HELPER_OK);
>  	if (ret < 0) {
> -		lbs_pr_err("helper firmware doesn't answer\n");
> +		pr_err("helper firmware doesn't answer\n");
>  		goto done;
>  	}
>  
> @@ -683,13 +685,13 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
>  		len = if_cs_read16(card, IF_CS_SQ_READ_LOW);
>  		if (len & 1) {
>  			retry++;
> -			lbs_pr_info("odd, need to retry this firmware block\n");
> +			pr_info("odd, need to retry this firmware block\n");
>  		} else {
>  			retry = 0;
>  		}
>  
>  		if (retry > 20) {
> -			lbs_pr_err("could not download firmware\n");
> +			pr_err("could not download firmware\n");
>  			ret = -ENODEV;
>  			goto done;
>  		}
> @@ -709,14 +711,14 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
>  		ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
>  			IF_CS_BIT_COMMAND);
>  		if (ret < 0) {
> -			lbs_pr_err("can't download firmware at 0x%x\n", sent);
> +			pr_err("can't download firmware at 0x%x\n", sent);
>  			goto done;
>  		}
>  	}
>  
>  	ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
>  	if (ret < 0)
> -		lbs_pr_err("firmware download failed\n");
> +		pr_err("firmware download failed\n");
>  
>  done:
>  	lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
> @@ -750,7 +752,7 @@ static int if_cs_host_to_card(struct lbs_private *priv,
>  		ret = if_cs_send_cmd(priv, buf, nb);
>  		break;
>  	default:
> -		lbs_pr_err("%s: unsupported type %d\n", __func__, type);
> +		pr_err("%s: unsupported type %d\n", __func__, type);
>  	}
>  
>  	lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
> @@ -779,7 +781,7 @@ static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
>  	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
>  
>  	if (p_dev->resource[1]->end) {
> -		lbs_pr_err("wrong CIS (check number of IO windows)\n");
> +		pr_err("wrong CIS (check number of IO windows)\n");
>  		return -ENODEV;
>  	}
>  
> @@ -800,7 +802,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
>  
>  	card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
>  	if (!card) {
> -		lbs_pr_err("error in kzalloc\n");
> +		pr_err("error in kzalloc\n");
>  		goto out;
>  	}
>  	card->p_dev = p_dev;
> @@ -809,7 +811,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
>  	p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
>  
>  	if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) {
> -		lbs_pr_err("error in pcmcia_loop_config\n");
> +		pr_err("error in pcmcia_loop_config\n");
>  		goto out1;
>  	}
>  
> @@ -825,14 +827,14 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
>  	card->iobase = ioport_map(p_dev->resource[0]->start,
>  				resource_size(p_dev->resource[0]));
>  	if (!card->iobase) {
> -		lbs_pr_err("error in ioport_map\n");
> +		pr_err("error in ioport_map\n");
>  		ret = -EIO;
>  		goto out1;
>  	}
>  
>  	ret = pcmcia_enable_device(p_dev);
>  	if (ret) {
> -		lbs_pr_err("error in pcmcia_enable_device\n");
> +		pr_err("error in pcmcia_enable_device\n");
>  		goto out2;
>  	}
>  
> @@ -847,8 +849,8 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
>  
>  	card->model = get_model(p_dev->manf_id, p_dev->card_id);
>  	if (card->model == MODEL_UNKNOWN) {
> -		lbs_pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
> -			   p_dev->manf_id, p_dev->card_id);
> +		pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
> +		       p_dev->manf_id, p_dev->card_id);
>  		goto out2;
>  	}
>  
> @@ -857,20 +859,20 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
>  	if (card->model == MODEL_8305) {
>  		card->align_regs = 1;
>  		if (prod_id < IF_CS_CF8305_B1_REV) {
> -			lbs_pr_err("8305 rev B0 and older are not supported\n");
> +			pr_err("8305 rev B0 and older are not supported\n");
>  			ret = -ENODEV;
>  			goto out2;
>  		}
>  	}
>  
>  	if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) {
> -		lbs_pr_err("8381 rev B2 and older are not supported\n");
> +		pr_err("8381 rev B2 and older are not supported\n");
>  		ret = -ENODEV;
>  		goto out2;
>  	}
>  
>  	if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) {
> -		lbs_pr_err("8385 rev B0 and older are not supported\n");
> +		pr_err("8385 rev B0 and older are not supported\n");
>  		ret = -ENODEV;
>  		goto out2;
>  	}
> @@ -878,7 +880,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
>  	ret = lbs_get_firmware(&p_dev->dev, NULL, NULL, card->model,
>  				&fw_table[0], &helper, &mainfw);
>  	if (ret) {
> -		lbs_pr_err("failed to find firmware (%d)\n", ret);
> +		pr_err("failed to find firmware (%d)\n", ret);
>  		goto out2;
>  	}
>  
> @@ -909,7 +911,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
>  	ret = request_irq(p_dev->irq, if_cs_interrupt,
>  		IRQF_SHARED, DRV_NAME, card);
>  	if (ret) {
> -		lbs_pr_err("error in request_irq\n");
> +		pr_err("error in request_irq\n");
>  		goto out3;
>  	}
>  
> @@ -920,7 +922,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
>  
>  	/* And finally bring the card up */
>  	if (lbs_start_card(priv) != 0) {
> -		lbs_pr_err("could not activate card\n");
> +		pr_err("could not activate card\n");
>  		goto out3;
>  	}
>  
> diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
> index b4de0ca..ab86779 100644
> --- a/drivers/net/wireless/libertas/if_sdio.c
> +++ b/drivers/net/wireless/libertas/if_sdio.c
> @@ -26,6 +26,8 @@
>   * if_sdio_card_to_host() to pad the data.
>   */
>  
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
>  #include <linux/kernel.h>
>  #include <linux/moduleparam.h>
>  #include <linux/slab.h>
> @@ -409,7 +411,7 @@ static int if_sdio_card_to_host(struct if_sdio_card *card)
>  
>  out:
>  	if (ret)
> -		lbs_pr_err("problem fetching packet from firmware\n");
> +		pr_err("problem fetching packet from firmware\n");
>  
>  	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
>  
> @@ -446,7 +448,7 @@ static void if_sdio_host_to_card_worker(struct work_struct *work)
>  		}
>  
>  		if (ret)
> -			lbs_pr_err("error %d sending packet to firmware\n", ret);
> +			pr_err("error %d sending packet to firmware\n", ret);
>  
>  		sdio_release_host(card->func);
>  
> @@ -555,7 +557,7 @@ release:
>  
>  out:
>  	if (ret)
> -		lbs_pr_err("failed to load helper firmware\n");
> +		pr_err("failed to load helper firmware\n");
>  
>  	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
>  	return ret;
> @@ -669,7 +671,7 @@ release:
>  
>  out:
>  	if (ret)
> -		lbs_pr_err("failed to load firmware\n");
> +		pr_err("failed to load firmware\n");
>  
>  	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
>  	return ret;
> @@ -723,7 +725,7 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
>  	ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name,
>  				card->model, &fw_table[0], &helper, &mainfw);
>  	if (ret) {
> -		lbs_pr_err("failed to find firmware (%d)\n", ret);
> +		pr_err("failed to find firmware (%d)\n", ret);
>  		goto out;
>  	}
>  
> @@ -849,7 +851,7 @@ static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
>  	ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
>  			lbs_cmd_copyback, (unsigned long) &cmd);
>  	if (ret)
> -		lbs_pr_err("DEEP_SLEEP cmd failed\n");
> +		pr_err("DEEP_SLEEP cmd failed\n");
>  
>  	mdelay(200);
>  	return ret;
> @@ -865,7 +867,7 @@ static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
>  
>  	sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
>  	if (ret)
> -		lbs_pr_err("sdio_writeb failed!\n");
> +		pr_err("sdio_writeb failed!\n");
>  
>  	sdio_release_host(card->func);
>  	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
> @@ -882,7 +884,7 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
>  
>  	sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
>  	if (ret)
> -		lbs_pr_err("sdio_writeb failed!\n");
> +		pr_err("sdio_writeb failed!\n");
>  
>  	sdio_release_host(card->func);
>  	lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
> @@ -961,7 +963,7 @@ static int if_sdio_probe(struct sdio_func *func,
>  	}
>  
>  	if (i == func->card->num_info) {
> -		lbs_pr_err("unable to identify card model\n");
> +		pr_err("unable to identify card model\n");
>  		return -ENODEV;
>  	}
>  
> @@ -995,7 +997,7 @@ static int if_sdio_probe(struct sdio_func *func,
>  			break;
>  	}
>  	if (i == ARRAY_SIZE(fw_table)) {
> -		lbs_pr_err("unknown card model 0x%x\n", card->model);
> +		pr_err("unknown card model 0x%x\n", card->model);
>  		ret = -ENODEV;
>  		goto free;
>  	}
> @@ -1101,7 +1103,7 @@ static int if_sdio_probe(struct sdio_func *func,
>  		lbs_deb_sdio("send function INIT command\n");
>  		if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
>  				lbs_cmd_copyback, (unsigned long) &cmd))
> -			lbs_pr_alert("CMD_FUNC_INIT cmd failed\n");
> +			pr_alert("CMD_FUNC_INIT cmd failed\n");
>  	}
>  
>  	ret = lbs_start_card(priv);
> @@ -1163,7 +1165,7 @@ static void if_sdio_remove(struct sdio_func *func)
>  		if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN,
>  				&cmd, sizeof(cmd), lbs_cmd_copyback,
>  				(unsigned long) &cmd))
> -			lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
> +			pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
>  	}
>  
> 
> @@ -1202,21 +1204,19 @@ static int if_sdio_suspend(struct device *dev)
>  
>  	mmc_pm_flag_t flags = sdio_get_host_pm_caps(func);
>  
> -	lbs_pr_info("%s: suspend: PM flags = 0x%x\n",
> -						sdio_func_id(func), flags);
> +	pr_info("%s: suspend: PM flags = 0x%x\n", sdio_func_id(func), flags);
>  
>  	/* If we aren't being asked to wake on anything, we should bail out
>  	 * and let the SD stack power down the card.
>  	 */
>  	if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) {
> -		lbs_pr_info("Suspend without wake params -- "
> -						"powering down card.");
> +		pr_info("Suspend without wake params -- powering down card\n");
>  		return -ENOSYS;
>  	}
>  
>  	if (!(flags & MMC_PM_KEEP_POWER)) {
> -		lbs_pr_err("%s: cannot remain alive while host is suspended\n",
> -			sdio_func_id(func));
> +		pr_err("%s: cannot remain alive while host is suspended\n",
> +		       sdio_func_id(func));
>  		return -ENOSYS;
>  	}
>  
> @@ -1237,7 +1237,7 @@ static int if_sdio_resume(struct device *dev)
>  	struct if_sdio_card *card = sdio_get_drvdata(func);
>  	int ret;
>  
> -	lbs_pr_info("%s: resume: we're back\n", sdio_func_id(func));
> +	pr_info("%s: resume: we're back\n", sdio_func_id(func));
>  
>  	ret = lbs_resume(card->priv);
>  
> diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
> index 078ef43..bebd9f0 100644
> --- a/drivers/net/wireless/libertas/if_spi.c
> +++ b/drivers/net/wireless/libertas/if_spi.c
> @@ -17,6 +17,8 @@
>   * (at your option) any later version.
>   */
>  
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
>  #include <linux/moduleparam.h>
>  #include <linux/firmware.h>
>  #include <linux/jiffies.h>
> @@ -297,8 +299,7 @@ static int spu_wait_for_u16(struct if_spi_card *card, u16 reg,
>  		}
>  		udelay(100);
>  		if (time_after(jiffies, timeout)) {
> -			lbs_pr_err("%s: timeout with val=%02x, "
> -			       "target_mask=%02x, target=%02x\n",
> +			pr_err("%s: timeout with val=%02x, target_mask=%02x, target=%02x\n",
>  			       __func__, val, target_mask, target);
>  			return -ETIMEDOUT;
>  		}
> @@ -391,7 +392,7 @@ static int spu_set_bus_mode(struct if_spi_card *card, u16 mode)
>  	if (err)
>  		return err;
>  	if ((rval & 0xF) != mode) {
> -		lbs_pr_err("Can't read bus mode register.\n");
> +		pr_err("Can't read bus mode register\n");
>  		return -EIO;
>  	}
>  	return 0;
> @@ -512,7 +513,7 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
>  
>  out:
>  	if (err)
> -		lbs_pr_err("failed to load helper firmware (err=%d)\n", err);
> +		pr_err("failed to load helper firmware (err=%d)\n", err);
>  	lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
>  	return err;
>  }
> @@ -531,7 +532,7 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
>  				IF_SPI_HIST_CMD_DOWNLOAD_RDY,
>  				IF_SPI_HIST_CMD_DOWNLOAD_RDY);
>  	if (err) {
> -		lbs_pr_err("timed out waiting for host_int_status\n");
> +		pr_err("timed out waiting for host_int_status\n");
>  		return err;
>  	}
>  
> @@ -541,9 +542,8 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
>  		return err;
>  
>  	if (len > IF_SPI_CMD_BUF_SIZE) {
> -		lbs_pr_err("firmware load device requested a larger "
> -			   "tranfer than we are prepared to "
> -			   "handle. (len = %d)\n", len);
> +		pr_err("firmware load device requested a larger transfer than we are prepared to handle (len = %d)\n",
> +		       len);
>  		return -EIO;
>  	}
>  	if (len & 0x1) {
> @@ -572,8 +572,8 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card,
>  
>  	err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0);
>  	if (err) {
> -		lbs_pr_err("%s: timed out waiting for initial "
> -			   "scratch reg = 0\n", __func__);
> +		pr_err("%s: timed out waiting for initial scratch reg = 0\n",
> +		       __func__);
>  		goto out;
>  	}
>  
> @@ -589,15 +589,13 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card,
>  		if (bytes < 0) {
>  			/* If there are no more bytes left, we would normally
>  			 * expect to have terminated with len = 0 */
> -			lbs_pr_err("Firmware load wants more bytes "
> -				   "than we have to offer.\n");
> +			pr_err("Firmware load wants more bytes than we have to offer\n");
>  			break;
>  		}
>  		if (crc_err) {
>  			/* Previous transfer failed. */
>  			if (++num_crc_errs > MAX_MAIN_FW_LOAD_CRC_ERR) {
> -				lbs_pr_err("Too many CRC errors encountered "
> -					   "in firmware load.\n");
> +				pr_err("Too many CRC errors encountered in firmware load\n");
>  				err = -EIO;
>  				goto out;
>  			}
> @@ -626,21 +624,20 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card,
>  		prev_len = len;
>  	}
>  	if (bytes > prev_len) {
> -		lbs_pr_err("firmware load wants fewer bytes than "
> -			   "we have to offer.\n");
> +		pr_err("firmware load wants fewer bytes than we have to offer\n");
>  	}
>  
>  	/* Confirm firmware download */
>  	err = spu_wait_for_u32(card, IF_SPI_SCRATCH_4_REG,
>  					SUCCESSFUL_FW_DOWNLOAD_MAGIC);
>  	if (err) {
> -		lbs_pr_err("failed to confirm the firmware download\n");
> +		pr_err("failed to confirm the firmware download\n");
>  		goto out;
>  	}
>  
>  out:
>  	if (err)
> -		lbs_pr_err("failed to load firmware (err=%d)\n", err);
> +		pr_err("failed to load firmware (err=%d)\n", err);
>  	lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
>  	return err;
>  }
> @@ -677,14 +674,12 @@ static int if_spi_c2h_cmd(struct if_spi_card *card)
>  	if (err)
>  		goto out;
>  	if (!len) {
> -		lbs_pr_err("%s: error: card has no data for host\n",
> -			   __func__);
> +		pr_err("%s: error: card has no data for host\n", __func__);
>  		err = -EINVAL;
>  		goto out;
>  	} else if (len > IF_SPI_CMD_BUF_SIZE) {
> -		lbs_pr_err("%s: error: response packet too large: "
> -			   "%d bytes, but maximum is %d\n",
> -			   __func__, len, IF_SPI_CMD_BUF_SIZE);
> +		pr_err("%s: error: response packet too large: %d bytes, but maximum is %d\n",
> +		       __func__, len, IF_SPI_CMD_BUF_SIZE);
>  		err = -EINVAL;
>  		goto out;
>  	}
> @@ -705,7 +700,7 @@ static int if_spi_c2h_cmd(struct if_spi_card *card)
>  
>  out:
>  	if (err)
> -		lbs_pr_err("%s: err=%d\n", __func__, err);
> +		pr_err("%s: err=%d\n", __func__, err);
>  	lbs_deb_leave(LBS_DEB_SPI);
>  	return err;
>  }
> @@ -725,14 +720,12 @@ static int if_spi_c2h_data(struct if_spi_card *card)
>  	if (err)
>  		goto out;
>  	if (!len) {
> -		lbs_pr_err("%s: error: card has no data for host\n",
> -			   __func__);
> +		pr_err("%s: error: card has no data for host\n", __func__);
>  		err = -EINVAL;
>  		goto out;
>  	} else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
> -		lbs_pr_err("%s: error: card has %d bytes of data, but "
> -			   "our maximum skb size is %zu\n",
> -			   __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
> +		pr_err("%s: error: card has %d bytes of data, but our maximum skb size is %zu\n",
> +		       __func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
>  		err = -EINVAL;
>  		goto out;
>  	}
> @@ -763,7 +756,7 @@ free_skb:
>  	dev_kfree_skb(skb);
>  out:
>  	if (err)
> -		lbs_pr_err("%s: err=%d\n", __func__, err);
> +		pr_err("%s: err=%d\n", __func__, err);
>  	lbs_deb_leave(LBS_DEB_SPI);
>  	return err;
>  }
> @@ -785,7 +778,7 @@ static void if_spi_h2c(struct if_spi_card *card,
>  		port_reg = IF_SPI_CMD_RDWRPORT_REG;
>  		break;
>  	default:
> -		lbs_pr_err("can't transfer buffer of type %d\n", type);
> +		pr_err("can't transfer buffer of type %d\n", type);
>  		err = -EINVAL;
>  		goto out;
>  	}
> @@ -799,7 +792,7 @@ out:
>  	kfree(packet);
>  
>  	if (err)
> -		lbs_pr_err("%s: error %d\n", __func__, err);
> +		pr_err("%s: error %d\n", __func__, err);
>  }
>  
>  /* Inform the host about a card event */
> @@ -823,7 +816,7 @@ static void if_spi_e2h(struct if_spi_card *card)
>  	lbs_queue_event(priv, cause & 0xff);
>  out:
>  	if (err)
> -		lbs_pr_err("%s: error %d\n", __func__, err);
> +		pr_err("%s: error %d\n", __func__, err);
>  }
>  
>  static void if_spi_host_to_card_worker(struct work_struct *work)
> @@ -843,7 +836,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work)
>  	err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG,
>  				&hiStatus);
>  	if (err) {
> -		lbs_pr_err("I/O error\n");
> +		pr_err("I/O error\n");
>  		goto err;
>  	}
>  
> @@ -905,7 +898,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work)
>  
>  err:
>  	if (err)
> -		lbs_pr_err("%s: got error %d\n", __func__, err);
> +		pr_err("%s: got error %d\n", __func__, err);
>  
>  	lbs_deb_leave(LBS_DEB_SPI);
>  }
> @@ -927,7 +920,7 @@ static int if_spi_host_to_card(struct lbs_private *priv,
>  	lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb);
>  
>  	if (nb == 0) {
> -		lbs_pr_err("%s: invalid size requested: %d\n", __func__, nb);
> +		pr_err("%s: invalid size requested: %d\n", __func__, nb);
>  		err = -EINVAL;
>  		goto out;
>  	}
> @@ -955,7 +948,7 @@ static int if_spi_host_to_card(struct lbs_private *priv,
>  		spin_unlock_irqrestore(&card->buffer_lock, flags);
>  		break;
>  	default:
> -		lbs_pr_err("can't transfer buffer of type %d", type);
> +		pr_err("can't transfer buffer of type %d\n", type);
>  		err = -EINVAL;
>  		break;
>  	}
> @@ -1016,8 +1009,7 @@ static int if_spi_init_card(struct if_spi_card *card)
>  				break;
>  		}
>  		if (i == ARRAY_SIZE(fw_table)) {
> -			lbs_pr_err("Unsupported chip_id: 0x%02x\n",
> -					card->card_id);
> +			pr_err("Unsupported chip_id: 0x%02x\n", card->card_id);
>  			err = -ENODEV;
>  			goto out;
>  		}
> @@ -1026,7 +1018,7 @@ static int if_spi_init_card(struct if_spi_card *card)
>  					card->card_id, &fw_table[0], &helper,
>  					&mainfw);
>  		if (err) {
> -			lbs_pr_err("failed to find firmware (%d)\n", err);
> +			pr_err("failed to find firmware (%d)\n", err);
>  			goto out;
>  		}
>  
> @@ -1149,7 +1141,7 @@ static int __devinit if_spi_probe(struct spi_device *spi)
>  	err = request_irq(spi->irq, if_spi_host_interrupt,
>  			IRQF_TRIGGER_FALLING, "libertas_spi", card);
>  	if (err) {
> -		lbs_pr_err("can't get host irq line-- request_irq failed\n");
> +		pr_err("can't get host irq line-- request_irq failed\n");
>  		goto terminate_workqueue;
>  	}
>  
> diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
> index 6524c70..7260791 100644
> --- a/drivers/net/wireless/libertas/if_usb.c
> +++ b/drivers/net/wireless/libertas/if_usb.c
> @@ -1,6 +1,9 @@
>  /**
>    * This file contains functions used in USB interface module.
>    */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
>  #include <linux/delay.h>
>  #include <linux/moduleparam.h>
>  #include <linux/firmware.h>
> @@ -145,7 +148,7 @@ static void if_usb_write_bulk_callback(struct urb *urb)
>  			lbs_host_to_card_done(priv);
>  	} else {
>  		/* print the failure status number for debug */
> -		lbs_pr_info("URB in failure status: %d\n", urb->status);
> +		pr_info("URB in failure status: %d\n", urb->status);
>  	}
>  }
>  
> @@ -195,7 +198,7 @@ static void if_usb_setup_firmware(struct lbs_private *priv)
>  	wake_method.hdr.size = cpu_to_le16(sizeof(wake_method));
>  	wake_method.action = cpu_to_le16(CMD_ACT_GET);
>  	if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
> -		lbs_pr_info("Firmware does not seem to support PS mode\n");
> +		pr_info("Firmware does not seem to support PS mode\n");
>  		priv->fwcapinfo &= ~FW_CAPINFO_PS;
>  	} else {
>  		if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
> @@ -204,7 +207,7 @@ static void if_usb_setup_firmware(struct lbs_private *priv)
>  			/* The versions which boot up this way don't seem to
>  			   work even if we set it to the command interrupt */
>  			priv->fwcapinfo &= ~FW_CAPINFO_PS;
> -			lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
> +			pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
>  		}
>  	}
>  }
> @@ -216,7 +219,7 @@ static void if_usb_fw_timeo(unsigned long priv)
>  	if (cardp->fwdnldover) {
>  		lbs_deb_usb("Download complete, no event. Assuming success\n");
>  	} else {
> -		lbs_pr_err("Download timed out\n");
> +		pr_err("Download timed out\n");
>  		cardp->surprise_removed = 1;
>  	}
>  	wake_up(&cardp->fw_wq);
> @@ -250,7 +253,7 @@ static int if_usb_probe(struct usb_interface *intf,
>  
>  	cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
>  	if (!cardp) {
> -		lbs_pr_err("Out of memory allocating private data.\n");
> +		pr_err("Out of memory allocating private data\n");
>  		goto error;
>  	}
>  
> @@ -340,10 +343,10 @@ static int if_usb_probe(struct usb_interface *intf,
>  	usb_set_intfdata(intf, cardp);
>  
>  	if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_fw))
> -		lbs_pr_err("cannot register lbs_flash_fw attribute\n");
> +		pr_err("cannot register lbs_flash_fw attribute\n");
>  
>  	if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2))
> -		lbs_pr_err("cannot register lbs_flash_boot2 attribute\n");
> +		pr_err("cannot register lbs_flash_boot2 attribute\n");
>  
>  	/*
>  	 * EHS_REMOVE_WAKEUP is not supported on all versions of the firmware.
> @@ -528,7 +531,7 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
>  	int ret = -1;
>  
>  	if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
> -		lbs_pr_err("No free skb\n");
> +		pr_err("No free skb\n");
>  		goto rx_ret;
>  	}
>  
> @@ -587,7 +590,7 @@ static void if_usb_receive_fwload(struct urb *urb)
>  
>  		if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
>  		    tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) {
> -			lbs_pr_info("Firmware ready event received\n");
> +			pr_info("Firmware ready event received\n");
>  			wake_up(&cardp->fw_wq);
>  		} else {
>  			lbs_deb_usb("Waiting for confirmation; got %x %x\n",
> @@ -614,20 +617,20 @@ static void if_usb_receive_fwload(struct urb *urb)
>  			    bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
>  			    bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
>  				if (!cardp->bootcmdresp)
> -					lbs_pr_info("Firmware already seems alive; resetting\n");
> +					pr_info("Firmware already seems alive; resetting\n");
>  				cardp->bootcmdresp = -1;
>  			} else {
> -				lbs_pr_info("boot cmd response wrong magic number (0x%x)\n",
> +				pr_info("boot cmd response wrong magic number (0x%x)\n",
>  					    le32_to_cpu(bootcmdresp.magic));
>  			}
>  		} else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) &&
>  			   (bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) &&
>  			   (bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) {
> -			lbs_pr_info("boot cmd response cmd_tag error (%d)\n",
> -				    bootcmdresp.cmd);
> +			pr_info("boot cmd response cmd_tag error (%d)\n",
> +				bootcmdresp.cmd);
>  		} else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
> -			lbs_pr_info("boot cmd response result error (%d)\n",
> -				    bootcmdresp.result);
> +			pr_info("boot cmd response result error (%d)\n",
> +				bootcmdresp.result);
>  		} else {
>  			cardp->bootcmdresp = 1;
>  			lbs_deb_usbd(&cardp->udev->dev,
> @@ -892,7 +895,7 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
>  	} while (!exit);
>  
>  	if (ret)
> -		lbs_pr_err("firmware file format check FAIL\n");
> +		pr_err("firmware file format check FAIL\n");
>  	else
>  		lbs_deb_fw("firmware file format check PASS\n");
>  
> @@ -989,7 +992,7 @@ static int __if_usb_prog_firmware(struct if_usb_card *cardp,
>  
>  	ret = get_fw(cardp, fwname);
>  	if (ret) {
> -		lbs_pr_err("failed to find firmware (%d)\n", ret);
> +		pr_err("failed to find firmware (%d)\n", ret);
>  		goto done;
>  	}
>  
> @@ -1064,13 +1067,13 @@ restart:
>  	usb_kill_urb(cardp->rx_urb);
>  
>  	if (!cardp->fwdnldover) {
> -		lbs_pr_info("failed to load fw, resetting device!\n");
> +		pr_info("failed to load fw, resetting device!\n");
>  		if (--reset_count >= 0) {
>  			if_usb_reset_device(cardp);
>  			goto restart;
>  		}
>  
> -		lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
> +		pr_info("FW download failure, time = %d ms\n", i * 100);
>  		ret = -EIO;
>  		goto release_fw;
>  	}
> diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
> index ca8149c..639461b 100644
> --- a/drivers/net/wireless/libertas/main.c
> +++ b/drivers/net/wireless/libertas/main.c
> @@ -4,6 +4,8 @@
>    * thread etc..
>    */
>  
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
>  #include <linux/moduleparam.h>
>  #include <linux/delay.h>
>  #include <linux/etherdevice.h>
> @@ -153,7 +155,7 @@ static void lbs_tx_timeout(struct net_device *dev)
>  
>  	lbs_deb_enter(LBS_DEB_TX);
>  
> -	lbs_pr_err("tx watch dog timeout\n");
> +	pr_err("tx watch dog timeout\n");
>  
>  	dev->trans_start = jiffies; /* prevent tx timeout */
>  
> @@ -462,7 +464,7 @@ static int lbs_thread(void *data)
>  		if (priv->cmd_timed_out && priv->cur_cmd) {
>  			struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
>  
> -			lbs_pr_info("Timeout submitting command 0x%04x\n",
> +			pr_info("Timeout submitting command 0x%04x\n",
>  				le16_to_cpu(cmdnode->cmdbuf->command));
>  			lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
>  			if (priv->reset_card)
> @@ -490,8 +492,7 @@ static int lbs_thread(void *data)
>  				 * after firmware fixes it
>  				 */
>  				priv->psstate = PS_STATE_AWAKE;
> -				lbs_pr_alert("ignore PS_SleepConfirm in "
> -					"non-connected state\n");
> +				pr_alert("ignore PS_SleepConfirm in non-connected state\n");
>  			}
>  		}
>  
> @@ -585,7 +586,7 @@ int lbs_suspend(struct lbs_private *priv)
>  	if (priv->is_deep_sleep) {
>  		ret = lbs_set_deep_sleep(priv, 0);
>  		if (ret) {
> -			lbs_pr_err("deep sleep cancellation failed: %d\n", ret);
> +			pr_err("deep sleep cancellation failed: %d\n", ret);
>  			return ret;
>  		}
>  		priv->deep_sleep_required = 1;
> @@ -618,7 +619,7 @@ int lbs_resume(struct lbs_private *priv)
>  		priv->deep_sleep_required = 0;
>  		ret = lbs_set_deep_sleep(priv, 1);
>  		if (ret)
> -			lbs_pr_err("deep sleep activation failed: %d\n", ret);
> +			pr_err("deep sleep activation failed: %d\n", ret);
>  	}
>  
>  	if (priv->setup_fw_on_resume)
> @@ -644,7 +645,7 @@ static void lbs_cmd_timeout_handler(unsigned long data)
>  	if (!priv->cur_cmd)
>  		goto out;
>  
> -	lbs_pr_info("command 0x%04x timed out\n",
> +	pr_info("command 0x%04x timed out\n",
>  		le16_to_cpu(priv->cur_cmd->cmdbuf->command));
>  
>  	priv->cmd_timed_out = 1;
> @@ -748,7 +749,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
>  
>  	/* Allocate the command buffers */
>  	if (lbs_allocate_cmd_buffer(priv)) {
> -		lbs_pr_err("Out of memory allocating command buffers\n");
> +		pr_err("Out of memory allocating command buffers\n");
>  		ret = -ENOMEM;
>  		goto out;
>  	}
> @@ -758,7 +759,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
>  	/* Create the event FIFO */
>  	ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL);
>  	if (ret) {
> -		lbs_pr_err("Out of memory allocating event FIFO buffer\n");
> +		pr_err("Out of memory allocating event FIFO buffer\n");
>  		goto out;
>  	}
>  
> @@ -809,7 +810,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
>  	/* Allocate an Ethernet device and register it */
>  	wdev = lbs_cfg_alloc(dmdev);
>  	if (IS_ERR(wdev)) {
> -		lbs_pr_err("cfg80211 init failed\n");
> +		pr_err("cfg80211 init failed\n");
>  		goto done;
>  	}
>  
> @@ -818,7 +819,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
>  	priv->wdev = wdev;
>  
>  	if (lbs_init_adapter(priv)) {
> -		lbs_pr_err("failed to initialize adapter structure.\n");
> +		pr_err("failed to initialize adapter structure\n");
>  		goto err_wdev;
>  	}
>  
> @@ -950,7 +951,7 @@ int lbs_start_card(struct lbs_private *priv)
>  		goto done;
>  
>  	if (lbs_cfg_register(priv)) {
> -		lbs_pr_err("cannot register device\n");
> +		pr_err("cannot register device\n");
>  		goto done;
>  	}
>  
> @@ -960,7 +961,7 @@ int lbs_start_card(struct lbs_private *priv)
>  
>  	lbs_debugfs_init_one(priv, dev);
>  
> -	lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
> +	pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
>  
>  	ret = 0;
>  
> @@ -1087,16 +1088,14 @@ int lbs_get_firmware(struct device *dev, const char *user_helper,
>  	if (user_helper) {
>  		ret = request_firmware(helper, user_helper, dev);
>  		if (ret) {
> -			lbs_pr_err("couldn't find helper firmware %s",
> -					user_helper);
> +			pr_err("couldn't find helper firmware %s", user_helper);
>  			goto fail;
>  		}
>  	}
>  	if (user_mainfw) {
>  		ret = request_firmware(mainfw, user_mainfw, dev);
>  		if (ret) {
> -			lbs_pr_err("couldn't find main firmware %s",
> -					user_mainfw);
> +			pr_err("couldn't find main firmware %s", user_mainfw);
>  			goto fail;
>  		}
>  	}
> diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
> index 9d097b9..f7c51cb 100644
> --- a/drivers/net/wireless/libertas/mesh.c
> +++ b/drivers/net/wireless/libertas/mesh.c
> @@ -1,3 +1,5 @@
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
>  #include <linux/delay.h>
>  #include <linux/etherdevice.h>
>  #include <linux/netdevice.h>
> @@ -246,7 +248,7 @@ int lbs_init_mesh(struct lbs_private *priv)
>  		lbs_add_mesh(priv);
>  
>  		if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
> -			lbs_pr_err("cannot register lbs_mesh attribute\n");
> +			pr_err("cannot register lbs_mesh attribute\n");
>  
>  		ret = 1;
>  	}
> @@ -374,7 +376,7 @@ int lbs_add_mesh(struct lbs_private *priv)
>  	/* Register virtual mesh interface */
>  	ret = register_netdev(mesh_dev);
>  	if (ret) {
> -		lbs_pr_err("cannot register mshX virtual interface\n");
> +		pr_err("cannot register mshX virtual interface\n");
>  		goto err_free;
>  	}
>  
> @@ -926,7 +928,7 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
>  		return ret;
>  
>  	if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
> -		lbs_pr_err("inconsistent mesh ID length");
> +		pr_err("inconsistent mesh ID length\n");
>  		defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
>  	}
>  
> diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
> index a2b1df2..fd045aa 100644
> --- a/drivers/net/wireless/libertas/rx.c
> +++ b/drivers/net/wireless/libertas/rx.c
> @@ -1,6 +1,9 @@
>  /**
>    * This file contains the handling of RX in wlan driver.
>    */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
>  #include <linux/etherdevice.h>
>  #include <linux/slab.h>
>  #include <linux/types.h>
> @@ -191,7 +194,7 @@ static u8 convert_mv_rate_to_radiotap(u8 rate)
>  	case 12:		/*  54 Mbps */
>  		return 108;
>  	}
> -	lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate);
> +	pr_alert("Invalid Marvell WLAN rate %i\n", rate);
>  	return 0;
>  }
>  
> @@ -248,7 +251,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
>  	/* add space for the new radio header */
>  	if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
>  	    pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) {
> -		lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__);
> +		pr_alert("%s: couldn't pskb_expand_head\n", __func__);
>  		ret = -ENOMEM;
>  		kfree_skb(skb);
>  		goto done;


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: Divide error in bictcp_cong_avoid ?
From: David Miller @ 2011-05-04 19:40 UTC (permalink / raw)
  To: shemminger; +Cc: Valdis.Kletnieks, rdunlap, lkml, netdev, linux-kernel
In-Reply-To: <20110504123738.7bb4d1ee@nehalam>

From: Stephen Hemminger <shemminger@vyatta.com>
Date: Wed, 4 May 2011 12:37:38 -0700

> Don't use BIC, it is known to be unfair between flows.

That doesn't fix the user's bug, nothing in the kernel should causes
crashes under normal circumstances.

Please stop with this deflecting on this report and instead try to
figure out why the illegal divide happens.

Thanks.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox