driver: update bnxt_en driver to 1.10.1-216.1.92.0

Signed-off-by: Zhiping Du <zhipingdu@tencent.com>
This commit is contained in:
Zhiping du 2020-04-27 19:44:34 +08:00 committed by Xiaoming Gao
parent b0e23ef723
commit 4a019c19d4
40 changed files with 46096 additions and 7681 deletions

View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,871 @@
obj-$(CONFIG_BNXT) += bnxt_en.o
#!/usr/bin/make
# Makefile for building Linux Broadcom Gigabit ethernet driver as a module.
# $id$
KVER=
ifeq ($(KVER),)
KVER=$(shell uname -r)
endif
bnxt_en-y := bnxt.o bnxt_sriov.o bnxt_ethtool.o bnxt_dcb.o bnxt_ulp.o bnxt_xdp.o bnxt_vfr.o bnxt_tc.o
__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
ifneq ($(KDIR),)
LINUX=$(KDIR)
LINUXSRC=$(LINUX)
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 -so "GENL_ID_GENERATE" $(LINUXSRC)/include/uapi/linux/genetlink.h),)
DISTRO_CFLAG += -DHAVE_GENL_ID_GENERATE
endif
ifneq ($(shell grep "genl_register_family_with_ops" $(LINUXSRC)/include/net/genetlink.h),)
DISTRO_CFLAG += -DHAVE_GENL_REG_FAMILY_WITH_OPS
endif
ifneq ($(shell grep -A 8 "genl_family {" $(LINUXSRC)/include/net/genetlink.h | grep -o "struct nla_policy"),)
DISTRO_CFLAG += -DHAVE_GENL_POLICY
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 -o "skb_frag_off_add" $(LINUXSRC)/include/linux/skbuff.h),)
DISTRO_CFLAG += -DHAVE_SKB_FRAG_ACCESSORS
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 "xmit_more" $(LINUXSRC)/include/linux/skbuff.h),)
DISTRO_CFLAG += -DHAVE_SKB_XMIT_MORE
endif
ifneq ($(shell grep -so "min_tx_rate" $(LINUXSRC)/include/$(UAPI)/linux/if_link.h),)
DISTRO_CFLAG += -DHAVE_IFLA_TX_RATE
endif
ifneq ($(shell grep -so "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 ls $(LINUXSRC)/include/linux/dma-attrs.h > /dev/null 2>&1 && echo dma_attrs),)
DISTRO_CFLAG += -DHAVE_DMA_ATTRS_H
endif
ifneq ($(shell grep -o "dma_map_page_attrs" $(LINUXSRC)/include/linux/dma-mapping.h),)
DISTRO_CFLAG += -DHAVE_DMA_MAP_PAGE_ATTRS
else
ifneq ($(shell grep -so "dma_map_page_attrs" $(LINUXSRC)/include/asm-generic/dma-mapping-common.h),)
DISTRO_CFLAG += -DHAVE_DMA_MAP_PAGE_ATTRS
endif
endif
ifneq ($(shell grep -o "dma_zalloc_coherent" $(LINUXSRC)/include/linux/dma-mapping.h),)
DISTRO_CFLAG += -DHAVE_DMA_ZALLOC_COHERENT
endif
ifneq ($(shell grep -o "ndo_add_vxlan_port" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_ADD_VXLAN
ifneq ($(shell grep -so "vxlan_get_rx_port" $(LINUXSRC)/include/net/vxlan.h),)
DISTRO_CFLAG += -DHAVE_VXLAN_GET_RX_PORT
endif
endif
ifneq ($(shell grep -o "ndo_udp_tunnel_add" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_UDP_TUNNEL
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
ifneq ($(shell grep -o "flow_hash_from_keys" $(LINUXSRC)/include/net/flow_dissector.h),)
DISTRO_CFLAG += -DHAVE_FLOW_HASH_FROM_KEYS
endif
endif
ifneq ($(shell ls $(LINUXSRC)/include/net/flow_offload.h > /dev/null 2>&1 && echo flow_offload),)
DISTRO_CFLAG += -DHAVE_FLOW_OFFLOAD_H
ifneq ($(shell grep -so "struct flow_cls_offload" $(LINUXSRC)/include/net/flow_offload.h),)
DISTRO_CFLAG += -DHAVE_TC_FLOW_CLS_OFFLOAD
endif
ifneq ($(shell grep -o "flow_block_cb_setup_simple" $(LINUXSRC)/include/net/flow_offload.h),)
DISTRO_CFLAG += -DHAVE_SETUP_TC_BLOCK_HELPER
endif
ifneq ($(shell grep -o "__flow_indr_block_cb_register" $(LINUXSRC)/include/net/flow_offload.h),)
DISTRO_CFLAG += -DHAVE_FLOW_INDR_BLOCK_CB
endif
ifneq ($(shell grep -o "FLOW_ACTION_POLICE" $(LINUXSRC)/include/net/flow_offload.h),)
DISTRO_CFLAG += -DHAVE_FLOW_ACTION_POLICE
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 -s "eth_get_headlen" $(LINUXSRC)/include/linux/etherdevice.h | grep -o "struct net_device"),)
DISTRO_CFLAG += -DHAVE_ETH_GET_HEADLEN_NEW
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 "(\*set_rxfh)" $(LINUXSRC)/include/linux/ethtool.h),)
DISTRO_CFLAG += -DHAVE_SET_RXFH
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 -so "ETHTOOL_LINK_MODE_25000baseCR_Full_BIT" $(LINUXSRC)/include/$(UAPI)/linux/ethtool.h),)
ifeq ($(shell grep -o "^struct new_ethtool_ops {" $(LINUXSRC)/include/linux/ethtool.h),)
DISTRO_CFLAG += -DHAVE_ETHTOOL_GLINKSETTINGS_25G
endif
endif
ifneq ($(shell grep -so "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 "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 "netdev_notifier_info_to_dev" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NETDEV_NOTIFIER_INFO_TO_DEV
endif
ifneq ($(shell grep "register_netdevice_notifier_rh" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_REGISTER_NETDEVICE_NOTIFIER_RH
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),)
DISTRO_CFLAG += -DPCIE_SRIOV_CONFIGURE
ifneq ($(shell grep -A 2 "pci_driver_rh" $(LINUXSRC)/include/linux/pci.h | \
grep -o "sriov_configure"),)
DISTRO_CFLAG += -DSRIOV_CONF_DEF_IN_PCI_DRIVER_RH
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 -A 4 "ndo_bridge_setlink" $(LINUXSRC)/include/linux/netdevice.h | grep -o "netlink_ext_ack"),)
DISTRO_CFLAG += -DHAVE_NDO_BRIDGE_SETLINK_EXTACK
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 "RH_KABI_EXTEND(struct net_device_ops_extended 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_set_vf_trust" $(LINUXSRC)/include/linux/netdevice.h),)
ifeq ($(shell grep -o "net_device_ops_ext" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_SET_VF_TRUST
endif
ifneq ($(shell grep -A 3 "net_device_ops_extended" $(LINUXSRC)/include/linux/netdevice.h | grep -o "ndo_set_vf_trust"),)
DISTRO_CFLAG += -DHAVE_NDO_SET_VF_TRUST
DISTRO_CFLAG += -DHAVE_NDO_SET_VF_TRUST_RH
endif
endif
ifneq ($(shell grep -o "ndo_set_vf_queues" $(LINUXSRC)/include/linux/netdevice.h),)
ifeq ($(shell grep -o "net_device_ops_ext" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_SET_VF_QUEUES
endif
endif
ifneq ($(shell grep -o "ndo_change_mtu_rh74" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_CHANGE_MTU_RH74
endif
ifneq ($(shell grep -o "RH_KABI_USE_P(16, struct net_device_extended \*extended)" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NET_DEVICE_EXT
endif
ifneq ($(shell grep -o "RH_KABI_EXTEND(struct net_device_ops_extended extended)" $(LINUXSRC)/include/linux/netdevice.h),)
ifneq ($(shell grep -o "ndo_get_phys_port_name" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_EXT_GET_PHYS_PORT_NAME
endif
endif
ifneq ($(shell grep -o "ndo_setup_tc_rh72" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_SETUP_TC_RH72
endif
ifneq ($(shell grep -o "(\*ndo_setup_tc_rh)" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_SETUP_TC_RH
endif
ifneq ($(shell grep -o "tc_setup_cb_egdev_call" $(LINUXSRC)/include/net/act_api.h),)
DISTRO_CFLAG += -DHAVE_TC_CB_EGDEV
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
ifneq ($(shell grep -o "enum tc_setup_type" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_TC_SETUP_TYPE
endif
ifneq ($(shell grep -so "tc_cls_flower_offload" $(LINUXSRC)/include/net/pkt_cls.h),)
DISTRO_CFLAG += -DHAVE_TC_CLS_FLOWER_OFFLOAD
endif
ifneq ($(shell grep -o "TC_SETUP_BLOCK" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_TC_SETUP_BLOCK
endif
ifneq ($(shell grep -o "TC_SETUP_QDISC_MQPRIO" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_TC_SETUP_QDISC_MQPRIO
endif
ifneq ($(shell grep -so "tcf_mirred_dev" $(LINUXSRC)/include/net/tc_act/tc_mirred.h),)
DISTRO_CFLAG += -DHAVE_TCF_MIRRED_DEV
endif
ifneq ($(shell grep -so "tc_cls_can_offload_and_chain0" $(LINUXSRC)/include/net/pkt_cls.h),)
DISTRO_CFLAG += -DHAVE_TC_CLS_CAN_OFFLOAD_AND_CHAIN0
endif
ifneq ($(shell grep -s -A 2 "tcf_block_cb_register" $(LINUXSRC)/include/net/pkt_cls.h | grep -o "netlink_ext_ack"),)
DISTRO_CFLAG += -DHAVE_TC_CB_REG_EXTACK
endif
ifneq ($(shell grep -so "tcf_exts_for_each_action" $(LINUXSRC)/include/net/pkt_cls.h),)
DISTRO_CFLAG += -DHAVE_TC_EXTS_FOR_ACTION
endif
ifneq ($(shell grep -s -A 3 "struct tc_cls_matchall_offload" $(LINUXSRC)/include/net/pkt_cls.h | grep -o "flow_rule"),)
DISTRO_CFLAG += -DHAVE_TC_MATCHALL_FLOW_RULE
endif
endif
ifneq ($(shell grep -so "FLOW_DISSECTOR_KEY_ICMP" $(LINUXSRC)/include/net/flow_dissector.h),)
DISTRO_CFLAG += -DHAVE_FLOW_DISSECTOR_KEY_ICMP
endif
ifneq ($(shell grep -so "rhashtable" $(LINUXSRC)/include/linux/rhashtable.h),)
DISTRO_CFLAG += -DHAVE_RHASHTABLE
endif
ifneq ($(shell grep -so "tcf_exts_to_list" $(LINUXSRC)/include/net/pkt_cls.h),)
DISTRO_CFLAG += -DHAVE_TCF_EXTS_TO_LIST
endif
ifneq ($(shell grep -so "tcf_exts_stats_update" $(LINUXSRC)/include/net/pkt_cls.h),)
DISTRO_CFLAG += -DHAVE_TCF_STATS_UPDATE
endif
ifneq ($(shell grep -so "tcf_exts_has_actions" $(LINUXSRC)/include/net/pkt_cls.h),)
DISTRO_CFLAG += -DHAVE_TCF_EXTS_HAS_ACTIONS
endif
ifneq ($(shell grep -so "is_tcf_tunnel_set" $(LINUXSRC)/include/net/tc_act/tc_tunnel_key.h),)
DISTRO_CFLAG += -DHAVE_TCF_TUNNEL
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_get_port_parent_id" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_GET_PORT_PARENT_ID
endif
ifneq ($(shell grep -o "net_device_ops_extended" $(LINUXSRC)/include/linux/netdevice.h),)
ifneq ($(shell grep -o "ndo_xdp_xmit" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_EXT_NDO_XDP_XMIT
endif
else ifneq ($(shell grep -o "ndo_xdp" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_XDP
ifneq ($(shell grep -o "ndo_bpf" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NDO_BPF
endif
ifneq ($(shell ls $(LINUXSRC)/include/net/bpf_trace.h > /dev/null 2>&1 && echo bpf_trace),)
DISTRO_CFLAG += -DHAVE_BPF_TRACE
endif
ifneq ($(shell grep -o "xdp_set_data_meta_invalid" $(LINUXSRC)/include/linux/filter.h),)
DISTRO_CFLAG += -DHAVE_XDP_SET_DATA_META_INVALID
endif
ifneq ($(shell grep -o "void bpf_prog_add" $(LINUXSRC)/include/linux/bpf.h),)
DISTRO_CFLAG += -DHAVE_VOID_BPF_PROG_ADD
endif
endif
ifneq ($(shell grep -so "enum xdp_action" $(LINUXSRC)/include/uapi/linux/bpf.h),)
DISTRO_CFLAG += -DHAVE_XDP_ACTION
endif
ifneq ($(shell grep -so "XDP_REDIRECT" $(LINUXSRC)/include/uapi/linux/bpf.h),)
DISTRO_CFLAG += -DHAVE_XDP_REDIRECT
endif
ifneq ($(shell grep -so "struct xdp_frame" $(LINUXSRC)/include/net/xdp.h),)
DISTRO_CFLAG += -DHAVE_XDP_FRAME
endif
ifneq ($(shell grep -so "enum xdp_mem_type" $(LINUXSRC)/include/net/xdp.h),)
DISTRO_CFLAG += -DHAVE_XDP_MEM_TYPE
endif
ifneq ($(shell grep -so "struct xdp_rxq_info" $(LINUXSRC)/include/net/xdp.h),)
DISTRO_CFLAG += -DHAVE_XDP_RXQ_INFO
ifneq ($(shell grep -o "xdp_rxq_info_is_reg" $(LINUXSRC)/include/net/xdp.h),)
DISTRO_CFLAG += -DHAVE_XDP_RXQ_INFO_IS_REG
endif
endif
ifneq ($(shell grep -so "page_pool_release_page" $(LINUXSRC)/include/net/page_pool.h),)
DISTRO_CFLAG += -DHAVE_PAGE_POOL_RELEASE_PAGE
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 "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 "prog_attached" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_PROG_ATTACHED
endif
ifneq ($(shell grep -o "netdev_xmit_more" $(LINUXSRC)/include/linux/netdevice.h),)
DISTRO_CFLAG += -DHAVE_NETDEV_XMIT_MORE
endif
ifneq ($(shell grep -A 1 "ndo_tx_timeout" $(LINUXSRC)/include/linux/netdevice.h | grep -o txqueue),)
DISTRO_CFLAG += -DHAVE_NDO_TX_TIMEOUT_QUEUE
endif
ifneq ($(shell grep -o "netpoll_poll_dev" $(LINUXSRC)/include/linux/netpoll.h),)
DISTRO_CFLAG += -DHAVE_NETPOLL_POLL_DEV
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 "kmalloc_array" $(LINUXSRC)/include/linux/slab.h),)
DISTRO_CFLAG += -DHAVE_KMALLOC_ARRAY
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_link_width" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG += -DHAVE_PCI_LINK_WIDTH
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 grep -o "pci_upstream_bridge" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG += -DHAVE_PCI_UPSTREAM_BRIDGE
endif
ifneq ($(shell grep -o "pcie_print_link_status" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG += -DHAVE_PCI_PRINT_LINK_STATUS
endif
ifneq ($(shell grep -o "_genl_register_family_with_ops_grps" $(LINUXSRC)/include/net/genetlink.h),)
DISTRO_CFLAG += -DHAVE_GENL_REG_OPS_GRPS
endif
ifneq ($(shell grep -o "pci_physfn" $(LINUXSRC)/include/linux/pci.h),)
DISTRO_CFLAG += -DHAVE_PCI_PHYSFN
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
ifneq ($(shell grep -o "time64_to_tm" $(LINUXSRC)/include/linux/time.h),)
DISTRO_CFLAG += -DHAVE_TIME64
endif
ifneq ($(shell grep -o "timer_setup" $(LINUXSRC)/include/linux/timer.h),)
DISTRO_CFLAG += -DHAVE_TIMER_SETUP
endif
ifneq ($(shell grep -s "devlink_ops" $(LINUXSRC)/include/net/devlink.h),)
DISTRO_CFLAG += -DHAVE_DEVLINK
endif
ifneq ($(shell grep -s "devlink_param" $(LINUXSRC)/include/net/devlink.h),)
DISTRO_CFLAG += -DHAVE_DEVLINK_PARAM
ifneq ($(shell grep -s -A 2 "int (\*validate)" $(LINUXSRC)/include/net/devlink.h | grep "struct netlink_ext_ack \*extack"),)
DISTRO_CFLAG += -DHAVE_DEVLINK_VALIDATE_NEW
endif
endif
ifneq ($(shell grep -s -A 7 "devlink_port_attrs" $(LINUXSRC)/include/net/devlink.h | grep -o "netdev_phys_item_id"),)
DISTRO_CFLAG += -DHAVE_DEVLINK_PORT_ATTRS
endif
ifneq ($(shell grep -s "ndo_get_devlink_port" $(LINUXSRC)/include/net/devlink.h),)
DISTRO_CFLAG += -DHAVE_NDO_DEVLINK_PORT
endif
ifneq ($(shell grep -s "devlink_port_params_register" $(LINUXSRC)/include/net/devlink.h),)
DISTRO_CFLAG += -DHAVE_DEVLINK_PORT_PARAM
endif
ifneq ($(shell grep -s "devlink_params_publish" $(LINUXSRC)/include/net/devlink.h),)
DISTRO_CFLAG += -DHAVE_DEVLINK_PARAM_PUBLISH
endif
ifneq ($(shell grep -s -A 1 "eswitch_mode_set" $(LINUXSRC)/include/net/devlink.h | grep -o "netlink_ext_ack"),)
DISTRO_CFLAG += -DHAVE_ESWITCH_MODE_SET_EXTACK
endif
ifneq ($(shell grep -so "DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI" $(LINUXSRC)/include/net/devlink.h),)
DISTRO_CFLAG += -DHAVE_IGNORE_ARI
endif
ifneq ($(shell grep -so "info_get" $(LINUXSRC)/include/net/devlink.h),)
DISTRO_CFLAG += -DHAVE_DEVLINK_INFO
endif
ifneq ($(shell grep -so "flash_update" $(LINUXSRC)/include/net/devlink.h),)
DISTRO_CFLAG += -DHAVE_DEVLINK_FLASH_UPDATE
endif
ifneq ($(shell grep -so "devlink_flash_update_status_notify" $(LINUXSRC)/include/net/devlink.h),)
DISTRO_CFLAG += -DHAVE_DEVLINK_FLASH_UPDATE_STATUS
endif
ifneq ($(shell grep -so "struct devlink_health_reporter" $(LINUXSRC)/include/net/devlink.h),)
DISTRO_CFLAG += -DHAVE_DEVLINK_HEALTH_REPORT
endif
ifneq ($(shell grep -so "devlink_health_reporter_state_update" $(LINUXSRC)/include/net/devlink.h),)
DISTRO_CFLAG += -DHAVE_DEVLINK_HEALTH_REPORTER_STATE_UPDATE
endif
ifneq ($(shell grep -s -A 1 "(*recover)" $(LINUXSRC)/include/net/devlink.h | grep netlink_ext_ack),)
DISTRO_CFLAG += -DHAVE_DEVLINK_HEALTH_REPORT_EXTACK
endif
ifneq ($(shell grep -so "devlink_health_reporter_recovery_done" $(LINUXSRC)/include/net/devlink.h),)
DISTRO_CFLAG += -DHAVE_DEVLINK_HEALTH_REPORTER_RECOVERY_DONE
endif
# Check if the file exists or not
ifneq ($(shell grep -s "switchdev_ops" $(LINUXSRC)/include/net/switchdev.h),)
DISTRO_CFLAG += -DHAVE_SWITCHDEV
endif
ifneq ($(shell grep -s "METADATA_HW_PORT_MUX" $(LINUXSRC)/include/net/dst_metadata.h),)
DISTRO_CFLAG += -DHAVE_METADATA_HW_PORT_MUX
endif
ifneq ($(shell grep -so "(*ieee_delapp)" $(LINUXSRC)/include/net/dcbnl.h),)
DISTRO_CFLAG += -DHAVE_IEEE_DELAPP
endif
ifneq ($(shell grep -o cpumask_local_spread $(LINUXSRC)/include/linux/cpumask.h),)
DISTRO_CFLAG += -DHAVE_CPUMASK_LOCAL_SPREAD
endif
ifneq ($(shell grep -o cpumask_set_cpu_local_first $(LINUXSRC)/include/linux/cpumask.h),)
DISTRO_CFLAG += -DHAVE_CPUMASK_LOCAL_FIRST
endif
ifeq ($(shell grep -so "ETH_RESET_AP" $(LINUXSRC)/include/$(UAPI)/linux/ethtool.h),)
DISTRO_CFLAG += -DNO_ETH_RESET_AP
endif
ifneq ($(shell ls $(LINUXSRC)/include/linux/dim.h > /dev/null 2>&1 && echo dim),)
DISTRO_CFLAG += -DHAVE_DIM
endif
ifneq ($(shell grep -o simple_open $(LINUXSRC)/include/linux/fs.h),)
DISTRO_CFLAG += -DHAVE_SIMPLE_OPEN
endif
ifneq ($(shell grep -o hwmon_device_register_with_groups $(LINUXSRC)/include/linux/hwmon.h),)
DISTRO_CFLAG += -DHAVE_NEW_HWMON_API
endif
EXTRA_CFLAGS += ${DISTRO_CFLAG} -g -DCHIMP_FW -D__LINUX -DCONFIG_BNXT_SRIOV -DCONFIG_BNXT_DCB -DCONFIG_BNXT_FLASHDEV -DHSI_DBG_DISABLE -DCONFIG_BNXT_LFC
cflags-y += $(EXTRA_CFLAGS)
BCM_DRV = bnxt_en.ko
ifneq ($(KERNELRELEASE),)
LINUX_VER=$(shell echo $(KVER) | cut -d "." -f1)
ifeq ($(shell expr $(LINUX_VER) \>= 5), 1)
BNXT_DBGFS_OBJ = bnxt_debugfs.o
else
BNXT_DBGFS_OBJ = bnxt_debugfs_cpt.o
endif
obj-$(CONFIG_BNXT) += 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 bnxt_vfr.o bnxt_tc.o bnxt_devlink.o bnxt_lfc.o bnxt_netlink.o bnxt_dim.o $(BNXT_DBGFS_OBJ) #decode_hsi.o
else
default:
ifeq ($(CROSS_COMPILE),)
make -C $(LINUX) M=$(shell pwd) modules
else ifneq ($(CROSS_COMPILE),)
make -C $(LINUXSRC) M=$(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
@if [ "$(KDIR)" != "" ]; then \
echo "Cannot use install with KDIR option"; exit 2;\
fi
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_ptp.o .bnxt_ptp.* bnxt_xdp.o .bnxt_xdp.* bnxt_lfc.o .bnxt_lfc.*
-rm -rf bnxt_vfr.o .bnxt_vfr.* bnxt_tc.o .bnxt_tc.* bnxt_devlink.o .bnxt_devlink.* bnxt_netlink.o .bnxt_netlink.*
-rm -rf bnxt_dim.o .bnxt_dim.* bnxt_debugfs*.o .bnxt_debugfs*
-rm -f Module.markers Module.symvers modules.order

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2018 Broadcom Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*/
#ifndef BNXT_COREDUMP_H
#define BNXT_COREDUMP_H
#if defined(ETHTOOL_GET_DUMP_FLAG) && !defined(GET_ETHTOOL_OP_EXT)
struct bnxt_coredump_segment_hdr {
__u8 signature[4];
__le32 component_id;
__le32 segment_id;
__le32 flags;
__u8 low_version;
__u8 high_version;
__le16 function_id;
__le32 offset;
__le32 length;
__le32 status;
__le32 duration;
__le32 data_offset;
__le32 instance;
__le32 rsvd[5];
};
struct bnxt_coredump_record {
__u8 signature[4];
__le32 flags;
__u8 low_version;
__u8 high_version;
__u8 asic_state;
__u8 rsvd0[5];
char system_name[32];
__le16 year;
__le16 month;
__le16 day;
__le16 hour;
__le16 minute;
__le16 second;
__le16 utc_bias;
__le16 rsvd1;
char commandline[256];
__le32 total_segments;
__le32 os_ver_major;
__le32 os_ver_minor;
__le32 rsvd2;
char os_name[32];
__le16 end_year;
__le16 end_month;
__le16 end_day;
__le16 end_hour;
__le16 end_minute;
__le16 end_second;
__le16 end_utc_bias;
__le32 asic_id1;
__le32 asic_id2;
__le32 coredump_status;
__u8 ioctl_low_version;
__u8 ioctl_high_version;
__le16 rsvd3[313];
};
#endif /* defined(ETHTOOL_GET_DUMP_FLAG) && !defined(GET_ETHTOOL_OP_EXT) */
#endif

View File

@ -15,17 +15,32 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <rdma/ib_verbs.h>
#include "bnxt_compat.h"
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_dcb.h"
#ifdef CONFIG_BNXT_DCB
static int bnxt_queue_to_tc(struct bnxt *bp, u8 queue_id)
{
int i, j;
for (i = 0; i < bp->max_tc; i++) {
if (bp->q_info[i].queue_id == queue_id) {
for (j = 0; j < bp->max_tc; j++) {
if (bp->tc_to_qidx[j] == i)
return j;
}
}
}
return -EINVAL;
}
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;
int i;
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 |
@ -33,13 +48,15 @@ static int bnxt_hwrm_queue_pri2cos_cfg(struct bnxt *bp, struct ieee_ets *ets)
pri2cos = &req.pri0_cos_queue_id;
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
u8 qidx;
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;
qidx = bp->tc_to_qidx[ets->prio_tc[i]];
pri2cos[i] = bp->q_info[qidx].queue_id;
}
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
return rc;
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
static int bnxt_hwrm_queue_pri2cos_qcfg(struct bnxt *bp, struct ieee_ets *ets)
@ -55,17 +72,15 @@ static int bnxt_hwrm_queue_pri2cos_qcfg(struct bnxt *bp, struct ieee_ets *ets)
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc) {
u8 *pri2cos = &resp->pri0_cos_queue_id;
int i, j;
int i;
for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
u8 queue_id = pri2cos[i];
int tc;
for (j = 0; j < bp->max_tc; j++) {
if (bp->q_info[j].queue_id == queue_id) {
ets->prio_tc[i] = j;
break;
}
}
tc = bnxt_queue_to_tc(bp, queue_id);
if (tc >= 0)
ets->prio_tc[i] = tc;
}
}
mutex_unlock(&bp->hwrm_cmd_lock);
@ -77,17 +92,19 @@ static int bnxt_hwrm_queue_cos2bw_cfg(struct bnxt *bp, struct ieee_ets *ets,
{
struct hwrm_queue_cos2bw_cfg_input req = {0};
struct bnxt_cos2bw_cfg cos2bw;
int rc = 0, i;
void *data;
int i;
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) {
for (i = 0; i < max_tc; i++) {
u8 qidx = bp->tc_to_qidx[i];
req.enables |= cpu_to_le32(
QUEUE_COS2BW_CFG_REQ_ENABLES_COS_QUEUE_ID0_VALID << i);
QUEUE_COS2BW_CFG_REQ_ENABLES_COS_QUEUE_ID0_VALID <<
qidx);
memset(&cos2bw, 0, sizeof(cos2bw));
cos2bw.queue_id = bp->q_info[i].queue_id;
cos2bw.queue_id = bp->q_info[qidx].queue_id;
if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_STRICT) {
cos2bw.tsa =
QUEUE_COS2BW_QCFG_RESP_QUEUE_ID0_TSA_ASSIGN_SP;
@ -103,14 +120,14 @@ static int bnxt_hwrm_queue_cos2bw_cfg(struct bnxt *bp, struct ieee_ets *ets,
cpu_to_le32((ets->tc_tx_bw[i] * 100) |
BW_VALUE_UNIT_PERCENT1_100);
}
data = &req.unused_0 + qidx * (sizeof(cos2bw) - 4);
memcpy(data, &cos2bw.queue_id, sizeof(cos2bw) - 4);
if (i == 0) {
if (qidx == 0) {
req.queue_id0 = cos2bw.queue_id;
req.unused_0 = 0;
}
}
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
return rc;
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
static int bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt *bp, struct ieee_ets *ets)
@ -132,66 +149,81 @@ static int bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt *bp, struct ieee_ets *ets)
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;
int tc;
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;
}
tc = bnxt_queue_to_tc(bp, cos2bw.queue_id);
if (tc < 0)
continue;
if (cos2bw.tsa ==
QUEUE_COS2BW_QCFG_RESP_QUEUE_ID0_TSA_ASSIGN_SP) {
ets->tc_tsa[tc] = IEEE_8021QAZ_TSA_STRICT;
} else {
ets->tc_tsa[tc] = IEEE_8021QAZ_TSA_ETS;
ets->tc_tx_bw[tc] = cos2bw.bw_weight;
}
}
mutex_unlock(&bp->hwrm_cmd_lock);
return 0;
}
static int bnxt_hwrm_queue_cfg(struct bnxt *bp, unsigned int lltc_mask)
static int bnxt_queue_remap(struct bnxt *bp, unsigned int lltc_mask)
{
struct hwrm_queue_cfg_input req = {0};
int i;
unsigned long qmap = 0;
int max = bp->max_tc;
int i, j, rc;
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++) {
/* Assign lossless TCs first */
for (i = 0, j = 0; i < max; ) {
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 (BNXT_LLQ(bp->q_info[j].queue_profile)) {
bp->tc_to_qidx[i] = j;
__set_bit(j, &qmap);
i++;
}
j++;
continue;
}
i++;
}
for (i = 0, j = 0; i < max; i++) {
if (lltc_mask & (1 << i))
continue;
j = find_next_zero_bit(&qmap, max, j);
bp->tc_to_qidx[i] = j;
__set_bit(j, &qmap);
j++;
}
if (netif_running(bp->dev)) {
bnxt_close_nic(bp, false, false);
rc = bnxt_open_nic(bp, false, false);
if (rc) {
netdev_warn(bp->dev, "failed to open NIC, rc = %d\n", rc);
return rc;
}
}
if (netif_running(bp->dev))
bnxt_tx_enable(bp);
if (bp->ieee_ets) {
int tc = netdev_get_num_tc(bp->dev);
if (!tc)
tc = 1;
rc = bnxt_hwrm_queue_cos2bw_cfg(bp, bp->ieee_ets, tc);
if (rc) {
netdev_warn(bp->dev, "failed to config BW, rc = %d\n", rc);
return rc;
}
rc = bnxt_hwrm_queue_pri2cos_cfg(bp, bp->ieee_ets);
if (rc) {
netdev_warn(bp->dev, "failed to config prio, rc = %d\n", rc);
return rc;
}
}
return 0;
}
@ -201,8 +233,7 @@ static int bnxt_hwrm_queue_pfc_cfg(struct bnxt *bp, struct ieee_pfc *pfc)
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;
bool need_q_remap = false;
if (!my_ets)
return -EINVAL;
@ -221,23 +252,23 @@ static int bnxt_hwrm_queue_pfc_cfg(struct bnxt *bp, struct ieee_pfc *pfc)
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;
u8 qidx = bp->tc_to_qidx[i];
if (!BNXT_LLQ(bp->q_info[qidx].queue_profile)) {
need_q_remap = true;
break;
}
}
}
if (need_q_recfg)
rc = bnxt_hwrm_queue_cfg(bp, tc_mask);
if (need_q_remap)
bnxt_queue_remap(bp, tc_mask);
return rc;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PFCENABLE_CFG, -1, -1);
req.flags = cpu_to_le32(pri_mask);
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
static int bnxt_hwrm_queue_pfc_qcfg(struct bnxt *bp, struct ieee_pfc *pfc)
@ -278,12 +309,11 @@ static int bnxt_hwrm_set_dcbx_app(struct bnxt *bp, struct dcb_app *app,
n = IEEE_8021QAZ_MAX_TCS;
data_len = sizeof(*data) + sizeof(*fw_app) * n;
data = dma_alloc_coherent(&bp->pdev->dev, data_len, &mapping,
GFP_KERNEL);
data = dma_zalloc_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);
@ -340,14 +370,66 @@ static int bnxt_hwrm_set_dcbx_app(struct bnxt *bp, struct dcb_app *app,
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_hwrm_queue_dscp_qcaps(struct bnxt *bp)
{
struct hwrm_queue_dscp_qcaps_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_queue_dscp_qcaps_input req = {0};
int rc;
bp->max_dscp_value = 0;
if (bp->hwrm_spec_code < 0x10800 || BNXT_VF(bp))
return 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_DSCP_QCAPS, -1, -1);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc) {
bp->max_dscp_value = (1 << resp->num_dscp_bits) - 1;
if (bp->max_dscp_value < 0x3f)
bp->max_dscp_value = 0;
}
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int bnxt_hwrm_queue_dscp2pri_cfg(struct bnxt *bp, struct dcb_app *app,
bool add)
{
struct hwrm_queue_dscp2pri_cfg_input req = {0};
struct bnxt_dscp2pri_entry *dscp2pri;
dma_addr_t mapping;
int rc;
if (bp->hwrm_spec_code < 0x10800)
return 0;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_DSCP2PRI_CFG, -1, -1);
dscp2pri = dma_alloc_coherent(&bp->pdev->dev, sizeof(*dscp2pri),
&mapping, GFP_KERNEL);
if (!dscp2pri)
return -ENOMEM;
req.src_data_addr = cpu_to_le64(mapping);
dscp2pri->dscp = app->protocol;
if (add)
dscp2pri->mask = 0x3f;
else
dscp2pri->mask = 0;
dscp2pri->pri = app->priority;
req.entry_cnt = cpu_to_le16(1);
rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
dma_free_coherent(&bp->pdev->dev, sizeof(*dscp2pri), dscp2pri,
mapping);
return rc;
}
static int bnxt_ets_validate(struct bnxt *bp, struct ieee_ets *ets, u8 *tc)
{
int total_ets_bw = 0;
@ -379,7 +461,10 @@ static int bnxt_ets_validate(struct bnxt *bp, struct ieee_ets *ets, u8 *tc)
if (total_ets_bw > 100)
return -EINVAL;
*tc = max_tc + 1;
if (max_tc >= bp->max_tc)
*tc = bp->max_tc;
else
*tc = max_tc + 1;
return 0;
}
@ -514,25 +599,43 @@ static int bnxt_dcbnl_ieee_setpfc(struct net_device *dev, struct ieee_pfc *pfc)
return rc;
}
static int bnxt_dcbnl_ieee_dscp_app_prep(struct bnxt *bp, struct dcb_app *app)
{
if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP) {
if (!bp->max_dscp_value)
return -ENOTSUPP;
if (app->protocol > bp->max_dscp_value)
return -EINVAL;
}
return 0;
}
static int bnxt_dcbnl_ieee_setapp(struct net_device *dev, struct dcb_app *app)
{
struct bnxt *bp = netdev_priv(dev);
int rc = -EINVAL;
int rc;
if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
!(bp->dcbx_cap & DCB_CAP_DCBX_HOST))
return -EINVAL;
rc = bnxt_dcbnl_ieee_dscp_app_prep(bp, app);
if (rc)
return rc;
rc = dcb_ieee_setapp(dev, app);
if (rc)
return rc;
if ((app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
app->protocol == ETH_P_IBOE) ||
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);
if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
rc = bnxt_hwrm_queue_dscp2pri_cfg(bp, app, true);
return rc;
}
@ -545,15 +648,22 @@ static int bnxt_dcbnl_ieee_delapp(struct net_device *dev, struct dcb_app *app)
!(bp->dcbx_cap & DCB_CAP_DCBX_HOST))
return -EINVAL;
rc = bnxt_dcbnl_ieee_dscp_app_prep(bp, app);
if (rc)
return rc;
rc = dcb_ieee_delapp(dev, app);
if (rc)
return rc;
if ((app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
app->protocol == ETH_P_IBOE) ||
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);
if (app->selector == IEEE_8021QAZ_APP_SEL_DSCP)
rc = bnxt_hwrm_queue_dscp2pri_cfg(bp, app, false);
return rc;
}
@ -573,7 +683,7 @@ static u8 bnxt_dcbnl_setdcbx(struct net_device *dev, u8 mode)
return 1;
if (mode & DCB_CAP_DCBX_HOST) {
if (BNXT_VF(bp) || (bp->flags & BNXT_FLAG_FW_LLDP_AGENT))
if (BNXT_VF(bp) || (bp->fw_cap & BNXT_FW_CAP_LLDP_AGENT))
return 1;
/* only support IEEE */
@ -602,13 +712,15 @@ static const struct dcbnl_rtnl_ops dcbnl_ops = {
void bnxt_dcb_init(struct bnxt *bp)
{
bp->dcbx_cap = 0;
if (bp->hwrm_spec_code < 0x10501)
return;
bnxt_hwrm_queue_dscp_qcaps(bp);
bp->dcbx_cap = DCB_CAP_DCBX_VER_IEEE;
if (BNXT_PF(bp) && !(bp->flags & BNXT_FLAG_FW_LLDP_AGENT))
if (BNXT_PF(bp) && !(bp->fw_cap & BNXT_FW_CAP_LLDP_AGENT))
bp->dcbx_cap |= DCB_CAP_DCBX_HOST;
else if (bp->flags & BNXT_FLAG_FW_DCBX_AGENT)
else if (bp->fw_cap & BNXT_FW_CAP_DCBX_AGENT)
bp->dcbx_cap |= DCB_CAP_DCBX_LLD_MANAGED;
bp->dev->dcbnl_ops = &dcbnl_ops;
}

View File

@ -33,11 +33,19 @@ struct bnxt_cos2bw_cfg {
u8 unused;
};
struct bnxt_dscp2pri_entry {
u8 dscp;
u8 mask;
u8 pri;
};
#define BNXT_LLQ(q_profile) \
((q_profile) == QUEUE_QPORTCFG_RESP_QUEUE_ID0_SERVICE_PROFILE_LOSSLESS)
((q_profile) == QUEUE_QPORTCFG_RESP_QUEUE_ID0_SERVICE_PROFILE_LOSSLESS_ROCE)
#define BNXT_CNPQ(q_profile) \
((q_profile) == QUEUE_QPORTCFG_RESP_QUEUE_ID0_SERVICE_PROFILE_LOSSY_ROCE_CNP)
#define HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL 0x0300
void bnxt_dcb_init(struct bnxt *bp);
void bnxt_dcb_free(struct bnxt *bp);
void bnxt_dcb_init(struct bnxt *);
void bnxt_dcb_free(struct bnxt *);
#endif

View File

@ -0,0 +1,115 @@
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2017-2018 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/debugfs.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "bnxt_hsi.h"
#include "bnxt_compat.h"
#ifdef HAVE_DIM
#include <linux/dim.h>
#else
#include "bnxt_dim.h"
#endif
#include "bnxt.h"
#ifdef CONFIG_DEBUG_FS
static struct dentry *bnxt_debug_mnt;
static ssize_t debugfs_dim_read(struct file *filep,
char __user *buffer,
size_t count, loff_t *ppos)
{
struct dim *dim = filep->private_data;
int len;
char *buf;
if (*ppos)
return 0;
if (!dim)
return -ENODEV;
buf = kasprintf(GFP_KERNEL,
"state = %d\n" \
"profile_ix = %d\n" \
"mode = %d\n" \
"tune_state = %d\n" \
"steps_right = %d\n" \
"steps_left = %d\n" \
"tired = %d\n",
dim->state,
dim->profile_ix,
dim->mode,
dim->tune_state,
dim->steps_right,
dim->steps_left,
dim->tired);
if (!buf)
return -ENOMEM;
if (count < strlen(buf)) {
kfree(buf);
return -ENOSPC;
}
len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
kfree(buf);
return len;
}
static const struct file_operations debugfs_dim_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = debugfs_dim_read,
};
static void debugfs_dim_ring_init(struct dim *dim, int ring_idx,
struct dentry *dd)
{
static char qname[16];
snprintf(qname, 10, "%d", ring_idx);
debugfs_create_file(qname, 0600, dd, dim, &debugfs_dim_fops);
}
void bnxt_debug_dev_init(struct bnxt *bp)
{
const char *pname = pci_name(bp->pdev);
struct dentry *dir;
int i;
bp->debugfs_pdev = debugfs_create_dir(pname, bnxt_debug_mnt);
dir = debugfs_create_dir("dim", bp->debugfs_pdev);
/* create files for each rx ring */
for (i = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_cp_ring_info *cpr = &bp->bnapi[i]->cp_ring;
if (cpr && bp->bnapi[i]->rx_ring)
debugfs_dim_ring_init(&cpr->dim, i, dir);
}
}
void bnxt_debug_dev_exit(struct bnxt *bp)
{
if (bp) {
debugfs_remove_recursive(bp->debugfs_pdev);
bp->debugfs_pdev = NULL;
}
}
void bnxt_debug_init(void)
{
bnxt_debug_mnt = debugfs_create_dir("bnxt_en", NULL);
}
void bnxt_debug_exit(void)
{
debugfs_remove_recursive(bnxt_debug_mnt);
}
#endif /* CONFIG_DEBUG_FS */

View File

@ -0,0 +1,23 @@
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2017-2018 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 "bnxt_hsi.h"
#include "bnxt.h"
#ifdef CONFIG_DEBUG_FS
void bnxt_debug_init(void);
void bnxt_debug_exit(void);
void bnxt_debug_dev_init(struct bnxt *bp);
void bnxt_debug_dev_exit(struct bnxt *bp);
#else
static inline void bnxt_debug_init(void) {}
static inline void bnxt_debug_exit(void) {}
static inline void bnxt_debug_dev_init(struct bnxt *bp) {}
static inline void bnxt_debug_dev_exit(struct bnxt *bp) {}
#endif

View File

@ -0,0 +1,132 @@
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2017-2018 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/debugfs.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "bnxt_hsi.h"
#include "bnxt_compat.h"
#ifdef HAVE_DIM
#include <linux/dim.h>
#else
#include "bnxt_dim.h"
#endif
#include "bnxt.h"
#ifdef CONFIG_DEBUG_FS
static struct dentry *bnxt_debug_mnt;
static ssize_t debugfs_dim_read(struct file *filep,
char __user *buffer,
size_t count, loff_t *ppos)
{
struct dim *dim = filep->private_data;
int len;
char *buf;
if (*ppos)
return 0;
if (!dim)
return -ENODEV;
buf = kasprintf(GFP_KERNEL,
"state = %d\n" \
"profile_ix = %d\n" \
"mode = %d\n" \
"tune_state = %d\n" \
"steps_right = %d\n" \
"steps_left = %d\n" \
"tired = %d\n",
dim->state,
dim->profile_ix,
dim->mode,
dim->tune_state,
dim->steps_right,
dim->steps_left,
dim->tired);
if (!buf)
return -ENOMEM;
if (count < strlen(buf)) {
kfree(buf);
return -ENOSPC;
}
len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
kfree(buf);
return len;
}
static const struct file_operations debugfs_dim_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = debugfs_dim_read,
};
static struct dentry *debugfs_dim_ring_init(struct dim *dim, int ring_idx,
struct dentry *dd)
{
static char qname[16];
snprintf(qname, 10, "%d", ring_idx);
return debugfs_create_file(qname, 0600, dd,
dim, &debugfs_dim_fops);
}
void bnxt_debug_dev_init(struct bnxt *bp)
{
const char *pname = pci_name(bp->pdev);
struct dentry *pdevf;
int i;
bp->debugfs_pdev = debugfs_create_dir(pname, bnxt_debug_mnt);
if (bp->debugfs_pdev) {
pdevf = debugfs_create_dir("dim", bp->debugfs_pdev);
if (!pdevf) {
pr_err("failed to create debugfs entry %s/dim\n",
pname);
return;
}
bp->debugfs_dim = pdevf;
/* create files for each rx ring */
for (i = 0; i < bp->cp_nr_rings; i++) {
struct bnxt_cp_ring_info *cpr = &bp->bnapi[i]->cp_ring;
if (cpr && bp->bnapi[i]->rx_ring) {
pdevf = debugfs_dim_ring_init(&cpr->dim, i,
bp->debugfs_dim);
if (!pdevf)
pr_err("failed to create debugfs entry %s/dim/%d\n",
pname, i);
}
}
} else {
pr_err("failed to create debugfs entry %s\n", pname);
}
}
void bnxt_debug_dev_exit(struct bnxt *bp)
{
if (bp) {
debugfs_remove_recursive(bp->debugfs_pdev);
bp->debugfs_pdev = NULL;
}
}
void bnxt_debug_init(void)
{
bnxt_debug_mnt = debugfs_create_dir("bnxt_en", NULL);
if (!bnxt_debug_mnt)
pr_err("failed to init bnxt_en debugfs\n");
}
void bnxt_debug_exit(void)
{
debugfs_remove_recursive(bnxt_debug_mnt);
}
#endif /* CONFIG_DEBUG_FS */

View File

@ -0,0 +1,815 @@
/* 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/pci.h>
#include <linux/netdevice.h>
#if defined(CONFIG_VF_REPS) || defined(HAVE_DEVLINK_PARAM)
#include <net/devlink.h>
#endif
#include "bnxt_compat.h"
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_vfr.h"
#include "bnxt_devlink.h"
#include "bnxt_ethtool.h"
#if defined(CONFIG_VF_REPS) || defined(HAVE_DEVLINK_PARAM)
#ifdef HAVE_DEVLINK_INFO
static void bnxt_copy_from_nvm_data(union devlink_param_value *dst,
union bnxt_nvm_data *src,
int nvm_num_bits, int dl_num_bytes);
static int bnxt_hwrm_get_nvm_cfg_ver(struct bnxt *bp,
union devlink_param_value *nvm_cfg_ver)
{
struct hwrm_nvm_get_variable_input req = {0};
union bnxt_nvm_data *data;
dma_addr_t data_dma_addr;
int rc;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1);
data = dma_zalloc_coherent(&bp->pdev->dev, sizeof(*data),
&data_dma_addr, GFP_KERNEL);
if (!data)
return -ENOMEM;
req.dest_data_addr = cpu_to_le64(data_dma_addr);
req.data_len = cpu_to_le16(BNXT_NVM_CFG_VER_BITS);
req.option_num = cpu_to_le16(NVM_OFF_NVM_CFG_VER);
rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc)
bnxt_copy_from_nvm_data(nvm_cfg_ver, data,
BNXT_NVM_CFG_VER_BITS,
BNXT_NVM_CFG_VER_BYTES);
dma_free_coherent(&bp->pdev->dev, sizeof(*data), data, data_dma_addr);
return rc;
}
static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
struct netlink_ext_ack *extack)
{
struct bnxt *bp = bnxt_get_bp_from_dl(dl);
union devlink_param_value nvm_cfg_ver;
struct hwrm_ver_get_output *ver_resp;
char mgmt_ver[FW_VER_STR_LEN];
char roce_ver[FW_VER_STR_LEN];
char fw_ver[FW_VER_STR_LEN];
char buf[32];
int rc;
rc = devlink_info_driver_name_put(req, DRV_MODULE_NAME);
if (rc)
return rc;
sprintf(buf, "%X", bp->chip_num);
rc = devlink_info_version_fixed_put(req,
DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, buf);
if (rc)
return rc;
ver_resp = &bp->ver_resp;
sprintf(buf, "%X", ver_resp->chip_rev);
rc = devlink_info_version_fixed_put(req,
DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, buf);
if (rc)
return rc;
if (BNXT_PF(bp) && (bp->flags & BNXT_FLAG_DSN_VALID)) {
sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
bp->dsn[7], bp->dsn[6], bp->dsn[5], bp->dsn[4],
bp->dsn[3], bp->dsn[2], bp->dsn[1], bp->dsn[0]);
rc = devlink_info_serial_number_put(req, buf);
if (rc)
return rc;
}
if (strlen(ver_resp->active_pkg_name)) {
rc =
devlink_info_version_running_put(req,
DEVLINK_INFO_VERSION_GENERIC_FW,
ver_resp->active_pkg_name);
if (rc)
return rc;
}
if (BNXT_PF(bp) && !bnxt_hwrm_get_nvm_cfg_ver(bp, &nvm_cfg_ver)) {
u32 ver = nvm_cfg_ver.vu32;
sprintf(buf, "%X.%X.%X", (ver >> 16) & 0xF, (ver >> 8) & 0xF,
ver & 0xF);
rc = devlink_info_version_running_put(req,
DEVLINK_INFO_VERSION_GENERIC_FW_PSID, buf);
if (rc)
return rc;
}
if (ver_resp->flags & VER_GET_RESP_FLAGS_EXT_VER_AVAIL) {
snprintf(fw_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
ver_resp->hwrm_fw_major, ver_resp->hwrm_fw_minor,
ver_resp->hwrm_fw_build, ver_resp->hwrm_fw_patch);
snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
ver_resp->mgmt_fw_major, ver_resp->mgmt_fw_minor,
ver_resp->mgmt_fw_build, ver_resp->mgmt_fw_patch);
snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
ver_resp->roce_fw_major, ver_resp->roce_fw_minor,
ver_resp->roce_fw_build, ver_resp->roce_fw_patch);
} else {
snprintf(fw_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
ver_resp->hwrm_fw_maj_8b, ver_resp->hwrm_fw_min_8b,
ver_resp->hwrm_fw_bld_8b, ver_resp->hwrm_fw_rsvd_8b);
snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
ver_resp->mgmt_fw_maj_8b, ver_resp->mgmt_fw_min_8b,
ver_resp->mgmt_fw_bld_8b, ver_resp->mgmt_fw_rsvd_8b);
snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d",
ver_resp->roce_fw_maj_8b, ver_resp->roce_fw_min_8b,
ver_resp->roce_fw_bld_8b, ver_resp->roce_fw_rsvd_8b);
}
rc = devlink_info_version_running_put(req,
DEVLINK_INFO_VERSION_GENERIC_FW_APP, fw_ver);
if (rc)
return rc;
if (!(bp->flags & BNXT_FLAG_CHIP_P5)) {
rc = devlink_info_version_running_put(req,
DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver);
if (rc)
return rc;
rc = devlink_info_version_running_put(req,
DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver);
if (rc)
return rc;
}
return 0;
}
#endif /* HAVE_DEVLINK_INFO */
#ifdef HAVE_DEVLINK_FLASH_UPDATE
static int
bnxt_dl_flash_update(struct devlink *dl, const char *filename,
const char *region, struct netlink_ext_ack *extack)
{
struct bnxt *bp = bnxt_get_bp_from_dl(dl);
int rc;
if (region)
return -EOPNOTSUPP;
if (!BNXT_PF(bp)) {
NL_SET_ERR_MSG_MOD(extack,
"flash update not supported from a VF");
return -EPERM;
}
devlink_flash_update_begin_notify(dl);
devlink_flash_update_status_notify(dl, "Preparing to flash", region, 0,
0);
rc = bnxt_flash_package_from_file(bp->dev, filename, 0);
if (!rc)
devlink_flash_update_status_notify(dl, "Flashing done", region,
0, 0);
else
devlink_flash_update_status_notify(dl, "Flashing failed",
region, 0, 0);
devlink_flash_update_end_notify(dl);
return rc;
}
#endif /* HAVE_DEVLINK_FLASH_UPDATE */
#ifdef HAVE_DEVLINK_HEALTH_REPORT
static int bnxt_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
struct devlink_fmsg *fmsg,
struct netlink_ext_ack *extack)
{
struct bnxt *bp = devlink_health_reporter_priv(reporter);
u32 val, health_status;
int rc;
if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
return 0;
val = bnxt_fw_health_readl(bp, BNXT_FW_HEALTH_REG);
health_status = val & 0xffff;
if (health_status < BNXT_FW_STATUS_HEALTHY) {
rc = devlink_fmsg_string_pair_put(fmsg, "Description",
"Not yet completed initialization");
if (rc)
return rc;
} else if (health_status > BNXT_FW_STATUS_HEALTHY) {
rc = devlink_fmsg_string_pair_put(fmsg, "Description",
"Encountered fatal error and cannot recover");
if (rc)
return rc;
}
if (val >> 16) {
rc = devlink_fmsg_u32_pair_put(fmsg, "Error code", val >> 16);
if (rc)
return rc;
}
val = bnxt_fw_health_readl(bp, BNXT_FW_RESET_CNT_REG);
rc = devlink_fmsg_u32_pair_put(fmsg, "Reset count", val);
if (rc)
return rc;
return 0;
}
static const struct devlink_health_reporter_ops bnxt_dl_fw_reporter_ops = {
.name = "fw",
.diagnose = bnxt_fw_reporter_diagnose,
};
static int bnxt_fw_reset_recover(struct devlink_health_reporter *reporter,
void *priv_ctx,
struct netlink_ext_ack *extack)
{
struct bnxt *bp = devlink_health_reporter_priv(reporter);
if (!priv_ctx)
return -EOPNOTSUPP;
bnxt_fw_reset(bp);
#ifdef HAVE_DEVLINK_HEALTH_REPORTER_RECOVERY_DONE
return -EINPROGRESS;
#else
return 0;
#endif
}
static const
struct devlink_health_reporter_ops bnxt_dl_fw_reset_reporter_ops = {
.name = "fw_reset",
.recover = bnxt_fw_reset_recover,
};
static int bnxt_fw_fatal_recover(struct devlink_health_reporter *reporter,
void *priv_ctx,
struct netlink_ext_ack *extack)
{
struct bnxt *bp = devlink_health_reporter_priv(reporter);
struct bnxt_fw_reporter_ctx *fw_reporter_ctx = priv_ctx;
unsigned long event;
if (!priv_ctx)
return -EOPNOTSUPP;
bp->fw_health->fatal = true;
event = fw_reporter_ctx->sp_event;
if (event == BNXT_FW_RESET_NOTIFY_SP_EVENT)
bnxt_fw_reset(bp);
else if (event == BNXT_FW_EXCEPTION_SP_EVENT)
bnxt_fw_exception(bp);
#ifdef HAVE_DEVLINK_HEALTH_REPORTER_RECOVERY_DONE
return -EINPROGRESS;
#else
return 0;
#endif
}
static const
struct devlink_health_reporter_ops bnxt_dl_fw_fatal_reporter_ops = {
.name = "fw_fatal",
.recover = bnxt_fw_fatal_recover,
};
void bnxt_dl_fw_reporters_create(struct bnxt *bp)
{
struct bnxt_fw_health *health = bp->fw_health;
if (!bp->dl || !health)
return;
if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET) || health->fw_reset_reporter)
goto err_recovery;
health->fw_reset_reporter =
devlink_health_reporter_create(bp->dl,
&bnxt_dl_fw_reset_reporter_ops,
0, true, bp);
if (IS_ERR(health->fw_reset_reporter)) {
netdev_warn(bp->dev, "Failed to create FW reset health reporter, rc = %ld\n",
PTR_ERR(health->fw_reset_reporter));
health->fw_reset_reporter = NULL;
bp->fw_cap &= ~BNXT_FW_CAP_HOT_RESET;
}
err_recovery:
if (!(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY))
return;
if (!health->fw_reporter) {
health->fw_reporter =
devlink_health_reporter_create(bp->dl,
&bnxt_dl_fw_reporter_ops,
0, false, bp);
if (IS_ERR(health->fw_reporter)) {
netdev_warn(bp->dev, "Failed to create FW health reporter, rc = %ld\n",
PTR_ERR(health->fw_reporter));
health->fw_reporter = NULL;
bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
return;
}
}
if (health->fw_fatal_reporter)
return;
health->fw_fatal_reporter =
devlink_health_reporter_create(bp->dl,
&bnxt_dl_fw_fatal_reporter_ops,
0, true, bp);
if (IS_ERR(health->fw_fatal_reporter)) {
netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n",
PTR_ERR(health->fw_fatal_reporter));
health->fw_fatal_reporter = NULL;
bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
}
}
void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all)
{
struct bnxt_fw_health *health = bp->fw_health;
if (!bp->dl || !health)
return;
if ((all || !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) &&
health->fw_reset_reporter) {
devlink_health_reporter_destroy(health->fw_reset_reporter);
health->fw_reset_reporter = NULL;
}
if ((bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY) && !all)
return;
if (health->fw_reporter) {
devlink_health_reporter_destroy(health->fw_reporter);
health->fw_reporter = NULL;
}
if (health->fw_fatal_reporter) {
devlink_health_reporter_destroy(health->fw_fatal_reporter);
health->fw_fatal_reporter = NULL;
}
}
void bnxt_devlink_health_report(struct bnxt *bp, unsigned long event)
{
struct bnxt_fw_health *fw_health = bp->fw_health;
struct bnxt_fw_reporter_ctx fw_reporter_ctx;
fw_reporter_ctx.sp_event = event;
switch (event) {
case BNXT_FW_RESET_NOTIFY_SP_EVENT:
if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state)) {
if (!fw_health->fw_fatal_reporter)
return;
devlink_health_report(fw_health->fw_fatal_reporter,
"FW fatal async event received",
&fw_reporter_ctx);
return;
}
if (!fw_health->fw_reset_reporter)
return;
devlink_health_report(fw_health->fw_reset_reporter,
"FW non-fatal reset event received",
&fw_reporter_ctx);
return;
case BNXT_FW_EXCEPTION_SP_EVENT:
if (!fw_health->fw_fatal_reporter)
return;
devlink_health_report(fw_health->fw_fatal_reporter,
"FW fatal error reported",
&fw_reporter_ctx);
return;
}
}
void bnxt_dl_health_status_update(struct bnxt *bp, bool healthy)
{
struct bnxt_fw_health *health = bp->fw_health;
u8 state;
if (healthy)
state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
else
state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
if (health->fatal)
devlink_health_reporter_state_update(health->fw_fatal_reporter,
state);
else
devlink_health_reporter_state_update(health->fw_reset_reporter,
state);
health->fatal = false;
}
void bnxt_dl_health_recovery_done(struct bnxt *bp)
{
struct bnxt_fw_health *hlth = bp->fw_health;
if (hlth->fatal)
devlink_health_reporter_recovery_done(hlth->fw_fatal_reporter);
else
devlink_health_reporter_recovery_done(hlth->fw_reset_reporter);
}
#endif /* HAVE_DEVLINK_HEALTH_REPORT */
static const struct devlink_ops bnxt_dl_ops = {
#ifdef CONFIG_VF_REPS
#ifdef CONFIG_BNXT_SRIOV
.eswitch_mode_set = bnxt_dl_eswitch_mode_set,
.eswitch_mode_get = bnxt_dl_eswitch_mode_get,
#endif /* CONFIG_BNXT_SRIOV */
#endif /* CONFIG_VF_REPS */
#ifdef HAVE_DEVLINK_INFO
.info_get = bnxt_dl_info_get,
#endif /* HAVE_DEVLINK_INFO */
#ifdef HAVE_DEVLINK_FLASH_UPDATE
.flash_update = bnxt_dl_flash_update,
#endif /* HAVE_DEVLINK_FLASH_UPDATE */
};
static const struct devlink_ops bnxt_vf_dl_ops = {
#ifdef HAVE_DEVLINK_INFO
.info_get = bnxt_dl_info_get,
#endif /* HAVE_DEVLINK_INFO */
};
#ifdef HAVE_DEVLINK_PARAM
enum bnxt_dl_param_id {
BNXT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
};
static const struct bnxt_dl_nvm_param nvm_params[] = {
{DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV,
BNXT_NVM_SHARED_CFG, 1, 1},
#ifdef HAVE_IGNORE_ARI
{DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, NVM_OFF_IGNORE_ARI,
BNXT_NVM_SHARED_CFG, 1, 1},
{DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
NVM_OFF_MSIX_VEC_PER_PF_MAX, BNXT_NVM_SHARED_CFG, 10, 4},
{DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
NVM_OFF_MSIX_VEC_PER_PF_MIN, BNXT_NVM_SHARED_CFG, 7, 4},
#endif
{BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, NVM_OFF_DIS_GRE_VER_CHECK,
BNXT_NVM_SHARED_CFG, 1, 1},
};
static void bnxt_copy_to_nvm_data(union bnxt_nvm_data *dst,
union devlink_param_value *src,
int nvm_num_bits, int dl_num_bytes)
{
u32 val32 = 0;
if (nvm_num_bits == 1) {
dst->val8 = src->vbool;
return;
}
if (dl_num_bytes == 4)
val32 = src->vu32;
else if (dl_num_bytes == 2)
val32 = (u32)src->vu16;
else if (dl_num_bytes == 1)
val32 = (u32)src->vu8;
dst->val32 = cpu_to_le32(val32);
}
static void bnxt_copy_from_nvm_data(union devlink_param_value *dst,
union bnxt_nvm_data *src,
int nvm_num_bits, int dl_num_bytes)
{
u32 val32;
if (nvm_num_bits == 1) {
dst->vbool = src->val8;
return;
}
val32 = le32_to_cpu(src->val32);
if (dl_num_bytes == 4)
dst->vu32 = val32;
else if (dl_num_bytes == 2)
dst->vu16 = (u16)val32;
else if (dl_num_bytes == 1)
dst->vu8 = (u8)val32;
}
static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
int msg_len, union devlink_param_value *val)
{
struct hwrm_nvm_get_variable_input *req = msg;
struct bnxt_dl_nvm_param nvm_param;
union bnxt_nvm_data *data;
dma_addr_t data_dma_addr;
int idx = 0, rc, i;
/* Get/Set NVM CFG parameter is supported only on PFs */
if (BNXT_VF(bp))
return -EPERM;
for (i = 0; i < ARRAY_SIZE(nvm_params); i++) {
if (nvm_params[i].id == param_id) {
nvm_param = nvm_params[i];
break;
}
}
if (i == ARRAY_SIZE(nvm_params))
return -EOPNOTSUPP;
if (nvm_param.dir_type == BNXT_NVM_PORT_CFG)
idx = bp->pf.port_id;
else if (nvm_param.dir_type == BNXT_NVM_FUNC_CFG)
idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID;
data = dma_zalloc_coherent(&bp->pdev->dev, sizeof(*data),
&data_dma_addr, GFP_KERNEL);
if (!data)
return -ENOMEM;
req->dest_data_addr = cpu_to_le64(data_dma_addr);
req->data_len = cpu_to_le16(nvm_param.nvm_num_bits);
req->option_num = cpu_to_le16(nvm_param.offset);
req->index_0 = cpu_to_le16(idx);
if (idx)
req->dimensions = cpu_to_le16(1);
if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE)) {
bnxt_copy_to_nvm_data(data, val, nvm_param.nvm_num_bits,
nvm_param.dl_num_bytes);
rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
} else {
rc = hwrm_send_message_silent(bp, msg, msg_len,
HWRM_CMD_TIMEOUT);
if (!rc) {
bnxt_copy_from_nvm_data(val, data,
nvm_param.nvm_num_bits,
nvm_param.dl_num_bytes);
} else {
struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr;
if (resp->cmd_err ==
NVM_GET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST)
rc = -EOPNOTSUPP;
}
}
dma_free_coherent(&bp->pdev->dev, sizeof(*data), data, data_dma_addr);
if (rc == -EACCES)
netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n");
return rc;
}
static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
{
struct hwrm_nvm_get_variable_input req = {0};
struct bnxt *bp = bnxt_get_bp_from_dl(dl);
int rc;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1);
rc = bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
if (!rc)
if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
ctx->val.vbool = !ctx->val.vbool;
return rc;
}
static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id,
struct devlink_param_gset_ctx *ctx)
{
struct hwrm_nvm_set_variable_input req = {0};
struct bnxt *bp = bnxt_get_bp_from_dl(dl);
if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
ctx->val.vbool = !ctx->val.vbool;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_SET_VARIABLE, -1, -1);
return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
}
#ifdef HAVE_IGNORE_ARI
static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
union devlink_param_value val,
struct netlink_ext_ack *extack)
{
int max_val = -1;
if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX)
max_val = BNXT_MSIX_VEC_MAX;
if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN)
max_val = BNXT_MSIX_VEC_MIN_MAX;
if (val.vu32 > max_val) {
NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range");
return -EINVAL;
}
return 0;
}
#endif
static const struct devlink_param bnxt_dl_params[] = {
DEVLINK_PARAM_GENERIC(ENABLE_SRIOV,
BIT(DEVLINK_PARAM_CMODE_PERMANENT),
bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
NULL),
#ifdef HAVE_IGNORE_ARI
DEVLINK_PARAM_GENERIC(IGNORE_ARI,
BIT(DEVLINK_PARAM_CMODE_PERMANENT),
bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
NULL),
DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX,
BIT(DEVLINK_PARAM_CMODE_PERMANENT),
bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
bnxt_dl_msix_validate),
DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN,
BIT(DEVLINK_PARAM_CMODE_PERMANENT),
bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
bnxt_dl_msix_validate),
#endif
DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
"gre_ver_check", DEVLINK_PARAM_TYPE_BOOL,
BIT(DEVLINK_PARAM_CMODE_PERMANENT),
bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
NULL),
};
#ifdef HAVE_DEVLINK_PORT_PARAM
static const struct devlink_param bnxt_dl_port_params[] = {
};
#endif
#endif /* HAVE_DEVLINK_PARAM */
static int bnxt_dl_params_register(struct bnxt *bp)
{
#ifdef HAVE_DEVLINK_PARAM
int rc;
if (bp->hwrm_spec_code < 0x10600)
return 0;
rc = devlink_params_register(bp->dl, bnxt_dl_params,
ARRAY_SIZE(bnxt_dl_params));
if (rc) {
netdev_warn(bp->dev, "devlink_params_register failed. rc=%d",
rc);
return rc;
}
#ifdef HAVE_DEVLINK_PORT_PARAM
rc = devlink_port_params_register(&bp->dl_port, bnxt_dl_port_params,
ARRAY_SIZE(bnxt_dl_port_params));
if (rc) {
netdev_err(bp->dev, "devlink_port_params_register failed");
devlink_params_unregister(bp->dl, bnxt_dl_params,
ARRAY_SIZE(bnxt_dl_params));
return rc;
}
#endif /* HAVE_DEVLINK_PORT_PARAM */
devlink_params_publish(bp->dl);
#endif /* HAVE_DEVLINK_PARAM */
return 0;
}
static void bnxt_dl_params_unregister(struct bnxt *bp)
{
#ifdef HAVE_DEVLINK_PARAM
if (bp->hwrm_spec_code < 0x10600)
return;
devlink_params_unregister(bp->dl, bnxt_dl_params,
ARRAY_SIZE(bnxt_dl_params));
#ifdef HAVE_DEVLINK_PORT_PARAM
devlink_port_params_unregister(&bp->dl_port, bnxt_dl_port_params,
ARRAY_SIZE(bnxt_dl_port_params));
#endif /* HAVE_DEVLINK_PORT_PARAM */
#endif /* HAVE_DEVLINK_PARAM */
}
int bnxt_dl_register(struct bnxt *bp)
{
struct devlink *dl;
int rc;
if (BNXT_PF(bp))
dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl));
else
dl = devlink_alloc(&bnxt_vf_dl_ops, sizeof(struct bnxt_dl));
if (!dl) {
netdev_warn(bp->dev, "devlink_alloc failed");
return -ENOMEM;
}
bnxt_link_bp_to_dl(bp, dl);
#ifdef CONFIG_VF_REPS
/* Add switchdev eswitch mode setting, if SRIOV supported */
if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) &&
bp->hwrm_spec_code > 0x10803)
bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
#endif
rc = devlink_register(dl, &bp->pdev->dev);
if (rc) {
netdev_warn(bp->dev, "devlink_register failed. rc=%d", rc);
goto err_dl_free;
}
if (!BNXT_PF(bp))
return 0;
#ifdef HAVE_DEVLINK_PORT_PARAM
#ifdef HAVE_DEVLINK_PORT_ATTRS
devlink_port_attrs_set(&bp->dl_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
bp->pf.port_id, false, 0, bp->dsn,
sizeof(bp->dsn));
#endif
rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id);
if (rc) {
netdev_err(bp->dev, "devlink_port_register failed");
goto err_dl_unreg;
}
#endif /* HAVE_DEVLINK_PORT_PARAM */
rc = bnxt_dl_params_register(bp);
if (rc)
goto err_dl_port_unreg;
return 0;
err_dl_port_unreg:
#ifdef HAVE_DEVLINK_PORT_PARAM
devlink_port_unregister(&bp->dl_port);
err_dl_unreg:
#endif /* HAVE_DEVLINK_PORT_PARAM */
devlink_unregister(dl);
err_dl_free:
bnxt_link_bp_to_dl(bp, NULL);
devlink_free(dl);
return rc;
}
void bnxt_dl_unregister(struct bnxt *bp)
{
struct devlink *dl = bp->dl;
if (!dl)
return;
if (BNXT_PF(bp)) {
bnxt_dl_params_unregister(bp);
#ifdef HAVE_DEVLINK_PORT_PARAM
devlink_port_unregister(&bp->dl_port);
#endif
}
devlink_unregister(dl);
devlink_free(dl);
}
#endif /* CONFIG_VF_REPS || HAVE_DEVLINK_PARAM */
#ifndef HAVE_DEVLINK_HEALTH_REPORT
void bnxt_devlink_health_report(struct bnxt *bp, unsigned long event)
{
switch (event) {
case BNXT_FW_RESET_NOTIFY_SP_EVENT:
bnxt_fw_reset(bp);
break;
case BNXT_FW_EXCEPTION_SP_EVENT:
bnxt_fw_exception(bp);
break;
}
}
void bnxt_dl_health_status_update(struct bnxt *bp, bool healthy)
{
}
void bnxt_dl_health_recovery_done(struct bnxt *bp)
{
}
#endif /* HAVE_DEVLINK_HEALTH_REPORT */

View File

@ -0,0 +1,101 @@
/* 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_DEVLINK_H
#define BNXT_DEVLINK_H
#if defined(CONFIG_VF_REPS) || defined(HAVE_DEVLINK_PARAM)
/* Struct to hold housekeeping info needed by devlink interface */
struct bnxt_dl {
struct bnxt *bp; /* back ptr to the controlling dev */
};
static inline struct bnxt *bnxt_get_bp_from_dl(struct devlink *dl)
{
return ((struct bnxt_dl *)devlink_priv(dl))->bp;
}
/* To clear devlink pointer from bp, pass NULL dl */
static inline void bnxt_link_bp_to_dl(struct bnxt *bp, struct devlink *dl)
{
bp->dl = dl;
/* add a back pointer in dl to bp */
if (dl) {
struct bnxt_dl *bp_dl = devlink_priv(dl);
bp_dl->bp = bp;
}
}
#ifdef HAVE_DEVLINK_PARAM
#define NVM_OFF_MSIX_VEC_PER_PF_MAX 108
#define NVM_OFF_MSIX_VEC_PER_PF_MIN 114
#define NVM_OFF_IGNORE_ARI 164
#define NVM_OFF_DIS_GRE_VER_CHECK 171
#define NVM_OFF_ENABLE_SRIOV 401
#define NVM_OFF_NVM_CFG_VER 602
#define BNXT_NVM_CFG_VER_BITS 24
#define BNXT_NVM_CFG_VER_BYTES 4
#define BNXT_MSIX_VEC_MAX 1280
#define BNXT_MSIX_VEC_MIN_MAX 128
union bnxt_nvm_data {
u8 val8;
__le32 val32;
};
enum bnxt_nvm_dir_type {
BNXT_NVM_SHARED_CFG = 40,
BNXT_NVM_PORT_CFG,
BNXT_NVM_FUNC_CFG,
};
struct bnxt_dl_nvm_param {
u16 id;
u16 offset;
u16 dir_type;
u16 nvm_num_bits;
u8 dl_num_bytes;
};
#endif /* HAVE_DEVLINK_PARAM */
int bnxt_dl_register(struct bnxt *bp);
void bnxt_dl_unregister(struct bnxt *bp);
#else /* CONFIG_VF_REPS || HAVE_DEVLINK_PARAM */
static inline int bnxt_dl_register(struct bnxt *bp)
{
return 0;
}
static inline void bnxt_dl_unregister(struct bnxt *bp)
{
}
#endif /* CONFIG_VF_REPS || HAVE_DEVLINK_PARAM */
void bnxt_devlink_health_report(struct bnxt *bp, unsigned long event);
void bnxt_dl_health_status_update(struct bnxt *bp, bool healthy);
void bnxt_dl_health_recovery_done(struct bnxt *bp);
#ifdef HAVE_DEVLINK_HEALTH_REPORT
void bnxt_dl_fw_reporters_create(struct bnxt *bp);
void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all);
#else
static inline void bnxt_dl_fw_reporters_create(struct bnxt *bp)
{
}
static inline void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all)
{
}
#endif /* HAVE_DEVLINK_HEALTH_REPORT */
#endif /* BNXT_DEVLINK_H */

View File

@ -0,0 +1,38 @@
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2017-2018 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/pci.h>
#include <linux/netdevice.h>
#include "bnxt_compat.h"
#ifdef HAVE_DIM
#include <linux/dim.h>
#else
#include "bnxt_dim.h"
#endif
#include "bnxt_hsi.h"
#include "bnxt.h"
void bnxt_dim_work(struct work_struct *work)
{
struct dim *dim = container_of(work, struct dim, work);
struct bnxt_cp_ring_info *cpr = container_of(dim,
struct bnxt_cp_ring_info,
dim);
struct bnxt_napi *bnapi = container_of(cpr,
struct bnxt_napi,
cp_ring);
struct dim_cq_moder cur_moder =
net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
cpr->rx_ring_coal.coal_ticks = cur_moder.usec;
cpr->rx_ring_coal.coal_bufs = cur_moder.pkts;
bnxt_hwrm_set_ring_coal(bnapi->bp, bnapi);
dim->state = DIM_START_MEASURE;
}

View File

@ -0,0 +1,379 @@
/*
* Copyright (c) 2016, Mellanox Technologies. All rights reserved.
* Copyright (c) 2017-2018, Broadcom Limited. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef NET_DIM_H
#define NET_DIM_H
#include <linux/module.h>
struct dim_cq_moder {
u16 usec;
u16 pkts;
u8 cq_period_mode;
};
struct dim_sample {
ktime_t time;
u32 pkt_ctr;
u32 byte_ctr;
u16 event_ctr;
};
struct dim_stats {
int ppms; /* packets per msec */
int bpms; /* bytes per msec */
int epms; /* events per msec */
};
struct dim { /* Adaptive Moderation */
u8 state;
struct dim_stats prev_stats;
struct dim_sample start_sample;
struct work_struct work;
u8 profile_ix;
u8 mode;
u8 tune_state;
u8 steps_right;
u8 steps_left;
u8 tired;
};
enum {
DIM_CQ_PERIOD_MODE_START_FROM_EQE = 0x0,
DIM_CQ_PERIOD_MODE_START_FROM_CQE = 0x1,
DIM_CQ_PERIOD_NUM_MODES
};
/* Adaptive moderation logic */
enum {
DIM_START_MEASURE,
DIM_MEASURE_IN_PROGRESS,
DIM_APPLY_NEW_PROFILE,
};
enum {
DIM_PARKING_ON_TOP,
DIM_PARKING_TIRED,
DIM_GOING_RIGHT,
DIM_GOING_LEFT,
};
enum {
DIM_STATS_WORSE,
DIM_STATS_SAME,
DIM_STATS_BETTER,
};
enum {
DIM_STEPPED,
DIM_TOO_TIRED,
DIM_ON_EDGE,
};
#define NET_DIM_PARAMS_NUM_PROFILES 5
/* Adaptive moderation profiles */
#define NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE 256
#define NET_DIM_DEF_PROFILE_CQE 1
#define NET_DIM_DEF_PROFILE_EQE 1
/* All profiles sizes must be NET_PARAMS_DIM_NUM_PROFILES */
#define NET_DIM_EQE_PROFILES { \
{1, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
{4, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
{8, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
{32, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
{256, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
}
#define NET_DIM_CQE_PROFILES { \
{2, 256}, \
{8, 128}, \
{16, 64}, \
{32, 64}, \
{64, 64} \
}
static const struct dim_cq_moder
profile[DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
NET_DIM_EQE_PROFILES,
NET_DIM_CQE_PROFILES,
};
static inline struct dim_cq_moder
net_dim_get_rx_moderation(u8 cq_period_mode, int ix)
{
struct dim_cq_moder cq_moder = profile[cq_period_mode][ix];
cq_moder.cq_period_mode = cq_period_mode;
return cq_moder;
}
static inline struct dim_cq_moder
net_dim_get_def_rx_moderation(u8 rx_cq_period_mode)
{
int default_profile_ix;
if (rx_cq_period_mode == DIM_CQ_PERIOD_MODE_START_FROM_CQE)
default_profile_ix = NET_DIM_DEF_PROFILE_CQE;
else /* DIM_CQ_PERIOD_MODE_START_FROM_EQE */
default_profile_ix = NET_DIM_DEF_PROFILE_EQE;
return net_dim_get_rx_moderation(rx_cq_period_mode, default_profile_ix);
}
static inline bool dim_on_top(struct dim *dim)
{
switch (dim->tune_state) {
case DIM_PARKING_ON_TOP:
case DIM_PARKING_TIRED:
return true;
case DIM_GOING_RIGHT:
return (dim->steps_left > 1) && (dim->steps_right == 1);
default: /* DIM_GOING_LEFT */
return (dim->steps_right > 1) && (dim->steps_left == 1);
}
}
static inline void dim_turn(struct dim *dim)
{
switch (dim->tune_state) {
case DIM_PARKING_ON_TOP:
case DIM_PARKING_TIRED:
break;
case DIM_GOING_RIGHT:
dim->tune_state = DIM_GOING_LEFT;
dim->steps_left = 0;
break;
case DIM_GOING_LEFT:
dim->tune_state = DIM_GOING_RIGHT;
dim->steps_right = 0;
break;
}
}
static inline int net_dim_step(struct dim *dim)
{
if (dim->tired == (NET_DIM_PARAMS_NUM_PROFILES * 2))
return DIM_TOO_TIRED;
switch (dim->tune_state) {
case DIM_PARKING_ON_TOP:
case DIM_PARKING_TIRED:
break;
case DIM_GOING_RIGHT:
if (dim->profile_ix == (NET_DIM_PARAMS_NUM_PROFILES - 1))
return DIM_ON_EDGE;
dim->profile_ix++;
dim->steps_right++;
break;
case DIM_GOING_LEFT:
if (dim->profile_ix == 0)
return DIM_ON_EDGE;
dim->profile_ix--;
dim->steps_left++;
break;
}
dim->tired++;
return DIM_STEPPED;
}
static inline void dim_park_on_top(struct dim *dim)
{
dim->steps_right = 0;
dim->steps_left = 0;
dim->tired = 0;
dim->tune_state = DIM_PARKING_ON_TOP;
}
static inline void dim_park_tired(struct dim *dim)
{
dim->steps_right = 0;
dim->steps_left = 0;
dim->tune_state = DIM_PARKING_TIRED;
}
static inline void net_dim_exit_parking(struct dim *dim)
{
dim->tune_state = dim->profile_ix ? DIM_GOING_LEFT :
DIM_GOING_RIGHT;
net_dim_step(dim);
}
#define IS_SIGNIFICANT_DIFF(val, ref) \
(((100 * abs((val) - (ref))) / (ref)) > 10) /* more than 10% difference */
static inline int net_dim_stats_compare(struct dim_stats *curr,
struct dim_stats *prev)
{
if (!prev->bpms)
return curr->bpms ? DIM_STATS_BETTER :
DIM_STATS_SAME;
if (IS_SIGNIFICANT_DIFF(curr->bpms, prev->bpms))
return (curr->bpms > prev->bpms) ? DIM_STATS_BETTER :
DIM_STATS_WORSE;
if (!prev->ppms)
return curr->ppms ? DIM_STATS_BETTER :
DIM_STATS_SAME;
if (IS_SIGNIFICANT_DIFF(curr->ppms, prev->ppms))
return (curr->ppms > prev->ppms) ? DIM_STATS_BETTER :
DIM_STATS_WORSE;
if (!prev->epms)
return DIM_STATS_SAME;
if (IS_SIGNIFICANT_DIFF(curr->epms, prev->epms))
return (curr->epms < prev->epms) ? DIM_STATS_BETTER :
DIM_STATS_WORSE;
return DIM_STATS_SAME;
}
static inline bool net_dim_decision(struct dim_stats *curr_stats,
struct dim *dim)
{
int prev_state = dim->tune_state;
int prev_ix = dim->profile_ix;
int stats_res;
int step_res;
switch (dim->tune_state) {
case DIM_PARKING_ON_TOP:
stats_res = net_dim_stats_compare(curr_stats, &dim->prev_stats);
if (stats_res != DIM_STATS_SAME)
net_dim_exit_parking(dim);
break;
case DIM_PARKING_TIRED:
dim->tired--;
if (!dim->tired)
net_dim_exit_parking(dim);
break;
case DIM_GOING_RIGHT:
case DIM_GOING_LEFT:
stats_res = net_dim_stats_compare(curr_stats, &dim->prev_stats);
if (stats_res != DIM_STATS_BETTER)
dim_turn(dim);
if (dim_on_top(dim)) {
dim_park_on_top(dim);
break;
}
step_res = net_dim_step(dim);
switch (step_res) {
case DIM_ON_EDGE:
dim_park_on_top(dim);
break;
case DIM_TOO_TIRED:
dim_park_tired(dim);
break;
}
break;
}
if ((prev_state != DIM_PARKING_ON_TOP) ||
(dim->tune_state != DIM_PARKING_ON_TOP))
dim->prev_stats = *curr_stats;
return dim->profile_ix != prev_ix;
}
static inline void dim_update_sample(u16 event_ctr,
u64 packets,
u64 bytes,
struct dim_sample *s)
{
s->time = ktime_get();
s->pkt_ctr = packets;
s->byte_ctr = bytes;
s->event_ctr = event_ctr;
}
#define DIM_NEVENTS 320
#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)
#define BIT_GAP(bits, end, start) ((((end) - (start)) + BIT_ULL(bits)) & (BIT_ULL(bits) - 1))
static inline void dim_calc_stats(struct dim_sample *start,
struct dim_sample *end,
struct dim_stats *curr_stats)
{
/* u32 holds up to 71 minutes, should be enough */
u32 delta_us = ktime_us_delta(end->time, start->time);
u32 npkts = BIT_GAP(BITS_PER_TYPE(u32), end->pkt_ctr, start->pkt_ctr);
u32 nbytes = BIT_GAP(BITS_PER_TYPE(u32), end->byte_ctr,
start->byte_ctr);
if (!delta_us)
return;
curr_stats->ppms = DIV_ROUND_UP(npkts * USEC_PER_MSEC, delta_us);
curr_stats->bpms = DIV_ROUND_UP(nbytes * USEC_PER_MSEC, delta_us);
curr_stats->epms = DIV_ROUND_UP(DIM_NEVENTS * USEC_PER_MSEC,
delta_us);
}
static inline void net_dim(struct dim *dim,
struct dim_sample end_sample)
{
struct dim_stats curr_stats;
u16 nevents;
switch (dim->state) {
case DIM_MEASURE_IN_PROGRESS:
nevents = BIT_GAP(BITS_PER_TYPE(u16),
end_sample.event_ctr,
dim->start_sample.event_ctr);
if (nevents < DIM_NEVENTS)
break;
dim_calc_stats(&dim->start_sample, &end_sample, &curr_stats);
if (net_dim_decision(&curr_stats, dim)) {
dim->state = DIM_APPLY_NEW_PROFILE;
schedule_work(&dim->work);
break;
}
/* fall through */
case DIM_START_MEASURE:
dim->state = DIM_MEASURE_IN_PROGRESS;
break;
case DIM_APPLY_NEW_PROFILE:
break;
}
}
#endif /* NET_DIM_H */

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,11 @@
#ifndef BNXT_ETHTOOL_H
#define BNXT_ETHTOOL_H
#if defined(ETHTOOL_GET_DUMP_FLAG) && !defined(GET_ETHTOOL_OP_EXT)
#include <linux/time.h>
#include <linux/rtc.h>
#endif
struct bnxt_led_cfg {
u8 led_id;
u8 led_state;
@ -22,6 +27,59 @@ struct bnxt_led_cfg {
u8 rsvd;
};
#if defined(ETHTOOL_GET_DUMP_FLAG) && !defined(GET_ETHTOOL_OP_EXT)
#define COREDUMP_LIST_BUF_LEN 2048
#define COREDUMP_RETRIEVE_BUF_LEN 4096
struct bnxt_coredump {
void *data;
int data_size;
u16 total_segs;
};
struct bnxt_time {
#if defined(HAVE_TIME64)
struct tm tm;
#elif defined(CONFIG_RTC_LIB) || defined(CONFIG_RTC_LIB_MODULE)
struct rtc_time tm;
#endif
};
#define BNXT_COREDUMP_BUF_LEN(len) ((len) - sizeof(struct bnxt_coredump_record))
struct bnxt_hwrm_dbg_dma_info {
void *dest_buf;
int dest_buf_size;
u16 dma_len;
u16 seq_off;
u16 data_len_off;
u16 segs;
u32 seg_start;
u32 buf_len;
};
struct hwrm_dbg_cmn_input {
__le16 req_type;
__le16 cmpl_ring;
__le16 seq_id;
__le16 target_id;
__le64 resp_addr;
__le64 host_dest_addr;
__le32 host_buf_len;
};
struct hwrm_dbg_cmn_output {
__le16 error_code;
__le16 req_type;
__le16 seq_id;
__le16 resp_len;
u8 flags;
#define HWRM_DBG_CMN_FLAGS_MORE 1
};
#define BNXT_CRASH_DUMP_LEN (8 << 20)
#endif /* defined(ETHTOOL_GET_DUMP_FLAG) && !defined(GET_ETHTOOL_OP_EXT) */
#define BNXT_LED_DFLT_ENA \
(PORT_LED_CFG_REQ_ENABLES_LED0_ID | \
PORT_LED_CFG_REQ_ENABLES_LED0_STATE | \
@ -34,11 +92,18 @@ struct bnxt_led_cfg {
#define BNXT_LED_DFLT_ENABLES(x) \
cpu_to_le32(BNXT_LED_DFLT_ENA << (BNXT_LED_DFLT_ENA_SHIFT * (x)))
#define BNXT_FW_RESET_AP 0xfffe
#define BNXT_FW_RESET_CHIP 0xffff
#define BNXT_PXP_REG_LEN 0x3110
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);
int bnxt_flash_package_from_file(struct net_device *dev, const char *filename,
u32 install_type);
void bnxt_ethtool_init(struct bnxt *bp);
void bnxt_ethtool_free(struct bnxt *bp);

View File

@ -0,0 +1,15 @@
/* 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_EXTRA_VER_H
#define BNXT_EXTRA_VER_H
#define DRV_MODULE_EXTRA_VER "-216.1.92.0"
#endif

View File

@ -1,6 +1,7 @@
/* 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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,835 @@
/* 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/module.h>
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/rtnetlink.h>
#include "bnxt_compat.h"
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_ulp.h"
#include "bnxt_lfc.h"
#include "bnxt_lfc_ioctl.h"
#ifdef CONFIG_BNXT_LFC
#define MAX_LFC_OPEN_ULP_DEVICES 32
#define PRIME_1 29
#define PRIME_2 31
static struct bnxt_gloabl_dev blfc_global_dev;
static struct bnxt_lfc_dev_array blfc_array[MAX_LFC_OPEN_ULP_DEVICES];
static bool bnxt_lfc_inited;
static bool is_domain_available;
static int domain_no;
static void bnxt_lfc_unreg(struct bnxt_lfc_dev *blfc_dev);
static int lfc_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
u32 i;
struct bnxt_lfc_dev *blfc_dev;
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
switch (event) {
case NETDEV_UNREGISTER:
for (i = 0; i < MAX_LFC_OPEN_ULP_DEVICES; i++) {
mutex_lock(&blfc_global_dev.bnxt_lfc_lock);
blfc_dev = blfc_array[i].bnxt_lfc_dev;
if (blfc_dev && blfc_dev->ndev == dev) {
bnxt_lfc_unreg(blfc_dev);
dev_put(blfc_dev->ndev);
kfree(blfc_dev);
blfc_array[i].bnxt_lfc_dev = NULL;
blfc_array[i].taken = 0;
mutex_unlock(&blfc_global_dev.bnxt_lfc_lock);
break;
}
mutex_unlock(&blfc_global_dev.bnxt_lfc_lock);
}
break;
default:
/* do nothing */
break;
}
return 0;
}
struct notifier_block lfc_device_notifier = {
.notifier_call = lfc_device_event
};
static u32 bnxt_lfc_get_hash_key(u32 bus, u32 devfn)
{
return ((bus * PRIME_1 + devfn) * PRIME_2) % MAX_LFC_OPEN_ULP_DEVICES;
}
static int32_t bnxt_lfc_probe_and_reg(struct bnxt_lfc_dev *blfc_dev)
{
int32_t rc;
struct pci_dev *pdev = blfc_dev->pdev;
blfc_dev->bp = netdev_priv(blfc_dev->ndev);
if (!blfc_dev->bp->ulp_probe) {
BNXT_LFC_ERR(&pdev->dev,
"Probe routine not valid\n");
return -EINVAL;
}
blfc_dev->en_dev = blfc_dev->bp->ulp_probe(blfc_dev->ndev);
if (IS_ERR(blfc_dev->en_dev)) {
BNXT_LFC_ERR(&pdev->dev,
"Device probing failed\n");
return -EINVAL;
}
rtnl_lock();
rc = blfc_dev->en_dev->en_ops->bnxt_register_device(blfc_dev->en_dev,
BNXT_OTHER_ULP,
&blfc_dev->uops,
blfc_dev);
if (rc) {
BNXT_LFC_ERR(&pdev->dev,
"Device registration failed\n");
rtnl_unlock();
return rc;
}
rtnl_unlock();
return 0;
}
static void bnxt_lfc_unreg(struct bnxt_lfc_dev *blfc_dev)
{
int32_t rc;
rc = blfc_dev->en_dev->en_ops->bnxt_unregister_device(
blfc_dev->en_dev,
BNXT_OTHER_ULP);
if (rc)
BNXT_LFC_ERR(&blfc_dev->pdev->dev,
"netdev %p unregister failed!",
blfc_dev->ndev);
}
static bool bnxt_lfc_is_valid_pdev(struct pci_dev *pdev)
{
int32_t idx;
if (!pdev) {
BNXT_LFC_ERR(NULL, "No such PCI device\n");
return false;
}
if (pdev->vendor != PCI_VENDOR_ID_BROADCOM) {
pci_dev_put(pdev);
BNXT_LFC_ERR(NULL, "Not a Broadcom PCI device\n");
return false;
}
for (idx = 0; bnxt_pci_tbl[idx].device != 0; idx++) {
if (pdev->device == bnxt_pci_tbl[idx].device) {
BNXT_LFC_DEBUG(&pdev->dev, "Found valid PCI device\n");
return true;
}
}
pci_dev_put(pdev);
BNXT_LFC_ERR(NULL, "PCI device not supported\n");
return false;
}
static void bnxt_lfc_init_req_hdr(struct input *req_hdr, u16 req_type,
u16 cpr_id, u16 tgt_id)
{
req_hdr->req_type = cpu_to_le16(req_type);
req_hdr->cmpl_ring = cpu_to_le16(cpr_id);
req_hdr->target_id = cpu_to_le16(tgt_id);
}
static void bnxt_lfc_prep_fw_msg(struct bnxt_fw_msg *fw_msg, void *msg,
int32_t msg_len, void *resp,
int32_t resp_max_len,
int32_t timeout)
{
fw_msg->msg = msg;
fw_msg->msg_len = msg_len;
fw_msg->resp = resp;
fw_msg->resp_max_len = resp_max_len;
fw_msg->timeout = timeout;
}
static int32_t bnxt_lfc_process_nvm_flush(struct bnxt_lfc_dev *blfc_dev)
{
int32_t rc = 0;
struct bnxt_en_dev *en_dev = blfc_dev->en_dev;
struct hwrm_nvm_flush_input req = {0};
struct hwrm_nvm_flush_output resp = {0};
struct bnxt_fw_msg fw_msg;
bnxt_lfc_init_req_hdr((void *)&req,
HWRM_NVM_FLUSH, -1, -1);
bnxt_lfc_prep_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp,
sizeof(resp), BNXT_NVM_FLUSH_TIMEOUT);
rc = en_dev->en_ops->bnxt_send_fw_msg(en_dev, BNXT_OTHER_ULP, &fw_msg);
if (rc)
BNXT_LFC_ERR(&blfc_dev->pdev->dev,
"Failed to send NVM_FLUSH FW msg, rc = 0x%x", rc);
return rc;
}
static int32_t bnxt_lfc_process_nvm_get_var_req(struct bnxt_lfc_dev *blfc_dev,
struct bnxt_lfc_nvm_get_var_req
*nvm_get_var_req)
{
int32_t rc;
uint16_t len_in_bytes;
struct pci_dev *pdev = blfc_dev->pdev;
struct bnxt_en_dev *en_dev = blfc_dev->en_dev;
struct hwrm_nvm_get_variable_input req = {0};
struct hwrm_nvm_get_variable_output resp = {0};
struct bnxt_fw_msg fw_msg;
void *dest_data_addr = NULL;
dma_addr_t dest_data_dma_addr;
if (nvm_get_var_req->len_in_bits == 0) {
BNXT_LFC_ERR(&blfc_dev->pdev->dev, "Invalid Length\n");
return -ENOMEM;
}
len_in_bytes = (nvm_get_var_req->len_in_bits + 7) / 8;
dest_data_addr = dma_alloc_coherent(&pdev->dev,
len_in_bytes,
&dest_data_dma_addr,
GFP_KERNEL);
if (dest_data_addr == NULL) {
BNXT_LFC_ERR(&blfc_dev->pdev->dev,
"Failed to alloc mem for data\n");
return -ENOMEM;
}
bnxt_lfc_init_req_hdr((void *)&req,
HWRM_NVM_GET_VARIABLE, -1, -1);
req.dest_data_addr = cpu_to_le64(dest_data_dma_addr);
req.data_len = cpu_to_le16(nvm_get_var_req->len_in_bits);
req.option_num = cpu_to_le16(nvm_get_var_req->option_num);
req.dimensions = cpu_to_le16(nvm_get_var_req->dimensions);
req.index_0 = cpu_to_le16(nvm_get_var_req->index_0);
req.index_1 = cpu_to_le16(nvm_get_var_req->index_1);
req.index_2 = cpu_to_le16(nvm_get_var_req->index_2);
req.index_3 = cpu_to_le16(nvm_get_var_req->index_3);
bnxt_lfc_prep_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp,
sizeof(resp), DFLT_HWRM_CMD_TIMEOUT);
rc = en_dev->en_ops->bnxt_send_fw_msg(en_dev, BNXT_OTHER_ULP, &fw_msg);
if (rc) {
BNXT_LFC_ERR(&blfc_dev->pdev->dev,
"Failed to send NVM_GET_VARIABLE FW msg, rc = 0x%x",
rc);
goto done;
}
rc = copy_to_user(nvm_get_var_req->out_val, dest_data_addr,
len_in_bytes);
if (rc != 0) {
BNXT_LFC_ERR(&blfc_dev->pdev->dev,
"Failed to send %d characters to the user\n", rc);
rc = -EFAULT;
}
done:
dma_free_coherent(&pdev->dev, (nvm_get_var_req->len_in_bits),
dest_data_addr,
dest_data_dma_addr);
return rc;
}
static int32_t bnxt_lfc_process_nvm_set_var_req(struct bnxt_lfc_dev *blfc_dev,
struct bnxt_lfc_nvm_set_var_req
*nvm_set_var_req)
{
int32_t rc;
uint16_t len_in_bytes;
struct pci_dev *pdev = blfc_dev->pdev;
struct bnxt_en_dev *en_dev = blfc_dev->en_dev;
struct hwrm_nvm_set_variable_input req = {0};
struct hwrm_nvm_set_variable_output resp = {0};
struct bnxt_fw_msg fw_msg;
void *src_data_addr = NULL;
dma_addr_t src_data_dma_addr;
if (nvm_set_var_req->len_in_bits == 0) {
BNXT_LFC_ERR(&blfc_dev->pdev->dev, "Invalid Length\n");
return -ENOMEM;
}
len_in_bytes = (nvm_set_var_req->len_in_bits + 7) / 8;
src_data_addr = dma_alloc_coherent(&pdev->dev,
len_in_bytes,
&src_data_dma_addr,
GFP_KERNEL);
if (src_data_addr == NULL) {
BNXT_LFC_ERR(&blfc_dev->pdev->dev,
"Failed to alloc mem for data\n");
return -ENOMEM;
}
rc = copy_from_user(src_data_addr,
nvm_set_var_req->in_val,
len_in_bytes);
if (rc != 0) {
BNXT_LFC_ERR(&blfc_dev->pdev->dev,
"Failed to send %d bytes from the user\n", rc);
rc = -EFAULT;
goto done;
}
bnxt_lfc_init_req_hdr((void *)&req,
HWRM_NVM_SET_VARIABLE, -1, -1);
req.src_data_addr = cpu_to_le64(src_data_dma_addr);
req.data_len = cpu_to_le16(nvm_set_var_req->len_in_bits);
req.option_num = cpu_to_le16(nvm_set_var_req->option_num);
req.dimensions = cpu_to_le16(nvm_set_var_req->dimensions);
req.index_0 = cpu_to_le16(nvm_set_var_req->index_0);
req.index_1 = cpu_to_le16(nvm_set_var_req->index_1);
req.index_2 = cpu_to_le16(nvm_set_var_req->index_2);
req.index_3 = cpu_to_le16(nvm_set_var_req->index_3);
bnxt_lfc_prep_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp,
sizeof(resp), DFLT_HWRM_CMD_TIMEOUT);
rc = en_dev->en_ops->bnxt_send_fw_msg(en_dev, BNXT_OTHER_ULP, &fw_msg);
if (rc)
BNXT_LFC_ERR(&blfc_dev->pdev->dev,
"Failed to send NVM_SET_VARIABLE FW msg, rc = 0x%x", rc);
done:
dma_free_coherent(&pdev->dev, len_in_bytes,
src_data_addr,
src_data_dma_addr);
return rc;
}
static int32_t bnxt_lfc_fill_fw_msg(struct pci_dev *pdev,
struct bnxt_fw_msg *fw_msg,
struct blfc_fw_msg *msg)
{
int32_t rc = 0;
if (copy_from_user(fw_msg->msg,
(void __user *)((unsigned long)msg->usr_req),
msg->len_req)) {
BNXT_LFC_ERR(&pdev->dev, "Failed to copy data from user\n");
return -EFAULT;
}
fw_msg->msg_len = msg->len_req;
fw_msg->resp_max_len = msg->len_resp;
if (!msg->timeout)
fw_msg->timeout = DFLT_HWRM_CMD_TIMEOUT;
else
fw_msg->timeout = msg->timeout;
return rc;
}
static int32_t bnxt_lfc_prepare_dma_operations(struct bnxt_lfc_dev *blfc_dev,
struct blfc_fw_msg *msg,
struct bnxt_fw_msg *fw_msg)
{
int32_t rc = 0;
uint8_t i, num_allocated = 0;
void *dma_ptr;
for (i = 0; i < msg->num_dma_indications; i++) {
if (msg->dma[i].length == 0 ||
msg->dma[i].length > MAX_DMA_MEM_SIZE) {
BNXT_LFC_ERR(&blfc_dev->pdev->dev,
"Invalid DMA memory length\n");
rc = -EINVAL;
goto err;
}
blfc_dev->dma_virt_addr[i] = dma_alloc_coherent(
&blfc_dev->pdev->dev,
msg->dma[i].length,
&blfc_dev->dma_addr[i],
GFP_KERNEL);
if (!blfc_dev->dma_virt_addr[i]) {
BNXT_LFC_ERR(&blfc_dev->pdev->dev,
"Failed to allocate memory for data_addr[%d]\n",
i);
rc = -ENOMEM;
goto err;
}
num_allocated++;
if (!(msg->dma[i].read_or_write)) {
if (copy_from_user(blfc_dev->dma_virt_addr[i],
(void __user *)(
(unsigned long)(msg->dma[i].data)),
msg->dma[i].length)) {
BNXT_LFC_ERR(&blfc_dev->pdev->dev,
"Failed to copy data from user for data_addr[%d]\n",
i);
rc = -EFAULT;
goto err;
}
}
dma_ptr = fw_msg->msg + msg->dma[i].offset;
if ((PTR_ALIGN(dma_ptr, 8) == dma_ptr) &&
(msg->dma[i].offset < msg->len_req)) {
__le64 *dmap = dma_ptr;
*dmap = cpu_to_le64(blfc_dev->dma_addr[i]);
} else {
BNXT_LFC_ERR(&blfc_dev->pdev->dev,
"Wrong input parameter\n");
rc = -EINVAL;
goto err;
}
}
return rc;
err:
for (i = 0; i < num_allocated; i++)
dma_free_coherent(&blfc_dev->pdev->dev,
msg->dma[i].length,
blfc_dev->dma_virt_addr[i],
blfc_dev->dma_addr[i]);
return rc;
}
static int32_t bnxt_lfc_process_hwrm(struct bnxt_lfc_dev *blfc_dev,
struct bnxt_lfc_req *lfc_req)
{
int32_t rc = 0, i, hwrm_err = 0;
struct bnxt_en_dev *en_dev = blfc_dev->en_dev;
struct pci_dev *pdev = blfc_dev->pdev;
struct bnxt_fw_msg fw_msg;
struct blfc_fw_msg msg, *msg2 = NULL;
if (copy_from_user(&msg,
(void __user *)((unsigned long)lfc_req->req.hreq),
sizeof(msg))) {
BNXT_LFC_ERR(&pdev->dev, "Failed to copy data from user\n");
return -EFAULT;
}
if (msg.len_req > BNXT_LFC_MAX_HWRM_REQ_LENGTH ||
msg.len_resp > BNXT_LFC_MAX_HWRM_RESP_LENGTH) {
BNXT_LFC_ERR(&pdev->dev,
"Invalid length\n");
return -EINVAL;
}
fw_msg.msg = kmalloc(msg.len_req, GFP_KERNEL);
if (!fw_msg.msg) {
BNXT_LFC_ERR(&pdev->dev,
"Failed to allocate input req memory\n");
return -ENOMEM;
}
fw_msg.resp = kmalloc(msg.len_resp, GFP_KERNEL);
if (!fw_msg.resp) {
BNXT_LFC_ERR(&pdev->dev,
"Failed to allocate resp memory\n");
rc = -ENOMEM;
goto err;
}
rc = bnxt_lfc_fill_fw_msg(pdev, &fw_msg, &msg);
if (rc) {
BNXT_LFC_ERR(&pdev->dev,
"Failed to fill the FW data\n");
goto err;
}
if (msg.num_dma_indications) {
if (msg.num_dma_indications > MAX_NUM_DMA_INDICATIONS) {
BNXT_LFC_ERR(&pdev->dev,
"Invalid DMA indications\n");
rc = -EINVAL;
goto err1;
}
msg2 = kmalloc((sizeof(struct blfc_fw_msg) +
(msg.num_dma_indications * sizeof(struct dma_info))),
GFP_KERNEL);
if (!msg2) {
BNXT_LFC_ERR(&pdev->dev,
"Failed to allocate memory\n");
rc = -ENOMEM;
goto err;
}
if (copy_from_user((void *)msg2,
(void __user *)((unsigned long)lfc_req->req.hreq),
(sizeof(struct blfc_fw_msg) +
(msg.num_dma_indications *
sizeof(struct dma_info))))) {
BNXT_LFC_ERR(&pdev->dev,
"Failed to copy data from user\n");
rc = -EFAULT;
goto err;
}
rc = bnxt_lfc_prepare_dma_operations(blfc_dev, msg2, &fw_msg);
if (rc) {
BNXT_LFC_ERR(&pdev->dev,
"Failed to perform DMA operaions\n");
goto err;
}
}
hwrm_err = en_dev->en_ops->bnxt_send_fw_msg(en_dev,
BNXT_OTHER_ULP, &fw_msg);
if (hwrm_err) {
struct input *req = fw_msg.msg;
BNXT_LFC_ERR(&pdev->dev,
"Failed to send FW msg type = 0x%x, error = 0x%x",
req->req_type, hwrm_err);
goto err;
}
for (i = 0; i < msg.num_dma_indications; i++) {
if (msg2->dma[i].read_or_write) {
if (copy_to_user((void __user *)
((unsigned long)msg2->dma[i].data),
blfc_dev->dma_virt_addr[i],
msg2->dma[i].length)) {
BNXT_LFC_ERR(&pdev->dev,
"Failed to copy data from user\n");
rc = -EFAULT;
goto err;
}
}
}
err:
for (i = 0; i < msg.num_dma_indications; i++)
dma_free_coherent(&pdev->dev, msg2->dma[i].length,
blfc_dev->dma_virt_addr[i],
blfc_dev->dma_addr[i]);
if (hwrm_err != -EBUSY && hwrm_err != -E2BIG) {
if (copy_to_user((void __user *)((unsigned long)msg.usr_resp),
fw_msg.resp,
msg.len_resp)) {
BNXT_LFC_ERR(&pdev->dev,
"Failed to copy data from user\n");
rc = -EFAULT;
}
}
err1:
kfree(msg2);
kfree(fw_msg.msg);
fw_msg.msg = NULL;
kfree(fw_msg.resp);
fw_msg.resp = NULL;
/* If HWRM command fails, return the response error code */
if (hwrm_err)
return hwrm_err;
return rc;
}
static int32_t bnxt_lfc_process_req(struct bnxt_lfc_dev *blfc_dev,
struct bnxt_lfc_req *lfc_req)
{
int32_t rc;
switch (lfc_req->hdr.req_type) {
case BNXT_LFC_NVM_GET_VAR_REQ:
rc = bnxt_lfc_process_nvm_get_var_req(blfc_dev,
&lfc_req->req.nvm_get_var_req);
break;
case BNXT_LFC_NVM_SET_VAR_REQ:
rc = bnxt_lfc_process_nvm_set_var_req(blfc_dev,
&lfc_req->req.nvm_set_var_req);
break;
case BNXT_LFC_NVM_FLUSH_REQ:
rc = bnxt_lfc_process_nvm_flush(blfc_dev);
break;
case BNXT_LFC_GENERIC_HWRM_REQ:
rc = bnxt_lfc_process_hwrm(blfc_dev, lfc_req);
break;
default:
BNXT_LFC_DEBUG(&blfc_dev->pdev->dev,
"No valid request found\n");
return -EINVAL;
}
return rc;
}
static int32_t bnxt_lfc_open(struct inode *inode, struct file *flip)
{
BNXT_LFC_DEBUG(NULL, "open is called");
return 0;
}
static ssize_t bnxt_lfc_read(struct file *filp, char __user *buff,
size_t length, loff_t *offset)
{
return -EINVAL;
}
static ssize_t bnxt_lfc_write(struct file *filp, const char __user *ubuff,
size_t len, loff_t *offset)
{
struct bnxt_lfc_generic_msg kbuff;
if (len != sizeof(kbuff)) {
BNXT_LFC_ERR(NULL, "Invalid length provided (%zu)\n", len);
return -EINVAL;
}
if (copy_from_user(&kbuff, (void __user *)ubuff, len)) {
BNXT_LFC_ERR(NULL, "Failed to copy data from user application\n");
return -EFAULT;
}
switch (kbuff.key) {
case BNXT_LFC_KEY_DOMAIN_NO:
is_domain_available = true;
domain_no = kbuff.value;
break;
default:
BNXT_LFC_ERR(NULL, "Invalid Key provided (%u)\n", kbuff.key);
return -EINVAL;
}
return len;
}
static loff_t bnxt_lfc_seek(struct file *filp, loff_t offset, int32_t whence)
{
return -EINVAL;
}
static void bnxt_lfc_stop(void *handle)
{
struct bnxt_lfc_dev *blfc_dev_stop = handle;
struct bnxt_lfc_dev *blfc_dev = NULL;
int i;
for (i = 0; i < MAX_LFC_OPEN_ULP_DEVICES; i++) {
blfc_dev = blfc_array[i].bnxt_lfc_dev;
if(blfc_dev == blfc_dev_stop) {
bnxt_lfc_unreg(blfc_dev);
dev_put(blfc_dev->ndev);
kfree(blfc_dev);
blfc_array[i].bnxt_lfc_dev = NULL;
blfc_array[i].taken = 0;
break;
}
}
}
static long bnxt_lfc_ioctl(struct file *flip, unsigned int cmd,
unsigned long args)
{
int32_t rc;
struct bnxt_lfc_req temp;
struct bnxt_lfc_req *lfc_req;
u32 index;
struct bnxt_lfc_dev *blfc_dev = NULL;
rc = copy_from_user(&temp, (void __user *)args, sizeof(struct bnxt_lfc_req));
if (rc) {
BNXT_LFC_ERR(NULL,
"Failed to send %d bytes from the user\n", rc);
return -EINVAL;
}
lfc_req = &temp;
if (!lfc_req)
return -EINVAL;
switch (cmd) {
case BNXT_LFC_REQ:
BNXT_LFC_DEBUG(NULL, "BNXT_LFC_REQ called");
mutex_lock(&blfc_global_dev.bnxt_lfc_lock);
index = bnxt_lfc_get_hash_key(lfc_req->hdr.bus, lfc_req->hdr.devfn);
if (blfc_array[index].taken) {
if (lfc_req->hdr.devfn != blfc_array[index].bnxt_lfc_dev->devfn ||
lfc_req->hdr.bus != blfc_array[index].bnxt_lfc_dev->bus) {
/* we have a false hit. Free the older blfc device
store the new one */
rtnl_lock();
bnxt_lfc_unreg(blfc_array[index].bnxt_lfc_dev);
dev_put(blfc_array[index].bnxt_lfc_dev->ndev);
kfree(blfc_array[index].bnxt_lfc_dev);
blfc_array[index].bnxt_lfc_dev = NULL;
blfc_array[index].taken = 0;
rtnl_unlock();
goto not_taken;
}
blfc_dev = blfc_array[index].bnxt_lfc_dev;
}
else {
not_taken:
blfc_dev = kzalloc(sizeof(struct bnxt_lfc_dev), GFP_KERNEL);
if (!blfc_dev) {
mutex_unlock(&blfc_global_dev.bnxt_lfc_lock);
return -EINVAL;
}
blfc_dev->pdev =
pci_get_domain_bus_and_slot(
((is_domain_available == true) ?
domain_no : 0), lfc_req->hdr.bus,
lfc_req->hdr.devfn);
if (bnxt_lfc_is_valid_pdev(blfc_dev->pdev) != true) {
mutex_unlock(&blfc_global_dev.bnxt_lfc_lock);
return -EINVAL;
}
rtnl_lock();
blfc_dev->ndev = pci_get_drvdata(blfc_dev->pdev);
if (!blfc_dev->ndev) {
printk("Driver with provided BDF doesn't exist\n");
pci_dev_put(blfc_dev->pdev);
rtnl_unlock();
mutex_unlock(&blfc_global_dev.bnxt_lfc_lock);
return -EINVAL;
}
dev_hold(blfc_dev->ndev);
rtnl_unlock();
if (try_module_get(blfc_dev->pdev->driver->driver.owner)) {
blfc_dev->uops.ulp_stop = bnxt_lfc_stop;
rc = bnxt_lfc_probe_and_reg(blfc_dev);
module_put(blfc_dev->pdev->driver->driver.owner);
} else {
rc = -EINVAL;
}
pci_dev_put(blfc_dev->pdev);
if (rc) {
dev_put(blfc_dev->ndev);
kfree(blfc_dev);
is_domain_available = false;
mutex_unlock(&blfc_global_dev.bnxt_lfc_lock);
return -EINVAL;
}
blfc_dev->bus = lfc_req->hdr.bus;
blfc_dev->devfn = lfc_req->hdr.devfn;
rtnl_lock();
blfc_array[index].bnxt_lfc_dev = blfc_dev;
blfc_array[index].taken = 1;
rtnl_unlock();
}
rc = bnxt_lfc_process_req(blfc_dev, lfc_req);
mutex_unlock(&blfc_global_dev.bnxt_lfc_lock);
break;
default:
BNXT_LFC_ERR(NULL, "No Valid IOCTL found\n");
return -EINVAL;
}
return rc;
}
static int32_t bnxt_lfc_release(struct inode *inode, struct file *filp)
{
BNXT_LFC_DEBUG(NULL, "release is called");
return 0;
}
int32_t __init bnxt_lfc_init(void)
{
int32_t rc;
rc = alloc_chrdev_region(&blfc_global_dev.d_dev, 0, 1, BNXT_LFC_DEV_NAME);
if (rc < 0) {
BNXT_LFC_ERR(NULL, "Allocation of char dev region is failed\n");
return rc;
}
blfc_global_dev.d_class = class_create(THIS_MODULE, BNXT_LFC_DEV_NAME);
if (IS_ERR(blfc_global_dev.d_class)) {
BNXT_LFC_ERR(NULL, "Class creation is failed\n");
unregister_chrdev_region(blfc_global_dev.d_dev, 1);
return -1;
}
if (IS_ERR(device_create(blfc_global_dev.d_class, NULL, blfc_global_dev.d_dev, NULL,
BNXT_LFC_DEV_NAME))) {
BNXT_LFC_ERR(NULL, "Device creation is failed\n");
class_destroy(blfc_global_dev.d_class);
unregister_chrdev_region(blfc_global_dev.d_dev, 1);
return -1;
}
blfc_global_dev.fops.owner = THIS_MODULE;
blfc_global_dev.fops.open = bnxt_lfc_open;
blfc_global_dev.fops.read = bnxt_lfc_read;
blfc_global_dev.fops.write = bnxt_lfc_write;
blfc_global_dev.fops.llseek = bnxt_lfc_seek;
blfc_global_dev.fops.unlocked_ioctl = bnxt_lfc_ioctl;
blfc_global_dev.fops.release = bnxt_lfc_release;
cdev_init(&blfc_global_dev.c_dev, &blfc_global_dev.fops);
if (cdev_add(&blfc_global_dev.c_dev, blfc_global_dev.d_dev, 1) == -1) {
BNXT_LFC_ERR(NULL, "Char device addition is failed\n");
device_destroy(blfc_global_dev.d_class, blfc_global_dev.d_dev);
class_destroy(blfc_global_dev.d_class);
unregister_chrdev_region(blfc_global_dev.d_dev, 1);
return -1;
}
mutex_init(&blfc_global_dev.bnxt_lfc_lock);
bnxt_lfc_inited = true;
memset(blfc_array, 0, sizeof(struct bnxt_lfc_dev_array)
* MAX_LFC_OPEN_ULP_DEVICES);
rc = bnxt_en_register_netdevice_notifier(&lfc_device_notifier);
if (rc) {
BNXT_LFC_ERR(NULL, "Error on register NETDEV event notifier\n");
return -1;
}
return 0;
}
void __exit bnxt_lfc_exit(void)
{
struct bnxt_lfc_dev *blfc_dev;
u32 i;
if (!bnxt_lfc_inited)
return;
for (i = 0; i < MAX_LFC_OPEN_ULP_DEVICES; i++) {
mutex_lock(&blfc_global_dev.bnxt_lfc_lock);
blfc_dev = blfc_array[i].bnxt_lfc_dev;
if (blfc_dev) {
rtnl_lock();
bnxt_lfc_unreg(blfc_dev);
blfc_array[i].bnxt_lfc_dev = NULL;
blfc_array[i].taken = 0;
rtnl_unlock();
dev_put(blfc_dev->ndev);
kfree(blfc_dev);
}
mutex_unlock(&blfc_global_dev.bnxt_lfc_lock);
}
bnxt_en_unregister_netdevice_notifier(&lfc_device_notifier);
cdev_del(&blfc_global_dev.c_dev);
device_destroy(blfc_global_dev.d_class, blfc_global_dev.d_dev);
class_destroy(blfc_global_dev.d_class);
unregister_chrdev_region(blfc_global_dev.d_dev, 1);
}
#endif

View File

@ -0,0 +1,98 @@
/* 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_LFC_H
#define BNXT_LFC_H
#ifdef CONFIG_BNXT_LFC
/* Assuming that no HWRM command requires more than 10 DMA address
* as input requests.
*/
#define MAX_NUM_DMA_INDICATIONS 10
#define MAX_DMA_MEM_SIZE 0x10000 /*64K*/
/* To prevent mismatch between bnxtnvm user application and bnxt_lfc
* keeping the max. size as 512.
*/
#define BNXT_LFC_MAX_HWRM_REQ_LENGTH HWRM_MAX_REQ_LEN
#define BNXT_LFC_MAX_HWRM_RESP_LENGTH (512)
#define BNXT_NVM_FLUSH_TIMEOUT ((DFLT_HWRM_CMD_TIMEOUT) * 100)
#define BNXT_LFC_DEV_NAME "bnxt_lfc"
#define DRV_NAME BNXT_LFC_DEV_NAME
#define BNXT_LFC_ERR(dev, fmt, arg...) \
dev_err(dev, "%s: %s:%d: "fmt "\n", \
DRV_NAME, __func__, \
__LINE__, ##arg) \
#define BNXT_LFC_WARN(dev, fmt, arg...) \
dev_warn(dev, "%s: %s:%d: "fmt "\n", \
DRV_NAME, __func__, \
__LINE__, ##arg) \
#define BNXT_LFC_INFO(dev, fmt, arg...) \
dev_info(dev, "%s: %s:%d: "fmt "\n", \
DRV_NAME, __func__, \
__LINE__, ##arg) \
#define BNXT_LFC_DEBUG(dev, fmt, arg...) \
dev_dbg(dev, "%s: %s:%d: "fmt "\n", \
DRV_NAME, __func__, \
__LINE__, ##arg) \
struct bnxt_lfc_dev_array {
u32 taken;
struct bnxt_lfc_dev *bnxt_lfc_dev;
};
struct bnxt_lfc_dev {
struct pci_dev *pdev;
struct net_device *ndev;
struct bnxt *bp;
struct bnxt_en_dev *en_dev;
struct bnxt_ulp_ops uops;
u32 bus;
u32 devfn;
/* dma_virt_addr to hold the virtual address
* of the DMA memory.
*/
void *dma_virt_addr[MAX_NUM_DMA_INDICATIONS];
/* dma_addr to hold the DMA addresses*/
dma_addr_t dma_addr[MAX_NUM_DMA_INDICATIONS];
};
struct bnxt_gloabl_dev {
dev_t d_dev;
struct class *d_class;
struct cdev c_dev;
struct file_operations fops;
struct mutex bnxt_lfc_lock;
};
int32_t bnxt_lfc_init(void);
void bnxt_lfc_exit(void);
#else
static inline int32_t bnxt_lfc_init()
{
}
static inline void bnxt_lfc_exit()
{
}
#endif
#endif /*BNXT_LFC_H*/

View File

@ -0,0 +1,106 @@
/* 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_LFC_IOCTL_H
#define BNXT_LFC_IOCTL_H
#define BNXT_LFC_IOCTL_MAGIC 0x98
#define BNXT_LFC_VER 1
enum bnxt_lfc_req_type {
BNXT_LFC_NVM_GET_VAR_REQ = 1,
BNXT_LFC_NVM_SET_VAR_REQ,
BNXT_LFC_NVM_FLUSH_REQ,
BNXT_LFC_GENERIC_HWRM_REQ,
};
struct bnxt_lfc_req_hdr {
uint32_t ver;
uint32_t bus;
uint32_t devfn;
enum bnxt_lfc_req_type req_type;
};
struct bnxt_lfc_nvm_get_var_req {
uint16_t option_num;
uint16_t dimensions;
uint16_t index_0;
uint16_t index_1;
uint16_t index_2;
uint16_t index_3;
uint16_t len_in_bits;
uint8_t __user *out_val;
};
struct bnxt_lfc_nvm_set_var_req {
uint16_t option_num;
uint16_t dimensions;
uint16_t index_0;
uint16_t index_1;
uint16_t index_2;
uint16_t index_3;
uint16_t len_in_bits;
uint8_t __user *in_val;
};
struct dma_info {
__u64 data;
/* Based on read_or_write parameter
* LFC will either fill or read the
* data to or from the user memory
*/
__u32 length;
/* Length of the data for read/write */
__u16 offset;
/* Offset at which HWRM input structure needs DMA address*/
__u8 read_or_write;
/* It should be 0 for write and 1 for read */
__u8 unused;
};
struct blfc_fw_msg {
__u64 usr_req;
/* HWRM input structure */
__u64 usr_resp;
/* HWRM output structure */
__u32 len_req;
/* HWRM input structure length*/
__u32 len_resp;
/* HWRM output structure length*/
__u32 timeout;
/* HWRM command timeout. If 0 then
* LFC will provide default timeout
*/
__u32 num_dma_indications;
/* Number of DMA addresses used in HWRM command */
struct dma_info dma[0];
/* User should allocate it with
* (sizeof(struct dma_info) * num_dma_indications)
*/
};
struct bnxt_lfc_generic_msg {
__u8 key;
#define BNXT_LFC_KEY_DOMAIN_NO 1
__u8 reserved[3];
__u32 value;
};
struct bnxt_lfc_req {
struct bnxt_lfc_req_hdr hdr;
union {
struct bnxt_lfc_nvm_get_var_req nvm_get_var_req;
struct bnxt_lfc_nvm_set_var_req nvm_set_var_req;
__u64 hreq; /* Pointer to "struct blfc_fw_msg" */
} req;
};
#define BNXT_LFC_REQ _IOW(BNXT_LFC_IOCTL_MAGIC, 1, struct bnxt_lfc_req)
#endif /*BNXT_LFC_IOCTL_H*/

View File

@ -0,0 +1,234 @@
/* 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/pci.h>
#include "bnxt_compat.h"
#include "bnxt_hsi.h"
#include "bnxt_netlink.h"
#include "bnxt.h"
/* attribute policy */
static struct nla_policy bnxt_netlink_policy[BNXT_NUM_ATTRS] = {
[BNXT_ATTR_PID] = { .type = NLA_U32 },
[BNXT_ATTR_IF_INDEX] = { .type = NLA_U32 },
[BNXT_ATTR_REQUEST] = { .type = NLA_BINARY },
[BNXT_ATTR_RESPONSE] = { .type = NLA_BINARY },
};
static struct genl_family bnxt_netlink_family;
static int bnxt_parse_attrs(struct nlattr **a, struct bnxt **bp,
struct net_device **dev)
{
pid_t pid;
struct net *ns = NULL;
const char *drivername;
if (!a[BNXT_ATTR_PID]) {
netdev_err(*dev, "No process ID specified\n");
goto err_inval;
}
pid = nla_get_u32(a[BNXT_ATTR_PID]);
ns = get_net_ns_by_pid(pid);
if (IS_ERR(ns)) {
netdev_err(*dev, "Invalid net namespace for pid %d (err: %ld)\n",
pid, PTR_ERR(ns));
goto err_inval;
}
if (!a[BNXT_ATTR_IF_INDEX]) {
netdev_err(*dev, "No interface index specified\n");
goto err_inval;
}
*dev = dev_get_by_index(ns, nla_get_u32(a[BNXT_ATTR_IF_INDEX]));
put_net(ns);
ns = NULL;
if (!*dev) {
netdev_err(*dev, "Invalid network interface index %d (err: %ld)\n",
nla_get_u32(a[BNXT_ATTR_IF_INDEX]), PTR_ERR(ns));
goto err_inval;
}
if (!(*dev)->dev.parent || !(*dev)->dev.parent->driver ||
!(*dev)->dev.parent->driver->name) {
netdev_err(*dev, "Unable to get driver name for device %s\n",
(*dev)->name);
goto err_inval;
}
drivername = (*dev)->dev.parent->driver->name;
if (strcmp(drivername, DRV_MODULE_NAME)) {
netdev_err(*dev, "Device %s (%s) is not a %s device!\n",
(*dev)->name, drivername, DRV_MODULE_NAME);
goto err_inval;
}
*bp = netdev_priv(*dev);
if (!*bp) {
netdev_warn((*bp)->dev, "No private data\n");
goto err_inval;
}
return 0;
err_inval:
if (ns && !IS_ERR(ns))
put_net(ns);
return -EINVAL;
}
/* handler */
static int bnxt_netlink_hwrm(struct sk_buff *skb, struct genl_info *info)
{
struct nlattr **a = info->attrs;
int len;
struct sk_buff *reply = NULL;
struct input *req;
struct output *resp;
struct bnxt *bp = NULL;
int rc = 0;
void *hdr;
struct net_device *dev = NULL;
rc = bnxt_parse_attrs(a, &bp, &dev);
if (rc)
goto err_rc;
if (!bp) {
rc = -EINVAL;
goto err_rc;
}
if (!bp->hwrm_cmd_resp_addr) {
netdev_warn(bp->dev, "HWRM interface not currently available on %s\n",
dev->name);
rc = -EINVAL;
goto err_rc;
}
if (bp->fw_cap & BNXT_FW_CAP_KONG_MB_CHNL &&
!bp->hwrm_cmd_kong_resp_addr) {
netdev_warn(bp->dev, "HWRM Kong interface not currently available on %s\n",
dev->name);
rc = -EINVAL;
goto err_rc;
}
if (!a[BNXT_ATTR_REQUEST]) {
netdev_warn(bp->dev, "No request specified\n");
rc = -EINVAL;
goto err_rc;
}
len = nla_len(a[BNXT_ATTR_REQUEST]);
req = nla_data(a[BNXT_ATTR_REQUEST]);
reply = genlmsg_new(PAGE_SIZE, GFP_KERNEL);
if (!reply) {
netdev_warn(bp->dev, "Error: genlmsg_new failed\n");
rc = -ENOMEM;
goto err_rc;
}
bnxt_hwrm_cmd_hdr_init(bp, req, req->req_type, -1, -1);
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message_silent(bp, req, len, HWRM_CMD_TIMEOUT);
if (rc) {
/*
* Indicate success for the hwrm transport, while letting
* the hwrm error be passed back to the netlink caller in
* the response message. Caller is responsible for handling
* any errors.
*
* no kernel warnings are logged in this case.
*/
rc = 0;
}
hdr = genlmsg_put_reply(reply, info, &bnxt_netlink_family, 0,
BNXT_CMD_HWRM);
resp = (struct output *)bnxt_get_hwrm_resp_addr(bp, req);
if (nla_put(reply, BNXT_ATTR_RESPONSE, resp->resp_len, resp)) {
netdev_warn(bp->dev, "No space for response attribte\n");
mutex_unlock(&bp->hwrm_cmd_lock);
rc = -ENOMEM;
goto err_rc;
}
genlmsg_end(reply, hdr);
mutex_unlock(&bp->hwrm_cmd_lock);
dev_put(dev);
dev = NULL;
return genlmsg_reply(reply, info);
err_rc:
if (reply && !IS_ERR(reply))
kfree_skb(reply);
if (dev && !IS_ERR(dev))
dev_put(dev);
if (bp)
netdev_warn(bp->dev, "returning with error code %d\n", rc);
return rc;
}
/* handlers */
#if defined(HAVE_GENL_REG_OPS_GRPS) || !defined(HAVE_GENL_REG_FAMILY_WITH_OPS)
static const struct genl_ops bnxt_netlink_ops[] = {
#else
static struct genl_ops bnxt_netlink_ops[] = {
#endif
{
.cmd = BNXT_CMD_HWRM,
.flags = GENL_ADMIN_PERM, /* Req's CAP_NET_ADMIN privilege */
#ifndef HAVE_GENL_POLICY
.policy = bnxt_netlink_policy,
#endif
.doit = bnxt_netlink_hwrm,
.dumpit = NULL,
},
};
/* family definition */
static struct genl_family bnxt_netlink_family = {
#ifdef HAVE_GENL_ID_GENERATE
.id = GENL_ID_GENERATE,
#endif
.hdrsize = 0,
.name = BNXT_NL_NAME,
.version = BNXT_NL_VER,
.maxattr = BNXT_NUM_ATTRS,
#ifdef HAVE_GENL_POLICY
.policy = bnxt_netlink_policy,
#endif
#ifndef HAVE_GENL_REG_FAMILY_WITH_OPS
.ops = bnxt_netlink_ops,
.n_ops = ARRAY_SIZE(bnxt_netlink_ops)
#endif
};
int bnxt_nl_register(void)
{
#ifndef HAVE_GENL_REG_FAMILY_WITH_OPS
return genl_register_family(&bnxt_netlink_family);
#elif defined(HAVE_GENL_REG_OPS_GRPS)
return genl_register_family_with_ops(&bnxt_netlink_family,
bnxt_netlink_ops);
#else
return genl_register_family_with_ops(&bnxt_netlink_family,
bnxt_netlink_ops,
ARRAY_SIZE(bnxt_netlink_ops));
#endif
return 0;
}
int bnxt_nl_unregister(void)
{
return genl_unregister_family(&bnxt_netlink_family);
}

View File

@ -0,0 +1,41 @@
/* 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_NETLINK_H__
#define __BNXT_NETLINK_H__
#include <net/genetlink.h>
#include <net/netlink.h>
/* commands */
enum {
BNXT_CMD_UNSPEC,
BNXT_CMD_HWRM,
BNXT_NUM_CMDS
};
#define BNXT_CMD_MAX (BNXT_NUM_CMDS - 1)
/* attributes */
enum {
BNXT_ATTR_UNSPEC,
BNXT_ATTR_PID,
BNXT_ATTR_IF_INDEX,
BNXT_ATTR_REQUEST,
BNXT_ATTR_RESPONSE,
BNXT_NUM_ATTRS
};
#define BNXT_ATTR_MAX (BNXT_NUM_ATTRS - 1)
#define BNXT_NL_NAME "bnxt_netlink"
#define BNXT_NL_VER 1
int bnxt_nl_register(void);
int bnxt_nl_unregister(void);
#endif

View File

@ -1,6 +1,7 @@
/* 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
@ -59,8 +60,6 @@ enum bnxt_nvm_directory_type {
#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,

View File

@ -0,0 +1,458 @@
/* 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);
return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}
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

View File

@ -0,0 +1,70 @@
/* 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

File diff suppressed because it is too large Load Diff

View File

@ -11,15 +11,58 @@
#ifndef BNXT_SRIOV_H
#define BNXT_SRIOV_H
#define BNXT_FWD_RESP_SIZE_ERR(n) \
((offsetof(struct hwrm_fwd_resp_input, encap_resp) + n) > \
sizeof(struct hwrm_fwd_resp_input))
#define BNXT_EXEC_FWD_RESP_SIZE_ERR(n) \
((offsetof(struct hwrm_exec_fwd_resp_input, encap_request) + n) >\
offsetof(struct hwrm_exec_fwd_resp_input, encap_resp_target_id))
#define BNXT_VF_MIN_RSS_CTX 1
#define BNXT_VF_MAX_RSS_CTX 1
#define BNXT_VF_MIN_L2_CTX 1
#define BNXT_VF_MAX_L2_CTX 4
#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
#ifdef HAVE_NDO_SET_VF_TRUST
int bnxt_set_vf_trust(struct net_device *dev, int vf_id, bool trust);
#endif
#ifdef HAVE_NDO_SET_VF_QUEUES
int bnxt_set_vf_queues(struct net_device *dev, int vf_id, int min_txq,
int max_txq, int min_rxq, int max_rxq);
#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
int bnxt_cfg_hw_sriov(struct bnxt *bp, int *num_vfs, bool reset);
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 *);
int bnxt_approve_mac(struct bnxt *, u8 *, bool);
void bnxt_update_vf_vnic(struct bnxt *bp, u32 vf_idx, u32 state);
void bnxt_commit_vf_vnic(struct bnxt *bp, u32 vf_idx);
bool bnxt_vf_vnic_state_is_up(struct bnxt *bp, u32 vf_idx);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,8 @@
#ifdef CONFIG_BNXT_FLOWER_OFFLOAD
#include <net/ip_tunnels.h>
/* Structs used for storing the filter/actions of the TC cmd.
*/
struct bnxt_tc_l2_key {
@ -21,6 +23,9 @@ struct bnxt_tc_l2_key {
__be16 inner_vlan_tci;
__be16 ether_type;
u8 num_vlans;
u8 dir;
#define BNXT_DIR_RX 1
#define BNXT_DIR_TX 0
};
struct bnxt_tc_l3_key {
@ -50,6 +55,19 @@ struct bnxt_tc_l4_key {
};
};
struct bnxt_tc_tunnel_key {
struct bnxt_tc_l2_key l2;
struct bnxt_tc_l3_key l3;
struct bnxt_tc_l4_key l4;
__be32 id;
};
#define bnxt_eth_addr_key_mask_invalid(eth_addr, eth_addr_mask) \
((is_wildcard(&(eth_addr)[0], ETH_ALEN) && \
is_wildcard(&(eth_addr)[ETH_ALEN / 2], ETH_ALEN)) || \
(is_wildcard(&(eth_addr_mask)[0], ETH_ALEN) && \
is_wildcard(&(eth_addr_mask)[ETH_ALEN / 2], ETH_ALEN)))
struct bnxt_tc_actions {
u32 flags;
#define BNXT_TC_ACTION_FLAG_FWD BIT(0)
@ -57,16 +75,30 @@ struct bnxt_tc_actions {
#define BNXT_TC_ACTION_FLAG_PUSH_VLAN BIT(3)
#define BNXT_TC_ACTION_FLAG_POP_VLAN BIT(4)
#define BNXT_TC_ACTION_FLAG_DROP BIT(5)
#define BNXT_TC_ACTION_FLAG_TUNNEL_ENCAP BIT(6)
#define BNXT_TC_ACTION_FLAG_TUNNEL_DECAP BIT(7)
#define BNXT_TC_ACTION_FLAG_L2_REWRITE BIT(8)
#define BNXT_TC_ACTION_FLAG_NAT_XLATE BIT(9)
u16 dst_fid;
struct net_device *dst_dev;
__be16 push_vlan_tpid;
__be16 push_vlan_tci;
};
struct bnxt_tc_flow_stats {
u64 packets;
u64 bytes;
/* tunnel encap */
struct ip_tunnel_key tun_encap_key;
#define PEDIT_OFFSET_SMAC_LAST_4_BYTES 0x8
__be16 l2_rewrite_dmac[3];
__be16 l2_rewrite_smac[3];
struct {
bool src_xlate; /* true => translate src,
* false => translate dst
* Mutually exclusive, i.e cannot set both
*/
bool l3_is_ipv4; /* false means L3 is ipv6 */
struct bnxt_tc_l3_key l3;
struct bnxt_tc_l4_key l4;
} nat;
};
struct bnxt_tc_flow {
@ -76,6 +108,16 @@ struct bnxt_tc_flow {
#define BNXT_TC_FLOW_FLAGS_IPV6_ADDRS BIT(3)
#define BNXT_TC_FLOW_FLAGS_PORTS BIT(4)
#define BNXT_TC_FLOW_FLAGS_ICMP BIT(5)
#define BNXT_TC_FLOW_FLAGS_TUNL_ETH_ADDRS BIT(6)
#define BNXT_TC_FLOW_FLAGS_TUNL_IPV4_ADDRS BIT(7)
#define BNXT_TC_FLOW_FLAGS_TUNL_IPV6_ADDRS BIT(8)
#define BNXT_TC_FLOW_FLAGS_TUNL_PORTS BIT(9)
#define BNXT_TC_FLOW_FLAGS_TUNL_ID BIT(10)
#define BNXT_TC_FLOW_FLAGS_TUNNEL (BNXT_TC_FLOW_FLAGS_TUNL_ETH_ADDRS | \
BNXT_TC_FLOW_FLAGS_TUNL_IPV4_ADDRS | \
BNXT_TC_FLOW_FLAGS_TUNL_IPV6_ADDRS |\
BNXT_TC_FLOW_FLAGS_TUNL_PORTS |\
BNXT_TC_FLOW_FLAGS_TUNL_ID)
/* flow applicable to pkts ingressing on this fid */
u16 src_fid;
@ -85,6 +127,8 @@ struct bnxt_tc_flow {
struct bnxt_tc_l3_key l3_mask;
struct bnxt_tc_l4_key l4_key;
struct bnxt_tc_l4_key l4_mask;
struct ip_tunnel_key tun_key;
struct ip_tunnel_key tun_mask;
struct bnxt_tc_actions actions;
@ -93,13 +137,41 @@ struct bnxt_tc_flow {
/* previous snap-shot of stats */
struct bnxt_tc_flow_stats prev_stats;
unsigned long lastused; /* jiffies */
/* for calculating delta from prev_stats and
* updating prev_stats atomically.
*/
spinlock_t stats_lock;
};
/* L2 hash table
* This data-struct is used for L2-flow table.
* The L2 part of a flow is stored in a hash table.
/*
* Tunnel encap/decap hash table
* This table is used to maintain a list of flows that use
* the same tunnel encap/decap params (ip_daddrs, vni, udp_dport)
* and the FW returned handle.
* A separate table is maintained for encap and decap
*/
struct bnxt_tc_tunnel_node {
struct ip_tunnel_key key;
struct rhash_head node;
/* tunnel l2 info */
struct bnxt_tc_l2_key l2_info;
#define INVALID_TUNNEL_HANDLE cpu_to_le32(0xffffffff)
/* tunnel handle returned by FW */
__le32 tunnel_handle;
u32 refcount;
struct rcu_head rcu;
};
/*
* L2 hash table
* The same data-struct is used for L2-flow table and L2-tunnel table.
* The L2 part of a flow or tunnel is stored in a hash table.
* A flow that shares the same L2 key/mask with an
* already existing flow must refer to it's flow handle.
* already existing flow/tunnel must refer to it's flow handle or
* decap_filter_id respectively.
*/
struct bnxt_tc_l2_node {
/* hash key: first 16b of key */
@ -110,12 +182,18 @@ struct bnxt_tc_l2_node {
/* a linked list of flows that share the same l2 key */
struct list_head common_l2_flows;
/* number of flows sharing the l2 key */
/* number of flows/tunnels sharing the l2 key */
u16 refcount;
struct rcu_head rcu;
};
/* Track if the TC offload API is invoked on an ingress or egress device. */
enum {
BNXT_TC_DEV_INGRESS = 1,
BNXT_TC_DEV_EGRESS = 2
};
struct bnxt_tc_flow_node {
/* hash key: provided by TC */
unsigned long cookie;
@ -123,29 +201,54 @@ struct bnxt_tc_flow_node {
struct bnxt_tc_flow flow;
__le64 ext_flow_handle;
__le16 flow_handle;
__le32 flow_id;
int tc_dev_dir;
/* L2 node in l2 hashtable that shares flow's l2 key */
struct bnxt_tc_l2_node *l2_node;
/* for the shared_flows list maintained in l2_node */
struct list_head l2_list_node;
/* tunnel encap related */
struct bnxt_tc_tunnel_node *encap_node;
/* tunnel decap related */
struct bnxt_tc_tunnel_node *decap_node;
/* L2 node in tunnel-l2 hashtable that shares flow's tunnel l2 key */
struct bnxt_tc_l2_node *decap_l2_node;
/* for the shared_flows list maintained in tunnel decap l2_node */
struct list_head decap_l2_list_node;
struct rcu_head rcu;
};
#ifdef HAVE_TC_CB_EGDEV
int bnxt_tc_setup_flower(struct bnxt *bp, u16 src_fid,
struct tc_cls_flower_offload *cls_flower);
struct flow_cls_offload *cls_flower,
int tc_dev_dir);
#else
int bnxt_tc_setup_flower(struct bnxt *bp, u16 src_fid,
struct flow_cls_offload *cls_flower);
#endif
int bnxt_init_tc(struct bnxt *bp);
void bnxt_shutdown_tc(struct bnxt *bp);
void bnxt_tc_flow_stats_work(struct bnxt *bp);
#if defined(HAVE_TC_MATCHALL_FLOW_RULE) && defined(HAVE_FLOW_ACTION_POLICE)
int bnxt_tc_setup_matchall(struct bnxt *bp, u16 src_fid,
struct tc_cls_matchall_offload *cls_matchall);
#endif
static inline bool bnxt_tc_flower_enabled(struct bnxt *bp)
{
return bp->tc_info && bp->tc_info->enabled;
}
#else /* CONFIG_BNXT_FLOWER_OFFLOAD */
static inline int bnxt_tc_setup_flower(struct bnxt *bp, u16 src_fid,
struct tc_cls_flower_offload *cls_flower)
{
return -EOPNOTSUPP;
}
static inline int bnxt_init_tc(struct bnxt *bp)
{
return 0;
@ -154,5 +257,15 @@ static inline int bnxt_init_tc(struct bnxt *bp)
static inline void bnxt_shutdown_tc(struct bnxt *bp)
{
}
static inline void bnxt_tc_flow_stats_work(struct bnxt *bp)
{
}
static inline bool bnxt_tc_flower_enabled(struct bnxt *bp)
{
return false;
}
#endif /* CONFIG_BNXT_FLOWER_OFFLOAD */
#endif /* BNXT_TC_H */

View File

@ -1,12 +1,13 @@
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2016 Broadcom Limited
* 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>
@ -20,6 +21,7 @@
#include <asm/byteorder.h>
#include <linux/bitmap.h>
#include "bnxt_compat.h"
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_ulp.h"
@ -45,10 +47,8 @@ static int bnxt_register_dev(struct bnxt_en_dev *edev, int ulp_id,
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)
bp->cp_nr_rings == 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);
@ -79,16 +79,11 @@ static int bnxt_unregister_dev(struct bnxt_en_dev *edev, int ulp_id)
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;
if (ulp_id == BNXT_ROCE_ULP && ulp->msix_requested)
edev->en_ops->bnxt_free_msix(edev, ulp_id);
max_stat_ctxs = bnxt_get_max_func_stat_ctxs(bp);
bnxt_set_max_func_stat_ctxs(bp, max_stat_ctxs + 1);
if (ulp->msix_requested)
edev->en_ops->bnxt_free_msix(edev, ulp_id);
}
if (ulp->max_async_event_id)
bnxt_hwrm_func_rgtr_async_events(bp, NULL, 0);
bnxt_hwrm_func_drv_rgtr(bp, NULL, 0, true);
RCU_INIT_POINTER(ulp->ulp_ops, NULL);
synchronize_rcu();
@ -101,13 +96,36 @@ static int bnxt_unregister_dev(struct bnxt_en_dev *edev, int ulp_id)
return 0;
}
static void bnxt_fill_msix_vecs(struct bnxt *bp, struct bnxt_msix_entry *ent)
{
struct bnxt_en_dev *edev = bp->edev;
int num_msix, idx, i;
num_msix = edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested;
idx = edev->ulp_tbl[BNXT_ROCE_ULP].msix_base;
for (i = 0; i < num_msix; i++) {
ent[i].vector = bp->irq_tbl[idx + i].vector;
ent[i].ring_idx = idx + i;
if (bp->flags & BNXT_FLAG_CHIP_P5) {
ent[i].db_offset = DB_PF_OFFSET_P5;
if (BNXT_VF(bp))
ent[i].db_offset = DB_VF_OFFSET_P5;
} else {
ent[i].db_offset = (idx + i) * 0x80;
}
}
}
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);
struct bnxt_hw_resc *hw_resc;
int max_idx, max_cp_rings;
int avail_msix, i, idx;
int avail_msix, idx;
int total_vecs;
int rc = 0;
ASSERT_RTNL();
if (ulp_id != BNXT_ROCE_ULP)
@ -116,23 +134,49 @@ static int bnxt_req_msix_vecs(struct bnxt_en_dev *edev, int ulp_id,
if (!(bp->flags & BNXT_FLAG_USING_MSIX))
return -ENODEV;
if (edev->ulp_tbl[ulp_id].msix_requested)
return -EAGAIN;
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;
avail_msix = bnxt_get_avail_msix(bp, num_msix);
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;
if (BNXT_NEW_RM(bp)) {
idx = bp->cp_nr_rings;
} else {
max_idx = min_t(int, bp->total_irqs, max_cp_rings);
idx = max_idx - avail_msix;
}
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_base = idx;
edev->ulp_tbl[ulp_id].msix_requested = avail_msix;
hw_resc = &bp->hw_resc;
total_vecs = idx + avail_msix;
if (bp->total_irqs < total_vecs ||
(BNXT_NEW_RM(bp) && hw_resc->resv_irqs < total_vecs)) {
if (netif_running(dev)) {
bnxt_close_nic(bp, true, false);
rc = bnxt_open_nic(bp, true, false);
} else {
rc = bnxt_reserve_rings(bp, true);
}
}
if (rc) {
edev->ulp_tbl[ulp_id].msix_requested = 0;
return -EAGAIN;
}
if (BNXT_NEW_RM(bp)) {
int resv_msix;
resv_msix = hw_resc->resv_irqs - bp->cp_nr_rings;
avail_msix = min_t(int, resv_msix, avail_msix);
edev->ulp_tbl[ulp_id].msix_requested = avail_msix;
}
bnxt_fill_msix_vecs(bp, ent);
edev->flags |= BNXT_EN_FLAG_MSIX_REQUESTED;
return avail_msix;
}
@ -140,33 +184,50 @@ 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);
if (!(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
return 0;
edev->ulp_tbl[ulp_id].msix_requested = 0;
bnxt_set_max_func_irqs(bp, bp->total_irqs);
edev->flags &= ~BNXT_EN_FLAG_MSIX_REQUESTED;
if (netif_running(dev) && !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED)) {
bnxt_close_nic(bp, true, false);
bnxt_open_nic(bp, true, false);
}
return 0;
}
void bnxt_subtract_ulp_resources(struct bnxt *bp, int ulp_id)
int bnxt_get_ulp_msix_num(struct bnxt *bp)
{
ASSERT_RTNL();
if (bnxt_ulp_registered(bp->edev, ulp_id)) {
if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
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);
return edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested;
}
return 0;
}
int bnxt_get_ulp_msix_base(struct bnxt *bp)
{
if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
struct bnxt_en_dev *edev = bp->edev;
if (edev->ulp_tbl[BNXT_ROCE_ULP].msix_requested)
return edev->ulp_tbl[BNXT_ROCE_ULP].msix_base;
}
return 0;
}
int bnxt_get_ulp_stat_ctxs(struct bnxt *bp)
{
if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP))
return BNXT_MIN_ROCE_STAT_CTXS;
return 0;
}
static int bnxt_send_msg(struct bnxt_en_dev *edev, int ulp_id,
@ -177,12 +238,15 @@ static int bnxt_send_msg(struct bnxt_en_dev *edev, int ulp_id,
struct input *req;
int rc;
if ((ulp_id != BNXT_ROCE_ULP) && bp->fw_reset_state)
return -EBUSY;
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) {
if (rc != -EBUSY && rc != -E2BIG) {
struct output *resp = bp->hwrm_cmd_resp_addr;
u32 len = le16_to_cpu(resp->resp_len);
@ -214,6 +278,7 @@ void bnxt_ulp_stop(struct bnxt *bp)
if (!edev)
return;
edev->flags |= BNXT_EN_FLAG_ULP_STOPPED;
for (i = 0; i < BNXT_MAX_ULP; i++) {
struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
@ -224,7 +289,7 @@ void bnxt_ulp_stop(struct bnxt *bp)
}
}
void bnxt_ulp_start(struct bnxt *bp)
void bnxt_ulp_start(struct bnxt *bp, int err)
{
struct bnxt_en_dev *edev = bp->edev;
struct bnxt_ulp_ops *ops;
@ -233,6 +298,11 @@ void bnxt_ulp_start(struct bnxt *bp)
if (!edev)
return;
edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
if (err)
return;
for (i = 0; i < BNXT_MAX_ULP; i++) {
struct bnxt_ulp *ulp = &edev->ulp_tbl[i];
@ -287,6 +357,58 @@ void bnxt_ulp_shutdown(struct bnxt *bp)
}
}
void bnxt_ulp_irq_stop(struct bnxt *bp)
{
struct bnxt_en_dev *edev = bp->edev;
struct bnxt_ulp_ops *ops;
if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
return;
if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
struct bnxt_ulp *ulp = &edev->ulp_tbl[BNXT_ROCE_ULP];
if (!ulp->msix_requested)
return;
ops = rtnl_dereference(ulp->ulp_ops);
if (!ops || !ops->ulp_irq_stop)
return;
ops->ulp_irq_stop(ulp->handle);
}
}
void bnxt_ulp_irq_restart(struct bnxt *bp, int err)
{
struct bnxt_en_dev *edev = bp->edev;
struct bnxt_ulp_ops *ops;
if (!edev || !(edev->flags & BNXT_EN_FLAG_MSIX_REQUESTED))
return;
if (bnxt_ulp_registered(bp->edev, BNXT_ROCE_ULP)) {
struct bnxt_ulp *ulp = &edev->ulp_tbl[BNXT_ROCE_ULP];
struct bnxt_msix_entry *ent = NULL;
if (!ulp->msix_requested)
return;
ops = rtnl_dereference(ulp->ulp_ops);
if (!ops || !ops->ulp_irq_restart)
return;
if (!err) {
ent = kcalloc(ulp->msix_requested, sizeof(*ent),
GFP_KERNEL);
if (!ent)
return;
bnxt_fill_msix_vecs(bp, ent);
}
ops->ulp_irq_restart(ulp->handle, ent);
kfree(ent);
}
}
void bnxt_ulp_async_events(struct bnxt *bp, struct hwrm_async_event_cmpl *cmpl)
{
u16 event_id = le16_to_cpu(cmpl->event_id);
@ -331,7 +453,7 @@ static int bnxt_register_async_events(struct bnxt_en_dev *edev, int ulp_id,
/* 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);
bnxt_hwrm_func_drv_rgtr(bp, events_bmap, max_id + 1, true);
return 0;
}
@ -361,6 +483,8 @@ struct bnxt_en_dev *bnxt_ulp_probe(struct net_device *dev)
edev->flags |= BNXT_EN_FLAG_ROCEV2_CAP;
edev->net = dev;
edev->pdev = bp->pdev;
edev->l2_db_size = bp->db_size;
edev->l2_db_size_nc = bp->db_size_nc;
bp->edev = edev;
}
return bp->edev;

View File

@ -1,6 +1,6 @@
/* Broadcom NetXtreme-C/E network driver.
*
* Copyright (c) 2016 Broadcom Limited
* 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
@ -10,6 +10,8 @@
#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
@ -20,6 +22,15 @@
struct hwrm_async_event_cmpl;
struct bnxt;
struct bnxt_msix_entry {
u32 vector;
u32 ring_idx;
u32 db_offset;
};
/* Change BNXT_ULP_VERSION in bnxt.h if any structure or API exposed to
* bnxt_re is modified.
*/
struct bnxt_ulp_ops {
/* async_notifier() cannot sleep (in BH context) */
void (*ulp_async_notifier)(void *, struct hwrm_async_event_cmpl *);
@ -27,12 +38,8 @@ struct bnxt_ulp_ops {
void (*ulp_start)(void *);
void (*ulp_sriov_config)(void *, int);
void (*ulp_shutdown)(void *);
};
struct bnxt_msix_entry {
u32 vector;
u32 ring_idx;
u32 db_offset;
void (*ulp_irq_stop)(void *);
void (*ulp_irq_restart)(void *, struct bnxt_msix_entry *);
};
struct bnxt_fw_msg {
@ -49,6 +56,7 @@ struct bnxt_ulp {
unsigned long *async_events_bmap;
u16 max_async_event_id;
u16 msix_requested;
u16 msix_base;
atomic_t ref_count;
};
@ -60,8 +68,18 @@ struct bnxt_en_dev {
#define BNXT_EN_FLAG_ROCEV2_CAP 0x2
#define BNXT_EN_FLAG_ROCE_CAP (BNXT_EN_FLAG_ROCEV1_CAP | \
BNXT_EN_FLAG_ROCEV2_CAP)
#define BNXT_EN_FLAG_MSIX_REQUESTED 0x4
#define BNXT_EN_FLAG_ULP_STOPPED 0x8
const struct bnxt_en_ops *en_ops;
struct bnxt_ulp ulp_tbl[BNXT_MAX_ULP];
int l2_db_size; /* Doorbell BAR size in
* bytes mapped by L2
* driver.
*/
int l2_db_size_nc; /* Doorbell BAR size in
* bytes mapped as non-
* cacheable.
*/
};
struct bnxt_en_ops {
@ -84,12 +102,15 @@ static inline bool bnxt_ulp_registered(struct bnxt_en_dev *edev, int ulp_id)
return false;
}
void bnxt_subtract_ulp_resources(struct bnxt *bp, int ulp_id);
int bnxt_get_ulp_msix_num(struct bnxt *bp);
int bnxt_get_ulp_msix_base(struct bnxt *bp);
int bnxt_get_ulp_stat_ctxs(struct bnxt *bp);
void bnxt_ulp_stop(struct bnxt *bp);
void bnxt_ulp_start(struct bnxt *bp);
void bnxt_ulp_start(struct bnxt *bp, int err);
void bnxt_ulp_sriov_cfg(struct bnxt *bp, int num_vfs);
void bnxt_ulp_shutdown(struct bnxt *bp);
void bnxt_ulp_irq_stop(struct bnxt *bp);
void bnxt_ulp_irq_restart(struct bnxt *bp, int err);
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

View File

@ -11,14 +11,18 @@
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
#include <linux/jhash.h>
#ifdef HAVE_TC_SETUP_TYPE
#include <net/pkt_cls.h>
#endif
#include "bnxt_compat.h"
#include "bnxt_hsi.h"
#include "bnxt.h"
#include "bnxt_vfr.h"
#include "bnxt_devlink.h"
#include "bnxt_tc.h"
#ifdef CONFIG_BNXT_SRIOV
#ifdef CONFIG_VF_REPS
#define CFA_HANDLE_INVALID 0xffff
#define VF_IDX_INVALID 0xffff
@ -63,6 +67,31 @@ static int hwrm_cfa_vfr_free(struct bnxt *bp, u16 vf_idx)
return rc;
}
static int bnxt_hwrm_vfr_qcfg(struct bnxt *bp, struct bnxt_vf_rep *vf_rep,
u16 *max_mtu)
{
struct hwrm_func_qcfg_output *resp = bp->hwrm_cmd_resp_addr;
struct hwrm_func_qcfg_input req = {0};
u16 mtu;
int rc;
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QCFG, -1, -1);
req.fid = bp->pf.vf[vf_rep->vf_idx].fw_fid;
mutex_lock(&bp->hwrm_cmd_lock);
rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
if (!rc) {
mtu = le16_to_cpu(resp->max_mtu_configured);
if (!mtu)
*max_mtu = BNXT_MAX_MTU;
else
*max_mtu = mtu;
}
mutex_unlock(&bp->hwrm_cmd_lock);
return rc;
}
static int bnxt_vf_rep_open(struct net_device *dev)
{
struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
@ -115,21 +144,143 @@ bnxt_vf_rep_get_stats64(struct net_device *dev,
stats->tx_bytes = vf_rep->tx_stats.bytes;
}
static int bnxt_vf_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
#ifdef CONFIG_BNXT_FLOWER_OFFLOAD
#ifdef HAVE_TC_SETUP_TYPE
#ifdef HAVE_TC_SETUP_BLOCK
static LIST_HEAD(bnxt_vf_block_cb_list);
static int bnxt_vf_rep_setup_tc_block_cb(enum tc_setup_type type,
void *type_data,
void *cb_priv)
{
struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
struct bnxt_vf_rep *vf_rep = cb_priv;
struct bnxt *bp = vf_rep->bp;
int vf_fid = bp->pf.vf[vf_rep->vf_idx].fw_fid;
if (!bnxt_tc_flower_enabled(vf_rep->bp) ||
!tc_cls_can_offload_and_chain0(bp->dev, type_data))
return -EOPNOTSUPP;
switch (type) {
case TC_SETUP_CLSFLOWER:
#ifdef HAVE_TC_CB_EGDEV
return bnxt_tc_setup_flower(bp, vf_fid, type_data,
BNXT_TC_DEV_INGRESS);
#else
return bnxt_tc_setup_flower(bp, vf_fid, type_data);
#endif
#if defined(HAVE_TC_MATCHALL_FLOW_RULE) && defined(HAVE_FLOW_ACTION_POLICE)
case TC_SETUP_CLSMATCHALL:
return bnxt_tc_setup_matchall(bp, vf_fid, type_data);
#endif
default:
return -EOPNOTSUPP;
}
}
#endif /* HAVE_TC_SETUP_BLOCK */
static int bnxt_vf_rep_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data)
{
struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
switch (type) {
#ifdef HAVE_TC_SETUP_BLOCK
case TC_SETUP_BLOCK:
return flow_block_cb_setup_simple(type_data,
&bnxt_vf_block_cb_list,
bnxt_vf_rep_setup_tc_block_cb, vf_rep, vf_rep, true);
#else
case TC_SETUP_CLSFLOWER: {
struct bnxt *bp = vf_rep->bp;
int vf_fid = bp->pf.vf[vf_rep->vf_idx].fw_fid;
#ifdef HAVE_TC_CB_EGDEV
return bnxt_tc_setup_flower(bp, vf_fid, type_data,
BNXT_TC_DEV_INGRESS);
#else
return bnxt_tc_setup_flower(bp, vf_fid, type_data);
#endif
}
#endif
default:
return -EOPNOTSUPP;
}
}
#else /* HAVE_TC_SETUP_TYPE */
#ifdef HAVE_CHAIN_INDEX
static int bnxt_vf_rep_setup_tc(struct net_device *dev, u32 handle,
u32 chain_index, __be16 proto,
struct tc_to_netdev *ntc)
#else
static int bnxt_vf_rep_setup_tc(struct net_device *dev, u32 handle,
__be16 proto, struct tc_to_netdev *ntc)
#endif
{
struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
if (!bnxt_tc_flower_enabled(vf_rep->bp))
return -EOPNOTSUPP;
switch (ntc->type) {
case TC_SETUP_CLSFLOWER:
#ifdef HAVE_TC_CB_EGDEV
return bnxt_tc_setup_flower(vf_rep->bp,
bnxt_vf_rep_get_fid(dev),
ntc->cls_flower,
BNXT_TC_DEV_INGRESS);
#else
return bnxt_tc_setup_flower(vf_rep->bp,
bnxt_vf_rep_get_fid(dev),
ntc->cls_flower);
#endif
default:
return -EOPNOTSUPP;
}
}
#endif /* HAVE_TC_SETUP_TYPE */
#ifdef HAVE_TC_CB_EGDEV
static int bnxt_vf_rep_tc_cb_egdev(enum tc_setup_type type, void *type_data,
void *cb_priv)
{
struct bnxt_vf_rep *vf_rep = cb_priv;
struct bnxt *bp = vf_rep->bp;
int vf_fid = bp->pf.vf[vf_rep->vf_idx].fw_fid;
if (!bnxt_tc_flower_enabled(vf_rep->bp) ||
!tc_cls_can_offload_and_chain0(bp->dev, type_data))
return -EOPNOTSUPP;
switch (type) {
case TC_SETUP_CLSFLOWER:
return bnxt_tc_setup_flower(bp, vf_fid, type_data,
BNXT_TC_DEV_EGRESS);
default:
return -EOPNOTSUPP;
}
}
#else
#ifdef HAVE_TC_SETUP_TYPE
static int bnxt_vf_rep_tc_cb_egdev(enum tc_setup_type type, void *type_data,
void *cb_priv)
#else
static int bnxt_vf_rep_tc_cb_egdev(int type, void *type_data, void *cb_priv)
#endif /* HAVE_TC_SETUP_TYPE */
{
return 0;
}
#endif /* HAVE_TC_CB_EGDEV */
#define bnxt_cb_egdev ((void *)bnxt_vf_rep_tc_cb_egdev)
#endif /* CONFIG_BNXT_FLOWER_OFFLOAD */
struct net_device *bnxt_get_vf_rep(struct bnxt *bp, u16 cfa_code)
{
u16 vf_idx;
@ -145,9 +296,7 @@ struct net_device *bnxt_get_vf_rep(struct bnxt *bp, u16 cfa_code)
void bnxt_vf_rep_rx(struct bnxt *bp, struct sk_buff *skb)
{
struct bnxt_vf_rep *vf_rep = netdev_priv(skb->dev);
struct bnxt_vf_rep_stats *rx_stats;
rx_stats = &vf_rep->rx_stats;
vf_rep->rx_stats.bytes += skb->len;
vf_rep->rx_stats.packets++;
@ -175,6 +324,20 @@ static void bnxt_vf_rep_get_drvinfo(struct net_device *dev,
strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version));
}
#ifdef HAVE_NDO_GET_PORT_PARENT_ID
static int bnxt_vf_rep_get_port_parent_id(struct net_device *dev,
struct netdev_phys_item_id *ppid)
{
struct bnxt_vf_rep *vf_rep = netdev_priv(dev);
/* as only PORT_PARENT_ID is supported currently use common code
* between PF and VF-rep for now.
*/
return bnxt_get_port_parent_id(vf_rep->bp->dev, ppid);
}
#else
static int bnxt_vf_rep_port_attr_get(struct net_device *dev,
struct switchdev_attr *attr)
{
@ -189,20 +352,42 @@ static int bnxt_vf_rep_port_attr_get(struct net_device *dev,
static const struct switchdev_ops bnxt_vf_rep_switchdev_ops = {
.switchdev_port_attr_get = bnxt_vf_rep_port_attr_get
};
#endif
static const struct ethtool_ops bnxt_vf_rep_ethtool_ops = {
.get_drvinfo = bnxt_vf_rep_get_drvinfo
};
static const struct net_device_ops bnxt_vf_rep_netdev_ops = {
#ifdef HAVE_NDO_SETUP_TC_RH
.ndo_size = sizeof(const struct net_device_ops),
#endif
.ndo_open = bnxt_vf_rep_open,
.ndo_stop = bnxt_vf_rep_close,
.ndo_start_xmit = bnxt_vf_rep_xmit,
.ndo_get_stats64 = bnxt_vf_rep_get_stats64,
#ifdef CONFIG_BNXT_FLOWER_OFFLOAD
#ifdef HAVE_NDO_SETUP_TC_RH
.extended.ndo_setup_tc_rh = bnxt_vf_rep_setup_tc,
#else
.ndo_setup_tc = bnxt_vf_rep_setup_tc,
#endif
#endif
#ifdef HAVE_NDO_GET_PORT_PARENT_ID
.ndo_get_port_parent_id = bnxt_vf_rep_get_port_parent_id,
#endif
#ifdef HAVE_EXT_GET_PHYS_PORT_NAME
.extended.ndo_get_phys_port_name = bnxt_vf_rep_get_phys_port_name
#else
.ndo_get_phys_port_name = bnxt_vf_rep_get_phys_port_name
#endif
};
bool bnxt_dev_is_vf_rep(struct net_device *dev)
{
return dev->netdev_ops == &bnxt_vf_rep_netdev_ops;
}
/* Called when the parent PF interface is closed:
* As the mode transition from SWITCHDEV to LEGACY
* happens under the rtnl_lock() this routine is safe
@ -258,8 +443,14 @@ static void __bnxt_vf_reps_destroy(struct bnxt *bp)
/* if register_netdev failed, then netdev_ops
* would have been set to NULL
*/
if (vf_rep->dev->netdev_ops)
if (vf_rep->dev->netdev_ops) {
#ifdef CONFIG_BNXT_FLOWER_OFFLOAD
bnxt_unreg_egdev(vf_rep->dev,
bnxt_cb_egdev,
(void *)vf_rep);
#endif
unregister_netdev(vf_rep->dev);
}
free_netdev(vf_rep->dev);
}
}
@ -321,10 +512,13 @@ static void bnxt_vf_rep_netdev_init(struct bnxt *bp, struct bnxt_vf_rep *vf_rep,
struct net_device *dev)
{
struct net_device *pf_dev = bp->dev;
u16 max_mtu;
dev->netdev_ops = &bnxt_vf_rep_netdev_ops;
dev->ethtool_ops = &bnxt_vf_rep_ethtool_ops;
#ifndef HAVE_NDO_GET_PORT_PARENT_ID
SWITCHDEV_SET_OPS(dev, &bnxt_vf_rep_switchdev_ops);
#endif
/* Just inherit all the featues of the parent PF as the VF-R
* uses the RX/TX rings of the parent PF
*/
@ -336,6 +530,15 @@ static void bnxt_vf_rep_netdev_init(struct bnxt *bp, struct bnxt_vf_rep *vf_rep,
bnxt_vf_rep_eth_addr_gen(bp->pf.mac_addr, vf_rep->vf_idx,
dev->perm_addr);
ether_addr_copy(dev->dev_addr, dev->perm_addr);
/* Set VF-Rep's max-mtu to the corresponding VF's max-mtu */
if (!bnxt_hwrm_vfr_qcfg(bp, vf_rep, &max_mtu))
#ifdef HAVE_NET_DEVICE_EXT
dev->extended->max_mtu = max_mtu;
dev->extended->min_mtu = ETH_ZLEN;
#else
dev->max_mtu = max_mtu;
dev->min_mtu = ETH_ZLEN;
#endif
}
static int bnxt_vf_reps_create(struct bnxt *bp)
@ -345,13 +548,16 @@ static int bnxt_vf_reps_create(struct bnxt *bp)
struct net_device *dev;
int rc, i;
if (!(bp->flags & BNXT_FLAG_DSN_VALID))
return -ENODEV;
bp->vf_reps = kcalloc(num_vfs, sizeof(vf_rep), GFP_KERNEL);
if (!bp->vf_reps)
return -ENOMEM;
/* storage for cfa_code to vf-idx mapping */
cfa_code_map = kmalloc(sizeof(*bp->cfa_code_map) * MAX_CFA_CODE,
GFP_KERNEL);
cfa_code_map = kmalloc_array(MAX_CFA_CODE, sizeof(*bp->cfa_code_map),
GFP_KERNEL);
if (!cfa_code_map) {
rc = -ENOMEM;
goto err;
@ -400,6 +606,10 @@ static int bnxt_vf_reps_create(struct bnxt *bp)
dev->netdev_ops = NULL;
goto err;
}
#ifdef CONFIG_BNXT_FLOWER_OFFLOAD
bnxt_reg_egdev(vf_rep->dev, bnxt_cb_egdev, (void *)vf_rep,
vf_rep->vf_idx);
#endif
}
/* publish cfa_code_map only after all VF-reps have been initialized */
@ -416,7 +626,7 @@ err:
}
/* Devlink related routines */
static int bnxt_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode)
int bnxt_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode)
{
struct bnxt *bp = bnxt_get_bp_from_dl(devlink);
@ -424,7 +634,12 @@ static int bnxt_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode)
return 0;
}
static int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode)
#ifdef HAVE_ESWITCH_MODE_SET_EXTACK
int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode,
struct netlink_ext_ack *extack)
#else
int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode)
#endif
{
struct bnxt *bp = bnxt_get_bp_from_dl(devlink);
int rc = 0;
@ -444,9 +659,14 @@ static int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode)
break;
case DEVLINK_ESWITCH_MODE_SWITCHDEV:
if (bp->hwrm_spec_code < 0x10803) {
netdev_warn(bp->dev, "FW does not support SRIOV E-Switch SWITCHDEV mode\n");
rc = -ENOTSUPP;
goto done;
}
if (pci_num_vf(bp->pdev) == 0) {
netdev_info(bp->dev,
"Enable VFs before setting switchdev mode");
netdev_info(bp->dev, "Enable VFs before setting switchdev mode");
rc = -EPERM;
goto done;
}
@ -462,52 +682,4 @@ done:
return rc;
}
static const struct devlink_ops bnxt_dl_ops = {
.eswitch_mode_set = bnxt_dl_eswitch_mode_set,
.eswitch_mode_get = bnxt_dl_eswitch_mode_get
};
int bnxt_dl_register(struct bnxt *bp)
{
struct devlink *dl;
int rc;
if (!pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV))
return 0;
if (bp->hwrm_spec_code < 0x10800) {
netdev_warn(bp->dev, "Firmware does not support SR-IOV E-Switch SWITCHDEV mode.\n");
return -ENOTSUPP;
}
dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl));
if (!dl) {
netdev_warn(bp->dev, "devlink_alloc failed");
return -ENOMEM;
}
bnxt_link_bp_to_dl(bp, dl);
bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
rc = devlink_register(dl, &bp->pdev->dev);
if (rc) {
bnxt_link_bp_to_dl(bp, NULL);
devlink_free(dl);
netdev_warn(bp->dev, "devlink_register failed. rc=%d", rc);
return rc;
}
return 0;
}
void bnxt_dl_unregister(struct bnxt *bp)
{
struct devlink *dl = bp->dl;
if (!dl)
return;
devlink_unregister(dl);
devlink_free(dl);
}
#endif
#endif /* CONFIG_VF_REPS */

View File

@ -10,35 +10,10 @@
#ifndef BNXT_VFR_H
#define BNXT_VFR_H
#ifdef CONFIG_BNXT_SRIOV
#ifdef CONFIG_VF_REPS
#define MAX_CFA_CODE 65536
/* Struct to hold housekeeping info needed by devlink interface */
struct bnxt_dl {
struct bnxt *bp; /* back ptr to the controlling dev */
};
static inline struct bnxt *bnxt_get_bp_from_dl(struct devlink *dl)
{
return ((struct bnxt_dl *)devlink_priv(dl))->bp;
}
/* To clear devlink pointer from bp, pass NULL dl */
static inline void bnxt_link_bp_to_dl(struct bnxt *bp, struct devlink *dl)
{
bp->dl = dl;
/* add a back pointer in dl to bp */
if (dl) {
struct bnxt_dl *bp_dl = devlink_priv(dl);
bp_dl->bp = bp;
}
}
int bnxt_dl_register(struct bnxt *bp);
void bnxt_dl_unregister(struct bnxt *bp);
void bnxt_vf_reps_destroy(struct bnxt *bp);
void bnxt_vf_reps_close(struct bnxt *bp);
void bnxt_vf_reps_open(struct bnxt *bp);
@ -53,14 +28,18 @@ static inline u16 bnxt_vf_rep_get_fid(struct net_device *dev)
return bp->pf.vf[vf_rep->vf_idx].fw_fid;
}
bool bnxt_dev_is_vf_rep(struct net_device *dev);
int bnxt_dl_eswitch_mode_get(struct devlink *devlink, u16 *mode);
#ifdef HAVE_ESWITCH_MODE_SET_EXTACK
int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode,
struct netlink_ext_ack *extack);
#else
int bnxt_dl_eswitch_mode_set(struct devlink *devlink, u16 mode);
#endif
#else
static inline int bnxt_dl_register(struct bnxt *bp)
{
return 0;
}
static inline void bnxt_dl_unregister(struct bnxt *bp)
static inline void bnxt_vf_reps_destroy(struct bnxt *bp)
{
}
@ -85,5 +64,10 @@ static inline u16 bnxt_vf_rep_get_fid(struct net_device *dev)
{
return 0;
}
#endif /* CONFIG_BNXT_SRIOV */
static inline bool bnxt_dev_is_vf_rep(struct net_device *dev)
{
return false;
}
#endif /* CONFIG_VF_REPS */
#endif /* BNXT_VFR_H */

View File

@ -12,15 +12,24 @@
#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"
#ifdef CONFIG_PAGE_POOL
#include <net/page_pool.h>
#endif
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 *bnxt_xmit_bd(struct bnxt *bp,
struct bnxt_tx_ring_info *txr,
dma_addr_t mapping, u32 len)
{
struct bnxt_sw_tx_bd *tx_buf;
struct tx_bd *txbd;
@ -28,8 +37,7 @@ void bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
u16 prod;
prod = txr->tx_prod;
tx_buf = &txr->tx_buf_ring[prod];
tx_buf->rx_prod = rx_prod;
tx_buf = &txr->tx_buf_ring[RING_TX(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) |
@ -40,30 +48,72 @@ void bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
prod = NEXT_TX(prod);
txr->tx_prod = prod;
return tx_buf;
}
#ifdef HAVE_NDO_XDP
static 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;
tx_buf = bnxt_xmit_bd(bp, txr, mapping, len);
tx_buf->rx_prod = rx_prod;
tx_buf->action = XDP_TX;
}
#ifdef HAVE_XDP_FRAME
static void __bnxt_xmit_xdp_redirect(struct bnxt *bp,
struct bnxt_tx_ring_info *txr,
dma_addr_t mapping, u32 len,
struct xdp_frame *xdpf)
{
struct bnxt_sw_tx_bd *tx_buf;
tx_buf = bnxt_xmit_bd(bp, txr, mapping, len);
tx_buf->action = XDP_REDIRECT;
tx_buf->xdpf = xdpf;
dma_unmap_addr_set(tx_buf, mapping, mapping);
dma_unmap_len_set(tx_buf, len, 0);
}
#endif
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;
bool rx_doorbell_needed = false;
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_buf = &txr->tx_buf_ring[RING_TX(tx_cons)];
if (tx_buf->action == XDP_REDIRECT) {
struct pci_dev *pdev = bp->pdev;
dma_unmap_single(&pdev->dev,
dma_unmap_addr(tx_buf, mapping),
dma_unmap_len(tx_buf, len),
PCI_DMA_TODEVICE);
#ifdef HAVE_XDP_FRAME
xdp_return_frame(tx_buf->xdpf);
#endif
tx_buf->action = 0;
tx_buf->xdpf = NULL;
} else if (tx_buf->action == XDP_TX) {
rx_doorbell_needed = true;
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;
if (rx_doorbell_needed) {
tx_buf = &txr->tx_buf_ring[RING_TX(last_tx_cons)];
bnxt_db_write(bp, &rxr->rx_db, tx_buf->rx_prod);
}
bnxt_db_write(bp, rxr->rx_doorbell, DB_KEY_RX | rx_prod);
}
/* returns the following:
@ -88,18 +138,24 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
return false;
pdev = bp->pdev;
txr = rxr->bnapi->tx_ring;
rx_buf = &rxr->rx_buf_ring[cons];
offset = bp->rx_offset;
xdp.data_hard_start = *data_ptr - offset;
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);
txr = rxr->bnapi->tx_ring;
#if XDP_PACKET_HEADROOM
xdp.data_hard_start = *data_ptr - offset;
#endif
xdp.data = *data_ptr;
xdp_set_data_meta_invalid(&xdp);
xdp.data_end = *data_ptr + *len;
#ifdef HAVE_XDP_RXQ_INFO
xdp.rxq = &rxr->xdp_rxq;
#endif
orig_data = xdp.data;
rcu_read_lock();
act = bpf_prog_run_xdp(xdp_prog, &xdp);
rcu_read_unlock();
@ -111,10 +167,14 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
if (tx_avail != bp->tx_ring_size)
*event &= ~BNXT_RX_EVENT;
#if XDP_PACKET_HEADROOM
*len = xdp.data_end - xdp.data;
#endif
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:
@ -130,10 +190,38 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
*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,
__bnxt_xmit_xdp(bp, txr, mapping + offset, *len,
NEXT_RX(rxr->rx_prod));
bnxt_reuse_rx_data(rxr, cons, page);
return true;
case XDP_REDIRECT:
/* if we are calling this here then we know that the
* redirect is coming from a frame received by the
* bnxt_en driver.
*/
dma_unmap_page_attrs(&pdev->dev, mapping,
PAGE_SIZE, bp->rx_dir,
DMA_ATTR_WEAK_ORDERING);
/* if we are unable to allocate a new buffer, abort and reuse */
if (bnxt_alloc_rx_data(bp, rxr, rxr->rx_prod, GFP_ATOMIC)) {
trace_xdp_exception(bp->dev, xdp_prog, act);
bnxt_reuse_rx_data(rxr, cons, page);
return true;
}
if (xdp_do_redirect(bp->dev, &xdp, xdp_prog)) {
trace_xdp_exception(bp->dev, xdp_prog, act);
#ifndef CONFIG_PAGE_POOL
__free_page(page);
#else
page_pool_recycle_direct(rxr->page_pool, page);
#endif
return true;
}
*event |= BNXT_REDIRECT_EVENT;
break;
default:
bpf_warn_invalid_xdp_action(act);
/* Fall thru */
@ -147,6 +235,57 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,
return true;
}
#ifdef HAVE_XDP_FRAME
int bnxt_xdp_xmit(struct net_device *dev, int num_frames,
struct xdp_frame **frames, u32 flags)
{
struct bnxt *bp = netdev_priv(dev);
struct bpf_prog *xdp_prog = READ_ONCE(bp->xdp_prog);
struct pci_dev *pdev = bp->pdev;
struct bnxt_tx_ring_info *txr;
dma_addr_t mapping;
int drops = 0;
int ring;
int i;
if (!test_bit(BNXT_STATE_OPEN, &bp->state) ||
!bp->tx_nr_rings_xdp ||
!xdp_prog)
return -EINVAL;
ring = smp_processor_id() % bp->tx_nr_rings_xdp;
txr = &bp->tx_ring[ring];
for (i = 0; i < num_frames; i++) {
struct xdp_frame *xdp = frames[i];
if (!txr || !bnxt_tx_avail(bp, txr) ||
!(bp->bnapi[ring]->flags & BNXT_NAPI_FLAG_XDP)) {
xdp_return_frame_rx_napi(xdp);
drops++;
continue;
}
mapping = dma_map_single(&pdev->dev, xdp->data, xdp->len,
DMA_TO_DEVICE);
if (dma_mapping_error(&pdev->dev, mapping)) {
xdp_return_frame_rx_napi(xdp);
drops++;
continue;
}
__bnxt_xmit_xdp_redirect(bp, txr, mapping, xdp->len, xdp);
}
if (flags & XDP_XMIT_FLUSH) {
/* Sync BD data before updating doorbell */
wmb();
bnxt_db_write(bp, &txr->tx_db, txr->tx_prod);
}
return num_frames - drops;
}
#endif
/* Under rtnl_lock */
static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
{
@ -197,7 +336,6 @@ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
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);
@ -207,7 +345,7 @@ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog)
return 0;
}
int bnxt_xdp(struct net_device *dev, struct netdev_xdp *xdp)
int bnxt_xdp(struct net_device *dev, struct netdev_bpf *xdp)
{
struct bnxt *bp = netdev_priv(dev);
int rc;
@ -217,8 +355,12 @@ int bnxt_xdp(struct net_device *dev, struct netdev_xdp *xdp)
rc = bnxt_xdp_set(bp, xdp->prog);
break;
case XDP_QUERY_PROG:
#ifdef HAVE_PROG_ATTACHED
xdp->prog_attached = !!bp->xdp_prog;
#endif
#ifdef HAVE_IFLA_XDP_PROG_ID
xdp->prog_id = bp->xdp_prog ? bp->xdp_prog->aux->id : 0;
#endif
rc = 0;
break;
default:
@ -227,3 +369,14 @@ int bnxt_xdp(struct net_device *dev, struct netdev_xdp *xdp)
}
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

View File

@ -10,12 +10,22 @@
#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);
struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
struct bnxt_tx_ring_info *txr,
dma_addr_t mapping, u32 len);
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);
int bnxt_xdp(struct net_device *dev, struct netdev_xdp *xdp);
#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_bpf *xdp);
#ifdef HAVE_XDP_FRAME
int bnxt_xdp_xmit(struct net_device *dev, int num_frames,
struct xdp_frame **frames, u32 flags);
#endif
#endif