Commit a5ed3798 authored by Juerg Haefliger's avatar Juerg Haefliger Committed by Kleber Sacilotto de Souza
parent 5c8a7212
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
This source diff could not be displayed because it is too large. You can view the blob instead.
#!/usr/bin/make
# Makefile for building Linux Broadcom Gigabit ethernet driver as a module.
# $id$
KVER=
ifeq ($(KVER),)
KVER=$(shell uname -r)
endif
__ARCH=$(shell uname -m)
# PREFIX may be set by the RPM build to set the effective root.
PREFIX=
ifeq ($(shell ls /lib/modules/$(KVER)/build > /dev/null 2>&1 && echo build),)
# SuSE source RPMs
_KVER=$(shell echo $(KVER) | cut -d "-" -f1,2)
_KFLA=$(shell echo $(KVER) | cut -d "-" -f3)
_ARCH=$(shell file -b /lib/modules/$(shell uname -r)/build | cut -d "/" -f5)
ifeq ($(_ARCH),)
_ARCH=$(__ARCH)
endif
ifeq ($(shell ls /usr/src/linux-$(_KVER)-obj > /dev/null 2>&1 && echo linux),)
ifeq ($(shell ls /usr/src/kernels/$(KVER)-$(__ARCH) > /dev/null 2>&1 && echo linux),)
LINUX=
else
LINUX=/usr/src/kernels/$(KVER)-$(__ARCH)
LINUXSRC=$(LINUX)
endif
else
LINUX=/usr/src/linux-$(_KVER)-obj/$(_ARCH)/$(_KFLA)
LINUXSRC=/usr/src/linux-$(_KVER)
endif
else
LINUX=/lib/modules/$(KVER)/build
ifeq ($(shell ls /lib/modules/$(KVER)/source > /dev/null 2>&1 && echo source),)
LINUXSRC=$(LINUX)
else
LINUXSRC=/lib/modules/$(KVER)/source
endif
endif
ifeq ($(shell ls $(LINUXSRC)/include/uapi/linux > /dev/null 2>&1 && echo uapi),)
UAPI=
else
UAPI=uapi
endif
ifeq ($(BCMMODDIR),)
ifeq ($(shell ls /lib/modules/$(KVER)/updates > /dev/null 2>&1 && echo 1),1)
BCMMODDIR=/lib/modules/$(KVER)/updates
else
ifeq ($(shell grep -q "search.*[[:space:]]updates" /etc/depmod.conf > /dev/null 2>&1 && echo 1),1)
BCMMODDIR=/lib/modules/$(KVER)/updates
else
ifeq ($(shell grep -q "search.*[[:space:]]updates" /etc/depmod.d/* > /dev/null 2>&1 && echo 1),1)
BCMMODDIR=/lib/modules/$(KVER)/updates
else
BCMMODDIR=/lib/modules/$(KVER)/kernel/drivers/net
endif
endif
endif
endif
ifneq ($(shell grep -o "pci_enable_msix_range" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG = -DHAVE_MSIX_RANGE
else
DISTRO_CFLAG =
endif
ifneq ($(shell grep -o "msix_cap" $(LINUXSRC)/include/linux/pci.h),)
ifeq ($(shell grep -o "pci_dev_rh1" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG += -DHAVE_MSIX_CAP
endif
endif
ifneq ($(shell grep -o "module_pci_driver" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG += -DHAVE_MODULE_PCI_DRIVER
endif
ifneq ($(shell grep "hlist_for_each_entry_safe" $(LINUXSRC)/include/linux/list.h | grep "tpos" > /dev/null 2>&1 && echo tpos),)
DISTRO_CFLAG += -DHAVE_OLD_HLIST
endif
ifneq ($(shell grep -o "csum_level" $(LINUXSRC)/include/linux/skbuff.h),)
DISTRO_CFLAG += -DHAVE_CSUM_LEVEL
endif
ifneq ($(shell grep -o "build_skb" $(LINUXSRC)/include/linux/skbuff.h),)
DISTRO_CFLAG += -DHAVE_BUILD_SKB
ifneq ($(shell grep "build_skb" $(LINUXSRC)/include/linux/skbuff.h | grep "int frag_size" > /dev/null 2>&1 && echo frag_size),)
DISTRO_CFLAG += -DHAVE_NEW_BUILD_SKB
endif
endif
ifneq ($(shell grep -o "inner_network_offset" $(LINUXSRC)/include/linux/skbuff.h),)
DISTRO_CFLAG += -DHAVE_INNER_NETWORK_OFFSET
endif
ifeq ($(shell grep -o "skb_frag_size" $(LINUXSRC)/include/linux/skbuff.h),)
DISTRO_CFLAG += -DNO_SKB_FRAG_SIZE
endif
ifneq ($(shell grep -so "n_proto" $(LINUXSRC)/include/net/flow_keys.h),)
DISTRO_CFLAG += -DHAVE_N_PROTO
endif
ifneq ($(shell grep -so "flow_keys" $(LINUXSRC)/include/net/flow_keys.h),)
DISTRO_CFLAG += -DHAVE_FLOW_KEYS
endif
ifneq ($(shell grep -o "skb_get_hash_raw" $(LINUXSRC)/include/linux/skbuff.h),)
DISTRO_CFLAG += -DHAVE_GET_HASH_RAW
endif
ifneq ($(shell grep -o "PKT_HASH_TYPE" $(LINUXSRC)/include/linux/skbuff.h),)
DISTRO_CFLAG += -DHAVE_SKB_HASH_TYPE
endif
ifneq ($(shell grep -o "SKB_GSO_UDP_TUNNEL_CSUM" $(LINUXSRC)/include/linux/skbuff.h),)
DISTRO_CFLAG += -DHAVE_SKB_GSO_UDP_TUNNEL_CSUM
else
ifneq ($(shell grep -o "SKB_GSO_UDP_TUNNEL" $(LINUXSRC)/include/linux/skbuff.h),)
DISTRO_CFLAG += -DHAVE_SKB_GSO_UDP_TUNNEL
endif
endif
ifneq ($(shell grep -o "skb_frag_page" $(LINUXSRC)/include/linux/skbuff.h),)
DISTRO_CFLAG += -DHAVE_SKB_FRAG_PAGE
endif
ifneq ($(shell grep "skb_checksum_none_assert" $(LINUXSRC)/include/linux/skbuff.h > /dev/null 2>&1 && echo skb_cs_none_assert),)
DISTRO_CFLAG += -DHAVE_SKB_CHECKSUM_NONE_ASSERT
endif
ifneq ($(shell grep -o "min_tx_rate" $(LINUXSRC)/include/$(UAPI)/linux/if_link.h),)
DISTRO_CFLAG += -DHAVE_IFLA_TX_RATE
endif
ifneq ($(shell grep -o "IFLA_XDP_PROG_ID" $(LINUXSRC)/include/$(UAPI)/linux/if_link.h),)
DISTRO_CFLAG += -DHAVE_IFLA_XDP_PROG_ID
endif
ifneq ($(shell grep -o "dma_set_mask_and_coherent" $(LINUXSRC)/include/linux/dma-mapping.h),)
DISTRO_CFLAG += -DHAVE_SET_MASK_AND_COHERENT
endif
ifneq ($(shell grep -o "dma_set_coherent_mask" $(LINUXSRC)/include/linux/dma-mapping.h),)
DISTRO_CFLAG += -DHAVE_SET_COHERENT_MASK
endif
ifneq ($(shell grep -o "ndo_add_vxlan_port" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_ADD_VXLAN
endif
ifneq ($(shell grep -o "struct dev_addr_list" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_DEV_ADDR_LIST
endif
ifneq ($(shell grep "netif_set_real_num_tx" $(LINUXSRC)/include/linux/netdevice.h > /dev/null 2>&1 && echo real_tx),)
DISTRO_CFLAG += -DHAVE_NETIF_SET_REAL_NUM_TX
else
DISTRO_CFLAG += -DVOID_NETIF_SET_NUM_TX
endif
ifneq ($(shell grep "netif_set_real_num_tx" $(LINUXSRC)/include/linux/netdevice.h | grep void > /dev/null 2>&1 && echo netif_set_real),)
DISTRO_CFLAG += -DVOID_NETIF_SET_NUM_TX
endif
ifneq ($(shell grep -o "netdev_tx_sent_queue" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NETDEV_TX_QUEUE_CTRL
endif
ifneq ($(shell ls $(LINUXSRC)/include/net/flow_dissector.h > /dev/null 2>&1 && echo flow),)
DISTRO_CFLAG += -DNEW_FLOW_KEYS -DHAVE_FLOW_KEYS
ifneq ($(shell grep -so "static inline bool skb_flow_dissect_flow_keys" $(LINUXSRC)/include/linux/skbuff.h),)
ifneq ($(shell grep -A 2 "static inline bool skb_flow_dissect_flow_keys" $(LINUXSRC)/include/linux/skbuff.h | grep -o "unsigned int flags"),)
DISTRO_CFLAG += -DHAVE_NEW_FLOW_DISSECTOR_WITH_FLAGS
endif
ifneq ($(shell grep -o "FLOW_DIS_ENCAPSULATION" $(LINUXSRC)/include/net/flow_dissector.h),)
DISTRO_CFLAG += -DHAVE_NEW_FLOW_DISSECTOR
endif
endif
endif
ifneq ($(shell ls $(LINUXSRC)/include/net/udp_tunnel.h > /dev/null 2>&1 && echo udp_tunnel),)
DISTRO_CFLAG += -DHAVE_UDP_TUNNEL_H
endif
ifneq ($(shell grep -o "ether_addr_equal" $(LINUXSRC)/include/linux/etherdevice.h),)
DISTRO_CFLAG += -DHAVE_ETHER_ADDR_EQUAL
endif
ifneq ($(shell grep -o "ether_addr_copy" $(LINUXSRC)/include/linux/etherdevice.h),)
DISTRO_CFLAG += -DHAVE_ETHER_ADDR_COPY
endif
ifneq ($(shell grep -o "eth_broadcast_addr" $(LINUXSRC)/include/linux/etherdevice.h),)
DISTRO_CFLAG += -DHAVE_ETH_BROADCAST_ADDR
endif
ifneq ($(shell grep -o "eth_get_headlen" $(LINUXSRC)/include/linux/etherdevice.h),)
DISTRO_CFLAG += -DHAVE_ETH_GET_HEADLEN
endif
ifneq ($(shell grep -o "eth_hw_addr_random" $(LINUXSRC)/include/linux/etherdevice.h),)
DISTRO_CFLAG += -DHAVE_ETH_HW_ADDR_RANDOM
endif
ifneq ($(shell grep -o "get_rxnfc" $(LINUXSRC)/include/linux/ethtool.h),)
DISTRO_CFLAG += -DHAVE_RXNFC
ifneq ($(shell grep -A 2 "get_rxnfc" $(LINUXSRC)/include/linux/ethtool.h | grep -o "void"),)
DISTRO_CFLAG += -DHAVE_RXNFC_VOID
endif
endif
ifneq ($(shell grep -o "get_rxfh_key_size" $(LINUXSRC)/include/linux/ethtool.h),)
ifneq ($(shell grep -o "ETH_RSS_HASH_TOP" $(LINUXSRC)/include/linux/ethtool.h),)
DISTRO_CFLAG += -DHAVE_GET_RXFH_KEY_SIZE
endif
endif
ifneq ($(shell grep -o "get_rxfh_indir_size" $(LINUXSRC)/include/linux/ethtool.h),)
DISTRO_CFLAG += -DHAVE_RXFH_INDIR_SIZE
endif
ifneq ($(shell grep -o "set_phys_id" $(LINUXSRC)/include/linux/ethtool.h),)
DISTRO_CFLAG += -DHAVE_SET_PHYS_ID
endif
ifneq ($(shell grep -o "ETHTOOL_LINK_MODE_25000baseCR_Full_BIT" $(LINUXSRC)/include/$(UAPI)/linux/ethtool.h),)
DISTRO_CFLAG += -DHAVE_ETHTOOL_GLINKSETTINGS_25G
endif
ifneq ($(shell grep -o "ethtool_tcpip6_spec" $(LINUXSRC)/include/$(UAPI)/linux/ethtool.h),)
DISTRO_CFLAG += -DHAVE_ETHTOOL_IP6_SPEC
endif
ifeq ($(shell grep -o "rx_cpu_rmap" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DNO_NETDEV_CPU_RMAP
else
ifneq ($(shell grep -o "struct net_device_extended" $(LINUXSRC)/include/linux/netdevice.h || \
grep -o "irq_run_affinity_notifiers" $(LINUXSRC)/include/linux/interrupt.h),)
DISTRO_CFLAG += -DNO_NETDEV_CPU_RMAP
endif
endif
ifneq ($(shell grep -o "hw_features" $(LINUXSRC)/include/linux/netdevice.h),)
ifeq ($(shell grep -o "get_netdev_hw_features" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DNETDEV_HW_FEATURES
endif
endif
ifneq ($(shell grep -o "hw_enc_features" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DNETDEV_HW_ENC_FEATURES
endif
ifneq ($(shell grep -o "sriov_configure" $(LINUXSRC)/include/linux/pci.h),)
ifeq ($(shell grep -o "rh_reserved" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG += -DPCIE_SRIOV_CONFIGURE
endif
endif
ifneq ($(shell grep -o "pci_vfs_assigned" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG += -DHAVE_PCI_VFS_ASSIGNED
endif
ifneq ($(shell grep -o "pci_num_vf" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG += -DHAVE_PCI_NUM_VF
endif
ifneq ($(shell grep -o "ndo_fix_features" $(LINUXSRC)/include/linux/netdevice.h),)
ifeq ($(shell grep -o "net_device_ops_ext" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DNETDEV_FEATURE_CONTROL
endif
ifneq ($(shell grep -o "net_device_ops_extended" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DNETDEV_FEATURE_CONTROL
endif
endif
ifneq ($(shell grep -o "ndo_rx_flow_steer" $(LINUXSRC)/include/linux/netdevice.h),)
ifeq ($(shell grep -o "netdev_rfs_info" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DNETDEV_RX_FLOW_STEER
endif
endif
ifneq ($(shell grep -o "ndo_busy_poll" $(LINUXSRC)/include/linux/netdevice.h),)
ifeq ($(shell grep -o "net_device_extended" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DNETDEV_BUSY_POLL
endif
endif
ifneq ($(shell grep -o "ndo_get_stats64" $(LINUXSRC)/include/linux/netdevice.h),)
ifeq ($(shell grep -o "net_device_ops_ext" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DNETDEV_GET_STATS64
endif
ifneq ($(shell grep -o "net_device_ops_extended" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DNETDEV_GET_STATS64
endif
ifneq ($(shell grep "ndo_get_stats64" $(LINUXSRC)/include/linux/netdevice.h | grep -o "void"),)
DISTRO_CFLAG += -DNETDEV_GET_STATS64_VOID
endif
endif
ifneq ($(shell grep -o "ndo_get_vf_config" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_GET_VF_CONFIG
endif
ifneq ($(shell grep -A 2 "ndo_bridge_getlink" $(LINUXSRC)/include/linux/netdevice.h | grep -o "nlflags"),)
ifneq ($(shell grep -A 3 "ndo_dflt_bridge_getlink" $(LINUXSRC)/include/linux/rtnetlink.h | grep -o "filter_mask"),)
DISTRO_CFLAG += -DHAVE_NDO_BRIDGE_GETLINK
endif
endif
ifneq ($(shell grep -o "ndo_set_vf_link_state" $(LINUXSRC)/include/linux/netdevice.h),)
ifeq ($(shell grep -o "net_device_ops_ext" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_SET_VF_LINK_STATE
endif
ifneq ($(shell grep -o "net_device_ops_extended" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_SET_VF_LINK_STATE
endif
endif
ifneq ($(shell grep -o "ndo_set_vf_spoofchk" $(LINUXSRC)/include/linux/netdevice.h),)
ifeq ($(shell grep -o "net_device_ops_ext" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_VF_SPOOFCHK
endif
ifneq ($(shell grep -o "net_device_ops_extended" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_VF_SPOOFCHK
endif
endif
ifneq ($(shell grep -A 1 "ndo_set_vf_vlan" $(LINUXSRC)/include/linux/netdevice.h | grep -o "proto"),)
ifeq ($(shell grep -o "net_device_ops_extended" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DNEW_NDO_SET_VF_VLAN
endif
endif
ifneq ($(shell grep -o "ndo_set_vf_vlan_rh73" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_SET_VF_VLAN_RH73
endif
ifneq ($(shell grep -o "ndo_setup_tc" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_SETUP_TC
ifneq ($(shell grep -o "struct tc_to_netdev" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_TC_TO_NETDEV
ifneq ($(shell grep -o "struct tc_mqprio_qopt" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_MQPRIO_QOPT
endif
ifneq ($(shell grep -A 1 "ndo_setup_tc" $(LINUXSRC)/include/linux/netdevice.h | grep -o "u32 chain_index"),)
DISTRO_CFLAG += -DHAVE_CHAIN_INDEX
endif
endif
endif
ifneq ($(shell grep -o "netdev_get_num_tc" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_GET_NUM_TC
endif
ifneq ($(shell grep -so "netdev_features_t" $(LINUXSRC)/include/linux/netdev_features.h || \
grep -o "netdev_features_t" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NETDEV_FEATURES_T
endif
ifneq ($(shell grep -o "ndo_fix_features" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_FIX_FEATURES
endif
ifneq ($(shell grep -o "netif_set_real_num_rx" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NETIF_SET_REAL_NUM_RX
endif
ifneq ($(shell grep -o "netif_get_num_default_rss_queues" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NETIF_GET_DEFAULT_RSS
endif
ifneq ($(shell grep -o "ndo_vlan_rx_register" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_VLAN_RX_REGISTER
endif
ifneq ($(shell grep -o "ndo_xdp" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_XDP
ifneq ($(shell ls $(LINUXSRC)/include/net/bpf_trace.h > /dev/null 2>&1 && echo bpf_trace),)
DISTRO_CFLAG += -DHAVE_BPF_TRACE
endif
endif
ifneq ($(shell grep -o "netdev_name" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NETDEV_NAME
endif
ifneq ($(shell grep -o "netdev_update_features" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NETDEV_UPDATE_FEATURES
endif
ifneq ($(shell grep -o "dev_port" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_DEV_PORT
endif
ifneq ($(shell grep -o "napi_hash_add" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NAPI_HASH_ADD
endif
ifneq ($(shell grep -o "napi_hash_del" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NAPI_HASH_DEL
endif
ifneq ($(shell grep "napi_complete_done" $(LINUXSRC)/include/linux/netdevice.h | grep -o "bool"),)
DISTRO_CFLAG += -DHAVE_NEW_NAPI_COMPLETE_DONE
endif
ifneq ($(shell grep -o "min_mtu" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_MIN_MTU
endif
ifneq ($(shell grep -o "prandom_bytes" $(LINUXSRC)/include/linux/random.h),)
DISTRO_CFLAG += -DHAVE_PRANDOM_BYTES
endif
ifneq ($(shell grep -o "tcp_v6_check" $(LINUXSRC)/include/net/ip6_checksum.h),)
DISTRO_CFLAG += -DHAVE_TCP_V6_CHECK
endif
ifneq ($(shell grep -o "usleep_range" $(LINUXSRC)/include/linux/delay.h),)
DISTRO_CFLAG += -DHAVE_USLEEP_RANGE
endif
ifneq ($(shell grep -o "vzalloc" $(LINUXSRC)/include/linux/vmalloc.h),)
DISTRO_CFLAG += -DHAVE_VZALLOC
endif
ifneq ($(shell grep -o "pcie_get_minimum_link" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG += -DHAVE_PCIE_GET_MINIMUM_LINK
endif
ifneq ($(shell grep -o "pcie_capability_read_word" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG += -DHAVE_PCIE_CAPABILITY_READ_WORD
endif
ifneq ($(shell grep -o "PCIE_SPEED_2_5GT" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG += -DHAVE_PCIE_BUS_SPEED
endif
ifneq ($(shell grep -o "pci_is_bridge" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG += -DHAVE_PCI_IS_BRIDGE
endif
ifneq ($(shell ls $(LINUXSRC)/include/$(UAPI)/linux/net_tstamp.h > /dev/null 2>&1 && echo net_tstamp),)
ifneq ($(shell ls $(LINUXSRC)/include/linux/timecounter.h > /dev/null 2>&1 && echo timecounter),)
ifneq ($(shell ls $(LINUXSRC)/include/linux/timekeeping.h > /dev/null 2>&1 && echo timekeeping),)
ifneq ($(shell grep -o "HWTSTAMP_FILTER_PTP_V2_EVENT" $(LINUXSRC)/include/$(UAPI)/linux/net_tstamp.h),)
DISTRO_CFLAG += -DHAVE_IEEE1588_SUPPORT
endif
endif
endif
endif
EXTRA_CFLAGS += ${DISTRO_CFLAG} -g -DCHIMP_FW -D__LINUX -DCONFIG_BNXT_SRIOV -DCONFIG_BNXT_DCB -DCONFIG_BNXT_FLASHDEV -DHSI_DBG_DISABLE -DCONFIG_BNXT_RE
cflags-y += $(EXTRA_CFLAGS)
BCM_DRV = bnxt_en.ko
ifneq ($(KERNELRELEASE),)
obj-m += bnxt_en.o
bnxt_en-y := bnxt.o bnxt_ethtool.o bnxt_sriov.o bnxt_dcb.o bnxt_ulp.o bnxt_xdp.o bnxt_ptp.o #decode_hsi.o
else
default:
ifeq ($(CROSS_COMPILE),)
make -C $(LINUX) SUBDIRS=$(shell pwd) modules
else ifneq ($(CROSS_COMPILE),)
make -C $(LINUXSRC) SUBDIRS=$(shell pwd) modules CROSS_COMPILE=$(CROSS_COMPILE) ARCH=$(ARCH)
endif
yocto_all:
$(MAKE) -C $(LINUXSRC) M=$(shell pwd)
modules_install:
$(MAKE) -C $(LINUXSRC) M=$(shell pwd) modules_install
endif
install: default
mkdir -p $(PREFIX)/$(BCMMODDIR);
install -m 444 $(BCM_DRV) $(PREFIX)/$(BCMMODDIR);
@if [ "$(PREFIX)" = "" ]; then /sbin/depmod -a ;\
else echo " *** Run '/sbin/depmod -a' to update the module database.";\
fi
.PHONEY: all clean install
clean:
-rm -f bnxt.o bnxt.mod.c bnxt.mod.o .bnxt.*.cmd *.cmd *.markers *.order *.symvers decode_hsi.o .decode_*
-rm -rf .tmp_versions
-rm -rf bnxt_en.o bnxt_en.ko bnxt_en.mod.o bnxt_en.mod.c .bnxt_en.* bnxt_sriov.o .bnxt_sriov.* bnxt_ethtool.o .bnxt_ethtool.* bnxt_dcb.o .bnxt_dcb.* bnxt_ulp.o .bnxt_ulp.* bnxt_xdp.o .bnxt_xdp.*
-rm -f Module.markers Module.symvers modules.order
README Notes
Broadcom bnxt_en Linux Driver
Version 1.8.1
07/11/2017
Broadcom Limited
5300 California Avenue,
Irvine, CA 92617
Copyright (c) 2015 - 2016 Broadcom Corporation
Copyright (c) 2016 - 2017 Broadcom Limited
All rights reserved
Table of Contents
=================
Introduction
Limitations
Port Speeds
BNXT_EN Driver Dependencies
BNXT_EN Driver Settings
Autoneg
Energy Efficient Ethernet
Enabling Receive Side Scaling (RSS)
Enabling Accelerated Receive Flow Steering (RFS)
Enabling Busy Poll Sockets
Enabling SR-IOV
Virtual Ethernet Bridge (VEB)
Hardware QoS
PTP Hardware Clock
BNXT_EN Driver Parameters
BNXT_EN Driver Defaults
Statistics
Unloading and Removing Driver
Updating Firmware for Broadcom NetXtreme-C and NetXtreme-E devices
Updating Firmware for Broadcom Nitro device
Introduction
============
This file describes the bnxt_en Linux driver for the Broadcom NetXtreme-C
and NetXtreme-E BCM573xx and BCM574xx 10/25/40/50 Gbps Ethernet Network
Controllers and Broadcom Nitro BCM58700 4-port 1/2.5/10 Gbps Ethernet Network
Controller.
Limitations
===========
1. The current version of the driver will compile on RHEL7.x, RHEL6.x,
OLE6.x UEK, SLES12, SLES11SP1 and newer, most 3.x/4.x kernels, and some
2.6 kernels starting from 2.6.32.
2. Laser needs to be brought up for Nitro BCM58700 Ethernet controller
using the following command, to bring up the Link.
i2cset -f -y 1 0x70 0 7 && i2cset -f -y 1 0x24 0xff 0x0
3. Each device supports hundreds of MSIX vectors. The driver will enable
all MSIX vectors when it loads. On some systems running on some kernels,
the system may run out of interrupt descriptors.
Port Speeds
===========
On some dual-port devices, the port speed of each port must be compatible
with the port speed of the other port. 10Gbps and 25Gbps are not compatible
speeds. For example, if one port is set to 10Gbps and link is up, the other
port cannot be set to 25Gbps. However, the driver will allow incompatible
speeds to be set on the two ports if link is not up yet. Subsequent link up
on one port will render the incompatible speed on the other port to become
unsupported. A console message like this may appear when this scenario
happens:
bnxt_en 0000:04:00.0 eth0: Link speed 25000 no longer supported
If the link is up on one port, the driver will not allow the other port to
be set to an incompatible speed. An attempt to do that will result in an
error. For example, eth0 and eth1 are the 2 ports of the dual-port device,
eth0 is set to 10Gbps and link is up.
ethtool -s eth1 speed 25000
Cannot set new settings: Invalid argument
not setting speed
This operation will only be allowed when the link goes down on eth0 or if
eth0 is brought down using ifconfig/ip.
On some NPAR (NIC partioning) devices where one port is shared by multiple
PCI functions, the port speed is pre-configured and cannot be changed by
the driver.
See Autoneg section below for additional information.
BNXT_EN Driver Dependencies
===========================
The driver has no dependencies on user-space firmware packages as all necessary
firmware must be programmed in NVRAM(or QSPI for Nitro BCM58700 devices).
Starting with driver version 1.0.0, the goal is that the driver will be
compatible with all future versions of production firmware. All future versions
of the driver will be backwards compatible with firmware as far back as the
first production firmware.
The first production firmware is version 20.1.11 using Hardware Resource
Manager (HWRM) spec. 1.0.0.
ethtool -i displays the firmware versions. For example:
ethtool -i eth0
will show among other things:
firmware-version: 20.1.11/1.0.0 pkg 20.02.00.03
In this example, the first version number (20.1.11) is the firmware version,
the second version number (1.0.0) is the HWRM spec. version. The third
version number (20.02.00.03) is the package version of all the different
firmware components in NVRAM. The package version may not be available on
all devices.
Using kernels older than 4.7, if CONFIG_VLAN_MODULE kernel option is set as a
module option, the vxlan.ko module must be loaded before the bnxt_en.ko module.
BNXT_EN Driver Settings
=======================
The bnxt_en driver settings can be queried and changed using ethtool. The
latest ethtool can be downloaded from
ftp://ftp.kernel.org/pub/software/network/ethtool if it is not already
installed. The following are some common examples on how to use ethtool. See
the ethtool man page for more information. ethtool settings do not persist
across reboot or module reload. The ethtool commands can be put in a startup
script such as /etc/rc.local to preserve the settings across a reboot. On
Red Hat distributions, "ethtool -s" parameters can be specified in the
ifcfg-ethx scripts using the ETHTOOL_OPTS keyword.
Some ethtool examples:
1. Show current speed, duplex, and link status:
ethtool eth0
2. Set speed:
Example: Set speed to 10Gbps with autoneg off:
ethtool -s eth0 speed 10000 autoneg off
Example: Set speed to 25Gbps with autoneg off:
ethtool -s eth0 speed 25000 autoneg off
On some NPAR (NIC partitioning) devices, the port speed and flow control
settings cannot be changed by the driver.
See Autoneg section below for additional information on configuring
Autonegotiation.
3. Show offload settings:
ethtool -k eth0
4. Change offload settings:
Example: Turn off TSO (TCP Segmentation Offload)
ethtool -K eth0 tso off
Example: Turn off hardware GRO and LRO
ethtool -K eth0 gro off lro off
Example: Turn on hardware GRO only
ethtool -K eth0 gro on lro off
Note that if both gro and lro are set, the driver will use hardware GRO.
5. Show ring sizes:
ethtool -g eth0
6. Change ring sizes:
ethtool -G eth0 rx N
Note that the RX Jumbo ring size is set automatically when needed and
cannot be changed by the user.
7. Get statistics:
ethtool -S eth0
8. Show number of channels (rings):
ethtool -l eth0
9. Set number of channels (rings):
ethtool -L eth0 rx N tx N combined 0
ethtool -L eth0 rx 0 tx 0 combined M
Note that the driver can support either all combined or all rx/tx channels,
but not a combination of combined and rx/tx channels. The default is
combined channels to match the number of CPUs up to 8. Combined channels
use less system resources but may have lower performance than rx/tx channels
under very high traffic stress. rx and tx channels can have different numbers
for rx and tx but must both be non-zero.
10. Show interrupt coalescing settings:
ethtool -c eth0
11. Set interrupt coalescing settings:
ethtool -C eth0 rx-frames N
Note that only these parameters are supported:
rx-usecs, rx-frames, rx-usecs-irq, rx-frames-irq,
tx-usecs, tx-frames, tx-usecs-irq, tx-frames-irq,
stats-block-usecs.
12. Show RSS flow hash indirection table and RSS hash key:
ethtool -x eth0
13. Run self test:
ethtool -t eth0
Note that only single function PFs can execute self tests. If a PF has
active VFs, only online tests can be executed.
14. See ethtool man page for more options.
Autoneg
=======
The bnxt_en driver supports Autonegotiation of speed and flow control on
most devices. Some dual-port 25G devices do not support Autoneg. Autoneg
must be enabled for 10GBase-T devices.
Note that parallel detection is not supported when autonegotiating
50GBase-CR2, 40GBase-CR4, 25GBase-CR, 10GbE SFP+. If one side is
autonegoatiating and the other side is not, link will not come up.
25G and 50G advertisements are newer standards first defined in the 4.7
kernel's ethtool interface. To fully support these new advertisement speeds
for autonegotiation, 4.7 (or newer) kernel and a newer ethtool utility are
required.
Below are some examples to illustrate the limitations when using 4.6 and
older kernels:
1. Enable Autoneg with all supported speeds advertised when the device
currently has Autoneg disabled:
ethtool -s eth0 autoneg on advertise 0x0
Note that to advertise all supported speeds (including 25G and 50G), the
device must initially have Autoneg disabled. advertise is a hexadecimal
value specifying one or more advertised speed. 0x0 is special value that
means all supported speeds. See ethtool man page. These advertise values
are supported by the driver:
0x020 1000baseT Full
0x1000 10000baseT Full
0x1000000 40000baseCR4 Full
2. Enable Autoneg with only 10G advertised:
ethtool -s eth0 autoneg on advertise 0x1000
or:
ethtool -s eth0 autoneg on speed 10000 duplex full
3. Enable Autoneg with only 40G advertised:
ethtool -s eth0 autoneg on advertise 0x01000000
4. Enable Autoneg with 40G and 10G advertised:
ethtool -s eth0 autoneg on advertise 0x01001000
Note that the "Supported link modes" and "Advertised link modes" will not
show 25G and 50G even though they may be supported or advertised. For
example, on a device that is supporting and advertising 10G, 25G, 40G, and
50G, and linking up at 50G, ethtool will show the following:
ethtool eth0
Settings for eth0:
Supported ports: [ FIBRE ]
Supported link modes: 10000baseT/Full
40000baseCR4/Full
Supported pause frame use: Symmetric Receive-only
Supports auto-negotiation: Yes
Advertised link modes: 10000baseT/Full
40000baseCR4/Full
Advertised pause frame use: Symmetric
Advertised auto-negotiation: Yes
Speed: 50000Mb/s
Duplex: Full
Port: FIBRE
PHYAD: 1
Transceiver: internal
Auto-negotiation: on
Current message level: 0x00000000 (0)
Link detected: yes
Using kernels 4.7 or newer and ethtool version 4.8 or newer, 25G and 50G
advertisement speeds can be properly configured and displayed, without any
of the limitations described above. ethtool version 4.8 has a bug that
ignores the advertise parameter, so it is recommended to use ethtool 4.10.
Example ethtool 4.10 output showing 10G/25G/40G/50G advertisement settings:
ethtool eth0
Settings for eth0:
Supported ports: [ FIBRE ]
Supported link modes: 10000baseT/Full
40000baseCR4/Full
25000baseCR/Full
50000baseCR2/Full
Supported pause frame use: Symmetric Receive-only
Supports auto-negotiation: Yes
Advertised link modes: 10000baseT/Full
40000baseCR4/Full
25000baseCR/Full
50000baseCR2/Full
Advertised pause frame use: No
Advertised auto-negotiation: Yes
Speed: 50000Mb/s
Duplex: Full
Port: Direct Attach Copper
PHYAD: 1
Transceiver: internal
Auto-negotiation: on
Supports Wake-on: d
Wake-on: d
Current message level: 0x00000000 (0)
Link detected: yes
These are the complete advertise values supported by the driver using 4.7
kernel or newer and a compatible version of ethtool supporting the new
values:
0x020 1000baseT Full
0x1000 10000baseT Full
0x1000000 40000baseCR4 Full
0x80000000 25000baseCR Full
0x400000000 50000baseCR2 Full
Note that the driver does not make a distinction on the exact physical
layer encoding and media type for a link speed. For example, at 50G, the
device may support 50000baseCR2 and 50000baseSR2 for copper and multimode
fiber cables respectively. Regardless of what cabling is used for 50G,
the driver currently uses only the ethtool value defined for 50000baseCR2
to cover all variants of the 50G media types. The same applies to all
other advertise value for other link speeds listed above.
Energy Efficient Ethernet
=========================
The driver supports Energy Efficient Ethernet (EEE) settings on 10GBase-T
devices. If enabled, and connected to a link partner that advertises EEE,
EEE will become active. EEE saves power by entering Low Power Idle (LPI)
state when the transmitter is idle. The downside is increased latency as
it takes a few microseconds to exit LPI to start transmitting again.
On a 10GBase-T device that supports EEE, the link up console message will
include the current state of EEE. For example:
bnxt_en 0000:05:00.0 eth0: NIC Link is Up, 10000 Mbps full duplex, Flow control: none
bnxt_en 0000:05:00.0 eth0: EEE is active
The active state means that EEE is negotiated to be active during
autonegotiation. Additional EEE parameters can be obtained using ethtool:
ethtool --show-eee eth0
EEE Settings for eth0:
EEE status: enabled - active
Tx LPI: 8 (us)
Supported EEE link modes: 10000baseT/Full
Advertised EEE link modes: 10000baseT/Full
Link partner advertised EEE link modes: 10000baseT/Full
The tx LPI timer of 8 microseconds is currently fixed and cannot be adjusted.
EEE is only supported on 10GBase-T. 1GBase-T does not currently support EEE.
To disable EEE:
ethtool --set-eee eth0 eee off
To enable EEE, but disable LPI:
ethtool --set-eee eth0 eee on tx-lpi off
This setting will negotiate EEE with the link partner but the transmitter on
eth0 will not enter LPI during idle. The link partner may independently
choose to enter LPI when its transmitter is idle.
Enabling Receive Side Scaling (RSS)
===================================
By default, the driver enables RSS by allocating receive rings to match the
the number of CPUs (up to 8). Incoming packets are run through a 4-tuple
or 2-tuple hash function for TCP/IP packets and IP packets respectively.
Non fragmented UDP packets are run through a 4-tuple hash function on newer
devices (2-tuple on older devices). See below for more information about
4-tuple and 2-tuple and how to configure it.
The computed hash value will determine the receive ring number for the
packet. This way, RSS distributes packets to multiple receive rings while
guaranteeing that all packets from the same flow will be steered to the same
receive ring. The processing of each receive ring can be done in parallel
by different CPUs to achieve higher performance. For example, irqbalance
will distribute the MSIX vector of each RSS receive ring across CPUs.
However, RSS does not guarantee even distribution or optimal distribution of
packets.
To disable RSS, set the number of receive channels (or combined channels) to 1:
ethtool -L eth0 rx 1 combined 0
or
ethtool -L eth0 combined 1 rx 0 tx 0
To re-enable RSS, set the number of receive channels or (combined channels) to
a value higher than 1.
The RSS hash can be configured for 4-tuple or 2-tuple for various flow types.
4-tuple means that the source, destination IP addresses and layer 4 port
numbers are included in the hash function. 2-tuple means that only the source
and destination IP addresses are included. 4-tuple generally gives better
results. Below are some examples on how to set and display the hash function.
To display the current hash for TCP over IPv4:
ethtool -u eth0 rx-flow-hash tcp4
To disable 4-tuple (enable 2-tuple) for UDP over IPv4:
ethtool -U eth0 rx-flow-hash udp4 sd
To enable 4-tuple for UDP over IPv4:
ethtool -U eth0 rx-flow-hash udp4 sdfn
Enabling Accelerated Receive Flow Steering (RFS)
================================================
RSS distributes packets based on n-tuple hash to multiple receive rings.
The destination receive ring of a packet flow is solely determined by the
hash value. This receive ring may or may not be processed in the kernel by
the CPU where the sockets application consuming the packet flow is running.
Accelerated RFS will steer incoming packet flows to the ring whose MSI-X
vector will interrupt the CPU running the sockets application consuming
the packets. The benefit is higher cache locality of the packet data from
the moment it is processed by the kernel until it is consumed by the
application.
Accelerated RFS requires n-tuple filters to be supported. On older
devices, only Physical Functions (PFs, see SR-IOV below) support n-tuple
filters. On the latest devices, n-tuple filters are supported and enabled
by default on all functions. Use ethtool to disable n-tuple filters:
ethtool -K eth0 ntuple off
To re-enable n-tuple filters:
ethtool -K eth0 ntuple on
After n-tuple filters are enabled, Accelerated RFS will be automatically
enabled when RFS is enabled. These are example steps to enable RFS on
a device with 8 rx rings:
echo 32768 > /proc/sys/net/core/rps_sock_flow_entries
echo 2048 > /sys/class/net/eth0/queues/rx-0/rps_flow_cnt
echo 2048 > /sys/class/net/eth0/queues/rx-1/rps_flow_cnt
echo 2048 > /sys/class/net/eth0/queues/rx-2/rps_flow_cnt
echo 2048 > /sys/class/net/eth0/queues/rx-3/rps_flow_cnt
echo 2048 > /sys/class/net/eth0/queues/rx-4/rps_flow_cnt
echo 2048 > /sys/class/net/eth0/queues/rx-5/rps_flow_cnt
echo 2048 > /sys/class/net/eth0/queues/rx-6/rps_flow_cnt
echo 2048 > /sys/class/net/eth0/queues/rx-7/rps_flow_cnt
These steps will set the global flow table to have 32K entries and each
receive ring to have 2K entries. These values can be adjusted based on
usage.
Note that for Accelerated RFS to be effective, the number of receive channels
(or combined channels) should generally match the number of CPUs. Use
ethtool -L to fine-tune the number of receive channels (or combined channels)
if necessary. Accelerated RFS has precedence over RSS. If a packet matches an
n-tuple filter rule, it will be steered to the RFS specified receive ring.
If the packet does not match any n-tuple filter rule, it will be steered
according to RSS hash.
To display the active n-tuple filters setup for Accelerated RFS:
ethtool -n eth0
IPv6, GRE and IP-inIP n-tuple filters are supported on 4.5 and newer kernels.
Enabling Busy Poll Sockets
==========================
Using 3.11 and newer kernels (also backported to some major distributions),
Busy Poll Sockets are supported by the bnxt_en driver if
CONFIG_NET_RX_BUSY_POLL is enabled. Individual sockets can set the
SO_BUSY_POLL option, or it can be enabled globally using sysctl:
sysctl -w net.core.busy_read=50
This sets the time to busy read the device's receive ring to 50 usecs.
For socket applications waiting for data to arrive, using this method
can decrease latency by 2 or 3 usecs typically at the expense of
higher CPU utilization. The value to use depends on the expected
time the socket will wait for data to arrive. Use 50 usecs as a
starting recommended value.
In addition, the following sysctl parameter should also be set:
sysctl -w net.core.busy_poll=50
This sets the time to busy poll for socket poll and select to 50 usecs.
50 usecs is a recommended value for a small number of polling sockets.
Enabling SR-IOV
===============
The Broadcom NetXtreme-C and NetXtreme-E devices support Single Root I/O
Virtualization (SR-IOV) with Physical Functions (PFs) and Virtual Functions
(VFs) sharing the Ethernet port. The same bnxt_en driver is used for both
PFs and VFs under Linux.
Only the PFs are automatically enabled. If a PF supports SR-IOV, lspci
will show that it has the SR-IOV capability and the total number of VFs
supported. To enable one or more VFs, write the desired number of VFs
to the following sysfs file:
/sys/bus/pci/devices/<domain>:<bus>:<device>:<function>/sriov_numvfs
For example, to enable 4 VFs on bus 82 device 0 function 0:
echo 4 > /sys/bus/pci/devices/0000:82:00.0/sriov_numvfs
To disable the VFs, write 0 to the same sysfs file. Note that to change
the number of VFs, 0 must first be written before writing the new number
of VFs.
On older 2.6 kernels that do not support the sysfs method to enable SR-IOV,
the driver uses the module parameter "num_vfs" to enable the desired number
of VFs. Note that this is a global parameter that applies to all PF
devices in the system. For example, to enable 4 VFs on all supported PFs:
modprobe bnxt_en num_vfs=4
The 4 VFs of each supported PF will be enabled when the PF is brought up.
The VF and the PF operate almost identically under the same Linux driver
but not all operations supported on the PF are supported on the VF.
The resources needed by each VF are assigned by the PF based on how many
VFs are requested to be enabled and the resources currently used by the PF.
It is important to fully configure the PF first with all the desired features,
such as number of RSS/TSS channels, jumbo MTU, etc, before enabling SR-IOV.
After enabling SR-IOV, there may not be enough resources left to reconfigure
the PF.
The resources are evenly divided among the VFs. Enabling a large number of
VFs will result in less resources (such as RSS/TSS channels) for each VF.
Refer to other documentation on how to map a VF to a VM or a Linux Container.
Some attributes of a VF can be set using iproute2 through the PF. SR-IOV
must be enabled by setting the number of desired VFs before any attributes
can be set. Some examples:
1. Set VF MAC address:
ip link set <pf> vf <vf_index> mac <vf_mac>
Example:
ip link set eth0 vf 0 mac 00:12:34:56:78:9a
Note that if the VF MAC addres is not set as shown, a random MAC address will
be used for the VF. If the VF MAC address is changed while the VF driver has
already brought up the VF, it is necessary to bring down and up the VF before
the new MAC address will take effect.
2. Set VF link state:
ip link set <pf> vf <vf_index> state auto|enable|disable
The default is "auto" which reflects the true link state. Setting the VF
link to "enable" allows loopback traffic regardless of the true link state.
Example:
ip link set eth0 vf 0 state enable
3. Set VF default VLAN:
ip link set <pf> vf <vf_index> vlan <vlan id>
Example:
ip link set eth0 vf 0 vlan 100
4. Set VF MAC address spoof check:
ip link set <pf> vf <vf_index> spoofchk on|off
Example:
ip link set eth0 vf 0 spoofchk on
Note that spoofchk is only effective if a VF MAC address has been set as
shown in #1 above.
Virtual Ethernet Bridge (VEB)
=============================
The NetXtreme-C/E devices contain an internal hardware Virtual Ethernet
Bridge (VEB) to bridge traffic between virtual ports enabled by SR-IOV.
VEB is normally turned on by default. VEB can be switched to VEPA
(Virtual Ethernet Port Aggregator) mode if an external VEPA switch is used
to provide bridging between the virtual ports.
Use the bridge command to switch between VEB/VEPA mode. Note that only
the PF driver will accept the command for all virtual ports belonging to the
same physical port. The bridge mode cannot be changed if there are multiple
PFs sharing the same physical port (e.g. NPAR or Multi-Host).
To set the bridge mode:
bridge link set dev <pf> hwmode {veb/vepa}
To show the bridge mode:
bridge link show dev <pf>
Example:
bridge link set dev eth0 hwmode vepa
Note that older firmware does not support VEPA mode.
Hardware QoS
============
The NetXtreme-C/E devices support hardware QoS. The hardware has multiple
internal queues, each can be configured to support different QoS attributes,
such as latency, bandwidth, lossy or lossless data delivery. These QoS
attributes are specified in the IEEE Data Center Bridging (DCB) standard
extensions to Ethernet. DCB parameters include Enhanced Transmission
Selection (ETS) and Priority-based Flow Control (PFC). In a DCB network,
all traffic will be classified into multiple Traffic Classes (TCs), each
of which is assigned different DCB parameters.
Typically, all traffic is VLAN tagged with a 3-bit priority in the VLAN
tag. The VLAN priority is mapped to a TC. For example, a network with
3 TCs may have the following priority to TC mapping:
0:0,1:0,2:0,3:2,4:1,5:0,6:0,7:0
This means that priorities 0,1,2,5,6,7 are mapped to TC0, priority 3 to TC2,
and priority 4 to TC1. ETS allows bandwidth assigment for the TCs. For
example, the ETS bandwidth assignment may be 40%, 50%, and 10% to TC0, TC1,
and TC2 respectively. PFC provides link level flow control for each VLAN
priority independently. For example, if PFC is enabled on VLAN priority 4,
then only TC1 will be subject to flow control without affecting the other
two TCs.
Typically, DCB parameters are automatically configured using the DCB
Capabilities Exchange protocol (DCBX). The bnxt_en driver currently
supports the Linux lldpad DCBX agent. lldpad supports all versions of
DCBX but the bnxt_en driver currently only supports the IEEE DCBX version.
Typically, the DCBX enabled switch will convey the DCB parameters to lldpad
which will then send the hardware QoS parameters to bnxt_en to configure
the device. Refer to the lldpad(8) and lldptool(8) man pages for further
information on how to setup the lldpad DCBX agent.
To support hardware TCs, the proper Linux qdisc must be used to classify
outgoing traffic into their proper hardware TCs. For example, the mqprio
qdisc may be used. A simple example using mqprio qdisc is illustrated below.
Refer to the tc-mqprio(8) man page for more information.
tc qdisc add dev eth0 root mqprio num_tc 3 map 0 0 0 2 1 0 0 0 hw 1
The above command creates the mqprio qdisc with 3 hardware TCs. The priority
to TC mapping is the same as the example at the beginning of the section.
The bnxt_en driver will create 3 groups of tx rings, with each group mapping
to an internal hardware TC.
Once this is created, SKBs with different priorities will be mapped to the
3 TCs according to the specified map above. Note that this SKB priority
is only used to direct packets within the kernel stack to the proper hardware
ring. If the outgoing packets are VLAN tagged, the SKB priority does not
automatically map to the VLAN priority of the packet. The VLAN egress map
has to be set up to have the proper VLAN priority for each packet.
In the current example, if VLAN 100 is used for all traffic, the VLAN egress
map can be set up like this:
ip link add link eth0 name eth0.100 type vlan id 100 \
egress 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7
This creates a one-to-one mapping of SKB priority to VLAN egress priority.
In other words, SKB priority 0 maps VLAN priority 0, SKB priority 1 maps to
VLAN priority 1, etc. This one-to-one mapping should generally be used.
If each TC has more than one ring, TSS will be performed to select a tx ring
within the TC.
To display the current qdisc configuration:
tc qdisc show
Example output:
qdisc mqprio 8010: dev eth0 root tc 3 map 0 0 0 2 1 0 0 0 0 0 0 0 0 0 0 0
queues:(0:3) (4:7) (8:11)
The example above shows that bnxt_en has allocated 4 tx rings for each of the
3 TCs. SKBs with priorities 0,1,2,5,6,7 will be transmitted using tx rings
0 to 3 (TC0). SKBs with priority 4 will be transmitted using rings 4 to 7
(TC1). SKBs with priority 3 will be transmitted using rings 8 to 11 (TC2).
Next, SKB priorities have to be set for different applications so that the
packets from the different applications will be mapped to the proper TCs.
By default, the SKB priority is set to 0. There are multiple methods to set
SKB priorities. net_prio cgroup is a convenient way to do this. Refer to the
link below for more information:
https://www.kernel.org/doc/Documentation/cgroup-v1/net_prio.txt
As mentioned previously, the DCB attributes of each TC are normally configured
by the DCBX agent in lldpad. It is also possible to set the DCB attributes
manually in a simple network or for test purposes. The following example
will manually set up eth0 with the example DCB local parameters mentioned at
the beginning of the section.
lldpad -d
lldptool -T -i eth0 -V ETS-CFG tsa=0:ets,1:ets,2:ets \
up2tc=0:0,1:0,2:0,3:2,4:1,5:0,6:0,7:0 \
tcbw=40,50,10
lldptool -T -i eth0 -V PFC enabled=4
Note that the ETS bandwidth distribution will only be evident when all
traffic classes are transmitting and reaching the link capacity.
See lldptool-ets(8) and lldptool-pfc(8) man pages for more information.
On an NPAR device with multiple partitions sharing the same network port,
DCBX cannot be run on more than one partition. In other words, the lldpad
adminStatus can be set to rxtx on no more than one partition. The same is
true for SRIOV virtual functions. DCBX cannot be run on the VFs.
On these multi-function devices, the hardware TCs are generally shared
between all the functions. The DCB parameters negotiated and setup on
the main function (NPAR or PF function) will be the same on the other
functions sharing the same port. Note that the standard lldptool will
not be able to show the DCB parameters on the other functions which have
adminStatus disabled.
PTP Hardware Clock
==================
The NetXtreme-C/E devices support PTP Hardware Clock which provides hardware
timestamps for PTP v2 packets. The Linux PTP project contains more
information about this feature. A newer 4.x kernel and newer firmware
(2.6.134 or newer) are required to use this feature. Only the first PF
of the network port has access to the hardware PTP feature. Use ethtool -T
to check if PTP Hardware Clock is supported.
BNXT_EN Module Parameters
=========================
On newer 3.x/4.x kernels, the driver does not support any driver parameters.
Please use standard tools (sysfs, ethtool, iproute2, etc) to configure the
driver.
The only exception is the "num_vfs" module parameter supported on older 2.6
kernels to enable SR-IOV. Please see the SR-IOV section above.
BNXT_EN Driver Defaults
=======================
Speed : 1G/2.5G/10G/25G/40G/50G depending on the board.
Flow control : None
MTU : 1500 (range 60 - 9500)
Rx Ring Size : 511 (range 0 - 2047)
Rx Jumbo Ring Size : 2044 (range 0 - 8191) automatically adjusted by the
driver.
Tx Ring Size : 511 (range (MAX_SKB_FRAGS+1) - 2047)
MAX_SKB_FRAGS varies on different kernels and
different architectures. On a 2.6/3.x kernel for
x86, MAX_SKB_FRAGS is 18.
Number of RSS/TSS channels:Up to 8 combined channels to match the number of
CPUs
TSO : Enabled
GRO (hardware) : Enabled
LRO : Disabled
Coalesce rx usecs : 12 usec
Coalesce rx usecs irq : 1 usec
Coalesce rx frames : 15 frames
Coalesce rx frames irq : 1 frame
Coalesce tx usecs : 25 usec
Coalesce tx usecs irq : 2 usec
Coalesce tx frames : 30 frames
Coalesce tx frames irq : 2 frame
Coalesce stats usecs : 1000000 usec (range 250000 - 1000000, 0 to disable)
Statistics
==========
The driver reports all major standard network counters to the stack. These
counters are reported in /proc/net/dev or by other standard tools such as
netstat -i.
Note that the counters are updated every second by the firmware by
default. To increase the frequency of these updates, ethtool -C can
be used to increase the frequency to 0.25 seconds if necessary.
More detailed statistics are reported by ethtool -S. Some of the counters
reported by ethtool -S are for diagnostics purposes only. For example,
the "rx_drops" counter reported by ethtool -S includes dropped packets
that don't match the unicast and multicast filters in the hardware. A
non-zero count is normal and does not generally reflect any error conditions.
This counter should not be confused with the "RX-DRP" counter reported by
netstat -i. The latter reflects dropped packets due to buffer overflow
conditions.
Another example is the "tpa_aborts" counter reported by ethtool -S. It
counts the LRO (Large Receive Offload) aggregation aborts due to normal
TCP conditions. A high tpa_aborts count is generally not an indication
of any errors.
The "rx_ovrsz_frames" counter reported by ethtool -S may count all
packets bigger than 1518 bytes when using earlier versions of the firmware.
Newer version of the firmware has reprogrammed the counter to count
packets bigger than 9600 bytes.
Unloading and Removing Driver
=============================
rmmod bnxt_en
Note that if SR-IOV is enabled and there are active VFs running in VMs, the
PF driver should never be unloaded. It can cause catastrophic failures such
as kernel panics or reboots. The only time the PF driver can be unloaded
with active VFs is when all the VFs and the PF are running in the same host
kernel environment with one driver instance controlling the PF and all the
VFs. Using Linux Containers is one such example where the PF driver can be
unloaded to gracefully shutdown the PF and all the VFs.
Updating Firmware for Broadcom NetXtreme-C and NetXtreme-E devices
==================================================================
Controller firmware may be updated using the Linux request_firmware interface
in conjunction with the ethtool "flash device" interface.
Using the ethtool utility, the controller's boot processor firmware may be
updated by copying the 2 "boot code" firmware files to the local /lib/firmware/
directory:
cp bc1_cm_a.bin bc2_cm_a.bin /lib/firmware
and then issuing the following 2 ethtool commands (both are required):
ethtool -f <device> bc1_cm_a.bin 4
ethtool -f <device> bc2_cm_a.bin 18
NVM packages (*.pkg files) containing controller firmware, microcode,
pre-boot software and configuration data may be installed into a controller's
NVRAM using the ethtool utility by first copying the .pkg file to the local
/lib/firmware/ directory and then executing a single command:
ethtool -f <device> <filename.pkg>
Note: do not specify the full path to the file on the ethtool -f command-line.
Note: root privileges are required to successfully execute these commands.
After "flashing" new firmware into the controller's NVRAM, a cold restart of
the system is required for the new firmware to take effect. This requirement
will be removed in future firmware and driver versions.
Updating Firmware for Broadcom Nitro device
===========================================
Nitro controller firmware should be updated from Uboot prompt by following the
below steps
sf probe
sf erase 0x50000 0x30000
tftpboot 0x85000000 <location>/chimp_xxx.bin
sf write 0x85000000 0x50000 <size in hex>
Release Notes
Broadcom bnxt_en Linux Driver
Version 1.8.1
07/11/2017
Broadcom Limited
5300 California Avenue,
Irvine, CA 92617
Copyright (c) 2015 - 2016 Broadcom Corporation
Copyright (c) 2016 - 2017 Broadcom Limited
All rights reserved
v1.8.1 (July 11, 2017)
======================
This version uses HWRM 1.8.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-25863) Fix warnings and errors in netpoll mode.
2. (CTRL-25665) Fix uninitalized ethtool -S counters when
interface is down on older kernels.
3. (CTRL-25917) Fix crash when ifconfig is retreiving counters
while device is closing.
4. (CTRL-26071) Fix occasional failures when changing ethtool -L
channels from combined to rx/tx or vice versa.
5. Fix SRIOV on big-endian systems.
Enhancements:
1. Fix compile errors on 4.13 kernel.
2. Allow users to disable periodic counter updates for debugging
purposes.
3. Add PTP hardware timestamp support (requires HWRM 1.8.0)
4. Update to HWRM 1.8.0 with better support for link duplex
reporting.
v1.7.30 (June 16, 2017)
=======================
This version uses HWRM 1.7.8.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Fix potential memory corruption when lots of RFS filters are in
use. (backported from 1.7.53)
2. Fixed compile errors on 4.11 kernel. (backported from 1.7.51)
Enhancements:
1. (CTRL-25004) Add VEPA support. (backported from 1.7.54)
2. Fix compile errors on RHEL7.4. (backported from 1.7.53)
v1.7.25 (April 10, 2017)
========================
This version uses HWRM 1.7.6.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Fixed regression in v1.7.24 on the kernels that the fix was
intended for (e.g. 3.10).
v1.7.24 (April 10, 2017)
=======================
This version uses HWRM 1.7.6.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Fixed VF tx rate attribute on some older kernels (e.g. 3.10).
v1.7.23 (April 8, 2017)
=======================
This version uses HWRM 1.7.6.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-25309) Do not allow lldpad to set host based DCBX if
firmware DCBX agent is running.
v1.7.22 (April 7, 2017)
=======================
This version uses HWRM 1.7.6.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-25309) Report to DCBNL if firmware DCBX agent is enabled
so that lldpad will not try to configure the device.
2. Fix VF qos attribute reporting.
Enhancements:
1. (CTRL-25284) Use up to 8 RSS rings by default on RHEL6.3 and
other similar old kernels.
v1.7.21 (Mar 31, 2017)
=======================
This version uses HWRM 1.7.6.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. (CTRL-24874) Cap the use of MSIX with max available completion
rings.
v1.7.20 (Mar 29, 2017)
=======================
This version uses HWRM 1.7.5 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. DMA unmapping bug during shutdown in XDP mode.
2. Removed ethtool -d which is unused and buggy.
3. Fixed compile errors on 4.12 rc kernels.
4. (CTRL-25056) Fixed NULL pointer crash in one open error path.
Enhancements:
1. (CTRL-24492) Use short TX BDs for XDP.
v1.7.9 (Mar 08, 2017)
=====================
This version uses HWRM 1.7.5 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Do not call firmware to get the list of available selftests
unless it is a single PF on a port.
2. Do not allow offline tests if there are active VFs.
v1.7.8 (Mar 07, 2017)
=====================
This version uses HWRM 1.7.5 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. GPL clean up. Remove miscellaneous non-GPL files that are not
needed.
2. Ignore 0 value in autoneg supported speed from firmware.
v1.7.7 (Mar 04, 2017)
=====================
This version uses HWRM 1.7.5 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. Updated to HWRM spec 1.7.5.
v1.7.6 (Mar 03, 2017)
=====================
This version uses HWRM 1.7.4 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-24746) Fix phy loopback self test failure when link
speed is autoneg.
v1.7.5 (Mar 01, 2017)
=====================
This version uses HWRM 1.7.4 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-24724) Perform function reset earlier so that reserved
rings will not be cleared by firmware.
Enhancements:
1. (CTRL-23660) Add ethtool -t selftest supported by HWRM 1.7.4.
2. Disallow lldpad if firmware DCBX/LLDP agent is running.
3. Notify RDMA driver during tx timeout.
v1.7.4 (Feb 20, 2017)
=====================
This version uses HWRM 1.7.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (SOC-5134) Reject driver probe against all bridge devices.
2. (CTRL-24802) Fix NULL pointer dereference when open fails.
3. (CTRL-24803) Fix PCI cleanup when probe fails.
Enhancements:
1. (CTRL-23667) Update to HWRM 1.7.1 spec to support VF MAC address
spoof check.
v1.7.3 (Feb 13, 2017)
=====================
This version uses HWRM 1.7.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-24618) Fix ethtool -l pre-set max combined channels.
2. (CTRL-24206) Fix bugs in retry NVRAM install update operation.
Enhancements:
1. (CTRL-24491, CTRL-24492) Merge with latest upstream XDP
implementation.
v1.7.2 (Feb 6, 2017)
====================
This version uses HWRM 1.7.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. Removed -DNEW_TX compile option. It will always use the new
logic if HWRM spec is 1.6.1 or newer.
v1.7.1 (Feb 6, 2017)
====================
This version uses HWRM 1.7.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. (CTRL-24206) Retry NVRAM install update with defragmentation.
v1.7.0 (Feb 3, 2017)
====================
This version uses HWRM 1.7.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Fix compile errors on Ubuntu 4.2 kernel.
Enhancements:
1. (CTRL-24646) Add support for 57452 and 57454 devices.
v1.6.10 (Jan 26, 2017)
======================
This version uses HWRM 1.6.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-24550, CTRL-24540) Fix compile errors on various
distributions introduced by the Yocto Makefile changes for SoC.
v1.6.9 (Jan 24, 2017)
=====================
This version uses HWRM 1.6.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-24522) Fix compile warnings on RHEL6.9.
2. (CTRL-24491) Fix compile errors on newer kernels supporting XDP.
3. (CTRL-24491) Fix compile errors on early 4.x kernels.
v1.6.8 (Jan 23, 2017)
=====================
This version uses HWRM 1.6.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Fix a kernel mutex deadlock situation during some link event
scenarios.
2. (CTRL-24496) Allow NTUPLE to be enabled on VFs.
3. (CTRL-24365) Silence warning messages from NPAR and VFs by
skipping phy configuration unless it is a single PF.
4. Fix poor TPA GRO performance on Cu devices when TCP timestamp
is not enabled.
5. Fix memory leak when setting DCBX APP TLV.
6. Fix ethtool -p kernel compatibility checks.
v1.6.7 (Jan 09, 2017)
=====================
This version uses HWRM 1.6.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-24308) Fix proper punctuations in bnxt_setup_tc() error
message.
2. (CTRL-24269) Fix compiler warnings when CONFIG_RFS_ACCEL is
not defined.
Enhancements:
1. (CTRL-24268) Compile RDMA interface for all supported kernels.
2. (CTRL-23664) Add GRE and IP encapsulated NTUPLE filter support.
3. Add ethtool -p support.
4. Add SRIOV hooks for RDMA interface.
v1.6.6 (Dec 28, 2016)
=====================
This version uses HWRM 1.6.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-23746) Reserve TX rings when changing the number of TCs
(-DNEW_TX compile option required).
2. (CTRL-24283) Handle one available RX ring gracefully by
disabling TPA and HDS.
Enhancements:
1. Added support for 4.10 kernel's new core MTU structure.
v1.6.5 (Dec 23, 2016)
=====================
This version uses HWRM 1.6.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-24266) Fix regression on VF driver.
v1.6.4 (Dec 22, 2016)
=====================
This version uses HWRM 1.6.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-24213) Disable MSIX before PCI shutdown to prevent
PCIE unsupported request error.
2. (CTRL-23907, CTRL-24172) Set default completion ring for
async event, otherwise all async events may end up going
to bnxt_re's completion ring.
v1.6.3 (Dec 19, 2016)
======================
This version uses HWRM 1.6.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-24084, CTRL-24149, CTRL-24191) Fix Makefile for proper
RHEL7.3 compatibility.
2. Fixed endian conversion for DCBX protocol_id.
v1.6.2 (Dec 14, 2016)
======================
This version uses HWRM 1.6.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. (CTRL-23854) Added support for ipv6 flows on RFS.
2. (CTRL-23683) Implemented new TX ring allocation scheme as a compile
option.
3. (CTRL-23653) Display FEC settings during link up.
v1.6.1 (Dec 08, 2016)
======================
This version uses HWRM 1.6.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Fixed hang issue during modprobe introduced in 1.6.0 when
running on HWRM 1.6.0 or above firmware.
Enhancements:
1. Updated to 1.6.1 firmware HSI.
v1.6.0 (Dec 06, 2016)
======================
This version uses HWRM 1.6.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-23711) Fix IRQ disable sequence during shutdown.
2. (CTRL-23724) Improve resource allocation for VFs.
3. Fix TPA/GRO code path on Cu+ devices.
Enhancements:
1. Updated to 1.6.0 firmware HSI.
2. (CTRL-22565) Improve interface with RDMA driver.
3. Added support for improved Cu+ RFS mode which also supports RFS
on VFs (requires new HWRM 1.6.0 firmware).
4. DCBNL setapp/delapp implemented according to new spec.
v1.5.13 (Nov 17, 2016)
======================
This version uses HWRM 1.5.4 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-23724) Fix bnxt_re registration failure.
v1.5.12 (Nov 16, 2016)
=====================
This version uses HWRM 1.5.4 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. Updated HSI file to include 1.5.0 RoCE HSI.
2. Added ethtool -u|-U to display/set RSS hash (see README.TXT).
3. Better DCB support for NPAR/SR-IOV (see README.TXT).
v1.5.11 (Nov 9, 2016)
=====================
This version uses HWRM 1.5.4 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-22565) Improve NULL pointer fix when bnxt_re registers
using new MSIX scheme (initial Fix in v1.5.7).
v1.5.10 (Nov 8, 2016)
=====================
This version uses HWRM 1.5.4 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Move function reset from open to probe. With the new MSIX
scheme, doing function reset in open may free all resources
allocated by bnxt_re.
v1.5.9 (Nov 4, 2016)
====================
This version uses HWRM 1.5.4 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-22565) Improve early MSIX enablement scheme to prevent
race conditions with RoCE driver.
v1.5.8 (Nov 4, 2016)
====================
This version uses HWRM 1.5.4 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-23629) Fixed RoCE registration regression caused by
fix for CTRL-23568.
v1.5.7 (Nov 2, 2016)
====================
This version uses HWRM 1.5.4 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-23568) Fixed RoCE MSIX regression seen on VF.
2. (CTRL-23475) Fixed VF virtual link state regression since
firmware 20.6.0.
3. (CTRL-22565) Fix NULL pointer derefernce when bnxt_re loads
before network is up.
Enhancements:
1. Added per priority PFC statistics.
2. Changed egress VLAN priority scheme.
v1.5.6 (Oct 26, 2016)
====================
This version uses HWRM 1.5.4 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Fixed hang issue when enabling PFC mapped to TC 2 and above.
2. (CTRL-23288) Do full function reset after suspend/resume.
Enhancements:
1. (CTRL-22565) Enable MSIX early during PCI probe so that MSIX
will always be available whether the network interface is up or
down.
v1.5.5 (Oct 19, 2016)
====================
This version uses HWRM 1.5.3 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. (CTRL-23432) Send DCBX RoCE app TLV data to firmware.
v1.5.4 (Oct 6, 2016)
====================
This version uses HWRM 1.5.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. Updated to HWRM 1.5.2 spec to use the new FORCE_LINK_DWN bit.
v1.5.3 (Sep 23, 2016)
=====================
This version uses HWRM 1.5.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-23107, CTRL-23121, CTRL-23122) Fixed memory corruption
after setting ETS TLV under some conditions.
2. Fix compile error on kernels without CONFIG_DCB enabled.
3. Fix compile error on kernels without RTC_LIB enabled.
4. Fix compile error on SLES11SP4.
v1.5.2 (Sep 16, 2016)
====================
This version uses HWRM 1.5.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Fixed Compilation issue on 3.7 Debian kernel.
2. Fixed autoneg issues on some dual-port devices.
3. (CTRL-22897) Reserved some statistics contexts for RoCE.
Enhancements:
1. Added UDP RSS for 57X1X (Cu+) devices.
2. Added initial hardware QoS support.
v1.5.1 (Sep 2, 2016)
====================
This version uses HWRM 1.5.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Fixed TX PUSH operation on ARM64 and similar architectures.
2. (CTRL-22870) Fixed compile issue on Debian 7.7 (3.2.0-4 kernel)
Enhancements:
1. Updated to support HWRM spec 1.5.1.
2. (CTRL-22776) Added missing 57407 and 5741X NPAR PCI IDs.
3. (CTRL-22886) Improved the setting of VF link state.
4. (CTRL-22737) Added ethtool -r support.
v1.5.0 (Aug 25, 2016)
======================
This version uses HWRM 1.5.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-22748) Fix ethtool -l|-L minor inconsistency.
2. Pad TX packets below 52 bytes to allow traffic to loopback to BMC.
Enhancements:
1. Updated to support HWRM spec 1.5.0.
2. (CTRL-21966) Added secure firmware update.
3. Enable software GRO on 2.6 kernels.
4. Removed "Single-port/Dual-port" from device strings.
v1.3.23 (Jul 15, 2016)
======================
This version uses HWRM 1.3.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Fix 5731X/5741X GRO logic.
Enhancements:
1. (CTRL-22449) Added support for RoCE statistics context.
2. (CTRL-22525) Added all NPAR and 57416/57417 device IDs.
3. (CTRL-22021) Added support for 58700 Nitro devices.
4. Improved ntuple filters by including destination MAC in the
filter.
v1.3.22 (Jun 30, 2016)
======================
This version uses HWRM 1.3.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Fix RoCE MSI-X and completion ring reservation logic. It was
causing SRIOV to fail when enabling a large number of VFs.
v1.3.21 (Jun 29, 2016)
======================
This version uses HWRM 1.3.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. (CTRL-22163) Added support for changing statistics coalescing
using ethtool -C (requires firmware 2.6.11 or newer).
2. Added promiscuous mode support on VF if default VLAN is in use.
v1.3.20 (Jun 23, 2016)
======================
This version uses HWRM 1.3.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Fix hwrm_vnic_cfg with MRU enable bit for correctness.
Enhancements:
1. Increased maximum MTU to 9500.
v1.3.2 (Jul 28, 2016)
=====================
This version uses HWRM 1.3.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. (CTRL-22663) Removed "Single-port/Dual-port" from device strings.
v1.3.1 (Jul 13, 2016)
=====================
This version uses HWRM 1.3.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. (CTRL-22510) Added 5740X NPAR and 57407 device IDs.
v1.3.0 (Jun 29, 2016)
=====================
This version uses HWRM 1.3.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. (CTRL-22089) Added support for suspend/resume.
2. Set up dev_port sysfs attribute with port ID.
v1.2.22 (Jun 17, 2016)
======================
This version uses HWRM 1.3.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. ifup/ifdown on the PF will not cause catastrophic failure on
active VFs.
2. (CTRL-22235) Add support for Kong and Bono firmware updates.
3. Fixed compile issues on 4.6 and 4.7 kernels.
4. (CTRL-22014) Added RoCE driver hooks.
v1.2.21 (Jun 03, 2016)
======================
This version uses HWRM 1.2.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-22179) Fix tx push race condition causing driver crash.
Enhancements:
1. (CTRL-22201) Request APE reset after firmware upgrade.
2. (CTRL-21966) Support NVM secure update item.
v1.2.20 (May 25, 2016)
=====================
This version uses HWRM 1.2.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. (CTRL-22125) Added support for 5731X and 5741X devices.
Known Issues:
1. Default VLAN not working on 5731x/5741x (20.6.6 firmware issue).
2. Accelerated RFS not working on 5731x/5741x (20.6.6 firmware issue).
v1.2.8 (Jun 17, 2016)
=====================
This version uses HWRM 1.3.0 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-22211) Fixed VLAN receive on 3.8 and similar kernels.
2. (CTRL-22319) Fix compatibility issue on SRIOV mode which caused
the set_vf_link_state code to be disabled.
Enhancements:
1. (CTRL-22089) Added magic packet WoL support (shutdown only).
v1.2.7 (Jun 3, 2016)
====================
This version uses HWRM 1.2.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-22158) Return error code when NPAR/VF functions try to
change speed, flow control, etc.
v1.2.6 (May 18, 2016)
=====================
This version uses HWRM 1.2.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Re-implemented default VLAN properly by disabling RX VLAN
acceleration on the VF. New firmware which fixes CTRL-22105 is
also required.
Enhancements:
1. (CTRL-21914) Add NPAR support for 57402, 57404, 57406.
v1.2.5 (May 16, 2016)
=====================
This version uses HWRM 1.2.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Various fixes for ethtool -m.
2. (CTRL-21932) Unsupported SFP modules are now detected before device
is up.
3. (CTRL-22078) Firmware wait time extended to the proper time
specified by the firmware. This may fix some VF firmware timeout
issue.
4. (CTRL-22019) Fixed powerpc panic issue.
Enhancements:
1. (CTRL-21956) Added PCIE link speed and width message during
modprobe.
v1.2.4 (Apr 22, 2016)
=====================
This version uses HWRM 1.2.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-21914) Fix invalid max channels displayed by ethtool -l
when one MSIX is assigned to the function.
2. Fix rx path on architectures using 64K PAGE_SIZE.
Enhancements:
1. (CTRL-21786) Added support for ethtool -m.
v1.2.3 (Apr 15, 2016)
=====================
This version uses HWRM 1.2.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-21965) Don't allow autoneg on NICs that don't support it.
v1.2.2 (Apr 12, 2016)
=====================
This version uses HWRM 1.2.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-21776) Add workaround for hardware duplicate rx opaque
bug (CUMULUS-7831).
2. (CTRL-21934) Don't fall back to INTA if msix allocation fails
on the VF.
v1.2.1 (Mar 25, 2016)
=====================
This version uses HWRM 1.2.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. Fixed incorrect link down state when unsupported optical modules
notifications are enabled.
v1.2.0 (Mar 24, 2016)
=====================
This version uses HWRM 1.2.2 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-21822) Implemented new HWRM scheme for VF MAC address change
for VMWare that also works for Linux PF.
2. (CTRL-21859) Fixed flow control reporting when autoneg is off.
v1.0.7 (Mar 16, 2016)
=====================
This version uses HWRM 1.2.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-21839) Fixed inconsistent EEE reporting on dmesg.
2. Fixed flow control settings logic. This fixes the
update_phy error message when bringing up the VFs with
flow control set to autoneg.
v1.0.6 (Mar 14, 2016)
=====================
This version uses HWRM 1.2.1 and is compatible with all firmware using
HWRM 1.0.0 or above.
Enhancements:
1. (CTRL-21729) Provide NVM and FW status information via ethtool
GEEPROM.
2. Adjusted default coalescing parameters to reduce interrupts.
3. Added check for valid forced speed during ethtool -s.
4. Improved ethtool forced speed settings display.
5. Added default VLAN support for VFs.
Fixes:
1. Fixed RHEL6.8 compile error.
2. (CTRL-21440) Worked around RHEL6.3 source tree bug that caused
issues with IOMMU.
3. Disallow forced speed on 10GbaseT/1GBaseT.
v1.0.5 (Mar 2, 2016)
====================
Enhancements:
1. Added unsupported SFP+ module reporting.
v1.0.4 (Mar 1, 2016)
====================
This version is compatible with all ChiMP FW versions 20.1.x and above using
HWRM 1.0.0 or above.
Enhancements:
1. Updated to support HWRM 1.2.0, backwards compatible to 1.0.0.
2. (CTRL-21401) Added EEE for 10GBase-T devices.
v1.0.3 (Feb 16, 2016)
=====================
This version is compatible with all ChiMP FW version 20.1.x and above using
HWRM 1.0.0 or above.
Fixes:
1. (CTRL-21636) Fixed link down condition when doing rapid speed
changes and changing other settings.
2. (CTRL-20564) Improve default firmware timeout behavior so that
messages requiring long timeouts (such as NVM commands) will work
better with older firmware.
Enhancements:
1. (CTRL-21405) Add PCIE advanced error reporting.
2. Added port statistics for PF.
3. (CTRL-21587) Add autoneg support for 25G/40G/50G. See README.TXT.
v1.0.2 (Jan 26, 2016)
=====================
This version requires ChiMP FW version 20.1.11 (HWRM 1.0.0).
Fixes:
1. (CTRL-21271) Reduce default ring sizes and change default to
combined channels to reduce memory and DMA mappings.
2. (CTRL-21271) Fix crash when freeing tx ring during tx timeout.
3. Fix firmware error message logging to print message fields
properly.
4. Use completion ring to process ring free response response
from firmware.
Enhancements:
1. (CTRL-21288) Add package version information to ethtool -i.
v1.0.1 (Jan 08, 2016)
=====================
This version requires ChiMP FW version 20.1.9 (HWRM 1.0.0).
Fixes:
1. (CTRL-21410, CUMULUS-6643) Exclude hw rx_drop_pkts from the stack's
rx_dropped counter.
v1.0.0 (Jan 07, 2016)
=====================
This version requires ChiMP FW version 20.1.7 (HWRM 1.0.0).
Enhancements:
1. Driver is now compatible with all future versions of production
firmware using HWRM spec 1.0.0 or newer.
v0.1.32 (Dec 18, 2015)
======================
This version requires ChiMP FW version 20.1.5 (HWRM 0.8.0).
Enhancements:
1. Enhanced ethtool -d with a signature to determine endianess.
v0.1.31 (Dec 16, 2015)
======================
This version requires ChiMP FW version 20.1.3 (HWRM 0.7.8).
Fixes:
1. (CTRL-21319) Fixed compile error on RHEL6 2.6.32-573.el6 kernel.
2. (CTRL-20830) Keep track of ring group resources advertised by
firmware.
3. Check for adequate resources before allowing NTUPLE to be enabled.
4. Fixed compile issues on 4.3/4.4 kernels.
5. (CTRL-21379) Fixed rmmod hang on older 3.x kernels.
Enhancements:
1. Removed all A0 workarounds.
2. Added preliminary support for ethtool -d.
3. Added reset to tx timeout and reverted back to 5 seconds.
v0.1.30 (Nov 23, 2015)
======================
This version requires ChiMP FW version 0.1.41 (HWRM 0.7.8).
Fixes:
1. Fixed compile error on generic 3.10 kernel. This was a
regression introduced in version 0.1.29.
v0.1.29 (Nov 23, 2015)
======================
This version requires ChiMP FW version 0.1.41 (HWRM 0.7.8).
Enhancements:
1. (CTRL-21302) Added support for upgrading APE/NC-SI firmware using
ethtool -f.
2. (CTRL-20980) Completed support for all RHEL6.x kernels and generic
2.6.32 kernel.
Fixes:
1. (CTRL-21203) Increment software checksum error counter only if
rx checksum offload is enabled.
v0.1.28 (Nov 17, 2015)
======================
This version requires ChiMP FW version 0.1.39 (HWRM 0.7.8).
Enhancements:
1. (CTRL-21270) Added PCI IDs for 57301 and 57402 devices.
2. More robust SRIOV cleanup sequence to prevent VF crash when
the PF driver is unloaded.
3. (CTRL-20989, CTRL-20925) Implement rx/tx channels to improve tx
performance with dedicated tx and rx completion rings. See
ethtool -L in README.TXT for more information.
Fixes:
1. (CTRL-21217) Fixed SRIOV implementation on RHEL6.x kernels with
num_vfs module parameter.
2. (CTRL-21211) Fixed VLAN acceleration for RHEL6.x kernels.
3. (CTRL-21255) Fixed macvlan issue after driver reset. The
unicast address list needs to be reprogrammed after reset.
4. Fixed INTA implementation by properly mapping the CAG register.
v0.1.27 (Oct 28, 2015)
======================
This version requires ChiMP FW version 0.1.38 (HWRM 0.7.8).
Fixes:
1. (CTRL-21223) Fixed GRO issue when running ipv6 without TCP
timestamps.
v0.1.26 (Oct 23, 2015)
======================
This version requires ChiMP FW version 0.1.38 (HWRM 0.7.8).
Fixes:
1. Fixed MAC address change to take effect immediately.
Enhancements:
1. (CTRL-21163) Added support for RHEL6.3 kernel and OLE6.3 UEK.
2. (CTRL-21186) Added ChiMP reset after flashing firmware with
ethtool -f.
3. (CTRL-21165) Added support for flashing AVS firmware.
v0.1.25 (Oct 09, 2015)
======================
This version requires ChiMP FW version 0.1.36 (HWRM 0.7.8).
Fixes:
1. (CTRL-21064) Fix PF max ring calculation to prevent ethtool -L
failure on PF when SRIOV is enabled.
v0.1.24 (Oct 07, 2015)
======================
This version requires ChiMP FW version 0.1.36 (HWRM 0.7.8).
New Features:
1. (CTRL-21053) Added support for INTA mode. The driver will
automatically fall back to INTA if MSIX is not available.
2. (CTRL-20980) Added initial support for RHEL6.7 and some
similar kernels.
Fixes:
1. Added fixes for ethtool -K ntuple on|off.
2. Added proper accounting of statistics context resources when
changing ethtool channels.
3. (CTRL-21095) Ensure we have enough RSS contexts before enabling
a VF.
4. (CTRL-21048) Make sure GRO packets have valid hash. Disable TPA
during shutdown. Close the device if we cannot initialize it
during configuration changes.
5. (CTRL-20989) Partial fix by setting a limit on tx completion
processing.
6. (CTRL-21011) Make sure ring pages don't exceed the maximum.
Adjust maximum ring sizes to prevent exceeding the maximum.
7. (CTRL-21064) Do not do function reset during ring changes
so that PF/VFs are not affected during ring changes.
Enhancements:
1. Added extra padding for small packets to work in loopback mode
using latest firmware that has TXP padding disabled.
2. Enhanced pause setting changes to trigger link change and
print a new link message when appropriate.
Known Issues:
1. Known VEB firmware issue of duplicating multicast packets on
NIC2. This would cause ipv6 to detect duplicate address.
v0.1.23 (Sep 22, 2015)
======================
This version requires ChiMP FW version 0.1.34 (HWRM 0.7.6).
New Features:
1. Added support for BCM57302 PCI ID.
Fixes:
1. (CTRL-21032) Use modified firmware ring reset to workaround
hardware issue CUMULUS-5196.
2. (CTRL-20989) Partial fix of tx timeout issue by increasing the
timeout value from 5 to 10 seconds. This is a temporary workaround
for the occasional tx completions that can take longer than 5
seconds while the issue is being investigated.
3. (CTRL-21048) Fix macvtap BUG condition while doing ring changes
with TPA (GRO) enabled.
4. Fix the msix table size read from the msix capability. It was off
by 1 in previous versions.
5. (CTRL-21059) Fix RFS on 2nd port. ChiMP firmware fix in 0.1.33
also required.
6. (CTRL-21033) Limit maximum ethtool channels to no more than the
msix table size to prevent failures.
Enhancements:
1. Use smaller (256-byte) 1st buffer with HDS mode.
2. Support asynchronous link events in VF driver.
v0.1.22 (Sep 14, 2015)
======================
This version requires ChiMP FW version 0.1.32 (HWRM 0.7.6).
Fixes:
1. (CTRL-20993) Reject SRIOV configuration from sysfs if PF is down.
2. Fixed ethtool -S counter names discard and drop to match exactly
hardware counter definitions.
3. (CTRL-20705) Fixed kernel oops when running ethtool -L rx 0 tx 0.
Enhancements:
1. (CTRL-20686) Call firmware hwrm_ring_reset to perform recovery
from duplicate opaque hardware issue (CUMULUS-5196)
2. Added support for 3.8 kernel.
v0.1.21 (Sep 10, 2015)
======================
This version requires ChiMP FW version 0.1.31 (HWRM 0.7.6).
New Features:
1. Added autoneg support for 57406 10GBase-T device.
2. (CTRL-20619) Added rx_l4_csum_errors software counter.
Fixes:
1. (CTRL-20704) ethttol -L now returns error when user tries to set
combined or other channels.
2. (CTRL-20704) Fix incorrect ethtool -S statistics when device is
down.
3. Added RSS hash values to skb->hash for RFS packets.
Enhancements:
1. Improved ethtool -{L|l} when VFs are configured.
2. Added support for 3.9 kernel.
v0.1.20 (Sep 01, 2015)
======================
This version requires ChiMP FW version 0.1.30 (HWRM 0.7.6).
New Features:
1. (CTRL-20800) Added ethtool -x to display RSS indirection table and
hash key.
Fixes:
1. Fixed the problem of non-functioning Low Latency Polling mode
after driver config. changes such as MTU change.
Enhancements:
1. Added ability to configure VF MAC address at any time after SR-IOV
is enabled.
v0.1.19 (Aug 26, 2015)
======================
This version requires ChiMP FW version 0.1.28 (HWRM 0.7.6).
New Features:
1. Added Accelerated RFS support on PF for TCP/IPv4.
2. Enabled Header Data split for TPA and jumbo frames.
Fixes:
1. (CTRL-20905) Fixed over-subscription of rx rings, causing failure
when enabling a large number of VFs.
2. Use correct length hint for TSO packets for correct TSO mbuf usage.
3. (CTRL-20930) Enhanced duplicate opaque workaround logic for dual
port and multiple fuctions.
Enhancements:
1. Added basic register and state dump during tx timeout, but no
recovery logic yet.
2. Added support for setting VF link state.
v0.1.18 (Aug 20, 2015)
======================
This version requires ChiMP FW version 0.1.27 (HWRM 0.7.6).
New Features:
1. Added support for 57406 10GBase-T device.
Fixes:
1. (CTRL-20890) Fixed ethtool -L driver bug when increasing the rings
beyond 16.
2. (CTRL-20905) Fixed vnic allocation in VF to increase the number
of supported VF. ChiMP fix is also required to support more
than 32 VFs.
Enhancements:
1. Modified MSI-X IRQ name to work with affinity scripts.
2. Enhanced recovery steps further to include RE_FLUSH and rx doorbell
unmap for hw bug CTRL-20686 (CUMULUS-5196).
Known Issues:
1. PF cannot be brought down or reconfigured if there are active VFs.
v0.1.17 (Aug 12, 2015)
======================
This version requires ChiMP FW version 0.1.26 (HWRM 0.7.5).
New Features:
1. (CTRL-20869) Add support to ethtool -f for pre-boot components.
Enhancements:
1. Speed up the recovery steps for hw bug CTRL-20686 (CUMULUS-5196).
v0.1.16 (Aug 09, 2015)
======================
This version requires ChiMP FW version 0.1.26 (HWRM 0.7.5).
New Features:
1. Added VF device ID 0x16d3 for 57404 VF.
v0.1.15 (Aug 05, 2015)
======================
This version requires ChiMP FW version 0.1.24 (HWRM 0.7.5).
New Features:
1. SR-IOV tested to work on ChiMP FW 0.1.24.
Fixes:
1. (CTRL-20804) Added workaround for TPA_FLUSH to make recovery from
duplicate agg completion (CTRL-20686) reliable.
2. (CUMULUS-5361) Use different TPA_TIMERS_CFG to make TPA timeouts
reliable.
Known Issues:
1. ChiMP FW 0.1.24 has an issue with multicast and SR-IOV. For
example, this problem can affect ipv6 neighbor discovery with
VFs enabled.
v0.1.14 (July 30, 2015)
=======================
This version requires ChiMP FW version 0.1.23 (HWRM 0.7.5).
Fixes:
1. (CTRL-20848) Fix failure to create vxlan tunnel.
2. (CTRL-20651) Update NVRAM HWRM API to work with ChiMP 0.1.23.
3. (CTRL-20823) Fix ethtool -C failure due to out-of-range rx-frames
value.
Known Issues:
1. (CTRL-20841) MTU may need to be adjusted when creating a tunnel so
that the tunnel MTU is divisble by 4 to avoid PCIE errors caused
by known issue with TPA enabled (CTRL-20641).
2. SRIOV has issues with Firmware 0.1.23.
v0.1.13 (July 28, 2015)
=======================
This version requires ChiMP FW version 0.1.22 (HWRM 0.7.5).
New Features:
1. Geneve tunnel stateless offload.
2. VXLAN arbitrary UDP port.
3. Support 4.x kernels.
4. PCIe and PHY microcode update using ethtool -f.
Fixes:
1. (CTRL-20793, CTRL-20796) Fix bridging issues with hardware GRO.
Enhancements:
1. Improved workaround for CTRL-20686.
v0.1.12 (July 13, 2015)
=======================
Fixes:
01. Increased TPA concurrent aggregations to max (64).
02. Refined IRQ coalescing to only enable RING_IDLE feature if
rx-usecs is less than 25 us.
v0.1.11 (July 09, 2015)
=======================
This version supports ChiMP FW version 0.1.20 (HWRM 0.7.4).
Fixes:
01. (CTRL-20686) Implemented workaround to recover from duplicate
aggregation ring completions hardware bug.
v0.1.10 (June 30, 2015)
======================
This version supports ChiMP FW version 0.1.19 (HWRM 0.7.4).
Fixes:
01. Disabled HDS (header data split) to workaround CTRL-20686 hardware
issue so that standard MTU will not hit the issue.
v0.1.9 (June 30, 2015)
======================
This version supports ChiMP FW version 0.1.19 (HWRM 0.7.4).
Fixes:
01. Added support for generic 4.0 kernel.
02. Enabled HDS (header data split) when aggregation ring is used.
v0.1.8 (June 26, 2015)
======================
This version supports ChiMP FW version 0.1.18 (HWRM 0.7.4).
Fixes:
01. Added support for generic 3.10/3.11 kernels.
v0.1.7 (June 24, 2015)
======================
This version supports ChiMP FW version 0.1.18 (HWRM 0.7.4).
Fixes:
01. (CTRL-20641) Added SOP (start of frame padding) to workaround
PCIE error with TPA enabled.
v0.1.6 (June 20, 2015)
======================
This version supports ChiMP FW version 0.1.18 (HWRM 0.7.4).
Fixes:
01. Enabled link change events.
02. Added support for link pause flow control (preview feature, not
well tested).
03. (CTRL-20630) Fixed most crashes during GRO and LRO settings
changes.
v0.1.5 (June 17, 2015)
======================
This version supports ChiMP FW version 0.1.16 (HWRM 0.7.3).
Fixes:
01. Fixed low latency (busy poll) socket mode.
02. (CTRL-20624) Fixed "ethtool -C rx-frames 1" problem.
03. Added ethtool -f support for upgrading firmware.
04. Added ethtool -e support to read NVRAM.
05. Added multiple unicast address support, eliminating the
need to always go into promiscuous mode.
06. Fixed low performance with tunnel packets in GRO mode.
07. (CTRL-20660) Fixed macvtap crash with GRO enabled.
v0.1.4 (May 29, 2015)
======================
This version supports ChiMP FW version 0.1.12 (HWRM 0.7.3).
Fixes:
01. (CTRL-20585) Added workaround for bridge multicast storm issue.
02. Added interrupt coalescing support with new default settings
and configurable using ethtool.
03. Fixed VLAN issue by configuring chip to strip VLAN tags on RX.
04. Added page table support for the larger ring sizes.
05. (CTRL-20599) Fixed transmit queue 8 timeout issue.
06. Updated Chip names with official marketing names.
v0.1.3 (May 23, 2015)
======================
This version supports ChiMP FW version 0.1.11 (HWRM 0.7.3).
Fixes:
01. Fixed TPA setup with large MTUs. Before this fix, TCP
performance was very poor with larger MTUs.
02. Fixed the problem of statistics counters not working after
configuration changes.
v0.1.2 (May 21, 2015)
======================
Fixes:
01. Fixed the "DMA: Out of SW-IOMMU space ..." error by enabling
64-bit DMA. This should also improve performance slightly.
02. Fixed firmware version in ethtool -i by reporting the ChiMP
firmware version as "bc" and the HWRM spec version as "rm".
PHY firmware version was added as "ph".
03. Added module version and description for modinfo.
v0.1.1 (May 19, 2015)
======================
Features tested
01. Cumulus A0 NIC2 and NIC3 at 10/25 Gbps.
02. Dual port support on NIC2
03. TX/RX Checksum offload (IPv4/IPv6)
04. TCP segmentation offload (TSO IPv4/IPv6)
05. MultiQ (TSS / RSS)
06. Statistics (PF only)
07. Ethtool (only options -s -k,-K,-i,-g,-G,-l,-L)
08. vlan acceleration
09. TPA GRO and LRO with ethtool support
10. Broadcast/multicast replication
11. Promiscuous mode support
v0.1.0 (May 15, 2015)
======================
Features tested
01. Cumulus A0 NIC2 at 10 Gbps.
02. Dual port support
03. TX/RX Checksum offload (IPv4/IPv6)
04. TCP segmentation offload (TSO IPv4/IPv6)
05. MultiQ (TSS / RSS)
06. Statistics (PF only)
07. Ethtool (only options -k,-K,-i,-g,-G,-l,-L)
08. vlan acceleration
09. TPA GRO and LRO with ethtool support
10. Broadcast/multicast replication
11. Promiscuous mode support
v0.008 (Mar 11, 2015)
======================
Features supported
01. Dual port support
02. TX/RX Checksum offload (IPv4/IPv6)
03. TCP segmentation offload (TSO IPv4/IPv6)
04. MultiQ (TSS / RSS)
05. Change MTU
06. Jumbo Frames
07. Statistics (PF only)
08. Ethtool (only options -k,-K,-i,-g,-G)
09. vlan acceleration
10. VXLAN stateless offload (only UDP port 4789 is supported)
11. GRE stateless offload
12. IPinIP stateless offload
13. SRIOV
14. VEB
15. TPA GRO and LRO with ethtool support
16. Broadcast/multicast replication fully supported on PF and VF
17. TXP padding disabled and XLMAC padding enabled to workaround
JIRA-4080
18. Added double doorbell to workaround JIRA-3918
19. Added promiscuous mode support
Features not supported:
01. Ethtool options other than -k,-K,-i,-g,-G,-S
02. QoS/DCBX
FPGA: 3.1.27
Chimp FW: 0.0.18
v0.007 (Feb 25, 2015)
======================
Features supported
01. Dual port support
02. TX/RX Checksum offload (IPv4/IPv6)
03. TCP segmentation offload (TSO IPv4/IPv6)
04. MultiQ (TSS / RSS)
05. Change MTU
06. Jumbo Frames
07. Statistics (PF only)
08. Ethtool (only options -k,-K,-i,-g,-G)
09. vlan acceleration
10. VXLAN stateless offload (only UDP port 4789 is supported)
11. GRE stateless offload
12. IPinIP stateless offload
13. SRIOV (most previous limitations removed)
14. VEB (previous limitations removed)
15. TPA GRO and LRO with ethtool support (previous limitations removed)
16. Broadcast/multicast replication fully supported on PF and VF
17. TXP padding disabled and XLMAC padding enabled to workaround
JIRA-4080
18. Added double doorbell to workaround JIRA-3918
Features not supported:
01. Ethtool options other than -k,-K,-i,-g,-G,-S
02. QoS/DCBX
FPGA: 3.1.27
Chimp FW: 0.0.18
v0.006 (Jan 29, 2015)
======================
Features supported
01. Dual port support
02. TX/RX Checksum offload (IPv4/IPv6)
03. TCP segmentation offload (TSO IPv4/IPv6)
04. Change MTU
05. Jumbo Frames
06. Statistics (PF only)
07. Ethtool (only options -k,-K,-i,-g,-G)
08. vlan acceleration
09. VXLAN stateless offload (only UDP port 4789 is supported)
10. GRE stateless offload
11. IPinIP stateless offload
12. SRIOV (limited functionality, check limitations below)
13. VEB (limited functionality, check limitations below)
14. TPA GRO and LRO with ethtool support (check limitations below)
Features not supported:
01. Ethtool options other than -k,-K,-i,-g,-G,-S
02. QoS/DCBX
03. MultiQ (TSS / RSS)
FPGA: 3.1.21
Chimp FW: 0.0.17
v0.005 (Jan 21, 2015)
======================
Features supported
01. Dual port support
02. TX/RX Checksum offload (IPv4/IPv6)
03. TCP segmentation offload (TSO IPv4/IPv6)
04. Change MTU
05. Change Mac Address
06. Jumbo Frames
07. Ethtool (only options -k,-K,-i)
08. vlan acceleration
09. VXLAN stateless offload (only UDP port 4789 is supported)
10. GRE stateless offload
11. IPinIP stateless offload
12. SRIOV (limited functionality, check limitations below)
13. VEB (limited functionality, check limitations below)
13. TPA GRO and LRO with ethtool support (check limitations below)
Features not supported:
01. Statistics
02. Ethtool options other than -k,-K,-i
03. QoS/DCBX
04. MultiQ (TSS / RSS)
v0.004 (Jan 20, 2015)
======================
Features supported
01. Dual port support
02. TX/RX Checksum offload (IPv4/IPv6)
03. TCP segmentation offload (TSO IPv4/IPv6)
04. Change MTU
05. Change Mac Address
06. Jumbo Frames
07. Ethtool (only options -k,-K,-i)
08. vlan acceleration
09. VXLAN stateless offload (only UDP port 4789 is supported)
10. GRE stateless offload
11. IPinIP stateless offload
12. SRIOV (limited functionality, check limitations below)
13. TPA (known issues, check limitations)
Features not supported:
01. Statistics
02. Ethtool options other than -k,-K,-i
03. QoS/DCBX
04. MultiQ (TSS / RSS)
v0.003 (Dec 15, 2014)
======================
Bug fixes:
1. Aggregation ring enablement (JIRA 3359).
2. Broadcast/Multicast filters (JIRA's 3315, 3358).
Features supported
01. TX/RX Checksum offload (IPv4/IPv6)
02. TCP segmentation offload (TSO IPv4/IPv6)
03. MultiQ (TSS / RSS)
04. Change MTU
05. Change Mac Address
06. Jumbo Frames
07. Ethtool (only options -k,-K,-i)
08. vlan acceleration
09. TPA (only LRO)
10. VXLAN stateless offload (only UDP port 4789 is supported)
11. GRE stateless offload
12. IPinIP stateless offload
Features not supported:
01. SRIOV
02. Statistics
03. Ethtool options other than -k,-K,-i
04. QoS/DCBX
v0.001 (Oct 31, 2014)
======================
Features supported:
1. TX/RX Checksum offload
2. Large segment offload (LSO)
3. MultiQ (TSS / RSS)
4. Change MTU
5. Change Mac Address
6. Jumbo Frames
7. vlan
8. Ethtool (only options -k,-K,-i)
Features not supported:
1. Statistics (basic & advanced)
2. Ethtool options other than -k,-K,-i
3. vlan acceleration
4. TPA (LRO/GRO)
5. SRIOV
6. QoS/DCBX
7. Vxlan
========================================================================
DETAILS:
FPGA version 3.1.27:
To program FPGA
1. RDP to any of pb_sniffer[5-10]
2. Map \\pb_file_srvr\drive_e to a drive.
3. Change directory to <DRIVE>\ProDesign\<FPGA version>
4. Run “prg_fpga.bat” <IP address of FPGA>
Chimp FW version 0.0.18:
Locaton: ~/nseg/rels/bcm5734x/firmware/ChiMP_Firmware/0.0.18
To program Chimp FW to NVRAM:
1.esx-dbg (Administrator/broadcom) has the dos USB key.
2.Open your setup idrac and map the usb key (use Mozilla or Chrome)
3.Boot to dos
4.cd cdiag/0915/
5.cdiag.exe -eng
6.Enter the following command in cdiag and wait for completion
1:> nvm upgrade –cfw ncfc0000.17
7.Enter the following command to get fw version
1:> nvm dir
Kernel:
Standard kernel that comes with RHEL7.0 or above
(Development was done using 3.10.0-123.el7.x86_64)
Driver:
nseg: ~/nseg/rels/bcm5734x/drivers/linux/0.006
iproute2:
https://www.kernel.org/pub/linux/utils/net/iproute2/ OR
git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git
============================================================================
Know Issues/Limitations:
SRIOV:
1. Max 2 VF's can be enabled.
2. All VF development/testing was done using 'network namespace' on the
hypervisor itself, no major issues are expected when VF driver is
brought up on a real VM.
a. To enable 'x' VF's
#echo x > /sys/bus/pci/devices/<pci_bus_id of PF0>/sriov_numvfs
b. To disable VF's
#echo 0 > /sys/bus/pci/devices/<pci_bus_id of PF0>/sriov_numvfs
Vlan:
1. RX side vlan stripping cannot be disabled on HW. Thus there is no
support for non-accelerated vlan on RX. If user disables vlan
stripping it will not ping.
2. On TX side vlan normal/accelerated modes are supported.
a. To enable/disable TX vlan acceleration
#ethtool -K vlan-tx-offload on/off
b. To enable/disable RX vlan acceleration
#ethtool -K vlan-rx-offload on/off
============================================================================
This source diff could not be displayed because it is too large. You can view the blob instead.
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2016 Broadcom Corporation
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#ifndef BNXT_H
#define BNXT_H
#define DRV_MODULE_NAME "bnxt_en"
#define DRV_MODULE_VERSION "1.8.1"
#define DRV_VER_MAJ 1
#define DRV_VER_MIN 8
#define DRV_VER_UPD 1
#include <linux/interrupt.h>
struct tx_bd {
__le32 tx_bd_len_flags_type;
#define TX_BD_TYPE (0x3f << 0)
#define TX_BD_TYPE_SHORT_TX_BD (0x00 << 0)
#define TX_BD_TYPE_LONG_TX_BD (0x10 << 0)
#define TX_BD_FLAGS_PACKET_END (1 << 6)
#define TX_BD_FLAGS_NO_CMPL (1 << 7)
#define TX_BD_FLAGS_BD_CNT (0x1f << 8)
#define TX_BD_FLAGS_BD_CNT_SHIFT 8
#define TX_BD_FLAGS_LHINT (3 << 13)
#define TX_BD_FLAGS_LHINT_SHIFT 13
#define TX_BD_FLAGS_LHINT_512_AND_SMALLER (0 << 13)
#define TX_BD_FLAGS_LHINT_512_TO_1023 (1 << 13)
#define TX_BD_FLAGS_LHINT_1024_TO_2047 (2 << 13)
#define TX_BD_FLAGS_LHINT_2048_AND_LARGER (3 << 13)
#define TX_BD_FLAGS_COAL_NOW (1 << 15)
#define TX_BD_LEN (0xffff << 16)
#define TX_BD_LEN_SHIFT 16
u32 tx_bd_opaque;
__le64 tx_bd_haddr;
} __packed;
struct tx_bd_ext {
__le32 tx_bd_hsize_lflags;
#define TX_BD_FLAGS_TCP_UDP_CHKSUM (1 << 0)
#define TX_BD_FLAGS_IP_CKSUM (1 << 1)
#define TX_BD_FLAGS_NO_CRC (1 << 2)
#define TX_BD_FLAGS_STAMP (1 << 3)
#define TX_BD_FLAGS_T_IP_CHKSUM (1 << 4)
#define TX_BD_FLAGS_LSO (1 << 5)
#define TX_BD_FLAGS_IPID_FMT (1 << 6)
#define TX_BD_FLAGS_T_IPID (1 << 7)
#define TX_BD_HSIZE (0xff << 16)
#define TX_BD_HSIZE_SHIFT 16
__le32 tx_bd_mss;
__le32 tx_bd_cfa_action;
#define TX_BD_CFA_ACTION (0xffff << 16)
#define TX_BD_CFA_ACTION_SHIFT 16
__le32 tx_bd_cfa_meta;
#define TX_BD_CFA_META_MASK 0xfffffff
#define TX_BD_CFA_META_VID_MASK 0xfff
#define TX_BD_CFA_META_PRI_MASK (0xf << 12)
#define TX_BD_CFA_META_PRI_SHIFT 12
#define TX_BD_CFA_META_TPID_MASK (3 << 16)
#define TX_BD_CFA_META_TPID_SHIFT 16
#define TX_BD_CFA_META_KEY (0xf << 28)
#define TX_BD_CFA_META_KEY_SHIFT 28
#define TX_BD_CFA_META_KEY_VLAN (1 << 28)
};
struct rx_bd {
__le32 rx_bd_len_flags_type;
#define RX_BD_TYPE (0x3f << 0)
#define RX_BD_TYPE_RX_PACKET_BD 0x4
#define RX_BD_TYPE_RX_BUFFER_BD 0x5
#define RX_BD_TYPE_RX_AGG_BD 0x6
#define RX_BD_TYPE_16B_BD_SIZE (0 << 4)
#define RX_BD_TYPE_32B_BD_SIZE (1 << 4)
#define RX_BD_TYPE_48B_BD_SIZE (2 << 4)
#define RX_BD_TYPE_64B_BD_SIZE (3 << 4)
#define RX_BD_FLAGS_SOP (1 << 6)
#define RX_BD_FLAGS_EOP (1 << 7)
#define RX_BD_FLAGS_BUFFERS (3 << 8)
#define RX_BD_FLAGS_1_BUFFER_PACKET (0 << 8)
#define RX_BD_FLAGS_2_BUFFER_PACKET (1 << 8)
#define RX_BD_FLAGS_3_BUFFER_PACKET (2 << 8)
#define RX_BD_FLAGS_4_BUFFER_PACKET (3 << 8)
#define RX_BD_LEN (0xffff << 16)
#define RX_BD_LEN_SHIFT 16
u32 rx_bd_opaque;
__le64 rx_bd_haddr;
};
struct tx_cmp {
__le32 tx_cmp_flags_type;
#define CMP_TYPE (0x3f << 0)
#define CMP_TYPE_TX_L2_CMP 0
#define CMP_TYPE_RX_L2_CMP 17
#define CMP_TYPE_RX_AGG_CMP 18
#define CMP_TYPE_RX_L2_TPA_START_CMP 19
#define CMP_TYPE_RX_L2_TPA_END_CMP 21
#define CMP_TYPE_STATUS_CMP 32
#define CMP_TYPE_REMOTE_DRIVER_REQ 34
#define CMP_TYPE_REMOTE_DRIVER_RESP 36
#define CMP_TYPE_ERROR_STATUS 48
#define CMPL_BASE_TYPE_STAT_EJECT 0x1aUL
#define CMPL_BASE_TYPE_HWRM_DONE 0x20UL
#define CMPL_BASE_TYPE_HWRM_FWD_REQ 0x22UL
#define CMPL_BASE_TYPE_HWRM_FWD_RESP 0x24UL
#define CMPL_BASE_TYPE_HWRM_ASYNC_EVENT 0x2eUL
#define TX_CMP_FLAGS_ERROR (1 << 6)
#define TX_CMP_FLAGS_PUSH (1 << 7)
u32 tx_cmp_opaque;
__le32 tx_cmp_errors_v;
#define TX_CMP_V (1 << 0)
#define TX_CMP_ERRORS_BUFFER_ERROR (7 << 1)
#define TX_CMP_ERRORS_BUFFER_ERROR_NO_ERROR 0
#define TX_CMP_ERRORS_BUFFER_ERROR_BAD_FORMAT 2
#define TX_CMP_ERRORS_BUFFER_ERROR_INVALID_STAG 4
#define TX_CMP_ERRORS_BUFFER_ERROR_STAG_BOUNDS 5
#define TX_CMP_ERRORS_ZERO_LENGTH_PKT (1 << 4)
#define TX_CMP_ERRORS_EXCESSIVE_BD_LEN (1 << 5)
#define TX_CMP_ERRORS_DMA_ERROR (1 << 6)
#define TX_CMP_ERRORS_HINT_TOO_SHORT (1 << 7)
__le32 tx_cmp_unsed_3;
};
struct rx_cmp {
__le32 rx_cmp_len_flags_type;
#define RX_CMP_CMP_TYPE (0x3f << 0)
#define RX_CMP_FLAGS_ERROR (1 << 6)
#define RX_CMP_FLAGS_PLACEMENT (7 << 7)
#define RX_CMP_FLAGS_RSS_VALID (1 << 10)
#define RX_CMP_FLAGS_UNUSED (1 << 11)
#define RX_CMP_FLAGS_ITYPES_SHIFT 12
#define RX_CMP_FLAGS_ITYPES_MASK 0xf000
#define RX_CMP_FLAGS_ITYPE_UNKNOWN (0 << 12)
#define RX_CMP_FLAGS_ITYPE_IP (1 << 12)
#define RX_CMP_FLAGS_ITYPE_TCP (2 << 12)
#define RX_CMP_FLAGS_ITYPE_UDP (3 << 12)
#define RX_CMP_FLAGS_ITYPE_FCOE (4 << 12)
#define RX_CMP_FLAGS_ITYPE_ROCE (5 << 12)
#define RX_CMP_FLAGS_ITYPE_PTP_WO_TS (8 << 12)
#define RX_CMP_FLAGS_ITYPE_PTP_W_TS (9 << 12)
#define RX_CMP_LEN (0xffff << 16)
#define RX_CMP_LEN_SHIFT 16
u32 rx_cmp_opaque;
__le32 rx_cmp_misc_v1;
#define RX_CMP_V1 (1 << 0)
#define RX_CMP_AGG_BUFS (0x1f << 1)
#define RX_CMP_AGG_BUFS_SHIFT 1
#define RX_CMP_RSS_HASH_TYPE (0x7f << 9)
#define RX_CMP_RSS_HASH_TYPE_SHIFT 9
#define RX_CMP_PAYLOAD_OFFSET (0xff << 16)
#define RX_CMP_PAYLOAD_OFFSET_SHIFT 16
__le32 rx_cmp_rss_hash;
};
#define RX_CMP_HASH_VALID(rxcmp) \
((rxcmp)->rx_cmp_len_flags_type & cpu_to_le32(RX_CMP_FLAGS_RSS_VALID))
#define RSS_PROFILE_ID_MASK 0x1f
#define RX_CMP_HASH_TYPE(rxcmp) \
(((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_RSS_HASH_TYPE) >>\
RX_CMP_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK)
struct rx_cmp_ext {
__le32 rx_cmp_flags2;
#define RX_CMP_FLAGS2_IP_CS_CALC 0x1
#define RX_CMP_FLAGS2_L4_CS_CALC (0x1 << 1)
#define RX_CMP_FLAGS2_T_IP_CS_CALC (0x1 << 2)
#define RX_CMP_FLAGS2_T_L4_CS_CALC (0x1 << 3)
#define RX_CMP_FLAGS2_META_FORMAT_VLAN (0x1 << 4)
__le32 rx_cmp_meta_data;
#define RX_CMP_FLAGS2_METADATA_VID_MASK 0xfff
#define RX_CMP_FLAGS2_METADATA_TPID_MASK 0xffff0000
#define RX_CMP_FLAGS2_METADATA_TPID_SFT 16
__le32 rx_cmp_cfa_code_errors_v2;
#define RX_CMP_V (1 << 0)
#define RX_CMPL_ERRORS_MASK (0x7fff << 1)
#define RX_CMPL_ERRORS_SFT 1
#define RX_CMPL_ERRORS_BUFFER_ERROR_MASK (0x7 << 1)
#define RX_CMPL_ERRORS_BUFFER_ERROR_NO_BUFFER (0x0 << 1)
#define RX_CMPL_ERRORS_BUFFER_ERROR_DID_NOT_FIT (0x1 << 1)
#define RX_CMPL_ERRORS_BUFFER_ERROR_NOT_ON_CHIP (0x2 << 1)
#define RX_CMPL_ERRORS_BUFFER_ERROR_BAD_FORMAT (0x3 << 1)
#define RX_CMPL_ERRORS_IP_CS_ERROR (0x1 << 4)
#define RX_CMPL_ERRORS_L4_CS_ERROR (0x1 << 5)
#define RX_CMPL_ERRORS_T_IP_CS_ERROR (0x1 << 6)
#define RX_CMPL_ERRORS_T_L4_CS_ERROR (0x1 << 7)
#define RX_CMPL_ERRORS_CRC_ERROR (0x1 << 8)
#define RX_CMPL_ERRORS_T_PKT_ERROR_MASK (0x7 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_NO_ERROR (0x0 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_T_L3_BAD_VERSION (0x1 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_T_L3_BAD_HDR_LEN (0x2 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_TUNNEL_TOTAL_ERROR (0x3 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_T_IP_TOTAL_ERROR (0x4 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_T_UDP_TOTAL_ERROR (0x5 << 9)
#define RX_CMPL_ERRORS_T_PKT_ERROR_T_L3_BAD_TTL (0x6 << 9)
#define RX_CMPL_ERRORS_PKT_ERROR_MASK (0xf << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_NO_ERROR (0x0 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_L3_BAD_VERSION (0x1 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_L3_BAD_HDR_LEN (0x2 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_L3_BAD_TTL (0x3 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_IP_TOTAL_ERROR (0x4 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_UDP_TOTAL_ERROR (0x5 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_L4_BAD_HDR_LEN (0x6 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_L4_BAD_HDR_LEN_TOO_SMALL (0x7 << 12)
#define RX_CMPL_ERRORS_PKT_ERROR_L4_BAD_OPT_LEN (0x8 << 12)
#define RX_CMPL_CFA_CODE_MASK (0xffff << 16)
#define RX_CMPL_CFA_CODE_SFT 16
__le32 rx_cmp_unused3;
};
#define RX_CMP_L2_ERRORS \
cpu_to_le32(RX_CMPL_ERRORS_BUFFER_ERROR_MASK | RX_CMPL_ERRORS_CRC_ERROR)
#define RX_CMP_L4_CS_BITS \
(cpu_to_le32(RX_CMP_FLAGS2_L4_CS_CALC | RX_CMP_FLAGS2_T_L4_CS_CALC))
#define RX_CMP_L4_CS_ERR_BITS \
(cpu_to_le32(RX_CMPL_ERRORS_L4_CS_ERROR | RX_CMPL_ERRORS_T_L4_CS_ERROR))
#define RX_CMP_L4_CS_OK(rxcmp1) \
(((rxcmp1)->rx_cmp_flags2 & RX_CMP_L4_CS_BITS) && \
!((rxcmp1)->rx_cmp_cfa_code_errors_v2 & RX_CMP_L4_CS_ERR_BITS))
#define RX_CMP_ENCAP(rxcmp1) \
((le32_to_cpu((rxcmp1)->rx_cmp_flags2) & \
RX_CMP_FLAGS2_T_L4_CS_CALC) >> 3)
struct rx_agg_cmp {
__le32 rx_agg_cmp_len_flags_type;
#define RX_AGG_CMP_TYPE (0x3f << 0)
#define RX_AGG_CMP_LEN (0xffff << 16)
#define RX_AGG_CMP_LEN_SHIFT 16
u32 rx_agg_cmp_opaque;
__le32 rx_agg_cmp_v;
#define RX_AGG_CMP_V (1 << 0)
__le32 rx_agg_cmp_unused;
};
struct rx_tpa_start_cmp {
__le32 rx_tpa_start_cmp_len_flags_type;
#define RX_TPA_START_CMP_TYPE (0x3f << 0)
#define RX_TPA_START_CMP_FLAGS (0x3ff << 6)
#define RX_TPA_START_CMP_FLAGS_SHIFT 6
#define RX_TPA_START_CMP_FLAGS_PLACEMENT (0x7 << 7)
#define RX_TPA_START_CMP_FLAGS_PLACEMENT_SHIFT 7
#define RX_TPA_START_CMP_FLAGS_PLACEMENT_JUMBO (0x1 << 7)
#define RX_TPA_START_CMP_FLAGS_PLACEMENT_HDS (0x2 << 7)
#define RX_TPA_START_CMP_FLAGS_PLACEMENT_GRO_JUMBO (0x5 << 7)
#define RX_TPA_START_CMP_FLAGS_PLACEMENT_GRO_HDS (0x6 << 7)
#define RX_TPA_START_CMP_FLAGS_RSS_VALID (0x1 << 10)
#define RX_TPA_START_CMP_FLAGS_ITYPES (0xf << 12)
#define RX_TPA_START_CMP_FLAGS_ITYPES_SHIFT 12
#define RX_TPA_START_CMP_FLAGS_ITYPE_TCP (0x2 << 12)
#define RX_TPA_START_CMP_LEN (0xffff << 16)
#define RX_TPA_START_CMP_LEN_SHIFT 16
u32 rx_tpa_start_cmp_opaque;
__le32 rx_tpa_start_cmp_misc_v1;
#define RX_TPA_START_CMP_V1 (0x1 << 0)
#define RX_TPA_START_CMP_RSS_HASH_TYPE (0x7f << 9)
#define RX_TPA_START_CMP_RSS_HASH_TYPE_SHIFT 9
#define RX_TPA_START_CMP_AGG_ID (0x7f << 25)
#define RX_TPA_START_CMP_AGG_ID_SHIFT 25
__le32 rx_tpa_start_cmp_rss_hash;
};
#define TPA_START_HASH_VALID(rx_tpa_start) \
((rx_tpa_start)->rx_tpa_start_cmp_len_flags_type & \
cpu_to_le32(RX_TPA_START_CMP_FLAGS_RSS_VALID))
#define TPA_START_HASH_TYPE(rx_tpa_start) \
(((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \
RX_TPA_START_CMP_RSS_HASH_TYPE) >> \
RX_TPA_START_CMP_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK)
#define TPA_START_AGG_ID(rx_tpa_start) \
((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \
RX_TPA_START_CMP_AGG_ID) >> RX_TPA_START_CMP_AGG_ID_SHIFT)
struct rx_tpa_start_cmp_ext {
__le32 rx_tpa_start_cmp_flags2;
#define RX_TPA_START_CMP_FLAGS2_IP_CS_CALC (0x1 << 0)
#define RX_TPA_START_CMP_FLAGS2_L4_CS_CALC (0x1 << 1)
#define RX_TPA_START_CMP_FLAGS2_T_IP_CS_CALC (0x1 << 2)
#define RX_TPA_START_CMP_FLAGS2_T_L4_CS_CALC (0x1 << 3)
#define RX_TPA_START_CMP_FLAGS2_IP_TYPE (0x1 << 8)
__le32 rx_tpa_start_cmp_metadata;
__le32 rx_tpa_start_cmp_cfa_code_v2;
#define RX_TPA_START_CMP_V2 (0x1 << 0)
#define RX_TPA_START_CMP_CFA_CODE (0xffff << 16)
#define RX_TPA_START_CMPL_CFA_CODE_SHIFT 16
__le32 rx_tpa_start_cmp_hdr_info;
};
struct rx_tpa_end_cmp {
__le32 rx_tpa_end_cmp_len_flags_type;
#define RX_TPA_END_CMP_TYPE (0x3f << 0)
#define RX_TPA_END_CMP_FLAGS (0x3ff << 6)
#define RX_TPA_END_CMP_FLAGS_SHIFT 6
#define RX_TPA_END_CMP_FLAGS_PLACEMENT (0x7 << 7)
#define RX_TPA_END_CMP_FLAGS_PLACEMENT_SHIFT 7
#define RX_TPA_END_CMP_FLAGS_PLACEMENT_JUMBO (0x1 << 7)
#define RX_TPA_END_CMP_FLAGS_PLACEMENT_HDS (0x2 << 7)
#define RX_TPA_END_CMP_FLAGS_PLACEMENT_GRO_JUMBO (0x5 << 7)
#define RX_TPA_END_CMP_FLAGS_PLACEMENT_GRO_HDS (0x6 << 7)
#define RX_TPA_END_CMP_FLAGS_RSS_VALID (0x1 << 10)
#define RX_TPA_END_CMP_FLAGS_ITYPES (0xf << 12)
#define RX_TPA_END_CMP_FLAGS_ITYPES_SHIFT 12
#define RX_TPA_END_CMP_FLAGS_ITYPE_TCP (0x2 << 12)
#define RX_TPA_END_CMP_LEN (0xffff << 16)
#define RX_TPA_END_CMP_LEN_SHIFT 16
u32 rx_tpa_end_cmp_opaque;
__le32 rx_tpa_end_cmp_misc_v1;
#define RX_TPA_END_CMP_V1 (0x1 << 0)
#define RX_TPA_END_CMP_AGG_BUFS (0x3f << 1)
#define RX_TPA_END_CMP_AGG_BUFS_SHIFT 1
#define RX_TPA_END_CMP_TPA_SEGS (0xff << 8)
#define RX_TPA_END_CMP_TPA_SEGS_SHIFT 8
#define RX_TPA_END_CMP_PAYLOAD_OFFSET (0xff << 16)
#define RX_TPA_END_CMP_PAYLOAD_OFFSET_SHIFT 16
#define RX_TPA_END_CMP_AGG_ID (0x7f << 25)
#define RX_TPA_END_CMP_AGG_ID_SHIFT 25
__le32 rx_tpa_end_cmp_tsdelta;
#define RX_TPA_END_GRO_TS (0x1 << 31)
};
#define TPA_END_AGG_ID(rx_tpa_end) \
((le32_to_cpu((rx_tpa_end)->rx_tpa_end_cmp_misc_v1) & \
RX_TPA_END_CMP_AGG_ID) >> RX_TPA_END_CMP_AGG_ID_SHIFT)
#define TPA_END_TPA_SEGS(rx_tpa_end) \
((le32_to_cpu((rx_tpa_end)->rx_tpa_end_cmp_misc_v1) & \
RX_TPA_END_CMP_TPA_SEGS) >> RX_TPA_END_CMP_TPA_SEGS_SHIFT)
#define RX_TPA_END_CMP_FLAGS_PLACEMENT_ANY_GRO \
cpu_to_le32(RX_TPA_END_CMP_FLAGS_PLACEMENT_GRO_JUMBO & \
RX_TPA_END_CMP_FLAGS_PLACEMENT_GRO_HDS)
#define TPA_END_GRO(rx_tpa_end) \
((rx_tpa_end)->rx_tpa_end_cmp_len_flags_type & \
RX_TPA_END_CMP_FLAGS_PLACEMENT_ANY_GRO)
#define TPA_END_GRO_TS(rx_tpa_end) \
(!!((rx_tpa_end)->rx_tpa_end_cmp_tsdelta & \
cpu_to_le32(RX_TPA_END_GRO_TS)))
struct rx_tpa_end_cmp_ext {
__le32 rx_tpa_end_cmp_dup_acks;
#define RX_TPA_END_CMP_TPA_DUP_ACKS (0xf << 0)
__le32 rx_tpa_end_cmp_seg_len;
#define RX_TPA_END_CMP_TPA_SEG_LEN (0xffff << 0)
__le32 rx_tpa_end_cmp_errors_v2;
#define RX_TPA_END_CMP_V2 (0x1 << 0)
#define RX_TPA_END_CMP_ERRORS (0x3 << 1)
#define RX_TPA_END_CMPL_ERRORS_SHIFT 1
u32 rx_tpa_end_cmp_start_opaque;
};
#define TPA_END_ERRORS(rx_tpa_end_ext) \
((rx_tpa_end_ext)->rx_tpa_end_cmp_errors_v2 & \
cpu_to_le32(RX_TPA_END_CMP_ERRORS))
#define DB_IDX_MASK 0xffffff
#define DB_IDX_VALID (0x1 << 26)
#define DB_IRQ_DIS (0x1 << 27)
#define DB_KEY_TX (0x0 << 28)
#define DB_KEY_RX (0x1 << 28)
#define DB_KEY_CP (0x2 << 28)
#define DB_KEY_ST (0x3 << 28)
#define DB_KEY_TX_PUSH (0x4 << 28)
#define DB_LONG_TX_PUSH (0x2 << 24)
#define INVALID_HW_RING_ID ((u16)-1)
/* The hardware supports certain page sizes. Use the supported page sizes
* to allocate the rings.
*/
#if (PAGE_SHIFT < 12)
#define BNXT_PAGE_SHIFT 12
#elif (PAGE_SHIFT <= 13)
#define BNXT_PAGE_SHIFT PAGE_SHIFT
#elif (PAGE_SHIFT < 16)
#define BNXT_PAGE_SHIFT 13
#else
#define BNXT_PAGE_SHIFT 16
#endif
#define BNXT_PAGE_SIZE (1 << BNXT_PAGE_SHIFT)
/* The RXBD length is 16-bit so we can only support page sizes < 64K */
#if (PAGE_SHIFT > 15)
#define BNXT_RX_PAGE_SHIFT 15
#else
#define BNXT_RX_PAGE_SHIFT PAGE_SHIFT
#endif
#define BNXT_RX_PAGE_SIZE (1 << BNXT_RX_PAGE_SHIFT)
#define BNXT_MAX_MTU 9500
#define BNXT_MAX_PAGE_MODE_MTU \
((unsigned int)PAGE_SIZE - VLAN_ETH_HLEN - NET_IP_ALIGN - \
XDP_PACKET_HEADROOM)
#define BNXT_MIN_PKT_SIZE 52
#define BNXT_DEFAULT_RX_RING_SIZE 511
#define BNXT_DEFAULT_TX_RING_SIZE 511
#define MAX_TPA 64
#if (BNXT_PAGE_SHIFT == 16)
#define MAX_RX_PAGES 1
#define MAX_RX_AGG_PAGES 4
#define MAX_TX_PAGES 1
#define MAX_CP_PAGES 8
#else
#define MAX_RX_PAGES 8
#define MAX_RX_AGG_PAGES 32
#define MAX_TX_PAGES 8
#define MAX_CP_PAGES 64
#endif
#define RX_DESC_CNT (BNXT_PAGE_SIZE / sizeof(struct rx_bd))
#define TX_DESC_CNT (BNXT_PAGE_SIZE / sizeof(struct tx_bd))
#define CP_DESC_CNT (BNXT_PAGE_SIZE / sizeof(struct tx_cmp))
#define SW_RXBD_RING_SIZE (sizeof(struct bnxt_sw_rx_bd) * RX_DESC_CNT)
#define HW_RXBD_RING_SIZE (sizeof(struct rx_bd) * RX_DESC_CNT)
#define SW_RXBD_AGG_RING_SIZE (sizeof(struct bnxt_sw_rx_agg_bd) * RX_DESC_CNT)
#define SW_TXBD_RING_SIZE (sizeof(struct bnxt_sw_tx_bd) * TX_DESC_CNT)
#define HW_TXBD_RING_SIZE (sizeof(struct tx_bd) * TX_DESC_CNT)
#define HW_CMPD_RING_SIZE (sizeof(struct tx_cmp) * CP_DESC_CNT)
#define BNXT_MAX_RX_DESC_CNT (RX_DESC_CNT * MAX_RX_PAGES - 1)
#define BNXT_MAX_RX_JUM_DESC_CNT (RX_DESC_CNT * MAX_RX_AGG_PAGES - 1)
#define BNXT_MAX_TX_DESC_CNT (TX_DESC_CNT * MAX_TX_PAGES - 1)
#define RX_RING(x) (((x) & ~(RX_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4))
#define RX_IDX(x) ((x) & (RX_DESC_CNT - 1))
#define TX_RING(x) (((x) & ~(TX_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4))
#define TX_IDX(x) ((x) & (TX_DESC_CNT - 1))
#define CP_RING(x) (((x) & ~(CP_DESC_CNT - 1)) >> (BNXT_PAGE_SHIFT - 4))
#define CP_IDX(x) ((x) & (CP_DESC_CNT - 1))
#define TX_CMP_VALID(txcmp, raw_cons) \
(!!((txcmp)->tx_cmp_errors_v & cpu_to_le32(TX_CMP_V)) == \
!((raw_cons) & bp->cp_bit))
#define RX_CMP_VALID(rxcmp1, raw_cons) \
(!!((rxcmp1)->rx_cmp_cfa_code_errors_v2 & cpu_to_le32(RX_CMP_V)) ==\
!((raw_cons) & bp->cp_bit))
#define RX_AGG_CMP_VALID(agg, raw_cons) \
(!!((agg)->rx_agg_cmp_v & cpu_to_le32(RX_AGG_CMP_V)) == \
!((raw_cons) & bp->cp_bit))
#define TX_CMP_TYPE(txcmp) \
(le32_to_cpu((txcmp)->tx_cmp_flags_type) & CMP_TYPE)
#define RX_CMP_TYPE(rxcmp) \
(le32_to_cpu((rxcmp)->rx_cmp_len_flags_type) & RX_CMP_CMP_TYPE)
#define NEXT_RX(idx) (((idx) + 1) & bp->rx_ring_mask)
#define NEXT_RX_AGG(idx) (((idx) + 1) & bp->rx_agg_ring_mask)
#define NEXT_TX(idx) (((idx) + 1) & bp->tx_ring_mask)
#define ADV_RAW_CMP(idx, n) ((idx) + (n))
#define NEXT_RAW_CMP(idx) ADV_RAW_CMP(idx, 1)
#define RING_CMP(idx) ((idx) & bp->cp_ring_mask)
#define NEXT_CMP(idx) RING_CMP(ADV_RAW_CMP(idx, 1))
#define BNXT_HWRM_MAX_REQ_LEN (bp->hwrm_max_req_len)
#define DFLT_HWRM_CMD_TIMEOUT 500
#define HWRM_CMD_TIMEOUT (bp->hwrm_cmd_timeout)
#define HWRM_RESET_TIMEOUT ((HWRM_CMD_TIMEOUT) * 4)
#define HWRM_RESP_ERR_CODE_MASK 0xffff
#define HWRM_RESP_LEN_OFFSET 4
#define HWRM_RESP_LEN_MASK 0xffff0000
#define HWRM_RESP_LEN_SFT 16
#define HWRM_RESP_VALID_MASK 0xff000000
#define HWRM_SEQ_ID_INVALID -1
#define BNXT_HWRM_REQ_MAX_SIZE 128
#define BNXT_HWRM_REQS_PER_PAGE (BNXT_PAGE_SIZE / \
BNXT_HWRM_REQ_MAX_SIZE)
#define BNXT_RX_EVENT 1
#define BNXT_AGG_EVENT 2
#define BNXT_TX_EVENT 4
struct bnxt_sw_tx_bd {
struct sk_buff *skb;
DEFINE_DMA_UNMAP_ADDR(mapping);
u8 is_gso;
u8 is_push;
union {
unsigned short nr_frags;
u16 rx_prod;
};
};
struct bnxt_sw_rx_bd {
void *data;
u8 *data_ptr;
dma_addr_t mapping;
};
struct bnxt_sw_rx_agg_bd {
struct page *page;
unsigned int offset;
dma_addr_t mapping;
};
struct bnxt_ring_struct {
int nr_pages;
int page_size;
void **pg_arr;
dma_addr_t *dma_arr;
__le64 *pg_tbl;
dma_addr_t pg_tbl_map;
int vmem_size;
void **vmem;
u16 fw_ring_id; /* Ring id filled by Chimp FW */
u8 queue_id;
};
struct tx_push_bd {
__le32 doorbell;
__le32 tx_bd_len_flags_type;
u32 tx_bd_opaque;
struct tx_bd_ext txbd2;
};
struct tx_push_buffer {
struct tx_push_bd push_bd;
u32 data[25];
};
struct bnxt_tx_ring_info {
struct bnxt_napi *bnapi;
u16 tx_prod;
u16 tx_cons;
u16 txq_index;
void __iomem *tx_doorbell;
struct tx_bd *tx_desc_ring[MAX_TX_PAGES];
struct bnxt_sw_tx_bd *tx_buf_ring;
dma_addr_t tx_desc_mapping[MAX_TX_PAGES];
struct tx_push_buffer *tx_push;
dma_addr_t tx_push_mapping;
__le64 data_mapping;
#define BNXT_DEV_STATE_CLOSING 0x1
u32 dev_state;
struct bnxt_ring_struct tx_ring_struct;
};
struct bnxt_tpa_info {
void *data;
u8 *data_ptr;
dma_addr_t mapping;
u16 len;
unsigned short gso_type;
u32 flags2;
u32 metadata;
enum pkt_hash_types hash_type;
u32 rss_hash;
u32 hdr_info;
#define BNXT_TPA_L4_SIZE(hdr_info) \
(((hdr_info) & 0xf8000000) ? ((hdr_info) >> 27) : 32)
#define BNXT_TPA_INNER_L3_OFF(hdr_info) \
(((hdr_info) >> 18) & 0x1ff)
#define BNXT_TPA_INNER_L2_OFF(hdr_info) \
(((hdr_info) >> 9) & 0x1ff)
#define BNXT_TPA_OUTER_L3_OFF(hdr_info) \
((hdr_info) & 0x1ff)
};
struct bnxt_rx_ring_info {
struct bnxt_napi *bnapi;
u16 rx_prod;
u16 rx_agg_prod;
u16 rx_sw_agg_prod;
u16 rx_next_cons;
void __iomem *rx_doorbell;
void __iomem *rx_agg_doorbell;
#ifdef HAVE_NDO_XDP
struct bpf_prog *xdp_prog;
#endif
struct rx_bd *rx_desc_ring[MAX_RX_PAGES];
struct bnxt_sw_rx_bd *rx_buf_ring;
struct rx_bd *rx_agg_desc_ring[MAX_RX_AGG_PAGES];
struct bnxt_sw_rx_agg_bd *rx_agg_ring;
unsigned long *rx_agg_bmap;
u16 rx_agg_bmap_size;
struct page *rx_page;
unsigned int rx_page_offset;
dma_addr_t rx_desc_mapping[MAX_RX_PAGES];
dma_addr_t rx_agg_desc_mapping[MAX_RX_AGG_PAGES];
struct bnxt_tpa_info *rx_tpa;
struct bnxt_ring_struct rx_ring_struct;
struct bnxt_ring_struct rx_agg_ring_struct;
};
struct bnxt_sw_stats {
u64 rx_l4_csum_errors;
u64 rx_resets;
};
struct bnxt_cp_ring_info {
u32 cp_raw_cons;
void __iomem *cp_doorbell;
struct tx_cmp *cp_desc_ring[MAX_CP_PAGES];
dma_addr_t cp_desc_mapping[MAX_CP_PAGES];
struct ctx_hw_stats *hw_stats;
dma_addr_t hw_stats_map;
u32 hw_stats_ctx_id;
struct bnxt_sw_stats sw_stats;
struct bnxt_ring_struct cp_ring_struct;
};
struct bnxt_napi {
struct napi_struct napi;
struct bnxt *bp;
int index;
struct bnxt_cp_ring_info cp_ring;
struct bnxt_rx_ring_info *rx_ring;
struct bnxt_tx_ring_info *tx_ring;
void (*tx_int)(struct bnxt *, struct bnxt_napi *,
int);
u32 flags;
#define BNXT_NAPI_FLAG_XDP 0x1
#ifdef BNXT_PRIV_RX_BUSY_POLL
atomic_t poll_state;
#endif
bool in_reset;
};
#ifdef BNXT_PRIV_RX_BUSY_POLL
enum bnxt_poll_state_t {
BNXT_STATE_IDLE = 0,
BNXT_STATE_NAPI,
BNXT_STATE_POLL,
BNXT_STATE_DISABLE,
};
#endif
struct bnxt_irq {
irq_handler_t handler;
unsigned int vector;
u8 requested;
char name[IFNAMSIZ + 2];
};
#define HWRM_RING_ALLOC_TX 0x1
#define HWRM_RING_ALLOC_RX 0x2
#define HWRM_RING_ALLOC_AGG 0x4
#define HWRM_RING_ALLOC_CMPL 0x8
#define INVALID_STATS_CTX_ID -1
struct bnxt_ring_grp_info {
u16 fw_stats_ctx;
u16 fw_grp_id;
u16 rx_fw_ring_id;
u16 agg_fw_ring_id;
u16 cp_fw_ring_id;
};
struct bnxt_vnic_info {
u16 fw_vnic_id; /* returned by Chimp during alloc */
#define BNXT_MAX_CTX_PER_VNIC 2
u16 fw_rss_cos_lb_ctx[BNXT_MAX_CTX_PER_VNIC];
u16 fw_l2_ctx_id;
#define BNXT_MAX_UC_ADDRS 4
__le64 fw_l2_filter_id[BNXT_MAX_UC_ADDRS];
/* index 0 always dev_addr */
u16 uc_filter_count;
u8 *uc_list;
u16 *fw_grp_ids;
dma_addr_t rss_table_dma_addr;
__le16 *rss_table;
dma_addr_t rss_hash_key_dma_addr;
u64 *rss_hash_key;
u32 rx_mask;
u8 *mc_list;
int mc_list_size;
int mc_list_count;
dma_addr_t mc_list_mapping;
#define BNXT_MAX_MC_ADDRS 16
u32 flags;
#define BNXT_VNIC_RSS_FLAG 1
#define BNXT_VNIC_RFS_FLAG 2
#define BNXT_VNIC_MCAST_FLAG 4
#define BNXT_VNIC_UCAST_FLAG 8
#define BNXT_VNIC_RFS_NEW_RSS_FLAG 0x10
};
#if defined(CONFIG_BNXT_SRIOV)
struct bnxt_vf_info {
u16 fw_fid;
u8 mac_addr[ETH_ALEN];
u16 max_rsscos_ctxs;
u16 max_cp_rings;
u16 max_tx_rings;
u16 max_rx_rings;
u16 max_hw_ring_grps;
u16 max_l2_ctxs;
u16 max_irqs;
u16 max_vnics;
u16 max_stat_ctxs;
u16 vlan;
u32 flags;
#define BNXT_VF_QOS 0x1
#define BNXT_VF_SPOOFCHK 0x2
#define BNXT_VF_LINK_FORCED 0x4
#define BNXT_VF_LINK_UP 0x8
u32 func_flags; /* func cfg flags */
u32 min_tx_rate;
u32 max_tx_rate;
void *hwrm_cmd_req_addr;
dma_addr_t hwrm_cmd_req_dma_addr;
};
#endif
struct bnxt_pf_info {
#define BNXT_FIRST_PF_FID 1
#define BNXT_FIRST_VF_FID 128
u16 fw_fid;
u16 port_id;
u8 mac_addr[ETH_ALEN];
u16 max_rsscos_ctxs;
u16 max_cp_rings;
u16 max_tx_rings; /* HW assigned max tx rings for this PF */
u16 max_rx_rings; /* HW assigned max rx rings for this PF */
u16 max_hw_ring_grps;
u16 max_irqs;
u16 max_l2_ctxs;
u16 max_vnics;
u16 max_stat_ctxs;
u32 first_vf_id;
u16 active_vfs;
u16 max_vfs;
u32 max_encap_records;
u32 max_decap_records;
u32 max_tx_em_flows;
u32 max_tx_wm_flows;
u32 max_rx_em_flows;
u32 max_rx_wm_flows;
unsigned long *vf_event_bmap;
u16 hwrm_cmd_req_pages;
void *hwrm_cmd_req_addr[4];
dma_addr_t hwrm_cmd_req_dma_addr[4];
struct bnxt_vf_info *vf;
};
#ifdef CONFIG_RFS_ACCEL
struct bnxt_ntuple_filter {
struct hlist_node hash;
u8 dst_mac_addr[ETH_ALEN];
u8 src_mac_addr[ETH_ALEN];
struct flow_keys fkeys;
__le64 filter_id;
u16 sw_id;
u8 l2_fltr_idx;
u16 rxq;
u32 flow_id;
unsigned long state;
#define BNXT_FLTR_VALID 0
#define BNXT_FLTR_UPDATE 1
};
#endif
struct bnxt_link_info {
u8 phy_type;
u8 media_type;
u8 transceiver;
u8 phy_addr;
u8 phy_link_status;
#define BNXT_LINK_NO_LINK PORT_PHY_QCFG_RESP_LINK_NO_LINK
#define BNXT_LINK_SIGNAL PORT_PHY_QCFG_RESP_LINK_SIGNAL
#define BNXT_LINK_LINK PORT_PHY_QCFG_RESP_LINK_LINK
u8 wire_speed;
u8 loop_back;
u8 link_up;
u8 duplex;
#define BNXT_LINK_DUPLEX_HALF PORT_PHY_QCFG_RESP_DUPLEX_STATE_HALF
#define BNXT_LINK_DUPLEX_FULL PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL
u8 pause;
#define BNXT_LINK_PAUSE_TX PORT_PHY_QCFG_RESP_PAUSE_TX
#define BNXT_LINK_PAUSE_RX PORT_PHY_QCFG_RESP_PAUSE_RX
#define BNXT_LINK_PAUSE_BOTH (PORT_PHY_QCFG_RESP_PAUSE_RX | \
PORT_PHY_QCFG_RESP_PAUSE_TX)
u8 lp_pause;
u8 auto_pause_setting;
u8 force_pause_setting;
u8 duplex_setting;
u8 auto_mode;
#define BNXT_AUTO_MODE(mode) ((mode) > BNXT_LINK_AUTO_NONE && \
(mode) <= BNXT_LINK_AUTO_MSK)
#define BNXT_LINK_AUTO_NONE PORT_PHY_QCFG_RESP_AUTO_MODE_NONE
#define BNXT_LINK_AUTO_ALLSPDS PORT_PHY_QCFG_RESP_AUTO_MODE_ALL_SPEEDS
#define BNXT_LINK_AUTO_ONESPD PORT_PHY_QCFG_RESP_AUTO_MODE_ONE_SPEED
#define BNXT_LINK_AUTO_ONEORBELOW PORT_PHY_QCFG_RESP_AUTO_MODE_ONE_OR_BELOW
#define BNXT_LINK_AUTO_MSK PORT_PHY_QCFG_RESP_AUTO_MODE_SPEED_MASK
#define PHY_VER_LEN 3
u8 phy_ver[PHY_VER_LEN];
u16 link_speed;
#define BNXT_LINK_SPEED_100MB PORT_PHY_QCFG_RESP_LINK_SPEED_100MB
#define BNXT_LINK_SPEED_1GB PORT_PHY_QCFG_RESP_LINK_SPEED_1GB
#define BNXT_LINK_SPEED_2GB PORT_PHY_QCFG_RESP_LINK_SPEED_2GB
#define BNXT_LINK_SPEED_2_5GB PORT_PHY_QCFG_RESP_LINK_SPEED_2_5GB
#define BNXT_LINK_SPEED_10GB PORT_PHY_QCFG_RESP_LINK_SPEED_10GB
#define BNXT_LINK_SPEED_20GB PORT_PHY_QCFG_RESP_LINK_SPEED_20GB
#define BNXT_LINK_SPEED_25GB PORT_PHY_QCFG_RESP_LINK_SPEED_25GB
#define BNXT_LINK_SPEED_40GB PORT_PHY_QCFG_RESP_LINK_SPEED_40GB
#define BNXT_LINK_SPEED_50GB PORT_PHY_QCFG_RESP_LINK_SPEED_50GB
u16 support_speeds;
u16 auto_link_speeds; /* fw adv setting */
#define BNXT_LINK_SPEED_MSK_100MB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_100MB
#define BNXT_LINK_SPEED_MSK_1GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_1GB
#define BNXT_LINK_SPEED_MSK_2GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_2GB
#define BNXT_LINK_SPEED_MSK_10GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_10GB
#define BNXT_LINK_SPEED_MSK_2_5GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_2_5GB
#define BNXT_LINK_SPEED_MSK_20GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_20GB
#define BNXT_LINK_SPEED_MSK_25GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_25GB
#define BNXT_LINK_SPEED_MSK_40GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_40GB
#define BNXT_LINK_SPEED_MSK_50GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_50GB
u16 support_auto_speeds;
u16 lp_auto_link_speeds;
u16 force_link_speed;
u32 preemphasis;
u8 module_status;
u16 fec_cfg;
#define BNXT_FEC_AUTONEG PORT_PHY_QCFG_RESP_FEC_CFG_FEC_AUTONEG_ENABLED
#define BNXT_FEC_ENC_BASE_R PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE74_ENABLED
#define BNXT_FEC_ENC_RS PORT_PHY_QCFG_RESP_FEC_CFG_FEC_CLAUSE91_ENABLED
/* copy of requested setting from ethtool cmd */
u8 autoneg;
#define BNXT_AUTONEG_SPEED 1
#define BNXT_AUTONEG_FLOW_CTRL 2
u8 req_duplex;
u8 req_flow_ctrl;
u16 req_link_speed;
u16 advertising; /* user adv setting */
bool force_link_chng;
/* a copy of phy_qcfg output used to report link
* info to VF
*/
struct hwrm_port_phy_qcfg_output phy_qcfg_resp;
};
#define BNXT_MAX_QUEUE 8
struct bnxt_queue_info {
u8 queue_id;
u8 queue_profile;
};
#define BNXT_MAX_LED 4
struct bnxt_led_info {
u8 led_id;
u8 led_type;
u8 led_group_id;
u8 unused;
__le16 led_state_caps;
#define BNXT_LED_ALT_BLINK_CAP(x) ((x) & \
cpu_to_le16(PORT_LED_QCAPS_RESP_LED0_STATE_CAPS_BLINK_ALT_SUPPORTED))
__le16 led_color_caps;
};
#define BNXT_MAX_TEST 8
struct bnxt_test_info {
u8 offline_mask;
u16 timeout;
char string[BNXT_MAX_TEST][ETH_GSTRING_LEN];
};
#define BNXT_GRCPF_REG_WINDOW_BASE_OUT 0x400
#define BNXT_GRCPF_REG_SYNC_TIME 0x480
#define BNXT_GRCPF_REG_SYNC_TIME_ADJ 0x488
#define BNXT_GRCPF_REG_SYNC_TIME_ADJ_PER_MSK 0xffffffUL
#define BNXT_GRCPF_REG_SYNC_TIME_ADJ_PER_SFT 0
#define BNXT_GRCPF_REG_SYNC_TIME_ADJ_VAL_MSK 0x1f000000UL
#define BNXT_GRCPF_REG_SYNC_TIME_ADJ_VAL_SFT 24
#define BNXT_GRCPF_REG_SYNC_TIME_ADJ_SIGN_MSK 0x20000000UL
#define BNXT_GRCPF_REG_SYNC_TIME_ADJ_SIGN_SFT 29
#define BNXT_CAG_REG_LEGACY_INT_STATUS 0x4014
#define BNXT_CAG_REG_BASE 0x300000
struct bnxt {
void __iomem *bar0;
void __iomem *bar1;
void __iomem *bar2;
u32 reg_base;
u16 chip_num;
#define CHIP_NUM_57301 0x16c8
#define CHIP_NUM_57302 0x16c9
#define CHIP_NUM_57304 0x16ca
#define CHIP_NUM_58700 0x16cd
#define CHIP_NUM_57402 0x16d0
#define CHIP_NUM_57404 0x16d1
#define CHIP_NUM_57406 0x16d2
#define CHIP_NUM_57311 0x16ce
#define CHIP_NUM_57312 0x16cf
#define CHIP_NUM_57314 0x16df
#define CHIP_NUM_57412 0x16d6
#define CHIP_NUM_57414 0x16d7
#define CHIP_NUM_57416 0x16d8
#define CHIP_NUM_57417 0x16d9
#define BNXT_CHIP_NUM_5730X(chip_num) \
((chip_num) >= CHIP_NUM_57301 && \
(chip_num) <= CHIP_NUM_57304)
#define BNXT_CHIP_NUM_5740X(chip_num) \
((chip_num) >= CHIP_NUM_57402 && \
(chip_num) <= CHIP_NUM_57406)
#define BNXT_CHIP_NUM_5731X(chip_num) \
((chip_num) == CHIP_NUM_57311 || \
(chip_num) == CHIP_NUM_57312 || \
(chip_num) == CHIP_NUM_57314)
#define BNXT_CHIP_NUM_5741X(chip_num) \
((chip_num) >= CHIP_NUM_57412 && \
(chip_num) <= CHIP_NUM_57417)
#define BNXT_CHIP_NUM_57X0X(chip_num) \
(BNXT_CHIP_NUM_5730X(chip_num) || BNXT_CHIP_NUM_5740X(chip_num))
#define BNXT_CHIP_NUM_57X1X(chip_num) \
(BNXT_CHIP_NUM_5731X(chip_num) || BNXT_CHIP_NUM_5741X(chip_num))
struct net_device *dev;
struct pci_dev *pdev;
atomic_t intr_sem;
u32 flags;
#define BNXT_FLAG_DCB_ENABLED 0x1
#define BNXT_FLAG_VF 0x2
#define BNXT_FLAG_LRO 0x4
#ifdef CONFIG_INET
#define BNXT_FLAG_GRO 0x8
#else
/* Cannot support hardware GRO if CONFIG_INET is not set */
#define BNXT_FLAG_GRO 0x0
#endif
#define BNXT_FLAG_TPA (BNXT_FLAG_LRO | BNXT_FLAG_GRO)
#define BNXT_FLAG_JUMBO 0x10
#define BNXT_FLAG_STRIP_VLAN 0x20
#define BNXT_FLAG_AGG_RINGS (BNXT_FLAG_JUMBO | BNXT_FLAG_GRO | \
BNXT_FLAG_LRO)
#define BNXT_FLAG_USING_MSIX 0x40
#define BNXT_FLAG_MSIX_CAP 0x80
#define BNXT_FLAG_RFS 0x100
#define BNXT_FLAG_SHARED_RINGS 0x200
#define BNXT_FLAG_PORT_STATS 0x400
#define BNXT_FLAG_UDP_RSS_CAP 0x800
#define BNXT_FLAG_EEE_CAP 0x1000
#define BNXT_FLAG_NEW_RSS_CAP 0x2000
#define BNXT_FLAG_WOL_CAP 0x4000
#define BNXT_FLAG_ROCEV1_CAP 0x8000
#define BNXT_FLAG_ROCEV2_CAP 0x10000
#define BNXT_FLAG_ROCE_CAP (BNXT_FLAG_ROCEV1_CAP | \
BNXT_FLAG_ROCEV2_CAP)
#define BNXT_FLAG_NO_AGG_RINGS 0x20000
#define BNXT_FLAG_RX_PAGE_MODE 0x40000
#define BNXT_FLAG_FW_LLDP_AGENT 0x80000
#define BNXT_FLAG_CHIP_NITRO_A0 0x1000000
#define BNXT_FLAG_ALL_CONFIG_FEATS (BNXT_FLAG_TPA | \
BNXT_FLAG_RFS | \
BNXT_FLAG_STRIP_VLAN)
#define BNXT_PF(bp) (!((bp)->flags & BNXT_FLAG_VF))
#define BNXT_VF(bp) ((bp)->flags & BNXT_FLAG_VF)
#define BNXT_NPAR(bp) ((bp)->port_partition_type)
#define BNXT_SINGLE_PF(bp) (BNXT_PF(bp) && !BNXT_NPAR(bp))
#define BNXT_CHIP_TYPE_NITRO_A0(bp) ((bp)->flags & BNXT_FLAG_CHIP_NITRO_A0)
#define BNXT_RX_PAGE_MODE(bp) ((bp)->flags & BNXT_FLAG_RX_PAGE_MODE)
struct bnxt_en_dev *edev;
struct bnxt_en_dev * (*ulp_probe)(struct net_device *);
struct bnxt_napi **bnapi;
#ifdef OLD_VLAN
struct vlan_group *vlgrp;
#endif
struct bnxt_rx_ring_info *rx_ring;
struct bnxt_tx_ring_info *tx_ring;
u16 *tx_ring_map;
struct sk_buff * (*gro_func)(struct bnxt_tpa_info *, int, int,
struct sk_buff *);
struct sk_buff * (*rx_skb_func)(struct bnxt *,
struct bnxt_rx_ring_info *,
u16, void *, u8 *, dma_addr_t,
unsigned int);
u32 rx_buf_size;
u32 rx_buf_use_size; /* useable size */
u16 rx_offset;
u16 rx_dma_offset;
enum dma_data_direction rx_dir;
u32 rx_ring_size;
u32 rx_agg_ring_size;
u32 rx_copy_thresh;
u32 rx_ring_mask;
u32 rx_agg_ring_mask;
int rx_nr_pages;
int rx_agg_nr_pages;
int rx_nr_rings;
int rsscos_nr_ctxs;
u32 tx_ring_size;
u32 tx_ring_mask;
int tx_nr_pages;
int tx_nr_rings;
int tx_nr_rings_per_tc;
int tx_nr_rings_xdp;
int tx_wake_thresh;
int tx_push_thresh;
int tx_push_size;
u32 cp_ring_size;
u32 cp_ring_mask;
u32 cp_bit;
int cp_nr_pages;
int cp_nr_rings;
int num_stat_ctxs;
/* grp_info indexed by completion ring index */
struct bnxt_ring_grp_info *grp_info;
struct bnxt_vnic_info *vnic_info;
int nr_vnics;
u32 rss_hash_cfg;
u8 max_tc;
u8 max_lltc; /* lossless TCs */
struct bnxt_queue_info q_info[BNXT_MAX_QUEUE];
unsigned int current_interval;
#define BNXT_TIMER_INTERVAL HZ
struct timer_list timer;
unsigned long state;
#define BNXT_STATE_OPEN 0
#define BNXT_STATE_IN_SP_TASK 1
#define BNXT_STATE_READ_STATS 2
struct bnxt_irq *irq_tbl;
int total_irqs;
u8 mac_addr[ETH_ALEN];
#ifdef CONFIG_BNXT_DCB
struct ieee_pfc *ieee_pfc;
struct ieee_ets *ieee_ets;
u8 dcbx_cap;
u8 default_pri;
#endif /* CONFIG_BNXT_DCB */
u32 msg_enable;
u32 hwrm_spec_code;
u16 hwrm_cmd_seq;
u32 hwrm_intr_seq_id;
void *hwrm_cmd_resp_addr;
dma_addr_t hwrm_cmd_resp_dma_addr;
void *hwrm_dbg_resp_addr;
dma_addr_t hwrm_dbg_resp_dma_addr;
#define HWRM_DBG_REG_BUF_SIZE 128
struct rx_port_stats *hw_rx_port_stats;
struct tx_port_stats *hw_tx_port_stats;
dma_addr_t hw_rx_port_stats_map;
dma_addr_t hw_tx_port_stats_map;
int hw_port_stats_size;
u16 hwrm_max_req_len;
int hwrm_cmd_timeout;
struct mutex hwrm_cmd_lock; /* serialize hwrm messages */
struct hwrm_ver_get_output ver_resp;
#define FW_VER_STR_LEN 32
#define BC_HWRM_STR_LEN 21
#define PHY_VER_STR_LEN (FW_VER_STR_LEN - BC_HWRM_STR_LEN)
char fw_ver_str[FW_VER_STR_LEN];
__be16 vxlan_port;
u8 vxlan_port_cnt;
__le16 vxlan_fw_dst_port_id;
__be16 nge_port;
u8 nge_port_cnt;
__le16 nge_fw_dst_port_id;
u8 port_partition_type;
u16 br_mode;
u16 rx_coal_ticks;
u16 rx_coal_ticks_irq;
u16 rx_coal_bufs;
u16 rx_coal_bufs_irq;
u16 tx_coal_ticks;
u16 tx_coal_ticks_irq;
u16 tx_coal_bufs;
u16 tx_coal_bufs_irq;
#define BNXT_USEC_TO_COAL_TIMER(x) ((x) * 25 / 2)
u32 stats_coal_ticks;
#define BNXT_DEF_STATS_COAL_TICKS 1000000
#define BNXT_MIN_STATS_COAL_TICKS 250000
#define BNXT_MAX_STATS_COAL_TICKS 1000000
struct work_struct sp_task;
unsigned long sp_event;
#define BNXT_RX_MASK_SP_EVENT 0
#define BNXT_RX_NTP_FLTR_SP_EVENT 1
#define BNXT_LINK_CHNG_SP_EVENT 2
#define BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT 3
#define BNXT_VXLAN_ADD_PORT_SP_EVENT 4
#define BNXT_VXLAN_DEL_PORT_SP_EVENT 5
#define BNXT_RESET_TASK_SP_EVENT 6
#define BNXT_RST_RING_SP_EVENT 7
#define BNXT_HWRM_PF_UNLOAD_SP_EVENT 8
#define BNXT_PERIODIC_STATS_SP_EVENT 9
#define BNXT_HWRM_PORT_MODULE_SP_EVENT 10
#define BNXT_RESET_TASK_SILENT_SP_EVENT 11
#define BNXT_GENEVE_ADD_PORT_SP_EVENT 12
#define BNXT_GENEVE_DEL_PORT_SP_EVENT 13
#define BNXT_LINK_SPEED_CHNG_SP_EVENT 14
struct bnxt_pf_info pf;
#ifdef CONFIG_BNXT_SRIOV
int nr_vfs;
struct bnxt_vf_info vf;
wait_queue_head_t sriov_cfg_wait;
bool sriov_cfg;
#define BNXT_SRIOV_CFG_WAIT_TMO msecs_to_jiffies(10000)
#endif
#define BNXT_NTP_FLTR_MAX_FLTR 4096
#define BNXT_NTP_FLTR_HASH_SIZE 512
#define BNXT_NTP_FLTR_HASH_MASK (BNXT_NTP_FLTR_HASH_SIZE - 1)
struct hlist_head ntp_fltr_hash_tbl[BNXT_NTP_FLTR_HASH_SIZE];
spinlock_t ntp_fltr_lock; /* for hash table add, del */
unsigned long *ntp_fltr_bmap;
int ntp_fltr_count;
struct bnxt_link_info link_info;
struct ethtool_eee eee;
u32 lpi_tmr_lo;
u32 lpi_tmr_hi;
u8 num_tests;
struct bnxt_test_info *test_info;
u8 wol_filter_id;
u8 wol;
u8 num_leds;
struct bnxt_led_info leds[BNXT_MAX_LED];
#ifdef HAVE_NDO_XDP
struct bpf_prog *xdp_prog;
#endif
struct bnxt_ptp_cfg *ptp_cfg;
#ifndef PCIE_SRIOV_CONFIGURE
int req_vfs;
struct work_struct iov_task;
#endif
};
#define BNXT_RX_STATS_OFFSET(counter) \
(offsetof(struct rx_port_stats, counter) / 8)
#define BNXT_TX_STATS_OFFSET(counter) \
((offsetof(struct tx_port_stats, counter) + \
sizeof(struct rx_port_stats) + 512) / 8)
#ifdef BNXT_PRIV_RX_BUSY_POLL
static inline void bnxt_enable_poll(struct bnxt_napi *bnapi)
{
atomic_set(&bnapi->poll_state, BNXT_STATE_IDLE);
}
/* called from the NAPI poll routine to get ownership of a bnapi */
static inline bool bnxt_lock_napi(struct bnxt_napi *bnapi)
{
int rc = atomic_cmpxchg(&bnapi->poll_state, BNXT_STATE_IDLE,
BNXT_STATE_NAPI);
return rc == BNXT_STATE_IDLE;
}
static inline void bnxt_unlock_napi(struct bnxt_napi *bnapi)
{
atomic_set(&bnapi->poll_state, BNXT_STATE_IDLE);
}
/* called from the busy poll routine to get ownership of a bnapi */
static inline bool bnxt_lock_poll(struct bnxt_napi *bnapi)
{
int rc = atomic_cmpxchg(&bnapi->poll_state, BNXT_STATE_IDLE,
BNXT_STATE_POLL);
return rc == BNXT_STATE_IDLE;
}
static inline void bnxt_unlock_poll(struct bnxt_napi *bnapi)
{
atomic_set(&bnapi->poll_state, BNXT_STATE_IDLE);
}
static inline bool bnxt_busy_polling(struct bnxt_napi *bnapi)
{
return atomic_read(&bnapi->poll_state) == BNXT_STATE_POLL;
}
static inline void bnxt_disable_poll(struct bnxt_napi *bnapi)
{
int old;
while (1) {
old = atomic_cmpxchg(&bnapi->poll_state, BNXT_STATE_IDLE,
BNXT_STATE_DISABLE);
if (old == BNXT_STATE_IDLE)
break;
usleep_range(500, 5000);
}
}
#else
static inline void bnxt_enable_poll(struct bnxt_napi *bnapi)
{
}
static inline bool bnxt_lock_napi(struct bnxt_napi *bnapi)
{
return true;
}
static inline void bnxt_unlock_napi(struct bnxt_napi *bnapi)
{
}
static inline bool bnxt_lock_poll(struct bnxt_napi *bnapi)
{
return false;
}
static inline void bnxt_unlock_poll(struct bnxt_napi *bnapi)
{
}
static inline bool bnxt_busy_polling(struct bnxt_napi *bnapi)
{
return false;
}
static inline void bnxt_disable_poll(struct bnxt_napi *bnapi)
{
}
#endif
#define I2C_DEV_ADDR_A0 0xa0
#define I2C_DEV_ADDR_A2 0xa2
#define SFP_EEPROM_SFF_8472_COMP_ADDR 0x5e
#define SFP_EEPROM_SFF_8472_COMP_SIZE 1
#define SFF_MODULE_ID_SFP 0x3
#define SFF_MODULE_ID_QSFP 0xc
#define SFF_MODULE_ID_QSFP_PLUS 0xd
#define SFF_MODULE_ID_QSFP28 0x11
#define BNXT_MAX_PHY_I2C_RESP_SIZE 64
#define BDETBD_REG_BD_PRODUCER_IDX 0x90000UL
#define BDETBD_REG_BD_REQ_CONSUMER_IDX 0x91000UL
#define BDETBD_REG_BD_CMPL_CONSUMER_IDX 0x92000UL
#define BDERBD_REG_BD_PRODUCER_IDX 0x410000UL
#define BDERBD_REG_BD_REQ_CONSUMER_IDX 0x411000UL
#define BDERBD_REG_BD_CMPL_CONSUMER_IDX 0x412000UL
#define CAG_REG_CAG_PRODUCER_INDEX_REG 0x302000UL
#define CAG_REG_CAG_CONSUMER_INDEX_REG 0x303000UL
#define CAG_REG_CAG_VECTOR_CTRL 0x301000UL
#define TDC_REG_INT_STS_0 0x180020UL
#define TDC_REG_TDC_DEBUG_CNTL 0x180014UL
#define TDC_REG_TDC_DEBUG_STATUS 0x180018UL
#define TDI_REG_DBG_DWORD_ENABLE 0x100104UL
#define TDI_REG_DBG_OUT_DATA 0x100120UL
#define TDI_REG_DBG_SELECT 0x100100UL
#define TE_DEC_REG_PORT_CURRENT_CREDIT_REG 0x2401300UL
#define RDI_REG_RDI_DEBUG_CONTROL_REG 0x27001cUL
#define RDI_REG_RDI_DEBUG_STATUS_REG 0x270020UL
static inline u32 bnxt_tx_avail(struct bnxt *bp, struct bnxt_tx_ring_info *txr)
{
/* Tell compiler to fetch tx indices from memory. */
barrier();
return bp->tx_ring_size -
((txr->tx_prod - txr->tx_cons) & bp->tx_ring_mask);
}
extern const u16 bnxt_lhint_arr[];
int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
u16 prod, gfp_t gfp);
void bnxt_reuse_rx_data(struct bnxt_rx_ring_info *rxr, u16 cons, void *data);
void bnxt_set_tpa_flags(struct bnxt *bp);
void bnxt_set_ring_params(struct bnxt *);
int bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode);
void bnxt_hwrm_cmd_hdr_init(struct bnxt *, void *, u16, u16, u16);
int _hwrm_send_message(struct bnxt *, void *, u32, int);
int hwrm_send_message(struct bnxt *, void *, u32, int);
int hwrm_send_message_silent(struct bnxt *, void *, u32, int);
int bnxt_hwrm_func_rgtr_async_events(struct bnxt *bp, unsigned long *bmap,
int bmap_size);
int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id);
int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings);
int bnxt_hwrm_set_coal(struct bnxt *);
int bnxt_hwrm_func_qcaps(struct bnxt *);
unsigned int bnxt_get_max_func_stat_ctxs(struct bnxt *bp);
void bnxt_set_max_func_stat_ctxs(struct bnxt *bp, unsigned int max);
unsigned int bnxt_get_max_func_cp_rings(struct bnxt *bp);
void bnxt_set_max_func_cp_rings(struct bnxt *bp, unsigned int max);
void bnxt_set_max_func_irqs(struct bnxt *bp, unsigned int max);
void bnxt_tx_disable(struct bnxt *);
void bnxt_tx_enable(struct bnxt *);
int bnxt_hwrm_set_pause(struct bnxt *);
int bnxt_hwrm_set_link_setting(struct bnxt *, bool, bool);
int bnxt_hwrm_alloc_wol_fltr(struct bnxt *);
int bnxt_hwrm_free_wol_fltr(struct bnxt *);
int bnxt_hwrm_fw_set_time(struct bnxt *);
int bnxt_open_nic(struct bnxt *, bool, bool);
int bnxt_half_open_nic(struct bnxt *bp);
void bnxt_half_close_nic(struct bnxt *bp);
int bnxt_close_nic(struct bnxt *, bool, bool);
int bnxt_reserve_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
int tx_xdp);
#if defined(HAVE_SETUP_TC) || defined(CONFIG_BNXT_DCB)
int bnxt_setup_mq_tc(struct net_device *, u8);
#endif
int bnxt_get_max_rings(struct bnxt *, int *, int *, bool);
void bnxt_restore_pf_fw_resources(struct bnxt *bp);
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2016 Broadcom Corporation
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#include <linux/version.h>
#include <linux/ethtool.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#if !defined(NEW_FLOW_KEYS) && defined(HAVE_FLOW_KEYS)
#include <net/flow_keys.h>
#endif
#include <linux/sched.h>
#ifndef SPEED_20000
#define SPEED_20000 20000
#endif
#ifndef SPEED_25000
#define SPEED_25000 25000
#endif
#ifndef SPEED_40000
#define SPEED_40000 40000
#endif
#ifndef SPEED_50000
#define SPEED_50000 50000
#endif
#ifndef SPEED_UNKNOWN
#define SPEED_UNKNOWN -1
#endif
#ifndef DUPLEX_UNKNOWN
#define DUPLEX_UNKNOWN 0xff
#endif
#ifndef PORT_DA
#define PORT_DA 0x05
#endif
#ifndef PORT_NONE
#define PORT_NONE 0xef
#endif
#if !defined(SUPPORTED_40000baseCR4_Full)
#define SUPPORTED_40000baseCR4_Full (1 << 24)
#define ADVERTISED_40000baseCR4_Full (1 << 24)
#endif
#if !defined(IPV4_FLOW)
#define IPV4_FLOW 0x10
#endif
#if !defined(IPV6_FLOW)
#define IPV6_FLOW 0x11
#endif
#if defined(HAVE_ETH_GET_HEADLEN) || (LINUX_VERSION_CODE > 0x040900)
#define BNXT_RX_PAGE_MODE_SUPPORT 1
#endif
#if !defined(ETH_P_8021AD)
#define ETH_P_8021AD 0x88A8
#endif
#if !defined(ETH_P_ROCE)
#define ETH_P_ROCE 0x8915
#endif
#if !defined(ROCE_V2_UDP_PORT)
#define ROCE_V2_UDP_DPORT 4791
#endif
#ifndef NETIF_F_GSO_UDP_TUNNEL
#define NETIF_F_GSO_UDP_TUNNEL 0
#endif
#ifndef NETIF_F_GSO_UDP_TUNNEL_CSUM
#define NETIF_F_GSO_UDP_TUNNEL_CSUM 0
#endif
#ifndef NETIF_F_GSO_GRE
#define NETIF_F_GSO_GRE 0
#endif
#ifndef NETIF_F_GSO_GRE_CSUM
#define NETIF_F_GSO_GRE_CSUM 0
#endif
#ifndef NETIF_F_GSO_IPIP
#define NETIF_F_GSO_IPIP 0
#endif
#ifndef NETIF_F_GSO_SIT
#define NETIF_F_GSO_SIT 0
#endif
#ifndef NETIF_F_GSO_IPXIP4
#define NETIF_F_GSO_IPXIP4 (NETIF_F_GSO_IPIP | NETIF_F_GSO_SIT)
#endif
#ifndef NETIF_F_GSO_PARTIAL
#define NETIF_F_GSO_PARTIAL 0
#else
#define HAVE_GSO_PARTIAL_FEATURES 1
#endif
/* Tie rx checksum offload to tx checksum offload for older kernels. */
#ifndef NETIF_F_RXCSUM
#define NETIF_F_RXCSUM NETIF_F_IP_CSUM
#endif
#ifndef NETIF_F_NTUPLE
#define NETIF_F_NTUPLE 0
#endif
#ifndef NETIF_F_RXHASH
#define NETIF_F_RXHASH 0
#else
#define HAVE_NETIF_F_RXHASH
#endif
#ifndef HAVE_SKB_GSO_UDP_TUNNEL_CSUM
#ifndef HAVE_SKB_GSO_UDP_TUNNEL
#define SKB_GSO_UDP_TUNNEL 0
#endif
#define SKB_GSO_UDP_TUNNEL_CSUM SKB_GSO_UDP_TUNNEL
#endif
#ifndef BRIDGE_MODE_VEB
#define BRIDGE_MODE_VEB 0
#endif
#ifndef BRIDGE_MODE_VEPA
#define BRIDGE_MODE_VEPA 1
#endif
#ifndef BRIDGE_MODE_UNDEF
#define BRIDGE_MODE_UNDEF 0xffff
#endif
#ifndef DEFINE_DMA_UNMAP_ADDR
#define DEFINE_DMA_UNMAP_ADDR(mapping) DECLARE_PCI_UNMAP_ADDR(mapping)
#endif
#ifndef dma_unmap_addr_set
#define dma_unmap_addr_set pci_unmap_addr_set
#endif
#ifndef dma_unmap_addr
#define dma_unmap_addr pci_unmap_addr
#endif
#ifndef RHEL_RELEASE_VERSION
#define RHEL_RELEASE_VERSION(a, b) 0
#endif
#if defined(RHEL_RELEASE_CODE) && (RHEL_RELEASE_CODE == RHEL_RELEASE_VERSION(6,3))
#if defined(CONFIG_X86_64) && !defined(CONFIG_NEED_DMA_MAP_STATE)
#undef DEFINE_DMA_UNMAP_ADDR
#define DEFINE_DMA_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME
#undef DEFINE_DMA_UNMAP_LEN
#define DEFINE_DMA_UNMAP_LEN(LEN_NAME) __u32 LEN_NAME
#undef dma_unmap_addr
#define dma_unmap_addr(PTR, ADDR_NAME) ((PTR)->ADDR_NAME)
#undef dma_unmap_addr_set
#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL) (((PTR)->ADDR_NAME) = (VAL))
#undef dma_unmap_len
#define dma_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME)
#undef dma_unmap_len_set
#define dma_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL))
#endif
#endif
#ifdef HAVE_NDO_SET_VF_VLAN_RH73
#define ndo_set_vf_vlan ndo_set_vf_vlan_rh73
#endif
#ifndef ETHTOOL_GEEE
struct ethtool_eee {
__u32 cmd;
__u32 supported;
__u32 advertised;
__u32 lp_advertised;
__u32 eee_active;
__u32 eee_enabled;
__u32 tx_lpi_enabled;
__u32 tx_lpi_timer;
__u32 reserved[2];
};
#endif
#ifndef HAVE_SKB_FRAG_PAGE
static inline struct page *skb_frag_page(const skb_frag_t *frag)
{
return frag->page;
}
static inline void *skb_frag_address_safe(const skb_frag_t *frag)
{
void *ptr = page_address(skb_frag_page(frag));
if (unlikely(!ptr))
return NULL;
return ptr + frag->page_offset;
}
static inline void __skb_frag_set_page(skb_frag_t *frag, struct page *page)
{
frag->page = page;
}
#define skb_frag_dma_map(x, frag, y, len, z) \
pci_map_page(bp->pdev, (frag)->page, \
(frag)->page_offset, (len), PCI_DMA_TODEVICE)
#endif
#ifndef HAVE_PCI_VFS_ASSIGNED
static inline int pci_vfs_assigned(struct pci_dev *dev)
{
return 0;
}
#endif
#ifndef HAVE_PCI_NUM_VF
#include <../drivers/pci/pci.h>
static inline int pci_num_vf(struct pci_dev *dev)
{
if (!dev->is_physfn)
return 0;
return dev->sriov->nr_virtfn;
}
#endif
#ifndef SKB_ALLOC_NAPI
static inline struct sk_buff *napi_alloc_skb(struct napi_struct *napi,
unsigned int length)
{
struct sk_buff *skb;
length += NET_SKB_PAD + NET_IP_ALIGN;
skb = netdev_alloc_skb(napi->dev, length);
if (likely(skb))
skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
return skb;
}
#endif
#ifndef HAVE_SKB_HASH_TYPE
enum pkt_hash_types {
PKT_HASH_TYPE_NONE, /* Undefined type */
PKT_HASH_TYPE_L2, /* Input: src_MAC, dest_MAC */
PKT_HASH_TYPE_L3, /* Input: src_IP, dst_IP */
PKT_HASH_TYPE_L4, /* Input: src_IP, dst_IP, src_port, dst_port */
};
static inline void
skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type)
{
#ifdef HAVE_NETIF_F_RXHASH
skb->rxhash = hash;
#endif
}
#endif
#define GET_NET_STATS(x) (unsigned long)le64_to_cpu(x)
#if !defined(NETDEV_RX_FLOW_STEER) || !defined(HAVE_FLOW_KEYS) || (LINUX_VERSION_CODE < 0x030300) || defined(NO_NETDEV_CPU_RMAP)
#undef CONFIG_RFS_ACCEL
#endif
#if !defined(IEEE_8021QAZ_APP_SEL_DGRAM) || !defined(CONFIG_DCB)
#undef CONFIG_BNXT_DCB
#endif
#ifdef NETDEV_UDP_TUNNEL_PUSH_INFO
#define HAVE_NDO_UDP_TUNNEL 1
#endif
#ifdef HAVE_NDO_XDP
#define CONFIG_BNXT_XDP 1
#endif
#ifndef NETDEV_HW_FEATURES
#define hw_features features
#endif
#ifndef HAVE_NETDEV_FEATURES_T
#ifdef HAVE_NDO_FIX_FEATURES
typedef u32 netdev_features_t;
#else
typedef unsigned long netdev_features_t;
#endif
#endif
#if !defined(IFF_UNICAST_FLT)
#define IFF_UNICAST_FLT 0
#endif
#ifndef HAVE_NEW_BUILD_SKB
#define build_skb(data, frag) build_skb(data)
#endif
#ifndef __rcu
#define __rcu
#endif
#ifndef rcu_dereference_protected
#define rcu_dereference_protected(p, c) \
rcu_dereference((p))
#endif
#ifndef rcu_access_pointer
#define rcu_access_pointer rcu_dereference
#endif
#ifndef rtnl_dereference
#define rtnl_dereference(p) \
rcu_dereference_protected(p, lockdep_rtnl_is_held())
#endif
#ifndef RCU_INIT_POINTER
#define RCU_INIT_POINTER(p, v) \
p = (typeof(*v) __force __rcu *)(v)
#endif
#ifdef HAVE_OLD_HLIST
#define __hlist_for_each_entry_rcu(f, n, h, m) \
hlist_for_each_entry_rcu(f, n, h, m)
#define __hlist_for_each_entry_safe(f, n, t, h, m) \
hlist_for_each_entry_safe(f, n, t, h, m)
#else
#define __hlist_for_each_entry_rcu(f, n, h, m) \
hlist_for_each_entry_rcu(f, h, m)
#define __hlist_for_each_entry_safe(f, n, t, h, m) \
hlist_for_each_entry_safe(f, t, h, m)
#endif
#ifndef skb_vlan_tag_present
#define skb_vlan_tag_present(skb) vlan_tx_tag_present(skb)
#define skb_vlan_tag_get(skb) vlan_tx_tag_get(skb)
#endif
#ifndef VLAN_PRIO_SHIFT
#define VLAN_PRIO_SHIFT 13
#endif
#ifndef NETIF_F_HW_VLAN_CTAG_TX
#define NETIF_F_HW_VLAN_CTAG_TX NETIF_F_HW_VLAN_TX
#define NETIF_F_HW_VLAN_CTAG_RX NETIF_F_HW_VLAN_RX
/* 802.1AD not supported on older kernels */
#define NETIF_F_HW_VLAN_STAG_TX 0
#define NETIF_F_HW_VLAN_STAG_RX 0
#define __vlan_hwaccel_put_tag(skb, proto, tag) \
if (proto == ntohs(ETH_P_8021Q)) \
__vlan_hwaccel_put_tag(skb, tag)
#define vlan_proto protocol
#if defined(HAVE_VLAN_RX_REGISTER)
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#define OLD_VLAN 1
#define OLD_VLAN_VALID (1 << 31)
#endif
#endif
#endif
#ifndef HAVE_NETDEV_UPDATE_FEATURES
static inline void netdev_update_features(struct net_device *dev)
{
/* Do nothing, since we can't set default VLAN on these old kernels. */
}
#endif
#if !defined(netdev_printk) && (LINUX_VERSION_CODE < 0x020624)
#ifndef HAVE_NETDEV_NAME
static inline const char *netdev_name(const struct net_device *dev)
{
if (dev->reg_state != NETREG_REGISTERED)
return "(unregistered net_device)";
return dev->name;
}
#endif
#define NET_PARENT_DEV(netdev) ((netdev)->dev.parent)
#define netdev_printk(level, netdev, format, args...) \
dev_printk(level, NET_PARENT_DEV(netdev), \
"%s: " format, \
netdev_name(netdev), ##args)
#endif
#ifndef netdev_err
#define netdev_err(dev, format, args...) \
netdev_printk(KERN_ERR, dev, format, ##args)
#endif
#ifndef netdev_info
#define netdev_info(dev, format, args...) \
netdev_printk(KERN_INFO, dev, format, ##args)
#endif
#ifndef netdev_warn
#define netdev_warn(dev, format, args...) \
netdev_printk(KERN_WARNING, dev, format, ##args)
#endif
#ifndef netdev_uc_count
#define netdev_uc_count(dev) ((dev)->uc.count)
#endif
#ifndef netdev_for_each_uc_addr
#define netdev_for_each_uc_addr(ha, dev) \
list_for_each_entry(ha, &dev->uc.list, list)
#endif
#ifndef netdev_for_each_mc_addr
#define netdev_for_each_mc_addr(mclist, dev) \
for (mclist = dev->mc_list; mclist; mclist = mclist->next)
#endif
#ifndef smp_mb__before_atomic
#define smp_mb__before_atomic() smp_mb()
#endif
#ifndef smp_mb__after_atomic
#define smp_mb__after_atomic() smp_mb()
#endif
#ifndef dma_rmb
#define dma_rmb() rmb()
#endif
#ifdef CONFIG_NET_RX_BUSY_POLL
#include <net/busy_poll.h>
#if defined(HAVE_NAPI_HASH_ADD) && defined(NETDEV_BUSY_POLL)
#define BNXT_PRIV_RX_BUSY_POLL 1
#endif
#endif
#if !defined(CONFIG_PTP_1588_CLOCK) && !defined(CONFIG_PTP_1588_CLOCK_MODULE)
#undef HAVE_IEEE1588_SUPPORT
#endif
#if !defined(HAVE_NAPI_HASH_DEL)
static inline void napi_hash_del(struct napi_struct *napi)
{
}
#endif
#if !defined(LL_FLUSH_FAILED) || !defined(HAVE_NAPI_HASH_ADD)
static inline void napi_hash_add(struct napi_struct *napi)
{
}
#endif
#ifndef HAVE_SET_COHERENT_MASK
static inline int dma_set_coherent_mask(struct device *dev, u64 mask)
{
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
return pci_set_consistent_dma_mask(pdev, mask);
}
#endif
#ifndef HAVE_SET_MASK_AND_COHERENT
static inline int dma_set_mask_and_coherent(struct device *dev, u64 mask)
{
int rc = dma_set_mask(dev, mask);
if (rc == 0)
dma_set_coherent_mask(dev, mask);
return rc;
}
#endif
#ifndef HAVE_IFLA_TX_RATE
#define ndo_set_vf_rate ndo_set_vf_tx_rate
#endif
#ifndef HAVE_PRANDOM_BYTES
#define prandom_bytes get_random_bytes
#endif
#ifndef rounddown
#define rounddown(x, y) ( \
{ \
typeof(x) __x = (x); \
__x - (__x % (y)); \
} \
)
#endif
#ifdef NO_SKB_FRAG_SIZE
static inline unsigned int skb_frag_size(const skb_frag_t *frag)
{
return frag->size;
}
#endif
#ifndef HAVE_SKB_CHECKSUM_NONE_ASSERT
static inline void skb_checksum_none_assert(struct sk_buff *skb)
{
skb->ip_summed = CHECKSUM_NONE;
}
#endif
#ifndef HAVE_NEW_FLOW_DISSECTOR_WITH_FLAGS
#define skb_flow_dissect_flow_keys(skb, fkeys, flags) \
skb_flow_dissect_flow_keys(skb, fkeys)
#endif
#ifndef HAVE_ETHER_ADDR_EQUAL
static inline bool ether_addr_equal(const u8 *addr1, const u8 *addr2)
{
return !compare_ether_addr(addr1, addr2);
}
#endif
#ifndef HAVE_ETHER_ADDR_COPY
static inline void ether_addr_copy(u8 *dst, const u8 *src)
{
memcpy(dst, src, ETH_ALEN);
}
#endif
#ifndef HAVE_ETH_BROADCAST_ADDR
static inline void eth_broadcast_addr(u8 *addr)
{
memset(addr, 0xff, ETH_ALEN);
}
#endif
#ifndef HAVE_ETH_HW_ADDR_RANDOM
static inline void eth_hw_addr_random(struct net_device *dev)
{
#if defined(NET_ADDR_RANDOM)
dev->addr_assign_type = NET_ADDR_RANDOM;
#endif
random_ether_addr(dev->dev_addr);
}
#endif
#ifndef HAVE_NETDEV_TX_QUEUE_CTRL
static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue,
unsigned int bytes)
{
}
static inline void netdev_tx_completed_queue(struct netdev_queue *dev_queue,
unsigned int pkts, unsigned int bytes)
{
}
static inline void netdev_tx_reset_queue(struct netdev_queue *q)
{
}
#endif
#ifndef HAVE_NETIF_SET_REAL_NUM_RX
static inline int netif_set_real_num_rx_queues(struct net_device *dev,
unsigned int rxq)
{
return 0;
}
#endif
#ifndef HAVE_NETIF_SET_REAL_NUM_TX
static inline void netif_set_real_num_tx_queues(struct net_device *dev,
unsigned int txq)
{
dev->real_num_tx_queues = txq;
}
#endif
#ifndef HAVE_NETIF_GET_DEFAULT_RSS
static inline int netif_get_num_default_rss_queues(void)
{
return min_t(int, 8, num_online_cpus());
}
#endif
#if !defined(HAVE_TCP_V6_CHECK)
static __inline__ __sum16 tcp_v6_check(int len,
const struct in6_addr *saddr,
const struct in6_addr *daddr,
__wsum base)
{
return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
}
#endif
#ifndef HAVE_USLEEP_RANGE
static inline void usleep_range(unsigned long min, unsigned long max)
{
if (min < 1000)
udelay(min);
else
msleep(min / 1000);
}
#endif
#ifndef HAVE_GET_NUM_TC
static inline int netdev_get_num_tc(struct net_device *dev)
{
return 0;
}
static inline void netdev_reset_tc(struct net_device *dev)
{
}
static inline int netdev_set_tc_queue(struct net_device *devi, u8 tc,
u16 count, u16 offset)
{
return 0;
}
#endif
#ifndef HAVE_VZALLOC
static inline void *vzalloc(size_t size)
{
void *ret = vmalloc(size);
if (ret)
memset(ret, 0, size);
return ret;
}
#endif
#ifndef ETH_MODULE_SFF_8436
#define ETH_MODULE_SFF_8436 0x4
#endif
#ifndef ETH_MODULE_SFF_8436_LEN
#define ETH_MODULE_SFF_8436_LEN 256
#endif
#ifndef ETH_MODULE_SFF_8636
#define ETH_MODULE_SFF_8636 0x3
#endif
#ifndef ETH_MODULE_SFF_8636_LEN
#define ETH_MODULE_SFF_8636_LEN 256
#endif
#ifndef HAVE_PCIE_GET_MINIMUM_LINK
enum pcie_link_width {
PCIE_LNK_WIDTH_UNKNOWN = 0xFF,
};
#ifndef HAVE_PCIE_BUS_SPEED
enum pci_bus_speed {
PCIE_SPEED_2_5GT = 0x14,
PCIE_SPEED_5_0GT = 0x15,
PCIE_SPEED_8_0GT = 0x16,
PCI_SPEED_UNKNOWN = 0xFF,
};
#endif
static const unsigned char 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 */
PCI_SPEED_UNKNOWN, /* 5 */
PCI_SPEED_UNKNOWN, /* 6 */
PCI_SPEED_UNKNOWN, /* 7 */
PCI_SPEED_UNKNOWN, /* 8 */
PCI_SPEED_UNKNOWN, /* 9 */
PCI_SPEED_UNKNOWN, /* A */
PCI_SPEED_UNKNOWN, /* B */
PCI_SPEED_UNKNOWN, /* C */
PCI_SPEED_UNKNOWN, /* D */
PCI_SPEED_UNKNOWN, /* E */
PCI_SPEED_UNKNOWN /* F */
};
#ifndef PCI_EXP_LNKSTA_NLW_SHIFT
#define PCI_EXP_LNKSTA_NLW_SHIFT 4
#endif
#ifdef HAVE_PCIE_CAPABILITY_READ_WORD
static inline int pcie_get_minimum_link(struct pci_dev *dev,
enum pci_bus_speed *speed,
enum pcie_link_width *width)
{
int ret;
*speed = PCI_SPEED_UNKNOWN;
*width = PCIE_LNK_WIDTH_UNKNOWN;
while (dev) {
u16 lnksta;
enum pci_bus_speed next_speed;
enum pcie_link_width next_width;
ret = pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
if (ret)
return ret;
next_speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS];
next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >>
PCI_EXP_LNKSTA_NLW_SHIFT;
if (next_speed < *speed)
*speed = next_speed;
if (next_width < *width)
*width = next_width;
dev = dev->bus->self;
}
return 0;
}
#else
static inline int pcie_get_minimum_link(struct pci_dev *dev,
enum pci_bus_speed *speed,
enum pcie_link_width *width)
{
#define BNXT_PCIE_CAP 0xAC
u16 lnksta;
int ret;
ret = pci_read_config_word(dev, BNXT_PCIE_CAP + PCI_EXP_LNKSTA,
&lnksta);
if (ret)
return ret;
*speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS];
*width = (lnksta & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
return 0;
}
#endif
#endif
#ifndef HAVE_PCI_IS_BRIDGE
static inline bool pci_is_bridge(struct pci_dev *dev)
{
return dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS;
}
#endif
#ifndef HAVE_NDO_XDP
struct netdev_xdp;
#endif
#ifndef XDP_PACKET_HEADROOM
#define XDP_PACKET_HEADROOM 0
#endif
#ifndef HAVE_BPF_TRACE
#define trace_xdp_exception(dev, xdp_prog, act)
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2016 Broadcom Corporation
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/rtnetlink.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include "bnxt_compat.h"
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_dcb.h"
#ifdef CONFIG_BNXT_DCB
static int bnxt_hwrm_queue_pri2cos_cfg(struct bnxt *bp, struct ieee_ets *ets)
{
struct hwrm_queue_pri2cos_cfg_input req = {0};
int rc = 0, i;
u8 *pri2cos;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PRI2COS_CFG, -1, -1);
req.flags = cpu_to_le32(QUEUE_PRI2COS_CFG_REQ_FLAGS_PATH_BIDIR |
QUEUE_PRI2COS_CFG_REQ_FLAGS_IVLAN);
pri2cos = &req.pri0_cos_queue_id;
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
req.enables |= cpu_to_le32(
QUEUE_PRI2COS_CFG_REQ_ENABLES_PRI0_COS_QUEUE_ID << i);
pri2cos[i] = bp->q_info[ets->prio_tc[i]].queue_id;
}
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
return rc;
}
static int bnxt_hwrm_queue_pri2cos_qcfg(struct bnxt *bp, struct ieee_ets *ets)
{
struct hwrm_queue_pri2cos_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_queue_pri2cos_qcfg_input req = {0};
int rc = 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PRI2COS_QCFG, -1, -1);
req.flags = cpu_to_le32(QUEUE_PRI2COS_QCFG_REQ_FLAGS_IVLAN);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc) {
u8 *pri2cos = &resp->pri0_cos_queue_id;
int i, j;
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
u8 queue_id = pri2cos[i];
for (j = 0; j < bp->max_tc; j++) {
if (bp->q_info[j].queue_id == queue_id) {
ets->prio_tc[i] = j;
break;
}
}
}
}
return rc;
}
static int bnxt_hwrm_queue_cos2bw_cfg(struct bnxt *bp, struct ieee_ets *ets,
u8 max_tc)
{
struct hwrm_queue_cos2bw_cfg_input req = {0};
struct bnxt_cos2bw_cfg cos2bw;
int rc = 0, i;
void *data;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_COS2BW_CFG, -1, -1);
data = &req.unused_0;
for (i = 0; i < max_tc; i++, data += sizeof(cos2bw) - 4) {
req.enables |= cpu_to_le32(
QUEUE_COS2BW_CFG_REQ_ENABLES_COS_QUEUE_ID0_VALID << i);
memset(&cos2bw, 0, sizeof(cos2bw));
cos2bw.queue_id = bp->q_info[i].queue_id;
if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_STRICT) {
cos2bw.tsa =
QUEUE_COS2BW_QCFG_RESP_QUEUE_ID0_TSA_ASSIGN_SP;
cos2bw.pri_lvl = i;
} else {
cos2bw.tsa =
QUEUE_COS2BW_QCFG_RESP_QUEUE_ID0_TSA_ASSIGN_ETS;
cos2bw.bw_weight = ets->tc_tx_bw[i];
}
memcpy(data, &cos2bw.queue_id, sizeof(cos2bw) - 4);
if (i == 0) {
req.queue_id0 = cos2bw.queue_id;
req.unused_0 = 0;
}
}
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
return rc;
}
static int bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt *bp, struct ieee_ets *ets)
{
struct hwrm_queue_cos2bw_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_queue_cos2bw_qcfg_input req = {0};
struct bnxt_cos2bw_cfg cos2bw;
void *data;
int rc, i;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_COS2BW_QCFG, -1, -1);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc)
return rc;
data = &resp->queue_id0 + offsetof(struct bnxt_cos2bw_cfg, queue_id);
for (i = 0; i < bp->max_tc; i++, data += sizeof(cos2bw) - 4) {
int j;
memcpy(&cos2bw.queue_id, data, sizeof(cos2bw) - 4);
if (i == 0)
cos2bw.queue_id = resp->queue_id0;
for (j = 0; j < bp->max_tc; j++) {
if (bp->q_info[j].queue_id != cos2bw.queue_id)
continue;
if (cos2bw.tsa ==
QUEUE_COS2BW_QCFG_RESP_QUEUE_ID0_TSA_ASSIGN_SP) {
ets->tc_tsa[j] = IEEE_8021QAZ_TSA_STRICT;
} else {
ets->tc_tsa[j] = IEEE_8021QAZ_TSA_ETS;
ets->tc_tx_bw[j] = cos2bw.bw_weight;
}
}
}
return 0;
}
static int bnxt_hwrm_queue_cfg(struct bnxt *bp, unsigned int lltc_mask)
{
struct hwrm_queue_cfg_input req = {0};
int i;
if (netif_running(bp->dev))
bnxt_tx_disable(bp);
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_CFG, -1, -1);
req.flags = cpu_to_le32(QUEUE_CFG_REQ_FLAGS_PATH_BIDIR);
req.enables = cpu_to_le32(QUEUE_CFG_REQ_ENABLES_SERVICE_PROFILE);
/* Configure lossless queues to lossy first */
req.service_profile = QUEUE_CFG_REQ_SERVICE_PROFILE_LOSSY;
for (i = 0; i < bp->max_tc; i++) {
if (BNXT_LLQ(bp->q_info[i].queue_profile)) {
req.queue_id = cpu_to_le32(bp->q_info[i].queue_id);
hwrm_send_message(bp, &req, sizeof(req),
HWRM_CMD_TIMEOUT);
bp->q_info[i].queue_profile =
QUEUE_CFG_REQ_SERVICE_PROFILE_LOSSY;
}
}
/* Now configure desired queues to lossless */
req.service_profile = QUEUE_CFG_REQ_SERVICE_PROFILE_LOSSLESS;
for (i = 0; i < bp->max_tc; i++) {
if (lltc_mask & (1 << i)) {
req.queue_id = cpu_to_le32(bp->q_info[i].queue_id);
hwrm_send_message(bp, &req, sizeof(req),
HWRM_CMD_TIMEOUT);
bp->q_info[i].queue_profile =
QUEUE_CFG_REQ_SERVICE_PROFILE_LOSSLESS;
}
}
if (netif_running(bp->dev))
bnxt_tx_enable(bp);
return 0;
}
static int bnxt_hwrm_queue_pfc_cfg(struct bnxt *bp, struct ieee_pfc *pfc)
{
struct hwrm_queue_pfcenable_cfg_input req = {0};
struct ieee_ets *my_ets = bp->ieee_ets;
unsigned int tc_mask = 0, pri_mask = 0;
u8 i, pri, lltc_count = 0;
bool need_q_recfg = false;
int rc;
if (!my_ets)
return -EINVAL;
for (i = 0; i < bp->max_tc; i++) {
for (pri = 0; pri < IEEE_8021QAZ_MAX_TCS; pri++) {
if ((pfc->pfc_en & (1 << pri)) &&
(my_ets->prio_tc[pri] == i)) {
pri_mask |= 1 << pri;
tc_mask |= 1 << i;
}
}
if (tc_mask & (1 << i))
lltc_count++;
}
if (lltc_count > bp->max_lltc)
return -EINVAL;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PFCENABLE_CFG, -1, -1);
req.flags = cpu_to_le32(pri_mask);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc)
return rc;
for (i = 0; i < bp->max_tc; i++) {
if (tc_mask & (1 << i)) {
if (!BNXT_LLQ(bp->q_info[i].queue_profile))
need_q_recfg = true;
}
}
if (need_q_recfg)
rc = bnxt_hwrm_queue_cfg(bp, tc_mask);
return rc;
}
static int bnxt_hwrm_queue_pfc_qcfg(struct bnxt *bp, struct ieee_pfc *pfc)
{
struct hwrm_queue_pfcenable_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_queue_pfcenable_qcfg_input req = {0};
u8 pri_mask;
int rc;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PFCENABLE_QCFG, -1, -1);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc)
return rc;
pri_mask = le32_to_cpu(resp->flags);
pfc->pfc_en = pri_mask;
return 0;
}
static int bnxt_hwrm_set_dcbx_app(struct bnxt *bp, struct dcb_app *app,
bool add)
{
struct hwrm_fw_set_structured_data_input set = {0};
struct hwrm_fw_get_structured_data_input get = {0};
struct hwrm_struct_data_dcbx_app *fw_app;
struct hwrm_struct_hdr *data;
dma_addr_t mapping;
size_t data_len;
int rc, n, i;
if (bp->hwrm_spec_code < 0x10601)
return 0;
n = 8;
data_len = sizeof(*data) + sizeof(*fw_app) * n;
data = dma_alloc_coherent(&bp->pdev->dev, data_len, &mapping,
GFP_KERNEL);
if (!data)
return -ENOMEM;
memset(data, 0, data_len);
bnxt_hwrm_cmd_hdr_init(bp, &get, HWRM_FW_GET_STRUCTURED_DATA, -1, -1);
get.dest_data_addr = cpu_to_le64(mapping);
get.structure_id = cpu_to_le16(STRUCT_HDR_STRUCT_ID_DCBX_APP);
get.subtype = cpu_to_le16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL);
get.count = 0;
rc = hwrm_send_message(bp, &get, sizeof(get), HWRM_CMD_TIMEOUT);
if (rc)
goto set_app_exit;
fw_app = (struct hwrm_struct_data_dcbx_app *)(data + 1);
if (data->struct_id != cpu_to_le16(STRUCT_HDR_STRUCT_ID_DCBX_APP)) {
rc = -ENODEV;
goto set_app_exit;
}
n = data->count;
for (i = 0; i < n; i++, fw_app++) {
if (fw_app->protocol_id == cpu_to_be16(app->protocol) &&
fw_app->protocol_selector == app->selector &&
fw_app->priority == app->priority) {
if (add)
goto set_app_exit;
else
break;
}
}
if (add) {
/* append */
n++;
fw_app->protocol_id = cpu_to_be16(app->protocol);
fw_app->protocol_selector = app->selector;
fw_app->priority = app->priority;
fw_app->valid = 1;
} else {
size_t len = 0;
/* not found, nothing to delete */
if (n == i)
goto set_app_exit;
len = (n - 1 - i) * sizeof(*fw_app);
if (len)
memmove(fw_app, fw_app + 1, len);
n--;
memset(fw_app + n, 0, sizeof(*fw_app));
}
data->count = n;
data->len = cpu_to_le16(sizeof(*fw_app) * n);
data->subtype = cpu_to_le16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL);
bnxt_hwrm_cmd_hdr_init(bp, &set, HWRM_FW_SET_STRUCTURED_DATA, -1, -1);
set.src_data_addr = cpu_to_le64(mapping);
set.data_len = cpu_to_le16(sizeof(*data) + sizeof(*fw_app) * n);
set.hdr_cnt = 1;
rc = hwrm_send_message(bp, &set, sizeof(set), HWRM_CMD_TIMEOUT);
if (rc)
rc = -EIO;
set_app_exit:
dma_free_coherent(&bp->pdev->dev, data_len, data, mapping);
return rc;
}
static int bnxt_ets_validate(struct bnxt *bp, struct ieee_ets *ets, u8 *tc)
{
int total_ets_bw = 0;
u8 max_tc = 0;
int i;
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
if (ets->prio_tc[i] > bp->max_tc) {
netdev_err(bp->dev, "priority to TC mapping exceeds TC count %d\n",
ets->prio_tc[i]);
return -EINVAL;
}
if (ets->prio_tc[i] > max_tc)
max_tc = ets->prio_tc[i];
if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]) && i > bp->max_tc)
return -EINVAL;
switch (ets->tc_tsa[i]) {
case IEEE_8021QAZ_TSA_STRICT:
break;
case IEEE_8021QAZ_TSA_ETS:
total_ets_bw += ets->tc_tx_bw[i];
break;
default:
return -ENOTSUPP;
}
}
if (total_ets_bw > 100)
return -EINVAL;
*tc = max_tc + 1;
return 0;
}
static int bnxt_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets)
{
struct bnxt *bp = netdev_priv(dev);
struct ieee_ets *my_ets = bp->ieee_ets;
ets->ets_cap = bp->max_tc;
if (!my_ets) {
int rc;
if (bp->dcbx_cap & DCB_CAP_DCBX_HOST)
return 0;
my_ets = kzalloc(sizeof(*my_ets), GFP_KERNEL);
if (!my_ets)
return 0;
rc = bnxt_hwrm_queue_cos2bw_qcfg(bp, my_ets);
if (rc)
return 0;
rc = bnxt_hwrm_queue_pri2cos_qcfg(bp, my_ets);
if (rc)
return 0;
}
ets->cbs = my_ets->cbs;
memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw));
memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw));
memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa));
memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc));
return 0;
}
static int bnxt_dcbnl_ieee_setets(struct net_device *dev, struct ieee_ets *ets)
{
struct bnxt *bp = netdev_priv(dev);
struct ieee_ets *my_ets = bp->ieee_ets;
u8 max_tc = 0;
int rc, i;
if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
!(bp->dcbx_cap & DCB_CAP_DCBX_HOST))
return -EINVAL;
rc = bnxt_ets_validate(bp, ets, &max_tc);
if (!rc) {
if (!my_ets) {
my_ets = kzalloc(sizeof(*my_ets), GFP_KERNEL);
if (!my_ets)
return -ENOMEM;
/* initialize PRI2TC mappings to invalid value */
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++)
my_ets->prio_tc[i] = IEEE_8021QAZ_MAX_TCS;
bp->ieee_ets = my_ets;
}
rc = bnxt_setup_mq_tc(dev, max_tc);
if (rc)
return rc;
rc = bnxt_hwrm_queue_cos2bw_cfg(bp, ets, max_tc);
if (rc)
return rc;
rc = bnxt_hwrm_queue_pri2cos_cfg(bp, ets);
if (rc)
return rc;
memcpy(my_ets, ets, sizeof(*my_ets));
}
return rc;
}
static int bnxt_dcbnl_ieee_getpfc(struct net_device *dev, struct ieee_pfc *pfc)
{
struct bnxt *bp = netdev_priv(dev);
__le64 *stats = (__le64 *)bp->hw_rx_port_stats;
struct ieee_pfc *my_pfc = bp->ieee_pfc;
long rx_off, tx_off;
int i, rc;
pfc->pfc_cap = bp->max_lltc;
if (!my_pfc) {
if (bp->dcbx_cap & DCB_CAP_DCBX_HOST)
return 0;
my_pfc = kzalloc(sizeof(*my_pfc), GFP_KERNEL);
if (!my_pfc)
return 0;
bp->ieee_pfc = my_pfc;
rc = bnxt_hwrm_queue_pfc_qcfg(bp, my_pfc);
if (rc)
return 0;
}
pfc->pfc_en = my_pfc->pfc_en;
pfc->mbc = my_pfc->mbc;
pfc->delay = my_pfc->delay;
if (!stats)
return 0;
rx_off = BNXT_RX_STATS_OFFSET(rx_pfc_ena_frames_pri0);
tx_off = BNXT_TX_STATS_OFFSET(tx_pfc_ena_frames_pri0);
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++, rx_off++, tx_off++) {
pfc->requests[i] = le64_to_cpu(*(stats + tx_off));
pfc->indications[i] = le64_to_cpu(*(stats + rx_off));
}
return 0;
}
static int bnxt_dcbnl_ieee_setpfc(struct net_device *dev, struct ieee_pfc *pfc)
{
struct bnxt *bp = netdev_priv(dev);
struct ieee_pfc *my_pfc = bp->ieee_pfc;
int rc;
if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
!(bp->dcbx_cap & DCB_CAP_DCBX_HOST))
return -EINVAL;
if (!my_pfc) {
my_pfc = kzalloc(sizeof(*my_pfc), GFP_KERNEL);
if (!my_pfc)
return -ENOMEM;
bp->ieee_pfc = my_pfc;
}
rc = bnxt_hwrm_queue_pfc_cfg(bp, pfc);
if (!rc)
memcpy(my_pfc, pfc, sizeof(*my_pfc));
return rc;
}
static int bnxt_dcbnl_ieee_setapp(struct net_device *dev, struct dcb_app *app)
{
struct bnxt *bp = netdev_priv(dev);
int rc = -EINVAL;
if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
!(bp->dcbx_cap & DCB_CAP_DCBX_HOST))
return -EINVAL;
rc = dcb_ieee_setapp(dev, app);
if (rc)
return rc;
if ((app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
app->protocol == ETH_P_ROCE) ||
(app->selector == IEEE_8021QAZ_APP_SEL_DGRAM &&
app->protocol == ROCE_V2_UDP_DPORT))
rc = bnxt_hwrm_set_dcbx_app(bp, app, true);
return rc;
}
static int bnxt_dcbnl_ieee_delapp(struct net_device *dev, struct dcb_app *app)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
!(bp->dcbx_cap & DCB_CAP_DCBX_HOST))
return -EINVAL;
rc = dcb_ieee_delapp(dev, app);
if (rc)
return rc;
if ((app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
app->protocol == ETH_P_ROCE) ||
(app->selector == IEEE_8021QAZ_APP_SEL_DGRAM &&
app->protocol == ROCE_V2_UDP_DPORT))
rc = bnxt_hwrm_set_dcbx_app(bp, app, false);
return rc;
}
static u8 bnxt_dcbnl_getdcbx(struct net_device *dev)
{
struct bnxt *bp = netdev_priv(dev);
return bp->dcbx_cap;
}
static u8 bnxt_dcbnl_setdcbx(struct net_device *dev, u8 mode)
{
struct bnxt *bp = netdev_priv(dev);
/* only support IEEE */
if ((mode & DCB_CAP_DCBX_VER_CEE) || !(mode & DCB_CAP_DCBX_VER_IEEE))
return 1;
if (mode & DCB_CAP_DCBX_HOST) {
if (BNXT_VF(bp) || (bp->flags & BNXT_FLAG_FW_LLDP_AGENT))
return 1;
}
if (mode == bp->dcbx_cap)
return 0;
bp->dcbx_cap = mode;
return 0;
}
static const struct dcbnl_rtnl_ops dcbnl_ops = {
.ieee_getets = bnxt_dcbnl_ieee_getets,
.ieee_setets = bnxt_dcbnl_ieee_setets,
.ieee_getpfc = bnxt_dcbnl_ieee_getpfc,
.ieee_setpfc = bnxt_dcbnl_ieee_setpfc,
.ieee_setapp = bnxt_dcbnl_ieee_setapp,
.ieee_delapp = bnxt_dcbnl_ieee_delapp,
.getdcbx = bnxt_dcbnl_getdcbx,
.setdcbx = bnxt_dcbnl_setdcbx,
};
void bnxt_dcb_init(struct bnxt *bp)
{
if (bp->hwrm_spec_code < 0x10501)
return;
bp->dcbx_cap = DCB_CAP_DCBX_VER_IEEE;
if (BNXT_PF(bp) && !(bp->flags & BNXT_FLAG_FW_LLDP_AGENT))
bp->dcbx_cap |= DCB_CAP_DCBX_HOST;
else
bp->dcbx_cap |= DCB_CAP_DCBX_LLD_MANAGED;
bp->dev->dcbnl_ops = &dcbnl_ops;
}
void bnxt_dcb_free(struct bnxt *bp)
{
kfree(bp->ieee_pfc);
kfree(bp->ieee_ets);
bp->ieee_pfc = NULL;
bp->ieee_ets = NULL;
}
#else
void bnxt_dcb_init(struct bnxt *bp)
{
}
void bnxt_dcb_free(struct bnxt *bp)
{
}
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2016 Broadcom Corporation
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#ifndef BNXT_DCB_H
#define BNXT_DCB_H
#include <net/dcbnl.h>
struct bnxt_dcb {
u8 max_tc;
struct ieee_pfc *ieee_pfc;
struct ieee_ets *ieee_ets;
u8 dcbx_cap;
u8 default_pri;
};
struct bnxt_cos2bw_cfg {
u8 pad[3];
u8 queue_id;
__le32 min_bw;
__le32 max_bw;
u8 tsa;
u8 pri_lvl;
u8 bw_weight;
u8 unused;
};
#define BNXT_LLQ(q_profile) \
((q_profile) == QUEUE_QPORTCFG_RESP_QUEUE_ID0_SERVICE_PROFILE_LOSSLESS)
#define HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL 0x0300
void bnxt_dcb_init(struct bnxt *);
void bnxt_dcb_free(struct bnxt *);
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2016 Broadcom Corporation
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#include <linux/ctype.h>
#include <linux/stringify.h>
#include <linux/ethtool.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
#if !defined(NEW_FLOW_KEYS) && defined(HAVE_FLOW_KEYS)
#include <net/flow_keys.h>
#endif
#if defined(ETHTOOL_GET_TS_INFO) && defined(HAVE_IEEE1588_SUPPORT)
#include <linux/ptp_clock_kernel.h>
#include <linux/net_tstamp.h>
#include <linux/timecounter.h>
#endif
#include "bnxt_compat.h"
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_xdp.h"
#include "bnxt_ptp.h"
#include "bnxt_ethtool.h"
#ifdef CONFIG_BNXT_FLASHDEV
#include "bnxt_nvm_defs.h" /* NVRAM content constant and structure defs */
#include "bnxt_fw_hdr.h" /* Firmware hdr constant and structure defs */
#define FLASH_NVRAM_TIMEOUT ((HWRM_CMD_TIMEOUT) * 100)
#define FLASH_PACKAGE_TIMEOUT ((HWRM_CMD_TIMEOUT) * 200)
#define INSTALL_PACKAGE_TIMEOUT ((HWRM_CMD_TIMEOUT) * 200)
#endif
static char *bnxt_get_pkgver(struct net_device *dev, char *buf, size_t buflen);
static u32 bnxt_get_msglevel(struct net_device *dev)
{
struct bnxt *bp = netdev_priv(dev);
return bp->msg_enable;
}
static void bnxt_set_msglevel(struct net_device *dev, u32 value)
{
struct bnxt *bp = netdev_priv(dev);
bp->msg_enable = value;
}
static int bnxt_get_coalesce(struct net_device *dev,
struct ethtool_coalesce *coal)
{
struct bnxt *bp = netdev_priv(dev);
memset(coal, 0, sizeof(*coal));
coal->rx_coalesce_usecs = bp->rx_coal_ticks;
/* 2 completion records per rx packet */
coal->rx_max_coalesced_frames = bp->rx_coal_bufs / 2;
coal->rx_coalesce_usecs_irq = bp->rx_coal_ticks_irq;
coal->rx_max_coalesced_frames_irq = bp->rx_coal_bufs_irq / 2;
coal->tx_coalesce_usecs = bp->tx_coal_ticks;
coal->tx_max_coalesced_frames = bp->tx_coal_bufs;
coal->tx_coalesce_usecs_irq = bp->tx_coal_ticks_irq;
coal->tx_max_coalesced_frames_irq = bp->tx_coal_bufs_irq;
coal->stats_block_coalesce_usecs = bp->stats_coal_ticks;
return 0;
}
static int bnxt_set_coalesce(struct net_device *dev,
struct ethtool_coalesce *coal)
{
struct bnxt *bp = netdev_priv(dev);
bool update_stats = false;
int rc = 0;
bp->rx_coal_ticks = coal->rx_coalesce_usecs;
/* 2 completion records per rx packet */
bp->rx_coal_bufs = coal->rx_max_coalesced_frames * 2;
bp->rx_coal_ticks_irq = coal->rx_coalesce_usecs_irq;
bp->rx_coal_bufs_irq = coal->rx_max_coalesced_frames_irq * 2;
bp->tx_coal_ticks = coal->tx_coalesce_usecs;
bp->tx_coal_bufs = coal->tx_max_coalesced_frames;
bp->tx_coal_ticks_irq = coal->tx_coalesce_usecs_irq;
bp->tx_coal_bufs_irq = coal->tx_max_coalesced_frames_irq;
if (bp->stats_coal_ticks != coal->stats_block_coalesce_usecs) {
u32 stats_ticks = coal->stats_block_coalesce_usecs;
/* Allow 0, which means disable. */
if (stats_ticks)
stats_ticks = clamp_t(u32, stats_ticks,
BNXT_MIN_STATS_COAL_TICKS,
BNXT_MAX_STATS_COAL_TICKS);
stats_ticks = rounddown(stats_ticks, BNXT_MIN_STATS_COAL_TICKS);
bp->stats_coal_ticks = stats_ticks;
update_stats = true;
}
if (netif_running(dev)) {
if (update_stats) {
rc = bnxt_close_nic(bp, true, false);
if (!rc)
rc = bnxt_open_nic(bp, true, false);
} else {
rc = bnxt_hwrm_set_coal(bp);
}
}
return rc;
}
#define BNXT_NUM_STATS 22
#define BNXT_RX_STATS_ENTRY(counter) \
{ BNXT_RX_STATS_OFFSET(counter), __stringify(counter) }
#define BNXT_TX_STATS_ENTRY(counter) \
{ BNXT_TX_STATS_OFFSET(counter), __stringify(counter) }
static const struct {
long offset;
char string[ETH_GSTRING_LEN];
} bnxt_port_stats_arr[] = {
BNXT_RX_STATS_ENTRY(rx_64b_frames),
BNXT_RX_STATS_ENTRY(rx_65b_127b_frames),
BNXT_RX_STATS_ENTRY(rx_128b_255b_frames),
BNXT_RX_STATS_ENTRY(rx_256b_511b_frames),
BNXT_RX_STATS_ENTRY(rx_512b_1023b_frames),
BNXT_RX_STATS_ENTRY(rx_1024b_1518_frames),
BNXT_RX_STATS_ENTRY(rx_good_vlan_frames),
BNXT_RX_STATS_ENTRY(rx_1519b_2047b_frames),
BNXT_RX_STATS_ENTRY(rx_2048b_4095b_frames),
BNXT_RX_STATS_ENTRY(rx_4096b_9216b_frames),
BNXT_RX_STATS_ENTRY(rx_9217b_16383b_frames),
BNXT_RX_STATS_ENTRY(rx_total_frames),
BNXT_RX_STATS_ENTRY(rx_ucast_frames),
BNXT_RX_STATS_ENTRY(rx_mcast_frames),
BNXT_RX_STATS_ENTRY(rx_bcast_frames),
BNXT_RX_STATS_ENTRY(rx_fcs_err_frames),
BNXT_RX_STATS_ENTRY(rx_ctrl_frames),
BNXT_RX_STATS_ENTRY(rx_pause_frames),
BNXT_RX_STATS_ENTRY(rx_pfc_frames),
BNXT_RX_STATS_ENTRY(rx_align_err_frames),
BNXT_RX_STATS_ENTRY(rx_ovrsz_frames),
BNXT_RX_STATS_ENTRY(rx_jbr_frames),
BNXT_RX_STATS_ENTRY(rx_mtu_err_frames),
BNXT_RX_STATS_ENTRY(rx_tagged_frames),
BNXT_RX_STATS_ENTRY(rx_double_tagged_frames),
BNXT_RX_STATS_ENTRY(rx_good_frames),
BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri0),
BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri1),
BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri2),
BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri3),
BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri4),
BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri5),
BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri6),
BNXT_RX_STATS_ENTRY(rx_pfc_ena_frames_pri7),
BNXT_RX_STATS_ENTRY(rx_undrsz_frames),
BNXT_RX_STATS_ENTRY(rx_eee_lpi_events),
BNXT_RX_STATS_ENTRY(rx_eee_lpi_duration),
BNXT_RX_STATS_ENTRY(rx_bytes),
BNXT_RX_STATS_ENTRY(rx_runt_bytes),
BNXT_RX_STATS_ENTRY(rx_runt_frames),
BNXT_TX_STATS_ENTRY(tx_64b_frames),
BNXT_TX_STATS_ENTRY(tx_65b_127b_frames),
BNXT_TX_STATS_ENTRY(tx_128b_255b_frames),
BNXT_TX_STATS_ENTRY(tx_256b_511b_frames),
BNXT_TX_STATS_ENTRY(tx_512b_1023b_frames),
BNXT_TX_STATS_ENTRY(tx_1024b_1518_frames),
BNXT_TX_STATS_ENTRY(tx_good_vlan_frames),
BNXT_TX_STATS_ENTRY(tx_1519b_2047_frames),
BNXT_TX_STATS_ENTRY(tx_2048b_4095b_frames),
BNXT_TX_STATS_ENTRY(tx_4096b_9216b_frames),
BNXT_TX_STATS_ENTRY(tx_9217b_16383b_frames),
BNXT_TX_STATS_ENTRY(tx_good_frames),
BNXT_TX_STATS_ENTRY(tx_total_frames),
BNXT_TX_STATS_ENTRY(tx_ucast_frames),
BNXT_TX_STATS_ENTRY(tx_mcast_frames),
BNXT_TX_STATS_ENTRY(tx_bcast_frames),
BNXT_TX_STATS_ENTRY(tx_pause_frames),
BNXT_TX_STATS_ENTRY(tx_pfc_frames),
BNXT_TX_STATS_ENTRY(tx_jabber_frames),
BNXT_TX_STATS_ENTRY(tx_fcs_err_frames),
BNXT_TX_STATS_ENTRY(tx_err),
BNXT_TX_STATS_ENTRY(tx_fifo_underruns),
BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri0),
BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri1),
BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri2),
BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri3),
BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri4),
BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri5),
BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri6),
BNXT_TX_STATS_ENTRY(tx_pfc_ena_frames_pri7),
BNXT_TX_STATS_ENTRY(tx_eee_lpi_events),
BNXT_TX_STATS_ENTRY(tx_eee_lpi_duration),
BNXT_TX_STATS_ENTRY(tx_total_collisions),
BNXT_TX_STATS_ENTRY(tx_bytes),
};
#define BNXT_NUM_PORT_STATS ARRAY_SIZE(bnxt_port_stats_arr)
static int bnxt_get_num_stats(struct bnxt *bp)
{
int num_stats = BNXT_NUM_STATS * bp->cp_nr_rings;
if (bp->flags & BNXT_FLAG_PORT_STATS)
num_stats += BNXT_NUM_PORT_STATS;
return num_stats;
}
static int bnxt_get_sset_count(struct net_device *dev, int sset)
{
struct bnxt *bp = netdev_priv(dev);
switch (sset) {
case ETH_SS_STATS:
return bnxt_get_num_stats(bp);
case ETH_SS_TEST:
if (!bp->num_tests)
return -EOPNOTSUPP;
return bp->num_tests;
default:
return -EOPNOTSUPP;
}
}
static void bnxt_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *buf)
{
u32 i, j = 0;
struct bnxt *bp = netdev_priv(dev);
int buf_size = bnxt_get_num_stats(bp) * sizeof(u64);
u32 stat_fields = sizeof(struct ctx_hw_stats) / 8;
memset(buf, 0, buf_size);
if (!bp->bnapi)
return;
for (i = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_napi *bnapi = bp->bnapi[i];
struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
__le64 *hw_stats = (__le64 *)cpr->hw_stats;
struct bnxt_sw_stats *sw_stats = &cpr->sw_stats;
int k;
for (k = 0; k < stat_fields; j++, k++)
buf[j] = le64_to_cpu(hw_stats[k]);
buf[j++] = sw_stats->rx_l4_csum_errors;
buf[j++] = sw_stats->rx_resets;
}
if (bp->flags & BNXT_FLAG_PORT_STATS) {
__le64 *port_stats = (__le64 *)bp->hw_rx_port_stats;
for (i = 0; i < BNXT_NUM_PORT_STATS; i++, j++) {
buf[j] = le64_to_cpu(*(port_stats +
bnxt_port_stats_arr[i].offset));
}
}
}
static void bnxt_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
{
struct bnxt *bp = netdev_priv(dev);
u32 i;
switch (stringset) {
/* The number of strings must match BNXT_NUM_STATS defined above. */
case ETH_SS_STATS:
for (i = 0; i < bp->cp_nr_rings; i++) {
sprintf(buf, "[%d]: rx_ucast_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_mcast_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_bcast_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_discards", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_drops", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_ucast_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_mcast_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_bcast_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_ucast_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_mcast_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_bcast_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_discards", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_drops", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_ucast_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_mcast_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tx_bcast_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tpa_packets", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tpa_bytes", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tpa_events", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: tpa_aborts", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_l4_csum_errors", i);
buf += ETH_GSTRING_LEN;
sprintf(buf, "[%d]: rx_resets", i);
buf += ETH_GSTRING_LEN;
}
if (bp->flags & BNXT_FLAG_PORT_STATS) {
for (i = 0; i < BNXT_NUM_PORT_STATS; i++) {
strcpy(buf, bnxt_port_stats_arr[i].string);
buf += ETH_GSTRING_LEN;
}
}
break;
case ETH_SS_TEST:
if (bp->num_tests)
memcpy(buf, bp->test_info->string,
bp->num_tests * ETH_GSTRING_LEN);
break;
default:
netdev_err(bp->dev, "bnxt_get_strings invalid request %x\n",
stringset);
break;
}
}
static void bnxt_get_ringparam(struct net_device *dev,
struct ethtool_ringparam *ering)
{
struct bnxt *bp = netdev_priv(dev);
ering->rx_max_pending = BNXT_MAX_RX_DESC_CNT;
ering->rx_jumbo_max_pending = BNXT_MAX_RX_JUM_DESC_CNT;
ering->tx_max_pending = BNXT_MAX_TX_DESC_CNT;
ering->rx_pending = bp->rx_ring_size;
ering->rx_jumbo_pending = bp->rx_agg_ring_size;
ering->tx_pending = bp->tx_ring_size;
}
static int bnxt_set_ringparam(struct net_device *dev,
struct ethtool_ringparam *ering)
{
struct bnxt *bp = netdev_priv(dev);
if ((ering->rx_pending > BNXT_MAX_RX_DESC_CNT) ||
(ering->tx_pending > BNXT_MAX_TX_DESC_CNT) ||
(ering->tx_pending <= MAX_SKB_FRAGS))
return -EINVAL;
if (netif_running(dev))
bnxt_close_nic(bp, false, false);
bp->rx_ring_size = ering->rx_pending;
bp->tx_ring_size = ering->tx_pending;
bnxt_set_ring_params(bp);
if (netif_running(dev))
return bnxt_open_nic(bp, false, false);
return 0;
}
#if defined(ETHTOOL_GCHANNELS) && !defined(GET_ETHTOOL_OP_EXT)
static void bnxt_get_channels(struct net_device *dev,
struct ethtool_channels *channel)
{
struct bnxt *bp = netdev_priv(dev);
int max_rx_rings, max_tx_rings, tcs;
bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, true);
channel->max_combined = min_t(int, max_rx_rings, max_tx_rings);
if (bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings, false)) {
max_rx_rings = 0;
max_tx_rings = 0;
}
tcs = netdev_get_num_tc(dev);
if (tcs > 1)
max_tx_rings /= tcs;
channel->max_rx = max_rx_rings;
channel->max_tx = max_tx_rings;
channel->max_other = 0;
if (bp->flags & BNXT_FLAG_SHARED_RINGS) {
channel->combined_count = bp->rx_nr_rings;
if (BNXT_CHIP_TYPE_NITRO_A0(bp))
channel->combined_count--;
} else {
if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) {
channel->rx_count = bp->rx_nr_rings;
channel->tx_count = bp->tx_nr_rings_per_tc;
}
}
}
static int bnxt_set_channels(struct net_device *dev,
struct ethtool_channels *channel)
{
struct bnxt *bp = netdev_priv(dev);
int req_tx_rings, req_rx_rings, tcs;
bool sh = false;
int tx_xdp = 0;
int rc = 0;
if (channel->other_count)
return -EINVAL;
if (!channel->combined_count &&
(!channel->rx_count || !channel->tx_count))
return -EINVAL;
if (channel->combined_count &&
(channel->rx_count || channel->tx_count))
return -EINVAL;
if (BNXT_CHIP_TYPE_NITRO_A0(bp) && (channel->rx_count ||
channel->tx_count))
return -EINVAL;
if (channel->combined_count)
sh = true;
tcs = netdev_get_num_tc(dev);
req_tx_rings = sh ? channel->combined_count : channel->tx_count;
req_rx_rings = sh ? channel->combined_count : channel->rx_count;
if (bp->tx_nr_rings_xdp) {
if (!sh) {
netdev_err(dev, "Only combined mode supported when XDP is enabled.\n");
return -EINVAL;
}
tx_xdp = req_rx_rings;
}
rc = bnxt_reserve_rings(bp, req_tx_rings, req_rx_rings, sh, tcs,
tx_xdp);
if (rc) {
netdev_warn(dev, "Unable to allocate the requested rings\n");
return rc;
}
if (netif_running(dev)) {
if (BNXT_PF(bp)) {
/* TODO CHIMP_FW: Send message to all VF's
* before PF unload
*/
}
rc = bnxt_close_nic(bp, true, false);
if (rc) {
netdev_err(bp->dev, "Set channel failure rc :%x\n",
rc);
return rc;
}
}
if (sh) {
bp->flags |= BNXT_FLAG_SHARED_RINGS;
bp->rx_nr_rings = channel->combined_count;
bp->tx_nr_rings_per_tc = channel->combined_count;
} else {
bp->flags &= ~BNXT_FLAG_SHARED_RINGS;
bp->rx_nr_rings = channel->rx_count;
bp->tx_nr_rings_per_tc = channel->tx_count;
}
bp->tx_nr_rings_xdp = tx_xdp;
bp->tx_nr_rings = bp->tx_nr_rings_per_tc + tx_xdp;
if (tcs > 1)
bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp;
bp->cp_nr_rings = sh ? max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) :
bp->tx_nr_rings + bp->rx_nr_rings;
bp->num_stat_ctxs = bp->cp_nr_rings;
/* After changing number of rx channels, update NTUPLE feature. */
netdev_update_features(dev);
if (netif_running(dev)) {
rc = bnxt_open_nic(bp, true, false);
if ((!rc) && BNXT_PF(bp)) {
/* TODO CHIMP_FW: Send message to all VF's
* to renable
*/
}
}
return rc;
}
#endif
#ifdef HAVE_RXNFC
#ifdef CONFIG_RFS_ACCEL
static int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd,
u32 *rule_locs)
{
int i, j = 0;
cmd->data = bp->ntp_fltr_count;
for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) {
struct hlist_head *head;
struct hlist_node __maybe_unused *node;
struct bnxt_ntuple_filter *fltr;
head = &bp->ntp_fltr_hash_tbl[i];
rcu_read_lock();
__hlist_for_each_entry_rcu(fltr, node, head, hash) {
if (j == cmd->rule_cnt)
break;
rule_locs[j++] = fltr->sw_id;
}
rcu_read_unlock();
if (j == cmd->rule_cnt)
break;
}
cmd->rule_cnt = j;
return 0;
}
static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
{
struct ethtool_rx_flow_spec *fs =
(struct ethtool_rx_flow_spec *)&cmd->fs;
struct bnxt_ntuple_filter *fltr;
struct flow_keys *fkeys;
int i, rc = -EINVAL;
if (fs->location < 0 || fs->location >= BNXT_NTP_FLTR_MAX_FLTR)
return rc;
for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) {
struct hlist_head *head;
struct hlist_node __maybe_unused *node;
head = &bp->ntp_fltr_hash_tbl[i];
rcu_read_lock();
__hlist_for_each_entry_rcu(fltr, node, head, hash) {
if (fltr->sw_id == fs->location)
goto fltr_found;
}
rcu_read_unlock();
}
return rc;
fltr_found:
fkeys = &fltr->fkeys;
#ifdef NEW_FLOW_KEYS
if (fkeys->basic.n_proto == htons(ETH_P_IP)) {
if (fkeys->basic.ip_proto == IPPROTO_TCP)
fs->flow_type = TCP_V4_FLOW;
else if (fkeys->basic.ip_proto == IPPROTO_UDP)
fs->flow_type = UDP_V4_FLOW;
else
goto fltr_err;
fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src;
fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0);
fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst;
fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0);
fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src;
fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0);
fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst;
fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0);
} else {
#ifdef HAVE_ETHTOOL_IP6_SPEC
int i;
if (fkeys->basic.ip_proto == IPPROTO_TCP)
fs->flow_type = TCP_V6_FLOW;
else if (fkeys->basic.ip_proto == IPPROTO_UDP)
fs->flow_type = UDP_V6_FLOW;
else
goto fltr_err;
*(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] =
fkeys->addrs.v6addrs.src;
*(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] =
fkeys->addrs.v6addrs.dst;
for (i = 0; i < 4; i++) {
fs->m_u.tcp_ip6_spec.ip6src[i] = cpu_to_be32(~0);
fs->m_u.tcp_ip6_spec.ip6dst[i] = cpu_to_be32(~0);
}
fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src;
fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(~0);
fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst;
fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0);
#endif
}
#else
if (fkeys->ip_proto == IPPROTO_TCP)
fs->flow_type = TCP_V4_FLOW;
else if (fkeys->ip_proto == IPPROTO_UDP)
fs->flow_type = UDP_V4_FLOW;
else
goto fltr_err;
fs->h_u.tcp_ip4_spec.ip4src = fkeys->src;
fs->m_u.tcp_ip4_spec.ip4src = (__be32) ~0;
fs->h_u.tcp_ip4_spec.ip4dst = fkeys->dst;
fs->m_u.tcp_ip4_spec.ip4dst = (__be32) ~0;
fs->h_u.tcp_ip4_spec.psrc = fkeys->port16[0];
fs->m_u.tcp_ip4_spec.psrc = (__be16) ~0;
fs->h_u.tcp_ip4_spec.pdst = fkeys->port16[1];
fs->m_u.tcp_ip4_spec.pdst = (__be16) ~0;
#endif
fs->ring_cookie = fltr->rxq;
rc = 0;
fltr_err:
rcu_read_unlock();
return rc;
}
#endif /* CONFIG_RFS_ACCEL */
static u64 get_ethtool_ipv4_rss(struct bnxt *bp)
{
if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4)
return RXH_IP_SRC | RXH_IP_DST;
return 0;
}
static u64 get_ethtool_ipv6_rss(struct bnxt *bp)
{
if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6)
return RXH_IP_SRC | RXH_IP_DST;
return 0;
}
static int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
{
cmd->data = 0;
switch (cmd->flow_type) {
case TCP_V4_FLOW:
if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4)
cmd->data |= RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3;
cmd->data |= get_ethtool_ipv4_rss(bp);
break;
case UDP_V4_FLOW:
if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4)
cmd->data |= RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3;
/* fall through */
case SCTP_V4_FLOW:
case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
case IPV4_FLOW:
cmd->data |= get_ethtool_ipv4_rss(bp);
break;
case TCP_V6_FLOW:
if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6)
cmd->data |= RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3;
cmd->data |= get_ethtool_ipv6_rss(bp);
break;
case UDP_V6_FLOW:
if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6)
cmd->data |= RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3;
/* fall through */
case SCTP_V6_FLOW:
case AH_ESP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
case IPV6_FLOW:
cmd->data |= get_ethtool_ipv6_rss(bp);
break;
}
return 0;
}
#define RXH_4TUPLE (RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)
#define RXH_2TUPLE (RXH_IP_SRC | RXH_IP_DST)
static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
{
u32 rss_hash_cfg = bp->rss_hash_cfg;
int tuple, rc = 0;
if (cmd->data == RXH_4TUPLE)
tuple = 4;
else if (cmd->data == RXH_2TUPLE)
tuple = 2;
else if (!cmd->data)
tuple = 0;
else
return -EINVAL;
if (cmd->flow_type == TCP_V4_FLOW) {
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
if (tuple == 4)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
} else if (cmd->flow_type == UDP_V4_FLOW) {
if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP))
return -EINVAL;
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4;
if (tuple == 4)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4;
} else if (cmd->flow_type == TCP_V6_FLOW) {
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
if (tuple == 4)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6;
} else if (cmd->flow_type == UDP_V6_FLOW) {
if (tuple == 4 && !(bp->flags & BNXT_FLAG_UDP_RSS_CAP))
return -EINVAL;
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
if (tuple == 4)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
} else if (tuple == 4) {
return -EINVAL;
}
switch (cmd->flow_type) {
case TCP_V4_FLOW:
case UDP_V4_FLOW:
case SCTP_V4_FLOW:
case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
case IPV4_FLOW:
if (tuple == 2)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4;
else if (!tuple)
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4;
break;
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
case AH_ESP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
case IPV6_FLOW:
if (tuple == 2)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6;
else if (!tuple)
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6;
break;
}
if (bp->rss_hash_cfg == rss_hash_cfg)
return 0;
bp->rss_hash_cfg = rss_hash_cfg;
if (netif_running(bp->dev)) {
bnxt_close_nic(bp, false, false);
rc = bnxt_open_nic(bp, false, false);
}
return rc;
}
static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
#ifdef HAVE_RXNFC_VOID
void *rule_locs)
#else
u32 *rule_locs)
#endif
{
struct bnxt *bp = netdev_priv(dev);
int rc = 0;
switch (cmd->cmd) {
#ifdef CONFIG_RFS_ACCEL
case ETHTOOL_GRXRINGS:
cmd->data = bp->rx_nr_rings;
break;
case ETHTOOL_GRXCLSRLCNT:
cmd->rule_cnt = bp->ntp_fltr_count;
cmd->data = BNXT_NTP_FLTR_MAX_FLTR;
break;
case ETHTOOL_GRXCLSRLALL:
rc = bnxt_grxclsrlall(bp, cmd, (u32 *)rule_locs);
break;
case ETHTOOL_GRXCLSRULE:
rc = bnxt_grxclsrule(bp, cmd);
break;
#endif
case ETHTOOL_GRXFH:
rc = bnxt_grxfh(bp, cmd);
break;
default:
rc = -EOPNOTSUPP;
break;
}
return rc;
}
static int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
switch (cmd->cmd) {
case ETHTOOL_SRXFH:
rc = bnxt_srxfh(bp, cmd);
break;
default:
rc = -EOPNOTSUPP;
break;
}
return rc;
}
#endif /* HAVE_RXNFC */
#if defined(HAVE_RXFH_INDIR_SIZE) && !defined(GET_ETHTOOL_OP_EXT)
static u32 bnxt_get_rxfh_indir_size(struct net_device *dev)
{
return HW_HASH_INDEX_SIZE;
}
#endif
#if defined(HAVE_GET_RXFH_KEY_SIZE) && !defined(GET_ETHTOOL_OP_EXT)
static u32 bnxt_get_rxfh_key_size(struct net_device *dev)
{
return HW_HASH_KEY_SIZE;
}
static int bnxt_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
u8 *hfunc)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vnic_info *vnic = &bp->vnic_info[0];
int i = 0;
if (hfunc)
*hfunc = ETH_RSS_HASH_TOP;
if (indir)
for (i = 0; i < HW_HASH_INDEX_SIZE; i++)
indir[i] = le16_to_cpu(vnic->rss_table[i]);
if (key)
memcpy(key, vnic->rss_hash_key, HW_HASH_KEY_SIZE);
return 0;
}
#endif
static void bnxt_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct bnxt *bp = netdev_priv(dev);
char *pkglog;
char *pkgver = NULL;
pkglog = kmalloc(BNX_PKG_LOG_MAX_LENGTH, GFP_KERNEL);
if (pkglog)
pkgver = bnxt_get_pkgver(dev, pkglog, BNX_PKG_LOG_MAX_LENGTH);
strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
if (pkgver && *pkgver != 0 && isdigit(*pkgver))
snprintf(info->fw_version, sizeof(info->fw_version) - 1,
"%s pkg %s", bp->fw_ver_str, pkgver);
else
strlcpy(info->fw_version, bp->fw_ver_str,
sizeof(info->fw_version));
strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info));
info->n_stats = bnxt_get_num_stats(bp);
info->testinfo_len = bp->num_tests;
/* TODO CHIMP_FW: eeprom dump details */
info->eedump_len = 0;
/* TODO CHIMP FW: reg dump details */
info->regdump_len = 0;
kfree(pkglog);
}
static void bnxt_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct bnxt *bp = netdev_priv(dev);
wol->supported = 0;
wol->wolopts = 0;
memset(&wol->sopass, 0, sizeof(wol->sopass));
if (bp->flags & BNXT_FLAG_WOL_CAP) {
wol->supported = WAKE_MAGIC;
if (bp->wol)
wol->wolopts = WAKE_MAGIC;
}
}
static int bnxt_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct bnxt *bp = netdev_priv(dev);
if (wol->wolopts & ~WAKE_MAGIC)
return -EINVAL;
if (wol->wolopts & WAKE_MAGIC) {
if (!(bp->flags & BNXT_FLAG_WOL_CAP))
return -EINVAL;
if (!bp->wol) {
if (bnxt_hwrm_alloc_wol_fltr(bp))
return -EBUSY;
bp->wol = 1;
}
} else {
if (bp->wol) {
if (bnxt_hwrm_free_wol_fltr(bp))
return -EBUSY;
bp->wol = 0;
}
}
return 0;
}
u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause)
{
u32 speed_mask = 0;
/* TODO: support 25GB, 40GB, 50GB with different cable type */
/* set the advertised speeds */
if (fw_speeds & BNXT_LINK_SPEED_MSK_100MB)
speed_mask |= ADVERTISED_100baseT_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_1GB)
speed_mask |= ADVERTISED_1000baseT_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_2_5GB)
speed_mask |= ADVERTISED_2500baseX_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_10GB)
speed_mask |= ADVERTISED_10000baseT_Full;
if (fw_speeds & BNXT_LINK_SPEED_MSK_40GB)
speed_mask |= ADVERTISED_40000baseCR4_Full;
if ((fw_pause & BNXT_LINK_PAUSE_BOTH) == BNXT_LINK_PAUSE_BOTH)
speed_mask |= ADVERTISED_Pause;
else if (fw_pause & BNXT_LINK_PAUSE_TX)
speed_mask |= ADVERTISED_Asym_Pause;
else if (fw_pause & BNXT_LINK_PAUSE_RX)
speed_mask |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
return speed_mask;
}
#ifdef HAVE_ETHTOOL_GLINKSETTINGS_25G
#define BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, name)\
{ \
if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100MB) \
ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
100baseT_Full); \
if ((fw_speeds) & BNXT_LINK_SPEED_MSK_1GB) \
ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
1000baseT_Full); \
if ((fw_speeds) & BNXT_LINK_SPEED_MSK_10GB) \
ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
10000baseT_Full); \
if ((fw_speeds) & BNXT_LINK_SPEED_MSK_25GB) \
ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
25000baseCR_Full); \
if ((fw_speeds) & BNXT_LINK_SPEED_MSK_40GB) \
ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
40000baseCR4_Full);\
if ((fw_speeds) & BNXT_LINK_SPEED_MSK_50GB) \
ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
50000baseCR2_Full);\
if ((fw_pause) & BNXT_LINK_PAUSE_RX) { \
ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
Pause); \
if (!((fw_pause) & BNXT_LINK_PAUSE_TX)) \
ethtool_link_ksettings_add_link_mode( \
lk_ksettings, name, Asym_Pause);\
} else if ((fw_pause) & BNXT_LINK_PAUSE_TX) { \
ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\
Asym_Pause); \
} \
}
#define BNXT_ETHTOOL_TO_FW_SPDS(fw_speeds, lk_ksettings, name) \
{ \
if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \
100baseT_Full) || \
ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \
100baseT_Half)) \
(fw_speeds) |= BNXT_LINK_SPEED_MSK_100MB; \
if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \
1000baseT_Full) || \
ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \
1000baseT_Half)) \
(fw_speeds) |= BNXT_LINK_SPEED_MSK_1GB; \
if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \
10000baseT_Full)) \
(fw_speeds) |= BNXT_LINK_SPEED_MSK_10GB; \
if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \
25000baseCR_Full)) \
(fw_speeds) |= BNXT_LINK_SPEED_MSK_25GB; \
if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \
40000baseCR4_Full)) \
(fw_speeds) |= BNXT_LINK_SPEED_MSK_40GB; \
if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \
50000baseCR2_Full)) \
(fw_speeds) |= BNXT_LINK_SPEED_MSK_50GB; \
}
static void bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info,
struct ethtool_link_ksettings *lk_ksettings)
{
u16 fw_speeds = link_info->advertising;
u8 fw_pause = 0;
if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
fw_pause = link_info->auto_pause_setting;
BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, advertising);
}
static void bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info,
struct ethtool_link_ksettings *lk_ksettings)
{
u16 fw_speeds = link_info->lp_auto_link_speeds;
u8 fw_pause = 0;
if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
fw_pause = link_info->lp_pause;
BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings,
lp_advertising);
}
static void bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info,
struct ethtool_link_ksettings *lk_ksettings)
{
u16 fw_speeds = link_info->support_speeds;
BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, 0, lk_ksettings, supported);
ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, Pause);
ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
Asym_Pause);
if (link_info->support_auto_speeds)
ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
Autoneg);
}
#else
static u32 bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info)
{
u16 fw_speeds = link_info->advertising;
u8 fw_pause = 0;
if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
fw_pause = link_info->auto_pause_setting;
return _bnxt_fw_to_ethtool_adv_spds(fw_speeds, fw_pause);
}
static u32 bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info)
{
u16 fw_speeds = link_info->lp_auto_link_speeds;
u8 fw_pause = 0;
if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
fw_pause = link_info->lp_pause;
return _bnxt_fw_to_ethtool_adv_spds(fw_speeds, fw_pause);
}
static u32 bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info)
{
u16 fw_speeds = link_info->support_speeds;
u32 supported;
supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0);
return supported | SUPPORTED_Pause | SUPPORTED_Asym_Pause;
}
static u32 bnxt_fw_to_ethtool_support_adv_spds(struct bnxt_link_info *link_info)
{
u16 fw_speeds = link_info->support_auto_speeds;
u32 supported;
supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0);
if (supported)
supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
return supported;
}
#endif
u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed)
{
switch (fw_link_speed) {
case BNXT_LINK_SPEED_100MB:
return SPEED_100;
case BNXT_LINK_SPEED_1GB:
return SPEED_1000;
case BNXT_LINK_SPEED_2_5GB:
return SPEED_2500;
case BNXT_LINK_SPEED_10GB:
return SPEED_10000;
case BNXT_LINK_SPEED_20GB:
return SPEED_20000;
case BNXT_LINK_SPEED_25GB:
return SPEED_25000;
case BNXT_LINK_SPEED_40GB:
return SPEED_40000;
case BNXT_LINK_SPEED_50GB:
return SPEED_50000;
default:
return SPEED_UNKNOWN;
}
}
#ifdef HAVE_ETHTOOL_GLINKSETTINGS_25G
static int bnxt_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *lk_ksettings)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
struct ethtool_link_settings *base = &lk_ksettings->base;
u32 ethtool_speed;
ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported);
bnxt_fw_to_ethtool_support_spds(link_info, lk_ksettings);
ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising);
if (link_info->autoneg) {
bnxt_fw_to_ethtool_advertised_spds(link_info, lk_ksettings);
ethtool_link_ksettings_add_link_mode(lk_ksettings,
advertising, Autoneg);
base->autoneg = AUTONEG_ENABLE;
if (link_info->phy_link_status == BNXT_LINK_LINK)
bnxt_fw_to_ethtool_lp_adv(link_info, lk_ksettings);
ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed);
if (!netif_carrier_ok(dev))
base->duplex = DUPLEX_UNKNOWN;
else if (link_info->duplex & BNXT_LINK_DUPLEX_FULL)
base->duplex = DUPLEX_FULL;
else
base->duplex = DUPLEX_HALF;
} else {
base->autoneg = AUTONEG_DISABLE;
ethtool_speed =
bnxt_fw_to_ethtool_speed(link_info->req_link_speed);
base->duplex = DUPLEX_HALF;
if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL)
base->duplex = DUPLEX_FULL;
}
base->speed = ethtool_speed;
base->port = PORT_NONE;
if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
base->port = PORT_TP;
ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
TP);
ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising,
TP);
} else {
ethtool_link_ksettings_add_link_mode(lk_ksettings, supported,
FIBRE);
ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising,
FIBRE);
if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC)
base->port = PORT_DA;
else if (link_info->media_type ==
PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE)
base->port = PORT_FIBRE;
}
base->phy_address = link_info->phy_addr;
return 0;
}
#else
static int bnxt_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
u16 ethtool_speed;
cmd->supported = bnxt_fw_to_ethtool_support_spds(link_info);
if (link_info->support_auto_speeds)
cmd->supported |= SUPPORTED_Autoneg;
if (link_info->autoneg) {
cmd->advertising =
bnxt_fw_to_ethtool_advertised_spds(link_info);
cmd->advertising |= ADVERTISED_Autoneg;
cmd->autoneg = AUTONEG_ENABLE;
if (link_info->phy_link_status == BNXT_LINK_LINK)
cmd->lp_advertising =
bnxt_fw_to_ethtool_lp_adv(link_info);
ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed);
if (!netif_carrier_ok(dev))
cmd->duplex = DUPLEX_UNKNOWN;
else if (link_info->duplex & BNXT_LINK_DUPLEX_FULL)
cmd->duplex = DUPLEX_FULL;
else
cmd->duplex = DUPLEX_HALF;
} else {
cmd->autoneg = AUTONEG_DISABLE;
cmd->advertising = 0;
ethtool_speed =
bnxt_fw_to_ethtool_speed(link_info->req_link_speed);
cmd->duplex = DUPLEX_HALF;
if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL)
cmd->duplex = DUPLEX_FULL;
}
ethtool_cmd_speed_set(cmd, ethtool_speed);
cmd->port = PORT_NONE;
if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
cmd->port = PORT_TP;
cmd->supported |= SUPPORTED_TP;
cmd->advertising |= ADVERTISED_TP;
} else {
cmd->supported |= SUPPORTED_FIBRE;
cmd->advertising |= ADVERTISED_FIBRE;
if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC)
cmd->port = PORT_DA;
else if (link_info->media_type ==
PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE)
cmd->port = PORT_FIBRE;
}
if (link_info->transceiver ==
PORT_PHY_QCFG_RESP_XCVR_PKG_TYPE_XCVR_INTERNAL)
cmd->transceiver = XCVR_INTERNAL;
else
cmd->transceiver = XCVR_EXTERNAL;
cmd->phy_address = link_info->phy_addr;
return 0;
}
#endif
static u32 bnxt_get_fw_speed(struct net_device *dev, u16 ethtool_speed)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
u16 support_spds = link_info->support_speeds;
u32 fw_speed = 0;
switch (ethtool_speed) {
case SPEED_100:
if (support_spds & BNXT_LINK_SPEED_MSK_100MB)
fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_100MB;
break;
case SPEED_1000:
if (support_spds & BNXT_LINK_SPEED_MSK_1GB)
fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_1GB;
break;
case SPEED_2500:
if (support_spds & BNXT_LINK_SPEED_MSK_2_5GB)
fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_2_5GB;
break;
case SPEED_10000:
if (support_spds & BNXT_LINK_SPEED_MSK_10GB)
fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_10GB;
break;
case SPEED_20000:
if (support_spds & BNXT_LINK_SPEED_MSK_20GB)
fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_20GB;
break;
case SPEED_25000:
if (support_spds & BNXT_LINK_SPEED_MSK_25GB)
fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_25GB;
break;
case SPEED_40000:
if (support_spds & BNXT_LINK_SPEED_MSK_40GB)
fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_40GB;
break;
case SPEED_50000:
if (support_spds & BNXT_LINK_SPEED_MSK_50GB)
fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_50GB;
break;
default:
netdev_err(dev, "unsupported speed!\n");
break;
}
return fw_speed;
}
u16 bnxt_get_fw_auto_link_speeds(u32 advertising)
{
u16 fw_speed_mask = 0;
/* only support autoneg at speed 100, 1000, and 10000 */
if (advertising & (ADVERTISED_100baseT_Full |
ADVERTISED_100baseT_Half)) {
fw_speed_mask |= BNXT_LINK_SPEED_MSK_100MB;
}
if (advertising & (ADVERTISED_1000baseT_Full |
ADVERTISED_1000baseT_Half)) {
fw_speed_mask |= BNXT_LINK_SPEED_MSK_1GB;
}
if (advertising & ADVERTISED_10000baseT_Full)
fw_speed_mask |= BNXT_LINK_SPEED_MSK_10GB;
if (advertising & ADVERTISED_40000baseCR4_Full)
fw_speed_mask |= BNXT_LINK_SPEED_MSK_40GB;
return fw_speed_mask;
}
#ifdef HAVE_ETHTOOL_GLINKSETTINGS_25G
static int bnxt_set_link_ksettings(struct net_device *dev,
const struct ethtool_link_ksettings *lk_ksettings)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
const struct ethtool_link_settings *base = &lk_ksettings->base;
bool set_pause = false;
u16 fw_advertising = 0;
u32 speed;
int rc = 0;
if (!BNXT_SINGLE_PF(bp))
return -EOPNOTSUPP;
if (base->autoneg == AUTONEG_ENABLE) {
BNXT_ETHTOOL_TO_FW_SPDS(fw_advertising, lk_ksettings,
advertising);
link_info->autoneg |= BNXT_AUTONEG_SPEED;
if (!fw_advertising)
link_info->advertising = link_info->support_auto_speeds;
else
link_info->advertising = fw_advertising;
/* any change to autoneg will cause link change, therefore the
* driver should put back the original pause setting in autoneg
*/
set_pause = true;
} else {
u16 fw_speed;
u8 phy_type = link_info->phy_type;
if (phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASET ||
phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE ||
link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
netdev_err(dev, "10GBase-T devices must autoneg\n");
rc = -EINVAL;
goto set_setting_exit;
}
if (base->duplex == DUPLEX_HALF) {
netdev_err(dev, "HALF DUPLEX is not supported!\n");
rc = -EINVAL;
goto set_setting_exit;
}
speed = base->speed;
fw_speed = bnxt_get_fw_speed(dev, speed);
if (!fw_speed) {
rc = -EINVAL;
goto set_setting_exit;
}
link_info->req_link_speed = fw_speed;
link_info->req_duplex = BNXT_LINK_DUPLEX_FULL;
link_info->autoneg = 0;
link_info->advertising = 0;
}
if (netif_running(dev))
rc = bnxt_hwrm_set_link_setting(bp, set_pause, false);
set_setting_exit:
return rc;
}
#else
static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
int rc = 0;
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
bool set_pause = false;
u16 fw_advertising = 0;
u32 speed;
if (!BNXT_SINGLE_PF(bp))
return -EOPNOTSUPP;
if (cmd->autoneg == AUTONEG_ENABLE) {
u32 supported_spds =
bnxt_fw_to_ethtool_support_adv_spds(link_info);
if (!supported_spds) {
netdev_err(dev, "Autoneg not supported\n");
rc = -EINVAL;
goto set_setting_exit;
}
if (cmd->advertising & ~(supported_spds | ADVERTISED_Autoneg |
ADVERTISED_TP | ADVERTISED_FIBRE)) {
netdev_err(dev, "Unsupported advertising mask (adv: 0x%x)\n",
cmd->advertising);
rc = -EINVAL;
goto set_setting_exit;
}
fw_advertising = bnxt_get_fw_auto_link_speeds(cmd->advertising);
link_info->autoneg |= BNXT_AUTONEG_SPEED;
if (!fw_advertising)
link_info->advertising = link_info->support_auto_speeds;
else
link_info->advertising = fw_advertising;
/* any change to autoneg will cause link change, therefore the
* driver should put back the original pause setting in autoneg
*/
set_pause = true;
} else {
u16 fw_speed;
u8 phy_type = link_info->phy_type;
if (phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASET ||
phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE ||
link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
netdev_err(dev, "10GBase-T devices must autoneg\n");
rc = -EINVAL;
goto set_setting_exit;
}
/* TODO: currently don't support half duplex */
if (cmd->duplex == DUPLEX_HALF) {
netdev_err(dev, "HALF DUPLEX is not supported!\n");
rc = -EINVAL;
goto set_setting_exit;
}
/* If received a request for an unknown duplex, assume full*/
if (cmd->duplex == DUPLEX_UNKNOWN)
cmd->duplex = DUPLEX_FULL;
speed = ethtool_cmd_speed(cmd);
fw_speed = bnxt_get_fw_speed(dev, speed);
if (!fw_speed) {
rc = -EINVAL;
goto set_setting_exit;
}
link_info->req_link_speed = fw_speed;
link_info->req_duplex = BNXT_LINK_DUPLEX_FULL;
link_info->autoneg = 0;
link_info->advertising = 0;
}
if (netif_running(dev))
rc = bnxt_hwrm_set_link_setting(bp, set_pause, false);
set_setting_exit:
return rc;
}
#endif
static void bnxt_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *epause)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
if (BNXT_VF(bp))
return;
epause->autoneg = !!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL);
epause->rx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_RX);
epause->tx_pause = !!(link_info->req_flow_ctrl & BNXT_LINK_PAUSE_TX);
}
static int bnxt_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *epause)
{
int rc = 0;
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
if (!BNXT_SINGLE_PF(bp))
return -EOPNOTSUPP;
if (epause->autoneg) {
if (!(link_info->autoneg & BNXT_AUTONEG_SPEED))
return -EINVAL;
link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
if (bp->hwrm_spec_code >= 0x10201)
link_info->req_flow_ctrl =
PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE;
} else {
/* when transition from auto pause to force pause,
* force a link change
*/
if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
link_info->force_link_chng = true;
link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL;
link_info->req_flow_ctrl = 0;
}
if (epause->rx_pause)
link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_RX;
if (epause->tx_pause)
link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX;
if (netif_running(dev))
rc = bnxt_hwrm_set_pause(bp);
return rc;
}
static u32 bnxt_get_link(struct net_device *dev)
{
struct bnxt *bp = netdev_priv(dev);
/* TODO: handle MF, VF, driver close case */
return bp->link_info.link_up;
}
#ifdef CONFIG_BNXT_FLASHDEV
static int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal,
u16 ext, u16 *index, u32 *item_length,
u32 *data_length);
static int bnxt_flash_nvram(struct net_device *dev,
u16 dir_type,
u16 dir_ordinal,
u16 dir_ext,
u16 dir_attr,
const u8 *data,
size_t data_len)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
struct hwrm_nvm_write_input req = {0};
dma_addr_t dma_handle;
u8 *kmem;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_WRITE, -1, -1);
req.dir_type = cpu_to_le16(dir_type);
req.dir_ordinal = cpu_to_le16(dir_ordinal);
req.dir_ext = cpu_to_le16(dir_ext);
req.dir_attr = cpu_to_le16(dir_attr);
req.dir_data_length = cpu_to_le32(data_len);
kmem = dma_alloc_coherent(&bp->pdev->dev, data_len, &dma_handle,
GFP_KERNEL);
if (!kmem) {
netdev_err(dev, "dma_alloc_coherent failure, length = %u\n",
(unsigned)data_len);
return -ENOMEM;
}
memcpy(kmem, data, data_len);
req.host_src_addr = cpu_to_le64(dma_handle);
rc = hwrm_send_message(bp, &req, sizeof(req), FLASH_NVRAM_TIMEOUT);
dma_free_coherent(&bp->pdev->dev, data_len, kmem, dma_handle);
return rc;
}
static int bnxt_firmware_reset(struct net_device *dev,
u16 dir_type)
{
struct bnxt *bp = netdev_priv(dev);
struct hwrm_fw_reset_input req = {0};
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FW_RESET, -1, -1);
/* TODO: Support ASAP ChiMP self-reset (e.g. upon PF driver unload) */
/* TODO: Address self-reset of APE/KONG/BONO/TANG or ungraceful reset */
/* (e.g. when firmware isn't already running) */
switch (dir_type) {
case BNX_DIR_TYPE_CHIMP_PATCH:
case BNX_DIR_TYPE_BOOTCODE:
case BNX_DIR_TYPE_BOOTCODE_2:
req.embedded_proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_BOOT;
/* Self-reset ChiMP upon next PCIe reset: */
req.selfrst_status = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST;
break;
case BNX_DIR_TYPE_APE_FW:
case BNX_DIR_TYPE_APE_PATCH:
req.embedded_proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_MGMT;
/* Self-reset APE upon next PCIe reset: */
req.selfrst_status = FW_RESET_REQ_SELFRST_STATUS_SELFRSTPCIERST;
break;
case BNX_DIR_TYPE_KONG_FW:
case BNX_DIR_TYPE_KONG_PATCH:
req.embedded_proc_type =
FW_RESET_REQ_EMBEDDED_PROC_TYPE_NETCTRL;
break;
case BNX_DIR_TYPE_BONO_FW:
case BNX_DIR_TYPE_BONO_PATCH:
req.embedded_proc_type = FW_RESET_REQ_EMBEDDED_PROC_TYPE_ROCE;
break;
default:
return -EINVAL;
}
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
static int bnxt_flash_firmware(struct net_device *dev,
u16 dir_type,
const u8 *fw_data,
size_t fw_size)
{
int rc = 0;
u16 code_type;
u32 stored_crc;
u32 calculated_crc;
struct bnxt_fw_header *header = (struct bnxt_fw_header *)fw_data;
switch (dir_type) {
case BNX_DIR_TYPE_BOOTCODE:
case BNX_DIR_TYPE_BOOTCODE_2:
code_type = CODE_BOOT;
break;
case BNX_DIR_TYPE_CHIMP_PATCH:
code_type = CODE_CHIMP_PATCH;
break;
case BNX_DIR_TYPE_APE_FW:
code_type = CODE_MCTP_PASSTHRU;
break;
case BNX_DIR_TYPE_APE_PATCH:
code_type = CODE_APE_PATCH;
break;
case BNX_DIR_TYPE_KONG_FW:
code_type = CODE_KONG_FW;
break;
case BNX_DIR_TYPE_KONG_PATCH:
code_type = CODE_KONG_PATCH;
break;
case BNX_DIR_TYPE_BONO_FW:
code_type = CODE_BONO_FW;
break;
case BNX_DIR_TYPE_BONO_PATCH:
code_type = CODE_BONO_PATCH;
break;
default:
netdev_err(dev, "Unsupported directory entry type: %u\n",
dir_type);
return -EINVAL;
}
if (fw_size < sizeof(struct bnxt_fw_header)) {
netdev_err(dev, "Invalid firmware file size: %u\n",
(unsigned int)fw_size);
return -EINVAL;
}
if (header->signature != cpu_to_le32(BNXT_FIRMWARE_BIN_SIGNATURE)) {
netdev_err(dev, "Invalid firmware signature: %08X\n",
le32_to_cpu(header->signature));
return -EINVAL;
}
if (header->code_type != code_type) {
netdev_err(dev, "Expected firmware type: %d, read: %d\n",
code_type, header->code_type);
return -EINVAL;
}
if (header->device != DEVICE_CUMULUS_FAMILY) {
netdev_err(dev, "Expected firmware device family %d, read: %d\n",
DEVICE_CUMULUS_FAMILY, header->device);
return -EINVAL;
}
/* Confirm the CRC32 checksum of the file: */
stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size -
sizeof(stored_crc)));
calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc));
if (calculated_crc != stored_crc) {
netdev_err(dev, "Firmware file CRC32 checksum (%08lX) does not match calculated checksum (%08lX)\n",
(unsigned long)stored_crc,
(unsigned long)calculated_crc);
return -EINVAL;
}
rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST,
0, 0, fw_data, fw_size);
if (rc == 0) /* Firmware update successful */
rc = bnxt_firmware_reset(dev, dir_type);
return rc;
}
static int bnxt_flash_microcode(struct net_device *dev,
u16 dir_type,
const u8 *fw_data,
size_t fw_size)
{
struct bnxt_ucode_trailer *trailer;
u32 calculated_crc;
u32 stored_crc;
int rc = 0;
if (fw_size < sizeof(struct bnxt_ucode_trailer)) {
netdev_err(dev, "Invalid microcode file size: %u\n",
(unsigned int)fw_size);
return -EINVAL;
}
trailer = (struct bnxt_ucode_trailer *)(fw_data + (fw_size -
sizeof(*trailer)));
if (trailer->sig != cpu_to_le32(BNXT_UCODE_TRAILER_SIGNATURE)) {
netdev_err(dev, "Invalid microcode trailer signature: %08X\n",
le32_to_cpu(trailer->sig));
return -EINVAL;
}
if (le16_to_cpu(trailer->dir_type) != dir_type) {
netdev_err(dev, "Expected microcode type: %d, read: %d\n",
dir_type, le16_to_cpu(trailer->dir_type));
return -EINVAL;
}
if (le16_to_cpu(trailer->trailer_length) <
sizeof(struct bnxt_ucode_trailer)) {
netdev_err(dev, "Invalid microcode trailer length: %d\n",
le16_to_cpu(trailer->trailer_length));
return -EINVAL;
}
/* Confirm the CRC32 checksum of the file: */
stored_crc = le32_to_cpu(*(__le32 *)(fw_data + fw_size -
sizeof(stored_crc)));
calculated_crc = ~crc32(~0, fw_data, fw_size - sizeof(stored_crc));
if (calculated_crc != stored_crc) {
netdev_err(dev,
"CRC32 (%08lX) does not match calculated: %08lX\n",
(unsigned long)stored_crc,
(unsigned long)calculated_crc);
return -EINVAL;
}
rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST,
0, 0, fw_data, fw_size);
return rc;
}
static bool bnxt_dir_type_is_ape_bin_format(u16 dir_type)
{
switch (dir_type) {
case BNX_DIR_TYPE_CHIMP_PATCH:
case BNX_DIR_TYPE_BOOTCODE:
case BNX_DIR_TYPE_BOOTCODE_2:
case BNX_DIR_TYPE_APE_FW:
case BNX_DIR_TYPE_APE_PATCH:
case BNX_DIR_TYPE_KONG_FW:
case BNX_DIR_TYPE_KONG_PATCH:
case BNX_DIR_TYPE_BONO_FW:
case BNX_DIR_TYPE_BONO_PATCH:
return true;
}
return false;
}
static bool bnxt_dir_type_is_other_exec_format(u16 dir_type)
{
switch (dir_type) {
case BNX_DIR_TYPE_AVS:
case BNX_DIR_TYPE_EXP_ROM_MBA:
case BNX_DIR_TYPE_PCIE:
case BNX_DIR_TYPE_TSCF_UCODE:
case BNX_DIR_TYPE_EXT_PHY:
case BNX_DIR_TYPE_CCM:
case BNX_DIR_TYPE_ISCSI_BOOT:
case BNX_DIR_TYPE_ISCSI_BOOT_IPV6:
case BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6:
return true;
}
return false;
}
static bool bnxt_dir_type_is_executable(u16 dir_type)
{
return bnxt_dir_type_is_ape_bin_format(dir_type) ||
bnxt_dir_type_is_other_exec_format(dir_type);
}
static int bnxt_flash_firmware_from_file(struct net_device *dev,
u16 dir_type,
const char *filename)
{
const struct firmware *fw;
int rc;
rc = request_firmware(&fw, filename, &dev->dev);
if (rc != 0) {
netdev_err(dev, "Error %d requesting firmware file: %s\n",
rc, filename);
return rc;
}
if (bnxt_dir_type_is_ape_bin_format(dir_type) == true)
rc = bnxt_flash_firmware(dev, dir_type, fw->data, fw->size);
else if (bnxt_dir_type_is_other_exec_format(dir_type) == true)
rc = bnxt_flash_microcode(dev, dir_type, fw->data, fw->size);
else
rc = bnxt_flash_nvram(dev, dir_type, BNX_DIR_ORDINAL_FIRST,
0, 0, fw->data, fw->size);
release_firmware(fw);
return rc;
}
static int bnxt_flash_package_from_file(struct net_device *dev,
char *filename, u32 install_type)
{
struct bnxt *bp = netdev_priv(dev);
struct hwrm_nvm_install_update_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_nvm_install_update_input install = {0};
const struct firmware *fw;
u32 item_len;
u16 index;
int rc;
bnxt_hwrm_fw_set_time(bp);
if (bnxt_find_nvram_item(dev, BNX_DIR_TYPE_UPDATE,
BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE,
&index, &item_len, NULL) != 0) {
netdev_err(dev, "PKG update area not created in nvram\n");
return -ENOBUFS;
}
rc = request_firmware(&fw, filename, &dev->dev);
if (rc != 0) {
netdev_err(dev, "PKG error %d requesting file: %s\n",
rc, filename);
return rc;
}
if (fw->size > item_len) {
netdev_err(dev, "PKG insufficient update area in nvram: %lu",
(unsigned long)fw->size);
rc = -EFBIG;
} else {
dma_addr_t dma_handle;
u8 *kmem;
struct hwrm_nvm_modify_input modify = {0};
bnxt_hwrm_cmd_hdr_init(bp, &modify, HWRM_NVM_MODIFY, -1, -1);
modify.dir_idx = cpu_to_le16(index);
modify.len = cpu_to_le32(fw->size);
kmem = dma_alloc_coherent(&bp->pdev->dev, fw->size,
&dma_handle, GFP_KERNEL);
if (!kmem) {
netdev_err(dev,
"dma_alloc_coherent failure, length = %u\n",
(unsigned int)fw->size);
rc = -ENOMEM;
} else {
memcpy(kmem, fw->data, fw->size);
modify.host_src_addr = cpu_to_le64(dma_handle);
rc = hwrm_send_message(bp, &modify, sizeof(modify),
FLASH_PACKAGE_TIMEOUT);
dma_free_coherent(&bp->pdev->dev, fw->size, kmem,
dma_handle);
}
}
release_firmware(fw);
if (rc)
return rc;
if ((install_type & 0xffff) == 0)
install_type >>= 16;
bnxt_hwrm_cmd_hdr_init(bp, &install, HWRM_NVM_INSTALL_UPDATE, -1, -1);
install.install_type = cpu_to_le32(install_type);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &install, sizeof(install),
INSTALL_PACKAGE_TIMEOUT);
if (rc) {
rc = -EOPNOTSUPP;
goto flash_pkg_exit;
}
if (resp->error_code) {
u8 error_code = ((struct hwrm_err_output *)resp)->cmd_err;
if (error_code == NVM_INSTALL_UPDATE_CMD_ERR_CODE_FRAG_ERR) {
install.flags |= cpu_to_le16(
NVM_INSTALL_UPDATE_REQ_FLAGS_ALLOWED_TO_DEFRAG);
rc = _hwrm_send_message(bp, &install, sizeof(install),
INSTALL_PACKAGE_TIMEOUT);
if (rc) {
rc = -EOPNOTSUPP;
goto flash_pkg_exit;
}
}
}
if (resp->result) {
netdev_err(dev, "PKG install error = %d, problem_item = %d\n",
(s8)resp->result, (int)resp->problem_item);
rc = -ENOPKG;
}
flash_pkg_exit:
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int bnxt_flash_device(struct net_device *dev,
struct ethtool_flash *flash)
{
if (!BNXT_PF((struct bnxt *)netdev_priv(dev))) {
netdev_err(dev, "flashdev not supported from a virtual function\n");
return -EINVAL;
}
if (flash->region == ETHTOOL_FLASH_ALL_REGIONS ||
flash->region > 0xffff)
return bnxt_flash_package_from_file(dev, flash->data,
flash->region);
return bnxt_flash_firmware_from_file(dev, flash->region, flash->data);
}
static int nvm_get_dir_info(struct net_device *dev, u32 *entries, u32 *length)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
struct hwrm_nvm_get_dir_info_input req = {0};
struct hwrm_nvm_get_dir_info_output *output = bp->hwrm_cmd_resp_addr;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_DIR_INFO, -1, -1);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc) {
*entries = le32_to_cpu(output->entries);
*length = le32_to_cpu(output->entry_length);
}
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int bnxt_get_eeprom_len(struct net_device *dev)
{
/* The -1 return value allows the entire 32-bit range of offsets to be
* passed via the ethtool command-line utility.
*/
return -1;
}
static int bnxt_get_nvram_directory(struct net_device *dev, u32 len, u8 *data)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
u32 dir_entries;
u32 entry_length;
u8 *buf;
size_t buflen;
dma_addr_t dma_handle;
struct hwrm_nvm_get_dir_entries_input req = {0};
rc = nvm_get_dir_info(dev, &dir_entries, &entry_length);
if (rc != 0)
return rc;
/* Insert 2 bytes of directory info (count and size of entries) */
if (len < 2)
return -EINVAL;
*data++ = dir_entries;
*data++ = entry_length;
len -= 2;
memset(data, 0xff, len);
buflen = dir_entries * entry_length;
buf = dma_alloc_coherent(&bp->pdev->dev, buflen, &dma_handle,
GFP_KERNEL);
if (!buf) {
netdev_err(dev, "dma_alloc_coherent failure, length = %u\n",
(unsigned)buflen);
return -ENOMEM;
}
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_DIR_ENTRIES, -1, -1);
req.host_dest_addr = cpu_to_le64(dma_handle);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc == 0)
memcpy(data, buf, len > buflen ? buflen : len);
dma_free_coherent(&bp->pdev->dev, buflen, buf, dma_handle);
return rc;
}
static int bnxt_get_nvram_item(struct net_device *dev, u32 index, u32 offset,
u32 length, u8 *data)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
u8 *buf;
dma_addr_t dma_handle;
struct hwrm_nvm_read_input req = {0};
buf = dma_alloc_coherent(&bp->pdev->dev, length, &dma_handle,
GFP_KERNEL);
if (!buf) {
netdev_err(dev, "dma_alloc_coherent failure, length = %u\n",
(unsigned)length);
return -ENOMEM;
}
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_READ, -1, -1);
req.host_dest_addr = cpu_to_le64(dma_handle);
req.dir_idx = cpu_to_le16(index);
req.offset = cpu_to_le32(offset);
req.len = cpu_to_le32(length);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc == 0)
memcpy(data, buf, length);
dma_free_coherent(&bp->pdev->dev, length, buf, dma_handle);
return rc;
}
static int bnxt_find_nvram_item(struct net_device *dev, u16 type, u16 ordinal,
u16 ext, u16 *index, u32 *item_length,
u32 *data_length)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
struct hwrm_nvm_find_dir_entry_input req = {0};
struct hwrm_nvm_find_dir_entry_output *output = bp->hwrm_cmd_resp_addr;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_FIND_DIR_ENTRY, -1, -1);
req.enables = 0;
req.dir_idx = 0;
req.dir_type = cpu_to_le16(type);
req.dir_ordinal = cpu_to_le16(ordinal);
req.dir_ext = cpu_to_le16(ext);
req.opt_ordinal = NVM_FIND_DIR_ENTRY_REQ_OPT_ORDINAL_EQ;
rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc == 0) {
if (index)
*index = le16_to_cpu(output->dir_idx);
if (item_length)
*item_length = le32_to_cpu(output->dir_item_length);
if (data_length)
*data_length = le32_to_cpu(output->dir_data_length);
}
return rc;
}
static char *bnxt_parse_pkglog(int desired_field, u8 *data, size_t datalen)
{
char *retval = NULL;
char *p;
char *value;
int field = 0;
if (datalen < 1)
return NULL;
/* null-terminate the log data (removing last '\n'): */
data[datalen - 1] = 0;
for (p = data; *p != 0; p++) {
field = 0;
retval = NULL;
while (*p != 0 && *p != '\n') {
value = p;
while (*p != 0 && *p != '\t' && *p != '\n')
p++;
if (field == desired_field)
retval = value;
if (*p != '\t')
break;
*p = 0;
field++;
p++;
}
if (*p == 0)
break;
*p = 0;
}
return retval;
}
static char *bnxt_get_pkgver(struct net_device *dev, char *buf, size_t buflen)
{
u16 index = 0;
u32 datalen;
if (bnxt_find_nvram_item(dev, BNX_DIR_TYPE_PKG_LOG,
BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE,
&index, NULL, &datalen) != 0)
return NULL;
memset(buf, 0, buflen);
if (bnxt_get_nvram_item(dev, index, 0, datalen, buf) != 0)
return NULL;
return bnxt_parse_pkglog(BNX_PKG_LOG_FIELD_IDX_PKG_VERSION, buf,
datalen);
}
static int bnxt_get_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom,
u8 *data)
{
int i;
int rc;
u32 index;
u32 offset;
u32 size;
struct bnxt *bp = netdev_priv(dev);
struct hwrm_fw_qstatus_input fw_status_req = {0};
struct hwrm_fw_qstatus_output *fw_status_resp = bp->hwrm_cmd_resp_addr;
struct hwrm_nvm_get_dev_info_input dev_info_req = {0};
if (eeprom->len < 1)
return -EINVAL;
if (eeprom->offset == 0) /* special offset value to get directory */
return bnxt_get_nvram_directory(dev, eeprom->len, data);
index = eeprom->offset >> 24;
offset = eeprom->offset & 0xffffff;
if (index != 0)
return bnxt_get_nvram_item(dev, index - 1, offset, eeprom->len,
data);
switch (offset) {
case 1: /* Query firmware reset status */
if (eeprom->len < 5)
return -EINVAL;
size = 4; /* procs: BOOT, MGMT, NETCTRL, and ROCE */
*(data++) = size;
mutex_lock(&bp->hwrm_cmd_lock);
for (i = 0; i < size; i++) {
bnxt_hwrm_cmd_hdr_init(bp, &fw_status_req,
HWRM_FW_QSTATUS, -1, -1);
fw_status_req.embedded_proc_type = i;
rc = _hwrm_send_message(bp, &fw_status_req,
sizeof(fw_status_req),
HWRM_CMD_TIMEOUT);
if (rc == 0)
*(data++) = fw_status_resp->selfrst_status;
else
break;
}
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
case 2: /* Query firmware version information */
size = sizeof(bp->ver_resp);
*(data++) = size;
memcpy(data, &bp->ver_resp, min(size, eeprom->len - 1));
return 0;
case 3: /* Query NVM device information */
bnxt_hwrm_cmd_hdr_init(bp, &dev_info_req,
HWRM_NVM_GET_DEV_INFO, -1, -1);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &dev_info_req, sizeof(dev_info_req),
HWRM_CMD_TIMEOUT);
if (rc == 0) {
size = sizeof(struct hwrm_nvm_get_dev_info_output);
*(data++) = size;
memcpy(data, bp->hwrm_cmd_resp_addr, min(size,
eeprom->len - 1));
}
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
return -EINVAL;
}
static int bnxt_erase_nvram_directory(struct net_device *dev, u8 index)
{
struct bnxt *bp = netdev_priv(dev);
struct hwrm_nvm_erase_dir_entry_input req = {0};
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_ERASE_DIR_ENTRY, -1, -1);
req.dir_idx = cpu_to_le16(index);
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
static int bnxt_set_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom,
u8 *data)
{
struct bnxt *bp = netdev_priv(dev);
u8 index, dir_op;
u16 type, ext, ordinal, attr;
if (!BNXT_PF(bp)) {
netdev_err(dev, "NVM write not supported from a virtual function\n");
return -EINVAL;
}
type = eeprom->magic >> 16;
if (type == 0xffff) { /* special value for directory operations */
index = eeprom->magic & 0xff;
dir_op = eeprom->magic >> 8;
if (index == 0)
return -EINVAL;
switch (dir_op) {
case 0x0e: /* erase */
if (eeprom->offset != ~eeprom->magic)
return -EINVAL;
return bnxt_erase_nvram_directory(dev, index - 1);
default:
return -EINVAL;
}
}
/* Create or re-write an NVM item: */
if (bnxt_dir_type_is_executable(type) == true)
return -EOPNOTSUPP;
ext = eeprom->magic & 0xffff;
ordinal = eeprom->offset >> 16;
attr = eeprom->offset & 0xffff;
return bnxt_flash_nvram(dev, type, ordinal, ext, attr, data,
eeprom->len);
}
#endif
#if defined(ETHTOOL_GEEE) && !defined(GET_ETHTOOL_OP_EXT)
static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata)
{
struct bnxt *bp = netdev_priv(dev);
struct ethtool_eee *eee = &bp->eee;
struct bnxt_link_info *link_info = &bp->link_info;
u32 advertising =
_bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0);
int rc = 0;
if (!BNXT_SINGLE_PF(bp))
return -EOPNOTSUPP;
if (!(bp->flags & BNXT_FLAG_EEE_CAP))
return -EOPNOTSUPP;
if (!edata->eee_enabled)
goto eee_ok;
if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
netdev_warn(dev, "EEE requires autoneg\n");
return -EINVAL;
}
if (edata->tx_lpi_enabled) {
if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi ||
edata->tx_lpi_timer < bp->lpi_tmr_lo)) {
netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n",
bp->lpi_tmr_lo, bp->lpi_tmr_hi);
return -EINVAL;
} else if (!bp->lpi_tmr_hi) {
edata->tx_lpi_timer = eee->tx_lpi_timer;
}
}
if (!edata->advertised) {
edata->advertised = advertising & eee->supported;
} else if (edata->advertised & ~advertising) {
netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n",
edata->advertised, advertising);
return -EINVAL;
}
eee->advertised = edata->advertised;
eee->tx_lpi_enabled = edata->tx_lpi_enabled;
eee->tx_lpi_timer = edata->tx_lpi_timer;
eee_ok:
eee->eee_enabled = edata->eee_enabled;
if (netif_running(dev))
rc = bnxt_hwrm_set_link_setting(bp, false, true);
return rc;
}
static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata)
{
struct bnxt *bp = netdev_priv(dev);
if (!(bp->flags & BNXT_FLAG_EEE_CAP))
return -EOPNOTSUPP;
*edata = bp->eee;
if (!bp->eee.eee_enabled) {
/* Preserve tx_lpi_timer so that the last value will be used
* by default when it is re-enabled.
*/
edata->advertised = 0;
edata->tx_lpi_enabled = 0;
}
if (!bp->eee.eee_active)
edata->lp_advertised = 0;
return 0;
}
#endif
#if defined(ETHTOOL_GMODULEEEPROM) && !defined(GET_ETHTOOL_OP_EXT)
static int bnxt_read_sfp_module_eeprom_info(struct bnxt *bp, u16 i2c_addr,
u16 page_number, u16 start_addr,
u16 data_length, u8 *buf)
{
struct hwrm_port_phy_i2c_read_input req = {0};
struct hwrm_port_phy_i2c_read_output *output = bp->hwrm_cmd_resp_addr;
int rc, byte_offset = 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_I2C_READ, -1, -1);
req.i2c_slave_addr = i2c_addr;
req.page_number = cpu_to_le16(page_number);
req.port_id = cpu_to_le16(bp->pf.port_id);
do {
u16 xfer_size;
xfer_size = min_t(u16, data_length, BNXT_MAX_PHY_I2C_RESP_SIZE);
data_length -= xfer_size;
req.page_offset = cpu_to_le16(start_addr + byte_offset);
req.data_length = xfer_size;
req.enables = cpu_to_le32(start_addr + byte_offset ?
PORT_PHY_I2C_READ_REQ_ENABLES_PAGE_OFFSET : 0);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req),
HWRM_CMD_TIMEOUT);
if (!rc)
memcpy(buf + byte_offset, output->data, xfer_size);
mutex_unlock(&bp->hwrm_cmd_lock);
byte_offset += xfer_size;
} while (!rc && data_length > 0);
return rc;
}
static int bnxt_get_module_info(struct net_device *dev,
struct ethtool_modinfo *modinfo)
{
struct bnxt *bp = netdev_priv(dev);
struct hwrm_port_phy_i2c_read_input req = {0};
struct hwrm_port_phy_i2c_read_output *output = bp->hwrm_cmd_resp_addr;
int rc;
/* No point in going further if phy status indicates
* module is not inserted or if it is powered down or
* if it is of type 10GBase-T
*/
if (bp->link_info.module_status >
PORT_PHY_QCFG_RESP_MODULE_STATUS_WARNINGMSG)
return -EOPNOTSUPP;
/* This feature is not supported in older firmware versions */
if (bp->hwrm_spec_code < 0x10202)
return -EOPNOTSUPP;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_I2C_READ, -1, -1);
req.i2c_slave_addr = I2C_DEV_ADDR_A0;
req.page_number = 0;
req.page_offset = cpu_to_le16(SFP_EEPROM_SFF_8472_COMP_ADDR);
req.data_length = SFP_EEPROM_SFF_8472_COMP_SIZE;
req.port_id = cpu_to_le16(bp->pf.port_id);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc) {
u32 module_id = le32_to_cpu(output->data[0]);
switch (module_id) {
case SFF_MODULE_ID_SFP:
modinfo->type = ETH_MODULE_SFF_8472;
modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
break;
case SFF_MODULE_ID_QSFP:
case SFF_MODULE_ID_QSFP_PLUS:
modinfo->type = ETH_MODULE_SFF_8436;
modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN;
break;
case SFF_MODULE_ID_QSFP28:
modinfo->type = ETH_MODULE_SFF_8636;
modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN;
break;
default:
rc = -EOPNOTSUPP;
break;
}
}
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int bnxt_get_module_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom,
u8 *data)
{
struct bnxt *bp = netdev_priv(dev);
u16 start = eeprom->offset, length = eeprom->len;
int rc = 0;
memset(data, 0, eeprom->len);
/* Read A0 portion of the EEPROM */
if (start < ETH_MODULE_SFF_8436_LEN) {
if (start + eeprom->len > ETH_MODULE_SFF_8436_LEN)
length = ETH_MODULE_SFF_8436_LEN - start;
rc = bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A0, 0,
start, length, data);
if (rc)
return rc;
start += length;
data += start;
length = eeprom->len - length;
}
/* Read A2 portion of the EEPROM */
if (length) {
start -= ETH_MODULE_SFF_8436_LEN;
bnxt_read_sfp_module_eeprom_info(bp, I2C_DEV_ADDR_A2, 1, start,
length, data);
}
return rc;
}
#endif
static int bnxt_nway_reset(struct net_device *dev)
{
int rc = 0;
struct bnxt *bp = netdev_priv(dev);
struct bnxt_link_info *link_info = &bp->link_info;
if (!BNXT_SINGLE_PF(bp))
return -EOPNOTSUPP;
if (!(link_info->autoneg & BNXT_AUTONEG_SPEED))
return -EINVAL;
if (netif_running(dev))
rc = bnxt_hwrm_set_link_setting(bp, true, false);
return rc;
}
#if defined(HAVE_SET_PHYS_ID) && !defined(GET_ETHTOOL_OP_EXT)
static int bnxt_set_phys_id(struct net_device *dev,
enum ethtool_phys_id_state state)
{
struct hwrm_port_led_cfg_input req = {0};
struct bnxt *bp = netdev_priv(dev);
struct bnxt_pf_info *pf = &bp->pf;
struct bnxt_led_cfg *led_cfg;
u8 led_state;
__le16 duration;
int i, rc;
if (!bp->num_leds || BNXT_VF(bp))
return -EOPNOTSUPP;
if (state == ETHTOOL_ID_ACTIVE) {
led_state = PORT_LED_CFG_REQ_LED0_STATE_BLINKALT;
duration = cpu_to_le16(500);
} else if (state == ETHTOOL_ID_INACTIVE) {
led_state = PORT_LED_CFG_REQ_LED1_STATE_DEFAULT;
duration = cpu_to_le16(0);
} else {
return -EINVAL;
}
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_LED_CFG, -1, -1);
req.port_id = cpu_to_le16(pf->port_id);
req.num_leds = bp->num_leds;
led_cfg = (struct bnxt_led_cfg *) &req.led0_id;
for (i = 0; i < bp->num_leds; i++, led_cfg++) {
req.enables |= BNXT_LED_DFLT_ENABLES(i);
led_cfg->led_id = bp->leds[i].led_id;
led_cfg->led_state = led_state;
led_cfg->led_blink_on = duration;
led_cfg->led_blink_off = duration;
led_cfg->led_group_id = bp->leds[i].led_group_id;
}
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc)
rc = -EIO;
return rc;
}
#endif
static int bnxt_hwrm_selftest_irq(struct bnxt *bp, u16 cmpl_ring)
{
struct hwrm_selftest_irq_input req = {0};
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_SELFTEST_IRQ, cmpl_ring, -1);
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
static int bnxt_test_irq(struct bnxt *bp)
{
int i;
for (i = 0; i < bp->cp_nr_rings; i++) {
u16 cmpl_ring = bp->grp_info[i].cp_fw_ring_id;
int rc;
rc = bnxt_hwrm_selftest_irq(bp, cmpl_ring);
if (rc)
return rc;
}
return 0;
}
static int bnxt_hwrm_mac_loopback(struct bnxt *bp, bool enable)
{
struct hwrm_port_mac_cfg_input req = {0};
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_MAC_CFG, -1, -1);
req.enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_LPBK);
if (enable)
req.lpbk = PORT_MAC_CFG_REQ_LPBK_LOCAL;
else
req.lpbk = PORT_MAC_CFG_REQ_LPBK_NONE;
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
static int bnxt_disable_an_for_lpbk(struct bnxt *bp,
struct hwrm_port_phy_cfg_input *req)
{
struct bnxt_link_info *link_info = &bp->link_info;
u16 fw_advertising = link_info->advertising;
u16 fw_speed;
int rc;
if (!link_info->autoneg)
return 0;
fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_1GB;
if (netif_carrier_ok(bp->dev))
fw_speed = bp->link_info.link_speed;
else if (fw_advertising & BNXT_LINK_SPEED_MSK_10GB)
fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_10GB;
else if (fw_advertising & BNXT_LINK_SPEED_MSK_25GB)
fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_25GB;
else if (fw_advertising & BNXT_LINK_SPEED_MSK_40GB)
fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_40GB;
else if (fw_advertising & BNXT_LINK_SPEED_MSK_50GB)
fw_speed = PORT_PHY_CFG_REQ_FORCE_LINK_SPEED_50GB;
req->force_link_speed = cpu_to_le16(fw_speed);
req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE |
PORT_PHY_CFG_REQ_FLAGS_RESET_PHY);
rc = hwrm_send_message(bp, req, sizeof(*req), HWRM_CMD_TIMEOUT);
req->flags = 0;
req->force_link_speed = cpu_to_le16(0);
return rc;
}
static int bnxt_hwrm_phy_loopback(struct bnxt *bp, bool enable)
{
struct hwrm_port_phy_cfg_input req = {0};
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_CFG, -1, -1);
if (enable) {
bnxt_disable_an_for_lpbk(bp, &req);
req.lpbk = PORT_PHY_CFG_REQ_LPBK_LOCAL;
} else {
req.lpbk = PORT_PHY_CFG_REQ_LPBK_NONE;
}
req.enables = cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_LPBK);
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
static int bnxt_rx_loopback(struct bnxt *bp, struct bnxt_napi *bnapi,
u32 raw_cons, int pkt_size)
{
struct bnxt_cp_ring_info *cpr = &bnapi->cp_ring;
struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
struct bnxt_sw_rx_bd *rx_buf;
struct rx_cmp *rxcmp;
u16 cp_cons, cons;
u8 *data;
u32 len;
int i;
cp_cons = RING_CMP(raw_cons);
rxcmp = (struct rx_cmp *)
&cpr->cp_desc_ring[CP_RING(cp_cons)][CP_IDX(cp_cons)];
cons = rxcmp->rx_cmp_opaque;
rx_buf = &rxr->rx_buf_ring[cons];
data = rx_buf->data_ptr;
len = le32_to_cpu(rxcmp->rx_cmp_len_flags_type) >> RX_CMP_LEN_SHIFT;
if (len != pkt_size)
return -EIO;
i = ETH_ALEN;
if (!ether_addr_equal(data + i, bnapi->bp->dev->dev_addr))
return -EIO;
i += ETH_ALEN;
for ( ; i < pkt_size; i++) {
if (data[i] != (u8)(i & 0xff))
return -EIO;
}
return 0;
}
static int bnxt_poll_loopback(struct bnxt *bp, int pkt_size)
{
struct bnxt_napi *bnapi = bp->bnapi[0];
struct bnxt_cp_ring_info *cpr;
struct tx_cmp *txcmp;
int rc = -EIO;
u32 raw_cons;
u32 cons;
int i;
cpr = &bnapi->cp_ring;
raw_cons = cpr->cp_raw_cons;
for (i = 0; i < 200; i++) {
cons = RING_CMP(raw_cons);
txcmp = &cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)];
if (!TX_CMP_VALID(txcmp, raw_cons)) {
udelay(5);
continue;
}
/* The valid test of the entry must be done first before
* reading any further.
*/
dma_rmb();
if (TX_CMP_TYPE(txcmp) == CMP_TYPE_RX_L2_CMP) {
rc = bnxt_rx_loopback(bp, bnapi, raw_cons, pkt_size);
raw_cons = NEXT_RAW_CMP(raw_cons);
raw_cons = NEXT_RAW_CMP(raw_cons);
break;
}
raw_cons = NEXT_RAW_CMP(raw_cons);
}
cpr->cp_raw_cons = raw_cons;
return rc;
}
static int bnxt_run_loopback(struct bnxt *bp)
{
struct bnxt_tx_ring_info *txr = &bp->tx_ring[0];
int pkt_size, i = 0;
struct sk_buff *skb;
dma_addr_t map;
u8 *data;
int rc;
pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_copy_thresh);
skb = netdev_alloc_skb(bp->dev, pkt_size);
if (!skb)
return -ENOMEM;
data = skb_put(skb, pkt_size);
eth_broadcast_addr(data);
i += ETH_ALEN;
ether_addr_copy(&data[i], bp->dev->dev_addr);
i += ETH_ALEN;
for ( ; i < pkt_size; i++)
data[i] = (u8)(i & 0xff);
map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size,
PCI_DMA_TODEVICE);
if (dma_mapping_error(&bp->pdev->dev, map)) {
dev_kfree_skb(skb);
return -EIO;
}
bnxt_xmit_xdp(bp, txr, map, pkt_size, 0);
/* Sync BD data before updating doorbell */
wmb();
writel(DB_KEY_TX | txr->tx_prod, txr->tx_doorbell);
writel(DB_KEY_TX | txr->tx_prod, txr->tx_doorbell);
rc = bnxt_poll_loopback(bp, pkt_size);
dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE);
dev_kfree_skb(skb);
return rc;
}
static int bnxt_run_fw_tests(struct bnxt *bp, u8 test_mask, u8 *test_results)
{
struct hwrm_selftest_exec_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_selftest_exec_input req = {0};
int rc;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_SELFTEST_EXEC, -1, -1);
mutex_lock(&bp->hwrm_cmd_lock);
resp->test_success = 0;
req.flags = test_mask;
rc = _hwrm_send_message(bp, &req, sizeof(req), bp->test_info->timeout);
*test_results = resp->test_success;
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
#define BNXT_DRV_TESTS 3
#define BNXT_MACLPBK_TEST_IDX (bp->num_tests - BNXT_DRV_TESTS)
#define BNXT_PHYLPBK_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 1)
#define BNXT_IRQ_TEST_IDX (BNXT_MACLPBK_TEST_IDX + 2)
static void bnxt_self_test(struct net_device *dev, struct ethtool_test *etest,
u64 *buf)
{
struct bnxt *bp = netdev_priv(dev);
bool offline = false;
u8 test_results = 0;
u8 test_mask = 0;
int rc, i;
if (!bp->num_tests || !BNXT_SINGLE_PF(bp))
return;
memset(buf, 0, sizeof(u64) * bp->num_tests);
if (!netif_running(dev)) {
etest->flags |= ETH_TEST_FL_FAILED;
return;
}
if (etest->flags & ETH_TEST_FL_OFFLINE) {
if (bp->pf.active_vfs) {
etest->flags |= ETH_TEST_FL_FAILED;
netdev_warn(dev, "Offline tests cannot be run with active VFs\n");
return;
}
offline = true;
}
for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) {
u8 bit_val = 1 << i;
if (!(bp->test_info->offline_mask & bit_val))
test_mask |= bit_val;
else if (offline)
test_mask |= bit_val;
}
if (!offline) {
bnxt_run_fw_tests(bp, test_mask, &test_results);
} else {
rc = bnxt_close_nic(bp, false, false);
if (rc)
return;
bnxt_run_fw_tests(bp, test_mask, &test_results);
buf[BNXT_MACLPBK_TEST_IDX] = 1;
bnxt_hwrm_mac_loopback(bp, true);
msleep(250);
rc = bnxt_half_open_nic(bp);
if (rc) {
bnxt_hwrm_mac_loopback(bp, false);
etest->flags |= ETH_TEST_FL_FAILED;
return;
}
if (bnxt_run_loopback(bp))
etest->flags |= ETH_TEST_FL_FAILED;
else
buf[BNXT_MACLPBK_TEST_IDX] = 0;
bnxt_hwrm_mac_loopback(bp, false);
bnxt_hwrm_phy_loopback(bp, true);
msleep(1000);
if (bnxt_run_loopback(bp)) {
buf[BNXT_PHYLPBK_TEST_IDX] = 1;
etest->flags |= ETH_TEST_FL_FAILED;
}
bnxt_hwrm_phy_loopback(bp, false);
bnxt_half_close_nic(bp);
bnxt_open_nic(bp, false, true);
}
if (bnxt_test_irq(bp)) {
buf[BNXT_IRQ_TEST_IDX] = 1;
etest->flags |= ETH_TEST_FL_FAILED;
}
for (i = 0; i < bp->num_tests - BNXT_DRV_TESTS; i++) {
u8 bit_val = 1 << i;
if ((test_mask & bit_val) && !(test_results & bit_val)) {
buf[i] = 1;
etest->flags |= ETH_TEST_FL_FAILED;
}
}
}
#if defined(ETHTOOL_GET_TS_INFO) && defined(HAVE_IEEE1588_SUPPORT)
static int bnxt_get_ts_info(struct net_device *dev,
struct ethtool_ts_info *info)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_ptp_cfg *ptp;
ptp = bp->ptp_cfg;
info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
SOF_TIMESTAMPING_RX_SOFTWARE |
SOF_TIMESTAMPING_SOFTWARE;
info->phc_index = -1;
if (!ptp)
return 0;
info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
if (ptp->ptp_clock)
info->phc_index = ptp_clock_index(ptp->ptp_clock);
info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON);
info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
(1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT);
return 0;
}
#endif
void bnxt_ethtool_init(struct bnxt *bp)
{
struct hwrm_selftest_qlist_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_selftest_qlist_input req = {0};
struct bnxt_test_info *test_info;
int i, rc;
if (bp->hwrm_spec_code < 0x10704 || !BNXT_SINGLE_PF(bp))
return;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_SELFTEST_QLIST, -1, -1);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc)
goto ethtool_init_exit;
test_info = kzalloc(sizeof(*bp->test_info), GFP_KERNEL);
if (!test_info)
goto ethtool_init_exit;
bp->test_info = test_info;
bp->num_tests = resp->num_tests + BNXT_DRV_TESTS;
if (bp->num_tests > BNXT_MAX_TEST)
bp->num_tests = BNXT_MAX_TEST;
test_info->offline_mask = resp->offline_tests;
test_info->timeout = le16_to_cpu(resp->test_timeout);
if (!test_info->timeout)
test_info->timeout = HWRM_CMD_TIMEOUT;
for (i = 0; i < bp->num_tests; i++) {
char *str = test_info->string[i];
char *fw_str = resp->test0_name + i * 32;
if (i == BNXT_MACLPBK_TEST_IDX) {
strcpy(str, "Mac loopback test (offline)");
} else if (i == BNXT_PHYLPBK_TEST_IDX) {
strcpy(str, "Phy loopback test (offline)");
} else if (i == BNXT_IRQ_TEST_IDX) {
strcpy(str, "Interrupt_test (offline)");
} else {
strlcpy(str, fw_str, ETH_GSTRING_LEN);
strncat(str, " test", ETH_GSTRING_LEN - strlen(str));
if (test_info->offline_mask & (1 << i))
strncat(str, " (offline)",
ETH_GSTRING_LEN - strlen(str));
else
strncat(str, " (online)",
ETH_GSTRING_LEN - strlen(str));
}
}
ethtool_init_exit:
mutex_unlock(&bp->hwrm_cmd_lock);
}
void bnxt_ethtool_free(struct bnxt *bp)
{
kfree(bp->test_info);
bp->test_info = NULL;
}
const struct ethtool_ops bnxt_ethtool_ops = {
#ifdef HAVE_ETHTOOL_GLINKSETTINGS_25G
.get_link_ksettings = bnxt_get_link_ksettings,
.set_link_ksettings = bnxt_set_link_ksettings,
#else
.get_settings = bnxt_get_settings,
.set_settings = bnxt_set_settings,
#endif
.get_pauseparam = bnxt_get_pauseparam,
.set_pauseparam = bnxt_set_pauseparam,
.get_drvinfo = bnxt_get_drvinfo,
.get_wol = bnxt_get_wol,
.set_wol = bnxt_set_wol,
.get_coalesce = bnxt_get_coalesce,
.set_coalesce = bnxt_set_coalesce,
.get_msglevel = bnxt_get_msglevel,
.set_msglevel = bnxt_set_msglevel,
.get_sset_count = bnxt_get_sset_count,
.get_strings = bnxt_get_strings,
.get_ethtool_stats = bnxt_get_ethtool_stats,
.set_ringparam = bnxt_set_ringparam,
.get_ringparam = bnxt_get_ringparam,
#if defined(ETHTOOL_GCHANNELS) && !defined(GET_ETHTOOL_OP_EXT)
.get_channels = bnxt_get_channels,
.set_channels = bnxt_set_channels,
#endif
#ifdef HAVE_RXNFC
.get_rxnfc = bnxt_get_rxnfc,
.set_rxnfc = bnxt_set_rxnfc,
#endif
#if defined(HAVE_RXFH_INDIR_SIZE) && !defined(GET_ETHTOOL_OP_EXT)
.get_rxfh_indir_size = bnxt_get_rxfh_indir_size,
#endif
#if defined(HAVE_GET_RXFH_KEY_SIZE) && !defined(GET_ETHTOOL_OP_EXT)
.get_rxfh_key_size = bnxt_get_rxfh_key_size,
.get_rxfh = bnxt_get_rxfh,
#endif
#ifdef CONFIG_BNXT_FLASHDEV
.flash_device = bnxt_flash_device,
.get_eeprom_len = bnxt_get_eeprom_len,
.get_eeprom = bnxt_get_eeprom,
.set_eeprom = bnxt_set_eeprom,
#endif
.get_link = bnxt_get_link,
#if defined(ETHTOOL_GEEE) && !defined(GET_ETHTOOL_OP_EXT)
.get_eee = bnxt_get_eee,
.set_eee = bnxt_set_eee,
#endif
#if defined(ETHTOOL_GMODULEEEPROM) && !defined(GET_ETHTOOL_OP_EXT)
.get_module_info = bnxt_get_module_info,
.get_module_eeprom = bnxt_get_module_eeprom,
#endif
.nway_reset = bnxt_nway_reset,
#if defined(HAVE_SET_PHYS_ID) && !defined(GET_ETHTOOL_OP_EXT)
.set_phys_id = bnxt_set_phys_id,
#endif
.self_test = bnxt_self_test,
#if defined(ETHTOOL_GET_TS_INFO) && defined(HAVE_IEEE1588_SUPPORT)
.get_ts_info = bnxt_get_ts_info,
#endif
};
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2016 Broadcom Corporation
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#ifndef BNXT_ETHTOOL_H
#define BNXT_ETHTOOL_H
struct bnxt_led_cfg {
u8 led_id;
u8 led_state;
u8 led_color;
u8 unused;
__le16 led_blink_on;
__le16 led_blink_off;
u8 led_group_id;
u8 rsvd;
};
#define BNXT_LED_DFLT_ENA \
(PORT_LED_CFG_REQ_ENABLES_LED0_ID | \
PORT_LED_CFG_REQ_ENABLES_LED0_STATE | \
PORT_LED_CFG_REQ_ENABLES_LED0_BLINK_ON | \
PORT_LED_CFG_REQ_ENABLES_LED0_BLINK_OFF | \
PORT_LED_CFG_REQ_ENABLES_LED0_GROUP_ID)
#define BNXT_LED_DFLT_ENA_SHIFT 6
#define BNXT_LED_DFLT_ENABLES(x) \
cpu_to_le32(BNXT_LED_DFLT_ENA << (BNXT_LED_DFLT_ENA_SHIFT * (x)))
extern const struct ethtool_ops bnxt_ethtool_ops;
u32 _bnxt_fw_to_ethtool_adv_spds(u16, u8);
u32 bnxt_fw_to_ethtool_speed(u16);
u16 bnxt_get_fw_auto_link_speeds(u32);
void bnxt_ethtool_init(struct bnxt *bp);
void bnxt_ethtool_free(struct bnxt *bp);
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2016 Broadcom Corporation
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#ifndef __BNXT_FW_HDR_H__
#define __BNXT_FW_HDR_H__
#define BNXT_FIRMWARE_BIN_SIGNATURE 0x1a4d4342 /* "BCM"+0x1a */
#define BNXT_UCODE_TRAILER_SIGNATURE 0x726c7254 /* "Trlr" */
enum SUPPORTED_FAMILY {
DEVICE_5702_3_4_FAMILY, /* 0 - Denali, Vinson, K2 */
DEVICE_5705_FAMILY, /* 1 - Bachelor */
DEVICE_SHASTA_FAMILY, /* 2 - 5751 */
DEVICE_5706_FAMILY, /* 3 - Teton */
DEVICE_5714_FAMILY, /* 4 - Hamilton */
DEVICE_STANFORD_FAMILY, /* 5 - 5755 */
DEVICE_STANFORD_ME_FAMILY, /* 6 - 5756 */
DEVICE_SOLEDAD_FAMILY, /* 7 - 5761[E] */
DEVICE_CILAI_FAMILY, /* 8 - 57780/60/90/91 */
DEVICE_ASPEN_FAMILY, /* 9 - 57781/85/61/65/91/95 */
DEVICE_ASPEN_PLUS_FAMILY, /* 10 - 57786 */
DEVICE_LOGAN_FAMILY, /* 11 - Any device in the Logan family
*/
DEVICE_LOGAN_5762, /* 12 - Logan Enterprise (aka Columbia)
*/
DEVICE_LOGAN_57767, /* 13 - Logan Client */
DEVICE_LOGAN_57787, /* 14 - Logan Consumer */
DEVICE_LOGAN_5725, /* 15 - Logan Server (TruManage-enabled)
*/
DEVICE_SAWTOOTH_FAMILY, /* 16 - 5717/18 */
DEVICE_COTOPAXI_FAMILY, /* 17 - 5719 */
DEVICE_SNAGGLETOOTH_FAMILY, /* 18 - 5720 */
DEVICE_CUMULUS_FAMILY, /* 19 - Cumulus/Whitney */
MAX_DEVICE_FAMILY
};
enum SUPPORTED_CODE {
CODE_ASF1, /* 0 - ASF VERSION 1.03 <deprecated> */
CODE_ASF2, /* 1 - ASF VERSION 2.00 <deprecated> */
CODE_PASSTHRU, /* 2 - PassThru <deprecated> */
CODE_PT_SEC, /* 3 - PassThru with security <deprecated> */
CODE_UMP, /* 4 - UMP <deprecated> */
CODE_BOOT, /* 5 - Bootcode */
CODE_DASH, /* 6 - TruManage (DASH + ASF + PMCI)
* Management firmwares
*/
CODE_MCTP_PASSTHRU, /* 7 - NCSI / MCTP Passt-hrough firmware */
CODE_PM_OFFLOAD, /* 8 - Power-Management Proxy Offload firmwares
*/
CODE_MDNS_SD_OFFLOAD, /* 9 - Multicast DNS Service Discovery Proxys
* Offload firmware
*/
CODE_DISC_OFFLOAD, /* 10 - Discovery Offload firmware */
CODE_MUSTANG, /* 11 - I2C Error reporting APE firmwares
* <deprecated>
*/
CODE_ARP_BATCH, /* 12 - ARP Batch firmware */
CODE_SMASH, /* 13 - TruManage (SMASH + DCMI/IPMI + PMCI)
* Management firmware
*/
CODE_APE_DIAG, /* 14 - APE Test Diag firmware */
CODE_APE_PATCH, /* 15 - APE Patch firmware */
CODE_TANG_PATCH, /* 16 - TANG Patch firmware */
CODE_KONG_FW, /* 17 - KONG firmware */
CODE_KONG_PATCH, /* 18 - KONG Patch firmware */
CODE_BONO_FW, /* 19 - BONO firmware */
CODE_BONO_PATCH, /* 20 - BONO Patch firmware */
CODE_CHIMP_PATCH, /* 21 - ChiMP Patch firmware */
MAX_CODE_TYPE,
};
enum SUPPORTED_MEDIA {
MEDIA_COPPER, /* 0 */
MEDIA_FIBER, /* 1 */
MEDIA_NONE, /* 2 */
MEDIA_COPPER_FIBER, /* 3 */
MAX_MEDIA_TYPE,
};
struct bnxt_fw_header {
__le32 signature; /* constains the constant value of
* BNXT_FIRMWARE_BIN_SIGNATURE
*/
u8 flags; /* reserved for ChiMP use */
u8 code_type; /* enum SUPPORTED_CODE */
u8 device; /* enum SUPPORTED_FAMILY */
u8 media; /* enum SUPPORTED_MEDIA */
u8 version[16]; /* the null terminated version string to
* indicate the version of the
* file, this will be copied from the binary
* file version string
*/
u8 build;
u8 revision;
u8 minor_ver;
u8 major_ver;
};
/* Microcode and pre-boot software/firmware trailer: */
struct bnxt_ucode_trailer {
u8 rsa_sig[256];
__le16 flags;
u8 version_format;
u8 version_length;
u8 version[16];
__le16 dir_type;
__le16 trailer_length;
__le32 sig; /* BNXT_UCODE_TRAILER_SIGNATURE */
__le32 chksum; /* CRC-32 */
};
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2016 Broadcom Corporation
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#ifndef _BNXT_NVM_DEFS_H_
#define _BNXT_NVM_DEFS_H_
enum bnxt_nvm_directory_type {
BNX_DIR_TYPE_UNUSED = 0,
BNX_DIR_TYPE_PKG_LOG = 1,
BNX_DIR_TYPE_UPDATE = 2,
BNX_DIR_TYPE_CHIMP_PATCH = 3,
BNX_DIR_TYPE_BOOTCODE = 4,
BNX_DIR_TYPE_VPD = 5,
BNX_DIR_TYPE_EXP_ROM_MBA = 6,
BNX_DIR_TYPE_AVS = 7,
BNX_DIR_TYPE_PCIE = 8,
BNX_DIR_TYPE_PORT_MACRO = 9,
BNX_DIR_TYPE_APE_FW = 10,
BNX_DIR_TYPE_APE_PATCH = 11,
BNX_DIR_TYPE_KONG_FW = 12,
BNX_DIR_TYPE_KONG_PATCH = 13,
BNX_DIR_TYPE_BONO_FW = 14,
BNX_DIR_TYPE_BONO_PATCH = 15,
BNX_DIR_TYPE_TANG_FW = 16,
BNX_DIR_TYPE_TANG_PATCH = 17,
BNX_DIR_TYPE_BOOTCODE_2 = 18,
BNX_DIR_TYPE_CCM = 19,
BNX_DIR_TYPE_PCI_CFG = 20,
BNX_DIR_TYPE_TSCF_UCODE = 21,
BNX_DIR_TYPE_ISCSI_BOOT = 22,
BNX_DIR_TYPE_ISCSI_BOOT_IPV6 = 24,
BNX_DIR_TYPE_ISCSI_BOOT_IPV4N6 = 25,
BNX_DIR_TYPE_ISCSI_BOOT_CFG6 = 26,
BNX_DIR_TYPE_EXT_PHY = 27,
BNX_DIR_TYPE_SHARED_CFG = 40,
BNX_DIR_TYPE_PORT_CFG = 41,
BNX_DIR_TYPE_FUNC_CFG = 42,
BNX_DIR_TYPE_MGMT_CFG = 48,
BNX_DIR_TYPE_MGMT_DATA = 49,
BNX_DIR_TYPE_MGMT_WEB_DATA = 50,
BNX_DIR_TYPE_MGMT_WEB_META = 51,
BNX_DIR_TYPE_MGMT_EVENT_LOG = 52,
BNX_DIR_TYPE_MGMT_AUDIT_LOG = 53
};
#define BNX_DIR_ORDINAL_FIRST 0
#define BNX_DIR_EXT_NONE 0
#define BNX_DIR_EXT_INACTIVE (1 << 0)
#define BNX_DIR_EXT_UPDATE (1 << 1)
#define BNX_DIR_ATTR_NONE 0
#define BNX_DIR_ATTR_NO_CHKSUM (1 << 0)
#define BNX_DIR_ATTR_PROP_STREAM (1 << 1)
#define BNX_PKG_LOG_MAX_LENGTH 4096
enum bnxnvm_pkglog_field_index {
BNX_PKG_LOG_FIELD_IDX_INSTALLED_TIMESTAMP = 0,
BNX_PKG_LOG_FIELD_IDX_PKG_DESCRIPTION = 1,
BNX_PKG_LOG_FIELD_IDX_PKG_VERSION = 2,
BNX_PKG_LOG_FIELD_IDX_PKG_TIMESTAMP = 3,
BNX_PKG_LOG_FIELD_IDX_PKG_CHECKSUM = 4,
BNX_PKG_LOG_FIELD_IDX_INSTALLED_ITEMS = 5,
BNX_PKG_LOG_FIELD_IDX_INSTALLED_MASK = 6
};
#endif /* Don't add anything after this line */
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2017 Broadcom Limited
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#ifdef HAVE_IEEE1588_SUPPORT
#include <linux/ptp_clock_kernel.h>
#include <linux/net_tstamp.h>
#include <linux/timecounter.h>
#include <linux/timekeeping.h>
#endif
#include "bnxt_compat.h"
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_ptp.h"
#ifdef HAVE_IEEE1588_SUPPORT
static int bnxt_ptp_settime(struct ptp_clock_info *ptp_info,
const struct timespec64 *ts)
{
struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
ptp_info);
u64 ns = timespec64_to_ns(ts);
ns = timespec64_to_ns(ts);
timecounter_init(&ptp->tc, &ptp->cc, ns);
return 0;
}
static int bnxt_ptp_gettime(struct ptp_clock_info *ptp_info,
struct timespec64 *ts)
{
struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
ptp_info);
u64 ns;
ns = timecounter_read(&ptp->tc);
*ts = ns_to_timespec64(ns);
return 0;
}
static int bnxt_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
{
struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
ptp_info);
timecounter_adjtime(&ptp->tc, delta);
return 0;
}
static int bnxt_ptp_adjfreq(struct ptp_clock_info *ptp_info, s32 ppb)
{
struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
ptp_info);
s32 period, period1, period2, dif, dif1, dif2;
s32 step, best_step = 0, best_period = 0;
s32 best_dif = BNXT_MAX_PHC_DRIFT;
u32 drift_sign = 1;
/* Frequency adjustment requires programming 3 values:
* 1-bit direction
* 5-bit adjustment step in 1 ns unit
* 24-bit period in 1 us unit between adjustments
*/
if (ppb < 0) {
ppb = -ppb;
drift_sign = 0;
}
if (ppb == 0) {
/* no adjustment */
best_step = 0;
best_period = 0xFFFFFF;
} else if (ppb >= BNXT_MAX_PHC_DRIFT) {
/* max possible adjustment */
best_step = 31;
best_period = 1;
} else {
/* Find the best possible adjustment step and period */
for (step = 0; step <= 31; step++) {
period1 = step * 1000000 / ppb;
period2 = period1 + 1;
if (period1 != 0)
dif1 = ppb - (step * 1000000 / period1);
else
dif1 = BNXT_MAX_PHC_DRIFT;
if (dif1 < 0)
dif1 = -dif1;
dif2 = ppb - (step * 1000000 / period2);
if (dif2 < 0)
dif2 = -dif2;
dif = (dif1 < dif2) ? dif1 : dif2;
period = (dif1 < dif2) ? period1 : period2;
if (dif < best_dif) {
best_dif = dif;
best_step = step;
best_period = period;
}
}
}
writel((drift_sign << BNXT_GRCPF_REG_SYNC_TIME_ADJ_SIGN_SFT) |
(best_step << BNXT_GRCPF_REG_SYNC_TIME_ADJ_VAL_SFT) |
(best_period & BNXT_GRCPF_REG_SYNC_TIME_ADJ_PER_MSK),
ptp->bp->bar0 + BNXT_GRCPF_REG_SYNC_TIME_ADJ);
return 0;
}
static int bnxt_ptp_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on)
{
return -ENOTSUPP;
}
static void bnxt_clr_rx_ts(struct bnxt *bp)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
struct bnxt_pf_info *pf = &bp->pf;
u16 port_id;
int i = 0;
u32 fifo;
if (!ptp)
return;
port_id = pf->port_id;
fifo = readl(bp->bar0 + ptp->rx_mapped_regs[BNXT_PTP_RX_FIFO]);
while ((fifo & BNXT_PTP_RX_FIFO_PENDING) && (i < 10)) {
writel(1 << port_id, bp->bar0 +
ptp->rx_mapped_regs[BNXT_PTP_RX_FIFO_ADV]);
fifo = readl(bp->bar0 + ptp->rx_mapped_regs[BNXT_PTP_RX_FIFO]);
i++;
}
}
static int bnxt_hwrm_ptp_cfg(struct bnxt *bp)
{
struct hwrm_port_mac_cfg_input req = {0};
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
u32 flags = 0;
if (!ptp)
return 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_MAC_CFG, -1, -1);
if (ptp->rx_filter)
flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_RX_TS_CAPTURE_ENABLE;
else
flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_RX_TS_CAPTURE_DISABLE;
if (ptp->tx_tstamp_en)
flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_TX_TS_CAPTURE_ENABLE;
else
flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_TX_TS_CAPTURE_DISABLE;
req.flags = cpu_to_le32(flags);
req.enables = cpu_to_le32(
PORT_MAC_CFG_REQ_ENABLES_RX_TS_CAPTURE_PTP_MSG_TYPE);
req.rx_ts_capture_ptp_msg_type = cpu_to_le16(ptp->rxctl);
if (hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT))
return -EIO;
return 0;
}
int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
{
struct bnxt *bp = netdev_priv(dev);
struct hwtstamp_config stmpconf;
struct bnxt_ptp_cfg *ptp;
u16 old_rxctl, new_rxctl;
int old_rx_filter, rc;
u8 old_tx_tstamp_en;
ptp = bp->ptp_cfg;
if (!ptp)
return -EOPNOTSUPP;
if (copy_from_user(&stmpconf, ifr->ifr_data, sizeof(stmpconf)))
return -EFAULT;
if (stmpconf.flags)
return -EINVAL;
if (stmpconf.tx_type != HWTSTAMP_TX_ON &&
stmpconf.tx_type != HWTSTAMP_TX_OFF)
return -ERANGE;
old_rx_filter = ptp->rx_filter;
old_rxctl = ptp->rxctl;
old_tx_tstamp_en = ptp->tx_tstamp_en;
switch (stmpconf.rx_filter) {
case HWTSTAMP_FILTER_NONE:
new_rxctl = 0;
ptp->rx_filter = HWTSTAMP_FILTER_NONE;
break;
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
new_rxctl = BNXT_PTP_MSG_EVENTS;
ptp->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
new_rxctl = BNXT_PTP_MSG_SYNC;
ptp->rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC;
break;
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
new_rxctl = BNXT_PTP_MSG_DELAY_REQ;
ptp->rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ;
break;
default:
return -ERANGE;
}
if (stmpconf.tx_type == HWTSTAMP_TX_ON)
ptp->tx_tstamp_en = 1;
else
ptp->tx_tstamp_en = 0;
if (!old_rxctl && new_rxctl) {
rc = bnxt_hwrm_ptp_cfg(bp);
if (rc)
goto ts_set_err;
ptp->rxctl = new_rxctl;
bnxt_clr_rx_ts(bp);
}
rc = bnxt_hwrm_ptp_cfg(bp);
if (rc)
goto ts_set_err;
stmpconf.rx_filter = ptp->rx_filter;
return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ?
-EFAULT : 0;
ts_set_err:
ptp->rx_filter = old_rx_filter;
ptp->rxctl = old_rxctl;
ptp->tx_tstamp_en = old_tx_tstamp_en;
return rc;
}
int bnxt_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
{
struct bnxt *bp = netdev_priv(dev);
struct hwtstamp_config stmpconf;
struct bnxt_ptp_cfg *ptp;
ptp = bp->ptp_cfg;
if (!ptp)
return -EOPNOTSUPP;
stmpconf.flags = 0;
stmpconf.tx_type = ptp->tx_tstamp_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
stmpconf.rx_filter = ptp->rx_filter;
return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ?
-EFAULT : 0;
}
static int bnxt_map_regs(struct bnxt *bp, u32 *reg_arr, int count, int reg_win)
{
u32 reg_base = *reg_arr & 0xfffff000;
u32 win_off;
int i;
for (i = 0; i < count; i++) {
if ((reg_arr[i] & 0xfffff000) != reg_base)
return -ERANGE;
}
win_off = BNXT_GRCPF_REG_WINDOW_BASE_OUT + (reg_win - 1) * 4;
writel(reg_base, bp->bar0 + win_off);
return 0;
}
static int bnxt_map_ptp_regs(struct bnxt *bp)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
u32 *reg_arr, reg_base;
int rc, i;
reg_arr = ptp->rx_regs;
rc = bnxt_map_regs(bp, reg_arr, BNXT_PTP_RX_REGS, 5);
if (rc)
return rc;
reg_arr = ptp->tx_regs;
rc = bnxt_map_regs(bp, reg_arr, BNXT_PTP_TX_REGS, 6);
if (rc)
return rc;
reg_base = ptp->rx_regs[BNXT_PTP_RX_TS_L] & 0xfffff000;
for (i = 0; i < BNXT_PTP_RX_REGS; i++)
ptp->rx_mapped_regs[i] = 0x5000 + (ptp->rx_regs[i] & 0xfff);
reg_base = ptp->tx_regs[BNXT_PTP_TX_TS_L] & 0xfffff000;
for (i = 0; i < BNXT_PTP_TX_REGS; i++)
ptp->tx_mapped_regs[i] = 0x6000 + (ptp->tx_regs[i] & 0xfff);
return 0;
}
static void bnxt_unmap_ptp_regs(struct bnxt *bp)
{
writel(0, bp->bar0 + BNXT_GRCPF_REG_WINDOW_BASE_OUT + 16);
writel(0, bp->bar0 + BNXT_GRCPF_REG_WINDOW_BASE_OUT + 20);
}
static u64 bnxt_cc_read(const struct cyclecounter *cc)
{
struct bnxt_ptp_cfg *ptp = container_of(cc, struct bnxt_ptp_cfg, cc);
struct bnxt *bp = ptp->bp;
u64 ns;
ns = readl(bp->bar0 + BNXT_GRCPF_REG_SYNC_TIME);
ns |= (u64)readl(bp->bar0 + BNXT_GRCPF_REG_SYNC_TIME + 4) << 32;
return ns;
}
int bnxt_get_tx_ts(struct bnxt *bp, u64 *ts)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
u32 fifo;
fifo = readl(bp->bar0 + ptp->tx_mapped_regs[BNXT_PTP_TX_FIFO]);
if (fifo & BNXT_PTP_TX_FIFO_EMPTY)
return -EAGAIN;
fifo = readl(bp->bar0 + ptp->tx_mapped_regs[BNXT_PTP_TX_FIFO]);
*ts = readl(bp->bar0 + ptp->tx_mapped_regs[BNXT_PTP_TX_TS_L]);
*ts |= (u64)readl(bp->bar0 + ptp->tx_mapped_regs[BNXT_PTP_TX_TS_H]) <<
32;
readl(bp->bar0 + ptp->tx_mapped_regs[BNXT_PTP_TX_SEQ]);
return 0;
}
int bnxt_get_rx_ts(struct bnxt *bp, u64 *ts)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
struct bnxt_pf_info *pf = &bp->pf;
u16 port_id;
u32 fifo;
if (!ptp)
return -ENODEV;
fifo = readl(bp->bar0 + ptp->rx_mapped_regs[BNXT_PTP_RX_FIFO]);
if (!(fifo & BNXT_PTP_RX_FIFO_PENDING))
return -EAGAIN;
port_id = pf->port_id;
writel(1 << port_id, bp->bar0 +
ptp->rx_mapped_regs[BNXT_PTP_RX_FIFO_ADV]);
fifo = readl(bp->bar0 + ptp->rx_mapped_regs[BNXT_PTP_RX_FIFO]);
if (fifo & BNXT_PTP_RX_FIFO_PENDING) {
bnxt_clr_rx_ts(bp);
return -EBUSY;
}
*ts = readl(bp->bar0 + ptp->rx_mapped_regs[BNXT_PTP_RX_TS_L]);
*ts |= (u64)readl(bp->bar0 + ptp->rx_mapped_regs[BNXT_PTP_RX_TS_H]) <<
32;
return 0;
}
static const struct ptp_clock_info bnxt_ptp_caps = {
.owner = THIS_MODULE,
.name = "bnxt clock",
.max_adj = BNXT_MAX_PHC_DRIFT,
.n_alarm = 0,
.n_ext_ts = 0,
.n_per_out = 1,
.n_pins = 0,
.pps = 0,
.adjfreq = bnxt_ptp_adjfreq,
.adjtime = bnxt_ptp_adjtime,
.gettime64 = bnxt_ptp_gettime,
.settime64 = bnxt_ptp_settime,
.enable = bnxt_ptp_enable,
};
int bnxt_ptp_init(struct bnxt *bp)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
int rc;
if (!ptp)
return 0;
rc = bnxt_map_ptp_regs(bp);
if (rc)
return rc;
atomic_set(&ptp->tx_avail, BNXT_MAX_TX_TS);
memset(&ptp->cc, 0, sizeof(ptp->cc));
ptp->cc.read = bnxt_cc_read;
ptp->cc.mask = CYCLECOUNTER_MASK(64);
ptp->cc.shift = 0;
ptp->cc.mult = 1;
timecounter_init(&ptp->tc, &ptp->cc, ktime_to_ns(ktime_get_real()));
ptp->ptp_info = bnxt_ptp_caps;
ptp->ptp_clock = ptp_clock_register(&ptp->ptp_info, &bp->pdev->dev);
if (IS_ERR(ptp->ptp_clock))
ptp->ptp_clock = NULL;
return 0;
}
void bnxt_ptp_free(struct bnxt *bp)
{
struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
if (!ptp)
return;
if (ptp->ptp_clock)
ptp_clock_unregister(ptp->ptp_clock);
ptp->ptp_clock = NULL;
bnxt_unmap_ptp_regs(bp);
}
#else
int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
{
return -EOPNOTSUPP;
}
int bnxt_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
{
return -EOPNOTSUPP;
}
int bnxt_ptp_init(struct bnxt *bp)
{
return 0;
}
void bnxt_ptp_free(struct bnxt *bp)
{
return;
}
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2017 Broadcom Limited
*
* 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.
*/
#ifndef BNXT_PTP_H
#define BNXT_PTP_H
#define BNXT_MAX_PHC_DRIFT 31000000
struct bnxt_ptp_cfg {
#ifdef HAVE_IEEE1588_SUPPORT
struct ptp_clock_info ptp_info;
struct ptp_clock *ptp_clock;
struct cyclecounter cc;
struct timecounter tc;
#endif
struct bnxt *bp;
atomic_t tx_avail;
#define BNXT_MAX_TX_TS 1
u16 rxctl;
#define BNXT_PTP_MSG_SYNC (1 << 0)
#define BNXT_PTP_MSG_DELAY_REQ (1 << 1)
#define BNXT_PTP_MSG_PDELAY_REQ (1 << 2)
#define BNXT_PTP_MSG_PDELAY_RESP (1 << 3)
#define BNXT_PTP_MSG_FOLLOW_UP (1 << 8)
#define BNXT_PTP_MSG_DELAY_RESP (1 << 9)
#define BNXT_PTP_MSG_PDELAY_RESP_FOLLOW_UP (1 << 10)
#define BNXT_PTP_MSG_ANNOUNCE (1 << 11)
#define BNXT_PTP_MSG_SIGNALING (1 << 12)
#define BNXT_PTP_MSG_MANAGEMENT (1 << 13)
#define BNXT_PTP_MSG_EVENTS (BNXT_PTP_MSG_SYNC | \
BNXT_PTP_MSG_DELAY_REQ | \
BNXT_PTP_MSG_PDELAY_REQ | \
BNXT_PTP_MSG_PDELAY_RESP)
u8 tx_tstamp_en:1;
int rx_filter;
#define BNXT_PTP_RX_TS_L 0
#define BNXT_PTP_RX_TS_H 1
#define BNXT_PTP_RX_SEQ 2
#define BNXT_PTP_RX_FIFO 3
#define BNXT_PTP_RX_FIFO_PENDING 0x1
#define BNXT_PTP_RX_FIFO_ADV 4
#define BNXT_PTP_RX_REGS 5
#define BNXT_PTP_TX_TS_L 0
#define BNXT_PTP_TX_TS_H 1
#define BNXT_PTP_TX_SEQ 2
#define BNXT_PTP_TX_FIFO 3
#define BNXT_PTP_TX_FIFO_EMPTY 0x2
#define BNXT_PTP_TX_REGS 4
u32 rx_regs[BNXT_PTP_RX_REGS];
u32 rx_mapped_regs[BNXT_PTP_RX_REGS];
u32 tx_regs[BNXT_PTP_TX_REGS];
u32 tx_mapped_regs[BNXT_PTP_TX_REGS];
};
int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr);
int bnxt_hwtstamp_get(struct net_device *dev, struct ifreq *ifr);
int bnxt_get_tx_ts(struct bnxt *bp, u64 *ts);
int bnxt_get_rx_ts(struct bnxt *bp, u64 *ts);
int bnxt_ptp_init(struct bnxt *bp);
void bnxt_ptp_free(struct bnxt *bp);
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2016 Broadcom Corporation
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
#include <linux/rtnetlink.h>
#include <linux/interrupt.h>
#include <linux/etherdevice.h>
#include "bnxt_compat.h"
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_ulp.h"
#include "bnxt_sriov.h"
#include "bnxt_ethtool.h"
#ifdef CONFIG_BNXT_SRIOV
static int bnxt_hwrm_fwd_async_event_cmpl(struct bnxt *bp,
struct bnxt_vf_info *vf,
u16 event_id)
{
int rc = 0;
struct hwrm_fwd_async_event_cmpl_input req = {0};
struct hwrm_fwd_async_event_cmpl_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_async_event_cmpl *async_cmpl;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FWD_ASYNC_EVENT_CMPL, -1, -1);
if (vf)
req.encap_async_event_target_id = cpu_to_le16(vf->fw_fid);
else
/* broadcast this async event to all VFs */
req.encap_async_event_target_id = cpu_to_le16(0xffff);
async_cmpl = (struct hwrm_async_event_cmpl *)req.encap_async_event_cmpl;
async_cmpl->type = cpu_to_le16(ASYNC_EVENT_CMPL_TYPE_HWRM_ASYNC_EVENT);
async_cmpl->event_id = cpu_to_le16(event_id);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc) {
netdev_err(bp->dev, "hwrm_fwd_async_event_cmpl failed. rc:%d\n",
rc);
goto fwd_async_event_cmpl_exit;
}
if (resp->error_code) {
netdev_err(bp->dev, "hwrm_fwd_async_event_cmpl error %d\n",
resp->error_code);
rc = -1;
}
fwd_async_event_cmpl_exit:
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
#ifdef HAVE_NDO_GET_VF_CONFIG
static int bnxt_vf_ndo_prep(struct bnxt *bp, int vf_id)
{
if (!test_bit(BNXT_STATE_OPEN, &bp->state)) {
netdev_err(bp->dev, "vf ndo called though PF is down\n");
return -EINVAL;
}
if (!bp->pf.active_vfs) {
netdev_err(bp->dev, "vf ndo called though sriov is disabled\n");
return -EINVAL;
}
if (vf_id >= bp->pf.max_vfs) {
netdev_err(bp->dev, "Invalid VF id %d\n", vf_id);
return -EINVAL;
}
return 0;
}
#ifdef HAVE_VF_SPOOFCHK
int bnxt_set_vf_spoofchk(struct net_device *dev, int vf_id, bool setting)
{
struct hwrm_func_cfg_input req = {0};
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vf_info *vf;
bool old_setting = false;
u32 func_flags;
int rc;
if (bp->hwrm_spec_code < 0x10701)
return -ENOTSUPP;
rc = bnxt_vf_ndo_prep(bp, vf_id);
if (rc)
return rc;
vf = &bp->pf.vf[vf_id];
if (vf->flags & BNXT_VF_SPOOFCHK)
old_setting = true;
if (old_setting == setting)
return 0;
if (setting)
func_flags = FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_ENABLE;
else
func_flags = FUNC_CFG_REQ_FLAGS_SRC_MAC_ADDR_CHECK_DISABLE;
/*TODO: if the driver supports VLAN filter on guest VLAN,
* the spoof check should also include vlan anti-spoofing
*/
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
req.fid = cpu_to_le16(vf->fw_fid);
req.flags = cpu_to_le32(func_flags);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc) {
vf->func_flags = func_flags;
if (setting)
vf->flags |= BNXT_VF_SPOOFCHK;
else
vf->flags &= ~BNXT_VF_SPOOFCHK;
}
return rc;
}
#endif
int bnxt_get_vf_config(struct net_device *dev, int vf_id,
struct ifla_vf_info *ivi)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vf_info *vf;
int rc;
rc = bnxt_vf_ndo_prep(bp, vf_id);
if (rc)
return rc;
ivi->vf = vf_id;
vf = &bp->pf.vf[vf_id];
memcpy(&ivi->mac, vf->mac_addr, ETH_ALEN);
#ifdef HAVE_IFLA_TX_RATE
ivi->max_tx_rate = vf->max_tx_rate;
ivi->min_tx_rate = vf->min_tx_rate;
#else
ivi->tx_rate = vf->max_tx_rate;
#endif
ivi->vlan = vf->vlan;
if (vf->flags & BNXT_VF_QOS)
ivi->qos = vf->vlan >> VLAN_PRIO_SHIFT;
else
ivi->qos = 0;
#ifdef HAVE_VF_SPOOFCHK
ivi->spoofchk = !!(vf->flags & BNXT_VF_SPOOFCHK);
#endif
#ifdef HAVE_NDO_SET_VF_LINK_STATE
if (!(vf->flags & BNXT_VF_LINK_FORCED))
ivi->linkstate = IFLA_VF_LINK_STATE_AUTO;
else if (vf->flags & BNXT_VF_LINK_UP)
ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE;
else
ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE;
#endif
return 0;
}
int bnxt_set_vf_mac(struct net_device *dev, int vf_id, u8 *mac)
{
struct hwrm_func_cfg_input req = {0};
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vf_info *vf;
int rc;
rc = bnxt_vf_ndo_prep(bp, vf_id);
if (rc)
return rc;
/* reject bc or mc mac addr, zero mac addr means allow
* VF to use its own mac addr
*/
if (is_multicast_ether_addr(mac)) {
netdev_err(dev, "Invalid VF ethernet address\n");
return -EINVAL;
}
vf = &bp->pf.vf[vf_id];
memcpy(vf->mac_addr, mac, ETH_ALEN);
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
req.fid = cpu_to_le16(vf->fw_fid);
req.flags = cpu_to_le32(vf->func_flags);
req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_MAC_ADDR);
memcpy(req.dflt_mac_addr, mac, ETH_ALEN);
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
#ifdef NEW_NDO_SET_VF_VLAN
int bnxt_set_vf_vlan(struct net_device *dev, int vf_id, u16 vlan_id, u8 qos,
__be16 vlan_proto)
#else
int bnxt_set_vf_vlan(struct net_device *dev, int vf_id, u16 vlan_id, u8 qos)
#endif
{
struct hwrm_func_cfg_input req = {0};
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vf_info *vf;
u16 vlan_tag;
int rc;
if (bp->hwrm_spec_code < 0x10201)
return -ENOTSUPP;
#ifdef NEW_NDO_SET_VF_VLAN
if (vlan_proto != htons(ETH_P_8021Q))
return -EPROTONOSUPPORT;
#endif
rc = bnxt_vf_ndo_prep(bp, vf_id);
if (rc)
return rc;
/* TODO: needed to implement proper handling of user priority,
* currently fail the command if there is valid priority
*/
if (vlan_id > 4095 || qos)
return -EINVAL;
vf = &bp->pf.vf[vf_id];
vlan_tag = vlan_id;
if (vlan_tag == vf->vlan)
return 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
req.fid = cpu_to_le16(vf->fw_fid);
req.flags = cpu_to_le32(vf->func_flags);
req.dflt_vlan = cpu_to_le16(vlan_tag);
req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_DFLT_VLAN);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc)
vf->vlan = vlan_tag;
return rc;
}
#ifdef HAVE_IFLA_TX_RATE
int bnxt_set_vf_bw(struct net_device *dev, int vf_id, int min_tx_rate,
int max_tx_rate)
#else
int bnxt_set_vf_bw(struct net_device *dev, int vf_id, int max_tx_rate)
#endif
{
struct hwrm_func_cfg_input req = {0};
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vf_info *vf;
u32 pf_link_speed;
int rc;
rc = bnxt_vf_ndo_prep(bp, vf_id);
if (rc)
return rc;
vf = &bp->pf.vf[vf_id];
pf_link_speed = bnxt_fw_to_ethtool_speed(bp->link_info.link_speed);
if (max_tx_rate > pf_link_speed) {
netdev_info(bp->dev, "max tx rate %d exceed PF link speed for VF %d\n",
max_tx_rate, vf_id);
return -EINVAL;
}
#ifdef HAVE_IFLA_TX_RATE
if (min_tx_rate > pf_link_speed || min_tx_rate > max_tx_rate) {
netdev_info(bp->dev, "min tx rate %d is invalid for VF %d\n",
min_tx_rate, vf_id);
return -EINVAL;
}
if (min_tx_rate == vf->min_tx_rate && max_tx_rate == vf->max_tx_rate)
return 0;
#else
if (max_tx_rate == vf->max_tx_rate)
return 0;
#endif
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
req.fid = cpu_to_le16(vf->fw_fid);
req.flags = cpu_to_le32(vf->func_flags);
req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_MAX_BW);
req.max_bw = cpu_to_le32(max_tx_rate);
#ifdef HAVE_IFLA_TX_RATE
req.enables |= cpu_to_le32(FUNC_CFG_REQ_ENABLES_MIN_BW);
req.min_bw = cpu_to_le32(min_tx_rate);
#endif
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc) {
#ifdef HAVE_IFLA_TX_RATE
vf->min_tx_rate = min_tx_rate;
#endif
vf->max_tx_rate = max_tx_rate;
}
return rc;
}
#ifdef HAVE_NDO_SET_VF_LINK_STATE
int bnxt_set_vf_link_state(struct net_device *dev, int vf_id, int link)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_vf_info *vf;
int rc;
rc = bnxt_vf_ndo_prep(bp, vf_id);
if (rc)
return rc;
vf = &bp->pf.vf[vf_id];
vf->flags &= ~(BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED);
switch (link) {
case IFLA_VF_LINK_STATE_AUTO:
vf->flags |= BNXT_VF_LINK_UP;
break;
case IFLA_VF_LINK_STATE_DISABLE:
vf->flags |= BNXT_VF_LINK_FORCED;
break;
case IFLA_VF_LINK_STATE_ENABLE:
vf->flags |= BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED;
break;
default:
netdev_err(bp->dev, "Invalid link option\n");
rc = -EINVAL;
break;
}
if (vf->flags & (BNXT_VF_LINK_UP | BNXT_VF_LINK_FORCED))
rc = bnxt_hwrm_fwd_async_event_cmpl(bp, vf,
ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE);
return rc;
}
#endif
#endif
static int bnxt_set_vf_attr(struct bnxt *bp, int num_vfs)
{
int i;
struct bnxt_vf_info *vf;
for (i = 0; i < num_vfs; i++) {
vf = &bp->pf.vf[i];
memset(vf, 0, sizeof(*vf));
}
return 0;
}
static int bnxt_hwrm_func_vf_resource_free(struct bnxt *bp, int num_vfs)
{
int i, rc = 0;
struct bnxt_pf_info *pf = &bp->pf;
struct hwrm_func_vf_resc_free_input req = {0};
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_RESC_FREE, -1, -1);
mutex_lock(&bp->hwrm_cmd_lock);
for (i = pf->first_vf_id; i < pf->first_vf_id + num_vfs; i++) {
req.vf_id = cpu_to_le16(i);
rc = _hwrm_send_message(bp, &req, sizeof(req),
HWRM_CMD_TIMEOUT);
if (rc)
break;
}
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static void bnxt_free_vf_resources(struct bnxt *bp)
{
struct pci_dev *pdev = bp->pdev;
int i;
kfree(bp->pf.vf_event_bmap);
bp->pf.vf_event_bmap = NULL;
for (i = 0; i < 4; i++) {
if (bp->pf.hwrm_cmd_req_addr[i]) {
dma_free_coherent(&pdev->dev, BNXT_PAGE_SIZE,
bp->pf.hwrm_cmd_req_addr[i],
bp->pf.hwrm_cmd_req_dma_addr[i]);
bp->pf.hwrm_cmd_req_addr[i] = NULL;
}
}
kfree(bp->pf.vf);
bp->pf.vf = NULL;
}
static int bnxt_alloc_vf_resources(struct bnxt *bp, int num_vfs)
{
struct pci_dev *pdev = bp->pdev;
u32 nr_pages, size, i, j, k = 0;
bp->pf.vf = kcalloc(num_vfs, sizeof(struct bnxt_vf_info), GFP_KERNEL);
if (!bp->pf.vf)
return -ENOMEM;
bnxt_set_vf_attr(bp, num_vfs);
size = num_vfs * BNXT_HWRM_REQ_MAX_SIZE;
nr_pages = size / BNXT_PAGE_SIZE;
if (size & (BNXT_PAGE_SIZE - 1))
nr_pages++;
for (i = 0; i < nr_pages; i++) {
bp->pf.hwrm_cmd_req_addr[i] =
dma_alloc_coherent(&pdev->dev, BNXT_PAGE_SIZE,
&bp->pf.hwrm_cmd_req_dma_addr[i],
GFP_KERNEL);
if (!bp->pf.hwrm_cmd_req_addr[i])
return -ENOMEM;
for (j = 0; j < BNXT_HWRM_REQS_PER_PAGE && k < num_vfs; j++) {
struct bnxt_vf_info *vf = &bp->pf.vf[k];
vf->hwrm_cmd_req_addr = bp->pf.hwrm_cmd_req_addr[i] +
j * BNXT_HWRM_REQ_MAX_SIZE;
vf->hwrm_cmd_req_dma_addr =
bp->pf.hwrm_cmd_req_dma_addr[i] + j *
BNXT_HWRM_REQ_MAX_SIZE;
k++;
}
}
/* Max 128 VF's */
bp->pf.vf_event_bmap = kzalloc(16, GFP_KERNEL);
if (!bp->pf.vf_event_bmap)
return -ENOMEM;
bp->pf.hwrm_cmd_req_pages = nr_pages;
return 0;
}
static int bnxt_hwrm_func_buf_rgtr(struct bnxt *bp)
{
struct hwrm_func_buf_rgtr_input req = {0};
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_BUF_RGTR, -1, -1);
req.req_buf_num_pages = cpu_to_le16(bp->pf.hwrm_cmd_req_pages);
req.req_buf_page_size = cpu_to_le16(BNXT_PAGE_SHIFT);
req.req_buf_len = cpu_to_le16(BNXT_HWRM_REQ_MAX_SIZE);
req.req_buf_page_addr0 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[0]);
req.req_buf_page_addr1 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[1]);
req.req_buf_page_addr2 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[2]);
req.req_buf_page_addr3 = cpu_to_le64(bp->pf.hwrm_cmd_req_dma_addr[3]);
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
/* only call by PF to reserve resources for VF */
static int bnxt_hwrm_func_cfg(struct bnxt *bp, int num_vfs)
{
u32 rc = 0, mtu, i;
u16 vf_tx_rings, vf_rx_rings, vf_cp_rings, vf_stat_ctx, vf_vnics;
u16 vf_ring_grps, max_stat_ctxs;
struct hwrm_func_cfg_input req = {0};
struct bnxt_pf_info *pf = &bp->pf;
int total_vf_tx_rings = 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
max_stat_ctxs = pf->max_stat_ctxs;
/* Remaining rings are distributed equally amongs VF's for now */
vf_cp_rings = (pf->max_cp_rings - bp->cp_nr_rings) / num_vfs;
vf_stat_ctx = (max_stat_ctxs - bp->num_stat_ctxs) / num_vfs;
if (bp->flags & BNXT_FLAG_AGG_RINGS)
vf_rx_rings = (pf->max_rx_rings - bp->rx_nr_rings * 2) /
num_vfs;
else
vf_rx_rings = (pf->max_rx_rings - bp->rx_nr_rings) / num_vfs;
vf_ring_grps = (bp->pf.max_hw_ring_grps - bp->rx_nr_rings) / num_vfs;
vf_tx_rings = (pf->max_tx_rings - bp->tx_nr_rings) / num_vfs;
vf_vnics = (pf->max_vnics - bp->nr_vnics) / num_vfs;
vf_vnics = min_t(u16, vf_vnics, vf_rx_rings);
req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_MTU |
FUNC_CFG_REQ_ENABLES_MRU |
FUNC_CFG_REQ_ENABLES_NUM_RSSCOS_CTXS |
FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS |
FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS |
FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS |
FUNC_CFG_REQ_ENABLES_NUM_L2_CTXS |
FUNC_CFG_REQ_ENABLES_NUM_VNICS |
FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS);
mtu = bp->dev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
req.mru = cpu_to_le16(mtu);
req.mtu = cpu_to_le16(mtu);
req.num_rsscos_ctxs = cpu_to_le16(1);
req.num_cmpl_rings = cpu_to_le16(vf_cp_rings);
req.num_tx_rings = cpu_to_le16(vf_tx_rings);
req.num_rx_rings = cpu_to_le16(vf_rx_rings);
req.num_hw_ring_grps = cpu_to_le16(vf_ring_grps);
req.num_l2_ctxs = cpu_to_le16(4);
req.num_vnics = cpu_to_le16(vf_vnics);
/* FIXME spec currently uses 1 bit for stats ctx */
req.num_stat_ctxs = cpu_to_le16(vf_stat_ctx);
mutex_lock(&bp->hwrm_cmd_lock);
for (i = 0; i < num_vfs; i++) {
int vf_tx_rsvd = vf_tx_rings;
req.fid = cpu_to_le16(pf->first_vf_id + i);
rc = _hwrm_send_message(bp, &req, sizeof(req),
HWRM_CMD_TIMEOUT);
if (rc)
break;
pf->active_vfs = i + 1;
pf->vf[i].fw_fid = le16_to_cpu(req.fid);
rc = __bnxt_hwrm_get_tx_rings(bp, pf->vf[i].fw_fid,
&vf_tx_rsvd);
if (rc)
break;
total_vf_tx_rings += vf_tx_rsvd;
}
mutex_unlock(&bp->hwrm_cmd_lock);
if (!rc) {
pf->max_tx_rings -= total_vf_tx_rings;
pf->max_rx_rings -= vf_rx_rings * num_vfs;
pf->max_hw_ring_grps -= vf_ring_grps * num_vfs;
pf->max_cp_rings -= vf_cp_rings * num_vfs;
pf->max_rsscos_ctxs -= num_vfs;
pf->max_stat_ctxs -= vf_stat_ctx * num_vfs;
pf->max_vnics -= vf_vnics * num_vfs;
}
return rc;
}
static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs)
{
int rc = 0, vfs_supported;
int min_rx_rings, min_tx_rings, min_rss_ctxs;
int tx_ok = 0, rx_ok = 0, rss_ok = 0;
/* Check if we can enable requested num of vf's. At a mininum
* we require 1 RX 1 TX rings for each VF. In this minimum conf
* features like TPA will not be available.
*/
vfs_supported = *num_vfs;
while (vfs_supported) {
min_rx_rings = vfs_supported;
min_tx_rings = vfs_supported;
min_rss_ctxs = vfs_supported;
if (bp->flags & BNXT_FLAG_AGG_RINGS) {
if (bp->pf.max_rx_rings - bp->rx_nr_rings * 2 >=
min_rx_rings)
rx_ok = 1;
} else {
if (bp->pf.max_rx_rings - bp->rx_nr_rings >=
min_rx_rings)
rx_ok = 1;
}
if (bp->pf.max_vnics - bp->nr_vnics < min_rx_rings)
rx_ok = 0;
if (bp->pf.max_tx_rings - bp->tx_nr_rings >= min_tx_rings)
tx_ok = 1;
if (bp->pf.max_rsscos_ctxs - bp->rsscos_nr_ctxs >= min_rss_ctxs)
rss_ok = 1;
if (tx_ok && rx_ok && rss_ok)
break;
vfs_supported--;
}
if (!vfs_supported) {
netdev_err(bp->dev, "Cannot enable VF's as all resources are used by PF\n");
return -EINVAL;
}
if (vfs_supported != *num_vfs) {
netdev_info(bp->dev, "Requested VFs %d, can enable %d\n",
*num_vfs, vfs_supported);
*num_vfs = vfs_supported;
}
rc = bnxt_alloc_vf_resources(bp, *num_vfs);
if (rc)
goto err_out1;
/* Reserve resources for VFs */
rc = bnxt_hwrm_func_cfg(bp, *num_vfs);
if (rc)
goto err_out2;
/* Register buffers for VFs */
rc = bnxt_hwrm_func_buf_rgtr(bp);
if (rc)
goto err_out2;
bnxt_ulp_sriov_cfg(bp, *num_vfs);
rc = pci_enable_sriov(bp->pdev, *num_vfs);
if (rc)
goto err_out2;
return 0;
err_out2:
/* Free the resources reserved for various VF's */
bnxt_hwrm_func_vf_resource_free(bp, *num_vfs);
err_out1:
bnxt_free_vf_resources(bp);
return rc;
}
void bnxt_sriov_disable(struct bnxt *bp)
{
u16 num_vfs = pci_num_vf(bp->pdev);
if (!num_vfs)
return;
if (pci_vfs_assigned(bp->pdev)) {
bnxt_hwrm_fwd_async_event_cmpl(
bp, NULL, ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD);
netdev_warn(bp->dev, "Unable to free %d VFs because some are assigned to VMs.\n",
num_vfs);
} else {
pci_disable_sriov(bp->pdev);
/* Free the HW resources reserved for various VF's */
bnxt_hwrm_func_vf_resource_free(bp, num_vfs);
}
bnxt_free_vf_resources(bp);
bp->pf.active_vfs = 0;
/* Reclaim all resources for the PF. */
rtnl_lock();
bnxt_restore_pf_fw_resources(bp);
rtnl_unlock();
bnxt_ulp_sriov_cfg(bp, 0);
}
int bnxt_sriov_configure(struct pci_dev *pdev, int num_vfs)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct bnxt *bp = netdev_priv(dev);
if (!(bp->flags & BNXT_FLAG_USING_MSIX)) {
netdev_warn(dev, "Not allow SRIOV if the irq mode is not MSIX\n");
return 0;
}
rtnl_lock();
if (!netif_running(dev)) {
netdev_warn(dev, "Reject SRIOV config request since if is down!\n");
rtnl_unlock();
return 0;
}
bp->sriov_cfg = true;
rtnl_unlock();
if (pci_vfs_assigned(bp->pdev)) {
netdev_warn(dev, "Unable to configure SRIOV since some VFs are assigned to VMs.\n");
num_vfs = 0;
goto sriov_cfg_exit;
}
/* Check if enabled VFs is same as requested */
if (num_vfs && num_vfs == bp->pf.active_vfs)
goto sriov_cfg_exit;
/* if there are previous existing VFs, clean them up */
bnxt_sriov_disable(bp);
if (!num_vfs)
goto sriov_cfg_exit;
bnxt_sriov_enable(bp, &num_vfs);
sriov_cfg_exit:
bp->sriov_cfg = false;
wake_up(&bp->sriov_cfg_wait);
return num_vfs;
}
#ifndef PCIE_SRIOV_CONFIGURE
static struct workqueue_struct *bnxt_iov_wq;
void bnxt_sriov_init(unsigned int num_vfs)
{
if (num_vfs)
bnxt_iov_wq = create_singlethread_workqueue("bnxt_iov_wq");
}
void bnxt_sriov_exit(void)
{
if (bnxt_iov_wq)
destroy_workqueue(bnxt_iov_wq);
bnxt_iov_wq = NULL;
}
static void bnxt_iov_task(struct work_struct *work)
{
struct bnxt *bp;
bp = container_of(work, struct bnxt, iov_task);
bnxt_sriov_configure(bp->pdev, bp->req_vfs);
}
void bnxt_start_sriov(struct bnxt *bp, int num_vfs)
{
int pos, req_vfs;
if (!num_vfs || !BNXT_PF(bp))
return;
pos = pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV);
if (!pos) {
return;
} else {
u16 t_vf = 0;
pci_read_config_word(bp->pdev, pos + PCI_SRIOV_TOTAL_VF, &t_vf);
req_vfs = min_t(int, num_vfs, (int)t_vf);
}
if (!bnxt_iov_wq) {
netdev_warn(bp->dev, "Work queue not available to start SRIOV\n");
return;
}
bp->req_vfs = req_vfs;
INIT_WORK(&bp->iov_task, bnxt_iov_task);
queue_work(bnxt_iov_wq, &bp->iov_task);
}
#endif
static int bnxt_hwrm_fwd_resp(struct bnxt *bp, struct bnxt_vf_info *vf,
void *encap_resp, __le64 encap_resp_addr,
__le16 encap_resp_cpr, u32 msg_size)
{
int rc = 0;
struct hwrm_fwd_resp_input req = {0};
struct hwrm_fwd_resp_output *resp = bp->hwrm_cmd_resp_addr;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FWD_RESP, -1, -1);
/* Set the new target id */
req.target_id = cpu_to_le16(vf->fw_fid);
req.encap_resp_target_id = cpu_to_le16(vf->fw_fid);
req.encap_resp_len = cpu_to_le16(msg_size);
req.encap_resp_addr = encap_resp_addr;
req.encap_resp_cmpl_ring = encap_resp_cpr;
memcpy(req.encap_resp, encap_resp, msg_size);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc) {
netdev_err(bp->dev, "hwrm_fwd_resp failed. rc:%d\n", rc);
goto fwd_resp_exit;
}
if (resp->error_code) {
netdev_err(bp->dev, "hwrm_fwd_resp error %d\n",
resp->error_code);
rc = -1;
}
fwd_resp_exit:
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int bnxt_hwrm_fwd_err_resp(struct bnxt *bp, struct bnxt_vf_info *vf,
u32 msg_size)
{
int rc = 0;
struct hwrm_reject_fwd_resp_input req = {0};
struct hwrm_reject_fwd_resp_output *resp = bp->hwrm_cmd_resp_addr;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_REJECT_FWD_RESP, -1, -1);
/* Set the new target id */
req.target_id = cpu_to_le16(vf->fw_fid);
req.encap_resp_target_id = cpu_to_le16(vf->fw_fid);
memcpy(req.encap_request, vf->hwrm_cmd_req_addr, msg_size);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc) {
netdev_err(bp->dev, "hwrm_fwd_err_resp failed. rc:%d\n", rc);
goto fwd_err_resp_exit;
}
if (resp->error_code) {
netdev_err(bp->dev, "hwrm_fwd_err_resp error %d\n",
resp->error_code);
rc = -1;
}
fwd_err_resp_exit:
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int bnxt_hwrm_exec_fwd_resp(struct bnxt *bp, struct bnxt_vf_info *vf,
u32 msg_size)
{
int rc = 0;
struct hwrm_exec_fwd_resp_input req = {0};
struct hwrm_exec_fwd_resp_output *resp = bp->hwrm_cmd_resp_addr;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_EXEC_FWD_RESP, -1, -1);
/* Set the new target id */
req.target_id = cpu_to_le16(vf->fw_fid);
req.encap_resp_target_id = cpu_to_le16(vf->fw_fid);
memcpy(req.encap_request, vf->hwrm_cmd_req_addr, msg_size);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (rc) {
netdev_err(bp->dev, "hwrm_exec_fw_resp failed. rc:%d\n", rc);
goto exec_fwd_resp_exit;
}
if (resp->error_code) {
netdev_err(bp->dev, "hwrm_exec_fw_resp error %d\n",
resp->error_code);
rc = -1;
}
exec_fwd_resp_exit:
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int bnxt_vf_validate_set_mac(struct bnxt *bp, struct bnxt_vf_info *vf)
{
u32 msg_size = sizeof(struct hwrm_cfa_l2_filter_alloc_input);
struct hwrm_cfa_l2_filter_alloc_input *req =
(struct hwrm_cfa_l2_filter_alloc_input *)vf->hwrm_cmd_req_addr;
if (!is_valid_ether_addr(vf->mac_addr) ||
ether_addr_equal((const u8 *)req->l2_addr, vf->mac_addr))
return bnxt_hwrm_exec_fwd_resp(bp, vf, msg_size);
else
return bnxt_hwrm_fwd_err_resp(bp, vf, msg_size);
}
static int bnxt_vf_set_link(struct bnxt *bp, struct bnxt_vf_info *vf)
{
int rc = 0;
if (!(vf->flags & BNXT_VF_LINK_FORCED)) {
/* real link */
rc = bnxt_hwrm_exec_fwd_resp(
bp, vf, sizeof(struct hwrm_port_phy_qcfg_input));
} else {
struct hwrm_port_phy_qcfg_output phy_qcfg_resp;
struct hwrm_port_phy_qcfg_input *phy_qcfg_req;
phy_qcfg_req =
(struct hwrm_port_phy_qcfg_input *)vf->hwrm_cmd_req_addr;
mutex_lock(&bp->hwrm_cmd_lock);
memcpy(&phy_qcfg_resp, &bp->link_info.phy_qcfg_resp,
sizeof(phy_qcfg_resp));
mutex_unlock(&bp->hwrm_cmd_lock);
phy_qcfg_resp.seq_id = phy_qcfg_req->seq_id;
if (vf->flags & BNXT_VF_LINK_UP) {
/* if physical link is down, force link up on VF */
if (phy_qcfg_resp.link !=
PORT_PHY_QCFG_RESP_LINK_LINK) {
phy_qcfg_resp.link =
PORT_PHY_QCFG_RESP_LINK_LINK;
phy_qcfg_resp.link_speed = cpu_to_le16(
PORT_PHY_QCFG_RESP_LINK_SPEED_10GB);
phy_qcfg_resp.duplex_cfg =
PORT_PHY_QCFG_RESP_DUPLEX_CFG_FULL;
phy_qcfg_resp.duplex_state =
PORT_PHY_QCFG_RESP_DUPLEX_STATE_FULL;
phy_qcfg_resp.pause =
(PORT_PHY_QCFG_RESP_PAUSE_TX |
PORT_PHY_QCFG_RESP_PAUSE_RX);
}
} else {
/* force link down */
phy_qcfg_resp.link = PORT_PHY_QCFG_RESP_LINK_NO_LINK;
phy_qcfg_resp.link_speed = 0;
phy_qcfg_resp.duplex_state =
PORT_PHY_QCFG_RESP_DUPLEX_STATE_HALF;
phy_qcfg_resp.pause = 0;
}
rc = bnxt_hwrm_fwd_resp(bp, vf, &phy_qcfg_resp,
phy_qcfg_req->resp_addr,
phy_qcfg_req->cmpl_ring,
sizeof(phy_qcfg_resp));
}
return rc;
}
static int bnxt_vf_req_validate_snd(struct bnxt *bp, struct bnxt_vf_info *vf)
{
int rc = 0;
struct input *encap_req = vf->hwrm_cmd_req_addr;
u32 req_type = le16_to_cpu(encap_req->req_type);
switch (req_type) {
case HWRM_CFA_L2_FILTER_ALLOC:
rc = bnxt_vf_validate_set_mac(bp, vf);
break;
case HWRM_FUNC_CFG:
/* TODO Validate if VF is allowed to change mac address,
* mtu, num of rings etc
*/
rc = bnxt_hwrm_exec_fwd_resp(
bp, vf, sizeof(struct hwrm_func_cfg_input));
break;
case HWRM_PORT_PHY_QCFG:
rc = bnxt_vf_set_link(bp, vf);
break;
default:
break;
}
return rc;
}
void bnxt_hwrm_exec_fwd_req(struct bnxt *bp)
{
u32 i = 0, active_vfs = bp->pf.active_vfs, vf_id;
/* Scan through VF's and process commands */
while (1) {
vf_id = find_next_bit(bp->pf.vf_event_bmap, active_vfs, i);
if (vf_id >= active_vfs)
break;
clear_bit(vf_id, bp->pf.vf_event_bmap);
bnxt_vf_req_validate_snd(bp, &bp->pf.vf[vf_id]);
i = vf_id + 1;
}
}
void bnxt_update_vf_mac(struct bnxt *bp)
{
struct hwrm_func_qcaps_input req = {0};
struct hwrm_func_qcaps_output *resp = bp->hwrm_cmd_resp_addr;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QCAPS, -1, -1);
req.fid = cpu_to_le16(0xffff);
mutex_lock(&bp->hwrm_cmd_lock);
if (_hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT))
goto update_vf_mac_exit;
/* Store MAC address from the firmware. There are 2 cases:
* 1. MAC address is valid. It is assigned from the PF and we
* need to override the current VF MAC address with it.
* 2. MAC address is zero. The VF will use a random MAC address by
* default but the stored zero MAC will allow the VF user to change
* the random MAC address using ndo_set_mac_address() if he wants.
*/
if (!ether_addr_equal(resp->mac_address, bp->vf.mac_addr))
memcpy(bp->vf.mac_addr, resp->mac_address, ETH_ALEN);
/* overwrite netdev dev_addr with admin VF MAC */
if (is_valid_ether_addr(bp->vf.mac_addr))
memcpy(bp->dev->dev_addr, bp->vf.mac_addr, ETH_ALEN);
update_vf_mac_exit:
mutex_unlock(&bp->hwrm_cmd_lock);
}
int bnxt_approve_mac(struct bnxt *bp, u8 *mac)
{
struct hwrm_func_vf_cfg_input req = {0};
int rc = 0;
if (!BNXT_VF(bp))
return 0;
if (bp->hwrm_spec_code < 0x10202) {
if (is_valid_ether_addr(bp->vf.mac_addr))
rc = -EADDRNOTAVAIL;
goto mac_done;
}
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_CFG, -1, -1);
req.enables = cpu_to_le32(FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR);
memcpy(req.dflt_mac_addr, mac, ETH_ALEN);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
mac_done:
if (rc) {
rc = -EADDRNOTAVAIL;
netdev_warn(bp->dev, "VF MAC address %pM not approved by the PF\n",
mac);
}
return rc;
}
#else
void bnxt_sriov_disable(struct bnxt *bp)
{
}
void bnxt_hwrm_exec_fwd_req(struct bnxt *bp)
{
netdev_err(bp->dev, "Invalid VF message received when SRIOV is not enable\n");
}
void bnxt_update_vf_mac(struct bnxt *bp)
{
}
int bnxt_approve_mac(struct bnxt *bp, u8 *mac)
{
return 0;
}
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2014-2016 Broadcom Corporation
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#ifndef BNXT_SRIOV_H
#define BNXT_SRIOV_H
#ifdef HAVE_NDO_GET_VF_CONFIG
int bnxt_get_vf_config(struct net_device *, int, struct ifla_vf_info *);
int bnxt_set_vf_mac(struct net_device *, int, u8 *);
#ifdef NEW_NDO_SET_VF_VLAN
int bnxt_set_vf_vlan(struct net_device *, int, u16, u8, __be16);
#else
int bnxt_set_vf_vlan(struct net_device *, int, u16, u8);
#endif
#ifdef HAVE_IFLA_TX_RATE
int bnxt_set_vf_bw(struct net_device *, int, int, int);
#else
int bnxt_set_vf_bw(struct net_device *, int, int);
#endif
#ifdef HAVE_NDO_SET_VF_LINK_STATE
int bnxt_set_vf_link_state(struct net_device *, int, int);
#endif
#ifdef HAVE_VF_SPOOFCHK
int bnxt_set_vf_spoofchk(struct net_device *, int, bool);
#endif
#endif
int bnxt_sriov_configure(struct pci_dev *pdev, int num_vfs);
#ifndef PCIE_SRIOV_CONFIGURE
void bnxt_start_sriov(struct bnxt *, int);
void bnxt_sriov_init(unsigned int);
void bnxt_sriov_exit(void);
#endif
void bnxt_sriov_disable(struct bnxt *);
void bnxt_hwrm_exec_fwd_req(struct bnxt *);
void bnxt_update_vf_mac(struct bnxt *);
int bnxt_approve_mac(struct bnxt *, u8 *);
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
#include <linux/bitops.h>
#include <linux/irq.h>
#include <asm/byteorder.h>
#include <linux/bitmap.h>
#include "bnxt_compat.h"
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_ulp.h"
static int bnxt_register_dev(struct bnxt_en_dev *edev, int ulp_id,
struct bnxt_ulp_ops *ulp_ops, void *handle)
{
struct net_device *dev = edev->net;
struct bnxt *bp = netdev_priv(dev);
struct bnxt_ulp *ulp;
ASSERT_RTNL();
if (ulp_id >= BNXT_MAX_ULP)
return -EINVAL;
ulp = &edev->ulp_tbl[ulp_id];
if (rcu_access_pointer(ulp->ulp_ops)) {
netdev_err(bp->dev, "ulp id %d already registered\n", ulp_id);
return -EBUSY;
}
if (ulp_id == BNXT_ROCE_ULP) {
unsigned int max_stat_ctxs;
max_stat_ctxs = bnxt_get_max_func_stat_ctxs(bp);
if (max_stat_ctxs <= BNXT_MIN_ROCE_STAT_CTXS ||
bp->num_stat_ctxs == max_stat_ctxs)
return -ENOMEM;
bnxt_set_max_func_stat_ctxs(bp, max_stat_ctxs -
BNXT_MIN_ROCE_STAT_CTXS);
}
atomic_set(&ulp->ref_count, 0);
ulp->handle = handle;
rcu_assign_pointer(ulp->ulp_ops, ulp_ops);
if (ulp_id == BNXT_ROCE_ULP) {
if (test_bit(BNXT_STATE_OPEN, &bp->state))
bnxt_hwrm_vnic_cfg(bp, 0);
}
return 0;
}
static int bnxt_unregister_dev(struct bnxt_en_dev *edev, int ulp_id)
{
struct net_device *dev = edev->net;
struct bnxt *bp = netdev_priv(dev);
struct bnxt_ulp *ulp;
int i = 0;
ASSERT_RTNL();
if (ulp_id >= BNXT_MAX_ULP)
return -EINVAL;
ulp = &edev->ulp_tbl[ulp_id];
if (!rcu_access_pointer(ulp->ulp_ops)) {
netdev_err(bp->dev, "ulp id %d not registered\n", ulp_id);
return -EINVAL;
}
if (ulp_id == BNXT_ROCE_ULP) {
unsigned int max_stat_ctxs;
max_stat_ctxs = bnxt_get_max_func_stat_ctxs(bp);
bnxt_set_max_func_stat_ctxs(bp, max_stat_ctxs + 1);
}
if (ulp->max_async_event_id)
bnxt_hwrm_func_rgtr_async_events(bp, NULL, 0);
RCU_INIT_POINTER(ulp->ulp_ops, NULL);
synchronize_rcu();
ulp->max_async_event_id = 0;
ulp->async_events_bmap = NULL;
while (atomic_read(&ulp->ref_count) != 0 && i < 10) {
msleep(100);
i++;
}
return 0;
}
static int bnxt_req_msix_vecs(struct bnxt_en_dev *edev, int ulp_id,
struct bnxt_msix_entry *ent, int num_msix)
{
struct net_device *dev = edev->net;
struct bnxt *bp = netdev_priv(dev);
int max_idx, max_cp_rings;
int avail_msix, i, idx;
ASSERT_RTNL();
if (ulp_id != BNXT_ROCE_ULP)
return -EINVAL;
if (!(bp->flags & BNXT_FLAG_USING_MSIX))
return -ENODEV;
max_cp_rings = bnxt_get_max_func_cp_rings(bp);
max_idx = min_t(int, bp->total_irqs, max_cp_rings);
avail_msix = max_idx - bp->cp_nr_rings;
if (!avail_msix)
return -ENOMEM;
if (avail_msix > num_msix)
avail_msix = num_msix;
idx = max_idx - avail_msix;
for (i = 0; i < avail_msix; i++) {
ent[i].vector = bp->irq_tbl[idx + i].vector;
ent[i].ring_idx = idx + i;
ent[i].db_offset = (idx + i) * 0x80;
}
bnxt_set_max_func_irqs(bp, max_idx - avail_msix);
bnxt_set_max_func_cp_rings(bp, max_cp_rings - avail_msix);
edev->ulp_tbl[ulp_id].msix_requested = avail_msix;
return avail_msix;
}
static int bnxt_free_msix_vecs(struct bnxt_en_dev *edev, int ulp_id)
{
struct net_device *dev = edev->net;
struct bnxt *bp = netdev_priv(dev);
int max_cp_rings, msix_requested;
ASSERT_RTNL();
if (ulp_id != BNXT_ROCE_ULP)
return -EINVAL;
max_cp_rings = bnxt_get_max_func_cp_rings(bp);
msix_requested = edev->ulp_tbl[ulp_id].msix_requested;
bnxt_set_max_func_cp_rings(bp, max_cp_rings + msix_requested);
edev->ulp_tbl[ulp_id].msix_requested = 0;
bnxt_set_max_func_irqs(bp, bp->total_irqs);
return 0;
}
void bnxt_subtract_ulp_resources(struct bnxt *bp, int ulp_id)
{
ASSERT_RTNL();
if (bnxt_ulp_registered(bp->edev, ulp_id)) {
struct bnxt_en_dev *edev = bp->edev;
unsigned int msix_req, max;
msix_req = edev->ulp_tbl[ulp_id].msix_requested;
max = bnxt_get_max_func_cp_rings(bp);
bnxt_set_max_func_cp_rings(bp, max - msix_req);
max = bnxt_get_max_func_stat_ctxs(bp);
bnxt_set_max_func_stat_ctxs(bp, max - 1);
}
}
static int bnxt_send_msg(struct bnxt_en_dev *edev, int ulp_id,
struct bnxt_fw_msg *fw_msg)
{
struct net_device *dev = edev->net;
struct bnxt *bp = netdev_priv(dev);
struct input *req;
int rc;
mutex_lock(&bp->hwrm_cmd_lock);
req = fw_msg->msg;
req->resp_addr = cpu_to_le64(bp->hwrm_cmd_resp_dma_addr);
rc = _hwrm_send_message(bp, fw_msg->msg, fw_msg->msg_len,
fw_msg->timeout);
if (!rc) {
struct output *resp = bp->hwrm_cmd_resp_addr;
u32 len = le16_to_cpu(resp->resp_len);
if (fw_msg->resp_max_len < len)
len = fw_msg->resp_max_len;
memcpy(fw_msg->resp, resp, len);
}
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static void bnxt_ulp_get(struct bnxt_ulp *ulp)
{
atomic_inc(&ulp->ref_count);
}
static void bnxt_ulp_put(struct bnxt_ulp *ulp)
{
atomic_dec(&ulp->ref_count);
}
void bnxt_ulp_stop(struct bnxt *bp)
{
struct bnxt_en_dev *edev = bp->edev;
struct bnxt_ulp_ops *ops;
int i;
if (!edev)
return;
for (i = 0; i < BNXT_MAX_ULP; i++) {
struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
ops = rtnl_dereference(ulp->ulp_ops);
if (!ops || !ops->ulp_stop)
continue;
ops->ulp_stop(ulp->handle);
}
}
void bnxt_ulp_start(struct bnxt *bp)
{
struct bnxt_en_dev *edev = bp->edev;
struct bnxt_ulp_ops *ops;
int i;
if (!edev)
return;
for (i = 0; i < BNXT_MAX_ULP; i++) {
struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
ops = rtnl_dereference(ulp->ulp_ops);
if (!ops || !ops->ulp_start)
continue;
ops->ulp_start(ulp->handle);
}
}
void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs)
{
struct bnxt_en_dev *edev = bp->edev;
struct bnxt_ulp_ops *ops;
int i;
if (!edev)
return;
for (i = 0; i < BNXT_MAX_ULP; i++) {
struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
rcu_read_lock();
ops = rcu_dereference(ulp->ulp_ops);
if (!ops || !ops->ulp_sriov_config) {
rcu_read_unlock();
continue;
}
bnxt_ulp_get(ulp);
rcu_read_unlock();
ops->ulp_sriov_config(ulp->handle, num_vfs);
bnxt_ulp_put(ulp);
}
}
void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl)
{
u16 event_id = le16_to_cpu(cmpl->event_id);
struct bnxt_en_dev *edev = bp->edev;
struct bnxt_ulp_ops *ops;
int i;
if (!edev)
return;
rcu_read_lock();
for (i = 0; i < BNXT_MAX_ULP; i++) {
struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
ops = rcu_dereference(ulp->ulp_ops);
if (!ops || !ops->ulp_async_notifier)
continue;
if (!ulp->async_events_bmap ||
event_id > ulp->max_async_event_id)
continue;
/* Read max_async_event_id first before testing the bitmap. */
smp_rmb();
if (test_bit(event_id, ulp->async_events_bmap))
ops->ulp_async_notifier(ulp->handle, cmpl);
}
rcu_read_unlock();
}
static int bnxt_register_async_events(struct bnxt_en_dev *edev, int ulp_id,
unsigned long *events_bmap, u16 max_id)
{
struct net_device *dev = edev->net;
struct bnxt *bp = netdev_priv(dev);
struct bnxt_ulp *ulp;
if (ulp_id >= BNXT_MAX_ULP)
return -EINVAL;
ulp = &edev->ulp_tbl[ulp_id];
ulp->async_events_bmap = events_bmap;
/* Make sure bnxt_ulp_async_events() sees this order */
smp_wmb();
ulp->max_async_event_id = max_id;
bnxt_hwrm_func_rgtr_async_events(bp, events_bmap, max_id + 1);
return 0;
}
static const struct bnxt_en_ops bnxt_en_ops_tbl = {
.bnxt_register_device = bnxt_register_dev,
.bnxt_unregister_device = bnxt_unregister_dev,
.bnxt_request_msix = bnxt_req_msix_vecs,
.bnxt_free_msix = bnxt_free_msix_vecs,
.bnxt_send_fw_msg = bnxt_send_msg,
.bnxt_register_fw_async_events = bnxt_register_async_events,
};
struct bnxt_en_dev *bnxt_ulp_probe(struct net_device *dev)
{
struct bnxt *bp = netdev_priv(dev);
struct bnxt_en_dev *edev;
edev = bp->edev;
if (!edev) {
edev = kzalloc(sizeof(*edev), GFP_KERNEL);
if (!edev)
return ERR_PTR(-ENOMEM);
edev->en_ops = &bnxt_en_ops_tbl;
if (bp->flags & BNXT_FLAG_ROCEV1_CAP)
edev->flags |= BNXT_EN_FLAG_ROCEV1_CAP;
if (bp->flags & BNXT_FLAG_ROCEV2_CAP)
edev->flags |= BNXT_EN_FLAG_ROCEV2_CAP;
edev->net = dev;
edev->pdev = bp->pdev;
bp->edev = edev;
}
return bp->edev;
}
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#ifndef BNXT_ULP_H
#define BNXT_ULP_H
#include <linux/version.h>
#define BNXT_ROCE_ULP 0
#define BNXT_OTHER_ULP 1
#define BNXT_MAX_ULP 2
#define BNXT_MIN_ROCE_CP_RINGS 2
#define BNXT_MIN_ROCE_STAT_CTXS 1
struct hwrm_async_event_cmpl;
struct bnxt;
struct bnxt_ulp_ops {
/* async_notifier() cannot sleep (in BH context) */
void (*ulp_async_notifier)(void *, struct hwrm_async_event_cmpl *);
void (*ulp_stop)(void *);
void (*ulp_start)(void *);
void (*ulp_sriov_config)(void *, int);
};
struct bnxt_msix_entry {
u32 vector;
u32 ring_idx;
u32 db_offset;
};
struct bnxt_fw_msg {
void *msg;
int msg_len;
void *resp;
int resp_max_len;
int timeout;
};
struct bnxt_ulp {
void *handle;
struct bnxt_ulp_ops __rcu *ulp_ops;
unsigned long *async_events_bmap;
u16 max_async_event_id;
u16 msix_requested;
atomic_t ref_count;
};
struct bnxt_en_dev {
struct net_device *net;
struct pci_dev *pdev;
u32 flags;
#define BNXT_EN_FLAG_ROCEV1_CAP 0x1
#define BNXT_EN_FLAG_ROCEV2_CAP 0x2
#define BNXT_EN_FLAG_ROCE_CAP (BNXT_EN_FLAG_ROCEV1_CAP | \
BNXT_EN_FLAG_ROCEV2_CAP)
const struct bnxt_en_ops *en_ops;
struct bnxt_ulp ulp_tbl[BNXT_MAX_ULP];
};
struct bnxt_en_ops {
int (*bnxt_register_device)(struct bnxt_en_dev *, int,
struct bnxt_ulp_ops *, void *);
int (*bnxt_unregister_device)(struct bnxt_en_dev *, int);
int (*bnxt_request_msix)(struct bnxt_en_dev *, int,
struct bnxt_msix_entry *, int);
int (*bnxt_free_msix)(struct bnxt_en_dev *, int);
int (*bnxt_send_fw_msg)(struct bnxt_en_dev *, int,
struct bnxt_fw_msg *);
int (*bnxt_register_fw_async_events)(struct bnxt_en_dev *, int,
unsigned long *, u16);
};
static inline bool bnxt_ulp_registered(struct bnxt_en_dev *edev, int ulp_id)
{
if (edev && rcu_access_pointer(edev->ulp_tbl[ulp_id].ulp_ops))
return true;
return false;
}
void bnxt_subtract_ulp_resources(struct bnxt *bp, int ulp_id);
void bnxt_ulp_stop(struct bnxt *bp);
void bnxt_ulp_start(struct bnxt *bp);
void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs);
void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl);
struct bnxt_en_dev *bnxt_ulp_probe(struct net_device *dev);
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#ifdef HAVE_NDO_XDP
#include <linux/bpf.h>
#ifdef HAVE_BPF_TRACE
#include <linux/bpf_trace.h>
#endif
#include <linux/filter.h>
#endif
#include "bnxt_compat.h"
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_xdp.h"
void bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
dma_addr_t mapping, u32 len, u16 rx_prod)
{
struct bnxt_sw_tx_bd *tx_buf;
struct tx_bd *txbd;
u32 flags;
u16 prod;
prod = txr->tx_prod;
tx_buf = &txr->tx_buf_ring[prod];
tx_buf->rx_prod = rx_prod;
txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];
flags = (len << TX_BD_LEN_SHIFT) | (1 << TX_BD_FLAGS_BD_CNT_SHIFT) |
TX_BD_FLAGS_PACKET_END | bnxt_lhint_arr[len >> 9];
txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
txbd->tx_bd_opaque = prod;
txbd->tx_bd_haddr = cpu_to_le64(mapping);
prod = NEXT_TX(prod);
txr->tx_prod = prod;
}
#ifdef HAVE_NDO_XDP
void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts)
{
struct bnxt_tx_ring_info *txr = bnapi->tx_ring;
struct bnxt_rx_ring_info *rxr = bnapi->rx_ring;
struct bnxt_sw_tx_bd *tx_buf;
u16 tx_cons = txr->tx_cons;
u16 last_tx_cons = tx_cons;
u16 rx_prod;
int i;
for (i = 0; i < nr_pkts; i++) {
last_tx_cons = tx_cons;
tx_cons = NEXT_TX(tx_cons);
}
txr->tx_cons = tx_cons;
if (bnxt_tx_avail(bp, txr) == bp->tx_ring_size) {
rx_prod = rxr->rx_prod;
} else {
tx_buf = &txr->tx_buf_ring[last_tx_cons];
rx_prod = tx_buf->rx_prod;
}
writel(DB_KEY_RX | rx_prod, rxr->rx_doorbell);
}
/* returns the following:
* true - packet consumed by XDP and new buffer is allocated.
* false - packet should be passed to the stack.
*/
bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
struct page *page, u8 **data_ptr, unsigned int *len, u8 *event)
{
struct bpf_prog *xdp_prog = READ_ONCE(rxr->xdp_prog);
struct bnxt_tx_ring_info *txr;
struct bnxt_sw_rx_bd *rx_buf;
struct pci_dev *pdev;
struct xdp_buff xdp;
dma_addr_t mapping;
void *orig_data;
u32 tx_avail;
u32 offset;
u32 act;
if (!xdp_prog)
return false;
pdev = bp->pdev;
txr = rxr->bnapi->tx_ring;
rx_buf = &rxr->rx_buf_ring[cons];
offset = bp->rx_offset;
#if XDP_PACKET_HEADROOM
xdp.data_hard_start = *data_ptr - offset;
#endif
xdp.data = *data_ptr;
xdp.data_end = *data_ptr + *len;
orig_data = xdp.data;
mapping = rx_buf->mapping - bp->rx_dma_offset;
dma_sync_single_for_cpu(&pdev->dev, mapping + offset, *len, bp->rx_dir);
rcu_read_lock();
act = bpf_prog_run_xdp(xdp_prog, &xdp);
rcu_read_unlock();
tx_avail = bnxt_tx_avail(bp, txr);
/* If the tx ring is not full, we must not update the rx producer yet
* because we may still be transmitting on some BDs.
*/
if (tx_avail != bp->tx_ring_size)
*event &= ~BNXT_RX_EVENT;
if (orig_data != xdp.data) {
#if XDP_PACKET_HEADROOM
offset = xdp.data - xdp.data_hard_start;
*data_ptr = xdp.data_hard_start + offset;
*len = xdp.data_end - xdp.data;
#endif
}
switch (act) {
case XDP_PASS:
return false;
case XDP_TX:
if (tx_avail < 1) {
trace_xdp_exception(bp->dev, xdp_prog, act);
bnxt_reuse_rx_data(rxr, cons, page);
return true;
}
*event = BNXT_TX_EVENT;
dma_sync_single_for_device(&pdev->dev, mapping + offset, *len,
bp->rx_dir);
bnxt_xmit_xdp(bp, txr, mapping + offset, *len,
NEXT_RX(rxr->rx_prod));
bnxt_reuse_rx_data(rxr, cons, page);
return true;
default:
bpf_warn_invalid_xdp_action(act);
/* Fall thru */
case XDP_ABORTED:
trace_xdp_exception(bp->dev, xdp_prog, act);
/* Fall thru */
case XDP_DROP:
bnxt_reuse_rx_data(rxr, cons, page);
break;
}
return true;
}
/* Under rtnl_lock */
static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
{
struct net_device *dev = bp->dev;
int tx_xdp = 0, rc, tc;
struct bpf_prog *old;
if (prog && bp->dev->mtu > BNXT_MAX_PAGE_MODE_MTU) {
netdev_warn(dev, "MTU %d larger than largest XDP supported MTU %d.\n",
bp->dev->mtu, BNXT_MAX_PAGE_MODE_MTU);
return -EOPNOTSUPP;
}
if (!(bp->flags & BNXT_FLAG_SHARED_RINGS)) {
netdev_warn(dev, "ethtool rx/tx channels must be combined to support XDP.\n");
return -EOPNOTSUPP;
}
if (prog)
tx_xdp = bp->rx_nr_rings;
tc = netdev_get_num_tc(dev);
if (!tc)
tc = 1;
rc = bnxt_reserve_rings(bp, bp->tx_nr_rings_per_tc, bp->rx_nr_rings,
true, tc, tx_xdp);
if (rc) {
netdev_warn(dev, "Unable to reserve enough TX rings to support XDP.\n");
return rc;
}
if (netif_running(dev))
bnxt_close_nic(bp, true, false);
old = xchg(&bp->xdp_prog, prog);
if (old)
bpf_prog_put(old);
if (prog) {
bnxt_set_rx_skb_mode(bp, true);
} else {
int rx, tx;
bnxt_set_rx_skb_mode(bp, false);
bnxt_get_max_rings(bp, &rx, &tx, true);
if (rx > 1) {
bp->flags &= ~BNXT_FLAG_NO_AGG_RINGS;
bp->dev->hw_features |= NETIF_F_LRO;
}
}
bp->tx_nr_rings_xdp = tx_xdp;
bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tc + tx_xdp;
bp->cp_nr_rings = max_t(int, bp->tx_nr_rings, bp->rx_nr_rings);
bp->num_stat_ctxs = bp->cp_nr_rings;
bnxt_set_tpa_flags(bp);
bnxt_set_ring_params(bp);
if (netif_running(dev))
return bnxt_open_nic(bp, true, false);
return 0;
}
int bnxt_xdp(struct net_device *dev, struct netdev_xdp *xdp)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
switch (xdp->command) {
case XDP_SETUP_PROG:
rc = bnxt_xdp_set(bp, xdp->prog);
break;
case XDP_QUERY_PROG:
xdp->prog_attached = !!bp->xdp_prog;
#ifdef HAVE_IFLA_XDP_PROG_ID
xdp->prog_id = bp->xdp_prog ? bp->xdp_prog->aux->id : 0;
#endif
rc = 0;
break;
default:
rc = -EINVAL;
break;
}
return rc;
}
#else
void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts)
{
}
bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
void *page, u8 **data_ptr, unsigned int *len, u8 *event)
{
return false;
}
#endif
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2016-2017 Broadcom Limited
*
* 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.
*/
#ifndef BNXT_XDP_H
#define BNXT_XDP_H
void bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
dma_addr_t mapping, u32 len, u16 rx_prod);
void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts);
#ifdef HAVE_NDO_XDP
bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
struct page *page, u8 **data_ptr, unsigned int *len,
u8 *event);
#else
bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
void *page, u8 **data_ptr, unsigned int *len,
u8 *event);
#endif
int bnxt_xdp(struct net_device *dev, struct netdev_xdp *xdp);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment