mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-23 17:55:05 +03:00
mft: Initial copy of mft source
Add initial mft source of version-4.26.1-3 from https://www.mellanox.com/downloads/MFT/mft-4.26.1-3-arm64-deb.tgz bug 4192483 bug 4312056 Change-Id: I77c0af297c9833c3dcbcdfc89b316042548b9af8 Signed-off-by: Bharath H S <bhs@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3069977 (cherry picked from commit d65df2a986469950aab3f323bbee3a3aee0c0308) Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3069972 GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com> Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
f451b88fd7
commit
bf89e2d98e
378
drivers/net/ethernet/mft/COPYING
Normal file
378
drivers/net/ethernet/mft/COPYING
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
This software is available to you under a choice of one of two licenses.
|
||||||
|
You may chose to be licensed under the terms of the the OpenIB.org BSD
|
||||||
|
license or the GNU General Public License (GPL) Version 2, both included
|
||||||
|
below.
|
||||||
|
|
||||||
|
Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
|
||||||
|
|
||||||
|
==================================================================
|
||||||
|
|
||||||
|
OpenIB.org BSD license
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
==================================================================
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
||||||
25
drivers/net/ethernet/mft/Makefile
Normal file
25
drivers/net/ethernet/mft/Makefile
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
CPU_ARCH ?= $(shell uname -m)
|
||||||
|
|
||||||
|
all:
|
||||||
|
cd mst_backward_compatibility/mst_pci && $(MAKE)
|
||||||
|
cd mst_backward_compatibility/mst_pciconf && $(MAKE)
|
||||||
|
|
||||||
|
ifneq ($(findstring ppc64, $(CPU_ARCH)),)
|
||||||
|
cd mst_backward_compatibility/mst_ppc && $(MAKE)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(findstring aarch64, $(CPU_ARCH)),)
|
||||||
|
cd misc_drivers/bf3_livefish && $(MAKE)
|
||||||
|
endif
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(MAKE) clean -C mst_backward_compatibility/mst_pci
|
||||||
|
$(MAKE) clean -C mst_backward_compatibility/mst_pciconf
|
||||||
|
|
||||||
|
ifneq ($(findstring ppc64, $(CPU_ARCH)),)
|
||||||
|
$(MAKE) clean -C mst_backward_compatibility/mst_ppc
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(findstring aarch64, $(CPU_ARCH)),)
|
||||||
|
$(MAKE) clean -C misc_drivers/bf3_livefish
|
||||||
|
endif
|
||||||
296
drivers/net/ethernet/mft/common.postinst
Executable file
296
drivers/net/ethernet/mft/common.postinst
Executable file
@@ -0,0 +1,296 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
uname_s=$(uname -s)
|
||||||
|
|
||||||
|
_get_kernel_dir() {
|
||||||
|
KVER=$1
|
||||||
|
case ${uname_s} in
|
||||||
|
Linux) DIR="/lib/modules/$KVER/build" ;;
|
||||||
|
GNU/kFreeBSD) DIR="/usr/src/kfreebsd-headers-$KVER/sys" ;;
|
||||||
|
esac
|
||||||
|
echo $DIR
|
||||||
|
}
|
||||||
|
|
||||||
|
_check_kernel_dir() {
|
||||||
|
DIR=$(_get_kernel_dir $1)
|
||||||
|
case ${uname_s} in
|
||||||
|
Linux) test -e $DIR/include ;;
|
||||||
|
GNU/kFreeBSD) test -e $DIR/kern && test -e $DIR/conf/kmod.mk ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check the existence of a kernel named as $1
|
||||||
|
_is_kernel_name_correct() {
|
||||||
|
CORRECT="no"
|
||||||
|
KERNEL_NAME=$1
|
||||||
|
|
||||||
|
for kernel in /boot/config-*; do
|
||||||
|
KERNEL=${kernel#*-}
|
||||||
|
if [ "${KERNEL}" = "${KERNEL_NAME}" ]; then
|
||||||
|
CORRECT="yes"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo $CORRECT
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Get the most recent kernel on Debian based systems. This keeps
|
||||||
|
# into account both the version and the ABI. If the current kernel
|
||||||
|
# is the most recent kernel then the function will print a null string.
|
||||||
|
_get_newest_kernel_debian() {
|
||||||
|
NEWEST_KERNEL=
|
||||||
|
NEWEST_VERSION=
|
||||||
|
NEWEST_ABI=
|
||||||
|
|
||||||
|
for kernel in /boot/config-*; do
|
||||||
|
KERNEL=${kernel#*-}
|
||||||
|
KERNEL_VERSION=${KERNEL%%-*}
|
||||||
|
ABI=${KERNEL#*-}
|
||||||
|
ABI=${ABI%%-*}
|
||||||
|
|
||||||
|
if [ -z "$NEWEST_KERNEL" ]; then
|
||||||
|
# The 1st time get a version which is bigger than $1
|
||||||
|
COMPARE_TO=$1
|
||||||
|
else
|
||||||
|
# Get the biggest version
|
||||||
|
COMPARE_TO="$NEWEST_VERSION-$NEWEST_ABI"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make sure that kernel exists before comparing it
|
||||||
|
if [ ! -e /lib/modules/$KERNEL ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if $kernel is greater than $COMPARE_TO
|
||||||
|
if [ `dpkg --compare-versions "$KERNEL_VERSION-$ABI" gt "$COMPARE_TO" && echo "yes" || \
|
||||||
|
echo "no"` = "yes" ]; then
|
||||||
|
NEWEST_KERNEL=$KERNEL
|
||||||
|
NEWEST_VERSION=$KERNEL_VERSION
|
||||||
|
NEWEST_ABI=$ABI
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "$NEWEST_KERNEL"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the most recent kernel in Rhel based systems. If the current kernel
|
||||||
|
# is the most recent kernel then the function will print a null string.
|
||||||
|
_get_newest_kernel_rhel() {
|
||||||
|
NEWEST_KERNEL=
|
||||||
|
|
||||||
|
LAST_INSTALLED_KERNEL=$(rpm -q --whatprovides kernel --last | grep kernel -m1 | cut -f1 -d' ')
|
||||||
|
|
||||||
|
LIK_FORMATTED_NAME=$(rpm -q $LAST_INSTALLED_KERNEL --queryformat="%{VERSION}-%{RELEASE}.%{ARCH}\n")
|
||||||
|
|
||||||
|
if [ `echo $LIK_FORMATTED_NAME | grep 2.6 >/dev/null` ]; then
|
||||||
|
# Fedora and Suse
|
||||||
|
NEWEST_KERNEL=$LIK_FORMATTED_NAME
|
||||||
|
else
|
||||||
|
# Hack for Mandriva where $LIK_FORMATTED_NAME is broken
|
||||||
|
LIK_NAME=$(rpm -q $LAST_INSTALLED_KERNEL --queryformat="%{NAME}\n")
|
||||||
|
LIK_TYPE=${LIK_NAME#kernel-}
|
||||||
|
LIK_TYPE=${LIK_TYPE%%-*}
|
||||||
|
LIK_STRIPPED=${LIK_NAME#kernel-}
|
||||||
|
LIK_STRIPPED=${LIK_STRIPPED#$LIK_TYPE-}
|
||||||
|
LIK_STRIPPED_BASE=${LIK_STRIPPED%%-*}
|
||||||
|
LIK_STRIPPED_END=${LIK_STRIPPED#$LIK_STRIPPED_BASE-}
|
||||||
|
LIK_FINAL=$LIK_STRIPPED_BASE-$LIK_TYPE-$LIK_STRIPPED_END
|
||||||
|
|
||||||
|
NEWEST_KERNEL=$LIK_FINAL
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $NEWEST_KERNEL
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the newest kernel on Debian and Rhel based systems.
|
||||||
|
get_newest_kernel() {
|
||||||
|
NEWEST_KERNEL=
|
||||||
|
# Try Debian first as rpm can be installed in Debian based distros
|
||||||
|
if [ -e /usr/bin/dpkg ]; then
|
||||||
|
# If DEB based
|
||||||
|
CURRENT_KERNEL=$1
|
||||||
|
CURRENT_VERSION=${CURRENT_KERNEL%%-*}
|
||||||
|
CURRENT_ABI=${CURRENT_KERNEL#*-}
|
||||||
|
CURRENT_FLAVOUR=${CURRENT_ABI#*-}
|
||||||
|
CURRENT_ABI=${CURRENT_ABI%%-*}
|
||||||
|
NEWEST_KERNEL=$(_get_newest_kernel_debian "$CURRENT_VERSION-$CURRENT_ABI")
|
||||||
|
|
||||||
|
elif [ `which rpm >/dev/null` ]; then
|
||||||
|
# If RPM based
|
||||||
|
NEWEST_KERNEL=$(_get_newest_kernel_rhel)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make sure that kernel name that we extracted corresponds to an installed
|
||||||
|
# kernel
|
||||||
|
if [ -n "$NEWEST_KERNEL" ] && [ `_is_kernel_name_correct $NEWEST_KERNEL` = "no" ]; then
|
||||||
|
NEWEST_KERNEL=
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $NEWEST_KERNEL
|
||||||
|
}
|
||||||
|
|
||||||
|
NAME=$1
|
||||||
|
VERSION=$2
|
||||||
|
TARBALL_ROOT=$3
|
||||||
|
ARCH=$4
|
||||||
|
UPGRADE=$5
|
||||||
|
|
||||||
|
if [ -z "$NAME" ] || [ -z "$VERSION" ]; then
|
||||||
|
echo "Need NAME, and VERSION defined"
|
||||||
|
echo "ARCH is optional"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
KERNELS=$(ls /lib/modules/ 2>/dev/null || true)
|
||||||
|
CURRENT_KERNEL=$(uname -r)
|
||||||
|
|
||||||
|
#We never want to keep an older version side by side to prevent conflicts
|
||||||
|
if [ -e "/var/lib/dkms/$NAME/$VERSION" ]; then
|
||||||
|
echo "Removing old $NAME-$VERSION DKMS files..."
|
||||||
|
dkms remove -m $NAME -v $VERSION --all
|
||||||
|
fi
|
||||||
|
|
||||||
|
#Load new files, by source package and by tarball
|
||||||
|
if [ -f "$TARBALL_ROOT/$NAME-$VERSION.dkms.tar.gz" ]; then
|
||||||
|
if ! dkms ldtarball --archive "$TARBALL_ROOT/$NAME-$VERSION.dkms.tar.gz"; then
|
||||||
|
echo ""
|
||||||
|
echo ""
|
||||||
|
echo "Unable to load DKMS tarball $TARBALL_ROOT/$NAME-$VERSION.dkms.tar.gz."
|
||||||
|
echo "Common causes include: "
|
||||||
|
echo " - You must be using DKMS 2.1.0.0 or later to support binaries only"
|
||||||
|
echo " distribution specific archives."
|
||||||
|
echo " - Corrupt distribution specific archive"
|
||||||
|
echo ""
|
||||||
|
echo ""
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
elif [ -d "/usr/src/$NAME-$VERSION" ]; then
|
||||||
|
echo "Loading new $NAME-$VERSION DKMS files..."
|
||||||
|
dkms add -m $NAME -v $VERSION > /dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
# On 1st installation, let us look for a directory
|
||||||
|
# in /lib/modules which matches `uname -r`. If none
|
||||||
|
# is found it is possible that buildd is being used
|
||||||
|
# and that uname -r is giving us the name of the
|
||||||
|
# kernel used by the buildd machine.
|
||||||
|
#
|
||||||
|
# If this is the case we try to build the kernel
|
||||||
|
# module for each kernel which has a directory in
|
||||||
|
# /lib/modules. Furthermore we will have to tell
|
||||||
|
# DKMS which architecture it should build the module
|
||||||
|
# for (e.g. if the buildd machine is using a
|
||||||
|
# 2.6.24-23-xen 64bit kernel).
|
||||||
|
#
|
||||||
|
# NOTE: if the headers are not installed then the
|
||||||
|
# module won't be built, as usual
|
||||||
|
if [ -z "$UPGRADE" ]; then
|
||||||
|
echo "First Installation: checking all kernels..."
|
||||||
|
for KERNEL in $KERNELS; do
|
||||||
|
if [ ${KERNEL} = ${CURRENT_KERNEL} ]; then
|
||||||
|
# Kernel found
|
||||||
|
KERNELS=$CURRENT_KERNEL
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
KERNELS=$CURRENT_KERNEL
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Here we look for the most recent kernel so that we can
|
||||||
|
# build the module for it (in addition to doing it for the
|
||||||
|
# current kernel.
|
||||||
|
NEWEST_KERNEL=$(get_newest_kernel "$KERNELS")
|
||||||
|
|
||||||
|
# If the current kernel doesn't come from the host of a chroot
|
||||||
|
if [ `_is_kernel_name_correct $CURRENT_KERNEL` = "yes" ]; then
|
||||||
|
# See if it's worth building the module for both the newest kernel
|
||||||
|
# and for the current kernel
|
||||||
|
if [ -n "$NEWEST_KERNEL" ] && [ ${CURRENT_KERNEL} != ${NEWEST_KERNEL} ]; then
|
||||||
|
echo "Building for $CURRENT_KERNEL and $NEWEST_KERNEL"
|
||||||
|
KERNELS="$CURRENT_KERNEL $NEWEST_KERNEL"
|
||||||
|
else
|
||||||
|
echo "Building only for $CURRENT_KERNEL"
|
||||||
|
fi
|
||||||
|
# The current kernel is not useful as it's the host's
|
||||||
|
else
|
||||||
|
echo "It is likely that $CURRENT_KERNEL belongs to a chroot's host"
|
||||||
|
|
||||||
|
# Let's use only the newest kernel
|
||||||
|
if [ -n "$NEWEST_KERNEL" ]; then
|
||||||
|
KERNELS="$NEWEST_KERNEL"
|
||||||
|
echo "Building only for $NEWEST_KERNEL"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$ARCH" ]; then
|
||||||
|
if which lsb_release >/dev/null && [ $(lsb_release -s -i) = "Ubuntu" ]; then
|
||||||
|
case $ARCH in
|
||||||
|
amd64)
|
||||||
|
ARCH="x86_64"
|
||||||
|
;;
|
||||||
|
lpia|i?86)
|
||||||
|
ARCH="i686"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
echo "Building for architecture $ARCH"
|
||||||
|
ARCH="-a $ARCH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for KERNEL in $KERNELS; do
|
||||||
|
dkms_status=`dkms status -m $NAME -v $VERSION -k $KERNEL $ARCH`
|
||||||
|
if [ `echo $KERNEL | grep -c "BOOT"` -gt 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "Module build and install for $KERNEL was skipped as "
|
||||||
|
echo "it is a BOOT variant"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
#if the module isn't yet built, try to build it
|
||||||
|
if [ `echo $dkms_status | grep -c ": built"` -eq 0 ]; then
|
||||||
|
if [ ! -L /var/lib/dkms/$NAME/$VERSION/source ]; then
|
||||||
|
echo "This package appears to be a binaries-only package"
|
||||||
|
echo " you will not be able to build against kernel $KERNEL"
|
||||||
|
echo " since the package source was not provided"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if _check_kernel_dir $KERNEL; then
|
||||||
|
echo "Building initial module for $KERNEL"
|
||||||
|
set +e
|
||||||
|
dkms build -m $NAME -v $VERSION -k $KERNEL $ARCH > /dev/null
|
||||||
|
case $? in
|
||||||
|
9)
|
||||||
|
set -e
|
||||||
|
echo "Skipped."
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
0)
|
||||||
|
set -e
|
||||||
|
echo "Done."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
dkms_status=`dkms status -m $NAME -v $VERSION -k $KERNEL $ARCH`
|
||||||
|
else
|
||||||
|
echo "Module build for the currently running kernel was skipped since the"
|
||||||
|
echo "kernel source for this kernel does not seem to be installed."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
#if the module is built (either pre-built or just now), install it
|
||||||
|
if [ `echo $dkms_status | grep -c ": built"` -eq 1 ] &&
|
||||||
|
[ `echo $dkms_status | grep -c ": installed"` -eq 0 ]; then
|
||||||
|
dkms install -m $NAME -v $VERSION -k $KERNEL $ARCH --force
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
21
drivers/net/ethernet/mft/dkms.conf
Normal file
21
drivers/net/ethernet/mft/dkms.conf
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
PACKAGE_NAME=kernel-mft-dkms
|
||||||
|
PACKAGE_VERSION=4.26.1
|
||||||
|
MAKE[0]="make all KPVER=$kernelver"
|
||||||
|
CLEAN="make -C src/ clean"
|
||||||
|
BUILT_MODULE_NAME[0]=mst_pci
|
||||||
|
BUILT_MODULE_NAME[1]=mst_pciconf
|
||||||
|
BUILT_MODULE_LOCATION[0]=./mst_backward_compatibility/mst_pci
|
||||||
|
BUILT_MODULE_LOCATION[1]=./mst_backward_compatibility/mst_pciconf
|
||||||
|
DEST_MODULE_LOCATION[0]="/updates"
|
||||||
|
DEST_MODULE_LOCATION[1]="/updates"
|
||||||
|
|
||||||
|
if [ $(arch) = aarch64 ]; then
|
||||||
|
BUILT_MODULE_NAME[2]=bf3_livefish
|
||||||
|
BUILT_MODULE_LOCATION[2]=./misc_drivers/bf3_livefish/
|
||||||
|
DEST_MODULE_LOCATION[2]="/updates"
|
||||||
|
fi
|
||||||
|
|
||||||
|
#REMAKE_INITRD=yes
|
||||||
|
|
||||||
|
# Rebuild and autoinstall automatically when dkms_autoinstaller runs for a new kernel
|
||||||
|
AUTOINSTALL="yes"
|
||||||
11
drivers/net/ethernet/mft/misc_drivers/bf3_livefish/Makefile
Normal file
11
drivers/net/ethernet/mft/misc_drivers/bf3_livefish/Makefile
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
KPVER ?= $(shell uname -r)
|
||||||
|
KSRC ?= /lib/modules/$(KPVER)/build
|
||||||
|
|
||||||
|
obj-m += bf3_livefish.o
|
||||||
|
|
||||||
|
all:
|
||||||
|
make -C $(KSRC) M=$(PWD) CONFIG_CTF= CONFIG_CC_STACKPROTECTOR_STRONG= $(WITH_MAKE_PARAMS) modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C $(KSRC) M=$(PWD) clean
|
||||||
|
|
||||||
@@ -0,0 +1,357 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
|
||||||
|
*
|
||||||
|
* This software product is a proprietary product of Nvidia Corporation and its affiliates
|
||||||
|
* (the "Company") and all right, title, and interest in and to the software
|
||||||
|
* product, including all associated intellectual property rights, are and
|
||||||
|
* shall remain exclusively with the Company.
|
||||||
|
*
|
||||||
|
* This software product is governed by the End User License Agreement
|
||||||
|
* provided with the software product.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "bf3_livefish.h"
|
||||||
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
|
static __iomem void *hca_va;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A valid I/O must be entirely within CR space and not extend into
|
||||||
|
* any unmapped areas of CR space. We don't truncate I/O that extends
|
||||||
|
* past the end of the CR space region (unlike the behavior of, for
|
||||||
|
* example, simple_read_from_buffer) but instead just call the whole
|
||||||
|
* I/O invalid. We also enforce 4-byte alignment for all I/O.
|
||||||
|
*/
|
||||||
|
static bool valid_range(loff_t offset, size_t len)
|
||||||
|
{
|
||||||
|
if ((offset % 4 != 0) || (len % 4 != 0)) {
|
||||||
|
// Unaligned,
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((offset >= 0) && (offset + len <= CRSPACE_SIZE)) {
|
||||||
|
// Inside the HCA space.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static bool set_lock(void)
|
||||||
|
{
|
||||||
|
int retries;
|
||||||
|
|
||||||
|
for (retries = 0; retries < 100; retries++) {
|
||||||
|
// Reading the lock value from g_gw_arm_nonsecure.lock.
|
||||||
|
u32 lock_dword = readl_relaxed(hca_va);
|
||||||
|
if (!(lock_dword & 0x80000000)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void release_lock(void)
|
||||||
|
{
|
||||||
|
// Reading the lock value from g_gw_arm_nonsecure.lock.
|
||||||
|
u32 lock_dword = readl_relaxed(hca_va);
|
||||||
|
lock_dword &= 0x7fffffff;
|
||||||
|
writel_relaxed(lock_dword, hca_va);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static bool set_busy(void)
|
||||||
|
{
|
||||||
|
int retries;
|
||||||
|
|
||||||
|
// Set busy bit.
|
||||||
|
u32 busy_dword = readl_relaxed(hca_va);
|
||||||
|
busy_dword |= 1UL << 30;
|
||||||
|
writel_relaxed(busy_dword, hca_va);
|
||||||
|
|
||||||
|
for (retries = 0; retries < 1000; retries++) {
|
||||||
|
// Reading the bust value from g_gw_arm_nonsecure.busy.
|
||||||
|
u32 busy = readl_relaxed(hca_va);
|
||||||
|
if (!(busy & 0x40000000)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static u32 crspace_read(int offset)
|
||||||
|
{
|
||||||
|
u32 data, new_offset;
|
||||||
|
|
||||||
|
if (!set_lock()) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the address to the GA: g_gw_arm_nonsecure.desc0.addr.
|
||||||
|
new_offset = offset >> 2; // HW expects addr[25:2] in that register.
|
||||||
|
writel_relaxed(new_offset, hca_va + 0x18);
|
||||||
|
|
||||||
|
// Set read operation.
|
||||||
|
writel_relaxed(1, hca_va + 0x0c);
|
||||||
|
|
||||||
|
if (!set_busy()) {
|
||||||
|
release_lock();
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reading the value of the desired address from
|
||||||
|
// gw_cr_64b.g_gw_arm_nonsecure.desc0.data_31_0 plus offset 0x14.
|
||||||
|
data = readl_relaxed(hca_va + 0x14);
|
||||||
|
|
||||||
|
release_lock();
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void crspace_write(u32 data, int offset)
|
||||||
|
{
|
||||||
|
u32 new_offset;
|
||||||
|
|
||||||
|
if (!set_lock()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the address to the GA: g_gw_arm_nonsecure.desc0.addr.
|
||||||
|
new_offset = offset >> 2; // HW expects addr[25:2] in that register.
|
||||||
|
writel_relaxed(new_offset, hca_va + 0x18);
|
||||||
|
|
||||||
|
// Writing the value of the desired address from
|
||||||
|
// gw_cr_64b.g_gw_arm_nonsecure.desc0.data_31_0 plus offset 0x14.
|
||||||
|
writel_relaxed(data, hca_va + 0x14);
|
||||||
|
|
||||||
|
// Set write operation.
|
||||||
|
writel_relaxed(0, hca_va + 0x0c);
|
||||||
|
|
||||||
|
if (!set_busy()) {
|
||||||
|
release_lock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
release_lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that you can seek to illegal areas within the livefish device,
|
||||||
|
* but you won't be able to read or write there.
|
||||||
|
*/
|
||||||
|
static loff_t livefish_llseek(struct file *filp, loff_t offset, int whence)
|
||||||
|
{
|
||||||
|
if (offset % 4 != 0) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fixed_size_llseek(filp, offset, whence, CRSPACE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static ssize_t livefish_read(struct file *filp, char __user *to,
|
||||||
|
size_t len, loff_t *ppos)
|
||||||
|
{
|
||||||
|
loff_t pos = *ppos;
|
||||||
|
size_t counter;
|
||||||
|
int word;
|
||||||
|
|
||||||
|
if (!valid_range(pos, len)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (counter = 0; counter < len; counter += 4, pos += 4) {
|
||||||
|
word = crspace_read(pos);
|
||||||
|
|
||||||
|
if (put_user(word, (int __user *)(to + counter)) != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppos = pos;
|
||||||
|
|
||||||
|
return counter ?: -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static ssize_t livefish_write(struct file *filp, const char __user *from,
|
||||||
|
size_t len, loff_t *ppos)
|
||||||
|
{
|
||||||
|
loff_t pos = *ppos;
|
||||||
|
size_t counter;
|
||||||
|
int word;
|
||||||
|
|
||||||
|
if (!valid_range(pos, len)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (counter = 0; counter < len; counter += 4, pos += 4) {
|
||||||
|
if (get_user(word, (int __user *)(from + counter)) != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
crspace_write(word, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppos = pos;
|
||||||
|
|
||||||
|
return counter ?: -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const struct file_operations livefish_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.llseek = livefish_llseek,
|
||||||
|
.read = livefish_read,
|
||||||
|
.write = livefish_write,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This name causes the correct semantics for the Mellanox MST tools. */
|
||||||
|
static struct miscdevice livefish_dev = {
|
||||||
|
.minor = MISC_DYNAMIC_MINOR,
|
||||||
|
.name = "bf3-livefish",
|
||||||
|
.mode = 0600,
|
||||||
|
.fops = &livefish_fops
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Release any VA or PA mappings that have been set up. */
|
||||||
|
static void livefish_cleanup_mappings(void)
|
||||||
|
{
|
||||||
|
if (hca_va) {
|
||||||
|
iounmap(hca_va);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int livefish_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev);
|
||||||
|
const char *hid = acpi_device_hid(acpi_dev);
|
||||||
|
struct resource *res;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
// Device ID validation.
|
||||||
|
if (strcmp(hid, "MLNXBF45") != 0) {
|
||||||
|
dev_err(&pdev->dev, "Invalid device ID %s\n", hid);
|
||||||
|
error = -ENODEV;
|
||||||
|
goto ReturnOnError;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find and map the HCA region.
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
if (res == NULL) {
|
||||||
|
error = -ENODEV;
|
||||||
|
goto ReturnOnError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request_mem_region(res->start, resource_size(res),
|
||||||
|
"LiveFish (HCA)") == NULL) {
|
||||||
|
error = -ENODEV;
|
||||||
|
goto ReturnOnError;
|
||||||
|
}
|
||||||
|
|
||||||
|
hca_va = ioremap(res->start, resource_size(res));
|
||||||
|
|
||||||
|
if (!hca_va) {
|
||||||
|
error = -EINVAL;
|
||||||
|
goto ReturnOnError;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(&pdev->dev, "HCA Region PA: 0x%llx Size: 0x%llx\n",
|
||||||
|
res->start, resource_size(res));
|
||||||
|
|
||||||
|
error = misc_register(&livefish_dev);
|
||||||
|
if (error) {
|
||||||
|
goto ReturnOnError;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(&pdev->dev, "probed\n");
|
||||||
|
|
||||||
|
return error;
|
||||||
|
|
||||||
|
ReturnOnError:
|
||||||
|
livefish_cleanup_mappings();
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int livefish_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
misc_deregister(&livefish_dev);
|
||||||
|
livefish_cleanup_mappings();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id livefish_of_match[] = {
|
||||||
|
{ .compatible = "mellanox,mlxbf-livefish" },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(of, livefish_of_match);
|
||||||
|
|
||||||
|
static const struct acpi_device_id livefish_acpi_match[] = {
|
||||||
|
{ "MLNXBF45", 0 },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(acpi, livefish_acpi_match);
|
||||||
|
|
||||||
|
static struct platform_driver livefish_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "mlxbf-livefish",
|
||||||
|
.of_match_table = livefish_of_match,
|
||||||
|
.acpi_match_table = ACPI_PTR(livefish_acpi_match),
|
||||||
|
},
|
||||||
|
.probe = livefish_probe,
|
||||||
|
.remove = livefish_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module_platform_driver(livefish_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("Dual BSD/GPL");
|
||||||
|
MODULE_DESCRIPTION("BlueField 3 LiveFish driver");
|
||||||
|
MODULE_AUTHOR("Itay Avraham <itayavr@nvidia.com>");
|
||||||
|
MODULE_VERSION(STRINGIFY(DRIVER_VERSION));
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef BF3_LIVEFISH_H
|
||||||
|
#define BF3_LIVEFISH_H
|
||||||
|
|
||||||
|
|
||||||
|
#define DRIVER_VERSION 1.0
|
||||||
|
#define STRINGIFY(s) #s
|
||||||
|
#define CRSPACE_SIZE (2 * 1024 * 1024)
|
||||||
|
|
||||||
|
#endif // BF3_LIVEFISH_H
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
KPVER ?= $(shell uname -r)
|
||||||
|
KSRC ?= /lib/modules/$(KPVER)/build
|
||||||
|
|
||||||
|
# Oracle Linux OS.
|
||||||
|
ifneq ($(shell if (echo $(KPVER) | grep -qE 'uek'); then \
|
||||||
|
echo "YES"; else echo ""; fi),)
|
||||||
|
override WITH_MAKE_PARAMS += ctf-dir=$(CWD)/.ctf
|
||||||
|
endif
|
||||||
|
|
||||||
|
NNT_DRIVER_LOCATION = ../../nnt_driver
|
||||||
|
PACKAGE_NAME = nnt-driver
|
||||||
|
PACKAGE_VERSION = 1.0.0
|
||||||
|
PACKAGE_RC = 1
|
||||||
|
|
||||||
|
%: %.in
|
||||||
|
sed \
|
||||||
|
-e 's/@PACKAGE_NAME@/$(PACKAGE_NAME)/g' \
|
||||||
|
-e 's/@PACKAGE_VERSION@/$(PACKAGE_VERSION)/g' \
|
||||||
|
-e 's/@PACKAGE_RC@/$(PACKAGE_RC)/g' \
|
||||||
|
<$< >$@
|
||||||
|
|
||||||
|
obj-m += mst_pci.o
|
||||||
|
EXTRA_CFLAGS= -I$(PWD)/$(NNT_DRIVER_LOCATION)
|
||||||
|
mst_pci-objs += $(NNT_DRIVER_LOCATION)/nnt_device.o $(NNT_DRIVER_LOCATION)/nnt_dma.o $(NNT_DRIVER_LOCATION)/nnt_pci_conf_access.o \
|
||||||
|
$(NNT_DRIVER_LOCATION)/nnt_pci_conf_access_no_vsec.o $(NNT_DRIVER_LOCATION)/nnt_memory_access.o \
|
||||||
|
$(NNT_DRIVER_LOCATION)/nnt_ioctl.o mst_pci_bc.o
|
||||||
|
|
||||||
|
all:
|
||||||
|
make -C $(KSRC) M=$(PWD) CONFIG_CTF= CONFIG_CC_STACKPROTECTOR_STRONG= $(WITH_MAKE_PARAMS) modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C $(KSRC) M=$(PWD) clean
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
mst_pciconf.ko external
|
||||||
|
mst_pci.ko external
|
||||||
|
mst_ppc_pci_reset.ko external
|
||||||
@@ -0,0 +1,436 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/semaphore.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include "nnt_ioctl.h"
|
||||||
|
#include "nnt_defs.h"
|
||||||
|
#include "nnt_device.h"
|
||||||
|
#include "nnt_ioctl_defs.h"
|
||||||
|
#include "nnt_pci_conf_access.h"
|
||||||
|
#include "mst_pci_bc.h"
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Itay Avraham <itayavr@nvidia.com>");
|
||||||
|
MODULE_DESCRIPTION("NNT Linux driver (NVIDIA® networking tools driver), this is the backward compatibility driver");
|
||||||
|
MODULE_LICENSE("Dual BSD/GPL");
|
||||||
|
|
||||||
|
struct driver_info nnt_driver_info;
|
||||||
|
static int major_number = -1;
|
||||||
|
static char* name = "mst_pci";
|
||||||
|
|
||||||
|
#define INIT PCI_INIT
|
||||||
|
#define STOP PCI_STOP
|
||||||
|
#define PCI_PARAMS_ PCI_PARAMS
|
||||||
|
#define CONNECTX_WA PCI_CONNECTX_WA
|
||||||
|
|
||||||
|
struct mst_device_data
|
||||||
|
{
|
||||||
|
char buffer[MST_BC_BUFFER_SIZE];
|
||||||
|
int buffer_used;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct mst_device_data mst_devices[MST_BC_MAX_MINOR];
|
||||||
|
|
||||||
|
static int mst_pci_bc_open(struct inode* inode, struct file* file)
|
||||||
|
{
|
||||||
|
if (file->private_data)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_private_data_open(file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t mst_pci_bc_read(struct file* file, char* buf, size_t count, loff_t* f_pos)
|
||||||
|
{
|
||||||
|
struct mst_device_data* mst_device = NULL;
|
||||||
|
struct nnt_device* nnt_device = NULL;
|
||||||
|
int* buffer_used = NULL;
|
||||||
|
char* buffer = NULL;
|
||||||
|
int minor = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Get the nnt device structure */
|
||||||
|
error = get_nnt_device(file, &nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
minor = iminor(file_inode(file));
|
||||||
|
mst_device = &mst_devices[minor];
|
||||||
|
buffer = mst_device->buffer;
|
||||||
|
buffer_used = &mst_device->buffer_used;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer = nnt_device->buffer_bc;
|
||||||
|
buffer_used = &nnt_device->buffer_used_bc;
|
||||||
|
error = mutex_lock_nnt(file);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*f_pos >= *buffer_used)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
goto MutexUnlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*f_pos + count > *buffer_used)
|
||||||
|
{
|
||||||
|
count = *buffer_used - *f_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_to_user(buf, buffer + *f_pos, count))
|
||||||
|
{
|
||||||
|
count = -EFAULT;
|
||||||
|
goto MutexUnlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
*f_pos += count;
|
||||||
|
|
||||||
|
MutexUnlock:
|
||||||
|
if (nnt_device)
|
||||||
|
{
|
||||||
|
mutex_unlock_nnt(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t mst_pci_bc_write(struct file* file, const char* buf, size_t count, loff_t* f_pos)
|
||||||
|
{
|
||||||
|
struct mst_device_data* mst_device = NULL;
|
||||||
|
struct nnt_device* nnt_device = NULL;
|
||||||
|
int* buffer_used = NULL;
|
||||||
|
char* buffer = NULL;
|
||||||
|
int minor = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Get the nnt device structure */
|
||||||
|
error = get_nnt_device(file, &nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
minor = iminor(file_inode(file));
|
||||||
|
mst_device = &mst_devices[minor];
|
||||||
|
buffer = mst_device->buffer;
|
||||||
|
buffer_used = &mst_device->buffer_used;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer = nnt_device->buffer_bc;
|
||||||
|
buffer_used = &nnt_device->buffer_used_bc;
|
||||||
|
error = mutex_lock_nnt(file);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*f_pos >= MST_BC_BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
goto MutexUnlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*f_pos + count > MST_BC_BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
count = MST_BC_BUFFER_SIZE - *f_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_from_user(buffer + *f_pos, buf, count))
|
||||||
|
{
|
||||||
|
count = -EFAULT;
|
||||||
|
goto MutexUnlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
*f_pos += count;
|
||||||
|
|
||||||
|
if (*buffer_used < *f_pos)
|
||||||
|
{
|
||||||
|
*buffer_used = *f_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
MutexUnlock:
|
||||||
|
if (nnt_device)
|
||||||
|
{
|
||||||
|
mutex_unlock_nnt(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int noncached_address(unsigned long addr)
|
||||||
|
{
|
||||||
|
return addr >= __pa(high_memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mst_pci_mmap(struct file* file, struct vm_area_struct* vma)
|
||||||
|
{
|
||||||
|
struct nnt_device* nnt_device = NULL;
|
||||||
|
unsigned long long offset = 0;
|
||||||
|
unsigned long vsize = 0;
|
||||||
|
unsigned long off = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Get the nnt device structure */
|
||||||
|
error = get_nnt_device(file, &nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
off = vma->vm_pgoff << PAGE_SHIFT;
|
||||||
|
vsize = vma->vm_end - vma->vm_start;
|
||||||
|
|
||||||
|
if ((nnt_device->device_pci.bar_size <= off) || (nnt_device->device_pci.bar_size < off + vsize))
|
||||||
|
{
|
||||||
|
error = -EINVAL;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = nnt_device->device_pci.bar_address + off;
|
||||||
|
|
||||||
|
/* Accessing memory above the top the kernel knows about or through
|
||||||
|
a file pointer that was marked O_SYNC will be done non-cached. */
|
||||||
|
if (noncached_address(offset) || (file->f_flags & O_SYNC))
|
||||||
|
{
|
||||||
|
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = io_remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT, vsize, vma->vm_page_prot);
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long ioctl(struct file* file, unsigned int command, unsigned long argument)
|
||||||
|
{
|
||||||
|
void* user_buffer = (void*)argument;
|
||||||
|
struct nnt_device* nnt_device = NULL;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* By convention, any user gets read access
|
||||||
|
* and is allowed to use the device.
|
||||||
|
* Commands with no direction are administration
|
||||||
|
* commands, and you need write permission
|
||||||
|
* for this */
|
||||||
|
|
||||||
|
if (_IOC_DIR(command) == _IOC_NONE)
|
||||||
|
{
|
||||||
|
if (!(file->f_mode & FMODE_WRITE))
|
||||||
|
{
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(file->f_mode & FMODE_READ))
|
||||||
|
{
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command != INIT)
|
||||||
|
{
|
||||||
|
error = mutex_lock_nnt(file);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Get the nnt device structure */
|
||||||
|
error = get_nnt_device(file, &nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
error = 0;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case INIT:
|
||||||
|
{
|
||||||
|
struct mst_pci_init_st mst_init;
|
||||||
|
struct pci_bus* bus = NULL;
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&mst_init, user_buffer, sizeof(struct mst_pci_init_st)))
|
||||||
|
{
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = set_private_data_bc(file, mst_init.bus, mst_init.devfn, mst_init.domain);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = mutex_lock_nnt(file);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Get the nnt device structure */
|
||||||
|
error = get_nnt_device(file, &nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
bus = pci_find_bus(mst_init.domain, mst_init.bus);
|
||||||
|
|
||||||
|
if (!bus)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "unable to find pci bus for domain: %x and bus: %x\n", mst_init.domain, mst_init.bus);
|
||||||
|
error = -ENXIO;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
nnt_device->pci_device = NULL;
|
||||||
|
nnt_device->pci_device = pci_get_slot(bus, mst_init.devfn);
|
||||||
|
|
||||||
|
if (!nnt_device->pci_device)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "missing pci device");
|
||||||
|
error = -ENXIO;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mst_init.bar >= DEVICE_COUNT_RESOURCE)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "bar offset is too large");
|
||||||
|
error = -ENXIO;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
nnt_device->device_pci.bar_address = nnt_device->pci_device->resource[mst_init.bar].start;
|
||||||
|
nnt_device->device_pci.bar_size = nnt_device->pci_device->resource[mst_init.bar].end + 1 -
|
||||||
|
nnt_device->pci_device->resource[mst_init.bar].start;
|
||||||
|
|
||||||
|
if (nnt_device->device_pci.bar_size == 1)
|
||||||
|
{
|
||||||
|
nnt_device->device_pci.bar_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nnt_device->buffer_used_bc = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PCI_PARAMS_:
|
||||||
|
{
|
||||||
|
struct mst_pci_params_st params;
|
||||||
|
params.bar = nnt_device->device_pci.bar_address;
|
||||||
|
params.size = nnt_device->device_pci.bar_size;
|
||||||
|
|
||||||
|
if (copy_to_user(user_buffer, ¶ms, sizeof(struct mst_pci_params_st)))
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CONNECTX_WA:
|
||||||
|
{
|
||||||
|
struct nnt_connectx_wa connectx_wa;
|
||||||
|
error = pci_connectx_wa(&connectx_wa, nnt_device);
|
||||||
|
|
||||||
|
/* Copy the data to the user space. */
|
||||||
|
if (copy_to_user(user_buffer, &connectx_wa, sizeof(struct nnt_connectx_wa)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STOP:
|
||||||
|
error = destroy_nnt_device_bc(nnt_device);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
mutex_unlock_nnt(file);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mst_release(struct inode* inode, struct file* file)
|
||||||
|
{
|
||||||
|
struct nnt_device* nnt_device = NULL;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Get the nnt device structure */
|
||||||
|
error = get_nnt_device(file, &nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
error = 0;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nnt_device->memory_device.connectx_wa_slot_p1)
|
||||||
|
{
|
||||||
|
unsigned int mask = 0;
|
||||||
|
|
||||||
|
error = mutex_lock_nnt(file);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
mask = ~(1 << (nnt_device->memory_device.connectx_wa_slot_p1 - 1));
|
||||||
|
|
||||||
|
nnt_device->memory_device.connectx_wa_slot_p1 &= mask; // Fix me
|
||||||
|
|
||||||
|
nnt_device->memory_device.connectx_wa_slot_p1 = 0;
|
||||||
|
mutex_unlock_nnt(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file_operations fop = {.unlocked_ioctl = ioctl,
|
||||||
|
.open = mst_pci_bc_open,
|
||||||
|
.write = mst_pci_bc_write,
|
||||||
|
.read = mst_pci_bc_read,
|
||||||
|
.mmap = mst_pci_mmap,
|
||||||
|
.release = mst_release,
|
||||||
|
.owner = THIS_MODULE};
|
||||||
|
|
||||||
|
int with_unknown = 0;
|
||||||
|
|
||||||
|
module_param(with_unknown, int, S_IRUSR | S_IWUSR);
|
||||||
|
|
||||||
|
static int __init mst_pci_init_module(void)
|
||||||
|
{
|
||||||
|
dev_t device_number = -1;
|
||||||
|
int is_alloc_chrdev_region = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Allocate char driver region and assign major number */
|
||||||
|
major_number = register_chrdev(0, name, &fop);
|
||||||
|
if (major_number <= 0)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "Unable to register character mst pci driver.\n");
|
||||||
|
error = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create device files for MFT. */
|
||||||
|
error = create_nnt_devices(device_number, is_alloc_chrdev_region, &fop, NNT_PCI_DEVICES, NNT_MELLANOX_PCI_VENDOR,
|
||||||
|
with_unknown) ||
|
||||||
|
create_nnt_devices(device_number, is_alloc_chrdev_region, &fop, NNT_PCI_DEVICES, NNT_NVIDIA_PCI_VENDOR,
|
||||||
|
with_unknown);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit mst_pci_cleanup_module(void)
|
||||||
|
{
|
||||||
|
int is_alloc_chrdev_region = 0;
|
||||||
|
|
||||||
|
destroy_nnt_devices(is_alloc_chrdev_region);
|
||||||
|
unregister_chrdev(major_number, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(mst_pci_init_module);
|
||||||
|
module_exit(mst_pci_cleanup_module);
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef MST_PCI_H
|
||||||
|
#define MST_PCI_H
|
||||||
|
|
||||||
|
/* These will be specific for PCI */
|
||||||
|
#define PCI_MAGIC 0xD1
|
||||||
|
|
||||||
|
#define PCI_INIT _IOC(_IOC_NONE,PCI_MAGIC,0,sizeof(struct mst_pci_init_st))
|
||||||
|
struct mst_pci_init_st {
|
||||||
|
unsigned int domain;
|
||||||
|
unsigned int bus;
|
||||||
|
unsigned int devfn;
|
||||||
|
int bar;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PCI_STOP _IOC(_IOC_NONE,PCI_MAGIC,1,0)
|
||||||
|
|
||||||
|
#define PCI_PARAMS _IOR(PCI_MAGIC,2, struct mst_pci_params_st)
|
||||||
|
|
||||||
|
struct mst_pci_params_st {
|
||||||
|
unsigned long long __attribute__((packed)) bar;
|
||||||
|
unsigned long long __attribute__((packed)) size;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define CONNECTX_WA_BASE 0xf0384 // SEM BASE ADDR. SEM 0xf0380 is reserved for external tools usage.
|
||||||
|
#define CONNECTX_WA_SIZE 3 // Size in entries
|
||||||
|
|
||||||
|
#define PCI_CONNECTX_WA _IOR(PCI_MAGIC,3, u_int32_t)
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
KPVER ?= $(shell uname -r)
|
||||||
|
KSRC ?= /lib/modules/$(KPVER)/build
|
||||||
|
|
||||||
|
# Oracle Linux OS.
|
||||||
|
ifneq ($(shell if (echo $(KPVER) | grep -qE 'uek'); then \
|
||||||
|
echo "YES"; else echo ""; fi),)
|
||||||
|
override WITH_MAKE_PARAMS += ctf-dir=$(CWD)/.ctf
|
||||||
|
endif
|
||||||
|
|
||||||
|
NNT_DRIVER_LOCATION = ../../nnt_driver
|
||||||
|
PACKAGE_NAME = nnt-driver
|
||||||
|
PACKAGE_VERSION = 1.0.0
|
||||||
|
PACKAGE_RC = 1
|
||||||
|
|
||||||
|
%: %.in
|
||||||
|
sed \
|
||||||
|
-e 's/@PACKAGE_NAME@/$(PACKAGE_NAME)/g' \
|
||||||
|
-e 's/@PACKAGE_VERSION@/$(PACKAGE_VERSION)/g' \
|
||||||
|
-e 's/@PACKAGE_RC@/$(PACKAGE_RC)/g' \
|
||||||
|
<$< >$@
|
||||||
|
|
||||||
|
obj-m += mst_pciconf.o
|
||||||
|
EXTRA_CFLAGS= -I$(PWD)/$(NNT_DRIVER_LOCATION)
|
||||||
|
mst_pciconf-objs += $(NNT_DRIVER_LOCATION)/nnt_device.o $(NNT_DRIVER_LOCATION)/nnt_dma.o $(NNT_DRIVER_LOCATION)/nnt_pci_conf_access.o \
|
||||||
|
$(NNT_DRIVER_LOCATION)/nnt_pci_conf_access_no_vsec.o $(NNT_DRIVER_LOCATION)/nnt_memory_access.o \
|
||||||
|
$(NNT_DRIVER_LOCATION)/nnt_ioctl.o mst_pciconf_bc.o
|
||||||
|
|
||||||
|
all:
|
||||||
|
make -C $(KSRC) M=$(PWD) CONFIG_CTF= CONFIG_CC_STACKPROTECTOR_STRONG= $(WITH_MAKE_PARAMS) modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C $(KSRC) M=$(PWD) clean
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
mst_pciconf.ko external
|
||||||
|
mst_pci.ko external
|
||||||
|
mst_ppc_pci_reset.ko external
|
||||||
@@ -0,0 +1,635 @@
|
|||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/semaphore.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include "nnt_ioctl.h"
|
||||||
|
#include "nnt_defs.h"
|
||||||
|
#include "nnt_device.h"
|
||||||
|
#include "nnt_ioctl_defs.h"
|
||||||
|
#include "nnt_pci_conf_access.h"
|
||||||
|
#include "mst_pciconf_bc.h"
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Itay Avraham <itayavr@nvidia.com>");
|
||||||
|
MODULE_DESCRIPTION("NNT Linux driver (NVIDIA® networking tools driver), this is the backward compatibility driver");
|
||||||
|
MODULE_LICENSE("Dual BSD/GPL");
|
||||||
|
|
||||||
|
struct driver_info nnt_driver_info;
|
||||||
|
static int major_number = -1;
|
||||||
|
static char* name = "mst_pciconf";
|
||||||
|
|
||||||
|
#define INIT PCICONF_INIT
|
||||||
|
#define STOP PCICONF_STOP
|
||||||
|
#define READ4 PCICONF_READ4
|
||||||
|
#define READ4_NEW PCICONF_READ4_NEW
|
||||||
|
#define WRITE4 PCICONF_WRITE4
|
||||||
|
#define WRITE4_NEW PCICONF_WRITE4_NEW
|
||||||
|
#define MODIFY PCICONF_MODIFY
|
||||||
|
#define READ4_BUFFER PCICONF_READ4_BUFFER
|
||||||
|
#define READ4_BUFFER_EX PCICONF_READ4_BUFFER_EX
|
||||||
|
#define WRITE4_BUFFER PCICONF_WRITE4_BUFFER
|
||||||
|
#define MST_PARAMS PCICONF_MST_PARAMS
|
||||||
|
#define MST_META_DATA PCICONF_MST_META_DATA
|
||||||
|
#define GET_DMA_PAGES PCICONF_GET_DMA_PAGES
|
||||||
|
#define RELEASE_DMA_PAGES PCICONF_RELEASE_DMA_PAGES
|
||||||
|
#define READ_DWORD_FROM_CONFIG_SPACE PCICONF_READ_DWORD_FROM_CONFIG_SPACE
|
||||||
|
|
||||||
|
static int mst_pciconf_bc_open(struct inode* inode, struct file* file)
|
||||||
|
{
|
||||||
|
if (file->private_data)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_private_data_open(file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t mst_pciconf_bc_read(struct file* file, char* buf, size_t count, loff_t* f_pos)
|
||||||
|
{
|
||||||
|
struct nnt_device* nnt_device = NULL;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Get the nnt device structure */
|
||||||
|
error = get_nnt_device(file, &nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
count = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = mutex_lock_nnt(file);
|
||||||
|
|
||||||
|
if (*f_pos >= nnt_device->buffer_used_bc)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
goto MutexUnlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*f_pos + count > nnt_device->buffer_used_bc)
|
||||||
|
{
|
||||||
|
count = nnt_device->buffer_used_bc - *f_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_to_user(buf, nnt_device->buffer_bc + *f_pos, count))
|
||||||
|
{
|
||||||
|
count = -EFAULT;
|
||||||
|
goto MutexUnlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
*f_pos += count;
|
||||||
|
|
||||||
|
MutexUnlock:
|
||||||
|
mutex_unlock_nnt(file);
|
||||||
|
ReturnOnFinished:
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t mst_pciconf_bc_write(struct file* file, const char* buf, size_t count, loff_t* f_pos)
|
||||||
|
{
|
||||||
|
struct nnt_device* nnt_device = NULL;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Get the nnt device structure */
|
||||||
|
error = get_nnt_device(file, &nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
count = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = mutex_lock_nnt(file);
|
||||||
|
|
||||||
|
if (*f_pos >= MST_BC_BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
goto MutexUnlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*f_pos + count > MST_BC_BUFFER_SIZE)
|
||||||
|
{
|
||||||
|
count = MST_BC_BUFFER_SIZE - *f_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy_from_user(nnt_device->buffer_bc + *f_pos, buf, count))
|
||||||
|
{
|
||||||
|
count = -EFAULT;
|
||||||
|
goto MutexUnlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
*f_pos += count;
|
||||||
|
|
||||||
|
if (nnt_device->buffer_used_bc < *f_pos)
|
||||||
|
{
|
||||||
|
nnt_device->buffer_used_bc = *f_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
MutexUnlock:
|
||||||
|
mutex_unlock_nnt(file);
|
||||||
|
ReturnOnFinished:
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long ioctl(struct file* file, unsigned int command, unsigned long argument)
|
||||||
|
{
|
||||||
|
void* user_buffer = (void*)argument;
|
||||||
|
struct nnt_device* nnt_device = NULL;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* By convention, any user gets read access
|
||||||
|
* and is allowed to use the device.
|
||||||
|
* Commands with no direction are administration
|
||||||
|
* commands, and you need write permission
|
||||||
|
* for this */
|
||||||
|
|
||||||
|
if (_IOC_DIR(command) == _IOC_NONE)
|
||||||
|
{
|
||||||
|
if (!(file->f_mode & FMODE_WRITE))
|
||||||
|
{
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(file->f_mode & FMODE_READ))
|
||||||
|
{
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command != INIT)
|
||||||
|
{
|
||||||
|
error = mutex_lock_nnt(file);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Get the nnt device structure */
|
||||||
|
error = get_nnt_device(file, &nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case INIT:
|
||||||
|
{
|
||||||
|
struct nnt_pciconf_init nnt_init;
|
||||||
|
struct mst_pciconf_init_st mst_init;
|
||||||
|
struct nnt_device* nnt_device = NULL;
|
||||||
|
|
||||||
|
if (copy_from_user(&mst_init, user_buffer, sizeof(struct mst_pciconf_init_st)))
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = set_private_data_bc(file, mst_init.bus, mst_init.devfn, mst_init.domain);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = mutex_lock_nnt(file);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Get the nnt device structure */
|
||||||
|
error = get_nnt_device(file, &nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
nnt_init.address_register = mst_init.addr_reg;
|
||||||
|
nnt_init.address_data_register = mst_init.data_reg;
|
||||||
|
|
||||||
|
/* Truncate to 0 length on open for writing. */
|
||||||
|
if (file->f_flags & O_APPEND)
|
||||||
|
{
|
||||||
|
file->f_pos = nnt_device->buffer_used_bc;
|
||||||
|
}
|
||||||
|
else if ((file->f_flags & O_TRUNC) || (file->f_flags & O_WRONLY))
|
||||||
|
{
|
||||||
|
nnt_device->buffer_used_bc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = nnt_device->access.init(nnt_device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WRITE4:
|
||||||
|
{
|
||||||
|
struct nnt_rw_operation rw_operation;
|
||||||
|
struct mst_write4_st mst_write;
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&mst_write, user_buffer, sizeof(struct mst_write4_st)))
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
rw_operation.data[0] = mst_write.data;
|
||||||
|
rw_operation.offset = mst_write.offset;
|
||||||
|
rw_operation.size = 4;
|
||||||
|
|
||||||
|
error = nnt_device->access.write(nnt_device, &rw_operation);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WRITE4_NEW:
|
||||||
|
{
|
||||||
|
struct nnt_rw_operation rw_operation;
|
||||||
|
struct mst_write4_new_st mst_write;
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&mst_write, user_buffer, sizeof(struct mst_write4_new_st)))
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
rw_operation.data[0] = mst_write.data;
|
||||||
|
rw_operation.offset = mst_write.offset;
|
||||||
|
rw_operation.address_space = mst_write.address_space;
|
||||||
|
rw_operation.size = 4;
|
||||||
|
|
||||||
|
error = nnt_device->access.write(nnt_device, &rw_operation);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WRITE4_BUFFER:
|
||||||
|
{
|
||||||
|
struct mst_write4_buffer_st mst_write;
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&mst_write, user_buffer, sizeof(struct mst_write4_buffer_st)))
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = nnt_device->access.write(nnt_device, (struct nnt_rw_operation*)&mst_write);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No error, return the requested data length. */
|
||||||
|
error = mst_write.size;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case READ4:
|
||||||
|
{
|
||||||
|
struct nnt_rw_operation rw_operation;
|
||||||
|
struct mst_read4_st mst_read;
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&mst_read, user_buffer, sizeof(struct mst_read4_st)))
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
rw_operation.offset = mst_read.offset;
|
||||||
|
rw_operation.size = 4;
|
||||||
|
|
||||||
|
error = nnt_device->access.read(nnt_device, &rw_operation);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
mst_read.data = rw_operation.data[0];
|
||||||
|
|
||||||
|
/* Copy the data to the user space. */
|
||||||
|
if (copy_to_user(user_buffer, &mst_read, sizeof(struct mst_read4_st)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case READ4_NEW:
|
||||||
|
{
|
||||||
|
struct nnt_rw_operation rw_operation;
|
||||||
|
struct mst_read4_new_st mst_read;
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&mst_read, user_buffer, sizeof(struct mst_read4_new_st)))
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
rw_operation.offset = mst_read.offset;
|
||||||
|
rw_operation.address_space = mst_read.address_space;
|
||||||
|
rw_operation.size = 4;
|
||||||
|
error = nnt_device->access.read(nnt_device, &rw_operation);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
mst_read.data = rw_operation.data[0];
|
||||||
|
|
||||||
|
/* Copy the data to the user space. */
|
||||||
|
if (copy_to_user(user_buffer, &mst_read, sizeof(struct mst_read4_new_st)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case READ4_BUFFER_EX:
|
||||||
|
case READ4_BUFFER:
|
||||||
|
{
|
||||||
|
struct mst_read4_buffer_st mst_read;
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&mst_read, user_buffer, sizeof(struct mst_read4_buffer_st)))
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = nnt_device->access.read(nnt_device, (struct nnt_rw_operation*)&mst_read);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the data to the user space. */
|
||||||
|
if (copy_to_user(user_buffer, &mst_read, sizeof(struct mst_read4_buffer_st)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No error, return the requested data length. */
|
||||||
|
error = mst_read.size;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PCICONF_VPD_READ4:
|
||||||
|
{
|
||||||
|
int vpd_default_timeout = 2000;
|
||||||
|
struct mst_vpd_read4_st mst_vpd_read;
|
||||||
|
struct nnt_vpd nnt_vpd;
|
||||||
|
|
||||||
|
if (!nnt_device->vpd_capability_address)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "Device %s not support Vital Product Data\n", nnt_device->device_name);
|
||||||
|
error = -ENODEV;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&mst_vpd_read, user_buffer, sizeof(struct mst_vpd_read4_st)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
nnt_vpd.offset = mst_vpd_read.offset;
|
||||||
|
nnt_vpd.data = mst_vpd_read.data;
|
||||||
|
|
||||||
|
if (!nnt_vpd.timeout)
|
||||||
|
{
|
||||||
|
nnt_vpd.timeout = vpd_default_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = vpd_read(&nnt_vpd, nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
mst_vpd_read.offset = nnt_vpd.offset;
|
||||||
|
mst_vpd_read.data = nnt_vpd.data;
|
||||||
|
|
||||||
|
/* Copy the data to the user space. */
|
||||||
|
if (copy_to_user(user_buffer, &mst_vpd_read, sizeof(struct mst_vpd_read4_st)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PCICONF_VPD_WRITE4:
|
||||||
|
{
|
||||||
|
int vpd_default_timeout = 2000;
|
||||||
|
struct mst_vpd_write4_st mst_vpd_write;
|
||||||
|
struct nnt_vpd nnt_vpd;
|
||||||
|
|
||||||
|
if (!nnt_device->vpd_capability_address)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "Device %s not support Vital Product Data\n", nnt_device->device_name);
|
||||||
|
error = -ENODEV;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&mst_vpd_write, user_buffer, sizeof(struct mst_vpd_write4_st)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
nnt_vpd.offset = mst_vpd_write.offset;
|
||||||
|
nnt_vpd.data = mst_vpd_write.data;
|
||||||
|
|
||||||
|
if (!nnt_vpd.timeout)
|
||||||
|
{
|
||||||
|
nnt_vpd.timeout = vpd_default_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = vpd_write(&nnt_vpd, nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
mst_vpd_write.offset = nnt_vpd.offset;
|
||||||
|
mst_vpd_write.data = nnt_vpd.data;
|
||||||
|
|
||||||
|
/* Copy the data to the user space. */
|
||||||
|
if (copy_to_user(user_buffer, &mst_vpd_write, sizeof(struct mst_vpd_write4_st)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case GET_DMA_PAGES:
|
||||||
|
{
|
||||||
|
error = dma_pages_ioctl(NNT_GET_DMA_PAGES, user_buffer, nnt_device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RELEASE_DMA_PAGES:
|
||||||
|
{
|
||||||
|
error = dma_pages_ioctl(NNT_RELEASE_DMA_PAGES, user_buffer, nnt_device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case READ_DWORD_FROM_CONFIG_SPACE:
|
||||||
|
{
|
||||||
|
struct nnt_read_dword_from_config_space nnt_read_from_cspace = {0};
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&nnt_read_from_cspace, user_buffer, sizeof(struct nnt_read_dword_from_config_space)))
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the dword. */
|
||||||
|
if (read_dword(&nnt_read_from_cspace, nnt_device))
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the data to the user space. */
|
||||||
|
if (copy_to_user(user_buffer, &nnt_read_from_cspace, sizeof(struct nnt_read_dword_from_config_space)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MST_META_DATA:
|
||||||
|
{
|
||||||
|
struct mst_meta_data meta_data;
|
||||||
|
struct mst_hdr hdr;
|
||||||
|
memset(&meta_data, 0, sizeof(meta_data));
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&hdr, user_buffer, sizeof(struct mst_hdr)))
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hdr.payload_version_major != MST_META_DATA_VERSION_MAJOR || hdr.payload_len < sizeof(meta_data.data))
|
||||||
|
{
|
||||||
|
error = -EINVAL;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
// fill meta_data hdr
|
||||||
|
meta_data.hdr.hdr_version = MST_HDR_VERSION;
|
||||||
|
meta_data.hdr.hdr_len = sizeof(meta_data.hdr);
|
||||||
|
meta_data.hdr.payload_len = sizeof(meta_data.data);
|
||||||
|
meta_data.hdr.payload_version_major = MST_META_DATA_VERSION_MAJOR;
|
||||||
|
meta_data.hdr.payload_version_minor = MST_META_DATA_VERSION_MINOR;
|
||||||
|
// fill payload
|
||||||
|
meta_data.data.api_version_major = MST_API_VERSION_MAJOR;
|
||||||
|
meta_data.data.api_version_minor = MST_API_VERSION_MINOR;
|
||||||
|
|
||||||
|
/* Copy the data to the user space. */
|
||||||
|
if (copy_to_user(user_buffer, &meta_data, sizeof(meta_data)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MST_PARAMS:
|
||||||
|
{
|
||||||
|
struct nnt_device_parameters nnt_parameters;
|
||||||
|
struct mst_params_st mst_params;
|
||||||
|
|
||||||
|
error = get_nnt_device_parameters(&nnt_parameters, nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
mst_params.bus = nnt_parameters.bus;
|
||||||
|
mst_params.bar = 0;
|
||||||
|
mst_params.domain = nnt_parameters.domain;
|
||||||
|
mst_params.func = nnt_parameters.function;
|
||||||
|
mst_params.slot = nnt_parameters.slot;
|
||||||
|
mst_params.device = nnt_parameters.device;
|
||||||
|
mst_params.vendor = nnt_parameters.vendor;
|
||||||
|
mst_params.subsystem_device = nnt_parameters.subsystem_device;
|
||||||
|
mst_params.subsystem_vendor = nnt_parameters.subsystem_vendor;
|
||||||
|
mst_params.vendor_specific_cap = nnt_parameters.vendor_specific_capability;
|
||||||
|
mst_params.multifunction = nnt_parameters.multifunction;
|
||||||
|
mst_params.vsec_cap_mask = nnt_parameters.vsec_capability_mask;
|
||||||
|
|
||||||
|
/* Copy the data to the user space. */
|
||||||
|
if (copy_to_user(user_buffer, &mst_params, sizeof(struct mst_params_st)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STOP:
|
||||||
|
{
|
||||||
|
error = destroy_nnt_device_bc(nnt_device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PCICONF_DMA_PROPS:
|
||||||
|
case PCICONF_MEM_ACCESS:
|
||||||
|
case MODIFY:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
mutex_unlock_nnt(file);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file_operations fop = {.unlocked_ioctl = ioctl,
|
||||||
|
.open = mst_pciconf_bc_open,
|
||||||
|
.write = mst_pciconf_bc_write,
|
||||||
|
.read = mst_pciconf_bc_read,
|
||||||
|
.owner = THIS_MODULE};
|
||||||
|
|
||||||
|
int with_unknown = 0;
|
||||||
|
|
||||||
|
module_param(with_unknown, int, S_IRUSR | S_IWUSR);
|
||||||
|
|
||||||
|
static int __init mst_pciconf_init_module(void)
|
||||||
|
{
|
||||||
|
dev_t device_number = -1;
|
||||||
|
int is_alloc_chrdev_region = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Allocate char driver region and assign major number */
|
||||||
|
major_number = register_chrdev(0, name, &fop);
|
||||||
|
if (major_number <= 0)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "Unable to register character mst pciconf driver.\n");
|
||||||
|
error = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create device files for MFT. */
|
||||||
|
error = create_nnt_devices(device_number, is_alloc_chrdev_region, &fop, NNT_PCICONF_DEVICES,
|
||||||
|
NNT_MELLANOX_PCI_VENDOR, with_unknown) ||
|
||||||
|
create_nnt_devices(device_number, is_alloc_chrdev_region, &fop, NNT_PCI_DEVICES, NNT_NVIDIA_PCI_VENDOR,
|
||||||
|
with_unknown);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit mst_pciconf_cleanup_module(void)
|
||||||
|
{
|
||||||
|
int is_alloc_chrdev_region = 0;
|
||||||
|
|
||||||
|
destroy_nnt_devices(is_alloc_chrdev_region);
|
||||||
|
unregister_chrdev(major_number, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(mst_pciconf_init_module);
|
||||||
|
module_exit(mst_pciconf_cleanup_module);
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
#ifndef MST_PCICONF_H
|
||||||
|
#define MST_PCICONF_H
|
||||||
|
|
||||||
|
|
||||||
|
/* These will be specific for PCI CONF*/
|
||||||
|
#define PCICONF_MAGIC 0xD2
|
||||||
|
#define PCICONF_MAX_BUFFER_SIZE 256
|
||||||
|
#define PCICONF_MAX_MEMACCESS_SIZE 1024
|
||||||
|
#define PCICONF_MAX_PAGES_SIZE 8
|
||||||
|
#define PCICONF_CAP_VEC_LEN 16
|
||||||
|
|
||||||
|
/* Versions */
|
||||||
|
#define MST_HDR_VERSION 1
|
||||||
|
#define MST_META_DATA_VERSION_MAJOR 1
|
||||||
|
#define MST_META_DATA_VERSION_MINOR 0
|
||||||
|
#define MST_API_VERSION_MAJOR 1
|
||||||
|
#define MST_API_VERSION_MINOR 0
|
||||||
|
|
||||||
|
/* Common Structs*/
|
||||||
|
struct mst_hdr {
|
||||||
|
unsigned short hdr_version;
|
||||||
|
unsigned short hdr_len;
|
||||||
|
unsigned short payload_version_major;
|
||||||
|
unsigned int payload_version_minor;
|
||||||
|
unsigned int payload_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define PCICONF_INIT _IOC(_IOC_NONE,PCICONF_MAGIC,0,sizeof(struct mst_pciconf_init_st))
|
||||||
|
struct mst_pciconf_init_st {
|
||||||
|
unsigned int domain;
|
||||||
|
unsigned int bus;
|
||||||
|
unsigned int devfn;
|
||||||
|
/* Byte offsets in configuration space */
|
||||||
|
unsigned int addr_reg;
|
||||||
|
unsigned int data_reg;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PCICONF_STOP _IOC (_IOC_NONE,PCICONF_MAGIC,1,0)
|
||||||
|
|
||||||
|
#define PCICONF_READ4 _IOR (PCICONF_MAGIC,1,struct mst_read4_st)
|
||||||
|
struct mst_read4_st {
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned int data; /*OUT*/
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PCICONF_WRITE4 _IOW (PCICONF_MAGIC,2,struct mst_write4_st)
|
||||||
|
struct mst_write4_st {
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned int data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define PCICONF_MODIFY _IOWR(PCICONF_MAGIC,3,struct mst_modify_st)
|
||||||
|
struct mst_modify_st {
|
||||||
|
unsigned int address_space;
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned int data;
|
||||||
|
unsigned int mask;
|
||||||
|
unsigned int old_data; /*OUT*/
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PCICONF_READ4_BUFFER _IOR (PCICONF_MAGIC,4,struct mst_read4_st)
|
||||||
|
#define PCICONF_READ4_BUFFER_EX _IOR (PCICONF_MAGIC,4,struct mst_read4_buffer_st)
|
||||||
|
struct mst_read4_buffer_st {
|
||||||
|
unsigned int address_space;
|
||||||
|
unsigned int offset;
|
||||||
|
int size;
|
||||||
|
unsigned int data[PCICONF_MAX_BUFFER_SIZE/4]; /*OUT*/
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PCICONF_WRITE4_BUFFER _IOW (PCICONF_MAGIC,5,struct mst_write4_buffer_st)
|
||||||
|
struct mst_write4_buffer_st {
|
||||||
|
unsigned int address_space;
|
||||||
|
unsigned int offset;
|
||||||
|
int size;
|
||||||
|
unsigned int data[PCICONF_MAX_BUFFER_SIZE/4]; /*IN*/
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PCICONF_MST_PARAMS _IOR (PCICONF_MAGIC,6,struct mst_params_st)
|
||||||
|
struct mst_params_st {
|
||||||
|
unsigned int domain;
|
||||||
|
unsigned int bus;
|
||||||
|
unsigned int slot;
|
||||||
|
unsigned int func;
|
||||||
|
unsigned int bar;
|
||||||
|
unsigned int device;
|
||||||
|
unsigned int vendor;
|
||||||
|
unsigned int subsystem_device;
|
||||||
|
unsigned int subsystem_vendor;
|
||||||
|
unsigned int vendor_specific_cap;
|
||||||
|
u_int32_t vsec_cap_mask;
|
||||||
|
unsigned int multifunction;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PCICONF_READ4_NEW _IOR (PCICONF_MAGIC,7,struct mst_read4_new_st)
|
||||||
|
struct mst_read4_new_st {
|
||||||
|
unsigned int address_space;
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned int data; /*OUT*/
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************/
|
||||||
|
/* VPD ACCESS */
|
||||||
|
#define PCICONF_VPD_READ4 _IOR(PCICONF_MAGIC, 7, struct mst_vpd_read4_st)
|
||||||
|
struct mst_vpd_read4_st {
|
||||||
|
unsigned int offset; /* IN - must be aligned to DWORD */
|
||||||
|
unsigned int data; /* OUT */
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PCICONF_WRITE4_NEW _IOW (PCICONF_MAGIC,8,struct mst_write4_new_st)
|
||||||
|
struct mst_write4_new_st {
|
||||||
|
unsigned int address_space;
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned int data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define PCICONF_VPD_WRITE4 _IOW(PCICONF_MAGIC, 8, struct mst_vpd_write4_st)
|
||||||
|
struct mst_vpd_write4_st {
|
||||||
|
unsigned int offset; /* IN - must be aligned to DWORD */
|
||||||
|
unsigned int data; /* IN */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MEM_ACCESS
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MST_DMA_ICMD,
|
||||||
|
MST_DMA_END=32
|
||||||
|
} mst_dma_type_t;
|
||||||
|
|
||||||
|
|
||||||
|
#define PCICONF_MEM_ACCESS _IOWR(PCICONF_MAGIC, 10, struct mst_mem_access_st)
|
||||||
|
struct mst_mem_access_st {
|
||||||
|
mst_dma_type_t mem_type;
|
||||||
|
unsigned int _rw; /* READ: 0, WRITE: 1 */
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned int size;
|
||||||
|
unsigned char data[PCICONF_MAX_MEMACCESS_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PCICONF_DMA_PROPS _IOR (PCICONF_MAGIC, 11, struct mst_dma_props_st)
|
||||||
|
|
||||||
|
struct dma_prop {
|
||||||
|
unsigned long long int dma_pa;
|
||||||
|
unsigned int mem_size;
|
||||||
|
};
|
||||||
|
struct mst_dma_props_st {
|
||||||
|
struct dma_prop dma_props[MST_DMA_END];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define PCICONF_MST_META_DATA _IOR (PCICONF_MAGIC, 12, struct mst_meta_data)
|
||||||
|
|
||||||
|
struct mst_meta_data_payload {
|
||||||
|
unsigned short api_version_major;
|
||||||
|
unsigned int api_version_minor;
|
||||||
|
unsigned int cap_vector[PCICONF_CAP_VEC_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mst_meta_data {
|
||||||
|
struct mst_hdr hdr;
|
||||||
|
struct mst_meta_data_payload data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define PCICONF_GET_DMA_PAGES _IOR (PCICONF_MAGIC, 13, struct page_info_st)
|
||||||
|
#define PCICONF_RELEASE_DMA_PAGES _IOR (PCICONF_MAGIC, 14, struct page_info_st)
|
||||||
|
|
||||||
|
struct page_address_st {
|
||||||
|
u_int64_t dma_address;
|
||||||
|
u_int64_t virtual_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct page_info_st {
|
||||||
|
unsigned int page_amount;
|
||||||
|
unsigned long page_pointer_start;
|
||||||
|
struct page_address_st page_address_array[PCICONF_MAX_PAGES_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define PCICONF_READ_DWORD_FROM_CONFIG_SPACE _IOR (PCICONF_MAGIC, 15, struct read_dword_from_config_space)
|
||||||
|
struct read_dword_from_config_space {
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned int data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
KPVER ?= $(shell uname -r)
|
||||||
|
KSRC ?= /lib/modules/$(KPVER)/build
|
||||||
|
CPU_ARCH ?= $(shell uname -m)
|
||||||
|
|
||||||
|
# Oracle Linux OS.
|
||||||
|
ifneq ($(shell if (echo $(KPVER) | grep -qE 'uek'); then \
|
||||||
|
echo "YES"; else echo ""; fi),)
|
||||||
|
override WITH_MAKE_PARAMS += ctf-dir=$(CWD)/.ctf
|
||||||
|
endif
|
||||||
|
|
||||||
|
NNT_DRIVER_LOCATION = ../../nnt_driver
|
||||||
|
PACKAGE_NAME = nnt-driver
|
||||||
|
PACKAGE_VERSION = 1.0.0
|
||||||
|
PACKAGE_RC = 1
|
||||||
|
|
||||||
|
%: %.in
|
||||||
|
sed \
|
||||||
|
-e 's/@PACKAGE_NAME@/$(PACKAGE_NAME)/g' \
|
||||||
|
-e 's/@PACKAGE_VERSION@/$(PACKAGE_VERSION)/g' \
|
||||||
|
-e 's/@PACKAGE_RC@/$(PACKAGE_RC)/g' \
|
||||||
|
<$< >$@
|
||||||
|
|
||||||
|
ifneq ($(findstring ppc64, $(CPU_ARCH)),)
|
||||||
|
obj-m += mst_ppc_pci_reset.o
|
||||||
|
EXTRA_CFLAGS= -I$(PWD)/$(NNT_DRIVER_LOCATION)
|
||||||
|
endif
|
||||||
|
|
||||||
|
all:
|
||||||
|
make -C $(KSRC) M=$(PWD) CONFIG_CTF= CONFIG_CC_STACKPROTECTOR_STRONG= $(WITH_MAKE_PARAMS) modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C $(KSRC) M=$(PWD) clean
|
||||||
306
drivers/net/ethernet/mft/mst_backward_compatibility/mst_ppc/mst_ppc_pci_reset.c
Executable file
306
drivers/net/ethernet/mft/mst_backward_compatibility/mst_ppc/mst_ppc_pci_reset.c
Executable file
@@ -0,0 +1,306 @@
|
|||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kmod.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include "nnt_ppc_device_list.h"
|
||||||
|
#include "nnt_ppc_driver_defs.h"
|
||||||
|
#include "nnt_defs.h"
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Itay Avraham <itayavr@nvidia.com>");
|
||||||
|
MODULE_DESCRIPTION("NNT PPC driver (NVIDIA® networking tools driver)");
|
||||||
|
MODULE_LICENSE("Dual BSD/GPL");
|
||||||
|
|
||||||
|
|
||||||
|
/* Passing PCI devices (DBDF addresses), separated by comma, for example:
|
||||||
|
* 0000:00:08.0,0000:00:08.1 */
|
||||||
|
char pci_device_list[NNT_DEVICE_LIST_SIZE];
|
||||||
|
|
||||||
|
/* Create the file in sysfs. */
|
||||||
|
module_param_string(pci_dev, pci_device_list, sizeof(pci_device_list), 0444);
|
||||||
|
|
||||||
|
|
||||||
|
struct nnt_ppc_reset_info nnt_ppc_reset;
|
||||||
|
|
||||||
|
|
||||||
|
void restore_pci_configuration_space(void)
|
||||||
|
{
|
||||||
|
struct nnt_ppc_device* nnt_pci_device;
|
||||||
|
|
||||||
|
list_for_each_entry(nnt_pci_device, &nnt_device_list,
|
||||||
|
entry) {
|
||||||
|
/* Restore the saved state of a PCI device. */
|
||||||
|
pci_restore_state(nnt_pci_device->pci_device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wait_for_response(void)
|
||||||
|
{
|
||||||
|
unsigned short device_id = NNT_UNKNOWN_DEVICE_ID;
|
||||||
|
struct nnt_ppc_device* nnt_pci_device;
|
||||||
|
int polling_counter = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
list_for_each_entry(nnt_pci_device, &nnt_device_list,
|
||||||
|
entry) {
|
||||||
|
struct pci_dev* pci_device = nnt_pci_device->pci_device;
|
||||||
|
|
||||||
|
/* Device id still unknown ? */
|
||||||
|
while(device_id != pci_device->device) {
|
||||||
|
/* 100ms is the minimum time that prevents error logs on
|
||||||
|
dmesg (device is not ready for PCI configuration cycles). */
|
||||||
|
msleep(NNT_MINIMUM_WAITING_TIME);
|
||||||
|
|
||||||
|
/* Read the device id.
|
||||||
|
Access can fail (if device is not ready) and
|
||||||
|
as a result we might get errors in dmesg. */
|
||||||
|
pci_read_config_word(pci_device, PCI_DEVICE_ID,
|
||||||
|
&device_id);
|
||||||
|
|
||||||
|
/* Polling counter violation. */
|
||||||
|
if (polling_counter > NNT_MAXIMUM_POLLING_NUMBER) {
|
||||||
|
printk(KERN_ERR "%s Polling on device id failed: reached max value of polling failures for device: %s\n",
|
||||||
|
dev_driver_string(&pci_device->dev), dev_name(&pci_device->dev));
|
||||||
|
error = -EINVAL;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
polling_counter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int set_reset_state(enum pcie_reset_state state)
|
||||||
|
{
|
||||||
|
struct nnt_ppc_device* nnt_pci_device;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
list_for_each_entry(nnt_pci_device, &nnt_device_list,
|
||||||
|
entry) {
|
||||||
|
struct pci_dev* pci_device = nnt_pci_device->pci_device;
|
||||||
|
|
||||||
|
if (PCI_FUNC(pci_device->devfn) == 0) {
|
||||||
|
/* Set reset state for device devce. */
|
||||||
|
printk(KERN_DEBUG "%s Send hot reset to the device: %s\n",dev_driver_string(&pci_device->dev), dev_name(&pci_device->dev));
|
||||||
|
error = pci_set_pcie_reset_state(pci_device, state);
|
||||||
|
if (error) {
|
||||||
|
printk(KERN_ERR "%s Set reset state for device failed for device: %s - error: %d\n",
|
||||||
|
dev_driver_string(&pci_device->dev), dev_name(&pci_device->dev), error);
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int save_pci_configucation_space(void)
|
||||||
|
{
|
||||||
|
struct nnt_ppc_device* nnt_pci_device = NULL;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
list_for_each_entry(nnt_pci_device, &nnt_device_list,
|
||||||
|
entry) {
|
||||||
|
struct pci_dev* pci_device = nnt_pci_device->pci_device;
|
||||||
|
|
||||||
|
/* Initialize device before it's used by a driver. */
|
||||||
|
error = pci_enable_device(pci_device);
|
||||||
|
if (error) {
|
||||||
|
printk(KERN_ERR "%s Reset failed for device: %s - error: %d\n",
|
||||||
|
dev_driver_string(&pci_device->dev), dev_name(&pci_device->dev), error);
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enables bus-mastering for device device. */
|
||||||
|
pci_set_master(pci_device);
|
||||||
|
|
||||||
|
/* Save the PCI configuration space of a device before sending hot reset. */
|
||||||
|
error = pci_save_state(pci_device);
|
||||||
|
if (error) {
|
||||||
|
printk(KERN_ERR "%s Reset failed for device: %s - error: %d\n",
|
||||||
|
dev_driver_string(&pci_device->dev), dev_name(&pci_device->dev), error);
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int pci_devices_reset(void)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
if (nnt_ppc_reset.reset_was_done) {
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save configuration space for all devices. */
|
||||||
|
error = save_pci_configucation_space();
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Disable the link by sending the hot reset. */
|
||||||
|
error = set_reset_state(pcie_hot_reset);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
msleep(jiffies_to_msecs(HZ));
|
||||||
|
|
||||||
|
/* Enable the link by sending the hot reset. */
|
||||||
|
error = set_reset_state(pcie_deassert_reset);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Wait for the device to response to PCI configuration cycles. */
|
||||||
|
error = wait_for_response();
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Restore PCI configuration space for all PCI devices. */
|
||||||
|
restore_pci_configuration_space();
|
||||||
|
|
||||||
|
nnt_ppc_reset.reset_was_done = 1;
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int init_pci_device(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||||
|
{
|
||||||
|
struct nnt_ppc_device* nnt_pci_device;
|
||||||
|
|
||||||
|
list_for_each_entry(nnt_pci_device, &nnt_device_list,
|
||||||
|
entry) {
|
||||||
|
if (!strcmp(nnt_pci_device->pci_device_dbdf_name, dev_name(&pdev->dev))) {
|
||||||
|
nnt_pci_device->pci_device = pdev;
|
||||||
|
nnt_ppc_reset.number_of_found_pci_device++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nnt_ppc_reset.number_of_requested_pci_device == nnt_ppc_reset.number_of_found_pci_device) {
|
||||||
|
return pci_devices_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void remove_pci_device(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
struct nnt_ppc_device* nnt_pci_device;
|
||||||
|
|
||||||
|
list_for_each_entry(nnt_pci_device, &nnt_device_list,
|
||||||
|
entry) {
|
||||||
|
if (!strcmp(nnt_pci_device->pci_device_dbdf_name, dev_name(&pdev->dev))) {
|
||||||
|
pci_clear_master(pdev);
|
||||||
|
pci_disable_device(pdev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int ppc_device_structure_init(struct nnt_ppc_device** nnt_pci_device, unsigned int pci_device_name_length)
|
||||||
|
{
|
||||||
|
/* Allocate nnt device structure. */
|
||||||
|
*nnt_pci_device=
|
||||||
|
kzalloc(sizeof(struct nnt_ppc_device),GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!(*nnt_pci_device)) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize nnt structure. */
|
||||||
|
memset(*nnt_pci_device, 0, sizeof(struct nnt_ppc_device));
|
||||||
|
|
||||||
|
(*nnt_pci_device)->pci_device_dbdf_name =
|
||||||
|
kzalloc(pci_device_name_length,GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!(*nnt_pci_device)->pci_device_dbdf_name) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int parse_pci_devices_string(void)
|
||||||
|
{
|
||||||
|
struct nnt_ppc_device* nnt_pci_device;
|
||||||
|
char buffer[NNT_DEVICE_LIST_SIZE];
|
||||||
|
char* pci_device_dbdf_name = NULL;
|
||||||
|
char* dbdf_list = NULL;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
strncpy(buffer, pci_device_list, NNT_DEVICE_LIST_SIZE);
|
||||||
|
dbdf_list = buffer;
|
||||||
|
|
||||||
|
/* Add the pci device name (DBDF) to the list. */
|
||||||
|
while ((pci_device_dbdf_name = strsep(&dbdf_list, ",")) != NULL) {
|
||||||
|
/* Allocate ppc device info structure. */
|
||||||
|
unsigned int pci_device_name_length = strlen(pci_device_dbdf_name);
|
||||||
|
nnt_pci_device = NULL;
|
||||||
|
|
||||||
|
error = ppc_device_structure_init(&nnt_pci_device, pci_device_name_length);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Copy the device name string. */
|
||||||
|
strncpy(nnt_pci_device->pci_device_dbdf_name, pci_device_dbdf_name,
|
||||||
|
pci_device_name_length);
|
||||||
|
|
||||||
|
/* Create a device entry in the list. */
|
||||||
|
list_add_tail(&nnt_pci_device->entry, &nnt_device_list);
|
||||||
|
nnt_ppc_reset.number_of_requested_pci_device++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void init_members(void)
|
||||||
|
{
|
||||||
|
memset(&nnt_ppc_reset, 0, sizeof(struct nnt_ppc_reset_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct pci_driver nnt_ppc_driver = {
|
||||||
|
.name = "nnt_ppc_driver",
|
||||||
|
.id_table = pciconf_devices,
|
||||||
|
.probe = init_pci_device,
|
||||||
|
.remove = remove_pci_device,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init init(void)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
init_members();
|
||||||
|
|
||||||
|
/* Parse the parameters from the user space. */
|
||||||
|
error = parse_pci_devices_string();
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Register the NNT PPC driver. */
|
||||||
|
return pci_register_driver(&nnt_ppc_driver);
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void __exit cleanup(void)
|
||||||
|
{
|
||||||
|
/* Unregister the NNT PPC driver. */
|
||||||
|
pci_unregister_driver(&nnt_ppc_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module_init(init);
|
||||||
|
module_exit(cleanup);
|
||||||
34
drivers/net/ethernet/mft/nnt_driver/Makefile
Normal file
34
drivers/net/ethernet/mft/nnt_driver/Makefile
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
KVERSION ?= $(shell uname -r)
|
||||||
|
CPU_ARCH ?= $(shell uname -m)
|
||||||
|
|
||||||
|
# Oracle Linux OS.
|
||||||
|
ifneq ($(shell if (echo $(KVERSION) | grep -qE 'uek'); then \
|
||||||
|
echo "YES"; else echo ""; fi),)
|
||||||
|
override WITH_MAKE_PARAMS += ctf-dir=$(CWD)/.ctf
|
||||||
|
endif
|
||||||
|
|
||||||
|
PACKAGE_NAME = nnt-driver
|
||||||
|
PACKAGE_VERSION = 1.0.0
|
||||||
|
PACKAGE_RC = 1
|
||||||
|
|
||||||
|
%: %.in
|
||||||
|
sed \
|
||||||
|
-e 's/@PACKAGE_NAME@/$(PACKAGE_NAME)/g' \
|
||||||
|
-e 's/@PACKAGE_VERSION@/$(PACKAGE_VERSION)/g' \
|
||||||
|
-e 's/@PACKAGE_RC@/$(PACKAGE_RC)/g' \
|
||||||
|
<$< >$@
|
||||||
|
|
||||||
|
ifneq ($(findstring ppc64, $(CPU_ARCH)),)
|
||||||
|
obj-m += mst_ppc_pci_reset.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
obj-m += nnt_driver.o
|
||||||
|
nnt_driver-objs += nnt_device.o nnt_dma.o nnt_pci_conf_access.o \
|
||||||
|
nnt_pci_conf_access_no_vsec.o nnt_memory_access.o \
|
||||||
|
nnt_ioctl.o
|
||||||
|
|
||||||
|
all:
|
||||||
|
make -C /lib/modules/$(KVERSION)/build M=$(PWD) CONFIG_CTF= CONFIG_CC_STACKPROTECTOR_STRONG= $(WITH_MAKE_PARAMS) modules
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
|
||||||
42
drivers/net/ethernet/mft/nnt_driver/nnt_defs.h
Normal file
42
drivers/net/ethernet/mft/nnt_driver/nnt_defs.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#ifndef NNT_DEFS_H
|
||||||
|
#define NNT_DEFS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* Passing MFT flag argument */
|
||||||
|
extern int is_mft_package;
|
||||||
|
extern struct driver_info nnt_driver_info;
|
||||||
|
|
||||||
|
#define NNT_DRIVER_NAME "nnt_driver"
|
||||||
|
#define NNT_CLASS_NAME "nnt_class"
|
||||||
|
#define NNT_DEVICE_PREFIX "mt"
|
||||||
|
#define NNT_DRIVER "NNT Driver::"
|
||||||
|
|
||||||
|
#define CHECK_PCI_READ_ERROR(error, address) \
|
||||||
|
if (error) { \
|
||||||
|
printk(KERN_ERR "Failed to read from address: %x\n", address); \
|
||||||
|
goto ReturnOnFinished; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHECK_PCI_WRITE_ERROR(error, address, data) \
|
||||||
|
if (error) { \
|
||||||
|
printk(KERN_ERR "Failed to write to address: %x, data: %x\n", address, data); \
|
||||||
|
goto ReturnOnFinished; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHECK_ERROR(error) \
|
||||||
|
if (error) { \
|
||||||
|
goto ReturnOnFinished; \
|
||||||
|
}
|
||||||
|
|
||||||
|
struct driver_info {
|
||||||
|
dev_t device_number;
|
||||||
|
int contiguous_device_numbers;
|
||||||
|
struct class* class_driver;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
626
drivers/net/ethernet/mft/nnt_driver/nnt_device.c
Normal file
626
drivers/net/ethernet/mft/nnt_driver/nnt_device.c
Normal file
@@ -0,0 +1,626 @@
|
|||||||
|
#include "nnt_device.h"
|
||||||
|
#include "nnt_device_defs.h"
|
||||||
|
#include "nnt_defs.h"
|
||||||
|
#include "nnt_pci_conf_access.h"
|
||||||
|
#include "nnt_pci_conf_access_no_vsec.h"
|
||||||
|
#include "nnt_memory_access.h"
|
||||||
|
#include <linux/module.h>
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
/* Device list to check if device is available
|
||||||
|
since it could be removed by hotplug event. */
|
||||||
|
LIST_HEAD(nnt_device_list);
|
||||||
|
|
||||||
|
int get_nnt_device(struct file* file, struct nnt_device** nnt_device)
|
||||||
|
{
|
||||||
|
int error_code = 0;
|
||||||
|
|
||||||
|
if (!file->private_data)
|
||||||
|
{
|
||||||
|
error_code = -EINVAL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*nnt_device = file->private_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_private_data_open(struct file* file)
|
||||||
|
{
|
||||||
|
struct nnt_device* current_nnt_device = NULL;
|
||||||
|
struct nnt_device* temp_nnt_device = NULL;
|
||||||
|
int minor = iminor(file_inode(file));
|
||||||
|
|
||||||
|
/* Set private data to nnt structure. */
|
||||||
|
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||||
|
{
|
||||||
|
if ((minor == current_nnt_device->device_minor_number) && current_nnt_device->device_enabled)
|
||||||
|
{
|
||||||
|
file->private_data = current_nnt_device;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_private_data_bc(struct file* file, unsigned int bus, unsigned int devfn, unsigned int domain)
|
||||||
|
{
|
||||||
|
struct nnt_device* current_nnt_device = NULL;
|
||||||
|
struct nnt_device* temp_nnt_device = NULL;
|
||||||
|
int minor = iminor(file_inode(file));
|
||||||
|
unsigned int current_function;
|
||||||
|
unsigned int current_device;
|
||||||
|
|
||||||
|
/* Set private data to nnt structure. */
|
||||||
|
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||||
|
{
|
||||||
|
struct pci_bus* pci_bus = pci_find_bus(current_nnt_device->dbdf.domain, current_nnt_device->dbdf.bus);
|
||||||
|
if (!pci_bus)
|
||||||
|
{
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_nnt_device->pci_device = pci_get_slot(pci_bus, current_nnt_device->dbdf.devfn);
|
||||||
|
if (!current_nnt_device->pci_device)
|
||||||
|
{
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_function = PCI_FUNC(current_nnt_device->dbdf.devfn);
|
||||||
|
current_device = PCI_SLOT(current_nnt_device->dbdf.devfn);
|
||||||
|
|
||||||
|
if ((current_nnt_device->dbdf.bus == bus) && (current_device == PCI_SLOT(devfn)) &&
|
||||||
|
(current_function == PCI_FUNC(devfn)) && (current_nnt_device->dbdf.domain == domain))
|
||||||
|
{
|
||||||
|
current_nnt_device->device_minor_number = minor;
|
||||||
|
current_nnt_device->device_enabled = true;
|
||||||
|
file->private_data = current_nnt_device;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_private_data(struct file* file)
|
||||||
|
{
|
||||||
|
struct nnt_device* current_nnt_device = NULL;
|
||||||
|
struct nnt_device* temp_nnt_device = NULL;
|
||||||
|
int minor = iminor(file_inode(file));
|
||||||
|
|
||||||
|
/* Set private data to nnt structure. */
|
||||||
|
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||||
|
{
|
||||||
|
if (current_nnt_device->device_minor_number == minor)
|
||||||
|
{
|
||||||
|
file->private_data = current_nnt_device;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printk(KERN_ERR "failed to find device with minor=%d\n", minor);
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_file_name_mstflint(struct pci_dev* pci_device, struct nnt_device* nnt_dev, enum nnt_device_type device_type)
|
||||||
|
{
|
||||||
|
sprintf(nnt_dev->device_name, "%4.4x:%2.2x:%2.2x.%1.1x_%s", pci_domain_nr(pci_device->bus), pci_device->bus->number,
|
||||||
|
PCI_SLOT(pci_device->devfn), PCI_FUNC(pci_device->devfn),
|
||||||
|
(device_type == NNT_PCICONF) ? MSTFLINT_PCICONF_DEVICE_NAME : MSTFLINT_MEMORY_DEVICE_NAME);
|
||||||
|
|
||||||
|
printk(KERN_DEBUG
|
||||||
|
"MSTFlint device name created: id: %d, slot id: %d, device name: /dev/%s domain: 0x%x bus: 0x%x\n",
|
||||||
|
pci_device->device, PCI_FUNC(pci_device->devfn), nnt_dev->device_name, pci_domain_nr(pci_device->bus),
|
||||||
|
pci_device->bus->number);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_file_name_mft(struct pci_dev* pci_device, struct nnt_device* nnt_dev, enum nnt_device_type device_type)
|
||||||
|
{
|
||||||
|
sprintf(nnt_dev->device_name, "mst/mt%d_%s0.%x", pci_device->device,
|
||||||
|
(device_type == NNT_PCICONF) ? MFT_PCICONF_DEVICE_NAME : MFT_MEMORY_DEVICE_NAME,
|
||||||
|
PCI_FUNC(pci_device->devfn));
|
||||||
|
|
||||||
|
printk(KERN_DEBUG "MFT device name created: id: %d, slot id: %d, device name: /dev/%s domain: 0x%x bus: 0x%x\n",
|
||||||
|
pci_device->device, PCI_FUNC(pci_device->devfn), nnt_dev->device_name, pci_domain_nr(pci_device->bus),
|
||||||
|
pci_device->bus->number);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nnt_device_structure_init(struct nnt_device** nnt_device)
|
||||||
|
{
|
||||||
|
/* Allocate nnt device structure. */
|
||||||
|
*nnt_device = kzalloc(sizeof(struct nnt_device), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!(*nnt_device))
|
||||||
|
{
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize nnt structure. */
|
||||||
|
memset(*nnt_device, 0, sizeof(struct nnt_device));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_nnt_device(struct pci_dev* pci_device, enum nnt_device_type device_type, int is_alloc_chrdev_region)
|
||||||
|
{
|
||||||
|
struct nnt_device* nnt_device = NULL;
|
||||||
|
int error_code = 0;
|
||||||
|
|
||||||
|
/* Allocate nnt device info structure. */
|
||||||
|
if ((error_code = nnt_device_structure_init(&nnt_device)) != 0)
|
||||||
|
goto ReturnOnError;
|
||||||
|
|
||||||
|
if (is_alloc_chrdev_region)
|
||||||
|
{
|
||||||
|
/* Build the device file name of MSTFlint. */
|
||||||
|
if ((error_code = create_file_name_mstflint(pci_device, nnt_device, device_type)) != 0)
|
||||||
|
goto ReturnOnError;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Build the device file name of MFT. */
|
||||||
|
if ((error_code = create_file_name_mft(pci_device, nnt_device, device_type)) != 0)
|
||||||
|
goto ReturnOnError;
|
||||||
|
}
|
||||||
|
|
||||||
|
nnt_device->dbdf.bus = pci_device->bus->number;
|
||||||
|
nnt_device->dbdf.devfn = pci_device->devfn;
|
||||||
|
nnt_device->dbdf.domain = pci_domain_nr(pci_device->bus);
|
||||||
|
nnt_device->pci_device = pci_device;
|
||||||
|
nnt_device->device_type = device_type;
|
||||||
|
|
||||||
|
/* Add the nnt device structure to the list. */
|
||||||
|
list_add_tail(&nnt_device->entry, &nnt_device_list);
|
||||||
|
|
||||||
|
return error_code;
|
||||||
|
|
||||||
|
ReturnOnError:
|
||||||
|
if (nnt_device)
|
||||||
|
{
|
||||||
|
kfree(nnt_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
return error_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_pci_id_range(unsigned short pci_device_id, unsigned short id_range_start)
|
||||||
|
{
|
||||||
|
return (pci_device_id >= id_range_start) && (pci_device_id <= (id_range_start + 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_connectx(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return check_pci_id_range(pci_device_id, CONNECTX3_PCI_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_connectx3(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return pci_device_id == CONNECTX3_PCI_ID || pci_device_id == CONNECTX3PRO_PCI_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_bluefield(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return check_pci_id_range(pci_device_id, BLUEFIELD_PCI_ID) ||
|
||||||
|
check_pci_id_range(pci_device_id, BLUEFIELD_DPU_AUX_PCI_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_pcie_switch(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return check_pci_id_range(pci_device_id, SCHRODINGER_PCI_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_quantum(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return check_pci_id_range(pci_device_id, QUANTUM_PCI_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_spectrum(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return (pci_device_id == SPECTRUM_PCI_ID) || (check_pci_id_range(pci_device_id, SPECTRUM2_PCI_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_switch_ib(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return pci_device_id == SWITCHIB_PCI_ID || pci_device_id == SWITCHIB2_PCI_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_bw00(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return check_pci_id_range(pci_device_id, BW00_PCI_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_bw02(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return check_pci_id_range(pci_device_id, BW02_PCI_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_livefish_device(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return pci_device_id >= CONNECTX3_LIVEFISH_ID && pci_device_id < CONNECTX3_PCI_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_nic(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return is_connectx(pci_device_id) || is_bluefield(pci_device_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_switch(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return is_pcie_switch(pci_device_id) || is_quantum(pci_device_id) || is_spectrum(pci_device_id) ||
|
||||||
|
is_switch_ib(pci_device_id) || is_bw00(pci_device_id) || is_bw02(pci_device_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_toolspf(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return is_nic(pci_device_id - 4000) || is_switch(pci_device_id - 4000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_pciconf_device(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return is_nic(pci_device_id) || is_toolspf(pci_device_id) || is_livefish_device(pci_device_id) ||
|
||||||
|
is_switch(pci_device_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_pcicr_device(unsigned short pci_device_id)
|
||||||
|
{
|
||||||
|
return (is_switch(pci_device_id) || is_toolspf(pci_device_id) || is_connectx3(pci_device_id)) &&
|
||||||
|
(!is_livefish_device(pci_device_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_device_file(struct nnt_device* current_nnt_device,
|
||||||
|
dev_t device_number,
|
||||||
|
int minor,
|
||||||
|
struct file_operations* fop,
|
||||||
|
int is_alloc_chrdev_region)
|
||||||
|
{
|
||||||
|
struct device* device = NULL;
|
||||||
|
int error = 0;
|
||||||
|
int count = 1;
|
||||||
|
|
||||||
|
/* NNT driver will create the device file
|
||||||
|
once we stop support backward compatibility. */
|
||||||
|
current_nnt_device->device_minor_number = -1;
|
||||||
|
current_nnt_device->device_number = device_number;
|
||||||
|
current_nnt_device->mcdev.owner = THIS_MODULE;
|
||||||
|
|
||||||
|
mutex_init(¤t_nnt_device->lock);
|
||||||
|
|
||||||
|
if (!is_alloc_chrdev_region)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create device with a new minor number.
|
||||||
|
current_nnt_device->device_minor_number = minor;
|
||||||
|
current_nnt_device->device_number = MKDEV(MAJOR(device_number), minor);
|
||||||
|
|
||||||
|
current_nnt_device->device_enabled = true;
|
||||||
|
current_nnt_device->connectx_wa_slot_p1 = 0;
|
||||||
|
|
||||||
|
/* Create device node. */
|
||||||
|
device = device_create(nnt_driver_info.class_driver, NULL, current_nnt_device->device_number, NULL,
|
||||||
|
current_nnt_device->device_name);
|
||||||
|
if (!device)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "Device creation failed\n");
|
||||||
|
error = -EINVAL;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init new device. */
|
||||||
|
cdev_init(¤t_nnt_device->mcdev, fop);
|
||||||
|
|
||||||
|
/* Add device to the system. */
|
||||||
|
error = cdev_add(¤t_nnt_device->mcdev, current_nnt_device->device_number, count);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_if_vsec_supported(struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
error = nnt_device->access.init(nnt_device);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
if (!nnt_device->pciconf_device.vsec_fully_supported)
|
||||||
|
{
|
||||||
|
nnt_device->device_type = NNT_PCICONF_NO_VSEC;
|
||||||
|
nnt_device->access.read = read_pciconf_no_vsec;
|
||||||
|
nnt_device->access.write = write_pciconf_no_vsec;
|
||||||
|
nnt_device->access.init = init_pciconf_no_vsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_mellanox_vendor_type(struct nnt_device* current_nnt_device, unsigned int vsec_address)
|
||||||
|
{
|
||||||
|
u_int8_t vendor_type = 0;
|
||||||
|
int error = 0;
|
||||||
|
/* Read the capability type field */
|
||||||
|
if ((error = pci_read_config_byte(current_nnt_device->pci_device, (vsec_address + PCI_TYPE_OFFSET), &vendor_type)))
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "Reading VSEC type failed with error %d\n", error);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vendor_type == MELLANOX_VSEC_TYPE)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int get_mellanox_vsec_address(struct nnt_device* current_nnt_device)
|
||||||
|
{
|
||||||
|
unsigned int vsec_address = 0;
|
||||||
|
|
||||||
|
/* Look for the Mellanox VSEC address. if Mellanox VSEC isn't supported the address should be 0 */
|
||||||
|
vsec_address = pci_find_capability(current_nnt_device->pci_device, VSEC_CAPABILITY_ADDRESS);
|
||||||
|
if (!vsec_address || is_mellanox_vendor_type(current_nnt_device, vsec_address))
|
||||||
|
{
|
||||||
|
return vsec_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if found a non-Mellanox type VSEC, iterate of the next available VSECs*/
|
||||||
|
while (
|
||||||
|
(vsec_address = pci_find_next_capability(current_nnt_device->pci_device, vsec_address, VSEC_CAPABILITY_ADDRESS)))
|
||||||
|
{
|
||||||
|
if (is_mellanox_vendor_type(current_nnt_device, vsec_address))
|
||||||
|
{
|
||||||
|
return vsec_address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* if Mellanox VSEC address was not found, return 0 */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_devices(dev_t device_number, struct file_operations* fop, int is_alloc_chrdev_region)
|
||||||
|
{
|
||||||
|
struct nnt_device* current_nnt_device = NULL;
|
||||||
|
struct nnt_device* temp_nnt_device = NULL;
|
||||||
|
int minor = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Create necessary number of the devices. */
|
||||||
|
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||||
|
{
|
||||||
|
/* Create the device file. */
|
||||||
|
if ((error = create_device_file(current_nnt_device, device_number, minor, fop, is_alloc_chrdev_region)) != 0)
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
|
||||||
|
/* Members initialization. */
|
||||||
|
current_nnt_device->pciconf_device.vendor_specific_capability = get_mellanox_vsec_address(current_nnt_device);
|
||||||
|
current_nnt_device->vpd_capability_address =
|
||||||
|
pci_find_capability(current_nnt_device->pci_device, PCI_CAP_ID_VPD);
|
||||||
|
|
||||||
|
if (!current_nnt_device->pciconf_device.vendor_specific_capability)
|
||||||
|
{
|
||||||
|
current_nnt_device->device_type = NNT_PCICONF_NO_VSEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (current_nnt_device->device_type)
|
||||||
|
{
|
||||||
|
case NNT_PCICONF:
|
||||||
|
current_nnt_device->access.read = read_pciconf;
|
||||||
|
current_nnt_device->access.write = write_pciconf;
|
||||||
|
current_nnt_device->access.init = init_pciconf;
|
||||||
|
|
||||||
|
error = check_if_vsec_supported(current_nnt_device);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NNT_PCICONF_NO_VSEC:
|
||||||
|
current_nnt_device->access.read = read_pciconf_no_vsec;
|
||||||
|
current_nnt_device->access.write = write_pciconf_no_vsec;
|
||||||
|
current_nnt_device->access.init = init_pciconf_no_vsec;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NNT_PCI_MEMORY:
|
||||||
|
current_nnt_device->access.read = read_memory;
|
||||||
|
current_nnt_device->access.write = write_memory;
|
||||||
|
current_nnt_device->access.init = init_memory;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_alloc_chrdev_region)
|
||||||
|
{
|
||||||
|
error = current_nnt_device->access.init(current_nnt_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
minor++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_nnt_devices(dev_t device_number,
|
||||||
|
int is_alloc_chrdev_region,
|
||||||
|
struct file_operations* fop,
|
||||||
|
enum nnt_device_type_flag nnt_device_flag,
|
||||||
|
unsigned int vendor_id,
|
||||||
|
int with_unknown)
|
||||||
|
{
|
||||||
|
struct pci_dev* pci_device = NULL;
|
||||||
|
int error_code = 0;
|
||||||
|
|
||||||
|
/* Find all Nvidia PCI devices. */
|
||||||
|
while ((pci_device = pci_get_device(vendor_id, PCI_ANY_ID, pci_device)) != NULL)
|
||||||
|
{
|
||||||
|
if ((nnt_device_flag == NNT_PCICONF_DEVICES) || (nnt_device_flag == NNT_ALL_DEVICES))
|
||||||
|
{
|
||||||
|
/* Create pciconf device. */
|
||||||
|
if (with_unknown || is_pciconf_device(pci_device->device))
|
||||||
|
{
|
||||||
|
if ((error_code = create_nnt_device(pci_device, NNT_PCICONF, is_alloc_chrdev_region)) != 0)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "Failed to create pci conf device\n");
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((nnt_device_flag == NNT_PCI_DEVICES) || (nnt_device_flag == NNT_ALL_DEVICES))
|
||||||
|
{
|
||||||
|
/* Create pci memory device. */
|
||||||
|
if (with_unknown || is_pcicr_device(pci_device->device))
|
||||||
|
{
|
||||||
|
if ((error_code = create_nnt_device(pci_device, NNT_PCI_MEMORY, is_alloc_chrdev_region)) != 0)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "Failed to create pci memory device\n");
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create the devices. */
|
||||||
|
if ((error_code = create_devices(device_number, fop, is_alloc_chrdev_region)) != 0)
|
||||||
|
{
|
||||||
|
return error_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
int find_all_vendor_devices(unsigned int vendor_id)
|
||||||
|
{
|
||||||
|
struct pci_dev* pci_device = NULL;
|
||||||
|
int contiguous_device_numbers = 0;
|
||||||
|
while ((pci_device = pci_get_device(vendor_id, PCI_ANY_ID, pci_device)) != NULL)
|
||||||
|
{
|
||||||
|
contiguous_device_numbers++;
|
||||||
|
}
|
||||||
|
return contiguous_device_numbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_amount_of_nvidia_devices(void)
|
||||||
|
{
|
||||||
|
int contiguous_device_numbers = 0;
|
||||||
|
/* Find all Mellanox & Nvidia PCI devices. */
|
||||||
|
contiguous_device_numbers +=
|
||||||
|
find_all_vendor_devices(NNT_MELLANOX_PCI_VENDOR) + find_all_vendor_devices(NNT_NVIDIA_PCI_VENDOR);
|
||||||
|
return contiguous_device_numbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mutex_lock_nnt(struct file* file)
|
||||||
|
{
|
||||||
|
struct nnt_device* nnt_device;
|
||||||
|
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nnt_device = file->private_data;
|
||||||
|
|
||||||
|
if (!nnt_device)
|
||||||
|
{
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&nnt_device->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mutex_unlock_nnt(struct file* file)
|
||||||
|
{
|
||||||
|
struct nnt_device* nnt_device = file->private_data;
|
||||||
|
|
||||||
|
if (nnt_device)
|
||||||
|
{
|
||||||
|
mutex_unlock(&nnt_device->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_nnt_devices(int is_alloc_chrdev_region)
|
||||||
|
{
|
||||||
|
struct nnt_device* current_nnt_device;
|
||||||
|
struct nnt_device* temp_nnt_device;
|
||||||
|
|
||||||
|
/* free all nnt_devices */
|
||||||
|
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||||
|
{
|
||||||
|
/* Character device is no longer, it must be properly destroyed. */
|
||||||
|
if (is_alloc_chrdev_region)
|
||||||
|
{
|
||||||
|
cdev_del(¤t_nnt_device->mcdev);
|
||||||
|
device_destroy(nnt_driver_info.class_driver, current_nnt_device->device_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
list_del(¤t_nnt_device->entry);
|
||||||
|
kfree(current_nnt_device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy_nnt_devices_bc(void)
|
||||||
|
{
|
||||||
|
struct nnt_device* current_nnt_device;
|
||||||
|
struct nnt_device* temp_nnt_device;
|
||||||
|
|
||||||
|
/* free all nnt_devices */
|
||||||
|
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||||
|
{
|
||||||
|
/* Character device is no longer, it must be properly destroyed. */
|
||||||
|
list_del(¤t_nnt_device->entry);
|
||||||
|
kfree(current_nnt_device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int destroy_nnt_device_bc(struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
struct nnt_device* current_nnt_device;
|
||||||
|
struct nnt_device* temp_nnt_device;
|
||||||
|
unsigned int current_function;
|
||||||
|
unsigned int current_device;
|
||||||
|
|
||||||
|
/* Set private data to nnt structure. */
|
||||||
|
list_for_each_entry_safe(current_nnt_device, temp_nnt_device, &nnt_device_list, entry)
|
||||||
|
{
|
||||||
|
struct pci_bus* pci_bus = pci_find_bus(current_nnt_device->dbdf.domain, current_nnt_device->dbdf.bus);
|
||||||
|
if (!pci_bus)
|
||||||
|
{
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_nnt_device->pci_device = pci_get_slot(pci_bus, current_nnt_device->dbdf.devfn);
|
||||||
|
if (!current_nnt_device->pci_device)
|
||||||
|
{
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_function = PCI_FUNC(current_nnt_device->dbdf.devfn);
|
||||||
|
current_device = PCI_SLOT(current_nnt_device->dbdf.devfn);
|
||||||
|
|
||||||
|
if ((current_nnt_device->dbdf.bus == nnt_device->dbdf.bus) &&
|
||||||
|
(current_device == PCI_SLOT(nnt_device->dbdf.devfn)) &&
|
||||||
|
(current_function == PCI_FUNC(nnt_device->dbdf.devfn)) &&
|
||||||
|
(current_nnt_device->dbdf.domain == nnt_device->dbdf.domain))
|
||||||
|
{
|
||||||
|
/* Character device is no longer, it must be properly disabled. */
|
||||||
|
current_nnt_device->device_enabled = false;
|
||||||
|
printk(KERN_DEBUG "Device removed: domain: %d, bus: %d, device:%d, function:%d \n",
|
||||||
|
current_nnt_device->dbdf.domain, current_nnt_device->dbdf.bus, current_device, current_function);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
26
drivers/net/ethernet/mft/nnt_driver/nnt_device.h
Normal file
26
drivers/net/ethernet/mft/nnt_driver/nnt_device.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef NNT_DEVICE_H
|
||||||
|
#define NNT_DEVICE_H
|
||||||
|
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include "nnt_device_defs.h"
|
||||||
|
|
||||||
|
int create_nnt_devices(dev_t device_number,
|
||||||
|
int is_alloc_chrdev_region,
|
||||||
|
struct file_operations* fop,
|
||||||
|
enum nnt_device_type_flag nnt_device_flag,
|
||||||
|
unsigned int vendor_id,
|
||||||
|
int with_unknown);
|
||||||
|
void destroy_nnt_devices(int is_alloc_chrdev_region);
|
||||||
|
void destroy_nnt_devices_bc(void);
|
||||||
|
int destroy_nnt_device_bc(struct nnt_device* nnt_device);
|
||||||
|
int is_pciconf_device(unsigned short pci_device_id);
|
||||||
|
int is_pcicr_device(unsigned short pci_device_id);
|
||||||
|
int get_amount_of_nvidia_devices(void);
|
||||||
|
int set_private_data(struct file* file);
|
||||||
|
void set_private_data_open(struct file* file);
|
||||||
|
int set_private_data_bc(struct file* file, unsigned int bus, unsigned int devfn, unsigned int domain);
|
||||||
|
int get_nnt_device(struct file* file, struct nnt_device** nnt_device);
|
||||||
|
int mutex_lock_nnt(struct file* file);
|
||||||
|
void mutex_unlock_nnt(struct file* file);
|
||||||
|
|
||||||
|
#endif
|
||||||
169
drivers/net/ethernet/mft/nnt_driver/nnt_device_defs.h
Normal file
169
drivers/net/ethernet/mft/nnt_driver/nnt_device_defs.h
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
#ifndef NNT_DEVICE_DEFS_H
|
||||||
|
#define NNT_DEVICE_DEFS_H
|
||||||
|
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/cdev.h>
|
||||||
|
#include "nnt_ioctl_defs.h"
|
||||||
|
|
||||||
|
#define NNT_DEVICE_ID_OFFSET 0xf0014
|
||||||
|
#define NNT_WO_REG_ADDR_DATA 0xbadacce5
|
||||||
|
#define NNT_NAME_SIZE 75
|
||||||
|
#define NNT_CONF_ADDRES_REGISETER 88
|
||||||
|
#define NNT_CONF_DATA_REGISTER 92
|
||||||
|
#define MELLANOX_VSEC_TYPE 0
|
||||||
|
#define PCI_TYPE_OFFSET 0x03
|
||||||
|
#define PCI_SEMAPHORE_OFFSET 0x0c
|
||||||
|
#define PCI_ADDRESS_OFFSET 0x10
|
||||||
|
#define PCI_DATA_OFFSET 0x14
|
||||||
|
#define NNT_MEMORY_SIZE 1024 * 1024
|
||||||
|
#define VSEC_CAPABILITY_ADDRESS 0x9
|
||||||
|
|
||||||
|
#define MSTFLINT_PCICONF_DEVICE_NAME "mstconf"
|
||||||
|
#define MSTFLINT_MEMORY_DEVICE_NAME "mstcr"
|
||||||
|
#define MFT_PCICONF_DEVICE_NAME "pciconf"
|
||||||
|
#define MFT_MEMORY_DEVICE_NAME "pci_cr"
|
||||||
|
|
||||||
|
#define MST_BC_BUFFER_SIZE 256
|
||||||
|
#define MST_BC_MAX_MINOR 256
|
||||||
|
|
||||||
|
// Mellanox Vendor ID.
|
||||||
|
#define NNT_MELLANOX_PCI_VENDOR 0x15b3
|
||||||
|
|
||||||
|
// NVIDIA Vendor ID.
|
||||||
|
#define NNT_NVIDIA_PCI_VENDOR 0x10de
|
||||||
|
|
||||||
|
// Livefish Device ID range.
|
||||||
|
#define CONNECTX3_LIVEFISH_ID 502
|
||||||
|
|
||||||
|
// PCI Device IDs.
|
||||||
|
#define CONNECTX3_PCI_ID 4099
|
||||||
|
#define CONNECTX3PRO_PCI_ID 4103
|
||||||
|
#define CONNECTIB_PCI_ID 4113
|
||||||
|
#define CONNECTX4_PCI_ID 4115
|
||||||
|
#define CONNECTX4LX_PCI_ID 4117
|
||||||
|
#define CONNECTX5_PCI_ID 4119
|
||||||
|
#define CONNECTX5EX_PCI_ID 4121
|
||||||
|
#define CONNECTX6_PCI_ID 4123
|
||||||
|
#define CONNECTX6DX_PCI_ID 4125
|
||||||
|
#define CONNECTX6LX_PCI_ID 4127
|
||||||
|
#define CONNECTX7_PCI_ID 4129
|
||||||
|
#define CONNECTX8_PCI_ID 4131
|
||||||
|
#define SCHRODINGER_PCI_ID 6518
|
||||||
|
#define FREYSA_PCI_ID 6521
|
||||||
|
#define BLUEFIELD_PCI_ID 41682
|
||||||
|
#define BLUEFIELD2_PCI_ID 41686
|
||||||
|
#define BLUEFIELD_DPU_AUX_PCI_ID 49873
|
||||||
|
#define BLUEFIELD3_PCI_ID 41692
|
||||||
|
#define BLUEFIELD4_PCI_ID 41694
|
||||||
|
#define SWITCHIB_PCI_ID 52000
|
||||||
|
#define SWITCHIB2_PCI_ID 53000
|
||||||
|
#define QUANTUM_PCI_ID 54000
|
||||||
|
#define QUANTUM2_PCI_ID 54002
|
||||||
|
#define QUANTUM3_PCI_ID 54004
|
||||||
|
#define SPECTRUM_PCI_ID 52100
|
||||||
|
#define SPECTRUM2_PCI_ID 53100
|
||||||
|
#define SPECTRUM3_PCI_ID 53104
|
||||||
|
#define SPECTRUM4_PCI_ID 53120
|
||||||
|
#define BW00_PCI_ID 10496
|
||||||
|
#define BW02_PCI_ID 10624
|
||||||
|
|
||||||
|
enum nnt_device_type_flag
|
||||||
|
{
|
||||||
|
NNT_PCICONF_DEVICES = 0x01,
|
||||||
|
NNT_PCI_DEVICES,
|
||||||
|
NNT_ALL_DEVICES
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nnt_dma_page
|
||||||
|
{
|
||||||
|
struct page** page_list;
|
||||||
|
dma_addr_t* dma_address_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum nnt_device_type
|
||||||
|
{
|
||||||
|
NNT_PCICONF,
|
||||||
|
NNT_PCICONF_NO_VSEC,
|
||||||
|
NNT_PCI_MEMORY
|
||||||
|
};
|
||||||
|
|
||||||
|
struct supported_address_space
|
||||||
|
{
|
||||||
|
int cr_space;
|
||||||
|
int icmd;
|
||||||
|
int semaphore;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Forward declaration */
|
||||||
|
struct nnt_device;
|
||||||
|
typedef int (*callback_read)(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation);
|
||||||
|
typedef int (*callback_write)(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation);
|
||||||
|
typedef int (*callback_init)(struct nnt_device* nnt_device);
|
||||||
|
|
||||||
|
struct nnt_access_callback
|
||||||
|
{
|
||||||
|
callback_read read;
|
||||||
|
callback_write write;
|
||||||
|
callback_init init;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nnt_device_pciconf
|
||||||
|
{
|
||||||
|
struct supported_address_space address_space;
|
||||||
|
unsigned int address_register;
|
||||||
|
unsigned int data_register;
|
||||||
|
unsigned int semaphore_offset;
|
||||||
|
unsigned int data_offset;
|
||||||
|
unsigned int address_offset;
|
||||||
|
unsigned int vendor_specific_capability;
|
||||||
|
unsigned int vsec_capability_mask;
|
||||||
|
unsigned int vsec_fully_supported;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nnt_device_pci
|
||||||
|
{
|
||||||
|
unsigned long long bar_address;
|
||||||
|
unsigned int bar_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nnt_device_memory
|
||||||
|
{
|
||||||
|
unsigned int pci_memory_bar_address;
|
||||||
|
unsigned int connectx_wa_slot_p1;
|
||||||
|
void* hardware_memory_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nnt_device_dbdf
|
||||||
|
{
|
||||||
|
unsigned int domain;
|
||||||
|
unsigned int bus;
|
||||||
|
unsigned int devfn;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nnt_device
|
||||||
|
{
|
||||||
|
struct nnt_device_pciconf pciconf_device;
|
||||||
|
struct nnt_device_memory memory_device;
|
||||||
|
struct nnt_access_callback access;
|
||||||
|
struct nnt_device_pci device_pci;
|
||||||
|
struct pci_dev* pci_device;
|
||||||
|
struct nnt_dma_page dma_page;
|
||||||
|
struct list_head entry;
|
||||||
|
struct cdev mcdev;
|
||||||
|
struct mutex lock;
|
||||||
|
struct nnt_device_dbdf dbdf;
|
||||||
|
enum nnt_device_type device_type;
|
||||||
|
int vpd_capability_address;
|
||||||
|
int device_minor_number;
|
||||||
|
int wo_address;
|
||||||
|
int buffer_used_bc;
|
||||||
|
int device_enabled;
|
||||||
|
char device_name[NNT_NAME_SIZE];
|
||||||
|
char buffer_bc[MST_BC_BUFFER_SIZE];
|
||||||
|
unsigned int connectx_wa_slot_p1;
|
||||||
|
unsigned char connectx_wa_slots;
|
||||||
|
dev_t device_number;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
196
drivers/net/ethernet/mft/nnt_driver/nnt_dma.c
Normal file
196
drivers/net/ethernet/mft/nnt_driver/nnt_dma.c
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include "nnt_device_defs.h"
|
||||||
|
#include "nnt_pci_conf_access_defs.h"
|
||||||
|
#include "nnt_pci_conf_access.h"
|
||||||
|
#include "nnt_defs.h"
|
||||||
|
#include "nnt_ioctl_defs.h"
|
||||||
|
|
||||||
|
int dma_mapping_page(unsigned int total_pinned, unsigned int page_mapped_counter,
|
||||||
|
struct nnt_device* nnt_device, struct page** current_pages,
|
||||||
|
struct nnt_page_info* page_info)
|
||||||
|
{
|
||||||
|
int current_page = total_pinned + page_mapped_counter;
|
||||||
|
int error_code = 0;
|
||||||
|
|
||||||
|
/* Get the dma address. */
|
||||||
|
nnt_device->dma_page.dma_address_list[current_page] =
|
||||||
|
dma_map_page(&nnt_device->pci_device->dev, current_pages[current_page],
|
||||||
|
0, PAGE_SIZE,
|
||||||
|
DMA_BIDIRECTIONAL);
|
||||||
|
/* Do we get a valid dma address ? */
|
||||||
|
if (dma_mapping_error(&nnt_device->pci_device->dev, nnt_device->dma_page.dma_address_list[current_page])) {
|
||||||
|
printk(KERN_ERR "Failed to get DMA addresses\n");
|
||||||
|
error_code = -EINVAL;
|
||||||
|
goto ReturnOnFinsihed;
|
||||||
|
}
|
||||||
|
|
||||||
|
page_info->page_address_array[current_page].dma_address =
|
||||||
|
nnt_device->dma_page.dma_address_list[current_page];
|
||||||
|
|
||||||
|
ReturnOnFinsihed:
|
||||||
|
return error_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int pin_user_pages_in_kernel_space(unsigned int total_pages, unsigned int total_pinned,
|
||||||
|
int* pinned_pages, struct nnt_device* nnt_device,
|
||||||
|
struct nnt_page_info* page_info, struct page*** current_pages)
|
||||||
|
{
|
||||||
|
unsigned long page_pointer_start = page_info->page_pointer_start;
|
||||||
|
int error_code = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* Remaining pages to pin. */
|
||||||
|
int remaining_pages = total_pages - total_pinned;
|
||||||
|
|
||||||
|
/* Point to the current offset. */
|
||||||
|
uint64_t current_page_pointer = page_pointer_start + (total_pinned * PAGE_SIZE);
|
||||||
|
|
||||||
|
/* Save the current page. */
|
||||||
|
*current_pages = nnt_device->dma_page.page_list + total_pinned;
|
||||||
|
|
||||||
|
/* Returns number of pages pinned - this may be fewer than the number requested
|
||||||
|
or -errno in case of error. */
|
||||||
|
*pinned_pages = get_user_pages_fast(current_page_pointer, remaining_pages,
|
||||||
|
FOLL_WRITE, *current_pages);
|
||||||
|
|
||||||
|
if (*pinned_pages < 1) {
|
||||||
|
kfree(nnt_device->dma_page.page_list);
|
||||||
|
error_code = -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate dma addresses structure. */
|
||||||
|
if ((nnt_device->dma_page.dma_address_list =
|
||||||
|
kcalloc(total_pages, sizeof(dma_addr_t), GFP_KERNEL)) == NULL) {
|
||||||
|
error_code = -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int pin_user_memory_in_kernel_space(unsigned int total_pages, struct nnt_device* nnt_device,
|
||||||
|
struct nnt_page_info* page_info)
|
||||||
|
{
|
||||||
|
unsigned int page_mapped_counter= 0;
|
||||||
|
unsigned int total_pinned = 0;
|
||||||
|
unsigned int pinned_pages;
|
||||||
|
struct page** current_pages = NULL;
|
||||||
|
int error_code = 0;
|
||||||
|
|
||||||
|
while (total_pinned < total_pages) {
|
||||||
|
/* Pinning user pages in kernel space. */
|
||||||
|
if((error_code =
|
||||||
|
pin_user_pages_in_kernel_space(total_pages, total_pinned,
|
||||||
|
&pinned_pages, nnt_device,
|
||||||
|
page_info, ¤t_pages)) != 0)
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
|
||||||
|
/* When the parameter 'inter_iommu' is on, we need to set up
|
||||||
|
a mapping on a pages in order to access the physical address. */
|
||||||
|
while(page_mapped_counter < pinned_pages)
|
||||||
|
{
|
||||||
|
if((error_code =
|
||||||
|
dma_mapping_page(total_pinned, page_mapped_counter,
|
||||||
|
nnt_device, current_pages,
|
||||||
|
page_info)) != 0)
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
|
||||||
|
page_mapped_counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance the memory that already pinned. */
|
||||||
|
total_pinned += pinned_pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There is a page not pinned in the kernel space ? */
|
||||||
|
if (total_pinned != total_pages) {
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int map_dma_pages(struct nnt_page_info* page_info, struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
unsigned int total_pages = page_info->total_pages;
|
||||||
|
int page_counter = 0;
|
||||||
|
int error_code = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* Check if we allow locking memory. */
|
||||||
|
if (!can_do_mlock()) {
|
||||||
|
error_code = -EPERM;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate the page list. */
|
||||||
|
if ((nnt_device->dma_page.page_list =
|
||||||
|
kcalloc(total_pages, sizeof(struct page *), GFP_KERNEL)) == NULL) {
|
||||||
|
error_code = -ENOMEM;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Go over the user memory buffer and pin user pages in kernel space */
|
||||||
|
if((error_code =
|
||||||
|
pin_user_memory_in_kernel_space(total_pages, nnt_device,
|
||||||
|
page_info)) != 0)
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
|
||||||
|
for (page_counter = 0;
|
||||||
|
page_counter < total_pages;
|
||||||
|
page_counter++) {
|
||||||
|
printk(KERN_INFO "Page address structure number: %d, device: %04x:%02x:%02x.%0x\n",
|
||||||
|
page_counter, pci_domain_nr(nnt_device->pci_device->bus),
|
||||||
|
nnt_device->pci_device->bus->number, PCI_SLOT(nnt_device->pci_device->devfn),
|
||||||
|
PCI_FUNC(nnt_device->pci_device->devfn));
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int release_dma_pages(struct nnt_page_info* page_info, struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
int page_counter;
|
||||||
|
|
||||||
|
if (nnt_device->dma_page.page_list == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deallocate the pages. */
|
||||||
|
for (page_counter = 0;
|
||||||
|
page_counter < page_info->total_pages;
|
||||||
|
page_counter++) {
|
||||||
|
/* DMA activity is finished. */
|
||||||
|
dma_unmap_page(&nnt_device->pci_device->dev, nnt_device->dma_page.dma_address_list[page_counter],
|
||||||
|
PAGE_SIZE, DMA_BIDIRECTIONAL);
|
||||||
|
|
||||||
|
/* Release the page list. */
|
||||||
|
set_page_dirty(nnt_device->dma_page.page_list[page_counter]);
|
||||||
|
put_page(nnt_device->dma_page.page_list[page_counter]);
|
||||||
|
nnt_device->dma_page.page_list[page_counter] = NULL;
|
||||||
|
nnt_device->dma_page.dma_address_list[page_counter] = 0;
|
||||||
|
|
||||||
|
printk(KERN_INFO "Page structure number: %d was released. device:%04x:%02x:%02x.%0x\n",
|
||||||
|
page_counter, pci_domain_nr(nnt_device->pci_device->bus),
|
||||||
|
nnt_device->pci_device->bus->number, PCI_SLOT(nnt_device->pci_device->devfn),
|
||||||
|
PCI_FUNC(nnt_device->pci_device->devfn));
|
||||||
|
}
|
||||||
|
|
||||||
|
// All the pages are clean.
|
||||||
|
nnt_device->dma_page.page_list = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
10
drivers/net/ethernet/mft/nnt_driver/nnt_dma.h
Normal file
10
drivers/net/ethernet/mft/nnt_driver/nnt_dma.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef NNT_DMA_H
|
||||||
|
#define NNT_DMA_H
|
||||||
|
|
||||||
|
#include "nnt_ioctl_defs.h"
|
||||||
|
#include "nnt_device_defs.h"
|
||||||
|
|
||||||
|
int map_dma_pages(struct nnt_page_info* page_info, struct nnt_device* nnt_device);
|
||||||
|
int release_dma_pages(struct nnt_page_info* page_info, struct nnt_device* nnt_device);
|
||||||
|
|
||||||
|
#endif
|
||||||
230
drivers/net/ethernet/mft/nnt_driver/nnt_ioctl.c
Normal file
230
drivers/net/ethernet/mft/nnt_driver/nnt_ioctl.c
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/highmem.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include "nnt_dma.h"
|
||||||
|
#include "nnt_defs.h"
|
||||||
|
#include "nnt_pci_conf_access.h"
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int mask = 0x7fff;
|
||||||
|
unsigned int msb_mask = 0x8000;
|
||||||
|
|
||||||
|
int dma_pages_ioctl(unsigned int command, void* user_buffer,
|
||||||
|
struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
struct nnt_page_info page_info;
|
||||||
|
int error_code = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* Copy the page info structure from user space. */
|
||||||
|
if (copy_from_user(&page_info, user_buffer,
|
||||||
|
sizeof(struct nnt_page_info))) {
|
||||||
|
error_code = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command == NNT_GET_DMA_PAGES) {
|
||||||
|
if (map_dma_pages(&page_info, nnt_device)) {
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the physical address to the user */
|
||||||
|
if (copy_to_user(user_buffer, &page_info,
|
||||||
|
sizeof(struct nnt_page_info)) != 0) {
|
||||||
|
error_code = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error_code =
|
||||||
|
release_dma_pages(&page_info, nnt_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int read_dword_ioctl(void* user_buffer, struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
struct nnt_read_dword_from_config_space read_from_cspace;
|
||||||
|
int error_code = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&read_from_cspace, user_buffer,
|
||||||
|
sizeof(struct nnt_read_dword_from_config_space)) != 0) {
|
||||||
|
error_code = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the dword. */
|
||||||
|
if (read_dword(&read_from_cspace, nnt_device)) {
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the data to the user space. */
|
||||||
|
if (copy_to_user(user_buffer, &read_from_cspace,
|
||||||
|
sizeof(struct nnt_read_dword_from_config_space)) != 0) {
|
||||||
|
error_code = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int get_nnt_device_parameters(struct nnt_device_parameters* nnt_parameters, struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
nnt_parameters->domain = pci_domain_nr(nnt_device->pci_device->bus);
|
||||||
|
nnt_parameters->bus = nnt_device->pci_device->bus->number;
|
||||||
|
nnt_parameters->slot = PCI_SLOT(nnt_device->pci_device->devfn);
|
||||||
|
nnt_parameters->function = PCI_FUNC(nnt_device->pci_device->devfn);
|
||||||
|
nnt_parameters->pci_memory_bar_address= nnt_device->memory_device.pci_memory_bar_address;
|
||||||
|
nnt_parameters->device = nnt_device->pci_device->device;
|
||||||
|
nnt_parameters->vendor = nnt_device->pci_device->vendor;
|
||||||
|
nnt_parameters->subsystem_device = nnt_device->pci_device->subsystem_device;
|
||||||
|
nnt_parameters->multifunction = nnt_device->pci_device->multifunction;
|
||||||
|
nnt_parameters->subsystem_vendor = nnt_device->pci_device->subsystem_vendor;
|
||||||
|
|
||||||
|
check_address_space_support(nnt_device);
|
||||||
|
if (nnt_device->pciconf_device.vendor_specific_capability &&
|
||||||
|
(nnt_device->pciconf_device.address_space.icmd || nnt_device->pciconf_device.address_space.cr_space ||
|
||||||
|
nnt_device->pciconf_device.address_space.semaphore)) {
|
||||||
|
nnt_parameters->vendor_specific_capability = nnt_device->pciconf_device.vendor_specific_capability;
|
||||||
|
nnt_parameters->vsec_capability_mask = nnt_device->pciconf_device.vsec_capability_mask;
|
||||||
|
} else {
|
||||||
|
nnt_parameters->vendor_specific_capability = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int pci_connectx_wa(struct nnt_connectx_wa* connectx_wa, struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
unsigned int slot_mask;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Is this slot exists ? */
|
||||||
|
if (nnt_device->memory_device.connectx_wa_slot_p1) {
|
||||||
|
printk(KERN_DEBUG "Slot exits for file %s, slot:0x%x\n",
|
||||||
|
nnt_device->device_name, nnt_device->memory_device.connectx_wa_slot_p1);
|
||||||
|
error = 0;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find first un(set) bit. and remember the slot */
|
||||||
|
nnt_device->memory_device.connectx_wa_slot_p1= ffs(~nnt_device->memory_device.connectx_wa_slot_p1);
|
||||||
|
if (nnt_device->memory_device.connectx_wa_slot_p1 == 0 ||
|
||||||
|
nnt_device->memory_device.connectx_wa_slot_p1 > NNT_CONNECTX_WA_SIZE) {
|
||||||
|
error = -ENOLCK;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot_mask = 1 << (nnt_device->memory_device.connectx_wa_slot_p1 - 1);
|
||||||
|
|
||||||
|
/* set the slot as taken */
|
||||||
|
nnt_device->memory_device.connectx_wa_slot_p1 |= slot_mask;
|
||||||
|
|
||||||
|
connectx_wa->connectx_wa_slot_p1 = nnt_device->memory_device.connectx_wa_slot_p1;
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int vpd_read(struct nnt_vpd* vpd, struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
unsigned long jiffies_time;
|
||||||
|
unsigned int address;
|
||||||
|
unsigned short data;
|
||||||
|
int is_bit_set = 0;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Sets F bit to zero and write VPD address. */
|
||||||
|
address = mask & vpd->offset;
|
||||||
|
error = pci_write_config_word(nnt_device->pci_device, nnt_device->vpd_capability_address + PCI_VPD_ADDR,
|
||||||
|
address);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, nnt_device->vpd_capability_address + PCI_VPD_ADDR,
|
||||||
|
address);
|
||||||
|
|
||||||
|
/* Wait for data until F bit is set with one */
|
||||||
|
jiffies_time = msecs_to_jiffies(vpd->timeout) + jiffies;
|
||||||
|
while (time_before(jiffies, jiffies_time)) {
|
||||||
|
error = pci_read_config_word(nnt_device->pci_device, nnt_device->vpd_capability_address + PCI_VPD_ADDR,
|
||||||
|
&data);
|
||||||
|
CHECK_PCI_READ_ERROR(error, nnt_device->vpd_capability_address + PCI_VPD_ADDR);
|
||||||
|
|
||||||
|
if (data & msb_mask) {
|
||||||
|
is_bit_set = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cond_resched();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_bit_set) {
|
||||||
|
printk(KERN_ERR "Failed to retrieve valid data\n");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read data */
|
||||||
|
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->vpd_capability_address + PCI_VPD_DATA,
|
||||||
|
&vpd->data);
|
||||||
|
CHECK_PCI_READ_ERROR(error, nnt_device->vpd_capability_address + PCI_VPD_DATA);
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int vpd_write(struct nnt_vpd* vpd, struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
unsigned long jiffies_time;
|
||||||
|
unsigned int address;
|
||||||
|
unsigned short data;
|
||||||
|
int is_bit_set = 0;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Write the user data */
|
||||||
|
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->vpd_capability_address + PCI_VPD_DATA,
|
||||||
|
vpd->data);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, nnt_device->vpd_capability_address + PCI_VPD_DATA,
|
||||||
|
vpd->data);
|
||||||
|
|
||||||
|
/* sets F bit to one and write VPD addr */
|
||||||
|
address = msb_mask | (mask & vpd->offset);
|
||||||
|
error = pci_write_config_word(nnt_device->pci_device, nnt_device->vpd_capability_address + PCI_VPD_ADDR,
|
||||||
|
address);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, nnt_device->vpd_capability_address + PCI_VPD_ADDR,
|
||||||
|
address);
|
||||||
|
|
||||||
|
/* wait for data until F bit is set with zero */
|
||||||
|
jiffies_time = msecs_to_jiffies(vpd->timeout) + jiffies;
|
||||||
|
while (time_before(jiffies, jiffies_time)) {
|
||||||
|
error = pci_read_config_word(nnt_device->pci_device, nnt_device->vpd_capability_address + PCI_VPD_ADDR,
|
||||||
|
&data);
|
||||||
|
CHECK_PCI_READ_ERROR(error, nnt_device->vpd_capability_address + PCI_VPD_ADDR);
|
||||||
|
|
||||||
|
if (!(data & msb_mask)) {
|
||||||
|
is_bit_set = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cond_resched();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_bit_set) {
|
||||||
|
printk(KERN_ERR "Failed to retrieve valid data\n");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
14
drivers/net/ethernet/mft/nnt_driver/nnt_ioctl.h
Normal file
14
drivers/net/ethernet/mft/nnt_driver/nnt_ioctl.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef NNT_IOCTL_H
|
||||||
|
#define NNT_IOCTL_H
|
||||||
|
|
||||||
|
#include "nnt_device_defs.h"
|
||||||
|
|
||||||
|
int dma_pages_ioctl(unsigned int command, void* user_buffer,
|
||||||
|
struct nnt_device* nnt_device);
|
||||||
|
int read_dword_ioctl(unsigned int command, void* user_buffer,
|
||||||
|
struct nnt_device* nnt_device);
|
||||||
|
int get_nnt_device_parameters(struct nnt_device_parameters* nnt_parameters, struct nnt_device* nnt_device);
|
||||||
|
int pci_connectx_wa(struct nnt_connectx_wa* connectx_wa, struct nnt_device* nnt_device);
|
||||||
|
int vpd_read(struct nnt_vpd* vpd, struct nnt_device* nnt_device);
|
||||||
|
int vpd_write(struct nnt_vpd* vpd, struct nnt_device* nnt_device);
|
||||||
|
#endif
|
||||||
83
drivers/net/ethernet/mft/nnt_driver/nnt_ioctl_defs.h
Normal file
83
drivers/net/ethernet/mft/nnt_driver/nnt_ioctl_defs.h
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
#ifndef NNT_IOCTL_DEFS_H
|
||||||
|
#define NNT_IOCTL_DEFS_H
|
||||||
|
|
||||||
|
#define NNT_MAGIC_NUMBER 0xD3
|
||||||
|
#define MAX_BUFFER_BLOCK_SIZE 256
|
||||||
|
#define NNT_MAX_PAGES_SIZE 8
|
||||||
|
#define NNT_CONNECTX_WA_SIZE 3
|
||||||
|
|
||||||
|
#define NNT_WRITE _IOW (NNT_MAGIC_NUMBER, 1, struct nnt_rw_operation)
|
||||||
|
#define NNT_READ _IOW (NNT_MAGIC_NUMBER, 2, struct nnt_rw_operation)
|
||||||
|
#define NNT_GET_DMA_PAGES _IOR (NNT_MAGIC_NUMBER, 3, struct nnt_page_info)
|
||||||
|
#define NNT_RELEASE_DMA_PAGES _IOR (NNT_MAGIC_NUMBER, 4, struct nnt_page_info)
|
||||||
|
#define NNT_READ_DWORD_FROM_CONFIG_SPACE _IOR (NNT_MAGIC_NUMBER, 5, struct nnt_read_dword_from_config_space)
|
||||||
|
#define NNT_GET_DEVICE_PARAMETERS _IOR (NNT_MAGIC_NUMBER, 6, struct nnt_device_parameters)
|
||||||
|
#define NNT_INIT _IOR (NNT_MAGIC_NUMBER, 7, struct nnt_pciconf_init)
|
||||||
|
#define NNT_PCI_CONNECTX_WA _IOR (NNT_MAGIC_NUMBER, 8, u_int32_t)
|
||||||
|
#define NNT_VPD_READ _IOR (NNT_MAGIC_NUMBER, 9, struct nnt_vpd)
|
||||||
|
#define NNT_VPD_WRITE _IOW (NNT_MAGIC_NUMBER, 10, struct nnt_vpd)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct nnt_vpd {
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned int timeout;
|
||||||
|
unsigned int data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct nnt_pciconf_init {
|
||||||
|
unsigned int address_register;
|
||||||
|
unsigned int address_data_register;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct nnt_device_parameters {
|
||||||
|
unsigned int domain;
|
||||||
|
unsigned int bus;
|
||||||
|
unsigned int slot;
|
||||||
|
unsigned int function;
|
||||||
|
unsigned int pci_memory_bar_address;
|
||||||
|
unsigned int device;
|
||||||
|
unsigned int vendor;
|
||||||
|
unsigned int subsystem_device;
|
||||||
|
unsigned int subsystem_vendor;
|
||||||
|
unsigned int multifunction;
|
||||||
|
unsigned int vendor_specific_capability;
|
||||||
|
unsigned int vsec_capability_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct nnt_page_address {
|
||||||
|
u_int64_t dma_address;
|
||||||
|
u_int64_t virtual_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct nnt_page_info {
|
||||||
|
unsigned int total_pages;
|
||||||
|
unsigned long page_pointer_start;
|
||||||
|
struct nnt_page_address page_address_array[NNT_MAX_PAGES_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct nnt_read_dword_from_config_space {
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned int data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct nnt_rw_operation {
|
||||||
|
unsigned int address_space;
|
||||||
|
unsigned int offset;
|
||||||
|
int size;
|
||||||
|
unsigned int data[MAX_BUFFER_BLOCK_SIZE / 4];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct nnt_connectx_wa {
|
||||||
|
unsigned int connectx_wa_slot_p1;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
295
drivers/net/ethernet/mft/nnt_driver/nnt_linux_driver_main.c
Normal file
295
drivers/net/ethernet/mft/nnt_driver/nnt_linux_driver_main.c
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
* BSD-3-Clause
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. 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.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/semaphore.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include "nnt_defs.h"
|
||||||
|
#include "nnt_device.h"
|
||||||
|
#include "nnt_ioctl.h"
|
||||||
|
#include "nnt_ioctl_defs.h"
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Itay Avraham <itayavr@nvidia.com>");
|
||||||
|
MODULE_DESCRIPTION("NNT Linux driver (NVIDIA® networking tools driver)");
|
||||||
|
|
||||||
|
/* Passing MFT flag argument */
|
||||||
|
int mft_package = 0;
|
||||||
|
|
||||||
|
/* Create the file in sysfs. */
|
||||||
|
module_param(mft_package, int, S_IRUSR);
|
||||||
|
|
||||||
|
struct driver_info nnt_driver_info;
|
||||||
|
|
||||||
|
static long nnt_ioctl(struct file* file, unsigned int command, unsigned long argument)
|
||||||
|
{
|
||||||
|
void* user_buffer = (void*)argument;
|
||||||
|
struct nnt_device* nnt_device = NULL;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* By convention, any user gets read access
|
||||||
|
* and is allowed to use the device.
|
||||||
|
* Commands with no direction are administration
|
||||||
|
* commands, and you need write permission for this */
|
||||||
|
|
||||||
|
if (_IOC_DIR(command) == _IOC_NONE)
|
||||||
|
{
|
||||||
|
if (!(file->f_mode & FMODE_WRITE))
|
||||||
|
{
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(file->f_mode & FMODE_READ))
|
||||||
|
{
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error = mutex_lock_nnt(file);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Get the nnt device structure */
|
||||||
|
error = get_nnt_device(file, &nnt_device);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case NNT_GET_DMA_PAGES:
|
||||||
|
case NNT_RELEASE_DMA_PAGES:
|
||||||
|
error = dma_pages_ioctl(command, user_buffer, nnt_device);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NNT_READ_DWORD_FROM_CONFIG_SPACE:
|
||||||
|
error = read_dword_ioctl(command, user_buffer, nnt_device);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NNT_WRITE:
|
||||||
|
case NNT_READ:
|
||||||
|
{
|
||||||
|
struct nnt_rw_operation rw_operation;
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&rw_operation, user_buffer, sizeof(struct nnt_rw_operation)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case NNT_WRITE:
|
||||||
|
nnt_device->access.write(nnt_device, &rw_operation);
|
||||||
|
break;
|
||||||
|
case NNT_READ:
|
||||||
|
nnt_device->access.read(nnt_device, &rw_operation);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the data to the user space. */
|
||||||
|
if (copy_to_user(user_buffer, &rw_operation, sizeof(struct nnt_rw_operation)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NNT_GET_DEVICE_PARAMETERS:
|
||||||
|
{
|
||||||
|
struct nnt_device_parameters nnt_parameters;
|
||||||
|
|
||||||
|
error = get_nnt_device_parameters(&nnt_parameters, nnt_device);
|
||||||
|
|
||||||
|
/* Copy the data to the user space. */
|
||||||
|
if (copy_to_user(user_buffer, &nn_parameters, sizeof(struct device_parameters)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NNT_INIT:
|
||||||
|
{
|
||||||
|
struct nnt_pciconf_init init;
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&init, user_buffer, sizeof(struct nnt_pciconf_init)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
error = nnt_device->access.init(&init, nnt_device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NNT_PCI_CONNECTX_WA:
|
||||||
|
{
|
||||||
|
struct nnt_connectx_wa connectx_wa;
|
||||||
|
error = pci_connectx_wa(&connectx_wa, nnt_device);
|
||||||
|
|
||||||
|
/* Copy the data to the user space. */
|
||||||
|
if (copy_to_user(user_buffer, &connectx_wa, sizeof(struct nnt_connectx_wa)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NNT_VPD_READ:
|
||||||
|
case NNT_VPD_WRITE:
|
||||||
|
{
|
||||||
|
int vpd_default_timeout = 2000;
|
||||||
|
struct nnt_vpd vpd;
|
||||||
|
|
||||||
|
if (!nnt_device->vpd_capability_address)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "Device %s not support Vital Product Data\n", nnt_device->device_name);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the request from user space. */
|
||||||
|
if (copy_from_user(&vpd, user_buffer, sizeof(struct nnt_vpd)) != 0)
|
||||||
|
{
|
||||||
|
error = -EFAULT;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vpd.timeout)
|
||||||
|
{
|
||||||
|
vpd.timeout = vpd_default_timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case NNT_VPD_READ:
|
||||||
|
error = vpd_read(command, &vpd, nnt_device);
|
||||||
|
break;
|
||||||
|
case NNT_VPD_WRITE:
|
||||||
|
error = vpd_write(command, &vpd, nnt_device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
printk(KERN_ERR "ioctl not implemented, command id: %x\n", command);
|
||||||
|
error = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
mutex_unlock_nnt(file);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nnt_open(struct inode* inode, struct file* file)
|
||||||
|
{
|
||||||
|
if (file->private_data)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return set_private_data(inode, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file_operations fop = {.unlocked_ioctl = ioctl, .open = nnt_open, .owner = THIS_MODULE};
|
||||||
|
|
||||||
|
int with_unknown = 0;
|
||||||
|
|
||||||
|
module_param(with_unknown, int, S_IRUSR | S_IWUSR);
|
||||||
|
|
||||||
|
static int __init nnt_init_module(void)
|
||||||
|
{
|
||||||
|
int first_minor_number = 0;
|
||||||
|
int error = 0;
|
||||||
|
dev_t device_numbers;
|
||||||
|
|
||||||
|
/* Get the amount of the Nvidia devices. */
|
||||||
|
if ((nnt_driver_info.contiguous_device_numbers = get_amount_of_nvidia_devices()) == 0)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "No devices found\n");
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate char driver region and assign major number */
|
||||||
|
if ((error = alloc_chrdev_region(&device_numbers, first_minor_number, nnt_driver_info.contiguous_device_numbers,
|
||||||
|
NNT_DRIVER_NAME)) != 0)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "failed to allocate chrdev_region\n");
|
||||||
|
goto CharDeviceAllocated;
|
||||||
|
}
|
||||||
|
|
||||||
|
nnt_driver_info.driver_major_number = MAJOR(device_numbers);
|
||||||
|
|
||||||
|
/* create sysfs class. */
|
||||||
|
if ((nnt_driver_info.class_driver = class_create(THIS_MODULE, NNT_CLASS_NAME)) == NULL)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "Class creation failed\n");
|
||||||
|
error = -EFAULT;
|
||||||
|
goto DriverClassAllocated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create device files for MSTflint and MFT */
|
||||||
|
error = create_nnt_devices(nnt_driver_info.contiguous_device_numbers, device_numbers, mft_package,
|
||||||
|
NNT_MELLANOX_PCI_VENDOR, &fop) ||
|
||||||
|
create_nnt_devices(nnt_driver_info.contiguous_device_numbers, device_numbers, mft_package,
|
||||||
|
NNT_NVIDIA_PCI_VENDOR, &fop);
|
||||||
|
if ((error) == 0)
|
||||||
|
{
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
DriverClassAllocated:
|
||||||
|
destroy_nnt_devices();
|
||||||
|
class_destroy(nnt_driver_info.class_driver);
|
||||||
|
|
||||||
|
CharDeviceAllocated:
|
||||||
|
unregister_chrdev_region(nnt_driver_info.driver_major_number, nnt_driver_info.contiguous_device_numbers);
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit nnt_cleanup_module(void)
|
||||||
|
{
|
||||||
|
destroy_nnt_devices();
|
||||||
|
class_destroy(nnt_driver_info.class_driver);
|
||||||
|
unregister_chrdev_region(nnt_driver_info.driver_major_number, nnt_driver_info.contiguous_device_numbers);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(nnt_init_module);
|
||||||
|
module_exit(nnt_cleanup_module);
|
||||||
46
drivers/net/ethernet/mft/nnt_driver/nnt_memory_access.c
Normal file
46
drivers/net/ethernet/mft/nnt_driver/nnt_memory_access.c
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#include "nnt_device_defs.h"
|
||||||
|
#include "nnt_pci_conf_access_defs.h"
|
||||||
|
#include "nnt_pci_conf_access.h"
|
||||||
|
#include "nnt_defs.h"
|
||||||
|
|
||||||
|
|
||||||
|
int write_memory(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation)
|
||||||
|
{
|
||||||
|
/* Endianness conversion. */
|
||||||
|
cpu_to_be32s(write_operation->data);
|
||||||
|
write_operation->data[0] = cpu_to_le32(write_operation->data[0]);
|
||||||
|
|
||||||
|
/* Write to the hardware memory address. */
|
||||||
|
iowrite32(write_operation->data[0], nnt_device->memory_device.hardware_memory_address + write_operation->offset);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int read_memory(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation)
|
||||||
|
{
|
||||||
|
/* Read from the hardware memory address. */
|
||||||
|
read_operation->data[0] = ioread32(nnt_device->memory_device.hardware_memory_address + read_operation->offset);
|
||||||
|
|
||||||
|
/* Endianness conversion */
|
||||||
|
be32_to_cpus(read_operation->data);
|
||||||
|
read_operation->data[0] = cpu_to_le32(read_operation->data[0]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int init_memory(struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
nnt_device->memory_device.connectx_wa_slot_p1 = 0;
|
||||||
|
nnt_device->memory_device.hardware_memory_address =
|
||||||
|
ioremap(pci_resource_start(nnt_device->pci_device, nnt_device->memory_device.pci_memory_bar_address),
|
||||||
|
NNT_MEMORY_SIZE);
|
||||||
|
|
||||||
|
if (nnt_device->memory_device.hardware_memory_address <= 0) {
|
||||||
|
printk(KERN_ERR "could not map device memory\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
7
drivers/net/ethernet/mft/nnt_driver/nnt_memory_access.h
Normal file
7
drivers/net/ethernet/mft/nnt_driver/nnt_memory_access.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#ifndef NNT_MEMORY_ACCESS_H
|
||||||
|
#define NNT_MEMORY_ACCESS_H
|
||||||
|
|
||||||
|
int read_memory(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation);
|
||||||
|
int write_memory(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation);
|
||||||
|
int init_memory(struct nnt_device* nnt_device);
|
||||||
|
#endif
|
||||||
430
drivers/net/ethernet/mft/nnt_driver/nnt_pci_conf_access.c
Normal file
430
drivers/net/ethernet/mft/nnt_driver/nnt_pci_conf_access.c
Normal file
@@ -0,0 +1,430 @@
|
|||||||
|
#include "nnt_device_defs.h"
|
||||||
|
#include "nnt_pci_conf_access_defs.h"
|
||||||
|
#include "nnt_pci_conf_access.h"
|
||||||
|
#include "nnt_defs.h"
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
|
|
||||||
|
int clear_vsec_semaphore(struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
/* Clear the semaphore. */
|
||||||
|
int error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.semaphore_offset,
|
||||||
|
0);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.semaphore_offset,
|
||||||
|
0)
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int get_semaphore_ticket(struct nnt_device* nnt_device, unsigned int* lock_value,
|
||||||
|
unsigned int* counter)
|
||||||
|
{
|
||||||
|
unsigned int counter_offset = nnt_device->pciconf_device.vendor_specific_capability + PCI_COUNTER_OFFSET;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Read ticket. */
|
||||||
|
error = pci_read_config_dword(nnt_device->pci_device, counter_offset,
|
||||||
|
counter);
|
||||||
|
CHECK_PCI_READ_ERROR(error, counter_offset);
|
||||||
|
|
||||||
|
/* Write to semaphore ticket. */
|
||||||
|
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.semaphore_offset,
|
||||||
|
*counter);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.semaphore_offset,
|
||||||
|
*counter);
|
||||||
|
|
||||||
|
/* Read back semaphore to make sure the
|
||||||
|
* ticket is equal to semphore */
|
||||||
|
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.semaphore_offset,
|
||||||
|
lock_value);
|
||||||
|
CHECK_PCI_READ_ERROR(error, nnt_device->pciconf_device.semaphore_offset);
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int lock_vsec_semaphore(struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
unsigned int lock_value = -1;
|
||||||
|
unsigned int counter = 0;
|
||||||
|
unsigned int retries = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (retries > SEMAPHORE_MAX_RETRIES) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the semaphore, until we will get 0. */
|
||||||
|
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.semaphore_offset,
|
||||||
|
&lock_value);
|
||||||
|
|
||||||
|
CHECK_PCI_READ_ERROR(error, nnt_device->pciconf_device.semaphore_offset);
|
||||||
|
|
||||||
|
/* Is semaphore taken ? */
|
||||||
|
if (lock_value) {
|
||||||
|
retries++;
|
||||||
|
udelay(1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get semaphore ticket */
|
||||||
|
error = get_semaphore_ticket(nnt_device, &lock_value,
|
||||||
|
&counter);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
} while (counter != lock_value);
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int read_dword(struct nnt_read_dword_from_config_space* read_from_cspace, struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Take semaphore. */
|
||||||
|
error = lock_vsec_semaphore(nnt_device);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Read dword from config space. */
|
||||||
|
error = pci_read_config_dword(nnt_device->pci_device, read_from_cspace->offset,
|
||||||
|
&read_from_cspace->data);
|
||||||
|
CHECK_PCI_READ_ERROR(error, read_from_cspace->offset);
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
/* Clear semaphore. */
|
||||||
|
clear_vsec_semaphore(nnt_device);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int wait_on_flag(struct nnt_device* nnt_device, u8 expected_val)
|
||||||
|
{
|
||||||
|
unsigned int flag = 0;
|
||||||
|
int retries = 0;
|
||||||
|
int error = -1;
|
||||||
|
|
||||||
|
for (retries = 0; retries < IFC_MAX_RETRIES; retries++) {
|
||||||
|
/* Read the flag. */
|
||||||
|
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_offset,
|
||||||
|
&flag);
|
||||||
|
CHECK_PCI_READ_ERROR(error, nnt_device->pciconf_device.address_offset);
|
||||||
|
|
||||||
|
flag = EXTRACT(flag, PCI_FLAG_BIT_OFFSET,
|
||||||
|
1);
|
||||||
|
if (flag == expected_val) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int set_address_space(struct nnt_device* nnt_device, unsigned int address_space)
|
||||||
|
{
|
||||||
|
unsigned int control_offset = nnt_device->pciconf_device.vendor_specific_capability + PCI_CONTROL_OFFSET;
|
||||||
|
unsigned int value = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Read value from control offset. */
|
||||||
|
error = pci_read_config_dword(nnt_device->pci_device, control_offset,
|
||||||
|
&value);
|
||||||
|
CHECK_PCI_READ_ERROR(error, control_offset);
|
||||||
|
|
||||||
|
/* Set the bit address_space indication and write it back. */
|
||||||
|
value = MERGE(value, address_space,
|
||||||
|
PCI_SPACE_BIT_OFFSET, PCI_SPACE_BIT_LENGTH);
|
||||||
|
error = pci_write_config_dword(nnt_device->pci_device, control_offset,
|
||||||
|
value);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, control_offset,
|
||||||
|
value);
|
||||||
|
|
||||||
|
/* Read status and make sure address_space is supported. */
|
||||||
|
error = pci_read_config_dword(nnt_device->pci_device, control_offset,
|
||||||
|
&value);
|
||||||
|
CHECK_PCI_READ_ERROR(error, control_offset);
|
||||||
|
|
||||||
|
if (EXTRACT(value, PCI_STATUS_BIT_OFFSET,
|
||||||
|
PCI_STATUS_BIT_LEN) == 0) {
|
||||||
|
error = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int check_address_space_support(struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
if ((!nnt_device->pciconf_device.vendor_specific_capability) || (!nnt_device->pci_device)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get semaphore ticket */
|
||||||
|
error = lock_vsec_semaphore(nnt_device);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Is ICMD address space supported ?*/
|
||||||
|
if(set_address_space(nnt_device, ADDRESS_SPACE_ICMD) == 0) {
|
||||||
|
nnt_device->pciconf_device.address_space.icmd = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is CR Space address space supported ?*/
|
||||||
|
if(set_address_space(nnt_device, ADDRESS_SPACE_CR_SPACE) == 0) {
|
||||||
|
nnt_device->pciconf_device.address_space.cr_space = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is semaphore address space supported ?*/
|
||||||
|
if(set_address_space(nnt_device, ADDRESS_SPACE_SEMAPHORE) == 0) {
|
||||||
|
nnt_device->pciconf_device.address_space.semaphore = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
/* Clear semaphore. */
|
||||||
|
clear_vsec_semaphore(nnt_device);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int set_rw_address(unsigned int* offset, unsigned int rw)
|
||||||
|
{
|
||||||
|
u32 address = *offset;
|
||||||
|
|
||||||
|
/* Last 2 bits must be zero as we only allow 30 bits addresses. */
|
||||||
|
if (EXTRACT(address, 30,
|
||||||
|
2)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
address = MERGE(address, rw,
|
||||||
|
PCI_FLAG_BIT_OFFSET, 1);
|
||||||
|
*offset = address;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int read(struct nnt_device* nnt_device, unsigned int offset,
|
||||||
|
unsigned int* data)
|
||||||
|
{
|
||||||
|
int error = set_rw_address(&offset, READ_OPERATION);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Write address. */
|
||||||
|
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_offset,
|
||||||
|
offset);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.address_offset,
|
||||||
|
offset);
|
||||||
|
|
||||||
|
error = wait_on_flag(nnt_device, 1);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Read data. */
|
||||||
|
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.data_offset,
|
||||||
|
data);
|
||||||
|
CHECK_PCI_READ_ERROR(error, nnt_device->pciconf_device.data_offset);
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int read_pciconf(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation)
|
||||||
|
{
|
||||||
|
int counter = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Lock semaphore. */
|
||||||
|
error = lock_vsec_semaphore(nnt_device);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Is CR Space address space supported ?*/
|
||||||
|
error = set_address_space(nnt_device, read_operation->address_space);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
for (counter = 0; counter < read_operation->size; counter += 4) {
|
||||||
|
if (read(nnt_device, read_operation->offset + counter,
|
||||||
|
&read_operation->data[counter >> 2])) {
|
||||||
|
error = counter;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
/* Clear semaphore. */
|
||||||
|
clear_vsec_semaphore(nnt_device);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int write(struct nnt_device* nnt_device, unsigned int offset,
|
||||||
|
unsigned int data)
|
||||||
|
{
|
||||||
|
int error = set_rw_address(&offset, WRITE_OPERATION);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Write data. */
|
||||||
|
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.data_offset,
|
||||||
|
data);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error,nnt_device->pciconf_device.data_offset,
|
||||||
|
data);
|
||||||
|
|
||||||
|
/* Write address. */
|
||||||
|
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_offset,
|
||||||
|
offset);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.address_offset,
|
||||||
|
offset);
|
||||||
|
|
||||||
|
error = wait_on_flag(nnt_device, 0);
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int write_pciconf(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation)
|
||||||
|
{
|
||||||
|
int counter = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Lock semaphore. */
|
||||||
|
error = lock_vsec_semaphore(nnt_device);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
/* Is CR Space address space supported ?*/
|
||||||
|
error = set_address_space(nnt_device, write_operation->address_space);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
for (counter = 0; counter < write_operation->size; counter += 4) {
|
||||||
|
if (write(nnt_device, write_operation->offset + counter,
|
||||||
|
write_operation->data[counter >> 2])) {
|
||||||
|
error = counter;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
/* Clear semaphore. */
|
||||||
|
clear_vsec_semaphore(nnt_device);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int address_space_to_capability(u_int16_t address_space)
|
||||||
|
{
|
||||||
|
switch (address_space) {
|
||||||
|
case NNT_SPACE_ICMD:
|
||||||
|
return NNT_VSEC_ICMD_SPACE_SUPPORTED;
|
||||||
|
case NNT_SPACE_CR_SPACE:
|
||||||
|
return NNT_VSEC_CRSPACE_SPACE_SUPPORTED;
|
||||||
|
case NNT_SPACE_ALL_ICMD:
|
||||||
|
return NNT_VSEC_ALL_ICMD_SPACE_SUPPORTED;
|
||||||
|
case NNT_SPACE_NODNIC_INIT_SEG:
|
||||||
|
return NNT_VSEC_NODNIC_INIT_SEG_SPACE_SUPPORTED;
|
||||||
|
case NNT_SPACE_EXPANSION_ROM:
|
||||||
|
return NNT_VSEC_EXPANSION_ROM_SPACE_SUPPORTED;
|
||||||
|
case NNT_SPACE_ND_CR_SPACE:
|
||||||
|
return NNT_VSEC_ND_CRSPACE_SPACE_SUPPORTED;
|
||||||
|
case NNT_SPACE_SCAN_CR_SPACE:
|
||||||
|
return NNT_VSEC_SCAN_CRSPACE_SPACE_SUPPORTED;
|
||||||
|
case NNT_SPACE_GLOBAL_SEMAPHORE:
|
||||||
|
return NNT_VSEC_GLOBAL_SEMAPHORE_SPACE_SUPPORTED;
|
||||||
|
case NNT_SPACE_MAC:
|
||||||
|
return NNT_VSEC_MAC_SPACE_SUPPORTED;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int get_space_support_status(struct nnt_device* nnt_device, u_int16_t address_space)
|
||||||
|
{
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
if(set_address_space(nnt_device, address_space) == 0) {
|
||||||
|
status = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nnt_device->pciconf_device.vsec_capability_mask |=
|
||||||
|
(status << address_space_to_capability(address_space));
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int init_vsec_capability_mask(struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
/* Lock semaphore. */
|
||||||
|
error = lock_vsec_semaphore(nnt_device);
|
||||||
|
CHECK_ERROR(error);
|
||||||
|
|
||||||
|
get_space_support_status(nnt_device, NNT_SPACE_ICMD);
|
||||||
|
get_space_support_status(nnt_device, NNT_SPACE_CR_SPACE);
|
||||||
|
get_space_support_status(nnt_device, NNT_SPACE_ALL_ICMD);
|
||||||
|
get_space_support_status(nnt_device, NNT_SPACE_NODNIC_INIT_SEG);
|
||||||
|
get_space_support_status(nnt_device, NNT_SPACE_EXPANSION_ROM);
|
||||||
|
get_space_support_status(nnt_device, NNT_SPACE_ND_CR_SPACE);
|
||||||
|
get_space_support_status(nnt_device, NNT_SPACE_SCAN_CR_SPACE);
|
||||||
|
get_space_support_status(nnt_device, NNT_SPACE_GLOBAL_SEMAPHORE);
|
||||||
|
get_space_support_status(nnt_device, NNT_SPACE_MAC);
|
||||||
|
nnt_device->pciconf_device.vsec_capability_mask |= (1 << NNT_VSEC_INITIALIZED);
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
/* Clear semaphore. */
|
||||||
|
clear_vsec_semaphore(nnt_device);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void check_vsec_minimum_support(struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
if ((nnt_device->pciconf_device.vsec_capability_mask & (1 << NNT_VSEC_INITIALIZED)) &&
|
||||||
|
(nnt_device->pciconf_device.vsec_capability_mask & (1 << NNT_VSEC_ICMD_SPACE_SUPPORTED)) &&
|
||||||
|
(nnt_device->pciconf_device.vsec_capability_mask & (1 << NNT_VSEC_CRSPACE_SPACE_SUPPORTED)) &&
|
||||||
|
(nnt_device->pciconf_device.vsec_capability_mask & (1 << NNT_VSEC_GLOBAL_SEMAPHORE_SPACE_SUPPORTED))) {
|
||||||
|
|
||||||
|
nnt_device->pciconf_device.vsec_fully_supported = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int init_pciconf(struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
nnt_device->pciconf_device.semaphore_offset =
|
||||||
|
nnt_device->pciconf_device.vendor_specific_capability + PCI_SEMAPHORE_OFFSET;
|
||||||
|
nnt_device->pciconf_device.data_offset =
|
||||||
|
nnt_device->pciconf_device.vendor_specific_capability + PCI_DATA_OFFSET;
|
||||||
|
nnt_device->pciconf_device.address_offset =
|
||||||
|
nnt_device->pciconf_device.vendor_specific_capability + PCI_ADDRESS_OFFSET;
|
||||||
|
|
||||||
|
error = init_vsec_capability_mask(nnt_device);
|
||||||
|
check_vsec_minimum_support(nnt_device);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
14
drivers/net/ethernet/mft/nnt_driver/nnt_pci_conf_access.h
Normal file
14
drivers/net/ethernet/mft/nnt_driver/nnt_pci_conf_access.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef NNT_PCICONF_H
|
||||||
|
#define NNT_PCICONF_H
|
||||||
|
|
||||||
|
#include "nnt_device_defs.h"
|
||||||
|
#include "nnt_ioctl_defs.h"
|
||||||
|
|
||||||
|
|
||||||
|
int read_pciconf(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation);
|
||||||
|
int write_pciconf(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation);
|
||||||
|
int init_pciconf(struct nnt_device* nnt_device);
|
||||||
|
int read_dword(struct nnt_read_dword_from_config_space* read_from_cspace, struct nnt_device* nnt_device);
|
||||||
|
int check_address_space_support(struct nnt_device* nnt_device);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#ifndef NNT_PCICONF_DEFS_H
|
||||||
|
#define NNT_PCICONF_DEFS_H
|
||||||
|
|
||||||
|
#define ADDRESS_SPACE_CR_SPACE 0x2
|
||||||
|
#define ADDRESS_SPACE_ICMD 0x3
|
||||||
|
#define ADDRESS_SPACE_SEMAPHORE 0xa
|
||||||
|
|
||||||
|
#define PCI_CONTROL_OFFSET 0x04
|
||||||
|
#define PCI_COUNTER_OFFSET 0x08
|
||||||
|
|
||||||
|
#define SEMAPHORE_MAX_RETRIES 0x1000
|
||||||
|
|
||||||
|
#define PCI_SPACE_BIT_OFFSET 0
|
||||||
|
#define PCI_SPACE_BIT_LENGTH 16
|
||||||
|
#define PCI_STATUS_BIT_OFFSET 29
|
||||||
|
#define PCI_STATUS_BIT_LEN 3
|
||||||
|
#define PCI_FLAG_BIT_OFFSET 31
|
||||||
|
|
||||||
|
#define READ_OPERATION 0
|
||||||
|
#define WRITE_OPERATION 1
|
||||||
|
|
||||||
|
#define IFC_MAX_RETRIES 0x10000
|
||||||
|
#define SEMAPHORE_MAX_RETRIES 0x1000
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum nnt_space_address {
|
||||||
|
NNT_SPACE_ICMD = 0x1,
|
||||||
|
NNT_SPACE_CR_SPACE = 0x2,
|
||||||
|
NNT_SPACE_ALL_ICMD = 0x3,
|
||||||
|
NNT_SPACE_NODNIC_INIT_SEG = 0x4,
|
||||||
|
NNT_SPACE_EXPANSION_ROM = 0x5,
|
||||||
|
NNT_SPACE_ND_CR_SPACE = 0x6,
|
||||||
|
NNT_SPACE_SCAN_CR_SPACE = 0x7,
|
||||||
|
NNT_SPACE_GLOBAL_SEMAPHORE = 0xa,
|
||||||
|
NNT_SPACE_MAC = 0xf
|
||||||
|
} NNT_SPACE_ADDRESS;
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum nnt_vsec_capability {
|
||||||
|
NNT_VSEC_INITIALIZED = 0,
|
||||||
|
NNT_VSEC_ICMD_SPACE_SUPPORTED,
|
||||||
|
NNT_VSEC_CRSPACE_SPACE_SUPPORTED,
|
||||||
|
NNT_VSEC_ALL_ICMD_SPACE_SUPPORTED,
|
||||||
|
NNT_VSEC_NODNIC_INIT_SEG_SPACE_SUPPORTED,
|
||||||
|
NNT_VSEC_EXPANSION_ROM_SPACE_SUPPORTED,
|
||||||
|
NNT_VSEC_ND_CRSPACE_SPACE_SUPPORTED,
|
||||||
|
NNT_VSEC_SCAN_CRSPACE_SPACE_SUPPORTED,
|
||||||
|
NNT_VSEC_GLOBAL_SEMAPHORE_SPACE_SUPPORTED,
|
||||||
|
NNT_VSEC_MAC_SPACE_SUPPORTED,
|
||||||
|
} NNT_VSEC_CAPABILITY;
|
||||||
|
|
||||||
|
|
||||||
|
// BIT Slicing macros
|
||||||
|
#define ONES32(size) ((size)?(0xffffffff>>(32-(size))):0)
|
||||||
|
#define MASK32(offset, size) ( ONES32(size)<<(offset))
|
||||||
|
|
||||||
|
#define EXTRACT_C(source, offset, size) ((((unsigned int)(source))>>(offset)) & ONES32(size))
|
||||||
|
#define EXTRACT(src, start, len) (((len) == 32)?(src):EXTRACT_C(src, start, len))
|
||||||
|
|
||||||
|
#define MERGE_C(rsrc1, rsrc2, start, len) ((((rsrc2)<<(start)) & (MASK32((start), (len)))) | ((rsrc1) & (~MASK32((start), (len)))))
|
||||||
|
#define MERGE(rsrc1, rsrc2, start, len) (((len) == 32)?(rsrc2):MERGE_C(rsrc1, rsrc2, start, len))
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
#include "nnt_device_defs.h"
|
||||||
|
#include "nnt_pci_conf_access_no_vsec.h"
|
||||||
|
#include "nnt_defs.h"
|
||||||
|
|
||||||
|
|
||||||
|
int read_no_vsec(struct nnt_device* nnt_device, unsigned int offset,
|
||||||
|
unsigned int* data)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
if (nnt_device->wo_address) {
|
||||||
|
offset |= 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the wanted address to address register. */
|
||||||
|
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_register,
|
||||||
|
offset);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.address_register,
|
||||||
|
offset);
|
||||||
|
|
||||||
|
/* Read the result from data register */
|
||||||
|
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.data_register,
|
||||||
|
data);
|
||||||
|
CHECK_PCI_READ_ERROR(error, nnt_device->pciconf_device.data_register);
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int read_pciconf_no_vsec(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation)
|
||||||
|
{
|
||||||
|
int counter = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
for (counter = 0; counter < read_operation->size; counter += 4) {
|
||||||
|
if (read_no_vsec(nnt_device, read_operation->offset + counter,
|
||||||
|
&read_operation->data[counter >> 2])) {
|
||||||
|
error = counter;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int write_no_vsec(struct nnt_device* nnt_device, unsigned int offset,
|
||||||
|
unsigned int data)
|
||||||
|
{
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
if (nnt_device->wo_address) {
|
||||||
|
/* write the data to the data register. */
|
||||||
|
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.data_register,
|
||||||
|
data);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.data_register,
|
||||||
|
data);
|
||||||
|
/* Write the destination address to address register. */
|
||||||
|
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_register,
|
||||||
|
offset);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.address_register,
|
||||||
|
offset);
|
||||||
|
} else {
|
||||||
|
/* Write the destination address to address register. */
|
||||||
|
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_register,
|
||||||
|
offset);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.address_register,
|
||||||
|
offset);
|
||||||
|
|
||||||
|
/* write the data to the data register. */
|
||||||
|
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.data_register,
|
||||||
|
data);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.data_register,
|
||||||
|
data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int write_pciconf_no_vsec(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation)
|
||||||
|
{
|
||||||
|
int counter = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
for (counter = 0; counter < write_operation->size; counter += 4) {
|
||||||
|
if (write_no_vsec(nnt_device, write_operation->offset + counter,
|
||||||
|
write_operation->data[counter >> 2])) {
|
||||||
|
error = counter;
|
||||||
|
goto ReturnOnFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int is_wo_gw(struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
unsigned int data = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
error = pci_write_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_register,
|
||||||
|
NNT_DEVICE_ID_OFFSET);
|
||||||
|
CHECK_PCI_WRITE_ERROR(error, nnt_device->pciconf_device.address_register,
|
||||||
|
NNT_DEVICE_ID_OFFSET);
|
||||||
|
|
||||||
|
/* Read the result from data register */
|
||||||
|
error = pci_read_config_dword(nnt_device->pci_device, nnt_device->pciconf_device.address_register,
|
||||||
|
&data);
|
||||||
|
CHECK_PCI_READ_ERROR(error, nnt_device->pciconf_device.address_register);
|
||||||
|
|
||||||
|
if (data == NNT_WO_REG_ADDR_DATA) {
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnOnFinished:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int init_pciconf_no_vsec(struct nnt_device* nnt_device)
|
||||||
|
{
|
||||||
|
nnt_device->pciconf_device.address_register = NNT_CONF_ADDRES_REGISETER;
|
||||||
|
nnt_device->pciconf_device.data_register = NNT_CONF_DATA_REGISTER;
|
||||||
|
nnt_device->wo_address = is_wo_gw(nnt_device);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef NNT_PCICONF_NO_VSEC_H
|
||||||
|
#define NNT_PCICONF_NO_VSEC_H
|
||||||
|
|
||||||
|
#include "nnt_device_defs.h"
|
||||||
|
#include "nnt_ioctl_defs.h"
|
||||||
|
|
||||||
|
|
||||||
|
int read_pciconf_no_vsec(struct nnt_device* nnt_device, struct nnt_rw_operation* read_operation);
|
||||||
|
int write_pciconf_no_vsec(struct nnt_device* nnt_device, struct nnt_rw_operation* write_operation);
|
||||||
|
int init_pciconf_no_vsec(struct nnt_device* nnt_device);
|
||||||
|
|
||||||
|
#endif
|
||||||
38
drivers/net/ethernet/mft/nnt_driver/nnt_ppc_device_list.h
Normal file
38
drivers/net/ethernet/mft/nnt_driver/nnt_ppc_device_list.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef NNT_DEVICE_LIST_H
|
||||||
|
#define NNT_DEVICE_LIST_H
|
||||||
|
|
||||||
|
#include "nnt_device_defs.h"
|
||||||
|
|
||||||
|
static struct pci_device_id pciconf_devices[] = {{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX3_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX3PRO_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTIB_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX4_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX4LX_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX5_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX5EX_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX6_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX6DX_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX6LX_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX7_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, CONNECTX8_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SCHRODINGER_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, FREYSA_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, BLUEFIELD_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, BLUEFIELD2_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, BLUEFIELD3_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, BLUEFIELD4_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SWITCHIB_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SWITCHIB2_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, QUANTUM_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, QUANTUM2_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, QUANTUM3_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SPECTRUM_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SPECTRUM2_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SPECTRUM3_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, SPECTRUM4_PCI_ID)},
|
||||||
|
{PCI_DEVICE(NNT_MELLANOX_PCI_VENDOR, BW00_PCI_ID)},
|
||||||
|
{
|
||||||
|
0,
|
||||||
|
}};
|
||||||
|
|
||||||
|
#endif // NNT_DEVICE_LIST_H
|
||||||
26
drivers/net/ethernet/mft/nnt_driver/nnt_ppc_driver_defs.h
Normal file
26
drivers/net/ethernet/mft/nnt_driver/nnt_ppc_driver_defs.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef NNT_DRIVER_PPC_H
|
||||||
|
#define NNT_DRIVER_PPC_H
|
||||||
|
|
||||||
|
LIST_HEAD(nnt_device_list);
|
||||||
|
|
||||||
|
#define NNT_MAXIMUM_DEVICE_NAME_LENGTH 128
|
||||||
|
#define NNT_MAXIMUM_NUMBER_OF_DEVICES 8
|
||||||
|
#define NNT_MAXIMUM_POLLING_NUMBER 100
|
||||||
|
#define NNT_UNKNOWN_DEVICE_ID 0xffff
|
||||||
|
#define NNT_MINIMUM_WAITING_TIME 100
|
||||||
|
#define NNT_DEVICE_LIST_SIZE NNT_MAXIMUM_DEVICE_NAME_LENGTH * NNT_MAXIMUM_NUMBER_OF_DEVICES
|
||||||
|
|
||||||
|
struct nnt_ppc_device {
|
||||||
|
struct list_head entry;
|
||||||
|
struct pci_dev* pci_device;
|
||||||
|
char* pci_device_dbdf_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct nnt_ppc_reset_info {
|
||||||
|
unsigned int number_of_found_pci_device;
|
||||||
|
unsigned int number_of_requested_pci_device;
|
||||||
|
int reset_was_done;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
13
drivers/net/ethernet/mft/scripts/install_mst_ppc_pci_reset.sh
Executable file
13
drivers/net/ethernet/mft/scripts/install_mst_ppc_pci_reset.sh
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
kernel_version="`modinfo -Fvermagic ./mst_backward_compatibility/mst_ppc/mst_ppc_pci_reset.ko | awk '{ print $1 }'`"
|
||||||
|
path_to_build="`pwd`"
|
||||||
|
path_to_build="$path_to_build/../build"
|
||||||
|
cd $path_to_build
|
||||||
|
|
||||||
|
mkdir -p /etc/mft/mlxfwreset/$kernel_version
|
||||||
|
/bin/cp -f ./mst_backward_compatibility/mst_ppc/mst_ppc_pci_reset.ko /etc/mft/mlxfwreset/$kernel_version/
|
||||||
|
|
||||||
|
cd -
|
||||||
|
|
||||||
Reference in New Issue
Block a user