]> review.fuel-infra Code Review - packages/trusty/i40e-dkms.git/commitdiff
Update i40e to 2.7.29 97/40697/1 9.0
authorRoman Lubianyi <rlubianyi@mirantis.com>
Tue, 5 Mar 2019 11:50:10 +0000 (13:50 +0200)
committerRoman Lubianyi <rlubianyi@mirantis.com>
Tue, 5 Mar 2019 11:53:10 +0000 (13:53 +0200)
Change-Id: Iea12e77a2521207a66ed8824720f061176fb4057
Closes-Bug: #1818618

60 files changed:
debian/changelog
i40e-dkms/i40e-2.4.6/COPYING [deleted file]
i40e-dkms/i40e-2.4.6/SUMS [deleted file]
i40e-dkms/i40e-2.4.6/src/i40e_devids.h [deleted file]
i40e-dkms/i40e-2.4.6/src/i40e_diag.h [deleted file]
i40e-dkms/i40e-2.7.29/COPYING [new file with mode: 0644]
i40e-dkms/i40e-2.7.29/README [moved from i40e-dkms/i40e-2.4.6/README with 70% similarity]
i40e-dkms/i40e-2.7.29/SUMS [new file with mode: 0644]
i40e-dkms/i40e-2.7.29/i40e.7 [moved from i40e-dkms/i40e-2.4.6/i40e.7 with 79% similarity]
i40e-dkms/i40e-2.7.29/i40e.spec [moved from i40e-dkms/i40e-2.4.6/i40e.spec with 68% similarity]
i40e-dkms/i40e-2.7.29/pci.updates [moved from i40e-dkms/i40e-2.4.6/pci.updates with 86% similarity]
i40e-dkms/i40e-2.7.29/scripts/dump_tables [moved from i40e-dkms/i40e-2.4.6/scripts/dump_tables with 100% similarity]
i40e-dkms/i40e-2.7.29/scripts/set_irq_affinity [moved from i40e-dkms/i40e-2.4.6/scripts/set_irq_affinity with 100% similarity]
i40e-dkms/i40e-2.7.29/scripts/virt_perf_default [moved from i40e-dkms/i40e-2.4.6/scripts/virt_perf_default with 100% similarity]
i40e-dkms/i40e-2.7.29/src/Makefile [moved from i40e-dkms/i40e-2.4.6/src/Makefile with 68% similarity]
i40e-dkms/i40e-2.7.29/src/Module.supported [moved from i40e-dkms/i40e-2.4.6/src/Module.supported with 100% similarity]
i40e-dkms/i40e-2.7.29/src/common.mk [moved from i40e-dkms/i40e-2.4.6/src/common.mk with 91% similarity]
i40e-dkms/i40e-2.7.29/src/i40e.h [moved from i40e-dkms/i40e-2.4.6/src/i40e.h with 86% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_adminq.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_adminq.c with 96% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_adminq.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_adminq.h with 79% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_adminq_cmd.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_adminq_cmd.h with 93% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_alloc.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_alloc.h with 51% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_client.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_client.c with 94% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_client.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_client.h with 85% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_common.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_common.c with 96% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_dcb.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_dcb.c with 91% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_dcb.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_dcb.h with 81% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_dcb_nl.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_dcb_nl.c with 86% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_ddp.c [new file with mode: 0644]
i40e-dkms/i40e-2.7.29/src/i40e_debugfs.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_debugfs.c with 96% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_devids.h [new file with mode: 0644]
i40e-dkms/i40e-2.7.29/src/i40e_diag.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_diag.c with 79% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_diag.h [new file with mode: 0644]
i40e-dkms/i40e-2.7.29/src/i40e_ethtool.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_ethtool.c with 86% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_ethtool_stats.h [new file with mode: 0644]
i40e-dkms/i40e-2.7.29/src/i40e_filters.c [new file with mode: 0644]
i40e-dkms/i40e-2.7.29/src/i40e_filters.h [new file with mode: 0644]
i40e-dkms/i40e-2.7.29/src/i40e_helper.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_helper.h with 75% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_hmc.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_hmc.c with 90% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_hmc.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_hmc.h with 87% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_lan_hmc.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_lan_hmc.c with 96% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_lan_hmc.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_lan_hmc.h with 80% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_main.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_main.c with 79% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_nvm.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_nvm.c with 97% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_osdep.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_osdep.h with 74% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_prototype.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_prototype.h with 92% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_ptp.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_ptp.c with 93% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_register.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_register.h with 99% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_status.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_status.h with 70% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_trace.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_trace.h with 84% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_txrx.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_txrx.c with 91% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_txrx.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_txrx.h with 93% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_type.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_type.h with 96% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_virtchnl_pf.c [moved from i40e-dkms/i40e-2.4.6/src/i40e_virtchnl_pf.c with 51% similarity]
i40e-dkms/i40e-2.7.29/src/i40e_virtchnl_pf.h [moved from i40e-dkms/i40e-2.4.6/src/i40e_virtchnl_pf.h with 76% similarity]
i40e-dkms/i40e-2.7.29/src/kcompat.c [moved from i40e-dkms/i40e-2.4.6/src/kcompat.c with 90% similarity]
i40e-dkms/i40e-2.7.29/src/kcompat.h [moved from i40e-dkms/i40e-2.4.6/src/kcompat.h with 90% similarity]
i40e-dkms/i40e-2.7.29/src/kcompat_vfd.c [new file with mode: 0644]
i40e-dkms/i40e-2.7.29/src/kcompat_vfd.h [new file with mode: 0644]
i40e-dkms/i40e-2.7.29/src/virtchnl.h [moved from i40e-dkms/i40e-2.4.6/src/virtchnl.h with 82% similarity]

index a0b5edd6161ee19408de77fb5127ef7eb8965a63..3c2efe28f35a87314c25dc10c10031b96c72e28a 100644 (file)
@@ -1,3 +1,9 @@
+i40e-dkms (2.7.29-1~u14.04+mos1) mos; urgency=low
+
+  * Update to version 2.7.29
+
+ -- Roman Lubianyi <rlubianyi@mirantis.com>  Tue, 5 Mar 2019 13:48:00 +0200
+
 i40e-dkms (2.4.6-1~u14.04+mos1) mos; urgency=low
 
   * Update to version 2.4.6
diff --git a/i40e-dkms/i40e-2.4.6/COPYING b/i40e-dkms/i40e-2.4.6/COPYING
deleted file mode 100644 (file)
index 53f1178..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-
-"This software program is licensed subject to the GNU General Public License
-(GPL). Version 2, June 1991, available at
-<http://www.fsf.org/copyleft/gpl.html>"
-
-GNU General Public License
-
-Version 2, June 1991
-
-Copyright (C) 1989, 1991 Free Software Foundation, Inc. 
-59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 Library 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.
-
-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 an idea of what it does.
-Copyright (C) yyyy  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., 59
-Temple Place - Suite 330, Boston, MA  02111-1307, 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 Library General Public
-License instead of this License.
diff --git a/i40e-dkms/i40e-2.4.6/SUMS b/i40e-dkms/i40e-2.4.6/SUMS
deleted file mode 100644 (file)
index 6aae663..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-08564   109 i40e-2.4.6/src/i40e_txrx.c
-41515    20 i40e-2.4.6/src/i40e_txrx.h
-09324     4 i40e-2.4.6/src/i40e_osdep.h
-56307     4 i40e-2.4.6/src/i40e_helper.h
-39730     7 i40e-2.4.6/src/i40e_trace.h
-19269   369 i40e-2.4.6/src/i40e_main.c
-45570   178 i40e-2.4.6/src/i40e_ethtool.c
-21177    36 i40e-2.4.6/src/i40e.h
-26657    80 i40e-2.4.6/src/i40e_debugfs.c
-08628    94 i40e-2.4.6/src/i40e_virtchnl_pf.c
-07022     6 i40e-2.4.6/src/i40e_virtchnl_pf.h
-11204    23 i40e-2.4.6/src/i40e_client.c
-24595     7 i40e-2.4.6/src/i40e_client.h
-07868     9 i40e-2.4.6/src/i40e_dcb_nl.c
-28819    27 i40e-2.4.6/src/i40e_ptp.c
-62562   191 i40e-2.4.6/src/i40e_common.c
-63604    30 i40e-2.4.6/src/i40e_adminq.c
-50421     5 i40e-2.4.6/src/i40e_adminq.h
-22692    83 i40e-2.4.6/src/i40e_adminq_cmd.h
-29864   364 i40e-2.4.6/src/i40e_register.h
-15312    48 i40e-2.4.6/src/i40e_type.h
-09757     4 i40e-2.4.6/src/i40e_status.h
-31866    11 i40e-2.4.6/src/i40e_hmc.c
-29823     5 i40e-2.4.6/src/i40e_diag.c
-08614     2 i40e-2.4.6/src/i40e_diag.h
-04545    35 i40e-2.4.6/src/i40e_lan_hmc.c
-04399     6 i40e-2.4.6/src/i40e_lan_hmc.h
-07701     3 i40e-2.4.6/src/i40e_alloc.h
-31071     8 i40e-2.4.6/src/i40e_hmc.h
-43697    23 i40e-2.4.6/src/i40e_prototype.h
-57274    46 i40e-2.4.6/src/i40e_nvm.c
-00985     2 i40e-2.4.6/src/i40e_devids.h
-48100    27 i40e-2.4.6/src/i40e_dcb.c
-11217     6 i40e-2.4.6/src/i40e_dcb.h
-54678   173 i40e-2.4.6/src/kcompat.h
-56098    58 i40e-2.4.6/src/kcompat.c
-33574    23 i40e-2.4.6/src/virtchnl.h
-56182     6 i40e-2.4.6/src/Makefile
-35144    12 i40e-2.4.6/src/common.mk
-44588     1 i40e-2.4.6/src/Module.supported
-33977     7 i40e-2.4.6/scripts/set_irq_affinity
-49876     5 i40e-2.4.6/scripts/virt_perf_default
-20875     2 i40e-2.4.6/scripts/dump_tables
-45078     7 i40e-2.4.6/pci.updates
-43521    19 i40e-2.4.6/COPYING
-30395    55 i40e-2.4.6/README
-60959     3 i40e-2.4.6/i40e.7
-63230    11 i40e-2.4.6/i40e.spec
diff --git a/i40e-dkms/i40e-2.4.6/src/i40e_devids.h b/i40e-dkms/i40e-2.4.6/src/i40e_devids.h
deleted file mode 100644 (file)
index 044f053..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
-
-#define _I40E_DEVIDS_H_
-
-/* Device IDs */
-#define I40E_DEV_ID_SFP_XL710          0x1572
-#define I40E_DEV_ID_QEMU               0x1574
-#define I40E_DEV_ID_KX_B               0x1580
-#define I40E_DEV_ID_KX_C               0x1581
-#define I40E_DEV_ID_QSFP_A             0x1583
-#define I40E_DEV_ID_QSFP_B             0x1584
-#define I40E_DEV_ID_QSFP_C             0x1585
-#define I40E_DEV_ID_10G_BASE_T         0x1586
-#define I40E_DEV_ID_20G_KR2            0x1587
-#define I40E_DEV_ID_20G_KR2_A          0x1588
-#define I40E_DEV_ID_10G_BASE_T4                0x1589
-#define I40E_DEV_ID_25G_B              0x158A
-#define I40E_DEV_ID_25G_SFP28          0x158B
-#define I40E_DEV_ID_KX_X722            0x37CE
-#define I40E_DEV_ID_QSFP_X722          0x37CF
-#define I40E_DEV_ID_SFP_X722           0x37D0
-#define I40E_DEV_ID_1G_BASE_T_X722     0x37D1
-#define I40E_DEV_ID_10G_BASE_T_X722    0x37D2
-#define I40E_DEV_ID_SFP_I_X722         0x37D3
-
-#define i40e_is_40G_device(d)          ((d) == I40E_DEV_ID_QSFP_A  || \
-                                        (d) == I40E_DEV_ID_QSFP_B  || \
-                                        (d) == I40E_DEV_ID_QSFP_C)
-
-#define i40e_is_25G_device(d)          ((d) == I40E_DEV_ID_25G_B  || \
-                                        (d) == I40E_DEV_ID_25G_SFP28)
-
diff --git a/i40e-dkms/i40e-2.4.6/src/i40e_diag.h b/i40e-dkms/i40e-2.4.6/src/i40e_diag.h
deleted file mode 100644 (file)
index 167169a..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
-
-#ifndef _I40E_DIAG_H_
-#define _I40E_DIAG_H_
-
-#include "i40e_type.h"
-
-enum i40e_lb_mode {
-       I40E_LB_MODE_NONE       = 0x0,
-       I40E_LB_MODE_PHY_LOCAL  = I40E_AQ_LB_PHY_LOCAL,
-       I40E_LB_MODE_PHY_REMOTE = I40E_AQ_LB_PHY_REMOTE,
-       I40E_LB_MODE_MAC_LOCAL  = I40E_AQ_LB_MAC_LOCAL,
-};
-
-struct i40e_diag_reg_test_info {
-       u32 offset;     /* the base register */
-       u32 mask;       /* bits that can be tested */
-       u32 elements;   /* number of elements if array */
-       u32 stride;     /* bytes between each element */
-};
-
-extern struct i40e_diag_reg_test_info i40e_reg_list[];
-
-i40e_status i40e_diag_reg_test(struct i40e_hw *hw);
-i40e_status i40e_diag_eeprom_test(struct i40e_hw *hw);
-
-#endif /* _I40E_DIAG_H_ */
diff --git a/i40e-dkms/i40e-2.7.29/COPYING b/i40e-dkms/i40e-2.7.29/COPYING
new file mode 100644 (file)
index 0000000..a953f51
--- /dev/null
@@ -0,0 +1,319 @@
+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.
+
+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 an idea of what it does.
+    Copyright (C) yyyy 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.
similarity index 70%
rename from i40e-dkms/i40e-2.4.6/README
rename to i40e-dkms/i40e-2.7.29/README
index fb477ae6d601400aa7d4535a7e02d87a318049af..2051f7aaded9d86925f95b762ad993dbef1f8dc2 100644 (file)
@@ -2,12 +2,11 @@
 i40e Linux* Base Driver for the Intel(R) Ethernet Controller 700 Series
 ===============================================================================
 
-December 4, 2017
-
-===============================================================================
+December 10, 2018
+Copyright(c) 2014-2018 Intel Corporation.
 
 Contents
---------
+========
 
 - Important Notes
 - Overview
@@ -27,66 +26,70 @@ Important Notes
 
 TC0 must be enabled when setting up DCB on a switch
 ---------------------------------------------------
-The kernel assumes that TC0 is available, and will disable Priority Flow 
-Control (PFC) on the device if TC0 is not available. To fix this, ensure TC0 is 
+The kernel assumes that TC0 is available, and will disable Priority Flow
+Control (PFC) on the device if TC0 is not available. To fix this, ensure TC0 is
 enabled when setting up DCB on your switch.
 
 
 Enabling a VF link if the port is disconnected
 ----------------------------------------------
-If the physical function (PF) link is down, you can force link up (from the 
-host PF) on any virtual functions (VF) bound to the PF. Note that this requires 
-kernel support (Redhat kernel 3.10.0-327 or newer, upstream kernel 3.11.0 or 
-newer, and associated iproute2 user space support). If the following command 
-does not work, it may not be supported by your system. The following command 
+If the physical function (PF) link is down, you can force link up (from the
+host PF) on any virtual functions (VF) bound to the PF. Note that this requires
+kernel support (Redhat kernel 3.10.0-327 or newer, upstream kernel 3.11.0 or
+newer, and associated iproute2 user space support). If the following command
+does not work, it may not be supported by your system. The following command
 forces link up on VF 0 bound to PF eth0:
   ip link set eth0 vf 0 state enable
 
 
 Do not unload port driver if VF with active VM is bound to it
 -------------------------------------------------------------
-Do not unload a port's driver if a Virtual Function (VF) with an active Virtual 
-Machine (VM) is bound to it. Doing so will cause the port to appear to hang. 
+Do not unload a port's driver if a Virtual Function (VF) with an active Virtual
+Machine (VM) is bound to it. Doing so will cause the port to appear to hang.
 Once the VM shuts down, or otherwise releases the VF, the command will complete.
 
 
 Configuring SR-IOV for improved network security
 ------------------------------------------------
-In a virtualized environment, on Intel(R) Ethernet Server Adapters that support 
-SR-IOV, the virtual function (VF) may be subject to malicious behavior. 
-Software-generated layer two frames, like IEEE 802.3x (link flow control), IEEE 
-802.1Qbb (priority based flow-control), and others of this type, are not 
-expected and can throttle traffic between the host and the virtual switch, 
-reducing performance. To resolve this issue, configure all SR-IOV enabled ports 
-for VLAN tagging. This configuration allows unexpected, and potentially 
-malicious, frames to be dropped.
+In a virtualized environment, on Intel(R) Ethernet Server Adapters that support
+SR-IOV, the virtual function (VF) may be subject to malicious behavior.
+Software-generated layer two frames, like IEEE 802.3x (link flow control), IEEE
+802.1Qbb (priority based flow-control), and others of this type, are not
+expected and can throttle traffic between the host and the virtual switch,
+reducing performance. To resolve this issue, and to ensure isolation from
+unintended traffic streams, configure all SR-IOV enabled ports for VLAN tagging
+from the administrative interface on the PF. This configuration allows
+unexpected, and potentially malicious, frames to be dropped.
 
 
 Overview
---------
+========
 This driver supports kernel versions 2.6.32 and newer.
 
-Driver information can be obtained using ethtool, lspci, and ifconfig. 
-Instructions on updating ethtool can be found in the section Additional 
+Driver information can be obtained using ethtool, lspci, and ifconfig.
+Instructions on updating ethtool can be found in the section Additional
 Configurations later in this document.
 
-This driver is only supported as a loadable module at this time. Intel is not 
-supplying patches against the kernel source to allow for static linking of the 
+This driver is only supported as a loadable module at this time. Intel is not
+supplying patches against the kernel source to allow for static linking of the
 drivers.
 
-For questions related to hardware requirements, refer to the documentation 
-supplied with your Intel adapter. All hardware requirements listed apply to use 
+For questions related to hardware requirements, refer to the documentation
+supplied with your Intel adapter. All hardware requirements listed apply to use
 with Linux.
 
-Adapter teaming is implemented using the native Linux Channel bonding module. 
-This is included in supported Linux kernels. Channel Bonding documentation can 
+Adapter teaming is implemented using the native Linux Channel bonding module.
+This is included in supported Linux kernels. Channel Bonding documentation can
 be found in the Linux kernel source:
 /documentation/networking/bonding.txt
 
-The driver information previously displayed in the /proc file system is not 
+This driver supports XDP (Express Data Path) on kernel 4.14 and later. Note
+that XDP is blocked for frame sizes larger than 3KB.
+
+The driver information previously displayed in the /proc file system is not
 supported in this release.
 
-NOTE: 1 Gb devices based on the Intel(R) Ethernet Network Connection X722 do 
+NOTE: 1 Gb devices based on the Intel(R) Ethernet Network Connection X722 do
 not support the following features:
   * Data Center Bridging (DCB)
   * QOS
@@ -98,17 +101,17 @@ not support the following features:
 
 
 Identifying Your Adapter
-------------------------
+========================
 The driver in this release is compatible with devices based on the following:
   * Intel(R) Ethernet Controller X710
   * Intel(R) Ethernet Controller XL710
   * Intel(R) Ethernet Network Connection X722
   * Intel(R) Ethernet Controller XXV710
 
-For the best performance, make sure the latest NVM/FW is installed on your 
+For the best performance, make sure the latest NVM/FW is installed on your
 device and that you are using the newest drivers.
 
-For information on how to identify your adapter, and for the latest NVM/FW 
+For information on how to identify your adapter, and for the latest NVM/FW
 images and Intel network drivers, refer to the Intel Support website:
 http://www.intel.com/support
 
@@ -118,18 +121,18 @@ SFP+ and QSFP+ Devices:
 For information about supported media, refer to this document:
 http://www.intel.com/content/dam/www/public/us/en/documents/release-notes/xl710-
 ethernet-controller-feature-matrix.pdf
-NOTE: Some adapters based on the Intel(R) Ethernet Controller 700 Series only 
-support Intel Ethernet Optics modules. On these adapters, other modules are not 
+NOTE: Some adapters based on the Intel(R) Ethernet Controller 700 Series only
+support Intel Ethernet Optics modules. On these adapters, other modules are not
 supported and will not function.
 
-NOTE: For connections based on Intel(R) Ethernet Controller 700 Series, support 
+NOTE: For connections based on Intel(R) Ethernet Controller 700 Series, support
 is dependent on your system board. Please see your vendor for details.
 
-NOTE:In all cases Intel recommends using Intel Ethernet Optics; other modules 
-may function but are not validated by Intel. Contact Intel for supported media 
+NOTE:In all cases Intel recommends using Intel Ethernet Optics; other modules
+may function but are not validated by Intel. Contact Intel for supported media
 types.
 
-NOTE: In systems that do not have adequate airflow to cool the adapter and 
+NOTE: In systems that do not have adequate airflow to cool the adapter and
 optical modules, you must use high temperature optical modules.
 
 
@@ -138,16 +141,20 @@ optical modules, you must use high temperature optical modules.
 
 Building and Installation
 -------------------------
-To build a binary RPM* package of this driver, run 'rpmbuild -tb 
-i40e-<x.x.x>.tar.gz', where <x.x.x> is the version number for the driver tar 
+To build a binary RPM* package of this driver, run 'rpmbuild -tb
+i40e-<x.x.x>.tar.gz', where <x.x.x> is the version number for the driver tar
 file.
 
-Note: For the build to work properly, the currently running kernel MUST match 
-the version and configuration of the installed kernel sources. If you have just 
+Note: For the build to work properly, the currently running kernel MUST match
+the version and configuration of the installed kernel sources. If you have just
 recompiled the kernel reboot the system before building.
 
+- To compile the driver on some kernel/arch combinations, a package with the
+development version of libelf (e.g. libelf-dev, libelf-devel,
+elfutilsl-libelf-devel) may need to be installed.
+
 Note: RPM functionality has only been tested in Red Hat distributions.
-_lbank_line_
+
 
 1. Move the base driver tar file to the directory of your choice. For
    example, use '/home/username/i40e' or '/usr/local/src/i40e'.
@@ -183,7 +190,7 @@ _lbank_line_
 
 6. Assign an IP address to the interface by entering the following,
    where ethX is the interface name that was shown in dmesg after modprobe:
-   
+  
    ip address add <IP_address>/<netmask bits> dev ethX
 
 7. Verify that the interface works. Enter the following, where IP_address
@@ -191,9 +198,9 @@ _lbank_line_
    that is being tested:
    ping <IP_address>
 
-Note: For certain distributions like (but not limited to) RedHat Enterprise 
-Linux 7 and Ubuntu, once the driver is installed the initrd/initramfs file may 
-need to be updated to prevent the OS loading old versions of the i40e driver. 
+Note: For certain distributions like (but not limited to) RedHat Enterprise
+Linux 7 and Ubuntu, once the driver is installed the initrd/initramfs file may
+need to be updated to prevent the OS loading old versions of the i40e driver.
 The dracut utility may be used on RedHat distributions:
        # dracut --force
    For Ubuntu:
@@ -205,45 +212,45 @@ The dracut utility may be used on RedHat distributions:
 
 Command Line Parameters
 -----------------------
-In general, ethtool and other OS specific commands are used to configure user 
-changeable parameters after the driver is loaded. The i40e driver only supports 
-the max_vfs kernel parameter on older kernels that do not have the standard 
-sysfs interface. The only other module parameter supported is the debug 
+In general, ethtool and other OS specific commands are used to configure user
+changeable parameters after the driver is loaded. The i40e driver only supports
+the max_vfs kernel parameter on older kernels that do not have the standard
+sysfs interface. The only other module parameter supported is the debug
 parameter that can control the default logging verbosity of the driver.
 
-If the driver is built as a module, the following optional parameters are used 
-by entering them on the command line with the modprobe command using this 
+If the driver is built as a module, the following optional parameters are used
+by entering them on the command line with the modprobe command using this
 syntax:
 modprobe i40e [<option>=<VAL1>]
 
-There needs to be a <VAL#> for each network port in the system supported by 
+There needs to be a <VAL#> for each network port in the system supported by
 this driver. The values will be applied to each instance, in function order.
 For example:
 modprobe i40e max_vfs=7
 
-The default value for each parameter is generally the recommended setting, 
+The default value for each parameter is generally the recommended setting,
 unless otherwise noted.
 
 
 max_vfs
 -------
-This parameter adds support for SR-IOV. It causes the driver to spawn up to 
+This parameter adds support for SR-IOV. It causes the driver to spawn up to
 max_vfs worth of virtual functions.
 Valid Range:
 1-32 (Intel Ethernet Controller X710 based devices)
 1-64 (Intel Ethernet Controller XXV710/XL710 based devices)
 
-NOTE: This parameter is only used on kernel 3.7.x and below. On kernel 3.8.x 
-and above, use sysfs to enable VFs. Also, for Red Hat distributions, this 
-parameter is only used on version 6.6 and older. For version 6.7 and newer, use 
+NOTE: This parameter is only used on kernel 3.7.x and below. On kernel 3.8.x
+and above, use sysfs to enable VFs. Also, for Red Hat distributions, this
+parameter is only used on version 6.6 and older. For version 6.7 and newer, use
 sysfs. For example:
-#echo $num_vf_enabled > /sys/class/net/$dev/device/sriov_numvfs        //enable 
+#echo $num_vf_enabled > /sys/class/net/$dev/device/sriov_numvfs        //enable
 VFs
 #echo 0 > /sys/class/net/$dev/device/sriov_numvfs      //disable VFs
 
-The parameters for the driver are referenced by position. Thus, if you have a 
-dual port adapter, or more than one adapter in your system, and want N virtual 
-functions per port, you must specify a number for each port with each parameter 
+The parameters for the driver are referenced by position. Thus, if you have a
+dual port adapter, or more than one adapter in your system, and want N virtual
+functions per port, you must specify a number for each port with each parameter
 separated by a comma. For example:
 
   modprobe i40e max_vfs=4
@@ -254,20 +261,20 @@ This will spawn 4 VFs on the first port.
 
 This will spawn 2 VFs on the first port and 4 VFs on the second port.
 
-NOTE: Caution must be used in loading the driver with these parameters. 
-Depending on your system configuration, number of slots, etc., it is impossible 
+NOTE: Caution must be used in loading the driver with these parameters.
+Depending on your system configuration, number of slots, etc., it is impossible
 to predict in all cases where the positions would be on the command line.
 
-NOTE: Neither the device nor the driver control how VFs are mapped into config 
-space. Bus layout will vary by operating system. On operating systems that 
+NOTE: Neither the device nor the driver control how VFs are mapped into config
+space. Bus layout will vary by operating system. On operating systems that
 support it, you can check sysfs to find the mapping.
 
-Some hardware configurations support fewer SR-IOV instances, as the whole Intel 
-Ethernet Controller XL710 (all functions) is limited to 128 SR-IOV interfaces 
+Some hardware configurations support fewer SR-IOV instances, as the whole Intel
+Ethernet Controller XL710 (all functions) is limited to 128 SR-IOV interfaces
 in total.
 
-NOTE: When SR-IOV mode is enabled, hardware VLAN filtering and VLAN tag 
-stripping/insertion will remain enabled. Please remove the old VLAN filter 
+NOTE: When SR-IOV mode is enabled, hardware VLAN filtering and VLAN tag
+stripping/insertion will remain enabled. Please remove the old VLAN filter
 before the new VLAN filter is added. For example,
 ip link set eth0 vf 0 vlan 100 // set vlan 100 for VF 0
 ip link set eth0 vf 0 vlan 0   // Delete vlan 100
@@ -276,41 +283,42 @@ ip link set eth0 vf 0 vlan 200    // set a new vlan 200 for VF 0
 
 Configuring SR-IOV for improved network security
 ------------------------------------------------
-In a virtualized environment, on Intel(R) Ethernet Server Adapters that support 
-SR-IOV, the virtual function (VF) may be subject to malicious behavior. 
-Software-generated layer two frames, like IEEE 802.3x (link flow control), IEEE 
-802.1Qbb (priority based flow-control), and others of this type, are not 
-expected and can throttle traffic between the host and the virtual switch, 
-reducing performance. To resolve this issue, configure all SR-IOV enabled ports 
-for VLAN tagging. This configuration allows unexpected, and potentially 
-malicious, frames to be dropped.
+In a virtualized environment, on Intel(R) Ethernet Server Adapters that support
+SR-IOV, the virtual function (VF) may be subject to malicious behavior.
+Software-generated layer two frames, like IEEE 802.3x (link flow control), IEEE
+802.1Qbb (priority based flow-control), and others of this type, are not
+expected and can throttle traffic between the host and the virtual switch,
+reducing performance. To resolve this issue, and to ensure isolation from
+unintended traffic streams, configure all SR-IOV enabled ports for VLAN tagging
+from the administrative interface on the PF. This configuration allows
+unexpected, and potentially malicious, frames to be dropped.
 
 
 Configuring VLAN tagging on SR-IOV enabled adapter ports
 --------------------------------------------------------
-To configure VLAN tagging for the ports on an SR-IOV enabled adapter, use the 
-following command. The VLAN configuration should be done before the VF driver 
+To configure VLAN tagging for the ports on an SR-IOV enabled adapter, use the
+following command. The VLAN configuration should be done before the VF driver
 is loaded or the VM is booted.
 
 $ ip link set dev <PF netdev id> vf <id> vlan <vlan id>
 
-For example, the following instructions will configure PF eth0 and the first VF 
+For example, the following instructions will configure PF eth0 and the first VF
 on VLAN 10.
 $ ip link set dev eth0 vf 0 vlan 10
 
 
 VLAN Tag Packet Steering
 ------------------------
-Allows you to send all packets with a specific VLAN tag to a particular SR-IOV 
-virtual function (VF). Further, this feature allows you to designate a 
-particular VF as trusted, and allows that trusted VF to request selective 
+Allows you to send all packets with a specific VLAN tag to a particular SR-IOV
+virtual function (VF). Further, this feature allows you to designate a
+particular VF as trusted, and allows that trusted VF to request selective
 promiscuous mode on the Physical Function (PF).
 
-To set a VF as trusted or untrusted, enter the following command in the 
+To set a VF as trusted or untrusted, enter the following command in the
 Hypervisor:
   # ip link set dev eth0 vf 1 trust [on|off]
 
-Once the VF is designated as trusted, use the following commands in the VM to 
+Once the VF is designated as trusted, use the following commands in the VM to
 set the VF to promiscuous mode.
   For promiscuous all:
   #ip link set eth2 promisc on
@@ -319,30 +327,30 @@ set the VF to promiscuous mode.
   #ip link set eth2 allmulticast on
     Where eth2 is a VF interface in the VM
 
-NOTE: By default, the ethtool priv-flag vf-true-promisc-support is set to 
-"off",meaning that promiscuous mode for the VF will be limited. To set the 
-promiscuous mode for the VF to true promiscuous and allow the VF to see all 
+NOTE: By default, the ethtool priv-flag vf-true-promisc-support is set to
+"off",meaning that promiscuous mode for the VF will be limited. To set the
+promiscuous mode for the VF to true promiscuous and allow the VF to see all
 ingress traffic, use the following command.
   #ethtool -set-priv-flags p261p1 vf-true-promisc-support on
-The vf-true-promisc-support priv-flag does not enable promiscuous mode; rather, 
-it designates which type of promiscuous mode (limited or true) you will get 
-when you enable promiscuous mode using the ip link commands above. Note that 
-this is a global setting that affects the entire device. However,the 
-vf-true-promisc-support priv-flag is only exposed to the first PF of the 
-device. The PF remains in limited promiscuous mode (unless it is in MFP mode) 
+The vf-true-promisc-support priv-flag does not enable promiscuous mode; rather,
+it designates which type of promiscuous mode (limited or true) you will get
+when you enable promiscuous mode using the ip link commands above. Note that
+this is a global setting that affects the entire device. However,the
+vf-true-promisc-support priv-flag is only exposed to the first PF of the
+device. The PF remains in limited promiscuous mode (unless it is in MFP mode)
 regardless of the vf-true-promisc-support setting.
 
 Now add a VLAN interface on the VF interface.
   #ip link add link eth2 name eth2.100 type vlan id 100
 
-Note that the order in which you set the VF to promiscuous mode and add the 
-VLAN interface does not matter (you can do either first). The end result in 
+Note that the order in which you set the VF to promiscuous mode and add the
+VLAN interface does not matter (you can do either first). The end result in
 this example is that the VF will get all traffic that is tagged with VLAN 100.
 
 
 Intel(R) Ethernet Flow Director
 -------------------------------
-NOTE: Intel Ethernet Flow Director parameters are only supported on kernel 
+NOTE: Intel Ethernet Flow Director parameters are only supported on kernel
 versions 2.6.30 or newer.
 
 The Intel Ethernet Flow Director performs the following tasks:
@@ -353,20 +361,20 @@ The Intel Ethernet Flow Director performs the following tasks:
 - Supports multiple parameters for flexible flow classification and load
   balancing (in SFP mode only).
 
-NOTE: An included script (set_irq_affinity) automates setting the IRQ to CPU 
+NOTE: An included script (set_irq_affinity) automates setting the IRQ to CPU
 affinity.
 
-NOTE: The Linux i40edriver supports the following flow types: IPv4, TCPv4, and 
-UDPv4. For a given flow type, it supports valid combinations of IP addresses 
-(source or destination) and UDP/TCP ports (source and destination). For 
-example, you can supply only a source IP address, a source IP address and a 
+NOTE: The Linux i40e driver supports the following flow types: IPv4, TCPv4, and
+UDPv4. For a given flow type, it supports valid combinations of IP addresses
+(source or destination) and UDP/TCP ports (source and destination). For
+example, you can supply only a source IP address, a source IP address and a
 destination port, or any combination of one or more of these four parameters.
 
-NOTE: The Linux i40edriver allows you to filter traffic based on a user-defined 
-flexible two-byte pattern and offset by using the ethtool user-def and mask 
-fields. Only L3 and L4 flow types are supported for user-defined flexible 
-filters. For a given flow type, you must clear all Intel Ethernet Flow Director 
-filters before changing the input set (for that flow type).
+NOTE: The Linux i40e driver allows you to filter traffic based on a
+user-defined flexible two-byte pattern and offset by using the ethtool user-def
+and mask fields. Only L3 and L4 flow types are supported for user-defined
+flexible filters. For a given flow type, you must clear all Intel Ethernet Flow
+Director filters before changing the input set (for that flow type).
 
 ethtool commands:
 
@@ -374,8 +382,8 @@ To enable or disable the Intel Ethernet Flow Director:
 
   # ethtool -K ethX ntuple <on|off>
 
-When disabling ntuple filters, all the user programed filters are flushed from 
-the driver cache and hardware. All needed filters must be re-added when ntuple 
+When disabling ntuple filters, all the user programmed filters are flushed from
+the driver cache and hardware. All needed filters must be re-added when ntuple
 is re-enabled.
 
 To add a filter that directs packet to queue 2, use -U or -N switch:
@@ -391,74 +399,77 @@ To set a filter using only the source and destination IP address:
 To set a filter based on a user defined pattern and offset:
 
   # ethtool -N ethX flow-type tcp4 src-ip 192.168.10.1 dst-ip \
-  192.168.10.2 user-def 0xffffffff00000001 m 0x40 action 2 [loc 1]
-
-  where the value of the user-def field (0xffffffff00000001) is the
-  pattern and m 0x40 is the offset.
+  192.168.10.2 user-def 0x4FFFF action 2 [loc 1]
 
-Note that in this case the mask (m 0x40) parameter is used with the user-def 
-field, whereas for cloud filter support the mask parameter is not used.
+  where the value of the user-def field contains the offset (4 bytes) and
+  the pattern (0xffff). This is described in more detail in the Sideband
+  Perfect Filters section.
 
 To see the list of filters currently present:
   # ethtool <-u|-n> ethX
 
+
 Application Targeted Routing (ATR) Perfect Filters
 --------------------------------------------------
-ATR is enabled by default when the kernel is in multiple transmit queue mode. 
-An ATR Intel Ethernet Flow Director filter rule is added when a TCP-IP flow 
-starts and is deleted when the flow ends. When a TCP-IP Intel Ethernet Flow 
-Director rule is added from ethtool (Sideband filter), ATR is turned off by the 
-driver. To re-enable ATR, the sideband can be disabled with the ethtool -K 
-option. If sideband is re-enabled after ATR is re-enabled, ATR remains enabled 
-until a TCP-IP flow is added. When all TCP-IP sideband rules are deleted, ATR 
-is automatically re-enabled.
-
-Packets that match the ATR rules are counted in fdir_atr_match stats in 
+ATR is enabled by default when the kernel is in multiple transmit queue mode.
+An ATR Intel Ethernet Flow Director filter rule is added when a TCP-IP flow
+starts and is deleted when the flow ends. When a TCP-IP Intel Ethernet Flow
+Director rule is added from ethtool (Sideband filter), ATR is turned off by the
+driver. To re-enable ATR, the sideband can be disabled with the ethtool -K
+option. For example:
+ethtool -K [adapter] ntuple [off|on]
+
+If sideband is re-enabled after ATR is re-enabled, ATR remains enabled until a
+TCP-IP flow is added. When all TCP-IP sideband rules are deleted, ATR is
+automatically re-enabled.
+
+Packets that match the ATR rules are counted in fdir_atr_match stats in
 ethtool, which also can be used to verify whether ATR rules still exist.
 
+
 Sideband Perfect Filters
 ------------------------
-Sideband Perfect Filters are used to direct traffic that matches specified 
-characteristics. They are enabled through ethtool's ntuple interface. To add a 
+Sideband Perfect Filters are used to direct traffic that matches specified
+characteristics. They are enabled through ethtool's ntuple interface. To add a
 new filter use the following command:
-  ethtool -U <device> flow-type <type> src-ip <ip> dst-ip <ip> src-port <port> 
+  ethtool -U <device> flow-type <type> src-ip <ip> dst-ip <ip> src-port <port>
 dst-port <port> action <queue>
 Where:
   <device> - the ethernet device to program
   <type> - can be ip4, tcp4, udp4, or sctp4
   <ip> - the ip address to match on
   <port> - the port number to match on
-  <queue> - the queue to direct traffic towards (-1 discards the matched 
+  <queue> - the queue to direct traffic towards (-1 discards the matched
 traffic)
 Use the following command to display all of the active filters:
   ethtool -u <device>
 Use the following command to delete a filter:
   ethtool -U <device> delete <N>
-Where <N> is the filter id displayed when printing all the active filters, and 
+Where <N> is the filter id displayed when printing all the active filters, and
 may also have been specified using "loc <N>" when adding the filter.
 
-The following example matches TCP traffic sent from 192.168.0.1, port 5300, 
+The following example matches TCP traffic sent from 192.168.0.1, port 5300,
 directed to 192.168.0.5, port 80, and sends it to queue 7:
   ethtool -U enp130s0 flow-type tcp4 src-ip 192.168.0.1 dst-ip 192.168.0.5
-  src-port 5300 dst-port 7 action 7
+  src-port 5300 dst-port 80 action 7
 
-For each flow-type, the programmed filters must all have the same matching 
+For each flow-type, the programmed filters must all have the same matching
 input set. For example, issuing the following two commands is acceptable:
   ethtool -U enp130s0 flow-type ip4 src-ip 192.168.0.1 src-port 5300 action 7
   ethtool -U enp130s0 flow-type ip4 src-ip 192.168.0.5 src-port 55 action 10
-Issuing the next two commands, however, is not acceptable, since the first 
+Issuing the next two commands, however, is not acceptable, since the first
 specifies src-ip and the second specifies dst-ip:
   ethtool -U enp130s0 flow-type ip4 src-ip 192.168.0.1 src-port 5300 action 7
   ethtool -U enp130s0 flow-type ip4 dst-ip 192.168.0.5 src-port 55 action 10
-The second command will fail with an error. You may program multiple filters 
-with the same fields, using different values, but, on one device, you may not 
+The second command will fail with an error. You may program multiple filters
+with the same fields, using different values, but, on one device, you may not
 program two tcp4 filters with different matching fields.
 
-Matching on a sub-portion of a field is not supported by the i40edriver, thus 
+Matching on a sub-portion of a field is not supported by the i40e driver, thus
 partial mask fields are not supported.
 
-The driver also supports matching user-defined data within the packet payload. 
-This flexible data is specified using the "user-def" field of the ethtool 
+The driver also supports matching user-defined data within the packet payload.
+This flexible data is specified using the "user-def" field of the ethtool
 command in the following way:
 +----------------------------+--------------------------+
 | 31    28    24    20    16 | 15    12    8    4    0  |
@@ -469,66 +480,66 @@ command in the following way:
 For example,
   ... user-def 0x4FFFF ...
 
-tells the filter to look 4 bytes into the payload and match that value against 
-0xFFFF. The offset is based on the beginning of the payload, and not the 
+tells the filter to look 4 bytes into the payload and match that value against
+0xFFFF. The offset is based on the beginning of the payload, and not the
 beginning of the packet. Thus
 
   flow-type tcp4 ... user-def 0x8BEAF ...
 
-would match TCP/IPv4 packets which have the value 0xBEAF 8 bytes into the 
+would match TCP/IPv4 packets which have the value 0xBEAF 8 bytes into the
 TCP/IPv4 payload.
 
-Note that ICMP headers are parsed as 4 bytes of header and 4 bytes of payload. 
-Thus to match the first byte of the payload, you must actually add 4 bytes to 
-the offset. Also note that ip4 filters match both ICMP frames as well as raw 
+Note that ICMP headers are parsed as 4 bytes of header and 4 bytes of payload.
+Thus to match the first byte of the payload, you must actually add 4 bytes to
+the offset. Also note that ip4 filters match both ICMP frames as well as raw
 (unknown) ip4 frames, where the payload will be the L3 payload of the IP4 frame.
 
-The maximum offset is 64. The hardware will only read up to 64 bytes of data 
-from the payload. The offset must be even because the flexible data is 2 bytes 
+The maximum offset is 64. The hardware will only read up to 64 bytes of data
+from the payload. The offset must be even because the flexible data is 2 bytes
 long and must be aligned to byte 0 of the packet payload.
 
-The user-defined flexible offset is also considered part of the input set and 
-cannot be programmed separately for multiple filters of the same type. However, 
-the flexible data is not part of the input set and multiple filters may use the 
+The user-defined flexible offset is also considered part of the input set and
+cannot be programmed separately for multiple filters of the same type. However,
+the flexible data is not part of the input set and multiple filters may use the
 same offset but match against different data.
 
-To create filters that direct traffic to a specific Virtual Function, use the 
-"action" parameter. Specify the action as a 64 bit value, where the lower 32 
+To create filters that direct traffic to a specific Virtual Function, use the
+"action" parameter. Specify the action as a 64 bit value, where the lower 32
 bits represents the queue number, while the next 8 bits represent which VF.
 Note that 0 is the PF, so the VF identifier is offset by 1. For example:
 
   ... action 0x800000002 ...
 
-specifies to direct traffic to Virtual Function 7 (8 minus 1) into queue 2 of 
+specifies to direct traffic to Virtual Function 7 (8 minus 1) into queue 2 of
 that VF.
 
-Note that these filters will not break internal routing rules, and will not 
-route traffic that otherwise would not have been sent to the specified Virtual 
+Note that these filters will not break internal routing rules, and will not
+route traffic that otherwise would not have been sent to the specified Virtual
 Function.
 
 
 Cloud Filter Support
 --------------------
-On a complex network that supports multiple types of traffic (such as for 
-storage as well as cloud), cloud filter support allows you to send one type of 
-traffic (for example, the storage traffic) to the Physical Function (PF) and 
-another type (say, the cloud traffic) to a Virtual Function (VF). Because cloud 
-networks are typically VXLAN/GENEVE-based, you can define a cloud filter to 
-identify VXLAN/GENEVE packets and send them to a queue in the VF to be 
-processed by the virtual machine (VM). Similarly, other cloud filters can be 
+On a complex network that supports multiple types of traffic (such as for
+storage as well as cloud), cloud filter support allows you to send one type of
+traffic (for example, the storage traffic) to the Physical Function (PF) and
+another type (say, the cloud traffic) to a Virtual Function (VF). Because cloud
+networks are typically VXLAN/GENEVE-based, you can define a cloud filter to
+identify VXLAN/GENEVE packets and send them to a queue in the VF to be
+processed by the virtual machine (VM). Similarly, other cloud filters can be
 designed for various other traffic tunneling.
 
-NOTE: Cloud filters are only supported when the underlying device is in Single 
+NOTE: Cloud filters are only supported when the underlying device is in Single
 Function per Port mode.
 
-NOTE: The "action -1" option, which drops matching packets in regular Intel 
-Ethernet Flow Director filters, is not available to drop packets when used with 
+NOTE: The "action -1" option, which drops matching packets in regular Intel
+Ethernet Flow Director filters, is not available to drop packets when used with
 cloud filters.
 
-NOTE: For IPv4 and ether flow-types, cloud filters cannot be used for TCP or 
+NOTE: For IPv4 and ether flow-types, cloud filters cannot be used for TCP or
 UDP filters.
 
-NOTE: Cloud filters can be used as a method for implementing queue splitting in 
+NOTE: Cloud filters can be used as a method for implementing queue splitting in
 the PF.
 
 The following filters are supported:
@@ -537,17 +548,21 @@ The following filters are supported:
     Inner MAC, Inner VLAN, Tenant ID (for NVGRE, VXLAN or GENEVE packets)
     Inner MAC, Tenant ID (NVGRE packet or VXLAN/GENEVE packets)
     Outer MAC L2 filter
+    Inner MAC filter
+    Outer MAC, Tenant ID, Inner MAC
+    Application Destination IP
+    Application Source-IP, Inner MAC
     ToQueue: Use MAC, VLAN to point to a queue
   L3 filters
     Application Destination IP
 
-Cloud filters are specified using ethtool's ntuple interface, but the driver 
-uses user-def to determine whether to treat the filter as a cloud filter or a 
-regular filter. To enable a cloud filter, set the highest bit of the user-def 
-field, "user-def 0x8000000000000000" to enable the cloud features described 
-below. This specifies to the driver to treat the filter specially and not treat 
-it like the regular filters described above. Note that cloud filters also read 
-the other bits in the user-def field separately so you cannot use the flexible 
+Cloud filters are specified using ethtool's ntuple interface, but the driver
+uses user-def to determine whether to treat the filter as a cloud filter or a
+regular filter. To enable a cloud filter, set the highest bit of the user-def
+field, "user-def 0x8000000000000000" to enable the cloud features described
+below. This specifies to the driver to treat the filter specially and not treat
+it like the regular filters described above. Note that cloud filters also read
+the other bits in the user-def field separately so you cannot use the flexible
 data feature described above.
 
 For regular Intel Ethernet Flow Director filters:
@@ -565,7 +580,7 @@ For L3 filters (non-tunneled packets):
 
   Example:
 
-    ethtool -U enp130s0 flow-type ip4 src-ip 192.168.42.13 dst-ip 192.168.42.33 
+    ethtool -U enp130s0 flow-type ip4 src-ip 192.168.42.13 dst-ip 192.168.42.33
 /
     src-port 12344 dst-port 12344 user-def 0x8000000000000000 action /
     0x200000000 loc 3
@@ -588,12 +603,12 @@ For cloud filters (tunneled packets):
 
   Example:
 
-    ethtool U enp130s0 flow-type ether dst 8b:9d:ed:6a:ce:43 \
+    ethtool -U enp130s0 flow-type ether dst 8b:9d:ed:6a:ce:43 \
     src 1d:44:9d:54:da:de user-def 0x8000000000000022 loc 38 \
     action 0x200000000
       Redirect traffic on VXLAN using tunnel id 34 (hex 0x22) coming from
       outer MAC address 8b:9d:ed:6a:ce:43 and inner MAC address
-      1d:44:9d:54:da:de into VF id 1 and call this “rule 38”.
+      1d:44:9d:54:da:de into VF id 1 and call this "rule 38".
 
 
 ================================================================================
@@ -602,22 +617,21 @@ For cloud filters (tunneled packets):
 Additional Features and Configurations
 -------------------------------------------
 
-
 Configuring the Driver on Different Distributions
 -------------------------------------------------
-Configuring a network driver to load properly when the system is started is 
-distribution dependent. Typically, the configuration process involves adding an 
-alias line to /etc/modules.conf or /etc/modprobe.conf as well as editing other 
-system startup scripts and/or configuration files. Many popular Linux 
-distributions ship with tools to make these changes for you. To learn the 
-proper way to configure a network device for your system, refer to your 
-distribution documentation. If during this process you are asked for the driver 
+Configuring a network driver to load properly when the system is started is
+distribution dependent. Typically, the configuration process involves adding an
+alias line to /etc/modules.conf or /etc/modprobe.conf as well as editing other
+system startup scripts and/or configuration files. Many popular Linux
+distributions ship with tools to make these changes for you. To learn the
+proper way to configure a network device for your system, refer to your
+distribution documentation. If during this process you are asked for the driver
 or module name, the name for the Base Driver is i40e.
 
 
 Setting the link-down-on-close Private Flag
 -------------------------------------------
-When the link-down-on-close private flag is set to "on", the port's link will 
+When the link-down-on-close private flag is set to "on", the port's link will
 go down when the interface is brought down using the ifconfig ethX down command.
 
 Use ethtool to view and set link-down-on-close, as follows:
@@ -627,8 +641,8 @@ Use ethtool to view and set link-down-on-close, as follows:
 
 Viewing Link Messages
 ---------------------
-Link messages will not be displayed to the console if the distribution is 
-restricting system messages. In order to see network driver link messages on 
+Link messages will not be displayed to the console if the distribution is
+restricting system messages. In order to see network driver link messages on
 your console, set dmesg to eight by entering the following:
 dmesg -n 8
 
@@ -637,10 +651,10 @@ NOTE: This setting is not saved across reboots.
 
 Jumbo Frames
 ------------
-Jumbo Frames support is enabled by changing the Maximum Transmission Unit (MTU) 
+Jumbo Frames support is enabled by changing the Maximum Transmission Unit (MTU)
 to a value larger than the default value of 1500.
 
-Use the ifconfig command to increase the MTU size. For example, enter the 
+Use the ifconfig command to increase the MTU size. For example, enter the
 following where <x> is the interface number:
 
    ifconfig eth<x> mtu 9000 up
@@ -648,23 +662,27 @@ Alternatively, you can use the ip command as follows:
    ip link set mtu 9000 dev eth<x>
    ip link set up dev eth<x>
 
-This setting is not saved across reboots. The setting change can be made 
+This setting is not saved across reboots. The setting change can be made
 permanent by adding 'MTU=9000' to the file:
 /etc/sysconfig/network-scripts/ifcfg-eth<x> for RHEL or to the file
 /etc/sysconfig/network/<config_file> for SLES.
 
-NOTE: The maximum MTU setting for Jumbo Frames is 9702. This value coincides 
+NOTE: The maximum MTU setting for Jumbo Frames is 9702. This value coincides
 with the maximum Jumbo Frames size of 9728 bytes.
 
-NOTE: This driver will attempt to use multiple page sized buffers to receive 
-each jumbo packet. This should help to avoid buffer starvation issues when 
+NOTE: This driver will attempt to use multiple page sized buffers to receive
+each jumbo packet. This should help to avoid buffer starvation issues when
 allocating receive packets.
 
+NOTE: Packet loss may have a greater impact on throughput when you use jumbo
+frames. If you observe a drop in performance after enabling jumbo frames,
+enabling flow control may mitigate the issue.
+
 
 ethtool
 -------
-The driver utilizes the ethtool interface for driver configuration and 
-diagnostics, as well as displaying statistical information. The latest ethtool 
+The driver utilizes the ethtool interface for driver configuration and
+diagnostics, as well as displaying statistical information. The latest ethtool
 version is required for this functionality. Download it at:
 http://ftp.kernel.org/pub/software/network/ethtool/
 
@@ -679,7 +697,7 @@ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|tcp6|udp6|ah6|esp6|sctp6
 -N --config-nfc
   Configures the receive network flow classification.
 
-rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|tcp6|udp6|ah6|esp6|sctp6 
+rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|tcp6|udp6|ah6|esp6|sctp6
 m|v|t|s|d|f|n|r...
   Configures the hash options for the specified network traffic type.
 
@@ -692,38 +710,38 @@ m|v|t|s|d|f|n|r...
 
 Speed and Duplex Configuration
 ------------------------------
-In addressing speed and duplex configuration issues, you need to distinguish 
+In addressing speed and duplex configuration issues, you need to distinguish
 between copper-based adapters and fiber-based adapters.
 
-In the default mode, an Intel(R) Ethernet Network Adapter using copper 
-connections will attempt to auto-negotiate with its link partner to determine 
-the best setting. If the adapter cannot establish link with the link partner 
-using auto-negotiation, you may need to manually configure the adapter and link 
-partner to identical settings to establish link and pass packets. This should 
-only be needed when attempting to link with an older switch that does not 
-support auto-negotiation or one that has been forced to a specific speed or 
-duplex mode. Your link partner must match the setting you choose. 1 Gbps speeds 
-and higher cannot be forced. Use the autonegotiation advertising setting to 
+In the default mode, an Intel(R) Ethernet Network Adapter using copper
+connections will attempt to auto-negotiate with its link partner to determine
+the best setting. If the adapter cannot establish link with the link partner
+using auto-negotiation, you may need to manually configure the adapter and link
+partner to identical settings to establish link and pass packets. This should
+only be needed when attempting to link with an older switch that does not
+support auto-negotiation or one that has been forced to a specific speed or
+duplex mode. Your link partner must match the setting you choose. 1 Gbps speeds
+and higher cannot be forced. Use the autonegotiation advertising setting to
 manually set devices for 1 Gbps and higher.
 
-NOTE: You cannot set the speed for devices based on the Intel(R) Ethernet 
+NOTE: You cannot set the speed for devices based on the Intel(R) Ethernet
 Network Adapter XXV710 based devices.
 
-Speed, duplex, and autonegotiation advertising are configured through the 
-ethtool* utility. ethtool is included with all versions of Red Hat after Red 
-Hat 7.2. For the latest version, download and install ethtool from the 
+Speed, duplex, and autonegotiation advertising are configured through the
+ethtool* utility. ethtool is included with all versions of Red Hat after Red
+Hat 7.2. For the latest version, download and install ethtool from the
 following website:
 
    http://ftp.kernel.org/pub/software/network/ethtool/
 
-Caution: Only experienced network administrators should force speed and duplex 
-or change autonegotiation advertising manually. The settings at the switch must 
-always match the adapter settings. Adapter performance may suffer or your 
-adapter may not operate if you configure the adapter differently from your 
+Caution: Only experienced network administrators should force speed and duplex
+or change autonegotiation advertising manually. The settings at the switch must
+always match the adapter settings. Adapter performance may suffer or your
+adapter may not operate if you configure the adapter differently from your
 switch.
 
-An Intel(R) Ethernet Network Adapter using fiber-based connections, however, 
-will not attempt to auto-negotiate with its link partner since those adapters 
+An Intel(R) Ethernet Network Adapter using fiber-based connections, however,
+will not attempt to auto-negotiate with its link partner since those adapters
 operate only in full duplex and only at their native speed.
 
 
@@ -736,11 +754,11 @@ https://www.linuxfoundation.org/collaborate/workgroups/networking/napi
 
 Flow Control
 ------------
-Ethernet Flow Control (IEEE 802.3x) can be configured with ethtool to enable 
-receiving and transmitting pause frames for i40e. When transmit is enabled, 
-pause frames are generated when the receive packet buffer crosses a predefined 
-threshold. When receive is enabled, the transmit unit will halt for the time 
-delay specified when a pause frame is received. 
+Ethernet Flow Control (IEEE 802.3x) can be configured with ethtool to enable
+receiving and transmitting pause frames for i40e. When transmit is enabled,
+pause frames are generated when the receive packet buffer crosses a predefined
+threshold. When receive is enabled, the transmit unit will halt for the time
+delay specified when a pause frame is received.
 
 NOTE: You must have a flow control capable link partner.
 
@@ -750,20 +768,20 @@ Use ethtool to change the flow control settings.
 
 To enable or disable rx or tx Flow Control:
 ethtool -A eth? rx <on|off> tx <on|off>
-Note: This command only enables or disables Flow Control if auto-negotiation is 
-disabled. If auto-negotiation is enabled, this command changes the parameters 
+Note: This command only enables or disables Flow Control if auto-negotiation is
+disabled. If auto-negotiation is enabled, this command changes the parameters
 used for auto-negotiation with the link partner.
 
 To enable or disable auto-negotiation:
 ethtool -s eth? autoneg <on|off>
-Note: Flow Control auto-negotiation is part of link auto-negotiation. Depending 
+Note: Flow Control auto-negotiation is part of link auto-negotiation. Depending
 on your device, you may not be able to change the auto-negotiation setting.
 
 
 RSS Hash Flow
 -------------
 
-Allows you to set the hash bytes per flow type and any combination of one or 
+Allows you to set the hash bytes per flow type and any combination of one or
 more options for Receive Side Scaling (RSS) hash byte configuration.
 
 #ethtool -N <dev> rx-flow-hash <type> <option>
@@ -782,8 +800,7 @@ And <option> is one or more of:
 
 MAC and VLAN anti-spoofing feature
 ----------------------------------
-
-When a malicious driver attempts to send a spoofed packet, it is dropped by the 
+When a malicious driver attempts to send a spoofed packet, it is dropped by the
 hardware and not transmitted.
 NOTE: This feature can be disabled for a specific Virtual Function (VF):
 ip link set <pf dev> vf <vf id> spoofchk {off|on}
@@ -791,21 +808,19 @@ ip link set <pf dev> vf <vf id> spoofchk {off|on}
 
 IEEE 1588 Precision Time Protocol (PTP) Hardware Clock (PHC)
 ------------------------------------------------------------
-
-Precision Time Protocol (PTP) is used to synchronize clocks in a computer 
-network. PTP support varies among Intel devices that support this driver. Use 
-"ethtool -T <netdev name>" to get a definitive list of PTP capabilities 
+Precision Time Protocol (PTP) is used to synchronize clocks in a computer
+network. PTP support varies among Intel devices that support this driver. Use
+"ethtool -T <netdev name>" to get a definitive list of PTP capabilities
 supported by the device.
 
 
-
-IEEE 802.1ad (QinQ) Support
+IEEE 802.1ad (QinQ) Support
 ---------------------------
 
-The IEEE 802.1ad standard, informally known as QinQ, allows for multiple VLAN 
-IDs within a single Ethernet frame. VLAN IDs are sometimes referred to as 
-"tags," and multiple VLAN IDs are thus referred to as a "tag stack." Tag stacks 
-allow L2 tunneling and the ability to segregate traffic within a particular 
+The IEEE 802.1ad standard, informally known as QinQ, allows for multiple VLAN
+IDs within a single Ethernet frame. VLAN IDs are sometimes referred to as
+"tags," and multiple VLAN IDs are thus referred to as a "tag stack." Tag stacks
+allow L2 tunneling and the ability to segregate traffic within a particular
 VLAN ID, among other uses.
 
 The following are examples of how to configure 802.1ad (QinQ):
@@ -815,36 +830,36 @@ Where "24" and "371" are example VLAN IDs.
 
 NOTES:
 - 802.1ad (QinQ)is supported in 3.19 and later kernels.
-- Receive checksum offloads, cloud filters, and VLAN acceleration are not 
+- Receive checksum offloads, cloud filters, and VLAN acceleration are not
 supported for 802.1ad (QinQ) packets.
 
 
 VXLAN and GENEVE Overlay HW Offloading
 --------------------------------------
 
-Virtual Extensible LAN (VXLAN) allows you to extend an L2 network over an L3 
-network, which may be useful in a virtualized or cloud environment. Some 
-Intel(R) Ethernet Network devices perform VXLAN processing, offloading it from 
+Virtual Extensible LAN (VXLAN) allows you to extend an L2 network over an L3
+network, which may be useful in a virtualized or cloud environment. Some
+Intel(R) Ethernet Network devices perform VXLAN processing, offloading it from
 the operating system. This reduces CPU utilization.
-VXLAN offloading is controlled by the tx and rx checksum offload options 
-provided by ethtool. That is, if tx checksum offload is enabled, and the 
+
+VXLAN offloading is controlled by the tx and rx checksum offload options
+provided by ethtool. That is, if tx checksum offload is enabled, and the
 adapter has the capability, VXLAN offloading is also enabled.
 
-Support for VXLAN and GENEVE HW offloading is dependent on kernel support of 
+Support for VXLAN and GENEVE HW offloading is dependent on kernel support of
 the HW offloading features.
 
 
 Multiple Functions per Port
 ---------------------------
 
-Some adapters based on the Intel Ethernet Controller X710/XL710 support 
-multiple functions on a single physical port. Configure these functions through 
+Some adapters based on the Intel Ethernet Controller X710/XL710 support
+multiple functions on a single physical port. Configure these functions through
 the System Setup/BIOS.
 
-Minimum TX Bandwidth is the guaranteed minimum data transmission bandwidth, as 
-a percentage of the full physical port link speed, that the partition will 
-receive. The bandwidth the partition is awarded will never fall below the level 
+Minimum TX Bandwidth is the guaranteed minimum data transmission bandwidth, as
+a percentage of the full physical port link speed, that the partition will
+receive. The bandwidth the partition is awarded will never fall below the level
 you specify.
 
 The range for the minimum bandwidth values is:
@@ -852,52 +867,51 @@ The range for the minimum bandwidth values is:
 For example, if a physical port has 4 partitions, the range would be:
 1 to ((100 - 4) + 1 = 97)
 
-The Maximum Bandwidth percentage represents the maximum transmit bandwidth 
-allocated to the partition as a percentage of the full physical port link 
-speed. The accepted range of values is 1-100. The value is used as a limiter, 
-should you chose that any one particular function not be able to consume 100% 
-of a port's bandwidth (should it be available). The sum of all the values for 
-Maximum Bandwidth is not restricted, because no more than 100% of a port's 
+The Maximum Bandwidth percentage represents the maximum transmit bandwidth
+allocated to the partition as a percentage of the full physical port link
+speed. The accepted range of values is 1-100. The value is used as a limiter,
+should you chose that any one particular function not be able to consume 100%
+of a port's bandwidth (should it be available). The sum of all the values for
+Maximum Bandwidth is not restricted, because no more than 100% of a port's
 bandwidth can ever be used.
 
-NOTE: X710/XXV710 devices fail to enable Max VFs (64) when Multiple Functions 
-per Port (MFP) and SR-IOV are enabled. An error from i40e is logged that says 
-"add vsi failed for VF N, aq_err 16". To workaround the issue, enable less than 
+NOTE: X710/XXV710 devices fail to enable Max VFs (64) when Multiple Functions
+per Port (MFP) and SR-IOV are enabled. An error from i40e is logged that says
+"add vsi failed for VF N, aq_err 16". To workaround the issue, enable less than
 64 virtual functions (VFs).
 
 
 Data Center Bridging (DCB)
 --------------------------
-
 NOTE:
-The kernel assumes that TC0 is available, and will disable Priority Flow 
-Control (PFC) on the device if TC0 is not available. To fix this, ensure TC0 is 
+The kernel assumes that TC0 is available, and will disable Priority Flow
+Control (PFC) on the device if TC0 is not available. To fix this, ensure TC0 is
 enabled when setting up DCB on your switch.
 
 
-DCB is a configuration Quality of Service implementation in hardware. It uses 
-the VLAN priority tag (802.1p) to filter traffic. That means that there are 8 
-different priorities that traffic can be filtered into. It also enables 
-priority flow control (802.1Qbb) which can limit or eliminate the number of 
-dropped packets during network stress. Bandwidth can be allocated to each of 
+DCB is a configuration Quality of Service implementation in hardware. It uses
+the VLAN priority tag (802.1p) to filter traffic. That means that there are 8
+different priorities that traffic can be filtered into. It also enables
+priority flow control (802.1Qbb) which can limit or eliminate the number of
+dropped packets during network stress. Bandwidth can be allocated to each of
 these priorities, which is enforced at the hardware level (802.1Qaz).
 
-Adapter firmware implements LLDP and DCBX protocol agents as per 802.1AB and 
-802.1Qaz respectively. The firmware based DCBX agent runs in willing mode only 
-and can accept settings from a DCBX capable peer. Software configuration of 
+Adapter firmware implements LLDP and DCBX protocol agents as per 802.1AB and
+802.1Qaz respectively. The firmware based DCBX agent runs in willing mode only
+and can accept settings from a DCBX capable peer. Software configuration of
 DCBX parameters via dcbtool/lldptool are not supported.
 
 NOTE: Firmware LLDP can be disabled by setting the private flag disable-fw-lldp.
 
-The i40e driver implements the DCB netlink interface layer to allow user-space 
+The i40e driver implements the DCB netlink interface layer to allow user-space
 to communicate with the driver and query DCB configuration for the port.
 
 
 Interrupt Rate Limiting
 -----------------------
 
-The Intel(R) Ethernet Controller XL710 family supports an interrupt rate 
-limiting mechanism. The user can control, via ethtool, the number of 
+The Intel(R) Ethernet Controller XL710 family supports an interrupt rate
+limiting mechanism. The user can control, via ethtool, the number of
 microseconds between interrupts.
 
 Syntax:
@@ -905,32 +919,327 @@ Syntax:
 
 Valid Range: 0-235 (0=no limit)
 
-The range of 0-235 microseconds provides an effective range of 4,310 to 250,000 
-interrupts per second. The value of rx-usecs-high can be set independently of 
-rx-usecs and tx-usecs in the same ethtool command, and is also independent of 
-the adaptive interrupt moderation algorithm. The underlying hardware supports 
-granularity in 4-microsecond intervals, so adjacent values may result in the 
+The range of 0-235 microseconds provides an effective range of 4,310 to 250,000
+interrupts per second. The value of rx-usecs-high can be set independently of
+rx-usecs and tx-usecs in the same ethtool command, and is also independent of
+the adaptive interrupt moderation algorithm. The underlying hardware supports
+granularity in 4-microsecond intervals, so adjacent values may result in the
 same interrupt rate.
 
 One possible use case is the following:
 # ethtool -C ethX adaptive-rx off adaptive-tx off rx-usecs-high 20 rx-usecs 5
 tx-usecs 5
 
-The above command would disable adaptive interrupt moderation, and allow a 
-maximum of 5 microseconds before indicating a receive or transmit was complete. 
-However, instead of resulting in as many as 200,000 interrupts per second, it 
+The above command would disable adaptive interrupt moderation, and allow a
+maximum of 5 microseconds before indicating a receive or transmit was complete.
+However, instead of resulting in as many as 200,000 interrupts per second, it
 limits total interrupts per second to 50,000 via the rx-usecs-high parameter.
 
 
+Application Device Queues (ADQ)
+-------------------------------
+Application Device Queues (ADQ) allows you to dedicate one or more queues to a
+specific application. This can reduce latency for the specified application,
+and allow Tx traffic to be rate limited per application. Follow the steps below
+to set ADQ.
+
+Requirements:
+- Kernel version 4.15 or later
+- The sch_mqprio, act_mirred and cls_flower modules must be loaded
+- The latest version of iproute2
+- NVM version 6.01 or later
+- ADQ cannot be enabled when any the following features are enabled: Data
+Center Bridging (DCB), Multiple Functions per Port (MFP), or Sideband Filters.
+- If another driver (for example, DPDK) has set cloud filters, you cannot
+enable ADQ.
+
+1. Create traffic classes (TCs). You can create a maximum of 8 TCs per
+interface. The shaper bw_rlimit parameter is optional.
+
+This example sets up two tcs, tc0 and tc1, with 16 queues each and max tx rate
+set to 1Gbit for tc0 and 3Gbit for tc1:
+  # tc qdisc add dev <interface> root mqprio num_tc 2 map 0 0 0 0 1 1 1 1
+  queues 16@0 16@16 hw 1 mode channel shaper bw_rlimit min_rate 1Gbit 2Gbit
+  max_rate 1Gbit 3Gbit
+
+Where
+map: priority mapping for up to 16 priorities to tcs (e.g. map 0 0 0 0 1 1 1 1
+sets priorities 0-3 to use tc0 and 4-7 to use tc1)
+
+queues: for each tc, <num queues>@<offset> (e.g. queues 16@0 16@16 assigns 16
+queues to tc0 at offset 0 and 16 queues to tc1 at offset 16. Max total number
+of queues for all tcs is 64 or number of cores, whichever is lower.)
+
+hw 1 mode channel: 'channel' with 'hw' set to 1 is a new new hardware offload
+mode in mqprio that makes full use of the mqprio options, the TCs, the queue
+configurations, and the QoS parameters.
+
+shaper bw_rlimit: for each tc, sets minimum and maximum bandwidth rates. The
+totals must be equal or less than port speed. For example:
+  min_rate 1Gbit 3Gbit:
+Verify bandwidth limit using network monitoring tools such as ifstat or sar -n
+DEV [interval] [number of samples]
+
+NOTE: Setting up channels via ethtool (ethtool -L) is not supported when the
+TCs are configured using mqprio.
+
+2. Enable HW TC offload on interface:
+  # ethtool -K <interface> hw-tc-offload on
+
+3. Apply TCs to ingress (RX) flow of interface:
+  # tc qdisc add dev <interface> ingress
+
+NOTES:
+- Tunnel filters are not supported in ADQ. If encapsulated packets do arrive in
+non-tunnel mode, filtering will be done on the inner headers. For example, for
+VXLAN traffic in non-tunnel mode, if PCTYPE is identified as a VXLAN
+encapsulated packet, then the outer headers are ignored. Therefore, inner
+headers are matched.
+- If a TC filter on a PF matches traffic over a VF (on the PF), that traffic
+will be routed to the appropriate queue of the PF, and will not be passed on
+the VF. Such traffic will end up getting dropped higher up in the TCP/IP stack
+as it does not match PF address data.
+- If traffic matches multiple TC filters that point to different TCs, that
+traffic will be duplicated and sent to all matching TC queues. The hardware
+switch mirrors the packet to a VSI list when multiple filters are matched.
+
+
+Forward Error Correction (FEC)
+------------------------------
+Allows you to set the Forward Error Correction (FEC) mode. FEC improves link
+stability, but increases latency. Many high quality optics, direct attach
+cables, and backplane channels provide a stable link without FEC.
+
+NOTE: For devices to benefit from this feature, link partners must have FEC
+enabled.
+
+On kernels older than 4.14, use the following private flags to disable
+FEC modes:
+  rs-fec (0 to disable, 1 to enable)
+  base-r-fec (0 to disable, 1 to enable)
+On kernel 4.14 or later, use ethtool to get/set the following FEC modes:
+  No FEC
+  Auto FEC
+  BASE-R FEC
+  RS FEC
+
+
+SR-IOV Hypervisor Management Interface
+--------------------------------------
+The sysfs file structure below supports the SR-IOV hypervisor management
+interface.
+
+/sys/class/net/<interface-name>/device/sriov (see 1 below)
++-- [VF-id, 0 .. 127] (see 2 below)
+| +-- trunk
+| +-- vlan_mirror
+| +-- engress_mirror
+| +-- ingress_mirror
+| +-- mac_anti_spoof
+| +-- vlan_anti_spoof
+| +-- loopback
+| +-- mac
+| +-- mac_list
+| +-- promisc
+| +-- vlan_strip
+| +-- stats
+| +-- link_state
+| +-- max_tx_rate
+| +-- min_tx_rate
+| +-- spoofcheck
+| +-- trust
+| +-- vlan
+*1: kobject started from “sriov” is not available from existing kernel
+sysfs, and it requires device driver to implement this interface.
+*2: assume maximum # of VF supported by a PF is 128. To support a device
+that supports more than 128 SR-IOV instances, a “vfx” is added to 0..127.
+With “vfx” kboject, users need to add vf index as the first parameter and
+followed by “:”.
+
+SR-IOV hypervisor functions:
+
+- trunk
+  Supports two operations: add and rem.
+  - add: adds one or more VLAN id into VF VLAN filtering.
+  - rem: removes VLAN ids from the VF VLAN filtering list.
+  Example 1: add multiple VLAN tags, VLANs 2,4,5,10-20, by PF, p1p2, on
+  a selected VF, 1, for filtering, with the sysfs support:
+  #echo add 2,4,5,10-20 > /sys/class/net/p1p2/device/sriov/1/trunk
+  Example 2: remove VLANs 5, 11-13 from PF p1p2 VF 1 with sysfs:
+  #echo rem 5,11-13 > /sys/class/net/p1p2/device/sriov/1/trunk
+  Note: for rem, if VLAN id is not on the VLAN filtering list, the
+  VLAN id will be ignored.
+
+- vlan_mirror
+  Supports both ingress and egress traffic mirroring.
+  Example 1: mirror traffic based upon VLANs 2,4,6,18-22 to VF 3 of PF p1p1.
+  # echo add 2,4,6,18-22 > /sys/class/net/p1p1/device/sriov/3/vlan_mirror
+  Example 2: remove VLAN 4, 15-17 from traffic mirroring at destination VF 3.
+  # echo rem 15-17 > /sys/class/net/p1p1/device/sriov/3/vlan_mirror
+  Example 3: remove all VLANs from mirroring at VF 3.
+  # echo rem 0 - 4095> /sys/class/net/p1p1/device/sriov/3/vlan_mirror
+
+- egress_mirror
+  Supports egress traffic mirroring.
+  Example 1: add egress traffic mirroring on PF p1p2 VF 1 to VF 7.
+  #echo add 7 > /sys/class/net/p1p2/device/sriov/1/egress_mirror
+  Example 2: remove egress traffic mirroring on PF p1p2 VF 1 to VF 7.
+  #echo rem 7 > /sys/class/net/p1p2/device/sriov/1/egress_mirror
+
+- ingress_mirror
+  Supports ingress traffic mirroring.
+  Example 1: mirror ingress traffic on PF p1p2 VF 1 to VF 7.
+  #echo add 7 > /sys/class/net/p1p2/device/sriov/1/ingress_mirror
+  Example 2: show current ingress mirroring configuration.
+  #cat /sys/class/net/p1p2/device/sriov/1/ingress_mirror
+
+- mac_anti_spoof
+  Supports Enable/Disable MAC anti-spoof. Allows VFs to transmit packets with
+  any SRC MAC, which is needed for some L2 applications as well as vNIC bonding
+  within VMs if set to OFF.
+  Example 1: enable MAC anti-spoof for PF p2p1 VF 1.
+  #echo ON /sys/class/net/p1p2/device/sriov/1/mac_anti_spoof
+  Example 2: disable MAC anti-spoof for PF p2p1 VF 1.
+  #echo OFF /sys/class/net/p1p2/device/sriov/1/mac_anti_spoof
+
+- vlan_anti_spoof
+  Supports Enable/Disable VLAN anti-spoof. Allows VFs to transmit packets only
+  with VLAN tag specified in “trunk” settings, also will not allow to transmit
+  “untagged” packets if set to ON. Violation have to increment tx_spoof stats
+  counter.
+  Example 1: enable VLAN anti-spoof for PF p2p1 VF 1.
+  #echo ON /sys/class/net/p1p2/device/sriov/1/vlan_anti_spoof
+  Example 2: disable VLAN anti-spoof for PF p2p1 VF 1.
+  #echo OFF /sys/class/net/p1p2/device/sriov/1/vlan_anti_spoof
+
+- loopback
+  Supports Enable/Disable VEB/VEPA (Local loopback).
+  Example 1: allow traffic switching between VFs on the same PF.
+  #echo ON > /sys/class/net/p1p2/device/sriov/loopback
+  Example 2: send Hairpin traffic to the switch to which the PF is connected.
+  #echo OFF > /sys/class/net/p1p2/device/sriov/loopback
+  Example 3: show loopback configuration.
+  #cat /sys/class/net/p1p2/device/sriov/loopback
+
+- mac
+  Supports setting default MAC address. If MAC address is set by this
+  command, the PF will not allow VF to change it using an MBOX request.
+  Example 1: set default MAC address to VF 1.
+  #echo "00:11:22:33:44:55" > /sys/class/net/p1p2/device/sriov/1/mac
+  Example 2: show default MAC address.
+  #cat /sys/class/net/p1p2/device/sriov/1/mac
+
+- mac_list
+  Supports adding additional MACs to the VF. The default MAC is taken from
+  "ip link set p1p2 vf 1 mac 00:11:22:33:44:55" if configured. If not, a random
+  address is assigned to the VF by the NIC. If the MAC is configured using
+the IP LINK command, the VF cannot change it via MBOX/AdminQ requests.
+  Example 1: add mac 00:11:22:33:44:55 and 00:66:55:44:33:22 to PF p1p2 VF 1.
+  #echo add "00:11:22:33:44:55,00:66:55:44:33:22" >
+  /sys/class/net/p1p2/device/sriov/1/mac_list
+  Example 2: delete mac 00:11:22:33:44:55 from above VF device.
+  #echo rem 00:11:22:33:44:55 > /sys/class/net/p1p2/device/sriov/1/mac_list
+  Example 3: display a VF MAC address list.
+  #cat /sys/class/net/p1p2/device/sriov/1/mac_lis
+
+- promisc
+  Supports setting/unsetting VF device unicast promiscuous mode and multicast
+  promiscuous mode.
+  Example 1: set MCAST promiscuous on PF p1p2 VF 1.
+  #echo add mcast > /sys/class/net/p1p2/device/sriov/1/promisc
+  Example 2: set UCAST promiscuous on PF p1p2 VF 1.
+  #echo add ucast > /sys/class/net/p1p2/device/sriov/1/promisc
+  Example 3: unset MCAST promiscuous on PF p1p2 VF 1.
+  #echo rem mcast > /sys/class/net/p1p2/device/sriov/1/promisc
+  Example 4: show current promiscuous mode configuration.
+  #cat /sys/class/net/p1p2/device/sriov/1/promisc
+
+- vlan_strip
+  Supports enabling/disabling VF device outer VLAN stripping
+  Example 1: enable VLAN strip on VF 3.
+  # echo ON > /sys/class/net/p1p1/device/sriov/3/vlan_strip
+  Example 2: disable VLAN striping VF 3.
+  # echo OFF > /sys/class/net/p1p1/device/sriov/3/vlan_strip
+
+- stats
+  Supports getting VF statistics
+  Example 1: display anti-spoofing violations counter for VF 1.
+  #cat /sys/class/net/p1p2/device/sriov/1/stats/tx_spoofed
+
+- link_state
+  Sets/displays link status.
+  Example 1: display link status on link speed.
+  #cat /sys/class/net/p1p2/device/sriov/1/link_state
+  Example 2 set VF 1 to track status of PF link.
+  #echo auto > /sys/class/net/p1p2/device/sriov/1/link_state
+  Example 3: disable VF 1.
+  #echo disable > /sys/class/net/p1p2/device/sriov/1/link_state
+
+
+Dynamic Device Personalization
+------------------------------
+Dynamic Device Personalization (DDP) allows you to change the packet processing
+pipeline of a device by applying a profile package to the device at runtime.
+Profiles can be used to, for example, add support for new protocols, change
+existing protocols, or change default settings. DDP profiles can also be rolled
+back without rebooting the system.
+Requirements:
+-Intel Ethernet X710/XXV710/XL710 adapter (X722 series devices are not
+supported at this time)
+-Firmware 6.0 or newer
+-RHEL 7.5 or later or Linux Kernel 4.0.1 or newer
+
+To apply a profile, copy it first to intel/i40e/ddp directory relative to your
+firmware root (usually /lib/firmware).
+For example:
+  /lib/firmware/intel/i40e/ddp
+
+Then use the ethtool -f|--flash flag with region 100:
+ethtool -f <interface name> <profile name> 100
+
+For example:
+  ethtool -f eth0 gtp.pkgo 100
+
+You can roll back to a previously loaded profile using '-' instead of profile
+name:
+ethtool -f <interface name> - 100
+
+For example:
+  ethtool -f eth0 - 100
+
+For every rollback request one profile will be removed, from last to first
+(LIFO) order.
+
+NOTES:
+- DDP profiles are loaded only on the interface corresponding to first physical
+function of the device (PF0), but the configuration is applied to all ports of
+the adapter.
+- DDP profiles are not persistent. A system reboot will reset the device to its
+default configuration.
+- DDP profiles are NOT automatically unloaded when the driver in
+unbound/unloaded. Please note that subsequent driver reload may corrupt the
+profile configuration during its initialization and is NOT recommended.
+- DDP profiles should be manually rolled-back before driver unload/unbind if
+the intention is to start with clean HW configuration.
+- Exercise caution while loading DDP profiles, attempting to load files other
+than DDP profiles provided by Intel may cause system instability, system
+crashes, or system hangs.
+
+More details about Dynamic Device Personalization can be found on the Intel
+Developer Zone site:
+https://software.intel.com/en-us/articles/dynamic-device-personalization-for-int
+el-ethernet-700-series
+
+
 Performance Optimization:
 -------------------------
 
-Driver defaults are meant to fit a wide variety of workloads, but if further 
+Driver defaults are meant to fit a wide variety of workloads, but if further
 optimization is required we recommend experimenting with the following settings.
 
-NOTE: For better performance when processing small (64B) frame sizes, try 
-enabling Hyper threading in the BIOS in order to increase the number of logical 
-cores in the system and subsequently increase the number of queues available to 
+NOTE: For better performance when processing small (64B) frame sizes, try
+enabling Hyper threading in the BIOS in order to increase the number of logical
+cores in the system and subsequently increase the number of queues available to
 the adapter.
 
 Virtualized Environments:
@@ -950,8 +1259,8 @@ Virtualized Environments:
 
 Non-virtualized Environments
 
-Pin the adapter's IRQs to specific cores by disabling the irqbalance service 
-and using the included set_irq_affinity script. Please see the script's help 
+Pin the adapter's IRQs to specific cores by disabling the irqbalance service
+and using the included set_irq_affinity script. Please see the script's help
 text for further options.
 
   - The following settings will distribute the IRQs across all the cores
@@ -966,28 +1275,28 @@ text for further options.
 
 For very CPU intensive workloads, we recommend pinning the IRQs to all cores.
 
-For IP Forwarding: Disable Adaptive ITR and lower rx and tx interrupts per 
+For IP Forwarding: Disable Adaptive ITR and lower rx and tx interrupts per
 queue using ethtool.
 
   - Setting rx-usecs and tx-usecs to 125 will limit interrupts to about 8000
     interrupts per second per queue.
 
-    # ethtool -C <interface> adaptive-rx off adaptive-tx off rx-usecs 125 
+    # ethtool -C <interface> adaptive-rx off adaptive-tx off rx-usecs 125
     tx-usecs 125
 
-For lower CPU utilization: Disable Adaptive ITR and lower rx and tx interrupts 
+For lower CPU utilization: Disable Adaptive ITR and lower rx and tx interrupts
 per queue using ethtool.
 
   - Setting rx-usecs and tx-usecs to 250 will limit interrupts to about 4000
     interrupts per second per queue.
 
-    # ethtool -C <interface> adaptive-rx off adaptive-tx off rx-usecs 250 
+    # ethtool -C <interface> adaptive-rx off adaptive-tx off rx-usecs 250
     tx-usecs 250
 
-For lower latency: Disable Adaptive ITR and ITR by setting rx and tx to 0 using 
+For lower latency: Disable Adaptive ITR and ITR by setting rx and tx to 0 using
 ethtool.
 
-    # ethtool -C <interface> adaptive-rx off adaptive-tx off rx-usecs 0 
+    # ethtool -C <interface> adaptive-rx off adaptive-tx off rx-usecs 0
     tx-usecs 0
 
 
@@ -995,109 +1304,118 @@ ethtool.
 
 
 Known Issues/Troubleshooting
-----------------------------
+============================
+
+LACP PDUs not being sent
+------------------------
+Configuring bonding interface of mode 4 (802.3ad) on Ubuntu 14.04.5 will
+require manually recompiling the kernel with additional patch applied:
+ https://lore.kernel.org/patchwork/patch/651248/
+
+The reason for that is because Ubuntu's kernel 4.4 backports new
+ethtool GKLINKSETTINGS API from kernel 4.6 without tuning bonding driver
+to actually use it.
 
 
 Failure to enable MAX VFs when MFP and SR-IOV enabled
 -----------------------------------------------------
-
-X710/XXV710 devices fail to enable Max VFs (64) when Multiple Functions per 
-Port (MFP) and SR-IOV are enabled. An error from i40e is logged that says "add 
-vsi failed for VF N, aq_err 16". To workaround the issue, enable less than 64 
+X710/XXV710 devices fail to enable Max VFs (64) when Multiple Functions per
+Port (MFP) and SR-IOV are enabled. An error from i40e is logged that says "add
+vsi failed for VF N, aq_err 16". To workaround the issue, enable less than 64
 virtual functions (VFs).
 
 
 ip link show command shows incorrect VF MAC if VF MAC was set from VF side
 --------------------------------------------------------------------------
-Executing the command "ip link show" only shows MAC addresses if they are set 
+Executing the command "ip link show" only shows MAC addresses if they are set
 by the PF. Otherwise, it shows all zeros.
 
-This is expected behavior. The PF driver is passing zeroes to the VF driver 
-that the VF driver can generate its own random MAC address and report it to the 
-guest OS. Without this feature, some guest operating systems will incorrectly 
+This is expected behavior. The PF driver is passing zeroes to the VF driver
+that the VF driver can generate its own random MAC address and report it to the
+guest OS. Without this feature, some guest operating systems will incorrectly
 assign the VF a new interface name each time they reboot.
 
 
 SSL error (No such file) when installing driver on Ubuntu 14.04
 ---------------------------------------------------------------
-When installing the driver on Ubuntu 14.04, you may get an SSL error stating 
-"no such file or directory." This issue does not affect driver installation or 
+When installing the driver on Ubuntu 14.04, you may get an SSL error stating
+"no such file or directory." This issue does not affect driver installation or
 performance and can be ignored.
 
 
 IPv6/UDP checksum offload does not work on some older kernels
 -------------------------------------------------------------
-Some distributions with older kernels do not properly enable IPv6/UDP checksum 
-offload. To use IPv6 checksum offload, it may be necessary to upgrade to a 
+Some distributions with older kernels do not properly enable IPv6/UDP checksum
+offload. To use IPv6 checksum offload, it may be necessary to upgrade to a
 newer kernel.
 
 
 Poor performance when using VXLAN encapsulation
 -----------------------------------------------
-When using VXLAN encapsulation on Red Hat Enterprise Linux 7.2 and 7.3, you may 
-experience poor performance due to limitations in the kernel on these OS 
+When using VXLAN encapsulation on Red Hat Enterprise Linux 7.2 and 7.3, you may
+experience poor performance due to limitations in the kernel on these OS
 releases. To resolve this issue, upgrade your kernel.
 
 
 Driver Buffer Overflow Fix
 --------------------------
-The fix to resolve CVE-2016-8105, referenced in Intel SA-00069 
+The fix to resolve CVE-2016-8105, referenced in Intel SA-00069
 <https://security-center.intel.com/advisory.aspx?intelid=INTEL-SA-00069&language
 id=en-fr>, is included in this and future versions of the driver.
 
 
 depmod warning messages about unknown symbol during installation
 ----------------------------------------------------------------
-During driver installation, you may see depmod warning messages referring to 
-unknown symbols i40e_register_client and i40e_unregister_client. These messages 
-are informational only; no user action is required. The installation should 
+During driver installation, you may see depmod warning messages referring to
+unknown symbols i40e_register_client and i40e_unregister_client. These messages
+are informational only; no user action is required. The installation should
 complete successfully.
 
 
 Error: <ifname> selects TX queue XX but real number of TX queues is YY
 ----------------------------------------------------------------------
-When configuring the number of queues under heavy traffic load, you may see an 
-error message stating "<ifname> selects TX queue XX, but real number of TX 
-queues is YY". This message is informational only and does not affect 
+When configuring the number of queues under heavy traffic load, you may see an
+error message stating "<ifname> selects TX queue XX, but real number of TX
+queues is YY". This message is informational only and does not affect
 functionality.
 
 
 Windows Server 2016 Does Not Work as a Guest OS on Older RHEL and SLES KVMs
 ---------------------------------------------------------------------------
-Microsoft* Windows Server* 2016 does not work as a guest operating system on 
-the KVM hypervisor version included with Red Hat* Enterprise Linux* (RHEL) 
-version 6.8 and Suse* Linux Enterprise Server (SLES) version 11.4. Windows 
+Microsoft* Windows Server* 2016 does not work as a guest operating system on
+the KVM hypervisor version included with Red Hat* Enterprise Linux* (RHEL)
+version 6.8 and Suse* Linux Enterprise Server (SLES) version 11.4. Windows
 Server 2016 does work as a guest OS on RHEL 7.2 and SLES 12.1.
 
 
 Fixing Performance Issues When Using IOMMU in Virtualized Environments
 ----------------------------------------------------------------------
-The IOMMU feature of the processor prevents I/O devices from accessing memory 
-outside the boundaries set by the OS. It also allows devices to be directly 
-assigned to a Virtual Machine. However, IOMMU may affect performance, both in 
-latency (each DMA access by the device must be translated by the IOMMU) and in 
-CPU utilization (each buffer assigned to every device must be mapped in the 
+The IOMMU feature of the processor prevents I/O devices from accessing memory
+outside the boundaries set by the OS. It also allows devices to be directly
+assigned to a Virtual Machine. However, IOMMU may affect performance, both in
+latency (each DMA access by the device must be translated by the IOMMU) and in
+CPU utilization (each buffer assigned to every device must be mapped in the
 IOMMU).
 
-If you experience significant performance issues with IOMMU, try using it in 
+If you experience significant performance issues with IOMMU, try using it in
 "passthrough" mode by adding the following to the kernel boot command line:
   intel_iommu=on iommu=pt
 
-NOTE: This mode enables remapping for assigning devices to VMs, providing 
-near-native I/O performance, but does not provide the additional memory 
+NOTE: This mode enables remapping for assigning devices to VMs, providing
+near-native I/O performance, but does not provide the additional memory
 protection.
 
 
 Transmit hangs leading to no traffic
 ------------------------------------
-Disabling flow control while the device is under stress may cause tx hangs and 
-eventually lead to the device no longer passing traffic. You must reboot the 
+Disabling flow control while the device is under stress may cause tx hangs and
+eventually lead to the device no longer passing traffic. You must reboot the
 system to resolve this issue.
 
 
 Incomplete messages in the system log
 -------------------------------------
-The NVMUpdate utility may write several incomplete messages in the system log. 
+The NVMUpdate utility may write several incomplete messages in the system log.
 These messages take the form:
   in the driver Pci Ex config function byte index 114
   in the driver Pci Ex config function byte index 115
@@ -1106,39 +1424,39 @@ These messages can be ignored.
 
 Bad checksum counter incorrectly increments when using VXLAN
 ------------------------------------------------------------
-When passing non-UDP traffic over a VXLAN interface, the port.rx_csum_bad 
+When passing non-UDP traffic over a VXLAN interface, the port.rx_csum_bad
 counter increments for the packets.
 
 
 Statistic counters reset when promiscuous mode is changed
 ---------------------------------------------------------
-Changing promiscuous mode triggers a reset of the physical function driver. 
+Changing promiscuous mode triggers a reset of the physical function driver.
 This will reset the statistic counters.
 
 
 Virtual machine does not get link
 ---------------------------------
-If the virtual machine has more than one virtual port assigned to it, and those 
-virtual ports are bound to different physical ports, you may not get link on 
+If the virtual machine has more than one virtual port assigned to it, and those
+virtual ports are bound to different physical ports, you may not get link on
 all of the virtual ports. The following command may work around the issue:
 ethtool -r <PF>
-Where <PF> is the PF interface in the host, for example: p5p1. You may need to 
+Where <PF> is the PF interface in the host, for example: p5p1. You may need to
 run the command more than once to get link on all virtual ports.
 
 
 MAC address of Virtual Function changes unexpectedly
 ----------------------------------------------------
-If a Virtual Function's MAC address is not assigned in the host, then the VF 
-(virtual function) driver will use a random MAC address. This random MAC 
-address may change each time the VF driver is reloaded. You can assign a static 
+If a Virtual Function's MAC address is not assigned in the host, then the VF
+(virtual function) driver will use a random MAC address. This random MAC
+address may change each time the VF driver is reloaded. You can assign a static
 MAC address in the host machine. This static MAC address will survive
 a VF driver reload.
 
 
 Changing the number of Rx or Tx queues with ethtool -L may cause a kernel panic
 -------------------------------------------------------------------------------
-Changing the number of Rx or Tx queues with ethtool -L while traffic is flowing 
-and the interface is up may cause a kernel panic. Bring the interface down 
+Changing the number of Rx or Tx queues with ethtool -L while traffic is flowing
+and the interface is up may cause a kernel panic. Bring the interface down
 first to avoid the issue. For example:
   ip link set ethx down
   ethtool -L ethx combined 4
@@ -1146,49 +1464,49 @@ first to avoid the issue. For example:
 
 Adding an Intel Ethernet Flow Director Sideband rule fails incorrectly
 ----------------------------------------------------------------------
-If you try to add an Intel Ethernet Flow Director rule when no more sideband 
-rule space is available, i40e logs an error that the rule could not be added, 
-but ethtool returns success. You can remove rules to free up space. In 
-addition, remove the rule that failed. This will evict it from the driver's 
+If you try to add an Intel Ethernet Flow Director rule when no more sideband
+rule space is available, i40e logs an error that the rule could not be added,
+but ethtool returns success. You can remove rules to free up space. In
+addition, remove the rule that failed. This will evict it from the driver's
 cache.
 
 
 Intel Ethernet Flow Director Sideband Logic adds duplicate filter
 -----------------------------------------------------------------
-The Intel Ethernet Flow Director Sideband Logic adds a duplicate filter in the 
-software filter list if the location is not specified or the specified location 
-differs from the previous location but has the same filter criteria. In this 
-case, the second of the two filters that appear is the valid one in hardware 
+The Intel Ethernet Flow Director Sideband Logic adds a duplicate filter in the
+software filter list if the location is not specified or the specified location
+differs from the previous location but has the same filter criteria. In this
+case, the second of the two filters that appear is the valid one in hardware
 and it decides the filter action.
 
 
 Multiple Interfaces on Same Ethernet Broadcast Network
 ------------------------------------------------------
-Due to the default ARP behavior on Linux, it is not possible to have one system 
-on two IP networks in the same Ethernet broadcast domain (non-partitioned 
-switch) behave as expected. All Ethernet interfaces will respond to IP traffic 
-for any IP address assigned to the system. This results in unbalanced receive 
+Due to the default ARP behavior on Linux, it is not possible to have one system
+on two IP networks in the same Ethernet broadcast domain (non-partitioned
+switch) behave as expected. All Ethernet interfaces will respond to IP traffic
+for any IP address assigned to the system. This results in unbalanced receive
 traffic.
 
-If you have multiple interfaces in a server, either turn on ARP filtering by 
+If you have multiple interfaces in a server, either turn on ARP filtering by
 entering:
 echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
 
 This only works if your kernel's version is higher than 2.4.5.
 
 
-NOTE: This setting is not saved across reboots. The configuration change can be 
+NOTE: This setting is not saved across reboots. The configuration change can be
 made permanent by adding the following line to the file /etc/sysctl.conf:
 net.ipv4.conf.all.arp_filter = 1
 
-Another alternative is to install the interfaces in separate broadcast domains 
+Another alternative is to install the interfaces in separate broadcast domains
 (either in different switches or in a switch partitioned to VLANs).
 
 
 UDP Stress Test Dropped Packet Issue
 ------------------------------------
-Under small packet UDP stress with the i40e driver, the system may drop UDP 
-packets due to socket buffers being full. Setting the driver Intel Ethernet 
+Under small packet UDP stress with the i40e driver, the system may drop UDP
+packets due to socket buffers being full. Setting the driver Intel Ethernet
 Flow Control variables to the minimum may resolve the issue. You may also try
 increasing the kernel's default buffer sizes by changing the values in
 
@@ -1197,67 +1515,67 @@ increasing the kernel's default buffer sizes by changing the values in
 
 Unplugging Network Cable While ethtool -p is Running
 ----------------------------------------------------
-In kernel versions 2.6.32 and newer, unplugging the network cable while ethtool 
--p is running will cause the system to become unresponsive to keyboard 
-commands, except for control-alt-delete. Restarting the system should resolve 
+In kernel versions 2.6.32 and newer, unplugging the network cable while ethtool
+-p is running will cause the system to become unresponsive to keyboard
+commands, except for control-alt-delete. Restarting the system should resolve
 the issue.
 
 
 Rx Page Allocation Errors
 -------------------------
-'Page allocation failure. order:0' errors may occur under stress. with kernels 
-2.6.25 and newer. 
+'Page allocation failure. order:0' errors may occur under stress with kernels
+2.6.25 and newer.
 This is caused by the way the Linux kernel reports this stressed condition.
 
 
 
 Lower than expected performance
 -------------------------------
-Some PCIe x8 slots are actually configured as x4 slots. These slots have 
-insufficient bandwidth for full line rate with dual port and quad port devices. 
-In addition, if you put a PCIe v3.0-capable adapter into a PCIe v2.x slot, you 
-cannot get full bandwidth. The driver detects this situation and writes the 
+Some PCIe x8 slots are actually configured as x4 slots. These slots have
+insufficient bandwidth for full line rate with dual port and quad port devices.
+In addition, if you put a PCIe v3.0-capable adapter into a PCIe v2.x slot, you
+cannot get full bandwidth. The driver detects this situation and writes the
 following message in the system log:
 
-"PCI-Express bandwidth available for this card is not sufficient for optimal 
+"PCI-Express bandwidth available for this card is not sufficient for optimal
 performance. For optimal performance a x8 PCI-Express slot is required."
 
-If this error occurs, moving your adapter to a true PCIe v3.0 x8 slot will 
+If this error occurs, moving your adapter to a true PCIe v3.0 x8 slot will
 resolve the issue.
 
 
 ethtool may incorrectly display SFP+ fiber module as direct attached cable
 --------------------------------------------------------------------------
-Due to kernel limitations, port type can only be correctly displayed on kernel 
+Due to kernel limitations, port type can only be correctly displayed on kernel
 2.6.33 or greater.
 
 
 Running ethtool -t ethX command causes break between PF and test client
 -----------------------------------------------------------------------
-When there are active VFs, "ethtool -t" performs a full diagnostic. In the 
-process, it resets itself and all attached VFs. The VF drivers encounter a 
+When there are active VFs, "ethtool -t" performs a full diagnostic. In the
+process, it resets itself and all attached VFs. The VF drivers encounter a
 disruption, but are able to recover.
 
 
-Enabling SR-IOV in a 64-bit Microsoft* Windows Server* 2012/R2 guest OS under 
+Enabling SR-IOV in a 64-bit Microsoft* Windows Server* 2012/R2 guest OS under
 Linux KVM
 --------------------------------------------------------------------------------
-KVM Hypervisor/VMM supports direct assignment of a PCIe device to a VM. This 
-includes traditional PCIe devices, as well as SR-IOV-capable devices based on 
+KVM Hypervisor/VMM supports direct assignment of a PCIe device to a VM. This
+includes traditional PCIe devices, as well as SR-IOV-capable devices based on
 the Intel Ethernet Controller XL710.
 
 
 Unable to obtain DHCP lease on boot with RedHat
 -----------------------------------------------
-In configurations where the auto-negotiation process takes more than 5 seconds, 
+In configurations where the auto-negotiation process takes more than 5 seconds,
 the boot script may fail with the following message:
 "ethX: failed. No link present. Check cable?"
 
-This error may occur even though the presence of link can be confirmed using 
+This error may occur even though the presence of link can be confirmed using
 ethtool ethx. In this case, try setting "LINKDELAY=30" in
 /etc/sysconfig/network-scripts/ifdfg-ethx.
 
-The same issue can occur during a network boot (via PXE) on RedHat 
+The same issue can occur during a network boot (via PXE) on RedHat
 distributions that use the dracut script:
 "Warning: No carrier detected on interface <interface_name>"
 
@@ -1265,29 +1583,40 @@ In this case add "rd.net.timeout.carrier=30" at the kernel command line.
 
 NOTE: Link time can vary. Adjust LINKDELAY value accordingly.
 
-Alternatively, NetworkManager can be used to configure the interfaces, which 
-avoids the set timeout. For configuration instructions of NetworkManager refer 
+Alternatively, NetworkManager can be used to configure the interfaces, which
+avoids the set timeout. For configuration instructions of NetworkManager refer
 to the documentation provided by your distribution.
 
 
 Loading i40e driver in 3.2.x and newer kernels displays kernel tainted message
 ------------------------------------------------------------------------------
-Due to recent kernel changes, loading an out of tree driver causes the kernel 
+Due to recent kernel changes, loading an out of tree driver causes the kernel
 to be tainted.
 
 
+Unexpected Issues when the device driver and DPDK share a device
+-------------------------------------------------------------------------------
+Unexpected issues may result when an i40e device is in multi driver mode and
+the kernel driver and DPDK driver are sharing the device. This is because
+access to the global NIC resources is not synchronized between multiple
+drivers. Any change to the global NIC configuration (writing to a global
+register, setting global configuration by AQ, or changing switch modes) will
+affect all ports and drivers on the device. Loading DPDK with the
+"multi-driver" module parameter may mitigate some of the issues.
+
+
 ================================================================================
 
 
 Support
--------
+=======
 For general information, go to the Intel support website at:
-www.intel.com/support/
+http://www.intel.com/support/
 
 or the Intel Wired Networking project hosted by Sourceforge at:
 http://sourceforge.net/projects/e1000
-If an issue is identified with the released source code on a supported kernel 
-with a supported adapter, email the specific information related to the issue 
+If an issue is identified with the released source code on a supported kernel
+with a supported adapter, email the specific information related to the issue
 to e1000-devel@lists.sf.net.
 
 
@@ -1296,28 +1625,28 @@ to e1000-devel@lists.sf.net.
 
 License
 -------
-This program is free software; you can redistribute it and/or modify it under 
-the terms and conditions of the GNU General Public License, version 2, as 
+This program is free software; you can redistribute it and/or modify it under
+the terms and conditions of the GNU General Public License, version 2, as
 published by the Free Software Foundation.
 
-This program is distributed in the hope it will be useful, but WITHOUT ANY 
-WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
+This program is distributed in the hope 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 
+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
 St - Fifth Floor, Boston, MA 02110-1301 USA.
 
-The full GNU General Public License is included in this distribution in the 
+The full GNU General Public License is included in this distribution in the
 file called "COPYING".
 
-Copyright(c) 2014-2017 Intel Corporation.
+Copyright(c) 2014-2018 Intel Corporation.
 ================================================================================
 
 
 Trademarks
 ----------
-Intel and Itanium are trademarks or registered trademarks of Intel Corporation 
+Intel and Itanium are trademarks or registered trademarks of Intel Corporation
 or its subsidiaries in the United States and/or other countries.
 
 * Other names and brands may be claimed as the property of others.
diff --git a/i40e-dkms/i40e-2.7.29/SUMS b/i40e-dkms/i40e-2.7.29/SUMS
new file mode 100644 (file)
index 0000000..502f054
--- /dev/null
@@ -0,0 +1,54 @@
+20875     2 i40e-2.7.29/scripts/dump_tables
+33977     7 i40e-2.7.29/scripts/set_irq_affinity
+49876     5 i40e-2.7.29/scripts/virt_perf_default
+12529    18 i40e-2.7.29/COPYING
+44955   117 i40e-2.7.29/src/i40e_txrx.c
+42701   363 i40e-2.7.29/src/i40e_register.h
+32176    44 i40e-2.7.29/src/kcompat_vfd.c
+31605   194 i40e-2.7.29/src/i40e_common.c
+27887     1 i40e-2.7.29/src/i40e_filters.h
+44588     1 i40e-2.7.29/src/Module.supported
+56582    87 i40e-2.7.29/src/i40e_adminq_cmd.h
+30091    28 i40e-2.7.29/src/i40e_dcb.c
+31037     2 i40e-2.7.29/src/i40e_devids.h
+25104    26 i40e-2.7.29/src/virtchnl.h
+02847     5 i40e-2.7.29/src/i40e_dcb.h
+04857     6 i40e-2.7.29/src/i40e_client.h
+61288    22 i40e-2.7.29/src/i40e_client.c
+61837    30 i40e-2.7.29/src/i40e_adminq.c
+40033     6 i40e-2.7.29/src/Makefile
+51306     5 i40e-2.7.29/src/i40e_lan_hmc.h
+30856     2 i40e-2.7.29/src/i40e_alloc.h
+07018   163 i40e-2.7.29/src/i40e_virtchnl_pf.c
+46000    10 i40e-2.7.29/src/i40e_ethtool_stats.h
+36334   184 i40e-2.7.29/src/i40e_ethtool.c
+26631    46 i40e-2.7.29/src/i40e_nvm.c
+62182     6 i40e-2.7.29/src/i40e_virtchnl_pf.h
+52716    63 i40e-2.7.29/src/kcompat.c
+22362    27 i40e-2.7.29/src/i40e_ptp.c
+46479     3 i40e-2.7.29/src/i40e_osdep.h
+08541    22 i40e-2.7.29/src/i40e_prototype.h
+45153     8 i40e-2.7.29/src/i40e_dcb_nl.c
+01064    20 i40e-2.7.29/src/i40e_txrx.h
+47070     4 i40e-2.7.29/src/i40e_diag.c
+55125     1 i40e-2.7.29/src/i40e_diag.h
+01719     6 i40e-2.7.29/src/i40e_trace.h
+26278   189 i40e-2.7.29/src/kcompat.h
+31897    14 i40e-2.7.29/src/i40e_ddp.c
+24389   443 i40e-2.7.29/src/i40e_main.c
+04560     4 i40e-2.7.29/src/i40e_adminq.h
+51964    10 i40e-2.7.29/src/i40e_hmc.c
+24221     8 i40e-2.7.29/src/i40e_hmc.h
+31600     2 i40e-2.7.29/src/i40e_filters.c
+15818    79 i40e-2.7.29/src/i40e_debugfs.c
+42046     3 i40e-2.7.29/src/i40e_status.h
+32480    11 i40e-2.7.29/src/common.mk
+19343     4 i40e-2.7.29/src/i40e_helper.h
+04472    39 i40e-2.7.29/src/i40e.h
+01661    34 i40e-2.7.29/src/i40e_lan_hmc.c
+45072     5 i40e-2.7.29/src/kcompat_vfd.h
+00949    48 i40e-2.7.29/src/i40e_type.h
+50070     7 i40e-2.7.29/pci.updates
+01114     3 i40e-2.7.29/i40e.7
+53019    68 i40e-2.7.29/README
+55456     9 i40e-2.7.29/i40e.spec
similarity index 79%
rename from i40e-dkms/i40e-2.4.6/i40e.7
rename to i40e-dkms/i40e-2.7.29/i40e.7
index 20803e9e737a6c74a5ba6ffabec128bb51a66c50..0184c8b880cf85646a61dde566f63c6f9d398269 100644 (file)
@@ -5,7 +5,7 @@
 .\" * Other names and brands may be claimed as the property of others.
 .\"
 .
-.TH i40e 1 "May 3, 2017"
+.TH i40e 1 "November 12, 2018"
 .SH NAME
 i40e \-This file describes the Linux* Base Driver
 for the Intel Ethernet Controller XL710 Family of Controllers.
@@ -14,13 +14,11 @@ for the Intel Ethernet Controller XL710 Family of Controllers.
 modprobe i40e [<option>=<VAL1>,<VAL2>,...]
 .PD 1v
 .SH DESCRIPTION
-This driver is intended for \fB2.6.32\fR and newer kernels. 
-This driver includes support for any 64 bit Linux supported system, 
-including Itanium(R)2, x86_64, PPC64,ARM, etc.
+This driver is intended for \fB2.6.32\fR and newer kernels. A version of the driver may already be included by your distribution and/or the kernel.org kernel.
+
+This driver includes support for any 64 bit Linux supported system, including Itanium(R)2, x86_64, PPC64, ARM, etc.
 .LP
-This driver is only supported as a loadable module at this time. Intel is
-not supplying patches against the kernel source to allow for static linking of
-the drivers.
+This driver is only supported as a loadable module at this time. Intel is not supplying patches against the kernel source to allow for static linking of the drivers.
 
 
 For questions related to hardware requirements, refer to the documentation
@@ -41,6 +39,8 @@ Alternatively, you can use the ip command as follows:
 NOTE: The maximum MTU setting for Jumbo Frames is 9702. This value coincides with the maximum Jumbo Frames size of 9728 bytes.
 
 NOTE: This driver will attempt to use multiple page sized buffers to receive each jumbo packet. This should help to avoid buffer starvation issues when allocating receive packets.
+
+NOTE: Packet loss may have a greater impact on throughput when you use jumbo frames. If you observe a drop in performance after enabling jumbo frames, enabling flow control may mitigate the issue.
 See the section "Jumbo Frames" in the Readme.
 .SH SUPPORT
 .LP
@@ -48,7 +48,7 @@ For additional information regarding building and installation, see the
 README
 included with the driver.
 For general information, go to the Intel support website at:
-.B www.intel.com/support/
+.B http://www.intel.com/support/
 .LP
 If an issue is identified with the released source code on a supported kernel with a supported adapter, email the specific information related to the issue to e1000-devel@lists.sf.net.
 .LP
similarity index 68%
rename from i40e-dkms/i40e-2.4.6/i40e.spec
rename to i40e-dkms/i40e-2.7.29/i40e.spec
index 081ee37724dfe46b3aab25fbc4a4abe132beedfe..9c4bdda5c92468ec5f17b9e9bf795dbe9ef38ff7 100644 (file)
@@ -1,19 +1,16 @@
 Name: i40e
 Summary: Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
-Version: 2.4.6
+Version: 2.7.29
 Release: 1
 Source: %{name}-%{version}.tar.gz
 Vendor: Intel Corporation
-License: GPL
+License: GPL-2.0
 ExclusiveOS: linux
 Group: System Environment/Kernel
 Provides: %{name}
-URL: http://www.intel.com/network/connectivity/products/server_adapters.htm
+URL: http://support.intel.com
 BuildRoot: %{_tmppath}/%{name}-%{version}-root
-# do not generate debugging packages by default - newer versions of rpmbuild
-# may instead need:
-#%define debug_package %{nil}
-%debug_package %{nil}
+%global debug_package %{nil}
 # macros for finding system files to update at install time (pci.ids, pcitable)
 %define find() %(for f in %*; do if [ -e $f ]; then echo $f; break; fi; done)
 %define _pciids   /usr/share/pci.ids        /usr/share/hwdata/pci.ids
@@ -33,12 +30,12 @@ make -C src clean
 make -C src
 
 %install
-make -C src INSTALL_MOD_PATH=%{buildroot} MANDIR=%{_mandir} rpm
-# Append .new to driver name to avoid conflict with kernel RPM
+make -C src INSTALL_MOD_PATH=%{buildroot} MANDIR=%{_mandir} modules_install mandocs_install
+# Remove modules files that we do not want to include
+find %{buildroot}/lib/modules/ -name 'modules.*' -exec rm -f {} \;
 cd %{buildroot}
-find lib -name "i40e.*o" -exec mv {} {}.new \; \
-         -fprintf %{_builddir}/%{name}-%{version}/file.list "/%p.new\n"
-find lib/modules -name modules.* -exec rm -f {} \;
+find lib -name "i40e.ko" \
+       -fprintf %{_builddir}/%{name}-%{version}/file.list "/%p\n"
 
 
 %clean
@@ -53,61 +50,16 @@ rm -rf %{buildroot}
 %doc pci.updates
 
 %post
-FL="%{_docdir}/%{name}-%{version}/file.list
-    %{_docdir}/%{name}/file.list"
-FL=$(for d in $FL ; do if [ -e $d ]; then echo $d; break; fi;  done)
-
-if [ -d /usr/local/lib/%{name} ]; then
-       rm -rf /usr/local/lib/%{name}
-fi
 if [ -d /usr/local/share/%{name} ]; then
        rm -rf /usr/local/share/%{name}
 fi
-
-# Save old drivers (aka .ko and .ko.gz)
+mkdir /usr/local/share/%{name}
+cp --parents %{pciids} /usr/local/share/%{name}/
 echo "original pci.ids saved in /usr/local/share/%{name}";
 if [ "%{pcitable}" != "/dev/null" ]; then
+       cp --parents %{pcitable} /usr/local/share/%{name}/
        echo "original pcitable saved in /usr/local/share/%{name}";
 fi
-for k in $(sed 's#/lib/modules/\([0-9a-zA-Z.+_-]*\).*$#\1#' $FL) ;
-do
-       d_drivers=/lib/modules/$k
-       d_usr=/usr/local/share/%{name}/$k
-       mkdir -p $d_usr
-       cd $d_drivers; find . -name %{name}.*o -exec cp --parents {} $d_usr \; -exec rm -f {} \;
-       cd $d_drivers; find . -name %{name}_*.*o -exec cp --parents {} $d_usr \; -exec rm -f {} \;
-       cd $d_drivers; find . -name %{name}.*o.gz -exec cp --parents {} $d_usr \; -exec rm -f {} \;
-       cd $d_drivers; find . -name %{name}_*.*o.gz -exec cp --parents {} $d_usr \; -exec rm -f {} \;
-       cp --parents %{pciids} /usr/local/share/%{name}/
-       if [ "%{pcitable}" != "/dev/null" ]; then
-               cp --parents %{pcitable} /usr/local/share/%{name}/
-       fi
-done
-
-# Add driver link
-for f in $(sed 's/\.new$//' $FL) ; do
-       ln -f $f.new $f
-done
-
-# Check if kernel version rpm was built on IS the same as running kernel
-BK_LIST=$(sed 's#/lib/modules/\([0-9a-zA-Z.+_-]*\).*$#\1#' $FL) ;
-MATCH=no
-for i in $BK_LIST
-do
-       if [ $(uname -r) == $i ] ; then
-               MATCH=yes
-               break
-       fi
-done
-if [ $MATCH == no ] ; then
-       echo -n "WARNING: Running kernel is $(uname -r).  "
-       echo -n "RPM supports kernels (  "
-       for i in $BK_LIST
-       do
-               echo -n "$i  "
-       done
-       echo ")"
-fi
 
 LD="%{_docdir}/%{name}";
 if [ -d %{_docdir}/%{name}-%{version} ]; then
@@ -369,62 +321,62 @@ END
 
 mv -f $LD/pci.ids.new  %{pciids}
 if [ "%{pcitable}" != "/dev/null" ]; then
-mv -f $LD/pcitable.new %{pcitable}
+       mv -f $LD/pcitable.new %{pcitable}
 fi
 
 uname -r | grep BOOT || /sbin/depmod -a > /dev/null 2>&1 || true
 
-echo "Updating initrd..."
-# Decide which initrd update utility to use.
-# Default is dracut but we'll try mkinitrd if that's not found.
-which dracut >/dev/null 2>&1
-if [ $? -eq 0 ]; then
-       echo "Using dracut to update initrd..."
-       initrd_cmd="dracut --force"
-else
-       which mkinitrd >/dev/null 2>&1
-       if [ $? -eq 0 ]; then
-               echo "Using mkinitrd to update initrd..."
-               initrd_cmd="mkinitrd"
+if which dracut >/dev/null 2>&1; then
+       echo "Updating initramfs with dracut..."
+       if dracut --force ; then
+               echo "Successfully updated initramfs."
        else
-               echo "Unable to find initrd update utility."
-               echo "You must update your initrd for changes to take place."
+               echo "Failed to update initramfs."
+               echo "You must update your initramfs image for changes to take place."
                exit -1
        fi
-fi
-
-# Do the initrd update and report success or failure.
-if [ "$initrd_cmd" != "" ]; then
-       eval "$initrd_cmd"
-       if [ $? -ne 0 ]; then
+elif which mkinitrd >/dev/null 2>&1; then
+       echo "Updating initrd with mkinitrd..."
+       if mkinitrd; then
+               echo "Successfully updated initrd."
+       else
                echo "Failed to update initrd."
-               echo "You must update your initrd for changes to take place."
+               echo "You must update your initrd image for changes to take place."
                exit -1
-       else
-               echo "Successfully updated initrd."
        fi
+else
+       echo "Unable to determine utility to update initrd image."
+       echo "You must update your initrd manually for changes to take place."
+       exit -1
 fi
 
 %preun
-# If doing RPM un-install
-if [ $1 -eq 0 ] ; then
-       FL="%{_docdir}/%{name}-%{version}/file.list
-               %{_docdir}/%{name}/file.list"
-       FL=$(for d in $FL ; do if [ -e $d ]; then echo $d; break; fi;  done)
+rm -rf /usr/local/share/%{name}
 
-       # Remove driver link
-       for f in $(sed 's/\.new$//' $FL) ; do
-               rm -f $f
-       done
+%postun
+uname -r | grep BOOT || /sbin/depmod -a > /dev/null 2>&1 || true
 
-       # Restore old drivers
-       if [ -d /usr/local/share/%{name} ]; then
-               cd /usr/local/share/%{name}; find . -name '%{name}.*o*' -exec cp --parents {} /lib/modules/ \;
-               cd /usr/local/share/%{name}; find . -name '%{name}_*.*o*' -exec cp --parents {} /lib/modules/ \;
-               rm -rf /usr/local/share/%{name}
+if which dracut >/dev/null 2>&1; then
+       echo "Updating initramfs with dracut..."
+       if dracut --force ; then
+               echo "Successfully updated initramfs."
+       else
+               echo "Failed to update initramfs."
+               echo "You must update your initramfs image for changes to take place."
+               exit -1
        fi
+elif which mkinitrd >/dev/null 2>&1; then
+       echo "Updating initrd with mkinitrd..."
+       if mkinitrd; then
+               echo "Successfully updated initrd."
+       else
+               echo "Failed to update initrd."
+               echo "You must update your initrd image for changes to take place."
+               exit -1
+       fi
+else
+       echo "Unable to determine utility to update initrd image."
+       echo "You must update your initrd manually for changes to take place."
+       exit -1
 fi
 
-%postun
-uname -r | grep BOOT || /sbin/depmod -a > /dev/null 2>&1 || true
-
similarity index 86%
rename from i40e-dkms/i40e-2.4.6/pci.updates
rename to i40e-dkms/i40e-2.7.29/pci.updates
index 29197c0d862860e87726b55c1923c69793125ad3..3e449ae102e6f84e334fd40699a8a3956921938d 100644 (file)
@@ -1,25 +1,5 @@
-################################################################################
-#
-# Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
+# SPDX-License-Identifier: GPL-2.0
 # Copyright(c) 2013 - 2018 Intel Corporation.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms and conditions of the GNU General Public License,
-# version 2, as published by the Free Software Foundation.
-#
-# This program is distributed in the hope 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.
-#
-# The full GNU General Public License is included in this distribution in
-# the file called "COPYING".
-#
-# Contact Information:
-# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-#
-################################################################################
 
 # updates for the system pci.ids file
 #
                8086 0003  Ethernet Converged Network Adapter X710-T
                8086 00a0  Ethernet Converged Network Adapter X710-T4
        158a  Ethernet Controller XXV710 for 25GbE backplane
+               1590 0000  10/25Gb Ethernet Adapter
+               1590 0286  Synergy 4610C 10/25Gb Ethernet Adapter
                8086 0000  Ethernet Controller XXV710 for 25GbE backplane
                8086 000a  Ethernet 25G 2P XXV710 Mezz
        158b  Ethernet Controller XXV710 for 25GbE SFP28
                17aa 4023  Ethernet Connection X722 for 10GbE backplane
        37cf  Ethernet Connection X722 for 10GbE QSFP+
        37d0  Ethernet Connection X722 for 10GbE SFP+
+               8086 0001  Ethernet Network Adapter X722-2
+               8086 0002  Ethernet Network Adapter X722-2
+               8086 0003  Ethernet Network Adapter X722-4
+               8086 0004  Ethernet Network Adapter X722-4
        37d1  Ethernet Connection X722 for 1GbE
                1590 0216  Ethernet 1Gb 2-port 368i Adapter
                1590 0217  Ethernet 1Gb 2-port 368FLR-MMT Adapter
similarity index 68%
rename from i40e-dkms/i40e-2.4.6/src/Makefile
rename to i40e-dkms/i40e-2.7.29/src/Makefile
index d33d3a82c264d51067d6dab2a88477c685eb2750..4d046c5b32742590c00f0ff9fa87d0079317a4e8 100644 (file)
@@ -1,25 +1,5 @@
-################################################################################
-#
-# Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
+# SPDX-License-Identifier: GPL-2.0
 # Copyright(c) 2013 - 2018 Intel Corporation.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms and conditions of the GNU General Public License,
-# version 2, as published by the Free Software Foundation.
-#
-# This program is distributed in the hope 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.
-#
-# The full GNU General Public License is included in this distribution in
-# the file called "COPYING".
-#
-# Contact Information:
-# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-#
-################################################################################
 
 ifneq ($(KERNELRELEASE),)
 # kbuild part of makefile
@@ -43,11 +23,14 @@ i40e-y := i40e_main.o \
        i40e_diag.o \
        i40e_txrx.o \
        i40e_ptp.o \
+       i40e_filters.o \
+       i40e_ddp.o \
        i40e_client.o \
        i40e_virtchnl_pf.o
 
 i40e-$(CONFIG_DCB) += i40e_dcb.o i40e_dcb_nl.o
 i40e-y += kcompat.o
+i40e-y += kcompat_vfd.o
 
 else   # ifneq($(KERNELRELEASE),)
 # normal makefile
@@ -65,6 +48,18 @@ include common.mk
 $(call minimum_kver_check,2,6,32)
 endif
 
+# Command to update initramfs or display a warning message
+ifeq (${cmd_initrd},)
+define cmd_initramfs
+@echo "Unable to update initramfs. You may need to do this manaully."
+endef
+else
+define cmd_initramfs
+@echo "Updating initramfs..."
+-@$(call cmd_initrd)
+endef
+endif
+
 ###############
 # Build rules #
 ###############
@@ -102,58 +97,75 @@ clean:
        @+$(call kernelbuild,clean)
        @-rm -rf *.${MANSECTION}.gz *.ko
 
-# Install the modules and manpage
-install: default manfile
+mandocs_install: manfile
        @echo "Copying manpages..."
        @install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
+
+# Install kernel module files. This target is called by the RPM specfile when
+# generating binary RPMs, and is not expected to modify files outside of the
+# build root. Thus, it must not update initramfs, or run depmod.
+modules_install: default
        @echo "Installing modules..."
        @+$(call kernelbuild,modules_install)
-       @echo "Running depmod..."
-       @$(call cmd_depmod)
-ifeq (${cmd_initrd},)
-       @echo "Unable to update initrd. You may need to do this manually."
-else
-       @echo "Updating initrd..."
-       -@$(call cmd_initrd)
-endif
+
+# After installing all the files, perform necessary work to ensure the system
+# will use the new modules. This includes running depmod to update module
+# dependencies and updating the initramfs image in case the module is loaded
+# during early boot.
+install: modules_install
+       $(call cmd_depmod)
+       $(call cmd_initramfs)
+       $(MAKE) mandocs_install
 
 # Target used by rpmbuild spec file
-rpm: default manfile
-       @install -D -m 644 ${DRIVER}.${MANSECTION}.gz ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz
-       @install -D -m 644 ${DRIVER}.ko ${INSTALL_MOD_PATH}/lib/modules/${KVER}/${INSTALL_MOD_DIR}/${DRIVER}.ko
+rpm: modules_install
+       $(MAKE) mandocs_install
 
-uninstall:
-       rm -f ${INSTALL_MOD_PATH}/lib/modules/${KVER}/${INSTALL_MOD_DIR}/${DRIVER}.ko;
-       $(call cmd_depmod)
-ifeq (${cmd_initrd},)
-       @echo "Unable to update initrd. You may need to do this manually."
-else
-       @echo "Updating initrd..."
-       -@$(call cmd_initrd)
-endif
+mandocs_uninstall:
        if [ -e ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz ] ; then \
                rm -f ${INSTALL_MOD_PATH}${MANDIR}/man${MANSECTION}/${DRIVER}.${MANSECTION}.gz ; \
        fi;
 
+# Remove installed module files. This target is called by the RPM specfile when
+# generating binary RPMs, and is not expected to modify files outside of the
+# build root. Thus, it must not update the initramfs image or run depmod.
+modules_uninstall:
+       rm -f ${INSTALL_MOD_PATH}/lib/modules/${KVER}/${INSTALL_MOD_DIR}/${DRIVER}.ko;
+
+# After uninstalling all the files, perform necessary work to restore the
+# system back to using the default kernel modules. This includes running depmod
+# to update module dependencies and updating the initramfs image.
+uninstall: modules_uninstall mandocs_uninstall
+       $(call cmd_depmod)
+       $(call cmd_initramfs)
+
 ########
 # Help #
 ########
 help:
-       @echo 'Cleaning targets:'
-       @echo '  clean               - Clean files generated by kernel module build'
        @echo 'Build targets:'
        @echo '  default             - Build module(s) with standard verbosity'
        @echo '  noisy               - Build module(s) with V=1 verbosity -- very noisy'
        @echo '  silent              - Build module(s), squelching all output'
+       @echo ''
        @echo 'Static Analysis:'
        @echo '  checkwarnings       - Clean, then build module(s) with W=1 warnings enabled'
        @echo '  sparse              - Clean, then check module(s) using sparse'
        @echo '  ccc                 - Clean, then check module(s) using coccicheck'
+       @echo ''
+       @echo 'Cleaning targets:'
+       @echo '  clean               - Clean files generated by kernel module build'
+       @echo ''
        @echo 'Other targets:'
        @echo '  manfile             - Generate a gzipped manpage'
-       @echo '  install             - Build then install the module(s) and manpage'
-       @echo '  uninstall           - Uninstall the module(s) and manpage'
+       @echo '  modules_install     - install the module(s) only'
+       @echo '  mandocs_install     - install the manpage only'
+       @echo '  install             - Build then install the module(s) and manpage, and update initramfs'
+       @echo '  modules_uninstall   - uninstall the module(s) only'
+       @echo '  mandocs_uninstall   - uninstall the manpage only'
+       @echo '  uninstall           - Uninstall the module(s) and manpage, and update initramfs'
        @echo '  help                - Display this help message'
+       @echo ''
        @echo 'Variables:'
        @echo '  LINUX_VERSION       - Debug tool to force kernel LINUX_VERSION_CODE. Use at your own risk.'
        @echo '  W=N                 - Kernel variable for setting warning levels'
similarity index 91%
rename from i40e-dkms/i40e-2.4.6/src/common.mk
rename to i40e-dkms/i40e-2.7.29/src/common.mk
index 70f252f00ddb96d57db3bfa7a192d706eeaf4364..2eb1ec5b9d277e54a23dd6499e9171bfd36e958a 100644 (file)
@@ -1,25 +1,5 @@
-################################################################################
-#
-# Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
+# SPDX-License-Identifier: GPL-2.0
 # Copyright(c) 2013 - 2018 Intel Corporation.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms and conditions of the GNU General Public License,
-# version 2, as published by the Free Software Foundation.
-#
-# This program is distributed in the hope 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.
-#
-# The full GNU General Public License is included in this distribution in
-# the file called "COPYING".
-#
-# Contact Information:
-# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
-# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-#
-################################################################################
 
 # common Makefile rules useful for out-of-tree Linux driver builds
 #
similarity index 86%
rename from i40e-dkms/i40e-2.4.6/src/i40e.h
rename to i40e-dkms/i40e-2.7.29/src/i40e.h
index d7ac580bcaf193c71d8f13ebd026ca0a2596eaea..3bd674459ce4c9d8d304b499c2533152c71665df 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_H_
 #define _I40E_H_
@@ -62,6 +42,9 @@
 #include <linux/net_tstamp.h>
 #include <linux/ptp_clock_kernel.h>
 #endif /* HAVE_PTP_1588_CLOCK */
+#ifdef __TC_MQPRIO_MODE_MAX
+#include <net/pkt_cls.h>
+#endif
 #include "i40e_type.h"
 #include "i40e_prototype.h"
 #include "i40e_client.h"
 #include "i40e_txrx.h"
 #include "i40e_dcb.h"
 
+#ifdef HAVE_XDP_SUPPORT
+#include <linux/bpf_trace.h>
+#endif
+
 /* Useful i40e defaults */
 #define I40E_MAX_VEB                   16
 
 /* default to trying for four seconds */
 #define I40E_TRY_LINK_TIMEOUT  (4 * HZ)
 
+/* BW rate limiting */
+#define I40E_BW_CREDIT_DIVISOR         50 /* 50Mbps per BW credit */
+#define I40E_MAX_BW_INACTIVE_ACCUM     4  /* accumulate 4 credits max */
+
 /* driver state flags */
 enum i40e_state_t {
        __I40E_TESTING,
@@ -163,14 +154,26 @@ enum i40e_state_t {
        __I40E_DEBUG_MODE,
        __I40E_DOWN_REQUESTED,
        __I40E_FD_FLUSH_REQUESTED,
+       __I40E_FD_ATR_AUTO_DISABLED,
+       __I40E_FD_SB_AUTO_DISABLED,
        __I40E_RESET_FAILED,
        __I40E_PORT_SUSPENDED,
        __I40E_PTP_TX_IN_PROGRESS,
        __I40E_VF_DISABLE,
+       __I40E_RECOVERY_MODE,
+       __I40E_MACVLAN_SYNC_PENDING,
+       __I40E_UDP_FILTER_SYNC_PENDING,
+       __I40E_TEMP_LINK_POLLING,
+       __I40E_CLIENT_SERVICE_REQUESTED,
+       __I40E_CLIENT_L2_CHANGE,
+       __I40E_CLIENT_RESET,
+       __I40E_VIRTCHNL_OP_PENDING,
        /* This must be last as it determines the size of the BITMAP */
        __I40E_STATE_SIZE__,
 };
 
+#define I40E_PF_RESET_FLAG     BIT_ULL(__I40E_PF_RESET_REQUESTED)
+
 /* VSI state flags */
 enum i40e_vsi_state_t {
        __I40E_VSI_DOWN,
@@ -288,19 +291,41 @@ struct i40e_fdir_filter {
 
 struct i40e_cloud_filter {
        struct hlist_node cloud_node;
+       unsigned long cookie;
        /* cloud filter input set follows */
        u8 outer_mac[ETH_ALEN];
        u8 inner_mac[ETH_ALEN];
        __be16 inner_vlan;
        __be32 inner_ip[4];
+       u16 queue_id;
+       u32 id;
+       /* cloud filter input set follows */
+       u8 dst_mac[ETH_ALEN];
+       u8 src_mac[ETH_ALEN];
+       __be16 vlan_id;
+       u16 seid;       /* filter control */
+       __be16 dst_port;
+       __be16 src_port;
        u32 tenant_id;
+       union {
+               struct {
+                       struct in_addr dst_ip;
+                       struct in_addr src_ip;
+               } v4;
+               struct {
+                       struct in6_addr dst_ip6;
+                       struct in6_addr src_ip6;
+               } v6;
+       } ip;
+#define dst_ipv6       ip.v6.dst_ip6.s6_addr32
+#define src_ipv6       ip.v6.src_ip6.s6_addr32
+#define dst_ipv4       ip.v4.dst_ip.s_addr
+#define src_ipv4       ip.v4.src_ip.s_addr
+       u16 n_proto;    /* Ethernet Protocol */
+       u8 ip_proto;    /* IPPROTO value */
        u8 flags;
 #define I40E_CLOUD_TNL_TYPE_NONE       0xff
        u8 tunnel_type;
-       /* filter control */
-       u16 seid;
-       u16 queue_id;
-       u32 id;
 };
 
 #define I40E_ETH_P_LLDP                        0x88cc
@@ -322,10 +347,36 @@ struct i40e_tc_configuration {
        struct i40e_tc_info tc_info[I40E_MAX_TRAFFIC_CLASS];
 };
 
+#define I40E_UDP_PORT_INDEX_UNUSED     255
 struct i40e_udp_port_config {
        /* AdminQ command interface expects port number in Host byte order */
        u16 port;
        u8 type;
+       u8 filter_index;
+};
+
+#define I40_DDP_FLASH_REGION 100
+#define I40E_PROFILE_INFO_SIZE 48
+#define I40E_MAX_PROFILE_NUM 16
+#define I40E_PROFILE_LIST_SIZE \
+       (I40E_PROFILE_INFO_SIZE * I40E_MAX_PROFILE_NUM + 4)
+#define I40E_DDP_PROFILE_PATH "intel/i40e/ddp/"
+#define I40E_DDP_PROFILE_NAME_MAX 64
+
+int i40e_ddp_load(struct net_device *netdev, const u8 *data, size_t size,
+                 bool is_add);
+void i40e_ddp_restore_all(struct i40e_pf *pf);
+int i40e_ddp_flash(struct net_device *netdev, struct ethtool_flash *flash);
+
+struct i40e_ddp_profile_list {
+       u32 p_count;
+       struct i40e_profile_info p_info[0];
+};
+
+struct i40e_ddp_old_profile_list {
+       struct list_head list;
+       size_t old_ddp_size;
+       u8 old_ddp_buf[0];
 };
 
 /* macros related to FLX_PIT */
@@ -391,12 +442,45 @@ struct i40e_udp_port_config {
                                 I40E_FLEX_54_MASK | I40E_FLEX_55_MASK | \
                                 I40E_FLEX_56_MASK | I40E_FLEX_57_MASK)
 
+#define I40E_QINT_TQCTL_VAL(qp, vector, nextq_type) \
+       (I40E_QINT_TQCTL_CAUSE_ENA_MASK | \
+       (I40E_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) | \
+       ((vector) << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) | \
+       ((qp) << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) | \
+       (I40E_QUEUE_TYPE_##nextq_type << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT))
+
+#define I40E_QINT_RQCTL_VAL(qp, vector, nextq_type) \
+       (I40E_QINT_RQCTL_CAUSE_ENA_MASK | \
+       (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) | \
+       ((vector) << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) | \
+       ((qp) << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | \
+       (I40E_QUEUE_TYPE_##nextq_type << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT))
+
 struct i40e_flex_pit {
        struct list_head list;
        u16 src_offset;
        u8 pit_index;
 };
 
+struct i40e_channel {
+       struct list_head list;
+       bool initialized;
+       u8 type;
+       u16 vsi_number; /* Assigned VSI number from AQ 'Add VSI' response */
+       u16 stat_counter_idx;
+       u16 base_queue;
+       u16 num_queue_pairs; /* Requested by user */
+       u16 seid;
+
+       u8 enabled_tc;
+       struct i40e_aqc_vsi_properties_data info;
+
+       u64 max_tx_rate;
+
+       /* track this channel belongs to which VSI */
+       struct i40e_vsi *parent_vsi;
+};
+
 /* struct that defines the Ethernet device */
 struct i40e_pf {
        struct pci_dev *pdev;
@@ -453,6 +537,7 @@ struct i40e_pf {
 
        struct hlist_head cloud_filter_list;
        u16 num_cloud_filters;
+
        enum i40e_interrupt_policy int_policy;
        u16 rx_itr_default;
        u16 tx_itr_default;
@@ -491,34 +576,30 @@ struct i40e_pf {
 #define I40E_FLAG_MSIX_ENABLED                 BIT(2)
 #define I40E_FLAG_RSS_ENABLED                  BIT(3)
 #define I40E_FLAG_VMDQ_ENABLED                 BIT(4)
-#define I40E_FLAG_FILTER_SYNC                  BIT(5)
-#define I40E_FLAG_SRIOV_ENABLED                        BIT(6)
-#define I40E_FLAG_DCB_CAPABLE                  BIT(7)
-#define I40E_FLAG_DCB_ENABLED                  BIT(8)
-#define I40E_FLAG_FD_SB_ENABLED                        BIT(9)
-#define I40E_FLAG_FD_ATR_ENABLED               BIT(10)
-#define I40E_FLAG_FD_SB_AUTO_DISABLED          BIT(11)
-#define I40E_FLAG_FD_ATR_AUTO_DISABLED         BIT(12)
-#define I40E_FLAG_MFP_ENABLED                  BIT(13)
-#define I40E_FLAG_UDP_FILTER_SYNC              BIT(14)
-#define I40E_FLAG_HW_ATR_EVICT_ENABLED         BIT(15)
-#define I40E_FLAG_VEB_MODE_ENABLED             BIT(16)
-#define I40E_FLAG_VEB_STATS_ENABLED            BIT(17)
-#define I40E_FLAG_LINK_POLLING_ENABLED         BIT(18)
-#define I40E_FLAG_TRUE_PROMISC_SUPPORT         BIT(19)
-#define I40E_FLAG_TEMP_LINK_POLLING            BIT(20)
-#define I40E_FLAG_LEGACY_RX                    BIT(21)
+#define I40E_FLAG_SRIOV_ENABLED                        BIT(5)
+#define I40E_FLAG_DCB_CAPABLE                  BIT(6)
+#define I40E_FLAG_DCB_ENABLED                  BIT(7)
+#define I40E_FLAG_FD_SB_ENABLED                        BIT(8)
+#define I40E_FLAG_FD_ATR_ENABLED               BIT(9)
+#define I40E_FLAG_MFP_ENABLED                  BIT(10)
+#define I40E_FLAG_HW_ATR_EVICT_ENABLED         BIT(11)
+#define I40E_FLAG_VEB_MODE_ENABLED             BIT(12)
+#define I40E_FLAG_VEB_STATS_ENABLED            BIT(13)
+#define I40E_FLAG_LINK_POLLING_ENABLED         BIT(14)
+#define I40E_FLAG_TRUE_PROMISC_SUPPORT         BIT(15)
+#define I40E_FLAG_LEGACY_RX                    BIT(16)
 #ifdef HAVE_PTP_1588_CLOCK
-#define I40E_FLAG_PTP                          BIT(22)
+#define I40E_FLAG_PTP                          BIT(17)
 #endif /* HAVE_PTP_1588_CLOCK */
-#define I40E_FLAG_IWARP_ENABLED                        BIT(23)
-#define I40E_FLAG_SERVICE_CLIENT_REQUESTED     BIT(24)
-#define I40E_FLAG_CLIENT_L2_CHANGE             BIT(25)
-#define I40E_FLAG_CLIENT_RESET                 BIT(26)
-#define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED   BIT(27)
-#define I40E_FLAG_SOURCE_PRUNING_DISABLED       BIT(28)
-#define I40E_FLAG_DISABLE_FW_LLDP              BIT(29)
-
+#define I40E_FLAG_IWARP_ENABLED                        BIT(18)
+#define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED   BIT(19)
+#define I40E_FLAG_SOURCE_PRUNING_DISABLED       BIT(20)
+#define I40E_FLAG_TC_MQPRIO                    BIT(21)
+#define I40E_FLAG_FD_SB_INACTIVE               BIT(22)
+#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER                BIT(23)
+#define I40E_FLAG_DISABLE_FW_LLDP              BIT(24)
+#define I40E_FLAG_RS_FEC                       BIT(25)
+#define I40E_FLAG_BASE_R_FEC                   BIT(26)
        /* flag to enable/disable vf base mode support */
        bool vf_base_mode_only;
 
@@ -586,7 +667,7 @@ struct i40e_pf {
        unsigned long ptp_tx_start;
        struct hwtstamp_config tstamp_config;
        struct mutex tmreg_lock; /* Used to protect the SYSTIME registers. */
-       u64 ptp_base_adj;
+       u32 ptp_adj_mult;
        u32 tx_hwtstamp_timeouts;
        u32 tx_hwtstamp_skipped;
        u32 rx_hwtstamp_cleared;
@@ -619,6 +700,13 @@ struct i40e_pf {
        u32 ioremap_len;
        u32 fd_inv;
        u16 phy_led_val;
+       u16 last_sw_conf_flags;
+       u16 last_sw_conf_valid_flags;
+
+       u16 override_q_count;
+       struct vfd_objects *vfd_obj;
+       /* List to keep previous DDP profiles to be rolled back in the future */
+       struct list_head ddp_old_prof;
 };
 
 /**
@@ -734,6 +822,7 @@ struct i40e_vsi {
        /* These are containers of ring pointers, allocated at run-time */
        struct i40e_ring **rx_rings;
        struct i40e_ring **tx_rings;
+       struct i40e_ring **xdp_rings; /* XDP Tx rings */
 
        u32  active_filters;
        u32  promisc_threshold;
@@ -749,6 +838,8 @@ struct i40e_vsi {
        u16 max_frame;
        u16 rx_buf_len;
 
+       struct bpf_prog *xdp_prog;
+
        /* List of q_vectors allocated to this VSI */
        struct i40e_q_vector **q_vectors;
        int num_q_vectors;
@@ -766,7 +857,9 @@ struct i40e_vsi {
        u16 num_desc;
        enum i40e_vsi_type type;  /* VSI type, e.g., LAN, FCoE, etc */
        s16 vf_id;              /* Virtual function ID for SRIOV VSIs */
-
+#ifdef __TC_MQPRIO_MODE_MAX
+       struct tc_mqprio_qopt_offload mqprio_qopt; /* queue parameters */
+#endif
        struct i40e_tc_configuration tc_config;
        struct i40e_aqc_vsi_properties_data info;
 
@@ -787,6 +880,16 @@ struct i40e_vsi {
        struct kobject *kobj;   /* sysfs object */
        bool current_isup;      /* Sync 'link up' logging */
        enum i40e_aq_link_speed current_speed;  /* Sync link speed logging */
+       /* channel specific fields */
+       u16 cnt_q_avail;        /* num of queues available for channel usage */
+       u16 orig_rss_size;
+       u16 current_rss_size;
+       bool reconfig_rss;
+
+       u16 next_base_queue;    /* next queue to be used for channel setup */
+
+       struct list_head ch_list;
+       u16 tc_seid_map[I40E_MAX_TRAFFIC_CLASS];
 
        void *priv;     /* client driver data reference. */
        bool block_tx_timeout;
@@ -1011,6 +1114,9 @@ void i40e_service_event_schedule(struct i40e_pf *pf);
 void i40e_notify_client_of_vf_msg(struct i40e_vsi *vsi, u32 vf_id,
                                  u8 *msg, u16 len);
 
+int i40e_control_wait_tx_q(int seid, struct i40e_pf *pf, int pf_q, bool is_xdp,
+                          bool enable);
+int i40e_control_wait_rx_q(struct i40e_pf *pf, int pf_q, bool enable);
 int i40e_vsi_start_rings(struct i40e_vsi *vsi);
 void i40e_vsi_stop_rings(struct i40e_vsi *vsi);
 void i40e_vsi_stop_rings_no_wait(struct  i40e_vsi *vsi);
@@ -1028,9 +1134,6 @@ int i40e_veb_config_tc(struct i40e_veb *veb, u8 enabled_tc);
 int i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid);
 void i40e_vsi_remove_pvid(struct i40e_vsi *vsi);
 int i40e_get_cloud_filter_type(u8 flags, u16 *type);
-int i40e_add_del_cloud_filter(struct i40e_pf *pf,
-                             struct i40e_cloud_filter *filter,
-                             bool add);
 void i40e_vsi_reset_stats(struct i40e_vsi *vsi);
 void i40e_pf_reset_stats(struct i40e_pf *pf);
 #ifdef CONFIG_DEBUG_FS
@@ -1052,6 +1155,7 @@ void i40e_notify_client_of_l2_param_changes(struct i40e_vsi *vsi);
 void i40e_notify_client_of_netdev_close(struct i40e_vsi *vsi, bool reset);
 void i40e_notify_client_of_vf_enable(struct i40e_pf *pf, u32 num_vfs);
 void i40e_notify_client_of_vf_reset(struct i40e_pf *pf, u32 vf_id);
+void i40e_client_update_msix_info(struct i40e_pf *pf);
 int i40e_vf_client_capable(struct i40e_pf *pf, u32 vf_id);
 /**
  * i40e_irq_dynamic_enable - Enable default interrupt generation settings
@@ -1116,5 +1220,22 @@ int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi);
 i40e_status i40e_get_partition_bw_setting(struct i40e_pf *pf);
 i40e_status i40e_set_partition_bw_setting(struct i40e_pf *pf);
 i40e_status i40e_commit_partition_bw_setting(struct i40e_pf *pf);
+int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate);
+int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
+                             struct i40e_cloud_filter *filter,
+                             bool add);
+int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,
+                                     struct i40e_cloud_filter *filter,
+                                     bool add);
 void i40e_print_link_message(struct i40e_vsi *vsi, bool isup);
+int i40e_create_queue_channel(struct i40e_vsi *vsi, struct i40e_channel *ch);
+int i40e_get_link_speed(struct i40e_vsi *vsi);
+
+void i40e_set_fec_in_flags(u8 fec_cfg, u64 *flags);
+
+static inline bool i40e_enabled_xdp_vsi(struct i40e_vsi *vsi)
+{
+       return !!vsi->xdp_prog;
+}
+
 #endif /* _I40E_H_ */
similarity index 96%
rename from i40e-dkms/i40e-2.4.6/src/i40e_adminq.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_adminq.c
index 9cf1ecc2f2c56218b2636181b7b6f3b48f8ed33e..eff828c49344681e858656568a9405765e937b94 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #include "i40e_status.h"
 #include "i40e_type.h"
@@ -114,6 +94,7 @@ static i40e_status i40e_alloc_adminq_arq_ring(struct i40e_hw *hw)
  **/
 static void i40e_free_adminq_asq(struct i40e_hw *hw)
 {
+       i40e_free_virt_mem(hw, &hw->aq.asq.cmd_buf);
        i40e_free_dma_mem(hw, &hw->aq.asq.desc_buf);
 }
 
@@ -385,7 +366,7 @@ static i40e_status i40e_init_asq(struct i40e_hw *hw)
        /* initialize base registers */
        ret_code = i40e_config_asq_regs(hw);
        if (ret_code != I40E_SUCCESS)
-               goto init_adminq_free_rings;
+               goto init_config_regs;
 
        /* success! */
        hw->aq.asq.count = hw->aq.num_asq_entries;
@@ -393,6 +374,10 @@ static i40e_status i40e_init_asq(struct i40e_hw *hw)
 
 init_adminq_free_rings:
        i40e_free_adminq_asq(hw);
+       return ret_code;
+
+init_config_regs:
+       i40e_free_asq_bufs(hw);
 
 init_adminq_exit:
        return ret_code;
@@ -632,6 +617,12 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw)
            hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
            hw->aq.api_min_ver >= I40E_MINOR_VER_GET_LINK_INFO_XL710) {
                hw->flags |= I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE;
+               hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE;
+       }
+       if (hw->mac.type == I40E_MAC_X722 &&
+           hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
+           hw->aq.api_min_ver >= I40E_MINOR_VER_FW_LLDP_STOPPABLE_X722) {
+               hw->flags |= I40E_HW_FLAG_FW_LLDP_STOPPABLE;
        }
 
        /* Newer versions of firmware require lock when reading the NVM */
@@ -920,6 +911,8 @@ i40e_status i40e_asq_send_command(struct i40e_hw *hw,
                cmd_completed = true;
                if ((enum i40e_admin_queue_err)retval == I40E_AQ_RC_OK)
                        status = I40E_SUCCESS;
+               else if ((enum i40e_admin_queue_err)retval == I40E_AQ_RC_EBUSY)
+                       status = I40E_ERR_NOT_READY;
                else
                        status = I40E_ERR_ADMIN_QUEUE_ERROR;
                hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval;
similarity index 79%
rename from i40e-dkms/i40e-2.4.6/src/i40e_adminq.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_adminq.h
index 5f76acd64cfde859b189a78458ce6f1d4dfdf80a..fc9c27c12fcadc108bc91a94ac7e7d0b197083a6 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_ADMINQ_H_
 #define _I40E_ADMINQ_H_
similarity index 93%
rename from i40e-dkms/i40e-2.4.6/src/i40e_adminq_cmd.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_adminq_cmd.h
index b7d3f8609b6cae4c1e049d9acfb775cbc6fe71c3..e8e7067502579da5ec376ea268ad75aa2ca090c8 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_ADMINQ_CMD_H_
 #define _I40E_ADMINQ_CMD_H_
@@ -31,7 +11,7 @@
  */
 
 #define I40E_FW_API_VERSION_MAJOR      0x0001
-#define I40E_FW_API_VERSION_MINOR_X722 0x0005
+#define I40E_FW_API_VERSION_MINOR_X722 0x0006
 #define I40E_FW_API_VERSION_MINOR_X710 0x0007
 
 #define I40E_FW_MINOR_VERSION(_h) ((_h)->mac.type == I40E_MAC_XL710 ? \
@@ -40,6 +20,8 @@
 
 /* API version 1.7 implements additional link and PHY-specific APIs  */
 #define I40E_MINOR_VER_GET_LINK_INFO_XL710 0x0007
+/* API version 1.6 for X722 devices adds ability to stop FW LLDP agent */
+#define I40E_MINOR_VER_FW_LLDP_STOPPABLE_X722 0x0006
 
 struct i40e_aq_desc {
        __le16 flags;
@@ -796,7 +778,35 @@ struct i40e_aqc_set_switch_config {
         */
        __le16  first_tag;
        __le16  second_tag;
-       u8      reserved[6];
+       /* Next byte is split into following:
+        * Bit 7    : 0 : No action, 1: Switch to mode defined by bits 6:0
+        * Bit 6    : 0 : Destination Port, 1: source port
+        * Bit 5..4 : L4 type
+        * 0: rsvd
+        * 1: TCP
+        * 2: UDP
+        * 3: Both TCP and UDP
+        * Bits 3:0 Mode
+        * 0: default mode
+        * 1: L4 port only mode
+        * 2: non-tunneled mode
+        * 3: tunneled mode
+        */
+#define I40E_AQ_SET_SWITCH_BIT7_VALID          0x80
+
+#define I40E_AQ_SET_SWITCH_L4_SRC_PORT         0x40
+
+#define I40E_AQ_SET_SWITCH_L4_TYPE_RSVD                0x00
+#define I40E_AQ_SET_SWITCH_L4_TYPE_TCP         0x10
+#define I40E_AQ_SET_SWITCH_L4_TYPE_UDP         0x20
+#define I40E_AQ_SET_SWITCH_L4_TYPE_BOTH                0x30
+
+#define I40E_AQ_SET_SWITCH_MODE_DEFAULT                0x00
+#define I40E_AQ_SET_SWITCH_MODE_L4_PORT                0x01
+#define I40E_AQ_SET_SWITCH_MODE_NON_TUNNEL     0x02
+#define I40E_AQ_SET_SWITCH_MODE_TUNNEL         0x03
+       u8      mode;
+       u8      rsvd5[5];
 };
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_set_switch_config);
@@ -1351,6 +1361,7 @@ struct i40e_aqc_add_remove_cloud_filters {
                                        I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT)
        u8      big_buffer_flag;
 #define I40E_AQC_ADD_REM_CLOUD_CMD_BIG_BUFFER  1
+#define I40E_AQC_ADD_CLOUD_CMD_BB              1
        u8      reserved2[3];
        __le32  addr_high;
        __le32  addr_low;
@@ -1358,7 +1369,7 @@ struct i40e_aqc_add_remove_cloud_filters {
 
 I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_cloud_filters);
 
-struct i40e_aqc_add_remove_cloud_filters_element_data {
+struct i40e_aqc_cloud_filters_element_data {
        u8      outer_mac[6];
        u8      inner_mac[6];
        __le16  inner_vlan;
@@ -1370,6 +1381,9 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
                struct {
                        u8 data[16];
                } v6;
+               struct {
+                       __le16 data[8];
+               } raw_v6;
        } ipaddr;
        __le16  flags;
 #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT                        0
@@ -1389,6 +1403,9 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
 #define I40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC     0x000B
 #define I40E_AQC_ADD_CLOUD_FILTER_IIP                  0x000C
 /* 0x0010 to 0x0017 is for custom filters */
+#define I40E_AQC_ADD_CLOUD_FILTER_IP_PORT              0x0010 /* Dest IP + L4 Port */
+#define I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT             0x0011 /* Dest MAC + L4 Port */
+#define I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT                0x0012 /* Dest MAC + VLAN + L4 Port */
 
 #define I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE              0x0080
 #define I40E_AQC_ADD_CLOUD_VNK_SHIFT                   6
@@ -1424,11 +1441,10 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
 };
 
 /* i40e_aqc_add_rm_cloud_filt_elem_ext is used when
- * I40E_AQC_ADD_REM_CLOUD_CMD_BIG_BUFFER flag is set. refer to
- * DCR288
+ * I40E_AQC_ADD_REM_CLOUD_CMD_BIG_BUFFER flag is set.
  */
 struct i40e_aqc_add_rm_cloud_filt_elem_ext {
-       struct i40e_aqc_add_remove_cloud_filters_element_data element;
+       struct i40e_aqc_cloud_filters_element_data element;
        u16     general_fields[32];
 #define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD0   0
 #define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1   1
@@ -1463,6 +1479,49 @@ struct i40e_aqc_add_rm_cloud_filt_elem_ext {
 #define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD7   30
 };
 
+I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_cloud_filters_element_data);
+
+/* i40e_aqc_cloud_filters_element_bb is used when
+ * I40E_AQC_CLOUD_CMD_BB flag is set.
+ */
+struct i40e_aqc_cloud_filters_element_bb {
+       struct i40e_aqc_cloud_filters_element_data element;
+       u16     general_fields[32];
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD0   0
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD1   1
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X10_WORD2   2
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD0   3
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD1   4
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X11_WORD2   5
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD0   6
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD1   7
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X12_WORD2   8
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD0   9
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD1   10
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X13_WORD2   11
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD0   12
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD1   13
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X14_WORD2   14
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD0   15
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD1   16
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD2   17
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD3   18
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD4   19
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD5   20
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD6   21
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD7   22
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD0   23
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD1   24
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD2   25
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD3   26
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD4   27
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD5   28
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD6   29
+#define I40E_AQC_ADD_CLOUD_FV_FLU_0X17_WORD7   30
+};
+
+I40E_CHECK_STRUCT_LEN(0x80, i40e_aqc_cloud_filters_element_bb);
+
 struct i40e_aqc_remove_cloud_filters_completion {
        __le16 perfect_ovlan_used;
        __le16 perfect_ovlan_free;
@@ -1483,6 +1542,8 @@ struct i40e_filter_data {
        u8 input[3];
 };
 
+I40E_CHECK_STRUCT_LEN(4, i40e_filter_data);
+
 struct i40e_aqc_replace_cloud_filters_cmd {
        u8      valid_flags;
 #define I40E_AQC_REPLACE_L1_FILTER             0x0
@@ -1493,11 +1554,14 @@ struct i40e_aqc_replace_cloud_filters_cmd {
        u8      old_filter_type;
        u8      new_filter_type;
        u8      tr_bit;
-       u8      reserved[4];
+       u8      tr_bit2;
+       u8      reserved[3];
        __le32 addr_high;
        __le32 addr_low;
 };
 
+I40E_CHECK_CMD_LENGTH(i40e_aqc_replace_cloud_filters_cmd);
+
 struct i40e_aqc_replace_cloud_filters_cmd_buf {
        u8      data[32];
 /* Filter type INPUT codes*/
@@ -1522,6 +1586,8 @@ struct i40e_aqc_replace_cloud_filters_cmd_buf {
        struct i40e_filter_data filters[8];
 };
 
+I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_replace_cloud_filters_cmd_buf);
+
 /* Add Mirror Rule (indirect or direct 0x0260)
  * Delete Mirror Rule (indirect or direct 0x0261)
  * note: some rule types (4,5) do not use an external buffer.
@@ -1870,23 +1936,68 @@ enum i40e_aq_phy_type {
        I40E_PHY_TYPE_25GBASE_LR                = 0x22,
        I40E_PHY_TYPE_25GBASE_AOC               = 0x23,
        I40E_PHY_TYPE_25GBASE_ACC               = 0x24,
+       I40E_PHY_TYPE_2_5GBASE_T                = 0x30,
+       I40E_PHY_TYPE_5GBASE_T                  = 0x31,
        I40E_PHY_TYPE_MAX,
        I40E_PHY_TYPE_NOT_SUPPORTED_HIGH_TEMP   = 0xFD,
        I40E_PHY_TYPE_EMPTY                     = 0xFE,
        I40E_PHY_TYPE_DEFAULT                   = 0xFF,
 };
 
+#define I40E_PHY_TYPES_BITMASK (BIT_ULL(I40E_PHY_TYPE_SGMII) | \
+                               BIT_ULL(I40E_PHY_TYPE_1000BASE_KX) | \
+                               BIT_ULL(I40E_PHY_TYPE_10GBASE_KX4) | \
+                               BIT_ULL(I40E_PHY_TYPE_10GBASE_KR) | \
+                               BIT_ULL(I40E_PHY_TYPE_40GBASE_KR4) | \
+                               BIT_ULL(I40E_PHY_TYPE_XAUI) | \
+                               BIT_ULL(I40E_PHY_TYPE_XFI) | \
+                               BIT_ULL(I40E_PHY_TYPE_SFI) | \
+                               BIT_ULL(I40E_PHY_TYPE_XLAUI) | \
+                               BIT_ULL(I40E_PHY_TYPE_XLPPI) | \
+                               BIT_ULL(I40E_PHY_TYPE_40GBASE_CR4_CU) | \
+                               BIT_ULL(I40E_PHY_TYPE_10GBASE_CR1_CU) | \
+                               BIT_ULL(I40E_PHY_TYPE_10GBASE_AOC) | \
+                               BIT_ULL(I40E_PHY_TYPE_40GBASE_AOC) | \
+                               BIT_ULL(I40E_PHY_TYPE_UNRECOGNIZED) | \
+                               BIT_ULL(I40E_PHY_TYPE_UNSUPPORTED) | \
+                               BIT_ULL(I40E_PHY_TYPE_100BASE_TX) | \
+                               BIT_ULL(I40E_PHY_TYPE_1000BASE_T) | \
+                               BIT_ULL(I40E_PHY_TYPE_10GBASE_T) | \
+                               BIT_ULL(I40E_PHY_TYPE_10GBASE_SR) | \
+                               BIT_ULL(I40E_PHY_TYPE_10GBASE_LR) | \
+                               BIT_ULL(I40E_PHY_TYPE_10GBASE_SFPP_CU) | \
+                               BIT_ULL(I40E_PHY_TYPE_10GBASE_CR1) | \
+                               BIT_ULL(I40E_PHY_TYPE_40GBASE_CR4) | \
+                               BIT_ULL(I40E_PHY_TYPE_40GBASE_SR4) | \
+                               BIT_ULL(I40E_PHY_TYPE_40GBASE_LR4) | \
+                               BIT_ULL(I40E_PHY_TYPE_1000BASE_SX) | \
+                               BIT_ULL(I40E_PHY_TYPE_1000BASE_LX) | \
+                               BIT_ULL(I40E_PHY_TYPE_1000BASE_T_OPTICAL) | \
+                               BIT_ULL(I40E_PHY_TYPE_20GBASE_KR2) | \
+                               BIT_ULL(I40E_PHY_TYPE_25GBASE_KR) | \
+                               BIT_ULL(I40E_PHY_TYPE_25GBASE_CR) | \
+                               BIT_ULL(I40E_PHY_TYPE_25GBASE_SR) | \
+                               BIT_ULL(I40E_PHY_TYPE_25GBASE_LR) | \
+                               BIT_ULL(I40E_PHY_TYPE_25GBASE_AOC) | \
+                               BIT_ULL(I40E_PHY_TYPE_25GBASE_ACC) | \
+                               BIT_ULL(I40E_PHY_TYPE_2_5GBASE_T) | \
+                               BIT_ULL(I40E_PHY_TYPE_5GBASE_T))
+
+#define I40E_LINK_SPEED_2_5GB_SHIFT    0x0
 #define I40E_LINK_SPEED_100MB_SHIFT    0x1
 #define I40E_LINK_SPEED_1000MB_SHIFT   0x2
 #define I40E_LINK_SPEED_10GB_SHIFT     0x3
 #define I40E_LINK_SPEED_40GB_SHIFT     0x4
 #define I40E_LINK_SPEED_20GB_SHIFT     0x5
 #define I40E_LINK_SPEED_25GB_SHIFT     0x6
+#define I40E_LINK_SPEED_5GB_SHIFT      0x7
 
 enum i40e_aq_link_speed {
        I40E_LINK_SPEED_UNKNOWN = 0,
        I40E_LINK_SPEED_100MB   = (1 << I40E_LINK_SPEED_100MB_SHIFT),
        I40E_LINK_SPEED_1GB     = (1 << I40E_LINK_SPEED_1000MB_SHIFT),
+       I40E_LINK_SPEED_2_5GB   = (1 << I40E_LINK_SPEED_2_5GB_SHIFT),
+       I40E_LINK_SPEED_5GB     = (1 << I40E_LINK_SPEED_5GB_SHIFT),
        I40E_LINK_SPEED_10GB    = (1 << I40E_LINK_SPEED_10GB_SHIFT),
        I40E_LINK_SPEED_40GB    = (1 << I40E_LINK_SPEED_40GB_SHIFT),
        I40E_LINK_SPEED_20GB    = (1 << I40E_LINK_SPEED_20GB_SHIFT),
@@ -1932,6 +2043,8 @@ struct i40e_aq_get_phy_abilities_resp {
 #define I40E_AQ_PHY_TYPE_EXT_25G_LR    0x08
 #define I40E_AQ_PHY_TYPE_EXT_25G_AOC   0x10
 #define I40E_AQ_PHY_TYPE_EXT_25G_ACC   0x20
+#define I40E_AQ_PHY_TYPE_EXT_2_5GBASE_T        0x40
+#define I40E_AQ_PHY_TYPE_EXT_5GBASE_T  0x80
        u8      fec_cfg_curr_mod_ext_info;
 #define I40E_AQ_ENABLE_FEC_KR          0x01
 #define I40E_AQ_ENABLE_FEC_RS          0x02
@@ -2193,7 +2306,9 @@ struct i40e_aqc_phy_register_access {
 #define I40E_AQ_PHY_REG_ACCESS_EXTERNAL        1
 #define I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE 2
        u8      dev_addres;
-       u8      reserved1[2];
+       u8      cmd_flags;
+#define I40E_AQ_PHY_REG_ACCESS_DONT_CHANGE_QSFP_PAGE   1
+       u8      reserved1;
        __le32  reg_address;
        __le32  reg_value;
        u8      reserved2[4];
@@ -2208,6 +2323,8 @@ I40E_CHECK_CMD_LENGTH(i40e_aqc_phy_register_access);
 struct i40e_aqc_nvm_update {
        u8      command_flags;
 #define I40E_AQ_NVM_LAST_CMD                   0x01
+#define I40E_AQ_NVM_REARRANGE_TO_FLAT          0x20
+#define I40E_AQ_NVM_REARRANGE_TO_STRUCT                0x40
 #define I40E_AQ_NVM_FLASH_ONLY                 0x80
 #define I40E_AQ_NVM_PRESERVATION_FLAGS_SHIFT   1
 #define I40E_AQ_NVM_PRESERVATION_FLAGS_MASK    0x03
similarity index 51%
rename from i40e-dkms/i40e-2.4.6/src/i40e_alloc.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_alloc.h
index 572fa261adf9821fa2779322a6dd7c069ab01a9b..cb8689222c8b77c957be573b6fad8e6d75bcaa4d 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_ALLOC_H_
 #define _I40E_ALLOC_H_
similarity index 94%
rename from i40e-dkms/i40e-2.4.6/src/i40e_client.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_client.c
index b1e6e1cf577094f29d13291337e090aaceb740d9..97a9cd080e35e0b1ad5e7ee95371637a9e7f0060 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #include <linux/list.h>
 #include <linux/errno.h>
@@ -60,7 +40,7 @@ static struct i40e_ops i40e_lan_ops = {
 /**
  * i40e_client_get_params - Get the params that can change at runtime
  * @vsi: the VSI with the message
- * @param: clinet param struct
+ * @params: clinet param struct
  *
  **/
 static
@@ -284,6 +264,17 @@ out:
        return capable;
 }
 
+void i40e_client_update_msix_info(struct i40e_pf *pf)
+{
+       struct i40e_client_instance *cdev = pf->cinst;
+
+       if (!cdev || !cdev->client)
+               return;
+
+       cdev->lan_info.msix_count = pf->num_iwarp_msix;
+       cdev->lan_info.msix_entries = &pf->msix_entries[pf->iwarp_base_vector];
+}
+
 /**
  * i40e_client_add_instance - add a client instance struct to the instance list
  * @pf: pointer to the board struct
@@ -322,9 +313,6 @@ static void i40e_client_add_instance(struct i40e_pf *pf)
                return;
        }
 
-       cdev->lan_info.msix_count = pf->num_iwarp_msix;
-       cdev->lan_info.msix_entries = &pf->msix_entries[pf->iwarp_base_vector];
-
        mac = list_first_entry(&cdev->lan_info.netdev->dev_addrs.list,
                               struct netdev_hw_addr, list);
        if (mac)
@@ -334,6 +322,8 @@ static void i40e_client_add_instance(struct i40e_pf *pf)
 
        cdev->client = registered_client;
        pf->cinst = cdev;
+
+       i40e_client_update_msix_info(pf);
 }
 
 /**
@@ -359,9 +349,8 @@ void i40e_client_subtask(struct i40e_pf *pf)
        struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
        int ret = 0;
 
-       if (!(pf->flags & I40E_FLAG_SERVICE_CLIENT_REQUESTED))
+       if (!test_and_clear_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state))
                return;
-       pf->flags &= ~I40E_FLAG_SERVICE_CLIENT_REQUESTED;
        cdev = pf->cinst;
 
        /* If we're down or resetting, just bail */
@@ -442,7 +431,7 @@ int i40e_lan_add_device(struct i40e_pf *pf)
         * added, we can schedule a subtask to go initiate the clients if
         * they can be launched at probe time.
         */
-       pf->flags |= I40E_FLAG_SERVICE_CLIENT_REQUESTED;
+       set_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state);
        i40e_service_event_schedule(pf);
 
 out:
@@ -538,7 +527,7 @@ static void i40e_client_prepare(struct i40e_client *client)
                pf = ldev->pf;
                i40e_client_add_instance(pf);
                /* Start the client subtask */
-               pf->flags |= I40E_FLAG_SERVICE_CLIENT_REQUESTED;
+               set_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state);
                i40e_service_event_schedule(pf);
        }
        mutex_unlock(&i40e_device_mutex);
@@ -575,7 +564,7 @@ static int i40e_client_virtchnl_send(struct i40e_info *ldev,
  * i40e_client_setup_qvlist
  * @ldev: pointer to L2 context.
  * @client: Client pointer.
- * @qv_info: queue and vector list
+ * @qvlist_info: queue and vector list
  *
  * Return 0 on success or < 0 on error
  **/
@@ -650,7 +639,7 @@ err:
  * i40e_client_request_reset
  * @ldev: pointer to L2 context.
  * @client: Client pointer.
- * @level: reset level
+ * @reset_level: reset level
  **/
 static void i40e_client_request_reset(struct i40e_info *ldev,
                                      struct i40e_client *client,
similarity index 85%
rename from i40e-dkms/i40e-2.4.6/src/i40e_client.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_client.h
index 081cdb24295cedcd11ead789bb3cd2ad623d6a86..2202fafff9578e42750e09ffb840e15d144d36c3 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_CLIENT_H_
 #define _I40E_CLIENT_H_
similarity index 96%
rename from i40e-dkms/i40e-2.4.6/src/i40e_common.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_common.c
index da132e9a950fa7a297ad55e58be066a5a1ad0552..d13b51aa6ad50ca68dbb099d0816b3cf5362e255 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #include "i40e_type.h"
 #include "i40e_adminq.h"
@@ -48,6 +28,7 @@ static i40e_status i40e_set_mac_type(struct i40e_hw *hw)
                case I40E_DEV_ID_QSFP_C:
                case I40E_DEV_ID_10G_BASE_T:
                case I40E_DEV_ID_10G_BASE_T4:
+               case I40E_DEV_ID_10G_BASE_T_BC:
                case I40E_DEV_ID_20G_KR2:
                case I40E_DEV_ID_20G_KR2_A:
                case I40E_DEV_ID_25G_B:
@@ -949,6 +930,17 @@ i40e_status i40e_init_shared_code(struct i40e_hw *hw)
                hw->flags |= I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE |
                             I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK;
 
+       /* NVMUpdate features structure initialization */
+       hw->nvmupd_features.major = I40E_NVMUPD_FEATURES_API_VER_MAJOR;
+       hw->nvmupd_features.minor = I40E_NVMUPD_FEATURES_API_VER_MINOR;
+       hw->nvmupd_features.size = sizeof(hw->nvmupd_features);
+       i40e_memset(hw->nvmupd_features.features, 0x0,
+                   I40E_NVMUPD_FEATURES_API_FEATURES_ARRAY_LEN *
+                   sizeof(*hw->nvmupd_features.features),
+                   I40E_NONDMA_MEM);
+
+       hw->nvmupd_features.features[0] = I40E_NVMUPD_FEATURE_FLAT_NVM_SUPPORT;
+
        status = i40e_init_nvm(hw);
        return status;
 }
@@ -1168,6 +1160,8 @@ static enum i40e_media_type i40e_get_media_type(struct i40e_hw *hw)
                break;
        case I40E_PHY_TYPE_100BASE_TX:
        case I40E_PHY_TYPE_1000BASE_T:
+       case I40E_PHY_TYPE_2_5GBASE_T:
+       case I40E_PHY_TYPE_5GBASE_T:
        case I40E_PHY_TYPE_10GBASE_T:
                media = I40E_MEDIA_TYPE_BASET;
                break;
@@ -1204,6 +1198,29 @@ static enum i40e_media_type i40e_get_media_type(struct i40e_hw *hw)
        return media;
 }
 
+/**
+ * i40e_poll_globr - Poll for Global Reset completion
+ * @hw: pointer to the hardware structure
+ * @retry_limit: how many times to retry before failure
+ **/
+static i40e_status i40e_poll_globr(struct i40e_hw *hw,
+                                            u32 retry_limit)
+{
+       u32 cnt, reg = 0;
+
+       for (cnt = 0; cnt < retry_limit; cnt++) {
+               reg = rd32(hw, I40E_GLGEN_RSTAT);
+               if (!(reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK))
+                       return I40E_SUCCESS;
+               msleep(100);
+       }
+
+       hw_dbg(hw, "Global reset failed.\n");
+       hw_dbg(hw, "I40E_GLGEN_RSTAT = 0x%x\n", reg);
+
+       return I40E_ERR_RESET_FAILED;
+}
+
 #define I40E_PF_RESET_WAIT_COUNT       200
 /**
  * i40e_pf_reset - Reset the PF
@@ -1227,7 +1244,7 @@ i40e_status i40e_pf_reset(struct i40e_hw *hw)
                        I40E_GLGEN_RSTCTL_GRSTDEL_MASK) >>
                        I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT;
 
-       grst_del = grst_del * 20;
+       grst_del = min(grst_del * 20, 160U);
 
        for (cnt = 0; cnt < grst_del; cnt++) {
                reg = rd32(hw, I40E_GLGEN_RSTAT);
@@ -1273,14 +1290,14 @@ i40e_status i40e_pf_reset(struct i40e_hw *hw)
                        if (!(reg & I40E_PFGEN_CTRL_PFSWR_MASK))
                                break;
                        reg2 = rd32(hw, I40E_GLGEN_RSTAT);
-                       if (reg2 & I40E_GLGEN_RSTAT_DEVSTATE_MASK) {
-                               hw_dbg(hw, "Core reset upcoming.\n");
-                               hw_dbg(hw, "I40E_GLGEN_RSTAT = 0x%x\n", reg2);
-                               return I40E_ERR_NOT_READY;
-                       }
+                       if (reg2 & I40E_GLGEN_RSTAT_DEVSTATE_MASK)
+                               break;
                        usleep_range(1000, 2000);
                }
-               if (reg & I40E_PFGEN_CTRL_PFSWR_MASK) {
+               if (reg2 & I40E_GLGEN_RSTAT_DEVSTATE_MASK) {
+                       if (i40e_poll_globr(hw, grst_del) != I40E_SUCCESS)
+                               return I40E_ERR_RESET_FAILED;
+               } else if (reg & I40E_PFGEN_CTRL_PFSWR_MASK) {
                        hw_dbg(hw, "PF reset polling failed to complete.\n");
                        return I40E_ERR_RESET_FAILED;
                }
@@ -1648,6 +1665,8 @@ i40e_status i40e_aq_set_phy_config(struct i40e_hw *hw,
 /**
  * i40e_set_fc
  * @hw: pointer to the hw struct
+ * @aq_failures: buffer to return AdminQ failure information
+ * @atomic_restart: whether to enable atomic link restart
  *
  * Set the requested flow control mode using set_phy_config.
  **/
@@ -2429,13 +2448,14 @@ i40e_status i40e_aq_get_switch_config(struct i40e_hw *hw,
  * i40e_aq_set_switch_config
  * @hw: pointer to the hardware structure
  * @flags: bit flag values to set
+ * @mode: cloud filter mode
  * @valid_flags: which bit flags to set
  * @cmd_details: pointer to command details structure or NULL
  *
  * Set switch configuration bits
  **/
 i40e_status i40e_aq_set_switch_config(struct i40e_hw *hw,
-                               u16 flags, u16 valid_flags,
+                               u16 flags, u16 valid_flags, u8 mode,
                                struct i40e_asq_cmd_details *cmd_details)
 {
        struct i40e_aq_desc desc;
@@ -2447,6 +2467,7 @@ i40e_status i40e_aq_set_switch_config(struct i40e_hw *hw,
                                          i40e_aqc_opc_set_switch_config);
        scfg->flags = CPU_TO_LE16(flags);
        scfg->valid_flags = CPU_TO_LE16(valid_flags);
+       scfg->mode = mode;
        if (hw->flags & I40E_HW_FLAG_802_1AD_CAPABLE) {
                scfg->switch_tag = CPU_TO_LE16(hw->switch_tag);
                scfg->first_tag = CPU_TO_LE16(hw->first_tag);
@@ -2816,8 +2837,8 @@ i40e_status i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 seid,
  * @mr_list: list of mirrored VSI SEIDs or VLAN IDs
  * @cmd_details: pointer to command details structure or NULL
  * @rule_id: Rule ID returned from FW
- * @rule_used: Number of rules used in internal switch
- * @rule_free: Number of rules free in internal switch
+ * @rules_used: Number of rules used in internal switch
+ * @rules_free: Number of rules free in internal switch
  *
  * Add/Delete a mirror rule to a specific switch. Mirror rules are supported for
  * VEBs/VEPA elements only
@@ -2877,8 +2898,8 @@ static i40e_status i40e_mirrorrule_op(struct i40e_hw *hw,
  * @mr_list: list of mirrored VSI SEIDs or VLAN IDs
  * @cmd_details: pointer to command details structure or NULL
  * @rule_id: Rule ID returned from FW
- * @rule_used: Number of rules used in internal switch
- * @rule_free: Number of rules free in internal switch
+ * @rules_used: Number of rules used in internal switch
+ * @rules_free: Number of rules free in internal switch
  *
  * Add mirror rule. Mirror rules are supported for VEBs or VEPA elements only
  **/
@@ -2908,8 +2929,8 @@ i40e_status i40e_aq_add_mirrorrule(struct i40e_hw *hw, u16 sw_seid,
  *             add_mirrorrule.
  * @mr_list: list of mirrored VLAN IDs to be removed
  * @cmd_details: pointer to command details structure or NULL
- * @rule_used: Number of rules used in internal switch
- * @rule_free: Number of rules free in internal switch
+ * @rules_used: Number of rules used in internal switch
+ * @rules_free: Number of rules free in internal switch
  *
  * Delete a mirror rule. Mirror rules are supported for VEBs/VEPA elements only
  **/
@@ -3226,6 +3247,8 @@ i40e_status i40e_aq_write_nvm_config(struct i40e_hw *hw,
 /**
  * i40e_aq_oem_post_update - triggers an OEM specific flow after update
  * @hw: pointer to the hw struct
+ * @buff: buffer for result
+ * @buff_size: buffer size
  * @cmd_details: pointer to command details structure or NULL
  **/
 i40e_status i40e_aq_oem_post_update(struct i40e_hw *hw,
@@ -3302,9 +3325,10 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff,
        u32 valid_functions, num_functions;
        u32 number, logical_id, phys_id;
        struct i40e_hw_capabilities *p;
+       i40e_status status;
+       u16 id, ocp_cfg_word0;
        u8 major_rev;
        u32 i = 0;
-       u16 id;
 
        cap = (struct i40e_aqc_list_capabilities_element_resp *) buff;
 
@@ -3596,6 +3620,26 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff,
                        hw->num_ports++;
        }
 
+       /* OCP cards case: if a mezz is removed the ethernet port is at
+        * disabled state in PRTGEN_CNF register. Additional NVM read is
+        * needed in order to check if we are dealing with OCP card.
+        * Those cards have 4 PFs at minimum, so using PRTGEN_CNF for counting
+        * physical ports results in wrong partition id calculation and thus
+        * not supporting WoL.
+        */
+       if (hw->mac.type == I40E_MAC_X722) {
+               if (i40e_acquire_nvm(hw, I40E_RESOURCE_READ) == I40E_SUCCESS) {
+                       status = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR,
+                                                 2 * I40E_SR_OCP_CFG_WORD0,
+                                                 sizeof(ocp_cfg_word0),
+                                                 &ocp_cfg_word0, true, NULL);
+                       if (status == I40E_SUCCESS &&
+                           (ocp_cfg_word0 & I40E_SR_OCP_ENABLED))
+                               hw->num_ports = 4;
+                       i40e_release_nvm(hw);
+               }
+       }
+
        valid_functions = p->valid_functions;
        num_functions = 0;
        while (valid_functions) {
@@ -3723,10 +3767,46 @@ i40e_aq_update_nvm_exit:
        return status;
 }
 
+/**
+ * i40e_aq_rearrange_nvm
+ * @hw: pointer to the hw struct
+ * @rearrange_nvm: defines direction of rearrangement
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Rearrange NVM structure, available only for transition FW
+ **/
+i40e_status i40e_aq_rearrange_nvm(struct i40e_hw *hw,
+                               u8 rearrange_nvm,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aqc_nvm_update *cmd;
+       i40e_status status;
+       struct i40e_aq_desc desc;
+
+       cmd = (struct i40e_aqc_nvm_update *)&desc.params.raw;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_nvm_update);
+
+       rearrange_nvm &= (I40E_AQ_NVM_REARRANGE_TO_FLAT |
+                        I40E_AQ_NVM_REARRANGE_TO_STRUCT);
+
+       if (!rearrange_nvm) {
+               status = I40E_ERR_PARAM;
+               goto i40e_aq_rearrange_nvm_exit;
+       }
+
+       cmd->command_flags |= rearrange_nvm;
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+i40e_aq_rearrange_nvm_exit:
+       return status;
+}
+
 /**
  * i40e_aq_nvm_progress
  * @hw: pointer to the hw struct
  * @progress: pointer to progress returned from AQ
+ * @cmd_details: pointer to command details structure or NULL
  *
  * Gets progress of flash rearrangement process
  **/
@@ -3827,7 +3907,7 @@ i40e_status i40e_aq_set_lldp_mib(struct i40e_hw *hw,
 
        cmd->type = mib_type;
        cmd->length = CPU_TO_LE16(buff_size);
-       cmd->address_high = CPU_TO_LE32(high_16_bits((u64)buff));
+       cmd->address_high = CPU_TO_LE32(upper_32_bits((u64)buff));
        cmd->address_low =  CPU_TO_LE32(lower_32_bits((u64)buff));
 
        status = i40e_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
@@ -3927,6 +4007,9 @@ i40e_aq_set_dcb_parameters(struct i40e_hw *hw, bool dcb_enable,
                (struct i40e_aqc_set_dcb_parameters *)&desc.params.raw;
        i40e_status status;
 
+       if (!(hw->flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE))
+               return I40E_ERR_DEVICE_NOT_SUPPORTED;
+
        i40e_fill_default_direct_cmd_desc(&desc,
                                          i40e_aqc_opc_set_dcb_parameters);
 
@@ -4001,7 +4084,6 @@ i40e_status i40e_aq_start_stop_dcbx(struct i40e_hw *hw,
  * i40e_aq_add_udp_tunnel
  * @hw: pointer to the hw struct
  * @udp_port: the UDP port to add in Host byte order
- * @header_len: length of the tunneling header length in DWords
  * @protocol_index: protocol index type
  * @filter_index: pointer to filter index
  * @cmd_details: pointer to command details structure or NULL
@@ -4267,6 +4349,7 @@ i40e_status i40e_aq_config_vsi_tc_bw(struct i40e_hw *hw,
  * @hw: pointer to the hw struct
  * @seid: seid of the switching component connected to Physical Port
  * @ets_data: Buffer holding ETS parameters
+ * @opcode: Tx scheduler AQ command opcode
  * @cmd_details: pointer to command details structure or NULL
  **/
 i40e_status i40e_aq_config_switch_comp_ets(struct i40e_hw *hw,
@@ -4611,10 +4694,10 @@ i40e_status i40e_aq_add_rem_control_packet_filter(struct i40e_hw *hw,
  * @hw: pointer to the hw struct
  * @seid: VSI seid to add ethertype filter from
  **/
-#define I40E_FLOW_CONTROL_ETHTYPE 0x8808
 void i40e_add_filter_to_drop_tx_flow_control_frames(struct i40e_hw *hw,
                                                    u16 seid)
 {
+#define I40E_FLOW_CONTROL_ETHTYPE 0x8808
        u16 flag = I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC |
                   I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP |
                   I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TX;
@@ -4637,10 +4720,10 @@ void i40e_add_filter_to_drop_tx_flow_control_frames(struct i40e_hw *hw,
  * to be shifted 1 byte over from the VxLAN VNI
  **/
 static void i40e_fix_up_geneve_vni(
-       struct i40e_aqc_add_remove_cloud_filters_element_data *filters,
+       struct i40e_aqc_cloud_filters_element_data *filters,
        u8 filter_count)
 {
-       struct i40e_aqc_add_remove_cloud_filters_element_data *f = filters;
+       struct i40e_aqc_cloud_filters_element_data *f = filters;
        int i;
 
        for (i = 0; i < filter_count; i++) {
@@ -4665,13 +4748,13 @@ static void i40e_fix_up_geneve_vni(
  * @filter_count: number of filters contained in the buffer
  *
  * Set the cloud filters for a given VSI.  The contents of the
- * i40e_aqc_add_remove_cloud_filters_element_data are filled
+ * i40e_aqc_cloud_filters_element_data are filled
  * in by the caller of the function.
  *
  **/
 i40e_status i40e_aq_add_cloud_filters(struct i40e_hw *hw,
        u16 seid,
-       struct i40e_aqc_add_remove_cloud_filters_element_data *filters,
+       struct i40e_aqc_cloud_filters_element_data *filters,
        u8 filter_count)
 {
        struct i40e_aq_desc desc;
@@ -4697,21 +4780,21 @@ i40e_status i40e_aq_add_cloud_filters(struct i40e_hw *hw,
 }
 
 /**
- * i40e_aq_add_cloud_filters_big_buffer
+ * i40e_aq_add_cloud_filters_bb
  * @hw: pointer to the hardware structure
  * @seid: VSI seid to add cloud filters from
  * @filters: Buffer which contains the filters in big buffer to be added
  * @filter_count: number of filters contained in the buffer
  *
  * Set the cloud filters for a given VSI.  The contents of the
- * i40e_aqc_add_rm_cloud_filt_elem_ext are filled in by the caller of
+ * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the
  * the function.
  *
  **/
-i40e_status i40e_aq_add_cloud_filters_big_buffer(struct i40e_hw *hw,
-       u16 seid,
-       struct i40e_aqc_add_rm_cloud_filt_elem_ext *filters,
-       u8 filter_count)
+enum i40e_status_code
+i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
+                            struct i40e_aqc_cloud_filters_element_bb *filters,
+                            u8 filter_count)
 {
        struct i40e_aq_desc desc;
        struct i40e_aqc_add_remove_cloud_filters *cmd =
@@ -4728,9 +4811,8 @@ i40e_status i40e_aq_add_cloud_filters_big_buffer(struct i40e_hw *hw,
        desc.flags |= CPU_TO_LE16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
        cmd->num_filters = filter_count;
        cmd->seid = CPU_TO_LE16(seid);
-       cmd->big_buffer_flag = I40E_AQC_ADD_REM_CLOUD_CMD_BIG_BUFFER;
+       cmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;
 
-       /* adjust Geneve VNI for HW issue */
        for (i = 0; i < filter_count; i++) {
                u16 tnl_type;
                u32 ti;
@@ -4738,6 +4820,11 @@ i40e_status i40e_aq_add_cloud_filters_big_buffer(struct i40e_hw *hw,
                tnl_type = (LE16_TO_CPU(filters[i].element.flags) &
                           I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>
                           I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;
+
+               /* Due to hardware eccentricities, the VNI for Geneve is shifted
+                * one more byte further than normally used for Tenant ID in
+                * other tunnel types.
+                */
                if (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {
                        ti = LE32_TO_CPU(filters[i].element.tenant_id);
                        filters[i].element.tenant_id = CPU_TO_LE32(ti << 8);
@@ -4750,21 +4837,21 @@ i40e_status i40e_aq_add_cloud_filters_big_buffer(struct i40e_hw *hw,
 }
 
 /**
- * i40e_aq_remove_cloud_filters
+ * i40e_aq_rem_cloud_filters
  * @hw: pointer to the hardware structure
  * @seid: VSI seid to remove cloud filters from
  * @filters: Buffer which contains the filters to be removed
  * @filter_count: number of filters contained in the buffer
  *
  * Remove the cloud filters for a given VSI.  The contents of the
- * i40e_aqc_add_remove_cloud_filters_element_data are filled
- * in by the caller of the function.
+ * i40e_aqc_cloud_filters_element_data are filled in by the caller
+ * of the function.
  *
  **/
-i40e_status i40e_aq_remove_cloud_filters(struct i40e_hw *hw,
-       u16 seid,
-       struct i40e_aqc_add_remove_cloud_filters_element_data *filters,
-       u8 filter_count)
+enum i40e_status_code
+i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 seid,
+                         struct i40e_aqc_cloud_filters_element_data *filters,
+                         u8 filter_count)
 {
        struct i40e_aq_desc desc;
        struct i40e_aqc_add_remove_cloud_filters *cmd =
@@ -4789,22 +4876,21 @@ i40e_status i40e_aq_remove_cloud_filters(struct i40e_hw *hw,
 }
 
 /**
- * i40e_aq_remove_cloud_filters_big_buffer
+ * i40e_aq_rem_cloud_filters_bb
  * @hw: pointer to the hardware structure
  * @seid: VSI seid to remove cloud filters from
  * @filters: Buffer which contains the filters in big buffer to be removed
  * @filter_count: number of filters contained in the buffer
  *
- * Remove the cloud filters for a given VSI.  The contents of the
- * i40e_aqc_add_rm_cloud_filt_elem_ext are filled in by the caller of
- * the function.
+ * Remove the big buffer cloud filters for a given VSI.  The contents of the
+ * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the
+ * function.
  *
  **/
-i40e_status i40e_aq_remove_cloud_filters_big_buffer(
-       struct i40e_hw *hw,
-       u16 seid,
-       struct i40e_aqc_add_rm_cloud_filt_elem_ext *filters,
-       u8 filter_count)
+enum i40e_status_code
+i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
+                            struct i40e_aqc_cloud_filters_element_bb *filters,
+                            u8 filter_count)
 {
        struct i40e_aq_desc desc;
        struct i40e_aqc_add_remove_cloud_filters *cmd =
@@ -4821,9 +4907,8 @@ i40e_status i40e_aq_remove_cloud_filters_big_buffer(
        desc.flags |= CPU_TO_LE16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
        cmd->num_filters = filter_count;
        cmd->seid = CPU_TO_LE16(seid);
-       cmd->big_buffer_flag = I40E_AQC_ADD_REM_CLOUD_CMD_BIG_BUFFER;
+       cmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;
 
-       /* adjust Geneve VNI for HW issue */
        for (i = 0; i < filter_count; i++) {
                u16 tnl_type;
                u32 ti;
@@ -4831,6 +4916,11 @@ i40e_status i40e_aq_remove_cloud_filters_big_buffer(
                tnl_type = (LE16_TO_CPU(filters[i].element.flags) &
                           I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>
                           I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;
+
+               /* Due to hardware eccentricities, the VNI for Geneve is shifted
+                * one more byte further than normally used for Tenant ID in
+                * other tunnel types.
+                */
                if (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {
                        ti = LE32_TO_CPU(filters[i].element.tenant_id);
                        filters[i].element.tenant_id = CPU_TO_LE32(ti << 8);
@@ -4860,6 +4950,14 @@ i40e_status_code i40e_aq_replace_cloud_filters(struct i40e_hw *hw,
        i40e_status status = I40E_SUCCESS;
        int i = 0;
 
+       /* X722 doesn't support this command */
+       if (hw->mac.type == I40E_MAC_X722)
+               return I40E_ERR_DEVICE_NOT_SUPPORTED;
+
+       /* need FW version greater than 6.00 */
+       if (hw->aq.fw_maj_ver < 6)
+               return I40E_NOT_SUPPORTED;
+
        i40e_fill_default_direct_cmd_desc(&desc,
                                          i40e_aqc_opc_replace_cloud_filters);
 
@@ -4869,6 +4967,7 @@ i40e_status_code i40e_aq_replace_cloud_filters(struct i40e_hw *hw,
        cmd->new_filter_type = filters->new_filter_type;
        cmd->valid_flags = filters->valid_flags;
        cmd->tr_bit = filters->tr_bit;
+       cmd->tr_bit2 = filters->tr_bit2;
 
        status = i40e_asq_send_command(hw, &desc, cmd_buf,
                sizeof(struct i40e_aqc_replace_cloud_filters_cmd_buf),  NULL);
@@ -5001,6 +5100,7 @@ void i40e_set_pci_config_data(struct i40e_hw *hw, u16 link_status)
  * @ret_buff_size: actual buffer size returned
  * @ret_next_table: next block to read
  * @ret_next_index: next index to read
+ * @cmd_details: pointer to command details structure or NULL
  *
  * Dump internal FW/HW data for debug purposes.
  *
@@ -5123,7 +5223,7 @@ i40e_status i40e_aq_configure_partition_bw(struct i40e_hw *hw,
  * i40e_read_phy_register_clause22
  * @hw: pointer to the HW structure
  * @reg: register address in the page
- * @phy_adr: PHY address on MDIO interface
+ * @phy_addr: PHY address on MDIO interface
  * @value: PHY register value
  *
  * Reads specified PHY register value
@@ -5168,7 +5268,7 @@ i40e_status i40e_read_phy_register_clause22(struct i40e_hw *hw,
  * i40e_write_phy_register_clause22
  * @hw: pointer to the HW structure
  * @reg: register address in the page
- * @phy_adr: PHY address on MDIO interface
+ * @phy_addr: PHY address on MDIO interface
  * @value: PHY register value
  *
  * Writes specified PHY register value
@@ -5209,7 +5309,7 @@ i40e_status i40e_write_phy_register_clause22(struct i40e_hw *hw,
  * @hw: pointer to the HW structure
  * @page: registers page number
  * @reg: register address in the page
- * @phy_adr: PHY address on MDIO interface
+ * @phy_addr: PHY address on MDIO interface
  * @value: PHY register value
  *
  * Reads specified PHY register value
@@ -5283,7 +5383,7 @@ phy_read_end:
  * @hw: pointer to the HW structure
  * @page: registers page number
  * @reg: register address in the page
- * @phy_adr: PHY address on MDIO interface
+ * @phy_addr: PHY address on MDIO interface
  * @value: PHY register value
  *
  * Writes value to specified PHY register
@@ -5350,7 +5450,7 @@ phy_write_end:
  * @hw: pointer to the HW structure
  * @page: registers page number
  * @reg: register address in the page
- * @phy_adr: PHY address on MDIO interface
+ * @phy_addr: PHY address on MDIO interface
  * @value: PHY register value
  *
  * Writes value to specified PHY register
@@ -5367,6 +5467,7 @@ i40e_status i40e_write_phy_register(struct i40e_hw *hw,
                break;
        case I40E_DEV_ID_10G_BASE_T:
        case I40E_DEV_ID_10G_BASE_T4:
+       case I40E_DEV_ID_10G_BASE_T_BC:
        case I40E_DEV_ID_10G_BASE_T_X722:
        case I40E_DEV_ID_25G_B:
        case I40E_DEV_ID_25G_SFP28:
@@ -5386,7 +5487,7 @@ i40e_status i40e_write_phy_register(struct i40e_hw *hw,
  * @hw: pointer to the HW structure
  * @page: registers page number
  * @reg: register address in the page
- * @phy_adr: PHY address on MDIO interface
+ * @phy_addr: PHY address on MDIO interface
  * @value: PHY register value
  *
  * Reads specified PHY register value
@@ -5403,6 +5504,7 @@ i40e_status i40e_read_phy_register(struct i40e_hw *hw,
                break;
        case I40E_DEV_ID_10G_BASE_T:
        case I40E_DEV_ID_10G_BASE_T4:
+       case I40E_DEV_ID_10G_BASE_T_BC:
        case I40E_DEV_ID_10G_BASE_T_X722:
        case I40E_DEV_ID_25G_B:
        case I40E_DEV_ID_25G_SFP28:
@@ -5421,7 +5523,6 @@ i40e_status i40e_read_phy_register(struct i40e_hw *hw,
  * i40e_get_phy_address
  * @hw: pointer to the HW structure
  * @dev_num: PHY port num that address we want
- * @phy_addr: Returned PHY address
  *
  * Gets PHY address for current port
  **/
@@ -5523,7 +5624,7 @@ static i40e_status i40e_led_get_reg(struct i40e_hw *hw, u16 led_addr,
        if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
                status = i40e_aq_get_phy_register(hw,
                                                I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
-                                               I40E_PHY_COM_REG_PAGE,
+                                               I40E_PHY_COM_REG_PAGE, true,
                                                I40E_PHY_LED_PROV_REG_1,
                                                reg_val, NULL);
        } else {
@@ -5551,7 +5652,7 @@ static i40e_status i40e_led_set_reg(struct i40e_hw *hw, u16 led_addr,
        if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
                status = i40e_aq_set_phy_register(hw,
                                                I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
-                                               I40E_PHY_COM_REG_PAGE,
+                                               I40E_PHY_COM_REG_PAGE, true,
                                                I40E_PHY_LED_PROV_REG_1,
                                                reg_val, NULL);
        } else {
@@ -5585,7 +5686,7 @@ i40e_status i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
        if (hw->flags & I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE) {
                status = i40e_aq_get_phy_register(hw,
                                                I40E_AQ_PHY_REG_ACCESS_EXTERNAL,
-                                               I40E_PHY_COM_REG_PAGE,
+                                               I40E_PHY_COM_REG_PAGE, true,
                                                I40E_PHY_LED_PROV_REG_1,
                                                &reg_val_aq, NULL);
                if (status == I40E_SUCCESS)
@@ -5615,7 +5716,9 @@ i40e_status i40e_led_get_phy(struct i40e_hw *hw, u16 *led_addr,
  * i40e_led_set_phy
  * @hw: pointer to the HW structure
  * @on: true or false
+ * @led_addr: address of led register to use
  * @mode: original val plus bit for set or ignore
+ *
  * Set led's on or off when controlled by the PHY
  *
  **/
@@ -5788,6 +5891,7 @@ do_retry:
  * @hw: pointer to the hw struct
  * @phy_select: select which phy should be accessed
  * @dev_addr: PHY device address
+ * @page_change: enable auto page change
  * @reg_addr: PHY register address
  * @reg_val: new register value
  * @cmd_details: pointer to command details structure or NULL
@@ -5795,7 +5899,7 @@ do_retry:
  * Write the external PHY register.
  **/
 i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw,
-                               u8 phy_select, u8 dev_addr,
+                               u8 phy_select, u8 dev_addr, bool page_change,
                                u32 reg_addr, u32 reg_val,
                                struct i40e_asq_cmd_details *cmd_details)
 {
@@ -5812,6 +5916,9 @@ i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw,
        cmd->reg_address = CPU_TO_LE32(reg_addr);
        cmd->reg_value = CPU_TO_LE32(reg_val);
 
+       if (!page_change)
+               cmd->cmd_flags = I40E_AQ_PHY_REG_ACCESS_DONT_CHANGE_QSFP_PAGE;
+
        status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
 
        return status;
@@ -5822,6 +5929,7 @@ i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw,
  * @hw: pointer to the hw struct
  * @phy_select: select which phy should be accessed
  * @dev_addr: PHY device address
+ * @page_change: enable auto page change
  * @reg_addr: PHY register address
  * @reg_val: read register value
  * @cmd_details: pointer to command details structure or NULL
@@ -5829,7 +5937,7 @@ i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw,
  * Read the external PHY register.
  **/
 i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw,
-                               u8 phy_select, u8 dev_addr,
+                               u8 phy_select, u8 dev_addr, bool page_change,
                                u32 reg_addr, u32 *reg_val,
                                struct i40e_asq_cmd_details *cmd_details)
 {
@@ -5845,6 +5953,9 @@ i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw,
        cmd->dev_addres = dev_addr;
        cmd->reg_address = CPU_TO_LE32(reg_addr);
 
+       if (!page_change)
+               cmd->cmd_flags = I40E_AQ_PHY_REG_ACCESS_DONT_CHANGE_QSFP_PAGE;
+
        status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
        if (!status)
                *reg_val = LE32_TO_CPU(cmd->reg_value);
@@ -5855,7 +5966,7 @@ i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw,
 /**
  * i40e_aq_set_arp_proxy_config
  * @hw: pointer to the HW structure
- * @proxy_config - pointer to proxy config command table struct
+ * @proxy_config: pointer to proxy config command table struct
  * @cmd_details: pointer to command details
  *
  * Set ARP offload parameters from pre-populated
@@ -6092,6 +6203,7 @@ i40e_status_code i40e_aq_write_ddp(struct i40e_hw *hw, void *buff,
  * @hw: pointer to the hw struct
  * @buff: command buffer (size in bytes = buff_size)
  * @buff_size: buffer size in bytes
+ * @flags: AdminQ command flags
  * @cmd_details: pointer to command details structure or NULL
  **/
 enum
similarity index 91%
rename from i40e-dkms/i40e-2.4.6/src/i40e_dcb.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_dcb.c
index 4bdffdceb6df74c7e3b879073a8f0ae75d9fe00c..d377d993e5f22616b7885a355167613eb9808995 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #include "i40e_adminq.h"
 #include "i40e_prototype.h"
@@ -939,6 +919,70 @@ i40e_status i40e_init_dcb(struct i40e_hw *hw)
        return ret;
 }
 
+/**
+ * _i40e_read_lldp_cfg - generic read of LLDP Configuration data from NVM
+ * @hw: pointer to the HW structure
+ * @lldp_cfg: pointer to hold lldp configuration variables
+ * @module: address of the module pointer
+ * @word_offset: offset of LLDP configuration
+ *
+ * Reads the LLDP configuration data from NVM using passed addresses
+ **/
+static i40e_status _i40e_read_lldp_cfg(struct i40e_hw *hw,
+                                         struct i40e_lldp_variables *lldp_cfg,
+                                         u8 module, u32 word_offset)
+{
+       u32 address, offset = (2 * word_offset);
+       i40e_status ret;
+       __le16 raw_mem;
+       u16 mem;
+
+       ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+       if (ret != I40E_SUCCESS)
+               return ret;
+
+       ret = i40e_aq_read_nvm(hw, 0x0, module * 2, sizeof(raw_mem), &raw_mem,
+                              true, NULL);
+       i40e_release_nvm(hw);
+       if (ret != I40E_SUCCESS)
+               return ret;
+
+       mem = LE16_TO_CPU(raw_mem);
+       /* Check if this pointer needs to be read in word size or 4K sector
+        * units.
+        */
+       if (mem & I40E_PTR_TYPE)
+               address = (0x7FFF & mem) * 4096;
+       else
+               address = (0x7FFF & mem) * 2;
+
+       ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+       if (ret != I40E_SUCCESS)
+               goto err_lldp_cfg;
+
+       ret = i40e_aq_read_nvm(hw, module, offset, sizeof(raw_mem), &raw_mem,
+                              true, NULL);
+       i40e_release_nvm(hw);
+       if (ret != I40E_SUCCESS)
+               return ret;
+
+       mem = LE16_TO_CPU(raw_mem);
+       offset = mem + word_offset;
+       offset *= 2;
+
+       ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+       if (ret != I40E_SUCCESS)
+               goto err_lldp_cfg;
+
+       ret = i40e_aq_read_nvm(hw, 0, address + offset,
+                              sizeof(struct i40e_lldp_variables), lldp_cfg,
+                              true, NULL);
+       i40e_release_nvm(hw);
+
+err_lldp_cfg:
+       return ret;
+}
+
 /**
  * i40e_read_lldp_cfg - read LLDP Configuration data from NVM
  * @hw: pointer to the HW structure
@@ -950,21 +994,34 @@ i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,
                                         struct i40e_lldp_variables *lldp_cfg)
 {
        i40e_status ret = I40E_SUCCESS;
-       u32 offset = (2 * I40E_NVM_LLDP_CFG_PTR);
+       u32 mem;
 
        if (!lldp_cfg)
                return I40E_ERR_PARAM;
 
        ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
        if (ret != I40E_SUCCESS)
-               goto err_lldp_cfg;
+               return ret;
 
-       ret = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR, offset,
-                              sizeof(struct i40e_lldp_variables),
-                              (u8 *)lldp_cfg,
-                              true, NULL);
+       ret = i40e_aq_read_nvm(hw, I40E_SR_NVM_CONTROL_WORD, 0, sizeof(mem),
+                              &mem, true, NULL);
        i40e_release_nvm(hw);
+       if (ret != I40E_SUCCESS)
+               return ret;
+
+       /* Read a bit that holds information whether we are running flat or
+        * structured NVM image. Flat image has LLDP configuration in shadow
+        * ram, so there is a need to pass different addresses for both cases.
+        */
+       if (mem & I40E_SR_NVM_MAP_STRUCTURE_TYPE) {
+               /* Flat NVM case */
+               ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_SR_EMP_MODULE_PTR,
+                                         I40E_SR_LLDP_CFG_PTR);
+       } else {
+               /* Good old structured NVM image */
+               ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_EMP_MODULE_PTR,
+                                         I40E_NVM_LLDP_CFG_PTR);
+       }
 
-err_lldp_cfg:
        return ret;
 }
similarity index 81%
rename from i40e-dkms/i40e-2.4.6/src/i40e_dcb.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_dcb.h
index f4123ea44fce8a3400ee8aebeb81fccab4e9c5d1..dfd5bf988e792bd069ff085de059b4605ba15d6f 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_DCB_H_
 #define _I40E_DCB_H_
similarity index 86%
rename from i40e-dkms/i40e-2.4.6/src/i40e_dcb_nl.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_dcb_nl.c
index 8982e765ca3c50ee928f11d6331896b8203a7115..0785695d70f0a3b23d455ade259aa0441d2a0352 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifdef CONFIG_DCB
 #include "i40e.h"
@@ -44,7 +24,7 @@ static void i40e_get_pfc_delay(struct i40e_hw *hw, u16 *delay)
 
 /**
  * i40e_dcbnl_ieee_getets - retrieve local IEEE ETS configuration
- * @netdev: the corresponding netdev
+ * @dev: the corresponding netdev
  * @ets: structure to hold the ETS information
  *
  * Returns local IEEE ETS configuration
@@ -83,8 +63,8 @@ static int i40e_dcbnl_ieee_getets(struct net_device *dev,
 
 /**
  * i40e_dcbnl_ieee_getpfc - retrieve local IEEE PFC configuration
- * @netdev: the corresponding netdev
- * @ets: structure to hold the PFC information
+ * @dev: the corresponding netdev
+ * @pfc: structure to hold the PFC information
  *
  * Returns local IEEE PFC configuration
  **/
@@ -116,7 +96,7 @@ static int i40e_dcbnl_ieee_getpfc(struct net_device *dev,
 
 /**
  * i40e_dcbnl_getdcbx - retrieve current DCBx capability
- * @netdev: the corresponding netdev
+ * @dev: the corresponding netdev
  *
  * Returns DCBx capability features
  **/
@@ -129,7 +109,8 @@ static u8 i40e_dcbnl_getdcbx(struct net_device *dev)
 
 /**
  * i40e_dcbnl_get_perm_hw_addr - MAC address used by DCBx
- * @netdev: the corresponding netdev
+ * @dev: the corresponding netdev
+ * @perm_addr: buffer to store the MAC address
  *
  * Returns the SAN MAC address used for LLDP exchange
  **/
diff --git a/i40e-dkms/i40e-2.7.29/src/i40e_ddp.c b/i40e-dkms/i40e-2.7.29/src/i40e_ddp.c
new file mode 100644 (file)
index 0000000..47db7c5
--- /dev/null
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#include "i40e.h"
+
+#include <linux/firmware.h>
+
+/**
+ * i40e_ddp_profiles_eq - checks if DDP profiles are the equivalent
+ * @a: new profile info
+ * @b: old profile info
+ *
+ * checks if DDP profiles are the equivalent.
+ * Returns true if profiles are the same.
+ **/
+static bool i40e_ddp_profiles_eq(struct i40e_profile_info *a,
+                                struct i40e_profile_info *b)
+{
+       return a->track_id == b->track_id &&
+              !memcmp(&a->version, &b->version, sizeof(a->version)) &&
+               !memcmp(&a->name, &b->name, I40E_DDP_NAME_SIZE);
+}
+
+/**
+ * i40e_ddp_does_profile_exist - checks if DDP profile loaded already
+ * @hw: HW data structure
+ * @pinfo: DDP profile information structure
+ *
+ * checks if DDP profile loaded already.
+ * Returns >0 if the profile exists.
+ * Returns  0 if the profile is absent.
+ * Returns <0 if error.
+ **/
+static int i40e_ddp_does_profile_exist(struct i40e_hw *hw,
+                                      struct i40e_profile_info *pinfo)
+{
+       struct i40e_ddp_profile_list *profile_list;
+       u8 buff[I40E_PROFILE_LIST_SIZE];
+       i40e_status status;
+       int i;
+
+       status = i40e_aq_get_ddp_list(hw, buff, I40E_PROFILE_LIST_SIZE, 0,
+                                     NULL);
+       if (status != I40E_SUCCESS)
+               return -1;
+
+       profile_list = (struct i40e_ddp_profile_list *)buff;
+       for (i = 0; i < profile_list->p_count; i++) {
+               if (i40e_ddp_profiles_eq(pinfo, &profile_list->p_info[i]))
+                       return 1;
+       }
+       return 0;
+}
+
+/**
+ * i40e_ddp_profiles_overlap - checks if DDP profiles overlap.
+ * @new: new profile info
+ * @old: old profile info
+ *
+ * checks if DDP profiles overlap.
+ * Returns true if profiles are overlap.
+ **/
+static bool i40e_ddp_profiles_overlap(struct i40e_profile_info *new,
+                                     struct i40e_profile_info *old)
+{
+       unsigned int group_id_old = (u8)((old->track_id & 0x00FF0000) >> 16);
+       unsigned int group_id_new = (u8)((new->track_id & 0x00FF0000) >> 16);
+
+       /* 0x00 group must be only the first */
+       if( group_id_new == 0 )
+               return true;
+       /* 0xFF group is compatible with anything else */
+       if( group_id_new == 0xFF || group_id_old == 0xFF)
+               return false;
+       /* otherwise only profiles from the same group are compatible*/
+       return group_id_old != group_id_new;
+}
+
+/**
+ * i40e_ddp_does_profiles_ - checks if DDP overlaps with existing one.
+ * @hw: HW data structure
+ * @pinfo: DDP profile information structure
+ *
+ * checks if DDP profile overlaps with existing one.
+ * Returns >0 if the profile overlaps.
+ * Returns  0 if the profile is ok.
+ * Returns <0 if error.
+ **/
+static int i40e_ddp_does_profile_overlap(struct i40e_hw *hw,
+                                        struct i40e_profile_info *pinfo)
+{
+       struct i40e_ddp_profile_list *profile_list;
+       u8 buff[I40E_PROFILE_LIST_SIZE];
+       i40e_status status;
+       int i;
+
+       status = i40e_aq_get_ddp_list(hw, buff, I40E_PROFILE_LIST_SIZE, 0,
+                                     NULL);
+       if (status != I40E_SUCCESS)
+               return -EIO;
+
+       profile_list = (struct i40e_ddp_profile_list *)buff;
+       for (i = 0; i < profile_list->p_count; i++) {
+               if (i40e_ddp_profiles_overlap(pinfo,
+                                             &profile_list->p_info[i]))
+                       return 1;
+       }
+       return 0;
+}
+
+
+/**
+ * i40e_add_pinfo
+ * @hw: pointer to the hardware structure
+ * @profile: pointer to the profile segment of the package
+ * @profile_info_sec: buffer for information section
+ * @track_id: package tracking id
+ *
+ * Register a profile to the list of loaded profiles.
+ */
+i40e_status i40e_add_pinfo(struct i40e_hw *hw,
+                                    struct i40e_profile_segment *profile,
+                                    u8 *profile_info_sec, u32 track_id)
+{
+       struct i40e_profile_section_header *sec;
+       struct i40e_profile_info *pinfo;
+       i40e_status status;
+       u32 offset = 0, info = 0;
+
+       sec = (struct i40e_profile_section_header *)profile_info_sec;
+       sec->tbl_size = 1;
+       sec->data_end = sizeof(struct i40e_profile_section_header) +
+                       sizeof(struct i40e_profile_info);
+       sec->section.type = SECTION_TYPE_INFO;
+       sec->section.offset = sizeof(struct i40e_profile_section_header);
+       sec->section.size = sizeof(struct i40e_profile_info);
+       pinfo = (struct i40e_profile_info *)(profile_info_sec +
+                                            sec->section.offset);
+       pinfo->track_id = track_id;
+       pinfo->version = profile->version;
+       pinfo->op = I40E_DDP_ADD_TRACKID;
+
+       /* Clear reserved field */
+       memset(pinfo->reserved, 0, sizeof(pinfo->reserved));
+       i40e_memcpy(pinfo->name, profile->name, I40E_DDP_NAME_SIZE,
+                   I40E_NONDMA_TO_NONDMA);
+
+       status = i40e_aq_write_ddp(hw, (void *)sec, sec->data_end,
+                                  track_id, &offset, &info, NULL);
+       return status;
+}
+
+/**
+ * i40e_del_pinfo - delete DDP profile info from NIC
+ * @hw: HW data structure
+ * @profile: DDP profile segment to be deleted
+ * @profile_info_sec: DDP profile section header
+ * @track_id: track ID of the profile for deletion
+ *
+ * Removes DDP profile from the NIC.
+ **/
+static enum i40e_status_code
+i40e_del_pinfo(struct i40e_hw *hw, struct i40e_profile_segment *profile,
+              u8 *profile_info_sec, u32 track_id)
+{
+       struct i40e_profile_section_header *sec;
+       struct i40e_profile_info *pinfo;
+       i40e_status status;
+       u32 offset = 0, info = 0;
+
+       sec = (struct i40e_profile_section_header *)profile_info_sec;
+       sec->tbl_size = 1;
+       sec->data_end = sizeof(struct i40e_profile_section_header) +
+                       sizeof(struct i40e_profile_info);
+       sec->section.type = SECTION_TYPE_INFO;
+       sec->section.offset = sizeof(struct i40e_profile_section_header);
+       sec->section.size = sizeof(struct i40e_profile_info);
+       pinfo = (struct i40e_profile_info *)(profile_info_sec +
+                                            sec->section.offset);
+       pinfo->track_id = track_id;
+       pinfo->version = profile->version;
+       pinfo->op = I40E_DDP_REMOVE_TRACKID;
+
+       /* Clear reserved field */
+       memset(pinfo->reserved, 0, sizeof(pinfo->reserved));
+       memcpy(pinfo->name, profile->name, I40E_DDP_NAME_SIZE);
+
+       status = i40e_aq_write_ddp(hw, (void *)sec, sec->data_end,
+                                  track_id, &offset, &info, NULL);
+       return status;
+}
+
+/**
+ * i40e_ddp_is_pkg_hdr_valid - performs basic pkg header integrity checks
+ * @netdev: net device structure (for logging purposes)
+ * @pkg_hdr: pointer to package header
+ * @size_huge: size of the whole DDP profile package in size_t
+ *
+ * Checks correctness of pkg header: Version, size too big/small, and
+ * all segment offsets alignment and boundaries. This function lets
+ * reject non DDP profile file to be loaded by administrator mistake.
+ **/
+bool i40e_ddp_is_pkg_hdr_valid(struct net_device *netdev,
+                              struct i40e_package_header *pkg_hdr, size_t size_huge)
+{
+       u32 size = 0xFFFFFFFFU & size_huge;
+       u32 pkg_hdr_size;
+       u32 segment;
+
+       if (!pkg_hdr)
+               return false;
+
+       if (pkg_hdr->version.major > 0) {
+               struct i40e_ddp_version ver = pkg_hdr->version;
+               netdev_err(netdev, "Unsupported DDP profile version %u.%u.%u.%u",
+                                  ver.major, ver.minor, ver.update, ver.draft);
+               return false;
+       }
+       if (size_huge > size) {
+               netdev_err(netdev, "Invalid DDP profile - size is bigger than 4G");
+               return false;
+       }
+       if (size < (sizeof(struct i40e_package_header) +
+               sizeof(struct i40e_metadata_segment) + sizeof(u32) * 2)) {
+               netdev_err(netdev, "Invalid DDP profile - size is too small.");
+               return false;
+       }
+
+       pkg_hdr_size = sizeof(u32) * (pkg_hdr->segment_count + 2U);
+       if (size < pkg_hdr_size) {
+               netdev_err(netdev, "Invalid DDP profile - too many segments");
+               return false;
+       }
+       for (segment = 0; segment < pkg_hdr->segment_count; ++segment ) {
+               u32 offset = pkg_hdr->segment_offset[segment];
+
+               if (0xFU & offset) {
+                       netdev_err(netdev, "Invalid DDP profile %u segment alignment", segment);
+                       return false;
+               }
+               if (pkg_hdr_size > offset || offset >= size) {
+                       netdev_err(netdev, "Invalid DDP profile %u segment offset", segment);
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+/**
+ * i40e_ddp_load - performs DDP loading
+ * @netdev: net device structure
+ * @data: buffer containing recipe file
+ * @size: size of the buffer
+ * @is_add: true when loading profile, false when rolling back the previous one
+ *
+ * Checks correctness and loads DDP profile to the NIC. The function is
+ * also used for rolling back previously loaded profile.
+ **/
+int i40e_ddp_load(struct net_device *netdev, const u8 *data, size_t size,
+                 bool is_add)
+{
+       u8 profile_info_sec[sizeof(struct i40e_profile_section_header) +
+                           sizeof(struct i40e_profile_info)];
+       struct i40e_metadata_segment *metadata_hdr;
+       struct i40e_profile_segment *profile_hdr;
+       struct i40e_profile_info pinfo;
+       struct i40e_package_header *pkg_hdr;
+       i40e_status status;
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       u32 track_id;
+       int istatus;
+
+       pkg_hdr = (struct i40e_package_header *)data;
+       if (!i40e_ddp_is_pkg_hdr_valid(netdev, pkg_hdr, size))
+               return -EINVAL;
+
+       if (size < (sizeof(struct i40e_package_header) +
+                   sizeof(struct i40e_metadata_segment) + sizeof(u32) * 2)) {
+               netdev_err(netdev, "Invalid DDP recipe size.");
+               return -EINVAL;
+       }
+
+       /* Find beginning of segment data in buffer */
+       metadata_hdr = (struct i40e_metadata_segment *)
+               i40e_find_segment_in_package(SEGMENT_TYPE_METADATA, pkg_hdr);
+       if (!metadata_hdr) {
+               netdev_err(netdev, "Failed to find metadata segment in DDP recipe.");
+               return -EINVAL;
+       }
+
+       track_id = metadata_hdr->track_id;
+       profile_hdr = (struct i40e_profile_segment *)
+               i40e_find_segment_in_package(SEGMENT_TYPE_I40E, pkg_hdr);
+       if (!profile_hdr) {
+               netdev_err(netdev, "Failed to find profile segment in DDP recipe.");
+               return -EINVAL;
+       }
+
+       pinfo.track_id = track_id;
+       pinfo.version = profile_hdr->version;
+       if (is_add)
+               pinfo.op = I40E_DDP_ADD_TRACKID;
+       else
+               pinfo.op = I40E_DDP_REMOVE_TRACKID;
+
+       memcpy(pinfo.name, profile_hdr->name, I40E_DDP_NAME_SIZE);
+
+       /* Check if profile data already exists*/
+       istatus = i40e_ddp_does_profile_exist(&pf->hw, &pinfo);
+       if (istatus < 0) {
+               netdev_err(netdev, "Failed to fetch loaded profiles.");
+               return istatus;
+       }
+       if (is_add) {
+               if (istatus > 0) {
+                       netdev_err(netdev, "DDP profile already loaded.");
+                       return -EINVAL;
+               }
+               istatus = i40e_ddp_does_profile_overlap(&pf->hw, &pinfo);
+               if (istatus < 0) {
+                       netdev_err(netdev, "Failed to fetch loaded profiles.");
+                       return istatus;
+               }
+               if (istatus > 0) {
+                       netdev_err(netdev, "DDP profile overlaps with existing one.");
+                       return -EINVAL;
+               }
+       } else {
+               if (istatus == 0) {
+                       netdev_err(netdev,
+                                  "DDP profile for deletion does not exist.");
+                       return -EINVAL;
+               }
+       }
+
+       /* Load profile data */
+       if (is_add) {
+               status = i40e_write_profile(&pf->hw, profile_hdr, track_id);
+               if (status) {
+                       if ( status == I40E_ERR_DEVICE_NOT_SUPPORTED) {
+                           netdev_err(netdev, "Profile is not supported by the device.");
+                           return -EPERM;
+                       }
+                       netdev_err(netdev, "Failed to write DDP profile.");
+                       return -EIO;
+               }
+       } else {
+               status = i40e_rollback_profile(&pf->hw, profile_hdr, track_id);
+               if (status) {
+                       netdev_err(netdev, "Failed to remove DDP profile.");
+                       return -EIO;
+               }
+       }
+
+       /* Add/remove profile to/from profile list in FW */
+       if (is_add) {
+               status = i40e_add_pinfo(&pf->hw, profile_hdr, profile_info_sec,
+                                       track_id);
+               if (status) {
+                       netdev_err(netdev, "Failed to add DDP profile info.");
+                       return -EIO;
+               }
+       } else {
+               status = i40e_del_pinfo(&pf->hw, profile_hdr, profile_info_sec,
+                                       track_id);
+               if (status) {
+                       netdev_err(netdev, "Failed to restore DDP profile info.");
+                       return -EIO;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_ddp_restore - restore previously loaded profile and remove from list
+ * @pf: PF data struct
+ *
+ * Restores previously loaded profile stored on the list in driver memory.
+ * After rolling back removes entry from the list.
+ **/
+int i40e_ddp_restore(struct i40e_pf *pf)
+{
+       struct i40e_ddp_old_profile_list *entry;
+       struct net_device *netdev = pf->vsi[pf->lan_vsi]->netdev;
+       int status = 0;
+
+       if (!list_empty(&pf->ddp_old_prof)) {
+               entry = list_first_entry(&pf->ddp_old_prof,
+                                        struct i40e_ddp_old_profile_list,
+                                        list);
+               status = i40e_ddp_load(netdev, entry->old_ddp_buf,
+                                      entry->old_ddp_size, false);
+               list_del(&entry->list);
+               kfree(entry);
+       }
+       return status;
+}
+
+/**
+ * i40e_ddp_flash - callback function for ethtool flash feature
+ * @netdev: net device structure
+ * @flash: kernel flash structure
+ *
+ * Ethtool callback function used for loading and unloading DDP profiles.
+ **/
+int i40e_ddp_flash(struct net_device *netdev, struct ethtool_flash *flash)
+{
+       const struct firmware *ddp_config;
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       int status = 0;
+
+       /* Check for valid region first */
+       if(flash->region != I40_DDP_FLASH_REGION) {
+               netdev_err(netdev, "Requested firmware region is not recognized by this driver.");
+               return -EINVAL;
+       }
+       if(pf->hw.bus.func != 0) {
+               netdev_err(netdev, "Any DDP operation is allowed only on Phy0 NIC interface");
+               return -EINVAL;
+       }
+
+       /* If the user supplied "-" instead of file name rollback previously
+        * stored profile.
+        */
+       if (strncmp(flash->data, "-", 2) != 0) {
+               struct i40e_ddp_old_profile_list *list_entry;
+               char profile_name[sizeof(I40E_DDP_PROFILE_PATH)+I40E_DDP_PROFILE_NAME_MAX];
+
+               profile_name[sizeof(profile_name)-1]=0;
+               strncpy(profile_name, I40E_DDP_PROFILE_PATH, sizeof(profile_name)-1);
+               strncat(profile_name, flash->data, I40E_DDP_PROFILE_NAME_MAX);
+               /* Load DDP recipe. */
+               status = request_firmware(&ddp_config, profile_name,
+                                         &netdev->dev);
+               if (status) {
+                       netdev_err(netdev, "DDP recipe file request failed.");
+                       return status;
+               }
+
+               status = i40e_ddp_load(netdev, ddp_config->data,
+                                      ddp_config->size, true);
+
+               if (!status) {
+                       list_entry = kzalloc(
+                               sizeof(struct i40e_ddp_old_profile_list) +
+                               ddp_config->size, GFP_KERNEL);
+                       if (!list_entry) {
+                               netdev_info(netdev, "Failed to allocate memory for previous DDP profile data.");
+                               netdev_info(netdev, "New profile loaded but roll-back will be impossible.");
+                       } else {
+                               memcpy(list_entry->old_ddp_buf,
+                                      ddp_config->data, ddp_config->size);
+                               list_entry->old_ddp_size = ddp_config->size;
+                               list_add(&list_entry->list, &pf->ddp_old_prof);
+                       }
+               }
+
+               release_firmware(ddp_config);
+       } else {
+               if (!list_empty(&pf->ddp_old_prof)) {
+                       status = i40e_ddp_restore(pf);
+               } else {
+                       netdev_warn(netdev, "There is no DDP profile to restore.");
+                       status = -ENOENT;
+               }
+       }
+       return status;
+}
similarity index 96%
rename from i40e-dkms/i40e-2.4.6/src/i40e_debugfs.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_debugfs.c
index 60ce72864ddf5c6736767f042d385b6adbbeb0cb..b78e0a5025f3bab0fa9e51de09201a3e4663e5be 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifdef CONFIG_DEBUG_FS
 
@@ -32,8 +12,8 @@ static struct dentry *i40e_dbg_root;
 
 /**
  * i40e_dbg_find_vsi - searches for the vsi with the given seid
- * @pf - the PF structure to search for the vsi
- * @seid - seid of the vsi it is searching for
+ * @pf: the PF structure to search for the vsi
+ * @seid: seid of the vsi it is searching for
  **/
 static struct i40e_vsi *i40e_dbg_find_vsi(struct i40e_pf *pf, int seid)
 {
@@ -51,8 +31,8 @@ static struct i40e_vsi *i40e_dbg_find_vsi(struct i40e_pf *pf, int seid)
 
 /**
  * i40e_dbg_find_veb - searches for the veb with the given seid
- * @pf - the PF structure to search for the veb
- * @seid - seid of the veb it is searching for
+ * @pf: the PF structure to search for the veb
+ * @seid: seid of the veb it is searching for
  **/
 static struct i40e_veb *i40e_dbg_find_veb(struct i40e_pf *pf, int seid)
 {
@@ -207,12 +187,11 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
 #endif
        }
 #ifdef HAVE_VLAN_RX_REGISTER
-       if (vsi->vlgrp)
-               dev_info(&pf->pdev->dev,
-                        "    vlgrp: & = %p\n", vsi->vlgrp);
+       dev_info(&pf->pdev->dev, "    vlgrp is %s\n",
+                vsi->vlgrp ? "<valid>" : "<null>");
 #else
-       dev_info(&pf->pdev->dev,
-                "    vlgrp: & = %p\n", vsi->active_vlans);
+       dev_info(&pf->pdev->dev, "    active_vlans is %s\n",
+                vsi->active_vlans ? "<valid>" : "<null>");
 #endif /* HAVE_VLAN_RX_REGISTER */
        dev_info(&pf->pdev->dev,
                 "    flags = 0x%016llx, netdev_registered = %i, current_netdev_flags = 0x%04x\n",
@@ -317,14 +296,6 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                if (!rx_ring)
                        continue;
 
-               dev_info(&pf->pdev->dev,
-                        "    rx_rings[%i]: desc = %p\n",
-                        i, rx_ring->desc);
-               dev_info(&pf->pdev->dev,
-                        "    rx_rings[%i]: dev = %p, netdev = %p, rx_bi = %p\n",
-                        i, rx_ring->dev,
-                        rx_ring->netdev,
-                        rx_ring->rx_bi);
                dev_info(&pf->pdev->dev,
                         "    rx_rings[%i]: state = %lu, queue_index = %d, reg_idx = %d\n",
                         i, *rx_ring->state,
@@ -355,13 +326,8 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                         rx_ring->rx_stats.realloc_count,
                         rx_ring->rx_stats.page_reuse_count);
                dev_info(&pf->pdev->dev,
-                        "    rx_rings[%i]: size = %i, dma = 0x%08lx\n",
-                        i, rx_ring->size,
-                        (unsigned long int)rx_ring->dma);
-               dev_info(&pf->pdev->dev,
-                        "    rx_rings[%i]: vsi = %p, q_vector = %p\n",
-                        i, rx_ring->vsi,
-                        rx_ring->q_vector);
+                        "    rx_rings[%i]: size = %i\n",
+                        i, rx_ring->size);
                dev_info(&pf->pdev->dev,
                         "    rx_rings[%i]: rx_itr_setting = %d (%s)\n",
                         i, rx_ring->itr_setting,
@@ -374,14 +340,6 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                if (!tx_ring)
                        continue;
 
-               dev_info(&pf->pdev->dev,
-                        "    tx_rings[%i]: desc = %p\n",
-                        i, tx_ring->desc);
-               dev_info(&pf->pdev->dev,
-                        "    tx_rings[%i]: dev = %p, netdev = %p, tx_bi = %p\n",
-                        i, tx_ring->dev,
-                        tx_ring->netdev,
-                        tx_ring->tx_bi);
                dev_info(&pf->pdev->dev,
                         "    tx_rings[%i]: state = %lu, queue_index = %d, reg_idx = %d\n",
                         i, *tx_ring->state,
@@ -404,13 +362,8 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                         tx_ring->tx_stats.tx_busy,
                         tx_ring->tx_stats.tx_done_old);
                dev_info(&pf->pdev->dev,
-                        "    tx_rings[%i]: size = %i, dma = 0x%08lx\n",
-                        i, tx_ring->size,
-                        (unsigned long int)tx_ring->dma);
-               dev_info(&pf->pdev->dev,
-                        "    tx_rings[%i]: vsi = %p, q_vector = %p\n",
-                        i, tx_ring->vsi,
-                        tx_ring->q_vector);
+                        "    tx_rings[%i]: size = %i\n",
+                        i, tx_ring->size);
                dev_info(&pf->pdev->dev,
                         "    tx_rings[%i]: DCB tc = %d\n",
                         i, tx_ring->dcb_tc);
@@ -516,8 +469,6 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
                 vsi->info.resp_reserved[6], vsi->info.resp_reserved[7],
                 vsi->info.resp_reserved[8], vsi->info.resp_reserved[9],
                 vsi->info.resp_reserved[10], vsi->info.resp_reserved[11]);
-       if (vsi->back)
-               dev_info(&pf->pdev->dev, "    PF = %p\n", vsi->back);
        dev_info(&pf->pdev->dev, "    idx = %d\n", vsi->idx);
        dev_info(&pf->pdev->dev,
                 "    tc_config: numtc = %d, enabled_tc = 0x%x\n",
@@ -1165,8 +1116,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                 */
                if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
                        pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
-                       i40e_do_reset_safe(pf,
-                                          BIT_ULL(__I40E_PF_RESET_REQUESTED));
+                       i40e_do_reset_safe(pf, I40E_PF_RESET_FLAG);
                }
 
                vsi = i40e_vsi_setup(pf, I40E_VSI_VMDQ2, vsi_seid, 0);
@@ -1753,6 +1703,12 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                if (strncmp(&cmd_buf[5], "stop", 4) == 0) {
                        int ret;
 
+                       if (pf->hw.flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE) {
+                               dev_info(&pf->pdev->dev,
+                                        "Use ethtool to disable LLDP firmware agent:"\
+                                        "\"ethtool --set-priv-flags <interface> disable-fw-lldp on\".\n");
+                               goto command_write_done;
+                       }
                        ret = i40e_aq_stop_lldp(&pf->hw, false, NULL);
                        if (ret) {
                                dev_info(&pf->pdev->dev,
@@ -1767,8 +1723,8 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                                                0, true, NULL, NULL);
                        if (ret) {
                                dev_info(&pf->pdev->dev,
-                                       "%s: Add Control Packet Filter AQ command failed =0x%x\n",
-                                       __func__, pf->hw.aq.asq_last_status);
+                                        "%s: Add Control Packet Filter AQ command failed =0x%x\n",
+                                        __func__, pf->hw.aq.asq_last_status);
                                goto command_write_done;
                        }
 #ifdef CONFIG_DCB
@@ -1780,6 +1736,12 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                } else if (strncmp(&cmd_buf[5], "start", 5) == 0) {
                        int ret;
 
+                       if (pf->hw.flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE) {
+                               dev_info(&pf->pdev->dev,
+                                        "Use ethtool to enable LLDP firmware agent:"\
+                                        "\"ethtool --set-priv-flags <interface> disable-fw-lldp off\".\n");
+                               goto command_write_done;
+                       }
                        ret = i40e_aq_add_rem_control_packet_filter(&pf->hw,
                                                pf->hw.mac.addr,
                                                I40E_ETH_P_LLDP, 0,
@@ -1787,11 +1749,10 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
                                                0, false, NULL, NULL);
                        if (ret) {
                                dev_info(&pf->pdev->dev,
-                                       "%s: Remove Control Packet Filter AQ command failed =0x%x\n",
-                                       __func__, pf->hw.aq.asq_last_status);
+                                        "%s: Remove Control Packet Filter AQ command failed =0x%x\n",
+                                        __func__, pf->hw.aq.asq_last_status);
                                /* Continue and start FW LLDP anyways */
                        }
-
                        ret = i40e_aq_start_lldp(&pf->hw, NULL);
                        if (ret) {
                                dev_info(&pf->pdev->dev,
@@ -2379,8 +2340,13 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
                        dev_info(&pf->pdev->dev, "change_mtu: no netdev for VSI %d\n",
                                 vsi_seid);
                } else if (rtnl_trylock()) {
+#ifdef HAVE_RHEL7_EXTENDED_MIN_MAX_MTU
+                       vsi->netdev->netdev_ops->extended.ndo_change_mtu(
+                                                vsi->netdev, mtu);
+#else
                        vsi->netdev->netdev_ops->ndo_change_mtu(vsi->netdev,
                                                                mtu);
+#endif
                        rtnl_unlock();
                        dev_info(&pf->pdev->dev, "change_mtu called\n");
                } else {
diff --git a/i40e-dkms/i40e-2.7.29/src/i40e_devids.h b/i40e-dkms/i40e-2.7.29/src/i40e_devids.h
new file mode 100644 (file)
index 0000000..8d8cac6
--- /dev/null
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#define _I40E_DEVIDS_H_
+
+/* Device IDs */
+#define I40E_DEV_ID_SFP_XL710          0x1572
+#define I40E_DEV_ID_QEMU               0x1574
+#define I40E_DEV_ID_KX_B               0x1580
+#define I40E_DEV_ID_KX_C               0x1581
+#define I40E_DEV_ID_QSFP_A             0x1583
+#define I40E_DEV_ID_QSFP_B             0x1584
+#define I40E_DEV_ID_QSFP_C             0x1585
+#define I40E_DEV_ID_10G_BASE_T         0x1586
+#define I40E_DEV_ID_20G_KR2            0x1587
+#define I40E_DEV_ID_20G_KR2_A          0x1588
+#define I40E_DEV_ID_10G_BASE_T4                0x1589
+#define I40E_DEV_ID_25G_B              0x158A
+#define I40E_DEV_ID_25G_SFP28          0x158B
+#define I40E_DEV_ID_10G_BASE_T_BC      0x15FF
+#define I40E_DEV_ID_KX_X722            0x37CE
+#define I40E_DEV_ID_QSFP_X722          0x37CF
+#define I40E_DEV_ID_SFP_X722           0x37D0
+#define I40E_DEV_ID_1G_BASE_T_X722     0x37D1
+#define I40E_DEV_ID_10G_BASE_T_X722    0x37D2
+#define I40E_DEV_ID_SFP_I_X722         0x37D3
+
+#define i40e_is_40G_device(d)          ((d) == I40E_DEV_ID_QSFP_A  || \
+                                        (d) == I40E_DEV_ID_QSFP_B  || \
+                                        (d) == I40E_DEV_ID_QSFP_C)
+
+#define i40e_is_25G_device(d)          ((d) == I40E_DEV_ID_25G_B  || \
+                                        (d) == I40E_DEV_ID_25G_SFP28)
+
similarity index 79%
rename from i40e-dkms/i40e-2.4.6/src/i40e_diag.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_diag.c
index f4fb5313e663ae55dd806441e8d4e722c63a7e10..e72d862576cf275f791c162d45d630637a9ae069 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #include "i40e_diag.h"
 #include "i40e_prototype.h"
diff --git a/i40e-dkms/i40e-2.7.29/src/i40e_diag.h b/i40e-dkms/i40e-2.7.29/src/i40e_diag.h
new file mode 100644 (file)
index 0000000..c3340f3
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#ifndef _I40E_DIAG_H_
+#define _I40E_DIAG_H_
+
+#include "i40e_type.h"
+
+enum i40e_lb_mode {
+       I40E_LB_MODE_NONE       = 0x0,
+       I40E_LB_MODE_PHY_LOCAL  = I40E_AQ_LB_PHY_LOCAL,
+       I40E_LB_MODE_PHY_REMOTE = I40E_AQ_LB_PHY_REMOTE,
+       I40E_LB_MODE_MAC_LOCAL  = I40E_AQ_LB_MAC_LOCAL,
+};
+
+struct i40e_diag_reg_test_info {
+       u32 offset;     /* the base register */
+       u32 mask;       /* bits that can be tested */
+       u32 elements;   /* number of elements if array */
+       u32 stride;     /* bytes between each element */
+};
+
+extern struct i40e_diag_reg_test_info i40e_reg_list[];
+
+i40e_status i40e_diag_reg_test(struct i40e_hw *hw);
+i40e_status i40e_diag_eeprom_test(struct i40e_hw *hw);
+
+#endif /* _I40E_DIAG_H_ */
similarity index 86%
rename from i40e-dkms/i40e-2.4.6/src/i40e_ethtool.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_ethtool.c
index d97286f62ad28f93a9eface670d632614a9f5c64..71578a4a8978fdd3950c355eb277b06147dae7da 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 /* ethtool support for i40e */
 
 
 #endif
 #ifdef ETHTOOL_GSTATS
-struct i40e_stats {
-       char stat_string[ETH_GSTRING_LEN];
-       int sizeof_stat;
-       int stat_offset;
-};
 
-#define I40E_STAT(_type, _name, _stat) { \
-       .stat_string = _name, \
-       .sizeof_stat = FIELD_SIZEOF(_type, _stat), \
-       .stat_offset = offsetof(_type, _stat) \
-}
+#include "i40e_ethtool_stats.h"
 
-#ifdef HAVE_NDO_GET_STATS64
-#define I40E_NETDEV_STAT(_net_stat) \
-               I40E_STAT(struct rtnl_link_stats64, #_net_stat, _net_stat)
-#else
-#define I40E_NETDEV_STAT(_net_stat) \
-               I40E_STAT(struct net_device_stats, #_net_stat, _net_stat)
-#endif
 #define I40E_PF_STAT(_name, _stat) \
-               I40E_STAT(struct i40e_pf, _name, _stat)
+       I40E_STAT(struct i40e_pf, _name, _stat)
 #define I40E_VSI_STAT(_name, _stat) \
-               I40E_STAT(struct i40e_vsi, _name, _stat)
+       I40E_STAT(struct i40e_vsi, _name, _stat)
 #define I40E_VEB_STAT(_name, _stat) \
-               I40E_STAT(struct i40e_veb, _name, _stat)
+       I40E_STAT(struct i40e_veb, _name, _stat)
+#define I40E_PFC_STAT(_name, _stat) \
+       I40E_STAT(struct i40e_pfc_stats, _name, _stat)
+#define I40E_QUEUE_STAT(_name, _stat) \
+       I40E_STAT(struct i40e_ring, _name, _stat)
 
 static const struct i40e_stats i40e_gstrings_net_stats[] = {
        I40E_NETDEV_STAT(rx_packets),
@@ -73,18 +41,25 @@ static const struct i40e_stats i40e_gstrings_net_stats[] = {
 };
 
 static const struct i40e_stats i40e_gstrings_veb_stats[] = {
-       I40E_VEB_STAT("rx_bytes", stats.rx_bytes),
-       I40E_VEB_STAT("tx_bytes", stats.tx_bytes),
-       I40E_VEB_STAT("rx_unicast", stats.rx_unicast),
-       I40E_VEB_STAT("tx_unicast", stats.tx_unicast),
-       I40E_VEB_STAT("rx_multicast", stats.rx_multicast),
-       I40E_VEB_STAT("tx_multicast", stats.tx_multicast),
-       I40E_VEB_STAT("rx_broadcast", stats.rx_broadcast),
-       I40E_VEB_STAT("tx_broadcast", stats.tx_broadcast),
-       I40E_VEB_STAT("rx_discards", stats.rx_discards),
-       I40E_VEB_STAT("tx_discards", stats.tx_discards),
-       I40E_VEB_STAT("tx_errors", stats.tx_errors),
-       I40E_VEB_STAT("rx_unknown_protocol", stats.rx_unknown_protocol),
+       I40E_VEB_STAT("veb.rx_bytes", stats.rx_bytes),
+       I40E_VEB_STAT("veb.tx_bytes", stats.tx_bytes),
+       I40E_VEB_STAT("veb.rx_unicast", stats.rx_unicast),
+       I40E_VEB_STAT("veb.tx_unicast", stats.tx_unicast),
+       I40E_VEB_STAT("veb.rx_multicast", stats.rx_multicast),
+       I40E_VEB_STAT("veb.tx_multicast", stats.tx_multicast),
+       I40E_VEB_STAT("veb.rx_broadcast", stats.rx_broadcast),
+       I40E_VEB_STAT("veb.tx_broadcast", stats.tx_broadcast),
+       I40E_VEB_STAT("veb.rx_discards", stats.rx_discards),
+       I40E_VEB_STAT("veb.tx_discards", stats.tx_discards),
+       I40E_VEB_STAT("veb.tx_errors", stats.tx_errors),
+       I40E_VEB_STAT("veb.rx_unknown_protocol", stats.rx_unknown_protocol),
+};
+
+static const struct i40e_stats i40e_gstrings_veb_tc_stats[] = {
+       I40E_VEB_STAT("veb.tc_%u_tx_packets", tc_stats.tc_tx_packets),
+       I40E_VEB_STAT("veb.tc_%u_tx_bytes", tc_stats.tc_tx_bytes),
+       I40E_VEB_STAT("veb.tc_%u_rx_packets", tc_stats.tc_rx_packets),
+       I40E_VEB_STAT("veb.tc_%u_rx_bytes", tc_stats.tc_rx_bytes),
 };
 
 static const struct i40e_stats i40e_gstrings_misc_stats[] = {
@@ -97,6 +72,7 @@ static const struct i40e_stats i40e_gstrings_misc_stats[] = {
        I40E_VSI_STAT("rx_unknown_protocol", eth_stats.rx_unknown_protocol),
        I40E_VSI_STAT("tx_linearize", tx_linearize),
        I40E_VSI_STAT("tx_force_wb", tx_force_wb),
+       I40E_VSI_STAT("tx_busy", tx_busy),
        I40E_VSI_STAT("rx_alloc_fail", rx_buf_failed),
        I40E_VSI_STAT("rx_pg_alloc_fail", rx_page_failed),
 };
@@ -112,115 +88,124 @@ static const struct i40e_stats i40e_gstrings_misc_stats[] = {
  * is queried on the base PF netdev, not on the VMDq or FCoE netdev.
  */
 static const struct i40e_stats i40e_gstrings_stats[] = {
-       I40E_PF_STAT("rx_bytes", stats.eth.rx_bytes),
-       I40E_PF_STAT("tx_bytes", stats.eth.tx_bytes),
-       I40E_PF_STAT("rx_unicast", stats.eth.rx_unicast),
-       I40E_PF_STAT("tx_unicast", stats.eth.tx_unicast),
-       I40E_PF_STAT("rx_multicast", stats.eth.rx_multicast),
-       I40E_PF_STAT("tx_multicast", stats.eth.tx_multicast),
-       I40E_PF_STAT("rx_broadcast", stats.eth.rx_broadcast),
-       I40E_PF_STAT("tx_broadcast", stats.eth.tx_broadcast),
-       I40E_PF_STAT("tx_errors", stats.eth.tx_errors),
-       I40E_PF_STAT("rx_dropped", stats.eth.rx_discards),
-       I40E_PF_STAT("tx_dropped_link_down", stats.tx_dropped_link_down),
-       I40E_PF_STAT("rx_crc_errors", stats.crc_errors),
-       I40E_PF_STAT("illegal_bytes", stats.illegal_bytes),
-       I40E_PF_STAT("mac_local_faults", stats.mac_local_faults),
-       I40E_PF_STAT("mac_remote_faults", stats.mac_remote_faults),
-       I40E_PF_STAT("tx_timeout", tx_timeout_count),
-       I40E_PF_STAT("rx_csum_bad", hw_csum_rx_error),
-       I40E_PF_STAT("rx_length_errors", stats.rx_length_errors),
-       I40E_PF_STAT("link_xon_rx", stats.link_xon_rx),
-       I40E_PF_STAT("link_xoff_rx", stats.link_xoff_rx),
-       I40E_PF_STAT("link_xon_tx", stats.link_xon_tx),
-       I40E_PF_STAT("link_xoff_tx", stats.link_xoff_tx),
-       I40E_PF_STAT("priority_xon_rx", stats.priority_xon_rx),
-       I40E_PF_STAT("priority_xoff_rx", stats.priority_xoff_rx),
-       I40E_PF_STAT("priority_xon_tx", stats.priority_xon_tx),
-       I40E_PF_STAT("priority_xoff_tx", stats.priority_xoff_tx),
-       I40E_PF_STAT("rx_size_64", stats.rx_size_64),
-       I40E_PF_STAT("rx_size_127", stats.rx_size_127),
-       I40E_PF_STAT("rx_size_255", stats.rx_size_255),
-       I40E_PF_STAT("rx_size_511", stats.rx_size_511),
-       I40E_PF_STAT("rx_size_1023", stats.rx_size_1023),
-       I40E_PF_STAT("rx_size_1522", stats.rx_size_1522),
-       I40E_PF_STAT("rx_size_big", stats.rx_size_big),
-       I40E_PF_STAT("tx_size_64", stats.tx_size_64),
-       I40E_PF_STAT("tx_size_127", stats.tx_size_127),
-       I40E_PF_STAT("tx_size_255", stats.tx_size_255),
-       I40E_PF_STAT("tx_size_511", stats.tx_size_511),
-       I40E_PF_STAT("tx_size_1023", stats.tx_size_1023),
-       I40E_PF_STAT("tx_size_1522", stats.tx_size_1522),
-       I40E_PF_STAT("tx_size_big", stats.tx_size_big),
-       I40E_PF_STAT("rx_undersize", stats.rx_undersize),
-       I40E_PF_STAT("rx_fragments", stats.rx_fragments),
-       I40E_PF_STAT("rx_oversize", stats.rx_oversize),
-       I40E_PF_STAT("rx_jabber", stats.rx_jabber),
-       I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests),
-       I40E_PF_STAT("arq_overflows", arq_overflows),
+       I40E_PF_STAT("port.rx_bytes", stats.eth.rx_bytes),
+       I40E_PF_STAT("port.tx_bytes", stats.eth.tx_bytes),
+       I40E_PF_STAT("port.rx_unicast", stats.eth.rx_unicast),
+       I40E_PF_STAT("port.tx_unicast", stats.eth.tx_unicast),
+       I40E_PF_STAT("port.rx_multicast", stats.eth.rx_multicast),
+       I40E_PF_STAT("port.tx_multicast", stats.eth.tx_multicast),
+       I40E_PF_STAT("port.rx_broadcast", stats.eth.rx_broadcast),
+       I40E_PF_STAT("port.tx_broadcast", stats.eth.tx_broadcast),
+       I40E_PF_STAT("port.tx_errors", stats.eth.tx_errors),
+       I40E_PF_STAT("port.rx_dropped", stats.eth.rx_discards),
+       I40E_PF_STAT("port.tx_dropped_link_down", stats.tx_dropped_link_down),
+       I40E_PF_STAT("port.rx_crc_errors", stats.crc_errors),
+       I40E_PF_STAT("port.illegal_bytes", stats.illegal_bytes),
+       I40E_PF_STAT("port.mac_local_faults", stats.mac_local_faults),
+       I40E_PF_STAT("port.mac_remote_faults", stats.mac_remote_faults),
+       I40E_PF_STAT("port.tx_timeout", tx_timeout_count),
+       I40E_PF_STAT("port.rx_csum_bad", hw_csum_rx_error),
+       I40E_PF_STAT("port.rx_length_errors", stats.rx_length_errors),
+       I40E_PF_STAT("port.link_xon_rx", stats.link_xon_rx),
+       I40E_PF_STAT("port.link_xoff_rx", stats.link_xoff_rx),
+       I40E_PF_STAT("port.link_xon_tx", stats.link_xon_tx),
+       I40E_PF_STAT("port.link_xoff_tx", stats.link_xoff_tx),
+       I40E_PF_STAT("port.rx_size_64", stats.rx_size_64),
+       I40E_PF_STAT("port.rx_size_127", stats.rx_size_127),
+       I40E_PF_STAT("port.rx_size_255", stats.rx_size_255),
+       I40E_PF_STAT("port.rx_size_511", stats.rx_size_511),
+       I40E_PF_STAT("port.rx_size_1023", stats.rx_size_1023),
+       I40E_PF_STAT("port.rx_size_1522", stats.rx_size_1522),
+       I40E_PF_STAT("port.rx_size_big", stats.rx_size_big),
+       I40E_PF_STAT("port.tx_size_64", stats.tx_size_64),
+       I40E_PF_STAT("port.tx_size_127", stats.tx_size_127),
+       I40E_PF_STAT("port.tx_size_255", stats.tx_size_255),
+       I40E_PF_STAT("port.tx_size_511", stats.tx_size_511),
+       I40E_PF_STAT("port.tx_size_1023", stats.tx_size_1023),
+       I40E_PF_STAT("port.tx_size_1522", stats.tx_size_1522),
+       I40E_PF_STAT("port.tx_size_big", stats.tx_size_big),
+       I40E_PF_STAT("port.rx_undersize", stats.rx_undersize),
+       I40E_PF_STAT("port.rx_fragments", stats.rx_fragments),
+       I40E_PF_STAT("port.rx_oversize", stats.rx_oversize),
+       I40E_PF_STAT("port.rx_jabber", stats.rx_jabber),
+       I40E_PF_STAT("port.VF_admin_queue_requests", vf_aq_requests),
+       I40E_PF_STAT("port.arq_overflows", arq_overflows),
 #ifdef HAVE_PTP_1588_CLOCK
-       I40E_PF_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
-       I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared),
-       I40E_PF_STAT("tx_hwtstamp_skipped", tx_hwtstamp_skipped),
+       I40E_PF_STAT("port.tx_hwtstamp_timeouts", tx_hwtstamp_timeouts),
+       I40E_PF_STAT("port.rx_hwtstamp_cleared", rx_hwtstamp_cleared),
+       I40E_PF_STAT("port.tx_hwtstamp_skipped", tx_hwtstamp_skipped),
 #endif /* HAVE_PTP_1588_CLOCK */
-       I40E_PF_STAT("fdir_flush_cnt", fd_flush_cnt),
-       I40E_PF_STAT("fdir_atr_match", stats.fd_atr_match),
-       I40E_PF_STAT("fdir_atr_tunnel_match", stats.fd_atr_tunnel_match),
-       I40E_PF_STAT("fdir_atr_status", stats.fd_atr_status),
-       I40E_PF_STAT("fdir_sb_match", stats.fd_sb_match),
-       I40E_PF_STAT("fdir_sb_status", stats.fd_sb_status),
+       I40E_PF_STAT("port.fdir_flush_cnt", fd_flush_cnt),
+       I40E_PF_STAT("port.fdir_atr_match", stats.fd_atr_match),
+       I40E_PF_STAT("port.fdir_atr_tunnel_match", stats.fd_atr_tunnel_match),
+       I40E_PF_STAT("port.fdir_atr_status", stats.fd_atr_status),
+       I40E_PF_STAT("port.fdir_sb_match", stats.fd_sb_match),
+       I40E_PF_STAT("port.fdir_sb_status", stats.fd_sb_status),
 #ifdef I40E_ADD_PROBES
-       I40E_PF_STAT("tx_tcp_segments", tcp_segs),
-       I40E_PF_STAT("tx_tcp_cso", tx_tcp_cso),
-       I40E_PF_STAT("tx_udp_cso", tx_udp_cso),
-       I40E_PF_STAT("tx_sctp_cso", tx_sctp_cso),
-       I40E_PF_STAT("tx_ip4_cso", tx_ip4_cso),
-       I40E_PF_STAT("rx_tcp_cso", rx_tcp_cso),
-       I40E_PF_STAT("rx_udp_cso", rx_udp_cso),
-       I40E_PF_STAT("rx_sctp_cso", rx_sctp_cso),
-       I40E_PF_STAT("rx_ip4_cso", rx_ip4_cso),
-       I40E_PF_STAT("rx_csum_offload_outer", hw_csum_rx_outer),
-       I40E_PF_STAT("rx_tcp_cso_error", rx_tcp_cso_err),
-       I40E_PF_STAT("rx_udp_cso_error", rx_udp_cso_err),
-       I40E_PF_STAT("rx_sctp_cso_error", rx_sctp_cso_err),
-       I40E_PF_STAT("rx_ip4_cso_error", rx_ip4_cso_err),
+       I40E_PF_STAT("port.tx_tcp_segments", tcp_segs),
+       I40E_PF_STAT("port.tx_tcp_cso", tx_tcp_cso),
+       I40E_PF_STAT("port.tx_udp_cso", tx_udp_cso),
+       I40E_PF_STAT("port.tx_sctp_cso", tx_sctp_cso),
+       I40E_PF_STAT("port.tx_ip4_cso", tx_ip4_cso),
+       I40E_PF_STAT("port.rx_tcp_cso", rx_tcp_cso),
+       I40E_PF_STAT("port.rx_udp_cso", rx_udp_cso),
+       I40E_PF_STAT("port.rx_sctp_cso", rx_sctp_cso),
+       I40E_PF_STAT("port.rx_ip4_cso", rx_ip4_cso),
+       I40E_PF_STAT("port.rx_csum_offload_outer", hw_csum_rx_outer),
+       I40E_PF_STAT("port.rx_tcp_cso_error", rx_tcp_cso_err),
+       I40E_PF_STAT("port.rx_udp_cso_error", rx_udp_cso_err),
+       I40E_PF_STAT("port.rx_sctp_cso_error", rx_sctp_cso_err),
+       I40E_PF_STAT("port.rx_ip4_cso_error", rx_ip4_cso_err),
 #endif
 
        /* LPI stats */
-       I40E_PF_STAT("tx_lpi_status", stats.tx_lpi_status),
-       I40E_PF_STAT("rx_lpi_status", stats.rx_lpi_status),
-       I40E_PF_STAT("tx_lpi_count", stats.tx_lpi_count),
-       I40E_PF_STAT("rx_lpi_count", stats.rx_lpi_count),
+       I40E_PF_STAT("port.tx_lpi_status", stats.tx_lpi_status),
+       I40E_PF_STAT("port.rx_lpi_status", stats.rx_lpi_status),
+       I40E_PF_STAT("port.tx_lpi_count", stats.tx_lpi_count),
+       I40E_PF_STAT("port.rx_lpi_count", stats.rx_lpi_count),
 };
 
-#define I40E_QUEUE_STATS_LEN(n) \
-       (((struct i40e_netdev_priv *)netdev_priv((n)))->vsi->num_queue_pairs \
-           * 2 /* Tx and Rx together */                                     \
-           * (sizeof(struct i40e_queue_stats) / sizeof(u64)))
-#define I40E_GLOBAL_STATS_LEN  ARRAY_SIZE(i40e_gstrings_stats)
-#define I40E_NETDEV_STATS_LEN   ARRAY_SIZE(i40e_gstrings_net_stats)
+struct i40e_pfc_stats {
+       u64 priority_xon_rx;
+       u64 priority_xoff_rx;
+       u64 priority_xon_tx;
+       u64 priority_xoff_tx;
+       u64 priority_xon_2_xoff;
+};
+
+static const struct i40e_stats i40e_gstrings_pfc_stats[] = {
+       I40E_PFC_STAT("port.tx_priority_%u_xon_tx", priority_xon_tx),
+       I40E_PFC_STAT("port.tx_priority_%u_xoff_tx", priority_xoff_tx),
+       I40E_PFC_STAT("port.rx_priority_%u_xon_rx", priority_xon_rx),
+       I40E_PFC_STAT("port.rx_priority_%u_xoff_rx", priority_xoff_rx),
+       I40E_PFC_STAT("port.rx_priority_%u_xon_2_xoff", priority_xon_2_xoff),
+};
+
+#define I40E_NETDEV_STATS_LEN  ARRAY_SIZE(i40e_gstrings_net_stats)
+
 #define I40E_MISC_STATS_LEN    ARRAY_SIZE(i40e_gstrings_misc_stats)
-#define I40E_VSI_STATS_LEN(n)   (I40E_NETDEV_STATS_LEN + \
-                                I40E_MISC_STATS_LEN + \
-                                I40E_QUEUE_STATS_LEN((n)))
-#define I40E_PFC_STATS_LEN ( \
-               (FIELD_SIZEOF(struct i40e_pf, stats.priority_xoff_rx) + \
-                FIELD_SIZEOF(struct i40e_pf, stats.priority_xon_rx) + \
-                FIELD_SIZEOF(struct i40e_pf, stats.priority_xoff_tx) + \
-                FIELD_SIZEOF(struct i40e_pf, stats.priority_xon_tx) + \
-                FIELD_SIZEOF(struct i40e_pf, stats.priority_xon_2_xoff)) \
-                / sizeof(u64))
-#define I40E_VEB_TC_STATS_LEN ( \
-               (FIELD_SIZEOF(struct i40e_veb, tc_stats.tc_rx_packets) + \
-                FIELD_SIZEOF(struct i40e_veb, tc_stats.tc_rx_bytes) + \
-                FIELD_SIZEOF(struct i40e_veb, tc_stats.tc_tx_packets) + \
-                FIELD_SIZEOF(struct i40e_veb, tc_stats.tc_tx_bytes)) \
-                / sizeof(u64))
-#define I40E_VEB_STATS_LEN     ARRAY_SIZE(i40e_gstrings_veb_stats)
-#define I40E_VEB_STATS_TOTAL   (I40E_VEB_STATS_LEN + I40E_VEB_TC_STATS_LEN)
-#define I40E_PF_STATS_LEN(n)   (I40E_GLOBAL_STATS_LEN + \
+
+#define I40E_VSI_STATS_LEN     (I40E_NETDEV_STATS_LEN + I40E_MISC_STATS_LEN)
+
+#define I40E_PFC_STATS_LEN     (ARRAY_SIZE(i40e_gstrings_pfc_stats) * \
+                                I40E_MAX_USER_PRIORITY)
+
+#define I40E_VEB_STATS_LEN     (ARRAY_SIZE(i40e_gstrings_veb_stats) + \
+                                (ARRAY_SIZE(i40e_gstrings_veb_tc_stats) * \
+                                 I40E_MAX_TRAFFIC_CLASS))
+
+#define I40E_GLOBAL_STATS_LEN  ARRAY_SIZE(i40e_gstrings_stats)
+
+#define I40E_PF_STATS_LEN      (I40E_GLOBAL_STATS_LEN + \
                                 I40E_PFC_STATS_LEN + \
-                                I40E_VSI_STATS_LEN((n)))
+                                I40E_VEB_STATS_LEN + \
+                                I40E_VSI_STATS_LEN)
+
+/* Length of stats for a single queue */
+#define I40E_QUEUE_STATS_LEN   ARRAY_SIZE(i40e_gstrings_queue_stats)
+#ifdef HAVE_XDP_SUPPORT
+#define I40E_QUEUE_STATS_XDP_LEN ARRAY_SIZE(i40e_gstrings_rx_queue_xdp_stats)
+#endif
 
 #endif /* ETHTOOL_GSTATS */
 #ifdef ETHTOOL_TEST
@@ -270,6 +255,8 @@ static const struct i40e_priv_flags i40e_gstrings_priv_flags[] = {
        I40E_PRIV_FLAG("disable-source-pruning",
                       I40E_FLAG_SOURCE_PRUNING_DISABLED, 0),
        I40E_PRIV_FLAG("disable-fw-lldp", I40E_FLAG_DISABLE_FW_LLDP, 0),
+       I40E_PRIV_FLAG("rs-fec", I40E_FLAG_RS_FEC, 0),
+       I40E_PRIV_FLAG("base-r-fec", I40E_FLAG_BASE_R_FEC, 0),
 };
 
 #define I40E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_gstrings_priv_flags)
@@ -283,116 +270,6 @@ static const struct i40e_priv_flags i40e_gl_gstrings_priv_flags[] = {
 #define I40E_GL_PRIV_FLAGS_STR_LEN ARRAY_SIZE(i40e_gl_gstrings_priv_flags)
 
 #endif /* HAVE_ETHTOOL_GET_SSET_COUNT */
-#ifndef ETHTOOL_GLINKSETTINGS
-#define I40E_LEGACY_LINK_MASK_SIZE 1
-/**
- * struct ethtool_link_ksettings
- * @link_modes: supported and advertising, single item arrays
- *
- * This struct and the following macros provide a way to support the old
- * ethtool get/set_settings API on older kernels, but in the style of the new
- * GLINKSETTINGS API.  In this way, the same code can be used to support both
- * APIs as seemlessly as possible.
- *
- * It should be noted the old API only has support up to the first 32 bits.
- */
-struct ethtool_link_ksettings {
-       struct {
-               u32 speed;
-               u8 port;
-               u8 duplex;
-               u8 autoneg;
-       } base;
-       struct {
-               unsigned long supported[I40E_LEGACY_LINK_MASK_SIZE];
-               unsigned long advertising[I40E_LEGACY_LINK_MASK_SIZE];
-       } link_modes;
-};
-
-#define ETHTOOL_LINK_NAME_advertising(mode) ADVERTISED_ ## mode
-#define ETHTOOL_LINK_NAME_supported(mode) SUPPORTED_ ## mode
-#define ETHTOOL_LINK_NAME(name) ETHTOOL_LINK_NAME_ ## name
-#define ETHTOOL_LINK_CONVERT(name, mode)                               \
-       ETHTOOL_LINK_NAME(name)(mode)
-
-/**
- * ethtool_link_ksettings_zero_link_mode
- * @ptr: ptr to ksettings struct
- * @name: supported or advertising
- */
-#define ethtool_link_ksettings_zero_link_mode(ptr, name)               \
-       (*((ptr)->link_modes.name) = 0x0)
-
-/**
- * ethtool_link_ksettings_add_link_mode
- * @ptr: ptr to ksettings struct
- * @name: supported or advertising
- * @mode: link mode to add
- */
-#define ethtool_link_ksettings_add_link_mode(ptr, name, mode)          \
-       (*((ptr)->link_modes.name) |= ETHTOOL_LINK_CONVERT(name, mode))
-
-/**
- * ethtool_link_ksettings_test_link_mode
- * @ptr: ptr to ksettings struct
- * @name: supported or advertising
- * @mode: link mode to add
- */
-#define ethtool_link_ksettings_test_link_mode(ptr, name, mode)         \
-       (!!(*((ptr)->link_modes.name) & ETHTOOL_LINK_CONVERT(name, mode)))
-
-/**
- * ethtool_link_ksettings_del_link_mode
- * @ptr: ptr to ksettings struct
- * @name: supported or advertising
- * @mode: link mode to delete
- */
-#ifdef ethtool_link_ksettings_del_link_mode
-#undef ethtool_link_ksettings_del_link_mode
-#endif
-#define ethtool_link_ksettings_del_link_mode(ptr, name, mode)          \
-       ((*(ptr)->link_modes.name) &=                                   \
-        ~((unsigned long)ETHTOOL_LINK_CONVERT(name, mode)))
-
-/**
- * i40e_ethtool_ksettings_to_cmd
- * @ks: ethtool_link_ksettings struct
- * @cmd: ethtool_cmd struct
- *
- * Convert a ethtool_link_ksettings to a ethtool_cmd
- */
-static void i40e_ethtool_ksettings_to_cmd(struct ethtool_link_ksettings *ks,
-                                         struct ethtool_cmd *cmd)
-{
-       cmd->supported = (u32)ks->link_modes.supported[0];
-       cmd->advertising = (u32)ks->link_modes.advertising[0];
-       ethtool_cmd_speed_set(cmd, ks->base.speed);
-       cmd->duplex = ks->base.duplex;
-       cmd->autoneg = ks->base.autoneg;
-       cmd->port = ks->base.port;
-}
-
-/**
- * ethtool_intersect_link_mode_masks
- * @dst: resulting intersection and first mask
- * @src: mask to AND with
- *
- * Given two link mode masks, AND them together and save the result in dst.
- */
-static void ethtool_intersect_link_masks(struct ethtool_link_ksettings *dst,
-                                        struct ethtool_link_ksettings *src)
-{
-       int idx = 0;
-
-       for (; idx < I40E_LEGACY_LINK_MASK_SIZE; idx++) {
-               dst->link_modes.supported[idx] &=
-                       src->link_modes.supported[idx];
-               dst->link_modes.advertising[idx] &=
-                       src->link_modes.advertising[idx];
-       }
-}
-
-#endif /* !ETHTOOL_GLINKSETTINGS */
 /**
  * i40e_partition_setting_complaint - generic complaint for MFP restriction
  * @pf: the PF struct
@@ -550,6 +427,26 @@ static void i40e_phy_type_to_ethtool(struct i40e_pf *pf,
                        ethtool_link_ksettings_add_link_mode(ks, advertising,
                                                             25000baseCR_Full);
        }
+#ifdef ETHTOOL_GFECPARAM
+       if (phy_types & I40E_CAP_PHY_TYPE_25GBASE_KR ||
+           phy_types & I40E_CAP_PHY_TYPE_25GBASE_CR ||
+           phy_types & I40E_CAP_PHY_TYPE_25GBASE_SR ||
+           phy_types & I40E_CAP_PHY_TYPE_25GBASE_LR ||
+           phy_types & I40E_CAP_PHY_TYPE_25GBASE_AOC ||
+           phy_types & I40E_CAP_PHY_TYPE_25GBASE_ACC) {
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
+               if (hw_link_info->requested_speeds & I40E_LINK_SPEED_25GB) {
+                       ethtool_link_ksettings_add_link_mode(ks, advertising,
+                                                            FEC_NONE);
+                       ethtool_link_ksettings_add_link_mode(ks, advertising,
+                                                            FEC_RS);
+                       ethtool_link_ksettings_add_link_mode(ks, advertising,
+                                                            FEC_BASER);
+               }
+       }
+#endif /* ETHTOOL_GFECPARAM */
 #endif /* HAVE_ETHTOOL_25G_BITS */
 #ifdef HAVE_ETHTOOL_NEW_10G_BITS
        /* need to add new 10G PHY types */
@@ -690,6 +587,15 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
                                                     25000baseSR_Full);
                ethtool_link_ksettings_add_link_mode(ks, advertising,
                                                     25000baseSR_Full);
+#ifdef ETHTOOL_GFECPARAM
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
+               ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE);
+               ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
+               ethtool_link_ksettings_add_link_mode(ks, advertising,
+                                                    FEC_BASER);
+#endif /* ETHTOOL_GFECPARAM */
 #endif /* HAVE_ETHTOOL_25G_BITS */
 #ifdef HAVE_ETHTOOL_NEW_10G_BITS
                ethtool_link_ksettings_add_link_mode(ks, supported,
@@ -798,7 +704,12 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
 #ifdef HAVE_ETHTOOL_25G_BITS
                ethtool_link_ksettings_add_link_mode(ks, supported,
                                                     25000baseKR_Full);
-#endif
+#ifdef ETHTOOL_GFECPARAM
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
+#endif /* ETHTOOL_GFECPARAM */
+#endif /* HAVE_ETHTOOL_25G_BITS */
                ethtool_link_ksettings_add_link_mode(ks, supported,
                                                     20000baseKR2_Full);
                ethtool_link_ksettings_add_link_mode(ks, supported,
@@ -813,7 +724,13 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
 #ifdef HAVE_ETHTOOL_25G_BITS
                ethtool_link_ksettings_add_link_mode(ks, advertising,
                                                     25000baseKR_Full);
-#endif
+#ifdef ETHTOOL_GFECPARAM
+               ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE);
+               ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
+               ethtool_link_ksettings_add_link_mode(ks, advertising,
+                                                    FEC_BASER);
+#endif /* ETHTOOL_GFECPARAM */
+#endif /* HAVE_ETHTOOL_25G_BITS */
                ethtool_link_ksettings_add_link_mode(ks, advertising,
                                                     20000baseKR2_Full);
                ethtool_link_ksettings_add_link_mode(ks, advertising,
@@ -832,6 +749,15 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
                                                     25000baseCR_Full);
                ethtool_link_ksettings_add_link_mode(ks, advertising,
                                                     25000baseCR_Full);
+#ifdef ETHTOOL_GFECPARAM
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
+               ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE);
+               ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
+               ethtool_link_ksettings_add_link_mode(ks, advertising,
+                                                    FEC_BASER);
+#endif /* ETHTOOL_GFECPARAM */
 #endif /* HAVE_ETHTOOL_25G_BITS */
                break;
        case I40E_PHY_TYPE_25GBASE_AOC:
@@ -841,9 +767,17 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
 #ifdef HAVE_ETHTOOL_25G_BITS
                ethtool_link_ksettings_add_link_mode(ks, supported,
                                                     25000baseCR_Full);
-
                ethtool_link_ksettings_add_link_mode(ks, advertising,
                                                     25000baseCR_Full);
+#ifdef ETHTOOL_GFECPARAM
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_NONE);
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_RS);
+               ethtool_link_ksettings_add_link_mode(ks, supported, FEC_BASER);
+               ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_NONE);
+               ethtool_link_ksettings_add_link_mode(ks, advertising, FEC_RS);
+               ethtool_link_ksettings_add_link_mode(ks, advertising,
+                                                    FEC_BASER);
+#endif /* ETHTOOL_GFECPARAM */
 #endif /* HAVE_ETHTOOL_25G_BITS */
 #ifdef HAVE_ETHTOOL_NEW_10G_BITS
                ethtool_link_ksettings_add_link_mode(ks, supported,
@@ -888,6 +822,7 @@ static void i40e_get_settings_link_up(struct i40e_hw *hw,
                ks->base.speed = SPEED_100;
                break;
        default:
+               ks->base.speed = SPEED_UNKNOWN;
                break;
        }
        ks->base.duplex = DUPLEX_FULL;
@@ -1042,7 +977,9 @@ static int i40e_set_link_ksettings(struct net_device *netdev,
        if (hw->device_id == I40E_DEV_ID_KX_B ||
            hw->device_id == I40E_DEV_ID_KX_C ||
            hw->device_id == I40E_DEV_ID_20G_KR2 ||
-           hw->device_id == I40E_DEV_ID_20G_KR2_A) {
+           hw->device_id == I40E_DEV_ID_20G_KR2_A ||
+           hw->device_id == I40E_DEV_ID_25G_B ||
+           hw->device_id == I40E_DEV_ID_KX_X722) {
                netdev_info(netdev, "Changing settings is not supported on backplane.\n");
                return -EOPNOTSUPP;
        }
@@ -1053,23 +990,21 @@ static int i40e_set_link_ksettings(struct net_device *netdev,
        /* save autoneg out of ksettings */
        autoneg = copy_ks.base.autoneg;
 
-       memset(&safe_ks, 0, sizeof(safe_ks));
+       /* get our own copy of the bits to check against */
+       memset(&safe_ks, 0, sizeof(struct ethtool_link_ksettings));
+       safe_ks.base.cmd = copy_ks.base.cmd;
+       safe_ks.base.link_mode_masks_nwords =
+               copy_ks.base.link_mode_masks_nwords;
+       i40e_get_link_ksettings(netdev, &safe_ks);
+
        /* Get link modes supported by hardware and check against modes
         * requested by user.  Return an error if unsupported mode was set.
         */
-       i40e_phy_type_to_ethtool(pf, &safe_ks);
        if (!bitmap_subset(copy_ks.link_modes.advertising,
                           safe_ks.link_modes.supported,
                           __ETHTOOL_LINK_MODE_MASK_NBITS))
                return -EINVAL;
 
-       /* get our own copy of the bits to check against */
-       memset(&safe_ks, 0, sizeof(struct ethtool_link_ksettings));
-       safe_ks.base.cmd = copy_ks.base.cmd;
-       safe_ks.base.link_mode_masks_nwords =
-               copy_ks.base.link_mode_masks_nwords;
-       i40e_get_link_ksettings(netdev, &safe_ks);
-
        /* set autoneg back to what it currently is */
        copy_ks.base.autoneg = safe_ks.base.autoneg;
 
@@ -1160,7 +1095,9 @@ static int i40e_set_link_ksettings(struct net_device *netdev,
            ethtool_link_ksettings_test_link_mode(ks, advertising,
                                                  10000baseCR_Full) ||
            ethtool_link_ksettings_test_link_mode(ks, advertising,
-                                                 10000baseSR_Full))
+                                                 10000baseSR_Full) ||
+           ethtool_link_ksettings_test_link_mode(ks, advertising,
+                                                 10000baseLR_Full))
 #else
            0)
 #endif /* HAVE_ETHTOOL_NEW_10G_BITS */
@@ -1261,7 +1198,7 @@ static int i40e_get_settings(struct net_device *netdev,
        struct ethtool_link_ksettings ks;
 
        i40e_get_link_ksettings(netdev, &ks);
-       i40e_ethtool_ksettings_to_cmd(&ks, ecmd);
+       _kc_ethtool_ksettings_to_cmd(&ks, ecmd);
        ecmd->transceiver = XCVR_EXTERNAL;
        return 0;
 }
@@ -1489,6 +1426,157 @@ done:
 }
 
 #endif /* ETHTOOL_GLINKSETTINGS */
+
+static int i40e_set_fec_cfg(struct net_device *netdev, u8 fec_cfg)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_aq_get_phy_abilities_resp abilities;
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       i40e_status status = 0;
+       u64 flags = 0;
+       int err = 0;
+
+       flags = READ_ONCE(pf->flags);
+       i40e_set_fec_in_flags(fec_cfg, &flags);
+
+       /* Get the current phy config */
+       memset(&abilities, 0, sizeof(abilities));
+       status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
+                                             NULL);
+       if (status) {
+               err = -EAGAIN;
+               goto done;
+       }
+
+       if (abilities.fec_cfg_curr_mod_ext_info != fec_cfg) {
+               struct i40e_aq_set_phy_config config;
+
+               memset(&config, 0, sizeof(config));
+               config.phy_type = abilities.phy_type;
+               config.abilities = abilities.abilities;
+               config.phy_type_ext = abilities.phy_type_ext;
+               config.link_speed = abilities.link_speed;
+               config.eee_capability = abilities.eee_capability;
+               config.eeer = abilities.eeer_val;
+               config.low_power_ctrl = abilities.d3_lpan;
+               config.fec_config = fec_cfg & I40E_AQ_PHY_FEC_CONFIG_MASK;
+               status = i40e_aq_set_phy_config(hw, &config, NULL);
+               if (status) {
+                       netdev_info(netdev,
+                                   "Set phy config failed, err %s aq_err %s\n",
+                                   i40e_stat_str(hw, status),
+                                   i40e_aq_str(hw, hw->aq.asq_last_status));
+                       err = -EAGAIN;
+                       goto done;
+               }
+               pf->flags = flags;
+               status = i40e_update_link_info(hw);
+               if (status)
+                       /* debug level message only due to relation to the link
+                        * itself rather than to the FEC settings
+                        * (e.g. no physical connection etc.)
+                        */
+                       netdev_dbg(netdev,
+                                  "Updating link info failed with err %s aq_err %s\n",
+                                  i40e_stat_str(hw, status),
+                                  i40e_aq_str(hw, hw->aq.asq_last_status));
+       }
+
+done:
+       return err;
+}
+
+#ifdef ETHTOOL_GFECPARAM
+static int i40e_get_fec_param(struct net_device *netdev,
+                             struct ethtool_fecparam *fecparam)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_aq_get_phy_abilities_resp abilities;
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       i40e_status status = 0;
+       int err = 0;
+
+       /* Get the current phy config */
+       memset(&abilities, 0, sizeof(abilities));
+       status = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
+                                             NULL);
+       if (status) {
+               err = -EAGAIN;
+               goto done;
+       }
+
+       fecparam->fec = 0;
+       if (abilities.fec_cfg_curr_mod_ext_info & I40E_AQ_SET_FEC_AUTO)
+               fecparam->fec |= ETHTOOL_FEC_AUTO;
+       if ((abilities.fec_cfg_curr_mod_ext_info &
+            I40E_AQ_SET_FEC_REQUEST_RS) ||
+           (abilities.fec_cfg_curr_mod_ext_info &
+            I40E_AQ_SET_FEC_ABILITY_RS))
+               fecparam->fec |= ETHTOOL_FEC_RS;
+       if ((abilities.fec_cfg_curr_mod_ext_info &
+            I40E_AQ_SET_FEC_REQUEST_KR) ||
+           (abilities.fec_cfg_curr_mod_ext_info & I40E_AQ_SET_FEC_ABILITY_KR))
+               fecparam->fec |= ETHTOOL_FEC_BASER;
+       if (abilities.fec_cfg_curr_mod_ext_info == 0)
+               fecparam->fec |= ETHTOOL_FEC_OFF;
+
+       if (hw->phy.link_info.fec_info & I40E_AQ_CONFIG_FEC_KR_ENA)
+               fecparam->active_fec = ETHTOOL_FEC_BASER;
+       else if (hw->phy.link_info.fec_info & I40E_AQ_CONFIG_FEC_RS_ENA)
+               fecparam->active_fec = ETHTOOL_FEC_RS;
+       else
+               fecparam->active_fec = ETHTOOL_FEC_OFF;
+done:
+       return err;
+}
+
+static int i40e_set_fec_param(struct net_device *netdev,
+                             struct ethtool_fecparam *fecparam)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       u8 fec_cfg = 0;
+       int err = 0;
+
+       if (hw->device_id != I40E_DEV_ID_25G_SFP28 &&
+           hw->device_id != I40E_DEV_ID_25G_B) {
+               err = -EPERM;
+               goto done;
+       }
+
+       switch (fecparam->fec) {
+       case ETHTOOL_FEC_AUTO:
+               fec_cfg = I40E_AQ_SET_FEC_AUTO;
+               break;
+       case ETHTOOL_FEC_RS:
+               fec_cfg = (I40E_AQ_SET_FEC_REQUEST_RS |
+                            I40E_AQ_SET_FEC_ABILITY_RS);
+               break;
+       case ETHTOOL_FEC_BASER:
+               fec_cfg = (I40E_AQ_SET_FEC_REQUEST_KR |
+                            I40E_AQ_SET_FEC_ABILITY_KR);
+               break;
+       case ETHTOOL_FEC_OFF:
+       case ETHTOOL_FEC_NONE:
+               fec_cfg = 0;
+               break;
+       default:
+               dev_warn(&pf->pdev->dev, "Unsupported FEC mode: %d",
+                        fecparam->fec);
+               err = -EINVAL;
+               goto done;
+       }
+
+       err = i40e_set_fec_cfg(netdev, fec_cfg);
+
+done:
+       return err;
+}
+#endif /* ETHTOOL_GFECPARAM */
+
 static int i40e_nway_reset(struct net_device *netdev)
 {
        /* restart autonegotiation */
@@ -1511,6 +1599,9 @@ static int i40e_nway_reset(struct net_device *netdev)
 
 /**
  * i40e_get_pauseparam -  Get Flow Control status
+ * @netdev: netdevice structure
+ * @pause: buffer to return pause parameters
+ *
  * Return tx/rx-pause status
  **/
 static void i40e_get_pauseparam(struct net_device *netdev,
@@ -1558,6 +1649,7 @@ static int i40e_set_pauseparam(struct net_device *netdev,
        i40e_status status;
        u8 aq_failures;
        int err = 0;
+       u32 is_an;
 
        /* Changing the port's flow control is not supported if this isn't the
         * port's controlling PF
@@ -1570,14 +1662,14 @@ static int i40e_set_pauseparam(struct net_device *netdev,
        if (vsi != pf->vsi[pf->lan_vsi])
                return -EOPNOTSUPP;
 
-       if (pause->autoneg != (hw_link_info->an_info & I40E_AQ_AN_COMPLETED)) {
+       is_an = hw_link_info->an_info & I40E_AQ_AN_COMPLETED;
+       if (pause->autoneg != is_an) {
                netdev_info(netdev, "To change autoneg please use: ethtool -s <dev> autoneg <on|off>\n");
                return -EOPNOTSUPP;
        }
 
        /* If we have link and don't have autoneg */
-       if (!test_bit(__I40E_DOWN, pf->state) &&
-           !(hw_link_info->an_info & I40E_AQ_AN_COMPLETED)) {
+       if (!test_bit(__I40E_DOWN, pf->state) && !is_an) {
                /* Send message that it might not necessarily work*/
                netdev_info(netdev, "Autoneg did not complete so changing settings may not result in an actual change.\n");
        }
@@ -1597,7 +1689,7 @@ static int i40e_set_pauseparam(struct net_device *netdev,
        else if (!pause->rx_pause && !pause->tx_pause)
                hw->fc.requested_mode = I40E_FC_NONE;
        else
-                return -EINVAL;
+               return -EINVAL;
 
        /* Tell the OS link is going down, the link will go back up when fw
         * says it is ready asynchronously
@@ -1628,7 +1720,7 @@ static int i40e_set_pauseparam(struct net_device *netdev,
                err = -EAGAIN;
        }
 
-       if (!test_bit(__I40E_DOWN, pf->state)) {
+       if (!test_bit(__I40E_DOWN, pf->state) && is_an) {
                /* Give it a little more time to try to come back */
                msleep(75);
                if (!test_bit(__I40E_DOWN, pf->state))
@@ -2007,6 +2099,17 @@ static void i40e_get_ringparam(struct net_device *netdev,
        ring->rx_jumbo_pending = 0;
 }
 
+static bool i40e_active_tx_ring_index(struct i40e_vsi *vsi, u16 index)
+{
+       if (i40e_enabled_xdp_vsi(vsi)) {
+               return index < vsi->num_queue_pairs ||
+                       (index >= vsi->alloc_queue_pairs &&
+                        index < vsi->alloc_queue_pairs + vsi->num_queue_pairs);
+       }
+
+       return index < vsi->num_queue_pairs;
+}
+
 static int i40e_set_ringparam(struct net_device *netdev,
                              struct ethtool_ringparam *ring)
 {
@@ -2016,6 +2119,7 @@ static int i40e_set_ringparam(struct net_device *netdev,
        struct i40e_vsi *vsi = np->vsi;
        struct i40e_pf *pf = vsi->back;
        u32 new_rx_count, new_tx_count;
+       u16 tx_alloc_queue_pairs;
        int timeout = 50;
        int i, err = 0;
 
@@ -2053,6 +2157,8 @@ static int i40e_set_ringparam(struct net_device *netdev,
                for (i = 0; i < vsi->num_queue_pairs; i++) {
                        vsi->tx_rings[i]->count = new_tx_count;
                        vsi->rx_rings[i]->count = new_rx_count;
+                       if (i40e_enabled_xdp_vsi(vsi))
+                               vsi->xdp_rings[i]->count = new_tx_count;
                }
                goto done;
        }
@@ -2062,19 +2168,23 @@ static int i40e_set_ringparam(struct net_device *netdev,
         * to the Tx and Rx ring structs.
         */
 
-       /* alloc updated Tx resources */
+       /* alloc updated Tx and XDP Tx resources */
+       tx_alloc_queue_pairs = vsi->alloc_queue_pairs *
+                              (i40e_enabled_xdp_vsi(vsi) ? 2 : 1);
        if (new_tx_count != vsi->tx_rings[0]->count) {
                netdev_info(netdev,
                            "Changing Tx descriptor count from %d to %d\n",
                            vsi->tx_rings[0]->count, new_tx_count);
-               tx_rings = kcalloc(vsi->alloc_queue_pairs,
+               tx_rings = kcalloc(tx_alloc_queue_pairs,
                                   sizeof(struct i40e_ring), GFP_KERNEL);
                if (!tx_rings) {
                        err = -ENOMEM;
                        goto done;
                }
 
-               for (i = 0; i < vsi->num_queue_pairs; i++) {
+               for (i = 0; i < tx_alloc_queue_pairs; i++) {
+                       if (!i40e_active_tx_ring_index(vsi, i))
+                               continue;
                        /* clone ring and setup updated count */
                        tx_rings[i] = *vsi->tx_rings[i];
                        tx_rings[i].count = new_tx_count;
@@ -2087,6 +2197,8 @@ static int i40e_set_ringparam(struct net_device *netdev,
                        if (err) {
                                while (i) {
                                        i--;
+                                       if (!i40e_active_tx_ring_index(vsi, i))
+                                               continue;
                                        i40e_free_tx_resources(&tx_rings[i]);
                                }
                                kfree(tx_rings);
@@ -2110,7 +2222,6 @@ static int i40e_set_ringparam(struct net_device *netdev,
                }
 
                for (i = 0; i < vsi->num_queue_pairs; i++) {
-                       struct i40e_ring *ring;
                        u16 unused;
 
                        /* clone ring and setup updated count */
@@ -2121,6 +2232,11 @@ static int i40e_set_ringparam(struct net_device *netdev,
                         */
                        rx_rings[i].desc = NULL;
                        rx_rings[i].rx_bi = NULL;
+#ifdef HAVE_XDP_BUFF_RXQ
+                       /* Clear cloned XDP RX-queue info before setup call */
+                       memset(&rx_rings[i].xdp_rxq, 0,
+                              sizeof(rx_rings[i].xdp_rxq));
+#endif
                        /* this is to allow wr32 to have something to write to
                         * during early allocation of Rx buffers
                         */
@@ -2132,9 +2248,8 @@ static int i40e_set_ringparam(struct net_device *netdev,
                        /* now allocate the Rx buffers to make sure the OS
                         * has enough memory, any failure here means abort
                         */
-                       ring = &rx_rings[i];
-                       unused = I40E_DESC_UNUSED(ring);
-                       err = i40e_alloc_rx_buffers(ring, unused);
+                       unused = I40E_DESC_UNUSED(&rx_rings[i]);
+                       err = i40e_alloc_rx_buffers(&rx_rings[i], unused);
 rx_unwind:
                        if (err) {
                                do {
@@ -2154,9 +2269,11 @@ rx_unwind:
        i40e_down(vsi);
 
        if (tx_rings) {
-               for (i = 0; i < vsi->num_queue_pairs; i++) {
-                       i40e_free_tx_resources(vsi->tx_rings[i]);
-                       *vsi->tx_rings[i] = tx_rings[i];
+               for (i = 0; i < tx_alloc_queue_pairs; i++) {
+                       if (i40e_active_tx_ring_index(vsi, i)) {
+                               i40e_free_tx_resources(vsi->tx_rings[i]);
+                               *vsi->tx_rings[i] = tx_rings[i];
+                       }
                }
                kfree(tx_rings);
                tx_rings = NULL;
@@ -2187,8 +2304,10 @@ rx_unwind:
 free_tx:
        /* error cleanup if the Rx allocations failed after getting Tx */
        if (tx_rings) {
-               for (i = 0; i < vsi->num_queue_pairs; i++)
-                       i40e_free_tx_resources(&tx_rings[i]);
+               for (i = 0; i < tx_alloc_queue_pairs; i++) {
+                       if (i40e_active_tx_ring_index(vsi, i))
+                               i40e_free_tx_resources(vsi->tx_rings[i]);
+               }
                kfree(tx_rings);
                tx_rings = NULL;
        }
@@ -2199,24 +2318,55 @@ done:
        return err;
 }
 
-#ifndef HAVE_ETHTOOL_GET_SSET_COUNT
+/**
+ * i40e_get_stats_count - return the stats count for a device
+ * @netdev: the netdev to return the count for
+ *
+ * Returns the total number of statistics for this netdev. Note that even
+ * though this is a function, it is required that the count for a specific
+ * netdev must never change. Basing the count on static values such as the
+ * maximum number of queues or the device type is ok. However, the API for
+ * obtaining stats is *not* safe against changes based on non-static
+ * values such as the *current* number of queues, or runtime flags.
+ *
+ * If a statistic is not always enabled, return it as part of the count
+ * anyways, always return its string, and report its value as zero.
+ **/
 static int i40e_get_stats_count(struct net_device *netdev)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
        struct i40e_pf *pf = vsi->back;
+       int stats_len;
 
-       if (vsi == pf->vsi[pf->lan_vsi] && pf->hw.partition_id == 1) {
-               if ((pf->lan_veb != I40E_NO_VEB) &&
-                   (pf->flags & I40E_FLAG_VEB_STATS_ENABLED))
-                       return I40E_PF_STATS_LEN(netdev) + I40E_VEB_STATS_TOTAL;
-               else
-                       return I40E_PF_STATS_LEN(netdev);
+       if (vsi == pf->vsi[pf->lan_vsi] && pf->hw.partition_id == 1)
+               stats_len = I40E_PF_STATS_LEN;
        else
-               return I40E_VSI_STATS_LEN(netdev);
+               stats_len = I40E_VSI_STATS_LEN;
+
+       /* The number of stats reported for a given net_device must remain
+        * constant throughout the life of that device.
+        *
+        * This is because the API for obtaining the size, strings, and stats
+        * is spread out over three separate ethtool ioctls. There is no safe
+        * way to lock the number of stats across these calls, so we must
+        * assume that they will never change.
+        *
+        * Due to this, we report the maximum number of queues, even if not
+        * every queue is currently configured. Since we always allocate
+        * queues in pairs, we'll just use netdev->num_tx_queues * 2. This
+        * works because the num_tx_queues is set at device creation and never
+        * changes.
+        */
+       stats_len += I40E_QUEUE_STATS_LEN * 2 * netdev->num_tx_queues;
+#ifdef HAVE_XDP_SUPPORT
+       stats_len += I40E_QUEUE_STATS_XDP_LEN * netdev->num_tx_queues;
+#endif
+
+       return stats_len;
 }
 
-#else /* HAVE_ETHTOOL_GET_SSET_COUNT */
+#ifdef HAVE_ETHTOOL_GET_SSET_COUNT
 static int i40e_get_sset_count(struct net_device *netdev, int sset)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
@@ -2227,16 +2377,7 @@ static int i40e_get_sset_count(struct net_device *netdev, int sset)
        case ETH_SS_TEST:
                return I40E_TEST_LEN;
        case ETH_SS_STATS:
-               if (vsi == pf->vsi[pf->lan_vsi] && pf->hw.partition_id == 1) {
-                       int len = I40E_PF_STATS_LEN(netdev);
-
-                       if ((pf->lan_veb != I40E_NO_VEB) &&
-                           (pf->flags & I40E_FLAG_VEB_STATS_ENABLED))
-                               len += I40E_VEB_STATS_TOTAL;
-                       return len;
-               } else {
-                       return I40E_VSI_STATS_LEN(netdev);
-               }
+               return i40e_get_stats_count(netdev);
        case ETH_SS_PRIV_FLAGS:
                return I40E_PRIV_FLAGS_STR_LEN +
                        (pf->hw.pf_id == 0 ? I40E_GL_PRIV_FLAGS_STR_LEN : 0);
@@ -2244,110 +2385,157 @@ static int i40e_get_sset_count(struct net_device *netdev, int sset)
                return -EOPNOTSUPP;
        }
 }
-
 #endif /* HAVE_ETHTOOL_GET_SSET_COUNT */
+
+/**
+ * i40e_get_pfc_stats - copy HW PFC statistics to formatted structure
+ * @pf: the PF device structure
+ * @i: the priority value to copy
+ *
+ * The PFC stats are found as arrays in pf->stats, which is not easy to pass
+ * into i40e_add_ethtool_stats. Produce a formatted i40e_pfc_stats structure
+ * of the PFC stats for the given priority.
+ **/
+static inline struct i40e_pfc_stats
+i40e_get_pfc_stats(struct i40e_pf *pf, unsigned int i)
+{
+#define I40E_GET_PFC_STAT(stat, priority) \
+       .stat = pf->stats.stat[priority]
+
+       struct i40e_pfc_stats pfc = {
+               I40E_GET_PFC_STAT(priority_xon_rx, i),
+               I40E_GET_PFC_STAT(priority_xoff_rx, i),
+               I40E_GET_PFC_STAT(priority_xon_tx, i),
+               I40E_GET_PFC_STAT(priority_xoff_tx, i),
+               I40E_GET_PFC_STAT(priority_xon_2_xoff, i),
+       };
+       return pfc;
+}
+
+/**
+ * i40e_get_ethtool_stats - copy stat values into supplied buffer
+ * @netdev: the netdev to collect stats for
+ * @stats: ethtool stats command structure
+ * @data: ethtool supplied buffer
+ *
+ * Copy the stats values for this netdev into the buffer. Expects data to be
+ * pre-allocated to the size returned by i40e_get_stats_count.. Note that all
+ * statistics must be copied in a static order, and the count must not change
+ * for a given netdev. See i40e_get_stats_count for more details.
+ *
+ * If a statistic is not currently valid (such as a disabled queue), this
+ * function reports its value as zero.
+ **/
 static void i40e_get_ethtool_stats(struct net_device *netdev,
                                   struct ethtool_stats *stats, u64 *data)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
-       struct i40e_ring *tx_ring, *rx_ring;
        struct i40e_vsi *vsi = np->vsi;
        struct i40e_pf *pf = vsi->back;
-       int i = 0;
-       char *p;
-       unsigned int j;
-
-#ifdef HAVE_NDO_GET_STATS64
-       struct rtnl_link_stats64 *net_stats = i40e_get_vsi_stats_struct(vsi);
-       unsigned int start;
-#else
-       struct net_device_stats *net_stats = i40e_get_vsi_stats_struct(vsi);
-#endif
+       struct i40e_veb *veb = pf->veb[pf->lan_veb];
+       unsigned int i;
+       bool veb_stats;
+       u64 *p = data;
 
        i40e_update_stats(vsi);
 
-       for (j = 0; j < I40E_NETDEV_STATS_LEN; j++) {
-               p = (char *)net_stats + i40e_gstrings_net_stats[j].stat_offset;
-               data[i++] = (i40e_gstrings_net_stats[j].sizeof_stat ==
-                       sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+       i40e_add_ethtool_stats(&data, i40e_get_vsi_stats_struct(vsi),
+                              i40e_gstrings_net_stats);
+
+       i40e_add_ethtool_stats(&data, vsi, i40e_gstrings_misc_stats);
+
+       rcu_read_lock();
+       for (i = 0; i < netdev->num_tx_queues; i++) {
+               i40e_add_queue_stats(&data, READ_ONCE(vsi->tx_rings[i]));
+               i40e_add_queue_stats(&data, READ_ONCE(vsi->rx_rings[i]));
+#ifdef HAVE_XDP_SUPPORT
+               i40e_add_rx_queue_xdp_stats(&data, READ_ONCE(vsi->rx_rings[i]));
+#endif
        }
-       for (j = 0; j < I40E_MISC_STATS_LEN; j++) {
-               p = (char *)vsi + i40e_gstrings_misc_stats[j].stat_offset;
-               data[i++] = (i40e_gstrings_misc_stats[j].sizeof_stat ==
-                           sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+       rcu_read_unlock();
+
+       if (vsi != pf->vsi[pf->lan_vsi] || pf->hw.partition_id != 1)
+               goto check_data_pointer;
+
+       veb_stats = ((pf->lan_veb != I40E_NO_VEB) &&
+                    (pf->flags & I40E_FLAG_VEB_STATS_ENABLED));
+
+       /* If veb stats aren't enabled, pass NULL instead of the veb so that
+        * we initialize stats to zero and update the data pointer
+        * intelligently
+        */
+       i40e_add_ethtool_stats(&data, veb_stats ? veb : NULL,
+                              i40e_gstrings_veb_stats);
+
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+               i40e_add_ethtool_stats(&data, veb_stats ? veb : NULL,
+                                      i40e_gstrings_veb_tc_stats);
+
+       i40e_add_ethtool_stats(&data, pf, i40e_gstrings_stats);
+
+       for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
+               struct i40e_pfc_stats pfc = i40e_get_pfc_stats(pf, i);
+
+               i40e_add_ethtool_stats(&data, &pfc, i40e_gstrings_pfc_stats);
        }
-       rcu_read_lock();
-       for (j = 0; j < vsi->num_queue_pairs; j++) {
-               tx_ring = READ_ONCE(vsi->tx_rings[j]);
 
-               if (!tx_ring)
-                       continue;
+check_data_pointer:
+       WARN_ONCE(data - p != i40e_get_stats_count(netdev),
+                 "ethtool stats count mismatch!");
+}
 
-               /* process Tx ring statistics */
-#ifdef HAVE_NDO_GET_STATS64
-               do {
-                       start = u64_stats_fetch_begin_irq(&tx_ring->syncp);
-#endif
-                       data[i] = tx_ring->stats.packets;
-                       data[i + 1] = tx_ring->stats.bytes;
-#ifdef HAVE_NDO_GET_STATS64
-               } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start));
-#endif
-               i += 2;
+/**
+ * i40e_get_stat_strings - copy stat strings into supplied buffer
+ * @netdev: the netdev to collect strings for
+ * @data: supplied buffer to copy strings into
+ *
+ * Copy the strings related to stats for this netdev. Expects data to be
+ * pre-allocated with the size reported by i40e_get_stats_count. Note that the
+ * strings must be copied in a static order and the total count must not
+ * change for a given netdev. See i40e_get_stats_count for more details.
+ **/
+static void i40e_get_stat_strings(struct net_device *netdev, u8 *data)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       unsigned int i;
+       u8 *p = data;
 
-               /* Rx ring is the 2nd half of the queue pair */
-               rx_ring = &tx_ring[1];
-#ifdef HAVE_NDO_GET_STATS64
-               do {
-                       start = u64_stats_fetch_begin_irq(&rx_ring->syncp);
-#endif
-                       data[i] = rx_ring->stats.packets;
-                       data[i + 1] = rx_ring->stats.bytes;
-#ifdef HAVE_NDO_GET_STATS64
-               } while (u64_stats_fetch_retry_irq(&rx_ring->syncp, start));
+       i40e_add_stat_strings(&data, i40e_gstrings_net_stats);
+
+       i40e_add_stat_strings(&data, i40e_gstrings_misc_stats);
+
+       for (i = 0; i < netdev->num_tx_queues; i++) {
+               i40e_add_stat_strings(&data, i40e_gstrings_queue_stats,
+                                     "tx", i);
+               i40e_add_stat_strings(&data, i40e_gstrings_queue_stats,
+                                     "rx", i);
+#ifdef HAVE_XDP_SUPPORT
+               i40e_add_stat_strings(&data, i40e_gstrings_rx_queue_xdp_stats,
+                                     "rx", i);
 #endif
-               i += 2;
        }
-       rcu_read_unlock();
+
        if (vsi != pf->vsi[pf->lan_vsi] || pf->hw.partition_id != 1)
                return;
 
-       if ((pf->lan_veb != I40E_NO_VEB) &&
-           (pf->flags & I40E_FLAG_VEB_STATS_ENABLED)) {
-               struct i40e_veb *veb = pf->veb[pf->lan_veb];
+       i40e_add_stat_strings(&data, i40e_gstrings_veb_stats);
 
-               for (j = 0; j < I40E_VEB_STATS_LEN; j++) {
-                       p = (char *)veb;
-                       p += i40e_gstrings_veb_stats[j].stat_offset;
-                       data[i++] = (i40e_gstrings_veb_stats[j].sizeof_stat ==
-                                    sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
-               }
-               for (j = 0; j < I40E_MAX_TRAFFIC_CLASS; j++) {
-                       data[i++] = veb->tc_stats.tc_tx_packets[j];
-                       data[i++] = veb->tc_stats.tc_tx_bytes[j];
-                       data[i++] = veb->tc_stats.tc_rx_packets[j];
-                       data[i++] = veb->tc_stats.tc_rx_bytes[j];
-               }
-       }
-       for (j = 0; j < I40E_GLOBAL_STATS_LEN; j++) {
-               p = (char *)pf + i40e_gstrings_stats[j].stat_offset;
-               data[i++] = (i40e_gstrings_stats[j].sizeof_stat ==
-                            sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
-       }
-       for (j = 0; j < I40E_MAX_USER_PRIORITY; j++) {
-               data[i++] = pf->stats.priority_xon_tx[j];
-               data[i++] = pf->stats.priority_xoff_tx[j];
-       }
-       for (j = 0; j < I40E_MAX_USER_PRIORITY; j++) {
-               data[i++] = pf->stats.priority_xon_rx[j];
-               data[i++] = pf->stats.priority_xoff_rx[j];
-       }
-       for (j = 0; j < I40E_MAX_USER_PRIORITY; j++)
-               data[i++] = pf->stats.priority_xon_2_xoff[j];
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+               i40e_add_stat_strings(&data, i40e_gstrings_veb_tc_stats, i);
+
+       i40e_add_stat_strings(&data, i40e_gstrings_stats);
+
+       for (i = 0; i < I40E_MAX_USER_PRIORITY; i++)
+               i40e_add_stat_strings(&data, i40e_gstrings_pfc_stats, i);
+
+       WARN_ONCE(data - p != i40e_get_stats_count(netdev) * ETH_GSTRING_LEN,
+                 "stat strings count mismatch!");
 }
 
-static void i40e_get_strings(struct net_device *netdev, u32 stringset,
-                            u8 *data)
+#ifdef HAVE_ETHTOOL_GET_SSET_COUNT
+static void i40e_get_priv_flag_strings(struct net_device *netdev, u8 *data)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
@@ -2355,99 +2543,35 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset,
        char *p = (char *)data;
        unsigned int i;
 
+       for (i = 0; i < I40E_PRIV_FLAGS_STR_LEN; i++) {
+               snprintf(p, ETH_GSTRING_LEN, "%s",
+                        i40e_gstrings_priv_flags[i].flag_string);
+               p += ETH_GSTRING_LEN;
+       }
+       if (pf->hw.pf_id != 0)
+               return;
+       for (i = 0; i < I40E_GL_PRIV_FLAGS_STR_LEN; i++) {
+               snprintf(p, ETH_GSTRING_LEN, "%s",
+                        i40e_gl_gstrings_priv_flags[i].flag_string);
+               p += ETH_GSTRING_LEN;
+       }
+}
+#endif
+
+static void i40e_get_strings(struct net_device *netdev, u32 stringset,
+                            u8 *data)
+{
        switch (stringset) {
        case ETH_SS_TEST:
                memcpy(data, i40e_gstrings_test,
                       I40E_TEST_LEN * ETH_GSTRING_LEN);
                break;
        case ETH_SS_STATS:
-               for (i = 0; i < I40E_NETDEV_STATS_LEN; i++) {
-                       snprintf(p, ETH_GSTRING_LEN, "%s",
-                                i40e_gstrings_net_stats[i].stat_string);
-                       p += ETH_GSTRING_LEN;
-               }
-               for (i = 0; i < I40E_MISC_STATS_LEN; i++) {
-                       snprintf(p, ETH_GSTRING_LEN, "%s",
-                                i40e_gstrings_misc_stats[i].stat_string);
-                       p += ETH_GSTRING_LEN;
-               }
-               for (i = 0; i < vsi->num_queue_pairs; i++) {
-                       snprintf(p, ETH_GSTRING_LEN, "tx-%u.tx_packets", i);
-                       p += ETH_GSTRING_LEN;
-                       snprintf(p, ETH_GSTRING_LEN, "tx-%u.tx_bytes", i);
-                       p += ETH_GSTRING_LEN;
-                       snprintf(p, ETH_GSTRING_LEN, "rx-%u.rx_packets", i);
-                       p += ETH_GSTRING_LEN;
-                       snprintf(p, ETH_GSTRING_LEN, "rx-%u.rx_bytes", i);
-                       p += ETH_GSTRING_LEN;
-               }
-               if (vsi != pf->vsi[pf->lan_vsi] || pf->hw.partition_id != 1)
-                       return;
-
-               if ((pf->lan_veb != I40E_NO_VEB) &&
-                   (pf->flags & I40E_FLAG_VEB_STATS_ENABLED)) {
-                       for (i = 0; i < I40E_VEB_STATS_LEN; i++) {
-                               snprintf(p, ETH_GSTRING_LEN, "veb.%s",
-                                       i40e_gstrings_veb_stats[i].stat_string);
-                               p += ETH_GSTRING_LEN;
-                       }
-                       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-                               snprintf(p, ETH_GSTRING_LEN,
-                                        "veb.tc_%u_tx_packets", i);
-                               p += ETH_GSTRING_LEN;
-                               snprintf(p, ETH_GSTRING_LEN,
-                                        "veb.tc_%u_tx_bytes", i);
-                               p += ETH_GSTRING_LEN;
-                               snprintf(p, ETH_GSTRING_LEN,
-                                        "veb.tc_%u_rx_packets", i);
-                               p += ETH_GSTRING_LEN;
-                               snprintf(p, ETH_GSTRING_LEN,
-                                        "veb.tc_%u_rx_bytes", i);
-                               p += ETH_GSTRING_LEN;
-                       }
-               }
-               for (i = 0; i < I40E_GLOBAL_STATS_LEN; i++) {
-                       snprintf(p, ETH_GSTRING_LEN, "port.%s",
-                                i40e_gstrings_stats[i].stat_string);
-                       p += ETH_GSTRING_LEN;
-               }
-               for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
-                       snprintf(p, ETH_GSTRING_LEN,
-                                "port.tx_priority_%u_xon", i);
-                       p += ETH_GSTRING_LEN;
-                       snprintf(p, ETH_GSTRING_LEN,
-                                "port.tx_priority_%u_xoff", i);
-                       p += ETH_GSTRING_LEN;
-               }
-               for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
-                       snprintf(p, ETH_GSTRING_LEN,
-                                "port.rx_priority_%u_xon", i);
-                       p += ETH_GSTRING_LEN;
-                       snprintf(p, ETH_GSTRING_LEN,
-                                "port.rx_priority_%u_xoff", i);
-                       p += ETH_GSTRING_LEN;
-               }
-               for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
-                       snprintf(p, ETH_GSTRING_LEN,
-                                "port.rx_priority_%u_xon_2_xoff", i);
-                       p += ETH_GSTRING_LEN;
-               }
-               /* BUG_ON(p - data != I40E_STATS_LEN * ETH_GSTRING_LEN); */
+               i40e_get_stat_strings(netdev, data);
                break;
 #ifdef HAVE_ETHTOOL_GET_SSET_COUNT
        case ETH_SS_PRIV_FLAGS:
-               for (i = 0; i < I40E_PRIV_FLAGS_STR_LEN; i++) {
-                       snprintf(p, ETH_GSTRING_LEN, "%s",
-                                i40e_gstrings_priv_flags[i].flag_string);
-                       p += ETH_GSTRING_LEN;
-               }
-               if (pf->hw.pf_id != 0)
-                       break;
-               for (i = 0; i < I40E_GL_PRIV_FLAGS_STR_LEN; i++) {
-                       snprintf(p, ETH_GSTRING_LEN, "%s",
-                                i40e_gl_gstrings_priv_flags[i].flag_string);
-                       p += ETH_GSTRING_LEN;
-               }
+               i40e_get_priv_flag_strings(netdev, data);
                break;
 #endif
        default:
@@ -3185,7 +3309,7 @@ static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd)
 /**
  * i40e_check_mask - Check whether a mask field is set
  * @mask: the full mask value
- * @field; mask of the field to check
+ * @field: mask of the field to check
  *
  * If the given mask is fully set, return positive value. If the mask for the
  * field is fully unset, return zero. Otherwise return a negative error code.
@@ -3285,6 +3409,7 @@ static int i40e_parse_rx_flow_user_data(struct ethtool_rx_flow_spec *fsp,
 /**
  * i40e_fill_rx_flow_user_data - Fill in user-defined data field
  * @fsp: pointer to rx_flow specification
+ * @data: pointer to return userdef data
  *
  * Reads the userdef data structure and properly fills in the user defined
  * fields of the rx_flow_spec.
@@ -3577,6 +3702,7 @@ static int i40e_get_cloud_filter_entry(struct i40e_pf *pf,
  * i40e_get_rxnfc - command to get RX flow classification rules
  * @netdev: network interface device structure
  * @cmd: ethtool rxnfc command
+ * @rule_locs: pointer to store rule data
  *
  * Returns Success if the command is supported.
  **/
@@ -3594,7 +3720,7 @@ static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
 
        switch (cmd->cmd) {
        case ETHTOOL_GRXRINGS:
-               cmd->data = vsi->num_queue_pairs;
+               cmd->data = vsi->rss_size;
                ret = 0;
                break;
        case ETHTOOL_GRXFH:
@@ -3630,7 +3756,7 @@ static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
 /**
  * i40e_get_rss_hash_bits - Read RSS Hash bits from register
  * @nfc: pointer to user request
- * @i_setc bits currently set
+ * @i_setc: bits currently set
  *
  * Returns value of bits to be set per user request
  **/
@@ -3675,7 +3801,7 @@ static u64 i40e_get_rss_hash_bits(struct ethtool_rxnfc *nfc, u64 i_setc)
 /**
  * i40e_set_rss_hash_opt - Enable/Disable flow types for RSS hash
  * @pf: pointer to the physical function struct
- * @cmd: ethtool rxnfc command
+ * @nfc: ethtool rxnfc command
  *
  * Returns Success if the flow input set is supported.
  **/
@@ -3788,6 +3914,7 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
  * i40e_cloud_filter_mask2flags- Convert cloud filter details to filter type
  * @pf: pointer to the physical function struct
  * @fsp: RX flow classification rules
+ * @userdef: pointer to userdef field data
  * @flags: Resultant combination of all the fields to decide the tuple
  *
  * The general trick in setting these flags is that if the mask field for
@@ -3894,8 +4021,9 @@ static int i40e_del_fdir_entry(struct i40e_vsi *vsi,
 
 /**
  * i40e_add_cloud_filter_ethtool - Add cloud filter
- * @pf: pointer to the physical function struct
+ * @vsi: pointer to the VSI structure
  * @cmd: The command to get or set Rx flow classification rules
+ * @userdef: pointer to userdef field data
  *
  * Add cloud filter for a specific flow spec.
  * Returns 0 if the filter were successfully added.
@@ -3973,10 +4101,9 @@ static int i40e_add_cloud_filter_ethtool(struct i40e_vsi *vsi,
        }
        if (filter && (filter->id == fsp->location)) {
                /* found it in the cloud list, so remove it */
-               ret = i40e_add_del_cloud_filter(pf, filter, false);
-               if (ret && (pf->hw.aq.asq_last_status != I40E_AQ_RC_ENOENT)) {
+               ret = i40e_add_del_cloud_filter(vsi, filter, false);
+               if (ret && pf->hw.aq.asq_last_status != I40E_AQ_RC_ENOENT)
                        return ret;
-               }
                hlist_del(&filter->cloud_node);
                kfree(filter);
                pf->num_cloud_filters--;
@@ -4028,7 +4155,7 @@ static int i40e_add_cloud_filter_ethtool(struct i40e_vsi *vsi,
        filter->flags = flags;
        filter->inner_vlan = fsp->h_ext.vlan_tci;
 
-       ret = i40e_add_del_cloud_filter(pf, filter, true);
+       ret = i40e_add_del_cloud_filter(vsi, filter, true);
        if (ret) {
                kfree(filter);
                return ret;
@@ -4059,6 +4186,7 @@ static int i40e_del_cloud_filter_ethtool(struct i40e_pf *pf,
        struct i40e_cloud_filter *rule, *filter = NULL;
        struct ethtool_rx_flow_spec *fsp;
        struct hlist_node *node2;
+       struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
 
        fsp = (struct ethtool_rx_flow_spec *)&cmd->fs;
        hlist_for_each_entry_safe(rule, node2,
@@ -4075,7 +4203,7 @@ static int i40e_del_cloud_filter_ethtool(struct i40e_pf *pf,
                return -ENOENT;
 
        /* remove filter from the list even if failed to remove from device */
-       (void)i40e_add_del_cloud_filter(pf, filter, false);
+       (void)i40e_add_del_cloud_filter(vsi, filter, false);
        hlist_del(&filter->cloud_node);
        kfree(filter);
        pf->num_cloud_filters--;
@@ -4370,7 +4498,7 @@ static int i40e_add_flex_offset(struct list_head *flex_pit_list,
  * __i40e_reprogram_flex_pit - Re-program specific FLX_PIT table
  * @pf: Pointer to the PF structure
  * @flex_pit_list: list of flexible src offsets in use
- * #flex_pit_start: index to first entry for this section of the table
+ * @flex_pit_start: index to first entry for this section of the table
  *
  * In order to handle flexible data, the hardware uses a table of values
  * called the FLX_PIT table. This table is used to indicate which sections of
@@ -4484,7 +4612,7 @@ static void i40e_reprogram_flex_pit(struct i40e_pf *pf)
 
 /**
  * i40e_flow_str - Converts a flow_type into a human readable string
- * @flow_type: the flow type from a flow specification
+ * @fsp: the flow specification
  *
  * Currently only flow types we support are included here, and the string
  * value attempts to match what ethtool would use to configure this flow type.
@@ -4943,7 +5071,7 @@ static int i40e_check_fdir_input_set(struct i40e_vsi *vsi,
 static bool i40e_match_fdir_filter(struct i40e_fdir_filter *a,
                                   struct i40e_fdir_filter *b)
 {
-       /* The filters do not much if any of these criteria differ. */
+       /* The filters do not match if any of these criteria differ. */
        if (a->dst_ip != b->dst_ip ||
            a->src_ip != b->src_ip ||
            a->dst_port != b->dst_port ||
@@ -5037,7 +5165,7 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
        if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
                return -EOPNOTSUPP;
 
-       if (pf->flags & I40E_FLAG_FD_SB_AUTO_DISABLED)
+       if (test_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state))
                return -ENOSPC;
 
        if (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state) ||
@@ -5200,7 +5328,7 @@ static unsigned int i40e_max_channels(struct i40e_vsi *vsi)
 
 /**
  * i40e_get_channels - Get the current channels enabled and max supported etc.
- * @netdev: network interface device structure
+ * @dev: network interface device structure
  * @ch: ethtool channels structure
  *
  * We don't support separate tx and rx queues as channels. The other count
@@ -5209,7 +5337,7 @@ static unsigned int i40e_max_channels(struct i40e_vsi *vsi)
  * q_vectors since we support a lot more queue pairs than q_vectors.
  **/
 static void i40e_get_channels(struct net_device *dev,
-                              struct ethtool_channels *ch)
+                             struct ethtool_channels *ch)
 {
        struct i40e_netdev_priv *np = netdev_priv(dev);
        struct i40e_vsi *vsi = np->vsi;
@@ -5228,14 +5356,14 @@ static void i40e_get_channels(struct net_device *dev,
 
 /**
  * i40e_set_channels - Set the new channels count.
- * @netdev: network interface device structure
+ * @dev: network interface device structure
  * @ch: ethtool channels structure
  *
  * The new channels count may not be the same as requested by the user
  * since it gets rounded down to a power of 2 value.
  **/
 static int i40e_set_channels(struct net_device *dev,
-                             struct ethtool_channels *ch)
+                            struct ethtool_channels *ch)
 {
        const u8 drop = I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET;
        struct i40e_netdev_priv *np = netdev_priv(dev);
@@ -5251,6 +5379,12 @@ static int i40e_set_channels(struct net_device *dev,
        if (vsi->type != I40E_VSI_MAIN)
                return -EINVAL;
 
+       /* We do not support setting channels via ethtool when TCs are
+        * configured through mqprio
+        */
+       if (pf->flags & I40E_FLAG_TC_MQPRIO)
+               return -EINVAL;
+
        /* verify they are not requesting separate vectors */
        if (!count || ch->rx_count || ch->tx_count)
                return -EINVAL;
@@ -5373,6 +5507,7 @@ out:
  * @netdev: network interface device structure
  * @indir: indirection table
  * @key: hash key
+ * @hfunc: hash function to use
  *
  * Returns -EINVAL if the table specifies an invalid queue id, otherwise
  * returns 0 after programming the table.
@@ -5543,44 +5678,37 @@ flags_complete:
                return -EOPNOTSUPP;
 
        /* If the driver detected FW LLDP was disabled on init, this flag could
-        * be set, however we do not support _changing_ the flag if NPAR is
-        * enabled or FW API version < 1.7.  There are situations where older
-        * FW versions/NPAR enabled PFs could disable LLDP, however we _must_
-        * not allow the user to enable/disable LLDP with this flag on
-        * unsupported FW verions.
+        * be set, however we do not support _changing_ the flag:
+        * - on XL710 if NPAR is enabled or FW API version < 1.7
+        * - on X722 with FW API version < 1.6
+        * There are situations where older FW versions/NPAR enabled PFs could
+        * disable LLDP, however we _must_ not allow the user to enable/disable
+        * LLDP with this flag on unsupported FW versions.
         */
        if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP) {
-               if (pf->hw.func_caps.npar_enable) {
-                       dev_warn(&pf->pdev->dev,
-                                "Unable to change FW LLDP if NPAR active\n");
-                       return -EOPNOTSUPP;
-               }
-
-               if (pf->hw.aq.api_maj_ver < 1 ||
-                   (pf->hw.aq.api_maj_ver == 1 &&
-                    pf->hw.aq.api_min_ver < 7)) {
+               if (!(pf->hw.flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE)) {
                        dev_warn(&pf->pdev->dev,
-                                "FW ver does not support changing FW LLDP\n");
+                                "Device does not support changing FW LLDP\n");
                        return -EOPNOTSUPP;
                }
        }
 
-       /* Compare and exchange the new flags into place. If we failed, that
-        * is if cmpxchg returns anything but the old value, this means that
-        * something else has modified the flags variable since we copied it
-        * originally. We'll just punt with an error and log something in the
-        * message buffer.
-        *
-        * This is the point of no return for this function.  We need to have
-        * checked any discrepencies or misconfigurations and returned
-        * EOPNOTSUPP before updating pf->flags here.
-        */
-       if (cmpxchg64(&pf->flags, orig_flags, new_flags) != orig_flags) {
+       if (((changed_flags & I40E_FLAG_RS_FEC) ||
+            (changed_flags & I40E_FLAG_BASE_R_FEC)) &&
+           pf->hw.device_id != I40E_DEV_ID_25G_SFP28 &&
+           pf->hw.device_id != I40E_DEV_ID_25G_B) {
                dev_warn(&pf->pdev->dev,
-                        "Unable to update pf->flags as it was modified by another thread...\n");
-               return -EAGAIN;
+                        "Device does not support changing FEC configuration\n");
+               return -EOPNOTSUPP;
        }
 
+       /* Now that we've checked to ensure that the new flags are valid, load
+        * them into place. Since we only modify flags either (a) during
+        * initialization or (b) while holding the RTNL lock, we don't need
+        * anything fancy here.
+        */
+       pf->flags = new_flags;
+
        /* Process any additional changes needed as a result of flag changes.
         * The changed_flags value reflects the list of bits that were
         * changed in the code above.
@@ -5589,7 +5717,7 @@ flags_complete:
        /* Flush current ATR settings if ATR was disabled */
        if ((changed_flags & I40E_FLAG_FD_ATR_ENABLED) &&
            !(pf->flags & I40E_FLAG_FD_ATR_ENABLED)) {
-               pf->flags |= I40E_FLAG_FD_ATR_AUTO_DISABLED;
+               set_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state);
                set_bit(__I40E_FD_FLUSH_REQUESTED, pf->state);
        }
 
@@ -5601,7 +5729,7 @@ flags_complete:
                        sw_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
                valid_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
                ret = i40e_aq_set_switch_config(&pf->hw, sw_flags, valid_flags,
-                                               NULL);
+                                               0, NULL);
                if (ret && pf->hw.aq.asq_last_status != I40E_AQ_RC_ESRCH) {
                        dev_info(&pf->pdev->dev,
                                 "couldn't set switch config bits, err %s aq_err %s\n",
@@ -5612,6 +5740,24 @@ flags_complete:
                }
        }
 
+       if ((changed_flags & I40E_FLAG_RS_FEC) ||
+           (changed_flags & I40E_FLAG_BASE_R_FEC)) {
+               u8 fec_cfg = 0;
+
+               if (pf->flags & I40E_FLAG_RS_FEC &&
+                   pf->flags & I40E_FLAG_BASE_R_FEC) {
+                       fec_cfg = I40E_AQ_SET_FEC_AUTO;
+               } else if (pf->flags & I40E_FLAG_RS_FEC) {
+                       fec_cfg = (I40E_AQ_SET_FEC_REQUEST_RS |
+                                  I40E_AQ_SET_FEC_ABILITY_RS);
+               } else if (pf->flags & I40E_FLAG_BASE_R_FEC) {
+                       fec_cfg = (I40E_AQ_SET_FEC_REQUEST_KR |
+                                  I40E_AQ_SET_FEC_ABILITY_KR);
+               }
+               if (i40e_set_fec_cfg(dev, fec_cfg))
+                       dev_warn(&pf->pdev->dev, "Cannot change FEC config\n");
+       }
+
        if ((changed_flags & pf->flags &
             I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED) &&
            (pf->flags & I40E_FLAG_MFP_ENABLED))
@@ -5621,7 +5767,6 @@ flags_complete:
        if (changed_flags & I40E_FLAG_DISABLE_FW_LLDP) {
                if (pf->flags & I40E_FLAG_DISABLE_FW_LLDP) {
                        struct i40e_dcbx_config *dcbcfg;
-                       int i;
 
                        i40e_aq_stop_lldp(&pf->hw, true, NULL);
                        i40e_aq_set_dcb_parameters(&pf->hw, true, NULL);
@@ -5696,7 +5841,7 @@ static int i40e_get_module_info(struct net_device *netdev,
        case I40E_MODULE_TYPE_SFP:
                status = i40e_aq_get_phy_register(hw,
                                I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
-                               I40E_I2C_EEPROM_DEV_ADDR,
+                               I40E_I2C_EEPROM_DEV_ADDR, true,
                                I40E_MODULE_SFF_8472_COMP,
                                &sff8472_comp, NULL);
                if (status)
@@ -5704,7 +5849,7 @@ static int i40e_get_module_info(struct net_device *netdev,
 
                status = i40e_aq_get_phy_register(hw,
                                I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
-                               I40E_I2C_EEPROM_DEV_ADDR,
+                               I40E_I2C_EEPROM_DEV_ADDR, true,
                                I40E_MODULE_SFF_8472_SWAP,
                                &sff8472_swap, NULL);
                if (status)
@@ -5731,7 +5876,7 @@ static int i40e_get_module_info(struct net_device *netdev,
                /* Read from memory page 0. */
                status = i40e_aq_get_phy_register(hw,
                                I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
-                               0,
+                               0, true,
                                I40E_MODULE_REVISION_ADDR,
                                &sff8636_rev, NULL);
                if (status)
@@ -5802,7 +5947,7 @@ static int i40e_get_module_eeprom(struct net_device *netdev,
 
                status = i40e_aq_get_phy_register(hw,
                                I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE,
-                               addr, offset, &value, NULL);
+                               addr, true, offset, &value, NULL);
                if (status)
                        return -EIO;
                data[i] = value;
@@ -5811,6 +5956,12 @@ static int i40e_get_module_eeprom(struct net_device *netdev,
 }
 #endif /* ETHTOOL_GMODULEINFO */
 
+static const struct ethtool_ops i40e_ethtool_recovery_mode_ops = {
+       .set_eeprom             = i40e_set_eeprom,
+       .get_eeprom_len         = i40e_get_eeprom_len,
+       .get_eeprom             = i40e_get_eeprom,
+};
+
 static const struct ethtool_ops i40e_ethtool_ops = {
 #ifndef ETHTOOL_GLINKSETTINGS
        .get_settings           = i40e_get_settings,
@@ -5905,6 +6056,14 @@ static const struct ethtool_ops i40e_ethtool_ops = {
        .get_link_ksettings = i40e_get_link_ksettings,
        .set_link_ksettings = i40e_set_link_ksettings,
 #endif /* ETHTOOL_GLINKSETTINGS */
+#ifdef ETHTOOL_GFECPARAM
+       .get_fecparam = i40e_get_fec_param,
+       .set_fecparam = i40e_set_fec_param,
+#endif /* ETHTOOL_GFECPARAM */
+#if ( LINUX_VERSION_CODE > KERNEL_VERSION(4,0,0) ) || \
+    (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2))
+       .flash_device = i40e_ddp_flash,
+#endif
 };
 
 #ifdef HAVE_RHEL6_ETHTOOL_OPS_EXT_STRUCT
@@ -5928,13 +6087,26 @@ static const struct ethtool_ops_ext i40e_ethtool_ops_ext = {
 
 void i40e_set_ethtool_ops(struct net_device *netdev)
 {
-       netdev->ethtool_ops = &i40e_ethtool_ops;
-       set_ethtool_ops_ext(netdev, &i40e_ethtool_ops_ext);
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf          *pf = np->vsi->back;
+
+       if (test_bit(__I40E_RECOVERY_MODE, pf->state)) {
+               netdev->ethtool_ops = &i40e_ethtool_recovery_mode_ops;
+       } else {
+               netdev->ethtool_ops = &i40e_ethtool_ops;
+               set_ethtool_ops_ext(netdev, &i40e_ethtool_ops_ext);
+       }
 }
 #else
 void i40e_set_ethtool_ops(struct net_device *netdev)
 {
-       netdev->ethtool_ops = &i40e_ethtool_ops;
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf          *pf = np->vsi->back;
+
+       if (test_bit(__I40E_RECOVERY_MODE, pf->state))
+               netdev->ethtool_ops = &i40e_ethtool_recovery_mode_ops;
+       else
+               netdev->ethtool_ops = &i40e_ethtool_ops;
 }
 #endif /* HAVE_RHEL6_ETHTOOL_OPS_EXT_STRUCT */
 #endif /* SIOCETHTOOL */
diff --git a/i40e-dkms/i40e-2.7.29/src/i40e_ethtool_stats.h b/i40e-dkms/i40e-2.7.29/src/i40e_ethtool_stats.h
new file mode 100644 (file)
index 0000000..2b3c6e4
--- /dev/null
@@ -0,0 +1,293 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+/* ethtool statistics helpers */
+
+/**
+ * struct i40e_stats - definition for an ethtool statistic
+ * @stat_string: statistic name to display in ethtool -S output
+ * @sizeof_stat: the sizeof() the stat, must be no greater than sizeof(u64)
+ * @stat_offset: offsetof() the stat from a base pointer
+ *
+ * This structure defines a statistic to be added to the ethtool stats buffer.
+ * It defines a statistic as offset from a common base pointer. Stats should
+ * be defined in constant arrays using the I40E_STAT macro, with every element
+ * of the array using the same _type for calculating the sizeof_stat and
+ * stat_offset.
+ *
+ * The @sizeof_stat is expected to be sizeof(u8), sizeof(u16), sizeof(u32) or
+ * sizeof(u64). Other sizes are not expected and will produce a WARN_ONCE from
+ * the i40e_add_ethtool_stat() helper function.
+ *
+ * The @stat_string is interpreted as a format string, allowing formatted
+ * values to be inserted while looping over multiple structures for a given
+ * statistics array. Thus, every statistic string in an array should have the
+ * same type and number of format specifiers, to be formatted by variadic
+ * arguments to the i40e_add_stat_string() helper function.
+ **/
+struct i40e_stats {
+       char stat_string[ETH_GSTRING_LEN];
+       int sizeof_stat;
+       int stat_offset;
+};
+
+/* Helper macro to define an i40e_stat structure with proper size and type.
+ * Use this when defining constant statistics arrays. Note that @_type expects
+ * only a type name and is used multiple times.
+ */
+#define I40E_STAT(_type, _name, _stat) { \
+       .stat_string = _name, \
+       .sizeof_stat = FIELD_SIZEOF(_type, _stat), \
+       .stat_offset = offsetof(_type, _stat) \
+}
+
+/* Helper macro for defining some statistics directly copied from the netdev
+ * stats structure.
+ */
+#ifdef HAVE_NDO_GET_STATS64
+#define I40E_NETDEV_STAT(_net_stat) \
+       I40E_STAT(struct rtnl_link_stats64, #_net_stat, _net_stat)
+#else
+#define I40E_NETDEV_STAT(_net_stat) \
+       I40E_STAT(struct net_device_stats, #_net_stat, _net_stat)
+#endif
+
+/* Helper macro for defining some statistics related to queues */
+#define I40E_QUEUE_STAT(_name, _stat) \
+       I40E_STAT(struct i40e_ring, _name, _stat)
+
+/* Stats associated with a Tx or Rx ring */
+static const struct i40e_stats i40e_gstrings_queue_stats[] = {
+       I40E_QUEUE_STAT("%s-%u.packets", stats.packets),
+       I40E_QUEUE_STAT("%s-%u.bytes", stats.bytes),
+};
+
+#ifdef HAVE_XDP_SUPPORT
+/* Stats associated with Rx ring's XDP prog */
+static const struct i40e_stats i40e_gstrings_rx_queue_xdp_stats[] = {
+       I40E_QUEUE_STAT("%s-%u.xdp.pass", xdp_stats.xdp_pass),
+       I40E_QUEUE_STAT("%s-%u.xdp.drop", xdp_stats.xdp_drop),
+       I40E_QUEUE_STAT("%s-%u.xdp.tx", xdp_stats.xdp_tx),
+       I40E_QUEUE_STAT("%s-%u.xdp.unknown", xdp_stats.xdp_unknown),
+       I40E_QUEUE_STAT("%s-%u.xdp.redirect", xdp_stats.xdp_redirect),
+       I40E_QUEUE_STAT("%s-%u.xdp.redirect_fail", xdp_stats.xdp_redirect_fail),
+};
+#endif
+
+/**
+ * i40e_add_one_ethtool_stat - copy the stat into the supplied buffer
+ * @data: location to store the stat value
+ * @pointer: basis for where to copy from
+ * @stat: the stat definition
+ *
+ * Copies the stat data defined by the pointer and stat structure pair into
+ * the memory supplied as data. Used to implement i40e_add_ethtool_stats and
+ * i40e_add_queue_stats. If the pointer is null, data will be zero'd.
+ */
+static void
+i40e_add_one_ethtool_stat(u64 *data, void *pointer,
+                         const struct i40e_stats *stat)
+{
+       char *p;
+
+       if (!pointer) {
+               /* ensure that the ethtool data buffer is zero'd for any stats
+                * which don't have a valid pointer.
+                */
+               *data = 0;
+               return;
+       }
+
+       p = (char *)pointer + stat->stat_offset;
+       switch (stat->sizeof_stat) {
+       case sizeof(u64):
+               *data = *((u64 *)p);
+               break;
+       case sizeof(u32):
+               *data = *((u32 *)p);
+               break;
+       case sizeof(u16):
+               *data = *((u16 *)p);
+               break;
+       case sizeof(u8):
+               *data = *((u8 *)p);
+               break;
+       default:
+               WARN_ONCE(1, "unexpected stat size for %s",
+                         stat->stat_string);
+               *data = 0;
+       }
+}
+
+/**
+ * __i40e_add_ethtool_stats - copy stats into the ethtool supplied buffer
+ * @data: ethtool stats buffer
+ * @pointer: location to copy stats from
+ * @stats: array of stats to copy
+ * @size: the size of the stats definition
+ *
+ * Copy the stats defined by the stats array using the pointer as a base into
+ * the data buffer supplied by ethtool. Updates the data pointer to point to
+ * the next empty location for successive calls to __i40e_add_ethtool_stats.
+ * If pointer is null, set the data values to zero and update the pointer to
+ * skip these stats.
+ **/
+static void
+__i40e_add_ethtool_stats(u64 **data, void *pointer,
+                        const struct i40e_stats stats[],
+                        const unsigned int size)
+{
+       unsigned int i;
+
+       for (i = 0; i < size; i++)
+               i40e_add_one_ethtool_stat((*data)++, pointer, &stats[i]);
+}
+
+/**
+ * i40e_add_ethtool_stats - copy stats into ethtool supplied buffer
+ * @data: ethtool stats buffer
+ * @pointer: location where stats are stored
+ * @stats: static const array of stat definitions
+ *
+ * Macro to ease the use of __i40e_add_ethtool_stats by taking a static
+ * constant stats array and passing the ARRAY_SIZE(). This avoids typos by
+ * ensuring that we pass the size associated with the given stats array.
+ *
+ * The parameter @stats is evaluated twice, so parameters with side effects
+ * should be avoided.
+ **/
+#define i40e_add_ethtool_stats(data, pointer, stats) \
+       __i40e_add_ethtool_stats(data, pointer, stats, ARRAY_SIZE(stats))
+
+/**
+ * i40e_add_queue_stats - copy queue statistics into supplied buffer
+ * @data: ethtool stats buffer
+ * @ring: the ring to copy
+ *
+ * Queue statistics must be copied while protected by
+ * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats.
+ * Assumes that queue stats are defined in i40e_gstrings_queue_stats. If the
+ * ring pointer is null, zero out the queue stat values and update the data
+ * pointer. Otherwise safely copy the stats from the ring into the supplied
+ * buffer and update the data pointer when finished.
+ *
+ * This function expects to be called while under rcu_read_lock().
+ **/
+static void
+i40e_add_queue_stats(u64 **data, struct i40e_ring *ring)
+{
+       const unsigned int size = ARRAY_SIZE(i40e_gstrings_queue_stats);
+       const struct i40e_stats *stats = i40e_gstrings_queue_stats;
+#ifdef HAVE_NDO_GET_STATS64
+       unsigned int start;
+#endif
+       unsigned int i;
+
+       /* To avoid invalid statistics values, ensure that we keep retrying
+        * the copy until we get a consistent value according to
+        * u64_stats_fetch_retry_irq. But first, make sure our ring is
+        * non-null before attempting to access its syncp.
+        */
+#ifdef HAVE_NDO_GET_STATS64
+       do {
+               start = !ring ? 0 : u64_stats_fetch_begin_irq(&ring->syncp);
+#endif
+               for (i = 0; i < size; i++) {
+                       i40e_add_one_ethtool_stat(&(*data)[i], ring,
+                                                 &stats[i]);
+               }
+#ifdef HAVE_NDO_GET_STATS64
+       } while (ring && u64_stats_fetch_retry_irq(&ring->syncp, start));
+#endif
+
+       /* Once we successfully copy the stats in, update the data pointer */
+       *data += size;
+}
+
+#ifdef HAVE_XDP_SUPPORT
+/**
+ * i40e_add_rx_queue_xdp_stats - copy XDP statistics into supplied buffer
+ * @data: ethtool stats buffer
+ * @rx_ring: the rx ring to copy
+ *
+ * RX queue XDP statistics must be copied while protected by
+ * u64_stats_fetch_begin_irq, so we can't directly use i40e_add_ethtool_stats.
+ * Assumes that queue stats are defined in i40e_gstrings_rx_queue_xdp_stats. If
+ * the ring pointer is null, zero out the queue stat values and update the data
+ * pointer. Otherwise safely copy the stats from the ring into the supplied
+ * buffer and update the data pointer when finished.
+ *
+ * This function expects to be called while under rcu_read_lock().
+ **/
+static void
+i40e_add_rx_queue_xdp_stats(u64 **data, struct i40e_ring *rx_ring)
+{
+       const unsigned int xdp_size =
+               ARRAY_SIZE(i40e_gstrings_rx_queue_xdp_stats);
+       const struct i40e_stats *xdp_stats = i40e_gstrings_rx_queue_xdp_stats;
+#ifdef HAVE_NDO_GET_STATS64
+       unsigned int start;
+#endif
+       unsigned int i;
+
+       /* To avoid invalid statistics values, ensure that we keep retrying
+        * the copy until we get a consistent value according to
+        * u64_stats_fetch_retry_irq. But first, make sure our ring is
+        * non-null before attempting to access its syncp.
+        */
+#ifdef HAVE_NDO_GET_STATS64
+       do {
+               start = !rx_ring ? 0 :
+                       u64_stats_fetch_begin_irq(&rx_ring->syncp);
+#endif
+       for (i = 0; i < xdp_size; i++) {
+               i40e_add_one_ethtool_stat(&(*data)[i], rx_ring,
+                                         &xdp_stats[i]);
+       }
+#ifdef HAVE_NDO_GET_STATS64
+       } while (rx_ring && u64_stats_fetch_retry_irq(&rx_ring->syncp, start));
+#endif
+
+       /* Once we successfully copy the stats in, update the data pointer */
+       *data += xdp_size;
+}
+#endif
+
+/**
+ * __i40e_add_stat_strings - copy stat strings into ethtool buffer
+ * @p: ethtool supplied buffer
+ * @stats: stat definitions array
+ * @size: size of the stats array
+ *
+ * Format and copy the strings described by stats into the buffer pointed at
+ * by p.
+ **/
+static void __i40e_add_stat_strings(u8 **p, const struct i40e_stats stats[],
+                                   const unsigned int size, ...)
+{
+       unsigned int i;
+
+       for (i = 0; i < size; i++) {
+               va_list args;
+
+               va_start(args, size);
+               vsnprintf(*p, ETH_GSTRING_LEN, stats[i].stat_string, args);
+               *p += ETH_GSTRING_LEN;
+               va_end(args);
+       }
+}
+
+/**
+ * 40e_add_stat_strings - copy stat strings into ethtool buffer
+ * @p: ethtool supplied buffer
+ * @stats: stat definitions array
+ *
+ * Format and copy the strings described by the const static stats value into
+ * the buffer pointed at by p.
+ *
+ * The parameter @stats is evaluated twice, so parameters with side effects
+ * should be avoided. Additionally, stats must be an array such that
+ * ARRAY_SIZE can be called on it.
+ **/
+#define i40e_add_stat_strings(p, stats, ...) \
+       __i40e_add_stat_strings(p, stats, ARRAY_SIZE(stats), ## __VA_ARGS__)
diff --git a/i40e-dkms/i40e-2.7.29/src/i40e_filters.c b/i40e-dkms/i40e-2.7.29/src/i40e_filters.c
new file mode 100644 (file)
index 0000000..ba02c68
--- /dev/null
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#include "i40e_filters.h"
+
+/**
+ * __i40e_del_filter - Remove a specific filter from the VSI
+ * @vsi: VSI to remove from
+ * @f: the filter to remove from the list
+ *
+ * This function should be called instead of i40e_del_filter only if you know
+ * the exact filter you will remove already, such as via i40e_find_filter or
+ * i40e_find_mac.
+ *
+ * NOTE: This function is expected to be called with mac_filter_hash_lock
+ * being held.
+ * ANOTHER NOTE: This function MUST be called from within the context of
+ * the "safe" variants of any list iterators, e.g. list_for_each_entry_safe()
+ * instead of list_for_each_entry().
+ **/
+void __i40e_del_filter(struct i40e_vsi *vsi, struct i40e_mac_filter *f)
+{
+       if (!f)
+               return;
+
+       /* If the filter was never added to firmware then we can just delete it
+        * directly and we don't want to set the status to remove or else an
+        * admin queue command will unnecessarily fire.
+        */
+       if (f->state == I40E_FILTER_FAILED || f->state == I40E_FILTER_NEW) {
+               hash_del(&f->hlist);
+               kfree(f);
+       } else {
+               f->state = I40E_FILTER_REMOVE;
+       }
+
+       vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
+       set_bit(__I40E_MACVLAN_SYNC_PENDING, vsi->back->state);
+}
+
diff --git a/i40e-dkms/i40e-2.7.29/src/i40e_filters.h b/i40e-dkms/i40e-2.7.29/src/i40e_filters.h
new file mode 100644 (file)
index 0000000..3141404
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#ifndef _I40E_FILTERS_H_
+#define _I40E_FILTERS_H_
+
+#include "i40e.h"
+
+void __i40e_del_filter(struct i40e_vsi *vsi, struct i40e_mac_filter *f);
+
+#endif /* _I40E_FILTERS_H_ */
similarity index 75%
rename from i40e-dkms/i40e-2.4.6/src/i40e_helper.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_helper.h
index 7521ef8bc606c8df3b7da2e59780808f94b817ad..4405c801b17bf3c6d3292982fe52fbc2efae1292 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_HELPER_H_
 #define _I40E_HELPER_H_
similarity index 90%
rename from i40e-dkms/i40e-2.4.6/src/i40e_hmc.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_hmc.c
index 62af2a5b97fa645434de20422b8365dd010c1e15..171629c22fe65dc065f77564c88f8204118f7ea3 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #include "i40e_osdep.h"
 #include "i40e_register.h"
@@ -202,7 +182,6 @@ exit:
  * @hw: pointer to our HW structure
  * @hmc_info: pointer to the HMC configuration information structure
  * @idx: the page index
- * @is_pf: distinguishes a VF from a PF
  *
  * This function:
  *     1. Marks the entry in pd tabe (for paged address mode) or in sd table
similarity index 87%
rename from i40e-dkms/i40e-2.4.6/src/i40e_hmc.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_hmc.h
index 1f8fc854341e82a35f8d129305c5ed1a569da268..1c78de838857be788669cc6873984d0ac1cd49d5 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_HMC_H_
 #define _I40E_HMC_H_
similarity index 96%
rename from i40e-dkms/i40e-2.4.6/src/i40e_lan_hmc.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_lan_hmc.c
index 14457189ac79baff1ab2ebc32a9b3210fc2678ae..342e86da52692e2189f97f8f223f0e2c5646c1f8 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #include "i40e_osdep.h"
 #include "i40e_register.h"
@@ -133,7 +113,7 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
                ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
                hw_dbg(hw, "i40e_init_lan_hmc: Tx context: asks for 0x%x but max allowed is 0x%x, returns error %d\n",
                          txq_num, obj->max_cnt, ret_code);
-               goto init_lan_hmc_out;
+               goto free_hmc_out;
        }
 
        /* aggregate values into the full LAN object for later */
@@ -156,7 +136,7 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
                ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
                hw_dbg(hw, "i40e_init_lan_hmc: Rx context: asks for 0x%x but max allowed is 0x%x, returns error %d\n",
                          rxq_num, obj->max_cnt, ret_code);
-               goto init_lan_hmc_out;
+               goto free_hmc_out;
        }
 
        /* aggregate values into the full LAN object for later */
@@ -179,7 +159,7 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
                ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
                hw_dbg(hw, "i40e_init_lan_hmc: FCoE context: asks for 0x%x but max allowed is 0x%x, returns error %d\n",
                          fcoe_cntx_num, obj->max_cnt, ret_code);
-               goto init_lan_hmc_out;
+               goto free_hmc_out;
        }
 
        /* aggregate values into the full LAN object for later */
@@ -202,7 +182,7 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
                ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
                hw_dbg(hw, "i40e_init_lan_hmc: FCoE filter: asks for 0x%x but max allowed is 0x%x, returns error %d\n",
                          fcoe_filt_num, obj->max_cnt, ret_code);
-               goto init_lan_hmc_out;
+               goto free_hmc_out;
        }
 
        /* aggregate values into the full LAN object for later */
@@ -223,7 +203,7 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
                                          (sizeof(struct i40e_hmc_sd_entry) *
                                          hw->hmc.sd_table.sd_cnt));
                if (ret_code)
-                       goto init_lan_hmc_out;
+                       goto free_hmc_out;
                hw->hmc.sd_table.sd_entry =
                        (struct i40e_hmc_sd_entry *)hw->hmc.sd_table.addr.va;
        }
@@ -231,6 +211,11 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
        full_obj->size = l2fpm_size;
 
 init_lan_hmc_out:
+       return ret_code;
+free_hmc_out:
+       if (hw->hmc.hmc_obj_virt_mem.va)
+               i40e_free_virt_mem(hw, &hw->hmc.hmc_obj_virt_mem);
+
        return ret_code;
 }
 
similarity index 80%
rename from i40e-dkms/i40e-2.4.6/src/i40e_lan_hmc.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_lan_hmc.h
index a087cac7f7b21ed8c1bd0a6dfc18e3e72f453740..c46a2c449e60e6ced95eb9894dedc0c8130dd59a 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_LAN_HMC_H_
 #define _I40E_LAN_HMC_H_
similarity index 79%
rename from i40e-dkms/i40e-2.4.6/src/i40e_main.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_main.c
index ae669c3fa761eb0f6be215fb3687e30de3028cfe..1914934ebe67b9276799653a61ae6b88128b6e1e 100644 (file)
@@ -1,26 +1,9 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
+#ifdef HAVE_XDP_SUPPORT
+#include <linux/bpf.h>
+#endif
 /* Local includes */
 #include "i40e.h"
 #include "i40e_helper.h"
@@ -59,8 +42,8 @@ static const char i40e_driver_string[] =
 #define DRV_VERSION_DESC ""
 
 #define DRV_VERSION_MAJOR 2
-#define DRV_VERSION_MINOR 4
-#define DRV_VERSION_BUILD 6
+#define DRV_VERSION_MINOR 7
+#define DRV_VERSION_BUILD 29
 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
        __stringify(DRV_VERSION_MINOR) "." \
        __stringify(DRV_VERSION_BUILD) \
@@ -81,8 +64,15 @@ static void i40e_clear_rss_config_user(struct i40e_vsi *vsi);
 static void i40e_prep_for_reset(struct i40e_pf *pf, bool lock_acquired);
 static int i40e_reset(struct i40e_pf *pf);
 static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired);
+static int i40e_setup_misc_vector_for_recovery_mode(struct i40e_pf *pf);
+static int i40e_restore_interrupt_scheme(struct i40e_pf *pf);
+static bool i40e_check_recovery_mode(struct i40e_pf *pf);
+static int i40e_init_recovery_mode(struct i40e_pf *pf, struct i40e_hw *hw);
+static i40e_status i40e_force_link_state(struct i40e_pf *pf, bool is_up);
 static void i40e_fdir_sb_setup(struct i40e_pf *pf);
 static int i40e_veb_get_bw_info(struct i40e_veb *veb);
+static int i40e_get_capabilities(struct i40e_pf *pf,
+                                enum i40e_admin_queue_opc list_type);
 /* i40e_pci_tbl - PCI Device ID Table
  *
  * Last entry must be all 0s
@@ -100,6 +90,7 @@ static const struct pci_device_id i40e_pci_tbl[] = {
        {PCI_VDEVICE(INTEL, I40E_DEV_ID_QSFP_C), 0},
        {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T), 0},
        {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T4), 0},
+       {PCI_VDEVICE(INTEL, I40E_DEV_ID_10G_BASE_T_BC), 0},
        {PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2), 0},
        {PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2_A), 0},
        {PCI_VDEVICE(INTEL, I40E_DEV_ID_KX_X722), 0},
@@ -162,8 +153,8 @@ static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
 
        if (!pile || needed == 0 || id >= I40E_PILE_VALID_BIT) {
                dev_info(&pf->pdev->dev,
-                        "param err: pile=%p needed=%d id=0x%04x\n",
-                        pile, needed, id);
+                        "param err: pile=%s needed=%d id=0x%04x\n",
+                        pile ? "<valid>" : "<null>", needed, id);
                return -EINVAL;
        }
 
@@ -230,8 +221,8 @@ static int i40e_put_lump(struct i40e_lump_tracking *pile, u16 index, u16 id)
 
 /**
  * i40e_find_vsi_from_id - searches for the vsi with the given id
- * @pf - the pf structure to search for the vsi
- * @id - id of the vsi it is searching for
+ * @pf: the pf structure to search for the vsi
+ * @id: id of the vsi it is searching for
  **/
 struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id)
 {
@@ -246,8 +237,8 @@ struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id)
 
 /**
  * i40e_find_vsi_from_seid - searches for the vsi with the given seid
- * @pf - the pf structure to search for the vsi
- * @seid - seid of the vsi it is searching for
+ * @pf: the pf structure to search for the vsi
+ * @seid: seid of the vsi it is searching for
  **/
 struct i40e_vsi *i40e_find_vsi_from_seid(struct i40e_pf *pf, u16 seid)
 {
@@ -268,8 +259,9 @@ struct i40e_vsi *i40e_find_vsi_from_seid(struct i40e_pf *pf, u16 seid)
  **/
 void i40e_service_event_schedule(struct i40e_pf *pf)
 {
-       if (!test_bit(__I40E_DOWN, pf->state) &&
-           !test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
+       if ((!test_bit(__I40E_DOWN, pf->state) &&
+            !test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state)) ||
+             test_bit(__I40E_RECOVERY_MODE, pf->state))
                queue_work(i40e_wq, &pf->service_task);
 }
 
@@ -403,14 +395,36 @@ struct net_device_stats *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi)
 }
 #endif
 
+#ifdef HAVE_NDO_GET_STATS64
+/**
+ * i40e_get_netdev_stats_struct_tx - populate stats from a Tx ring
+ * @ring: Tx ring to get statistics from
+ * @stats: statistics entry to be updated
+ **/
+static void i40e_get_netdev_stats_struct_tx(struct i40e_ring *ring,
+                                           struct rtnl_link_stats64 *stats)
+{
+       u64 bytes, packets;
+       unsigned int start;
+
+       do {
+               start = u64_stats_fetch_begin_irq(&ring->syncp);
+               packets = ring->stats.packets;
+               bytes   = ring->stats.bytes;
+       } while (u64_stats_fetch_retry_irq(&ring->syncp, start));
+
+       stats->tx_packets += packets;
+       stats->tx_bytes   += bytes;
+}
+
 /**
  * i40e_get_netdev_stats_struct - Get statistics for netdev interface
  * @netdev: network interface device structure
+ * @stats: data structure to store statistics
  *
  * Returns the address of the device statistics structure.
  * The statistics are actually updated from the service task.
  **/
-#ifdef HAVE_NDO_GET_STATS64
 #ifdef HAVE_VOID_NDO_GET_STATS64
 static void i40e_get_netdev_stats_struct(struct net_device *netdev,
                                         struct rtnl_link_stats64 *stats)
@@ -449,14 +463,7 @@ static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct(
                if (!tx_ring)
                        continue;
 
-               do {
-                       start = u64_stats_fetch_begin_irq(&tx_ring->syncp);
-                       packets = tx_ring->stats.packets;
-                       bytes   = tx_ring->stats.bytes;
-               } while (u64_stats_fetch_retry_irq(&tx_ring->syncp, start));
-
-               stats->tx_packets += packets;
-               stats->tx_bytes   += bytes;
+               i40e_get_netdev_stats_struct_tx(tx_ring, stats);
                rx_ring = &tx_ring[1];
 
                do {
@@ -467,6 +474,9 @@ static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct(
 
                stats->rx_packets += packets;
                stats->rx_bytes   += bytes;
+
+               if (i40e_enabled_xdp_vsi(vsi))
+                       i40e_get_netdev_stats_struct_tx(&rx_ring[1], stats);
        }
        rcu_read_unlock();
 
@@ -521,6 +531,10 @@ void i40e_vsi_reset_stats(struct i40e_vsi *vsi)
                               sizeof(vsi->rx_rings[i]->stats));
                        memset(&vsi->rx_rings[i]->rx_stats, 0,
                               sizeof(vsi->rx_rings[i]->rx_stats));
+#ifdef HAVE_XDP_SUPPORT
+                       memset(&vsi->rx_rings[i]->xdp_stats, 0,
+                              sizeof(vsi->rx_rings[i]->xdp_stats));
+#endif
                        memset(&vsi->tx_rings[i]->stats, 0,
                               sizeof(vsi->tx_rings[i]->stats));
                        memset(&vsi->tx_rings[i]->tx_stats, 0,
@@ -1121,13 +1135,13 @@ static void i40e_update_pf_stats(struct i40e_pf *pf)
                           &osd->rx_lpi_count, &nsd->rx_lpi_count);
 
        if (pf->flags & I40E_FLAG_FD_SB_ENABLED &&
-           !(pf->flags & I40E_FLAG_FD_SB_AUTO_DISABLED))
+           !test_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state))
                nsd->fd_sb_status = true;
        else
                nsd->fd_sb_status = false;
 
        if (pf->flags & I40E_FLAG_FD_ATR_ENABLED &&
-           !(pf->flags & I40E_FLAG_FD_ATR_AUTO_DISABLED))
+           !test_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state))
                nsd->fd_atr_status = true;
        else
                nsd->fd_atr_status = false;
@@ -1413,14 +1427,7 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
 
                ether_addr_copy(f->macaddr, macaddr);
                f->vlan = vlan;
-               /* If we're in overflow promisc mode, set the state directly
-                * to failed, so we don't bother to try sending the filter
-                * to the hardware.
-                */
-               if (test_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state))
-                       f->state = I40E_FILTER_FAILED;
-               else
-                       f->state = I40E_FILTER_NEW;
+               f->state = I40E_FILTER_NEW;
 
                INIT_HLIST_NODE(&f->hlist);
 
@@ -1428,7 +1435,7 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
                hash_add(vsi->mac_filter_hash, &f->hlist, key);
 
                vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
-               vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
+               set_bit(__I40E_MACVLAN_SYNC_PENDING, vsi->back->state);
        }
 
        /* If we're asked to add a filter that has been marked for removal, it
@@ -1445,42 +1452,6 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
        return f;
 }
 
-/**
- * __i40e_del_filter - Remove a specific filter from the VSI
- * @vsi: VSI to remove from
- * @f: the filter to remove from the list
- *
- * This function should be called instead of i40e_del_filter only if you know
- * the exact filter you will remove already, such as via i40e_find_filter or
- * i40e_find_mac.
- *
- * NOTE: This function is expected to be called with mac_filter_hash_lock
- * being held.
- * ANOTHER NOTE: This function MUST be called from within the context of
- * the "safe" variants of any list iterators, e.g. list_for_each_entry_safe()
- * instead of list_for_each_entry().
- **/
-void __i40e_del_filter(struct i40e_vsi *vsi, struct i40e_mac_filter *f)
-{
-       if (!f)
-               return;
-
-       /* If the filter was never added to firmware then we can just delete it
-        * directly and we don't want to set the status to remove or else an
-        * admin queue command will unnecessarily fire.
-        */
-       if ((f->state == I40E_FILTER_FAILED) ||
-           (f->state == I40E_FILTER_NEW)) {
-               hash_del(&f->hlist);
-               kfree(f);
-       } else {
-               f->state = I40E_FILTER_REMOVE;
-       }
-
-       vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
-       vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
-}
-
 /**
  * i40e_del_filter - Remove a mac/vlan filter from the VSI
  * @vsi: the VSI to be searched
@@ -1595,8 +1566,8 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
                return 0;
        }
 
-       if (test_bit(__I40E_DOWN, vsi->back->state) ||
-           test_bit(__I40E_RESET_RECOVERY_PENDING, vsi->back->state))
+       if (test_bit(__I40E_DOWN, pf->state) ||
+           test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
                return -EADDRNOTAVAIL;
 
        if (ether_addr_equal(hw->mac.addr, addr->sa_data))
@@ -1605,16 +1576,22 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
        else
                netdev_info(netdev, "set new mac address %pM\n", addr->sa_data);
 
+       /* Copy the address first, so that we avoid a possible race with
+        * .set_rx_mode(). If we copy after changing the address in the filter
+        * list, we might open ourselves to a narrow race window where
+        * .set_rx_mode could delete our dev_addr filter and prevent traffic
+        * from passing.
+        */
+       ether_addr_copy(netdev->dev_addr, addr->sa_data);
+
        spin_lock_bh(&vsi->mac_filter_hash_lock);
        i40e_del_mac_filter(vsi, netdev->dev_addr);
        i40e_add_mac_filter(vsi, addr->sa_data);
        spin_unlock_bh(&vsi->mac_filter_hash_lock);
-       ether_addr_copy(netdev->dev_addr, addr->sa_data);
        if (vsi->type == I40E_VSI_MAIN) {
                i40e_status ret;
 
-               ret = i40e_aq_mac_address_write(&vsi->back->hw,
-                                               I40E_AQC_WRITE_TYPE_LAA_WOL,
+               ret = i40e_aq_mac_address_write(hw, I40E_AQC_WRITE_TYPE_LAA_WOL,
                                                addr->sa_data, NULL);
                if (ret)
                        netdev_info(netdev, "Ignoring error from firmware on LAA update, status %s, AQ ret %s\n",
@@ -1625,9 +1602,177 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
        /* schedule our worker thread which will take care of
         * applying the new filter changes
         */
-       i40e_service_event_schedule(vsi->back);
+       i40e_service_event_schedule(pf);
+       return 0;
+}
+
+/**
+ * i40e_config_rss_aq - Prepare for RSS using AQ commands
+ * @vsi: vsi structure
+ * @seed: RSS hash seed
+ * @lut: Buffer to store the lookup table entries
+ * @lut_size: Size of buffer to store the lookup table entries
+ **/
+static int i40e_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
+                             u8 *lut, u16 lut_size)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       int ret = 0;
+
+       if (seed) {
+               struct i40e_aqc_get_set_rss_key_data *seed_dw =
+                       (struct i40e_aqc_get_set_rss_key_data *)seed;
+               ret = i40e_aq_set_rss_key(hw, vsi->id, seed_dw);
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "Cannot set RSS key, err %s aq_err %s\n",
+                                i40e_stat_str(hw, ret),
+                                i40e_aq_str(hw, hw->aq.asq_last_status));
+                       return ret;
+               }
+       }
+       if (lut) {
+               bool pf_lut = vsi->type == I40E_VSI_MAIN ? true : false;
+
+               ret = i40e_aq_set_rss_lut(hw, vsi->id, pf_lut, lut, lut_size);
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "Cannot set RSS lut, err %s aq_err %s\n",
+                                i40e_stat_str(hw, ret),
+                                i40e_aq_str(hw, hw->aq.asq_last_status));
+                       return ret;
+               }
+       }
+       return ret;
+}
+
+/**
+ * i40e_vsi_config_rss - Prepare for VSI(VMDq) RSS if used
+ * @vsi: VSI structure
+ **/
+static int i40e_vsi_config_rss(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+       u8 seed[I40E_HKEY_ARRAY_SIZE];
+       u8 *lut;
+       int ret;
+
+       if (!(pf->hw_features & I40E_HW_RSS_AQ_CAPABLE))
+               return 0;
+       if (!vsi->rss_size)
+               vsi->rss_size = min_t(int, pf->alloc_rss_size,
+                                     vsi->num_queue_pairs);
+       if (!vsi->rss_size)
+               return -EINVAL;
+       lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
+       if (!lut)
+               return -ENOMEM;
+
+       /* Use the user configured hash keys and lookup table if there is one,
+        * otherwise use default
+        */
+       if (vsi->rss_lut_user)
+               memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size);
+       else
+               i40e_fill_rss_lut(pf, lut, vsi->rss_table_size, vsi->rss_size);
+       if (vsi->rss_hkey_user)
+               memcpy(seed, vsi->rss_hkey_user, I40E_HKEY_ARRAY_SIZE);
+       else
+               netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
+       ret = i40e_config_rss_aq(vsi, seed, lut, vsi->rss_table_size);
+       kfree(lut);
+       return ret;
+}
+
+#ifdef __TC_MQPRIO_MODE_MAX
+/**
+ * i40e_vsi_setup_queue_map_mqprio - Prepares mqprio based tc_config
+ * @vsi: the VSI being configured,
+ * @ctxt: VSI context structure
+ * @enabled_tc: number of traffic classes to enable
+ *
+ * Prepares VSI tc_config to have queue configurations based on MQPRIO options.
+ **/
+static int i40e_vsi_setup_queue_map_mqprio(struct i40e_vsi *vsi,
+                                          struct i40e_vsi_context *ctxt,
+                                          u8 enabled_tc)
+{
+       u16 qcount = 0, max_qcount, qmap, sections = 0;
+       int i, override_q, pow, num_qps, ret;
+       u8 netdev_tc = 0, offset = 0;
+
+       if (vsi->type != I40E_VSI_MAIN)
+               return -EINVAL;
+       sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
+       sections |= I40E_AQ_VSI_PROP_SCHED_VALID;
+       vsi->tc_config.numtc = vsi->mqprio_qopt.qopt.num_tc;
+       vsi->tc_config.enabled_tc = enabled_tc ? enabled_tc : 1;
+       num_qps = vsi->mqprio_qopt.qopt.count[0];
+
+       /* find the next higher power-of-2 of num queue pairs */
+       pow = ilog2(num_qps);
+       if (!is_power_of_2(num_qps))
+               pow++;
+       qmap = (offset << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
+               (pow << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT);
+
+       /* Setup queue offset/count for all TCs for given VSI */
+       max_qcount = vsi->mqprio_qopt.qopt.count[0];
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               /* See if the given TC is enabled for the given VSI */
+               if (vsi->tc_config.enabled_tc & BIT(i)) {
+                       offset = vsi->mqprio_qopt.qopt.offset[i];
+                       qcount = vsi->mqprio_qopt.qopt.count[i];
+                       if (qcount > max_qcount)
+                               max_qcount = qcount;
+                       vsi->tc_config.tc_info[i].qoffset = offset;
+                       vsi->tc_config.tc_info[i].qcount = qcount;
+                       vsi->tc_config.tc_info[i].netdev_tc = netdev_tc++;
+               } else {
+                       /* TC is not enabled so set the offset to
+                        * default queue and allocate one queue
+                        * for the given TC.
+                        */
+                       vsi->tc_config.tc_info[i].qoffset = 0;
+                       vsi->tc_config.tc_info[i].qcount = 1;
+                       vsi->tc_config.tc_info[i].netdev_tc = 0;
+               }
+       }
+
+       /* Set actual Tx/Rx queue pairs */
+       vsi->num_queue_pairs = offset + qcount;
+
+       /* Setup queue TC[0].qmap for given VSI context */
+       ctxt->info.tc_mapping[0] = cpu_to_le16(qmap);
+       ctxt->info.mapping_flags |= cpu_to_le16(I40E_AQ_VSI_QUE_MAP_CONTIG);
+       ctxt->info.queue_mapping[0] = cpu_to_le16(vsi->base_queue);
+       ctxt->info.valid_sections |= cpu_to_le16(sections);
+
+       /* Reconfigure RSS for main VSI with max queue count */
+       vsi->rss_size = max_qcount;
+       ret = i40e_vsi_config_rss(vsi);
+       if (ret) {
+               dev_info(&vsi->back->pdev->dev,
+                        "Failed to reconfig rss for num_queues (%u)\n",
+                        max_qcount);
+               return ret;
+       }
+       vsi->reconfig_rss = true;
+       dev_dbg(&vsi->back->pdev->dev,
+               "Reconfigured rss with num_queues (%u)\n", max_qcount);
+
+       /* Find queue count available for channel VSIs and starting offset
+        * for channel VSIs
+        */
+       override_q = vsi->mqprio_qopt.qopt.count[0];
+       if (override_q && override_q < vsi->num_queue_pairs) {
+               vsi->cnt_q_avail = vsi->num_queue_pairs - override_q;
+               vsi->next_base_queue = override_q;
+       }
        return 0;
 }
+#endif
 
 /**
  * i40e_vsi_setup_queue_map - Setup a VSI queue map based on enabled_tc
@@ -1646,8 +1791,8 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
        struct i40e_pf *pf = vsi->back;
        u16 sections = 0;
        u8 netdev_tc = 0;
-       u16 numtc = 0;
-       u16 qcount;
+       u16 qcount = 0;
+       u16 numtc = 1;
        u8 offset;
        u16 qmap;
        int i;
@@ -1656,9 +1801,11 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
        sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
        offset = 0;
 
+       /* Number of queues per enabled TC */
+       num_tc_qps = vsi->alloc_queue_pairs;
        if (enabled_tc && (vsi->back->flags & I40E_FLAG_DCB_ENABLED)) {
                /* Find numtc from enabled TC bitmap */
-               for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               for (i = 0, numtc = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
                        if (enabled_tc & BIT(i)) /* TC is enabled */
                                numtc++;
                }
@@ -1666,18 +1813,13 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
                        dev_warn(&pf->pdev->dev, "DCB is enabled but no TC enabled, forcing TC0\n");
                        numtc = 1;
                }
-       } else {
-               /* At least TC0 is enabled in case of non-DCB case */
-               numtc = 1;
+               num_tc_qps = num_tc_qps / numtc;
+               num_tc_qps = min_t(int, num_tc_qps,
+                                  i40e_pf_get_max_q_per_tc(pf));
        }
 
        vsi->tc_config.numtc = numtc;
        vsi->tc_config.enabled_tc = enabled_tc ? enabled_tc : 1;
-       /* Number of queues per enabled TC */
-       qcount = vsi->alloc_queue_pairs;
-
-       num_tc_qps = qcount / numtc;
-       num_tc_qps = min_t(int, num_tc_qps, i40e_pf_get_max_q_per_tc(pf));
 
        /* Do not allow use more TC queue pairs than MSI-X vectors exist */
        if (pf->flags & I40E_FLAG_MSIX_ENABLED)
@@ -1691,9 +1833,14 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
 
                        switch (vsi->type) {
                        case I40E_VSI_MAIN:
-                               qcount = min_t(int, pf->alloc_rss_size,
-                                              num_tc_qps);
-                               break;
+                               if (!(pf->flags & (I40E_FLAG_FD_SB_ENABLED |
+                                   I40E_FLAG_FD_ATR_ENABLED)) ||
+                                   vsi->tc_config.enabled_tc != 1) {
+                                       qcount = min_t(int, pf->alloc_rss_size,
+                                                      num_tc_qps);
+                                       break;
+                               }
+                               /* fall through */
                        case I40E_VSI_FDIR:
                        case I40E_VSI_SRIOV:
                        case I40E_VSI_VMDQ2:
@@ -1798,6 +1945,14 @@ static int i40e_addr_unsync(struct net_device *netdev, const u8 *addr)
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
 
+       /* Under some circumstances, we might receive a request to delete
+        * our own device address from our uc list. Because we store the
+        * device address in the VSI's MAC/VLAN filter list, we need to ignore
+        * such requests and not delete our device address from this list.
+        */
+       if (ether_addr_equal(addr, netdev->dev_addr))
+               return 0;
+
        i40e_del_mac_filter(vsi, addr);
 
        return 0;
@@ -1822,7 +1977,7 @@ static void i40e_set_rx_mode(struct net_device *netdev)
        /* check for other flag changes */
        if (vsi->current_netdev_flags != vsi->netdev->flags) {
                vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
-               vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
+               set_bit(__I40E_MACVLAN_SYNC_PENDING, vsi->back->state);
        }
 
        /* schedule our worker thread which will take care of
@@ -1899,7 +2054,7 @@ struct i40e_new_mac_filter *i40e_next_filter(struct i40e_new_mac_filter *next)
  * from firmware
  * @count: Number of filters added
  * @add_list: return data from fw
- * @head: pointer to first filter in current batch
+ * @add_head: pointer to first filter in current batch
  *
  * MAC filter entries from list were slated to be added to device. Returns
  * number of successful filters. Note that 0 does NOT mean success!
@@ -1976,17 +2131,16 @@ void i40e_aqc_del_filters(struct i40e_vsi *vsi, const char *vsi_name,
  * @list: the list of filters to send to firmware
  * @add_head: Position in the add hlist
  * @num_add: the number of filters to add
- * @promisc_change: set to true on exit if promiscuous mode was forced on
  *
  * Send a request to firmware via AdminQ to add a chunk of filters. Will set
- * promisc_changed to true if the firmware has run out of space for more
- * filters.
+ * __I40E_VSI_OVERFLOW_PROMISC bit in vsi->state if the firmware has run out of
+ * space for more filters.
  */
 static
 void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name,
                          struct i40e_aqc_add_macvlan_element_data *list,
                          struct i40e_new_mac_filter *add_head,
-                         int num_add, bool *promisc_changed)
+                         int num_add)
 {
        struct i40e_hw *hw = &vsi->back->hw;
        int aq_err, fcnt;
@@ -1996,7 +2150,6 @@ void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name,
        fcnt = i40e_update_filter_state(num_add, list, add_head);
 
        if (fcnt != num_add) {
-               *promisc_changed = true;
                set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
                dev_warn(&vsi->back->pdev->dev,
                         "Error %s adding RX filters on %s, promiscuous mode forced on\n",
@@ -2008,6 +2161,7 @@ void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name,
 /**
  * i40e_aqc_broadcast_filter - Set promiscuous broadcast flags
  * @vsi: pointer to the VSI
+ * @vsi_name: the VSI name
  * @f: filter data
  *
  * This function sets or clears the promiscuous broadcast flags for VLAN
@@ -2037,11 +2191,13 @@ i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name,
                                                            NULL);
        }
 
-       if (aq_ret)
+       if (aq_ret) {
+               set_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
                dev_warn(&vsi->back->pdev->dev,
-                        "Error %s setting broadcast promiscuous mode on %s\n",
+                        "Error %s, forcing overflow promiscuous on %s\n",
                         i40e_aq_str(hw, hw->aq.asq_last_status),
                         vsi_name);
+       }
 
        return aq_ret;
 }
@@ -2127,9 +2283,9 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
        struct i40e_mac_filter *f;
        struct i40e_new_mac_filter *new, *add_head = NULL;
        struct i40e_hw *hw = &vsi->back->hw;
+       bool old_overflow, new_overflow;
        unsigned int failed_filters = 0;
        unsigned int vlan_filters = 0;
-       bool promisc_changed = false;
        char vsi_name[16] = "PF";
        int filter_list_len = 0;
        i40e_status aq_ret = 0;
@@ -2151,6 +2307,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                usleep_range(1000, 2000);
        pf = vsi->back;
 
+       old_overflow = test_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
+
        if (vsi->netdev) {
                changed_flags = vsi->current_netdev_flags ^ vsi->netdev->flags;
                vsi->current_netdev_flags = vsi->netdev->flags;
@@ -2283,12 +2441,6 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 
                num_add = 0;
                hlist_for_each_entry_safe(new, h, &tmp_add_list, hlist) {
-                       if (test_bit(__I40E_VSI_OVERFLOW_PROMISC,
-                                    vsi->state)) {
-                               new->state = I40E_FILTER_FAILED;
-                               continue;
-                       }
-
                        /* handle broadcast filters by updating the broadcast
                         * promiscuous flag instead of adding a MAC filter.
                         */
@@ -2324,15 +2476,14 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                        /* flush a full buffer */
                        if (num_add == filter_list_len) {
                                i40e_aqc_add_filters(vsi, vsi_name, add_list,
-                                                    add_head, num_add,
-                                                    &promisc_changed);
+                                                    add_head, num_add);
                                memset(add_list, 0, list_size);
                                num_add = 0;
                        }
                }
                if (num_add) {
                        i40e_aqc_add_filters(vsi, vsi_name, add_list, add_head,
-                                            num_add, &promisc_changed);
+                                            num_add);
                }
                /* Now move all of the filters from the temp add list back to
                 * the VSI's list.
@@ -2361,24 +2512,16 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
        }
        spin_unlock_bh(&vsi->mac_filter_hash_lock);
 
-       /* If promiscuous mode has changed, we need to calculate a new
-        * threshold for when we are safe to exit
-        */
-       if (promisc_changed)
-               vsi->promisc_threshold = (vsi->active_filters * 3) / 4;
-
        /* Check if we are able to exit overflow promiscuous mode. We can
         * safely exit if we didn't just enter, we no longer have any failed
         * filters, and we have reduced filters below the threshold value.
         */
-       if (test_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state) &&
-           !promisc_changed && !failed_filters &&
-           (vsi->active_filters < vsi->promisc_threshold)) {
+       if (old_overflow && !failed_filters &&
+           vsi->active_filters < vsi->promisc_threshold) {
                dev_info(&pf->pdev->dev,
                         "filter logjam cleared on %s, leaving overflow promiscuous mode\n",
                         vsi_name);
                clear_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
-               promisc_changed = true;
                vsi->promisc_threshold = 0;
        }
        /* if the VF is not trusted do not do promisc */
@@ -2387,6 +2530,14 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                goto out;
        }
 
+       new_overflow = test_bit(__I40E_VSI_OVERFLOW_PROMISC, vsi->state);
+
+       /* If we are entering overflow promiscuous, we need to calculate a new
+        * threshold for when we are safe to exit
+        */
+       if (!old_overflow && new_overflow)
+               vsi->promisc_threshold = (vsi->active_filters * 3) / 4;
+
        /* check for changes in promiscuous modes */
        if (changed_flags & IFF_ALLMULTI) {
                bool cur_multipromisc;
@@ -2407,12 +2558,11 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                }
        }
 
-       if ((changed_flags & IFF_PROMISC) || promisc_changed) {
+       if ((changed_flags & IFF_PROMISC) || old_overflow != new_overflow) {
                bool cur_promisc;
 
                cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) ||
-                              test_bit(__I40E_VSI_OVERFLOW_PROMISC,
-                                       vsi->state));
+                              new_overflow);
                aq_ret = i40e_set_promiscuous(pf, cur_promisc);
                if (aq_ret) {
                        retval = i40e_aq_rc_to_posix(aq_ret,
@@ -2455,10 +2605,11 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf)
 {
        int v;
 
-       if (!pf || !(pf->flags & I40E_FLAG_FILTER_SYNC))
+       if (!pf)
                return;
 
-       pf->flags &= ~I40E_FLAG_FILTER_SYNC;
+       if (!test_and_clear_bit(__I40E_MACVLAN_SYNC_PENDING, pf->state))
+               return;
 
        for (v = 0; v < pf->num_alloc_vsi; v++) {
                if (pf->vsi[v] &&
@@ -2466,13 +2617,26 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf)
                        int ret = i40e_sync_vsi_filters(pf->vsi[v]);
                        if (ret) {
                                /* come back and try again later */
-                               pf->flags |= I40E_FLAG_FILTER_SYNC;
+                               set_bit(__I40E_MACVLAN_SYNC_PENDING,
+                                       pf->state);
                                break;
                        }
                }
        }
 }
 
+/**
+ * i40e_max_xdp_frame_size - returns the maximum allowed frame size for XDP
+ * @vsi: the vsi
+ **/
+static int i40e_max_xdp_frame_size(struct i40e_vsi *vsi)
+{
+       if (PAGE_SIZE >= 8192 || (vsi->back->flags & I40E_FLAG_LEGACY_RX))
+               return I40E_RXBUFFER_2048;
+       else
+               return I40E_RXBUFFER_3072;
+}
+
 /**
  * i40e_change_mtu - NDO callback to change the Maximum Transfer Unit
  * @netdev: network interface device structure
@@ -2490,41 +2654,41 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu)
        /* MTU < 68 is an error and causes problems on some kernels */
        if ((new_mtu < 68) || (max_frame > I40E_MAX_RXBUFFER))
                return -EINVAL;
+
+       if (i40e_enabled_xdp_vsi(vsi)) {
+               if (max_frame > i40e_max_xdp_frame_size(vsi))
+                       return -EINVAL;
+       }
+
 #ifndef HAVE_NDO_FEATURES_CHECK
 
        /* MTU < 576 causes problems with TSO */
        if (new_mtu < 576) {
                netdev->features &= ~NETIF_F_TSO;
                netdev->features &= ~NETIF_F_TSO6;
-       } else {
 #ifdef HAVE_NDO_SET_FEATURES
+       } else {
 #ifndef HAVE_RHEL6_NET_DEVICE_OPS_EXT
-       if (netdev->wanted_features & NETIF_F_TSO)
-               netdev->features |= NETIF_F_TSO;
-       if (netdev->wanted_features & NETIF_F_TSO6)
-               netdev->features |= NETIF_F_TSO6;
+               if (netdev->wanted_features & NETIF_F_TSO)
+                       netdev->features |= NETIF_F_TSO;
+               if (netdev->wanted_features & NETIF_F_TSO6)
+                       netdev->features |= NETIF_F_TSO6;
 #else
-       if (netdev_extended(netdev)->wanted_features & NETIF_F_TSO)
-               netdev->features |= NETIF_F_TSO;
-       if (netdev_extended(netdev)->wanted_features & NETIF_F_TSO6)
-               netdev->features |= NETIF_F_TSO6;
+               if (netdev_extended(netdev)->wanted_features & NETIF_F_TSO)
+                       netdev->features |= NETIF_F_TSO;
+               if (netdev_extended(netdev)->wanted_features & NETIF_F_TSO6)
+                       netdev->features |= NETIF_F_TSO6;
 #endif /* HAVE_RHEL6_NET_DEVICE_OPS_EXT */
-#else
-               netdev->features |= NETIF_F_TSO;
-               netdev->features |= NETIF_F_TSO6;
 #endif /* HAVE_NDO_SET_FEATURES */
        }
-#else
-       netdev->features |= NETIF_F_TSO;
-       netdev->features |= NETIF_F_TSO6;
 #endif /* ! HAVE_NDO_FEATURES_CHECK */
        netdev_info(netdev, "changing MTU from %d to %d\n",
                    netdev->mtu, new_mtu);
        netdev->mtu = new_mtu;
        if (netif_running(netdev))
                i40e_vsi_reinit_locked(vsi);
-       pf->flags |= (I40E_FLAG_SERVICE_CLIENT_REQUESTED |
-                     I40E_FLAG_CLIENT_L2_CHANGE);
+       set_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state);
+       set_bit(__I40E_CLIENT_L2_CHANGE, pf->state);
        return 0;
 }
 
@@ -2626,37 +2790,19 @@ void i40e_vlan_stripping_disable(struct i40e_vsi *vsi)
  **/
 static void i40e_vlan_rx_register(struct net_device *netdev,
                                  struct vlan_group *grp)
-#else /* HAVE_VLAN_RX_REGISTER */
-/**
- * i40e_vlan_rx_register - Setup or shutdown vlan offload
- * @netdev: network interface to be adjusted
- * @features: netdev features to test if VLAN offload is enabled or not
- **/
-static void i40e_vlan_rx_register(struct net_device *netdev, u32 features)
-#endif /* HAVE_VLAN_RX_REGISTER */
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
-#ifdef HAVE_VLAN_RX_REGISTER
        bool enable;
 
        vsi->vlgrp = grp;
        enable = (grp || (vsi->back->flags & I40E_FLAG_DCB_ENABLED));
        if (enable)
                i40e_vlan_stripping_enable(vsi);
-#else /* HAVE_VLAN_RX_REGISTER */
-
-#ifdef NETIF_F_HW_VLAN_CTAG_RX
-       if (features & NETIF_F_HW_VLAN_CTAG_RX)
-               i40e_vlan_stripping_enable(vsi);
-#else
-       if (features & NETIF_F_HW_VLAN_RX)
-               i40e_vlan_stripping_enable(vsi);
-#endif
-#endif /* HAVE_VLAN_RX_REGISTER */
        else
                i40e_vlan_stripping_disable(vsi);
 }
+#endif /* HAVE_VLAN_RX_REGISTER */
 
 /**
  * i40e_add_vlan_all_mac - Add a MAC/VLAN filter for each existing MAC address
@@ -2777,6 +2923,7 @@ void i40e_vsi_kill_vlan(struct i40e_vsi *vsi, u16 vid)
 /**
  * i40e_vlan_rx_add_vid - Add a vlan id filter to HW offload
  * @netdev: network interface to be adjusted
+ * @proto: unused protocol value
  * @vid: vlan id to be added
  *
  * net_device_ops implementation for adding vlan ids
@@ -2834,34 +2981,80 @@ static void i40e_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
 }
 
 /**
- * i40e_vlan_rx_kill_vid - Remove a vlan id filter from HW offload
+ * i40e_vlan_rx_add_vid_up - Add a vlan id filter to HW offload in UP path
  * @netdev: network interface to be adjusted
- * @vid: vlan id to be removed
- *
- * net_device_ops implementation for removing vlan ids
+ * @proto: unused protocol value
+ * @vid: vlan id to be added
  **/
-#ifdef HAVE_INT_NDO_VLAN_RX_ADD_VID
 #ifdef NETIF_F_HW_VLAN_CTAG_RX
-static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
-                                __always_unused __be16 proto, u16 vid)
-#else
-static int i40e_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
-#endif
+static void i40e_vlan_rx_add_vid_up(struct net_device *netdev,
+                                   __always_unused __be16 proto, u16 vid)
 #else
-static void i40e_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+static void i40e_vlan_rx_add_vid_up(struct net_device *netdev, u16 vid)
 #endif
 {
+#if (!defined(HAVE_NETDEV_VLAN_FEATURES) || !defined(HAVE_VLAN_RX_REGISTER))
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_vsi *vsi = np->vsi;
+#endif
 
-       /* return code is ignored as there is nothing a user
-        * can do about failure to remove and a log message was
-        * already printed from the other function
-        */
-       i40e_vsi_kill_vlan(vsi, vid);
+       if (vid >= VLAN_N_VID)
+               return;
 #ifndef HAVE_VLAN_RX_REGISTER
+       set_bit(vid, vsi->active_vlans);
+#endif /* !HAVE_VLAN_RX_REGISTER */
+#ifndef HAVE_NETDEV_VLAN_FEATURES
 
-       clear_bit(vid, vsi->active_vlans);
+       /* Copy feature flags from netdev to the vlan netdev for this vid.
+        * This allows things like TSO to bubble down to our vlan device.
+        * Some vlans, such as VLAN 0 for DCB will not have a v_netdev so
+        * we will not have a netdev that needs updating.
+        */
+       if (vsi->vlgrp) {
+               struct vlan_group *vlgrp = vsi->vlgrp;
+               struct net_device *v_netdev = vlan_group_get_device(vlgrp, vid);
+
+               if (v_netdev) {
+                       v_netdev->features |= netdev->features;
+#ifdef HAVE_ENCAP_CSUM_OFFLOAD
+                       v_netdev->enc_features |= netdev->enc_features;
+#endif
+                       vlan_group_set_device(vlgrp, vid, v_netdev);
+               }
+       }
+#endif /* HAVE_NETDEV_VLAN_FEATURES */
+}
+
+/**
+ * i40e_vlan_rx_kill_vid - Remove a vlan id filter from HW offload
+ * @netdev: network interface to be adjusted
+ * @proto: unused protocol value
+ * @vid: vlan id to be removed
+ *
+ * net_device_ops implementation for removing vlan ids
+ **/
+#ifdef HAVE_INT_NDO_VLAN_RX_ADD_VID
+#ifdef NETIF_F_HW_VLAN_CTAG_RX
+static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
+                                __always_unused __be16 proto, u16 vid)
+#else
+static int i40e_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+#endif
+#else
+static void i40e_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+#endif
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+
+       /* return code is ignored as there is nothing a user
+        * can do about failure to remove and a log message was
+        * already printed from the other function
+        */
+       i40e_vsi_kill_vlan(vsi, vid);
+#ifndef HAVE_VLAN_RX_REGISTER
+
+       clear_bit(vid, vsi->active_vlans);
 #endif /* HAVE_VLAN_RX_REGISTER */
 #ifdef HAVE_INT_NDO_VLAN_RX_ADD_VID
 
@@ -2888,22 +3081,30 @@ static void i40e_restore_vlan(struct i40e_vsi *vsi)
                        if (!vlan_group_get_device(vsi->vlgrp, vid))
                                continue;
 #ifdef NETIF_F_HW_VLAN_CTAG_RX
-                       i40e_vlan_rx_add_vid(vsi->netdev, htons(ETH_P_8021Q),
-                                            vid);
+                       i40e_vlan_rx_add_vid_up(vsi->netdev, htons(ETH_P_8021Q),
+                                               vid);
 #else
-                       i40e_vlan_rx_add_vid(vsi->netdev, vid);
+                       i40e_vlan_rx_add_vid_up(vsi->netdev, vid);
 #endif
                }
        }
 #else /* HAVE_VLAN_RX_REGISTER */
-       i40e_vlan_rx_register(vsi->netdev, vsi->netdev->features);
+#ifdef NETIF_F_HW_VLAN_CTAG_RX
+       if (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
+               i40e_vlan_stripping_enable(vsi);
+#else
+       if (vsi->netdev->features & NETIF_F_HW_VLAN_RX)
+               i40e_vlan_stripping_enable(vsi);
+#endif
+       else
+               i40e_vlan_stripping_disable(vsi);
 
        for_each_set_bit(vid, vsi->active_vlans, VLAN_N_VID)
 #ifdef NETIF_F_HW_VLAN_CTAG_RX
-               i40e_vlan_rx_add_vid(vsi->netdev, htons(ETH_P_8021Q),
-                                    vid);
+               i40e_vlan_rx_add_vid_up(vsi->netdev, htons(ETH_P_8021Q),
+                                       vid);
 #else
-               i40e_vlan_rx_add_vid(vsi->netdev, vid);
+               i40e_vlan_rx_add_vid_up(vsi->netdev, vid);
 #endif
 #endif
 }
@@ -2990,73 +3191,6 @@ int i40e_get_cloud_filter_type(u8 flags, u16 *type)
        return 0;
 }
 
-/**
- * i40e_add_del_cloud_filter - Add/del cloud filter
- * @pf: pointer to the physical function struct
- * @filter: cloud filter rule
- * @add: if true, add, if false, delete
- *
- * Add or delete a cloud filter for a specific flow spec.
- * Returns 0 if the filter were successfully added.
- **/
-int i40e_add_del_cloud_filter(struct i40e_pf *pf,
-                             struct i40e_cloud_filter *filter,
-                             bool add)
-{
-       struct i40e_aqc_add_remove_cloud_filters_element_data cld_filter;
-       u32 ipaddr;
-       u16 type;
-       int ret;
-
-       ret = i40e_get_cloud_filter_type(filter->flags, &type);
-       if (ret)
-               return -EINVAL;
-
-       memset(&cld_filter, 0, sizeof(cld_filter));
-       ether_addr_copy(cld_filter.outer_mac, filter->outer_mac);
-       ether_addr_copy(cld_filter.inner_mac, filter->inner_mac);
-
-       /* the low index of data storing IP address indicate the last
-        * byte on wire.
-        */
-       ipaddr = be32_to_cpu(filter->inner_ip[0]);
-       memcpy(&cld_filter.ipaddr.v4.data, &ipaddr, 4);
-       cld_filter.inner_vlan = cpu_to_le16(ntohs(filter->inner_vlan));
-       cld_filter.tenant_id = cpu_to_le32(filter->tenant_id);
-
-       if (filter->tunnel_type != I40E_CLOUD_TNL_TYPE_NONE)
-               cld_filter.flags = cpu_to_le16(filter->tunnel_type <<
-                                            I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT);
-
-       if (filter->flags != I40E_CLOUD_FILTER_FLAGS_OMAC) {
-               cld_filter.flags |=
-                       cpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE);
-               cld_filter.queue_number = cpu_to_le16(filter->queue_id);
-       }
-
-       cld_filter.flags |= cpu_to_le16(type | I40E_AQC_ADD_CLOUD_FLAGS_IPV4);
-
-       if (add) {
-               ret = i40e_aq_add_cloud_filters(&pf->hw, filter->seid,
-                                               &cld_filter, 1);
-       } else {
-               ret = i40e_aq_remove_cloud_filters(&pf->hw, filter->seid,
-                                                  &cld_filter, 1);
-               if (ret && pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOENT) {
-                       /* ignore error on delete of non-existent filter */
-                       ret = 0;
-                       pf->hw.aq.asq_last_status = 0;
-               }
-       }
-
-       if (ret)
-               dev_err(&pf->pdev->dev,
-                       "fail to %s cloud filter, err %s aq_err %s\n",
-                       add ? "add" : "delete", i40e_stat_str(&pf->hw, ret),
-                       i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
-       return i40e_aq_rc_to_posix(ret, pf->hw.aq.asq_last_status);
-}
-
 /**
  * i40e_vsi_setup_tx_resources - Allocate VSI Tx queue resources
  * @vsi: ptr to the VSI
@@ -3074,6 +3208,11 @@ int i40e_vsi_setup_tx_resources(struct i40e_vsi *vsi)
        for (i = 0; i < vsi->num_queue_pairs && !err; i++)
                err = i40e_setup_tx_descriptors(vsi->tx_rings[i]);
 
+       if (!i40e_enabled_xdp_vsi(vsi))
+               return err;
+
+       for (i = 0; i < vsi->num_queue_pairs && !err; i++)
+               err = i40e_setup_tx_descriptors(vsi->xdp_rings[i]);
        return err;
 }
 
@@ -3087,12 +3226,17 @@ static void i40e_vsi_free_tx_resources(struct i40e_vsi *vsi)
 {
        int i;
 
-       if (!vsi->tx_rings)
-               return;
+       if (vsi->tx_rings) {
+               for (i = 0; i < vsi->num_queue_pairs; i++)
+                       if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc)
+                               i40e_free_tx_resources(vsi->tx_rings[i]);
+       }
 
-       for (i = 0; i < vsi->num_queue_pairs; i++)
-               if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc)
-                       i40e_free_tx_resources(vsi->tx_rings[i]);
+       if (vsi->xdp_rings) {
+               for (i = 0; i < vsi->num_queue_pairs; i++)
+                       if (vsi->xdp_rings[i] && vsi->xdp_rings[i]->desc)
+                               i40e_free_tx_resources(vsi->xdp_rings[i]);
+       }
 }
 
 /**
@@ -3146,7 +3290,7 @@ static void i40e_config_xps_tx_ring(struct i40e_ring *ring)
 #endif
        int cpu;
 
-       if (!ring->q_vector || !ring->netdev)
+       if (!ring->q_vector || !ring->netdev || ring->ch)
                return;
 
 #ifndef HAVE_XPS_QOS_SUPPORT
@@ -3242,7 +3386,14 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
         * initialization. This has to be done regardless of
         * DCB as by default everything is mapped to TC0.
         */
-       tx_ctx.rdylist = le16_to_cpu(vsi->info.qs_handle[ring->dcb_tc]);
+
+       if (ring->ch)
+               tx_ctx.rdylist =
+                       le16_to_cpu(ring->ch->info.qs_handle[ring->dcb_tc]);
+
+       else
+               tx_ctx.rdylist = le16_to_cpu(vsi->info.qs_handle[ring->dcb_tc]);
+
        tx_ctx.rdylist_act = 0;
 
        /* clear the context in the HMC */
@@ -3264,12 +3415,23 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
        }
 
        /* Now associate this queue with this PCI function */
-       if (vsi->type == I40E_VSI_VMDQ2) {
-               qtx_ctl = I40E_QTX_CTL_VM_QUEUE;
-               qtx_ctl |= ((vsi->id) << I40E_QTX_CTL_VFVM_INDX_SHIFT) &
-                          I40E_QTX_CTL_VFVM_INDX_MASK;
+       if (ring->ch) {
+               if (ring->ch->type == I40E_VSI_VMDQ2)
+                       qtx_ctl = I40E_QTX_CTL_VM_QUEUE;
+               else
+                       return -EINVAL;
+
+               qtx_ctl |= (ring->ch->vsi_number <<
+                           I40E_QTX_CTL_VFVM_INDX_SHIFT) &
+                           I40E_QTX_CTL_VFVM_INDX_MASK;
        } else {
-               qtx_ctl = I40E_QTX_CTL_PF_QUEUE;
+               if (vsi->type == I40E_VSI_VMDQ2) {
+                       qtx_ctl = I40E_QTX_CTL_VM_QUEUE;
+                       qtx_ctl |= ((vsi->id) << I40E_QTX_CTL_VFVM_INDX_SHIFT) &
+                                   I40E_QTX_CTL_VFVM_INDX_MASK;
+               } else {
+                       qtx_ctl = I40E_QTX_CTL_PF_QUEUE;
+               }
        }
 
        qtx_ctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) &
@@ -3380,6 +3542,12 @@ static int i40e_vsi_configure_tx(struct i40e_vsi *vsi)
        for (i = 0; (i < vsi->num_queue_pairs) && !err; i++)
                err = i40e_configure_tx_ring(vsi->tx_rings[i]);
 
+       if (!i40e_enabled_xdp_vsi(vsi))
+               return err;
+
+       for (i = 0; (i < vsi->num_queue_pairs) && !err; i++)
+               err = i40e_configure_tx_ring(vsi->xdp_rings[i]);
+
        return err;
 }
 
@@ -3446,6 +3614,7 @@ static void i40e_vsi_config_dcb_rings(struct i40e_vsi *vsi)
                        rx_ring->dcb_tc = 0;
                        tx_ring->dcb_tc = 0;
                }
+               return;
        }
 
        for (n = 0; n < I40E_MAX_TRAFFIC_CLASS; n++) {
@@ -3512,11 +3681,138 @@ static void i40e_cloud_filter_restore(struct i40e_pf *pf)
 {
        struct i40e_cloud_filter *filter;
        struct hlist_node *node;
+       struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
 
        hlist_for_each_entry_safe(filter, node,
                                  &pf->cloud_filter_list, cloud_node) {
-               i40e_add_del_cloud_filter(pf, filter, true);
+               i40e_add_del_cloud_filter(vsi, filter, true);
+       }
+}
+
+/**
+ * i40e_set_cld_element - sets cloud filter element data
+ * @filter: cloud filter rule
+ * @cld: ptr to cloud filter element data
+ *
+ * This is helper function to copy data into cloud filter element
+ **/
+static inline void
+i40e_set_cld_element(struct i40e_cloud_filter *filter,
+                    struct i40e_aqc_cloud_filters_element_data *cld)
+{
+       int i, j;
+       u32 ipa;
+
+       memset(cld, 0, sizeof(*cld));
+       ether_addr_copy(cld->outer_mac, filter->dst_mac);
+       ether_addr_copy(cld->inner_mac, filter->src_mac);
+
+       if (filter->n_proto != ETH_P_IP && filter->n_proto != ETH_P_IPV6) {
+               /* copy parameters from filter to cloud filters element
+                * which are not specific to IP protos
+                */
+               ether_addr_copy(cld->outer_mac, filter->outer_mac);
+               ether_addr_copy(cld->inner_mac, filter->inner_mac);
+               cld->inner_vlan = cpu_to_le16(ntohs(filter->inner_vlan));
+               cld->tenant_id = cpu_to_le32(filter->tenant_id);
+               return;
+       }
+
+       if (filter->n_proto == ETH_P_IPV6) {
+#define IPV6_MAX_INDEX (ARRAY_SIZE(filter->dst_ipv6) - 1)
+               for (i = 0, j = 0; i < ARRAY_SIZE(filter->dst_ipv6);
+                    i++, j += 2) {
+                       ipa = be32_to_cpu(filter->dst_ipv6[IPV6_MAX_INDEX - i]);
+                       memcpy(&cld->ipaddr.raw_v6.data[j], &ipa, sizeof(ipa));
+               }
+       } else {
+               ipa = be32_to_cpu(filter->dst_ipv4);
+               memcpy(&cld->ipaddr.v4.data, &ipa, sizeof(ipa));
+       }
+
+       cld->inner_vlan = cpu_to_le16(ntohs(filter->vlan_id));
+
+       /* tenant_id is not supported by FW now, once the support is enabled
+        * fill the cld->tenant_id with cpu_to_le32(filter->tenant_id)
+        */
+       if (filter->tenant_id)
+               return;
+}
+
+/**
+ * i40e_add_del_cloud_filter - Add/del cloud filter
+ * @vsi: pointer to VSI
+ * @filter: cloud filter rule
+ * @add: if true, add, if false, delete
+ *
+ * Add or delete a cloud filter for a specific flow spec.
+ * Returns 0 if the filter were successfully added.
+ **/
+int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
+                             struct i40e_cloud_filter *filter, bool add)
+{
+       struct i40e_aqc_cloud_filters_element_data cld_filter;
+       struct i40e_pf *pf = vsi->back;
+       int ret;
+       static const u16 flag_table[128] = {
+               [I40E_CLOUD_FILTER_FLAGS_OMAC]  =
+                       I40E_AQC_ADD_CLOUD_FILTER_OMAC,
+               [I40E_CLOUD_FILTER_FLAGS_IMAC]  =
+                       I40E_AQC_ADD_CLOUD_FILTER_IMAC,
+               [I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN]  =
+                       I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN,
+               [I40E_CLOUD_FILTER_FLAGS_IMAC_TEN_ID] =
+                       I40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID,
+               [I40E_CLOUD_FILTER_FLAGS_OMAC_TEN_ID_IMAC] =
+                       I40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC,
+               [I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN_TEN_ID] =
+                       I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID,
+               [I40E_CLOUD_FILTER_FLAGS_IIP] =
+                       I40E_AQC_ADD_CLOUD_FILTER_IIP,
+       };
+
+       if (filter->flags >= ARRAY_SIZE(flag_table))
+               return I40E_ERR_CONFIG;
+
+       /* copy element needed to add cloud filter from filter */
+       i40e_set_cld_element(filter, &cld_filter);
+
+       if (filter->tunnel_type != I40E_CLOUD_TNL_TYPE_NONE)
+               cld_filter.flags = cpu_to_le16(filter->tunnel_type <<
+                                            I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT);
+
+       /* copy queue number from filter to pass to cloud filter engine
+        * with flags for targeting traffic to specific queue
+        */
+       if (filter->flags != I40E_CLOUD_FILTER_FLAGS_OMAC) {
+               cld_filter.flags |=
+                       cpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE);
+               cld_filter.queue_number = cpu_to_le16(filter->queue_id);
        }
+
+       if (filter->n_proto == ETH_P_IPV6)
+               cld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |
+                                               I40E_AQC_ADD_CLOUD_FLAGS_IPV6);
+       else
+               cld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |
+                                               I40E_AQC_ADD_CLOUD_FLAGS_IPV4);
+
+       if (add)
+               ret = i40e_aq_add_cloud_filters(&pf->hw, filter->seid,
+                                               &cld_filter, 1);
+       else
+               ret = i40e_aq_rem_cloud_filters(&pf->hw, filter->seid,
+                                               &cld_filter, 1);
+       if (ret)
+               dev_dbg(&pf->pdev->dev,
+                       "Failed to %s cloud filter using l4 port %u, err %d aq_err %d\n",
+                       add ? "add" : "delete", filter->dst_port, ret,
+                       pf->hw.aq.asq_last_status);
+       else
+               dev_info(&pf->pdev->dev,
+                        "%s cloud filter for VSI: %d\n",
+                        add ? "Added" : "Deleted", filter->seid);
+       return ret;
 }
 
 /**
@@ -3543,6 +3839,7 @@ static int i40e_vsi_configure(struct i40e_vsi *vsi)
  **/
 static void i40e_vsi_configure_msix(struct i40e_vsi *vsi)
 {
+       bool has_xdp = i40e_enabled_xdp_vsi(vsi);
        struct i40e_pf *pf = vsi->back;
        struct i40e_hw *hw = &pf->hw;
        u16 vector;
@@ -3578,23 +3875,18 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi)
                /* Linked list for the queuepairs assigned to this vector */
                wr32(hw, I40E_PFINT_LNKLSTN(vector - 1), qp);
                for (q = 0; q < q_vector->num_ringpairs; q++) {
+                       u32 nextqp = has_xdp ? qp + vsi->alloc_queue_pairs : qp;
                        u32 val;
 
-                       val = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
-                             (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT)  |
-                             (vector      << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
-                             (qp          << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT)|
-                             (I40E_QUEUE_TYPE_TX
-                                     << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
-
+                       val = I40E_QINT_RQCTL_VAL(nextqp, vector, TX);
                        wr32(hw, I40E_QINT_RQCTL(qp), val);
 
-                       val = I40E_QINT_TQCTL_CAUSE_ENA_MASK |
-                             (I40E_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT)  |
-                             (vector      << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
-                             ((qp+1)      << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT)|
-                             (I40E_QUEUE_TYPE_RX
-                                     << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
+                       if (has_xdp) {
+                               val = I40E_QINT_TQCTL_VAL(qp, vector, TX);
+                               wr32(hw, I40E_QINT_TQCTL(nextqp), val);
+                       }
+
+                       val = I40E_QINT_TQCTL_VAL((qp + 1), vector, RX);
 
                        /* Terminate the linked list */
                        if (q == (q_vector->num_ringpairs - 1))
@@ -3611,7 +3903,7 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi)
 
 /**
  * i40e_enable_misc_int_causes - enable the non-queue interrupts
- * @hw: ptr to the hardware info
+ * @pf: pointer to private device data structure
  **/
 static void i40e_enable_misc_int_causes(struct i40e_pf *pf)
 {
@@ -3654,6 +3946,7 @@ static void i40e_enable_misc_int_causes(struct i40e_pf *pf)
  **/
 static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi)
 {
+       u32 nextqp = i40e_enabled_xdp_vsi(vsi) ? vsi->alloc_queue_pairs : 0;
        struct i40e_q_vector *q_vector = vsi->q_vectors[0];
        struct i40e_pf *pf = vsi->back;
        struct i40e_hw *hw = &pf->hw;
@@ -3675,12 +3968,21 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi)
        wr32(hw, I40E_PFINT_LNKLST0, 0);
 
        /* Associate the queue pair to the vector and enable the queue int */
-       val = I40E_QINT_RQCTL_CAUSE_ENA_MASK                  |
-             (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
+       val = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
+             (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT)  |
+             (nextqp      << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
              (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
 
        wr32(hw, I40E_QINT_RQCTL(0), val);
 
+       if (i40e_enabled_xdp_vsi(vsi)) {
+               val = I40E_QINT_TQCTL_CAUSE_ENA_MASK |
+                     (I40E_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
+                     (I40E_QUEUE_TYPE_TX
+                      << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
+
+               wr32(hw, I40E_QINT_TQCTL(nextqp), val);
+       }
        val = I40E_QINT_TQCTL_CAUSE_ENA_MASK                  |
              (I40E_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
              (I40E_QUEUE_END_OF_LIST << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
@@ -3873,6 +4175,10 @@ static void i40e_vsi_disable_irq(struct i40e_vsi *vsi)
                val = rd32(hw, I40E_QINT_RQCTL(vsi->rx_rings[i]->reg_idx));
                val &= ~I40E_QINT_RQCTL_CAUSE_ENA_MASK;
                wr32(hw, I40E_QINT_RQCTL(vsi->rx_rings[i]->reg_idx), val);
+
+               if (!i40e_enabled_xdp_vsi(vsi))
+                       continue;
+               wr32(hw, I40E_QINT_TQCTL(vsi->xdp_rings[i]->reg_idx), 0);
        }
 
        /* disable each interrupt */
@@ -4054,7 +4360,8 @@ static irqreturn_t i40e_intr(int irq, void *data)
 enable_intr:
        /* re-enable interrupt causes */
        wr32(hw, I40E_PFINT_ICR0_ENA, ena_mask);
-       if (!test_bit(__I40E_DOWN, pf->state)) {
+       if (!test_bit(__I40E_DOWN, pf->state) ||
+           test_bit(__I40E_RECOVERY_MODE, pf->state)) {
                i40e_service_event_schedule(pf);
                i40e_irq_dynamic_enable_icr0(pf);
        }
@@ -4183,6 +4490,16 @@ static void i40e_map_vector_to_qp(struct i40e_vsi *vsi, int v_idx, int qp_idx)
        q_vector->tx.ring = tx_ring;
        q_vector->tx.count++;
 
+       /* Place XDP Tx ring in the same q_vector ring list as regular Tx */
+       if (i40e_enabled_xdp_vsi(vsi)) {
+               struct i40e_ring *xdp_ring = vsi->xdp_rings[qp_idx];
+
+               xdp_ring->q_vector = q_vector;
+               xdp_ring->next = q_vector->tx.ring;
+               q_vector->tx.ring = xdp_ring;
+               q_vector->tx.count++;
+       }
+
        rx_ring->q_vector = q_vector;
        rx_ring->next = q_vector->rx.ring;
        q_vector->rx.ring = rx_ring;
@@ -4362,6 +4679,33 @@ static void i40e_control_tx_q(struct i40e_pf *pf, int pf_q, bool enable)
        wr32(hw, I40E_QTX_ENA(pf_q), tx_reg);
 }
 
+/**
+ * i40e_control_wait_tx_q - Start/stop Tx queue and wait for completion
+ * @seid: VSI SEID
+ * @pf: the PF structure
+ * @pf_q: the PF queue to configure
+ * @is_xdp: true if the queue is used for XDP
+ * @enable: start or stop the queue
+ **/
+int i40e_control_wait_tx_q(int seid, struct i40e_pf *pf, int pf_q,
+                          bool is_xdp, bool enable)
+{
+       int ret;
+
+       i40e_control_tx_q(pf, pf_q, enable);
+
+       /* wait for the change to finish */
+       ret = i40e_pf_txq_wait(pf, pf_q, enable);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "VSI seid %d %sTx ring %d %sable timeout\n",
+                        seid, (is_xdp ? "XDP " : ""), pf_q,
+                        (enable ? "en" : "dis"));
+       }
+
+       return ret;
+}
+
 /**
  * i40e_vsi_control_tx - Start or stop a VSI's rings
  * @vsi: the VSI being configured
@@ -4374,18 +4718,22 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
 
        pf_q = vsi->base_queue;
        for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
-               i40e_control_tx_q(pf, pf_q, enable);
+               ret = i40e_control_wait_tx_q(vsi->seid, pf,
+                                            pf_q,
+                                            false /*is xdp*/, enable);
+               if (ret)
+                       break;
 
-               /* wait for the change to finish */
-               ret = i40e_pf_txq_wait(pf, pf_q, enable);
-               if (ret) {
-                       dev_info(&pf->pdev->dev,
-                                "VSI seid %d Tx ring %d %sable timeout\n",
-                                vsi->seid, pf_q, (enable ? "en" : "dis"));
+               if (!i40e_enabled_xdp_vsi(vsi))
+                       continue;
+
+               ret = i40e_control_wait_tx_q(vsi->seid, pf,
+                                            pf_q + vsi->alloc_queue_pairs,
+                                            true /*is xdp*/, enable);
+
+               if (ret)
                        break;
-               }
        }
-
        return ret;
 }
 
@@ -4424,9 +4772,9 @@ static int i40e_pf_rxq_wait(struct i40e_pf *pf, int pf_q, bool enable)
  * @pf_q: the PF queue to configure
  * @enable: start or stop the queue
  *
- * This function enables or disables a single queue. Note that any delay
- * required after the operation is expected to be handled by the caller of
- * this function.
+ * This function enables or disables a single queue. Note that
+ * any delay required after the operation is expected to be
+ * handled by the caller of this function.
  **/
 static void i40e_control_rx_q(struct i40e_pf *pf, int pf_q, bool enable)
 {
@@ -4455,6 +4803,30 @@ static void i40e_control_rx_q(struct i40e_pf *pf, int pf_q, bool enable)
        wr32(hw, I40E_QRX_ENA(pf_q), rx_reg);
 }
 
+/**
+ * i40e_control_wait_rx_q
+ * @pf: the PF structure
+ * @pf_q: queue being configured
+ * @enable: start or stop the rings
+ *
+ * This function enables or disables a single queue along with waiting
+ * for the change to finish. The caller of this function should handle
+ * the delays needed in the case of disabling queues.
+ **/
+int i40e_control_wait_rx_q(struct i40e_pf *pf, int pf_q, bool enable)
+{
+       int ret = 0;
+
+       i40e_control_rx_q(pf, pf_q, enable);
+
+       /* wait for the change to finish */
+       ret = i40e_pf_rxq_wait(pf, pf_q, enable);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
 /**
  * i40e_vsi_control_rx - Start or stop a VSI's rings
  * @vsi: the VSI being configured
@@ -4467,10 +4839,7 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
 
        pf_q = vsi->base_queue;
        for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
-               i40e_control_rx_q(pf, pf_q, enable);
-
-               /* wait for the change to finish */
-               ret = i40e_pf_rxq_wait(pf, pf_q, enable);
+               ret = i40e_control_wait_rx_q(pf, pf_q, enable);
                if (ret) {
                        dev_info(&pf->pdev->dev,
                                 "VSI seid %d Rx ring %d %sable timeout\n",
@@ -4808,9 +5177,9 @@ static void i40e_vsi_close(struct i40e_vsi *vsi)
        i40e_vsi_free_tx_resources(vsi);
        i40e_vsi_free_rx_resources(vsi);
        vsi->current_netdev_flags = 0;
-       pf->flags |= I40E_FLAG_SERVICE_CLIENT_REQUESTED;
+       set_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state);
        if (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state))
-               pf->flags |=  I40E_FLAG_CLIENT_RESET;
+               set_bit(__I40E_CLIENT_RESET, pf->state);
 }
 
 /**
@@ -4902,8 +5271,22 @@ int i40e_vsi_wait_queues_disabled(struct i40e_vsi *vsi)
                        return ret;
                }
 
-               /* Check and wait for the Tx queue */
-               ret = i40e_pf_rxq_wait(pf, pf_q, false);
+               if (!i40e_enabled_xdp_vsi(vsi))
+                       goto wait_rx;
+
+               /* Check and wait for the XDP Tx queue */
+               ret = i40e_pf_txq_wait(pf, pf_q + vsi->alloc_queue_pairs,
+                                      false);
+
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "VSI seid %d XDP Tx ring %d disable timeout\n",
+                                vsi->seid, pf_q);
+                       return ret;
+               }
+wait_rx:
+               /* Check and wait for the Rx queue */
+               ret = i40e_pf_rxq_wait(pf, pf_q, false);
                if (ret) {
                        dev_info(&pf->pdev->dev,
                                 "VSI seid %d Rx ring %d disable timeout\n",
@@ -5029,6 +5412,26 @@ static u8 i40e_dcb_get_enabled_tc(struct i40e_dcbx_config *dcbcfg)
        return enabled_tc;
 }
 
+#ifdef __TC_MQPRIO_MODE_MAX
+/**
+ * i40e_mqprio_get_enabled_tc - Get enabled traffic classes
+ * @pf: PF being queried
+ *
+ * Query the current MQPRIO configuration and return the number of
+ * traffic classes enabled.
+ **/
+static u8 i40e_mqprio_get_enabled_tc(struct i40e_pf *pf)
+{
+       struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
+       u8 num_tc = vsi->mqprio_qopt.qopt.num_tc;
+       u8 enabled_tc = 1, i;
+
+       for (i = 1; i < num_tc; i++)
+               enabled_tc |= BIT(i);
+       return enabled_tc;
+}
+#endif
+
 /**
  * i40e_pf_get_num_tc - Get enabled traffic classes for PF
  * @pf: PF being queried
@@ -5042,7 +5445,12 @@ u8 i40e_pf_get_num_tc(struct i40e_pf *pf)
        u8 num_tc = 0;
        struct i40e_dcbx_config *dcbcfg = &hw->local_dcbx_config;
 
-       /* If DCB is not enabled then always in single TC */
+#ifdef __TC_MQPRIO_MODE_MAX
+       if (pf->flags & I40E_FLAG_TC_MQPRIO)
+               return pf->vsi[pf->lan_vsi]->mqprio_qopt.qopt.num_tc;
+#endif
+
+       /* If neither MQPRIO nor DCB is enabled, then always use single TC */
        if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
                return 1;
 
@@ -5071,7 +5479,14 @@ u8 i40e_pf_get_num_tc(struct i40e_pf *pf)
  **/
 static u8 i40e_pf_get_tc_map(struct i40e_pf *pf)
 {
-       /* If DCB is not enabled for this PF then just return default TC */
+#ifdef __TC_MQPRIO_MODE_MAX
+       if (pf->flags & I40E_FLAG_TC_MQPRIO)
+               return i40e_mqprio_get_enabled_tc(pf);
+#endif
+
+       /* If neither MQPRIO nor DCB is enabled for this PF then just return
+        * default TC
+        */
        if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
                return I40E_DEFAULT_TRAFFIC_CLASS;
 
@@ -5150,7 +5565,7 @@ static int i40e_vsi_get_bw_info(struct i40e_vsi *vsi)
  * i40e_vsi_configure_bw_alloc - Configure VSI BW allocation per TC
  * @vsi: the VSI being configured
  * @enabled_tc: TC bitmap
- * @bw_credits: BW shared credits per TC
+ * @bw_share: BW shared credits per TC
  *
  * Returns 0 on success, negative value on failure
  **/
@@ -5158,19 +5573,32 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc,
                                       u8 *bw_share)
 {
        struct i40e_aqc_configure_vsi_tc_bw_data bw_data;
+       struct i40e_pf *pf = vsi->back;
        i40e_status ret;
        int i;
 
+#ifdef __TC_MQPRIO_MODE_MAX
+       /* There is no need to reset BW when mqprio mode is on.  */
+       if (pf->flags & I40E_FLAG_TC_MQPRIO)
+               return 0;
+       if (!vsi->mqprio_qopt.qopt.hw && !(pf->flags & I40E_FLAG_DCB_ENABLED)) {
+               ret = i40e_set_bw_limit(vsi, vsi->seid, 0);
+               if (ret)
+                       dev_info(&pf->pdev->dev,
+                                "Failed to reset tx rate for vsi->seid %u\n",
+                                vsi->seid);
+               return ret;
+       }
+#endif
        bw_data.tc_valid_bits = enabled_tc;
        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
                bw_data.tc_bw_credits[i] = bw_share[i];
 
-       ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, vsi->seid, &bw_data,
-                                      NULL);
+       ret = i40e_aq_config_vsi_tc_bw(&pf->hw, vsi->seid, &bw_data, NULL);
        if (ret) {
-               dev_info(&vsi->back->pdev->dev,
+               dev_info(&pf->pdev->dev,
                         "AQ command Config VSI BW allocation per TC failed = %d\n",
-                        vsi->back->hw.aq.asq_last_status);
+                        pf->hw.aq.asq_last_status);
                return -EINVAL;
        }
 
@@ -5223,6 +5651,9 @@ static void i40e_vsi_config_netdev_tc(struct i40e_vsi *vsi, u8 enabled_tc)
                                        vsi->tc_config.tc_info[i].qoffset);
        }
 
+       if (pf->flags & I40E_FLAG_TC_MQPRIO)
+               return;
+
        /* Assign UP2TC map for the VSI */
        for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
                /* Get the actual TC# for the UP */
@@ -5273,10 +5704,15 @@ int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc)
        struct i40e_vsi_context ctxt;
        int ret = 0;
        int i;
-
+#ifdef __TC_MQPRIO_MODE_MAX
        /* Check if enabled_tc is same as existing or new TCs */
+       if (vsi->tc_config.enabled_tc == enabled_tc &&
+           vsi->mqprio_qopt.mode != TC_MQPRIO_MODE_CHANNEL)
+               return ret;
+#else
        if (vsi->tc_config.enabled_tc == enabled_tc)
                return ret;
+#endif
 
        /* Enable ETS TCs with equal BW Share for now across all VSIs */
        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
@@ -5328,7 +5764,32 @@ int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc)
        ctxt.vf_num = 0;
        ctxt.uplink_seid = vsi->uplink_seid;
        ctxt.info = vsi->info;
+
+#ifdef __TC_MQPRIO_MODE_MAX
+       if (vsi->back->flags & I40E_FLAG_TC_MQPRIO) {
+               ret = i40e_vsi_setup_queue_map_mqprio(vsi, &ctxt, enabled_tc);
+               if (ret)
+                       goto out;
+       } else {
+               i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, false);
+       }
+       /* On destroying the qdisc, reset vsi->rss_size, as number of enabled
+        * queues changed.
+        */
+       if (!vsi->mqprio_qopt.qopt.hw && vsi->reconfig_rss) {
+               vsi->rss_size = min_t(int, vsi->back->alloc_rss_size,
+                                     vsi->num_queue_pairs);
+               ret = i40e_vsi_config_rss(vsi);
+               if (ret) {
+                       dev_info(&vsi->back->pdev->dev,
+                                "Failed to reconfig rss for num_queues\n");
+                       return ret;
+               }
+               vsi->reconfig_rss = false;
+       }
+#else
        i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, false);
+#endif
 
        if (vsi->back->flags & I40E_FLAG_IWARP_ENABLED) {
                ctxt.info.valid_sections |=
@@ -5336,7 +5797,9 @@ int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc)
                ctxt.info.queueing_opt_flags |= I40E_AQ_VSI_QUE_OPT_TCP_ENA;
        }
 
-       /* Update the VSI after updating the VSI queue-mapping information */
+       /* Update the VSI after updating the VSI queue-mapping
+        * information
+        */
        ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
        if (ret) {
                dev_info(&pf->pdev->dev,
@@ -5563,6 +6026,7 @@ out:
 /**
  * i40e_print_link_message - print link up or down
  * @vsi: the VSI for which link needs a message
+ * @isup: true of link is up, false otherwise
  */
 void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
 {
@@ -5574,7 +6038,10 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
        char *req_fec = "";
        char *an = "";
 
-       new_speed = pf->hw.phy.link_info.link_speed;
+       if (isup)
+               new_speed = pf->hw.phy.link_info.link_speed;
+       else
+               new_speed = I40E_LINK_SPEED_UNKNOWN;
 
        if ((vsi->current_isup == isup) && (vsi->current_speed == new_speed))
                return;
@@ -5707,7 +6174,7 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
        /* On the next run of the service_task, notify any clients of the new
         * opened netdev
         */
-       pf->flags |= I40E_FLAG_SERVICE_CLIENT_REQUESTED;
+       set_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state);
        i40e_service_event_schedule(pf);
 
        return 0;
@@ -5728,7 +6195,6 @@ static void i40e_vsi_reinit_locked(struct i40e_vsi *vsi)
        while (test_and_set_bit(__I40E_CONFIG_BUSY, pf->state))
                usleep_range(1000, 2000);
        i40e_down(vsi);
-
        i40e_up(vsi);
        clear_bit(__I40E_CONFIG_BUSY, pf->state);
 }
@@ -5741,6 +6207,10 @@ int i40e_up(struct i40e_vsi *vsi)
 {
        int err;
 
+       if (vsi->type == I40E_VSI_MAIN &&
+           (vsi->back->flags & I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED))
+               i40e_force_link_state(vsi->back, true);
+
        err = i40e_vsi_configure(vsi);
        if (!err)
                err = i40e_up_complete(vsi);
@@ -5753,52 +6223,76 @@ int i40e_up(struct i40e_vsi *vsi)
  * @pf: board private structure
  * @is_up: whether the link state should be forced up or down
  **/
-static void i40e_force_link_state(struct i40e_pf *pf, bool is_up)
+static i40e_status i40e_force_link_state(struct i40e_pf *pf, bool is_up)
 {
        struct i40e_aq_get_phy_abilities_resp abilities;
        struct i40e_aq_set_phy_config config = {0};
        struct i40e_hw *hw = &pf->hw;
-       enum i40e_aq_phy_type cnt;
-       u64 mask = 0;
        i40e_status err;
+       u64 mask;
+       u8 speed;
+
+       /* Card might've been put in an unstable state by other drivers
+        * and applications, which causes incorrect speed values being
+        * set on startup. In order to clear speed registers, we call
+        * get_phy_capabilities twice, once to get initial state of
+        * available speeds, and once to get current phy config.
+        */
+       err = i40e_aq_get_phy_capabilities(hw, false, true, &abilities,
+                                          NULL);
+       if (err) {
+               dev_err(&pf->pdev->dev,
+                       "failed to get phy cap., ret =  %s last_status =  %s\n",
+                       i40e_stat_str(hw, err),
+                       i40e_aq_str(hw, hw->aq.asq_last_status));
+               return err;
+       }
+       speed = abilities.link_speed;
 
        /* Get the current phy config */
        err = i40e_aq_get_phy_capabilities(hw, false, false, &abilities,
                                           NULL);
-       if (err)
-               dev_dbg(&pf->pdev->dev,
+       if (err) {
+               dev_err(&pf->pdev->dev,
                        "failed to get phy cap., ret =  %s last_status =  %s\n",
                        i40e_stat_str(hw, err),
                        i40e_aq_str(hw, hw->aq.asq_last_status));
+               return err;
+       }
 
        /* If link needs to go up, but was not forced to go down,
-        * no need for a flap
+        * and its speed values are OK, no need for a flap
         */
-       if (is_up && abilities.phy_type != 0)
-               return;
+       if (is_up && abilities.phy_type != 0 && abilities.link_speed != 0)
+               return I40E_SUCCESS;
 
        /* To force link we need to set bits for all supported PHY types,
         * but there are now more than 32, so we need to split the bitmap
         * across two fields.
         */
-       for (cnt = I40E_PHY_TYPE_SGMII; cnt < I40E_PHY_TYPE_MAX; cnt++)
-               mask |= (1ULL << cnt);
-
+       mask = I40E_PHY_TYPES_BITMASK;
        config.phy_type = is_up ? cpu_to_le32((u32)(mask & 0xffffffff)) : 0;
        config.phy_type_ext = is_up ? (u8)((mask >> 32) & 0xff) : 0;
        /* Copy the old settings, except of phy_type */
        config.abilities = abilities.abilities;
-       config.link_speed = abilities.link_speed;
+       if (abilities.link_speed != 0)
+               config.link_speed = abilities.link_speed;
+       else
+               config.link_speed = speed;
        config.eee_capability = abilities.eee_capability;
        config.eeer = abilities.eeer_val;
        config.low_power_ctrl = abilities.d3_lpan;
+       config.fec_config = abilities.fec_cfg_curr_mod_ext_info &
+                           I40E_AQ_PHY_FEC_CONFIG_MASK;
        err = i40e_aq_set_phy_config(hw, &config, NULL);
 
-       if (err)
-               dev_dbg(&pf->pdev->dev,
+       if (err) {
+               dev_err(&pf->pdev->dev,
                        "set phy config ret =  %s last_status =  %s\n",
                        i40e_stat_str(&pf->hw, err),
                        i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
+               return err;
+       }
 
        /* Update the link info */
        err = i40e_update_link_info(hw);
@@ -5812,6 +6306,8 @@ static void i40e_force_link_state(struct i40e_pf *pf, bool is_up)
        }
 
        i40e_aq_set_link_restart_an(hw, true, NULL);
+
+       return I40E_SUCCESS;
 }
 
 /**
@@ -5838,69 +6334,1760 @@ void i40e_down(struct i40e_vsi *vsi)
 
        for (i = 0; i < vsi->num_queue_pairs; i++) {
                i40e_clean_tx_ring(vsi->tx_rings[i]);
+               if (i40e_enabled_xdp_vsi(vsi))
+                       i40e_clean_tx_ring(vsi->xdp_rings[i]);
                i40e_clean_rx_ring(vsi->rx_rings[i]);
        }
 
 }
 
-#ifdef HAVE_SETUP_TC
 /**
- * i40e_setup_tc - configure multiple traffic classes
- * @netdev: net device to configure
- * @tc: number of traffic classes to enable
+ * i40e_get_link_speed - Returns link speed for the interface
+ * @vsi: VSI to be configured
+ *
  **/
-static int i40e_setup_tc(struct net_device *netdev, u8 tc)
+int i40e_get_link_speed(struct i40e_vsi *vsi)
 {
-       struct i40e_netdev_priv *np = netdev_priv(netdev);
-       struct i40e_vsi *vsi = np->vsi;
        struct i40e_pf *pf = vsi->back;
-       u8 enabled_tc = 0;
-       int ret = -EINVAL;
-       int i;
 
-       /* Check if DCB enabled to continue */
-       if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) {
-               netdev_info(netdev, "DCB is not enabled for adapter\n");
-               goto exit;
+       switch (pf->hw.phy.link_info.link_speed) {
+       case I40E_LINK_SPEED_40GB:
+               return 40000;
+       case I40E_LINK_SPEED_25GB:
+               return 25000;
+       case I40E_LINK_SPEED_20GB:
+               return 20000;
+       case I40E_LINK_SPEED_10GB:
+               return 10000;
+       case I40E_LINK_SPEED_1GB:
+               return 1000;
+       default:
+               return -EINVAL;
        }
+}
 
-       /* Check if MFP enabled */
-       if (pf->flags & I40E_FLAG_MFP_ENABLED) {
-               netdev_info(netdev, "Configuring TC not supported in MFP mode\n");
-               goto exit;
+/**
+ * i40e_set_bw_limit - setup BW limit for Tx traffic based on max_tx_rate
+ * @vsi: VSI to be configured
+ * @seid: seid of the channel/VSI
+ * @max_tx_rate: max TX rate to be configured as BW limit
+ *
+ * Helper function to set BW limit for a given VSI
+ **/
+int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate)
+{
+       struct i40e_pf *pf = vsi->back;
+       int speed = 0;
+       int ret = 0;
+
+       speed = i40e_get_link_speed(vsi);
+       if (max_tx_rate > speed) {
+               dev_err(&pf->pdev->dev,
+                       "Invalid max tx rate %llu specified for VSI seid %d.",
+                       max_tx_rate, seid);
+               return -EINVAL;
+       }
+       if (max_tx_rate && max_tx_rate < 50) {
+               dev_warn(&pf->pdev->dev,
+                        "Setting max tx rate to minimum usable value of 50Mbps.\n");
+               max_tx_rate = 50;
        }
 
-       /* Check whether tc count is within enabled limit */
-       if (tc > i40e_pf_get_num_tc(pf)) {
-               netdev_info(netdev, "TC count greater than enabled on link for adapter\n");
-               goto exit;
+       /* Tx rate credits are in values of 50Mbps, 0 is disabled */
+       ret = i40e_aq_config_vsi_bw_limit(&pf->hw, seid,
+                                         max_tx_rate / I40E_BW_CREDIT_DIVISOR,
+                                         I40E_MAX_BW_INACTIVE_ACCUM, NULL);
+       if (ret)
+               dev_err(&pf->pdev->dev,
+                       "Failed set tx rate (%llu Mbps) for vsi->seid %u, err %s aq_err %s\n",
+                       max_tx_rate, seid, i40e_stat_str(&pf->hw, ret),
+                       i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
+       return ret;
+}
+
+#ifdef __TC_MQPRIO_MODE_MAX
+/**
+ * i40e_validate_and_set_switch_mode - sets up switch mode correctly
+ * @vsi: ptr to VSI which has PF backing
+ *
+ * Sets up switch mode correctly if it needs to be changed and perform
+ * what are allowed modes.
+ **/
+static int i40e_validate_and_set_switch_mode(struct i40e_vsi *vsi)
+{
+       u8 mode;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       int ret;
+
+       ret = i40e_get_capabilities(pf, i40e_aqc_opc_list_dev_capabilities);
+       if (ret)
+               return -EINVAL;
+
+       if (hw->dev_caps.switch_mode) {
+               /* if switch mode is set, support mode2 (non-tunneled for
+                * cloud filter) for now
+                */
+               u32 switch_mode = hw->dev_caps.switch_mode &
+                                 I40E_SWITCH_MODE_MASK;
+               if (switch_mode >= I40E_CLOUD_FILTER_MODE1) {
+                       if (switch_mode == I40E_CLOUD_FILTER_MODE2)
+                               return 0;
+                       dev_err(&pf->pdev->dev,
+                               "Invalid switch_mode (%d), only non-tunneled mode for cloud filter is supported\n",
+                               hw->dev_caps.switch_mode);
+                       return -EINVAL;
+               }
        }
 
-       /* Generate TC map for number of tc requested */
-       for (i = 0; i < tc; i++)
-               enabled_tc |= BIT(i);
+       /* Set Bit 7 to be valid */
+       mode = I40E_AQ_SET_SWITCH_BIT7_VALID;
 
-       /* Requesting same TC configuration as already enabled */
-       if (enabled_tc == vsi->tc_config.enabled_tc)
-               return 0;
+       /* Set L4type for TCP support */
+       mode |= I40E_AQ_SET_SWITCH_L4_TYPE_TCP;
 
-       /* Quiesce VSI queues */
-       i40e_quiesce_vsi(vsi);
+       /* Set cloud filter mode */
+       mode |= I40E_AQ_SET_SWITCH_MODE_NON_TUNNEL;
 
-       /* Configure VSI for enabled TCs */
-       ret = i40e_vsi_config_tc(vsi, enabled_tc);
-       if (ret) {
-               netdev_info(netdev, "Failed configuring TC for VSI seid=%d\n",
-                           vsi->seid);
-               goto exit;
+       /* Prep mode field for set_switch_config */
+       ret = i40e_aq_set_switch_config(hw, pf->last_sw_conf_flags,
+                                       pf->last_sw_conf_valid_flags,
+                                       mode, NULL);
+       if (ret && hw->aq.asq_last_status != I40E_AQ_RC_ESRCH)
+               dev_err(&pf->pdev->dev,
+                       "couldn't set switch config bits, err %s aq_err %s\n",
+                       i40e_stat_str(hw, ret),
+                       i40e_aq_str(hw,
+                                   hw->aq.asq_last_status));
+
+       return ret;
+}
+
+/**
+ * i40e_add_del_cloud_filter_big_buf - Add/del cloud filter using big_buf
+ * @vsi: pointer to VSI
+ * @filter: cloud filter rule
+ * @add: if true, add, if false, delete
+ *
+ * Add or delete a cloud filter for a specific flow spec using big buffer.
+ * Returns 0 if the filter were successfully added.
+ **/
+int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,
+                                     struct i40e_cloud_filter *filter,
+                                     bool add)
+{
+       struct i40e_aqc_cloud_filters_element_bb cld_filter;
+       struct i40e_pf *pf = vsi->back;
+       int ret;
+
+       /* Both (src/dst) valid mac_addr are not supported */
+       if ((is_valid_ether_addr(filter->dst_mac) &&
+            is_valid_ether_addr(filter->src_mac)) ||
+           (is_multicast_ether_addr(filter->dst_mac) &&
+            is_multicast_ether_addr(filter->src_mac)))
+               return -EOPNOTSUPP;
+
+       /* Big buffer cloud filter needs 'L4 port' to be non-zero. Also, UDP
+        * ports are not supported via big buffer now.
+        */
+       if (!filter->dst_port || filter->ip_proto == IPPROTO_UDP)
+               return -EOPNOTSUPP;
+
+       /* adding filter using src_port/src_ip is not supported at this stage */
+       if (filter->src_port || filter->src_ipv4 ||
+           !ipv6_addr_any(&filter->ip.v6.src_ip6))
+               return -EOPNOTSUPP;
+
+       /* copy element needed to add cloud filter from filter */
+       i40e_set_cld_element(filter, &cld_filter.element);
+
+       if (is_valid_ether_addr(filter->dst_mac) ||
+           is_valid_ether_addr(filter->src_mac) ||
+           is_multicast_ether_addr(filter->dst_mac) ||
+           is_multicast_ether_addr(filter->src_mac)) {
+               /* MAC + IP : unsupported mode */
+               if (filter->dst_ipv4)
+                       return -EOPNOTSUPP;
+
+               /* since we validated that L4 port must be valid before
+                * we get here, start with respective "flags" value
+                * and update if vlan is present or not
+                */
+               cld_filter.element.flags =
+                       cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT);
+
+               if (filter->vlan_id) {
+                       cld_filter.element.flags =
+                       cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT);
+               }
+
+       } else if (filter->dst_ipv4 ||
+                  !ipv6_addr_any(&filter->ip.v6.dst_ip6)) {
+               cld_filter.element.flags =
+                               cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_IP_PORT);
+               if (filter->n_proto == ETH_P_IPV6)
+                       cld_filter.element.flags |=
+                               cpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV6);
+               else
+                       cld_filter.element.flags |=
+                               cpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV4);
+       } else {
+               dev_err(&pf->pdev->dev,
+                       "either mac or ip has to be valid for cloud filter\n");
+               return -EINVAL;
+       }
+
+       /* Now copy L4 port in Byte 6..7 in general fields */
+       cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD0] =
+                                               be16_to_cpu(filter->dst_port);
+
+       if (add) {
+               /* Validate current device switch mode, change if necessary */
+               ret = i40e_validate_and_set_switch_mode(vsi);
+               if (ret) {
+                       dev_err(&pf->pdev->dev,
+                               "failed to set switch mode, ret %d\n",
+                               ret);
+                       return ret;
+               }
+
+               ret = i40e_aq_add_cloud_filters_bb(&pf->hw, filter->seid,
+                                                  &cld_filter, 1);
+       } else {
+               ret = i40e_aq_rem_cloud_filters_bb(&pf->hw, filter->seid,
+                                                  &cld_filter, 1);
+       }
+
+       if (ret)
+               dev_dbg(&pf->pdev->dev,
+                       "Failed to %s cloud filter(big buffer) err %d aq_err %d\n",
+                       add ? "add" : "delete", ret, pf->hw.aq.asq_last_status);
+       else
+               dev_info(&pf->pdev->dev,
+                        "%s cloud filter for VSI: %d, L4 port: %d\n",
+                        add ? "add" : "delete", filter->seid,
+                        ntohs(filter->dst_port));
+       return ret;
+}
+
+/**
+ * i40e_remove_queue_channels - Remove queue channels for the TCs
+ * @vsi: VSI to be configured
+ *
+ * Remove queue channels for the TCs
+ **/
+static void i40e_remove_queue_channels(struct i40e_vsi *vsi)
+{
+       enum i40e_admin_queue_err last_aq_status;
+       struct i40e_cloud_filter *cfilter;
+       struct i40e_channel *ch, *ch_tmp;
+       struct i40e_pf *pf = vsi->back;
+       struct hlist_node *node;
+       int ret, i;
+
+       /* Reset rss size that was stored when reconfiguring rss for
+        * channel VSIs with non-power-of-2 queue count.
+        */
+       vsi->current_rss_size = 0;
+
+       /* perform cleanup for channels if they exist */
+       if (list_empty(&vsi->ch_list))
+               return;
+
+       list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list, list) {
+               struct i40e_vsi *p_vsi;
+
+               list_del(&ch->list);
+               p_vsi = ch->parent_vsi;
+               if (!p_vsi || !ch->initialized) {
+                       kfree(ch);
+                       continue;
+               }
+               /* Reset queue contexts */
+               for (i = 0; i < ch->num_queue_pairs; i++) {
+                       struct i40e_ring *tx_ring, *rx_ring;
+                       u16 pf_q;
+
+                       pf_q = ch->base_queue + i;
+                       tx_ring = vsi->tx_rings[pf_q];
+                       tx_ring->ch = NULL;
+
+                       rx_ring = vsi->rx_rings[pf_q];
+                       rx_ring->ch = NULL;
+               }
+
+               /* Reset BW configured for this VSI via mqprio */
+               ret = i40e_set_bw_limit(vsi, ch->seid, 0);
+               if (ret)
+                       dev_info(&vsi->back->pdev->dev,
+                                "Failed to reset tx rate for ch->seid %u\n",
+                                ch->seid);
+
+               /* delete cloud filters associated with this channel */
+               hlist_for_each_entry_safe(cfilter, node,
+                                         &pf->cloud_filter_list, cloud_node) {
+                       if (cfilter->seid != ch->seid)
+                               continue;
+
+                       hash_del(&cfilter->cloud_node);
+                       if (cfilter->dst_port)
+                               ret = i40e_add_del_cloud_filter_big_buf(vsi,
+                                                                       cfilter,
+                                                                       false);
+                       else
+                               ret = i40e_add_del_cloud_filter(vsi, cfilter,
+                                                               false);
+                       last_aq_status = pf->hw.aq.asq_last_status;
+                       if (ret)
+                               dev_info(&pf->pdev->dev,
+                                        "Failed to delete cloud filter, err %s aq_err %s\n",
+                                        i40e_stat_str(&pf->hw, ret),
+                                        i40e_aq_str(&pf->hw, last_aq_status));
+                       kfree(cfilter);
+               }
+
+               /* delete cloud filters associated with this channel */
+               hlist_for_each_entry_safe(cfilter, node,
+                                         &pf->cloud_filter_list, cloud_node) {
+                       if (cfilter->seid != ch->seid)
+                               continue;
+
+                       hash_del(&cfilter->cloud_node);
+                       if (cfilter->dst_port)
+                               ret = i40e_add_del_cloud_filter_big_buf(vsi,
+                                                                       cfilter,
+                                                                       false);
+                       else
+                               ret = i40e_add_del_cloud_filter(vsi, cfilter,
+                                                               false);
+                       last_aq_status = pf->hw.aq.asq_last_status;
+                       if (ret)
+                               dev_info(&pf->pdev->dev,
+                                        "Failed to delete cloud filter, err %s aq_err %s\n",
+                                        i40e_stat_str(&pf->hw, ret),
+                                        i40e_aq_str(&pf->hw, last_aq_status));
+                       kfree(cfilter);
+               }
+
+               /* delete VSI from FW */
+               ret = i40e_aq_delete_element(&vsi->back->hw, ch->seid,
+                                            NULL);
+               if (ret)
+                       dev_err(&vsi->back->pdev->dev,
+                               "unable to remove channel (%d) for parent VSI(%d)\n",
+                               ch->seid, p_vsi->seid);
+               kfree(ch);
+       }
+       INIT_LIST_HEAD(&vsi->ch_list);
+}
+
+/**
+ * i40e_is_any_channel - channel exist or not
+ * @vsi: ptr to VSI to which channels are associated with
+ *
+ * Returns true or false if channel(s) exist for associated VSI or not
+ **/
+static bool i40e_is_any_channel(struct i40e_vsi *vsi)
+{
+       struct i40e_channel *ch, *ch_tmp;
+
+       list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list, list) {
+               if (ch->initialized)
+                       return true;
+       }
+
+       return false;
+}
+
+/**
+ * i40e_get_max_queues_for_channel
+ * @vsi: ptr to VSI to which channels are associated with
+ *
+ * Helper function which returns max value among the queue counts set on the
+ * channels/TCs created.
+ **/
+static int i40e_get_max_queues_for_channel(struct i40e_vsi *vsi)
+{
+       struct i40e_channel *ch, *ch_tmp;
+       int max = 0;
+
+       list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list, list) {
+               if (!ch->initialized)
+                       continue;
+               if (ch->num_queue_pairs > max)
+                       max = ch->num_queue_pairs;
+       }
+
+       return max;
+}
+
+/**
+ * i40e_validate_num_queues - validate num_queues w.r.t channel
+ * @pf: ptr to PF device
+ * @num_queues: number of queues
+ * @vsi: the parent VSI
+ * @reconfig_rss: indicates should the RSS be reconfigured or not
+ *
+ * This function validates number of queues in the context of new channel
+ * which is being established and determines if RSS should be reconfigured
+ * or not for parent VSI.
+ **/
+static int i40e_validate_num_queues(struct i40e_pf *pf, int num_queues,
+                                   struct i40e_vsi *vsi, bool *reconfig_rss)
+{
+       int max_ch_queues;
+
+       if (!reconfig_rss)
+               return -EINVAL;
+
+       *reconfig_rss = false;
+       if (vsi->current_rss_size) {
+               if (num_queues > vsi->current_rss_size) {
+                       dev_dbg(&pf->pdev->dev,
+                               "Error: num_queues (%d) > vsi's current_size(%d)\n",
+                               num_queues, vsi->current_rss_size);
+                       return -EINVAL;
+               } else if ((num_queues < vsi->current_rss_size) &&
+                          (!is_power_of_2(num_queues))) {
+                       dev_dbg(&pf->pdev->dev,
+                               "Error: num_queues (%d) < vsi's current_size(%d), but not power of 2\n",
+                               num_queues, vsi->current_rss_size);
+                       return -EINVAL;
+               }
+       }
+
+       if (!is_power_of_2(num_queues)) {
+               /* Find the max num_queues configured for channel if channel
+                * exist.
+                * if channel exist, then enforce 'num_queues' to be more than
+                * max ever queues configured for channel.
+                */
+               max_ch_queues = i40e_get_max_queues_for_channel(vsi);
+               if (num_queues < max_ch_queues) {
+                       dev_dbg(&pf->pdev->dev,
+                               "Error: num_queues (%d) < max queues configured for channel(%d)\n",
+                               num_queues, max_ch_queues);
+                       return -EINVAL;
+               }
+               *reconfig_rss = true;
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_vsi_reconfig_rss - reconfig RSS based on specified rss_size
+ * @vsi: the VSI being setup
+ * @rss_size: size of RSS, accordingly LUT gets reprogrammed
+ *
+ * This function reconfigures RSS by reprogramming LUTs using 'rss_size'
+ **/
+static int i40e_vsi_reconfig_rss(struct i40e_vsi *vsi, u16 rss_size)
+{
+       struct i40e_pf *pf = vsi->back;
+       u8 seed[I40E_HKEY_ARRAY_SIZE];
+       struct i40e_hw *hw = &pf->hw;
+       int local_rss_size;
+       u8 *lut;
+       int ret;
+
+       if (!vsi->rss_size)
+               return -EINVAL;
+
+       if (rss_size > vsi->rss_size)
+               return -EINVAL;
+
+       local_rss_size = min_t(int, vsi->rss_size, rss_size);
+       lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
+       if (!lut)
+               return -ENOMEM;
+
+       /* Ignoring user configured lut if there is one */
+       i40e_fill_rss_lut(pf, lut, vsi->rss_table_size, local_rss_size);
+
+       /* Use user configured hash key if there is one, otherwise
+        * use default.
+        */
+       if (vsi->rss_hkey_user)
+               memcpy(seed, vsi->rss_hkey_user, I40E_HKEY_ARRAY_SIZE);
+       else
+               netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
+
+       ret = i40e_config_rss(vsi, seed, lut, vsi->rss_table_size);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "Cannot set RSS lut, err %s aq_err %s\n",
+                        i40e_stat_str(hw, ret),
+                        i40e_aq_str(hw, hw->aq.asq_last_status));
+               kfree(lut);
+               return ret;
+       }
+       kfree(lut);
+
+       /* Do the update w.r.t. storing rss_size */
+       if (!vsi->orig_rss_size)
+               vsi->orig_rss_size = vsi->rss_size;
+       vsi->current_rss_size = local_rss_size;
+
+       return ret;
+}
+
+/**
+ * i40e_channel_setup_queue_map - Setup a channel queue map
+ * @pf: ptr to PF device
+ * @ctxt: VSI context structure
+ * @ch: ptr to channel structure
+ *
+ * Setup queue map for a specific channel
+ **/
+static void i40e_channel_setup_queue_map(struct i40e_pf *pf,
+                                        struct i40e_vsi_context *ctxt,
+                                        struct i40e_channel *ch)
+{
+       u16 qcount, qmap, sections = 0;
+       u8 offset = 0;
+       int pow;
+
+       sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
+       sections |= I40E_AQ_VSI_PROP_SCHED_VALID;
+
+       qcount = min_t(int, ch->num_queue_pairs, pf->num_lan_msix);
+       ch->num_queue_pairs = qcount;
+
+       /* find the next higher power-of-2 of num queue pairs */
+       pow = ilog2(qcount);
+       if (!is_power_of_2(qcount))
+               pow++;
+
+       qmap = (offset << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
+               (pow << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT);
+
+       /* Setup queue TC[0].qmap for given VSI context */
+       ctxt->info.tc_mapping[0] = cpu_to_le16(qmap);
+
+       ctxt->info.up_enable_bits = 0x1; /* TC0 enabled */
+       ctxt->info.mapping_flags |= cpu_to_le16(I40E_AQ_VSI_QUE_MAP_CONTIG);
+       ctxt->info.queue_mapping[0] = cpu_to_le16(ch->base_queue);
+       ctxt->info.valid_sections |= cpu_to_le16(sections);
+}
+
+/**
+ * i40e_add_channel - add a channel by adding VSI
+ * @pf: ptr to PF device
+ * @uplink_seid: underlying HW switching element (VEB) ID
+ * @ch: ptr to channel structure
+ *
+ * Add a channel (VSI) using add_vsi and queue_map
+ **/
+static int i40e_add_channel(struct i40e_pf *pf, u16 uplink_seid,
+                           struct i40e_channel *ch)
+{
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_vsi_context ctxt;
+       u8 enabled_tc = 0x1; /* TC0 enabled */
+       int ret;
+
+       if (ch->type != I40E_VSI_VMDQ2) {
+               dev_info(&pf->pdev->dev,
+                        "add new vsi failed, ch->type %d\n", ch->type);
+               return -EINVAL;
+       }
+
+       memset(&ctxt, 0, sizeof(ctxt));
+       ctxt.pf_num = hw->pf_id;
+       ctxt.vf_num = 0;
+       ctxt.uplink_seid = uplink_seid;
+       ctxt.connection_type = I40E_AQ_VSI_CONN_TYPE_NORMAL;
+       if (ch->type == I40E_VSI_VMDQ2)
+               ctxt.flags = I40E_AQ_VSI_TYPE_VMDQ2;
+
+       if (pf->flags & I40E_FLAG_VEB_MODE_ENABLED) {
+               ctxt.info.valid_sections |=
+                    cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
+               ctxt.info.switch_id =
+                  cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
+       }
+
+       /* Set queue map for a given VSI context */
+       i40e_channel_setup_queue_map(pf, &ctxt, ch);
+
+       /* Now time to create VSI */
+       ret = i40e_aq_add_vsi(hw, &ctxt, NULL);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "add new vsi failed, err %s aq_err %s\n",
+                        i40e_stat_str(&pf->hw, ret),
+                        i40e_aq_str(&pf->hw,
+                                    pf->hw.aq.asq_last_status));
+               return -ENOENT;
+       }
+
+       /* Success, update channel */
+       ch->enabled_tc = enabled_tc;
+       ch->seid = ctxt.seid;
+       ch->vsi_number = ctxt.vsi_number;
+       ch->stat_counter_idx = le16_to_cpu(ctxt.info.stat_counter_idx);
+
+       /* copy just the sections touched not the entire info
+        * since not all sections are valid as returned by
+        * update vsi params
+        */
+       ch->info.mapping_flags = ctxt.info.mapping_flags;
+       memcpy(&ch->info.queue_mapping,
+              &ctxt.info.queue_mapping, sizeof(ctxt.info.queue_mapping));
+       memcpy(&ch->info.tc_mapping, ctxt.info.tc_mapping,
+              sizeof(ctxt.info.tc_mapping));
+
+       return 0;
+}
+
+static int i40e_channel_config_bw(struct i40e_vsi *vsi, struct i40e_channel *ch,
+                                 u8 *bw_share)
+{
+       struct i40e_aqc_configure_vsi_tc_bw_data bw_data;
+       i40e_status ret;
+       int i;
+
+       bw_data.tc_valid_bits = ch->enabled_tc;
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+               bw_data.tc_bw_credits[i] = bw_share[i];
+
+       ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, ch->seid,
+                                      &bw_data, NULL);
+       if (ret) {
+               dev_info(&vsi->back->pdev->dev,
+                        "Config VSI BW allocation per TC failed, aq_err: %d for new_vsi->seid %u\n",
+                        vsi->back->hw.aq.asq_last_status, ch->seid);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+               ch->info.qs_handle[i] = bw_data.qs_handles[i];
+
+       return 0;
+}
+
+/**
+ * i40e_channel_config_tx_ring - config TX ring associated with new channel
+ * @pf: ptr to PF device
+ * @vsi: the VSI being setup
+ * @ch: ptr to channel structure
+ *
+ * Configure TX rings associated with channel (VSI) since queues are being
+ * from parent VSI.
+ **/
+static int i40e_channel_config_tx_ring(struct i40e_pf *pf,
+                                      struct i40e_vsi *vsi,
+                                      struct i40e_channel *ch)
+{
+       i40e_status ret;
+       int i;
+       u8 bw_share[I40E_MAX_TRAFFIC_CLASS] = {0};
+
+       /* Enable ETS TCs with equal BW Share for now across all VSIs */
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               if (ch->enabled_tc & BIT(i))
+                       bw_share[i] = 1;
+       }
+
+       /* configure BW for new VSI */
+       ret = i40e_channel_config_bw(vsi, ch, bw_share);
+       if (ret) {
+               dev_info(&vsi->back->pdev->dev,
+                        "Failed configuring TC map %d for channel (seid %u)\n",
+                        ch->enabled_tc, ch->seid);
+               return ret;
+       }
+
+       for (i = 0; i < ch->num_queue_pairs; i++) {
+               struct i40e_ring *tx_ring, *rx_ring;
+               u16 pf_q;
+
+               pf_q = ch->base_queue + i;
+
+               /* Get to TX ring ptr of main VSI, for re-setup TX queue
+                * context
+                */
+               tx_ring = vsi->tx_rings[pf_q];
+               tx_ring->ch = ch;
+
+               /* Get the RX ring ptr */
+               rx_ring = vsi->rx_rings[pf_q];
+               rx_ring->ch = ch;
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_setup_hw_channel - setup new channel
+ * @pf: ptr to PF device
+ * @vsi: the VSI being setup
+ * @ch: ptr to channel structure
+ * @uplink_seid: underlying HW switching element (VEB) ID
+ * @type: type of channel to be created (VMDq2/VF)
+ *
+ * Setup new channel (VSI) based on specified type (VMDq2/VF)
+ * and configures TX rings accordingly
+ **/
+static inline int i40e_setup_hw_channel(struct i40e_pf *pf,
+                                       struct i40e_vsi *vsi,
+                                       struct i40e_channel *ch,
+                                       u16 uplink_seid, u8 type)
+{
+       int ret;
+
+       ch->initialized = false;
+       ch->base_queue = vsi->next_base_queue;
+       ch->type = type;
+
+       /* Proceed with creation of channel (VMDq2) VSI */
+       ret = i40e_add_channel(pf, uplink_seid, ch);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "failed to add_channel using uplink_seid %u\n",
+                        uplink_seid);
+               return ret;
+       }
+
+       /* Mark the successful creation of channel */
+       ch->initialized = true;
+
+       /* Reconfigure TX queues using QTX_CTL register */
+       ret = i40e_channel_config_tx_ring(pf, vsi, ch);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "failed to configure TX rings for channel %u\n",
+                        ch->seid);
+               return ret;
+       }
+
+       /* update 'next_base_queue' */
+       vsi->next_base_queue = vsi->next_base_queue + ch->num_queue_pairs;
+       dev_dbg(&pf->pdev->dev,
+               "Added channel: vsi_seid %u, vsi_number %u, stat_counter_idx %u, num_queue_pairs %u, pf->next_base_queue %d\n",
+               ch->seid, ch->vsi_number, ch->stat_counter_idx,
+               ch->num_queue_pairs,
+               vsi->next_base_queue);
+       return ret;
+}
+
+/**
+ * i40e_setup_channel - setup new channel using uplink element
+ * @pf: ptr to PF device
+ * @vsi: the VSI being setup
+ * @ch: ptr to channel structure
+ *
+ * Setup new channel (VSI) based on specified type (VMDq2/VF)
+ * and uplink switching element (uplink_seid)
+ **/
+static bool i40e_setup_channel(struct i40e_pf *pf, struct i40e_vsi *vsi,
+                              struct i40e_channel *ch)
+{
+       u8 vsi_type;
+       u16 seid;
+       int ret;
+
+       if (vsi->type == I40E_VSI_MAIN) {
+               vsi_type = I40E_VSI_VMDQ2;
+       } else {
+               dev_err(&pf->pdev->dev, "unsupported parent vsi type(%d)\n",
+                       vsi->type);
+               return false;
+       }
+
+       /* underlying switching element */
+       seid = pf->vsi[pf->lan_vsi]->uplink_seid;
+
+       /* create channel (VSI), configure TX rings */
+       ret = i40e_setup_hw_channel(pf, vsi, ch, seid, vsi_type);
+       if (ret) {
+               dev_err(&pf->pdev->dev, "failed to setup hw_channel\n");
+               return false;
+       }
+
+       return ch->initialized ? true : false;
+}
+
+/**
+ * i40e_create_queue_channel - function to create channel
+ * @vsi: VSI to be configured
+ * @ch: ptr to channel (it contains channel specific params)
+ *
+ * This function creates channel (VSI) using num_queues specified by user,
+ * reconfigs RSS if needed.
+ **/
+int i40e_create_queue_channel(struct i40e_vsi *vsi,
+                             struct i40e_channel *ch)
+{
+       struct i40e_pf *pf = vsi->back;
+       bool reconfig_rss;
+       int err;
+
+       if (!ch)
+               return -EINVAL;
+
+       if (!ch->num_queue_pairs) {
+               dev_err(&pf->pdev->dev, "Invalid num_queues requested: %d\n",
+                       ch->num_queue_pairs);
+               return -EINVAL;
+       }
+
+       /* validate user requested num_queues for channel */
+       err = i40e_validate_num_queues(pf, ch->num_queue_pairs, vsi,
+                                      &reconfig_rss);
+       if (err) {
+               dev_info(&pf->pdev->dev, "Failed to validate num_queues (%d)\n",
+                        ch->num_queue_pairs);
+               return -EINVAL;
+       }
+
+       /* By default we are in VEPA mode, if this is the first VF/VMDq
+        * VSI to be added switch to VEB mode.
+        */
+       if ((!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) ||
+           (!i40e_is_any_channel(vsi))) {
+               if (!is_power_of_2(vsi->tc_config.tc_info[0].qcount)) {
+                       dev_dbg(&pf->pdev->dev,
+                               "Failed to create channel. Override queues (%u) not power of 2\n",
+                               vsi->tc_config.tc_info[0].qcount);
+                       return -EINVAL;
+               }
+
+               if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
+                       pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
+
+                       if (vsi->type == I40E_VSI_MAIN) {
+                               if (pf->flags & I40E_FLAG_TC_MQPRIO)
+                                       i40e_do_reset(pf, I40E_PF_RESET_FLAG,
+                                                     true);
+                               else
+                                       i40e_do_reset_safe(pf,
+                                                          I40E_PF_RESET_FLAG);
+                       }
+               }
+               /* now onwards for main VSI, number of queues will be value
+                * of TC0's queue count
+                */
+       }
+
+       /* By this time, vsi->cnt_q_avail shall be set to non-zero and
+        * it should be more than num_queues
+        */
+       if (!vsi->cnt_q_avail || vsi->cnt_q_avail < ch->num_queue_pairs) {
+               dev_dbg(&pf->pdev->dev,
+                       "Error: cnt_q_avail (%u) less than num_queues %d\n",
+                       vsi->cnt_q_avail, ch->num_queue_pairs);
+               return -EINVAL;
+       }
+
+       /* reconfig_rss only if vsi type is MAIN_VSI */
+       if (reconfig_rss && vsi->type == I40E_VSI_MAIN) {
+               err = i40e_vsi_reconfig_rss(vsi, ch->num_queue_pairs);
+               if (err) {
+                       dev_info(&pf->pdev->dev,
+                                "Error: unable to reconfig rss for num_queues (%u)\n",
+                                ch->num_queue_pairs);
+                       return -EINVAL;
+               }
+       }
+
+       if (!i40e_setup_channel(pf, vsi, ch)) {
+               dev_info(&pf->pdev->dev, "Failed to setup channel\n");
+               return -EINVAL;
+       }
+
+       dev_info(&pf->pdev->dev,
+                "Setup channel (id:%u) utilizing num_queues %d\n",
+                ch->seid, ch->num_queue_pairs);
+
+       /* configure VSI for BW limit */
+       if (ch->max_tx_rate) {
+               if (i40e_set_bw_limit(vsi, ch->seid, ch->max_tx_rate))
+                       return -EINVAL;
+
+               dev_dbg(&pf->pdev->dev,
+                       "Set tx rate of %llu Mbps (count of 50Mbps %llu) for vsi->seid %u\n",
+                       ch->max_tx_rate,
+                       ch->max_tx_rate / I40E_BW_CREDIT_DIVISOR, ch->seid);
+       }
+
+       /* in case of VF, this will be main SRIOV VSI */
+       ch->parent_vsi = vsi;
+
+       /* and update main_vsi's count for queue_available to use */
+       vsi->cnt_q_avail -= ch->num_queue_pairs;
+
+       return 0;
+}
+
+/**
+ * i40e_configure_queue_channels - Add queue channel for the given TCs
+ * @vsi: VSI to be configured
+ *
+ * Configures queue channel mapping to the given TCs
+ **/
+static int i40e_configure_queue_channels(struct i40e_vsi *vsi)
+{
+       struct i40e_channel *ch;
+       int ret = 0, i;
+
+       /* Create app vsi with the TCs. Main VSI with TC0 is already set up */
+       vsi->tc_seid_map[0] = vsi->seid;
+       for (i = 1; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               if (vsi->tc_config.enabled_tc & BIT(i)) {
+                       ch = kzalloc(sizeof(*ch), GFP_KERNEL);
+                       if (!ch) {
+                               ret = -ENOMEM;
+                               goto err_free;
+                       }
+
+                       INIT_LIST_HEAD(&ch->list);
+                       ch->num_queue_pairs =
+                               vsi->tc_config.tc_info[i].qcount;
+                       ch->base_queue =
+                               vsi->tc_config.tc_info[i].qoffset;
+
+                       /* Bandwidth limit through tc interface is in bytes/s,
+                        * change to Mbit/s
+                        */
+                       ch->max_tx_rate =
+                               vsi->mqprio_qopt.max_rate[i] / (1000000 / 8);
+
+                       list_add_tail(&ch->list, &vsi->ch_list);
+
+                       ret = i40e_create_queue_channel(vsi, ch);
+                       if (ret) {
+                               dev_err(&vsi->back->pdev->dev,
+                                       "Failed creating queue channel with TC%d: queues %d\n",
+                                       i, ch->num_queue_pairs);
+                               goto err_free;
+                       }
+                       vsi->tc_seid_map[i] = ch->seid;
+               }
+       }
+       return ret;
+
+err_free:
+       i40e_remove_queue_channels(vsi);
+       return ret;
+}
+
+/**
+ * i40e_validate_mqprio_qopt- validate queue mapping info
+ * @vsi: the VSI being configured
+ * @mqprio_qopt: queue parametrs
+ **/
+static int i40e_validate_mqprio_qopt(struct i40e_vsi *vsi,
+                                    struct tc_mqprio_qopt_offload *mqprio_qopt)
+{
+       u64 sum_max_rate = 0;
+       int i;
+
+       if (mqprio_qopt->qopt.offset[0] != 0 ||
+           mqprio_qopt->qopt.num_tc < 1 ||
+           mqprio_qopt->qopt.num_tc > I40E_MAX_TRAFFIC_CLASS)
+               return -EINVAL;
+       for (i = 0; ; i++) {
+               if (!mqprio_qopt->qopt.count[i])
+                       return -EINVAL;
+               if (mqprio_qopt->min_rate[i]) {
+                       dev_err(&vsi->back->pdev->dev,
+                               "Invalid min tx rate (greater than 0) specified\n");
+                       return -EINVAL;
+               }
+               sum_max_rate += (mqprio_qopt->max_rate[i] / (1000000 / 8));
+
+               if (i >= mqprio_qopt->qopt.num_tc - 1)
+                       break;
+               if (mqprio_qopt->qopt.offset[i + 1] !=
+                   (mqprio_qopt->qopt.offset[i] + mqprio_qopt->qopt.count[i]))
+                       return -EINVAL;
+       }
+       if (vsi->num_queue_pairs <
+           (mqprio_qopt->qopt.offset[i] + mqprio_qopt->qopt.count[i])) {
+               return -EINVAL;
+       }
+       if (sum_max_rate > i40e_get_link_speed(vsi)) {
+               dev_err(&vsi->back->pdev->dev,
+                       "Invalid max tx rate specified\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/**
+ * i40e_vsi_set_default_tc_config - set default values for tc configuration
+ * @vsi: the VSI being configured
+ **/
+static void i40e_vsi_set_default_tc_config(struct i40e_vsi *vsi)
+{
+       u16 qcount;
+       int i;
+
+       /* Only TC0 is enabled */
+       vsi->tc_config.numtc = 1;
+       vsi->tc_config.enabled_tc = 1;
+       qcount = min_t(int, vsi->alloc_queue_pairs,
+                      i40e_pf_get_max_q_per_tc(vsi->back));
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               /* For the TC that is not enabled set the offset to to default
+                * queue and allocate one queue for the given TC.
+                */
+               vsi->tc_config.tc_info[i].qoffset = 0;
+               if (i == 0)
+                       vsi->tc_config.tc_info[i].qcount = qcount;
+               else
+                       vsi->tc_config.tc_info[i].qcount = 1;
+               vsi->tc_config.tc_info[i].netdev_tc = 0;
+       }
+}
+
+/**
+ * i40e_rebuild_cloud_filters - Rebuilds cloud filters for VSIs
+ * @vsi: PF main vsi
+ * @seid: seid of main or channel VSIs
+ *
+ * Rebuilds cloud filters associated with main VSI and channel VSIs if they
+ * existed before reset
+ **/
+static int i40e_rebuild_cloud_filters(struct i40e_vsi *vsi, u16 seid)
+{
+       struct i40e_cloud_filter *cfilter;
+       struct i40e_pf *pf = vsi->back;
+       struct hlist_node *node;
+       i40e_status ret;
+
+       /* Add cloud filters back if they exist */
+       hlist_for_each_entry_safe(cfilter, node, &pf->cloud_filter_list,
+                                 cloud_node) {
+               if (cfilter->seid != seid)
+                       continue;
+
+               if (cfilter->dst_port)
+                       ret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter,
+                                                               true);
+               else
+                       ret = i40e_add_del_cloud_filter(vsi, cfilter, true);
+
+               if (ret) {
+                       dev_dbg(&pf->pdev->dev,
+                               "Failed to rebuild cloud filter, err %s aq_err %s\n",
+                               i40e_stat_str(&pf->hw, ret),
+                               i40e_aq_str(&pf->hw,
+                                           pf->hw.aq.asq_last_status));
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+/**
+ * i40e_rebuild_channels - Rebuilds channel VSIs if they existed before reset
+ * @vsi: PF main vsi
+ *
+ * Rebuilds channel VSIs if they existed before reset
+ **/
+static int i40e_rebuild_channels(struct i40e_vsi *vsi)
+{
+       struct i40e_channel *ch, *ch_tmp;
+       i40e_status ret;
+
+       if (list_empty(&vsi->ch_list))
+               return 0;
+
+       list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list, list) {
+               if (!ch->initialized)
+                       break;
+               /* Proceed with creation of channel (VMDq2) VSI */
+               ret = i40e_add_channel(vsi->back, vsi->uplink_seid, ch);
+               if (ret) {
+                       dev_info(&vsi->back->pdev->dev,
+                                "failed to rebuild channels using uplink_seid %u\n",
+                                vsi->uplink_seid);
+                       return ret;
+               }
+               if (ch->max_tx_rate) {
+                       if (i40e_set_bw_limit(vsi, ch->seid,
+                                             ch->max_tx_rate))
+                               return -EINVAL;
+
+                       dev_dbg(&vsi->back->pdev->dev,
+                               "Set tx rate of %llu Mbps (count of 50Mbps %llu) for vsi->seid %u\n",
+                               ch->max_tx_rate,
+                               ch->max_tx_rate / I40E_BW_CREDIT_DIVISOR,
+                               ch->seid);
+               }
+               ret = i40e_rebuild_cloud_filters(vsi, ch->seid);
+               if (ret) {
+                       dev_dbg(&vsi->back->pdev->dev,
+                               "Failed to rebuild cloud filters for channel VSI %u\n",
+                               ch->seid);
+                       return ret;
+               }
+       }
+       return 0;
+}
+#endif /* __TC_MQPRIO_MODE_MAX */
+
+#ifdef HAVE_SETUP_TC
+/**
+ * i40e_setup_tc - configure multiple traffic classes
+ * @netdev: net device to configure
+ * @type_data: tc offload data
+ **/
+#ifdef __TC_MQPRIO_MODE_MAX
+static int i40e_setup_tc(struct net_device *netdev, void *type_data)
+#else
+static int i40e_setup_tc(struct net_device *netdev, u8 tc)
+#endif
+{
+#ifdef __TC_MQPRIO_MODE_MAX
+       struct tc_mqprio_qopt_offload *mqprio_qopt = type_data;
+       bool need_reset = false;
+       u16 mode;
+       u8 hw;
+#endif
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       u8 enabled_tc = 0, num_tc;
+       int ret = -EINVAL;
+       int i;
+
+       /* Check if MFP enabled */
+       if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+               netdev_info(netdev,
+                           "Configuring TC not supported in MFP mode\n");
+               goto exit;
+       }
+
+#ifndef HAVE_NDO_SETUP_TC_REMOVE_TC_TO_NETDEV
+       /* Check whether tc count is within enabled limit */
+       if (tc > i40e_pf_get_num_tc(pf)) {
+               netdev_info(netdev, "TC count greater than enabled on link for adapter\n");
+               goto exit;
+       }
+#endif
+
+#ifdef __TC_MQPRIO_MODE_MAX
+       num_tc = mqprio_qopt->qopt.num_tc;
+       hw = mqprio_qopt->qopt.hw;
+       mode = mqprio_qopt->mode;
+       if (!hw) {
+               pf->flags &= ~I40E_FLAG_TC_MQPRIO;
+               memcpy(&vsi->mqprio_qopt, mqprio_qopt, sizeof(*mqprio_qopt));
+               goto config_tc;
+       }
+
+       switch (mode) {
+       case TC_MQPRIO_MODE_DCB:
+               pf->flags &= ~I40E_FLAG_TC_MQPRIO;
+
+               /* Check if DCB enabled to continue */
+               if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) {
+                       netdev_info(netdev,
+                                   "DCB is not enabled for adapter\n");
+                       return ret;
+               }
+
+               /* Check whether tc count is within enabled limit */
+               if (num_tc > i40e_pf_get_num_tc(pf)) {
+                       netdev_info(netdev,
+                                   "TC count greater than enabled on link for adapter\n");
+                       return ret;
+               }
+               break;
+       case TC_MQPRIO_MODE_CHANNEL:
+               if (pf->flags & I40E_FLAG_DCB_ENABLED) {
+                       netdev_info(netdev,
+                                   "Full offload of TC Mqprio options is not supported when DCB is enabled\n");
+                       return ret;
+               }
+               if (!(pf->flags & I40E_FLAG_MSIX_ENABLED))
+                       return ret;
+               ret = i40e_validate_mqprio_qopt(vsi, mqprio_qopt);
+               if (ret)
+                       return ret;
+               memcpy(&vsi->mqprio_qopt, mqprio_qopt,
+                      sizeof(*mqprio_qopt));
+               pf->flags |= I40E_FLAG_TC_MQPRIO;
+               pf->flags &= ~I40E_FLAG_DCB_ENABLED;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+config_tc:
+#else
+       /* Check if DCB enabled to continue */
+       if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) {
+               netdev_info(netdev, "DCB is not enabled for adapter\n");
+               goto exit;
+       }
+       num_tc = tc;
+#endif
+       /* Generate TC map for number of tc requested */
+       for (i = 0; i < num_tc; i++)
+               enabled_tc |= BIT(i);
+
+       /* Requesting same TC configuration as already enabled */
+#ifdef __TC_MQPRIO_MODE_MAX
+       if (enabled_tc == vsi->tc_config.enabled_tc &&
+           mode != TC_MQPRIO_MODE_CHANNEL)
+               return 0;
+#else
+       if (enabled_tc == vsi->tc_config.enabled_tc)
+               return 0;
+#endif
+
+       /* Quiesce VSI queues */
+       i40e_quiesce_vsi(vsi);
+
+#ifdef __TC_MQPRIO_MODE_MAX
+       if (!hw && !(pf->flags & I40E_FLAG_TC_MQPRIO))
+               i40e_remove_queue_channels(vsi);
+#endif
+
+       /* Configure VSI for enabled TCs */
+       ret = i40e_vsi_config_tc(vsi, enabled_tc);
+       if (ret) {
+               netdev_info(netdev, "Failed configuring TC for VSI seid=%d\n",
+                           vsi->seid);
+#ifdef __TC_MQPRIO_MODE_MAX
+               need_reset = true;
+#endif
+               goto exit;
+       }
+
+#ifdef __TC_MQPRIO_MODE_MAX
+       if (pf->flags & I40E_FLAG_TC_MQPRIO) {
+               if (vsi->mqprio_qopt.max_rate[0]) {
+                       u64 max_tx_rate = vsi->mqprio_qopt.max_rate[0] /
+                                                               (1000000 / 8);
+                       ret = i40e_set_bw_limit(vsi, vsi->seid, max_tx_rate);
+                       if (!ret) {
+                               dev_dbg(&vsi->back->pdev->dev,
+                                       "Set tx rate of %llu Mbps (count of 50Mbps %llu) for vsi->seid %u\n",
+                                       max_tx_rate,
+                                       max_tx_rate / I40E_BW_CREDIT_DIVISOR,
+                                       vsi->seid);
+                       } else {
+                               need_reset = true;
+                               goto exit;
+                       }
+               }
+               ret = i40e_configure_queue_channels(vsi);
+               if (ret) {
+                       netdev_info(netdev,
+                                   "Failed configuring queue channels\n");
+                       need_reset = true;
+                       goto exit;
+               }
+       }
+
+       /* Reset the configuration data to defaults, only TC0 is enabled */
+       if (need_reset) {
+               i40e_vsi_set_default_tc_config(vsi);
+               need_reset = false;
+       }
+#endif
+
+exit:
+       /* Unquiesce VSI */
+       i40e_unquiesce_vsi(vsi);
+       return ret;
+}
+
+#ifdef __TC_MQPRIO_MODE_MAX
+/**
+ * i40e_parse_cls_flower - Parse tc flower filters provided by kernel
+ * @vsi: Pointer to VSI
+ * @f: Pointer to struct tc_cls_flower_offload
+ * @filter: Pointer to cloud filter structure
+ *
+ **/
+static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
+                                struct tc_cls_flower_offload *f,
+                                struct i40e_cloud_filter *filter)
+{
+       u16 n_proto_mask = 0, n_proto_key = 0, addr_type = 0;
+       struct i40e_pf *pf = vsi->back;
+       u8 field_flags = 0;
+
+       if (f->dissector->used_keys &
+           ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
+             BIT(FLOW_DISSECTOR_KEY_BASIC) |
+             BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
+             BIT(FLOW_DISSECTOR_KEY_VLAN) |
+             BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
+             BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
+             BIT(FLOW_DISSECTOR_KEY_PORTS) |
+             BIT(FLOW_DISSECTOR_KEY_ENC_KEYID))) {
+               dev_err(&pf->pdev->dev, "Unsupported key used: 0x%x\n",
+                       f->dissector->used_keys);
+               return -EOPNOTSUPP;
+       }
+
+       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
+               struct flow_dissector_key_keyid *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_ENC_KEYID,
+                                                 f->key);
+
+               struct flow_dissector_key_keyid *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_ENC_KEYID,
+                                                 f->mask);
+
+               if (mask->keyid != 0)
+                       field_flags |= I40E_CLOUD_FIELD_TEN_ID;
+
+               filter->tenant_id = be32_to_cpu(key->keyid);
+       }
+
+       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
+               struct flow_dissector_key_basic *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_BASIC,
+                                                 f->key);
+
+               struct flow_dissector_key_basic *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_BASIC,
+                                                 f->mask);
+
+               n_proto_key = ntohs(key->n_proto);
+               n_proto_mask = ntohs(mask->n_proto);
+
+               if (n_proto_key == ETH_P_ALL) {
+                       n_proto_key = 0;
+                       n_proto_mask = 0;
+               }
+               filter->n_proto = n_proto_key & n_proto_mask;
+               filter->ip_proto = key->ip_proto;
+       }
+
+       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
+               struct flow_dissector_key_eth_addrs *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_ETH_ADDRS,
+                                                 f->key);
+
+               struct flow_dissector_key_eth_addrs *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_ETH_ADDRS,
+                                                 f->mask);
+
+               /* use is_broadcast and is_zero to check for all 0xf or 0 */
+               if (!is_zero_ether_addr(mask->dst)) {
+                       if (is_broadcast_ether_addr(mask->dst)) {
+                               field_flags |= I40E_CLOUD_FIELD_OMAC;
+                       } else {
+                               dev_err(&pf->pdev->dev, "Bad ether dest mask %pM\n",
+                                       mask->dst);
+                               return I40E_ERR_CONFIG;
+                       }
+               }
+
+               if (!is_zero_ether_addr(mask->src)) {
+                       if (is_broadcast_ether_addr(mask->src)) {
+                               field_flags |= I40E_CLOUD_FIELD_IMAC;
+                       } else {
+                               dev_err(&pf->pdev->dev, "Bad ether src mask %pM\n",
+                                       mask->src);
+                               return I40E_ERR_CONFIG;
+                       }
+               }
+               ether_addr_copy(filter->dst_mac, key->dst);
+               ether_addr_copy(filter->src_mac, key->src);
+       }
+
+       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
+               struct flow_dissector_key_vlan *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_VLAN,
+                                                 f->key);
+               struct flow_dissector_key_vlan *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_VLAN,
+                                                 f->mask);
+
+               if (mask->vlan_id) {
+                       if (mask->vlan_id == VLAN_VID_MASK) {
+                               field_flags |= I40E_CLOUD_FIELD_IVLAN;
+
+                       } else {
+                               dev_err(&pf->pdev->dev, "Bad vlan mask 0x%04x\n",
+                                       mask->vlan_id);
+                               return I40E_ERR_CONFIG;
+                       }
+               }
+
+               filter->vlan_id = cpu_to_be16(key->vlan_id);
+       }
+
+       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
+               struct flow_dissector_key_control *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_CONTROL,
+                                                 f->key);
+
+               addr_type = key->addr_type;
+       }
+
+       if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
+               struct flow_dissector_key_ipv4_addrs *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_IPV4_ADDRS,
+                                                 f->key);
+               struct flow_dissector_key_ipv4_addrs *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_IPV4_ADDRS,
+                                                 f->mask);
+
+               if (mask->dst) {
+                       if (mask->dst == cpu_to_be32(0xffffffff)) {
+                               field_flags |= I40E_CLOUD_FIELD_IIP;
+                       } else {
+                               dev_err(&pf->pdev->dev, "Bad ip dst mask %pI4b\n",
+                                       &mask->dst);
+                               return I40E_ERR_CONFIG;
+                       }
+               }
+
+               if (mask->src) {
+                       if (mask->src == cpu_to_be32(0xffffffff)) {
+                               field_flags |= I40E_CLOUD_FIELD_IIP;
+                       } else {
+                               dev_err(&pf->pdev->dev, "Bad ip src mask %pI4b\n",
+                                       &mask->src);
+                               return I40E_ERR_CONFIG;
+                       }
+               }
+
+               if (field_flags & I40E_CLOUD_FIELD_TEN_ID) {
+                       dev_err(&pf->pdev->dev, "Tenant id not allowed for ip filter\n");
+                       return I40E_ERR_CONFIG;
+               }
+               filter->dst_ipv4 = key->dst;
+               filter->src_ipv4 = key->src;
+       }
+
+       if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
+               struct flow_dissector_key_ipv6_addrs *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_IPV6_ADDRS,
+                                                 f->key);
+               struct flow_dissector_key_ipv6_addrs *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_IPV6_ADDRS,
+                                                 f->mask);
+
+               /* src and dest IPV6 address should not be LOOPBACK
+                * (0:0:0:0:0:0:0:1), which can be represented as ::1
+                */
+               if (ipv6_addr_loopback(&key->dst) ||
+                   ipv6_addr_loopback(&key->src)) {
+                       dev_err(&pf->pdev->dev,
+                               "Bad ipv6, addr is LOOPBACK\n");
+                       return I40E_ERR_CONFIG;
+               }
+               if (!ipv6_addr_any(&mask->dst) || !ipv6_addr_any(&mask->src))
+                       field_flags |= I40E_CLOUD_FIELD_IIP;
+
+               memcpy(&filter->src_ipv6, &key->src.s6_addr32,
+                      sizeof(filter->src_ipv6));
+               memcpy(&filter->dst_ipv6, &key->dst.s6_addr32,
+                      sizeof(filter->dst_ipv6));
+       }
+
+       if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
+               struct flow_dissector_key_ports *key =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_PORTS,
+                                                 f->key);
+               struct flow_dissector_key_ports *mask =
+                       skb_flow_dissector_target(f->dissector,
+                                                 FLOW_DISSECTOR_KEY_PORTS,
+                                                 f->mask);
+
+               if (mask->src) {
+                       if (mask->src == cpu_to_be16(0xffff)) {
+                               field_flags |= I40E_CLOUD_FIELD_IIP;
+                       } else {
+                               dev_err(&pf->pdev->dev, "Bad src port mask 0x%04x\n",
+                                       be16_to_cpu(mask->src));
+                               return I40E_ERR_CONFIG;
+                       }
+               }
+
+               if (mask->dst) {
+                       if (mask->dst == cpu_to_be16(0xffff)) {
+                               field_flags |= I40E_CLOUD_FIELD_IIP;
+                       } else {
+                               dev_err(&pf->pdev->dev, "Bad dst port mask 0x%04x\n",
+                                       be16_to_cpu(mask->dst));
+                               return I40E_ERR_CONFIG;
+                       }
+               }
+
+               filter->dst_port = key->dst;
+               filter->src_port = key->src;
+
+               switch (filter->ip_proto) {
+               case IPPROTO_TCP:
+               case IPPROTO_UDP:
+                       break;
+               default:
+                       dev_err(&pf->pdev->dev,
+                               "Only UDP and TCP transport are supported\n");
+                       return -EINVAL;
+               }
+       }
+       filter->flags = field_flags;
+       return 0;
+}
+
+/**
+ * i40e_handle_tclass: Forward to a traffic class on the device
+ * @vsi: Pointer to VSI
+ * @tc: traffic class index on the device
+ * @filter: Pointer to cloud filter structure
+ *
+ **/
+static int i40e_handle_tclass(struct i40e_vsi *vsi, u32 tc,
+                             struct i40e_cloud_filter *filter)
+{
+       struct i40e_channel *ch, *ch_tmp;
+
+       /* direct to a traffic class on the same device */
+       if (tc == 0) {
+               filter->seid = vsi->seid;
+               return 0;
+       } else if (vsi->tc_config.enabled_tc & BIT(tc)) {
+               if (!filter->dst_port) {
+                       dev_err(&vsi->back->pdev->dev,
+                               "Specify destination port to direct to traffic class that is not default\n");
+                       return -EINVAL;
+               }
+               if (list_empty(&vsi->ch_list))
+                       return -EINVAL;
+               list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list,
+                                        list) {
+                       if (ch->seid == vsi->tc_seid_map[tc])
+                               filter->seid = ch->seid;
+               }
+               return 0;
+       }
+       dev_err(&vsi->back->pdev->dev, "TC is not enabled\n");
+       return -EINVAL;
+}
+
+/**
+ * i40e_configure_clsflower - Configure tc flower filters
+ * @vsi: Pointer to VSI
+ * @cls_flower: Pointer to struct tc_cls_flower_offload
+ *
+ **/
+static int i40e_configure_clsflower(struct i40e_vsi *vsi,
+                                   struct tc_cls_flower_offload *cls_flower)
+{
+       int tc = tc_classid_to_hwtc(vsi->netdev, cls_flower->classid);
+       struct i40e_cloud_filter *filter = NULL;
+       struct i40e_pf *pf = vsi->back;
+       int err = 0;
+
+       if (tc < 0) {
+               dev_err(&vsi->back->pdev->dev, "Invalid traffic class\n");
+               return -EINVAL;
+       }
+
+       if (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state) ||
+           test_bit(__I40E_RESET_INTR_RECEIVED, pf->state))
+               return -EBUSY;
+
+       if (pf->fdir_pf_active_filters ||
+           (!hlist_empty(&pf->fdir_filter_list))) {
+               dev_err(&vsi->back->pdev->dev,
+                       "Flow Director Sideband filters exists, turn ntuple off to configure cloud filters\n");
+               return -EINVAL;
+       }
+
+       if (vsi->back->flags & I40E_FLAG_FD_SB_ENABLED) {
+               dev_err(&vsi->back->pdev->dev,
+                       "Disable Flow Director Sideband, configuring Cloud filters via tc-flower\n");
+               vsi->back->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+               vsi->back->flags |= I40E_FLAG_FD_SB_TO_CLOUD_FILTER;
+       }
+
+       filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+       if (!filter)
+               return -ENOMEM;
+
+       filter->cookie = cls_flower->cookie;
+
+       err = i40e_parse_cls_flower(vsi, cls_flower, filter);
+       if (err < 0)
+               goto err;
+
+       err = i40e_handle_tclass(vsi, tc, filter);
+       if (err < 0)
+               goto err;
+
+       /* Add cloud filter */
+       if (filter->dst_port)
+               err = i40e_add_del_cloud_filter_big_buf(vsi, filter, true);
+       else
+               err = i40e_add_del_cloud_filter(vsi, filter, true);
+
+       if (err) {
+               dev_err(&pf->pdev->dev,
+                       "Failed to add cloud filter, err %s\n",
+                       i40e_stat_str(&pf->hw, err));
+               goto err;
+       }
+
+       /* add filter to the ordered list */
+       INIT_HLIST_NODE(&filter->cloud_node);
+
+       hlist_add_head(&filter->cloud_node, &pf->cloud_filter_list);
+
+       pf->num_cloud_filters++;
+
+       return err;
+err:
+       kfree(filter);
+       return err;
+}
+
+/**
+ * i40e_find_cloud_filter - Find the could filter in the list
+ * @vsi: Pointer to VSI
+ * @cookie: filter specific cookie
+ *
+ **/
+static struct i40e_cloud_filter *i40e_find_cloud_filter(struct i40e_vsi *vsi,
+                                                       unsigned long *cookie)
+{
+       struct i40e_cloud_filter *filter = NULL;
+       struct hlist_node *node2;
+
+       hlist_for_each_entry_safe(filter, node2,
+                                 &vsi->back->cloud_filter_list, cloud_node)
+               if (!memcmp(cookie, &filter->cookie, sizeof(filter->cookie)))
+                       return filter;
+       return NULL;
+}
+
+/**
+ * i40e_delete_clsflower - Remove tc flower filters
+ * @vsi: Pointer to VSI
+ * @cls_flower: Pointer to struct tc_cls_flower_offload
+ *
+ **/
+static int i40e_delete_clsflower(struct i40e_vsi *vsi,
+                                struct tc_cls_flower_offload *cls_flower)
+{
+       struct i40e_cloud_filter *filter = NULL;
+       struct i40e_pf *pf = vsi->back;
+       int err = 0;
+
+       filter = i40e_find_cloud_filter(vsi, &cls_flower->cookie);
+
+       if (!filter)
+               return -EINVAL;
+
+       hash_del(&filter->cloud_node);
+
+       if (filter->dst_port)
+               err = i40e_add_del_cloud_filter_big_buf(vsi, filter, false);
+       else
+               err = i40e_add_del_cloud_filter(vsi, filter, false);
+
+       kfree(filter);
+       if (err) {
+               dev_err(&pf->pdev->dev,
+                       "Failed to delete cloud filter, err %s\n",
+                       i40e_stat_str(&pf->hw, err));
+               return i40e_aq_rc_to_posix(err, pf->hw.aq.asq_last_status);
+       }
+
+       pf->num_cloud_filters--;
+       if (!pf->num_cloud_filters)
+               if ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&
+                   !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {
+                       pf->flags |= I40E_FLAG_FD_SB_ENABLED;
+                       pf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;
+                       pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;
+               }
+       return 0;
+}
+
+/**
+ * i40e_setup_tc_cls_flower - flower classifier offloads
+ * @np: net device to configure
+ * @cls_flower: pointer to cls flower offload structure
+ **/
+static int i40e_setup_tc_cls_flower(struct i40e_netdev_priv *np,
+                                   struct tc_cls_flower_offload *cls_flower)
+{
+       struct i40e_vsi *vsi = np->vsi;
+
+       if (cls_flower->common.chain_index)
+               return -EOPNOTSUPP;
+
+       switch (cls_flower->command) {
+       case TC_CLSFLOWER_REPLACE:
+               return i40e_configure_clsflower(vsi, cls_flower);
+       case TC_CLSFLOWER_DESTROY:
+               return i40e_delete_clsflower(vsi, cls_flower);
+       case TC_CLSFLOWER_STATS:
+               return -EOPNOTSUPP;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int i40e_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
+                                 void *cb_priv)
+{
+       struct i40e_netdev_priv *np = cb_priv;
+
+       switch (type) {
+       case TC_SETUP_CLSFLOWER:
+               return i40e_setup_tc_cls_flower(np, type_data);
+
+       default:
+               return -EOPNOTSUPP;
        }
+}
 
-       /* Unquiesce VSI */
-       i40e_unquiesce_vsi(vsi);
+static int i40e_setup_tc_block(struct net_device *dev,
+                              struct tc_block_offload *f)
+{
+       struct i40e_netdev_priv *np = netdev_priv(dev);
 
-exit:
-       return ret;
+       if (f->binder_type != TCF_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
+               return -EOPNOTSUPP;
+
+       switch (f->command) {
+       case TC_BLOCK_BIND:
+#ifdef HAVE_TCF_BLOCK_CB_REGISTER_EXTACK
+               return tcf_block_cb_register(f->block, i40e_setup_tc_block_cb,
+                                            np, np, f->extack);
+#else
+               return tcf_block_cb_register(f->block, i40e_setup_tc_block_cb,
+                                            np, np);
+#endif
+       case TC_BLOCK_UNBIND:
+               tcf_block_cb_unregister(f->block, i40e_setup_tc_block_cb, np);
+               return 0;
+       default:
+               return -EOPNOTSUPP;
+       }
 }
+#endif
 
 #ifdef NETIF_F_HW_TC
 #ifdef HAVE_NDO_SETUP_TC_REMOVE_TC_TO_NETDEV
@@ -5916,14 +8103,25 @@ static int __i40e_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
 #endif
 {
 #ifdef HAVE_NDO_SETUP_TC_REMOVE_TC_TO_NETDEV
+#ifndef __TC_MQPRIO_MODE_MAX
        struct tc_mqprio_qopt *mqprio = type_data;
+#endif
 #else
 #ifdef TC_MQPRIO_HW_OFFLOAD_MAX
        struct tc_mqprio_qopt *mqprio = tc->mqprio;
 #endif /* TC_MQPRIO_HW_OFFLOAD_MAX*/
        unsigned int type = tc->type;
 #endif /* HAVE_NDO_SETUP_TC_REMOVE_TC_TO_NETDEV */
-
+#ifdef __TC_MQPRIO_MODE_MAX
+       switch (type) {
+       case TC_SETUP_QDISC_MQPRIO:
+               return i40e_setup_tc(netdev, type_data);
+       case TC_SETUP_BLOCK:
+               return i40e_setup_tc_block(netdev, type_data);
+       default:
+               return -EOPNOTSUPP;
+       }
+#else
        if (type != TC_SETUP_QDISC_MQPRIO)
                return -EINVAL;
 
@@ -5933,7 +8131,8 @@ static int __i40e_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
        return i40e_setup_tc(netdev, mqprio->num_tc);
 #else
        return i40e_setup_tc(netdev, tc->tc);
-#endif
+#endif /* TC_MQPRIO_HW_OFFLOAD_MAX */
+#endif /* __TC_MQPRIO_MODE_MAX */
 }
 #endif /* NETIF_F_HW_TC */
 #endif /* HAVE_SETUP_TC */
@@ -5964,7 +8163,8 @@ int i40e_open(struct net_device *netdev)
 
        netif_carrier_off(netdev);
 
-       i40e_force_link_state(pf, true);
+       if (i40e_force_link_state(pf, true))
+               return -EAGAIN;
 
        err = i40e_vsi_open(vsi);
        if (err)
@@ -6065,7 +8265,7 @@ err_setup_rx:
 err_setup_tx:
        i40e_vsi_free_tx_resources(vsi);
        if (vsi == pf->vsi[pf->lan_vsi])
-               i40e_do_reset(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED), true);
+               i40e_do_reset(pf, I40E_PF_RESET_FLAG, true);
 
        return err;
 }
@@ -6147,6 +8347,13 @@ static void i40e_cloud_filter_exit(struct i40e_pf *pf)
                kfree(cfilter);
        }
        pf->num_cloud_filters = 0;
+
+       if ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&
+           !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {
+               pf->flags |= I40E_FLAG_FD_SB_ENABLED;
+               pf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;
+               pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;
+       }
 }
 
 /**
@@ -6215,7 +8422,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags, bool lock_acquired)
                wr32(&pf->hw, I40E_GLGEN_RTRIG, val);
                i40e_flush(&pf->hw);
 
-       } else if (reset_flags & BIT_ULL(__I40E_PF_RESET_REQUESTED)) {
+       } else if (reset_flags & I40E_PF_RESET_FLAG) {
 
                /* Request a PF Reset
                 *
@@ -6431,8 +8638,8 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
                i40e_service_event_schedule(pf);
        } else {
                i40e_pf_unquiesce_all_vsi(pf);
-       pf->flags |= (I40E_FLAG_SERVICE_CLIENT_REQUESTED |
-                     I40E_FLAG_CLIENT_L2_CHANGE);
+       set_bit(__I40E_CLIENT_SERVICE_REQUESTED, pf->state);
+       set_bit(__I40E_CLIENT_L2_CHANGE, pf->state);
        }
 
 exit:
@@ -6519,6 +8726,94 @@ u32 i40e_get_global_fd_count(struct i40e_pf *pf)
        return fcnt_prog;
 }
 
+/**
+ * i40e_reenable_fdir_sb - Restore FDir SB capability
+ * @pf: board private structure
+ **/
+static void i40e_reenable_fdir_sb(struct i40e_pf *pf)
+{
+       if (test_and_clear_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state))
+               if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
+                   (I40E_DEBUG_FD & pf->hw.debug_mask))
+                       dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
+}
+
+/**
+ * i40e_reenable_fdir_atr - Restore FDir ATR capability
+ * @pf: board private structure
+ **/
+static void i40e_reenable_fdir_atr(struct i40e_pf *pf)
+{
+       if (test_and_clear_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state)) {
+               /* ATR uses the same filtering logic as SB rules. It only
+                * functions properly if the input set mask is at the default
+                * settings. It is safe to restore the default input set
+                * because there are no active TCPv4 filter rules.
+                */
+               i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_OTHER,
+                                       I40E_L3_SRC_MASK | I40E_L3_DST_MASK |
+                                       I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
+               i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_SCTP,
+                                       I40E_L3_SRC_MASK | I40E_L3_DST_MASK |
+                                       I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
+               i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_TCP,
+                                       I40E_L3_SRC_MASK | I40E_L3_DST_MASK |
+                                       I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
+               i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_UDP,
+                                       I40E_L3_SRC_MASK | I40E_L3_DST_MASK |
+                                       I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
+
+               if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+                   (I40E_DEBUG_FD & pf->hw.debug_mask))
+                       dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table and there are no conflicting ntuple rules\n");
+       }
+}
+
+/**
+ * i40e_delete_invalid_filter - Delete an invalid FDIR filter
+ * @pf: board private structure
+ * @filter: FDir filter to remove
+ */
+static void i40e_delete_invalid_filter(struct i40e_pf *pf,
+                                      struct i40e_fdir_filter *filter)
+{
+       /* Update counters */
+       pf->fdir_pf_active_filters--;
+       pf->fd_inv = 0;
+
+       switch (filter->flow_type) {
+       case TCP_V4_FLOW:
+               pf->fd_tcp4_filter_cnt--;
+               break;
+       case UDP_V4_FLOW:
+               pf->fd_udp4_filter_cnt--;
+               break;
+       case SCTP_V4_FLOW:
+               pf->fd_sctp4_filter_cnt--;
+               break;
+       case IP_USER_FLOW:
+               switch (filter->ip4_proto) {
+               case IPPROTO_TCP:
+                       pf->fd_tcp4_filter_cnt--;
+                       break;
+               case IPPROTO_UDP:
+                       pf->fd_udp4_filter_cnt--;
+                       break;
+               case IPPROTO_SCTP:
+                       pf->fd_sctp4_filter_cnt--;
+                       break;
+               case IPPROTO_IP:
+                       pf->fd_ip4_filter_cnt--;
+                       break;
+               }
+               break;
+       }
+
+       /* Remove the filter from the list and free memory */
+       hlist_del(&filter->fdir_node);
+       kfree(filter);
+}
+
 /**
  * i40e_fdir_check_and_reenable - Function to reenabe FD ATR or SB if disabled
  * @pf: board private structure
@@ -6537,40 +8832,26 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
        fcnt_avail = pf->fdir_pf_filter_count;
        if ((fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) ||
            (pf->fd_add_err == 0) ||
-           (i40e_get_current_atr_cnt(pf) < pf->fd_atr_cnt)) {
-               if (pf->flags & I40E_FLAG_FD_SB_AUTO_DISABLED) {
-                       pf->flags &= ~I40E_FLAG_FD_SB_AUTO_DISABLED;
-                       if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
-                           (I40E_DEBUG_FD & pf->hw.debug_mask))
-                               dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
-               }
-       }
+           (i40e_get_current_atr_cnt(pf) < pf->fd_atr_cnt))
+               i40e_reenable_fdir_sb(pf);
 
        /* We should wait for even more space before re-enabling ATR.
         * Additionally, we cannot enable ATR as long as we still have TCP SB
         * rules active.
         */
        if ((fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM_FOR_ATR)) &&
-           (pf->fd_tcp4_filter_cnt == 0)) {
-               if (pf->flags & I40E_FLAG_FD_ATR_AUTO_DISABLED) {
-                       pf->flags &= ~I40E_FLAG_FD_ATR_AUTO_DISABLED;
-                       if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
-                           (I40E_DEBUG_FD & pf->hw.debug_mask))
-                               dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table and there are no conflicting ntuple rules\n");
-               }
-       }
+                         !pf->fd_sctp4_filter_cnt &&
+                         !pf->fd_tcp4_filter_cnt &&
+                         !pf->fd_udp4_filter_cnt &&
+                         !pf->fd_ip4_filter_cnt)
+               i40e_reenable_fdir_atr(pf);
 
        /* if hw had a problem adding a filter, delete it */
        if (pf->fd_inv > 0) {
                hlist_for_each_entry_safe(filter, node,
-                                         &pf->fdir_filter_list, fdir_node) {
-                       if (filter->fd_id == pf->fd_inv) {
-                               hlist_del(&filter->fdir_node);
-                               kfree(filter);
-                               pf->fdir_pf_active_filters--;
-                               pf->fd_inv = 0;
-                       }
-               }
+                                         &pf->fdir_filter_list, fdir_node)
+                       if (filter->fd_id == pf->fd_inv)
+                               i40e_delete_invalid_filter(pf, filter);
        }
 }
 
@@ -6607,7 +8888,7 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf)
        }
 
        pf->fd_flush_timestamp = jiffies;
-       pf->flags |= I40E_FLAG_FD_ATR_AUTO_DISABLED;
+       set_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state);
        /* flush all filters */
        wr32(&pf->hw, I40E_PFQF_CTL_1,
             I40E_PFQF_CTL_1_CLEARFDTABLE_MASK);
@@ -6627,8 +8908,12 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf)
        } else {
                /* replay sideband filters */
                i40e_fdir_filter_restore(pf->vsi[pf->lan_vsi]);
-               if (!disable_atr && !pf->fd_tcp4_filter_cnt)
-                       pf->flags &= ~I40E_FLAG_FD_ATR_AUTO_DISABLED;
+               if (!disable_atr &&
+                   !pf->fd_sctp4_filter_cnt &&
+                   !pf->fd_tcp4_filter_cnt &&
+                   !pf->fd_udp4_filter_cnt &&
+                   !pf->fd_ip4_filter_cnt)
+                       clear_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state);
                clear_bit(__I40E_FD_FLUSH_REQUESTED, pf->state);
                if (I40E_DEBUG_FD & pf->hw.debug_mask)
                        dev_info(&pf->pdev->dev, "FD Filter table flushed and FD-SB replayed.\n");
@@ -6739,25 +9024,19 @@ static void i40e_link_event(struct i40e_pf *pf)
        i40e_status status;
        bool new_link, old_link;
 
-       /* save off old link status information */
-       pf->hw.phy.link_info_old = pf->hw.phy.link_info;
-
        /* set this to force the get_link_status call to refresh state */
        pf->hw.phy.get_link_info = true;
-
        old_link = (pf->hw.phy.link_info_old.link_info & I40E_AQ_LINK_UP);
-
        status = i40e_get_link_status(&pf->hw, &new_link);
 
        /* On success, disable temp link polling */
        if (status == I40E_SUCCESS) {
-               if (pf->flags & I40E_FLAG_TEMP_LINK_POLLING)
-                       pf->flags &= ~I40E_FLAG_TEMP_LINK_POLLING;
+               clear_bit(__I40E_TEMP_LINK_POLLING, pf->state);
        } else {
                /* Enable link polling temporarily until i40e_get_link_status
                 * returns I40E_SUCCESS
                 */
-               pf->flags |= I40E_FLAG_TEMP_LINK_POLLING;
+               set_bit(__I40E_TEMP_LINK_POLLING, pf->state);
                dev_dbg(&pf->pdev->dev, "couldn't get link state, status: %d\n",
                        status);
                return;
@@ -6811,7 +9090,7 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf)
        pf->service_timer_previous = jiffies;
 
        if ((pf->flags & I40E_FLAG_LINK_POLLING_ENABLED) ||
-           (pf->flags & I40E_FLAG_TEMP_LINK_POLLING))
+           test_bit(__I40E_TEMP_LINK_POLLING, pf->state))
                i40e_link_event(pf);
 
        /* Update the stats for active netdevs so the network stack
@@ -7258,8 +9537,10 @@ end_reconstitute:
 /**
  * i40e_get_capabilities - get info about the HW
  * @pf: the PF struct
+ * @list_type: admin queue opcode list type
  **/
-static int i40e_get_capabilities(struct i40e_pf *pf)
+static int i40e_get_capabilities(struct i40e_pf *pf,
+                                enum i40e_admin_queue_opc list_type)
 {
        struct i40e_aqc_list_capabilities_element_resp *cap_buf;
        u16 data_size;
@@ -7274,9 +9555,8 @@ static int i40e_get_capabilities(struct i40e_pf *pf)
 
                /* this loads the data into the hw struct for us */
                err = i40e_aq_discover_capabilities(&pf->hw, cap_buf, buf_len,
-                                           &data_size,
-                                           i40e_aqc_opc_list_func_capabilities,
-                                           NULL);
+                                                   &data_size, list_type,
+                                                   NULL);
                /* data loaded, buffer no longer needed */
                kfree(cap_buf);
 
@@ -7293,16 +9573,33 @@ static int i40e_get_capabilities(struct i40e_pf *pf)
                }
        } while (err);
 
-       if (pf->hw.debug_mask & I40E_DEBUG_USER)
-               dev_info(&pf->pdev->dev,
-                        "pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\n",
-                        pf->hw.pf_id, pf->hw.func_caps.num_vfs,
-                        pf->hw.func_caps.num_msix_vectors,
-                        pf->hw.func_caps.num_msix_vectors_vf,
-                        pf->hw.func_caps.fd_filters_guaranteed,
-                        pf->hw.func_caps.fd_filters_best_effort,
-                        pf->hw.func_caps.num_tx_qp,
-                        pf->hw.func_caps.num_vsis);
+       if (pf->hw.debug_mask & I40E_DEBUG_USER) {
+               if (list_type == i40e_aqc_opc_list_func_capabilities) {
+                       dev_info(&pf->pdev->dev,
+                                "pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\n",
+                                pf->hw.pf_id, pf->hw.func_caps.num_vfs,
+                                pf->hw.func_caps.num_msix_vectors,
+                                pf->hw.func_caps.num_msix_vectors_vf,
+                                pf->hw.func_caps.fd_filters_guaranteed,
+                                pf->hw.func_caps.fd_filters_best_effort,
+                                pf->hw.func_caps.num_tx_qp,
+                                pf->hw.func_caps.num_vsis);
+               } else if (list_type == i40e_aqc_opc_list_dev_capabilities) {
+                       dev_info(&pf->pdev->dev,
+                                "switch_mode=0x%04x, function_valid=0x%08x\n",
+                                pf->hw.dev_caps.switch_mode,
+                                pf->hw.dev_caps.valid_functions);
+                       dev_info(&pf->pdev->dev,
+                                "SR-IOV=%d, num_vfs for all function=%u\n",
+                                pf->hw.dev_caps.sr_iov_1_1,
+                                pf->hw.dev_caps.num_vfs);
+                       dev_info(&pf->pdev->dev,
+                                "num_vsis=%u, num_rx:%u, num_tx=%u\n",
+                                pf->hw.dev_caps.num_vsis,
+                                pf->hw.dev_caps.num_rx_qp,
+                                pf->hw.dev_caps.num_tx_qp);
+               }
+       }
 
        return 0;
 }
@@ -7330,6 +9627,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
                if (!vsi) {
                        dev_info(&pf->pdev->dev, "Couldn't create FDir VSI\n");
                        pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+                       pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
                        return;
                }
        }
@@ -7489,13 +9787,24 @@ static int i40e_reset(struct i40e_pf *pf)
  **/
 static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
 {
+       int old_recovery_mode_bit = test_bit(__I40E_RECOVERY_MODE, pf->state);
+       struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
        struct i40e_hw *hw = &pf->hw;
        u8 set_fc_aq_fail = 0;
        i40e_status ret;
        u32 val;
        int v;
 
-       if (test_bit(__I40E_DOWN, pf->state))
+       if (test_bit(__I40E_EMP_RESET_INTR_RECEIVED, pf->state) &&
+           i40e_check_recovery_mode(pf)) {
+#ifdef SIOCETHTOOL
+               i40e_set_ethtool_ops(pf->vsi[pf->lan_vsi]->netdev);
+#endif
+       }
+
+       if (test_bit(__I40E_DOWN, pf->state) &&
+           !test_bit(__I40E_RECOVERY_MODE, pf->state) &&
+           !old_recovery_mode_bit)
                goto clear_recovery;
        dev_dbg(&pf->pdev->dev, "Rebuilding internal switch\n");
 
@@ -7525,8 +9834,46 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
                i40e_verify_eeprom(pf);
        }
 
+       /* if we are going out of or into recovery mode we have to act
+        * accordingly with regard to resources initialization
+        * and deinitialization
+        */
+       if (test_bit(__I40E_RECOVERY_MODE, pf->state) ||
+           old_recovery_mode_bit) {
+               if (i40e_get_capabilities(pf,
+                                         i40e_aqc_opc_list_func_capabilities))
+                       goto end_unlock;
+
+               if (test_bit(__I40E_RECOVERY_MODE, pf->state)) {
+                       /* we're staying in recovery mode so we'll reinitialize
+                        * misc vector here
+                        */
+                       if (i40e_setup_misc_vector_for_recovery_mode(pf))
+                               goto end_unlock;
+               } else {
+                       if (!lock_acquired)
+                               rtnl_lock();
+                       /* we're going out of recovery mode so we'll free
+                        * the IRQ allocated specifically for recovery mode
+                        * and restore the interrupt scheme
+                        */
+                       free_irq(pf->pdev->irq, pf);
+                       i40e_clear_interrupt_scheme(pf);
+                       if (i40e_restore_interrupt_scheme(pf))
+                               goto end_unlock;
+               }
+
+               /* tell the firmware that we're starting */
+               i40e_send_version(pf);
+
+               /* bail out in case recovery mode was detected, as there is
+                * no need for further configuration.
+                */
+               goto end_unlock;
+       }
+
        i40e_clear_pxe_mode(hw);
-       ret = i40e_get_capabilities(pf);
+       ret = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);
        if (ret)
                goto end_core_reset;
 
@@ -7587,7 +9934,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
         * If there were VEBs but the reconstitution failed, we'll try
         * try to recover minimal use by getting the basic PF VSI working.
         */
-       if (pf->vsi[pf->lan_vsi]->uplink_seid != pf->mac_seid) {
+       if (vsi->uplink_seid != pf->mac_seid) {
                dev_dbg(&pf->pdev->dev, "attempting to rebuild switch\n");
                /* find the one VEB connected to the MAC, and find orphans */
                for (v = 0; v < I40E_MAX_VEB; v++) {
@@ -7611,8 +9958,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
                                        dev_info(&pf->pdev->dev,
                                                 "rebuild of switch failed: %d, will try to set up simple PF connection\n",
                                                 ret);
-                                       pf->vsi[pf->lan_vsi]->uplink_seid
-                                                               = pf->mac_seid;
+                                       vsi->uplink_seid = pf->mac_seid;
                                        break;
                                } else if (pf->veb[v]->uplink_seid == 0) {
                                        dev_info(&pf->pdev->dev,
@@ -7623,10 +9969,10 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
                }
        }
 
-       if (pf->vsi[pf->lan_vsi]->uplink_seid == pf->mac_seid) {
+       if (vsi->uplink_seid == pf->mac_seid) {
                dev_dbg(&pf->pdev->dev, "attempting to rebuild PF VSI\n");
                /* no VEB, so rebuild only the Main VSI */
-               ret = i40e_add_vsi(pf->vsi[pf->lan_vsi]);
+               ret = i40e_add_vsi(vsi);
                if (ret) {
                        dev_info(&pf->pdev->dev,
                                 "rebuild of Main VSI failed: %d\n", ret);
@@ -7634,6 +9980,31 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)
                }
        }
 
+#ifdef __TC_MQPRIO_MODE_MAX
+       if (vsi->mqprio_qopt.max_rate[0]) {
+               u64 max_tx_rate = vsi->mqprio_qopt.max_rate[0] / (1000000 / 8);
+
+               ret = i40e_set_bw_limit(vsi, vsi->seid, max_tx_rate);
+               if (!ret)
+                       dev_dbg(&vsi->back->pdev->dev,
+                               "Set tx rate of %llu Mbps (count of 50Mbps %llu) for vsi->seid %u\n",
+                               max_tx_rate,
+                               max_tx_rate / I40E_BW_CREDIT_DIVISOR,
+                               vsi->seid);
+               else
+                       goto end_unlock;
+       }
+#endif
+
+#ifdef __TC_MQPRIO_MODE_MAX
+       /* PF Main VSI is rebuild by now, go ahead and rebuild channel VSIs
+        * for this main VSI if they exist
+        */
+       ret = i40e_rebuild_channels(vsi);
+       if (ret)
+               goto end_unlock;
+#endif
+
        /* Reconfigure hardware for allowing smaller MSS in the case
         * of TSO, so that we avoid the MDD being fired and causing
         * a reset in the case of small MSS+TSO.
@@ -7850,9 +10221,9 @@ static void i40e_handle_mdd_event(struct i40e_pf *pf)
 
 #if defined(HAVE_VXLAN_RX_OFFLOAD) || defined(HAVE_UDP_ENC_RX_OFFLOAD)
 #if defined(HAVE_UDP_ENC_TUNNEL) || defined(HAVE_UDP_ENC_RX_OFFLOAD)
-static const char *i40e_tunnel_name(struct i40e_udp_port_config *port)
+static const char *i40e_tunnel_name(u8 type)
 {
-       switch (port->type) {
+       switch (type) {
        case UDP_TUNNEL_TYPE_VXLAN:
                return "vxlan";
        case UDP_TUNNEL_TYPE_GENEVE:
@@ -7876,7 +10247,7 @@ static void i40e_sync_udp_filters(struct i40e_pf *pf)
                        pf->pending_udp_bitmap |= BIT_ULL(i);
        }
 
-       pf->flags |= I40E_FLAG_UDP_FILTER_SYNC;
+       set_bit(__I40E_UDP_FILTER_SYNC_PENDING, pf->state);
 }
 
 /**
@@ -7886,39 +10257,68 @@ static void i40e_sync_udp_filters(struct i40e_pf *pf)
 static void i40e_sync_udp_filters_subtask(struct i40e_pf *pf)
 {
        struct i40e_hw *hw = &pf->hw;
-       i40e_status ret;
+       u8 filter_index, type;
        u16 port;
        int i;
 
-       if (!(pf->flags & I40E_FLAG_UDP_FILTER_SYNC))
+       if (!test_and_clear_bit(__I40E_UDP_FILTER_SYNC_PENDING, pf->state))
                return;
 
-       pf->flags &= ~I40E_FLAG_UDP_FILTER_SYNC;
+       /* acquire RTNL to maintain state of flags and port requests */
+       rtnl_lock();
 
        for (i = 0; i < I40E_MAX_PF_UDP_OFFLOAD_PORTS; i++) {
                if (pf->pending_udp_bitmap & BIT_ULL(i)) {
+                       struct i40e_udp_port_config *udp_port;
+                       i40e_status ret = 0;
+
+                       udp_port = &pf->udp_ports[i];
                        pf->pending_udp_bitmap &= ~BIT_ULL(i);
-                       port = pf->udp_ports[i].port;
+
+                       port = READ_ONCE(udp_port->port);
+                       type = READ_ONCE(udp_port->type);
+                       filter_index = READ_ONCE(udp_port->filter_index);
+
+                       /* release RTNL while we wait on AQ command */
+                       rtnl_unlock();
+
                        if (port)
                                ret = i40e_aq_add_udp_tunnel(hw, port,
-                                                       pf->udp_ports[i].type,
-                                                       NULL, NULL);
-                       else
-                               ret = i40e_aq_del_udp_tunnel(hw, i, NULL);
+                                                            type,
+                                                            &filter_index,
+                                                            NULL);
+                       else if (filter_index != I40E_UDP_PORT_INDEX_UNUSED)
+                               ret = i40e_aq_del_udp_tunnel(hw, filter_index,
+                                                            NULL);
+
+                       /* reacquire RTNL so we can update filter_index */
+                       rtnl_lock();
 
                        if (ret) {
                                dev_info(&pf->pdev->dev,
                                         "%s %s port %d, index %d failed, err %s aq_err %s\n",
-                                        i40e_tunnel_name(&pf->udp_ports[i]),
+                                        i40e_tunnel_name(type),
                                         port ? "add" : "delete",
-                                        port, i,
+                                        port,
+                                        filter_index,
                                         i40e_stat_str(&pf->hw, ret),
                                         i40e_aq_str(&pf->hw,
                                                    pf->hw.aq.asq_last_status));
-                               pf->udp_ports[i].port = 0;
+                               if (port) {
+                                       /* failed to add, just reset port,
+                                        * drop pending bit for any deletion
+                                        */
+                                       udp_port->port = 0;
+                                       pf->pending_udp_bitmap &= ~BIT_ULL(i);
+                               }
+                       } else if (port) {
+                               /* record filter index on success */
+                               udp_port->filter_index = filter_index;
                        }
                }
        }
+
+       rtnl_unlock();
 }
 
 #endif /* HAVE_UDP_ENC_TUNNEL || HAVE_UDP_ENC_RX_OFFLOAD */
@@ -7944,32 +10344,34 @@ static void i40e_service_task(struct work_struct *work)
        if (test_and_set_bit(__I40E_SERVICE_SCHED, pf->state))
                return;
 
-       i40e_detect_recover_hung(pf->vsi[pf->lan_vsi]);
-       i40e_sync_filters_subtask(pf);
-       i40e_reset_subtask(pf);
-       i40e_handle_mdd_event(pf);
-       i40e_vc_process_vflr_event(pf);
-       i40e_watchdog_subtask(pf);
-       i40e_fdir_reinit_subtask(pf);
-       if (pf->flags & I40E_FLAG_CLIENT_RESET) {
-               /* Client subtask will reopen next time through. */
-               i40e_notify_client_of_netdev_close(
-                                       pf->vsi[pf->lan_vsi], true);
-               pf->flags &= ~I40E_FLAG_CLIENT_RESET;
-       } else {
-               i40e_client_subtask(pf);
-               if (pf->flags & I40E_FLAG_CLIENT_L2_CHANGE) {
-                       i40e_notify_client_of_l2_param_changes(
-                                               pf->vsi[pf->lan_vsi]);
-                       pf->flags &= ~I40E_FLAG_CLIENT_L2_CHANGE;
+       if (!test_bit(__I40E_RECOVERY_MODE, pf->state)) {
+               i40e_detect_recover_hung(pf->vsi[pf->lan_vsi]);
+               i40e_sync_filters_subtask(pf);
+               i40e_reset_subtask(pf);
+               i40e_handle_mdd_event(pf);
+               i40e_vc_process_vflr_event(pf);
+               i40e_watchdog_subtask(pf);
+               i40e_fdir_reinit_subtask(pf);
+               if (test_and_clear_bit(__I40E_CLIENT_RESET, pf->state)) {
+                       /* Client subtask will reopen next time through. */
+                       i40e_notify_client_of_netdev_close(
+                                               pf->vsi[pf->lan_vsi], true);
+               } else {
+                       i40e_client_subtask(pf);
+                       if (test_and_clear_bit(__I40E_CLIENT_L2_CHANGE,
+                                              pf->state))
+                               i40e_notify_client_of_l2_param_changes(
+                                                       pf->vsi[pf->lan_vsi]);
                }
-       }
 #if defined(HAVE_VXLAN_RX_OFFLOAD) || defined(HAVE_UDP_ENC_RX_OFFLOAD)
 #if defined(HAVE_UDP_ENC_TUNNEL) || defined(HAVE_UDP_ENC_RX_OFFLOAD)
-       i40e_sync_udp_filters_subtask(pf);
+               i40e_sync_udp_filters_subtask(pf);
 
 #endif
 #endif /* HAVE_VXLAN_RX_OFFLOAD || HAVE_UDP_ENC_RX_OFFLOAD */
+       } else {
+               i40e_reset_subtask(pf);
+       }
 
        i40e_clean_adminq_subtask(pf);
 
@@ -8052,7 +10454,7 @@ static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi)
 
 /**
  * i40e_vsi_alloc_arrays - Allocate queue and vector pointer arrays for the vsi
- * @type: VSI pointer
+ * @vsi: VSI pointer
  * @alloc_qvectors: a bool to specify if q_vectors need to be allocated.
  *
  * On error: returns error code (negative)
@@ -8060,15 +10462,23 @@ static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi)
  **/
 static int i40e_vsi_alloc_arrays(struct i40e_vsi *vsi, bool alloc_qvectors)
 {
+       struct i40e_ring **next_rings;
        int size;
        int ret = 0;
 
-       /* allocate memory for both Tx and Rx ring pointers */
-       size = sizeof(struct i40e_ring *) * vsi->alloc_queue_pairs * 2;
+       /* allocate memory for both Tx, XDP Tx and Rx ring pointers */
+       size = sizeof(struct i40e_ring *) * vsi->alloc_queue_pairs *
+              (i40e_enabled_xdp_vsi(vsi) ? 3 : 2);
+
        vsi->tx_rings = kzalloc(size, GFP_KERNEL);
        if (!vsi->tx_rings)
                return -ENOMEM;
-       vsi->rx_rings = &vsi->tx_rings[vsi->alloc_queue_pairs];
+       next_rings = vsi->tx_rings + vsi->alloc_queue_pairs;
+       if (i40e_enabled_xdp_vsi(vsi)) {
+               vsi->xdp_rings = next_rings;
+               next_rings += vsi->alloc_queue_pairs;
+       }
+       vsi->rx_rings = next_rings;
 
        if (alloc_qvectors) {
                /* allocate memory for q_vector pointers */
@@ -8175,7 +10585,7 @@ unlock_pf:
 
 /**
  * i40e_vsi_free_arrays - Free queue and vector pointer arrays for the VSI
- * @type: VSI pointer
+ * @vsi: VSI pointer
  * @free_qvectors: a bool to specify if q_vectors need to be freed.
  *
  * On error: returns error code (negative)
@@ -8191,6 +10601,7 @@ static void i40e_vsi_free_arrays(struct i40e_vsi *vsi, bool free_qvectors)
        kfree(vsi->tx_rings);
        vsi->tx_rings = NULL;
        vsi->rx_rings = NULL;
+       vsi->xdp_rings = NULL;
 }
 
 /**
@@ -8210,18 +10621,17 @@ static int i40e_vsi_clear(struct i40e_vsi *vsi)
 
        mutex_lock(&pf->switch_mutex);
        if (!pf->vsi[vsi->idx]) {
-               dev_err(&pf->pdev->dev, "pf->vsi[%d] is NULL, just free vsi[%d](%p,type %d)\n",
-                       vsi->idx, vsi->idx, vsi, vsi->type);
+               dev_err(&pf->pdev->dev, "pf->vsi[%d] is NULL, just free vsi[%d](type %d)\n",
+                       vsi->idx, vsi->idx, vsi->type);
                goto unlock_vsi;
        }
 
        if (pf->vsi[vsi->idx] != vsi) {
                dev_err(&pf->pdev->dev,
-                       "pf->vsi[%d](%p, type %d) != vsi[%d](%p,type %d): no free!\n",
+                       "pf->vsi[%d](type %d) != vsi[%d](type %d): no free!\n",
                        pf->vsi[vsi->idx]->idx,
-                       pf->vsi[vsi->idx],
                        pf->vsi[vsi->idx]->type,
-                       vsi->idx, vsi, vsi->type);
+                       vsi->idx, vsi->type);
                goto unlock_vsi;
        }
 
@@ -8257,6 +10667,8 @@ static void i40e_vsi_clear_rings(struct i40e_vsi *vsi)
                        kfree_rcu(vsi->tx_rings[i], rcu);
                        vsi->tx_rings[i] = NULL;
                        vsi->rx_rings[i] = NULL;
+                       if (vsi->xdp_rings)
+                               vsi->xdp_rings[i] = NULL;
                }
        }
 }
@@ -8267,44 +10679,62 @@ static void i40e_vsi_clear_rings(struct i40e_vsi *vsi)
  **/
 static int i40e_alloc_rings(struct i40e_vsi *vsi)
 {
-       struct i40e_ring *tx_ring, *rx_ring;
+       int i, qpv = i40e_enabled_xdp_vsi(vsi) ? 3 : 2;
        struct i40e_pf *pf = vsi->back;
-       int i;
+       struct i40e_ring *ring;
 
        /* Set basic values in the rings to be used later during open() */
        for (i = 0; i < vsi->alloc_queue_pairs; i++) {
                /* allocate space for both Tx and Rx in one shot */
-               tx_ring = kzalloc(sizeof(struct i40e_ring) * 2, GFP_KERNEL);
-               if (!tx_ring)
+               ring = kcalloc(qpv, sizeof(struct i40e_ring), GFP_KERNEL);
+               if (!ring)
                        goto err_out;
 
-               tx_ring->queue_index = i;
-               tx_ring->reg_idx = vsi->base_queue + i;
-               tx_ring->ring_active = false;
-               tx_ring->vsi = vsi;
-               tx_ring->netdev = vsi->netdev;
-               tx_ring->dev = &pf->pdev->dev;
-               tx_ring->count = vsi->num_desc;
-               tx_ring->size = 0;
-               tx_ring->dcb_tc = 0;
+               ring->queue_index = i;
+               ring->reg_idx = vsi->base_queue + i;
+               ring->ring_active = false;
+               ring->vsi = vsi;
+               ring->netdev = vsi->netdev;
+               ring->dev = &pf->pdev->dev;
+               ring->count = vsi->num_desc;
+               ring->size = 0;
+               ring->dcb_tc = 0;
 
                if (vsi->back->hw_features & I40E_HW_WB_ON_ITR_CAPABLE)
-                       tx_ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
-               tx_ring->itr_setting = pf->tx_itr_default;
-               vsi->tx_rings[i] = tx_ring;
-
-               rx_ring = &tx_ring[1];
-               rx_ring->queue_index = i;
-               rx_ring->reg_idx = vsi->base_queue + i;
-               rx_ring->ring_active = false;
-               rx_ring->vsi = vsi;
-               rx_ring->netdev = vsi->netdev;
-               rx_ring->dev = &pf->pdev->dev;
-               rx_ring->count = vsi->num_desc;
-               rx_ring->size = 0;
-               rx_ring->dcb_tc = 0;
-               rx_ring->itr_setting = pf->rx_itr_default;
-               vsi->rx_rings[i] = rx_ring;
+                       ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
+               ring->itr_setting = pf->tx_itr_default;
+               vsi->tx_rings[i] = ring++;
+
+               if (!i40e_enabled_xdp_vsi(vsi))
+                       goto setup_rx;
+
+               ring->queue_index = vsi->alloc_queue_pairs + i;
+               ring->reg_idx = vsi->base_queue + ring->queue_index;
+               ring->ring_active = false;
+               ring->vsi = vsi;
+               ring->netdev = NULL;
+               ring->dev = &pf->pdev->dev;
+               ring->count = vsi->num_desc;
+               ring->size = 0;
+               ring->dcb_tc = 0;
+               if (vsi->back->hw_features & I40E_HW_WB_ON_ITR_CAPABLE)
+                       ring->flags = I40E_TXR_FLAGS_WB_ON_ITR;
+               set_ring_xdp(ring);
+               ring->itr_setting = pf->tx_itr_default;
+               vsi->xdp_rings[i] = ring++;
+
+setup_rx:
+               ring->queue_index = i;
+               ring->reg_idx = vsi->base_queue + i;
+               ring->ring_active = false;
+               ring->vsi = vsi;
+               ring->netdev = vsi->netdev;
+               ring->dev = &pf->pdev->dev;
+               ring->count = vsi->num_desc;
+               ring->size = 0;
+               ring->dcb_tc = 0;
+               ring->itr_setting = pf->rx_itr_default;
+               vsi->rx_rings[i] = ring;
        }
 
        return 0;
@@ -8418,21 +10848,28 @@ static int i40e_init_msix(struct i40e_pf *pf)
 
        /* any vectors left over go for VMDq support */
        if (pf->flags & I40E_FLAG_VMDQ_ENABLED) {
-               int vmdq_vecs_wanted = pf->num_vmdq_vsis * pf->num_vmdq_qps;
-               int vmdq_vecs = min_t(int, vectors_left, vmdq_vecs_wanted);
-
                if (!vectors_left) {
                        pf->num_vmdq_msix = 0;
                        pf->num_vmdq_qps = 0;
                } else {
+                       int vmdq_vecs_wanted =
+                               pf->num_vmdq_vsis * pf->num_vmdq_qps;
+                       int vmdq_vecs =
+                               min_t(int, vectors_left, vmdq_vecs_wanted);
+
                        /* if we're short on vectors for what's desired, we
                         * limit the queues per vmdq.  If this is still more
                         * than are available, the user will need to change
                         * the number of queues/vectors used by the PF later
                         * with the ethtool channels command
                         */
-                       if (vmdq_vecs < vmdq_vecs_wanted)
+                       if (vectors_left < vmdq_vecs_wanted) {
                                pf->num_vmdq_qps = 1;
+                               vmdq_vecs_wanted = pf->num_vmdq_vsis;
+                               vmdq_vecs = min_t(int,
+                                                 vectors_left,
+                                                 vmdq_vecs_wanted);
+                       }
                        pf->num_vmdq_msix = pf->num_vmdq_qps;
 
                        v_budget += vmdq_vecs;
@@ -8469,6 +10906,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
                pf->flags &= ~I40E_FLAG_MSIX_ENABLED;
                kfree(pf->msix_entries);
                pf->msix_entries = NULL;
+               pci_disable_msix(pf->pdev);
                return -ENODEV;
        }
 
@@ -8533,6 +10971,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
            (pf->num_fdsb_msix == 0)) {
                dev_info(&pf->pdev->dev, "Sideband Flowdir disabled, not enough MSI-X vectors\n");
                pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+               pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
        }
        if ((pf->flags & I40E_FLAG_VMDQ_ENABLED) &&
            (pf->num_vmdq_msix == 0)) {
@@ -8641,6 +11080,7 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)
                                       I40E_FLAG_FD_SB_ENABLED  |
                                       I40E_FLAG_FD_ATR_ENABLED |
                                       I40E_FLAG_VMDQ_ENABLED);
+                       pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
 
                        /* rework the queue expectations without MSIX */
                        i40e_determine_queue_usage(pf);
@@ -8682,6 +11122,48 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)
        return 0;
 }
 
+/**
+ * i40e_setup_misc_vector_for_recovery_mode - Setup the misc vector to handle
+ * non queue events in recovery mode
+ * @pf: board private structure
+ *
+ * This sets up the handler for MSIX 0 or MSI/legacy, which is used to manage
+ * the non-queue interrupts, e.g. AdminQ and errors in recovery mode.
+ * This is handled differently than in recovery mode since no Tx/Rx resources
+ * are being allocated.
+ **/
+static int i40e_setup_misc_vector_for_recovery_mode(struct i40e_pf *pf)
+{
+       int err;
+
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+               err = i40e_setup_misc_vector(pf);
+
+               if (err) {
+                       dev_info(&pf->pdev->dev,
+                                "MSI-X misc vector request failed, error %d\n",
+                                err);
+                       return err;
+               }
+       } else {
+               u32 flags = pf->flags & I40E_FLAG_MSI_ENABLED ? 0 : IRQF_SHARED;
+
+               err = request_irq(pf->pdev->irq, i40e_intr, flags,
+                                 pf->int_name, pf);
+
+               if (err) {
+                       dev_info(&pf->pdev->dev,
+                                "MSI/legacy misc vector request failed, error %d\n",
+                                err);
+                       return err;
+               }
+               i40e_enable_misc_int_causes(pf);
+               i40e_irq_dynamic_enable_icr0(pf);
+       }
+
+       return 0;
+}
+
 /**
  * i40e_setup_misc_vector - Setup the misc vector to handle non queue events
  * @pf: board private structure
@@ -8760,6 +11242,9 @@ static int i40e_restore_interrupt_scheme(struct i40e_pf *pf)
        if (err)
                goto err_unwind;
 
+       if (pf->flags & I40E_FLAG_IWARP_ENABLED)
+               i40e_client_update_msix_info(pf);
+
        return 0;
 
 err_unwind:
@@ -8772,50 +11257,6 @@ err_unwind:
 }
 #endif /* CONFIG_PM */
 
-/**
- * i40e_config_rss_aq - Configure RSS keys and lut by using AQ commands
- * @vsi: Pointer to vsi structure
- * @seed: RSS hash seed
- * @lut: Lookup table
- * @lut_size: Lookup table size
- *
- * Return 0 on success, negative on failure
- **/
-static int i40e_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
-                             u8 *lut, u16 lut_size)
-{
-       struct i40e_pf *pf = vsi->back;
-       struct i40e_hw *hw = &pf->hw;
-       int ret = 0;
-
-       if (seed) {
-               struct i40e_aqc_get_set_rss_key_data *seed_dw =
-                       (struct i40e_aqc_get_set_rss_key_data *)seed;
-               ret = i40e_aq_set_rss_key(hw, vsi->id, seed_dw);
-               if (ret) {
-                       dev_info(&pf->pdev->dev,
-                                "Cannot set RSS key, err %s aq_err %s\n",
-                                i40e_stat_str(hw, ret),
-                                i40e_aq_str(hw, hw->aq.asq_last_status));
-                       return ret;
-               }
-       }
-       if (lut) {
-               bool pf_lut = vsi->type == I40E_VSI_MAIN ? true : false;
-
-               ret = i40e_aq_set_rss_lut(hw, vsi->id, pf_lut, lut, lut_size);
-               if (ret) {
-                       dev_info(&pf->pdev->dev,
-                                "Cannot set RSS lut, err %s aq_err %s\n",
-                                i40e_stat_str(hw, ret),
-                                i40e_aq_str(hw, hw->aq.asq_last_status));
-                       return ret;
-               }
-       }
-
-       return ret;
-}
-
 /**
  * i40e_get_rss_aq - Get RSS keys and lut by using AQ commands
  * @vsi: Pointer to vsi structure
@@ -8856,48 +11297,8 @@ static int i40e_get_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
                                 i40e_aq_str(&pf->hw,
                                             pf->hw.aq.asq_last_status));
                        return ret;
-               }
-       }
-       return ret;
-}
-
-/**
- * i40e_vsi_config_rss - Prepare for VSI(VMDq) RSS if used
- * @vsi: VSI structure
- **/
-static int i40e_vsi_config_rss(struct i40e_vsi *vsi)
-{
-       u8 seed[I40E_HKEY_ARRAY_SIZE];
-       struct i40e_pf *pf = vsi->back;
-       u8 *lut;
-       int ret;
-
-       if (!(pf->hw_features & I40E_HW_RSS_AQ_CAPABLE))
-               return 0;
-
-       if (!vsi->rss_size)
-               vsi->rss_size = min_t(int, pf->alloc_rss_size,
-                                     vsi->num_queue_pairs);
-       if (!vsi->rss_size)
-               return -EINVAL;
-
-       lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
-       if (!lut)
-               return -ENOMEM;
-       /* Use the user configured hash keys and lookup table if there is one,
-        * otherwise use default
-        */
-       if (vsi->rss_lut_user)
-               memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size);
-       else
-               i40e_fill_rss_lut(pf, lut, vsi->rss_table_size, vsi->rss_size);
-       if (vsi->rss_hkey_user)
-               memcpy(seed, vsi->rss_hkey_user, I40E_HKEY_ARRAY_SIZE);
-       else
-               netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
-       ret = i40e_config_rss_aq(vsi, seed, lut, vsi->rss_table_size);
-       kfree(lut);
-
+               }
+       }
        return ret;
 }
 
@@ -9012,7 +11413,7 @@ int i40e_config_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
  * @vsi: Pointer to VSI structure
  * @seed: Buffer to store the keys
  * @lut: Buffer to store the lookup table entries
- * lut_size: Size of buffer to store the lookup table entries
+ * @lut_size: Size of buffer to store the lookup table entries
  *
  * Returns 0 on success, negative on failure
  */
@@ -9144,6 +11545,7 @@ int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count)
        if (!(pf->flags & I40E_FLAG_RSS_ENABLED))
                return 0;
 
+       queue_count = min_t(int, queue_count, num_online_cpus());
        new_rss_size = min_t(int, queue_count, pf->rss_size_max);
 
        if (queue_count != vsi->num_queue_pairs) {
@@ -9310,14 +11712,11 @@ bw_commit_out:
  * Fields are initialized based on PCI device information and
  * OS network device settings (MTU size).
  **/
-#ifdef HAVE_CONFIG_HOTPLUG
-static int __devinit i40e_sw_init(struct i40e_pf *pf)
-#else
 static int i40e_sw_init(struct i40e_pf *pf)
-#endif
 {
        int err = 0;
        int size;
+       u16 pow;
 
        pf->msg_enable = netif_msg_init(I40E_DEFAULT_MSG_ENABLE,
                                (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK));
@@ -9345,6 +11744,10 @@ static int i40e_sw_init(struct i40e_pf *pf)
        pf->rss_size_max = min_t(int, pf->rss_size_max,
                                 pf->hw.func_caps.num_tx_qp);
 
+       /* find the next higher power-of-2 of num cpus */
+       pow = roundup_pow_of_two(num_online_cpus());
+       pf->rss_size_max = min_t(int, pf->rss_size_max, pow);
+
        if (pf->hw.func_caps.rss) {
                pf->flags |= I40E_FLAG_RSS_ENABLED;
                pf->alloc_rss_size = min_t(int, pf->rss_size_max,
@@ -9453,6 +11856,15 @@ static int i40e_sw_init(struct i40e_pf *pf)
                /* IWARP needs one extra vector for CQP just like MISC.*/
                pf->num_iwarp_msix = (int)num_online_cpus() + 1;
        }
+       /* Stopping FW LLDP engine is supported on XL710 and X722
+        * starting from FW versions determined in i40e_init_adminq.
+        * Stopping the FW LLDP engine is not supported on XL710
+        * if NPAR is functioning so unset this hw flag in this case.
+        */
+       if (pf->hw.mac.type == I40E_MAC_XL710 &&
+           pf->hw.func_caps.npar_enable &&
+           (pf->hw.flags & I40E_HW_FLAG_FW_LLDP_STOPPABLE))
+               pf->hw.flags &= ~I40E_HW_FLAG_FW_LLDP_STOPPABLE;
 
 #ifndef HAVE_SWIOTLB_SKIP_CPU_SYNC
        /* force legacy Rx if SKIP_CPU_SYNC is not supported */
@@ -9533,9 +11945,13 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
                /* Enable filters and mark for reset */
                if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
                        need_reset = true;
-               /* enable FD_SB only if there is MSI-X vector */
-               if (pf->num_fdsb_msix > 0)
+               /* enable FD_SB only if there is MSI-X vector and no cloud
+                * filters exist
+                */
+               if (pf->num_fdsb_msix > 0 && !pf->num_cloud_filters) {
                        pf->flags |= I40E_FLAG_FD_SB_ENABLED;
+                       pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;
+               }
        } else {
                /* turn off filters, mark for reset and clear SW filter list */
                if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
@@ -9543,17 +11959,16 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
                        i40e_fdir_filter_exit(pf);
                        i40e_cloud_filter_exit(pf);
                }
-               pf->flags &= ~(I40E_FLAG_FD_SB_ENABLED |
-                              I40E_FLAG_FD_SB_AUTO_DISABLED);
+               pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+               clear_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state);
+               pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
                /* reset fd counters */
                pf->fd_add_err = pf->fd_atr_cnt = 0;
                /* if ATR was auto disabled it can be re-enabled. */
-               if (pf->flags & I40E_FLAG_FD_ATR_AUTO_DISABLED) {
-                       pf->flags &= ~I40E_FLAG_FD_ATR_AUTO_DISABLED;
+               if (test_and_clear_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state))
                        if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
                            (I40E_DEBUG_FD & pf->hw.debug_mask))
                                dev_info(&pf->pdev->dev, "ATR re-enabled.\n");
-               }
        }
        return need_reset;
 }
@@ -9614,10 +12029,17 @@ static int i40e_set_features(struct net_device *netdev,
        else
                i40e_vlan_stripping_disable(vsi);
 
+#ifdef NETIF_F_HW_TC
+       if (!(features & NETIF_F_HW_TC) && pf->num_cloud_filters) {
+               dev_err(&pf->pdev->dev,
+                       "Offloaded tc filters active, can't turn hw_tc_offload off");
+               return -EINVAL;
+       }
+#endif
        need_reset = i40e_set_ntuple(pf, features);
 
        if (need_reset)
-               i40e_do_reset(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED), true);
+               i40e_do_reset(pf, I40E_PF_RESET_FLAG, true);
 
        return 0;
 }
@@ -9635,6 +12057,11 @@ static u8 i40e_get_udp_port_idx(struct i40e_pf *pf, u16 port)
        u8 i;
 
        for (i = 0; i < I40E_MAX_PF_UDP_OFFLOAD_PORTS; i++) {
+               /* Do not report ports with pending deletions as
+                * being available.
+                */
+               if (!port && (pf->pending_udp_bitmap & BIT_ULL(i)))
+                       continue;
                if (pf->udp_ports[i].port == port)
                        return i;
        }
@@ -9690,8 +12117,9 @@ static void i40e_udp_tunnel_add(struct net_device *netdev,
 
        /* New port: add it and mark its index in the bitmap */
        pf->udp_ports[next_idx].port = port;
+       pf->udp_ports[next_idx].filter_index = I40E_UDP_PORT_INDEX_UNUSED;
        pf->pending_udp_bitmap |= BIT_ULL(next_idx);
-       pf->flags |= I40E_FLAG_UDP_FILTER_SYNC;
+       set_bit(__I40E_UDP_FILTER_SYNC_PENDING, pf->state);
 }
 
 /**
@@ -9734,8 +12162,13 @@ static void i40e_udp_tunnel_del(struct net_device *netdev,
         * and make it pending
         */
        pf->udp_ports[idx].port = 0;
-       pf->pending_udp_bitmap |= BIT_ULL(idx);
-       pf->flags |= I40E_FLAG_UDP_FILTER_SYNC;
+
+       /* Toggle pending bit instead of setting it. This way if we are
+        * deleting a port that has yet to be added we just clear the pending
+        * bit and don't have to worry about it.
+        */
+       pf->pending_udp_bitmap ^= BIT_ULL(idx);
+       set_bit(__I40E_UDP_FILTER_SYNC_PENDING, pf->state);
 
        return;
 not_found:
@@ -9841,16 +12274,17 @@ static int i40e_get_phys_port_id(struct net_device *netdev,
 }
 
 #endif /* HAVE_NDO_GET_PHYS_PORT_ID */
-#ifdef HAVE_FDB_OPS
-#ifdef USE_CONST_DEV_UC_CHAR
 /**
  * i40e_ndo_fdb_add - add an entry to the hardware database
  * @ndm: the input from the stack
  * @tb: pointer to array of nladdr (unused)
  * @dev: the net device pointer
  * @addr: the MAC address entry being added
+ * @vid: VLAN ID
  * @flags: instructions from stack about fdb operation
  */
+#ifdef HAVE_FDB_OPS
+#ifdef USE_CONST_DEV_UC_CHAR
 static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
                            struct net_device *dev,
                            const unsigned char *addr,
@@ -9859,13 +12293,6 @@ static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 #endif
                            u16 flags)
 #else
-/**
- * i40e_ndo_fdb_add - add an entry to the hardware database
- * @ndm: the input from the stack
- * @dev: the net device pointer
- * @addr: the MAC address entry being added
- * @flags: instructions from stack about fdb operation
- */
 static int i40e_ndo_fdb_add(struct ndmsg *ndm,
                            struct net_device *dev,
                            unsigned char *addr,
@@ -9908,7 +12335,7 @@ static int i40e_ndo_fdb_add(struct ndmsg *ndm,
 /**
  * i40e_features_check - Validate encapsulated packet conforms to limits
  * @skb: skb buff
- * @netdev: This physical port's netdev
+ * @dev: This physical port's netdev
  * @features: Offload features that the stack believes apply
  **/
 static netdev_features_t i40e_features_check(struct sk_buff *skb,
@@ -9963,6 +12390,80 @@ out_err:
        return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
 }
 
+#ifdef HAVE_XDP_SUPPORT
+/**
+ * i40e_xdp_setup - add/remove an XDP program
+ * @vsi: VSI to changed
+ * @prog: XDP program
+ **/
+static int i40e_xdp_setup(struct i40e_vsi *vsi,
+                         struct bpf_prog *prog)
+{
+       int frame_size = vsi->netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+       struct i40e_pf *pf = vsi->back;
+       struct bpf_prog *old_prog;
+       bool need_reset;
+       int i;
+
+       /* Don't allow frames that span over multiple buffers */
+       if (frame_size > vsi->rx_buf_len)
+               return -EINVAL;
+
+       if (!i40e_enabled_xdp_vsi(vsi) && !prog)
+               return 0;
+
+       /* When turning XDP on->off/off->on we reset and rebuild the rings. */
+       need_reset = (i40e_enabled_xdp_vsi(vsi) != !!prog);
+
+       if (need_reset)
+               i40e_prep_for_reset(pf, true);
+
+       old_prog = xchg(&vsi->xdp_prog, prog);
+
+       if (need_reset)
+               i40e_reset_and_rebuild(pf, true, true);
+
+       for (i = 0; i < vsi->num_queue_pairs; i++)
+               WRITE_ONCE(vsi->rx_rings[i]->xdp_prog, vsi->xdp_prog);
+
+       if (old_prog)
+               bpf_prog_put(old_prog);
+
+       return 0;
+}
+
+/**
+ * i40e_xdp - implements ndo_xdp for i40e
+ * @dev: netdevice
+ * @xdp: XDP command
+ **/
+#ifdef HAVE_NDO_BPF
+static int i40e_xdp(struct net_device *dev,
+                   struct netdev_bpf *xdp)
+#else
+static int i40e_xdp(struct net_device *dev,
+                   struct netdev_xdp *xdp)
+#endif
+{
+       struct i40e_netdev_priv *np = netdev_priv(dev);
+       struct i40e_vsi *vsi = np->vsi;
+
+       if (vsi->type != I40E_VSI_MAIN)
+               return -EINVAL;
+
+       switch (xdp->command) {
+       case XDP_SETUP_PROG:
+               return i40e_xdp_setup(vsi, xdp->prog);
+       case XDP_QUERY_PROG:
+#ifndef NO_NETDEV_BPF_PROG_ATTACHED
+               xdp->prog_attached = i40e_enabled_xdp_vsi(vsi);
+#endif /* !NO_NETDEV_BPF_PROG_ATTACHED */
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+#endif /* HAVE_XDP_SUPPORT */
 #endif /* HAVE_NDO_FEATURES_CHECK */
 #ifndef USE_DEFAULT_FDB_DEL_DUMP
 #ifdef USE_CONST_DEV_UC_CHAR
@@ -10030,6 +12531,7 @@ static int i40e_ndo_fdb_dump(struct sk_buff *skb,
  * i40e_ndo_bridge_setlink - Set the hardware bridge mode
  * @dev: the netdev being configured
  * @nlh: RTNL message
+ * @flags: bridge flags
  *
  * Inserts a new hardware bridge if not already created and
  * enables the bridging mode requested (VEB or VEPA). If the
@@ -10098,8 +12600,7 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev,
                                pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
                        else
                                pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
-                       i40e_do_reset(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED),
-                                     true);
+                       i40e_do_reset(pf, I40E_PF_RESET_FLAG, true);
                        break;
                }
        }
@@ -10183,6 +12684,7 @@ static const struct net_device_ops i40e_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = i40e_set_mac,
 #ifdef HAVE_RHEL7_EXTENDED_MIN_MAX_MTU
+       .ndo_size               = sizeof(struct net_device_ops),
        .extended.ndo_change_mtu = i40e_change_mtu,
 #else
        .ndo_change_mtu         = i40e_change_mtu,
@@ -10281,6 +12783,16 @@ static const struct net_device_ops i40e_netdev_ops = {
        .ndo_bridge_setlink     = i40e_ndo_bridge_setlink,
 #endif /* HAVE_BRIDGE_ATTRIBS */
 #endif /* HAVE_FDB_OPS */
+#ifdef HAVE_XDP_SUPPORT
+#ifdef HAVE_NDO_BPF
+       .ndo_bpf                = i40e_xdp,
+       .ndo_xdp_xmit           = i40e_xdp_xmit,
+#else
+       .ndo_xdp                = i40e_xdp,
+       .ndo_xdp_xmit           = i40e_xdp_xmit,
+       .ndo_xdp_flush          = i40e_xdp_flush,
+#endif /* HAVE_NDO_BPF */
+#endif /* HAVE_XDP_SUPPORT */
 #ifdef HAVE_RHEL6_NET_DEVICE_OPS_EXT
 };
 
@@ -10329,7 +12841,9 @@ static void i40e_assign_netdev_ops(struct net_device *dev)
 #endif
        dev->tx_timeout = i40e_tx_timeout;
 #ifdef NETIF_F_HW_VLAN_TX
+#ifdef HAVE_VLAN_RX_REGISTER
        dev->vlan_rx_register = i40e_vlan_rx_register;
+#endif
        dev->vlan_rx_add_vid = i40e_vlan_rx_add_vid;
        dev->vlan_rx_kill_vid = i40e_vlan_rx_kill_vid;
 #endif
@@ -10448,8 +12962,12 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
 
 #if defined(HAVE_NDO_SET_FEATURES) || defined(ETHTOOL_GRXRINGS)
        if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
+#ifdef NETIF_F_HW_TC
+               hw_features |= NETIF_F_NTUPLE | NETIF_F_HW_TC;
+#else
                hw_features |= NETIF_F_NTUPLE;
 #endif
+#endif
 
 #ifdef HAVE_NDO_SET_FEATURES
 #ifdef HAVE_RHEL6_NET_DEVICE_OPS_EXT
@@ -10501,7 +13019,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
                snprintf(netdev->name, IFNAMSIZ, "%.*sv%%d",
                         IFNAMSIZ - 4,
                         pf->vsi[pf->lan_vsi]->netdev->name);
-               random_ether_addr(mac_addr);
+               eth_random_addr(mac_addr);
 
                spin_lock_bh(&vsi->mac_filter_hash_lock);
                i40e_add_mac_filter(vsi, mac_addr);
@@ -10867,7 +13385,7 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
 
        if (f_count) {
                vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
-               pf->flags |= I40E_FLAG_FILTER_SYNC;
+               set_bit(__I40E_MACVLAN_SYNC_PENDING, pf->state);
        }
 
        /* Update VSI BW information */
@@ -11052,6 +13570,7 @@ vector_setup_out:
  **/
 static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
 {
+       u16 alloc_queue_pairs;
        struct i40e_pf *pf;
        u8 enabled_tc;
        int ret;
@@ -11070,11 +13589,14 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi)
        if (ret)
                goto err_vsi;
 
-       ret = i40e_get_lump(pf, pf->qp_pile, vsi->alloc_queue_pairs, vsi->idx);
+       alloc_queue_pairs = vsi->alloc_queue_pairs *
+                           (i40e_enabled_xdp_vsi(vsi) ? 2 : 1);
+
+       ret = i40e_get_lump(pf, pf->qp_pile, alloc_queue_pairs, vsi->idx);
        if (ret < 0) {
                dev_info(&pf->pdev->dev,
                         "failed to get tracking for %d queues for VSI %d err %d\n",
-                        vsi->alloc_queue_pairs, vsi->seid, ret);
+                        alloc_queue_pairs, vsi->seid, ret);
                goto err_vsi;
        }
        vsi->base_queue = ret;
@@ -11598,7 +14120,7 @@ struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags,
        for (vsi_idx = 0; vsi_idx < pf->num_alloc_vsi; vsi_idx++)
                if (pf->vsi[vsi_idx] && pf->vsi[vsi_idx]->seid == vsi_seid)
                        break;
-       if (vsi_idx >= pf->num_alloc_vsi && vsi_seid != 0) {
+       if (vsi_idx == pf->num_alloc_vsi && vsi_seid != 0) {
                dev_info(&pf->pdev->dev, "vsi seid %d not found\n",
                         vsi_seid);
                return NULL;
@@ -11815,14 +14337,16 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
        */
 
        if ((pf->hw.pf_id == 0) &&
-           !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT))
+           !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT)) {
                flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
+               pf->last_sw_conf_flags = flags;
+       }
 
        if (pf->hw.pf_id == 0) {
                u16 valid_flags;
 
                valid_flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
-               ret = i40e_aq_set_switch_config(&pf->hw, flags, valid_flags,
+               ret = i40e_aq_set_switch_config(&pf->hw, flags, valid_flags, 0,
                                                NULL);
                if (ret && pf->hw.aq.asq_last_status != I40E_AQ_RC_ESRCH) {
                        dev_info(&pf->pdev->dev,
@@ -11832,6 +14356,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
                                             pf->hw.aq.asq_last_status));
                        /* not a fatal problem, just keep going */
                }
+               pf->last_sw_conf_valid_flags = valid_flags;
        }
 
        /* first time setup */
@@ -11852,6 +14377,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
                        vsi = i40e_vsi_reinit_setup(pf->vsi[pf->lan_vsi]);
                if (!vsi) {
                        dev_info(&pf->pdev->dev, "setup of MAIN VSI failed\n");
+                       i40e_cloud_filter_exit(pf);
                        i40e_fdir_teardown(pf);
                        return -EAGAIN;
                }
@@ -11933,6 +14459,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)
                               I40E_FLAG_DCB_ENABLED    |
                               I40E_FLAG_SRIOV_ENABLED  |
                               I40E_FLAG_VMDQ_ENABLED);
+               pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
        } else if (!(pf->flags & (I40E_FLAG_RSS_ENABLED |
                                  I40E_FLAG_FD_SB_ENABLED |
                                  I40E_FLAG_FD_ATR_ENABLED |
@@ -11947,6 +14474,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)
                               I40E_FLAG_FD_ATR_ENABLED |
                               I40E_FLAG_DCB_ENABLED    |
                               I40E_FLAG_VMDQ_ENABLED);
+               pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
        } else {
                /* Not enough queues for all TCs */
                if ((pf->flags & I40E_FLAG_DCB_CAPABLE) &&
@@ -11968,6 +14496,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)
                        queues_left -= 1; /* save 1 queue for FD */
                } else {
                        pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+                       pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
                        dev_info(&pf->pdev->dev, "not enough queues for Flow Director. Flow Director feature is disabled\n");
                }
        }
@@ -12096,6 +14625,146 @@ static void i40e_get_platform_mac_addr(struct pci_dev *pdev, struct i40e_pf *pf)
                i40e_get_mac_addr(&pf->hw, pf->hw.mac.addr);
 }
 
+/**
+ * i40e_check_recovery_mode - check if we are running transition firmware
+ * @pf: board private structure
+ *
+ * Check registers indicating the firmware runs in recovery mode. Sets the
+ * appropriate driver state.
+ *
+ * Returns true if the recovery mode was detected, false otherwise
+ **/
+static bool i40e_check_recovery_mode(struct i40e_pf *pf)
+{
+       u32 val = rd32(&pf->hw, I40E_GL_FWSTS);
+
+       if (val & I40E_GL_FWSTS_FWS1B_MASK) {
+               dev_notice(&pf->pdev->dev, "Firmware recovery mode detected. Limiting functionality.\n");
+               dev_notice(&pf->pdev->dev, "Refer to the Intel(R) Ethernet Adapters and Devices User Guide for details on firmware recovery mode.\n");
+               set_bit(__I40E_RECOVERY_MODE, pf->state);
+
+               return true;
+       }
+       if (test_and_clear_bit(__I40E_RECOVERY_MODE, pf->state))
+               dev_info(&pf->pdev->dev, "Reinitializing in normal mode with full functionality.\n");
+
+       return false;
+}
+
+/**
+ * i40e_init_recovery_mode - initialize subsystems needed in recovery mode
+ * @pf: board private structure
+ * @hw: ptr to the hardware info
+ *
+ * This function does a minimal setup of all subsystems needed for running
+ * recovery mode.
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_init_recovery_mode(struct i40e_pf *pf, struct i40e_hw *hw)
+{
+       struct i40e_vsi *vsi;
+       int err;
+       int v_idx;
+
+#ifdef HAVE_PCI_ERS
+       pci_save_state(pf->pdev);
+#endif
+
+       /* set up periodic task facility */
+       timer_setup(&pf->service_timer, i40e_service_timer, 0);
+       pf->service_timer_period = HZ;
+
+       INIT_WORK(&pf->service_task, i40e_service_task);
+       clear_bit(__I40E_SERVICE_SCHED, pf->state);
+
+       err = i40e_init_interrupt_scheme(pf);
+       if (err)
+               goto err_switch_setup;
+
+       /* The number of VSIs reported by the FW is the minimum guaranteed
+        * to us; HW supports far more and we share the remaining pool with
+        * the other PFs. We allocate space for more than the guarantee with
+        * the understanding that we might not get them all later.
+        */
+       if (pf->hw.func_caps.num_vsis < I40E_MIN_VSI_ALLOC)
+               pf->num_alloc_vsi = I40E_MIN_VSI_ALLOC;
+       else
+               pf->num_alloc_vsi = pf->hw.func_caps.num_vsis;
+
+       /* Set up the vsi struct and our local tracking of the MAIN PF vsi. */
+       pf->vsi = kcalloc(pf->num_alloc_vsi, sizeof(struct i40e_vsi *),
+                         GFP_KERNEL);
+       if (!pf->vsi) {
+               err = -ENOMEM;
+               goto err_switch_setup;
+       }
+
+       /* We allocate one VSI which is needed as absolute minimum
+        * in order to register the netdev
+        */
+       v_idx = i40e_vsi_mem_alloc(pf, I40E_VSI_MAIN);
+       if (v_idx < 0)
+               goto err_switch_setup;
+       pf->lan_vsi = v_idx;
+       vsi = pf->vsi[v_idx];
+       if (!vsi)
+               goto err_switch_setup;
+       vsi->alloc_queue_pairs = 1;
+       err = i40e_config_netdev(vsi);
+       if (err)
+               goto err_switch_setup;
+       err = register_netdev(vsi->netdev);
+       if (err)
+               goto err_switch_setup;
+       vsi->netdev_registered = true;
+       i40e_dbg_pf_init(pf);
+
+       err = i40e_setup_misc_vector_for_recovery_mode(pf);
+       if (err)
+               goto err_switch_setup;
+
+       /* tell the firmware that we're starting */
+       i40e_send_version(pf);
+
+       /* since everything's happy, start the service_task timer */
+       mod_timer(&pf->service_timer,
+                 round_jiffies(jiffies + pf->service_timer_period));
+
+       return 0;
+
+err_switch_setup:
+       i40e_reset_interrupt_capability(pf);
+       del_timer_sync(&pf->service_timer);
+       dev_warn(&pf->pdev->dev, "previous errors forcing module to load in debug mode\n");
+       i40e_dbg_pf_init(pf);
+       set_bit(__I40E_DEBUG_MODE, pf->state);
+       return 0;
+}
+
+/**
+ * i40e_set_fec_in_flags - helper function for setting FEC options in flags
+ * @fec_cfg: FEC option to set in flags
+ * @flags: ptr to flags in which we set FEC option
+ **/
+void i40e_set_fec_in_flags(u8 fec_cfg, u64 *flags)
+{
+       if (fec_cfg & I40E_AQ_SET_FEC_AUTO)
+               *flags |= I40E_FLAG_RS_FEC | I40E_FLAG_BASE_R_FEC;
+       if ((fec_cfg & I40E_AQ_SET_FEC_REQUEST_RS) ||
+           (fec_cfg & I40E_AQ_SET_FEC_ABILITY_RS)) {
+               *flags |= I40E_FLAG_RS_FEC;
+               *flags &= ~I40E_FLAG_BASE_R_FEC;
+       }
+       if ((fec_cfg & I40E_AQ_SET_FEC_REQUEST_KR) ||
+           (fec_cfg & I40E_AQ_SET_FEC_ABILITY_KR)) {
+               *flags |= I40E_FLAG_BASE_R_FEC;
+               *flags &= ~I40E_FLAG_RS_FEC;
+       }
+       if (fec_cfg == 0)
+               *flags &= ~(I40E_FLAG_RS_FEC | I40E_FLAG_BASE_R_FEC);
+}
+
 /**
  * i40e_probe - Device initialization routine
  * @pdev: PCI device information struct
@@ -12141,11 +14810,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        /* set up pci connections */
-       err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
-                                          IORESOURCE_MEM), i40e_driver_name);
+       err = pci_request_mem_regions(pdev, i40e_driver_name);
        if (err) {
                dev_info(&pdev->dev,
-                        "pci_request_selected_regions failed %d\n", err);
+                        "pci_request_mem_regions failed %d\n", err);
                goto err_pci_reg;
        }
 
@@ -12200,6 +14868,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        INIT_LIST_HEAD(&pf->l3_flex_pit_list);
        INIT_LIST_HEAD(&pf->l4_flex_pit_list);
+       INIT_LIST_HEAD(&pf->ddp_old_prof);
 
        /* set up the spinlocks for the AQ, do this only once in probe
         * and destroy them only once in remove
@@ -12213,12 +14882,15 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* Reset here to make sure all is clean and to define PF 'n' */
        /* have to do the PF reset first to "graceful abort" all queues */
        i40e_clear_hw(hw);
-       err = i40e_pf_reset(hw);
-       if (err) {
-               dev_info(&pdev->dev, "Initial pf_reset failed: %d\n", err);
-               goto err_pf_reset;
+       if (!i40e_check_recovery_mode(pf)) {
+               err = i40e_pf_reset(hw);
+               if (err) {
+                       dev_info(&pdev->dev, "Initial pf_reset failed: %d\n",
+                                err);
+                       goto err_pf_reset;
+               }
+               pf->pfr_count++;
        }
-       pf->pfr_count++;
 
        hw->aq.num_arq_entries = I40E_AQ_LEN;
        hw->aq.num_asq_entries = I40E_AQ_LEN;
@@ -12275,7 +14947,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        i40e_clear_pxe_mode(hw);
 
-       err = i40e_get_capabilities(pf);
+       err = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);
        if (err)
                goto err_adminq_setup;
 
@@ -12285,6 +14957,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto err_sw_init;
        }
 
+       if (test_bit(__I40E_RECOVERY_MODE, pf->state))
+               return i40e_init_recovery_mode(pf, hw);
+
        err = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
                                hw->func_caps.num_rx_qp, 0, 0);
        if (err) {
@@ -12395,6 +15070,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_info(&pdev->dev, "setup_pf_switch failed: %d\n", err);
                goto err_vsis;
        }
+       INIT_LIST_HEAD(&pf->vsi[pf->lan_vsi]->ch_list);
 
        /* Make sure flow control is set according to current settings */
        err = i40e_set_fc(hw, &set_fc_aq_fail, true);
@@ -12555,23 +15231,23 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
                switch (hw->bus.speed) {
                case i40e_bus_speed_8000:
-                       strncpy(speed, "8.0", PCI_SPEED_SIZE); break;
+                       strlcpy(speed, "8.0", PCI_SPEED_SIZE); break;
                case i40e_bus_speed_5000:
-                       strncpy(speed, "5.0", PCI_SPEED_SIZE); break;
+                       strlcpy(speed, "5.0", PCI_SPEED_SIZE); break;
                case i40e_bus_speed_2500:
-                       strncpy(speed, "2.5", PCI_SPEED_SIZE); break;
+                       strlcpy(speed, "2.5", PCI_SPEED_SIZE); break;
                default:
                        break;
                }
                switch (hw->bus.width) {
                case i40e_bus_width_pcie_x8:
-                       strncpy(width, "8", PCI_WIDTH_SIZE); break;
+                       strlcpy(width, "8", PCI_WIDTH_SIZE); break;
                case i40e_bus_width_pcie_x4:
-                       strncpy(width, "4", PCI_WIDTH_SIZE); break;
+                       strlcpy(width, "4", PCI_WIDTH_SIZE); break;
                case i40e_bus_width_pcie_x2:
-                       strncpy(width, "2", PCI_WIDTH_SIZE); break;
+                       strlcpy(width, "2", PCI_WIDTH_SIZE); break;
                case i40e_bus_width_pcie_x1:
-                       strncpy(width, "1", PCI_WIDTH_SIZE); break;
+                       strlcpy(width, "1", PCI_WIDTH_SIZE); break;
                default:
                        break;
                }
@@ -12594,6 +15270,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                        i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
        pf->hw.phy.link_info.requested_speeds = abilities.link_speed;
 
+       /* set the FEC config due to the board capabilities */
+       i40e_set_fec_in_flags(abilities.fec_cfg_curr_mod_ext_info, &pf->flags);
+
        /* get the supported phy types from the fw */
        err = i40e_aq_get_phy_capabilities(hw, false, true, &abilities, NULL);
        if (err)
@@ -12644,8 +15323,7 @@ err_ioremap:
        kfree(pf);
 err_pf_alloc:
        pci_disable_pcie_error_reporting(pdev);
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 err_pci_reg:
 err_dma:
        pci_disable_device(pdev);
@@ -12690,7 +15368,21 @@ static void i40e_remove(struct pci_dev *pdev)
                cancel_work_sync(&pf->service_task);
 
        if (test_bit(__I40E_DEBUG_MODE, pf->state))
+               goto debug_mode_clear;
+
+       if (test_bit(__I40E_RECOVERY_MODE, pf->state)) {
+               struct i40e_vsi *vsi = pf->vsi[0];
+
+               /* We know that we have allocated only one vsi for this PF,
+                * it was just for registering netdevice, so the interface
+                * could be visible in the 'ifconfig' output
+                */
+               unregister_netdev(vsi->netdev);
+               free_netdev(vsi->netdev);
+               vsi->netdev = NULL;
+
                goto unmap;
+       }
 
        /* Client close must be called explicitly here because the timer
         * has been stopped.
@@ -12722,6 +15414,8 @@ static void i40e_remove(struct pci_dev *pdev)
        if (pf->vsi[pf->lan_vsi])
                i40e_vsi_release(pf->vsi[pf->lan_vsi]);
 
+       i40e_cloud_filter_exit(pf);
+
        /* remove attached clients */
        if (pf->flags & I40E_FLAG_IWARP_ENABLED) {
                ret_code = i40e_lan_del_device(pf);
@@ -12740,22 +15434,36 @@ static void i40e_remove(struct pci_dev *pdev)
        }
 
 unmap:
-       /* shutdown the adminq */
-       i40e_shutdown_adminq(hw);
-
-       /* destroy the locks only once, here */
-       i40e_destroy_spinlock_d(&hw->aq.arq_spinlock);
-       i40e_destroy_spinlock_d(&hw->aq.asq_spinlock);
+       /* Free MSI/legacy interrupt 0 when in recovery mode.
+        * This is normally done in i40e_vsi_free_irq on
+        * VSI close but since recovery mode doesn't allow to up
+        * an interface and we do not allocate all Rx/Tx resources
+        * for it we'll just do it here
+        */
+       if (test_bit(__I40E_RECOVERY_MODE, pf->state) &&
+           !(pf->flags & I40E_FLAG_MSIX_ENABLED))
+               free_irq(pf->pdev->irq, pf);
 
        /* Clear all dynamic memory lists of rings, q_vectors, and VSIs */
+       rtnl_lock();
        i40e_clear_interrupt_scheme(pf);
        for (i = 0; i < pf->num_alloc_vsi; i++) {
                if (pf->vsi[i]) {
-                       i40e_vsi_clear_rings(pf->vsi[i]);
+                       if (!test_bit(__I40E_RECOVERY_MODE, pf->state))
+                               i40e_vsi_clear_rings(pf->vsi[i]);
                        i40e_vsi_clear(pf->vsi[i]);
                        pf->vsi[i] = NULL;
                }
        }
+       rtnl_unlock();
+
+debug_mode_clear:
+       /* shutdown the adminq */
+       i40e_shutdown_adminq(hw);
+
+       /* destroy the locks only once, here */
+       i40e_destroy_spinlock_d(&hw->aq.arq_spinlock);
+       i40e_destroy_spinlock_d(&hw->aq.asq_spinlock);
 
        for (i = 0; i < I40E_MAX_VEB; i++) {
                kfree(pf->veb[i]);
@@ -12767,8 +15475,7 @@ unmap:
 
        iounmap(hw->hw_addr);
        kfree(pf);
-       pci_release_selected_regions(pdev,
-                                    pci_select_bars(pdev, IORESOURCE_MEM));
+       pci_release_mem_regions(pdev);
 
        pci_disable_pcie_error_reporting(pdev);
        pci_disable_device(pdev);
@@ -12778,6 +15485,7 @@ unmap:
 /**
  * i40e_pci_error_detected - warning that something funky happened in PCI land
  * @pdev: PCI device information struct
+ * @error: the type of PCI error
  *
  * Called to warn that something happened and the error handling steps
  * are in progress.  Allows the driver to quiesce things, be ready for
@@ -12957,6 +15665,11 @@ static void i40e_enable_mc_magic_wake(struct i40e_pf *pf)
                        "Failed to enable Multicast Magic Packet wake up\n");
 }
 
+/* FW state indicating on X722 that we need to disable WoL to
+ * allow adapter to shutdown completely
+ */
+#define I40E_GL_FWSTS_FWS0B_STAGE_FW_UPDATE_POR_REQUIRED 0x0F
+
 /**
  * i40e_shutdown - PCI callback for shutting down
  * @pdev: PCI device information struct
@@ -12965,6 +15678,7 @@ static void i40e_shutdown(struct pci_dev *pdev)
 {
        struct i40e_pf *pf = pci_get_drvdata(pdev);
        struct i40e_hw *hw = &pf->hw;
+       u32 val = 0;
 
        set_bit(__I40E_SUSPENDED, pf->state);
        set_bit(__I40E_DOWN, pf->state);
@@ -12974,6 +15688,7 @@ static void i40e_shutdown(struct pci_dev *pdev)
 
        del_timer_sync(&pf->service_timer);
        cancel_work_sync(&pf->service_task);
+       i40e_cloud_filter_exit(pf);
        i40e_fdir_teardown(pf);
 
        /* Client close must be called explicitly here because the timer
@@ -12981,23 +15696,64 @@ static void i40e_shutdown(struct pci_dev *pdev)
         */
        i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], false);
 
-       if (pf->wol_en && (pf->hw_features & I40E_HW_WOL_MC_MAGIC_PKT_WAKE))
-               i40e_enable_mc_magic_wake(pf);
+       val = rd32(hw, I40E_GL_FWSTS) & I40E_GL_FWSTS_FWS0B_MASK;
 
-       i40e_prep_for_reset(pf, false);
+       if (pf->hw.mac.type == I40E_MAC_X722) {
+               /* We check here if we need to disable the WoL to allow adapter
+                * to shutdown completely after a FW update
+                */
+               if (val != I40E_GL_FWSTS_FWS0B_STAGE_FW_UPDATE_POR_REQUIRED &&
+                   pf->wol_en) {
+                       if (pf->hw_features & I40E_HW_WOL_MC_MAGIC_PKT_WAKE)
+                               i40e_enable_mc_magic_wake(pf);
+
+                       i40e_prep_for_reset(pf, false);
+
+                       wr32(hw, I40E_PFPM_APM, I40E_PFPM_APM_APME_MASK);
+                       wr32(hw, I40E_PFPM_WUFC, I40E_PFPM_WUFC_MAG_MASK);
+               } else {
+                       i40e_prep_for_reset(pf, false);
+
+                       wr32(hw, I40E_PFPM_APM, 0);
+                       wr32(hw, I40E_PFPM_WUFC, 0);
+               }
+       } else {
+               i40e_prep_for_reset(pf, false);
+
+               wr32(hw, I40E_PFPM_APM,
+                    (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0));
+               wr32(hw, I40E_PFPM_WUFC,
+                    (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
+       }
 
-       wr32(hw, I40E_PFPM_APM,
-            (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0));
-       wr32(hw, I40E_PFPM_WUFC,
-            (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
+       /* Free MSI/legacy interrupt 0 when in recovery mode.
+        * This is normally done in i40e_vsi_free_irq on
+        * VSI close but since recovery mode doesn't allow to up
+        * an interface and we do not allocate all Rx/Tx resources
+        * for it we'll just do it here
+        */
+       if (test_bit(__I40E_RECOVERY_MODE, pf->state) &&
+           !(pf->flags & I40E_FLAG_MSIX_ENABLED))
+               free_irq(pf->pdev->irq, pf);
 
+       /* Since we're going to destroy queues during the
+        * i40e_clear_interrupt_scheme() we should hold the RTNL lock for this
+        * whole section
+        */
+       rtnl_lock();
        i40e_clear_interrupt_scheme(pf);
+       rtnl_unlock();
 
 debug_mode:
-       if (system_state == SYSTEM_POWER_OFF) {
+
+       if (pf->hw.mac.type == I40E_MAC_X722 &&
+           val == I40E_GL_FWSTS_FWS0B_STAGE_FW_UPDATE_POR_REQUIRED) {
+               pci_wake_from_d3(pdev, false);
+               device_set_wakeup_enable(&pdev->dev, false);
+       } else if (system_state == SYSTEM_POWER_OFF) {
                pci_wake_from_d3(pdev, pf->wol_en);
-               pci_set_power_state(pdev, PCI_D3hot);
        }
+       pci_set_power_state(pdev, PCI_D3hot);
 }
 
 #ifdef CONFIG_PM
@@ -13021,13 +15777,24 @@ static int i40e_suspend(struct device *dev)
        del_timer_sync(&pf->service_timer);
        cancel_work_sync(&pf->service_task);
 
+       /* Client close must be called explicitly here because the timer
+        * has been stopped.
+        */
+       i40e_notify_client_of_netdev_close(pf->vsi[pf->lan_vsi], false);
+
        if (test_bit(__I40E_DEBUG_MODE, pf->state))
                return 0;
 
        if (pf->wol_en && (pf->hw_features & I40E_HW_WOL_MC_MAGIC_PKT_WAKE))
                i40e_enable_mc_magic_wake(pf);
 
-       i40e_prep_for_reset(pf, false);
+       /* Since we're going to destroy queues during the
+        * i40e_clear_interrupt_scheme() we should hold the RTNL lock for this
+        * whole section
+        */
+       rtnl_lock();
+
+       i40e_prep_for_reset(pf, true);
 
        wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0));
        wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0));
@@ -13039,6 +15806,8 @@ static int i40e_suspend(struct device *dev)
         */
        i40e_clear_interrupt_scheme(pf);
 
+       rtnl_unlock();
+
        return 0;
 }
 
@@ -13056,6 +15825,11 @@ static int i40e_resume(struct device *dev)
        if (!test_bit(__I40E_SUSPENDED, pf->state))
                return 0;
 
+       /* We need to hold the RTNL lock prior to restoring interrupt schemes,
+        * since we're going to be restoring queues
+        */
+       rtnl_lock();
+
        /* We cleared the interrupt scheme when we suspended, so we need to
         * restore it now to resume device functionality.
         */
@@ -13066,7 +15840,9 @@ static int i40e_resume(struct device *dev)
        }
 
        clear_bit(__I40E_DOWN, pf->state);
-       i40e_reset_and_rebuild(pf, false, false);
+       i40e_reset_and_rebuild(pf, false, true);
+
+       rtnl_unlock();
 
        /* Clear suspended state last after everything is recovered */
        clear_bit(__I40E_SUSPENDED, pf->state);
@@ -13082,6 +15858,7 @@ static int i40e_resume(struct device *dev)
 /**
  * i40e_legacy_suspend - PCI callback for moving to D3
  * @pdev: PCI device information struct
+ * @state: PCI power state
  *
  * Legacy suspend handler for older kernels which do not support the newer
  * generic callbacks
@@ -13106,12 +15883,11 @@ static int i40e_legacy_suspend(struct pci_dev *pdev, pm_message_t state)
 }
 
 /**
- * i40e_resume - PCI callback for waking up from D3
+ * i40e_legacy_resume - PCI callback for waking up from D3
  * @pdev: PCI device information struct
  *
  * Legacy resume handler for kernels which do not support the newer generic
  * callbacks.
- * __always_unused
  **/
 static int i40e_legacy_resume(struct pci_dev *pdev)
 {
similarity index 97%
rename from i40e-dkms/i40e-2.4.6/src/i40e_nvm.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_nvm.c
index 1512a42c4eefc9bb4f94b0e8ec888e86f9c6c565..415a5a9c65a4805700be0f8f5fea41cbaa914770 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #include "i40e_prototype.h"
 
@@ -704,6 +684,7 @@ static const char *i40e_nvm_update_state_str[] = {
        "I40E_NVMUPD_EXEC_AQ",
        "I40E_NVMUPD_GET_AQ_RESULT",
        "I40E_NVMUPD_GET_AQ_EVENT",
+       "I40E_NVMUPD_GET_FEATURES",
 };
 
 /**
@@ -764,6 +745,31 @@ i40e_status i40e_nvmupd_command(struct i40e_hw *hw,
                return I40E_SUCCESS;
        }
 
+       /*
+        * A supported features request returns immediately
+        * rather than going into state machine
+        */
+       if (upd_cmd == I40E_NVMUPD_FEATURES) {
+               if (cmd->data_size < hw->nvmupd_features.size) {
+                       *perrno = -EFAULT;
+                       return I40E_ERR_BUF_TOO_SHORT;
+               }
+
+               /*
+                * If buffer is bigger than i40e_nvmupd_features structure,
+                * make sure the trailing bytes are set to 0x0.
+                */
+               if (cmd->data_size > hw->nvmupd_features.size)
+                       i40e_memset(bytes + hw->nvmupd_features.size, 0x0,
+                                   cmd->data_size - hw->nvmupd_features.size,
+                                   I40E_NONDMA_MEM);
+
+               i40e_memcpy(bytes, &hw->nvmupd_features,
+                           hw->nvmupd_features.size, I40E_NONDMA_MEM);
+
+               return I40E_SUCCESS;
+       }
+
        /* Clear status even it is not read and log */
        if (hw->nvmupd_state == I40E_NVMUPD_STATE_ERROR) {
                i40e_debug(hw, I40E_DEBUG_NVM,
@@ -1161,6 +1167,7 @@ void i40e_nvmupd_clear_wait_state(struct i40e_hw *hw)
  * i40e_nvmupd_check_wait_event - handle NVM update operation events
  * @hw: pointer to the hardware structure
  * @opcode: the event that just happened
+ * @desc: AdminQ descriptor
  **/
 void i40e_nvmupd_check_wait_event(struct i40e_hw *hw, u16 opcode,
                                  struct i40e_aq_desc *desc)
@@ -1221,10 +1228,20 @@ static enum i40e_nvmupd_cmd i40e_nvmupd_validate_command(struct i40e_hw *hw,
                        upd_cmd = I40E_NVMUPD_READ_SA;
                        break;
                case I40E_NVM_EXEC:
-                       if (module == 0xf)
-                               upd_cmd = I40E_NVMUPD_STATUS;
-                       else if (module == 0)
+                       switch (module) {
+                       case I40E_NVM_EXEC_GET_AQ_RESULT:
                                upd_cmd = I40E_NVMUPD_GET_AQ_RESULT;
+                               break;
+                       case I40E_NVM_EXEC_FEATURES:
+                               upd_cmd = I40E_NVMUPD_FEATURES;
+                               break;
+                       case I40E_NVM_EXEC_STATUS:
+                               upd_cmd = I40E_NVMUPD_STATUS;
+                               break;
+                       default:
+                               *perrno = -EFAULT;
+                               return I40E_NVMUPD_INVALID;
+                       }
                        break;
                case I40E_NVM_AQE:
                        upd_cmd = I40E_NVMUPD_GET_AQ_EVENT;
similarity index 74%
rename from i40e-dkms/i40e-2.4.6/src/i40e_osdep.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_osdep.h
index 279c4c1fb687b7170d1fc79f366f021ba4c4fe94..d3809cea52ea1910dce9bd999559d56e802517a5 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_OSDEP_H_
 #define _I40E_OSDEP_H_
similarity index 92%
rename from i40e-dkms/i40e-2.4.6/src/i40e_prototype.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_prototype.h
index 51106c7d3730e4d35555d82bb7072a0f97674383..ef1fe6910ea889b1a1058c61c254550286ddde0d 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_PROTOTYPE_H_
 #define _I40E_PROTOTYPE_H_
@@ -186,7 +166,7 @@ i40e_status i40e_aq_get_switch_config(struct i40e_hw *hw,
                                u16 buf_size, u16 *start_seid,
                                struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_set_switch_config(struct i40e_hw *hw,
-                               u16 flags, u16 valid_flags,
+                               u16 flags, u16 valid_flags, u8 mode,
                                struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_request_resource(struct i40e_hw *hw,
                                enum i40e_aq_resources_ids resource,
@@ -223,6 +203,9 @@ i40e_status i40e_aq_update_nvm(struct i40e_hw *hw, u8 module_pointer,
                                u32 offset, u16 length, void *data,
                                bool last_command, u8 preservation_flags,
                                struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_rearrange_nvm(struct i40e_hw *hw,
+                               u8 rearrange_nvm,
+                               struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_nvm_progress(struct i40e_hw *hw, u8 *progress,
                                struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_get_lldp_mib(struct i40e_hw *hw, u8 bridge_type,
@@ -307,24 +290,24 @@ i40e_status i40e_aq_query_switch_comp_bw_config(struct i40e_hw *hw,
                struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_resume_port_tx(struct i40e_hw *hw,
                                struct i40e_asq_cmd_details *cmd_details);
+enum i40e_status_code
+i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
+                            struct i40e_aqc_cloud_filters_element_bb *filters,
+                            u8 filter_count);
+enum i40e_status_code
+i40e_aq_add_cloud_filters(struct i40e_hw *hw, u16 vsi,
+                         struct i40e_aqc_cloud_filters_element_data *filters,
+                         u8 filter_count);
+enum i40e_status_code
+i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 vsi,
+                         struct i40e_aqc_cloud_filters_element_data *filters,
+                         u8 filter_count);
+enum i40e_status_code
+i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
+                            struct i40e_aqc_cloud_filters_element_bb *filters,
+                            u8 filter_count);
 i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,
                                        struct i40e_lldp_variables *lldp_cfg);
-i40e_status i40e_aq_add_cloud_filters(struct i40e_hw *hw,
-               u16 vsi,
-               struct i40e_aqc_add_remove_cloud_filters_element_data *filters,
-               u8 filter_count);
-i40e_status i40e_aq_add_cloud_filters_big_buffer(struct i40e_hw *hw,
-       u16 seid,
-       struct i40e_aqc_add_rm_cloud_filt_elem_ext *filters,
-       u8 filter_count);
-i40e_status i40e_aq_remove_cloud_filters(struct i40e_hw *hw,
-               u16 vsi,
-               struct i40e_aqc_add_remove_cloud_filters_element_data *filters,
-               u8 filter_count);
-i40e_status i40e_aq_remove_cloud_filters_big_buffer(
-       struct i40e_hw *hw, u16 seid,
-       struct i40e_aqc_add_rm_cloud_filt_elem_ext *filters,
-       u8 filter_count);
 i40e_status i40e_aq_replace_cloud_filters(struct i40e_hw *hw,
                struct i40e_aqc_replace_cloud_filters_cmd *filters,
                struct i40e_aqc_replace_cloud_filters_cmd_buf *cmd_buf);
@@ -441,11 +424,11 @@ i40e_status i40e_aq_rx_ctl_write_register(struct i40e_hw *hw,
                                struct i40e_asq_cmd_details *cmd_details);
 void i40e_write_rx_ctl(struct i40e_hw *hw, u32 reg_addr, u32 reg_val);
 i40e_status i40e_aq_set_phy_register(struct i40e_hw *hw,
-                               u8 phy_select, u8 dev_addr,
+                               u8 phy_select, u8 dev_addr, bool page_change,
                                u32 reg_addr, u32 reg_val,
                                struct i40e_asq_cmd_details *cmd_details);
 i40e_status i40e_aq_get_phy_register(struct i40e_hw *hw,
-                               u8 phy_select, u8 dev_addr,
+                               u8 phy_select, u8 dev_addr, bool page_change,
                                u32 reg_addr, u32 *reg_val,
                                struct i40e_asq_cmd_details *cmd_details);
 
similarity index 93%
rename from i40e-dkms/i40e-2.4.6/src/i40e_ptp.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_ptp.c
index 2ccfcb4fff54ae59bc95757be43271b60c8503e3..c284ab8826e26230f3f559a7b30ed7f673e7e933 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 /* this lets the macros that return timespec64 or structs compile cleanly with
  * W=2
@@ -41,9 +21,9 @@
  * At 1Gb link, the period is multiplied by 20. (32ns)
  * 1588 functionality is not supported at 100Mbps.
  */
-#define I40E_PTP_40GB_INCVAL 0x0199999999ULL
-#define I40E_PTP_10GB_INCVAL 0x0333333333ULL
-#define I40E_PTP_1GB_INCVAL  0x2000000000ULL
+#define I40E_PTP_40GB_INCVAL      0x0199999999ULL
+#define I40E_PTP_10GB_INCVAL_MULT 2
+#define I40E_PTP_1GB_INCVAL_MULT  20
 
 #define I40E_PRTTSYN_CTL1_TSYNTYPE_V1  BIT(I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT)
 #define I40E_PRTTSYN_CTL1_TSYNTYPE_V2  (2 << \
@@ -131,17 +111,24 @@ static int i40e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
                ppb = -ppb;
        }
 
-       smp_mb(); /* Force any pending update before accessing. */
-       adj = READ_ONCE(pf->ptp_base_adj);
-
-       freq = adj;
+       freq = I40E_PTP_40GB_INCVAL;
        freq *= ppb;
        diff = div_u64(freq, 1000000000ULL);
 
        if (neg_adj)
-               adj -= diff;
+               adj = I40E_PTP_40GB_INCVAL - diff;
        else
-               adj += diff;
+               adj = I40E_PTP_40GB_INCVAL + diff;
+
+       /* At some link speeds, the base incval is so large that directly
+        * multiplying by ppb would result in arithmetic overflow even when
+        * using a u64. Avoid this by instead calculating the new incval
+        * always in terms of the 40GbE clock rate and then multiplying by the
+        * link speed factor afterwards. This does result in slightly lower
+        * precision at lower link speeds, but it is fairly minor.
+        */
+       smp_mb(); /* Force any pending update before accessing. */
+       adj *= READ_ONCE(pf->ptp_adj_mult);
 
        wr32(hw, I40E_PRTTSYN_INC_L, (u32)adj);
        wr32(hw, I40E_PRTTSYN_INC_H, (u32)(adj >> 32));
@@ -370,10 +357,12 @@ void i40e_ptp_rx_hang(struct i40e_pf *pf)
  * This watchdog task is run periodically to make sure that we clear the Tx
  * timestamp logic if we don't obtain a timestamp in a reasonable amount of
  * time. It is unexpected in the normal case but if it occurs it results in
- * permanently prevent timestamps of future packets
+ * permanently preventing timestamps of future packets.
  **/
 void i40e_ptp_tx_hang(struct i40e_pf *pf)
 {
+       struct sk_buff *skb;
+
        if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx)
                return;
 
@@ -386,9 +375,12 @@ void i40e_ptp_tx_hang(struct i40e_pf *pf)
         * within a second it is reasonable to assume that we never will.
         */
        if (time_is_before_jiffies(pf->ptp_tx_start + HZ)) {
-               dev_kfree_skb_any(pf->ptp_tx_skb);
+               skb = pf->ptp_tx_skb;
                pf->ptp_tx_skb = NULL;
                clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state);
+
+               /* Free the skb after we clear the bitlock */
+               dev_kfree_skb_any(skb);
                pf->tx_hwtstamp_timeouts++;
        }
 }
@@ -498,6 +490,7 @@ void i40e_ptp_set_increment(struct i40e_pf *pf)
        struct i40e_link_status *hw_link_info;
        struct i40e_hw *hw = &pf->hw;
        u64 incval;
+       u32 mult;
 
        hw_link_info = &hw->phy.link_info;
 
@@ -505,10 +498,10 @@ void i40e_ptp_set_increment(struct i40e_pf *pf)
 
        switch (hw_link_info->link_speed) {
        case I40E_LINK_SPEED_10GB:
-               incval = I40E_PTP_10GB_INCVAL;
+               mult = I40E_PTP_10GB_INCVAL_MULT;
                break;
        case I40E_LINK_SPEED_1GB:
-               incval = I40E_PTP_1GB_INCVAL;
+               mult = I40E_PTP_1GB_INCVAL_MULT;
                break;
        case I40E_LINK_SPEED_100MB:
        {
@@ -519,15 +512,20 @@ void i40e_ptp_set_increment(struct i40e_pf *pf)
                                 "1588 functionality is not supported at 100 Mbps. Stopping the PHC.\n");
                        warn_once++;
                }
-               incval = 0;
+               mult = 0;
                break;
        }
        case I40E_LINK_SPEED_40GB:
        default:
-               incval = I40E_PTP_40GB_INCVAL;
+               mult = 1;
                break;
        }
 
+       /* The increment value is calculated by taking the base 40GbE incvalue
+        * and multiplying it by a factor based on the link speed.
+        */
+       incval = I40E_PTP_40GB_INCVAL * mult;
+
        /* Write the new increment value into the increment register. The
         * hardware will not update the clock until both registers have been
         * written.
@@ -536,14 +534,14 @@ void i40e_ptp_set_increment(struct i40e_pf *pf)
        wr32(hw, I40E_PRTTSYN_INC_H, (u32)(incval >> 32));
 
        /* Update the base adjustement value. */
-       WRITE_ONCE(pf->ptp_base_adj, incval);
+       WRITE_ONCE(pf->ptp_adj_mult, mult);
        smp_mb(); /* Force the above update. */
 }
 
 /**
  * i40e_ptp_get_ts_config - ioctl interface to read the HW timestamping
  * @pf: Board private structure
- * @ifreq: ioctl data
+ * @ifr: ioctl data
  *
  * Obtain the current hardware timestamping settigs as requested. To do this,
  * keep a shadow copy of the timestamp settings rather than attempting to
@@ -689,7 +687,7 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf,
 /**
  * i40e_ptp_set_ts_config - ioctl interface to control the HW timestamping
  * @pf: Board private structure
- * @ifreq: ioctl data
+ * @ifr: ioctl data
  *
  * Respond to the user filter requests and make the appropriate hardware
  * changes here. The XL710 cannot support splitting of the Tx/Rx timestamping
@@ -738,7 +736,8 @@ static long i40e_ptp_create_clock(struct i40e_pf *pf)
        if (!IS_ERR_OR_NULL(pf->ptp_clock))
                return 0;
 
-       strncpy(pf->ptp_caps.name, i40e_driver_name, sizeof(pf->ptp_caps.name));
+       strlcpy(pf->ptp_caps.name, i40e_driver_name,
+               sizeof(pf->ptp_caps.name) - 1);
        pf->ptp_caps.owner = THIS_MODULE;
        pf->ptp_caps.max_adj = 999999999;
        pf->ptp_caps.n_ext_ts = 0;
@@ -845,9 +844,11 @@ void i40e_ptp_stop(struct i40e_pf *pf)
        pf->ptp_rx = false;
 
        if (pf->ptp_tx_skb) {
-               dev_kfree_skb_any(pf->ptp_tx_skb);
+               struct sk_buff *skb = pf->ptp_tx_skb;
+
                pf->ptp_tx_skb = NULL;
                clear_bit_unlock(__I40E_PTP_TX_IN_PROGRESS, pf->state);
+               dev_kfree_skb_any(skb);
        }
 
        if (pf->ptp_clock) {
similarity index 99%
rename from i40e-dkms/i40e-2.4.6/src/i40e_register.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_register.h
index 633cf30106935037c7e95090924df61912ff2436..bd36a1d7bd367495e2eb66d3d262d617d5d7f16e 100644 (file)
@@ -1,48 +1,28 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_REGISTER_H_
 #define _I40E_REGISTER_H_
 
-#define I40E_GL_ARQBAH 0x000801C0 /* Reset: EMPR */
+#define I40E_GL_ARQBAH              0x000801C0 /* Reset: EMPR */
 #define I40E_GL_ARQBAH_ARQBAH_SHIFT 0
-#define I40E_GL_ARQBAH_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ARQBAH_ARQBAH_SHIFT)
-#define I40E_GL_ARQBAL 0x000800C0 /* Reset: EMPR */
+#define I40E_GL_ARQBAH_ARQBAH_MASK  I40E_MASK(0xFFFFFFFF, I40E_GL_ARQBAH_ARQBAH_SHIFT)
+#define I40E_GL_ARQBAL              0x000800C0 /* Reset: EMPR */
 #define I40E_GL_ARQBAL_ARQBAL_SHIFT 0
-#define I40E_GL_ARQBAL_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ARQBAL_ARQBAL_SHIFT)
-#define I40E_GL_ARQH 0x000803C0 /* Reset: EMPR */
+#define I40E_GL_ARQBAL_ARQBAL_MASK  I40E_MASK(0xFFFFFFFF, I40E_GL_ARQBAL_ARQBAL_SHIFT)
+#define I40E_GL_ARQH            0x000803C0 /* Reset: EMPR */
 #define I40E_GL_ARQH_ARQH_SHIFT 0
-#define I40E_GL_ARQH_ARQH_MASK I40E_MASK(0x3FF, I40E_GL_ARQH_ARQH_SHIFT)
-#define I40E_GL_ARQT 0x000804C0 /* Reset: EMPR */
+#define I40E_GL_ARQH_ARQH_MASK  I40E_MASK(0x3FF, I40E_GL_ARQH_ARQH_SHIFT)
+#define I40E_GL_ARQT            0x000804C0 /* Reset: EMPR */
 #define I40E_GL_ARQT_ARQT_SHIFT 0
-#define I40E_GL_ARQT_ARQT_MASK I40E_MASK(0x3FF, I40E_GL_ARQT_ARQT_SHIFT)
-#define I40E_GL_ATQBAH 0x00080140 /* Reset: EMPR */
+#define I40E_GL_ARQT_ARQT_MASK  I40E_MASK(0x3FF, I40E_GL_ARQT_ARQT_SHIFT)
+#define I40E_GL_ATQBAH              0x00080140 /* Reset: EMPR */
 #define I40E_GL_ATQBAH_ATQBAH_SHIFT 0
-#define I40E_GL_ATQBAH_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ATQBAH_ATQBAH_SHIFT)
-#define I40E_GL_ATQBAL 0x00080040 /* Reset: EMPR */
+#define I40E_GL_ATQBAH_ATQBAH_MASK  I40E_MASK(0xFFFFFFFF, I40E_GL_ATQBAH_ATQBAH_SHIFT)
+#define I40E_GL_ATQBAL              0x00080040 /* Reset: EMPR */
 #define I40E_GL_ATQBAL_ATQBAL_SHIFT 0
-#define I40E_GL_ATQBAL_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ATQBAL_ATQBAL_SHIFT)
-#define I40E_GL_ATQH 0x00080340 /* Reset: EMPR */
+#define I40E_GL_ATQBAL_ATQBAL_MASK  I40E_MASK(0xFFFFFFFF, I40E_GL_ATQBAL_ATQBAL_SHIFT)
+#define I40E_GL_ATQH            0x00080340 /* Reset: EMPR */
 #define I40E_GL_ATQH_ATQH_SHIFT 0
 #define I40E_GL_ATQH_ATQH_MASK I40E_MASK(0x3FF, I40E_GL_ATQH_ATQH_SHIFT)
 #define I40E_GL_ATQLEN 0x00080240 /* Reset: EMPR */
similarity index 70%
rename from i40e-dkms/i40e-2.4.6/src/i40e_status.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_status.h
index 16cdcec37d0a37dd2f1d7c91933d79369e446a49..77be0702d07c8c044469ac70406b3e26656f75ba 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_STATUS_H_
 #define _I40E_STATUS_H_
similarity index 84%
rename from i40e-dkms/i40e-2.4.6/src/i40e_trace.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_trace.h
index 210eae21ee694d5f521fbdcba523a4b0626c167d..b9866ee47b7cd70e716f54704585c643abc878f0 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef CONFIG_TRACEPOINTS
 #if !defined(_I40E_TRACE_H_)
similarity index 91%
rename from i40e-dkms/i40e-2.4.6/src/i40e_txrx.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_txrx.c
index eea26ba04124cda948c7681e06759f8d693b7b95..1859d78be81dd98900331865e5f6251785ef0d42 100644 (file)
@@ -1,27 +1,10 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #include <linux/prefetch.h>
+#ifdef HAVE_XDP_SUPPORT
+#include <net/xdp.h>
+#endif
 #include "i40e.h"
 #include "i40e_trace.h"
 #include "i40e_prototype.h"
@@ -325,7 +308,6 @@ static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
                if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
                    I40E_DEBUG_FD & pf->hw.debug_mask)
                        dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n");
-               pf->flags |= I40E_FLAG_FD_ATR_AUTO_DISABLED;
        } else {
                pf->fd_tcp4_filter_cnt--;
        }
@@ -479,7 +461,7 @@ static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
 /**
  * i40e_add_del_fdir - Build raw packets to add/del fdir filter
  * @vsi: pointer to the targeted VSI
- * @cmd: command to get or set RX flow classification rules
+ * @input: filter to add or delete
  * @add: true adds a filter, false removes it
  *
  **/
@@ -578,8 +560,14 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
                pf->fd_atr_cnt = i40e_get_current_atr_cnt(pf);
 
                if ((rx_desc->wb.qword0.hi_dword.fd_id == 0) &&
-                   pf->flags & I40E_FLAG_FD_SB_AUTO_DISABLED) {
-                       pf->flags |= I40E_FLAG_FD_ATR_AUTO_DISABLED;
+                   test_bit(__I40E_FD_SB_AUTO_DISABLED, pf->state)) {
+                       /* These set_bit() calls aren't atomic with the
+                        * test_bit() here, but worse case we potentially
+                        * disable ATR and queue a flush right after SB
+                        * support is re-enabled. That shouldn't cause an
+                        * issue in practice
+                        */
+                       set_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state);
                        set_bit(__I40E_FD_FLUSH_REQUESTED, pf->state);
                }
 
@@ -592,11 +580,10 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring,
                 */
                if (fcnt_prog >= (fcnt_avail - I40E_FDIR_BUFFER_FULL_MARGIN)) {
                        if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
-                           !(pf->flags & I40E_FLAG_FD_SB_AUTO_DISABLED)) {
-                               pf->flags |= I40E_FLAG_FD_SB_AUTO_DISABLED;
+                           !test_and_set_bit(__I40E_FD_SB_AUTO_DISABLED,
+                                             pf->state))
                                if (I40E_DEBUG_FD & pf->hw.debug_mask)
                                        dev_warn(&pdev->dev, "FD filter space full, new ntuple rules will not be added\n");
-                       }
                }
        } else if (error == BIT(I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) {
                if (I40E_DEBUG_FD & pf->hw.debug_mask)
@@ -616,6 +603,14 @@ static void i40e_unmap_and_free_tx_resource(struct i40e_ring *ring,
        if (tx_buffer->skb) {
                if (tx_buffer->tx_flags & I40E_TX_FLAGS_FD_SB)
                        kfree(tx_buffer->raw_buf);
+#ifdef HAVE_XDP_SUPPORT
+               else if (ring_is_xdp(ring))
+#ifdef HAVE_XDP_FRAME_STRUCT
+                       xdp_return_frame(tx_buffer->xdpf);
+#else
+                       page_frag_free(tx_buffer->raw_buf);
+#endif
+#endif
                else
                        dev_kfree_skb_any(tx_buffer->skb);
                if (dma_unmap_len(tx_buffer, len))
@@ -690,7 +685,7 @@ void i40e_free_tx_resources(struct i40e_ring *tx_ring)
 
 /**
  * i40e_get_tx_pending - how many tx descriptors not processed
- * @tx_ring: the ring of descriptors
+ * @ring: the ring of descriptors
  * @in_sw: use SW variables
  *
  * Since there is no access to the ring head register
@@ -816,8 +811,17 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
                total_bytes += tx_buf->bytecount;
                total_packets += tx_buf->gso_segs;
 
-               /* free the skb */
-               napi_consume_skb(tx_buf->skb, napi_budget);
+               /* free the skb/XDP data */
+#ifdef HAVE_XDP_SUPPORT
+               if (ring_is_xdp(tx_ring))
+#ifdef HAVE_XDP_FRAME_STRUCT
+                       xdp_return_frame(tx_buf->xdpf);
+#else
+                       page_frag_free(tx_buf->raw_buf);
+#endif
+               else
+#endif
+                       napi_consume_skb(tx_buf->skb, napi_budget);
 
                /* unmap skb header data */
                dma_unmap_single(tx_ring->dev,
@@ -893,6 +897,9 @@ static bool i40e_clean_tx_irq(struct i40e_vsi *vsi,
                        tx_ring->arm_wb = true;
        }
 
+       if (ring_is_xdp(tx_ring))
+               return !!budget;
+
        /* notify netdev of completed buffers */
        netdev_tx_completed_queue(txring_txq(tx_ring),
                                  total_packets, total_bytes);
@@ -1459,6 +1466,11 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
 void i40e_free_rx_resources(struct i40e_ring *rx_ring)
 {
        i40e_clean_rx_ring(rx_ring);
+#ifdef HAVE_XDP_BUFF_RXQ
+       if (rx_ring->vsi->type == I40E_VSI_MAIN)
+               xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+#endif
+       rx_ring->xdp_prog = NULL;
        kfree(rx_ring->rx_bi);
        rx_ring->rx_bi = NULL;
 
@@ -1478,6 +1490,7 @@ void i40e_free_rx_resources(struct i40e_ring *rx_ring)
 int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring)
 {
        struct device *dev = rx_ring->dev;
+       int err = -ENOMEM;
        int bi_size;
 
        /* warn if we are about to overwrite the pointer */
@@ -1506,12 +1519,22 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring)
        rx_ring->next_to_alloc = 0;
        rx_ring->next_to_clean = 0;
        rx_ring->next_to_use = 0;
+#ifdef HAVE_XDP_BUFF_RXQ
+       /* XDP RX-queue info only needed for RX rings exposed to XDP */
+       if (rx_ring->vsi->type == I40E_VSI_MAIN) {
+               err = xdp_rxq_info_reg(&rx_ring->xdp_rxq, rx_ring->netdev,
+                                      rx_ring->queue_index);
+               if (err < 0)
+                       goto err;
+       }
 
+       rx_ring->xdp_prog = rx_ring->vsi->xdp_prog;
+#endif
        return 0;
 err:
        kfree(rx_ring->rx_bi);
        rx_ring->rx_bi = NULL;
-       return -ENOMEM;
+       return err;
 }
 
 /**
@@ -1784,7 +1807,7 @@ static void i40e_rx_extra_counters(struct i40e_vsi *vsi, u32 rx_error,
 }
 
 #endif /* I40E_ADD_PROBES */
-#if defined(HAVE_VXLAN_RX_OFFLOAD) || defined(HAVE_GENEVE_RX_OFFLOAD) || defined(HAVE_UDP_ENC_RX_OFFLOAD) || defined(ESX55)
+#if defined(HAVE_VXLAN_RX_OFFLOAD) || defined(HAVE_GENEVE_RX_OFFLOAD) || defined(HAVE_UDP_ENC_RX_OFFLOAD)
 #define I40E_TUNNEL_SUPPORT
 #endif
 /**
@@ -1922,6 +1945,8 @@ static inline enum pkt_hash_types i40e_ptype_to_htype(u8 ptype)
  * i40e_rx_hash - set the hash value in the skb
  * @ring: descriptor ring
  * @rx_desc: specific descriptor
+ * @skb: skb currently being received and modified
+ * @rx_ptype: Rx packet type
  **/
 static inline void i40e_rx_hash(struct i40e_ring *ring,
                                union i40e_rx_desc *rx_desc,
@@ -1986,6 +2011,7 @@ void i40e_process_skb_fields(struct i40e_ring *rx_ring,
  * i40e_cleanup_headers - Correct empty headers
  * @rx_ring: rx descriptor ring packet is being transacted on
  * @skb: pointer to current skb being fixed
+ * @rx_desc: pointer to the EOP Rx descriptor
  *
  * Also address the case where we are pulling data in on pages only
  * and as such no data is present in the skb header.
@@ -1995,8 +2021,24 @@ void i40e_process_skb_fields(struct i40e_ring *rx_ring,
  *
  * Returns true if an error was encountered and skb was freed.
  **/
-static bool i40e_cleanup_headers(struct i40e_ring *rx_ring, struct sk_buff *skb)
+static bool i40e_cleanup_headers(struct i40e_ring *rx_ring, struct sk_buff *skb,
+                                union i40e_rx_desc *rx_desc)
 {
+       /* XDP packets use error pointer so abort at this point */
+       if (IS_ERR(skb))
+               return true;
+
+       /* ERR_MASK will only have valid bits if EOP set, and
+        * what we are doing here is actually checking
+        * I40E_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in
+        * the error field
+        */
+       if (unlikely(i40e_test_staterr(rx_desc,
+                                      BIT(I40E_RXD_QW1_ERROR_SHIFT)))) {
+               dev_kfree_skb_any(skb);
+               return true;
+       }
+
        /* if eth_skb_pad returns an error the skb was freed */
        if (eth_skb_pad(skb))
                return true;
@@ -2195,7 +2237,7 @@ static struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring,
  * i40e_construct_skb - Allocate skb and populate it
  * @rx_ring: rx descriptor ring to transact packets on
  * @rx_buffer: rx buffer to pull data from
- * @size: size of buffer to add to skb
+ * @xdp: xdp_buff pointing to the data
  *
  * This function allocates an skb.  It then populates it with the page
  * data from the current receive descriptor, taking care to set up the
@@ -2203,9 +2245,10 @@ static struct i40e_rx_buffer *i40e_get_rx_buffer(struct i40e_ring *rx_ring,
  */
 static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
                                          struct i40e_rx_buffer *rx_buffer,
-                                         unsigned int size)
+                                         struct xdp_buff *xdp)
 {
-       u8 *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
+       unsigned int size = (u8 *)xdp->data_end - (u8 *)xdp->data;
+
 #if (PAGE_SIZE < 8192)
        unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;
 #else
@@ -2216,9 +2259,9 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
        struct sk_buff *skb;
 
        /* prefetch first cache line of first page */
-       prefetch(va);
+       prefetch(xdp->data);
 #if L1_CACHE_BYTES < 128
-       prefetch((void *)(va + L1_CACHE_BYTES));
+       prefetch((void *)((u8 *)xdp->data + L1_CACHE_BYTES));
 #endif
 
        /* allocate a skb to store the frags */
@@ -2231,10 +2274,11 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
        /* Determine available headroom for copy */
        headlen = size;
        if (headlen > I40E_RX_HDR_SIZE)
-               headlen = eth_get_headlen(va, I40E_RX_HDR_SIZE);
+               headlen = eth_get_headlen(xdp->data, I40E_RX_HDR_SIZE);
 
        /* align pull length to size of long to optimize memcpy performance */
-       memcpy(__skb_put(skb, headlen), va, ALIGN(headlen, sizeof(long)));
+       memcpy(__skb_put(skb, headlen), xdp->data,
+              ALIGN(headlen, sizeof(long)));
 
        /* update all of the pointers */
        size -= headlen;
@@ -2262,36 +2306,38 @@ static struct sk_buff *i40e_construct_skb(struct i40e_ring *rx_ring,
  * i40e_build_skb - Build skb around an existing buffer
  * @rx_ring: rx descriptor ring to transact packets on
  * @rx_buffer: rx buffer to pull data from
- * @size: size of buffer to add to skb
+ * @xdp: xdp_buff pointing to the data
  *
  * This function builds an skb around an existing Rx buffer, taking care
  * to set up the skb correctly and avoid any memcpy overhead.
  */
 static struct sk_buff *i40e_build_skb(struct i40e_ring *rx_ring,
                                      struct i40e_rx_buffer *rx_buffer,
-                                     unsigned int size)
+                                     struct xdp_buff *xdp)
 {
-       void *va = page_address(rx_buffer->page) + rx_buffer->page_offset;
+       unsigned int size = (u8 *)xdp->data_end - (u8 *)xdp->data;
+
 #if (PAGE_SIZE < 8192)
        unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;
 #else
        unsigned int truesize = SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
-                               SKB_DATA_ALIGN(I40E_SKB_PAD + size);
+                               SKB_DATA_ALIGN(xdp->data_end -
+                                              xdp->data_hard_start);
 #endif
        struct sk_buff *skb;
 
        /* prefetch first cache line of first page */
-       prefetch(va);
+       prefetch(xdp->data);
 #if L1_CACHE_BYTES < 128
-       prefetch(va + L1_CACHE_BYTES);
+       prefetch(xdp->data + L1_CACHE_BYTES);
 #endif
        /* build an skb around the page buffer */
-       skb = build_skb(va - I40E_SKB_PAD, truesize);
+       skb = build_skb(xdp->data_hard_start, truesize);
        if (unlikely(!skb))
                return NULL;
 
        /* update pointers within the skb to store the data */
-       skb_reserve(skb, I40E_SKB_PAD);
+       skb_reserve(skb, xdp->data - xdp->data_hard_start);
        __skb_put(skb, size);
 
        /* buffer is used by skb, update page_offset */
@@ -2367,6 +2413,124 @@ static bool i40e_is_non_eop(struct i40e_ring *rx_ring,
        return true;
 }
 
+#define I40E_XDP_PASS 0
+#define I40E_XDP_CONSUMED 1
+#define I40E_XDP_TX 2
+
+#ifdef HAVE_XDP_SUPPORT
+#ifdef HAVE_XDP_FRAME_STRUCT
+static int i40e_xmit_xdp_ring(struct xdp_frame *xdp,
+                             struct i40e_ring *xdp_ring);
+
+static int i40e_xmit_xdp_tx_ring(struct xdp_buff *xdp,
+                                struct i40e_ring *xdp_ring)
+{
+       struct xdp_frame *xdpf = convert_to_xdp_frame(xdp);
+
+       if (unlikely(!xdpf))
+               return I40E_XDP_CONSUMED;
+
+       return i40e_xmit_xdp_ring(xdpf, xdp_ring);
+}
+#else
+static int i40e_xmit_xdp_ring(struct xdp_buff *xdp,
+                             struct i40e_ring *xdp_ring);
+#endif
+#endif
+
+/**
+ * i40e_run_xdp - run an XDP program
+ * @rx_ring: Rx ring being processed
+ * @xdp: XDP buffer containing the frame
+ **/
+static struct sk_buff *i40e_run_xdp(struct i40e_ring *rx_ring,
+                                   struct xdp_buff *xdp)
+{
+       int result = I40E_XDP_PASS;
+#ifdef HAVE_XDP_SUPPORT
+       struct i40e_ring *xdp_ring;
+       struct bpf_prog *xdp_prog;
+       u32 act;
+       int err;
+
+       rcu_read_lock();
+       xdp_prog = READ_ONCE(rx_ring->xdp_prog);
+
+       if (!xdp_prog)
+               goto xdp_out;
+
+       prefetchw(xdp->data_hard_start); /* xdp_frame write */
+
+       act = bpf_prog_run_xdp(xdp_prog, xdp);
+       switch (act) {
+       case XDP_PASS:
+               rx_ring->xdp_stats.xdp_pass++;
+               break;
+       case XDP_TX:
+               xdp_ring = rx_ring->vsi->xdp_rings[rx_ring->queue_index];
+#ifdef HAVE_XDP_FRAME_STRUCT
+               result = i40e_xmit_xdp_tx_ring(xdp, xdp_ring);
+#else
+               result = i40e_xmit_xdp_ring(xdp, xdp_ring);
+#endif
+               rx_ring->xdp_stats.xdp_tx++;
+               break;
+       case XDP_REDIRECT:
+               err = xdp_do_redirect(rx_ring->netdev, xdp, xdp_prog);
+               result = !err ? I40E_XDP_TX : I40E_XDP_CONSUMED;
+               if (!err)
+                       rx_ring->xdp_stats.xdp_redirect++;
+               else
+                       rx_ring->xdp_stats.xdp_redirect_fail++;
+               break;
+       default:
+               bpf_warn_invalid_xdp_action(act);
+               /* fallthrough -- abort and drop */
+       case XDP_ABORTED:
+               trace_xdp_exception(rx_ring->netdev, xdp_prog, act);
+               rx_ring->xdp_stats.xdp_unknown++;
+               /* fallthrough -- handle aborts by dropping packet */
+       case XDP_DROP:
+               result = I40E_XDP_CONSUMED;
+               rx_ring->xdp_stats.xdp_drop++;
+               break;
+       }
+xdp_out:
+       rcu_read_unlock();
+#endif /* HAVE_XDP_SUPPORT */
+       return (struct sk_buff *)ERR_PTR(-result);
+}
+
+/**
+ * i40e_rx_buffer_flip - adjusted rx_buffer to point to an unused region
+ * @rx_ring: Rx ring
+ * @rx_buffer: Rx buffer to adjust
+ * @size: Size of adjustment
+ **/
+static void i40e_rx_buffer_flip(struct i40e_ring *rx_ring,
+                               struct i40e_rx_buffer *rx_buffer,
+                               unsigned int size)
+{
+#if (PAGE_SIZE < 8192)
+       unsigned int truesize = i40e_rx_pg_size(rx_ring) / 2;
+
+       rx_buffer->page_offset ^= truesize;
+#else
+       unsigned int truesize = SKB_DATA_ALIGN(i40e_rx_offset(rx_ring) + size);
+
+       rx_buffer->page_offset += truesize;
+#endif
+}
+
+static inline void i40e_xdp_ring_update_tail(struct i40e_ring *xdp_ring)
+{
+       /* Force memory writes to complete before letting h/w
+        * know there are new descriptors to fetch.
+        */
+       wmb();
+       writel_relaxed(xdp_ring->next_to_use, xdp_ring->tail);
+}
+
 /**
  * i40e_clean_rx_irq - Clean completed descriptors from Rx ring - bounce buf
  * @rx_ring: rx descriptor ring to transact packets on
@@ -2384,7 +2548,12 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
        unsigned int total_rx_bytes = 0, total_rx_packets = 0;
        struct sk_buff *skb = rx_ring->skb;
        u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
-       bool failure = false;
+       bool failure = false, xdp_xmit = false;
+       struct xdp_buff xdp;
+
+#ifdef HAVE_XDP_BUFF_RXQ
+       xdp.rxq = &rx_ring->xdp_rxq;
+#endif
 
        while (likely(total_rx_packets < (unsigned int)budget)) {
                struct i40e_rx_buffer *rx_buffer;
@@ -2436,14 +2605,34 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
                skb = rx_buffer->skb;
                __skb_put(skb, size);
 #else
-               if (skb)
+               if (!skb) {
+                       xdp.data = page_address(rx_buffer->page) +
+                                  rx_buffer->page_offset;
+                       xdp.data_hard_start = (void *)((u8 *)xdp.data -
+                                             i40e_rx_offset(rx_ring));
+                       xdp.data_end = (void *)((u8 *)xdp.data + size);
+
+                       skb = i40e_run_xdp(rx_ring, &xdp);
+               }
+
+               if (IS_ERR(skb)) {
+                       if (PTR_ERR(skb) == -I40E_XDP_TX) {
+                               xdp_xmit = true;
+                               i40e_rx_buffer_flip(rx_ring, rx_buffer, size);
+                       } else {
+                               rx_buffer->pagecnt_bias++;
+                       }
+                       total_rx_bytes += size;
+                       total_rx_packets++;
+               } else if (skb) {
                        i40e_add_rx_frag(rx_ring, rx_buffer, skb, size);
 #ifdef HAVE_SWIOTLB_SKIP_CPU_SYNC
-               else if (ring_uses_build_skb(rx_ring))
-                       skb = i40e_build_skb(rx_ring, rx_buffer, size);
+               } else if (ring_uses_build_skb(rx_ring)) {
+                       skb = i40e_build_skb(rx_ring, rx_buffer, &xdp);
 #endif
-               else
-                       skb = i40e_construct_skb(rx_ring, rx_buffer, size);
+               } else {
+                       skb = i40e_construct_skb(rx_ring, rx_buffer, &xdp);
+               }
 
                /* exit if we failed to retrieve a buffer */
                if (!skb) {
@@ -2459,18 +2648,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
                if (i40e_is_non_eop(rx_ring, rx_desc, skb))
                        continue;
 
-               /* ERR_MASK will only have valid bits if EOP set, and
-                * what we are doing here is actually checking
-                * I40E_RX_DESC_ERROR_RXE_SHIFT, since it is the zeroth bit in
-                * the error field
-                */
-               if (unlikely(i40e_test_staterr(rx_desc, BIT(I40E_RXD_QW1_ERROR_SHIFT)))) {
-                       dev_kfree_skb_any(skb);
-                       skb = NULL;
-                       continue;
-               }
-
-               if (i40e_cleanup_headers(rx_ring, skb)) {
+               if (i40e_cleanup_headers(rx_ring, skb, rx_desc)) {
                        skb = NULL;
                        continue;
                }
@@ -2495,7 +2673,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
                /* update budget accounting */
                total_rx_packets++;
        }
+       if (xdp_xmit) {
+               struct i40e_ring *xdp_ring =
+                       rx_ring->vsi->xdp_rings[rx_ring->queue_index];
 
+               i40e_xdp_ring_update_tail(xdp_ring);
+               xdp_do_flush_map();
+       }
        rx_ring->skb = skb;
 
        u64_stats_update_begin(&rx_ring->syncp);
@@ -2742,7 +2926,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
        if (!(pf->flags & I40E_FLAG_FD_ATR_ENABLED))
                return;
 
-       if (pf->flags & I40E_FLAG_FD_ATR_AUTO_DISABLED)
+       if (test_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state))
                return;
 
        /* if sampling is disabled do nothing */
@@ -2785,7 +2969,7 @@ static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
        th = (struct tcphdr *)(hdr.network + hlen);
 
        /* Due to lack of space, no more new filters can be programmed */
-       if (th->syn && (pf->flags & I40E_FLAG_FD_ATR_AUTO_DISABLED))
+       if (th->syn && test_bit(__I40E_FD_ATR_AUTO_DISABLED, pf->state))
                return;
 
        if (pf->flags & I40E_FLAG_HW_ATR_EVICT_ENABLED) {
@@ -3124,6 +3308,7 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb,
 #else
                skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
 #endif
+               pf->ptp_tx_start = jiffies;
                pf->ptp_tx_skb = skb_get(skb);
        } else {
                pf->tx_hwtstamp_skipped++;
@@ -3608,6 +3793,11 @@ static inline int i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
        tx_desc->cmd_type_offset_bsz =
                        build_ctob(td_cmd, td_offset, size, td_tag);
 
+       /* timestamp the skb as late as possible, just prior to notifying
+        * the MAC that it should transmit this packet
+        */
+       skb_tx_timestamp(skb);
+
        /* Force memory writes to complete before letting h/w know there
         * are new descriptors to fetch.
         *
@@ -3673,6 +3863,71 @@ u16 i40e_lan_select_queue(struct net_device *netdev, struct sk_buff *skb)
 }
 
 #endif /* !HAVE_NET_DEVICE_OPS && HAVE_NETDEV_SELECT_QUEUE */
+
+#ifdef HAVE_XDP_SUPPORT
+/**
+ * i40e_xmit_xdp_ring - transmits an XDP buffer to an XDP Tx ring
+ * @xdp: frame data to transmit
+ * @xdp_ring: XDP Tx ring
+ **/
+#ifdef HAVE_XDP_FRAME_STRUCT
+static int i40e_xmit_xdp_ring(struct xdp_frame *xdp,
+                             struct i40e_ring *xdp_ring)
+#else
+static int i40e_xmit_xdp_ring(struct xdp_buff *xdp,
+                             struct i40e_ring *xdp_ring)
+#endif
+{
+       u16 i = xdp_ring->next_to_use;
+       struct i40e_tx_buffer *tx_bi;
+       struct i40e_tx_desc *tx_desc;
+       dma_addr_t dma;
+       void *data;
+       u32 size;
+
+       size = xdp_get_len(xdp);
+       data = xdp->data;
+
+       if (!unlikely(I40E_DESC_UNUSED(xdp_ring))) {
+               xdp_ring->tx_stats.tx_busy++;
+               return I40E_XDP_CONSUMED;
+       }
+       dma = dma_map_single(xdp_ring->dev, data, size, DMA_TO_DEVICE);
+       if (dma_mapping_error(xdp_ring->dev, dma))
+               return I40E_XDP_CONSUMED;
+       tx_bi = &xdp_ring->tx_bi[i];
+       tx_bi->bytecount = size;
+       tx_bi->gso_segs = 1;
+#ifdef HAVE_XDP_FRAME_STRUCT
+       tx_bi->xdpf = xdp;
+#else
+       tx_bi->raw_buf = data;
+#endif
+
+       /* record length, and DMA address */
+       dma_unmap_len_set(tx_bi, len, size);
+       dma_unmap_addr_set(tx_bi, dma, dma);
+
+       tx_desc = I40E_TX_DESC(xdp_ring, i);
+       tx_desc->buffer_addr = cpu_to_le64(dma);
+       tx_desc->cmd_type_offset_bsz = build_ctob(I40E_TX_DESC_CMD_ICRC
+                                                 | I40E_TXD_CMD,
+                                                 0, size, 0);
+
+       /* Make certain all of the status bits have been updated
+        * before next_to_watch is written.
+        */
+       smp_wmb();
+
+       i++;
+       if (i == xdp_ring->count)
+               i = 0;
+       tx_bi->next_to_watch = tx_desc;
+       xdp_ring->next_to_use = i;
+       return I40E_XDP_TX;
+}
+#endif
+
 /**
  * i40e_xmit_frame_ring - Sends buffer on Tx ring
  * @skb:     send buffer
@@ -3761,7 +4016,6 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
                tx_flags |= I40E_TX_FLAGS_TSYN;
 
 #endif /* HAVE_PTP_1588_CLOCK */
-       skb_tx_timestamp(skb);
 
        /* always enable CRC insertion offload */
        td_cmd |= I40E_TX_DESC_CMD_ICRC;
@@ -3827,3 +4081,90 @@ netdev_tx_t i40e_lan_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        return i40e_xmit_frame_ring(skb, tx_ring);
 }
+
+#ifdef HAVE_XDP_SUPPORT
+/**
+ * i40e_xdp_xmit - Implements ndo_xdp_xmit
+ * @dev: netdev
+ * @n: amount of frames
+ * @frames: XDP frames
+ * @flags: XDP xmit flags
+ *
+ * Returns number of frames successfully sent. Frames that fail are
+ * free'ed via XDP return API.
+ *
+ * For error cases, a negative errno code is returned and no-frames
+ * are transmitted (caller must handle freeing frames).
+ **/
+#ifdef HAVE_XDP_FRAME_STRUCT
+int i40e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
+                 u32 flags)
+#else
+int i40e_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp)
+#endif
+{
+       struct i40e_netdev_priv *np = netdev_priv(dev);
+       unsigned int queue_index = smp_processor_id();
+       struct i40e_vsi *vsi = np->vsi;
+#ifdef HAVE_XDP_FRAME_STRUCT
+       struct i40e_ring *xdp_ring;
+       int drops = 0;
+       int i;
+#endif
+       int err;
+
+       if (test_bit(__I40E_VSI_DOWN, vsi->state))
+               return -ENETDOWN;
+
+       if (!i40e_enabled_xdp_vsi(vsi) || queue_index >= vsi->num_queue_pairs)
+               return -ENXIO;
+#ifdef HAVE_XDP_FRAME_STRUCT
+       if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK))
+               return -EINVAL;
+
+       xdp_ring = vsi->xdp_rings[queue_index];
+
+       for (i = 0; i < n; i++) {
+               struct xdp_frame *xdpf = frames[i];
+
+               err = i40e_xmit_xdp_ring(xdpf, xdp_ring);
+               if (err != I40E_XDP_TX) {
+                       xdp_return_frame_rx_napi(xdpf);
+                       drops++;
+               }
+       }
+
+       if (unlikely(flags & XDP_XMIT_FLUSH))
+               i40e_xdp_ring_update_tail(xdp_ring);
+
+       return n - drops;
+#else
+       err = i40e_xmit_xdp_ring(xdp, vsi->xdp_rings[queue_index]);
+
+       if (err != I40E_XDP_TX)
+               return -ENOSPC;
+
+       return 0;
+#endif
+}
+
+/**
+ * i40e_xdp_flush - Implements ndo_xdp_flush
+ * @dev: netdev
+ **/
+void i40e_xdp_flush(struct net_device *dev)
+{
+       struct i40e_netdev_priv *np = netdev_priv(dev);
+       unsigned int queue_index = smp_processor_id();
+       struct i40e_vsi *vsi = np->vsi;
+
+       if (test_bit(__I40E_VSI_DOWN, vsi->state))
+               return;
+
+       if (!i40e_enabled_xdp_vsi(vsi) || queue_index >= vsi->num_queue_pairs)
+               return;
+
+       i40e_xdp_ring_update_tail(vsi->xdp_rings[queue_index]);
+}
+#endif
+
similarity index 93%
rename from i40e-dkms/i40e-2.4.6/src/i40e_txrx.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_txrx.h
index 2100da8426b267b98b052d9a98a92795613ff674..102742e990b4fc754d27b5b6d0c66072a75a0da9 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_TXRX_H_
 #define _I40E_TXRX_H_
@@ -287,7 +267,7 @@ static inline unsigned int i40e_txd_use_count(unsigned int size)
 }
 
 /* Tx Descriptors needed, worst case */
-#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
+#define DESC_NEEDED (MAX_SKB_FRAGS + 6)
 #define I40E_MIN_DESC_PENDING  4
 
 #define I40E_TX_FLAGS_HW_VLAN          BIT(1)
@@ -310,6 +290,7 @@ static inline unsigned int i40e_txd_use_count(unsigned int size)
 struct i40e_tx_buffer {
        struct i40e_tx_desc *next_to_watch;
        union {
+               struct xdp_frame *xdpf;
                struct sk_buff *skb;
                void *raw_buf;
        };
@@ -341,6 +322,17 @@ struct i40e_queue_stats {
        u64 bytes;
 };
 
+#ifdef HAVE_XDP_SUPPORT
+struct i40e_xdp_stats {
+       u64 xdp_pass;
+       u64 xdp_drop;
+       u64 xdp_tx;
+       u64 xdp_unknown;
+       u64 xdp_redirect;
+       u64 xdp_redirect_fail;
+};
+#endif
+
 struct i40e_tx_queue_stats {
        u64 restart_queue;
        u64 tx_busy;
@@ -381,6 +373,7 @@ struct i40e_ring {
        void *desc;                     /* Descriptor ring memory */
        struct device *dev;             /* Used for DMA mapping */
        struct net_device *netdev;      /* netdev ring maps to */
+       struct bpf_prog *xdp_prog;
        union {
                struct i40e_tx_buffer *tx_bi;
                struct i40e_rx_buffer *rx_bi;
@@ -415,11 +408,15 @@ struct i40e_ring {
        u16 flags;
 #define I40E_TXR_FLAGS_WB_ON_ITR               BIT(0)
 #define I40E_RXR_FLAGS_BUILD_SKB_ENABLED       BIT(1)
+#define I40E_TXR_FLAGS_XDP                     BIT(2)
 
        /* stats structs */
        struct i40e_queue_stats stats;
 #ifdef HAVE_NDO_GET_STATS64
        struct u64_stats_sync syncp;
+#endif
+#ifdef HAVE_XDP_SUPPORT
+       struct i40e_xdp_stats xdp_stats;
 #endif
        union {
                struct i40e_tx_queue_stats tx_stats;
@@ -442,6 +439,11 @@ struct i40e_ring {
                                         * i40e_clean_rx_ring_irq() is called
                                         * for this ring.
                                         */
+
+       struct i40e_channel *ch;
+#ifdef HAVE_XDP_BUFF_RXQ
+       struct xdp_rxq_info xdp_rxq;
+#endif
 } ____cacheline_internodealigned_in_smp;
 
 static inline bool ring_uses_build_skb(struct i40e_ring *ring)
@@ -466,6 +468,16 @@ static inline void clear_ring_build_skb_enabled(struct i40e_ring *ring)
 #define I40E_ITR_ADAPTIVE_BULK          0x0000
 #define ITR_IS_BULK(x) (!((x) & I40E_ITR_ADAPTIVE_LATENCY))
 
+static inline bool ring_is_xdp(struct i40e_ring *ring)
+{
+       return !!(ring->flags & I40E_TXR_FLAGS_XDP);
+}
+
+static inline void set_ring_xdp(struct i40e_ring *ring)
+{
+       ring->flags |= I40E_TXR_FLAGS_XDP;
+}
+
 struct i40e_ring_container {
        struct i40e_ring *ring;         /* pointer to linked list of ring(s) */
        unsigned long next_update;      /* jiffies value of next update */
@@ -509,6 +521,27 @@ u32 i40e_get_tx_pending(struct i40e_ring *ring, bool in_sw);
 void i40e_detect_recover_hung(struct i40e_vsi *vsi);
 int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size);
 bool __i40e_chk_linearize(struct sk_buff *skb);
+#ifdef HAVE_XDP_FRAME_STRUCT
+int i40e_xdp_xmit(struct net_device *dev, int n, struct xdp_frame **frames,
+                 u32 flags);
+#else
+int i40e_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp);
+#endif
+void i40e_xdp_flush(struct net_device *dev);
+
+#ifdef HAVE_XDP_SUPPORT
+#ifdef HAVE_XDP_FRAME_STRUCT
+static inline u32 xdp_get_len(struct xdp_frame *xdp)
+{
+       return xdp->len;
+}
+#else
+static inline u32 xdp_get_len(struct xdp_buff *xdp)
+{
+       return xdp->data_end - xdp->data;
+}
+#endif
+#endif
 
 /**
  * i40e_get_head - Retrieve head from head writeback
similarity index 96%
rename from i40e-dkms/i40e-2.4.6/src/i40e_type.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_type.h
index a1a1240f7beaa0a8c60a8facb1ece1abdcac50e1..ecdc5ef83c24fec7b3dba70db5379e1fe152f0ef 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_TYPE_H_
 #define _I40E_TYPE_H_
@@ -36,7 +16,7 @@
 #define I40E_MASK(mask, shift) (mask << shift)
 
 #define I40E_MAX_VSI_QP                        16
-#define I40E_MAX_VF_VSI                        3
+#define I40E_MAX_VF_VSI                        4
 #define I40E_MAX_CHAINED_RX_BUFFERS    5
 #define I40E_MAX_PF_UDP_OFFLOAD_PORTS  16
 
@@ -278,6 +258,12 @@ struct i40e_phy_info {
                                             I40E_PHY_TYPE_OFFSET)
 #define I40E_CAP_PHY_TYPE_25GBASE_ACC BIT_ULL(I40E_PHY_TYPE_25GBASE_ACC + \
                                             I40E_PHY_TYPE_OFFSET)
+/* Offset for 2.5G/5G PHY Types value to bit number conversion */
+#define I40E_PHY_TYPE_OFFSET2 (-10)
+#define I40E_CAP_PHY_TYPE_2_5GBASE_T BIT_ULL(I40E_PHY_TYPE_2_5GBASE_T + \
+                                            I40E_PHY_TYPE_OFFSET2)
+#define I40E_CAP_PHY_TYPE_5GBASE_T BIT_ULL(I40E_PHY_TYPE_5GBASE_T + \
+                                            I40E_PHY_TYPE_OFFSET2)
 #define I40E_HW_CAP_MAX_GPIO                   30
 enum i40e_acpi_programming_method {
        I40E_ACPI_PROGRAMMING_METHOD_HW_FVL = 0,
@@ -295,6 +281,16 @@ struct i40e_hw_capabilities {
 #define I40E_NVM_IMAGE_TYPE_CLOUD      0x2
 #define I40E_NVM_IMAGE_TYPE_UDP_CLOUD  0x3
 
+       /* Cloud filter modes:
+        * Mode1: Filter on L4 port only
+        * Mode2: Filter for non-tunneled traffic
+        * Mode3: Filter for tunnel traffic
+        */
+#define I40E_CLOUD_FILTER_MODE1        0x6
+#define I40E_CLOUD_FILTER_MODE2        0x7
+#define I40E_CLOUD_FILTER_MODE3        0x8
+#define I40E_SWITCH_MODE_MASK  0xF
+
        u32  management_mode;
        u32  mng_protocols_over_mctp;
 #define I40E_MNG_PROTOCOL_PLDM         0x2
@@ -408,6 +404,7 @@ enum i40e_nvmupd_cmd {
        I40E_NVMUPD_EXEC_AQ,
        I40E_NVMUPD_GET_AQ_RESULT,
        I40E_NVMUPD_GET_AQ_EVENT,
+       I40E_NVMUPD_FEATURES,
 };
 
 enum i40e_nvmupd_state {
@@ -443,6 +440,10 @@ enum i40e_nvmupd_state {
 #define I40E_NVM_AQE                           0xe
 #define I40E_NVM_EXEC                          0xf
 
+#define I40E_NVM_EXEC_GET_AQ_RESULT            0x0
+#define I40E_NVM_EXEC_FEATURES                 0xe
+#define I40E_NVM_EXEC_STATUS                   0xf
+
 #define I40E_NVM_ADAPT_SHIFT   16
 #define I40E_NVM_ADAPT_MASK    (0xffffULL << I40E_NVM_ADAPT_SHIFT)
 
@@ -457,6 +458,20 @@ struct i40e_nvm_access {
        u8 data[1];
 };
 
+/* NVMUpdate features API */
+#define I40E_NVMUPD_FEATURES_API_VER_MAJOR             0
+#define I40E_NVMUPD_FEATURES_API_VER_MINOR             14
+#define I40E_NVMUPD_FEATURES_API_FEATURES_ARRAY_LEN    12
+
+#define I40E_NVMUPD_FEATURE_FLAT_NVM_SUPPORT           BIT(0)
+
+struct i40e_nvmupd_features {
+       u8 major;
+       u8 minor;
+       u16 size;
+       u8 features[I40E_NVMUPD_FEATURES_API_FEATURES_ARRAY_LEN];
+};
+
 /* (Q)SFP module access definitions */
 #define I40E_I2C_EEPROM_DEV_ADDR       0xA0
 #define I40E_I2C_EEPROM_DEV_ADDR2      0xA2
@@ -648,6 +663,7 @@ struct i40e_hw {
 #define I40E_HW_FLAG_802_1AD_CAPABLE        BIT_ULL(1)
 #define I40E_HW_FLAG_AQ_PHY_ACCESS_CAPABLE  BIT_ULL(2)
 #define I40E_HW_FLAG_NVM_READ_REQUIRES_LOCK BIT_ULL(3)
+#define I40E_HW_FLAG_FW_LLDP_STOPPABLE     BIT_ULL(4)
        u64 flags;
 
        /* Used in set switch config AQ command */
@@ -655,6 +671,9 @@ struct i40e_hw {
        u16 first_tag;
        u16 second_tag;
 
+       /* NVMUpdate features */
+       struct i40e_nvmupd_features nvmupd_features;
+
        /* debug mask */
        u32 debug_mask;
        char err_str[16];
@@ -1318,7 +1337,8 @@ struct i40e_hw_port_stats {
 
 /* Checksum and Shadow RAM pointers */
 #define I40E_SR_NVM_CONTROL_WORD               0x00
-#define I40E_SR_EMP_MODULE_PTR                 0x0F
+#define I40E_EMP_MODULE_PTR                    0x0F
+#define I40E_SR_EMP_MODULE_PTR                 0x48
 #define I40E_SR_PBA_FLAGS                      0x15
 #define I40E_SR_PBA_BLOCK_PTR                  0x16
 #define I40E_SR_BOOT_CONFIG_PTR                        0x17
@@ -1343,6 +1363,9 @@ struct i40e_hw_port_stats {
 #define I40E_SR_CONTROL_WORD_1_MASK    (0x03 << I40E_SR_CONTROL_WORD_1_SHIFT)
 #define I40E_SR_CONTROL_WORD_1_NVM_BANK_VALID  BIT(5)
 #define I40E_SR_NVM_MAP_STRUCTURE_TYPE         BIT(12)
+#define I40E_PTR_TYPE                          BIT(15)
+#define I40E_SR_OCP_CFG_WORD0                  0x2B
+#define I40E_SR_OCP_ENABLED                    BIT(15)
 
 /* Shadow RAM related */
 #define I40E_SR_SECTOR_SIZE_IN_WORDS   0x800
@@ -1457,7 +1480,8 @@ enum i40e_reset_type {
 };
 
 /* IEEE 802.1AB LLDP Agent Variables from NVM */
-#define I40E_NVM_LLDP_CFG_PTR          0xD
+#define I40E_NVM_LLDP_CFG_PTR   0x06
+#define I40E_SR_LLDP_CFG_PTR    0x31
 struct i40e_lldp_variables {
        u16 length;
        u16 adminstatus;
similarity index 51%
rename from i40e-dkms/i40e-2.4.6/src/i40e_virtchnl_pf.c
rename to i40e-dkms/i40e-2.7.29/src/i40e_virtchnl_pf.c
index 6c7549f79b67d82558bc9698e0522a3aa13f17a3..18d66a15ef712d2889c177dc716b1ccc1e15704e 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #include "i40e.h"
 
@@ -28,8 +8,8 @@
 /**
  * i40e_vc_vf_broadcast
  * @pf: pointer to the PF structure
- * @opcode: operation code
- * @retval: return value
+ * @v_opcode: operation code
+ * @v_retval: return value
  * @msg: pointer to the msg buffer
  * @msglen: msg length
  *
@@ -258,6 +238,38 @@ static u16 i40e_vc_get_pf_queue_id(struct i40e_vf *vf, u16 vsi_id,
        return pf_queue_id;
 }
 
+/**
+ * i40e_get_real_pf_qid
+ * @vf: pointer to the VF info
+ * @vsi_id: vsi id
+ * @queue_id: queue number
+ *
+ * wrapper function to get pf_queue_id handling ADq code as well
+ **/
+static u16 i40e_get_real_pf_qid(struct i40e_vf *vf, u16 vsi_id, u16 queue_id)
+{
+       int i;
+
+       if (vf->adq_enabled) {
+               /* Although VF considers all the queues(can be 1 to 16) as its
+                * own but they may actually belong to different VSIs(up to 4).
+                * We need to find which queues belongs to which VSI.
+                */
+               for (i = 0; i < vf->num_tc; i++) {
+                       if (queue_id < vf->ch[i].num_qps) {
+                               vsi_id = vf->ch[i].vsi_id;
+                               break;
+                       }
+                       /* find right queue id which is relative to a
+                        * given VSI.
+                        */
+                       queue_id -= vf->ch[i].num_qps;
+               }
+       }
+
+       return i40e_vc_get_pf_queue_id(vf, vsi_id, queue_id);
+}
+
 /**
  * i40e_config_irq_link_list
  * @vf: pointer to the VF info
@@ -311,7 +323,7 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id,
 
        vsi_queue_id = next_q / I40E_VIRTCHNL_SUPPORTED_QTYPES;
        qtype = next_q % I40E_VIRTCHNL_SUPPORTED_QTYPES;
-       pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_id, vsi_queue_id);
+       pf_queue_id = i40e_get_real_pf_qid(vf, vsi_id, vsi_queue_id);
        reg = ((qtype << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) | pf_queue_id);
 
        wr32(hw, reg_idx, reg);
@@ -334,8 +346,9 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id,
                if (next_q < size) {
                        vsi_queue_id = next_q / I40E_VIRTCHNL_SUPPORTED_QTYPES;
                        qtype = next_q % I40E_VIRTCHNL_SUPPORTED_QTYPES;
-                       pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_id,
-                                                             vsi_queue_id);
+                       pf_queue_id = i40e_get_real_pf_qid(vf,
+                                                          vsi_id,
+                                                          vsi_queue_id);
                } else {
                        pf_queue_id = I40E_QUEUE_END_OF_LIST;
                        qtype = 0;
@@ -665,2835 +678,5638 @@ error_param:
 }
 
 /**
- * i40e_alloc_vsi_res
- * @vf: pointer to the VF info
- * @type: type of VSI to allocate
+ * i40e_validate_vf
+ * @pf: the physical function
+ * @vf_id: VF identifier
  *
- * alloc VF vsi context & resources
+ * Check that the VF is enabled and the vsi exists.
+ *
+ * Returns 0 on success, negative on failure
  **/
-static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
+static int i40e_validate_vf(struct i40e_pf *pf, int vf_id)
 {
-       struct i40e_mac_filter *f = NULL;
-       struct i40e_pf *pf = vf->pf;
        struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
        int ret = 0;
 
-       vsi = i40e_vsi_setup(pf, type, pf->vsi[pf->lan_vsi]->seid, vf->vf_id);
-
-       if (!vsi) {
+       if (vf_id >= pf->num_alloc_vfs) {
                dev_err(&pf->pdev->dev,
-                       "add vsi failed for VF %d, aq_err %d\n",
-                       vf->vf_id, pf->hw.aq.asq_last_status);
-               ret = -ENOENT;
-               goto error_alloc_vsi_res;
-       }
-       if (type == I40E_VSI_SRIOV) {
-               u64 hena = i40e_pf_get_default_rss_hena(pf);
-               u8 broadcast[ETH_ALEN];
-
-               vf->lan_vsi_idx = vsi->idx;
-               vf->lan_vsi_id = vsi->id;
-               /* If the port VLAN has been configured and then the
-                * VF driver was removed then the VSI port VLAN
-                * configuration was destroyed.  Check if there is
-                * a port VLAN and restore the VSI configuration if
-                * needed.
-                */
-               if (vf->port_vlan_id)
-                       i40e_vsi_add_pvid(vsi, vf->port_vlan_id);
-
-               spin_lock_bh(&vsi->mac_filter_hash_lock);
-               if (is_valid_ether_addr(vf->default_lan_addr.addr)) {
-                       f = i40e_add_mac_filter(vsi,
-                                               vf->default_lan_addr.addr);
-                       if (!f)
-                               dev_info(&pf->pdev->dev,
-                                       "Could not add MAC filter %pM for VF %d\n",
-                                       vf->default_lan_addr.addr, vf->vf_id);
-               }
-               eth_broadcast_addr(broadcast);
-               f = i40e_add_mac_filter(vsi, broadcast);
-               if (!f)
-                       dev_info(&pf->pdev->dev,
-                                "Could not allocate VF broadcast filter\n");
-               spin_unlock_bh(&vsi->mac_filter_hash_lock);
-               wr32(&pf->hw, I40E_VFQF_HENA1(0, vf->vf_id), (u32)hena);
-               wr32(&pf->hw, I40E_VFQF_HENA1(1, vf->vf_id), (u32)(hena >> 32));
-       }
-
-       /* program mac filter */
-       ret = i40e_sync_vsi_filters(vsi);
-       if (ret)
-               dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
-
-       /* Set VF bandwidth if specified */
-       if (vf->tx_rate) {
-               ret = i40e_aq_config_vsi_bw_limit(&pf->hw, vsi->seid,
-                                                 vf->tx_rate / 50, 0, NULL);
-               if (ret)
-                       dev_err(&pf->pdev->dev, "Unable to set tx rate, VF %d, error code %d.\n",
-                               vf->vf_id, ret);
+                       "Invalid VF Identifier %d\n", vf_id);
+               ret = -EINVAL;
+               goto err_out;
        }
-
-error_alloc_vsi_res:
+       vf = &pf->vf[vf_id];
+       vsi = i40e_find_vsi_from_id(pf, vf->lan_vsi_id);
+       if (!vsi)
+               ret = -EINVAL;
+err_out:
        return ret;
 }
 
 /**
- * i40e_enable_vf_mappings
- * @vf: pointer to the VF info
+ * i40e_set_spoof_settings
+ * @vsi: VF VSI to configure
+ * @sec_flag: the spoof check flag to enable or disable
+ * @enable: enable or disable
  *
- * enable VF mappings
+ * This function sets the spoof check settings
+ *
+ * Returns 0 on success, negative on failure
  **/
-static void i40e_enable_vf_mappings(struct i40e_vf *vf)
+static int i40e_set_spoof_settings(struct i40e_vsi *vsi, u8 sec_flag,
+                                  bool enable)
 {
-       struct i40e_pf *pf = vf->pf;
+       struct i40e_pf *pf = vsi->back;
        struct i40e_hw *hw = &pf->hw;
-       u32 reg, total_queue_pairs = 0;
-       int j;
-
-       /* Tell the hardware we're using noncontiguous mapping. HW requires
-        * that VF queues be mapped using this method, even when they are
-        * contiguous in real life
-        */
-       i40e_write_rx_ctl(hw, I40E_VSILAN_QBASE(vf->lan_vsi_id),
-                         I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
-
-       /* enable VF vplan_qtable mappings */
-       reg = I40E_VPLAN_MAPENA_TXRX_ENA_MASK;
-       wr32(hw, I40E_VPLAN_MAPENA(vf->vf_id), reg);
-
-       /* map PF queues to VF queues */
-       for (j = 0; j < pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs; j++) {
-               u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_id, j);
+       struct i40e_vsi_context ctxt;
+       int ret = 0;
 
-               reg = (qid & I40E_VPLAN_QTABLE_QINDEX_MASK);
-               wr32(hw, I40E_VPLAN_QTABLE(total_queue_pairs, vf->vf_id), reg);
-               total_queue_pairs++;
-       }
+       vsi->info.valid_sections = CPU_TO_LE16(I40E_AQ_VSI_PROP_SECURITY_VALID);
+       if (enable)
+               vsi->info.sec_flags |= sec_flag;
+       else
+               vsi->info.sec_flags &= ~sec_flag;
 
-       /* map PF queues to VSI */
-       for (j = 0; j < 7; j++) {
-               if (j * 2 >= pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs) {
-                       reg = 0x07FF07FF;       /* unused */
-               } else {
-                       u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_id,
-                                                         j * 2);
-                       reg = qid;
-                       qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_id,
-                                                     (j * 2) + 1);
-                       reg |= qid << 16;
-               }
-               i40e_write_rx_ctl(hw, I40E_VSILAN_QTABLE(j, vf->lan_vsi_id),
-                                 reg);
+       memset(&ctxt, 0, sizeof(ctxt));
+       ctxt.seid = vsi->seid;
+       ctxt.pf_num = vsi->back->hw.pf_id;
+       ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
+       if (ret) {
+               dev_err(&pf->pdev->dev, "Error %d updating VSI parameters\n",
+                       ret);
+               ret = -EIO;
        }
-
-       i40e_flush(hw);
+       return ret;
 }
 
 /**
- * i40e_disable_vf_mappings
- * @vf: pointer to the VF info
+ * i40e_configure_vf_loopback
+ * @vsi: VF VSI to configure
+ * @vf_id: VF identifier
+ * @enable: enable or disable
+ *
+ * This function configures the VF VSI with the loopback settings
+ *
+ * Returns 0 on success, negative on failure
  *
- * disable VF mappings
  **/
-static void i40e_disable_vf_mappings(struct i40e_vf *vf)
+static int i40e_configure_vf_loopback(struct i40e_vsi *vsi, int vf_id,
+                                     bool enable)
 {
-       struct i40e_pf *pf = vf->pf;
-       struct i40e_hw *hw = &pf->hw;
-       int i;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_vsi_context ctxt;
+       int ret = 0;
 
-       /* disable qp mappings */
-       wr32(hw, I40E_VPLAN_MAPENA(vf->vf_id), 0);
-       for (i = 0; i < I40E_MAX_VSI_QP; i++)
-               wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_id),
-                    I40E_QUEUE_END_OF_LIST);
-       i40e_flush(hw);
+       vsi->info.valid_sections = CPU_TO_LE16(I40E_AQ_VSI_PROP_SWITCH_VALID);
+       if (enable)
+               vsi->info.switch_id |=
+                               CPU_TO_LE16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
+       else
+               vsi->info.switch_id &=
+                               ~CPU_TO_LE16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
+
+       memset(&ctxt, 0, sizeof(ctxt));
+       ctxt.seid = vsi->seid;
+       ctxt.pf_num = vsi->back->hw.pf_id;
+       ret = i40e_aq_update_vsi_params(&pf->hw, &ctxt, NULL);
+       if (ret) {
+               dev_err(&pf->pdev->dev, "Error %d configuring loopback for VF %d\n",
+                       ret, vf_id);
+               ret = -EIO;
+       }
+       return ret;
 }
 
 /**
- * i40e_free_vf_res
- * @vf: pointer to the VF info
+ * i40e_configure_vf_vlan_stripping
+ * @vsi: VF VSI to configure
+ * @vf_id: VF identifier
+ * @enable: enable or disable
  *
- * free VF resources
+ * This function enables or disables vlan stripping on the VF
+ *
+ * Returns 0 on success, negative on failure
  **/
-static void i40e_free_vf_res(struct i40e_vf *vf)
+static int i40e_configure_vf_vlan_stripping(struct i40e_vsi *vsi, int vf_id,
+                                           bool enable)
 {
-       struct i40e_pf *pf = vf->pf;
-       struct i40e_hw *hw = &pf->hw;
-       u32 reg_idx, reg;
-       int i, msix_vf;
-
-       /* Start by disabling VF's configuration API to prevent the OS from
-        * accessing the VF's VSI after it's freed / invalidated.
-        */
-       clear_bit(I40E_VF_STATE_INIT, &vf->vf_states);
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_vsi_context ctxt;
+       int ret = 0;
+       u8 flag;
 
-       /* It's possible the VF had requeuested more queues than the default so
-        * do the accounting here when we're about to free them.
-        */
-       if (vf->num_queue_pairs > I40E_DEFAULT_QUEUES_PER_VF) {
-               pf->queues_left +=
-                       vf->num_queue_pairs - I40E_DEFAULT_QUEUES_PER_VF;
+       vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID);
+       if (enable) {
+               /* Don't enable vlan stripping if port vlan is set */
+               if (vsi->info.pvid) {
+                       dev_err(&pf->pdev->dev,
+                               "Cannot enable vlan stripping when port VLAN is set\n");
+                       ret = -EINVAL;
+                       goto err_out;
+               }
+               flag = I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
+       } else {
+               flag = I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
        }
-
-       /* free vsi & disconnect it from the parent uplink */
-       if (vf->lan_vsi_idx) {
-               i40e_vsi_release(pf->vsi[vf->lan_vsi_idx]);
-               vf->lan_vsi_idx = 0;
-               vf->lan_vsi_id = 0;
-               vf->num_mac = 0;
+       vsi->info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL | flag;
+       ctxt.seid = vsi->seid;
+       ctxt.info = vsi->info;
+       ret = i40e_aq_update_vsi_params(&pf->hw, &ctxt, NULL);
+       if (ret) {
+               dev_err(&pf->pdev->dev, "Error %d configuring vlan stripping for VF %d\n",
+                       ret, vf_id);
+               ret = -EIO;
        }
-       msix_vf = pf->hw.func_caps.num_msix_vectors_vf;
+err_out:
+       return ret;
+}
 
-       /* disable interrupts so the VF starts in a known state */
-       for (i = 0; i < msix_vf; i++) {
-               /* format is same for both registers */
-               if (0 == i)
-                       reg_idx = I40E_VFINT_DYN_CTL0(vf->vf_id);
-               else
-                       reg_idx = I40E_VFINT_DYN_CTLN(((msix_vf - 1) *
-                                                     (vf->vf_id))
-                                                    + (i - 1));
-               wr32(hw, reg_idx, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
-               i40e_flush(hw);
-       }
+/**
+ * i40e_configure_vf_promisc_mode
+ * @vf: VF
+ * @vsi: VF VSI to configure
+ * @promisc_mode: promisc mode to configure
+ *
+ * This function configures the requested promisc mode for a vf
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_configure_vf_promisc_mode(struct i40e_vf *vf,
+                                         struct i40e_vsi *vsi,
+                                         u8 promisc_mode)
+{
+       struct i40e_pf *pf = vsi->back;
+       int ret = 0;
 
-       /* clear the irq settings */
-       for (i = 0; i < msix_vf; i++) {
-               /* format is same for both registers */
-               if (0 == i)
-                       reg_idx = I40E_VPINT_LNKLST0(vf->vf_id);
+       switch (promisc_mode) {
+       case VFD_PROMISC_MULTICAST:
+               ret = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw, vsi->seid,
+                                                           true, NULL);
+               if (ret)
+                       goto err;
+               vf->promisc_mode = VFD_PROMISC_MULTICAST;
+               break;
+       case VFD_PROMISC_UNICAST:
+               ret = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw, vsi->seid,
+                                                         true, NULL, true);
+               if (ret)
+                       goto err;
+               vf->promisc_mode = VFD_PROMISC_UNICAST;
+               break;
+       case VFD_PROMISC_OFF:
+               if (vf->promisc_mode & VFD_PROMISC_MULTICAST)
+                       ret = i40e_aq_set_vsi_multicast_promiscuous(&pf->hw,
+                                                                   vsi->seid,
+                                                                   false,
+                                                                   NULL);
                else
-                       reg_idx = I40E_VPINT_LNKLSTN(((msix_vf - 1) *
-                                                     (vf->vf_id))
-                                                    + (i - 1));
-               reg = (I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK |
-                      I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
-               wr32(hw, reg_idx, reg);
-               i40e_flush(hw);
+                       ret = i40e_aq_set_vsi_unicast_promiscuous(&pf->hw,
+                                                                 vsi->seid,
+                                                                 false, NULL,
+                                                                 true);
+               if (!ret)
+                       vf->promisc_mode = VFD_PROMISC_OFF;
+               break;
+       default:
+               break;
        }
-       /* reset some of the state variables keeping track of the resources */
-       vf->num_queue_pairs = 0;
-       clear_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states);
-       clear_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states);
+err:
+       if (ret)
+               dev_err(&pf->pdev->dev, "Error %d configuring promisc mode for VF %d\n",
+                       ret, vf->vf_id);
+
+       return ret;
 }
 
 /**
- * i40e_alloc_vf_res
- * @vf: pointer to the VF info
+ * i40e_vf_add_ingress_egress_mirror
+ * @vf: VF
+ * @mirror: mirror VF
+ * @rule_type: rule type to configure
  *
- * allocate VF resources
+ * This function adds the requested ingress/egress for a vf
+ *
+ * Returns 0 on success, negative on failure
  **/
-static int i40e_alloc_vf_res(struct i40e_vf *vf)
+static int i40e_vf_add_ingress_egress_mirror(struct i40e_vf *vf, int mirror,
+                                            u16 rule_type)
 {
+       u16 sw_seid, dst_seid, rule_id, rules_used, rules_free;
+       struct i40e_vsi *vsi, *mirror_vsi;
        struct i40e_pf *pf = vf->pf;
-       int total_queue_pairs = 0;
-       int ret;
+       struct i40e_vf *mirror_vf;
+       int ret, num = 0, cnt = 1;
+       __le16 *mr_list;
 
-       if (vf->num_req_queues &&
-           vf->num_req_queues <= pf->queues_left + I40E_DEFAULT_QUEUES_PER_VF)
-               pf->num_vf_qps = vf->num_req_queues;
-       else
-               pf->num_vf_qps = I40E_DEFAULT_QUEUES_PER_VF;
-
-       /* allocate hw vsi context & associated resources */
-       ret = i40e_alloc_vsi_res(vf, I40E_VSI_SRIOV);
+       ret = i40e_validate_vf(pf, mirror);
        if (ret)
-               goto error_alloc;
-       total_queue_pairs += pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs;
-
-       /* We account for each VF to get a default number of queue pairs.  If
-        * the VF has now requested more, we need to account for that to make
-        * certain we never request more queues than we actually have left in
-        * HW.
-        */
-       if (total_queue_pairs > I40E_DEFAULT_QUEUES_PER_VF)
-               pf->queues_left -=
-                       total_queue_pairs - I40E_DEFAULT_QUEUES_PER_VF;
-
-       if (vf->trusted)
-               set_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
-       else
-               clear_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
-       /* if iwarp, then use an iwarp PF callback to allocate
-        * iwarp resources
-        */
-#if 0
-       if (test_bit(VIRTCHNL_VF_CAP_IWARP, &vf->vf_caps))
-               /* TODO: */
-#endif
-
-       /* store the total qps number for the runtime
-        * VF req validation
-        */
-       vf->num_queue_pairs = total_queue_pairs;
-
-       /* VF is now completely initialized */
-       set_bit(I40E_VF_STATE_INIT, &vf->vf_states);
-
-error_alloc:
+               goto err_out;
+       mirror_vf = &pf->vf[mirror];
+       mirror_vsi = pf->vsi[mirror_vf->lan_vsi_idx];
+       mr_list = kcalloc(cnt, sizeof(__le16), GFP_KERNEL);
+       if (!mr_list)
+               return -ENOMEM;
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       sw_seid = vsi->uplink_seid;
+       dst_seid = mirror_vsi->seid;
+       mr_list[num] = CPU_TO_LE16(mirror_vsi->seid);
+       ret = i40e_aq_add_mirrorrule(&pf->hw, sw_seid,
+                                    rule_type, dst_seid,
+                                    cnt, mr_list, NULL,
+                                    &rule_id, &rules_used,
+                                    &rules_free);
        if (ret)
-               i40e_free_vf_res(vf);
-
+               goto err_free;
+       if (rule_type == I40E_AQC_MIRROR_RULE_TYPE_VPORT_INGRESS)
+               vf->ingress_rule_id = rule_id;
+       else
+               vf->egress_rule_id = rule_id;
+err_free:
+       kfree(mr_list);
+err_out:
        return ret;
 }
 
-#define VF_DEVICE_STATUS 0xAA
-#define VF_TRANS_PENDING_MASK 0x20
 /**
- * i40e_quiesce_vf_pci
- * @vf: pointer to the VF structure
+ * i40e_vf_del_ingress_egress_mirror
+ * @vf: VF
+ * @rule_type: rule type to configure
  *
- * Wait for VF PCI transactions to be cleared after reset. Returns -EIO
- * if the transactions never clear.
+ * This function deletes the ingress/egress mirror for a vf
+ *
+ * Returns 0 on success, negative on failure
  **/
-static int i40e_quiesce_vf_pci(struct i40e_vf *vf)
+static int i40e_vf_del_ingress_egress_mirror(struct i40e_vf *vf, u16 rule_type)
 {
+       u16 sw_seid, rule_id, rules_used, rules_free;
+       int ret, num = 0, cnt = 1, mirror;
+       struct i40e_vsi *vsi, *mirror_vsi;
        struct i40e_pf *pf = vf->pf;
-       struct i40e_hw *hw = &pf->hw;
-       int vf_abs_id, i;
-       u32 reg;
+       struct i40e_vf *mirror_vf;
+       __le16 *mr_list;
 
-       vf_abs_id = vf->vf_id + hw->func_caps.vf_base_id;
-
-       wr32(hw, I40E_PF_PCI_CIAA,
-            VF_DEVICE_STATUS | (vf_abs_id << I40E_PF_PCI_CIAA_VF_NUM_SHIFT));
-       for (i = 0; i < 100; i++) {
-               reg = rd32(hw, I40E_PF_PCI_CIAD);
-               if ((reg & VF_TRANS_PENDING_MASK) == 0)
-                       return 0;
-               udelay(1);
+       if (rule_type == I40E_AQC_MIRROR_RULE_TYPE_VPORT_INGRESS) {
+               rule_id = vf->ingress_rule_id;
+               mirror = vf->ingress_vlan;
+       } else {
+               rule_id = vf->egress_rule_id;
+               mirror = vf->egress_vlan;
        }
-       return -EIO;
+       ret = i40e_validate_vf(pf, mirror);
+       if (ret)
+               goto err_out;
+       mirror_vf = &pf->vf[mirror];
+       mirror_vsi = pf->vsi[mirror_vf->lan_vsi_idx];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       sw_seid = vsi->uplink_seid;
+       mr_list = kcalloc(cnt, sizeof(__le16), GFP_KERNEL);
+       if (!mr_list)
+               return -ENOMEM;
+       mr_list[num] = CPU_TO_LE16(mirror_vsi->seid);
+       ret = i40e_aq_delete_mirrorrule(&pf->hw, sw_seid, rule_type,
+                                       rule_id, cnt, mr_list, NULL,
+                                       &rules_used, &rules_free);
+       kfree(mr_list);
+err_out:
+       return ret;
 }
 
 /**
- * i40e_trigger_vf_reset
- * @vf: pointer to the VF structure
- * @flr: VFLR was issued or not
+ * i40e_configure_vf_link
+ * @vf: VF
+ * @link: link state to configure
  *
- * Trigger hardware to start a reset for a particular VF. Expects the caller
- * to wait the proper amount of time to allow hardware to reset the VF before
- * it cleans up and restores VF functionality.
+ * This function configures the requested link state for a VF
+ *
+ * Returns 0 on success, negative on failure
  **/
-static void i40e_trigger_vf_reset(struct i40e_vf *vf, bool flr)
+static int i40e_configure_vf_link(struct i40e_vf *vf, u8 link)
 {
+       struct virtchnl_pf_event pfe;
+       struct i40e_link_status *ls;
        struct i40e_pf *pf = vf->pf;
-       struct i40e_hw *hw = &pf->hw;
-       u32 reg, reg_idx, bit_idx;
-
-       /* warn the VF */
-       clear_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states);
-
-       /* Disable VF's configuration API during reset. The flag is re-enabled
-        * in i40e_alloc_vf_res(), when it's safe again to access VF's VSI.
-        * It's normally disabled in i40e_free_vf_res(), but it's safer
-        * to do it earlier to give some time to finish to any VF config
-        * functions that may still be running at this point.
-        */
-       clear_bit(I40E_VF_STATE_INIT, &vf->vf_states);
+       struct i40e_hw *hw;
+       int abs_vf_id;
+       int ret = 0;
 
-       /* In the case of a VFLR, the HW has already reset the VF and we
-        * just need to clean up, so don't hit the VFRTRIG register.
-        */
-       if (!flr) {
-               /* reset VF using VPGEN_VFRTRIG reg */
-               reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id));
-               reg |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
-               wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg);
+       hw = &pf->hw;
+       abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
+       pfe.event = VIRTCHNL_EVENT_LINK_CHANGE;
+       pfe.severity = PF_EVENT_SEVERITY_INFO;
+       ls = &pf->hw.phy.link_info;
+       switch (link) {
+       case VFD_LINKSTATE_AUTO:
+               vf->link_forced = false;
+               pfe.event_data.link_event.link_status =
+                       ls->link_info & I40E_AQ_LINK_UP;
+               pfe.event_data.link_event.link_speed =
+                       i40e_virtchnl_link_speed(ls->link_speed);
+               break;
+       case VFD_LINKSTATE_ON:
+               vf->link_forced = true;
+               vf->link_up = true;
+               pfe.event_data.link_event.link_status = true;
+               pfe.event_data.link_event.link_speed = I40E_LINK_SPEED_40GB;
+               break;
+       case VFD_LINKSTATE_OFF:
+               vf->link_forced = true;
+               vf->link_up = false;
+               pfe.event_data.link_event.link_status = false;
+               pfe.event_data.link_event.link_speed = 0;
+               break;
+       default:
+               ret = -EINVAL;
+               goto error_out;
        }
-       /* clear the VFLR bit in GLGEN_VFLRSTAT */
-       reg_idx = (hw->func_caps.vf_base_id + vf->vf_id) / 32;
-       bit_idx = (hw->func_caps.vf_base_id + vf->vf_id) % 32;
-       wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
-       i40e_flush(hw);
-
-       if (i40e_quiesce_vf_pci(vf))
-               dev_err(&pf->pdev->dev, "VF %d PCI transactions stuck\n",
-                       vf->vf_id);
+       /* Notify the VF of its new link state */
+       i40e_aq_send_msg_to_vf(hw, abs_vf_id, VIRTCHNL_OP_EVENT,
+                              I40E_SUCCESS, (u8 *)&pfe, sizeof(pfe), NULL);
+error_out:
+       return ret;
 }
 
 /**
- * i40e_cleanup_reset_vf
+ * i40e_restore_vfd_config
  * @vf: pointer to the VF structure
+ * @vsi: VF VSI to be configured
+ *
+ * Restore the VF-d config as per the stored configuration
+ *
+ * Returns 0 on success, negative on failure
  *
- * Cleanup a VF after the hardware reset is finished. Expects the caller to
- * have verified whether the reset is finished properly, and ensure the
- * minimum amount of wait time has passed.
  **/
-static void i40e_cleanup_reset_vf(struct i40e_vf *vf)
+static int i40e_restore_vfd_config(struct i40e_vf *vf, struct i40e_vsi *vsi)
 {
        struct i40e_pf *pf = vf->pf;
-       struct i40e_hw *hw = &pf->hw;
-       u32 reg;
-
-       /* free VF resources to begin resetting the VSI state */
-       i40e_free_vf_res(vf);
-
-       /* Enable hardware by clearing the reset bit in the VPGEN_VFRTRIG reg.
-        * By doing this we allow HW to access VF memory at any point. If we
-        * did it any sooner, HW could access memory while it was being freed
-        * in i40e_free_vf_res(), causing an IOMMU fault.
-        *
-        * On the other hand, this needs to be done ASAP, because the VF driver
-        * is waiting for this to happen and may report a timeout. It's
-        * harmless, but it gets logged into Guest OS kernel log, so best avoid
-        * it.
-        */
-       reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id));
-       reg &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
-       wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg);
+       int ret = 0, cnt = 0;
+       u8 sec_flag;
+       u16 vid;
 
-       /* reallocate VF resources to finish resetting the VSI state */
-       if (!i40e_alloc_vf_res(vf)) {
-               int abs_vf_id = vf->vf_id + (int)hw->func_caps.vf_base_id;
-               i40e_enable_vf_mappings(vf);
-               set_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states);
-               clear_bit(I40E_VF_STATE_DISABLED, &vf->vf_states);
-               /* Do not notify the client during VF init */
-               if (!test_and_clear_bit(I40E_VF_STATE_PRE_ENABLE,
-                                       &vf->vf_states))
-                       i40e_notify_client_of_vf_reset(pf, abs_vf_id);
-               vf->num_vlan = 0;
+       /* Restore all VF-d configuration on reset */
+       for_each_set_bit(vid, vf->trunk_vlans, VLAN_N_VID) {
+               ret = i40e_vsi_add_vlan(vsi, vid);
+               if (ret)
+                       goto err_out;
+       }
+       if (!vf->allow_untagged) {
+               spin_lock_bh(&vsi->mac_filter_hash_lock);
+               i40e_rm_vlan_all_mac(vsi, 0);
+               spin_unlock_bh(&vsi->mac_filter_hash_lock);
+               i40e_service_event_schedule(vsi->back);
+       }
+
+       cnt = bitmap_weight(vf->mirror_vlans, VLAN_N_VID);
+       if (cnt) {
+               u16 rule_type = I40E_AQC_MIRROR_RULE_TYPE_VLAN;
+               u16 rule_id, rules_used, rules_free;
+               u16 sw_seid = vsi->uplink_seid;
+               u16 dst_seid = vsi->seid;
+               __le16 *mr_list;
+               int num = 0;
+
+               mr_list = kcalloc(cnt, sizeof(__le16), GFP_KERNEL);
+               if (!mr_list)
+                       return -ENOMEM;
+               for_each_set_bit(vid, vf->mirror_vlans, VLAN_N_VID) {
+                       mr_list[num] = CPU_TO_LE16(vid);
+                       num++;
+               }
+               ret = i40e_aq_add_mirrorrule(&pf->hw, sw_seid, rule_type,
+                                            dst_seid, cnt, mr_list, NULL,
+                                            &rule_id, &rules_used,
+                                            &rules_free);
+               if (!ret)
+                       vf->vlan_rule_id = rule_id;
+               kfree(mr_list);
        }
 
-       /* Tell the VF driver the reset is done. This needs to be done only
-        * after VF has been fully initialized, because the VF driver may
-        * request resources immediately after setting this flag.
-        */
-       wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), VIRTCHNL_VFR_VFACTIVE);
-}
+       if (vf->mac_anti_spoof) {
+               sec_flag = I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK;
+               ret = i40e_set_spoof_settings(vsi, sec_flag, true);
+               if (ret)
+                       goto err_out;
+       }
 
-/**
- * i40e_reset_vf
- * @vf: pointer to the VF structure
- * @flr: VFLR was issued or not
- *
- * Returns true if the VF is reset, false otherwise.
- **/
-bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
-{
-       struct i40e_pf *pf = vf->pf;
-       struct i40e_hw *hw = &pf->hw;
-       bool rsd = false;
-       u32 reg;
-       int i;
+       if (vf->vlan_anti_spoof) {
+               sec_flag = I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK;
+               ret = i40e_set_spoof_settings(vsi, sec_flag, true);
+               if (ret)
+                       goto err_out;
+       }
 
-       /* If the VFs have been disabled, this means something else is
-        * resetting the VF, so we shouldn't continue.
-        */
-       if (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
-               return false;
+       if (vf->loopback) {
+               ret = i40e_configure_vf_loopback(vsi, vf->vf_id, true);
+               if (ret) {
+                       vf->loopback = false;
+                       goto err_out;
+               }
+       }
 
-       i40e_trigger_vf_reset(vf, flr);
+       if (vf->vlan_stripping) {
+               ret = i40e_configure_vf_vlan_stripping(vsi, vf->vf_id, true);
+               if (ret) {
+                       vf->vlan_stripping = false;
+                       goto err_out;
+               }
+       }
 
-       /* poll VPGEN_VFRSTAT reg to make sure
-        * that reset is complete
-        */
-       for (i = 0; i < 10; i++) {
-               /* VF reset requires driver to first reset the VF and then
-                * poll the status register to make sure that the reset
-                * completed successfully. Due to internal HW FIFO flushes,
-                * we must wait 10ms before the register will be valid.
-                */
-               usleep_range(10000, 20000);
-               reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id));
-               if (reg & I40E_VPGEN_VFRSTAT_VFRD_MASK) {
-                       rsd = true;
-                       break;
+       if (vf->promisc_mode) {
+               ret = i40e_configure_vf_promisc_mode(vf, vsi, vf->promisc_mode);
+               if (ret) {
+                       vf->promisc_mode = VFD_PROMISC_OFF;
+                       goto err_out;
                }
        }
 
-       if (flr)
-               usleep_range(10000, 20000);
+       if (vf->ingress_vlan) {
+               u16 rule_type;
 
-       if (!rsd)
-               dev_err(&pf->pdev->dev, "VF reset check timeout on VF %d\n",
-                       vf->vf_id);
-       usleep_range(10000, 20000);
+               rule_type = I40E_AQC_MIRROR_RULE_TYPE_VPORT_INGRESS;
+               ret = i40e_vf_add_ingress_egress_mirror(vf, vf->ingress_vlan,
+                                                       rule_type);
+               if (ret) {
+                       vf->ingress_vlan = I40E_NO_VF_MIRROR;
+                       goto err_out;
+               }
+       }
 
-       /* On initial reset, we don't have any queues to disable */
-       if (vf->lan_vsi_idx != 0)
-               i40e_vsi_stop_rings(pf->vsi[vf->lan_vsi_idx]);
+       if (vf->egress_vlan) {
+               u16 rule_type;
 
-       i40e_cleanup_reset_vf(vf);
+               rule_type = I40E_AQC_MIRROR_RULE_TYPE_VPORT_EGRESS;
+               ret = i40e_vf_add_ingress_egress_mirror(vf, vf->egress_vlan,
+                                                       rule_type);
+               if (ret) {
+                       vf->egress_vlan = I40E_NO_VF_MIRROR;
+                       goto err_out;
+               }
+       }
 
-       i40e_flush(hw);
-       clear_bit(__I40E_VF_DISABLE, pf->state);
+       if (vf->link_forced) {
+               u8 link;
 
-       return true;
+               link = (vf->link_up ? VFD_LINKSTATE_ON : VFD_LINKSTATE_OFF);
+               ret = i40e_configure_vf_link(vf, link);
+               if (ret) {
+                       vf->link_forced = false;
+                       goto err_out;
+               }
+       }
+err_out:
+       return ret;
 }
-
 /**
- * i40e_reset_all_vfs
- * @pf: pointer to the PF structure
- * @flr: VFLR was issued or not
- *
- * Reset all allocated VFs in one go. First, tell the hardware to reset each
- * VF, then do all the waiting in one chunk, and finally finish restoring each
- * VF after the wait. This is useful during PF routines which need to reset
- * all VFs, as otherwise it must perform these resets in a serialized fashion.
+ * i40e_alloc_vsi_res
+ * @vf: pointer to the VF info
+ * @idx: VSI index, applies only for ADq mode, zero otherwise
  *
- * Returns true if any VFs were reset, and false otherwise.
+ * alloc VF vsi context & resources
  **/
-bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
+static int i40e_alloc_vsi_res(struct i40e_vf *vf, u8 idx)
 {
-       struct i40e_hw *hw = &pf->hw;
-       struct i40e_vf *vf;
-       int i, v;
-       u32 reg;
-
-       /* If we don't have any VFs, then there is nothing to reset */
-       if (!pf->num_alloc_vfs)
-               return false;
+       struct i40e_mac_filter *f = NULL;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi;
+       u64 max_tx_rate = 0;
+       int ret = 0;
 
-       /* If VFs have been disabled, there is no need to reset */
-       if (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
-               return false;
+       vsi = i40e_vsi_setup(pf, I40E_VSI_SRIOV, pf->vsi[pf->lan_vsi]->seid,
+                            vf->vf_id);
 
-       /* Begin reset on all VFs at once */
-       for (v = 0; v < pf->num_alloc_vfs; v++)
-               i40e_trigger_vf_reset(&pf->vf[v], flr);
+       if (!vsi) {
+               dev_err(&pf->pdev->dev,
+                       "add vsi failed for VF %d, aq_err %d\n",
+                       vf->vf_id, pf->hw.aq.asq_last_status);
+               ret = -ENOENT;
+               goto error_alloc_vsi_res;
+       }
 
-       /* HW requires some time to make sure it can flush the FIFO for a VF
-        * when it resets it. Poll the VPGEN_VFRSTAT register for each VF in
-        * sequence to make sure that it has completed. We'll keep track of
-        * the VFs using a simple iterator that increments once that VF has
-        * finished resetting.
-        */
-       for (i = 0, v = 0; i < 10 && v < pf->num_alloc_vfs; i++) {
-               usleep_range(10000, 20000);
+       if (!idx) {
+               u64 hena = i40e_pf_get_default_rss_hena(pf);
+               u8 broadcast[ETH_ALEN];
 
-               /* Check each VF in sequence, beginning with the VF to fail
-                * the previous check.
+               vf->lan_vsi_idx = vsi->idx;
+               vf->lan_vsi_id = vsi->id;
+               /* If the port VLAN has been configured and then the
+                * VF driver was removed then the VSI port VLAN
+                * configuration was destroyed.  Check if there is
+                * a port VLAN and restore the VSI configuration if
+                * needed.
                 */
-               while (v < pf->num_alloc_vfs) {
-                       vf = &pf->vf[v];
-                       reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id));
-                       if (!(reg & I40E_VPGEN_VFRSTAT_VFRD_MASK))
-                               break;
+               if (vf->port_vlan_id)
+                       i40e_vsi_add_pvid(vsi, vf->port_vlan_id);
 
-                       /* If the current VF has finished resetting, move on
-                        * to the next VF in sequence.
-                        */
-                       v++;
+               spin_lock_bh(&vsi->mac_filter_hash_lock);
+               if (is_valid_ether_addr(vf->default_lan_addr.addr)) {
+                       f = i40e_add_mac_filter(vsi,
+                                               vf->default_lan_addr.addr);
+                       if (!f)
+                               dev_info(&pf->pdev->dev,
+                                       "Could not add MAC filter %pM for VF %d\n",
+                                       vf->default_lan_addr.addr, vf->vf_id);
                }
+               eth_broadcast_addr(broadcast);
+               f = i40e_add_mac_filter(vsi, broadcast);
+               if (!f)
+                       dev_info(&pf->pdev->dev,
+                                "Could not allocate VF broadcast filter\n");
+               spin_unlock_bh(&vsi->mac_filter_hash_lock);
+               wr32(&pf->hw, I40E_VFQF_HENA1(0, vf->vf_id), (u32)hena);
+               wr32(&pf->hw, I40E_VFQF_HENA1(1, vf->vf_id), (u32)(hena >> 32));
+               /* program mac filter only for VF VSI */
+               ret = i40e_sync_vsi_filters(vsi);
+               if (ret)
+                       dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
        }
 
-       if (flr)
-               usleep_range(10000, 20000);
-
-       /* Display a warning if at least one VF didn't manage to reset in
-        * time, but continue on with the operation.
-        */
-       if (v < pf->num_alloc_vfs)
-               dev_err(&pf->pdev->dev, "VF reset check timeout on VF %d\n",
-                       pf->vf[v].vf_id);
-       usleep_range(10000, 20000);
-
-       /* Begin disabling all the rings associated with VFs, but do not wait
-        * between each VF.
-        */
-       for (v = 0; v < pf->num_alloc_vfs; v++) {
-               /* On initial reset, we don't have any queues to disable */
-               if (pf->vf[v].lan_vsi_idx == 0)
-                       continue;
-
-               i40e_vsi_stop_rings_no_wait(pf->vsi[pf->vf[v].lan_vsi_idx]);
+       /* storing VSI index and id for ADq and don't apply the mac filter */
+       if (vf->adq_enabled) {
+               vf->ch[idx].vsi_idx = vsi->idx;
+               vf->ch[idx].vsi_id = vsi->id;
        }
 
-       /* Now that we've notified HW to disable all of the VF rings, wait
-        * until they finish.
-        */
-       for (v = 0; v < pf->num_alloc_vfs; v++) {
-               /* On initial reset, we don't have any queues to disable */
-               if (pf->vf[v].lan_vsi_idx == 0)
-                       continue;
-
-               i40e_vsi_wait_queues_disabled(pf->vsi[pf->vf[v].lan_vsi_idx]);
+       /* Set VF bandwidth if specified */
+       if (vf->tx_rate) {
+               max_tx_rate = vf->tx_rate;
+       } else if (vf->ch[idx].max_tx_rate) {
+               max_tx_rate = vf->ch[idx].max_tx_rate;
        }
 
-       /* Hw may need up to 50ms to finish disabling the RX queues. We
-        * minimize the wait by delaying only once for all VFs.
-        */
-       mdelay(50);
-
-       /* Finish the reset on each VF */
-       for (v = 0; v < pf->num_alloc_vfs; v++)
-               i40e_cleanup_reset_vf(&pf->vf[v]);
-
-       i40e_flush(hw);
-       clear_bit(__I40E_VF_DISABLE, pf->state);
+       if (max_tx_rate) {
+               max_tx_rate = div_u64(max_tx_rate, I40E_BW_CREDIT_DIVISOR);
+               ret = i40e_aq_config_vsi_bw_limit(&pf->hw, vsi->seid,
+                                                 max_tx_rate, 0, NULL);
+               if (ret)
+                       dev_err(&pf->pdev->dev, "Unable to set tx rate, VF %d, error code %d.\n",
+                               vf->vf_id, ret);
+       }
+       ret = i40e_restore_vfd_config(vf, vsi);
+       if (ret)
+               dev_err(&pf->pdev->dev,
+                       "Failed to restore VF-d config error %d\n", ret);
 
-       return true;
+error_alloc_vsi_res:
+       return ret;
 }
 
 /**
- * i40e_free_vfs
- * @pf: pointer to the PF structure
+ * i40e_map_pf_queues_to_vsi
+ * @vf: pointer to the VF info
  *
- * free VF resources
+ * PF maps LQPs to a VF by programming VSILAN_QTABLE & VPLAN_QTABLE. This
+ * function takes care of first part VSILAN_QTABLE, mapping pf queues to VSI.
  **/
-void i40e_free_vfs(struct i40e_pf *pf)
+static void i40e_map_pf_queues_to_vsi(struct i40e_vf *vf)
 {
+       struct i40e_pf *pf = vf->pf;
        struct i40e_hw *hw = &pf->hw;
-       u32 reg_idx, bit_idx;
-       int i, tmp, vf_id;
+       u32 reg, num_tc = 1; /* VF has at least one traffic class */
+       u16 vsi_id, qps;
+       int i, j;
 
-       if (!pf->vf)
-               return;
-       while (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
-               usleep_range(1000, 2000);
+       if (vf->adq_enabled)
+               num_tc = vf->num_tc;
 
-       i40e_notify_client_of_vf_enable(pf, 0);
-
-       /* Amortize wait time by stopping all VFs at the same time */
-       for (i = 0; i < pf->num_alloc_vfs; i++) {
-               if (test_bit(I40E_VF_STATE_INIT, &pf->vf[i].vf_states))
-                       continue;
+       for (i = 0; i < num_tc; i++) {
+               if (vf->adq_enabled) {
+                       qps = vf->ch[i].num_qps;
+                       vsi_id =  vf->ch[i].vsi_id;
+               } else {
+                       qps = pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs;
+                       vsi_id = vf->lan_vsi_id;
+               }
 
-               i40e_vsi_stop_rings_no_wait(pf->vsi[pf->vf[i].lan_vsi_idx]);
+               for (j = 0; j < 7; j++) {
+                       if (j * 2 >= qps) {
+                               /* end of list */
+                               reg = 0x07FF07FF;
+                       } else {
+                               u16 qid = i40e_vc_get_pf_queue_id(vf,
+                                                                 vsi_id,
+                                                                 j * 2);
+                               reg = qid;
+                               qid = i40e_vc_get_pf_queue_id(vf, vsi_id,
+                                                             (j * 2) + 1);
+                               reg |= qid << 16;
+                       }
+                       i40e_write_rx_ctl(hw,
+                                         I40E_VSILAN_QTABLE(j, vsi_id),
+                                         reg);
+               }
        }
+}
 
-       for (i = 0; i < pf->num_alloc_vfs; i++) {
-               if (test_bit(I40E_VF_STATE_INIT, &pf->vf[i].vf_states))
-                       continue;
+/**
+ * i40e_map_pf_to_vf_queues
+ * @vf: pointer to the VF info
+ *
+ * PF maps LQPs to a VF by programming VSILAN_QTABLE & VPLAN_QTABLE. This
+ * function takes care of the second part VPLAN_QTABLE & completes VF mappings.
+ **/
+static void i40e_map_pf_to_vf_queues(struct i40e_vf *vf)
+{
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       u32 reg, total_qps = 0;
+       u32 qps, num_tc = 1; /* VF has at least one traffic class */
+       u16 vsi_id, qid;
+       int i, j;
+
+       if (vf->adq_enabled)
+               num_tc = vf->num_tc;
+
+       for (i = 0; i < num_tc; i++) {
+               if (vf->adq_enabled) {
+                       qps = vf->ch[i].num_qps;
+                       vsi_id =  vf->ch[i].vsi_id;
+               } else {
+                       qps = pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs;
+                       vsi_id = vf->lan_vsi_id;
+               }
 
-               i40e_vsi_wait_queues_disabled(pf->vsi[pf->vf[i].lan_vsi_idx]);
+               for (j = 0; j < qps; j++) {
+                       qid = i40e_vc_get_pf_queue_id(vf, vsi_id, j);
+
+                       reg = (qid & I40E_VPLAN_QTABLE_QINDEX_MASK);
+                       wr32(hw, I40E_VPLAN_QTABLE(total_qps, vf->vf_id),
+                            reg);
+                       total_qps++;
+               }
        }
+}
 
-       /* Disable IOV before freeing resources. This lets any VF drivers
-        * running in the host get themselves cleaned up before we yank
-        * the carpet out from underneath their feet.
+/**
+ * i40e_enable_vf_mappings
+ * @vf: pointer to the VF info
+ *
+ * enable VF mappings
+ **/
+static void i40e_enable_vf_mappings(struct i40e_vf *vf)
+{
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       u32 reg;
+
+       /* Tell the hardware we're using noncontiguous mapping. HW requires
+        * that VF queues be mapped using this method, even when they are
+        * contiguous in real life
         */
-       if (!pci_vfs_assigned(pf->pdev))
-               pci_disable_sriov(pf->pdev);
-       else
-               dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n");
+       i40e_write_rx_ctl(hw, I40E_VSILAN_QBASE(vf->lan_vsi_id),
+                         I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
 
-       /* free up VF resources */
-       tmp = pf->num_alloc_vfs;
-       pf->num_alloc_vfs = 0;
-       for (i = 0; i < tmp; i++) {
-               if (test_bit(I40E_VF_STATE_INIT, &pf->vf[i].vf_states))
-                       i40e_free_vf_res(&pf->vf[i]);
-               /* disable qp mappings */
-               i40e_disable_vf_mappings(&pf->vf[i]);
-       }
+       /* enable VF vplan_qtable mappings */
+       reg = I40E_VPLAN_MAPENA_TXRX_ENA_MASK;
+       wr32(hw, I40E_VPLAN_MAPENA(vf->vf_id), reg);
 
-       kfree(pf->vf);
-       pf->vf = NULL;
+       i40e_map_pf_to_vf_queues(vf);
+       i40e_map_pf_queues_to_vsi(vf);
 
-       /* This check is for when the driver is unloaded while VFs are
-        * assigned. Setting the number of VFs to 0 through sysfs is caught
-        * before this function ever gets called.
-        */
-       if (!pci_vfs_assigned(pf->pdev)) {
-               /* Acknowledge VFLR for all VFS. Without this, VFs will fail to
-                * work correctly when SR-IOV gets re-enabled.
-                */
-               for (vf_id = 0; vf_id < tmp; vf_id++) {
-                       reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32;
-                       bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32;
-                       wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
-               }
-       }
-       clear_bit(__I40E_VF_DISABLE, pf->state);
+       i40e_flush(hw);
 }
 
-#ifdef CONFIG_PCI_IOV
 /**
- * i40e_alloc_vfs
- * @pf: pointer to the PF structure
- * @num_alloc_vfs: number of VFs to allocate
+ * i40e_disable_vf_mappings
+ * @vf: pointer to the VF info
  *
- * allocate VF resources
+ * disable VF mappings
  **/
-int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
+static void i40e_disable_vf_mappings(struct i40e_vf *vf)
 {
-       struct i40e_vf *vfs;
-       int i, ret = 0;
-
-       /* Disable interrupt 0 so we don't try to handle the VFLR. */
-       i40e_irq_dynamic_disable_icr0(pf);
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       int i;
 
-       /* Check to see if we're just allocating resources for extant VFs */
-       if (pci_num_vf(pf->pdev) != num_alloc_vfs) {
-               ret = pci_enable_sriov(pf->pdev, num_alloc_vfs);
-               if (ret) {
-                       pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
-                       pf->num_alloc_vfs = 0;
-                       goto err_iov;
-               }
-       }
-       /* allocate memory */
-       vfs = kcalloc(num_alloc_vfs, sizeof(struct i40e_vf), GFP_KERNEL);
-       if (!vfs) {
-               ret = -ENOMEM;
-               goto err_alloc;
-       }
-       pf->vf = vfs;
+       /* disable qp mappings */
+       wr32(hw, I40E_VPLAN_MAPENA(vf->vf_id), 0);
+       for (i = 0; i < I40E_MAX_VSI_QP; i++)
+               wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_id),
+                    I40E_QUEUE_END_OF_LIST);
+       i40e_flush(hw);
+}
 
-       /* apply default profile */
-       for (i = 0; i < num_alloc_vfs; i++) {
-               vfs[i].pf = pf;
-               vfs[i].parent_type = I40E_SWITCH_ELEMENT_TYPE_VEB;
-               vfs[i].vf_id = i;
+/**
+ * i40e_free_vf_res
+ * @vf: pointer to the VF info
+ *
+ * free VF resources
+ **/
+static void i40e_free_vf_res(struct i40e_vf *vf)
+{
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       u32 reg_idx, reg;
+       int i, j, msix_vf;
 
-               /* assign default capabilities */
-               set_bit(I40E_VIRTCHNL_VF_CAP_L2, &vfs[i].vf_caps);
-               vfs[i].spoofchk = true;
-#if 0
-               /* TODO */
-               set_bit(VIRTCHNL_VF_CAP_IWARP, &vfs[i].vf_caps);
-#endif
-               set_bit(I40E_VF_STATE_PRE_ENABLE, &vfs[i].vf_states);
+       /* Start by disabling VF's configuration API to prevent the OS from
+        * accessing the VF's VSI after it's freed / invalidated.
+        */
+       clear_bit(I40E_VF_STATE_INIT, &vf->vf_states);
+
+       /* It's possible the VF had requeuested more queues than the default so
+        * do the accounting here when we're about to free them.
+        */
+       if (vf->num_queue_pairs > I40E_DEFAULT_QUEUES_PER_VF) {
+               pf->queues_left +=
+                       vf->num_queue_pairs - I40E_DEFAULT_QUEUES_PER_VF;
        }
-       pf->num_alloc_vfs = num_alloc_vfs;
 
-       /* VF resources get allocated during reset */
-       i40e_reset_all_vfs(pf, false);
+       /* free vsi & disconnect it from the parent uplink */
+       if (vf->lan_vsi_idx) {
+               i40e_vsi_release(pf->vsi[vf->lan_vsi_idx]);
+               vf->lan_vsi_idx = 0;
+               vf->lan_vsi_id = 0;
+               vf->num_mac = 0;
+       }
 
-       i40e_notify_client_of_vf_enable(pf, num_alloc_vfs);
+       /* do the accounting and remove additional ADq VSI's */
+       if (vf->adq_enabled && vf->ch[0].vsi_idx) {
+               for (j = 0; j < vf->num_tc; j++) {
+                       /* At this point VSI0 is already released so don't
+                        * release it again and only clear their values in
+                        * structure variables
+                        */
+                       if (j)
+                               i40e_vsi_release(pf->vsi[vf->ch[j].vsi_idx]);
+                       vf->ch[j].vsi_idx = 0;
+                       vf->ch[j].vsi_id = 0;
+               }
+       }
+       msix_vf = pf->hw.func_caps.num_msix_vectors_vf;
 
-err_alloc:
-       if (ret)
-               i40e_free_vfs(pf);
-err_iov:
-       /* Re-enable interrupt 0. */
-       i40e_irq_dynamic_enable_icr0(pf);
-       return ret;
+       /* disable interrupts so the VF starts in a known state */
+       for (i = 0; i < msix_vf; i++) {
+               /* format is same for both registers */
+               if (0 == i)
+                       reg_idx = I40E_VFINT_DYN_CTL0(vf->vf_id);
+               else
+                       reg_idx = I40E_VFINT_DYN_CTLN(((msix_vf - 1) *
+                                                     (vf->vf_id))
+                                                    + (i - 1));
+               wr32(hw, reg_idx, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
+               i40e_flush(hw);
+       }
+
+       /* clear the irq settings */
+       for (i = 0; i < msix_vf; i++) {
+               /* format is same for both registers */
+               if (0 == i)
+                       reg_idx = I40E_VPINT_LNKLST0(vf->vf_id);
+               else
+                       reg_idx = I40E_VPINT_LNKLSTN(((msix_vf - 1) *
+                                                     (vf->vf_id))
+                                                    + (i - 1));
+               reg = (I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK |
+                      I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
+               wr32(hw, reg_idx, reg);
+               i40e_flush(hw);
+       }
+       /* reset some of the state variables keeping track of the resources */
+       vf->num_queue_pairs = 0;
+       clear_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states);
+       clear_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states);
 }
 
-#endif
-#if defined(HAVE_SRIOV_CONFIGURE) || defined(HAVE_RHEL6_SRIOV_CONFIGURE)
 /**
- * i40e_pci_sriov_enable
- * @pdev: pointer to a pci_dev structure
- * @num_vfs: number of VFs to allocate
+ * i40e_alloc_vf_res
+ * @vf: pointer to the VF info
  *
- * Enable or change the number of VFs
+ * allocate VF resources
  **/
-static int i40e_pci_sriov_enable(struct pci_dev *pdev, int num_vfs)
+static int i40e_alloc_vf_res(struct i40e_vf *vf)
 {
-#ifdef CONFIG_PCI_IOV
-       struct i40e_pf *pf = pci_get_drvdata(pdev);
-       int pre_existing_vfs = pci_num_vf(pdev);
-       int err = 0;
-
-       if (test_bit(__I40E_TESTING, pf->state)) {
-               dev_warn(&pdev->dev,
-                        "Cannot enable SR-IOV virtual functions while the device is undergoing diagnostic testing\n");
-               err = -EPERM;
-               goto err_out;
-       }
+       struct i40e_pf *pf = vf->pf;
+       int total_queue_pairs = 0;
+       int ret, idx;
 
-       if (pre_existing_vfs && pre_existing_vfs != num_vfs)
-               i40e_free_vfs(pf);
-       else if (pre_existing_vfs && pre_existing_vfs == num_vfs)
-               goto out;
+       if (vf->num_req_queues &&
+           vf->num_req_queues <= pf->queues_left + I40E_DEFAULT_QUEUES_PER_VF)
+               pf->num_vf_qps = vf->num_req_queues;
+       else
+               pf->num_vf_qps = I40E_DEFAULT_QUEUES_PER_VF;
 
-       if (num_vfs > pf->num_req_vfs) {
-               dev_warn(&pdev->dev, "Unable to enable %d VFs. Limited to %d VFs due to device resource constraints.\n",
-                        num_vfs, pf->num_req_vfs);
-               err = -EPERM;
-               goto err_out;
-       }
+       /* allocate hw vsi context & associated resources */
+       ret = i40e_alloc_vsi_res(vf, 0);
+       if (ret)
+               goto error_alloc;
+       total_queue_pairs += pf->vsi[vf->lan_vsi_idx]->alloc_queue_pairs;
 
-       dev_info(&pdev->dev, "Allocating %d VFs.\n", num_vfs);
-       err = i40e_alloc_vfs(pf, num_vfs);
-       if (err) {
-               dev_warn(&pdev->dev, "Failed to enable SR-IOV: %d\n", err);
-               goto err_out;
+       /* allocate additional VSIs based on tc information for ADq */
+       if (vf->adq_enabled) {
+               if (pf->queues_left >=
+                   (I40E_MAX_VF_QUEUES - I40E_DEFAULT_QUEUES_PER_VF)) {
+                       /* TC 0 always belongs to VF VSI */
+                       for (idx = 1; idx < vf->num_tc; idx++) {
+                               ret = i40e_alloc_vsi_res(vf, idx);
+                               if (ret)
+                                       goto error_alloc;
+                       }
+                       /* send correct number of queues */
+                       total_queue_pairs = I40E_MAX_VF_QUEUES;
+               } else {
+                       dev_info(&pf->pdev->dev, "VF %d: Not enough queues to allocate, disabling ADq\n",
+                                vf->vf_id);
+                       vf->adq_enabled = false;
+               }
        }
 
-out:
-       return num_vfs;
+       /* We account for each VF to get a default number of queue pairs.  If
+        * the VF has now requested more, we need to account for that to make
+        * certain we never request more queues than we actually have left in
+        * HW.
+        */
+       if (total_queue_pairs > I40E_DEFAULT_QUEUES_PER_VF)
+               pf->queues_left -=
+                       total_queue_pairs - I40E_DEFAULT_QUEUES_PER_VF;
 
-err_out:
-       return err;
+       if (vf->trusted)
+               set_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
+       else
+               clear_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
+       /* if iwarp, then use an iwarp PF callback to allocate
+        * iwarp resources
+        */
+#if 0
+       if (test_bit(VIRTCHNL_VF_CAP_IWARP, &vf->vf_caps))
+               /* TODO: */
 #endif
-       return 0;
+
+       /* store the total qps number for the runtime
+        * VF req validation
+        */
+       vf->num_queue_pairs = total_queue_pairs;
+
+       /* VF is now completely initialized */
+       set_bit(I40E_VF_STATE_INIT, &vf->vf_states);
+
+error_alloc:
+       if (ret)
+               i40e_free_vf_res(vf);
+
+       return ret;
 }
 
+#define VF_DEVICE_STATUS 0xAA
+#define VF_TRANS_PENDING_MASK 0x20
 /**
- * i40e_pci_sriov_configure
- * @pdev: pointer to a pci_dev structure
- * @num_vfs: number of vfs to allocate
+ * i40e_quiesce_vf_pci
+ * @vf: pointer to the VF structure
  *
- * Enable or change the number of VFs. Called when the user updates the number
- * of VFs in sysfs.
+ * Wait for VF PCI transactions to be cleared after reset. Returns -EIO
+ * if the transactions never clear.
  **/
-int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
+static int i40e_quiesce_vf_pci(struct i40e_vf *vf)
 {
-       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       int vf_abs_id, i;
+       u32 reg;
 
-       if (num_vfs) {
-               if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
-                       pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
-                       i40e_do_reset_safe(pf,
-                                          BIT_ULL(__I40E_PF_RESET_REQUESTED));
-               }
-               return i40e_pci_sriov_enable(pdev, num_vfs);
-       }
-       if (!pci_vfs_assigned(pdev)) {
-               i40e_free_vfs(pf);
-               pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
-               i40e_do_reset_safe(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED));
-       } else {
-               dev_warn(&pdev->dev, "Unable to free VFs because some are assigned to VMs.\n");
-               return -EINVAL;
-       }
+       vf_abs_id = vf->vf_id + hw->func_caps.vf_base_id;
 
-       return 0;
+       wr32(hw, I40E_PF_PCI_CIAA,
+            VF_DEVICE_STATUS | (vf_abs_id << I40E_PF_PCI_CIAA_VF_NUM_SHIFT));
+       for (i = 0; i < 100; i++) {
+               reg = rd32(hw, I40E_PF_PCI_CIAD);
+               if ((reg & VF_TRANS_PENDING_MASK) == 0)
+                       return 0;
+               udelay(1);
+       }
+       return -EIO;
 }
-#endif
 
-/***********************virtual channel routines******************/
+static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi);
 
 /**
- * i40e_vc_send_msg_to_vf
+ * i40e_config_vf_promiscuous_mode
  * @vf: pointer to the VF info
- * @v_opcode: virtual channel opcode
- * @v_retval: virtual channel return value
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * @vsi_id: VSI id
+ * @allmulti: set MAC L2 layer multicast promiscuous enable/disable
+ * @alluni: set MAC L2 layer unicast promiscuous enable/disable
  *
- * send msg to VF
+ * Called from the VF to configure the promiscuous mode of
+ * VF vsis and from the VF reset path to reset promiscuous mode.
  **/
-static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode,
-                                 u32 v_retval, u8 *msg, u16 msglen)
+static i40e_status i40e_config_vf_promiscuous_mode(struct i40e_vf *vf,
+                                                  u16 vsi_id,
+                                                  bool allmulti,
+                                                  bool alluni)
 {
-       struct i40e_pf *pf;
-       struct i40e_hw *hw;
-       int abs_vf_id;
-       i40e_status aq_ret;
-
-       /* validate the request */
-       if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs)
-               return -EINVAL;
+       i40e_status aq_ret = I40E_SUCCESS;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_mac_filter *f;
+       struct i40e_vsi *vsi;
+       int bkt;
 
-       pf = vf->pf;
-       hw = &pf->hw;
-       abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
+       vsi = i40e_find_vsi_from_id(pf, vsi_id);
+       if (!i40e_vc_isvalid_vsi_id(vf, vsi_id) || !vsi)
+               return I40E_ERR_PARAM;
 
-       /* single place to detect unsuccessful return values */
-       if (v_retval) {
-               vf->num_invalid_msgs++;
-               dev_info(&pf->pdev->dev, "VF %d failed opcode %d, retval: %d\n",
-                        vf->vf_id, v_opcode, v_retval);
-               if (vf->num_invalid_msgs >
-                   I40E_DEFAULT_NUM_INVALID_MSGS_ALLOWED) {
-                       dev_err(&pf->pdev->dev,
-                               "Number of invalid messages exceeded for VF %d\n",
+       if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) &&
+           (allmulti || alluni)) {
+               dev_err(&pf->pdev->dev,
+                       "Unprivileged VF %d is attempting to configure promiscuous mode\n",
+                       vf->vf_id);
+               if (pf->vf_base_mode_only)
+                       dev_err(&pf->pdev->dev, "VF %d is in base mode only, promiscuous mode is not be supported\n",
                                vf->vf_id);
-                       dev_err(&pf->pdev->dev, "Use PF Control I/F to enable the VF\n");
-                       set_bit(I40E_VF_STATE_DISABLED, &vf->vf_states);
+               /* Lie to the VF on purpose, because this is an error we can
+                * ignore. Unprivileged VF is not a virtual channel error.
+                */
+               return I40E_SUCCESS;
+       }
+
+       if (vf->port_vlan_id) {
+               aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw, vsi->seid,
+                                                           allmulti,
+                                                           vf->port_vlan_id,
+                                                           NULL);
+               if (aq_ret) {
+                       int aq_err = pf->hw.aq.asq_last_status;
+
+                       dev_err(&pf->pdev->dev,
+                               "VF %d failed to set multicast promiscuous mode err %s aq_err %s\n",
+                               vf->vf_id,
+                               i40e_stat_str(&pf->hw, aq_ret),
+                               i40e_aq_str(&pf->hw, aq_err));
+                       return aq_ret;
                }
-       } else {
-               vf->num_valid_msgs++;
-               /* reset the invalid counter, if a valid message is received. */
-               vf->num_invalid_msgs = 0;
+
+               aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, vsi->seid,
+                                                           alluni,
+                                                           vf->port_vlan_id,
+                                                           NULL);
+               if (aq_ret) {
+                       int aq_err = pf->hw.aq.asq_last_status;
+
+                       dev_err(&pf->pdev->dev,
+                               "VF %d failed to set unicast promiscuous mode err %s aq_err %s\n",
+                               vf->vf_id,
+                               i40e_stat_str(&pf->hw, aq_ret),
+                               i40e_aq_str(&pf->hw, aq_err));
+               }
+               return aq_ret;
+       } else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
+               hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
+                       if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID)
+                               continue;
+                       aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw,
+                                                                   vsi->seid,
+                                                                   allmulti,
+                                                                   f->vlan,
+                                                                   NULL);
+                       if (aq_ret) {
+                               int aq_err = pf->hw.aq.asq_last_status;
+
+                               dev_err(&pf->pdev->dev,
+                                       "Could not add VLAN %d to multicast promiscuous domain err %s aq_err %s\n",
+                                       f->vlan,
+                                       i40e_stat_str(&pf->hw, aq_ret),
+                                       i40e_aq_str(&pf->hw, aq_err));
+                       }
+
+                       aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw,
+                                                                   vsi->seid,
+                                                                   alluni,
+                                                                   f->vlan,
+                                                                   NULL);
+                       if (aq_ret) {
+                               int aq_err = pf->hw.aq.asq_last_status;
+
+                               dev_err(&pf->pdev->dev,
+                                       "Could not add VLAN %d to Unicast promiscuous domain err %s aq_err %s\n",
+                                       f->vlan,
+                                       i40e_stat_str(&pf->hw, aq_ret),
+                                       i40e_aq_str(&pf->hw, aq_err));
+                       }
+               }
+               return aq_ret;
        }
+       aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid, allmulti,
+                                                      NULL);
+       if (aq_ret) {
+               int aq_err = pf->hw.aq.asq_last_status;
 
-       aq_ret = i40e_aq_send_msg_to_vf(hw, abs_vf_id, v_opcode, v_retval,
-                                       msg, msglen, NULL);
+               dev_err(&pf->pdev->dev,
+                       "VF %d failed to set multicast promiscuous mode err %s aq_err %s\n",
+                       vf->vf_id,
+                       i40e_stat_str(&pf->hw, aq_ret),
+                       i40e_aq_str(&pf->hw, aq_err));
+               return aq_ret;
+       }
+
+       aq_ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid, alluni,
+                                                    NULL, true);
        if (aq_ret) {
-               dev_info(&pf->pdev->dev,
-                        "Unable to send the message to VF %d aq_err %d\n",
-                        vf->vf_id, pf->hw.aq.asq_last_status);
-               return -EIO;
+               int aq_err = pf->hw.aq.asq_last_status;
+
+               dev_err(&pf->pdev->dev,
+                       "VF %d failed to set unicast promiscuous mode err %s aq_err %s\n",
+                       vf->vf_id,
+                       i40e_stat_str(&pf->hw, aq_ret),
+                       i40e_aq_str(&pf->hw, aq_err));
        }
 
-       return 0;
+       return aq_ret;
 }
 
 /**
- * i40e_vc_send_resp_to_vf
- * @vf: pointer to the VF info
- * @opcode: operation code
- * @retval: return value
+ * i40e_trigger_vf_reset
+ * @vf: pointer to the VF structure
+ * @flr: VFLR was issued or not
  *
- * send resp msg to VF
+ * Trigger hardware to start a reset for a particular VF. Expects the caller
+ * to wait the proper amount of time to allow hardware to reset the VF before
+ * it cleans up and restores VF functionality.
  **/
-static int i40e_vc_send_resp_to_vf(struct i40e_vf *vf,
-                                  enum virtchnl_ops opcode,
-                                  i40e_status retval)
+static void i40e_trigger_vf_reset(struct i40e_vf *vf, bool flr)
 {
-       return i40e_vc_send_msg_to_vf(vf, opcode, retval, NULL, 0);
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       u32 reg, reg_idx, bit_idx;
+
+       /* warn the VF */
+       clear_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states);
+
+       /* Disable VF's configuration API during reset. The flag is re-enabled
+        * in i40e_alloc_vf_res(), when it's safe again to access VF's VSI.
+        * It's normally disabled in i40e_free_vf_res(), but it's safer
+        * to do it earlier to give some time to finish to any VF config
+        * functions that may still be running at this point.
+        */
+       clear_bit(I40E_VF_STATE_INIT, &vf->vf_states);
+
+       /* In the case of a VFLR, the HW has already reset the VF and we
+        * just need to clean up, so don't hit the VFRTRIG register.
+        */
+       if (!flr) {
+               /* reset VF using VPGEN_VFRTRIG reg */
+               reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id));
+               reg |= I40E_VPGEN_VFRTRIG_VFSWR_MASK;
+               wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg);
+       }
+       /* clear the VFLR bit in GLGEN_VFLRSTAT */
+       reg_idx = (hw->func_caps.vf_base_id + vf->vf_id) / 32;
+       bit_idx = (hw->func_caps.vf_base_id + vf->vf_id) % 32;
+       wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
+       i40e_flush(hw);
+
+       if (i40e_quiesce_vf_pci(vf))
+               dev_err(&pf->pdev->dev, "VF %d PCI transactions stuck\n",
+                       vf->vf_id);
 }
 
 /**
- * i40e_vc_get_version_msg
- * @vf: pointer to the VF info
+ * i40e_cleanup_reset_vf
+ * @vf: pointer to the VF structure
  *
- * called from the VF to request the API version used by the PF
+ * Cleanup a VF after the hardware reset is finished. Expects the caller to
+ * have verified whether the reset is finished properly, and ensure the
+ * minimum amount of wait time has passed.
  **/
-static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg)
+static void i40e_cleanup_reset_vf(struct i40e_vf *vf)
 {
-       struct virtchnl_version_info info = {
-               VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR
-       };
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       u32 reg;
 
-       vf->vf_ver = *(struct virtchnl_version_info *)msg;
-       /* VFs running the 1.0 API expect to get 1.0 back or they will cry. */
-       if (VF_IS_V10(&vf->vf_ver))
-               info.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS;
-       return i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_VERSION,
-                                     I40E_SUCCESS, (u8 *)&info,
-                                     sizeof(struct virtchnl_version_info));
+       /* disable promisc modes in case they were enabled */
+       i40e_config_vf_promiscuous_mode(vf, vf->lan_vsi_id, false, false);
+
+       /* free VF resources to begin resetting the VSI state */
+       i40e_free_vf_res(vf);
+
+       /* Enable hardware by clearing the reset bit in the VPGEN_VFRTRIG reg.
+        * By doing this we allow HW to access VF memory at any point. If we
+        * did it any sooner, HW could access memory while it was being freed
+        * in i40e_free_vf_res(), causing an IOMMU fault.
+        *
+        * On the other hand, this needs to be done ASAP, because the VF driver
+        * is waiting for this to happen and may report a timeout. It's
+        * harmless, but it gets logged into Guest OS kernel log, so best avoid
+        * it.
+        */
+       reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id));
+       reg &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
+       wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg);
+
+       /* reallocate VF resources to finish resetting the VSI state */
+       if (!i40e_alloc_vf_res(vf)) {
+               int abs_vf_id = vf->vf_id + (int)hw->func_caps.vf_base_id;
+               i40e_enable_vf_mappings(vf);
+               set_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states);
+               clear_bit(I40E_VF_STATE_DISABLED, &vf->vf_states);
+               /* Do not notify the client during VF init */
+               if (!test_and_clear_bit(I40E_VF_STATE_PRE_ENABLE,
+                                       &vf->vf_states))
+                       i40e_notify_client_of_vf_reset(pf, abs_vf_id);
+               vf->num_vlan = 0;
+       }
+
+       /* Tell the VF driver the reset is done. This needs to be done only
+        * after VF has been fully initialized, because the VF driver may
+        * request resources immediately after setting this flag.
+        */
+       wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), VIRTCHNL_VFR_VFACTIVE);
 }
 
 /**
- * i40e_vc_get_vf_resources_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_reset_vf
+ * @vf: pointer to the VF structure
+ * @flr: VFLR was issued or not
  *
- * called from the VF to request its resources
+ * Returns true if the VF is reset, false otherwise.
  **/
-static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
+bool i40e_reset_vf(struct i40e_vf *vf, bool flr)
 {
-       struct virtchnl_vf_resource *vfres = NULL;
        struct i40e_pf *pf = vf->pf;
-       i40e_status aq_ret = 0;
-       struct i40e_vsi *vsi;
-       int num_vsis = 1;
-       int len = 0;
-       int ret;
-
-       if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto err;
-       }
+       struct i40e_hw *hw = &pf->hw;
+       bool rsd = false;
+       u32 reg;
+       int i;
 
-       if (test_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states))
-               num_vsis++;
+       /* If the VFs have been disabled, this means something else is
+        * resetting the VF, so we shouldn't continue.
+        */
+       if (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
+               return false;
 
-       len = (sizeof(struct virtchnl_vf_resource) +
-              sizeof(struct virtchnl_vsi_resource) * num_vsis);
+       i40e_trigger_vf_reset(vf, flr);
 
-       vfres = kzalloc(len, GFP_KERNEL);
-       if (!vfres) {
-               aq_ret = I40E_ERR_NO_MEMORY;
+       /* poll VPGEN_VFRSTAT reg to make sure
+        * that reset is complete
+        */
+       for (i = 0; i < 10; i++) {
+               /* VF reset requires driver to first reset the VF and then
+                * poll the status register to make sure that the reset
+                * completed successfully. Due to internal HW FIFO flushes,
+                * we must wait 10ms before the register will be valid.
+                */
+               usleep_range(10000, 20000);
+               reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id));
+               if (reg & I40E_VPGEN_VFRSTAT_VFRD_MASK) {
+                       rsd = true;
+                       break;
+               }
+       }
+
+       if (flr)
+               usleep_range(10000, 20000);
+
+       if (!rsd)
+               dev_err(&pf->pdev->dev, "VF reset check timeout on VF %d\n",
+                       vf->vf_id);
+       usleep_range(10000, 20000);
+
+       /* On initial reset, we don't have any queues to disable */
+       if (vf->lan_vsi_idx != 0)
+               i40e_vsi_stop_rings(pf->vsi[vf->lan_vsi_idx]);
+
+       i40e_cleanup_reset_vf(vf);
+
+       i40e_flush(hw);
+       clear_bit(__I40E_VF_DISABLE, pf->state);
+
+       return true;
+}
+
+/**
+ * i40e_reset_all_vfs
+ * @pf: pointer to the PF structure
+ * @flr: VFLR was issued or not
+ *
+ * Reset all allocated VFs in one go. First, tell the hardware to reset each
+ * VF, then do all the waiting in one chunk, and finally finish restoring each
+ * VF after the wait. This is useful during PF routines which need to reset
+ * all VFs, as otherwise it must perform these resets in a serialized fashion.
+ *
+ * Returns true if any VFs were reset, and false otherwise.
+ **/
+bool i40e_reset_all_vfs(struct i40e_pf *pf, bool flr)
+{
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_vf *vf;
+       int i, v;
+       u32 reg;
+
+       /* If we don't have any VFs, then there is nothing to reset */
+       if (!pf->num_alloc_vfs)
+               return false;
+
+       /* If VFs have been disabled, there is no need to reset */
+       if (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
+               return false;
+
+       /* Begin reset on all VFs at once */
+       for (v = 0; v < pf->num_alloc_vfs; v++)
+               i40e_trigger_vf_reset(&pf->vf[v], flr);
+
+       /* HW requires some time to make sure it can flush the FIFO for a VF
+        * when it resets it. Poll the VPGEN_VFRSTAT register for each VF in
+        * sequence to make sure that it has completed. We'll keep track of
+        * the VFs using a simple iterator that increments once that VF has
+        * finished resetting.
+        */
+       for (i = 0, v = 0; i < 10 && v < pf->num_alloc_vfs; i++) {
+               usleep_range(10000, 20000);
+
+               /* Check each VF in sequence, beginning with the VF to fail
+                * the previous check.
+                */
+               while (v < pf->num_alloc_vfs) {
+                       vf = &pf->vf[v];
+                       reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id));
+                       if (!(reg & I40E_VPGEN_VFRSTAT_VFRD_MASK))
+                               break;
+
+                       /* If the current VF has finished resetting, move on
+                        * to the next VF in sequence.
+                        */
+                       v++;
+               }
+       }
+
+       if (flr)
+               usleep_range(10000, 20000);
+
+       /* Display a warning if at least one VF didn't manage to reset in
+        * time, but continue on with the operation.
+        */
+       if (v < pf->num_alloc_vfs)
+               dev_err(&pf->pdev->dev, "VF reset check timeout on VF %d\n",
+                       pf->vf[v].vf_id);
+       usleep_range(10000, 20000);
+
+       /* Begin disabling all the rings associated with VFs, but do not wait
+        * between each VF.
+        */
+       for (v = 0; v < pf->num_alloc_vfs; v++) {
+               /* On initial reset, we don't have any queues to disable */
+               if (pf->vf[v].lan_vsi_idx == 0)
+                       continue;
+
+               i40e_vsi_stop_rings_no_wait(pf->vsi[pf->vf[v].lan_vsi_idx]);
+       }
+
+       /* Now that we've notified HW to disable all of the VF rings, wait
+        * until they finish.
+        */
+       for (v = 0; v < pf->num_alloc_vfs; v++) {
+               /* On initial reset, we don't have any queues to disable */
+               if (pf->vf[v].lan_vsi_idx == 0)
+                       continue;
+
+               i40e_vsi_wait_queues_disabled(pf->vsi[pf->vf[v].lan_vsi_idx]);
+       }
+
+       /* Hw may need up to 50ms to finish disabling the RX queues. We
+        * minimize the wait by delaying only once for all VFs.
+        */
+       mdelay(50);
+
+       /* Finish the reset on each VF */
+       for (v = 0; v < pf->num_alloc_vfs; v++)
+               i40e_cleanup_reset_vf(&pf->vf[v]);
+
+       i40e_flush(hw);
+       clear_bit(__I40E_VF_DISABLE, pf->state);
+
+       return true;
+}
+
+/**
+ * i40e_free_vfs
+ * @pf: pointer to the PF structure
+ *
+ * free VF resources
+ **/
+void i40e_free_vfs(struct i40e_pf *pf)
+{
+       struct i40e_hw *hw = &pf->hw;
+       u32 reg_idx, bit_idx;
+       int i, tmp, vf_id;
+
+       if (!pf->vf)
+               return;
+       while (test_and_set_bit(__I40E_VF_DISABLE, pf->state))
+               usleep_range(1000, 2000);
+
+       i40e_notify_client_of_vf_enable(pf, 0);
+
+       /* Amortize wait time by stopping all VFs at the same time */
+       for (i = 0; i < pf->num_alloc_vfs; i++) {
+               if (test_bit(I40E_VF_STATE_INIT, &pf->vf[i].vf_states))
+                       continue;
+
+               i40e_vsi_stop_rings_no_wait(pf->vsi[pf->vf[i].lan_vsi_idx]);
+       }
+
+       for (i = 0; i < pf->num_alloc_vfs; i++) {
+               if (test_bit(I40E_VF_STATE_INIT, &pf->vf[i].vf_states))
+                       continue;
+
+               i40e_vsi_wait_queues_disabled(pf->vsi[pf->vf[i].lan_vsi_idx]);
+       }
+
+       /* Disable IOV before freeing resources. This lets any VF drivers
+        * running in the host get themselves cleaned up before we yank
+        * the carpet out from underneath their feet.
+        */
+       if (!pci_vfs_assigned(pf->pdev))
+               pci_disable_sriov(pf->pdev);
+       else
+               dev_warn(&pf->pdev->dev, "VFs are assigned - not disabling SR-IOV\n");
+
+       /* free up VF resources */
+       tmp = pf->num_alloc_vfs;
+       pf->num_alloc_vfs = 0;
+       for (i = 0; i < tmp; i++) {
+               if (test_bit(I40E_VF_STATE_INIT, &pf->vf[i].vf_states))
+                       i40e_free_vf_res(&pf->vf[i]);
+               /* disable qp mappings */
+               i40e_disable_vf_mappings(&pf->vf[i]);
+       }
+       if (pf->vfd_obj) {
+               destroy_vfd_sysfs(pf->pdev, pf->vfd_obj);
+               pf->vfd_obj = NULL;
+       }
+
+       kfree(pf->vf);
+       pf->vf = NULL;
+
+       /* This check is for when the driver is unloaded while VFs are
+        * assigned. Setting the number of VFs to 0 through sysfs is caught
+        * before this function ever gets called.
+        */
+       if (!pci_vfs_assigned(pf->pdev)) {
+               /* Acknowledge VFLR for all VFS. Without this, VFs will fail to
+                * work correctly when SR-IOV gets re-enabled.
+                */
+               for (vf_id = 0; vf_id < tmp; vf_id++) {
+                       reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32;
+                       bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32;
+                       wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
+               }
+       }
+       clear_bit(__I40E_VF_DISABLE, pf->state);
+}
+
+#ifdef CONFIG_PCI_IOV
+/**
+ * i40e_alloc_vfs
+ * @pf: pointer to the PF structure
+ * @num_alloc_vfs: number of VFs to allocate
+ *
+ * allocate VF resources
+ **/
+int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
+{
+       struct i40e_vf *vfs;
+       int i, ret = 0;
+
+       /* Disable interrupt 0 so we don't try to handle the VFLR. */
+       i40e_irq_dynamic_disable_icr0(pf);
+
+       /* Check to see if we're just allocating resources for extant VFs */
+       if (pci_num_vf(pf->pdev) != num_alloc_vfs) {
+               ret = pci_enable_sriov(pf->pdev, num_alloc_vfs);
+               if (ret) {
+                       pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
+                       pf->num_alloc_vfs = 0;
+                       goto err_iov;
+               }
+       }
+       /* allocate memory */
+       vfs = kcalloc(num_alloc_vfs, sizeof(struct i40e_vf), GFP_KERNEL);
+       if (!vfs) {
+               ret = -ENOMEM;
+               goto err_alloc;
+       }
+       pf->vf = vfs;
+
+       /* set vfd ops */
+       vfd_ops = &i40e_vfd_ops;
+       /* create the sriov kobjects */
+       pf->vfd_obj = create_vfd_sysfs(pf->pdev, num_alloc_vfs);
+
+       /* apply default profile */
+       for (i = 0; i < num_alloc_vfs; i++) {
+               vfs[i].pf = pf;
+               vfs[i].parent_type = I40E_SWITCH_ELEMENT_TYPE_VEB;
+               vfs[i].vf_id = i;
+
+               /* assign default capabilities */
+               set_bit(I40E_VIRTCHNL_VF_CAP_L2, &vfs[i].vf_caps);
+               vfs[i].spoofchk = true;
+#if 0
+               /* TODO */
+               set_bit(VIRTCHNL_VF_CAP_IWARP, &vfs[i].vf_caps);
+#endif
+               set_bit(I40E_VF_STATE_PRE_ENABLE, &vfs[i].vf_states);
+       }
+       pf->num_alloc_vfs = num_alloc_vfs;
+
+       /* VF resources get allocated during reset */
+       i40e_reset_all_vfs(pf, false);
+
+       i40e_notify_client_of_vf_enable(pf, num_alloc_vfs);
+
+err_alloc:
+       if (ret)
+               i40e_free_vfs(pf);
+err_iov:
+       /* Re-enable interrupt 0. */
+       i40e_irq_dynamic_enable_icr0(pf);
+       return ret;
+}
+
+#endif
+#if defined(HAVE_SRIOV_CONFIGURE) || defined(HAVE_RHEL6_SRIOV_CONFIGURE)
+/**
+ * i40e_pci_sriov_enable
+ * @pdev: pointer to a pci_dev structure
+ * @num_vfs: number of VFs to allocate
+ *
+ * Enable or change the number of VFs
+ **/
+static int i40e_pci_sriov_enable(struct pci_dev *pdev, int num_vfs)
+{
+#ifdef CONFIG_PCI_IOV
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       int pre_existing_vfs = pci_num_vf(pdev);
+       int err = 0;
+
+       if (test_bit(__I40E_TESTING, pf->state)) {
+               dev_warn(&pdev->dev,
+                        "Cannot enable SR-IOV virtual functions while the device is undergoing diagnostic testing\n");
+               err = -EPERM;
+               goto err_out;
+       }
+
+       if (pre_existing_vfs && pre_existing_vfs != num_vfs)
+               i40e_free_vfs(pf);
+       else if (pre_existing_vfs && pre_existing_vfs == num_vfs)
+               goto out;
+
+       if (num_vfs > pf->num_req_vfs) {
+               dev_warn(&pdev->dev, "Unable to enable %d VFs. Limited to %d VFs due to device resource constraints.\n",
+                        num_vfs, pf->num_req_vfs);
+               err = -EPERM;
+               goto err_out;
+       }
+
+       dev_info(&pdev->dev, "Allocating %d VFs.\n", num_vfs);
+       err = i40e_alloc_vfs(pf, num_vfs);
+       if (err) {
+               dev_warn(&pdev->dev, "Failed to enable SR-IOV: %d\n", err);
+               goto err_out;
+       }
+
+out:
+       return num_vfs;
+
+err_out:
+       return err;
+#endif
+       return 0;
+}
+
+/**
+ * i40e_pci_sriov_configure
+ * @pdev: pointer to a pci_dev structure
+ * @num_vfs: number of vfs to allocate
+ *
+ * Enable or change the number of VFs. Called when the user updates the number
+ * of VFs in sysfs.
+ **/
+int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       int ret = 0;
+
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
+       }
+
+       if (num_vfs) {
+               if (!(pf->flags & I40E_FLAG_VEB_MODE_ENABLED)) {
+                       pf->flags |= I40E_FLAG_VEB_MODE_ENABLED;
+                       i40e_do_reset_safe(pf, I40E_PF_RESET_FLAG);
+               }
+               ret = i40e_pci_sriov_enable(pdev, num_vfs);
+               goto sriov_configure_out;
+       }
+       if (!pci_vfs_assigned(pdev)) {
+               i40e_free_vfs(pf);
+               pf->flags &= ~I40E_FLAG_VEB_MODE_ENABLED;
+               i40e_do_reset_safe(pf, I40E_PF_RESET_FLAG);
+       } else {
+               dev_warn(&pdev->dev, "Unable to free VFs because some are assigned to VMs.\n");
+               ret = -EINVAL;
+               goto sriov_configure_out;
+       }
+sriov_configure_out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
+}
+#endif
+
+/***********************virtual channel routines******************/
+
+/**
+ * i40e_vc_send_msg_to_vf
+ * @vf: pointer to the VF info
+ * @v_opcode: virtual channel opcode
+ * @v_retval: virtual channel return value
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * send msg to VF
+ **/
+static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode,
+                                 u32 v_retval, u8 *msg, u16 msglen)
+{
+       struct i40e_pf *pf;
+       struct i40e_hw *hw;
+       int abs_vf_id;
+       i40e_status aq_ret;
+
+       /* validate the request */
+       if (!vf || vf->vf_id >= vf->pf->num_alloc_vfs)
+               return -EINVAL;
+
+       pf = vf->pf;
+       hw = &pf->hw;
+       abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
+
+       /* single place to detect unsuccessful return values */
+       if (v_retval) {
+               vf->num_invalid_msgs++;
+               dev_info(&pf->pdev->dev, "VF %d failed opcode %d, retval: %d\n",
+                        vf->vf_id, v_opcode, v_retval);
+               if (vf->num_invalid_msgs >
+                   I40E_DEFAULT_NUM_INVALID_MSGS_ALLOWED) {
+                       dev_err(&pf->pdev->dev,
+                               "Number of invalid messages exceeded for VF %d\n",
+                               vf->vf_id);
+                       dev_err(&pf->pdev->dev, "Use PF Control I/F to enable the VF\n");
+                       set_bit(I40E_VF_STATE_DISABLED, &vf->vf_states);
+               }
+       } else {
+               vf->num_valid_msgs++;
+               /* reset the invalid counter, if a valid message is received. */
+               vf->num_invalid_msgs = 0;
+       }
+
+       aq_ret = i40e_aq_send_msg_to_vf(hw, abs_vf_id, v_opcode, v_retval,
+                                       msg, msglen, NULL);
+       if (aq_ret) {
+               dev_info(&pf->pdev->dev,
+                        "Unable to send the message to VF %d aq_err %d\n",
+                        vf->vf_id, pf->hw.aq.asq_last_status);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_vc_send_resp_to_vf
+ * @vf: pointer to the VF info
+ * @opcode: operation code
+ * @retval: return value
+ *
+ * send resp msg to VF
+ **/
+static int i40e_vc_send_resp_to_vf(struct i40e_vf *vf,
+                                  enum virtchnl_ops opcode,
+                                  i40e_status retval)
+{
+       return i40e_vc_send_msg_to_vf(vf, opcode, retval, NULL, 0);
+}
+
+/**
+ * i40e_vc_get_version_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to request the API version used by the PF
+ **/
+static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_version_info info = {
+               VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR
+       };
+
+       vf->vf_ver = *(struct virtchnl_version_info *)msg;
+       /* VFs running the 1.0 API expect to get 1.0 back or they will cry. */
+       if (VF_IS_V10(&vf->vf_ver))
+               info.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS;
+       return i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_VERSION,
+                                     I40E_SUCCESS, (u8 *)&info,
+                                     sizeof(struct virtchnl_version_info));
+}
+
+#ifdef __TC_MQPRIO_MODE_MAX
+/**
+ * i40e_del_qch - delete all the additional VSIs created as a part of ADq
+ * @vf: pointer to VF structure
+ **/
+static void i40e_del_qch(struct i40e_vf *vf)
+{
+       struct i40e_pf *pf = vf->pf;
+       int i;
+
+       /* first element in the array belongs to primary VF VSI and we shouldn't
+        * delete it. We should however delete the rest of the VSIs created
+        */
+       for (i = 1; i < vf->num_tc; i++) {
+               if (vf->ch[i].vsi_idx) {
+                       i40e_vsi_release(pf->vsi[vf->ch[i].vsi_idx]);
+                       vf->ch[i].vsi_idx = 0;
+                       vf->ch[i].vsi_id = 0;
+               }
+       }
+}
+
+#endif /* __TC_MQPRIO_MODE_MAX */
+
+/**
+ * i40e_vc_get_vf_resources_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to request its resources
+ **/
+static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_vf_resource *vfres = NULL;
+       struct i40e_pf *pf = vf->pf;
+       i40e_status aq_ret = 0;
+       struct i40e_vsi *vsi;
+       int num_vsis = 1;
+       int len = 0;
+       int ret;
+
+       if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+
+       if (test_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states))
+               num_vsis++;
+
+       len = (sizeof(struct virtchnl_vf_resource) +
+              sizeof(struct virtchnl_vsi_resource) * num_vsis);
+
+       vfres = kzalloc(len, GFP_KERNEL);
+       if (!vfres) {
+               aq_ret = I40E_ERR_NO_MEMORY;
+               len = 0;
+               goto err;
+       }
+       if (VF_IS_V11(&vf->vf_ver))
+               vf->driver_caps = *(u32 *)msg;
+       else
+               vf->driver_caps = VIRTCHNL_VF_OFFLOAD_L2 |
+                                 VIRTCHNL_VF_OFFLOAD_RSS_REG |
+                                 VIRTCHNL_VF_OFFLOAD_VLAN;
+
+       vfres->vf_cap_flags = VIRTCHNL_VF_OFFLOAD_L2;
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       if (!vsi->info.pvid)
+               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_VLAN;
+       if (i40e_vf_client_capable(pf, vf->vf_id) &&
+           (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_IWARP)) {
+               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_IWARP;
+               set_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states);
+       } else {
+               clear_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states);
+       }
+
+       if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
+               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF;
+       } else {
+               if ((pf->hw_features & I40E_HW_RSS_AQ_CAPABLE) &&
+                   (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_AQ))
+                       vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_AQ;
+               else
+                       vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_REG;
+       }
+       if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) {
+               if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
+                       vfres->vf_cap_flags |=
+                               VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2;
+       }
+
+       if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP)
+               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP;
+
+       if ((pf->hw_features & I40E_HW_OUTER_UDP_CSUM_CAPABLE) &&
+           (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM))
+               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM;
+
+       if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_POLLING) {
+               if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+                       dev_err(&pf->pdev->dev,
+                               "VF %d requested polling mode: this feature is supported only when the device is running in single function per port (SFP) mode\n",
+                                vf->vf_id);
+                       aq_ret = I40E_ERR_PARAM;
+                       goto err;
+               }
+               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_POLLING;
+       }
+
+       if (pf->hw_features & I40E_HW_WB_ON_ITR_CAPABLE) {
+               if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
+                       vfres->vf_cap_flags |=
+                                       VIRTCHNL_VF_OFFLOAD_WB_ON_ITR;
+       }
+
+       if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_REQ_QUEUES)
+               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_REQ_QUEUES;
+
+#ifdef __TC_MQPRIO_MODE_MAX
+       if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ADQ)
+               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ADQ;
+#endif /* __TC_MQPRIO_MODE_MAX */
+
+       vfres->num_vsis = num_vsis;
+       vfres->num_queue_pairs = vf->num_queue_pairs;
+       vfres->max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
+       vfres->rss_key_size = I40E_HKEY_ARRAY_SIZE;
+       vfres->rss_lut_size = I40E_VF_HLUT_ARRAY_SIZE;
+
+       if (vf->lan_vsi_idx) {
+               vfres->vsi_res[0].vsi_id = vf->lan_vsi_id;
+               vfres->vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV;
+               vfres->vsi_res[0].num_queue_pairs = vsi->alloc_queue_pairs;
+               /* VFs only use TC 0 */
+               vfres->vsi_res[0].qset_handle
+                                         = LE16_TO_CPU(vsi->info.qs_handle[0]);
+               ether_addr_copy(vfres->vsi_res[0].default_mac_addr,
+                               vf->default_lan_addr.addr);
+       }
+       set_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states);
+
+       /* if vf is in base mode, keep only the base capabilities that are
+        * negotiated
+        */
+       if (pf->vf_base_mode_only)
+               vfres->vf_cap_flags &= VF_BASE_MODE_OFFLOADS;
+err:
+       /* send the response back to the VF */
+       ret = i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_VF_RESOURCES,
+                                    aq_ret, (u8 *)vfres, len);
+
+       kfree(vfres);
+       return ret;
+}
+
+/**
+ * i40e_vc_reset_vf_msg
+ * @vf: pointer to the VF info
+ *
+ * called from the VF to reset itself,
+ * unlike other virtchnl messages, PF driver
+ * doesn't send the response back to the VF
+ **/
+static void i40e_vc_reset_vf_msg(struct i40e_vf *vf)
+{
+       if (test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states))
+               i40e_reset_vf(vf, false);
+}
+
+/**
+ * i40e_getnum_vf_vsi_vlan_filters
+ * @vsi: pointer to the vsi
+ *
+ * called to get the number of VLANs offloaded on this VF
+ **/
+static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
+{
+       struct i40e_mac_filter *f;
+       int num_vlans = 0, bkt;
+
+       hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
+               if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID)
+                       num_vlans++;
+       }
+
+       return num_vlans;
+}
+
+/**
+ * i40e_vc_config_promiscuous_mode_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to configure the promiscuous mode of
+ * VF vsis
+ **/
+static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_promisc_info *info =
+           (struct virtchnl_promisc_info *)msg;
+       i40e_status aq_ret = I40E_SUCCESS;
+       struct i40e_pf *pf = vf->pf;
+       bool allmulti = false;
+       bool alluni = false;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states))
+               return I40E_ERR_PARAM;
+
+       /* Multicast promiscuous handling*/
+       if (info->flags & FLAG_VF_MULTICAST_PROMISC)
+               allmulti = true;
+
+       if (info->flags & FLAG_VF_UNICAST_PROMISC)
+               alluni = true;
+
+       aq_ret = i40e_config_vf_promiscuous_mode(vf, info->vsi_id, allmulti,
+                                                alluni);
+       if (!aq_ret) {
+               if (allmulti) {
+                       dev_info(&pf->pdev->dev,
+                                "VF %d successfully set multicast promiscuous mode\n",
+                                vf->vf_id);
+                       set_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states);
+               } else {
+                       dev_info(&pf->pdev->dev,
+                                "VF %d successfully unset multicast promiscuous mode\n",
+                                vf->vf_id);
+                       clear_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states);
+               }
+               if (alluni) {
+                       dev_info(&pf->pdev->dev,
+                                "VF %d successfully set unicast promiscuous mode\n",
+                                vf->vf_id);
+                       set_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states);
+               } else {
+                       dev_info(&pf->pdev->dev,
+                                "VF %d successfully unset unicast promiscuous mode\n",
+                                vf->vf_id);
+                       clear_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states);
+               }
+       }
+       /* send the response to the VF */
+       return i40e_vc_send_resp_to_vf(vf,
+                                      VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_config_queues_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to configure the rx/tx
+ * queues
+ **/
+static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_vsi_queue_config_info *qci =
+           (struct virtchnl_vsi_queue_config_info *)msg;
+       struct virtchnl_queue_pair_info *qpi;
+       struct i40e_pf *pf = vf->pf;
+       u16 vsi_id, vsi_queue_id = 0;
+       i40e_status aq_ret = 0;
+       int i, j = 0, idx = 0;
+
+       vsi_id = qci->vsi_id;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       if (!i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+       for (i = 0; i < qci->num_queue_pairs; i++) {
+               qpi = &qci->qpair[i];
+
+               if (!vf->adq_enabled) {
+                       vsi_queue_id = qpi->txq.queue_id;
+
+                       if (qpi->txq.vsi_id != qci->vsi_id ||
+                           qpi->rxq.vsi_id != qci->vsi_id ||
+                           qpi->rxq.queue_id != vsi_queue_id) {
+                               aq_ret = I40E_ERR_PARAM;
+                               goto error_param;
+                       }
+               }
+
+               if (!i40e_vc_isvalid_queue_id(vf, vsi_id, vsi_queue_id)) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+
+               if (i40e_config_vsi_rx_queue(vf, vsi_id, vsi_queue_id,
+                                            &qpi->rxq) ||
+                   i40e_config_vsi_tx_queue(vf, vsi_id, vsi_queue_id,
+                                            &qpi->txq)) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+
+               /* For ADq there can be up to 4 VSIs with max 4 queues each.
+                * VF does not know about these additional VSIs and all
+                * it cares is about its own queues. PF configures these queues
+                * to its appropriate VSIs based on TC mapping
+                **/
+               if (vf->adq_enabled) {
+                       if (j == (vf->ch[idx].num_qps - 1)) {
+                               idx++;
+                               j = 0; /* resetting the queue count */
+                               vsi_queue_id = 0;
+                       } else {
+                               j++;
+                               vsi_queue_id++;
+                       }
+                       vsi_id = vf->ch[idx].vsi_id;
+               }
+       }
+
+       /* set vsi num_queue_pairs in use to num configured by VF */
+       if (!vf->adq_enabled) {
+               pf->vsi[vf->lan_vsi_idx]->num_queue_pairs =
+                       qci->num_queue_pairs;
+       } else {
+               for (i = 0; i < vf->num_tc; i++)
+                       pf->vsi[vf->ch[i].vsi_idx]->num_queue_pairs =
+                              vf->ch[i].num_qps;
+       }
+
+error_param:
+       /* send the response to the VF */
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES,
+                                      aq_ret);
+}
+
+/**
+ * i40e_validate_queue_map
+ * @vf: pointer to the VF info
+ * @vsi_id: vsi id
+ * @queuemap: Tx or Rx queue map
+ *
+ * check if Tx or Rx queue map is valid
+ **/
+static int i40e_validate_queue_map(struct i40e_vf *vf, u16 vsi_id,
+                                  unsigned long queuemap)
+{
+       u16 vsi_queue_id, queue_id;
+
+       for_each_set_bit(vsi_queue_id, &queuemap, I40E_MAX_VSI_QP) {
+               if (vf->adq_enabled) {
+                       vsi_id = vf->ch[vsi_queue_id / I40E_MAX_VF_VSI].vsi_id;
+                       queue_id = (vsi_queue_id % I40E_DEFAULT_QUEUES_PER_VF);
+               } else {
+                       queue_id = vsi_queue_id;
+               }
+
+               if (!i40e_vc_isvalid_queue_id(vf, vsi_id, queue_id))
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_vc_config_irq_map_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to configure the irq to
+ * queue map
+ **/
+static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_irq_map_info *irqmap_info =
+           (struct virtchnl_irq_map_info *)msg;
+       struct virtchnl_vector_map *map;
+       u16 vsi_id, vector_id;
+       i40e_status aq_ret = 0;
+       int i;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       for (i = 0; i < irqmap_info->num_vectors; i++) {
+               map = &irqmap_info->vecmap[i];
+               vector_id = map->vector_id;
+               vsi_id = map->vsi_id;
+               /* validate msg params */
+               if (!i40e_vc_isvalid_vector_id(vf, vector_id) ||
+                   !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+
+               if (i40e_validate_queue_map(vf, vsi_id, map->rxq_map)) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+
+               if (i40e_validate_queue_map(vf, vsi_id, map->txq_map)) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+
+               i40e_config_irq_link_list(vf, vsi_id, map);
+       }
+error_param:
+       /* send the response to the VF */
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_IRQ_MAP,
+                                      aq_ret);
+}
+
+/**
+ * i40e_ctrl_vf_tx_rings
+ * @vsi: the SRIOV VSI being configured
+ * @q_map: bit map of the queues to be enabled
+ * @enable: start or stop the queue
+ **/
+static int i40e_ctrl_vf_tx_rings(struct i40e_vsi *vsi, unsigned long q_map,
+                                bool enable)
+{
+       struct i40e_pf *pf = vsi->back;
+       int ret = 0;
+       u16 q_id;
+
+       for_each_set_bit(q_id, &q_map, I40E_MAX_VF_QUEUES) {
+               ret = i40e_control_wait_tx_q(vsi->seid, pf,
+                                            vsi->base_queue + q_id,
+                                            false /*is xdp*/, enable);
+               if (ret)
+                       break;
+       }
+       return ret;
+}
+
+/**
+ * i40e_ctrl_vf_rx_rings
+ * @vsi: the SRIOV VSI being configured
+ * @q_map: bit map of the queues to be enabled
+ * @enable: start or stop the queue
+ **/
+static int i40e_ctrl_vf_rx_rings(struct i40e_vsi *vsi, unsigned long q_map,
+                                bool enable)
+{
+       struct i40e_pf *pf = vsi->back;
+       int ret = 0;
+       u16 q_id;
+
+       for_each_set_bit(q_id, &q_map, I40E_MAX_VF_QUEUES) {
+               ret = i40e_control_wait_rx_q(pf, vsi->base_queue + q_id,
+                                            enable);
+               if (ret)
+                       break;
+       }
+       return ret;
+}
+
+/**
+ * i40e_vc_enable_queues_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to enable all or specific queue(s)
+ **/
+static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_queue_select *vqs =
+           (struct virtchnl_queue_select *)msg;
+       struct i40e_pf *pf = vf->pf;
+       u16 vsi_id = vqs->vsi_id;
+       i40e_status aq_ret = 0;
+       int i;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       if (!i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       if ((0 == vqs->rx_queues) && (0 == vqs->tx_queues)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       /* Use the queue bit map sent by the VF */
+       if (i40e_ctrl_vf_rx_rings(pf->vsi[vf->lan_vsi_idx], vqs->rx_queues,
+                                 true)) {
+               aq_ret = I40E_ERR_TIMEOUT;
+               goto error_param;
+       }
+       if (i40e_ctrl_vf_tx_rings(pf->vsi[vf->lan_vsi_idx], vqs->tx_queues,
+                                 true)) {
+               aq_ret = I40E_ERR_TIMEOUT;
+               goto error_param;
+       }
+
+       /* need to start the rings for additional ADq VSI's as well */
+       if (vf->adq_enabled) {
+               /* zero belongs to LAN VSI */
+               for (i = 1; i < vf->num_tc; i++) {
+                       if (i40e_ctrl_vf_rx_rings(pf->vsi[vf->ch[i].vsi_idx],
+                                                 vqs->rx_queues, true)) {
+                               aq_ret = I40E_ERR_TIMEOUT;
+                               goto error_param;
+                       }
+                       if (i40e_ctrl_vf_tx_rings(pf->vsi[vf->ch[i].vsi_idx],
+                                                 vqs->tx_queues, true)) {
+                               aq_ret = I40E_ERR_TIMEOUT;
+                               goto error_param;
+                       }
+               }
+       }
+
+error_param:
+       /* send the response to the VF */
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_disable_queues_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to disable all or specific
+ * queue(s)
+ **/
+static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_queue_select *vqs =
+           (struct virtchnl_queue_select *)msg;
+       struct i40e_pf *pf = vf->pf;
+       i40e_status aq_ret = 0;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       if (!i40e_vc_isvalid_vsi_id(vf, vqs->vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       if ((0 == vqs->rx_queues) && (0 == vqs->tx_queues)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       /* Use the queue bit map sent by the VF */
+       if (i40e_ctrl_vf_tx_rings(pf->vsi[vf->lan_vsi_idx], vqs->tx_queues,
+                                 false)) {
+               aq_ret = I40E_ERR_TIMEOUT;
+               goto error_param;
+       }
+       if (i40e_ctrl_vf_rx_rings(pf->vsi[vf->lan_vsi_idx], vqs->rx_queues,
+                                 false)) {
+               aq_ret = I40E_ERR_TIMEOUT;
+               goto error_param;
+       }
+error_param:
+       /* send the response to the VF */
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DISABLE_QUEUES,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_request_queues_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * VFs get a default number of queues but can use this message to request a
+ * different number.  If the request is successful, PF will reset the VF and
+ * return 0.  If unsuccessful, PF will send message informing VF of number of
+ * available queues and return result of sending VF a message.
+ **/
+static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_vf_res_request *vfres =
+               (struct virtchnl_vf_res_request *)msg;
+       int req_pairs = vfres->num_queue_pairs;
+       int cur_pairs = vf->num_queue_pairs;
+       struct i40e_pf *pf = vf->pf;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states))
+               return -EINVAL;
+
+       if (req_pairs <= 0) {
+               dev_err(&pf->pdev->dev,
+                       "VF %d tried to request %d queues.  Ignoring.\n",
+                       vf->vf_id, req_pairs);
+       } else if (req_pairs > I40E_MAX_VF_QUEUES) {
+               dev_err(&pf->pdev->dev,
+                       "VF %d tried to request more than %d queues.\n",
+                       vf->vf_id,
+                       I40E_MAX_VF_QUEUES);
+               vfres->num_queue_pairs = I40E_MAX_VF_QUEUES;
+       } else if (req_pairs - cur_pairs > pf->queues_left) {
+               dev_warn(&pf->pdev->dev,
+                        "VF %d requested %d more queues, but only %d left.\n",
+                        vf->vf_id,
+                        req_pairs - cur_pairs,
+                        pf->queues_left);
+               vfres->num_queue_pairs = pf->queues_left + cur_pairs;
+       } else {
+               /* successful request */
+               vf->num_req_queues = req_pairs;
+               i40e_vc_notify_vf_reset(vf);
+               i40e_reset_vf(vf, false);
+               return 0;
+       }
+
+       return i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_REQUEST_QUEUES, 0,
+                                     (u8 *)vfres, sizeof(*vfres));
+}
+
+/**
+ * i40e_vc_get_stats_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * called from the VF to get vsi stats
+ **/
+static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_queue_select *vqs =
+           (struct virtchnl_queue_select *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_eth_stats stats;
+       i40e_status aq_ret = 0;
+       struct i40e_vsi *vsi;
+
+       memset(&stats, 0, sizeof(struct i40e_eth_stats));
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       if (!i40e_vc_isvalid_vsi_id(vf, vqs->vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       if (!vsi) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+       i40e_update_eth_stats(vsi);
+       stats = vsi->eth_stats;
+
+error_param:
+       /* send the response back to the VF */
+       return i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_STATS, aq_ret,
+                                     (u8 *)&stats, sizeof(stats));
+}
+
+/* If the VF is not trusted restrict the number of MAC/VLAN it can program */
+#define I40E_VC_MAX_MAC_ADDR_PER_VF 12
+#define I40E_VC_MAX_VLAN_PER_VF 8
+
+/**
+ * i40e_check_vf_permission
+ * @vf: pointer to the VF info
+ * @al: MAC address list from virtchnl
+ *
+ * Check that the given list of MAC addresses is allowed. Will return -EPERM
+ * if any address in the list is not valid. Checks the following conditions:
+ *
+ * 1) broadcast and zero addresses are never valid
+ * 2) unicast addresses are not allowed if the VMM has administratively set
+ *    the VF MAC address, unless the VF is marked as privileged.
+ * 3) There is enough space to add all the addresses.
+ *
+ * Note that to guarantee consistency, it is expected this function be called
+ * while holding the mac_filter_hash_lock, as otherwise the current number of
+ * addresses might not be accurate.
+ **/
+static inline int i40e_check_vf_permission(struct i40e_vf *vf,
+                                          struct virtchnl_ether_addr_list *al)
+{
+       struct i40e_pf *pf = vf->pf;
+       int i;
+
+       /* If this VF is not privileged, then we can't add more than a limited
+        * number of addresses. Check to make sure that the additions do not
+        * push us over the limit.
+        */
+       if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) &&
+           (vf->num_mac + al->num_elements) > I40E_VC_MAX_MAC_ADDR_PER_VF) {
+               dev_err(&pf->pdev->dev,
+                       "Cannot add more MAC addresses, VF is not trusted, switch the VF to trusted to add more functionality\n");
+               if (pf->vf_base_mode_only)
+                       dev_err(&pf->pdev->dev, "VF %d is in base mode only, cannot add more than %d filters\n",
+                               vf->vf_id, I40E_VC_MAX_MAC_ADDR_PER_VF);
+               return -EPERM;
+       }
+
+       for (i = 0; i < al->num_elements; i++) {
+               u8 *addr = al->list[i].addr;
+
+               if (is_broadcast_ether_addr(addr) ||
+                   is_zero_ether_addr(addr)) {
+                       dev_err(&pf->pdev->dev, "invalid VF MAC addr %pM\n", addr);
+                       return I40E_ERR_INVALID_MAC_ADDR;
+               }
+
+               /* If the host VMM administrator has set the VF MAC address
+                * administratively via the ndo_set_vf_mac command then deny
+                * permission to the VF to add or delete unicast MAC addresses.
+                * Unless the VF is privileged and then it can do whatever.
+                * The VF may request to set the MAC address filter already
+                * assigned to it so do not return an error in that case.
+                */
+               if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) &&
+                   !is_multicast_ether_addr(addr) && vf->pf_set_mac &&
+                   !ether_addr_equal(addr, vf->default_lan_addr.addr)) {
+                       dev_err(&pf->pdev->dev,
+                               "VF attempting to override administratively set MAC address, bring down and up the VF interface to resume normal operation\n");
+                       return -EPERM;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_vc_add_mac_addr_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * add guest mac address filter
+ **/
+static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_ether_addr_list *al =
+           (struct virtchnl_ether_addr_list *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       u16 vsi_id = al->vsi_id;
+       i40e_status ret = 0;
+       int i;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+           !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+               ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       vsi = pf->vsi[vf->lan_vsi_idx];
+
+       /* Lock once, because all function inside for loop accesses VSI's
+        * MAC filter list which needs to be protected using same lock.
+        */
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+
+       ret = i40e_check_vf_permission(vf, al);
+       if (ret) {
+               spin_unlock_bh(&vsi->mac_filter_hash_lock);
+               goto error_param;
+       }
+
+       /* add new addresses to the list */
+       for (i = 0; i < al->num_elements; i++) {
+               struct i40e_mac_filter *f;
+
+               f = i40e_find_mac(vsi, al->list[i].addr);
+               if (!f) {
+                       f = i40e_add_mac_filter(vsi, al->list[i].addr);
+                       if (!f) {
+                               dev_err(&pf->pdev->dev,
+                                       "Unable to add MAC filter %pM for VF %d\n",
+                                       al->list[i].addr, vf->vf_id);
+                               ret = I40E_ERR_PARAM;
+                               spin_unlock_bh(&vsi->mac_filter_hash_lock);
+                               goto error_param;
+                       } else {
+                               vf->num_mac++;
+                       }
+               }
+       }
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+
+       /* program the updated filter list */
+       ret = i40e_sync_vsi_filters(vsi);
+       if (ret)
+               dev_err(&pf->pdev->dev, "Unable to program VF %d MAC filters, error %d\n",
+                       vf->vf_id, ret);
+
+error_param:
+       /* send the response to the VF */
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ADD_ETH_ADDR,
+                                      ret);
+}
+
+/**
+ * i40e_vc_del_mac_addr_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * remove guest mac address filter
+ **/
+static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_ether_addr_list *al =
+           (struct virtchnl_ether_addr_list *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       u16 vsi_id = al->vsi_id;
+       i40e_status ret = 0;
+       int i;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+           !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+               ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       for (i = 0; i < al->num_elements; i++) {
+               if (is_broadcast_ether_addr(al->list[i].addr) ||
+                   is_zero_ether_addr(al->list[i].addr)) {
+                       dev_err(&pf->pdev->dev, "Invalid MAC addr %pM for VF %d\n",
+                               al->list[i].addr, vf->vf_id);
+                       ret = I40E_ERR_INVALID_MAC_ADDR;
+                       goto error_param;
+               }
+
+               if (vf->pf_set_mac &&
+                   ether_addr_equal(al->list[i].addr,
+                                    vf->default_lan_addr.addr)) {
+                       dev_err(&pf->pdev->dev,
+                               "MAC addr %pM has been set by PF, cannot delete it for VF %d, reset VF to change MAC addr\n",
+                               vf->default_lan_addr.addr, vf->vf_id);
+                       ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+       }
+       vsi = pf->vsi[vf->lan_vsi_idx];
+
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+       /* delete addresses from the list */
+       for (i = 0; i < al->num_elements; i++)
+               if (i40e_del_mac_filter(vsi, al->list[i].addr)) {
+                       ret = I40E_ERR_INVALID_MAC_ADDR;
+                       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+                       goto error_param;
+               } else {
+                       vf->num_mac--;
+               }
+
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+
+       /* program the updated filter list */
+       ret = i40e_sync_vsi_filters(vsi);
+       if (ret)
+               dev_err(&pf->pdev->dev, "Unable to program VF %d MAC filters, error %d\n",
+                       vf->vf_id, ret);
+
+error_param:
+       /* send the response to the VF */
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DEL_ETH_ADDR,
+                                      ret);
+}
+
+/**
+ * i40e_vc_add_vlan_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * program guest vlan id
+ **/
+static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_vlan_filter_list *vfl =
+           (struct virtchnl_vlan_filter_list *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       u16 vsi_id = vfl->vsi_id;
+       i40e_status aq_ret = 0;
+       int i;
+
+       if ((vf->num_vlan >= I40E_VC_MAX_VLAN_PER_VF) &&
+           !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) {
+               dev_err(&pf->pdev->dev,
+                       "VF is not trusted, switch the VF to trusted to add more VLAN addresses\n");
+               if (pf->vf_base_mode_only)
+                       dev_err(&pf->pdev->dev, "VF %d is in base mode only, cannot add more than %d vlans\n",
+                               vf->vf_id, I40E_VC_MAX_VLAN_PER_VF);
+               goto error_param;
+       }
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+           !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       for (i = 0; i < vfl->num_elements; i++) {
+               if (vfl->vlan_id[i] > I40E_MAX_VLANID) {
+                       aq_ret = I40E_ERR_PARAM;
+                       dev_err(&pf->pdev->dev,
+                               "invalid VF VLAN id %d\n", vfl->vlan_id[i]);
+                       goto error_param;
+               }
+       }
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       if (vsi->info.pvid) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       i40e_vlan_stripping_enable(vsi);
+       for (i = 0; i < vfl->num_elements; i++) {
+               /* add new VLAN filter */
+               int ret = i40e_vsi_add_vlan(vsi, vfl->vlan_id[i]);
+               if (!ret)
+                       vf->num_vlan++;
+
+               if (test_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states))
+                       i40e_aq_set_vsi_uc_promisc_on_vlan(&pf->hw, vsi->seid,
+                                                          true,
+                                                          vfl->vlan_id[i],
+                                                          NULL);
+               if (test_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states))
+                       i40e_aq_set_vsi_mc_promisc_on_vlan(&pf->hw, vsi->seid,
+                                                          true,
+                                                          vfl->vlan_id[i],
+                                                          NULL);
+
+               if (ret)
+                       dev_err(&pf->pdev->dev,
+                               "Unable to add VLAN filter %d for VF %d, error %d\n",
+                               vfl->vlan_id[i], vf->vf_id, ret);
+       }
+
+error_param:
+       /* send the response to the VF */
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ADD_VLAN, aq_ret);
+}
+
+/**
+ * i40e_vc_remove_vlan_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * remove programmed guest vlan id
+ **/
+static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_vlan_filter_list *vfl =
+           (struct virtchnl_vlan_filter_list *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       u16 vsi_id = vfl->vsi_id;
+       i40e_status aq_ret = 0;
+       int i;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+           !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       for (i = 0; i < vfl->num_elements; i++) {
+               if (vfl->vlan_id[i] > I40E_MAX_VLANID) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+       }
+
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       if (vsi->info.pvid) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       for (i = 0; i < vfl->num_elements; i++) {
+               i40e_vsi_kill_vlan(vsi, vfl->vlan_id[i]);
+               vf->num_vlan--;
+
+               if (test_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states))
+                       i40e_aq_set_vsi_uc_promisc_on_vlan(&pf->hw, vsi->seid,
+                                                          false,
+                                                          vfl->vlan_id[i],
+                                                          NULL);
+               if (test_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states))
+                       i40e_aq_set_vsi_mc_promisc_on_vlan(&pf->hw, vsi->seid,
+                                                          false,
+                                                          vfl->vlan_id[i],
+                                                          NULL);
+       }
+
+error_param:
+       /* send the response to the VF */
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DEL_VLAN, aq_ret);
+}
+
+/**
+ * i40e_vc_iwarp_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * called from the VF for the iwarp msgs
+ **/
+static int i40e_vc_iwarp_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+{
+       struct i40e_pf *pf = vf->pf;
+       int abs_vf_id = vf->vf_id + (int)pf->hw.func_caps.vf_base_id;
+       i40e_status aq_ret = I40E_SUCCESS;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+           !test_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       i40e_notify_client_of_vf_msg(pf->vsi[pf->lan_vsi], abs_vf_id,
+                                    msg, msglen);
+
+error_param:
+       /* send the response to the VF */
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_IWARP,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_iwarp_qvmap_msg
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ * @config: config qvmap or release it
+ *
+ * called from the VF for the iwarp msgs
+ **/
+static int i40e_vc_iwarp_qvmap_msg(struct i40e_vf *vf, u8 *msg, bool config)
+{
+       struct virtchnl_iwarp_qvlist_info *qvlist_info =
+                               (struct virtchnl_iwarp_qvlist_info *)msg;
+       i40e_status aq_ret = 0;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+           !test_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       if (config) {
+               if (i40e_config_iwarp_qvlist(vf, qvlist_info))
+                       aq_ret = I40E_ERR_PARAM;
+       } else {
+               i40e_release_iwarp_qvlist(vf);
+       }
+
+error_param:
+       /* send the response to the VF */
+       return i40e_vc_send_resp_to_vf(vf,
+                              config ? VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP :
+                              VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP,
+                              aq_ret);
+}
+
+/**
+ * i40e_vc_config_rss_key
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * Configure the VF's RSS key
+ **/
+static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_rss_key *vrk =
+               (struct virtchnl_rss_key *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       u16 vsi_id = vrk->vsi_id;
+       i40e_status aq_ret = 0;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+           !i40e_vc_isvalid_vsi_id(vf, vsi_id) ||
+           (vrk->key_len != I40E_HKEY_ARRAY_SIZE)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       aq_ret = i40e_config_rss(vsi, vrk->key, NULL, 0);
+err:
+       /* send the response to the VF */
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_KEY,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_config_rss_lut
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * Configure the VF's RSS LUT
+ **/
+static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_rss_lut *vrl =
+               (struct virtchnl_rss_lut *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       u16 vsi_id = vrl->vsi_id;
+       i40e_status aq_ret = 0;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
+           !i40e_vc_isvalid_vsi_id(vf, vsi_id) ||
+           (vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       aq_ret = i40e_config_rss(vsi, NULL, vrl->lut, I40E_VF_HLUT_ARRAY_SIZE);
+       /* send the response to the VF */
+err:
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_LUT,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_get_rss_hena
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * Return the RSS HENA bits allowed by the hardware
+ **/
+static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_rss_hena *vrh = NULL;
+       struct i40e_pf *pf = vf->pf;
+       i40e_status aq_ret = 0;
+       int len = 0;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+       len = sizeof(struct virtchnl_rss_hena);
+
+       vrh = kzalloc(len, GFP_KERNEL);
+       if (!vrh) {
+               aq_ret = I40E_ERR_NO_MEMORY;
                len = 0;
                goto err;
        }
-       if (VF_IS_V11(&vf->vf_ver))
-               vf->driver_caps = *(u32 *)msg;
+       vrh->hena = i40e_pf_get_default_rss_hena(pf);
+err:
+       /* send the response back to the VF */
+       aq_ret = i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_RSS_HENA_CAPS,
+                                       aq_ret, (u8 *)vrh, len);
+       kfree(vrh);
+       return aq_ret;
+}
+
+/**
+ * i40e_vc_set_rss_hena
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * Set the RSS HENA bits for the VF
+ **/
+static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_rss_hena *vrh =
+               (struct virtchnl_rss_hena *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       i40e_status aq_ret = 0;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+       i40e_write_rx_ctl(hw, I40E_VFQF_HENA1(0, vf->vf_id), (u32)vrh->hena);
+       i40e_write_rx_ctl(hw, I40E_VFQF_HENA1(1, vf->vf_id),
+                         (u32)(vrh->hena >> 32));
+
+       /* send the response to the VF */
+err:
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_SET_RSS_HENA, aq_ret);
+}
+
+/**
+ * i40e_vc_enable_vlan_stripping
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * Enable vlan header stripping for the VF
+ **/
+static int i40e_vc_enable_vlan_stripping(struct i40e_vf *vf, u8 *msg)
+{
+       struct i40e_vsi *vsi = vf->pf->vsi[vf->lan_vsi_idx];
+       i40e_status aq_ret = 0;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+
+       i40e_vlan_stripping_enable(vsi);
+
+       /* send the response to the VF */
+err:
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_VLAN_STRIPPING,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_disable_vlan_stripping
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * Disable vlan header stripping for the VF
+ **/
+static int i40e_vc_disable_vlan_stripping(struct i40e_vf *vf, u8 *msg)
+{
+       struct i40e_vsi *vsi = vf->pf->vsi[vf->lan_vsi_idx];
+       i40e_status aq_ret = 0;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+
+       i40e_vlan_stripping_disable(vsi);
+
+       /* send the response to the VF */
+err:
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING,
+                                      aq_ret);
+}
+
+#ifdef __TC_MQPRIO_MODE_MAX
+/**
+ * i40e_validate_cloud_filter
+ * @vf: pointer to the VF info
+ * @tc_filter: pointer to virtchnl_filter
+ *
+ * This function validates cloud filter programmed as TC filter for ADq
+ **/
+static int i40e_validate_cloud_filter(struct i40e_vf *vf,
+                                     struct virtchnl_filter *tc_filter)
+{
+       struct virtchnl_l4_spec mask = tc_filter->mask.tcp_spec;
+       struct virtchnl_l4_spec data = tc_filter->data.tcp_spec;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       struct i40e_mac_filter *f;
+       struct hlist_node *h;
+       bool found = false;
+       int bkt;
+
+       if (!tc_filter->action) {
+               dev_info(&pf->pdev->dev,
+                        "VF %d: Currently ADq doesn't support Drop Action\n",
+                        vf->vf_id);
+               goto err;
+       }
+
+       /* action_meta is TC number here to which the filter is applied */
+       if (!tc_filter->action_meta ||
+           tc_filter->action_meta > I40E_MAX_VF_VSI) {
+               dev_info(&pf->pdev->dev, "VF %d: Invalid TC number %u\n",
+                        vf->vf_id, tc_filter->action_meta);
+               goto err;
+       }
+
+       /* Check filter if it's programmed for advanced mode or basic mode.
+        * There are two ADq modes (for VF only),
+        * 1. Basic mode: intended to allow as many filter options as possible
+        *                to be added to a VF in Non-trusted mode. Main goal is
+        *                to add filters to its own MAC and VLAN id.
+        * 2. Advanced mode: is for allowing filters to be applied other than
+        *                its own MAC or VLAN. This mode requires the VF to be
+        *                Trusted.
+        */
+       if (mask.dst_mac[0] && !mask.dst_ip[0]) {
+               vsi = pf->vsi[vf->lan_vsi_idx];
+               f = i40e_find_mac(vsi, data.dst_mac);
+
+               if (!f) {
+                       dev_info(&pf->pdev->dev,
+                                "Destination MAC %pM doesn't belong to VF %d\n",
+                                data.dst_mac, vf->vf_id);
+                       goto err;
+               }
+
+               if (mask.vlan_id) {
+                       hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f,
+                                          hlist) {
+                               if (f->vlan == ntohs(data.vlan_id)) {
+                                       found = true;
+                                       break;
+                               }
+                       }
+                       if (!found) {
+                               dev_info(&pf->pdev->dev,
+                                        "VF %d doesn't have any VLAN id %u\n",
+                                        vf->vf_id, ntohs(data.vlan_id));
+                               goto err;
+                       }
+               }
+       } else {
+               /* Check if VF is trusted */
+               if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) {
+                       dev_err(&pf->pdev->dev,
+                               "VF %d not trusted, make VF trusted to add advanced mode ADq cloud filters\n",
+                               vf->vf_id);
+                       return I40E_ERR_CONFIG;
+               }
+       }
+
+       if (mask.dst_mac[0] & data.dst_mac[0]) {
+               if (is_broadcast_ether_addr(data.dst_mac) ||
+                   is_zero_ether_addr(data.dst_mac)) {
+                       dev_info(&pf->pdev->dev, "VF %d: Invalid Dest MAC addr %pM\n",
+                                vf->vf_id, data.dst_mac);
+                       goto err;
+               }
+       }
+
+       if (mask.src_mac[0] & data.src_mac[0]) {
+               if (is_broadcast_ether_addr(data.src_mac) ||
+                   is_zero_ether_addr(data.src_mac)) {
+                       dev_info(&pf->pdev->dev, "VF %d: Invalid Source MAC addr %pM\n",
+                                vf->vf_id, data.src_mac);
+                       goto err;
+               }
+       }
+
+       if (mask.dst_port & data.dst_port) {
+               if (!data.dst_port || be16_to_cpu(data.dst_port) > 0xFFFF) {
+                       dev_info(&pf->pdev->dev, "VF %d: Invalid Dest port\n",
+                                vf->vf_id);
+                       goto err;
+               }
+       }
+
+       if (mask.src_port & data.src_port) {
+               if (!data.src_port || be16_to_cpu(data.src_port) > 0xFFFF) {
+                       dev_info(&pf->pdev->dev, "VF %d: Invalid Source port\n",
+                                vf->vf_id);
+                       goto err;
+               }
+       }
+
+       if (tc_filter->flow_type != VIRTCHNL_TCP_V6_FLOW &&
+           tc_filter->flow_type != VIRTCHNL_TCP_V4_FLOW) {
+               dev_info(&pf->pdev->dev, "VF %d: Invalid Flow type\n",
+                        vf->vf_id);
+               goto err;
+       }
+
+       if (mask.vlan_id & data.vlan_id) {
+               if (ntohs(data.vlan_id) > I40E_MAX_VLANID) {
+                       dev_info(&pf->pdev->dev, "VF %d: invalid VLAN ID\n",
+                                vf->vf_id);
+                       goto err;
+               }
+       }
+
+       return I40E_SUCCESS;
+err:
+       return I40E_ERR_CONFIG;
+}
+
+/**
+ * i40e_find_vf_vsi_from_seid - searches for the vsi with the given seid
+ * @vf: pointer to the VF info
+ * @seid: seid of the vsi it is searching for
+ **/
+static struct i40e_vsi *i40e_find_vf_vsi_from_seid(struct i40e_vf *vf, u16 seid)
+{
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       int i;
+
+       for (i = 0; i < vf->num_tc ; i++) {
+               vsi = i40e_find_vsi_from_id(pf, vf->ch[i].vsi_id);
+               if (vsi && vsi->seid == seid)
+                       return vsi;
+       }
+       return NULL;
+}
+
+/**
+ * i40e_del_all_cloud_filters
+ * @vf: pointer to the VF info
+ *
+ * This function deletes all cloud filters
+ **/
+static void i40e_del_all_cloud_filters(struct i40e_vf *vf)
+{
+       struct i40e_cloud_filter *cfilter = NULL;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       struct hlist_node *node;
+       int ret;
+
+       hlist_for_each_entry_safe(cfilter, node,
+                                 &vf->cloud_filter_list, cloud_node) {
+               vsi = i40e_find_vf_vsi_from_seid(vf, cfilter->seid);
+
+               if (!vsi) {
+                       dev_err(&pf->pdev->dev, "VF %d: no VSI found for matching %u seid, can't delete cloud filter\n",
+                               vf->vf_id, cfilter->seid);
+                       continue;
+               }
+
+               if (cfilter->dst_port)
+                       ret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter,
+                                                               false);
+               else
+                       ret = i40e_add_del_cloud_filter(vsi, cfilter, false);
+               if (ret)
+                       dev_err(&pf->pdev->dev,
+                               "VF %d: Failed to delete cloud filter, err %s aq_err %s\n",
+                               vf->vf_id, i40e_stat_str(&pf->hw, ret),
+                               i40e_aq_str(&pf->hw,
+                                           pf->hw.aq.asq_last_status));
+
+               hlist_del(&cfilter->cloud_node);
+               kfree(cfilter);
+               vf->num_cloud_filters--;
+       }
+}
+
+/**
+ * i40e_vc_del_cloud_filter
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * This function deletes a cloud filter programmed as TC filter for ADq
+ **/
+static int i40e_vc_del_cloud_filter(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_filter *vcf = (struct virtchnl_filter *)msg;
+       struct virtchnl_l4_spec mask = vcf->mask.tcp_spec;
+       struct virtchnl_l4_spec tcf = vcf->data.tcp_spec;
+       struct i40e_cloud_filter cfilter, *cf = NULL;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       struct hlist_node *node;
+       i40e_status aq_ret = 0;
+       int i, ret;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+
+       if (!vf->adq_enabled) {
+               dev_info(&pf->pdev->dev,
+                        "VF %d: ADq not enabled, can't apply cloud filter\n",
+                        vf->vf_id);
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+
+       if (i40e_validate_cloud_filter(vf, vcf)) {
+               dev_info(&pf->pdev->dev,
+                        "VF %d: Invalid input, can't apply cloud filter\n",
+                        vf->vf_id);
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+
+       memset(&cfilter, 0, sizeof(cfilter));
+       /* parse destination mac address */
+       for (i = 0; i < ETH_ALEN; i++)
+               cfilter.dst_mac[i] = mask.dst_mac[i] & tcf.dst_mac[i];
+
+       /* parse source mac address */
+       for (i = 0; i < ETH_ALEN; i++)
+               cfilter.src_mac[i] = mask.src_mac[i] & tcf.src_mac[i];
+
+       cfilter.vlan_id = mask.vlan_id & tcf.vlan_id;
+       cfilter.dst_port = mask.dst_port & tcf.dst_port;
+       cfilter.src_port = mask.src_port & tcf.src_port;
+
+       switch (vcf->flow_type) {
+       case VIRTCHNL_TCP_V4_FLOW:
+               cfilter.n_proto = ETH_P_IP;
+               if (mask.dst_ip[0] & tcf.dst_ip[0])
+                       memcpy(&cfilter.ip.v4.dst_ip, tcf.dst_ip,
+                              ARRAY_SIZE(tcf.dst_ip));
+               else if (mask.src_ip[0] & tcf.dst_ip[0])
+                       memcpy(&cfilter.ip.v4.src_ip, tcf.src_ip,
+                              ARRAY_SIZE(tcf.dst_ip));
+               break;
+       case VIRTCHNL_TCP_V6_FLOW:
+               cfilter.n_proto = ETH_P_IPV6;
+               if (mask.dst_ip[3] & tcf.dst_ip[3])
+                       memcpy(&cfilter.ip.v6.dst_ip6, tcf.dst_ip,
+                              sizeof(cfilter.ip.v6.dst_ip6));
+               if (mask.src_ip[3] & tcf.src_ip[3])
+                       memcpy(&cfilter.ip.v6.src_ip6, tcf.src_ip,
+                              sizeof(cfilter.ip.v6.src_ip6));
+               break;
+       default:
+               /* TC filter can be configured based on different combinations
+                * and in this case IP is not a part of filter config
+                */
+               dev_info(&pf->pdev->dev, "VF %d: Flow type not configured\n",
+                        vf->vf_id);
+       }
+
+       /* get the vsi to which the tc belongs to */
+       vsi = pf->vsi[vf->ch[vcf->action_meta].vsi_idx];
+       cfilter.seid = vsi->seid;
+       cfilter.flags = vcf->field_flags;
+
+       /* Deleting TC filter */
+       if (tcf.dst_port)
+               ret = i40e_add_del_cloud_filter_big_buf(vsi, &cfilter, false);
        else
-               vf->driver_caps = VIRTCHNL_VF_OFFLOAD_L2 |
-                                 VIRTCHNL_VF_OFFLOAD_RSS_REG |
-                                 VIRTCHNL_VF_OFFLOAD_VLAN;
+               ret = i40e_add_del_cloud_filter(vsi, &cfilter, false);
+       if (ret) {
+               dev_err(&pf->pdev->dev,
+                       "VF %d: Failed to delete cloud filter, err %s aq_err %s\n",
+                       vf->vf_id, i40e_stat_str(&pf->hw, ret),
+                       i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
+               goto err;
+       }
+
+       hlist_for_each_entry_safe(cf, node,
+                                 &vf->cloud_filter_list, cloud_node) {
+               if (cf->seid != cfilter.seid)
+                       continue;
+               if (mask.dst_port)
+                       if (cfilter.dst_port != cf->dst_port)
+                               continue;
+               if (mask.dst_mac[0])
+                       if (!ether_addr_equal(cf->src_mac, cfilter.src_mac))
+                               continue;
+               /* for ipv4 data to be valid, only first byte of mask is set */
+               if (cfilter.n_proto == ETH_P_IP && mask.dst_ip[0])
+                       if (memcmp(&cfilter.ip.v4.dst_ip, &cf->ip.v4.dst_ip,
+                                  ARRAY_SIZE(tcf.dst_ip)))
+                               continue;
+               /* for ipv6, mask is set for all sixteen bytes (4 words) */
+               if (cfilter.n_proto == ETH_P_IPV6 && mask.dst_ip[3])
+                       if (memcmp(&cfilter.ip.v6.dst_ip6, &cf->ip.v6.dst_ip6,
+                                  sizeof(cfilter.ip.v6.src_ip6)))
+                               continue;
+               if (mask.vlan_id)
+                       if (cfilter.vlan_id != cf->vlan_id)
+                               continue;
+
+               hlist_del(&cf->cloud_node);
+               kfree(cf);
+               vf->num_cloud_filters--;
+       }
+
+err:
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DEL_CLOUD_FILTER,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_add_cloud_filter
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ *
+ * This function adds a cloud filter programmed as TC filter for ADq
+ **/
+static int i40e_vc_add_cloud_filter(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_filter *vcf = (struct virtchnl_filter *)msg;
+       struct virtchnl_l4_spec mask = vcf->mask.tcp_spec;
+       struct virtchnl_l4_spec tcf = vcf->data.tcp_spec;
+       struct i40e_cloud_filter *cfilter = NULL;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       i40e_status aq_ret = 0;
+       int i, ret;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+
+       if (!vf->adq_enabled) {
+               dev_info(&pf->pdev->dev,
+                        "VF %d: ADq is not enabled, can't apply cloud filter\n",
+                        vf->vf_id);
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+
+       if (i40e_validate_cloud_filter(vf, vcf)) {
+               dev_info(&pf->pdev->dev,
+                        "VF %d: Invalid input/s, can't apply cloud filter\n",
+                        vf->vf_id);
+                       aq_ret = I40E_ERR_PARAM;
+                       goto err;
+       }
+
+       cfilter = kzalloc(sizeof(*cfilter), GFP_KERNEL);
+       if (!cfilter)
+               return -ENOMEM;
+
+       /* parse destination mac address */
+       for (i = 0; i < ETH_ALEN; i++)
+               cfilter->dst_mac[i] = mask.dst_mac[i] & tcf.dst_mac[i];
+
+       /* parse source mac address */
+       for (i = 0; i < ETH_ALEN; i++)
+               cfilter->src_mac[i] = mask.src_mac[i] & tcf.src_mac[i];
+
+       cfilter->vlan_id = mask.vlan_id & tcf.vlan_id;
+       cfilter->dst_port = mask.dst_port & tcf.dst_port;
+       cfilter->src_port = mask.src_port & tcf.src_port;
+
+       switch (vcf->flow_type) {
+       case VIRTCHNL_TCP_V4_FLOW:
+               cfilter->n_proto = ETH_P_IP;
+               if (mask.dst_ip[0] & tcf.dst_ip[0])
+                       memcpy(&cfilter->ip.v4.dst_ip, tcf.dst_ip,
+                              ARRAY_SIZE(tcf.dst_ip));
+               else if (mask.src_ip[0] & tcf.dst_ip[0])
+                       memcpy(&cfilter->ip.v4.src_ip, tcf.src_ip,
+                              ARRAY_SIZE(tcf.dst_ip));
+               break;
+       case VIRTCHNL_TCP_V6_FLOW:
+               cfilter->n_proto = ETH_P_IPV6;
+               if (mask.dst_ip[3] & tcf.dst_ip[3])
+                       memcpy(&cfilter->ip.v6.dst_ip6, tcf.dst_ip,
+                              sizeof(cfilter->ip.v6.dst_ip6));
+               if (mask.src_ip[3] & tcf.src_ip[3])
+                       memcpy(&cfilter->ip.v6.src_ip6, tcf.src_ip,
+                              sizeof(cfilter->ip.v6.src_ip6));
+               break;
+       default:
+               /* TC filter can be configured based on different combinations
+                * and in this case IP is not a part of filter config
+                */
+               dev_info(&pf->pdev->dev, "VF %d: Flow type not configured\n",
+                        vf->vf_id);
+       }
+
+       /* get the VSI to which the TC belongs to */
+       vsi = pf->vsi[vf->ch[vcf->action_meta].vsi_idx];
+       cfilter->seid = vsi->seid;
+       cfilter->flags = vcf->field_flags;
+
+       /* Adding cloud filter programmed as TC filter */
+       if (tcf.dst_port)
+               ret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter, true);
+       else
+               ret = i40e_add_del_cloud_filter(vsi, cfilter, true);
+       if (ret) {
+               dev_err(&pf->pdev->dev,
+                       "VF %d: Failed to add cloud filter, err %s aq_err %s\n",
+                       vf->vf_id, i40e_stat_str(&pf->hw, ret),
+                       i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
+               goto err;
+       }
+
+       INIT_HLIST_NODE(&cfilter->cloud_node);
+       hlist_add_head(&cfilter->cloud_node, &vf->cloud_filter_list);
+       vf->num_cloud_filters++;
+err:
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ADD_CLOUD_FILTER,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_add_qch_msg: Add queue channel and enable ADq
+ * @vf: pointer to the VF info
+ * @msg: pointer to the msg buffer
+ **/
+static int i40e_vc_add_qch_msg(struct i40e_vf *vf, u8 *msg)
+{
+       struct virtchnl_tc_info *tci = (struct virtchnl_tc_info *)msg;
+       int i, adq_request_qps = 0, speed = 0;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_link_status *ls;
+       i40e_status aq_ret = 0;
 
-       vfres->vf_cap_flags = VIRTCHNL_VF_OFFLOAD_L2;
-       vsi = pf->vsi[vf->lan_vsi_idx];
-       if (!vsi->info.pvid)
-               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_VLAN;
-       if (i40e_vf_client_capable(pf, vf->vf_id) &&
-           (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_IWARP)) {
-               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_IWARP;
-               set_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states);
-       } else {
-               clear_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states);
+       ls = &pf->hw.phy.link_info;
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
        }
 
-       if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
-               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_PF;
-       } else {
-               if ((pf->hw_features & I40E_HW_RSS_AQ_CAPABLE) &&
-                   (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_AQ))
-                       vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_AQ;
-               else
-                       vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RSS_REG;
-       }
-       if (pf->hw_features & I40E_HW_MULTIPLE_TCP_UDP_RSS_PCTYPE) {
-               if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2)
-                       vfres->vf_cap_flags |=
-                               VIRTCHNL_VF_OFFLOAD_RSS_PCTYPE_V2;
+       /* ADq cannot be applied if spoof check is ON */
+       if (vf->spoofchk) {
+               dev_err(&pf->pdev->dev,
+                       "Spoof check is ON, turn it OFF to enable ADq\n");
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
        }
 
-       if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP)
-               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP;
+       if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ADQ)) {
+               dev_err(&pf->pdev->dev,
+                       "VF %d attempting to enable ADq, but hasn't properly negotiated that capability\n",
+                       vf->vf_id);
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
 
-       if ((pf->hw_features & I40E_HW_OUTER_UDP_CSUM_CAPABLE) &&
-           (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM))
-               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM;
+       /* max number of traffic classes for VF currently capped at 4 */
+       if (!tci->num_tc || tci->num_tc > I40E_MAX_VF_VSI) {
+               dev_err(&pf->pdev->dev,
+                       "VF %d trying to set %u TCs, valid range 1-4 TCs per VF\n",
+                       vf->vf_id, tci->num_tc);
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
 
-       if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_RX_POLLING) {
-               if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+       /* validate queues for each TC */
+       for (i = 0; i < tci->num_tc; i++)
+               if (!tci->list[i].count ||
+                   tci->list[i].count > I40E_DEFAULT_QUEUES_PER_VF) {
                        dev_err(&pf->pdev->dev,
-                               "VF %d requested polling mode: this feature is supported only when the device is running in single function per port (SFP) mode\n",
-                                vf->vf_id);
+                               "VF %d: TC %d trying to set %u queues, valid range 1-4 queues per TC\n",
+                               vf->vf_id, i, tci->list[i].count);
                        aq_ret = I40E_ERR_PARAM;
                        goto err;
                }
-               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_RX_POLLING;
-       }
 
-       if (pf->hw_features & I40E_HW_WB_ON_ITR_CAPABLE) {
-               if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
-                       vfres->vf_cap_flags |=
-                                       VIRTCHNL_VF_OFFLOAD_WB_ON_ITR;
-       }
+       /* need Max VF queues but already have default number of queues */
+       adq_request_qps = I40E_MAX_VF_QUEUES - I40E_DEFAULT_QUEUES_PER_VF;
 
-       if (vf->driver_caps & VIRTCHNL_VF_OFFLOAD_REQ_QUEUES)
-               vfres->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_REQ_QUEUES;
+       if (pf->queues_left < adq_request_qps) {
+               dev_err(&pf->pdev->dev,
+                       "No queues left to allocate to VF %d\n",
+                       vf->vf_id);
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       } else {
+               /* we need to allocate max VF queues to enable ADq so as to
+                * make sure ADq enabled VF always gets back queues when it
+                * goes through a reset.
+                */
+               vf->num_queue_pairs = I40E_MAX_VF_QUEUES;
+       }
 
-       vfres->num_vsis = num_vsis;
-       vfres->num_queue_pairs = vf->num_queue_pairs;
-       vfres->max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
-       vfres->rss_key_size = I40E_HKEY_ARRAY_SIZE;
-       vfres->rss_lut_size = I40E_VF_HLUT_ARRAY_SIZE;
+       /* get link speed in MB to validate rate limit */
+       switch (ls->link_speed) {
+       case VIRTCHNL_LINK_SPEED_100MB:
+               speed = SPEED_100;
+               break;
+       case VIRTCHNL_LINK_SPEED_1GB:
+               speed = SPEED_1000;
+               break;
+       case VIRTCHNL_LINK_SPEED_10GB:
+               speed = SPEED_10000;
+               break;
+       case VIRTCHNL_LINK_SPEED_20GB:
+               speed = SPEED_20000;
+               break;
+       case VIRTCHNL_LINK_SPEED_25GB:
+               speed = SPEED_25000;
+               break;
+       case VIRTCHNL_LINK_SPEED_40GB:
+               speed = SPEED_40000;
+               break;
+       default:
+               dev_err(&pf->pdev->dev, "Cannot detect link speed\n");
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
 
-       if (vf->lan_vsi_idx) {
-               vfres->vsi_res[0].vsi_id = vf->lan_vsi_id;
-               vfres->vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV;
-               vfres->vsi_res[0].num_queue_pairs = vsi->alloc_queue_pairs;
-               /* VFs only use TC 0 */
-               vfres->vsi_res[0].qset_handle
-                                         = LE16_TO_CPU(vsi->info.qs_handle[0]);
-               ether_addr_copy(vfres->vsi_res[0].default_mac_addr,
-                               vf->default_lan_addr.addr);
+       /* parse data from the queue channel info */
+       vf->num_tc = tci->num_tc;
+       for (i = 0; i < vf->num_tc; i++) {
+               if (tci->list[i].max_tx_rate) {
+                       if (tci->list[i].max_tx_rate > speed) {
+                               dev_err(&pf->pdev->dev,
+                                       "Invalid max tx rate %llu specified for VF %d.",
+                                       tci->list[i].max_tx_rate,
+                                       vf->vf_id);
+                               aq_ret = I40E_ERR_PARAM;
+                               goto err;
+                       } else {
+                               vf->ch[i].max_tx_rate =
+                                       tci->list[i].max_tx_rate;
+                       }
+               }
+               vf->ch[i].num_qps = tci->list[i].count;
        }
-       set_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states);
 
-       /* if vf is in base mode, keep only the base capabilities that are
-        * negotiated
+       /* set this flag only after making sure all inputs are sane */
+       vf->adq_enabled = true;
+       /* num_req_queues is set when user changes number of queues via ethtool
+        * and this causes issue for default VSI(which depends on this variable)
+        * when ADq is enabled, hence reset it.
         */
-       if (pf->vf_base_mode_only)
-               vfres->vf_cap_flags &= VF_BASE_MODE_OFFLOADS;
-err:
-       /* send the response back to the VF */
-       ret = i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_VF_RESOURCES,
-                                    aq_ret, (u8 *)vfres, len);
+       vf->num_req_queues = 0;
 
-       kfree(vfres);
-       return ret;
+       /* reset the VF in order to allocate resources */
+       i40e_vc_notify_vf_reset(vf);
+       i40e_reset_vf(vf, false);
+
+       return I40E_SUCCESS;
+
+       /* send the response to the VF */
+err:
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_CHANNELS,
+                                      aq_ret);
 }
 
 /**
- * i40e_vc_reset_vf_msg
+ * i40e_vc_del_qch_msg
  * @vf: pointer to the VF info
  * @msg: pointer to the msg buffer
- * @msglen: msg length
- *
- * called from the VF to reset itself,
- * unlike other virtchnl messages, PF driver
- * doesn't send the response back to the VF
  **/
-static void i40e_vc_reset_vf_msg(struct i40e_vf *vf)
+static int i40e_vc_del_qch_msg(struct i40e_vf *vf, u8 *msg)
 {
-       if (test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states))
-               i40e_reset_vf(vf, false);
+       struct i40e_pf *pf = vf->pf;
+       i40e_status aq_ret = 0;
+
+       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+
+       if (vf->adq_enabled) {
+               i40e_del_all_cloud_filters(vf);
+               i40e_del_qch(vf);
+               vf->adq_enabled = false;
+               vf->num_tc = 0;
+               dev_info(&pf->pdev->dev,
+                        "Deleting Queue Channels and cloud filters for ADq on VF %d\n",
+                        vf->vf_id);
+       } else {
+               dev_info(&pf->pdev->dev, "VF %d trying to delete queue channels but ADq isn't enabled\n",
+                        vf->vf_id);
+               aq_ret = I40E_ERR_PARAM;
+       }
+
+       /* reset the VF in order to allocate resources */
+       i40e_vc_notify_vf_reset(vf);
+       i40e_reset_vf(vf, false);
+
+       return I40E_SUCCESS;
+
+err:
+       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DISABLE_CHANNELS,
+                                      aq_ret);
 }
 
+#endif /* __TC_MQPRIO_MODE_MAX */
+
 /**
- * i40e_getnum_vf_vsi_vlan_filters
- * @vsi: pointer to the vsi
+ * i40e_vc_process_vf_msg
+ * @pf: pointer to the PF structure
+ * @vf_id: source VF id
+ * @v_opcode: operation code
+ * @v_retval: unused return value code
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
  *
- * called to get the number of VLANs offloaded on this VF
+ * called from the common aeq/arq handler to
+ * process request from VF
  **/
-static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
+int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode,
+                          u32 __always_unused v_retval, u8 *msg, u16 msglen)
 {
-       struct i40e_mac_filter *f;
-       int num_vlans = 0, bkt;
+       struct i40e_hw *hw = &pf->hw;
+       int local_vf_id = vf_id - (s16)hw->func_caps.vf_base_id;
+       struct i40e_vf *vf;
+       int ret;
 
-       hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
-               if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID)
-                       num_vlans++;
+       pf->vf_aq_requests++;
+       if (local_vf_id >= pf->num_alloc_vfs)
+               return -EINVAL;
+       vf = &(pf->vf[local_vf_id]);
+
+       /* Check if VF is disabled. */
+       if (test_bit(I40E_VF_STATE_DISABLED, &vf->vf_states))
+               return I40E_ERR_PARAM;
+
+       /* perform basic checks on the msg */
+       ret = virtchnl_vc_validate_vf_msg(&vf->vf_ver, v_opcode, msg, msglen);
+
+       /* perform additional checks specific to this driver */
+       if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_KEY) {
+               struct virtchnl_rss_key *vrk = (struct virtchnl_rss_key *)msg;
+
+               if (vrk->key_len != I40E_HKEY_ARRAY_SIZE)
+                       ret = -EINVAL;
+       } else if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_LUT) {
+               struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg;
+
+               if (vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE)
+                       ret = -EINVAL;
+       }
+
+       if (ret) {
+               i40e_vc_send_resp_to_vf(vf, v_opcode, I40E_ERR_PARAM);
+               dev_err(&pf->pdev->dev, "Invalid message from VF %d, opcode %d, len %d\n",
+                       local_vf_id, v_opcode, msglen);
+               switch (ret) {
+               case VIRTCHNL_ERR_PARAM:
+                       return -EPERM;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       switch (v_opcode) {
+       case VIRTCHNL_OP_VERSION:
+               ret = i40e_vc_get_version_msg(vf, msg);
+               break;
+       case VIRTCHNL_OP_GET_VF_RESOURCES:
+               ret = i40e_vc_get_vf_resources_msg(vf, msg);
+               i40e_vc_notify_vf_link_state(vf);
+               break;
+       case VIRTCHNL_OP_RESET_VF:
+               i40e_vc_reset_vf_msg(vf);
+               ret = 0;
+               break;
+       case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
+               ret = i40e_vc_config_promiscuous_mode_msg(vf, msg);
+               break;
+       case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
+               ret = i40e_vc_config_queues_msg(vf, msg);
+               break;
+       case VIRTCHNL_OP_CONFIG_IRQ_MAP:
+               ret = i40e_vc_config_irq_map_msg(vf, msg);
+               break;
+       case VIRTCHNL_OP_ENABLE_QUEUES:
+               ret = i40e_vc_enable_queues_msg(vf, msg);
+               i40e_vc_notify_vf_link_state(vf);
+               break;
+       case VIRTCHNL_OP_DISABLE_QUEUES:
+               ret = i40e_vc_disable_queues_msg(vf, msg);
+               break;
+       case VIRTCHNL_OP_ADD_ETH_ADDR:
+               ret = i40e_vc_add_mac_addr_msg(vf, msg);
+               break;
+       case VIRTCHNL_OP_DEL_ETH_ADDR:
+               ret = i40e_vc_del_mac_addr_msg(vf, msg);
+               break;
+       case VIRTCHNL_OP_ADD_VLAN:
+               ret = i40e_vc_add_vlan_msg(vf, msg);
+               break;
+       case VIRTCHNL_OP_DEL_VLAN:
+               ret = i40e_vc_remove_vlan_msg(vf, msg);
+               break;
+       case VIRTCHNL_OP_GET_STATS:
+               ret = i40e_vc_get_stats_msg(vf, msg);
+               break;
+       case VIRTCHNL_OP_IWARP:
+               ret = i40e_vc_iwarp_msg(vf, msg, msglen);
+               break;
+       case VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP:
+               ret = i40e_vc_iwarp_qvmap_msg(vf, msg, true);
+               break;
+       case VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP:
+               ret = i40e_vc_iwarp_qvmap_msg(vf, msg, false);
+               break;
+       case VIRTCHNL_OP_CONFIG_RSS_KEY:
+               ret = i40e_vc_config_rss_key(vf, msg);
+               break;
+       case VIRTCHNL_OP_CONFIG_RSS_LUT:
+               ret = i40e_vc_config_rss_lut(vf, msg);
+               break;
+       case VIRTCHNL_OP_GET_RSS_HENA_CAPS:
+               ret = i40e_vc_get_rss_hena(vf, msg);
+               break;
+       case VIRTCHNL_OP_SET_RSS_HENA:
+               ret = i40e_vc_set_rss_hena(vf, msg);
+               break;
+       case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
+               ret = i40e_vc_enable_vlan_stripping(vf, msg);
+               break;
+       case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING:
+               ret = i40e_vc_disable_vlan_stripping(vf, msg);
+               break;
+       case VIRTCHNL_OP_REQUEST_QUEUES:
+               ret = i40e_vc_request_queues_msg(vf, msg);
+               break;
+#ifdef __TC_MQPRIO_MODE_MAX
+       case VIRTCHNL_OP_ENABLE_CHANNELS:
+               ret = i40e_vc_add_qch_msg(vf, msg);
+               break;
+       case VIRTCHNL_OP_DISABLE_CHANNELS:
+               ret = i40e_vc_del_qch_msg(vf, msg);
+               break;
+       case VIRTCHNL_OP_ADD_CLOUD_FILTER:
+               ret = i40e_vc_add_cloud_filter(vf, msg);
+               break;
+       case VIRTCHNL_OP_DEL_CLOUD_FILTER:
+               ret = i40e_vc_del_cloud_filter(vf, msg);
+               break;
+#endif /* __TC_MQPRIO_MODE_MAX */
+       case VIRTCHNL_OP_UNKNOWN:
+       default:
+               dev_err(&pf->pdev->dev, "Unsupported opcode %d from VF %d\n",
+                       v_opcode, local_vf_id);
+               ret = i40e_vc_send_resp_to_vf(vf, v_opcode,
+                                             I40E_ERR_NOT_IMPLEMENTED);
+               break;
        }
 
-       return num_vlans;
+       return ret;
 }
 
 /**
- * i40e_vc_config_promiscuous_mode_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_vc_process_vflr_event
+ * @pf: pointer to the PF structure
  *
- * called from the VF to configure the promiscuous mode of
- * VF vsis
+ * called from the vlfr irq handler to
+ * free up VF resources and state variables
  **/
-static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf,
-                                              u8 *msg, u16 msglen)
+int i40e_vc_process_vflr_event(struct i40e_pf *pf)
 {
-       struct virtchnl_promisc_info *info =
-           (struct virtchnl_promisc_info *)msg;
-       i40e_status aq_ret = I40E_SUCCESS;
-       struct i40e_pf *pf = vf->pf;
        struct i40e_hw *hw = &pf->hw;
-       struct i40e_mac_filter *f;
-       bool allmulti = false;
-       struct i40e_vsi *vsi;
-       bool alluni = false;
-       int aq_err = 0;
-       int bkt;
-
-       vsi = i40e_find_vsi_from_id(pf, info->vsi_id);
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
-           !i40e_vc_isvalid_vsi_id(vf, info->vsi_id) ||
-           !vsi) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
-       }
-       if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) {
-               dev_err(&pf->pdev->dev,
-                       "Unprivileged VF %d is attempting to configure promiscuous mode\n",
-                       vf->vf_id);
-               if (pf->vf_base_mode_only)
-                       dev_err(&pf->pdev->dev, "VF %d is in base mode only, promiscuous mode is not be supported\n",
-                               vf->vf_id);
-               /* Lie to the VF on purpose. */
-               aq_ret = I40E_SUCCESS;
-               goto error_param;
-       }
-       /* Multicast promiscuous handling*/
-       if (info->flags & FLAG_VF_MULTICAST_PROMISC)
-               allmulti = true;
-       if (vf->port_vlan_id) {
-               aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw, vsi->seid,
-                                                           allmulti,
-                                                           vf->port_vlan_id,
-                                                           NULL);
-       } else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
-               hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
-                       if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID)
-                               continue;
-                       aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw,
-                                                                   vsi->seid,
-                                                                   allmulti,
-                                                                   f->vlan,
-                                                                   NULL);
-                       aq_err = pf->hw.aq.asq_last_status;
-                       if (aq_ret) {
-                               dev_err(&pf->pdev->dev,
-                                       "Could not add VLAN %d to multicast promiscuous domain err %s aq_err %s\n",
-                                       f->vlan,
-                                       i40e_stat_str(&pf->hw, aq_ret),
-                                       i40e_aq_str(&pf->hw, aq_err));
-                               break;
-                       }
-               }
-       } else {
-               aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid,
-                                                              allmulti, NULL);
-               aq_err = pf->hw.aq.asq_last_status;
-               if (aq_ret) {
-                       dev_err(&pf->pdev->dev,
-                               "VF %d failed to set multicast promiscuous mode err %s aq_err %s\n",
-                               vf->vf_id,
-                               i40e_stat_str(&pf->hw, aq_ret),
-                               i40e_aq_str(&pf->hw, aq_err));
-                       goto error_param;
-               }
-       }
+       u32 reg, reg_idx, bit_idx;
+       struct i40e_vf *vf;
+       int vf_id;
 
-       if (!aq_ret) {
-               dev_info(&pf->pdev->dev,
-                        "VF %d successfully set multicast promiscuous mode\n",
-                        vf->vf_id);
-               if (allmulti)
-                       set_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states);
-               else
-                       clear_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states);
-       }
+       if (!test_bit(__I40E_VFLR_EVENT_PENDING, pf->state))
+               return 0;
 
-       if (info->flags & FLAG_VF_UNICAST_PROMISC)
-               alluni = true;
-       if (vf->port_vlan_id) {
-               aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw, vsi->seid,
-                                                           alluni,
-                                                           vf->port_vlan_id,
-                                                           NULL);
-       } else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
-               hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
-                       if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID)
-                               continue;
-                       aq_ret = i40e_aq_set_vsi_uc_promisc_on_vlan(hw,
-                                                                   vsi->seid,
-                                                                   alluni,
-                                                                   f->vlan,
-                                                                   NULL);
-                       aq_err = pf->hw.aq.asq_last_status;
-                       if (aq_ret)
-                               dev_err(&pf->pdev->dev,
-                                       "Could not add VLAN %d to Unicast promiscuous domain err %s aq_err %s\n",
-                                       f->vlan,
-                                       i40e_stat_str(&pf->hw, aq_ret),
-                                       i40e_aq_str(&pf->hw, aq_err));
-               }
-       } else {
-               aq_ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid,
-                                                            alluni, NULL,
-                                                            true);
-               aq_err = pf->hw.aq.asq_last_status;
-               if (aq_ret) {
-                       dev_err(&pf->pdev->dev,
-                               "VF %d failed to set unicast promiscuous mode %8.8x err %s aq_err %s\n",
-                               vf->vf_id, info->flags,
-                               i40e_stat_str(&pf->hw, aq_ret),
-                               i40e_aq_str(&pf->hw, aq_err));
-                       goto error_param;
-               }
-       }
+       /* Re-enable the VFLR interrupt cause here, before looking for which
+        * VF got reset. Otherwise, if another VF gets a reset while the
+        * first one is being processed, that interrupt will be lost, and
+        * that VF will be stuck in reset forever.
+        */
+       reg = rd32(hw, I40E_PFINT_ICR0_ENA);
+       reg |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
+       wr32(hw, I40E_PFINT_ICR0_ENA, reg);
+       i40e_flush(hw);
 
-       if (!aq_ret) {
-               dev_info(&pf->pdev->dev,
-                        "VF %d successfully set unicast promiscuous mode\n",
-                        vf->vf_id);
-               if (alluni)
-                       set_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states);
-               else
-                       clear_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states);
+       clear_bit(__I40E_VFLR_EVENT_PENDING, pf->state);
+       for (vf_id = 0; vf_id < pf->num_alloc_vfs; vf_id++) {
+               reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32;
+               bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32;
+               /* read GLGEN_VFLRSTAT register to find out the flr VFs */
+               vf = &pf->vf[vf_id];
+               reg = rd32(hw, I40E_GLGEN_VFLRSTAT(reg_idx));
+               if (reg & BIT(bit_idx))
+                       /* i40e_reset_vf will clear the bit in GLGEN_VFLRSTAT */
+                       i40e_reset_vf(vf, true);
        }
 
-error_param:
-       /* send the response to the VF */
-       return i40e_vc_send_resp_to_vf(vf,
-                                      VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE,
-                                      aq_ret);
+       return 0;
 }
 
+#ifdef IFLA_VF_MAX
+
 /**
- * i40e_vc_config_queues_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_set_vf_mac
+ * @vf: the VF
+ * @vsi: VF VSI to configure
+ * @mac: the mac address
+ *
+ * This function allows the administrator to set the mac address for the VF
+ *
+ * Returns 0 on success, negative on failure
  *
- * called from the VF to configure the rx/tx
- * queues
  **/
-static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_set_vf_mac(struct i40e_vf *vf, struct i40e_vsi *vsi,
+                          const u8 *mac)
 {
-       struct virtchnl_vsi_queue_config_info *qci =
-           (struct virtchnl_vsi_queue_config_info *)msg;
-       struct virtchnl_queue_pair_info *qpi;
-       struct i40e_pf *pf = vf->pf;
-       u16 vsi_id, vsi_queue_id;
-       i40e_status aq_ret = 0;
-       int i;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_mac_filter *f;
+       struct hlist_node *h;
+       int ret = 0;
+       int bkt;
+       u8 i;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pf->pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
 
-       vsi_id = qci->vsi_id;
-       if (!i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
-               aq_ret = I40E_ERR_PARAM;
+       if (is_multicast_ether_addr(mac)) {
+               dev_err(&pf->pdev->dev,
+                       "Invalid Ethernet address %pM for VF %d\n",
+                       mac, vf->vf_id);
+               ret = -EINVAL;
                goto error_param;
        }
-       for (i = 0; i < qci->num_queue_pairs; i++) {
-               qpi = &qci->qpair[i];
-               vsi_queue_id = qpi->txq.queue_id;
-               if ((qpi->txq.vsi_id != vsi_id) ||
-                   (qpi->rxq.vsi_id != vsi_id) ||
-                   (qpi->rxq.queue_id != vsi_queue_id) ||
-                   !i40e_vc_isvalid_queue_id(vf, vsi_id, vsi_queue_id)) {
-                       aq_ret = I40E_ERR_PARAM;
-                       goto error_param;
-               }
 
-               if (i40e_config_vsi_rx_queue(vf, vsi_id, vsi_queue_id,
-                                            &qpi->rxq) ||
-                   i40e_config_vsi_tx_queue(vf, vsi_id, vsi_queue_id,
-                                            &qpi->txq)) {
-                       aq_ret = I40E_ERR_PARAM;
-                       goto error_param;
-               }
+       /* When the VF is resetting wait until it is done.
+        * It can take up to 200 milliseconds,
+        * but wait for up to 300 milliseconds to be safe.
+        */
+       for (i = 0; i < 15; i++) {
+               if (test_bit(I40E_VF_STATE_INIT, &vf->vf_states))
+                       break;
+               msleep(20);
        }
-
-       /* set vsi num_queue_pairs in use to num configured by VF */
-       pf->vsi[vf->lan_vsi_idx]->num_queue_pairs = qci->num_queue_pairs;
-
-error_param:
-       /* send the response to the VF */
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_VSI_QUEUES,
-                                      aq_ret);
-}
-
-/**
- * i40e_vc_config_irq_map_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
- *
- * called from the VF to configure the irq to
- * queue map
- **/
-static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
-{
-       struct virtchnl_irq_map_info *irqmap_info =
-           (struct virtchnl_irq_map_info *)msg;
-       struct virtchnl_vector_map *map;
-       u16 vsi_id, vsi_queue_id, vector_id;
-       i40e_status aq_ret = 0;
-       unsigned long tempmap;
-       int i;
-
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
-               aq_ret = I40E_ERR_PARAM;
+       if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
+               dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
+                       vf->vf_id);
+               ret = -EAGAIN;
                goto error_param;
        }
 
-       for (i = 0; i < irqmap_info->num_vectors; i++) {
-               map = &irqmap_info->vecmap[i];
+       /* Lock once because below invoked function add/del_filter requires
+        * mac_filter_hash_lock to be held
+        */
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
 
-               vector_id = map->vector_id;
-               vsi_id = map->vsi_id;
-               /* validate msg params */
-               if (!i40e_vc_isvalid_vector_id(vf, vector_id) ||
-                   !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
-                       aq_ret = I40E_ERR_PARAM;
-                       goto error_param;
-               }
+       /* delete the temporary mac address */
+       if (!is_zero_ether_addr(vf->default_lan_addr.addr))
+               i40e_del_mac_filter(vsi, vf->default_lan_addr.addr);
 
-               /* lookout for the invalid queue index */
-               tempmap = map->rxq_map;
-               for_each_set_bit(vsi_queue_id, &tempmap, I40E_MAX_VSI_QP) {
-                       if (!i40e_vc_isvalid_queue_id(vf, vsi_id,
-                                                     vsi_queue_id)) {
-                               aq_ret = I40E_ERR_PARAM;
-                               goto error_param;
-                       }
-               }
+       /* Delete all the filters for this VSI - we're going to kill it
+        * anyway.
+        */
+       hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist)
+               __i40e_del_filter(vsi, f);
 
-               tempmap = map->txq_map;
-               for_each_set_bit(vsi_queue_id, &tempmap, I40E_MAX_VSI_QP) {
-                       if (!i40e_vc_isvalid_queue_id(vf, vsi_id,
-                                                     vsi_queue_id)) {
-                               aq_ret = I40E_ERR_PARAM;
-                               goto error_param;
-                       }
-               }
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
 
-               i40e_config_irq_link_list(vf, vsi_id, map);
+       /* program mac filter */
+       if (i40e_sync_vsi_filters(vsi)) {
+               dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
+               ret = -EIO;
+               goto error_param;
+       }
+       ether_addr_copy(vf->default_lan_addr.addr, mac);
+
+       if (is_zero_ether_addr(mac)) {
+               vf->pf_set_mac = false;
+               dev_info(&pf->pdev->dev, "Removing MAC on VF %d\n", vf->vf_id);
+       } else {
+               vf->pf_set_mac = true;
+               dev_info(&pf->pdev->dev, "Setting MAC %pM on VF %d\n",
+                        mac, vf->vf_id);
        }
+
+       /* Force the VF interface down so it has to bring up with new MAC
+        * address
+        */
+       i40e_vc_disable_vf(vf);
+       dev_info(&pf->pdev->dev, "Bring down and up the VF interface to make this change effective.\n");
 error_param:
-       /* send the response to the VF */
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_IRQ_MAP,
-                                      aq_ret);
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
 }
 
 /**
- * i40e_vc_enable_queues_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_ndo_set_vf_mac
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @mac: mac address
  *
- * called from the VF to enable all or specific queue(s)
+ * program VF mac address
  **/
-static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
 {
-       struct virtchnl_queue_select *vqs =
-           (struct virtchnl_queue_select *)msg;
-       struct i40e_pf *pf = vf->pf;
-       u16 vsi_id = vqs->vsi_id;
-       i40e_status aq_ret = 0;
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_vf *vf;
+       int ret = 0;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
-               aq_ret = I40E_ERR_PARAM;
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
                goto error_param;
-       }
 
-       if (!i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
-       }
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       ret = i40e_set_vf_mac(vf, vsi, mac);
+error_param:
+       return ret;
+}
 
-       if ((0 == vqs->rx_queues) && (0 == vqs->tx_queues)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
-       }
+/**
+ * i40e_vsi_has_vlans - True if VSI has configured VLANs
+ * @vsi: pointer to the vsi
+ *
+ * Check if a VSI has configured any VLANs. False if we have a port VLAN or if
+ * we have no configured VLANs. Do not call while holding the
+ * mac_filter_hash_lock.
+ */
+static bool i40e_vsi_has_vlans(struct i40e_vsi *vsi)
+{
+       bool have_vlans;
 
-       if (i40e_vsi_start_rings(pf->vsi[vf->lan_vsi_idx]))
-               aq_ret = I40E_ERR_TIMEOUT;
-error_param:
-       /* send the response to the VF */
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_QUEUES,
-                                      aq_ret);
+       /* If we have a port VLAN, then the VSI cannot have any VLANs
+        * configured, as all MAC/VLAN filters will be assigned to the PVID.
+        */
+       if (vsi->info.pvid)
+               return false;
+
+       /* Since we don't have a PVID, we know that if the device is in VLAN
+        * mode it must be because of a VLAN filter configured on this VSI.
+        */
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+       have_vlans = i40e_is_vsi_in_vlan(vsi);
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+
+       return have_vlans;
 }
 
 /**
- * i40e_vc_disable_queues_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_ndo_set_vf_port_vlan
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @vlan_id: mac address
+ * @qos: priority setting
+ * @vlan_proto: vlan protocol
  *
- * called from the VF to disable all or specific
- * queue(s)
+ * program VF vlan id and/or qos
  **/
-static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+#ifdef IFLA_VF_VLAN_INFO_MAX
+int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
+                             u16 vlan_id, u8 qos, __be16 vlan_proto)
+#else
+int i40e_ndo_set_vf_port_vlan(struct net_device *netdev,
+                             int vf_id, u16 vlan_id, u8 qos)
+#endif /* IFLA_VF_VLAN_INFO_MAX */
 {
-       struct virtchnl_queue_select *vqs =
-           (struct virtchnl_queue_select *)msg;
-       struct i40e_pf *pf = vf->pf;
-       i40e_status aq_ret = 0;
+       u16 vlanprio = vlan_id | (qos << I40E_VLAN_PRIORITY_SHIFT);
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret = 0;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pf->pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
 
-       if (!i40e_vc_isvalid_vsi_id(vf, vqs->vsi_id)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto error_pvid;
+
+       if ((vlan_id > I40E_MAX_VLANID) || (qos > 7)) {
+               dev_err(&pf->pdev->dev, "Invalid VF Parameters\n");
+               ret = -EINVAL;
+               goto error_pvid;
        }
+#ifdef IFLA_VF_VLAN_INFO_MAX
 
-       if ((0 == vqs->rx_queues) && (0 == vqs->tx_queues)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
+       if (vlan_proto != htons(ETH_P_8021Q)) {
+               dev_err(&pf->pdev->dev, "VF VLAN protocol is not supported\n");
+               ret = -EPROTONOSUPPORT;
+               goto error_pvid;
        }
+#endif
 
-       i40e_vsi_stop_rings(pf->vsi[vf->lan_vsi_idx]);
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
+               dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
+                       vf_id);
+               ret = -EAGAIN;
+               goto error_pvid;
+       }
 
-error_param:
-       /* send the response to the VF */
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DISABLE_QUEUES,
-                                      aq_ret);
-}
+       if (le16_to_cpu(vsi->info.pvid) == vlanprio)
+               /* duplicate request, so just return success */
+               goto error_pvid;
 
-/**
- * i40e_vc_request_queues_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
- *
- * VFs get a default number of queues but can use this message to request a
- * different number.  If the request is successful, PF will reset the VF and
- * return 0.  If unsuccessful, PF will send message informing VF of number of
- * available queues and return result of sending VF a message.
- **/
-static int i40e_vc_request_queues_msg(struct i40e_vf *vf, u8 *msg, int msglen)
-{
-       struct virtchnl_vf_res_request *vfres =
-               (struct virtchnl_vf_res_request *)msg;
-       int req_pairs = vfres->num_queue_pairs;
-       int cur_pairs = vf->num_queue_pairs;
-       struct i40e_pf *pf = vf->pf;
+       if (i40e_vsi_has_vlans(vsi)) {
+               dev_err(&pf->pdev->dev,
+                       "VF %d has already configured VLAN filters and the administrator is requesting a port VLAN override.\nPlease unload and reload the VF driver for this change to take effect.\n",
+                       vf_id);
+               /* Administrator Error - knock the VF offline until he does
+                * the right thing by reconfiguring his network correctly
+                * and then reloading the VF driver.
+                */
+               i40e_vc_disable_vf(vf);
+               /* During reset the VF got a new VSI, so refresh the pointer. */
+               vsi = pf->vsi[vf->lan_vsi_idx];
+       }
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states))
-               return -EINVAL;
+       /* Locked once because multiple functions below iterate list */
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
 
-       if (req_pairs <= 0) {
-               dev_err(&pf->pdev->dev,
-                       "VF %d tried to request %d queues.  Ignoring.\n",
-                       vf->vf_id, req_pairs);
-       } else if (req_pairs > I40E_MAX_VF_QUEUES) {
-               dev_err(&pf->pdev->dev,
-                       "VF %d tried to request more than %d queues.\n",
-                       vf->vf_id,
-                       I40E_MAX_VF_QUEUES);
-               vfres->num_queue_pairs = I40E_MAX_VF_QUEUES;
-       } else if (req_pairs - cur_pairs > pf->queues_left) {
-               dev_warn(&pf->pdev->dev,
-                        "VF %d requested %d more queues, but only %d left.\n",
-                        vf->vf_id,
-                        req_pairs - cur_pairs,
-                        pf->queues_left);
-               vfres->num_queue_pairs = pf->queues_left + cur_pairs;
-       } else {
-               /* successful request */
-               vf->num_req_queues = req_pairs;
-               i40e_vc_notify_vf_reset(vf);
-               i40e_reset_vf(vf, false);
-               return 0;
+       /* Check for condition where there was already a port VLAN ID
+        * filter set and now it is being deleted by setting it to zero.
+        * Additionally check for the condition where there was a port
+        * VLAN but now there is a new and different port VLAN being set.
+        * Before deleting all the old VLAN filters we must add new ones
+        * with -1 (I40E_VLAN_ANY) or otherwise we're left with all our
+        * MAC addresses deleted.
+        */
+       if ((!(vlan_id || qos) ||
+           vlanprio != le16_to_cpu(vsi->info.pvid)) &&
+           vsi->info.pvid) {
+               ret = i40e_add_vlan_all_mac(vsi, I40E_VLAN_ANY);
+               if (ret) {
+                       dev_info(&vsi->back->pdev->dev,
+                                "add VF VLAN failed, ret=%d aq_err=%d\n", ret,
+                                vsi->back->hw.aq.asq_last_status);
+                       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+                       goto error_pvid;
+               }
+       }
+
+       if (vsi->info.pvid) {
+               /* remove all filters on the old VLAN */
+               i40e_rm_vlan_all_mac(vsi, (le16_to_cpu(vsi->info.pvid) &
+                                          VLAN_VID_MASK));
+       }
+
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+       if (vlan_id || qos)
+               ret = i40e_vsi_add_pvid(vsi, vlanprio);
+       else
+               i40e_vsi_remove_pvid(vsi);
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+
+       if (vlan_id) {
+               dev_info(&pf->pdev->dev, "Setting VLAN %d, QOS 0x%x on VF %d\n",
+                        vlan_id, qos, vf_id);
+
+               /* add new VLAN filter for each MAC */
+               ret = i40e_add_vlan_all_mac(vsi, vlan_id);
+               if (ret) {
+                       dev_info(&vsi->back->pdev->dev,
+                                "add VF VLAN failed, ret=%d aq_err=%d\n", ret,
+                                vsi->back->hw.aq.asq_last_status);
+                       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+                       goto error_pvid;
+               }
+
+               /* remove the previously added non-VLAN MAC filters */
+               i40e_rm_vlan_all_mac(vsi, I40E_VLAN_ANY);
        }
 
-       return i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_REQUEST_QUEUES, 0,
-                                     (u8 *)vfres, sizeof(*vfres));
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+
+       /* Schedule the worker thread to take care of applying changes */
+       i40e_service_event_schedule(vsi->back);
+
+       if (ret) {
+               dev_err(&pf->pdev->dev, "Unable to update VF vsi context\n");
+               goto error_pvid;
+       }
+
+       /* The Port VLAN needs to be saved across resets the same as the
+        * default LAN MAC address.
+        */
+       vf->port_vlan_id = le16_to_cpu(vsi->info.pvid);
+       ret = 0;
+
+error_pvid:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
 }
 
 /**
- * i40e_vc_get_stats_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_ndo_set_vf_bw
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @min_tx_rate: Minimum Tx rate
+ * @max_tx_rate: Maximum Tx rate
  *
- * called from the VF to get vsi stats
+ * configure VF Tx rate
  **/
-static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
+int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
+                      int max_tx_rate)
+#else
+int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int max_tx_rate)
+#endif
 {
-       struct virtchnl_queue_select *vqs =
-           (struct virtchnl_queue_select *)msg;
-       struct i40e_pf *pf = vf->pf;
-       struct i40e_eth_stats stats;
-       i40e_status aq_ret = 0;
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
        struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret = 0;
 
-       memset(&stats, 0, sizeof(struct i40e_eth_stats));
-
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pf->pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
 
-       if (!i40e_vc_isvalid_vsi_id(vf, vqs->vsi_id)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
-       }
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto error;
 
+       vf = &pf->vf[vf_id];
        vsi = pf->vsi[vf->lan_vsi_idx];
-       if (!vsi) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
+       if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
+               dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
+                       vf_id);
+               ret = -EAGAIN;
+               goto error;
        }
-       i40e_update_eth_stats(vsi);
-       stats = vsi->eth_stats;
 
-error_param:
-       /* send the response back to the VF */
-       return i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_STATS, aq_ret,
-                                     (u8 *)&stats, sizeof(stats));
-}
+       ret = i40e_set_bw_limit(vsi, vsi->seid, max_tx_rate);
+       if (ret)
+               goto error;
 
-/* If the VF is not trusted restrict the number of MAC/VLAN it can program */
-#define I40E_VC_MAX_MAC_ADDR_PER_VF 12
-#define I40E_VC_MAX_VLAN_PER_VF 8
+       vf->tx_rate = max_tx_rate;
+error:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
+}
 
 /**
- * i40e_check_vf_permission
- * @vf: pointer to the VF info
- * @macaddr: pointer to the MAC Address being checked
+ * i40e_ndo_enable_vf
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @enable: true to enable & false to disable
  *
- * Check if the VF has permission to add or delete unicast MAC address
- * filters and return error code -EPERM if not.  Then check if the
- * address filter requested is broadcast or zero and if so return
- * an invalid MAC address error code.
+ * enable/disable VF
  **/
-static inline int i40e_check_vf_permission(struct i40e_vf *vf, u8 *macaddr)
+int i40e_ndo_enable_vf(struct net_device *netdev, int vf_id, bool enable)
 {
-       struct i40e_pf *pf = vf->pf;
-       int ret = 0;
-
-       if (is_broadcast_ether_addr(macaddr) ||
-                  is_zero_ether_addr(macaddr)) {
-               dev_err(&pf->pdev->dev, "invalid VF MAC addr %pM\n", macaddr);
-               ret = I40E_ERR_INVALID_MAC_ADDR;
-       } else if (vf->pf_set_mac && !is_multicast_ether_addr(macaddr) &&
-                  !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) &&
-                  !ether_addr_equal(macaddr, vf->default_lan_addr.addr)) {
-               /* If the host VMM administrator has set the VF MAC address
-                * administratively via the ndo_set_vf_mac command then deny
-                * permission to the VF to add or delete unicast MAC addresses.
-                * Unless the VF is privileged and then it can do whatever.
-                * The VF may request to set the MAC address filter already
-                * assigned to it so do not return an error in that case.
-                */
-               dev_err(&pf->pdev->dev,
-                       "VF attempting to override administratively set MAC address, reload the VF driver to resume normal operation\n");
-               ret = -EPERM;
-       } else if ((vf->num_mac >= I40E_VC_MAX_MAC_ADDR_PER_VF) &&
-                  !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) {
-               dev_err(&pf->pdev->dev,
-                       "VF is not trusted, switch the VF to trusted to add more functionality\n");
-               if (pf->vf_base_mode_only)
-                       dev_err(&pf->pdev->dev, "VF %d is in base mode only, cannot add more than %d filters\n",
-                               vf->vf_id, I40E_VC_MAX_MAC_ADDR_PER_VF);
-               ret = -EPERM;
-       }
-       return ret;
+       return -EOPNOTSUPP;
 }
 
 /**
- * i40e_vc_add_mac_addr_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_ndo_get_vf_config
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @ivi: VF configuration structure
  *
- * add guest mac address filter
+ * return VF configuration
  **/
-static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+int i40e_ndo_get_vf_config(struct net_device *netdev,
+                          int vf_id, struct ifla_vf_info *ivi)
 {
-       struct virtchnl_ether_addr_list *al =
-           (struct virtchnl_ether_addr_list *)msg;
-       struct i40e_pf *pf = vf->pf;
-       struct i40e_vsi *vsi = NULL;
-       u16 vsi_id = al->vsi_id;
-       i40e_status ret = 0;
-       int i;
-
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
-           !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
-               ret = I40E_ERR_PARAM;
-               goto error_param;
-       }
-
-       for (i = 0; i < al->num_elements; i++) {
-               ret = i40e_check_vf_permission(vf, al->list[i].addr);
-               if (ret)
-                       goto error_param;
-       }
-       vsi = pf->vsi[vf->lan_vsi_idx];
-
-       /* Lock once, because all function inside for loop accesses VSI's
-        * MAC filter list which needs to be protected using same lock.
-        */
-       spin_lock_bh(&vsi->mac_filter_hash_lock);
-
-       /* add new addresses to the list */
-       for (i = 0; i < al->num_elements; i++) {
-               struct i40e_mac_filter *f;
-
-               f = i40e_find_mac(vsi, al->list[i].addr);
-               if (!f)
-                       f = i40e_add_mac_filter(vsi, al->list[i].addr);
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_vf *vf;
+       int ret = 0;
 
-               if (!f) {
-                       dev_err(&pf->pdev->dev,
-                               "Unable to add MAC filter %pM for VF %d\n",
-                                al->list[i].addr, vf->vf_id);
-                       ret = I40E_ERR_PARAM;
-                       spin_unlock_bh(&vsi->mac_filter_hash_lock);
-                       goto error_param;
-               } else {
-                       vf->num_mac++;
-               }
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pf->pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
-       spin_unlock_bh(&vsi->mac_filter_hash_lock);
 
-       /* program the updated filter list */
-       ret = i40e_sync_vsi_filters(vsi);
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
        if (ret)
-               dev_err(&pf->pdev->dev, "Unable to program VF %d MAC filters, error %d\n",
-                       vf->vf_id, ret);
-
-error_param:
-       /* send the response to the VF */
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ADD_ETH_ADDR,
-                                      ret);
-}
-
-/**
- * i40e_vc_del_mac_addr_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
- *
- * remove guest mac address filter
- **/
-static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
-{
-       struct virtchnl_ether_addr_list *al =
-           (struct virtchnl_ether_addr_list *)msg;
-       struct i40e_pf *pf = vf->pf;
-       struct i40e_vsi *vsi = NULL;
-       u16 vsi_id = al->vsi_id;
-       i40e_status ret = 0;
-       int i;
-
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
-           !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
-               ret = I40E_ERR_PARAM;
                goto error_param;
-       }
 
-       for (i = 0; i < al->num_elements; i++) {
-               if (is_broadcast_ether_addr(al->list[i].addr) ||
-                   is_zero_ether_addr(al->list[i].addr)) {
-                       dev_err(&pf->pdev->dev, "Invalid MAC addr %pM for VF %d\n",
-                               al->list[i].addr, vf->vf_id);
-                       ret = I40E_ERR_INVALID_MAC_ADDR;
-                       goto error_param;
-               }
-       }
+       vf = &pf->vf[vf_id];
+       /* first vsi is always the LAN vsi */
        vsi = pf->vsi[vf->lan_vsi_idx];
+       if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
+               dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
+                       vf_id);
+               ret = -EAGAIN;
+               goto error_param;
+       }
 
-       spin_lock_bh(&vsi->mac_filter_hash_lock);
-       /* delete addresses from the list */
-       for (i = 0; i < al->num_elements; i++)
-               if (i40e_del_mac_filter(vsi, al->list[i].addr)) {
-                       ret = I40E_ERR_INVALID_MAC_ADDR;
-                       spin_unlock_bh(&vsi->mac_filter_hash_lock);
-                       goto error_param;
-               } else {
-                       vf->num_mac--;
-               }
+       ivi->vf = vf_id;
 
-       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+       ether_addr_copy(ivi->mac, vf->default_lan_addr.addr);
 
-       /* program the updated filter list */
-       ret = i40e_sync_vsi_filters(vsi);
-       if (ret)
-               dev_err(&pf->pdev->dev, "Unable to program VF %d MAC filters, error %d\n",
-                       vf->vf_id, ret);
+#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
+       ivi->max_tx_rate = vf->tx_rate;
+       ivi->min_tx_rate = 0;
+#else
+       ivi->tx_rate = vf->tx_rate;
+#endif
+       ivi->vlan = le16_to_cpu(vsi->info.pvid) & I40E_VLAN_MASK;
+       ivi->qos = (le16_to_cpu(vsi->info.pvid) & I40E_PRIORITY_MASK) >>
+                  I40E_VLAN_PRIORITY_SHIFT;
+#ifdef HAVE_NDO_SET_VF_LINK_STATE
+       if (vf->link_forced == false)
+               ivi->linkstate = IFLA_VF_LINK_STATE_AUTO;
+       else if (vf->link_up == true)
+               ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE;
+       else
+               ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE;
+#endif
+#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
+       ivi->spoofchk = vf->spoofchk;
+#endif
+#ifdef HAVE_NDO_SET_VF_TRUST
+       ivi->trusted = vf->trusted;
+#endif /* HAVE_NDO_SET_VF_TRUST */
+       ret = 0;
 
 error_param:
-       /* send the response to the VF */
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DEL_ETH_ADDR,
-                                      ret);
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
 }
 
+#ifdef HAVE_NDO_SET_VF_LINK_STATE
 /**
- * i40e_vc_add_vlan_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_ndo_set_vf_link_state
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @link: required link state
  *
- * program guest vlan id
+ * Set the link state of a specified VF, regardless of physical link state
  **/
-static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link)
 {
-       struct virtchnl_vlan_filter_list *vfl =
-           (struct virtchnl_vlan_filter_list *)msg;
-       struct i40e_pf *pf = vf->pf;
-       struct i40e_vsi *vsi = NULL;
-       u16 vsi_id = vfl->vsi_id;
-       i40e_status aq_ret = 0;
-       int i;
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_link_status *ls = &pf->hw.phy.link_info;
+       struct virtchnl_pf_event pfe;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_vf *vf;
+       int abs_vf_id;
+       int ret = 0;
 
-       if ((vf->num_vlan >= I40E_VC_MAX_VLAN_PER_VF) &&
-           !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) {
-               dev_err(&pf->pdev->dev,
-                       "VF is not trusted, switch the VF to trusted to add more VLAN addresses\n");
-               if (pf->vf_base_mode_only)
-                       dev_err(&pf->pdev->dev, "VF %d is in base mode only, cannot add more than %d vlans\n",
-                               vf->vf_id, I40E_VC_MAX_VLAN_PER_VF);
-               goto error_param;
-       }
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
-           !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pf->pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
 
-       for (i = 0; i < vfl->num_elements; i++) {
-               if (vfl->vlan_id[i] > I40E_MAX_VLANID) {
-                       aq_ret = I40E_ERR_PARAM;
-                       dev_err(&pf->pdev->dev,
-                               "invalid VF VLAN id %d\n", vfl->vlan_id[i]);
-                       goto error_param;
-               }
-       }
-       vsi = pf->vsi[vf->lan_vsi_idx];
-       if (vsi->info.pvid) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
+       /* validate the request */
+       if (vf_id >= pf->num_alloc_vfs) {
+               dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
+               ret = -EINVAL;
+               goto error_out;
        }
 
-       i40e_vlan_stripping_enable(vsi);
-       for (i = 0; i < vfl->num_elements; i++) {
-               /* add new VLAN filter */
-               int ret = i40e_vsi_add_vlan(vsi, vfl->vlan_id[i]);
-               if (!ret)
-                       vf->num_vlan++;
+       vf = &pf->vf[vf_id];
+       abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
 
-               if (test_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states))
-                       i40e_aq_set_vsi_uc_promisc_on_vlan(&pf->hw, vsi->seid,
-                                                          true,
-                                                          vfl->vlan_id[i],
-                                                          NULL);
-               if (test_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states))
-                       i40e_aq_set_vsi_mc_promisc_on_vlan(&pf->hw, vsi->seid,
-                                                          true,
-                                                          vfl->vlan_id[i],
-                                                          NULL);
+       pfe.event = VIRTCHNL_EVENT_LINK_CHANGE;
+       pfe.severity = PF_EVENT_SEVERITY_INFO;
 
-               if (ret)
-                       dev_err(&pf->pdev->dev,
-                               "Unable to add VLAN filter %d for VF %d, error %d\n",
-                               vfl->vlan_id[i], vf->vf_id, ret);
+       switch (link) {
+       case IFLA_VF_LINK_STATE_AUTO:
+               vf->link_forced = false;
+               pfe.event_data.link_event.link_status =
+                       ls->link_info & I40E_AQ_LINK_UP;
+               pfe.event_data.link_event.link_speed =
+                       i40e_virtchnl_link_speed(ls->link_speed);
+               break;
+       case IFLA_VF_LINK_STATE_ENABLE:
+               vf->link_forced = true;
+               vf->link_up = true;
+               pfe.event_data.link_event.link_status = true;
+               pfe.event_data.link_event.link_speed = I40E_LINK_SPEED_40GB;
+               break;
+       case IFLA_VF_LINK_STATE_DISABLE:
+               vf->link_forced = true;
+               vf->link_up = false;
+               pfe.event_data.link_event.link_status = false;
+               pfe.event_data.link_event.link_speed = 0;
+               break;
+       default:
+               ret = -EINVAL;
+               goto error_out;
        }
+       /* Notify the VF of its new link state */
+       i40e_aq_send_msg_to_vf(hw, abs_vf_id, VIRTCHNL_OP_EVENT,
+                              I40E_SUCCESS, (u8 *)&pfe, sizeof(pfe), NULL);
 
-error_param:
-       /* send the response to the VF */
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ADD_VLAN, aq_ret);
+error_out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
 }
 
+#endif /* HAVE_NDO_SET_VF_LINK_STATE */
+#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
 /**
- * i40e_vc_remove_vlan_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_ndo_set_vf_spoofchk
+ * @netdev: network interface device structure
+ * @vf_id: VF identifier
+ * @enable: flag to enable or disable feature
  *
- * remove programmed guest vlan id
+ * Enable or disable VF spoof checking
  **/
-static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable)
 {
-       struct virtchnl_vlan_filter_list *vfl =
-           (struct virtchnl_vlan_filter_list *)msg;
-       struct i40e_pf *pf = vf->pf;
-       struct i40e_vsi *vsi = NULL;
-       u16 vsi_id = vfl->vsi_id;
-       i40e_status aq_ret = 0;
-       int i;
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_vsi_context ctxt;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_vf *vf;
+       int ret = 0;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
-           !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pf->pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
 
-       for (i = 0; i < vfl->num_elements; i++) {
-               if (vfl->vlan_id[i] > I40E_MAX_VLANID) {
-                       aq_ret = I40E_ERR_PARAM;
-                       goto error_param;
-               }
+       /* validate the request */
+       if (vf_id >= pf->num_alloc_vfs) {
+               dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
+               ret = -EINVAL;
+               goto out;
        }
 
-       vsi = pf->vsi[vf->lan_vsi_idx];
-       if (vsi->info.pvid) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
+       vf = &(pf->vf[vf_id]);
+       if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
+               dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
+                       vf_id);
+               ret = -EAGAIN;
+               goto out;
        }
 
-       for (i = 0; i < vfl->num_elements; i++) {
-               i40e_vsi_kill_vlan(vsi, vfl->vlan_id[i]);
-               vf->num_vlan--;
+       if (enable == vf->spoofchk)
+               goto out;
 
-               if (test_bit(I40E_VF_STATE_UC_PROMISC, &vf->vf_states))
-                       i40e_aq_set_vsi_uc_promisc_on_vlan(&pf->hw, vsi->seid,
-                                                          false,
-                                                          vfl->vlan_id[i],
-                                                          NULL);
-               if (test_bit(I40E_VF_STATE_MC_PROMISC, &vf->vf_states))
-                       i40e_aq_set_vsi_mc_promisc_on_vlan(&pf->hw, vsi->seid,
-                                                          false,
-                                                          vfl->vlan_id[i],
-                                                          NULL);
+       vf->spoofchk = enable;
+       memset(&ctxt, 0, sizeof(ctxt));
+       ctxt.seid = pf->vsi[vf->lan_vsi_idx]->seid;
+       ctxt.pf_num = pf->hw.pf_id;
+       ctxt.info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SECURITY_VALID);
+       if (enable)
+               ctxt.info.sec_flags |= (I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK |
+                                       I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK);
+       ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
+       if (ret) {
+               dev_err(&pf->pdev->dev, "Error %d updating VSI parameters\n",
+                       ret);
+               ret = -EIO;
        }
-
-error_param:
-       /* send the response to the VF */
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DEL_VLAN, aq_ret);
+out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
 }
 
+#endif /* HAVE_VF_SPOOFCHK_CONFIGURE */
+#ifdef HAVE_NDO_SET_VF_TRUST
 /**
- * i40e_vc_iwarp_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_ndo_set_vf_trust
+ * @netdev: network interface device structure of the pf
+ * @vf_id: VF identifier
+ * @setting: trust setting
  *
- * called from the VF for the iwarp msgs
+ * Enable or disable VF trust setting
  **/
-static int i40e_vc_iwarp_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+int i40e_ndo_set_vf_trust(struct net_device *netdev, int vf_id, bool setting)
 {
-       struct i40e_pf *pf = vf->pf;
-       int abs_vf_id = vf->vf_id + (int)pf->hw.func_caps.vf_base_id;
-       i40e_status aq_ret = I40E_SUCCESS;
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_vf *vf;
+       int ret = 0;
+
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pf->pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
+       }
+
+       /* validate the request */
+       if (vf_id >= pf->num_alloc_vfs) {
+               dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+               dev_err(&pf->pdev->dev, "Trusted VF not supported in MFP mode.\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       vf = &pf->vf[vf_id];
+
+       /* if vf is in base mode, make it untrusted */
+       if (pf->vf_base_mode_only)
+               setting = false;
+       if (setting == vf->trusted)
+               goto out;
+
+       vf->trusted = setting;
+       i40e_vc_disable_vf(vf);
+       dev_info(&pf->pdev->dev, "VF %u is now %strusted\n",
+                vf_id, setting ? "" : "un");
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
-           !test_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
+#ifdef __TC_MQPRIO_MODE_MAX
+       if (vf->adq_enabled) {
+               if (!vf->trusted) {
+                       dev_info(&pf->pdev->dev,
+                                "VF %u no longer Trusted, deleting all cloud filters\n",
+                                vf_id);
+                       i40e_del_all_cloud_filters(vf);
+               }
        }
+#endif /* __TC_MQPRIO_MODE_MAX */
 
-       i40e_notify_client_of_vf_msg(pf->vsi[pf->lan_vsi], abs_vf_id,
-                                    msg, msglen);
-
-error_param:
-       /* send the response to the VF */
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_IWARP,
-                                      aq_ret);
+out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
 }
+#endif /* HAVE_NDO_SET_VF_TRUST */
+#endif /* IFLA_VF_MAX */
 
 /**
- * i40e_vc_iwarp_qvmap_msg
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
- * @config: config qvmap or release it
+ * i40e_get_vlan_anti_spoof
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @enable: on success, true if enabled, false if not
  *
- * called from the VF for the iwarp msgs
+ * This function queries if VLAN anti spoof is enabled or not
+ *
+ * Returns 0 on success, negative on failure.
  **/
-static int i40e_vc_iwarp_qvmap_msg(struct i40e_vf *vf, u8 *msg, u16 msglen,
-                                  bool config)
+static int i40e_get_vlan_anti_spoof(struct pci_dev *pdev, int vf_id,
+                                   bool *enable)
 {
-       struct virtchnl_iwarp_qvlist_info *qvlist_info =
-                               (struct virtchnl_iwarp_qvlist_info *)msg;
-       i40e_status aq_ret = 0;
-
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
-           !test_bit(I40E_VF_STATE_IWARPENA, &vf->vf_states)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto error_param;
-       }
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret;
 
-       if (config) {
-               if (i40e_config_iwarp_qvlist(vf, qvlist_info))
-                       aq_ret = I40E_ERR_PARAM;
-       } else {
-               i40e_release_iwarp_qvlist(vf);
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
 
-error_param:
-       /* send the response to the VF */
-       return i40e_vc_send_resp_to_vf(vf,
-                              config ? VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP :
-                              VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP,
-                              aq_ret);
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       if ((vsi->info.valid_sections &
+           CPU_TO_LE16(I40E_AQ_VSI_PROP_SECURITY_VALID)) &&
+           (vsi->info.sec_flags & I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK))
+               *enable = true;
+       else
+               *enable = false;
+out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
 }
 
 /**
- * i40e_vc_config_rss_key
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_set_vlan_anti_spoof
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @enable: enable/disable
  *
- * Configure the VF's RSS key
+ * This function enables or disables VLAN anti-spoof
+ *
+ * Returns 0 on success, negative on failure
  **/
-static int i40e_vc_config_rss_key(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_set_vlan_anti_spoof(struct pci_dev *pdev, int vf_id,
+                                   const bool enable)
 {
-       struct virtchnl_rss_key *vrk =
-               (struct virtchnl_rss_key *)msg;
-       struct i40e_pf *pf = vf->pf;
-       struct i40e_vsi *vsi = NULL;
-       u16 vsi_id = vrk->vsi_id;
-       i40e_status aq_ret = 0;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       u8 sec_flag;
+       int ret;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
-           !i40e_vc_isvalid_vsi_id(vf, vsi_id) ||
-           (vrk->key_len != I40E_HKEY_ARRAY_SIZE)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto err;
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
-
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto out;
+       vf = &pf->vf[vf_id];
        vsi = pf->vsi[vf->lan_vsi_idx];
-       aq_ret = i40e_config_rss(vsi, vrk->key, NULL, 0);
-err:
-       /* send the response to the VF */
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_KEY,
-                                      aq_ret);
+       sec_flag = I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK;
+       ret = i40e_set_spoof_settings(vsi, sec_flag, enable);
+       if (!ret)
+               vf->vlan_anti_spoof = enable;
+out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
 }
 
 /**
- * i40e_vc_config_rss_lut
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_get_mac_anti_spoof
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @enable: on success, true if enabled, false if not
  *
- * Configure the VF's RSS LUT
+ * This function queries if MAC anti spoof is enabled or not.
+ *
+ * Returns 0 on success, negative error on failure.
  **/
-static int i40e_vc_config_rss_lut(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_get_mac_anti_spoof(struct pci_dev *pdev, int vf_id,
+                                  bool *enable)
 {
-       struct virtchnl_rss_lut *vrl =
-               (struct virtchnl_rss_lut *)msg;
-       struct i40e_pf *pf = vf->pf;
-       struct i40e_vsi *vsi = NULL;
-       u16 vsi_id = vrl->vsi_id;
-       i40e_status aq_ret = 0;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states) ||
-           !i40e_vc_isvalid_vsi_id(vf, vsi_id) ||
-           (vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto err;
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
 
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto out;
+       vf = &pf->vf[vf_id];
        vsi = pf->vsi[vf->lan_vsi_idx];
-       aq_ret = i40e_config_rss(vsi, NULL, vrl->lut, I40E_VF_HLUT_ARRAY_SIZE);
-       /* send the response to the VF */
-err:
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_CONFIG_RSS_LUT,
-                                      aq_ret);
+       if ((vsi->info.valid_sections &
+           CPU_TO_LE16(I40E_AQ_VSI_PROP_SECURITY_VALID)) &&
+           (vsi->info.sec_flags & I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK))
+               *enable = true;
+       else
+               *enable = false;
+out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
 }
 
 /**
- * i40e_vc_get_rss_hena
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_set_mac_anti_spoof
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @enable: enable/disable
  *
- * Return the RSS HENA bits allowed by the hardware
+ * This function enables or disables MAC anti-spoof
+ *
+ * Returns 0 on success, negative on failure
  **/
-static int i40e_vc_get_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_set_mac_anti_spoof(struct pci_dev *pdev, int vf_id,
+                                  const bool enable)
 {
-       struct virtchnl_rss_hena *vrh = NULL;
-       struct i40e_pf *pf = vf->pf;
-       i40e_status aq_ret = 0;
-       int len = 0;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       u8 sec_flag;
+       int ret;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto err;
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
-       len = sizeof(struct virtchnl_rss_hena);
 
-       vrh = kzalloc(len, GFP_KERNEL);
-       if (!vrh) {
-               aq_ret = I40E_ERR_NO_MEMORY;
-               len = 0;
-               goto err;
-       }
-       vrh->hena = i40e_pf_get_default_rss_hena(pf);
-err:
-       /* send the response back to the VF */
-       aq_ret = i40e_vc_send_msg_to_vf(vf, VIRTCHNL_OP_GET_RSS_HENA_CAPS,
-                                       aq_ret, (u8 *)vrh, len);
-       kfree(vrh);
-       return aq_ret;
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       sec_flag = I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
+       ret = i40e_set_spoof_settings(vsi, sec_flag, enable);
+       if (!ret)
+               vf->mac_anti_spoof = enable;
+out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
 }
 
 /**
- * i40e_vc_set_rss_hena
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_get_trunk - Gets the configured VLAN filters
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @trunk_vlans: trunk vlans
  *
- * Set the RSS HENA bits for the VF
+ * Gets the active trunk vlans
+ *
+ * Returns the number of active vlans filters on success,
+ * negative on failure
  **/
-static int i40e_vc_set_rss_hena(struct i40e_vf *vf, u8 *msg, u16 msglen)
+static int i40e_get_trunk(struct pci_dev *pdev, int vf_id,
+                         unsigned long *trunk_vlans)
 {
-       struct virtchnl_rss_hena *vrh =
-               (struct virtchnl_rss_hena *)msg;
-       struct i40e_pf *pf = vf->pf;
-       struct i40e_hw *hw = &pf->hw;
-       i40e_status aq_ret = 0;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vf *vf;
+       int ret;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto err;
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
-       i40e_write_rx_ctl(hw, I40E_VFQF_HENA1(0, vf->vf_id), (u32)vrh->hena);
-       i40e_write_rx_ctl(hw, I40E_VFQF_HENA1(1, vf->vf_id),
-                         (u32)(vrh->hena >> 32));
 
-       /* send the response to the VF */
-err:
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_SET_RSS_HENA, aq_ret);
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto out;
+       vf = &pf->vf[vf_id];
+       bitmap_copy(trunk_vlans, vf->trunk_vlans, VLAN_N_VID);
+       ret = bitmap_weight(trunk_vlans, VLAN_N_VID);
+out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
 }
 
 /**
- * i40e_vc_enable_vlan_stripping
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
+ * i40e_set_trunk - Configure VLAN filters
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @vlan_bitmap: vlans to filter on
  *
- * Enable vlan header stripping for the VF
+ * Applies the VLAN filters
+ *
+ * Returns 0 on success, negative on failure
  **/
-static int i40e_vc_enable_vlan_stripping(struct i40e_vf *vf, u8 *msg,
-                                        u16 msglen)
+static int i40e_set_trunk(struct pci_dev *pdev, int vf_id,
+                         const unsigned long *vlan_bitmap)
 {
-       struct i40e_vsi *vsi = vf->pf->vsi[vf->lan_vsi_idx];
-       i40e_status aq_ret = 0;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret;
+       u16 vid;
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto err;
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
 
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
        i40e_vlan_stripping_enable(vsi);
 
-       /* send the response to the VF */
-err:
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_ENABLE_VLAN_STRIPPING,
-                                      aq_ret);
-}
-
-/**
- * i40e_vc_disable_vlan_stripping
- * @vf: pointer to the VF info
- * @msg: pointer to the msg buffer
- * @msglen: msg length
- *
- * Disable vlan header stripping for the VF
- **/
-static int i40e_vc_disable_vlan_stripping(struct i40e_vf *vf, u8 *msg,
-                                         u16 msglen)
-{
-       struct i40e_vsi *vsi = vf->pf->vsi[vf->lan_vsi_idx];
-       i40e_status aq_ret = 0;
+       /* Add vlans */
+       for_each_set_bit(vid, vlan_bitmap, VLAN_N_VID) {
+               if (!test_bit(vid, vf->trunk_vlans)) {
+                       ret = i40e_vsi_add_vlan(vsi, vid);
+                       if (ret)
+                               goto out;
+                       }
 
-       if (!test_bit(I40E_VF_STATE_ACTIVE, &vf->vf_states)) {
-               aq_ret = I40E_ERR_PARAM;
-               goto err;
+               /* VLAN 0 filters are added by default */
+               vf->allow_untagged = true;
        }
 
-       i40e_vlan_stripping_disable(vsi);
-
-       /* send the response to the VF */
-err:
-       return i40e_vc_send_resp_to_vf(vf, VIRTCHNL_OP_DISABLE_VLAN_STRIPPING,
-                                      aq_ret);
-}
+       /* If deleting all vlan filters, check if we have VLAN 0 filters
+        * existing. If we don't, add filters to allow all traffic i.e
+        * VLAN tag = -1 before deleting all filters because the in the
+        * delete all filters flow, we check if there are VLAN 0 filters
+        * and then replace them with filters of VLAN id = -1
+        */
+       if (!bitmap_weight(vlan_bitmap, VLAN_N_VID) && !vf->allow_untagged)
+               i40e_vsi_add_vlan(vsi, I40E_VLAN_ANY);
 
-/**
- * i40e_vc_process_vf_msg
- * @pf: pointer to the PF structure
- * @vf_id: source VF id
- * @msg: pointer to the msg buffer
- * @msglen: msg length
- * @msghndl: msg handle
+       /* Del vlans */
+       for_each_set_bit(vid, vf->trunk_vlans, VLAN_N_VID) {
+               if (!test_bit(vid, vlan_bitmap))
+                       i40e_vsi_kill_vlan(vsi, vid);
+       }
+       /* Copy over the updated bitmap */
+       bitmap_copy(vf->trunk_vlans, vlan_bitmap, VLAN_N_VID);
+out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
+}
+
+/**
+ * i40e_get_mirror - Gets the configured  VLAN mirrors
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @mirror_vlans: mirror vlans
  *
- * called from the common aeq/arq handler to
- * process request from VF
+ * Gets the active mirror vlans
+ *
+ * Returns the number of active mirror vlans on success,
+ * negative on failure
  **/
-int i40e_vc_process_vf_msg(struct i40e_pf *pf, s16 vf_id, u32 v_opcode,
-                          u32 v_retval, u8 *msg, u16 msglen)
+static int i40e_get_mirror(struct pci_dev *pdev, int vf_id,
+                          unsigned long *mirror_vlans)
 {
-       struct i40e_hw *hw = &pf->hw;
-       int local_vf_id = vf_id - (s16)hw->func_caps.vf_base_id;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
        struct i40e_vf *vf;
        int ret;
 
-       pf->vf_aq_requests++;
-       if (local_vf_id >= pf->num_alloc_vfs)
-               return -EINVAL;
-       vf = &(pf->vf[local_vf_id]);
-
-       /* Check if VF is disabled. */
-       if (test_bit(I40E_VF_STATE_DISABLED, &vf->vf_states))
-               return I40E_ERR_PARAM;
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
+       }
 
-       /* perform basic checks on the msg */
-       ret = virtchnl_vc_validate_vf_msg(&vf->vf_ver, v_opcode, msg, msglen);
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto out;
+       vf = &pf->vf[vf_id];
+       bitmap_copy(mirror_vlans, vf->mirror_vlans, VLAN_N_VID);
+       ret = bitmap_weight(mirror_vlans, VLAN_N_VID);
+out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
+}
 
-       /* perform additional checks specific to this driver */
-       if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_KEY) {
-               struct virtchnl_rss_key *vrk = (struct virtchnl_rss_key *)msg;
+/**
+ * i40e_set_mirror - Configure VLAN mirrors
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @vlan_bitmap: vlans to configure as mirrors
+ *
+ * Configures the mirror vlans
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_set_mirror(struct pci_dev *pdev, int vf_id,
+                          const unsigned long *vlan_bitmap)
+{
+       u16 vid, sw_seid, dst_seid, rule_id, rule_type;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       int ret = 0, num = 0, cnt = 0, add = 0;
+       u16 rules_used, rules_free;
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       __le16 *mr_list;
 
-               if (vrk->key_len != I40E_HKEY_ARRAY_SIZE)
-                       ret = -EINVAL;
-       } else if (v_opcode == VIRTCHNL_OP_CONFIG_RSS_LUT) {
-               struct virtchnl_rss_lut *vrl = (struct virtchnl_rss_lut *)msg;
+       DECLARE_BITMAP(num_vlans, VLAN_N_VID);
 
-               if (vrl->lut_entries != I40E_VF_HLUT_ARRAY_SIZE)
-                       ret = -EINVAL;
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
 
-       if (ret) {
-               i40e_vc_send_resp_to_vf(vf, v_opcode, I40E_ERR_PARAM);
-               dev_err(&pf->pdev->dev, "Invalid message from VF %d, opcode %d, len %d\n",
-                       local_vf_id, v_opcode, msglen);
-               switch (ret) {
-               case VIRTCHNL_ERR_PARAM:
-                       return -EPERM;
-               default:
-                       return -EINVAL;
-               }
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       sw_seid = vsi->uplink_seid;
+       dst_seid = vsi->seid;
+       rule_type = I40E_AQC_MIRROR_RULE_TYPE_VLAN;
+       bitmap_xor(num_vlans, vf->mirror_vlans, vlan_bitmap, VLAN_N_VID);
+       cnt = bitmap_weight(num_vlans, VLAN_N_VID);
+       if (!cnt)
+               goto out;
+       mr_list = kcalloc(cnt, sizeof(__le16), GFP_KERNEL);
+       if (!mr_list) {
+               ret = -ENOMEM;
+               goto out;
        }
 
-       switch (v_opcode) {
-       case VIRTCHNL_OP_VERSION:
-               ret = i40e_vc_get_version_msg(vf, msg);
-               break;
-       case VIRTCHNL_OP_GET_VF_RESOURCES:
-               ret = i40e_vc_get_vf_resources_msg(vf, msg);
-               i40e_vc_notify_vf_link_state(vf);
-               break;
-       case VIRTCHNL_OP_RESET_VF:
-               i40e_vc_reset_vf_msg(vf);
-               ret = 0;
-               break;
-       case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
-               ret = i40e_vc_config_promiscuous_mode_msg(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
-               ret = i40e_vc_config_queues_msg(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_CONFIG_IRQ_MAP:
-               ret = i40e_vc_config_irq_map_msg(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_ENABLE_QUEUES:
-               ret = i40e_vc_enable_queues_msg(vf, msg, msglen);
-               i40e_vc_notify_vf_link_state(vf);
-               break;
-       case VIRTCHNL_OP_DISABLE_QUEUES:
-               ret = i40e_vc_disable_queues_msg(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_ADD_ETH_ADDR:
-               ret = i40e_vc_add_mac_addr_msg(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_DEL_ETH_ADDR:
-               ret = i40e_vc_del_mac_addr_msg(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_ADD_VLAN:
-               ret = i40e_vc_add_vlan_msg(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_DEL_VLAN:
-               ret = i40e_vc_remove_vlan_msg(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_GET_STATS:
-               ret = i40e_vc_get_stats_msg(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_IWARP:
-               ret = i40e_vc_iwarp_msg(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP:
-               ret = i40e_vc_iwarp_qvmap_msg(vf, msg, msglen, true);
-               break;
-       case VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP:
-               ret = i40e_vc_iwarp_qvmap_msg(vf, msg, msglen, false);
-               break;
-       case VIRTCHNL_OP_CONFIG_RSS_KEY:
-               ret = i40e_vc_config_rss_key(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_CONFIG_RSS_LUT:
-               ret = i40e_vc_config_rss_lut(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_GET_RSS_HENA_CAPS:
-               ret = i40e_vc_get_rss_hena(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_SET_RSS_HENA:
-               ret = i40e_vc_set_rss_hena(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING:
-               ret = i40e_vc_enable_vlan_stripping(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_DISABLE_VLAN_STRIPPING:
-               ret = i40e_vc_disable_vlan_stripping(vf, msg, msglen);
-               break;
-       case VIRTCHNL_OP_REQUEST_QUEUES:
-               ret = i40e_vc_request_queues_msg(vf, msg, msglen);
-               break;
-
-       case VIRTCHNL_OP_UNKNOWN:
-       default:
-               dev_err(&pf->pdev->dev, "Unsupported opcode %d from VF %d\n",
-                       v_opcode, local_vf_id);
-               ret = i40e_vc_send_resp_to_vf(vf, v_opcode,
-                                             I40E_ERR_NOT_IMPLEMENTED);
-               break;
+       /* figure out if adding or deleting */
+       bitmap_and(num_vlans, vlan_bitmap, num_vlans, VLAN_N_VID);
+       add = bitmap_weight(num_vlans, VLAN_N_VID);
+       if (add) {
+               /* Add mirrors */
+               for_each_set_bit(vid, vlan_bitmap, VLAN_N_VID) {
+                       if (!test_bit(vid, vf->mirror_vlans)) {
+                               mr_list[num] = CPU_TO_LE16(vid);
+                               num++;
+                       }
+               }
+               ret = i40e_aq_add_mirrorrule(&pf->hw, sw_seid,
+                                            rule_type, dst_seid,
+                                            cnt, mr_list, NULL,
+                                            &rule_id, &rules_used,
+                                            &rules_free);
+               if (ret)
+                       goto err_free;
+               vf->vlan_rule_id = rule_id;
+       } else {
+               /* Del mirrors */
+               for_each_set_bit(vid, vf->mirror_vlans, VLAN_N_VID) {
+                       if (!test_bit(vid, vlan_bitmap)) {
+                               mr_list[num] = CPU_TO_LE16(vid);
+                               num++;
+                       }
+               }
+               ret = i40e_aq_delete_mirrorrule(&pf->hw, sw_seid, rule_type,
+                                               vf->vlan_rule_id, cnt, mr_list,
+                                               NULL, &rules_used,
+                                               &rules_free);
+               if (ret)
+                       goto err_free;
        }
 
+       /* Copy over the updated bitmap */
+       bitmap_copy(vf->mirror_vlans, vlan_bitmap, VLAN_N_VID);
+err_free:
+       kfree(mr_list);
+out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
        return ret;
 }
 
 /**
- * i40e_vc_process_vflr_event
- * @pf: pointer to the PF structure
+ * i40e_get_allow_untagged
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @on: on or off
  *
- * called from the vlfr irq handler to
- * free up VF resources and state variables
+ * This functions checks if the untagged packets
+ * are allowed or not. By default, allow_untagged is on
+ * when VLAN filters are present on the VF.
+ *
+ * Returns 0 on success, negative on failure
  **/
-int i40e_vc_process_vflr_event(struct i40e_pf *pf)
+static int i40e_get_allow_untagged(struct pci_dev *pdev, int vf_id,
+                                  bool *on)
 {
-       struct i40e_hw *hw = &pf->hw;
-       u32 reg, reg_idx, bit_idx;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
        struct i40e_vf *vf;
-       int vf_id;
-
-       if (!test_bit(__I40E_VFLR_EVENT_PENDING, pf->state))
-               return 0;
-
-       /* Re-enable the VFLR interrupt cause here, before looking for which
-        * VF got reset. Otherwise, if another VF gets a reset while the
-        * first one is being processed, that interrupt will be lost, and
-        * that VF will be stuck in reset forever.
-        */
-       reg = rd32(hw, I40E_PFINT_ICR0_ENA);
-       reg |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
-       wr32(hw, I40E_PFINT_ICR0_ENA, reg);
-       i40e_flush(hw);
+       int ret;
 
-       clear_bit(__I40E_VFLR_EVENT_PENDING, pf->state);
-       for (vf_id = 0; vf_id < pf->num_alloc_vfs; vf_id++) {
-               reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32;
-               bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32;
-               /* read GLGEN_VFLRSTAT register to find out the flr VFs */
-               vf = &pf->vf[vf_id];
-               reg = rd32(hw, I40E_GLGEN_VFLRSTAT(reg_idx));
-               if (reg & BIT(bit_idx))
-                       /* i40e_reset_vf will clear the bit in GLGEN_VFLRSTAT */
-                       i40e_reset_vf(vf, true);
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
 
-       return 0;
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto out;
+       vf = &pf->vf[vf_id];
+       *on = vf->allow_untagged;
+out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
 }
 
-#ifdef IFLA_VF_MAX
-
 /**
- * i40e_ndo_set_vf_mac
- * @netdev: network interface device structure
+ * i40e_set_allow_untagged
+ * @pdev: PCI device information struct
  * @vf_id: VF identifier
- * @mac: mac address
+ * @on: on or off
  *
- * program VF mac address
+ * This functions allows or stops untagged packets
+ * on the VF. By default, allow_untagged is on when
+ * VLAN filters are present on the VF.
+ *
+ * Returns 0 on success, negative on failure
  **/
-int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
+static int i40e_set_allow_untagged(struct pci_dev *pdev, int vf_id,
+                                  const bool on)
 {
-       struct i40e_netdev_priv *np = netdev_priv(netdev);
-       struct i40e_vsi *vsi = np->vsi;
-       struct i40e_pf *pf = vsi->back;
-       struct i40e_mac_filter *f;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
        struct i40e_vf *vf;
-       int ret = 0;
-       struct hlist_node *h;
-       int bkt;
+       int ret;
 
-       /* validate the request */
-       if (vf_id >= pf->num_alloc_vfs) {
-               dev_err(&pf->pdev->dev,
-                       "Invalid VF Identifier %d\n", vf_id);
-               ret = -EINVAL;
-               goto error_param;
+       if (test_and_set_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state)) {
+               dev_warn(&pdev->dev, "Unable to configure VFs, other operation is pending.\n");
+               return -EAGAIN;
        }
 
-       vf = &(pf->vf[vf_id]);
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto out;
+       vf = &pf->vf[vf_id];
        vsi = pf->vsi[vf->lan_vsi_idx];
-       if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
-               dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
-                       vf_id);
-               ret = -EAGAIN;
-               goto error_param;
-       }
-
-       if (is_multicast_ether_addr(mac)) {
-               dev_err(&pf->pdev->dev,
-                       "Invalid Ethernet address %pM for VF %d\n", mac, vf_id);
+       if (vsi->info.pvid) {
                ret = -EINVAL;
-               goto error_param;
+               goto out;
        }
-
-       /* Lock once because below invoked function add/del_filter requires
-        * mac_filter_hash_lock to be held
-        */
        spin_lock_bh(&vsi->mac_filter_hash_lock);
-
-       /* delete the temporary mac address */
-       if (!is_zero_ether_addr(vf->default_lan_addr.addr))
-               i40e_del_mac_filter(vsi, vf->default_lan_addr.addr);
-
-       /* Delete all the filters for this VSI - we're going to kill it
-        * anyway.
-        */
-       hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist)
-               __i40e_del_filter(vsi, f);
-
-       spin_unlock_bh(&vsi->mac_filter_hash_lock);
-
-       /* program mac filter */
-       if (i40e_sync_vsi_filters(vsi)) {
-               dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
-               ret = -EIO;
-               goto error_param;
-       }
-       ether_addr_copy(vf->default_lan_addr.addr, mac);
-
-       if (is_zero_ether_addr(mac)) {
-               vf->pf_set_mac = false;
-               dev_info(&pf->pdev->dev, "Removing MAC on VF %d\n", vf_id);
+       if (!on) {
+               i40e_rm_vlan_all_mac(vsi, 0);
+               i40e_service_event_schedule(vsi->back);
        } else {
-               vf->pf_set_mac = true;
-               dev_info(&pf->pdev->dev, "Setting MAC %pM on VF %d\n",
-                        mac, vf_id);
+               ret = i40e_add_vlan_all_mac(vsi, 0);
+               i40e_service_event_schedule(vsi->back);
        }
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+       if (!ret)
+               vf->allow_untagged = on;
+out:
+       clear_bit(__I40E_VIRTCHNL_OP_PENDING, pf->state);
+       return ret;
+}
 
-       /* Force the VF driver stop so it has to reload with new MAC address */
-       i40e_vc_disable_vf(vf);
-       dev_info(&pf->pdev->dev, "Reload the VF driver to make this change effective.\n");
+/**
+ * i40e_get_loopback
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @enable: enable or disable
+ *
+ * This function checks loopback is enabled
+ *
+ * Returns 1 if enabled, 0 if disabled
+ **/
+static int i40e_get_loopback(struct pci_dev *pdev, int vf_id, bool *enable)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vf *vf;
+       int ret = 0;
 
-error_param:
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       *enable = vf->loopback;
+err_out:
        return ret;
 }
 
 /**
- * i40e_vsi_has_vlans - True if VSI has configured VLANs
- * @vsi: pointer to the vsi
+ * i40e_set_loopback
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @enable: enable or disable
  *
- * Check if a VSI has configured any VLANs. False if we have a port VLAN or if
- * we have no configured VLANs. Do not call while holding the
- * mac_filter_hash_lock.
- */
-static bool i40e_vsi_has_vlans(struct i40e_vsi *vsi)
+ * This function enables or disables loopback
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_set_loopback(struct pci_dev *pdev, int vf_id,
+                            const bool enable)
 {
-       bool have_vlans;
-
-       /* If we have a port VLAN, then the VSI cannot have any VLANs
-        * configured, as all MAC/VLAN filters will be assigned to the PVID.
-        */
-       if (vsi->info.pvid)
-               return false;
-
-       /* Since we don't have a PVID, we know that if the device is in VLAN
-        * mode it must be because of a VLAN filter configured on this VSI.
-        */
-       spin_lock_bh(&vsi->mac_filter_hash_lock);
-       have_vlans = i40e_is_vsi_in_vlan(vsi);
-       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret;
 
-       return have_vlans;
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       ret = i40e_configure_vf_loopback(vsi, vf_id, enable);
+       if (!ret)
+               vf->loopback = enable;
+err_out:
+       return ret;
 }
 
-#ifdef IFLA_VF_VLAN_INFO_MAX
 /**
- * i40e_ndo_set_vf_port_vlan
- * @netdev: network interface device structure
+ * i40e_get_vlan_strip
+ * @pdev: PCI device information struct
  * @vf_id: VF identifier
- * @vlan_id: mac address
- * @qos: priority setting
- * @vlan_proto: vlan protocol
+ * @enable: enable or disable
  *
- * program VF vlan id and/or qos
+ * This function checks if vlan stripping is enabled or not
+ *
+ * Returns 0 on success, negative on failure
  **/
-int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
-                             u16 vlan_id, u8 qos, __be16 vlan_proto)
-#else
+static int i40e_get_vlan_strip(struct pci_dev *pdev, int vf_id, bool *enable)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vf *vf;
+       int ret;
+
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       *enable = vf->vlan_stripping;
+err_out:
+       return ret;
+}
+
 /**
- * i40e_ndo_set_vf_port_vlan
- * @netdev: network interface device structure
+ * i40e_set_vlan_strip
+ * @pdev: PCI device information struct
  * @vf_id: VF identifier
- * @vlan_id: mac address
- * @qos: priority setting
+ * @enable: enable/disable
  *
- * program VF vlan id and/or qos
+ * This function enables or disables VLAN stripping on a VF
+ *
+ * Returns 0 on success, negative on failure
  **/
-int i40e_ndo_set_vf_port_vlan(struct net_device *netdev,
-                             int vf_id, u16 vlan_id, u8 qos)
-#endif /* IFLA_VF_VLAN_INFO_MAX */
+static int i40e_set_vlan_strip(struct pci_dev *pdev, int vf_id,
+                              const bool enable)
 {
-       u16 vlanprio = vlan_id | (qos << I40E_VLAN_PRIORITY_SHIFT);
-       struct i40e_netdev_priv *np = netdev_priv(netdev);
-       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
        struct i40e_vsi *vsi;
        struct i40e_vf *vf;
-       int ret = 0;
+       int ret;
 
        /* validate the request */
-       if (vf_id >= pf->num_alloc_vfs) {
-               dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
-               ret = -EINVAL;
-               goto error_pvid;
-       }
-
-       if ((vlan_id > I40E_MAX_VLANID) || (qos > 7)) {
-               dev_err(&pf->pdev->dev, "Invalid VF Parameters\n");
-               ret = -EINVAL;
-               goto error_pvid;
-       }
-#ifdef IFLA_VF_VLAN_INFO_MAX
-
-       if (vlan_proto != htons(ETH_P_8021Q)) {
-               dev_err(&pf->pdev->dev, "VF VLAN protocol is not supported\n");
-               ret = -EPROTONOSUPPORT;
-               goto error_pvid;
-       }
-#endif
-
-       vf = &(pf->vf[vf_id]);
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
        vsi = pf->vsi[vf->lan_vsi_idx];
-       if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
-               dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
-                       vf_id);
-               ret = -EAGAIN;
-               goto error_pvid;
-       }
-
-       if (le16_to_cpu(vsi->info.pvid) == vlanprio)
-               /* duplicate request, so just return success */
-               goto error_pvid;
-
-       if (i40e_vsi_has_vlans(vsi)) {
-               dev_err(&pf->pdev->dev,
-                       "VF %d has already configured VLAN filters and the administrator is requesting a port VLAN override.\nPlease unload and reload the VF driver for this change to take effect.\n",
-                       vf_id);
-               /* Administrator Error - knock the VF offline until he does
-                * the right thing by reconfiguring his network correctly
-                * and then reloading the VF driver.
-                */
-               i40e_vc_disable_vf(vf);
-               /* During reset the VF got a new VSI, so refresh the pointer. */
-               vsi = pf->vsi[vf->lan_vsi_idx];
-       }
+       ret = i40e_configure_vf_vlan_stripping(vsi, vf_id, enable);
+       if (!ret)
+               vf->vlan_stripping = enable;
+err_out:
+       return ret;
+}
 
-       /* Locked once because multiple functions below iterate list */
-       spin_lock_bh(&vsi->mac_filter_hash_lock);
+/**
+ * i40e_get_rx_bytes
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @rx_bytes: pointer to the caller's rx_bytes variable
+ *
+ * This function gets the received bytes on the VF
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_get_rx_bytes(struct pci_dev *pdev, int vf_id,
+                            u64 *rx_bytes)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret;
 
-       /* Check for condition where there was already a port VLAN ID
-        * filter set and now it is being deleted by setting it to zero.
-        * Additionally check for the condition where there was a port
-        * VLAN but now there is a new and different port VLAN being set.
-        * Before deleting all the old VLAN filters we must add new ones
-        * with -1 (I40E_VLAN_ANY) or otherwise we're left with all our
-        * MAC addresses deleted.
-        */
-       if ((!(vlan_id || qos) ||
-           vlanprio != le16_to_cpu(vsi->info.pvid)) &&
-           vsi->info.pvid) {
-               ret = i40e_add_vlan_all_mac(vsi, I40E_VLAN_ANY);
-               if (ret) {
-                       dev_info(&vsi->back->pdev->dev,
-                                "add VF VLAN failed, ret=%d aq_err=%d\n", ret,
-                                vsi->back->hw.aq.asq_last_status);
-                       spin_unlock_bh(&vsi->mac_filter_hash_lock);
-                       goto error_pvid;
-               }
-       }
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       i40e_update_eth_stats(vsi);
+       *rx_bytes = vsi->eth_stats.rx_bytes;
+err_out:
+       return ret;
+}
 
-       if (vsi->info.pvid) {
-               /* remove all filters on the old VLAN */
-               i40e_rm_vlan_all_mac(vsi, (le16_to_cpu(vsi->info.pvid) &
-                                          VLAN_VID_MASK));
-       }
+/**
+ * i40e_get_rx_dropped
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @rx_dropped: pointer to the caller's rx_dropped variable
+ *
+ * This function gets the dropped received bytes on the VF
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_get_rx_dropped(struct pci_dev *pdev, int vf_id,
+                              u64 *rx_dropped)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret;
 
-       spin_unlock_bh(&vsi->mac_filter_hash_lock);
-       if (vlan_id || qos)
-               ret = i40e_vsi_add_pvid(vsi, vlanprio);
-       else
-               i40e_vsi_remove_pvid(vsi);
-       spin_lock_bh(&vsi->mac_filter_hash_lock);
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       i40e_update_eth_stats(vsi);
+       *rx_dropped = vsi->eth_stats.rx_discards;
+err_out:
+       return ret;
+}
 
-       if (vlan_id) {
-               dev_info(&pf->pdev->dev, "Setting VLAN %d, QOS 0x%x on VF %d\n",
-                        vlan_id, qos, vf_id);
+/**
+ * i40e_get_rx_packets
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @rx_packets: pointer to the caller's rx_packets variable
+ *
+ * This function gets the number of packets received on the VF
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_get_rx_packets(struct pci_dev *pdev, int vf_id,
+                              u64 *rx_packets)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret;
 
-               /* add new VLAN filter for each MAC */
-               ret = i40e_add_vlan_all_mac(vsi, vlan_id);
-               if (ret) {
-                       dev_info(&vsi->back->pdev->dev,
-                                "add VF VLAN failed, ret=%d aq_err=%d\n", ret,
-                                vsi->back->hw.aq.asq_last_status);
-                       spin_unlock_bh(&vsi->mac_filter_hash_lock);
-                       goto error_pvid;
-               }
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       i40e_update_eth_stats(vsi);
+       *rx_packets = vsi->eth_stats.rx_unicast + vsi->eth_stats.rx_multicast +
+                     vsi->eth_stats.rx_broadcast;
+err_out:
+       return ret;
+}
 
-               /* remove the previously added non-VLAN MAC filters */
-               i40e_rm_vlan_all_mac(vsi, I40E_VLAN_ANY);
-       }
+/**
+ * i40e_get_tx_bytes
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @tx_bytes: pointer to the caller's tx_bytes variable
+ *
+ * This function gets the transmitted bytes by the VF
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_get_tx_bytes(struct pci_dev *pdev, int vf_id,
+                            u64 *tx_bytes)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret;
 
-       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       i40e_update_eth_stats(vsi);
+       *tx_bytes = vsi->eth_stats.tx_bytes;
+err_out:
+       return ret;
+}
 
-       /* Schedule the worker thread to take care of applying changes */
-       i40e_service_event_schedule(vsi->back);
+/**
+ * i40e_get_tx_dropped
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @tx_dropped: pointer to the caller's tx_dropped variable
+ *
+ * This function gets the dropped tx bytes by the VF
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_get_tx_dropped(struct pci_dev *pdev, int vf_id,
+                              u64 *tx_dropped)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret;
 
-       if (ret) {
-               dev_err(&pf->pdev->dev, "Unable to update VF vsi context\n");
-               goto error_pvid;
-       }
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       i40e_update_eth_stats(vsi);
+       *tx_dropped = vsi->eth_stats.tx_discards;
+err_out:
+       return ret;
+}
 
-       /* The Port VLAN needs to be saved across resets the same as the
-        * default LAN MAC address.
-        */
-       vf->port_vlan_id = le16_to_cpu(vsi->info.pvid);
-       ret = 0;
+/**
+ * i40e_get_tx_packets
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @tx_packets: pointer to the caller's tx_packets variable
+ *
+ * This function gets the number of packets transmitted by the VF
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_get_tx_packets(struct pci_dev *pdev, int vf_id,
+                              u64 *tx_packets)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret;
 
-error_pvid:
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       i40e_update_eth_stats(vsi);
+       *tx_packets = vsi->eth_stats.tx_unicast + vsi->eth_stats.tx_multicast +
+                     vsi->eth_stats.tx_broadcast;
+err_out:
        return ret;
 }
 
-#define I40E_BW_CREDIT_DIVISOR 50     /* 50Mbps per BW credit */
-#define I40E_MAX_BW_INACTIVE_ACCUM 4  /* device can accumulate 4 credits max */
 /**
- * i40e_ndo_set_vf_bw
- * @netdev: network interface device structure
+ * i40e_get_tx_errors
+ * @pdev: PCI device information struct
  * @vf_id: VF identifier
- * @tx_rate: Tx rate
+ * @tx_errors: pointer to the caller's tx_errors variable
  *
- * configure VF Tx rate
+ * This function gets the number of packets transmitted by the VF
+ *
+ * Returns 0 on success, negative on failure
  **/
-#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
-int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
-                      int max_tx_rate)
-#else
-int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int max_tx_rate)
-#endif
+static int i40e_get_tx_errors(struct pci_dev *pdev, int vf_id,
+                             u64 *tx_errors)
 {
-       struct i40e_netdev_priv *np = netdev_priv(netdev);
-       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
        struct i40e_vsi *vsi;
        struct i40e_vf *vf;
-       int speed = 0;
-       int ret = 0;
+       int ret;
 
        /* validate the request */
-       if (vf_id >= pf->num_alloc_vfs) {
-               dev_err(&pf->pdev->dev, "Invalid VF Identifier %d.\n", vf_id);
-               ret = -EINVAL;
-               goto error;
-       }
-
-       vf = &(pf->vf[vf_id]);
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
        vsi = pf->vsi[vf->lan_vsi_idx];
-       if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
-               dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
-                       vf_id);
-               ret = -EAGAIN;
-               goto error;
-       }
-
-       switch (pf->hw.phy.link_info.link_speed) {
-       case I40E_LINK_SPEED_40GB:
-               speed = 40000;
-               break;
-       case I40E_LINK_SPEED_25GB:
-               speed = 25000;
-               break;
-       case I40E_LINK_SPEED_20GB:
-               speed = 20000;
-               break;
-       case I40E_LINK_SPEED_10GB:
-               speed = 10000;
-               break;
-       case I40E_LINK_SPEED_1GB:
-               speed = 1000;
-               break;
-       default:
-               break;
-       }
+       i40e_update_eth_stats(vsi);
+       *tx_errors = vsi->eth_stats.tx_errors;
+err_out:
+       return ret;
+}
 
-       if (max_tx_rate > speed) {
-               dev_err(&pf->pdev->dev, "Invalid tx rate %d specified for VF %d.",
-                       max_tx_rate, vf->vf_id);
-               ret = -EINVAL;
-               goto error;
-       }
-       if ((max_tx_rate < 50) && (max_tx_rate > 0)) {
-               dev_warn(&pf->pdev->dev, "Setting tx rate to minimum usable value of 50Mbps.\n");
-               max_tx_rate = 50;
-       }
+/**
+ * i40e_get_mac
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @mac: the default mac address
+ *
+ * This function gets the default mac address
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_get_mac(struct pci_dev *pdev, int vf_id, u8 *mac)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vf *vf;
+       int ret;
 
-       /* Tx rate credits are in values of 50Mbps, 0 is disabled*/
-       ret = i40e_aq_config_vsi_bw_limit(&pf->hw, vsi->seid,
-                                         max_tx_rate / I40E_BW_CREDIT_DIVISOR,
-                                         I40E_MAX_BW_INACTIVE_ACCUM, NULL);
-       if (ret) {
-               dev_err(&pf->pdev->dev, "Unable to set tx rate, error code %d.\n",
-                       ret);
-               ret = -EIO;
-               goto error;
-       }
-       vf->tx_rate = max_tx_rate;
-error:
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       ether_addr_copy(mac, vf->default_lan_addr.addr);
+err_out:
        return ret;
 }
 
 /**
- * i40e_ndo_enable_vf
- * @netdev: network interface device structure
+ * i40e_set_mac
+ * @pdev: PCI device information struct
  * @vf_id: VF identifier
- * @enable: true to enable & false to disable
+ * @mac: the default mac address to set
  *
- * enable/disable VF
+ * This function sets the default mac address for the VF
+ *
+ * Returns 0 on success, negative on failure
  **/
-int i40e_ndo_enable_vf(struct net_device *netdev, int vf_id, bool enable)
+static int i40e_set_mac(struct pci_dev *pdev, int vf_id, const u8 *mac)
 {
-       return -EOPNOTSUPP;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret;
+
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       ret = i40e_set_vf_mac(vf, vsi, mac);
+err_out:
+       return ret;
 }
 
 /**
- * i40e_ndo_get_vf_config
- * @netdev: network interface device structure
+ * i40e_get_promisc
+ * @pdev: PCI device information struct
  * @vf_id: VF identifier
- * @ivi: VF configuration structure
+ * @promisc_mode: current promiscuous mode
  *
- * return VF configuration
+ * This function gets the current promiscuous mode configuration.
+ *
+ * Returns 0 on success, negative on failure
  **/
-int i40e_ndo_get_vf_config(struct net_device *netdev,
-                          int vf_id, struct ifla_vf_info *ivi)
+static int i40e_get_promisc(struct pci_dev *pdev, int vf_id, u8 *promisc_mode)
 {
-       struct i40e_netdev_priv *np = netdev_priv(netdev);
-       struct i40e_vsi *vsi = np->vsi;
-       struct i40e_pf *pf = vsi->back;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
        struct i40e_vf *vf;
-       int ret = 0;
+       int ret;
 
        /* validate the request */
-       if (vf_id >= pf->num_alloc_vfs) {
-               dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
-               ret = -EINVAL;
-               goto error_param;
-       }
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       *promisc_mode = vf->promisc_mode;
+err_out:
+       return ret;
+}
 
-       vf = &(pf->vf[vf_id]);
-       /* first vsi is always the LAN vsi */
-       vsi = pf->vsi[vf->lan_vsi_idx];
-       if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
-               dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
-                       vf_id);
-               ret = -EAGAIN;
-               goto error_param;
-       }
+/**
+ * i40e_set_promisc
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @promisc_mode: promiscuous mode to be set
+ *
+ * This function sets the promiscuous mode configuration.
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_set_promisc(struct pci_dev *pdev, int vf_id,
+                           const u8 promisc_mode)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret;
 
-       ivi->vf = vf_id;
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       ret = i40e_configure_vf_promisc_mode(vf, vsi, promisc_mode);
+err:
+       return ret;
+}
 
-       ether_addr_copy(ivi->mac, vf->default_lan_addr.addr);
+/**
+ * i40e_get_ingress_mirror - Gets the configured ingress mirror
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @mirror: pointer to return the ingress mirror
+ *
+ * Gets the ingress mirror configured
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_get_ingress_mirror(struct pci_dev *pdev, int vf_id, int *mirror)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vf *vf;
+       int ret;
 
-#ifdef HAVE_NDO_SET_VF_MIN_MAX_TX_RATE
-       ivi->max_tx_rate = vf->tx_rate;
-       ivi->min_tx_rate = 0;
-#else
-       ivi->tx_rate = vf->tx_rate;
-#endif
-       ivi->vlan = le16_to_cpu(vsi->info.pvid) & I40E_VLAN_MASK;
-       ivi->qos = (le16_to_cpu(vsi->info.pvid) & I40E_PRIORITY_MASK) >>
-                  I40E_VLAN_PRIORITY_SHIFT;
-#ifdef HAVE_NDO_SET_VF_LINK_STATE
-       if (vf->link_forced == false)
-               ivi->linkstate = IFLA_VF_LINK_STATE_AUTO;
-       else if (vf->link_up == true)
-               ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE;
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       if (!vf->ingress_vlan)
+               *mirror = I40E_NO_VF_MIRROR;
        else
-               ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE;
-#endif
-#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
-       ivi->spoofchk = vf->spoofchk;
-#endif
-#ifdef HAVE_NDO_SET_VF_TRUST
-       ivi->trusted = vf->trusted;
-#endif /* HAVE_NDO_SET_VF_TRUST */
-       ret = 0;
+               *mirror = vf->ingress_vlan;
+err_out:
+       return ret;
+}
 
-error_param:
+/**
+ * i40e_set_ingress_mirror - Configure ingress mirror
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @mirror: mirror vf
+ *
+ * Configures the ingress mirror
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_set_ingress_mirror(struct pci_dev *pdev, int vf_id,
+                                  const int mirror)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vf *vf;
+       u16 rule_type;
+       int ret;
+
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       rule_type = I40E_AQC_MIRROR_RULE_TYPE_VPORT_INGRESS;
+       if (mirror == I40E_NO_VF_MIRROR) {
+               /* Del mirrors */
+               ret = i40e_vf_del_ingress_egress_mirror(vf, rule_type);
+               if (ret)
+                       goto err_out;
+               vf->ingress_vlan = I40E_NO_VF_MIRROR;
+       } else {
+               /* Add mirrors */
+               ret = i40e_vf_add_ingress_egress_mirror(vf, mirror, rule_type);
+               if (ret)
+                       goto err_out;
+               vf->ingress_vlan = mirror;
+       }
+err_out:
        return ret;
 }
 
-#ifdef HAVE_NDO_SET_VF_LINK_STATE
 /**
- * i40e_ndo_set_vf_link_state
- * @netdev: network interface device structure
+ * i40e_get_egress_mirror - Gets the configured egress mirror
+ * @pdev: PCI device information struct
  * @vf_id: VF identifier
- * @link: required link state
+ * @mirror: pointer to return the egress mirror
  *
- * Set the link state of a specified VF, regardless of physical link state
+ * Gets the egress mirror configured
+ *
+ * Returns 0 on success, negative on failure
  **/
-int i40e_ndo_set_vf_link_state(struct net_device *netdev, int vf_id, int link)
+static int i40e_get_egress_mirror(struct pci_dev *pdev, int vf_id, int *mirror)
 {
-       struct i40e_netdev_priv *np = netdev_priv(netdev);
-       struct i40e_pf *pf = np->vsi->back;
-       struct i40e_link_status *ls = &pf->hw.phy.link_info;
-       struct virtchnl_pf_event pfe;
-       struct i40e_hw *hw = &pf->hw;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
        struct i40e_vf *vf;
-       int abs_vf_id;
-       int ret = 0;
+       int ret;
 
        /* validate the request */
-       if (vf_id >= pf->num_alloc_vfs) {
-               dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
-               ret = -EINVAL;
-               goto error_out;
-       }
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       if (!vf->egress_vlan)
+               *mirror = I40E_NO_VF_MIRROR;
+       else
+               *mirror = vf->egress_vlan;
+err_out:
+       return ret;
+}
+
+/**
+ * i40e_set_egress_mirror - Configure egress mirror
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @mirror: mirror vf
+ *
+ * Configures the egress mirror
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_set_egress_mirror(struct pci_dev *pdev, int vf_id,
+                                 const int mirror)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_vf *vf;
+       u16 rule_type;
+       int ret;
 
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
        vf = &pf->vf[vf_id];
-       abs_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
+       rule_type = I40E_AQC_MIRROR_RULE_TYPE_VPORT_EGRESS;
+       if (mirror == I40E_NO_VF_MIRROR) {
+               /* Del mirrors */
+               ret = i40e_vf_del_ingress_egress_mirror(vf, rule_type);
+               if (ret)
+                       goto err_out;
+               vf->egress_vlan = I40E_NO_VF_MIRROR;
+       } else {
+               /* Add mirrors */
+               ret = i40e_vf_add_ingress_egress_mirror(vf, mirror, rule_type);
+               if (ret)
+                       goto err_out;
+               vf->egress_vlan = mirror;
+       }
+err_out:
+       return ret;
+}
 
-       pfe.event = VIRTCHNL_EVENT_LINK_CHANGE;
-       pfe.severity = PF_EVENT_SEVERITY_INFO;
+/**
+ * i40e_get_link_state
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @enabled: link state
+ * @link_speed: link speed of the VF
+ *
+ * Gets the status of link and the link speed
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_get_link_state(struct pci_dev *pdev, int vf_id, bool *enabled,
+                              enum vfd_link_speed *link_speed)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_link_status *ls;
+       struct i40e_vf *vf;
+       int ret;
 
-       switch (link) {
-       case IFLA_VF_LINK_STATE_AUTO:
-               vf->link_forced = false;
-               pfe.event_data.link_event.link_status =
-                       ls->link_info & I40E_AQ_LINK_UP;
-               pfe.event_data.link_event.link_speed =
-                       i40e_virtchnl_link_speed(ls->link_speed);
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto err_out;
+       vf = &pf->vf[vf_id];
+       ls = &pf->hw.phy.link_info;
+       if (vf->link_forced)
+               *enabled = vf->link_up;
+       else
+               *enabled = ls->link_info & I40E_AQ_LINK_UP;
+       switch (ls->link_speed) {
+       case I40E_LINK_SPEED_UNKNOWN:
+               *link_speed = VFD_LINK_SPEED_UNKNOWN;
                break;
-       case IFLA_VF_LINK_STATE_ENABLE:
-               vf->link_forced = true;
-               vf->link_up = true;
-               pfe.event_data.link_event.link_status = true;
-               pfe.event_data.link_event.link_speed = I40E_LINK_SPEED_40GB;
+       case I40E_LINK_SPEED_100MB:
+               *link_speed = VFD_LINK_SPEED_100MB;
                break;
-       case IFLA_VF_LINK_STATE_DISABLE:
-               vf->link_forced = true;
-               vf->link_up = false;
-               pfe.event_data.link_event.link_status = false;
-               pfe.event_data.link_event.link_speed = 0;
+       case I40E_LINK_SPEED_1GB:
+               *link_speed = VFD_LINK_SPEED_1GB;
+               break;
+       case I40E_LINK_SPEED_10GB:
+               *link_speed = VFD_LINK_SPEED_10GB;
+               break;
+       case I40E_LINK_SPEED_20GB:
+               *link_speed = VFD_LINK_SPEED_20GB;
+               break;
+       case I40E_LINK_SPEED_25GB:
+               *link_speed = VFD_LINK_SPEED_25GB;
+               break;
+       case I40E_LINK_SPEED_40GB:
+               *link_speed = VFD_LINK_SPEED_40GB;
                break;
        default:
-               ret = -EINVAL;
-               goto error_out;
+               *link_speed = VFD_LINK_SPEED_UNKNOWN;
        }
-       /* Notify the VF of its new link state */
-       i40e_aq_send_msg_to_vf(hw, abs_vf_id, VIRTCHNL_OP_EVENT,
-                              I40E_SUCCESS, (u8 *)&pfe, sizeof(pfe), NULL);
-
-error_out:
+err_out:
        return ret;
 }
 
-#endif /* HAVE_NDO_SET_VF_LINK_STATE */
-#ifdef HAVE_VF_SPOOFCHK_CONFIGURE
 /**
- * i40e_ndo_set_vf_spoofchk
- * @netdev: network interface device structure
+ * i40e_set_link_state
+ * @pdev: PCI device information struct
  * @vf_id: VF identifier
- * @enable: flag to enable or disable feature
+ * @link: the link state to configure
  *
- * Enable or disable VF spoof checking
+ * Configures link for a vf
+ *
+ * Returns 0 on success, negative on failure
  **/
-int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable)
+static int i40e_set_link_state(struct pci_dev *pdev, int vf_id, const u8 link)
 {
-       struct i40e_netdev_priv *np = netdev_priv(netdev);
-       struct i40e_vsi *vsi = np->vsi;
-       struct i40e_pf *pf = vsi->back;
-       struct i40e_vsi_context ctxt;
-       struct i40e_hw *hw = &pf->hw;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
        struct i40e_vf *vf;
-       int ret = 0;
+       int ret;
 
        /* validate the request */
-       if (vf_id >= pf->num_alloc_vfs) {
-               dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
-               ret = -EINVAL;
-               goto out;
-       }
-
-       vf = &(pf->vf[vf_id]);
-       if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
-               dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
-                       vf_id);
-               ret = -EAGAIN;
-               goto out;
-       }
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto error_out;
+       vf = &pf->vf[vf_id];
+       ret = i40e_configure_vf_link(vf, link);
+error_out:
+       return ret;
+}
 
-       if (enable == vf->spoofchk)
-               goto out;
+/*
+ * i40e_get_mac_list
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @list_head: list of mac addresses
+ *
+ * This function returns the list of mac address configured on the VF.
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int i40e_get_mac_list(struct pci_dev *pdev, int vf_id,
+                            struct list_head *mac_list)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct i40e_mac_filter *f;
+       struct vfd_macaddr *tmp;
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret, bkt;
 
-       vf->spoofchk = enable;
-       memset(&ctxt, 0, sizeof(ctxt));
-       ctxt.seid = pf->vsi[vf->lan_vsi_idx]->seid;
-       ctxt.pf_num = pf->hw.pf_id;
-       ctxt.info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SECURITY_VALID);
-       if (enable)
-               ctxt.info.sec_flags |= (I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK |
-                                       I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK);
-       ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
-       if (ret) {
-               dev_err(&pf->pdev->dev, "Error %d updating VSI parameters\n",
-                       ret);
-               ret = -EIO;
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto error_out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+       hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
+               tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+               if (!tmp) {
+                       ret = -ENOMEM;
+                       goto error_out;
+               }
+               INIT_LIST_HEAD(&tmp->list);
+               ether_addr_copy(tmp->mac, f->macaddr);
+               list_add_tail(&tmp->list, mac_list);
        }
-out:
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+error_out:
        return ret;
 }
 
-#endif /* HAVE_VF_SPOOFCHK_CONFIGURE */
-#ifdef HAVE_NDO_SET_VF_TRUST
-/**
- * i40e_ndo_set_vf_trust
- * @netdev: network interface device structure of the pf
+/*
+ * i40e_add_macs_to_list
+ * @pdev: PCI device information struct
  * @vf_id: VF identifier
- * @setting: trust setting
+ * @list_head: list of mac addresses
  *
- * Enable or disable VF trust setting
- **/
-int i40e_ndo_set_vf_trust(struct net_device *netdev, int vf_id, bool setting)
+ * This function adds a list of mac addresses for a VF
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int i40e_add_macs_to_list(struct pci_dev *pdev, int vf_id,
+                                struct list_head *mac_list)
 {
-       struct i40e_netdev_priv *np = netdev_priv(netdev);
-       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct vfd_macaddr *tmp;
+       struct i40e_vsi *vsi;
        struct i40e_vf *vf;
-       int ret = 0;
+       int ret;
 
        /* validate the request */
-       if (vf_id >= pf->num_alloc_vfs) {
-               dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
-               return -EINVAL;
-       }
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto error_out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+       list_for_each_entry(tmp, mac_list, list) {
+               struct i40e_mac_filter *f;
 
-       if (pf->flags & I40E_FLAG_MFP_ENABLED) {
-               dev_err(&pf->pdev->dev, "Trusted VF not supported in MFP mode.\n");
-               return -EINVAL;
+               f = i40e_find_mac(vsi, tmp->mac);
+               if (!f) {
+                       f = i40e_add_mac_filter(vsi, tmp->mac);
+                       if (!f) {
+                               dev_err(&pf->pdev->dev,
+                                       "Unable to add MAC filter %pM for VF %d\n",
+                                       tmp->mac, vf->vf_id);
+                               ret = I40E_ERR_PARAM;
+                               spin_unlock_bh(&vsi->mac_filter_hash_lock);
+                               goto error_out;
+                       } else {
+                               vf->num_mac++;
+                       }
+               }
        }
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
 
-       vf = &pf->vf[vf_id];
+       /* program the updated filter list */
+       ret = i40e_sync_vsi_filters(vsi);
+       if (ret)
+               dev_err(&pf->pdev->dev, "Unable to program VF %d MAC filters, error %d\n",
+                       vf->vf_id, ret);
+error_out:
+       return ret;
+}
 
-       /* if vf is in base mode, make it untrusted */
-       if (pf->vf_base_mode_only)
-               setting = false;
-       if (setting == vf->trusted)
-               goto out;
+/*
+ * i40e_rem_macs_from_list
+ * @pdev: PCI device information struct
+ * @vf_id: VF identifier
+ * @list_head: list of mac addresses
+ *
+ * This function removes a list of mac addresses from a VF
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int i40e_rem_macs_from_list(struct pci_dev *pdev, int vf_id,
+                                  struct list_head *mac_list)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       struct vfd_macaddr *tmp;
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret;
 
-       vf->trusted = setting;
-       i40e_vc_disable_vf(vf);
-       dev_info(&pf->pdev->dev, "VF %u is now %strusted\n",
-                vf_id, setting ? "" : "un");
-out:
+       /* validate the request */
+       ret = i40e_validate_vf(pf, vf_id);
+       if (ret)
+               goto error_out;
+       vf = &pf->vf[vf_id];
+       vsi = pf->vsi[vf->lan_vsi_idx];
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+       list_for_each_entry(tmp, mac_list, list) {
+               if (ether_addr_equal(tmp->mac, vf->default_lan_addr.addr) ||
+                   i40e_del_mac_filter(vsi, tmp->mac)) {
+                       ret = I40E_ERR_INVALID_MAC_ADDR;
+                       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+                       goto error_out;
+               } else {
+                       vf->num_mac--;
+               }
+       }
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+
+       /* program the updated filter list */
+       ret = i40e_sync_vsi_filters(vsi);
+       if (ret)
+               dev_err(&pf->pdev->dev, "Unable to program VF %d MAC filters, error %d\n",
+                       vf->vf_id, ret);
+error_out:
        return ret;
 }
-#endif /* HAVE_NDO_SET_VF_TRUST */
-#endif /* IFLA_VF_MAX */
+
+const struct vfd_ops i40e_vfd_ops = {
+       .get_trunk              = i40e_get_trunk,
+       .set_trunk              = i40e_set_trunk,
+       .get_vlan_mirror        = i40e_get_mirror,
+       .set_vlan_mirror        = i40e_set_mirror,
+       .get_mac_anti_spoof     = i40e_get_mac_anti_spoof,
+       .set_mac_anti_spoof     = i40e_set_mac_anti_spoof,
+       .get_vlan_anti_spoof    = i40e_get_vlan_anti_spoof,
+       .set_vlan_anti_spoof    = i40e_set_vlan_anti_spoof,
+       .set_allow_untagged     = i40e_set_allow_untagged,
+       .get_allow_untagged     = i40e_get_allow_untagged,
+       .get_loopback           = i40e_get_loopback,
+       .set_loopback           = i40e_set_loopback,
+       .get_vlan_strip         = i40e_get_vlan_strip,
+       .set_vlan_strip         = i40e_set_vlan_strip,
+       .get_rx_bytes           = i40e_get_rx_bytes,
+       .get_rx_dropped         = i40e_get_rx_dropped,
+       .get_rx_packets         = i40e_get_rx_packets,
+       .get_tx_bytes           = i40e_get_tx_bytes,
+       .get_tx_dropped         = i40e_get_tx_dropped,
+       .get_tx_packets         = i40e_get_tx_packets,
+       .get_tx_errors          = i40e_get_tx_errors,
+       .get_mac                = i40e_get_mac,
+       .set_mac                = i40e_set_mac,
+       .get_promisc            = i40e_get_promisc,
+       .set_promisc            = i40e_set_promisc,
+       .get_ingress_mirror     = i40e_get_ingress_mirror,
+       .set_ingress_mirror     = i40e_set_ingress_mirror,
+       .get_egress_mirror      = i40e_get_egress_mirror,
+       .set_egress_mirror      = i40e_set_egress_mirror,
+       .get_link_state         = i40e_get_link_state,
+       .set_link_state         = i40e_set_link_state,
+       .get_mac_list           = i40e_get_mac_list,
+       .add_macs_to_list       = i40e_add_macs_to_list,
+       .rem_macs_from_list     = i40e_rem_macs_from_list,
+};
similarity index 76%
rename from i40e-dkms/i40e-2.4.6/src/i40e_virtchnl_pf.h
rename to i40e-dkms/i40e-2.7.29/src/i40e_virtchnl_pf.h
index 8f48651eca73f23af5b370ff1175925f6e77612e..f235f5319e80a802dc9defe31d7e2f1c683ab31e 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _I40E_VIRTCHNL_PF_H_
 #define _I40E_VIRTCHNL_PF_H_
@@ -33,9 +13,9 @@
 #define I40E_DEFAULT_NUM_MDD_EVENTS_ALLOWED    3
 #define I40E_DEFAULT_NUM_INVALID_MSGS_ALLOWED  10
 
-#define I40E_VLAN_PRIORITY_SHIFT       12
+#define I40E_VLAN_PRIORITY_SHIFT       13
 #define I40E_VLAN_MASK                 0xFFF
-#define I40E_PRIORITY_MASK             0x7000
+#define I40E_PRIORITY_MASK             0xE000
 
 /* Various queue ctrls */
 enum i40e_queue_ctrl {
@@ -66,6 +46,19 @@ enum i40e_vf_capabilities {
        I40E_VIRTCHNL_VF_CAP_IWARP,
 };
 
+/* In ADq, max 4 VSI's can be allocated per VF including primary VF VSI.
+ * These variables are used to store indices, id's and number of queues
+ * for each VSI including that of primary VF VSI. Each Traffic class is
+ * termed as channel and each channel can in-turn have 4 queues which
+ * means max 16 queues overall per VF.
+ */
+struct i40evf_channel {
+       u16 vsi_idx; /* index in PF struct for all channel VSIs */
+       u16 vsi_id; /* VSI ID used by firmware */
+       u16 num_qps; /* number of queue pairs requested by user */
+       u64 max_tx_rate; /* bandwidth rate allocation for VSIs */
+};
+
 /* VF information structure */
 struct i40e_vf {
        struct i40e_pf *pf;
@@ -109,6 +102,27 @@ struct i40e_vf {
        bool spoofchk;
        u16 num_mac;
        u16 num_vlan;
+       DECLARE_BITMAP(mirror_vlans, VLAN_N_VID);
+       u16 vlan_rule_id;
+#define I40E_NO_VF_MIRROR      -1
+       u16 ingress_rule_id;
+       int ingress_vlan;
+       u16 egress_rule_id;
+       int egress_vlan;
+       DECLARE_BITMAP(trunk_vlans, VLAN_N_VID);
+       bool mac_anti_spoof;
+       bool vlan_anti_spoof;
+       bool allow_untagged;
+       bool loopback;
+       bool vlan_stripping;
+       u8 promisc_mode;
+
+       /* ADq related variables */
+       bool adq_enabled; /* flag to enable adq */
+       u8 num_tc;
+       struct i40evf_channel ch[I40E_MAX_VF_VSI];
+       struct hlist_head cloud_filter_list;
+       u16 num_cloud_filters;
 
        /* RDMA Client */
        struct virtchnl_iwarp_qvlist_info *qvlist_info;
@@ -159,4 +173,6 @@ int i40e_ndo_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool enable);
 void i40e_vc_notify_link_state(struct i40e_pf *pf);
 void i40e_vc_notify_reset(struct i40e_pf *pf);
 
+extern const struct vfd_ops i40e_vfd_ops;
+
 #endif /* _I40E_VIRTCHNL_PF_H_ */
similarity index 90%
rename from i40e-dkms/i40e-2.4.6/src/kcompat.c
rename to i40e-dkms/i40e-2.7.29/src/kcompat.c
index c825e938fd9bde0729ee7ae019a8b5128f9e4682..51b90e66139460f15005b5ed5f1b225172b4893b 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #include "i40e.h"
 #include "kcompat.h"
@@ -1419,6 +1399,34 @@ int __kc_pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val)
        return 0;
 }
 
+int __kc_pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val)
+{
+       int ret;
+
+       *val = 0;
+       if (pos & 3)
+               return -EINVAL;
+
+       if (__kc_pcie_capability_reg_implemented(dev, pos)) {
+               ret = pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, val);
+               /*
+                * Reset *val to 0 if pci_read_config_dword() fails, it may
+                * have been written as 0xFFFFFFFF if hardware error happens
+                * during pci_read_config_dword().
+                */
+               if (ret)
+                       *val = 0;
+               return ret;
+       }
+
+       if (pci_is_pcie(dev) && pos == PCI_EXP_SLTSTA &&
+           pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) {
+               *val = PCI_EXP_SLTSTA_PDS;
+       }
+
+       return 0;
+}
+
 int __kc_pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
 {
        if (pos & 1)
@@ -1709,14 +1717,12 @@ int __kc_pci_vfs_assigned(struct pci_dev __maybe_unused *dev)
 #endif /* CONFIG_PCI_IOV */
 #endif /* 3.10.0 */
 
-/*****************************************************************************/
-#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) )
-static const unsigned char pcie_link_speed[] = {
+static const unsigned char __maybe_unused pcie_link_speed[] = {
        PCI_SPEED_UNKNOWN,      /* 0 */
        PCIE_SPEED_2_5GT,       /* 1 */
        PCIE_SPEED_5_0GT,       /* 2 */
        PCIE_SPEED_8_0GT,       /* 3 */
-       PCI_SPEED_UNKNOWN,      /* 4 */
+       PCIE_SPEED_16_0GT,      /* 4 */
        PCI_SPEED_UNKNOWN,      /* 5 */
        PCI_SPEED_UNKNOWN,      /* 6 */
        PCI_SPEED_UNKNOWN,      /* 7 */
@@ -1730,6 +1736,8 @@ static const unsigned char pcie_link_speed[] = {
        PCI_SPEED_UNKNOWN       /* F */
 };
 
+/*****************************************************************************/
+#if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0) )
 int __kc_pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
                               enum pcie_link_width *width)
 {
@@ -1779,21 +1787,6 @@ int __kc_dma_set_mask_and_coherent(struct device *dev, u64 mask)
                err = dma_set_coherent_mask(dev, mask);
        return err;
 }
-
-void __kc_netdev_rss_key_fill(void *buffer, size_t len)
-{
-       /* Set of random keys generated using kernel random number generator */
-       static const u8 seed[NETDEV_RSS_KEY_LEN] = {0xE6, 0xFA, 0x35, 0x62,
-                               0x95, 0x12, 0x3E, 0xA3, 0xFB, 0x46, 0xC1, 0x5F,
-                               0xB1, 0x43, 0x82, 0x5B, 0x6A, 0x49, 0x50, 0x95,
-                               0xCD, 0xAB, 0xD8, 0x11, 0x8F, 0xC5, 0xBD, 0xBC,
-                               0x6A, 0x4A, 0xB2, 0xD4, 0x1F, 0xFE, 0xBC, 0x41,
-                               0xBF, 0xAC, 0xB2, 0x9A, 0x8F, 0x70, 0xE9, 0x2A,
-                               0xD7, 0xB2, 0x80, 0xB6, 0x5B, 0xAA, 0x9D, 0x20};
-
-       BUG_ON(len > NETDEV_RSS_KEY_LEN);
-       memcpy(buffer, seed, len);
-}
 #endif /* 3.13.0 */
 
 #if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) )
@@ -1940,6 +1933,21 @@ char *_kc_devm_kstrdup(struct device *dev, const char *s, gfp_t gfp)
                memcpy(buf, s, size);
        return buf;
 }
+
+void __kc_netdev_rss_key_fill(void *buffer, size_t len)
+{
+       /* Set of random keys generated using kernel random number generator */
+       static const u8 seed[NETDEV_RSS_KEY_LEN] = {0xE6, 0xFA, 0x35, 0x62,
+                               0x95, 0x12, 0x3E, 0xA3, 0xFB, 0x46, 0xC1, 0x5F,
+                               0xB1, 0x43, 0x82, 0x5B, 0x6A, 0x49, 0x50, 0x95,
+                               0xCD, 0xAB, 0xD8, 0x11, 0x8F, 0xC5, 0xBD, 0xBC,
+                               0x6A, 0x4A, 0xB2, 0xD4, 0x1F, 0xFE, 0xBC, 0x41,
+                               0xBF, 0xAC, 0xB2, 0x9A, 0x8F, 0x70, 0xE9, 0x2A,
+                               0xD7, 0xB2, 0x80, 0xB6, 0x5B, 0xAA, 0x9D, 0x20};
+
+       BUG_ON(len > NETDEV_RSS_KEY_LEN);
+       memcpy(buffer, seed, len);
+}
 #endif /* 3.15.0 */
 
 #if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) )
@@ -2282,6 +2290,22 @@ void __kc_netdev_rss_key_fill(void *buffer, size_t len)
        memcpy(buffer, __kc_netdev_rss_key, len);
 }
 #endif
+
+int _kc_bitmap_print_to_pagebuf(bool list, char *buf,
+                               const unsigned long *maskp,
+                               int nmaskbits)
+{
+       ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf - 2;
+       int n = 0;
+
+       if (len > 1) {
+               n = list ? bitmap_scnlistprintf(buf, len, maskp, nmaskbits) :
+                          bitmap_scnprintf(buf, len, maskp, nmaskbits);
+               buf[n++] = '\n';
+               buf[n] = '\0';
+       }
+       return n;
+}
 #endif
 
 /******************************************************************************/
@@ -2380,9 +2404,51 @@ int _kc_eth_platform_get_mac_address(struct device *dev __maybe_unused,
 #endif /* !(RHEL_RELEASE >= 7.3) */
 #endif /* < 4.5.0 */
 
+/*****************************************************************************/
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)) || \
+     (SLE_VERSION_CODE && (SLE_VERSION_CODE <= SLE_VERSION(12,3,0))) || \
+     (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE <= RHEL_RELEASE_VERSION(7,5))))
+const char *_kc_phy_speed_to_str(int speed)
+{
+       switch (speed) {
+       case SPEED_10:
+               return "10Mbps";
+       case SPEED_100:
+               return "100Mbps";
+       case SPEED_1000:
+               return "1Gbps";
+       case SPEED_2500:
+               return "2.5Gbps";
+       case SPEED_5000:
+               return "5Gbps";
+       case SPEED_10000:
+               return "10Gbps";
+       case SPEED_14000:
+               return "14Gbps";
+       case SPEED_20000:
+               return "20Gbps";
+       case SPEED_25000:
+               return "25Gbps";
+       case SPEED_40000:
+               return "40Gbps";
+       case SPEED_50000:
+               return "50Gbps";
+       case SPEED_56000:
+               return "56Gbps";
+#ifdef SPEED_100000
+       case SPEED_100000:
+               return "100Gbps";
+#endif
+       case SPEED_UNKNOWN:
+               return "Unknown";
+       default:
+               return "Unsupported (update phy-core.c)";
+       }
+}
+#endif /* (LINUX < 4.14.0) || (SLES <= 12.3.0) || (RHEL <= 7.5) */
+
 /******************************************************************************/
 #if ( LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) )
-#ifdef ETHTOOL_GLINKSETTINGS
 void _kc_ethtool_intersect_link_masks(struct ethtool_link_ksettings *dst,
                                      struct ethtool_link_ksettings *src)
 {
@@ -2396,5 +2462,152 @@ void _kc_ethtool_intersect_link_masks(struct ethtool_link_ksettings *dst,
                        src->link_modes.advertising[idx];
        }
 }
-#endif /* ETHTOOL_GKLINKSETTINGS */
 #endif /* 4.15.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0))
+/* PCIe link information */
+#define PCIE_SPEED2STR(speed) \
+       ((speed) == PCIE_SPEED_16_0GT ? "16 GT/s" : \
+        (speed) == PCIE_SPEED_8_0GT ? "8 GT/s" : \
+        (speed) == PCIE_SPEED_5_0GT ? "5 GT/s" : \
+        (speed) == PCIE_SPEED_2_5GT ? "2.5 GT/s" : \
+        "Unknown speed")
+
+/* PCIe speed to Mb/s reduced by encoding overhead */
+#define PCIE_SPEED2MBS_ENC(speed) \
+       ((speed) == PCIE_SPEED_16_0GT ? 16000*128/130 : \
+        (speed) == PCIE_SPEED_8_0GT  ?  8000*128/130 : \
+        (speed) == PCIE_SPEED_5_0GT  ?  5000*8/10 : \
+        (speed) == PCIE_SPEED_2_5GT  ?  2500*8/10 : \
+        0)
+
+static u32
+_kc_pcie_bandwidth_available(struct pci_dev *dev,
+                            struct pci_dev **limiting_dev,
+                            enum pci_bus_speed *speed,
+                            enum pcie_link_width *width)
+{
+       u16 lnksta;
+       enum pci_bus_speed next_speed;
+       enum pcie_link_width next_width;
+       u32 bw, next_bw;
+
+       if (speed)
+               *speed = PCI_SPEED_UNKNOWN;
+       if (width)
+               *width = PCIE_LNK_WIDTH_UNKNOWN;
+
+       bw = 0;
+
+       while (dev) {
+               pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
+
+               next_speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS];
+               next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >>
+                       PCI_EXP_LNKSTA_NLW_SHIFT;
+
+               next_bw = next_width * PCIE_SPEED2MBS_ENC(next_speed);
+
+               /* Check if current device limits the total bandwidth */
+               if (!bw || next_bw <= bw) {
+                       bw = next_bw;
+
+                       if (limiting_dev)
+                               *limiting_dev = dev;
+                       if (speed)
+                               *speed = next_speed;
+                       if (width)
+                               *width = next_width;
+               }
+
+               dev = pci_upstream_bridge(dev);
+       }
+
+       return bw;
+}
+
+static enum pci_bus_speed _kc_pcie_get_speed_cap(struct pci_dev *dev)
+{
+       u32 lnkcap2, lnkcap;
+
+       /*
+        * PCIe r4.0 sec 7.5.3.18 recommends using the Supported Link
+        * Speeds Vector in Link Capabilities 2 when supported, falling
+        * back to Max Link Speed in Link Capabilities otherwise.
+        */
+       pcie_capability_read_dword(dev, PCI_EXP_LNKCAP2, &lnkcap2);
+       if (lnkcap2) { /* PCIe r3.0-compliant */
+               if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB)
+                       return PCIE_SPEED_16_0GT;
+               else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB)
+                       return PCIE_SPEED_8_0GT;
+               else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB)
+                       return PCIE_SPEED_5_0GT;
+               else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB)
+                       return PCIE_SPEED_2_5GT;
+               return PCI_SPEED_UNKNOWN;
+       }
+
+       pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
+       if (lnkcap) {
+               if (lnkcap & PCI_EXP_LNKCAP_SLS_16_0GB)
+                       return PCIE_SPEED_16_0GT;
+               else if (lnkcap & PCI_EXP_LNKCAP_SLS_8_0GB)
+                       return PCIE_SPEED_8_0GT;
+               else if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB)
+                       return PCIE_SPEED_5_0GT;
+               else if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB)
+                       return PCIE_SPEED_2_5GT;
+       }
+
+       return PCI_SPEED_UNKNOWN;
+}
+
+static enum pcie_link_width _kc_pcie_get_width_cap(struct pci_dev *dev)
+{
+       u32 lnkcap;
+
+       pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
+       if (lnkcap)
+               return (lnkcap & PCI_EXP_LNKCAP_MLW) >> 4;
+
+       return PCIE_LNK_WIDTH_UNKNOWN;
+}
+
+static u32
+_kc_pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed,
+                          enum pcie_link_width *width)
+{
+       *speed = _kc_pcie_get_speed_cap(dev);
+       *width = _kc_pcie_get_width_cap(dev);
+
+       if (*speed == PCI_SPEED_UNKNOWN || *width == PCIE_LNK_WIDTH_UNKNOWN)
+               return 0;
+
+       return *width * PCIE_SPEED2MBS_ENC(*speed);
+}
+
+void _kc_pcie_print_link_status(struct pci_dev *dev) {
+       enum pcie_link_width width, width_cap;
+       enum pci_bus_speed speed, speed_cap;
+       struct pci_dev *limiting_dev = NULL;
+       u32 bw_avail, bw_cap;
+
+       bw_cap = _kc_pcie_bandwidth_capable(dev, &speed_cap, &width_cap);
+       bw_avail = _kc_pcie_bandwidth_available(dev, &limiting_dev, &speed,
+                                               &width);
+
+       if (bw_avail >= bw_cap)
+               pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth (%s x%d link)\n",
+                        bw_cap / 1000, bw_cap % 1000,
+                        PCIE_SPEED2STR(speed_cap), width_cap);
+       else
+               pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth, limited by %s x%d link at %s (capable of %u.%03u Gb/s with %s x%d link)\n",
+                        bw_avail / 1000, bw_avail % 1000,
+                        PCIE_SPEED2STR(speed), width,
+                        limiting_dev ? pci_name(limiting_dev) : "<unknown>",
+                        bw_cap / 1000, bw_cap % 1000,
+                        PCIE_SPEED2STR(speed_cap), width_cap);
+}
+#endif /* 4.17.0 */
similarity index 90%
rename from i40e-dkms/i40e-2.4.6/src/kcompat.h
rename to i40e-dkms/i40e-2.7.29/src/kcompat.h
index f63da5bede1f54178415638f6e72f9e3ef1677e6..6da0d7e2549f43dc187be59aad022ad4339187ac 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _KCOMPAT_H_
 #define _KCOMPAT_H_
@@ -87,6 +67,9 @@
 
 /* packet split disable/enable */
 #ifdef DISABLE_PACKET_SPLIT
+#ifndef CONFIG_I40E_DISABLE_PACKET_SPLIT
+#define CONFIG_I40E_DISABLE_PACKET_SPLIT
+#endif
 #endif /* DISABLE_PACKET_SPLIT */
 
 /* MSI compatibility code for all kernels and drivers */
@@ -729,12 +712,18 @@ struct _kc_ethtool_pauseparam {
 #ifndef SPEED_5000
 #define SPEED_5000 5000
 #endif
+#ifndef SPEED_14000
+#define SPEED_14000 14000
+#endif
 #ifndef SPEED_25000
 #define SPEED_25000 25000
 #endif
 #ifndef SPEED_50000
 #define SPEED_50000 50000
 #endif
+#ifndef SPEED_56000
+#define SPEED_56000 56000
+#endif
 #ifndef SPEED_100000
 #define SPEED_100000 100000
 #endif
@@ -863,15 +852,36 @@ struct _kc_ethtool_pauseparam {
 /* SLES12 SP1 GA is 3.12.49-11
  * updates 3.12.xx-60.yy where xx={51..} */
 #define SLE_VERSION_CODE SLE_VERSION(12,1,0)
-#elif (LINUX_VERSION_CODE == KERNEL_VERSION(4,4,21))
-/* SLES12 SP2 GA is 4.4.21-69 */
+#elif ((LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,21) && \
+       (LINUX_VERSION_CODE <= KERNEL_VERSION(4,4,59))) || \
+       (LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,74) && \
+        LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0) && \
+        SLE_LOCALVERSION_CODE >= KERNEL_VERSION(92,0,0) && \
+        SLE_LOCALVERSION_CODE <  KERNEL_VERSION(93,0,0)))
+/* SLES12 SP2 GA is 4.4.21-69.
+ * SLES12 SP2 updates before SLES12 SP3 are: 4.4.{21,38,49,59}
+ * SLES12 SP2 updates after SLES12 SP3 are: 4.4.{74,90,103,114,120}
+ * but they all use a SLE_LOCALVERSION_CODE matching 92.nn.y */
 #define SLE_VERSION_CODE SLE_VERSION(12,2,0)
-/* SLES12 SP3 GM is 4.4.73-5 and update kernel is 4.4.82-6.3 */
-#elif ((LINUX_VERSION_CODE == KERNEL_VERSION(4,4,73)) || \
-       (LINUX_VERSION_CODE == KERNEL_VERSION(4,4,82)))
+#elif ((LINUX_VERSION_CODE == KERNEL_VERSION(4,4,73) || \
+        LINUX_VERSION_CODE == KERNEL_VERSION(4,4,82) || \
+        LINUX_VERSION_CODE == KERNEL_VERSION(4,4,92)) || \
+       (LINUX_VERSION_CODE == KERNEL_VERSION(4,4,103) && \
+       (SLE_LOCALVERSION_CODE == KERNEL_VERSION(6,33,0) || \
+        SLE_LOCALVERSION_CODE == KERNEL_VERSION(6,38,0))) || \
+       (LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,114) && \
+        LINUX_VERSION_CODE < KERNEL_VERSION(4,5,0) && \
+        SLE_LOCALVERSION_CODE >= KERNEL_VERSION(94,0,0) && \
+        SLE_LOCALVERSION_CODE <  KERNEL_VERSION(95,0,0)) )
+/* SLES12 SP3 GM is 4.4.73-5 and update kernels are 4.4.82-6.3.
+ * SLES12 SP3 updates not conflicting with SP2 are: 4.4.{82,92}
+ * SLES12 SP3 updates conflicting with SP2 are:
+ *   - 4.4.103-6.33.1, 4.4.103-6.38.1
+ *   - 4.4.{114,120}-94.nn.y */
 #define SLE_VERSION_CODE SLE_VERSION(12,3,0)
-/* SLES15 Beta1 is 4.12.14-2 */
 #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,14))
+/* SLES15 Beta1 is 4.12.14-2.
+ * SLES12 SP4 will also use 4.12.14-nn.xx.y */
 #define SLE_VERSION_CODE SLE_VERSION(15,0,0)
 /* new SLES kernels must be added here with >= based on kernel
  * the idea is to order from newest to oldest and just catch all
@@ -896,6 +906,7 @@ struct _kc_ethtool_pauseparam {
 #endif
 
 #define memcpy(dest, src, len) memcpy_s(dest, len, src, len)
+#define memset(dest, ch, len)  memset_s(dest, len, ch, len)
 
 static inline int _kc_test_and_clear_bit(int nr, volatile unsigned long *addr)
 {
@@ -947,8 +958,16 @@ static inline int _kc_test_and_set_bit(int nr, volatile unsigned long *addr)
             pos;                                                            \
             pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
 
+#ifdef uninitialized_var
+#undef uninitialized_var
+#define uninitialized_var(x) x = *(&(x))
+#endif
 #endif /* __KLOCWORK__ */
 
+#include "kcompat_vfd.h"
+struct vfd_objects *create_vfd_sysfs(struct pci_dev *pdev, int num_alloc_vfs);
+void destroy_vfd_sysfs(struct pci_dev *pdev, struct vfd_objects *vfd_obj);
+
 /*****************************************************************************/
 /* 2.4.3 => 2.4.0 */
 #if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3) )
@@ -2898,6 +2917,11 @@ extern void _kc_pci_clear_master(struct pci_dev *dev);
 #ifndef PCI_EXP_LNKCTL_ASPMC
 #define  PCI_EXP_LNKCTL_ASPMC  0x0003  /* ASPM Control */
 #endif
+
+#ifndef PCI_EXP_LNKCAP_MLW
+#define PCI_EXP_LNKCAP_MLW     0x000003f0 /* Maximum Link Width */
+#endif
+
 #else /* < 2.6.29 */
 #ifndef HAVE_NET_DEVICE_OPS
 #define HAVE_NET_DEVICE_OPS
@@ -2942,8 +2966,20 @@ static inline void _kc_synchronize_irq(unsigned int a)
 #define nr_cpus_node(node) cpumask_weight(cpumask_of_node(node))
 #endif
 
+#if (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5,5))
+#define HAVE_PCI_DEV_IS_VIRTFN_BIT
+#endif /* RHEL >= 5.5 */
+
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(5,5)))
+static inline bool pci_is_root_bus(struct pci_bus *pbus)
+{
+       return !(pbus->parent);
+}
+#endif
+
 #else /* < 2.6.30 */
 #define HAVE_ASPM_QUIRKS
+#define HAVE_PCI_DEV_IS_VIRTFN_BIT
 #endif /* < 2.6.30 */
 
 /*****************************************************************************/
@@ -3409,6 +3445,19 @@ ssize_t _kc_simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
                                   const void __user *from, size_t count);
 #define simple_write_to_buffer _kc_simple_write_to_buffer
 
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,4)))
+static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
+{
+#ifdef HAVE_PCI_DEV_IS_VIRTFN_BIT
+#ifdef CONFIG_PCI_IOV
+       if (dev->is_virtfn)
+               dev = dev->physfn;
+#endif /* CONFIG_PCI_IOV */
+#endif /* HAVE_PCI_DEV_IS_VIRTFN_BIT */
+       return dev;
+}
+#endif /* ! RHEL >= 6.4 */
+
 #ifndef PCI_EXP_LNKSTA_NLW_SHIFT
 #define PCI_EXP_LNKSTA_NLW_SHIFT 4
 #endif
@@ -4216,6 +4265,7 @@ static inline void _kc_eth_random_addr(u8 *addr)
 
 /******************************************************************************/
 #if ( LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) )
+#include <linux/workqueue.h>
 #ifndef ADVERTISED_40000baseKR4_Full
 /* these defines were all added in one commit, so should be safe
  * to trigger activiation on one define
@@ -4353,6 +4403,11 @@ int __kc_pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val);
 #define pcie_capability_read_word(d,p,v) __kc_pcie_capability_read_word(d,p,v)
 #endif /* pcie_capability_read_word */
 
+#ifndef pcie_capability_read_dword
+int __kc_pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val);
+#define pcie_capability_read_dword(d,p,v) __kc_pcie_capability_read_dword(d,p,v)
+#endif
+
 #ifndef pcie_capability_write_word
 int __kc_pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val);
 #define pcie_capability_write_word(d,p,v) __kc_pcie_capability_write_word(d,p,v)
@@ -4449,6 +4504,37 @@ static inline void hash_del(struct hlist_node *node)
 #define __setup_timer(_timer, _fn, _data, _flags)      \
        setup_timer((_timer), (_fn), (_data))           \
 
+#if ( ! ( RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,7) ) ) && \
+       ( ! ( SLE_VERSION_CODE >= SLE_VERSION(12,0,0) ) )
+
+#ifndef mod_delayed_work
+/**
+ * __mod_delayed_work - modify delay or queue delayed work
+ * @wq: workqueue to use
+ * @dwork: delayed work to queue
+ * @delay: number of jiffies to wait before queueing
+ *
+ * Return: %true if @dwork was pending and was rescheduled;
+ *         %false if it wasn't pending
+ *
+ * Note: the dwork parameter was declared as a void*
+ *       to avoid comptibility problems with early 2.6 kernels
+ *       where struct delayed_work is not declared. Unlike the original
+ *       implementation flags are not preserved and it shouldn't be
+ *       used in the interrupt context.
+ */
+static inline bool __mod_delayed_work(struct workqueue_struct *wq,
+                                   void *dwork,
+                                   unsigned long delay)
+{
+       bool ret = cancel_delayed_work(dwork);
+       queue_delayed_work(wq, dwork, delay);
+       return ret;
+}
+#define mod_delayed_work(wq, dwork, delay) __mod_delayed_work(wq, dwork, delay)
+#endif /* mod_delayed_work */
+
+#endif /* !(RHEL >= 6.7) && !(SLE >= 12.0) */
 #else /* >= 3.7.0 */
 #include <linux/hashtable.h>
 #define HAVE_CONST_STRUCT_PCI_ERROR_HANDLERS
@@ -4498,6 +4584,23 @@ static inline bool __kc_is_link_local_ether_addr(const u8 *addr)
 #define HAVE_SRIOV_CONFIGURE
 #endif
 
+#ifndef PCI_EXP_LNKCAP_SLS_2_5GB
+#define PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */
+#endif
+
+#ifndef PCI_EXP_LNKCAP_SLS_5_0GB
+#define PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */
+#endif
+
+#undef PCI_EXP_LNKCAP2_SLS_2_5GB
+#define PCI_EXP_LNKCAP2_SLS_2_5GB 0x00000002 /* Supported Speed 2.5GT/s */
+
+#undef PCI_EXP_LNKCAP2_SLS_5_0GB
+#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x00000004 /* Supported Speed 5GT/s */
+
+#undef PCI_EXP_LNKCAP2_SLS_8_0GB
+#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x00000008 /* Supported Speed 8GT/s */
+
 #else /* >= 3.8.0 */
 #ifndef __devinit
 #define __devinit
@@ -4752,14 +4855,13 @@ of_get_mac_address(struct device_node __always_unused *np)
 #define HAVE_RHEL7_PCI_RESET_NOTIFY
 #endif /* RHEL >= 7.2 */
 #if (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3))
-#define HAVE_RHEL7_NET_DEVICE_OPS_EXT
+#if (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,5))
 #define HAVE_GENEVE_RX_OFFLOAD
+#endif /* RHEL >=7.3 && RHEL < 7.5 */
+#define HAVE_RHEL7_NET_DEVICE_OPS_EXT
 #if !defined(HAVE_UDP_ENC_TUNNEL) && IS_ENABLED(CONFIG_GENEVE)
 #define HAVE_UDP_ENC_TUNNEL
 #endif
-#ifdef ETHTOOL_GLINKSETTINGS
-#define HAVE_ETHTOOL_25G_BITS
-#endif /* ETHTOOL_GLINKSETTINGS */
 #endif /* RHEL >= 7.3 */
 
 /* new hooks added to net_device_ops_extended in RHEL7.4 */
@@ -4817,8 +4919,19 @@ extern int __kc_dma_set_mask_and_coherent(struct device *dev, u64 mask);
 #ifndef u64_stats_init
 #define u64_stats_init(a) do { } while(0)
 #endif
-#ifndef BIT_ULL
+#undef BIT_ULL
 #define BIT_ULL(n) (1ULL << (n))
+
+#if (!(SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(12,0,0)) && \
+     !(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,0)))
+static inline struct pci_dev *pci_upstream_bridge(struct pci_dev *dev)
+{
+       dev = pci_physfn(dev);
+       if (pci_is_root_bus(dev->bus))
+               return NULL;
+
+       return dev->bus->self;
+}
 #endif
 
 #if (SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(12,1,0))
@@ -4846,7 +4959,6 @@ extern int __kc_dma_set_mask_and_coherent(struct device *dev, u64 mask);
 #else
 #define HAVE_NDO_SELECT_QUEUE_ACCEL
 #endif
-#define HAVE_NET_GET_RANDOM_ONCE
 #define HAVE_HWMON_DEVICE_REGISTER_WITH_GROUPS
 #endif
 
@@ -4898,9 +5010,11 @@ static inline void __kc_skb_set_hash(struct sk_buff __maybe_unused *skb,
 
 #else  /* RHEL_RELEASE_CODE >= 7.0 || SLE_VERSION_CODE >= 12.0 */
 
+#if (!(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5)))
 #ifndef HAVE_VXLAN_RX_OFFLOAD
 #define HAVE_VXLAN_RX_OFFLOAD
 #endif /* HAVE_VXLAN_RX_OFFLOAD */
+#endif
 
 #if !defined(HAVE_UDP_ENC_TUNNEL) && IS_ENABLED(CONFIG_VXLAN)
 #define HAVE_UDP_ENC_TUNNEL
@@ -4943,6 +5057,15 @@ static inline void __kc_ether_addr_copy(u8 *dst, const u8 *src)
 int __kc_ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
                       int target, unsigned short *fragoff, int *flags);
 #define ipv6_find_hdr(a, b, c, d, e) __kc_ipv6_find_hdr((a), (b), (c), (d), (e))
+
+#ifndef OPTIMIZE_HIDE_VAR
+#ifdef __GNUC__
+#define OPTIMIZER_HIDE_VAR(var) __asm__ ("" : "=r" (var) : "0" (var))
+#else
+#include <linux/barrier.h>
+#define OPTIMIZE_HIDE_VAR(var) barrier()
+#endif
+#endif
 #else /* >= 3.14.0 */
 
 /* for ndo_dfwd_ ops add_station, del_station and _start_xmit */
@@ -4965,6 +5088,7 @@ char *_kc_devm_kstrdup(struct device *dev, const char *s, gfp_t gfp);
 #define devm_kstrdup(dev, s, gfp) _kc_devm_kstrdup(dev, s, gfp)
 
 #else
+#define HAVE_NET_GET_RANDOM_ONCE
 #define HAVE_PTP_1588_CLOCK_PINS
 #define HAVE_NETDEV_PORT
 #endif /* 3.15.0 */
@@ -5183,12 +5307,17 @@ static inline void _kc_napi_complete_done(struct napi_struct *napi,
 }
 #define napi_complete_done _kc_napi_complete_done
 
+extern int _kc_bitmap_print_to_pagebuf(bool list, char *buf,
+                                       const unsigned long *maskp,
+                                       int nmaskbits);
+#define bitmap_print_to_pagebuf _kc_bitmap_print_to_pagebuf
+
 #ifndef NETDEV_RSS_KEY_LEN
 #define NETDEV_RSS_KEY_LEN (13 * 4)
 #endif
-#if ( !(RHEL_RELEASE_CODE && \
-       (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,7) && \
-       (RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)))) )
+#if (!(RHEL_RELEASE_CODE && \
+      ((RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6,7) && RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0)) || \
+       (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,2)))))
 #define netdev_rss_key_fill(buffer, len) __kc_netdev_rss_key_fill(buffer, len)
 #endif /* RHEL_RELEASE_CODE */
 extern void __kc_netdev_rss_key_fill(void *buffer, size_t len);
@@ -5198,6 +5327,9 @@ extern void __kc_netdev_rss_key_fill(void *buffer, size_t len);
 #define dma_rmb() rmb()
 #endif
 #ifndef dev_alloc_pages
+#ifndef NUMA_NO_NODE
+#define NUMA_NO_NODE -1
+#endif
 #define dev_alloc_pages(_order) alloc_pages_node(NUMA_NO_NODE, (GFP_ATOMIC | __GFP_COLD | __GFP_COMP | __GFP_MEMALLOC), (_order))
 #endif
 #ifndef dev_alloc_page
@@ -5274,6 +5406,9 @@ static inline struct sk_buff *__kc_napi_alloc_skb(struct napi_struct *napi, unsi
 #ifndef ETH_MODULE_SFF_8436_LEN
 #define ETH_MODULE_SFF_8436_LEN                256
 #endif
+#ifndef writel_relaxed
+#define writel_relaxed writel
+#endif
 #else /* 3.19.0 */
 #define HAVE_NDO_FDB_ADD_VID
 #define HAVE_RXFH_HASHFUNC
@@ -5349,6 +5484,7 @@ extern unsigned int _kc_cpumask_local_spread(unsigned int i, int node);
 #define HAVE_NDO_BRIDGE_GETLINK_NLFLAGS
 #define HAVE_PASSTHRU_FEATURES_CHECK
 #define HAVE_NDO_SET_VF_RSS_QUERY_EN
+#define HAVE_NDO_SET_TX_MAXRATE
 #endif /* 4,1,0 */
 
 /*****************************************************************************/
@@ -5497,8 +5633,8 @@ static inline void csum_replace_by_diff(__sum16 *sum, __wsum diff)
        * sum = csum_fold(csum_add(diff, ~csum_unfold(*sum)));
 }
 #endif
-
-#if !(RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2)))
+#if !(RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7,2))) && \
+       !(SLE_VERSION_CODE && (SLE_VERSION_CODE > SLE_VERSION(12,3,0)))
 static inline void page_ref_inc(struct page *page)
 {
        get_page(page);
@@ -5506,16 +5642,13 @@ static inline void page_ref_inc(struct page *page)
 #else
 #define HAVE_PAGE_COUNT_BULK_UPDATE
 #endif
-
-#else /* 4.6.0 */
-#if (UBUNTU_VERSION_CODE && \
-     UBUNTU_VERSION_CODE >= UBUNTU_VERSION(4,4,0,21)) || \
-     (RHEL_RELEASE_CODE && \
-      RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3)) || \
-     (SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(12,3,0))
-#define HAVE_DEVLINK_SUPPORT
-#endif /* UBUNTU 4,4,0,21, RHEL 7.3, SLES12 SP3 */
+#ifndef IPV4_USER_FLOW
+#define        IPV4_USER_FLOW  0x0d    /* spec only (usr_ip4_spec) */
+#endif
+#else /* >= 4.6.0 */
 #define HAVE_PAGE_COUNT_BULK_UPDATE
+#define HAVE_ETHTOOL_FLOW_UNION_IP6_SPEC
+#define HAVE_PTP_CROSSTIMESTAMP
 #endif /* 4.6.0 */
 
 /*****************************************************************************/
@@ -5524,12 +5657,17 @@ static inline void page_ref_inc(struct page *page)
        (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4))
 #define HAVE_NETIF_TRANS_UPDATE
 #endif
+#if (UBUNTU_VERSION_CODE && \
+     UBUNTU_VERSION_CODE >= UBUNTU_VERSION(4,4,0,21)) || \
+     (RHEL_RELEASE_CODE && \
+      RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4)) || \
+     (SLE_VERSION_CODE && SLE_VERSION_CODE >= SLE_VERSION(12,3,0))
+#define HAVE_DEVLINK_SUPPORT
+#endif /* UBUNTU 4,4,0,21, RHEL 7.4, SLES12 SP3 */
 #else /* 4.7.0 */
+#define HAVE_DEVLINK_SUPPORT
 #define HAVE_NETIF_TRANS_UPDATE
 #define HAVE_ETHTOOL_CONVERT_U32_AND_LINK_MODE
-#ifdef ETHTOOL_GLINKSETTINGS
-#define HAVE_ETHTOOL_25G_BITS
-#endif /* ETHTOOL_GLINKSETTINGS */
 #endif /* 4.7.0 */
 
 /*****************************************************************************/
@@ -5546,6 +5684,10 @@ struct udp_tunnel_info {
 };
 #endif
 
+#if (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5))
+#define HAVE_TCF_EXTS_TO_LIST
+#endif
+
 #if !(SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,3,0))) &&\
        !(RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4))
 static inline int
@@ -5586,32 +5728,99 @@ pci_release_mem_regions(struct pci_dev *pdev)
 #endif /* !SLE_VERSION(12,3,0) */
 #else
 #define HAVE_UDP_ENC_RX_OFFLOAD
+#define HAVE_TCF_EXTS_TO_LIST
 #endif /* 4.8.0 */
 
 /*****************************************************************************/
+#ifdef ETHTOOL_GLINKSETTINGS
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0))
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,3)))
+#define HAVE_ETHTOOL_25G_BITS
+#define HAVE_ETHTOOL_50G_BITS
+#define HAVE_ETHTOOL_100G_BITS
+#endif /* RHEL_RELEASE_VERSION(7,3) */
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,3,0)))
+#define HAVE_ETHTOOL_25G_BITS
+#define HAVE_ETHTOOL_50G_BITS
+#define HAVE_ETHTOOL_100G_BITS
+#endif /* SLE_VERSION(12,3,0) */
+#else
+#define HAVE_ETHTOOL_25G_BITS
+#define HAVE_ETHTOOL_50G_BITS
+#define HAVE_ETHTOOL_100G_BITS
+#endif /* KERNEL_VERSION(4.7.0) */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0))
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4)))
+#define HAVE_ETHTOOL_NEW_50G_BITS
+#endif /* RHEL_RELEASE_VERSION(7,4) */
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,3,0)))
+#define HAVE_ETHTOOL_NEW_50G_BITS
+#endif /* SLE_VERSION(12,3,0) */
+#else
+#define HAVE_ETHTOOL_NEW_50G_BITS
+#endif /* KERNEL_VERSION(4.8.0)*/
+
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0))
 #if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4)))
+#define HAVE_ETHTOOL_NEW_1G_BITS
 #define HAVE_ETHTOOL_NEW_10G_BITS
-#endif /* RHEL */
+#endif /* RHEL_RELEASE_VERSION(7,4) */
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(15,4,0)))
+#define HAVE_ETHTOOL_NEW_1G_BITS
+#define HAVE_ETHTOOL_NEW_10G_BITS
+#endif /* SLE_VERSION(15,4,0) */
 #else
+#define HAVE_ETHTOOL_NEW_1G_BITS
 #define HAVE_ETHTOOL_NEW_10G_BITS
-#endif /* 4.9.0 */
+#endif /* KERNEL_VERSION(4.9.0) */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0))
+#if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4)))
+#define HAVE_ETHTOOL_NEW_2500MB_BITS
+#define HAVE_ETHTOOL_5G_BITS
+#endif /* RHEL_RELEASE_VERSION(7,4) */
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(15,4,0)))
+#define HAVE_ETHTOOL_NEW_2500MB_BITS
+#define HAVE_ETHTOOL_5G_BITS
+#endif /* SLE_VERSION(15,4,0) */
+#else
+#define HAVE_ETHTOOL_NEW_2500MB_BITS
+#define HAVE_ETHTOOL_5G_BITS
+#endif /* KERNEL_VERSION(4.10.0) */
+
+#endif /* ETHTOOL_GLINKSETTINGS */
+
+/*****************************************************************************/
+#ifdef NETIF_F_HW_TC
+#endif /* NETIF_F_HW_TC */
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,9,0))
+#ifdef NETIF_F_HW_TC
+#if (!(RHEL_RELEASE_CODE) && !(SLE_VERSION_CODE) || \
+    (SLE_VERSION_CODE && (SLE_VERSION_CODE < SLE_VERSION(12,3,0))))
+#define HAVE_TC_FLOWER_VLAN_IN_TAGS
+#endif /* !RHEL_RELEASE_CODE && !SLE_VERSION_CODE || SLE_VERSION(12,3,0) */
+#endif /* NETIF_F_HW_TC */
+#endif /* KERNEL_VERSION(4.9.0) */
 
 /*****************************************************************************/
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0))
 #if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,4)))
 #define HAVE_DEV_WALK_API
 #endif
-#if (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,3,0)))
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE == SLE_VERSION(12,3,0)))
 #define HAVE_STRUCT_DMA_ATTRS
+#endif /* (SLES == 12.3.0) */
+#if (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,3,0)))
 #define HAVE_NETDEVICE_MIN_MAX_MTU
-#endif
-
+#endif /* (SLES >= 12.3.0) */
 #if (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5)))
+#define HAVE_STRUCT_DMA_ATTRS
 #define HAVE_RHEL7_EXTENDED_MIN_MAX_MTU
 #define HAVE_NETDEVICE_MIN_MAX_MTU
 #endif
-
 #if (!(SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,3,0))) && \
      !(RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5))))
 #ifndef dma_map_page_attrs
@@ -5653,13 +5862,20 @@ static inline void __page_frag_cache_drain(struct page *page,
        __free_pages(page, compound_order(page));
 }
 #endif /* !SLE_VERSION(12,3,0) && !RHEL_VERSION(7,5) */
-#ifndef page_frag_free
+#if ((SLE_VERSION_CODE && (SLE_VERSION_CODE > SLE_VERSION(12,3,0))) ||\
+     (RHEL_RELEASE_CODE && RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5)))
+#define HAVE_SWIOTLB_SKIP_CPU_SYNC
+#endif
+
+#if ((SLE_VERSION_CODE && (SLE_VERSION_CODE < SLE_VERSION(15,0,0))) ||\
+     (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE <= RHEL_RELEASE_VERSION(7,4))))
 #define page_frag_free __free_page_frag
 #endif
 #ifndef ETH_MIN_MTU
 #define ETH_MIN_MTU 68
 #endif /* ETH_MIN_MTU */
 #else /* >= 4.10 */
+#define HAVE_TC_FLOWER_ENC
 #define HAVE_NETDEVICE_MIN_MAX_MTU
 #define HAVE_SWIOTLB_SKIP_CPU_SYNC
 #define HAVE_NETDEV_TC_RESETS_XPS
@@ -5671,11 +5887,11 @@ static inline void __page_frag_cache_drain(struct page *page,
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0))
 #ifdef CONFIG_NET_RX_BUSY_POLL
 #define HAVE_NDO_BUSY_POLL
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 #if ((SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(12,3,0))) || \
      (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,5))))
 #define HAVE_VOID_NDO_GET_STATS64
-#endif
-#endif
+#endif /* (SLES >= 12.3.0) && (RHEL >= 7.5) */
 #else /* > 4.11 */
 #define HAVE_VOID_NDO_GET_STATS64
 #define HAVE_VM_OPS_FAULT_NO_VMA
@@ -5683,6 +5899,7 @@ static inline void __page_frag_cache_drain(struct page *page,
 
 /*****************************************************************************/
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4,13,0))
+#define  PCI_EXP_LNKCAP_SLS_8_0GB 0x00000003 /* LNKCAP2 SLS Vector bit 2 */
 #else /* > 4.13 */
 #define HAVE_HWTSTAMP_FILTER_NTP_ALL
 #define HAVE_NDO_SETUP_TC_CHAIN_INDEX
@@ -5692,10 +5909,12 @@ static inline void __page_frag_cache_drain(struct page *page,
 
 /*****************************************************************************/
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0))
+#ifdef ETHTOOL_GLINKSETTINGS
 #ifndef ethtool_link_ksettings_del_link_mode
 #define ethtool_link_ksettings_del_link_mode(ptr, name, mode)          \
        __clear_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, (ptr)->link_modes.name)
 #endif
+#endif /* ETHTOOL_GLINKSETTINGS */
 #if (SLE_VERSION_CODE && (SLE_VERSION_CODE >= SLE_VERSION(15,0,0)))
 #define HAVE_NDO_SETUP_TC_REMOVE_TC_TO_NETDEV
 #endif
@@ -5715,18 +5934,269 @@ static inline void __page_frag_cache_drain(struct page *page,
 #define from_timer(var, callback_timer, timer_fieldname) \
        container_of(callback_timer, typeof(*var), timer_fieldname)
 
+#ifndef xdp_do_flush_map
+#define xdp_do_flush_map() do {} while (0)
+#endif
+struct _kc_xdp_buff {
+       void *data;
+       void *data_end;
+       void *data_hard_start;
+};
+#define xdp_buff _kc_xdp_buff
+struct _kc_bpf_prog {
+};
+#define bpf_prog _kc_bpf_prog
 #else /* > 4.14 */
+#define HAVE_XDP_SUPPORT
 #define HAVE_NDO_SETUP_TC_REMOVE_TC_TO_NETDEV
 #endif /* 4.14.0 */
 
+/*****************************************************************************/
+#ifndef ETHTOOL_GLINKSETTINGS
+
+#define __ETHTOOL_LINK_MODE_MASK_NBITS 32
+#define ETHTOOL_LINK_MASK_SIZE BITS_TO_LONGS(__ETHTOOL_LINK_MODE_MASK_NBITS)
+
+/**
+ * struct ethtool_link_ksettings
+ * @link_modes: supported and advertising, single item arrays
+ * @link_modes.supported: bitmask of supported link speeds
+ * @link_modes.advertising: bitmask of currently advertised speeds
+ * @base: base link details
+ * @base.speed: current link speed
+ * @base.port: current port type
+ * @base.duplex: current duplex mode
+ * @base.autoneg: current autonegotiation settings
+ *
+ * This struct and the following macros provide a way to support the old
+ * ethtool get/set_settings API on older kernels, but in the style of the new
+ * GLINKSETTINGS API.  In this way, the same code can be used to support both
+ * APIs as seemlessly as possible.
+ *
+ * It should be noted the old API only has support up to the first 32 bits.
+ */
+struct ethtool_link_ksettings {
+       struct {
+               u32 speed;
+               u8 port;
+               u8 duplex;
+               u8 autoneg;
+       } base;
+       struct {
+               unsigned long supported[ETHTOOL_LINK_MASK_SIZE];
+               unsigned long advertising[ETHTOOL_LINK_MASK_SIZE];
+       } link_modes;
+};
+
+#define ETHTOOL_LINK_NAME_advertising(mode) ADVERTISED_ ## mode
+#define ETHTOOL_LINK_NAME_supported(mode) SUPPORTED_ ## mode
+#define ETHTOOL_LINK_NAME(name) ETHTOOL_LINK_NAME_ ## name
+#define ETHTOOL_LINK_CONVERT(name, mode) ETHTOOL_LINK_NAME(name)(mode)
+
+/**
+ * ethtool_link_ksettings_zero_link_mode
+ * @ptr: ptr to ksettings struct
+ * @name: supported or advertising
+ */
+#define ethtool_link_ksettings_zero_link_mode(ptr, name)\
+       (*((ptr)->link_modes.name) = 0x0)
+
+/**
+ * ethtool_link_ksettings_add_link_mode
+ * @ptr: ptr to ksettings struct
+ * @name: supported or advertising
+ * @mode: link mode to add
+ */
+#define ethtool_link_ksettings_add_link_mode(ptr, name, mode)\
+       (*((ptr)->link_modes.name) |= (typeof(*((ptr)->link_modes.name)))ETHTOOL_LINK_CONVERT(name, mode))
+
+/**
+ * ethtool_link_ksettings_del_link_mode
+ * @ptr: ptr to ksettings struct
+ * @name: supported or advertising
+ * @mode: link mode to delete
+ */
+#define ethtool_link_ksettings_del_link_mode(ptr, name, mode)\
+       (*((ptr)->link_modes.name) &= ~(typeof(*((ptr)->link_modes.name)))ETHTOOL_LINK_CONVERT(name, mode))
+
+/**
+ * ethtool_link_ksettings_test_link_mode
+ * @ptr: ptr to ksettings struct
+ * @name: supported or advertising
+ * @mode: link mode to add
+ */
+#define ethtool_link_ksettings_test_link_mode(ptr, name, mode)\
+       (!!(*((ptr)->link_modes.name) & ETHTOOL_LINK_CONVERT(name, mode)))
+
+/**
+ * _kc_ethtool_ksettings_to_cmd - Convert ethtool_link_ksettings to ethtool_cmd
+ * @ks: ethtool_link_ksettings struct
+ * @cmd: ethtool_cmd struct
+ *
+ * Convert an ethtool_link_ksettings structure into the older ethtool_cmd
+ * structure. We provide this in kcompat.h so that drivers can easily
+ * implement the older .{get|set}_settings as wrappers around the new api.
+ * Hence, we keep it prefixed with _kc_ to make it clear this isn't actually
+ * a real function in the kernel.
+ */
+static inline void
+_kc_ethtool_ksettings_to_cmd(struct ethtool_link_ksettings *ks,
+                            struct ethtool_cmd *cmd)
+{
+       cmd->supported = (u32)ks->link_modes.supported[0];
+       cmd->advertising = (u32)ks->link_modes.advertising[0];
+       ethtool_cmd_speed_set(cmd, ks->base.speed);
+       cmd->duplex = ks->base.duplex;
+       cmd->autoneg = ks->base.autoneg;
+       cmd->port = ks->base.port;
+}
+
+#endif /* !ETHTOOL_GLINKSETTINGS */
+
+/*****************************************************************************/
+#if ((LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)) || \
+     (SLE_VERSION_CODE && (SLE_VERSION_CODE <= SLE_VERSION(12,3,0))) || \
+     (RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE <= RHEL_RELEASE_VERSION(7,5))))
+#define phy_speed_to_str _kc_phy_speed_to_str
+const char *_kc_phy_speed_to_str(int speed);
+#else /* (LINUX >= 4.14.0) || (SLES > 12.3.0) || (RHEL > 7.5) */
+#include <linux/phy.h>
+#endif /* (LINUX < 4.14.0) || (SLES <= 12.3.0) || (RHEL <= 7.5) */
+
 /*****************************************************************************/
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0))
+#if !(RHEL_RELEASE_CODE && (RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(7,6)))
 #define TC_SETUP_QDISC_MQPRIO TC_SETUP_MQPRIO
-#ifdef ETHTOOL_GLINKSETTINGS
+#endif
 void _kc_ethtool_intersect_link_masks(struct ethtool_link_ksettings *dst,
                                      struct ethtool_link_ksettings *src);
 #define ethtool_intersect_link_masks _kc_ethtool_intersect_link_masks
-#endif /* ETHTOOL_GLINKSETTINGS */
+#else /* >= 4.15 */
+#define HAVE_NDO_BPF
+#define HAVE_XDP_BUFF_DATA_META
+#define HAVE_TC_CB_AND_SETUP_QDISC_MQPRIO
 #endif /* 4.15.0 */
 
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0))
+#define pci_printk(level, pdev, fmt, arg...) \
+       dev_printk(level, &(pdev)->dev, fmt, ##arg)
+#define pci_emerg(pdev, fmt, arg...)   dev_emerg(&(pdev)->dev, fmt, ##arg)
+#define pci_alert(pdev, fmt, arg...)   dev_alert(&(pdev)->dev, fmt, ##arg)
+#define pci_crit(pdev, fmt, arg...)    dev_crit(&(pdev)->dev, fmt, ##arg)
+#define pci_err(pdev, fmt, arg...)     dev_err(&(pdev)->dev, fmt, ##arg)
+#define pci_warn(pdev, fmt, arg...)    dev_warn(&(pdev)->dev, fmt, ##arg)
+#define pci_notice(pdev, fmt, arg...)  dev_notice(&(pdev)->dev, fmt, ##arg)
+#define pci_info(pdev, fmt, arg...)    dev_info(&(pdev)->dev, fmt, ##arg)
+#define pci_dbg(pdev, fmt, arg...)     dev_dbg(&(pdev)->dev, fmt, ##arg)
+
+#ifndef array_index_nospec
+static inline unsigned long _kc_array_index_mask_nospec(unsigned long index,
+                                                       unsigned long size)
+{
+       /*
+        * Always calculate and emit the mask even if the compiler
+        * thinks the mask is not needed. The compiler does not take
+        * into account the value of @index under speculation.
+        */
+       OPTIMIZER_HIDE_VAR(index);
+       return ~(long)(index | (size - 1UL - index)) >> (BITS_PER_LONG - 1);
+}
+
+#define array_index_nospec(index, size)                                        \
+({                                                                     \
+       typeof(index) _i = (index);                                     \
+       typeof(size) _s = (size);                                       \
+       unsigned long _mask = _kc_array_index_mask_nospec(_i, _s);      \
+                                                                       \
+       BUILD_BUG_ON(sizeof(_i) > sizeof(long));                        \
+       BUILD_BUG_ON(sizeof(_s) > sizeof(long));                        \
+                                                                       \
+       (typeof(_i)) (_i & _mask);                                      \
+})
+#endif /* array_index_nospec */
+#else /* >= 4.16 */
+#include <linux/nospec.h>
+#define HAVE_XDP_BUFF_RXQ
+#endif /* 4.16.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0))
+#include <linux/pci_regs.h>
+#include <linux/pci.h>
+#define PCIE_SPEED_16_0GT 0x17
+#define PCI_EXP_LNKCAP_SLS_16_0GB 0x00000004 /* LNKCAP2 SLS Vector bit 3 */
+#define PCI_EXP_LNKSTA_CLS_16_0GB 0x0004 /* Current Link Speed 16.0GT/s */
+#define PCI_EXP_LNKCAP2_SLS_16_0GB 0x00000010 /* Supported Speed 16GT/s */
+void _kc_pcie_print_link_status(struct pci_dev *dev);
+#define pcie_print_link_status _kc_pcie_print_link_status
+#endif /* 4.17.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0))
+#ifdef NETIF_F_HW_L2FW_DOFFLOAD
+#include <linux/if_macvlan.h>
+#ifndef macvlan_supports_dest_filter
+#define macvlan_supports_dest_filter _kc_macvlan_supports_dest_filter
+static inline bool _kc_macvlan_supports_dest_filter(struct net_device *dev)
+{
+       struct macvlan_dev *macvlan = netdev_priv(dev);
+
+       return macvlan->mode == MACVLAN_MODE_PRIVATE ||
+              macvlan->mode == MACVLAN_MODE_VEPA ||
+              macvlan->mode == MACVLAN_MODE_BRIDGE;
+}
+#endif
+
+#ifndef macvlan_accel_priv
+#define macvlan_accel_priv _kc_macvlan_accel_priv
+static inline void *_kc_macvlan_accel_priv(struct net_device *dev)
+{
+       struct macvlan_dev *macvlan = netdev_priv(dev);
+
+       return macvlan->fwd_priv;
+}
+#endif
+
+#ifndef macvlan_release_l2fw_offload
+#define macvlan_release_l2fw_offload _kc_macvlan_release_l2fw_offload
+static inline int _kc_macvlan_release_l2fw_offload(struct net_device *dev)
+{
+       struct macvlan_dev *macvlan = netdev_priv(dev);
+
+       macvlan->fwd_priv = NULL;
+       return dev_uc_add(macvlan->lowerdev, dev->dev_addr);
+}
+#endif
+#endif /* NETIF_F_HW_L2FW_DOFFLOAD */
+#ifdef AF_XDP_SUPPORT
+#undef AF_XDP_SUPPORT
+#endif /* AF_XDP_SUPPORT */
+#else
+#define HAVE_XDP_FRAME_STRUCT
+#define HAVE_NDO_XDP_XMIT_BULK_AND_FLAGS
+#define NO_NDO_XDP_FLUSH
+#endif /* 4.18.0 */
+
+/*****************************************************************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0))
+#ifdef ETHTOOL_GLINKSETTINGS
+#define ethtool_ks_clear(ptr, name) \
+       ethtool_link_ksettings_zero_link_mode(ptr, name)
+#define ethtool_ks_add_mode(ptr, name, mode) \
+       ethtool_link_ksettings_add_link_mode(ptr, name, mode)
+#define ethtool_ks_del_mode(ptr, name, mode) \
+       ethtool_link_ksettings_del_link_mode(ptr, name, mode)
+#define ethtool_ks_test(ptr, name, mode) \
+       ethtool_link_ksettings_test_link_mode(ptr, name, mode)
+#endif /* ETHTOOL_GLINKSETTINGS */
+#define HAVE_NETPOLL_CONTROLLER
+#else /* >= 4.19.0 */
+#define HAVE_TCF_BLOCK_CB_REGISTER_EXTACK
+#define NO_NETDEV_BPF_PROG_ATTACHED
+#define HAVE_NDO_SELECT_QUEUE_SB_DEV
+#undef HAVE_TCF_EXTS_TO_LIST
+#define HAVE_TCF_EXTS_FOR_EACH_ACTION
+#endif /* 4.19.0 */
+
 #endif /* _KCOMPAT_H_ */
diff --git a/i40e-dkms/i40e-2.7.29/src/kcompat_vfd.c b/i40e-dkms/i40e-2.7.29/src/kcompat_vfd.c
new file mode 100644 (file)
index 0000000..5e35f68
--- /dev/null
@@ -0,0 +1,1835 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#include "kcompat.h"
+#include "kcompat_vfd.h"
+
+#define to_dev(obj) container_of(obj, struct device, kobj)
+
+const struct vfd_ops *vfd_ops = NULL;
+
+static int __get_pdev_and_vfid(struct kobject *kobj, struct pci_dev **pdev,
+                              int *vf_id)
+{
+       struct device *dev;
+       int ret = 0;
+
+       if (!kobj->parent->parent)
+               return -EINVAL;
+
+       /* get pdev */
+       dev = to_dev(kobj->parent->parent);
+       *pdev = to_pci_dev(dev);
+
+       /* get vf_id */
+       if (kstrtoint(kobj->name, 10, vf_id) != 0) {
+               dev_err(&(*pdev)->dev, "Failed to convert %s to vf_id\n",
+                       kobj->name);
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+/**
+ * __parse_bool_data - helper function to parse boolean data
+ * @pdev:      PCI device information struct
+ * @buff:      buffer with input data
+ * @attr_name: name of the attribute
+ * @data:      pointer to output data
+ */
+static int __parse_bool_data(struct pci_dev *pdev, const char *buff,
+                            const char *attr_name, bool *data)
+{
+       if (sysfs_streq("on", buff)) {
+               *data = true;
+       } else if (sysfs_streq("off", buff)) {
+               *data = false;
+       } else {
+               dev_err(&pdev->dev, "set %s: invalid input string", attr_name);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/**
+ * __parse_egress_ingress_input - helper function for ingress/egress_mirror attributes
+ * @pdev:      PCI device information struct
+ * @buff:      buffer with input data
+ * @attr_name: name of the attribute
+ * @data_new:  pointer to input data merged with the old data
+ * @data_old:  pointer to old data of the attribute
+ *
+ * Get the input data for egress_mirror or ingress_mirror attribute in the form
+ * "add <number>" or "rem <number>".
+ * Set the output data to off if in "rem <number>", <number> matches old data.
+ *
+ */
+static int __parse_egress_ingress_input(struct pci_dev *pdev, const char *buff,
+                                       const char *attr_name, int *data_new,
+                                       int *data_old)
+{
+       int ret = 0;
+       char *p;
+
+       if (strstr(buff, "add")) {
+               p = strstr(buff, "add");
+
+               ret = kstrtoint(p + sizeof("add"), 10, data_new);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "add %s: input error %d\n", attr_name, ret);
+                       return ret;
+               }
+       } else if (strstr(buff, "rem")) {
+               p = strstr(buff, "rem");
+
+               ret = kstrtoint(p + sizeof("rem"), 10, data_new);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "rem %s: input error %d\n", attr_name, ret);
+                       return ret;
+               }
+
+               if (*data_new == *data_old) {
+                       if (!strcmp(attr_name, "egress_mirror"))
+                               *data_new = VFD_EGRESS_MIRROR_OFF;
+                       else if (!strcmp(attr_name, "ingress_mirror"))
+                               *data_new = VFD_INGRESS_MIRROR_OFF;
+               } else {
+                       dev_err(&pdev->dev,
+                               "rem %s: input doesn't match current value",
+                               attr_name);
+                       return -EINVAL;
+               }
+       } else {
+               dev_err(&pdev->dev, "set %s: invalid input string", attr_name);
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+/**
+ * __parse_add_rem_bitmap - helper function to parse bitmap data
+ * @pdev:      PCI device information struct
+ * @buff:      buffer with input data
+ * @attr_name: name of the attribute
+ * @data_new:  pointer to input data merged with the old data
+ * @data_old:  pointer to old data of the attribute
+ *
+ * If passed add: set data_new to "data_old || data_input"
+ * If passed rem: set data_new to "data_old || ~data_input"
+ */
+static int __parse_add_rem_bitmap(struct pci_dev *pdev, const char *buff,
+                                 const char *attr_name,
+                                 unsigned long *data_new,
+                                 unsigned long *data_old)
+{
+       int ret = 0;
+       char *p;
+
+       if (strstr(buff, "add")) {
+               p = strstr(buff, "add");
+               bitmap_zero(data_new, VLAN_N_VID);
+
+               ret = bitmap_parselist(p + sizeof("add"), data_new, VLAN_N_VID);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "add %s: input error %d\n", attr_name, ret);
+                       return ret;
+               }
+
+               bitmap_or(data_new, data_new, data_old, VLAN_N_VID);
+       } else if (strstr(buff, "rem")) {
+               p = strstr(buff, "rem");
+               bitmap_zero(data_new, VLAN_N_VID);
+
+               ret = bitmap_parselist(p + sizeof("rem"), data_new, VLAN_N_VID);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "rem %s: input error %d\n", attr_name, ret);
+                       return ret;
+               }
+
+               /* new = old & ~rem */
+               bitmap_andnot(data_new, data_old, data_new, VLAN_N_VID);
+       } else {
+               dev_err(&pdev->dev, "set %s: invalid input string", attr_name);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* Handlers for each VFd operation */
+
+/**
+ * vfd_trunk_show - handler for trunk show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ *
+ * Get current data from driver and copy to buffer
+ **/
+static ssize_t vfd_trunk_show(struct kobject *kobj,
+                             struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+
+       DECLARE_BITMAP(data, VLAN_N_VID);
+       bitmap_zero(data, VLAN_N_VID);
+
+       if (!vfd_ops->get_trunk)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_trunk(pdev, vf_id, data);
+       if (ret)
+               ret = bitmap_print_to_pagebuf(1, buff, data, VLAN_N_VID);
+
+       return ret;
+}
+
+/**
+ * vfd_trunk_store - handler for trunk store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ *
+ * Get current data from driver, compose new data based on input values
+ * depending on "add" or "rem" command, and pass new data to the driver to set.
+ *
+ * On success return count, indicating that we used the whole buffer. On
+ * failure return a negative error condition.
+ **/
+static ssize_t vfd_trunk_store(struct kobject *kobj,
+                              struct kobj_attribute *attr,
+                              const char *buff, size_t count)
+{
+       unsigned long *data_old, *data_new;
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+
+       if (!vfd_ops->set_trunk || !vfd_ops->get_trunk)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       data_old = kcalloc(BITS_TO_LONGS(VLAN_N_VID), sizeof(unsigned long),
+                          GFP_KERNEL);
+       if (!data_old)
+               return -ENOMEM;
+       data_new = kcalloc(BITS_TO_LONGS(VLAN_N_VID), sizeof(unsigned long),
+                          GFP_KERNEL);
+       if (!data_new) {
+               kfree(data_old);
+               return -ENOMEM;
+       }
+
+       ret = vfd_ops->get_trunk(pdev, vf_id, data_old);
+       if (ret < 0)
+               goto err_free;
+
+       ret = __parse_add_rem_bitmap(pdev, buff, "trunk", data_new, data_old);
+       if (ret)
+               goto err_free;
+
+       if (!bitmap_equal(data_new, data_old, VLAN_N_VID))
+               ret = vfd_ops->set_trunk(pdev, vf_id, data_new);
+
+err_free:
+       kfree(data_old);
+       kfree(data_new);
+       return ret ? ret : count;
+}
+
+/**
+ * vfd_vlan_mirror_show - handler for vlan_mirror show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ *
+ * Get current data from driver and copy to buffer
+ **/
+static ssize_t vfd_vlan_mirror_show(struct kobject *kobj,
+                                   struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+
+       DECLARE_BITMAP(data, VLAN_N_VID);
+       bitmap_zero(data, VLAN_N_VID);
+
+       if (!vfd_ops->get_vlan_mirror)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_vlan_mirror(pdev, vf_id, data);
+       if (ret)
+               ret = bitmap_print_to_pagebuf(1, buff, data, VLAN_N_VID);
+
+       return ret;
+}
+
+/**
+ * vfd_vlan_mirror_store - handler for vlan_mirror store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ *
+ * Get current data from driver, compose new data based on input values
+ * depending on "add" or "rem" command, and pass new data to the driver to set.
+ *
+ * On success return count, indicating that we used the whole buffer. On
+ * failure return a negative error condition.
+ **/
+static ssize_t vfd_vlan_mirror_store(struct kobject *kobj,
+                                    struct kobj_attribute *attr,
+                                    const char *buff, size_t count)
+{
+       unsigned long *data_old, *data_new;
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+
+       if (!vfd_ops->set_vlan_mirror || !vfd_ops->get_vlan_mirror)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       data_old = kcalloc(BITS_TO_LONGS(VLAN_N_VID), sizeof(unsigned long),
+                          GFP_KERNEL);
+       if (!data_old)
+               return -ENOMEM;
+       data_new = kcalloc(BITS_TO_LONGS(VLAN_N_VID), sizeof(unsigned long),
+                          GFP_KERNEL);
+       if (!data_new) {
+               kfree(data_old);
+               return -ENOMEM;
+       }
+
+       ret = vfd_ops->get_vlan_mirror(pdev, vf_id, data_old);
+       if (ret < 0)
+               goto err_free;
+
+       ret = __parse_add_rem_bitmap(pdev, buff, "vlan_mirror",
+                                    data_new, data_old);
+       if (ret)
+               goto err_free;
+
+       if (!bitmap_equal(data_new, data_old, VLAN_N_VID))
+               ret = vfd_ops->set_vlan_mirror(pdev, vf_id, data_new);
+
+err_free:
+       kfree(data_old);
+       kfree(data_new);
+       return ret ? ret : count;
+}
+
+/**
+ * vfd_egress_mirror_show - handler for egress_mirror show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_egress_mirror_show(struct kobject *kobj,
+                                     struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       int data;
+
+       if (!vfd_ops->get_egress_mirror)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_egress_mirror(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       if (data == VFD_EGRESS_MIRROR_OFF)
+               ret = scnprintf(buff, PAGE_SIZE, "off\n");
+       else
+               ret = scnprintf(buff, PAGE_SIZE, "%u\n", data);
+
+       return ret;
+}
+
+/**
+ * vfd_egress_mirror_store - handler for egress_mirror store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ **/
+static ssize_t vfd_egress_mirror_store(struct kobject *kobj,
+                                      struct kobj_attribute *attr,
+                                      const char *buff, size_t count)
+{
+       int data_new, data_old;
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+
+       if (!vfd_ops->set_egress_mirror || !vfd_ops->get_egress_mirror)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_egress_mirror(pdev, vf_id, &data_old);
+       if (ret < 0)
+               return ret;
+
+       ret = __parse_egress_ingress_input(pdev, buff, "egress_mirror",
+                                          &data_new, &data_old);
+       if (ret)
+               return ret;
+
+       if (data_new != data_old)
+               ret = vfd_ops->set_egress_mirror(pdev, vf_id, data_new);
+
+       return ret ? ret : count;
+}
+
+/**
+ * vfd_ingress_mirror_show - handler for ingress_mirror show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_ingress_mirror_show(struct kobject *kobj,
+                                      struct kobj_attribute *attr,
+                                      char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       int data;
+
+       if (!vfd_ops->get_ingress_mirror)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_ingress_mirror(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       if (data == VFD_INGRESS_MIRROR_OFF)
+               ret = scnprintf(buff, PAGE_SIZE, "off\n");
+       else
+               ret = scnprintf(buff, PAGE_SIZE, "%u\n", data);
+
+       return ret;
+}
+
+/**
+ * vfd_ingress_mirror_store - handler for ingress_mirror store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ **/
+static ssize_t vfd_ingress_mirror_store(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       const char *buff, size_t count)
+{
+       int data_new, data_old;
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+
+       if (!vfd_ops->set_ingress_mirror || !vfd_ops->get_ingress_mirror)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_ingress_mirror(pdev, vf_id, &data_old);
+       if (ret < 0)
+               return ret;
+
+       ret = __parse_egress_ingress_input(pdev, buff, "ingress_mirror",
+                                          &data_new, &data_old);
+       if (ret)
+               return ret;
+
+       if (data_new != data_old)
+               ret = vfd_ops->set_ingress_mirror(pdev, vf_id, data_new);
+
+       return ret ? ret : count;
+}
+
+/**
+ * vfd_mac_anti_spoof_show - handler for mac_anti_spoof show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_mac_anti_spoof_show(struct kobject *kobj,
+                                      struct kobj_attribute *attr,
+                                      char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       bool data;
+
+       if (!vfd_ops->get_mac_anti_spoof)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_mac_anti_spoof(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       if (data)
+               ret = scnprintf(buff, PAGE_SIZE, "on\n");
+       else
+               ret = scnprintf(buff, PAGE_SIZE, "off\n");
+
+       return ret;
+}
+
+/**
+ * vfd_mac_anti_spoof_store - handler for mac_anti_spoof store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ *
+ * On success return count, indicating that we used the whole buffer. On
+ * failure return a negative error condition.
+ **/
+static ssize_t vfd_mac_anti_spoof_store(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       const char *buff, size_t count)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       bool data_new, data_old;
+
+       if (!vfd_ops->set_mac_anti_spoof || !vfd_ops->get_mac_anti_spoof)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_mac_anti_spoof(pdev, vf_id, &data_old);
+       if (ret < 0)
+               return ret;
+
+       ret = __parse_bool_data(pdev, buff, "mac_anti_spoof", &data_new);
+       if (ret)
+               return ret;
+
+       if (data_new != data_old)
+               ret = vfd_ops->set_mac_anti_spoof(pdev, vf_id, data_new);
+
+       return ret ? ret : count;
+}
+
+/**
+ * vfd_vlan_anti_spoof_show - handler for vlan_anti_spoof show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_vlan_anti_spoof_show(struct kobject *kobj,
+                                       struct kobj_attribute *attr,
+                                       char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       bool data;
+
+       if (!vfd_ops->get_vlan_anti_spoof)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_vlan_anti_spoof(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       if (data)
+               ret = scnprintf(buff, PAGE_SIZE, "on\n");
+       else
+               ret = scnprintf(buff, PAGE_SIZE, "off\n");
+
+       return ret;
+}
+
+/**
+ * vfd_vlan_anti_spoof_store - handler for vlan_anti_spoof store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ *
+ * On success return count, indicating that we used the whole buffer. On
+ * failure return a negative error condition.
+ **/
+static ssize_t vfd_vlan_anti_spoof_store(struct kobject *kobj,
+                                        struct kobj_attribute *attr,
+                                        const char *buff, size_t count)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       bool data_new, data_old;
+
+       if (!vfd_ops->set_vlan_anti_spoof || !vfd_ops->get_vlan_anti_spoof)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_vlan_anti_spoof(pdev, vf_id, &data_old);
+       if (ret < 0)
+               return ret;
+
+       ret = __parse_bool_data(pdev, buff, "vlan_anti_spoof", &data_new);
+       if (ret)
+               return ret;
+
+       if (data_new != data_old)
+               ret = vfd_ops->set_vlan_anti_spoof(pdev, vf_id, data_new);
+
+       return ret ? ret : count;
+}
+
+/**
+ * vfd_allow_untagged_show - handler for allow_untagged show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_allow_untagged_show(struct kobject *kobj,
+                                      struct kobj_attribute *attr,
+                                      char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       bool data;
+
+       if (!vfd_ops->get_allow_untagged)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_allow_untagged(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       if (data)
+               ret = scnprintf(buff, PAGE_SIZE, "on\n");
+       else
+               ret = scnprintf(buff, PAGE_SIZE, "off\n");
+
+       return ret;
+}
+
+/**
+ * vfd_allow_untagged_store - handler for allow_untagged store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ **/
+static ssize_t vfd_allow_untagged_store(struct kobject *kobj,
+                                 struct kobj_attribute *attr,
+                                 const char *buff, size_t count)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       bool data_new, data_old;
+
+       if (!vfd_ops->set_allow_untagged || !vfd_ops->get_allow_untagged)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_allow_untagged(pdev, vf_id, &data_old);
+       if (ret < 0)
+               return ret;
+
+       ret = __parse_bool_data(pdev, buff, "allow_untagged", &data_new);
+       if (ret)
+               return ret;
+
+       if (data_new != data_old)
+               ret = vfd_ops->set_allow_untagged(pdev, vf_id, data_new);
+
+       return ret ? ret : count;
+}
+
+/**
+ * vfd_loopback_show - handler for loopback show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_loopback_show(struct kobject *kobj,
+                                struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       bool data;
+
+       if (!vfd_ops->get_loopback)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_loopback(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       if (data)
+               ret = scnprintf(buff, PAGE_SIZE, "on\n");
+       else
+               ret = scnprintf(buff, PAGE_SIZE, "off\n");
+
+       return ret;
+}
+
+/**
+ * vfd_loopback_store - handler for loopback store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ **/
+static ssize_t vfd_loopback_store(struct kobject *kobj,
+                                 struct kobj_attribute *attr,
+                                 const char *buff, size_t count)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       bool data_new, data_old;
+
+       if (!vfd_ops->set_loopback || !vfd_ops->get_loopback)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_loopback(pdev, vf_id, &data_old);
+       if (ret < 0)
+               return ret;
+
+       ret = __parse_bool_data(pdev, buff, "loopback", &data_new);
+       if (ret)
+               return ret;
+
+       if (data_new != data_old)
+               ret = vfd_ops->set_loopback(pdev, vf_id, data_new);
+
+       return ret ? ret : count;
+}
+
+/**
+ * vfd_mac_show - handler for mac show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_mac_show(struct kobject *kobj, struct kobj_attribute *attr,
+                           char *buff)
+{
+       u8 macaddr[ETH_ALEN];
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+
+       if (!vfd_ops->get_mac)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_mac(pdev, vf_id, macaddr);
+       if (ret < 0)
+               return ret;
+
+       ret = scnprintf(buff, PAGE_SIZE, "%pM\n", macaddr);
+
+       return ret;
+}
+
+/**
+ * vfd_mac_store - handler for mac store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ **/
+static ssize_t vfd_mac_store(struct kobject *kobj,
+                            struct kobj_attribute *attr,
+                            const char *buff, size_t count)
+{
+       u8 macaddr[ETH_ALEN];
+       u8 macaddr_old[ETH_ALEN];
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+
+       if (!vfd_ops->set_mac || !vfd_ops->get_mac)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_mac(pdev, vf_id, macaddr_old);
+       if (ret < 0)
+               return ret;
+
+       ret = sscanf(buff, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+                    &macaddr[0], &macaddr[1], &macaddr[2],
+                    &macaddr[3], &macaddr[4], &macaddr[5]);
+
+       if (ret != 6)
+               return -EINVAL;
+
+       if (!ether_addr_equal(macaddr, macaddr_old))
+               ret = vfd_ops->set_mac(pdev, vf_id, macaddr);
+
+       return ret ? ret : count;
+}
+
+/**
+ * vfd_mac_list_show - handler for mac_list show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ *
+ * This function also frees the memory allocated for mac_list in another function.
+ *
+ **/
+static ssize_t vfd_mac_list_show(struct kobject *kobj,
+                                struct kobj_attribute *attr, char *buff)
+{
+       struct list_head *pos, *n;
+       struct pci_dev *pdev;
+       int vf_id, ret;
+       char *written;
+       LIST_HEAD(mac_list);
+
+       if (!vfd_ops->get_mac_list)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_mac_list(pdev, vf_id, &mac_list);
+       if (ret < 0)
+               goto err_free;
+
+       written = buff;
+        list_for_each_safe(pos, n, &mac_list) {
+                struct vfd_macaddr *mac = NULL;
+
+                mac = list_entry(pos, struct vfd_macaddr, list);
+               if (list_is_last(pos, &mac_list))
+                       ret += scnprintf(written, PAGE_SIZE, "%pM\n", mac->mac);
+               else
+                       ret += scnprintf(written, PAGE_SIZE, "%pM,", mac->mac);
+
+               written += 3*ETH_ALEN;
+        }
+
+err_free:
+        list_for_each_safe(pos, n, &mac_list) {
+                struct vfd_macaddr *mac = NULL;
+
+                mac = list_entry(pos, struct vfd_macaddr, list);
+                list_del(pos);
+                kfree(mac);
+        }
+       return ret;
+}
+
+/**
+ * vfd_mac_list_store - handler for mac_list store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ *
+ * Get input mac list into the linked list and depending on "add" or "rem" command
+ * pass the input mac list to the driver to either add or remove macs to the list.
+ *
+ * This function also frees the memory allocated for mac_list in another function.
+ *
+ **/
+static ssize_t vfd_mac_list_store(struct kobject *kobj,
+                                 struct kobj_attribute *attr,
+                                 const char *buff, size_t count)
+{
+       struct list_head *pos, *n;
+       struct pci_dev *pdev;
+       u8 macaddr[ETH_ALEN];
+       int vf_id, ret;
+       size_t shift;
+       bool add;
+       LIST_HEAD(mac_list_inp);
+
+       if (!vfd_ops->add_macs_to_list || !vfd_ops->rem_macs_from_list)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       if (strstr(buff, "add")) {
+               shift = sizeof("add");
+               add = true;
+       } else if (strstr(buff, "rem")) {
+               shift = sizeof("rem");
+               add = false;
+       } else {
+               dev_err(&pdev->dev, "Invalid input string");
+               ret = -EINVAL;
+               goto err_free;
+       }
+
+       /* Get input data */
+       for (;;) {
+               struct vfd_macaddr *mac_new;
+
+               if (*(buff + shift) == ' ' || *(buff + shift) == ',') {
+                       shift++;
+                       continue;
+               }
+
+               ret = sscanf(buff + shift,
+                            "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+                            &macaddr[0], &macaddr[1], &macaddr[2],
+                            &macaddr[3], &macaddr[4], &macaddr[5]);
+
+               if (ret != 6)
+                       break;
+
+               if (!is_valid_ether_addr(macaddr)) {
+                       shift += 3*ETH_ALEN;
+                       continue;
+               }
+
+               mac_new = kmalloc(sizeof(struct vfd_macaddr), GFP_KERNEL);
+               if (!mac_new) {
+                       ret = -ENOMEM;
+                       goto err_free;
+               }
+
+               ether_addr_copy(mac_new->mac, macaddr);
+               list_add(&mac_new->list, &mac_list_inp);
+
+               shift += 3*ETH_ALEN;
+       }
+
+       if (add)
+               ret = vfd_ops->add_macs_to_list(pdev, vf_id, &mac_list_inp);
+       else
+               ret = vfd_ops->rem_macs_from_list(pdev, vf_id, &mac_list_inp);
+
+err_free:
+        list_for_each_safe(pos, n, &mac_list_inp) {
+                struct vfd_macaddr *mac = NULL;
+
+                mac = list_entry(pos, struct vfd_macaddr, list);
+                list_del(pos);
+                kfree(mac);
+        }
+       return ret ? ret : count;
+}
+
+/**
+ * vfd_promisc_show - handler for promisc show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_promisc_show(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       u8 data;
+
+       if (!vfd_ops->get_promisc)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_promisc(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       if (data == VFD_PROMISC_UNICAST)
+               ret = scnprintf(buff, PAGE_SIZE, "ucast\n");
+       else if (data == VFD_PROMISC_MULTICAST)
+               ret = scnprintf(buff, PAGE_SIZE, "mcast\n");
+       else if (data == VFD_PROMISC_OFF)
+               ret = scnprintf(buff, PAGE_SIZE, "off\n");
+
+       return ret;
+}
+
+/**
+ * vfd_promisc_store - handler for promisc store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ **/
+static ssize_t vfd_promisc_store(struct kobject *kobj,
+                                struct kobj_attribute *attr,
+                                const char *buff, size_t count)
+{
+       u8 data_new = 0, data_old;
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+
+       if (!vfd_ops->get_promisc || !vfd_ops->set_promisc)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_promisc(pdev, vf_id, &data_old);
+       if (ret < 0)
+               return ret;
+
+       if (strstr(buff, "add")) {
+               if (strstr(buff, "ucast"))
+                       data_new |= VFD_PROMISC_UNICAST;
+               if (strstr(buff, "mcast"))
+                       data_new |= VFD_PROMISC_MULTICAST;
+       } else if (strstr(buff, "rem")) {
+               if (strstr(buff, "ucast"))
+                       data_new &= ~VFD_PROMISC_UNICAST;
+               if (strstr(buff, "mcast"))
+                       data_new &= ~VFD_PROMISC_MULTICAST;
+       } else {
+               dev_err(&pdev->dev, "Invalid input string");
+               return -EINVAL;
+       }
+
+       if (data_new != data_old)
+               ret = vfd_ops->set_promisc(pdev, vf_id, data_new);
+
+       return ret ? ret : count;
+
+}
+
+/**
+ * vfd_vlan_strip_show - handler for vlan_strip show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_vlan_strip_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       bool data;
+
+       if (!vfd_ops->get_vlan_strip)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_vlan_strip(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       if (data)
+               ret = scnprintf(buff, PAGE_SIZE, "on\n");
+       else
+               ret = scnprintf(buff, PAGE_SIZE, "off\n");
+
+       return ret;
+}
+
+/**
+ * vfd_vlan_strip_store - handler for vlan_strip store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ **/
+static ssize_t vfd_vlan_strip_store(struct kobject *kobj,
+                                   struct kobj_attribute *attr,
+                                   const char *buff, size_t count)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       bool data_new, data_old;
+
+       if (!vfd_ops->set_vlan_strip || !vfd_ops->get_vlan_strip)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_vlan_strip(pdev, vf_id, &data_old);
+       if (ret < 0)
+               return ret;
+
+       ret = __parse_bool_data(pdev, buff, "vlan_strip", &data_new);
+       if (ret)
+               return ret;
+
+       if (data_new != data_old)
+               ret = vfd_ops->set_vlan_strip(pdev, vf_id, data_new);
+
+       return ret ? ret : count;
+}
+
+/**
+ * vfd_link_state_show - handler for link_state show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_link_state_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr, char *buff)
+{
+       enum vfd_link_speed link_speed;
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       bool enabled;
+
+       if (!vfd_ops->get_link_state)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_link_state(pdev, vf_id, &enabled, &link_speed);
+       if (ret < 0)
+               return ret;
+
+       if (enabled) {
+               const char *speed_str;
+
+               switch (link_speed) {
+               case VFD_LINK_SPEED_100MB:
+                       speed_str = "100 Mbps";
+                       break;
+               case VFD_LINK_SPEED_1GB:
+                       speed_str = "1 Gbps";
+                       break;
+               case VFD_LINK_SPEED_10GB:
+                       speed_str = "10 Gbps";
+                       break;
+               case VFD_LINK_SPEED_40GB:
+                       speed_str = "40 Gbps";
+                       break;
+               case VFD_LINK_SPEED_20GB:
+                       speed_str = "20 Gbps";
+                       break;
+               case VFD_LINK_SPEED_25GB:
+                       speed_str = "25 Gbps";
+                       break;
+               case VFD_LINK_SPEED_UNKNOWN:
+                       speed_str = "unknown speed";
+                       break;
+               default:
+                       dev_err(&pdev->dev, "Link speed is not supported");
+                       return -EOPNOTSUPP;
+               }
+
+               ret = scnprintf(buff, PAGE_SIZE, "%s, %s\n", "up", speed_str);
+       } else {
+               ret = scnprintf(buff, PAGE_SIZE, "down\n");
+       }
+
+       return ret;
+}
+
+/**
+ * vfd_link_state_store - handler for link_state store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ **/
+static ssize_t vfd_link_state_store(struct kobject *kobj,
+                                     struct kobj_attribute *attr,
+                                     const char *buff, size_t count)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       u8 data;
+
+       if (!vfd_ops->set_link_state)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       if (sysfs_streq("enable", buff)) {
+               data = VFD_LINKSTATE_ON;
+       } else if (sysfs_streq("disable", buff)) {
+               data = VFD_LINKSTATE_OFF;
+       } else if (sysfs_streq("auto", buff)) {
+               data = VFD_LINKSTATE_AUTO;
+       } else {
+               dev_err(&pdev->dev, "Invalid input string");
+               return -EINVAL;
+       }
+
+       ret = vfd_ops->set_link_state(pdev, vf_id, data);
+
+       return ret ? ret : count;
+}
+
+/**
+ * vfd_max_tx_rate_show - handler for mac_tx_rate show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_max_tx_rate_show(struct kobject *kobj,
+                                   struct kobj_attribute *attr, char *buff)
+{
+       if (!vfd_ops->get_max_tx_rate)
+               return -EOPNOTSUPP;
+
+       return vfd_ops->get_max_tx_rate(kobj, attr, buff);
+}
+
+/**
+ * vfd_max_tx_rate_store - handler for max_tx_rate store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ **/
+static ssize_t vfd_max_tx_rate_store(struct kobject *kobj,
+                                    struct kobj_attribute *attr,
+                                    const char *buff, size_t count)
+{
+       if (!vfd_ops->set_max_tx_rate)
+               return -EOPNOTSUPP;
+
+       return vfd_ops->set_max_tx_rate(kobj, attr, buff, count);
+}
+
+/**
+ * vfd_min_tx_rate_show - handler for min_tx_rate show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_min_tx_rate_show(struct kobject *kobj,
+                                   struct kobj_attribute *attr, char *buff)
+{
+       if (!vfd_ops->get_min_tx_rate)
+               return -EOPNOTSUPP;
+
+       return vfd_ops->get_min_tx_rate(kobj, attr, buff);
+}
+
+/**
+ * vfd_min_tx_rate_store - handler for min_tx_rate store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ **/
+static ssize_t vfd_min_tx_rate_store(struct kobject *kobj,
+                                    struct kobj_attribute *attr,
+                                    const char *buff, size_t count)
+{
+       if (!vfd_ops->set_min_tx_rate)
+               return -EOPNOTSUPP;
+
+       return vfd_ops->set_min_tx_rate(kobj, attr, buff, count);
+}
+
+/**
+ * vfd_spoofcheck_show - handler for spoofcheck show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_spoofcheck_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr, char *buff)
+{
+       if (!vfd_ops->get_spoofcheck)
+               return -EOPNOTSUPP;
+
+       return vfd_ops->get_spoofcheck(kobj, attr, buff);
+}
+
+/**
+ * vfd_spoofcheck_store - handler for spoofcheck store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ **/
+static ssize_t vfd_spoofcheck_store(struct kobject *kobj,
+                                   struct kobj_attribute *attr,
+                                   const char *buff, size_t count)
+{
+       if (!vfd_ops->set_spoofcheck)
+               return -EOPNOTSUPP;
+
+       return vfd_ops->set_spoofcheck(kobj, attr, buff, count);
+}
+
+/**
+ * vfd_trust_show - handler for trust show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_trust_show(struct kobject *kobj,
+                             struct kobj_attribute *attr, char *buff)
+{
+       if (!vfd_ops->get_trust)
+               return -EOPNOTSUPP;
+
+       return vfd_ops->get_trust(kobj, attr, buff);
+}
+
+/**
+ * vfd_trust_store - handler for trust store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ **/
+static ssize_t vfd_trust_store(struct kobject *kobj,
+                              struct kobj_attribute *attr,
+                              const char *buff, size_t count)
+{
+       if (!vfd_ops->set_trust)
+               return -EOPNOTSUPP;
+
+       return vfd_ops->set_trust(kobj, attr, buff, count);
+}
+
+/**
+ * vfd_vlan_show - handler for vlan show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_vlan_show(struct kobject *kobj,
+                            struct kobj_attribute *attr, char *buff)
+{
+       if (!vfd_ops->get_vlan)
+               return -EOPNOTSUPP;
+
+       return vfd_ops->get_vlan(kobj, attr, buff);
+}
+
+/**
+ * vfd_vlan_store - handler for vlan store function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer with input data
+ * @count:     size of buff
+ **/
+static ssize_t vfd_vlan_store(struct kobject *kobj,
+                             struct kobj_attribute *attr,
+                             const char *buff, size_t count)
+{
+       if (!vfd_ops->set_vlan)
+               return -EOPNOTSUPP;
+
+       return vfd_ops->set_vlan(kobj, attr, buff, count);
+}
+
+/**
+ * vfd_rx_bytes_show - handler for rx_bytes show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_rx_bytes_show(struct kobject *kobj,
+                                struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       u64 data;
+
+       if (!vfd_ops->get_rx_bytes)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_rx_bytes(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       ret = scnprintf(buff, PAGE_SIZE, "%llu\n", data);
+
+       return ret;
+}
+
+/**
+ * vfd_rx_dropped_show - handler for rx_dropped show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_rx_dropped_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       u64 data;
+
+       if (!vfd_ops->get_rx_dropped)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_rx_dropped(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       ret = scnprintf(buff, PAGE_SIZE, "%llu\n", data);
+
+       return ret;
+}
+
+/**
+ * vfd_rx_packets_show - handler for rx_packets show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_rx_packets_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       u64 data;
+
+       if (!vfd_ops->get_rx_packets)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_rx_packets(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       ret = scnprintf(buff, PAGE_SIZE, "%llu\n", data);
+
+       return ret;
+}
+
+/**
+ * vfd_tx_bytes_show - handler for tx_bytes show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_tx_bytes_show(struct kobject *kobj,
+                                struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       u64 data;
+
+       if (!vfd_ops->get_tx_bytes)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_tx_bytes(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       ret = scnprintf(buff, PAGE_SIZE, "%llu\n", data);
+
+       return ret;
+}
+
+/**
+ * vfd_tx_dropped_show - handler for tx_dropped show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_tx_dropped_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       u64 data;
+
+       if (!vfd_ops->get_tx_dropped)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_tx_dropped(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       ret = scnprintf(buff, PAGE_SIZE, "%llu\n", data);
+
+       return ret;
+}
+
+/**
+ * vfd_tx_packets_show - handler for tx_packets show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_tx_packets_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       u64 data;
+
+       if (!vfd_ops->get_tx_packets)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_tx_packets(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       ret = scnprintf(buff, PAGE_SIZE, "%llu\n", data);
+
+       return ret;
+}
+
+/**
+ * vfd_tx_spoofed_show - handler for tx_spoofed show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_tx_spoofed_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       u64 data;
+
+       if (!vfd_ops->get_tx_spoofed)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_tx_spoofed(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       ret = scnprintf(buff, PAGE_SIZE, "%llu\n", data);
+
+       return ret;
+}
+
+/**
+ * vfd_tx_errors_show - handler for tx_errors show function
+ * @kobj:      kobject being called
+ * @attr:      struct kobj_attribute
+ * @buff:      buffer for data
+ **/
+static ssize_t vfd_tx_errors_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr, char *buff)
+{
+       struct pci_dev *pdev;
+       int vf_id, ret = 0;
+       u64 data;
+
+       if (!vfd_ops->get_tx_errors)
+               return -EOPNOTSUPP;
+
+       ret = __get_pdev_and_vfid(kobj, &pdev, &vf_id);
+       if (ret)
+               return ret;
+
+       ret = vfd_ops->get_tx_errors(pdev, vf_id, &data);
+       if (ret < 0)
+               return ret;
+
+       ret = scnprintf(buff, PAGE_SIZE, "%llu\n", data);
+
+       return ret;
+}
+
+static struct kobj_attribute trunk_attribute =
+       __ATTR(trunk, 0644, vfd_trunk_show, vfd_trunk_store);
+static struct kobj_attribute vlan_mirror_attribute =
+       __ATTR(vlan_mirror, 0644, vfd_vlan_mirror_show, vfd_vlan_mirror_store);
+static struct kobj_attribute egress_mirror_attribute =
+       __ATTR(egress_mirror, 0644,
+              vfd_egress_mirror_show, vfd_egress_mirror_store);
+static struct kobj_attribute ingress_mirror_attribute =
+       __ATTR(ingress_mirror, 0644,
+              vfd_ingress_mirror_show, vfd_ingress_mirror_store);
+static struct kobj_attribute mac_anti_spoof_attribute =
+       __ATTR(mac_anti_spoof, 0644,
+              vfd_mac_anti_spoof_show, vfd_mac_anti_spoof_store);
+static struct kobj_attribute vlan_anti_spoof_attribute =
+       __ATTR(vlan_anti_spoof, 0644,
+              vfd_vlan_anti_spoof_show, vfd_vlan_anti_spoof_store);
+static struct kobj_attribute allow_untagged_attribute =
+       __ATTR(allow_untagged, 0644,
+              vfd_allow_untagged_show, vfd_allow_untagged_store);
+static struct kobj_attribute loopback_attribute =
+       __ATTR(loopback, 0644, vfd_loopback_show, vfd_loopback_store);
+static struct kobj_attribute mac_attribute =
+       __ATTR(mac, 0644, vfd_mac_show, vfd_mac_store);
+static struct kobj_attribute mac_list_attribute =
+       __ATTR(mac_list, 0644, vfd_mac_list_show, vfd_mac_list_store);
+static struct kobj_attribute promisc_attribute =
+       __ATTR(promisc, 0644, vfd_promisc_show, vfd_promisc_store);
+static struct kobj_attribute vlan_strip_attribute =
+       __ATTR(vlan_strip, 0644, vfd_vlan_strip_show, vfd_vlan_strip_store);
+static struct kobj_attribute link_state_attribute =
+       __ATTR(link_state, 0644, vfd_link_state_show, vfd_link_state_store);
+static struct kobj_attribute max_tx_rate_attribute =
+       __ATTR(max_tx_rate, 0644, vfd_max_tx_rate_show, vfd_max_tx_rate_store);
+static struct kobj_attribute min_tx_rate_attribute =
+       __ATTR(min_tx_rate, 0644, vfd_min_tx_rate_show, vfd_min_tx_rate_store);
+static struct kobj_attribute spoofcheck_attribute =
+       __ATTR(spoofcheck, 0644, vfd_spoofcheck_show, vfd_spoofcheck_store);
+static struct kobj_attribute trust_attribute =
+       __ATTR(trust, 0644, vfd_trust_show, vfd_trust_store);
+static struct kobj_attribute vlan_attribute =
+       __ATTR(vlan, 0644, vfd_vlan_show, vfd_vlan_store);
+
+static struct attribute *s_attrs[] = {
+       &trunk_attribute.attr,
+       &vlan_mirror_attribute.attr,
+       &egress_mirror_attribute.attr,
+       &ingress_mirror_attribute.attr,
+       &mac_anti_spoof_attribute.attr,
+       &vlan_anti_spoof_attribute.attr,
+       &allow_untagged_attribute.attr,
+       &loopback_attribute.attr,
+       &mac_attribute.attr,
+       &mac_list_attribute.attr,
+       &promisc_attribute.attr,
+       &vlan_strip_attribute.attr,
+       &link_state_attribute.attr,
+       &max_tx_rate_attribute.attr,
+       &min_tx_rate_attribute.attr,
+       &spoofcheck_attribute.attr,
+       &trust_attribute.attr,
+       &vlan_attribute.attr,
+       NULL,
+};
+
+static struct attribute_group vfd_group = {
+       .attrs = s_attrs,
+};
+
+static struct kobj_attribute rx_bytes_attribute =
+       __ATTR(rx_bytes, 0444, vfd_rx_bytes_show, NULL);
+static struct kobj_attribute rx_dropped_attribute =
+       __ATTR(rx_dropped, 0444, vfd_rx_dropped_show, NULL);
+static struct kobj_attribute rx_packets_attribute =
+       __ATTR(rx_packets, 0444, vfd_rx_packets_show, NULL);
+static struct kobj_attribute tx_bytes_attribute =
+       __ATTR(tx_bytes, 0444, vfd_tx_bytes_show, NULL);
+static struct kobj_attribute tx_dropped_attribute =
+       __ATTR(tx_dropped, 0444, vfd_tx_dropped_show, NULL);
+static struct kobj_attribute tx_packets_attribute =
+       __ATTR(tx_packets, 0444, vfd_tx_packets_show, NULL);
+static struct kobj_attribute tx_spoofed_attribute =
+       __ATTR(tx_spoofed, 0444, vfd_tx_spoofed_show, NULL);
+static struct kobj_attribute tx_errors_attribute =
+       __ATTR(tx_errors, 0444, vfd_tx_errors_show, NULL);
+
+static struct attribute *stats_attrs[] = {
+       &rx_bytes_attribute.attr,
+       &rx_dropped_attribute.attr,
+       &rx_packets_attribute.attr,
+       &tx_bytes_attribute.attr,
+       &tx_dropped_attribute.attr,
+       &tx_packets_attribute.attr,
+       &tx_spoofed_attribute.attr,
+       &tx_errors_attribute.attr,
+       NULL,
+};
+
+static struct attribute_group stats_group = {
+       .name = "stats",
+       .attrs = stats_attrs,
+};
+
+/**
+ * create_vfs_sysfs - create sysfs hierarchy for VF
+ * @pdev:      PCI device information struct
+ * @vfd_obj:   VF-d kobjects information struct
+ *
+ * Creates a kobject for Virtual Function and assigns attributes to it.
+ **/
+static int create_vfs_sysfs(struct pci_dev *pdev, struct vfd_objects *vfd_obj)
+{
+       struct kobject *vf_kobj;
+       char kname[4];
+       int ret, i;
+
+       for (i = 0; i < vfd_obj->num_vfs; i++) {
+               int length = snprintf(kname, sizeof(kname), "%d", i);
+
+               if (length >= sizeof(kname)) {
+                       dev_err(&pdev->dev,
+                               "cannot request %d vfs, try again with smaller number of vfs\n",
+                               i);
+                       --i;
+                       goto err_vfs_sysfs;
+               }
+
+               vf_kobj = kobject_create_and_add(kname, vfd_obj->sriov_kobj);
+               if (!vf_kobj) {
+                       dev_err(&pdev->dev,
+                               "failed to create VF kobj: %s\n", kname);
+                       i--;
+                       ret = -ENOMEM;
+                       goto err_vfs_sysfs;
+               }
+               dev_info(&pdev->dev, "created VF %s sysfs", vf_kobj->name);
+
+               /* create VF sys attr */
+               ret = sysfs_create_group(vf_kobj, &vfd_group);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to create VF sys attribute: %d", i);
+                       goto err_vfs_sysfs;
+               }
+               vfd_obj->vf_kobj[i] = vf_kobj;
+
+               ret = sysfs_create_group(vf_kobj, &stats_group);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to create VF stats attribute: %d", i);
+                       goto err_vfs_sysfs;
+               }
+       }
+
+       return 0;
+
+err_vfs_sysfs:
+       for (; i >= 0; i--)
+               kobject_put(vfd_obj->vf_kobj[i]);
+       return ret;
+}
+
+/**
+ * create_vfd_sysfs - create sysfs hierarchy used by VF-d
+ * @pdev:              PCI device information struct
+ * @num_alloc_vfs:     number of VFs to allocate
+ *
+ * If the kobjects were not able to be created, NULL will be returned.
+ **/
+struct vfd_objects *create_vfd_sysfs(struct pci_dev *pdev, int num_alloc_vfs)
+{
+       struct vfd_objects *vfd_obj;
+       int ret;
+
+       vfd_obj = kzalloc(sizeof(*vfd_obj) +
+                         sizeof(struct kobject *)*num_alloc_vfs, GFP_KERNEL);
+       if (!vfd_obj)
+               return NULL;
+
+       vfd_obj->num_vfs = num_alloc_vfs;
+
+       vfd_obj->sriov_kobj = kobject_create_and_add("sriov", &pdev->dev.kobj);
+       if (!vfd_obj->sriov_kobj)
+               goto err_sysfs;
+
+       dev_info(&pdev->dev, "created %s sysfs", vfd_obj->sriov_kobj->name);
+       ret = create_vfs_sysfs(pdev, vfd_obj);
+       if (ret)
+               goto err_sysfs;
+
+       return vfd_obj;
+
+err_sysfs:
+       kobject_put(vfd_obj->sriov_kobj);
+       kfree(vfd_obj);
+
+       return NULL;
+}
+
+/**
+ * destroy_vfd_sysfs - destroy sysfs hierarchy used by VF-d
+ * @pdev:      PCI device information struct
+ * @vfd_obj:   VF-d kobjects information struct
+ **/
+void destroy_vfd_sysfs(struct pci_dev *pdev, struct vfd_objects *vfd_obj)
+{
+       int i;
+
+       for (i = 0; i < vfd_obj->num_vfs; i++) {
+               dev_info(&pdev->dev, "deleting VF %s sysfs",
+                        vfd_obj->vf_kobj[i]->name);
+               kobject_put(vfd_obj->vf_kobj[i]);
+       }
+
+       dev_info(&pdev->dev, "deleting %s sysfs", vfd_obj->sriov_kobj->name);
+       kobject_put(vfd_obj->sriov_kobj);
+
+       kfree(vfd_obj);
+}
diff --git a/i40e-dkms/i40e-2.7.29/src/kcompat_vfd.h b/i40e-dkms/i40e-2.7.29/src/kcompat_vfd.h
new file mode 100644 (file)
index 0000000..c14e715
--- /dev/null
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
+
+#ifndef _KCOMPAT_VFD_H_
+#define _KCOMPAT_VFD_H_
+
+#define VFD_PROMISC_OFF                0x00
+#define VFD_PROMISC_UNICAST    0x01
+#define VFD_PROMISC_MULTICAST  0x02
+
+#define VFD_LINKSTATE_OFF      0x00
+#define VFD_LINKSTATE_ON       0x01
+#define VFD_LINKSTATE_AUTO     0x02
+
+#define VFD_EGRESS_MIRROR_OFF  -1
+#define VFD_INGRESS_MIRROR_OFF -1
+
+/**
+ * struct vfd_objects - VF-d kobjects information struct
+ * @num_vfs:   number of VFs allocated
+ * @sriov_kobj:        pointer to the top sriov kobject
+ * @vf_kobj:   array of pointer to each VF's kobjects
+ */
+struct vfd_objects {
+       int num_vfs;
+       struct kobject *sriov_kobj;
+       struct kobject *vf_kobj[0];
+};
+
+struct vfd_macaddr {
+       u8 mac[ETH_ALEN];
+       struct list_head list;
+};
+
+#define VFD_LINK_SPEED_100MB_SHIFT             0x1
+#define VFD_LINK_SPEED_1GB_SHIFT               0x2
+#define VFD_LINK_SPEED_10GB_SHIFT              0x3
+#define VFD_LINK_SPEED_40GB_SHIFT              0x4
+#define VFD_LINK_SPEED_20GB_SHIFT              0x5
+#define VFD_LINK_SPEED_25GB_SHIFT              0x6
+
+enum vfd_link_speed {
+       VFD_LINK_SPEED_UNKNOWN  = 0,
+       VFD_LINK_SPEED_100MB    = BIT(VFD_LINK_SPEED_100MB_SHIFT),
+       VFD_LINK_SPEED_1GB      = BIT(VFD_LINK_SPEED_1GB_SHIFT),
+       VFD_LINK_SPEED_10GB     = BIT(VFD_LINK_SPEED_10GB_SHIFT),
+       VFD_LINK_SPEED_40GB     = BIT(VFD_LINK_SPEED_40GB_SHIFT),
+       VFD_LINK_SPEED_20GB     = BIT(VFD_LINK_SPEED_20GB_SHIFT),
+       VFD_LINK_SPEED_25GB     = BIT(VFD_LINK_SPEED_25GB_SHIFT),
+};
+
+struct vfd_ops {
+       int (*get_trunk)(struct pci_dev *pdev, int vf_id, unsigned long *buff);
+       int (*set_trunk)(struct pci_dev *pdev, int vf_id,
+                        const unsigned long *buff);
+       int (*get_vlan_mirror)(struct pci_dev *pdev, int vf_id,
+                              unsigned long *buff);
+       int (*set_vlan_mirror)(struct pci_dev *pdev, int vf_id,
+                              const unsigned long *buff);
+       int (*get_egress_mirror)(struct pci_dev *pdev, int vf_id, int *data);
+       int (*set_egress_mirror)(struct pci_dev *pdev, int vf_id,
+                                const int data);
+       int (*get_ingress_mirror)(struct pci_dev *pdev, int vf_id, int *data);
+       int (*set_ingress_mirror)(struct pci_dev *pdev, int vf_id,
+                                 const int data);
+       int (*get_mac_anti_spoof)(struct pci_dev *pdev, int vf_id, bool *data);
+       int (*set_mac_anti_spoof)(struct pci_dev *pdev, int vf_id,
+                                 const bool data);
+       int (*get_vlan_anti_spoof)(struct pci_dev *pdev, int vf_id, bool *data);
+       int (*set_vlan_anti_spoof)(struct pci_dev *pdev, int vf_id,
+                                  const bool data);
+       int (*get_allow_untagged)(struct pci_dev *pdev, int vf_id, bool *data);
+       int (*set_allow_untagged)(struct pci_dev *pdev, int vf_id,
+                                 const bool data);
+       int (*get_loopback)(struct pci_dev *pdev, int vf_id, bool *data);
+       int (*set_loopback)(struct pci_dev *pdev, int vf_id, const bool data);
+       int (*get_mac)(struct pci_dev *pdev, int vf_id, u8 *macaddr);
+       int (*set_mac)(struct pci_dev *pdev, int vf_id, const u8 *macaddr);
+       int (*get_mac_list)(struct pci_dev *pdev, int vf_id,
+                           struct list_head *mac_list);
+       int (*add_macs_to_list)(struct pci_dev *pdev, int vf_id,
+                               struct list_head *mac_list);
+       int (*rem_macs_from_list)(struct pci_dev *pdev, int vf_id,
+                                 struct list_head *mac_list);
+       int (*get_promisc)(struct pci_dev *pdev, int vf_id, u8 *data);
+       int (*set_promisc)(struct pci_dev *pdev, int vf_id, const u8 data);
+       int (*get_vlan_strip)(struct pci_dev *pdev, int vf_id, bool *data);
+       int (*set_vlan_strip)(struct pci_dev *pdev, int vf_id, const bool data);
+       int (*get_link_state)(struct pci_dev *pdev, int vf_id, bool *enabled,
+                             enum vfd_link_speed *link_speed);
+       int (*set_link_state)(struct pci_dev *pdev, int vf_id, const u8 data);
+       int (*get_max_tx_rate)(struct kobject *,
+                              struct kobj_attribute *, char *);
+       int (*set_max_tx_rate)(struct kobject *, struct kobj_attribute *,
+                              const char *, size_t);
+       int (*get_min_tx_rate)(struct kobject *,
+                              struct kobj_attribute *, char *);
+       int (*set_min_tx_rate)(struct kobject *, struct kobj_attribute *,
+                              const char *, size_t);
+       int (*get_spoofcheck)(struct kobject *,
+                             struct kobj_attribute *, char *);
+       int (*set_spoofcheck)(struct kobject *, struct kobj_attribute *,
+                             const char *, size_t);
+       int (*get_trust)(struct kobject *,
+                        struct kobj_attribute *, char *);
+       int (*set_trust)(struct kobject *, struct kobj_attribute *,
+                        const char *, size_t);
+       int (*get_vlan)(struct kobject *, struct kobj_attribute *, char *);
+       int (*set_vlan)(struct kobject *, struct kobj_attribute *,
+                       const char *, size_t);
+       int (*get_rx_bytes)  (struct pci_dev *pdev, int vf_id, u64 *data);
+       int (*get_rx_dropped)(struct pci_dev *pdev, int vf_id, u64 *data);
+       int (*get_rx_packets)(struct pci_dev *pdev, int vf_id, u64 *data);
+       int (*get_tx_bytes)  (struct pci_dev *pdev, int vf_id, u64 *data);
+       int (*get_tx_dropped)(struct pci_dev *pdev, int vf_id, u64 *data);
+       int (*get_tx_packets)(struct pci_dev *pdev, int vf_id, u64 *data);
+       int (*get_tx_spoofed)(struct pci_dev *pdev, int vf_id, u64 *data);
+       int (*get_tx_errors)(struct pci_dev *pdev, int vf_id, u64 *data);
+};
+
+extern const struct vfd_ops *vfd_ops;
+
+#endif /* _KCOMPAT_VFD_H_ */
similarity index 82%
rename from i40e-dkms/i40e-2.4.6/src/virtchnl.h
rename to i40e-dkms/i40e-2.7.29/src/virtchnl.h
index ac123b29ba6f73256a5b132bd716b7cea00c51ad..28d69a690c950b726330e060ac5bef5c58c0f340 100644 (file)
@@ -1,25 +1,5 @@
-/*******************************************************************************
- *
- * Intel(R) 40-10 Gigabit Ethernet Connection Network Driver
- * Copyright(c) 2013 - 2018 Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * The full GNU General Public License is included in this distribution in
- * the file called "COPYING".
- *
- * Contact Information:
- * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- ******************************************************************************/
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright(c) 2013 - 2018 Intel Corporation. */
 
 #ifndef _VIRTCHNL_H_
 #define _VIRTCHNL_H_
 /* Error Codes */
 enum virtchnl_status_code {
        VIRTCHNL_STATUS_SUCCESS                         = 0,
-       VIRTCHNL_ERR_PARAM                              = -5,
+       VIRTCHNL_STATUS_ERR_PARAM                       = -5,
+       VIRTCHNL_STATUS_ERR_NO_MEMORY                   = -18,
        VIRTCHNL_STATUS_ERR_OPCODE_MISMATCH             = -38,
        VIRTCHNL_STATUS_ERR_CQP_COMPL_ERROR             = -39,
        VIRTCHNL_STATUS_ERR_INVALID_VF_ID               = -40,
-       VIRTCHNL_STATUS_NOT_SUPPORTED                   = -64,
+       VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR           = -53,
+       VIRTCHNL_STATUS_ERR_NOT_SUPPORTED               = -64,
 };
 
+/* Backward compatibility */
+#define VIRTCHNL_ERR_PARAM VIRTCHNL_STATUS_ERR_PARAM
+#define VIRTCHNL_STATUS_NOT_SUPPORTED VIRTCHNL_STATUS_ERR_NOT_SUPPORTED
+
 #define VIRTCHNL_LINK_SPEED_100MB_SHIFT                0x1
 #define VIRTCHNL_LINK_SPEED_1000MB_SHIFT       0x2
 #define VIRTCHNL_LINK_SPEED_10GB_SHIFT         0x3
@@ -123,6 +109,7 @@ enum virtchnl_ops {
        VIRTCHNL_OP_GET_STATS = 15,
        VIRTCHNL_OP_RSVD = 16,
        VIRTCHNL_OP_EVENT = 17, /* must ALWAYS be 17 */
+       /* opcode 19 is reserved */
        VIRTCHNL_OP_IWARP = 20, /* advanced opcode */
        VIRTCHNL_OP_CONFIG_IWARP_IRQ_MAP = 21, /* advanced opcode */
        VIRTCHNL_OP_RELEASE_IWARP_IRQ_MAP = 22, /* advanced opcode */
@@ -133,16 +120,22 @@ enum virtchnl_ops {
        VIRTCHNL_OP_ENABLE_VLAN_STRIPPING = 27,
        VIRTCHNL_OP_DISABLE_VLAN_STRIPPING = 28,
        VIRTCHNL_OP_REQUEST_QUEUES = 29,
+       VIRTCHNL_OP_ENABLE_CHANNELS = 30,
+       VIRTCHNL_OP_DISABLE_CHANNELS = 31,
+       VIRTCHNL_OP_ADD_CLOUD_FILTER = 32,
+       VIRTCHNL_OP_DEL_CLOUD_FILTER = 33,
 
 };
 
-/* This macro is used to generate a compilation error if a structure
+/* These macros are used to generate compilation errors if a structure/union
  * is not exactly the correct length. It gives a divide by zero error if the
- * structure is not of the correct size, otherwise it creates an enum that is
- * never used.
+ * structure/union is not of the correct size, otherwise it creates an enum
+ * that is never used.
  */
 #define VIRTCHNL_CHECK_STRUCT_LEN(n, X) enum virtchnl_static_assert_enum_##X \
-       {virtchnl_static_assert_##X = (n) / ((sizeof(struct X) == (n)) ? 1 : 0)}
+       { virtchnl_static_assert_##X = (n)/((sizeof(struct X) == (n)) ? 1 : 0) }
+#define VIRTCHNL_CHECK_UNION_LEN(n, X) enum virtchnl_static_asset_enum_##X \
+       { virtchnl_static_assert_##X = (n)/((sizeof(union X) == (n)) ? 1 : 0) }
 
 /* Virtual channel message descriptor. This overlays the admin queue
  * descriptor. All other data is passed in external buffers.
@@ -157,7 +150,7 @@ struct virtchnl_msg {
 
 VIRTCHNL_CHECK_STRUCT_LEN(20, virtchnl_msg);
 
-/* Message descriptions and data structures.*/
+/* Message descriptions and data structures. */
 
 /* VIRTCHNL_OP_VERSION
  * VF posts its version number to the PF. PF responds with its version number
@@ -242,6 +235,9 @@ VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_vsi_resource);
 #define VIRTCHNL_VF_OFFLOAD_ENCAP              0X00100000
 #define VIRTCHNL_VF_OFFLOAD_ENCAP_CSUM         0X00200000
 #define VIRTCHNL_VF_OFFLOAD_RX_ENCAP_CSUM      0X00400000
+#define VIRTCHNL_VF_OFFLOAD_ADQ                        0X00800000
+/* Define below the capability flags that are not offloads */
+#define VIRTCHNL_VF_CAP_ADV_LINK_SPEED         0x00000080
 
 #define VF_BASE_MODE_OFFLOADS (VIRTCHNL_VF_OFFLOAD_L2 | \
                               VIRTCHNL_VF_OFFLOAD_VLAN | \
@@ -453,9 +449,24 @@ VIRTCHNL_CHECK_STRUCT_LEN(4, virtchnl_promisc_info);
  * the virtchnl_queue_select struct to specify the VSI. The queue_id
  * field is ignored by the PF.
  *
- * PF replies with struct eth_stats in an external buffer.
+ * PF replies with struct virtchnl_eth_stats in an external buffer.
  */
 
+struct virtchnl_eth_stats {
+       u64 rx_bytes;                   /* received bytes */
+       u64 rx_unicast;                 /* received unicast pkts */
+       u64 rx_multicast;               /* received multicast pkts */
+       u64 rx_broadcast;               /* received broadcast pkts */
+       u64 rx_discards;
+       u64 rx_unknown_protocol;
+       u64 tx_bytes;                   /* transmitted bytes */
+       u64 tx_unicast;                 /* transmitted unicast pkts */
+       u64 tx_multicast;               /* transmitted multicast pkts */
+       u64 tx_broadcast;               /* transmitted broadcast pkts */
+       u64 tx_discards;
+       u64 tx_errors;
+};
+
 /* VIRTCHNL_OP_CONFIG_RSS_KEY
  * VIRTCHNL_OP_CONFIG_RSS_LUT
  * VF sends these messages to configure RSS. Only supported if both PF
@@ -476,7 +487,7 @@ VIRTCHNL_CHECK_STRUCT_LEN(6, virtchnl_rss_key);
 struct virtchnl_rss_lut {
        u16 vsi_id;
        u16 lut_entries;
-       u8 lut[1];        /* RSS lookup table*/
+       u8 lut[1];        /* RSS lookup table */
 };
 
 VIRTCHNL_CHECK_STRUCT_LEN(6, virtchnl_rss_lut);
@@ -494,6 +505,81 @@ struct virtchnl_rss_hena {
 
 VIRTCHNL_CHECK_STRUCT_LEN(8, virtchnl_rss_hena);
 
+/* VIRTCHNL_OP_ENABLE_CHANNELS
+ * VIRTCHNL_OP_DISABLE_CHANNELS
+ * VF sends these messages to enable or disable channels based on
+ * the user specified queue count and queue offset for each traffic class.
+ * This struct encompasses all the information that the PF needs from
+ * VF to create a channel.
+ */
+struct virtchnl_channel_info {
+       u16 count; /* number of queues in a channel */
+       u16 offset; /* queues in a channel start from 'offset' */
+       u32 pad;
+       u64 max_tx_rate;
+};
+
+VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_channel_info);
+
+struct virtchnl_tc_info {
+       u32     num_tc;
+       u32     pad;
+       struct  virtchnl_channel_info list[1];
+};
+
+VIRTCHNL_CHECK_STRUCT_LEN(24, virtchnl_tc_info);
+
+/* VIRTCHNL_ADD_CLOUD_FILTER
+ * VIRTCHNL_DEL_CLOUD_FILTER
+ * VF sends these messages to add or delete a cloud filter based on the
+ * user specified match and action filters. These structures encompass
+ * all the information that the PF needs from the VF to add/delete a
+ * cloud filter.
+ */
+
+struct virtchnl_l4_spec {
+       u8      src_mac[ETH_ALEN];
+       u8      dst_mac[ETH_ALEN];
+       __be16  vlan_id;
+       __be16  pad; /* reserved for future use */
+       __be32  src_ip[4];
+       __be32  dst_ip[4];
+       __be16  src_port;
+       __be16  dst_port;
+};
+
+VIRTCHNL_CHECK_STRUCT_LEN(52, virtchnl_l4_spec);
+
+union virtchnl_flow_spec {
+       struct  virtchnl_l4_spec tcp_spec;
+       u8      buffer[128]; /* reserved for future use */
+};
+
+VIRTCHNL_CHECK_UNION_LEN(128, virtchnl_flow_spec);
+
+enum virtchnl_action {
+       /* action types */
+       VIRTCHNL_ACTION_DROP = 0,
+       VIRTCHNL_ACTION_TC_REDIRECT,
+};
+
+enum virtchnl_flow_type {
+       /* flow types */
+       VIRTCHNL_TCP_V4_FLOW = 0,
+       VIRTCHNL_TCP_V6_FLOW,
+};
+
+struct virtchnl_filter {
+       union   virtchnl_flow_spec data;
+       union   virtchnl_flow_spec mask;
+       enum    virtchnl_flow_type flow_type;
+       enum    virtchnl_action action;
+       u32     action_meta;
+       u8      field_flags;
+};
+
+VIRTCHNL_CHECK_STRUCT_LEN(272, virtchnl_filter);
+
 /* VIRTCHNL_OP_EVENT
  * PF sends this message to inform the VF driver of events that may affect it.
  * No direct response is expected from the VF, though it may generate other
@@ -512,10 +598,23 @@ enum virtchnl_event_codes {
 struct virtchnl_pf_event {
        enum virtchnl_event_codes event;
        union {
+               /* If the PF driver does not support the new speed reporting
+                * capabilities then use link_event else use link_event_adv to
+                * get the speed and link information. The ability to understand
+                * new speeds is indicated by setting the capability flag
+                * VIRTCHNL_VF_CAP_ADV_LINK_SPEED in vf_cap_flags parameter
+                * in virtchnl_vf_resource struct and can be used to determine
+                * which link event struct to use below.
+                */
                struct {
                        enum virtchnl_link_speed link_speed;
-                       bool link_status;
+                       u8 link_status;
                } link_event;
+               struct {
+                       /* link_speed provided in Mbps */
+                       u32 link_speed;
+                       u8 link_status;
+               } link_event_adv;
        } event_data;
 
        int severity;
@@ -534,14 +633,6 @@ VIRTCHNL_CHECK_STRUCT_LEN(16, virtchnl_pf_event);
  * to a single vector.
  * PF configures interrupt mapping and returns status.
  */
-
-/* HW does not define a type value for AEQ; only for RX/TX and CEQ.
- * In order for us to keep the interface simple, SW will define a
- * unique type value for AEQ.
- */
-#define QUEUE_TYPE_PE_AEQ  0x80
-#define QUEUE_INVALID_IDX  0xFFFF
-
 struct virtchnl_iwarp_qv_info {
        u32 v_idx; /* msix_vector */
        u16 ceq_idx;
@@ -716,14 +807,31 @@ virtchnl_vc_validate_vf_msg(struct virtchnl_version_info *ver, u32 v_opcode,
        case VIRTCHNL_OP_REQUEST_QUEUES:
                valid_len = sizeof(struct virtchnl_vf_res_request);
                break;
+       case VIRTCHNL_OP_ENABLE_CHANNELS:
+               valid_len = sizeof(struct virtchnl_tc_info);
+               if (msglen >= valid_len) {
+                       struct virtchnl_tc_info *vti =
+                               (struct virtchnl_tc_info *)msg;
+                       valid_len += (vti->num_tc - 1) *
+                                    sizeof(struct virtchnl_channel_info);
+                       if (vti->num_tc == 0)
+                               err_msg_format = true;
+               }
+               break;
+       case VIRTCHNL_OP_DISABLE_CHANNELS:
+               break;
+       case VIRTCHNL_OP_ADD_CLOUD_FILTER:
+       case VIRTCHNL_OP_DEL_CLOUD_FILTER:
+               valid_len = sizeof(struct virtchnl_filter);
+               break;
        /* These are always errors coming from the VF. */
        case VIRTCHNL_OP_EVENT:
        case VIRTCHNL_OP_UNKNOWN:
        default:
-               return VIRTCHNL_ERR_PARAM;
+               return VIRTCHNL_STATUS_ERR_PARAM;
        }
        /* few more checks */
-       if ((valid_len != msglen) || (err_msg_format))
+       if (err_msg_format || valid_len != msglen)
                return VIRTCHNL_STATUS_ERR_OPCODE_MISMATCH;
 
        return 0;