Project import generated by Copybara.

GitOrigin-RevId: 1580025a683159450153d0209163d160594c5dc9
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c4df588
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,32 @@
+*.o
+
+Makefile
+Makefile.in
+
+INSTALL
+missing
+depcomp
+install-sh
+compile
+ethtool-config.h*
+ethtool.spec
+ethtool.8
+ethtool
+test-cmdline
+test-driver
+test-features
+stamp-h1
+config.*
+aclocal.m4
+configure
+*.tar.gz
+push
+
+.dotest
+autom4te.cache
+.deps
+test-*.log
+test-*.trs
+
+.*.swp
+*.patch
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e1f0715
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,9 @@
+David Miller <davem@redhat.com>
+Jakub Jelinek <jj@ultra.linux.cz>
+Jeff Garzik <jgarzik@pobox.com>
+Tim Hockin <thockin@sun.com>
+Eli Kupermann <eli.kupermann@intel.com>
+Chris Leech <christopher.leech@intel.com>
+Scott Feldman <scott.feldman@intel.com>
+Andi Kleen
+Ben Hutchings <ben@decadent.org.uk>
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..6bbb05d
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,44 @@
+cc_binary {
+    name: "ethtool",
+    srcs: [
+        "amd8111e.c",
+        "at76c50x-usb.c",
+        "de2104x.c",
+        "dsa.c",
+        "e100.c",
+        "e1000.c",
+        "et131x.c",
+        "ethtool.c",
+        "fec.c",
+        "fec_8xx.c",
+        "fjes.c",
+        "ibm_emac.c",
+        "igb.c",
+        "ixgb.c",
+        "ixgbe.c",
+        "ixgbevf.c",
+        "lan78xx.c",
+        "marvell.c",
+        "natsemi.c",
+        "pcnet32.c",
+        "qsfp.c",
+        "realtek.c",
+        "rxclass.c",
+        "sfc.c",
+        "sff-common.c",
+        "sfpdiag.c",
+        "sfpid.c",
+        "smsc911x.c",
+        "stmmac.c",
+        "tg3.c",
+        "tse.c",
+        "vioc.c",
+        "vmxnet3.c",
+    ],
+    cflags: [
+        "-Wno-missing-field-initializers",
+        "-DPACKAGE=\"ethtool\"",
+        "-DVERSION=\"5.3\"",
+        "-std=gnu11",
+    ]
+}
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..3a40fc2
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,52 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := ethtool
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES :=\
+        amd8111e.c \
+        at76c50x-usb.c \
+        de2104x.c \
+        dsa.c \
+        e100.c \
+        e1000.c \
+        et131x.c \
+        ethtool.c \
+        fec.c \
+        fec_8xx.c \
+        fjes.c \
+        ibm_emac.c \
+        igb.c \
+        ixgb.c \
+        ixgbe.c \
+        ixgbevf.c \
+        lan78xx.c \
+        marvell.c \
+        natsemi.c \
+        pcnet32.c \
+        qsfp.c \
+        realtek.c \
+        rxclass.c \
+        sfc.c \
+        sff-common.c \
+        sfpdiag.c \
+        sfpid.c \
+        smsc911x.c \
+        stmmac.c \
+        tg3.c \
+        tse.c \
+        vioc.c \
+        vmxnet3.c
+
+LOCAL_CFLAGS :=\
+        -Wno-missing-field-initializers \
+        -DPACKAGE=\"ethtool\" \
+        -DVERSION=\"5.3\" \
+        -std=gnu11
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+
+include $(BUILD_EXECUTABLE)
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..1fd043e
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,353 @@
+The changelog after March 2005 can be obtained from the git repository
+at <git://git.kernel.org/pub/scm/network/ethtool/ethtool.git>.
+
+The changelog after version 2 up to March 2005 can be obtained from the
+BitKeeper repository at <bk://gkernel.bkbits.net/ethtool>.
+
+
+Tue Aug 17 2004  Jeff Garzik <jgarzik@pobox.com>
+
+	* NEWS, configure.ac:  Release version 2
+
+Fri Jul  2 2004  Jeff Garzik <jgarzik@pobox.com>
+
+	Merged
+	* fec_8xx.c, ethtool-util.h, Makefile.am: Add fec_8xx register dump.
+	Contributed by Pantelis Antoniou <panto@intracom.gr>
+
+	* Update ethtool.c to iterate through a list of drivers
+	* Fixed fec_8xx.c warnings on 64-bit
+
+Fri Jul  2 2004  Jim Lewis <jim@jklewis.com>
+
+	* pcnet32.c, ethtool-util.h, Makefile.am: Add pcnet32 register dump.
+
+Fri Apr  9 2004  Jason Lunz <lunz@reflexsecurity.com>
+
+	* ethtool.c: Remove incorrect restriction on ethernet interface
+	names.
+
+Fri Apr  9 2004  OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
+
+	* ethtool.c: This fixes the bogus tail backslash that I did.
+
+Fri Apr  9 2004  Jim Lewis <jim@jklewis.com>
+
+	* ethtool.c:  Return results of self-test back to OS,
+	via exit(2).
+
+Fri Apr  9 2004  Jeb Cramer  <cramerj@intel.com>
+
+	* e1000.c: Update device id list and add printout of phy type in
+	register dump.  Set default mac_type to 82543 since register offsets
+	haven't changed.
+
+Fri Apr  9 2004  Jeff Garzik  <jgarzik@pobox.com>
+
+	* configure.ac, Makefile.am, ethtool.c, etc.:
+	convert to more recent autoconf.
+
+Sat Aug 30 2003  OGAWA Hirofumi  <hirofumi@mail.parknet.co.jp>
+
+	* ethtool.8, ethtool.c: ethtool register dump raw mode
+
+Sat Jul 19 2003  Scott Feldman  <scott.feldman@intel.com>
+
+	* ethtool.8, ethtool.c, ethtool-copy.h:
+	Add support for TSO get/set.  Corresponds to NETIF_F_TSO.
+	Extended -k|K option to included tso, and changed meaning from
+	just "checksum/sg" to more general "offload".  Now covers Rx/Tx
+	csum, SG, and TSO.
+
+Thu May 28 2003  Ganesh Venkatesan  <ganesh.venkatesan@intel.com>
+
+	* ethtool-copy.h: new definitions for 10GbE
+
+Thu May 28 2003  Scott Feldman  <scott.feldman@intel.com>
+
+	* ethtool.c: Add ethtool -E to write EEPROM byte.
+	* e100.c: Added MDI/MDI-X status to register dump.
+
+Thu May 28 2003   Reeja John  <reeja.john@amd.com>
+
+	* amd8111e.c: new file, support for AMD-8111e NICs
+	* ethtool.c: properly set ecmd.advertising
+
+Sat Mar 29 2003   OGAWA Hirofumi  <hirofumi@mail.parknet.co.jp>
+
+	* realtek.c: clean up chip enumeration, support additional chips
+
+Fri Mar 28 2003   Jeb Cramer  <cramerj@intel.com>
+
+	* e1000.c: Update supported devices (82541 & 82547).  Add bus type,
+	speed and width to register dump printout.
+	* ethtool.c (show_usage): Add -S to printout of supported commands.
+
+Tue Jan 22 2003   Jeff Garzik  <jgarzik@pobox.com>
+
+	* natsemi.c (PRINT_INTR, __print_intr): Decompose PRINT_INTR
+	macro into macro abuse and function call portions.  Move the
+	actual function body to new static functoin __print_intr.
+
+	This eliminates the annoying build warning :)
+
+Thu Jan 16 2003   Jeb Cramer  <jeb.j.cramer@intel.com>
+
+	* ethtool.c (do_regs, dump_eeprom): Fix memory leaks on failed
+	operations.  Add error handling of dump_regs().  Modify printout of
+	eeprom dump to accomodate larger eeproms.
+	* e1000.c: Update supported devices.  Add error conditions for
+	unsupported devices.
+
+Mon Oct 21 2002   Ben Collins  <bcollins@debian.org>
+
+	* ethtool.c: Add new parameters to -e, for raw EEPROM output, and
+	offset and length options.
+	* natsemi.c (natsemi_dump_eeprom): Show correct offset using new
+	offset feature above.
+	* tg3.c: New file, implements tg3_dump_eeprom.
+	* Makefile.am: Add it to the build sources.
+	* ethtool-util.h: Prototype tg3_dump_eeprom.
+	* ethtool.8: Document new -e options.
+
+Thu Oct 17 2002   Tim Hockin  <thockin@sun.com>
+
+	* ethtool.c: make calls to strtol() use base 0
+
+Wed Sep 18 2002   Scott Feldman  <scott.feldman@intel.com>
+
+	* ethtool.c (dump_regs): call e100_dump_regs if e100
+	* e100.c: new file
+	* ethtool-util.h: prototype e100_dump_regs
+
+Thu Jun 20 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool.8: document new -S stats dump argument
+	* configure.in, NEWS: release version 1.6
+
+Fri Jun 14 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* realtek.c (realtek_dump_regs): dump legacy 8139 registers
+	* ethtool.c (do_gstats, doit, parse_cmdline):
+	support dumping of NIC-specific statistics
+
+Fri Jun 14 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* realtek.c (realtek_dump_regs): dump RTL8139C+ registers
+
+Fri Jun 14 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* realtek.c: new file, dumps RealTek RTL8169 PCI NIC's registers
+	* Makefile.am, ethtool.c, ethtool-util.h: use it
+
+Tue Jun 11 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* NEWS: list new commands added recently
+	* ethtool.c (do_gcoalesce, do_scoalesce, dump_coalesce): new
+	(parse_cmdline, doit): handle get/set coalesce parameters (-c,-C)
+	(do_[gs]*): convert to use table-driven cmd line parsing
+	* ethtool.8: document -c and -C
+
+Tue Jun 11 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool.c (do_gring, do_sring, dump_ring,
+	parse_ring_cmdline): new functions
+	(parse_cmdline, doit): handle get/set ring parameters (-g,-G)
+	(do_spause): fix off-by-one bugs
+	* ethtool.8: document -g and -G
+
+Tue Jun 11 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool.c (do_gpause, do_spause, dump_pause,
+	parse_pause_cmdline): new functions
+	(parse_cmdline, doit): handle get/set pause parameters (-a,-A)
+	* ethtool.8: document -a, -A, -e, and -p
+
+Wed May 22 2002  Chris Leech <christopher.leech@intel.com>
+            Scott Feldman <scott.feldman@intel.com>
+
+	* ethtool-copy.h: add support for ETHTOOL_PHYS_ID function.
+	* ethtool.c: add support for ETHTOOL_PHYS_ID function, add
+	  support for e1000 reg dump.
+	* Makefile.am: add e1000.c
+	* e1000.c: reg dump support for Intel(R) PRO/1000 adapters.
+	* ethtool-util.h: add e1000 reg dump support.
+
+Sat May 11 2002  Eli Kupermann  <eli.kupermann@intel.com>
+
+	* ethtool.c (do_test): add support for online/offline test modes
+	Elsewhere: document "-t" arg usage, and handle usage
+
+Sat May 11 2002  Jes Sorensen  <jes@wildopensource.com>
+
+	* ethtool.c (dump_ecmd): If unknown value is
+	encountered in speed, duplex, or port ETHTOOL_GSET
+	return data, print the numeric value returned.
+
+Wed May 1 2002  Eli Kupermann  <eli.kupermann@intel.com>
+
+	* ethtool.8: document new -t test option
+
+Wed May 1 2002  Christoph Hellwig  <hch@lst.de>
+
+	* Makefile.am (dist-hook): Use $(top-srcdir) for refering to sources.
+
+Mon Apr 29 2002  Christoph Hellwig  <hch@lst.de>
+
+	* Makefile.am (SUBDIRS): Remove.
+	(RPMSRCS): Likewise.
+	(TMPDIR): Likewise.
+	(rpm): Likewise.
+	(EXTRA_DIST): Add ethtool.spec.in.
+	(dist-hook): New rule.  Create rpm specfile.
+	* configure.in (AC_OUTPUT): Add ethtool.spec.
+	* ethtool.spec.in: New file.  Rpm specfile template.
+	* redhat/ethtool.spec.in: Removed.
+	* redhat/Makefile.am: Removed.
+
+Wed Mar 20 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool-copy.h: Merge coalescing param, ring
+	param, and pause param ioctl structs from kernel 2.5.7.
+	Merge ethtool_test changes fromkernel 2.5.7.
+	* ethtool: Update for ethtool_test cleanups.
+
+Wed Mar 20 2002   Eli Kupermann  <eli.kupermann@intel.com>
+
+	* ethtool.c: (do_test): new function
+	Elsewhere: add support for 'perform test' function,
+	via a new "-t" arg, by calling do_test.
+
+Sun Mar  3 2002   Brad Hards  <bhards@bigpond.net.au>
+
+	* ethtool.c (parse_cmdline): Support "usb"
+	as well as "eth" network interfaces.  USB networking
+	uses a different prefix.
+
+Fri Feb  8 2002  "Noam, Amir" <amir.noam@intel.com>,
+		 "Kupermann, Eli" <eli.kupermann@intel.com>
+
+	* ethtool.c (dump_advertised): new function.
+	(dump_ecmd): Call it.
+	Elsewhere: reformat code.
+
+Wed Nov 28 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* configure.in, Makefile.am, redhat/Makefile.am:
+	make sure redhat spec is included in dist tarball.
+
+Tue Nov 27 2001  Tim Hockin  <thockin@sun.com>
+
+	* natsemi.c: strings changes
+	* ethtool.c: print messagelevel as hex (netif_msg_* shows better :)
+
+Sun Nov 18 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* NEWS: update with recent changes
+	* ethtool.8: phy address can be used if implemented in the
+	  driver, so remove "Not used yet" remark.
+
+Sun Nov 18 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* Makefile.am, de2104x.c, ethtool-util.h, ethtool.c:
+	  Support register dumps for de2104x driver.
+
+Tue Nov 13 2001  Tim Hockin  <thockin@sun.com>
+
+	* natsemi.c, ethtool.c: use u8 data for ethtool_regs
+	* ethtool-copy.h: latest from kernel
+	* natsemi.c, ethtool.c: support ETHTOOL_GEEPROM via -e param
+
+Mon Nov 12 2001  Tim Hockin  <thockin@sun.com>
+
+	* natsemi.c: check version, conditionally print RFCR-indexed data
+
+Wed Nov 07 2001  Tim Hockin  <thockin@sun.com>
+
+	* ethtool.c: print less errors for unsupported ioctl()s
+	* ethtool.c: warn if all ioctl()s are unsupported or failed
+	* ethtool.c: change autoneg-restart mechanism to -r (as per jgarzik)
+	* ethtool.c: check for "eth" in devicename (per jg)
+	* ethtool.c: remove 'extraneous' braces
+
+Wed Nov 07 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool.c, ethtool.8: support bnc port/media
+
+Tue Nov 06 2001  Tim Hockin  <thockin@sun.com>
+
+	* ethtool.c: clean up output for unhandled register dumps
+	* natsemi.c: finish pretty-printing register dumps
+	* ethtool.8: document -d option
+	* various: add copyright info, where applicable
+	* ethtool.c: be nicer about unsupported ioctl()s where possible
+	  and be more verbose where nice is not an option.
+
+Mon Nov 05 2001  Tim Hockin  <thockin@sun.com>
+
+	* natsemi.c: first cut at 'pretty-printing' register dumps
+
+Fri Nov 02 2001  Tim Hockin  <thockin@sun.com>
+
+	* ethtool.c: add support for ETHTOOL_GREGS via -d (dump) flag
+	* ethtool.c: add support for device-specific dumps for known devices
+	* ethtool.c: make mode-specific handling allocate ifr_data
+	* Makefile.am: import ChangeLog to rpm specfile
+	* natsemi.c: added
+	* ethtool-util.h: added
+
+Thu Nov 01 2001  Tim Hockin  <thockin@sun.com>
+
+	* ethtool.c: add support for ETHTOOL_GLINK in output
+	* ethtool.c: add support for ETHTOOL_NWAY_RST via 'autoneg restart'
+	* ethtool.c: add support for ETHTOOL_[GS]MSGLVL via 'msglvl' param
+	* ethtool.8: add documentation for above
+	* ethtool-copy.h: updated to sync with kernel
+
+Fri Oct 26 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool.8: Update contributors list, home page URL.
+	* ethtool.8: Much cleanup, no content change.
+	Contributed by Andre Majorel.
+	* ethtool.c: Clean up '-h' usage message.
+	Contributed by Andre Majorel.
+
+Fri Oct 26 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* Configure.in: bump version to 1.4cvs
+	* Makefile.am: include ethtool-copy.h in list of sources
+	* ethtool-copy.h:
+	Import ethtool.h from kernel 2.4.13.
+	* ethtool.c:
+	Define SIOCETHTOOL if it is missing,
+	trim trailing whitespace.
+	* NEWS: update for these changes
+
+Wed Sep 19 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool.c, ethtool-copy.h:
+	Import copy of kernel 2.4.10-pre12's ethtool.h.
+
+Wed Sep 19 2001  Tim Hockin  <thockin@sun.com>
+
+	* Makefile.am, redhat/ethtool.spec.in:
+	Basic "make rpm" support.
+
+Wed Sep 19 2001  Tim Hockin  <thockin@sun.com>
+
+	* AUTHORS, NEWS, ethtool.8, ethtool.c:
+	Wake-on-LAN support.
+
+Thu May 17 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* configure.in, NEWS, README: Version 1.2 release
+
+	* ethtool.c: Support ETHTOOL_GDRVINFO.
+	* ethtool.8: Document it.
+
+Fri Mar 20 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* Makefile.am, configure.in, autogen.sh, NEWS,
+	  ChangeLog, AUTHORS, README:
+	  Add autoconf/automake support.
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d68dccb
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,3 @@
+ethtool is available under the terms of the GNU Public License version 2.
+
+See COPYING for details.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..3af4d4c
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,34 @@
+AM_CFLAGS = -Wall
+LDADD = -lm
+
+man_MANS = ethtool.8
+EXTRA_DIST = LICENSE ethtool.8 ethtool.spec.in aclocal.m4 ChangeLog autogen.sh
+
+sbin_PROGRAMS = ethtool
+ethtool_SOURCES = ethtool.c ethtool-copy.h internal.h net_tstamp-copy.h \
+		  rxclass.c
+if ETHTOOL_ENABLE_PRETTY_DUMP
+ethtool_SOURCES += \
+		  amd8111e.c de2104x.c dsa.c e100.c e1000.c et131x.c igb.c	\
+		  fec.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	\
+		  sff-common.c sff-common.h sfpid.c sfpdiag.c	\
+		  ixgbevf.c tse.c vmxnet3.c qsfp.c qsfp.h fjes.c lan78xx.c
+endif
+
+if ENABLE_BASH_COMPLETION
+bashcompletiondir = $(BASH_COMPLETION_DIR)
+dist_bashcompletion_DATA = shell-completion/bash/ethtool
+endif
+
+TESTS = test-cmdline test-features
+check_PROGRAMS = test-cmdline test-features
+test_cmdline_SOURCES = test-cmdline.c test-common.c $(ethtool_SOURCES) 
+test_cmdline_CFLAGS = -DTEST_ETHTOOL
+test_features_SOURCES = test-features.c test-common.c $(ethtool_SOURCES) 
+test_features_CFLAGS = -DTEST_ETHTOOL
+
+dist-hook:
+	cp $(top_srcdir)/ethtool.spec $(distdir)
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..70f2396
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,499 @@
+Version 5.3 - September 23, 2019
+	* Feature: igb: dump RR2DCDELAY register
+	* Feature: dump nested registers
+
+Version 5.2 - July 25, 2019
+	* Feature: Add 100BaseT1 and 1000BaseT1 link modes
+	* Feature: Use standard file location macros in ethtool.spec
+
+Version 5.1 - May 17, 2019
+	* Feature: Add support for 200Gbps (50Gbps per lane) link mode
+	* Feature: simplify handling of PHY tunable downshift
+	* Feature: add support for PHY tunable Fast Link Down
+	* Feature: add PHY Fast Link Down tunable to man page
+	* Feature: Add a 'start N' option when specifying the Rx flow hash indirection table.
+	* Feature: Add bash-completion script
+	* Feature: add 10000baseR_FEC link mode name
+	* Fix: qsfp: fix special value comparison
+	* Feature: move option parsing related code into function
+	* Feature: move cmdline_coalesce out of do_scoalesce
+	* Feature: introduce new ioctl for per-queue settings
+	* Feature: support per-queue sub command --show-coalesce
+	* Feature: support per-queue sub command --coalesce
+	* Fix: fix up dump_coalesce output to match actual option names
+	* Feature: fec: add pretty dump
+
+Version 5.0 - March 13, 2019
+	* Feature: don't report UFO on kernels v4.14 and above
+	* Fix: zero initialize coalesce struct
+	* Feature: dsa: add pretty dump
+	* Feature: dsa: mv88e6xxx: add pretty dump
+	* Feature: dsa: mv88e6xxx: add pretty dump for 88E6185
+	* Feature: dsa: mv88e6xxx: add pretty dump for 88E6161
+	* Feature: dsa: mv88e6xxx: add pretty dump for 88E6352
+	* Feature: dsa: mv88e6xxx: add pretty dump for 88E6390
+	* Feature: dsa: mv88e6xxx: add pretty dump for others
+
+Version 4.19 - November 2, 2018
+	* Feature: support combinations of FEC modes
+	* Feature: better syntax for combinations of FEC modes
+	* Fix: Fix uninitialized variable use at qsfp dump
+
+Version 4.18 - August 24, 2018
+	* Feature: Add support for WAKE_FILTER (WoL using filters)
+	* Feature: Add support for action value -2 (wake-up filter)
+	* Fix: document WoL filters option also in help message
+	* Feature: ixgbe dump strings for security registers
+
+Version 4.17 - June 15, 2018
+
+	* Fix: In ethtool.8, remove superfluous and incorrect \c.
+	* Fix: fix uninitialized return value
+	* Fix: fix RING_VF assignment
+	* Fix: remove unused global variable
+	* Fix: several fixes in do_gregs()
+	* Fix: correctly free hkey when get_stringset() fails
+	* Fix: remove unreachable code
+	* Fix: fix stack clash in do_get_phy_tunable and do_set_phy_tunable
+	* Feature: Add register dump support for MICROCHIP LAN78xx
+
+Version 4.16 - April 13, 2018
+
+	* Feature: add support for extra RSS contexts and RSS steering filters
+	* Feature: Document RSS context control and RSS filters
+	* Fix: don't fall back to grxfhindir when context was specified
+	* Fix: correct display of VF when showing vf/queue filters
+	* Fix: show VF and queue in the help for -N
+	* Fix: correct VF index values for the ring_cookie parameter
+	* Feature: Add SFF 8636 date code parsing support
+
+Version 4.15 - February 1, 2018
+
+	* Feature: Support for FEC encoding control
+	* Fix: Fix coding style warnings and errors reported by checkpatch
+	* Feature: Add extended compliance codes parsing to sfp modules
+	* Fix: Revert "ethtool: Add DMA Coalescing support"
+	* Feature: Add ETHTOOL_RESET support via --reset command
+	* Fix: fix MFLCN register dump for 82599 and newer
+
+Version 4.13 - October 27, 2017
+
+	* Fix: Do not return error code if no changes were attempted.
+	* Fix: Fix formatting of advertise bitmask
+	* Feature: Document 56000 advertise link modes
+	* Fix: fix the rx vs tx mixup in set channel message
+	* Feature: add support for HWTSTAMP_FILTER_NTP_ALL
+	* Feature: Add DMA Coalescing support
+	* Feature: Remove UDP Fragmentation Offload error prints
+	* Feature: stmmac: Add macros for number of registers
+	* Feature: stmmac: Add DMA HW Feature Register
+
+Version 4.11 - June 2, 2017
+
+	* Feature: Support for configurable RSS hash function
+	* Feature: support queue and VF fields for rxclass filters
+	* Feature: Add support for 2500baseT/5000baseT link modes
+	* Fix: Fix SFF 8079 cable technology bit parsing
+	* Fix: sync help output for -x/-X with man page
+
+Version 4.10 - March 24, 2017
+
+	* Fix: Fix the "advertise" parameter logic.
+	* Feature: Implement ETHTOOL_PHY_GTUNABLE/ETHTOOL_PHY_STUNABLE and PHY downshift
+	* Feature: add register dump support for fjes driver (-d option)
+
+Version 4.8 - October 3, 2016
+
+	* Feature: QSFP Plus/QSFP28 Diagnostics Information Support
+	* Feature: Enhancing link mode bits to support 25G/50G/100G
+	* Feature: add support for 1000BaseX and missing 10G link mode
+	* Fixes: address Coverity issues 1363118 - 1363125
+
+Version 4.6 - June 26, 2016
+
+	* Feature: Support register dump on Intel X550 NICs (-d option)
+	* Fix: Correct some reported register offsets on Intel 10GbE NICs
+	  (-d option)
+	* Feature: Add IPv6 support to NFC (-n, -N, -u and -U options)
+	* Feature: Add support for ETHTOOL_xLINKSETTINGS ioctls (no option
+	  and -s option)
+	* Feature: Use netlink socket when AF_INET not available
+
+Version 4.5 - March 14, 2016
+
+	* Tests: Fix missing function declarations when building tests
+	* Tests: Fix return type of test_free() prorotype
+	* Feature: Add PHY statistics support (--phy-statistics option)
+	* Doc: Properly indent sub-options in man page
+	* Feature: Support setting default Rx flow indirection table
+	  (-X option)
+	* Fix: Use 'sane' kernel type definitions on 64-bit architectures
+	* Fix: Don't ignore fread() return value (-d option)
+	* Fix: Heap corruption when dumping registers from a file (-d option)
+	* Fix: Stricter input validation for EEPROM setting (-E option)
+	* Fix: Fix strict-aliasing compiler warnings in marvell.c
+	* Tests: Fix use of uninitialised variable in test_realloc()
+	* Tests: Fix compiler warning in test-features.c
+
+Version 4.2 - October 9, 2015
+
+	* Feature: Support soldered-on modules in module EEPROM dump (-m option)
+	* Feature: Add register dump support for VMware vmxnet3 (-d option)
+	* Feature: Update register dump support for IBM EMAC (-d option)
+	  (requires Linux 4.3 or a future stable update to 4.1 or 4.2)
+	* Doc: Fix typo in man page
+
+Version 4.0 - May 31, 2015
+
+	* Fix: Formatting of RX flow hash indirection table when size not
+	  divisible by 8 (-x option)
+	* Fix: Add missing Advertised speeds (no option and -s option)
+	* Feature: Add support to get expansion ROM version (-i option)
+	* Feature: Include SFP serial number and date in EEPROM dump
+	  (-m option)
+
+Version 3.18 - December 14, 2014
+
+	* Fix: Lookup of SFP Tx bias in SFF-8472 module diagnostics (-m option)
+	* Fix: Build with musl by using more common typedefs
+
+Version 3.16 - September 22, 2014
+
+	* Feature: Support for configurable RSS hash key (-x/-X options)
+
+Version 3.15 - July 20, 2014
+
+	* Feature: Add register dump support for Altera Triple Speed Ethernet
+	  (-d option)
+
+Version 3.14 - April 21, 2014
+
+	* Fix: Report Backplane as supported port (no option)
+	* Feature: Allow building a smaller executable without pretty-
+	  printing of register/EEPROM dumps (./configure --disable-pretty-dump)
+	* Fix: Typo in channel parameter format in an error message (-L option)
+
+Version 3.13 - January 27, 2014
+
+	* Doc: Update GPL text to include current address of the FSF
+	* Fix: Spelling fixes
+	* Doc: Fix advertising flag values in manual page for 20G link modes,
+	  and add missing 1G, 10G and 40G link modes
+
+Version 3.12.1 - November 8, 2013
+
+	* Fix: Memory corruption when applying external calibration to
+	  SFF-8472 module diagnostics (-m option)
+	* Feature: Add Intel 82599 and x540 DCB registers to dump
+	  (-d option)
+
+Version 3.12 - November 7, 2013
+
+	* Fix: Remove alternate method to check for VLAN tag offload on Linux
+	  < 2.6.37 (-k/-K options)
+	* Fix: Hide state of VLAN tag offload and LRO if the kernel is too old
+	  for us to reliably detect them (-k option)
+	* Feature: Add register dump support for Solarflare SFC9100 family
+	  (-d option)
+
+Version 3.11 - September 12, 2013
+
+	* Feature: Update Realtek chip list for register dump to match
+	  r8169 driver in Linux 3.11 (-d option)
+	* Feature: Add ixgbevf support for register dump (-d option)
+	* Feature: Filter ixgbe register dump according to the specific chip
+	  (-d option)
+
+Version 3.10 - July 1, 2013
+
+	* Feature: Beautify private flags print (--show-priv-flags option)
+
+Version 3.9 - April 30, 2013
+
+	* Feature: Display support for 10000BASE-KR link mode (no options)
+	* Feature: Add support for new versions of ixgbe register dump
+	  (-d dump)
+
+Version 3.8 - February 28, 2013
+
+	* Feature: Allow setting destination MAC address in L3/L4 flow spec
+	  rules (-N/-U option)
+	* Fix: Show full 64 bits of user-data (-n/-u option)
+	* Fix: Add version check for et131x regs (-d option)
+	* Doc: Improve description of -f, -t, -s, -N/-U, -W options in man page
+	* Fix: Restore 20000baseKR2 cap display (no options)
+
+Version 3.7 - December 13, 2012
+
+	* Fix: Gracefully handle failure of register pretty-printer (-d option)
+	* Feature: Add support for et131x registers (-d option)
+	* Feature: Basic optical diagnostics for SFF-8472 modules (-m option)
+
+Version 3.6 - October 5, 2012
+
+	* Feature: Allow setting MDI-X state (-s option)
+	* Fix: Preserve pause advertising bits when setting speed and
+	  duplex with autoneg on (-s option)
+	* Fix: Don't call ioctl to set EEE parameters if they are the same
+	  as the current parameters (--set-eee option)
+
+Version 3.5 - August 2, 2012
+
+	* Feature: Display support for 1000BASE-KX and 10GBASE-KX4 link modes
+	* Feature: Energy-Efficient Ethernet (EEE) configuration
+	  (--show-eee and --set-eee options)
+	* Fix: Don't trust drivers to null-terminate strings
+	* Feature: Display support for 40G link modes
+	* Package: Update RPM summary, description and URL
+	* Package: Exclude redundant documentation from RPM
+
+Version 3.4.2 - July 16, 2012
+
+	* Fix: Fix regression in RX NFC rule insertion for drivers that do
+	  not select rule locations (-N/-U option)
+	* Fix: Remove bogus error message when changing offload settings
+	  on Linux < 2.6.39 (-K option)
+	* Fix: Use alternate method to check for VLAN tag offload on Linux
+	  < 2.6.37 (-k option)
+
+Version 3.4.1 - June 13, 2012
+
+	* Fix: Work around failure of ETHTOOL_GSSET_INFO for unprivileged
+	  users (-k option)
+	* Fix: Report any unexpected error code from ETHTOOL_GSSET_INFO
+	  (-k and -K options)
+	* Doc: Fix the date of the man page to match the last update
+
+Version 3.4 - June 8, 2012
+
+	* Cleanup: Merge RX NFC options
+	* Doc: Improve description of RX NFC options
+	* Doc: Add ntuple to the -K option in the man page
+	* Feature: Show time stamping capabilities (-T option)
+	* Feature: Dump plug-in module EEPROM (-m option)
+	* Feature: Show and change all generic net device features
+	  (-k and -K options)
+
+Version 3.2 - January 12, 2012
+
+	* Feature: Add support for querying and setting private flags
+	  (--show-priv-flags, --set-priv-flags options)
+	* Feature: Omit zero values in Solarflare register tables (-d option)
+	* Feature: Allow driver to select RX NFC rule location (-U option)
+	* Fix: Correct register dump offsets for Intel 82575 chipsets
+	  (-d option)
+
+Version 3.1 - November 16, 2011
+
+	* Fix: Show all non-zero registers for tg3 (-d option)
+	* Feature: Add support for external loopback test (-t option)
+	* Fix: Show correct flow control registers for Intel 82599 (-d option)
+	* Feature: Add support for reporting and configuring numbers of
+	  channels/queues (-l and -L options)
+	* Feature: Report pause frame autonegotiation result (-a option)
+	* Doc: Change device name metavariable from 'ethX' to 'devname'
+	* Doc: Fix various layout problems
+	* Cleanup: Reorganise and add test cases for argument parsing
+	* Fix: Strictly check for extraneous or missing arguments; in
+	  particular, fail if the device name is missing
+
+Version 3.0 - August 4, 2011
+
+	* Feature: Report supported pause frame modes
+	* Feature: Support firmware dump (-w and -W options)
+	* Feature: Report advertised and supported 20G link modes
+	* Feature: Add an 'l4data' option for ip4 filters (-U option)
+	* Fix: Correct swapped h_source and h_dest fields for ether filters
+	  (-U option)
+	* Fix: Set ip_ver field correctly for ip4 filters (-U option)
+	* Fix: Correct parameter validation for -e and -E options; in
+	  particular, treat the 'magic' value as unsigned
+
+Version 2.6.39 - June 1, 2011
+
+	* Feature: Report some driver features (-i option)
+	* Doc: Remove misleading 'Auto' advertising mask from manual page
+	* Doc: Improve table formatting on manual page, using tbl
+	* Doc: Remove initial blank page in printed manual page
+	* Doc: Fix line-wrapping of options
+	* Feature: Add support for ESP as a separate protocol from AH
+	  (-n, -N, -u and -U options)
+	* Cleanup: Remove support for showing RX n-tuple settings
+	  (-u option), which was never implemented correctly in the kernel
+	* Feature: Add support for RX network flow classifier (NFC)
+	  (-u and -U options)
+	* Feature: Add support for e1000 M88 PHY registers (-d option)
+	* Cleanup: Change bug-address to netdev
+
+Version 2.6.38 - March 15, 2011
+
+	* Doc: Fix spelling and spacing in online help
+	* Doc: Update date, version and web site reference in manual page
+	* Doc: Fix spelling, capitalisation, consistency and style in
+	  manual page
+	* Doc: Generalise some references to network devices rather than
+	  Ethernet devices
+	* Fix: Don't silently ignore speed/duplex when autoneg is on
+	* Fix: Report an error (rather than full usage information) if
+	  given an unrecognised option
+	* Feature: Add --version option
+
+Version 2.6.37 - January 5, 2011
+
+	* Fix: Build fix for distributions with kernel headers from
+	  Linux 2.6.9 or earlier
+
+Version 2.6.36 - November 16, 2010
+
+	* Fix: RX n-tuple masks and documentation
+	* Feature: Ethernet-level RX n-tuple filtering and 'clear' action
+	* Feature: stmmac register dump support
+	* Feature: get permanent address (-P) option
+	* Feature: VLAN acceleration control
+
+Version 2.6.35 - August 10, 2010
+
+	* Feature: sfc register dump support
+	* Feature: improve cmd line parsing of ints, IPv4 addresses
+	* Feature: support ethtool named flags, messaging types
+	* Feature: minor man page fixes
+	* Feature: control RX flow hash indirection
+
+Version 2.6.34 - May 26, 2010
+
+	* Feature: Support n-tuple filter programming
+	* Feature: Support rx hashing, v2 (targetted for 2.6.35)
+	* Feature: Add names of newer Marvell chips
+
+Version 2.6.33 - February 24, 2010
+
+	This version introduces a new release numbering scheme, based
+	on the latest upstream kernel interface supported.
+
+	* Fix: several man page corrections
+	* Feature: rx flow hash configuration
+	* Feature: report 10000baseT support, where available
+	* Feature: report MDI-X status, pause auto-neg, link partner adverts
+	* Feature: support additional port types
+	* Feature: support arbitrary speeds, faster than 65535 Mb
+	* Feature: large and generic receive offload (LRO, GRO) support
+	* Feature: option to flash firmware image from specified file
+	* Feature: support for block writing of EEPROMs
+	* Feature: marvell register dump update
+	* Feature: at76c50x-usb, e1000e, igb, ixgbe, r8169 register dump support
+	* Cleanup: remove support for RX hashing by port (was removed in
+	  kernel by 59089d8d162ddcb5c434672e915331964d38a754)
+	* Doc: Explicitly ship GPLv2 license, rather than relying
+	  on autotools to supply it for us (autotools started auto-installing
+	  GPLv3 recently)
+
+Version 6 - July 26, 2007
+
+	* Fix/security: Fix handling of statistics where the label
+	  is exactly 32 bytes (ETH_GSTRING_LEN).
+	* Feature: Add ability to change the advertised speed/duplex
+	  to a different range of values, rather than all-or-one.
+	* Feature: ixgb register dump support
+	* Feature: sky2 register dump support
+	* Feature: Fabric7 VIOC register dump support
+	* Feature: Decode raw register dump stored in a file
+	* Feature: Add ability to force hex register dump, if desired
+	* Feature: update e1000 register dump
+	* Feature: Additional 10Gbps support
+	* Feature: Add 2.5G support
+	* Feature: Update r8169 register dump
+	* Feature: SMSC LAN911x/LAN921x register dump support
+	* Cleanup: Update internal ethtool.h copy to match upstream
+	  kernel 2.6.23-rc1 version of ethtool.h.
+
+Version 5 - September 1, 2006
+
+	* Security: Avoid potential buffer overflow
+	* Feature: GSO support
+	* Feature: skge register dump
+
+Version 4 - July 18, 2006
+
+	* Feature: UFO support
+	* Feature: support long options
+	* Features: e1000, pcnet32, tg3 updates
+	* Feature: added PPC4xx EMAC support
+	* Feature: Use hexdump instead of single values for register dump
+
+Version 3 - January 27, 2005
+
+	* Feature: r8159 register dump support
+	* Feature / bug fix: Support advertising gigabit ethernet
+	* Bug fix: make sure to advertise 10baseT-HD
+	* Other minor bug fixes.
+
+Version 2 - August 17, 2004
+
+	* Feature: ethtool register dump raw mode
+	* Feature: return results of self-test back to OS via exit(2)
+	* Feature: add verbose register dump for pcnet32, fec_8xx
+	* Maintenance: update to more recent autoconf
+	* Maintenance: minor updates to e1000-specific module
+	* Bug fix: Remove silly restriction on ethernet interface naming
+
+Version 1.8 - July 19, 2003
+
+	* Feature: Support amd8111e register dumps
+	* Feature: Support TSO enable/disable
+	* Feature: Support 10 gigabit ethernet
+	* Feature: Support writing EEPROM data
+	* Feature: Output e100 MDI/MDI-x status in register dump
+	* Feature: Clean up RealTek (RTL) chip output, support new chips.
+	* Feature: More supported e1000 devices.
+	* Bug fix: Properly set ecmd.advertising
+	* Bug fix: Fix leaks, handle some error conditions better.
+
+Version 1.7 - October 21, 2002
+
+	* Feature: Support e100 register dumps
+	* Feature: Support tg3 eeprom dumps
+	* Feature: Support partial eeprom dumps (with non-zero offsets)
+	* Feature: Support decimal/octal/hex numbers transparently,
+	  at the user's discretion.
+
+Version 1.6 - June 20, 2002
+
+	* Feature: Support e1000 register dumps
+	* Feature: Support RealTek RTL-8139C+ and RTL-8169 register dumps
+	* Feature: Support coalescing config (ETHTOOL_[GS]COALESCE)
+	* Feature: Support ring param config (ETHTOOL_[GS]RINGPARAM)
+	* Feature: Support pause param config (ETHTOOL_[GS]PAUSEPARAM)
+	* Feature: Support physical NIC identification (ETHTOOL_PHYS_ID)
+	* Feature: Support NIC self-testing (ETHTOOL_TEST)
+	* Feature: Support NIC checksum/scatter-gather configuration
+		(ETHTOOL_[GS]RXCSUM, ETHTOOL_[GS]TXCSUM, ETHTOOL_[GS]SG)
+
+Version 1.5 - Mar 4, 2002
+
+	* Fix: support usb network interfaces
+	* Fix: include redhat spec file in autoconf build system
+	* Fix: minor fixes to natsemi register dump
+	* Feature: report advertised as well as supported media,
+	  when printing device settings.
+
+Version 1.4 - Nov 19, 2001
+
+	* Support builds on configurations missing SIOCETHTOOL constant.
+	* Import ethtool.h from kernel 2.4.15-pre6.
+	* Support retrieval/setting of per-driver debug levels
+	  (ETHTOOL G/SMSGLVL)
+	* Support pretty-printing register dumps on natsemi, de2104x
+	  (ETHTOOL GREGS)
+	* Support restarting autonegotiation (ETHTOOL NWAY_RST)
+	* Support obtaining link status (ETHTOOL GLINK)
+
+Version 1.3 - Aug 02, 2001
+
+	* Support Wake-on-LAN (ETHTOOL GWOL and ETHTOOL SWOL ioctl).
+
+Version 1.2 - May 17, 2001
+
+	* Support ETHTOOL_GDRVINFO ioctl, which obtains
+	  information from the ethernet driver associated
+	  with the specified interface.
+
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..139b26e
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,3 @@
+eliribble@google.com
+allenlintwo@google.com
+jlevasseur@google.com
diff --git a/README b/README
new file mode 100644
index 0000000..9e03205
--- /dev/null
+++ b/README
@@ -0,0 +1,2 @@
+ethtool is a small utility for examining and tuning your ethernet-based
+network interface.  See the man page for more details.
diff --git a/amd8111e.c b/amd8111e.c
new file mode 100644
index 0000000..5a056b3
--- /dev/null
+++ b/amd8111e.c
@@ -0,0 +1,306 @@
+
+/* Copyright (C) 2003  Advanced Micro Devices Inc. */
+#include <stdio.h>
+#include "internal.h"
+
+typedef enum {
+	/* VAL2 */
+	RDMD0			= (1 << 16),
+	/* VAL1 */
+	TDMD3			= (1 << 11),
+	TDMD2			= (1 << 10),
+	TDMD1			= (1 << 9),
+	TDMD0			= (1 << 8),
+	/* VAL0 */
+	UINTCMD			= (1 << 6),
+	RX_FAST_SPND		= (1 << 5),
+	TX_FAST_SPND		= (1 << 4),
+	RX_SPND			= (1 << 3),
+	TX_SPND			= (1 << 2),
+	INTREN			= (1 << 1),
+	RUN			= (1 << 0),
+
+	CMD0_CLEAR 		= 0x000F0F7F,   /* Command style register */
+
+}CMD0_BITS;
+typedef enum {
+
+	/* VAL3 */
+	CONDUIT_MODE		= (1 << 29),
+	/* VAL2 */
+	RPA			= (1 << 19),
+	DRCVPA			= (1 << 18),
+	DRCVBC			= (1 << 17),
+	PROM			= (1 << 16),
+	/* VAL1 */
+	ASTRP_RCV		= (1 << 13),
+	RCV_DROP0	  	= (1 << 12),
+	EMBA			= (1 << 11),
+	DXMT2PD			= (1 << 10),
+	LTINTEN			= (1 << 9),
+	DXMTFCS			= (1 << 8),
+	/* VAL0 */
+	APAD_XMT		= (1 << 6),
+	DRTY			= (1 << 5),
+	INLOOP			= (1 << 4),
+	EXLOOP			= (1 << 3),
+	REX_RTRY		= (1 << 2),
+	REX_UFLO		= (1 << 1),
+	REX_LCOL		= (1 << 0),
+
+	CMD2_CLEAR 		= 0x3F7F3F7F,   /* Command style register */
+
+}CMD2_BITS;
+typedef enum {
+
+	/* VAL3 */
+	ASF_INIT_DONE_ALIAS	= (1 << 29),
+	/* VAL2 */
+	JUMBO			= (1 << 21),
+	VSIZE			= (1 << 20),
+	VLONLY			= (1 << 19),
+	VL_TAG_DEL		= (1 << 18),
+	/* VAL1 */
+	EN_PMGR			= (1 << 14),
+	INTLEVEL		= (1 << 13),
+	FORCE_FULL_DUPLEX	= (1 << 12),
+	FORCE_LINK_STATUS	= (1 << 11),
+	APEP			= (1 << 10),
+	MPPLBA			= (1 << 9),
+	/* VAL0 */
+	RESET_PHY_PULSE		= (1 << 2),
+	RESET_PHY		= (1 << 1),
+	PHY_RST_POL		= (1 << 0),
+
+}CMD3_BITS;
+typedef enum {
+
+	INTR			= (1 << 31),
+	PCSINT			= (1 << 28),
+	LCINT			= (1 << 27),
+	APINT5			= (1 << 26),
+	APINT4			= (1 << 25),
+	APINT3			= (1 << 24),
+	TINT_SUM		= (1 << 23),
+	APINT2			= (1 << 22),
+	APINT1			= (1 << 21),
+	APINT0			= (1 << 20),
+	MIIPDTINT		= (1 << 19),
+	MCCINT			= (1 << 17),
+	MREINT			= (1 << 16),
+	RINT_SUM		= (1 << 15),
+	SPNDINT			= (1 << 14),
+	MPINT			= (1 << 13),
+	SINT			= (1 << 12),
+	TINT3			= (1 << 11),
+	TINT2			= (1 << 10),
+	TINT1			= (1 << 9),
+	TINT0			= (1 << 8),
+	UINT			= (1 << 7),
+	STINT			= (1 << 4),
+	RINT0			= (1 << 0),
+
+}INT0_BITS;
+typedef enum {
+
+	/* VAL3 */
+	LCINTEN			= (1 << 27),
+	APINT5EN		= (1 << 26),
+	APINT4EN		= (1 << 25),
+	APINT3EN		= (1 << 24),
+	/* VAL2 */
+	APINT2EN		= (1 << 22),
+	APINT1EN		= (1 << 21),
+	APINT0EN		= (1 << 20),
+	MIIPDTINTEN		= (1 << 19),
+	MCCIINTEN		= (1 << 18),
+	MCCINTEN		= (1 << 17),
+	MREINTEN		= (1 << 16),
+	/* VAL1 */
+	SPNDINTEN		= (1 << 14),
+	MPINTEN			= (1 << 13),
+	TINTEN3			= (1 << 11),
+	SINTEN			= (1 << 12),
+	TINTEN2			= (1 << 10),
+	TINTEN1			= (1 << 9),
+	TINTEN0			= (1 << 8),
+	/* VAL0 */
+	STINTEN			= (1 << 4),
+	RINTEN0			= (1 << 0),
+
+	INTEN0_CLEAR 		= 0x1F7F7F1F, /* Command style register */
+
+}INTEN0_BITS;
+
+typedef enum {
+
+	PMAT_DET		= (1 << 12),
+	MP_DET		        = (1 << 11),
+	LC_DET			= (1 << 10),
+	SPEED_MASK		= (1 << 9)|(1 << 8)|(1 << 7),
+	FULL_DPLX		= (1 << 6),
+	LINK_STATS		= (1 << 5),
+	AUTONEG_COMPLETE	= (1 << 4),
+	MIIPD			= (1 << 3),
+	RX_SUSPENDED		= (1 << 2),
+	TX_SUSPENDED		= (1 << 1),
+	RUNNING			= (1 << 0),
+
+}STAT0_BITS;
+
+#define PHY_SPEED_10		0x2
+#define PHY_SPEED_100		0x3
+
+
+int amd8111e_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		       struct ethtool_regs *regs)
+{
+
+	u32 *reg_buff = (u32 *)regs->data;
+	u32 reg;
+
+	fprintf(stdout, "Descriptor Registers\n");
+	fprintf(stdout, "---------------------\n");
+
+	/* Transmit descriptor base address register */
+	reg = reg_buff[0];
+	fprintf(stdout,
+		"0x00100: Transmit descriptor base address register %08X\n",reg);
+
+	/* Transmit descriptor length register */
+	reg = reg_buff[1];
+	fprintf(stdout,
+		"0x00140: Transmit descriptor length register 0x%08X\n",reg);
+
+	/* Receive descriptor base address register */
+	reg = reg_buff[2];
+	fprintf(stdout,
+		"0x00120: Receive descriptor base address register %08X\n",reg);
+
+	/* Receive descriptor length register */
+	reg = reg_buff[3];
+	fprintf(stdout,
+		"0x00150: Receive descriptor length register 0x%08X\n",reg);
+
+	fprintf(stdout, "\n");
+
+
+	fprintf(stdout, "Command Registers\n");
+	fprintf(stdout, "-------------------\n");
+
+	/* Command 0 Register */
+	reg = reg_buff[4];
+	fprintf(stdout,
+		"0x00048: Command 0 register  0x%08X\n"
+		"	Interrupts:				%s\n"
+		"	Device:					%s\n",
+		reg,
+		reg & INTREN   		? "Enabled"     : "Disabled",
+		reg & RUN    		? "Running"     : "Stopped");
+
+	/* Command 2 Register */
+	reg = reg_buff[5];
+	fprintf(stdout,
+		"0x00050: Command 2 register  0x%08X\n"
+		"	Promiscuous mode:			%s\n"
+		"	Retransmit on underflow:		%s\n",
+		reg,
+		reg & PROM   		? "Enabled"     : "Disabled",
+		reg & REX_UFLO   	? "Enabled"     : "Disabled");
+	/* Command 3 Register */
+	reg = reg_buff[6];
+	fprintf(stdout,
+		"0x00054: Command 3 register  0x%08X\n"
+		"	Jumbo frame:				%s\n"
+		"	Admit only VLAN frame:	 		%s\n"
+		"	Delete VLAN tag:			%s\n",
+		reg,
+		reg & JUMBO  		? "Enabled"     : "Disabled",
+		reg &  VLONLY 		? "Yes"     : "No",
+		reg &  VL_TAG_DEL 		? "Yes"     : "No");
+
+	/* Command 7 Register */
+	reg = reg_buff[7];
+	fprintf(stdout,
+		"0x00064: Command 7 register  0x%08X\n",
+		 reg);
+
+	fprintf(stdout, "\n");
+	fprintf(stdout, "Interrupt Registers\n");
+	fprintf(stdout, "-------------------\n");
+
+	/* Interrupt 0 Register */
+	reg = reg_buff[8];
+	fprintf(stdout,
+		"0x00038: Interrupt register  0x%08X\n"
+		"	Any interrupt is set: 			%s\n"
+		"	Link change interrupt:	  		%s\n"
+		"	Register 0 auto-poll interrupt:		%s\n"
+		"	Transmit interrupt:			%s\n"
+		"	Software timer interrupt:		%s\n"
+		"	Receive interrupt:			%s\n",
+		 reg,
+		 reg &   INTR		? "Yes"     : "No",
+		 reg &   LCINT		? "Yes"     : "No",
+		 reg &   APINT0		? "Yes"     : "No",
+		 reg &   TINT0		? "Yes"     : "No",
+		 reg &   STINT		? "Yes"     : "No",
+		 reg &   RINT0		? "Yes"     : "No"
+		 );
+	/* Interrupt 0 enable Register */
+	reg = reg_buff[9];
+	fprintf(stdout,
+		"0x00040: Interrupt enable register  0x%08X\n"
+		"	Link change interrupt:	  		%s\n"
+		"	Register 0 auto-poll interrupt:		%s\n"
+		"	Transmit interrupt:			%s\n"
+		"	Software timer interrupt:		%s\n"
+		"	Receive interrupt:			%s\n",
+		 reg,
+		 reg &   LCINTEN		? "Enabled"     : "Disabled",
+		 reg &   APINT0EN		? "Enabled"     : "Disabled",
+		 reg &   TINTEN0		? "Enabled"     : "Disabled",
+		 reg &   STINTEN		? "Enabled"     : "Disabled",
+		 reg &   RINTEN0		? "Enabled"     : "Disabled"
+		);
+
+	fprintf(stdout, "\n");
+	fprintf(stdout, "Logical Address Filter Register\n");
+	fprintf(stdout, "-------------------\n");
+
+	/* Logical Address Filter Register */
+	fprintf(stdout,
+		"0x00168: Logical address filter register  0x%08X%08X\n",
+		 reg_buff[11],reg_buff[10]);
+
+	fprintf(stdout, "\n");
+	fprintf(stdout, "Link status Register\n");
+	fprintf(stdout, "-------------------\n");
+
+	/* Status 0  Register */
+	reg = reg_buff[12];
+	if(reg & LINK_STATS){
+	fprintf(stdout,
+		"0x00030: Link status register  0x%08X\n"
+		"	Link status:	  		%s\n"
+		"	Auto negotiation complete	%s\n"
+		"	Duplex				%s\n"
+		"	Speed				%s\n",
+		reg,
+		reg &  LINK_STATS 		? "Valid"     : "Invalid",
+		reg &  AUTONEG_COMPLETE		? "Yes"	      : "No",
+		reg &  FULL_DPLX 		? "Full"      : "Half",
+		((reg & SPEED_MASK) >> 7 == PHY_SPEED_10) ? "10Mbits/ Sec":
+							"100Mbits/Sec");
+
+	}
+	else{
+	fprintf(stdout,
+		"0x00030: Link status register  0x%08X\n"
+		"	Link status:	  		%s\n",
+		reg,
+		reg &  LINK_STATS 		? "Valid"     : "Invalid");
+	}
+	return 0;
+
+}
diff --git a/at76c50x-usb.c b/at76c50x-usb.c
new file mode 100644
index 0000000..0121e98
--- /dev/null
+++ b/at76c50x-usb.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include "internal.h"
+
+static char *hw_versions[] = {
+        "503_ISL3861",
+        "503_ISL3863",
+        "        503",
+        "    503_ACC",
+        "        505",
+        "   505_2958",
+        "       505A",
+        "     505AMX",
+};
+
+int at76c50x_usb_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+			   struct ethtool_regs *regs)
+{
+	u8 version = (u8)(regs->version >> 24);
+	u8 rev_id = (u8)(regs->version);
+	char *ver_string;
+
+	if (version != 0)
+		return -1;
+
+	ver_string = hw_versions[rev_id];
+	fprintf(stdout,
+		"Hardware Version                    %s\n",
+		ver_string);
+
+	return 0;
+}
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..9f98ef8
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# You need autoconf 2.5x, preferably 2.57 or later
+# You need automake 1.7 or later. 1.6 might work.
+
+set -e
+
+aclocal
+autoheader
+automake --gnu --add-missing --copy
+autoconf
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..56e4683
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,70 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(ethtool, 5.3, netdev@vger.kernel.org)
+AC_PREREQ(2.52)
+AC_CONFIG_SRCDIR([ethtool.c])
+AM_INIT_AUTOMAKE([gnu])
+AC_CONFIG_HEADERS([ethtool-config.h])
+
+AM_MAINTAINER_MODE
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_GCC_TRADITIONAL
+AM_PROG_CC_C_O
+PKG_PROG_PKG_CONFIG
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_MSG_CHECKING([whether <linux/types.h> defines big-endian types])
+AC_TRY_COMPILE([#include <linux/types.h>],
+	       [__be16 foo;__be32 bar;],
+	       [AC_MSG_RESULT(yes)
+		AC_DEFINE([HAVE_BE_TYPES], [1],
+			  [Define to 1 if <linux/types.h> defines big-endian types])],
+	       [AC_MSG_RESULT(no)])
+
+dnl Checks for library functions.
+AC_HEADER_STDC
+AC_CHECK_FUNCS(socket strtol)
+
+dnl Check for options
+AC_ARG_ENABLE(pretty-dump,
+	      [  --enable-pretty-dump	  enable registers, EEPROM and SFP pretty dumps (enabled by default)],
+	      ,
+	      enable_pretty_dump=yes)
+if test x$enable_pretty_dump = xyes; then
+    AC_DEFINE(ETHTOOL_ENABLE_PRETTY_DUMP, 1,
+	      [Define this to enable register, EEPROM and SFP pretty dumps.])
+fi
+AM_CONDITIONAL([ETHTOOL_ENABLE_PRETTY_DUMP], [test x$enable_pretty_dump = xyes])
+
+AC_ARG_WITH([bash-completion-dir],
+	    AS_HELP_STRING([--with-bash-completion-dir[=PATH]],
+	                   [Install the bash-completion script in this directory. @<:@default=yes@:>@]),
+	    [],
+	    [with_bash_completion_dir=yes])
+AS_IF([test "x$with_bash_completion_dir" = xyes],
+      [AC_MSG_CHECKING([for bash-completion directory])
+       dnl Attempt to use pkg-config completionsdir variable with given $prefix.
+       dnl This matches distcheck expectation that all files install to $prefix.
+       dnl It works with /usr and /usr/local (for default $XDG_DATA_DIRS) but
+       dnl may install to directory not used by bash-completion in other cases.
+       dnl See: https://lore.kernel.org/netdev/20190417025333.GA28674@kevinolos/
+       AS_IF([test "x$PKG_CONFIG" != x \
+	      && bash_completion_prefix=`"$PKG_CONFIG" --print-errors --variable=prefix bash-completion 2>&AS_MESSAGE_LOG_FD` \
+	      && bash_completion_dir=`"$PKG_CONFIG" --print-errors --variable=completionsdir bash-completion 2>&AS_MESSAGE_LOG_FD`],
+	     [bash_completion_dir="${bash_completion_dir#"$bash_completion_prefix"}"
+	      bash_completion_dir="${bash_completion_dir#/}"
+	      BASH_COMPLETION_DIR='${prefix}'/"$bash_completion_dir"],
+	     [BASH_COMPLETION_DIR='${datadir}/bash-completion/completions'])
+       AC_MSG_RESULT([$BASH_COMPLETION_DIR])],
+      [BASH_COMPLETION_DIR="$with_bash_completion_dir"])
+AC_SUBST([BASH_COMPLETION_DIR])
+AM_CONDITIONAL([ENABLE_BASH_COMPLETION],
+	       [test "x$with_bash_completion_dir" != xno])
+
+AC_CONFIG_FILES([Makefile ethtool.spec ethtool.8])
+AC_OUTPUT
diff --git a/de2104x.c b/de2104x.c
new file mode 100644
index 0000000..cc03533
--- /dev/null
+++ b/de2104x.c
@@ -0,0 +1,783 @@
+/* Copyright 2001 Sun Microsystems (thockin@sun.com) */
+#include <stdio.h>
+#include "internal.h"
+
+static const char * const csr0_tap[4] = {
+	"No transmit automatic polling",
+	"Transmit automatic polling every 200 seconds",
+	"Transmit automatic polling every 800 seconds",
+	"Transmit automatic polling every 1.6 milliseconds",
+};
+
+static const char * const csr0_cache_al[4] = {
+	"not used",
+	"8-longword boundary alignment",
+	"16-longword boundary alignment",
+	"32-longword boundary alignment",
+};
+
+static const char * const csr5_buserr[8] = {
+	"      Bus error: parity",
+	"      Bus error: master abort",
+	"      Bus error: target abort",
+	"      Bus error: (unknown code, reserved)",
+	"      Bus error: (unknown code, reserved)",
+	"      Bus error: (unknown code, reserved)",
+	"      Bus error: (unknown code, reserved)",
+	"      Bus error: (unknown code, reserved)",
+};
+
+static const int csr6_tx_thresh[4] = {
+	72,
+	96,
+	128,
+	160,
+};
+
+static const char * const csr6_om[4] = {
+	"normal",
+	"internal loopback",
+	"external loopback",
+	"unknown (not used)",
+};
+
+static const char * const csr5_tx_state[8] = {
+	"stopped",
+	"running: fetch desc",
+	"running: wait xmit end",
+	"running: read buf",
+	"unknown (reserved)",
+	"running: setup packet",
+	"suspended",
+	"running: close desc",
+};
+
+static const char * const csr5_rx_state[8] = {
+	"stopped",
+	"running: fetch desc",
+	"running: chk pkt end",
+	"running: wait for pkt",
+	"suspended",
+	"running: close",
+	"running: flush",
+	"running: queue",
+};
+
+static const char * const csr12_nway_state[8] = {
+	"Autonegotiation disable",
+	"Transmit disable",
+	"Ability detect",
+	"Acknowledge detect",
+	"Complete acknowledge",
+	"FLP link good, nway complete",
+	"Link check",
+	"unknown (reserved)",
+};
+
+static const char * const csr14_tp_comp[4] = {
+	"Compensation Disabled Mode",
+	"Compensation Disabled Mode",
+	"High Power Mode",
+	"Normal Compensation Mode",
+};
+
+static void
+print_ring_addresses(u32 csr3, u32 csr4)
+{
+	fprintf(stdout,
+		"0x18: CSR3 (Rx Ring Base Address)        0x%08x\n"
+		"0x20: CSR4 (Tx Ring Base Address)        0x%08x\n"
+		,
+		csr3,
+		csr4);
+}
+
+static void
+print_rx_missed(u32 csr8)
+{
+	fprintf(stdout,
+		"0x40: CSR8 (Missed Frames Counter)       0x%08x\n", csr8);
+	if (csr8 & (1 << 16))
+		fprintf(stdout,
+		"      Counter overflow\n");
+	else {
+		unsigned int rx_missed = csr8 & 0xffff;
+		if (!rx_missed)
+			fprintf(stdout,
+			"      No missed frames\n");
+		else
+			fprintf(stdout,
+			"      %u missed frames\n", rx_missed);
+	}
+}
+
+static void de21040_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+			      struct ethtool_regs *regs)
+{
+	u32 tmp, v, *data = (u32 *)regs->data;
+
+	fprintf(stdout, "21040 Registers\n");
+	fprintf(stdout, "---------------\n");
+
+	/*
+	 * CSR0
+	 */
+	v = data[0];
+	fprintf(stdout,
+		"0x00: CSR0 (Bus Mode)                    0x%08x\n"
+		"      %s\n"
+		"      %s address space\n"
+		"      Cache alignment: %s\n"
+		,
+		v,
+		csr0_tap[(v >> 17) & 3],
+		v & (1 << 16) ? "Diagnostic" : "Standard",
+		csr0_cache_al[(v >> 14) & 3]);
+	tmp = (v >> 8) & 0x3f;
+	if (tmp == 0)
+		fprintf(stdout, "      Programmable burst length unlimited\n");
+	else
+		fprintf(stdout,
+			"      Programmable burst length %d longwords\n",
+			tmp);
+	fprintf(stdout,
+		"      %s endian data buffers\n"
+		"      Descriptor skip length %d longwords\n"
+		"      %s bus arbitration scheme\n"
+		,
+		v & (1 << 7) ? "Big" : "Little",
+		(v >> 2) & 0x1f,
+		v & (1 << 1) ? "Round-robin" : "RX-has-priority");
+	if (v & (1 << 0))
+		fprintf(stdout, "      Software reset asserted\n");
+
+	/*
+	 * CSR3, 4
+	 */
+	print_ring_addresses(data[3], data[4]);
+
+	/*
+	 * CSR5
+	 */
+	v = data[5];
+	fprintf(stdout,
+		"0x28: CSR5 (Status)                      0x%08x\n"
+		"%s"
+		"      Transmit process %s\n"
+		"      Receive process %s\n"
+		"      Link %s\n"
+		,
+		v,
+		v & (1 << 13) ? csr5_buserr[(v >> 23) & 0x7] : "",
+		csr5_tx_state[(v >> 20) & 0x7],
+		csr5_rx_state[(v >> 17) & 0x7],
+		v & (1 << 12) ? "fail" : "OK");
+	if (v & (1 << 16))
+		fprintf(stdout,
+		"      Normal interrupts: %s%s%s\n"
+		,
+		v & (1 << 0) ? "TxOK " : "",
+		v & (1 << 2) ? "TxNoBufs " : "",
+		v & (1 << 6) ? "RxOK" : "");
+	if (v & (1 << 15))
+		fprintf(stdout,
+		"      Abnormal intr: %s%s%s%s%s%s%s%s\n"
+		,
+		v & (1 << 1) ? "TxStop " : "",
+		v & (1 << 3) ? "TxJabber " : "",
+		v & (1 << 5) ? "TxUnder " : "",
+		v & (1 << 7) ? "RxNoBufs " : "",
+		v & (1 << 8) ? "RxStopped " : "",
+		v & (1 << 9) ? "RxTimeout " : "",
+		v & (1 << 10) ? "AUI_TP " : "",
+		v & (1 << 11) ? "FD_Short " : "");
+
+	/*
+	 * CSR6
+	 */
+	v = data[6];
+	fprintf(stdout,
+		"0x30: CSR6 (Operating Mode)              0x%08x\n"
+		"%s"
+		"%s"
+		"      Transmit threshold %d bytes\n"
+		"      Transmit DMA %sabled\n"
+		"%s"
+		"      Operating mode: %s\n"
+		"      %s duplex\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      Receive DMA %sabled\n"
+		"      %s filtering mode\n"
+		,
+		v,
+		v & (1<<17) ? "      Capture effect enabled\n" : "",
+		v & (1<<16) ? "      Back pressure enabled\n" : "",
+		csr6_tx_thresh[(v >> 14) & 3],
+		v & (1<<13) ? "en" : "dis",
+		v & (1<<12) ? "      Forcing collisions\n" : "",
+		csr6_om[(v >> 10) & 3],
+		v & (1<<9) ? "Full" : "Half",
+		v & (1<<8) ? "      Flaky oscillator disable\n" : "",
+		v & (1<<7) ? "      Pass All Multicast\n" : "",
+		v & (1<<6) ? "      Promisc Mode\n" : "",
+		v & (1<<5) ? "      Start/Stop Backoff Counter\n" : "",
+		v & (1<<4) ? "      Inverse Filtering\n" : "",
+		v & (1<<3) ? "      Pass Bad Frames\n" : "",
+		v & (1<<2) ? "      Hash-only Filtering\n" : "",
+		v & (1<<1) ? "en" : "dis",
+		v & (1<<0) ? "Hash" : "Perfect");
+
+	/*
+	 * CSR7
+	 */
+	v = data[7];
+	fprintf(stdout,
+		"0x38: CSR7 (Interrupt Mask)              0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<16) ? "      Normal interrupt summary\n" : "",
+		v & (1<<15) ? "      Abnormal interrupt summary\n" : "",
+		v & (1<<13) ? "      System error\n" : "",
+		v & (1<<12) ? "      Link fail\n" : "",
+		v & (1<<11) ? "      Full duplex\n" : "",
+		v & (1<<10) ? "      AUI_TP pin\n" : "",
+		v & (1<<9) ? "      Receive watchdog timeout\n" : "",
+		v & (1<<8) ? "      Receive stopped\n" : "",
+		v & (1<<7) ? "      Receive buffer unavailable\n" : "",
+		v & (1<<6) ? "      Receive interrupt\n" : "",
+		v & (1<<5) ? "      Transmit underflow\n" : "",
+		v & (1<<3) ? "      Transmit jabber timeout\n" : "",
+		v & (1<<2) ? "      Transmit buffer unavailable\n" : "",
+		v & (1<<1) ? "      Transmit stopped\n" : "",
+		v & (1<<0) ? "      Transmit interrupt\n" : "");
+
+	/*
+	 * CSR8
+	 */
+	print_rx_missed(data[8]);
+
+	/*
+	 * CSR9
+	 */
+	v = data[9];
+	fprintf(stdout,
+		"0x48: CSR9 (Ethernet Address ROM)        0x%08x\n", v);
+
+	/*
+	 * CSR11
+	 */
+	v = data[11];
+	fprintf(stdout,
+		"0x58: CSR11 (Full Duplex Autoconfig)     0x%08x\n", v);
+
+	/*
+	 * CSR12
+	 */
+	v = data[12];
+	fprintf(stdout,
+		"0x60: CSR12 (SIA Status)                 0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      AUI_TP pin: %s\n"
+		,
+		v,
+		v & (1<<7) ? "      PLL sampler high\n" : "",
+		v & (1<<6) ? "      PLL sampler low\n" : "",
+		v & (1<<5) ? "      PLL self-test pass\n" : "",
+		v & (1<<4) ? "      PLL self-test done\n" : "",
+		v & (1<<3) ? "      Autopolarity state\n" : "",
+		v & (1<<2) ? "      Link fail\n" : "",
+		v & (1<<1) ? "      Network connection error\n" : "",
+		v & (1<<0) ? "AUI" : "TP");
+
+	/*
+	 * CSR13
+	 */
+	v = data[13];
+	fprintf(stdout,
+		"0x68: CSR13 (SIA Connectivity)           0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      External port output multiplexer select: %u%u%u%u\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      %s interface selected\n"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<15) ? "      Enable pins 5, 6, 7\n" : "",
+		v & (1<<14) ? "      Enable pins 2, 4\n" : "",
+		v & (1<<13) ? "      Enable pins 1, 3\n" : "",
+		v & (1<<12) ? "      Input enable\n" : "",
+		v & (1<<11) ? 1 : 0,
+		v & (1<<10) ? 1 : 0,
+		v & (1<<9) ? 1 : 0,
+		v & (1<<8) ? 1 : 0,
+		v & (1<<7) ? "      APLL start\n" : "",
+		v & (1<<6) ? "      Serial interface input multiplexer\n" : "",
+		v & (1<<5) ? "      Encoder input multiplexer\n" : "",
+		v & (1<<4) ? "      SIA PLL external input enable\n" : "",
+		v & (1<<3) ? "AUI" : "10base-T",
+		v & (1<<2) ? "      CSR autoconfiguration\n" : "",
+		v & (1<<1) ? "      AUI_TP pin autoconfiguration\n" : "",
+		v & (1<<0) ? "      SIA reset\n" : "");
+
+	/*
+	 * CSR14
+	 */
+	v = data[14];
+	fprintf(stdout,
+		"0x70: CSR14 (SIA Transmit and Receive)   0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      %s\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<14) ? "      Set polarity plus\n" : "",
+		v & (1<<13) ? "      Autopolarity enable\n" : "",
+		v & (1<<12) ? "      Link test enable\n" : "",
+		v & (1<<11) ? "      Heartbeat enable\n" : "",
+		v & (1<<10) ? "      Collision detect enable\n" : "",
+		v & (1<<9) ? "      Collision squelch enable\n" : "",
+		v & (1<<8) ? "      Receive squelch enable\n" : "",
+		csr14_tp_comp[(v >> 4) & 0x3],
+		v & (1<<3) ? "      Link pulse send enable\n" : "",
+		v & (1<<2) ? "      Driver enable\n" : "",
+		v & (1<<1) ? "      Loopback enable\n" : "",
+		v & (1<<0) ? "      Encoder enable\n" : "");
+
+	/*
+	 * CSR15
+	 */
+	v = data[15];
+	fprintf(stdout,
+		"0x78: CSR15 (SIA General)                0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<13) ? "      Force receiver low\n" : "",
+		v & (1<<12) ? "      PLL self-test start\n" : "",
+		v & (1<<11) ? "      Force link fail\n" : "",
+		v & (1<<9) ? "      Force unsquelch\n" : "",
+		v & (1<<8) ? "      Test clock\n" : "",
+		v & (1<<5) ? "      Receive watchdog release\n" : "",
+		v & (1<<4) ? "      Receive watchdog disable\n" : "",
+		v & (1<<2) ? "      Jabber clock\n" : "",
+		v & (1<<1) ? "      Host unjab\n" : "",
+		v & (1<<0) ? "      Jabber disable\n" : "");
+}
+
+static void de21041_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+			      struct ethtool_regs *regs)
+{
+	u32 tmp, v, *data = (u32 *)regs->data;
+
+	fprintf(stdout, "21041 Registers\n");
+	fprintf(stdout, "---------------\n");
+
+	/*
+	 * CSR0
+	 */
+	v = data[0];
+	fprintf(stdout,
+		"0x00: CSR0 (Bus Mode)                    0x%08x\n"
+		"      %s endian descriptors\n"
+		"      %s\n"
+		"      %s address space\n"
+		"      Cache alignment: %s\n"
+		,
+		v,
+		v & (1 << 20) ? "Big" : "Little",
+		csr0_tap[(v >> 17) & 3],
+		v & (1 << 16) ? "Diagnostic" : "Standard",
+		csr0_cache_al[(v >> 14) & 3]);
+	tmp = (v >> 8) & 0x3f;
+	if (tmp == 0)
+		fprintf(stdout, "      Programmable burst length unlimited\n");
+	else
+		fprintf(stdout,
+			"      Programmable burst length %d longwords\n",
+			tmp);
+	fprintf(stdout,
+		"      %s endian data buffers\n"
+		"      Descriptor skip length %d longwords\n"
+		"      %s bus arbitration scheme\n"
+		,
+		v & (1 << 7) ? "Big" : "Little",
+		(v >> 2) & 0x1f,
+		v & (1 << 1) ? "Round-robin" : "RX-has-priority");
+	if (v & (1 << 0))
+		fprintf(stdout, "      Software reset asserted\n");
+
+	/*
+	 * CSR3, 4
+	 */
+	print_ring_addresses(data[3], data[4]);
+
+	/*
+	 * CSR5
+	 */
+	v = data[5];
+	fprintf(stdout,
+		"0x28: CSR5 (Status)                      0x%08x\n"
+		"%s"
+		"      Transmit process %s\n"
+		"      Receive process %s\n"
+		"      Link %s\n"
+		,
+		v,
+		v & (1 << 13) ? csr5_buserr[(v >> 23) & 0x7] : "",
+		csr5_tx_state[(v >> 20) & 0x7],
+		csr5_rx_state[(v >> 17) & 0x7],
+		v & (1 << 12) ? "fail" : "OK");
+	if (v & (1 << 16))
+		fprintf(stdout,
+		"      Normal interrupts: %s%s%s%s%s\n"
+		,
+		v & (1 << 0) ? "TxOK " : "",
+		v & (1 << 2) ? "TxNoBufs " : "",
+		v & (1 << 6) ? "RxOK" : "",
+		v & (1 << 11) ? "TimerExp " : "",
+		v & (1 << 14) ? "EarlyRx " : "");
+	if (v & (1 << 15))
+		fprintf(stdout,
+		"      Abnormal intr: %s%s%s%s%s%s%s\n"
+		,
+		v & (1 << 1) ? "TxStop " : "",
+		v & (1 << 3) ? "TxJabber " : "",
+		v & (1 << 4) ? "ANC " : "",
+		v & (1 << 5) ? "TxUnder " : "",
+		v & (1 << 7) ? "RxNoBufs " : "",
+		v & (1 << 8) ? "RxStopped " : "",
+		v & (1 << 9) ? "RxTimeout " : "");
+
+	/*
+	 * CSR6
+	 */
+	v = data[6];
+	fprintf(stdout,
+		"0x30: CSR6 (Operating Mode)              0x%08x\n"
+		"%s"
+		"%s"
+		"      Transmit threshold %d bytes\n"
+		"      Transmit DMA %sabled\n"
+		"%s"
+		"      Operating mode: %s\n"
+		"      %s duplex\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      Receive DMA %sabled\n"
+		"      %s filtering mode\n"
+		,
+		v,
+		v & (1<<31) ? "      Special capture effect enabled\n" : "",
+		v & (1<<17) ? "      Capture effect enabled\n" : "",
+		csr6_tx_thresh[(v >> 14) & 3],
+		v & (1<<13) ? "en" : "dis",
+		v & (1<<12) ? "      Forcing collisions\n" : "",
+		csr6_om[(v >> 10) & 3],
+		v & (1<<9) ? "Full" : "Half",
+		v & (1<<8) ? "      Flaky oscillator disable\n" : "",
+		v & (1<<7) ? "      Pass All Multicast\n" : "",
+		v & (1<<6) ? "      Promisc Mode\n" : "",
+		v & (1<<5) ? "      Start/Stop Backoff Counter\n" : "",
+		v & (1<<4) ? "      Inverse Filtering\n" : "",
+		v & (1<<3) ? "      Pass Bad Frames\n" : "",
+		v & (1<<2) ? "      Hash-only Filtering\n" : "",
+		v & (1<<1) ? "en" : "dis",
+		v & (1<<0) ? "Hash" : "Perfect");
+
+	/*
+	 * CSR7
+	 */
+	v = data[7];
+	fprintf(stdout,
+		"0x38: CSR7 (Interrupt Mask)              0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<16) ? "      Normal interrupt summary\n" : "",
+		v & (1<<15) ? "      Abnormal interrupt summary\n" : "",
+		v & (1<<14) ? "      Early receive interrupt\n" : "",
+		v & (1<<13) ? "      System error\n" : "",
+		v & (1<<12) ? "      Link fail\n" : "",
+		v & (1<<11) ? "      Timer expired\n" : "",
+		v & (1<<9) ? "      Receive watchdog timeout\n" : "",
+		v & (1<<8) ? "      Receive stopped\n" : "",
+		v & (1<<7) ? "      Receive buffer unavailable\n" : "",
+		v & (1<<6) ? "      Receive interrupt\n" : "",
+		v & (1<<5) ? "      Transmit underflow\n" : "",
+		v & (1<<4) ? "      Link pass\n" : "",
+		v & (1<<3) ? "      Transmit jabber timeout\n" : "",
+		v & (1<<2) ? "      Transmit buffer unavailable\n" : "",
+		v & (1<<1) ? "      Transmit stopped\n" : "",
+		v & (1<<0) ? "      Transmit interrupt\n" : "");
+
+	/*
+	 * CSR8
+	 */
+	print_rx_missed(data[8]);
+
+	/*
+	 * CSR9
+	 */
+	v = data[9];
+	fprintf(stdout,
+		"0x48: CSR9 (Boot and Ethernet ROMs)      0x%08x\n"
+		"      Select bits: %s%s%s%s%s%s\n"
+		"      Data: %d%d%d%d%d%d%d%d\n"
+		,
+		v,
+		v & (1<<15) ? "Mode " : "",
+		v & (1<<14) ? "Read " : "",
+		v & (1<<13) ? "Write " : "",
+		v & (1<<12) ? "BootROM " : "",
+		v & (1<<11) ? "SROM " : "",
+		v & (1<<10) ? "ExtReg " : "",
+		v & (1<<7) ? 1 : 0,
+		v & (1<<6) ? 1 : 0,
+		v & (1<<5) ? 1 : 0,
+		v & (1<<4) ? 1 : 0,
+		v & (1<<3) ? 1 : 0,
+		v & (1<<2) ? 1 : 0,
+		v & (1<<1) ? 1 : 0,
+		v & (1<<0) ? 1 : 0);
+
+	/*
+	 * CSR10
+	 */
+	v = data[10];
+	fprintf(stdout,
+		"0x50: CSR10 (Boot ROM Address)           0x%08x\n", v);
+
+	/*
+	 * CSR11
+	 */
+	v = data[11];
+	fprintf(stdout,
+		"0x58: CSR11 (General Purpose Timer)      0x%08x\n"
+		"%s"
+		"      Timer value: %u cycles\n"
+		,
+		v,
+		v & (1<<16) ? "      Continuous mode\n" : "",
+		v & 0xffff);
+
+	/*
+	 * CSR12
+	 */
+	v = data[12];
+	fprintf(stdout,
+		"0x60: CSR12 (SIA Status)                 0x%08x\n"
+		"      Link partner code word 0x%04x\n"
+		"%s"
+		"      NWay state: %s\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v >> 16,
+		v & (1<<15) ? "      Link partner negotiable\n" : "",
+		csr12_nway_state[(v >> 12) & 0x7],
+		v & (1<<11) ? "      Transmit remote fault\n" : "",
+		v & (1<<10) ? "      Unstable NLP detected\n" : "",
+		v & (1<<9) ? "      Non-selected port receive activity\n" : "",
+		v & (1<<8) ? "      Selected port receive activity\n" : "",
+		v & (1<<7) ? "      PLL sampler high\n" : "",
+		v & (1<<6) ? "      PLL sampler low\n" : "",
+		v & (1<<5) ? "      PLL self-test pass\n" : "",
+		v & (1<<4) ? "      PLL self-test done\n" : "",
+		v & (1<<3) ? "      Autopolarity state\n" : "",
+		v & (1<<2) ? "      Link fail\n" : "",
+		v & (1<<1) ? "      Network connection error\n" : "");
+
+	/*
+	 * CSR13
+	 */
+	v = data[13];
+	fprintf(stdout,
+		"0x68: CSR13 (SIA Connectivity)           0x%08x\n"
+		"      SIA Diagnostic Mode 0x%04x\n"
+		"      %s\n"
+		"%s"
+		"%s"
+		,
+		v,
+		(v >> 4) & 0xfff,
+		v & (1<<3) ? "AUI/BNC port" : "10base-T port",
+		v & (1<<2) ? "      CSR autoconfiguration enabled\n" : "",
+		v & (1<<0) ? "      SIA register reset asserted\n" : "");
+
+	/*
+	 * CSR14
+	 */
+	v = data[14];
+	fprintf(stdout,
+		"0x70: CSR14 (SIA Transmit and Receive)   0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      %s\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<15) ? "      10base-T/AUI autosensing\n" : "",
+		v & (1<<14) ? "      Set polarity plus\n" : "",
+		v & (1<<13) ? "      Autopolarity enable\n" : "",
+		v & (1<<12) ? "      Link test enable\n" : "",
+		v & (1<<11) ? "      Heartbeat enable\n" : "",
+		v & (1<<10) ? "      Collision detect enable\n" : "",
+		v & (1<<9) ? "      Collision squelch enable\n" : "",
+		v & (1<<8) ? "      Receive squelch enable\n" : "",
+		v & (1<<7) ? "      Autonegotiation enable\n" : "",
+		v & (1<<6) ? "      Must Be One\n" : "",
+		csr14_tp_comp[(v >> 4) & 0x3],
+		v & (1<<3) ? "      Link pulse send enable\n" : "",
+		v & (1<<2) ? "      Driver enable\n" : "",
+		v & (1<<1) ? "      Loopback enable\n" : "",
+		v & (1<<0) ? "      Encoder enable\n" : "");
+
+	/*
+	 * CSR15
+	 */
+	v = data[15];
+	fprintf(stdout,
+		"0x78: CSR15 (SIA General)                0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      %s port selected\n"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<15) ? "      GP LED2 on\n" : "",
+		v & (1<<14) ? "      GP LED2 enable\n" : "",
+		v & (1<<13) ? "      Force receiver low\n" : "",
+		v & (1<<12) ? "      PLL self-test start\n" : "",
+		v & (1<<11) ? "      LED stretch disable\n" : "",
+		v & (1<<10) ? "      Force link fail\n" : "",
+		v & (1<<9) ? "      Force unsquelch\n" : "",
+		v & (1<<8) ? "      Test clock\n" : "",
+		v & (1<<7) ? "      GP LED1 on\n" : "",
+		v & (1<<6) ? "      GP LED1 enable\n" : "",
+		v & (1<<5) ? "      Receive watchdog release\n" : "",
+		v & (1<<4) ? "      Receive watchdog disable\n" : "",
+		v & (1<<3) ? "AUI" : "BNC",
+		v & (1<<2) ? "      Jabber clock\n" : "",
+		v & (1<<1) ? "      Host unjab\n" : "",
+		v & (1<<0) ? "      Jabber disable\n" : "");
+}
+
+int
+de2104x_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+	unsigned int de21040 = regs->version & 1;
+
+	if (de21040)
+		de21040_dump_regs(info, regs);
+	else
+		de21041_dump_regs(info, regs);
+
+	return 0;
+}
+
diff --git a/dsa.c b/dsa.c
new file mode 100644
index 0000000..50a171b
--- /dev/null
+++ b/dsa.c
@@ -0,0 +1,686 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "internal.h"
+
+/* Macros and dump functions for the 16-bit mv88e6xxx per-port registers */
+
+#define REG(_reg, _name, _val) \
+	printf("%.02u: %-38.38s 0x%.4x\n", _reg, _name, _val)
+
+#define FIELD(_name, _fmt, ...) \
+	printf("      %-36.36s " _fmt "\n", _name, ##__VA_ARGS__)
+
+#define FIELD_BITMAP(_name, _val) \
+	FIELD(_name, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", \
+	      ((_val) & 0x0001) ? "0 " : "", \
+	      ((_val) & 0x0002) ? "1 " : "", \
+	      ((_val) & 0x0004) ? "2 " : "", \
+	      ((_val) & 0x0008) ? "3 " : "", \
+	      ((_val) & 0x0010) ? "4 " : "", \
+	      ((_val) & 0x0020) ? "5 " : "", \
+	      ((_val) & 0x0040) ? "6 " : "", \
+	      ((_val) & 0x0080) ? "7 " : "", \
+	      ((_val) & 0x0100) ? "8 " : "", \
+	      ((_val) & 0x0200) ? "9 " : "", \
+	      ((_val) & 0x0400) ? "10 " : "", \
+	      ((_val) & 0x0800) ? "11 " : "", \
+	      ((_val) & 0x1000) ? "12 " : "", \
+	      ((_val) & 0x2000) ? "13 " : "", \
+	      ((_val) & 0x4000) ? "14 " : "", \
+	      ((_val) & 0x8000) ? "15 " : "")
+
+static void dsa_mv88e6161(int reg, u16 val)
+{
+	switch (reg) {
+	case 0:
+		REG(reg, "Port Status", val);
+		FIELD("Pause Enabled", "%u", !!(val & 0x8000));
+		FIELD("My Pause", "%u", !!(val & 0x4000));
+		FIELD("Half-duplex Flow Control", "%u", !!(val & 0x2000));
+		FIELD("802.3 PHY Detected", "%u", !!(val & 0x1000));
+		FIELD("Link Status", "%s", val & 0x0800 ? "Up" : "Down");
+		FIELD("Duplex", "%s", val & 0x0400 ? "Full" : "Half");
+		FIELD("Speed", "%s",
+		      (val & 0x0300) == 0x0000 ? "10 Mbps" :
+		      (val & 0x0300) == 0x0100 ? "100 Mbps" :
+		      (val & 0x0300) == 0x0200 ? "1000 Mbps" :
+		      (val & 0x0300) == 0x0300 ? "Reserved" : "?");
+		FIELD("Auto-Media Detect Disable", "%u", !!(val & 0x0040));
+		FIELD("Transmitter Paused", "%u", !!(val & 0x0020));
+		FIELD("Flow Control", "%u", !!(val & 0x0010));
+		FIELD("Config Duplex", "%s", val & 0x0008 ? "Full" : "Half");
+		FIELD("Config Mode", "0x%x", val & 0x0007);
+		break;
+	case 1:
+		REG(reg, "PCS Control", val);
+		FIELD("Flow Control's Forced value", "%u", !!(val & 0x0080));
+		FIELD("Force Flow Control", "%u", !!(val & 0x0040));
+		FIELD("Link's Forced value", "%s", val & 0x0020 ? "Up" : "Down");
+		FIELD("Force Link", "%u", !!(val & 0x0010));
+		FIELD("Duplex's Forced value", "%s", val & 0x0008 ? "Full" : "Half");
+		FIELD("Force Duplex", "%u", !!(val & 0x0004));
+		FIELD("Force Speed", "%s",
+		      (val & 0x0003) == 0x0000 ? "10 Mbps" :
+		      (val & 0x0003) == 0x0001 ? "100 Mbps" :
+		      (val & 0x0003) == 0x0002 ? "1000 Mbps" :
+		      (val & 0x0003) == 0x0003 ? "Not forced" : "?");
+		break;
+	case 2:
+		REG(reg, "Jamming Control", val);
+		break;
+	case 3:
+		REG(reg, "Switch Identifier", val);
+		break;
+	case 4:
+		REG(reg, "Port Control", val);
+		FIELD("Source Address Filtering controls", "%s",
+		      (val & 0xc000) == 0x0000 ? "Disabled" :
+		      (val & 0xc000) == 0x4000 ? "Drop On Lock" :
+		      (val & 0xc000) == 0x8000 ? "Drop On Unlock" :
+		      (val & 0xc000) == 0xc000 ? "Drop to CPU" : "?");
+		FIELD("Egress Mode", "%s",
+		      (val & 0x3000) == 0x0000 ? "Unmodified" :
+		      (val & 0x3000) == 0x1000 ? "Untagged" :
+		      (val & 0x3000) == 0x2000 ? "Tagged" :
+		      (val & 0x3000) == 0x3000 ? "Reserved" : "?");
+		FIELD("Ingress & Egress Header Mode", "%u", !!(val & 0x0800));
+		FIELD("IGMP and MLD Snooping", "%u", !!(val & 0x0400));
+		FIELD("Frame Mode", "%s",
+		      (val & 0x0300) == 0x0000 ? "Normal" :
+		      (val & 0x0300) == 0x0100 ? "DSA" :
+		      (val & 0x0300) == 0x0200 ? "Provider" :
+		      (val & 0x0300) == 0x0300 ? "Ether Type DSA" : "?");
+		FIELD("VLAN Tunnel", "%u", !!(val & 0x0080));
+		FIELD("TagIfBoth", "%u", !!(val & 0x0040));
+		FIELD("Initial Priority assignment", "%s",
+		      (val & 0x0030) == 0x0000 ? "Defaults" :
+		      (val & 0x0030) == 0x0010 ? "Tag Priority" :
+		      (val & 0x0030) == 0x0020 ? "IP Priority" :
+		      (val & 0x0030) == 0x0030 ? "Tag & IP Priority" : "?");
+		FIELD("Egress Flooding mode", "%s",
+		      (val & 0x000c) == 0x0000 ? "No unknown DA" :
+		      (val & 0x000c) == 0x0004 ? "No unknown multicast DA" :
+		      (val & 0x000c) == 0x0008 ? "No unknown unicast DA" :
+		      (val & 0x000c) == 0x000c ? "Allow unknown DA" : "?");
+		FIELD("Port State", "%s",
+		      (val & 0x0003) == 0x0000 ? "Disabled" :
+		      (val & 0x0003) == 0x0001 ? "Blocking/Listening" :
+		      (val & 0x0003) == 0x0002 ? "Learning" :
+		      (val & 0x0003) == 0x0003 ? "Forwarding" : "?");
+		break;
+	case 5:
+		REG(reg, "Port Control 1", val);
+		FIELD("Message Port", "%u", !!(val & 0x8000));
+		FIELD("Trunk Port", "%u", !!(val & 0x4000));
+		FIELD("Trunk ID", "%u", (val & 0x0f00) >> 8);
+		FIELD("FID[5:4]", "0x%.2x", (val & 0x0003) << 4);
+		break;
+	case 6:
+		REG(reg, "Port Base VLAN Map (Header)", val);
+		FIELD("FID[3:0]", "0x%.2x", (val & 0xf000) >> 12);
+		FIELD_BITMAP("VLANTable", val & 0x003f);
+		break;
+	case 7:
+		REG(reg, "Default VLAN ID & Priority", val);
+		FIELD("Default Priority", "0x%x", (val & 0xe000) >> 13);
+		FIELD("Force to use Default VID", "%u", !!(val & 0x1000));
+		FIELD("Default VLAN Identifier", "%u", val & 0x0fff);
+		break;
+	case 8:
+		REG(reg, "Port Control 2", val);
+		FIELD("Force good FCS in the frame", "%u", !!(val & 0x8000));
+		FIELD("Jumbo Mode", "%s",
+		      (val & 0x3000) == 0x0000 ? "1522" :
+		      (val & 0x3000) == 0x1000 ? "2048" :
+		      (val & 0x3000) == 0x2000 ? "10240" :
+		      (val & 0x3000) == 0x3000 ? "Reserved" : "?");
+		FIELD("802.1QMode", "%s",
+		      (val & 0x0c00) == 0x0000 ? "Disabled" :
+		      (val & 0x0c00) == 0x0400 ? "Fallback" :
+		      (val & 0x0c00) == 0x0800 ? "Check" :
+		      (val & 0x0c00) == 0x0c00 ? "Secure" : "?");
+		FIELD("Discard Tagged Frames", "%u", !!(val & 0x0200));
+		FIELD("Discard Untagged Frames", "%u", !!(val & 0x0100));
+		FIELD("Map using DA hits", "%u", !!(val & 0x0080));
+		FIELD("ARP Mirror enable", "%u", !!(val & 0x0040));
+		FIELD("Egress Monitor Source Port", "%u", !!(val & 0x0020));
+		FIELD("Ingress Monitor Source Port", "%u", !!(val & 0x0010));
+		break;
+	case 9:
+		REG(reg, "Egress Rate Control", val);
+		break;
+	case 10:
+		REG(reg, "Egress Rate Control 2", val);
+		break;
+	case 11:
+		REG(reg, "Port Association Vector", val);
+		break;
+	case 12:
+		REG(reg, "Port ATU Control", val);
+		break;
+	case 13:
+		REG(reg, "Priority Override", val);
+		break;
+	case 15:
+		REG(reg, "PortEType", val);
+		break;
+	case 16:
+		REG(reg, "InDiscardsLo Frame Counter", val);
+		break;
+	case 17:
+		REG(reg, "InDiscardsHi Frame Counter", val);
+		break;
+	case 18:
+		REG(reg, "InFiltered Frame Counter", val);
+		break;
+	case 19:
+		REG(reg, "OutFiltered Frame Counter", val);
+		break;
+	case 24:
+		REG(reg, "Tag Remap 0-3", val);
+		break;
+	case 25:
+		REG(reg, "Tag Remap 4-7", val);
+		break;
+	case 27:
+		REG(reg, "Queue Counters", val);
+		break;
+	default:
+		REG(reg, "Reserved", val);
+		break;
+	}
+}
+
+static void dsa_mv88e6185(int reg, u16 val)
+{
+	switch (reg) {
+	case 0:
+		REG(reg, "Port Status", val);
+		break;
+	case 1:
+		REG(reg, "PCS Control", val);
+		break;
+	case 3:
+		REG(reg, "Switch Identifier", val);
+		break;
+	case 4:
+		REG(reg, "Port Control", val);
+		break;
+	case 5:
+		REG(reg, "Port Control 1", val);
+		break;
+	case 6:
+		REG(reg, "Port Base VLAN Map (Header)", val);
+		break;
+	case 7:
+		REG(reg, "Default VLAN ID & Priority", val);
+		break;
+	case 8:
+		REG(reg, "Port Control 2", val);
+		break;
+	case 9:
+		REG(reg, "Rate Control", val);
+		break;
+	case 10:
+		REG(reg, "Rate Control 2", val);
+		break;
+	case 11:
+		REG(reg, "Port Association Vector", val);
+		break;
+	case 16:
+		REG(reg, "InDiscardsLo Frame Counter", val);
+		break;
+	case 17:
+		REG(reg, "InDiscardsHi Frame Counter", val);
+		break;
+	case 18:
+		REG(reg, "InFiltered Frame Counter", val);
+		break;
+	case 19:
+		REG(reg, "OutFiltered Frame Counter", val);
+		break;
+	case 24:
+		REG(reg, "Tag Remap 0-3", val);
+		break;
+	case 25:
+		REG(reg, "Tag Remap 4-7", val);
+		break;
+	default:
+		REG(reg, "Reserved", val);
+		break;
+	}
+};
+
+static void dsa_mv88e6352(int reg, u16 val)
+{
+	switch (reg) {
+	case 0:
+		REG(reg, "Port Status", val);
+		FIELD("Pause Enabled", "%u", !!(val & 0x8000));
+		FIELD("My Pause", "%u", !!(val & 0x4000));
+		FIELD("802.3 PHY Detected", "%u", !!(val & 0x1000));
+		FIELD("Link Status", "%s", val & 0x0800 ? "Up" : "Down");
+		FIELD("Duplex", "%s", val & 0x0400 ? "Full" : "Half");
+		FIELD("Speed", "%s",
+		      (val & 0x0300) == 0x0000 ? "10 Mbps" :
+		      (val & 0x0300) == 0x0100 ? "100 or 200 Mbps" :
+		      (val & 0x0300) == 0x0200 ? "1000 Mbps" :
+		      (val & 0x0300) == 0x0300 ? "Reserved" : "?");
+		FIELD("EEE Enabled", "%u", !!(val & 0x0040));
+		FIELD("Transmitter Paused", "%u", !!(val & 0x0020));
+		FIELD("Flow Control", "%u", !!(val & 0x0010));
+		FIELD("Config Mode", "0x%x", val & 0x000f);
+		break;
+	case 1:
+		REG(reg, "Physical Control", val);
+		FIELD("RGMII Receive Timing Control", "%s", val & 0x8000 ? "Delay" : "Default");
+		FIELD("RGMII Transmit Timing Control", "%s", val & 0x4000 ? "Delay" : "Default");
+		FIELD("200 BASE Mode", "%s", val & 0x1000 ? "200" : "100");
+		FIELD("Flow Control's Forced value", "%u", !!(val & 0x0080));
+		FIELD("Force Flow Control", "%u", !!(val & 0x0040));
+		FIELD("Link's Forced value", "%s", val & 0x0020 ? "Up" : "Down");
+		FIELD("Force Link", "%u", !!(val & 0x0010));
+		FIELD("Duplex's Forced value", "%s", val & 0x0008 ? "Full" : "Half");
+		FIELD("Force Duplex", "%u", !!(val & 0x0004));
+		FIELD("Force Speed", "%s",
+		      (val & 0x0003) == 0x0000 ? "10 Mbps" :
+		      (val & 0x0003) == 0x0001 ? "100 or 200 Mbps" :
+		      (val & 0x0003) == 0x0002 ? "1000 Mbps" :
+		      (val & 0x0003) == 0x0003 ? "Not forced" : "?");
+		break;
+	case 2:
+		REG(reg, "Jamming Control", val);
+		break;
+	case 3:
+		REG(reg, "Switch Identifier", val);
+		break;
+	case 4:
+		REG(reg, "Port Control", val);
+		FIELD("Source Address Filtering controls", "%s",
+		      (val & 0xc000) == 0x0000 ? "Disabled" :
+		      (val & 0xc000) == 0x4000 ? "Drop On Lock" :
+		      (val & 0xc000) == 0x8000 ? "Drop On Unlock" :
+		      (val & 0xc000) == 0xc000 ? "Drop to CPU" : "?");
+		FIELD("Egress Mode", "%s",
+		      (val & 0x3000) == 0x0000 ? "Unmodified" :
+		      (val & 0x3000) == 0x1000 ? "Untagged" :
+		      (val & 0x3000) == 0x2000 ? "Tagged" :
+		      (val & 0x3000) == 0x3000 ? "Reserved" : "?");
+		FIELD("Ingress & Egress Header Mode", "%u", !!(val & 0x0800));
+		FIELD("IGMP and MLD Snooping", "%u", !!(val & 0x0400));
+		FIELD("Frame Mode", "%s",
+		      (val & 0x0300) == 0x0000 ? "Normal" :
+		      (val & 0x0300) == 0x0100 ? "DSA" :
+		      (val & 0x0300) == 0x0200 ? "Provider" :
+		      (val & 0x0300) == 0x0300 ? "Ether Type DSA" : "?");
+		FIELD("VLAN Tunnel", "%u", !!(val & 0x0080));
+		FIELD("TagIfBoth", "%u", !!(val & 0x0040));
+		FIELD("Initial Priority assignment", "%s",
+		      (val & 0x0030) == 0x0000 ? "Defaults" :
+		      (val & 0x0030) == 0x0010 ? "Tag Priority" :
+		      (val & 0x0030) == 0x0020 ? "IP Priority" :
+		      (val & 0x0030) == 0x0030 ? "Tag & IP Priority" : "?");
+		FIELD("Egress Flooding mode", "%s",
+		      (val & 0x000c) == 0x0000 ? "No unknown DA" :
+		      (val & 0x000c) == 0x0004 ? "No unknown multicast DA" :
+		      (val & 0x000c) == 0x0008 ? "No unknown unicast DA" :
+		      (val & 0x000c) == 0x000c ? "Allow unknown DA" : "?");
+		FIELD("Port State", "%s",
+		      (val & 0x0003) == 0x0000 ? "Disabled" :
+		      (val & 0x0003) == 0x0001 ? "Blocking/Listening" :
+		      (val & 0x0003) == 0x0002 ? "Learning" :
+		      (val & 0x0003) == 0x0003 ? "Forwarding" : "?");
+		break;
+	case 5:
+		REG(reg, "Port Control 1", val);
+		FIELD("Message Port", "%u", !!(val & 0x8000));
+		FIELD("Trunk Port", "%u", !!(val & 0x4000));
+		FIELD("Trunk ID", "%u", (val & 0x0f00) >> 8);
+		FIELD("FID[11:4]", "0x%.3x", (val & 0x00ff) << 4);
+		break;
+	case 6:
+		REG(reg, "Port Base VLAN Map (Header)", val);
+		FIELD("FID[3:0]", "0x%.3x", (val & 0xf000) >> 12);
+		FIELD_BITMAP("VLANTable", val & 0x007f);
+		break;
+	case 7:
+		REG(reg, "Default VLAN ID & Priority", val);
+		FIELD("Default Priority", "0x%x", (val & 0xe000) >> 13);
+		FIELD("Force to use Default VID", "%u", !!(val & 0x1000));
+		FIELD("Default VLAN Identifier", "%u", val & 0x0fff);
+		break;
+	case 8:
+		REG(reg, "Port Control 2", val);
+		FIELD("Force good FCS in the frame", "%u", !!(val & 0x8000));
+		FIELD("Jumbo Mode", "%s",
+		      (val & 0x3000) == 0x0000 ? "1522" :
+		      (val & 0x3000) == 0x1000 ? "2048" :
+		      (val & 0x3000) == 0x2000 ? "10240" :
+		      (val & 0x3000) == 0x3000 ? "Reserved" : "?");
+		FIELD("802.1QMode", "%s",
+		      (val & 0x0c00) == 0x0000 ? "Disabled" :
+		      (val & 0x0c00) == 0x0400 ? "Fallback" :
+		      (val & 0x0c00) == 0x0800 ? "Check" :
+		      (val & 0x0c00) == 0x0c00 ? "Secure" : "?");
+		FIELD("Discard Tagged Frames", "%u", !!(val & 0x0200));
+		FIELD("Discard Untagged Frames", "%u", !!(val & 0x0100));
+		FIELD("Map using DA hits", "%u", !!(val & 0x0080));
+		FIELD("ARP Mirror enable", "%u", !!(val & 0x0040));
+		FIELD("Egress Monitor Source Port", "%u", !!(val & 0x0020));
+		FIELD("Ingress Monitor Source Port", "%u", !!(val & 0x0010));
+		FIELD("Use Default Queue Priority", "%u", !!(val & 0x0008));
+		FIELD("Default Queue Priority", "0x%x", (val & 0x0006) >> 1);
+		break;
+	case 9:
+		REG(reg, "Egress Rate Control", val);
+		break;
+	case 10:
+		REG(reg, "Egress Rate Control 2", val);
+		break;
+	case 11:
+		REG(reg, "Port Association Vector", val);
+		break;
+	case 12:
+		REG(reg, "Port ATU Control", val);
+		break;
+	case 13:
+		REG(reg, "Override", val);
+		break;
+	case 14:
+		REG(reg, "Policy Control", val);
+		break;
+	case 15:
+		REG(reg, "Port Ether Type", val);
+		break;
+	case 16:
+		REG(reg, "InDiscardsLo Frame Counter", val);
+		break;
+	case 17:
+		REG(reg, "InDiscardsHi Frame Counter", val);
+		break;
+	case 18:
+		REG(reg, "InFiltered/TcamCtr Frame Counter", val);
+		break;
+	case 19:
+		REG(reg, "Rx Frame Counter", val);
+		break;
+	case 22:
+		REG(reg, "LED Control", val);
+		break;
+	case 24:
+		REG(reg, "Tag Remap 0-3", val);
+		break;
+	case 25:
+		REG(reg, "Tag Remap 4-7", val);
+		break;
+	case 27:
+		REG(reg, "Queue Counters", val);
+		break;
+	default:
+		REG(reg, "Reserved", val);
+		break;
+	}
+};
+
+static void dsa_mv88e6390(int reg, u16 val)
+{
+	switch (reg) {
+	case 0:
+		REG(reg, "Port Status", val);
+		FIELD("Transmit Pause Enable bit", "%u", !!(val & 0x8000));
+		FIELD("Receive Pause Enable bit", "%u", !!(val & 0x4000));
+		FIELD("802.3 PHY Detected", "%u", !!(val & 0x1000));
+		FIELD("Link Status", "%s", val & 0x0800 ? "Up" : "Down");
+		FIELD("Duplex", "%s", val & 0x0400 ? "Full" : "Half");
+		FIELD("Speed", "%s",
+		      (val & 0x0300) == 0x0000 ? "10 Mbps" :
+		      (val & 0x0300) == 0x0100 ? "100 or 200 Mbps" :
+		      (val & 0x0300) == 0x0200 ? "1000 Mbps" :
+		      (val & 0x0300) == 0x0300 ? "10 Gb or 2500 Mbps" : "?");
+		FIELD("Duplex Fixed", "%u", !!(val & 0x0080));
+		FIELD("EEE Enabled", "%u", !!(val & 0x0040));
+		FIELD("Transmitter Paused", "%u", !!(val & 0x0020));
+		FIELD("Flow Control", "%u", !!(val & 0x0010));
+		FIELD("Config Mode", "0x%x", val & 0x000f);
+		break;
+	case 1:
+		REG(reg, "Physical Control", val);
+		FIELD("RGMII Receive Timing Control", "%s", val & 0x8000 ? "Delay" : "Default");
+		FIELD("RGMII Transmit Timing Control", "%s", val & 0x4000 ? "Delay" : "Default");
+		FIELD("Force Speed", "%u", !!(val & 0x2000));
+		FIELD("Alternate Speed Mode", "%s", val & 0x1000 ? "Alternate" : "Normal");
+		FIELD("MII PHY Mode", "%s", val & 0x0800 ? "PHY" : "MAC");
+		FIELD("EEE force value", "%u", !!(val & 0x0200));
+		FIELD("Force EEE", "%u", !!(val & 0x0100));
+		FIELD("Link's Forced value", "%s", val & 0x0020 ? "Up" : "Down");
+		FIELD("Force Link", "%u", !!(val & 0x0010));
+		FIELD("Duplex's Forced value", "%s", val & 0x0008 ? "Full" : "Half");
+		FIELD("Force Duplex", "%u", !!(val & 0x0004));
+		FIELD("Force Speed", "%s",
+		      (val & 0x0003) == 0x0000 ? "10 Mbps" :
+		      (val & 0x0003) == 0x0001 ? "100 or 200 Mbps" :
+		      (val & 0x0003) == 0x0002 ? "1000 Mbps" :
+		      (val & 0x0003) == 0x0003 ? "10 Gb or 2500 Mbps" : "?");
+		break;
+	case 2:
+		REG(reg, "Flow Control", val);
+		break;
+	case 3:
+		REG(reg, "Switch Identifier", val);
+		break;
+	case 4:
+		REG(reg, "Port Control", val);
+		FIELD("Source Address Filtering controls", "%s",
+		      (val & 0xc000) == 0x0000 ? "Disabled" :
+		      (val & 0xc000) == 0x4000 ? "Drop On Lock" :
+		      (val & 0xc000) == 0x8000 ? "Drop On Unlock" :
+		      (val & 0xc000) == 0xc000 ? "Drop to CPU" : "?");
+		FIELD("Egress Mode", "%s",
+		      (val & 0x3000) == 0x0000 ? "Unmodified" :
+		      (val & 0x3000) == 0x1000 ? "Untagged" :
+		      (val & 0x3000) == 0x2000 ? "Tagged" :
+		      (val & 0x3000) == 0x3000 ? "Reserved" : "?");
+		FIELD("Ingress & Egress Header Mode", "%u", !!(val & 0x0800));
+		FIELD("IGMP and MLD Snooping", "%u", !!(val & 0x0400));
+		FIELD("Frame Mode", "%s",
+		      (val & 0x0300) == 0x0000 ? "Normal" :
+		      (val & 0x0300) == 0x0100 ? "DSA" :
+		      (val & 0x0300) == 0x0200 ? "Provider" :
+		      (val & 0x0300) == 0x0300 ? "Ether Type DSA" : "?");
+		FIELD("VLAN Tunnel", "%u", !!(val & 0x0080));
+		FIELD("TagIfBoth", "%u", !!(val & 0x0040));
+		FIELD("Initial Priority assignment", "%s",
+		      (val & 0x0030) == 0x0000 ? "Defaults" :
+		      (val & 0x0030) == 0x0010 ? "Tag Priority" :
+		      (val & 0x0030) == 0x0020 ? "IP Priority" :
+		      (val & 0x0030) == 0x0030 ? "Tag & IP Priority" : "?");
+		FIELD("Egress Flooding mode", "%s",
+		      (val & 0x000c) == 0x0000 ? "No unknown DA" :
+		      (val & 0x000c) == 0x0004 ? "No unknown multicast DA" :
+		      (val & 0x000c) == 0x0008 ? "No unknown unicast DA" :
+		      (val & 0x000c) == 0x000c ? "Allow unknown DA" : "?");
+		FIELD("Port State", "%s",
+		      (val & 0x0003) == 0x0000 ? "Disabled" :
+		      (val & 0x0003) == 0x0001 ? "Blocking/Listening" :
+		      (val & 0x0003) == 0x0002 ? "Learning" :
+		      (val & 0x0003) == 0x0003 ? "Forwarding" : "?");
+		break;
+	case 5:
+		REG(reg, "Port Control 1", val);
+		FIELD("Message Port", "%u", !!(val & 0x8000));
+		FIELD("LAG Port", "%u", !!(val & 0x4000));
+		FIELD("VTU Page", "%u", !!(val & 0x2000));
+		FIELD("LAG ID", "%u", (val & 0x0f00) >> 8);
+		FIELD("FID[11:4]", "0x%.3x", (val & 0x00ff) << 4);
+		break;
+	case 6:
+		REG(reg, "Port Base VLAN Map (Header)", val);
+		FIELD("FID[3:0]", "0x%.3x", (val & 0xf000) >> 12);
+		FIELD("Force Mapping", "%u", !!(val & 0x0800));
+		FIELD_BITMAP("VLANTable", val & 0x007ff);
+		break;
+	case 7:
+		REG(reg, "Default VLAN ID & Priority", val);
+		FIELD("Default Priority", "0x%x", (val & 0xe000) >> 13);
+		FIELD("Force to use Default VID", "%u", !!(val & 0x1000));
+		FIELD("Default VLAN Identifier", "%u", val & 0x0fff);
+		break;
+	case 8:
+		REG(reg, "Port Control 2", val);
+		FIELD("Force good FCS in the frame", "%u", !!(val & 0x8000));
+		FIELD("Allow bad FCS", "%u", !!(val & 0x4000));
+		FIELD("Jumbo Mode", "%s",
+		      (val & 0x3000) == 0x0000 ? "1522" :
+		      (val & 0x3000) == 0x1000 ? "2048" :
+		      (val & 0x3000) == 0x2000 ? "10240" :
+		      (val & 0x3000) == 0x3000 ? "Reserved" : "?");
+		FIELD("802.1QMode", "%s",
+		      (val & 0x0c00) == 0x0000 ? "Disabled" :
+		      (val & 0x0c00) == 0x0400 ? "Fallback" :
+		      (val & 0x0c00) == 0x0800 ? "Check" :
+		      (val & 0x0c00) == 0x0c00 ? "Secure" : "?");
+		FIELD("Discard Tagged Frames", "%u", !!(val & 0x0200));
+		FIELD("Discard Untagged Frames", "%u", !!(val & 0x0100));
+		FIELD("Map using DA hits", "%u", !!(val & 0x0080));
+		FIELD("ARP Mirror enable", "%u", !!(val & 0x0040));
+		FIELD("Egress Monitor Source Port", "%u", !!(val & 0x0020));
+		FIELD("Ingress Monitor Source Port", "%u", !!(val & 0x0010));
+		FIELD("Allow VID of Zero", "%u", !!(val & 0x0008));
+		FIELD("Default Queue Priority", "0x%x", val & 0x0007);
+		break;
+	case 9:
+		REG(reg, "Egress Rate Control", val);
+		break;
+	case 10:
+		REG(reg, "Egress Rate Control 2", val);
+		break;
+	case 11:
+		REG(reg, "Port Association Vector", val);
+		break;
+	case 12:
+		REG(reg, "Port ATU Control", val);
+		break;
+	case 13:
+		REG(reg, "Override", val);
+		break;
+	case 14:
+		REG(reg, "Policy Control", val);
+		break;
+	case 15:
+		REG(reg, "Port Ether Type", val);
+		break;
+	case 22:
+		REG(reg, "LED Control", val);
+		break;
+	case 23:
+		REG(reg, "IP Priority Mapping Table", val);
+		break;
+	case 24:
+		REG(reg, "IEEE Priority Mapping Table", val);
+		break;
+	case 25:
+		REG(reg, "Port Control 3", val);
+		break;
+	case 27:
+		REG(reg, "Queue Counters", val);
+		break;
+	case 28:
+		REG(reg, "Queue Control", val);
+		break;
+	case 30:
+		REG(reg, "Cut Through Control", val);
+		break;
+	case 31:
+		REG(reg, "Debug Counters", val);
+		break;
+	default:
+		REG(reg, "Reserved", val);
+		break;
+	}
+};
+
+struct dsa_mv88e6xxx_switch {
+	void (*dump)(int reg, u16 val);
+	const char *name;
+	u16 id;
+};
+
+static const struct dsa_mv88e6xxx_switch dsa_mv88e6xxx_switches[] = {
+	{ .id = 0x04a0, .name = "88E6085 ", .dump = NULL },
+	{ .id = 0x0950, .name = "88E6095 ", .dump = NULL },
+	{ .id = 0x0990, .name = "88E6097 ", .dump = NULL },
+	{ .id = 0x0a00, .name = "88E6190X", .dump = dsa_mv88e6390 },
+	{ .id = 0x0a10, .name = "88E6390X", .dump = dsa_mv88e6390 },
+	{ .id = 0x1060, .name = "88E6131 ", .dump = NULL },
+	{ .id = 0x1150, .name = "88E6320 ", .dump = NULL },
+	{ .id = 0x1210, .name = "88E6123 ", .dump = dsa_mv88e6161 },
+	{ .id = 0x1610, .name = "88E6161 ", .dump = dsa_mv88e6161 },
+	{ .id = 0x1650, .name = "88E6165 ", .dump = NULL },
+	{ .id = 0x1710, .name = "88E6171 ", .dump = NULL },
+	{ .id = 0x1720, .name = "88E6172 ", .dump = dsa_mv88e6352 },
+	{ .id = 0x1750, .name = "88E6175 ", .dump = NULL },
+	{ .id = 0x1760, .name = "88E6176 ", .dump = dsa_mv88e6352 },
+	{ .id = 0x1900, .name = "88E6190 ", .dump = dsa_mv88e6390 },
+	{ .id = 0x1910, .name = "88E6191 ", .dump = NULL },
+	{ .id = 0x1a70, .name = "88E6185 ", .dump = dsa_mv88e6185 },
+	{ .id = 0x2400, .name = "88E6240 ", .dump = dsa_mv88e6352 },
+	{ .id = 0x2900, .name = "88E6290 ", .dump = dsa_mv88e6390 },
+	{ .id = 0x3100, .name = "88E6321 ", .dump = NULL },
+	{ .id = 0x3400, .name = "88E6141 ", .dump = NULL },
+	{ .id = 0x3410, .name = "88E6341 ", .dump = NULL },
+	{ .id = 0x3520, .name = "88E6352 ", .dump = dsa_mv88e6352 },
+	{ .id = 0x3710, .name = "88E6350 ", .dump = NULL },
+	{ .id = 0x3750, .name = "88E6351 ", .dump = NULL },
+	{ .id = 0x3900, .name = "88E6390 ", .dump = dsa_mv88e6390 },
+};
+
+static int dsa_mv88e6xxx_dump_regs(struct ethtool_regs *regs)
+{
+	const struct dsa_mv88e6xxx_switch *sw = NULL;
+	const u16 *data = (u16 *)regs->data;
+	u16 id;
+	int i;
+
+	/* Marvell chips have 32 per-port 16-bit registers */
+	if (regs->len < 32 * 2)
+		return 1;
+
+	id = regs->version & 0xfff0;
+
+	for (i = 0; i < ARRAY_SIZE(dsa_mv88e6xxx_switches); i++) {
+		if (id == dsa_mv88e6xxx_switches[i].id) {
+			sw = &dsa_mv88e6xxx_switches[i];
+			break;
+		}
+	}
+
+	if (!sw)
+		return 1;
+
+	printf("%s Switch Port Registers\n", sw->name);
+	printf("------------------------------\n");
+
+	for (i = 0; i < 32; i++)
+		if (sw->dump)
+			sw->dump(i, data[i]);
+		else
+			REG(i, "", data[i]);
+
+	return 0;
+}
+
+#undef FIELD_BITMAP
+#undef FIELD
+#undef REG
+
+int dsa_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		  struct ethtool_regs *regs)
+{
+	/* DSA per-driver register dump */
+	if (!dsa_mv88e6xxx_dump_regs(regs))
+		return 0;
+
+	/* Fallback to hexdump */
+	return 1;
+}
diff --git a/e100.c b/e100.c
new file mode 100644
index 0000000..540ae35
--- /dev/null
+++ b/e100.c
@@ -0,0 +1,238 @@
+/* Copyright (c) 2002 Intel Corporation */
+#include <stdio.h>
+#include "internal.h"
+
+#define D102_REV_ID		12
+
+#define MDI_MDIX_CONFIG_IS_OK	0x0010
+#define MDI_MDIX_STATUS		0x0020
+
+#define SOFT_INT            	0x0200		/* Generate a S/W interrupt */
+
+/* Interrupt masks */
+#define ALL_INT_MASK        	0x0100		/* Mask interrupts */
+#define FCP_INT_MASK        	0x0400		/* Flow Control Pause */
+#define ER_INT_MASK         	0x0800		/* Early Receive */
+#define RNR_INT_MASK        	0x1000		/* RU Not Ready */
+#define CNA_INT_MASK        	0x2000		/* CU Not Active */
+#define FR_INT_MASK         	0x4000		/* Frame Received */
+#define CX_INT_MASK         	0x8000		/* CU eXecution w/ I-bit done */
+
+/* Interrupts pending */
+#define FCP_INT_PENDING         0x0100		/* Flow Control Pause */
+#define ER_INT_PENDING          0x0200		/* Early Receive */
+#define SWI_INT_PENDING         0x0400		/* S/W generated interrupt */
+#define MDI_INT_PENDING         0x0800		/* MDI read or write done */
+#define RNR_INT_PENDING         0x1000		/* RU Became Not Ready */
+#define CNA_INT_PENDING         0x2000		/* CU Became Inactive (IDLE) */
+#define FR_INT_PENDING          0x4000		/* RU Received A Frame */
+#define CX_INT_PENDING          0x8000		/* CU Completed Action Cmd */
+
+/* Status */
+#define CU_STATUS		0x00C0
+#define RU_STATUS		0x003C
+
+/* Commands */
+#define CU_CMD			0x00F0
+#define RU_CMD			0x0007
+
+int e100_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		   struct ethtool_regs *regs)
+{
+	u32 *regs_buff = (u32 *)regs->data;
+	u8 version = (u8)(regs->version >> 24);
+	u8 rev_id = (u8)(regs->version);
+	u8 regs_len = regs->len / sizeof(u32);
+	u32 reg;
+	u16 scb_status, scb_cmd;
+
+	if (version != 1)
+		return -1;
+
+	reg = regs_buff[0];
+	scb_status = reg & 0x0000ffff;
+	scb_cmd = reg >> 16;
+	fprintf(stdout,
+		"SCB Status Word (Lower Word)             0x%04X\n",
+		scb_status);
+
+	switch ((scb_status & RU_STATUS) >> 2) {
+	case 0:
+		fprintf(stdout,
+		"      RU Status:               Idle\n");
+		break;
+	case 1:
+		fprintf(stdout,
+		"      RU Status:               Suspended\n");
+		break;
+	case 2:
+		fprintf(stdout,
+		"      RU Status:               No Resources\n");
+		break;
+	case 4:
+		fprintf(stdout,
+		"      RU Status:               Ready\n");
+		break;
+	case 9:
+		fprintf(stdout,
+		"      RU Status:               Suspended with no more RBDs\n");
+		break;
+	case 10:
+		fprintf(stdout,
+		"      RU Status:               No Resources due to no more RBDs\n");
+		break;
+	case 12:
+		fprintf(stdout,
+		"      RU Status:               Ready with no RBDs present\n");
+		break;
+	default:
+		fprintf(stdout,
+		"      RU Status:               Unknown State\n");
+		break;
+	}
+
+	switch ((scb_status & CU_STATUS) >> 6) {
+	case 0:
+		fprintf(stdout,
+		"      CU Status:               Idle\n");
+		break;
+	case 1:
+		fprintf(stdout,
+		"      CU Status:               Suspended\n");
+		break;
+        case 2:
+                fprintf(stdout,
+                "      CU Status:              Active\n");
+                break;
+	default:
+		fprintf(stdout,
+		"      CU Status:               Unknown State\n");
+		break;
+	}
+
+	fprintf(stdout,
+	        "      ---- Interrupts Pending ----\n"
+		"      Flow Control Pause:                %s\n"
+		"      Early Receive:                     %s\n"
+		"      Software Generated Interrupt:      %s\n"
+		"      MDI Done:                          %s\n"
+		"      RU Not In Ready State:             %s\n"
+		"      CU Not in Active State:            %s\n"
+		"      RU Received Frame:                 %s\n"
+		"      CU Completed Command:              %s\n",
+		scb_status & FCP_INT_PENDING     ? "yes"     : "no",
+		scb_status & ER_INT_PENDING      ? "yes"     : "no",
+		scb_status & SWI_INT_PENDING     ? "yes"     : "no",
+		scb_status & MDI_INT_PENDING     ? "yes"     : "no",
+		scb_status & RNR_INT_PENDING     ? "yes"     : "no",
+		scb_status & CNA_INT_PENDING     ? "yes"     : "no",
+		scb_status & FR_INT_PENDING      ? "yes"     : "no",
+		scb_status & CX_INT_PENDING      ? "yes"     : "no");
+
+	fprintf(stdout,
+		"SCB Command Word (Upper Word)            0x%04X\n",
+		scb_cmd);
+
+	switch (scb_cmd & RU_CMD) {
+	case 0:
+		fprintf(stdout,
+		"      RU Command:              No Command\n");
+		break;
+	case 1:
+		fprintf(stdout,
+		"      RU Command:              RU Start\n");
+		break;
+	case 2:
+		fprintf(stdout,
+		"      RU Command:              RU Resume\n");
+		break;
+	case 4:
+		fprintf(stdout,
+		"      RU Command:              RU Abort\n");
+		break;
+	case 6:
+		fprintf(stdout,
+		"      RU Command:              Load RU Base\n");
+		break;
+	default:
+		fprintf(stdout,
+		"      RU Command:              Unknown\n");
+		break;
+	}
+
+	switch ((scb_cmd & CU_CMD) >> 4) {
+	case 0:
+		fprintf(stdout,
+		"      CU Command:              No Command\n");
+		break;
+	case 1:
+		fprintf(stdout,
+		"      CU Command:              CU Start\n");
+		break;
+	case 2:
+		fprintf(stdout,
+		"      CU Command:              CU Resume\n");
+		break;
+	case 4:
+		fprintf(stdout,
+		"      CU Command:              Load Dump Counters Address\n");
+		break;
+	case 5:
+		fprintf(stdout,
+		"      CU Command:              Dump Counters\n");
+		break;
+	case 6:
+		fprintf(stdout,
+		"      CU Command:              Load CU Base\n");
+		break;
+	case 7:
+		fprintf(stdout,
+		"      CU Command:              Dump & Reset Counters\n");
+		break;
+	default:
+		fprintf(stdout,
+		"      CU Command:              Unknown\n");
+		break;
+	}
+
+	fprintf(stdout,
+		"      Software Generated Interrupt:      %s\n",
+		scb_cmd & SOFT_INT     ? "yes"     : "no");
+
+	fprintf(stdout,
+	        "      ---- Interrupts Masked ----\n"
+		"      ALL Interrupts:                    %s\n"
+		"      Flow Control Pause:                %s\n"
+		"      Early Receive:                     %s\n"
+		"      RU Not In Ready State:             %s\n"
+		"      CU Not in Active State:            %s\n"
+		"      RU Received Frame:                 %s\n"
+		"      CU Completed Command:              %s\n",
+		scb_cmd & ALL_INT_MASK     ? "yes"     : "no",
+		scb_cmd & FCP_INT_MASK     ? "yes"     : "no",
+		scb_cmd & ER_INT_MASK      ? "yes"     : "no",
+		scb_cmd & RNR_INT_MASK     ? "yes"     : "no",
+		scb_cmd & CNA_INT_MASK     ? "yes"     : "no",
+		scb_cmd & FR_INT_MASK      ? "yes"     : "no",
+		scb_cmd & CX_INT_MASK      ? "yes"     : "no");
+
+	if(regs_len > 1) {
+		fprintf(stdout, "MDI/MDI-X Status:                        ");
+		if(rev_id < D102_REV_ID)
+			fprintf(stdout, "MDI\n");
+		else {
+			u16 ctrl_reg = regs_buff[1];
+
+			if(ctrl_reg & MDI_MDIX_CONFIG_IS_OK) {
+				if(ctrl_reg & MDI_MDIX_STATUS)
+					fprintf(stdout, "MDI-X\n");
+				else
+					fprintf(stdout, "MDI\n");
+			} else
+				fprintf(stdout, "Unknown\n");
+		}
+	}
+
+	return 0;
+}
+
diff --git a/e1000.c b/e1000.c
new file mode 100644
index 0000000..91e5bc1
--- /dev/null
+++ b/e1000.c
@@ -0,0 +1,640 @@
+/* Copyright (c) 2002 Intel Corporation */
+#include <stdio.h>
+#include "internal.h"
+
+/* Register Bit Masks */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed  50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed  66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */
+
+/* Receive Control */
+#define E1000_RCTL_RST          0x00000001      /* Software reset */
+#define E1000_RCTL_EN           0x00000002      /* enable */
+#define E1000_RCTL_SBP          0x00000004      /* store bad packet */
+#define E1000_RCTL_UPE          0x00000008      /* unicast promiscuous enable */
+#define E1000_RCTL_MPE          0x00000010      /* multicast promiscuous enab */
+#define E1000_RCTL_LPE          0x00000020      /* long packet enable */
+#define E1000_RCTL_LBM_NO       0x00000000      /* no loopback mode */
+#define E1000_RCTL_LBM_MAC      0x00000040      /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP      0x00000080      /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR     0x000000C0      /* tcvr loopback mode */
+#define E1000_RCTL_RDMTS        0x00000300      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_HALF   0x00000000      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT   0x00000100      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH  0x00000200      /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT     12              /* multicast offset shift */
+#define E1000_RCTL_MO_0         0x00000000      /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1         0x00001000      /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2         0x00002000      /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3         0x00003000      /* multicast offset 15:4 */
+#define E1000_RCTL_MDR          0x00004000      /* multicast desc ring 0 */
+#define E1000_RCTL_BAM          0x00008000      /* broadcast enable */
+#define E1000_RCTL_SZ           0x00030000      /* rx buffer size */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048      0x00000000      /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024      0x00010000      /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512       0x00020000      /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256       0x00030000      /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384     0x00010000      /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192      0x00020000      /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096      0x00030000      /* rx buffer size 4096 */
+#define E1000_RCTL_VFE          0x00040000      /* vlan filter enable */
+#define E1000_RCTL_CFIEN        0x00080000      /* canonical form enable */
+#define E1000_RCTL_CFI          0x00100000      /* canonical form indicator */
+#define E1000_RCTL_DPF          0x00400000      /* discard pause frames */
+#define E1000_RCTL_PMCF         0x00800000      /* pass MAC control frames */
+#define E1000_RCTL_BSEX         0x02000000      /* Buffer size extension */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+
+/* M88E1000 PHY Specific Status Register */
+#define M88_PSSR_JABBER             0x0001 /* 1=Jabber */
+#define M88_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
+#define M88_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+#define M88_PSSR_CABLE_LENGTH       0x0380 /* 0=<50M;1=50-80M;2=80-110M;
+                                            * 3=110-140M;4=>140M */
+#define M88_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
+#define M88_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
+#define M88_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
+#define M88_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
+#define M88_PSSR_10MBS              0x0000 /* 00=10Mbs */
+#define M88_PSSR_100MBS             0x4000 /* 01=100Mbs */
+#define M88_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+
+#define M88_PSSR_CL_0_50     (0<<7)
+#define M88_PSSR_CL_50_80    (1<<7)
+#define M88_PSSR_CL_80_110   (2<<7)
+#define M88_PSSR_CL_110_140  (3<<7)
+#define M88_PSSR_CL_140_PLUS (4<<7)
+
+/* M88E1000 PHY Specific Control Register */
+#define M88_PSCR_JABBER_DISABLE    0x0001  /* 1=Jabber Function disabled */
+#define M88_PSCR_POLARITY_REVERSAL 0x0002  /* 1=Polarity Reversal enabled */
+#define M88_PSCR_SQE_TEST          0x0004  /* 1=SQE Test enabled */
+#define M88_PSCR_CLK125_DISABLE    0x0010  /* 1=CLK125 low,
+                                            * 0=CLK125 toggling
+                                            */
+#define M88_PSCR_MDI_MASK         0x0060
+#define M88_PSCR_MDI_MANUAL_MODE  0x0000   /* MDI Crossover Mode bits 6:5 */
+                                          /* Manual MDI configuration */
+#define M88_PSCR_MDIX_MANUAL_MODE 0x0020   /* Manual MDIX configuration */
+#define M88_PSCR_AUTO_X_1000T     0x0040   /* 1000BASE-T: Auto crossover,
+                                            *  100BASE-TX/10BASE-T:
+                                            *  MDI Mode
+                                            */
+#define M88_PSCR_AUTO_X_MODE      0x0060   /* Auto crossover enabled
+                                            * all speeds.
+                                            */
+#define M88_PSCR_10BT_EXT_DIST_ENABLE 0x0080
+                                   /* 1=Enable Extended 10BASE-T distance
+                                    * (Lower 10BASE-T RX Threshold)
+                                    * 0=Normal 10BASE-T RX Threshold */
+#define M88_PSCR_MII_5BIT_ENABLE      0x0100
+                                   /* 1=5-Bit interface in 100BASE-TX
+                                    * 0=MII interface in 100BASE-TX */
+#define M88_PSCR_SCRAMBLER_DISABLE    0x0200       /* 1=Scrambler disable */
+#define M88_PSCR_FORCE_LINK_GOOD      0x0400       /* 1=Force link good */
+#define M88_PSCR_ASSERT_CRS_ON_TX     0x0800       /* 1=Assert CRS on Transmit */
+
+#define M88_PSCR_POLARITY_REVERSAL_SHIFT    1
+#define M88_PSCR_AUTO_X_MODE_SHIFT          5
+#define M88_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542                    0x1000
+#define E1000_DEV_ID_82543GC_FIBER            0x1001
+#define E1000_DEV_ID_82543GC_COPPER           0x1004
+#define E1000_DEV_ID_82544EI_COPPER           0x1008
+#define E1000_DEV_ID_82544EI_FIBER            0x1009
+#define E1000_DEV_ID_82544GC_COPPER           0x100C
+#define E1000_DEV_ID_82544GC_LOM              0x100D
+#define E1000_DEV_ID_82540EM                  0x100E
+#define E1000_DEV_ID_82540EM_LOM              0x1015
+#define E1000_DEV_ID_82540EP_LOM              0x1016
+#define E1000_DEV_ID_82540EP                  0x1017
+#define E1000_DEV_ID_82540EP_LP               0x101E
+#define E1000_DEV_ID_82545EM_COPPER           0x100F
+#define E1000_DEV_ID_82545EM_FIBER            0x1011
+#define E1000_DEV_ID_82545GM_COPPER           0x1026
+#define E1000_DEV_ID_82545GM_FIBER            0x1027
+#define E1000_DEV_ID_82545GM_SERDES           0x1028
+#define E1000_DEV_ID_82546EB_COPPER           0x1010
+#define E1000_DEV_ID_82546EB_FIBER            0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER      0x101D
+#define E1000_DEV_ID_82546GB_COPPER           0x1079
+#define E1000_DEV_ID_82546GB_FIBER            0x107A
+#define E1000_DEV_ID_82546GB_SERDES           0x107B
+#define E1000_DEV_ID_82546GB_PCIE             0x108A
+#define E1000_DEV_ID_82546GB_QUAD_COPPER      0x1099
+#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
+#define E1000_DEV_ID_82541EI                  0x1013
+#define E1000_DEV_ID_82541EI_MOBILE           0x1018
+#define E1000_DEV_ID_82541ER_LOM              0x1014
+#define E1000_DEV_ID_82541ER                  0x1078
+#define E1000_DEV_ID_82541GI                  0x1076
+#define E1000_DEV_ID_82541GI_LF               0x107C
+#define E1000_DEV_ID_82541GI_MOBILE           0x1077
+#define E1000_DEV_ID_82547EI                  0x1019
+#define E1000_DEV_ID_82547EI_MOBILE           0x101A
+#define E1000_DEV_ID_82547GI                  0x1075
+#define E1000_DEV_ID_82571EB_COPPER           0x105E
+#define E1000_DEV_ID_82571EB_FIBER            0x105F
+#define E1000_DEV_ID_82571EB_SERDES           0x1060
+#define E1000_DEV_ID_82571EB_QUAD_COPPER      0x10A4
+#define E1000_DEV_ID_82571EB_QUAD_FIBER       0x10A5
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP   0x10BC
+#define E1000_DEV_ID_82572EI_COPPER           0x107D
+#define E1000_DEV_ID_82572EI_FIBER            0x107E
+#define E1000_DEV_ID_82572EI_SERDES           0x107F
+#define E1000_DEV_ID_82572EI                  0x10B9
+#define E1000_DEV_ID_82573E                   0x108B
+#define E1000_DEV_ID_82573E_IAMT              0x108C
+#define E1000_DEV_ID_82573L                   0x109A
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT   0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT   0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT   0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT   0x10BB
+#define E1000_DEV_ID_ICH8_IGP_M_AMT           0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT             0x104A
+#define E1000_DEV_ID_ICH8_IGP_C               0x104B
+#define E1000_DEV_ID_ICH8_IFE                 0x104C
+#define E1000_DEV_ID_ICH8_IFE_GT              0x10C4
+#define E1000_DEV_ID_ICH8_IFE_G               0x10C5
+#define E1000_DEV_ID_ICH8_IGP_M               0x104D
+
+#define E1000_82542_2_0_REV_ID 2
+#define E1000_82542_2_1_REV_ID 3
+
+/* Enumerated types specific to the e1000 hardware */
+/* Media Access Controlers */
+enum e1000_mac_type {
+	e1000_undefined = 0,
+	e1000_82542,
+	e1000_82543,
+	e1000_82544,
+	e1000_82540,
+	e1000_82545,
+	e1000_82545_rev_3,
+	e1000_82546,
+	e1000_82546_rev_3,
+	e1000_82541,
+	e1000_82541_rev_2,
+	e1000_82547,
+	e1000_82547_rev_2,
+	e1000_82571,
+	e1000_82572,
+	e1000_82573,
+	e1000_80003es2lan,
+	e1000_ich8lan,
+	e1000_num_macs
+};
+
+static enum e1000_mac_type e1000_get_mac_type(u16 device_id)
+{
+	enum e1000_mac_type mac_type = e1000_undefined;
+
+	switch (device_id) {
+	case E1000_DEV_ID_82542:
+		mac_type = e1000_82542;
+		break;
+	case E1000_DEV_ID_82543GC_FIBER:
+	case E1000_DEV_ID_82543GC_COPPER:
+		mac_type = e1000_82543;
+		break;
+	case E1000_DEV_ID_82544EI_COPPER:
+	case E1000_DEV_ID_82544EI_FIBER:
+	case E1000_DEV_ID_82544GC_COPPER:
+	case E1000_DEV_ID_82544GC_LOM:
+		mac_type = e1000_82544;
+		break;
+	case E1000_DEV_ID_82540EM:
+	case E1000_DEV_ID_82540EM_LOM:
+	case E1000_DEV_ID_82540EP:
+	case E1000_DEV_ID_82540EP_LOM:
+	case E1000_DEV_ID_82540EP_LP:
+		mac_type = e1000_82540;
+		break;
+	case E1000_DEV_ID_82545EM_COPPER:
+	case E1000_DEV_ID_82545EM_FIBER:
+		mac_type = e1000_82545;
+		break;
+	case E1000_DEV_ID_82545GM_COPPER:
+	case E1000_DEV_ID_82545GM_FIBER:
+	case E1000_DEV_ID_82545GM_SERDES:
+		mac_type = e1000_82545_rev_3;
+		break;
+	case E1000_DEV_ID_82546EB_COPPER:
+	case E1000_DEV_ID_82546EB_FIBER:
+	case E1000_DEV_ID_82546EB_QUAD_COPPER:
+		mac_type = e1000_82546;
+		break;
+	case E1000_DEV_ID_82546GB_COPPER:
+	case E1000_DEV_ID_82546GB_FIBER:
+	case E1000_DEV_ID_82546GB_SERDES:
+	case E1000_DEV_ID_82546GB_PCIE:
+	case E1000_DEV_ID_82546GB_QUAD_COPPER:
+	case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
+		mac_type = e1000_82546_rev_3;
+		break;
+	case E1000_DEV_ID_82541EI:
+	case E1000_DEV_ID_82541EI_MOBILE:
+	case E1000_DEV_ID_82541ER_LOM:
+		mac_type = e1000_82541;
+		break;
+	case E1000_DEV_ID_82541ER:
+	case E1000_DEV_ID_82541GI:
+	case E1000_DEV_ID_82541GI_LF:
+	case E1000_DEV_ID_82541GI_MOBILE:
+		mac_type = e1000_82541_rev_2;
+		break;
+	case E1000_DEV_ID_82547EI:
+	case E1000_DEV_ID_82547EI_MOBILE:
+		mac_type = e1000_82547;
+		break;
+	case E1000_DEV_ID_82547GI:
+		mac_type = e1000_82547_rev_2;
+		break;
+	case E1000_DEV_ID_82571EB_COPPER:
+	case E1000_DEV_ID_82571EB_FIBER:
+	case E1000_DEV_ID_82571EB_SERDES:
+	case E1000_DEV_ID_82571EB_QUAD_COPPER:
+	case E1000_DEV_ID_82571EB_QUAD_FIBER:
+	case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
+		mac_type = e1000_82571;
+		break;
+	case E1000_DEV_ID_82572EI:
+	case E1000_DEV_ID_82572EI_COPPER:
+	case E1000_DEV_ID_82572EI_FIBER:
+	case E1000_DEV_ID_82572EI_SERDES:
+		mac_type = e1000_82572;
+		break;
+	case E1000_DEV_ID_82573E:
+	case E1000_DEV_ID_82573E_IAMT:
+	case E1000_DEV_ID_82573L:
+		mac_type = e1000_82573;
+		break;
+	case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
+	case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+	case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
+	case E1000_DEV_ID_80003ES2LAN_SERDES_SPT:
+		mac_type = e1000_80003es2lan;
+		break;
+	case E1000_DEV_ID_ICH8_IFE:
+	case E1000_DEV_ID_ICH8_IFE_GT:
+	case E1000_DEV_ID_ICH8_IFE_G:
+	case E1000_DEV_ID_ICH8_IGP_M:
+	case E1000_DEV_ID_ICH8_IGP_M_AMT:
+	case E1000_DEV_ID_ICH8_IGP_AMT:
+	case E1000_DEV_ID_ICH8_IGP_C:
+		mac_type = e1000_ich8lan;
+		break;
+	default:
+		/* assume old nic and attempt so user can get limited
+		 * functionality */
+		mac_type = e1000_82543;
+		break;
+	}
+
+	return mac_type;
+}
+
+int e1000_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		    struct ethtool_regs *regs)
+{
+	u32 *regs_buff = (u32 *)regs->data;
+	u16 hw_device_id = (u16)regs->version;
+	/* u8 hw_revision_id = (u8)(regs->version >> 16); */
+	u8 version = (u8)(regs->version >> 24);
+	enum e1000_mac_type mac_type;
+	u32 reg;
+
+	if (version != 1)
+		return -1;
+
+	mac_type = e1000_get_mac_type(hw_device_id);
+
+	if(mac_type == e1000_undefined)
+		return -1;
+
+	fprintf(stdout, "MAC Registers\n");
+	fprintf(stdout, "-------------\n");
+
+	/* Device control register */
+	reg = regs_buff[0];
+	fprintf(stdout,
+		"0x00000: CTRL (Device control register)  0x%08X\n"
+		"      Endian mode (buffers):             %s\n"
+		"      Link reset:                        %s\n"
+		"      Set link up:                       %s\n"
+		"      Invert Loss-Of-Signal:             %s\n"
+		"      Receive flow control:              %s\n"
+		"      Transmit flow control:             %s\n"
+		"      VLAN mode:                         %s\n",
+		reg,
+		reg & E1000_CTRL_BEM    ? "big"      : "little",
+		reg & E1000_CTRL_LRST   ? "reset"    : "normal",
+		reg & E1000_CTRL_SLU    ? "1"        : "0",
+		reg & E1000_CTRL_ILOS   ? "yes"      : "no",
+		reg & E1000_CTRL_RFCE   ? "enabled"  : "disabled",
+		reg & E1000_CTRL_TFCE   ? "enabled"  : "disabled",
+		reg & E1000_CTRL_VME    ? "enabled"  : "disabled");
+	if(mac_type >= e1000_82543) {
+	fprintf(stdout,
+		"      Auto speed detect:                 %s\n"
+		"      Speed select:                      %s\n"
+		"      Force speed:                       %s\n"
+		"      Force duplex:                      %s\n",
+		reg & E1000_CTRL_ASDE   ? "enabled"  : "disabled",
+		(reg & E1000_CTRL_SPD_SEL) == E1000_CTRL_SPD_10   ? "10Mb/s"   :
+		(reg & E1000_CTRL_SPD_SEL) == E1000_CTRL_SPD_100  ? "100Mb/s"  :
+		(reg & E1000_CTRL_SPD_SEL) == E1000_CTRL_SPD_1000 ? "1000Mb/s" :
+		"not used",
+		reg & E1000_CTRL_FRCSPD ? "yes"      : "no",
+		reg & E1000_CTRL_FRCDPX ? "yes"      : "no");
+	}
+
+	/* Device status register */
+	reg = regs_buff[1];
+	fprintf(stdout,
+		"0x00008: STATUS (Device status register) 0x%08X\n"
+		"      Duplex:                            %s\n"
+		"      Link up:                           %s\n",
+		reg,
+		reg & E1000_STATUS_FD      ? "full"        : "half",
+		reg & E1000_STATUS_LU      ? "link config" : "no link config");
+	if (mac_type >= e1000_82571) {
+	fprintf(stdout,
+		"      TBI mode:                          %s\n"
+		"      Link speed:                        %s\n"
+		"      Bus type:                          %s\n"
+		"      Port number:                       %s\n",
+		reg & E1000_STATUS_TBIMODE ? "enabled"     : "disabled",
+		(reg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_10   ?
+		"10Mb/s" :
+		(reg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_100  ?
+		"100Mb/s" :
+		(reg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_1000 ?
+		"1000Mb/s" : "not used",
+		"PCI Express",
+		(reg & E1000_STATUS_FUNC_MASK) == 0 ? "0" : "1");
+	}
+	else if (mac_type >= e1000_82543) {
+	fprintf(stdout,
+		"      TBI mode:                          %s\n"
+		"      Link speed:                        %s\n"
+		"      Bus type:                          %s\n"
+		"      Bus speed:                         %s\n"
+		"      Bus width:                         %s\n",
+		reg & E1000_STATUS_TBIMODE ? "enabled"     : "disabled",
+		(reg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_10   ?
+		"10Mb/s" :
+		(reg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_100  ?
+		"100Mb/s" :
+		(reg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_1000 ?
+		"1000Mb/s" : "not used",
+		(reg & E1000_STATUS_PCIX_MODE) ? "PCI-X" : "PCI",
+		(reg & E1000_STATUS_PCIX_MODE) ?
+			((reg & E1000_STATUS_PCIX_SPEED_133) ? "133MHz" :
+			(reg & E1000_STATUS_PCIX_SPEED_100) ? "100MHz" :
+			"66MHz")	       :
+			((reg & E1000_STATUS_PCI66) ? "66MHz" : "33MHz"),
+		(reg & E1000_STATUS_BUS64) ? "64-bit" : "32-bit");
+	}
+
+	/* Receive control register */
+	reg = regs_buff[2];
+	fprintf(stdout,
+		"0x00100: RCTL (Receive control register) 0x%08X\n"
+		"      Receiver:                          %s\n"
+		"      Store bad packets:                 %s\n"
+		"      Unicast promiscuous:               %s\n"
+		"      Multicast promiscuous:             %s\n"
+		"      Long packet:                       %s\n"
+		"      Descriptor minimum threshold size: %s\n"
+		"      Broadcast accept mode:             %s\n"
+		"      VLAN filter:                       %s\n"
+		"      Canonical form indicator:          %s\n"
+		"      Discard pause frames:              %s\n"
+		"      Pass MAC control frames:           %s\n",
+		reg,
+		reg & E1000_RCTL_EN      ? "enabled"  : "disabled",
+		reg & E1000_RCTL_SBP     ? "enabled"  : "disabled",
+		reg & E1000_RCTL_UPE     ? "enabled"  : "disabled",
+		reg & E1000_RCTL_MPE     ? "enabled"  : "disabled",
+		reg & E1000_RCTL_LPE     ? "enabled"  : "disabled",
+		(reg & E1000_RCTL_RDMTS) == E1000_RCTL_RDMTS_HALF  ? "1/2" :
+		(reg & E1000_RCTL_RDMTS) == E1000_RCTL_RDMTS_QUAT  ? "1/4" :
+		(reg & E1000_RCTL_RDMTS) == E1000_RCTL_RDMTS_EIGTH ? "1/8" :
+		"reserved",
+		reg & E1000_RCTL_BAM     ? "accept"   : "ignore",
+		reg & E1000_RCTL_VFE     ? "enabled"  : "disabled",
+		reg & E1000_RCTL_CFIEN   ? "enabled"  : "disabled",
+		reg & E1000_RCTL_DPF     ? "ignored"  : "filtered",
+		reg & E1000_RCTL_PMCF    ? "pass"     : "don't pass");
+	if(mac_type >= e1000_82543) {
+	fprintf(stdout,
+		"      Receive buffer size:               %s\n",
+		reg & E1000_RCTL_BSEX    ?
+			((reg & E1000_RCTL_SZ)==E1000_RCTL_SZ_16384 ? "16384" :
+			 (reg & E1000_RCTL_SZ)==E1000_RCTL_SZ_8192  ? "8192"  :
+			 (reg & E1000_RCTL_SZ)==E1000_RCTL_SZ_4096  ? "4096"  :
+			 "reserved")     :
+			((reg & E1000_RCTL_SZ)==E1000_RCTL_SZ_2048  ? "2048"  :
+			 (reg & E1000_RCTL_SZ)==E1000_RCTL_SZ_1024  ? "1024"  :
+			 (reg & E1000_RCTL_SZ)==E1000_RCTL_SZ_512   ? "512"   :
+			 "256"));
+	} else {
+	fprintf(stdout,
+		"      Receive buffer size:               %s\n",
+		(reg & E1000_RCTL_SZ) == E1000_RCTL_SZ_2048  ? "2048"  :
+		(reg & E1000_RCTL_SZ) == E1000_RCTL_SZ_1024  ? "1024"  :
+		(reg & E1000_RCTL_SZ) == E1000_RCTL_SZ_512   ? "512"   :
+		"256");
+	}
+
+	/* Receive descriptor registers */
+	fprintf(stdout,
+		"0x02808: RDLEN (Receive desc length)     0x%08X\n",
+		regs_buff[3]);
+	fprintf(stdout,
+		"0x02810: RDH   (Receive desc head)       0x%08X\n",
+		regs_buff[4]);
+	fprintf(stdout,
+		"0x02818: RDT   (Receive desc tail)       0x%08X\n",
+		regs_buff[5]);
+	fprintf(stdout,
+		"0x02820: RDTR  (Receive delay timer)     0x%08X\n",
+		regs_buff[6]);
+
+	/* Transmit control register */
+	reg = regs_buff[7];
+	fprintf(stdout,
+		"0x00400: TCTL (Transmit ctrl register)   0x%08X\n"
+		"      Transmitter:                       %s\n"
+		"      Pad short packets:                 %s\n"
+		"      Software XOFF Transmission:        %s\n",
+		reg,
+		reg & E1000_TCTL_EN      ? "enabled"  : "disabled",
+		reg & E1000_TCTL_PSP     ? "enabled"  : "disabled",
+		reg & E1000_TCTL_SWXOFF  ? "enabled"  : "disabled");
+	if(mac_type >= e1000_82543) {
+	fprintf(stdout,
+		"      Re-transmit on late collision:     %s\n",
+		reg & E1000_TCTL_RTLC    ? "enabled"  : "disabled");
+	}
+
+	/* Transmit descriptor registers */
+	fprintf(stdout,
+		"0x03808: TDLEN (Transmit desc length)    0x%08X\n",
+		regs_buff[8]);
+	fprintf(stdout,
+		"0x03810: TDH   (Transmit desc head)      0x%08X\n",
+		regs_buff[9]);
+	fprintf(stdout,
+		"0x03818: TDT   (Transmit desc tail)      0x%08X\n",
+		regs_buff[10]);
+	fprintf(stdout,
+		"0x03820: TIDV  (Transmit delay timer)    0x%08X\n",
+		regs_buff[11]);
+
+	/* PHY type */
+	fprintf(stdout,
+		"PHY type:                                %s\n",
+		regs_buff[12] == 0 ? "M88" :
+		regs_buff[12] == 1 ? "IGP" :
+		regs_buff[12] == 2 ? "IGP2" : "unknown" );
+
+	if (0 == regs_buff[12]) {
+		reg = regs_buff[13];
+		fprintf(stdout,
+			"M88 PHY STATUS REGISTER:                 0x%08X\n"
+			"      Jabber:                            %s\n"
+			"      Polarity:                          %s\n"
+			"      Downshifted:                       %s\n"
+			"      MDI/MDIX:                          %s\n"
+			"      Cable Length Estimate:             %s meters\n"
+			"      Link State:                        %s\n"
+			"      Speed & Duplex Resolved:           %s\n"
+			"      Page Received:                     %s\n"
+			"      Duplex:                            %s\n"
+			"      Speed:                             %s mbps\n",
+			reg,
+			reg & M88_PSSR_JABBER       ? "yes"     : "no",
+			reg & M88_PSSR_REV_POLARITY ? "reverse" : "normal",
+			reg & M88_PSSR_DOWNSHIFT    ? "yes"     : "no",
+			reg & M88_PSSR_MDIX         ? "MDIX"    : "MDI",
+			((reg & M88_PSSR_CABLE_LENGTH)==M88_PSSR_CL_0_50 ? "0-50"
+				: (reg & M88_PSSR_CABLE_LENGTH)==M88_PSSR_CL_50_80 ? "50-80"
+				: (reg & M88_PSSR_CABLE_LENGTH)==M88_PSSR_CL_80_110 ? "80-110"
+				: (reg & M88_PSSR_CABLE_LENGTH)==M88_PSSR_CL_110_140? "110-140"
+				: (reg & M88_PSSR_CABLE_LENGTH)==M88_PSSR_CL_140_PLUS ? "140+"
+				: "unknown"),
+			reg & M88_PSSR_LINK              ? "Up"      : "Down",
+			reg & M88_PSSR_SPD_DPLX_RESOLVED ? "Yes"     : "No",
+			reg & M88_PSSR_PAGE_RCVD         ? "Yes"     : "No",
+			reg & M88_PSSR_DPLX              ? "Full"    : "Half",
+			((reg & M88_PSSR_SPEED)==M88_PSSR_10MBS        ? "10"
+				: (reg & M88_PSSR_SPEED)==M88_PSSR_100MBS  ? "100"
+				: (reg & M88_PSSR_SPEED)==M88_PSSR_1000MBS ? "1000"
+				: "unknown")
+		);
+
+		reg = regs_buff[17];
+		fprintf(stdout,
+			"M88 PHY CONTROL REGISTER:                0x%08X\n"
+			"      Jabber function:                   %s\n"
+			"      Auto-polarity:                     %s\n"
+			"      SQE Test:                          %s\n"
+			"      CLK125:                            %s\n"
+			"      Auto-MDIX:                         %s\n"
+			"      Extended 10Base-T Distance:        %s\n"
+			"      100Base-TX Interface:              %s\n"
+			"      Scrambler:                         %s\n"
+			"      Force Link Good:                   %s\n"
+			"      Assert CRS on Transmit:            %s\n",
+			reg,
+			reg & M88_PSCR_JABBER_DISABLE    ? "disabled" : "enabled",
+			reg & M88_PSCR_POLARITY_REVERSAL ? "enabled"  : "disabled",
+			reg & M88_PSCR_SQE_TEST          ? "enabled"  : "disabled",
+			reg & M88_PSCR_CLK125_DISABLE    ? "disabled" : "enabled",
+			((reg & M88_PSCR_MDI_MASK)==M88_PSCR_MDI_MANUAL_MODE ? "force MDI"
+				: (reg & M88_PSCR_MDI_MASK)==M88_PSCR_MDIX_MANUAL_MODE ? "force MDIX"
+				: (reg & M88_PSCR_MDI_MASK)==M88_PSCR_AUTO_X_1000T ? "1000 auto, 10/100 MDI"
+				: (reg & M88_PSCR_MDI_MASK)==M88_PSCR_AUTO_X_MODE ? "auto"
+				: "wtf"),
+			reg & M88_PSCR_10BT_EXT_DIST_ENABLE ? "enabled" : "disabled",
+			reg & M88_PSCR_MII_5BIT_ENABLE ? "5-bit" : "MII",
+			reg & M88_PSCR_SCRAMBLER_DISABLE ? "disabled" : "enabled",
+			reg & M88_PSCR_FORCE_LINK_GOOD ? "forced" : "disabled",
+			reg & M88_PSCR_ASSERT_CRS_ON_TX ? "enabled" : "disabled"
+		);
+	}
+
+	return 0;
+}
+
diff --git a/et131x.c b/et131x.c
new file mode 100644
index 0000000..1b06071
--- /dev/null
+++ b/et131x.c
@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <string.h>
+#include "internal.h"
+
+int et131x_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		     struct ethtool_regs *regs)
+{
+	u8 version = (u8)(regs->version >> 24);
+	u32 *reg = (u32 *)regs->data;
+
+	if (version != 1)
+		return -1;
+
+	fprintf(stdout, "PHY Registers\n");
+	fprintf(stdout, "0x0, Basic Control Reg          = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1, Basic Status Reg           = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x2, PHY identifier 1           = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x3, PHY identifier 2           = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x4, Auto Neg Advertisement     = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x5, Auto Neg L Partner Ability = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x6, Auto Neg Expansion         = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x7, Reserved                   = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x8, Reserved                   = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x9, 1000T Control              = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xA, 1000T Status               = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xB, Reserved                   = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xC, Reserved                   = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xD, MMD Access Control         = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xE, MMD access Data            = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xF, Extended Status            = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x10, Phy Index                 = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x11, Phy Data                  = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x12, MPhy Control              = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x13, Phy Loopback Control1     = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x14, Phy Loopback Control2     = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x15, Register Management       = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x16, Phy Config                = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x17, Phy Phy Control           = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x18, Phy Interrupt Mask        = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x19, Phy Interrupt Status      = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1A, Phy Phy Status            = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1B, Phy LED1                  = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1C, Phy LED2                  = 0x%04X\n", *reg++);
+	fprintf(stdout, "\n");
+
+	fprintf(stdout, "JAGCore Global Registers\n");
+	fprintf(stdout, "0x0, TXQ Start Address          = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1, TXQ End Address            = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x2, RXQ Start Address          = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x3, RXQ End Address            = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x4, Power Management Status    = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x5, Interrupt Status           = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x6, Interrupt Mask             = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x7, Int Alias Clear Mask       = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x8, Int Status Alias           = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x9, Software Reset             = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xA, SLV Timer                  = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xB, MSI Config                 = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xC, Loopback                   = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xD, Watchdog Timer             = 0x%04X\n", *reg++);
+	fprintf(stdout, "\n");
+
+	fprintf(stdout, "TXDMA Registers\n");
+	fprintf(stdout, "0x0, Control Status             = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1, Packet Ring Base Addr (Hi) = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x2, Packet Ring Base Addr (Lo) = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x3, Packet Ring Num Descrs     = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x4, TX Queue Write Address     = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x5, TX Queue Write Address Ext = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x6, TX Queue Read Address      = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x7, Status Writeback Addr (Hi) = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x8, Status Writeback Addr (Lo) = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x9, Service Request            = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xA, Service Complete           = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xB, Cache Read Index           = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xC, Cache Write Index          = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xD, TXDMA Error                = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xE, Descriptor Abort Count     = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xF, Payload Abort Count        = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x10, Writeback Abort Count     = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x11, Descriptor Timeout Count  = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x12, Payload Timeout Count     = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x13, Writeback Timeout Count   = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x14, Descriptor Error Count    = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x15, Payload Error Count       = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x16, Writeback Error Count     = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x17, Dropped TLP Count         = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x18, New service Complete      = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1A, Ethernet Packet Count     = 0x%04X\n", *reg++);
+	fprintf(stdout, "\n");
+
+	fprintf(stdout, "RXDMA Registers\n");
+	fprintf(stdout, "0x0, Control Status             = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1, Writeback Addr (Hi)        = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x2, Writeback Addr (Lo)        = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x3, Num Packets Done           = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x4, Max Packet Time            = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x5, RX Queue Read Addr         = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x6, RX Queue Read Address Ext  = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x7, RX Queue Write Addr        = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x8, Packet Ring Base Addr (Hi) = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x9, Packet Ring Base Addr (Lo) = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xA, Packet Ring Num Descrs     = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xE, Packet Ring Avail Offset   = 0x%04X\n", *reg++);
+	fprintf(stdout, "0xF, Packet Ring Full Offset    = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x10, Packet Ring Access Index  = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x11, Packet Ring Min Descrip   = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x12, FBR0 Address (Lo)         = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x13, FBR0 Address (Hi)         = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x14, FBR0 Num Descriptors      = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x15, FBR0 Available Offset     = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x16, FBR0 Full Offset          = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x17, FBR0 Read Index           = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x18, FBR0 Minimum Descriptors  = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x19, FBR1 Address (Lo)         = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1A, FBR1 Address (Hi)         = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1B, FBR1 Num Descriptors      = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1C, FBR1 Available Offset     = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1D, FBR1 Full Offset          = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1E, FBR1 Read Index           = 0x%04X\n", *reg++);
+	fprintf(stdout, "0x1F, FBR1 Minimum Descriptors  = 0x%04X\n", *reg++);
+	fprintf(stdout, "\n");
+	return 0;
+}
diff --git a/ethtool-copy.h b/ethtool-copy.h
new file mode 100644
index 0000000..9afd2e6
--- /dev/null
+++ b/ethtool-copy.h
@@ -0,0 +1,1889 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * ethtool.h: Defines for Linux ethtool.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
+ * Copyright 2001 Jeff Garzik <jgarzik@pobox.com>
+ * Portions Copyright 2001 Sun Microsystems (thockin@sun.com)
+ * Portions Copyright 2002 Intel (eli.kupermann@intel.com,
+ *                                christopher.leech@intel.com,
+ *                                scott.feldman@intel.com)
+ * Portions Copyright (C) Sun Microsystems 2008
+ */
+
+#ifndef _LINUX_ETHTOOL_H
+#define _LINUX_ETHTOOL_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/if_ether.h>
+
+#include <limits.h> /* for INT_MAX */
+
+/* All structures exposed to userland should be defined such that they
+ * have the same layout for 32-bit and 64-bit userland.
+ */
+
+/**
+ * struct ethtool_cmd - DEPRECATED, link control and status
+ * This structure is DEPRECATED, please use struct ethtool_link_settings.
+ * @cmd: Command number = %ETHTOOL_GSET or %ETHTOOL_SSET
+ * @supported: Bitmask of %SUPPORTED_* flags for the link modes,
+ *	physical connectors and other link features for which the
+ *	interface supports autonegotiation or auto-detection.
+ *	Read-only.
+ * @advertising: Bitmask of %ADVERTISED_* flags for the link modes,
+ *	physical connectors and other link features that are
+ *	advertised through autonegotiation or enabled for
+ *	auto-detection.
+ * @speed: Low bits of the speed, 1Mb units, 0 to INT_MAX or SPEED_UNKNOWN
+ * @duplex: Duplex mode; one of %DUPLEX_*
+ * @port: Physical connector type; one of %PORT_*
+ * @phy_address: MDIO address of PHY (transceiver); 0 or 255 if not
+ *	applicable.  For clause 45 PHYs this is the PRTAD.
+ * @transceiver: Historically used to distinguish different possible
+ *	PHY types, but not in a consistent way.  Deprecated.
+ * @autoneg: Enable/disable autonegotiation and auto-detection;
+ *	either %AUTONEG_DISABLE or %AUTONEG_ENABLE
+ * @mdio_support: Bitmask of %ETH_MDIO_SUPPORTS_* flags for the MDIO
+ *	protocols supported by the interface; 0 if unknown.
+ *	Read-only.
+ * @maxtxpkt: Historically used to report TX IRQ coalescing; now
+ *	obsoleted by &struct ethtool_coalesce.  Read-only; deprecated.
+ * @maxrxpkt: Historically used to report RX IRQ coalescing; now
+ *	obsoleted by &struct ethtool_coalesce.  Read-only; deprecated.
+ * @speed_hi: High bits of the speed, 1Mb units, 0 to INT_MAX or SPEED_UNKNOWN
+ * @eth_tp_mdix: Ethernet twisted-pair MDI(-X) status; one of
+ *	%ETH_TP_MDI_*.  If the status is unknown or not applicable, the
+ *	value will be %ETH_TP_MDI_INVALID.  Read-only.
+ * @eth_tp_mdix_ctrl: Ethernet twisted pair MDI(-X) control; one of
+ *	%ETH_TP_MDI_*.  If MDI(-X) control is not implemented, reads
+ *	yield %ETH_TP_MDI_INVALID and writes may be ignored or rejected.
+ *	When written successfully, the link should be renegotiated if
+ *	necessary.
+ * @lp_advertising: Bitmask of %ADVERTISED_* flags for the link modes
+ *	and other link features that the link partner advertised
+ *	through autonegotiation; 0 if unknown or not applicable.
+ *	Read-only.
+ *
+ * The link speed in Mbps is split between @speed and @speed_hi.  Use
+ * the ethtool_cmd_speed() and ethtool_cmd_speed_set() functions to
+ * access it.
+ *
+ * If autonegotiation is disabled, the speed and @duplex represent the
+ * fixed link mode and are writable if the driver supports multiple
+ * link modes.  If it is enabled then they are read-only; if the link
+ * is up they represent the negotiated link mode; if the link is down,
+ * the speed is 0, %SPEED_UNKNOWN or the highest enabled speed and
+ * @duplex is %DUPLEX_UNKNOWN or the best enabled duplex mode.
+ *
+ * Some hardware interfaces may have multiple PHYs and/or physical
+ * connectors fitted or do not allow the driver to detect which are
+ * fitted.  For these interfaces @port and/or @phy_address may be
+ * writable, possibly dependent on @autoneg being %AUTONEG_DISABLE.
+ * Otherwise, attempts to write different values may be ignored or
+ * rejected.
+ *
+ * Users should assume that all fields not marked read-only are
+ * writable and subject to validation by the driver.  They should use
+ * %ETHTOOL_GSET to get the current values before making specific
+ * changes and then applying them with %ETHTOOL_SSET.
+ *
+ * Deprecated fields should be ignored by both users and drivers.
+ */
+struct ethtool_cmd {
+	__u32	cmd;
+	__u32	supported;
+	__u32	advertising;
+	__u16	speed;
+	__u8	duplex;
+	__u8	port;
+	__u8	phy_address;
+	__u8	transceiver;
+	__u8	autoneg;
+	__u8	mdio_support;
+	__u32	maxtxpkt;
+	__u32	maxrxpkt;
+	__u16	speed_hi;
+	__u8	eth_tp_mdix;
+	__u8	eth_tp_mdix_ctrl;
+	__u32	lp_advertising;
+	__u32	reserved[2];
+};
+
+static __inline__ void ethtool_cmd_speed_set(struct ethtool_cmd *ep,
+					 __u32 speed)
+{
+	ep->speed = (__u16)(speed & 0xFFFF);
+	ep->speed_hi = (__u16)(speed >> 16);
+}
+
+static __inline__ __u32 ethtool_cmd_speed(const struct ethtool_cmd *ep)
+{
+	return (ep->speed_hi << 16) | ep->speed;
+}
+
+/* Device supports clause 22 register access to PHY or peripherals
+ * using the interface defined in <linux/mii.h>.  This should not be
+ * set if there are known to be no such peripherals present or if
+ * the driver only emulates clause 22 registers for compatibility.
+ */
+#define ETH_MDIO_SUPPORTS_C22	1
+
+/* Device supports clause 45 register access to PHY or peripherals
+ * using the interface defined in <linux/mii.h> and <linux/mdio.h>.
+ * This should not be set if there are known to be no such peripherals
+ * present.
+ */
+#define ETH_MDIO_SUPPORTS_C45	2
+
+#define ETHTOOL_FWVERS_LEN	32
+#define ETHTOOL_BUSINFO_LEN	32
+#define ETHTOOL_EROMVERS_LEN	32
+
+/**
+ * struct ethtool_drvinfo - general driver and device information
+ * @cmd: Command number = %ETHTOOL_GDRVINFO
+ * @driver: Driver short name.  This should normally match the name
+ *	in its bus driver structure (e.g. pci_driver::name).  Must
+ *	not be an empty string.
+ * @version: Driver version string; may be an empty string
+ * @fw_version: Firmware version string; may be an empty string
+ * @erom_version: Expansion ROM version string; may be an empty string
+ * @bus_info: Device bus address.  This should match the dev_name()
+ *	string for the underlying bus device, if there is one.  May be
+ *	an empty string.
+ * @n_priv_flags: Number of flags valid for %ETHTOOL_GPFLAGS and
+ *	%ETHTOOL_SPFLAGS commands; also the number of strings in the
+ *	%ETH_SS_PRIV_FLAGS set
+ * @n_stats: Number of u64 statistics returned by the %ETHTOOL_GSTATS
+ *	command; also the number of strings in the %ETH_SS_STATS set
+ * @testinfo_len: Number of results returned by the %ETHTOOL_TEST
+ *	command; also the number of strings in the %ETH_SS_TEST set
+ * @eedump_len: Size of EEPROM accessible through the %ETHTOOL_GEEPROM
+ *	and %ETHTOOL_SEEPROM commands, in bytes
+ * @regdump_len: Size of register dump returned by the %ETHTOOL_GREGS
+ *	command, in bytes
+ *
+ * Users can use the %ETHTOOL_GSSET_INFO command to get the number of
+ * strings in any string set (from Linux 2.6.34).
+ *
+ * Drivers should set at most @driver, @version, @fw_version and
+ * @bus_info in their get_drvinfo() implementation.  The ethtool
+ * core fills in the other fields using other driver operations.
+ */
+struct ethtool_drvinfo {
+	__u32	cmd;
+	char	driver[32];
+	char	version[32];
+	char	fw_version[ETHTOOL_FWVERS_LEN];
+	char	bus_info[ETHTOOL_BUSINFO_LEN];
+	char	erom_version[ETHTOOL_EROMVERS_LEN];
+	char	reserved2[12];
+	__u32	n_priv_flags;
+	__u32	n_stats;
+	__u32	testinfo_len;
+	__u32	eedump_len;
+	__u32	regdump_len;
+};
+
+#define SOPASS_MAX	6
+
+/**
+ * struct ethtool_wolinfo - Wake-On-Lan configuration
+ * @cmd: Command number = %ETHTOOL_GWOL or %ETHTOOL_SWOL
+ * @supported: Bitmask of %WAKE_* flags for supported Wake-On-Lan modes.
+ *	Read-only.
+ * @wolopts: Bitmask of %WAKE_* flags for enabled Wake-On-Lan modes.
+ * @sopass: SecureOn(tm) password; meaningful only if %WAKE_MAGICSECURE
+ *	is set in @wolopts.
+ */
+struct ethtool_wolinfo {
+	__u32	cmd;
+	__u32	supported;
+	__u32	wolopts;
+	__u8	sopass[SOPASS_MAX];
+};
+
+/* for passing single values */
+struct ethtool_value {
+	__u32	cmd;
+	__u32	data;
+};
+
+#define PFC_STORM_PREVENTION_AUTO	0xffff
+#define PFC_STORM_PREVENTION_DISABLE	0
+
+enum tunable_id {
+	ETHTOOL_ID_UNSPEC,
+	ETHTOOL_RX_COPYBREAK,
+	ETHTOOL_TX_COPYBREAK,
+	ETHTOOL_PFC_PREVENTION_TOUT, /* timeout in msecs */
+	/*
+	 * Add your fresh new tunable attribute above and remember to update
+	 * tunable_strings[] in net/core/ethtool.c
+	 */
+	__ETHTOOL_TUNABLE_COUNT,
+};
+
+enum tunable_type_id {
+	ETHTOOL_TUNABLE_UNSPEC,
+	ETHTOOL_TUNABLE_U8,
+	ETHTOOL_TUNABLE_U16,
+	ETHTOOL_TUNABLE_U32,
+	ETHTOOL_TUNABLE_U64,
+	ETHTOOL_TUNABLE_STRING,
+	ETHTOOL_TUNABLE_S8,
+	ETHTOOL_TUNABLE_S16,
+	ETHTOOL_TUNABLE_S32,
+	ETHTOOL_TUNABLE_S64,
+};
+
+struct ethtool_tunable {
+	__u32	cmd;
+	__u32	id;
+	__u32	type_id;
+	__u32	len;
+	void	*data[0];
+};
+
+#define DOWNSHIFT_DEV_DEFAULT_COUNT	0xff
+#define DOWNSHIFT_DEV_DISABLE		0
+
+/* Time in msecs after which link is reported as down
+ * 0 = lowest time supported by the PHY
+ * 0xff = off, link down detection according to standard
+ */
+#define ETHTOOL_PHY_FAST_LINK_DOWN_ON	0
+#define ETHTOOL_PHY_FAST_LINK_DOWN_OFF	0xff
+
+/* Energy Detect Power Down (EDPD) is a feature supported by some PHYs, where
+ * the PHY's RX & TX blocks are put into a low-power mode when there is no
+ * link detected (typically cable is un-plugged). For RX, only a minimal
+ * link-detection is available, and for TX the PHY wakes up to send link pulses
+ * to avoid any lock-ups in case the peer PHY may also be running in EDPD mode.
+ *
+ * Some PHYs may support configuration of the wake-up interval for TX pulses,
+ * and some PHYs may support only disabling TX pulses entirely. For the latter
+ * a special value is required (ETHTOOL_PHY_EDPD_NO_TX) so that this can be
+ * configured from userspace (should the user want it).
+ *
+ * The interval units for TX wake-up are in milliseconds, since this should
+ * cover a reasonable range of intervals:
+ *  - from 1 millisecond, which does not sound like much of a power-saver
+ *  - to ~65 seconds which is quite a lot to wait for a link to come up when
+ *    plugging a cable
+ */
+#define ETHTOOL_PHY_EDPD_DFLT_TX_MSECS		0xffff
+#define ETHTOOL_PHY_EDPD_NO_TX			0xfffe
+#define ETHTOOL_PHY_EDPD_DISABLE		0
+
+enum phy_tunable_id {
+	ETHTOOL_PHY_ID_UNSPEC,
+	ETHTOOL_PHY_DOWNSHIFT,
+	ETHTOOL_PHY_FAST_LINK_DOWN,
+	ETHTOOL_PHY_EDPD,
+	/*
+	 * Add your fresh new phy tunable attribute above and remember to update
+	 * phy_tunable_strings[] in net/core/ethtool.c
+	 */
+	__ETHTOOL_PHY_TUNABLE_COUNT,
+};
+
+/**
+ * struct ethtool_regs - hardware register dump
+ * @cmd: Command number = %ETHTOOL_GREGS
+ * @version: Dump format version.  This is driver-specific and may
+ *	distinguish different chips/revisions.  Drivers must use new
+ *	version numbers whenever the dump format changes in an
+ *	incompatible way.
+ * @len: On entry, the real length of @data.  On return, the number of
+ *	bytes used.
+ * @data: Buffer for the register dump
+ *
+ * Users should use %ETHTOOL_GDRVINFO to find the maximum length of
+ * a register dump for the interface.  They must allocate the buffer
+ * immediately following this structure.
+ */
+struct ethtool_regs {
+	__u32	cmd;
+	__u32	version;
+	__u32	len;
+	__u8	data[0];
+};
+
+/**
+ * struct ethtool_eeprom - EEPROM dump
+ * @cmd: Command number = %ETHTOOL_GEEPROM, %ETHTOOL_GMODULEEEPROM or
+ *	%ETHTOOL_SEEPROM
+ * @magic: A 'magic cookie' value to guard against accidental changes.
+ *	The value passed in to %ETHTOOL_SEEPROM must match the value
+ *	returned by %ETHTOOL_GEEPROM for the same device.  This is
+ *	unused when @cmd is %ETHTOOL_GMODULEEEPROM.
+ * @offset: Offset within the EEPROM to begin reading/writing, in bytes
+ * @len: On entry, number of bytes to read/write.  On successful
+ *	return, number of bytes actually read/written.  In case of
+ *	error, this may indicate at what point the error occurred.
+ * @data: Buffer to read/write from
+ *
+ * Users may use %ETHTOOL_GDRVINFO or %ETHTOOL_GMODULEINFO to find
+ * the length of an on-board or module EEPROM, respectively.  They
+ * must allocate the buffer immediately following this structure.
+ */
+struct ethtool_eeprom {
+	__u32	cmd;
+	__u32	magic;
+	__u32	offset;
+	__u32	len;
+	__u8	data[0];
+};
+
+/**
+ * struct ethtool_eee - Energy Efficient Ethernet information
+ * @cmd: ETHTOOL_{G,S}EEE
+ * @supported: Mask of %SUPPORTED_* flags for the speed/duplex combinations
+ *	for which there is EEE support.
+ * @advertised: Mask of %ADVERTISED_* flags for the speed/duplex combinations
+ *	advertised as eee capable.
+ * @lp_advertised: Mask of %ADVERTISED_* flags for the speed/duplex
+ *	combinations advertised by the link partner as eee capable.
+ * @eee_active: Result of the eee auto negotiation.
+ * @eee_enabled: EEE configured mode (enabled/disabled).
+ * @tx_lpi_enabled: Whether the interface should assert its tx lpi, given
+ *	that eee was negotiated.
+ * @tx_lpi_timer: Time in microseconds the interface delays prior to asserting
+ *	its tx lpi (after reaching 'idle' state). Effective only when eee
+ *	was negotiated and tx_lpi_enabled was set.
+ */
+struct ethtool_eee {
+	__u32	cmd;
+	__u32	supported;
+	__u32	advertised;
+	__u32	lp_advertised;
+	__u32	eee_active;
+	__u32	eee_enabled;
+	__u32	tx_lpi_enabled;
+	__u32	tx_lpi_timer;
+	__u32	reserved[2];
+};
+
+/**
+ * struct ethtool_modinfo - plugin module eeprom information
+ * @cmd: %ETHTOOL_GMODULEINFO
+ * @type: Standard the module information conforms to %ETH_MODULE_SFF_xxxx
+ * @eeprom_len: Length of the eeprom
+ *
+ * This structure is used to return the information to
+ * properly size memory for a subsequent call to %ETHTOOL_GMODULEEEPROM.
+ * The type code indicates the eeprom data format
+ */
+struct ethtool_modinfo {
+	__u32   cmd;
+	__u32   type;
+	__u32   eeprom_len;
+	__u32   reserved[8];
+};
+
+/**
+ * struct ethtool_coalesce - coalescing parameters for IRQs and stats updates
+ * @cmd: ETHTOOL_{G,S}COALESCE
+ * @rx_coalesce_usecs: How many usecs to delay an RX interrupt after
+ *	a packet arrives.
+ * @rx_max_coalesced_frames: Maximum number of packets to receive
+ *	before an RX interrupt.
+ * @rx_coalesce_usecs_irq: Same as @rx_coalesce_usecs, except that
+ *	this value applies while an IRQ is being serviced by the host.
+ * @rx_max_coalesced_frames_irq: Same as @rx_max_coalesced_frames,
+ *	except that this value applies while an IRQ is being serviced
+ *	by the host.
+ * @tx_coalesce_usecs: How many usecs to delay a TX interrupt after
+ *	a packet is sent.
+ * @tx_max_coalesced_frames: Maximum number of packets to be sent
+ *	before a TX interrupt.
+ * @tx_coalesce_usecs_irq: Same as @tx_coalesce_usecs, except that
+ *	this value applies while an IRQ is being serviced by the host.
+ * @tx_max_coalesced_frames_irq: Same as @tx_max_coalesced_frames,
+ *	except that this value applies while an IRQ is being serviced
+ *	by the host.
+ * @stats_block_coalesce_usecs: How many usecs to delay in-memory
+ *	statistics block updates.  Some drivers do not have an
+ *	in-memory statistic block, and in such cases this value is
+ *	ignored.  This value must not be zero.
+ * @use_adaptive_rx_coalesce: Enable adaptive RX coalescing.
+ * @use_adaptive_tx_coalesce: Enable adaptive TX coalescing.
+ * @pkt_rate_low: Threshold for low packet rate (packets per second).
+ * @rx_coalesce_usecs_low: How many usecs to delay an RX interrupt after
+ *	a packet arrives, when the packet rate is below @pkt_rate_low.
+ * @rx_max_coalesced_frames_low: Maximum number of packets to be received
+ *	before an RX interrupt, when the packet rate is below @pkt_rate_low.
+ * @tx_coalesce_usecs_low: How many usecs to delay a TX interrupt after
+ *	a packet is sent, when the packet rate is below @pkt_rate_low.
+ * @tx_max_coalesced_frames_low: Maximum nuumber of packets to be sent before
+ *	a TX interrupt, when the packet rate is below @pkt_rate_low.
+ * @pkt_rate_high: Threshold for high packet rate (packets per second).
+ * @rx_coalesce_usecs_high: How many usecs to delay an RX interrupt after
+ *	a packet arrives, when the packet rate is above @pkt_rate_high.
+ * @rx_max_coalesced_frames_high: Maximum number of packets to be received
+ *	before an RX interrupt, when the packet rate is above @pkt_rate_high.
+ * @tx_coalesce_usecs_high: How many usecs to delay a TX interrupt after
+ *	a packet is sent, when the packet rate is above @pkt_rate_high.
+ * @tx_max_coalesced_frames_high: Maximum number of packets to be sent before
+ *	a TX interrupt, when the packet rate is above @pkt_rate_high.
+ * @rate_sample_interval: How often to do adaptive coalescing packet rate
+ *	sampling, measured in seconds.  Must not be zero.
+ *
+ * Each pair of (usecs, max_frames) fields specifies that interrupts
+ * should be coalesced until
+ *	(usecs > 0 && time_since_first_completion >= usecs) ||
+ *	(max_frames > 0 && completed_frames >= max_frames)
+ *
+ * It is illegal to set both usecs and max_frames to zero as this
+ * would cause interrupts to never be generated.  To disable
+ * coalescing, set usecs = 0 and max_frames = 1.
+ *
+ * Some implementations ignore the value of max_frames and use the
+ * condition time_since_first_completion >= usecs
+ *
+ * This is deprecated.  Drivers for hardware that does not support
+ * counting completions should validate that max_frames == !rx_usecs.
+ *
+ * Adaptive RX/TX coalescing is an algorithm implemented by some
+ * drivers to improve latency under low packet rates and improve
+ * throughput under high packet rates.  Some drivers only implement
+ * one of RX or TX adaptive coalescing.  Anything not implemented by
+ * the driver causes these values to be silently ignored.
+ *
+ * When the packet rate is below @pkt_rate_high but above
+ * @pkt_rate_low (both measured in packets per second) the
+ * normal {rx,tx}_* coalescing parameters are used.
+ */
+struct ethtool_coalesce {
+	__u32	cmd;
+	__u32	rx_coalesce_usecs;
+	__u32	rx_max_coalesced_frames;
+	__u32	rx_coalesce_usecs_irq;
+	__u32	rx_max_coalesced_frames_irq;
+	__u32	tx_coalesce_usecs;
+	__u32	tx_max_coalesced_frames;
+	__u32	tx_coalesce_usecs_irq;
+	__u32	tx_max_coalesced_frames_irq;
+	__u32	stats_block_coalesce_usecs;
+	__u32	use_adaptive_rx_coalesce;
+	__u32	use_adaptive_tx_coalesce;
+	__u32	pkt_rate_low;
+	__u32	rx_coalesce_usecs_low;
+	__u32	rx_max_coalesced_frames_low;
+	__u32	tx_coalesce_usecs_low;
+	__u32	tx_max_coalesced_frames_low;
+	__u32	pkt_rate_high;
+	__u32	rx_coalesce_usecs_high;
+	__u32	rx_max_coalesced_frames_high;
+	__u32	tx_coalesce_usecs_high;
+	__u32	tx_max_coalesced_frames_high;
+	__u32	rate_sample_interval;
+};
+
+/**
+ * struct ethtool_ringparam - RX/TX ring parameters
+ * @cmd: Command number = %ETHTOOL_GRINGPARAM or %ETHTOOL_SRINGPARAM
+ * @rx_max_pending: Maximum supported number of pending entries per
+ *	RX ring.  Read-only.
+ * @rx_mini_max_pending: Maximum supported number of pending entries
+ *	per RX mini ring.  Read-only.
+ * @rx_jumbo_max_pending: Maximum supported number of pending entries
+ *	per RX jumbo ring.  Read-only.
+ * @tx_max_pending: Maximum supported number of pending entries per
+ *	TX ring.  Read-only.
+ * @rx_pending: Current maximum number of pending entries per RX ring
+ * @rx_mini_pending: Current maximum number of pending entries per RX
+ *	mini ring
+ * @rx_jumbo_pending: Current maximum number of pending entries per RX
+ *	jumbo ring
+ * @tx_pending: Current maximum supported number of pending entries
+ *	per TX ring
+ *
+ * If the interface does not have separate RX mini and/or jumbo rings,
+ * @rx_mini_max_pending and/or @rx_jumbo_max_pending will be 0.
+ *
+ * There may also be driver-dependent minimum values for the number
+ * of entries per ring.
+ */
+struct ethtool_ringparam {
+	__u32	cmd;
+	__u32	rx_max_pending;
+	__u32	rx_mini_max_pending;
+	__u32	rx_jumbo_max_pending;
+	__u32	tx_max_pending;
+	__u32	rx_pending;
+	__u32	rx_mini_pending;
+	__u32	rx_jumbo_pending;
+	__u32	tx_pending;
+};
+
+/**
+ * struct ethtool_channels - configuring number of network channel
+ * @cmd: ETHTOOL_{G,S}CHANNELS
+ * @max_rx: Read only. Maximum number of receive channel the driver support.
+ * @max_tx: Read only. Maximum number of transmit channel the driver support.
+ * @max_other: Read only. Maximum number of other channel the driver support.
+ * @max_combined: Read only. Maximum number of combined channel the driver
+ *	support. Set of queues RX, TX or other.
+ * @rx_count: Valid values are in the range 1 to the max_rx.
+ * @tx_count: Valid values are in the range 1 to the max_tx.
+ * @other_count: Valid values are in the range 1 to the max_other.
+ * @combined_count: Valid values are in the range 1 to the max_combined.
+ *
+ * This can be used to configure RX, TX and other channels.
+ */
+
+struct ethtool_channels {
+	__u32	cmd;
+	__u32	max_rx;
+	__u32	max_tx;
+	__u32	max_other;
+	__u32	max_combined;
+	__u32	rx_count;
+	__u32	tx_count;
+	__u32	other_count;
+	__u32	combined_count;
+};
+
+/**
+ * struct ethtool_pauseparam - Ethernet pause (flow control) parameters
+ * @cmd: Command number = %ETHTOOL_GPAUSEPARAM or %ETHTOOL_SPAUSEPARAM
+ * @autoneg: Flag to enable autonegotiation of pause frame use
+ * @rx_pause: Flag to enable reception of pause frames
+ * @tx_pause: Flag to enable transmission of pause frames
+ *
+ * Drivers should reject a non-zero setting of @autoneg when
+ * autoneogotiation is disabled (or not supported) for the link.
+ *
+ * If the link is autonegotiated, drivers should use
+ * mii_advertise_flowctrl() or similar code to set the advertised
+ * pause frame capabilities based on the @rx_pause and @tx_pause flags,
+ * even if @autoneg is zero.  They should also allow the advertised
+ * pause frame capabilities to be controlled directly through the
+ * advertising field of &struct ethtool_cmd.
+ *
+ * If @autoneg is non-zero, the MAC is configured to send and/or
+ * receive pause frames according to the result of autonegotiation.
+ * Otherwise, it is configured directly based on the @rx_pause and
+ * @tx_pause flags.
+ */
+struct ethtool_pauseparam {
+	__u32	cmd;
+	__u32	autoneg;
+	__u32	rx_pause;
+	__u32	tx_pause;
+};
+
+#define ETH_GSTRING_LEN		32
+
+/**
+ * enum ethtool_stringset - string set ID
+ * @ETH_SS_TEST: Self-test result names, for use with %ETHTOOL_TEST
+ * @ETH_SS_STATS: Statistic names, for use with %ETHTOOL_GSTATS
+ * @ETH_SS_PRIV_FLAGS: Driver private flag names, for use with
+ *	%ETHTOOL_GPFLAGS and %ETHTOOL_SPFLAGS
+ * @ETH_SS_NTUPLE_FILTERS: Previously used with %ETHTOOL_GRXNTUPLE;
+ *	now deprecated
+ * @ETH_SS_FEATURES: Device feature names
+ * @ETH_SS_RSS_HASH_FUNCS: RSS hush function names
+ * @ETH_SS_PHY_STATS: Statistic names, for use with %ETHTOOL_GPHYSTATS
+ * @ETH_SS_PHY_TUNABLES: PHY tunable names
+ */
+enum ethtool_stringset {
+	ETH_SS_TEST		= 0,
+	ETH_SS_STATS,
+	ETH_SS_PRIV_FLAGS,
+	ETH_SS_NTUPLE_FILTERS,
+	ETH_SS_FEATURES,
+	ETH_SS_RSS_HASH_FUNCS,
+	ETH_SS_TUNABLES,
+	ETH_SS_PHY_STATS,
+	ETH_SS_PHY_TUNABLES,
+};
+
+/**
+ * struct ethtool_gstrings - string set for data tagging
+ * @cmd: Command number = %ETHTOOL_GSTRINGS
+ * @string_set: String set ID; one of &enum ethtool_stringset
+ * @len: On return, the number of strings in the string set
+ * @data: Buffer for strings.  Each string is null-padded to a size of
+ *	%ETH_GSTRING_LEN.
+ *
+ * Users must use %ETHTOOL_GSSET_INFO to find the number of strings in
+ * the string set.  They must allocate a buffer of the appropriate
+ * size immediately following this structure.
+ */
+struct ethtool_gstrings {
+	__u32	cmd;
+	__u32	string_set;
+	__u32	len;
+	__u8	data[0];
+};
+
+/**
+ * struct ethtool_sset_info - string set information
+ * @cmd: Command number = %ETHTOOL_GSSET_INFO
+ * @sset_mask: On entry, a bitmask of string sets to query, with bits
+ *	numbered according to &enum ethtool_stringset.  On return, a
+ *	bitmask of those string sets queried that are supported.
+ * @data: Buffer for string set sizes.  On return, this contains the
+ *	size of each string set that was queried and supported, in
+ *	order of ID.
+ *
+ * Example: The user passes in @sset_mask = 0x7 (sets 0, 1, 2) and on
+ * return @sset_mask == 0x6 (sets 1, 2).  Then @data[0] contains the
+ * size of set 1 and @data[1] contains the size of set 2.
+ *
+ * Users must allocate a buffer of the appropriate size (4 * number of
+ * sets queried) immediately following this structure.
+ */
+struct ethtool_sset_info {
+	__u32	cmd;
+	__u32	reserved;
+	__u64	sset_mask;
+	__u32	data[0];
+};
+
+/**
+ * enum ethtool_test_flags - flags definition of ethtool_test
+ * @ETH_TEST_FL_OFFLINE: if set perform online and offline tests, otherwise
+ *	only online tests.
+ * @ETH_TEST_FL_FAILED: Driver set this flag if test fails.
+ * @ETH_TEST_FL_EXTERNAL_LB: Application request to perform external loopback
+ *	test.
+ * @ETH_TEST_FL_EXTERNAL_LB_DONE: Driver performed the external loopback test
+ */
+
+enum ethtool_test_flags {
+	ETH_TEST_FL_OFFLINE	= (1 << 0),
+	ETH_TEST_FL_FAILED	= (1 << 1),
+	ETH_TEST_FL_EXTERNAL_LB	= (1 << 2),
+	ETH_TEST_FL_EXTERNAL_LB_DONE	= (1 << 3),
+};
+
+/**
+ * struct ethtool_test - device self-test invocation
+ * @cmd: Command number = %ETHTOOL_TEST
+ * @flags: A bitmask of flags from &enum ethtool_test_flags.  Some
+ *	flags may be set by the user on entry; others may be set by
+ *	the driver on return.
+ * @len: On return, the number of test results
+ * @data: Array of test results
+ *
+ * Users must use %ETHTOOL_GSSET_INFO or %ETHTOOL_GDRVINFO to find the
+ * number of test results that will be returned.  They must allocate a
+ * buffer of the appropriate size (8 * number of results) immediately
+ * following this structure.
+ */
+struct ethtool_test {
+	__u32	cmd;
+	__u32	flags;
+	__u32	reserved;
+	__u32	len;
+	__u64	data[0];
+};
+
+/**
+ * struct ethtool_stats - device-specific statistics
+ * @cmd: Command number = %ETHTOOL_GSTATS
+ * @n_stats: On return, the number of statistics
+ * @data: Array of statistics
+ *
+ * Users must use %ETHTOOL_GSSET_INFO or %ETHTOOL_GDRVINFO to find the
+ * number of statistics that will be returned.  They must allocate a
+ * buffer of the appropriate size (8 * number of statistics)
+ * immediately following this structure.
+ */
+struct ethtool_stats {
+	__u32	cmd;
+	__u32	n_stats;
+	__u64	data[0];
+};
+
+/**
+ * struct ethtool_perm_addr - permanent hardware address
+ * @cmd: Command number = %ETHTOOL_GPERMADDR
+ * @size: On entry, the size of the buffer.  On return, the size of the
+ *	address.  The command fails if the buffer is too small.
+ * @data: Buffer for the address
+ *
+ * Users must allocate the buffer immediately following this structure.
+ * A buffer size of %MAX_ADDR_LEN should be sufficient for any address
+ * type.
+ */
+struct ethtool_perm_addr {
+	__u32	cmd;
+	__u32	size;
+	__u8	data[0];
+};
+
+/* boolean flags controlling per-interface behavior characteristics.
+ * When reading, the flag indicates whether or not a certain behavior
+ * is enabled/present.  When writing, the flag indicates whether
+ * or not the driver should turn on (set) or off (clear) a behavior.
+ *
+ * Some behaviors may read-only (unconditionally absent or present).
+ * If such is the case, return EINVAL in the set-flags operation if the
+ * flag differs from the read-only value.
+ */
+enum ethtool_flags {
+	ETH_FLAG_TXVLAN		= (1 << 7),	/* TX VLAN offload enabled */
+	ETH_FLAG_RXVLAN		= (1 << 8),	/* RX VLAN offload enabled */
+	ETH_FLAG_LRO		= (1 << 15),	/* LRO is enabled */
+	ETH_FLAG_NTUPLE		= (1 << 27),	/* N-tuple filters enabled */
+	ETH_FLAG_RXHASH		= (1 << 28),
+};
+
+/* The following structures are for supporting RX network flow
+ * classification and RX n-tuple configuration. Note, all multibyte
+ * fields, e.g., ip4src, ip4dst, psrc, pdst, spi, etc. are expected to
+ * be in network byte order.
+ */
+
+/**
+ * struct ethtool_tcpip4_spec - flow specification for TCP/IPv4 etc.
+ * @ip4src: Source host
+ * @ip4dst: Destination host
+ * @psrc: Source port
+ * @pdst: Destination port
+ * @tos: Type-of-service
+ *
+ * This can be used to specify a TCP/IPv4, UDP/IPv4 or SCTP/IPv4 flow.
+ */
+struct ethtool_tcpip4_spec {
+	__be32	ip4src;
+	__be32	ip4dst;
+	__be16	psrc;
+	__be16	pdst;
+	__u8    tos;
+};
+
+/**
+ * struct ethtool_ah_espip4_spec - flow specification for IPsec/IPv4
+ * @ip4src: Source host
+ * @ip4dst: Destination host
+ * @spi: Security parameters index
+ * @tos: Type-of-service
+ *
+ * This can be used to specify an IPsec transport or tunnel over IPv4.
+ */
+struct ethtool_ah_espip4_spec {
+	__be32	ip4src;
+	__be32	ip4dst;
+	__be32	spi;
+	__u8    tos;
+};
+
+#define	ETH_RX_NFC_IP4	1
+
+/**
+ * struct ethtool_usrip4_spec - general flow specification for IPv4
+ * @ip4src: Source host
+ * @ip4dst: Destination host
+ * @l4_4_bytes: First 4 bytes of transport (layer 4) header
+ * @tos: Type-of-service
+ * @ip_ver: Value must be %ETH_RX_NFC_IP4; mask must be 0
+ * @proto: Transport protocol number; mask must be 0
+ */
+struct ethtool_usrip4_spec {
+	__be32	ip4src;
+	__be32	ip4dst;
+	__be32	l4_4_bytes;
+	__u8    tos;
+	__u8    ip_ver;
+	__u8    proto;
+};
+
+/**
+ * struct ethtool_tcpip6_spec - flow specification for TCP/IPv6 etc.
+ * @ip6src: Source host
+ * @ip6dst: Destination host
+ * @psrc: Source port
+ * @pdst: Destination port
+ * @tclass: Traffic Class
+ *
+ * This can be used to specify a TCP/IPv6, UDP/IPv6 or SCTP/IPv6 flow.
+ */
+struct ethtool_tcpip6_spec {
+	__be32	ip6src[4];
+	__be32	ip6dst[4];
+	__be16	psrc;
+	__be16	pdst;
+	__u8    tclass;
+};
+
+/**
+ * struct ethtool_ah_espip6_spec - flow specification for IPsec/IPv6
+ * @ip6src: Source host
+ * @ip6dst: Destination host
+ * @spi: Security parameters index
+ * @tclass: Traffic Class
+ *
+ * This can be used to specify an IPsec transport or tunnel over IPv6.
+ */
+struct ethtool_ah_espip6_spec {
+	__be32	ip6src[4];
+	__be32	ip6dst[4];
+	__be32	spi;
+	__u8    tclass;
+};
+
+/**
+ * struct ethtool_usrip6_spec - general flow specification for IPv6
+ * @ip6src: Source host
+ * @ip6dst: Destination host
+ * @l4_4_bytes: First 4 bytes of transport (layer 4) header
+ * @tclass: Traffic Class
+ * @l4_proto: Transport protocol number (nexthdr after any Extension Headers)
+ */
+struct ethtool_usrip6_spec {
+	__be32	ip6src[4];
+	__be32	ip6dst[4];
+	__be32	l4_4_bytes;
+	__u8    tclass;
+	__u8    l4_proto;
+};
+
+union ethtool_flow_union {
+	struct ethtool_tcpip4_spec		tcp_ip4_spec;
+	struct ethtool_tcpip4_spec		udp_ip4_spec;
+	struct ethtool_tcpip4_spec		sctp_ip4_spec;
+	struct ethtool_ah_espip4_spec		ah_ip4_spec;
+	struct ethtool_ah_espip4_spec		esp_ip4_spec;
+	struct ethtool_usrip4_spec		usr_ip4_spec;
+	struct ethtool_tcpip6_spec		tcp_ip6_spec;
+	struct ethtool_tcpip6_spec		udp_ip6_spec;
+	struct ethtool_tcpip6_spec		sctp_ip6_spec;
+	struct ethtool_ah_espip6_spec		ah_ip6_spec;
+	struct ethtool_ah_espip6_spec		esp_ip6_spec;
+	struct ethtool_usrip6_spec		usr_ip6_spec;
+	struct ethhdr				ether_spec;
+	__u8					hdata[52];
+};
+
+/**
+ * struct ethtool_flow_ext - additional RX flow fields
+ * @h_dest: destination MAC address
+ * @vlan_etype: VLAN EtherType
+ * @vlan_tci: VLAN tag control information
+ * @data: user defined data
+ *
+ * Note, @vlan_etype, @vlan_tci, and @data are only valid if %FLOW_EXT
+ * is set in &struct ethtool_rx_flow_spec @flow_type.
+ * @h_dest is valid if %FLOW_MAC_EXT is set.
+ */
+struct ethtool_flow_ext {
+	__u8		padding[2];
+	unsigned char	h_dest[ETH_ALEN];
+	__be16		vlan_etype;
+	__be16		vlan_tci;
+	__be32		data[2];
+};
+
+/**
+ * struct ethtool_rx_flow_spec - classification rule for RX flows
+ * @flow_type: Type of match to perform, e.g. %TCP_V4_FLOW
+ * @h_u: Flow fields to match (dependent on @flow_type)
+ * @h_ext: Additional fields to match
+ * @m_u: Masks for flow field bits to be matched
+ * @m_ext: Masks for additional field bits to be matched
+ *	Note, all additional fields must be ignored unless @flow_type
+ *	includes the %FLOW_EXT or %FLOW_MAC_EXT flag
+ *	(see &struct ethtool_flow_ext description).
+ * @ring_cookie: RX ring/queue index to deliver to, or %RX_CLS_FLOW_DISC
+ *	if packets should be discarded, or %RX_CLS_FLOW_WAKE if the
+ *	packets should be used for Wake-on-LAN with %WAKE_FILTER
+ * @location: Location of rule in the table.  Locations must be
+ *	numbered such that a flow matching multiple rules will be
+ *	classified according to the first (lowest numbered) rule.
+ */
+struct ethtool_rx_flow_spec {
+	__u32		flow_type;
+	union ethtool_flow_union h_u;
+	struct ethtool_flow_ext h_ext;
+	union ethtool_flow_union m_u;
+	struct ethtool_flow_ext m_ext;
+	__u64		ring_cookie;
+	__u32		location;
+};
+
+/* How rings are laid out when accessing virtual functions or
+ * offloaded queues is device specific. To allow users to do flow
+ * steering and specify these queues the ring cookie is partitioned
+ * into a 32bit queue index with an 8 bit virtual function id.
+ * This also leaves the 3bytes for further specifiers. It is possible
+ * future devices may support more than 256 virtual functions if
+ * devices start supporting PCIe w/ARI. However at the moment I
+ * do not know of any devices that support this so I do not reserve
+ * space for this at this time. If a future patch consumes the next
+ * byte it should be aware of this possibility.
+ */
+#define ETHTOOL_RX_FLOW_SPEC_RING	0x00000000FFFFFFFFLL
+#define ETHTOOL_RX_FLOW_SPEC_RING_VF	0x000000FF00000000LL
+#define ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF 32
+static __inline__ __u64 ethtool_get_flow_spec_ring(__u64 ring_cookie)
+{
+	return ETHTOOL_RX_FLOW_SPEC_RING & ring_cookie;
+}
+
+static __inline__ __u64 ethtool_get_flow_spec_ring_vf(__u64 ring_cookie)
+{
+	return (ETHTOOL_RX_FLOW_SPEC_RING_VF & ring_cookie) >>
+				ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF;
+}
+
+/**
+ * struct ethtool_rxnfc - command to get or set RX flow classification rules
+ * @cmd: Specific command number - %ETHTOOL_GRXFH, %ETHTOOL_SRXFH,
+ *	%ETHTOOL_GRXRINGS, %ETHTOOL_GRXCLSRLCNT, %ETHTOOL_GRXCLSRULE,
+ *	%ETHTOOL_GRXCLSRLALL, %ETHTOOL_SRXCLSRLDEL or %ETHTOOL_SRXCLSRLINS
+ * @flow_type: Type of flow to be affected, e.g. %TCP_V4_FLOW
+ * @data: Command-dependent value
+ * @fs: Flow classification rule
+ * @rss_context: RSS context to be affected
+ * @rule_cnt: Number of rules to be affected
+ * @rule_locs: Array of used rule locations
+ *
+ * For %ETHTOOL_GRXFH and %ETHTOOL_SRXFH, @data is a bitmask indicating
+ * the fields included in the flow hash, e.g. %RXH_IP_SRC.  The following
+ * structure fields must not be used, except that if @flow_type includes
+ * the %FLOW_RSS flag, then @rss_context determines which RSS context to
+ * act on.
+ *
+ * For %ETHTOOL_GRXRINGS, @data is set to the number of RX rings/queues
+ * on return.
+ *
+ * For %ETHTOOL_GRXCLSRLCNT, @rule_cnt is set to the number of defined
+ * rules on return.  If @data is non-zero on return then it is the
+ * size of the rule table, plus the flag %RX_CLS_LOC_SPECIAL if the
+ * driver supports any special location values.  If that flag is not
+ * set in @data then special location values should not be used.
+ *
+ * For %ETHTOOL_GRXCLSRULE, @fs.@location specifies the location of an
+ * existing rule on entry and @fs contains the rule on return; if
+ * @fs.@flow_type includes the %FLOW_RSS flag, then @rss_context is
+ * filled with the RSS context ID associated with the rule.
+ *
+ * For %ETHTOOL_GRXCLSRLALL, @rule_cnt specifies the array size of the
+ * user buffer for @rule_locs on entry.  On return, @data is the size
+ * of the rule table, @rule_cnt is the number of defined rules, and
+ * @rule_locs contains the locations of the defined rules.  Drivers
+ * must use the second parameter to get_rxnfc() instead of @rule_locs.
+ *
+ * For %ETHTOOL_SRXCLSRLINS, @fs specifies the rule to add or update.
+ * @fs.@location either specifies the location to use or is a special
+ * location value with %RX_CLS_LOC_SPECIAL flag set.  On return,
+ * @fs.@location is the actual rule location.  If @fs.@flow_type
+ * includes the %FLOW_RSS flag, @rss_context is the RSS context ID to
+ * use for flow spreading traffic which matches this rule.  The value
+ * from the rxfh indirection table will be added to @fs.@ring_cookie
+ * to choose which ring to deliver to.
+ *
+ * For %ETHTOOL_SRXCLSRLDEL, @fs.@location specifies the location of an
+ * existing rule on entry.
+ *
+ * A driver supporting the special location values for
+ * %ETHTOOL_SRXCLSRLINS may add the rule at any suitable unused
+ * location, and may remove a rule at a later location (lower
+ * priority) that matches exactly the same set of flows.  The special
+ * values are %RX_CLS_LOC_ANY, selecting any location;
+ * %RX_CLS_LOC_FIRST, selecting the first suitable location (maximum
+ * priority); and %RX_CLS_LOC_LAST, selecting the last suitable
+ * location (minimum priority).  Additional special values may be
+ * defined in future and drivers must return -%EINVAL for any
+ * unrecognised value.
+ */
+struct ethtool_rxnfc {
+	__u32				cmd;
+	__u32				flow_type;
+	__u64				data;
+	struct ethtool_rx_flow_spec	fs;
+	union {
+		__u32			rule_cnt;
+		__u32			rss_context;
+	};
+	__u32				rule_locs[0];
+};
+
+
+/**
+ * struct ethtool_rxfh_indir - command to get or set RX flow hash indirection
+ * @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR
+ * @size: On entry, the array size of the user buffer, which may be zero.
+ *	On return from %ETHTOOL_GRXFHINDIR, the array size of the hardware
+ *	indirection table.
+ * @ring_index: RX ring/queue index for each hash value
+ *
+ * For %ETHTOOL_GRXFHINDIR, a @size of zero means that only the size
+ * should be returned.  For %ETHTOOL_SRXFHINDIR, a @size of zero means
+ * the table should be reset to default values.  This last feature
+ * is not supported by the original implementations.
+ */
+struct ethtool_rxfh_indir {
+	__u32	cmd;
+	__u32	size;
+	__u32	ring_index[0];
+};
+
+/**
+ * struct ethtool_rxfh - command to get/set RX flow hash indir or/and hash key.
+ * @cmd: Specific command number - %ETHTOOL_GRSSH or %ETHTOOL_SRSSH
+ * @rss_context: RSS context identifier.  Context 0 is the default for normal
+ *	traffic; other contexts can be referenced as the destination for RX flow
+ *	classification rules.  %ETH_RXFH_CONTEXT_ALLOC is used with command
+ *	%ETHTOOL_SRSSH to allocate a new RSS context; on return this field will
+ *	contain the ID of the newly allocated context.
+ * @indir_size: On entry, the array size of the user buffer for the
+ *	indirection table, which may be zero, or (for %ETHTOOL_SRSSH),
+ *	%ETH_RXFH_INDIR_NO_CHANGE.  On return from %ETHTOOL_GRSSH,
+ *	the array size of the hardware indirection table.
+ * @key_size: On entry, the array size of the user buffer for the hash key,
+ *	which may be zero.  On return from %ETHTOOL_GRSSH, the size of the
+ *	hardware hash key.
+ * @hfunc: Defines the current RSS hash function used by HW (or to be set to).
+ *	Valid values are one of the %ETH_RSS_HASH_*.
+ * @rsvd:	Reserved for future extensions.
+ * @rss_config: RX ring/queue index for each hash value i.e., indirection table
+ *	of @indir_size __u32 elements, followed by hash key of @key_size
+ *	bytes.
+ *
+ * For %ETHTOOL_GRSSH, a @indir_size and key_size of zero means that only the
+ * size should be returned.  For %ETHTOOL_SRSSH, an @indir_size of
+ * %ETH_RXFH_INDIR_NO_CHANGE means that indir table setting is not requested
+ * and a @indir_size of zero means the indir table should be reset to default
+ * values (if @rss_context == 0) or that the RSS context should be deleted.
+ * An hfunc of zero means that hash function setting is not requested.
+ */
+struct ethtool_rxfh {
+	__u32   cmd;
+	__u32	rss_context;
+	__u32   indir_size;
+	__u32   key_size;
+	__u8	hfunc;
+	__u8	rsvd8[3];
+	__u32	rsvd32;
+	__u32   rss_config[0];
+};
+#define ETH_RXFH_CONTEXT_ALLOC		0xffffffff
+#define ETH_RXFH_INDIR_NO_CHANGE	0xffffffff
+
+/**
+ * struct ethtool_rx_ntuple_flow_spec - specification for RX flow filter
+ * @flow_type: Type of match to perform, e.g. %TCP_V4_FLOW
+ * @h_u: Flow field values to match (dependent on @flow_type)
+ * @m_u: Masks for flow field value bits to be ignored
+ * @vlan_tag: VLAN tag to match
+ * @vlan_tag_mask: Mask for VLAN tag bits to be ignored
+ * @data: Driver-dependent data to match
+ * @data_mask: Mask for driver-dependent data bits to be ignored
+ * @action: RX ring/queue index to deliver to (non-negative) or other action
+ *	(negative, e.g. %ETHTOOL_RXNTUPLE_ACTION_DROP)
+ *
+ * For flow types %TCP_V4_FLOW, %UDP_V4_FLOW and %SCTP_V4_FLOW, where
+ * a field value and mask are both zero this is treated as if all mask
+ * bits are set i.e. the field is ignored.
+ */
+struct ethtool_rx_ntuple_flow_spec {
+	__u32		 flow_type;
+	union {
+		struct ethtool_tcpip4_spec		tcp_ip4_spec;
+		struct ethtool_tcpip4_spec		udp_ip4_spec;
+		struct ethtool_tcpip4_spec		sctp_ip4_spec;
+		struct ethtool_ah_espip4_spec		ah_ip4_spec;
+		struct ethtool_ah_espip4_spec		esp_ip4_spec;
+		struct ethtool_usrip4_spec		usr_ip4_spec;
+		struct ethhdr				ether_spec;
+		__u8					hdata[72];
+	} h_u, m_u;
+
+	__u16	        vlan_tag;
+	__u16	        vlan_tag_mask;
+	__u64		data;
+	__u64		data_mask;
+
+	__s32		action;
+#define ETHTOOL_RXNTUPLE_ACTION_DROP	(-1)	/* drop packet */
+#define ETHTOOL_RXNTUPLE_ACTION_CLEAR	(-2)	/* clear filter */
+};
+
+/**
+ * struct ethtool_rx_ntuple - command to set or clear RX flow filter
+ * @cmd: Command number - %ETHTOOL_SRXNTUPLE
+ * @fs: Flow filter specification
+ */
+struct ethtool_rx_ntuple {
+	__u32					cmd;
+	struct ethtool_rx_ntuple_flow_spec	fs;
+};
+
+#define ETHTOOL_FLASH_MAX_FILENAME	128
+enum ethtool_flash_op_type {
+	ETHTOOL_FLASH_ALL_REGIONS	= 0,
+};
+
+/* for passing firmware flashing related parameters */
+struct ethtool_flash {
+	__u32	cmd;
+	__u32	region;
+	char	data[ETHTOOL_FLASH_MAX_FILENAME];
+};
+
+/**
+ * struct ethtool_dump - used for retrieving, setting device dump
+ * @cmd: Command number - %ETHTOOL_GET_DUMP_FLAG, %ETHTOOL_GET_DUMP_DATA, or
+ * 	%ETHTOOL_SET_DUMP
+ * @version: FW version of the dump, filled in by driver
+ * @flag: driver dependent flag for dump setting, filled in by driver during
+ *        get and filled in by ethtool for set operation.
+ *        flag must be initialized by macro ETH_FW_DUMP_DISABLE value when
+ *        firmware dump is disabled.
+ * @len: length of dump data, used as the length of the user buffer on entry to
+ * 	 %ETHTOOL_GET_DUMP_DATA and this is returned as dump length by driver
+ * 	 for %ETHTOOL_GET_DUMP_FLAG command
+ * @data: data collected for get dump data operation
+ */
+struct ethtool_dump {
+	__u32	cmd;
+	__u32	version;
+	__u32	flag;
+	__u32	len;
+	__u8	data[0];
+};
+
+#define ETH_FW_DUMP_DISABLE 0
+
+/* for returning and changing feature sets */
+
+/**
+ * struct ethtool_get_features_block - block with state of 32 features
+ * @available: mask of changeable features
+ * @requested: mask of features requested to be enabled if possible
+ * @active: mask of currently enabled features
+ * @never_changed: mask of features not changeable for any device
+ */
+struct ethtool_get_features_block {
+	__u32	available;
+	__u32	requested;
+	__u32	active;
+	__u32	never_changed;
+};
+
+/**
+ * struct ethtool_gfeatures - command to get state of device's features
+ * @cmd: command number = %ETHTOOL_GFEATURES
+ * @size: On entry, the number of elements in the features[] array;
+ *	on return, the number of elements in features[] needed to hold
+ *	all features
+ * @features: state of features
+ */
+struct ethtool_gfeatures {
+	__u32	cmd;
+	__u32	size;
+	struct ethtool_get_features_block features[0];
+};
+
+/**
+ * struct ethtool_set_features_block - block with request for 32 features
+ * @valid: mask of features to be changed
+ * @requested: values of features to be changed
+ */
+struct ethtool_set_features_block {
+	__u32	valid;
+	__u32	requested;
+};
+
+/**
+ * struct ethtool_sfeatures - command to request change in device's features
+ * @cmd: command number = %ETHTOOL_SFEATURES
+ * @size: array size of the features[] array
+ * @features: feature change masks
+ */
+struct ethtool_sfeatures {
+	__u32	cmd;
+	__u32	size;
+	struct ethtool_set_features_block features[0];
+};
+
+/**
+ * struct ethtool_ts_info - holds a device's timestamping and PHC association
+ * @cmd: command number = %ETHTOOL_GET_TS_INFO
+ * @so_timestamping: bit mask of the sum of the supported SO_TIMESTAMPING flags
+ * @phc_index: device index of the associated PHC, or -1 if there is none
+ * @tx_types: bit mask of the supported hwtstamp_tx_types enumeration values
+ * @rx_filters: bit mask of the supported hwtstamp_rx_filters enumeration values
+ *
+ * The bits in the 'tx_types' and 'rx_filters' fields correspond to
+ * the 'hwtstamp_tx_types' and 'hwtstamp_rx_filters' enumeration values,
+ * respectively.  For example, if the device supports HWTSTAMP_TX_ON,
+ * then (1 << HWTSTAMP_TX_ON) in 'tx_types' will be set.
+ *
+ * Drivers should only report the filters they actually support without
+ * upscaling in the SIOCSHWTSTAMP ioctl. If the SIOCSHWSTAMP request for
+ * HWTSTAMP_FILTER_V1_SYNC is supported by HWTSTAMP_FILTER_V1_EVENT, then the
+ * driver should only report HWTSTAMP_FILTER_V1_EVENT in this op.
+ */
+struct ethtool_ts_info {
+	__u32	cmd;
+	__u32	so_timestamping;
+	__s32	phc_index;
+	__u32	tx_types;
+	__u32	tx_reserved[3];
+	__u32	rx_filters;
+	__u32	rx_reserved[3];
+};
+
+/*
+ * %ETHTOOL_SFEATURES changes features present in features[].valid to the
+ * values of corresponding bits in features[].requested. Bits in .requested
+ * not set in .valid or not changeable are ignored.
+ *
+ * Returns %EINVAL when .valid contains undefined or never-changeable bits
+ * or size is not equal to required number of features words (32-bit blocks).
+ * Returns >= 0 if request was completed; bits set in the value mean:
+ *   %ETHTOOL_F_UNSUPPORTED - there were bits set in .valid that are not
+ *	changeable (not present in %ETHTOOL_GFEATURES' features[].available)
+ *	those bits were ignored.
+ *   %ETHTOOL_F_WISH - some or all changes requested were recorded but the
+ *      resulting state of bits masked by .valid is not equal to .requested.
+ *      Probably there are other device-specific constraints on some features
+ *      in the set. When %ETHTOOL_F_UNSUPPORTED is set, .valid is considered
+ *      here as though ignored bits were cleared.
+ *   %ETHTOOL_F_COMPAT - some or all changes requested were made by calling
+ *      compatibility functions. Requested offload state cannot be properly
+ *      managed by kernel.
+ *
+ * Meaning of bits in the masks are obtained by %ETHTOOL_GSSET_INFO (number of
+ * bits in the arrays - always multiple of 32) and %ETHTOOL_GSTRINGS commands
+ * for ETH_SS_FEATURES string set. First entry in the table corresponds to least
+ * significant bit in features[0] fields. Empty strings mark undefined features.
+ */
+enum ethtool_sfeatures_retval_bits {
+	ETHTOOL_F_UNSUPPORTED__BIT,
+	ETHTOOL_F_WISH__BIT,
+	ETHTOOL_F_COMPAT__BIT,
+};
+
+#define ETHTOOL_F_UNSUPPORTED   (1 << ETHTOOL_F_UNSUPPORTED__BIT)
+#define ETHTOOL_F_WISH          (1 << ETHTOOL_F_WISH__BIT)
+#define ETHTOOL_F_COMPAT        (1 << ETHTOOL_F_COMPAT__BIT)
+
+#define MAX_NUM_QUEUE		4096
+
+/**
+ * struct ethtool_per_queue_op - apply sub command to the queues in mask.
+ * @cmd: ETHTOOL_PERQUEUE
+ * @sub_command: the sub command which apply to each queues
+ * @queue_mask: Bitmap of the queues which sub command apply to
+ * @data: A complete command structure following for each of the queues addressed
+ */
+struct ethtool_per_queue_op {
+	__u32	cmd;
+	__u32	sub_command;
+	__u32	queue_mask[__KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32)];
+	char	data[];
+};
+
+/**
+ * struct ethtool_fecparam - Ethernet forward error correction(fec) parameters
+ * @cmd: Command number = %ETHTOOL_GFECPARAM or %ETHTOOL_SFECPARAM
+ * @active_fec: FEC mode which is active on porte
+ * @fec: Bitmask of supported/configured FEC modes
+ * @rsvd: Reserved for future extensions. i.e FEC bypass feature.
+ *
+ * Drivers should reject a non-zero setting of @autoneg when
+ * autoneogotiation is disabled (or not supported) for the link.
+ *
+ */
+struct ethtool_fecparam {
+	__u32   cmd;
+	/* bitmask of FEC modes */
+	__u32   active_fec;
+	__u32   fec;
+	__u32   reserved;
+};
+
+/**
+ * enum ethtool_fec_config_bits - flags definition of ethtool_fec_configuration
+ * @ETHTOOL_FEC_NONE: FEC mode configuration is not supported
+ * @ETHTOOL_FEC_AUTO: Default/Best FEC mode provided by driver
+ * @ETHTOOL_FEC_OFF: No FEC Mode
+ * @ETHTOOL_FEC_RS: Reed-Solomon Forward Error Detection mode
+ * @ETHTOOL_FEC_BASER: Base-R/Reed-Solomon Forward Error Detection mode
+ */
+enum ethtool_fec_config_bits {
+	ETHTOOL_FEC_NONE_BIT,
+	ETHTOOL_FEC_AUTO_BIT,
+	ETHTOOL_FEC_OFF_BIT,
+	ETHTOOL_FEC_RS_BIT,
+	ETHTOOL_FEC_BASER_BIT,
+};
+
+#define ETHTOOL_FEC_NONE		(1 << ETHTOOL_FEC_NONE_BIT)
+#define ETHTOOL_FEC_AUTO		(1 << ETHTOOL_FEC_AUTO_BIT)
+#define ETHTOOL_FEC_OFF			(1 << ETHTOOL_FEC_OFF_BIT)
+#define ETHTOOL_FEC_RS			(1 << ETHTOOL_FEC_RS_BIT)
+#define ETHTOOL_FEC_BASER		(1 << ETHTOOL_FEC_BASER_BIT)
+
+/* CMDs currently supported */
+#define ETHTOOL_GSET		0x00000001 /* DEPRECATED, Get settings.
+					    * Please use ETHTOOL_GLINKSETTINGS
+					    */
+#define ETHTOOL_SSET		0x00000002 /* DEPRECATED, Set settings.
+					    * Please use ETHTOOL_SLINKSETTINGS
+					    */
+#define ETHTOOL_GDRVINFO	0x00000003 /* Get driver info. */
+#define ETHTOOL_GREGS		0x00000004 /* Get NIC registers. */
+#define ETHTOOL_GWOL		0x00000005 /* Get wake-on-lan options. */
+#define ETHTOOL_SWOL		0x00000006 /* Set wake-on-lan options. */
+#define ETHTOOL_GMSGLVL		0x00000007 /* Get driver message level */
+#define ETHTOOL_SMSGLVL		0x00000008 /* Set driver msg level. */
+#define ETHTOOL_NWAY_RST	0x00000009 /* Restart autonegotiation. */
+/* Get link status for host, i.e. whether the interface *and* the
+ * physical port (if there is one) are up (ethtool_value). */
+#define ETHTOOL_GLINK		0x0000000a
+#define ETHTOOL_GEEPROM		0x0000000b /* Get EEPROM data */
+#define ETHTOOL_SEEPROM		0x0000000c /* Set EEPROM data. */
+#define ETHTOOL_GCOALESCE	0x0000000e /* Get coalesce config */
+#define ETHTOOL_SCOALESCE	0x0000000f /* Set coalesce config. */
+#define ETHTOOL_GRINGPARAM	0x00000010 /* Get ring parameters */
+#define ETHTOOL_SRINGPARAM	0x00000011 /* Set ring parameters. */
+#define ETHTOOL_GPAUSEPARAM	0x00000012 /* Get pause parameters */
+#define ETHTOOL_SPAUSEPARAM	0x00000013 /* Set pause parameters. */
+#define ETHTOOL_GRXCSUM		0x00000014 /* Get RX hw csum enable (ethtool_value) */
+#define ETHTOOL_SRXCSUM		0x00000015 /* Set RX hw csum enable (ethtool_value) */
+#define ETHTOOL_GTXCSUM		0x00000016 /* Get TX hw csum enable (ethtool_value) */
+#define ETHTOOL_STXCSUM		0x00000017 /* Set TX hw csum enable (ethtool_value) */
+#define ETHTOOL_GSG		0x00000018 /* Get scatter-gather enable
+					    * (ethtool_value) */
+#define ETHTOOL_SSG		0x00000019 /* Set scatter-gather enable
+					    * (ethtool_value). */
+#define ETHTOOL_TEST		0x0000001a /* execute NIC self-test. */
+#define ETHTOOL_GSTRINGS	0x0000001b /* get specified string set */
+#define ETHTOOL_PHYS_ID		0x0000001c /* identify the NIC */
+#define ETHTOOL_GSTATS		0x0000001d /* get NIC-specific statistics */
+#define ETHTOOL_GTSO		0x0000001e /* Get TSO enable (ethtool_value) */
+#define ETHTOOL_STSO		0x0000001f /* Set TSO enable (ethtool_value) */
+#define ETHTOOL_GPERMADDR	0x00000020 /* Get permanent hardware address */
+#define ETHTOOL_GUFO		0x00000021 /* Get UFO enable (ethtool_value) */
+#define ETHTOOL_SUFO		0x00000022 /* Set UFO enable (ethtool_value) */
+#define ETHTOOL_GGSO		0x00000023 /* Get GSO enable (ethtool_value) */
+#define ETHTOOL_SGSO		0x00000024 /* Set GSO enable (ethtool_value) */
+#define ETHTOOL_GFLAGS		0x00000025 /* Get flags bitmap(ethtool_value) */
+#define ETHTOOL_SFLAGS		0x00000026 /* Set flags bitmap(ethtool_value) */
+#define ETHTOOL_GPFLAGS		0x00000027 /* Get driver-private flags bitmap */
+#define ETHTOOL_SPFLAGS		0x00000028 /* Set driver-private flags bitmap */
+
+#define ETHTOOL_GRXFH		0x00000029 /* Get RX flow hash configuration */
+#define ETHTOOL_SRXFH		0x0000002a /* Set RX flow hash configuration */
+#define ETHTOOL_GGRO		0x0000002b /* Get GRO enable (ethtool_value) */
+#define ETHTOOL_SGRO		0x0000002c /* Set GRO enable (ethtool_value) */
+#define ETHTOOL_GRXRINGS	0x0000002d /* Get RX rings available for LB */
+#define ETHTOOL_GRXCLSRLCNT	0x0000002e /* Get RX class rule count */
+#define ETHTOOL_GRXCLSRULE	0x0000002f /* Get RX classification rule */
+#define ETHTOOL_GRXCLSRLALL	0x00000030 /* Get all RX classification rule */
+#define ETHTOOL_SRXCLSRLDEL	0x00000031 /* Delete RX classification rule */
+#define ETHTOOL_SRXCLSRLINS	0x00000032 /* Insert RX classification rule */
+#define ETHTOOL_FLASHDEV	0x00000033 /* Flash firmware to device */
+#define ETHTOOL_RESET		0x00000034 /* Reset hardware */
+#define ETHTOOL_SRXNTUPLE	0x00000035 /* Add an n-tuple filter to device */
+#define ETHTOOL_GRXNTUPLE	0x00000036 /* deprecated */
+#define ETHTOOL_GSSET_INFO	0x00000037 /* Get string set info */
+#define ETHTOOL_GRXFHINDIR	0x00000038 /* Get RX flow hash indir'n table */
+#define ETHTOOL_SRXFHINDIR	0x00000039 /* Set RX flow hash indir'n table */
+
+#define ETHTOOL_GFEATURES	0x0000003a /* Get device offload settings */
+#define ETHTOOL_SFEATURES	0x0000003b /* Change device offload settings */
+#define ETHTOOL_GCHANNELS	0x0000003c /* Get no of channels */
+#define ETHTOOL_SCHANNELS	0x0000003d /* Set no of channels */
+#define ETHTOOL_SET_DUMP	0x0000003e /* Set dump settings */
+#define ETHTOOL_GET_DUMP_FLAG	0x0000003f /* Get dump settings */
+#define ETHTOOL_GET_DUMP_DATA	0x00000040 /* Get dump data */
+#define ETHTOOL_GET_TS_INFO	0x00000041 /* Get time stamping and PHC info */
+#define ETHTOOL_GMODULEINFO	0x00000042 /* Get plug-in module information */
+#define ETHTOOL_GMODULEEEPROM	0x00000043 /* Get plug-in module eeprom */
+#define ETHTOOL_GEEE		0x00000044 /* Get EEE settings */
+#define ETHTOOL_SEEE		0x00000045 /* Set EEE settings */
+
+#define ETHTOOL_GRSSH		0x00000046 /* Get RX flow hash configuration */
+#define ETHTOOL_SRSSH		0x00000047 /* Set RX flow hash configuration */
+#define ETHTOOL_GTUNABLE	0x00000048 /* Get tunable configuration */
+#define ETHTOOL_STUNABLE	0x00000049 /* Set tunable configuration */
+#define ETHTOOL_GPHYSTATS	0x0000004a /* get PHY-specific statistics */
+
+#define ETHTOOL_PERQUEUE	0x0000004b /* Set per queue options */
+
+#define ETHTOOL_GLINKSETTINGS	0x0000004c /* Get ethtool_link_settings */
+#define ETHTOOL_SLINKSETTINGS	0x0000004d /* Set ethtool_link_settings */
+#define ETHTOOL_PHY_GTUNABLE	0x0000004e /* Get PHY tunable configuration */
+#define ETHTOOL_PHY_STUNABLE	0x0000004f /* Set PHY tunable configuration */
+#define ETHTOOL_GFECPARAM	0x00000050 /* Get FEC settings */
+#define ETHTOOL_SFECPARAM	0x00000051 /* Set FEC settings */
+
+/* compatibility with older code */
+#define SPARC_ETH_GSET		ETHTOOL_GSET
+#define SPARC_ETH_SSET		ETHTOOL_SSET
+
+/* Link mode bit indices */
+enum ethtool_link_mode_bit_indices {
+	ETHTOOL_LINK_MODE_10baseT_Half_BIT	= 0,
+	ETHTOOL_LINK_MODE_10baseT_Full_BIT	= 1,
+	ETHTOOL_LINK_MODE_100baseT_Half_BIT	= 2,
+	ETHTOOL_LINK_MODE_100baseT_Full_BIT	= 3,
+	ETHTOOL_LINK_MODE_1000baseT_Half_BIT	= 4,
+	ETHTOOL_LINK_MODE_1000baseT_Full_BIT	= 5,
+	ETHTOOL_LINK_MODE_Autoneg_BIT		= 6,
+	ETHTOOL_LINK_MODE_TP_BIT		= 7,
+	ETHTOOL_LINK_MODE_AUI_BIT		= 8,
+	ETHTOOL_LINK_MODE_MII_BIT		= 9,
+	ETHTOOL_LINK_MODE_FIBRE_BIT		= 10,
+	ETHTOOL_LINK_MODE_BNC_BIT		= 11,
+	ETHTOOL_LINK_MODE_10000baseT_Full_BIT	= 12,
+	ETHTOOL_LINK_MODE_Pause_BIT		= 13,
+	ETHTOOL_LINK_MODE_Asym_Pause_BIT	= 14,
+	ETHTOOL_LINK_MODE_2500baseX_Full_BIT	= 15,
+	ETHTOOL_LINK_MODE_Backplane_BIT		= 16,
+	ETHTOOL_LINK_MODE_1000baseKX_Full_BIT	= 17,
+	ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT	= 18,
+	ETHTOOL_LINK_MODE_10000baseKR_Full_BIT	= 19,
+	ETHTOOL_LINK_MODE_10000baseR_FEC_BIT	= 20,
+	ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT = 21,
+	ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT	= 22,
+	ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT	= 23,
+	ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT	= 24,
+	ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT	= 25,
+	ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT	= 26,
+	ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT	= 27,
+	ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT	= 28,
+	ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT	= 29,
+	ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT	= 30,
+	ETHTOOL_LINK_MODE_25000baseCR_Full_BIT	= 31,
+
+	/* Last allowed bit for __ETHTOOL_LINK_MODE_LEGACY_MASK is bit
+	 * 31. Please do NOT define any SUPPORTED_* or ADVERTISED_*
+	 * macro for bits > 31. The only way to use indices > 31 is to
+	 * use the new ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API.
+	 */
+
+	ETHTOOL_LINK_MODE_25000baseKR_Full_BIT	= 32,
+	ETHTOOL_LINK_MODE_25000baseSR_Full_BIT	= 33,
+	ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT	= 34,
+	ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT	= 35,
+	ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT	= 36,
+	ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT	= 37,
+	ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT	= 38,
+	ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT	= 39,
+	ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT		= 40,
+	ETHTOOL_LINK_MODE_1000baseX_Full_BIT	= 41,
+	ETHTOOL_LINK_MODE_10000baseCR_Full_BIT	= 42,
+	ETHTOOL_LINK_MODE_10000baseSR_Full_BIT	= 43,
+	ETHTOOL_LINK_MODE_10000baseLR_Full_BIT	= 44,
+	ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT	= 45,
+	ETHTOOL_LINK_MODE_10000baseER_Full_BIT	= 46,
+	ETHTOOL_LINK_MODE_2500baseT_Full_BIT	= 47,
+	ETHTOOL_LINK_MODE_5000baseT_Full_BIT	= 48,
+
+	ETHTOOL_LINK_MODE_FEC_NONE_BIT	= 49,
+	ETHTOOL_LINK_MODE_FEC_RS_BIT	= 50,
+	ETHTOOL_LINK_MODE_FEC_BASER_BIT	= 51,
+	ETHTOOL_LINK_MODE_50000baseKR_Full_BIT		 = 52,
+	ETHTOOL_LINK_MODE_50000baseSR_Full_BIT		 = 53,
+	ETHTOOL_LINK_MODE_50000baseCR_Full_BIT		 = 54,
+	ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT	 = 55,
+	ETHTOOL_LINK_MODE_50000baseDR_Full_BIT		 = 56,
+	ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT	 = 57,
+	ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT	 = 58,
+	ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT	 = 59,
+	ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT = 60,
+	ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT	 = 61,
+	ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT	 = 62,
+	ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT	 = 63,
+	ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT = 64,
+	ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT	 = 65,
+	ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT	 = 66,
+	ETHTOOL_LINK_MODE_100baseT1_Full_BIT		 = 67,
+	ETHTOOL_LINK_MODE_1000baseT1_Full_BIT		 = 68,
+
+	/* must be last entry */
+	__ETHTOOL_LINK_MODE_MASK_NBITS
+};
+
+#define __ETHTOOL_LINK_MODE_LEGACY_MASK(base_name)	\
+	(1UL << (ETHTOOL_LINK_MODE_ ## base_name ## _BIT))
+
+/* DEPRECATED macros. Please migrate to
+ * ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API. Please do NOT
+ * define any new SUPPORTED_* macro for bits > 31.
+ */
+#define SUPPORTED_10baseT_Half		__ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Half)
+#define SUPPORTED_10baseT_Full		__ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Full)
+#define SUPPORTED_100baseT_Half		__ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Half)
+#define SUPPORTED_100baseT_Full		__ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Full)
+#define SUPPORTED_1000baseT_Half	__ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Half)
+#define SUPPORTED_1000baseT_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Full)
+#define SUPPORTED_Autoneg		__ETHTOOL_LINK_MODE_LEGACY_MASK(Autoneg)
+#define SUPPORTED_TP			__ETHTOOL_LINK_MODE_LEGACY_MASK(TP)
+#define SUPPORTED_AUI			__ETHTOOL_LINK_MODE_LEGACY_MASK(AUI)
+#define SUPPORTED_MII			__ETHTOOL_LINK_MODE_LEGACY_MASK(MII)
+#define SUPPORTED_FIBRE			__ETHTOOL_LINK_MODE_LEGACY_MASK(FIBRE)
+#define SUPPORTED_BNC			__ETHTOOL_LINK_MODE_LEGACY_MASK(BNC)
+#define SUPPORTED_10000baseT_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseT_Full)
+#define SUPPORTED_Pause			__ETHTOOL_LINK_MODE_LEGACY_MASK(Pause)
+#define SUPPORTED_Asym_Pause		__ETHTOOL_LINK_MODE_LEGACY_MASK(Asym_Pause)
+#define SUPPORTED_2500baseX_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(2500baseX_Full)
+#define SUPPORTED_Backplane		__ETHTOOL_LINK_MODE_LEGACY_MASK(Backplane)
+#define SUPPORTED_1000baseKX_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseKX_Full)
+#define SUPPORTED_10000baseKX4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKX4_Full)
+#define SUPPORTED_10000baseKR_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKR_Full)
+#define SUPPORTED_10000baseR_FEC	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseR_FEC)
+#define SUPPORTED_20000baseMLD2_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseMLD2_Full)
+#define SUPPORTED_20000baseKR2_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseKR2_Full)
+#define SUPPORTED_40000baseKR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseKR4_Full)
+#define SUPPORTED_40000baseCR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseCR4_Full)
+#define SUPPORTED_40000baseSR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseSR4_Full)
+#define SUPPORTED_40000baseLR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseLR4_Full)
+#define SUPPORTED_56000baseKR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseKR4_Full)
+#define SUPPORTED_56000baseCR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseCR4_Full)
+#define SUPPORTED_56000baseSR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseSR4_Full)
+#define SUPPORTED_56000baseLR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseLR4_Full)
+/* Please do not define any new SUPPORTED_* macro for bits > 31, see
+ * notice above.
+ */
+
+/*
+ * DEPRECATED macros. Please migrate to
+ * ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API. Please do NOT
+ * define any new ADERTISE_* macro for bits > 31.
+ */
+#define ADVERTISED_10baseT_Half		__ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Half)
+#define ADVERTISED_10baseT_Full		__ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Full)
+#define ADVERTISED_100baseT_Half	__ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Half)
+#define ADVERTISED_100baseT_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Full)
+#define ADVERTISED_1000baseT_Half	__ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Half)
+#define ADVERTISED_1000baseT_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Full)
+#define ADVERTISED_Autoneg		__ETHTOOL_LINK_MODE_LEGACY_MASK(Autoneg)
+#define ADVERTISED_TP			__ETHTOOL_LINK_MODE_LEGACY_MASK(TP)
+#define ADVERTISED_AUI			__ETHTOOL_LINK_MODE_LEGACY_MASK(AUI)
+#define ADVERTISED_MII			__ETHTOOL_LINK_MODE_LEGACY_MASK(MII)
+#define ADVERTISED_FIBRE		__ETHTOOL_LINK_MODE_LEGACY_MASK(FIBRE)
+#define ADVERTISED_BNC			__ETHTOOL_LINK_MODE_LEGACY_MASK(BNC)
+#define ADVERTISED_10000baseT_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseT_Full)
+#define ADVERTISED_Pause		__ETHTOOL_LINK_MODE_LEGACY_MASK(Pause)
+#define ADVERTISED_Asym_Pause		__ETHTOOL_LINK_MODE_LEGACY_MASK(Asym_Pause)
+#define ADVERTISED_2500baseX_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(2500baseX_Full)
+#define ADVERTISED_Backplane		__ETHTOOL_LINK_MODE_LEGACY_MASK(Backplane)
+#define ADVERTISED_1000baseKX_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseKX_Full)
+#define ADVERTISED_10000baseKX4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKX4_Full)
+#define ADVERTISED_10000baseKR_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKR_Full)
+#define ADVERTISED_10000baseR_FEC	__ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseR_FEC)
+#define ADVERTISED_20000baseMLD2_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseMLD2_Full)
+#define ADVERTISED_20000baseKR2_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseKR2_Full)
+#define ADVERTISED_40000baseKR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseKR4_Full)
+#define ADVERTISED_40000baseCR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseCR4_Full)
+#define ADVERTISED_40000baseSR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseSR4_Full)
+#define ADVERTISED_40000baseLR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseLR4_Full)
+#define ADVERTISED_56000baseKR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseKR4_Full)
+#define ADVERTISED_56000baseCR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseCR4_Full)
+#define ADVERTISED_56000baseSR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseSR4_Full)
+#define ADVERTISED_56000baseLR4_Full	__ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseLR4_Full)
+/* Please do not define any new ADVERTISED_* macro for bits > 31, see
+ * notice above.
+ */
+
+/* The following are all involved in forcing a particular link
+ * mode for the device for setting things.  When getting the
+ * devices settings, these indicate the current mode and whether
+ * it was forced up into this mode or autonegotiated.
+ */
+
+/* The forced speed, in units of 1Mb. All values 0 to INT_MAX are legal.
+ * Update drivers/net/phy/phy.c:phy_speed_to_str() and
+ * drivers/net/bonding/bond_3ad.c:__get_link_speed() when adding new values.
+ */
+#define SPEED_10		10
+#define SPEED_100		100
+#define SPEED_1000		1000
+#define SPEED_2500		2500
+#define SPEED_5000		5000
+#define SPEED_10000		10000
+#define SPEED_14000		14000
+#define SPEED_20000		20000
+#define SPEED_25000		25000
+#define SPEED_40000		40000
+#define SPEED_50000		50000
+#define SPEED_56000		56000
+#define SPEED_100000		100000
+#define SPEED_200000		200000
+
+#define SPEED_UNKNOWN		-1
+
+static __inline__ int ethtool_validate_speed(__u32 speed)
+{
+	return speed <= INT_MAX || speed == (__u32)SPEED_UNKNOWN;
+}
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF		0x00
+#define DUPLEX_FULL		0x01
+#define DUPLEX_UNKNOWN		0xff
+
+static __inline__ int ethtool_validate_duplex(__u8 duplex)
+{
+	switch (duplex) {
+	case DUPLEX_HALF:
+	case DUPLEX_FULL:
+	case DUPLEX_UNKNOWN:
+		return 1;
+	}
+
+	return 0;
+}
+
+/* Which connector port. */
+#define PORT_TP			0x00
+#define PORT_AUI		0x01
+#define PORT_MII		0x02
+#define PORT_FIBRE		0x03
+#define PORT_BNC		0x04
+#define PORT_DA			0x05
+#define PORT_NONE		0xef
+#define PORT_OTHER		0xff
+
+/* Which transceiver to use. */
+#define XCVR_INTERNAL		0x00 /* PHY and MAC are in the same package */
+#define XCVR_EXTERNAL		0x01 /* PHY and MAC are in different packages */
+#define XCVR_DUMMY1		0x02
+#define XCVR_DUMMY2		0x03
+#define XCVR_DUMMY3		0x04
+
+/* Enable or disable autonegotiation. */
+#define AUTONEG_DISABLE		0x00
+#define AUTONEG_ENABLE		0x01
+
+/* MDI or MDI-X status/control - if MDI/MDI_X/AUTO is set then
+ * the driver is required to renegotiate link
+ */
+#define ETH_TP_MDI_INVALID	0x00 /* status: unknown; control: unsupported */
+#define ETH_TP_MDI		0x01 /* status: MDI;     control: force MDI */
+#define ETH_TP_MDI_X		0x02 /* status: MDI-X;   control: force MDI-X */
+#define ETH_TP_MDI_AUTO		0x03 /*                  control: auto-select */
+
+/* Wake-On-Lan options. */
+#define WAKE_PHY		(1 << 0)
+#define WAKE_UCAST		(1 << 1)
+#define WAKE_MCAST		(1 << 2)
+#define WAKE_BCAST		(1 << 3)
+#define WAKE_ARP		(1 << 4)
+#define WAKE_MAGIC		(1 << 5)
+#define WAKE_MAGICSECURE	(1 << 6) /* only meaningful if WAKE_MAGIC */
+#define WAKE_FILTER		(1 << 7)
+
+/* L2-L4 network traffic flow types */
+#define	TCP_V4_FLOW	0x01	/* hash or spec (tcp_ip4_spec) */
+#define	UDP_V4_FLOW	0x02	/* hash or spec (udp_ip4_spec) */
+#define	SCTP_V4_FLOW	0x03	/* hash or spec (sctp_ip4_spec) */
+#define	AH_ESP_V4_FLOW	0x04	/* hash only */
+#define	TCP_V6_FLOW	0x05	/* hash or spec (tcp_ip6_spec; nfc only) */
+#define	UDP_V6_FLOW	0x06	/* hash or spec (udp_ip6_spec; nfc only) */
+#define	SCTP_V6_FLOW	0x07	/* hash or spec (sctp_ip6_spec; nfc only) */
+#define	AH_ESP_V6_FLOW	0x08	/* hash only */
+#define	AH_V4_FLOW	0x09	/* hash or spec (ah_ip4_spec) */
+#define	ESP_V4_FLOW	0x0a	/* hash or spec (esp_ip4_spec) */
+#define	AH_V6_FLOW	0x0b	/* hash or spec (ah_ip6_spec; nfc only) */
+#define	ESP_V6_FLOW	0x0c	/* hash or spec (esp_ip6_spec; nfc only) */
+#define	IPV4_USER_FLOW	0x0d	/* spec only (usr_ip4_spec) */
+#define	IP_USER_FLOW	IPV4_USER_FLOW
+#define	IPV6_USER_FLOW	0x0e	/* spec only (usr_ip6_spec; nfc only) */
+#define	IPV4_FLOW	0x10	/* hash only */
+#define	IPV6_FLOW	0x11	/* hash only */
+#define	ETHER_FLOW	0x12	/* spec only (ether_spec) */
+/* Flag to enable additional fields in struct ethtool_rx_flow_spec */
+#define	FLOW_EXT	0x80000000
+#define	FLOW_MAC_EXT	0x40000000
+/* Flag to enable RSS spreading of traffic matching rule (nfc only) */
+#define	FLOW_RSS	0x20000000
+
+/* L3-L4 network traffic flow hash options */
+#define	RXH_L2DA	(1 << 1)
+#define	RXH_VLAN	(1 << 2)
+#define	RXH_L3_PROTO	(1 << 3)
+#define	RXH_IP_SRC	(1 << 4)
+#define	RXH_IP_DST	(1 << 5)
+#define	RXH_L4_B_0_1	(1 << 6) /* src port in case of TCP/UDP/SCTP */
+#define	RXH_L4_B_2_3	(1 << 7) /* dst port in case of TCP/UDP/SCTP */
+#define	RXH_DISCARD	(1 << 31)
+
+#define	RX_CLS_FLOW_DISC	0xffffffffffffffffULL
+#define RX_CLS_FLOW_WAKE	0xfffffffffffffffeULL
+
+/* Special RX classification rule insert location values */
+#define RX_CLS_LOC_SPECIAL	0x80000000	/* flag */
+#define RX_CLS_LOC_ANY		0xffffffff
+#define RX_CLS_LOC_FIRST	0xfffffffe
+#define RX_CLS_LOC_LAST		0xfffffffd
+
+/* EEPROM Standards for plug in modules */
+#define ETH_MODULE_SFF_8079		0x1
+#define ETH_MODULE_SFF_8079_LEN		256
+#define ETH_MODULE_SFF_8472		0x2
+#define ETH_MODULE_SFF_8472_LEN		512
+#define ETH_MODULE_SFF_8636		0x3
+#define ETH_MODULE_SFF_8636_LEN		256
+#define ETH_MODULE_SFF_8436		0x4
+#define ETH_MODULE_SFF_8436_LEN		256
+
+#define ETH_MODULE_SFF_8636_MAX_LEN     640
+#define ETH_MODULE_SFF_8436_MAX_LEN     640
+
+/* Reset flags */
+/* The reset() operation must clear the flags for the components which
+ * were actually reset.  On successful return, the flags indicate the
+ * components which were not reset, either because they do not exist
+ * in the hardware or because they cannot be reset independently.  The
+ * driver must never reset any components that were not requested.
+ */
+enum ethtool_reset_flags {
+	/* These flags represent components dedicated to the interface
+	 * the command is addressed to.  Shift any flag left by
+	 * ETH_RESET_SHARED_SHIFT to reset a shared component of the
+	 * same type.
+	 */
+	ETH_RESET_MGMT		= 1 << 0,	/* Management processor */
+	ETH_RESET_IRQ		= 1 << 1,	/* Interrupt requester */
+	ETH_RESET_DMA		= 1 << 2,	/* DMA engine */
+	ETH_RESET_FILTER	= 1 << 3,	/* Filtering/flow direction */
+	ETH_RESET_OFFLOAD	= 1 << 4,	/* Protocol offload */
+	ETH_RESET_MAC		= 1 << 5,	/* Media access controller */
+	ETH_RESET_PHY		= 1 << 6,	/* Transceiver/PHY */
+	ETH_RESET_RAM		= 1 << 7,	/* RAM shared between
+						 * multiple components */
+	ETH_RESET_AP		= 1 << 8,	/* Application processor */
+
+	ETH_RESET_DEDICATED	= 0x0000ffff,	/* All components dedicated to
+						 * this interface */
+	ETH_RESET_ALL		= 0xffffffff,	/* All components used by this
+						 * interface, even if shared */
+};
+#define ETH_RESET_SHARED_SHIFT	16
+
+
+/**
+ * struct ethtool_link_settings - link control and status
+ *
+ * IMPORTANT, Backward compatibility notice: When implementing new
+ *	user-space tools, please first try %ETHTOOL_GLINKSETTINGS, and
+ *	if it succeeds use %ETHTOOL_SLINKSETTINGS to change link
+ *	settings; do not use %ETHTOOL_SSET if %ETHTOOL_GLINKSETTINGS
+ *	succeeded: stick to %ETHTOOL_GLINKSETTINGS/%SLINKSETTINGS in
+ *	that case.  Conversely, if %ETHTOOL_GLINKSETTINGS fails, use
+ *	%ETHTOOL_GSET to query and %ETHTOOL_SSET to change link
+ *	settings; do not use %ETHTOOL_SLINKSETTINGS if
+ *	%ETHTOOL_GLINKSETTINGS failed: stick to
+ *	%ETHTOOL_GSET/%ETHTOOL_SSET in that case.
+ *
+ * @cmd: Command number = %ETHTOOL_GLINKSETTINGS or %ETHTOOL_SLINKSETTINGS
+ * @speed: Link speed (Mbps)
+ * @duplex: Duplex mode; one of %DUPLEX_*
+ * @port: Physical connector type; one of %PORT_*
+ * @phy_address: MDIO address of PHY (transceiver); 0 or 255 if not
+ *	applicable.  For clause 45 PHYs this is the PRTAD.
+ * @autoneg: Enable/disable autonegotiation and auto-detection;
+ *	either %AUTONEG_DISABLE or %AUTONEG_ENABLE
+ * @mdio_support: Bitmask of %ETH_MDIO_SUPPORTS_* flags for the MDIO
+ *	protocols supported by the interface; 0 if unknown.
+ *	Read-only.
+ * @eth_tp_mdix: Ethernet twisted-pair MDI(-X) status; one of
+ *	%ETH_TP_MDI_*.  If the status is unknown or not applicable, the
+ *	value will be %ETH_TP_MDI_INVALID.  Read-only.
+ * @eth_tp_mdix_ctrl: Ethernet twisted pair MDI(-X) control; one of
+ *	%ETH_TP_MDI_*.  If MDI(-X) control is not implemented, reads
+ *	yield %ETH_TP_MDI_INVALID and writes may be ignored or rejected.
+ *	When written successfully, the link should be renegotiated if
+ *	necessary.
+ * @link_mode_masks_nwords: Number of 32-bit words for each of the
+ *	supported, advertising, lp_advertising link mode bitmaps. For
+ *	%ETHTOOL_GLINKSETTINGS: on entry, number of words passed by user
+ *	(>= 0); on return, if handshake in progress, negative if
+ *	request size unsupported by kernel: absolute value indicates
+ *	kernel expected size and all the other fields but cmd
+ *	are 0; otherwise (handshake completed), strictly positive
+ *	to indicate size used by kernel and cmd field stays
+ *	%ETHTOOL_GLINKSETTINGS, all other fields populated by driver. For
+ *	%ETHTOOL_SLINKSETTINGS: must be valid on entry, ie. a positive
+ *	value returned previously by %ETHTOOL_GLINKSETTINGS, otherwise
+ *	refused. For drivers: ignore this field (use kernel's
+ *	__ETHTOOL_LINK_MODE_MASK_NBITS instead), any change to it will
+ *	be overwritten by kernel.
+ * @supported: Bitmap with each bit meaning given by
+ *	%ethtool_link_mode_bit_indices for the link modes, physical
+ *	connectors and other link features for which the interface
+ *	supports autonegotiation or auto-detection.  Read-only.
+ * @advertising: Bitmap with each bit meaning given by
+ *	%ethtool_link_mode_bit_indices for the link modes, physical
+ *	connectors and other link features that are advertised through
+ *	autonegotiation or enabled for auto-detection.
+ * @lp_advertising: Bitmap with each bit meaning given by
+ *	%ethtool_link_mode_bit_indices for the link modes, and other
+ *	link features that the link partner advertised through
+ *	autonegotiation; 0 if unknown or not applicable.  Read-only.
+ * @transceiver: Used to distinguish different possible PHY types,
+ *	reported consistently by PHYLIB.  Read-only.
+ *
+ * If autonegotiation is disabled, the speed and @duplex represent the
+ * fixed link mode and are writable if the driver supports multiple
+ * link modes.  If it is enabled then they are read-only; if the link
+ * is up they represent the negotiated link mode; if the link is down,
+ * the speed is 0, %SPEED_UNKNOWN or the highest enabled speed and
+ * @duplex is %DUPLEX_UNKNOWN or the best enabled duplex mode.
+ *
+ * Some hardware interfaces may have multiple PHYs and/or physical
+ * connectors fitted or do not allow the driver to detect which are
+ * fitted.  For these interfaces @port and/or @phy_address may be
+ * writable, possibly dependent on @autoneg being %AUTONEG_DISABLE.
+ * Otherwise, attempts to write different values may be ignored or
+ * rejected.
+ *
+ * Deprecated %ethtool_cmd fields transceiver, maxtxpkt and maxrxpkt
+ * are not available in %ethtool_link_settings. These fields will be
+ * always set to zero in %ETHTOOL_GSET reply and %ETHTOOL_SSET will
+ * fail if any of them is set to non-zero value.
+ *
+ * Users should assume that all fields not marked read-only are
+ * writable and subject to validation by the driver.  They should use
+ * %ETHTOOL_GLINKSETTINGS to get the current values before making specific
+ * changes and then applying them with %ETHTOOL_SLINKSETTINGS.
+ *
+ * Drivers that implement %get_link_ksettings and/or
+ * %set_link_ksettings should ignore the @cmd
+ * and @link_mode_masks_nwords fields (any change to them overwritten
+ * by kernel), and rely only on kernel's internal
+ * %__ETHTOOL_LINK_MODE_MASK_NBITS and
+ * %ethtool_link_mode_mask_t. Drivers that implement
+ * %set_link_ksettings() should validate all fields other than @cmd
+ * and @link_mode_masks_nwords that are not described as read-only or
+ * deprecated, and must ignore all fields described as read-only.
+ */
+struct ethtool_link_settings {
+	__u32	cmd;
+	__u32	speed;
+	__u8	duplex;
+	__u8	port;
+	__u8	phy_address;
+	__u8	autoneg;
+	__u8	mdio_support;
+	__u8	eth_tp_mdix;
+	__u8	eth_tp_mdix_ctrl;
+	__s8	link_mode_masks_nwords;
+	__u8	transceiver;
+	__u8	reserved1[3];
+	__u32	reserved[7];
+	__u32	link_mode_masks[0];
+	/* layout of link_mode_masks fields:
+	 * __u32 map_supported[link_mode_masks_nwords];
+	 * __u32 map_advertising[link_mode_masks_nwords];
+	 * __u32 map_lp_advertising[link_mode_masks_nwords];
+	 */
+};
+#endif /* _LINUX_ETHTOOL_H */
diff --git a/ethtool.8.in b/ethtool.8.in
new file mode 100644
index 0000000..062695a
--- /dev/null
+++ b/ethtool.8.in
@@ -0,0 +1,1258 @@
+.\" -*- nroff -*-
+.\" Copyright 1999 by David S. Miller.  All Rights Reserved.
+.\" Portions Copyright 2001 Sun Microsystems
+.\" Portions Copyright 2007, 2009 Free Software Foundation, Inc.
+.\" This file may be copied under the terms of the GNU Public License.
+.\" 
+.\" There must be no text lines before .TH.  Use '.' for vertical spacing.
+.\"
+.\"	.An - list of n alternative values as in "flav vanilla|strawberry"
+.\"
+.de A1
+\\fB\\$1\\fP|\\fB\\$2\\fP
+..
+.de A2
+\\fB\\$1\\fP\ \\fB\\$2\\fP|\\fB\\$3\\fP
+..
+.de A3
+\\fB\\$1\\fP\ \\fB\\$2\\fP|\\fB\\$3\\fP|\\fB\\$4\\fP
+..
+.de A4
+\\fB\\$1\\fP\ \\fB\\$2\\fP|\\fB\\$3\\fP|\\fB\\$4\\fP|\\fB\\$5\\fP
+..
+.\" 
+.\"	.Bn - same as above but framed by square brackets
+.\"
+.de B1
+[\\fB\\$1\\fP|\\fB\\$2\\fP]
+..
+.de B2
+[\\fB\\$1\\fP\ \\fB\\$2\\fP|\\fB\\$3\\fP]
+..
+.de B3
+[\\fB\\$1\\fP\ \\fB\\$2\\fP|\\fB\\$3\\fP|\\fB\\$4\\fP]
+..
+.de B4
+[\\fB\\$1\\fP\ \\fB\\$2\\fP|\\fB\\$3\\fP|\\fB\\$4\\fP|\\fB\\$5\\fP]
+..
+.\"
+.\"	.BN - value with a numeric input as in "[value N]"
+.\"
+.de BN
+[\\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 \fIip-address\fP
+.\"
+.\"	\(*WO - wol flags
+.\"
+.ds WO \fBp\fP|\fBu\fP|\fBm\fP|\fBb\fP|\fBa\fP|\fBg\fP|\fBs\fP|\fBf|\fBd\fP...
+.\"
+.\"	\(*FL - flow type values
+.\"
+.ds FL \fBtcp4\fP|\fBudp4\fP|\fBah4\fP|\fBesp4\fP|\fBsctp4\fP|\fBtcp6\fP|\fBudp6\fP|\fBah6\fP|\fBesp6\fP|\fBsctp6\fP
+.\"
+.\"	\(*HO - hash options
+.\"
+.ds HO \fBm\fP|\fBv\fP|\fBt\fP|\fBs\fP|\fBd\fP|\fBf\fP|\fBn\fP|\fBr\fP...
+.\"
+.\"	\(*SD - Self-diag test values
+.\"
+.ds SD \fBoffline\fP|\fBonline\fP|\fBexternal_lb\fP
+.\"
+.\"	\(*NC - Network Classifier type values
+.\"
+.ds NC \fBether\fP|\fBip4\fP|\fBtcp4\fP|\fBudp4\fP|\fBsctp4\fP|\fBah4\fP|\fBesp4\fP|\fBip6\fP|\fBtcp6\fP|\fBudp6\fP|\fBah6\fP|\fBesp6\fP|\fBsctp6\fP
+..
+.\"
+.\" Start URL.
+.de UR
+.  ds m1 \\$1\"
+.  nh
+.  if \\n(mH \{\
+.    \" Start diversion in a new environment.
+.    do ev URL-div
+.    do di URL-div
+.  \}
+..
+.\" End URL.
+.de UE
+.  ie \\n(mH \{\
+.    br
+.    di
+.    ev
+.
+.    \" Has there been one or more input lines for the link text?
+.    ie \\n(dn \{\
+.      do HTML-NS "<a href=""\\*(m1"">"
+.      \" Yes, strip off final newline of diversion and emit it.
+.      do chop URL-div
+.      do URL-div
+\c
+.      do HTML-NS </a>
+.    \}
+.    el \
+.      do HTML-NS "<a href=""\\*(m1"">\\*(m1</a>"
+\&\\$*\"
+.  \}
+.  el \
+\\*(la\\*(m1\\*(ra\\$*\"
+.
+.  hy \\n(HY
+..
+.
+.TH ETHTOOL 8 "September 2019" "Ethtool version @VERSION@"
+.SH NAME
+ethtool \- query or control network driver and hardware settings
+.
+.SH SYNOPSIS
+.\" Do not adjust lines (i.e. left justification) and do not hyphenate.
+.na
+.nh
+.HP
+.B ethtool
+.I devname
+.HP
+.B ethtool \-h|\-\-help
+.HP
+.B ethtool \-\-version
+.HP
+.B ethtool \-a|\-\-show\-pause
+.I devname
+.HP
+.B ethtool \-A|\-\-pause
+.I devname
+.B2 autoneg on off
+.B2 rx on off
+.B2 tx on off
+.HP
+.B ethtool \-c|\-\-show\-coalesce
+.I devname
+.HP
+.B ethtool \-C|\-\-coalesce
+.I devname
+.B2 adaptive\-rx on off
+.B2 adaptive\-tx on off
+.BN rx\-usecs
+.BN rx\-frames
+.BN rx\-usecs\-irq
+.BN rx\-frames\-irq
+.BN tx\-usecs
+.BN tx\-frames
+.BN tx\-usecs\-irq
+.BN tx\-frames\-irq
+.BN stats\-block\-usecs
+.BN pkt\-rate\-low
+.BN rx\-usecs\-low
+.BN rx\-frames\-low
+.BN tx\-usecs\-low
+.BN tx\-frames\-low
+.BN pkt\-rate\-high
+.BN rx\-usecs\-high
+.BN rx\-frames\-high
+.BN tx\-usecs\-high
+.BN tx\-frames\-high
+.BN sample\-interval
+.HP
+.B ethtool \-g|\-\-show\-ring
+.I devname
+.HP
+.B ethtool \-G|\-\-set\-ring
+.I devname
+.BN rx
+.BN rx\-mini
+.BN rx\-jumbo
+.BN tx
+.HP
+.B ethtool \-i|\-\-driver
+.I devname
+.HP
+.B ethtool \-d|\-\-register\-dump
+.I devname
+.B2 raw on off
+.B2 hex on off
+.RB [ file 
+.IR name ]
+.HP
+.B ethtool \-e|\-\-eeprom\-dump
+.I devname
+.B2 raw on off
+.BN offset
+.BN length
+.HP
+.B ethtool \-E|\-\-change\-eeprom
+.I devname
+.BN magic
+.BN offset
+.BN length
+.BN value
+.HP
+.B ethtool \-k|\-\-show\-features|\-\-show\-offload
+.I devname
+.HP
+.B ethtool \-K|\-\-features|\-\-offload
+.I devname feature
+.A1 on off
+.RB ...
+.HP
+.B ethtool \-p|\-\-identify
+.I devname
+.RI [ N ]
+.HP
+.B ethtool \-P|\-\-show\-permaddr
+.I devname
+.HP
+.B ethtool \-r|\-\-negotiate
+.I devname
+.HP
+.B ethtool \-S|\-\-statistics
+.I devname
+.HP
+.B ethtool \-\-phy\-statistics
+.I devname
+.HP
+.B ethtool \-t|\-\-test
+.I devname
+.RI [\*(SD]
+.HP
+.B ethtool \-s
+.I devname
+.BN speed
+.B2 duplex half full
+.B4 port tp aui bnc mii fibre
+.B3 mdix auto on off
+.B2 autoneg on off
+.BN advertise
+.BN phyad
+.B2 xcvr internal external
+.RB [ wol \ \*(WO]
+.RB [ sopass \ \*(MA]
+.RB [ msglvl
+.IR N \ |
+.BI msglvl \ type
+.A1 on off
+.RB ...]
+.HP
+.B ethtool \-n|\-u|\-\-show\-nfc|\-\-show\-ntuple
+.I devname
+.RB [\  rx\-flow\-hash \ \*(FL \ |
+.br
+.BI rule \ N
+.RB ]
+.HP
+.B ethtool \-N|\-U|\-\-config\-nfc|\-\-config\-ntuple
+.I devname
+.BR rx\-flow\-hash \ \*(FL \ \: \*(HO \ |
+.br
+.B 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 tclass
+.BM l4proto
+.BM src\-port
+.BM dst\-port
+.BM spi
+.BM l4data
+.BM vlan\-etype
+.BM vlan
+.BM user\-def
+.RB [ dst-mac \ \*(MA\ [ m \ \*(MA]]
+.BN action
+.BN context
+.BN loc
+.RB |
+.br
+.BI delete \ N
+.HP
+.B ethtool \-w|\-\-get\-dump
+.I devname
+.RB [ data
+.IR filename ]
+.HP
+.B ethtool\ \-W|\-\-set\-dump
+.I devname N
+.HP
+.B ethtool \-T|\-\-show\-time\-stamping
+.I devname
+.HP
+.B ethtool \-x|\-\-show\-rxfh\-indir|\-\-show\-rxfh
+.I devname
+.HP
+.B ethtool \-X|\-\-set\-rxfh\-indir|\-\-rxfh
+.I devname
+.RB [ hkey \ \*(MA:\...]
+.RB [ start
+.IR N ]
+.RB [\  equal
+.IR N \ |
+.BI weight\  W0
+.IR W1
+.RB ...\ | \ default \ ]
+.RB [ hfunc
+.IR FUNC ]
+.RB [ context
+.I CTX
+.RB |\  new ]
+.RB [ delete ]
+.HP
+.B ethtool \-f|\-\-flash
+.I devname file
+.RI [ N ]
+.HP
+.B ethtool \-l|\-\-show\-channels
+.I devname
+.HP
+.B ethtool \-L|\-\-set\-channels
+.I devname
+.BN rx
+.BN tx
+.BN other
+.BN combined
+.HP
+.B ethtool \-m|\-\-dump\-module\-eeprom|\-\-module\-info
+.I devname
+.B2 raw on off
+.B2 hex on off
+.BN offset
+.BN length
+.HP
+.B ethtool \-\-show\-priv\-flags
+.I devname
+.HP
+.B ethtool \-\-set\-priv\-flags
+.I devname flag
+.A1 on off
+.RB ...
+.HP
+.B ethtool \-\-show\-eee
+.I devname
+.HP
+.B ethtool \-\-set\-eee
+.I devname
+.B2 eee on off
+.B2 tx-lpi on off
+.BN tx-timer
+.BN advertise
+.HP
+.B ethtool \-\-set\-phy\-tunable
+.I devname
+.RB [
+.B downshift
+.A1 on off
+.BN count
+.RB ]
+.RB [
+.B fast\-link\-down
+.A1 on off
+.BN msecs
+.RB ]
+.RB [
+.B energy\-detect\-power\-down
+.A1 on off
+.BN msecs
+.RB ]
+.HP
+.B ethtool \-\-get\-phy\-tunable
+.I devname
+.RB [ downshift ]
+.RB [ fast-link-down ]
+.RB [ energy-detect-power-down ]
+.HP
+.B ethtool \-\-reset
+.I devname
+.BN flags
+.RB [ mgmt ]
+.RB [ mgmt-shared ]
+.RB [ irq ]
+.RB [ irq-shared ]
+.RB [ dma ]
+.RB [ dma-shared ]
+.RB [ filter ]
+.RB [ filter-shared ]
+.RB [ offload ]
+.RB [ offload-shared ]
+.RB [ mac ]
+.RB [ mac-shared ]
+.RB [ phy ]
+.RB [ phy-shared ]
+.RB [ ram ]
+.RB [ ram-shared ]
+.RB [ ap ]
+.RB [ ap-shared ]
+.RB [ dedicated ]
+.RB [ all ]
+.HP
+.B ethtool \-\-show\-fec
+.I devname
+.HP
+.B ethtool \-\-set\-fec
+.I devname
+.B encoding
+.BR auto | off | rs | baser \ [...]
+.HP
+.B ethtool \-Q|\-\-per\-queue
+.I devname
+.RB [ queue_mask
+.IR %x ]
+.I sub_command
+.RB ...
+ .
+.
+.\" Adjust lines (i.e. full justification) and hyphenate.
+.ad
+.hy
+
+.SH DESCRIPTION
+.BI ethtool
+is used to query and control network device driver and hardware
+settings, particularly for wired Ethernet devices.
+
+.I devname
+is the name of the network device on which ethtool should operate.
+
+.SH OPTIONS
+.B ethtool
+with a single argument specifying the device name prints current
+settings of the specified device.
+.TP
+.B \-h \-\-help
+Shows a short help message.
+.TP
+.B \-\-version
+Shows the ethtool version number.
+.TP
+.B \-a \-\-show\-pause
+Queries the specified Ethernet device for pause parameter information.
+.TP
+.B \-A \-\-pause
+Changes the pause parameters of the specified Ethernet device.
+.RS 4
+.TP
+.A2 autoneg on off
+Specifies whether pause autonegotiation should be enabled.
+.TP
+.A2 rx on off
+Specifies whether RX pause should be enabled.
+.TP
+.A2 tx on off
+Specifies whether TX pause should be enabled.
+.RE
+.TP
+.B \-c \-\-show\-coalesce
+Queries the specified network device for coalescing information.
+.TP
+.B \-C \-\-coalesce
+Changes the coalescing settings of the specified network device.
+.TP
+.B \-g \-\-show\-ring
+Queries the specified network device for rx/tx ring parameter information.
+.TP
+.B \-G \-\-set\-ring
+Changes the rx/tx ring parameters of the specified network device.
+.RS 4
+.TP
+.BI rx \ N
+Changes the number of ring entries for the Rx ring.
+.TP
+.BI rx\-mini \ N
+Changes the number of ring entries for the Rx Mini ring.
+.TP
+.BI rx\-jumbo \ N
+Changes the number of ring entries for the Rx Jumbo ring.
+.TP
+.BI tx \ N
+Changes the number of ring entries for the Tx ring.
+.RE
+.TP
+.B \-i \-\-driver
+Queries the specified network device for associated driver information.
+.TP
+.B \-d \-\-register\-dump
+Retrieves and prints a register dump for the specified network device.
+The register format for some devices is known and decoded others
+are printed in hex.
+When 
+.I raw 
+is enabled, then ethtool dumps the raw register data to stdout.
+If
+.I file
+is specified, then use contents of previous raw register dump, rather
+than reading from the device.
+.TP
+.B \-e \-\-eeprom\-dump
+Retrieves and prints an EEPROM dump for the specified network device.
+When raw is enabled, then it dumps the raw EEPROM data to stdout. The
+length and offset parameters allow dumping certain portions of the EEPROM.
+Default is to dump the entire EEPROM.
+.RS 4
+.TP
+.BI raw \ on|off
+.TP
+.BI offset \ N
+.TP
+.BI length \ N
+.RE
+.TP
+.B \-E \-\-change\-eeprom
+If value is specified, changes EEPROM byte for the specified network device.
+offset and value specify which byte and it's new value. If value is not
+specified, stdin is read and written to the EEPROM. The length and offset
+parameters allow writing to certain portions of the EEPROM.
+Because of the persistent nature of writing to the EEPROM, a device-specific
+magic key must be specified to prevent the accidental writing to the EEPROM.
+.TP
+.B \-k \-\-show\-features \-\-show\-offload
+Queries the specified network device for the state of protocol
+offload and other features.
+.TP
+.B \-K \-\-features \-\-offload
+Changes the offload parameters and other features of the specified
+network device.  The following feature names are built-in and others
+may be defined by the kernel.
+.RS 4
+.TP
+.A2 rx on off
+Specifies whether RX checksumming should be enabled.
+.TP
+.A2 tx on off
+Specifies whether TX checksumming should be enabled.
+.TP
+.A2 sg on off
+Specifies whether scatter-gather should be enabled.
+.TP
+.A2 tso on off
+Specifies whether TCP segmentation offload should be enabled.
+.TP
+.A2 ufo on off
+Specifies whether UDP fragmentation offload should be enabled 
+.TP
+.A2 gso on off
+Specifies whether generic segmentation offload should be enabled 
+.TP
+.A2 gro on off
+Specifies whether generic receive offload should be enabled
+.TP
+.A2 lro on off
+Specifies whether large receive offload should be enabled
+.TP
+.A2 rxvlan on off
+Specifies whether RX VLAN acceleration should be enabled
+.TP
+.A2 txvlan on off
+Specifies whether TX VLAN acceleration should be enabled
+.TP
+.A2 ntuple on off
+Specifies whether Rx ntuple filters and actions should be enabled
+.TP
+.A2 rxhash on off
+Specifies whether receive hashing offload should be enabled
+.RE
+.TP
+.B \-p \-\-identify
+Initiates adapter-specific action intended to enable an operator to
+easily identify the adapter by sight.  Typically this involves
+blinking one or more LEDs on the specific network port.
+.RS 4
+.TP
+.BN
+Length of time to perform phys-id, in seconds.
+.RE
+.TP
+.B \-P \-\-show\-permaddr
+Queries the specified network device for permanent hardware address.
+.TP
+.B \-r \-\-negotiate
+Restarts auto-negotiation on the specified Ethernet device, if
+auto-negotiation is enabled.
+.TP
+.B \-S \-\-statistics
+Queries the specified network device for NIC- and driver-specific
+statistics.
+.TP
+.B \-\-phy\-statistics
+Queries the specified network device for PHY specific statistics.
+.TP
+.B \-t \-\-test
+Executes adapter selftest on the specified network device. Possible test modes are:
+.RS 4
+.TP
+.B offline
+Perform full set of tests, possibly interrupting normal operation
+during the tests,
+.TP
+.B online
+Perform limited set of tests, not interrupting normal operation,
+.TP
+.B external_lb
+Perform full set of tests, as for \fBoffline\fR, and additionally an
+external-loopback test.
+.RE
+.TP
+.B \-s \-\-change
+Allows changing some or all settings of the specified network device.
+All following options only apply if
+.B \-s
+was specified.
+.RS 4
+.TP
+.BI speed \ N
+Set speed in Mb/s.
+.B ethtool
+with just the device name as an argument will show you the supported device speeds.
+.TP
+.A2 duplex half full
+Sets full or half duplex mode.
+.TP
+.A4 port tp aui bnc mii fibre
+Selects device port.
+.TP
+.A3 mdix auto on off
+Selects MDI-X mode for port. May be used to override the automatic
+detection feature of most adapters. An argument of \fBauto\fR means
+automatic detection of MDI status, \fBon\fR forces MDI-X (crossover)
+mode, while \fBoff\fR means MDI (straight through) mode.  The driver
+should guarantee that this command takes effect immediately, and if
+necessary may reset the link to cause the change to take effect.
+.TP
+.A2 autoneg on off
+Specifies whether autonegotiation should be enabled. Autonegotiation 
+is enabled by default, but in some network devices may have trouble
+with it, so you can disable it if really necessary. 
+.TP
+.BI advertise \ N
+Sets the speed and duplex advertised by autonegotiation.  The argument is
+a hexadecimal value using one or a combination of the following values:
+.TS
+nokeep;
+lB	l	lB.
+0x001	10baseT Half
+0x002	10baseT Full
+0x004	100baseT Half
+0x008	100baseT Full
+0x80000000000000000	100baseT1 Full
+0x010	1000baseT Half	(not supported by IEEE standards)
+0x020	1000baseT Full
+0x100000000000000000	1000baseT1 Full
+0x20000	1000baseKX Full
+0x20000000000	1000baseX Full
+0x800000000000	2500baseT Full
+0x8000	2500baseX Full	(not supported by IEEE standards)
+0x1000000000000	5000baseT Full
+0x1000	10000baseT Full
+0x40000	10000baseKX4 Full
+0x80000	10000baseKR Full
+0x100000	10000baseR_FEC
+0x40000000000	10000baseCR  Full
+0x80000000000	10000baseSR  Full
+0x100000000000	10000baseLR  Full
+0x200000000000	10000baseLRM Full
+0x400000000000	10000baseER  Full
+0x200000	20000baseMLD2 Full	(not supported by IEEE standards)
+0x400000	20000baseKR2 Full	(not supported by IEEE standards)
+0x80000000	25000baseCR Full
+0x100000000	25000baseKR Full
+0x200000000	25000baseSR Full
+0x800000	40000baseKR4 Full
+0x1000000	40000baseCR4 Full
+0x2000000	40000baseSR4 Full
+0x4000000	40000baseLR4 Full
+0x400000000	50000baseCR2 Full
+0x800000000	50000baseKR2 Full
+0x10000000000	50000baseSR2 Full
+0x10000000000000	50000baseKR Full
+0x20000000000000	50000baseSR Full
+0x40000000000000	50000baseCR Full
+0x80000000000000	50000baseLR_ER_FR Full
+0x100000000000000	50000baseDR Full
+0x8000000	56000baseKR4 Full
+0x10000000	56000baseCR4 Full
+0x20000000	56000baseSR4 Full
+0x40000000	56000baseLR4 Full
+0x1000000000	100000baseKR4 Full
+0x2000000000	100000baseSR4 Full
+0x4000000000	100000baseCR4 Full
+0x8000000000	100000baseLR4_ER4 Full
+0x200000000000000	100000baseKR2 Full
+0x400000000000000	100000baseSR2 Full
+0x800000000000000	100000baseCR2 Full
+0x1000000000000000	100000baseLR2_ER2_FR2 Full
+0x2000000000000000	100000baseDR2 Full
+0x4000000000000000	200000baseKR4 Full
+0x8000000000000000	200000baseSR4 Full
+0x10000000000000000	200000baseLR4_ER4_FR4 Full
+0x20000000000000000	200000baseDR4 Full
+0x40000000000000000	200000baseCR4 Full
+.TE
+.TP
+.BI phyad \ N
+PHY address.
+.TP
+.A2 xcvr internal external
+Selects transceiver type. Currently only internal and external can be
+specified, in the future further types might be added.
+.TP
+.BR wol \ \*(WO
+Sets Wake-on-LAN options.  Not all devices support this.  The argument to 
+this option is a string of characters specifying which options to enable.
+.TS
+nokeep;
+lB	l.
+p	Wake on PHY activity
+u	Wake on unicast messages
+m	Wake on multicast messages
+b	Wake on broadcast messages
+a	Wake on ARP
+g	Wake on MagicPacket\[tm]
+s	Enable SecureOn\[tm] password for MagicPacket\[tm]
+f	Wake on filter(s)
+d	T{
+Disable (wake on nothing).  This option clears all previous options.
+T}
+.TE
+.TP
+.B sopass \*(MA
+Sets the SecureOn\[tm] password.  The argument to this option must be 6
+bytes in Ethernet MAC hex format (\*(MA).
+.PP
+.BI msglvl \ N
+.br
+.BI msglvl \ type
+.A1 on off
+.RB ...
+.RS
+Sets the driver message type flags by name or number. \fItype\fR
+names the type of message to enable or disable; \fIN\fR specifies the
+new flags numerically. The defined type names and numbers are:
+.TS
+nokeep;
+lB	l	l.
+drv	0x0001  General driver status
+probe	0x0002  Hardware probing
+link	0x0004  Link state
+timer	0x0008  Periodic status check
+ifdown	0x0010  Interface being brought down
+ifup	0x0020  Interface being brought up
+rx_err	0x0040  Receive error
+tx_err	0x0080  Transmit error
+tx_queued	0x0100  Transmit queueing
+intr	0x0200  Interrupt handling
+tx_done	0x0400  Transmit completion
+rx_status	0x0800  Receive completion
+pktdata	0x1000  Packet contents
+hw	0x2000  Hardware status
+wol	0x4000  Wake-on-LAN status
+.TE
+.PP
+The precise meanings of these type flags differ between drivers.
+.RE
+.PD
+.RE
+.TP
+.B \-n \-u \-\-show\-nfc \-\-show\-ntuple
+Retrieves receive network flow classification options or rules.
+.RS 4
+.TP
+.BR rx\-flow\-hash \ \*(FL
+Retrieves the hash options for the specified flow type.
+.TS
+nokeep;
+lB	l.
+tcp4	TCP over IPv4
+udp4	UDP over IPv4
+ah4	IPSEC AH over IPv4
+esp4	IPSEC ESP over IPv4
+sctp4	SCTP over IPv4
+tcp6	TCP over IPv6
+udp6	UDP over IPv6
+ah6	IPSEC AH over IPv6
+esp6	IPSEC ESP over IPv6
+sctp6	SCTP over IPv6
+.TE
+.TP
+.BI rule \ N
+Retrieves the RX classification rule with the given ID.
+.RE
+.PD
+.RE
+.TP
+.B \-N \-U \-\-config\-nfc \-\-config\-ntuple
+Configures receive network flow classification options or rules.
+.RS 4
+.TP
+.BR rx\-flow\-hash \ \*(FL \: \*(HO
+Configures the hash options for the specified flow type.
+.TS
+nokeep;
+lB	l.
+m	Hash on the Layer 2 destination address of the rx packet.
+v	Hash on the VLAN tag of the rx packet.
+t	Hash on the Layer 3 protocol field of the rx packet.
+s	Hash on the IP source address of the rx packet.
+d	Hash on the IP destination address of the rx packet.
+f	Hash on bytes 0 and 1 of the Layer 4 header of the rx packet.
+n	Hash on bytes 2 and 3 of the Layer 4 header of the rx packet.
+r	T{
+Discard all packets of this flow type. When this option is set, all
+other options are ignored.
+T}
+.TE
+.TP
+.B flow\-type \*(NC
+Inserts or updates a classification rule for the specified flow type.
+.TS
+nokeep;
+lB	l.
+ether	Ethernet
+ip4	Raw IPv4
+tcp4	TCP over IPv4
+udp4	UDP over IPv4
+sctp4	SCTP over IPv4
+ah4	IPSEC AH over IPv4
+esp4	IPSEC ESP over IPv4
+ip6	Raw IPv6
+tcp6	TCP over IPv6
+udp6	UDP over IPv6
+sctp6	SCTP over IPv6
+ah6	IPSEC AH over IPv6
+esp6	IPSEC ESP over IPv6
+.TE
+.PP
+For all fields that allow both a value and a mask to be specified, the
+mask may be specified immediately after the value using the \fBm\fR
+keyword, or separately using the field name keyword with \fB-mask\fR
+appended, e.g. \fBsrc-mask\fR.
+.PD
+.TP
+.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
+.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 proto \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Includes the Ethernet protocol number (ethertype) and an optional mask.
+Valid only for flow-type ether.
+.TP
+.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 IP based flow-types.
+.TP
+.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 IP based flow-types.
+.TP
+.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 tclass \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Specify the value of the Traffic Class field in the incoming packet to
+match along with an optional mask.  Applies to all IPv6 based flow-types.
+.TP
+.BI l4proto \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Includes the layer 4 protocol number and optional mask.  Valid only for
+flow-types ip4 and ip6.
+.TP
+.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 and their IPv6 equivalents.
+.TP
+.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 and their IPv6 equivalents.
+.TP
+.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 and their IPv6 equivalents.
+.TP
+.BI l4data \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Specify the value of the first 4 Bytes of Layer 4 in the incoming packet to
+match along with an optional mask.  Valid for ip4 and ip6 flow-types.
+.TP
+.BI vlan\-etype \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Includes the VLAN tag Ethertype and an optional mask.
+.TP
+.BI vlan \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Includes the VLAN tag and an optional mask.
+.TP
+.BI user\-def \ N \\fR\ [\\fPm \ N \\fR]\\fP
+Includes 64-bits of user-specific data and an optional mask.
+.TP
+.BR dst-mac \ \*(MA\ [ m \ \*(MA]
+Includes the destination MAC address, specified as 6 bytes in hexadecimal
+separated by colons, along with an optional mask.
+Valid for all IP based flow-types.
+.TP
+.BI action \ N
+Specifies the Rx queue to send packets to, or some other action.
+.TS
+nokeep;
+lB	l.
+-1	Drop the matched flow
+-2	Use the matched flow as a Wake-on-LAN filter
+0 or higher	Rx queue to route the flow
+.TE
+.TP
+.BI context \ N
+Specifies the RSS context to spread packets over multiple queues; either
+.B 0
+for the default RSS context, or a value returned by
+.BI ethtool\ -X\  ... \ context
+.BR new .
+.TP
+.BI vf \ N
+Specifies the Virtual Function the filter applies to. Not compatible with action.
+.TP
+.BI queue \ N
+Specifies the Rx queue to send packets to. Not compatible with action.
+.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.
+.TP
+.BI delete \ N
+Deletes the RX classification rule with the given ID.
+.RE
+.TP
+.B \-w \-\-get\-dump
+Retrieves and prints firmware dump for the specified network device.
+By default, it prints out the dump flag, version and length of the dump data.
+When
+.I data
+is indicated, then ethtool fetches the dump data and directs it to a
+.I file.
+.TP
+.B \-W \-\-set\-dump
+Sets the dump flag for the device.
+.TP
+.B \-T \-\-show\-time\-stamping
+Show the device's time stamping capabilities and associated PTP
+hardware clock.
+.TP
+.B \-x \-\-show\-rxfh\-indir \-\-show\-rxfh
+Retrieves the receive flow hash indirection table and/or RSS hash key.
+.TP
+.B \-X \-\-set\-rxfh\-indir \-\-rxfh
+Configures the receive flow hash indirection table and/or RSS hash key.
+.RS 4
+.TP
+.BI hkey
+Sets RSS hash key of the specified network device. RSS hash key should be of device supported length.
+Hash key format must be in xx:yy:zz:aa:bb:cc format meaning both the nibbles of a byte should be mentioned
+even if a nibble is zero.
+.TP
+.BI hfunc
+Sets RSS hash function of the specified network device.
+List of RSS hash functions which kernel supports is shown as a part of the --show-rxfh command output.
+.TP
+.BI start\  N
+For the \fBequal\fR and \fBweight\fR options, sets the starting receive queue
+for spreading flows to \fIN\fR.
+.TP
+.BI equal\  N
+Sets the receive flow hash indirection table to spread flows evenly
+between the first \fIN\fR receive queues.
+.TP
+\fBweight\fR \fIW0 W1\fR ...
+Sets the receive flow hash indirection table to spread flows between
+receive queues according to the given weights.  The sum of the weights
+must be non-zero and must not exceed the size of the indirection table.
+.TP
+.BI default
+Sets the receive flow hash indirection table to its default value.
+.TP
+\fBcontext \fICTX\fR | \fBnew\fR
+Specifies an RSS context to act on; either
+.B new
+to allocate a new RSS context, or
+.IR CTX ,
+a value returned by a previous
+.IB ... \ context
+.BR new .
+.TP
+.B delete
+Delete the specified RSS context.  May only be used in conjunction with
+.B context
+and a non-zero
+.I CTX
+value.
+.RE
+.TP
+.B \-f \-\-flash
+Write a firmware image to flash or other non-volatile memory on the
+device.
+.RS 4
+.TP
+.I file
+Specifies the filename of the firmware image.  The firmware must first
+be installed in one of the directories where the kernel firmware
+loader or firmware agent will look, such as /lib/firmware.
+.TP
+.I N
+If the device stores multiple firmware images in separate regions of
+non-volatile memory, this parameter may be used to specify which
+region is to be written.  The default is 0, requesting that all
+regions are written.  All other values are driver-dependent.
+.RE
+.PD
+.TP
+.B \-l \-\-show\-channels
+Queries the specified network device for the numbers of channels it has.
+A channel is an IRQ and the set of queues that can trigger that IRQ.
+.TP
+.B \-L \-\-set\-channels
+Changes the numbers of channels of the specified network device.
+.RS 4
+.TP
+.BI rx \ N
+Changes the number of channels with only receive queues.
+.TP
+.BI tx \ N
+Changes the number of channels with only transmit queues.
+.TP
+.BI other \ N
+Changes the number of channels used only for other purposes e.g. link interrupts or SR-IOV co-ordination.
+.TP
+.BI combined \ N
+Changes the number of multi-purpose channels.
+.RE
+.TP
+.B \-m \-\-dump\-module\-eeprom \-\-module\-info
+Retrieves and if possible decodes the EEPROM from plugin modules, e.g SFP+, QSFP.
+If the driver and module support it, the optical diagnostic information is also
+read and decoded.
+.TP
+.B \-\-show\-priv\-flags
+Queries the specified network device for its private flags.  The
+names and meanings of private flags (if any) are defined by each
+network device driver.
+.TP
+.B \-\-set\-priv\-flags
+Sets the device's private flags as specified.
+.RS 4
+.PP
+.I flag
+.A1 on off
+Sets the state of the named private flag.
+.RE
+.TP
+.B \-\-show\-eee
+Queries the specified network device for its support of Energy-Efficient
+Ethernet (according to the IEEE 802.3az specifications)
+.TP
+.B \-\-set\-eee
+Sets the device EEE behaviour.
+.RS 4
+.TP
+.A2 eee on off
+Enables/disables the device support of EEE.
+.TP
+.A2 tx-lpi on off
+Determines whether the device should assert its Tx LPI.
+.TP
+.BI advertise \ N
+Sets the speeds for which the device should advertise EEE capabilities.
+Values are as for
+.B \-\-change advertise
+.TP
+.BI tx-timer \ N
+Sets the amount of time the device should stay in idle mode prior to asserting
+its Tx LPI (in microseconds). This has meaning only when Tx LPI is enabled.
+.RE
+.TP
+.B \-\-set\-phy\-tunable
+Sets the PHY tunable parameters.
+.RS 4
+.TP
+.A2 downshift on off
+Specifies whether downshift should be enabled.
+.TS
+nokeep;
+lB	l.
+.BI count \ N
+	Sets the PHY downshift re-tries count.
+.TE
+.TP
+.A2 fast-link-down on off
+Specifies whether Fast Link Down should be enabled and time until link down (if supported).
+.TS
+nokeep;
+lB	l.
+.BI msecs \ N
+	Sets the period after which the link is reported as down. Note that the PHY may choose
+	the closest supported value. Only on reading back the tunable do you get the actual value.
+.TE
+.TP
+.A2 energy-detect-power-down on off
+Specifies whether Energy Detect Power Down (EDPD) should be enabled (if supported).
+This will put the RX and TX circuit blocks into a low power mode, and the PHY will
+wake up periodically to send link pulses to avoid any lock-up situation with a peer
+PHY that may also have EDPD enabled. By default, this setting will also enable the
+periodic transmission of TX pulses.
+.TS
+nokeep;
+lB	l.
+.BI msecs \ N
+	Some PHYs support configuration of the wake-up interval to send TX pulses.
+	This setting allows the control of this interval, and 0 disables TX pulses
+	if the PHY supports this. Disabling TX pulses can create a lock-up situation
+	where neither of the PHYs wakes the other one. If unspecified the default
+	value (in milliseconds) will be used by the PHY.
+.TE
+.TP
+.PD
+.RE
+.TP
+.B \-\-get\-phy\-tunable
+Gets the PHY tunable parameters.
+.RS 4
+.TP
+.B downshift
+For operation in cabling environments that are incompatible with 1000BASE-T,
+PHY device provides an automatic link speed downshift operation.
+Link speed downshift after N failed 1000BASE-T auto-negotiation attempts.
+Downshift is useful where cable does not have the 4 pairs instance.
+
+Gets the PHY downshift count/status.
+.TP
+.B fast\-link\-down
+Depending on the mode it may take 0.5s - 1s until a broken link is reported as down.
+In certain use cases a link-down event needs to be reported as soon as possible.
+Some PHYs support a Fast Link Down Feature and may allow configuration of the delay
+before a broken link is reported as being down.
+
+Gets the PHY Fast Link Down status / period.
+.TP
+.B energy\-detect\-power\-down
+Gets the current configured setting for Energy Detect Power Down (if supported).
+
+.RE
+.TP
+.B \-\-reset
+Reset hardware components specified by flags and components listed below
+.RS 4
+.TP
+.BI flags \ N
+Resets the components based on direct flags mask
+.TP
+.B mgmt
+Management processor
+.TP
+.B irq
+Interrupt requester
+.TP
+.B dma
+DMA engine
+.TP
+.B filter
+Filtering/flow direction
+.TP
+.B offload
+Protocol offload
+.TP
+.B mac
+Media access controller
+.TP
+.B phy
+Transceiver/PHY
+.TP
+.B ram
+RAM shared between multiple components
+.B ap
+Application Processor
+.TP
+.B dedicated
+All components dedicated to this interface
+.TP
+.B all
+All components used by this interface, even if shared
+.RE
+.TP
+.B \-\-show\-fec
+Queries the specified network device for its support of Forward Error Correction.
+.TP
+.B \-\-set\-fec
+Configures Forward Error Correction for the specified network device.
+
+Forward Error Correction modes selected by a user are expected to be persisted
+after any hotplug events. If a module is swapped that does not support the
+current FEC mode, the driver or firmware must take the link down
+administratively and report the problem in the system logs for users to correct.
+.RS 4
+.TP
+.BR encoding\ auto | off | rs | baser \ [...]
+
+Sets the FEC encoding for the device.  Combinations of options are specified as
+e.g.
+.B encoding auto rs
+; the semantics of such combinations vary between drivers.
+.TS
+nokeep;
+lB	l.
+auto	Use the driver's default encoding
+off	Turn off FEC
+RS	Force RS-FEC encoding
+BaseR	Force BaseR encoding
+.TE
+.RE
+.TP
+.B \-Q|\-\-per\-queue
+Applies provided sub command to specific queues.
+.RS 4
+.TP
+.B queue_mask %x
+Sets the specific queues which the sub command is applied to.
+If queue_mask is not set, the sub command will be applied to all queues.
+.TP
+.B sub_command
+Sub command to apply. The supported sub commands include --show-coalesce and
+--coalesce.
+.RE
+.SH BUGS
+Not supported (in part or whole) on all network drivers.
+.SH AUTHOR
+.B ethtool
+was written by David Miller.
+
+Modifications by 
+Jeff Garzik, 
+Tim Hockin,
+Jakub Jelinek,
+Andre Majorel,
+Eli Kupermann,
+Scott Feldman,
+Andi Kleen,
+Alexander Duyck,
+Sucheta Chakraborty,
+Jesse Brandeburg,
+Ben Hutchings,
+Scott Branden.
+.SH AVAILABILITY
+.B ethtool
+is available from
+.UR http://www.kernel.org/pub/software/network/ethtool/
+.UE
diff --git a/ethtool.c b/ethtool.c
new file mode 100644
index 0000000..acf183d
--- /dev/null
+++ b/ethtool.c
@@ -0,0 +1,5765 @@
+/*
+ * ethtool.c: Linux ethernet device configuration tool.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Portions Copyright 2001 Sun Microsystems
+ * 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>
+ * e100 support by Wen Tao <wen-hwa.tao@intel.com>
+ * ixgb support by Nicholas Nunley <Nicholas.d.nunley@intel.com>
+ * 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
+ * MDI-X set support by Jesse Brandeburg <jesse.brandeburg@intel.com>
+ *	Copyright 2012 Intel Corporation
+ * vmxnet3 support by Shrikrishna Khare <skhare@vmware.com>
+ * Various features by Ben Hutchings <ben@decadent.org.uk>;
+ *	Copyright 2008-2010, 2013-2016 Ben Hutchings
+ * QSFP+/QSFP28 DOM support by Vidya Sagar Ravipati <vidya@cumulusnetworks.com>
+ *
+ * TODO:
+ *   * show settings for all devices
+ */
+
+#include "internal.h"
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <sys/utsname.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <linux/sockios.h>
+#include <linux/netlink.h>
+
+#ifndef MAX_ADDR_LEN
+#define MAX_ADDR_LEN	32
+#endif
+
+#ifndef HAVE_NETIF_MSG
+enum {
+	NETIF_MSG_DRV		= 0x0001,
+	NETIF_MSG_PROBE		= 0x0002,
+	NETIF_MSG_LINK		= 0x0004,
+	NETIF_MSG_TIMER		= 0x0008,
+	NETIF_MSG_IFDOWN	= 0x0010,
+	NETIF_MSG_IFUP		= 0x0020,
+	NETIF_MSG_RX_ERR	= 0x0040,
+	NETIF_MSG_TX_ERR	= 0x0080,
+	NETIF_MSG_TX_QUEUED	= 0x0100,
+	NETIF_MSG_INTR		= 0x0200,
+	NETIF_MSG_TX_DONE	= 0x0400,
+	NETIF_MSG_RX_STATUS	= 0x0800,
+	NETIF_MSG_PKTDATA	= 0x1000,
+	NETIF_MSG_HW		= 0x2000,
+	NETIF_MSG_WOL		= 0x4000,
+};
+#endif
+
+#ifndef NETLINK_GENERIC
+#define NETLINK_GENERIC	16
+#endif
+
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+
+static void exit_bad_args(void) __attribute__((noreturn));
+
+static void exit_bad_args(void)
+{
+	fprintf(stderr,
+		"ethtool: bad command line argument(s)\n"
+		"For more information run ethtool -h\n");
+	exit(1);
+}
+
+typedef enum {
+	CMDL_NONE,
+	CMDL_BOOL,
+	CMDL_S32,
+	CMDL_U8,
+	CMDL_U16,
+	CMDL_U32,
+	CMDL_U64,
+	CMDL_BE16,
+	CMDL_IP4,
+	CMDL_STR,
+	CMDL_FLAG,
+	CMDL_MAC,
+} cmdline_type_t;
+
+struct cmdline_info {
+	const char *name;
+	cmdline_type_t type;
+	/* Points to int (BOOL), s32, u16, u32 (U32/FLAG/IP4), u64,
+	 * char * (STR) or u8[6] (MAC).  For FLAG, the value accumulates
+	 * all flags to be set. */
+	void *wanted_val;
+	void *ioctl_val;
+	/* For FLAG, the flag value to be set/cleared */
+	u32 flag_val;
+	/* For FLAG, points to u32 and accumulates all flags seen.
+	 * For anything else, points to int and is set if the option is
+	 * seen. */
+	void *seen_val;
+};
+
+struct flag_info {
+	const char *name;
+	u32 value;
+};
+
+static const struct flag_info flags_msglvl[] = {
+	{ "drv",	NETIF_MSG_DRV },
+	{ "probe",	NETIF_MSG_PROBE },
+	{ "link",	NETIF_MSG_LINK },
+	{ "timer",	NETIF_MSG_TIMER },
+	{ "ifdown",	NETIF_MSG_IFDOWN },
+	{ "ifup",	NETIF_MSG_IFUP },
+	{ "rx_err",	NETIF_MSG_RX_ERR },
+	{ "tx_err",	NETIF_MSG_TX_ERR },
+	{ "tx_queued",	NETIF_MSG_TX_QUEUED },
+	{ "intr",	NETIF_MSG_INTR },
+	{ "tx_done",	NETIF_MSG_TX_DONE },
+	{ "rx_status",	NETIF_MSG_RX_STATUS },
+	{ "pktdata",	NETIF_MSG_PKTDATA },
+	{ "hw",		NETIF_MSG_HW },
+	{ "wol",	NETIF_MSG_WOL },
+};
+
+struct off_flag_def {
+	const char *short_name;
+	const char *long_name;
+	const char *kernel_name;
+	u32 get_cmd, set_cmd;
+	u32 value;
+	/* For features exposed through ETHTOOL_GFLAGS, the oldest
+	 * kernel version for which we can trust the result.  Where
+	 * the flag was added at the same time the kernel started
+	 * supporting the feature, this is 0 (to allow for backports).
+	 * Where the feature was supported before the flag was added,
+	 * it is the version that introduced the flag.
+	 */
+	u32 min_kernel_ver;
+};
+static const struct off_flag_def off_flag_def[] = {
+	{ "rx",     "rx-checksumming",		    "rx-checksum",
+	  ETHTOOL_GRXCSUM, ETHTOOL_SRXCSUM, ETH_FLAG_RXCSUM,	0 },
+	{ "tx",     "tx-checksumming",		    "tx-checksum-*",
+	  ETHTOOL_GTXCSUM, ETHTOOL_STXCSUM, ETH_FLAG_TXCSUM,	0 },
+	{ "sg",     "scatter-gather",		    "tx-scatter-gather*",
+	  ETHTOOL_GSG,	   ETHTOOL_SSG,     ETH_FLAG_SG,	0 },
+	{ "tso",    "tcp-segmentation-offload",	    "tx-tcp*-segmentation",
+	  ETHTOOL_GTSO,	   ETHTOOL_STSO,    ETH_FLAG_TSO,	0 },
+	{ "ufo",    "udp-fragmentation-offload",    "tx-udp-fragmentation",
+	  ETHTOOL_GUFO,	   ETHTOOL_SUFO,    ETH_FLAG_UFO,	0 },
+	{ "gso",    "generic-segmentation-offload", "tx-generic-segmentation",
+	  ETHTOOL_GGSO,	   ETHTOOL_SGSO,    ETH_FLAG_GSO,	0 },
+	{ "gro",    "generic-receive-offload",	    "rx-gro",
+	  ETHTOOL_GGRO,	   ETHTOOL_SGRO,    ETH_FLAG_GRO,	0 },
+	{ "lro",    "large-receive-offload",	    "rx-lro",
+	  0,		   0,		    ETH_FLAG_LRO,
+	  KERNEL_VERSION(2,6,24) },
+	{ "rxvlan", "rx-vlan-offload",		    "rx-vlan-hw-parse",
+	  0,		   0,		    ETH_FLAG_RXVLAN,
+	  KERNEL_VERSION(2,6,37) },
+	{ "txvlan", "tx-vlan-offload",		    "tx-vlan-hw-insert",
+	  0,		   0,		    ETH_FLAG_TXVLAN,
+	  KERNEL_VERSION(2,6,37) },
+	{ "ntuple", "ntuple-filters",		    "rx-ntuple-filter",
+	  0,		   0,		    ETH_FLAG_NTUPLE,	0 },
+	{ "rxhash", "receive-hashing",		    "rx-hashing",
+	  0,		   0,		    ETH_FLAG_RXHASH,	0 },
+};
+
+struct feature_def {
+	char name[ETH_GSTRING_LEN];
+	int off_flag_index; /* index in off_flag_def; negative if none match */
+};
+
+struct feature_defs {
+	size_t n_features;
+	/* Number of features each offload flag is associated with */
+	unsigned int off_flag_matched[ARRAY_SIZE(off_flag_def)];
+	/* Name and offload flag index for each feature */
+	struct feature_def def[0];
+};
+
+#define FEATURE_BITS_TO_BLOCKS(n_bits)		DIV_ROUND_UP(n_bits, 32U)
+#define FEATURE_WORD(blocks, index, field)	((blocks)[(index) / 32U].field)
+#define FEATURE_FIELD_FLAG(index)		(1U << (index) % 32U)
+#define FEATURE_BIT_SET(blocks, index, field)			\
+	(FEATURE_WORD(blocks, index, field) |= FEATURE_FIELD_FLAG(index))
+#define FEATURE_BIT_CLEAR(blocks, index, field)			\
+	(FEATURE_WORD(blocks, index, filed) &= ~FEATURE_FIELD_FLAG(index))
+#define FEATURE_BIT_IS_SET(blocks, index, field)		\
+	(FEATURE_WORD(blocks, index, field) & FEATURE_FIELD_FLAG(index))
+
+static long long
+get_int_range(char *str, int base, long long min, long long max)
+{
+	long long v;
+	char *endp;
+
+	if (!str)
+		exit_bad_args();
+	errno = 0;
+	v = strtoll(str, &endp, base);
+	if (errno || *endp || v < min || v > max)
+		exit_bad_args();
+	return v;
+}
+
+static unsigned long long
+get_uint_range(char *str, int base, unsigned long long max)
+{
+	unsigned long long v;
+	char *endp;
+
+	if (!str)
+		exit_bad_args();
+	errno = 0;
+	v = strtoull(str, &endp, base);
+	if (errno || *endp || v > max)
+		exit_bad_args();
+	return v;
+}
+
+static int get_int(char *str, int base)
+{
+	return get_int_range(str, base, INT_MIN, INT_MAX);
+}
+
+static u32 get_u32(char *str, int base)
+{
+	return get_uint_range(str, base, 0xffffffff);
+}
+
+static void get_mac_addr(char *src, unsigned char *dest)
+{
+	int count;
+	int i;
+	int buf[ETH_ALEN];
+
+	count = sscanf(src, "%2x:%2x:%2x:%2x:%2x:%2x",
+		&buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5]);
+	if (count != ETH_ALEN)
+		exit_bad_args();
+
+	for (i = 0; i < count; i++)
+		dest[i] = buf[i];
+}
+
+static int parse_hex_u32_bitmap(const char *s,
+				unsigned int nbits, u32 *result)
+{
+	const unsigned int nwords = __KERNEL_DIV_ROUND_UP(nbits, 32);
+	size_t slen = strlen(s);
+	size_t i;
+
+	/* ignore optional '0x' prefix */
+	if ((slen > 2) && (strncasecmp(s, "0x", 2) == 0)) {
+		slen -= 2;
+		s += 2;
+	}
+
+	if (slen > 8 * nwords)  /* up to 2 digits per byte */
+		return -1;
+
+	memset(result, 0, 4 * nwords);
+	for (i = 0; i < slen; ++i) {
+		const unsigned int shift = (slen - 1 - i) * 4;
+		u32 *dest = &result[shift / 32];
+		u32 nibble;
+
+		if ('a' <= s[i] && s[i] <= 'f')
+			nibble = 0xa + (s[i] - 'a');
+		else if ('A' <= s[i] && s[i] <= 'F')
+			nibble = 0xa + (s[i] - 'A');
+		else if ('0' <= s[i] && s[i] <= '9')
+			nibble = (s[i] - '0');
+		else
+			return -1;
+
+		*dest |= (nibble << (shift % 32));
+	}
+
+	return 0;
+}
+
+static void parse_generic_cmdline(struct cmd_context *ctx,
+				  int *changed,
+				  struct cmdline_info *info,
+				  unsigned int n_info)
+{
+	int argc = ctx->argc;
+	char **argp = ctx->argp;
+	int i, idx;
+	int found;
+
+	for (i = 0; i < argc; i++) {
+		found = 0;
+		for (idx = 0; idx < n_info; idx++) {
+			if (!strcmp(info[idx].name, argp[i])) {
+				found = 1;
+				*changed = 1;
+				if (info[idx].type != CMDL_FLAG &&
+				    info[idx].seen_val)
+					*(int *)info[idx].seen_val = 1;
+				i += 1;
+				if (i >= argc)
+					exit_bad_args();
+				switch (info[idx].type) {
+				case CMDL_BOOL: {
+					int *p = info[idx].wanted_val;
+					if (!strcmp(argp[i], "on"))
+						*p = 1;
+					else if (!strcmp(argp[i], "off"))
+						*p = 0;
+					else
+						exit_bad_args();
+					break;
+				}
+				case CMDL_S32: {
+					s32 *p = info[idx].wanted_val;
+					*p = get_int_range(argp[i], 0,
+							   -0x80000000LL,
+							   0x7fffffff);
+					break;
+				}
+				case CMDL_U8: {
+					u8 *p = info[idx].wanted_val;
+					*p = get_uint_range(argp[i], 0, 0xff);
+					break;
+				}
+				case CMDL_U16: {
+					u16 *p = info[idx].wanted_val;
+					*p = get_uint_range(argp[i], 0, 0xffff);
+					break;
+				}
+				case CMDL_U32: {
+					u32 *p = info[idx].wanted_val;
+					*p = get_uint_range(argp[i], 0,
+							    0xffffffff);
+					break;
+				}
+				case CMDL_U64: {
+					u64 *p = info[idx].wanted_val;
+					*p = get_uint_range(
+						argp[i], 0,
+						0xffffffffffffffffLL);
+					break;
+				}
+				case CMDL_BE16: {
+					u16 *p = info[idx].wanted_val;
+					*p = cpu_to_be16(
+						get_uint_range(argp[i], 0,
+							       0xffff));
+					break;
+				}
+				case CMDL_IP4: {
+					u32 *p = info[idx].wanted_val;
+					struct in_addr in;
+					if (!inet_aton(argp[i], &in))
+						exit_bad_args();
+					*p = in.s_addr;
+					break;
+				}
+				case CMDL_MAC:
+					get_mac_addr(argp[i],
+						     info[idx].wanted_val);
+					break;
+				case CMDL_FLAG: {
+					u32 *p;
+					p = info[idx].seen_val;
+					*p |= info[idx].flag_val;
+					if (!strcmp(argp[i], "on")) {
+						p = info[idx].wanted_val;
+						*p |= info[idx].flag_val;
+					} else if (strcmp(argp[i], "off")) {
+						exit_bad_args();
+					}
+					break;
+				}
+				case CMDL_STR: {
+					char **s = info[idx].wanted_val;
+					*s = strdup(argp[i]);
+					break;
+				}
+				default:
+					exit_bad_args();
+				}
+				break;
+			}
+		}
+		if (!found)
+			exit_bad_args();
+	}
+}
+
+static void flag_to_cmdline_info(const char *name, u32 value,
+				 u32 *wanted, u32 *mask,
+				 struct cmdline_info *cli)
+{
+	memset(cli, 0, sizeof(*cli));
+	cli->name = name;
+	cli->type = CMDL_FLAG;
+	cli->flag_val = value;
+	cli->wanted_val = wanted;
+	cli->seen_val = mask;
+}
+
+static void
+print_flags(const struct flag_info *info, unsigned int n_info, u32 value)
+{
+	const char *sep = "";
+
+	while (n_info) {
+		if (value & info->value) {
+			printf("%s%s", sep, info->name);
+			sep = " ";
+			value &= ~info->value;
+		}
+		++info;
+		--n_info;
+	}
+
+	/* Print any unrecognised flags in hex */
+	if (value)
+		printf("%s%#x", sep, value);
+}
+
+static int rxflow_str_to_type(const char *str)
+{
+	int flow_type = 0;
+
+	if (!strcmp(str, "tcp4"))
+		flow_type = TCP_V4_FLOW;
+	else if (!strcmp(str, "udp4"))
+		flow_type = UDP_V4_FLOW;
+	else if (!strcmp(str, "ah4") || !strcmp(str, "esp4"))
+		flow_type = AH_ESP_V4_FLOW;
+	else if (!strcmp(str, "sctp4"))
+		flow_type = SCTP_V4_FLOW;
+	else if (!strcmp(str, "tcp6"))
+		flow_type = TCP_V6_FLOW;
+	else if (!strcmp(str, "udp6"))
+		flow_type = UDP_V6_FLOW;
+	else if (!strcmp(str, "ah6") || !strcmp(str, "esp6"))
+		flow_type = AH_ESP_V6_FLOW;
+	else if (!strcmp(str, "sctp6"))
+		flow_type = SCTP_V6_FLOW;
+	else if (!strcmp(str, "ether"))
+		flow_type = ETHER_FLOW;
+
+	return flow_type;
+}
+
+static int do_version(struct cmd_context *ctx maybe_unused)
+{
+	fprintf(stdout,
+		PACKAGE " version " VERSION
+#ifndef ETHTOOL_ENABLE_PRETTY_DUMP
+		" (pretty dumps disabled)"
+#endif
+		"\n");
+	return 0;
+}
+
+/* link mode routines */
+
+static ETHTOOL_DECLARE_LINK_MODE_MASK(all_advertised_modes);
+static ETHTOOL_DECLARE_LINK_MODE_MASK(all_advertised_flags);
+
+static void init_global_link_mode_masks(void)
+{
+	static const enum ethtool_link_mode_bit_indices
+		all_advertised_modes_bits[] = {
+		ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+		ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+		ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+		ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+		ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
+		ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+		ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+		ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
+		ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+		ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+		ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
+		ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
+		ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT,
+		ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
+		ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
+		ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
+		ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
+		ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
+		ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT,
+		ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT,
+		ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT,
+		ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT,
+		ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
+		ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
+		ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
+		ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
+		ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
+		ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
+		ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
+		ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
+		ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
+		ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
+		ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
+		ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
+		ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
+		ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
+		ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
+		ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
+		ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+		ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+		ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
+		ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
+		ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
+		ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
+		ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
+		ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
+		ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
+		ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
+		ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
+		ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
+		ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
+		ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
+		ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
+		ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT,
+		ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
+		ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
+		ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
+	};
+	static const enum ethtool_link_mode_bit_indices
+		additional_advertised_flags_bits[] = {
+		ETHTOOL_LINK_MODE_Autoneg_BIT,
+		ETHTOOL_LINK_MODE_TP_BIT,
+		ETHTOOL_LINK_MODE_AUI_BIT,
+		ETHTOOL_LINK_MODE_MII_BIT,
+		ETHTOOL_LINK_MODE_FIBRE_BIT,
+		ETHTOOL_LINK_MODE_BNC_BIT,
+		ETHTOOL_LINK_MODE_Pause_BIT,
+		ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+		ETHTOOL_LINK_MODE_Backplane_BIT,
+		ETHTOOL_LINK_MODE_FEC_NONE_BIT,
+		ETHTOOL_LINK_MODE_FEC_RS_BIT,
+		ETHTOOL_LINK_MODE_FEC_BASER_BIT,
+	};
+	unsigned int i;
+
+	ethtool_link_mode_zero(all_advertised_modes);
+	ethtool_link_mode_zero(all_advertised_flags);
+	for (i = 0; i < ARRAY_SIZE(all_advertised_modes_bits); ++i) {
+		ethtool_link_mode_set_bit(all_advertised_modes_bits[i],
+					  all_advertised_modes);
+		ethtool_link_mode_set_bit(all_advertised_modes_bits[i],
+					  all_advertised_flags);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(additional_advertised_flags_bits); ++i) {
+		ethtool_link_mode_set_bit(
+			additional_advertised_flags_bits[i],
+			all_advertised_flags);
+	}
+}
+
+static void dump_link_caps(const char *prefix, const char *an_prefix,
+			   const u32 *mask, int link_mode_only);
+
+static void dump_supported(const struct ethtool_link_usettings *link_usettings)
+{
+	fprintf(stdout, "	Supported ports: [ ");
+	if (ethtool_link_mode_test_bit(
+		    ETHTOOL_LINK_MODE_TP_BIT,
+		    link_usettings->link_modes.supported))
+		fprintf(stdout, "TP ");
+	if (ethtool_link_mode_test_bit(
+		    ETHTOOL_LINK_MODE_AUI_BIT,
+		    link_usettings->link_modes.supported))
+		fprintf(stdout, "AUI ");
+	if (ethtool_link_mode_test_bit(
+		    ETHTOOL_LINK_MODE_BNC_BIT,
+		    link_usettings->link_modes.supported))
+		fprintf(stdout, "BNC ");
+	if (ethtool_link_mode_test_bit(
+		    ETHTOOL_LINK_MODE_MII_BIT,
+		    link_usettings->link_modes.supported))
+		fprintf(stdout, "MII ");
+	if (ethtool_link_mode_test_bit(
+		    ETHTOOL_LINK_MODE_FIBRE_BIT,
+		    link_usettings->link_modes.supported))
+		fprintf(stdout, "FIBRE ");
+	if (ethtool_link_mode_test_bit(
+		    ETHTOOL_LINK_MODE_Backplane_BIT,
+		    link_usettings->link_modes.supported))
+		fprintf(stdout, "Backplane ");
+	fprintf(stdout, "]\n");
+
+	dump_link_caps("Supported", "Supports",
+		       link_usettings->link_modes.supported, 0);
+}
+
+/* Print link capability flags (supported, advertised or lp_advertised).
+ * Assumes that the corresponding SUPPORTED and ADVERTISED flags are equal.
+ */
+static void dump_link_caps(const char *prefix, const char *an_prefix,
+			   const u32 *mask, int link_mode_only)
+{
+	static const struct {
+		int same_line; /* print on same line as previous */
+		unsigned int bit_index;
+		const char *name;
+	} mode_defs[] = {
+		{ 0, ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+		  "10baseT/Half" },
+		{ 1, ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+		  "10baseT/Full" },
+		{ 0, ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+		  "100baseT/Half" },
+		{ 1, ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+		  "100baseT/Full" },
+		{ 0, ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
+		  "100baseT1/Full" },
+		{ 0, ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
+		  "1000baseT/Half" },
+		{ 1, ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+		  "1000baseT/Full" },
+		{ 0, ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
+		  "1000baseT1/Full" },
+		{ 0, ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
+		  "1000baseKX/Full" },
+		{ 0, ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
+		  "2500baseX/Full" },
+		{ 0, ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+		  "10000baseT/Full" },
+		{ 0, ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
+		  "10000baseKX4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
+		  "10000baseKR/Full" },
+		{ 0, ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
+		  "10000baseR_FEC" },
+		{ 0, ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT,
+		  "20000baseMLD2/Full" },
+		{ 0, ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
+		  "20000baseKR2/Full" },
+		{ 0, ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
+		  "40000baseKR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
+		  "40000baseCR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
+		  "40000baseSR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
+		  "40000baseLR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT,
+		  "56000baseKR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT,
+		  "56000baseCR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT,
+		  "56000baseSR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT,
+		  "56000baseLR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
+		  "25000baseCR/Full" },
+		{ 0, ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
+		  "25000baseKR/Full" },
+		{ 0, ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
+		  "25000baseSR/Full" },
+		{ 0, ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
+		  "50000baseCR2/Full" },
+		{ 0, ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
+		  "50000baseKR2/Full" },
+		{ 0, ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
+		  "100000baseKR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
+		  "100000baseSR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
+		  "100000baseCR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
+		  "100000baseLR4_ER4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
+		  "50000baseSR2/Full" },
+		{ 0, ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
+		  "1000baseX/Full" },
+		{ 0, ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
+		  "10000baseCR/Full" },
+		{ 0, ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
+		  "10000baseSR/Full" },
+		{ 0, ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
+		  "10000baseLR/Full" },
+		{ 0, ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
+		  "10000baseLRM/Full" },
+		{ 0, ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
+		  "10000baseER/Full" },
+		{ 0, ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+		  "2500baseT/Full" },
+		{ 0, ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+		  "5000baseT/Full" },
+		{ 0, ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
+		  "50000baseKR/Full" },
+		{ 0, ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
+		  "50000baseSR/Full" },
+		{ 0, ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
+		  "50000baseCR/Full" },
+		{ 0, ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
+		  "50000baseLR_ER_FR/Full" },
+		{ 0, ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
+		  "50000baseDR/Full" },
+		{ 0, ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
+		  "100000baseKR2/Full" },
+		{ 0, ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
+		  "100000baseSR2/Full" },
+		{ 0, ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
+		  "100000baseCR2/Full" },
+		{ 0, ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
+		  "100000baseLR2_ER2_FR2/Full" },
+		{ 0, ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
+		  "100000baseDR2/Full" },
+		{ 0, ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
+		  "200000baseKR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
+		  "200000baseSR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
+		  "200000baseLR4_ER4_FR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT,
+		  "200000baseDR4/Full" },
+		{ 0, ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
+		  "200000baseCR4/Full" },
+	};
+	int indent;
+	int did1, new_line_pend, i;
+	int fecreported = 0;
+
+	/* Indent just like the separate functions used to */
+	indent = strlen(prefix) + 14;
+	if (indent < 24)
+		indent = 24;
+
+	fprintf(stdout, "	%s link modes:%*s", prefix,
+		indent - (int)strlen(prefix) - 12, "");
+	did1 = 0;
+	new_line_pend = 0;
+	for (i = 0; i < ARRAY_SIZE(mode_defs); i++) {
+		if (did1 && !mode_defs[i].same_line)
+			new_line_pend = 1;
+		if (ethtool_link_mode_test_bit(mode_defs[i].bit_index,
+					       mask)) {
+			if (new_line_pend) {
+				fprintf(stdout, "\n");
+				fprintf(stdout, "	%*s", indent, "");
+				new_line_pend = 0;
+			}
+			did1++;
+			fprintf(stdout, "%s ", mode_defs[i].name);
+		}
+	}
+	if (did1 == 0)
+		fprintf(stdout, "Not reported");
+	fprintf(stdout, "\n");
+
+	if (!link_mode_only) {
+		fprintf(stdout, "	%s pause frame use: ", prefix);
+		if (ethtool_link_mode_test_bit(
+			    ETHTOOL_LINK_MODE_Pause_BIT, mask)) {
+			fprintf(stdout, "Symmetric");
+			if (ethtool_link_mode_test_bit(
+				    ETHTOOL_LINK_MODE_Asym_Pause_BIT, mask))
+				fprintf(stdout, " Receive-only");
+			fprintf(stdout, "\n");
+		} else {
+			if (ethtool_link_mode_test_bit(
+				    ETHTOOL_LINK_MODE_Asym_Pause_BIT, mask))
+				fprintf(stdout, "Transmit-only\n");
+			else
+				fprintf(stdout, "No\n");
+		}
+
+		fprintf(stdout, "	%s auto-negotiation: ", an_prefix);
+		if (ethtool_link_mode_test_bit(
+			    ETHTOOL_LINK_MODE_Autoneg_BIT, mask))
+			fprintf(stdout, "Yes\n");
+		else
+			fprintf(stdout, "No\n");
+
+		fprintf(stdout, "	%s FEC modes:", prefix);
+		if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT,
+					       mask)) {
+			fprintf(stdout, " None");
+			fecreported = 1;
+		}
+		if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_BASER_BIT,
+					       mask)) {
+			fprintf(stdout, " BaseR");
+			fecreported = 1;
+		}
+		if (ethtool_link_mode_test_bit(ETHTOOL_LINK_MODE_FEC_RS_BIT,
+					       mask)) {
+			fprintf(stdout, " RS");
+			fecreported = 1;
+		}
+		if (!fecreported)
+			fprintf(stdout, " Not reported");
+		fprintf(stdout, "\n");
+	}
+}
+
+static int
+dump_link_usettings(const struct ethtool_link_usettings *link_usettings)
+{
+	dump_supported(link_usettings);
+	dump_link_caps("Advertised", "Advertised",
+		       link_usettings->link_modes.advertising, 0);
+	if (!ethtool_link_mode_is_empty(
+		    link_usettings->link_modes.lp_advertising))
+		dump_link_caps("Link partner advertised",
+			       "Link partner advertised",
+			       link_usettings->link_modes.lp_advertising, 0);
+
+	fprintf(stdout, "	Speed: ");
+	if (link_usettings->base.speed == 0
+	    || link_usettings->base.speed == (u16)(-1)
+	    || link_usettings->base.speed == (u32)(-1))
+		fprintf(stdout, "Unknown!\n");
+	else
+		fprintf(stdout, "%uMb/s\n", link_usettings->base.speed);
+
+	fprintf(stdout, "	Duplex: ");
+	switch (link_usettings->base.duplex) {
+	case DUPLEX_HALF:
+		fprintf(stdout, "Half\n");
+		break;
+	case DUPLEX_FULL:
+		fprintf(stdout, "Full\n");
+		break;
+	default:
+		fprintf(stdout, "Unknown! (%i)\n", link_usettings->base.duplex);
+		break;
+	};
+
+	fprintf(stdout, "	Port: ");
+	switch (link_usettings->base.port) {
+	case PORT_TP:
+		fprintf(stdout, "Twisted Pair\n");
+		break;
+	case PORT_AUI:
+		fprintf(stdout, "AUI\n");
+		break;
+	case PORT_BNC:
+		fprintf(stdout, "BNC\n");
+		break;
+	case PORT_MII:
+		fprintf(stdout, "MII\n");
+		break;
+	case PORT_FIBRE:
+		fprintf(stdout, "FIBRE\n");
+		break;
+	case PORT_DA:
+		fprintf(stdout, "Direct Attach Copper\n");
+		break;
+	case PORT_NONE:
+		fprintf(stdout, "None\n");
+		break;
+	case PORT_OTHER:
+		fprintf(stdout, "Other\n");
+		break;
+	default:
+		fprintf(stdout, "Unknown! (%i)\n", link_usettings->base.port);
+		break;
+	};
+
+	fprintf(stdout, "	PHYAD: %d\n", link_usettings->base.phy_address);
+	fprintf(stdout, "	Transceiver: ");
+	switch (link_usettings->deprecated.transceiver) {
+	case XCVR_INTERNAL:
+		fprintf(stdout, "internal\n");
+		break;
+	case XCVR_EXTERNAL:
+		fprintf(stdout, "external\n");
+		break;
+	default:
+		fprintf(stdout, "Unknown!\n");
+		break;
+	};
+
+	fprintf(stdout, "	Auto-negotiation: %s\n",
+		(link_usettings->base.autoneg == AUTONEG_DISABLE) ?
+		"off" : "on");
+
+	if (link_usettings->base.port == PORT_TP) {
+		fprintf(stdout, "	MDI-X: ");
+		if (link_usettings->base.eth_tp_mdix_ctrl == ETH_TP_MDI) {
+			fprintf(stdout, "off (forced)\n");
+		} else if (link_usettings->base.eth_tp_mdix_ctrl
+			   == ETH_TP_MDI_X) {
+			fprintf(stdout, "on (forced)\n");
+		} else {
+			switch (link_usettings->base.eth_tp_mdix) {
+			case ETH_TP_MDI:
+				fprintf(stdout, "off");
+				break;
+			case ETH_TP_MDI_X:
+				fprintf(stdout, "on");
+				break;
+			default:
+				fprintf(stdout, "Unknown");
+				break;
+			}
+			if (link_usettings->base.eth_tp_mdix_ctrl
+			    == ETH_TP_MDI_AUTO)
+				fprintf(stdout, " (auto)");
+			fprintf(stdout, "\n");
+		}
+	}
+
+	return 0;
+}
+
+static int dump_drvinfo(struct ethtool_drvinfo *info)
+{
+	fprintf(stdout,
+		"driver: %.*s\n"
+		"version: %.*s\n"
+		"firmware-version: %.*s\n"
+		"expansion-rom-version: %.*s\n"
+		"bus-info: %.*s\n"
+		"supports-statistics: %s\n"
+		"supports-test: %s\n"
+		"supports-eeprom-access: %s\n"
+		"supports-register-dump: %s\n"
+		"supports-priv-flags: %s\n",
+		(int)sizeof(info->driver), info->driver,
+		(int)sizeof(info->version), info->version,
+		(int)sizeof(info->fw_version), info->fw_version,
+		(int)sizeof(info->erom_version), info->erom_version,
+		(int)sizeof(info->bus_info), info->bus_info,
+		info->n_stats ? "yes" : "no",
+		info->testinfo_len ? "yes" : "no",
+		info->eedump_len ? "yes" : "no",
+		info->regdump_len ? "yes" : "no",
+		info->n_priv_flags ? "yes" : "no");
+
+	return 0;
+}
+
+static int parse_wolopts(char *optstr, u32 *data)
+{
+	*data = 0;
+	while (*optstr) {
+		switch (*optstr) {
+		case 'p':
+			*data |= WAKE_PHY;
+			break;
+		case 'u':
+			*data |= WAKE_UCAST;
+			break;
+		case 'm':
+			*data |= WAKE_MCAST;
+			break;
+		case 'b':
+			*data |= WAKE_BCAST;
+			break;
+		case 'a':
+			*data |= WAKE_ARP;
+			break;
+		case 'g':
+			*data |= WAKE_MAGIC;
+			break;
+		case 's':
+			*data |= WAKE_MAGICSECURE;
+			break;
+		case 'f':
+			*data |= WAKE_FILTER;
+			break;
+		case 'd':
+			*data = 0;
+			break;
+		default:
+			return -1;
+		}
+		optstr++;
+	}
+	return 0;
+}
+
+static char *unparse_wolopts(int wolopts)
+{
+	static char buf[16];
+	char *p = buf;
+
+	memset(buf, 0, sizeof(buf));
+
+	if (wolopts) {
+		if (wolopts & WAKE_PHY)
+			*p++ = 'p';
+		if (wolopts & WAKE_UCAST)
+			*p++ = 'u';
+		if (wolopts & WAKE_MCAST)
+			*p++ = 'm';
+		if (wolopts & WAKE_BCAST)
+			*p++ = 'b';
+		if (wolopts & WAKE_ARP)
+			*p++ = 'a';
+		if (wolopts & WAKE_MAGIC)
+			*p++ = 'g';
+		if (wolopts & WAKE_MAGICSECURE)
+			*p++ = 's';
+		if (wolopts & WAKE_FILTER)
+			*p++ = 'f';
+	} else {
+		*p = 'd';
+	}
+
+	return buf;
+}
+
+static int dump_wol(struct ethtool_wolinfo *wol)
+{
+	fprintf(stdout, "	Supports Wake-on: %s\n",
+		unparse_wolopts(wol->supported));
+	fprintf(stdout, "	Wake-on: %s\n",
+		unparse_wolopts(wol->wolopts));
+	if (wol->supported & WAKE_MAGICSECURE) {
+		int i;
+		int delim = 0;
+
+		fprintf(stdout, "        SecureOn password: ");
+		for (i = 0; i < SOPASS_MAX; i++) {
+			fprintf(stdout, "%s%02x", delim?":":"", wol->sopass[i]);
+			delim = 1;
+		}
+		fprintf(stdout, "\n");
+	}
+
+	return 0;
+}
+
+static int parse_rxfhashopts(char *optstr, u32 *data)
+{
+	*data = 0;
+	while (*optstr) {
+		switch (*optstr) {
+		case 'm':
+			*data |= RXH_L2DA;
+			break;
+		case 'v':
+			*data |= RXH_VLAN;
+			break;
+		case 't':
+			*data |= RXH_L3_PROTO;
+			break;
+		case 's':
+			*data |= RXH_IP_SRC;
+			break;
+		case 'd':
+			*data |= RXH_IP_DST;
+			break;
+		case 'f':
+			*data |= RXH_L4_B_0_1;
+			break;
+		case 'n':
+			*data |= RXH_L4_B_2_3;
+			break;
+		case 'r':
+			*data |= RXH_DISCARD;
+			break;
+		default:
+			return -1;
+		}
+		optstr++;
+	}
+	return 0;
+}
+
+static char *unparse_rxfhashopts(u64 opts)
+{
+	static char buf[300];
+
+	memset(buf, 0, sizeof(buf));
+
+	if (opts) {
+		if (opts & RXH_L2DA)
+			strcat(buf, "L2DA\n");
+		if (opts & RXH_VLAN)
+			strcat(buf, "VLAN tag\n");
+		if (opts & RXH_L3_PROTO)
+			strcat(buf, "L3 proto\n");
+		if (opts & RXH_IP_SRC)
+			strcat(buf, "IP SA\n");
+		if (opts & RXH_IP_DST)
+			strcat(buf, "IP DA\n");
+		if (opts & RXH_L4_B_0_1)
+			strcat(buf, "L4 bytes 0 & 1 [TCP/UDP src port]\n");
+		if (opts & RXH_L4_B_2_3)
+			strcat(buf, "L4 bytes 2 & 3 [TCP/UDP dst port]\n");
+	} else {
+		sprintf(buf, "None");
+	}
+
+	return buf;
+}
+
+static int convert_string_to_hashkey(char *rss_hkey, u32 key_size,
+				     const char *rss_hkey_string)
+{
+	u32 i = 0;
+	int hex_byte, len;
+
+	do {
+		if (i > (key_size - 1)) {
+			fprintf(stderr,
+				"Key is too long for device (%u > %u)\n",
+				i + 1, key_size);
+			goto err;
+		}
+
+		if (sscanf(rss_hkey_string, "%2x%n", &hex_byte, &len) < 1 ||
+		    len != 2) {
+			fprintf(stderr, "Invalid RSS hash key format\n");
+			goto err;
+		}
+
+		rss_hkey[i++] = hex_byte;
+		rss_hkey_string += 2;
+
+		if (*rss_hkey_string == ':') {
+			rss_hkey_string++;
+		} else if (*rss_hkey_string != '\0') {
+			fprintf(stderr, "Invalid RSS hash key format\n");
+			goto err;
+		}
+
+	} while (*rss_hkey_string);
+
+	if (i != key_size) {
+		fprintf(stderr, "Key is too short for device (%u < %u)\n",
+			i, key_size);
+		goto err;
+	}
+
+	return 0;
+err:
+	return 2;
+}
+
+static int parse_hkey(char **rss_hkey, u32 key_size,
+		      const char *rss_hkey_string)
+{
+	if (!key_size) {
+		fprintf(stderr,
+			"Cannot set RX flow hash configuration:\n"
+			" Hash key setting not supported\n");
+		return 1;
+	}
+
+	*rss_hkey = malloc(key_size);
+	if (!(*rss_hkey)) {
+		perror("Cannot allocate memory for RSS hash key");
+		return 1;
+	}
+
+	if (convert_string_to_hashkey(*rss_hkey, key_size,
+				      rss_hkey_string)) {
+		free(*rss_hkey);
+		*rss_hkey = NULL;
+		return 2;
+	}
+	return 0;
+}
+
+static const struct {
+	const char *name;
+	int (*func)(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+} driver_list[] = {
+#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
+	{ "8139cp", realtek_dump_regs },
+	{ "8139too", realtek_dump_regs },
+	{ "r8169", realtek_dump_regs },
+	{ "de2104x", de2104x_dump_regs },
+	{ "e1000", e1000_dump_regs },
+	{ "e1000e", e1000_dump_regs },
+	{ "igb", igb_dump_regs },
+	{ "ixgb", ixgb_dump_regs },
+	{ "ixgbe", ixgbe_dump_regs },
+	{ "ixgbevf", ixgbevf_dump_regs },
+	{ "natsemi", natsemi_dump_regs },
+	{ "e100", e100_dump_regs },
+	{ "amd8111e", amd8111e_dump_regs },
+	{ "pcnet32", pcnet32_dump_regs },
+	{ "fec_8xx", fec_8xx_dump_regs },
+	{ "ibm_emac", ibm_emac_dump_regs },
+	{ "tg3", tg3_dump_regs },
+	{ "skge", skge_dump_regs },
+	{ "sky2", sky2_dump_regs },
+	{ "vioc", vioc_dump_regs },
+	{ "smsc911x", smsc911x_dump_regs },
+	{ "at76c50x-usb", at76c50x_usb_dump_regs },
+	{ "sfc", sfc_dump_regs },
+	{ "st_mac100", st_mac100_dump_regs },
+	{ "st_gmac", st_gmac_dump_regs },
+	{ "et131x", et131x_dump_regs },
+	{ "altera_tse", altera_tse_dump_regs },
+	{ "vmxnet3", vmxnet3_dump_regs },
+	{ "fjes", fjes_dump_regs },
+	{ "lan78xx", lan78xx_dump_regs },
+	{ "dsa", dsa_dump_regs },
+	{ "fec", fec_dump_regs },
+#endif
+};
+
+void dump_hex(FILE *file, const u8 *data, int len, int offset)
+{
+	int i;
+
+	fprintf(file, "Offset\t\tValues\n");
+	fprintf(file, "------\t\t------");
+	for (i = 0; i < len; i++) {
+		if (i % 16 == 0)
+			fprintf(file, "\n0x%04x:\t\t", i + offset);
+		fprintf(file, "%02x ", data[i]);
+	}
+	fprintf(file, "\n");
+}
+
+static int dump_regs(int gregs_dump_raw, int gregs_dump_hex,
+		     struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+	int i;
+
+	if (gregs_dump_raw) {
+		fwrite(regs->data, regs->len, 1, stdout);
+		goto nested;
+	}
+
+	if (!gregs_dump_hex)
+		for (i = 0; i < ARRAY_SIZE(driver_list); i++)
+			if (!strncmp(driver_list[i].name, info->driver,
+				     ETHTOOL_BUSINFO_LEN)) {
+				if (driver_list[i].func(info, regs) == 0)
+					goto nested;
+				/* This version (or some other
+				 * variation in the dump format) is
+				 * not handled; fall back to hex
+				 */
+				break;
+			}
+
+	dump_hex(stdout, regs->data, regs->len, 0);
+
+nested:
+	/* Recurse dump if some drvinfo and regs structures are nested */
+	if (info->regdump_len > regs->len + sizeof(*info) + sizeof(*regs)) {
+		info = (struct ethtool_drvinfo *)(&regs->data[0] + regs->len);
+		regs = (struct ethtool_regs *)(&regs->data[0] + regs->len + sizeof(*info));
+
+		return dump_regs(gregs_dump_raw, gregs_dump_hex, info, regs);
+	}
+
+	return 0;
+}
+
+static int dump_eeprom(int geeprom_dump_raw,
+		       struct ethtool_drvinfo *info maybe_unused,
+		       struct ethtool_eeprom *ee)
+{
+	if (geeprom_dump_raw) {
+		fwrite(ee->data, 1, ee->len, stdout);
+		return 0;
+	}
+#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
+	if (!strncmp("natsemi", info->driver, ETHTOOL_BUSINFO_LEN)) {
+		return natsemi_dump_eeprom(info, ee);
+	} else if (!strncmp("tg3", info->driver, ETHTOOL_BUSINFO_LEN)) {
+		return tg3_dump_eeprom(info, ee);
+	}
+#endif
+	dump_hex(stdout, ee->data, ee->len, ee->offset);
+
+	return 0;
+}
+
+static int dump_test(struct ethtool_test *test,
+		     struct ethtool_gstrings *strings)
+{
+	int i, rc;
+
+	rc = test->flags & ETH_TEST_FL_FAILED;
+	fprintf(stdout, "The test result is %s\n", rc ? "FAIL" : "PASS");
+
+	if (test->flags & ETH_TEST_FL_EXTERNAL_LB)
+		fprintf(stdout, "External loopback test was %sexecuted\n",
+			(test->flags & ETH_TEST_FL_EXTERNAL_LB_DONE) ?
+			"" : "not ");
+
+	if (strings->len)
+		fprintf(stdout, "The test extra info:\n");
+
+	for (i = 0; i < strings->len; i++) {
+		fprintf(stdout, "%s\t %d\n",
+			(char *)(strings->data + i * ETH_GSTRING_LEN),
+			(u32) test->data[i]);
+	}
+
+	fprintf(stdout, "\n");
+	return rc;
+}
+
+static int dump_pause(const struct ethtool_pauseparam *epause,
+		      u32 advertising, u32 lp_advertising)
+{
+	fprintf(stdout,
+		"Autonegotiate:	%s\n"
+		"RX:		%s\n"
+		"TX:		%s\n",
+		epause->autoneg ? "on" : "off",
+		epause->rx_pause ? "on" : "off",
+		epause->tx_pause ? "on" : "off");
+
+	if (lp_advertising) {
+		int an_rx = 0, an_tx = 0;
+
+		/* Work out negotiated pause frame usage per
+		 * IEEE 802.3-2005 table 28B-3.
+		 */
+		if (advertising & lp_advertising & ADVERTISED_Pause) {
+			an_tx = 1;
+			an_rx = 1;
+		} else if (advertising & lp_advertising &
+			   ADVERTISED_Asym_Pause) {
+			if (advertising & ADVERTISED_Pause)
+				an_rx = 1;
+			else if (lp_advertising & ADVERTISED_Pause)
+				an_tx = 1;
+		}
+
+		fprintf(stdout,
+			"RX negotiated:	%s\n"
+			"TX negotiated:	%s\n",
+			an_rx ? "on" : "off",
+			an_tx ? "on" : "off");
+	}
+
+	fprintf(stdout, "\n");
+	return 0;
+}
+
+static int dump_ring(const struct ethtool_ringparam *ering)
+{
+	fprintf(stdout,
+		"Pre-set maximums:\n"
+		"RX:		%u\n"
+		"RX Mini:	%u\n"
+		"RX Jumbo:	%u\n"
+		"TX:		%u\n",
+		ering->rx_max_pending,
+		ering->rx_mini_max_pending,
+		ering->rx_jumbo_max_pending,
+		ering->tx_max_pending);
+
+	fprintf(stdout,
+		"Current hardware settings:\n"
+		"RX:		%u\n"
+		"RX Mini:	%u\n"
+		"RX Jumbo:	%u\n"
+		"TX:		%u\n",
+		ering->rx_pending,
+		ering->rx_mini_pending,
+		ering->rx_jumbo_pending,
+		ering->tx_pending);
+
+	fprintf(stdout, "\n");
+	return 0;
+}
+
+static int dump_channels(const struct ethtool_channels *echannels)
+{
+	fprintf(stdout,
+		"Pre-set maximums:\n"
+		"RX:		%u\n"
+		"TX:		%u\n"
+		"Other:		%u\n"
+		"Combined:	%u\n",
+		echannels->max_rx, echannels->max_tx,
+		echannels->max_other,
+		echannels->max_combined);
+
+	fprintf(stdout,
+		"Current hardware settings:\n"
+		"RX:		%u\n"
+		"TX:		%u\n"
+		"Other:		%u\n"
+		"Combined:	%u\n",
+		echannels->rx_count, echannels->tx_count,
+		echannels->other_count,
+		echannels->combined_count);
+
+	fprintf(stdout, "\n");
+	return 0;
+}
+
+static int dump_coalesce(const struct ethtool_coalesce *ecoal)
+{
+	fprintf(stdout, "Adaptive RX: %s  TX: %s\n",
+		ecoal->use_adaptive_rx_coalesce ? "on" : "off",
+		ecoal->use_adaptive_tx_coalesce ? "on" : "off");
+
+	fprintf(stdout,
+		"stats-block-usecs: %u\n"
+		"sample-interval: %u\n"
+		"pkt-rate-low: %u\n"
+		"pkt-rate-high: %u\n"
+		"\n"
+		"rx-usecs: %u\n"
+		"rx-frames: %u\n"
+		"rx-usecs-irq: %u\n"
+		"rx-frames-irq: %u\n"
+		"\n"
+		"tx-usecs: %u\n"
+		"tx-frames: %u\n"
+		"tx-usecs-irq: %u\n"
+		"tx-frames-irq: %u\n"
+		"\n"
+		"rx-usecs-low: %u\n"
+		"rx-frames-low: %u\n"
+		"tx-usecs-low: %u\n"
+		"tx-frames-low: %u\n"
+		"\n"
+		"rx-usecs-high: %u\n"
+		"rx-frames-high: %u\n"
+		"tx-usecs-high: %u\n"
+		"tx-frames-high: %u\n"
+		"\n",
+		ecoal->stats_block_coalesce_usecs,
+		ecoal->rate_sample_interval,
+		ecoal->pkt_rate_low,
+		ecoal->pkt_rate_high,
+
+		ecoal->rx_coalesce_usecs,
+		ecoal->rx_max_coalesced_frames,
+		ecoal->rx_coalesce_usecs_irq,
+		ecoal->rx_max_coalesced_frames_irq,
+
+		ecoal->tx_coalesce_usecs,
+		ecoal->tx_max_coalesced_frames,
+		ecoal->tx_coalesce_usecs_irq,
+		ecoal->tx_max_coalesced_frames_irq,
+
+		ecoal->rx_coalesce_usecs_low,
+		ecoal->rx_max_coalesced_frames_low,
+		ecoal->tx_coalesce_usecs_low,
+		ecoal->tx_max_coalesced_frames_low,
+
+		ecoal->rx_coalesce_usecs_high,
+		ecoal->rx_max_coalesced_frames_high,
+		ecoal->tx_coalesce_usecs_high,
+		ecoal->tx_max_coalesced_frames_high);
+
+	return 0;
+}
+
+void dump_per_queue_coalesce(struct ethtool_per_queue_op *per_queue_opt,
+			     __u32 *queue_mask, int n_queues)
+{
+	struct ethtool_coalesce *ecoal;
+	int i, idx = 0;
+
+	ecoal = (struct ethtool_coalesce *)(per_queue_opt + 1);
+	for (i = 0; i < __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32); i++) {
+		int queue = i * 32;
+		__u32 mask = queue_mask[i];
+
+		while (mask > 0) {
+			if (mask & 0x1) {
+				fprintf(stdout, "Queue: %d\n", queue);
+				dump_coalesce(ecoal + idx);
+				idx++;
+			}
+			mask = mask >> 1;
+			queue++;
+		}
+		if (idx == n_queues)
+			break;
+	}
+}
+
+struct feature_state {
+	u32 off_flags;
+	struct ethtool_gfeatures features;
+};
+
+static void dump_one_feature(const char *indent, const char *name,
+			     const struct feature_state *state,
+			     const struct feature_state *ref_state,
+			     u32 index)
+{
+	if (ref_state &&
+	    !(FEATURE_BIT_IS_SET(state->features.features, index, active) ^
+	      FEATURE_BIT_IS_SET(ref_state->features.features, index, active)))
+		return;
+
+	printf("%s%s: %s%s\n",
+	       indent, name,
+	       FEATURE_BIT_IS_SET(state->features.features, index, active) ?
+	       "on" : "off",
+	       (!FEATURE_BIT_IS_SET(state->features.features, index, available)
+		|| FEATURE_BIT_IS_SET(state->features.features, index,
+				      never_changed))
+	       ? " [fixed]"
+	       : (FEATURE_BIT_IS_SET(state->features.features, index, requested)
+		  ^ FEATURE_BIT_IS_SET(state->features.features, index, active))
+	       ? (FEATURE_BIT_IS_SET(state->features.features, index, requested)
+		  ? " [requested on]" : " [requested off]")
+	       : "");
+}
+
+static int linux_version_code(void)
+{
+	struct utsname utsname;
+	unsigned version, patchlevel, sublevel = 0;
+
+	if (uname(&utsname))
+		return -1;
+	if (sscanf(utsname.release, "%u.%u.%u", &version, &patchlevel, &sublevel) < 2)
+		return -1;
+	return KERNEL_VERSION(version, patchlevel, sublevel);
+}
+
+static void dump_features(const struct feature_defs *defs,
+			  const struct feature_state *state,
+			  const struct feature_state *ref_state)
+{
+	int kernel_ver = linux_version_code();
+	u32 value;
+	int indent;
+	int i, j;
+
+	for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+		/* Don't show features whose state is unknown on this
+		 * kernel version
+		 */
+		if (defs->off_flag_matched[i] == 0 &&
+		    ((off_flag_def[i].get_cmd == 0 &&
+		      kernel_ver < off_flag_def[i].min_kernel_ver) ||
+		     (off_flag_def[i].get_cmd == ETHTOOL_GUFO &&
+		      kernel_ver >= KERNEL_VERSION(4, 14, 0))))
+			continue;
+
+		value = off_flag_def[i].value;
+
+		/* If this offload flag matches exactly one generic
+		 * feature then it's redundant to show the flag and
+		 * feature states separately.  Otherwise, show the
+		 * flag state first.
+		 */
+		if (defs->off_flag_matched[i] != 1 &&
+		    (!ref_state ||
+		     (state->off_flags ^ ref_state->off_flags) & value)) {
+			printf("%s: %s\n",
+			       off_flag_def[i].long_name,
+			       (state->off_flags & value) ? "on" : "off");
+			indent = 1;
+		} else {
+			indent = 0;
+		}
+
+		/* Show matching features */
+		for (j = 0; j < defs->n_features; j++) {
+			if (defs->def[j].off_flag_index != i)
+				continue;
+			if (defs->off_flag_matched[i] != 1)
+				/* Show all matching feature states */
+				dump_one_feature(indent ? "\t" : "",
+						 defs->def[j].name,
+						 state, ref_state, j);
+			else
+				/* Show full state with the old flag name */
+				dump_one_feature("", off_flag_def[i].long_name,
+						 state, ref_state, j);
+		}
+	}
+
+	/* Show all unmatched features that have non-null names */
+	for (j = 0; j < defs->n_features; j++)
+		if (defs->def[j].off_flag_index < 0 && defs->def[j].name[0])
+			dump_one_feature("", defs->def[j].name,
+					 state, ref_state, j);
+}
+
+static int dump_rxfhash(int fhash, u64 val)
+{
+	switch (fhash & ~FLOW_RSS) {
+	case TCP_V4_FLOW:
+		fprintf(stdout, "TCP over IPV4 flows");
+		break;
+	case UDP_V4_FLOW:
+		fprintf(stdout, "UDP over IPV4 flows");
+		break;
+	case SCTP_V4_FLOW:
+		fprintf(stdout, "SCTP over IPV4 flows");
+		break;
+	case AH_ESP_V4_FLOW:
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+		fprintf(stdout, "IPSEC AH/ESP over IPV4 flows");
+		break;
+	case TCP_V6_FLOW:
+		fprintf(stdout, "TCP over IPV6 flows");
+		break;
+	case UDP_V6_FLOW:
+		fprintf(stdout, "UDP over IPV6 flows");
+		break;
+	case SCTP_V6_FLOW:
+		fprintf(stdout, "SCTP over IPV6 flows");
+		break;
+	case AH_ESP_V6_FLOW:
+	case AH_V6_FLOW:
+	case ESP_V6_FLOW:
+		fprintf(stdout, "IPSEC AH/ESP over IPV6 flows");
+		break;
+	default:
+		break;
+	}
+
+	if (val & RXH_DISCARD) {
+		fprintf(stdout, " - All matching flows discarded on RX\n");
+		return 0;
+	}
+	fprintf(stdout, " use these fields for computing Hash flow key:\n");
+
+	fprintf(stdout, "%s\n", unparse_rxfhashopts(val));
+
+	return 0;
+}
+
+static void dump_eeecmd(struct ethtool_eee *ep)
+{
+	ETHTOOL_DECLARE_LINK_MODE_MASK(link_mode);
+
+	fprintf(stdout, "	EEE status: ");
+	if (!ep->supported) {
+		fprintf(stdout, "not supported\n");
+		return;
+	} else if (!ep->eee_enabled) {
+		fprintf(stdout, "disabled\n");
+	} else {
+		fprintf(stdout, "enabled - ");
+		if (ep->eee_active)
+			fprintf(stdout, "active\n");
+		else
+			fprintf(stdout, "inactive\n");
+	}
+
+	fprintf(stdout, "	Tx LPI:");
+	if (ep->tx_lpi_enabled)
+		fprintf(stdout, " %d (us)\n", ep->tx_lpi_timer);
+	else
+		fprintf(stdout, " disabled\n");
+
+	ethtool_link_mode_zero(link_mode);
+
+	link_mode[0] = ep->supported;
+	dump_link_caps("Supported EEE", "", link_mode, 1);
+
+	link_mode[0] = ep->advertised;
+	dump_link_caps("Advertised EEE", "", link_mode, 1);
+
+	link_mode[0] = ep->lp_advertised;
+	dump_link_caps("Link partner advertised EEE", "", link_mode, 1);
+}
+
+static void dump_fec(u32 fec)
+{
+	if (fec & ETHTOOL_FEC_NONE)
+		fprintf(stdout, " None");
+	if (fec & ETHTOOL_FEC_AUTO)
+		fprintf(stdout, " Auto");
+	if (fec & ETHTOOL_FEC_OFF)
+		fprintf(stdout, " Off");
+	if (fec & ETHTOOL_FEC_BASER)
+		fprintf(stdout, " BaseR");
+	if (fec & ETHTOOL_FEC_RS)
+		fprintf(stdout, " RS");
+}
+
+#define N_SOTS 7
+
+static char *so_timestamping_labels[N_SOTS] = {
+	"hardware-transmit     (SOF_TIMESTAMPING_TX_HARDWARE)",
+	"software-transmit     (SOF_TIMESTAMPING_TX_SOFTWARE)",
+	"hardware-receive      (SOF_TIMESTAMPING_RX_HARDWARE)",
+	"software-receive      (SOF_TIMESTAMPING_RX_SOFTWARE)",
+	"software-system-clock (SOF_TIMESTAMPING_SOFTWARE)",
+	"hardware-legacy-clock (SOF_TIMESTAMPING_SYS_HARDWARE)",
+	"hardware-raw-clock    (SOF_TIMESTAMPING_RAW_HARDWARE)",
+};
+
+#define N_TX_TYPES (HWTSTAMP_TX_ONESTEP_SYNC + 1)
+
+static char *tx_type_labels[N_TX_TYPES] = {
+	"off                   (HWTSTAMP_TX_OFF)",
+	"on                    (HWTSTAMP_TX_ON)",
+	"one-step-sync         (HWTSTAMP_TX_ONESTEP_SYNC)",
+};
+
+#define N_RX_FILTERS (HWTSTAMP_FILTER_NTP_ALL + 1)
+
+static char *rx_filter_labels[N_RX_FILTERS] = {
+	"none                  (HWTSTAMP_FILTER_NONE)",
+	"all                   (HWTSTAMP_FILTER_ALL)",
+	"some                  (HWTSTAMP_FILTER_SOME)",
+	"ptpv1-l4-event        (HWTSTAMP_FILTER_PTP_V1_L4_EVENT)",
+	"ptpv1-l4-sync         (HWTSTAMP_FILTER_PTP_V1_L4_SYNC)",
+	"ptpv1-l4-delay-req    (HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ)",
+	"ptpv2-l4-event        (HWTSTAMP_FILTER_PTP_V2_L4_EVENT)",
+	"ptpv2-l4-sync         (HWTSTAMP_FILTER_PTP_V2_L4_SYNC)",
+	"ptpv2-l4-delay-req    (HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ)",
+	"ptpv2-l2-event        (HWTSTAMP_FILTER_PTP_V2_L2_EVENT)",
+	"ptpv2-l2-sync         (HWTSTAMP_FILTER_PTP_V2_L2_SYNC)",
+	"ptpv2-l2-delay-req    (HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ)",
+	"ptpv2-event           (HWTSTAMP_FILTER_PTP_V2_EVENT)",
+	"ptpv2-sync            (HWTSTAMP_FILTER_PTP_V2_SYNC)",
+	"ptpv2-delay-req       (HWTSTAMP_FILTER_PTP_V2_DELAY_REQ)",
+	"ntp-all               (HWTSTAMP_FILTER_NTP_ALL)",
+};
+
+static int dump_tsinfo(const struct ethtool_ts_info *info)
+{
+	int i;
+
+	fprintf(stdout, "Capabilities:\n");
+
+	for (i = 0; i < N_SOTS; i++) {
+		if (info->so_timestamping & (1 << i))
+			fprintf(stdout, "\t%s\n", so_timestamping_labels[i]);
+	}
+
+	fprintf(stdout, "PTP Hardware Clock: ");
+
+	if (info->phc_index < 0)
+		fprintf(stdout, "none\n");
+	else
+		fprintf(stdout, "%d\n", info->phc_index);
+
+	fprintf(stdout, "Hardware Transmit Timestamp Modes:");
+
+	if (!info->tx_types)
+		fprintf(stdout, " none\n");
+	else
+		fprintf(stdout, "\n");
+
+	for (i = 0; i < N_TX_TYPES; i++) {
+		if (info->tx_types & (1 << i))
+			fprintf(stdout,	"\t%s\n", tx_type_labels[i]);
+	}
+
+	fprintf(stdout, "Hardware Receive Filter Modes:");
+
+	if (!info->rx_filters)
+		fprintf(stdout, " none\n");
+	else
+		fprintf(stdout, "\n");
+
+	for (i = 0; i < N_RX_FILTERS; i++) {
+		if (info->rx_filters & (1 << i))
+			fprintf(stdout, "\t%s\n", rx_filter_labels[i]);
+	}
+
+	return 0;
+}
+
+static struct ethtool_gstrings *
+get_stringset(struct cmd_context *ctx, enum ethtool_stringset set_id,
+	      ptrdiff_t drvinfo_offset, int null_terminate)
+{
+	struct {
+		struct ethtool_sset_info hdr;
+		u32 buf[1];
+	} sset_info;
+	struct ethtool_drvinfo drvinfo;
+	u32 len, i;
+	struct ethtool_gstrings *strings;
+
+	sset_info.hdr.cmd = ETHTOOL_GSSET_INFO;
+	sset_info.hdr.reserved = 0;
+	sset_info.hdr.sset_mask = 1ULL << set_id;
+	if (send_ioctl(ctx, &sset_info) == 0) {
+		len = sset_info.hdr.sset_mask ? sset_info.hdr.data[0] : 0;
+	} else if (errno == EOPNOTSUPP && drvinfo_offset != 0) {
+		/* Fallback for old kernel versions */
+		drvinfo.cmd = ETHTOOL_GDRVINFO;
+		if (send_ioctl(ctx, &drvinfo))
+			return NULL;
+		len = *(u32 *)((char *)&drvinfo + drvinfo_offset);
+	} else {
+		return NULL;
+	}
+
+	strings = calloc(1, sizeof(*strings) + len * ETH_GSTRING_LEN);
+	if (!strings)
+		return NULL;
+
+	strings->cmd = ETHTOOL_GSTRINGS;
+	strings->string_set = set_id;
+	strings->len = len;
+	if (len != 0 && send_ioctl(ctx, strings)) {
+		free(strings);
+		return NULL;
+	}
+
+	if (null_terminate)
+		for (i = 0; i < len; i++)
+			strings->data[(i + 1) * ETH_GSTRING_LEN - 1] = 0;
+
+	return strings;
+}
+
+static struct feature_defs *get_feature_defs(struct cmd_context *ctx)
+{
+	struct ethtool_gstrings *names;
+	struct feature_defs *defs;
+	u32 n_features;
+	int i, j;
+
+	names = get_stringset(ctx, ETH_SS_FEATURES, 0, 1);
+	if (names) {
+		n_features = names->len;
+	} else if (errno == EOPNOTSUPP || errno == EINVAL) {
+		/* Kernel doesn't support named features; not an error */
+		n_features = 0;
+	} else if (errno == EPERM) {
+		/* Kernel bug: ETHTOOL_GSSET_INFO was privileged.
+		 * Work around it. */
+		n_features = 0;
+	} else {
+		return NULL;
+	}
+
+	defs = malloc(sizeof(*defs) + sizeof(defs->def[0]) * n_features);
+	if (!defs) {
+		free(names);
+		return NULL;
+	}
+
+	defs->n_features = n_features;
+	memset(defs->off_flag_matched, 0, sizeof(defs->off_flag_matched));
+
+	/* Copy out feature names and find those associated with legacy flags */
+	for (i = 0; i < defs->n_features; i++) {
+		memcpy(defs->def[i].name, names->data + i * ETH_GSTRING_LEN,
+		       ETH_GSTRING_LEN);
+		defs->def[i].off_flag_index = -1;
+
+		for (j = 0;
+		     j < ARRAY_SIZE(off_flag_def) &&
+			     defs->def[i].off_flag_index < 0;
+		     j++) {
+			const char *pattern =
+				off_flag_def[j].kernel_name;
+			const char *name = defs->def[i].name;
+			for (;;) {
+				if (*pattern == '*') {
+					/* There is only one wildcard; so
+					 * switch to a suffix comparison */
+					size_t pattern_len =
+						strlen(pattern + 1);
+					size_t name_len = strlen(name);
+					if (name_len < pattern_len)
+						break; /* name is too short */
+					name += name_len - pattern_len;
+					++pattern;
+				} else if (*pattern != *name) {
+					break; /* mismatch */
+				} else if (*pattern == 0) {
+					defs->def[i].off_flag_index = j;
+					defs->off_flag_matched[j]++;
+					break;
+				} else {
+					++name;
+					++pattern;
+				}
+			}
+		}
+	}
+
+	free(names);
+	return defs;
+}
+
+static int do_gdrv(struct cmd_context *ctx)
+{
+	int err;
+	struct ethtool_drvinfo drvinfo;
+
+	if (ctx->argc != 0)
+		exit_bad_args();
+
+	drvinfo.cmd = ETHTOOL_GDRVINFO;
+	err = send_ioctl(ctx, &drvinfo);
+	if (err < 0) {
+		perror("Cannot get driver information");
+		return 71;
+	}
+	return dump_drvinfo(&drvinfo);
+}
+
+static int do_gpause(struct cmd_context *ctx)
+{
+	struct ethtool_pauseparam epause;
+	struct ethtool_cmd ecmd;
+	int err;
+
+	if (ctx->argc != 0)
+		exit_bad_args();
+
+	fprintf(stdout, "Pause parameters for %s:\n", ctx->devname);
+
+	epause.cmd = ETHTOOL_GPAUSEPARAM;
+	err = send_ioctl(ctx, &epause);
+	if (err) {
+		perror("Cannot get device pause settings");
+		return 76;
+	}
+
+	if (epause.autoneg) {
+		ecmd.cmd = ETHTOOL_GSET;
+		err = send_ioctl(ctx, &ecmd);
+		if (err) {
+			perror("Cannot get device settings");
+			return 1;
+		}
+		dump_pause(&epause, ecmd.advertising, ecmd.lp_advertising);
+	} else {
+		dump_pause(&epause, 0, 0);
+	}
+
+	return 0;
+}
+
+static void do_generic_set1(struct cmdline_info *info, int *changed_out)
+{
+	int wanted, *v1, *v2;
+
+	v1 = info->wanted_val;
+	wanted = *v1;
+
+	if (wanted < 0)
+		return;
+
+	v2 = info->ioctl_val;
+	if (wanted == *v2) {
+		fprintf(stderr, "%s unmodified, ignoring\n", info->name);
+	} else {
+		*v2 = wanted;
+		*changed_out = 1;
+	}
+}
+
+static void do_generic_set(struct cmdline_info *info,
+			   unsigned int n_info,
+			   int *changed_out)
+{
+	unsigned int i;
+
+	for (i = 0; i < n_info; i++)
+		do_generic_set1(&info[i], changed_out);
+}
+
+static int do_spause(struct cmd_context *ctx)
+{
+	struct ethtool_pauseparam epause;
+	int gpause_changed = 0;
+	int pause_autoneg_wanted = -1;
+	int pause_rx_wanted = -1;
+	int pause_tx_wanted = -1;
+	struct cmdline_info cmdline_pause[] = {
+		{ "autoneg", CMDL_BOOL, &pause_autoneg_wanted,
+		  &epause.autoneg },
+		{ "rx", CMDL_BOOL, &pause_rx_wanted, &epause.rx_pause },
+		{ "tx", CMDL_BOOL, &pause_tx_wanted, &epause.tx_pause },
+	};
+	int err, changed = 0;
+
+	parse_generic_cmdline(ctx, &gpause_changed,
+			      cmdline_pause, ARRAY_SIZE(cmdline_pause));
+
+	epause.cmd = ETHTOOL_GPAUSEPARAM;
+	err = send_ioctl(ctx, &epause);
+	if (err) {
+		perror("Cannot get device pause settings");
+		return 77;
+	}
+
+	do_generic_set(cmdline_pause, ARRAY_SIZE(cmdline_pause), &changed);
+
+	if (!changed) {
+		fprintf(stderr, "no pause parameters changed, aborting\n");
+		return 78;
+	}
+
+	epause.cmd = ETHTOOL_SPAUSEPARAM;
+	err = send_ioctl(ctx, &epause);
+	if (err) {
+		perror("Cannot set device pause parameters");
+		return 79;
+	}
+
+	return 0;
+}
+
+static int do_sring(struct cmd_context *ctx)
+{
+	struct ethtool_ringparam ering;
+	int gring_changed = 0;
+	s32 ring_rx_wanted = -1;
+	s32 ring_rx_mini_wanted = -1;
+	s32 ring_rx_jumbo_wanted = -1;
+	s32 ring_tx_wanted = -1;
+	struct cmdline_info cmdline_ring[] = {
+		{ "rx", CMDL_S32, &ring_rx_wanted, &ering.rx_pending },
+		{ "rx-mini", CMDL_S32, &ring_rx_mini_wanted,
+		  &ering.rx_mini_pending },
+		{ "rx-jumbo", CMDL_S32, &ring_rx_jumbo_wanted,
+		  &ering.rx_jumbo_pending },
+		{ "tx", CMDL_S32, &ring_tx_wanted, &ering.tx_pending },
+	};
+	int err, changed = 0;
+
+	parse_generic_cmdline(ctx, &gring_changed,
+			      cmdline_ring, ARRAY_SIZE(cmdline_ring));
+
+	ering.cmd = ETHTOOL_GRINGPARAM;
+	err = send_ioctl(ctx, &ering);
+	if (err) {
+		perror("Cannot get device ring settings");
+		return 76;
+	}
+
+	do_generic_set(cmdline_ring, ARRAY_SIZE(cmdline_ring), &changed);
+
+	if (!changed) {
+		fprintf(stderr, "no ring parameters changed, aborting\n");
+		return 80;
+	}
+
+	ering.cmd = ETHTOOL_SRINGPARAM;
+	err = send_ioctl(ctx, &ering);
+	if (err) {
+		perror("Cannot set device ring parameters");
+		return 81;
+	}
+
+	return 0;
+}
+
+static int do_gring(struct cmd_context *ctx)
+{
+	struct ethtool_ringparam ering;
+	int err;
+
+	if (ctx->argc != 0)
+		exit_bad_args();
+
+	fprintf(stdout, "Ring parameters for %s:\n", ctx->devname);
+
+	ering.cmd = ETHTOOL_GRINGPARAM;
+	err = send_ioctl(ctx, &ering);
+	if (err == 0) {
+		err = dump_ring(&ering);
+		if (err)
+			return err;
+	} else {
+		perror("Cannot get device ring settings");
+		return 76;
+	}
+
+	return 0;
+}
+
+static int do_schannels(struct cmd_context *ctx)
+{
+	struct ethtool_channels echannels;
+	int gchannels_changed;
+	s32 channels_rx_wanted = -1;
+	s32 channels_tx_wanted = -1;
+	s32 channels_other_wanted = -1;
+	s32 channels_combined_wanted = -1;
+	struct cmdline_info cmdline_channels[] = {
+		{ "rx", CMDL_S32, &channels_rx_wanted, &echannels.rx_count },
+		{ "tx", CMDL_S32, &channels_tx_wanted, &echannels.tx_count },
+		{ "other", CMDL_S32, &channels_other_wanted,
+		  &echannels.other_count },
+		{ "combined", CMDL_S32, &channels_combined_wanted,
+		  &echannels.combined_count },
+	};
+	int err, changed = 0;
+
+	parse_generic_cmdline(ctx, &gchannels_changed,
+			      cmdline_channels, ARRAY_SIZE(cmdline_channels));
+
+	echannels.cmd = ETHTOOL_GCHANNELS;
+	err = send_ioctl(ctx, &echannels);
+	if (err) {
+		perror("Cannot get device channel parameters");
+		return 1;
+	}
+
+	do_generic_set(cmdline_channels, ARRAY_SIZE(cmdline_channels),
+			&changed);
+
+	if (!changed) {
+		fprintf(stderr, "no channel parameters changed.\n");
+		fprintf(stderr, "current values: rx %u tx %u other %u"
+			" combined %u\n", echannels.rx_count,
+			echannels.tx_count, echannels.other_count,
+			echannels.combined_count);
+		return 0;
+	}
+
+	echannels.cmd = ETHTOOL_SCHANNELS;
+	err = send_ioctl(ctx, &echannels);
+	if (err) {
+		perror("Cannot set device channel parameters");
+		return 1;
+	}
+
+	return 0;
+}
+
+static int do_gchannels(struct cmd_context *ctx)
+{
+	struct ethtool_channels echannels;
+	int err;
+
+	if (ctx->argc != 0)
+		exit_bad_args();
+
+	fprintf(stdout, "Channel parameters for %s:\n", ctx->devname);
+
+	echannels.cmd = ETHTOOL_GCHANNELS;
+	err = send_ioctl(ctx, &echannels);
+	if (err == 0) {
+		err = dump_channels(&echannels);
+		if (err)
+			return err;
+	} else {
+		perror("Cannot get device channel parameters\n");
+		return 1;
+	}
+	return 0;
+
+}
+
+static int do_gcoalesce(struct cmd_context *ctx)
+{
+	struct ethtool_coalesce ecoal = {};
+	int err;
+
+	if (ctx->argc != 0)
+		exit_bad_args();
+
+	fprintf(stdout, "Coalesce parameters for %s:\n", ctx->devname);
+
+	ecoal.cmd = ETHTOOL_GCOALESCE;
+	err = send_ioctl(ctx, &ecoal);
+	if (err == 0) {
+		err = dump_coalesce(&ecoal);
+		if (err)
+			return err;
+	} else {
+		perror("Cannot get device coalesce settings");
+		return 82;
+	}
+
+	return 0;
+}
+
+#define DECLARE_COALESCE_OPTION_VARS()		\
+	s32 coal_stats_wanted = -1;		\
+	int coal_adaptive_rx_wanted = -1;	\
+	int coal_adaptive_tx_wanted = -1;	\
+	s32 coal_sample_rate_wanted = -1;	\
+	s32 coal_pkt_rate_low_wanted = -1;	\
+	s32 coal_pkt_rate_high_wanted = -1;	\
+	s32 coal_rx_usec_wanted = -1;		\
+	s32 coal_rx_frames_wanted = -1;		\
+	s32 coal_rx_usec_irq_wanted = -1;	\
+	s32 coal_rx_frames_irq_wanted = -1;	\
+	s32 coal_tx_usec_wanted = -1;		\
+	s32 coal_tx_frames_wanted = -1;		\
+	s32 coal_tx_usec_irq_wanted = -1;	\
+	s32 coal_tx_frames_irq_wanted = -1;	\
+	s32 coal_rx_usec_low_wanted = -1;	\
+	s32 coal_rx_frames_low_wanted = -1;	\
+	s32 coal_tx_usec_low_wanted = -1;	\
+	s32 coal_tx_frames_low_wanted = -1;	\
+	s32 coal_rx_usec_high_wanted = -1;	\
+	s32 coal_rx_frames_high_wanted = -1;	\
+	s32 coal_tx_usec_high_wanted = -1;	\
+	s32 coal_tx_frames_high_wanted = -1
+
+#define COALESCE_CMDLINE_INFO(__ecoal)					\
+{									\
+	{ "adaptive-rx", CMDL_BOOL, &coal_adaptive_rx_wanted,		\
+	  &__ecoal.use_adaptive_rx_coalesce },				\
+	{ "adaptive-tx", CMDL_BOOL, &coal_adaptive_tx_wanted,		\
+	  &__ecoal.use_adaptive_tx_coalesce },				\
+	{ "sample-interval", CMDL_S32, &coal_sample_rate_wanted,	\
+	  &__ecoal.rate_sample_interval },				\
+	{ "stats-block-usecs", CMDL_S32, &coal_stats_wanted,		\
+	  &__ecoal.stats_block_coalesce_usecs },			\
+	{ "pkt-rate-low", CMDL_S32, &coal_pkt_rate_low_wanted,		\
+	  &__ecoal.pkt_rate_low },					\
+	{ "pkt-rate-high", CMDL_S32, &coal_pkt_rate_high_wanted,	\
+	  &__ecoal.pkt_rate_high },					\
+	{ "rx-usecs", CMDL_S32, &coal_rx_usec_wanted,			\
+	  &__ecoal.rx_coalesce_usecs },					\
+	{ "rx-frames", CMDL_S32, &coal_rx_frames_wanted,		\
+	  &__ecoal.rx_max_coalesced_frames },				\
+	{ "rx-usecs-irq", CMDL_S32, &coal_rx_usec_irq_wanted,		\
+	  &__ecoal.rx_coalesce_usecs_irq },				\
+	{ "rx-frames-irq", CMDL_S32, &coal_rx_frames_irq_wanted,	\
+	  &__ecoal.rx_max_coalesced_frames_irq },			\
+	{ "tx-usecs", CMDL_S32, &coal_tx_usec_wanted,			\
+	  &__ecoal.tx_coalesce_usecs },					\
+	{ "tx-frames", CMDL_S32, &coal_tx_frames_wanted,		\
+	  &__ecoal.tx_max_coalesced_frames },				\
+	{ "tx-usecs-irq", CMDL_S32, &coal_tx_usec_irq_wanted,		\
+	  &__ecoal.tx_coalesce_usecs_irq },				\
+	{ "tx-frames-irq", CMDL_S32, &coal_tx_frames_irq_wanted,	\
+	  &__ecoal.tx_max_coalesced_frames_irq },			\
+	{ "rx-usecs-low", CMDL_S32, &coal_rx_usec_low_wanted,		\
+	  &__ecoal.rx_coalesce_usecs_low },				\
+	{ "rx-frames-low", CMDL_S32, &coal_rx_frames_low_wanted,	\
+	  &__ecoal.rx_max_coalesced_frames_low },			\
+	{ "tx-usecs-low", CMDL_S32, &coal_tx_usec_low_wanted,		\
+	  &__ecoal.tx_coalesce_usecs_low },				\
+	{ "tx-frames-low", CMDL_S32, &coal_tx_frames_low_wanted,	\
+	  &__ecoal.tx_max_coalesced_frames_low },			\
+	{ "rx-usecs-high", CMDL_S32, &coal_rx_usec_high_wanted,		\
+	  &__ecoal.rx_coalesce_usecs_high },				\
+	{ "rx-frames-high", CMDL_S32, &coal_rx_frames_high_wanted,	\
+	  &__ecoal.rx_max_coalesced_frames_high },			\
+	{ "tx-usecs-high", CMDL_S32, &coal_tx_usec_high_wanted,		\
+	  &__ecoal.tx_coalesce_usecs_high },				\
+	{ "tx-frames-high", CMDL_S32, &coal_tx_frames_high_wanted,	\
+	  &__ecoal.tx_max_coalesced_frames_high },			\
+}
+
+static int do_scoalesce(struct cmd_context *ctx)
+{
+	struct ethtool_coalesce ecoal;
+	int gcoalesce_changed = 0;
+	DECLARE_COALESCE_OPTION_VARS();
+	struct cmdline_info cmdline_coalesce[] = COALESCE_CMDLINE_INFO(ecoal);
+	int err, changed = 0;
+
+	parse_generic_cmdline(ctx, &gcoalesce_changed,
+			      cmdline_coalesce, ARRAY_SIZE(cmdline_coalesce));
+
+	ecoal.cmd = ETHTOOL_GCOALESCE;
+	err = send_ioctl(ctx, &ecoal);
+	if (err) {
+		perror("Cannot get device coalesce settings");
+		return 76;
+	}
+
+	do_generic_set(cmdline_coalesce, ARRAY_SIZE(cmdline_coalesce),
+		       &changed);
+
+	if (!changed) {
+		fprintf(stderr, "no coalesce parameters changed, aborting\n");
+		return 80;
+	}
+
+	ecoal.cmd = ETHTOOL_SCOALESCE;
+	err = send_ioctl(ctx, &ecoal);
+	if (err) {
+		perror("Cannot set device coalesce parameters");
+		return 81;
+	}
+
+	return 0;
+}
+
+static struct feature_state *
+get_features(struct cmd_context *ctx, const struct feature_defs *defs)
+{
+	struct feature_state *state;
+	struct ethtool_value eval;
+	int err, allfail = 1;
+	u32 value;
+	int i;
+
+	state = malloc(sizeof(*state) +
+		       FEATURE_BITS_TO_BLOCKS(defs->n_features) *
+		       sizeof(state->features.features[0]));
+	if (!state)
+		return NULL;
+
+	state->off_flags = 0;
+
+	for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+		value = off_flag_def[i].value;
+		if (!off_flag_def[i].get_cmd)
+			continue;
+		eval.cmd = off_flag_def[i].get_cmd;
+		err = send_ioctl(ctx, &eval);
+		if (err) {
+			if (errno == EOPNOTSUPP &&
+			    off_flag_def[i].get_cmd == ETHTOOL_GUFO)
+				continue;
+
+			fprintf(stderr,
+				"Cannot get device %s settings: %m\n",
+				off_flag_def[i].long_name);
+		} else {
+			if (eval.data)
+				state->off_flags |= value;
+			allfail = 0;
+		}
+	}
+
+	eval.cmd = ETHTOOL_GFLAGS;
+	err = send_ioctl(ctx, &eval);
+	if (err) {
+		perror("Cannot get device flags");
+	} else {
+		state->off_flags |= eval.data & ETH_FLAG_EXT_MASK;
+		allfail = 0;
+	}
+
+	if (defs->n_features) {
+		state->features.cmd = ETHTOOL_GFEATURES;
+		state->features.size = FEATURE_BITS_TO_BLOCKS(defs->n_features);
+		err = send_ioctl(ctx, &state->features);
+		if (err)
+			perror("Cannot get device generic features");
+		else
+			allfail = 0;
+	}
+
+	if (allfail) {
+		free(state);
+		return NULL;
+	}
+
+	return state;
+}
+
+static int do_gfeatures(struct cmd_context *ctx)
+{
+	struct feature_defs *defs;
+	struct feature_state *features;
+
+	if (ctx->argc != 0)
+		exit_bad_args();
+
+	defs = get_feature_defs(ctx);
+	if (!defs) {
+		perror("Cannot get device feature names");
+		return 1;
+	}
+
+	fprintf(stdout, "Features for %s:\n", ctx->devname);
+
+	features = get_features(ctx, defs);
+	if (!features) {
+		fprintf(stdout, "no feature info available\n");
+		free(defs);
+		return 1;
+	}
+
+	dump_features(defs, features, NULL);
+	free(features);
+	free(defs);
+	return 0;
+}
+
+static int do_sfeatures(struct cmd_context *ctx)
+{
+	struct feature_defs *defs;
+	int any_changed = 0, any_mismatch = 0;
+	u32 off_flags_wanted = 0;
+	u32 off_flags_mask = 0;
+	struct ethtool_sfeatures *efeatures;
+	struct cmdline_info *cmdline_features;
+	struct feature_state *old_state, *new_state;
+	struct ethtool_value eval;
+	int err, rc;
+	int i, j;
+
+	defs = get_feature_defs(ctx);
+	if (!defs) {
+		perror("Cannot get device feature names");
+		return 1;
+	}
+	if (defs->n_features) {
+		efeatures = malloc(sizeof(*efeatures) +
+				   FEATURE_BITS_TO_BLOCKS(defs->n_features) *
+				   sizeof(efeatures->features[0]));
+		if (!efeatures) {
+			perror("Cannot parse arguments");
+			rc = 1;
+			goto err;
+		}
+		efeatures->cmd = ETHTOOL_SFEATURES;
+		efeatures->size = FEATURE_BITS_TO_BLOCKS(defs->n_features);
+		memset(efeatures->features, 0,
+		       FEATURE_BITS_TO_BLOCKS(defs->n_features) *
+		       sizeof(efeatures->features[0]));
+	} else {
+		efeatures = NULL;
+	}
+
+	/* Generate cmdline_info for legacy flags and kernel-named
+	 * features, and parse our arguments.
+	 */
+	cmdline_features = calloc(ARRAY_SIZE(off_flag_def) + defs->n_features,
+				  sizeof(cmdline_features[0]));
+	if (!cmdline_features) {
+		perror("Cannot parse arguments");
+		rc = 1;
+		goto err;
+	}
+	for (i = 0; i < ARRAY_SIZE(off_flag_def); i++)
+		flag_to_cmdline_info(off_flag_def[i].short_name,
+				     off_flag_def[i].value,
+				     &off_flags_wanted, &off_flags_mask,
+				     &cmdline_features[i]);
+	for (i = 0; i < defs->n_features; i++)
+		flag_to_cmdline_info(
+			defs->def[i].name, FEATURE_FIELD_FLAG(i),
+			&FEATURE_WORD(efeatures->features, i, requested),
+			&FEATURE_WORD(efeatures->features, i, valid),
+			&cmdline_features[ARRAY_SIZE(off_flag_def) + i]);
+	parse_generic_cmdline(ctx, &any_changed, cmdline_features,
+			      ARRAY_SIZE(off_flag_def) + defs->n_features);
+	free(cmdline_features);
+
+	if (!any_changed) {
+		fprintf(stdout, "no features changed\n");
+		rc = 0;
+		goto err;
+	}
+
+	old_state = get_features(ctx, defs);
+	if (!old_state) {
+		rc = 1;
+		goto err;
+	}
+
+	if (efeatures) {
+		/* For each offload that the user specified, update any
+		 * related features that the user did not specify and that
+		 * are not fixed.  Warn if all related features are fixed.
+		 */
+		for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+			int fixed = 1;
+
+			if (!(off_flags_mask & off_flag_def[i].value))
+				continue;
+
+			for (j = 0; j < defs->n_features; j++) {
+				if (defs->def[j].off_flag_index != i ||
+				    !FEATURE_BIT_IS_SET(
+					    old_state->features.features,
+					    j, available) ||
+				    FEATURE_BIT_IS_SET(
+					    old_state->features.features,
+					    j, never_changed))
+					continue;
+
+				fixed = 0;
+				if (!FEATURE_BIT_IS_SET(efeatures->features,
+							j, valid)) {
+					FEATURE_BIT_SET(efeatures->features,
+							j, valid);
+					if (off_flags_wanted &
+					    off_flag_def[i].value)
+						FEATURE_BIT_SET(
+							efeatures->features,
+							j, requested);
+				}
+			}
+
+			if (fixed)
+				fprintf(stderr, "Cannot change %s\n",
+					off_flag_def[i].long_name);
+		}
+
+		err = send_ioctl(ctx, efeatures);
+		if (err < 0) {
+			perror("Cannot set device feature settings");
+			rc = 1;
+			goto err;
+		}
+	} else {
+		for (i = 0; i < ARRAY_SIZE(off_flag_def); i++) {
+			if (!off_flag_def[i].set_cmd)
+				continue;
+			if (off_flags_mask & off_flag_def[i].value) {
+				eval.cmd = off_flag_def[i].set_cmd;
+				eval.data = !!(off_flags_wanted &
+					       off_flag_def[i].value);
+				err = send_ioctl(ctx, &eval);
+				if (err) {
+					fprintf(stderr,
+						"Cannot set device %s settings: %m\n",
+						off_flag_def[i].long_name);
+					rc = 1;
+					goto err;
+				}
+			}
+		}
+
+		if (off_flags_mask & ETH_FLAG_EXT_MASK) {
+			eval.cmd = ETHTOOL_SFLAGS;
+			eval.data = (old_state->off_flags & ~off_flags_mask &
+				     ETH_FLAG_EXT_MASK);
+			eval.data |= off_flags_wanted & ETH_FLAG_EXT_MASK;
+
+			err = send_ioctl(ctx, &eval);
+			if (err) {
+				perror("Cannot set device flag settings");
+				rc = 92;
+				goto err;
+			}
+		}
+	}
+
+	/* Compare new state with requested state */
+	new_state = get_features(ctx, defs);
+	if (!new_state) {
+		rc = 1;
+		goto err;
+	}
+	any_changed = new_state->off_flags != old_state->off_flags;
+	any_mismatch = (new_state->off_flags !=
+			((old_state->off_flags & ~off_flags_mask) |
+			 off_flags_wanted));
+	for (i = 0; i < FEATURE_BITS_TO_BLOCKS(defs->n_features); i++) {
+		if (new_state->features.features[i].active !=
+		    old_state->features.features[i].active)
+			any_changed = 1;
+		if (new_state->features.features[i].active !=
+		    ((old_state->features.features[i].active &
+		      ~efeatures->features[i].valid) |
+		     efeatures->features[i].requested))
+			any_mismatch = 1;
+	}
+	if (any_mismatch) {
+		if (!any_changed) {
+			fprintf(stderr,
+				"Could not change any device features\n");
+			rc = 1;
+			goto err;
+		}
+		printf("Actual changes:\n");
+		dump_features(defs, new_state, old_state);
+	}
+
+	rc = 0;
+
+err:
+	free(defs);
+	if (efeatures)
+		free(efeatures);
+	return rc;
+}
+
+static struct ethtool_link_usettings *
+do_ioctl_glinksettings(struct cmd_context *ctx)
+{
+	int err;
+	struct {
+		struct ethtool_link_settings req;
+		__u32 link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
+	} ecmd;
+	struct ethtool_link_usettings *link_usettings;
+	unsigned int u32_offs;
+
+	/* Handshake with kernel to determine number of words for link
+	 * mode bitmaps. When requested number of bitmap words is not
+	 * the one expected by kernel, the latter returns the integer
+	 * opposite of what it is expecting. We request length 0 below
+	 * (aka. invalid bitmap length) to get this info.
+	 */
+	memset(&ecmd, 0, sizeof(ecmd));
+	ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
+	err = send_ioctl(ctx, &ecmd);
+	if (err < 0)
+		return NULL;
+
+	/* see above: we expect a strictly negative value from kernel.
+	 */
+	if (ecmd.req.link_mode_masks_nwords >= 0
+	    || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
+		return NULL;
+
+	/* got the real ecmd.req.link_mode_masks_nwords,
+	 * now send the real request
+	 */
+	ecmd.req.cmd = ETHTOOL_GLINKSETTINGS;
+	ecmd.req.link_mode_masks_nwords = -ecmd.req.link_mode_masks_nwords;
+	err = send_ioctl(ctx, &ecmd);
+	if (err < 0)
+		return NULL;
+
+	if (ecmd.req.link_mode_masks_nwords <= 0
+	    || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
+		return NULL;
+
+	/* Convert to usettings struct */
+	link_usettings = calloc(1, sizeof(*link_usettings));
+	if (link_usettings == NULL)
+		return NULL;
+
+	/* keep transceiver 0 */
+	memcpy(&link_usettings->base, &ecmd.req, sizeof(link_usettings->base));
+
+	/* copy link mode bitmaps */
+	u32_offs = 0;
+	memcpy(link_usettings->link_modes.supported,
+	       &ecmd.link_mode_data[u32_offs],
+	       4 * ecmd.req.link_mode_masks_nwords);
+
+	u32_offs += ecmd.req.link_mode_masks_nwords;
+	memcpy(link_usettings->link_modes.advertising,
+	       &ecmd.link_mode_data[u32_offs],
+	       4 * ecmd.req.link_mode_masks_nwords);
+
+	u32_offs += ecmd.req.link_mode_masks_nwords;
+	memcpy(link_usettings->link_modes.lp_advertising,
+	       &ecmd.link_mode_data[u32_offs],
+	       4 * ecmd.req.link_mode_masks_nwords);
+
+	return link_usettings;
+}
+
+static int
+do_ioctl_slinksettings(struct cmd_context *ctx,
+		       const struct ethtool_link_usettings *link_usettings)
+{
+	struct {
+		struct ethtool_link_settings req;
+		__u32 link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
+	} ecmd;
+	unsigned int u32_offs;
+
+	/* refuse to send ETHTOOL_SLINKSETTINGS ioctl if
+	 * link_usettings was retrieved with ETHTOOL_GSET
+	 */
+	if (link_usettings->base.cmd != ETHTOOL_GLINKSETTINGS)
+		return -1;
+
+	/* refuse to send ETHTOOL_SLINKSETTINGS ioctl if deprecated fields
+	 * were set
+	 */
+	if (link_usettings->deprecated.transceiver)
+		return -1;
+
+	if (link_usettings->base.link_mode_masks_nwords <= 0)
+		return -1;
+
+	memcpy(&ecmd.req, &link_usettings->base, sizeof(ecmd.req));
+	ecmd.req.cmd = ETHTOOL_SLINKSETTINGS;
+
+	/* copy link mode bitmaps */
+	u32_offs = 0;
+	memcpy(&ecmd.link_mode_data[u32_offs],
+	       link_usettings->link_modes.supported,
+	       4 * ecmd.req.link_mode_masks_nwords);
+
+	u32_offs += ecmd.req.link_mode_masks_nwords;
+	memcpy(&ecmd.link_mode_data[u32_offs],
+	       link_usettings->link_modes.advertising,
+	       4 * ecmd.req.link_mode_masks_nwords);
+
+	u32_offs += ecmd.req.link_mode_masks_nwords;
+	memcpy(&ecmd.link_mode_data[u32_offs],
+	       link_usettings->link_modes.lp_advertising,
+	       4 * ecmd.req.link_mode_masks_nwords);
+
+	return send_ioctl(ctx, &ecmd);
+}
+
+static struct ethtool_link_usettings *
+do_ioctl_gset(struct cmd_context *ctx)
+{
+	int err;
+	struct ethtool_cmd ecmd;
+	struct ethtool_link_usettings *link_usettings;
+
+	memset(&ecmd, 0, sizeof(ecmd));
+	ecmd.cmd = ETHTOOL_GSET;
+	err = send_ioctl(ctx, &ecmd);
+	if (err < 0)
+		return NULL;
+
+	link_usettings = calloc(1, sizeof(*link_usettings));
+	if (link_usettings == NULL)
+		return NULL;
+
+	/* remember that ETHTOOL_GSET was used */
+	link_usettings->base.cmd = ETHTOOL_GSET;
+
+	link_usettings->base.link_mode_masks_nwords = 1;
+	link_usettings->link_modes.supported[0] = ecmd.supported;
+	link_usettings->link_modes.advertising[0] = ecmd.advertising;
+	link_usettings->link_modes.lp_advertising[0] = ecmd.lp_advertising;
+	link_usettings->base.speed = ethtool_cmd_speed(&ecmd);
+	link_usettings->base.duplex = ecmd.duplex;
+	link_usettings->base.port = ecmd.port;
+	link_usettings->base.phy_address = ecmd.phy_address;
+	link_usettings->deprecated.transceiver = ecmd.transceiver;
+	link_usettings->base.autoneg = ecmd.autoneg;
+	link_usettings->base.mdio_support = ecmd.mdio_support;
+	/* ignored (fully deprecated): maxrxpkt, maxtxpkt */
+	link_usettings->base.eth_tp_mdix = ecmd.eth_tp_mdix;
+	link_usettings->base.eth_tp_mdix_ctrl = ecmd.eth_tp_mdix_ctrl;
+
+	return link_usettings;
+}
+
+static bool ethtool_link_mode_is_backward_compatible(const u32 *mask)
+{
+	unsigned int i;
+
+	for (i = 1; i < ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32; ++i)
+		if (mask[i])
+			return false;
+
+	return true;
+}
+
+static int
+do_ioctl_sset(struct cmd_context *ctx,
+	      const struct ethtool_link_usettings *link_usettings)
+{
+	struct ethtool_cmd ecmd;
+
+	/* refuse to send ETHTOOL_SSET ioctl if link_usettings was
+	 * retrieved with ETHTOOL_GLINKSETTINGS
+	 */
+	if (link_usettings->base.cmd != ETHTOOL_GSET)
+		return -1;
+
+	if (link_usettings->base.link_mode_masks_nwords <= 0)
+		return -1;
+
+	/* refuse to sset if any bit > 31 is set */
+	if (!ethtool_link_mode_is_backward_compatible(
+		    link_usettings->link_modes.supported))
+		return -1;
+	if (!ethtool_link_mode_is_backward_compatible(
+		    link_usettings->link_modes.advertising))
+		return -1;
+	if (!ethtool_link_mode_is_backward_compatible(
+		    link_usettings->link_modes.lp_advertising))
+		return -1;
+
+	memset(&ecmd, 0, sizeof(ecmd));
+	ecmd.cmd = ETHTOOL_SSET;
+
+	ecmd.supported = link_usettings->link_modes.supported[0];
+	ecmd.advertising = link_usettings->link_modes.advertising[0];
+	ecmd.lp_advertising = link_usettings->link_modes.lp_advertising[0];
+	ethtool_cmd_speed_set(&ecmd, link_usettings->base.speed);
+	ecmd.duplex = link_usettings->base.duplex;
+	ecmd.port = link_usettings->base.port;
+	ecmd.phy_address = link_usettings->base.phy_address;
+	ecmd.transceiver = link_usettings->deprecated.transceiver;
+	ecmd.autoneg = link_usettings->base.autoneg;
+	ecmd.mdio_support = link_usettings->base.mdio_support;
+	/* ignored (fully deprecated): maxrxpkt, maxtxpkt */
+	ecmd.eth_tp_mdix = link_usettings->base.eth_tp_mdix;
+	ecmd.eth_tp_mdix_ctrl = link_usettings->base.eth_tp_mdix_ctrl;
+	return send_ioctl(ctx, &ecmd);
+}
+
+static int do_gset(struct cmd_context *ctx)
+{
+	int err;
+	struct ethtool_link_usettings *link_usettings;
+	struct ethtool_wolinfo wolinfo;
+	struct ethtool_value edata;
+	int allfail = 1;
+
+	if (ctx->argc != 0)
+		exit_bad_args();
+
+	fprintf(stdout, "Settings for %s:\n", ctx->devname);
+
+	link_usettings = do_ioctl_glinksettings(ctx);
+	if (link_usettings == NULL)
+		link_usettings = do_ioctl_gset(ctx);
+	if (link_usettings != NULL) {
+		err = dump_link_usettings(link_usettings);
+		free(link_usettings);
+		if (err)
+			return err;
+		allfail = 0;
+	} else if (errno != EOPNOTSUPP) {
+		perror("Cannot get device settings");
+	}
+
+	wolinfo.cmd = ETHTOOL_GWOL;
+	err = send_ioctl(ctx, &wolinfo);
+	if (err == 0) {
+		err = dump_wol(&wolinfo);
+		if (err)
+			return err;
+		allfail = 0;
+	} else if (errno != EOPNOTSUPP) {
+		perror("Cannot get wake-on-lan settings");
+	}
+
+	edata.cmd = ETHTOOL_GMSGLVL;
+	err = send_ioctl(ctx, &edata);
+	if (err == 0) {
+		fprintf(stdout, "	Current message level: 0x%08x (%d)\n"
+			"			       ",
+			edata.data, edata.data);
+		print_flags(flags_msglvl, ARRAY_SIZE(flags_msglvl),
+			    edata.data);
+		fprintf(stdout, "\n");
+		allfail = 0;
+	} else if (errno != EOPNOTSUPP) {
+		perror("Cannot get message level");
+	}
+
+	edata.cmd = ETHTOOL_GLINK;
+	err = send_ioctl(ctx, &edata);
+	if (err == 0) {
+		fprintf(stdout, "	Link detected: %s\n",
+			edata.data ? "yes":"no");
+		allfail = 0;
+	} else if (errno != EOPNOTSUPP) {
+		perror("Cannot get link status");
+	}
+
+	if (allfail) {
+		fprintf(stdout, "No data available\n");
+		return 75;
+	}
+	return 0;
+}
+
+static int do_sset(struct cmd_context *ctx)
+{
+	int speed_wanted = -1;
+	int duplex_wanted = -1;
+	int port_wanted = -1;
+	int mdix_wanted = -1;
+	int autoneg_wanted = -1;
+	int phyad_wanted = -1;
+	int xcvr_wanted = -1;
+	u32 *full_advertising_wanted = NULL;
+	u32 *advertising_wanted = NULL;
+	ETHTOOL_DECLARE_LINK_MODE_MASK(mask_full_advertising_wanted);
+	ETHTOOL_DECLARE_LINK_MODE_MASK(mask_advertising_wanted);
+	int gset_changed = 0; /* did anything in GSET change? */
+	u32 wol_wanted = 0;
+	int wol_change = 0;
+	u8 sopass_wanted[SOPASS_MAX];
+	int sopass_change = 0;
+	int gwol_changed = 0; /* did anything in GWOL change? */
+	int msglvl_changed = 0;
+	u32 msglvl_wanted = 0;
+	u32 msglvl_mask = 0;
+	struct cmdline_info cmdline_msglvl[ARRAY_SIZE(flags_msglvl)];
+	int argc = ctx->argc;
+	char **argp = ctx->argp;
+	int i;
+	int err = 0;
+
+	for (i = 0; i < ARRAY_SIZE(flags_msglvl); i++)
+		flag_to_cmdline_info(flags_msglvl[i].name,
+				     flags_msglvl[i].value,
+				     &msglvl_wanted, &msglvl_mask,
+				     &cmdline_msglvl[i]);
+
+	for (i = 0; i < argc; i++) {
+		if (!strcmp(argp[i], "speed")) {
+			gset_changed = 1;
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			speed_wanted = get_int(argp[i], 10);
+		} else if (!strcmp(argp[i], "duplex")) {
+			gset_changed = 1;
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			if (!strcmp(argp[i], "half"))
+				duplex_wanted = DUPLEX_HALF;
+			else if (!strcmp(argp[i], "full"))
+				duplex_wanted = DUPLEX_FULL;
+			else
+				exit_bad_args();
+		} else if (!strcmp(argp[i], "port")) {
+			gset_changed = 1;
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			if (!strcmp(argp[i], "tp"))
+				port_wanted = PORT_TP;
+			else if (!strcmp(argp[i], "aui"))
+				port_wanted = PORT_AUI;
+			else if (!strcmp(argp[i], "bnc"))
+				port_wanted = PORT_BNC;
+			else if (!strcmp(argp[i], "mii"))
+				port_wanted = PORT_MII;
+			else if (!strcmp(argp[i], "fibre"))
+				port_wanted = PORT_FIBRE;
+			else
+				exit_bad_args();
+		} else if (!strcmp(argp[i], "mdix")) {
+			gset_changed = 1;
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			if (!strcmp(argp[i], "auto"))
+				mdix_wanted = ETH_TP_MDI_AUTO;
+			else if (!strcmp(argp[i], "on"))
+				mdix_wanted = ETH_TP_MDI_X;
+			else if (!strcmp(argp[i], "off"))
+				mdix_wanted = ETH_TP_MDI;
+			else
+				exit_bad_args();
+		} else if (!strcmp(argp[i], "autoneg")) {
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			if (!strcmp(argp[i], "on")) {
+				gset_changed = 1;
+				autoneg_wanted = AUTONEG_ENABLE;
+			} else if (!strcmp(argp[i], "off")) {
+				gset_changed = 1;
+				autoneg_wanted = AUTONEG_DISABLE;
+			} else {
+				exit_bad_args();
+			}
+		} else if (!strcmp(argp[i], "advertise")) {
+			gset_changed = 1;
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			if (parse_hex_u32_bitmap(
+				    argp[i],
+				    ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBITS,
+				    mask_full_advertising_wanted))
+				exit_bad_args();
+			full_advertising_wanted = mask_full_advertising_wanted;
+		} else if (!strcmp(argp[i], "phyad")) {
+			gset_changed = 1;
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			phyad_wanted = get_int(argp[i], 0);
+		} else if (!strcmp(argp[i], "xcvr")) {
+			gset_changed = 1;
+			i += 1;
+			if (i >= argc)
+				exit_bad_args();
+			if (!strcmp(argp[i], "internal"))
+				xcvr_wanted = XCVR_INTERNAL;
+			else if (!strcmp(argp[i], "external"))
+				xcvr_wanted = XCVR_EXTERNAL;
+			else
+				exit_bad_args();
+		} else if (!strcmp(argp[i], "wol")) {
+			gwol_changed = 1;
+			i++;
+			if (i >= argc)
+				exit_bad_args();
+			if (parse_wolopts(argp[i], &wol_wanted) < 0)
+				exit_bad_args();
+			wol_change = 1;
+		} else if (!strcmp(argp[i], "sopass")) {
+			gwol_changed = 1;
+			i++;
+			if (i >= argc)
+				exit_bad_args();
+			get_mac_addr(argp[i], sopass_wanted);
+			sopass_change = 1;
+		} else if (!strcmp(argp[i], "msglvl")) {
+			i++;
+			if (i >= argc)
+				exit_bad_args();
+			if (isdigit((unsigned char)argp[i][0])) {
+				msglvl_changed = 1;
+				msglvl_mask = ~0;
+				msglvl_wanted =
+					get_uint_range(argp[i], 0,
+						       0xffffffff);
+			} else {
+				ctx->argc -= i;
+				ctx->argp += i;
+				parse_generic_cmdline(
+					ctx, &msglvl_changed,
+					cmdline_msglvl,
+					ARRAY_SIZE(cmdline_msglvl));
+				break;
+			}
+		} else {
+			exit_bad_args();
+		}
+	}
+
+	if (full_advertising_wanted == NULL) {
+		/* User didn't supply a full advertisement bitfield:
+		 * construct one from the specified speed and duplex.
+		 */
+		int adv_bit = -1;
+
+		if (speed_wanted == SPEED_10 && duplex_wanted == DUPLEX_HALF)
+			adv_bit = ETHTOOL_LINK_MODE_10baseT_Half_BIT;
+		else if (speed_wanted == SPEED_10 &&
+			 duplex_wanted == DUPLEX_FULL)
+			adv_bit = ETHTOOL_LINK_MODE_10baseT_Full_BIT;
+		else if (speed_wanted == SPEED_100 &&
+			 duplex_wanted == DUPLEX_HALF)
+			adv_bit = ETHTOOL_LINK_MODE_100baseT_Half_BIT;
+		else if (speed_wanted == SPEED_100 &&
+			 duplex_wanted == DUPLEX_FULL)
+			adv_bit = ETHTOOL_LINK_MODE_100baseT_Full_BIT;
+		else if (speed_wanted == SPEED_1000 &&
+			 duplex_wanted == DUPLEX_HALF)
+			adv_bit = ETHTOOL_LINK_MODE_1000baseT_Half_BIT;
+		else if (speed_wanted == SPEED_1000 &&
+			 duplex_wanted == DUPLEX_FULL)
+			adv_bit = ETHTOOL_LINK_MODE_1000baseT_Full_BIT;
+		else if (speed_wanted == SPEED_2500 &&
+			 duplex_wanted == DUPLEX_FULL)
+			adv_bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT;
+		else if (speed_wanted == SPEED_10000 &&
+			 duplex_wanted == DUPLEX_FULL)
+			adv_bit = ETHTOOL_LINK_MODE_10000baseT_Full_BIT;
+
+		if (adv_bit >= 0) {
+			advertising_wanted = mask_advertising_wanted;
+			ethtool_link_mode_zero(advertising_wanted);
+			ethtool_link_mode_set_bit(
+				adv_bit, advertising_wanted);
+		}
+		/* otherwise: auto negotiate without forcing,
+		 * all supported speed will be assigned below
+		 */
+	}
+
+	if (gset_changed) {
+		struct ethtool_link_usettings *link_usettings;
+
+		link_usettings = do_ioctl_glinksettings(ctx);
+		if (link_usettings == NULL)
+			link_usettings = do_ioctl_gset(ctx);
+		if (link_usettings == NULL) {
+			perror("Cannot get current device settings");
+			err = -1;
+		} else {
+			/* Change everything the user specified. */
+			if (speed_wanted != -1)
+				link_usettings->base.speed = speed_wanted;
+			if (duplex_wanted != -1)
+				link_usettings->base.duplex = duplex_wanted;
+			if (port_wanted != -1)
+				link_usettings->base.port = port_wanted;
+			if (mdix_wanted != -1) {
+				/* check driver supports MDI-X */
+				if (link_usettings->base.eth_tp_mdix_ctrl
+				    != ETH_TP_MDI_INVALID)
+					link_usettings->base.eth_tp_mdix_ctrl
+						= mdix_wanted;
+				else
+					fprintf(stderr,
+						"setting MDI not supported\n");
+			}
+			if (autoneg_wanted != -1)
+				link_usettings->base.autoneg = autoneg_wanted;
+			if (phyad_wanted != -1)
+				link_usettings->base.phy_address = phyad_wanted;
+			if (xcvr_wanted != -1)
+				link_usettings->deprecated.transceiver
+					= xcvr_wanted;
+			/* XXX If the user specified speed or duplex
+			 * then we should mask the advertised modes
+			 * accordingly.  For now, warn that we aren't
+			 * doing that.
+			 */
+			if ((speed_wanted != -1 || duplex_wanted != -1) &&
+			    link_usettings->base.autoneg &&
+			    advertising_wanted == NULL) {
+				fprintf(stderr, "Cannot advertise");
+				if (speed_wanted >= 0)
+					fprintf(stderr, " speed %d",
+						speed_wanted);
+				if (duplex_wanted >= 0)
+					fprintf(stderr, " duplex %s",
+						duplex_wanted ?
+						"full" : "half");
+				fprintf(stderr,	"\n");
+			}
+			if (autoneg_wanted == AUTONEG_ENABLE &&
+			    advertising_wanted == NULL &&
+			    full_advertising_wanted == NULL) {
+				unsigned int i;
+
+				/* Auto negotiation enabled, but with
+				 * unspecified speed and duplex: enable all
+				 * supported speeds and duplexes.
+				 */
+				ethtool_link_mode_for_each_u32(i) {
+					u32 sup = link_usettings->link_modes.supported[i];
+					u32 *adv = link_usettings->link_modes.advertising + i;
+
+					*adv = ((*adv & ~all_advertised_modes[i])
+						| (sup & all_advertised_modes[i]));
+				}
+
+				/* If driver supports unknown flags, we cannot
+				 * be sure that we enable all link modes.
+				 */
+				ethtool_link_mode_for_each_u32(i) {
+					u32 sup = link_usettings->link_modes.supported[i];
+
+					if ((sup & all_advertised_flags[i]) != sup) {
+						fprintf(stderr, "Driver supports one or more unknown flags\n");
+						break;
+					}
+				}
+			} else if (advertising_wanted != NULL) {
+				unsigned int i;
+
+				/* Enable all requested modes */
+				ethtool_link_mode_for_each_u32(i) {
+					u32 *adv = link_usettings->link_modes.advertising + i;
+
+					*adv = ((*adv & ~all_advertised_modes[i])
+						| advertising_wanted[i]);
+				}
+			} else if (full_advertising_wanted != NULL) {
+				ethtool_link_mode_copy(
+					link_usettings->link_modes.advertising,
+					full_advertising_wanted);
+			}
+
+			/* Try to perform the update. */
+			if (link_usettings->base.cmd == ETHTOOL_GLINKSETTINGS)
+				err = do_ioctl_slinksettings(ctx,
+							     link_usettings);
+			else
+				err = do_ioctl_sset(ctx, link_usettings);
+			free(link_usettings);
+			if (err < 0)
+				perror("Cannot set new settings");
+		}
+		if (err < 0) {
+			if (speed_wanted != -1)
+				fprintf(stderr, "  not setting speed\n");
+			if (duplex_wanted != -1)
+				fprintf(stderr, "  not setting duplex\n");
+			if (port_wanted != -1)
+				fprintf(stderr, "  not setting port\n");
+			if (autoneg_wanted != -1)
+				fprintf(stderr, "  not setting autoneg\n");
+			if (phyad_wanted != -1)
+				fprintf(stderr, "  not setting phy_address\n");
+			if (xcvr_wanted != -1)
+				fprintf(stderr, "  not setting transceiver\n");
+			if (mdix_wanted != -1)
+				fprintf(stderr, "  not setting mdix\n");
+		}
+	}
+
+	if (gwol_changed) {
+		struct ethtool_wolinfo wol;
+
+		wol.cmd = ETHTOOL_GWOL;
+		err = send_ioctl(ctx, &wol);
+		if (err < 0) {
+			perror("Cannot get current wake-on-lan settings");
+		} else {
+			/* Change everything the user specified. */
+			if (wol_change)
+				wol.wolopts = wol_wanted;
+			if (sopass_change) {
+				int i;
+				for (i = 0; i < SOPASS_MAX; i++)
+					wol.sopass[i] = sopass_wanted[i];
+			}
+
+			/* Try to perform the update. */
+			wol.cmd = ETHTOOL_SWOL;
+			err = send_ioctl(ctx, &wol);
+			if (err < 0)
+				perror("Cannot set new wake-on-lan settings");
+		}
+		if (err < 0) {
+			if (wol_change)
+				fprintf(stderr, "  not setting wol\n");
+			if (sopass_change)
+				fprintf(stderr, "  not setting sopass\n");
+		}
+	}
+
+	if (msglvl_changed) {
+		struct ethtool_value edata;
+
+		edata.cmd = ETHTOOL_GMSGLVL;
+		err = send_ioctl(ctx, &edata);
+		if (err < 0) {
+			perror("Cannot get msglvl");
+		} else {
+			edata.cmd = ETHTOOL_SMSGLVL;
+			edata.data = ((edata.data & ~msglvl_mask) |
+				      msglvl_wanted);
+			err = send_ioctl(ctx, &edata);
+			if (err < 0)
+				perror("Cannot set new msglvl");
+		}
+	}
+
+	return 0;
+}
+
+static int do_gregs(struct cmd_context *ctx)
+{
+	int gregs_changed = 0;
+	int gregs_dump_raw = 0;
+	int gregs_dump_hex = 0;
+	char *gregs_dump_file = NULL;
+	struct cmdline_info cmdline_gregs[] = {
+		{ "raw", CMDL_BOOL, &gregs_dump_raw, NULL },
+		{ "hex", CMDL_BOOL, &gregs_dump_hex, NULL },
+		{ "file", CMDL_STR, &gregs_dump_file, NULL },
+	};
+	int err;
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs *regs;
+
+	parse_generic_cmdline(ctx, &gregs_changed,
+			      cmdline_gregs, ARRAY_SIZE(cmdline_gregs));
+
+	drvinfo.cmd = ETHTOOL_GDRVINFO;
+	err = send_ioctl(ctx, &drvinfo);
+	if (err < 0) {
+		perror("Cannot get driver information");
+		return 72;
+	}
+
+	regs = calloc(1, sizeof(*regs)+drvinfo.regdump_len);
+	if (!regs) {
+		perror("Cannot allocate memory for register dump");
+		return 73;
+	}
+	regs->cmd = ETHTOOL_GREGS;
+	regs->len = drvinfo.regdump_len;
+	err = send_ioctl(ctx, regs);
+	if (err < 0) {
+		perror("Cannot get register dump");
+		free(regs);
+		return 74;
+	}
+
+	if (!gregs_dump_raw && gregs_dump_file != NULL) {
+		/* overwrite reg values from file dump */
+		FILE *f = fopen(gregs_dump_file, "r");
+		struct ethtool_regs *nregs;
+		struct stat st;
+		size_t nread;
+
+		if (!f || fstat(fileno(f), &st) < 0) {
+			fprintf(stderr, "Can't open '%s': %s\n",
+				gregs_dump_file, strerror(errno));
+			if (f)
+				fclose(f);
+			free(regs);
+			return 75;
+		}
+
+		nregs = realloc(regs, sizeof(*regs) + st.st_size);
+		if (!nregs) {
+			perror("Cannot allocate memory for register dump");
+			free(regs); /* was not freed by realloc */
+			return 73;
+		}
+		regs = nregs;
+		regs->len = st.st_size;
+		nread = fread(regs->data, regs->len, 1, f);
+		fclose(f);
+		if (nread != 1) {
+			free(regs);
+			return 75;
+		}
+	}
+
+	if (dump_regs(gregs_dump_raw, gregs_dump_hex,
+		      &drvinfo, regs) < 0) {
+		fprintf(stderr, "Cannot dump registers\n");
+		free(regs);
+		return 75;
+	}
+	free(regs);
+
+	return 0;
+}
+
+static int do_nway_rst(struct cmd_context *ctx)
+{
+	struct ethtool_value edata;
+	int err;
+
+	if (ctx->argc != 0)
+		exit_bad_args();
+
+	edata.cmd = ETHTOOL_NWAY_RST;
+	err = send_ioctl(ctx, &edata);
+	if (err < 0)
+		perror("Cannot restart autonegotiation");
+
+	return err;
+}
+
+static int do_geeprom(struct cmd_context *ctx)
+{
+	int geeprom_changed = 0;
+	int geeprom_dump_raw = 0;
+	u32 geeprom_offset = 0;
+	u32 geeprom_length = -1;
+	struct cmdline_info cmdline_geeprom[] = {
+		{ "offset", CMDL_U32, &geeprom_offset, NULL },
+		{ "length", CMDL_U32, &geeprom_length, NULL },
+		{ "raw", CMDL_BOOL, &geeprom_dump_raw, NULL },
+	};
+	int err;
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_eeprom *eeprom;
+
+	parse_generic_cmdline(ctx, &geeprom_changed,
+			      cmdline_geeprom, ARRAY_SIZE(cmdline_geeprom));
+
+	drvinfo.cmd = ETHTOOL_GDRVINFO;
+	err = send_ioctl(ctx, &drvinfo);
+	if (err < 0) {
+		perror("Cannot get driver information");
+		return 74;
+	}
+
+	if (geeprom_length == -1)
+		geeprom_length = drvinfo.eedump_len;
+
+	if (drvinfo.eedump_len < geeprom_offset + geeprom_length)
+		geeprom_length = drvinfo.eedump_len - geeprom_offset;
+
+	eeprom = calloc(1, sizeof(*eeprom)+geeprom_length);
+	if (!eeprom) {
+		perror("Cannot allocate memory for EEPROM data");
+		return 75;
+	}
+	eeprom->cmd = ETHTOOL_GEEPROM;
+	eeprom->len = geeprom_length;
+	eeprom->offset = geeprom_offset;
+	err = send_ioctl(ctx, eeprom);
+	if (err < 0) {
+		perror("Cannot get EEPROM data");
+		free(eeprom);
+		return 74;
+	}
+	err = dump_eeprom(geeprom_dump_raw, &drvinfo, eeprom);
+	free(eeprom);
+
+	return err;
+}
+
+static int do_seeprom(struct cmd_context *ctx)
+{
+	int seeprom_changed = 0;
+	u32 seeprom_magic = 0;
+	u32 seeprom_length = -1;
+	u32 seeprom_offset = 0;
+	u8 seeprom_value = 0;
+	int seeprom_value_seen = 0;
+	struct cmdline_info cmdline_seeprom[] = {
+		{ "magic", CMDL_U32, &seeprom_magic, NULL },
+		{ "offset", CMDL_U32, &seeprom_offset, NULL },
+		{ "length", CMDL_U32, &seeprom_length, NULL },
+		{ "value", CMDL_U8, &seeprom_value, NULL,
+		  0, &seeprom_value_seen },
+	};
+	int err;
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_eeprom *eeprom;
+
+	parse_generic_cmdline(ctx, &seeprom_changed,
+			      cmdline_seeprom, ARRAY_SIZE(cmdline_seeprom));
+
+	drvinfo.cmd = ETHTOOL_GDRVINFO;
+	err = send_ioctl(ctx, &drvinfo);
+	if (err < 0) {
+		perror("Cannot get driver information");
+		return 74;
+	}
+
+	if (seeprom_value_seen)
+		seeprom_length = 1;
+
+	if (seeprom_length == -1)
+		seeprom_length = drvinfo.eedump_len;
+
+	if (drvinfo.eedump_len < seeprom_offset + seeprom_length) {
+		fprintf(stderr, "offset & length out of bounds\n");
+		return 1;
+	}
+
+	eeprom = calloc(1, sizeof(*eeprom)+seeprom_length);
+	if (!eeprom) {
+		perror("Cannot allocate memory for EEPROM data");
+		return 75;
+	}
+
+	eeprom->cmd = ETHTOOL_SEEPROM;
+	eeprom->len = seeprom_length;
+	eeprom->offset = seeprom_offset;
+	eeprom->magic = seeprom_magic;
+	eeprom->data[0] = seeprom_value;
+
+	/* Multi-byte write: read input from stdin */
+	if (!seeprom_value_seen) {
+		if (fread(eeprom->data, eeprom->len, 1, stdin) != 1) {
+			fprintf(stderr, "not enough data from stdin\n");
+			free(eeprom);
+			return 75;
+		}
+		if ((fgetc(stdin) != EOF) || !feof(stdin)) {
+			fprintf(stderr, "too much data from stdin\n");
+			free(eeprom);
+			return 75;
+		}
+	}
+
+	err = send_ioctl(ctx, eeprom);
+	if (err < 0) {
+		perror("Cannot set EEPROM data");
+		err = 87;
+	}
+	free(eeprom);
+
+	return err;
+}
+
+static int do_test(struct cmd_context *ctx)
+{
+	enum {
+		ONLINE = 0,
+		OFFLINE,
+		EXTERNAL_LB,
+	} test_type;
+	int err;
+	struct ethtool_test *test;
+	struct ethtool_gstrings *strings;
+
+	if (ctx->argc > 1)
+		exit_bad_args();
+	if (ctx->argc == 1) {
+		if (!strcmp(ctx->argp[0], "online"))
+			test_type = ONLINE;
+		else if (!strcmp(*ctx->argp, "offline"))
+			test_type = OFFLINE;
+		else if (!strcmp(*ctx->argp, "external_lb"))
+			test_type = EXTERNAL_LB;
+		else
+			exit_bad_args();
+	} else {
+		test_type = OFFLINE;
+	}
+
+	strings = get_stringset(ctx, ETH_SS_TEST,
+				offsetof(struct ethtool_drvinfo, testinfo_len),
+				1);
+	if (!strings) {
+		perror("Cannot get strings");
+		return 74;
+	}
+
+	test = calloc(1, sizeof(*test) + strings->len * sizeof(u64));
+	if (!test) {
+		perror("Cannot allocate memory for test info");
+		free(strings);
+		return 73;
+	}
+	memset(test->data, 0, strings->len * sizeof(u64));
+	test->cmd = ETHTOOL_TEST;
+	test->len = strings->len;
+	if (test_type == EXTERNAL_LB)
+		test->flags = (ETH_TEST_FL_OFFLINE | ETH_TEST_FL_EXTERNAL_LB);
+	else if (test_type == OFFLINE)
+		test->flags = ETH_TEST_FL_OFFLINE;
+	else
+		test->flags = 0;
+	err = send_ioctl(ctx, test);
+	if (err < 0) {
+		perror("Cannot test");
+		free(test);
+		free(strings);
+		return 74;
+	}
+
+	err = dump_test(test, strings);
+	free(test);
+	free(strings);
+
+	return err;
+}
+
+static int do_phys_id(struct cmd_context *ctx)
+{
+	int err;
+	struct ethtool_value edata;
+	int phys_id_time;
+
+	if (ctx->argc > 1)
+		exit_bad_args();
+	if (ctx->argc == 1)
+		phys_id_time = get_int(*ctx->argp, 0);
+	else
+		phys_id_time = 0;
+
+	edata.cmd = ETHTOOL_PHYS_ID;
+	edata.data = phys_id_time;
+	err = send_ioctl(ctx, &edata);
+	if (err < 0)
+		perror("Cannot identify NIC");
+
+	return err;
+}
+
+static int do_gstats(struct cmd_context *ctx, int cmd, int stringset,
+		    const char *name)
+{
+	struct ethtool_gstrings *strings;
+	struct ethtool_stats *stats;
+	unsigned int n_stats, sz_stats, i;
+	int err;
+
+	if (ctx->argc != 0)
+		exit_bad_args();
+
+	strings = get_stringset(ctx, stringset,
+				offsetof(struct ethtool_drvinfo, n_stats),
+				0);
+	if (!strings) {
+		perror("Cannot get stats strings information");
+		return 96;
+	}
+
+	n_stats = strings->len;
+	if (n_stats < 1) {
+		fprintf(stderr, "no stats available\n");
+		free(strings);
+		return 94;
+	}
+
+	sz_stats = n_stats * sizeof(u64);
+
+	stats = calloc(1, sz_stats + sizeof(struct ethtool_stats));
+	if (!stats) {
+		fprintf(stderr, "no memory available\n");
+		free(strings);
+		return 95;
+	}
+
+	stats->cmd = cmd;
+	stats->n_stats = n_stats;
+	err = send_ioctl(ctx, stats);
+	if (err < 0) {
+		perror("Cannot get stats information");
+		free(strings);
+		free(stats);
+		return 97;
+	}
+
+	/* todo - pretty-print the strings per-driver */
+	fprintf(stdout, "%s statistics:\n", name);
+	for (i = 0; i < n_stats; i++) {
+		fprintf(stdout, "     %.*s: %llu\n",
+			ETH_GSTRING_LEN,
+			&strings->data[i * ETH_GSTRING_LEN],
+			stats->data[i]);
+	}
+	free(strings);
+	free(stats);
+
+	return 0;
+}
+
+static int do_gnicstats(struct cmd_context *ctx)
+{
+	return do_gstats(ctx, ETHTOOL_GSTATS, ETH_SS_STATS, "NIC");
+}
+
+static int do_gphystats(struct cmd_context *ctx)
+{
+	return do_gstats(ctx, ETHTOOL_GPHYSTATS, ETH_SS_PHY_STATS, "PHY");
+}
+
+static int do_srxntuple(struct cmd_context *ctx,
+			struct ethtool_rx_flow_spec *rx_rule_fs);
+
+static int do_srxclass(struct cmd_context *ctx)
+{
+	int err;
+
+	if (ctx->argc < 2)
+		exit_bad_args();
+
+	if (!strcmp(ctx->argp[0], "rx-flow-hash")) {
+		int rx_fhash_set;
+		u32 rx_fhash_val;
+		struct ethtool_rxnfc nfccmd;
+		bool flow_rss = false;
+
+		if (ctx->argc == 5) {
+			if (strcmp(ctx->argp[3], "context"))
+				exit_bad_args();
+			flow_rss = true;
+			nfccmd.rss_context = get_u32(ctx->argp[4], 0);
+		} else if (ctx->argc != 3) {
+			exit_bad_args();
+		}
+		rx_fhash_set = rxflow_str_to_type(ctx->argp[1]);
+		if (!rx_fhash_set)
+			exit_bad_args();
+		if (parse_rxfhashopts(ctx->argp[2], &rx_fhash_val) < 0)
+			exit_bad_args();
+
+		nfccmd.cmd = ETHTOOL_SRXFH;
+		nfccmd.flow_type = rx_fhash_set;
+		nfccmd.data = rx_fhash_val;
+		if (flow_rss)
+			nfccmd.flow_type |= FLOW_RSS;
+
+		err = send_ioctl(ctx, &nfccmd);
+		if (err < 0)
+			perror("Cannot change RX network flow hashing options");
+	} else if (!strcmp(ctx->argp[0], "flow-type")) {
+		struct ethtool_rx_flow_spec rx_rule_fs;
+		__u32 rss_context = 0;
+
+		ctx->argc--;
+		ctx->argp++;
+		if (rxclass_parse_ruleopts(ctx, &rx_rule_fs, &rss_context) < 0)
+			exit_bad_args();
+
+		/* attempt to add rule via N-tuple specifier */
+		err = do_srxntuple(ctx, &rx_rule_fs);
+		if (!err)
+			return 0;
+
+		/* attempt to add rule via network flow classifier */
+		err = rxclass_rule_ins(ctx, &rx_rule_fs, rss_context);
+		if (err < 0) {
+			fprintf(stderr, "Cannot insert"
+				" classification rule\n");
+			return 1;
+		}
+	} else if (!strcmp(ctx->argp[0], "delete")) {
+		int rx_class_rule_del =
+			get_uint_range(ctx->argp[1], 0, INT_MAX);
+
+		err = rxclass_rule_del(ctx, rx_class_rule_del);
+
+		if (err < 0) {
+			fprintf(stderr, "Cannot delete"
+				" classification rule\n");
+			return 1;
+		}
+	} else {
+		exit_bad_args();
+	}
+
+	return 0;
+}
+
+static int do_grxclass(struct cmd_context *ctx)
+{
+	struct ethtool_rxnfc nfccmd;
+	int err;
+
+	if (ctx->argc > 0 && !strcmp(ctx->argp[0], "rx-flow-hash")) {
+		int rx_fhash_get;
+		bool flow_rss = false;
+
+		if (ctx->argc == 4) {
+			if (strcmp(ctx->argp[2], "context"))
+				exit_bad_args();
+			flow_rss = true;
+			nfccmd.rss_context = get_u32(ctx->argp[3], 0);
+		} else if (ctx->argc != 2) {
+			exit_bad_args();
+		}
+
+		rx_fhash_get = rxflow_str_to_type(ctx->argp[1]);
+		if (!rx_fhash_get)
+			exit_bad_args();
+
+		nfccmd.cmd = ETHTOOL_GRXFH;
+		nfccmd.flow_type = rx_fhash_get;
+		if (flow_rss)
+			nfccmd.flow_type |= FLOW_RSS;
+		err = send_ioctl(ctx, &nfccmd);
+		if (err < 0) {
+			perror("Cannot get RX network flow hashing options");
+		} else {
+			if (flow_rss)
+				fprintf(stdout, "For RSS context %u:\n",
+					nfccmd.rss_context);
+			dump_rxfhash(rx_fhash_get, nfccmd.data);
+		}
+	} else if (ctx->argc == 2 && !strcmp(ctx->argp[0], "rule")) {
+		int rx_class_rule_get =
+			get_uint_range(ctx->argp[1], 0, INT_MAX);
+
+		err = rxclass_rule_get(ctx, rx_class_rule_get);
+		if (err < 0)
+			fprintf(stderr, "Cannot get RX classification rule\n");
+	} else if (ctx->argc == 0) {
+		nfccmd.cmd = ETHTOOL_GRXRINGS;
+		err = send_ioctl(ctx, &nfccmd);
+		if (err < 0)
+			perror("Cannot get RX rings");
+		else
+			fprintf(stdout, "%d RX rings available\n",
+				(int)nfccmd.data);
+
+		err = rxclass_rule_getall(ctx);
+		if (err < 0)
+			fprintf(stderr, "RX classification rule retrieval failed\n");
+
+	} else {
+		exit_bad_args();
+	}
+
+	return err ? 1 : 0;
+}
+
+static void print_indir_table(struct cmd_context *ctx,
+			      struct ethtool_rxnfc *ring_count,
+			      u32 indir_size, u32 *indir)
+{
+	u32 i;
+
+	printf("RX flow hash indirection table for %s with %llu RX ring(s):\n",
+	       ctx->devname, ring_count->data);
+
+	if (!indir_size)
+		printf("Operation not supported\n");
+
+	for (i = 0; i < indir_size; i++) {
+		if (i % 8 == 0)
+			printf("%5u: ", i);
+		printf(" %5u", indir[i]);
+		if (i % 8 == 7 || i == indir_size - 1)
+			fputc('\n', stdout);
+	}
+}
+
+static int do_grxfhindir(struct cmd_context *ctx,
+			 struct ethtool_rxnfc *ring_count)
+{
+	struct ethtool_rxfh_indir indir_head;
+	struct ethtool_rxfh_indir *indir;
+	int err;
+
+	indir_head.cmd = ETHTOOL_GRXFHINDIR;
+	indir_head.size = 0;
+	err = send_ioctl(ctx, &indir_head);
+	if (err < 0) {
+		perror("Cannot get RX flow hash indirection table size");
+		return 1;
+	}
+
+	indir = malloc(sizeof(*indir) +
+		       indir_head.size * sizeof(*indir->ring_index));
+	if (!indir) {
+		perror("Cannot allocate memory for indirection table");
+		return 1;
+	}
+
+	indir->cmd = ETHTOOL_GRXFHINDIR;
+	indir->size = indir_head.size;
+	err = send_ioctl(ctx, indir);
+	if (err < 0) {
+		perror("Cannot get RX flow hash indirection table");
+		free(indir);
+		return 1;
+	}
+
+	print_indir_table(ctx, ring_count, indir->size, indir->ring_index);
+
+	free(indir);
+	return 0;
+}
+
+static int do_grxfh(struct cmd_context *ctx)
+{
+	struct ethtool_gstrings *hfuncs = NULL;
+	struct ethtool_rxfh rss_head = {0};
+	struct ethtool_rxnfc ring_count;
+	struct ethtool_rxfh *rss;
+	u32 rss_context = 0;
+	u32 i, indir_bytes;
+	int arg_num = 0;
+	char *hkey;
+	int err;
+
+	while (arg_num < ctx->argc) {
+		if (!strcmp(ctx->argp[arg_num], "context")) {
+			++arg_num;
+			rss_context = get_int_range(ctx->argp[arg_num], 0, 1,
+						    ETH_RXFH_CONTEXT_ALLOC - 1);
+			++arg_num;
+		} else {
+			exit_bad_args();
+		}
+	}
+
+	ring_count.cmd = ETHTOOL_GRXRINGS;
+	err = send_ioctl(ctx, &ring_count);
+	if (err < 0) {
+		perror("Cannot get RX ring count");
+		return 1;
+	}
+
+	rss_head.cmd = ETHTOOL_GRSSH;
+	rss_head.rss_context = rss_context;
+	err = send_ioctl(ctx, &rss_head);
+	if (err < 0 && errno == EOPNOTSUPP && !rss_context) {
+		return do_grxfhindir(ctx, &ring_count);
+	} else if (err < 0) {
+		perror("Cannot get RX flow hash indir size and/or key size");
+		return 1;
+	}
+
+	rss = calloc(1, sizeof(*rss) +
+			rss_head.indir_size * sizeof(rss_head.rss_config[0]) +
+			rss_head.key_size);
+	if (!rss) {
+		perror("Cannot allocate memory for RX flow hash config");
+		return 1;
+	}
+
+	rss->cmd = ETHTOOL_GRSSH;
+	rss->rss_context = rss_context;
+	rss->indir_size = rss_head.indir_size;
+	rss->key_size = rss_head.key_size;
+	err = send_ioctl(ctx, rss);
+	if (err < 0) {
+		perror("Cannot get RX flow hash configuration");
+		free(rss);
+		return 1;
+	}
+
+	print_indir_table(ctx, &ring_count, rss->indir_size, rss->rss_config);
+
+	indir_bytes = rss->indir_size * sizeof(rss->rss_config[0]);
+	hkey = ((char *)rss->rss_config + indir_bytes);
+
+	printf("RSS hash key:\n");
+	if (!rss->key_size)
+		printf("Operation not supported\n");
+
+	for (i = 0; i < rss->key_size; i++) {
+		if (i == (rss->key_size - 1))
+			printf("%02x\n", (u8) hkey[i]);
+		else
+			printf("%02x:", (u8) hkey[i]);
+	}
+
+	printf("RSS hash function:\n");
+	if (!rss->hfunc) {
+		printf("    Operation not supported\n");
+		goto out;
+	}
+
+	hfuncs = get_stringset(ctx, ETH_SS_RSS_HASH_FUNCS, 0, 1);
+	if (!hfuncs) {
+		perror("Cannot get hash functions names");
+		free(rss);
+		return 1;
+	}
+
+	for (i = 0; i < hfuncs->len; i++)
+		printf("    %s: %s\n",
+		       (const char *)hfuncs->data + i * ETH_GSTRING_LEN,
+		       (rss->hfunc & (1 << i)) ? "on" : "off");
+
+out:
+	free(hfuncs);
+	free(rss);
+	return 0;
+}
+
+static int fill_indir_table(u32 *indir_size, u32 *indir, int rxfhindir_default,
+			    int rxfhindir_start, int rxfhindir_equal,
+			    char **rxfhindir_weight, u32 num_weights)
+{
+	u32 i;
+
+	if (rxfhindir_equal) {
+		for (i = 0; i < *indir_size; i++)
+			indir[i] = rxfhindir_start + (i % rxfhindir_equal);
+	} else if (rxfhindir_weight) {
+		u32 j, weight, sum = 0, partial = 0;
+
+		for (j = 0; j < num_weights; j++) {
+			weight = get_u32(rxfhindir_weight[j], 0);
+			sum += weight;
+		}
+
+		if (sum == 0) {
+			fprintf(stderr,
+				"At least one weight must be non-zero\n");
+			return 2;
+		}
+
+		if (sum > *indir_size) {
+			fprintf(stderr,
+				"Total weight exceeds the size of the "
+				"indirection table\n");
+			return 2;
+		}
+
+		j = -1;
+		for (i = 0; i < *indir_size; i++) {
+			while (i >= (*indir_size) * partial / sum) {
+				j += 1;
+				weight = get_u32(rxfhindir_weight[j], 0);
+				partial += weight;
+			}
+			indir[i] = rxfhindir_start + j;
+		}
+	} else if (rxfhindir_default) {
+		/* "*indir_size == 0" ==> reset indir to default */
+		*indir_size = 0;
+	} else {
+		*indir_size = ETH_RXFH_INDIR_NO_CHANGE;
+	}
+
+	return 0;
+}
+
+static int do_srxfhindir(struct cmd_context *ctx, int rxfhindir_default,
+			 int rxfhindir_start, int rxfhindir_equal,
+			 char **rxfhindir_weight, u32 num_weights)
+{
+	struct ethtool_rxfh_indir indir_head;
+	struct ethtool_rxfh_indir *indir;
+	int err;
+
+	indir_head.cmd = ETHTOOL_GRXFHINDIR;
+	indir_head.size = 0;
+	err = send_ioctl(ctx, &indir_head);
+	if (err < 0) {
+		perror("Cannot get RX flow hash indirection table size");
+		return 1;
+	}
+
+	indir = malloc(sizeof(*indir) +
+		       indir_head.size * sizeof(*indir->ring_index));
+
+	if (!indir) {
+		perror("Cannot allocate memory for indirection table");
+		return 1;
+	}
+
+	indir->cmd = ETHTOOL_SRXFHINDIR;
+	indir->size = indir_head.size;
+
+	if (fill_indir_table(&indir->size, indir->ring_index,
+			     rxfhindir_default, rxfhindir_start,
+			     rxfhindir_equal, rxfhindir_weight, num_weights)) {
+		free(indir);
+		return 1;
+	}
+
+	err = send_ioctl(ctx, indir);
+	if (err < 0) {
+		perror("Cannot set RX flow hash indirection table");
+		free(indir);
+		return 1;
+	}
+
+	free(indir);
+	return 0;
+}
+
+static int do_srxfh(struct cmd_context *ctx)
+{
+	struct ethtool_rxfh rss_head = {0};
+	struct ethtool_rxfh *rss = NULL;
+	struct ethtool_rxnfc ring_count;
+	int rxfhindir_equal = 0, rxfhindir_default = 0, rxfhindir_start = 0;
+	struct ethtool_gstrings *hfuncs = NULL;
+	char **rxfhindir_weight = NULL;
+	char *rxfhindir_key = NULL;
+	char *req_hfunc_name = NULL;
+	char *hfunc_name = NULL;
+	char *hkey = NULL;
+	int err = 0;
+	int i;
+	u32 arg_num = 0, indir_bytes = 0;
+	u32 req_hfunc = 0;
+	u32 entry_size = sizeof(rss_head.rss_config[0]);
+	u32 num_weights = 0;
+	u32 rss_context = 0;
+	int delete = 0;
+
+	if (ctx->argc < 1)
+		exit_bad_args();
+
+	while (arg_num < ctx->argc) {
+		if (!strcmp(ctx->argp[arg_num], "equal")) {
+			++arg_num;
+			rxfhindir_equal = get_int_range(ctx->argp[arg_num],
+							0, 1, INT_MAX);
+			++arg_num;
+		} else if (!strcmp(ctx->argp[arg_num], "start")) {
+			++arg_num;
+			rxfhindir_start = get_int_range(ctx->argp[arg_num],
+							0, 0, INT_MAX);
+			++arg_num;
+		} else if (!strcmp(ctx->argp[arg_num], "weight")) {
+			++arg_num;
+			rxfhindir_weight = ctx->argp + arg_num;
+			while (arg_num < ctx->argc &&
+			       isdigit((unsigned char)ctx->argp[arg_num][0])) {
+				++arg_num;
+				++num_weights;
+			}
+			if (!num_weights)
+				exit_bad_args();
+		} else if (!strcmp(ctx->argp[arg_num], "hkey")) {
+			++arg_num;
+			rxfhindir_key = ctx->argp[arg_num];
+			if (!rxfhindir_key)
+				exit_bad_args();
+			++arg_num;
+		} else if (!strcmp(ctx->argp[arg_num], "default")) {
+			++arg_num;
+			rxfhindir_default = 1;
+		} else if (!strcmp(ctx->argp[arg_num], "hfunc")) {
+			++arg_num;
+			req_hfunc_name = ctx->argp[arg_num];
+			if (!req_hfunc_name)
+				exit_bad_args();
+			++arg_num;
+		} else if (!strcmp(ctx->argp[arg_num], "context")) {
+			++arg_num;
+			if(!strcmp(ctx->argp[arg_num], "new"))
+				rss_context = ETH_RXFH_CONTEXT_ALLOC;
+			else
+				rss_context = get_int_range(
+						ctx->argp[arg_num], 0, 1,
+						ETH_RXFH_CONTEXT_ALLOC - 1);
+			++arg_num;
+		} else if (!strcmp(ctx->argp[arg_num], "delete")) {
+			++arg_num;
+			delete = 1;
+		} else {
+			exit_bad_args();
+		}
+	}
+
+	if (rxfhindir_equal && rxfhindir_weight) {
+		fprintf(stderr,
+			"Equal and weight options are mutually exclusive\n");
+		return 1;
+	}
+
+	if (rxfhindir_equal && rxfhindir_default) {
+		fprintf(stderr,
+			"Equal and default options are mutually exclusive\n");
+		return 1;
+	}
+
+	if (rxfhindir_weight && rxfhindir_default) {
+		fprintf(stderr,
+			"Weight and default options are mutually exclusive\n");
+		return 1;
+	}
+
+	if (rxfhindir_start && rxfhindir_default) {
+		fprintf(stderr,
+			"Start and default options are mutually exclusive\n");
+		return 1;
+	}
+
+	if (rxfhindir_start && !(rxfhindir_equal || rxfhindir_weight)) {
+		fprintf(stderr,
+			"Start must be used with equal or weight options\n");
+		return 1;
+	}
+
+	if (rxfhindir_default && rss_context) {
+		fprintf(stderr,
+			"Default and context options are mutually exclusive\n");
+		return 1;
+	}
+
+	if (delete && !rss_context) {
+		fprintf(stderr, "Delete option requires context option\n");
+		return 1;
+	}
+
+	if (delete && rxfhindir_weight) {
+		fprintf(stderr,
+			"Delete and weight options are mutually exclusive\n");
+		return 1;
+	}
+
+	if (delete && rxfhindir_equal) {
+		fprintf(stderr,
+			"Delete and equal options are mutually exclusive\n");
+		return 1;
+	}
+
+	if (delete && rxfhindir_default) {
+		fprintf(stderr,
+			"Delete and default options are mutually exclusive\n");
+		return 1;
+	}
+
+	if (delete && rxfhindir_key) {
+		fprintf(stderr,
+			"Delete and hkey options are mutually exclusive\n");
+		return 1;
+	}
+
+	ring_count.cmd = ETHTOOL_GRXRINGS;
+	err = send_ioctl(ctx, &ring_count);
+	if (err < 0) {
+		perror("Cannot get RX ring count");
+		return 1;
+	}
+
+	rss_head.cmd = ETHTOOL_GRSSH;
+	err = send_ioctl(ctx, &rss_head);
+	if (err < 0 && errno == EOPNOTSUPP && !rxfhindir_key &&
+	    !req_hfunc_name && !rss_context) {
+		return do_srxfhindir(ctx, rxfhindir_default, rxfhindir_start,
+				     rxfhindir_equal, rxfhindir_weight,
+				     num_weights);
+	} else if (err < 0) {
+		perror("Cannot get RX flow hash indir size and key size");
+		return 1;
+	}
+
+	if (rxfhindir_key) {
+		err = parse_hkey(&hkey, rss_head.key_size,
+				 rxfhindir_key);
+		if (err)
+			return err;
+	}
+
+	if (rxfhindir_equal || rxfhindir_weight)
+		indir_bytes = rss_head.indir_size * entry_size;
+
+	if (rss_head.hfunc && req_hfunc_name) {
+		hfuncs = get_stringset(ctx, ETH_SS_RSS_HASH_FUNCS, 0, 1);
+		if (!hfuncs) {
+			perror("Cannot get hash functions names");
+			err = 1;
+			goto free;
+		}
+
+		for (i = 0; i < hfuncs->len && !req_hfunc ; i++) {
+			hfunc_name = (char *)(hfuncs->data +
+					      i * ETH_GSTRING_LEN);
+			if (!strncmp(hfunc_name, req_hfunc_name,
+				     ETH_GSTRING_LEN))
+				req_hfunc = (u32)1 << i;
+		}
+
+		if (!req_hfunc) {
+			fprintf(stderr,
+				"Unknown hash function: %s\n", req_hfunc_name);
+			err = 1;
+			goto free;
+		}
+	}
+
+	rss = calloc(1, sizeof(*rss) + indir_bytes + rss_head.key_size);
+	if (!rss) {
+		perror("Cannot allocate memory for RX flow hash config");
+		err = 1;
+		goto free;
+	}
+	rss->cmd = ETHTOOL_SRSSH;
+	rss->rss_context = rss_context;
+	rss->hfunc = req_hfunc;
+	if (delete) {
+		rss->indir_size = rss->key_size = 0;
+	} else {
+		rss->indir_size = rss_head.indir_size;
+		rss->key_size = rss_head.key_size;
+		if (fill_indir_table(&rss->indir_size, rss->rss_config,
+				     rxfhindir_default, rxfhindir_start,
+				     rxfhindir_equal, rxfhindir_weight,
+				     num_weights)) {
+			err = 1;
+			goto free;
+		}
+	}
+
+	if (hkey)
+		memcpy((char *)rss->rss_config + indir_bytes,
+		       hkey, rss->key_size);
+	else
+		rss->key_size = 0;
+
+	err = send_ioctl(ctx, rss);
+	if (err < 0) {
+		perror("Cannot set RX flow hash configuration");
+		err = 1;
+	} else if (rss_context == ETH_RXFH_CONTEXT_ALLOC) {
+		printf("New RSS context is %d\n", rss->rss_context);
+	}
+
+free:
+	free(hkey);
+	free(rss);
+	free(hfuncs);
+	return err;
+}
+
+static int do_flash(struct cmd_context *ctx)
+{
+	char *flash_file;
+	int flash_region;
+	struct ethtool_flash efl;
+	int err;
+
+	if (ctx->argc < 1 || ctx->argc > 2)
+		exit_bad_args();
+	flash_file = ctx->argp[0];
+	if (ctx->argc == 2) {
+		flash_region = strtol(ctx->argp[1], NULL, 0);
+		if (flash_region < 0)
+			exit_bad_args();
+	} else {
+		flash_region = -1;
+	}
+
+	if (strlen(flash_file) > ETHTOOL_FLASH_MAX_FILENAME - 1) {
+		fprintf(stdout, "Filename too long\n");
+		return 99;
+	}
+
+	efl.cmd = ETHTOOL_FLASHDEV;
+	strcpy(efl.data, flash_file);
+
+	if (flash_region < 0)
+		efl.region = ETHTOOL_FLASH_ALL_REGIONS;
+	else
+		efl.region = flash_region;
+
+	err = send_ioctl(ctx, &efl);
+	if (err < 0)
+		perror("Flashing failed");
+
+	return err;
+}
+
+static int do_permaddr(struct cmd_context *ctx)
+{
+	int i, err;
+	struct ethtool_perm_addr *epaddr;
+
+	epaddr = malloc(sizeof(struct ethtool_perm_addr) + MAX_ADDR_LEN);
+	if (!epaddr) {
+		perror("Cannot allocate memory for operation");
+		return 1;
+	}
+
+	epaddr->cmd = ETHTOOL_GPERMADDR;
+	epaddr->size = MAX_ADDR_LEN;
+
+	err = send_ioctl(ctx, epaddr);
+	if (err < 0)
+		perror("Cannot read permanent address");
+	else {
+		printf("Permanent address:");
+		for (i = 0; i < epaddr->size; i++)
+			printf("%c%02x", (i == 0) ? ' ' : ':',
+			       epaddr->data[i]);
+		printf("\n");
+	}
+	free(epaddr);
+
+	return err;
+}
+
+static bool flow_type_is_ntuple_supported(__u32 flow_type)
+{
+	switch (flow_type) {
+	case TCP_V4_FLOW:
+	case UDP_V4_FLOW:
+	case SCTP_V4_FLOW:
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+	case IPV4_USER_FLOW:
+	case ETHER_FLOW:
+		return true;
+	default:
+		return false;
+	}
+}
+
+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_ANY)
+		return -1;
+
+	/* destination MAC address in L3/L4 rules is not supported by ntuple */
+	if (fsp->flow_type & FLOW_MAC_EXT)
+		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;
+
+	/* IPv6 flow types are not supported by ntuple */
+	if (!flow_type_is_ntuple_supported(fsp->flow_type & ~FLOW_EXT))
+		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]);
+		}
+	}
+
+	/* Mask out the extended bit, because ntuple does not know it! */
+	ntuple->flow_type &= ~FLOW_EXT;
+
+	return 0;
+}
+
+static int do_srxntuple(struct cmd_context *ctx,
+			struct ethtool_rx_flow_spec *rx_rule_fs)
+{
+	struct ethtool_rx_ntuple ntuplecmd;
+	struct ethtool_value eval;
+	int err;
+
+	/* attempt to convert the flow classifier to an ntuple classifier */
+	err = flow_spec_to_ntuple(rx_rule_fs, &ntuplecmd.fs);
+	if (err)
+		return -1;
+
+	/*
+	 * 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;
+	err = send_ioctl(ctx, &eval);
+	if (err || !(eval.data & ETH_FLAG_NTUPLE))
+		return -1;
+
+	/* send rule via N-tuple */
+	ntuplecmd.cmd = ETHTOOL_SRXNTUPLE;
+	err = send_ioctl(ctx, &ntuplecmd);
+
+	/*
+	 * Display error only if response 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 < 0) {
+		if (errno != EOPNOTSUPP)
+			perror("Cannot add new rule via N-tuple");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int do_writefwdump(struct ethtool_dump *dump, const char *dump_file)
+{
+	int err = 0;
+	FILE *f;
+	size_t bytes;
+
+	f = fopen(dump_file, "wb+");
+
+	if (!f) {
+		fprintf(stderr, "Can't open file %s: %s\n",
+			dump_file, strerror(errno));
+		return 1;
+	}
+	bytes = fwrite(dump->data, 1, dump->len, f);
+	if (bytes != dump->len) {
+		fprintf(stderr, "Can not write all of dump data\n");
+		err = 1;
+	}
+	if (fclose(f)) {
+		fprintf(stderr, "Can't close file %s: %s\n",
+			dump_file, strerror(errno));
+		err = 1;
+	}
+	return err;
+}
+
+static int do_getfwdump(struct cmd_context *ctx)
+{
+	u32 dump_flag;
+	char *dump_file;
+	int err;
+	struct ethtool_dump edata;
+	struct ethtool_dump *data;
+
+	if (ctx->argc == 2 && !strcmp(ctx->argp[0], "data")) {
+		dump_flag = ETHTOOL_GET_DUMP_DATA;
+		dump_file = ctx->argp[1];
+	} else if (ctx->argc == 0) {
+		dump_flag = 0;
+		dump_file = NULL;
+	} else {
+		exit_bad_args();
+	}
+
+	edata.cmd = ETHTOOL_GET_DUMP_FLAG;
+
+	err = send_ioctl(ctx, &edata);
+	if (err < 0) {
+		perror("Can not get dump level\n");
+		return 1;
+	}
+	if (dump_flag != ETHTOOL_GET_DUMP_DATA) {
+		fprintf(stdout, "flag: %u, version: %u, length: %u\n",
+			edata.flag, edata.version, edata.len);
+		return 0;
+	}
+	data = calloc(1, offsetof(struct ethtool_dump, data) + edata.len);
+	if (!data) {
+		perror("Can not allocate enough memory\n");
+		return 1;
+	}
+	data->cmd = ETHTOOL_GET_DUMP_DATA;
+	data->len = edata.len;
+	err = send_ioctl(ctx, data);
+	if (err < 0) {
+		perror("Can not get dump data\n");
+		err = 1;
+		goto free;
+	}
+	err = do_writefwdump(data, dump_file);
+free:
+	free(data);
+	return err;
+}
+
+static int do_setfwdump(struct cmd_context *ctx)
+{
+	u32 dump_flag;
+	int err;
+	struct ethtool_dump dump;
+
+	if (ctx->argc != 1)
+		exit_bad_args();
+	dump_flag = get_u32(ctx->argp[0], 0);
+
+	dump.cmd = ETHTOOL_SET_DUMP;
+	dump.flag = dump_flag;
+	err = send_ioctl(ctx, &dump);
+	if (err < 0) {
+		perror("Can not set dump level\n");
+		return 1;
+	}
+	return 0;
+}
+
+static int do_gprivflags(struct cmd_context *ctx)
+{
+	struct ethtool_gstrings *strings;
+	struct ethtool_value flags;
+	unsigned int i;
+	int max_len = 0, cur_len, rc;
+
+	if (ctx->argc != 0)
+		exit_bad_args();
+
+	strings = get_stringset(ctx, ETH_SS_PRIV_FLAGS,
+				offsetof(struct ethtool_drvinfo, n_priv_flags),
+				1);
+	if (!strings) {
+		perror("Cannot get private flag names");
+		return 1;
+	}
+	if (strings->len == 0) {
+		fprintf(stderr, "No private flags defined\n");
+		rc = 1;
+		goto err;
+	}
+	if (strings->len > 32) {
+		/* ETHTOOL_GPFLAGS can only cover 32 flags */
+		fprintf(stderr, "Only showing first 32 private flags\n");
+		strings->len = 32;
+	}
+
+	flags.cmd = ETHTOOL_GPFLAGS;
+	if (send_ioctl(ctx, &flags)) {
+		perror("Cannot get private flags");
+		rc = 1;
+		goto err;
+	}
+
+	/* Find longest string and align all strings accordingly */
+	for (i = 0; i < strings->len; i++) {
+		cur_len = strlen((const char *)strings->data +
+				 i * ETH_GSTRING_LEN);
+		if (cur_len > max_len)
+			max_len = cur_len;
+	}
+
+	printf("Private flags for %s:\n", ctx->devname);
+	for (i = 0; i < strings->len; i++)
+		printf("%-*s: %s\n",
+		       max_len,
+		       (const char *)strings->data + i * ETH_GSTRING_LEN,
+		       (flags.data & (1U << i)) ? "on" : "off");
+
+	rc = 0;
+
+err:
+	free(strings);
+	return rc;
+}
+
+static int do_sprivflags(struct cmd_context *ctx)
+{
+	struct ethtool_gstrings *strings;
+	struct cmdline_info *cmdline;
+	struct ethtool_value flags;
+	u32 wanted_flags = 0, seen_flags = 0;
+	int any_changed, rc;
+	unsigned int i;
+
+	strings = get_stringset(ctx, ETH_SS_PRIV_FLAGS,
+				offsetof(struct ethtool_drvinfo, n_priv_flags),
+				1);
+	if (!strings) {
+		perror("Cannot get private flag names");
+		return 1;
+	}
+	if (strings->len == 0) {
+		fprintf(stderr, "No private flags defined\n");
+		rc = 1;
+		goto err;
+	}
+	if (strings->len > 32) {
+		/* ETHTOOL_{G,S}PFLAGS can only cover 32 flags */
+		fprintf(stderr, "Only setting first 32 private flags\n");
+		strings->len = 32;
+	}
+
+	cmdline = calloc(strings->len, sizeof(*cmdline));
+	if (!cmdline) {
+		perror("Cannot parse arguments");
+		rc = 1;
+		goto err;
+	}
+	for (i = 0; i < strings->len; i++) {
+		cmdline[i].name = ((const char *)strings->data +
+				   i * ETH_GSTRING_LEN);
+		cmdline[i].type = CMDL_FLAG;
+		cmdline[i].wanted_val = &wanted_flags;
+		cmdline[i].flag_val = 1U << i;
+		cmdline[i].seen_val = &seen_flags;
+	}
+	parse_generic_cmdline(ctx, &any_changed, cmdline, strings->len);
+	free(cmdline);
+
+	flags.cmd = ETHTOOL_GPFLAGS;
+	if (send_ioctl(ctx, &flags)) {
+		perror("Cannot get private flags");
+		rc = 1;
+		goto err;
+	}
+
+	flags.cmd = ETHTOOL_SPFLAGS;
+	flags.data = (flags.data & ~seen_flags) | wanted_flags;
+	if (send_ioctl(ctx, &flags)) {
+		perror("Cannot set private flags");
+		rc = 1;
+		goto err;
+	}
+
+	rc = 0;
+err:
+	free(strings);
+	return rc;
+}
+
+static int do_tsinfo(struct cmd_context *ctx)
+{
+	struct ethtool_ts_info info;
+
+	if (ctx->argc != 0)
+		exit_bad_args();
+
+	fprintf(stdout, "Time stamping parameters for %s:\n", ctx->devname);
+	info.cmd = ETHTOOL_GET_TS_INFO;
+	if (send_ioctl(ctx, &info)) {
+		perror("Cannot get device time stamping settings");
+		return -1;
+	}
+	dump_tsinfo(&info);
+	return 0;
+}
+
+static int do_getmodule(struct cmd_context *ctx)
+{
+	struct ethtool_modinfo modinfo;
+	struct ethtool_eeprom *eeprom;
+	u32 geeprom_offset = 0;
+	u32 geeprom_length = -1;
+	int geeprom_changed = 0;
+	int geeprom_dump_raw = 0;
+	int geeprom_dump_hex = 0;
+	int err;
+
+	struct cmdline_info cmdline_geeprom[] = {
+		{ "offset", CMDL_U32, &geeprom_offset, NULL },
+		{ "length", CMDL_U32, &geeprom_length, NULL },
+		{ "raw", CMDL_BOOL, &geeprom_dump_raw, NULL },
+		{ "hex", CMDL_BOOL, &geeprom_dump_hex, NULL },
+	};
+
+	parse_generic_cmdline(ctx, &geeprom_changed,
+			      cmdline_geeprom, ARRAY_SIZE(cmdline_geeprom));
+
+	if (geeprom_dump_raw && geeprom_dump_hex) {
+		printf("Hex and raw dump cannot be specified together\n");
+		return 1;
+	}
+
+	modinfo.cmd = ETHTOOL_GMODULEINFO;
+	err = send_ioctl(ctx, &modinfo);
+	if (err < 0) {
+		perror("Cannot get module EEPROM information");
+		return 1;
+	}
+
+	if (geeprom_length == -1)
+		geeprom_length = modinfo.eeprom_len;
+
+	if (modinfo.eeprom_len < geeprom_offset + geeprom_length)
+		geeprom_length = modinfo.eeprom_len - geeprom_offset;
+
+	eeprom = calloc(1, sizeof(*eeprom)+geeprom_length);
+	if (!eeprom) {
+		perror("Cannot allocate memory for Module EEPROM data");
+		return 1;
+	}
+
+	eeprom->cmd = ETHTOOL_GMODULEEEPROM;
+	eeprom->len = geeprom_length;
+	eeprom->offset = geeprom_offset;
+	err = send_ioctl(ctx, eeprom);
+	if (err < 0) {
+		perror("Cannot get Module EEPROM data");
+		free(eeprom);
+		return 1;
+	}
+
+	/*
+	 * SFF-8079 EEPROM layout contains the memory available at A0 address on
+	 * the PHY EEPROM.
+	 * SFF-8472 defines a virtual extension of the EEPROM, where the
+	 * microcontroller on the SFP/SFP+ generates a page at the A2 address,
+	 * which contains data relative to optical diagnostics.
+	 * The current kernel implementation returns a blob, which contains:
+	 *  - ETH_MODULE_SFF_8079 => The A0 page only.
+	 *  - ETH_MODULE_SFF_8472 => The A0 and A2 page concatenated.
+	 */
+	if (geeprom_dump_raw) {
+		fwrite(eeprom->data, 1, eeprom->len, stdout);
+	} else {
+		if (eeprom->offset != 0  ||
+		    (eeprom->len != modinfo.eeprom_len)) {
+			geeprom_dump_hex = 1;
+		} else if (!geeprom_dump_hex) {
+			switch (modinfo.type) {
+#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
+			case ETH_MODULE_SFF_8079:
+				sff8079_show_all(eeprom->data);
+				break;
+			case ETH_MODULE_SFF_8472:
+				sff8079_show_all(eeprom->data);
+				sff8472_show_all(eeprom->data);
+				break;
+			case ETH_MODULE_SFF_8436:
+			case ETH_MODULE_SFF_8636:
+				sff8636_show_all(eeprom->data,
+						 modinfo.eeprom_len);
+				break;
+#endif
+			default:
+				geeprom_dump_hex = 1;
+				break;
+			}
+		}
+		if (geeprom_dump_hex)
+			dump_hex(stdout, eeprom->data,
+				 eeprom->len, eeprom->offset);
+	}
+
+	free(eeprom);
+
+	return 0;
+}
+
+static int do_geee(struct cmd_context *ctx)
+{
+	struct ethtool_eee eeecmd;
+
+	if (ctx->argc != 0)
+		exit_bad_args();
+
+	eeecmd.cmd = ETHTOOL_GEEE;
+	if (send_ioctl(ctx, &eeecmd)) {
+		perror("Cannot get EEE settings");
+		return 1;
+	}
+
+	fprintf(stdout, "EEE Settings for %s:\n", ctx->devname);
+	dump_eeecmd(&eeecmd);
+
+	return 0;
+}
+
+static int do_seee(struct cmd_context *ctx)
+{
+	int adv_c = -1, lpi_c = -1, lpi_time_c = -1, eee_c = -1;
+	int change = -1, change2 = 0;
+	struct ethtool_eee eeecmd;
+	struct cmdline_info cmdline_eee[] = {
+		{ "advertise",    CMDL_U32,  &adv_c,       &eeecmd.advertised },
+		{ "tx-lpi",       CMDL_BOOL, &lpi_c,   &eeecmd.tx_lpi_enabled },
+		{ "tx-timer",	  CMDL_U32,  &lpi_time_c, &eeecmd.tx_lpi_timer},
+		{ "eee",	  CMDL_BOOL, &eee_c,	   &eeecmd.eee_enabled},
+	};
+
+	if (ctx->argc == 0)
+		exit_bad_args();
+
+	parse_generic_cmdline(ctx, &change, cmdline_eee,
+			      ARRAY_SIZE(cmdline_eee));
+
+	eeecmd.cmd = ETHTOOL_GEEE;
+	if (send_ioctl(ctx, &eeecmd)) {
+		perror("Cannot get EEE settings");
+		return 1;
+	}
+
+	do_generic_set(cmdline_eee, ARRAY_SIZE(cmdline_eee), &change2);
+
+	if (change2) {
+		eeecmd.cmd = ETHTOOL_SEEE;
+		if (send_ioctl(ctx, &eeecmd)) {
+			perror("Cannot set EEE settings");
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int do_get_phy_tunable(struct cmd_context *ctx)
+{
+	int argc = ctx->argc;
+	char **argp = ctx->argp;
+
+	if (argc < 1)
+		exit_bad_args();
+
+	if (!strcmp(argp[0], "downshift")) {
+		struct {
+			struct ethtool_tunable ds;
+			u8 count;
+		} cont;
+
+		cont.ds.cmd = ETHTOOL_PHY_GTUNABLE;
+		cont.ds.id = ETHTOOL_PHY_DOWNSHIFT;
+		cont.ds.type_id = ETHTOOL_TUNABLE_U8;
+		cont.ds.len = 1;
+		if (send_ioctl(ctx, &cont.ds) < 0) {
+			perror("Cannot Get PHY downshift count");
+			return 87;
+		}
+		if (cont.count)
+			fprintf(stdout, "Downshift count: %d\n", cont.count);
+		else
+			fprintf(stdout, "Downshift disabled\n");
+	} else if (!strcmp(argp[0], "fast-link-down")) {
+		struct {
+			struct ethtool_tunable fld;
+			u8 msecs;
+		} cont;
+
+		cont.fld.cmd = ETHTOOL_PHY_GTUNABLE;
+		cont.fld.id = ETHTOOL_PHY_FAST_LINK_DOWN;
+		cont.fld.type_id = ETHTOOL_TUNABLE_U8;
+		cont.fld.len = 1;
+		if (send_ioctl(ctx, &cont.fld) < 0) {
+			perror("Cannot Get PHY Fast Link Down value");
+			return 87;
+		}
+
+		if (cont.msecs == ETHTOOL_PHY_FAST_LINK_DOWN_ON)
+			fprintf(stdout, "Fast Link Down enabled\n");
+		else if (cont.msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)
+			fprintf(stdout, "Fast Link Down disabled\n");
+		else
+			fprintf(stdout, "Fast Link Down enabled, %d msecs\n",
+				cont.msecs);
+	} else if (!strcmp(argp[0], "energy-detect-power-down")) {
+		struct {
+			struct ethtool_tunable ds;
+			u16 msecs;
+		} cont;
+
+		cont.ds.cmd = ETHTOOL_PHY_GTUNABLE;
+		cont.ds.id = ETHTOOL_PHY_EDPD;
+		cont.ds.type_id = ETHTOOL_TUNABLE_U16;
+		cont.ds.len = 2;
+		if (send_ioctl(ctx, &cont.ds) < 0) {
+			perror("Cannot Get PHY Energy Detect Power Down value");
+			return 87;
+		}
+
+		if (cont.msecs == ETHTOOL_PHY_EDPD_DISABLE)
+			fprintf(stdout, "Energy Detect Power Down: disabled\n");
+		else if (cont.msecs == ETHTOOL_PHY_EDPD_NO_TX)
+			fprintf(stdout,
+				"Energy Detect Power Down: enabled, TX disabled\n");
+		else
+			fprintf(stdout,
+				"Energy Detect Power Down: enabled, TX %u msecs\n",
+				cont.msecs);
+	} else {
+		exit_bad_args();
+	}
+
+	return 0;
+}
+
+static __u32 parse_reset(char *val, __u32 bitset, char *arg, __u32 *data)
+{
+	__u32 bitval = 0;
+	int i;
+
+	/* Check for component match */
+	for (i = 0; val[i] != '\0'; i++)
+		if (arg[i] != val[i])
+			return 0;
+
+	/* Check if component has -shared specified or not */
+	if (arg[i] == '\0')
+		bitval = bitset;
+	else if (!strcmp(arg+i, "-shared"))
+		bitval = bitset << ETH_RESET_SHARED_SHIFT;
+
+	if (bitval) {
+		*data |= bitval;
+		return 1;
+	}
+	return 0;
+}
+
+static int do_reset(struct cmd_context *ctx)
+{
+	struct ethtool_value resetinfo;
+	__u32 data;
+	int argc = ctx->argc;
+	char **argp = ctx->argp;
+	int i;
+
+	if (argc == 0)
+		exit_bad_args();
+
+	data = 0;
+
+	for (i = 0; i < argc; i++) {
+		if (!strcmp(argp[i], "flags")) {
+			__u32 flags;
+
+			i++;
+			if (i >= argc)
+				exit_bad_args();
+			flags = strtoul(argp[i], NULL, 0);
+			if (flags == 0)
+				exit_bad_args();
+			else
+				data |= flags;
+		} else if (parse_reset("mgmt", ETH_RESET_MGMT,
+				      argp[i], &data)) {
+		} else if (parse_reset("irq",  ETH_RESET_IRQ,
+				    argp[i], &data)) {
+		} else if (parse_reset("dma", ETH_RESET_DMA,
+				    argp[i], &data)) {
+		} else if (parse_reset("filter", ETH_RESET_FILTER,
+				    argp[i], &data)) {
+		} else if (parse_reset("offload", ETH_RESET_OFFLOAD,
+				    argp[i], &data)) {
+		} else if (parse_reset("mac", ETH_RESET_MAC,
+				    argp[i], &data)) {
+		} else if (parse_reset("phy", ETH_RESET_PHY,
+				    argp[i], &data)) {
+		} else if (parse_reset("ram", ETH_RESET_RAM,
+				    argp[i], &data)) {
+		} else if (parse_reset("ap", ETH_RESET_AP,
+				    argp[i], &data)) {
+		} else if (!strcmp(argp[i], "dedicated")) {
+			data |= ETH_RESET_DEDICATED;
+		} else if (!strcmp(argp[i], "all")) {
+			data |= ETH_RESET_ALL;
+		} else {
+			exit_bad_args();
+		}
+	}
+
+	resetinfo.cmd = ETHTOOL_RESET;
+	resetinfo.data = data;
+	fprintf(stdout, "ETHTOOL_RESET 0x%x\n", resetinfo.data);
+
+	if (send_ioctl(ctx, &resetinfo)) {
+		perror("Cannot issue ETHTOOL_RESET");
+		return 1;
+	}
+
+	fprintf(stdout, "Components reset:     0x%x\n", data & ~resetinfo.data);
+	if (resetinfo.data)
+		fprintf(stdout, "Components not reset: 0x%x\n", resetinfo.data);
+
+	return 0;
+}
+
+static int parse_named_bool(struct cmd_context *ctx, const char *name, u8 *on)
+{
+	if (ctx->argc < 2)
+		return 0;
+
+	if (strcmp(*ctx->argp, name))
+		return 0;
+
+	if (!strcmp(*(ctx->argp + 1), "on")) {
+		*on = 1;
+	} else if (!strcmp(*(ctx->argp + 1), "off")) {
+		*on = 0;
+	} else {
+		fprintf(stderr, "Invalid boolean\n");
+		exit_bad_args();
+	}
+
+	ctx->argc -= 2;
+	ctx->argp += 2;
+
+	return 1;
+}
+
+static int parse_named_uint(struct cmd_context *ctx,
+			    const char *name,
+			    unsigned long long *val,
+			    unsigned long long max)
+{
+	if (ctx->argc < 2)
+		return 0;
+
+	if (strcmp(*ctx->argp, name))
+		return 0;
+
+	*val = get_uint_range(*(ctx->argp + 1), 0, max);
+
+	ctx->argc -= 2;
+	ctx->argp += 2;
+
+	return 1;
+}
+
+static int parse_named_u8(struct cmd_context *ctx, const char *name, u8 *val)
+{
+	unsigned long long val1;
+	int ret;
+
+	ret = parse_named_uint(ctx, name, &val1, 0xff);
+	if (ret)
+		*val = val1;
+
+	return ret;
+}
+
+static int parse_named_u16(struct cmd_context *ctx, const char *name, u16 *val)
+{
+	unsigned long long val1;
+	int ret;
+
+	ret = parse_named_uint(ctx, name, &val1, 0xffff);
+	if (ret)
+		*val = val1;
+
+	return ret;
+}
+
+static int do_set_phy_tunable(struct cmd_context *ctx)
+{
+	int err = 0;
+	u8 ds_cnt = DOWNSHIFT_DEV_DEFAULT_COUNT;
+	u8 ds_changed = 0, ds_has_cnt = 0, ds_enable = 0;
+	u8 fld_changed = 0, fld_enable = 0;
+	u8 fld_msecs = ETHTOOL_PHY_FAST_LINK_DOWN_ON;
+	u8 edpd_changed = 0, edpd_enable = 0;
+	u16 edpd_tx_interval = ETHTOOL_PHY_EDPD_DFLT_TX_MSECS;
+
+	/* Parse arguments */
+	if (parse_named_bool(ctx, "downshift", &ds_enable)) {
+		ds_changed = 1;
+		ds_has_cnt = parse_named_u8(ctx, "count", &ds_cnt);
+	} else if (parse_named_bool(ctx, "fast-link-down", &fld_enable)) {
+		fld_changed = 1;
+		if (fld_enable)
+			parse_named_u8(ctx, "msecs", &fld_msecs);
+	} else if (parse_named_bool(ctx, "energy-detect-power-down",
+				    &edpd_enable)) {
+		edpd_changed = 1;
+		if (edpd_enable)
+			parse_named_u16(ctx, "msecs", &edpd_tx_interval);
+	} else {
+		exit_bad_args();
+	}
+
+	/* Validate parameters */
+	if (ds_changed) {
+		if (!ds_enable && ds_has_cnt) {
+			fprintf(stderr, "'count' may not be set when downshift "
+				        "is off.\n");
+			exit_bad_args();
+		}
+
+		if (ds_enable && ds_has_cnt && ds_cnt == 0) {
+			fprintf(stderr, "'count' may not be zero.\n");
+			exit_bad_args();
+		}
+
+		if (!ds_enable)
+			ds_cnt = DOWNSHIFT_DEV_DISABLE;
+	} else if (fld_changed) {
+		if (!fld_enable)
+			fld_msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF;
+		else if (fld_msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)
+			exit_bad_args();
+	} else if (edpd_changed) {
+		if (!edpd_enable)
+			edpd_tx_interval = ETHTOOL_PHY_EDPD_DISABLE;
+		else if (edpd_tx_interval == 0)
+			edpd_tx_interval = ETHTOOL_PHY_EDPD_NO_TX;
+		else if (edpd_tx_interval > ETHTOOL_PHY_EDPD_NO_TX) {
+			fprintf(stderr, "'msecs' max value is %d.\n",
+				(ETHTOOL_PHY_EDPD_NO_TX - 1));
+			exit_bad_args();
+		}
+	}
+
+	/* Do it */
+	if (ds_changed) {
+		struct {
+			struct ethtool_tunable ds;
+			u8 count;
+		} cont;
+
+		cont.ds.cmd = ETHTOOL_PHY_STUNABLE;
+		cont.ds.id = ETHTOOL_PHY_DOWNSHIFT;
+		cont.ds.type_id = ETHTOOL_TUNABLE_U8;
+		cont.ds.len = 1;
+		cont.count = ds_cnt;
+		err = send_ioctl(ctx, &cont.ds);
+		if (err < 0) {
+			perror("Cannot Set PHY downshift count");
+			err = 87;
+		}
+	} else if (fld_changed) {
+		struct {
+			struct ethtool_tunable fld;
+			u8 msecs;
+		} cont;
+
+		cont.fld.cmd = ETHTOOL_PHY_STUNABLE;
+		cont.fld.id = ETHTOOL_PHY_FAST_LINK_DOWN;
+		cont.fld.type_id = ETHTOOL_TUNABLE_U8;
+		cont.fld.len = 1;
+		cont.msecs = fld_msecs;
+		err = send_ioctl(ctx, &cont.fld);
+		if (err < 0) {
+			perror("Cannot Set PHY Fast Link Down value");
+			err = 87;
+		}
+	} else if (edpd_changed) {
+		struct {
+			struct ethtool_tunable fld;
+			u16 msecs;
+		} cont;
+
+		cont.fld.cmd = ETHTOOL_PHY_STUNABLE;
+		cont.fld.id = ETHTOOL_PHY_EDPD;
+		cont.fld.type_id = ETHTOOL_TUNABLE_U16;
+		cont.fld.len = 2;
+		cont.msecs = edpd_tx_interval;
+		err = send_ioctl(ctx, &cont.fld);
+		if (err < 0) {
+			perror("Cannot Set PHY Energy Detect Power Down");
+			err = 87;
+		}
+	}
+
+	return err;
+}
+
+static int fecmode_str_to_type(const char *str)
+{
+	if (!strcasecmp(str, "auto"))
+		return ETHTOOL_FEC_AUTO;
+	if (!strcasecmp(str, "off"))
+		return ETHTOOL_FEC_OFF;
+	if (!strcasecmp(str, "rs"))
+		return ETHTOOL_FEC_RS;
+	if (!strcasecmp(str, "baser"))
+		return ETHTOOL_FEC_BASER;
+
+	return 0;
+}
+
+static int do_gfec(struct cmd_context *ctx)
+{
+	struct ethtool_fecparam feccmd = { 0 };
+	int rv;
+
+	if (ctx->argc != 0)
+		exit_bad_args();
+
+	feccmd.cmd = ETHTOOL_GFECPARAM;
+	rv = send_ioctl(ctx, &feccmd);
+	if (rv != 0) {
+		perror("Cannot get FEC settings");
+		return rv;
+	}
+
+	fprintf(stdout, "FEC parameters for %s:\n", ctx->devname);
+	fprintf(stdout, "Configured FEC encodings:");
+	dump_fec(feccmd.fec);
+	fprintf(stdout, "\n");
+
+	fprintf(stdout, "Active FEC encoding:");
+	dump_fec(feccmd.active_fec);
+	fprintf(stdout, "\n");
+
+	return 0;
+}
+
+static int do_sfec(struct cmd_context *ctx)
+{
+	enum { ARG_NONE, ARG_ENCODING } state = ARG_NONE;
+	struct ethtool_fecparam feccmd;
+	int fecmode = 0, newmode;
+	int rv, i;
+
+	for (i = 0; i < ctx->argc; i++) {
+		if (!strcmp(ctx->argp[i], "encoding")) {
+			state = ARG_ENCODING;
+			continue;
+		}
+		if (state == ARG_ENCODING) {
+			newmode = fecmode_str_to_type(ctx->argp[i]);
+			if (!newmode)
+				exit_bad_args();
+			fecmode |= newmode;
+			continue;
+		}
+		exit_bad_args();
+	}
+
+	if (!fecmode)
+		exit_bad_args();
+
+	feccmd.cmd = ETHTOOL_SFECPARAM;
+	feccmd.fec = fecmode;
+	rv = send_ioctl(ctx, &feccmd);
+	if (rv != 0) {
+		perror("Cannot set FEC settings");
+		return rv;
+	}
+
+	return 0;
+}
+
+static int do_perqueue(struct cmd_context *ctx);
+
+#ifndef TEST_ETHTOOL
+int send_ioctl(struct cmd_context *ctx, void *cmd)
+{
+	ctx->ifr.ifr_data = cmd;
+	return ioctl(ctx->fd, SIOCETHTOOL, &ctx->ifr);
+}
+#endif
+
+static int show_usage(struct cmd_context *ctx);
+
+static const struct option {
+	const char *opts;
+	int want_device;
+	int (*func)(struct cmd_context *);
+	char *help;
+	char *opthelp;
+} args[] = {
+	{ "-s|--change", 1, do_sset, "Change generic options",
+	  "		[ speed %d ]\n"
+	  "		[ duplex half|full ]\n"
+	  "		[ port tp|aui|bnc|mii|fibre ]\n"
+	  "		[ mdix auto|on|off ]\n"
+	  "		[ autoneg on|off ]\n"
+	  "		[ advertise %x ]\n"
+	  "		[ phyad %d ]\n"
+	  "		[ xcvr internal|external ]\n"
+	  "		[ wol p|u|m|b|a|g|s|f|d... ]\n"
+	  "		[ sopass %x:%x:%x:%x:%x:%x ]\n"
+	  "		[ msglvl %d | msglvl type on|off ... ]\n" },
+	{ "-a|--show-pause", 1, do_gpause, "Show pause options" },
+	{ "-A|--pause", 1, do_spause, "Set pause options",
+	  "		[ autoneg on|off ]\n"
+	  "		[ rx on|off ]\n"
+	  "		[ tx on|off ]\n" },
+	{ "-c|--show-coalesce", 1, do_gcoalesce, "Show coalesce options" },
+	{ "-C|--coalesce", 1, do_scoalesce, "Set coalesce options",
+	  "		[adaptive-rx on|off]\n"
+	  "		[adaptive-tx on|off]\n"
+	  "		[rx-usecs N]\n"
+	  "		[rx-frames N]\n"
+	  "		[rx-usecs-irq N]\n"
+	  "		[rx-frames-irq N]\n"
+	  "		[tx-usecs N]\n"
+	  "		[tx-frames N]\n"
+	  "		[tx-usecs-irq N]\n"
+	  "		[tx-frames-irq N]\n"
+	  "		[stats-block-usecs N]\n"
+	  "		[pkt-rate-low N]\n"
+	  "		[rx-usecs-low N]\n"
+	  "		[rx-frames-low N]\n"
+	  "		[tx-usecs-low N]\n"
+	  "		[tx-frames-low N]\n"
+	  "		[pkt-rate-high N]\n"
+	  "		[rx-usecs-high N]\n"
+	  "		[rx-frames-high N]\n"
+	  "		[tx-usecs-high N]\n"
+	  "		[tx-frames-high N]\n"
+	  "		[sample-interval N]\n" },
+	{ "-g|--show-ring", 1, do_gring, "Query RX/TX ring parameters" },
+	{ "-G|--set-ring", 1, do_sring, "Set RX/TX ring parameters",
+	  "		[ rx N ]\n"
+	  "		[ rx-mini N ]\n"
+	  "		[ rx-jumbo N ]\n"
+	  "		[ tx N ]\n" },
+	{ "-k|--show-features|--show-offload", 1, do_gfeatures,
+	  "Get state of protocol offload and other features" },
+	{ "-K|--features|--offload", 1, do_sfeatures,
+	  "Set protocol offload and other features",
+	  "		FEATURE on|off ...\n" },
+	{ "-i|--driver", 1, do_gdrv, "Show driver information" },
+	{ "-d|--register-dump", 1, do_gregs, "Do a register dump",
+	  "		[ raw on|off ]\n"
+	  "		[ file FILENAME ]\n" },
+	{ "-e|--eeprom-dump", 1, do_geeprom, "Do a EEPROM dump",
+	  "		[ raw on|off ]\n"
+	  "		[ offset N ]\n"
+	  "		[ length N ]\n" },
+	{ "-E|--change-eeprom", 1, do_seeprom,
+	  "Change bytes in device EEPROM",
+	  "		[ magic N ]\n"
+	  "		[ offset N ]\n"
+	  "		[ length N ]\n"
+	  "		[ value N ]\n" },
+	{ "-r|--negotiate", 1, do_nway_rst, "Restart N-WAY negotiation" },
+	{ "-p|--identify", 1, do_phys_id,
+	  "Show visible port identification (e.g. blinking)",
+	  "               [ TIME-IN-SECONDS ]\n" },
+	{ "-t|--test", 1, do_test, "Execute adapter self test",
+	  "               [ online | offline | external_lb ]\n" },
+	{ "-S|--statistics", 1, do_gnicstats, "Show adapter statistics" },
+	{ "--phy-statistics", 1, do_gphystats,
+	  "Show phy statistics" },
+	{ "-n|-u|--show-nfc|--show-ntuple", 1, do_grxclass,
+	  "Show Rx network flow classification options or rules",
+	  "		[ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
+	  "tcp6|udp6|ah6|esp6|sctp6 [context %d] |\n"
+	  "		  rule %d ]\n" },
+	{ "-N|-U|--config-nfc|--config-ntuple", 1, do_srxclass,
+	  "Configure Rx network flow classification options or rules",
+	  "		rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|"
+	  "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... [context %d] |\n"
+	  "		flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4|"
+	  "ip6|tcp6|udp6|ah6|esp6|sctp6\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 IP-ADDRESS [m IP-ADDRESS] ]\n"
+	  "			[ dst-ip IP-ADDRESS [m IP-ADDRESS] ]\n"
+	  "			[ tos %d [m %x] ]\n"
+	  "			[ tclass %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"
+	  "			[ dst-mac %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n"
+	  "			[ action %d ] | [ vf %d queue %d ]\n"
+	  "			[ context %d ]\n"
+	  "			[ loc %d]] |\n"
+	  "		delete %d\n" },
+	{ "-T|--show-time-stamping", 1, do_tsinfo,
+	  "Show time stamping capabilities" },
+	{ "-x|--show-rxfh-indir|--show-rxfh", 1, do_grxfh,
+	  "Show Rx flow hash indirection table and/or RSS hash key",
+	  "		[ context %d ]\n" },
+	{ "-X|--set-rxfh-indir|--rxfh", 1, do_srxfh,
+	  "Set Rx flow hash indirection table and/or RSS hash key",
+	  "		[ context %d|new ]\n"
+	  "		[ equal N | weight W0 W1 ... | default ]\n"
+	  "		[ hkey %x:%x:%x:%x:%x:.... ]\n"
+	  "		[ hfunc FUNC ]\n"
+	  "		[ delete ]\n" },
+	{ "-f|--flash", 1, do_flash,
+	  "Flash firmware image from the specified file to a region on the device",
+	  "               FILENAME [ REGION-NUMBER-TO-FLASH ]\n" },
+	{ "-P|--show-permaddr", 1, do_permaddr,
+	  "Show permanent hardware address" },
+	{ "-w|--get-dump", 1, do_getfwdump,
+	  "Get dump flag, data",
+	  "		[ data FILENAME ]\n" },
+	{ "-W|--set-dump", 1, do_setfwdump,
+	  "Set dump flag of the device",
+	  "		N\n"},
+	{ "-l|--show-channels", 1, do_gchannels, "Query Channels" },
+	{ "-L|--set-channels", 1, do_schannels, "Set Channels",
+	  "               [ rx N ]\n"
+	  "               [ tx N ]\n"
+	  "               [ other N ]\n"
+	  "               [ combined N ]\n" },
+	{ "--show-priv-flags", 1, do_gprivflags, "Query private flags" },
+	{ "--set-priv-flags", 1, do_sprivflags, "Set private flags",
+	  "		FLAG on|off ...\n" },
+	{ "-m|--dump-module-eeprom|--module-info", 1, do_getmodule,
+	  "Query/Decode Module EEPROM information and optical diagnostics if available",
+	  "		[ raw on|off ]\n"
+	  "		[ hex on|off ]\n"
+	  "		[ offset N ]\n"
+	  "		[ length N ]\n" },
+	{ "--show-eee", 1, do_geee, "Show EEE settings"},
+	{ "--set-eee", 1, do_seee, "Set EEE settings",
+	  "		[ eee on|off ]\n"
+	  "		[ advertise %x ]\n"
+	  "		[ tx-lpi on|off ]\n"
+	  "		[ tx-timer %d ]\n"},
+	{ "--set-phy-tunable", 1, do_set_phy_tunable, "Set PHY tunable",
+	  "		[ downshift on|off [count N] ]\n"
+	  "		[ fast-link-down on|off [msecs N] ]\n"
+	  "		[ energy-detect-power-down on|off [msecs N] ]\n"},
+	{ "--get-phy-tunable", 1, do_get_phy_tunable, "Get PHY tunable",
+	  "		[ downshift ]\n"
+	  "		[ fast-link-down ]\n"
+	  "		[ energy-detect-power-down ]\n"},
+	{ "--reset", 1, do_reset, "Reset components",
+	  "		[ flags %x ]\n"
+	  "		[ mgmt ]\n"
+	  "		[ mgmt-shared ]\n"
+	  "		[ irq ]\n"
+	  "		[ irq-shared ]\n"
+	  "		[ dma ]\n"
+	  "		[ dma-shared ]\n"
+	  "		[ filter ]\n"
+	  "		[ filter-shared ]\n"
+	  "		[ offload ]\n"
+	  "		[ offload-shared ]\n"
+	  "		[ mac ]\n"
+	  "		[ mac-shared ]\n"
+	  "		[ phy ]\n"
+	  "		[ phy-shared ]\n"
+	  "		[ ram ]\n"
+	  "		[ ram-shared ]\n"
+	  "		[ ap ]\n"
+	  "		[ ap-shared ]\n"
+	  "		[ dedicated ]\n"
+	  "		[ all ]\n"},
+	{ "--show-fec", 1, do_gfec, "Show FEC settings"},
+	{ "--set-fec", 1, do_sfec, "Set FEC settings",
+	  "		[ encoding auto|off|rs|baser [...]]\n"},
+	{ "-Q|--per-queue", 1, do_perqueue, "Apply per-queue command."
+	  "The supported sub commands include --show-coalesce, --coalesce",
+	  "             [queue_mask %x] SUB_COMMAND\n"},
+	{ "-h|--help", 0, show_usage, "Show this help" },
+	{ "--version", 0, do_version, "Show version number" },
+	{}
+};
+
+static int show_usage(struct cmd_context *ctx maybe_unused)
+{
+	int i;
+
+	/* ethtool -h */
+	fprintf(stdout, PACKAGE " version " VERSION "\n");
+	fprintf(stdout,
+		"Usage:\n"
+		"        ethtool DEVNAME\t"
+		"Display standard information about device\n");
+	for (i = 0; args[i].opts; i++) {
+		fputs("        ethtool ", stdout);
+		fprintf(stdout, "%s %s\t%s\n",
+			args[i].opts,
+			args[i].want_device ? "DEVNAME" : "\t",
+			args[i].help);
+		if (args[i].opthelp)
+			fputs(args[i].opthelp, stdout);
+	}
+
+	return 0;
+}
+
+static int find_option(char *arg)
+{
+	const char *opt;
+	size_t len;
+	int k;
+
+	for (k = 0; args[k].opts; k++) {
+		opt = args[k].opts;
+		for (;;) {
+			len = strcspn(opt, "|");
+			if (strncmp(arg, opt, len) == 0 && arg[len] == 0)
+				return k;
+
+			if (opt[len] == 0)
+				break;
+			opt += len + 1;
+		}
+	}
+
+	return -1;
+}
+
+#define MAX(x, y) (x > y ? x : y)
+
+static int find_max_num_queues(struct cmd_context *ctx)
+{
+	struct ethtool_channels echannels;
+
+	echannels.cmd = ETHTOOL_GCHANNELS;
+	if (send_ioctl(ctx, &echannels))
+		return -1;
+
+	return MAX(echannels.rx_count, echannels.tx_count) +
+		echannels.combined_count;
+}
+
+static struct ethtool_per_queue_op *
+get_per_queue_coalesce(struct cmd_context *ctx, __u32 *queue_mask, int n_queues)
+{
+	struct ethtool_per_queue_op *per_queue_opt;
+
+	per_queue_opt = malloc(sizeof(*per_queue_opt) + n_queues *
+			sizeof(struct ethtool_coalesce));
+	if (!per_queue_opt)
+		return NULL;
+
+	memcpy(per_queue_opt->queue_mask, queue_mask,
+	       __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32) * sizeof(__u32));
+	per_queue_opt->cmd = ETHTOOL_PERQUEUE;
+	per_queue_opt->sub_command = ETHTOOL_GCOALESCE;
+	if (send_ioctl(ctx, per_queue_opt)) {
+		free(per_queue_opt);
+		perror("Cannot get device per queue parameters");
+		return NULL;
+	}
+
+	return per_queue_opt;
+}
+
+static void set_per_queue_coalesce(struct cmd_context *ctx,
+				   struct ethtool_per_queue_op *per_queue_opt,
+				   int n_queues)
+{
+	struct ethtool_coalesce ecoal;
+	DECLARE_COALESCE_OPTION_VARS();
+	struct cmdline_info cmdline_coalesce[] = COALESCE_CMDLINE_INFO(ecoal);
+	__u32 *queue_mask = per_queue_opt->queue_mask;
+	struct ethtool_coalesce *ecoal_q;
+	int gcoalesce_changed = 0;
+	int i, idx = 0;
+
+	parse_generic_cmdline(ctx, &gcoalesce_changed,
+			      cmdline_coalesce, ARRAY_SIZE(cmdline_coalesce));
+
+	ecoal_q = (struct ethtool_coalesce *)(per_queue_opt + 1);
+	for (i = 0; i < __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32); i++) {
+		int queue = i * 32;
+		__u32 mask = queue_mask[i];
+
+		while (mask > 0) {
+			if (mask & 0x1) {
+				int changed = 0;
+
+				memcpy(&ecoal, ecoal_q + idx,
+				       sizeof(struct ethtool_coalesce));
+				do_generic_set(cmdline_coalesce,
+					       ARRAY_SIZE(cmdline_coalesce),
+					       &changed);
+				if (!changed)
+					fprintf(stderr,
+						"Queue %d, no coalesce parameters changed\n",
+						queue);
+				memcpy(ecoal_q + idx, &ecoal,
+				       sizeof(struct ethtool_coalesce));
+				idx++;
+			}
+			mask = mask >> 1;
+			queue++;
+		}
+		if (idx == n_queues)
+			break;
+	}
+
+	per_queue_opt->cmd = ETHTOOL_PERQUEUE;
+	per_queue_opt->sub_command = ETHTOOL_SCOALESCE;
+
+	if (send_ioctl(ctx, per_queue_opt))
+		perror("Cannot set device per queue parameters");
+}
+
+static int do_perqueue(struct cmd_context *ctx)
+{
+	struct ethtool_per_queue_op *per_queue_opt;
+	__u32 queue_mask[__KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32)] = {0};
+	int i, n_queues = 0;
+
+	if (ctx->argc == 0)
+		exit_bad_args();
+
+	/*
+	 * The sub commands will be applied to
+	 * all queues if no queue_mask set
+	 */
+	if (strncmp(*ctx->argp, "queue_mask", 11)) {
+		n_queues = find_max_num_queues(ctx);
+		if (n_queues < 0) {
+			perror("Cannot get number of queues");
+			return -EFAULT;
+		} else if (n_queues > MAX_NUM_QUEUE) {
+			n_queues = MAX_NUM_QUEUE;
+		}
+		for (i = 0; i < n_queues / 32; i++)
+			queue_mask[i] = ~0;
+		if (n_queues % 32)
+			queue_mask[i] = (1 << (n_queues - i * 32)) - 1;
+		fprintf(stdout,
+			"The sub commands will be applied to all %d queues\n",
+			n_queues);
+	} else {
+		ctx->argc--;
+		ctx->argp++;
+		if (parse_hex_u32_bitmap(*ctx->argp, MAX_NUM_QUEUE,
+		    queue_mask)) {
+			fprintf(stdout, "Invalid queue mask\n");
+			return -1;
+		}
+		for (i = 0; i < __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32); i++) {
+			__u32 mask = queue_mask[i];
+
+			while (mask > 0) {
+				if (mask & 0x1)
+					n_queues++;
+				mask = mask >> 1;
+			}
+		}
+		ctx->argc--;
+		ctx->argp++;
+	}
+
+	i = find_option(ctx->argp[0]);
+	if (i < 0)
+		exit_bad_args();
+
+	if (strstr(args[i].opts, "--show-coalesce") != NULL) {
+		per_queue_opt = get_per_queue_coalesce(ctx, queue_mask,
+						       n_queues);
+		if (per_queue_opt == NULL) {
+			perror("Cannot get device per queue parameters");
+			return -EFAULT;
+		}
+		dump_per_queue_coalesce(per_queue_opt, queue_mask, n_queues);
+		free(per_queue_opt);
+	} else if (strstr(args[i].opts, "--coalesce") != NULL) {
+		ctx->argc--;
+		ctx->argp++;
+		per_queue_opt = get_per_queue_coalesce(ctx, queue_mask,
+						       n_queues);
+		if (per_queue_opt == NULL) {
+			perror("Cannot get device per queue parameters");
+			return -EFAULT;
+		}
+		set_per_queue_coalesce(ctx, per_queue_opt, n_queues);
+		free(per_queue_opt);
+	} else {
+		perror("The subcommand is not supported yet");
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+int main(int argc, char **argp)
+{
+	int (*func)(struct cmd_context *);
+	int want_device;
+	struct cmd_context ctx;
+	int k;
+
+	init_global_link_mode_masks();
+
+	/* Skip command name */
+	argp++;
+	argc--;
+
+	/* First argument must be either a valid option or a device
+	 * name to get settings for (which we don't expect to begin
+	 * with '-').
+	 */
+	if (argc == 0)
+		exit_bad_args();
+
+	k = find_option(*argp);
+	if (k >= 0) {
+		argp++;
+		argc--;
+		func = args[k].func;
+		want_device = args[k].want_device;
+		goto opt_found;
+	}
+	if ((*argp)[0] == '-')
+		exit_bad_args();
+	func = do_gset;
+	want_device = 1;
+
+opt_found:
+	if (want_device) {
+		ctx.devname = *argp++;
+		argc--;
+
+		if (ctx.devname == NULL)
+			exit_bad_args();
+		if (strlen(ctx.devname) >= IFNAMSIZ)
+			exit_bad_args();
+
+		/* Setup our control structures. */
+		memset(&ctx.ifr, 0, sizeof(ctx.ifr));
+		strcpy(ctx.ifr.ifr_name, ctx.devname);
+
+		/* Open control socket. */
+		ctx.fd = socket(AF_INET, SOCK_DGRAM, 0);
+		if (ctx.fd < 0)
+			ctx.fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+		if (ctx.fd < 0) {
+			perror("Cannot get control socket");
+			return 70;
+		}
+	} else {
+		ctx.fd = -1;
+	}
+
+	ctx.argc = argc;
+	ctx.argp = argp;
+
+	return func(&ctx);
+}
diff --git a/ethtool.spec.in b/ethtool.spec.in
new file mode 100644
index 0000000..9c01b07
--- /dev/null
+++ b/ethtool.spec.in
@@ -0,0 +1,40 @@
+Name		: @PACKAGE@
+Version		: @VERSION@
+Release		: 1
+Group		: Utilities
+
+Summary		: Settings tool for Ethernet and other network devices
+
+License		: GPL
+URL		: https://ftp.kernel.org/pub/software/network/ethtool/
+
+Buildroot	: %{_tmppath}/%{name}-%{version}
+Source		: %{name}-%{version}.tar.gz
+
+
+%description
+This utility allows querying and changing settings such as speed,
+port, auto-negotiation, PCI locations and checksum offload on many
+network devices, especially Ethernet devices.
+
+%prep
+%setup -q
+
+
+%build
+CFLAGS="${RPM_OPT_FLAGS}" ./configure --prefix=%{_prefix} --mandir=%{_mandir}
+make
+
+
+%install
+make install DESTDIR=${RPM_BUILD_ROOT}
+
+
+%files
+%defattr(-,root,root)
+%{_sbindir}/ethtool
+%{_mandir}/man8/ethtool.8*
+%doc AUTHORS COPYING NEWS README
+
+
+%changelog
diff --git a/fec.c b/fec.c
new file mode 100644
index 0000000..22bc09f
--- /dev/null
+++ b/fec.c
@@ -0,0 +1,220 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "internal.h"
+
+/* Macros and dump functions for the 32-bit "fec" driver registers */
+
+#define REG(_reg, _name, _val) \
+	printf("0x%.03x: %-44.44s 0x%.8x\n", _reg, _name, _val)
+
+#define FIELD(_name, _fmt, ...) \
+	printf("    %-47.47s " _fmt "\n", _name, ##__VA_ARGS__)
+
+static void fec_dump_reg_v1(int reg, u32 val)
+{
+	switch (reg) {
+	case 0x000: /* FEC_ECNTRL */
+	case 0x004: /* FEC_IEVENT */
+	case 0x008: /* FEC_IMASK */
+	case 0x00c: /* FEC_IVEC */
+	case 0x010: /* FEC_R_DES_ACTIVE_0 */
+	case 0x014: /* FEC_X_DES_ACTIVE_0 */
+	case 0x040: /* FEC_MII_DATA */
+	case 0x044: /* FEC_MII_SPEED */
+	case 0x08c: /* FEC_R_BOUND */
+	case 0x090: /* FEC_R_FSTART */
+	case 0x0a4: /* FEC_X_WMRK */
+	case 0x0ac: /* FEC_X_FSTART */
+	case 0x104: /* FEC_R_CNTRL */
+	case 0x108: /* FEC_MAX_FRM_LEN */
+	case 0x144: /* FEC_X_CNTRL */
+	case 0x3c0: /* FEC_ADDR_LOW */
+	case 0x3c4: /* FEC_ADDR_HIGH */
+	case 0x3c8: /* FEC_GRP_HASH_TABLE_HIGH */
+	case 0x3cc: /* FEC_GRP_HASH_TABLE_LOW */
+	case 0x3d0: /* FEC_R_DES_START_0 */
+	case 0x3d4: /* FEC_X_DES_START_0 */
+	case 0x3d8: /* FEC_R_BUFF_SIZE_0 */
+		REG(reg, "", val);
+		break;
+	}
+}
+
+static void fec_dump_reg_v2(int reg, u32 val)
+{
+	switch (reg) {
+	case 0x084: /* FEC_R_CNTRL */
+		REG(reg, "RCR (Receive Control Register)", val);
+		FIELD("MAX_FL (Maximum frame length)", "%u", (val & 0x07ff0000) >> 16);
+		FIELD("FCE (Flow control enable)", "%u", !!(val & 0x00000020));
+		FIELD("BC_REJ (Broadcast frame reject)", "%u", !!(val & 0x00000010));
+		FIELD("PROM (Promiscuous mode)", "%u", !!(val & 0x00000008));
+		FIELD("DRT (Disable receive on transmit)", "%u", !!(val & 0x00000002));
+		FIELD("LOOP (Internal loopback)", "%u", !!(val & 0x00000001));
+		break;
+	case 0x0c4: /* FEC_X_CNTRL */
+		REG(reg, "TCR (Transmit Control Register)", val);
+		FIELD("RFC_PAUSE (Receive frame control pause)", "%u", !!(val & 0x00000010));
+		FIELD("TFC_PAUSE (Transmit frame control pause)", "%u", !!(val & 0x00000008));
+		FIELD("FDEN (Full duplex enable)", "%u", !!(val & 0x00000004));
+		FIELD("HBC (Heartbeat control)", "%u", !!(val & 0x00000002));
+		FIELD("GTS (Graceful transmit stop)", "%u", !!(val & 0x00000001));
+		break;
+	case 0x118: /* FEC_HASH_TABLE_HIGH */
+		REG(reg, "IAUR (Individual Address Upper Register)", val);
+		FIELD("IADDR1", "0x%.16llx", (u64)((u64)val) << 32);
+		break;
+	case 0x11c: /* FEC_HASH_TABLE_LOW */
+		REG(reg, "IALR (Individual Address Lower Register)", val);
+		FIELD("IADDR2", "0x%.16x", val);
+		break;
+	case 0x120: /* FEC_GRP_HASH_TABLE_HIGH */
+		REG(reg, "GAUR (Group Address Upper Register)", val);
+		FIELD("GADDR1", "0x%.16llx", (u64)((u64)val) << 32);
+		break;
+	case 0x124: /* FEC_GRP_HASH_TABLE_LOW */
+		REG(reg, "GALR (Group Address Lower Register)", val);
+		FIELD("GADDR2", "0x%.16x", val);
+		break;
+	case 0x144: /* FEC_X_WMRK */
+		REG(reg, "TFWR (Transmit FIFO Watermark Register)", val);
+		FIELD("X_WMRK", "%s",
+			(val & 0x00000003) == 0x00000000 ? "64 bytes" :
+			(val & 0x00000003) == 0x00000002 ? "128 bytes" :
+			(val & 0x00000003) == 0x00000003 ? "192 bytes" : "?");
+		break;
+	case 0x14c: /* FEC_R_BOUND */
+		REG(reg, "FRBR (FIFO Receive Bound Register)", val);
+		FIELD("R_BOUND (Highest valid FIFO RAM address)", "0x%.2x", (val & 0x000003fc) >> 2);
+		break;
+	case 0x188: /* FEC_R_BUFF_SIZE_0 */
+		REG(reg, "EMRBR (Maximum Receive Buffer Size)", val);
+		FIELD("R_BUF_SIZE (Receive buffer size)", "%u", (val & 0x000007f0) >> 4);
+		break;
+	case 0x004: /* FEC_IEVENT */
+	case 0x008: /* FEC_IMASK */
+	case 0x010: /* FEC_R_DES_ACTIVE_0 */
+	case 0x014: /* FEC_X_DES_ACTIVE_0 */
+	case 0x024: /* FEC_ECNTRL */
+	case 0x040: /* FEC_MII_DATA */
+	case 0x044: /* FEC_MII_SPEED */
+	case 0x064: /* FEC_MIB_CTRLSTAT */
+	case 0x0e4: /* FEC_ADDR_LOW */
+	case 0x0e8: /* FEC_ADDR_HIGH */
+	case 0x0ec: /* FEC_OPD */
+	case 0x0f0: /* FEC_TXIC0 */
+	case 0x0f4: /* FEC_TXIC1 */
+	case 0x0f8: /* FEC_TXIC2 */
+	case 0x100: /* FEC_RXIC0 */
+	case 0x104: /* FEC_RXIC1 */
+	case 0x108: /* FEC_RXIC2 */
+	case 0x150: /* FEC_R_FSTART */
+	case 0x160: /* FEC_R_DES_START_1 */
+	case 0x164: /* FEC_X_DES_START_1 */
+	case 0x168: /* FEC_R_BUFF_SIZE_1 */
+	case 0x16c: /* FEC_R_DES_START_2 */
+	case 0x170: /* FEC_X_DES_START_2 */
+	case 0x174: /* FEC_R_BUFF_SIZE_2 */
+	case 0x180: /* FEC_R_DES_START_0 */
+	case 0x184: /* FEC_X_DES_START_0 */
+	case 0x190: /* FEC_R_FIFO_RSFL */
+	case 0x194: /* FEC_R_FIFO_RSEM */
+	case 0x198: /* FEC_R_FIFO_RAEM */
+	case 0x19c: /* FEC_R_FIFO_RAFL */
+	case 0x1c4: /* FEC_RACC */
+	case 0x1c8: /* FEC_RCMR_1 */
+	case 0x1cc: /* FEC_RCMR_2 */
+	case 0x1d8: /* FEC_DMA_CFG_1 */
+	case 0x1dc: /* FEC_DMA_CFG_2 */
+	case 0x1e0: /* FEC_R_DES_ACTIVE_1 */
+	case 0x1e4: /* FEC_X_DES_ACTIVE_1 */
+	case 0x1e8: /* FEC_R_DES_ACTIVE_2 */
+	case 0x1ec: /* FEC_X_DES_ACTIVE_2 */
+	case 0x1f0: /* FEC_QOS_SCHEME */
+	case 0x200: /* RMON_T_DROP */
+	case 0x204: /* RMON_T_PACKETS */
+	case 0x208: /* RMON_T_BC_PKT */
+	case 0x20c: /* RMON_T_MC_PKT */
+	case 0x210: /* RMON_T_CRC_ALIGN */
+	case 0x214: /* RMON_T_UNDERSIZE */
+	case 0x218: /* RMON_T_OVERSIZE */
+	case 0x21c: /* RMON_T_FRAG */
+	case 0x220: /* RMON_T_JAB */
+	case 0x224: /* RMON_T_COL */
+	case 0x228: /* RMON_T_P64 */
+	case 0x22c: /* RMON_T_P65TO127 */
+	case 0x230: /* RMON_T_P128TO255 */
+	case 0x234: /* RMON_T_P256TO511 */
+	case 0x238: /* RMON_T_P512TO1023 */
+	case 0x23c: /* RMON_T_P1024TO2047 */
+	case 0x240: /* RMON_T_P_GTE2048 */
+	case 0x244: /* RMON_T_OCTETS */
+	case 0x248: /* IEEE_T_DROP */
+	case 0x24c: /* IEEE_T_FRAME_OK */
+	case 0x250: /* IEEE_T_1COL */
+	case 0x254: /* IEEE_T_MCOL */
+	case 0x258: /* IEEE_T_DEF */
+	case 0x25c: /* IEEE_T_LCOL */
+	case 0x260: /* IEEE_T_EXCOL */
+	case 0x264: /* IEEE_T_MACERR */
+	case 0x268: /* IEEE_T_CSERR */
+	case 0x26c: /* IEEE_T_SQE */
+	case 0x270: /* IEEE_T_FDXFC */
+	case 0x274: /* IEEE_T_OCTETS_OK */
+	case 0x284: /* RMON_R_PACKETS */
+	case 0x288: /* RMON_R_BC_PKT */
+	case 0x28c: /* RMON_R_MC_PKT */
+	case 0x290: /* RMON_R_CRC_ALIGN */
+	case 0x294: /* RMON_R_UNDERSIZE */
+	case 0x298: /* RMON_R_OVERSIZE */
+	case 0x29c: /* RMON_R_FRAG */
+	case 0x2a0: /* RMON_R_JAB */
+	case 0x2a4: /* RMON_R_RESVD_O */
+	case 0x2a8: /* RMON_R_P64 */
+	case 0x2ac: /* RMON_R_P65TO127 */
+	case 0x2b0: /* RMON_R_P128TO255 */
+	case 0x2b4: /* RMON_R_P256TO511 */
+	case 0x2b8: /* RMON_R_P512TO1023 */
+	case 0x2bc: /* RMON_R_P1024TO2047 */
+	case 0x2c0: /* RMON_R_P_GTE2048 */
+	case 0x2c4: /* RMON_R_OCTETS */
+	case 0x2c8: /* IEEE_R_DROP */
+	case 0x2cc: /* IEEE_R_FRAME_OK */
+	case 0x2d0: /* IEEE_R_CRC */
+	case 0x2d4: /* IEEE_R_ALIGN */
+	case 0x2d8: /* IEEE_R_MACERR */
+	case 0x2dc: /* IEEE_R_FDXFC */
+	case 0x2e0: /* IEEE_R_OCTETS_OK */
+		REG(reg, "", val);
+		break;
+	}
+}
+
+#undef FIELD
+#undef REG
+
+int fec_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		  struct ethtool_regs *regs)
+{
+	const u32 *data = (u32 *)regs->data;
+	int offset;
+	u32 val;
+
+	for (offset = 0; offset < regs->len; offset += 4) {
+		val = data[offset / 4];
+
+		switch (regs->version) {
+		case 1:
+			fec_dump_reg_v1(offset, val);
+			break;
+		case 2:
+			fec_dump_reg_v2(offset, val);
+			break;
+		default:
+			return 1;
+		}
+	}
+
+	return 0;
+}
diff --git a/fec_8xx.c b/fec_8xx.c
new file mode 100644
index 0000000..02ecaef
--- /dev/null
+++ b/fec_8xx.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2004 Intracom S.A.
+ * Pantelis Antoniou <panto@intracom.gr>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include "internal.h"
+
+struct fec {
+	uint32_t	addr_low;	/* lower 32 bits of station address	*/
+	uint32_t	addr_high;	/* upper 16 bits of station address||0  */
+	uint32_t	hash_table_high;/* upper 32-bits of hash table		*/
+	uint32_t	hash_table_low;	/* lower 32-bits of hash table		*/
+	uint32_t	r_des_start;	/* beginning of Rx descriptor ring	*/
+	uint32_t	x_des_start;	/* beginning of Tx descriptor ring	*/
+	uint32_t	r_buff_size;	/* Rx buffer size			*/
+	uint32_t	res2[9];	/* reserved				*/
+	uint32_t	ecntrl;		/* ethernet control register		*/
+	uint32_t	ievent;		/* interrupt event register		*/
+	uint32_t	imask;		/* interrupt mask register		*/
+	uint32_t	ivec;		/* interrupt level and vector status	*/
+	uint32_t	r_des_active;	/* Rx ring updated flag			*/
+	uint32_t	x_des_active;	/* Tx ring updated flag			*/
+	uint32_t	res3[10];	/* reserved				*/
+	uint32_t	mii_data;	/* MII data register			*/
+	uint32_t	mii_speed;	/* MII speed control register		*/
+	uint32_t	res4[17];	/* reserved				*/
+	uint32_t	r_bound;	/* end of RAM (read-only)		*/
+	uint32_t	r_fstart;	/* Rx FIFO start address		*/
+	uint32_t	res5[6];	/* reserved				*/
+	uint32_t	x_fstart;	/* Tx FIFO start address		*/
+	uint32_t	res6[17];	/* reserved				*/
+	uint32_t	fun_code;	/* fec SDMA function code		*/
+	uint32_t	res7[3];	/* reserved				*/
+	uint32_t	r_cntrl;	/* Rx control register			*/
+	uint32_t	r_hash;		/* Rx hash register			*/
+	uint32_t	res8[14];	/* reserved				*/
+	uint32_t	x_cntrl;	/* Tx control register			*/
+	uint32_t	res9[0x1e];	/* reserved				*/
+};
+
+#define DUMP_REG(f, x)	fprintf(stdout, \
+			"0x%04lx: %-16s 0x%08x\n", \
+				(unsigned long)(offsetof(struct fec, x)), \
+				#x, f->x)
+
+int fec_8xx_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		      struct ethtool_regs *regs)
+{
+	struct fec *f = (struct fec *)regs->data;
+
+	fprintf(stdout, "Descriptor Registers\n");
+	fprintf(stdout, "---------------------\n");
+
+	DUMP_REG(f, addr_low);
+	DUMP_REG(f, addr_high);
+	DUMP_REG(f, hash_table_high);
+	DUMP_REG(f, hash_table_low);
+	DUMP_REG(f, r_des_start);
+	DUMP_REG(f, x_des_start);
+	DUMP_REG(f, r_buff_size);
+	DUMP_REG(f, ecntrl);
+	DUMP_REG(f, ievent);
+	DUMP_REG(f, imask);
+	DUMP_REG(f, ivec);
+	DUMP_REG(f, r_des_active);
+	DUMP_REG(f, x_des_active);
+	DUMP_REG(f, mii_data);
+	DUMP_REG(f, mii_speed);
+	DUMP_REG(f, r_bound);
+	DUMP_REG(f, r_fstart);
+	DUMP_REG(f, x_fstart);
+	DUMP_REG(f, fun_code);
+	DUMP_REG(f, r_cntrl);
+	DUMP_REG(f, r_hash);
+	DUMP_REG(f, x_cntrl);
+
+	return 0;
+}
diff --git a/fjes.c b/fjes.c
new file mode 100644
index 0000000..4c5f6bc
--- /dev/null
+++ b/fjes.c
@@ -0,0 +1,90 @@
+/* Copyright (c) 2016 FUJITSU LIMITED */
+#include <stdio.h>
+#include "internal.h"
+
+int fjes_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		   struct ethtool_regs *regs)
+{
+	u32 *regs_buff = (u32 *)regs->data;
+
+	if (regs->version != 1)
+		return -1;
+
+	/* Information registers */
+	fprintf(stdout,
+		"0x0000: OWNER_EPID    (Owner EPID)                       0x%08X\n",
+		regs_buff[0]);
+
+	fprintf(stdout,
+		"0x0004: MAX_EP        (Maximum EP)                       0x%08X\n",
+		regs_buff[1]);
+
+	/* Device Control registers */
+	fprintf(stdout,
+		"0x0010: DCTL          (Device Control)                   0x%08X\n",
+		regs_buff[4]);
+
+	/* Command Control registers */
+	fprintf(stdout,
+		"0x0020: CR            (Command request)                  0x%08X\n",
+		regs_buff[8]);
+
+	fprintf(stdout,
+		"0x0024: CS            (Command status)                   0x%08X\n",
+		regs_buff[9]);
+
+	fprintf(stdout,
+		"0x0028: SHSTSAL       (Share status address Low)         0x%08X\n",
+		regs_buff[10]);
+
+	fprintf(stdout,
+		"0x002C: SHSTSAH       (Share status address High)        0x%08X\n",
+		regs_buff[11]);
+
+	fprintf(stdout,
+		"0x0034: REQBL         (Request Buffer length)            0x%08X\n",
+		regs_buff[13]);
+
+	fprintf(stdout,
+		"0x0038: REQBAL        (Request Buffer Address Low)       0x%08X\n",
+		regs_buff[14]);
+
+	fprintf(stdout,
+		"0x003C: REQBAH        (Request Buffer Address High)      0x%08X\n",
+		regs_buff[15]);
+
+	fprintf(stdout,
+		"0x0044: RESPBL        (Response Buffer Length)           0x%08X\n",
+		regs_buff[17]);
+
+	fprintf(stdout,
+		"0x0048: RESPBAL       (Response Buffer Address Low)      0x%08X\n",
+		regs_buff[18]);
+
+	fprintf(stdout,
+		"0x004C: RESPBAH       (Response Buffer Address High)     0x%08X\n",
+		regs_buff[19]);
+
+	/* Interrupt Control registers */
+	fprintf(stdout,
+		"0x0080: IS            (Interrupt status)                 0x%08X\n",
+		regs_buff[32]);
+
+	fprintf(stdout,
+		"0x0084: IMS           (Interrupt mask set)               0x%08X\n",
+		regs_buff[33]);
+
+	fprintf(stdout,
+		"0x0088: IMC           (Interrupt mask clear)             0x%08X\n",
+		regs_buff[34]);
+
+	fprintf(stdout,
+		"0x008C: IG            (Interrupt generator)              0x%08X\n",
+		regs_buff[35]);
+
+	fprintf(stdout,
+		"0x0090: ICTL          (Interrupt control)                0x%08X\n",
+		regs_buff[36]);
+
+	return 0;
+}
diff --git a/ibm_emac.c b/ibm_emac.c
new file mode 100644
index 0000000..3259c17
--- /dev/null
+++ b/ibm_emac.c
@@ -0,0 +1,334 @@
+/*
+ *  Copyright (c) 2004, 2005 Zultys Technologies
+ *  Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ */
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include "internal.h"
+
+/* Ethtool get_regs complex data.
+ * we want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH
+ * when available.
+ *
+ * Returned BLOB consists of the ibm_emac_ethtool_regs_hdr,
+ * MAL registers, EMAC registers and optional ZMII, RGMII, TAH registers.
+ * Each register component is preceded with emac_ethtool_regs_subhdr.
+ * Order of the optional headers follows their relative bit posititions
+ * in emac_ethtool_regs_hdr.components
+ */
+#define EMAC_ETHTOOL_REGS_ZMII		0x00000001
+#define EMAC_ETHTOOL_REGS_RGMII		0x00000002
+#define EMAC_ETHTOOL_REGS_TAH		0x00000004
+
+#define EMAC_VERSION			3
+#define EMAC4_VERSION			4
+#define EMAC4SYNC_VERSION		5
+
+struct emac_ethtool_regs_hdr {
+	u32 components;
+};
+
+struct emac_ethtool_regs_subhdr {
+	u32 version;
+	u32 index;
+};
+
+struct emac_regs {
+	/* Common registers across all EMAC implementations. */
+	u32 mr0;			/* Special 	*/
+	u32 mr1;			/* Reset 	*/
+	u32 tmr0;			/* Special 	*/
+	u32 tmr1;			/* Special 	*/
+	u32 rmr;			/* Reset 	*/
+	u32 isr;			/* Always 	*/
+	u32 iser;			/* Reset 	*/
+	u32 iahr;			/* Reset, R, T 	*/
+	u32 ialr;			/* Reset, R, T 	*/
+	u32 vtpid;			/* Reset, R, T 	*/
+	u32 vtci;			/* Reset, R, T 	*/
+	u32 ptr;			/* Reset,    T 	*/
+	union {
+		/* Registers unique to EMAC4 implementations */
+		struct {
+			u32 iaht1;	/* Reset, R	*/
+			u32 iaht2;	/* Reset, R	*/
+			u32 iaht3;	/* Reset, R	*/
+			u32 iaht4;	/* Reset, R	*/
+			u32 gaht1;	/* Reset, R	*/
+			u32 gaht2;	/* Reset, R	*/
+			u32 gaht3;	/* Reset, R	*/
+			u32 gaht4;	/* Reset, R	*/
+		} emac4;
+		/* Registers unique to EMAC4SYNC implementations */
+		struct {
+			u32 mahr;	/* Reset, R, T  */
+			u32 malr;	/* Reset, R, T  */
+			u32 mmahr;	/* Reset, R, T  */
+			u32 mmalr;	/* Reset, R, T  */
+			u32 rsvd0[4];
+		} emac4sync;
+	} u0;
+	/* Common registers across all EMAC implementations. */
+	u32 lsah;
+	u32 lsal;
+	u32 ipgvr;			/* Reset,    T 	*/
+	u32 stacr;			/* Special 	*/
+	u32 trtr;			/* Special 	*/
+	u32 rwmr;			/* Reset 	*/
+	u32 octx;
+	u32 ocrx;
+	union {
+		/* Registers unique to EMAC4 implementations */
+		struct {
+			u32 ipcr;
+		} emac4;
+		/* Registers unique to EMAC4SYNC implementations */
+		struct {
+			u32 rsvd1;
+			u32 revid;
+			u32 rsvd2[2];
+			u32 iaht1;	/* Reset, R     */
+			u32 iaht2;	/* Reset, R     */
+			u32 iaht3;	/* Reset, R     */
+			u32 iaht4;	/* Reset, R     */
+			u32 iaht5;	/* Reset, R     */
+			u32 iaht6;	/* Reset, R     */
+			u32 iaht7;	/* Reset, R     */
+			u32 iaht8;	/* Reset, R     */
+			u32 gaht1;	/* Reset, R     */
+			u32 gaht2;	/* Reset, R     */
+			u32 gaht3;	/* Reset, R     */
+			u32 gaht4;	/* Reset, R     */
+			u32 gaht5;	/* Reset, R     */
+			u32 gaht6;	/* Reset, R     */
+			u32 gaht7;	/* Reset, R     */
+			u32 gaht8;	/* Reset, R     */
+			u32 tpc;	/* Reset, T     */
+		} emac4sync;
+	} u1;
+};
+
+struct mal_regs {
+	u32 tx_count;
+	u32 rx_count;
+
+	u32 cfg;
+	u32 esr;
+	u32 ier;
+	u32 tx_casr;
+	u32 tx_carr;
+	u32 tx_eobisr;
+	u32 tx_deir;
+	u32 rx_casr;
+	u32 rx_carr;
+	u32 rx_eobisr;
+	u32 rx_deir;
+	u32 tx_ctpr[32];
+	u32 rx_ctpr[32];
+	u32 rcbs[32];
+};
+
+struct zmii_regs {
+	u32 fer;
+	u32 ssr;
+	u32 smiisr;
+};
+
+struct rgmii_regs {
+	u32 fer;
+	u32 ssr;
+};
+
+struct tah_regs {
+	u32 revid;
+	u32 pad[3];
+	u32 mr;
+	u32 ssr0;
+	u32 ssr1;
+	u32 ssr2;
+	u32 ssr3;
+	u32 ssr4;
+	u32 ssr5;
+	u32 tsr;
+};
+
+static void *print_emac_regs(void *buf)
+{
+	struct emac_ethtool_regs_subhdr *hdr = buf;
+	struct emac_regs *p = (struct emac_regs *)(hdr + 1);
+	void *res = p + 1;
+
+	if (!((hdr->version == EMAC_VERSION) ||
+		(hdr->version == EMAC4_VERSION) ||
+		(hdr->version == EMAC4SYNC_VERSION)))
+	{
+		printf("This driver version doesn't support information\n"
+			" output for EMAC area, please update it or use older\n"
+			" ethtool version\n");
+		return res;
+	}
+
+	printf("EMAC%d Registers\n", hdr->index);
+	printf("-----------------\n");
+	printf("MR0   = 0x%08x MR1  = 0x%08x RMR = 0x%08x\n"
+	       "ISR   = 0x%08x ISER = 0x%08x\n"
+	       "TMR0  = 0x%08x TMR1 = 0x%08x\n"
+	       "TRTR  = 0x%08x RWMR = 0x%08x\n"
+	       "IAR   = %04x%08x\n"
+	       "LSA   = %04x%08x\n"
+	       "VTPID = 0x%04x VTCI = 0x%04x\n"
+	       "IPGVR = 0x%04x STACR = 0x%08x\n"
+	       "OCTX  = 0x%08x OCRX = 0x%08x\n",
+	       p->mr0, p->mr1, p->rmr,
+	       p->isr, p->iser,
+	       p->tmr0, p->tmr1,
+	       p->trtr, p->rwmr,
+	       p->iahr, p->ialr,
+	       p->lsah, p->lsal,
+	       p->vtpid, p->vtci,
+	       p->ipgvr, p->stacr, p->octx, p->ocrx);
+
+	if (hdr->version == EMAC4SYNC_VERSION) {
+		printf("MAHR  = 0x%08x MALR  = 0x%08x MMAHR = 0x%08x\n"
+			"MMALR  = 0x%08x REVID  = 0x%08x\n",
+			p->u0.emac4sync.mahr, p->u0.emac4sync.malr,
+			p->u0.emac4sync.mmahr, p->u0.emac4sync.mmalr,
+			p->u1.emac4sync.revid);
+
+		printf("IAHT  = 0x%04x 0x%04x 0x%04x 0x%04x\n",
+			p->u1.emac4sync.iaht1, p->u1.emac4sync.iaht2,
+			p->u1.emac4sync.iaht3, p->u1.emac4sync.iaht4);
+		printf("        0x%04x 0x%04x 0x%04x 0x%04x\n",
+			p->u1.emac4sync.iaht5, p->u1.emac4sync.iaht6,
+			p->u1.emac4sync.iaht7, p->u1.emac4sync.iaht8);
+
+
+		printf("GAHT  = 0x%04x 0x%04x 0x%04x 0x%04x\n",
+			p->u1.emac4sync.gaht1, p->u1.emac4sync.gaht2,
+			p->u1.emac4sync.gaht3, p->u1.emac4sync.gaht4);
+		printf("        0x%04x 0x%04x 0x%04x 0x%04x\n\n",
+			p->u1.emac4sync.gaht5, p->u1.emac4sync.gaht6,
+			p->u1.emac4sync.gaht7, p->u1.emac4sync.gaht8);
+
+	} else if (hdr->version == EMAC4_VERSION) {
+		printf("IAHT  = 0x%04x 0x%04x 0x%04x 0x%04x\n",
+			p->u0.emac4.iaht1, p->u0.emac4.iaht2,
+			p->u0.emac4.iaht3, p->u0.emac4.iaht4);
+
+		printf("GAHT  = 0x%04x 0x%04x 0x%04x 0x%04x\n",
+			p->u0.emac4.gaht1, p->u0.emac4.gaht2,
+			p->u0.emac4.gaht3, p->u0.emac4.gaht4);
+
+		printf(" IPCR = 0x%08x\n\n", p->u1.emac4.ipcr);
+	} else if (hdr->version == EMAC_VERSION) {
+		printf("IAHT  = 0x%04x 0x%04x 0x%04x 0x%04x\n",
+			p->u0.emac4.iaht1, p->u0.emac4.iaht2,
+			p->u0.emac4.iaht3, p->u0.emac4.iaht4);
+
+		printf("GAHT  = 0x%04x 0x%04x 0x%04x 0x%04x\n",
+			p->u0.emac4.gaht1, p->u0.emac4.gaht2,
+			p->u0.emac4.gaht3, p->u0.emac4.gaht4);
+	}
+	return res;
+}
+
+static void *print_mal_regs(void *buf)
+{
+	struct emac_ethtool_regs_subhdr *hdr = buf;
+	struct mal_regs *p = (struct mal_regs *)(hdr + 1);
+	int i;
+
+	printf("MAL%d Registers\n", hdr->index);
+	printf("-----------------\n");
+	printf("CFG = 0x%08x ESR = 0x%08x IER = 0x%08x\n"
+	       "TX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n"
+	       "RX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n",
+	       p->cfg, p->esr, p->ier,
+	       p->tx_casr, p->tx_carr, p->tx_eobisr, p->tx_deir,
+	       p->rx_casr, p->rx_carr, p->rx_eobisr, p->rx_deir);
+
+	printf("TX|");
+	for (i = 0; i < p->tx_count; ++i) {
+		if (i && !(i % 4))
+			printf("\n   ");
+		printf("CTP%d = 0x%08x ", i, p->tx_ctpr[i]);
+	}
+	printf("\nRX|");
+	for (i = 0; i < p->rx_count; ++i) {
+		if (i && !(i % 4))
+			printf("\n   ");
+		printf("CTP%d = 0x%08x ", i, p->rx_ctpr[i]);
+	}
+	printf("\n   ");
+	for (i = 0; i < p->rx_count; ++i) {
+		u32 r = p->rcbs[i];
+		if (i && !(i % 3))
+			printf("\n   ");
+		printf("RCBS%d = 0x%08x (%d) ", i, r, r * 16);
+	}
+	printf("\n\n");
+	return p + 1;
+}
+
+static void *print_zmii_regs(void *buf)
+{
+	struct emac_ethtool_regs_subhdr *hdr = buf;
+	struct zmii_regs *p = (struct zmii_regs *)(hdr + 1);
+
+	printf("ZMII%d Registers\n", hdr->index);
+	printf("-----------------\n");
+	printf("FER    = %08x SSR = %08x\n"
+	       "SMIISR = %08x\n\n", p->fer, p->ssr, p->smiisr);
+
+	return p + 1;
+}
+
+static void *print_rgmii_regs(void *buf)
+{
+	struct emac_ethtool_regs_subhdr *hdr = buf;
+	struct rgmii_regs *p = (struct rgmii_regs *)(hdr + 1);
+
+	printf("RGMII%d Registers\n", hdr->index);
+	printf("-----------------\n");
+	printf("FER    = %08x SSR = %08x\n\n", p->fer, p->ssr);
+
+	return p + 1;
+}
+
+static void *print_tah_regs(void *buf)
+{
+	struct emac_ethtool_regs_subhdr *hdr = buf;
+	struct tah_regs *p = (struct tah_regs *)(hdr + 1);
+
+	printf("TAH%d Registers\n", hdr->index);
+	printf("-----------------\n");
+
+	printf("REVID = %08x MR = %08x TSR = %08x\n"
+	       "SSR0  = %08x SSR1 = %08x SSR2 = %08x\n"
+	       "SSR3  = %08x SSR4 = %08x SSR5 = %08x\n\n",
+	       p->revid, p->mr, p->tsr,
+	       p->ssr0, p->ssr1, p->ssr2, p->ssr3, p->ssr4, p->ssr5);
+
+	return p + 1;
+}
+
+int ibm_emac_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		       struct ethtool_regs *regs)
+{
+	struct emac_ethtool_regs_hdr *hdr =
+	    (struct emac_ethtool_regs_hdr *)regs->data;
+	void *buf = hdr + 1;
+
+	buf = print_mal_regs(buf);
+	buf = print_emac_regs(buf);
+	if (hdr->components & EMAC_ETHTOOL_REGS_ZMII)
+		buf = print_zmii_regs(buf);
+	if (hdr->components & EMAC_ETHTOOL_REGS_RGMII)
+		buf = print_rgmii_regs(buf);
+	if (hdr->components & EMAC_ETHTOOL_REGS_TAH)
+		print_tah_regs(buf);
+
+	return 0;
+}
diff --git a/igb.c b/igb.c
new file mode 100644
index 0000000..89b5cdb
--- /dev/null
+++ b/igb.c
@@ -0,0 +1,876 @@
+/* Copyright (c) 2007 Intel Corporation */
+#include <stdio.h>
+#include "internal.h"
+
+/* Register Bit Masks */
+/* Device Control */
+#define E1000_CTRL_FD         0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_PRIOR      0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_GIOMASTERD 0x00000008  /* GIO Master Disable*/
+#define E1000_CTRL_TME        0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE        0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE       0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU        0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS       0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL    0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10     0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100    0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000   0x00000200  /* Force 1Gb */
+#define E1000_CTRL_FRCSPD     0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX     0x00001000  /* Force Duplex */
+#define E1000_CTRL_SDP0_GPIEN 0x00010000  /* General Purpose Interrupt Detection Enable for SDP0 */
+#define E1000_CTRL_SDP1_GPIEN 0x00020000  /* General Purpose Interrupt Detection Enable for SDP1 */
+#define E1000_CTRL_SDP0_DATA  0x00040000  /* SDP0 Data */
+#define E1000_CTRL_SDP1_DATA  0x00080000  /* SDP1 Data */
+#define E1000_CTRL_ADVD3WUC   0x00100000  /* D3Cold WakeUp Capability Advertisement Enable */
+#define E1000_CTRL_SDP0_WDE   0x00200000  /* Watchdog Indication for SDP0 */
+#define E1000_CTRL_SDP1_IODIR 0x00400000  /* SDP1 Directionality */
+#define E1000_CTRL_RST        0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE       0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE       0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_VME        0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST    0x80000000  /* PHY Reset */
+
+/* Device Status */
+#define E1000_STATUS_FD          0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU          0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_LANID       0x00000008      /* LAN ID */
+#define E1000_STATUS_TXOFF       0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE     0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK  0x000000C0      /* Speed Mask */
+#define E1000_STATUS_SPEED_10    0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100   0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000  0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_ASDV        0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_PHYRA       0x00000400      /* PHY Reset Asserted */
+#define E1000_STATUS_GIOMASTEREN 0x00080000      /* GIO Master Enable Status */
+#define E1000_STATUS_DMA_CGEN    0x80000000      /* DMA clock gating Enable */
+
+/* Receive Control */
+#define E1000_RCTL_EN           0x00000002      /* enable */
+#define E1000_RCTL_SBP          0x00000004      /* store bad packet */
+#define E1000_RCTL_UPE          0x00000008      /* unicast promiscuous enable */
+#define E1000_RCTL_MPE          0x00000010      /* multicast promiscuous enab */
+#define E1000_RCTL_LPE          0x00000020      /* long packet enable */
+#define E1000_RCTL_LBM_MASK     0x000000C0      /* Loopback mode mask */
+#define E1000_RCTL_LBM_NORM     0x00000000      /* normal loopback mode */
+#define E1000_RCTL_LBM_MAC      0x00000040      /* MAC loopback mode */
+#define E1000_RCTL_LBM_SERDES   0x000000C0      /* SERDES loopback mode */
+#define E1000_RCTL_RDMTS        0x00000300      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_HALF   0x00000000      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT   0x00000100      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH  0x00000200      /* rx desc min threshold size */
+#define E1000_RCTL_MO           0x00003000      /* multicast offset shift */
+#define E1000_RCTL_MO_0         0x00000000      /* multicast offset 47:36 */
+#define E1000_RCTL_MO_1         0x00001000      /* multicast offset 46:35 */
+#define E1000_RCTL_MO_2         0x00002000      /* multicast offset 45:34 */
+#define E1000_RCTL_MO_3         0x00003000      /* multicast offset 43:32 */
+#define E1000_RCTL_BAM          0x00008000      /* broadcast enable */
+#define E1000_RCTL_BSIZE        0x00030000      /* rx buffer size */
+#define E1000_RCTL_BSIZE_2048   0x00000000      /* rx buffer size 2048 */
+#define E1000_RCTL_BSIZE_1024   0x00010000      /* rx buffer size 1024 */
+#define E1000_RCTL_BSIZE_512    0x00020000      /* rx buffer size 512 */
+#define E1000_RCTL_BSIZE_256    0x00030000      /* rx buffer size 256 */
+#define E1000_RCTL_VFE          0x00040000      /* vlan filter enable */
+#define E1000_RCTL_CFIEN        0x00080000      /* canonical form enable */
+#define E1000_RCTL_CFI          0x00100000      /* canonical form indicator */
+#define E1000_RCTL_DPF          0x00400000      /* discard pause frames */
+#define E1000_RCTL_PMCF         0x00800000      /* pass MAC control frames */
+#define E1000_RCTL_SECRC        0x04000000      /* Strip Ethernet CRC from packet.0=No strip;1=strip */
+
+/* Transmit Control */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_BST    0x003ff000    /* Backoff Slot time */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+
+int igb_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		  struct ethtool_regs *regs)
+{
+	u32 *regs_buff = (u32 *)regs->data;
+	u32 reg;
+	u8 i;
+	u8 version = (u8)(regs->version >> 24);
+
+	if (version != 1)
+		return -1;
+
+	/* Device control register */
+	reg = regs_buff[0];
+	fprintf(stdout,
+		"0x00000: CTRL (Device control register)               0x%08X\n"
+		"       Invert Loss-Of-Signal:                         %s\n"
+		"       Receive flow control:                          %s\n"
+		"       Transmit flow control:                         %s\n"
+		"       VLAN mode:                                     %s\n"
+		"       Set link up:                                   %s\n"
+		"       D3COLD WakeUp capability advertisement:        %s\n",
+		reg,
+		reg & E1000_CTRL_ILOS     ? "yes"      : "no",
+		reg & E1000_CTRL_RFCE     ? "enabled"  : "disabled",
+		reg & E1000_CTRL_TFCE     ? "enabled"  : "disabled",
+		reg & E1000_CTRL_VME      ? "enabled"  : "disabled",
+		reg & E1000_CTRL_SLU      ? "1"        : "0",
+		reg & E1000_CTRL_ADVD3WUC ? "enabled"  : "disabled");
+	fprintf(stdout,
+		"       Auto speed detect:                             %s\n"
+		"       Speed select:                                  %s\n"
+		"       Force speed:                                   %s\n"
+		"       Force duplex:                                  %s\n",
+		reg & E1000_CTRL_ASDE   ? "enabled"  : "disabled",
+		(reg & E1000_CTRL_SPD_SEL) == E1000_CTRL_SPD_10   ? "10Mb/s"   :
+		(reg & E1000_CTRL_SPD_SEL) == E1000_CTRL_SPD_100  ? "100Mb/s"  :
+		(reg & E1000_CTRL_SPD_SEL) == E1000_CTRL_SPD_1000 ? "1000Mb/s" :
+		"not used",
+		reg & E1000_CTRL_FRCSPD ? "yes"      : "no",
+		reg & E1000_CTRL_FRCDPX ? "yes"      : "no");
+
+	/* Device status register */
+	reg = regs_buff[1];
+	fprintf(stdout,
+		"0x00008: STATUS (Device status register)              0x%08X\n"
+		"       Duplex:                                        %s\n"
+		"       Link up:                                       %s\n"
+		"       Transmission:                                  %s\n"
+		"       DMA clock gating:                              %s\n",
+		reg,
+		reg & E1000_STATUS_FD       ? "full"        : "half",
+		reg & E1000_STATUS_LU       ? "link config" : "no link config",
+		reg & E1000_STATUS_TXOFF    ? "paused"      : "on",
+		reg & E1000_STATUS_DMA_CGEN ? "enabled"     : "disabled");
+	fprintf(stdout,
+		"       TBI mode:                                      %s\n"
+		"       Link speed:                                    %s\n"
+		"       Bus type:                                      %s\n",
+		reg & E1000_STATUS_TBIMODE ? "enabled"     : "disabled",
+		(reg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_10   ?
+		"10Mb/s" :
+		(reg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_100  ?
+		"100Mb/s" :
+		(reg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_1000 ?
+		"1000Mb/s" : "not used",
+		"PCI Express");
+
+	/* Receive control register */
+	reg = regs_buff[32];
+	fprintf(stdout,
+		"0x00100: RCTL (Receive control register)              0x%08X\n"
+		"       Receiver:                                      %s\n"
+		"       Store bad packets:                             %s\n"
+		"       Unicast promiscuous:                           %s\n"
+		"       Multicast promiscuous:                         %s\n"
+		"       Long packet:                                   %s\n"
+		"       Descriptor minimum threshold size:             %s\n"
+		"       Broadcast accept mode:                         %s\n"
+		"       VLAN filter:                                   %s\n"
+		"       Cononical form indicator:                      %s\n"
+		"       Discard pause frames:                          %s\n"
+		"       Pass MAC control frames:                       %s\n"
+		"       Loopback mode:                                 %s\n",
+		reg,
+		reg & E1000_RCTL_EN      ? "enabled"  : "disabled",
+		reg & E1000_RCTL_SBP     ? "enabled"  : "disabled",
+		reg & E1000_RCTL_UPE     ? "enabled"  : "disabled",
+		reg & E1000_RCTL_MPE     ? "enabled"  : "disabled",
+		reg & E1000_RCTL_LPE     ? "enabled"  : "disabled",
+		(reg & E1000_RCTL_RDMTS) == E1000_RCTL_RDMTS_HALF  ? "1/2" :
+		(reg & E1000_RCTL_RDMTS) == E1000_RCTL_RDMTS_QUAT  ? "1/4" :
+		(reg & E1000_RCTL_RDMTS) == E1000_RCTL_RDMTS_EIGTH ? "1/8" :
+		"reserved",
+		reg & E1000_RCTL_BAM      ? "accept"   : "ignore",
+		reg & E1000_RCTL_VFE      ? "enabled"  : "disabled",
+		reg & E1000_RCTL_CFIEN    ? "enabled"  : "disabled",
+		reg & E1000_RCTL_DPF      ? "ignored"  : "filtered",
+		reg & E1000_RCTL_PMCF     ? "pass"     : "don't pass",
+		(reg & E1000_RCTL_LBM_MASK) == E1000_RCTL_LBM_NORM   ? "normal" :
+		(reg & E1000_RCTL_LBM_MASK) == E1000_RCTL_LBM_MAC    ? "MAC":
+		(reg & E1000_RCTL_LBM_MASK) == E1000_RCTL_LBM_SERDES ? "SERDES":
+		"undefined");
+	fprintf(stdout,
+		"       Receive buffer size:                           %s\n",
+		(reg & E1000_RCTL_BSIZE)==E1000_RCTL_BSIZE_2048  ? "2048"  :
+		(reg & E1000_RCTL_BSIZE)==E1000_RCTL_BSIZE_1024  ? "1024"  :
+		(reg & E1000_RCTL_BSIZE)==E1000_RCTL_BSIZE_512   ? "512"   :
+		"256");
+
+	/* Receive descriptor registers */
+	fprintf(stdout,
+		"0x02808: RDLEN  (Receive desc length)                 0x%08X\n",
+		regs_buff[137]);
+	fprintf(stdout,
+		"0x02810: RDH    (Receive desc head)                   0x%08X\n",
+		regs_buff[141]);
+	fprintf(stdout,
+		"0x02818: RDT    (Receive desc tail)                   0x%08X\n",
+		regs_buff[145]);
+
+	/* Transmit control register */
+	reg = regs_buff[38];
+	fprintf(stdout,
+		"0x00400: TCTL (Transmit ctrl register)                0x%08X\n"
+		"       Transmitter:                                   %s\n"
+		"       Pad short packets:                             %s\n"
+		"       Software XOFF Transmission:                    %s\n",
+		reg,
+		reg & E1000_TCTL_EN      ? "enabled"  : "disabled",
+		reg & E1000_TCTL_PSP     ? "enabled"  : "disabled",
+		reg & E1000_TCTL_SWXOFF  ? "enabled"  : "disabled");
+	fprintf(stdout,
+		"       Re-transmit on late collision:                 %s\n",
+		reg & E1000_TCTL_RTLC    ? "enabled"  : "disabled");
+
+	/* Transmit descriptor registers */
+	fprintf(stdout,
+		"0x03808: TDLEN       (Transmit desc length)           0x%08X\n",
+		regs_buff[219]);
+	fprintf(stdout,
+		"0x03810: TDH         (Transmit desc head)             0x%08X\n",
+		regs_buff[223]);
+	fprintf(stdout,
+		"0x03818: TDT         (Transmit desc tail)             0x%08X\n",
+		regs_buff[227]);
+
+
+	fprintf(stdout,
+		"0x00018: CTRL_EXT    (Extended device control)        0x%08X\n",
+		regs_buff[2]);
+
+	fprintf(stdout,
+		"0x00018: MDIC        (MDI control)                    0x%08X\n",
+		regs_buff[3]);
+
+	fprintf(stdout,
+		"0x00024: SCTL        (SERDES ANA)                     0x%08X\n",
+		regs_buff[4]);
+
+	fprintf(stdout,
+		"0x00034: CONNSW      (Copper/Fiber switch control)    0x%08X\n",
+		regs_buff[5]);
+
+	fprintf(stdout,
+		"0x00038: VET         (VLAN Ether type)                0x%08X\n",
+		regs_buff[6]);
+
+	fprintf(stdout,
+		"0x00E00: LEDCTL      (LED control)                    0x%08X\n",
+		regs_buff[7]);
+
+	fprintf(stdout,
+		"0x01000: PBA         (Packet buffer allocation)       0x%08X\n",
+		regs_buff[8]);
+
+	fprintf(stdout,
+		"0x01008: PBS         (Packet buffer size)             0x%08X\n",
+		regs_buff[9]);
+
+	fprintf(stdout,
+		"0x01048: FRTIMER     (Free running timer)             0x%08X\n",
+		regs_buff[10]);
+
+	fprintf(stdout,
+		"0x0104C: TCPTIMER    (TCP timer)                      0x%08X\n",
+		regs_buff[11]);
+
+	fprintf(stdout,
+		"0x00010: EEC         (EEPROM/FLASH control)           0x%08X\n",
+		regs_buff[12]);
+
+	fprintf(stdout,
+		"0x01580: EICR        (Extended interrupt cause)       0x%08X\n",
+		regs_buff[13]);
+
+	fprintf(stdout,
+		"0x01520: EICS        (Extended interrupt cause set)   0x%08X\n",
+		regs_buff[14]);
+
+	fprintf(stdout,
+		"0x01524: EIMS        (Extended interrup set/read)     0x%08X\n",
+		regs_buff[15]);
+
+	fprintf(stdout,
+		"0x01528: EIMC        (Extended interrupt mask clear)  0x%08X\n",
+		regs_buff[16]);
+
+	fprintf(stdout,
+		"0x0152C: EIAC        (Extended interrupt auto clear)  0x%08X\n",
+		regs_buff[17]);
+
+	fprintf(stdout,
+		"0x01530: EIAM        (Extended interrupt auto mask)   0x%08X\n",
+		regs_buff[18]);
+
+	fprintf(stdout,
+		"0x01500: ICR         (Interrupt cause read)           0x%08X\n",
+		regs_buff[19]);
+
+	fprintf(stdout,
+		"0x01504: ICS         (Interrupt cause set)            0x%08X\n",
+		regs_buff[20]);
+
+	fprintf(stdout,
+		"0x01508: IMS         (Interrupt mask set/read)        0x%08X\n",
+		regs_buff[21]);
+
+	fprintf(stdout,
+		"0x0150C: IMC         (Interrupt mask clear)           0x%08X\n",
+		regs_buff[22]);
+
+	fprintf(stdout,
+		"0x04100: IAC         (Interrupt assertion count)      0x%08X\n",
+		regs_buff[23]);
+
+	fprintf(stdout,
+		"0x01510: IAM         (Interr acknowledge auto-mask)   0x%08X\n",
+		regs_buff[24]);
+
+	fprintf(stdout,
+		"0x05AC0: IMIRVP      (Immed interr rx VLAN priority)  0x%08X\n",
+		regs_buff[25]);
+
+	fprintf(stdout,
+		"0x00028: FCAL        (Flow control address low)       0x%08X\n",
+		regs_buff[26]);
+
+	fprintf(stdout,
+		"0x0002C: FCAH        (Flow control address high)      0x%08X\n",
+		regs_buff[27]);
+
+	fprintf(stdout,
+		"0x00170: FCTTV       (Flow control tx timer value)    0x%08X\n",
+		regs_buff[28]);
+
+	fprintf(stdout,
+		"0x02160: FCRTL       (Flow control rx threshold low)  0x%08X\n",
+		regs_buff[29]);
+
+	fprintf(stdout,
+		"0x02168: FCRTH       (Flow control rx threshold high) 0x%08X\n",
+		regs_buff[30]);
+
+	fprintf(stdout,
+		"0x02460: FCRTV       (Flow control refresh threshold) 0x%08X\n",
+		regs_buff[31]);
+
+	fprintf(stdout,
+		"0x05000: RXCSUM      (Receive checksum control)       0x%08X\n",
+		regs_buff[33]);
+
+	fprintf(stdout,
+		"0x05004: RLPML       (Receive long packet max length) 0x%08X\n",
+		regs_buff[34]);
+
+	fprintf(stdout,
+		"0x05008: RFCTL       (Receive filter control)         0x%08X\n",
+		regs_buff[35]);
+
+	fprintf(stdout,
+		"0x05818: MRQC        (Multiple rx queues command)     0x%08X\n",
+		regs_buff[36]);
+
+	fprintf(stdout,
+		"0x0581C: VMD_CTL     (VMDq control)                   0x%08X\n",
+		regs_buff[37]);
+
+	fprintf(stdout,
+		"0x00404: TCTL_EXT    (Transmit control extended)      0x%08X\n",
+		regs_buff[39]);
+
+	fprintf(stdout,
+		"0x00410: TIPG        (Transmit IPG)                   0x%08X\n",
+		regs_buff[40]);
+
+	fprintf(stdout,
+		"0x03590: DTXCTL      (DMA tx control)                 0x%08X\n",
+		regs_buff[41]);
+
+	fprintf(stdout,
+		"0x05800: WUC         (Wake up control)                0x%08X\n",
+		regs_buff[42]);
+
+	fprintf(stdout,
+		"0x05808: WUFC        (Wake up filter control)         0x%08X\n",
+		regs_buff[43]);
+
+	fprintf(stdout,
+		"0x05810: WUS         (Wake up status)                 0x%08X\n",
+		regs_buff[44]);
+
+	fprintf(stdout,
+		"0x05838: IPAV        (IP address valid)               0x%08X\n",
+		regs_buff[45]);
+
+	fprintf(stdout,
+		"0x05900: WUPL        (Wake up packet length)          0x%08X\n",
+		regs_buff[46]);
+
+	fprintf(stdout,
+		"0x04200: PCS_CFG     (PCS configuration 0)            0x%08X\n",
+		regs_buff[47]);
+
+	fprintf(stdout,
+		"0x04208: PCS_LCTL    (PCS link control)               0x%08X\n",
+		regs_buff[48]);
+
+	fprintf(stdout,
+		"0x0420C: PCS_LSTS    (PCS link status)                0x%08X\n",
+		regs_buff[49]);
+
+	fprintf(stdout,
+		"0x04218: PCS_ANADV   (AN advertisement)               0x%08X\n",
+		regs_buff[50]);
+
+	fprintf(stdout,
+		"0x0421C: PCS_LPAB    (Link partner ability)           0x%08X\n",
+		regs_buff[51]);
+
+	fprintf(stdout,
+		"0x04220: PCS_NPTX    (Next Page transmit)             0x%08X\n",
+		regs_buff[52]);
+
+	fprintf(stdout,
+		"0x04224: PCS_LPABNP  (Link partner ability Next Page) 0x%08X\n",
+		regs_buff[53]);
+
+	fprintf(stdout,
+		"0x04000: CRCERRS     (CRC error count)                0x%08X\n",
+		regs_buff[54]);
+
+	fprintf(stdout,
+		"0x04004: ALGNERRC    (Alignment error count)          0x%08X\n",
+		regs_buff[55]);
+
+	fprintf(stdout,
+		"0x04008: SYMERRS     (Symbol error count)             0x%08X\n",
+		regs_buff[56]);
+
+	fprintf(stdout,
+		"0x0400C: RXERRC      (RX error count)                 0x%08X\n",
+		regs_buff[57]);
+
+	fprintf(stdout,
+		"0x04010: MPC         (Missed packets count)           0x%08X\n",
+		regs_buff[58]);
+
+	fprintf(stdout,
+		"0x04014: SCC         (Single collision count)         0x%08X\n",
+		regs_buff[59]);
+
+	fprintf(stdout,
+		"0x04018: ECOL        (Excessive collisions count)     0x%08X\n",
+		regs_buff[60]);
+
+	fprintf(stdout,
+		"0x0401C: MCC         (Multiple collision count)       0x%08X\n",
+		regs_buff[61]);
+
+	fprintf(stdout,
+		"0x04020: LATECOL     (Late collisions count)          0x%08X\n",
+		regs_buff[62]);
+
+	fprintf(stdout,
+		"0x04028: COLC        (Collision count)                0x%08X\n",
+		regs_buff[63]);
+
+	fprintf(stdout,
+		"0x04030: DC          (Defer count)                    0x%08X\n",
+		regs_buff[64]);
+
+	fprintf(stdout,
+		"0x04034: TNCRS       (Transmit with no CRS)           0x%08X\n",
+		regs_buff[65]);
+
+	fprintf(stdout,
+		"0x04038: SEC         (Sequence error count)           0x%08X\n",
+		regs_buff[66]);
+
+	fprintf(stdout,
+		"0x0403C: HTDPMC      (Host tx discrd pkts MAC count)  0x%08X\n",
+		regs_buff[67]);
+
+	fprintf(stdout,
+		"0x04040: RLEC        (Receive length error count)     0x%08X\n",
+		regs_buff[68]);
+
+	fprintf(stdout,
+		"0x04048: XONRXC      (XON received count)             0x%08X\n",
+		regs_buff[69]);
+
+	fprintf(stdout,
+		"0x0404C: XONTXC      (XON transmitted count)          0x%08X\n",
+		regs_buff[70]);
+
+	fprintf(stdout,
+		"0x04050: XOFFRXC     (XOFF received count)            0x%08X\n",
+		regs_buff[71]);
+
+	fprintf(stdout,
+		"0x04054: XOFFTXC     (XOFF transmitted count)         0x%08X\n",
+		regs_buff[72]);
+
+	fprintf(stdout,
+		"0x04058: FCRUC       (FC received unsupported count)  0x%08X\n",
+		regs_buff[73]);
+
+	fprintf(stdout,
+		"0x0405C: PRC64       (Packets rx (64 B) count)        0x%08X\n",
+		regs_buff[74]);
+
+	fprintf(stdout,
+		"0x04060: PRC127      (Packets rx (65-127 B) count)    0x%08X\n",
+		regs_buff[75]);
+
+	fprintf(stdout,
+		"0x04064: PRC255      (Packets rx (128-255 B) count)   0x%08X\n",
+		regs_buff[76]);
+
+	fprintf(stdout,
+		"0x04068: PRC511      (Packets rx (256-511 B) count)   0x%08X\n",
+		regs_buff[77]);
+
+	fprintf(stdout,
+		"0x0406C: PRC1023     (Packets rx (512-1023 B) count)  0x%08X\n",
+		regs_buff[78]);
+
+	fprintf(stdout,
+		"0x04070: PRC1522     (Packets rx (1024-max B) count)  0x%08X\n",
+		regs_buff[79]);
+
+	fprintf(stdout,
+		"0x04074: GPRC        (Good packets received count)    0x%08X\n",
+		regs_buff[80]);
+
+	fprintf(stdout,
+		"0x04078: BPRC        (Broadcast packets rx count)     0x%08X\n",
+		regs_buff[81]);
+
+	fprintf(stdout,
+		"0x0407C: MPRC        (Multicast packets rx count)     0x%08X\n",
+		regs_buff[82]);
+
+	fprintf(stdout,
+		"0x04080: GPTC        (Good packets tx count)          0x%08X\n",
+		regs_buff[83]);
+
+	fprintf(stdout,
+		"0x04088: GORCL       (Good octets rx count lower)     0x%08X\n",
+		regs_buff[84]);
+
+	fprintf(stdout,
+		"0x0408C: GORCH       (Good octets rx count upper)     0x%08X\n",
+		regs_buff[85]);
+
+	fprintf(stdout,
+		"0x04090: GOTCL       (Good octets tx count lower)     0x%08X\n",
+		regs_buff[86]);
+
+	fprintf(stdout,
+		"0x04094: GOTCH       (Good octets tx count upper)     0x%08X\n",
+		regs_buff[87]);
+
+	fprintf(stdout,
+		"0x040A0: RNBC        (Receive no buffers count)       0x%08X\n",
+		regs_buff[88]);
+
+	fprintf(stdout,
+		"0x040A4: RUC         (Receive undersize count)        0x%08X\n",
+		regs_buff[89]);
+
+	fprintf(stdout,
+		"0x040A8: RFC         (Receive fragment count)         0x%08X\n",
+		regs_buff[90]);
+
+	fprintf(stdout,
+		"0x040AC: ROC         (Receive oversize count)         0x%08X\n",
+		regs_buff[91]);
+
+	fprintf(stdout,
+		"0x040B0: RJC         (Receive jabber count)           0x%08X\n",
+		regs_buff[92]);
+
+	fprintf(stdout,
+		"0x040B4: MGPRC       (Management packets rx count)    0x%08X\n",
+		regs_buff[93]);
+
+	fprintf(stdout,
+		"0x040B8: MGPDC       (Management pkts dropped count)  0x%08X\n",
+		regs_buff[94]);
+
+	fprintf(stdout,
+		"0x040BC: MGPTC       (Management packets tx count)    0x%08X\n",
+		regs_buff[95]);
+
+	fprintf(stdout,
+		"0x040C0: TORL        (Total octets received lower)    0x%08X\n",
+		regs_buff[96]);
+
+	fprintf(stdout,
+		"0x040C4: TORH        (Total octets received upper)    0x%08X\n",
+		regs_buff[97]);
+
+	fprintf(stdout,
+		"0x040C8: TOTL        (Total octets transmitted lower) 0x%08X\n",
+		regs_buff[98]);
+
+	fprintf(stdout,
+		"0x040CC: TOTH        (Total octets transmitted upper) 0x%08X\n",
+		regs_buff[99]);
+
+	fprintf(stdout,
+		"0x040D0: TPR         (Total packets received)         0x%08X\n",
+		regs_buff[100]);
+
+	fprintf(stdout,
+		"0x040D4: TPT         (Total packets transmitted)      0x%08X\n",
+		regs_buff[101]);
+
+	fprintf(stdout,
+		"0x040D8: PTC64       (Packets tx (64 B) count)        0x%08X\n",
+		regs_buff[102]);
+
+	fprintf(stdout,
+		"0x040DC: PTC127      (Packets tx (65-127 B) count)    0x%08X\n",
+		regs_buff[103]);
+
+	fprintf(stdout,
+		"0x040E0: PTC255      (Packets tx (128-255 B) count)   0x%08X\n",
+		regs_buff[104]);
+
+	fprintf(stdout,
+		"0x040E4: PTC511      (Packets tx (256-511 B) count)   0x%08X\n",
+		regs_buff[105]);
+
+	fprintf(stdout,
+		"0x040E8: PTC1023     (Packets tx (512-1023 B) count)  0x%08X\n",
+		regs_buff[106]);
+
+	fprintf(stdout,
+		"0x040EC: PTC1522     (Packets tx (> 1024 B) count)    0x%08X\n",
+		regs_buff[107]);
+
+	fprintf(stdout,
+		"0x040F0: MPTC        (Multicast packets tx count)     0x%08X\n",
+		regs_buff[108]);
+
+	fprintf(stdout,
+		"0x040F4: BPTC        (Broadcast packets tx count)     0x%08X\n",
+		regs_buff[109]);
+
+	fprintf(stdout,
+		"0x040F8: TSCTC       (TCP segment context tx count)   0x%08X\n",
+		regs_buff[110]);
+
+	fprintf(stdout,
+		"0x04100: IAC         (Interrupt assertion count)      0x%08X\n",
+		regs_buff[111]);
+
+	fprintf(stdout,
+		"0x04104: RPTHC       (Rx packets to host count)       0x%08X\n",
+		regs_buff[112]);
+
+	fprintf(stdout,
+		"0x04118: HGPTC       (Host good packets tx count)     0x%08X\n",
+		regs_buff[113]);
+
+	fprintf(stdout,
+		"0x04128: HGORCL      (Host good octets rx cnt lower)  0x%08X\n",
+		regs_buff[114]);
+
+	fprintf(stdout,
+		"0x0412C: HGORCH      (Host good octets rx cnt upper)  0x%08X\n",
+		regs_buff[115]);
+
+	fprintf(stdout,
+		"0x04130: HGOTCL      (Host good octets tx cnt lower)  0x%08X\n",
+		regs_buff[116]);
+
+	fprintf(stdout,
+		"0x04134: HGOTCH      (Host good octets tx cnt upper)  0x%08X\n",
+		regs_buff[117]);
+
+	fprintf(stdout,
+		"0x04138: LENNERS     (Length error count)             0x%08X\n",
+		regs_buff[118]);
+
+	fprintf(stdout,
+		"0x04228: SCVPC       (SerDes/SGMII code viol pkt cnt) 0x%08X\n",
+		regs_buff[119]);
+
+	fprintf(stdout,
+		"0x0A018: HRMPC       (Header redir missed pkt count)  0x%08X\n",
+		regs_buff[120]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: SRRCTL%d     (Split and replic rx ctl%d)       0x%08X\n",
+		0x0280C + (0x100 * i), i, i, regs_buff[121 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: PSRTYPE%d    (Packet split receive type%d)     0x%08X\n",
+		0x05480 + (0x4 * i), i, i, regs_buff[125 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: RDBAL%d      (Rx desc base addr low%d)         0x%08X\n",
+		0x02800 + (0x100 * i), i, i, regs_buff[129 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: RDBAH%d      (Rx desc base addr high%d)        0x%08X\n",
+		0x02804 + (0x100 * i), i, i, regs_buff[133 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: RDLEN%d      (Rx descriptor length%d)          0x%08X\n",
+		0x02808 + (0x100 * i), i, i, regs_buff[137 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: RDH%d        (Rx descriptor head%d)            0x%08X\n",
+		0x02810 + (0x100 * i), i, i, regs_buff[141 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: RDT%d        (Rx descriptor tail%d)            0x%08X\n",
+		0x02818 + (0x100 * i), i, i, regs_buff[145 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: RXDCTL%d     (Rx descriptor control%d)         0x%08X\n",
+		0x02828 + (0x100 * i), i, i, regs_buff[149 + i]);
+
+	for (i = 0; i < 10; i++)
+		fprintf(stdout,
+		"0x0%02X: EITR%d       (Interrupt throttle%d)            0x%08X\n",
+		0x01680 + (0x4 * i), i, i, regs_buff[153 + i]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x0%02X: IMIR%d       (Immediate interrupt Rx%d)        0x%08X\n",
+		0x05A80 + (0x4 * i), i, i, regs_buff[163 + i]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x0%02X: IMIREXT%d    (Immediate interr Rx extended%d)  0x%08X\n",
+		0x05AA0 + (0x4 * i), i, i, regs_buff[171 + i]);
+
+	for (i = 0; i < 16; i++)
+		fprintf(stdout,
+		"0x0%02X: RAL%02d       (Receive address low%02d)          0x%08X\n",
+		0x05400 + (0x8 * i), i,i, regs_buff[179 + i]);
+
+	for (i = 0; i < 16; i++)
+		fprintf(stdout,
+		"0x0%02X: RAH%02d       (Receive address high%02d)         0x%08X\n",
+		0x05404 + (0x8 * i), i, i, regs_buff[195 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: TDBAL%d      (Tx desc base address low%d)      0x%08X\n",
+		0x03800 + (0x100 * i), i, i, regs_buff[211 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: TDBAH%d      (Tx desc base address high%d)     0x%08X\n",
+		0x03804 + (0x100 * i), i, i, regs_buff[215 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: TDLEN%d      (Tx descriptor length%d)          0x%08X\n",
+		0x03808 + (0x100 * i), i, i, regs_buff[219 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: TDH%d        (Transmit descriptor head%d)      0x%08X\n",
+		0x03810 + (0x100 * i), i, i, regs_buff[223 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: TDT%d        (Transmit descriptor tail%d)      0x%08X\n",
+		0x03818 + (0x100 * i), i, i, regs_buff[227 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: TXDCTL%d     (Transmit descriptor control%d)   0x%08X\n",
+		0x03828 + (0x100 * i), i, i, regs_buff[231 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: TDWBAL%d     (Tx desc complete wb addr low%d)  0x%08X\n",
+		0x03838 + (0x100 * i), i, i, regs_buff[235 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: TDWBAH%d     (Tx desc complete wb addr hi%d)   0x%08X\n",
+		0x0383C + (0x100 * i), i, i, regs_buff[239 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: DCA_TXCTRL%d (Tx DCA control%d)                0x%08X\n",
+		0x03814 + (0x100 * i), i, i, regs_buff[243 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: IP4AT%d      (IPv4 address table%d)            0x%08X\n",
+		0x05840 + (0x8 * i), i, i, regs_buff[247 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: IP6AT%d      (IPv6 address table%d)            0x%08X\n",
+		0x05880 + (0x4 * i), i, i, regs_buff[251 + i]);
+
+	for (i = 0; i < 32; i++)
+		fprintf(stdout,
+		"0x0%02X: WUPM%02d      (Wake up packet memory%02d)        0x%08X\n",
+		0x05A00 + (0x4 * i), i, i, regs_buff[255 + i]);
+
+	for (i = 0; i < 128; i++)
+		fprintf(stdout,
+		"0x0%02X: FFMT%03d     (Flexible filter mask table%03d)  0x%08X\n",
+		0x09000 + (0x8 * i), i, i, regs_buff[287 + i]);
+
+	for (i = 0; i < 128; i++)
+		fprintf(stdout,
+		"0x0%02X: FFVT%03d     (Flexible filter value table%03d) 0x%08X\n",
+		0x09800 + (0x8 * i), i, i, regs_buff[415 + i]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x0%02X: FFLT%d       (Flexible filter length table%d)  0x%08X\n",
+		0x05F00 + (0x8 * i), i, i, regs_buff[543 + i]);
+
+	fprintf(stdout,
+		"0x03410: TDFH        (Tx data FIFO head)              0x%08X\n",
+		regs_buff[547]);
+
+	fprintf(stdout,
+		"0x03418: TDFT        (Tx data FIFO tail)              0x%08X\n",
+		regs_buff[548]);
+
+	fprintf(stdout,
+		"0x03420: TDFHS       (Tx data FIFO head saved)        0x%08X\n",
+		regs_buff[549]);
+
+	fprintf(stdout,
+		"0x03430: TDFPC       (Tx data FIFO packet count)      0x%08X\n",
+		regs_buff[550]);
+
+	/*
+	 * Starting from kernel version 5.3 the registers dump buffer grew from
+	 * 739 4-byte words to 740 words, and word 740 contains the RR2DCDELAY
+	 * register.
+	 */
+	if (regs->len < 740)
+		return 0;
+
+	fprintf(stdout,
+		"0x05BF4: RR2DCDELAY  (Max. DMA read delay)            0x%08X\n",
+		regs_buff[739]);
+
+	return 0;
+}
+
diff --git a/internal.h b/internal.h
new file mode 100644
index 0000000..ff52c6e
--- /dev/null
+++ b/internal.h
@@ -0,0 +1,365 @@
+/* Portions Copyright 2001 Sun Microsystems (thockin@sun.com) */
+/* Portions Copyright 2002 Intel (scott.feldman@intel.com) */
+#ifndef ETHTOOL_INTERNAL_H__
+#define ETHTOOL_INTERNAL_H__
+
+/* Some platforms (eg. ppc64) need __SANE_USERSPACE_TYPES__ before
+ * <linux/types.h> to select 'int-ll64.h' and avoid compile warnings
+ * when printing __u64 with %llu.
+ */
+#define __SANE_USERSPACE_TYPES__
+
+#ifdef HAVE_CONFIG_H
+#include "ethtool-config.h"
+#endif
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <endian.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+#define maybe_unused __attribute__((__unused__))
+
+/* ethtool.h expects these to be defined by <linux/types.h> */
+#ifndef HAVE_BE_TYPES
+typedef uint16_t __be16;
+typedef uint32_t __be32;
+typedef unsigned long long __be64;
+#endif
+
+typedef unsigned long long u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+typedef int32_t s32;
+
+/* ethtool.h epxects __KERNEL_DIV_ROUND_UP to be defined by <linux/kernel.h> */
+#include <linux/kernel.h>
+#ifndef __KERNEL_DIV_ROUND_UP
+#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+#endif
+
+#include "ethtool-copy.h"
+#include "net_tstamp-copy.h"
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+static inline u16 cpu_to_be16(u16 value)
+{
+	return value;
+}
+static inline u32 cpu_to_be32(u32 value)
+{
+	return value;
+}
+static inline u64 cpu_to_be64(u64 value)
+{
+	return value;
+}
+#else
+static inline u16 cpu_to_be16(u16 value)
+{
+	return (value >> 8) | (value << 8);
+}
+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
+
+#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(unsigned int nr, unsigned long *addr)
+{
+	addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
+}
+
+static inline void clear_bit(unsigned 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]));
+}
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+#ifndef SIOCETHTOOL
+#define SIOCETHTOOL     0x8946
+#endif
+
+/* Internal values for old-style offload flags.  Values and names
+ * must not clash with the flags defined for ETHTOOL_{G,S}FLAGS.
+ */
+#define ETH_FLAG_RXCSUM		(1 << 0)
+#define ETH_FLAG_TXCSUM		(1 << 1)
+#define ETH_FLAG_SG		(1 << 2)
+#define ETH_FLAG_TSO		(1 << 3)
+#define ETH_FLAG_UFO		(1 << 4)
+#define ETH_FLAG_GSO		(1 << 5)
+#define ETH_FLAG_GRO		(1 << 6)
+#define ETH_FLAG_INT_MASK	(ETH_FLAG_RXCSUM | ETH_FLAG_TXCSUM |	\
+				 ETH_FLAG_SG | ETH_FLAG_TSO | ETH_FLAG_UFO | \
+				 ETH_FLAG_GSO | ETH_FLAG_GRO),
+/* Mask of all flags defined for ETHTOOL_{G,S}FLAGS. */
+#define ETH_FLAG_EXT_MASK	(ETH_FLAG_LRO | ETH_FLAG_RXVLAN |	\
+				 ETH_FLAG_TXVLAN | ETH_FLAG_NTUPLE |	\
+				 ETH_FLAG_RXHASH)
+
+/* internal API for link mode bitmap interaction with kernel. */
+
+#define ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32		\
+	(SCHAR_MAX)
+#define ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBITS		\
+	(32 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32)
+#define ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES	\
+	(4 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32)
+#define ETHTOOL_DECLARE_LINK_MODE_MASK(name)		\
+	u32 name[ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32]
+
+struct ethtool_link_usettings {
+	struct {
+		__u8 transceiver;
+	} deprecated;
+	struct ethtool_link_settings base;
+	struct {
+		ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+		ETHTOOL_DECLARE_LINK_MODE_MASK(advertising);
+		ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising);
+	} link_modes;
+};
+
+#define ethtool_link_mode_for_each_u32(index)			\
+	for ((index) = 0;					\
+	     (index) < ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32;	\
+	     ++(index))
+
+static inline void ethtool_link_mode_zero(u32 *dst)
+{
+	memset(dst, 0, ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES);
+}
+
+static inline bool ethtool_link_mode_is_empty(const u32 *mask)
+{
+	unsigned int i;
+
+	ethtool_link_mode_for_each_u32(i) {
+		if (mask[i] != 0)
+			return false;
+	}
+
+	return true;
+}
+
+static inline void ethtool_link_mode_copy(u32 *dst, const u32 *src)
+{
+	memcpy(dst, src, ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES);
+}
+
+static inline int ethtool_link_mode_test_bit(unsigned int nr, const u32 *mask)
+{
+	if (nr >= ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBITS)
+		return !!0;
+	return !!(mask[nr / 32] & (1 << (nr % 32)));
+}
+
+static inline int ethtool_link_mode_set_bit(unsigned int nr, u32 *mask)
+{
+	if (nr >= ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBITS)
+		return -1;
+	mask[nr / 32] |= (1 << (nr % 32));
+	return 0;
+}
+
+/* Context for sub-commands */
+struct cmd_context {
+	const char *devname;	/* net device name */
+	int fd;			/* socket suitable for ethtool ioctl */
+	struct ifreq ifr;	/* ifreq suitable for ethtool ioctl */
+	int argc;		/* number of arguments to the sub-command */
+	char **argp;		/* arguments to the sub-command */
+};
+
+#ifdef TEST_ETHTOOL
+int test_cmdline(const char *args);
+
+struct cmd_expect {
+	const void *cmd;	/* expected command; NULL at end of list */
+	size_t cmd_len;		/* length to match (might be < sizeof struct) */
+	int rc;			/* kernel return code */
+	const void *resp;	/* response to write back; may be NULL */
+	size_t resp_len;	/* length to write back */
+};
+int test_ioctl(const struct cmd_expect *expect, void *cmd);
+#define TEST_IOCTL_MISMATCH (-2)
+
+int test_main(int argc, char **argp);
+void test_exit(int rc) __attribute__((noreturn));
+
+#ifndef TEST_NO_WRAPPERS
+#define main(...) test_main(__VA_ARGS__)
+#undef exit
+#define exit(rc) test_exit(rc)
+void *test_malloc(size_t size);
+#undef malloc
+#define malloc(size) test_malloc(size)
+void *test_calloc(size_t nmemb, size_t size);
+#undef calloc
+#define calloc(nmemb, size) test_calloc(nmemb, size)
+char *test_strdup(const char *s);
+#undef strdup
+#define strdup(s) test_strdup(s)
+void test_free(void *ptr);
+#undef free
+#define free(ptr) test_free(ptr)
+void *test_realloc(void *ptr, size_t size);
+#undef realloc
+#define realloc(ptr, size) test_realloc(ptr, size)
+int test_open(const char *pathname, int flag, ...);
+#undef open
+#define open(...) test_open(__VA_ARGS__)
+int test_socket(int domain, int type, int protocol);
+#undef socket
+#define socket(...) test_socket(__VA_ARGS__)
+int test_close(int fd);
+#undef close
+#define close(fd) test_close(fd)
+FILE *test_fopen(const char *path, const char *mode);
+#undef fopen
+#define fopen(path, mode) test_fopen(path, mode)
+int test_fclose(FILE *fh);
+#undef fclose
+#define fclose(fh) test_fclose(fh)
+#endif
+#endif
+
+int send_ioctl(struct cmd_context *ctx, void *cmd);
+
+void dump_hex(FILE *f, const u8 *data, int len, int offset);
+
+/* National Semiconductor DP83815, DP83816 */
+int natsemi_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+int natsemi_dump_eeprom(struct ethtool_drvinfo *info,
+	struct ethtool_eeprom *ee);
+
+/* Digital/Intel 21040 and 21041 */
+int de2104x_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Intel(R) PRO/1000 Gigabit Adapter Family */
+int e1000_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+int igb_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* RealTek PCI */
+int realtek_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Intel(R) PRO/100 Fast Ethernet Adapter Family */
+int e100_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Tigon3 */
+int tg3_dump_eeprom(struct ethtool_drvinfo *info, struct ethtool_eeprom *ee);
+
+/* Advanced Micro Devices  AMD8111 based Adapter */
+int amd8111e_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Advanced Micro Devices PCnet32 Adapter */
+int pcnet32_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Motorola 8xx FEC Ethernet controller */
+int fec_8xx_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* PowerPC 4xx on-chip Ethernet controller */
+int ibm_emac_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Intel(R) PRO/10GBe Gigabit Adapter Family */
+int ixgb_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+int ixgbe_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+int ixgbevf_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Broadcom Tigon3 Ethernet controller */
+int tg3_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* SysKonnect Gigabit (Genesis and Yukon) */
+int skge_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* SysKonnect Gigabit (Yukon2) */
+int sky2_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Fabric7 VIOC */
+int vioc_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* SMSC LAN911x/LAN921x embedded ethernet controller */
+int smsc911x_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+int at76c50x_usb_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Solarflare Solarstorm controllers */
+int sfc_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* STMMAC embedded ethernet controller */
+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);
+
+/* Et131x ethernet controller */
+int et131x_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Altera TSE 10/100/1000 ethernet controller */
+int altera_tse_dump_regs(struct ethtool_drvinfo *info,
+			 struct ethtool_regs *regs);
+
+/* VMware vmxnet3 ethernet controller */
+int vmxnet3_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Rx flow classification */
+int rxclass_parse_ruleopts(struct cmd_context *ctx,
+			   struct ethtool_rx_flow_spec *fsp, __u32 *rss_context);
+int rxclass_rule_getall(struct cmd_context *ctx);
+int rxclass_rule_get(struct cmd_context *ctx, __u32 loc);
+int rxclass_rule_ins(struct cmd_context *ctx,
+		     struct ethtool_rx_flow_spec *fsp, __u32 rss_context);
+int rxclass_rule_del(struct cmd_context *ctx, __u32 loc);
+
+/* Module EEPROM parsing code */
+void sff8079_show_all(const __u8 *id);
+
+/* Optics diagnostics */
+void sff8472_show_all(const __u8 *id);
+
+/* QSFP Optics diagnostics */
+void sff8636_show_all(const __u8 *id, __u32 eeprom_len);
+
+/* FUJITSU Extended Socket network device */
+int fjes_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* MICROCHIP LAN78XX USB ETHERNET Controller */
+int lan78xx_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Distributed Switch Architecture */
+int dsa_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* i.MX Fast Ethernet Controller */
+int fec_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+#endif /* ETHTOOL_INTERNAL_H__ */
diff --git a/ixgb.c b/ixgb.c
new file mode 100644
index 0000000..7c16c6e
--- /dev/null
+++ b/ixgb.c
@@ -0,0 +1,147 @@
+/* Copyright (c) 2006 Intel Corporation */
+#include <stdio.h>
+#include "internal.h"
+
+/* CTRL0 Bit Masks */
+#define IXGB_CTRL0_LRST           0x00000008
+#define IXGB_CTRL0_VME            0x40000000
+
+/* STATUS Bit Masks */
+#define IXGB_STATUS_LU            0x00000002
+#define IXGB_STATUS_BUS64         0x00001000
+#define IXGB_STATUS_PCIX_MODE     0x00002000
+#define IXGB_STATUS_PCIX_SPD_100  0x00004000
+#define IXGB_STATUS_PCIX_SPD_133  0x00008000
+
+/* RCTL Bit Masks */
+#define IXGB_RCTL_RXEN            0x00000002
+#define IXGB_RCTL_SBP             0x00000004
+#define IXGB_RCTL_UPE             0x00000008
+#define IXGB_RCTL_MPE             0x00000010
+#define IXGB_RCTL_RDMTS_MASK      0x00000300
+#define IXGB_RCTL_RDMTS_1_2       0x00000000
+#define IXGB_RCTL_RDMTS_1_4       0x00000100
+#define IXGB_RCTL_RDMTS_1_8       0x00000200
+#define IXGB_RCTL_BAM             0x00008000
+#define IXGB_RCTL_BSIZE_MASK      0x00030000
+#define IXGB_RCTL_BSIZE_4096      0x00010000
+#define IXGB_RCTL_BSIZE_8192      0x00020000
+#define IXGB_RCTL_BSIZE_16384     0x00030000
+#define IXGB_RCTL_VFE             0x00040000
+#define IXGB_RCTL_CFIEN           0x00080000
+
+/* TCTL Bit Masks */
+#define IXGB_TCTL_TXEN            0x00000002
+
+/* RAH Bit Masks */
+#define IXGB_RAH_ASEL_DEST        0x00000000
+#define IXGB_RAH_ASEL_SRC         0x00010000
+#define IXGB_RAH_AV               0x80000000
+
+int ixgb_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		   struct ethtool_regs *regs)
+{
+	u32 *regs_buff = (u32 *)regs->data;
+	u8 version = (u8)(regs->version >> 24);
+	u32 reg;
+
+	if (version != 1)
+		return -1;
+	fprintf(stdout, "MAC Registers\n");
+	fprintf(stdout, "-------------\n");
+
+	/* Device control register */
+	reg = regs_buff[0];
+	fprintf(stdout,
+		"0x00000: CTRL0 (Device control register) 0x%08X\n"
+		"      Link reset:                        %s\n"
+		"      VLAN mode:                         %s\n",
+		reg,
+		reg & IXGB_CTRL0_LRST   ? "reset"    : "normal",
+		reg & IXGB_CTRL0_VME    ? "enabled"  : "disabled");
+
+	/* Device status register */
+	reg = regs_buff[2];
+	fprintf(stdout,
+		"0x00010: STATUS (Device status register) 0x%08X\n"
+		"      Link up:                           %s\n"
+		"      Bus type:                          %s\n"
+		"      Bus speed:                         %s\n"
+		"      Bus width:                         %s\n",
+		reg,
+		(reg & IXGB_STATUS_LU)        ? "link config" : "no link config",
+		(reg & IXGB_STATUS_PCIX_MODE) ? "PCI-X" : "PCI",
+			((reg & IXGB_STATUS_PCIX_SPD_133) ? "133MHz" :
+			(reg & IXGB_STATUS_PCIX_SPD_100) ? "100MHz" :
+			"66MHz"),
+		(reg & IXGB_STATUS_BUS64) ? "64-bit" : "32-bit");
+	/* Receive control register */
+	reg = regs_buff[9];
+	fprintf(stdout,
+		"0x00100: RCTL (Receive control register) 0x%08X\n"
+		"      Receiver:                          %s\n"
+		"      Store bad packets:                 %s\n"
+		"      Unicast promiscuous:               %s\n"
+		"      Multicast promiscuous:             %s\n"
+		"      Descriptor minimum threshold size: %s\n"
+		"      Broadcast accept mode:             %s\n"
+		"      VLAN filter:                       %s\n"
+		"      Cononical form indicator:          %s\n",
+		reg,
+		reg & IXGB_RCTL_RXEN    ? "enabled"  : "disabled",
+		reg & IXGB_RCTL_SBP     ? "enabled"  : "disabled",
+		reg & IXGB_RCTL_UPE     ? "enabled"  : "disabled",
+		reg & IXGB_RCTL_MPE     ? "enabled"  : "disabled",
+		(reg & IXGB_RCTL_RDMTS_MASK) == IXGB_RCTL_RDMTS_1_2 ? "1/2" :
+		(reg & IXGB_RCTL_RDMTS_MASK) == IXGB_RCTL_RDMTS_1_4 ? "1/4" :
+		(reg & IXGB_RCTL_RDMTS_MASK) == IXGB_RCTL_RDMTS_1_8 ? "1/8" :
+		"reserved",
+		reg & IXGB_RCTL_BAM     ? "accept"   : "ignore",
+		reg & IXGB_RCTL_VFE     ? "enabled"  : "disabled",
+		reg & IXGB_RCTL_CFIEN   ? "enabled"  : "disabled");
+	fprintf(stdout,
+		"      Receive buffer size:               %s\n",
+		(reg & IXGB_RCTL_BSIZE_MASK) == IXGB_RCTL_BSIZE_16384 ? "16384" :
+		(reg & IXGB_RCTL_BSIZE_MASK) == IXGB_RCTL_BSIZE_8192 ? "8192" :
+		(reg & IXGB_RCTL_BSIZE_MASK) == IXGB_RCTL_BSIZE_4096 ? "4096" :
+		"2048");
+
+	/* Receive descriptor registers */
+	fprintf(stdout,
+		"0x00120: RDLEN (Receive desc length)     0x%08X\n",
+		regs_buff[14]);
+	fprintf(stdout,
+		"0x00128: RDH   (Receive desc head)       0x%08X\n",
+		regs_buff[15]);
+	fprintf(stdout,
+		"0x00130: RDT   (Receive desc tail)       0x%08X\n",
+		regs_buff[16]);
+	fprintf(stdout,
+		"0x00138: RDTR  (Receive delay timer)     0x%08X\n",
+		regs_buff[17]);
+
+	/* Transmit control register */
+	reg = regs_buff[53];
+	fprintf(stdout,
+		"0x00600: TCTL (Transmit ctrl register)   0x%08X\n"
+		"      Transmitter:                       %s\n",
+		reg,
+		reg & IXGB_TCTL_TXEN      ? "enabled"  : "disabled");
+
+	/* Transmit descriptor registers */
+	fprintf(stdout,
+		"0x00610: TDLEN (Transmit desc length)    0x%08X\n",
+		regs_buff[56]);
+	fprintf(stdout,
+		"0x00618: TDH   (Transmit desc head)      0x%08X\n",
+		regs_buff[57]);
+	fprintf(stdout,
+		"0x00620: TDT   (Transmit desc tail)      0x%08X\n",
+		regs_buff[58]);
+	fprintf(stdout,
+		"0x00628: TIDV  (Transmit delay timer)    0x%08X\n",
+		regs_buff[59]);
+
+	return 0;
+}
+
diff --git a/ixgbe.c b/ixgbe.c
new file mode 100644
index 0000000..9754b2a
--- /dev/null
+++ b/ixgbe.c
@@ -0,0 +1,1296 @@
+/* Copyright (c) 2007 Intel Corporation */
+#include <stdio.h>
+#include "internal.h"
+
+/* Register Bit Masks */
+#define IXGBE_FCTRL_SBP            0x00000002
+#define IXGBE_FCTRL_MPE            0x00000100
+#define IXGBE_FCTRL_UPE            0x00000200
+#define IXGBE_FCTRL_BAM            0x00000400
+#define IXGBE_FCTRL_PMCF           0x00001000
+#define IXGBE_FCTRL_DPF            0x00002000
+#define IXGBE_FCTRL_RPFCE          0x00004000
+#define IXGBE_FCTRL_RFCE           0x00008000
+#define IXGBE_VLNCTRL_VET          0x0000FFFF
+#define IXGBE_VLNCTRL_CFI          0x10000000
+#define IXGBE_VLNCTRL_CFIEN        0x20000000
+#define IXGBE_VLNCTRL_VFE          0x40000000
+#define IXGBE_VLNCTRL_VME          0x80000000
+#define IXGBE_LINKS_UP             0x40000000
+#define IXGBE_LINKS_SPEED          0x20000000
+#define IXGBE_SRRCTL_BSIZEPKT_MASK 0x0000007F
+#define IXGBE_HLREG0_TXCRCEN       0x00000001
+#define IXGBE_HLREG0_RXCRCSTRP     0x00000002
+#define IXGBE_HLREG0_JUMBOEN       0x00000004
+#define IXGBE_HLREG0_TXPADEN       0x00000400
+#define IXGBE_HLREG0_LPBK          0x00008000
+#define IXGBE_RMCS_TFCE_802_3X     0x00000008
+#define IXGBE_RMCS_TFCE_PRIORITY   0x00000010
+#define IXGBE_FCCFG_TFCE_802_3X    0x00000008
+#define IXGBE_FCCFG_TFCE_PRIORITY  0x00000010
+#define IXGBE_MFLCN_PMCF           0x00000001 /* Pass MAC Control Frames */
+#define IXGBE_MFLCN_DPF            0x00000002 /* Discard Pause Frame */
+#define IXGBE_MFLCN_RPFCE          0x00000004 /* Receive Priority FC Enable */
+#define IXGBE_MFLCN_RFCE           0x00000008 /* Receive FC Enable */
+
+/* Device IDs */
+#define IXGBE_DEV_ID_82598               0x10B6
+#define IXGBE_DEV_ID_82598_BX            0x1508
+#define IXGBE_DEV_ID_82598AF_DUAL_PORT   0x10C6
+#define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7
+#define IXGBE_DEV_ID_82598EB_SFP_LOM     0x10DB
+#define IXGBE_DEV_ID_82598AT             0x10C8
+#define IXGBE_DEV_ID_82598AT2            0x150B
+#define IXGBE_DEV_ID_82598EB_CX4         0x10DD
+#define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC
+#define IXGBE_DEV_ID_82598_DA_DUAL_PORT  0x10F1
+#define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM      0x10E1
+#define IXGBE_DEV_ID_82598EB_XF_LR       0x10F4
+#define IXGBE_DEV_ID_82599_KX4           0x10F7
+#define IXGBE_DEV_ID_82599_KX4_MEZZ      0x1514
+#define IXGBE_DEV_ID_82599_KR            0x1517
+#define IXGBE_DEV_ID_82599_T3_LOM        0x151C
+#define IXGBE_DEV_ID_82599_CX4           0x10F9
+#define IXGBE_DEV_ID_82599_SFP           0x10FB
+#define IXGBE_DEV_ID_82599_BACKPLANE_FCOE       0x152a
+#define IXGBE_DEV_ID_82599_SFP_FCOE      0x1529
+#define IXGBE_SUBDEV_ID_82599_SFP        0x11A9
+#define IXGBE_DEV_ID_82599_SFP_EM        0x1507
+#define IXGBE_DEV_ID_82599_SFP_SF2       0x154D
+#define IXGBE_DEV_ID_82599EN_SFP         0x1557
+#define IXGBE_DEV_ID_82599_XAUI_LOM      0x10FC
+#define IXGBE_DEV_ID_82599_COMBO_BACKPLANE 0x10F8
+#define IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ  0x000C
+#define IXGBE_DEV_ID_82599_LS            0x154F
+#define IXGBE_DEV_ID_X540T               0x1528
+#define IXGBE_DEV_ID_82599_SFP_SF_QP     0x154A
+#define IXGBE_DEV_ID_82599_QSFP_SF_QP    0x1558
+#define IXGBE_DEV_ID_X540T1              0x1560
+
+#define IXGBE_DEV_ID_X550T		0x1563
+#define IXGBE_DEV_ID_X550T1		0x15D1
+#define IXGBE_DEV_ID_X550EM_X_KX4	0x15AA
+#define IXGBE_DEV_ID_X550EM_X_KR	0x15AB
+#define IXGBE_DEV_ID_X550EM_X_SFP	0x15AC
+#define IXGBE_DEV_ID_X550EM_X_10G_T	0x15AD
+#define IXGBE_DEV_ID_X550EM_X_1G_T	0x15AE
+#define IXGBE_DEV_ID_X550EM_A_KR	0x15C2
+#define IXGBE_DEV_ID_X550EM_A_KR_L	0x15C3
+#define IXGBE_DEV_ID_X550EM_A_SFP_N	0x15C4
+#define IXGBE_DEV_ID_X550EM_A_SGMII	0x15C6
+#define IXGBE_DEV_ID_X550EM_A_SGMII_L	0x15C7
+#define IXGBE_DEV_ID_X550EM_A_SFP	0x15CE
+
+/*
+ * Enumerated types specific to the ixgbe hardware
+ * Media Access Controlers
+ */
+enum ixgbe_mac_type {
+	ixgbe_mac_unknown = 0,
+	ixgbe_mac_82598EB,
+	ixgbe_mac_82599EB,
+	ixgbe_mac_X540,
+	ixgbe_mac_x550,
+	ixgbe_mac_x550em_x,
+	ixgbe_mac_x550em_a,
+	ixgbe_num_macs
+};
+
+static enum ixgbe_mac_type
+ixgbe_get_mac_type(u16 device_id)
+{
+	enum ixgbe_mac_type mac_type = ixgbe_mac_unknown;
+
+	switch (device_id) {
+	case IXGBE_DEV_ID_82598:
+	case IXGBE_DEV_ID_82598_BX:
+	case IXGBE_DEV_ID_82598AF_DUAL_PORT:
+	case IXGBE_DEV_ID_82598AF_SINGLE_PORT:
+	case IXGBE_DEV_ID_82598EB_SFP_LOM:
+	case IXGBE_DEV_ID_82598AT:
+	case IXGBE_DEV_ID_82598AT2:
+	case IXGBE_DEV_ID_82598EB_CX4:
+	case IXGBE_DEV_ID_82598_CX4_DUAL_PORT:
+	case IXGBE_DEV_ID_82598_DA_DUAL_PORT:
+	case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM:
+	case IXGBE_DEV_ID_82598EB_XF_LR:
+		mac_type = ixgbe_mac_82598EB;
+		break;
+	case IXGBE_DEV_ID_82599_KX4:
+	case IXGBE_DEV_ID_82599_KX4_MEZZ:
+	case IXGBE_DEV_ID_82599_KR:
+	case IXGBE_DEV_ID_82599_T3_LOM:
+	case IXGBE_DEV_ID_82599_CX4:
+	case IXGBE_DEV_ID_82599_SFP:
+	case IXGBE_DEV_ID_82599_BACKPLANE_FCOE:
+	case IXGBE_DEV_ID_82599_SFP_FCOE:
+	case IXGBE_SUBDEV_ID_82599_SFP:
+	case IXGBE_DEV_ID_82599_SFP_EM:
+	case IXGBE_DEV_ID_82599_SFP_SF2:
+	case IXGBE_DEV_ID_82599EN_SFP:
+	case IXGBE_DEV_ID_82599_XAUI_LOM:
+	case IXGBE_DEV_ID_82599_COMBO_BACKPLANE:
+	case IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ:
+	case IXGBE_DEV_ID_82599_LS:
+	case IXGBE_DEV_ID_82599_SFP_SF_QP:
+	case IXGBE_DEV_ID_82599_QSFP_SF_QP:
+		mac_type = ixgbe_mac_82599EB;
+		break;
+	case IXGBE_DEV_ID_X540T:
+	case IXGBE_DEV_ID_X540T1:
+		mac_type = ixgbe_mac_X540;
+		break;
+	case IXGBE_DEV_ID_X550T:
+	case IXGBE_DEV_ID_X550T1:
+		mac_type = ixgbe_mac_x550;
+		break;
+	case IXGBE_DEV_ID_X550EM_X_KX4:
+	case IXGBE_DEV_ID_X550EM_X_KR:
+	case IXGBE_DEV_ID_X550EM_X_SFP:
+	case IXGBE_DEV_ID_X550EM_X_10G_T:
+	case IXGBE_DEV_ID_X550EM_X_1G_T:
+		mac_type = ixgbe_mac_x550em_x;
+		break;
+	case IXGBE_DEV_ID_X550EM_A_KR:
+	case IXGBE_DEV_ID_X550EM_A_KR_L:
+	case IXGBE_DEV_ID_X550EM_A_SFP_N:
+	case IXGBE_DEV_ID_X550EM_A_SGMII:
+	case IXGBE_DEV_ID_X550EM_A_SGMII_L:
+	case IXGBE_DEV_ID_X550EM_A_SFP:
+		mac_type = ixgbe_mac_x550em_a;
+		break;
+	default:
+		mac_type = ixgbe_mac_82598EB;
+		break;
+	}
+
+	return mac_type;
+}
+
+int
+ixgbe_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		struct ethtool_regs *regs)
+{
+	u32 *regs_buff = (u32 *)regs->data;
+	u32 regs_buff_len = regs->len / sizeof(*regs_buff);
+	u32 reg;
+	u32 offset;
+	u16 hw_device_id = (u16) regs->version;
+	u8 version = (u8)(regs->version >> 24);
+	u8 i;
+	enum ixgbe_mac_type mac_type;
+
+	if (version == 0)
+		return -1;
+
+	/* The current driver reports the MAC type, but older versions
+	 * only report the device ID so we have to infer the MAC type.
+	 */
+	mac_type = version > 1 ? version : ixgbe_get_mac_type(hw_device_id);
+
+	reg = regs_buff[1065];
+	fprintf(stdout,
+	"0x042A4: LINKS (Link Status register)                 0x%08X\n"
+	"       Link Status:                                   %s\n"
+	"       Link Speed:                                    %s\n",
+	reg,
+	reg & IXGBE_LINKS_UP      ? "up"       : "down",
+	reg & IXGBE_LINKS_SPEED   ? "10G"      : "1G");
+
+	reg = regs_buff[515];
+	fprintf(stdout,
+	"0x05080: FCTRL (Filter Control register)              0x%08X\n"
+	"       Broadcast Accept:                              %s\n"
+	"       Unicast Promiscuous:                           %s\n"
+	"       Multicast Promiscuous:                         %s\n"
+	"       Store Bad Packets:                             %s\n",
+	reg,
+	reg & IXGBE_FCTRL_BAM     ? "enabled"  : "disabled",
+	reg & IXGBE_FCTRL_UPE     ? "enabled"  : "disabled",
+	reg & IXGBE_FCTRL_MPE     ? "enabled"  : "disabled",
+	reg & IXGBE_FCTRL_SBP     ? "enabled"  : "disabled");
+
+	/* Some FCTRL bits are valid only on 82598 */
+	if (mac_type == ixgbe_mac_82598EB) {
+		fprintf(stdout,
+		"       Receive Flow Control Packets:                  %s\n"
+		"       Receive Priority Flow Control Packets:         %s\n"
+		"       Discard Pause Frames:                          %s\n"
+		"       Pass MAC Control Frames:                       %s\n",
+		reg & IXGBE_FCTRL_RFCE    ? "enabled"  : "disabled",
+		reg & IXGBE_FCTRL_RPFCE   ? "enabled"  : "disabled",
+		reg & IXGBE_FCTRL_DPF     ? "enabled"  : "disabled",
+		reg & IXGBE_FCTRL_PMCF    ? "enabled"  : "disabled");
+	 }
+
+	reg = regs_buff[1128];
+	if (mac_type >= ixgbe_mac_82599EB) {
+		fprintf(stdout,
+		"0x04294: MFLCN (TabMAC Flow Control register)         0x%08X\n"
+		"       Receive Flow Control Packets:                  %s\n"
+		"       Discard Pause Frames:                          %s\n"
+		"       Pass MAC Control Frames:                       %s\n"
+		"       Receive Priority Flow Control Packets:         %s\n",
+		reg,
+		reg & IXGBE_MFLCN_RFCE    ? "enabled"  : "disabled",
+		reg & IXGBE_MFLCN_DPF     ? "enabled"  : "disabled",
+		reg & IXGBE_MFLCN_PMCF    ? "enabled"  : "disabled",
+		reg & IXGBE_MFLCN_RPFCE   ? "enabled"  : "disabled");
+	}
+
+	reg = regs_buff[516];
+	fprintf(stdout,
+	"0x05088: VLNCTRL (VLAN Control register)              0x%08X\n"
+	"       VLAN Mode:                                     %s\n"
+	"       VLAN Filter:                                   %s\n",
+	reg,
+	reg & IXGBE_VLNCTRL_VME   ? "enabled"  : "disabled",
+	reg & IXGBE_VLNCTRL_VFE   ? "enabled"  : "disabled");
+
+	reg = regs_buff[437];
+	fprintf(stdout,
+	"0x02100: SRRCTL0 (Split and Replic Rx Control 0)      0x%08X\n"
+	"       Receive Buffer Size:                           %uKB\n",
+	reg,
+	(reg & IXGBE_SRRCTL_BSIZEPKT_MASK) <= 0x10 ? (reg & IXGBE_SRRCTL_BSIZEPKT_MASK) : 0x10);
+
+	reg = regs_buff[829];
+	if (mac_type == ixgbe_mac_82598EB) {
+		fprintf(stdout,
+		"0x03D00: RMCS (Receive Music Control register)        0x%08X\n"
+		"       Transmit Flow Control:                         %s\n"
+		"       Priority Flow Control:                         %s\n",
+		reg,
+		reg & IXGBE_RMCS_TFCE_802_3X     ? "enabled"  : "disabled",
+		reg & IXGBE_RMCS_TFCE_PRIORITY   ? "enabled"  : "disabled");
+	} else if (mac_type >= ixgbe_mac_82599EB) {
+		fprintf(stdout,
+		"0x03D00: FCCFG (Flow Control Configuration)           0x%08X\n"
+		"       Transmit Flow Control:                         %s\n"
+		"       Priority Flow Control:                         %s\n",
+		reg,
+		reg & IXGBE_FCCFG_TFCE_802_3X     ? "enabled"  : "disabled",
+		reg & IXGBE_FCCFG_TFCE_PRIORITY   ? "enabled"  : "disabled");
+	}
+
+	reg = regs_buff[1047];
+	fprintf(stdout,
+	"0x04240: HLREG0 (Highlander Control 0 register)       0x%08X\n"
+	"       Transmit CRC:                                  %s\n"
+	"       Receive CRC Strip:                             %s\n"
+	"       Jumbo Frames:                                  %s\n"
+	"       Pad Short Frames:                              %s\n"
+	"       Loopback:                                      %s\n",
+	reg,
+	reg & IXGBE_HLREG0_TXCRCEN   ? "enabled"  : "disabled",
+	reg & IXGBE_HLREG0_RXCRCSTRP ? "enabled"  : "disabled",
+	reg & IXGBE_HLREG0_JUMBOEN   ? "enabled"  : "disabled",
+	reg & IXGBE_HLREG0_TXPADEN   ? "enabled"  : "disabled",
+	reg & IXGBE_HLREG0_LPBK      ? "enabled"  : "disabled");
+
+	/* General Registers */
+	fprintf(stdout,
+		"0x00000: CTRL        (Device Control)                 0x%08X\n",
+		regs_buff[0]);
+
+	fprintf(stdout,
+		"0x00008: STATUS      (Device Status)                  0x%08X\n",
+		regs_buff[1]);
+
+	fprintf(stdout,
+		"0x00018: CTRL_EXT    (Extended Device Control)        0x%08X\n",
+		regs_buff[2]);
+
+	fprintf(stdout,
+		"0x00020: ESDP        (Extended SDP Control)           0x%08X\n",
+		regs_buff[3]);
+
+	fprintf(stdout,
+		"0x00028: EODSDP      (Extended OD SDP Control)        0x%08X\n",
+		regs_buff[4]);
+
+	fprintf(stdout,
+		"0x00200: LEDCTL      (LED Control)                    0x%08X\n",
+		regs_buff[5]);
+
+	fprintf(stdout,
+		"0x00048: FRTIMER     (Free Running Timer)             0x%08X\n",
+		regs_buff[6]);
+
+	fprintf(stdout,
+		"0x0004C: TCPTIMER    (TCP Timer)                      0x%08X\n",
+		regs_buff[7]);
+
+	/* NVM Register */
+	offset = mac_type == ixgbe_mac_x550em_a ? 0x15FF8 : 0x10010;
+	fprintf(stdout,
+		"0x%05X: EEC         (EEPROM/Flash Control)           0x%08X\n",
+		offset, regs_buff[8]);
+
+	fprintf(stdout,
+		"0x10014: EERD        (EEPROM Read)                    0x%08X\n",
+		regs_buff[9]);
+
+	offset = mac_type == ixgbe_mac_x550em_a ? 0x15F6C : 0x1001C;
+	fprintf(stdout,
+		"0x%05X: FLA         (Flash Access)                   0x%08X\n",
+		offset, regs_buff[10]);
+
+	fprintf(stdout,
+		"0x10110: EEMNGCTL    (Manageability EEPROM Control)   0x%08X\n",
+		regs_buff[11]);
+
+	fprintf(stdout,
+		"0x10114: EEMNGDATA   (Manageability EEPROM R/W Data)  0x%08X\n",
+		regs_buff[12]);
+
+	fprintf(stdout,
+		"0x10118: FLMNGCTL    (Manageability Flash Control)    0x%08X\n",
+		regs_buff[13]);
+
+	fprintf(stdout,
+		"0x1011C: FLMNGDATA   (Manageability Flash Read Data)  0x%08X\n",
+		regs_buff[14]);
+
+	fprintf(stdout,
+		"0x10120: FLMNGCNT    (Manageability Flash Read Count) 0x%08X\n",
+		regs_buff[15]);
+
+	fprintf(stdout,
+		"0x1013C: FLOP        (Flash Opcode)                   0x%08X\n",
+		regs_buff[16]);
+
+	offset = mac_type == ixgbe_mac_x550em_a ? 0x15F64 : 0x10200;
+	fprintf(stdout,
+		"0x%05X: GRC         (General Receive Control)        0x%08X\n",
+		offset, regs_buff[17]);
+
+	/* Interrupt */
+	fprintf(stdout,
+		"0x00800: EICR        (Extended Interrupt Cause)       0x%08X\n",
+		regs_buff[18]);
+
+	fprintf(stdout,
+		"0x00808: EICS        (Extended Interrupt Cause Set)   0x%08X\n",
+		regs_buff[19]);
+
+	fprintf(stdout,
+		"0x00880: EIMS        (Extended Interr. Mask Set/Read) 0x%08X\n",
+		regs_buff[20]);
+
+	fprintf(stdout,
+		"0x00888: EIMC        (Extended Interrupt Mask Clear)  0x%08X\n",
+		regs_buff[21]);
+
+	fprintf(stdout,
+		"0x00810: EIAC        (Extended Interrupt Auto Clear)  0x%08X\n",
+		regs_buff[22]);
+
+	fprintf(stdout,
+		"0x00890: EIAM        (Extended Interr. Auto Mask EN)  0x%08X\n",
+		regs_buff[23]);
+
+	fprintf(stdout,
+		"0x00820: EITR0       (Extended Interrupt Throttle 0)  0x%08X\n",
+		regs_buff[24]);
+
+	fprintf(stdout,
+		"0x00900: IVAR0       (Interrupt Vector Allocation 0)  0x%08X\n",
+		regs_buff[25]);
+
+	fprintf(stdout,
+		"0x00000: MSIXT       (MSI-X Table)                    0x%08X\n",
+		regs_buff[26]);
+
+	if (mac_type == ixgbe_mac_82598EB)
+		fprintf(stdout,
+			"0x02000: MSIXPBA     (MSI-X Pending Bit Array)        0x%08X\n",
+			regs_buff[27]);
+
+	fprintf(stdout,
+		"0x11068: PBACL       (MSI-X PBA Clear)                0x%08X\n",
+		regs_buff[28]);
+
+	fprintf(stdout,
+		"0x00898: GPIE        (General Purpose Interrupt EN)   0x%08X\n",
+		regs_buff[29]);
+
+	/* Flow Control */
+	fprintf(stdout,
+		"0x03008: PFCTOP      (Priority Flow Ctrl Type Opcode) 0x%08X\n",
+		regs_buff[30]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+		"0x%05X: FCCTV%d      (Flow Ctrl Tx Timer Value %d)     0x%08X\n",
+		0x03200 + (4 * i), i, i, regs_buff[31 + i]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: FCRTL%d      (Flow Ctrl Rx Threshold low %d)   0x%08X\n",
+		0x3220 + (8 * i), i, i, regs_buff[35 + i]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: FCRTH%d      (Flow Ctrl Rx Threshold High %d)  0x%08X\n",
+		0x3260 + (8 * i), i, i, regs_buff[43 + i]);
+
+	fprintf(stdout,
+		"0x032A0: FCRTV       (Flow Control Refresh Threshold) 0x%08X\n",
+		regs_buff[51]);
+
+	fprintf(stdout,
+		"0x0CE00: TFCS        (Transmit Flow Control Status)   0x%08X\n",
+		regs_buff[52]);
+
+	/* Receive DMA */
+	for (i = 0; i < 64; i++)
+		fprintf(stdout,
+		"0x%05X: RDBAL%02d     (Rx Desc Base Addr Low %02d)       0x%08X\n",
+		0x01000 + (0x40 * i), i, i, regs_buff[53 + i]);
+
+	for (i = 0; i < 64; i++)
+		fprintf(stdout,
+		"0x%05X: RDBAH%02d     (Rx Desc Base Addr High %02d)      0x%08X\n",
+		0x01004 + (0x40 * i), i, i, regs_buff[117 + i]);
+
+	for (i = 0; i < 64; i++)
+		fprintf(stdout,
+		"0x%05X: RDLEN%02d     (Receive Descriptor Length %02d)   0x%08X\n",
+		0x01008 + (0x40 * i), i, i, regs_buff[181 + i]);
+
+	for (i = 0; i < 64; i++)
+		fprintf(stdout,
+		"0x%05X: RDH%02d       (Receive Descriptor Head %02d)     0x%08X\n",
+		0x01010 + (0x40 * i), i, i, regs_buff[245 + i]);
+
+	for (i = 0; i < 64; i++)
+		fprintf(stdout,
+		"0x%05X: RDT%02d       (Receive Descriptor Tail %02d)     0x%08X\n",
+		0x01018 + (0x40 * i), i, i, regs_buff[309 + i]);
+
+	for (i = 0; i < 64; i++)
+		fprintf(stdout,
+		"0x%05X: RXDCTL%02d    (Receive Descriptor Control %02d)  0x%08X\n",
+		0x01028 + (0x40 * i), i, i, regs_buff[373 + i]);
+
+	for (i = 0; i < 16; i++)
+		fprintf(stdout,
+		"0x%05X: SRRCTL%02d    (Split and Replic Rx Control %02d) 0x%08X\n",
+		0x02100 + (4 * i), i, i, regs_buff[437 + i]);
+
+	for (i = 0; i < 16; i++)
+		fprintf(stdout,
+		"0x%05X: DCA_RXCTRL%02d (Rx DCA Control %02d)             0x%08X\n",
+		0x02200 + (4 * i), i, i, regs_buff[453 + i]);
+
+	fprintf(stdout,
+		"0x02F00: RDRXCTL     (Receive DMA Control)            0x%08X\n",
+		regs_buff[469]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: RXPBSIZE%d   (Receive Packet Buffer Size %d)   0x%08X\n",
+		0x3C00 + (4 * i), i, i, regs_buff[470 + i]);
+
+	fprintf(stdout,
+		"0x03000: RXCTRL      (Receive Control)                0x%08X\n",
+		regs_buff[478]);
+
+	if (mac_type == ixgbe_mac_82598EB)
+		fprintf(stdout,
+			"0x03D04: DROPEN      (Drop Enable Control)            0x%08X\n",
+			regs_buff[479]);
+
+	/* Receive */
+	fprintf(stdout,
+		"0x05000: RXCSUM      (Receive Checksum Control)       0x%08X\n",
+		regs_buff[480]);
+
+	fprintf(stdout,
+		"0x05008: RFCTL       (Receive Filter Control)         0x%08X\n",
+		regs_buff[481]);
+
+	for (i = 0; i < 16; i++)
+		fprintf(stdout,
+		"0x%05X: RAL%02d       (Receive Address Low%02d)          0x%08X\n",
+		0x05400 + (8 * i), i, i, regs_buff[482 + i]);
+
+	for (i = 0; i < 16; i++)
+		fprintf(stdout,
+		"0x%05X: RAH%02d       (Receive Address High %02d)        0x%08X\n",
+		0x05404 + (8 * i), i, i, regs_buff[498 + i]);
+
+	fprintf(stdout,
+		"0x05480: PSRTYPE     (Packet Split Receive Type)      0x%08X\n",
+		regs_buff[514]);
+
+	fprintf(stdout,
+		"0x05090: MCSTCTRL    (Multicast Control)              0x%08X\n",
+		regs_buff[517]);
+
+	fprintf(stdout,
+		"0x05818: MRQC        (Multiple Rx Queues Command)     0x%08X\n",
+		regs_buff[518]);
+
+	fprintf(stdout,
+		"0x0581C: VMD_CTL     (VMDq Control)                   0x%08X\n",
+		regs_buff[519]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: IMIR%d       (Immediate Interrupt Rx %d)       0x%08X\n",
+		0x05A80 + (4 * i), i, i, regs_buff[520 + i]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: IMIREXT%d    (Immed. Interr. Rx Extended %d)   0x%08X\n",
+		0x05AA0 + (4 * i), i, i, regs_buff[528 + i]);
+
+	fprintf(stdout,
+		"0x05AC0: IMIRVP      (Immed. Interr. Rx VLAN Prior.)  0x%08X\n",
+		regs_buff[536]);
+
+	/* Transmit */
+	for (i = 0; i < 32; i++)
+		fprintf(stdout,
+		"0x%05X: TDBAL%02d     (Tx Desc Base Addr Low %02d)       0x%08X\n",
+		0x06000 + (0x40 * i), i, i, regs_buff[537 + i]);
+
+	for (i = 0; i < 32; i++)
+		fprintf(stdout,
+		"0x%05X: TDBAH%02d     (Tx Desc Base Addr High %02d)      0x%08X\n",
+		0x06004 + (0x40 * i), i, i, regs_buff[569 + i]);
+
+	for (i = 0; i < 32; i++)
+		fprintf(stdout,
+		"0x%05X: TDLEN%02d     (Tx Descriptor Length %02d)        0x%08X\n",
+		0x06008 + (0x40 * i), i, i, regs_buff[601 + i]);
+
+	for (i = 0; i < 32; i++)
+		fprintf(stdout,
+		"0x%05X: TDH%02d       (Transmit Descriptor Head %02d)    0x%08X\n",
+		0x06010 + (0x40 * i), i, i, regs_buff[633 + i]);
+
+	for (i = 0; i < 32; i++)
+		fprintf(stdout,
+		"0x%05X: TDT%02d       (Transmit Descriptor Tail %02d)    0x%08X\n",
+		0x06018 + (0x40 * i), i, i, regs_buff[665 + i]);
+
+	for (i = 0; i < 32; i++)
+		fprintf(stdout,
+		"0x%05X: TXDCTL%02d    (Tx Descriptor Control %02d)       0x%08X\n",
+		0x06028 + (0x40 * i), i, i, regs_buff[697 + i]);
+
+	for (i = 0; i < 32; i++)
+		fprintf(stdout,
+		"0x%05X: TDWBAL%02d    (Tx Desc Compl. WB Addr low %02d)  0x%08X\n",
+		0x06038 + (0x40 * i), i, i, regs_buff[729 + i]);
+
+	for (i = 0; i < 32; i++)
+		fprintf(stdout,
+		"0x%05X: TDWBAH%02d    (Tx Desc Compl. WB Addr High %02d) 0x%08X\n",
+		0x0603C + (0x40 * i), i, i, regs_buff[761 + i]);
+
+	fprintf(stdout,
+		"0x07E00: DTXCTL      (DMA Tx Control)                 0x%08X\n",
+		regs_buff[793]);
+
+	for (i = 0; i < 16; i++)
+		fprintf(stdout,
+		"0x%05X: DCA_TXCTRL%02d (Tx DCA Control %02d)             0x%08X\n",
+		0x07200 + (4 * i), i, i, regs_buff[794 + i]);
+
+	if (mac_type == ixgbe_mac_82598EB)
+		fprintf(stdout,
+			"0x0CB00: TIPG        (Transmit IPG Control)           0x%08X\n",
+			regs_buff[810]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: TXPBSIZE%d   (Transmit Packet Buffer Size %d)  0x%08X\n",
+		0x0CC00 + (4 * i), i, i, regs_buff[811 + i]);
+
+	fprintf(stdout,
+		"0x0CD10: MNGTXMAP    (Manageability Tx TC Mapping)    0x%08X\n",
+		regs_buff[819]);
+
+	/* Wake Up */
+	fprintf(stdout,
+		"0x05800: WUC         (Wake up Control)                0x%08X\n",
+		regs_buff[820]);
+
+	fprintf(stdout,
+		"0x05808: WUFC        (Wake Up Filter Control)         0x%08X\n",
+		regs_buff[821]);
+
+	fprintf(stdout,
+		"0x05810: WUS         (Wake Up Status)                 0x%08X\n",
+		regs_buff[822]);
+
+	fprintf(stdout,
+		"0x05838: IPAV        (IP Address Valid)               0x%08X\n",
+		regs_buff[823]);
+
+	fprintf(stdout,
+		"0x05840: IP4AT       (IPv4 Address Table)             0x%08X\n",
+		regs_buff[824]);
+
+	fprintf(stdout,
+		"0x05880: IP6AT       (IPv6 Address Table)             0x%08X\n",
+		regs_buff[825]);
+
+	fprintf(stdout,
+		"0x05900: WUPL        (Wake Up Packet Length)          0x%08X\n",
+		regs_buff[826]);
+
+	fprintf(stdout,
+		"0x05A00: WUPM        (Wake Up Packet Memory)          0x%08X\n",
+		regs_buff[827]);
+
+	fprintf(stdout,
+		"0x09000: FHFT        (Flexible Host Filter Table)     0x%08X\n",
+		regs_buff[828]);
+
+	/* DCB */
+	if (mac_type == ixgbe_mac_82598EB) {
+		fprintf(stdout,
+		"0x07F40: DPMCS       (Desc. Plan Music Ctrl Status)   0x%08X\n",
+		regs_buff[830]);
+
+		fprintf(stdout,
+		"0x0CD00: PDPMCS      (Pkt Data Plan Music ctrl Stat)  0x%08X\n",
+		regs_buff[831]);
+
+		fprintf(stdout,
+		"0x050A0: RUPPBMR     (Rx User Prior to Pkt Buff Map)  0x%08X\n",
+		regs_buff[832]);
+
+		for (i = 0; i < 8; i++)
+			fprintf(stdout,
+			"0x%05X: RT2CR%d      (Receive T2 Configure %d)         0x%08X\n",
+			0x03C20 + (4 * i), i, i, regs_buff[833 + i]);
+
+		for (i = 0; i < 8; i++)
+			fprintf(stdout,
+			"0x%05X: RT2SR%d      (Receive T2 Status %d)            0x%08X\n",
+			0x03C40 + (4 * i), i, i, regs_buff[841 + i]);
+
+		for (i = 0; i < 8; i++)
+			fprintf(stdout,
+			"0x%05X: TDTQ2TCCR%d  (Tx Desc TQ2 TC Config %d)        0x%08X\n",
+			0x0602C + (0x40 * i), i, i, regs_buff[849 + i]);
+
+		for (i = 0; i < 8; i++)
+			fprintf(stdout,
+			"0x%05X: TDTQ2TCSR%d  (Tx Desc TQ2 TC Status %d)        0x%08X\n",
+			0x0622C + (0x40 * i), i, i, regs_buff[857 + i]);
+
+		for (i = 0; i < 8; i++)
+			fprintf(stdout,
+			"0x%05X: TDPT2TCCR%d  (Tx Data Plane T2 TC Config %d)   0x%08X\n",
+			0x0CD20 + (4 * i), i, i, regs_buff[865 + i]);
+
+		for (i = 0; i < 8; i++)
+			fprintf(stdout,
+			"0x%05X: TDPT2TCSR%d  (Tx Data Plane T2 TC Status %d)   0x%08X\n",
+			0x0CD40 + (4 * i), i, i, regs_buff[873 + i]);
+	} else if (mac_type >= ixgbe_mac_82599EB && mac_type <= ixgbe_mac_x550) {
+		fprintf(stdout,
+			"0x04900: RTTDCS      (Tx Descr Plane Ctrl&Status)     0x%08X\n",
+			regs_buff[830]);
+
+		fprintf(stdout,
+			"0x0CD00: RTTPCS      (Tx Pkt Plane Ctrl&Status)       0x%08X\n",
+			regs_buff[831]);
+
+		fprintf(stdout,
+			"0x02430: RTRPCS      (Rx Packet Plane Ctrl&Status)    0x%08X\n",
+			regs_buff[832]);
+
+		for (i = 0; i < 8; i++)
+			fprintf(stdout,
+			"0x%05X: RTRPT4C%d    (Rx Packet Plane T4 Config %d)    0x%08X\n",
+			0x02140 + (4 * i), i, i, regs_buff[833 + i]);
+
+		for (i = 0; i < 8; i++)
+			fprintf(stdout,
+			"0x%05X: RTRPT4S%d    (Rx Packet Plane T4 Status %d)    0x%08X\n",
+			0x02160 + (4 * i), i, i, regs_buff[841 + i]);
+
+		for (i = 0; i < 8; i++)
+			fprintf(stdout,
+			"0x%05X: RTTDT2C%d    (Tx Descr Plane T2 Config %d)     0x%08X\n",
+			0x04910 + (4 * i), i, i, regs_buff[849 + i]);
+
+		if (mac_type < ixgbe_mac_x550)
+			for (i = 0; i < 8; i++)
+				fprintf(stdout,
+					"0x%05X: RTTDT2S%d    (Tx Descr Plane T2 Status %d)     0x%08X\n",
+					0x04930 + (4 * i), i, i, regs_buff[857 + i]);
+
+		for (i = 0; i < 8; i++)
+			fprintf(stdout,
+			"0x%05X: RTTPT2C%d    (Tx Packet Plane T2 Config %d)    0x%08X\n",
+			0x0CD20 + (4 * i), i, i, regs_buff[865]);
+
+		if (mac_type < ixgbe_mac_x550)
+			for (i = 0; i < 8; i++)
+				fprintf(stdout,
+					"0x%05X: RTTPT2S%d    (Tx Packet Plane T2 Status %d)    0x%08X\n",
+					0x0CD40 + (4 * i), i, i, regs_buff[873 + i]);
+	}
+
+	if (regs_buff_len > 1129 && mac_type != ixgbe_mac_82598EB) {
+		fprintf(stdout,
+			"0x03020: RTRUP2TC    (Rx User Prio to Traffic Classes)0x%08X\n",
+			regs_buff[1129]);
+
+		fprintf(stdout,
+			"0x0C800: RTTUP2TC    (Tx User Prio to Traffic Classes)0x%08X\n",
+			regs_buff[1130]);
+
+		if (mac_type <= ixgbe_mac_x550)
+			for (i = 0; i < 4; i++)
+				fprintf(stdout,
+					"0x%05X: TXLLQ%d      (Strict Low Lat Tx Queues %d)     0x%08X\n",
+					0x082E0 + (4 * i), i, i, regs_buff[1131 + i]);
+
+		if (mac_type == ixgbe_mac_82599EB) {
+			fprintf(stdout,
+				"0x04980: RTTBCNRM    (DCB TX Rate Sched MMW)          0x%08X\n",
+				regs_buff[1135]);
+
+			fprintf(stdout,
+				"0x0498C: RTTBCNRD    (DCB TX Rate-Scheduler Drift)    0x%08X\n",
+				regs_buff[1136]);
+		} else if (mac_type <= ixgbe_mac_x550) {
+			fprintf(stdout,
+				"0x04980: RTTQCNRM    (DCB TX QCN Rate Sched MMW)      0x%08X\n",
+				regs_buff[1135]);
+
+			fprintf(stdout,
+				"0x0498C: RTTQCNRR    (DCB TX QCN Rate Reset)          0x%08X\n",
+				regs_buff[1136]);
+
+			if (mac_type < ixgbe_mac_x550)
+				fprintf(stdout,
+					"0x08B00: RTTQCNCR    (DCB TX QCN Control)             0x%08X\n",
+					regs_buff[1137]);
+
+			fprintf(stdout,
+				"0x04A90: RTTQCNTG    (DCB TX QCN Tagging)             0x%08X\n",
+				regs_buff[1138]);
+		}
+	}
+
+	/* Statistics */
+	fprintf(stdout,
+		"0x04000: crcerrs     (CRC Error Count)                0x%08X\n",
+		regs_buff[881]);
+
+	fprintf(stdout,
+		"0x04004: illerrc     (Illegal Byte Error Count)       0x%08X\n",
+		regs_buff[882]);
+
+	fprintf(stdout,
+		"0x04008: errbc       (Error Byte Count)               0x%08X\n",
+		regs_buff[883]);
+
+	fprintf(stdout,
+		"0x04010: mspdc       (MAC Short Packet Discard Count) 0x%08X\n",
+		regs_buff[884]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: mpc%d        (Missed Packets Count %d)         0x%08X\n",
+		0x03FA0 + (4 * i), i, i, regs_buff[885 + i]);
+
+	fprintf(stdout,
+		"0x04034: mlfc        (MAC Local Fault Count)          0x%08X\n",
+		regs_buff[893]);
+
+	fprintf(stdout,
+		"0x04038: mrfc        (MAC Remote Fault Count)         0x%08X\n",
+		regs_buff[894]);
+
+	fprintf(stdout,
+		"0x04040: rlec        (Receive Length Error Count)     0x%08X\n",
+		regs_buff[895]);
+
+	fprintf(stdout,
+		"0x03F60: lxontxc     (Link XON Transmitted Count)     0x%08X\n",
+		regs_buff[896]);
+
+	fprintf(stdout,
+		"0x0CF60: lxonrxc     (Link XON Received Count)        0x%08X\n",
+		regs_buff[897]);
+
+	fprintf(stdout,
+		"0x03F68: lxofftxc    (Link XOFF Transmitted Count)    0x%08X\n",
+		regs_buff[898]);
+
+	fprintf(stdout,
+		"0x0CF68: lxoffrxc    (Link XOFF Received Count)       0x%08X\n",
+		regs_buff[899]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: pxontxc%d    (Priority XON Tx Count %d)        0x%08X\n",
+		0x03F00 + (4 * i), i, i, regs_buff[900 + i]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: pxonrxc%d    (Priority XON Received Count %d)  0x%08X\n",
+		0x0CF00 + (4 * i), i, i, regs_buff[908 + i]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: pxofftxc%d   (Priority XOFF Tx Count %d)       0x%08X\n",
+		0x03F20 + (4 * i), i, i, regs_buff[916 + i]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: pxoffrxc%d   (Priority XOFF Received Count %d) 0x%08X\n",
+		0x0CF20 + (4 * i), i, i, regs_buff[924 + i]);
+
+	fprintf(stdout,
+		"0x0405C: prc64       (Packets Received (64B) Count)   0x%08X\n",
+		regs_buff[932]);
+
+	fprintf(stdout,
+		"0x04060: prc127      (Packets Rx (65-127B) Count)     0x%08X\n",
+		regs_buff[933]);
+
+	fprintf(stdout,
+		"0x04064: prc255      (Packets Rx (128-255B) Count)    0x%08X\n",
+		regs_buff[934]);
+
+	fprintf(stdout,
+		"0x04068: prc511      (Packets Rx (256-511B) Count)    0x%08X\n",
+		regs_buff[935]);
+
+	fprintf(stdout,
+		"0x0406C: prc1023     (Packets Rx (512-1023B) Count)   0x%08X\n",
+		regs_buff[936]);
+
+	fprintf(stdout,
+		"0x04070: prc1522     (Packets Rx (1024-Max) Count)    0x%08X\n",
+		regs_buff[937]);
+
+	fprintf(stdout,
+		"0x04074: gprc        (Good Packets Received Count)    0x%08X\n",
+		regs_buff[938]);
+
+	fprintf(stdout,
+		"0x04078: bprc        (Broadcast Packets Rx Count)     0x%08X\n",
+		regs_buff[939]);
+
+	fprintf(stdout,
+		"0x0407C: mprc        (Multicast Packets Rx Count)     0x%08X\n",
+		regs_buff[940]);
+
+	fprintf(stdout,
+		"0x04080: gptc        (Good Packets Transmitted Count) 0x%08X\n",
+		regs_buff[941]);
+
+	fprintf(stdout,
+		"0x04088: gorcl       (Good Octets Rx Count Low)       0x%08X\n",
+		regs_buff[942]);
+
+	fprintf(stdout,
+		"0x0408C: gorch       (Good Octets Rx Count High)      0x%08X\n",
+		regs_buff[943]);
+
+	fprintf(stdout,
+		"0x04090: gotcl       (Good Octets Tx Count Low)       0x%08X\n",
+		regs_buff[944]);
+
+	fprintf(stdout,
+		"0x04094: gotch       (Good Octets Tx Count High)      0x%08X\n",
+		regs_buff[945]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: rnbc%d       (Receive No Buffers Count %d)     0x%08X\n",
+		0x03FC0 + (4 * i), i, i, regs_buff[946 + i]);
+
+	fprintf(stdout,
+		"0x040A4: ruc         (Receive Undersize count)        0x%08X\n",
+		regs_buff[954]);
+
+	fprintf(stdout,
+		"0x040A8: rfc         (Receive Fragment Count)         0x%08X\n",
+		regs_buff[955]);
+
+	fprintf(stdout,
+		"0x040AC: roc         (Receive Oversize Count)         0x%08X\n",
+		regs_buff[956]);
+
+	fprintf(stdout,
+		"0x040B0: rjc         (Receive Jabber Count)           0x%08X\n",
+		regs_buff[957]);
+
+	fprintf(stdout,
+		"0x040B4: mngprc      (Management Packets Rx Count)    0x%08X\n",
+		regs_buff[958]);
+
+	fprintf(stdout,
+		"0x040B8: mngpdc      (Management Pkts Dropped Count)  0x%08X\n",
+		regs_buff[959]);
+
+	fprintf(stdout,
+		"0x0CF90: mngptc      (Management Packets Tx Count)    0x%08X\n",
+		regs_buff[960]);
+
+	fprintf(stdout,
+		"0x040C0: torl        (Total Octets Rx Count Low)      0x%08X\n",
+		regs_buff[961]);
+
+	fprintf(stdout,
+		"0x040C4: torh        (Total Octets Rx Count High)     0x%08X\n",
+		regs_buff[962]);
+
+	fprintf(stdout,
+		"0x040D0: tpr         (Total Packets Received)         0x%08X\n",
+		regs_buff[963]);
+
+	fprintf(stdout,
+		"0x040D4: tpt         (Total Packets Transmitted)      0x%08X\n",
+		regs_buff[964]);
+
+	fprintf(stdout,
+		"0x040D8: ptc64       (Packets Tx (64B) Count)         0x%08X\n",
+		regs_buff[965]);
+
+	fprintf(stdout,
+		"0x040DC: ptc127      (Packets Tx (65-127B) Count)     0x%08X\n",
+		regs_buff[966]);
+
+	fprintf(stdout,
+		"0x040E0: ptc255      (Packets Tx (128-255B) Count)    0x%08X\n",
+		regs_buff[967]);
+
+	fprintf(stdout,
+		"0x040E4: ptc511      (Packets Tx (256-511B) Count)    0x%08X\n",
+		regs_buff[968]);
+
+	fprintf(stdout,
+		"0x040E8: ptc1023     (Packets Tx (512-1023B) Count)   0x%08X\n",
+		regs_buff[969]);
+
+	fprintf(stdout,
+		"0x040EC: ptc1522     (Packets Tx (1024-Max) Count)    0x%08X\n",
+		regs_buff[970]);
+
+	fprintf(stdout,
+		"0x040F0: mptc        (Multicast Packets Tx Count)     0x%08X\n",
+		regs_buff[971]);
+
+	fprintf(stdout,
+		"0x040F4: bptc        (Broadcast Packets Tx Count)     0x%08X\n",
+		regs_buff[972]);
+
+	fprintf(stdout,
+		"0x04120: xec         (XSUM Error Count)               0x%08X\n",
+		regs_buff[973]);
+
+	for (i = 0; i < 16; i++)
+		fprintf(stdout,
+		"0x%05X: qprc%02d      (Queue Packets Rx Count %02d)      0x%08X\n",
+		0x01030 + (0x40 * i), i, i, regs_buff[974 + i]);
+
+	for (i = 0; i < 16; i++)
+		fprintf(stdout,
+		"0x%05X: qptc%02d      (Queue Packets Tx Count %02d)      0x%08X\n",
+		0x06030 + (0x40 * i), i, i, regs_buff[990 + i]);
+
+	for (i = 0; i < 16; i++)
+		fprintf(stdout,
+		"0x%05X: qbrc%02d      (Queue Bytes Rx Count %02d)        0x%08X\n",
+		0x01034 + (0x40 * i), i, i, regs_buff[1006 + i]);
+
+	for (i = 0; i < 16; i++)
+		fprintf(stdout,
+		"0x%05X: qbtc%02d      (Queue Bytes Tx Count %02d)        0x%08X\n",
+		0x06034 + (0x40 * i), i, i, regs_buff[1022 + i]);
+
+	/* MAC */
+	if (mac_type < ixgbe_mac_X540) {
+		fprintf(stdout,
+			"0x04200: PCS1GCFIG   (PCS_1G Gloabal Config 1)        0x%08X\n",
+			regs_buff[1038]);
+
+		fprintf(stdout,
+			"0x04208: PCS1GLCTL   (PCS_1G Link Control)            0x%08X\n",
+			regs_buff[1039]);
+
+		fprintf(stdout,
+			"0x0420C: PCS1GLSTA   (PCS_1G Link Status)             0x%08X\n",
+			regs_buff[1040]);
+
+		fprintf(stdout,
+			"0x04210: PCS1GDBG0   (PCS_1G Debug 0)                 0x%08X\n",
+			regs_buff[1041]);
+
+		fprintf(stdout,
+			"0x04214: PCS1GDBG1   (PCS_1G Debug 1)                 0x%08X\n",
+			regs_buff[1042]);
+
+		fprintf(stdout,
+			"0x04218: PCS1GANA    (PCS-1G Auto Neg. Adv.)          0x%08X\n",
+			regs_buff[1043]);
+
+		fprintf(stdout,
+			"0x0421C: PCS1GANLP   (PCS-1G AN LP Ability)           0x%08X\n",
+			regs_buff[1044]);
+
+		fprintf(stdout,
+			"0x04220: PCS1GANNP   (PCS_1G Auto Neg Next Page Tx)   0x%08X\n",
+			regs_buff[1045]);
+
+		fprintf(stdout,
+			"0x04224: PCS1GANLPNP (PCS_1G Auto Neg LPs Next Page)  0x%08X\n",
+			regs_buff[1046]);
+	}
+
+	fprintf(stdout,
+		"0x04244: HLREG1      (Highlander Status 1)            0x%08X\n",
+		regs_buff[1048]);
+
+	fprintf(stdout,
+		"0x04248: PAP         (Pause and Pace)                 0x%08X\n",
+		regs_buff[1049]);
+
+	fprintf(stdout,
+		"0x0424C: MACA        (MDI Auto-Scan Command and Addr) 0x%08X\n",
+		regs_buff[1050]);
+
+	fprintf(stdout,
+		"0x04250: APAE        (Auto-Scan PHY Address Enable)   0x%08X\n",
+		regs_buff[1051]);
+
+	fprintf(stdout,
+		"0x04254: ARD         (Auto-Scan Read Data)            0x%08X\n",
+		regs_buff[1052]);
+
+	fprintf(stdout,
+		"0x04258: AIS         (Auto-Scan Interrupt Status)     0x%08X\n",
+		regs_buff[1053]);
+
+	fprintf(stdout,
+		"0x0425C: MSCA        (MDI Single Command and Addr)    0x%08X\n",
+		regs_buff[1054]);
+
+	fprintf(stdout,
+		"0x04260: MSRWD       (MDI Single Read and Write Data) 0x%08X\n",
+		regs_buff[1055]);
+
+	fprintf(stdout,
+		"0x04264: MLADD       (MAC Address Low)                0x%08X\n",
+		regs_buff[1056]);
+
+	fprintf(stdout,
+		"0x04268: MHADD       (MAC Addr High/Max Frame size)   0x%08X\n",
+		regs_buff[1057]);
+
+	fprintf(stdout,
+		"0x0426C: TREG        (Test Register)                  0x%08X\n",
+		regs_buff[1058]);
+
+	if (mac_type < ixgbe_mac_X540) {
+		fprintf(stdout,
+			"0x04288: PCSS1       (XGXS Status 1)                  0x%08X\n",
+			regs_buff[1059]);
+
+		fprintf(stdout,
+			"0x0428C: PCSS2       (XGXS Status 2)                  0x%08X\n",
+			regs_buff[1060]);
+
+		fprintf(stdout,
+			"0x04290: XPCSS       (10GBASE-X PCS Status)           0x%08X\n",
+			regs_buff[1061]);
+
+		fprintf(stdout,
+			"0x04298: SERDESC     (SERDES Interface Control)       0x%08X\n",
+			regs_buff[1062]);
+
+		fprintf(stdout,
+			"0x0429C: MACS        (FIFO Status/CNTL Report)        0x%08X\n",
+			regs_buff[1063]);
+
+		fprintf(stdout,
+			"0x042A0: AUTOC       (Auto Negotiation Control)       0x%08X\n",
+			regs_buff[1064]);
+
+		fprintf(stdout,
+			"0x042A8: AUTOC2      (Auto Negotiation Control 2)     0x%08X\n",
+			regs_buff[1066]);
+
+		fprintf(stdout,
+			"0x042AC: AUTOC3      (Auto Negotiation Control 3)     0x%08X\n",
+			regs_buff[1067]);
+
+		fprintf(stdout,
+			"0x042B0: ANLP1       (Auto Neg Lnk Part. Ctrl Word 1) 0x%08X\n",
+			regs_buff[1068]);
+
+		fprintf(stdout,
+			"0x042B4: ANLP2       (Auto Neg Lnk Part. Ctrl Word 2) 0x%08X\n",
+			regs_buff[1069]);
+	}
+
+	if (mac_type == ixgbe_mac_82598EB) {
+		fprintf(stdout,
+			"0x04800: ATLASCTL    (Atlas Analog Configuration)     0x%08X\n",
+			regs_buff[1070]);
+
+		/* Diagnostic */
+		fprintf(stdout,
+			"0x02C20: RDSTATCTL   (Rx DMA Statistic Control)       0x%08X\n",
+			regs_buff[1071]);
+
+		for (i = 0; i < 8; i++)
+			fprintf(stdout,
+				"0x%05X: RDSTAT%d     (Rx DMA Statistics %d)            0x%08X\n",
+				0x02C00 + (4 * i), i, i, regs_buff[1072 + i]);
+
+		fprintf(stdout,
+			"0x02F08: RDHMPN      (Rx Desc Handler Mem Page num)   0x%08X\n",
+			regs_buff[1080]);
+
+		fprintf(stdout,
+			"0x02F10: RIC_DW0     (Rx Desc Hand. Mem Read Data 0)  0x%08X\n",
+			regs_buff[1081]);
+
+		fprintf(stdout,
+			"0x02F14: RIC_DW1     (Rx Desc Hand. Mem Read Data 1)  0x%08X\n",
+			regs_buff[1082]);
+
+		fprintf(stdout,
+			"0x02F18: RIC_DW2     (Rx Desc Hand. Mem Read Data 2)  0x%08X\n",
+			regs_buff[1083]);
+
+		fprintf(stdout,
+			"0x02F1C: RIC_DW3     (Rx Desc Hand. Mem Read Data 3)  0x%08X\n",
+			regs_buff[1084]);
+	}
+
+	if (mac_type < ixgbe_mac_X540)
+		fprintf(stdout,
+			"0x02F20: RDPROBE     (Rx Probe Mode Status)           0x%08X\n",
+			regs_buff[1085]);
+
+	fprintf(stdout,
+		"0x07C20: TDSTATCTL   (Tx DMA Statistic Control)       0x%08X\n",
+		regs_buff[1086]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: TDSTAT%d     (Tx DMA Statistics %d)            0x%08X\n",
+		0x07C00 + (4 * i), i, i, regs_buff[1087 + i]);
+
+	fprintf(stdout,
+		"0x07F08: TDHMPN      (Tx Desc Handler Mem Page Num)   0x%08X\n",
+		regs_buff[1095]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+			"0x%05X: TIC_DW%d     (Tx Desc Hand. Mem Read Data %d)  0x%08X\n",
+			0x07F10 + (4 * i), i, i, regs_buff[1096 + i]);
+
+	fprintf(stdout,
+		"0x07F20: TDPROBE     (Tx Probe Mode Status)           0x%08X\n",
+		regs_buff[1100]);
+
+	fprintf(stdout,
+		"0x0C600: TXBUFCTRL   (TX Buffer Access Control)       0x%08X\n",
+		regs_buff[1101]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+			"0x%05X: TXBUFDATA%d  (TX Buffer DATA %d)               0x%08X\n",
+			0x0C610 + (4 * i), i, i, regs_buff[1102 + i]);
+
+	fprintf(stdout,
+		"0x03600: RXBUFCTRL   (RX Buffer Access Control)       0x%08X\n",
+		regs_buff[1106]);
+
+	for (i = 0; i < 4; i++)
+		fprintf(stdout,
+			"0x%05X: RXBUFDATA%d  (RX Buffer DATA %d)               0x%08X\n",
+			0x03610 + (4 * i), i, i, regs_buff[1107 + i]);
+
+	for (i = 0; i < 8; i++)
+		fprintf(stdout,
+		"0x%05X: PCIE_DIAG%d  (PCIe Diagnostic %d)              0x%08X\n",
+		0x11090 + (4 * i), i, i, regs_buff[1111 + i]);
+
+	fprintf(stdout,
+		"0x050A4: RFVAL       (Receive Filter Validation)      0x%08X\n",
+		regs_buff[1119]);
+
+	if (mac_type < ixgbe_mac_X540) {
+		fprintf(stdout,
+			"0x042B8: MDFTC1      (MAC DFT Control 1)              0x%08X\n",
+			regs_buff[1120]);
+
+		fprintf(stdout,
+			"0x042C0: MDFTC2      (MAC DFT Control 2)              0x%08X\n",
+			regs_buff[1121]);
+
+		fprintf(stdout,
+			"0x042C4: MDFTFIFO1   (MAC DFT FIFO 1)                 0x%08X\n",
+			regs_buff[1122]);
+
+		fprintf(stdout,
+			"0x042C8: MDFTFIFO2   (MAC DFT FIFO 2)                 0x%08X\n",
+			regs_buff[1123]);
+
+		fprintf(stdout,
+			"0x042CC: MDFTS       (MAC DFT Status)                 0x%08X\n",
+			regs_buff[1124]);
+	}
+
+	if (mac_type == ixgbe_mac_82598EB) {
+		fprintf(stdout,
+			"0x1106C: PCIEECCCTL  (PCIe ECC Control)               0x%08X\n",
+			regs_buff[1125]);
+
+		fprintf(stdout,
+			"0x0C300: PBTXECC     (Packet Buffer Tx ECC)           0x%08X\n",
+			regs_buff[1126]);
+
+		fprintf(stdout,
+			"0x03300: PBRXECC     (Packet Buffer Rx ECC)           0x%08X\n",
+			regs_buff[1127]);
+	}
+
+	if (regs_buff_len > 1139 && mac_type != ixgbe_mac_82598EB) {
+		fprintf(stdout,
+			"0x08800: SECTXCTRL   (Security Tx Control)            0x%08X\n",
+			regs_buff[1139]);
+
+		fprintf(stdout,
+			"0x08804: SECTXSTAT   (Security Tx Status)             0x%08X\n",
+			regs_buff[1140]);
+
+		fprintf(stdout,
+			"0x08808: SECTXBUFFAF (Security Tx Buffer Almost Full) 0x%08X\n",
+			regs_buff[1141]);
+
+		fprintf(stdout,
+			"0x08800: SECTXMINIFG (Security Tx Buffer Minimum IFG) 0x%08X\n",
+			regs_buff[1142]);
+
+		fprintf(stdout,
+			"0x08800: SECRXCTRL   (Security Rx Control)            0x%08X\n",
+			regs_buff[1143]);
+
+		fprintf(stdout,
+			"0x08800: SECRXSTAT   (Security Rx Status)             0x%08X\n",
+			regs_buff[1144]);
+	}
+
+	return 0;
+}
diff --git a/ixgbevf.c b/ixgbevf.c
new file mode 100644
index 0000000..265e0bf
--- /dev/null
+++ b/ixgbevf.c
@@ -0,0 +1,181 @@
+/* Copyright (c) 2013 Intel Corporation */
+#include <stdio.h>
+#include "internal.h"
+
+int
+ixgbevf_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		  struct ethtool_regs *regs)
+{
+	u32 *regs_buff = (u32 *)regs->data;
+	u8 version = (u8)(regs->version >> 24);
+	u8 i;
+
+	if (version == 0)
+		return -1;
+
+	fprintf(stdout,
+		"0x00000: VFCTRL      (VF Control Register) (Write Only) N/A\n");
+
+	fprintf(stdout,
+		"0x00008: VFSTATUS    (VF Status Register)               0x%08X\n",
+		regs_buff[1]);
+
+	fprintf(stdout,
+		"0x00010: VFLINKS     (VF Link Status Register)          0x%08X\n",
+		regs_buff[2]);
+
+	fprintf(stdout,
+		"0x03190: VFRXMEMWRAP (Rx Packet Buffer Flush Detect)    0x%08X\n",
+		regs_buff[3]);
+
+	fprintf(stdout,
+		"0x00048: VFFRTIMER   (VF Free Running Timer)            0x%08X\n",
+		regs_buff[4]);
+
+	fprintf(stdout,
+		"0x00100: VFEICR      (VF Extended Interrupt Cause)      0x%08X\n",
+		regs_buff[5]);
+
+	fprintf(stdout,
+		"0x00104: VFEICS      (VF Extended Interrupt Cause Set)  0x%08X\n",
+		regs_buff[6]);
+
+	fprintf(stdout,
+		"0x00108: VFEIMS      (VF Extended Interrupt Mask Set)   0x%08X\n",
+		regs_buff[7]);
+
+	fprintf(stdout,
+		"0x0010C: VFEIMC      (VF Extended Interrupt Mask Clear) 0x%08X\n",
+		regs_buff[8]);
+
+	fprintf(stdout,
+		"0x00110: VFEIAC      (VF Extended Interrupt Auto Clear) 0x%08X\n",
+		regs_buff[9]);
+
+	fprintf(stdout,
+		"0x00114: VFEIAM      (VF Extended Interrupt Auto Mask)  0x%08X\n",
+		regs_buff[10]);
+
+	fprintf(stdout,
+		"0x00820: VFEITR(0)   (VF Extended Interrupt Throttle)   0x%08X\n",
+		regs_buff[11]);
+
+	fprintf(stdout,
+		"0x00120: VFIVAR(0)   (VF Interrupt Vector Allocation)   0x%08X\n",
+		regs_buff[12]);
+
+	fprintf(stdout,
+		"0x00140: VFIVAR_MISC (VF Interrupt Vector Misc)         0x%08X\n",
+		regs_buff[13]);
+
+	fprintf(stdout,
+		"0x00104: VFPSRTYPE   (VF Replication Packet Split Type) 0x%08X\n",
+		regs_buff[28]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFRDBAL(%d)  (VF Rx Desc. Base Addr Low %d)      0x%08X\n",
+			0x1000 + 0x40*i,
+			i, i,
+			regs_buff[14+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFRDBAH(%d)  (VF Rx Desc. Base Addr High %d)     0x%08X\n",
+			0x1004 + 0x40*i,
+			i, i,
+			regs_buff[16+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFRDLEN(%d)  (VF Rx Desc. Length %d)             0x%08X\n",
+			0x1008 + 0x40*i,
+			i, i,
+			regs_buff[18+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFRDH(%d)    (VF Rx Desc. Head %d)               0x%08X\n",
+			0x1010 + 0x40*i,
+			i, i,
+			regs_buff[20+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFRDT(%d)    (VF Rx Desc. Tail %d)               0x%08X\n",
+			0x1018 + 0x40*i,
+			i, i,
+			regs_buff[22+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFRDT(%d)    (VF Rx Desc. Control %d),           0x%08X\n",
+			0x1028 + 0x40*i,
+			i, i,
+			regs_buff[24+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFSRRCTL(%d) (VF Split Rx Control %d)            0x%08X\n",
+			0x1014 + 0x40*i,
+			i, i,
+			regs_buff[26+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFTDBAL(%d)  (VF Tx Desc. Base Addr Low %d)      0x%08X\n",
+			0x2000 + 0x40*i,
+			i, i,
+			regs_buff[29+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFTDBAH(%d)  (VF Tx Desc. Base Addr High %d)     0x%08X\n",
+			0x2004 + 0x40*i,
+			i, i,
+			regs_buff[31+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFTDLEN(%d)  (VF Tx Desc. Length %d)             0x%08X\n",
+			0x2008 + 0x40*i,
+			i, i,
+			regs_buff[33+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFTDH(%d)    (VF Tx Desc. Head %d)               0x%08X\n",
+			0x2010 + 0x40*i,
+			i, i,
+			regs_buff[35+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFTDT(%d)    (VF Tx Desc. Tail %d)               0x%08X\n",
+			0x2018 + 0x40*i,
+			i, i,
+			regs_buff[37+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFTDT(%d)    (VF Tx Desc. Control %d)            0x%08X\n",
+			0x2028 + 0x40*i,
+			i, i,
+			regs_buff[39+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFTDWBAL(%d) (VF Tx Desc. Write Back Addr Lo %d) 0x%08X\n",
+			0x2038 + 0x40*i,
+			i, i,
+			regs_buff[41+i]);
+
+	for (i = 0; i < 2; i++)
+		fprintf(stdout,
+			"0x%05x: VFTDWBAH(%d) (VF Tx Desc. Write Back Addr Hi %d) 0x%08X\n",
+			0x203C + 0x40*i,
+			i, i,
+			regs_buff[43+i]);
+
+	return 0;
+}
diff --git a/lan78xx.c b/lan78xx.c
new file mode 100644
index 0000000..46ade1c
--- /dev/null
+++ b/lan78xx.c
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <string.h>
+#include "internal.h"
+
+int lan78xx_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		      struct ethtool_regs *regs)
+{
+	unsigned int *lan78xx_reg = (unsigned int *)regs->data;
+
+	fprintf(stdout, "LAN78xx Registers:\n");
+	fprintf(stdout, "------------------\n");
+	fprintf(stdout, "ID_REV       = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "INT_STS      = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "HW_CFG       = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "PMT_CTRL     = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "E2P_CMD      = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "E2P_DATA     = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "USB_STATUS   = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "VLAN_TYPE    = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "\n");
+
+	fprintf(stdout, "MAC Registers:\n");
+	fprintf(stdout, "--------------\n");
+	fprintf(stdout, "MAC_CR             = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "MAC_RX             = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "MAC_TX             = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "FLOW               = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "ERR_STS            = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "MII_ACC            = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "MII_DATA           = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "EEE_TX_LPI_REQ_DLY = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "EEE_TW_TX_SYS      = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "EEE_TX_LPI_REM_DLY = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "WUCSR              = 0x%08X\n", *lan78xx_reg++);
+	fprintf(stdout, "\n");
+
+	fprintf(stdout, "PHY Registers:\n");
+	fprintf(stdout, "--------------\n");
+	fprintf(stdout, "Mode Control = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Mode Status  = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Device identifier1   = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Device identifier2   = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Auto-Neg Advertisement         = 0x%04X\n",
+		*lan78xx_reg++);
+	fprintf(stdout, "Auto-Neg Link Partner Ability  = 0x%04X\n",
+		*lan78xx_reg++);
+	fprintf(stdout, "Auto-Neg Expansion      = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Auto-Neg Next Page TX   = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Auto-Neg Link Partner Next Page RX  = 0x%04X\n",
+		*lan78xx_reg++);
+	fprintf(stdout, "1000BASE-T Control  = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "1000BASE-T Status   = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Reserved  = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Reserved  = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "MMD Access Control       = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "MMD Access Address/Data  = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "1000BASE-T Status Extension1  = 0x%04X\n",
+		*lan78xx_reg++);
+	fprintf(stdout, "1000BASE-TX Status Extension  = 0x%04X\n",
+		*lan78xx_reg++);
+	fprintf(stdout, "1000BASE-T Status Extension2  = 0x%04X\n",
+		*lan78xx_reg++);
+	fprintf(stdout, "Bypass Control  = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout,
+		"100BASE-TX/1000BASE-T Rx Error Counter    = 0x%04X\n",
+		*lan78xx_reg++);
+	fprintf(stdout,
+		"100BASE-TX/1000BASE-T FC Err Counter      = 0x%04X\n",
+		*lan78xx_reg++);
+	fprintf(stdout,
+		"10BASE-T/100BASE-TX/1000BASE-T LD Counter = 0x%04X\n",
+		*lan78xx_reg++);
+	fprintf(stdout, "Extended 10BASE-T Control and Status      = 0x%04X\n",
+		*lan78xx_reg++);
+	fprintf(stdout, "Extended PHY Control1  = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Extended PHY Control2  = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Interrupt Mask    = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Interrupt Status  = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Reserved  = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Auxiliary Control and Status  = 0x%04X\n",
+		*lan78xx_reg++);
+	fprintf(stdout, "LED Mode Select  = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "LED Behavior     = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "Extended Page Access  = 0x%04X\n", *lan78xx_reg++);
+	fprintf(stdout, "\n");
+
+	return 0;
+}
diff --git a/marvell.c b/marvell.c
new file mode 100644
index 0000000..9e5440d
--- /dev/null
+++ b/marvell.c
@@ -0,0 +1,455 @@
+/*
+ * Code to dump Marvell SysKonnect registers for skge and sky2 drivers.
+ *
+ * Copyright (C) 2004, 2006
+ *  Stephen Hemminger <shemminger@osdl.org>
+ */
+
+#include <stdio.h>
+
+#include "internal.h"
+
+static void dump_addr(int n, const u8 *a)
+{
+	int i;
+
+	printf("Addr %d            ", n);
+	for (i = 0; i < 6; i++)
+		printf("%02X%c", a[i], i == 5 ? '\n' : ' ');
+}
+
+static void dump_timer(const char *name, const void *p)
+{
+	const u8 *a = p;
+	const u32 *r = p;
+
+	printf("%s\n", name);
+	printf("\tInit 0x%08X Value 0x%08X\n", r[0], r[1]);
+	printf("\tTest 0x%02X       Control 0x%02X\n", a[8], a[9]);
+}
+
+static void dump_queue(const char *name, const void *a, int rx)
+{
+	struct desc {
+		u_int32_t		ctl;
+		u_int32_t		next;
+		u_int32_t		data_lo;
+		u_int32_t		data_hi;
+		u_int32_t		status;
+		u_int32_t		timestamp;
+		u_int16_t		csum2;
+		u_int16_t		csum1;
+		u_int16_t		csum2_start;
+		u_int16_t		csum1_start;
+		u_int32_t		addr_lo;
+		u_int32_t		addr_hi;
+		u_int32_t		count_lo;
+		u_int32_t		count_hi;
+		u_int32_t               byte_count;
+		u_int32_t               csr;
+		u_int32_t               flag;
+	};
+	const struct desc *d = a;
+
+	/* is reset bit set? */
+	if (!(d->ctl & 2)) {
+		printf("\n%s (disabled)\n", name);
+		return;
+	}
+
+	printf("\n%s\n", name);
+	printf("---------------\n");
+	printf("Descriptor Address       0x%08X%08X\n",
+	       d->addr_hi, d->addr_lo);
+	printf("Address Counter          0x%08X%08X\n",
+	       d->count_hi, d->count_lo);
+	printf("Current Byte Counter             %d\n", d->byte_count);
+	printf("BMU Control/Status               0x%08X\n", d->csr);
+	printf("Flag & FIFO Address              0x%08X\n", d->flag);
+	printf("\n");
+	printf("Control                          0x%08X\n", d->ctl);
+	printf("Next                             0x%08X\n", d->next);
+	printf("Data                     0x%08X%08X\n",
+	       d->data_hi, d->data_lo);
+	printf("Status                           0x%08X\n", d->status);
+	printf("Timestamp                        0x%08X\n", d->timestamp);
+	if (rx) {
+		printf("Csum1      Offset %4d Position  %d\n",
+		       d->csum1, d->csum1_start);
+		printf("Csum2      Offset %4d Position  %d\n",
+		       d->csum2, d->csum2_start);
+	} else
+		printf("Csum Start 0x%04X Pos %4d Write %d\n",
+		       d->csum1, d->csum2_start, d->csum1_start);
+
+}
+
+static void dump_ram(const char *name, const void *p)
+{
+	const u32 *r = p;
+
+	if (!(r[10] & 2)) {
+		printf("\n%s (disabled)\n", name);
+		return;
+	}
+
+	printf("\n%s\n", name);
+	printf("---------------\n");
+	printf("Start Address                    0x%08X\n", r[0]);
+	printf("End Address                      0x%08X\n", r[1]);
+	printf("Write Pointer                    0x%08X\n", r[2]);
+	printf("Read Pointer                     0x%08X\n", r[3]);
+
+	if (*name == 'R') { /* Receive only */
+		printf("Upper Threshold/Pause Packets    0x%08X\n", r[4]);
+		printf("Lower Threshold/Pause Packets    0x%08X\n", r[5]);
+		printf("Upper Threshold/High Priority    0x%08X\n", r[6]);
+		printf("Lower Threshold/High Priority    0x%08X\n", r[7]);
+	}
+	printf("Packet Counter                   0x%08X\n", r[8]);
+	printf("Level                            0x%08X\n", r[9]);
+	printf("Control                          0x%08X\n", r[10]);
+}
+
+static void dump_fifo(const char *name, const void *p)
+{
+	const u32 *r = p;
+
+	printf("\n%s\n", name);
+	printf("---------------\n");
+	printf("End Address                      0x%08X\n", r[0]);
+	printf("Write Pointer                    0x%08X\n", r[1]);
+	printf("Read Pointer                     0x%08X\n", r[2]);
+	printf("Packet Counter                   0x%08X\n", r[3]);
+	printf("Level                            0x%08X\n", r[4]);
+	printf("Control                          0x%08X\n", r[5]);
+	printf("Control/Test                     0x%08X\n", r[6]);
+	dump_timer("LED", r + 8);
+}
+
+static void dump_gmac_fifo(const char *name, const void *p)
+{
+	const u32 *r = p;
+	int i;
+	static const char *regs[] = {
+		"End Address",
+		"Almost Full Thresh",
+		"Control/Test",
+		"FIFO Flush Mask",
+		"FIFO Flush Threshold",
+		"Truncation Threshold",
+		"Upper Pause Threshold",
+		"Lower Pause Threshold",
+		"VLAN Tag",
+		"FIFO Write Pointer",
+		"FIFO Write Level",
+		"FIFO Read Pointer",
+		"FIFO Read Level",
+	};
+
+	printf("\n%s\n", name);
+	for (i = 0; i < sizeof(regs)/sizeof(regs[0]); ++i)
+		printf("%-32s 0x%08X\n", regs[i], r[i]);
+
+}
+
+static void dump_mac(const u8 *r)
+{
+	u8 id;
+
+	printf("\nMAC Addresses\n");
+	printf("---------------\n");
+	dump_addr(1, r + 0x100);
+	dump_addr(2, r + 0x108);
+	dump_addr(3, r + 0x110);
+	printf("\n");
+
+	printf("Connector type               0x%02X (%c)\n",
+	       r[0x118], (char)r[0x118]);
+	printf("PMD type                     0x%02X (%c)\n",
+	       r[0x119], (char)r[0x119]);
+	printf("PHY type                     0x%02X\n", r[0x11d]);
+
+	id = r[0x11b];
+	printf("Chip Id                      0x%02X ", id);
+
+	switch (id) {
+	case 0x0a:	printf("Genesis");	break;
+	case 0xb0:	printf("Yukon");	break;
+	case 0xb1:	printf("Yukon-Lite");	break;
+	case 0xb2:	printf("Yukon-LP");	break;
+	case 0xb3:	printf("Yukon-2 XL");	break;
+	case 0xb5:	printf("Yukon Extreme"); break;
+	case 0xb4:	printf("Yukon-2 EC Ultra");	break;
+	case 0xb6:	printf("Yukon-2 EC");	break;
+ 	case 0xb7:	printf("Yukon-2 FE");	break;
+	case 0xb8:	printf("Yukon-2 FE Plus"); break;
+	case 0xb9:	printf("Yukon Supreme"); break;
+	case 0xba:	printf("Yukon Ultra 2"); break;
+	case 0xbc:	printf("Yukon Optima"); break;
+	default:	printf("(Unknown)");	break;
+	}
+
+	printf(" (rev %d)\n", (r[0x11a] & 0xf0) >> 4);
+
+	printf("Ram Buffer                   0x%02X\n", r[0x11c]);
+
+}
+
+static void dump_gma(const char *name, const u8 *r)
+{
+	int i;
+
+	printf("%12s address: ", name);
+	for (i = 0; i < 3; i++) {
+		u16 a = *(u16 *)(r + i * 4);
+		printf(" %02X %02X", a & 0xff, (a >> 8) & 0xff);
+	}
+	printf("\n");
+}
+
+static void dump_gmac(const char *name, const u8 *data)
+{
+	printf("\n%s\n", name);
+
+	printf("Status                       0x%04X\n", *(u16 *) data);
+	printf("Control                      0x%04X\n", *(u16 *) (data + 4));
+	printf("Transmit                     0x%04X\n", *(u16 *) (data + 8));
+	printf("Receive                      0x%04X\n", *(u16 *) (data + 0xc));
+	printf("Transmit flow control        0x%04X\n", *(u16 *) (data + 0x10));
+	printf("Transmit parameter           0x%04X\n", *(u16 *) (data + 0x14));
+	printf("Serial mode                  0x%04X\n", *(u16 *) (data + 0x18));
+
+	dump_gma("Source", data + 0x1c);
+	dump_gma("Physical", data + 0x28);
+}
+
+static void dump_pci(const u8 *cfg)
+{
+	int i;
+
+	printf("\nPCI config\n----------\n");
+	for(i = 0; i < 0x80; i++) {
+		if (!(i & 15))
+			printf("%02x:", i);
+		printf(" %02x", cfg[i]);
+		if ((i & 15) == 15)
+			putchar('\n');
+	}
+	putchar('\n');
+}
+
+static void dump_control(u8 *r)
+{
+	printf("Control Registers\n");
+	printf("-----------------\n");
+
+	printf("Register Access Port             0x%02X\n", *r);
+	printf("LED Control/Status               0x%08X\n", *(u32 *) (r + 4));
+
+	printf("Interrupt Source                 0x%08X\n", *(u32 *) (r + 8));
+	printf("Interrupt Mask                   0x%08X\n", *(u32 *) (r + 0xc));
+	printf("Interrupt Hardware Error Source  0x%08X\n", *(u32 *) (r + 0x10));
+	printf("Interrupt Hardware Error Mask    0x%08X\n", *(u32 *) (r + 0x14));
+	printf("Interrupt Control                0x%08X\n", *(u32 *) (r + 0x2c));
+	printf("Interrupt Moderation Mask        0x%08X\n", *(u32 *) (r + 0x14c));
+	printf("Hardware Moderation Mask         0x%08X\n", *(u32 *) (r + 0x150));
+	dump_timer("Moderation Timer", r + 0x140);
+
+	printf("General Purpose  I/O             0x%08X\n", *(u32 *) (r + 0x15c));
+}
+
+int skge_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		   struct ethtool_regs *regs)
+{
+	const u32 *r = (const u32 *) regs->data;
+	int dual = !(regs->data[0x11a] & 1);
+
+	dump_pci(regs->data + 0x380);
+
+	dump_control(regs->data);
+
+	printf("\nBus Management Unit\n");
+	printf("-------------------\n");
+	printf("CSR Receive Queue 1              0x%08X\n", r[24]);
+	printf("CSR Sync Queue 1                 0x%08X\n", r[26]);
+	printf("CSR Async Queue 1                0x%08X\n", r[27]);
+	if (dual) {
+		printf("CSR Receive Queue 2              0x%08X\n", r[25]);
+		printf("CSR Async Queue 2                0x%08X\n", r[29]);
+		printf("CSR Sync Queue 2                 0x%08X\n", r[28]);
+	}
+
+	dump_mac(regs->data);
+	dump_gmac("GMAC 1", regs->data + 0x2800);
+
+	dump_timer("Timer", regs->data + 0x130);
+	dump_timer("Blink Source", regs->data +0x170);
+
+	dump_queue("Receive Queue 1", regs->data +0x400, 1);
+	dump_queue("Sync Transmit Queue 1", regs->data +0x600, 0);
+	dump_queue("Async Transmit Queue 1", regs->data +0x680, 0);
+
+	dump_ram("Receive RAMbuffer 1", regs->data+0x800);
+	dump_ram("Sync Transmit RAMbuffer 1", regs->data+0xa00);
+	dump_ram("Async Transmit RAMbuffer 1", regs->data+0xa80);
+
+	dump_fifo("Receive MAC FIFO 1", regs->data+0xc00);
+	dump_fifo("Transmit MAC FIFO 1", regs->data+0xd00);
+	if (dual) {
+		dump_gmac("GMAC 1", regs->data + 0x2800);
+
+		dump_queue("Receive Queue 2", regs->data +0x480, 1);
+		dump_queue("Async Transmit Queue 2", regs->data +0x780, 0);
+		dump_queue("Sync Transmit Queue 2", regs->data +0x700, 0);
+
+		dump_ram("Receive RAMbuffer 2", regs->data+0x880);
+		dump_ram("Sync Transmit RAMbuffer 2", regs->data+0xb00);
+		dump_ram("Async Transmit RAMbuffer 21", regs->data+0xb80);
+
+		dump_fifo("Receive MAC FIFO 2", regs->data+0xc80);
+		dump_fifo("Transmit MAC FIFO 2", regs->data+0xd80);
+	}
+
+	dump_timer("Descriptor Poll", regs->data+0xe00);
+	return 0;
+
+}
+
+static void dump_queue2(const char *name, void *a, int rx)
+{
+	struct sky2_queue {
+		u16	buf_control;
+		u16	byte_count;
+		u32	rss;
+		u32	addr_lo, addr_hi;
+		u32	status;
+		u32	timestamp;
+		u16	csum1, csum2;
+		u16	csum1_start, csum2_start;
+		u16	length;
+		u16	vlan;
+		u16	rsvd1;
+		u16	done;
+		u32	req_lo, req_hi;
+		u16	rsvd2;
+		u16	req_count;
+		u32	csr;
+	} *d = a;
+
+	printf("\n%s\n", name);
+	printf("---------------\n");
+
+	printf("Buffer control                   0x%04X\n", d->buf_control);
+
+	printf("Byte Counter                     %d\n", d->byte_count);
+	printf("Descriptor Address               0x%08X%08X\n",
+	       d->addr_hi, d->addr_lo);
+	printf("Status                           0x%08X\n", d->status);
+	printf("Timestamp                        0x%08X\n", d->timestamp);
+	printf("BMU Control/Status               0x%08X\n", d->csr);
+	printf("Done                             0x%04X\n", d->done);
+	printf("Request                          0x%08X%08X\n",
+	       d->req_hi, d->req_lo);
+	if (rx) {
+		printf("Csum1      Offset %4d Position  %d\n",
+		       d->csum1, d->csum1_start);
+		printf("Csum2      Offset %4d Position  %d\n",
+		       d->csum2, d->csum2_start);
+	} else
+		printf("Csum Start 0x%04X Pos %4d Write %d\n",
+		       d->csum1, d->csum2_start, d->csum1_start);
+}
+
+static void dump_prefetch(const char *name, const void *r)
+{
+	const u32 *reg = r;
+
+	printf("\n%s Prefetch\n", name);
+	printf("Control               0x%08X\n", reg[0]);
+	printf("Last Index            %u\n", reg[1]);
+	printf("Start Address         0x%08x%08x\n", reg[3], reg[2]);
+	if (*name == 'S') { /* Status unit */
+		printf("TX1 report            %u\n", reg[4]);
+		printf("TX2 report            %u\n", reg[5]);
+		printf("TX threshold          %u\n", reg[6]);
+		printf("Put Index             %u\n", reg[7]);
+	} else {
+		printf("Get Index             %u\n", reg[4]);
+		printf("Put Index             %u\n", reg[5]);
+	}
+}
+
+int sky2_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		   struct ethtool_regs *regs)
+{
+	const u16 *r16 = (const u16 *) regs->data;
+	const u32 *r32 = (const u32 *) regs->data;
+	int dual;
+
+	dump_pci(regs->data + 0x1c00);
+
+	dump_control(regs->data);
+
+	printf("\nBus Management Unit\n");
+	printf("-------------------\n");
+	printf("CSR Receive Queue 1              0x%08X\n", r32[24]);
+	printf("CSR Sync Queue 1                 0x%08X\n", r32[26]);
+	printf("CSR Async Queue 1                0x%08X\n", r32[27]);
+
+	dual = (regs->data[0x11e] & 2) != 0;
+	if (dual) {
+		printf("CSR Receive Queue 2              0x%08X\n", r32[25]);
+		printf("CSR Async Queue 2                0x%08X\n", r32[29]);
+		printf("CSR Sync Queue 2                 0x%08X\n", r32[28]);
+	}
+
+	dump_mac(regs->data);
+
+	dump_prefetch("Status", regs->data + 0xe80);
+	dump_prefetch("Receive 1", regs->data + 0x450);
+	dump_prefetch("Transmit 1", regs->data + 0x450 + 0x280);
+
+	if (dual) {
+		dump_prefetch("Receive 2", regs->data + 0x450 + 0x80);
+		dump_prefetch("Transmit 2", regs->data + 0x450 + 0x380);
+	}
+
+	printf("\nStatus FIFO\n");
+  	printf("\tWrite Pointer            0x%02X\n", regs->data[0xea0]);
+  	printf("\tRead Pointer             0x%02X\n", regs->data[0xea4]);
+  	printf("\tLevel                    0x%02X\n", regs->data[0xea8]);
+  	printf("\tWatermark                0x%02X\n", regs->data[0xeac]);
+  	printf("\tISR Watermark            0x%02X\n", regs->data[0xead]);
+
+	dump_timer("Status level", regs->data + 0xeb0);
+	dump_timer("TX status", regs->data + 0xec0);
+	dump_timer("ISR", regs->data + 0xed0);
+
+	printf("\nGMAC control             0x%04X\n", r32[0xf00 >> 2]);
+	printf("GPHY control             0x%04X\n", r32[0xf04 >> 2]);
+	printf("LINK control             0x%02hX\n", r16[0xf10 >> 1]);
+
+	dump_gmac("GMAC 1", regs->data + 0x2800);
+	dump_gmac_fifo("Rx GMAC 1", regs->data + 0xc40);
+	dump_gmac_fifo("Tx GMAC 1", regs->data + 0xd40);
+
+	dump_queue2("Receive Queue 1", regs->data +0x400, 1);
+	dump_queue("Sync Transmit Queue 1", regs->data +0x600, 0);
+	dump_queue2("Async Transmit Queue 1", regs->data +0x680, 0);
+
+	dump_ram("Receive RAMbuffer 1", regs->data+0x800);
+	dump_ram("Sync Transmit RAMbuffer 1", regs->data+0xa00);
+	dump_ram("Async Transmit RAMbuffer 1", regs->data+0xa80);
+
+	if (dual) {
+		dump_ram("Receive RAMbuffer 2", regs->data+0x880);
+		dump_ram("Sync Transmit RAMbuffer 2", regs->data+0xb00);
+		dump_ram("Async Transmit RAMbuffer 21", regs->data+0xb80);
+		dump_gmac("GMAC 2", regs->data + 0x3800);
+		dump_gmac_fifo("Rx GMAC 2", regs->data + 0xc40 + 128);
+		dump_gmac_fifo("Tx GMAC 2", regs->data + 0xd40 + 128);
+	}
+
+	return 0;
+}
diff --git a/natsemi.c b/natsemi.c
new file mode 100644
index 0000000..ce82c42
--- /dev/null
+++ b/natsemi.c
@@ -0,0 +1,987 @@
+/* Copyright 2001 Sun Microsystems (thockin@sun.com) */
+#include <stdio.h>
+#include "internal.h"
+
+#define PCI_VENDOR_NATSEMI		0x100b
+#define PCI_DEVICE_DP83815		0x0020
+#define NATSEMI_MAGIC			(PCI_VENDOR_NATSEMI | \
+					 (PCI_DEVICE_DP83815<<16))
+
+/* register indices in the ethtool_regs->data */
+#define REG_CR				0
+#define   BIT_CR_TXE			(1<<0)
+#define   BIT_CR_RXE			(1<<2)
+#define   BIT_CR_RST			(1<<8)
+#define REG_CFG				1
+#define   BIT_CFG_BEM			(1<<0)
+#define   BIT_CFG_BROM_DIS		(1<<2)
+#define   BIT_CFG_PHY_DIS		(1<<9)
+#define   BIT_CFG_PHY_RST		(1<<10)
+#define   BIT_CFG_EXT_PHY		(1<<12)
+#define   BIT_CFG_ANEG_EN		(1<<13)
+#define   BIT_CFG_ANEG_100		(1<<14)
+#define   BIT_CFG_ANEG_FDUP		(1<<15)
+#define   BIT_CFG_PINT_ACEN		(1<<17)
+#define   BIT_CFG_PHY_CFG		(0x3f<<18)
+#define   BIT_CFG_ANEG_DN		(1<<27)
+#define   BIT_CFG_POL			(1<<28)
+#define   BIT_CFG_FDUP			(1<<29)
+#define   BIT_CFG_SPEED100		(1<<30)
+#define   BIT_CFG_LNKSTS		(1<<31)
+
+#define REG_MEAR			2
+#define REG_PTSCR			3
+#define   BIT_PTSCR_EEBIST_FAIL		(1<<0)
+#define   BIT_PTSCR_EELOAD_EN		(1<<2)
+#define   BIT_PTSCR_RBIST_RXFFAIL	(1<<3)
+#define   BIT_PTSCR_RBIST_TXFAIL	(1<<4)
+#define   BIT_PTSCR_RBIST_RXFAIL	(1<<5)
+#define REG_ISR				4
+#define REG_IMR				5
+#define   BIT_INTR_RXOK			(1<<0)
+#define   NAME_INTR_RXOK		"Rx Complete"
+#define   BIT_INTR_RXDESC		(1<<1)
+#define   NAME_INTR_RXDESC		"Rx Descriptor"
+#define   BIT_INTR_RXERR		(1<<2)
+#define   NAME_INTR_RXERR		"Rx Packet Error"
+#define   BIT_INTR_RXEARLY		(1<<3)
+#define   NAME_INTR_RXEARLY		"Rx Early Threshold"
+#define   BIT_INTR_RXIDLE		(1<<4)
+#define   NAME_INTR_RXIDLE		"Rx Idle"
+#define   BIT_INTR_RXORN		(1<<5)
+#define   NAME_INTR_RXORN		"Rx Overrun"
+#define   BIT_INTR_TXOK			(1<<6)
+#define   NAME_INTR_TXOK		"Tx Packet OK"
+#define   BIT_INTR_TXDESC		(1<<7)
+#define   NAME_INTR_TXDESC		"Tx Descriptor"
+#define   BIT_INTR_TXERR		(1<<8)
+#define   NAME_INTR_TXERR		"Tx Packet Error"
+#define   BIT_INTR_TXIDLE		(1<<9)
+#define   NAME_INTR_TXIDLE		"Tx Idle"
+#define   BIT_INTR_TXURN		(1<<10)
+#define   NAME_INTR_TXURN		"Tx Underrun"
+#define   BIT_INTR_MIB			(1<<11)
+#define   NAME_INTR_MIB			"MIB Service"
+#define   BIT_INTR_SWI			(1<<12)
+#define   NAME_INTR_SWI			"Software"
+#define   BIT_INTR_PME			(1<<13)
+#define   NAME_INTR_PME			"Power Management Event"
+#define   BIT_INTR_PHY			(1<<14)
+#define   NAME_INTR_PHY			"Phy"
+#define   BIT_INTR_HIBERR		(1<<15)
+#define   NAME_INTR_HIBERR		"High Bits Error"
+#define   BIT_INTR_RXSOVR		(1<<16)
+#define   NAME_INTR_RXSOVR		"Rx Status FIFO Overrun"
+#define   BIT_INTR_RTABT		(1<<20)
+#define   NAME_INTR_RTABT		"Received Target Abort"
+#define   BIT_INTR_RMABT		(1<<20)
+#define   NAME_INTR_RMABT		"Received Master Abort"
+#define   BIT_INTR_SSERR		(1<<20)
+#define   NAME_INTR_SSERR		"Signaled System Error"
+#define   BIT_INTR_DPERR		(1<<20)
+#define   NAME_INTR_DPERR		"Detected Parity Error"
+#define   BIT_INTR_RXRCMP		(1<<20)
+#define   NAME_INTR_RXRCMP		"Rx Reset Complete"
+#define   BIT_INTR_TXRCMP		(1<<20)
+#define   NAME_INTR_TXRCMP		"Tx Reset Complete"
+#define REG_IER				6
+#define   BIT_IER_IE			(1<<0)
+#define REG_TXDP			8
+#define REG_TXCFG			9
+#define   BIT_TXCFG_DRTH		(0x3f<<0)
+#define   BIT_TXCFG_FLTH		(0x3f<<8)
+#define   BIT_TXCFG_MXDMA		(0x7<<20)
+#define   BIT_TXCFG_ATP			(1<<28)
+#define   BIT_TXCFG_MLB			(1<<29)
+#define   BIT_TXCFG_HBI			(1<<30)
+#define   BIT_TXCFG_CSI			(1<<31)
+#define REG_RXDP			12
+#define REG_RXCFG			13
+#define   BIT_RXCFG_DRTH		(0x1f<<1)
+#define   BIT_RXCFG_MXDMA		(0x7<<20)
+#define   BIT_RXCFG_ALP			(1<<27)
+#define   BIT_RXCFG_ATX			(1<<28)
+#define   BIT_RXCFG_ARP			(1<<30)
+#define   BIT_RXCFG_AEP			(1<<31)
+#define REG_CCSR			15
+#define   BIT_CCSR_CLKRUN_EN		(1<<0)
+#define   BIT_CCSR_PMEEN		(1<<8)
+#define   BIT_CCSR_PMESTS		(1<<15)
+#define REG_WCSR			16
+#define   BIT_WCSR_WKPHY		(1<<0)
+#define   BIT_WCSR_WKUCP		(1<<1)
+#define   BIT_WCSR_WKMCP		(1<<2)
+#define   BIT_WCSR_WKBCP		(1<<3)
+#define   BIT_WCSR_WKARP		(1<<4)
+#define   BIT_WCSR_WKPAT0		(1<<5)
+#define   BIT_WCSR_WKPAT1		(1<<6)
+#define   BIT_WCSR_WKPAT2		(1<<7)
+#define   BIT_WCSR_WKPAT3		(1<<8)
+#define   BIT_WCSR_WKMAG		(1<<9)
+#define   BIT_WCSR_MPSOE		(1<<10)
+#define   BIT_WCSR_SOHACK		(1<<20)
+#define   BIT_WCSR_PHYINT		(1<<22)
+#define   BIT_WCSR_UCASTR		(1<<23)
+#define   BIT_WCSR_MCASTR		(1<<24)
+#define   BIT_WCSR_BCASTR		(1<<25)
+#define   BIT_WCSR_ARPR			(1<<26)
+#define   BIT_WCSR_PATM0		(1<<27)
+#define   BIT_WCSR_PATM1		(1<<28)
+#define   BIT_WCSR_PATM2		(1<<29)
+#define   BIT_WCSR_PATM3		(1<<30)
+#define   BIT_WCSR_MPR			(1<<31)
+#define REG_PCR				17
+#define   BIT_PCR_PAUSE_CNT		(0xffff<<0)
+#define   BIT_PCR_PSNEG			(1<<21)
+#define   BIT_PCR_PS_RCVD		(1<<22)
+#define   BIT_PCR_PS_DA			(1<<29)
+#define   BIT_PCR_PSMCAST		(1<<30)
+#define   BIT_PCR_PSEN			(1<<31)
+#define REG_RFCR			18
+#define   BIT_RFCR_UHEN			(1<<20)
+#define   BIT_RFCR_MHEN			(1<<21)
+#define   BIT_RFCR_AARP			(1<<22)
+#define   BIT_RFCR_APAT0		(1<<23)
+#define   BIT_RFCR_APAT1		(1<<24)
+#define   BIT_RFCR_APAT2		(1<<25)
+#define   BIT_RFCR_APAT3		(1<<26)
+#define   BIT_RFCR_APM			(1<<27)
+#define   BIT_RFCR_AAU			(1<<28)
+#define   BIT_RFCR_AAM			(1<<29)
+#define   BIT_RFCR_AAB			(1<<30)
+#define   BIT_RFCR_RFEN			(1<<31)
+#define REG_RFDR			19
+#define REG_BRAR			20
+#define   BIT_BRAR_AUTOINC		(1<<31)
+#define REG_BRDR			21
+#define REG_SRR				22
+#define REG_MIBC			23
+#define   BIT_MIBC_WRN			(1<<0)
+#define   BIT_MIBC_FRZ			(1<<1)
+#define REG_MIB0			24
+#define REG_MIB1			25
+#define REG_MIB2			26
+#define REG_MIB3			27
+#define REG_MIB4			28
+#define REG_MIB5			29
+#define REG_MIB6			30
+#define REG_BMCR			32
+#define   BIT_BMCR_FDUP			(1<<8)
+#define   BIT_BMCR_ANRST		(1<<9)
+#define   BIT_BMCR_ISOL			(1<<10)
+#define   BIT_BMCR_PDOWN		(1<<11)
+#define   BIT_BMCR_ANEN			(1<<12)
+#define   BIT_BMCR_SPEED		(1<<13)
+#define   BIT_BMCR_LOOP			(1<<14)
+#define   BIT_BMCR_RST			(1<<15)
+#define REG_BMSR			33
+#define   BIT_BMSR_JABBER		(1<<1)
+#define   BIT_BMSR_LNK			(1<<2)
+#define   BIT_BMSR_ANCAP		(1<<3)
+#define   BIT_BMSR_RFAULT		(1<<4)
+#define   BIT_BMSR_ANDONE		(1<<5)
+#define   BIT_BMSR_PREAMBLE		(1<<6)
+#define   BIT_BMSR_10HCAP		(1<<11)
+#define   BIT_BMSR_10FCAP		(1<<12)
+#define   BIT_BMSR_100HCAP		(1<<13)
+#define   BIT_BMSR_100FCAP		(1<<14)
+#define   BIT_BMSR_100T4CAP		(1<<15)
+#define REG_PHYIDR1			34
+#define REG_PHYIDR2			35
+#define   BIT_PHYIDR2_OUILSB		(0x3f<<10)
+#define   BIT_PHYIDR2_MODEL		(0x3f<<4)
+#define   BIT_PHYIDR2_REV		(0xf)
+#define REG_ANAR			36
+#define   BIT_ANAR_PROTO		(0x1f<<0)
+#define   BIT_ANAR_10			(1<<5)
+#define   BIT_ANAR_10_FD		(1<<6)
+#define   BIT_ANAR_TX			(1<<7)
+#define   BIT_ANAR_TXFD			(1<<8)
+#define   BIT_ANAR_T4			(1<<9)
+#define   BIT_ANAR_PAUSE		(1<<10)
+#define   BIT_ANAR_RF			(1<<13)
+#define   BIT_ANAR_NP			(1<<15)
+#define REG_ANLPAR			37
+#define   BIT_ANLPAR_PROTO		(0x1f<<0)
+#define   BIT_ANLPAR_10			(1<<5)
+#define   BIT_ANLPAR_10_FD		(1<<6)
+#define   BIT_ANLPAR_TX			(1<<7)
+#define   BIT_ANLPAR_TXFD		(1<<8)
+#define   BIT_ANLPAR_T4			(1<<9)
+#define   BIT_ANLPAR_PAUSE		(1<<10)
+#define   BIT_ANLPAR_RF			(1<<13)
+#define   BIT_ANLPAR_ACK		(1<<14)
+#define   BIT_ANLPAR_NP			(1<<15)
+#define REG_ANER			38
+#define   BIT_ANER_LP_AN_ENABLE		(1<<0)
+#define   BIT_ANER_PAGE_RX		(1<<1)
+#define   BIT_ANER_NP_ABLE		(1<<2)
+#define   BIT_ANER_LP_NP_ABLE		(1<<3)
+#define   BIT_ANER_PDF			(1<<4)
+#define REG_ANNPTR			39
+#define REG_PHYSTS			48
+#define   BIT_PHYSTS_LNK		(1<<0)
+#define   BIT_PHYSTS_SPD10		(1<<1)
+#define   BIT_PHYSTS_FDUP		(1<<2)
+#define   BIT_PHYSTS_LOOP		(1<<3)
+#define   BIT_PHYSTS_ANDONE		(1<<4)
+#define   BIT_PHYSTS_JABBER		(1<<5)
+#define   BIT_PHYSTS_RF			(1<<6)
+#define   BIT_PHYSTS_MINT		(1<<7)
+#define   BIT_PHYSTS_FC			(1<<11)
+#define   BIT_PHYSTS_POL		(1<<12)
+#define   BIT_PHYSTS_RXERR		(1<<13)
+#define REG_MICR			49
+#define   BIT_MICR_INTEN		(1<<1)
+#define REG_MISR			50
+#define   BIT_MISR_MSK_RHF		(1<<9)
+#define   BIT_MISR_MSK_FHF		(1<<10)
+#define   BIT_MISR_MSK_ANC		(1<<11)
+#define   BIT_MISR_MSK_RF		(1<<12)
+#define   BIT_MISR_MSK_JAB		(1<<13)
+#define   BIT_MISR_MSK_LNK		(1<<14)
+#define   BIT_MISR_MINT			(1<<15)
+#define REG_PGSEL			51
+#define REG_FCSCR			52
+#define REG_RECR			53
+#define REG_PCSR			54
+#define   BIT_PCSR_NRZI			(1<<2)
+#define   BIT_PCSR_FORCE_100		(1<<5)
+#define   BIT_PCSR_SDOPT		(1<<8)
+#define   BIT_PCSR_SDFORCE		(1<<9)
+#define   BIT_PCSR_TQM			(1<<10)
+#define   BIT_PCSR_CLK			(1<<11)
+#define   BIT_PCSR_4B5B			(1<<12)
+#define REG_PHYCR			57
+#define   BIT_PHYCR_PHYADDR		(0x1f<<0)
+#define   BIT_PHYCR_PAUSE_STS		(1<<7)
+#define   BIT_PHYCR_STRETCH		(1<<8)
+#define   BIT_PHYCR_BIST		(1<<9)
+#define   BIT_PHYCR_BIST_STAT		(1<<10)
+#define   BIT_PHYCR_PSR15		(1<<11)
+#define REG_TBTSCR			58
+#define   BIT_TBTSCR_JAB		(1<<0)
+#define   BIT_TBTSCR_BEAT		(1<<1)
+#define   BIT_TBTSCR_AUTOPOL		(1<<3)
+#define   BIT_TBTSCR_POL		(1<<4)
+#define   BIT_TBTSCR_FPOL		(1<<5)
+#define   BIT_TBTSCR_FORCE_10		(1<<6)
+#define   BIT_TBTSCR_PULSE		(1<<7)
+#define   BIT_TBTSCR_LOOP		(1<<8)
+#define REG_PMDCSR			64
+#define REG_TSTDAT			65
+#define REG_DSPCFG			66
+#define REG_SDCFG			67
+#define REG_PMATCH0			68
+#define REG_PMATCH1			69
+#define REG_PMATCH2			70
+#define REG_PCOUNT0			71
+#define REG_PCOUNT1			72
+#define REG_SOPASS0			73
+#define REG_SOPASS1			74
+#define REG_SOPASS2			75
+
+static void __print_intr(int d, int intr, const char *name,
+			 const char *s1, const char *s2)
+{
+	if ((d) & intr)
+		fprintf(stdout, "      %s Interrupt: %s\n", name, s1);
+	else if (s2)
+		fprintf(stdout, "      %s Interrupt: %s\n", name, s2);
+}
+
+#define PRINT_INTR(d, i, s1, s2) do { \
+	int intr = BIT_INTR_ ## i; \
+	const char *name = NAME_INTR_ ## i; \
+	__print_intr(d, intr, name, s1, s2); \
+} while (0)
+
+#define PRINT_INTRS(d, s1, s2) do { \
+	PRINT_INTR((d), RXOK, s1, s2); \
+	PRINT_INTR((d), RXDESC, s1, s2); \
+	PRINT_INTR((d), RXERR, s1, s2); \
+	PRINT_INTR((d), RXEARLY, s1, s2); \
+	PRINT_INTR((d), RXIDLE, s1, s2); \
+	PRINT_INTR((d), RXORN, s1, s2); \
+	PRINT_INTR((d), TXOK, s1, s2); \
+	PRINT_INTR((d), TXDESC, s1, s2); \
+	PRINT_INTR((d), TXERR, s1, s2); \
+	PRINT_INTR((d), TXIDLE, s1, s2); \
+	PRINT_INTR((d), TXURN, s1, s2); \
+	PRINT_INTR((d), MIB, s1, s2); \
+	PRINT_INTR((d), SWI, s1, s2); \
+	PRINT_INTR((d), PME, s1, s2); \
+	PRINT_INTR((d), PHY, s1, s2); \
+	PRINT_INTR((d), HIBERR, s1, s2); \
+	PRINT_INTR((d), RXSOVR, s1, s2); \
+	PRINT_INTR((d), RTABT, s1, s2); \
+	PRINT_INTR((d), RMABT, s1, s2); \
+	PRINT_INTR((d), SSERR, s1, s2); \
+	PRINT_INTR((d), DPERR, s1, s2); \
+	PRINT_INTR((d), RXRCMP, s1, s2); \
+	PRINT_INTR((d), TXRCMP, s1, s2); \
+} while (0)
+
+int
+natsemi_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		  struct ethtool_regs *regs)
+{
+	u32 *data = (u32 *)regs->data;
+	u32 tmp;
+
+	fprintf(stdout, "Mac/BIU Registers\n");
+	fprintf(stdout, "-----------------\n");
+
+	/* command register */
+	fprintf(stdout,
+		"0x00: CR (Command):                      0x%08x\n",
+		data[REG_CR]);
+	fprintf(stdout,
+		"      Transmit %s\n"
+		"      Receive %s\n",
+		data[REG_CR] & BIT_CR_TXE ? "Active" : "Idle",
+		data[REG_CR] & BIT_CR_RXE ? "Active" : "Idle");
+	if (data[REG_CR] & BIT_CR_RST) fprintf(stdout,
+		"      Reset In Progress\n");
+
+	/* configuration register */
+	fprintf(stdout,
+		"0x04: CFG (Configuration):               0x%08x\n",
+		data[REG_CFG]);
+	fprintf(stdout,
+		"      %s Endian\n"
+		"      Boot ROM %s\n"
+		"      Internal Phy %s\n"
+		"      Phy Reset %s\n"
+		"      External Phy %s\n"
+		"      Default Auto-Negotiation %s, %s %s Mb %s Duplex\n"
+		"      Phy Interrupt %sAuto-Cleared\n"
+		"      Phy Configuration = 0x%02x\n"
+		"      Auto-Negotiation %s\n"
+		"      %s Polarity\n"
+		"      %s Duplex\n"
+		"      %d Mb/s\n"
+		"      Link %s\n",
+		data[REG_CFG] & BIT_CFG_BEM ? "Big" : "Little",
+		data[REG_CFG] & BIT_CFG_BROM_DIS ? "Disabled" : "Enabled",
+		data[REG_CFG] & BIT_CFG_PHY_DIS ? "Disabled" : "Enabled",
+		data[REG_CFG] & BIT_CFG_PHY_RST ? "In Progress" : "Idle",
+		data[REG_CFG] & BIT_CFG_EXT_PHY ? "Enabled" : "Disabled",
+		data[REG_CFG] & BIT_CFG_ANEG_EN ? "Enabled" : "Disabled",
+		data[REG_CFG] & BIT_CFG_ANEG_EN ? "Advertise" : "Force",
+		data[REG_CFG] & BIT_CFG_ANEG_100 ?
+			(data[REG_CFG] & BIT_CFG_ANEG_EN ? "10/100" : "100")
+			: "10",
+		data[REG_CFG] & BIT_CFG_ANEG_FDUP ?
+			(data[REG_CFG] & BIT_CFG_ANEG_EN ? "Half/Full" : "Full")
+			: "Half",
+		data[REG_CFG] & BIT_CFG_PINT_ACEN ? "" : "Not ",
+		data[REG_CFG] & BIT_CFG_PHY_CFG >> 18,
+		data[REG_CFG] & BIT_CFG_ANEG_DN ? "Done" : "Not Done",
+		data[REG_CFG] & BIT_CFG_POL ? "Reversed" : "Normal",
+		data[REG_CFG] & BIT_CFG_FDUP ? "Full" : "Half",
+		data[REG_CFG] & BIT_CFG_SPEED100 ? 100 : 10,
+		data[REG_CFG] & BIT_CFG_LNKSTS ? "Up" : "Down");
+
+	/* EEPROM access register */
+	fprintf(stdout,
+		"0x08: MEAR (EEPROM Access):              0x%08x\n",
+		data[REG_MEAR]);
+
+	/* PCI test control register */
+	fprintf(stdout,
+		"0x0c: PTSCR (PCI Test Control):          0x%08x\n",
+		data[REG_PTSCR]);
+	fprintf(stdout,
+		"      EEPROM Self Test %s\n"
+		"      Rx Filter Self Test %s\n"
+		"      Tx FIFO Self Test %s\n"
+		"      Rx FIFO Self Test %s\n",
+		data[REG_PTSCR] & BIT_PTSCR_EEBIST_FAIL ? "Failed" : "Passed",
+		data[REG_PTSCR] & BIT_PTSCR_RBIST_RXFFAIL ? "Failed" : "Passed",
+		data[REG_PTSCR] & BIT_PTSCR_RBIST_TXFAIL ? "Failed" : "Passed",
+		data[REG_PTSCR] & BIT_PTSCR_RBIST_RXFAIL ? "Failed" : "Passed");
+	if (data[REG_PTSCR] & BIT_PTSCR_EELOAD_EN) fprintf(stdout,
+		"      EEPROM Reload In Progress\n");
+
+	/* Interrupt status register */
+	fprintf(stdout,
+		"0x10: ISR (Interrupt Status):            0x%08x\n",
+		data[REG_ISR]);
+	if (data[REG_ISR])
+		PRINT_INTRS(data[REG_ISR], "Active", (char *)NULL);
+	else
+		fprintf(stdout, "      No Interrupts Active\n");
+
+	/* Interrupt mask register */
+	fprintf(stdout,
+		"0x14: IMR (Interrupt Mask):              0x%08x\n",
+		data[REG_IMR]);
+	PRINT_INTRS(data[REG_IMR], "Enabled", "Masked");
+
+	/* Interrupt enable register */
+	fprintf(stdout,
+		"0x18: IER (Interrupt Enable):            0x%08x\n",
+		data[REG_IER]);
+	fprintf(stdout,
+		"      Interrupts %s\n",
+		data[REG_IER] & BIT_IER_IE ? "Enabled" : "Disabled");
+
+	/* Tx descriptor pointer register */
+	fprintf(stdout,
+		"0x20: TXDP (Tx Descriptor Pointer):      0x%08x\n",
+		data[REG_TXDP]);
+
+	/* Tx configuration register */
+	fprintf(stdout,
+		"0x24: TXCFG (Tx Config):                 0x%08x\n",
+		data[REG_TXCFG]);
+	tmp = (data[REG_TXCFG] & BIT_TXCFG_MXDMA)>>20;
+	fprintf(stdout,
+		"      Drain Threshold = %d bytes (%d)\n"
+		"      Fill Threshold = %d bytes (%d)\n"
+		"      Max DMA Burst per Tx = %d bytes\n"
+		"      Automatic Tx Padding %s\n"
+		"      Mac Loopback %s\n"
+		"      Heartbeat Ignore %s\n"
+		"      Carrier Sense Ignore %s\n",
+		(data[REG_TXCFG] & BIT_TXCFG_DRTH) * 32,
+		data[REG_TXCFG] & BIT_TXCFG_DRTH,
+		((data[REG_TXCFG] & BIT_TXCFG_FLTH)>>8) * 32,
+		data[REG_TXCFG] & BIT_TXCFG_FLTH,
+		tmp ? (1<<(tmp-1))*4 : 512,
+		data[REG_TXCFG] & BIT_TXCFG_ATP ? "Enabled" : "Disabled",
+		data[REG_TXCFG] & BIT_TXCFG_MLB ? "Enabled" : "Disabled",
+		data[REG_TXCFG] & BIT_TXCFG_HBI ? "Enabled" : "Disabled",
+		data[REG_TXCFG] & BIT_TXCFG_CSI ? "Enabled" : "Disabled");
+
+
+	/* Rx descriptor pointer register */
+	fprintf(stdout,
+		"0x30: RXDP (Rx Descriptor Pointer):      0x%08x\n",
+		data[REG_RXDP]);
+
+	/* Rx configuration register */
+	fprintf(stdout,
+		"0x34: RXCFG (Rx Config):                 0x%08x\n",
+		data[REG_RXCFG]);
+	tmp = (data[REG_RXCFG] & BIT_RXCFG_MXDMA)>>20;
+	fprintf(stdout,
+		"      Drain Threshold = %d bytes (%d)\n"
+		"      Max DMA Burst per Rx = %d bytes\n"
+		"      Long Packets %s\n"
+		"      Tx Packets %s\n"
+		"      Runt Packets %s\n"
+		"      Error Packets %s\n",
+		((data[REG_RXCFG] & BIT_RXCFG_DRTH) >> 1) * 8,
+		(data[REG_RXCFG] & BIT_RXCFG_DRTH) >> 1,
+		tmp ? (1<<(tmp-1))*4 : 512,
+		data[REG_RXCFG] & BIT_RXCFG_ALP ? "Accepted" : "Rejected",
+		data[REG_RXCFG] & BIT_RXCFG_ATX ? "Accepted" : "Rejected",
+		data[REG_RXCFG] & BIT_RXCFG_ARP ? "Accepted" : "Rejected",
+		data[REG_RXCFG] & BIT_RXCFG_AEP ? "Accepted" : "Rejected");
+
+	/* CLKRUN control/status register */
+	fprintf(stdout,
+		"0x3c: CCSR (CLKRUN Control/Status):      0x%08x\n",
+		data[REG_CCSR]);
+	fprintf(stdout,
+		"      CLKRUNN %s\n"
+		"      Power Management %s\n",
+		data[REG_CCSR] & BIT_CCSR_CLKRUN_EN ? "Enabled" : "Disabled",
+		data[REG_CCSR] & BIT_CCSR_PMEEN ? "Enabled" : "Disabled");
+	if (data[REG_CCSR] & BIT_CCSR_PMESTS) fprintf(stdout,
+		"      Power Management Event Pending\n");
+
+	/* WoL control/status register */
+	fprintf(stdout,
+		"0x40: WCSR (Wake-on-LAN Control/Status): 0x%08x\n",
+		data[REG_WCSR]);
+	if (data[REG_WCSR] & BIT_WCSR_WKPHY) fprintf(stdout,
+		"      Wake on Phy Interrupt Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKUCP) fprintf(stdout,
+		"      Wake on Unicast Packet Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKMCP) fprintf(stdout,
+		"      Wake on Multicast Packet Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKBCP) fprintf(stdout,
+		"      Wake on Broadcast Packet Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKARP) fprintf(stdout,
+		"      Wake on Arp Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKPAT0) fprintf(stdout,
+		"      Wake on Pattern 0 Match Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKPAT1) fprintf(stdout,
+		"      Wake on Pattern 1 Match Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKPAT2) fprintf(stdout,
+		"      Wake on Pattern 2 Match Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKPAT3) fprintf(stdout,
+		"      Wake on Pattern 3 Match Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKMAG) fprintf(stdout,
+		"      Wake on Magic Packet Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_MPSOE) fprintf(stdout,
+		"      Magic Packet SecureOn Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_SOHACK) fprintf(stdout,
+		"      SecureOn Hack Detected\n");
+	if (data[REG_WCSR] & BIT_WCSR_PHYINT) fprintf(stdout,
+		"      Phy Interrupt Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_UCASTR) fprintf(stdout,
+		"      Unicast Packet Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_MCASTR) fprintf(stdout,
+		"      Multicast Packet Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_BCASTR) fprintf(stdout,
+		"      Broadcast Packet Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_ARPR) fprintf(stdout,
+		"      Arp Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_PATM0) fprintf(stdout,
+		"      Pattern 0 Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_PATM1) fprintf(stdout,
+		"      Pattern 1 Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_PATM2) fprintf(stdout,
+		"      Pattern 2 Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_PATM3) fprintf(stdout,
+		"      Pattern 3 Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_MPR) fprintf(stdout,
+		"      Magic Packet Received\n");
+
+	/* Pause control/status register */
+	fprintf(stdout,
+		"0x44: PCR (Pause Control/Status):        0x%08x\n",
+		data[REG_PCR]);
+	fprintf(stdout,
+		"      Pause Counter = %d\n"
+		"      Pause %sNegotiated\n"
+		"      Pause on DA %s\n"
+		"      Pause on Mulitcast %s\n"
+		"      Pause %s\n",
+		data[REG_PCR] & BIT_PCR_PAUSE_CNT,
+		data[REG_PCR] & BIT_PCR_PSNEG ? "" : "Not ",
+		data[REG_PCR] & BIT_PCR_PS_DA ? "Enabled" : "Disabled",
+		data[REG_PCR] & BIT_PCR_PSMCAST ? "Enabled" : "Disabled",
+		data[REG_PCR] & BIT_PCR_PSEN ? "Enabled" : "Disabled");
+	if (data[REG_PCR] & BIT_PCR_PS_RCVD) fprintf(stdout,
+		"      PS_RCVD: Pause Frame Received\n");
+
+	/* Rx Filter Control */
+	fprintf(stdout,
+		"0x48: RFCR (Rx Filter Control):          0x%08x\n",
+		data[REG_RFCR]);
+	fprintf(stdout,
+		"      Unicast Hash %s\n"
+		"      Multicast Hash %s\n"
+		"      Arp %s\n"
+		"      Pattern 0 Match %s\n"
+		"      Pattern 1 Match %s\n"
+		"      Pattern 2 Match %s\n"
+		"      Pattern 3 Match %s\n"
+		"      Perfect Match %s\n"
+		"      All Unicast %s\n"
+		"      All Multicast %s\n"
+		"      All Broadcast %s\n"
+		"      Rx Filter %s\n",
+		data[REG_RFCR] & BIT_RFCR_UHEN ? "Enabled" : "Disabled",
+		data[REG_RFCR] & BIT_RFCR_MHEN ? "Enabled" : "Disabled",
+		data[REG_RFCR] & BIT_RFCR_AARP ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_APAT0 ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_APAT1 ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_APAT2 ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_APAT3 ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_APM ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_AAU ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_AAM ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_AAB ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_RFEN ? "Enabled" : "Disabled");
+
+	/* Rx filter data register */
+	fprintf(stdout,
+		"0x4c: RFDR (Rx Filter Data):             0x%08x\n",
+		data[REG_RFDR]);
+	if (regs->version >= 1) fprintf(stdout,
+		"      PMATCH 1-0 = 0x%08x\n"
+		"      PMATCH 3-2 = 0x%08x\n"
+		"      PMATCH 5-4 = 0x%08x\n"
+		"      PCOUNT 1-0 = 0x%08x\n"
+		"      PCOUNT 3-2 = 0x%08x\n"
+		"      SOPASS 1-0 = 0x%08x\n"
+		"      SOPASS 3-2 = 0x%08x\n"
+		"      SOPASS 5-4 = 0x%08x\n",
+		data[REG_PMATCH0], data[REG_PMATCH1], data[REG_PMATCH2],
+		data[REG_PCOUNT0], data[REG_PCOUNT1],
+		data[REG_SOPASS0], data[REG_SOPASS1], data[REG_SOPASS2]);
+
+
+	/* Boot ROM address register */
+	fprintf(stdout,
+		"0x50: BRAR (Boot ROM Address):           0x%08x\n",
+		data[REG_BRAR]);
+	if (data[REG_BRAR] & BIT_BRAR_AUTOINC) fprintf(stdout,
+		"      Automatically Increment Address\n");
+
+	/* Boot ROM data register */
+	fprintf(stdout,
+		"0x54: BRDR (Boot ROM Data):              0x%08x\n",
+		data[REG_BRDR]);
+
+	/* Silicon revison register */
+	fprintf(stdout,
+		"0x58: SRR (Silicon Revision):            0x%08x\n",
+		data[REG_SRR]);
+
+	/* Management information base control register */
+	fprintf(stdout,
+		"0x5c: MIBC (Mgmt Info Base Control):     0x%08x\n",
+		data[REG_MIBC]);
+	if (data[REG_MIBC] & BIT_MIBC_WRN) fprintf(stdout,
+		"      Counter Overflow Warning\n");
+	if (data[REG_MIBC] & BIT_MIBC_FRZ) fprintf(stdout,
+		"      Counters Frozen\n");
+
+	/* MIB registers */
+	fprintf(stdout,
+		"0x60: MIB[0] (Rx Errored Packets):       0x%04x\n",
+		data[REG_MIB0]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB0]);
+	fprintf(stdout,
+		"0x64: MIB[1] (Rx Frame Sequence Errors): 0x%02x\n",
+		data[REG_MIB1]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB1]);
+	fprintf(stdout,
+		"0x68: MIB[2] (Rx Missed Packets):        0x%02x\n",
+		data[REG_MIB2]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB2]);
+	fprintf(stdout,
+		"0x6c: MIB[3] (Rx Alignment Errors):      0x%02x\n",
+		data[REG_MIB3]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB3]);
+	fprintf(stdout,
+		"0x70: MIB[4] (Rx Symbol Errors):         0x%02x\n",
+		data[REG_MIB4]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB4]);
+	fprintf(stdout,
+		"0x74: MIB[5] (Rx Long Frame Errors):     0x%02x\n",
+		data[REG_MIB5]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB5]);
+	fprintf(stdout,
+		"0x78: MIB[6] (Tx Heartbeat Errors):      0x%02x\n",
+		data[REG_MIB6]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB6]);
+
+	fprintf(stdout, "\n");
+	fprintf(stdout, "Internal Phy Registers\n");
+	fprintf(stdout, "----------------------\n");
+
+	/* Basic mode control register */
+	fprintf(stdout,
+		"0x80: BMCR (Basic Mode Control):         0x%04x\n",
+		data[REG_BMCR]);
+	fprintf(stdout,
+		"      %s Duplex\n"
+		"      Port is Powered %s\n"
+		"      Auto-Negotiation %s\n"
+		"      %d Mb/s\n",
+		data[REG_BMCR] & BIT_BMCR_FDUP ? "Full" : "Half",
+		data[REG_BMCR] & BIT_BMCR_PDOWN ? "Down" : "Up",
+		data[REG_BMCR] & BIT_BMCR_ANEN ? "Enabled" : "Disabled",
+		data[REG_BMCR] & BIT_BMCR_SPEED ? 100 : 10);
+	if (data[REG_BMCR] & BIT_BMCR_ANRST) fprintf(stdout,
+		"      Auto-Negotiation Restarting\n");
+	if (data[REG_BMCR] & BIT_BMCR_ISOL) fprintf(stdout,
+		"      Port Isolated\n");
+	if (data[REG_BMCR] & BIT_BMCR_LOOP) fprintf(stdout,
+		"      Loopback Enabled\n");
+	if (data[REG_BMCR] & BIT_BMCR_RST) fprintf(stdout,
+		"      Reset In Progress\n");
+
+	/* Basic mode status register */
+	fprintf(stdout,
+		"0x84: BMSR (Basic Mode Status):          0x%04x\n",
+		data[REG_BMSR]);
+	fprintf(stdout,
+		"      Link %s\n"
+		"      %sCapable of Auto-Negotiation\n"
+		"      Auto-Negotiation %sComplete\n"
+		"      %sCapable of Preamble Suppression\n"
+		"      %sCapable of 10Base-T Half Duplex\n"
+		"      %sCapable of 10Base-T Full Duplex\n"
+		"      %sCapable of 100Base-TX Half Duplex\n"
+		"      %sCapable of 100Base-TX Full Duplex\n"
+		"      %sCapable of 100Base-T4\n",
+		data[REG_BMSR] & BIT_BMSR_LNK ? "Up" : "Down",
+		data[REG_BMSR] & BIT_BMSR_ANCAP ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_ANDONE ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_PREAMBLE ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_10HCAP ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_10FCAP ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_100HCAP ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_100FCAP ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_100T4CAP ? "" : "Not ");
+	if (data[REG_BMSR] & BIT_BMSR_JABBER) fprintf(stdout,
+		"      Jabber Condition Detected\n");
+	if (data[REG_BMSR] & BIT_BMSR_RFAULT) fprintf(stdout,
+		"      Remote Fault Detected\n");
+
+	/* PHY identification registers */
+	fprintf(stdout,
+		"0x88: PHYIDR1 (PHY ID #1):               0x%04x\n",
+		data[REG_PHYIDR1]);
+	fprintf(stdout,
+		"0x8c: PHYIDR2 (PHY ID #2):               0x%04x\n",
+		data[REG_PHYIDR2]);
+	fprintf(stdout,
+		"      OUI = 0x%06x\n"
+		"      Model = 0x%02x (%d)\n"
+		"      Revision = 0x%01x (%d)\n",
+		(data[REG_PHYIDR1] << 6) | (data[REG_PHYIDR2] >> 10),
+		(data[REG_PHYIDR2] & BIT_PHYIDR2_MODEL) >> 4 & 0x3f,
+		(data[REG_PHYIDR2] & BIT_PHYIDR2_MODEL) >> 4 & 0x3f,
+		data[REG_PHYIDR2] & BIT_PHYIDR2_REV,
+		data[REG_PHYIDR2] & BIT_PHYIDR2_REV);
+
+	/* autonegotiation advertising register */
+	fprintf(stdout,
+		"0x90: ANAR (Autoneg Advertising):        0x%04x\n",
+		data[REG_ANAR]);
+	fprintf(stdout,
+		"      Protocol Selector = 0x%02x (%d)\n",
+		data[REG_ANAR] & BIT_ANAR_PROTO,
+		data[REG_ANAR] & BIT_ANAR_PROTO);
+	if (data[REG_ANAR] & BIT_ANAR_10) fprintf(stdout,
+		"      Advertising 10Base-T Half Duplex\n");
+	if (data[REG_ANAR] & BIT_ANAR_10_FD) fprintf(stdout,
+		"      Advertising 10Base-T Full Duplex\n");
+	if (data[REG_ANAR] & BIT_ANAR_TX) fprintf(stdout,
+		"      Advertising 100Base-TX Half Duplex\n");
+	if (data[REG_ANAR] & BIT_ANAR_TXFD) fprintf(stdout,
+		"      Advertising 100Base-TX Full Duplex\n");
+	if (data[REG_ANAR] & BIT_ANAR_T4) fprintf(stdout,
+		"      Advertising 100Base-T4\n");
+	if (data[REG_ANAR] & BIT_ANAR_PAUSE) fprintf(stdout,
+		"      Advertising Pause\n");
+	if (data[REG_ANAR] & BIT_ANAR_RF) fprintf(stdout,
+		"      Indicating Remote Fault\n");
+	if (data[REG_ANAR] & BIT_ANAR_NP) fprintf(stdout,
+		"      Next Page Desired\n");
+
+	/* Autonegotiation link partner ability register */
+	fprintf(stdout,
+		"0x94: ANLPAR (Autoneg Partner):          0x%04x\n",
+		data[REG_ANLPAR]);
+	fprintf(stdout,
+		"      Protocol Selector = 0x%02x (%d)\n",
+		data[REG_ANLPAR] & BIT_ANLPAR_PROTO,
+		data[REG_ANLPAR] & BIT_ANLPAR_PROTO);
+	if (data[REG_ANLPAR] & BIT_ANLPAR_10) fprintf(stdout,
+		"      Supports 10Base-T Half Duplex\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_10_FD) fprintf(stdout,
+		"      Supports 10Base-T Full Duplex\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_TX) fprintf(stdout,
+		"      Supports 100Base-TX Half Duplex\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_TXFD) fprintf(stdout,
+		"      Supports 100Base-TX Full Duplex\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_T4) fprintf(stdout,
+		"      Supports 100Base-T4\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_PAUSE) fprintf(stdout,
+		"      Supports Pause\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_RF) fprintf(stdout,
+		"      Indicates Remote Fault\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_ACK) fprintf(stdout,
+		"      Indicates Acknowledgement\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_NP) fprintf(stdout,
+		"      Next Page Desired\n");
+
+	/* Autonegotiation expansion register */
+	fprintf(stdout,
+		"0x98: ANER (Autoneg Expansion):          0x%04x\n",
+		data[REG_ANER]);
+	fprintf(stdout,
+		"      Link Partner Can %sAuto-Negotiate\n"
+		"      Link Code Word %sReceived\n"
+		"      Next Page %sSupported\n"
+		"      Link Partner Next Page %sSupported\n",
+		data[REG_ANER] & BIT_ANER_LP_AN_ENABLE ? "" : "Not ",
+		data[REG_ANER] & BIT_ANER_PAGE_RX ? "" : "Not ",
+		data[REG_ANER] & BIT_ANER_NP_ABLE ? "" : "Not ",
+		data[REG_ANER] & BIT_ANER_LP_NP_ABLE ? "" : "Not ");
+	if (data[REG_ANER] & BIT_ANER_PDF) fprintf(stdout,
+		"      Parallel Detection Fault\n");
+
+	/* Autonegotiation next-page tx register */
+	fprintf(stdout,
+		"0x9c: ANNPTR (Autoneg Next Page Tx):     0x%04x\n",
+		data[REG_ANNPTR]);
+
+	/* Phy status register */
+	fprintf(stdout,
+		"0xc0: PHYSTS (Phy Status):               0x%04x\n",
+		data[REG_PHYSTS]);
+	fprintf(stdout,
+		"      Link %s\n"
+		"      %d Mb/s\n"
+		"      %s Duplex\n"
+		"      Auto-Negotiation %sComplete\n"
+		"      %s Polarity\n",
+		data[REG_PHYSTS] & BIT_PHYSTS_LNK ? "Up" : "Down",
+		data[REG_PHYSTS] & BIT_PHYSTS_SPD10 ? 10 : 100,
+		data[REG_PHYSTS] & BIT_PHYSTS_FDUP ? "Full" : "Half",
+		data[REG_PHYSTS] & BIT_PHYSTS_ANDONE ? "" : "Not ",
+		data[REG_PHYSTS] & BIT_PHYSTS_POL ? "Reverse" : "Normal");
+	if (data[REG_PHYSTS] & BIT_PHYSTS_LOOP) fprintf(stdout,
+		"      Loopback Enabled\n");
+	if (data[REG_PHYSTS] & BIT_PHYSTS_JABBER) fprintf(stdout,
+		"      Jabber Condition Detected\n");
+	if (data[REG_PHYSTS] & BIT_PHYSTS_RF) fprintf(stdout,
+		"      Remote Fault Detected\n");
+	if (data[REG_PHYSTS] & BIT_PHYSTS_MINT) fprintf(stdout,
+		"      MII Interrupt Detected\n");
+	if (data[REG_PHYSTS] & BIT_PHYSTS_FC) fprintf(stdout,
+		"      False Carrier Detected\n");
+	if (data[REG_PHYSTS] & BIT_PHYSTS_RXERR) fprintf(stdout,
+		"      Rx Error Detected\n");
+
+	fprintf(stdout,
+		"0xc4: MICR (MII Interrupt Control):      0x%04x\n",
+		data[REG_MICR]);
+	fprintf(stdout,
+		"      MII Interrupts %s\n",
+		data[REG_MICR] & BIT_MICR_INTEN ? "Enabled" : "Disabled");
+
+	fprintf(stdout,
+		"0xc8: MISR (MII Interrupt Status):       0x%04x\n",
+		data[REG_MISR]);
+	fprintf(stdout,
+		"      Rx Error Counter Half-Full Interrupt %s\n"
+		"      False Carrier Counter Half-Full Interrupt %s\n"
+		"      Auto-Negotiation Complete Interrupt %s\n"
+		"      Remote Fault Interrupt %s\n"
+		"      Jabber Interrupt %s\n"
+		"      Link Change Interrupt %s\n",
+		data[REG_MISR] & BIT_MISR_MSK_RHF ? "Masked" : "Enabled",
+		data[REG_MISR] & BIT_MISR_MSK_FHF ? "Masked" : "Enabled",
+		data[REG_MISR] & BIT_MISR_MSK_ANC ? "Masked" : "Enabled",
+		data[REG_MISR] & BIT_MISR_MSK_RF ? "Masked" : "Enabled",
+		data[REG_MISR] & BIT_MISR_MSK_JAB ? "Masked" : "Enabled",
+		data[REG_MISR] & BIT_MISR_MSK_LNK ? "Masked" : "Enabled");
+	if (data[REG_MISR] & BIT_MISR_MINT) fprintf(stdout,
+		"      MII Interrupt Pending\n");
+
+	/* Page select register (from section of spec on 'suggested values') */
+	fprintf(stdout,
+		"0xcc: PGSEL (Phy Register Page Select):  0x%04x\n",
+		data[REG_PGSEL]);
+
+	/* counters */
+	fprintf(stdout,
+		"0xd0: FCSCR (False Carrier Counter):     0x%04x\n",
+		data[REG_FCSCR]);
+	fprintf(stdout,
+		"      Value = %d\n", data[REG_FCSCR] & 0xff);
+	fprintf(stdout,
+		"0xd4: RECR (Rx Error Counter):           0x%04x\n",
+		data[REG_RECR]);
+	fprintf(stdout,
+		"      Value = %d\n", data[REG_RECR] & 0xff);
+
+	/* 100 Mbit configuration register */
+	fprintf(stdout,
+		"0xd8: PCSR (100Mb/s PCS Config/Status):  0x%04x\n",
+		data[REG_PCSR]);
+	fprintf(stdout,
+		"      NRZI Bypass %s\n"
+		"      %s Signal Detect Algorithm\n"
+		"      %s Signal Detect Operation\n"
+		"      True Quiet Mode %s\n"
+		"      Rx Clock is %s\n"
+		"      4B/5B Operation %s\n",
+		data[REG_PCSR] & BIT_PCSR_NRZI ? "Enabled" : "Disabled",
+		data[REG_PCSR] & BIT_PCSR_SDOPT ? "Enhanced" : "Reduced",
+		data[REG_PCSR] & BIT_PCSR_SDFORCE ? "Forced" : "Normal",
+		data[REG_PCSR] & BIT_PCSR_TQM ? "Enabled" : "Disabled",
+		data[REG_PCSR] & BIT_PCSR_CLK ?
+			"Free-Running" : "Phase-Adjusted",
+		data[REG_PCSR] & BIT_PCSR_4B5B ? "Bypassed" : "Normal");
+	if (data[REG_PCSR] & BIT_PCSR_FORCE_100) fprintf(stdout,
+		"      Forced 100 Mb/s Good Link\n");
+
+	/* Phy control register */
+	fprintf(stdout,
+		"0xe4: PHYCR (Phy Control):               0x%04x\n",
+		data[REG_PHYCR]);
+	fprintf(stdout,
+		"      Phy Address = 0x%x (%d)\n"
+		"      %sPause Compatible with Link Partner\n"
+		"      LED Stretching %s\n"
+		"      Phy Self Test %s\n"
+		"      Self Test Sequence = PSR%d\n",
+		data[REG_PHYCR] & BIT_PHYCR_PHYADDR,
+		data[REG_PHYCR] & BIT_PHYCR_PHYADDR,
+		data[REG_PHYCR] & BIT_PHYCR_PAUSE_STS ? "" : "Not ",
+		data[REG_PHYCR] & BIT_PHYCR_STRETCH ? "Bypassed" : "Enabled",
+		data[REG_PHYCR] & BIT_PHYCR_BIST ? "In Progress" :
+		  data[REG_PHYCR] & BIT_PHYCR_BIST_STAT ?
+		    "Passed" : "Failed or Not Run",
+		data[REG_PHYCR] & BIT_PHYCR_PSR15 ? 15 : 9);
+
+
+	/* 10 Mbit control and status register */
+	fprintf(stdout,
+		"0xe8: TBTSCR (10Base-T Status/Control):  0x%04x\n",
+		data[REG_TBTSCR]);
+	fprintf(stdout,
+		"      Jabber %s\n"
+		"      Heartbeat %s\n"
+		"      Polarity Auto-Sense/Correct %s\n"
+		"      %s Polarity %s\n"
+		"      Normal Link Pulse %s\n"
+		"      10 Mb/s Loopback %s\n",
+		data[REG_TBTSCR] & BIT_TBTSCR_JAB ? "Disabled" : "Enabled",
+		data[REG_TBTSCR] & BIT_TBTSCR_BEAT ? "Disabled" : "Enabled",
+		data[REG_TBTSCR] & BIT_TBTSCR_AUTOPOL ? "Disabled" : "Enabled",
+		data[REG_TBTSCR] & BIT_TBTSCR_AUTOPOL ?
+			data[REG_TBTSCR]&BIT_TBTSCR_FPOL ? "Reverse":"Normal" :
+			data[REG_TBTSCR]&BIT_TBTSCR_POL ? "Reverse":"Normal",
+		data[REG_TBTSCR] & BIT_TBTSCR_AUTOPOL ? "Forced" : "Detected",
+		data[REG_TBTSCR] & BIT_TBTSCR_PULSE ? "Disabled" : "Enabled",
+		data[REG_TBTSCR] & BIT_TBTSCR_LOOP ? "Enabled" : "Disabled");
+	if (data[REG_TBTSCR] & BIT_TBTSCR_FORCE_10) fprintf(stdout,
+		"      Forced 10 Mb/s Good Link\n");
+
+	/* the spec says to set these */
+	fprintf(stdout, "\n");
+	fprintf(stdout, "'Magic' Phy Registers\n");
+	fprintf(stdout, "---------------------\n");
+	fprintf(stdout,
+		"0xe4: PMDCSR:                            0x%04x\n",
+		data[REG_PMDCSR]);
+	fprintf(stdout,
+		"0xf4: DSPCFG:                            0x%04x\n",
+		data[REG_DSPCFG]);
+	fprintf(stdout,
+		"0xf8: SDCFG:                             0x%04x\n",
+		data[REG_SDCFG]);
+	fprintf(stdout,
+		"0xfc: TSTDAT:                            0x%04x\n",
+		data[REG_TSTDAT]);
+
+	return 0;
+}
+
+int
+natsemi_dump_eeprom(struct ethtool_drvinfo *info maybe_unused,
+		    struct ethtool_eeprom *ee)
+{
+	int i;
+	u16 *eebuf = (u16 *)ee->data;
+
+	if (ee->magic != NATSEMI_MAGIC) {
+		fprintf(stderr, "Magic number 0x%08x does not match 0x%08x\n",
+			ee->magic, NATSEMI_MAGIC);
+		return -1;
+	}
+
+	fprintf(stdout, "Address\tData\n");
+	fprintf(stdout, "-------\t------\n");
+	for (i = 0; i < ee->len/2; i++) {
+		fprintf(stdout, "0x%02x   \t0x%04x\n", i + ee->offset, eebuf[i]);
+	}
+
+	return 0;
+}
+
diff --git a/net_tstamp-copy.h b/net_tstamp-copy.h
new file mode 100644
index 0000000..3d421d9
--- /dev/null
+++ b/net_tstamp-copy.h
@@ -0,0 +1,143 @@
+/*
+ * Userspace API for hardware time stamping of network packets
+ *
+ * Copyright (C) 2008,2009 Intel Corporation
+ * Author: Patrick Ohly <patrick.ohly@intel.com>
+ *
+ */
+
+#ifndef _NET_TIMESTAMPING_H
+#define _NET_TIMESTAMPING_H
+
+#include <linux/types.h>
+#include <linux/socket.h>   /* for SO_TIMESTAMPING */
+
+/* SO_TIMESTAMPING gets an integer bit field comprised of these values */
+enum {
+	SOF_TIMESTAMPING_TX_HARDWARE = (1<<0),
+	SOF_TIMESTAMPING_TX_SOFTWARE = (1<<1),
+	SOF_TIMESTAMPING_RX_HARDWARE = (1<<2),
+	SOF_TIMESTAMPING_RX_SOFTWARE = (1<<3),
+	SOF_TIMESTAMPING_SOFTWARE = (1<<4),
+	SOF_TIMESTAMPING_SYS_HARDWARE = (1<<5),
+	SOF_TIMESTAMPING_RAW_HARDWARE = (1<<6),
+	SOF_TIMESTAMPING_OPT_ID = (1<<7),
+	SOF_TIMESTAMPING_TX_SCHED = (1<<8),
+	SOF_TIMESTAMPING_TX_ACK = (1<<9),
+	SOF_TIMESTAMPING_OPT_CMSG = (1<<10),
+	SOF_TIMESTAMPING_OPT_TSONLY = (1<<11),
+	SOF_TIMESTAMPING_OPT_STATS = (1<<12),
+	SOF_TIMESTAMPING_OPT_PKTINFO = (1<<13),
+	SOF_TIMESTAMPING_OPT_TX_SWHW = (1<<14),
+
+	SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_TX_SWHW,
+	SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) |
+				 SOF_TIMESTAMPING_LAST
+};
+
+/*
+ * SO_TIMESTAMPING flags are either for recording a packet timestamp or for
+ * reporting the timestamp to user space.
+ * Recording flags can be set both via socket options and control messages.
+ */
+#define SOF_TIMESTAMPING_TX_RECORD_MASK	(SOF_TIMESTAMPING_TX_HARDWARE | \
+					 SOF_TIMESTAMPING_TX_SOFTWARE | \
+					 SOF_TIMESTAMPING_TX_SCHED | \
+					 SOF_TIMESTAMPING_TX_ACK)
+
+/**
+ * struct hwtstamp_config - %SIOCGHWTSTAMP and %SIOCSHWTSTAMP parameter
+ *
+ * @flags:	no flags defined right now, must be zero for %SIOCSHWTSTAMP
+ * @tx_type:	one of HWTSTAMP_TX_*
+ * @rx_filter:	one of HWTSTAMP_FILTER_*
+ *
+ * %SIOCGHWTSTAMP and %SIOCSHWTSTAMP expect a &struct ifreq with a
+ * ifr_data pointer to this structure.  For %SIOCSHWTSTAMP, if the
+ * driver or hardware does not support the requested @rx_filter value,
+ * the driver may use a more general filter mode.  In this case
+ * @rx_filter will indicate the actual mode on return.
+ */
+struct hwtstamp_config {
+	int flags;
+	int tx_type;
+	int rx_filter;
+};
+
+/* possible values for hwtstamp_config->tx_type */
+enum hwtstamp_tx_types {
+	/*
+	 * No outgoing packet will need hardware time stamping;
+	 * should a packet arrive which asks for it, no hardware
+	 * time stamping will be done.
+	 */
+	HWTSTAMP_TX_OFF,
+
+	/*
+	 * Enables hardware time stamping for outgoing packets;
+	 * the sender of the packet decides which are to be
+	 * time stamped by setting %SOF_TIMESTAMPING_TX_SOFTWARE
+	 * before sending the packet.
+	 */
+	HWTSTAMP_TX_ON,
+
+	/*
+	 * Enables time stamping for outgoing packets just as
+	 * HWTSTAMP_TX_ON does, but also enables time stamp insertion
+	 * directly into Sync packets. In this case, transmitted Sync
+	 * packets will not received a time stamp via the socket error
+	 * queue.
+	 */
+	HWTSTAMP_TX_ONESTEP_SYNC,
+};
+
+/* possible values for hwtstamp_config->rx_filter */
+enum hwtstamp_rx_filters {
+	/* time stamp no incoming packet at all */
+	HWTSTAMP_FILTER_NONE,
+
+	/* time stamp any incoming packet */
+	HWTSTAMP_FILTER_ALL,
+
+	/* return value: time stamp all packets requested plus some others */
+	HWTSTAMP_FILTER_SOME,
+
+	/* PTP v1, UDP, any kind of event packet */
+	HWTSTAMP_FILTER_PTP_V1_L4_EVENT,
+	/* PTP v1, UDP, Sync packet */
+	HWTSTAMP_FILTER_PTP_V1_L4_SYNC,
+	/* PTP v1, UDP, Delay_req packet */
+	HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ,
+	/* PTP v2, UDP, any kind of event packet */
+	HWTSTAMP_FILTER_PTP_V2_L4_EVENT,
+	/* PTP v2, UDP, Sync packet */
+	HWTSTAMP_FILTER_PTP_V2_L4_SYNC,
+	/* PTP v2, UDP, Delay_req packet */
+	HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ,
+
+	/* 802.AS1, Ethernet, any kind of event packet */
+	HWTSTAMP_FILTER_PTP_V2_L2_EVENT,
+	/* 802.AS1, Ethernet, Sync packet */
+	HWTSTAMP_FILTER_PTP_V2_L2_SYNC,
+	/* 802.AS1, Ethernet, Delay_req packet */
+	HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ,
+
+	/* PTP v2/802.AS1, any layer, any kind of event packet */
+	HWTSTAMP_FILTER_PTP_V2_EVENT,
+	/* PTP v2/802.AS1, any layer, Sync packet */
+	HWTSTAMP_FILTER_PTP_V2_SYNC,
+	/* PTP v2/802.AS1, any layer, Delay_req packet */
+	HWTSTAMP_FILTER_PTP_V2_DELAY_REQ,
+
+	/* NTP, UDP, all versions and packet modes */
+	HWTSTAMP_FILTER_NTP_ALL,
+};
+
+/* SCM_TIMESTAMPING_PKTINFO control message */
+struct scm_ts_pktinfo {
+	__u32 if_index;
+	__u32 pkt_length;
+	__u32 reserved[2];
+};
+
+#endif /* _NET_TIMESTAMPING_H */
diff --git a/pcnet32.c b/pcnet32.c
new file mode 100644
index 0000000..b87cee7
--- /dev/null
+++ b/pcnet32.c
@@ -0,0 +1,249 @@
+/* Copyright 2004 IBM Corporation (jklewis@us.ibm.com) */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "internal.h"
+
+#define BIT0  0x0001
+#define BIT1  0x0002
+#define BIT2  0x0004
+#define BIT3  0x0008
+#define BIT4  0x0010
+#define BIT5  0x0020
+#define BIT6  0x0040
+#define BIT7  0x0080
+#define BIT8  0x0100
+#define BIT9  0x0200
+#define BIT10 0x0400
+#define BIT11 0x0800
+#define BIT12 0x1000
+#define BIT13 0x2000
+#define BIT14 0x4000
+#define BIT15 0x8000
+
+int pcnet32_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+	int i, csr;
+	u16 *data = (u16 *) regs->data;
+	int len = regs->len / 2;
+	u16 temp,*ptr;
+
+	printf("Driver:  %s\n",info->driver);
+	printf("Version: %s\n",info->version);
+
+	printf("APROM:  ");
+	for (i=0; i<8; i++)
+		printf(" %04x ", data[i]);
+	printf("\n");
+
+	csr = i;
+	for (; i<100; i++)
+	 {
+		if (((i-csr) & 7) == 0) printf("CSR%02d:  ", i-csr);
+		printf(" %04x ", data[i]);
+		if (((i-csr) & 7) == 7) printf("\n");
+	 }
+	if (((i-csr) & 7) != 7) printf("\n");
+
+	csr = i;
+	for (; i<136; i++)
+	 {
+		if (((i-csr) & 7) == 0) printf("BCR%02d:  ", i-csr);
+		printf(" %04x ", data[i]);
+		if (((i-csr) & 7) == 7) printf("\n");
+	 }
+	if (((i-csr) & 7) != 7) printf("\n");
+
+	csr = i;
+	for (; i<len; i++)
+	 {
+	  if (((i-csr) & 7) == 0) printf("MII%02d:  ", (i-csr) & 0x1f);
+		printf(" %04x ", data[i]);
+	  if (((i-csr) & 7) == 7) printf("\n");
+	 }
+	if (((i-csr) & 7) != 7) printf("\n");
+	printf("\n");
+
+	ptr=&data[8];            /* start of the CSRs */
+
+	printf("CSR0:   Status and Control         0x%04x\n  ",ptr[0]);
+	temp=ptr[0];
+
+	if(temp & BIT15) printf("ERR ");
+	if(temp & BIT14) printf("BABL ");
+	if(temp & BIT13) printf("CERR ");
+	if(temp & BIT12) printf("MISS ");
+	if(temp & BIT11) printf("MERR ");
+	if(temp & BIT10) printf("RINT ");
+	if(temp & BIT9)  printf("TINT ");
+	if(temp & BIT8)  printf("IDON ");
+	if(temp & BIT7)  printf("INTR ");
+	if(temp & BIT6)  printf("INT ");
+	if(temp & BIT5)  printf("RXON ");
+	if(temp & BIT4)  printf("TXON ");
+	if(temp & BIT3)  printf("TDMD ");
+	if(temp & BIT2)  printf("STOP ");
+	if(temp & BIT1)  printf("STRT ");
+	if(temp & BIT0)  printf("INIT ");
+
+	printf("\n");
+
+	printf("CSR3:   Interrupt Mask             0x%04x\n  ",ptr[3]);
+	temp=ptr[3];
+
+	if(temp & BIT14) printf("BABLM ");
+	if(temp & BIT12) printf("MISSM ");
+	if(temp & BIT11) printf("MERRM ");
+	if(temp & BIT10) printf("RINTM ");
+	if(temp & BIT9)  printf("TINTM ");
+	if(temp & BIT8)  printf("IDONM ");
+	if(temp & BIT6)  printf("DXSUFLO ");
+	if(temp & BIT5)  printf("LAPPEN ");
+	if(temp & BIT4)  printf("DXMT2PD ");
+	if(temp & BIT3)  printf("EMBA ");
+	if(temp & BIT2)  printf("BSWP ");
+
+	printf("\n");
+
+	printf("CSR4:   Test and Features          0x%04x\n  ",ptr[4]);
+	temp=ptr[4];
+
+	if(temp & BIT15) printf("EN124 ");
+	if(temp & BIT14) printf("DMAPLUS ");
+	if(temp & BIT12) printf("TXDPOLL ");
+	if(temp & BIT11) printf("APAD_XMT ");
+	if(temp & BIT10) printf("ASTRP_RCV ");
+	if(temp & BIT9)  printf("MFCO ");
+	if(temp & BIT8)  printf("MFCON ");
+	if(temp & BIT7)  printf("UINTCMD ");
+	if(temp & BIT6)  printf("UINT ");
+	if(temp & BIT5)  printf("RCVCCO ");
+	if(temp & BIT4)  printf("RCVCCOM ");
+	if(temp & BIT3)  printf("TXSTRT ");
+	if(temp & BIT2)  printf("TXSTRTM ");
+	if(temp & BIT1)  printf("JAB ");
+	if(temp & BIT0)  printf("JABM ");
+
+	printf("\n");
+
+	printf("CSR5:   Ext Control and Int 1      0x%04x\n  ",ptr[5]);
+	temp=ptr[5];
+
+	if(temp & BIT15) printf("TOKINTD ");
+	if(temp & BIT14) printf("LTINTEN ");
+	if(temp & BIT11) printf("SINT ");
+	if(temp & BIT10) printf("SINTE ");
+	if(temp & BIT9)  printf("SLPINT ");
+	if(temp & BIT8)  printf("SLPINTE ");
+	if(temp & BIT7)  printf("EXDINT ");
+	if(temp & BIT6)  printf("EXDINTE ");
+	if(temp & BIT5)  printf("MPPLBA ");
+	if(temp & BIT4)  printf("MPINT ");
+	if(temp & BIT3)  printf("MPINTE ");
+	if(temp & BIT2)  printf("MPEN ");
+	if(temp & BIT1)  printf("MPMODE ");
+	if(temp & BIT0)  printf("SPND ");
+
+	printf("\n");
+
+	printf("CSR7:   Ext Control and Int 2      0x%04x\n  ",ptr[7]);
+	temp=ptr[7];
+
+	if(temp & BIT15) printf("FASTSPNDE ");
+	if(temp & BIT14) printf("RXFRTG ");
+	if(temp & BIT13) printf("RDMD ");
+	if(temp & BIT12) printf("RXDPOLL ");
+	if(temp & BIT11) printf("STINT ");
+	if(temp & BIT10) printf("STINTE ");
+	if(temp & BIT9)  printf("MREINT ");
+	if(temp & BIT8)  printf("MREINTE ");
+	if(temp & BIT7)  printf("MAPINT ");
+	if(temp & BIT6)  printf("MAPINTE ");
+	if(temp & BIT5)  printf("MCCINT ");
+	if(temp & BIT4)  printf("MCCINTE ");
+	if(temp & BIT3)  printf("MCCIINT ");
+	if(temp & BIT2)  printf("MCCIINTE ");
+	if(temp & BIT1)  printf("MIIPDTINT ");
+	if(temp & BIT0)  printf("MIIPDTINTE ");
+
+	printf("\n");
+
+	printf("CSR15:  Mode                       0x%04x\n",ptr[15]);
+	printf("CSR40:  Current RX Byte Count      0x%04x\n",ptr[40]);
+	printf("CSR41:  Current RX Status          0x%04x\n",ptr[41]);
+	printf("CSR42:  Current TX Byte Count      0x%04x\n",ptr[42]);
+	printf("CSR43:  Current TX Status          0x%04x\n",ptr[43]);
+	printf("CSR88:  Chip ID Lower              0x%04x\n",ptr[88]);
+	temp = (((ptr[89] << 16) | ptr[88]) >> 12) & 0xffff;
+	switch (temp) {
+		case 0x2420:
+			printf("  PCnet/PCI 79C970\n");
+			break;
+		case 0x2621:
+			printf("  PCnet/PCI II 79C970A\n");
+			break;
+		case 0x2623:
+			printf("  PCnet/FAST 79C971\n");
+			break;
+		case 0x2624:
+			printf("  PCnet/FAST+ 79C972\n");
+			break;
+		case 0x2625:
+			printf("  PCnet/FAST III 79C973\n");
+			break;
+		case 0x2626:
+			printf("  PCnet/Home 79C978\n");
+			break;
+		case 0x2627:
+			printf("  PCnet/FAST III 79C975\n");
+			break;
+		case 0x2628:
+			printf("  PCnet/PRO 79C976\n");
+			break;
+	}
+
+	printf("CSR89:  Chip ID Upper              0x%04x\n  ",ptr[89]);
+	temp=ptr[89];
+	printf("VER: %04x  PARTIDU: %04x\n",temp >> 12,temp & 0x00000fff);
+
+	printf("CSR112: Missed Frame Count         0x%04x\n",ptr[90]);    /* 90 is 112 */
+	printf("CSR114: RX Collision Count         0x%04x\n",ptr[91]);
+
+	printf("\n");
+
+	ptr=&data[100];        /* point to BCR 0 */
+
+	printf("BCR2:   Misc. Configuration        0x%04x\n  ",ptr[2]);
+	temp=ptr[2];
+
+	if(temp & BIT14) printf("TMAULOOP ");
+	if(temp & BIT12) printf("LEDPE ");
+
+	if(temp & BIT8)  printf("APROMWE ");
+	if(temp & BIT7)  printf("INTLEVEL ");
+
+	if(temp & BIT3)  printf("EADISEL ");
+	if(temp & BIT2)  printf("AWAKE ");
+	if(temp & BIT1)  printf("ASEL ");
+	if(temp & BIT0)  printf("XMAUSEL ");
+
+	printf("\n");
+
+	printf("BCR9:   Full-Duplex Control        0x%04x\n",ptr[9]);
+	printf("BCR18:  Burst and Bus Control      0x%04x\n",ptr[18]);
+
+	printf("BCR19:  EEPROM Control and Status  0x%04x\n  ",ptr[19]);
+	temp=ptr[19];
+	if(temp & BIT15) printf("PVALID ");
+	if(temp & BIT13) printf("EEDET ");
+	printf("\n");
+
+	printf("BCR23:  PCI Subsystem Vendor ID    0x%04x\n",ptr[23]);
+	printf("BCR24:  PCI Subsystem ID           0x%04x\n",ptr[24]);
+	printf("BCR31:  Software Timer             0x%04x\n",ptr[31]);
+	printf("BCR32:  MII Control and Status     0x%04x\n",ptr[32]);
+	printf("BCR35:  PCI Vendor ID              0x%04x\n",ptr[35]);
+
+	return(0);
+}
+
diff --git a/qsfp.c b/qsfp.c
new file mode 100644
index 0000000..d0774b0
--- /dev/null
+++ b/qsfp.c
@@ -0,0 +1,788 @@
+/*
+ * qsfp.c: Implements SFF-8636 based QSFP+/QSFP28 Diagnostics Memory map.
+ *
+ * Copyright 2010 Solarflare Communications Inc.
+ * Aurelien Guillaume <aurelien@iwi.me> (C) 2012
+ * Copyright (C) 2014 Cumulus networks Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Freeoftware Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *  Vidya Ravipati <vidya@cumulusnetworks.com>
+ *   This implementation is loosely based on current SFP parser
+ *   and SFF-8636 spec Rev 2.7 (ftp://ftp.seagate.com/pub/sff/SFF-8636.PDF)
+ *   by SFF Committee.
+ */
+
+/*
+ *	Description:
+ *	a) The register/memory layout is up to 5 128 byte pages defined by
+ *		a "pages valid" register and switched via a "page select"
+ *		register. Memory of 256 bytes can be memory mapped at a time
+ *		according to SFF 8636.
+ *	b) SFF 8636 based 640 bytes memory layout is presented for parser
+ *
+ *           SFF 8636 based QSFP Memory Map
+ *
+ *           2-Wire Serial Address: 1010000x
+ *
+ *           Lower Page 00h (128 bytes)
+ *           ======================
+ *           |                     |
+ *           |Page Select Byte(127)|
+ *           ======================
+ *                    |
+ *                    V
+ *	     ----------------------------------------
+ *	    |             |            |             |
+ *	    V             V            V             V
+ *	 ----------   ----------   ---------    ------------
+ *	| Upper    | | Upper    | | Upper    | | Upper      |
+ *	| Page 00h | | Page 01h | | Page 02h | | Page 03h   |
+ *	|          | |(Optional)| |(Optional)| | (Optional) |
+ *	|          | |          | |          | |            |
+ *	|          | |          | |          | |            |
+ *	|    ID    | |   AST    | |  User    | |  For       |
+ *	|  Fields  | |  Table   | | EEPROM   | |  Cable     |
+ *	|          | |          | | Data     | | Assemblies |
+ *	|          | |          | |          | |            |
+ *	|          | |          | |          | |            |
+ *	-----------  -----------   ----------  --------------
+ *
+ *
+ **/
+#include <stdio.h>
+#include <math.h>
+#include "internal.h"
+#include "sff-common.h"
+#include "qsfp.h"
+
+#define MAX_DESC_SIZE	42
+
+static struct sff8636_aw_flags {
+	const char *str;        /* Human-readable string, null at the end */
+	int offset;             /* A2-relative address offset */
+	__u8 value;             /* Alarm is on if (offset & value) != 0. */
+} sff8636_aw_flags[] = {
+	{ "Laser bias current high alarm   (Chan 1)",
+		SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_1_HALARM) },
+	{ "Laser bias current low alarm    (Chan 1)",
+		SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_1_LALARM) },
+	{ "Laser bias current high warning (Chan 1)",
+		SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_1_HWARN) },
+	{ "Laser bias current low warning  (Chan 1)",
+		SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_1_LWARN) },
+
+	{ "Laser bias current high alarm   (Chan 2)",
+		SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_2_HALARM) },
+	{ "Laser bias current low alarm    (Chan 2)",
+		SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_2_LALARM) },
+	{ "Laser bias current high warning (Chan 2)",
+		SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_2_HWARN) },
+	{ "Laser bias current low warning  (Chan 2)",
+		SFF8636_TX_BIAS_12_AW_OFFSET, (SFF8636_TX_BIAS_2_LWARN) },
+
+	{ "Laser bias current high alarm   (Chan 3)",
+		SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_3_HALARM) },
+	{ "Laser bias current low alarm    (Chan 3)",
+		SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_3_LALARM) },
+	{ "Laser bias current high warning (Chan 3)",
+		SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_3_HWARN) },
+	{ "Laser bias current low warning  (Chan 3)",
+		SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_3_LWARN) },
+
+	{ "Laser bias current high alarm   (Chan 4)",
+		SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_4_HALARM) },
+	{ "Laser bias current low alarm    (Chan 4)",
+		SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_4_LALARM) },
+	{ "Laser bias current high warning (Chan 4)",
+		SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_4_HWARN) },
+	{ "Laser bias current low warning  (Chan 4)",
+		SFF8636_TX_BIAS_34_AW_OFFSET, (SFF8636_TX_BIAS_4_LWARN) },
+
+	{ "Module temperature high alarm",
+		SFF8636_TEMP_AW_OFFSET, (SFF8636_TEMP_HALARM_STATUS) },
+	{ "Module temperature low alarm",
+		SFF8636_TEMP_AW_OFFSET, (SFF8636_TEMP_LALARM_STATUS) },
+	{ "Module temperature high warning",
+		SFF8636_TEMP_AW_OFFSET, (SFF8636_TEMP_HWARN_STATUS) },
+	{ "Module temperature low warning",
+		SFF8636_TEMP_AW_OFFSET, (SFF8636_TEMP_LWARN_STATUS) },
+
+	{ "Module voltage high alarm",
+		SFF8636_VCC_AW_OFFSET, (SFF8636_VCC_HALARM_STATUS) },
+	{ "Module voltage low alarm",
+		SFF8636_VCC_AW_OFFSET, (SFF8636_VCC_LALARM_STATUS) },
+	{ "Module voltage high warning",
+		SFF8636_VCC_AW_OFFSET, (SFF8636_VCC_HWARN_STATUS) },
+	{ "Module voltage low warning",
+		SFF8636_VCC_AW_OFFSET, (SFF8636_VCC_LWARN_STATUS) },
+
+	{ "Laser tx power high alarm   (Channel 1)",
+		SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_1_HALARM) },
+	{ "Laser tx power low alarm    (Channel 1)",
+		SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_1_LALARM) },
+	{ "Laser tx power high warning (Channel 1)",
+		SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_1_HWARN) },
+	{ "Laser tx power low warning  (Channel 1)",
+		SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_1_LWARN) },
+
+	{ "Laser tx power high alarm   (Channel 2)",
+		SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_2_HALARM) },
+	{ "Laser tx power low alarm    (Channel 2)",
+		SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_2_LALARM) },
+	{ "Laser tx power high warning (Channel 2)",
+		SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_2_HWARN) },
+	{ "Laser tx power low warning  (Channel 2)",
+		SFF8636_TX_PWR_12_AW_OFFSET, (SFF8636_TX_PWR_2_LWARN) },
+
+	{ "Laser tx power high alarm   (Channel 3)",
+		SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_3_HALARM) },
+	{ "Laser tx power low alarm    (Channel 3)",
+		SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_3_LALARM) },
+	{ "Laser tx power high warning (Channel 3)",
+		SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_3_HWARN) },
+	{ "Laser tx power low warning  (Channel 3)",
+		SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_3_LWARN) },
+
+	{ "Laser tx power high alarm   (Channel 4)",
+		SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_4_HALARM) },
+	{ "Laser tx power low alarm    (Channel 4)",
+		SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_4_LALARM) },
+	{ "Laser tx power high warning (Channel 4)",
+		SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_4_HWARN) },
+	{ "Laser tx power low warning  (Channel 4)",
+		SFF8636_TX_PWR_34_AW_OFFSET, (SFF8636_TX_PWR_4_LWARN) },
+
+	{ "Laser rx power high alarm   (Channel 1)",
+		SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_1_HALARM) },
+	{ "Laser rx power low alarm    (Channel 1)",
+		SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_1_LALARM) },
+	{ "Laser rx power high warning (Channel 1)",
+		SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_1_HWARN) },
+	{ "Laser rx power low warning  (Channel 1)",
+		SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_1_LWARN) },
+
+	{ "Laser rx power high alarm   (Channel 2)",
+		SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_2_HALARM) },
+	{ "Laser rx power low alarm    (Channel 2)",
+		SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_2_LALARM) },
+	{ "Laser rx power high warning (Channel 2)",
+		SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_2_HWARN) },
+	{ "Laser rx power low warning  (Channel 2)",
+		SFF8636_RX_PWR_12_AW_OFFSET, (SFF8636_RX_PWR_2_LWARN) },
+
+	{ "Laser rx power high alarm   (Channel 3)",
+		SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_3_HALARM) },
+	{ "Laser rx power low alarm    (Channel 3)",
+		SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_3_LALARM) },
+	{ "Laser rx power high warning (Channel 3)",
+		SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_3_HWARN) },
+	{ "Laser rx power low warning  (Channel 3)",
+		SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_3_LWARN) },
+
+	{ "Laser rx power high alarm   (Channel 4)",
+		SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_4_HALARM) },
+	{ "Laser rx power low alarm    (Channel 4)",
+		SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_4_LALARM) },
+	{ "Laser rx power high warning (Channel 4)",
+		SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_4_HWARN) },
+	{ "Laser rx power low warning  (Channel 4)",
+		SFF8636_RX_PWR_34_AW_OFFSET, (SFF8636_RX_PWR_4_LWARN) },
+
+	{ NULL, 0, 0 },
+};
+
+static void sff8636_show_identifier(const __u8 *id)
+{
+	sff8024_show_identifier(id, SFF8636_ID_OFFSET);
+}
+
+static void sff8636_show_ext_identifier(const __u8 *id)
+{
+	printf("\t%-41s : 0x%02x\n", "Extended identifier",
+			id[SFF8636_EXT_ID_OFFSET]);
+
+	static const char *pfx =
+		"\tExtended identifier description           :";
+
+	switch (id[SFF8636_EXT_ID_OFFSET] & SFF8636_EXT_ID_PWR_CLASS_MASK) {
+	case SFF8636_EXT_ID_PWR_CLASS_1:
+		printf("%s 1.5W max. Power consumption\n", pfx);
+		break;
+	case SFF8636_EXT_ID_PWR_CLASS_2:
+		printf("%s 2.0W max. Power consumption\n", pfx);
+		break;
+	case SFF8636_EXT_ID_PWR_CLASS_3:
+		printf("%s 2.5W max. Power consumption\n", pfx);
+		break;
+	case SFF8636_EXT_ID_PWR_CLASS_4:
+		printf("%s 3.5W max. Power consumption\n", pfx);
+		break;
+	}
+
+	if (id[SFF8636_EXT_ID_OFFSET] & SFF8636_EXT_ID_CDR_TX_MASK)
+		printf("%s CDR present in TX,", pfx);
+	else
+		printf("%s No CDR in TX,", pfx);
+
+	if (id[SFF8636_EXT_ID_OFFSET] & SFF8636_EXT_ID_CDR_RX_MASK)
+		printf(" CDR present in RX\n");
+	else
+		printf(" No CDR in RX\n");
+
+	switch (id[SFF8636_EXT_ID_OFFSET] & SFF8636_EXT_ID_EPWR_CLASS_MASK) {
+	case SFF8636_EXT_ID_PWR_CLASS_LEGACY:
+		printf("%s", pfx);
+		break;
+	case SFF8636_EXT_ID_PWR_CLASS_5:
+		printf("%s 4.0W max. Power consumption,", pfx);
+		break;
+	case SFF8636_EXT_ID_PWR_CLASS_6:
+		printf("%s 4.5W max. Power consumption, ", pfx);
+		break;
+	case SFF8636_EXT_ID_PWR_CLASS_7:
+		printf("%s 5.0W max. Power consumption, ", pfx);
+		break;
+	}
+	if (id[SFF8636_PWR_MODE_OFFSET] & SFF8636_HIGH_PWR_ENABLE)
+		printf(" High Power Class (> 3.5 W) enabled\n");
+	else
+		printf(" High Power Class (> 3.5 W) not enabled\n");
+}
+
+static void sff8636_show_connector(const __u8 *id)
+{
+	sff8024_show_connector(id, SFF8636_CTOR_OFFSET);
+}
+
+static void sff8636_show_transceiver(const __u8 *id)
+{
+	static const char *pfx =
+		"\tTransceiver type                          :";
+
+	printf("\t%-41s : 0x%02x 0x%02x 0x%02x " \
+			"0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+			"Transceiver codes",
+			id[SFF8636_ETHERNET_COMP_OFFSET],
+			id[SFF8636_SONET_COMP_OFFSET],
+			id[SFF8636_SAS_COMP_OFFSET],
+			id[SFF8636_GIGE_COMP_OFFSET],
+			id[SFF8636_FC_LEN_OFFSET],
+			id[SFF8636_FC_TECH_OFFSET],
+			id[SFF8636_FC_TRANS_MEDIA_OFFSET],
+			id[SFF8636_FC_SPEED_OFFSET]);
+
+	/* 10G/40G Ethernet Compliance Codes */
+	if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_10G_LRM)
+		printf("%s 10G Ethernet: 10G Base-LRM\n", pfx);
+	if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_10G_LR)
+		printf("%s 10G Ethernet: 10G Base-LR\n", pfx);
+	if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_10G_SR)
+		printf("%s 10G Ethernet: 10G Base-SR\n", pfx);
+	if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_40G_CR4)
+		printf("%s 40G Ethernet: 40G Base-CR4\n", pfx);
+	if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_40G_SR4)
+		printf("%s 40G Ethernet: 40G Base-SR4\n", pfx);
+	if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_40G_LR4)
+		printf("%s 40G Ethernet: 40G Base-LR4\n", pfx);
+	if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_40G_ACTIVE)
+		printf("%s 40G Ethernet: 40G Active Cable (XLPPI)\n", pfx);
+	/* Extended Specification Compliance Codes from SFF-8024 */
+	if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_RSRVD) {
+		switch (id[SFF8636_OPTION_1_OFFSET]) {
+		case SFF8636_ETHERNET_UNSPECIFIED:
+			printf("%s (reserved or unknown)\n", pfx);
+			break;
+		case SFF8636_ETHERNET_100G_AOC:
+			printf("%s 100G Ethernet: 100G AOC or 25GAUI C2M AOC with worst BER of 5x10^(-5)\n",
+					pfx);
+			break;
+		case SFF8636_ETHERNET_100G_SR4:
+			printf("%s 100G Ethernet: 100G Base-SR4 or 25GBase-SR\n",
+					pfx);
+			break;
+		case SFF8636_ETHERNET_100G_LR4:
+			printf("%s 100G Ethernet: 100G Base-LR4\n", pfx);
+			break;
+		case SFF8636_ETHERNET_100G_ER4:
+			printf("%s 100G Ethernet: 100G Base-ER4\n", pfx);
+			break;
+		case SFF8636_ETHERNET_100G_SR10:
+			printf("%s 100G Ethernet: 100G Base-SR10\n", pfx);
+			break;
+		case SFF8636_ETHERNET_100G_CWDM4_FEC:
+			printf("%s 100G Ethernet: 100G CWDM4 MSA with FEC\n", pfx);
+			break;
+		case SFF8636_ETHERNET_100G_PSM4:
+			printf("%s 100G Ethernet: 100G PSM4 Parallel SMF\n", pfx);
+			break;
+		case SFF8636_ETHERNET_100G_ACC:
+			printf("%s 100G Ethernet: 100G ACC or 25GAUI C2M ACC with worst BER of 5x10^(-5)\n",
+				pfx);
+			break;
+		case SFF8636_ETHERNET_100G_CWDM4_NO_FEC:
+			printf("%s 100G Ethernet: 100G CWDM4 MSA without FEC\n", pfx);
+			break;
+		case SFF8636_ETHERNET_100G_RSVD1:
+			printf("%s (reserved or unknown)\n", pfx);
+			break;
+		case SFF8636_ETHERNET_100G_CR4:
+			printf("%s 100G Ethernet: 100G Base-CR4 or 25G Base-CR CA-L\n",
+				pfx);
+			break;
+		case SFF8636_ETHERNET_25G_CR_CA_S:
+			printf("%s 25G Ethernet: 25G Base-CR CA-S\n", pfx);
+			break;
+		case SFF8636_ETHERNET_25G_CR_CA_N:
+			printf("%s 25G Ethernet: 25G Base-CR CA-N\n", pfx);
+			break;
+		case SFF8636_ETHERNET_40G_ER4:
+			printf("%s 40G Ethernet: 40G Base-ER4\n", pfx);
+			break;
+		case SFF8636_ETHERNET_4X10_SR:
+			printf("%s 4x10G Ethernet: 10G Base-SR\n", pfx);
+			break;
+		case SFF8636_ETHERNET_40G_PSM4:
+			printf("%s 40G Ethernet: 40G PSM4 Parallel SMF\n", pfx);
+			break;
+		case SFF8636_ETHERNET_G959_P1I1_2D1:
+			printf("%s Ethernet: G959.1 profile P1I1-2D1 (10709 MBd, 2km, 1310nm SM)\n",
+					pfx);
+			break;
+		case SFF8636_ETHERNET_G959_P1S1_2D2:
+			printf("%s Ethernet: G959.1 profile P1S1-2D2 (10709 MBd, 40km, 1550nm SM)\n",
+					pfx);
+			break;
+		case SFF8636_ETHERNET_G959_P1L1_2D2:
+			printf("%s Ethernet: G959.1 profile P1L1-2D2 (10709 MBd, 80km, 1550nm SM)\n",
+					pfx);
+			break;
+		case SFF8636_ETHERNET_10GT_SFI:
+			printf("%s 10G Ethernet: 10G Base-T with SFI electrical interface\n",
+					pfx);
+			break;
+		case SFF8636_ETHERNET_100G_CLR4:
+			printf("%s 100G Ethernet: 100G CLR4\n", pfx);
+			break;
+		case SFF8636_ETHERNET_100G_AOC2:
+			printf("%s 100G Ethernet: 100G AOC or 25GAUI C2M AOC with worst BER of 10^(-12)\n",
+					pfx);
+			break;
+		case SFF8636_ETHERNET_100G_ACC2:
+			printf("%s 100G Ethernet: 100G ACC or 25GAUI C2M ACC with worst BER of 10^(-12)\n",
+					pfx);
+			break;
+		default:
+			printf("%s (reserved or unknown)\n", pfx);
+			break;
+		}
+	}
+
+	/* SONET Compliance Codes */
+	if (id[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_40G_OTN))
+		printf("%s 40G OTN (OTU3B/OTU3C)\n", pfx);
+	if (id[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_OC48_LR))
+		printf("%s SONET: OC-48, long reach\n", pfx);
+	if (id[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_OC48_IR))
+		printf("%s SONET: OC-48, intermediate reach\n", pfx);
+	if (id[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_OC48_SR))
+		printf("%s SONET: OC-48, short reach\n", pfx);
+
+	/* SAS/SATA Compliance Codes */
+	if (id[SFF8636_SAS_COMP_OFFSET] & (SFF8636_SAS_6G))
+		printf("%s SAS 6.0G\n", pfx);
+	if (id[SFF8636_SAS_COMP_OFFSET] & (SFF8636_SAS_3G))
+		printf("%s SAS 3.0G\n", pfx);
+
+	/* Ethernet Compliance Codes */
+	if (id[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_T)
+		printf("%s Ethernet: 1000BASE-T\n", pfx);
+	if (id[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_CX)
+		printf("%s Ethernet: 1000BASE-CX\n", pfx);
+	if (id[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_LX)
+		printf("%s Ethernet: 1000BASE-LX\n", pfx);
+	if (id[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_SX)
+		printf("%s Ethernet: 1000BASE-SX\n", pfx);
+
+	/* Fibre Channel link length */
+	if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_VERY_LONG)
+		printf("%s FC: very long distance (V)\n", pfx);
+	if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_SHORT)
+		printf("%s FC: short distance (S)\n", pfx);
+	if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_INT)
+		printf("%s FC: intermediate distance (I)\n", pfx);
+	if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_LONG)
+		printf("%s FC: long distance (L)\n", pfx);
+	if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_MED)
+		printf("%s FC: medium distance (M)\n", pfx);
+
+	/* Fibre Channel transmitter technology */
+	if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_TECH_LONG_LC)
+		printf("%s FC: Longwave laser (LC)\n", pfx);
+	if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_TECH_ELEC_INTER)
+		printf("%s FC: Electrical inter-enclosure (EL)\n", pfx);
+	if (id[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_ELEC_INTRA)
+		printf("%s FC: Electrical intra-enclosure (EL)\n", pfx);
+	if (id[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_SHORT_WO_OFC)
+		printf("%s FC: Shortwave laser w/o OFC (SN)\n", pfx);
+	if (id[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_SHORT_W_OFC)
+		printf("%s FC: Shortwave laser with OFC (SL)\n", pfx);
+	if (id[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_LONG_LL)
+		printf("%s FC: Longwave laser (LL)\n", pfx);
+
+	/* Fibre Channel transmission media */
+	if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_TW)
+		printf("%s FC: Twin Axial Pair (TW)\n", pfx);
+	if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_TP)
+		printf("%s FC: Twisted Pair (TP)\n", pfx);
+	if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_MI)
+		printf("%s FC: Miniature Coax (MI)\n", pfx);
+	if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_TV)
+		printf("%s FC: Video Coax (TV)\n", pfx);
+	if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_M6)
+		printf("%s FC: Multimode, 62.5m (M6)\n", pfx);
+	if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_M5)
+		printf("%s FC: Multimode, 50m (M5)\n", pfx);
+	if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_OM3)
+		printf("%s FC: Multimode, 50um (OM3)\n", pfx);
+	if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_SM)
+		printf("%s FC: Single Mode (SM)\n", pfx);
+
+	/* Fibre Channel speed */
+	if (id[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_1200_MBPS)
+		printf("%s FC: 1200 MBytes/sec\n", pfx);
+	if (id[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_800_MBPS)
+		printf("%s FC: 800 MBytes/sec\n", pfx);
+	if (id[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_1600_MBPS)
+		printf("%s FC: 1600 MBytes/sec\n", pfx);
+	if (id[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_400_MBPS)
+		printf("%s FC: 400 MBytes/sec\n", pfx);
+	if (id[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_200_MBPS)
+		printf("%s FC: 200 MBytes/sec\n", pfx);
+	if (id[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_100_MBPS)
+		printf("%s FC: 100 MBytes/sec\n", pfx);
+}
+
+static void sff8636_show_encoding(const __u8 *id)
+{
+	sff8024_show_encoding(id, SFF8636_ENCODING_OFFSET, ETH_MODULE_SFF_8636);
+}
+
+static void sff8636_show_rate_identifier(const __u8 *id)
+{
+	/* TODO: Need to fix rate select logic */
+	printf("\t%-41s : 0x%02x\n", "Rate identifier",
+			id[SFF8636_EXT_RS_OFFSET]);
+}
+
+static void sff8636_show_oui(const __u8 *id)
+{
+	sff8024_show_oui(id, SFF8636_VENDOR_OUI_OFFSET);
+}
+
+static void sff8636_show_wavelength_or_copper_compliance(const __u8 *id)
+{
+	printf("\t%-41s : 0x%02x", "Transmitter technology",
+		(id[SFF8636_DEVICE_TECH_OFFSET] & SFF8636_TRANS_TECH_MASK));
+
+	switch (id[SFF8636_DEVICE_TECH_OFFSET] & SFF8636_TRANS_TECH_MASK) {
+	case SFF8636_TRANS_850_VCSEL:
+		printf(" (850 nm VCSEL)\n");
+		break;
+	case SFF8636_TRANS_1310_VCSEL:
+		printf(" (1310 nm VCSEL)\n");
+		break;
+	case SFF8636_TRANS_1550_VCSEL:
+		printf(" (1550 nm VCSEL)\n");
+		break;
+	case SFF8636_TRANS_1310_FP:
+		printf(" (1310 nm FP)\n");
+		break;
+	case SFF8636_TRANS_1310_DFB:
+		printf(" (1310 nm DFB)\n");
+		break;
+	case SFF8636_TRANS_1550_DFB:
+		printf(" (1550 nm DFB)\n");
+		break;
+	case SFF8636_TRANS_1310_EML:
+		printf(" (1310 nm EML)\n");
+		break;
+	case SFF8636_TRANS_1550_EML:
+		printf(" (1550 nm EML)\n");
+		break;
+	case SFF8636_TRANS_OTHERS:
+		printf(" (Others/Undefined)\n");
+		break;
+	case SFF8636_TRANS_1490_DFB:
+		printf(" (1490 nm DFB)\n");
+		break;
+	case SFF8636_TRANS_COPPER_PAS_UNEQUAL:
+		printf(" (Copper cable unequalized)\n");
+		break;
+	case SFF8636_TRANS_COPPER_PAS_EQUAL:
+		printf(" (Copper cable passive equalized)\n");
+		break;
+	case SFF8636_TRANS_COPPER_LNR_FAR_EQUAL:
+		printf(" (Copper cable, near and far end limiting active equalizers)\n");
+		break;
+	case SFF8636_TRANS_COPPER_FAR_EQUAL:
+		printf(" (Copper cable, far end limiting active equalizers)\n");
+		break;
+	case SFF8636_TRANS_COPPER_NEAR_EQUAL:
+		printf(" (Copper cable, near end limiting active equalizers)\n");
+		break;
+	case SFF8636_TRANS_COPPER_LNR_EQUAL:
+		printf(" (Copper cable, linear active equalizers)\n");
+		break;
+	}
+
+	if ((id[SFF8636_DEVICE_TECH_OFFSET] & SFF8636_TRANS_TECH_MASK)
+			>= SFF8636_TRANS_COPPER_PAS_UNEQUAL) {
+		printf("\t%-41s : %udb\n", "Attenuation at 2.5GHz",
+			id[SFF8636_WAVELEN_HIGH_BYTE_OFFSET]);
+		printf("\t%-41s : %udb\n", "Attenuation at 5.0GHz",
+			id[SFF8636_WAVELEN_LOW_BYTE_OFFSET]);
+		printf("\t%-41s : %udb\n", "Attenuation at 7.0GHz",
+			id[SFF8636_WAVE_TOL_HIGH_BYTE_OFFSET]);
+		printf("\t%-41s : %udb\n", "Attenuation at 12.9GHz",
+			id[SFF8636_WAVE_TOL_LOW_BYTE_OFFSET]);
+	} else {
+		printf("\t%-41s : %.3lfnm\n", "Laser wavelength",
+			(((id[SFF8636_WAVELEN_HIGH_BYTE_OFFSET] << 8) |
+				id[SFF8636_WAVELEN_LOW_BYTE_OFFSET])*0.05));
+		printf("\t%-41s : %.3lfnm\n", "Laser wavelength tolerance",
+			(((id[SFF8636_WAVE_TOL_HIGH_BYTE_OFFSET] << 8) |
+			id[SFF8636_WAVE_TOL_LOW_BYTE_OFFSET])*0.005));
+	}
+}
+
+static void sff8636_show_revision_compliance(const __u8 *id)
+{
+	static const char *pfx =
+		"\tRevision Compliance                       :";
+
+	switch (id[SFF8636_REV_COMPLIANCE_OFFSET]) {
+	case SFF8636_REV_UNSPECIFIED:
+		printf("%s Revision not specified\n", pfx);
+		break;
+	case SFF8636_REV_8436_48:
+		printf("%s SFF-8436 Rev 4.8 or earlier\n", pfx);
+		break;
+	case SFF8636_REV_8436_8636:
+		printf("%s SFF-8436 Rev 4.8 or earlier\n", pfx);
+		break;
+	case SFF8636_REV_8636_13:
+		printf("%s SFF-8636 Rev 1.3 or earlier\n", pfx);
+		break;
+	case SFF8636_REV_8636_14:
+		printf("%s SFF-8636 Rev 1.4\n", pfx);
+		break;
+	case SFF8636_REV_8636_15:
+		printf("%s SFF-8636 Rev 1.5\n", pfx);
+		break;
+	case SFF8636_REV_8636_20:
+		printf("%s SFF-8636 Rev 2.0\n", pfx);
+		break;
+	case SFF8636_REV_8636_27:
+		printf("%s SFF-8636 Rev 2.5/2.6/2.7\n", pfx);
+		break;
+	default:
+		printf("%s Unallocated\n", pfx);
+		break;
+	}
+}
+
+/*
+ * 2-byte internal temperature conversions:
+ * First byte is a signed 8-bit integer, which is the temp decimal part
+ * Second byte are 1/256th of degree, which are added to the dec part.
+ */
+#define SFF8636_OFFSET_TO_TEMP(offset) ((__s16)OFFSET_TO_U16(offset))
+
+static void sff8636_dom_parse(const __u8 *id, struct sff_diags *sd)
+{
+	int i = 0;
+
+	/* Monitoring Thresholds for Alarms and Warnings */
+	sd->sfp_voltage[MCURR] = OFFSET_TO_U16(SFF8636_VCC_CURR);
+	sd->sfp_voltage[HALRM] = OFFSET_TO_U16(SFF8636_VCC_HALRM);
+	sd->sfp_voltage[LALRM] = OFFSET_TO_U16(SFF8636_VCC_LALRM);
+	sd->sfp_voltage[HWARN] = OFFSET_TO_U16(SFF8636_VCC_HWARN);
+	sd->sfp_voltage[LWARN] = OFFSET_TO_U16(SFF8636_VCC_LWARN);
+
+	sd->sfp_temp[MCURR] = SFF8636_OFFSET_TO_TEMP(SFF8636_TEMP_CURR);
+	sd->sfp_temp[HALRM] = SFF8636_OFFSET_TO_TEMP(SFF8636_TEMP_HALRM);
+	sd->sfp_temp[LALRM] = SFF8636_OFFSET_TO_TEMP(SFF8636_TEMP_LALRM);
+	sd->sfp_temp[HWARN] = SFF8636_OFFSET_TO_TEMP(SFF8636_TEMP_HWARN);
+	sd->sfp_temp[LWARN] = SFF8636_OFFSET_TO_TEMP(SFF8636_TEMP_LWARN);
+
+	sd->bias_cur[HALRM] = OFFSET_TO_U16(SFF8636_TX_BIAS_HALRM);
+	sd->bias_cur[LALRM] = OFFSET_TO_U16(SFF8636_TX_BIAS_LALRM);
+	sd->bias_cur[HWARN] = OFFSET_TO_U16(SFF8636_TX_BIAS_HWARN);
+	sd->bias_cur[LWARN] = OFFSET_TO_U16(SFF8636_TX_BIAS_LWARN);
+
+	sd->tx_power[HALRM] = OFFSET_TO_U16(SFF8636_TX_PWR_HALRM);
+	sd->tx_power[LALRM] = OFFSET_TO_U16(SFF8636_TX_PWR_LALRM);
+	sd->tx_power[HWARN] = OFFSET_TO_U16(SFF8636_TX_PWR_HWARN);
+	sd->tx_power[LWARN] = OFFSET_TO_U16(SFF8636_TX_PWR_LWARN);
+
+	sd->rx_power[HALRM] = OFFSET_TO_U16(SFF8636_RX_PWR_HALRM);
+	sd->rx_power[LALRM] = OFFSET_TO_U16(SFF8636_RX_PWR_LALRM);
+	sd->rx_power[HWARN] = OFFSET_TO_U16(SFF8636_RX_PWR_HWARN);
+	sd->rx_power[LWARN] = OFFSET_TO_U16(SFF8636_RX_PWR_LWARN);
+
+
+	/* Channel Specific Data */
+	for (i = 0; i < MAX_CHANNEL_NUM; i++) {
+		u8 rx_power_offset, tx_bias_offset;
+		u8 tx_power_offset;
+
+		switch (i) {
+		case 0:
+			rx_power_offset = SFF8636_RX_PWR_1_OFFSET;
+			tx_power_offset = SFF8636_TX_PWR_1_OFFSET;
+			tx_bias_offset = SFF8636_TX_BIAS_1_OFFSET;
+			break;
+		case 1:
+			rx_power_offset = SFF8636_RX_PWR_2_OFFSET;
+			tx_power_offset = SFF8636_TX_PWR_2_OFFSET;
+			tx_bias_offset = SFF8636_TX_BIAS_2_OFFSET;
+			break;
+		case 2:
+			rx_power_offset = SFF8636_RX_PWR_3_OFFSET;
+			tx_power_offset = SFF8636_TX_PWR_3_OFFSET;
+			tx_bias_offset = SFF8636_TX_BIAS_3_OFFSET;
+			break;
+		case 3:
+			rx_power_offset = SFF8636_RX_PWR_4_OFFSET;
+			tx_power_offset = SFF8636_TX_PWR_4_OFFSET;
+			tx_bias_offset = SFF8636_TX_BIAS_4_OFFSET;
+			break;
+		}
+		sd->scd[i].bias_cur = OFFSET_TO_U16(tx_bias_offset);
+		sd->scd[i].rx_power = OFFSET_TO_U16(rx_power_offset);
+		sd->scd[i].tx_power = OFFSET_TO_U16(tx_power_offset);
+	}
+
+}
+
+static void sff8636_show_dom(const __u8 *id, __u32 eeprom_len)
+{
+	struct sff_diags sd = {0};
+	char *rx_power_string = NULL;
+	char power_string[MAX_DESC_SIZE];
+	int i;
+
+	/*
+	 * There is no clear identifier to signify the existence of
+	 * optical diagnostics similar to SFF-8472. So checking existence
+	 * of page 3, will provide the gurantee for existence of alarms
+	 * and thresholds
+	 * If pagging support exists, then supports_alarms is marked as 1
+	 */
+
+	if (eeprom_len == ETH_MODULE_SFF_8636_MAX_LEN) {
+		if (!(id[SFF8636_STATUS_2_OFFSET] &
+					SFF8636_STATUS_PAGE_3_PRESENT)) {
+			sd.supports_alarms = 1;
+		}
+	}
+
+	sd.rx_power_type = id[SFF8636_DIAG_TYPE_OFFSET] &
+						SFF8636_RX_PWR_TYPE_MASK;
+	sd.tx_power_type = id[SFF8636_DIAG_TYPE_OFFSET] &
+						SFF8636_RX_PWR_TYPE_MASK;
+
+	sff8636_dom_parse(id, &sd);
+
+	PRINT_TEMP("Module temperature", sd.sfp_temp[MCURR]);
+	PRINT_VCC("Module voltage", sd.sfp_voltage[MCURR]);
+
+	/*
+	 * SFF-8636/8436 spec is not clear whether RX power/ TX bias
+	 * current fields are supported or not. A valid temperature
+	 * reading is used as existence for TX/RX power.
+	 */
+	if ((sd.sfp_temp[MCURR] == 0x0) ||
+	    (sd.sfp_temp[MCURR] == (__s16)0xFFFF))
+		return;
+
+	printf("\t%-41s : %s\n", "Alarm/warning flags implemented",
+		(sd.supports_alarms ? "Yes" : "No"));
+
+	for (i = 0; i < MAX_CHANNEL_NUM; i++) {
+		snprintf(power_string, MAX_DESC_SIZE, "%s (Channel %d)",
+					"Laser tx bias current", i+1);
+		PRINT_BIAS(power_string, sd.scd[i].bias_cur);
+	}
+
+	for (i = 0; i < MAX_CHANNEL_NUM; i++) {
+		snprintf(power_string, MAX_DESC_SIZE, "%s (Channel %d)",
+					"Transmit avg optical power", i+1);
+		PRINT_xX_PWR(power_string, sd.scd[i].tx_power);
+	}
+
+	if (!sd.rx_power_type)
+		rx_power_string = "Receiver signal OMA";
+	else
+		rx_power_string = "Rcvr signal avg optical power";
+
+	for (i = 0; i < MAX_CHANNEL_NUM; i++) {
+		snprintf(power_string, MAX_DESC_SIZE, "%s(Channel %d)",
+					rx_power_string, i+1);
+		PRINT_xX_PWR(power_string, sd.scd[i].rx_power);
+	}
+
+	if (sd.supports_alarms) {
+		for (i = 0; sff8636_aw_flags[i].str; ++i) {
+			printf("\t%-41s : %s\n", sff8636_aw_flags[i].str,
+			       id[sff8636_aw_flags[i].offset]
+			       & sff8636_aw_flags[i].value ? "On" : "Off");
+		}
+
+		sff_show_thresholds(sd);
+	}
+
+}
+void sff8636_show_all(const __u8 *id, __u32 eeprom_len)
+{
+	sff8636_show_identifier(id);
+	if ((id[SFF8636_ID_OFFSET] == SFF8024_ID_QSFP) ||
+		(id[SFF8636_ID_OFFSET] == SFF8024_ID_QSFP_PLUS) ||
+		(id[SFF8636_ID_OFFSET] == SFF8024_ID_QSFP28)) {
+		sff8636_show_ext_identifier(id);
+		sff8636_show_connector(id);
+		sff8636_show_transceiver(id);
+		sff8636_show_encoding(id);
+		sff_show_value_with_unit(id, SFF8636_BR_NOMINAL_OFFSET,
+				"BR, Nominal", 100, "Mbps");
+		sff8636_show_rate_identifier(id);
+		sff_show_value_with_unit(id, SFF8636_SM_LEN_OFFSET,
+			     "Length (SMF,km)", 1, "km");
+		sff_show_value_with_unit(id, SFF8636_OM3_LEN_OFFSET,
+				"Length (OM3 50um)", 2, "m");
+		sff_show_value_with_unit(id, SFF8636_OM2_LEN_OFFSET,
+				"Length (OM2 50um)", 1, "m");
+		sff_show_value_with_unit(id, SFF8636_OM1_LEN_OFFSET,
+			     "Length (OM1 62.5um)", 1, "m");
+		sff_show_value_with_unit(id, SFF8636_CBL_LEN_OFFSET,
+			     "Length (Copper or Active cable)", 1, "m");
+		sff8636_show_wavelength_or_copper_compliance(id);
+		sff_show_ascii(id, SFF8636_VENDOR_NAME_START_OFFSET,
+			       SFF8636_VENDOR_NAME_END_OFFSET, "Vendor name");
+		sff8636_show_oui(id);
+		sff_show_ascii(id, SFF8636_VENDOR_PN_START_OFFSET,
+			       SFF8636_VENDOR_PN_END_OFFSET, "Vendor PN");
+		sff_show_ascii(id, SFF8636_VENDOR_REV_START_OFFSET,
+			       SFF8636_VENDOR_REV_END_OFFSET, "Vendor rev");
+		sff_show_ascii(id, SFF8636_VENDOR_SN_START_OFFSET,
+			       SFF8636_VENDOR_SN_END_OFFSET, "Vendor SN");
+		sff_show_ascii(id, SFF8636_DATE_YEAR_OFFSET,
+			       SFF8636_DATE_VENDOR_LOT_OFFSET + 1, "Date code");
+		sff8636_show_revision_compliance(id);
+		sff8636_show_dom(id, eeprom_len);
+	}
+}
diff --git a/qsfp.h b/qsfp.h
new file mode 100644
index 0000000..b623174
--- /dev/null
+++ b/qsfp.h
@@ -0,0 +1,597 @@
+/*
+ * SFF 8636 standards based QSFP EEPROM Field Definitions
+ *
+ * Vidya Ravipati <vidya@cumulusnetworks.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef QSFP_H__
+#define QSFP_H__
+
+/*------------------------------------------------------------------------------
+ *
+ * QSFP EEPROM data structures
+ *
+ * register info from SFF-8636 Rev 2.7
+ */
+
+/*------------------------------------------------------------------------------
+ *
+ * Lower Memory Page 00h
+ * Measurement, Diagnostic and Control Functions
+ *
+ */
+/* Identifier - 0 */
+/* Values are defined under SFF8024_ID_OFFSET */
+#define	SFF8636_ID_OFFSET	0x00
+
+#define	SFF8636_REV_COMPLIANCE_OFFSET	0x01
+#define	 SFF8636_REV_UNSPECIFIED		0x00
+#define	 SFF8636_REV_8436_48			0x01
+#define	 SFF8636_REV_8436_8636			0x02
+#define	 SFF8636_REV_8636_13			0x03
+#define	 SFF8636_REV_8636_14			0x04
+#define	 SFF8636_REV_8636_15			0x05
+#define	 SFF8636_REV_8636_20			0x06
+#define	 SFF8636_REV_8636_27			0x07
+
+#define	SFF8636_STATUS_2_OFFSET	0x02
+/* Flat Memory:0- Paging, 1- Page 0 only */
+#define	 SFF8636_STATUS_PAGE_3_PRESENT		(1 << 2)
+#define	 SFF8636_STATUS_INTL_OUTPUT		(1 << 1)
+#define	 SFF8636_STATUS_DATA_NOT_READY		(1 << 0)
+
+/* Channel Status Interrupt Flags - 3-5 */
+#define	SFF8636_LOS_AW_OFFSET	0x03
+#define	 SFF8636_TX4_LOS_AW		(1 << 7)
+#define	 SFF8636_TX3_LOS_AW		(1 << 6)
+#define	 SFF8636_TX2_LOS_AW		(1 << 5)
+#define	 SFF8636_TX1_LOS_AW		(1 << 4)
+#define	 SFF8636_RX4_LOS_AW		(1 << 3)
+#define	 SFF8636_RX3_LOS_AW		(1 << 2)
+#define	 SFF8636_RX2_LOS_AW		(1 << 1)
+#define	 SFF8636_RX1_LOS_AW		(1 << 0)
+
+#define	SFF8636_FAULT_AW_OFFSET	0x04
+#define	 SFF8636_TX4_FAULT_AW	(1 << 3)
+#define	 SFF8636_TX3_FAULT_AW	(1 << 2)
+#define	 SFF8636_TX2_FAULT_AW	(1 << 1)
+#define	 SFF8636_TX1_FAULT_AW	(1 << 0)
+
+/* Module Monitor Interrupt Flags - 6-8 */
+#define	SFF8636_TEMP_AW_OFFSET	0x06
+#define	 SFF8636_TEMP_HALARM_STATUS		(1 << 7)
+#define	 SFF8636_TEMP_LALARM_STATUS		(1 << 6)
+#define	 SFF8636_TEMP_HWARN_STATUS		(1 << 5)
+#define	 SFF8636_TEMP_LWARN_STATUS		(1 << 4)
+
+#define	SFF8636_VCC_AW_OFFSET	0x07
+#define	 SFF8636_VCC_HALARM_STATUS		(1 << 7)
+#define	 SFF8636_VCC_LALARM_STATUS		(1 << 6)
+#define	 SFF8636_VCC_HWARN_STATUS		(1 << 5)
+#define	 SFF8636_VCC_LWARN_STATUS		(1 << 4)
+
+/* Channel Monitor Interrupt Flags - 9-21 */
+#define	SFF8636_RX_PWR_12_AW_OFFSET	0x09
+#define	 SFF8636_RX_PWR_1_HALARM		(1 << 7)
+#define	 SFF8636_RX_PWR_1_LALARM		(1 << 6)
+#define	 SFF8636_RX_PWR_1_HWARN			(1 << 5)
+#define	 SFF8636_RX_PWR_1_LWARN			(1 << 4)
+#define	 SFF8636_RX_PWR_2_HALARM		(1 << 3)
+#define	 SFF8636_RX_PWR_2_LALARM		(1 << 2)
+#define	 SFF8636_RX_PWR_2_HWARN			(1 << 1)
+#define	 SFF8636_RX_PWR_2_LWARN			(1 << 0)
+
+#define	SFF8636_RX_PWR_34_AW_OFFSET	0x0A
+#define	 SFF8636_RX_PWR_3_HALARM		(1 << 7)
+#define	 SFF8636_RX_PWR_3_LALARM		(1 << 6)
+#define	 SFF8636_RX_PWR_3_HWARN			(1 << 5)
+#define	 SFF8636_RX_PWR_3_LWARN			(1 << 4)
+#define	 SFF8636_RX_PWR_4_HALARM		(1 << 3)
+#define	 SFF8636_RX_PWR_4_LALARM		(1 << 2)
+#define	 SFF8636_RX_PWR_4_HWARN			(1 << 1)
+#define	 SFF8636_RX_PWR_4_LWARN			(1 << 0)
+
+#define	SFF8636_TX_BIAS_12_AW_OFFSET	0x0B
+#define	 SFF8636_TX_BIAS_1_HALARM		(1 << 7)
+#define	 SFF8636_TX_BIAS_1_LALARM		(1 << 6)
+#define	 SFF8636_TX_BIAS_1_HWARN		(1 << 5)
+#define	 SFF8636_TX_BIAS_1_LWARN		(1 << 4)
+#define	 SFF8636_TX_BIAS_2_HALARM		(1 << 3)
+#define	 SFF8636_TX_BIAS_2_LALARM		(1 << 2)
+#define	 SFF8636_TX_BIAS_2_HWARN		(1 << 1)
+#define	 SFF8636_TX_BIAS_2_LWARN		(1 << 0)
+
+#define	SFF8636_TX_BIAS_34_AW_OFFSET	0xC
+#define	 SFF8636_TX_BIAS_3_HALARM		(1 << 7)
+#define	 SFF8636_TX_BIAS_3_LALARM		(1 << 6)
+#define	 SFF8636_TX_BIAS_3_HWARN		(1 << 5)
+#define	 SFF8636_TX_BIAS_3_LWARN		(1 << 4)
+#define	 SFF8636_TX_BIAS_4_HALARM		(1 << 3)
+#define	 SFF8636_TX_BIAS_4_LALARM		(1 << 2)
+#define	 SFF8636_TX_BIAS_4_HWARN		(1 << 1)
+#define	 SFF8636_TX_BIAS_4_LWARN		(1 << 0)
+
+#define	SFF8636_TX_PWR_12_AW_OFFSET	0x0D
+#define	 SFF8636_TX_PWR_1_HALARM		(1 << 7)
+#define	 SFF8636_TX_PWR_1_LALARM		(1 << 6)
+#define	 SFF8636_TX_PWR_1_HWARN			(1 << 5)
+#define	 SFF8636_TX_PWR_1_LWARN			(1 << 4)
+#define	 SFF8636_TX_PWR_2_HALARM		(1 << 3)
+#define	 SFF8636_TX_PWR_2_LALARM		(1 << 2)
+#define	 SFF8636_TX_PWR_2_HWARN			(1 << 1)
+#define	 SFF8636_TX_PWR_2_LWARN			(1 << 0)
+
+#define	SFF8636_TX_PWR_34_AW_OFFSET	0x0E
+#define	 SFF8636_TX_PWR_3_HALARM		(1 << 7)
+#define	 SFF8636_TX_PWR_3_LALARM		(1 << 6)
+#define	 SFF8636_TX_PWR_3_HWARN			(1 << 5)
+#define	 SFF8636_TX_PWR_3_LWARN			(1 << 4)
+#define	 SFF8636_TX_PWR_4_HALARM		(1 << 3)
+#define	 SFF8636_TX_PWR_4_LALARM		(1 << 2)
+#define	 SFF8636_TX_PWR_4_HWARN			(1 << 1)
+#define	 SFF8636_TX_PWR_4_LWARN			(1 << 0)
+
+/* Module Monitoring Values - 22-33 */
+#define	SFF8636_TEMP_CURR		0x16
+#define	SFF8636_TEMP_MSB_OFFSET		0x16
+#define	SFF8636_TEMP_LSB_OFFSET		0x17
+
+#define	SFF8636_VCC_CURR		0x1A
+#define	SFF8636_VCC_MSB_OFFSET		0x1A
+#define	SFF8636_VCC_LSB_OFFSET		0x1B
+
+/* Channel Monitoring Values - 34-81 */
+#define	SFF8636_RX_PWR_1_OFFSET		0x22
+#define	SFF8636_RX_PWR_2_OFFSET		0x24
+#define	SFF8636_RX_PWR_3_OFFSET		0x26
+#define	SFF8636_RX_PWR_4_OFFSET		0x28
+
+#define	SFF8636_TX_BIAS_1_OFFSET	0x2A
+#define	SFF8636_TX_BIAS_2_OFFSET	0x2C
+#define	SFF8636_TX_BIAS_3_OFFSET	0x2E
+#define	SFF8636_TX_BIAS_4_OFFSET	0x30
+
+#define	SFF8636_TX_PWR_1_OFFSET		0x32
+#define	SFF8636_TX_PWR_2_OFFSET		0x34
+#define	SFF8636_TX_PWR_3_OFFSET		0x36
+#define	SFF8636_TX_PWR_4_OFFSET		0x38
+
+/* Control Bytes - 86 - 99 */
+#define	SFF8636_TX_DISABLE_OFFSET	0x56
+#define	 SFF8636_TX_DISABLE_4			(1 << 3)
+#define	 SFF8636_TX_DISABLE_3			(1 << 2)
+#define	 SFF8636_TX_DISABLE_2			(1 << 1)
+#define	 SFF8636_TX_DISABLE_1			(1 << 0)
+
+#define	SFF8636_RX_RATE_SELECT_OFFSET	0x57
+#define	 SFF8636_RX_RATE_SELECT_4_MASK		(3 << 6)
+#define	 SFF8636_RX_RATE_SELECT_3_MASK		(3 << 4)
+#define	 SFF8636_RX_RATE_SELECT_2_MASK		(3 << 2)
+#define	 SFF8636_RX_RATE_SELECT_1_MASK		(3 << 0)
+
+#define	SFF8636_TX_RATE_SELECT_OFFSET	0x58
+#define	 SFF8636_TX_RATE_SELECT_4_MASK		(3 << 6)
+#define	 SFF8636_TX_RATE_SELECT_3_MASK		(3 << 4)
+#define	 SFF8636_TX_RATE_SELECT_2_MASK		(3 << 2)
+#define	 SFF8636_TX_RATE_SELECT_1_MASK		(3 << 0)
+
+#define	SFF8636_RX_APP_SELECT_4_OFFSET	0x58
+#define	SFF8636_RX_APP_SELECT_3_OFFSET	0x59
+#define	SFF8636_RX_APP_SELECT_2_OFFSET	0x5A
+#define	SFF8636_RX_APP_SELECT_1_OFFSET	0x5B
+
+#define	SFF8636_PWR_MODE_OFFSET		0x5D
+#define	 SFF8636_HIGH_PWR_ENABLE		(1 << 2)
+#define	 SFF8636_LOW_PWR_MODE			(1 << 1)
+#define	 SFF8636_PWR_OVERRIDE			(1 << 0)
+
+#define	SFF8636_TX_APP_SELECT_4_OFFSET	0x5E
+#define	SFF8636_TX_APP_SELECT_3_OFFSET	0x5F
+#define	SFF8636_TX_APP_SELECT_2_OFFSET	0x60
+#define	SFF8636_TX_APP_SELECT_1_OFFSET	0x61
+
+#define	SFF8636_LOS_MASK_OFFSET		0x64
+#define	 SFF8636_TX_LOS_4_MASK			(1 << 7)
+#define	 SFF8636_TX_LOS_3_MASK			(1 << 6)
+#define	 SFF8636_TX_LOS_2_MASK			(1 << 5)
+#define	 SFF8636_TX_LOS_1_MASK			(1 << 4)
+#define	 SFF8636_RX_LOS_4_MASK			(1 << 3)
+#define	 SFF8636_RX_LOS_3_MASK			(1 << 2)
+#define	 SFF8636_RX_LOS_2_MASK			(1 << 1)
+#define	 SFF8636_RX_LOS_1_MASK			(1 << 0)
+
+#define	SFF8636_FAULT_MASK_OFFSET	0x65
+#define	 SFF8636_TX_FAULT_1_MASK		(1 << 3)
+#define	 SFF8636_TX_FAULT_2_MASK		(1 << 2)
+#define	 SFF8636_TX_FAULT_3_MASK		(1 << 1)
+#define	 SFF8636_TX_FAULT_4_MASK		(1 << 0)
+
+#define	SFF8636_TEMP_MASK_OFFSET	0x67
+#define	 SFF8636_TEMP_HALARM_MASK		(1 << 7)
+#define	 SFF8636_TEMP_LALARM_MASK		(1 << 6)
+#define	 SFF8636_TEMP_HWARN_MASK		(1 << 5)
+#define	 SFF8636_TEMP_LWARN_MASK		(1 << 4)
+
+#define	SFF8636_VCC_MASK_OFFSET		0x68
+#define	 SFF8636_VCC_HALARM_MASK		(1 << 7)
+#define	 SFF8636_VCC_LALARM_MASK		(1 << 6)
+#define	 SFF8636_VCC_HWARN_MASK			(1 << 5)
+#define	 SFF8636_VCC_LWARN_MASK			(1 << 4)
+
+/*------------------------------------------------------------------------------
+ *
+ * Upper Memory Page 00h
+ * Serial ID - Base ID, Extended ID and Vendor Specific ID fields
+ *
+ */
+/* Identifier - 128 */
+/* Identifier values same as Lower Memory Page 00h */
+#define	SFF8636_UPPER_PAGE_0_ID_OFFSET		0x80
+
+/* Extended Identifier - 128 */
+#define SFF8636_EXT_ID_OFFSET		0x81
+#define	 SFF8636_EXT_ID_PWR_CLASS_MASK		0xC0
+#define	  SFF8636_EXT_ID_PWR_CLASS_1		(0 << 6)
+#define	  SFF8636_EXT_ID_PWR_CLASS_2		(1 << 6)
+#define	  SFF8636_EXT_ID_PWR_CLASS_3		(2 << 6)
+#define	  SFF8636_EXT_ID_PWR_CLASS_4		(3 << 6)
+#define	 SFF8636_EXT_ID_CLIE_MASK		0x10
+#define	  SFF8636_EXT_ID_CLIEI_CODE_PRESENT	(1 << 4)
+#define	 SFF8636_EXT_ID_CDR_TX_MASK		0x08
+#define	  SFF8636_EXT_ID_CDR_TX_PRESENT		(1 << 3)
+#define	 SFF8636_EXT_ID_CDR_RX_MASK		0x04
+#define	  SFF8636_EXT_ID_CDR_RX_PRESENT		(1 << 2)
+#define	 SFF8636_EXT_ID_EPWR_CLASS_MASK		0x03
+#define	  SFF8636_EXT_ID_PWR_CLASS_LEGACY	0
+#define	  SFF8636_EXT_ID_PWR_CLASS_5		1
+#define	  SFF8636_EXT_ID_PWR_CLASS_6		2
+#define	  SFF8636_EXT_ID_PWR_CLASS_7		3
+
+/* Connector Values offset - 130 */
+/* Values are defined under SFF8024_CTOR */
+#define	SFF8636_CTOR_OFFSET		0x82
+#define	 SFF8636_CTOR_UNKNOWN			0x00
+#define	 SFF8636_CTOR_SC			0x01
+#define	 SFF8636_CTOR_FC_STYLE_1		0x02
+#define	 SFF8636_CTOR_FC_STYLE_2		0x03
+#define	 SFF8636_CTOR_BNC_TNC			0x04
+#define	 SFF8636_CTOR_FC_COAX			0x05
+#define	 SFF8636_CTOR_FIBER_JACK		0x06
+#define	 SFF8636_CTOR_LC			0x07
+#define	 SFF8636_CTOR_MT_RJ			0x08
+#define	 SFF8636_CTOR_MU			0x09
+#define	 SFF8636_CTOR_SG			0x0A
+#define	 SFF8636_CTOR_OPT_PT			0x0B
+#define	 SFF8636_CTOR_MPO			0x0C
+/* 0D-1Fh --- Reserved */
+#define	 SFF8636_CTOR_HSDC_II			0x20
+#define	 SFF8636_CTOR_COPPER_PT			0x21
+#define	 SFF8636_CTOR_RJ45			0x22
+#define	 SFF8636_CTOR_NO_SEPARABLE		0x23
+#define	 SFF8636_CTOR_MXC_2X16			0x24
+
+/* Specification Compliance - 131-138 */
+/* Ethernet Compliance Codes - 131 */
+#define	SFF8636_ETHERNET_COMP_OFFSET	0x83
+#define	 SFF8636_ETHERNET_RSRVD			(1 << 7)
+#define	 SFF8636_ETHERNET_10G_LRM		(1 << 6)
+#define	 SFF8636_ETHERNET_10G_LR		(1 << 5)
+#define	 SFF8636_ETHERNET_10G_SR		(1 << 4)
+#define	 SFF8636_ETHERNET_40G_CR4		(1 << 3)
+#define	 SFF8636_ETHERNET_40G_SR4		(1 << 2)
+#define	 SFF8636_ETHERNET_40G_LR4		(1 << 1)
+#define	 SFF8636_ETHERNET_40G_ACTIVE	(1 << 0)
+
+/* SONET Compliance Codes - 132 */
+#define	SFF8636_SONET_COMP_OFFSET	0x84
+#define	 SFF8636_SONET_40G_OTN			(1 << 3)
+#define	 SFF8636_SONET_OC48_LR			(1 << 2)
+#define	 SFF8636_SONET_OC48_IR			(1 << 1)
+#define	 SFF8636_SONET_OC48_SR			(1 << 0)
+
+/* SAS/SATA Complaince Codes - 133 */
+#define	SFF8636_SAS_COMP_OFFSET		0x85
+#define	 SFF8636_SAS_12G			(1 << 6)
+#define	 SFF8636_SAS_6G				(1 << 5)
+#define	 SFF8636_SAS_3G				(1 << 4)
+
+/* Gigabit Ethernet Compliance Codes - 134 */
+#define	SFF8636_GIGE_COMP_OFFSET	0x86
+#define	 SFF8636_GIGE_1000_BASE_T		(1 << 3)
+#define	 SFF8636_GIGE_1000_BASE_CX		(1 << 2)
+#define	 SFF8636_GIGE_1000_BASE_LX		(1 << 1)
+#define	 SFF8636_GIGE_1000_BASE_SX		(1 << 0)
+
+/* Fibre Channel Link length/Transmitter Tech. - 135,136 */
+#define	SFF8636_FC_LEN_OFFSET		0x87
+#define	 SFF8636_FC_LEN_VERY_LONG		(1 << 7)
+#define	 SFF8636_FC_LEN_SHORT			(1 << 6)
+#define	 SFF8636_FC_LEN_INT			(1 << 5)
+#define	 SFF8636_FC_LEN_LONG			(1 << 4)
+#define	 SFF8636_FC_LEN_MED			(1 << 3)
+#define	 SFF8636_FC_TECH_LONG_LC		(1 << 1)
+#define	 SFF8636_FC_TECH_ELEC_INTER		(1 << 0)
+
+#define	SFF8636_FC_TECH_OFFSET		0x88
+#define	 SFF8636_FC_TECH_ELEC_INTRA		(1 << 7)
+#define	 SFF8636_FC_TECH_SHORT_WO_OFC		(1 << 6)
+#define	 SFF8636_FC_TECH_SHORT_W_OFC		(1 << 5)
+#define	 SFF8636_FC_TECH_LONG_LL		(1 << 4)
+
+/* Fibre Channel Transmitter Media - 137 */
+#define	SFF8636_FC_TRANS_MEDIA_OFFSET	0x89
+/* Twin Axial Pair */
+#define	 SFF8636_FC_TRANS_MEDIA_TW		(1 << 7)
+/* Shielded Twisted Pair */
+#define	 SFF8636_FC_TRANS_MEDIA_TP		(1 << 6)
+/* Miniature Coax */
+#define	 SFF8636_FC_TRANS_MEDIA_MI		(1 << 5)
+/* Video Coax */
+#define	 SFF8636_FC_TRANS_MEDIA_TV		(1 << 4)
+/* Multi-mode 62.5m */
+#define	 SFF8636_FC_TRANS_MEDIA_M6		(1 << 3)
+/* Multi-mode 50m */
+#define	 SFF8636_FC_TRANS_MEDIA_M5		(1 << 2)
+/* Multi-mode 50um */
+#define	 SFF8636_FC_TRANS_MEDIA_OM3		(1 << 1)
+/* Single Mode */
+#define	 SFF8636_FC_TRANS_MEDIA_SM		(1 << 0)
+
+/* Fibre Channel Speed - 138 */
+#define	SFF8636_FC_SPEED_OFFSET		0x8A
+#define	 SFF8636_FC_SPEED_1200_MBPS		(1 << 7)
+#define	 SFF8636_FC_SPEED_800_MBPS		(1 << 6)
+#define	 SFF8636_FC_SPEED_1600_MBPS		(1 << 5)
+#define	 SFF8636_FC_SPEED_400_MBPS		(1 << 4)
+#define	 SFF8636_FC_SPEED_200_MBPS		(1 << 2)
+#define	 SFF8636_FC_SPEED_100_MBPS		(1 << 0)
+
+/* Encoding - 139 */
+/* Values are defined under SFF8024_ENCODING */
+#define	SFF8636_ENCODING_OFFSET		0x8B
+#define	 SFF8636_ENCODING_MANCHESTER	0x06
+#define	 SFF8636_ENCODING_64B66B		0x05
+#define	 SFF8636_ENCODING_SONET			0x04
+#define	 SFF8636_ENCODING_NRZ			0x03
+#define	 SFF8636_ENCODING_4B5B			0x02
+#define	 SFF8636_ENCODING_8B10B			0x01
+#define	 SFF8636_ENCODING_UNSPEC		0x00
+
+/* BR, Nominal - 140 */
+#define	SFF8636_BR_NOMINAL_OFFSET	0x8C
+
+/* Extended RateSelect - 141 */
+#define	SFF8636_EXT_RS_OFFSET		0x8D
+#define	 SFF8636_EXT_RS_V1			(1 << 0)
+
+/* Length (Standard SM Fiber)-km - 142 */
+#define	SFF8636_SM_LEN_OFFSET		0x8E
+
+/* Length (OM3)-Unit 2m - 143 */
+#define	SFF8636_OM3_LEN_OFFSET		0x8F
+
+/* Length (OM2)-Unit 1m - 144 */
+#define	SFF8636_OM2_LEN_OFFSET		0x90
+
+/* Length (OM1)-Unit 1m - 145 */
+#define	SFF8636_OM1_LEN_OFFSET		0x91
+
+/* Cable Assembly Length -Unit 1m - 146 */
+#define	SFF8636_CBL_LEN_OFFSET		0x92
+
+/* Device Technology - 147 */
+#define	SFF8636_DEVICE_TECH_OFFSET	0x93
+/* Transmitter Technology */
+#define	 SFF8636_TRANS_TECH_MASK		0xF0
+/* Copper cable, linear active equalizers */
+#define	 SFF8636_TRANS_COPPER_LNR_EQUAL		(15 << 4)
+/* Copper cable, near end limiting active equalizers */
+#define	 SFF8636_TRANS_COPPER_NEAR_EQUAL	(14 << 4)
+/* Copper cable, far end limiting active equalizers */
+#define	 SFF8636_TRANS_COPPER_FAR_EQUAL		(13 << 4)
+/* Copper cable, near & far end limiting active equalizers */
+#define	 SFF8636_TRANS_COPPER_LNR_FAR_EQUAL	(12 << 4)
+/* Copper cable, passive equalized */
+#define	 SFF8636_TRANS_COPPER_PAS_EQUAL		(11 << 4)
+/* Copper cable, unequalized */
+#define	 SFF8636_TRANS_COPPER_PAS_UNEQUAL	(10 << 4)
+/* 1490 nm DFB */
+#define	 SFF8636_TRANS_1490_DFB			(9 << 4)
+/* Others */
+#define	 SFF8636_TRANS_OTHERS			(8 << 4)
+/* 1550 nm EML */
+#define	 SFF8636_TRANS_1550_EML			(7 << 4)
+/* 1310 nm EML */
+#define	 SFF8636_TRANS_1310_EML			(6 << 4)
+/* 1550 nm DFB */
+#define	 SFF8636_TRANS_1550_DFB			(5 << 4)
+/* 1310 nm DFB */
+#define	 SFF8636_TRANS_1310_DFB			(4 << 4)
+/* 1310 nm FP */
+#define	 SFF8636_TRANS_1310_FP			(3 << 4)
+/* 1550 nm VCSEL */
+#define	 SFF8636_TRANS_1550_VCSEL		(2 << 4)
+/* 1310 nm VCSEL */
+#define	 SFF8636_TRANS_1310_VCSEL		(1 << 4)
+/* 850 nm VCSEL */
+#define	 SFF8636_TRANS_850_VCSEL		(0 << 4)
+
+ /* Active/No wavelength control */
+#define	 SFF8636_DEV_TECH_ACTIVE_WAVE_LEN	(1 << 3)
+/* Cooled transmitter */
+#define	 SFF8636_DEV_TECH_COOL_TRANS		(1 << 2)
+/* APD/Pin Detector */
+#define	 SFF8636_DEV_TECH_APD_DETECTOR		(1 << 1)
+/* Transmitter tunable */
+#define	 SFF8636_DEV_TECH_TUNABLE		(1 << 0)
+
+/* Vendor Name - 148-163 */
+#define	 SFF8636_VENDOR_NAME_START_OFFSET	0x94
+#define	 SFF8636_VENDOR_NAME_END_OFFSET		0xA3
+
+/* Extended Module Codes - 164 */
+#define	 SFF8636_EXT_MOD_CODE_OFFSET	0xA4
+#define	  SFF8636_EXT_MOD_INFINIBAND_EDR	(1 << 4)
+#define	  SFF8636_EXT_MOD_INFINIBAND_FDR	(1 << 3)
+#define	  SFF8636_EXT_MOD_INFINIBAND_QDR	(1 << 2)
+#define	  SFF8636_EXT_MOD_INFINIBAND_DDR	(1 << 1)
+#define	  SFF8636_EXT_MOD_INFINIBAND_SDR	(1 << 0)
+
+/* Vendor OUI - 165-167 */
+#define	 SFF8636_VENDOR_OUI_OFFSET		0xA5
+#define	  SFF8636_VENDOR_OUI_LEN		3
+
+/* Vendor OUI - 165-167 */
+#define	 SFF8636_VENDOR_PN_START_OFFSET		0xA8
+#define	 SFF8636_VENDOR_PN_END_OFFSET		0xB7
+
+/* Vendor Revision - 184-185 */
+#define	 SFF8636_VENDOR_REV_START_OFFSET	0xB8
+#define	 SFF8636_VENDOR_REV_END_OFFSET		0xB9
+
+/* Wavelength - 186-187 */
+#define	 SFF8636_WAVELEN_HIGH_BYTE_OFFSET	0xBA
+#define	 SFF8636_WAVELEN_LOW_BYTE_OFFSET	0xBB
+
+/* Wavelength  Tolerance- 188-189 */
+#define	 SFF8636_WAVE_TOL_HIGH_BYTE_OFFSET	0xBC
+#define	 SFF8636_WAVE_TOL_LOW_BYTE_OFFSET	0xBD
+
+/* Max case temp - Other than 70 C - 190 */
+#define	 SFF8636_MAXCASE_TEMP_OFFSET	0xBE
+
+/* CC_BASE - 191 */
+#define	 SFF8636_CC_BASE_OFFSET		0xBF
+
+/* Option Values - 192-195 */
+#define	 SFF8636_OPTION_1_OFFSET	0xC0
+#define	 SFF8636_ETHERNET_UNSPECIFIED		0x00
+#define	 SFF8636_ETHERNET_100G_AOC		0x01
+#define	 SFF8636_ETHERNET_100G_SR4		0x02
+#define	 SFF8636_ETHERNET_100G_LR4		0x03
+#define	 SFF8636_ETHERNET_100G_ER4		0x04
+#define	 SFF8636_ETHERNET_100G_SR10		0x05
+#define	 SFF8636_ETHERNET_100G_CWDM4_FEC	0x06
+#define	 SFF8636_ETHERNET_100G_PSM4		0x07
+#define	 SFF8636_ETHERNET_100G_ACC		0x08
+#define	 SFF8636_ETHERNET_100G_CWDM4_NO_FEC	0x09
+#define	 SFF8636_ETHERNET_100G_RSVD1		0x0A
+#define	 SFF8636_ETHERNET_100G_CR4		0x0B
+#define	 SFF8636_ETHERNET_25G_CR_CA_S		0x0C
+#define	 SFF8636_ETHERNET_25G_CR_CA_N		0x0D
+#define	 SFF8636_ETHERNET_40G_ER4		0x10
+#define	 SFF8636_ETHERNET_4X10_SR		0x11
+#define	 SFF8636_ETHERNET_40G_PSM4		0x12
+#define	 SFF8636_ETHERNET_G959_P1I1_2D1		0x13
+#define	 SFF8636_ETHERNET_G959_P1S1_2D2		0x14
+#define	 SFF8636_ETHERNET_G959_P1L1_2D2		0x15
+#define	 SFF8636_ETHERNET_10GT_SFI		0x16
+#define	 SFF8636_ETHERNET_100G_CLR4		0x17
+#define	 SFF8636_ETHERNET_100G_AOC2		0x18
+#define	 SFF8636_ETHERNET_100G_ACC2		0x19
+
+#define	 SFF8636_OPTION_2_OFFSET	0xC1
+/* Rx output amplitude */
+#define	  SFF8636_O2_RX_OUTPUT_AMP	(1 << 0)
+#define	 SFF8636_OPTION_3_OFFSET	0xC2
+/* Rx Squelch Disable */
+#define	  SFF8636_O3_RX_SQL_DSBL	(1 << 3)
+/* Rx Output Disable capable */
+#define	  SFF8636_O3_RX_OUTPUT_DSBL	(1 << 2)
+/* Tx Squelch Disable */
+#define	  SFF8636_O3_TX_SQL_DSBL	(1 << 1)
+/* Tx Squelch Impl */
+#define	  SFF8636_O3_TX_SQL_IMPL	(1 << 0)
+#define	 SFF8636_OPTION_4_OFFSET	0xC3
+/* Memory Page 02 present */
+#define	  SFF8636_O4_PAGE_02_PRESENT	(1 << 7)
+/* Memory Page 01 present */
+#define	  SFF8636_O4_PAGE_01_PRESENT	(1 << 6)
+/* Rate Select implemented */
+#define	  SFF8636_O4_RATE_SELECT	(1 << 5)
+/* Tx_DISABLE implemented */
+#define	  SFF8636_O4_TX_DISABLE		(1 << 4)
+/* Tx_FAULT implemented */
+#define	  SFF8636_O4_TX_FAULT		(1 << 3)
+/* Tx Squelch implemented */
+#define	  SFF8636_O4_TX_SQUELCH		(1 << 2)
+/* Tx Loss of Signal */
+#define	  SFF8636_O4_TX_LOS		(1 << 1)
+
+/* Vendor SN - 196-211 */
+#define	 SFF8636_VENDOR_SN_START_OFFSET	0xC4
+#define	 SFF8636_VENDOR_SN_END_OFFSET	0xD3
+
+/* Vendor Date - 212-219 */
+#define	 SFF8636_DATE_YEAR_OFFSET	0xD4
+#define	  SFF8636_DATE_YEAR_LEN			2
+#define	 SFF8636_DATE_MONTH_OFFSET	0xD6
+#define	  SFF8636_DATE_MONTH_LEN		2
+#define	 SFF8636_DATE_DAY_OFFSET	0xD8
+#define	  SFF8636_DATE_DAY_LEN			2
+#define	 SFF8636_DATE_VENDOR_LOT_OFFSET 0xDA
+#define	  SFF8636_DATE_VENDOR_LOT_LEN		2
+
+/* Diagnostic Monitoring Type - 220 */
+#define	 SFF8636_DIAG_TYPE_OFFSET	0xDC
+#define	  SFF8636_RX_PWR_TYPE_MASK	0x8
+#define	   SFF8636_RX_PWR_TYPE_AVG_PWR	(1 << 3)
+#define	   SFF8636_RX_PWR_TYPE_OMA	(0 << 3)
+#define	  SFF8636_TX_PWR_TYPE_MASK	0x4
+#define	   SFF8636_TX_PWR_TYPE_AVG_PWR	(1 << 2)
+
+/* Enhanced Options - 221 */
+#define	 SFF8636_ENH_OPTIONS_OFFSET	0xDD
+#define	  SFF8636_RATE_SELECT_EXT_SUPPORT	(1 << 3)
+#define	  SFF8636_RATE_SELECT_APP_TABLE_SUPPORT	(1 << 2)
+
+/* Check code - 223 */
+#define	 SFF8636_CC_EXT_OFFSET		0xDF
+#define	  SFF8636_CC_EXT_LEN		1
+
+/*------------------------------------------------------------------------------
+ *
+ * Upper Memory Page 03h
+ * Contains module thresholds, channel thresholds and masks,
+ * and optional channel controls
+ *
+ * Offset - Page Num(3) * PageSize(0x80) + Page offset
+ */
+
+/* Module Thresholds (48 Bytes) 128-175 */
+/* MSB at low address, LSB at high address */
+#define	SFF8636_TEMP_HALRM		0x200
+#define	SFF8636_TEMP_LALRM		0x202
+#define	SFF8636_TEMP_HWARN		0x204
+#define	SFF8636_TEMP_LWARN		0x206
+
+#define	SFF8636_VCC_HALRM		0x210
+#define	SFF8636_VCC_LALRM		0x212
+#define	SFF8636_VCC_HWARN		0x214
+#define	SFF8636_VCC_LWARN		0x216
+
+#define	SFF8636_RX_PWR_HALRM		0x230
+#define	SFF8636_RX_PWR_LALRM		0x232
+#define	SFF8636_RX_PWR_HWARN		0x234
+#define	SFF8636_RX_PWR_LWARN		0x236
+
+#define	SFF8636_TX_BIAS_HALRM		0x238
+#define	SFF8636_TX_BIAS_LALRM		0x23A
+#define	SFF8636_TX_BIAS_HWARN		0x23C
+#define	SFF8636_TX_BIAS_LWARN		0x23E
+
+#define	SFF8636_TX_PWR_HALRM		0x240
+#define	SFF8636_TX_PWR_LALRM		0x242
+#define	SFF8636_TX_PWR_HWARN		0x244
+#define	SFF8636_TX_PWR_LWARN		0x246
+
+#define	ETH_MODULE_SFF_8636_MAX_LEN	640
+#define	ETH_MODULE_SFF_8436_MAX_LEN	640
+
+#endif /* QSFP_H__ */
diff --git a/realtek.c b/realtek.c
new file mode 100644
index 0000000..d10cfd4
--- /dev/null
+++ b/realtek.c
@@ -0,0 +1,689 @@
+/* Copyright 2001 Sun Microsystems (thockin@sun.com) */
+#include <stdio.h>
+#include <stdlib.h>
+#include "internal.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+enum chip_type {
+	RTL8139 = 1,
+	RTL8139_K,
+	RTL8139A,
+	RTL8139A_G,
+	RTL8139B,
+	RTL8130,
+	RTL8139C,
+	RTL8100,
+	RTL8100B_8139D,
+	RTL8139Cp,
+	RTL8101,
+
+	/* chips not handled by 8139too/8139cp module */
+	RTL_GIGA_MAC_VER_01,
+	RTL_GIGA_MAC_VER_02,
+	RTL_GIGA_MAC_VER_03,
+	RTL_GIGA_MAC_VER_04,
+	RTL_GIGA_MAC_VER_05,
+	RTL_GIGA_MAC_VER_06,
+	RTL_GIGA_MAC_VER_07,
+	RTL_GIGA_MAC_VER_08,
+	RTL_GIGA_MAC_VER_09,
+	RTL_GIGA_MAC_VER_10,
+	RTL_GIGA_MAC_VER_11,
+	RTL_GIGA_MAC_VER_12,
+	RTL_GIGA_MAC_VER_13,
+	RTL_GIGA_MAC_VER_14,
+	RTL_GIGA_MAC_VER_15,
+	RTL_GIGA_MAC_VER_16,
+	RTL_GIGA_MAC_VER_17,
+	RTL_GIGA_MAC_VER_18,
+	RTL_GIGA_MAC_VER_19,
+	RTL_GIGA_MAC_VER_20,
+	RTL_GIGA_MAC_VER_21,
+	RTL_GIGA_MAC_VER_22,
+	RTL_GIGA_MAC_VER_23,
+	RTL_GIGA_MAC_VER_24,
+	RTL_GIGA_MAC_VER_25,
+	RTL_GIGA_MAC_VER_26,
+	RTL_GIGA_MAC_VER_27,
+	RTL_GIGA_MAC_VER_28,
+	RTL_GIGA_MAC_VER_29,
+	RTL_GIGA_MAC_VER_30,
+	RTL_GIGA_MAC_VER_31,
+	RTL_GIGA_MAC_VER_32,
+	RTL_GIGA_MAC_VER_33,
+	RTL_GIGA_MAC_VER_34,
+	RTL_GIGA_MAC_VER_35,
+	RTL_GIGA_MAC_VER_36,
+	RTL_GIGA_MAC_VER_37,
+	RTL_GIGA_MAC_VER_38,
+	RTL_GIGA_MAC_VER_39,
+	RTL_GIGA_MAC_VER_40,
+	RTL_GIGA_MAC_VER_41,
+	RTL_GIGA_MAC_VER_42,
+	RTL_GIGA_MAC_VER_43,
+	RTL_GIGA_MAC_VER_44,
+};
+
+static const char * const chip_names[] = {
+	[RTL8139] =		"8139",
+	[RTL8139_K] =		"8139-K",
+	[RTL8139A] =		"8139A",
+	[RTL8139A_G] =		"8139A-G",
+	[RTL8139B] =		"8139B",
+	[RTL8130] =		"8130",
+	[RTL8139C] =		"8139C",
+	[RTL8100] =		"8100",
+	[RTL8100B_8139D] =	"8100B/8139D",
+	[RTL8139Cp] =		"8139C+",
+	[RTL8101] =		"8101",
+
+	/* chips not handled by 8139too/8139cp module */
+	[RTL_GIGA_MAC_VER_01] = "8169",
+	[RTL_GIGA_MAC_VER_02] = "8169s",
+	[RTL_GIGA_MAC_VER_03] = "8110s",
+	[RTL_GIGA_MAC_VER_04] = "8169sb/8110sb",
+	[RTL_GIGA_MAC_VER_05] = "8169sc/8110sc",
+	[RTL_GIGA_MAC_VER_06] = "8169sc/8110sc",
+	[RTL_GIGA_MAC_VER_07] = "8102e",
+	[RTL_GIGA_MAC_VER_08] = "8102e",
+	[RTL_GIGA_MAC_VER_09] = "8102e",
+	[RTL_GIGA_MAC_VER_10] = "8101e",
+	[RTL_GIGA_MAC_VER_11] = "8168b/8111b",
+	[RTL_GIGA_MAC_VER_12] = "8168b/8111b",
+	[RTL_GIGA_MAC_VER_13] = "8101e",
+	[RTL_GIGA_MAC_VER_14] = "8100e",
+	[RTL_GIGA_MAC_VER_15] = "8100e",
+	[RTL_GIGA_MAC_VER_16] = "8101e",
+	[RTL_GIGA_MAC_VER_17] = "8168b/8111b",
+	[RTL_GIGA_MAC_VER_18] = "8168cp/8111cp",
+	[RTL_GIGA_MAC_VER_19] = "8168c/8111c",
+	[RTL_GIGA_MAC_VER_20] = "8168c/8111c",
+	[RTL_GIGA_MAC_VER_21] = "8168c/8111c",
+	[RTL_GIGA_MAC_VER_22] = "8168c/8111c",
+	[RTL_GIGA_MAC_VER_23] = "8168cp/8111cp",
+	[RTL_GIGA_MAC_VER_24] = "8168cp/8111cp",
+	[RTL_GIGA_MAC_VER_25] = "8168d/8111d",
+	[RTL_GIGA_MAC_VER_26] = "8168d/8111d",
+	[RTL_GIGA_MAC_VER_27] = "8168dp/8111dp",
+	[RTL_GIGA_MAC_VER_28] = "8168dp/8111dp",
+	[RTL_GIGA_MAC_VER_29] = "8105e",
+	[RTL_GIGA_MAC_VER_30] = "8105e",
+	[RTL_GIGA_MAC_VER_31] = "8168dp/8111dp",
+	[RTL_GIGA_MAC_VER_32] = "8168e/8111e",
+	[RTL_GIGA_MAC_VER_33] = "8168e/8111e",
+	[RTL_GIGA_MAC_VER_34] = "8168evl/8111evl",
+	[RTL_GIGA_MAC_VER_35] = "8168f/8111f",
+	[RTL_GIGA_MAC_VER_36] = "8168f/8111f",
+	[RTL_GIGA_MAC_VER_37] = "8402",
+	[RTL_GIGA_MAC_VER_38] = "8411",
+	[RTL_GIGA_MAC_VER_39] = "8106e",
+	[RTL_GIGA_MAC_VER_40] = "8168g/8111g",
+	[RTL_GIGA_MAC_VER_41] = "8168g/8111g",
+	[RTL_GIGA_MAC_VER_42] = "8168g/8111g",
+	[RTL_GIGA_MAC_VER_43] = "8106e",
+	[RTL_GIGA_MAC_VER_44] = "8411",
+};
+
+static struct chip_info {
+	u32 id_mask;
+	u32 id_val;
+	int mac_version;
+} rtl_info_tbl[] = {
+	{ 0xfcc00000, 0x40000000,	RTL8139 },
+	{ 0xfcc00000, 0x60000000,	RTL8139_K },
+	{ 0xfcc00000, 0x70000000,	RTL8139A },
+	{ 0xfcc00000, 0x70800000,	RTL8139A_G },
+	{ 0xfcc00000, 0x78000000,	RTL8139B },
+	{ 0xfcc00000, 0x7c000000,	RTL8130 },
+	{ 0xfcc00000, 0x74000000,	RTL8139C },
+	{ 0xfcc00000, 0x78800000,	RTL8100 },
+	{ 0xfcc00000, 0x74400000,	RTL8100B_8139D },
+	{ 0xfcc00000, 0x74800000,	RTL8139Cp },
+	{ 0xfcc00000, 0x74c00000,	RTL8101 },
+
+	/* chips not handled by 8139too/8139cp module */
+	/* 8168G family. */
+	{ 0x7cf00000, 0x5c800000,	RTL_GIGA_MAC_VER_44 },
+	{ 0x7cf00000, 0x50900000,	RTL_GIGA_MAC_VER_42 },
+	{ 0x7cf00000, 0x4c100000,	RTL_GIGA_MAC_VER_41 },
+	{ 0x7cf00000, 0x4c000000,	RTL_GIGA_MAC_VER_40 },
+
+	/* 8168F family. */
+	{ 0x7c800000, 0x48800000,	RTL_GIGA_MAC_VER_38 },
+	{ 0x7cf00000, 0x48100000,	RTL_GIGA_MAC_VER_36 },
+	{ 0x7cf00000, 0x48000000,	RTL_GIGA_MAC_VER_35 },
+
+	/* 8168E family. */
+	{ 0x7c800000, 0x2c800000,	RTL_GIGA_MAC_VER_34 },
+	{ 0x7cf00000, 0x2c200000,	RTL_GIGA_MAC_VER_33 },
+	{ 0x7cf00000, 0x2c100000,	RTL_GIGA_MAC_VER_32 },
+	{ 0x7c800000, 0x2c000000,	RTL_GIGA_MAC_VER_33 },
+
+	/* 8168D family. */
+	{ 0x7cf00000, 0x28300000,	RTL_GIGA_MAC_VER_26 },
+	{ 0x7cf00000, 0x28100000,	RTL_GIGA_MAC_VER_25 },
+	{ 0x7c800000, 0x28000000,	RTL_GIGA_MAC_VER_26 },
+
+	/* 8168DP family. */
+	{ 0x7cf00000, 0x28800000,	RTL_GIGA_MAC_VER_27 },
+	{ 0x7cf00000, 0x28a00000,	RTL_GIGA_MAC_VER_28 },
+	{ 0x7cf00000, 0x28b00000,	RTL_GIGA_MAC_VER_31 },
+
+	/* 8168C family. */
+	{ 0x7cf00000, 0x3cb00000,	RTL_GIGA_MAC_VER_24 },
+	{ 0x7cf00000, 0x3c900000,	RTL_GIGA_MAC_VER_23 },
+	{ 0x7cf00000, 0x3c800000,	RTL_GIGA_MAC_VER_18 },
+	{ 0x7c800000, 0x3c800000,	RTL_GIGA_MAC_VER_24 },
+	{ 0x7cf00000, 0x3c000000,	RTL_GIGA_MAC_VER_19 },
+	{ 0x7cf00000, 0x3c200000,	RTL_GIGA_MAC_VER_20 },
+	{ 0x7cf00000, 0x3c300000,	RTL_GIGA_MAC_VER_21 },
+	{ 0x7cf00000, 0x3c400000,	RTL_GIGA_MAC_VER_22 },
+	{ 0x7c800000, 0x3c000000,	RTL_GIGA_MAC_VER_22 },
+
+	/* 8168B family. */
+	{ 0x7cf00000, 0x38000000,	RTL_GIGA_MAC_VER_12 },
+	{ 0x7cf00000, 0x38500000,	RTL_GIGA_MAC_VER_17 },
+	{ 0x7c800000, 0x38000000,	RTL_GIGA_MAC_VER_17 },
+	{ 0x7c800000, 0x30000000,	RTL_GIGA_MAC_VER_11 },
+
+	/* 8101 family. */
+	{ 0x7cf00000, 0x44900000,	RTL_GIGA_MAC_VER_39 },
+	{ 0x7c800000, 0x44800000,	RTL_GIGA_MAC_VER_39 },
+	{ 0x7c800000, 0x44000000,	RTL_GIGA_MAC_VER_37 },
+	{ 0x7cf00000, 0x40b00000,	RTL_GIGA_MAC_VER_30 },
+	{ 0x7cf00000, 0x40a00000,	RTL_GIGA_MAC_VER_30 },
+	{ 0x7cf00000, 0x40900000,	RTL_GIGA_MAC_VER_29 },
+	{ 0x7c800000, 0x40800000,	RTL_GIGA_MAC_VER_30 },
+	{ 0x7cf00000, 0x34a00000,	RTL_GIGA_MAC_VER_09 },
+	{ 0x7cf00000, 0x24a00000,	RTL_GIGA_MAC_VER_09 },
+	{ 0x7cf00000, 0x34900000,	RTL_GIGA_MAC_VER_08 },
+	{ 0x7cf00000, 0x24900000,	RTL_GIGA_MAC_VER_08 },
+	{ 0x7cf00000, 0x34800000,	RTL_GIGA_MAC_VER_07 },
+	{ 0x7cf00000, 0x24800000,	RTL_GIGA_MAC_VER_07 },
+	{ 0x7cf00000, 0x34000000,	RTL_GIGA_MAC_VER_13 },
+	{ 0x7cf00000, 0x34300000,	RTL_GIGA_MAC_VER_10 },
+	{ 0x7cf00000, 0x34200000,	RTL_GIGA_MAC_VER_16 },
+	{ 0x7c800000, 0x34800000,	RTL_GIGA_MAC_VER_09 },
+	{ 0x7c800000, 0x24800000,	RTL_GIGA_MAC_VER_09 },
+	{ 0x7c800000, 0x34000000,	RTL_GIGA_MAC_VER_16 },
+	/* FIXME: where did these entries come from ? -- FR */
+	{ 0xfc800000, 0x38800000,	RTL_GIGA_MAC_VER_15 },
+	{ 0xfc800000, 0x30800000,	RTL_GIGA_MAC_VER_14 },
+
+	/* 8110 family. */
+	{ 0xfc800000, 0x98000000,	RTL_GIGA_MAC_VER_06 },
+	{ 0xfc800000, 0x18000000,	RTL_GIGA_MAC_VER_05 },
+	{ 0xfc800000, 0x10000000,	RTL_GIGA_MAC_VER_04 },
+	{ 0xfc800000, 0x04000000,	RTL_GIGA_MAC_VER_03 },
+	{ 0xfc800000, 0x00800000,	RTL_GIGA_MAC_VER_02 },
+	{ 0xfc800000, 0x00000000,	RTL_GIGA_MAC_VER_01 },
+
+	{ }
+};
+
+static void
+print_intr_bits(u16 mask)
+{
+	fprintf(stdout,
+		"      %s%s%s%s%s%s%s%s%s%s%s\n",
+		mask & (1 << 15)	? "SERR " : "",
+		mask & (1 << 14)	? "TimeOut " : "",
+		mask & (1 << 8)		? "SWInt " : "",
+		mask & (1 << 7)		? "TxNoBuf " : "",
+		mask & (1 << 6)		? "RxFIFO " : "",
+		mask & (1 << 5)		? "LinkChg " : "",
+		mask & (1 << 4)		? "RxNoBuf " : "",
+		mask & (1 << 3)		? "TxErr " : "",
+		mask & (1 << 2)		? "TxOK " : "",
+		mask & (1 << 1)		? "RxErr " : "",
+		mask & (1 << 0)		? "RxOK " : "");
+}
+
+int
+realtek_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		  struct ethtool_regs *regs)
+{
+	u32 *data = (u32 *) regs->data;
+	u8 *data8 = (u8 *) regs->data;
+	u32 v;
+	struct chip_info *ci;
+	unsigned int board_type;
+
+	v = data[0x40 >> 2]; /* TxConfig */
+
+	ci = &rtl_info_tbl[0];
+	while (ci->mac_version) {
+		if ((v & ci->id_mask) == ci->id_val)
+			break;
+		ci++;
+	}
+	board_type = ci->mac_version;
+	if (!board_type) {
+		fprintf(stderr, "Unknown RealTek chip (TxConfig: 0x%08x)\n", v);
+		return 91;
+	}
+
+	fprintf(stdout,
+		"RealTek RTL%s registers:\n"
+		"--------------------------------------------------------\n",
+		chip_names[board_type]);
+
+	fprintf(stdout,
+		"0x00: MAC Address                      %02x:%02x:%02x:%02x:%02x:%02x\n",
+		data8[0x00],
+		data8[0x01],
+		data8[0x02],
+		data8[0x03],
+		data8[0x04],
+		data8[0x05]);
+
+	fprintf(stdout,
+		"0x08: Multicast Address Filter     0x%08x 0x%08x\n",
+		data[0x08 >> 2],
+		data[0x0c >> 2]);
+
+	if (board_type == RTL8139Cp || board_type >= RTL_GIGA_MAC_VER_01) {
+	fprintf(stdout,
+		"0x10: Dump Tally Counter Command   0x%08x 0x%08x\n",
+		data[0x10 >> 2],
+		data[0x14 >> 2]);
+
+	fprintf(stdout,
+		"0x20: Tx Normal Priority Ring Addr 0x%08x 0x%08x\n",
+		data[0x20 >> 2],
+		data[0x24 >> 2]);
+
+	fprintf(stdout,
+		"0x28: Tx High Priority Ring Addr   0x%08x 0x%08x\n",
+		data[0x28 >> 2],
+		data[0x2C >> 2]);
+	} else {
+	fprintf(stdout,
+		"0x10: Transmit Status Desc 0                  0x%08x\n"
+		"0x14: Transmit Status Desc 1                  0x%08x\n"
+		"0x18: Transmit Status Desc 2                  0x%08x\n"
+		"0x1C: Transmit Status Desc 3                  0x%08x\n",
+		data[0x10 >> 2],
+		data[0x14 >> 2],
+		data[0x18 >> 2],
+		data[0x1C >> 2]);
+	fprintf(stdout,
+		"0x20: Transmit Start Addr  0                  0x%08x\n"
+		"0x24: Transmit Start Addr  1                  0x%08x\n"
+		"0x28: Transmit Start Addr  2                  0x%08x\n"
+		"0x2C: Transmit Start Addr  3                  0x%08x\n",
+		data[0x20 >> 2],
+		data[0x24 >> 2],
+		data[0x28 >> 2],
+		data[0x2C >> 2]);
+	}
+
+	if (board_type < RTL_GIGA_MAC_VER_11 ||
+		board_type > RTL_GIGA_MAC_VER_17) {
+	if (board_type >= RTL_GIGA_MAC_VER_01) {
+	fprintf(stdout,
+		"0x30: Flash memory read/write                 0x%08x\n",
+		data[0x30 >> 2]);
+	} else {
+	fprintf(stdout,
+		"0x30: Rx buffer addr (C mode)                 0x%08x\n",
+		data[0x30 >> 2]);
+	}
+	}
+
+	v = data8[0x36];
+	fprintf(stdout,
+		"0x34: Early Rx Byte Count                       %8u\n"
+		"0x36: Early Rx Status                               0x%02x\n",
+		data[0x34 >> 2] & 0xffff,
+		v);
+
+	if (v & 0xf) {
+	fprintf(stdout,
+		"      %s%s%s%s\n",
+		v & (1 << 3) ? "ERxGood " : "",
+		v & (1 << 2) ? "ERxBad " : "",
+		v & (1 << 1) ? "ERxOverWrite " : "",
+		v & (1 << 0) ? "ERxOK " : "");
+	}
+
+	v = data8[0x37];
+	fprintf(stdout,
+		"0x37: Command                                       0x%02x\n"
+		"      Rx %s, Tx %s%s\n",
+		data8[0x37],
+		v & (1 << 3) ? "on" : "off",
+		v & (1 << 2) ? "on" : "off",
+		v & (1 << 4) ? ", RESET" : "");
+
+	if (board_type < RTL_GIGA_MAC_VER_01) {
+	fprintf(stdout,
+		"0x38: Current Address of Packet Read (C mode)     0x%04x\n"
+		"0x3A: Current Rx buffer address (C mode)          0x%04x\n",
+		data[0x38 >> 2] & 0xffff,
+		data[0x38 >> 2] >> 16);
+	}
+
+	fprintf(stdout,
+		"0x3C: Interrupt Mask                              0x%04x\n",
+		data[0x3c >> 2] & 0xffff);
+	print_intr_bits(data[0x3c >> 2] & 0xffff);
+	fprintf(stdout,
+		"0x3E: Interrupt Status                            0x%04x\n",
+		data[0x3c >> 2] >> 16);
+	print_intr_bits(data[0x3c >> 2] >> 16);
+
+	fprintf(stdout,
+		"0x40: Tx Configuration                        0x%08x\n"
+		"0x44: Rx Configuration                        0x%08x\n"
+		"0x48: Timer count                             0x%08x\n"
+		"0x4C: Missed packet counter                     0x%06x\n",
+		data[0x40 >> 2],
+		data[0x44 >> 2],
+		data[0x48 >> 2],
+		data[0x4C >> 2] & 0xffffff);
+
+	fprintf(stdout,
+		"0x50: EEPROM Command                                0x%02x\n"
+		"0x51: Config 0                                      0x%02x\n"
+		"0x52: Config 1                                      0x%02x\n",
+		data8[0x50],
+		data8[0x51],
+		data8[0x52]);
+
+	if (board_type >= RTL_GIGA_MAC_VER_01) {
+	fprintf(stdout,
+		"0x53: Config 2                                      0x%02x\n"
+		"0x54: Config 3                                      0x%02x\n"
+		"0x55: Config 4                                      0x%02x\n"
+		"0x56: Config 5                                      0x%02x\n",
+		data8[0x53],
+		data8[0x54],
+		data8[0x55],
+		data8[0x56]);
+	fprintf(stdout,
+		"0x58: Timer interrupt                         0x%08x\n",
+		data[0x58 >> 2]);
+	}
+	else {
+	if (board_type >= RTL8139A) {
+	fprintf(stdout,
+		"0x54: Timer interrupt                         0x%08x\n",
+		data[0x54 >> 2]);
+	}
+	fprintf(stdout,
+		"0x58: Media status                                  0x%02x\n",
+		data8[0x58]);
+	if (board_type >= RTL8139A) {
+	fprintf(stdout,
+		"0x59: Config 3                                      0x%02x\n",
+		data8[0x59]);
+	}
+	if (board_type >= RTL8139B) {
+	fprintf(stdout,
+		"0x5A: Config 4                                      0x%02x\n",
+		data8[0x5A]);
+	}
+	}
+
+	fprintf(stdout,
+		"0x5C: Multiple Interrupt Select                   0x%04x\n",
+		data[0x5c >> 2] & 0xffff);
+
+	if (board_type >= RTL_GIGA_MAC_VER_01) {
+	fprintf(stdout,
+		"0x60: PHY access                              0x%08x\n",
+		data[0x60 >> 2]);
+
+	if (board_type < RTL_GIGA_MAC_VER_11 ||
+		board_type > RTL_GIGA_MAC_VER_17) {
+	fprintf(stdout,
+		"0x64: TBI control and status                  0x%08x\n",
+		data[0x64 >> 2]);
+	fprintf(stdout,
+		"0x68: TBI Autonegotiation advertisement (ANAR)    0x%04x\n"
+		"0x6A: TBI Link partner ability (LPAR)             0x%04x\n",
+		data[0x68 >> 2] & 0xffff,
+		data[0x68 >> 2] >> 16);
+	}
+
+	fprintf(stdout,
+		"0x6C: PHY status                                    0x%02x\n",
+		data8[0x6C]);
+
+	fprintf(stdout,
+		"0x84: PM wakeup frame 0            0x%08x 0x%08x\n"
+		"0x8C: PM wakeup frame 1            0x%08x 0x%08x\n",
+		data[0x84 >> 2],
+		data[0x88 >> 2],
+		data[0x8C >> 2],
+		data[0x90 >> 2]);
+
+	fprintf(stdout,
+		"0x94: PM wakeup frame 2 (low)      0x%08x 0x%08x\n"
+		"0x9C: PM wakeup frame 2 (high)     0x%08x 0x%08x\n",
+		data[0x94 >> 2],
+		data[0x98 >> 2],
+		data[0x9C >> 2],
+		data[0xA0 >> 2]);
+
+	fprintf(stdout,
+		"0xA4: PM wakeup frame 3 (low)      0x%08x 0x%08x\n"
+		"0xAC: PM wakeup frame 3 (high)     0x%08x 0x%08x\n",
+		data[0xA4 >> 2],
+		data[0xA8 >> 2],
+		data[0xAC >> 2],
+		data[0xB0 >> 2]);
+
+	fprintf(stdout,
+		"0xB4: PM wakeup frame 4 (low)      0x%08x 0x%08x\n"
+		"0xBC: PM wakeup frame 4 (high)     0x%08x 0x%08x\n",
+		data[0xB4 >> 2],
+		data[0xB8 >> 2],
+		data[0xBC >> 2],
+		data[0xC0 >> 2]);
+
+	fprintf(stdout,
+		"0xC4: Wakeup frame 0 CRC                          0x%04x\n"
+		"0xC6: Wakeup frame 1 CRC                          0x%04x\n"
+		"0xC8: Wakeup frame 2 CRC                          0x%04x\n"
+		"0xCA: Wakeup frame 3 CRC                          0x%04x\n"
+		"0xCC: Wakeup frame 4 CRC                          0x%04x\n",
+		data[0xC4 >> 2] & 0xffff,
+		data[0xC4 >> 2] >> 16,
+		data[0xC8 >> 2] & 0xffff,
+		data[0xC8 >> 2] >> 16,
+		data[0xCC >> 2] & 0xffff);
+	fprintf(stdout,
+		"0xDA: RX packet maximum size                      0x%04x\n",
+		data[0xD8 >> 2] >> 16);
+	}
+	else {
+	fprintf(stdout,
+		"0x5E: PCI revision id                               0x%02x\n",
+		data8[0x5e]);
+	fprintf(stdout,
+		"0x60: Transmit Status of All Desc (C mode)        0x%04x\n"
+		"0x62: MII Basic Mode Control Register             0x%04x\n",
+		data[0x60 >> 2] & 0xffff,
+		data[0x60 >> 2] >> 16);
+	fprintf(stdout,
+		"0x64: MII Basic Mode Status Register              0x%04x\n"
+		"0x66: MII Autonegotiation Advertising             0x%04x\n",
+		data[0x64 >> 2] & 0xffff,
+		data[0x64 >> 2] >> 16);
+	fprintf(stdout,
+		"0x68: MII Link Partner Ability                    0x%04x\n"
+		"0x6A: MII Expansion                               0x%04x\n",
+		data[0x68 >> 2] & 0xffff,
+		data[0x68 >> 2] >> 16);
+	fprintf(stdout,
+		"0x6C: MII Disconnect counter                      0x%04x\n"
+		"0x6E: MII False carrier sense counter             0x%04x\n",
+		data[0x6C >> 2] & 0xffff,
+		data[0x6C >> 2] >> 16);
+	fprintf(stdout,
+		"0x70: MII Nway test                               0x%04x\n"
+		"0x72: MII RX_ER counter                           0x%04x\n",
+		data[0x70 >> 2] & 0xffff,
+		data[0x70 >> 2] >> 16);
+	fprintf(stdout,
+		"0x74: MII CS configuration                        0x%04x\n",
+		data[0x74 >> 2] & 0xffff);
+	if (board_type >= RTL8139_K) {
+	fprintf(stdout,
+		"0x78: PHY parameter 1                         0x%08x\n"
+		"0x7C: Twister parameter                       0x%08x\n",
+		data[0x78 >> 2],
+		data[0x7C >> 2]);
+	if (board_type >= RTL8139A) {
+	fprintf(stdout,
+		"0x80: PHY parameter 2                               0x%02x\n",
+		data8[0x80]);
+	}
+	}
+	if (board_type == RTL8139Cp) {
+	fprintf(stdout,
+		"0x82: Low addr of a Tx Desc w/ Tx DMA OK          0x%04x\n",
+		data[0x80 >> 2] >> 16);
+	} else if (board_type == RTL8130) {
+	fprintf(stdout,
+		"0x82: MII register                                  0x%02x\n",
+		data8[0x82]);
+	}
+	if (board_type >= RTL8139A) {
+	fprintf(stdout,
+		"0x84: PM CRC for wakeup frame 0                     0x%02x\n"
+		"0x85: PM CRC for wakeup frame 1                     0x%02x\n"
+		"0x86: PM CRC for wakeup frame 2                     0x%02x\n"
+		"0x87: PM CRC for wakeup frame 3                     0x%02x\n"
+		"0x88: PM CRC for wakeup frame 4                     0x%02x\n"
+		"0x89: PM CRC for wakeup frame 5                     0x%02x\n"
+		"0x8A: PM CRC for wakeup frame 6                     0x%02x\n"
+		"0x8B: PM CRC for wakeup frame 7                     0x%02x\n",
+		data8[0x84],
+		data8[0x85],
+		data8[0x86],
+		data8[0x87],
+		data8[0x88],
+		data8[0x89],
+		data8[0x8A],
+		data8[0x8B]);
+	fprintf(stdout,
+		"0x8C: PM wakeup frame 0            0x%08x 0x%08x\n"
+		"0x94: PM wakeup frame 1            0x%08x 0x%08x\n"
+		"0x9C: PM wakeup frame 2            0x%08x 0x%08x\n"
+		"0xA4: PM wakeup frame 3            0x%08x 0x%08x\n"
+		"0xAC: PM wakeup frame 4            0x%08x 0x%08x\n"
+		"0xB4: PM wakeup frame 5            0x%08x 0x%08x\n"
+		"0xBC: PM wakeup frame 6            0x%08x 0x%08x\n"
+		"0xC4: PM wakeup frame 7            0x%08x 0x%08x\n",
+		data[0x8C >> 2],
+		data[0x90 >> 2],
+		data[0x94 >> 2],
+		data[0x98 >> 2],
+		data[0x9C >> 2],
+		data[0xA0 >> 2],
+		data[0xA4 >> 2],
+		data[0xA8 >> 2],
+		data[0xAC >> 2],
+		data[0xB0 >> 2],
+		data[0xB4 >> 2],
+		data[0xB8 >> 2],
+		data[0xBC >> 2],
+		data[0xC0 >> 2],
+		data[0xC4 >> 2],
+		data[0xC8 >> 2]);
+	fprintf(stdout,
+		"0xCC: PM LSB CRC for wakeup frame 0                 0x%02x\n"
+		"0xCD: PM LSB CRC for wakeup frame 1                 0x%02x\n"
+		"0xCE: PM LSB CRC for wakeup frame 2                 0x%02x\n"
+		"0xCF: PM LSB CRC for wakeup frame 3                 0x%02x\n"
+		"0xD0: PM LSB CRC for wakeup frame 4                 0x%02x\n"
+		"0xD1: PM LSB CRC for wakeup frame 5                 0x%02x\n"
+		"0xD2: PM LSB CRC for wakeup frame 6                 0x%02x\n"
+		"0xD3: PM LSB CRC for wakeup frame 7                 0x%02x\n",
+		data8[0xCC],
+		data8[0xCD],
+		data8[0xCE],
+		data8[0xCF],
+		data8[0xD0],
+		data8[0xD1],
+		data8[0xD2],
+		data8[0xD3]);
+	}
+	if (board_type >= RTL8139B) {
+	if (board_type != RTL8100 && board_type != RTL8100B_8139D &&
+	    board_type != RTL8101)
+	fprintf(stdout,
+		"0xD4: Flash memory read/write                 0x%08x\n",
+		data[0xD4 >> 2]);
+	if (board_type != RTL8130)
+	fprintf(stdout,
+		"0xD8: Config 5                                      0x%02x\n",
+		data8[0xD8]);
+	}
+	}
+
+	if (board_type == RTL8139Cp || board_type >= RTL_GIGA_MAC_VER_01) {
+	v = data[0xE0 >> 2] & 0xffff;
+	fprintf(stdout,
+		"0xE0: C+ Command                                  0x%04x\n",
+		v);
+	if (v & (1 << 9))
+		fprintf(stdout, "      Big-endian mode\n");
+	if (v & (1 << 8))
+		fprintf(stdout, "      Home LAN enable\n");
+	if (v & (1 << 6))
+		fprintf(stdout, "      VLAN de-tagging\n");
+	if (v & (1 << 5))
+		fprintf(stdout, "      RX checksumming\n");
+	if (v & (1 << 4))
+		fprintf(stdout, "      PCI 64-bit DAC\n");
+	if (v & (1 << 3))
+		fprintf(stdout, "      PCI Multiple RW\n");
+
+	v = data[0xe0 >> 2] >> 16;
+	fprintf(stdout,
+		"0xE2: Interrupt Mitigation                        0x%04x\n"
+		"      TxTimer:       %u\n"
+		"      TxPackets:     %u\n"
+		"      RxTimer:       %u\n"
+		"      RxPackets:     %u\n",
+		v,
+		v >> 12,
+		(v >> 8) & 0xf,
+		(v >> 4) & 0xf,
+		v & 0xf);
+
+	fprintf(stdout,
+		"0xE4: Rx Ring Addr                 0x%08x 0x%08x\n",
+		data[0xE4 >> 2],
+		data[0xE8 >> 2]);
+
+	fprintf(stdout,
+		"0xEC: Early Tx threshold                            0x%02x\n",
+		data8[0xEC]);
+
+	if (board_type == RTL8139Cp) {
+	fprintf(stdout,
+		"0xFC: External MII register                   0x%08x\n",
+		data[0xFC >> 2]);
+	} else if (board_type >= RTL_GIGA_MAC_VER_01 &&
+		(board_type < RTL_GIGA_MAC_VER_11 ||
+		board_type > RTL_GIGA_MAC_VER_17)) {
+	fprintf(stdout,
+		"0xF0: Func Event                              0x%08x\n"
+		"0xF4: Func Event Mask                         0x%08x\n"
+		"0xF8: Func Preset State                       0x%08x\n"
+		"0xFC: Func Force Event                        0x%08x\n",
+		data[0xF0 >> 2],
+		data[0xF4 >> 2],
+		data[0xF8 >> 2],
+		data[0xFC >> 2]);
+	}
+	}
+
+	return 0;
+}
diff --git a/rxclass.c b/rxclass.c
new file mode 100644
index 0000000..7997265
--- /dev/null
+++ b/rxclass.c
@@ -0,0 +1,1457 @@
+/*
+ * 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 "internal.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_ipv6_rule(__be32 *sip, __be32 *sipm, __be32 *dip,
+				    __be32 *dipm, u8 tclass, u8 tclassm)
+{
+	char sip_str[INET6_ADDRSTRLEN];
+	char sipm_str[INET6_ADDRSTRLEN];
+	char dip_str[INET6_ADDRSTRLEN];
+	char dipm_str[INET6_ADDRSTRLEN];
+
+	fprintf(stdout,
+		"\tSrc IP addr: %s mask: %s\n"
+		"\tDest IP addr: %s mask: %s\n"
+		"\tTraffic Class: 0x%x mask: 0x%x\n",
+		inet_ntop(AF_INET6, sip, sip_str, INET6_ADDRSTRLEN),
+		inet_ntop(AF_INET6, sipm, sipm_str, INET6_ADDRSTRLEN),
+		inet_ntop(AF_INET6, dip, dip_str, INET6_ADDRSTRLEN),
+		inet_ntop(AF_INET6, dipm, dipm_str, INET6_ADDRSTRLEN),
+		tclass, tclassm);
+}
+
+static void rxclass_print_nfc_spec_ext(struct ethtool_rx_flow_spec *fsp)
+{
+	if (fsp->flow_type & FLOW_EXT) {
+		u64 data, datam;
+		__u16 etype, etypem, tci, tcim;
+		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);
+	}
+
+	if (fsp->flow_type & FLOW_MAC_EXT) {
+		unsigned char *dmac, *dmacm;
+
+		dmac = fsp->h_ext.h_dest;
+		dmacm = fsp->m_ext.h_dest;
+
+		fprintf(stdout,
+			"\tDest MAC addr: %02X:%02X:%02X:%02X:%02X:%02X"
+			" mask: %02X:%02X:%02X:%02X:%02X:%02X\n",
+			dmac[0], dmac[1], dmac[2], dmac[3], dmac[4],
+			dmac[5], dmacm[0], dmacm[1], dmacm[2], dmacm[3],
+			dmacm[4], dmacm[5]);
+	}
+}
+
+static void rxclass_print_nfc_rule(struct ethtool_rx_flow_spec *fsp,
+				   __u32 rss_context)
+{
+	unsigned char	*smac, *smacm, *dmac, *dmacm;
+	__u32		flow_type;
+
+	fprintf(stdout,	"Filter: %d\n", fsp->location);
+
+	flow_type = fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
+
+	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 IPV4_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 TCP_V6_FLOW:
+	case UDP_V6_FLOW:
+	case SCTP_V6_FLOW:
+		if (flow_type == TCP_V6_FLOW)
+			fprintf(stdout, "\tRule Type: TCP over IPv6\n");
+		else if (flow_type == UDP_V6_FLOW)
+			fprintf(stdout, "\tRule Type: UDP over IPv6\n");
+		else
+			fprintf(stdout, "\tRule Type: SCTP over IPv6\n");
+		rxclass_print_ipv6_rule(fsp->h_u.tcp_ip6_spec.ip6src,
+				     fsp->m_u.tcp_ip6_spec.ip6src,
+				     fsp->h_u.tcp_ip6_spec.ip6dst,
+				     fsp->m_u.tcp_ip6_spec.ip6dst,
+				     fsp->h_u.tcp_ip6_spec.tclass,
+				     fsp->m_u.tcp_ip6_spec.tclass);
+		fprintf(stdout,
+			"\tSrc port: %d mask: 0x%x\n"
+			"\tDest port: %d mask: 0x%x\n",
+			ntohs(fsp->h_u.tcp_ip6_spec.psrc),
+			ntohs(fsp->m_u.tcp_ip6_spec.psrc),
+			ntohs(fsp->h_u.tcp_ip6_spec.pdst),
+			ntohs(fsp->m_u.tcp_ip6_spec.pdst));
+		break;
+	case AH_V6_FLOW:
+	case ESP_V6_FLOW:
+		if (flow_type == AH_V6_FLOW)
+			fprintf(stdout, "\tRule Type: IPSEC AH over IPv6\n");
+		else
+			fprintf(stdout, "\tRule Type: IPSEC ESP over IPv6\n");
+		rxclass_print_ipv6_rule(fsp->h_u.ah_ip6_spec.ip6src,
+				     fsp->m_u.ah_ip6_spec.ip6src,
+				     fsp->h_u.ah_ip6_spec.ip6dst,
+				     fsp->m_u.ah_ip6_spec.ip6dst,
+				     fsp->h_u.ah_ip6_spec.tclass,
+				     fsp->m_u.ah_ip6_spec.tclass);
+		fprintf(stdout,
+			"\tSPI: %d mask: 0x%x\n",
+			ntohl(fsp->h_u.esp_ip6_spec.spi),
+			ntohl(fsp->m_u.esp_ip6_spec.spi));
+		break;
+	case IPV6_USER_FLOW:
+		fprintf(stdout, "\tRule Type: Raw IPv6\n");
+		rxclass_print_ipv6_rule(fsp->h_u.usr_ip6_spec.ip6src,
+				     fsp->m_u.usr_ip6_spec.ip6src,
+				     fsp->h_u.usr_ip6_spec.ip6dst,
+				     fsp->m_u.usr_ip6_spec.ip6dst,
+				     fsp->h_u.usr_ip6_spec.tclass,
+				     fsp->m_u.usr_ip6_spec.tclass);
+		fprintf(stdout,
+			"\tProtocol: %d mask: 0x%x\n"
+			"\tL4 bytes: 0x%x mask: 0x%x\n",
+			fsp->h_u.usr_ip6_spec.l4_proto,
+			fsp->m_u.usr_ip6_spec.l4_proto,
+			ntohl(fsp->h_u.usr_ip6_spec.l4_4_bytes),
+			ntohl(fsp->m_u.usr_ip6_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->flow_type & FLOW_RSS)
+		fprintf(stdout, "\tRSS Context ID: %u\n", rss_context);
+
+	if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
+		fprintf(stdout, "\tAction: Drop\n");
+	} else if (fsp->ring_cookie == RX_CLS_FLOW_WAKE) {
+		fprintf(stdout, "\tAction: Wake-on-LAN\n");
+	} else {
+		u64 vf = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie);
+		u64 queue = ethtool_get_flow_spec_ring(fsp->ring_cookie);
+
+		/* A value of zero indicates that this rule targeted the main
+		 * function. A positive value indicates which virtual function
+		 * was targeted, so we'll subtract 1 in order to show the
+		 * correct VF index
+		 */
+		if (vf)
+			fprintf(stdout, "\tAction: Direct to VF %llu queue %llu\n",
+				vf - 1, queue);
+		else
+			fprintf(stdout, "\tAction: Direct to queue %llu\n",
+				queue);
+	}
+
+	fprintf(stdout, "\n");
+}
+
+static void rxclass_print_rule(struct ethtool_rx_flow_spec *fsp,
+			       __u32 rss_context)
+{
+	/* print the rule in this location */
+	switch (fsp->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS)) {
+	case TCP_V4_FLOW:
+	case UDP_V4_FLOW:
+	case SCTP_V4_FLOW:
+	case AH_V4_FLOW:
+	case ESP_V4_FLOW:
+	case TCP_V6_FLOW:
+	case UDP_V6_FLOW:
+	case SCTP_V6_FLOW:
+	case AH_V6_FLOW:
+	case ESP_V6_FLOW:
+	case IPV6_USER_FLOW:
+	case ETHER_FLOW:
+		rxclass_print_nfc_rule(fsp, rss_context);
+		break;
+	case IPV4_USER_FLOW:
+		if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4)
+			rxclass_print_nfc_rule(fsp, rss_context);
+		else /* IPv6 uses IPV6_USER_FLOW */
+			fprintf(stderr, "IPV4_USER_FLOW with wrong ip_ver\n");
+		break;
+	default:
+		fprintf(stderr, "rxclass: Unknown flow type\n");
+		break;
+	}
+}
+
+static int rxclass_get_dev_info(struct cmd_context *ctx, __u32 *count,
+				int *driver_select)
+{
+	struct ethtool_rxnfc nfccmd;
+	int err;
+
+	nfccmd.cmd = ETHTOOL_GRXCLSRLCNT;
+	nfccmd.data = 0;
+	err = send_ioctl(ctx, &nfccmd);
+	*count = nfccmd.rule_cnt;
+	if (driver_select)
+		*driver_select = !!(nfccmd.data & RX_CLS_LOC_SPECIAL);
+	if (err < 0)
+		perror("rxclass: Cannot get RX class rule count");
+
+	return err;
+}
+
+int rxclass_rule_get(struct cmd_context *ctx, __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;
+	err = send_ioctl(ctx, &nfccmd);
+	if (err < 0) {
+		perror("rxclass: Cannot get RX class rule");
+		return err;
+	}
+
+	/* display rule */
+	rxclass_print_rule(&nfccmd.fs, (__u32)nfccmd.rss_context);
+	return err;
+}
+
+int rxclass_rule_getall(struct cmd_context *ctx)
+{
+	struct ethtool_rxnfc *nfccmd;
+	__u32 *rule_locs;
+	int err, i;
+	__u32 count;
+
+	/* determine rule count */
+	err = rxclass_get_dev_info(ctx, &count, NULL);
+	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;
+	err = send_ioctl(ctx, nfccmd);
+	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(ctx, 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 {
+	/* flag for device/driver that can select locations itself */
+	int			driver_select;
+	/* slot contains a bitmap indicating which filters are valid */
+	unsigned long		*slot;
+	__u32			n_rules;
+	__u32			size;
+};
+
+static int rmgr_ins(struct rmgr_ctrl *rmgr, __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 rmgr_ctrl *rmgr,
+				struct ethtool_rx_flow_spec *fsp)
+{
+	__u32 loc;
+	__u32 slot_num;
+
+	/* leave this to the driver if possible */
+	if (rmgr->driver_select)
+		return 0;
+
+	/* 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(rmgr, loc);
+	}
+
+	/* No space to add this rule */
+	fprintf(stderr, "rmgr: Cannot find appropriate slot to insert rule\n");
+
+	return -1;
+}
+
+static int rmgr_init(struct cmd_context *ctx, struct rmgr_ctrl *rmgr)
+{
+	struct ethtool_rxnfc *nfccmd;
+	int err, i;
+	__u32 *rule_locs;
+
+	/* clear rule manager settings */
+	memset(rmgr, 0, sizeof(*rmgr));
+
+	/* request device/driver information */
+	err = rxclass_get_dev_info(ctx, &rmgr->n_rules, &rmgr->driver_select);
+	if (err < 0)
+		return err;
+
+	/* do not get the table if the device/driver can select locations */
+	if (rmgr->driver_select)
+		return 0;
+
+	/* 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;
+	err = send_ioctl(ctx, nfccmd);
+	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(rmgr, rule_locs[i]);
+		if (err < 0)
+			break;
+	}
+
+	free(nfccmd);
+
+	return err;
+}
+
+static void rmgr_cleanup(struct rmgr_ctrl *rmgr)
+{
+	free(rmgr->slot);
+	rmgr->slot = NULL;
+	rmgr->size = 0;
+}
+
+static int rmgr_set_location(struct cmd_context *ctx,
+			     struct ethtool_rx_flow_spec *fsp)
+{
+	struct rmgr_ctrl rmgr;
+	int err;
+
+	/* init table of available rules */
+	err = rmgr_init(ctx, &rmgr);
+	if (err < 0)
+		goto out;
+
+	/* verify rule location */
+	err = rmgr_find_empty_slot(&rmgr, fsp);
+
+out:
+	/* cleanup table and free resources */
+	rmgr_cleanup(&rmgr);
+
+	return err;
+}
+
+int rxclass_rule_ins(struct cmd_context *ctx,
+		     struct ethtool_rx_flow_spec *fsp, __u32 rss_context)
+{
+	struct ethtool_rxnfc nfccmd;
+	__u32 loc = fsp->location;
+	int err;
+
+	/*
+	 * if location is unspecified and driver cannot select locations, pull
+	 * rules from device and allocate a free rule for our use
+	 */
+	if (loc & RX_CLS_LOC_SPECIAL) {
+		err = rmgr_set_location(ctx, fsp);
+		if (err < 0)
+			return err;
+	}
+
+	/* notify netdev of new rule */
+	nfccmd.cmd = ETHTOOL_SRXCLSRLINS;
+	nfccmd.rss_context = rss_context;
+	nfccmd.fs = *fsp;
+	err = send_ioctl(ctx, &nfccmd);
+	if (err < 0)
+		perror("rmgr: Cannot insert RX class rule");
+	else if (loc & RX_CLS_LOC_SPECIAL)
+		printf("Added rule with ID %d\n", nfccmd.fs.location);
+
+	return 0;
+}
+
+int rxclass_rule_del(struct cmd_context *ctx, __u32 loc)
+{
+	struct ethtool_rxnfc nfccmd;
+	int err;
+
+	/* notify netdev of rule removal */
+	nfccmd.cmd = ETHTOOL_SRXCLSRLDEL;
+	nfccmd.fs.location = loc;
+	err = send_ioctl(ctx, &nfccmd);
+	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_RING_VF,
+	OPT_RING_QUEUE,
+	OPT_BE16,
+	OPT_BE32,
+	OPT_BE64,
+	OPT_IP4,
+	OPT_IP6,
+	OPT_MAC,
+} rule_opt_type_t;
+
+#define NFC_FLAG_RING		0x0001
+#define NFC_FLAG_LOC		0x0002
+#define NFC_FLAG_SADDR		0x0004
+#define NFC_FLAG_DADDR		0x0008
+#define NFC_FLAG_SPORT		0x0010
+#define NFC_FLAG_DPORT		0x0020
+#define NFC_FLAG_SPI		0x0030
+#define NFC_FLAG_TOS		0x0040
+#define NFC_FLAG_PROTO		0x0080
+#define NTUPLE_FLAG_VLAN	0x0100
+#define NTUPLE_FLAG_UDEF	0x0200
+#define NTUPLE_FLAG_VETH	0x0400
+#define NFC_FLAG_MAC_ADDR	0x0800
+#define NFC_FLAG_RING_VF	0x1000
+#define NFC_FLAG_RING_QUEUE	0x2000
+
+struct rule_opts {
+	const char	*name;
+	rule_opt_type_t	type;
+	u32		flag;
+	int		offset;
+	int		moffset;
+};
+
+static const 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 },
+	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
+	  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) },
+	{ "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
+};
+
+static const 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 },
+	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
+	  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) },
+	{ "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
+};
+
+static const 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) },
+	{ "l4data", 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) },
+	{ "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 },
+	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
+	  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) },
+	{ "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
+};
+
+static const struct rule_opts rule_nfc_tcp_ip6[] = {
+	{ "src-ip", OPT_IP6, NFC_FLAG_SADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.ip6src),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.ip6src) },
+	{ "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.ip6dst),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.ip6dst) },
+	{ "tclass", OPT_U8, NFC_FLAG_TOS,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.tclass),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.tclass) },
+	{ "src-port", OPT_BE16, NFC_FLAG_SPORT,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.psrc),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.psrc) },
+	{ "dst-port", OPT_BE16, NFC_FLAG_DPORT,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.tcp_ip6_spec.pdst),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.tcp_ip6_spec.pdst) },
+	{ "action", OPT_U64, NFC_FLAG_RING,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
+	  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) },
+	{ "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
+};
+
+static const struct rule_opts rule_nfc_esp_ip6[] = {
+	{ "src-ip", OPT_IP6, NFC_FLAG_SADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.ip6src),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.ip6src) },
+	{ "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.ip6dst),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.ip6dst) },
+	{ "tclass", OPT_U8, NFC_FLAG_TOS,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.tclass),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.tclass) },
+	{ "spi", OPT_BE32, NFC_FLAG_SPI,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.esp_ip6_spec.spi),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.esp_ip6_spec.spi) },
+	{ "action", OPT_U64, NFC_FLAG_RING,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
+	  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) },
+	{ "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
+};
+
+static const struct rule_opts rule_nfc_usr_ip6[] = {
+	{ "src-ip", OPT_IP6, NFC_FLAG_SADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.ip6src),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.ip6src) },
+	{ "dst-ip", OPT_IP6, NFC_FLAG_DADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.ip6dst),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.ip6dst) },
+	{ "tclass", OPT_U8, NFC_FLAG_TOS,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.tclass),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.tclass) },
+	{ "l4proto", OPT_U8, NFC_FLAG_PROTO,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_proto),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_proto) },
+	{ "l4data", OPT_BE32, NFC_FLAG_SPI,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
+	{ "spi", OPT_BE32, NFC_FLAG_SPI,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
+	{ "src-port", OPT_BE16, NFC_FLAG_SPORT,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) },
+	{ "dst-port", OPT_BE16, NFC_FLAG_DPORT,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.usr_ip6_spec.l4_4_bytes) + 2,
+	  offsetof(struct ethtool_rx_flow_spec, m_u.usr_ip6_spec.l4_4_bytes) + 2 },
+	{ "action", OPT_U64, NFC_FLAG_RING,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
+	  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) },
+	{ "dst-mac", OPT_MAC, NFC_FLAG_MAC_ADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_ext.h_dest),
+	  offsetof(struct ethtool_rx_flow_spec, m_ext.h_dest) },
+};
+
+static const struct rule_opts rule_nfc_ether[] = {
+	{ "src", OPT_MAC, NFC_FLAG_SADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_source),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_source) },
+	{ "dst", OPT_MAC, NFC_FLAG_DADDR,
+	  offsetof(struct ethtool_rx_flow_spec, h_u.ether_spec.h_dest),
+	  offsetof(struct ethtool_rx_flow_spec, m_u.ether_spec.h_dest) },
+	{ "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 },
+	{ "vf", OPT_RING_VF, NFC_FLAG_RING_VF,
+	  offsetof(struct ethtool_rx_flow_spec, ring_cookie), -1 },
+	{ "queue", OPT_RING_QUEUE, NFC_FLAG_RING_QUEUE,
+	  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_ipv6(char *str, __be32 *val)
+{
+	if (!inet_pton(AF_INET6, 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_RING_VF: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 8);
+		if (err)
+			return -1;
+
+		/* The ring_cookie uses 0 to indicate the rule targets the
+		 * main function, so add 1 to the value in order to target the
+		 * correct virtual function.
+		 */
+		val++;
+
+		*(u64 *)&p[opt->offset] &= ~ETHTOOL_RX_FLOW_SPEC_RING_VF;
+		*(u64 *)&p[opt->offset] |= (u64)val << ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF;
+		break;
+	}
+	case OPT_RING_QUEUE: {
+		unsigned long long val;
+		err = rxclass_get_ulong(str, &val, 32);
+		if (err)
+			return -1;
+		*(u64 *)&p[opt->offset] &= ~ETHTOOL_RX_FLOW_SPEC_RING;
+		*(u64 *)&p[opt->offset] |= (u64)val;
+		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_IP6: {
+		__be32 val[4];
+		err = rxclass_get_ipv6(str, val);
+		if (err)
+			return -1;
+		memcpy(&p[opt->offset], val, sizeof(val));
+		if (opt->moffset >= 0)
+			memset(&p[opt->moffset], mask, sizeof(val));
+		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_IP6: {
+		__be32 val[4], *field;
+		int i;
+		err = rxclass_get_ipv6(str, val);
+		if (err)
+			return -1;
+		field = (__be32 *)&p[opt->moffset];
+		for (i = 0; i < 4; i++)
+			field[i] = ~val[i];
+		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(struct cmd_context *ctx,
+			   struct ethtool_rx_flow_spec *fsp, __u32 *rss_context)
+{
+	const struct rule_opts *options;
+	unsigned char *p = (unsigned char *)fsp;
+	int i = 0, n_opts, err;
+	u32 flags = 0;
+	int flow_type;
+	int argc = ctx->argc;
+	char **argp = ctx->argp;
+
+	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 = IPV4_USER_FLOW;
+	else if (!strcmp(argp[0], "tcp6"))
+		flow_type = TCP_V6_FLOW;
+	else if (!strcmp(argp[0], "udp6"))
+		flow_type = UDP_V6_FLOW;
+	else if (!strcmp(argp[0], "sctp6"))
+		flow_type = SCTP_V6_FLOW;
+	else if (!strcmp(argp[0], "ah6"))
+		flow_type = AH_V6_FLOW;
+	else if (!strcmp(argp[0], "esp6"))
+		flow_type = ESP_V6_FLOW;
+	else if (!strcmp(argp[0], "ip6"))
+		flow_type = IPV6_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 IPV4_USER_FLOW:
+		options = rule_nfc_usr_ip4;
+		n_opts = ARRAY_SIZE(rule_nfc_usr_ip4);
+		break;
+	case TCP_V6_FLOW:
+	case UDP_V6_FLOW:
+	case SCTP_V6_FLOW:
+		options = rule_nfc_tcp_ip6;
+		n_opts = ARRAY_SIZE(rule_nfc_tcp_ip6);
+		break;
+	case AH_V6_FLOW:
+	case ESP_V6_FLOW:
+		options = rule_nfc_esp_ip6;
+		n_opts = ARRAY_SIZE(rule_nfc_esp_ip6);
+		break;
+	case IPV6_USER_FLOW:
+		options = rule_nfc_usr_ip6;
+		n_opts = ARRAY_SIZE(rule_nfc_usr_ip6);
+		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_ANY;
+
+	for (i = 1; i < argc;) {
+		const struct rule_opts *opt;
+		int idx;
+
+		/* special handling for 'context %d' as it doesn't go in
+		 * the struct ethtool_rx_flow_spec
+		 */
+		if (!strcmp(argp[i], "context")) {
+			unsigned long long val;
+
+			i++;
+			if (i >= argc) {
+				fprintf(stderr, "'context' missing value\n");
+				return -1;
+			}
+
+			if (rxclass_get_ulong(argp[i], &val, 32)) {
+				fprintf(stderr, "Invalid context value[%s]\n",
+					argp[i]);
+				return -1;
+			}
+
+			/* Can't use the ALLOC special value as the context ID
+			 * of a filter to insert
+			 */
+			if ((__u32)val == ETH_RXFH_CONTEXT_ALLOC) {
+				fprintf(stderr, "Bad context value %x\n",
+					(__u32)val);
+				return -1;
+			}
+
+			*rss_context = (__u32)val;
+			fsp->flow_type |= FLOW_RSS;
+			i++;
+			continue;
+		}
+
+		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 & NFC_FLAG_RING) && (flags & NFC_FLAG_RING_QUEUE)) {
+		fprintf(stderr, "action and queue are not compatible\n");
+			return -1;
+	}
+
+	if ((flags & NFC_FLAG_RING) && (flags & NFC_FLAG_RING_VF)) {
+		fprintf(stderr, "action and vf are not compatible\n");
+			return -1;
+	}
+
+	if (flow_type == IPV4_USER_FLOW)
+		fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
+	if (flags & (NTUPLE_FLAG_VLAN | NTUPLE_FLAG_UDEF | NTUPLE_FLAG_VETH))
+		fsp->flow_type |= FLOW_EXT;
+	if (flags & NFC_FLAG_MAC_ADDR)
+		fsp->flow_type |= FLOW_MAC_EXT;
+
+	return 0;
+
+syntax_err:
+	fprintf(stderr, "Add rule, invalid syntax\n");
+	return -1;
+}
diff --git a/sfc.c b/sfc.c
new file mode 100644
index 0000000..f56243d
--- /dev/null
+++ b/sfc.c
@@ -0,0 +1,3927 @@
+/****************************************************************************
+ * Support for Solarflare Solarstorm network controllers and boards
+ * Copyright 2010-2012 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "internal.h"
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+/* Falcon architecture register definitions
+ * (from linux/drivers/net/ethernet/sfc/farch_regs.h)
+ */
+
+/* ADR_REGION_REG: Address region register */
+#define	FR_AZ_ADR_REGION 0x00000000
+#define	FRF_AZ_ADR_REGION3_LBN 96
+#define	FRF_AZ_ADR_REGION3_WIDTH 18
+#define	FRF_AZ_ADR_REGION2_LBN 64
+#define	FRF_AZ_ADR_REGION2_WIDTH 18
+#define	FRF_AZ_ADR_REGION1_LBN 32
+#define	FRF_AZ_ADR_REGION1_WIDTH 18
+#define	FRF_AZ_ADR_REGION0_LBN 0
+#define	FRF_AZ_ADR_REGION0_WIDTH 18
+
+/* INT_EN_REG_KER: Kernel driver Interrupt enable register */
+#define	FR_AZ_INT_EN_KER 0x00000010
+#define	FRF_AZ_KER_INT_LEVE_SEL_LBN 8
+#define	FRF_AZ_KER_INT_LEVE_SEL_WIDTH 6
+#define	FRF_AZ_KER_INT_CHAR_LBN 4
+#define	FRF_AZ_KER_INT_CHAR_WIDTH 1
+#define	FRF_AZ_KER_INT_KER_LBN 3
+#define	FRF_AZ_KER_INT_KER_WIDTH 1
+#define	FRF_AZ_DRV_INT_EN_KER_LBN 0
+#define	FRF_AZ_DRV_INT_EN_KER_WIDTH 1
+
+/* INT_EN_REG_CHAR: Char Driver interrupt enable register */
+#define	FR_BZ_INT_EN_CHAR 0x00000020
+#define	FRF_BZ_CHAR_INT_LEVE_SEL_LBN 8
+#define	FRF_BZ_CHAR_INT_LEVE_SEL_WIDTH 6
+#define	FRF_BZ_CHAR_INT_CHAR_LBN 4
+#define	FRF_BZ_CHAR_INT_CHAR_WIDTH 1
+#define	FRF_BZ_CHAR_INT_KER_LBN 3
+#define	FRF_BZ_CHAR_INT_KER_WIDTH 1
+#define	FRF_BZ_DRV_INT_EN_CHAR_LBN 0
+#define	FRF_BZ_DRV_INT_EN_CHAR_WIDTH 1
+
+/* INT_ADR_REG_KER: Interrupt host address for Kernel driver */
+#define	FR_AZ_INT_ADR_KER 0x00000030
+#define	FRF_AZ_NORM_INT_VEC_DIS_KER_LBN 64
+#define	FRF_AZ_NORM_INT_VEC_DIS_KER_WIDTH 1
+#define	FRF_AZ_INT_ADR_KER_LBN 0
+#define	FRF_AZ_INT_ADR_KER_WIDTH 64
+
+/* INT_ADR_REG_CHAR: Interrupt host address for Char driver */
+#define	FR_BZ_INT_ADR_CHAR 0x00000040
+#define	FRF_BZ_NORM_INT_VEC_DIS_CHAR_LBN 64
+#define	FRF_BZ_NORM_INT_VEC_DIS_CHAR_WIDTH 1
+#define	FRF_BZ_INT_ADR_CHAR_LBN 0
+#define	FRF_BZ_INT_ADR_CHAR_WIDTH 64
+
+/* INT_ACK_KER: Kernel interrupt acknowledge register */
+#define	FR_AA_INT_ACK_KER 0x00000050
+#define	FRF_AA_INT_ACK_KER_FIELD_LBN 0
+#define	FRF_AA_INT_ACK_KER_FIELD_WIDTH 32
+
+/* INT_ISR0_REG: Function 0 Interrupt Acknowledge Status register */
+#define	FR_BZ_INT_ISR0 0x00000090
+#define	FRF_BZ_INT_ISR_REG_LBN 0
+#define	FRF_BZ_INT_ISR_REG_WIDTH 64
+
+/* HW_INIT_REG: Hardware initialization register */
+#define	FR_AZ_HW_INIT 0x000000c0
+#define	FRF_BB_BDMRD_CPLF_FULL_LBN 124
+#define	FRF_BB_BDMRD_CPLF_FULL_WIDTH 1
+#define	FRF_BB_PCIE_CPL_TIMEOUT_CTRL_LBN 121
+#define	FRF_BB_PCIE_CPL_TIMEOUT_CTRL_WIDTH 3
+#define	FRF_CZ_TX_MRG_TAGS_LBN 120
+#define	FRF_CZ_TX_MRG_TAGS_WIDTH 1
+#define	FRF_AB_TRGT_MASK_ALL_LBN 100
+#define	FRF_AB_TRGT_MASK_ALL_WIDTH 1
+#define	FRF_AZ_DOORBELL_DROP_LBN 92
+#define	FRF_AZ_DOORBELL_DROP_WIDTH 8
+#define	FRF_AB_TX_RREQ_MASK_EN_LBN 76
+#define	FRF_AB_TX_RREQ_MASK_EN_WIDTH 1
+#define	FRF_AB_PE_EIDLE_DIS_LBN 75
+#define	FRF_AB_PE_EIDLE_DIS_WIDTH 1
+#define	FRF_AA_FC_BLOCKING_EN_LBN 45
+#define	FRF_AA_FC_BLOCKING_EN_WIDTH 1
+#define	FRF_BZ_B2B_REQ_EN_LBN 45
+#define	FRF_BZ_B2B_REQ_EN_WIDTH 1
+#define	FRF_AA_B2B_REQ_EN_LBN 44
+#define	FRF_AA_B2B_REQ_EN_WIDTH 1
+#define	FRF_BB_FC_BLOCKING_EN_LBN 44
+#define	FRF_BB_FC_BLOCKING_EN_WIDTH 1
+#define	FRF_AZ_POST_WR_MASK_LBN 40
+#define	FRF_AZ_POST_WR_MASK_WIDTH 4
+#define	FRF_AZ_TLP_TC_LBN 34
+#define	FRF_AZ_TLP_TC_WIDTH 3
+#define	FRF_AZ_TLP_ATTR_LBN 32
+#define	FRF_AZ_TLP_ATTR_WIDTH 2
+#define	FRF_AB_INTB_VEC_LBN 24
+#define	FRF_AB_INTB_VEC_WIDTH 5
+#define	FRF_AB_INTA_VEC_LBN 16
+#define	FRF_AB_INTA_VEC_WIDTH 5
+#define	FRF_AZ_WD_TIMER_LBN 8
+#define	FRF_AZ_WD_TIMER_WIDTH 8
+#define	FRF_AZ_US_DISABLE_LBN 5
+#define	FRF_AZ_US_DISABLE_WIDTH 1
+#define	FRF_AZ_TLP_EP_LBN 4
+#define	FRF_AZ_TLP_EP_WIDTH 1
+#define	FRF_AZ_ATTR_SEL_LBN 3
+#define	FRF_AZ_ATTR_SEL_WIDTH 1
+#define	FRF_AZ_TD_SEL_LBN 1
+#define	FRF_AZ_TD_SEL_WIDTH 1
+#define	FRF_AZ_TLP_TD_LBN 0
+#define	FRF_AZ_TLP_TD_WIDTH 1
+
+/* EE_SPI_HCMD_REG: SPI host command register */
+#define	FR_AB_EE_SPI_HCMD 0x00000100
+#define	FRF_AB_EE_SPI_HCMD_CMD_EN_LBN 31
+#define	FRF_AB_EE_SPI_HCMD_CMD_EN_WIDTH 1
+#define	FRF_AB_EE_WR_TIMER_ACTIVE_LBN 28
+#define	FRF_AB_EE_WR_TIMER_ACTIVE_WIDTH 1
+#define	FRF_AB_EE_SPI_HCMD_SF_SEL_LBN 24
+#define	FRF_AB_EE_SPI_HCMD_SF_SEL_WIDTH 1
+#define	FRF_AB_EE_SPI_HCMD_DABCNT_LBN 16
+#define	FRF_AB_EE_SPI_HCMD_DABCNT_WIDTH 5
+#define	FRF_AB_EE_SPI_HCMD_READ_LBN 15
+#define	FRF_AB_EE_SPI_HCMD_READ_WIDTH 1
+#define	FRF_AB_EE_SPI_HCMD_DUBCNT_LBN 12
+#define	FRF_AB_EE_SPI_HCMD_DUBCNT_WIDTH 2
+#define	FRF_AB_EE_SPI_HCMD_ADBCNT_LBN 8
+#define	FRF_AB_EE_SPI_HCMD_ADBCNT_WIDTH 2
+#define	FRF_AB_EE_SPI_HCMD_ENC_LBN 0
+#define	FRF_AB_EE_SPI_HCMD_ENC_WIDTH 8
+
+/* USR_EV_CFG: User Level Event Configuration register */
+#define	FR_CZ_USR_EV_CFG 0x00000100
+#define	FRF_CZ_USREV_DIS_LBN 16
+#define	FRF_CZ_USREV_DIS_WIDTH 1
+#define	FRF_CZ_DFLT_EVQ_LBN 0
+#define	FRF_CZ_DFLT_EVQ_WIDTH 10
+
+/* EE_SPI_HADR_REG: SPI host address register */
+#define	FR_AB_EE_SPI_HADR 0x00000110
+#define	FRF_AB_EE_SPI_HADR_DUBYTE_LBN 24
+#define	FRF_AB_EE_SPI_HADR_DUBYTE_WIDTH 8
+#define	FRF_AB_EE_SPI_HADR_ADR_LBN 0
+#define	FRF_AB_EE_SPI_HADR_ADR_WIDTH 24
+
+/* EE_SPI_HDATA_REG: SPI host data register */
+#define	FR_AB_EE_SPI_HDATA 0x00000120
+#define	FRF_AB_EE_SPI_HDATA3_LBN 96
+#define	FRF_AB_EE_SPI_HDATA3_WIDTH 32
+#define	FRF_AB_EE_SPI_HDATA2_LBN 64
+#define	FRF_AB_EE_SPI_HDATA2_WIDTH 32
+#define	FRF_AB_EE_SPI_HDATA1_LBN 32
+#define	FRF_AB_EE_SPI_HDATA1_WIDTH 32
+#define	FRF_AB_EE_SPI_HDATA0_LBN 0
+#define	FRF_AB_EE_SPI_HDATA0_WIDTH 32
+
+/* EE_BASE_PAGE_REG: Expansion ROM base mirror register */
+#define	FR_AB_EE_BASE_PAGE 0x00000130
+#define	FRF_AB_EE_EXPROM_MASK_LBN 16
+#define	FRF_AB_EE_EXPROM_MASK_WIDTH 13
+#define	FRF_AB_EE_EXP_ROM_WINDOW_BASE_LBN 0
+#define	FRF_AB_EE_EXP_ROM_WINDOW_BASE_WIDTH 13
+
+/* EE_VPD_CFG0_REG: SPI/VPD configuration register 0 */
+#define	FR_AB_EE_VPD_CFG0 0x00000140
+#define	FRF_AB_EE_SF_FASTRD_EN_LBN 127
+#define	FRF_AB_EE_SF_FASTRD_EN_WIDTH 1
+#define	FRF_AB_EE_SF_CLOCK_DIV_LBN 120
+#define	FRF_AB_EE_SF_CLOCK_DIV_WIDTH 7
+#define	FRF_AB_EE_VPD_WIP_POLL_LBN 119
+#define	FRF_AB_EE_VPD_WIP_POLL_WIDTH 1
+#define	FRF_AB_EE_EE_CLOCK_DIV_LBN 112
+#define	FRF_AB_EE_EE_CLOCK_DIV_WIDTH 7
+#define	FRF_AB_EE_EE_WR_TMR_VALUE_LBN 96
+#define	FRF_AB_EE_EE_WR_TMR_VALUE_WIDTH 16
+#define	FRF_AB_EE_VPDW_LENGTH_LBN 80
+#define	FRF_AB_EE_VPDW_LENGTH_WIDTH 15
+#define	FRF_AB_EE_VPDW_BASE_LBN 64
+#define	FRF_AB_EE_VPDW_BASE_WIDTH 15
+#define	FRF_AB_EE_VPD_WR_CMD_EN_LBN 56
+#define	FRF_AB_EE_VPD_WR_CMD_EN_WIDTH 8
+#define	FRF_AB_EE_VPD_BASE_LBN 32
+#define	FRF_AB_EE_VPD_BASE_WIDTH 24
+#define	FRF_AB_EE_VPD_LENGTH_LBN 16
+#define	FRF_AB_EE_VPD_LENGTH_WIDTH 15
+#define	FRF_AB_EE_VPD_AD_SIZE_LBN 8
+#define	FRF_AB_EE_VPD_AD_SIZE_WIDTH 5
+#define	FRF_AB_EE_VPD_ACCESS_ON_LBN 5
+#define	FRF_AB_EE_VPD_ACCESS_ON_WIDTH 1
+#define	FRF_AB_EE_VPD_ACCESS_BLOCK_LBN 4
+#define	FRF_AB_EE_VPD_ACCESS_BLOCK_WIDTH 1
+#define	FRF_AB_EE_VPD_DEV_SF_SEL_LBN 2
+#define	FRF_AB_EE_VPD_DEV_SF_SEL_WIDTH 1
+#define	FRF_AB_EE_VPD_EN_AD9_MODE_LBN 1
+#define	FRF_AB_EE_VPD_EN_AD9_MODE_WIDTH 1
+#define	FRF_AB_EE_VPD_EN_LBN 0
+#define	FRF_AB_EE_VPD_EN_WIDTH 1
+
+/* EE_VPD_SW_CNTL_REG: VPD access SW control register */
+#define	FR_AB_EE_VPD_SW_CNTL 0x00000150
+#define	FRF_AB_EE_VPD_CYCLE_PENDING_LBN 31
+#define	FRF_AB_EE_VPD_CYCLE_PENDING_WIDTH 1
+#define	FRF_AB_EE_VPD_CYC_WRITE_LBN 28
+#define	FRF_AB_EE_VPD_CYC_WRITE_WIDTH 1
+#define	FRF_AB_EE_VPD_CYC_ADR_LBN 0
+#define	FRF_AB_EE_VPD_CYC_ADR_WIDTH 15
+
+/* EE_VPD_SW_DATA_REG: VPD access SW data register */
+#define	FR_AB_EE_VPD_SW_DATA 0x00000160
+#define	FRF_AB_EE_VPD_CYC_DAT_LBN 0
+#define	FRF_AB_EE_VPD_CYC_DAT_WIDTH 32
+
+/* PBMX_DBG_IADDR_REG: Capture Module address register */
+#define	FR_CZ_PBMX_DBG_IADDR 0x000001f0
+#define	FRF_CZ_PBMX_DBG_IADDR_LBN 0
+#define	FRF_CZ_PBMX_DBG_IADDR_WIDTH 32
+
+/* PCIE_CORE_INDIRECT_REG: Indirect Access to PCIE Core registers */
+#define	FR_BB_PCIE_CORE_INDIRECT 0x000001f0
+#define	FRF_BB_PCIE_CORE_TARGET_DATA_LBN 32
+#define	FRF_BB_PCIE_CORE_TARGET_DATA_WIDTH 32
+#define	FRF_BB_PCIE_CORE_INDIRECT_ACCESS_DIR_LBN 15
+#define	FRF_BB_PCIE_CORE_INDIRECT_ACCESS_DIR_WIDTH 1
+#define	FRF_BB_PCIE_CORE_TARGET_REG_ADRS_LBN 0
+#define	FRF_BB_PCIE_CORE_TARGET_REG_ADRS_WIDTH 12
+
+/* PBMX_DBG_IDATA_REG: Capture Module data register */
+#define	FR_CZ_PBMX_DBG_IDATA 0x000001f8
+#define	FRF_CZ_PBMX_DBG_IDATA_LBN 0
+#define	FRF_CZ_PBMX_DBG_IDATA_WIDTH 64
+
+/* NIC_STAT_REG: NIC status register */
+#define	FR_AB_NIC_STAT 0x00000200
+#define	FRF_BB_AER_DIS_LBN 34
+#define	FRF_BB_AER_DIS_WIDTH 1
+#define	FRF_BB_EE_STRAP_EN_LBN 31
+#define	FRF_BB_EE_STRAP_EN_WIDTH 1
+#define	FRF_BB_EE_STRAP_LBN 24
+#define	FRF_BB_EE_STRAP_WIDTH 4
+#define	FRF_BB_REVISION_ID_LBN 17
+#define	FRF_BB_REVISION_ID_WIDTH 7
+#define	FRF_AB_ONCHIP_SRAM_LBN 16
+#define	FRF_AB_ONCHIP_SRAM_WIDTH 1
+#define	FRF_AB_SF_PRST_LBN 9
+#define	FRF_AB_SF_PRST_WIDTH 1
+#define	FRF_AB_EE_PRST_LBN 8
+#define	FRF_AB_EE_PRST_WIDTH 1
+#define	FRF_AB_ATE_MODE_LBN 3
+#define	FRF_AB_ATE_MODE_WIDTH 1
+#define	FRF_AB_STRAP_PINS_LBN 0
+#define	FRF_AB_STRAP_PINS_WIDTH 3
+
+/* GPIO_CTL_REG: GPIO control register */
+#define	FR_AB_GPIO_CTL 0x00000210
+#define	FRF_AB_GPIO_OUT3_LBN 112
+#define	FRF_AB_GPIO_OUT3_WIDTH 16
+#define	FRF_AB_GPIO_IN3_LBN 104
+#define	FRF_AB_GPIO_IN3_WIDTH 8
+#define	FRF_AB_GPIO_PWRUP_VALUE3_LBN 96
+#define	FRF_AB_GPIO_PWRUP_VALUE3_WIDTH 8
+#define	FRF_AB_GPIO_OUT2_LBN 80
+#define	FRF_AB_GPIO_OUT2_WIDTH 16
+#define	FRF_AB_GPIO_IN2_LBN 72
+#define	FRF_AB_GPIO_IN2_WIDTH 8
+#define	FRF_AB_GPIO_PWRUP_VALUE2_LBN 64
+#define	FRF_AB_GPIO_PWRUP_VALUE2_WIDTH 8
+#define	FRF_AB_GPIO15_OEN_LBN 63
+#define	FRF_AB_GPIO15_OEN_WIDTH 1
+#define	FRF_AB_GPIO14_OEN_LBN 62
+#define	FRF_AB_GPIO14_OEN_WIDTH 1
+#define	FRF_AB_GPIO13_OEN_LBN 61
+#define	FRF_AB_GPIO13_OEN_WIDTH 1
+#define	FRF_AB_GPIO12_OEN_LBN 60
+#define	FRF_AB_GPIO12_OEN_WIDTH 1
+#define	FRF_AB_GPIO11_OEN_LBN 59
+#define	FRF_AB_GPIO11_OEN_WIDTH 1
+#define	FRF_AB_GPIO10_OEN_LBN 58
+#define	FRF_AB_GPIO10_OEN_WIDTH 1
+#define	FRF_AB_GPIO9_OEN_LBN 57
+#define	FRF_AB_GPIO9_OEN_WIDTH 1
+#define	FRF_AB_GPIO8_OEN_LBN 56
+#define	FRF_AB_GPIO8_OEN_WIDTH 1
+#define	FRF_AB_GPIO15_OUT_LBN 55
+#define	FRF_AB_GPIO15_OUT_WIDTH 1
+#define	FRF_AB_GPIO14_OUT_LBN 54
+#define	FRF_AB_GPIO14_OUT_WIDTH 1
+#define	FRF_AB_GPIO13_OUT_LBN 53
+#define	FRF_AB_GPIO13_OUT_WIDTH 1
+#define	FRF_AB_GPIO12_OUT_LBN 52
+#define	FRF_AB_GPIO12_OUT_WIDTH 1
+#define	FRF_AB_GPIO11_OUT_LBN 51
+#define	FRF_AB_GPIO11_OUT_WIDTH 1
+#define	FRF_AB_GPIO10_OUT_LBN 50
+#define	FRF_AB_GPIO10_OUT_WIDTH 1
+#define	FRF_AB_GPIO9_OUT_LBN 49
+#define	FRF_AB_GPIO9_OUT_WIDTH 1
+#define	FRF_AB_GPIO8_OUT_LBN 48
+#define	FRF_AB_GPIO8_OUT_WIDTH 1
+#define	FRF_AB_GPIO15_IN_LBN 47
+#define	FRF_AB_GPIO15_IN_WIDTH 1
+#define	FRF_AB_GPIO14_IN_LBN 46
+#define	FRF_AB_GPIO14_IN_WIDTH 1
+#define	FRF_AB_GPIO13_IN_LBN 45
+#define	FRF_AB_GPIO13_IN_WIDTH 1
+#define	FRF_AB_GPIO12_IN_LBN 44
+#define	FRF_AB_GPIO12_IN_WIDTH 1
+#define	FRF_AB_GPIO11_IN_LBN 43
+#define	FRF_AB_GPIO11_IN_WIDTH 1
+#define	FRF_AB_GPIO10_IN_LBN 42
+#define	FRF_AB_GPIO10_IN_WIDTH 1
+#define	FRF_AB_GPIO9_IN_LBN 41
+#define	FRF_AB_GPIO9_IN_WIDTH 1
+#define	FRF_AB_GPIO8_IN_LBN 40
+#define	FRF_AB_GPIO8_IN_WIDTH 1
+#define	FRF_AB_GPIO15_PWRUP_VALUE_LBN 39
+#define	FRF_AB_GPIO15_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO14_PWRUP_VALUE_LBN 38
+#define	FRF_AB_GPIO14_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO13_PWRUP_VALUE_LBN 37
+#define	FRF_AB_GPIO13_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO12_PWRUP_VALUE_LBN 36
+#define	FRF_AB_GPIO12_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO11_PWRUP_VALUE_LBN 35
+#define	FRF_AB_GPIO11_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO10_PWRUP_VALUE_LBN 34
+#define	FRF_AB_GPIO10_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO9_PWRUP_VALUE_LBN 33
+#define	FRF_AB_GPIO9_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO8_PWRUP_VALUE_LBN 32
+#define	FRF_AB_GPIO8_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_CLK156_OUT_EN_LBN 31
+#define	FRF_AB_CLK156_OUT_EN_WIDTH 1
+#define	FRF_AB_USE_NIC_CLK_LBN 30
+#define	FRF_AB_USE_NIC_CLK_WIDTH 1
+#define	FRF_AB_GPIO5_OEN_LBN 29
+#define	FRF_AB_GPIO5_OEN_WIDTH 1
+#define	FRF_AB_GPIO4_OEN_LBN 28
+#define	FRF_AB_GPIO4_OEN_WIDTH 1
+#define	FRF_AB_GPIO3_OEN_LBN 27
+#define	FRF_AB_GPIO3_OEN_WIDTH 1
+#define	FRF_AB_GPIO2_OEN_LBN 26
+#define	FRF_AB_GPIO2_OEN_WIDTH 1
+#define	FRF_AB_GPIO1_OEN_LBN 25
+#define	FRF_AB_GPIO1_OEN_WIDTH 1
+#define	FRF_AB_GPIO0_OEN_LBN 24
+#define	FRF_AB_GPIO0_OEN_WIDTH 1
+#define	FRF_AB_GPIO7_OUT_LBN 23
+#define	FRF_AB_GPIO7_OUT_WIDTH 1
+#define	FRF_AB_GPIO6_OUT_LBN 22
+#define	FRF_AB_GPIO6_OUT_WIDTH 1
+#define	FRF_AB_GPIO5_OUT_LBN 21
+#define	FRF_AB_GPIO5_OUT_WIDTH 1
+#define	FRF_AB_GPIO4_OUT_LBN 20
+#define	FRF_AB_GPIO4_OUT_WIDTH 1
+#define	FRF_AB_GPIO3_OUT_LBN 19
+#define	FRF_AB_GPIO3_OUT_WIDTH 1
+#define	FRF_AB_GPIO2_OUT_LBN 18
+#define	FRF_AB_GPIO2_OUT_WIDTH 1
+#define	FRF_AB_GPIO1_OUT_LBN 17
+#define	FRF_AB_GPIO1_OUT_WIDTH 1
+#define	FRF_AB_GPIO0_OUT_LBN 16
+#define	FRF_AB_GPIO0_OUT_WIDTH 1
+#define	FRF_AB_GPIO7_IN_LBN 15
+#define	FRF_AB_GPIO7_IN_WIDTH 1
+#define	FRF_AB_GPIO6_IN_LBN 14
+#define	FRF_AB_GPIO6_IN_WIDTH 1
+#define	FRF_AB_GPIO5_IN_LBN 13
+#define	FRF_AB_GPIO5_IN_WIDTH 1
+#define	FRF_AB_GPIO4_IN_LBN 12
+#define	FRF_AB_GPIO4_IN_WIDTH 1
+#define	FRF_AB_GPIO3_IN_LBN 11
+#define	FRF_AB_GPIO3_IN_WIDTH 1
+#define	FRF_AB_GPIO2_IN_LBN 10
+#define	FRF_AB_GPIO2_IN_WIDTH 1
+#define	FRF_AB_GPIO1_IN_LBN 9
+#define	FRF_AB_GPIO1_IN_WIDTH 1
+#define	FRF_AB_GPIO0_IN_LBN 8
+#define	FRF_AB_GPIO0_IN_WIDTH 1
+#define	FRF_AB_GPIO7_PWRUP_VALUE_LBN 7
+#define	FRF_AB_GPIO7_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO6_PWRUP_VALUE_LBN 6
+#define	FRF_AB_GPIO6_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO5_PWRUP_VALUE_LBN 5
+#define	FRF_AB_GPIO5_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO4_PWRUP_VALUE_LBN 4
+#define	FRF_AB_GPIO4_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO3_PWRUP_VALUE_LBN 3
+#define	FRF_AB_GPIO3_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO2_PWRUP_VALUE_LBN 2
+#define	FRF_AB_GPIO2_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO1_PWRUP_VALUE_LBN 1
+#define	FRF_AB_GPIO1_PWRUP_VALUE_WIDTH 1
+#define	FRF_AB_GPIO0_PWRUP_VALUE_LBN 0
+#define	FRF_AB_GPIO0_PWRUP_VALUE_WIDTH 1
+
+/* GLB_CTL_REG: Global control register */
+#define	FR_AB_GLB_CTL 0x00000220
+#define	FRF_AB_EXT_PHY_RST_CTL_LBN 63
+#define	FRF_AB_EXT_PHY_RST_CTL_WIDTH 1
+#define	FRF_AB_XAUI_SD_RST_CTL_LBN 62
+#define	FRF_AB_XAUI_SD_RST_CTL_WIDTH 1
+#define	FRF_AB_PCIE_SD_RST_CTL_LBN 61
+#define	FRF_AB_PCIE_SD_RST_CTL_WIDTH 1
+#define	FRF_AA_PCIX_RST_CTL_LBN 60
+#define	FRF_AA_PCIX_RST_CTL_WIDTH 1
+#define	FRF_BB_BIU_RST_CTL_LBN 60
+#define	FRF_BB_BIU_RST_CTL_WIDTH 1
+#define	FRF_AB_PCIE_STKY_RST_CTL_LBN 59
+#define	FRF_AB_PCIE_STKY_RST_CTL_WIDTH 1
+#define	FRF_AB_PCIE_NSTKY_RST_CTL_LBN 58
+#define	FRF_AB_PCIE_NSTKY_RST_CTL_WIDTH 1
+#define	FRF_AB_PCIE_CORE_RST_CTL_LBN 57
+#define	FRF_AB_PCIE_CORE_RST_CTL_WIDTH 1
+#define	FRF_AB_XGRX_RST_CTL_LBN 56
+#define	FRF_AB_XGRX_RST_CTL_WIDTH 1
+#define	FRF_AB_XGTX_RST_CTL_LBN 55
+#define	FRF_AB_XGTX_RST_CTL_WIDTH 1
+#define	FRF_AB_EM_RST_CTL_LBN 54
+#define	FRF_AB_EM_RST_CTL_WIDTH 1
+#define	FRF_AB_EV_RST_CTL_LBN 53
+#define	FRF_AB_EV_RST_CTL_WIDTH 1
+#define	FRF_AB_SR_RST_CTL_LBN 52
+#define	FRF_AB_SR_RST_CTL_WIDTH 1
+#define	FRF_AB_RX_RST_CTL_LBN 51
+#define	FRF_AB_RX_RST_CTL_WIDTH 1
+#define	FRF_AB_TX_RST_CTL_LBN 50
+#define	FRF_AB_TX_RST_CTL_WIDTH 1
+#define	FRF_AB_EE_RST_CTL_LBN 49
+#define	FRF_AB_EE_RST_CTL_WIDTH 1
+#define	FRF_AB_CS_RST_CTL_LBN 48
+#define	FRF_AB_CS_RST_CTL_WIDTH 1
+#define	FRF_AB_HOT_RST_CTL_LBN 40
+#define	FRF_AB_HOT_RST_CTL_WIDTH 2
+#define	FRF_AB_RST_EXT_PHY_LBN 31
+#define	FRF_AB_RST_EXT_PHY_WIDTH 1
+#define	FRF_AB_RST_XAUI_SD_LBN 30
+#define	FRF_AB_RST_XAUI_SD_WIDTH 1
+#define	FRF_AB_RST_PCIE_SD_LBN 29
+#define	FRF_AB_RST_PCIE_SD_WIDTH 1
+#define	FRF_AA_RST_PCIX_LBN 28
+#define	FRF_AA_RST_PCIX_WIDTH 1
+#define	FRF_BB_RST_BIU_LBN 28
+#define	FRF_BB_RST_BIU_WIDTH 1
+#define	FRF_AB_RST_PCIE_STKY_LBN 27
+#define	FRF_AB_RST_PCIE_STKY_WIDTH 1
+#define	FRF_AB_RST_PCIE_NSTKY_LBN 26
+#define	FRF_AB_RST_PCIE_NSTKY_WIDTH 1
+#define	FRF_AB_RST_PCIE_CORE_LBN 25
+#define	FRF_AB_RST_PCIE_CORE_WIDTH 1
+#define	FRF_AB_RST_XGRX_LBN 24
+#define	FRF_AB_RST_XGRX_WIDTH 1
+#define	FRF_AB_RST_XGTX_LBN 23
+#define	FRF_AB_RST_XGTX_WIDTH 1
+#define	FRF_AB_RST_EM_LBN 22
+#define	FRF_AB_RST_EM_WIDTH 1
+#define	FRF_AB_RST_EV_LBN 21
+#define	FRF_AB_RST_EV_WIDTH 1
+#define	FRF_AB_RST_SR_LBN 20
+#define	FRF_AB_RST_SR_WIDTH 1
+#define	FRF_AB_RST_RX_LBN 19
+#define	FRF_AB_RST_RX_WIDTH 1
+#define	FRF_AB_RST_TX_LBN 18
+#define	FRF_AB_RST_TX_WIDTH 1
+#define	FRF_AB_RST_SF_LBN 17
+#define	FRF_AB_RST_SF_WIDTH 1
+#define	FRF_AB_RST_CS_LBN 16
+#define	FRF_AB_RST_CS_WIDTH 1
+#define	FRF_AB_INT_RST_DUR_LBN 4
+#define	FRF_AB_INT_RST_DUR_WIDTH 3
+#define	FRF_AB_EXT_PHY_RST_DUR_LBN 1
+#define	FRF_AB_EXT_PHY_RST_DUR_WIDTH 3
+#define	FFE_AB_EXT_PHY_RST_DUR_10240US 7
+#define	FFE_AB_EXT_PHY_RST_DUR_5120US 6
+#define	FFE_AB_EXT_PHY_RST_DUR_2560US 5
+#define	FFE_AB_EXT_PHY_RST_DUR_1280US 4
+#define	FFE_AB_EXT_PHY_RST_DUR_640US 3
+#define	FFE_AB_EXT_PHY_RST_DUR_320US 2
+#define	FFE_AB_EXT_PHY_RST_DUR_160US 1
+#define	FFE_AB_EXT_PHY_RST_DUR_80US 0
+#define	FRF_AB_SWRST_LBN 0
+#define	FRF_AB_SWRST_WIDTH 1
+
+/* FATAL_INTR_REG_KER: Fatal interrupt register for Kernel */
+#define	FR_AZ_FATAL_INTR_KER 0x00000230
+#define	FRF_CZ_SRAM_PERR_INT_P_KER_EN_LBN 44
+#define	FRF_CZ_SRAM_PERR_INT_P_KER_EN_WIDTH 1
+#define	FRF_AB_PCI_BUSERR_INT_KER_EN_LBN 43
+#define	FRF_AB_PCI_BUSERR_INT_KER_EN_WIDTH 1
+#define	FRF_CZ_MBU_PERR_INT_KER_EN_LBN 43
+#define	FRF_CZ_MBU_PERR_INT_KER_EN_WIDTH 1
+#define	FRF_AZ_SRAM_OOB_INT_KER_EN_LBN 42
+#define	FRF_AZ_SRAM_OOB_INT_KER_EN_WIDTH 1
+#define	FRF_AZ_BUFID_OOB_INT_KER_EN_LBN 41
+#define	FRF_AZ_BUFID_OOB_INT_KER_EN_WIDTH 1
+#define	FRF_AZ_MEM_PERR_INT_KER_EN_LBN 40
+#define	FRF_AZ_MEM_PERR_INT_KER_EN_WIDTH 1
+#define	FRF_AZ_RBUF_OWN_INT_KER_EN_LBN 39
+#define	FRF_AZ_RBUF_OWN_INT_KER_EN_WIDTH 1
+#define	FRF_AZ_TBUF_OWN_INT_KER_EN_LBN 38
+#define	FRF_AZ_TBUF_OWN_INT_KER_EN_WIDTH 1
+#define	FRF_AZ_RDESCQ_OWN_INT_KER_EN_LBN 37
+#define	FRF_AZ_RDESCQ_OWN_INT_KER_EN_WIDTH 1
+#define	FRF_AZ_TDESCQ_OWN_INT_KER_EN_LBN 36
+#define	FRF_AZ_TDESCQ_OWN_INT_KER_EN_WIDTH 1
+#define	FRF_AZ_EVQ_OWN_INT_KER_EN_LBN 35
+#define	FRF_AZ_EVQ_OWN_INT_KER_EN_WIDTH 1
+#define	FRF_AZ_EVF_OFLO_INT_KER_EN_LBN 34
+#define	FRF_AZ_EVF_OFLO_INT_KER_EN_WIDTH 1
+#define	FRF_AZ_ILL_ADR_INT_KER_EN_LBN 33
+#define	FRF_AZ_ILL_ADR_INT_KER_EN_WIDTH 1
+#define	FRF_AZ_SRM_PERR_INT_KER_EN_LBN 32
+#define	FRF_AZ_SRM_PERR_INT_KER_EN_WIDTH 1
+#define	FRF_CZ_SRAM_PERR_INT_P_KER_LBN 12
+#define	FRF_CZ_SRAM_PERR_INT_P_KER_WIDTH 1
+#define	FRF_AB_PCI_BUSERR_INT_KER_LBN 11
+#define	FRF_AB_PCI_BUSERR_INT_KER_WIDTH 1
+#define	FRF_CZ_MBU_PERR_INT_KER_LBN 11
+#define	FRF_CZ_MBU_PERR_INT_KER_WIDTH 1
+#define	FRF_AZ_SRAM_OOB_INT_KER_LBN 10
+#define	FRF_AZ_SRAM_OOB_INT_KER_WIDTH 1
+#define	FRF_AZ_BUFID_DC_OOB_INT_KER_LBN 9
+#define	FRF_AZ_BUFID_DC_OOB_INT_KER_WIDTH 1
+#define	FRF_AZ_MEM_PERR_INT_KER_LBN 8
+#define	FRF_AZ_MEM_PERR_INT_KER_WIDTH 1
+#define	FRF_AZ_RBUF_OWN_INT_KER_LBN 7
+#define	FRF_AZ_RBUF_OWN_INT_KER_WIDTH 1
+#define	FRF_AZ_TBUF_OWN_INT_KER_LBN 6
+#define	FRF_AZ_TBUF_OWN_INT_KER_WIDTH 1
+#define	FRF_AZ_RDESCQ_OWN_INT_KER_LBN 5
+#define	FRF_AZ_RDESCQ_OWN_INT_KER_WIDTH 1
+#define	FRF_AZ_TDESCQ_OWN_INT_KER_LBN 4
+#define	FRF_AZ_TDESCQ_OWN_INT_KER_WIDTH 1
+#define	FRF_AZ_EVQ_OWN_INT_KER_LBN 3
+#define	FRF_AZ_EVQ_OWN_INT_KER_WIDTH 1
+#define	FRF_AZ_EVF_OFLO_INT_KER_LBN 2
+#define	FRF_AZ_EVF_OFLO_INT_KER_WIDTH 1
+#define	FRF_AZ_ILL_ADR_INT_KER_LBN 1
+#define	FRF_AZ_ILL_ADR_INT_KER_WIDTH 1
+#define	FRF_AZ_SRM_PERR_INT_KER_LBN 0
+#define	FRF_AZ_SRM_PERR_INT_KER_WIDTH 1
+
+/* FATAL_INTR_REG_CHAR: Fatal interrupt register for Char */
+#define	FR_BZ_FATAL_INTR_CHAR 0x00000240
+#define	FRF_CZ_SRAM_PERR_INT_P_CHAR_EN_LBN 44
+#define	FRF_CZ_SRAM_PERR_INT_P_CHAR_EN_WIDTH 1
+#define	FRF_BB_PCI_BUSERR_INT_CHAR_EN_LBN 43
+#define	FRF_BB_PCI_BUSERR_INT_CHAR_EN_WIDTH 1
+#define	FRF_CZ_MBU_PERR_INT_CHAR_EN_LBN 43
+#define	FRF_CZ_MBU_PERR_INT_CHAR_EN_WIDTH 1
+#define	FRF_BZ_SRAM_OOB_INT_CHAR_EN_LBN 42
+#define	FRF_BZ_SRAM_OOB_INT_CHAR_EN_WIDTH 1
+#define	FRF_BZ_BUFID_OOB_INT_CHAR_EN_LBN 41
+#define	FRF_BZ_BUFID_OOB_INT_CHAR_EN_WIDTH 1
+#define	FRF_BZ_MEM_PERR_INT_CHAR_EN_LBN 40
+#define	FRF_BZ_MEM_PERR_INT_CHAR_EN_WIDTH 1
+#define	FRF_BZ_RBUF_OWN_INT_CHAR_EN_LBN 39
+#define	FRF_BZ_RBUF_OWN_INT_CHAR_EN_WIDTH 1
+#define	FRF_BZ_TBUF_OWN_INT_CHAR_EN_LBN 38
+#define	FRF_BZ_TBUF_OWN_INT_CHAR_EN_WIDTH 1
+#define	FRF_BZ_RDESCQ_OWN_INT_CHAR_EN_LBN 37
+#define	FRF_BZ_RDESCQ_OWN_INT_CHAR_EN_WIDTH 1
+#define	FRF_BZ_TDESCQ_OWN_INT_CHAR_EN_LBN 36
+#define	FRF_BZ_TDESCQ_OWN_INT_CHAR_EN_WIDTH 1
+#define	FRF_BZ_EVQ_OWN_INT_CHAR_EN_LBN 35
+#define	FRF_BZ_EVQ_OWN_INT_CHAR_EN_WIDTH 1
+#define	FRF_BZ_EVF_OFLO_INT_CHAR_EN_LBN 34
+#define	FRF_BZ_EVF_OFLO_INT_CHAR_EN_WIDTH 1
+#define	FRF_BZ_ILL_ADR_INT_CHAR_EN_LBN 33
+#define	FRF_BZ_ILL_ADR_INT_CHAR_EN_WIDTH 1
+#define	FRF_BZ_SRM_PERR_INT_CHAR_EN_LBN 32
+#define	FRF_BZ_SRM_PERR_INT_CHAR_EN_WIDTH 1
+#define	FRF_CZ_SRAM_PERR_INT_P_CHAR_LBN 12
+#define	FRF_CZ_SRAM_PERR_INT_P_CHAR_WIDTH 1
+#define	FRF_BB_PCI_BUSERR_INT_CHAR_LBN 11
+#define	FRF_BB_PCI_BUSERR_INT_CHAR_WIDTH 1
+#define	FRF_CZ_MBU_PERR_INT_CHAR_LBN 11
+#define	FRF_CZ_MBU_PERR_INT_CHAR_WIDTH 1
+#define	FRF_BZ_SRAM_OOB_INT_CHAR_LBN 10
+#define	FRF_BZ_SRAM_OOB_INT_CHAR_WIDTH 1
+#define	FRF_BZ_BUFID_DC_OOB_INT_CHAR_LBN 9
+#define	FRF_BZ_BUFID_DC_OOB_INT_CHAR_WIDTH 1
+#define	FRF_BZ_MEM_PERR_INT_CHAR_LBN 8
+#define	FRF_BZ_MEM_PERR_INT_CHAR_WIDTH 1
+#define	FRF_BZ_RBUF_OWN_INT_CHAR_LBN 7
+#define	FRF_BZ_RBUF_OWN_INT_CHAR_WIDTH 1
+#define	FRF_BZ_TBUF_OWN_INT_CHAR_LBN 6
+#define	FRF_BZ_TBUF_OWN_INT_CHAR_WIDTH 1
+#define	FRF_BZ_RDESCQ_OWN_INT_CHAR_LBN 5
+#define	FRF_BZ_RDESCQ_OWN_INT_CHAR_WIDTH 1
+#define	FRF_BZ_TDESCQ_OWN_INT_CHAR_LBN 4
+#define	FRF_BZ_TDESCQ_OWN_INT_CHAR_WIDTH 1
+#define	FRF_BZ_EVQ_OWN_INT_CHAR_LBN 3
+#define	FRF_BZ_EVQ_OWN_INT_CHAR_WIDTH 1
+#define	FRF_BZ_EVF_OFLO_INT_CHAR_LBN 2
+#define	FRF_BZ_EVF_OFLO_INT_CHAR_WIDTH 1
+#define	FRF_BZ_ILL_ADR_INT_CHAR_LBN 1
+#define	FRF_BZ_ILL_ADR_INT_CHAR_WIDTH 1
+#define	FRF_BZ_SRM_PERR_INT_CHAR_LBN 0
+#define	FRF_BZ_SRM_PERR_INT_CHAR_WIDTH 1
+
+/* DP_CTRL_REG: Datapath control register */
+#define	FR_BZ_DP_CTRL 0x00000250
+#define	FRF_BZ_FLS_EVQ_ID_LBN 0
+#define	FRF_BZ_FLS_EVQ_ID_WIDTH 12
+
+/* MEM_STAT_REG: Memory status register */
+#define	FR_AZ_MEM_STAT 0x00000260
+#define	FRF_AB_MEM_PERR_VEC_LBN 53
+#define	FRF_AB_MEM_PERR_VEC_WIDTH 38
+#define	FRF_AB_MBIST_CORR_LBN 38
+#define	FRF_AB_MBIST_CORR_WIDTH 15
+#define	FRF_AB_MBIST_ERR_LBN 0
+#define	FRF_AB_MBIST_ERR_WIDTH 40
+#define	FRF_CZ_MEM_PERR_VEC_LBN 0
+#define	FRF_CZ_MEM_PERR_VEC_WIDTH 35
+
+/* CS_DEBUG_REG: Debug register */
+#define	FR_AZ_CS_DEBUG 0x00000270
+#define	FRF_AB_GLB_DEBUG2_SEL_LBN 50
+#define	FRF_AB_GLB_DEBUG2_SEL_WIDTH 3
+#define	FRF_AB_DEBUG_BLK_SEL2_LBN 47
+#define	FRF_AB_DEBUG_BLK_SEL2_WIDTH 3
+#define	FRF_AB_DEBUG_BLK_SEL1_LBN 44
+#define	FRF_AB_DEBUG_BLK_SEL1_WIDTH 3
+#define	FRF_AB_DEBUG_BLK_SEL0_LBN 41
+#define	FRF_AB_DEBUG_BLK_SEL0_WIDTH 3
+#define	FRF_CZ_CS_PORT_NUM_LBN 40
+#define	FRF_CZ_CS_PORT_NUM_WIDTH 2
+#define	FRF_AB_MISC_DEBUG_ADDR_LBN 36
+#define	FRF_AB_MISC_DEBUG_ADDR_WIDTH 5
+#define	FRF_AB_SERDES_DEBUG_ADDR_LBN 31
+#define	FRF_AB_SERDES_DEBUG_ADDR_WIDTH 5
+#define	FRF_CZ_CS_PORT_FPE_LBN 1
+#define	FRF_CZ_CS_PORT_FPE_WIDTH 35
+#define	FRF_AB_EM_DEBUG_ADDR_LBN 26
+#define	FRF_AB_EM_DEBUG_ADDR_WIDTH 5
+#define	FRF_AB_SR_DEBUG_ADDR_LBN 21
+#define	FRF_AB_SR_DEBUG_ADDR_WIDTH 5
+#define	FRF_AB_EV_DEBUG_ADDR_LBN 16
+#define	FRF_AB_EV_DEBUG_ADDR_WIDTH 5
+#define	FRF_AB_RX_DEBUG_ADDR_LBN 11
+#define	FRF_AB_RX_DEBUG_ADDR_WIDTH 5
+#define	FRF_AB_TX_DEBUG_ADDR_LBN 6
+#define	FRF_AB_TX_DEBUG_ADDR_WIDTH 5
+#define	FRF_AB_CS_BIU_DEBUG_ADDR_LBN 1
+#define	FRF_AB_CS_BIU_DEBUG_ADDR_WIDTH 5
+#define	FRF_AZ_CS_DEBUG_EN_LBN 0
+#define	FRF_AZ_CS_DEBUG_EN_WIDTH 1
+
+/* DRIVER_REG: Driver scratch register [0-7] */
+#define	FR_AZ_DRIVER 0x00000280
+#define	FR_AZ_DRIVER_STEP 16
+#define	FR_AZ_DRIVER_ROWS 8
+#define	FRF_AZ_DRIVER_DW0_LBN 0
+#define	FRF_AZ_DRIVER_DW0_WIDTH 32
+
+/* ALTERA_BUILD_REG: Altera build register */
+#define	FR_AZ_ALTERA_BUILD 0x00000300
+#define	FRF_AZ_ALTERA_BUILD_VER_LBN 0
+#define	FRF_AZ_ALTERA_BUILD_VER_WIDTH 32
+
+/* CSR_SPARE_REG: Spare register */
+#define	FR_AZ_CSR_SPARE 0x00000310
+#define	FRF_AB_MEM_PERR_EN_LBN 64
+#define	FRF_AB_MEM_PERR_EN_WIDTH 38
+#define	FRF_CZ_MEM_PERR_EN_LBN 64
+#define	FRF_CZ_MEM_PERR_EN_WIDTH 35
+#define	FRF_AB_MEM_PERR_EN_TX_DATA_LBN 72
+#define	FRF_AB_MEM_PERR_EN_TX_DATA_WIDTH 2
+#define	FRF_AZ_CSR_SPARE_BITS_LBN 0
+#define	FRF_AZ_CSR_SPARE_BITS_WIDTH 32
+
+/* PCIE_SD_CTL0123_REG: PCIE SerDes control register 0 to 3 */
+#define	FR_AB_PCIE_SD_CTL0123 0x00000320
+#define	FRF_AB_PCIE_TESTSIG_H_LBN 96
+#define	FRF_AB_PCIE_TESTSIG_H_WIDTH 19
+#define	FRF_AB_PCIE_TESTSIG_L_LBN 64
+#define	FRF_AB_PCIE_TESTSIG_L_WIDTH 19
+#define	FRF_AB_PCIE_OFFSET_LBN 56
+#define	FRF_AB_PCIE_OFFSET_WIDTH 8
+#define	FRF_AB_PCIE_OFFSETEN_H_LBN 55
+#define	FRF_AB_PCIE_OFFSETEN_H_WIDTH 1
+#define	FRF_AB_PCIE_OFFSETEN_L_LBN 54
+#define	FRF_AB_PCIE_OFFSETEN_L_WIDTH 1
+#define	FRF_AB_PCIE_HIVMODE_H_LBN 53
+#define	FRF_AB_PCIE_HIVMODE_H_WIDTH 1
+#define	FRF_AB_PCIE_HIVMODE_L_LBN 52
+#define	FRF_AB_PCIE_HIVMODE_L_WIDTH 1
+#define	FRF_AB_PCIE_PARRESET_H_LBN 51
+#define	FRF_AB_PCIE_PARRESET_H_WIDTH 1
+#define	FRF_AB_PCIE_PARRESET_L_LBN 50
+#define	FRF_AB_PCIE_PARRESET_L_WIDTH 1
+#define	FRF_AB_PCIE_LPBKWDRV_H_LBN 49
+#define	FRF_AB_PCIE_LPBKWDRV_H_WIDTH 1
+#define	FRF_AB_PCIE_LPBKWDRV_L_LBN 48
+#define	FRF_AB_PCIE_LPBKWDRV_L_WIDTH 1
+#define	FRF_AB_PCIE_LPBK_LBN 40
+#define	FRF_AB_PCIE_LPBK_WIDTH 8
+#define	FRF_AB_PCIE_PARLPBK_LBN 32
+#define	FRF_AB_PCIE_PARLPBK_WIDTH 8
+#define	FRF_AB_PCIE_RXTERMADJ_H_LBN 30
+#define	FRF_AB_PCIE_RXTERMADJ_H_WIDTH 2
+#define	FRF_AB_PCIE_RXTERMADJ_L_LBN 28
+#define	FRF_AB_PCIE_RXTERMADJ_L_WIDTH 2
+#define	FFE_AB_PCIE_RXTERMADJ_MIN15PCNT 3
+#define	FFE_AB_PCIE_RXTERMADJ_PL10PCNT 2
+#define	FFE_AB_PCIE_RXTERMADJ_MIN17PCNT 1
+#define	FFE_AB_PCIE_RXTERMADJ_NOMNL 0
+#define	FRF_AB_PCIE_TXTERMADJ_H_LBN 26
+#define	FRF_AB_PCIE_TXTERMADJ_H_WIDTH 2
+#define	FRF_AB_PCIE_TXTERMADJ_L_LBN 24
+#define	FRF_AB_PCIE_TXTERMADJ_L_WIDTH 2
+#define	FFE_AB_PCIE_TXTERMADJ_MIN15PCNT 3
+#define	FFE_AB_PCIE_TXTERMADJ_PL10PCNT 2
+#define	FFE_AB_PCIE_TXTERMADJ_MIN17PCNT 1
+#define	FFE_AB_PCIE_TXTERMADJ_NOMNL 0
+#define	FRF_AB_PCIE_RXEQCTL_H_LBN 18
+#define	FRF_AB_PCIE_RXEQCTL_H_WIDTH 2
+#define	FRF_AB_PCIE_RXEQCTL_L_LBN 16
+#define	FRF_AB_PCIE_RXEQCTL_L_WIDTH 2
+#define	FFE_AB_PCIE_RXEQCTL_OFF_ALT 3
+#define	FFE_AB_PCIE_RXEQCTL_OFF 2
+#define	FFE_AB_PCIE_RXEQCTL_MIN 1
+#define	FFE_AB_PCIE_RXEQCTL_MAX 0
+#define	FRF_AB_PCIE_HIDRV_LBN 8
+#define	FRF_AB_PCIE_HIDRV_WIDTH 8
+#define	FRF_AB_PCIE_LODRV_LBN 0
+#define	FRF_AB_PCIE_LODRV_WIDTH 8
+
+/* PCIE_SD_CTL45_REG: PCIE SerDes control register 4 and 5 */
+#define	FR_AB_PCIE_SD_CTL45 0x00000330
+#define	FRF_AB_PCIE_DTX7_LBN 60
+#define	FRF_AB_PCIE_DTX7_WIDTH 4
+#define	FRF_AB_PCIE_DTX6_LBN 56
+#define	FRF_AB_PCIE_DTX6_WIDTH 4
+#define	FRF_AB_PCIE_DTX5_LBN 52
+#define	FRF_AB_PCIE_DTX5_WIDTH 4
+#define	FRF_AB_PCIE_DTX4_LBN 48
+#define	FRF_AB_PCIE_DTX4_WIDTH 4
+#define	FRF_AB_PCIE_DTX3_LBN 44
+#define	FRF_AB_PCIE_DTX3_WIDTH 4
+#define	FRF_AB_PCIE_DTX2_LBN 40
+#define	FRF_AB_PCIE_DTX2_WIDTH 4
+#define	FRF_AB_PCIE_DTX1_LBN 36
+#define	FRF_AB_PCIE_DTX1_WIDTH 4
+#define	FRF_AB_PCIE_DTX0_LBN 32
+#define	FRF_AB_PCIE_DTX0_WIDTH 4
+#define	FRF_AB_PCIE_DEQ7_LBN 28
+#define	FRF_AB_PCIE_DEQ7_WIDTH 4
+#define	FRF_AB_PCIE_DEQ6_LBN 24
+#define	FRF_AB_PCIE_DEQ6_WIDTH 4
+#define	FRF_AB_PCIE_DEQ5_LBN 20
+#define	FRF_AB_PCIE_DEQ5_WIDTH 4
+#define	FRF_AB_PCIE_DEQ4_LBN 16
+#define	FRF_AB_PCIE_DEQ4_WIDTH 4
+#define	FRF_AB_PCIE_DEQ3_LBN 12
+#define	FRF_AB_PCIE_DEQ3_WIDTH 4
+#define	FRF_AB_PCIE_DEQ2_LBN 8
+#define	FRF_AB_PCIE_DEQ2_WIDTH 4
+#define	FRF_AB_PCIE_DEQ1_LBN 4
+#define	FRF_AB_PCIE_DEQ1_WIDTH 4
+#define	FRF_AB_PCIE_DEQ0_LBN 0
+#define	FRF_AB_PCIE_DEQ0_WIDTH 4
+
+/* PCIE_PCS_CTL_STAT_REG: PCIE PCS control and status register */
+#define	FR_AB_PCIE_PCS_CTL_STAT 0x00000340
+#define	FRF_AB_PCIE_PRBSERRCOUNT0_H_LBN 52
+#define	FRF_AB_PCIE_PRBSERRCOUNT0_H_WIDTH 4
+#define	FRF_AB_PCIE_PRBSERRCOUNT0_L_LBN 48
+#define	FRF_AB_PCIE_PRBSERRCOUNT0_L_WIDTH 4
+#define	FRF_AB_PCIE_PRBSERR_LBN 40
+#define	FRF_AB_PCIE_PRBSERR_WIDTH 8
+#define	FRF_AB_PCIE_PRBSERRH0_LBN 32
+#define	FRF_AB_PCIE_PRBSERRH0_WIDTH 8
+#define	FRF_AB_PCIE_FASTINIT_H_LBN 15
+#define	FRF_AB_PCIE_FASTINIT_H_WIDTH 1
+#define	FRF_AB_PCIE_FASTINIT_L_LBN 14
+#define	FRF_AB_PCIE_FASTINIT_L_WIDTH 1
+#define	FRF_AB_PCIE_CTCDISABLE_H_LBN 13
+#define	FRF_AB_PCIE_CTCDISABLE_H_WIDTH 1
+#define	FRF_AB_PCIE_CTCDISABLE_L_LBN 12
+#define	FRF_AB_PCIE_CTCDISABLE_L_WIDTH 1
+#define	FRF_AB_PCIE_PRBSSYNC_H_LBN 11
+#define	FRF_AB_PCIE_PRBSSYNC_H_WIDTH 1
+#define	FRF_AB_PCIE_PRBSSYNC_L_LBN 10
+#define	FRF_AB_PCIE_PRBSSYNC_L_WIDTH 1
+#define	FRF_AB_PCIE_PRBSERRACK_H_LBN 9
+#define	FRF_AB_PCIE_PRBSERRACK_H_WIDTH 1
+#define	FRF_AB_PCIE_PRBSERRACK_L_LBN 8
+#define	FRF_AB_PCIE_PRBSERRACK_L_WIDTH 1
+#define	FRF_AB_PCIE_PRBSSEL_LBN 0
+#define	FRF_AB_PCIE_PRBSSEL_WIDTH 8
+
+/* DEBUG_DATA_OUT_REG: Live Debug and Debug 2 out ports */
+#define	FR_BB_DEBUG_DATA_OUT 0x00000350
+#define	FRF_BB_DEBUG2_PORT_LBN 25
+#define	FRF_BB_DEBUG2_PORT_WIDTH 15
+#define	FRF_BB_DEBUG1_PORT_LBN 0
+#define	FRF_BB_DEBUG1_PORT_WIDTH 25
+
+/* EVQ_RPTR_REGP0: Event queue read pointer register */
+#define	FR_BZ_EVQ_RPTR_P0 0x00000400
+#define	FR_BZ_EVQ_RPTR_P0_STEP 8192
+#define	FR_BZ_EVQ_RPTR_P0_ROWS 1024
+/* EVQ_RPTR_REG_KER: Event queue read pointer register */
+#define	FR_AA_EVQ_RPTR_KER 0x00011b00
+#define	FR_AA_EVQ_RPTR_KER_STEP 4
+#define	FR_AA_EVQ_RPTR_KER_ROWS 4
+/* EVQ_RPTR_REG: Event queue read pointer register */
+#define	FR_BZ_EVQ_RPTR 0x00fa0000
+#define	FR_BZ_EVQ_RPTR_STEP 16
+#define	FR_BB_EVQ_RPTR_ROWS 4096
+#define	FR_CZ_EVQ_RPTR_ROWS 1024
+/* EVQ_RPTR_REGP123: Event queue read pointer register */
+#define	FR_BB_EVQ_RPTR_P123 0x01000400
+#define	FR_BB_EVQ_RPTR_P123_STEP 8192
+#define	FR_BB_EVQ_RPTR_P123_ROWS 3072
+#define	FRF_AZ_EVQ_RPTR_VLD_LBN 15
+#define	FRF_AZ_EVQ_RPTR_VLD_WIDTH 1
+#define	FRF_AZ_EVQ_RPTR_LBN 0
+#define	FRF_AZ_EVQ_RPTR_WIDTH 15
+
+/* TIMER_COMMAND_REGP0: Timer Command Registers */
+#define	FR_BZ_TIMER_COMMAND_P0 0x00000420
+#define	FR_BZ_TIMER_COMMAND_P0_STEP 8192
+#define	FR_BZ_TIMER_COMMAND_P0_ROWS 1024
+/* TIMER_COMMAND_REG_KER: Timer Command Registers */
+#define	FR_AA_TIMER_COMMAND_KER 0x00000420
+#define	FR_AA_TIMER_COMMAND_KER_STEP 8192
+#define	FR_AA_TIMER_COMMAND_KER_ROWS 4
+/* TIMER_COMMAND_REGP123: Timer Command Registers */
+#define	FR_BB_TIMER_COMMAND_P123 0x01000420
+#define	FR_BB_TIMER_COMMAND_P123_STEP 8192
+#define	FR_BB_TIMER_COMMAND_P123_ROWS 3072
+#define	FRF_CZ_TC_TIMER_MODE_LBN 14
+#define	FRF_CZ_TC_TIMER_MODE_WIDTH 2
+#define	FRF_AB_TC_TIMER_MODE_LBN 12
+#define	FRF_AB_TC_TIMER_MODE_WIDTH 2
+#define	FRF_CZ_TC_TIMER_VAL_LBN 0
+#define	FRF_CZ_TC_TIMER_VAL_WIDTH 14
+#define	FRF_AB_TC_TIMER_VAL_LBN 0
+#define	FRF_AB_TC_TIMER_VAL_WIDTH 12
+
+/* DRV_EV_REG: Driver generated event register */
+#define	FR_AZ_DRV_EV 0x00000440
+#define	FRF_AZ_DRV_EV_QID_LBN 64
+#define	FRF_AZ_DRV_EV_QID_WIDTH 12
+#define	FRF_AZ_DRV_EV_DATA_LBN 0
+#define	FRF_AZ_DRV_EV_DATA_WIDTH 64
+
+/* EVQ_CTL_REG: Event queue control register */
+#define	FR_AZ_EVQ_CTL 0x00000450
+#define	FRF_CZ_RX_EVQ_WAKEUP_MASK_LBN 15
+#define	FRF_CZ_RX_EVQ_WAKEUP_MASK_WIDTH 10
+#define	FRF_BB_RX_EVQ_WAKEUP_MASK_LBN 15
+#define	FRF_BB_RX_EVQ_WAKEUP_MASK_WIDTH 6
+#define	FRF_AZ_EVQ_OWNERR_CTL_LBN 14
+#define	FRF_AZ_EVQ_OWNERR_CTL_WIDTH 1
+#define	FRF_AZ_EVQ_FIFO_AF_TH_LBN 7
+#define	FRF_AZ_EVQ_FIFO_AF_TH_WIDTH 7
+#define	FRF_AZ_EVQ_FIFO_NOTAF_TH_LBN 0
+#define	FRF_AZ_EVQ_FIFO_NOTAF_TH_WIDTH 7
+
+/* EVQ_CNT1_REG: Event counter 1 register */
+#define	FR_AZ_EVQ_CNT1 0x00000460
+#define	FRF_AZ_EVQ_CNT_PRE_FIFO_LBN 120
+#define	FRF_AZ_EVQ_CNT_PRE_FIFO_WIDTH 7
+#define	FRF_AZ_EVQ_CNT_TOBIU_LBN 100
+#define	FRF_AZ_EVQ_CNT_TOBIU_WIDTH 20
+#define	FRF_AZ_EVQ_TX_REQ_CNT_LBN 80
+#define	FRF_AZ_EVQ_TX_REQ_CNT_WIDTH 20
+#define	FRF_AZ_EVQ_RX_REQ_CNT_LBN 60
+#define	FRF_AZ_EVQ_RX_REQ_CNT_WIDTH 20
+#define	FRF_AZ_EVQ_EM_REQ_CNT_LBN 40
+#define	FRF_AZ_EVQ_EM_REQ_CNT_WIDTH 20
+#define	FRF_AZ_EVQ_CSR_REQ_CNT_LBN 20
+#define	FRF_AZ_EVQ_CSR_REQ_CNT_WIDTH 20
+#define	FRF_AZ_EVQ_ERR_REQ_CNT_LBN 0
+#define	FRF_AZ_EVQ_ERR_REQ_CNT_WIDTH 20
+
+/* EVQ_CNT2_REG: Event counter 2 register */
+#define	FR_AZ_EVQ_CNT2 0x00000470
+#define	FRF_AZ_EVQ_UPD_REQ_CNT_LBN 104
+#define	FRF_AZ_EVQ_UPD_REQ_CNT_WIDTH 20
+#define	FRF_AZ_EVQ_CLR_REQ_CNT_LBN 84
+#define	FRF_AZ_EVQ_CLR_REQ_CNT_WIDTH 20
+#define	FRF_AZ_EVQ_RDY_CNT_LBN 80
+#define	FRF_AZ_EVQ_RDY_CNT_WIDTH 4
+#define	FRF_AZ_EVQ_WU_REQ_CNT_LBN 60
+#define	FRF_AZ_EVQ_WU_REQ_CNT_WIDTH 20
+#define	FRF_AZ_EVQ_WET_REQ_CNT_LBN 40
+#define	FRF_AZ_EVQ_WET_REQ_CNT_WIDTH 20
+#define	FRF_AZ_EVQ_INIT_REQ_CNT_LBN 20
+#define	FRF_AZ_EVQ_INIT_REQ_CNT_WIDTH 20
+#define	FRF_AZ_EVQ_TM_REQ_CNT_LBN 0
+#define	FRF_AZ_EVQ_TM_REQ_CNT_WIDTH 20
+
+/* USR_EV_REG: Event mailbox register */
+#define	FR_CZ_USR_EV 0x00000540
+#define	FR_CZ_USR_EV_STEP 8192
+#define	FR_CZ_USR_EV_ROWS 1024
+#define	FRF_CZ_USR_EV_DATA_LBN 0
+#define	FRF_CZ_USR_EV_DATA_WIDTH 32
+
+/* BUF_TBL_CFG_REG: Buffer table configuration register */
+#define	FR_AZ_BUF_TBL_CFG 0x00000600
+#define	FRF_AZ_BUF_TBL_MODE_LBN 3
+#define	FRF_AZ_BUF_TBL_MODE_WIDTH 1
+
+/* SRM_RX_DC_CFG_REG: SRAM receive descriptor cache configuration register */
+#define	FR_AZ_SRM_RX_DC_CFG 0x00000610
+#define	FRF_AZ_SRM_CLK_TMP_EN_LBN 21
+#define	FRF_AZ_SRM_CLK_TMP_EN_WIDTH 1
+#define	FRF_AZ_SRM_RX_DC_BASE_ADR_LBN 0
+#define	FRF_AZ_SRM_RX_DC_BASE_ADR_WIDTH 21
+
+/* SRM_TX_DC_CFG_REG: SRAM transmit descriptor cache configuration register */
+#define	FR_AZ_SRM_TX_DC_CFG 0x00000620
+#define	FRF_AZ_SRM_TX_DC_BASE_ADR_LBN 0
+#define	FRF_AZ_SRM_TX_DC_BASE_ADR_WIDTH 21
+
+/* SRM_CFG_REG: SRAM configuration register */
+#define	FR_AZ_SRM_CFG 0x00000630
+#define	FRF_AZ_SRM_OOB_ADR_INTEN_LBN 5
+#define	FRF_AZ_SRM_OOB_ADR_INTEN_WIDTH 1
+#define	FRF_AZ_SRM_OOB_BUF_INTEN_LBN 4
+#define	FRF_AZ_SRM_OOB_BUF_INTEN_WIDTH 1
+#define	FRF_AZ_SRM_INIT_EN_LBN 3
+#define	FRF_AZ_SRM_INIT_EN_WIDTH 1
+#define	FRF_AZ_SRM_NUM_BANK_LBN 2
+#define	FRF_AZ_SRM_NUM_BANK_WIDTH 1
+#define	FRF_AZ_SRM_BANK_SIZE_LBN 0
+#define	FRF_AZ_SRM_BANK_SIZE_WIDTH 2
+
+/* BUF_TBL_UPD_REG: Buffer table update register */
+#define	FR_AZ_BUF_TBL_UPD 0x00000650
+#define	FRF_AZ_BUF_UPD_CMD_LBN 63
+#define	FRF_AZ_BUF_UPD_CMD_WIDTH 1
+#define	FRF_AZ_BUF_CLR_CMD_LBN 62
+#define	FRF_AZ_BUF_CLR_CMD_WIDTH 1
+#define	FRF_AZ_BUF_CLR_END_ID_LBN 32
+#define	FRF_AZ_BUF_CLR_END_ID_WIDTH 20
+#define	FRF_AZ_BUF_CLR_START_ID_LBN 0
+#define	FRF_AZ_BUF_CLR_START_ID_WIDTH 20
+
+/* SRM_UPD_EVQ_REG: Buffer table update register */
+#define	FR_AZ_SRM_UPD_EVQ 0x00000660
+#define	FRF_AZ_SRM_UPD_EVQ_ID_LBN 0
+#define	FRF_AZ_SRM_UPD_EVQ_ID_WIDTH 12
+
+/* SRAM_PARITY_REG: SRAM parity register. */
+#define	FR_AZ_SRAM_PARITY 0x00000670
+#define	FRF_CZ_BYPASS_ECC_LBN 3
+#define	FRF_CZ_BYPASS_ECC_WIDTH 1
+#define	FRF_CZ_SEC_INT_LBN 2
+#define	FRF_CZ_SEC_INT_WIDTH 1
+#define	FRF_CZ_FORCE_SRAM_DOUBLE_ERR_LBN 1
+#define	FRF_CZ_FORCE_SRAM_DOUBLE_ERR_WIDTH 1
+#define	FRF_AB_FORCE_SRAM_PERR_LBN 0
+#define	FRF_AB_FORCE_SRAM_PERR_WIDTH 1
+#define	FRF_CZ_FORCE_SRAM_SINGLE_ERR_LBN 0
+#define	FRF_CZ_FORCE_SRAM_SINGLE_ERR_WIDTH 1
+
+/* RX_CFG_REG: Receive configuration register */
+#define	FR_AZ_RX_CFG 0x00000800
+#define	FRF_CZ_RX_MIN_KBUF_SIZE_LBN 72
+#define	FRF_CZ_RX_MIN_KBUF_SIZE_WIDTH 14
+#define	FRF_CZ_RX_HDR_SPLIT_EN_LBN 71
+#define	FRF_CZ_RX_HDR_SPLIT_EN_WIDTH 1
+#define	FRF_CZ_RX_HDR_SPLIT_PLD_BUF_SIZE_LBN 62
+#define	FRF_CZ_RX_HDR_SPLIT_PLD_BUF_SIZE_WIDTH 9
+#define	FRF_CZ_RX_HDR_SPLIT_HDR_BUF_SIZE_LBN 53
+#define	FRF_CZ_RX_HDR_SPLIT_HDR_BUF_SIZE_WIDTH 9
+#define	FRF_CZ_RX_PRE_RFF_IPG_LBN 49
+#define	FRF_CZ_RX_PRE_RFF_IPG_WIDTH 4
+#define	FRF_BZ_RX_TCP_SUP_LBN 48
+#define	FRF_BZ_RX_TCP_SUP_WIDTH 1
+#define	FRF_BZ_RX_INGR_EN_LBN 47
+#define	FRF_BZ_RX_INGR_EN_WIDTH 1
+#define	FRF_BZ_RX_IP_HASH_LBN 46
+#define	FRF_BZ_RX_IP_HASH_WIDTH 1
+#define	FRF_BZ_RX_HASH_ALG_LBN 45
+#define	FRF_BZ_RX_HASH_ALG_WIDTH 1
+#define	FRF_BZ_RX_HASH_INSRT_HDR_LBN 44
+#define	FRF_BZ_RX_HASH_INSRT_HDR_WIDTH 1
+#define	FRF_BZ_RX_DESC_PUSH_EN_LBN 43
+#define	FRF_BZ_RX_DESC_PUSH_EN_WIDTH 1
+#define	FRF_BZ_RX_RDW_PATCH_EN_LBN 42
+#define	FRF_BZ_RX_RDW_PATCH_EN_WIDTH 1
+#define	FRF_BB_RX_PCI_BURST_SIZE_LBN 39
+#define	FRF_BB_RX_PCI_BURST_SIZE_WIDTH 3
+#define	FRF_BZ_RX_OWNERR_CTL_LBN 38
+#define	FRF_BZ_RX_OWNERR_CTL_WIDTH 1
+#define	FRF_BZ_RX_XON_TX_TH_LBN 33
+#define	FRF_BZ_RX_XON_TX_TH_WIDTH 5
+#define	FRF_AA_RX_DESC_PUSH_EN_LBN 35
+#define	FRF_AA_RX_DESC_PUSH_EN_WIDTH 1
+#define	FRF_AA_RX_RDW_PATCH_EN_LBN 34
+#define	FRF_AA_RX_RDW_PATCH_EN_WIDTH 1
+#define	FRF_AA_RX_PCI_BURST_SIZE_LBN 31
+#define	FRF_AA_RX_PCI_BURST_SIZE_WIDTH 3
+#define	FRF_BZ_RX_XOFF_TX_TH_LBN 28
+#define	FRF_BZ_RX_XOFF_TX_TH_WIDTH 5
+#define	FRF_AA_RX_OWNERR_CTL_LBN 30
+#define	FRF_AA_RX_OWNERR_CTL_WIDTH 1
+#define	FRF_AA_RX_XON_TX_TH_LBN 25
+#define	FRF_AA_RX_XON_TX_TH_WIDTH 5
+#define	FRF_BZ_RX_USR_BUF_SIZE_LBN 19
+#define	FRF_BZ_RX_USR_BUF_SIZE_WIDTH 9
+#define	FRF_AA_RX_XOFF_TX_TH_LBN 20
+#define	FRF_AA_RX_XOFF_TX_TH_WIDTH 5
+#define	FRF_AA_RX_USR_BUF_SIZE_LBN 11
+#define	FRF_AA_RX_USR_BUF_SIZE_WIDTH 9
+#define	FRF_BZ_RX_XON_MAC_TH_LBN 10
+#define	FRF_BZ_RX_XON_MAC_TH_WIDTH 9
+#define	FRF_AA_RX_XON_MAC_TH_LBN 6
+#define	FRF_AA_RX_XON_MAC_TH_WIDTH 5
+#define	FRF_BZ_RX_XOFF_MAC_TH_LBN 1
+#define	FRF_BZ_RX_XOFF_MAC_TH_WIDTH 9
+#define	FRF_AA_RX_XOFF_MAC_TH_LBN 1
+#define	FRF_AA_RX_XOFF_MAC_TH_WIDTH 5
+#define	FRF_AZ_RX_XOFF_MAC_EN_LBN 0
+#define	FRF_AZ_RX_XOFF_MAC_EN_WIDTH 1
+
+/* RX_FILTER_CTL_REG: Receive filter control registers */
+#define	FR_BZ_RX_FILTER_CTL 0x00000810
+#define	FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT_LBN 94
+#define	FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT_WIDTH 8
+#define	FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT_LBN 86
+#define	FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT_WIDTH 8
+#define	FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES_LBN 85
+#define	FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES_WIDTH 1
+#define	FRF_CZ_RX_VLAN_MATCH_ETHERTYPE_LBN 69
+#define	FRF_CZ_RX_VLAN_MATCH_ETHERTYPE_WIDTH 16
+#define	FRF_CZ_MULTICAST_NOMATCH_Q_ID_LBN 57
+#define	FRF_CZ_MULTICAST_NOMATCH_Q_ID_WIDTH 12
+#define	FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED_LBN 56
+#define	FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED_WIDTH 1
+#define	FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE_LBN 55
+#define	FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE_WIDTH 1
+#define	FRF_CZ_UNICAST_NOMATCH_Q_ID_LBN 43
+#define	FRF_CZ_UNICAST_NOMATCH_Q_ID_WIDTH 12
+#define	FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED_LBN 42
+#define	FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED_WIDTH 1
+#define	FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE_LBN 41
+#define	FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE_WIDTH 1
+#define	FRF_BZ_SCATTER_ENBL_NO_MATCH_Q_LBN 40
+#define	FRF_BZ_SCATTER_ENBL_NO_MATCH_Q_WIDTH 1
+#define	FRF_BZ_UDP_FULL_SRCH_LIMIT_LBN 32
+#define	FRF_BZ_UDP_FULL_SRCH_LIMIT_WIDTH 8
+#define	FRF_BZ_NUM_KER_LBN 24
+#define	FRF_BZ_NUM_KER_WIDTH 2
+#define	FRF_BZ_UDP_WILD_SRCH_LIMIT_LBN 16
+#define	FRF_BZ_UDP_WILD_SRCH_LIMIT_WIDTH 8
+#define	FRF_BZ_TCP_WILD_SRCH_LIMIT_LBN 8
+#define	FRF_BZ_TCP_WILD_SRCH_LIMIT_WIDTH 8
+#define	FRF_BZ_TCP_FULL_SRCH_LIMIT_LBN 0
+#define	FRF_BZ_TCP_FULL_SRCH_LIMIT_WIDTH 8
+
+/* RX_FLUSH_DESCQ_REG: Receive flush descriptor queue register */
+#define	FR_AZ_RX_FLUSH_DESCQ 0x00000820
+#define	FRF_AZ_RX_FLUSH_DESCQ_CMD_LBN 24
+#define	FRF_AZ_RX_FLUSH_DESCQ_CMD_WIDTH 1
+#define	FRF_AZ_RX_FLUSH_DESCQ_LBN 0
+#define	FRF_AZ_RX_FLUSH_DESCQ_WIDTH 12
+
+/* RX_DESC_UPD_REGP0: Receive descriptor update register. */
+#define	FR_BZ_RX_DESC_UPD_P0 0x00000830
+#define	FR_BZ_RX_DESC_UPD_P0_STEP 8192
+#define	FR_BZ_RX_DESC_UPD_P0_ROWS 1024
+/* RX_DESC_UPD_REG_KER: Receive descriptor update register. */
+#define	FR_AA_RX_DESC_UPD_KER 0x00000830
+#define	FR_AA_RX_DESC_UPD_KER_STEP 8192
+#define	FR_AA_RX_DESC_UPD_KER_ROWS 4
+/* RX_DESC_UPD_REGP123: Receive descriptor update register. */
+#define	FR_BB_RX_DESC_UPD_P123 0x01000830
+#define	FR_BB_RX_DESC_UPD_P123_STEP 8192
+#define	FR_BB_RX_DESC_UPD_P123_ROWS 3072
+#define	FRF_AZ_RX_DESC_WPTR_LBN 96
+#define	FRF_AZ_RX_DESC_WPTR_WIDTH 12
+#define	FRF_AZ_RX_DESC_PUSH_CMD_LBN 95
+#define	FRF_AZ_RX_DESC_PUSH_CMD_WIDTH 1
+#define	FRF_AZ_RX_DESC_LBN 0
+#define	FRF_AZ_RX_DESC_WIDTH 64
+
+/* RX_DC_CFG_REG: Receive descriptor cache configuration register */
+#define	FR_AZ_RX_DC_CFG 0x00000840
+#define	FRF_AB_RX_MAX_PF_LBN 2
+#define	FRF_AB_RX_MAX_PF_WIDTH 2
+#define	FRF_AZ_RX_DC_SIZE_LBN 0
+#define	FRF_AZ_RX_DC_SIZE_WIDTH 2
+#define	FFE_AZ_RX_DC_SIZE_64 3
+#define	FFE_AZ_RX_DC_SIZE_32 2
+#define	FFE_AZ_RX_DC_SIZE_16 1
+#define	FFE_AZ_RX_DC_SIZE_8 0
+
+/* RX_DC_PF_WM_REG: Receive descriptor cache pre-fetch watermark register */
+#define	FR_AZ_RX_DC_PF_WM 0x00000850
+#define	FRF_AZ_RX_DC_PF_HWM_LBN 6
+#define	FRF_AZ_RX_DC_PF_HWM_WIDTH 6
+#define	FRF_AZ_RX_DC_PF_LWM_LBN 0
+#define	FRF_AZ_RX_DC_PF_LWM_WIDTH 6
+
+/* RX_RSS_TKEY_REG: RSS Toeplitz hash key */
+#define	FR_BZ_RX_RSS_TKEY 0x00000860
+#define	FRF_BZ_RX_RSS_TKEY_HI_LBN 64
+#define	FRF_BZ_RX_RSS_TKEY_HI_WIDTH 64
+#define	FRF_BZ_RX_RSS_TKEY_LO_LBN 0
+#define	FRF_BZ_RX_RSS_TKEY_LO_WIDTH 64
+
+/* RX_NODESC_DROP_REG: Receive dropped packet counter register */
+#define	FR_AZ_RX_NODESC_DROP 0x00000880
+#define	FRF_CZ_RX_NODESC_DROP_CNT_LBN 0
+#define	FRF_CZ_RX_NODESC_DROP_CNT_WIDTH 32
+#define	FRF_AB_RX_NODESC_DROP_CNT_LBN 0
+#define	FRF_AB_RX_NODESC_DROP_CNT_WIDTH 16
+
+/* RX_SELF_RST_REG: Receive self reset register */
+#define	FR_AA_RX_SELF_RST 0x00000890
+#define	FRF_AA_RX_ISCSI_DIS_LBN 17
+#define	FRF_AA_RX_ISCSI_DIS_WIDTH 1
+#define	FRF_AA_RX_SW_RST_REG_LBN 16
+#define	FRF_AA_RX_SW_RST_REG_WIDTH 1
+#define FRF_AA_RX_NODESC_WAIT_DIS_LBN 9
+#define FRF_AA_RX_NODESC_WAIT_DIS_WIDTH 1
+#define	FRF_AA_RX_SELF_RST_EN_LBN 8
+#define	FRF_AA_RX_SELF_RST_EN_WIDTH 1
+#define	FRF_AA_RX_MAX_PF_LAT_LBN 4
+#define	FRF_AA_RX_MAX_PF_LAT_WIDTH 4
+#define	FRF_AA_RX_MAX_LU_LAT_LBN 0
+#define	FRF_AA_RX_MAX_LU_LAT_WIDTH 4
+
+/* RX_DEBUG_REG: undocumented register */
+#define	FR_AZ_RX_DEBUG 0x000008a0
+#define	FRF_AZ_RX_DEBUG_LBN 0
+#define	FRF_AZ_RX_DEBUG_WIDTH 64
+
+/* RX_PUSH_DROP_REG: Receive descriptor push dropped counter register */
+#define	FR_AZ_RX_PUSH_DROP 0x000008b0
+#define	FRF_AZ_RX_PUSH_DROP_CNT_LBN 0
+#define	FRF_AZ_RX_PUSH_DROP_CNT_WIDTH 32
+
+/* RX_RSS_IPV6_REG1: IPv6 RSS Toeplitz hash key low bytes */
+#define	FR_CZ_RX_RSS_IPV6_REG1 0x000008d0
+#define	FRF_CZ_RX_RSS_IPV6_TKEY_LO_LBN 0
+#define	FRF_CZ_RX_RSS_IPV6_TKEY_LO_WIDTH 128
+
+/* RX_RSS_IPV6_REG2: IPv6 RSS Toeplitz hash key middle bytes */
+#define	FR_CZ_RX_RSS_IPV6_REG2 0x000008e0
+#define	FRF_CZ_RX_RSS_IPV6_TKEY_MID_LBN 0
+#define	FRF_CZ_RX_RSS_IPV6_TKEY_MID_WIDTH 128
+
+/* RX_RSS_IPV6_REG3: IPv6 RSS Toeplitz hash key upper bytes and IPv6 RSS settings */
+#define	FR_CZ_RX_RSS_IPV6_REG3 0x000008f0
+#define	FRF_CZ_RX_RSS_IPV6_THASH_ENABLE_LBN 66
+#define	FRF_CZ_RX_RSS_IPV6_THASH_ENABLE_WIDTH 1
+#define	FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE_LBN 65
+#define	FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE_WIDTH 1
+#define	FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS_LBN 64
+#define	FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS_WIDTH 1
+#define	FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN 0
+#define	FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH 64
+
+/* TX_FLUSH_DESCQ_REG: Transmit flush descriptor queue register */
+#define	FR_AZ_TX_FLUSH_DESCQ 0x00000a00
+#define	FRF_AZ_TX_FLUSH_DESCQ_CMD_LBN 12
+#define	FRF_AZ_TX_FLUSH_DESCQ_CMD_WIDTH 1
+#define	FRF_AZ_TX_FLUSH_DESCQ_LBN 0
+#define	FRF_AZ_TX_FLUSH_DESCQ_WIDTH 12
+
+/* TX_DESC_UPD_REGP0: Transmit descriptor update register. */
+#define	FR_BZ_TX_DESC_UPD_P0 0x00000a10
+#define	FR_BZ_TX_DESC_UPD_P0_STEP 8192
+#define	FR_BZ_TX_DESC_UPD_P0_ROWS 1024
+/* TX_DESC_UPD_REG_KER: Transmit descriptor update register. */
+#define	FR_AA_TX_DESC_UPD_KER 0x00000a10
+#define	FR_AA_TX_DESC_UPD_KER_STEP 8192
+#define	FR_AA_TX_DESC_UPD_KER_ROWS 8
+/* TX_DESC_UPD_REGP123: Transmit descriptor update register. */
+#define	FR_BB_TX_DESC_UPD_P123 0x01000a10
+#define	FR_BB_TX_DESC_UPD_P123_STEP 8192
+#define	FR_BB_TX_DESC_UPD_P123_ROWS 3072
+#define	FRF_AZ_TX_DESC_WPTR_LBN 96
+#define	FRF_AZ_TX_DESC_WPTR_WIDTH 12
+#define	FRF_AZ_TX_DESC_PUSH_CMD_LBN 95
+#define	FRF_AZ_TX_DESC_PUSH_CMD_WIDTH 1
+#define	FRF_AZ_TX_DESC_LBN 0
+#define	FRF_AZ_TX_DESC_WIDTH 95
+
+/* TX_DC_CFG_REG: Transmit descriptor cache configuration register */
+#define	FR_AZ_TX_DC_CFG 0x00000a20
+#define	FRF_AZ_TX_DC_SIZE_LBN 0
+#define	FRF_AZ_TX_DC_SIZE_WIDTH 2
+#define	FFE_AZ_TX_DC_SIZE_32 2
+#define	FFE_AZ_TX_DC_SIZE_16 1
+#define	FFE_AZ_TX_DC_SIZE_8 0
+
+/* TX_CHKSM_CFG_REG: Transmit checksum configuration register */
+#define	FR_AA_TX_CHKSM_CFG 0x00000a30
+#define	FRF_AA_TX_Q_CHKSM_DIS_96_127_LBN 96
+#define	FRF_AA_TX_Q_CHKSM_DIS_96_127_WIDTH 32
+#define	FRF_AA_TX_Q_CHKSM_DIS_64_95_LBN 64
+#define	FRF_AA_TX_Q_CHKSM_DIS_64_95_WIDTH 32
+#define	FRF_AA_TX_Q_CHKSM_DIS_32_63_LBN 32
+#define	FRF_AA_TX_Q_CHKSM_DIS_32_63_WIDTH 32
+#define	FRF_AA_TX_Q_CHKSM_DIS_0_31_LBN 0
+#define	FRF_AA_TX_Q_CHKSM_DIS_0_31_WIDTH 32
+
+/* TX_CFG_REG: Transmit configuration register */
+#define	FR_AZ_TX_CFG 0x00000a50
+#define	FRF_CZ_TX_CONT_LOOKUP_THRESH_RANGE_LBN 114
+#define	FRF_CZ_TX_CONT_LOOKUP_THRESH_RANGE_WIDTH 8
+#define	FRF_CZ_TX_FILTER_TEST_MODE_BIT_LBN 113
+#define	FRF_CZ_TX_FILTER_TEST_MODE_BIT_WIDTH 1
+#define	FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE_LBN 105
+#define	FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE_WIDTH 8
+#define	FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE_LBN 97
+#define	FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE_WIDTH 8
+#define	FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE_LBN 89
+#define	FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE_WIDTH 8
+#define	FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE_LBN 81
+#define	FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE_WIDTH 8
+#define	FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE_LBN 73
+#define	FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE_WIDTH 8
+#define	FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE_LBN 65
+#define	FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE_WIDTH 8
+#define	FRF_CZ_TX_FILTER_ALL_VLAN_ETHERTYPES_BIT_LBN 64
+#define	FRF_CZ_TX_FILTER_ALL_VLAN_ETHERTYPES_BIT_WIDTH 1
+#define	FRF_CZ_TX_VLAN_MATCH_ETHERTYPE_RANGE_LBN 48
+#define	FRF_CZ_TX_VLAN_MATCH_ETHERTYPE_RANGE_WIDTH 16
+#define	FRF_CZ_TX_FILTER_EN_BIT_LBN 47
+#define	FRF_CZ_TX_FILTER_EN_BIT_WIDTH 1
+#define	FRF_AZ_TX_IP_ID_P0_OFS_LBN 16
+#define	FRF_AZ_TX_IP_ID_P0_OFS_WIDTH 15
+#define	FRF_AZ_TX_NO_EOP_DISC_EN_LBN 5
+#define	FRF_AZ_TX_NO_EOP_DISC_EN_WIDTH 1
+#define	FRF_AZ_TX_P1_PRI_EN_LBN 4
+#define	FRF_AZ_TX_P1_PRI_EN_WIDTH 1
+#define	FRF_AZ_TX_OWNERR_CTL_LBN 2
+#define	FRF_AZ_TX_OWNERR_CTL_WIDTH 1
+#define	FRF_AA_TX_NON_IP_DROP_DIS_LBN 1
+#define	FRF_AA_TX_NON_IP_DROP_DIS_WIDTH 1
+#define	FRF_AZ_TX_IP_ID_REP_EN_LBN 0
+#define	FRF_AZ_TX_IP_ID_REP_EN_WIDTH 1
+
+/* TX_PUSH_DROP_REG: Transmit push dropped register */
+#define	FR_AZ_TX_PUSH_DROP 0x00000a60
+#define	FRF_AZ_TX_PUSH_DROP_CNT_LBN 0
+#define	FRF_AZ_TX_PUSH_DROP_CNT_WIDTH 32
+
+/* TX_RESERVED_REG: Transmit configuration register */
+#define	FR_AZ_TX_RESERVED 0x00000a80
+#define	FRF_AZ_TX_EVT_CNT_LBN 121
+#define	FRF_AZ_TX_EVT_CNT_WIDTH 7
+#define	FRF_AZ_TX_PREF_AGE_CNT_LBN 119
+#define	FRF_AZ_TX_PREF_AGE_CNT_WIDTH 2
+#define	FRF_AZ_TX_RD_COMP_TMR_LBN 96
+#define	FRF_AZ_TX_RD_COMP_TMR_WIDTH 23
+#define	FRF_AZ_TX_PUSH_EN_LBN 89
+#define	FRF_AZ_TX_PUSH_EN_WIDTH 1
+#define	FRF_AZ_TX_PUSH_CHK_DIS_LBN 88
+#define	FRF_AZ_TX_PUSH_CHK_DIS_WIDTH 1
+#define	FRF_AZ_TX_D_FF_FULL_P0_LBN 85
+#define	FRF_AZ_TX_D_FF_FULL_P0_WIDTH 1
+#define	FRF_AZ_TX_DMAR_ST_P0_LBN 81
+#define	FRF_AZ_TX_DMAR_ST_P0_WIDTH 1
+#define	FRF_AZ_TX_DMAQ_ST_LBN 78
+#define	FRF_AZ_TX_DMAQ_ST_WIDTH 1
+#define	FRF_AZ_TX_RX_SPACER_LBN 64
+#define	FRF_AZ_TX_RX_SPACER_WIDTH 8
+#define	FRF_AZ_TX_DROP_ABORT_EN_LBN 60
+#define	FRF_AZ_TX_DROP_ABORT_EN_WIDTH 1
+#define	FRF_AZ_TX_SOFT_EVT_EN_LBN 59
+#define	FRF_AZ_TX_SOFT_EVT_EN_WIDTH 1
+#define	FRF_AZ_TX_PS_EVT_DIS_LBN 58
+#define	FRF_AZ_TX_PS_EVT_DIS_WIDTH 1
+#define	FRF_AZ_TX_RX_SPACER_EN_LBN 57
+#define	FRF_AZ_TX_RX_SPACER_EN_WIDTH 1
+#define	FRF_AZ_TX_XP_TIMER_LBN 52
+#define	FRF_AZ_TX_XP_TIMER_WIDTH 5
+#define	FRF_AZ_TX_PREF_SPACER_LBN 44
+#define	FRF_AZ_TX_PREF_SPACER_WIDTH 8
+#define	FRF_AZ_TX_PREF_WD_TMR_LBN 22
+#define	FRF_AZ_TX_PREF_WD_TMR_WIDTH 22
+#define	FRF_AZ_TX_ONLY1TAG_LBN 21
+#define	FRF_AZ_TX_ONLY1TAG_WIDTH 1
+#define	FRF_AZ_TX_PREF_THRESHOLD_LBN 19
+#define	FRF_AZ_TX_PREF_THRESHOLD_WIDTH 2
+#define	FRF_AZ_TX_ONE_PKT_PER_Q_LBN 18
+#define	FRF_AZ_TX_ONE_PKT_PER_Q_WIDTH 1
+#define	FRF_AZ_TX_DIS_NON_IP_EV_LBN 17
+#define	FRF_AZ_TX_DIS_NON_IP_EV_WIDTH 1
+#define	FRF_AA_TX_DMA_FF_THR_LBN 16
+#define	FRF_AA_TX_DMA_FF_THR_WIDTH 1
+#define	FRF_AZ_TX_DMA_SPACER_LBN 8
+#define	FRF_AZ_TX_DMA_SPACER_WIDTH 8
+#define	FRF_AA_TX_TCP_DIS_LBN 7
+#define	FRF_AA_TX_TCP_DIS_WIDTH 1
+#define	FRF_BZ_TX_FLUSH_MIN_LEN_EN_LBN 7
+#define	FRF_BZ_TX_FLUSH_MIN_LEN_EN_WIDTH 1
+#define	FRF_AA_TX_IP_DIS_LBN 6
+#define	FRF_AA_TX_IP_DIS_WIDTH 1
+#define	FRF_AZ_TX_MAX_CPL_LBN 2
+#define	FRF_AZ_TX_MAX_CPL_WIDTH 2
+#define	FFE_AZ_TX_MAX_CPL_16 3
+#define	FFE_AZ_TX_MAX_CPL_8 2
+#define	FFE_AZ_TX_MAX_CPL_4 1
+#define	FFE_AZ_TX_MAX_CPL_NOLIMIT 0
+#define	FRF_AZ_TX_MAX_PREF_LBN 0
+#define	FRF_AZ_TX_MAX_PREF_WIDTH 2
+#define	FFE_AZ_TX_MAX_PREF_32 3
+#define	FFE_AZ_TX_MAX_PREF_16 2
+#define	FFE_AZ_TX_MAX_PREF_8 1
+#define	FFE_AZ_TX_MAX_PREF_OFF 0
+
+/* TX_PACE_REG: Transmit pace control register */
+#define	FR_BZ_TX_PACE 0x00000a90
+#define	FRF_BZ_TX_PACE_SB_NOT_AF_LBN 19
+#define	FRF_BZ_TX_PACE_SB_NOT_AF_WIDTH 10
+#define	FRF_BZ_TX_PACE_SB_AF_LBN 9
+#define	FRF_BZ_TX_PACE_SB_AF_WIDTH 10
+#define	FRF_BZ_TX_PACE_FB_BASE_LBN 5
+#define	FRF_BZ_TX_PACE_FB_BASE_WIDTH 4
+#define	FRF_BZ_TX_PACE_BIN_TH_LBN 0
+#define	FRF_BZ_TX_PACE_BIN_TH_WIDTH 5
+
+/* TX_PACE_DROP_QID_REG: PACE Drop QID Counter */
+#define	FR_BZ_TX_PACE_DROP_QID 0x00000aa0
+#define	FRF_BZ_TX_PACE_QID_DRP_CNT_LBN 0
+#define	FRF_BZ_TX_PACE_QID_DRP_CNT_WIDTH 16
+
+/* TX_VLAN_REG: Transmit VLAN tag register */
+#define	FR_BB_TX_VLAN 0x00000ae0
+#define	FRF_BB_TX_VLAN_EN_LBN 127
+#define	FRF_BB_TX_VLAN_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN7_PORT1_EN_LBN 125
+#define	FRF_BB_TX_VLAN7_PORT1_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN7_PORT0_EN_LBN 124
+#define	FRF_BB_TX_VLAN7_PORT0_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN7_LBN 112
+#define	FRF_BB_TX_VLAN7_WIDTH 12
+#define	FRF_BB_TX_VLAN6_PORT1_EN_LBN 109
+#define	FRF_BB_TX_VLAN6_PORT1_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN6_PORT0_EN_LBN 108
+#define	FRF_BB_TX_VLAN6_PORT0_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN6_LBN 96
+#define	FRF_BB_TX_VLAN6_WIDTH 12
+#define	FRF_BB_TX_VLAN5_PORT1_EN_LBN 93
+#define	FRF_BB_TX_VLAN5_PORT1_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN5_PORT0_EN_LBN 92
+#define	FRF_BB_TX_VLAN5_PORT0_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN5_LBN 80
+#define	FRF_BB_TX_VLAN5_WIDTH 12
+#define	FRF_BB_TX_VLAN4_PORT1_EN_LBN 77
+#define	FRF_BB_TX_VLAN4_PORT1_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN4_PORT0_EN_LBN 76
+#define	FRF_BB_TX_VLAN4_PORT0_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN4_LBN 64
+#define	FRF_BB_TX_VLAN4_WIDTH 12
+#define	FRF_BB_TX_VLAN3_PORT1_EN_LBN 61
+#define	FRF_BB_TX_VLAN3_PORT1_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN3_PORT0_EN_LBN 60
+#define	FRF_BB_TX_VLAN3_PORT0_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN3_LBN 48
+#define	FRF_BB_TX_VLAN3_WIDTH 12
+#define	FRF_BB_TX_VLAN2_PORT1_EN_LBN 45
+#define	FRF_BB_TX_VLAN2_PORT1_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN2_PORT0_EN_LBN 44
+#define	FRF_BB_TX_VLAN2_PORT0_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN2_LBN 32
+#define	FRF_BB_TX_VLAN2_WIDTH 12
+#define	FRF_BB_TX_VLAN1_PORT1_EN_LBN 29
+#define	FRF_BB_TX_VLAN1_PORT1_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN1_PORT0_EN_LBN 28
+#define	FRF_BB_TX_VLAN1_PORT0_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN1_LBN 16
+#define	FRF_BB_TX_VLAN1_WIDTH 12
+#define	FRF_BB_TX_VLAN0_PORT1_EN_LBN 13
+#define	FRF_BB_TX_VLAN0_PORT1_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN0_PORT0_EN_LBN 12
+#define	FRF_BB_TX_VLAN0_PORT0_EN_WIDTH 1
+#define	FRF_BB_TX_VLAN0_LBN 0
+#define	FRF_BB_TX_VLAN0_WIDTH 12
+
+/* TX_IPFIL_PORTEN_REG: Transmit filter control register */
+#define	FR_BZ_TX_IPFIL_PORTEN 0x00000af0
+#define	FRF_BZ_TX_MADR0_FIL_EN_LBN 64
+#define	FRF_BZ_TX_MADR0_FIL_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL31_PORT_EN_LBN 62
+#define	FRF_BB_TX_IPFIL31_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL30_PORT_EN_LBN 60
+#define	FRF_BB_TX_IPFIL30_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL29_PORT_EN_LBN 58
+#define	FRF_BB_TX_IPFIL29_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL28_PORT_EN_LBN 56
+#define	FRF_BB_TX_IPFIL28_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL27_PORT_EN_LBN 54
+#define	FRF_BB_TX_IPFIL27_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL26_PORT_EN_LBN 52
+#define	FRF_BB_TX_IPFIL26_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL25_PORT_EN_LBN 50
+#define	FRF_BB_TX_IPFIL25_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL24_PORT_EN_LBN 48
+#define	FRF_BB_TX_IPFIL24_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL23_PORT_EN_LBN 46
+#define	FRF_BB_TX_IPFIL23_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL22_PORT_EN_LBN 44
+#define	FRF_BB_TX_IPFIL22_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL21_PORT_EN_LBN 42
+#define	FRF_BB_TX_IPFIL21_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL20_PORT_EN_LBN 40
+#define	FRF_BB_TX_IPFIL20_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL19_PORT_EN_LBN 38
+#define	FRF_BB_TX_IPFIL19_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL18_PORT_EN_LBN 36
+#define	FRF_BB_TX_IPFIL18_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL17_PORT_EN_LBN 34
+#define	FRF_BB_TX_IPFIL17_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL16_PORT_EN_LBN 32
+#define	FRF_BB_TX_IPFIL16_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL15_PORT_EN_LBN 30
+#define	FRF_BB_TX_IPFIL15_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL14_PORT_EN_LBN 28
+#define	FRF_BB_TX_IPFIL14_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL13_PORT_EN_LBN 26
+#define	FRF_BB_TX_IPFIL13_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL12_PORT_EN_LBN 24
+#define	FRF_BB_TX_IPFIL12_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL11_PORT_EN_LBN 22
+#define	FRF_BB_TX_IPFIL11_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL10_PORT_EN_LBN 20
+#define	FRF_BB_TX_IPFIL10_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL9_PORT_EN_LBN 18
+#define	FRF_BB_TX_IPFIL9_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL8_PORT_EN_LBN 16
+#define	FRF_BB_TX_IPFIL8_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL7_PORT_EN_LBN 14
+#define	FRF_BB_TX_IPFIL7_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL6_PORT_EN_LBN 12
+#define	FRF_BB_TX_IPFIL6_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL5_PORT_EN_LBN 10
+#define	FRF_BB_TX_IPFIL5_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL4_PORT_EN_LBN 8
+#define	FRF_BB_TX_IPFIL4_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL3_PORT_EN_LBN 6
+#define	FRF_BB_TX_IPFIL3_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL2_PORT_EN_LBN 4
+#define	FRF_BB_TX_IPFIL2_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL1_PORT_EN_LBN 2
+#define	FRF_BB_TX_IPFIL1_PORT_EN_WIDTH 1
+#define	FRF_BB_TX_IPFIL0_PORT_EN_LBN 0
+#define	FRF_BB_TX_IPFIL0_PORT_EN_WIDTH 1
+
+/* TX_IPFIL_TBL: Transmit IP source address filter table */
+#define	FR_BB_TX_IPFIL_TBL 0x00000b00
+#define	FR_BB_TX_IPFIL_TBL_STEP 16
+#define	FR_BB_TX_IPFIL_TBL_ROWS 16
+#define	FRF_BB_TX_IPFIL_MASK_1_LBN 96
+#define	FRF_BB_TX_IPFIL_MASK_1_WIDTH 32
+#define	FRF_BB_TX_IP_SRC_ADR_1_LBN 64
+#define	FRF_BB_TX_IP_SRC_ADR_1_WIDTH 32
+#define	FRF_BB_TX_IPFIL_MASK_0_LBN 32
+#define	FRF_BB_TX_IPFIL_MASK_0_WIDTH 32
+#define	FRF_BB_TX_IP_SRC_ADR_0_LBN 0
+#define	FRF_BB_TX_IP_SRC_ADR_0_WIDTH 32
+
+/* MD_TXD_REG: PHY management transmit data register */
+#define	FR_AB_MD_TXD 0x00000c00
+#define	FRF_AB_MD_TXD_LBN 0
+#define	FRF_AB_MD_TXD_WIDTH 16
+
+/* MD_RXD_REG: PHY management receive data register */
+#define	FR_AB_MD_RXD 0x00000c10
+#define	FRF_AB_MD_RXD_LBN 0
+#define	FRF_AB_MD_RXD_WIDTH 16
+
+/* MD_CS_REG: PHY management configuration & status register */
+#define	FR_AB_MD_CS 0x00000c20
+#define	FRF_AB_MD_RD_EN_CMD_LBN 15
+#define	FRF_AB_MD_RD_EN_CMD_WIDTH 1
+#define	FRF_AB_MD_WR_EN_CMD_LBN 14
+#define	FRF_AB_MD_WR_EN_CMD_WIDTH 1
+#define	FRF_AB_MD_ADDR_CMD_LBN 13
+#define	FRF_AB_MD_ADDR_CMD_WIDTH 1
+#define	FRF_AB_MD_PT_LBN 7
+#define	FRF_AB_MD_PT_WIDTH 3
+#define	FRF_AB_MD_PL_LBN 6
+#define	FRF_AB_MD_PL_WIDTH 1
+#define	FRF_AB_MD_INT_CLR_LBN 5
+#define	FRF_AB_MD_INT_CLR_WIDTH 1
+#define	FRF_AB_MD_GC_LBN 4
+#define	FRF_AB_MD_GC_WIDTH 1
+#define	FRF_AB_MD_PRSP_LBN 3
+#define	FRF_AB_MD_PRSP_WIDTH 1
+#define	FRF_AB_MD_RIC_LBN 2
+#define	FRF_AB_MD_RIC_WIDTH 1
+#define	FRF_AB_MD_RDC_LBN 1
+#define	FRF_AB_MD_RDC_WIDTH 1
+#define	FRF_AB_MD_WRC_LBN 0
+#define	FRF_AB_MD_WRC_WIDTH 1
+
+/* MD_PHY_ADR_REG: PHY management PHY address register */
+#define	FR_AB_MD_PHY_ADR 0x00000c30
+#define	FRF_AB_MD_PHY_ADR_LBN 0
+#define	FRF_AB_MD_PHY_ADR_WIDTH 16
+
+/* MD_ID_REG: PHY management ID register */
+#define	FR_AB_MD_ID 0x00000c40
+#define	FRF_AB_MD_PRT_ADR_LBN 11
+#define	FRF_AB_MD_PRT_ADR_WIDTH 5
+#define	FRF_AB_MD_DEV_ADR_LBN 6
+#define	FRF_AB_MD_DEV_ADR_WIDTH 5
+
+/* MD_STAT_REG: PHY management status & mask register */
+#define	FR_AB_MD_STAT 0x00000c50
+#define	FRF_AB_MD_PINT_LBN 4
+#define	FRF_AB_MD_PINT_WIDTH 1
+#define	FRF_AB_MD_DONE_LBN 3
+#define	FRF_AB_MD_DONE_WIDTH 1
+#define	FRF_AB_MD_BSERR_LBN 2
+#define	FRF_AB_MD_BSERR_WIDTH 1
+#define	FRF_AB_MD_LNFL_LBN 1
+#define	FRF_AB_MD_LNFL_WIDTH 1
+#define	FRF_AB_MD_BSY_LBN 0
+#define	FRF_AB_MD_BSY_WIDTH 1
+
+/* MAC_STAT_DMA_REG: Port MAC statistical counter DMA register */
+#define	FR_AB_MAC_STAT_DMA 0x00000c60
+#define	FRF_AB_MAC_STAT_DMA_CMD_LBN 48
+#define	FRF_AB_MAC_STAT_DMA_CMD_WIDTH 1
+#define	FRF_AB_MAC_STAT_DMA_ADR_LBN 0
+#define	FRF_AB_MAC_STAT_DMA_ADR_WIDTH 48
+
+/* MAC_CTRL_REG: Port MAC control register */
+#define	FR_AB_MAC_CTRL 0x00000c80
+#define	FRF_AB_MAC_XOFF_VAL_LBN 16
+#define	FRF_AB_MAC_XOFF_VAL_WIDTH 16
+#define	FRF_BB_TXFIFO_DRAIN_EN_LBN 7
+#define	FRF_BB_TXFIFO_DRAIN_EN_WIDTH 1
+#define	FRF_AB_MAC_XG_DISTXCRC_LBN 5
+#define	FRF_AB_MAC_XG_DISTXCRC_WIDTH 1
+#define	FRF_AB_MAC_BCAD_ACPT_LBN 4
+#define	FRF_AB_MAC_BCAD_ACPT_WIDTH 1
+#define	FRF_AB_MAC_UC_PROM_LBN 3
+#define	FRF_AB_MAC_UC_PROM_WIDTH 1
+#define	FRF_AB_MAC_LINK_STATUS_LBN 2
+#define	FRF_AB_MAC_LINK_STATUS_WIDTH 1
+#define	FRF_AB_MAC_SPEED_LBN 0
+#define	FRF_AB_MAC_SPEED_WIDTH 2
+#define	FFE_AB_MAC_SPEED_10G 3
+#define	FFE_AB_MAC_SPEED_1G 2
+#define	FFE_AB_MAC_SPEED_100M 1
+#define	FFE_AB_MAC_SPEED_10M 0
+
+/* GEN_MODE_REG: General Purpose mode register (external interrupt mask) */
+#define	FR_BB_GEN_MODE 0x00000c90
+#define	FRF_BB_XFP_PHY_INT_POL_SEL_LBN 3
+#define	FRF_BB_XFP_PHY_INT_POL_SEL_WIDTH 1
+#define	FRF_BB_XG_PHY_INT_POL_SEL_LBN 2
+#define	FRF_BB_XG_PHY_INT_POL_SEL_WIDTH 1
+#define	FRF_BB_XFP_PHY_INT_MASK_LBN 1
+#define	FRF_BB_XFP_PHY_INT_MASK_WIDTH 1
+#define	FRF_BB_XG_PHY_INT_MASK_LBN 0
+#define	FRF_BB_XG_PHY_INT_MASK_WIDTH 1
+
+/* MAC_MC_HASH_REG0: Multicast address hash table */
+#define	FR_AB_MAC_MC_HASH_REG0 0x00000ca0
+#define	FRF_AB_MAC_MCAST_HASH0_LBN 0
+#define	FRF_AB_MAC_MCAST_HASH0_WIDTH 128
+
+/* MAC_MC_HASH_REG1: Multicast address hash table */
+#define	FR_AB_MAC_MC_HASH_REG1 0x00000cb0
+#define	FRF_AB_MAC_MCAST_HASH1_LBN 0
+#define	FRF_AB_MAC_MCAST_HASH1_WIDTH 128
+
+/* GM_CFG1_REG: GMAC configuration register 1 */
+#define	FR_AB_GM_CFG1 0x00000e00
+#define	FRF_AB_GM_SW_RST_LBN 31
+#define	FRF_AB_GM_SW_RST_WIDTH 1
+#define	FRF_AB_GM_SIM_RST_LBN 30
+#define	FRF_AB_GM_SIM_RST_WIDTH 1
+#define	FRF_AB_GM_RST_RX_MAC_CTL_LBN 19
+#define	FRF_AB_GM_RST_RX_MAC_CTL_WIDTH 1
+#define	FRF_AB_GM_RST_TX_MAC_CTL_LBN 18
+#define	FRF_AB_GM_RST_TX_MAC_CTL_WIDTH 1
+#define	FRF_AB_GM_RST_RX_FUNC_LBN 17
+#define	FRF_AB_GM_RST_RX_FUNC_WIDTH 1
+#define	FRF_AB_GM_RST_TX_FUNC_LBN 16
+#define	FRF_AB_GM_RST_TX_FUNC_WIDTH 1
+#define	FRF_AB_GM_LOOP_LBN 8
+#define	FRF_AB_GM_LOOP_WIDTH 1
+#define	FRF_AB_GM_RX_FC_EN_LBN 5
+#define	FRF_AB_GM_RX_FC_EN_WIDTH 1
+#define	FRF_AB_GM_TX_FC_EN_LBN 4
+#define	FRF_AB_GM_TX_FC_EN_WIDTH 1
+#define	FRF_AB_GM_SYNC_RXEN_LBN 3
+#define	FRF_AB_GM_SYNC_RXEN_WIDTH 1
+#define	FRF_AB_GM_RX_EN_LBN 2
+#define	FRF_AB_GM_RX_EN_WIDTH 1
+#define	FRF_AB_GM_SYNC_TXEN_LBN 1
+#define	FRF_AB_GM_SYNC_TXEN_WIDTH 1
+#define	FRF_AB_GM_TX_EN_LBN 0
+#define	FRF_AB_GM_TX_EN_WIDTH 1
+
+/* GM_CFG2_REG: GMAC configuration register 2 */
+#define	FR_AB_GM_CFG2 0x00000e10
+#define	FRF_AB_GM_PAMBL_LEN_LBN 12
+#define	FRF_AB_GM_PAMBL_LEN_WIDTH 4
+#define	FRF_AB_GM_IF_MODE_LBN 8
+#define	FRF_AB_GM_IF_MODE_WIDTH 2
+#define	FFE_AB_IF_MODE_BYTE_MODE 2
+#define	FFE_AB_IF_MODE_NIBBLE_MODE 1
+#define	FRF_AB_GM_HUGE_FRM_EN_LBN 5
+#define	FRF_AB_GM_HUGE_FRM_EN_WIDTH 1
+#define	FRF_AB_GM_LEN_CHK_LBN 4
+#define	FRF_AB_GM_LEN_CHK_WIDTH 1
+#define	FRF_AB_GM_PAD_CRC_EN_LBN 2
+#define	FRF_AB_GM_PAD_CRC_EN_WIDTH 1
+#define	FRF_AB_GM_CRC_EN_LBN 1
+#define	FRF_AB_GM_CRC_EN_WIDTH 1
+#define	FRF_AB_GM_FD_LBN 0
+#define	FRF_AB_GM_FD_WIDTH 1
+
+/* GM_IPG_REG: GMAC IPG register */
+#define	FR_AB_GM_IPG 0x00000e20
+#define	FRF_AB_GM_NONB2B_IPG1_LBN 24
+#define	FRF_AB_GM_NONB2B_IPG1_WIDTH 7
+#define	FRF_AB_GM_NONB2B_IPG2_LBN 16
+#define	FRF_AB_GM_NONB2B_IPG2_WIDTH 7
+#define	FRF_AB_GM_MIN_IPG_ENF_LBN 8
+#define	FRF_AB_GM_MIN_IPG_ENF_WIDTH 8
+#define	FRF_AB_GM_B2B_IPG_LBN 0
+#define	FRF_AB_GM_B2B_IPG_WIDTH 7
+
+/* GM_HD_REG: GMAC half duplex register */
+#define	FR_AB_GM_HD 0x00000e30
+#define	FRF_AB_GM_ALT_BOFF_VAL_LBN 20
+#define	FRF_AB_GM_ALT_BOFF_VAL_WIDTH 4
+#define	FRF_AB_GM_ALT_BOFF_EN_LBN 19
+#define	FRF_AB_GM_ALT_BOFF_EN_WIDTH 1
+#define	FRF_AB_GM_BP_NO_BOFF_LBN 18
+#define	FRF_AB_GM_BP_NO_BOFF_WIDTH 1
+#define	FRF_AB_GM_DIS_BOFF_LBN 17
+#define	FRF_AB_GM_DIS_BOFF_WIDTH 1
+#define	FRF_AB_GM_EXDEF_TX_EN_LBN 16
+#define	FRF_AB_GM_EXDEF_TX_EN_WIDTH 1
+#define	FRF_AB_GM_RTRY_LIMIT_LBN 12
+#define	FRF_AB_GM_RTRY_LIMIT_WIDTH 4
+#define	FRF_AB_GM_COL_WIN_LBN 0
+#define	FRF_AB_GM_COL_WIN_WIDTH 10
+
+/* GM_MAX_FLEN_REG: GMAC maximum frame length register */
+#define	FR_AB_GM_MAX_FLEN 0x00000e40
+#define	FRF_AB_GM_MAX_FLEN_LBN 0
+#define	FRF_AB_GM_MAX_FLEN_WIDTH 16
+
+/* GM_TEST_REG: GMAC test register */
+#define	FR_AB_GM_TEST 0x00000e70
+#define	FRF_AB_GM_MAX_BOFF_LBN 3
+#define	FRF_AB_GM_MAX_BOFF_WIDTH 1
+#define	FRF_AB_GM_REG_TX_FLOW_EN_LBN 2
+#define	FRF_AB_GM_REG_TX_FLOW_EN_WIDTH 1
+#define	FRF_AB_GM_TEST_PAUSE_LBN 1
+#define	FRF_AB_GM_TEST_PAUSE_WIDTH 1
+#define	FRF_AB_GM_SHORT_SLOT_LBN 0
+#define	FRF_AB_GM_SHORT_SLOT_WIDTH 1
+
+/* GM_ADR1_REG: GMAC station address register 1 */
+#define	FR_AB_GM_ADR1 0x00000f00
+#define	FRF_AB_GM_ADR_B0_LBN 24
+#define	FRF_AB_GM_ADR_B0_WIDTH 8
+#define	FRF_AB_GM_ADR_B1_LBN 16
+#define	FRF_AB_GM_ADR_B1_WIDTH 8
+#define	FRF_AB_GM_ADR_B2_LBN 8
+#define	FRF_AB_GM_ADR_B2_WIDTH 8
+#define	FRF_AB_GM_ADR_B3_LBN 0
+#define	FRF_AB_GM_ADR_B3_WIDTH 8
+
+/* GM_ADR2_REG: GMAC station address register 2 */
+#define	FR_AB_GM_ADR2 0x00000f10
+#define	FRF_AB_GM_ADR_B4_LBN 24
+#define	FRF_AB_GM_ADR_B4_WIDTH 8
+#define	FRF_AB_GM_ADR_B5_LBN 16
+#define	FRF_AB_GM_ADR_B5_WIDTH 8
+
+/* GMF_CFG0_REG: GMAC FIFO configuration register 0 */
+#define	FR_AB_GMF_CFG0 0x00000f20
+#define	FRF_AB_GMF_FTFENRPLY_LBN 20
+#define	FRF_AB_GMF_FTFENRPLY_WIDTH 1
+#define	FRF_AB_GMF_STFENRPLY_LBN 19
+#define	FRF_AB_GMF_STFENRPLY_WIDTH 1
+#define	FRF_AB_GMF_FRFENRPLY_LBN 18
+#define	FRF_AB_GMF_FRFENRPLY_WIDTH 1
+#define	FRF_AB_GMF_SRFENRPLY_LBN 17
+#define	FRF_AB_GMF_SRFENRPLY_WIDTH 1
+#define	FRF_AB_GMF_WTMENRPLY_LBN 16
+#define	FRF_AB_GMF_WTMENRPLY_WIDTH 1
+#define	FRF_AB_GMF_FTFENREQ_LBN 12
+#define	FRF_AB_GMF_FTFENREQ_WIDTH 1
+#define	FRF_AB_GMF_STFENREQ_LBN 11
+#define	FRF_AB_GMF_STFENREQ_WIDTH 1
+#define	FRF_AB_GMF_FRFENREQ_LBN 10
+#define	FRF_AB_GMF_FRFENREQ_WIDTH 1
+#define	FRF_AB_GMF_SRFENREQ_LBN 9
+#define	FRF_AB_GMF_SRFENREQ_WIDTH 1
+#define	FRF_AB_GMF_WTMENREQ_LBN 8
+#define	FRF_AB_GMF_WTMENREQ_WIDTH 1
+#define	FRF_AB_GMF_HSTRSTFT_LBN 4
+#define	FRF_AB_GMF_HSTRSTFT_WIDTH 1
+#define	FRF_AB_GMF_HSTRSTST_LBN 3
+#define	FRF_AB_GMF_HSTRSTST_WIDTH 1
+#define	FRF_AB_GMF_HSTRSTFR_LBN 2
+#define	FRF_AB_GMF_HSTRSTFR_WIDTH 1
+#define	FRF_AB_GMF_HSTRSTSR_LBN 1
+#define	FRF_AB_GMF_HSTRSTSR_WIDTH 1
+#define	FRF_AB_GMF_HSTRSTWT_LBN 0
+#define	FRF_AB_GMF_HSTRSTWT_WIDTH 1
+
+/* GMF_CFG1_REG: GMAC FIFO configuration register 1 */
+#define	FR_AB_GMF_CFG1 0x00000f30
+#define	FRF_AB_GMF_CFGFRTH_LBN 16
+#define	FRF_AB_GMF_CFGFRTH_WIDTH 5
+#define	FRF_AB_GMF_CFGXOFFRTX_LBN 0
+#define	FRF_AB_GMF_CFGXOFFRTX_WIDTH 16
+
+/* GMF_CFG2_REG: GMAC FIFO configuration register 2 */
+#define	FR_AB_GMF_CFG2 0x00000f40
+#define	FRF_AB_GMF_CFGHWM_LBN 16
+#define	FRF_AB_GMF_CFGHWM_WIDTH 6
+#define	FRF_AB_GMF_CFGLWM_LBN 0
+#define	FRF_AB_GMF_CFGLWM_WIDTH 6
+
+/* GMF_CFG3_REG: GMAC FIFO configuration register 3 */
+#define	FR_AB_GMF_CFG3 0x00000f50
+#define	FRF_AB_GMF_CFGHWMFT_LBN 16
+#define	FRF_AB_GMF_CFGHWMFT_WIDTH 6
+#define	FRF_AB_GMF_CFGFTTH_LBN 0
+#define	FRF_AB_GMF_CFGFTTH_WIDTH 6
+
+/* GMF_CFG4_REG: GMAC FIFO configuration register 4 */
+#define	FR_AB_GMF_CFG4 0x00000f60
+#define	FRF_AB_GMF_HSTFLTRFRM_LBN 0
+#define	FRF_AB_GMF_HSTFLTRFRM_WIDTH 18
+
+/* GMF_CFG5_REG: GMAC FIFO configuration register 5 */
+#define	FR_AB_GMF_CFG5 0x00000f70
+#define	FRF_AB_GMF_CFGHDPLX_LBN 22
+#define	FRF_AB_GMF_CFGHDPLX_WIDTH 1
+#define	FRF_AB_GMF_SRFULL_LBN 21
+#define	FRF_AB_GMF_SRFULL_WIDTH 1
+#define	FRF_AB_GMF_HSTSRFULLCLR_LBN 20
+#define	FRF_AB_GMF_HSTSRFULLCLR_WIDTH 1
+#define	FRF_AB_GMF_CFGBYTMODE_LBN 19
+#define	FRF_AB_GMF_CFGBYTMODE_WIDTH 1
+#define	FRF_AB_GMF_HSTDRPLT64_LBN 18
+#define	FRF_AB_GMF_HSTDRPLT64_WIDTH 1
+#define	FRF_AB_GMF_HSTFLTRFRMDC_LBN 0
+#define	FRF_AB_GMF_HSTFLTRFRMDC_WIDTH 18
+
+/* TX_SRC_MAC_TBL: Transmit IP source address filter table */
+#define	FR_BB_TX_SRC_MAC_TBL 0x00001000
+#define	FR_BB_TX_SRC_MAC_TBL_STEP 16
+#define	FR_BB_TX_SRC_MAC_TBL_ROWS 16
+#define	FRF_BB_TX_SRC_MAC_ADR_1_LBN 64
+#define	FRF_BB_TX_SRC_MAC_ADR_1_WIDTH 48
+#define	FRF_BB_TX_SRC_MAC_ADR_0_LBN 0
+#define	FRF_BB_TX_SRC_MAC_ADR_0_WIDTH 48
+
+/* TX_SRC_MAC_CTL_REG: Transmit MAC source address filter control */
+#define	FR_BB_TX_SRC_MAC_CTL 0x00001100
+#define	FRF_BB_TX_SRC_DROP_CTR_LBN 16
+#define	FRF_BB_TX_SRC_DROP_CTR_WIDTH 16
+#define	FRF_BB_TX_SRC_FLTR_EN_LBN 15
+#define	FRF_BB_TX_SRC_FLTR_EN_WIDTH 1
+#define	FRF_BB_TX_DROP_CTR_CLR_LBN 12
+#define	FRF_BB_TX_DROP_CTR_CLR_WIDTH 1
+#define	FRF_BB_TX_MAC_QID_SEL_LBN 0
+#define	FRF_BB_TX_MAC_QID_SEL_WIDTH 3
+
+/* XM_ADR_LO_REG: XGMAC address register low */
+#define	FR_AB_XM_ADR_LO 0x00001200
+#define	FRF_AB_XM_ADR_LO_LBN 0
+#define	FRF_AB_XM_ADR_LO_WIDTH 32
+
+/* XM_ADR_HI_REG: XGMAC address register high */
+#define	FR_AB_XM_ADR_HI 0x00001210
+#define	FRF_AB_XM_ADR_HI_LBN 0
+#define	FRF_AB_XM_ADR_HI_WIDTH 16
+
+/* XM_GLB_CFG_REG: XGMAC global configuration */
+#define	FR_AB_XM_GLB_CFG 0x00001220
+#define	FRF_AB_XM_RMTFLT_GEN_LBN 17
+#define	FRF_AB_XM_RMTFLT_GEN_WIDTH 1
+#define	FRF_AB_XM_DEBUG_MODE_LBN 16
+#define	FRF_AB_XM_DEBUG_MODE_WIDTH 1
+#define	FRF_AB_XM_RX_STAT_EN_LBN 11
+#define	FRF_AB_XM_RX_STAT_EN_WIDTH 1
+#define	FRF_AB_XM_TX_STAT_EN_LBN 10
+#define	FRF_AB_XM_TX_STAT_EN_WIDTH 1
+#define	FRF_AB_XM_RX_JUMBO_MODE_LBN 6
+#define	FRF_AB_XM_RX_JUMBO_MODE_WIDTH 1
+#define	FRF_AB_XM_WAN_MODE_LBN 5
+#define	FRF_AB_XM_WAN_MODE_WIDTH 1
+#define	FRF_AB_XM_INTCLR_MODE_LBN 3
+#define	FRF_AB_XM_INTCLR_MODE_WIDTH 1
+#define	FRF_AB_XM_CORE_RST_LBN 0
+#define	FRF_AB_XM_CORE_RST_WIDTH 1
+
+/* XM_TX_CFG_REG: XGMAC transmit configuration */
+#define	FR_AB_XM_TX_CFG 0x00001230
+#define	FRF_AB_XM_TX_PROG_LBN 24
+#define	FRF_AB_XM_TX_PROG_WIDTH 1
+#define	FRF_AB_XM_IPG_LBN 16
+#define	FRF_AB_XM_IPG_WIDTH 4
+#define	FRF_AB_XM_FCNTL_LBN 10
+#define	FRF_AB_XM_FCNTL_WIDTH 1
+#define	FRF_AB_XM_TXCRC_LBN 8
+#define	FRF_AB_XM_TXCRC_WIDTH 1
+#define	FRF_AB_XM_EDRC_LBN 6
+#define	FRF_AB_XM_EDRC_WIDTH 1
+#define	FRF_AB_XM_AUTO_PAD_LBN 5
+#define	FRF_AB_XM_AUTO_PAD_WIDTH 1
+#define	FRF_AB_XM_TX_PRMBL_LBN 2
+#define	FRF_AB_XM_TX_PRMBL_WIDTH 1
+#define	FRF_AB_XM_TXEN_LBN 1
+#define	FRF_AB_XM_TXEN_WIDTH 1
+#define	FRF_AB_XM_TX_RST_LBN 0
+#define	FRF_AB_XM_TX_RST_WIDTH 1
+
+/* XM_RX_CFG_REG: XGMAC receive configuration */
+#define	FR_AB_XM_RX_CFG 0x00001240
+#define	FRF_AB_XM_PASS_LENERR_LBN 26
+#define	FRF_AB_XM_PASS_LENERR_WIDTH 1
+#define	FRF_AB_XM_PASS_CRC_ERR_LBN 25
+#define	FRF_AB_XM_PASS_CRC_ERR_WIDTH 1
+#define	FRF_AB_XM_PASS_PRMBLE_ERR_LBN 24
+#define	FRF_AB_XM_PASS_PRMBLE_ERR_WIDTH 1
+#define	FRF_AB_XM_REJ_BCAST_LBN 20
+#define	FRF_AB_XM_REJ_BCAST_WIDTH 1
+#define	FRF_AB_XM_ACPT_ALL_MCAST_LBN 11
+#define	FRF_AB_XM_ACPT_ALL_MCAST_WIDTH 1
+#define	FRF_AB_XM_ACPT_ALL_UCAST_LBN 9
+#define	FRF_AB_XM_ACPT_ALL_UCAST_WIDTH 1
+#define	FRF_AB_XM_AUTO_DEPAD_LBN 8
+#define	FRF_AB_XM_AUTO_DEPAD_WIDTH 1
+#define	FRF_AB_XM_RXCRC_LBN 3
+#define	FRF_AB_XM_RXCRC_WIDTH 1
+#define	FRF_AB_XM_RX_PRMBL_LBN 2
+#define	FRF_AB_XM_RX_PRMBL_WIDTH 1
+#define	FRF_AB_XM_RXEN_LBN 1
+#define	FRF_AB_XM_RXEN_WIDTH 1
+#define	FRF_AB_XM_RX_RST_LBN 0
+#define	FRF_AB_XM_RX_RST_WIDTH 1
+
+/* XM_MGT_INT_MASK: documentation to be written for sum_XM_MGT_INT_MASK */
+#define	FR_AB_XM_MGT_INT_MASK 0x00001250
+#define	FRF_AB_XM_MSK_STA_INTR_LBN 16
+#define	FRF_AB_XM_MSK_STA_INTR_WIDTH 1
+#define	FRF_AB_XM_MSK_STAT_CNTR_HF_LBN 9
+#define	FRF_AB_XM_MSK_STAT_CNTR_HF_WIDTH 1
+#define	FRF_AB_XM_MSK_STAT_CNTR_OF_LBN 8
+#define	FRF_AB_XM_MSK_STAT_CNTR_OF_WIDTH 1
+#define	FRF_AB_XM_MSK_PRMBLE_ERR_LBN 2
+#define	FRF_AB_XM_MSK_PRMBLE_ERR_WIDTH 1
+#define	FRF_AB_XM_MSK_RMTFLT_LBN 1
+#define	FRF_AB_XM_MSK_RMTFLT_WIDTH 1
+#define	FRF_AB_XM_MSK_LCLFLT_LBN 0
+#define	FRF_AB_XM_MSK_LCLFLT_WIDTH 1
+
+/* XM_FC_REG: XGMAC flow control register */
+#define	FR_AB_XM_FC 0x00001270
+#define	FRF_AB_XM_PAUSE_TIME_LBN 16
+#define	FRF_AB_XM_PAUSE_TIME_WIDTH 16
+#define	FRF_AB_XM_RX_MAC_STAT_LBN 11
+#define	FRF_AB_XM_RX_MAC_STAT_WIDTH 1
+#define	FRF_AB_XM_TX_MAC_STAT_LBN 10
+#define	FRF_AB_XM_TX_MAC_STAT_WIDTH 1
+#define	FRF_AB_XM_MCNTL_PASS_LBN 8
+#define	FRF_AB_XM_MCNTL_PASS_WIDTH 2
+#define	FRF_AB_XM_REJ_CNTL_UCAST_LBN 6
+#define	FRF_AB_XM_REJ_CNTL_UCAST_WIDTH 1
+#define	FRF_AB_XM_REJ_CNTL_MCAST_LBN 5
+#define	FRF_AB_XM_REJ_CNTL_MCAST_WIDTH 1
+#define	FRF_AB_XM_ZPAUSE_LBN 2
+#define	FRF_AB_XM_ZPAUSE_WIDTH 1
+#define	FRF_AB_XM_XMIT_PAUSE_LBN 1
+#define	FRF_AB_XM_XMIT_PAUSE_WIDTH 1
+#define	FRF_AB_XM_DIS_FCNTL_LBN 0
+#define	FRF_AB_XM_DIS_FCNTL_WIDTH 1
+
+/* XM_PAUSE_TIME_REG: XGMAC pause time register */
+#define	FR_AB_XM_PAUSE_TIME 0x00001290
+#define	FRF_AB_XM_TX_PAUSE_CNT_LBN 16
+#define	FRF_AB_XM_TX_PAUSE_CNT_WIDTH 16
+#define	FRF_AB_XM_RX_PAUSE_CNT_LBN 0
+#define	FRF_AB_XM_RX_PAUSE_CNT_WIDTH 16
+
+/* XM_TX_PARAM_REG: XGMAC transmit parameter register */
+#define	FR_AB_XM_TX_PARAM 0x000012d0
+#define	FRF_AB_XM_TX_JUMBO_MODE_LBN 31
+#define	FRF_AB_XM_TX_JUMBO_MODE_WIDTH 1
+#define	FRF_AB_XM_MAX_TX_FRM_SIZE_HI_LBN 19
+#define	FRF_AB_XM_MAX_TX_FRM_SIZE_HI_WIDTH 11
+#define	FRF_AB_XM_MAX_TX_FRM_SIZE_LO_LBN 16
+#define	FRF_AB_XM_MAX_TX_FRM_SIZE_LO_WIDTH 3
+#define	FRF_AB_XM_PAD_CHAR_LBN 0
+#define	FRF_AB_XM_PAD_CHAR_WIDTH 8
+
+/* XM_RX_PARAM_REG: XGMAC receive parameter register */
+#define	FR_AB_XM_RX_PARAM 0x000012e0
+#define	FRF_AB_XM_MAX_RX_FRM_SIZE_HI_LBN 3
+#define	FRF_AB_XM_MAX_RX_FRM_SIZE_HI_WIDTH 11
+#define	FRF_AB_XM_MAX_RX_FRM_SIZE_LO_LBN 0
+#define	FRF_AB_XM_MAX_RX_FRM_SIZE_LO_WIDTH 3
+
+/* XM_MGT_INT_MSK_REG: XGMAC management interrupt mask register */
+#define	FR_AB_XM_MGT_INT_MSK 0x000012f0
+#define	FRF_AB_XM_STAT_CNTR_OF_LBN 9
+#define	FRF_AB_XM_STAT_CNTR_OF_WIDTH 1
+#define	FRF_AB_XM_STAT_CNTR_HF_LBN 8
+#define	FRF_AB_XM_STAT_CNTR_HF_WIDTH 1
+#define	FRF_AB_XM_PRMBLE_ERR_LBN 2
+#define	FRF_AB_XM_PRMBLE_ERR_WIDTH 1
+#define	FRF_AB_XM_RMTFLT_LBN 1
+#define	FRF_AB_XM_RMTFLT_WIDTH 1
+#define	FRF_AB_XM_LCLFLT_LBN 0
+#define	FRF_AB_XM_LCLFLT_WIDTH 1
+
+/* XX_PWR_RST_REG: XGXS/XAUI powerdown/reset register */
+#define	FR_AB_XX_PWR_RST 0x00001300
+#define	FRF_AB_XX_PWRDND_SIG_LBN 31
+#define	FRF_AB_XX_PWRDND_SIG_WIDTH 1
+#define	FRF_AB_XX_PWRDNC_SIG_LBN 30
+#define	FRF_AB_XX_PWRDNC_SIG_WIDTH 1
+#define	FRF_AB_XX_PWRDNB_SIG_LBN 29
+#define	FRF_AB_XX_PWRDNB_SIG_WIDTH 1
+#define	FRF_AB_XX_PWRDNA_SIG_LBN 28
+#define	FRF_AB_XX_PWRDNA_SIG_WIDTH 1
+#define	FRF_AB_XX_SIM_MODE_LBN 27
+#define	FRF_AB_XX_SIM_MODE_WIDTH 1
+#define	FRF_AB_XX_RSTPLLCD_SIG_LBN 25
+#define	FRF_AB_XX_RSTPLLCD_SIG_WIDTH 1
+#define	FRF_AB_XX_RSTPLLAB_SIG_LBN 24
+#define	FRF_AB_XX_RSTPLLAB_SIG_WIDTH 1
+#define	FRF_AB_XX_RESETD_SIG_LBN 23
+#define	FRF_AB_XX_RESETD_SIG_WIDTH 1
+#define	FRF_AB_XX_RESETC_SIG_LBN 22
+#define	FRF_AB_XX_RESETC_SIG_WIDTH 1
+#define	FRF_AB_XX_RESETB_SIG_LBN 21
+#define	FRF_AB_XX_RESETB_SIG_WIDTH 1
+#define	FRF_AB_XX_RESETA_SIG_LBN 20
+#define	FRF_AB_XX_RESETA_SIG_WIDTH 1
+#define	FRF_AB_XX_RSTXGXSRX_SIG_LBN 18
+#define	FRF_AB_XX_RSTXGXSRX_SIG_WIDTH 1
+#define	FRF_AB_XX_RSTXGXSTX_SIG_LBN 17
+#define	FRF_AB_XX_RSTXGXSTX_SIG_WIDTH 1
+#define	FRF_AB_XX_SD_RST_ACT_LBN 16
+#define	FRF_AB_XX_SD_RST_ACT_WIDTH 1
+#define	FRF_AB_XX_PWRDND_EN_LBN 15
+#define	FRF_AB_XX_PWRDND_EN_WIDTH 1
+#define	FRF_AB_XX_PWRDNC_EN_LBN 14
+#define	FRF_AB_XX_PWRDNC_EN_WIDTH 1
+#define	FRF_AB_XX_PWRDNB_EN_LBN 13
+#define	FRF_AB_XX_PWRDNB_EN_WIDTH 1
+#define	FRF_AB_XX_PWRDNA_EN_LBN 12
+#define	FRF_AB_XX_PWRDNA_EN_WIDTH 1
+#define	FRF_AB_XX_RSTPLLCD_EN_LBN 9
+#define	FRF_AB_XX_RSTPLLCD_EN_WIDTH 1
+#define	FRF_AB_XX_RSTPLLAB_EN_LBN 8
+#define	FRF_AB_XX_RSTPLLAB_EN_WIDTH 1
+#define	FRF_AB_XX_RESETD_EN_LBN 7
+#define	FRF_AB_XX_RESETD_EN_WIDTH 1
+#define	FRF_AB_XX_RESETC_EN_LBN 6
+#define	FRF_AB_XX_RESETC_EN_WIDTH 1
+#define	FRF_AB_XX_RESETB_EN_LBN 5
+#define	FRF_AB_XX_RESETB_EN_WIDTH 1
+#define	FRF_AB_XX_RESETA_EN_LBN 4
+#define	FRF_AB_XX_RESETA_EN_WIDTH 1
+#define	FRF_AB_XX_RSTXGXSRX_EN_LBN 2
+#define	FRF_AB_XX_RSTXGXSRX_EN_WIDTH 1
+#define	FRF_AB_XX_RSTXGXSTX_EN_LBN 1
+#define	FRF_AB_XX_RSTXGXSTX_EN_WIDTH 1
+#define	FRF_AB_XX_RST_XX_EN_LBN 0
+#define	FRF_AB_XX_RST_XX_EN_WIDTH 1
+
+/* XX_SD_CTL_REG: XGXS/XAUI powerdown/reset control register */
+#define	FR_AB_XX_SD_CTL 0x00001310
+#define	FRF_AB_XX_TERMADJ1_LBN 17
+#define	FRF_AB_XX_TERMADJ1_WIDTH 1
+#define	FRF_AB_XX_TERMADJ0_LBN 16
+#define	FRF_AB_XX_TERMADJ0_WIDTH 1
+#define	FRF_AB_XX_HIDRVD_LBN 15
+#define	FRF_AB_XX_HIDRVD_WIDTH 1
+#define	FRF_AB_XX_LODRVD_LBN 14
+#define	FRF_AB_XX_LODRVD_WIDTH 1
+#define	FRF_AB_XX_HIDRVC_LBN 13
+#define	FRF_AB_XX_HIDRVC_WIDTH 1
+#define	FRF_AB_XX_LODRVC_LBN 12
+#define	FRF_AB_XX_LODRVC_WIDTH 1
+#define	FRF_AB_XX_HIDRVB_LBN 11
+#define	FRF_AB_XX_HIDRVB_WIDTH 1
+#define	FRF_AB_XX_LODRVB_LBN 10
+#define	FRF_AB_XX_LODRVB_WIDTH 1
+#define	FRF_AB_XX_HIDRVA_LBN 9
+#define	FRF_AB_XX_HIDRVA_WIDTH 1
+#define	FRF_AB_XX_LODRVA_LBN 8
+#define	FRF_AB_XX_LODRVA_WIDTH 1
+#define	FRF_AB_XX_LPBKD_LBN 3
+#define	FRF_AB_XX_LPBKD_WIDTH 1
+#define	FRF_AB_XX_LPBKC_LBN 2
+#define	FRF_AB_XX_LPBKC_WIDTH 1
+#define	FRF_AB_XX_LPBKB_LBN 1
+#define	FRF_AB_XX_LPBKB_WIDTH 1
+#define	FRF_AB_XX_LPBKA_LBN 0
+#define	FRF_AB_XX_LPBKA_WIDTH 1
+
+/* XX_TXDRV_CTL_REG: XAUI SerDes transmit drive control register */
+#define	FR_AB_XX_TXDRV_CTL 0x00001320
+#define	FRF_AB_XX_DEQD_LBN 28
+#define	FRF_AB_XX_DEQD_WIDTH 4
+#define	FRF_AB_XX_DEQC_LBN 24
+#define	FRF_AB_XX_DEQC_WIDTH 4
+#define	FRF_AB_XX_DEQB_LBN 20
+#define	FRF_AB_XX_DEQB_WIDTH 4
+#define	FRF_AB_XX_DEQA_LBN 16
+#define	FRF_AB_XX_DEQA_WIDTH 4
+#define	FRF_AB_XX_DTXD_LBN 12
+#define	FRF_AB_XX_DTXD_WIDTH 4
+#define	FRF_AB_XX_DTXC_LBN 8
+#define	FRF_AB_XX_DTXC_WIDTH 4
+#define	FRF_AB_XX_DTXB_LBN 4
+#define	FRF_AB_XX_DTXB_WIDTH 4
+#define	FRF_AB_XX_DTXA_LBN 0
+#define	FRF_AB_XX_DTXA_WIDTH 4
+
+/* XX_PRBS_CTL_REG: documentation to be written for sum_XX_PRBS_CTL_REG */
+#define	FR_AB_XX_PRBS_CTL 0x00001330
+#define	FRF_AB_XX_CH3_RX_PRBS_SEL_LBN 30
+#define	FRF_AB_XX_CH3_RX_PRBS_SEL_WIDTH 2
+#define	FRF_AB_XX_CH3_RX_PRBS_INV_LBN 29
+#define	FRF_AB_XX_CH3_RX_PRBS_INV_WIDTH 1
+#define	FRF_AB_XX_CH3_RX_PRBS_CHKEN_LBN 28
+#define	FRF_AB_XX_CH3_RX_PRBS_CHKEN_WIDTH 1
+#define	FRF_AB_XX_CH2_RX_PRBS_SEL_LBN 26
+#define	FRF_AB_XX_CH2_RX_PRBS_SEL_WIDTH 2
+#define	FRF_AB_XX_CH2_RX_PRBS_INV_LBN 25
+#define	FRF_AB_XX_CH2_RX_PRBS_INV_WIDTH 1
+#define	FRF_AB_XX_CH2_RX_PRBS_CHKEN_LBN 24
+#define	FRF_AB_XX_CH2_RX_PRBS_CHKEN_WIDTH 1
+#define	FRF_AB_XX_CH1_RX_PRBS_SEL_LBN 22
+#define	FRF_AB_XX_CH1_RX_PRBS_SEL_WIDTH 2
+#define	FRF_AB_XX_CH1_RX_PRBS_INV_LBN 21
+#define	FRF_AB_XX_CH1_RX_PRBS_INV_WIDTH 1
+#define	FRF_AB_XX_CH1_RX_PRBS_CHKEN_LBN 20
+#define	FRF_AB_XX_CH1_RX_PRBS_CHKEN_WIDTH 1
+#define	FRF_AB_XX_CH0_RX_PRBS_SEL_LBN 18
+#define	FRF_AB_XX_CH0_RX_PRBS_SEL_WIDTH 2
+#define	FRF_AB_XX_CH0_RX_PRBS_INV_LBN 17
+#define	FRF_AB_XX_CH0_RX_PRBS_INV_WIDTH 1
+#define	FRF_AB_XX_CH0_RX_PRBS_CHKEN_LBN 16
+#define	FRF_AB_XX_CH0_RX_PRBS_CHKEN_WIDTH 1
+#define	FRF_AB_XX_CH3_TX_PRBS_SEL_LBN 14
+#define	FRF_AB_XX_CH3_TX_PRBS_SEL_WIDTH 2
+#define	FRF_AB_XX_CH3_TX_PRBS_INV_LBN 13
+#define	FRF_AB_XX_CH3_TX_PRBS_INV_WIDTH 1
+#define	FRF_AB_XX_CH3_TX_PRBS_CHKEN_LBN 12
+#define	FRF_AB_XX_CH3_TX_PRBS_CHKEN_WIDTH 1
+#define	FRF_AB_XX_CH2_TX_PRBS_SEL_LBN 10
+#define	FRF_AB_XX_CH2_TX_PRBS_SEL_WIDTH 2
+#define	FRF_AB_XX_CH2_TX_PRBS_INV_LBN 9
+#define	FRF_AB_XX_CH2_TX_PRBS_INV_WIDTH 1
+#define	FRF_AB_XX_CH2_TX_PRBS_CHKEN_LBN 8
+#define	FRF_AB_XX_CH2_TX_PRBS_CHKEN_WIDTH 1
+#define	FRF_AB_XX_CH1_TX_PRBS_SEL_LBN 6
+#define	FRF_AB_XX_CH1_TX_PRBS_SEL_WIDTH 2
+#define	FRF_AB_XX_CH1_TX_PRBS_INV_LBN 5
+#define	FRF_AB_XX_CH1_TX_PRBS_INV_WIDTH 1
+#define	FRF_AB_XX_CH1_TX_PRBS_CHKEN_LBN 4
+#define	FRF_AB_XX_CH1_TX_PRBS_CHKEN_WIDTH 1
+#define	FRF_AB_XX_CH0_TX_PRBS_SEL_LBN 2
+#define	FRF_AB_XX_CH0_TX_PRBS_SEL_WIDTH 2
+#define	FRF_AB_XX_CH0_TX_PRBS_INV_LBN 1
+#define	FRF_AB_XX_CH0_TX_PRBS_INV_WIDTH 1
+#define	FRF_AB_XX_CH0_TX_PRBS_CHKEN_LBN 0
+#define	FRF_AB_XX_CH0_TX_PRBS_CHKEN_WIDTH 1
+
+/* XX_PRBS_CHK_REG: documentation to be written for sum_XX_PRBS_CHK_REG */
+#define	FR_AB_XX_PRBS_CHK 0x00001340
+#define	FRF_AB_XX_REV_LB_EN_LBN 16
+#define	FRF_AB_XX_REV_LB_EN_WIDTH 1
+#define	FRF_AB_XX_CH3_DEG_DET_LBN 15
+#define	FRF_AB_XX_CH3_DEG_DET_WIDTH 1
+#define	FRF_AB_XX_CH3_LFSR_LOCK_IND_LBN 14
+#define	FRF_AB_XX_CH3_LFSR_LOCK_IND_WIDTH 1
+#define	FRF_AB_XX_CH3_PRBS_FRUN_LBN 13
+#define	FRF_AB_XX_CH3_PRBS_FRUN_WIDTH 1
+#define	FRF_AB_XX_CH3_ERR_CHK_LBN 12
+#define	FRF_AB_XX_CH3_ERR_CHK_WIDTH 1
+#define	FRF_AB_XX_CH2_DEG_DET_LBN 11
+#define	FRF_AB_XX_CH2_DEG_DET_WIDTH 1
+#define	FRF_AB_XX_CH2_LFSR_LOCK_IND_LBN 10
+#define	FRF_AB_XX_CH2_LFSR_LOCK_IND_WIDTH 1
+#define	FRF_AB_XX_CH2_PRBS_FRUN_LBN 9
+#define	FRF_AB_XX_CH2_PRBS_FRUN_WIDTH 1
+#define	FRF_AB_XX_CH2_ERR_CHK_LBN 8
+#define	FRF_AB_XX_CH2_ERR_CHK_WIDTH 1
+#define	FRF_AB_XX_CH1_DEG_DET_LBN 7
+#define	FRF_AB_XX_CH1_DEG_DET_WIDTH 1
+#define	FRF_AB_XX_CH1_LFSR_LOCK_IND_LBN 6
+#define	FRF_AB_XX_CH1_LFSR_LOCK_IND_WIDTH 1
+#define	FRF_AB_XX_CH1_PRBS_FRUN_LBN 5
+#define	FRF_AB_XX_CH1_PRBS_FRUN_WIDTH 1
+#define	FRF_AB_XX_CH1_ERR_CHK_LBN 4
+#define	FRF_AB_XX_CH1_ERR_CHK_WIDTH 1
+#define	FRF_AB_XX_CH0_DEG_DET_LBN 3
+#define	FRF_AB_XX_CH0_DEG_DET_WIDTH 1
+#define	FRF_AB_XX_CH0_LFSR_LOCK_IND_LBN 2
+#define	FRF_AB_XX_CH0_LFSR_LOCK_IND_WIDTH 1
+#define	FRF_AB_XX_CH0_PRBS_FRUN_LBN 1
+#define	FRF_AB_XX_CH0_PRBS_FRUN_WIDTH 1
+#define	FRF_AB_XX_CH0_ERR_CHK_LBN 0
+#define	FRF_AB_XX_CH0_ERR_CHK_WIDTH 1
+
+/* XX_PRBS_ERR_REG: documentation to be written for sum_XX_PRBS_ERR_REG */
+#define	FR_AB_XX_PRBS_ERR 0x00001350
+#define	FRF_AB_XX_CH3_PRBS_ERR_CNT_LBN 24
+#define	FRF_AB_XX_CH3_PRBS_ERR_CNT_WIDTH 8
+#define	FRF_AB_XX_CH2_PRBS_ERR_CNT_LBN 16
+#define	FRF_AB_XX_CH2_PRBS_ERR_CNT_WIDTH 8
+#define	FRF_AB_XX_CH1_PRBS_ERR_CNT_LBN 8
+#define	FRF_AB_XX_CH1_PRBS_ERR_CNT_WIDTH 8
+#define	FRF_AB_XX_CH0_PRBS_ERR_CNT_LBN 0
+#define	FRF_AB_XX_CH0_PRBS_ERR_CNT_WIDTH 8
+
+/* XX_CORE_STAT_REG: XAUI XGXS core status register */
+#define	FR_AB_XX_CORE_STAT 0x00001360
+#define	FRF_AB_XX_FORCE_SIG3_LBN 31
+#define	FRF_AB_XX_FORCE_SIG3_WIDTH 1
+#define	FRF_AB_XX_FORCE_SIG3_VAL_LBN 30
+#define	FRF_AB_XX_FORCE_SIG3_VAL_WIDTH 1
+#define	FRF_AB_XX_FORCE_SIG2_LBN 29
+#define	FRF_AB_XX_FORCE_SIG2_WIDTH 1
+#define	FRF_AB_XX_FORCE_SIG2_VAL_LBN 28
+#define	FRF_AB_XX_FORCE_SIG2_VAL_WIDTH 1
+#define	FRF_AB_XX_FORCE_SIG1_LBN 27
+#define	FRF_AB_XX_FORCE_SIG1_WIDTH 1
+#define	FRF_AB_XX_FORCE_SIG1_VAL_LBN 26
+#define	FRF_AB_XX_FORCE_SIG1_VAL_WIDTH 1
+#define	FRF_AB_XX_FORCE_SIG0_LBN 25
+#define	FRF_AB_XX_FORCE_SIG0_WIDTH 1
+#define	FRF_AB_XX_FORCE_SIG0_VAL_LBN 24
+#define	FRF_AB_XX_FORCE_SIG0_VAL_WIDTH 1
+#define	FRF_AB_XX_XGXS_LB_EN_LBN 23
+#define	FRF_AB_XX_XGXS_LB_EN_WIDTH 1
+#define	FRF_AB_XX_XGMII_LB_EN_LBN 22
+#define	FRF_AB_XX_XGMII_LB_EN_WIDTH 1
+#define	FRF_AB_XX_MATCH_FAULT_LBN 21
+#define	FRF_AB_XX_MATCH_FAULT_WIDTH 1
+#define	FRF_AB_XX_ALIGN_DONE_LBN 20
+#define	FRF_AB_XX_ALIGN_DONE_WIDTH 1
+#define	FRF_AB_XX_SYNC_STAT3_LBN 19
+#define	FRF_AB_XX_SYNC_STAT3_WIDTH 1
+#define	FRF_AB_XX_SYNC_STAT2_LBN 18
+#define	FRF_AB_XX_SYNC_STAT2_WIDTH 1
+#define	FRF_AB_XX_SYNC_STAT1_LBN 17
+#define	FRF_AB_XX_SYNC_STAT1_WIDTH 1
+#define	FRF_AB_XX_SYNC_STAT0_LBN 16
+#define	FRF_AB_XX_SYNC_STAT0_WIDTH 1
+#define	FRF_AB_XX_COMMA_DET_CH3_LBN 15
+#define	FRF_AB_XX_COMMA_DET_CH3_WIDTH 1
+#define	FRF_AB_XX_COMMA_DET_CH2_LBN 14
+#define	FRF_AB_XX_COMMA_DET_CH2_WIDTH 1
+#define	FRF_AB_XX_COMMA_DET_CH1_LBN 13
+#define	FRF_AB_XX_COMMA_DET_CH1_WIDTH 1
+#define	FRF_AB_XX_COMMA_DET_CH0_LBN 12
+#define	FRF_AB_XX_COMMA_DET_CH0_WIDTH 1
+#define	FRF_AB_XX_CGRP_ALIGN_CH3_LBN 11
+#define	FRF_AB_XX_CGRP_ALIGN_CH3_WIDTH 1
+#define	FRF_AB_XX_CGRP_ALIGN_CH2_LBN 10
+#define	FRF_AB_XX_CGRP_ALIGN_CH2_WIDTH 1
+#define	FRF_AB_XX_CGRP_ALIGN_CH1_LBN 9
+#define	FRF_AB_XX_CGRP_ALIGN_CH1_WIDTH 1
+#define	FRF_AB_XX_CGRP_ALIGN_CH0_LBN 8
+#define	FRF_AB_XX_CGRP_ALIGN_CH0_WIDTH 1
+#define	FRF_AB_XX_CHAR_ERR_CH3_LBN 7
+#define	FRF_AB_XX_CHAR_ERR_CH3_WIDTH 1
+#define	FRF_AB_XX_CHAR_ERR_CH2_LBN 6
+#define	FRF_AB_XX_CHAR_ERR_CH2_WIDTH 1
+#define	FRF_AB_XX_CHAR_ERR_CH1_LBN 5
+#define	FRF_AB_XX_CHAR_ERR_CH1_WIDTH 1
+#define	FRF_AB_XX_CHAR_ERR_CH0_LBN 4
+#define	FRF_AB_XX_CHAR_ERR_CH0_WIDTH 1
+#define	FRF_AB_XX_DISPERR_CH3_LBN 3
+#define	FRF_AB_XX_DISPERR_CH3_WIDTH 1
+#define	FRF_AB_XX_DISPERR_CH2_LBN 2
+#define	FRF_AB_XX_DISPERR_CH2_WIDTH 1
+#define	FRF_AB_XX_DISPERR_CH1_LBN 1
+#define	FRF_AB_XX_DISPERR_CH1_WIDTH 1
+#define	FRF_AB_XX_DISPERR_CH0_LBN 0
+#define	FRF_AB_XX_DISPERR_CH0_WIDTH 1
+
+/* RX_DESC_PTR_TBL_KER: Receive descriptor pointer table */
+#define	FR_AA_RX_DESC_PTR_TBL_KER 0x00011800
+#define	FR_AA_RX_DESC_PTR_TBL_KER_STEP 16
+#define	FR_AA_RX_DESC_PTR_TBL_KER_ROWS 4
+/* RX_DESC_PTR_TBL: Receive descriptor pointer table */
+#define	FR_BZ_RX_DESC_PTR_TBL 0x00f40000
+#define	FR_BZ_RX_DESC_PTR_TBL_STEP 16
+#define	FR_BB_RX_DESC_PTR_TBL_ROWS 4096
+#define	FR_CZ_RX_DESC_PTR_TBL_ROWS 1024
+#define	FRF_CZ_RX_HDR_SPLIT_LBN 90
+#define	FRF_CZ_RX_HDR_SPLIT_WIDTH 1
+#define	FRF_AA_RX_RESET_LBN 89
+#define	FRF_AA_RX_RESET_WIDTH 1
+#define	FRF_AZ_RX_ISCSI_DDIG_EN_LBN 88
+#define	FRF_AZ_RX_ISCSI_DDIG_EN_WIDTH 1
+#define	FRF_AZ_RX_ISCSI_HDIG_EN_LBN 87
+#define	FRF_AZ_RX_ISCSI_HDIG_EN_WIDTH 1
+#define	FRF_AZ_RX_DESC_PREF_ACT_LBN 86
+#define	FRF_AZ_RX_DESC_PREF_ACT_WIDTH 1
+#define	FRF_AZ_RX_DC_HW_RPTR_LBN 80
+#define	FRF_AZ_RX_DC_HW_RPTR_WIDTH 6
+#define	FRF_AZ_RX_DESCQ_HW_RPTR_LBN 68
+#define	FRF_AZ_RX_DESCQ_HW_RPTR_WIDTH 12
+#define	FRF_AZ_RX_DESCQ_SW_WPTR_LBN 56
+#define	FRF_AZ_RX_DESCQ_SW_WPTR_WIDTH 12
+#define	FRF_AZ_RX_DESCQ_BUF_BASE_ID_LBN 36
+#define	FRF_AZ_RX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define	FRF_AZ_RX_DESCQ_EVQ_ID_LBN 24
+#define	FRF_AZ_RX_DESCQ_EVQ_ID_WIDTH 12
+#define	FRF_AZ_RX_DESCQ_OWNER_ID_LBN 10
+#define	FRF_AZ_RX_DESCQ_OWNER_ID_WIDTH 14
+#define	FRF_AZ_RX_DESCQ_LABEL_LBN 5
+#define	FRF_AZ_RX_DESCQ_LABEL_WIDTH 5
+#define	FRF_AZ_RX_DESCQ_SIZE_LBN 3
+#define	FRF_AZ_RX_DESCQ_SIZE_WIDTH 2
+#define	FFE_AZ_RX_DESCQ_SIZE_4K 3
+#define	FFE_AZ_RX_DESCQ_SIZE_2K 2
+#define	FFE_AZ_RX_DESCQ_SIZE_1K 1
+#define	FFE_AZ_RX_DESCQ_SIZE_512 0
+#define	FRF_AZ_RX_DESCQ_TYPE_LBN 2
+#define	FRF_AZ_RX_DESCQ_TYPE_WIDTH 1
+#define	FRF_AZ_RX_DESCQ_JUMBO_LBN 1
+#define	FRF_AZ_RX_DESCQ_JUMBO_WIDTH 1
+#define	FRF_AZ_RX_DESCQ_EN_LBN 0
+#define	FRF_AZ_RX_DESCQ_EN_WIDTH 1
+
+/* TX_DESC_PTR_TBL_KER: Transmit descriptor pointer */
+#define	FR_AA_TX_DESC_PTR_TBL_KER 0x00011900
+#define	FR_AA_TX_DESC_PTR_TBL_KER_STEP 16
+#define	FR_AA_TX_DESC_PTR_TBL_KER_ROWS 8
+/* TX_DESC_PTR_TBL: Transmit descriptor pointer */
+#define	FR_BZ_TX_DESC_PTR_TBL 0x00f50000
+#define	FR_BZ_TX_DESC_PTR_TBL_STEP 16
+#define	FR_BB_TX_DESC_PTR_TBL_ROWS 4096
+#define	FR_CZ_TX_DESC_PTR_TBL_ROWS 1024
+#define	FRF_CZ_TX_DPT_Q_MASK_WIDTH_LBN 94
+#define	FRF_CZ_TX_DPT_Q_MASK_WIDTH_WIDTH 2
+#define	FRF_CZ_TX_DPT_ETH_FILT_EN_LBN 93
+#define	FRF_CZ_TX_DPT_ETH_FILT_EN_WIDTH 1
+#define	FRF_CZ_TX_DPT_IP_FILT_EN_LBN 92
+#define	FRF_CZ_TX_DPT_IP_FILT_EN_WIDTH 1
+#define	FRF_BZ_TX_NON_IP_DROP_DIS_LBN 91
+#define	FRF_BZ_TX_NON_IP_DROP_DIS_WIDTH 1
+#define	FRF_BZ_TX_IP_CHKSM_DIS_LBN 90
+#define	FRF_BZ_TX_IP_CHKSM_DIS_WIDTH 1
+#define	FRF_BZ_TX_TCP_CHKSM_DIS_LBN 89
+#define	FRF_BZ_TX_TCP_CHKSM_DIS_WIDTH 1
+#define	FRF_AZ_TX_DESCQ_EN_LBN 88
+#define	FRF_AZ_TX_DESCQ_EN_WIDTH 1
+#define	FRF_AZ_TX_ISCSI_DDIG_EN_LBN 87
+#define	FRF_AZ_TX_ISCSI_DDIG_EN_WIDTH 1
+#define	FRF_AZ_TX_ISCSI_HDIG_EN_LBN 86
+#define	FRF_AZ_TX_ISCSI_HDIG_EN_WIDTH 1
+#define	FRF_AZ_TX_DC_HW_RPTR_LBN 80
+#define	FRF_AZ_TX_DC_HW_RPTR_WIDTH 6
+#define	FRF_AZ_TX_DESCQ_HW_RPTR_LBN 68
+#define	FRF_AZ_TX_DESCQ_HW_RPTR_WIDTH 12
+#define	FRF_AZ_TX_DESCQ_SW_WPTR_LBN 56
+#define	FRF_AZ_TX_DESCQ_SW_WPTR_WIDTH 12
+#define	FRF_AZ_TX_DESCQ_BUF_BASE_ID_LBN 36
+#define	FRF_AZ_TX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define	FRF_AZ_TX_DESCQ_EVQ_ID_LBN 24
+#define	FRF_AZ_TX_DESCQ_EVQ_ID_WIDTH 12
+#define	FRF_AZ_TX_DESCQ_OWNER_ID_LBN 10
+#define	FRF_AZ_TX_DESCQ_OWNER_ID_WIDTH 14
+#define	FRF_AZ_TX_DESCQ_LABEL_LBN 5
+#define	FRF_AZ_TX_DESCQ_LABEL_WIDTH 5
+#define	FRF_AZ_TX_DESCQ_SIZE_LBN 3
+#define	FRF_AZ_TX_DESCQ_SIZE_WIDTH 2
+#define	FFE_AZ_TX_DESCQ_SIZE_4K 3
+#define	FFE_AZ_TX_DESCQ_SIZE_2K 2
+#define	FFE_AZ_TX_DESCQ_SIZE_1K 1
+#define	FFE_AZ_TX_DESCQ_SIZE_512 0
+#define	FRF_AZ_TX_DESCQ_TYPE_LBN 1
+#define	FRF_AZ_TX_DESCQ_TYPE_WIDTH 2
+#define	FRF_AZ_TX_DESCQ_FLUSH_LBN 0
+#define	FRF_AZ_TX_DESCQ_FLUSH_WIDTH 1
+
+/* EVQ_PTR_TBL_KER: Event queue pointer table */
+#define	FR_AA_EVQ_PTR_TBL_KER 0x00011a00
+#define	FR_AA_EVQ_PTR_TBL_KER_STEP 16
+#define	FR_AA_EVQ_PTR_TBL_KER_ROWS 4
+/* EVQ_PTR_TBL: Event queue pointer table */
+#define	FR_BZ_EVQ_PTR_TBL 0x00f60000
+#define	FR_BZ_EVQ_PTR_TBL_STEP 16
+#define	FR_CZ_EVQ_PTR_TBL_ROWS 1024
+#define	FR_BB_EVQ_PTR_TBL_ROWS 4096
+#define	FRF_BZ_EVQ_RPTR_IGN_LBN 40
+#define	FRF_BZ_EVQ_RPTR_IGN_WIDTH 1
+#define	FRF_AB_EVQ_WKUP_OR_INT_EN_LBN 39
+#define	FRF_AB_EVQ_WKUP_OR_INT_EN_WIDTH 1
+#define	FRF_CZ_EVQ_DOS_PROTECT_EN_LBN 39
+#define	FRF_CZ_EVQ_DOS_PROTECT_EN_WIDTH 1
+#define	FRF_AZ_EVQ_NXT_WPTR_LBN 24
+#define	FRF_AZ_EVQ_NXT_WPTR_WIDTH 15
+#define	FRF_AZ_EVQ_EN_LBN 23
+#define	FRF_AZ_EVQ_EN_WIDTH 1
+#define	FRF_AZ_EVQ_SIZE_LBN 20
+#define	FRF_AZ_EVQ_SIZE_WIDTH 3
+#define	FFE_AZ_EVQ_SIZE_32K 6
+#define	FFE_AZ_EVQ_SIZE_16K 5
+#define	FFE_AZ_EVQ_SIZE_8K 4
+#define	FFE_AZ_EVQ_SIZE_4K 3
+#define	FFE_AZ_EVQ_SIZE_2K 2
+#define	FFE_AZ_EVQ_SIZE_1K 1
+#define	FFE_AZ_EVQ_SIZE_512 0
+#define	FRF_AZ_EVQ_BUF_BASE_ID_LBN 0
+#define	FRF_AZ_EVQ_BUF_BASE_ID_WIDTH 20
+
+/* BUF_HALF_TBL_KER: Buffer table in half buffer table mode direct access by driver */
+#define	FR_AA_BUF_HALF_TBL_KER 0x00018000
+#define	FR_AA_BUF_HALF_TBL_KER_STEP 8
+#define	FR_AA_BUF_HALF_TBL_KER_ROWS 4096
+/* BUF_HALF_TBL: Buffer table in half buffer table mode direct access by driver */
+#define	FR_BZ_BUF_HALF_TBL 0x00800000
+#define	FR_BZ_BUF_HALF_TBL_STEP 8
+#define	FR_CZ_BUF_HALF_TBL_ROWS 147456
+#define	FR_BB_BUF_HALF_TBL_ROWS 524288
+#define	FRF_AZ_BUF_ADR_HBUF_ODD_LBN 44
+#define	FRF_AZ_BUF_ADR_HBUF_ODD_WIDTH 20
+#define	FRF_AZ_BUF_OWNER_ID_HBUF_ODD_LBN 32
+#define	FRF_AZ_BUF_OWNER_ID_HBUF_ODD_WIDTH 12
+#define	FRF_AZ_BUF_ADR_HBUF_EVEN_LBN 12
+#define	FRF_AZ_BUF_ADR_HBUF_EVEN_WIDTH 20
+#define	FRF_AZ_BUF_OWNER_ID_HBUF_EVEN_LBN 0
+#define	FRF_AZ_BUF_OWNER_ID_HBUF_EVEN_WIDTH 12
+
+/* BUF_FULL_TBL_KER: Buffer table in full buffer table mode direct access by driver */
+#define	FR_AA_BUF_FULL_TBL_KER 0x00018000
+#define	FR_AA_BUF_FULL_TBL_KER_STEP 8
+#define	FR_AA_BUF_FULL_TBL_KER_ROWS 4096
+/* BUF_FULL_TBL: Buffer table in full buffer table mode direct access by driver */
+#define	FR_BZ_BUF_FULL_TBL 0x00800000
+#define	FR_BZ_BUF_FULL_TBL_STEP 8
+#define	FR_CZ_BUF_FULL_TBL_ROWS 147456
+#define	FR_BB_BUF_FULL_TBL_ROWS 917504
+#define	FRF_AZ_BUF_FULL_UNUSED_LBN 51
+#define	FRF_AZ_BUF_FULL_UNUSED_WIDTH 13
+#define	FRF_AZ_IP_DAT_BUF_SIZE_LBN 50
+#define	FRF_AZ_IP_DAT_BUF_SIZE_WIDTH 1
+#define	FRF_AZ_BUF_ADR_REGION_LBN 48
+#define	FRF_AZ_BUF_ADR_REGION_WIDTH 2
+#define	FFE_AZ_BUF_ADR_REGN3 3
+#define	FFE_AZ_BUF_ADR_REGN2 2
+#define	FFE_AZ_BUF_ADR_REGN1 1
+#define	FFE_AZ_BUF_ADR_REGN0 0
+#define	FRF_AZ_BUF_ADR_FBUF_LBN 14
+#define	FRF_AZ_BUF_ADR_FBUF_WIDTH 34
+#define	FRF_AZ_BUF_OWNER_ID_FBUF_LBN 0
+#define	FRF_AZ_BUF_OWNER_ID_FBUF_WIDTH 14
+
+/* RX_FILTER_TBL0: TCP/IPv4 Receive filter table */
+#define	FR_BZ_RX_FILTER_TBL0 0x00f00000
+#define	FR_BZ_RX_FILTER_TBL0_STEP 32
+#define	FR_BZ_RX_FILTER_TBL0_ROWS 8192
+/* RX_FILTER_TBL1: TCP/IPv4 Receive filter table */
+#define	FR_BB_RX_FILTER_TBL1 0x00f00010
+#define	FR_BB_RX_FILTER_TBL1_STEP 32
+#define	FR_BB_RX_FILTER_TBL1_ROWS 8192
+#define	FRF_BZ_RSS_EN_LBN 110
+#define	FRF_BZ_RSS_EN_WIDTH 1
+#define	FRF_BZ_SCATTER_EN_LBN 109
+#define	FRF_BZ_SCATTER_EN_WIDTH 1
+#define	FRF_BZ_TCP_UDP_LBN 108
+#define	FRF_BZ_TCP_UDP_WIDTH 1
+#define	FRF_BZ_RXQ_ID_LBN 96
+#define	FRF_BZ_RXQ_ID_WIDTH 12
+#define	FRF_BZ_DEST_IP_LBN 64
+#define	FRF_BZ_DEST_IP_WIDTH 32
+#define	FRF_BZ_DEST_PORT_TCP_LBN 48
+#define	FRF_BZ_DEST_PORT_TCP_WIDTH 16
+#define	FRF_BZ_SRC_IP_LBN 16
+#define	FRF_BZ_SRC_IP_WIDTH 32
+#define	FRF_BZ_SRC_TCP_DEST_UDP_LBN 0
+#define	FRF_BZ_SRC_TCP_DEST_UDP_WIDTH 16
+
+/* RX_MAC_FILTER_TBL0: Receive Ethernet filter table */
+#define	FR_CZ_RX_MAC_FILTER_TBL0 0x00f00010
+#define	FR_CZ_RX_MAC_FILTER_TBL0_STEP 32
+#define	FR_CZ_RX_MAC_FILTER_TBL0_ROWS 512
+#define	FRF_CZ_RMFT_RSS_EN_LBN 75
+#define	FRF_CZ_RMFT_RSS_EN_WIDTH 1
+#define	FRF_CZ_RMFT_SCATTER_EN_LBN 74
+#define	FRF_CZ_RMFT_SCATTER_EN_WIDTH 1
+#define	FRF_CZ_RMFT_IP_OVERRIDE_LBN 73
+#define	FRF_CZ_RMFT_IP_OVERRIDE_WIDTH 1
+#define	FRF_CZ_RMFT_RXQ_ID_LBN 61
+#define	FRF_CZ_RMFT_RXQ_ID_WIDTH 12
+#define	FRF_CZ_RMFT_WILDCARD_MATCH_LBN 60
+#define	FRF_CZ_RMFT_WILDCARD_MATCH_WIDTH 1
+#define	FRF_CZ_RMFT_DEST_MAC_LBN 12
+#define	FRF_CZ_RMFT_DEST_MAC_WIDTH 48
+#define	FRF_CZ_RMFT_VLAN_ID_LBN 0
+#define	FRF_CZ_RMFT_VLAN_ID_WIDTH 12
+
+/* TIMER_TBL: Timer table */
+#define	FR_BZ_TIMER_TBL 0x00f70000
+#define	FR_BZ_TIMER_TBL_STEP 16
+#define	FR_CZ_TIMER_TBL_ROWS 1024
+#define	FR_BB_TIMER_TBL_ROWS 4096
+#define	FRF_CZ_TIMER_Q_EN_LBN 33
+#define	FRF_CZ_TIMER_Q_EN_WIDTH 1
+#define	FRF_CZ_INT_ARMD_LBN 32
+#define	FRF_CZ_INT_ARMD_WIDTH 1
+#define	FRF_CZ_INT_PEND_LBN 31
+#define	FRF_CZ_INT_PEND_WIDTH 1
+#define	FRF_CZ_HOST_NOTIFY_MODE_LBN 30
+#define	FRF_CZ_HOST_NOTIFY_MODE_WIDTH 1
+#define	FRF_CZ_RELOAD_TIMER_VAL_LBN 16
+#define	FRF_CZ_RELOAD_TIMER_VAL_WIDTH 14
+#define	FRF_CZ_TIMER_MODE_LBN 14
+#define	FRF_CZ_TIMER_MODE_WIDTH 2
+#define	FFE_CZ_TIMER_MODE_INT_HLDOFF 3
+#define	FFE_CZ_TIMER_MODE_TRIG_START 2
+#define	FFE_CZ_TIMER_MODE_IMMED_START 1
+#define	FFE_CZ_TIMER_MODE_DIS 0
+#define	FRF_BB_TIMER_MODE_LBN 12
+#define	FRF_BB_TIMER_MODE_WIDTH 2
+#define	FFE_BB_TIMER_MODE_INT_HLDOFF 2
+#define	FFE_BB_TIMER_MODE_TRIG_START 2
+#define	FFE_BB_TIMER_MODE_IMMED_START 1
+#define	FFE_BB_TIMER_MODE_DIS 0
+#define	FRF_CZ_TIMER_VAL_LBN 0
+#define	FRF_CZ_TIMER_VAL_WIDTH 14
+#define	FRF_BB_TIMER_VAL_LBN 0
+#define	FRF_BB_TIMER_VAL_WIDTH 12
+
+/* TX_PACE_TBL: Transmit pacing table */
+#define	FR_BZ_TX_PACE_TBL 0x00f80000
+#define	FR_BZ_TX_PACE_TBL_STEP 16
+#define	FR_CZ_TX_PACE_TBL_ROWS 1024
+#define	FR_BB_TX_PACE_TBL_ROWS 4096
+#define	FRF_BZ_TX_PACE_LBN 0
+#define	FRF_BZ_TX_PACE_WIDTH 5
+
+/* RX_INDIRECTION_TBL: RX Indirection Table */
+#define	FR_BZ_RX_INDIRECTION_TBL 0x00fb0000
+#define	FR_BZ_RX_INDIRECTION_TBL_STEP 16
+#define	FR_BZ_RX_INDIRECTION_TBL_ROWS 128
+#define	FRF_BZ_IT_QUEUE_LBN 0
+#define	FRF_BZ_IT_QUEUE_WIDTH 6
+
+/* TX_FILTER_TBL0: TCP/IPv4 Transmit filter table */
+#define	FR_CZ_TX_FILTER_TBL0 0x00fc0000
+#define	FR_CZ_TX_FILTER_TBL0_STEP 16
+#define	FR_CZ_TX_FILTER_TBL0_ROWS 8192
+#define	FRF_CZ_TIFT_TCP_UDP_LBN 108
+#define	FRF_CZ_TIFT_TCP_UDP_WIDTH 1
+#define	FRF_CZ_TIFT_TXQ_ID_LBN 96
+#define	FRF_CZ_TIFT_TXQ_ID_WIDTH 12
+#define	FRF_CZ_TIFT_DEST_IP_LBN 64
+#define	FRF_CZ_TIFT_DEST_IP_WIDTH 32
+#define	FRF_CZ_TIFT_DEST_PORT_TCP_LBN 48
+#define	FRF_CZ_TIFT_DEST_PORT_TCP_WIDTH 16
+#define	FRF_CZ_TIFT_SRC_IP_LBN 16
+#define	FRF_CZ_TIFT_SRC_IP_WIDTH 32
+#define	FRF_CZ_TIFT_SRC_TCP_DEST_UDP_LBN 0
+#define	FRF_CZ_TIFT_SRC_TCP_DEST_UDP_WIDTH 16
+
+/* TX_MAC_FILTER_TBL0: Transmit Ethernet filter table */
+#define	FR_CZ_TX_MAC_FILTER_TBL0 0x00fe0000
+#define	FR_CZ_TX_MAC_FILTER_TBL0_STEP 16
+#define	FR_CZ_TX_MAC_FILTER_TBL0_ROWS 512
+#define	FRF_CZ_TMFT_TXQ_ID_LBN 61
+#define	FRF_CZ_TMFT_TXQ_ID_WIDTH 12
+#define	FRF_CZ_TMFT_WILDCARD_MATCH_LBN 60
+#define	FRF_CZ_TMFT_WILDCARD_MATCH_WIDTH 1
+#define	FRF_CZ_TMFT_SRC_MAC_LBN 12
+#define	FRF_CZ_TMFT_SRC_MAC_WIDTH 48
+#define	FRF_CZ_TMFT_VLAN_ID_LBN 0
+#define	FRF_CZ_TMFT_VLAN_ID_WIDTH 12
+
+/* MC_TREG_SMEM: MC Shared Memory */
+#define	FR_CZ_MC_TREG_SMEM 0x00ff0000
+#define	FR_CZ_MC_TREG_SMEM_STEP 4
+#define	FR_CZ_MC_TREG_SMEM_ROWS 512
+#define	FRF_CZ_MC_TREG_SMEM_ROW_LBN 0
+#define	FRF_CZ_MC_TREG_SMEM_ROW_WIDTH 32
+
+/* EF10 architecture register definitions
+ * (from linux/drivers/net/ethernet/sfc/ef10_regs.h)
+ */
+
+/* BIU_HW_REV_ID_REG:  */
+#define	ER_DZ_BIU_HW_REV_ID 0x00000000
+#define	ERF_DZ_HW_REV_ID_LBN 0
+#define	ERF_DZ_HW_REV_ID_WIDTH 32
+
+/* BIU_MC_SFT_STATUS_REG:  */
+#define	ER_DZ_BIU_MC_SFT_STATUS 0x00000010
+#define	ER_DZ_BIU_MC_SFT_STATUS_STEP 4
+#define	ER_DZ_BIU_MC_SFT_STATUS_ROWS 8
+#define	ERF_DZ_MC_SFT_STATUS_LBN 0
+#define	ERF_DZ_MC_SFT_STATUS_WIDTH 32
+
+/* BIU_INT_ISR_REG:  */
+#define	ER_DZ_BIU_INT_ISR 0x00000090
+#define	ERF_DZ_ISR_REG_LBN 0
+#define	ERF_DZ_ISR_REG_WIDTH 32
+
+/* MC_DB_LWRD_REG:  */
+#define	ER_DZ_MC_DB_LWRD 0x00000200
+#define	ERF_DZ_MC_DOORBELL_L_LBN 0
+#define	ERF_DZ_MC_DOORBELL_L_WIDTH 32
+
+/* MC_DB_HWRD_REG:  */
+#define	ER_DZ_MC_DB_HWRD 0x00000204
+#define	ERF_DZ_MC_DOORBELL_H_LBN 0
+#define	ERF_DZ_MC_DOORBELL_H_WIDTH 32
+
+/*
+ * Register dump definition.  This is mostly taken from
+ * linux/drivers/net/ethernet/sfc/nic.c but has names and bitfield
+ * definitions added.
+ *
+ * The definitions of efx_nic_regs and efx_nic_reg_tables should be
+ * textually identical to those in the driver, though the structure
+ * definitions and the macros REGISTER and REGISTER_TABLE_DIMENSIONS
+ * are defined differently.
+ */
+
+#define REGISTER_REVISION_FA	1
+#define REGISTER_REVISION_FB	2
+#define REGISTER_REVISION_FC	3
+#define REGISTER_REVISION_FZ	3	/* last Falcon arch revision */
+#define REGISTER_REVISION_ED	4
+#define REGISTER_REVISION_EZ	4	/* latest EF10 arch revision */
+
+struct efx_nic_reg_field {
+	const char *name;
+	u8 lbn, width;
+	u8 min_revision, max_revision;
+};
+
+#define REGISTER_FIELD_RENAME(name, display_name, arch, min_rev, max_rev) { \
+	display_name,							\
+	arch ## RF_ ## min_rev ## max_rev ## _ ## name ## _LBN,		\
+	arch ## RF_ ## min_rev ## max_rev ## _ ## name ## _WIDTH,	\
+	REGISTER_REVISION_ ## arch ## min_rev,				\
+	REGISTER_REVISION_ ## arch ## max_rev				\
+}
+#define REGISTER_FIELD(name, arch, min_rev, max_rev)			\
+	REGISTER_FIELD_RENAME(name, #name, arch, min_rev, max_rev)
+#define REGISTER_FIELD_AA(name) REGISTER_FIELD(name, F, A, A)
+#define REGISTER_FIELD_AB(name) REGISTER_FIELD(name, F, A, B)
+#define REGISTER_FIELD_AZ(name) REGISTER_FIELD(name, F, A, Z)
+#define REGISTER_FIELD_BB(name) REGISTER_FIELD(name, F, B, B)
+#define REGISTER_FIELD_BZ(name) REGISTER_FIELD(name, F, B, Z)
+#define REGISTER_FIELD_CZ(name) REGISTER_FIELD(name, F, C, Z)
+#define REGISTER_FIELD_DZ(name) REGISTER_FIELD(name, E, D, Z)
+#define REGISTER_FIELD_AZ_RENAME(name, display_name)	\
+	REGISTER_FIELD_RENAME(name, display_name, F, A, Z)
+#define REGISTER_FIELD_BZ_RENAME(name, display_name)	\
+	REGISTER_FIELD_RENAME(name, display_name, F, B, Z)
+#define REGISTER_FIELD_CZ_RENAME(name, display_name)	\
+	REGISTER_FIELD_RENAME(name, display_name, F, C, Z)
+
+static const struct efx_nic_reg_field efx_nic_reg_fields_ADR_REGION[] = {
+	REGISTER_FIELD_AZ(ADR_REGION0),
+	REGISTER_FIELD_AZ(ADR_REGION1),
+	REGISTER_FIELD_AZ(ADR_REGION2),
+	REGISTER_FIELD_AZ(ADR_REGION3),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_INT_EN_KER[] = {
+	REGISTER_FIELD_AZ(DRV_INT_EN_KER),
+	REGISTER_FIELD_AZ(KER_INT_KER),
+	REGISTER_FIELD_AZ(KER_INT_CHAR),
+	REGISTER_FIELD_AZ(KER_INT_LEVE_SEL),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_INT_EN_CHAR[] = {
+	REGISTER_FIELD_BZ(DRV_INT_EN_CHAR),
+	REGISTER_FIELD_BZ(CHAR_INT_KER),
+	REGISTER_FIELD_BZ(CHAR_INT_CHAR),
+	REGISTER_FIELD_BZ(CHAR_INT_LEVE_SEL),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_INT_ADR_KER[] = {
+	REGISTER_FIELD_AZ(INT_ADR_KER),
+	REGISTER_FIELD_AZ(NORM_INT_VEC_DIS_KER),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_INT_ADR_CHAR[] = {
+	REGISTER_FIELD_BZ(INT_ADR_CHAR),
+	REGISTER_FIELD_BZ(NORM_INT_VEC_DIS_CHAR),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_HW_INIT[] = {
+	REGISTER_FIELD_AZ(TLP_TD),
+	REGISTER_FIELD_AZ(TD_SEL),
+	REGISTER_FIELD_AZ(ATTR_SEL),
+	REGISTER_FIELD_AZ(TLP_EP),
+	REGISTER_FIELD_AZ(US_DISABLE),
+	REGISTER_FIELD_AZ(WD_TIMER),
+	REGISTER_FIELD_AB(INTA_VEC),
+	REGISTER_FIELD_AB(INTB_VEC),
+	REGISTER_FIELD_AZ(TLP_ATTR),
+	REGISTER_FIELD_AZ(TLP_TC),
+	REGISTER_FIELD_AZ(POST_WR_MASK),
+	REGISTER_FIELD_BB(FC_BLOCKING_EN),
+	REGISTER_FIELD_AA(B2B_REQ_EN),
+	REGISTER_FIELD_BZ(B2B_REQ_EN),
+	REGISTER_FIELD_AA(FC_BLOCKING_EN),
+	REGISTER_FIELD_AB(PE_EIDLE_DIS),
+	REGISTER_FIELD_AB(TX_RREQ_MASK_EN),
+	REGISTER_FIELD_AZ(DOORBELL_DROP),
+	REGISTER_FIELD_AB(TRGT_MASK_ALL),
+	REGISTER_FIELD_CZ(TX_MRG_TAGS),
+	REGISTER_FIELD_BB(PCIE_CPL_TIMEOUT_CTRL),
+	REGISTER_FIELD_BB(BDMRD_CPLF_FULL),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_USR_EV_CFG[] = {
+	REGISTER_FIELD_CZ(DFLT_EVQ),
+	REGISTER_FIELD_CZ(USREV_DIS),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_EE_SPI_HCMD[] = {
+	REGISTER_FIELD_AB(EE_SPI_HCMD_ENC),
+	REGISTER_FIELD_AB(EE_SPI_HCMD_ADBCNT),
+	REGISTER_FIELD_AB(EE_SPI_HCMD_DUBCNT),
+	REGISTER_FIELD_AB(EE_SPI_HCMD_READ),
+	REGISTER_FIELD_AB(EE_SPI_HCMD_DABCNT),
+	REGISTER_FIELD_AB(EE_SPI_HCMD_SF_SEL),
+	REGISTER_FIELD_AB(EE_WR_TIMER_ACTIVE),
+	REGISTER_FIELD_AB(EE_SPI_HCMD_CMD_EN),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_EE_SPI_HADR[] = {
+	REGISTER_FIELD_AB(EE_SPI_HADR_ADR),
+	REGISTER_FIELD_AB(EE_SPI_HADR_DUBYTE),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_EE_SPI_HDATA[] = {
+	REGISTER_FIELD_AB(EE_SPI_HDATA0),
+	REGISTER_FIELD_AB(EE_SPI_HDATA1),
+	REGISTER_FIELD_AB(EE_SPI_HDATA2),
+	REGISTER_FIELD_AB(EE_SPI_HDATA3),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_EE_BASE_PAGE[] = {
+	REGISTER_FIELD_AB(EE_EXP_ROM_WINDOW_BASE),
+	REGISTER_FIELD_AB(EE_EXPROM_MASK),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_EE_VPD_CFG0[] = {
+	REGISTER_FIELD_AB(EE_VPD_EN),
+	REGISTER_FIELD_AB(EE_VPD_EN_AD9_MODE),
+	REGISTER_FIELD_AB(EE_VPD_DEV_SF_SEL),
+	REGISTER_FIELD_AB(EE_VPD_ACCESS_BLOCK),
+	REGISTER_FIELD_AB(EE_VPD_ACCESS_ON),
+	REGISTER_FIELD_AB(EE_VPD_AD_SIZE),
+	REGISTER_FIELD_AB(EE_VPD_LENGTH),
+	REGISTER_FIELD_AB(EE_VPD_BASE),
+	REGISTER_FIELD_AB(EE_VPD_WR_CMD_EN),
+	REGISTER_FIELD_AB(EE_VPDW_BASE),
+	REGISTER_FIELD_AB(EE_VPDW_LENGTH),
+	REGISTER_FIELD_AB(EE_EE_WR_TMR_VALUE),
+	REGISTER_FIELD_AB(EE_EE_CLOCK_DIV),
+	REGISTER_FIELD_AB(EE_VPD_WIP_POLL),
+	REGISTER_FIELD_AB(EE_SF_CLOCK_DIV),
+	REGISTER_FIELD_AB(EE_SF_FASTRD_EN),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_NIC_STAT[] = {
+	REGISTER_FIELD_AB(STRAP_PINS),
+	REGISTER_FIELD_AB(ATE_MODE),
+	REGISTER_FIELD_AB(EE_PRST),
+	REGISTER_FIELD_AB(SF_PRST),
+	REGISTER_FIELD_AB(ONCHIP_SRAM),
+	REGISTER_FIELD_BB(REVISION_ID),
+	REGISTER_FIELD_BB(EE_STRAP),
+	REGISTER_FIELD_BB(EE_STRAP_EN),
+	REGISTER_FIELD_BB(AER_DIS),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GPIO_CTL[] = {
+	REGISTER_FIELD_AB(GPIO0_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO1_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO2_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO3_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO4_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO5_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO6_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO7_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO0_IN),
+	REGISTER_FIELD_AB(GPIO1_IN),
+	REGISTER_FIELD_AB(GPIO2_IN),
+	REGISTER_FIELD_AB(GPIO3_IN),
+	REGISTER_FIELD_AB(GPIO4_IN),
+	REGISTER_FIELD_AB(GPIO5_IN),
+	REGISTER_FIELD_AB(GPIO6_IN),
+	REGISTER_FIELD_AB(GPIO7_IN),
+	REGISTER_FIELD_AB(GPIO0_OUT),
+	REGISTER_FIELD_AB(GPIO1_OUT),
+	REGISTER_FIELD_AB(GPIO2_OUT),
+	REGISTER_FIELD_AB(GPIO3_OUT),
+	REGISTER_FIELD_AB(GPIO4_OUT),
+	REGISTER_FIELD_AB(GPIO5_OUT),
+	REGISTER_FIELD_AB(GPIO6_OUT),
+	REGISTER_FIELD_AB(GPIO7_OUT),
+	REGISTER_FIELD_AB(GPIO0_OEN),
+	REGISTER_FIELD_AB(GPIO1_OEN),
+	REGISTER_FIELD_AB(GPIO2_OEN),
+	REGISTER_FIELD_AB(GPIO3_OEN),
+	REGISTER_FIELD_AB(GPIO4_OEN),
+	REGISTER_FIELD_AB(GPIO5_OEN),
+	REGISTER_FIELD_AB(USE_NIC_CLK),
+	REGISTER_FIELD_AB(CLK156_OUT_EN),
+	REGISTER_FIELD_AB(GPIO8_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO9_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO10_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO11_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO12_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO13_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO14_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO15_PWRUP_VALUE),
+	REGISTER_FIELD_AB(GPIO8_IN),
+	REGISTER_FIELD_AB(GPIO9_IN),
+	REGISTER_FIELD_AB(GPIO10_IN),
+	REGISTER_FIELD_AB(GPIO11_IN),
+	REGISTER_FIELD_AB(GPIO12_IN),
+	REGISTER_FIELD_AB(GPIO13_IN),
+	REGISTER_FIELD_AB(GPIO14_IN),
+	REGISTER_FIELD_AB(GPIO15_IN),
+	REGISTER_FIELD_AB(GPIO8_OUT),
+	REGISTER_FIELD_AB(GPIO9_OUT),
+	REGISTER_FIELD_AB(GPIO10_OUT),
+	REGISTER_FIELD_AB(GPIO11_OUT),
+	REGISTER_FIELD_AB(GPIO12_OUT),
+	REGISTER_FIELD_AB(GPIO13_OUT),
+	REGISTER_FIELD_AB(GPIO14_OUT),
+	REGISTER_FIELD_AB(GPIO15_OUT),
+	REGISTER_FIELD_AB(GPIO8_OEN),
+	REGISTER_FIELD_AB(GPIO9_OEN),
+	REGISTER_FIELD_AB(GPIO10_OEN),
+	REGISTER_FIELD_AB(GPIO11_OEN),
+	REGISTER_FIELD_AB(GPIO12_OEN),
+	REGISTER_FIELD_AB(GPIO13_OEN),
+	REGISTER_FIELD_AB(GPIO14_OEN),
+	REGISTER_FIELD_AB(GPIO15_OEN),
+	REGISTER_FIELD_AB(GPIO_PWRUP_VALUE2),
+	REGISTER_FIELD_AB(GPIO_IN2),
+	REGISTER_FIELD_AB(GPIO_OUT2),
+	REGISTER_FIELD_AB(GPIO_PWRUP_VALUE3),
+	REGISTER_FIELD_AB(GPIO_IN3),
+	REGISTER_FIELD_AB(GPIO_OUT3),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GLB_CTL[] = {
+	REGISTER_FIELD_AB(SWRST),
+	REGISTER_FIELD_AB(EXT_PHY_RST_DUR),
+	REGISTER_FIELD_AB(INT_RST_DUR),
+	REGISTER_FIELD_AB(RST_CS),
+	REGISTER_FIELD_AB(RST_SF),
+	REGISTER_FIELD_AB(RST_TX),
+	REGISTER_FIELD_AB(RST_RX),
+	REGISTER_FIELD_AB(RST_SR),
+	REGISTER_FIELD_AB(RST_EV),
+	REGISTER_FIELD_AB(RST_EM),
+	REGISTER_FIELD_AB(RST_XGTX),
+	REGISTER_FIELD_AB(RST_XGRX),
+	REGISTER_FIELD_AB(RST_PCIE_CORE),
+	REGISTER_FIELD_AB(RST_PCIE_NSTKY),
+	REGISTER_FIELD_AB(RST_PCIE_STKY),
+	REGISTER_FIELD_BB(RST_BIU),
+	REGISTER_FIELD_AA(RST_PCIX),
+	REGISTER_FIELD_AB(RST_PCIE_SD),
+	REGISTER_FIELD_AB(RST_XAUI_SD),
+	REGISTER_FIELD_AB(RST_EXT_PHY),
+	REGISTER_FIELD_AB(HOT_RST_CTL),
+	REGISTER_FIELD_AB(CS_RST_CTL),
+	REGISTER_FIELD_AB(EE_RST_CTL),
+	REGISTER_FIELD_AB(TX_RST_CTL),
+	REGISTER_FIELD_AB(RX_RST_CTL),
+	REGISTER_FIELD_AB(SR_RST_CTL),
+	REGISTER_FIELD_AB(EV_RST_CTL),
+	REGISTER_FIELD_AB(EM_RST_CTL),
+	REGISTER_FIELD_AB(XGTX_RST_CTL),
+	REGISTER_FIELD_AB(XGRX_RST_CTL),
+	REGISTER_FIELD_AB(PCIE_CORE_RST_CTL),
+	REGISTER_FIELD_AB(PCIE_NSTKY_RST_CTL),
+	REGISTER_FIELD_AB(PCIE_STKY_RST_CTL),
+	REGISTER_FIELD_BB(BIU_RST_CTL),
+	REGISTER_FIELD_AA(PCIX_RST_CTL),
+	REGISTER_FIELD_AB(PCIE_SD_RST_CTL),
+	REGISTER_FIELD_AB(XAUI_SD_RST_CTL),
+	REGISTER_FIELD_AB(EXT_PHY_RST_CTL),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_DP_CTRL[] = {
+	REGISTER_FIELD_BZ(FLS_EVQ_ID),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_MEM_STAT[] = {
+	REGISTER_FIELD_CZ(MEM_PERR_VEC),
+	REGISTER_FIELD_AB(MBIST_ERR),
+	REGISTER_FIELD_AB(MBIST_CORR),
+	REGISTER_FIELD_AB(MEM_PERR_VEC),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_CS_DEBUG[] = {
+	/* This is not a complete list of fields */
+	REGISTER_FIELD_AZ(CS_DEBUG_EN),
+	REGISTER_FIELD_CZ(CS_PORT_NUM),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_ALTERA_BUILD[] = {
+	REGISTER_FIELD_AZ(ALTERA_BUILD_VER),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_CSR_SPARE[] = {
+	REGISTER_FIELD_AZ(CSR_SPARE_BITS),
+	REGISTER_FIELD_AB(MEM_PERR_EN_TX_DATA),
+	REGISTER_FIELD_CZ(MEM_PERR_EN),
+	REGISTER_FIELD_AB(MEM_PERR_EN),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_PCIE_SD_CTL0123[] = {
+	REGISTER_FIELD_AB(PCIE_LODRV),
+	REGISTER_FIELD_AB(PCIE_HIDRV),
+	REGISTER_FIELD_AB(PCIE_RXEQCTL_L),
+	REGISTER_FIELD_AB(PCIE_RXEQCTL_H),
+	REGISTER_FIELD_AB(PCIE_TXTERMADJ_L),
+	REGISTER_FIELD_AB(PCIE_TXTERMADJ_H),
+	REGISTER_FIELD_AB(PCIE_RXTERMADJ_L),
+	REGISTER_FIELD_AB(PCIE_RXTERMADJ_H),
+	REGISTER_FIELD_AB(PCIE_PARLPBK),
+	REGISTER_FIELD_AB(PCIE_LPBK),
+	REGISTER_FIELD_AB(PCIE_LPBKWDRV_L),
+	REGISTER_FIELD_AB(PCIE_LPBKWDRV_H),
+	REGISTER_FIELD_AB(PCIE_PARRESET_L),
+	REGISTER_FIELD_AB(PCIE_PARRESET_H),
+	REGISTER_FIELD_AB(PCIE_HIVMODE_L),
+	REGISTER_FIELD_AB(PCIE_HIVMODE_H),
+	REGISTER_FIELD_AB(PCIE_OFFSETEN_L),
+	REGISTER_FIELD_AB(PCIE_OFFSETEN_H),
+	REGISTER_FIELD_AB(PCIE_OFFSET),
+	REGISTER_FIELD_AB(PCIE_TESTSIG_L),
+	REGISTER_FIELD_AB(PCIE_TESTSIG_H),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_PCIE_SD_CTL45[] = {
+	REGISTER_FIELD_AB(PCIE_DEQ0),
+	REGISTER_FIELD_AB(PCIE_DEQ1),
+	REGISTER_FIELD_AB(PCIE_DEQ2),
+	REGISTER_FIELD_AB(PCIE_DEQ3),
+	REGISTER_FIELD_AB(PCIE_DEQ4),
+	REGISTER_FIELD_AB(PCIE_DEQ5),
+	REGISTER_FIELD_AB(PCIE_DEQ6),
+	REGISTER_FIELD_AB(PCIE_DEQ7),
+	REGISTER_FIELD_AB(PCIE_DTX0),
+	REGISTER_FIELD_AB(PCIE_DTX1),
+	REGISTER_FIELD_AB(PCIE_DTX2),
+	REGISTER_FIELD_AB(PCIE_DTX3),
+	REGISTER_FIELD_AB(PCIE_DTX4),
+	REGISTER_FIELD_AB(PCIE_DTX5),
+	REGISTER_FIELD_AB(PCIE_DTX6),
+	REGISTER_FIELD_AB(PCIE_DTX7),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_PCIE_PCS_CTL_STAT[] = {
+	REGISTER_FIELD_AB(PCIE_PRBSSEL),
+	REGISTER_FIELD_AB(PCIE_PRBSERRACK_L),
+	REGISTER_FIELD_AB(PCIE_PRBSERRACK_H),
+	REGISTER_FIELD_AB(PCIE_PRBSSYNC_L),
+	REGISTER_FIELD_AB(PCIE_PRBSSYNC_H),
+	REGISTER_FIELD_AB(PCIE_CTCDISABLE_L),
+	REGISTER_FIELD_AB(PCIE_CTCDISABLE_H),
+	REGISTER_FIELD_AB(PCIE_FASTINIT_L),
+	REGISTER_FIELD_AB(PCIE_FASTINIT_H),
+	REGISTER_FIELD_AB(PCIE_PRBSERRH0),
+	REGISTER_FIELD_AB(PCIE_PRBSERR),
+	REGISTER_FIELD_AB(PCIE_PRBSERRCOUNT0_L),
+	REGISTER_FIELD_AB(PCIE_PRBSERRCOUNT0_H),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_EVQ_CTL[] = {
+	REGISTER_FIELD_AZ(EVQ_FIFO_NOTAF_TH),
+	REGISTER_FIELD_AZ(EVQ_FIFO_AF_TH),
+	REGISTER_FIELD_AZ(EVQ_OWNERR_CTL),
+	REGISTER_FIELD_BB(RX_EVQ_WAKEUP_MASK),
+	REGISTER_FIELD_CZ(RX_EVQ_WAKEUP_MASK),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_EVQ_CNT1[] = {
+	REGISTER_FIELD_AZ(EVQ_ERR_REQ_CNT),
+	REGISTER_FIELD_AZ(EVQ_CSR_REQ_CNT),
+	REGISTER_FIELD_AZ(EVQ_EM_REQ_CNT),
+	REGISTER_FIELD_AZ(EVQ_RX_REQ_CNT),
+	REGISTER_FIELD_AZ(EVQ_TX_REQ_CNT),
+	REGISTER_FIELD_AZ(EVQ_CNT_TOBIU),
+	REGISTER_FIELD_AZ(EVQ_CNT_PRE_FIFO),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_EVQ_CNT2[] = {
+	REGISTER_FIELD_AZ(EVQ_TM_REQ_CNT),
+	REGISTER_FIELD_AZ(EVQ_INIT_REQ_CNT),
+	REGISTER_FIELD_AZ(EVQ_WET_REQ_CNT),
+	REGISTER_FIELD_AZ(EVQ_WU_REQ_CNT),
+	REGISTER_FIELD_AZ(EVQ_RDY_CNT),
+	REGISTER_FIELD_AZ(EVQ_CLR_REQ_CNT),
+	REGISTER_FIELD_AZ(EVQ_UPD_REQ_CNT),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_BUF_TBL_CFG[] = {
+	REGISTER_FIELD_AZ(BUF_TBL_MODE),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_SRM_RX_DC_CFG[] = {
+	REGISTER_FIELD_AZ(SRM_RX_DC_BASE_ADR),
+	REGISTER_FIELD_AZ(SRM_CLK_TMP_EN),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_SRM_TX_DC_CFG[] = {
+	REGISTER_FIELD_AZ(SRM_TX_DC_BASE_ADR),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_SRM_CFG[] = {
+	REGISTER_FIELD_AZ(SRM_BANK_SIZE),
+	REGISTER_FIELD_AZ(SRM_NUM_BANK),
+	REGISTER_FIELD_AZ(SRM_INIT_EN),
+	REGISTER_FIELD_AZ(SRM_OOB_BUF_INTEN),
+	REGISTER_FIELD_AZ(SRM_OOB_ADR_INTEN),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_SRM_UPD_EVQ[] = {
+	REGISTER_FIELD_AZ(SRM_UPD_EVQ_ID),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_SRAM_PARITY[] = {
+	REGISTER_FIELD_CZ(FORCE_SRAM_SINGLE_ERR),
+	REGISTER_FIELD_AB(FORCE_SRAM_PERR),
+	REGISTER_FIELD_CZ(FORCE_SRAM_DOUBLE_ERR),
+	REGISTER_FIELD_CZ(SEC_INT),
+	REGISTER_FIELD_CZ(BYPASS_ECC),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_RX_CFG[] = {
+	REGISTER_FIELD_AZ(RX_XOFF_MAC_EN),
+	REGISTER_FIELD_AA(RX_XOFF_MAC_TH),
+	REGISTER_FIELD_BZ(RX_XOFF_MAC_TH),
+	REGISTER_FIELD_AA(RX_XON_MAC_TH),
+	REGISTER_FIELD_BZ(RX_XON_MAC_TH),
+	REGISTER_FIELD_AA(RX_USR_BUF_SIZE),
+	REGISTER_FIELD_AA(RX_XOFF_TX_TH),
+	REGISTER_FIELD_BZ(RX_USR_BUF_SIZE),
+	REGISTER_FIELD_AA(RX_XON_TX_TH),
+	REGISTER_FIELD_AA(RX_OWNERR_CTL),
+	REGISTER_FIELD_BZ(RX_XOFF_TX_TH),
+	REGISTER_FIELD_AA(RX_PCI_BURST_SIZE),
+	REGISTER_FIELD_AA(RX_RDW_PATCH_EN),
+	REGISTER_FIELD_AA(RX_DESC_PUSH_EN),
+	REGISTER_FIELD_BZ(RX_XON_TX_TH),
+	REGISTER_FIELD_BZ(RX_OWNERR_CTL),
+	REGISTER_FIELD_BB(RX_PCI_BURST_SIZE),
+	REGISTER_FIELD_BZ(RX_RDW_PATCH_EN),
+	REGISTER_FIELD_BZ(RX_DESC_PUSH_EN),
+	REGISTER_FIELD_BZ(RX_HASH_INSRT_HDR),
+	REGISTER_FIELD_BZ(RX_HASH_ALG),
+	REGISTER_FIELD_BZ(RX_IP_HASH),
+	REGISTER_FIELD_BZ(RX_INGR_EN),
+	REGISTER_FIELD_BZ(RX_TCP_SUP),
+	REGISTER_FIELD_CZ(RX_PRE_RFF_IPG),
+	REGISTER_FIELD_CZ(RX_HDR_SPLIT_HDR_BUF_SIZE),
+	REGISTER_FIELD_CZ(RX_HDR_SPLIT_PLD_BUF_SIZE),
+	REGISTER_FIELD_CZ(RX_HDR_SPLIT_EN),
+	REGISTER_FIELD_CZ(RX_MIN_KBUF_SIZE),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_RX_FILTER_CTL[] = {
+	REGISTER_FIELD_BZ(TCP_FULL_SRCH_LIMIT),
+	REGISTER_FIELD_BZ(TCP_WILD_SRCH_LIMIT),
+	REGISTER_FIELD_BZ(UDP_WILD_SRCH_LIMIT),
+	REGISTER_FIELD_BZ(NUM_KER),
+	REGISTER_FIELD_BZ(UDP_FULL_SRCH_LIMIT),
+	REGISTER_FIELD_BZ(SCATTER_ENBL_NO_MATCH_Q),
+	REGISTER_FIELD_CZ(UNICAST_NOMATCH_IP_OVERRIDE),
+	REGISTER_FIELD_CZ(UNICAST_NOMATCH_RSS_ENABLED),
+	REGISTER_FIELD_CZ(UNICAST_NOMATCH_Q_ID),
+	REGISTER_FIELD_CZ(MULTICAST_NOMATCH_IP_OVERRIDE),
+	REGISTER_FIELD_CZ(MULTICAST_NOMATCH_RSS_ENABLED),
+	REGISTER_FIELD_CZ(MULTICAST_NOMATCH_Q_ID),
+	REGISTER_FIELD_CZ(RX_VLAN_MATCH_ETHERTYPE),
+	REGISTER_FIELD_CZ(RX_FILTER_ALL_VLAN_ETHERTYPES),
+	REGISTER_FIELD_CZ(ETHERNET_FULL_SEARCH_LIMIT),
+	REGISTER_FIELD_CZ(ETHERNET_WILDCARD_SEARCH_LIMIT),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_RX_DC_CFG[] = {
+	REGISTER_FIELD_AZ(RX_DC_SIZE),
+	REGISTER_FIELD_AB(RX_MAX_PF),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_RX_DC_PF_WM[] = {
+	REGISTER_FIELD_AZ(RX_DC_PF_LWM),
+	REGISTER_FIELD_AZ(RX_DC_PF_HWM),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_RX_RSS_TKEY[] = {
+	REGISTER_FIELD_BZ(RX_RSS_TKEY_LO),
+	REGISTER_FIELD_BZ(RX_RSS_TKEY_HI),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_RX_SELF_RST[] = {
+	REGISTER_FIELD_AA(RX_MAX_LU_LAT),
+	REGISTER_FIELD_AA(RX_MAX_PF_LAT),
+	REGISTER_FIELD_AA(RX_SELF_RST_EN),
+	REGISTER_FIELD_AA(RX_NODESC_WAIT_DIS),
+	REGISTER_FIELD_AA(RX_SW_RST_REG),
+	REGISTER_FIELD_AA(RX_ISCSI_DIS),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_RX_RSS_IPV6_REG1[] = {
+	REGISTER_FIELD_CZ(RX_RSS_IPV6_TKEY_LO),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_RX_RSS_IPV6_REG2[] = {
+	REGISTER_FIELD_CZ(RX_RSS_IPV6_TKEY_MID),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_RX_RSS_IPV6_REG3[] = {
+	REGISTER_FIELD_CZ(RX_RSS_IPV6_TKEY_HI),
+	REGISTER_FIELD_CZ(RX_RSS_IPV6_TCP_SUPPRESS),
+	REGISTER_FIELD_CZ(RX_RSS_IPV6_IP_THASH_ENABLE),
+	REGISTER_FIELD_CZ(RX_RSS_IPV6_THASH_ENABLE),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_TX_DC_CFG[] = {
+	REGISTER_FIELD_AZ(TX_DC_SIZE),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_TX_CHKSM_CFG[] = {
+	REGISTER_FIELD_AA(TX_Q_CHKSM_DIS_0_31),
+	REGISTER_FIELD_AA(TX_Q_CHKSM_DIS_32_63),
+	REGISTER_FIELD_AA(TX_Q_CHKSM_DIS_64_95),
+	REGISTER_FIELD_AA(TX_Q_CHKSM_DIS_96_127),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_TX_CFG[] = {
+	REGISTER_FIELD_AZ(TX_IP_ID_REP_EN),
+	REGISTER_FIELD_AA(TX_NON_IP_DROP_DIS),
+	REGISTER_FIELD_AZ(TX_OWNERR_CTL),
+	REGISTER_FIELD_AZ(TX_P1_PRI_EN),
+	REGISTER_FIELD_AZ(TX_NO_EOP_DISC_EN),
+	REGISTER_FIELD_AZ(TX_IP_ID_P0_OFS),
+	REGISTER_FIELD_CZ(TX_FILTER_EN_BIT),
+	REGISTER_FIELD_CZ(TX_VLAN_MATCH_ETHERTYPE_RANGE),
+	REGISTER_FIELD_CZ(TX_FILTER_ALL_VLAN_ETHERTYPES_BIT),
+	REGISTER_FIELD_CZ(TX_TCPIP_FILTER_FULL_SEARCH_RANGE),
+	REGISTER_FIELD_CZ(TX_TCPIP_FILTER_WILD_SEARCH_RANGE),
+	REGISTER_FIELD_CZ(TX_UDPIP_FILTER_FULL_SEARCH_RANGE),
+	REGISTER_FIELD_CZ(TX_UDPIP_FILTER_WILD_SEARCH_RANGE),
+	REGISTER_FIELD_CZ(TX_ETH_FILTER_FULL_SEARCH_RANGE),
+	REGISTER_FIELD_CZ(TX_ETH_FILTER_WILD_SEARCH_RANGE),
+	REGISTER_FIELD_CZ(TX_FILTER_TEST_MODE_BIT),
+	REGISTER_FIELD_CZ(TX_CONT_LOOKUP_THRESH_RANGE),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_TX_RESERVED[] = {
+	REGISTER_FIELD_AZ(TX_MAX_PREF),
+	REGISTER_FIELD_AZ(TX_MAX_CPL),
+	REGISTER_FIELD_AA(TX_IP_DIS),
+	REGISTER_FIELD_BZ(TX_FLUSH_MIN_LEN_EN),
+	REGISTER_FIELD_AA(TX_TCP_DIS),
+	REGISTER_FIELD_AZ(TX_DMA_SPACER),
+	REGISTER_FIELD_AA(TX_DMA_FF_THR),
+	REGISTER_FIELD_AZ(TX_DIS_NON_IP_EV),
+	REGISTER_FIELD_AZ(TX_ONE_PKT_PER_Q),
+	REGISTER_FIELD_AZ(TX_PREF_THRESHOLD),
+	REGISTER_FIELD_AZ(TX_ONLY1TAG),
+	REGISTER_FIELD_AZ(TX_PREF_WD_TMR),
+	REGISTER_FIELD_AZ(TX_PREF_SPACER),
+	REGISTER_FIELD_AZ(TX_XP_TIMER),
+	REGISTER_FIELD_AZ(TX_RX_SPACER_EN),
+	REGISTER_FIELD_AZ(TX_PS_EVT_DIS),
+	REGISTER_FIELD_AZ(TX_SOFT_EVT_EN),
+	REGISTER_FIELD_AZ(TX_DROP_ABORT_EN),
+	REGISTER_FIELD_AZ(TX_RX_SPACER),
+	REGISTER_FIELD_AZ(TX_DMAQ_ST),
+	REGISTER_FIELD_AZ(TX_DMAR_ST_P0),
+	REGISTER_FIELD_AZ(TX_D_FF_FULL_P0),
+	REGISTER_FIELD_AZ(TX_PUSH_CHK_DIS),
+	REGISTER_FIELD_AZ(TX_PUSH_EN),
+	REGISTER_FIELD_AZ(TX_RD_COMP_TMR),
+	REGISTER_FIELD_AZ(TX_PREF_AGE_CNT),
+	REGISTER_FIELD_AZ(TX_EVT_CNT),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_TX_PACE[] = {
+	REGISTER_FIELD_BZ(TX_PACE_BIN_TH),
+	REGISTER_FIELD_BZ(TX_PACE_FB_BASE),
+	REGISTER_FIELD_BZ(TX_PACE_SB_AF),
+	REGISTER_FIELD_BZ(TX_PACE_SB_NOT_AF),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_TX_VLAN[] = {
+	REGISTER_FIELD_BB(TX_VLAN0),
+	REGISTER_FIELD_BB(TX_VLAN0_PORT0_EN),
+	REGISTER_FIELD_BB(TX_VLAN0_PORT1_EN),
+	REGISTER_FIELD_BB(TX_VLAN1),
+	REGISTER_FIELD_BB(TX_VLAN1_PORT0_EN),
+	REGISTER_FIELD_BB(TX_VLAN1_PORT1_EN),
+	REGISTER_FIELD_BB(TX_VLAN2),
+	REGISTER_FIELD_BB(TX_VLAN2_PORT0_EN),
+	REGISTER_FIELD_BB(TX_VLAN2_PORT1_EN),
+	REGISTER_FIELD_BB(TX_VLAN3),
+	REGISTER_FIELD_BB(TX_VLAN3_PORT0_EN),
+	REGISTER_FIELD_BB(TX_VLAN3_PORT1_EN),
+	REGISTER_FIELD_BB(TX_VLAN4),
+	REGISTER_FIELD_BB(TX_VLAN4_PORT0_EN),
+	REGISTER_FIELD_BB(TX_VLAN4_PORT1_EN),
+	REGISTER_FIELD_BB(TX_VLAN5),
+	REGISTER_FIELD_BB(TX_VLAN5_PORT0_EN),
+	REGISTER_FIELD_BB(TX_VLAN5_PORT1_EN),
+	REGISTER_FIELD_BB(TX_VLAN6),
+	REGISTER_FIELD_BB(TX_VLAN6_PORT0_EN),
+	REGISTER_FIELD_BB(TX_VLAN6_PORT1_EN),
+	REGISTER_FIELD_BB(TX_VLAN7),
+	REGISTER_FIELD_BB(TX_VLAN7_PORT0_EN),
+	REGISTER_FIELD_BB(TX_VLAN7_PORT1_EN),
+	REGISTER_FIELD_BB(TX_VLAN_EN),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_TX_IPFIL_PORTEN[] = {
+	REGISTER_FIELD_BB(TX_IPFIL0_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL1_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL2_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL3_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL4_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL5_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL6_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL7_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL8_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL9_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL10_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL11_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL12_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL13_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL14_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL15_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL16_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL17_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL18_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL19_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL20_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL21_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL22_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL23_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL24_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL25_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL26_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL27_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL28_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL29_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL30_PORT_EN),
+	REGISTER_FIELD_BB(TX_IPFIL31_PORT_EN),
+	REGISTER_FIELD_BZ(TX_MADR0_FIL_EN),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_TX_IPFIL_TBL[] = {
+	REGISTER_FIELD_BB(TX_IP_SRC_ADR_0),
+	REGISTER_FIELD_BB(TX_IPFIL_MASK_0),
+	REGISTER_FIELD_BB(TX_IP_SRC_ADR_1),
+	REGISTER_FIELD_BB(TX_IPFIL_MASK_1),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_MD_TXD[] = {
+	REGISTER_FIELD_AB(MD_TXD),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_MD_RXD[] = {
+	REGISTER_FIELD_AB(MD_RXD),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_MD_CS[] = {
+	REGISTER_FIELD_AB(MD_WRC),
+	REGISTER_FIELD_AB(MD_RDC),
+	REGISTER_FIELD_AB(MD_RIC),
+	REGISTER_FIELD_AB(MD_PRSP),
+	REGISTER_FIELD_AB(MD_GC),
+	REGISTER_FIELD_AB(MD_INT_CLR),
+	REGISTER_FIELD_AB(MD_PL),
+	REGISTER_FIELD_AB(MD_PT),
+	REGISTER_FIELD_AB(MD_ADDR_CMD),
+	REGISTER_FIELD_AB(MD_WR_EN_CMD),
+	REGISTER_FIELD_AB(MD_RD_EN_CMD),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_MD_PHY_ADR[] = {
+	REGISTER_FIELD_AB(MD_PHY_ADR),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_MD_ID[] = {
+	REGISTER_FIELD_AB(MD_DEV_ADR),
+	REGISTER_FIELD_AB(MD_PRT_ADR),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_MAC_STAT_DMA[] = {
+	REGISTER_FIELD_AB(MAC_STAT_DMA_ADR),
+	REGISTER_FIELD_AB(MAC_STAT_DMA_CMD),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_MAC_CTRL[] = {
+	REGISTER_FIELD_AB(MAC_SPEED),
+	REGISTER_FIELD_AB(MAC_LINK_STATUS),
+	REGISTER_FIELD_AB(MAC_UC_PROM),
+	REGISTER_FIELD_AB(MAC_BCAD_ACPT),
+	REGISTER_FIELD_AB(MAC_XG_DISTXCRC),
+	REGISTER_FIELD_BB(TXFIFO_DRAIN_EN),
+	REGISTER_FIELD_AB(MAC_XOFF_VAL),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GEN_MODE[] = {
+	REGISTER_FIELD_BB(XG_PHY_INT_MASK),
+	REGISTER_FIELD_BB(XFP_PHY_INT_MASK),
+	REGISTER_FIELD_BB(XG_PHY_INT_POL_SEL),
+	REGISTER_FIELD_BB(XFP_PHY_INT_POL_SEL),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_MAC_MC_HASH_REG0[] = {
+	REGISTER_FIELD_AB(MAC_MCAST_HASH0),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_MAC_MC_HASH_REG1[] = {
+	REGISTER_FIELD_AB(MAC_MCAST_HASH1),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GM_CFG1[] = {
+	REGISTER_FIELD_AB(GM_TX_EN),
+	REGISTER_FIELD_AB(GM_SYNC_TXEN),
+	REGISTER_FIELD_AB(GM_RX_EN),
+	REGISTER_FIELD_AB(GM_SYNC_RXEN),
+	REGISTER_FIELD_AB(GM_TX_FC_EN),
+	REGISTER_FIELD_AB(GM_RX_FC_EN),
+	REGISTER_FIELD_AB(GM_LOOP),
+	REGISTER_FIELD_AB(GM_RST_TX_FUNC),
+	REGISTER_FIELD_AB(GM_RST_RX_FUNC),
+	REGISTER_FIELD_AB(GM_RST_TX_MAC_CTL),
+	REGISTER_FIELD_AB(GM_RST_RX_MAC_CTL),
+	REGISTER_FIELD_AB(GM_SIM_RST),
+	REGISTER_FIELD_AB(GM_SW_RST),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GM_CFG2[] = {
+	REGISTER_FIELD_AB(GM_FD),
+	REGISTER_FIELD_AB(GM_CRC_EN),
+	REGISTER_FIELD_AB(GM_PAD_CRC_EN),
+	REGISTER_FIELD_AB(GM_LEN_CHK),
+	REGISTER_FIELD_AB(GM_HUGE_FRM_EN),
+	REGISTER_FIELD_AB(GM_IF_MODE),
+	REGISTER_FIELD_AB(GM_PAMBL_LEN),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GM_MAX_FLEN[] = {
+	REGISTER_FIELD_AB(GM_MAX_FLEN),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GM_ADR1[] = {
+	REGISTER_FIELD_AB(GM_ADR_B3),
+	REGISTER_FIELD_AB(GM_ADR_B2),
+	REGISTER_FIELD_AB(GM_ADR_B1),
+	REGISTER_FIELD_AB(GM_ADR_B0),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GM_ADR2[] = {
+	REGISTER_FIELD_AB(GM_ADR_B5),
+	REGISTER_FIELD_AB(GM_ADR_B4),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GMF_CFG0[] = {
+	REGISTER_FIELD_AB(GMF_HSTRSTWT),
+	REGISTER_FIELD_AB(GMF_HSTRSTSR),
+	REGISTER_FIELD_AB(GMF_HSTRSTFR),
+	REGISTER_FIELD_AB(GMF_HSTRSTST),
+	REGISTER_FIELD_AB(GMF_HSTRSTFT),
+	REGISTER_FIELD_AB(GMF_WTMENREQ),
+	REGISTER_FIELD_AB(GMF_SRFENREQ),
+	REGISTER_FIELD_AB(GMF_FRFENREQ),
+	REGISTER_FIELD_AB(GMF_STFENREQ),
+	REGISTER_FIELD_AB(GMF_FTFENREQ),
+	REGISTER_FIELD_AB(GMF_WTMENRPLY),
+	REGISTER_FIELD_AB(GMF_SRFENRPLY),
+	REGISTER_FIELD_AB(GMF_FRFENRPLY),
+	REGISTER_FIELD_AB(GMF_STFENRPLY),
+	REGISTER_FIELD_AB(GMF_FTFENRPLY),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GMF_CFG1[] = {
+	REGISTER_FIELD_AB(GMF_CFGXOFFRTX),
+	REGISTER_FIELD_AB(GMF_CFGFRTH),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GMF_CFG2[] = {
+	REGISTER_FIELD_AB(GMF_CFGLWM),
+	REGISTER_FIELD_AB(GMF_CFGHWM),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GMF_CFG3[] = {
+	REGISTER_FIELD_AB(GMF_CFGFTTH),
+	REGISTER_FIELD_AB(GMF_CFGHWMFT),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GMF_CFG4[] = {
+	REGISTER_FIELD_AB(GMF_HSTFLTRFRM),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_GMF_CFG5[] = {
+	REGISTER_FIELD_AB(GMF_HSTFLTRFRMDC),
+	REGISTER_FIELD_AB(GMF_HSTDRPLT64),
+	REGISTER_FIELD_AB(GMF_CFGBYTMODE),
+	REGISTER_FIELD_AB(GMF_HSTSRFULLCLR),
+	REGISTER_FIELD_AB(GMF_SRFULL),
+	REGISTER_FIELD_AB(GMF_CFGHDPLX),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_TX_SRC_MAC_TBL[] = {
+	REGISTER_FIELD_BB(TX_SRC_MAC_ADR_0),
+	REGISTER_FIELD_BB(TX_SRC_MAC_ADR_1),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_TX_SRC_MAC_CTL[] = {
+	REGISTER_FIELD_BB(TX_MAC_QID_SEL),
+	REGISTER_FIELD_BB(TX_DROP_CTR_CLR),
+	REGISTER_FIELD_BB(TX_SRC_FLTR_EN),
+	REGISTER_FIELD_BB(TX_SRC_DROP_CTR),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_XM_ADR_LO[] = {
+	REGISTER_FIELD_AB(XM_ADR_LO),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_XM_ADR_HI[] = {
+	REGISTER_FIELD_AB(XM_ADR_HI),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_XM_GLB_CFG[] = {
+	REGISTER_FIELD_AB(XM_CORE_RST),
+	REGISTER_FIELD_AB(XM_INTCLR_MODE),
+	REGISTER_FIELD_AB(XM_WAN_MODE),
+	REGISTER_FIELD_AB(XM_RX_JUMBO_MODE),
+	REGISTER_FIELD_AB(XM_TX_STAT_EN),
+	REGISTER_FIELD_AB(XM_RX_STAT_EN),
+	REGISTER_FIELD_AB(XM_DEBUG_MODE),
+	REGISTER_FIELD_AB(XM_RMTFLT_GEN),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_XM_TX_CFG[] = {
+	REGISTER_FIELD_AB(XM_TX_RST),
+	REGISTER_FIELD_AB(XM_TXEN),
+	REGISTER_FIELD_AB(XM_TX_PRMBL),
+	REGISTER_FIELD_AB(XM_AUTO_PAD),
+	REGISTER_FIELD_AB(XM_EDRC),
+	REGISTER_FIELD_AB(XM_TXCRC),
+	REGISTER_FIELD_AB(XM_FCNTL),
+	REGISTER_FIELD_AB(XM_IPG),
+	REGISTER_FIELD_AB(XM_TX_PROG),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_XM_RX_CFG[] = {
+	REGISTER_FIELD_AB(XM_RX_RST),
+	REGISTER_FIELD_AB(XM_RXEN),
+	REGISTER_FIELD_AB(XM_RX_PRMBL),
+	REGISTER_FIELD_AB(XM_RXCRC),
+	REGISTER_FIELD_AB(XM_AUTO_DEPAD),
+	REGISTER_FIELD_AB(XM_ACPT_ALL_UCAST),
+	REGISTER_FIELD_AB(XM_ACPT_ALL_MCAST),
+	REGISTER_FIELD_AB(XM_REJ_BCAST),
+	REGISTER_FIELD_AB(XM_PASS_PRMBLE_ERR),
+	REGISTER_FIELD_AB(XM_PASS_CRC_ERR),
+	REGISTER_FIELD_AB(XM_PASS_LENERR),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_XM_MGT_INT_MASK[] = {
+	REGISTER_FIELD_AB(XM_MSK_LCLFLT),
+	REGISTER_FIELD_AB(XM_MSK_RMTFLT),
+	REGISTER_FIELD_AB(XM_MSK_PRMBLE_ERR),
+	REGISTER_FIELD_AB(XM_MSK_STAT_CNTR_OF),
+	REGISTER_FIELD_AB(XM_MSK_STAT_CNTR_HF),
+	REGISTER_FIELD_AB(XM_MSK_STA_INTR),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_XM_FC[] = {
+	REGISTER_FIELD_AB(XM_DIS_FCNTL),
+	REGISTER_FIELD_AB(XM_XMIT_PAUSE),
+	REGISTER_FIELD_AB(XM_ZPAUSE),
+	REGISTER_FIELD_AB(XM_REJ_CNTL_MCAST),
+	REGISTER_FIELD_AB(XM_REJ_CNTL_UCAST),
+	REGISTER_FIELD_AB(XM_MCNTL_PASS),
+	REGISTER_FIELD_AB(XM_TX_MAC_STAT),
+	REGISTER_FIELD_AB(XM_RX_MAC_STAT),
+	REGISTER_FIELD_AB(XM_PAUSE_TIME),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_XM_PAUSE_TIME[] = {
+	REGISTER_FIELD_AB(XM_RX_PAUSE_CNT),
+	REGISTER_FIELD_AB(XM_TX_PAUSE_CNT),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_XM_TX_PARAM[] = {
+	REGISTER_FIELD_AB(XM_PAD_CHAR),
+	REGISTER_FIELD_AB(XM_MAX_TX_FRM_SIZE_LO),
+	REGISTER_FIELD_AB(XM_MAX_TX_FRM_SIZE_HI),
+	REGISTER_FIELD_AB(XM_TX_JUMBO_MODE),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_XM_RX_PARAM[] = {
+	REGISTER_FIELD_AB(XM_MAX_RX_FRM_SIZE_LO),
+	REGISTER_FIELD_AB(XM_MAX_RX_FRM_SIZE_HI),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_XX_PWR_RST[] = {
+	REGISTER_FIELD_AB(XX_RST_XX_EN),
+	REGISTER_FIELD_AB(XX_RSTXGXSTX_EN),
+	REGISTER_FIELD_AB(XX_RSTXGXSRX_EN),
+	REGISTER_FIELD_AB(XX_RESETA_EN),
+	REGISTER_FIELD_AB(XX_RESETB_EN),
+	REGISTER_FIELD_AB(XX_RESETC_EN),
+	REGISTER_FIELD_AB(XX_RESETD_EN),
+	REGISTER_FIELD_AB(XX_RSTPLLAB_EN),
+	REGISTER_FIELD_AB(XX_RSTPLLCD_EN),
+	REGISTER_FIELD_AB(XX_PWRDNA_EN),
+	REGISTER_FIELD_AB(XX_PWRDNB_EN),
+	REGISTER_FIELD_AB(XX_PWRDNC_EN),
+	REGISTER_FIELD_AB(XX_PWRDND_EN),
+	REGISTER_FIELD_AB(XX_SD_RST_ACT),
+	REGISTER_FIELD_AB(XX_RSTXGXSTX_SIG),
+	REGISTER_FIELD_AB(XX_RSTXGXSRX_SIG),
+	REGISTER_FIELD_AB(XX_RESETA_SIG),
+	REGISTER_FIELD_AB(XX_RESETB_SIG),
+	REGISTER_FIELD_AB(XX_RESETC_SIG),
+	REGISTER_FIELD_AB(XX_RESETD_SIG),
+	REGISTER_FIELD_AB(XX_RSTPLLAB_SIG),
+	REGISTER_FIELD_AB(XX_RSTPLLCD_SIG),
+	REGISTER_FIELD_AB(XX_SIM_MODE),
+	REGISTER_FIELD_AB(XX_PWRDNA_SIG),
+	REGISTER_FIELD_AB(XX_PWRDNB_SIG),
+	REGISTER_FIELD_AB(XX_PWRDNC_SIG),
+	REGISTER_FIELD_AB(XX_PWRDND_SIG),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_XX_SD_CTL[] = {
+	REGISTER_FIELD_AB(XX_LPBKA),
+	REGISTER_FIELD_AB(XX_LPBKB),
+	REGISTER_FIELD_AB(XX_LPBKC),
+	REGISTER_FIELD_AB(XX_LPBKD),
+	REGISTER_FIELD_AB(XX_LODRVA),
+	REGISTER_FIELD_AB(XX_HIDRVA),
+	REGISTER_FIELD_AB(XX_LODRVB),
+	REGISTER_FIELD_AB(XX_HIDRVB),
+	REGISTER_FIELD_AB(XX_LODRVC),
+	REGISTER_FIELD_AB(XX_HIDRVC),
+	REGISTER_FIELD_AB(XX_LODRVD),
+	REGISTER_FIELD_AB(XX_HIDRVD),
+	REGISTER_FIELD_AB(XX_TERMADJ0),
+	REGISTER_FIELD_AB(XX_TERMADJ1),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_XX_TXDRV_CTL[] = {
+	REGISTER_FIELD_AB(XX_DTXA),
+	REGISTER_FIELD_AB(XX_DTXB),
+	REGISTER_FIELD_AB(XX_DTXC),
+	REGISTER_FIELD_AB(XX_DTXD),
+	REGISTER_FIELD_AB(XX_DEQA),
+	REGISTER_FIELD_AB(XX_DEQB),
+	REGISTER_FIELD_AB(XX_DEQC),
+	REGISTER_FIELD_AB(XX_DEQD),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_BIU_HW_REV_ID[] = {
+	REGISTER_FIELD_DZ(HW_REV_ID),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_MC_DB_LWRD[] = {
+	REGISTER_FIELD_DZ(MC_DOORBELL_L),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_MC_DB_HWRD[] = {
+	REGISTER_FIELD_DZ(MC_DOORBELL_H),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_RX_DESC_PTR_TBL[] = {
+	/* Abbreviate field names to reduce the table width */
+	REGISTER_FIELD_AZ_RENAME(RX_DESCQ_EN, "EN"),
+	REGISTER_FIELD_AZ_RENAME(RX_DESCQ_JUMBO, "JUMBO"),
+	REGISTER_FIELD_AZ_RENAME(RX_DESCQ_TYPE, "TYPE"),
+	REGISTER_FIELD_AZ_RENAME(RX_DESCQ_SIZE, "SIZE"),
+	REGISTER_FIELD_AZ_RENAME(RX_DESCQ_LABEL, "LABEL"),
+	REGISTER_FIELD_AZ_RENAME(RX_DESCQ_OWNER_ID, "OWNER"),
+	REGISTER_FIELD_AZ_RENAME(RX_DESCQ_EVQ_ID, "EVQ"),
+	REGISTER_FIELD_AZ_RENAME(RX_DESCQ_BUF_BASE_ID, "BUF_BASE"),
+	REGISTER_FIELD_AZ_RENAME(RX_DESCQ_SW_WPTR, "SW_WPTR"),
+	REGISTER_FIELD_AZ_RENAME(RX_DESCQ_HW_RPTR, "HW_RPTR"),
+	REGISTER_FIELD_AZ_RENAME(RX_DC_HW_RPTR, "DC_HW_RPTR"),
+	REGISTER_FIELD_AZ_RENAME(RX_DESC_PREF_ACT, "PREF_ACT"),
+	REGISTER_FIELD_AZ_RENAME(RX_ISCSI_HDIG_EN, "HDIG"),
+	REGISTER_FIELD_AZ_RENAME(RX_ISCSI_DDIG_EN, "DDIG"),
+	REGISTER_FIELD_AA(RX_RESET),
+	REGISTER_FIELD_CZ_RENAME(RX_HDR_SPLIT, "HDR_SPLIT"),
+};
+#define efx_nic_reg_fields_RX_DESC_PTR_TBL_KER efx_nic_reg_fields_RX_DESC_PTR_TBL
+static const struct efx_nic_reg_field efx_nic_reg_fields_TX_DESC_PTR_TBL[] = {
+	/* Abbreviate field names to reduce the table width */
+	REGISTER_FIELD_AZ_RENAME(TX_DESCQ_FLUSH, "FLUSH"),
+	REGISTER_FIELD_AZ_RENAME(TX_DESCQ_TYPE, "TYPE"),
+	REGISTER_FIELD_AZ_RENAME(TX_DESCQ_SIZE, "SIZE"),
+	REGISTER_FIELD_AZ_RENAME(TX_DESCQ_LABEL, "LABEL"),
+	REGISTER_FIELD_AZ_RENAME(TX_DESCQ_OWNER_ID, "OWNER"),
+	REGISTER_FIELD_AZ_RENAME(TX_DESCQ_EVQ_ID, "EVQ"),
+	REGISTER_FIELD_AZ_RENAME(TX_DESCQ_BUF_BASE_ID, "BUF_BASE"),
+	REGISTER_FIELD_AZ_RENAME(TX_DESCQ_SW_WPTR, "SW_WPTR"),
+	REGISTER_FIELD_AZ_RENAME(TX_DESCQ_HW_RPTR, "HW_RPTR"),
+	REGISTER_FIELD_AZ_RENAME(TX_DC_HW_RPTR, "DC_HW_RPTR"),
+	REGISTER_FIELD_AZ_RENAME(TX_ISCSI_HDIG_EN, "HDIG"),
+	REGISTER_FIELD_AZ_RENAME(TX_ISCSI_DDIG_EN, "DDIG"),
+	REGISTER_FIELD_AZ_RENAME(TX_DESCQ_EN, "EN"),
+	REGISTER_FIELD_BZ_RENAME(TX_TCP_CHKSM_DIS, "!TCP_CHKSM"),
+	REGISTER_FIELD_BZ_RENAME(TX_IP_CHKSM_DIS, "!IP_CHKSM"),
+	REGISTER_FIELD_BZ_RENAME(TX_NON_IP_DROP_DIS, "!NON_IP_DROP"),
+	REGISTER_FIELD_CZ_RENAME(TX_DPT_IP_FILT_EN, "IP_FILT"),
+	REGISTER_FIELD_CZ_RENAME(TX_DPT_ETH_FILT_EN, "ETH_FILT"),
+	REGISTER_FIELD_CZ_RENAME(TX_DPT_Q_MASK_WIDTH, "Q_MASK_WIDTH"),
+};
+#define efx_nic_reg_fields_TX_DESC_PTR_TBL_KER efx_nic_reg_fields_TX_DESC_PTR_TBL
+static const struct efx_nic_reg_field efx_nic_reg_fields_EVQ_PTR_TBL[] = {
+	REGISTER_FIELD_AZ(EVQ_BUF_BASE_ID),
+	REGISTER_FIELD_AZ(EVQ_SIZE),
+	REGISTER_FIELD_AZ(EVQ_EN),
+	REGISTER_FIELD_AZ(EVQ_NXT_WPTR),
+	REGISTER_FIELD_CZ(EVQ_DOS_PROTECT_EN),
+	REGISTER_FIELD_AB(EVQ_WKUP_OR_INT_EN),
+	REGISTER_FIELD_BZ(EVQ_RPTR_IGN),
+};
+#define efx_nic_reg_fields_EVQ_PTR_TBL_KER efx_nic_reg_fields_EVQ_PTR_TBL
+static const struct efx_nic_reg_field efx_nic_reg_fields_BUF_FULL_TBL[] = {
+	REGISTER_FIELD_AZ(BUF_OWNER_ID_FBUF),
+	REGISTER_FIELD_AZ(BUF_ADR_FBUF),
+	REGISTER_FIELD_AZ(BUF_ADR_REGION),
+	REGISTER_FIELD_AZ(IP_DAT_BUF_SIZE),
+	REGISTER_FIELD_AZ(BUF_FULL_UNUSED),
+};
+#define efx_nic_reg_fields_BUF_FULL_TBL_KER efx_nic_reg_fields_BUF_FULL_TBL
+static const struct efx_nic_reg_field efx_nic_reg_fields_RX_FILTER_TBL0[] = {
+	/* Source port for full match; destination port for UDP wild match */
+	REGISTER_FIELD_BZ_RENAME(SRC_TCP_DEST_UDP, "SRC_PORT"),
+	REGISTER_FIELD_BZ(SRC_IP),
+	/* Destination port for full match or TCP wild match */
+	REGISTER_FIELD_BZ_RENAME(DEST_PORT_TCP, "DEST_PORT"),
+	REGISTER_FIELD_BZ(DEST_IP),
+	REGISTER_FIELD_BZ(RXQ_ID),
+	REGISTER_FIELD_BZ(TCP_UDP),
+	REGISTER_FIELD_BZ(SCATTER_EN),
+	REGISTER_FIELD_BZ(RSS_EN),
+};
+#define efx_nic_reg_fields_RX_FILTER_TBL1 efx_nic_reg_fields_RX_FILTER_TBL0
+static const struct efx_nic_reg_field efx_nic_reg_fields_RX_MAC_FILTER_TBL0[] = {
+	REGISTER_FIELD_CZ(RMFT_VLAN_ID),
+	REGISTER_FIELD_CZ(RMFT_DEST_MAC),
+	REGISTER_FIELD_CZ(RMFT_WILDCARD_MATCH),
+	REGISTER_FIELD_CZ(RMFT_RXQ_ID),
+	REGISTER_FIELD_CZ(RMFT_IP_OVERRIDE),
+	REGISTER_FIELD_CZ(RMFT_SCATTER_EN),
+	REGISTER_FIELD_CZ(RMFT_RSS_EN),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_TIMER_TBL[] = {
+	REGISTER_FIELD_BB(TIMER_VAL),
+	REGISTER_FIELD_CZ(TIMER_VAL),
+	REGISTER_FIELD_BB(TIMER_MODE),
+	REGISTER_FIELD_CZ(TIMER_MODE),
+	REGISTER_FIELD_CZ(RELOAD_TIMER_VAL),
+	REGISTER_FIELD_CZ(HOST_NOTIFY_MODE),
+	REGISTER_FIELD_CZ(INT_PEND),
+	REGISTER_FIELD_CZ(INT_ARMD),
+	REGISTER_FIELD_CZ(TIMER_Q_EN),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_TX_PACE_TBL[] = {
+	REGISTER_FIELD_BZ(TX_PACE),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_RX_INDIRECTION_TBL[] = {
+	REGISTER_FIELD_BZ(IT_QUEUE),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_TX_MAC_FILTER_TBL0[] = {
+	REGISTER_FIELD_CZ(TMFT_VLAN_ID),
+	REGISTER_FIELD_CZ(TMFT_SRC_MAC),
+	REGISTER_FIELD_CZ(TMFT_WILDCARD_MATCH),
+	REGISTER_FIELD_CZ(TMFT_TXQ_ID),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_MC_TREG_SMEM[] = {
+	REGISTER_FIELD_CZ(MC_TREG_SMEM_ROW),
+};
+static const struct efx_nic_reg_field efx_nic_reg_fields_BIU_MC_SFT_STATUS[] = {
+	REGISTER_FIELD_DZ(MC_SFT_STATUS),
+};
+
+struct efx_nic_reg {
+	const char *name;
+	const struct efx_nic_reg_field *fields;
+	u8 field_count;
+	u8 min_revision, max_revision;
+};
+
+#define REGISTER(name, arch, min_rev, max_rev) {			\
+	#name,								\
+	efx_nic_reg_fields_ ## name,					\
+	ARRAY_SIZE(efx_nic_reg_fields_ ## name),			\
+	REGISTER_REVISION_ ## arch ## min_rev,				\
+	REGISTER_REVISION_ ## arch ## max_rev				\
+}
+#define REGISTER_AA(name) REGISTER(name, F, A, A)
+#define REGISTER_AB(name) REGISTER(name, F, A, B)
+#define REGISTER_AZ(name) REGISTER(name, F, A, Z)
+#define REGISTER_BB(name) REGISTER(name, F, B, B)
+#define REGISTER_BZ(name) REGISTER(name, F, B, Z)
+#define REGISTER_CZ(name) REGISTER(name, F, C, Z)
+#define REGISTER_DZ(name) REGISTER(name, E, D, Z)
+
+static const struct efx_nic_reg efx_nic_regs[] = {
+	REGISTER_AZ(ADR_REGION),
+	REGISTER_AZ(INT_EN_KER),
+	REGISTER_BZ(INT_EN_CHAR),
+	REGISTER_AZ(INT_ADR_KER),
+	REGISTER_BZ(INT_ADR_CHAR),
+	/* INT_ACK_KER is WO */
+	/* INT_ISR0 is RC */
+	REGISTER_AZ(HW_INIT),
+	REGISTER_CZ(USR_EV_CFG),
+	REGISTER_AB(EE_SPI_HCMD),
+	REGISTER_AB(EE_SPI_HADR),
+	REGISTER_AB(EE_SPI_HDATA),
+	REGISTER_AB(EE_BASE_PAGE),
+	REGISTER_AB(EE_VPD_CFG0),
+	/* EE_VPD_SW_CNTL and EE_VPD_SW_DATA are not used */
+	/* PMBX_DBG_IADDR and PBMX_DBG_IDATA are indirect */
+	/* PCIE_CORE_INDIRECT is indirect */
+	REGISTER_AB(NIC_STAT),
+	REGISTER_AB(GPIO_CTL),
+	REGISTER_AB(GLB_CTL),
+	/* FATAL_INTR_KER and FATAL_INTR_CHAR are partly RC */
+	REGISTER_BZ(DP_CTRL),
+	REGISTER_AZ(MEM_STAT),
+	REGISTER_AZ(CS_DEBUG),
+	REGISTER_AZ(ALTERA_BUILD),
+	REGISTER_AZ(CSR_SPARE),
+	REGISTER_AB(PCIE_SD_CTL0123),
+	REGISTER_AB(PCIE_SD_CTL45),
+	REGISTER_AB(PCIE_PCS_CTL_STAT),
+	/* DEBUG_DATA_OUT is not used */
+	/* DRV_EV is WO */
+	REGISTER_AZ(EVQ_CTL),
+	REGISTER_AZ(EVQ_CNT1),
+	REGISTER_AZ(EVQ_CNT2),
+	REGISTER_AZ(BUF_TBL_CFG),
+	REGISTER_AZ(SRM_RX_DC_CFG),
+	REGISTER_AZ(SRM_TX_DC_CFG),
+	REGISTER_AZ(SRM_CFG),
+	/* BUF_TBL_UPD is WO */
+	REGISTER_AZ(SRM_UPD_EVQ),
+	REGISTER_AZ(SRAM_PARITY),
+	REGISTER_AZ(RX_CFG),
+	REGISTER_BZ(RX_FILTER_CTL),
+	/* RX_FLUSH_DESCQ is WO */
+	REGISTER_AZ(RX_DC_CFG),
+	REGISTER_AZ(RX_DC_PF_WM),
+	REGISTER_BZ(RX_RSS_TKEY),
+	/* RX_NODESC_DROP is RC */
+	REGISTER_AA(RX_SELF_RST),
+	/* RX_DEBUG, RX_PUSH_DROP are not used */
+	REGISTER_CZ(RX_RSS_IPV6_REG1),
+	REGISTER_CZ(RX_RSS_IPV6_REG2),
+	REGISTER_CZ(RX_RSS_IPV6_REG3),
+	/* TX_FLUSH_DESCQ is WO */
+	REGISTER_AZ(TX_DC_CFG),
+	REGISTER_AA(TX_CHKSM_CFG),
+	REGISTER_AZ(TX_CFG),
+	/* TX_PUSH_DROP is not used */
+	REGISTER_AZ(TX_RESERVED),
+	REGISTER_BZ(TX_PACE),
+	/* TX_PACE_DROP_QID is RC */
+	REGISTER_BB(TX_VLAN),
+	REGISTER_BZ(TX_IPFIL_PORTEN),
+	REGISTER_AB(MD_TXD),
+	REGISTER_AB(MD_RXD),
+	REGISTER_AB(MD_CS),
+	REGISTER_AB(MD_PHY_ADR),
+	REGISTER_AB(MD_ID),
+	/* MD_STAT is RC */
+	REGISTER_AB(MAC_STAT_DMA),
+	REGISTER_AB(MAC_CTRL),
+	REGISTER_BB(GEN_MODE),
+	REGISTER_AB(MAC_MC_HASH_REG0),
+	REGISTER_AB(MAC_MC_HASH_REG1),
+	REGISTER_AB(GM_CFG1),
+	REGISTER_AB(GM_CFG2),
+	/* GM_IPG and GM_HD are not used */
+	REGISTER_AB(GM_MAX_FLEN),
+	/* GM_TEST is not used */
+	REGISTER_AB(GM_ADR1),
+	REGISTER_AB(GM_ADR2),
+	REGISTER_AB(GMF_CFG0),
+	REGISTER_AB(GMF_CFG1),
+	REGISTER_AB(GMF_CFG2),
+	REGISTER_AB(GMF_CFG3),
+	REGISTER_AB(GMF_CFG4),
+	REGISTER_AB(GMF_CFG5),
+	REGISTER_BB(TX_SRC_MAC_CTL),
+	REGISTER_AB(XM_ADR_LO),
+	REGISTER_AB(XM_ADR_HI),
+	REGISTER_AB(XM_GLB_CFG),
+	REGISTER_AB(XM_TX_CFG),
+	REGISTER_AB(XM_RX_CFG),
+	REGISTER_AB(XM_MGT_INT_MASK),
+	REGISTER_AB(XM_FC),
+	REGISTER_AB(XM_PAUSE_TIME),
+	REGISTER_AB(XM_TX_PARAM),
+	REGISTER_AB(XM_RX_PARAM),
+	/* XM_MGT_INT_MSK (note no 'A') is RC */
+	REGISTER_AB(XX_PWR_RST),
+	REGISTER_AB(XX_SD_CTL),
+	REGISTER_AB(XX_TXDRV_CTL),
+	/* XX_PRBS_CTL, XX_PRBS_CHK and XX_PRBS_ERR are not used */
+	/* XX_CORE_STAT is partly RC */
+	REGISTER_DZ(BIU_HW_REV_ID),
+	REGISTER_DZ(MC_DB_LWRD),
+	REGISTER_DZ(MC_DB_HWRD),
+};
+
+struct efx_nic_reg_table {
+	const char *name;
+	const struct efx_nic_reg_field *fields;
+	u8 field_count;
+	u8 min_revision, max_revision;
+	u8 step;
+	u32 rows;
+};
+
+#define REGISTER_TABLE_DIMENSIONS(name, _, arch, min_rev, max_rev, step, rows) { \
+	#name,								\
+	efx_nic_reg_fields_ ## name,					\
+	ARRAY_SIZE(efx_nic_reg_fields_ ## name),			\
+	REGISTER_REVISION_ ## arch ## min_rev,				\
+	REGISTER_REVISION_ ## arch ## max_rev,				\
+	step, rows							\
+}
+#define REGISTER_TABLE(name, arch, min_rev, max_rev)			\
+	REGISTER_TABLE_DIMENSIONS(					\
+		name, arch ## R_ ## min_rev ## max_rev ## _ ## name,	\
+		arch, min_rev, max_rev,					\
+		arch ## R_ ## min_rev ## max_rev ## _ ## name ## _STEP,	\
+		arch ## R_ ## min_rev ## max_rev ## _ ## name ## _ROWS)
+#define REGISTER_TABLE_AA(name) REGISTER_TABLE(name, F, A, A)
+#define REGISTER_TABLE_AZ(name) REGISTER_TABLE(name, F, A, Z)
+#define REGISTER_TABLE_BB(name) REGISTER_TABLE(name, F, B, B)
+#define REGISTER_TABLE_BZ(name) REGISTER_TABLE(name, F, B, Z)
+#define REGISTER_TABLE_BB_CZ(name)					\
+	REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, F, B, B,	\
+				  FR_BZ_ ## name ## _STEP,		\
+				  FR_BB_ ## name ## _ROWS),		\
+	REGISTER_TABLE_DIMENSIONS(name, FR_BZ_ ## name, F, C, Z,	\
+				  FR_BZ_ ## name ## _STEP,		\
+				  FR_CZ_ ## name ## _ROWS)
+#define REGISTER_TABLE_CZ(name) REGISTER_TABLE(name, F, C, Z)
+#define REGISTER_TABLE_DZ(name) REGISTER_TABLE(name, E, D, Z)
+
+static const struct efx_nic_reg_table efx_nic_reg_tables[] = {
+	/* DRIVER is not used */
+	/* EVQ_RPTR, TIMER_COMMAND, USR_EV and {RX,TX}_DESC_UPD are WO */
+	REGISTER_TABLE_BB(TX_IPFIL_TBL),
+	REGISTER_TABLE_BB(TX_SRC_MAC_TBL),
+	REGISTER_TABLE_AA(RX_DESC_PTR_TBL_KER),
+	REGISTER_TABLE_BB_CZ(RX_DESC_PTR_TBL),
+	REGISTER_TABLE_AA(TX_DESC_PTR_TBL_KER),
+	REGISTER_TABLE_BB_CZ(TX_DESC_PTR_TBL),
+	REGISTER_TABLE_AA(EVQ_PTR_TBL_KER),
+	REGISTER_TABLE_BB_CZ(EVQ_PTR_TBL),
+	/* We can't reasonably read all of the buffer table (up to 8MB!).
+	 * However this driver will only use a few entries.  Reading
+	 * 1K entries allows for some expansion of queue count and
+	 * size before we need to change the version. */
+	REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL_KER, FR_AA_BUF_FULL_TBL_KER,
+				  F, A, A, 8, 1024),
+	REGISTER_TABLE_DIMENSIONS(BUF_FULL_TBL, FR_BZ_BUF_FULL_TBL,
+				  F, B, Z, 8, 1024),
+	REGISTER_TABLE_CZ(RX_MAC_FILTER_TBL0),
+	REGISTER_TABLE_BB_CZ(TIMER_TBL),
+	REGISTER_TABLE_BB_CZ(TX_PACE_TBL),
+	REGISTER_TABLE_BZ(RX_INDIRECTION_TBL),
+	/* TX_FILTER_TBL0 is huge and not used by this driver */
+	REGISTER_TABLE_CZ(TX_MAC_FILTER_TBL0),
+	REGISTER_TABLE_CZ(MC_TREG_SMEM),
+	/* MSIX_PBA_TABLE is not mapped */
+	/* SRM_DBG is not mapped (and is redundant with BUF_FLL_TBL) */
+	REGISTER_TABLE_BZ(RX_FILTER_TBL0),
+	REGISTER_TABLE_DZ(BIU_MC_SFT_STATUS),
+};
+
+static size_t column_width(const struct efx_nic_reg_field *field)
+{
+	size_t name_width, value_width;
+
+	name_width = strlen(field->name);
+	value_width = (field->width + 3) >> 2;
+
+	return name_width > value_width ? name_width : value_width;
+}
+
+static size_t column_padding(const struct efx_nic_reg_field *field)
+{
+	size_t name_width, value_width;
+
+	name_width = strlen(field->name);
+	value_width = (field->width + 3) >> 2;
+
+	return name_width > value_width ? name_width - value_width : 0;
+}
+
+static void
+print_field_value(const struct efx_nic_reg_field *field, const u8 *buf)
+{
+	unsigned left, right, sig_bits, digit;
+
+	right = field->lbn;
+	left = right + ((field->width + 3) & ~3);
+
+	/* How many bits are valid for the most significant hex digit? */
+	sig_bits = (field->width & 3) ? (field->width & 3) : 4;
+
+	while (left > right) {
+		left -= 4;
+		digit = buf[left >> 3];
+		if ((left & 7) + sig_bits > 8)
+			digit |= buf[(left >> 3) + 1] << 8;
+		digit = (digit >> (left & 7)) & ((1 << sig_bits) - 1);
+		printf("%x", digit);
+		sig_bits = 4; /* for all subsequent digits */
+	}
+}
+
+static const void *
+print_single_register(unsigned revision, const struct efx_nic_reg *reg,
+		      const void *buf)
+{
+	const struct efx_nic_reg_field *field;
+	int indent = 0;
+	size_t i;
+
+	for (i = 0; i < reg->field_count; i++) {
+		field = &reg->fields[i];
+		if (revision >= field->min_revision &&
+		    revision <= field->max_revision) {
+			if (indent == 0)
+				indent = printf("%s: ", reg->name);
+			else
+				printf("%*s", indent, "");
+			printf("%s = ", field->name);
+			print_field_value(field, buf);
+			fputc('\n', stdout);
+		}
+	}
+				
+	return (const u8 *)buf + 16;
+}
+
+static const void *
+print_simple_table(const struct efx_nic_reg_table *table, const void *buf)
+{
+	const struct efx_nic_reg_field *field = &table->fields[0];
+	size_t value_width = (field->width + 3) >> 2;
+	size_t column_count = 72 / (value_width + 1);
+	size_t size = table->step > 16 ? 16 : table->step;
+	size_t i;
+
+	for (i = 0; i < table->rows; i++) {
+		if (i % column_count == 0) {
+			if (i != 0)
+				fputc('\n', stdout);
+			printf("%4zu ", i);
+		}
+		fputc(' ', stdout);
+		print_field_value(field, buf);
+		buf = (const u8 *)buf + size;
+	}
+	fputc('\n', stdout);
+
+	return buf;
+}
+
+static int buf_is_zero(const u8 *buf, size_t size)
+{
+	size_t i;
+	for (i = 0; i < size; i++)
+		if (buf[i])
+			return 0;
+	return 1;
+}
+
+static const void *
+print_complex_table(unsigned revision, const struct efx_nic_reg_table *table,
+		    const void *buf)
+{
+	const struct efx_nic_reg_field *field;
+	size_t size = table->step > 16 ? 16 : table->step;
+	size_t i, j;
+
+	/* Column headings */
+	fputs("Row ", stdout);
+	for (i = 0; i < table->field_count; i++) {
+		field = &table->fields[i];
+		if (revision >= field->min_revision &&
+		    revision <= field->max_revision)
+			printf(" %-*s", (int)column_width(field),
+			       field->name);
+	}
+	fputc('\n', stdout);
+	fputs("----", stdout);
+	for (i = 0; i < table->field_count; i++) {
+		field = &table->fields[i];
+		if (revision >= field->min_revision &&
+		    revision <= field->max_revision) {
+			fputc(' ', stdout);
+			for (j = column_width(field); j > 0; j--)
+				fputc('-', stdout);
+		}
+	}
+	fputc('\n', stdout);
+
+	for (j = 0; j < table->rows; j++) {
+		if (!buf_is_zero(buf, size)) {
+			printf("%4zu", j);
+			for (i = 0; i < table->field_count; i++) {
+				field = &table->fields[i];
+				if (!(revision >= field->min_revision &&
+				      revision <= field->max_revision))
+					continue;
+				printf(" %*s", (int)column_padding(field), "");
+				print_field_value(field, buf);
+			}
+			fputc('\n', stdout);
+		}
+		buf = (const u8 *)buf + size;
+	}
+
+	return buf;
+}
+
+int
+sfc_dump_regs(struct ethtool_drvinfo *info maybe_unused, struct ethtool_regs *regs)
+{
+	const struct efx_nic_reg *reg;
+	const struct efx_nic_reg_table *table;
+	unsigned revision = regs->version;
+	const void *buf = regs->data;
+	const void *end = regs->data + regs->len;
+
+	if (revision > REGISTER_REVISION_ED)
+		return -1;
+
+	for (reg = efx_nic_regs;	
+	     reg < efx_nic_regs + ARRAY_SIZE(efx_nic_regs) && buf < end;
+	     reg++) {
+		if (revision >= reg->min_revision &&
+		    revision <= reg->max_revision)
+			buf = print_single_register(revision, reg, buf);
+	}
+
+	for (table = efx_nic_reg_tables;
+	     table < efx_nic_reg_tables + ARRAY_SIZE(efx_nic_reg_tables) &&
+		     buf < end;
+	     table++) {
+		if (revision >= table->min_revision &&
+		    revision <= table->max_revision) {
+			printf("\n%s:\n", table->name);
+			if (table->field_count == 1)
+				buf = print_simple_table(table, buf);
+			else
+				buf = print_complex_table(revision, table, buf);
+		}
+	}
+
+	return 0;
+}
diff --git a/sff-common.c b/sff-common.c
new file mode 100644
index 0000000..7700cbe
--- /dev/null
+++ b/sff-common.c
@@ -0,0 +1,304 @@
+/*
+ * sff-common.c: Implements SFF-8024 Rev 4.0 i.e. Specifcation
+ * of pluggable I/O configuration
+ *
+ * Common utilities across SFF-8436/8636 and SFF-8472/8079
+ * are defined in this file
+ *
+ * Copyright 2010 Solarflare Communications Inc.
+ * Aurelien Guillaume <aurelien@iwi.me> (C) 2012
+ * Copyright (C) 2014 Cumulus networks Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Freeoftware Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *  Vidya Sagar Ravipati <vidya@cumulusnetworks.com>
+ *   This implementation is loosely based on current SFP parser
+ *   and SFF-8024 Rev 4.0 spec (ftp://ftp.seagate.com/pub/sff/SFF-8024.PDF)
+ *   by SFF Committee.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include "sff-common.h"
+
+double convert_mw_to_dbm(double mw)
+{
+	return (10. * log10(mw / 1000.)) + 30.;
+}
+
+void sff_show_value_with_unit(const __u8 *id, unsigned int reg,
+			      const char *name, unsigned int mult,
+			      const char *unit)
+{
+	unsigned int val = id[reg];
+
+	printf("\t%-41s : %u%s\n", name, val * mult, unit);
+}
+
+void sff_show_ascii(const __u8 *id, unsigned int first_reg,
+		    unsigned int last_reg, const char *name)
+{
+	unsigned int reg, val;
+
+	printf("\t%-41s : ", name);
+	while (first_reg <= last_reg && id[last_reg] == ' ')
+		last_reg--;
+	for (reg = first_reg; reg <= last_reg; reg++) {
+		val = id[reg];
+		putchar(((val >= 32) && (val <= 126)) ? val : '_');
+	}
+	printf("\n");
+}
+
+void sff8024_show_oui(const __u8 *id, int id_offset)
+{
+	printf("\t%-41s : %02x:%02x:%02x\n", "Vendor OUI",
+		      id[id_offset], id[(id_offset) + 1],
+		      id[(id_offset) + 2]);
+}
+
+void sff8024_show_identifier(const __u8 *id, int id_offset)
+{
+	printf("\t%-41s : 0x%02x", "Identifier", id[id_offset]);
+	switch (id[id_offset]) {
+	case SFF8024_ID_UNKNOWN:
+		printf(" (no module present, unknown, or unspecified)\n");
+		break;
+	case SFF8024_ID_GBIC:
+		printf(" (GBIC)\n");
+		break;
+	case SFF8024_ID_SOLDERED_MODULE:
+		printf(" (module soldered to motherboard)\n");
+		break;
+	case SFF8024_ID_SFP:
+		printf(" (SFP)\n");
+		break;
+	case SFF8024_ID_300_PIN_XBI:
+		printf(" (300 pin XBI)\n");
+		break;
+	case SFF8024_ID_XENPAK:
+		printf(" (XENPAK)\n");
+		break;
+	case SFF8024_ID_XFP:
+		printf(" (XFP)\n");
+		break;
+	case SFF8024_ID_XFF:
+		printf(" (XFF)\n");
+		break;
+	case SFF8024_ID_XFP_E:
+		printf(" (XFP-E)\n");
+		break;
+	case SFF8024_ID_XPAK:
+		printf(" (XPAK)\n");
+		break;
+	case SFF8024_ID_X2:
+		printf(" (X2)\n");
+		break;
+	case SFF8024_ID_DWDM_SFP:
+		printf(" (DWDM-SFP)\n");
+		break;
+	case SFF8024_ID_QSFP:
+		printf(" (QSFP)\n");
+		break;
+	case SFF8024_ID_QSFP_PLUS:
+		printf(" (QSFP+)\n");
+		break;
+	case SFF8024_ID_CXP:
+		printf(" (CXP)\n");
+		break;
+	case SFF8024_ID_HD4X:
+		printf(" (Shielded Mini Multilane HD 4X)\n");
+		break;
+	case SFF8024_ID_HD8X:
+		printf(" (Shielded Mini Multilane HD 8X)\n");
+		break;
+	case SFF8024_ID_QSFP28:
+		printf(" (QSFP28)\n");
+		break;
+	case SFF8024_ID_CXP2:
+		printf(" (CXP2/CXP28)\n");
+		break;
+	case SFF8024_ID_CDFP:
+		printf(" (CDFP Style 1/Style 2)\n");
+		break;
+	case SFF8024_ID_HD4X_FANOUT:
+		printf(" (Shielded Mini Multilane HD 4X Fanout Cable)\n");
+		break;
+	case SFF8024_ID_HD8X_FANOUT:
+		printf(" (Shielded Mini Multilane HD 8X Fanout Cable)\n");
+		break;
+	case SFF8024_ID_CDFP_S3:
+		printf(" (CDFP Style 3)\n");
+		break;
+	case SFF8024_ID_MICRO_QSFP:
+		printf(" (microQSFP)\n");
+		break;
+	default:
+		printf(" (reserved or unknown)\n");
+		break;
+	}
+}
+
+void sff8024_show_connector(const __u8 *id, int ctor_offset)
+{
+	printf("\t%-41s : 0x%02x", "Connector", id[ctor_offset]);
+	switch (id[ctor_offset]) {
+	case  SFF8024_CTOR_UNKNOWN:
+		printf(" (unknown or unspecified)\n");
+		break;
+	case SFF8024_CTOR_SC:
+		printf(" (SC)\n");
+		break;
+	case SFF8024_CTOR_FC_STYLE_1:
+		printf(" (Fibre Channel Style 1 copper)\n");
+		break;
+	case SFF8024_CTOR_FC_STYLE_2:
+		printf(" (Fibre Channel Style 2 copper)\n");
+		break;
+	case SFF8024_CTOR_BNC_TNC:
+		printf(" (BNC/TNC)\n");
+		break;
+	case SFF8024_CTOR_FC_COAX:
+		printf(" (Fibre Channel coaxial headers)\n");
+		break;
+	case SFF8024_CTOR_FIBER_JACK:
+		printf(" (FibreJack)\n");
+		break;
+	case SFF8024_CTOR_LC:
+		printf(" (LC)\n");
+		break;
+	case SFF8024_CTOR_MT_RJ:
+		printf(" (MT-RJ)\n");
+		break;
+	case SFF8024_CTOR_MU:
+		printf(" (MU)\n");
+		break;
+	case SFF8024_CTOR_SG:
+		printf(" (SG)\n");
+		break;
+	case SFF8024_CTOR_OPT_PT:
+		printf(" (Optical pigtail)\n");
+		break;
+	case SFF8024_CTOR_MPO:
+		printf(" (MPO Parallel Optic)\n");
+		break;
+	case SFF8024_CTOR_MPO_2:
+		printf(" (MPO Parallel Optic - 2x16)\n");
+		break;
+	case SFF8024_CTOR_HSDC_II:
+		printf(" (HSSDC II)\n");
+		break;
+	case SFF8024_CTOR_COPPER_PT:
+		printf(" (Copper pigtail)\n");
+		break;
+	case SFF8024_CTOR_RJ45:
+		printf(" (RJ45)\n");
+		break;
+	case SFF8024_CTOR_NO_SEPARABLE:
+		printf(" (No separable connector)\n");
+		break;
+	case SFF8024_CTOR_MXC_2x16:
+		printf(" (MXC 2x16)\n");
+		break;
+	default:
+		printf(" (reserved or unknown)\n");
+		break;
+	}
+}
+
+void sff8024_show_encoding(const __u8 *id, int encoding_offset, int sff_type)
+{
+	printf("\t%-41s : 0x%02x", "Encoding", id[encoding_offset]);
+	switch (id[encoding_offset]) {
+	case SFF8024_ENCODING_UNSPEC:
+		printf(" (unspecified)\n");
+		break;
+	case SFF8024_ENCODING_8B10B:
+		printf(" (8B/10B)\n");
+		break;
+	case SFF8024_ENCODING_4B5B:
+		printf(" (4B/5B)\n");
+		break;
+	case SFF8024_ENCODING_NRZ:
+		printf(" (NRZ)\n");
+		break;
+	case SFF8024_ENCODING_4h:
+		if (sff_type == ETH_MODULE_SFF_8472)
+			printf(" (Manchester)\n");
+		else if (sff_type == ETH_MODULE_SFF_8636)
+			printf(" (SONET Scrambled)\n");
+		break;
+	case SFF8024_ENCODING_5h:
+		if (sff_type == ETH_MODULE_SFF_8472)
+			printf(" (SONET Scrambled)\n");
+		else if (sff_type == ETH_MODULE_SFF_8636)
+			printf(" (64B/66B)\n");
+		break;
+	case SFF8024_ENCODING_6h:
+		if (sff_type == ETH_MODULE_SFF_8472)
+			printf(" (64B/66B)\n");
+		else if (sff_type == ETH_MODULE_SFF_8636)
+			printf(" (Manchester)\n");
+		break;
+	case SFF8024_ENCODING_256B:
+		printf(" ((256B/257B (transcoded FEC-enabled data))\n");
+		break;
+	case SFF8024_ENCODING_PAM4:
+		printf(" (PAM4)\n");
+		break;
+	default:
+		printf(" (reserved or unknown)\n");
+		break;
+	}
+}
+
+void sff_show_thresholds(struct sff_diags sd)
+{
+	PRINT_BIAS("Laser bias current high alarm threshold",
+		   sd.bias_cur[HALRM]);
+	PRINT_BIAS("Laser bias current low alarm threshold",
+		   sd.bias_cur[LALRM]);
+	PRINT_BIAS("Laser bias current high warning threshold",
+		   sd.bias_cur[HWARN]);
+	PRINT_BIAS("Laser bias current low warning threshold",
+		   sd.bias_cur[LWARN]);
+
+	PRINT_xX_PWR("Laser output power high alarm threshold",
+		     sd.tx_power[HALRM]);
+	PRINT_xX_PWR("Laser output power low alarm threshold",
+		     sd.tx_power[LALRM]);
+	PRINT_xX_PWR("Laser output power high warning threshold",
+		     sd.tx_power[HWARN]);
+	PRINT_xX_PWR("Laser output power low warning threshold",
+		     sd.tx_power[LWARN]);
+
+	PRINT_TEMP("Module temperature high alarm threshold",
+		   sd.sfp_temp[HALRM]);
+	PRINT_TEMP("Module temperature low alarm threshold",
+		   sd.sfp_temp[LALRM]);
+	PRINT_TEMP("Module temperature high warning threshold",
+		   sd.sfp_temp[HWARN]);
+	PRINT_TEMP("Module temperature low warning threshold",
+		   sd.sfp_temp[LWARN]);
+
+	PRINT_VCC("Module voltage high alarm threshold",
+		  sd.sfp_voltage[HALRM]);
+	PRINT_VCC("Module voltage low alarm threshold",
+		  sd.sfp_voltage[LALRM]);
+	PRINT_VCC("Module voltage high warning threshold",
+		  sd.sfp_voltage[HWARN]);
+	PRINT_VCC("Module voltage low warning threshold",
+		  sd.sfp_voltage[LWARN]);
+
+	PRINT_xX_PWR("Laser rx power high alarm threshold",
+		     sd.rx_power[HALRM]);
+	PRINT_xX_PWR("Laser rx power low alarm threshold",
+		     sd.rx_power[LALRM]);
+	PRINT_xX_PWR("Laser rx power high warning threshold",
+		     sd.rx_power[HWARN]);
+	PRINT_xX_PWR("Laser rx power low warning threshold",
+		     sd.rx_power[LWARN]);
+}
diff --git a/sff-common.h b/sff-common.h
new file mode 100644
index 0000000..5562b4d
--- /dev/null
+++ b/sff-common.h
@@ -0,0 +1,189 @@
+/*
+ * sff-common.h: Implements SFF-8024 Rev 4.0 i.e. Specifcation
+ * of pluggable I/O configuration
+ *
+ * Common utilities across SFF-8436/8636 and SFF-8472/8079
+ * are defined in this file
+ *
+ * Copyright 2010 Solarflare Communications Inc.
+ * Aurelien Guillaume <aurelien@iwi.me> (C) 2012
+ * Copyright (C) 2014 Cumulus networks Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Freeoftware Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *  Vidya Sagar Ravipati <vidya@cumulusnetworks.com>
+ *   This implementation is loosely based on current SFP parser
+ *   and SFF-8024 specs (ftp://ftp.seagate.com/pub/sff/SFF-8024.PDF)
+ *   by SFF Committee.
+ */
+
+#ifndef SFF_COMMON_H__
+#define SFF_COMMON_H__
+
+#include <stdio.h>
+#include "internal.h"
+
+#define SFF8024_ID_OFFSET				0x00
+#define  SFF8024_ID_UNKNOWN				0x00
+#define  SFF8024_ID_GBIC				0x01
+#define  SFF8024_ID_SOLDERED_MODULE		0x02
+#define  SFF8024_ID_SFP					0x03
+#define  SFF8024_ID_300_PIN_XBI			0x04
+#define  SFF8024_ID_XENPAK				0x05
+#define  SFF8024_ID_XFP					0x06
+#define  SFF8024_ID_XFF					0x07
+#define  SFF8024_ID_XFP_E				0x08
+#define  SFF8024_ID_XPAK				0x09
+#define  SFF8024_ID_X2					0x0A
+#define  SFF8024_ID_DWDM_SFP			0x0B
+#define  SFF8024_ID_QSFP				0x0C
+#define  SFF8024_ID_QSFP_PLUS			0x0D
+#define  SFF8024_ID_CXP					0x0E
+#define  SFF8024_ID_HD4X				0x0F
+#define  SFF8024_ID_HD8X				0x10
+#define  SFF8024_ID_QSFP28				0x11
+#define  SFF8024_ID_CXP2				0x12
+#define  SFF8024_ID_CDFP				0x13
+#define  SFF8024_ID_HD4X_FANOUT			0x14
+#define  SFF8024_ID_HD8X_FANOUT			0x15
+#define  SFF8024_ID_CDFP_S3				0x16
+#define  SFF8024_ID_MICRO_QSFP			0x17
+#define  SFF8024_ID_LAST				SFF8024_ID_MICRO_QSFP
+#define  SFF8024_ID_UNALLOCATED_LAST	0x7F
+#define  SFF8024_ID_VENDOR_START		0x80
+#define  SFF8024_ID_VENDOR_LAST			0xFF
+
+#define  SFF8024_CTOR_UNKNOWN			0x00
+#define  SFF8024_CTOR_SC				0x01
+#define  SFF8024_CTOR_FC_STYLE_1		0x02
+#define  SFF8024_CTOR_FC_STYLE_2		0x03
+#define  SFF8024_CTOR_BNC_TNC			0x04
+#define  SFF8024_CTOR_FC_COAX			0x05
+#define  SFF8024_CTOR_FIBER_JACK		0x06
+#define  SFF8024_CTOR_LC				0x07
+#define  SFF8024_CTOR_MT_RJ				0x08
+#define  SFF8024_CTOR_MU				0x09
+#define  SFF8024_CTOR_SG				0x0A
+#define  SFF8024_CTOR_OPT_PT			0x0B
+#define  SFF8024_CTOR_MPO				0x0C
+#define  SFF8024_CTOR_MPO_2				0x0D
+/* 0E-1Fh --- Reserved */
+#define  SFF8024_CTOR_HSDC_II			0x20
+#define  SFF8024_CTOR_COPPER_PT			0x21
+#define  SFF8024_CTOR_RJ45				0x22
+#define  SFF8024_CTOR_NO_SEPARABLE		0x23
+#define  SFF8024_CTOR_MXC_2x16			0x24
+#define  SFF8024_CTOR_LAST				SFF8024_CTOR_MXC_2x16
+#define  SFF8024_CTOR_UNALLOCATED_LAST	0x7F
+#define  SFF8024_CTOR_VENDOR_START		0x80
+#define  SFF8024_CTOR_VENDOR_LAST		0xFF
+
+/* ENCODING Values */
+#define  SFF8024_ENCODING_UNSPEC		0x00
+#define  SFF8024_ENCODING_8B10B			0x01
+#define  SFF8024_ENCODING_4B5B			0x02
+#define  SFF8024_ENCODING_NRZ			0x03
+/*
+ * Value: 04h
+ * SFF-8472      - Manchester
+ * SFF-8436/8636 - SONET Scrambled
+ */
+#define  SFF8024_ENCODING_4h			0x04
+/*
+ * Value: 05h
+ * SFF-8472      - SONET Scrambled
+ * SFF-8436/8636 - 64B/66B
+ */
+#define  SFF8024_ENCODING_5h			0x05
+/*
+ * Value: 06h
+ * SFF-8472      - 64B/66B
+ * SFF-8436/8636 - Manchester
+ */
+#define  SFF8024_ENCODING_6h			0x06
+#define  SFF8024_ENCODING_256B			0x07
+#define  SFF8024_ENCODING_PAM4			0x08
+
+/* Most common case: 16-bit unsigned integer in a certain unit */
+#define OFFSET_TO_U16(offset) \
+		(id[offset] << 8 | id[(offset) + 1])
+
+# define PRINT_xX_PWR(string, var)                             \
+		printf("\t%-41s : %.4f mW / %.2f dBm\n", (string),         \
+		      (double)((var) / 10000.),                           \
+		       convert_mw_to_dbm((double)((var) / 10000.)))
+
+#define PRINT_BIAS(string, bias_cur)                             \
+		printf("\t%-41s : %.3f mA\n", (string),                       \
+		      (double)(bias_cur / 500.))
+
+#define PRINT_TEMP(string, temp)                                   \
+		printf("\t%-41s : %.2f degrees C / %.2f degrees F\n", \
+		      (string), (double)(temp / 256.),                \
+		      (double)(temp / 256. * 1.8 + 32.))
+
+#define PRINT_VCC(string, sfp_voltage)          \
+		printf("\t%-41s : %.4f V\n", (string),       \
+		      (double)(sfp_voltage / 10000.))
+
+# define PRINT_xX_THRESH_PWR(string, var, index)                       \
+		PRINT_xX_PWR(string, (var)[(index)])
+
+/* Channel Monitoring Fields */
+struct sff_channel_diags {
+	__u16 bias_cur;      /* Measured bias current in 2uA units */
+	__u16 rx_power;      /* Measured RX Power */
+	__u16 tx_power;      /* Measured TX Power */
+};
+
+/* Module Monitoring Fields */
+struct sff_diags {
+
+#define MAX_CHANNEL_NUM 4
+#define LWARN 0
+#define HWARN 1
+#define LALRM 2
+#define HALRM 3
+#define MCURR 4
+
+	/* Supports DOM */
+	__u8 supports_dom;
+	/* Supports alarm/warning thold */
+	__u8 supports_alarms;
+	/* RX Power: 0 = OMA, 1 = Average power */
+	__u8  rx_power_type;
+	/* TX Power: 0 = Not supported, 1 = Average power */
+	__u8  tx_power_type;
+
+	__u8 calibrated_ext;    /* Is externally calibrated */
+	/* [5] tables are low/high warn, low/high alarm, current */
+	/* SFP voltage in 0.1mV units */
+	__u16 sfp_voltage[5];
+	/* SFP Temp in 16-bit signed 1/256 Celcius */
+	__s16 sfp_temp[5];
+	/* Measured bias current in 2uA units */
+	__u16 bias_cur[5];
+	/* Measured TX Power */
+	__u16 tx_power[5];
+	/* Measured RX Power */
+	__u16 rx_power[5];
+	struct sff_channel_diags scd[MAX_CHANNEL_NUM];
+};
+
+double convert_mw_to_dbm(double mw);
+void sff_show_value_with_unit(const __u8 *id, unsigned int reg,
+			      const char *name, unsigned int mult,
+			      const char *unit);
+void sff_show_ascii(const __u8 *id, unsigned int first_reg,
+		    unsigned int last_reg, const char *name);
+void sff_show_thresholds(struct sff_diags sd);
+
+void sff8024_show_oui(const __u8 *id, int id_offset);
+void sff8024_show_identifier(const __u8 *id, int id_offset);
+void sff8024_show_connector(const __u8 *id, int ctor_offset);
+void sff8024_show_encoding(const __u8 *id, int encoding_offset, int sff_type);
+
+#endif /* SFF_COMMON_H__ */
diff --git a/sfpdiag.c b/sfpdiag.c
new file mode 100644
index 0000000..fa41651
--- /dev/null
+++ b/sfpdiag.c
@@ -0,0 +1,281 @@
+/*
+ * sfpdiag.c: Implements SFF-8472 optics diagnostics.
+ *
+ * Aurelien Guillaume <aurelien@iwi.me> (C) 2012
+ *   This implementation is loosely based on DOM patches
+ *   from Robert Olsson <robert@herjulf.se> (C) 2009
+ *   and SFF-8472 specs (ftp://ftp.seagate.com/pub/sff/SFF-8472.PDF)
+ *   by SFF Committee.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <arpa/inet.h>
+#include "internal.h"
+#include "sff-common.h"
+
+/* Offsets in decimal, for direct comparison with the SFF specs */
+
+/* A0-based EEPROM offsets for DOM support checks */
+#define SFF_A0_DOM                        92
+#define SFF_A0_OPTIONS                    93
+#define SFF_A0_COMP                       94
+
+/* EEPROM bit values for various registers */
+#define SFF_A0_DOM_EXTCAL                 (1 << 4)
+#define SFF_A0_DOM_INTCAL                 (1 << 5)
+#define SFF_A0_DOM_IMPL                   (1 << 6)
+#define SFF_A0_DOM_PWRT                   (1 << 3)
+
+#define SFF_A0_OPTIONS_AW                 (1 << 7)
+
+/*
+ * See ethtool.c comments about SFF-8472, this is the offset
+ * at which the A2 page is in the EEPROM blob returned by the
+ * kernel.
+ */
+#define SFF_A2_BASE                       0x100
+
+/* A2-based offsets for DOM */
+#define SFF_A2_TEMP                       96
+#define SFF_A2_TEMP_HALRM                 0
+#define SFF_A2_TEMP_LALRM                 2
+#define SFF_A2_TEMP_HWARN                 4
+#define SFF_A2_TEMP_LWARN                 6
+
+#define SFF_A2_VCC                        98
+#define SFF_A2_VCC_HALRM                  8
+#define SFF_A2_VCC_LALRM                  10
+#define SFF_A2_VCC_HWARN                  12
+#define SFF_A2_VCC_LWARN                  14
+
+#define SFF_A2_BIAS                       100
+#define SFF_A2_BIAS_HALRM                 16
+#define SFF_A2_BIAS_LALRM                 18
+#define SFF_A2_BIAS_HWARN                 20
+#define SFF_A2_BIAS_LWARN                 22
+
+#define SFF_A2_TX_PWR                     102
+#define SFF_A2_TX_PWR_HALRM               24
+#define SFF_A2_TX_PWR_LALRM               26
+#define SFF_A2_TX_PWR_HWARN               28
+#define SFF_A2_TX_PWR_LWARN               30
+
+#define SFF_A2_RX_PWR                     104
+#define SFF_A2_RX_PWR_HALRM               32
+#define SFF_A2_RX_PWR_LALRM               34
+#define SFF_A2_RX_PWR_HWARN               36
+#define SFF_A2_RX_PWR_LWARN               38
+
+#define SFF_A2_ALRM_FLG                   112
+#define SFF_A2_WARN_FLG                   116
+
+/* 32-bit little-endian calibration constants */
+#define SFF_A2_CAL_RXPWR4                 56
+#define SFF_A2_CAL_RXPWR3                 60
+#define SFF_A2_CAL_RXPWR2                 64
+#define SFF_A2_CAL_RXPWR1                 68
+#define SFF_A2_CAL_RXPWR0                 72
+
+/* 16-bit little endian calibration constants */
+#define SFF_A2_CAL_TXI_SLP                76
+#define SFF_A2_CAL_TXI_OFF                78
+#define SFF_A2_CAL_TXPWR_SLP              80
+#define SFF_A2_CAL_TXPWR_OFF              82
+#define SFF_A2_CAL_T_SLP                  84
+#define SFF_A2_CAL_T_OFF                  86
+#define SFF_A2_CAL_V_SLP                  88
+#define SFF_A2_CAL_V_OFF                  90
+
+static struct sff8472_aw_flags {
+	const char *str;        /* Human-readable string, null at the end */
+	int offset;             /* A2-relative address offset */
+	__u8 value;             /* Alarm is on if (offset & value) != 0. */
+} sff8472_aw_flags[] = {
+	{ "Laser bias current high alarm",   SFF_A2_ALRM_FLG, (1 << 3) },
+	{ "Laser bias current low alarm",    SFF_A2_ALRM_FLG, (1 << 2) },
+	{ "Laser bias current high warning", SFF_A2_WARN_FLG, (1 << 3) },
+	{ "Laser bias current low warning",  SFF_A2_WARN_FLG, (1 << 2) },
+
+	{ "Laser output power high alarm",   SFF_A2_ALRM_FLG, (1 << 1) },
+	{ "Laser output power low alarm",    SFF_A2_ALRM_FLG, (1 << 0) },
+	{ "Laser output power high warning", SFF_A2_WARN_FLG, (1 << 1) },
+	{ "Laser output power low warning",  SFF_A2_WARN_FLG, (1 << 0) },
+
+	{ "Module temperature high alarm",   SFF_A2_ALRM_FLG, (1 << 7) },
+	{ "Module temperature low alarm",    SFF_A2_ALRM_FLG, (1 << 6) },
+	{ "Module temperature high warning", SFF_A2_WARN_FLG, (1 << 7) },
+	{ "Module temperature low warning",  SFF_A2_WARN_FLG, (1 << 6) },
+
+	{ "Module voltage high alarm",   SFF_A2_ALRM_FLG, (1 << 5) },
+	{ "Module voltage low alarm",    SFF_A2_ALRM_FLG, (1 << 4) },
+	{ "Module voltage high warning", SFF_A2_WARN_FLG, (1 << 5) },
+	{ "Module voltage low warning",  SFF_A2_WARN_FLG, (1 << 4) },
+
+	{ "Laser rx power high alarm",   SFF_A2_ALRM_FLG + 1, (1 << 7) },
+	{ "Laser rx power low alarm",    SFF_A2_ALRM_FLG + 1, (1 << 6) },
+	{ "Laser rx power high warning", SFF_A2_WARN_FLG + 1, (1 << 7) },
+	{ "Laser rx power low warning",  SFF_A2_WARN_FLG + 1, (1 << 6) },
+
+	{ NULL, 0, 0 },
+};
+
+/* Most common case: 16-bit unsigned integer in a certain unit */
+#define A2_OFFSET_TO_U16(offset) \
+	(id[SFF_A2_BASE + (offset)] << 8 | id[SFF_A2_BASE + (offset) + 1])
+
+/* Calibration slope is a number between 0.0 included and 256.0 excluded. */
+#define A2_OFFSET_TO_SLP(offset) \
+	(id[SFF_A2_BASE + (offset)] + id[SFF_A2_BASE + (offset) + 1] / 256.)
+
+/* Calibration offset is an integer from -32768 to 32767 */
+#define A2_OFFSET_TO_OFF(offset) \
+	((__s16)A2_OFFSET_TO_U16(offset))
+
+/* RXPWR(x) are IEEE-754 floating point numbers in big-endian format */
+#define A2_OFFSET_TO_RXPWRx(offset) \
+	(befloattoh((__u32 *)(id + SFF_A2_BASE + (offset))))
+
+/*
+ * 2-byte internal temperature conversions:
+ * First byte is a signed 8-bit integer, which is the temp decimal part
+ * Second byte are 1/256th of degree, which are added to the dec part.
+ */
+#define A2_OFFSET_TO_TEMP(offset) ((__s16)A2_OFFSET_TO_U16(offset))
+
+static void sff8472_dom_parse(const __u8 *id, struct sff_diags *sd)
+{
+	sd->bias_cur[MCURR] = A2_OFFSET_TO_U16(SFF_A2_BIAS);
+	sd->bias_cur[HALRM] = A2_OFFSET_TO_U16(SFF_A2_BIAS_HALRM);
+	sd->bias_cur[LALRM] = A2_OFFSET_TO_U16(SFF_A2_BIAS_LALRM);
+	sd->bias_cur[HWARN] = A2_OFFSET_TO_U16(SFF_A2_BIAS_HWARN);
+	sd->bias_cur[LWARN] = A2_OFFSET_TO_U16(SFF_A2_BIAS_LWARN);
+
+	sd->sfp_voltage[MCURR] = A2_OFFSET_TO_U16(SFF_A2_VCC);
+	sd->sfp_voltage[HALRM] = A2_OFFSET_TO_U16(SFF_A2_VCC_HALRM);
+	sd->sfp_voltage[LALRM] = A2_OFFSET_TO_U16(SFF_A2_VCC_LALRM);
+	sd->sfp_voltage[HWARN] = A2_OFFSET_TO_U16(SFF_A2_VCC_HWARN);
+	sd->sfp_voltage[LWARN] = A2_OFFSET_TO_U16(SFF_A2_VCC_LWARN);
+
+	sd->tx_power[MCURR] = A2_OFFSET_TO_U16(SFF_A2_TX_PWR);
+	sd->tx_power[HALRM] = A2_OFFSET_TO_U16(SFF_A2_TX_PWR_HALRM);
+	sd->tx_power[LALRM] = A2_OFFSET_TO_U16(SFF_A2_TX_PWR_LALRM);
+	sd->tx_power[HWARN] = A2_OFFSET_TO_U16(SFF_A2_TX_PWR_HWARN);
+	sd->tx_power[LWARN] = A2_OFFSET_TO_U16(SFF_A2_TX_PWR_LWARN);
+
+	sd->rx_power[MCURR] = A2_OFFSET_TO_U16(SFF_A2_RX_PWR);
+	sd->rx_power[HALRM] = A2_OFFSET_TO_U16(SFF_A2_RX_PWR_HALRM);
+	sd->rx_power[LALRM] = A2_OFFSET_TO_U16(SFF_A2_RX_PWR_LALRM);
+	sd->rx_power[HWARN] = A2_OFFSET_TO_U16(SFF_A2_RX_PWR_HWARN);
+	sd->rx_power[LWARN] = A2_OFFSET_TO_U16(SFF_A2_RX_PWR_LWARN);
+
+	sd->sfp_temp[MCURR] = A2_OFFSET_TO_TEMP(SFF_A2_TEMP);
+	sd->sfp_temp[HALRM] = A2_OFFSET_TO_TEMP(SFF_A2_TEMP_HALRM);
+	sd->sfp_temp[LALRM] = A2_OFFSET_TO_TEMP(SFF_A2_TEMP_LALRM);
+	sd->sfp_temp[HWARN] = A2_OFFSET_TO_TEMP(SFF_A2_TEMP_HWARN);
+	sd->sfp_temp[LWARN] = A2_OFFSET_TO_TEMP(SFF_A2_TEMP_LWARN);
+}
+
+/* Converts to a float from a big-endian 4-byte source buffer. */
+static float befloattoh(const __u32 *source)
+{
+	union {
+		__u32 src;
+		float dst;
+	} converter;
+
+	converter.src = ntohl(*source);
+	return converter.dst;
+}
+
+static void sff8472_calibration(const __u8 *id, struct sff_diags *sd)
+{
+	int i;
+	__u16 rx_reading;
+
+	/* Calibration should occur for all values (threshold and current) */
+	for (i = 0; i < ARRAY_SIZE(sd->bias_cur); ++i) {
+		/*
+		 * Apply calibration formula 1 (Temp., Voltage, Bias, Tx Power)
+		 */
+		sd->bias_cur[i]    *= A2_OFFSET_TO_SLP(SFF_A2_CAL_TXI_SLP);
+		sd->tx_power[i]    *= A2_OFFSET_TO_SLP(SFF_A2_CAL_TXPWR_SLP);
+		sd->sfp_voltage[i] *= A2_OFFSET_TO_SLP(SFF_A2_CAL_V_SLP);
+		sd->sfp_temp[i]    *= A2_OFFSET_TO_SLP(SFF_A2_CAL_T_SLP);
+
+		sd->bias_cur[i]    += A2_OFFSET_TO_OFF(SFF_A2_CAL_TXI_OFF);
+		sd->tx_power[i]    += A2_OFFSET_TO_OFF(SFF_A2_CAL_TXPWR_OFF);
+		sd->sfp_voltage[i] += A2_OFFSET_TO_OFF(SFF_A2_CAL_V_OFF);
+		sd->sfp_temp[i]    += A2_OFFSET_TO_OFF(SFF_A2_CAL_T_OFF);
+
+		/*
+		 * Apply calibration formula 2 (Rx Power only)
+		 */
+		rx_reading = sd->rx_power[i];
+		sd->rx_power[i]    = A2_OFFSET_TO_RXPWRx(SFF_A2_CAL_RXPWR0);
+		sd->rx_power[i]    += rx_reading *
+			A2_OFFSET_TO_RXPWRx(SFF_A2_CAL_RXPWR1);
+		sd->rx_power[i]    += rx_reading *
+			A2_OFFSET_TO_RXPWRx(SFF_A2_CAL_RXPWR2);
+		sd->rx_power[i]    += rx_reading *
+			A2_OFFSET_TO_RXPWRx(SFF_A2_CAL_RXPWR3);
+	}
+}
+
+static void sff8472_parse_eeprom(const __u8 *id, struct sff_diags *sd)
+{
+	sd->supports_dom = id[SFF_A0_DOM] & SFF_A0_DOM_IMPL;
+	sd->supports_alarms = id[SFF_A0_OPTIONS] & SFF_A0_OPTIONS_AW;
+	sd->calibrated_ext = id[SFF_A0_DOM] & SFF_A0_DOM_EXTCAL;
+	sd->rx_power_type = id[SFF_A0_DOM] & SFF_A0_DOM_PWRT;
+
+	sff8472_dom_parse(id, sd);
+
+	/*
+	 * If the SFP is externally calibrated, we need to read calibration data
+	 * and compensate the already stored readings.
+	 */
+	if (sd->calibrated_ext)
+		sff8472_calibration(id, sd);
+}
+
+void sff8472_show_all(const __u8 *id)
+{
+	struct sff_diags sd = {0};
+	char *rx_power_string = NULL;
+	int i;
+
+	sff8472_parse_eeprom(id, &sd);
+
+	if (!sd.supports_dom) {
+		printf("\t%-41s : No\n", "Optical diagnostics support");
+		return;
+	}
+	printf("\t%-41s : Yes\n", "Optical diagnostics support");
+
+	PRINT_BIAS("Laser bias current", sd.bias_cur[MCURR]);
+	PRINT_xX_PWR("Laser output power", sd.tx_power[MCURR]);
+
+	if (!sd.rx_power_type)
+		rx_power_string = "Receiver signal OMA";
+	else
+		rx_power_string = "Receiver signal average optical power";
+
+	PRINT_xX_PWR(rx_power_string, sd.rx_power[MCURR]);
+
+	PRINT_TEMP("Module temperature", sd.sfp_temp[MCURR]);
+	PRINT_VCC("Module voltage", sd.sfp_voltage[MCURR]);
+
+	printf("\t%-41s : %s\n", "Alarm/warning flags implemented",
+	       (sd.supports_alarms ? "Yes" : "No"));
+	if (sd.supports_alarms) {
+
+		for (i = 0; sff8472_aw_flags[i].str; ++i) {
+			printf("\t%-41s : %s\n", sff8472_aw_flags[i].str,
+			       id[SFF_A2_BASE + sff8472_aw_flags[i].offset]
+			       & sff8472_aw_flags[i].value ? "On" : "Off");
+		}
+		sff_show_thresholds(sd);
+	}
+}
+
diff --git a/sfpid.c b/sfpid.c
new file mode 100644
index 0000000..a1753d3
--- /dev/null
+++ b/sfpid.c
@@ -0,0 +1,356 @@
+/****************************************************************************
+ * Support for Solarflare Solarstorm network controllers and boards
+ * Copyright 2010 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <stdio.h>
+#include "internal.h"
+#include "sff-common.h"
+
+static void sff8079_show_identifier(const __u8 *id)
+{
+	sff8024_show_identifier(id, 0);
+}
+
+static void sff8079_show_ext_identifier(const __u8 *id)
+{
+	printf("\t%-41s : 0x%02x", "Extended identifier", id[1]);
+	if (id[1] == 0x00)
+		printf(" (GBIC not specified / not MOD_DEF compliant)\n");
+	else if (id[1] == 0x04)
+		printf(" (GBIC/SFP defined by 2-wire interface ID)\n");
+	else if (id[1] <= 0x07)
+		printf(" (GBIC compliant with MOD_DEF %u)\n", id[1]);
+	else
+		printf(" (unknown)\n");
+}
+
+static void sff8079_show_connector(const __u8 *id)
+{
+	sff8024_show_connector(id, 2);
+}
+
+static void sff8079_show_transceiver(const __u8 *id)
+{
+	static const char *pfx =
+		"\tTransceiver type                          :";
+
+	printf("\t%-41s : 0x%02x 0x%02x 0x%02x " \
+	       "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+		   "Transceiver codes",
+	       id[3], id[4], id[5], id[6],
+	       id[7], id[8], id[9], id[10], id[36]);
+	/* 10G Ethernet Compliance Codes */
+	if (id[3] & (1 << 7))
+		printf("%s 10G Ethernet: 10G Base-ER" \
+		       " [SFF-8472 rev10.4 only]\n", pfx);
+	if (id[3] & (1 << 6))
+		printf("%s 10G Ethernet: 10G Base-LRM\n", pfx);
+	if (id[3] & (1 << 5))
+		printf("%s 10G Ethernet: 10G Base-LR\n", pfx);
+	if (id[3] & (1 << 4))
+		printf("%s 10G Ethernet: 10G Base-SR\n", pfx);
+	/* Infiniband Compliance Codes */
+	if (id[3] & (1 << 3))
+		printf("%s Infiniband: 1X SX\n", pfx);
+	if (id[3] & (1 << 2))
+		printf("%s Infiniband: 1X LX\n", pfx);
+	if (id[3] & (1 << 1))
+		printf("%s Infiniband: 1X Copper Active\n", pfx);
+	if (id[3] & (1 << 0))
+		printf("%s Infiniband: 1X Copper Passive\n", pfx);
+	/* ESCON Compliance Codes */
+	if (id[4] & (1 << 7))
+		printf("%s ESCON: ESCON MMF, 1310nm LED\n", pfx);
+	if (id[4] & (1 << 6))
+		printf("%s ESCON: ESCON SMF, 1310nm Laser\n", pfx);
+	/* SONET Compliance Codes */
+	if (id[4] & (1 << 5))
+		printf("%s SONET: OC-192, short reach\n", pfx);
+	if (id[4] & (1 << 4))
+		printf("%s SONET: SONET reach specifier bit 1\n", pfx);
+	if (id[4] & (1 << 3))
+		printf("%s SONET: SONET reach specifier bit 2\n", pfx);
+	if (id[4] & (1 << 2))
+		printf("%s SONET: OC-48, long reach\n", pfx);
+	if (id[4] & (1 << 1))
+		printf("%s SONET: OC-48, intermediate reach\n", pfx);
+	if (id[4] & (1 << 0))
+		printf("%s SONET: OC-48, short reach\n", pfx);
+	if (id[5] & (1 << 6))
+		printf("%s SONET: OC-12, single mode, long reach\n", pfx);
+	if (id[5] & (1 << 5))
+		printf("%s SONET: OC-12, single mode, inter. reach\n", pfx);
+	if (id[5] & (1 << 4))
+		printf("%s SONET: OC-12, short reach\n", pfx);
+	if (id[5] & (1 << 2))
+		printf("%s SONET: OC-3, single mode, long reach\n", pfx);
+	if (id[5] & (1 << 1))
+		printf("%s SONET: OC-3, single mode, inter. reach\n", pfx);
+	if (id[5] & (1 << 0))
+		printf("%s SONET: OC-3, short reach\n", pfx);
+	/* Ethernet Compliance Codes */
+	if (id[6] & (1 << 7))
+		printf("%s Ethernet: BASE-PX\n", pfx);
+	if (id[6] & (1 << 6))
+		printf("%s Ethernet: BASE-BX10\n", pfx);
+	if (id[6] & (1 << 5))
+		printf("%s Ethernet: 100BASE-FX\n", pfx);
+	if (id[6] & (1 << 4))
+		printf("%s Ethernet: 100BASE-LX/LX10\n", pfx);
+	if (id[6] & (1 << 3))
+		printf("%s Ethernet: 1000BASE-T\n", pfx);
+	if (id[6] & (1 << 2))
+		printf("%s Ethernet: 1000BASE-CX\n", pfx);
+	if (id[6] & (1 << 1))
+		printf("%s Ethernet: 1000BASE-LX\n", pfx);
+	if (id[6] & (1 << 0))
+		printf("%s Ethernet: 1000BASE-SX\n", pfx);
+	/* Fibre Channel link length */
+	if (id[7] & (1 << 7))
+		printf("%s FC: very long distance (V)\n", pfx);
+	if (id[7] & (1 << 6))
+		printf("%s FC: short distance (S)\n", pfx);
+	if (id[7] & (1 << 5))
+		printf("%s FC: intermediate distance (I)\n", pfx);
+	if (id[7] & (1 << 4))
+		printf("%s FC: long distance (L)\n", pfx);
+	if (id[7] & (1 << 3))
+		printf("%s FC: medium distance (M)\n", pfx);
+	/* Fibre Channel transmitter technology */
+	if (id[7] & (1 << 2))
+		printf("%s FC: Shortwave laser, linear Rx (SA)\n", pfx);
+	if (id[7] & (1 << 1))
+		printf("%s FC: Longwave laser (LC)\n", pfx);
+	if (id[7] & (1 << 0))
+		printf("%s FC: Electrical inter-enclosure (EL)\n", pfx);
+	if (id[8] & (1 << 7))
+		printf("%s FC: Electrical intra-enclosure (EL)\n", pfx);
+	if (id[8] & (1 << 6))
+		printf("%s FC: Shortwave laser w/o OFC (SN)\n", pfx);
+	if (id[8] & (1 << 5))
+		printf("%s FC: Shortwave laser with OFC (SL)\n", pfx);
+	if (id[8] & (1 << 4))
+		printf("%s FC: Longwave laser (LL)\n", pfx);
+	if (id[8] & (1 << 3))
+		printf("%s Active Cable\n", pfx);
+	if (id[8] & (1 << 2))
+		printf("%s Passive Cable\n", pfx);
+	if (id[8] & (1 << 1))
+		printf("%s FC: Copper FC-BaseT\n", pfx);
+	/* Fibre Channel transmission media */
+	if (id[9] & (1 << 7))
+		printf("%s FC: Twin Axial Pair (TW)\n", pfx);
+	if (id[9] & (1 << 6))
+		printf("%s FC: Twisted Pair (TP)\n", pfx);
+	if (id[9] & (1 << 5))
+		printf("%s FC: Miniature Coax (MI)\n", pfx);
+	if (id[9] & (1 << 4))
+		printf("%s FC: Video Coax (TV)\n", pfx);
+	if (id[9] & (1 << 3))
+		printf("%s FC: Multimode, 62.5um (M6)\n", pfx);
+	if (id[9] & (1 << 2))
+		printf("%s FC: Multimode, 50um (M5)\n", pfx);
+	if (id[9] & (1 << 0))
+		printf("%s FC: Single Mode (SM)\n", pfx);
+	/* Fibre Channel speed */
+	if (id[10] & (1 << 7))
+		printf("%s FC: 1200 MBytes/sec\n", pfx);
+	if (id[10] & (1 << 6))
+		printf("%s FC: 800 MBytes/sec\n", pfx);
+	if (id[10] & (1 << 4))
+		printf("%s FC: 400 MBytes/sec\n", pfx);
+	if (id[10] & (1 << 2))
+		printf("%s FC: 200 MBytes/sec\n", pfx);
+	if (id[10] & (1 << 0))
+		printf("%s FC: 100 MBytes/sec\n", pfx);
+	/* Extended Specification Compliance Codes from SFF-8024 */
+	if (id[36] == 0x1)
+		printf("%s Extended: 100G AOC or 25GAUI C2M AOC with worst BER of 5x10^(-5)\n", pfx);
+	if (id[36] == 0x2)
+		printf("%s Extended: 100G Base-SR4 or 25GBase-SR\n", pfx);
+	if (id[36] == 0x3)
+		printf("%s Extended: 100G Base-LR4 or 25GBase-LR\n", pfx);
+	if (id[36] == 0x4)
+		printf("%s Extended: 100G Base-ER4 or 25GBase-ER\n", pfx);
+	if (id[36] == 0x8)
+		printf("%s Extended: 100G ACC or 25GAUI C2M ACC with worst BER of 5x10^(-5)\n", pfx);
+	if (id[36] == 0xb)
+		printf("%s Extended: 100G Base-CR4 or 25G Base-CR CA-L\n", pfx);
+	if (id[36] == 0xc)
+		printf("%s Extended: 25G Base-CR CA-S\n", pfx);
+	if (id[36] == 0xd)
+		printf("%s Extended: 25G Base-CR CA-N\n", pfx);
+	if (id[36] == 0x18)
+		printf("%s Extended: 100G AOC or 25GAUI C2M AOC with worst BER of 10^(-12)\n", pfx);
+	if (id[36] == 0x19)
+		printf("%s Extended: 100G ACC or 25GAUI C2M ACC with worst BER of 10^(-12)\n", pfx);
+}
+
+static void sff8079_show_encoding(const __u8 *id)
+{
+	sff8024_show_encoding(id, 11, ETH_MODULE_SFF_8472);
+}
+
+static void sff8079_show_rate_identifier(const __u8 *id)
+{
+	printf("\t%-41s : 0x%02x", "Rate identifier", id[13]);
+	switch (id[13]) {
+	case 0x00:
+		printf(" (unspecified)\n");
+		break;
+	case 0x01:
+		printf(" (4/2/1G Rate_Select & AS0/AS1)\n");
+		break;
+	case 0x02:
+		printf(" (8/4/2G Rx Rate_Select only)\n");
+		break;
+	case 0x03:
+		printf(" (8/4/2G Independent Rx & Tx Rate_Select)\n");
+		break;
+	case 0x04:
+		printf(" (8/4/2G Tx Rate_Select only)\n");
+		break;
+	default:
+		printf(" (reserved or unknown)\n");
+		break;
+	}
+}
+
+static void sff8079_show_oui(const __u8 *id)
+{
+	printf("\t%-41s : %02x:%02x:%02x\n", "Vendor OUI",
+	       id[37], id[38], id[39]);
+}
+
+static void sff8079_show_wavelength_or_copper_compliance(const __u8 *id)
+{
+	if (id[8] & (1 << 2)) {
+		printf("\t%-41s : 0x%02x", "Passive Cu cmplnce.", id[60]);
+		switch (id[60]) {
+		case 0x00:
+			printf(" (unspecified)");
+			break;
+		case 0x01:
+			printf(" (SFF-8431 appendix E)");
+			break;
+		default:
+			printf(" (unknown)");
+			break;
+		}
+		printf(" [SFF-8472 rev10.4 only]\n");
+	} else if (id[8] & (1 << 3)) {
+		printf("\t%-41s : 0x%02x", "Active Cu cmplnce.", id[60]);
+		switch (id[60]) {
+		case 0x00:
+			printf(" (unspecified)");
+			break;
+		case 0x01:
+			printf(" (SFF-8431 appendix E)");
+			break;
+		case 0x04:
+			printf(" (SFF-8431 limiting)");
+			break;
+		default:
+			printf(" (unknown)");
+			break;
+		}
+		printf(" [SFF-8472 rev10.4 only]\n");
+	} else {
+		printf("\t%-41s : %unm\n", "Laser wavelength",
+		       (id[60] << 8) | id[61]);
+	}
+}
+
+static void sff8079_show_value_with_unit(const __u8 *id, unsigned int reg,
+					 const char *name, unsigned int mult,
+					 const char *unit)
+{
+	unsigned int val = id[reg];
+
+	printf("\t%-41s : %u%s\n", name, val * mult, unit);
+}
+
+static void sff8079_show_ascii(const __u8 *id, unsigned int first_reg,
+			       unsigned int last_reg, const char *name)
+{
+	unsigned int reg, val;
+
+	printf("\t%-41s : ", name);
+	while (first_reg <= last_reg && id[last_reg] == ' ')
+		last_reg--;
+	for (reg = first_reg; reg <= last_reg; reg++) {
+		val = id[reg];
+		putchar(((val >= 32) && (val <= 126)) ? val : '_');
+	}
+	printf("\n");
+}
+
+static void sff8079_show_options(const __u8 *id)
+{
+	static const char *pfx =
+		"\tOption                                    :";
+
+	printf("\t%-41s : 0x%02x 0x%02x\n", "Option values", id[64], id[65]);
+	if (id[65] & (1 << 1))
+		printf("%s RX_LOS implemented\n", pfx);
+	if (id[65] & (1 << 2))
+		printf("%s RX_LOS implemented, inverted\n", pfx);
+	if (id[65] & (1 << 3))
+		printf("%s TX_FAULT implemented\n", pfx);
+	if (id[65] & (1 << 4))
+		printf("%s TX_DISABLE implemented\n", pfx);
+	if (id[65] & (1 << 5))
+		printf("%s RATE_SELECT implemented\n", pfx);
+	if (id[65] & (1 << 6))
+		printf("%s Tunable transmitter technology\n", pfx);
+	if (id[65] & (1 << 7))
+		printf("%s Receiver decision threshold implemented\n", pfx);
+	if (id[64] & (1 << 0))
+		printf("%s Linear receiver output implemented\n", pfx);
+	if (id[64] & (1 << 1))
+		printf("%s Power level 2 requirement\n", pfx);
+	if (id[64] & (1 << 2))
+		printf("%s Cooled transceiver implemented\n", pfx);
+	if (id[64] & (1 << 3))
+		printf("%s Retimer or CDR implemented\n", pfx);
+	if (id[64] & (1 << 4))
+		printf("%s Paging implemented\n", pfx);
+	if (id[64] & (1 << 5))
+		printf("%s Power level 3 requirement\n", pfx);
+}
+
+void sff8079_show_all(const __u8 *id)
+{
+	sff8079_show_identifier(id);
+	if (((id[0] == 0x02) || (id[0] == 0x03)) && (id[1] == 0x04)) {
+		sff8079_show_ext_identifier(id);
+		sff8079_show_connector(id);
+		sff8079_show_transceiver(id);
+		sff8079_show_encoding(id);
+		sff8079_show_value_with_unit(id, 12, "BR, Nominal", 100, "MBd");
+		sff8079_show_rate_identifier(id);
+		sff8079_show_value_with_unit(id, 14,
+					     "Length (SMF,km)", 1, "km");
+		sff8079_show_value_with_unit(id, 15, "Length (SMF)", 100, "m");
+		sff8079_show_value_with_unit(id, 16, "Length (50um)", 10, "m");
+		sff8079_show_value_with_unit(id, 17,
+					     "Length (62.5um)", 10, "m");
+		sff8079_show_value_with_unit(id, 18, "Length (Copper)", 1, "m");
+		sff8079_show_value_with_unit(id, 19, "Length (OM3)", 10, "m");
+		sff8079_show_wavelength_or_copper_compliance(id);
+		sff8079_show_ascii(id, 20, 35, "Vendor name");
+		sff8079_show_oui(id);
+		sff8079_show_ascii(id, 40, 55, "Vendor PN");
+		sff8079_show_ascii(id, 56, 59, "Vendor rev");
+		sff8079_show_options(id);
+		sff8079_show_value_with_unit(id, 66, "BR margin, max", 1, "%");
+		sff8079_show_value_with_unit(id, 67, "BR margin, min", 1, "%");
+		sff8079_show_ascii(id, 68, 83, "Vendor SN");
+		sff8079_show_ascii(id, 84, 91, "Date code");
+	}
+}
diff --git a/shell-completion/bash/ethtool b/shell-completion/bash/ethtool
new file mode 100644
index 0000000..5305559
--- /dev/null
+++ b/shell-completion/bash/ethtool
@@ -0,0 +1,1251 @@
+# bash completion for ethtool(8)                          -*- shell-script -*-
+# shellcheck shell=bash disable=SC2207
+
+# Complete a word representing a set of characters.
+# @param $@ chars	Characters which may be present in completed set.
+_ethtool_compgen_letterset()
+{
+	local char
+	for char; do
+		case "$cur" in
+			*"$char"*)
+				# $cur already contains $char
+				;;
+			*)
+				COMPREPLY+=( "$cur$char" )
+				;;
+		esac
+	done
+}
+
+# Generate completions for words matched case-insensitively
+# @param $@ choices	Completion choices.
+_ethtool_compgen_nocase()
+{
+	local reset
+	reset=$( shopt -p nocasematch )
+	shopt -s nocasematch
+
+	local choice
+	for choice; do
+		case "$choice" in
+			"$cur"*) COMPREPLY+=( "$choice" ) ;;
+		esac
+	done
+
+	$reset
+}
+
+# Gets names from a section of ethtool output.
+# @param $1 section_bre	POSIX BRE matching section heading (without : at end).
+# @param $@		ethtool arguments
+_ethtool_get_names_in_section()
+{
+	local section_bre="$1"
+	shift
+
+	PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" \
+		ethtool "$@" 2>/dev/null |
+		command sed -n "
+# Line is section heading iff it ends with :
+# From requested section heading to next section heading
+/^$section_bre:$/,/:$/ {
+	# If line is section heading, ignore it
+	/:$/d
+	# Remove value and separator, if present
+	s/[[:space:]]*:.*//
+	# Remove leading space, if present
+	s/^[[:space:]]*//
+	# Print the line
+	p
+}"
+}
+
+# Complete an RSS Context ID
+_ethtool_context()
+{
+	COMPREPLY=(
+		$(PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" \
+			ethtool --show-nfc "${words[2]}" 2>/dev/null |
+			command sed -n 's/^[[:space:]]*RSS Context ID:[[:space:]]*\([0-9]*\)$/\1/p' |
+			sort -u) )
+}
+
+# Complete a network flow traffic type
+# Available OPTIONS:
+#	 --hash  Complete only types suitable for rx hashing
+_ethtool_flow_type()
+{
+	local types='ah4 ah6 esp4 esp6 ether sctp4 sctp6 tcp4 tcp6 udp4 udp6'
+	if [ "${1-}" != --hash ]; then
+		types="$types ip4 ip6"
+	fi
+	COMPREPLY=( $( compgen -W "$types" -- "$cur" ) )
+}
+
+# Completion for ethtool --change
+_ethtool_change()
+{
+	local -A settings=(
+		[advertise]=notseen
+		[autoneg]=notseen
+		[duplex]=notseen
+		[mdix]=notseen
+		[msglvl]=notseen
+		[port]=notseen
+		[phyad]=notseen
+		[speed]=notseen
+		[wol]=notseen
+		[xcvr]=notseen
+	)
+
+	local -A msgtypes=(
+		[drv]=notseen
+		[hw]=notseen
+		[ifdown]=notseen
+		[ifup]=notseen
+		[intr]=notseen
+		[link]=notseen
+		[pktdata]=notseen
+		[probe]=notseen
+		[rx_err]=notseen
+		[rx_status]=notseen
+		[timer]=notseen
+		[tx_done]=notseen
+		[tx_err]=notseen
+		[tx_queued]=notseen
+		[wol]=notseen
+	)
+
+	# Mark seen settings and msgtypes, and whether in msglvl sub-command
+	local in_msglvl=
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		if [ "$in_msglvl" ] && [ "${msgtypes[$word]+set}" ]; then
+			msgtypes[$word]=seen
+		elif [ "${settings[$word]+set}" ]; then
+			settings[$word]=seen
+			if [ "$word" = msglvl ]; then
+				in_msglvl=1
+			else
+				in_msglvl=
+			fi
+		fi
+	done
+
+	if [ "$in_msglvl" ] && [ "${msgtypes[$prev]+set}" ]; then
+		# All msgtypes take an on/off argument
+		COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
+		return
+	fi
+
+	case "$prev" in
+		advertise)
+			# Hex number
+			return ;;
+		autoneg)
+			COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
+			return ;;
+		duplex)
+			COMPREPLY=( $( compgen -W 'half full' -- "$cur" ) )
+			return ;;
+		mdix)
+			COMPREPLY=( $( compgen -W 'auto on off' -- "$cur" ) )
+			return ;;
+		msglvl)
+			# Unsigned integer or msgtype
+			COMPREPLY=( $( compgen -W "${!msgtypes[*]}" -- "$cur" ) )
+			return ;;
+		port)
+			COMPREPLY=( $( compgen -W 'aui bnc fibre mii tp' -- "$cur" ) )
+			return ;;
+		phyad)
+			# Integer
+			return ;;
+		sopass)
+			_mac_addresses
+			return ;;
+		speed)
+			# Number
+			return ;;
+		wol)
+			# $cur is a set of wol type characters.
+			_ethtool_compgen_letterset p u m b a g s f d
+			return ;;
+		xcvr)
+			COMPREPLY=( $( compgen -W 'internal external' -- "$cur" ) )
+			return ;;
+	esac
+
+	local -a comp_words=()
+
+	# Add settings not seen to completions
+	local setting
+	for setting in "${!settings[@]}"; do
+		if [ "${settings[$setting]}" = notseen ]; then
+			comp_words+=( "$setting" )
+		fi
+	done
+
+	# Add settings not seen to completions
+	if [ "$in_msglvl" ]; then
+		local msgtype
+		for msgtype in "${!msgtypes[@]}"; do
+			if [ "${msgtypes[$msgtype]}" = notseen ]; then
+				comp_words+=( "$msgtype" )
+			fi
+		done
+	fi
+
+	COMPREPLY=( $( compgen -W "${comp_words[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --change-eeprom
+_ethtool_change_eeprom()
+{
+	local -A settings=(
+		[length]=1
+		[magic]=1
+		[offset]=1
+		[value]=1
+	)
+
+	if [ "${settings[$prev]+set}" ]; then
+		# All settings take an unsigned integer argument
+		return
+	fi
+
+	# Remove settings which have been seen
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		unset "settings[$word]"
+	done
+
+	COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --coalesce
+_ethtool_coalesce()
+{
+	local -A settings=(
+		[adaptive-rx]=1
+		[adaptive-tx]=1
+		[pkt-rate-high]=1
+		[pkt-rate-low]=1
+		[rx-frames]=1
+		[rx-frames-high]=1
+		[rx-frames-irq]=1
+		[rx-frames-low]=1
+		[rx-usecs]=1
+		[rx-usecs-high]=1
+		[rx-usecs-irq]=1
+		[rx-usecs-low]=1
+		[sample-interval]=1
+		[stats-block-usecs]=1
+		[tx-frames]=1
+		[tx-frames-high]=1
+		[tx-frames-irq]=1
+		[tx-frames-low]=1
+		[tx-usecs]=1
+		[tx-usecs-high]=1
+		[tx-usecs-irq]=1
+		[tx-usecs-low]=1
+	)
+
+	case "$prev" in
+		adaptive-rx|\
+		adaptive-tx)
+			COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
+			return ;;
+	esac
+
+	if [ "${settings[$prev]+set}" ]; then
+		# Unsigned integer
+		return
+	fi
+
+	# Remove settings which have been seen
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		unset "settings[$word]"
+	done
+
+	COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --config-nfc <devname> flow-type
+_ethtool_config_nfc_flow_type()
+{
+	if [ "$cword" -eq 4 ]; then
+		_ethtool_flow_type --spec
+		return
+	fi
+
+	case "$prev" in
+		context)
+			_ethtool_context
+			return ;;
+		dst|\
+		dst-mac|\
+		src)
+			# TODO: Complete only local for dst and remote for src
+			_mac_addresses
+			return ;;
+		dst-ip)
+			# Note: RX classification, so dst is usually local
+			case "${words[4]}" in
+				*4) _ip_addresses -4 return ;;
+				*6) _ip_addresses -6 return ;;
+			esac
+			return ;;
+		src-ip)
+			# Note: RX classification, so src is usually remote
+			# TODO: Remote IP addresses (ARP cache + /etc/hosts + ?)
+			return ;;
+		m|\
+		*-mask)
+			# MAC, IP, or integer bitmask
+			return ;;
+	esac
+
+	local -A settings=(
+		[action]=1
+		[context]=1
+		[loc]=1
+		[queue]=1
+		[vf]=1
+	)
+
+	if [ "${settings[$prev]+set}" ]; then
+		# Integer
+		return
+	fi
+
+	case "${words[4]}" in
+		ah4|\
+		esp4)
+			local -A fields=(
+				[dst-ip]=1
+				[dst-mac]=1
+				[spi]=1
+				[src-ip]=1
+				[tos]=1
+				[user-def]=1
+				[vlan-etype]=1
+				[vlan]=1
+			)
+			;;
+		ah6|\
+		esp6)
+			local -A fields=(
+				[dst-ip]=1
+				[dst-mac]=1
+				[spi]=1
+				[src-ip]=1
+				[tclass]=1
+				[user-def]=1
+				[vlan-etype]=1
+				[vlan]=1
+			)
+			;;
+		ether)
+			local -A fields=(
+				[dst]=1
+				[proto]=1
+				[src]=1
+				[user-def]=1
+				[vlan-etype]=1
+				[vlan]=1
+			)
+			;;
+		ip4)
+			local -A fields=(
+				[dst-ip]=1
+				[dst-mac]=1
+				[dst-port]=1
+				[l4data]=1
+				[l4proto]=1
+				[spi]=1
+				[src-ip]=1
+				[src-port]=1
+				[tos]=1
+				[user-def]=1
+				[vlan-etype]=1
+				[vlan]=1
+			)
+			;;
+		ip6)
+			local -A fields=(
+				[dst-ip]=1
+				[dst-mac]=1
+				[dst-port]=1
+				[l4data]=1
+				[l4proto]=1
+				[spi]=1
+				[src-ip]=1
+				[src-port]=1
+				[tclass]=1
+				[user-def]=1
+				[vlan-etype]=1
+				[vlan]=1
+			)
+			;;
+		sctp4|\
+		tcp4|\
+		udp4)
+			local -A fields=(
+				[dst-ip]=1
+				[dst-mac]=1
+				[dst-port]=1
+				[src-ip]=1
+				[src-port]=1
+				[tos]=1
+				[user-def]=1
+				[vlan-etype]=1
+				[vlan]=1
+			)
+			;;
+		sctp6|\
+		tcp6|\
+		udp6)
+			local -A fields=(
+				[dst-ip]=1
+				[dst-mac]=1
+				[dst-port]=1
+				[src-ip]=1
+				[src-port]=1
+				[tclass]=1
+				[user-def]=1
+				[vlan-etype]=1
+				[vlan]=1
+			)
+			;;
+		*)
+			return ;;
+	esac
+
+	if [ "${fields[$prev]+set}" ]; then
+		# Integer
+		return
+	fi
+
+	# If the previous 2 words were a field+value, suggest a mask
+	local mask=
+	if [ "${fields[${words[$cword-2]}]+set}" ]; then
+		mask="m ${words[$cword-2]}-mask"
+	fi
+
+	# Remove fields and settings which have been seen
+	local word
+	for word in "${words[@]:5:${#words[@]}-6}"; do
+		unset "fields[$word]" "settings[$word]"
+	done
+
+	# Remove mutually-exclusive options
+	if ! [ "${settings[action]+set}" ]; then
+		unset 'settings[queue]' 'settings[vf]'
+	fi
+	if ! [ "${settings[queue]+set}" ]; then
+		unset 'settings[action]'
+	fi
+	if ! [ "${settings[vf]+set}" ]; then
+		unset 'settings[action]'
+	fi
+
+	COMPREPLY=( $( compgen -W "$mask ${!fields[*]} ${!settings[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --config-nfc
+_ethtool_config_nfc()
+{
+	if [ "$cword" -eq 3 ]; then
+		COMPREPLY=( $( compgen -W 'delete flow-type rx-flow-hash' -- "$cur" ) )
+		return
+	fi
+
+	case "${words[3]}" in
+		delete)
+			# Unsigned integer
+			return ;;
+		flow-type)
+			_ethtool_config_nfc_flow_type
+			return ;;
+		rx-flow-hash)
+			case "$cword" in
+				4)
+					_ethtool_flow_type --hash
+					return ;;
+				5)
+					_ethtool_compgen_letterset m v t s d f n r
+					return ;;
+				6)
+					COMPREPLY=( $( compgen -W context -- "$cur" ) )
+					return ;;
+				7)
+					_ethtool_context
+					return ;;
+			esac
+			return ;;
+	esac
+}
+
+# Completion for ethtool --eeprom-dump
+_ethtool_eeprom_dump()
+{
+	local -A settings=(
+		[length]=1
+		[offset]=1
+		[raw]=1
+	)
+
+	if [ "$prev" = raw ]; then
+		COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
+		return
+	fi
+
+	if [ "${settings[$prev]+set}" ]; then
+		# Unsigned integer argument
+		return
+	fi
+
+	# Remove settings which have been seen
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		unset "settings[$word]"
+	done
+
+	COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --features
+_ethtool_features()
+{
+	local -A abbreviations=(
+		[generic-receive-offload]=gro
+		[generic-segmentation-offload]=gso
+		[large-receive-offload]=lro
+		[ntuple-filters]=ntuple
+		[receive-hashing]=rxhash
+		[rx-checksumming]=rx
+		[rx-vlan-offload]=rxvlan
+		[scatter-gather]=sg
+		[tcp-segmentation-offload]=tso
+		[tx-checksumming]=tx
+		[tx-vlan-offload]=txvlan
+		[udp-fragmentation-offload]=ufo
+	)
+
+	local -A features=()
+	local feature status fixed
+	# shellcheck disable=SC2034
+	while read -r feature status fixed; do
+		if [ -z "$feature" ]; then
+			# Ignore blank line from empty expansion in here-document
+			continue
+		fi
+
+		if [ "$feature" = Features ]; then
+			# Ignore heading
+			continue
+		fi
+
+		if [ "$fixed" = '[fixed]' ]; then
+			# Fixed features can't be changed
+			continue
+		fi
+
+		feature=${feature%:}
+		if [ "${abbreviations[$feature]+set}" ]; then
+			features[${abbreviations[$feature]}]=1
+		else
+			features[$feature]=1
+		fi
+	done <<ETHTOOL_FEATURES
+$(PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" \
+	ethtool --show-features "${words[2]}" 2>/dev/null)
+ETHTOOL_FEATURES
+
+	if [ "${features[$prev]+set}" ]; then
+		COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
+		return
+	fi
+
+	# Remove features which have been seen
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		unset "features[$word]"
+	done
+
+	COMPREPLY=( $( compgen -W "${!features[*]}" -- "$cur" ) )
+}
+
+# Complete the current word as a kernel firmware file (for request_firmware)
+# See https://www.kernel.org/doc/html/latest/driver-api/firmware/core.html
+_ethtool_firmware()
+{
+	local -a firmware_paths=(
+		/lib/firmware/updates/
+		/lib/firmware/
+	)
+
+	local release
+	if release=$( uname -r 2>/dev/null ); then
+		firmware_paths+=(
+			"/lib/firmware/updates/$release/"
+			"/lib/firmware/$release/"
+		)
+	fi
+
+	local fw_path_para
+	if fw_path_para=$( cat /sys/module/firmware_class/parameters/path 2>/dev/null ) \
+			&& [ -n "$fw_path_para" ]; then
+		firmware_paths+=( "$fw_path_para" )
+	fi
+
+	local -A firmware_files=()
+
+	local firmware_path
+	for firmware_path in "${firmware_paths[@]}"; do
+		local firmware_file
+		for firmware_file in "$firmware_path"*; do
+			if [ -f "$firmware_file" ]; then
+				firmware_files[${firmware_file##*/}]=1
+			fi
+		done
+	done
+
+	local IFS='
+'
+	COMPREPLY=( $( compgen -W "${!firmware_files[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --flash
+_ethtool_flash()
+{
+	if [ "$cword" -eq 3 ]; then
+		_ethtool_firmware
+		return
+	fi
+}
+
+# Completion for ethtool --get-dump
+_ethtool_get_dump()
+{
+	case "$cword" in
+		3)
+			COMPREPLY=( $( compgen -W data -- "$cur" ) )
+			return ;;
+		4)
+			# Output filename
+			local IFS='
+'
+			COMPREPLY=( $( compgen -f -- "$cur" ) )
+			return ;;
+	esac
+}
+
+# Completion for ethtool --get-phy-tunable
+_ethtool_get_phy_tunable()
+{
+	if [ "$cword" -eq 3 ]; then
+		COMPREPLY=( $( compgen -W downshift -- "$cur" ) )
+		return
+	fi
+}
+
+# Completion for ethtool --module-info
+_ethtool_module_info()
+{
+	local -A settings=(
+		[hex]=1
+		[length]=1
+		[offset]=1
+		[raw]=1
+	)
+
+	case "$prev" in
+		hex|\
+		raw)
+			COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
+			return ;;
+	esac
+
+	if [ "${settings[$prev]+set}" ]; then
+		# Unsigned integer argument
+		return
+	fi
+
+	# Remove settings which have been seen
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		unset "settings[$word]"
+	done
+
+	COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --pause
+_ethtool_pause()
+{
+	local -A settings=(
+		[autoneg]=1
+		[rx]=1
+		[tx]=1
+	)
+
+	if [ "${settings[$prev]+set}" ]; then
+		COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
+		return
+	fi
+
+	# Remove settings which have been seen
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		unset "settings[$word]"
+	done
+
+	COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --per-queue
+_ethtool_per_queue()
+{
+	local -a subcommands=(
+		--coalesce
+		--show-coalesce
+	)
+
+	if [ "$cword" -eq 3 ]; then
+		COMPREPLY=( $( compgen -W "queue_mask ${subcommands[*]}" -- "$cur" ) )
+		return
+	fi
+
+	local sc_start=3
+	if [ "${words[3]}" = queue_mask ] ; then
+		case "$cword" in
+			4)
+				# Hex number
+				return ;;
+			5)
+				COMPREPLY=( $( compgen -W "${subcommands[*]}" -- "$cur" ) )
+				return ;;
+		esac
+
+		sc_start=5
+	fi
+
+	case "${words[$sc_start]}" in
+		--coalesce)
+			# Remove --per-queue args to match normal --coalesce invocation
+			local words=(
+				"${words[0]}"
+				--coalesce
+				"${words[2]}"
+				"${words[@]:$sc_start+1:${#words[@]}-$sc_start-1}"
+			)
+			_ethtool_coalesce
+			return ;;
+		--show-coalesce)
+			# No args
+			return ;;
+	esac
+}
+
+# Completion for ethtool --register-dump
+_ethtool_register_dump()
+{
+	local -A settings=(
+		[file]=1
+		[hex]=1
+		[raw]=1
+	)
+
+	case "$prev" in
+		hex|\
+		raw)
+			COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
+			return ;;
+		file)
+			local IFS='
+'
+			COMPREPLY=( $( compgen -f -- "$cur" ) )
+			return ;;
+	esac
+
+	# Remove settings which have been seen
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		unset "settings[$word]"
+	done
+
+	COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --reset
+_ethtool_reset()
+{
+	if [ "$prev" = flags ]; then
+		# Unsigned integer
+		return
+	fi
+
+	local -A flag_names=(
+		[ap]=1
+		[dma]=1
+		[filter]=1
+		[irq]=1
+		[mac]=1
+		[mgmt]=1
+		[offload]=1
+		[phy]=1
+		[ram]=1
+	)
+
+	local -A all_flag_names=()
+	local flag_name
+	for flag_name in "${!flag_names[@]}"; do
+		all_flag_names[$flag_name]=1
+		all_flag_names[$flag_name-shared]=1
+	done
+
+	# Remove all_flag_names which have been seen
+	local any_dedicated=
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		case "$word" in
+			all)
+				# Flags are always additive.
+				# Nothing to add after "all".
+				return ;;
+			dedicated)
+				any_dedicated=1
+				# "dedicated" sets all non-shared flags
+				for flag_name in "${!flag_names[@]}"; do
+					unset "all_flag_names[$flag_name]"
+				done
+				continue ;;
+		esac
+
+		if [ "${flag_names[$word]+set}" ]; then
+			any_dedicated=1
+		fi
+
+		unset "all_flag_names[$word]"
+	done
+
+	COMPREPLY=( $( compgen -W "${!all_flag_names[*]}" -- "$cur" ) )
+
+	# Although it is permitted to mix named and un-named flags or duplicate
+	# flags with "all" or "dedicated", it's not likely intentional.
+	# Reconsider if a real use-case (or good consistency argument) is found.
+	if [ "$cword" -eq 3 ]; then
+		COMPREPLY+=( all dedicated flags )
+	elif [ -z "$any_dedicated" ]; then
+		COMPREPLY+=( dedicated )
+	fi
+}
+
+# Completion for ethtool --rxfh
+_ethtool_rxfh()
+{
+	local -A settings=(
+		[context]=1
+		[default]=1
+		[delete]=1
+		[equal]=1
+		[hfunc]=1
+		[hkey]=1
+		[weight]=1
+	)
+
+	case "$prev" in
+		context)
+			_ethtool_context
+			# "new" to create a new context
+			COMPREPLY+=( new )
+			return ;;
+		equal)
+			# Positive integer
+			return ;;
+		hfunc)
+			# Complete available RSS hash functions
+			COMPREPLY=(
+				$(_ethtool_get_names_in_section 'RSS hash function' \
+					--show-rxfh "${words[2]}")
+			)
+			return ;;
+		hkey)
+			# Pairs of hex digits separated by :
+			return ;;
+		weight)
+			# Non-negative integer
+			return ;;
+	esac
+
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		# Remove settings which have been seen
+		unset "settings[$word]"
+
+		# Remove settings which are mutually-exclusive with seen settings
+		case "$word" in
+			context)
+				unset 'settings[default]'
+				;;
+			default)
+				unset \
+					'settings[context]' \
+					'settings[delete]' \
+					'settings[equal]' \
+					'settings[weight]'
+				;;
+			delete)
+				unset \
+					'settings[default]' \
+					'settings[equal]' \
+					'settings[hkey]' \
+					'settings[weight]'
+				;;
+			equal)
+				unset \
+					'settings[default]' \
+					'settings[delete]' \
+					'settings[weight]'
+				;;
+			hkey)
+				unset 'settings[delete]'
+				;;
+			weight)
+				unset \
+					'settings[default]' \
+					'settings[delete]' \
+					'settings[equal]'
+				;;
+		esac
+	done
+
+
+	COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --set-channels
+_ethtool_set_channels()
+{
+	local -A settings=(
+		[combined]=1
+		[other]=1
+		[rx]=1
+		[tx]=1
+	)
+
+	if [ "${settings[$prev]+set}" ]; then
+		# Unsigned integer argument
+		return
+	fi
+
+	# Remove settings which have been seen
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		unset "settings[$word]"
+	done
+
+	COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --set-eee
+_ethtool_set_eee()
+{
+	local -A settings=(
+		[advertise]=1
+		[eee]=1
+		[tx-lpi]=1
+		[tx-timer]=1
+	)
+
+	case "$prev" in
+		advertise|\
+		tx-timer)
+			# Unsigned integer
+			return ;;
+		eee|\
+		tx-lpi)
+			COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
+			return ;;
+	esac
+
+	# Remove settings which have been seen
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		unset "settings[$word]"
+	done
+
+	COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --set-fec
+_ethtool_set_fec()
+{
+	if [ "$cword" -eq 3 ]; then
+		COMPREPLY=( $( compgen -W encoding -- "$cur" ) )
+		return
+	fi
+
+	local -A modes=(
+		[auto]=auto
+		[rs]=RS
+		[off]=off
+		[baser]=BaseR
+	)
+
+	# Remove modes which have been seen
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		# ethtool recognizes modes case-insensitively
+		unset "modes[${word,,}]"
+	done
+
+	_ethtool_compgen_nocase "${modes[@]}"
+}
+
+# Completion for ethtool --set-phy-tunable
+_ethtool_set_phy_tunable()
+{
+	case "$cword" in
+		3)
+			COMPREPLY=( $( compgen -W downshift -- "$cur" ) )
+			return ;;
+		4)
+			COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
+			return ;;
+		5)
+			COMPREPLY=( $( compgen -W count -- "$cur" ) )
+			return ;;
+	esac
+}
+
+# Completion for ethtool --set-priv-flags
+_ethtool_set_priv_flags()
+{
+	if [ $(( cword % 2 )) -eq 0 ]; then
+		COMPREPLY=( $( compgen -W 'on off' -- "$cur" ) )
+		return
+	fi
+
+	# Get available private flags
+	local -A flags=()
+	local flag
+	while IFS= read -r flag; do
+		# Ignore blank line from empty here-document
+		if [ -n "$flag" ]; then
+			flags[$flag]=1
+		fi
+	done <<ETHTOOL_PRIV_FLAGS
+$(_ethtool_get_names_in_section \
+	'Private flags for [[:graph:]]*' --show-priv-flags "${words[2]}")
+ETHTOOL_PRIV_FLAGS
+
+	# Remove flags which have been seen
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		unset "flags[$word]"
+	done
+
+	COMPREPLY=( $( compgen -W "${!flags[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --set-ring
+_ethtool_set_ring()
+{
+	local -A settings=(
+		[rx-jumbo]=1
+		[rx-mini]=1
+		[rx]=1
+		[tx]=1
+	)
+
+	if [ "${settings[$prev]+set}" ]; then
+		# Unsigned integer argument
+		return
+	fi
+
+	# Remove settings which have been seen
+	local word
+	for word in "${words[@]:3:${#words[@]}-4}"; do
+		unset "settings[$word]"
+	done
+
+	COMPREPLY=( $( compgen -W "${!settings[*]}" -- "$cur" ) )
+}
+
+# Completion for ethtool --show-nfc
+_ethtool_show_nfc()
+{
+	if [ "$cword" -eq 3 ]; then
+		COMPREPLY=( $( compgen -W 'rule rx-flow-hash' -- "$cur" ) )
+		return
+	fi
+
+	case "${words[3]}" in
+		rule)
+			if [ "$cword" -eq 4 ]; then
+				COMPREPLY=(
+					$(PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" \
+						ethtool --show-nfc "${words[2]}" 2>/dev/null |
+						command sed -n 's/^Filter:[[:space:]]*\([0-9]*\)$/\1/p')
+				)
+			fi
+			return ;;
+		rx-flow-hash)
+			case "$cword" in
+				4)
+					_ethtool_flow_type --hash
+					return ;;
+				5)
+					COMPREPLY=( $( compgen -W context -- "$cur" ) )
+					return ;;
+				6)
+					_ethtool_context
+					return ;;
+			esac
+			;;
+	esac
+}
+
+# Completion for ethtool --show-rxfh
+_ethtool_show_rxfh()
+{
+	case "$cword" in
+		3)
+			COMPREPLY=( $( compgen -W context -- "$cur" ) )
+			return ;;
+		4)
+			_ethtool_context
+			return ;;
+	esac
+}
+
+# Completion for ethtool --test
+_ethtool_test()
+{
+	if [ "$cword" -eq 3 ]; then
+		COMPREPLY=( $( compgen -W 'external_lb offline online' -- "$cur" ) )
+		return
+	fi
+}
+
+
+# Complete any ethtool command
+_ethtool()
+{
+	local cur prev words cword
+	_init_completion || return
+
+	# Per "Contributing to bash-completion", complete non-duplicate long opts
+	local -A suggested_funcs=(
+		[--change-eeprom]=change_eeprom
+		[--change]=change
+		[--coalesce]=coalesce
+		[--config-nfc]=config_nfc
+		[--driver]=devname
+		[--dump-module-eeprom]=module_info
+		[--eeprom-dump]=eeprom_dump
+		[--features]=features
+		[--flash]=flash
+		[--get-dump]=get_dump
+		[--get-phy-tunable]=get_phy_tunable
+		[--identify]=devname
+		[--module-info]=module_info
+		[--negotiate]=devname
+		[--offload]=features
+		[--pause]=pause
+		[--per-queue]=per_queue
+		[--phy-statistics]=devname
+		[--register-dump]=register_dump
+		[--reset]=reset
+		[--set-channels]=set_channels
+		[--set-dump]=devname
+		[--set-eee]=set_eee
+		[--set-fec]=set_fec
+		[--set-phy-tunable]=set_phy_tunable
+		[--set-priv-flags]=set_priv_flags
+		[--set-ring]=set_ring
+		[--set-rxfh-indir]=rxfh
+		[--show-channels]=devname
+		[--show-coalesce]=devname
+		[--show-eee]=devname
+		[--show-features]=devname
+		[--show-fec]=devname
+		[--show-nfc]=show_nfc
+		[--show-offload]=devname
+		[--show-pause]=devname
+		[--show-permaddr]=devname
+		[--show-priv-flags]=devname
+		[--show-ring]=devname
+		[--show-rxfh]=show_rxfh
+		[--show-time-stamping]=devname
+		[--statistics]=devname
+		[--test]=test
+	)
+	local -A other_funcs=(
+		[--config-ntuple]=config_nfc
+		[--rxfh]=rxfh
+		[--show-ntuple]=show_nfc
+		[--show-rxfh-indir]=devname
+		[-A]=pause
+		[-C]=coalesce
+		[-E]=change_eeprom
+		[-G]=set_ring
+		[-K]=features
+		[-L]=set_channels
+		[-N]=config_nfc
+		[-P]=devname
+		[-Q]=per_queue
+		[-S]=devname
+		[-T]=devname
+		[-U]=config_nfc
+		[-W]=devname
+		[-X]=rxfh
+		[-a]=devname
+		[-c]=devname
+		[-d]=register_dump
+		[-e]=eeprom_dump
+		[-f]=flash
+		[-g]=devname
+		[-i]=devname
+		[-k]=devname
+		[-l]=devname
+		[-m]=module_info
+		[-n]=show_nfc
+		[-p]=devname
+		[-r]=devname
+		[-s]=change
+		[-t]=test
+		[-u]=show_nfc
+		[-w]=get_dump
+		[-x]=devname
+	)
+
+	if [ "$cword" -le 1 ]; then
+		_available_interfaces
+		COMPREPLY+=(
+			$( compgen -W "--help --version ${!suggested_funcs[*]}" -- "$cur" )
+		)
+		return
+	fi
+
+	local func=${suggested_funcs[${words[1]}]-${other_funcs[${words[1]}]-}}
+	if [ "$func" ]; then
+		# All sub-commands have devname as their first argument
+		if [ "$cword" -eq 2 ]; then
+			_available_interfaces
+			return
+		fi
+
+		if [ "$func" != devname ]; then
+			"_ethtool_$func"
+		fi
+	fi
+} &&
+complete -F _ethtool ethtool
+
+# ex: filetype=sh sts=8 sw=8 ts=8 noet
diff --git a/smsc911x.c b/smsc911x.c
new file mode 100644
index 0000000..bafee21
--- /dev/null
+++ b/smsc911x.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <string.h>
+#include "internal.h"
+
+int smsc911x_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		       struct ethtool_regs *regs)
+{
+	unsigned int *smsc_reg = (unsigned int *)regs->data;
+
+	fprintf(stdout, "LAN911x Registers\n");
+	fprintf(stdout, "offset 0x50, ID_REV       = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x54, INT_CFG      = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x58, INT_STS      = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x5C, INT_EN       = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x60, RESERVED     = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x64, BYTE_TEST    = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x68, FIFO_INT     = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x6C, RX_CFG       = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x70, TX_CFG       = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x74, HW_CFG       = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x78, RX_DP_CTRL   = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x7C, RX_FIFO_INF  = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x80, TX_FIFO_INF  = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x84, PMT_CTRL     = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x88, GPIO_CFG     = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x8C, GPT_CFG      = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x90, GPT_CNT      = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x94, FPGA_REV     = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x98, ENDIAN       = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0x9C, FREE_RUN     = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0xA0, RX_DROP      = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0xA4, MAC_CSR_CMD  = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0xA8, MAC_CSR_DATA = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0xAC, AFC_CFG      = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0xB0, E2P_CMD      = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "offset 0xB4, E2P_DATA     = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "\n");
+
+	fprintf(stdout, "MAC Registers\n");
+	fprintf(stdout, "index 1, MAC_CR   = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "index 2, ADDRH    = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "index 3, ADDRL    = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "index 4, HASHH    = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "index 5, HASHL    = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "index 6, MII_ACC  = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "index 7, MII_DATA = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "index 8, FLOW     = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "index 9, VLAN1    = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "index A, VLAN2    = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "index B, WUFF     = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "index C, WUCSR    = 0x%08X\n",*smsc_reg++);
+	fprintf(stdout, "\n");
+
+	fprintf(stdout, "PHY Registers\n");
+	fprintf(stdout, "index 0, Basic Control Reg = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 1, Basic Status Reg  = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 2, PHY identifier 1  = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 3, PHY identifier 2  = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 4, Auto Negotiation Advertisement Reg = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 5, Auto Negotiation Link Partner Ability Reg = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 6, Auto Negotiation Expansion Register = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 7, Reserved = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 8, Reserved = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 9, Reserved = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 10, Reserved = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 11, Reserved = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 12, Reserved = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 13, Reserved = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 14, Reserved = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 15, Reserved = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 16, Silicon Revision Reg = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 17, Mode Control/Status Reg = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 18, Special Modes = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 19, Reserved = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 20, TSTCNTL = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 21, TSTREAD1 = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 22, TSTREAD2 = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 23, TSTWRITE = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 24, Reserved = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 25, Reserved = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 26, Reserved = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 27, Control/Status Indication = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 28, Special internal testability = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 29, Interrupt Source Register = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 30, Interrupt Mask Register = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "index 31, PHY Special Control/Status Register = 0x%04X\n",*smsc_reg++);
+	fprintf(stdout, "\n");
+
+	return 0;
+}
+
diff --git a/stmmac.c b/stmmac.c
new file mode 100644
index 0000000..98d9058
--- /dev/null
+++ b/stmmac.c
@@ -0,0 +1,71 @@
+/****************************************************************************
+ * Support for the Synopsys MAC 10/100/1000 on-chip Ethernet controllers
+ *
+ * Copyright (C) 2007-2009  STMicroelectronics Ltd
+ *
+ * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "internal.h"
+
+#define MAC100_DMA_REG_NUM	9
+#define GMAC_REG_NUM		55
+#define GMAC_DMA_REG_NUM	23
+
+int st_mac100_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+			struct ethtool_regs *regs)
+{
+	int i;
+	unsigned int *stmmac_reg = (unsigned int *)regs->data;
+
+	fprintf(stdout, "ST MAC 10/100 Registers\n");
+	fprintf(stdout, "control reg  0x%08X\n", *stmmac_reg++);
+	fprintf(stdout, "addr HI 0x%08X\n", *stmmac_reg++);
+	fprintf(stdout, "addr LO 0x%08X\n", *stmmac_reg++);
+	fprintf(stdout, "multicast hash HI 0x%08X\n", *stmmac_reg++);
+	fprintf(stdout, "multicast hash LO 0x%08X\n", *stmmac_reg++);
+	fprintf(stdout, "MII addr 0x%08X\n", *stmmac_reg++);
+	fprintf(stdout, "MII data %08X\n", *stmmac_reg++);
+	fprintf(stdout, "flow control 0x%08X\n", *stmmac_reg++);
+	fprintf(stdout, "VLAN1 tag 0x%08X\n", *stmmac_reg++);
+	fprintf(stdout, "VLAN2 tag 0x%08X\n", *stmmac_reg++);
+	fprintf(stdout, "mac wakeup frame 0x%08X\n", *stmmac_reg++);
+	fprintf(stdout, "mac wakeup crtl 0x%08X\n", *stmmac_reg++);
+
+	fprintf(stdout, "\n");
+	fprintf(stdout, "DMA Registers\n");
+	for (i = 0; i < MAC100_DMA_REG_NUM; i++)
+		fprintf(stdout, "CSR%d  0x%08X\n", i, *stmmac_reg++);
+
+	fprintf(stdout, "DMA cur tx buf addr 0x%08X\n", *stmmac_reg++);
+	fprintf(stdout, "DMA cur rx buf addr 0x%08X\n", *stmmac_reg++);
+
+	fprintf(stdout, "\n");
+
+	return 0;
+}
+
+int st_gmac_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		      struct ethtool_regs *regs)
+{
+	int i;
+	unsigned int *stmmac_reg = (unsigned int *)regs->data;
+
+	fprintf(stdout, "ST GMAC Registers\n");
+	fprintf(stdout, "GMAC Registers\n");
+	for (i = 0; i < GMAC_REG_NUM; i++)
+		fprintf(stdout, "Reg%d  0x%08X\n", i, *stmmac_reg++);
+
+	fprintf(stdout, "\n");
+	fprintf(stdout, "DMA Registers\n");
+	for (i = 0; i < GMAC_DMA_REG_NUM; i++)
+		fprintf(stdout, "Reg%d  0x%08X\n", i, *stmmac_reg++);
+
+	return 0;
+}
diff --git a/test-cmdline.c b/test-cmdline.c
new file mode 100644
index 0000000..b76e2c3
--- /dev/null
+++ b/test-cmdline.c
@@ -0,0 +1,315 @@
+/****************************************************************************
+ * Test cases for ethtool command-line parsing
+ * Copyright 2011 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#define TEST_NO_WRAPPERS
+#include "internal.h"
+
+static struct test_case {
+	int rc;
+	const char *args;
+} test_cases[] = {
+	{ 1, "" },
+	{ 0, "devname" },
+	{ 0, "15_char_devname" },
+	{ 1, "16_char_devname!" },
+	/* Argument parsing for -s is specialised */
+	{ 0, "-s devname" },
+	{ 0, "--change devname speed 100 duplex half mdix auto" },
+	{ 1, "-s devname speed foo" },
+	{ 1, "--change devname speed" },
+	{ 0, "-s devname duplex half" },
+	{ 1, "--change devname duplex foo" },
+	{ 1, "-s devname duplex" },
+	{ 1, "--change devname mdix foo" },
+	{ 1, "-s devname mdix" },
+	{ 0, "--change devname port tp" },
+	{ 1, "-s devname port foo" },
+	{ 1, "--change devname port" },
+	{ 0, "-s devname autoneg on" },
+	{ 1, "--change devname autoneg foo" },
+	{ 1, "-s devname autoneg" },
+	{ 0, "--change devname advertise 0x1" },
+	{ 0, "--change devname advertise 0xf" },
+	{ 0, "--change devname advertise 0Xf" },
+	{ 0, "--change devname advertise 1" },
+	{ 0, "--change devname advertise f" },
+	{ 0, "--change devname advertise 01" },
+	{ 0, "--change devname advertise 0f" },
+	{ 0, "--change devname advertise 0xfffffffffffffffffffffffffffffffff" },
+	{ 0, "--change devname advertise fffffffffffffffffffffffffffffffff" },
+	{ 0, "--change devname advertise 0x0000fffffffffffffffffffffffffffff" },
+	{ 0, "--change devname advertise 0000fffffffffffffffffffffffffffff" },
+	{ 1, "-s devname advertise" },
+	{ 1, "-s devname advertise 0x" },
+	{ 1, "-s devname advertise foo" },
+	{ 1, "-s devname advertise 0xfoo" },
+	{ 1, "--change devname advertise" },
+	{ 0, "-s devname phyad 1" },
+	{ 1, "--change devname phyad foo" },
+	{ 1, "-s devname phyad" },
+	{ 0, "--change devname xcvr external" },
+	{ 1, "-s devname xcvr foo" },
+	{ 1, "--change devname xcvr" },
+	{ 0, "-s devname wol p" },
+	{ 1, "--change devname wol" },
+	{ 0, "-s devname sopass 01:23:45:67:89:ab" },
+	{ 1, "--change devname sopass 01:23:45:67:89:" },
+	{ 1, "-s devname sopass 01:23:45:67:89" },
+	{ 1, "--change devname sopass" },
+	{ 0, "-s devname msglvl 1" },
+	{ 1, "--change devname msglvl" },
+	{ 0, "-s devname msglvl hw on rx_status off" },
+	{ 1, "--change devname msglvl hw foo" },
+	{ 1, "-s devname msglvl hw" },
+	{ 0, "--change devname speed 100 duplex half port tp autoneg on advertise 0x1 phyad 1 xcvr external wol p sopass 01:23:45:67:89:ab msglvl 1" },
+	{ 1, "-s devname foo" },
+	{ 1, "-s" },
+	{ 0, "-a devname" },
+	{ 0, "--show-pause devname" },
+	{ 1, "-a" },
+	/* Many other sub-commands use parse_generic_cmdline() and
+	 * don't need to be check in that much detail. */
+	{ 0, "-A devname autoneg on" },
+	{ 1, "--pause devname autoneg foo" },
+	{ 1, "-A devname autoneg" },
+	{ 0, "--pause devname rx off" },
+	{ 0, "-A devname tx on rx on autoneg off" },
+	{ 1, "--pause devname foo on" },
+	{ 1, "-A" },
+	{ 0, "-c devname" },
+	{ 0, "--show-coalesce devname" },
+	{ 0, "-C devname adaptive-rx on adaptive-tx off rx-usecs 1 rx-frames 2 rx-usecs-irq 3 rx-frames-irq 4 tx-usecs 5 tx-frames 6 tx-usecs-irq 7 tx-frames-irq 8 stats-block-usecs 9 pkt-rate-low 10" },
+	{ 0, "--coalesce devname rx-usecs-low 11 rx-frames-low 12 tx-usecs-low 13 tx-frames-low 14 pkt-rate-high 15 rx-usecs-high 16 rx-frames-high 17 tx-usecs-high 18 tx-frames-high 19 sample-interval 20" },
+	{ 1, "-C devname adaptive-rx foo" },
+	{ 1, "--coalesce devname adaptive-rx" },
+	{ 1, "-C devname foo on" },
+	{ 1, "-C" },
+	{ 0, "-g devname" },
+	{ 0, "--show-ring devname" },
+	{ 1, "-g" },
+	{ 0, "-G devname rx 1 rx-mini 2 rx-jumbo 3 tx 4" },
+	{ 0, "--set-ring devname rx 1 rx-mini 2 rx-jumbo 3 tx 4" },
+	{ 1, "-G devname rx foo" },
+	{ 1, "--set-ring devname rx" },
+	{ 1, "-G devname foo 1" },
+	{ 1, "-G" },
+	{ 1, "-k" },
+	{ 1, "-K" },
+	{ 0, "-i devname" },
+	{ 0, "--driver devname" },
+	{ 1, "-i" },
+	{ 0, "-d devname" },
+	{ 0, "--register-dump devname raw on file foo" },
+	{ 1, "-d devname raw foo" },
+	{ 1, "--register-dump devname file" },
+	{ 1, "-d devname foo" },
+	{ 1, "-d" },
+	{ 0, "-e devname" },
+	{ 0, "--eeprom-dump devname raw on offset 1 length 2" },
+	{ 1, "-e devname raw foo" },
+	{ 1, "--eeprom-dump devname offset foo" },
+	{ 1, "-e devname length" },
+	{ 1, "--eeprom-dump devname foo" },
+	{ 1, "-e" },
+	{ 0, "-E devname" },
+	{ 0, "--change-eeprom devname magic 0x87654321 offset 0 value 1" },
+	{ 0, "-E devname magic 0x87654321 offset 0 length 2" },
+	{ 1, "-E" },
+	{ 0, "-r devname" },
+	{ 0, "--negotiate devname" },
+	{ 1, "-r" },
+	{ 0, "-p devname" },
+	{ 0, "--identify devname 1" },
+	{ 1, "-p devname 1 foo" },
+	{ 1, "--identify devname foo" },
+	{ 1, "-p" },
+	/* Argument parsing for -t is specialised */
+	{ 0, "-t devname" },
+	{ 0, "--test devname online" },
+	{ 1, "-t devname foo" },
+	{ 1, "--test devname online foo" },
+	{ 0, "-S devname" },
+	{ 0, "--statistics devname" },
+	{ 1, "-S" },
+	/* Argument parsing for -n/-u is specialised */
+	{ 0, "-n devname rx-flow-hash tcp4" },
+	{ 0, "-u devname rx-flow-hash sctp4" },
+	{ 0, "--show-nfc devname rx-flow-hash udp6" },
+	{ 0, "--show-ntuple devname rx-flow-hash esp6" },
+	{ 1, "-n devname rx-flow-hash foo" },
+	{ 1, "-u devname rx-flow-hash foo" },
+	{ 1, "--show-nfc devname rx-flow-hash" },
+	{ 1, "--show-ntuple devname rx-flow-hash" },
+	{ 1, "-n" },
+	/* Argument parsing for -f is specialised */
+	{ 1, "-f devname" },
+	{ 0, "--flash devname filename" },
+	{ 0, "-f devname filename 1" },
+	{ 1, "-f devname filename 1 foo" },
+	{ 1, "-f" },
+	/* Argument parsing for -N/-U is specialised */
+	{ 0, "-N devname rx-flow-hash tcp4 mvtsdfn" },
+	{ 0, "--config-ntuple devname rx-flow-hash tcp4 r" },
+	{ 1, "-U devname rx-flow-hash tcp4" },
+	{ 1, "--config-nfc devname rx-flow-hash foo" },
+	{ 1, "-N devname rx-flow-hash" },
+	{ 1, "--config-ntuple devname foo" },
+	{ 0, "-U devname delete 1" },
+	{ 1, "--config-nfc devname delete foo" },
+	{ 1, "-N devname delete" },
+	{ 0, "--config-ntuple devname flow-type ether src 01:23:45:67:89:ab m cd:ef:01:23:45:67 dst 89:ab:cd:ef:01:23 m 45:67:89:ab:cd:ef proto 0x0123 m 0x4567 vlan 0x89ab m 0xcdef action 0" },
+	{ 0, "-U devname flow-type ether src 01:23:45:67:89:ab src-mask cd:ef:01:23:45:67 dst 89:ab:cd:ef:01:23 dst-mask 45:67:89:ab:cd:ef proto 0x0123 proto-mask 0x4567 vlan 0x89ab vlan-mask 0xcdef action 1" },
+	{ 1, "--config-nfc devname flow-type ether src 01:23:45:67:89: action 3" },
+	{ 1, "-N devname flow-type ether src 01:23:45:67:89 action 4" },
+	{ 0, "--config-ntuple devname flow-type ip4 src-ip 0.123.45.67 m 89.0.123.45 dst-ip 67.89.0.123 m 45.67.89.0 tos 1 m 1 l4proto 0x23 m 0x45 l4data 0xfedcba98 m 76543210 vlan 0x89ab m 0xcdef action 6" },
+	{ 0, "-U devname flow-type ip4 src-ip 0.123.45.67 src-ip-mask 89.0.123.45 dst-ip 67.89.0.123 dst-ip-mask 45.67.89.0 tos 1 tos-mask 1 l4proto 0x23 l4proto-mask 0x45 l4data 0xfedcba98 l4data-mask 76543210 vlan 0x89ab vlan-mask 0xcdef action 7" },
+	{ 0, "--config-nfc devname flow-type tcp4 src-ip 0.123.45.67 m 89.0.123.45 dst-ip 67.89.0.123 m 45.67.89.0 tos 1 m 1 src-port 23456 m 7890 dst-port 12345 m 6789 vlan 0x89ab m 0xcdef action 8" },
+	{ 0, "-N devname flow-type tcp4 src-ip 0.123.45.67 src-ip-mask 89.0.123.45 dst-ip 67.89.0.123 dst-ip-mask 45.67.89.0 tos 1 tos-mask 1 src-port 23456 src-port-mask 7890 dst-port 12345 dst-port-mask 6789 vlan 0x89ab vlan-mask 0xcdef action 9" },
+	{ 0, "--config-ntuple devname flow-type ah4 src-ip 0.123.45.67 m 89.0.123.45 dst-ip 67.89.0.123 m 45.67.89.0 tos 1 m 1 spi 2 m 3 vlan 0x89ab m 0xcdef action 10" },
+	{ 0, "-U devname flow-type ah4 src-ip 0.123.45.67 src-ip-mask 89.0.123.45 dst-ip 67.89.0.123 dst-ip-mask 45.67.89.0 tos 1 tos-mask 1 spi 2 spi-mask 3 vlan 0x89ab vlan-mask 0xcdef action 11" },
+	{ 1, "--config-nfc devname flow-type tcp4 action foo" },
+	{ 1, "-N devname flow-type foo" },
+	{ 1, "--config-ntuple devname flow-type" },
+	{ 1, "-U devname foo" },
+	{ 1, "-N" },
+	{ 1, "-U" },
+	{ 0, "-T devname" },
+	{ 0, "--show-time-stamping devname" },
+	{ 1, "-T" },
+	{ 0, "-x devname" },
+	{ 0, "--show-rxfh-indir devname" },
+	{ 0, "--show-rxfh devname" },
+	{ 1, "-x" },
+	/* Argument parsing for -X is specialised */
+	{ 0, "-X devname equal 2" },
+	{ 0, "--set-rxfh-indir devname equal 256" },
+	{ 1, "-X devname equal 0" },
+	{ 1, "--set-rxfh-indir devname equal foo" },
+	{ 1, "-X devname equal" },
+	{ 1, "-X devname start" },
+	{ 1, "-X devname start 3" },
+	{ 0, "-X devname start 4 equal 2" },
+	{ 0, "--set-rxfh-indir devname weight 1 2 3 4" },
+	{ 0, "--set-rxfh-indir devname start 4 weight 1 2 3 4" },
+	{ 0, "--rxfh devname hkey 48:15:6e:bb:d8:bd:6f:b1:a4:c6:7a:c4:76:1c:29:98:da:e1:ae:6c:2e:12:2f:c0:b9:be:61:3d:00:54:35:9e:09:05:c7:d7:93:72:4a:ee" },
+	{ 0, "-X devname hkey 48:15:6e:bb:d8:bd:6f:b1:a4:c6:7a:c4:76:1c:29:98:da:e1:ae:6c:2e:12:2f:c0:b9:be:61:3d:00:54:35:9e:09:05:c7:d7:93:72:4a:ee" },
+#if 0
+	/* XXX These won't fail as expected because we don't parse the
+	 * hash key until after the first send_ioctl().  That needs to
+	 * be changed before we enable them.
+	 */
+	{ 1, "--rxfh devname hkey foo" },
+	{ 1, "-X devname hkey foo" },
+#endif
+	{ 0, "--rxfh devname hkey 48:15:6e:bb:d8:bd:6f:b1:a4:c6:7a:c4:76:1c:29:98:da:e1:ae:6c:2e:12:2f:c0:b9:be:61:3d:00:54:35:9e:09:05:c7:d7:93:72:4a:ee weight 1 2 3 4" },
+	{ 0, "-X devname weight 1 2 3 4 hkey 48:15:6e:bb:d8:bd:6f:b1:a4:c6:7a:c4:76:1c:29:98:da:e1:ae:6c:2e:12:2f:c0:b9:be:61:3d:00:54:35:9e:09:05:c7:d7:93:72:4a:ee" },
+	{ 0, "--rxfh devname hkey 48:15:6e:bb:d8:bd:6f:b1:a4:c6:7a:c4:76:1c:29:98:da:e1:ae:6c:2e:12:2f:c0:b9:be:61:3d:00:54:35:9e:09:05:c7:d7:93:72:4a:ee equal 2" },
+	{ 0, "-X devname equal 2 hkey 48:15:6e:bb:d8:bd:6f:b1:a4:c6:7a:c4:76:1c:29:98:da:e1:ae:6c:2e:12:2f:c0:b9:be:61:3d:00:54:35:9e:09:05:c7:d7:93:72:4a:ee" },
+	{ 1, "--rxfh devname weight 1 2 3 4 equal 8" },
+	{ 1, "-X devname weight 1 2 3 4 equal 8" },
+	{ 1, "-X devname foo" },
+	{ 1, "-X" },
+	{ 0, "-P devname" },
+	{ 0, "--show-permaddr devname" },
+	{ 1, "-P" },
+	{ 0, "-w devname" },
+	{ 0, "--get-dump devname data filename" },
+	{ 0, "-w devname data filename" },
+	{ 1, "--get-dump devname data" },
+	{ 1, "-w devname foo" },
+	{ 1, "-w" },
+	{ 0, "-W devname 1" },
+	{ 0, "--set-dump devname 2" },
+	{ 1, "-W devname 1 foo" },
+	{ 1, "-W devname foo" },
+	{ 1, "-W" },
+	{ 0, "-l devname" },
+	{ 0, "--show-channels devname" },
+	{ 1, "-l" },
+	{ 0, "-L devname rx 1 tx 2 other 3 combined 4" },
+	{ 0, "--set-channels devname rx 1 tx 2 other 3 combined 4" },
+	{ 1, "-L devname rx foo" },
+	{ 1, "--set-channels devname rx" },
+	{ 0, "-L devname" },
+	{ 1, "-L" },
+	{ 0, "--show-priv-flags devname" },
+	{ 1, "--show-priv-flags devname foo" },
+	{ 1, "--show-priv-flags" },
+	{ 1, "-m" },
+	{ 0, "-m devname" },
+	{ 1, "--dump-module-eeprom" },
+	{ 0, "--dump-module-eeprom devname" },
+	{ 1, "--module-info" },
+	{ 0, "--module-info devname" },
+	{ 0, "-m devname raw on" },
+	{ 0, "-m devname raw off" },
+	{ 0, "-m devname hex on" },
+	{ 0, "-m devname hex off" },
+	{ 1, "-m devname hex on raw on" },
+	{ 0, "-m devname offset 4 length 6" },
+	{ 1, "--show-eee" },
+	{ 0, "--show-eee devname" },
+	{ 1, "--show-eee devname foo" },
+	{ 1, "--set-eee" },
+	{ 1, "--set-eee devname" },
+	{ 1, "--set-eee devname foo" },
+	{ 0, "--set-eee devname eee on" },
+	{ 0, "--set-eee devname eee off" },
+	{ 1, "--set-eee devname eee foo" },
+	{ 0, "--set-eee devname tx-lpi on" },
+	{ 0, "--set-eee devname tx-lpi off" },
+	{ 1, "--set-eee devname tx-lpi foo" },
+	{ 0, "--set-eee devname tx-timer 42 advertise 0x4321" },
+	{ 1, "--set-eee devname tx-timer foo" },
+	{ 1, "--set-eee devname advertise foo" },
+	{ 1, "--set-fec devname" },
+	{ 0, "--set-fec devname encoding auto" },
+	{ 0, "--set-fec devname encoding off" },
+	{ 0, "--set-fec devname encoding baser rs" },
+	{ 0, "--set-fec devname encoding auto auto" },
+	{ 1, "--set-fec devname encoding foo" },
+	{ 1, "--set-fec devname encoding auto foo" },
+	{ 1, "--set-fec devname encoding none" },
+	{ 1, "--set-fec devname auto" },
+	/* can't test --set-priv-flags yet */
+	{ 0, "-h" },
+	{ 0, "--help" },
+	{ 0, "--version" },
+	{ 1, "--foo" },
+	{ 1, "-foo" },
+	{ 1, "-0" },
+};
+
+int send_ioctl(struct cmd_context *ctx, void *cmd)
+{
+	/* If we get this far then parsing succeeded */
+	test_exit(0);
+}
+
+int main(void)
+{
+	struct test_case *tc;
+	int test_rc;
+	int rc = 0;
+
+	for (tc = test_cases; tc < test_cases + ARRAY_SIZE(test_cases); tc++) {
+		if (getenv("ETHTOOL_TEST_VERBOSE"))
+			printf("I: Test command line: ethtool %s\n", tc->args);
+		test_rc = test_cmdline(tc->args);
+		if (test_rc != tc->rc) {
+			fprintf(stderr, "E: ethtool %s returns %d\n",
+				tc->args, test_rc);
+			rc = 1;
+		}
+	}
+
+	return rc;
+}
diff --git a/test-common.c b/test-common.c
new file mode 100644
index 0000000..cd63d1d
--- /dev/null
+++ b/test-common.c
@@ -0,0 +1,383 @@
+/****************************************************************************
+ * Common test functions for ethtool
+ * Copyright 2011 Solarflare Communications Inc.
+ *
+ * Partly derived from kernel <linux/list.h>.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <unistd.h>
+#define TEST_NO_WRAPPERS
+#include "internal.h"
+
+/* List utilities */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+static void init_list_head(struct list_head *list)
+{
+	list->next = list;
+	list->prev = list;
+}
+
+static void list_add(struct list_head *new, struct list_head *head)
+{
+	head->next->prev = new;
+	new->next = head->next;
+	new->prev = head;
+	head->next = new;
+}
+
+static void list_del(struct list_head *entry)
+{
+	entry->next->prev = entry->prev;
+	entry->prev->next = entry->next;
+	entry->next = NULL;
+	entry->prev = NULL;
+}
+
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/* Free memory at end of test */
+
+static struct list_head malloc_list = LIST_HEAD_INIT(malloc_list);
+
+void *test_malloc(size_t size)
+{
+	struct list_head *block = malloc(sizeof(*block) + size);
+
+	if (!block)
+		return NULL;
+	list_add(block, &malloc_list);
+	return block + 1;
+}
+
+void *test_calloc(size_t nmemb, size_t size)
+{
+	void *ptr = test_malloc(nmemb * size);
+
+	if (ptr)
+		memset(ptr, 0, nmemb * size);
+	return ptr;
+}
+
+char *test_strdup(const char *s)
+{
+	size_t size = strlen(s) + 1;
+	char *dup = test_malloc(size);
+
+	if (dup)
+		memcpy(dup, s, size);
+	return dup;
+}
+
+void test_free(void *ptr)
+{
+	struct list_head *block;
+
+	if (!ptr)
+		return;
+	block = (struct list_head *)ptr - 1;
+	list_del(block);
+	free(block);
+}
+
+void *test_realloc(void *ptr, size_t size)
+{
+	struct list_head *block = NULL;
+
+	if (ptr) {
+		block = (struct list_head *)ptr - 1;
+		list_del(block);
+	}
+	block = realloc(block, sizeof(*block) + size);
+	if (!block)
+		return NULL;
+	list_add(block, &malloc_list);
+	return block + 1;
+}
+
+static void test_free_all(void)
+{
+	struct list_head *block, *next;
+
+	list_for_each_safe(block, next, &malloc_list)
+		free(block);
+	init_list_head(&malloc_list);
+}
+
+/* Close files at end of test */
+
+struct file_node {
+	struct list_head link;
+	FILE *fh;
+	int fd;
+};
+
+static struct list_head file_list = LIST_HEAD_INIT(file_list);
+
+int test_open(const char *pathname, int flag, ...)
+{
+	struct file_node *node;
+	mode_t mode;
+
+	if (flag & O_CREAT) {
+		va_list ap;
+		va_start(ap, flag);
+		mode = va_arg(ap, mode_t);
+		va_end(ap);
+	} else {
+		mode = 0;
+	}
+
+	node = malloc(sizeof(*node));
+	if (!node)
+		return -1;
+
+	node->fd = open(pathname, flag, mode);
+	if (node->fd < 0) {
+		free(node);
+		return -1;
+	}
+
+	node->fh = NULL;
+	list_add(&node->link, &file_list);
+	return node->fd;
+}
+
+int test_socket(int domain, int type, int protocol)
+{
+	struct file_node *node;
+
+	node = malloc(sizeof(*node));
+	if (!node)
+		return -1;
+
+	node->fd = socket(domain, type, protocol);
+	if (node->fd < 0) {
+		free(node);
+		return -1;
+	}
+
+	node->fh = NULL;
+	list_add(&node->link, &file_list);
+	return node->fd;
+}
+
+int test_close(int fd)
+{
+	struct list_head *head, *next;
+
+	if (fd >= 0) {
+		list_for_each_safe(head, next, &file_list) {
+			if (((struct file_node *)head)->fd == fd) {
+				list_del(head);
+				free(head);
+				break;
+			}
+		}
+	}
+
+	return close(fd);
+}
+
+FILE *test_fopen(const char *path, const char *mode)
+{
+	struct file_node *node;
+
+	node = malloc(sizeof(*node));
+	if (!node)
+		return NULL;
+
+	node->fh = fopen(path, mode);
+	if (!node->fh) {
+		free(node);
+		return NULL;
+	}
+
+	node->fd = -1;
+	list_add(&node->link, &file_list);
+	return node->fh;	
+}
+
+int test_fclose(FILE *fh)
+{
+	struct list_head *head, *next;
+
+	assert(fh);
+
+	list_for_each_safe(head, next, &file_list) {
+		if (((struct file_node *)head)->fh == fh) {
+			list_del(head);
+			free(head);
+			break;
+		}
+	}
+
+	return fclose(fh);
+}
+
+static void test_close_all(void)
+{
+	struct list_head *head, *next;
+	struct file_node *node;
+
+	list_for_each_safe(head, next, &file_list) {
+		node = (struct file_node *)head;
+		if (node->fh)
+			fclose(node->fh);
+		else
+			close(node->fd);
+		free(node);
+	}
+	init_list_head(&file_list);
+}
+
+/* Wrap test main function */
+
+static jmp_buf test_return;
+static FILE *orig_stderr;
+
+void test_exit(int rc)
+{
+	longjmp(test_return, rc + 1);
+}
+
+int test_ioctl(const struct cmd_expect *expect, void *cmd)
+{
+	int rc;
+
+	if (!expect->cmd || *(u32 *)cmd != *(const u32 *)expect->cmd) {
+		/* We have no idea how long this command structure is */
+		fprintf(orig_stderr, "Unexpected ioctl: cmd=%#10x\n",
+			*(u32 *)cmd);
+		return TEST_IOCTL_MISMATCH;
+	}
+
+	if (memcmp(cmd, expect->cmd, expect->cmd_len)) {
+		fprintf(orig_stderr, "Expected ioctl structure:\n");
+		dump_hex(orig_stderr, expect->cmd, expect->cmd_len, 0);
+		fprintf(orig_stderr, "Actual ioctl structure:\n");
+		dump_hex(orig_stderr, cmd, expect->cmd_len, 0);
+		return TEST_IOCTL_MISMATCH;
+	}
+
+	if (expect->resp)
+		memcpy(cmd, expect->resp, expect->resp_len);
+	rc = expect->rc;
+
+	/* Convert kernel return code according to libc convention */
+	if (rc >= 0) {
+		return rc;
+	} else {
+		errno = -rc;
+		return -1;
+	}
+}
+
+int test_cmdline(const char *args)
+{
+	int argc, i;
+	char **argv;
+	const char *arg;
+	size_t len;
+	int dev_null = -1, orig_stdout_fd = -1, orig_stderr_fd = -1;
+	int rc;
+
+	/* Convert line to argv */
+	argc = 1;
+	arg = args;
+	for (;;) {
+		len = strcspn(arg, " ");
+		if (len == 0)
+			break;
+		argc++;
+		if (arg[len] == 0)
+			break;
+		arg += len + 1;
+	}
+	argv = test_calloc(argc + 1, sizeof(argv[0]));
+	argv[0] = test_strdup("ethtool");
+	arg = args;
+	for (i = 1; i < argc; i++) {
+		len = strcspn(arg, " ");
+		argv[i] = test_malloc(len + 1);
+		memcpy(argv[i], arg, len);
+		argv[i][len] = 0;
+		arg += len + 1;
+	}
+
+	dev_null = open("/dev/null", O_RDWR);
+	if (dev_null < 0) {
+		perror("open /dev/null");
+		rc = -1;
+		goto out;
+	}
+
+	fflush(NULL);
+	dup2(dev_null, STDIN_FILENO);
+	if (getenv("TEST_TEST_VERBOSE")) {
+		orig_stderr = stderr;
+	} else {
+		orig_stdout_fd = dup(STDOUT_FILENO);
+		if (orig_stdout_fd < 0) {
+			perror("dup stdout");
+			rc = -1;
+			goto out;
+		}
+		dup2(dev_null, STDOUT_FILENO);
+		orig_stderr_fd = dup(STDERR_FILENO);
+		if (orig_stderr_fd < 0) {
+			perror("dup stderr");
+			rc = -1;
+			goto out;
+		}
+		orig_stderr = fdopen(orig_stderr_fd, "w");
+		if (orig_stderr == NULL) {
+			perror("fdopen orig_stderr_fd");
+			rc = -1;
+			goto out;
+		}
+		dup2(dev_null, STDERR_FILENO);
+	}
+
+	rc = setjmp(test_return);
+	rc = rc ? rc - 1 : test_main(argc, argv);
+
+out:
+	fflush(NULL);
+	if (orig_stderr_fd >= 0) {
+		dup2(orig_stderr_fd, STDERR_FILENO);
+		if (orig_stderr)
+			fclose(orig_stderr);
+		else
+			close(orig_stderr_fd);
+	}
+	orig_stderr = NULL;
+	if (orig_stdout_fd >= 0) {
+		dup2(orig_stdout_fd, STDOUT_FILENO);
+		close(orig_stdout_fd);
+	}
+	if (dev_null >= 0)
+		close(dev_null);
+
+	test_free_all();
+	test_close_all();
+	return rc;
+}
diff --git a/test-features.c b/test-features.c
new file mode 100644
index 0000000..6ebb364
--- /dev/null
+++ b/test-features.c
@@ -0,0 +1,544 @@
+/****************************************************************************
+ * Test cases for ethtool features
+ * Copyright 2012 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define TEST_NO_WRAPPERS
+#include "internal.h"
+
+static const struct {
+	struct ethtool_sset_info cmd;
+	u32 data[1];
+}
+cmd_gssetinfo = { { ETHTOOL_GSSET_INFO, 0, 1ULL << ETH_SS_FEATURES }, { 34 } };
+
+static const struct ethtool_value
+cmd_grxcsum_off = { ETHTOOL_GRXCSUM, 0 },
+cmd_grxcsum_on = { ETHTOOL_GRXCSUM, 1 },
+cmd_srxcsum_off = { ETHTOOL_SRXCSUM, 0 },
+cmd_srxcsum_on = { ETHTOOL_SRXCSUM, 1 },
+cmd_gtxcsum_off = { ETHTOOL_GTXCSUM, 0 },
+cmd_gtxcsum_on = { ETHTOOL_GTXCSUM, 1 },
+cmd_stxcsum_off = { ETHTOOL_STXCSUM, 0 },
+cmd_stxcsum_on = { ETHTOOL_STXCSUM, 1 },
+cmd_gsg_off = { ETHTOOL_GSG, 0 },
+cmd_gsg_on = { ETHTOOL_GSG, 1 },
+cmd_ssg_off = { ETHTOOL_SSG, 0 },
+cmd_ssg_on = { ETHTOOL_SSG, 1 },
+cmd_gtso_off = { ETHTOOL_GTSO, 0 },
+cmd_gtso_on = { ETHTOOL_GTSO, 1 },
+cmd_stso_off = { ETHTOOL_STSO, 0 },
+cmd_stso_on = { ETHTOOL_STSO, 1 },
+cmd_gufo_off = { ETHTOOL_GUFO, 0 },
+cmd_gufo_on = { ETHTOOL_GUFO, 1 },
+cmd_sufo_off = { ETHTOOL_SUFO, 0 },
+cmd_sufo_on = { ETHTOOL_SUFO, 1 },
+cmd_ggso_off = { ETHTOOL_GGSO, 0 },
+cmd_ggso_on = { ETHTOOL_GGSO, 1 },
+cmd_sgso_off = { ETHTOOL_SGSO, 0 },
+cmd_sgso_on = { ETHTOOL_SGSO, 1 },
+cmd_ggro_off = { ETHTOOL_GGRO, 0 },
+cmd_ggro_on = { ETHTOOL_GGRO, 1 },
+cmd_sgro_off = { ETHTOOL_SGRO, 0 },
+cmd_sgro_on = { ETHTOOL_SGRO, 1 },
+cmd_gflags_off = { ETHTOOL_GFLAGS, 0 },
+cmd_gflags_on = { ETHTOOL_GFLAGS,
+		  ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
+		  ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH },
+cmd_sflags_off = { ETHTOOL_SFLAGS, 0 },
+cmd_sflags_ntuple = { ETHTOOL_GFLAGS, ETH_FLAG_NTUPLE },
+cmd_sflags_on = { ETHTOOL_SFLAGS,
+		  ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
+		  ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH },
+cmd_sflags_not_rxhash = { ETHTOOL_SFLAGS,
+			  ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
+			  ETH_FLAG_NTUPLE };
+
+static const struct cmd_expect cmd_expect_get_strings_old[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_get_features_off_old[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_get_features_off_old_some_unsup[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, -EOPNOTSUPP },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4, -EOPNOTSUPP },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_get_features_off_old_some_priv[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EPERM },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4, -EPERM },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_off_old[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
+	{ &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
+	{ &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
+	{ &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
+	{ &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
+	{ &cmd_gufo_on, 4, 0, &cmd_gufo_on, sizeof(cmd_gufo_on) },
+	{ &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
+	{ &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
+	{ &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
+	{ &cmd_srxcsum_off, sizeof(cmd_srxcsum_off), 0, 0, 0 },
+	{ &cmd_stxcsum_off, sizeof(cmd_stxcsum_off), 0, 0, 0 },
+	{ &cmd_ssg_off, sizeof(cmd_ssg_off), 0, 0, 0 },
+	{ &cmd_stso_off, sizeof(cmd_stso_off), 0, 0, 0 },
+	{ &cmd_sufo_off, sizeof(cmd_sufo_off), 0, 0, 0 },
+	{ &cmd_sgso_off, sizeof(cmd_sgso_off), 0, 0, 0 },
+	{ &cmd_sgro_off, sizeof(cmd_sgro_off), 0, 0, 0 },
+	{ &cmd_sflags_off, sizeof(cmd_sflags_off), 0, 0, 0 },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_sflags_off) },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_on_old[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ &cmd_srxcsum_on, sizeof(cmd_srxcsum_on), 0, 0, 0 },
+	{ &cmd_stxcsum_on, sizeof(cmd_stxcsum_on), 0, 0, 0 },
+	{ &cmd_ssg_on, sizeof(cmd_ssg_on), 0, 0, 0 },
+	{ &cmd_stso_on, sizeof(cmd_stso_on), 0, 0, 0 },
+	{ &cmd_sufo_on, sizeof(cmd_sufo_on), 0, 0, 0 },
+	{ &cmd_sgso_on, sizeof(cmd_sgso_on), 0, 0, 0 },
+	{ &cmd_sgro_on, sizeof(cmd_sgro_on), 0, 0, 0 },
+	{ &cmd_sflags_on, sizeof(cmd_sflags_on), 0, 0, 0 },
+	{ &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
+	{ &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
+	{ &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
+	{ &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
+	{ &cmd_gufo_on, 4, 0, &cmd_gufo_on, sizeof(cmd_gufo_on) },
+	{ &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
+	{ &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
+	{ &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_unsup_on_old[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ &cmd_stxcsum_on, sizeof(cmd_stxcsum_on), -EOPNOTSUPP },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct {
+	struct ethtool_gstrings cmd;
+	u8 data[34][ETH_GSTRING_LEN];
+}
+cmd_gstrings = {
+	{ ETHTOOL_GSTRINGS, ETH_SS_FEATURES, 34 },
+	{
+		"tx-scatter-gather",
+		"tx-checksum-ipv4",
+		"",
+		"tx-checksum-ip-generic",
+		"tx-checksum-ipv6",
+		"highdma",
+		"tx-scatter-gather-fraglist",
+		"tx-vlan-hw-insert",
+		"rx-vlan-hw-parse",
+		"rx-vlan-filter",
+		"vlan-challenged",
+		"tx-generic-segmentation",
+		"tx-lockless",
+		"netns-local",
+		"rx-gro",
+		"rx-lro",
+		"tx-tcp-segmentation",
+		"tx-udp-fragmentation",
+		"tx-gso-robust",
+		"tx-tcp-ecn-segmentation",
+		"tx-tcp6-segmentation",
+		"tx-fcoe-segmentation",
+		"",
+		"",
+		"tx-checksum-fcoe-crc",
+		"tx-checksum-sctp",
+		"fcoe-mtu",
+		"rx-ntuple-filter",
+		"rx-hashing",
+		"rx-checksum",
+		"tx-nocache-copy",
+		"loopback",
+		"rx-fcs",
+		"rx-all",
+	}
+};
+
+static const struct {
+	struct ethtool_gfeatures cmd;
+	struct ethtool_get_features_block data[2];
+}
+			    /* available   requested   active   never_changed */
+/* minimal: only GRO and GSO are available (and GSO won't work) */
+cmd_gfeatures_min_off =   { { ETHTOOL_GFEATURES, 2 },
+			    {{ 0x00004800, 0x00000000, 0x00000000, 0x00003400},
+			     { 0x00000000, 0x00000000, 0x00000000, 0x00000000}}
+},
+cmd_gfeatures_min_on =    { { ETHTOOL_GFEATURES, 2 },
+			    {{ 0x00004800, 0x00004800, 0x00004000, 0x00003400},
+			     { 0x00000000, 0x00000000, 0x00000000, 0x00000000}}
+},
+/* maximal: everything that isn't never-changed is available */
+cmd_gfeatures_max_off =   { { ETHTOOL_GFEATURES, 2 },
+			    {{ 0xffffcbff, 0x00000000, 0x00000000, 0x00003400 },
+			     { 0x00000003, 0x00000000, 0x00000000, 0x00000000 }}
+},
+cmd_gfeatures_max_on =    { { ETHTOOL_GFEATURES, 2 },
+			    {{ 0xffffcbff, 0xffffcbff, 0xffffcbff, 0x00003400 },
+			     { 0x00000003, 0x00000003, 0x00000003, 0x00000000 }}
+},
+/* IPv4: GRO, GSO, SG and some IPv4-specific offloads are available */
+cmd_gfeatures_ipv4_off =  { { ETHTOOL_GFEATURES, 2 },
+			    {{ 0x00014803, 0x00000000, 0x00000000, 0x00003400 },
+			     { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }}
+},
+cmd_gfeatures_ipv4_on =   { { ETHTOOL_GFEATURES, 2 },
+			    {{ 0x00014803, 0x00014803, 0x00014803, 0x00003400 },
+			     { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }}
+};
+
+static const struct {
+	struct ethtool_sfeatures cmd;
+	struct ethtool_set_features_block data[2];
+}
+			    /* valid       requested */
+cmd_sfeatures_min_on =   { { ETHTOOL_SFEATURES, 2 },
+			    {{ 0x00004800, 0x00004800 },
+			     { 0x00000000, 0x00000000 }} },
+cmd_sfeatures_min_off =  { { ETHTOOL_SFEATURES, 2 },
+			    {{ 0x00004800, 0x00000000 },
+			     { 0x00000000, 0x00000000 }} },
+cmd_sfeatures_noop =     { { ETHTOOL_SFEATURES, 2 },
+			    {{ 0x00000000, 0x00000000 },
+			     { 0x00000000, 0x00000000 }} },
+cmd_sfeatures_ipv4_on =  { { ETHTOOL_SFEATURES, 2 },
+			    {{ 0x00014803, 0x00014803 },
+			     { 0x00000000, 0x00000000 }} };
+
+static const struct cmd_expect cmd_expect_get_strings[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_get_features_min_off[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_get_features_max_on[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
+	{ &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
+	{ &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
+	{ &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
+	{ &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
+	{ &cmd_gufo_on, 4, 0, &cmd_gufo_on, sizeof(cmd_gufo_on) },
+	{ &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
+	{ &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
+	{ &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
+	{ &cmd_gfeatures_max_on, sizeof(cmd_gfeatures_max_on.cmd),
+	  0, &cmd_gfeatures_max_on, sizeof(cmd_gfeatures_max_on) },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_min_off_min_on[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+	{ &cmd_sfeatures_min_on, sizeof(cmd_sfeatures_min_on),
+	  ETHTOOL_F_WISH, 0, 0 },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on.cmd),
+	  0, &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on) },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_min_off_min_off[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+	{ &cmd_sfeatures_min_off, sizeof(cmd_sfeatures_min_off), 0, 0, 0 },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_min_on_min_off[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on.cmd),
+	  0, &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on) },
+	{ &cmd_sfeatures_min_off, sizeof(cmd_sfeatures_min_off), 0, 0, 0 },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_min_off_unsup_on[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+	{ &cmd_sfeatures_noop, sizeof(cmd_sfeatures_noop), 0, 0, 0 },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
+	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static const struct cmd_expect cmd_expect_set_features_ipv4_off_many_on[] = {
+	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
+	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
+	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
+	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
+	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
+	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
+	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
+	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
+	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ &cmd_gfeatures_ipv4_off, sizeof(cmd_gfeatures_ipv4_off.cmd),
+	  0, &cmd_gfeatures_ipv4_off, sizeof(cmd_gfeatures_ipv4_off) },
+	{ &cmd_sfeatures_ipv4_on, sizeof(cmd_sfeatures_ipv4_on), 0, 0, 0 },
+	{ &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
+	{ &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
+	{ &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
+	{ &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
+	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
+	{ &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
+	{ &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
+	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
+	{ &cmd_gfeatures_ipv4_on, sizeof(cmd_gfeatures_ipv4_on.cmd),
+	  0, &cmd_gfeatures_ipv4_on, sizeof(cmd_gfeatures_ipv4_on) },
+	{ 0, 0, 0, 0, 0 }
+};
+
+static struct test_case {
+	int rc;
+	const char *args;
+	const struct cmd_expect *expect;
+} const test_cases[] = {
+	{ 0, "-k devname", cmd_expect_get_features_off_old },
+	{ 0, "-k dev_unsup", cmd_expect_get_features_off_old_some_unsup },
+	{ 0, "-k dev_priv", cmd_expect_get_features_off_old_some_priv },
+	{ 0, "-K devname rx off tx off sg off tso off ufo off gso off lro off rxvlan off txvlan off ntuple off rxhash off gro off",
+	  cmd_expect_set_features_off_old },
+	{ 0, "-K devname rx on tx on sg on tso on ufo on gso on lro on rxvlan on txvlan on ntuple on rxhash on gro on",
+	  cmd_expect_set_features_on_old },
+	{ 1, "-K devname tx on sg on", cmd_expect_set_features_unsup_on_old },
+	{ 0, "--show-offload devname", cmd_expect_get_features_min_off },
+	{ 0, "--show-features devname", cmd_expect_get_features_max_on },
+	{ 0, "-K devname rx on tx on sg on tso on ufo on gso on gro on",
+	  cmd_expect_set_features_min_off_min_on },
+	{ 0, "-K devname rx off tx off sg off tso off ufo off gso off gro off",
+	  cmd_expect_set_features_min_off_min_off },
+	{ 0, "-K devname rx off tx off sg off tso off ufo off gso off gro off",
+	  cmd_expect_set_features_min_on_min_off },
+	{ 1, "-K devname tx on sg on",
+	  cmd_expect_set_features_min_off_unsup_on },
+	{ 0, "--features devname rx on tx on sg on tso on gso on gro on",
+	  cmd_expect_set_features_ipv4_off_many_on },
+	{ 1, "-K devname rx foo", cmd_expect_get_strings_old },
+	{ 1, "-K devname rx foo", cmd_expect_get_strings },
+	{ 1, "--offload devname rx", cmd_expect_get_strings_old },
+	{ 1, "--features devname rx", cmd_expect_get_strings },
+	{ 1, "--features devname foo on", cmd_expect_get_strings_old },
+	{ 1, "--offload devname foo on", cmd_expect_get_strings },
+};
+
+static int expect_matched;
+static const struct cmd_expect *expect_next;
+
+int send_ioctl(struct cmd_context *ctx, void *cmd)
+{
+	int rc = test_ioctl(expect_next, cmd);
+
+	if (rc == TEST_IOCTL_MISMATCH) {
+		expect_matched = 0;
+		test_exit(0);
+	}
+	expect_next++;
+	return rc;
+}
+
+int main(void)
+{
+	const struct test_case *tc;
+	int test_rc;
+	int rc = 0;
+
+	for (tc = test_cases; tc < test_cases + ARRAY_SIZE(test_cases); tc++) {
+		if (getenv("ETHTOOL_TEST_VERBOSE"))
+			printf("I: Test command line: ethtool %s\n", tc->args);
+		expect_matched = 1;
+		expect_next = tc->expect;
+		test_rc = test_cmdline(tc->args);
+
+		/* If we found a mismatch, or there is still another
+		 * expected ioctl to match, the test failed.
+		 */
+		if (!expect_matched || expect_next->cmd) {
+			fprintf(stderr,
+				"E: ethtool %s deviated from the expected "
+				"ioctl sequence after %zu calls\n",
+				tc->args, expect_next - tc->expect);
+			rc = 1;
+		} else if (test_rc != tc->rc) {
+			fprintf(stderr, "E: ethtool %s returns %d\n",
+				tc->args, test_rc);
+			rc = 1;
+		}
+	}
+
+	return rc;
+}
diff --git a/tg3.c b/tg3.c
new file mode 100644
index 0000000..8698391
--- /dev/null
+++ b/tg3.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <string.h>
+#include "internal.h"
+
+#define TG3_MAGIC 0x669955aa
+
+int tg3_dump_eeprom(struct ethtool_drvinfo *info maybe_unused,
+		    struct ethtool_eeprom *ee)
+{
+	int i;
+
+	if (ee->magic != TG3_MAGIC) {
+		fprintf(stderr, "Magic number 0x%08x does not match 0x%08x\n",
+			ee->magic, TG3_MAGIC);
+		return -1;
+	}
+
+	fprintf(stdout, "Address   \tData\n");
+	fprintf(stdout, "----------\t----\n");
+	for (i = 0; i < ee->len; i++)
+		fprintf(stdout, "0x%08x\t0x%02x\n", i + ee->offset, ee->data[i]);
+
+	return 0;
+}
+
+int tg3_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		  struct ethtool_regs *regs)
+{
+	int i;
+	u32 reg;
+
+	fprintf(stdout, "Offset\tValue\n");
+	fprintf(stdout, "------\t----------\n");
+	for (i = 0; i < regs->len; i += sizeof(reg)) {
+		memcpy(&reg, &regs->data[i], sizeof(reg));
+		if (reg)
+			fprintf(stdout, "0x%04x\t0x%08x\n", i, reg);
+
+	}
+	fprintf(stdout, "\n");
+	return 0;
+}
diff --git a/tse.c b/tse.c
new file mode 100644
index 0000000..e5241ee
--- /dev/null
+++ b/tse.c
@@ -0,0 +1,112 @@
+/****************************************************************************
+ * Support for the Altera Triple Speed Ethernet 10/100/1000 Controller
+ *
+ * Copyright (C) 2014 Altera Corporation
+ *
+ * Author: Vince Bridgers <vbridgers2013@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "internal.h"
+
+#define ALTERA_VERSION_MASK	0xffff
+#define ALTERA_ETHTOOL_V1	1
+
+int
+bitset(u32 val, int bit)
+{
+	if (val & (1 << bit))
+		return 1;
+	return 0;
+}
+
+int altera_tse_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+			 struct ethtool_regs *regs)
+{
+	int i;
+	u32 *tsereg = (unsigned int *)regs->data;
+	u32 version = regs->version;
+
+	if ((version & ALTERA_VERSION_MASK) > ALTERA_ETHTOOL_V1)
+		return -1;
+
+	/*
+	 * Version 1: Initial TSE driver release. No feature information
+	 *	      available, 32-bits of version is equal to 1.
+	 *
+	 * Version 2: Lower 16-bits of version is 2, upper 16 bits are:
+	 *	Bit 16 - SGMDA or MSGDMA Registers
+	 *	Bit 17 - PCS Present
+	 *	Bit 18 - Supplementary MAC Address Filter Registers Present
+	 *	Bit 19 - Multicast Hash Filter Present
+	 *	Bit 20 - IEEE 1588 Feature Present
+	 */
+	fprintf(stdout, "Altera TSE 10/100/1000 Registers, Version %d\n",
+		version);
+	fprintf(stdout, "---------------------------------------------\n");
+	fprintf(stdout, "Revision               0x%08X\n", tsereg[0]);
+	fprintf(stdout, "    Core Version       %d.%d\n",
+		(tsereg[0] & 0xffff) >> 8,
+		tsereg[0] & 0xff);
+	fprintf(stdout, "    CustVersion        0x%08X\n", tsereg[0] >> 16);
+	fprintf(stdout, "Scratch                0x%08X\n", tsereg[1]);
+	fprintf(stdout, "Command/Config         0x%08X\n", tsereg[2]);
+	fprintf(stdout, "    (0)TX_EN           %d\n", bitset(tsereg[2], 0));
+	fprintf(stdout, "    (1)RX_EN           %d\n", bitset(tsereg[2], 1));
+	fprintf(stdout, "    (2)XON_GEN         %d\n", bitset(tsereg[2], 2));
+	fprintf(stdout, "    (3)ETH_SPEED       %d\n", bitset(tsereg[2], 3));
+	fprintf(stdout, "    (4)PROMIS_EN       %d\n", bitset(tsereg[2], 4));
+	fprintf(stdout, "    (5)PAD_EN          %d\n", bitset(tsereg[2], 5));
+	fprintf(stdout, "    (6)CRC_FWD         %d\n", bitset(tsereg[2], 6));
+	fprintf(stdout, "    (7)PAUSE_FWD       %d\n", bitset(tsereg[2], 7));
+	fprintf(stdout, "    (8)PAUSE_IGN       %d\n", bitset(tsereg[2], 8));
+	fprintf(stdout, "    (9)TXADDR_INS      %d\n", bitset(tsereg[2], 9));
+	fprintf(stdout, "    (10)HD_EN          %d\n", bitset(tsereg[2], 10));
+	fprintf(stdout, "    (11)EXCESS_COL     %d\n", bitset(tsereg[2], 11));
+	fprintf(stdout, "    (12)LATE_COL       %d\n", bitset(tsereg[2], 12));
+	fprintf(stdout, "    (13)SW_RESET       %d\n", bitset(tsereg[2], 13));
+	fprintf(stdout, "    (14)MHASH_SEL      %d\n", bitset(tsereg[2], 14));
+	fprintf(stdout, "    (15)LOOP_EN        %d\n", bitset(tsereg[2], 15));
+	fprintf(stdout, "    (16-18)TX_ADDR_SEL %d\n",
+		(tsereg[2] & 0x30000) >> 16);
+	fprintf(stdout, "    (19)MAGIC_EN       %d\n", bitset(tsereg[2], 19));
+	fprintf(stdout, "    (20)SLEEP          %d\n", bitset(tsereg[2], 20));
+	fprintf(stdout, "    (21)WAKEUP         %d\n", bitset(tsereg[2], 21));
+	fprintf(stdout, "    (22)XOFF_GEN       %d\n", bitset(tsereg[2], 22));
+	fprintf(stdout, "    (23)CTRL_FRAME_EN  %d\n", bitset(tsereg[2], 23));
+	fprintf(stdout, "    (24)NO_LEN_CHECK   %d\n", bitset(tsereg[2], 24));
+	fprintf(stdout, "    (25)ENA_10         %d\n", bitset(tsereg[2], 25));
+	fprintf(stdout, "    (26)RX_ERR_DISC    %d\n", bitset(tsereg[2], 26));
+	fprintf(stdout, "    (31)CTRL_RESET     %d\n", bitset(tsereg[2], 31));
+	fprintf(stdout, "mac_0                  0x%08X\n", tsereg[3]);
+	fprintf(stdout, "mac_1                  0x%08X\n", tsereg[4]);
+	fprintf(stdout, "frm_length             0x%08X\n", tsereg[5]);
+	fprintf(stdout, "pause_quant            0x%08X\n", tsereg[6]);
+	fprintf(stdout, "rx_section_empty       0x%08X\n", tsereg[7]);
+	fprintf(stdout, "rx_section_full        0x%08X\n", tsereg[8]);
+	fprintf(stdout, "tx_section_empty       0x%08X\n", tsereg[9]);
+	fprintf(stdout, "tx_section_full        0x%08X\n", tsereg[0xa]);
+	fprintf(stdout, "rx_almost_empty        0x%08X\n", tsereg[0xb]);
+	fprintf(stdout, "rx_almost_full         0x%08X\n", tsereg[0xc]);
+	fprintf(stdout, "tx_almost_empty        0x%08X\n", tsereg[0xd]);
+	fprintf(stdout, "tx_almost_full         0x%08X\n", tsereg[0xe]);
+	fprintf(stdout, "mdio_addr0             0x%08X\n", tsereg[0xf]);
+	fprintf(stdout, "mdio_addr1             0x%08X\n", tsereg[0x10]);
+	fprintf(stdout, "holdoff_quant          0x%08X\n", tsereg[0x11]);
+
+	fprintf(stdout, "tx_ipg_length          0x%08X\n", tsereg[0x17]);
+	fprintf(stdout, "Transmit Command       0x%08X\n", tsereg[0x3a]);
+	fprintf(stdout, "Receive Command        0x%08X\n", tsereg[0x3b]);
+
+	for (i = 0; i < 64; i++)
+		fprintf(stdout, "Multicast Hash[%02d]     0x%08X\n",
+			i,
+			tsereg[0x40 + i]);
+	return 0;
+}
+
diff --git a/vioc.c b/vioc.c
new file mode 100644
index 0000000..ef163ab
--- /dev/null
+++ b/vioc.c
@@ -0,0 +1,34 @@
+/* Copyright 2006 Fabric7 Systems, Inc */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "internal.h"
+
+struct regs_line {
+		u32	addr;
+		u32	data;
+};
+
+#define VIOC_REGS_LINE_SIZE	sizeof(struct regs_line)
+
+int vioc_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		   struct ethtool_regs *regs)
+{
+	unsigned int	i;
+	unsigned int	num_regs;
+	struct regs_line *reg_info = (struct regs_line *) regs->data;
+
+	printf("ethtool_regs\n"
+		"%-20s = %04x\n"
+		"%-20s = %04x\n",
+		"cmd", regs->cmd,
+		"version", regs->version);
+
+	num_regs = regs->len/VIOC_REGS_LINE_SIZE;
+
+	for (i = 0; i < num_regs; i++){
+		printf("%08x = %08x\n", reg_info[i].addr, reg_info[i].data);
+	}
+
+	return 0;
+}
diff --git a/vmxnet3.c b/vmxnet3.c
new file mode 100644
index 0000000..c972145
--- /dev/null
+++ b/vmxnet3.c
@@ -0,0 +1,199 @@
+/* Copyright (c) 2015 VMware Inc.*/
+#include <stdio.h>
+#include "internal.h"
+
+int
+vmxnet3_dump_regs(struct ethtool_drvinfo *info maybe_unused,
+		  struct ethtool_regs *regs)
+{
+	u32 *regs_buff = (u32 *)regs->data;
+	u32 version = regs->version;
+	int i = 0, j = 0, cnt;
+
+	if (version != 2)
+		return -1;
+
+	fprintf(stdout, "Control Registers\n");
+	fprintf(stdout, "=================\n");
+
+	fprintf(stdout,
+		"    VRRS (Vmxnet3 Revision Report and Selection)    0x%x\n",
+		regs_buff[j++]);
+	fprintf(stdout,
+		"    UVRS (UPT Version Report and Selection)         0x%x\n",
+		regs_buff[j++]);
+	fprintf(stdout,
+		"    DSA  (Driver Shared Address)                    0x%08x%08x\n",
+		regs_buff[j+1], regs_buff[j]);
+	j += 2;
+	fprintf(stdout,
+		"    CMD  (Command Register)                         0x%x\n",
+		regs_buff[j++]);
+	fprintf(stdout,
+		"    MAC  (Media Access Control address)             %02x:%02x:%02x:%02x:%02x:%02x\n",
+		regs_buff[j] & 0xff,
+		(regs_buff[j] >> 8)  & 0xff,
+		(regs_buff[j] >> 16) & 0xff,
+		(regs_buff[j] >> 24) & 0xff,
+		regs_buff[j + 1] & 0xff,
+		(regs_buff[j + 1] >> 8)  & 0xff);
+	j += 2;
+	fprintf(stdout,
+		"    ICR  (Interrupt Cause Register)                 0x%x\n",
+		regs_buff[j++]);
+	fprintf(stdout,
+		"    ECR  (Event Cause Register)                     0x%x\n",
+		regs_buff[j++]);
+
+	fprintf(stdout, "Datapath Registers\n");
+	fprintf(stdout, "==================\n");
+
+	/* Interrupt Mask Registers */
+	cnt = regs_buff[j++];
+	for (i = 0; i < cnt; i++) {
+		fprintf(stdout,
+			"    IMR (Interrupt Mask Register) %d                 0x%x\n",
+			i, regs_buff[j++]);
+	}
+
+	/* Transmit Queue Registers */
+	cnt = regs_buff[j++];
+	for (i = 0; i < cnt; i++) {
+		fprintf(stdout, "    Transmit Queue %d\n", i);
+		fprintf(stdout, "    ----------------\n");
+		fprintf(stdout,
+			"        TXPROD (Transmit Ring Producer Register)    0x%x\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"        Transmit Ring\n");
+		fprintf(stdout,
+			"            Base Address                            0x%08x%08x\n",
+			regs_buff[j+1], regs_buff[j]);
+		j += 2;
+		fprintf(stdout,
+			"            Size                                    %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            next2fill                               %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            next2comp                               %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            gen                                     %u\n",
+			regs_buff[j++]);
+
+		fprintf(stdout,
+			"        Transmit Data Ring\n");
+		fprintf(stdout,
+			"            Base Address                            0x%08x%08x\n",
+			regs_buff[j+1], regs_buff[j]);
+		j += 2;
+		fprintf(stdout,
+			"            Size                                    %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            Buffer Size                             %u\n",
+			regs_buff[j++]);
+
+		fprintf(stdout,
+			"        Transmit Completion Ring\n");
+		fprintf(stdout,
+			"            Base Address                            0x%08x%08x\n",
+			regs_buff[j+1], regs_buff[j]);
+		j += 2;
+		fprintf(stdout,
+			"            size                                    %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            next2proc                               %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            gen                                     %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"        stopped                                     %u\n",
+			regs_buff[j++]);
+	}
+
+	/* Receive Queue Registers */
+	cnt = regs_buff[j++];
+	for (i = 0; i < cnt; i++) {
+		fprintf(stdout, "    Receive Queue %d\n", i);
+		fprintf(stdout, "    ----------------\n");
+		fprintf(stdout,
+			"        RXPROD1 (Receive Ring Producer Register) 1  0x%x\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"        RXPROD2 (Receive Ring Producer Register) 2  0x%x\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"        Receive Ring 0\n");
+		fprintf(stdout,
+			"            Base Address                            0x%08x%08x\n",
+			regs_buff[j+1], regs_buff[j]);
+		j += 2;
+		fprintf(stdout,
+			"            Size                                    %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            next2fill                               %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            next2comp                               %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            gen                                     %u\n",
+			regs_buff[j++]);
+
+		fprintf(stdout,
+			"        Receive Ring 1\n");
+		fprintf(stdout,
+			"            Base Address                            0x%08x%08x\n",
+			regs_buff[j+1], regs_buff[j]);
+		j += 2;
+		fprintf(stdout,
+			"            Size                                    %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            next2fill                               %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            next2comp                               %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            gen                                     %u\n",
+			regs_buff[j++]);
+
+		fprintf(stdout,
+			"        Receive Data Ring\n");
+		fprintf(stdout,
+			"            Base Address                            0x%08x%08x\n",
+			regs_buff[j+1], regs_buff[j]);
+		j += 2;
+		fprintf(stdout,
+			"            Size                                    %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            Buffer Size                             %u\n",
+			regs_buff[j++]);
+
+		fprintf(stdout,
+			"        Receive Completion Ring\n");
+		fprintf(stdout,
+			"            Base Address                            0x%08x%08x\n",
+			regs_buff[j+1], regs_buff[j]);
+		j += 2;
+		fprintf(stdout,
+			"            size                                    %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            next2proc                               %u\n",
+			regs_buff[j++]);
+		fprintf(stdout,
+			"            gen                                     %u\n",
+			regs_buff[j++]);
+	}
+
+	return 0;
+}